/
simple-tester.f
112 lines (94 loc) · 4.05 KB
/
simple-tester.f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
\ simple-tester is a unit tester intended for embedded systems or other hardware targets
\ based on the ANS Forth version of John Hayes' Forth ttester
\ the purpose of simple-tester is
\ (i) to allow unit testing on targets with limited resources and
\ (ii) to allow testing as early on as possible in the lifecycle of a new forth system,
\ even before the system knows how to compile new word defintions
\
\ simple-tester requires
\ (i) a numeric output device (e.g. a seven-segment display)
\ (ii) a system halt instruction
\ (iii ) the forth word DEPTH
\ The usage format has been changed from ttester with the hope/intention of being more "forth-like"
\ T{ module-of-code }T x1 x2 ... xn ==
\ T{ and }T brackets the code being tested
\ x1, x2, ... xn are the expected outputs
\ == is the assert instruction that performs the comparison and halts the system on the first fail
\ if a test either fails to complete execution or the actual and expected outputs do not match, then
\ the numeric output device will show the number of the test that failed
\ simple-tester uses a hash algorithm to compare inputs and outputs rather than cell by cell comparison
\ possible advantages
\ (i) 2 cells only of RAM required for operation
\ (ii) testing scope is limited only by stack depth
\ (iii) no stack gynmastics, easy to write the necessary code words in brief assembly language
\ (iv) fast, advantageous for power-on-self-test-applications
\ disadvantage
\ (i) false positive risk - hash collissions may allow a test to pass that should actually have been failed
\ the following words are expected to be available as code words on the target system, other words are utility words
\ Tstart Tend T{ T} ==
\ utility words called by the unit test code words
\ ===========================================================================================================
\ report the test number to a numeric output device, such as a seven-segment display
: T.
. \ for a desktop Forth
;
\ halt the system
: halt-system
quit \ for a desktop Forth
;
\ compute h1 by hashing x1 and h0
: hash ( x1 h0 -- h1)
swap 1+ xor \ hash may be any simple function initially but upgraded later
; \ make sure it is not symmetric since stack reversal is a common error
\ hash n items from the stack and return the hash code
: hash-n ( x1 x2 ... xn n -- h)
0 >R \ put the initial hash value on the return stack
BEGIN
dup 0 > \ confirm at least one value to process
WHILE
swap R> hash >R
1-
REPEAT
drop R>
;
variable Tcount
variable Tdepth
\ unit test code words to be suitably implemented on the target system
\ reference implementations here in Forth
\ ===========================================================================================================
\ start testing
: Tstart
0 Tcount !
0 T.
;
\ start a unit test
: T{ ( )
Tcount @ 1+ dup T. Tcount ! \ increment and report the test number
depth Tdepth ! \ save the stack depth before the module runs
;
\ finish a unit test,
: }T ( y1 y2 ... yn -- hy) \ y1, y2 ... yn are the actual outputs
depth Tdepth @ - ( y1 y2 ... yn Ny) \ Ny = no. outputs created by running the module
hash-n ( hy) \ hy = hash value of the actual outputs
depth Tdepth ! ( hy) \ save the stack depth before the expected outputs
;
\ compare actual output with expected output
: == ( hy x1 x2 ... xn --)
depth Tdepth @ - ( hy x1 x2 .. xn Nx) \ Nx = no. outputs expected
hash-n ( hy hx) \ hx = hash value of the expected outputs
= 0= IF halt-system THEN \ hash codes didn't match, stop the system
;
\ signal end of testing
: Tend ( --)
65535 ( 0xFFFF) T. \ some at-a-glance value to indicate successful completion
;
\ extension words, perhaps for desktop systems
\ reference implementations here in Forth
\ ===========================================================================================================
\ hash a string to a single value on stack
: hashs ( c-addr u -- h)
swap 2dup + swap ( u end start)
?do \ Let h0 = u
i @ ( h_i x) swap hash ( h_j) \ j = i + 1
loop
;