PageRenderTime 25ms CodeModel.GetById 12ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 1ms

/test/cases/0040-error.lua

http://github.com/lua-aplicado/lua-aplicado
Lua | 583 lines | 492 code | 56 blank | 35 comment | 1 complexity | 60b4f81efb3306bb150f7389849d4e11 MD5 | raw file
  1--------------------------------------------------------------------------------
  2-- test/cases/0040-error.lua: tests for error.lua
  3-- This file is a part of Lua-Aplicado library
  4-- Copyright (c) Lua-Aplicado authors (see file `COPYRIGHT` for the license)
  5--------------------------------------------------------------------------------
  6
  7local log, dbg, spam, log_error
  8      = import 'lua-aplicado/log.lua' { 'make_loggers' } (
  9         "test/error", "T040"
 10       )
 11
 12--------------------------------------------------------------------------------
 13
 14local ensure,
 15      ensure_equals,
 16      ensure_strequals,
 17      ensure_error,
 18      ensure_fails_with_substring,
 19      ensure_returns,
 20      ensure_tdeepequals
 21      = import 'lua-nucleo/ensure.lua'
 22      {
 23        'ensure',
 24        'ensure_equals',
 25        'ensure_strequals',
 26        'ensure_error',
 27        'ensure_fails_with_substring',
 28        'ensure_returns',
 29        'ensure_tdeepequals'
 30      }
 31
 32local is_table
 33      = import 'lua-nucleo/type.lua'
 34      {
 35        'is_table'
 36      }
 37
 38local pack
 39      = import 'lua-nucleo/args.lua'
 40      {
 41        'pack'
 42      }
 43
 44local call,
 45      fail,
 46      try,
 47      rethrow,
 48      xfinally,
 49      xcall,
 50      create_error_object,
 51      is_error_object,
 52      error_handler_for_call,
 53      error_exports
 54      = import 'lua-aplicado/error.lua'
 55      {
 56        'call',
 57        'fail',
 58        'try',
 59        'rethrow',
 60        'xfinally',
 61        'xcall',
 62        'create_error_object',
 63        'is_error_object',
 64        'error_handler_for_call'
 65      }
 66
 67--------------------------------------------------------------------------------
 68
 69local test = (...)("error", error_exports)
 70
 71--------------------------------------------------------------------------------
 72
 73test:group "xfinally"
 74
 75test:case "result-and-finalize" (function(env)
 76  local finalized = false
 77  ensure_returns(
 78      "return value",
 79      1, { 42 },
 80      xfinally(
 81          function()
 82            return 42
 83          end,
 84          function()
 85            finalized = true
 86          end
 87        )
 88    )
 89  ensure("finalized", finalized)
 90end)
 91
 92test:case "many-results-and-finalize" (function(env)
 93  local finalized = false
 94  ensure_returns(
 95      "return multiple values",
 96      3, { 42, 43, 44 },
 97      xfinally(
 98          function()
 99            return 42, 43, 44
100          end,
101          function()
102            finalized = true
103          end
104        )
105    )
106  ensure("finalized", finalized)
107end)
108
109test:case "error-inside-finalizer" (function(env)
110  ensure_fails_with_substring(
111      "should raise error",
112      function()
113        xfinally(
114            function()
115              return 42
116            end,
117            function()
118              error("exception_to_catch")
119            end
120        )
121      end,
122      "exception_to_catch"
123    )
124end)
125
126test:case "handle-error-and-finalize-after" (function(env)
127  local finalized = false
128  ensure_fails_with_substring(
129      "should raise error",
130      function()
131        xfinally(
132            function()
133              error("exception_to_catch")
134            end,
135            function()
136              finalized = true
137            end
138          )
139      end,
140      "exception_to_catch"
141    )
142  ensure("finalized", finalized)
143end)
144
145test:case "error-and-error-inside-finalizer" (function(env)
146  ensure_fails_with_substring(
147      "should raise error",
148      function()
149        xfinally(
150            function()
151              error("first_error")
152            end,
153            function()
154              error("second_error")
155            end
156          )
157      end,
158      "first_error"
159    )
160end)
161
162--------------------------------------------------------------------------------
163
164test:group "xcall"
165
166test:case "xcall-result-and-finalize" (function(env)
167  local finalized = false
168  ensure_returns(
169      "return value",
170      2, { true, 42 },
171      xcall(
172          function()
173            return 42
174          end,
175          function()
176            finalized = true
177          end
178        )
179    )
180  ensure("finalized", finalized)
181end)
182
183test:case "xcall-many-results-and-finalize" (function(env)
184  local finalized = false
185  ensure_returns(
186      "return multiple values",
187      4, { true, 42, 43, 44 },
188      xcall(
189          function()
190            return 42, 43, 44
191          end,
192          function()
193            finalized = true
194          end
195        )
196    )
197  ensure("finalized", finalized)
198end)
199
200test:case "xcall-error-inside-finalizer" (function(env)
201  -- we can't use ensure_returns, because it can't match exception tracebacks
202  local ok, err, fin_ok, fin_err = xcall(
203      function()
204        return 42
205      end,
206      function()
207        error("something happens")
208      end
209    )
210  ensure_equals("not ok", ok, nil)
211  ensure_equals("err", err, nil)
212  ensure_equals("finalizer failed", fin_ok, nil)
213  ensure("error", fin_err)
214end)
215
216test:case "xcall-handle-error-and-finalize-after" (function(env)
217  -- we can't use ensure_returns, because it can't match exception tracebacks
218  local finalized = false
219  local ok, err, fin_ok, fin_err = xcall(
220      function()
221        error("something happens")
222      end,
223      function()
224        finalized = true
225      end
226    )
227  ensure_equals("not ok", ok, nil)
228  ensure_equals("finalized ok", fin_ok, true)
229  ensure("error returned", err)
230  ensure("finalized", finalized)
231end)
232
233test:case "xcall-handle-errors-in-function-and-finalizer" (function(env)
234  -- we can't use ensure_returns, because it can't match exception tracebacks
235  local ok, err, fin_ok, fin_err = xcall(
236      function()
237        error("something happens")
238      end,
239      function()
240        error("something happens")
241      end
242    )
243  ensure_equals("not ok", ok, nil)
244  ensure_equals("finalized ok", fin_ok, nil)
245  ensure("error returned", err)
246  ensure("finalizer error returned", fin_err)
247end)
248
249--------------------------------------------------------------------------------
250
251test:group "fail"
252
253-- This test captures return stack via pack(pcall(...)), then examines it
254-- to ensure correctness of returned values.
255--
256-- TODO: https://github.com/lua-aplicado/lua-aplicado/issues/14
257--       This test should be rewritten, using ensure_returns and predicate
258test:case "fail-generate-proper-error-object" (function(env)
259  local num, values = pack(
260        pcall(
261            function()
262              fail("TEST_ERROR", "test error")
263            end
264          )
265    )
266  ensure_equals("pcall return two values", num, 2)
267  ensure_equals("pcall return two values", values[1], false)
268  ensure("is error object", is_error_object(values[2]))
269end)
270
271test:case "fail-require-error-id" (function(env)
272  ensure_fails_with_substring(
273      "fail() require error_id argument",
274      function()
275        fail(nil, "error message")
276      end,
277      "argument #1: expected `string', got `nil'"
278    )
279end)
280
281test:case "fail-require-error-message" (function(env)
282  ensure_fails_with_substring(
283      "fail() require error_message argument",
284      function()
285        fail("TEST_ERROR")
286      end,
287      "argument #2: expected `string', got `nil'"
288    )
289end)
290
291--------------------------------------------------------------------------------
292
293test:group "call"
294
295test:case "call-function-returns-single-value" (function(env)
296  ensure_returns(
297      "call returns single value",
298      1, { 42 },
299      call(function()
300        return 42
301      end)
302    )
303end)
304
305test:case "call-function-returns-many-values" (function(env)
306  ensure_returns(
307      "call returns multiple values",
308      3, { 42, 43, 44 },
309      call(
310          function()
311            return 42, 43, 44
312          end
313        )
314    )
315end)
316
317test:case "call-and-fail" (function(env)
318  ensure_returns(
319      "call return proper error value",
320      2,
321      { nil, "TEST_ERROR" },
322      call(
323          function()
324            fail("TEST_ERROR", "test error")
325          end
326        )
327    )
328end)
329
330test:case "call-and-plain-error" (function(env)
331  local ok, err
332  ensure_fails_with_substring(
333      "error pass through",
334      function()
335        ok, err = call(
336            function()
337              error("test error")
338            end
339          )
340      end,
341      "test error"
342    )
343  ensure_equals("nil", ok, nil)
344  ensure_equals("error skipped", err, nil)
345end)
346
347--------------------------------------------------------------------------------
348
349test:group "try"
350
351test:case "try-ok" (function(env)
352  ensure_returns(
353      "try() return correct value (outer test)",
354      2, { 42, "error message" },
355      call(
356          function()
357            return ensure_returns(
358                "try() return correct value (inner test)",
359                2,
360                { 42, "error message" },
361                try("TEST_ERROR", 42, "error message")
362              )
363          end
364        )
365    )
366end)
367
368-- TODO: https://github.com/lua-aplicado/lua-aplicado/issues/15
369--       Ensure that error message was logged
370test:case "try-and-fail" (function(env)
371  ensure_returns(
372      "try fails and return proper error value",
373      2, { nil, "TEST_ERROR" },
374      call(
375          function()
376            local value = try("TEST_ERROR", nil, "error message")
377            error("unreachable")
378          end
379        )
380    )
381end)
382
383--------------------------------------------------------------------------------
384
385test:group "rethrow"
386
387test:case "rethrow-fail" (function(env)
388  local failure_obj = create_error_object("TEST_ERROR", "test error")
389  ensure_returns(
390      "rethrow error object",
391      2, { nil, "TEST_ERROR" },
392      call(
393          function()
394            rethrow("NEW_ERROR", failure_obj)
395          end
396        )
397    )
398end)
399
400test:case "rethrow-error" (function(env)
401  ensure_returns(
402      "rethrow plain error",
403      2, { nil, "NEW_ERROR" },
404      call(
405          function()
406            rethrow("NEW_ERROR", "plain test error")
407          end
408        )
409    )
410end)
411
412--------------------------------------------------------------------------------
413
414-- Test for error.lua semi-public functions
415--
416-- These tests are related on implementation details, and can be altered,
417-- on implementation change, even if public contract stay unchanged
418test:group "create_error_object"
419
420test:case "create-error-object" (function(env)
421  -- Assuming knowledge about internal layout of "error object" table,
422  -- we inspect content of value
423  local value = create_error_object("TEST_ERROR", "message")
424  ensure("error object is table", is_table(value))
425  ensure_equals("error object has proper error ID set", value[2], "TEST_ERROR")
426
427  -- "error object" use table reference as marker, create another "error"
428  -- and ensure if marker is same.
429  local another_value = create_error_object("ANOTHER", "message")
430  ensure_equals("markers are equal", value[1], another_value[1])
431end)
432
433test:group "is_error_object"
434
435test:case "is-error-object-positive-test" (function(env)
436  local value = create_error_object("TEST_ERROR", "message")
437  ensure_returns(
438      "is_error_object() recognizes error object",
439      1, { true },
440      is_error_object(value)
441    )
442end)
443
444test:case "is-error-object-negative-test" (function(env)
445  ensure_returns(
446      "is_error_object() does not recognize number as error object",
447      1, { false },
448      is_error_object(42)
449    )
450  ensure_returns(
451      "is_error_object() does not recognize string as error object",
452      1, { false },
453      is_error_object("fourty two")
454    )
455  ensure_returns(
456      "is_error_object() does not recognize table as error object",
457      1, { false },
458      is_error_object( { 42 } )
459    )
460  ensure_returns(
461      "is_error_object() does not recognize boolean (true) as error object",
462      1, { false },
463      is_error_object(true)
464    )
465  ensure_returns(
466      "is_error_object() does not recognize boolean (false) as error object",
467      1, { false },
468      is_error_object(false)
469    )
470  ensure_returns(
471      "is_error_object() does not recognize nil as error object",
472      1, { false },
473      is_error_object(nil)
474    )
475end)
476
477-- TODO: https://github.com/lua-aplicado/lua-aplicado/issues/16
478test:UNTESTED "error_handler_for_call"
479
480--------------------------------------------------------------------------------
481
482-- Test xfinally transparency for call/fail
483
484test:case "call-and-finalize" (function(env)
485  local finalized = false
486  ensure_returns(
487      "call returns value",
488      1, { 42 },
489      call(
490          function()
491            return xfinally(
492                function()
493                  return 42
494                end,
495                function()
496                  finalized = true
497                end
498              )
499          end
500        )
501    )
502  ensure("finalized", finalized)
503end)
504
505test:case "call-function-many-results-and-finalize" (function(env)
506  local finalized = false
507  ensure_returns(
508      "call returns multiple values",
509      3, { 42, 43, 44 },
510      call(
511          function()
512            return xfinally(
513                function()
514                  return 42, 43, 44
515                end,
516                function()
517                  finalized = true
518                end
519              )
520          end
521        )
522    )
523  ensure("finalized", finalized)
524end)
525
526test:case "call-and-fail-inside-finalizer" (function(env)
527  ensure_returns(
528      "return proper error when finalizer fails",
529      2, { nil, "TEST_ERROR" },
530      call(
531          function()
532            xfinally(
533                function()
534                  return 42
535                end,
536                function()
537                  fail("TEST_ERROR", "test error")
538                end
539              )
540          end
541        )
542    )
543end)
544
545test:case "handle-fail-and-finalize-after" (function(env)
546  local finalized = false
547  ensure_returns(
548      "xfinally is transparent for exception raised by fail",
549      2, { nil, "TEST_ERROR" },
550      call(
551          function()
552            xfinally(
553                function()
554                  fail("TEST_ERROR", "test error")
555                end,
556                function()
557                  finalized = true
558                end
559              )
560          end
561        )
562    )
563  ensure("finalized", finalized)
564end)
565
566test:case "fail-and-fail-inside-finalizer" (function(env)
567  ensure_returns(
568      "fail and fail inside finalizer",
569      2, { nil, "TEST_ERROR"},
570      call(
571          function()
572            xfinally(
573                function()
574                  fail("TEST_ERROR", "first_error")
575                end,
576                function()
577                  fail("TEST_HANDLER_ERROR", "second_error")
578                end
579              )
580          end
581        )
582    )
583end)