1 # Ocean Interpreter test code
3 Regular testing is, of course, important for developing any software.
4 The Ocean interpreted is no exception. This document allows easy
7 - a collection of test program
8 - the expected output of these programs when run with various arguments
9 - some "Makefile" code to tie it all together.
11 Three different sorts of tests are run. As soon as any fail, the whole
14 1/ Each program is run and the output is compared against the expected
16 2/ Each program is then run under valgrind, and an error is reported
17 if valgrind detects an error, or if it reports and lost or unfreed
19 3/ Each program is parsed and printed, then the result is parsed and printed.
20 The two results must match.
21 4/ Each program is run with a version of `oceani` with test-coverage
22 recording enabled. Once all programs have successfully run and
23 all the coverage data is available, we check that all lines have
24 been tested at least once. A few exceptions are allowed such as
25 lines that call `abort()`. If any non-exceptional lines have not
26 been run, this final test fails.
27 Until the tests suite is (more) completed, we only throw and error
28 if fewer than 75% of the lines have been tested.
30 Each test has a name, which used to identify the section in this file, and optionally some
31 arguments separated from the name by commas. For each test, there is a section named
32 "output:" followed by the name-and-arguments.
34 ###### File: oceani-tests.mk
38 tests:: oceani_test_suite
39 oceani_test_suite: oceani coverage_oceani
40 @rm -rf coverage; mkdir -p coverage
42 @for T in $(oceani_tests); do \
43 echo -n "Test $$T ... "; \
44 i="$$IFS"; IFS=,; set $$T; IFS="$$i"; t=$$1; shift; \
45 ./md2c oceani-tests.mdc "output: $$T" | grep -v '^#' > .tmp.want; \
46 ./oceani --section "test: $$t" oceani-tests.mdc $${1+"$$@"} > .tmp.have; \
47 if ! cmp -s .tmp.want .tmp.have; then \
48 echo "FAILED"; diff -u .tmp.want .tmp.have ; exit 1; fi ;\
49 echo -n "passed ... "; \
50 if ! valgrind ./oceani --section "test: $$t" oceani-tests.mdc $${1+"$$@"} \
51 > /dev/null 2> .tmp.valg; then \
52 echo "valgrind FAILED"; cat .tmp.valg; exit 1; fi ; \
53 echo -n "valgrind passed ... "; \
54 echo '``````' > .tmp.code1; echo '``````' > .tmp.code2 ;\
55 ./oceani --noexec --print --section "test: $$t" oceani-tests.mdc >> .tmp.code1; \
56 ./oceani --noexec --print .tmp.code1 >> .tmp.code2 ;\
57 if ! cmp -s .tmp.code1 .tmp.code2; then \
58 echo "Printing Failed"; diff -u .tmp.code1 .tmp.code2; exit1 ; fi ; \
59 echo "Printing passed"; \
60 ./coverage_oceani --print --section "test: $$t" oceani-tests.mdc $${1+"$$@"} > /dev/null ; \
61 ./coverage_oceani -tpbn --section "test: $$t" oceani-tests.mdc > /dev/null 2>&1; \
63 @gcov -o coverage oceani.mdc > /dev/null 2> /dev/null
64 @mv *.gcov coverage ; [ -f .gcov ] && mv .gcov coverage
65 @ awk '/^ *[1-9]/ {ran+=1} /^ *###/ {skip+=1} \
66 END {printf "coverage: %6.2f%%\n", ran * 100 / (ran + skip); \
67 if (ran < (ran + skip) *0.75) exit(1) }' \
68 coverage/oceani.mdc.gcov
71 coverage_oceani: oceani.c
72 $(CC) $(CFLAGS) --coverage -fprofile-dir=coverage -o coverage_oceani oceani.c $(LDLIBS)
76 ## Values and variables
78 The first test stores values in variables and performs various
82 oceani_tests += "valvar"
89 print a, b, a+b, a-b, a*b, a/b, a%b
90 print a<b, a<=b, a>b, a>=b, a<a, a==b, a==a
92 c ::= "This is a string"
98 23 12 35 11 276 1.91667 11
99 False False True True False False True
100 This is a string field theory This is a string field theory
102 Next we change the value of variables
105 oceani_tests += "setvar"
112 a = (a + a) * (a + a)
116 ###### output: setvar
119 ## Conditions and Loops
121 Now we need to test if/else and some different loops
124 oceani_tests += cond_loop
126 ###### test: cond_loop
134 for b:=1; then b=b+b; while b < 100:
137 // Newtons method for square root of 2
143 current := guess * guess
144 use +(current - target) > 0.000000001
146 guess = (guess + (target / guess) ) / 2
149 print "error is ", target - guess * guess
151 ###### output: cond_loop
158 error is -4.51095e-12
162 The demonstration code presented in the interpreted is suitable for the test suite.
163 Here I break it into two parts, keeping the array code separate.
166 oceani_tests += "sayhello,55,33"
167 oceani_tests += "sayhello,12,60"
169 ###### test: sayhello
172 print "Hello World, what lovely oceans you have!"
173 /* When a variable is defined in both branches of an 'if',
174 * and used afterwards, the variables are merged.
180 print "Is", A, "bigger than", B,"? ", bigger
181 /* If a variable is not used after the 'if', no
182 * merge happens, so types can be different
185 double:string = "yes"
186 print A, "is more than twice", B, "?", double
189 print "double", B, "is", double
200 print "GCD of", A, "and", B,"is", a
202 print a, "is not positive, cannot calculate GCD"
204 print b, "is not positive, cannot calculate GCD"
209 print "Fibonacci:", f1,f2,
218 /* Binary search... */
235 print "Yay, I found", target
237 print "Closest I found was", mid
239 ###### output: sayhello,55,33
240 Hello World, what lovely oceans you have!
241 Is 55 bigger than 33 ? yes
243 GCD of 55 and 33 is 11
244 Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
245 Closest I found was 77.3438
247 ###### output: sayhello,12,60
248 Hello World, what lovely oceans you have!
249 Is 12 bigger than 60 ? no
251 GCD of 12 and 60 is 12
252 Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
253 Closest I found was 77.3438
256 oceani_tests += "insert_sort"
257 ###### test: insert_sort
262 for i:=1; then i = i + 1; while i < size:
263 n := list[i-1] * list[i-1]
264 list[i] = (n / 100) % 10000
267 for i:=0; then i = i + 1; while i < size:
268 print "list[",i,"]=",list[i]
270 for i := 1; then i=i+1; while i < size:
271 for j:=i-1; then j=j-1; while j >= 0:
272 if list[j] > list[j+1]:
277 for i:=0; then i = i + 1; while i < size:
278 print "list[",i,"]=",list[i]
280 ###### output: insert_sort