PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

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