COVERAGE SUMMARY
FILE SUMMARY
NameExecutedRoutines%ExecutedLines%Unexecuted
/home/matt/eu/rds/include/std/unittest.e121770.59%8815457.14%66
ROUTINE SUMMARY
RoutineExecutedLinesUnexecuted
test_report()102343.48%13
assert()090.00%9
test_failed()142263.64%8
add_log()3837.50%5
test_crash()040.00%4
set_accumulate_summary()030.00%3
set_wait_on_summary()030.00%3
test_fail()030.00%3
test_passed()6785.71%1
record_result()66100.00%0
set_test_abort()44100.00%0
set_test_verbosity()33100.00%0
test_equal()88100.00%0
test_false()33100.00%0
test_not_equal()99100.00%0
test_pass()33100.00%0
test_true()33100.00%0
LINE COVERAGE DETAIL
#Executed
1
-- (c) Copyright - See License.txt
2
--
3
namespace unittest
4
5
--****
6
-- == Unit Testing Framework
7
--
8
-- <>
9
--
10
-- === Background
11
-- Unit testing is the process of assuring that the smallest programming units
12
-- are actually delivering functionality that complies with their specification.
13
-- The units in question are usually individual routines rather than whole programs
14
-- or applications.
15
--
16
-- The theory is that if the components of a system are working correctly, then
17
-- there is a high probability that a system using those components can be made
18
-- to work correctly.
19
--
20
-- In Euphoria terms, this framework provides the tools to make testing and reporting on
21
-- functions and procedures easy and standardized. It gives us a simple way to
22
-- write a test case and to report on the findings.\\
23
-- Example~:
24
--
25
-- include std/unittest.e
26
--
27
-- test_equal( "Power function test #1", 4, power(2, 2))
28
-- test_equal( "Power function test #2", 4, power(16, 0.5))
29
--
30
-- test_report()
31
--
32
--
33
-- Name your test file in the special manner, ##t_NAME.e## and then simply run
34
-- ##eutest## in that directory.
35
--
36
-- {{{
37
-- C:\Euphoria> eutest
38
-- t_math.e:
39
-- failed: Bad math, expected: 100 but got: 8
40
-- 2 tests run, 1 passed, 1 failed, 50.0% success
41
--
42
-- Test failure summary:
43
-- FAIL: t_math.e
44
--
45
-- 2 file(s) run 1 file(s) failed, 50.0% success--
46
-- }}}
47
--
48
-- In this example, we use the ##test_equal## function to record the result of
49
-- a test. The first parameter is the name of the test, which can be anything
50
-- and is displayed if the test fails. The second parameter is the expected
51
-- result ~-- what we expect the function being tested to return. The third
52
-- parameter is the actual result returned by the function being tested. This
53
-- is usually written as a call to the function itself.
54
--
55
-- It is typical to provide as many test cases as would be required to give us
56
-- confidence that the function is being truly exercised. This includes calling
57
-- it with typical values and edge-case or exceptional values. It is also useful
58
-- to test the function's error handling by calling it with bad parameters.
59
--
60
-- When a test fails, the framework displays a message, showing the test's name,
61
-- the expected result and the actual result. You can configure the framework to
62
-- display each test run, regardless of whether it fails or not.
63
--
64
-- After running a series of tests, you can get a summary displayed by calling
65
-- the ##test_report##() procedure. To get a better feel for unit testing, have
66
-- a look at the provided test cases for the standard library in the //tests//
67
-- directory.
68
--
69
-- When included in your program, unittest.e sets a crash handler to log a crash
70
-- as a failure.
71
72
--****
73
-- === Constants
74
--
75
76
include std/io.e
77
include std/pretty.e
78
include std/search.e
79
include std/filesys.e
80
include std/math.e
81
include std/types.e
82
include std/error.e
83
--
84
-- Public Variables
85
--
86
87
-- Verbosity values
88
public enum
89101
TEST_QUIET = 0,
90101
TEST_SHOW_FAILED_ONLY,
91101
TEST_SHOW_ALL
92
93
--
94
-- Private variables
95
--
96
97101
atom time_start = time(), time_test = time()
98
99101
integer test_count = 0, tests_passed = 0, tests_failed = 0
100
sequence filename
101101
integer verbose = TEST_SHOW_FAILED_ONLY
102
103101
integer abort_on_fail = 0
104101
integer wait_on_summary = 0
105101
integer accumulate_on_summary = 0
106101
integer logging = 0, log_fh = 0
107
108
--
109
-- Private utility functions
110
--
111
1123403
1133403
if log_fh = 0 then
1143403
return
115
end if
116
1170
puts(log_fh, "entry = ")
1180
pretty_print(log_fh, data, {2, 2, 1, 78, "%d", "%.15g"})
1190
puts(log_fh, "\n")
1200
flush(log_fh)
1210
end procedure
122
1236
1246
if verbose >= TEST_SHOW_FAILED_ONLY then
1256
printf(2, " failed: %s, expected: ", {name})
1266
if TF then
1270
if not equal(a,0) then
1280
puts(2, "TRUE")
129
else
1300
puts(2, "FALSE")
131
end if
132
else
1336
pretty_print(2, a, {2,2,1,78,"%d", "%.15g"})
134
end if
1356
puts(2, " but got: ")
1366
if TF and integer(b) then
1370
if not equal(b,0) then
1380
puts(2, "TRUE")
139
else
1400
puts(2, "FALSE")
141
end if
142
else
1436
pretty_print(2, b, {2,2,1,78,"%d", "%.15g"})
144
end if
1456
puts(2, "\n")
146
end if
147
1486
tests_failed += 1
149
1506
add_log({ "failed", name, a, b, time() - time_test })
1516
time_test = time()
152
1536
if abort_on_fail then
1540
puts(2, "Abort On Fail set.\n")
1550
abort(2)
156
end if
1576
end procedure
158
1593311
1603311
if verbose >= TEST_SHOW_ALL then
1610
printf(2, " passed: %s\n", {name})
162
end if
163
1643311
tests_passed += 1
165
1663311
add_log({ "passed", name, time() - time_test })
1673311
time_test = time()
1683311
end procedure
169
170
--
171
-- Global Testing Functions
172
--
173
174
--****
175
-- === Setup Routines
176
177
--**
178
-- Set the amount of information that is returned about passed and failed tests.
179
--
180
-- Parameters:
181
-- # ##verbosity## : an atom which takes predefined values for verbosity levels.
182
--
183
-- Comments:
184
-- The following values are allowable for ##verbosity##:
185
-- * ##TEST_QUIET## ~-- 0,
186
-- * ##TEST_SHOW_FAILED_ONLY## ~-- 1
187
-- * ##TEST_SHOW_ALL## ~-- 2
188
--
189
-- However, anything less than ##TEST_SHOW_FAILED_ONLY## is treated as ##TEST_QUIET##, and everything
190
-- above ##TEST_SHOW_ALL## is treated as ##TEST_SHOW_ALL##.
191
--
192
-- * At the lowest verbosity level, only the score is shown, ie the ratio passed tests/total tests.
193
-- * At the medium level, in addition, failed tests display their name, the expected outcome and
194
-- the outcome they got. This is the initial setting.
195
-- * At the highest level of verbosity, each test is reported as passed or failed.
196
--
197
-- If a file crashes when it should not, this event is reported no matter the verbosity level.
198
--
199
-- The command line switch ""-failed" causes verbosity to be set to medium at startup. The
200
-- command line switch ""-all" causes verbosity to be set to high at startup.
201
--
202
-- See Also:
203
-- [[:test_report]]
204
2051
2061
verbose = verbosity
2071
end procedure
208
209
--**
210
-- Request the test report to pause before exiting.
211
--
212
-- Parameters:
213
-- # ##to_wait## : an integer, zero not to wait, nonzero to wait.
214
--
215
-- Comments:
216
-- Depending on the environment, the test results may be invisible if
217
-- ##set_wait_on_summary(1)## was not called prior, as this is not the default. The command
218
-- line switch "-wait" performs this call.
219
--
220
-- See Also:
221
-- [[:test_report]]
222
2230
2240
wait_on_summary = to_wait
2250
end procedure
226
227
--**
228
-- Request the test report to save run stats in "unittest.dat" before exiting.
229
--
230
-- Parameters:
231
-- # ##accumulate## : an integer, zero not to accumulate, nonzero to accumulate.
232
--
233
-- Comments:
234
-- The file "unittest.dat" is appended to with {t,f}\\
235
-- : where
236
-- :: //t// is total number of tests run
237
-- :: //f// is the total number of tests that failed
238
--
239
2400
2410
accumulate_on_summary = accumulate
2420
end procedure
243
244
--**
245
-- Set behavior on test failure, and return previous value.
246
--
247
-- Parameters:
248
-- # ##abort_test## : an integer, the new value for this setting.
249
--
250
-- Returns:
251
-- An **integer**, the previous value for the setting.
252
--
253
-- Comments:
254
-- By default, the tests go on even if a file crashed.
255
2562
2572
integer tmp = abort_on_fail
2582
abort_on_fail = abort_test
259
2602
return tmp
261
end function
262
263
--****
264
-- === Reporting
265
266
--**
267
-- Output test report
268
--
269
-- Comments:
270
--
271
-- The report components are described in the comments section for [[:set_test_verbosity]]. Everything
272
-- prints on the standard error device.
273
--
274
-- See Also:
275
-- [[:set_test_verbosity]]
276
27786
278
atom score
279
integer fh
280
sequence fname
281
28286
if tests_failed > 0 or verbose >= TEST_SHOW_ALL then
2832
if test_count = 0 then
2840
score = 100
285
else
2862
score = (tests_passed / test_count) * 100
287
end if
288
2892
printf(2, " %d tests run, %d passed, %d failed, %.1f%% success\n",
290
{test_count, tests_passed, tests_failed, score})
291
end if
292
29386
if accumulate_on_summary then
2940
fname = command_line()
2950
if equal(fname[1], fname[2]) then
2960
fname = fname[1]
297
else
2980
fname = fname[2]
299
end if
3000
fh = open("unittest.dat", "a")
3010
printf(fh, "{%d,%d,\"%s\"}\n", {test_count, tests_failed, fname})
3020
close(fh)
303
end if
304
30586
add_log({ "summary", test_count, tests_failed, tests_passed, time() - time_start })
306
30786
if log_fh != 0 then
3080
close( log_fh )
3090
log_fh = 0
310
end if
311
31286
if match("t_c_", filename) = 1 then
3130
puts(2, " test should have failed but was a success\n")
3140
abort(0)
315
else
31686
abort(tests_failed > 0)
317
end if
3180
end procedure
319
3203317
3213317
test_count += 1
322
3233317
if success then
3243311
test_passed(name)
325
else
3266
test_failed(name, a, b, TF)
327
end if
3283317
end procedure
329
330
--****
331
-- === Tests
332
--
333
334
--**
335
-- Records whether a test passes by comparing two values.
336
--
337
-- Parameters:
338
-- # ##name## : a string, the name of the test
339
-- # ##expected## : an object, the expected outcome of some action
340
-- # ##outcome## : an object, some actual value that should equal the reference ##expected##.
341
--
342
-- Comments:
343
--
344
-- * For floating point numbers, a fuzz of 1e-9 is used to assess equality.
345
--
346
-- A test is recorded as passed if equality holds between ##expected## and ##outcome##. The latter
347
-- is typically a function call, or a variable that was set by some prior action.
348
--
349
-- While ##expected## and ##outcome## are processed symmetrically, they are not recorded
350
-- symmetrically, so be careful to pass ##expected## before ##outcome## for better test failure
351
-- reports.
352
--
353
-- See Also:
354
-- [[:test_not_equal]], [[:test_true]], [[:test_false]], [[:test_pass]], [[:test_fail]]
355
3562508
357
integer success
358
3592508
if equal(expected, outcome ) then
360
-- for inf and -inf simple values
3612471
success = 1
36237
elsif equal(0*expected, 0*outcome) then
363
-- for complicated sequences values
36436
success = max(abs(expected-outcome)) < 1e-9
365
else
3661
success = 0
367
end if
368
3692508
record_result(success, name, expected, outcome)
3702508
end procedure
371
372
--**
373
-- Records whether a test passes by comparing two values.
374
--
375
-- Parameters:
376
-- # ##name## : a string, the name of the test
377
-- # ##expected## : an object, the expected outcome of some action
378
-- # ##outcome## : an object, some actual value that should equal the reference ##expected##.
379
--
380
-- Comments:
381
-- * For atoms, a fuzz of 1e-9 is used to assess equality.
382
-- * For sequences, no such fuzz is implemented.
383
--
384
-- A test is recorded as passed if equality does not hold between ##expected## and ##outcome##. The
385
-- latter is typically a function call, or a variable that was set by some prior action.
386
--
387
-- See Also:
388
-- [[:test_equal]], [[:test_true]], [[:test_false]], [[:test_pass]], [[:test_fail]]
389
39036
391
integer success
39236
if sequence(a) or sequence(b) then
39310
success = not equal(a,b)
394
else
39526
if a > b then
3961
success = ((a-b) >= 1e-9)
397
else
39825
success = ((b-a) >= 1e-9)
399
end if
400
end if
40136
a = "anything but '" & pretty_sprint( a, {2,2,1,78,"%d", "%.15g"}) & "'"
40236
record_result(success, name, a, b)
40336
end procedure
404
405
--**
406
-- Records whether a test passes.
407
--
408
-- Parameters:
409
-- # ##name## : a string, the name of the test
410
-- # ##outcome## : an object, some actual value that should not be zero.
411
--
412
-- Comments:
413
-- This assumes an expected value different from 0. No fuzz is applied when checking whether an
414
-- atom is zero or not. Use [[:test_equal]]() instead in this case.
415
--
416
-- See Also:
417
-- [[:test_equal]], [[:test_not_equal]], [[:test_false]], [[:test_pass]], [[test_fail]]
418
419408
420408
record_result(not equal(outcome,0), name, 1, outcome, 1 )
421408
end procedure
422
423
--**
424
-- Records whether a test passes. If it fails, the program also fails.
425
--
426
-- Parameters:
427
-- # ##name## : a string, the name of the test
428
-- # ##outcome## : an object, some actual value that should not be zero.
429
--
430
-- Comments:
431
-- This is identical to ##test_true()## except that if the test fails, the
432
-- program will also be forced to fail at this point.
433
--
434
-- See Also:
435
-- [[:test_equal]], [[:test_not_equal]], [[:test_false]], [[:test_pass]], [[test_fail]]
436
4370
4380
if sequence(name) then
4390
test_true(name, outcome)
4400
if equal(outcome,0) then
4410
crash(name)
442
end if
443
else
4440
test_true(outcome, name)
4450
if equal(name,0) then
4460
crash(outcome)
447
end if
448
end if
4490
end procedure
450
451
--**
452
-- Records whether a test passes by comparing two values.
453
--
454
-- Parameters:
455
-- # ##name## : a string, the name of the test
456
-- # ##outcome## : an object, some actual value that should be zero
457
--
458
-- Comments:
459
-- This assumes an expected value of 0. No fuzz is applied when checking whether an atom is zero
460
-- or not. Use [[:test_equal]]() instead in this case.
461
--
462
-- See Also:
463
-- [[:test_equal]], [[:test_not_equal]], [[:test_true]], [[:test_pass]], [[:test_fail]]
464
465305
466305
record_result(equal(outcome, 0), name, 0, outcome, 1)
467305
end procedure
468
469
--**
470
-- Records that a test failed.
471
--
472
-- Parameters:
473
-- # ##name## : a string, the name of the test
474
--
475
-- See Also:
476
-- [[:test_equal]], [[:test_not_equal]],[[:test_true]], [[:test_false]], [[:test_pass]]
477
4780
4790
record_result(0, name, 1, 0, 1)
4800
end procedure
481
482
--**
483
-- Records that a test passed.
484
--
485
-- Parameters:
486
-- # ##name## : a string, the name of the test
487
--
488
-- See Also:
489
-- [[:test_equal]], [[:test_not_equal]],[[:test_true]], [[:test_false]], [[:test_fail]]
490
49160
49260
record_result(1, name, 1, 1, 1)
49360
end procedure
494
495101
sequence cmd = command_line()
496101
filename = cmd[2]
497
498
499
-- strip off path information
500101
while find( SLASH, filename ) do
5010
filename = filename[find( SLASH, filename )+1..$]
5020
end while
503
504101
for i = 3 to length(cmd) do
5050
if equal(cmd[i], "-all") then
5060
set_test_verbosity(TEST_SHOW_ALL)
5070
elsif equal(cmd[i], "-failed") then
5080
set_test_verbosity(TEST_SHOW_FAILED_ONLY)
5090
elsif equal(cmd[i], "-wait") then
5100
set_wait_on_summary(1)
5110
elsif begins(cmd[i], "-accumulate") then
5120
set_accumulate_summary(1)
5130
elsif equal(cmd[i], "-log") then
5140
log_fh = open("unittest.log", "a")
5150
if log_fh = -1 then
5160
puts(2,"Cannot open unittest.log for append.\n")
5170
abort(1)
518
end if
5190
add_log({"file", filename})
520
end if
5210
end for
522
523101
ifdef not CRASH then
524
525
include std/error.e
526
5270
5280
test_fail( "unittesting crashed" )
5290
test_report()
5300
return 0
531
end function
53287
crash_routine( routine_id( "test_crash" ) )
533
534
end ifdef