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 oceani_valg_tests := $(oceani_tests)
41 tests:: oceani_test_suite
42 oceani_test_suite: oceani coverage_oceani
43 @echo -n Checking grammar ...
44 @./parsergen --report --LALR --tag Parser oceani.mdc | grep " - no conflicts" > /dev/null || \
45 { echo "Grammar contains conflicts, please review" ; exit 1; }
47 @rm -rf coverage; mkdir -p coverage
49 @for T in $(oceani_tests); do \
50 echo -n "Test $$T.. "; \
51 i="$$IFS"; IFS=,; set $$T; IFS="$$i"; t=$$1; shift; \
52 ./md2c oceani-tests.mdc "output: $$T" | grep -v '^#' > .tmp.want; \
53 ./oceani --section "test: $$t" oceani-tests.mdc $${1+"$$@"} > .tmp.have; \
54 if ! cmp -s .tmp.want .tmp.have; then \
55 echo "FAILED"; diff -u .tmp.want .tmp.have ; exit 1; fi ;\
56 echo -n "printing.. "; \
57 echo '``````' > .tmp.code1; echo '``````' > .tmp.code2 ;\
58 ./oceani --noexec --print --section "test: $$t" oceani-tests.mdc >> .tmp.code1; \
59 ./oceani --noexec --print .tmp.code1 >> .tmp.code2 || exit 1;\
60 if ! cmp -s .tmp.code1 .tmp.code2; then \
61 echo " Failed"; diff -u .tmp.code1 .tmp.code2; exit 1 ; fi ; \
62 echo -n "extra-newlines.. "; \
64 ' .tmp.code1 > .tmp.code1a; \
65 echo '``````' > .tmp.code2a ;\
66 ./oceani --noexec --print .tmp.code1a >> .tmp.code2a || exit 1;\
67 if ! cmp -s .tmp.code1 .tmp.code2a; then \
68 echo " Failed"; diff -u .tmp.code1 .tmp.code2a; exit 1; fi ; \
69 echo -n "exec-after-print.. "; \
70 ./oceani .tmp.code1 $${1+"$$@"} > .tmp.have ; \
71 if ! cmp -s .tmp.want .tmp.have; then \
72 echo " FAILED"; diff -u .tmp.want .tmp.have; exit 1;fi; \
74 ./coverage_oceani --print --section "test: $$t" oceani-tests.mdc $${1+"$$@"} > /dev/null ; \
75 ./coverage_oceani -tpbn --section "test: $$t" oceani-tests.mdc > /dev/null 2>&1; \
80 @for i in coverage/#*.gcda; do mv $$i coverage/$${i##*#}; done
81 @gcov -o coverage oceani.mdc > /dev/null 2> /dev/null
82 @mv *.gcov coverage ; [ -f .gcov ] && mv .gcov coverage || true
85 @[ -n "$$SKIP_VALGRIND" ] || for T in $(oceani_valg_tests); do \
86 echo -n "Valgrind $$T.. "; \
87 i="$$IFS"; IFS=,; set $$T; IFS="$$i"; t=$$1; shift; \
88 if valgrind --error-exitcode=42 --log-file=.tmp.valg ./oceani --section "test: $$t" oceani-tests.mdc $${1+"$$@"} \
89 > /dev/null 2>&1 ; [ $$? -eq 42 ] ; then \
90 echo "FAILED"; cat .tmp.valg; exit 1; fi ; \
91 if grep 'LEAK SUMMARY' .tmp.valg > /dev/null; then \
92 echo "valgrind found LEAKS"; cat .tmp.valg ; exit 1 ; fi; \
93 if grep 'in use at exit [1-9]' .tmp.valg > /dev/null; then \
94 echo "valgrind found memory in use at exit"; cat .tmp.valg ; exit 1 ; fi; \
98 @[ -n "$$SKIP_COVERAGE_CHECK" ] || awk '/NOTEST/ { next } /^ *[1-9]/ {ran+=1} /^ *###/ {skip+=1} \
99 END {printf "coverage: %6.2f%%\n", ran * 100 / (ran + skip); \
100 if (ran < (ran + skip) *0.98) exit(1) }' \
101 coverage/oceani.mdc.gcov
103 coverage_oceani: oceani.c
104 $(CC) $(CFLAGS) --coverage -fprofile-dir=coverage -o coverage_oceani oceani.c $(LDLIBS)
106 ## Values and variables
108 The first test stores values in variables and performs various
109 calculations on them.
112 oceani_tests += "valvar"
116 func main(argv:[]string)
117 a := 23; b:=12 ; b1 := -b
118 print a, b, a+b, a-b, a*b, a/b, a%b
119 print a<b, a<=b, a>b, a>=b, a<a, a==b, a==a
120 print +a, +b, +b1, -a, -b, -b1
121 x := True; y := False
122 print x and y, x or y, x and x, y or y, x and not x, x < y
124 c ::= "This is a string"
125 d ::= " field theory"
128 aconst :: string = "unchanging"
142 print "z??False", z??False, "w??False", w??False
145 print $"-34.56", $"not-a-number"
147 if True { pass; pass }
149 ###### output: valvar
151 23 12 35 11 276 1.916666667 11
152 False False True True False False True
154 False True True False False False
155 This is a string field theory This is a string field theory
159 z??False True w??False False
161 Unsupported suffix: 4i
164 Next we change the value of variables
167 oceani_tests += "setvar"
174 a = (a + a) * (a + a)
178 ###### output: setvar
184 oceani_tests += "consts"
190 four ::= 2 + 2 ; five ::= 10/2
191 const pie ::= "I like Pie";
192 cake ::= "The cake is"
196 print "Hello World, what lovely oceans you have!"
197 print "are there", five, "?"
198 print pi, pie, "but", cake, "Tau is", tau
200 ###### output: consts
201 Hello World, what lovely oceans you have!
203 3.141592653 I like Pie but The cake is a lie Tau is 6.283185306
205 Test merging of variables from multiple cases
208 oceani_tests += varmerge
210 ###### test: varmerge
213 for i:=0; then i=i+1; while i < 5:
216 case 1: scratch:=42; num:="one"
223 for i:=0; then i=i+1; while i < 5:
230 // re-declare a CondScope variable
235 ###### output: varmerge
236 zero , one , two , three , many ,
239 ## Conditions and Loops
241 Now we need to test if/else and some different loops
244 oceani_tests += cond_loop
246 ###### test: cond_loop
254 for b:=1; then b=b+b; while b < 100:
257 // Newtons method for square root of 2
263 current := guess * guess
264 use +(current - target) > 0.000000001
266 guess = (guess + (target / guess) ) / 2
269 print "error is ", target - guess * guess
271 for j:=0; then j = j+3 ; while j < 10:
272 if j != 0 and then 20 / j > 3:
273 print "20 /", j," =", 20 / j
275 print "I won't calculate 20 /", j
276 pi ::= 3.1415926535897
277 if 355/113 == pi or else +(pi - 355/113) < 0.001:
279 print "lower" if 355/113 < pi else "higher"
280 print "higher" if 355/113 > pi else "lower"
282 if pi > 3 then print "pi exceeds three"; else print "need more pie"
283 if (pi < 3) { print "not enough pi" } else { print "pi sufficient" }
284 for { i := 0; sum := 0 }
290 print "sum 1..10 is", sum
299 ###### output: cond_loop
306 error is -4.510950445e-12
307 I won't calculate 20 / 0
310 I won't calculate 20 / 9
321 The demonstration code presented in the interpreted is suitable for the test suite.
322 Here I break it into two parts, keeping the array code separate.
325 oceani_tests += "sayhello,55,33,hello,True"
326 oceani_tests += "sayhello,12,60,there,False"
328 ###### test: sayhello
330 func main(av:[]string)
331 A := $av[1]; B := $av[2]
334 bbool := av[l-1] == "True"
335 print "Hello World, what lovely oceans you have!"
336 /* When a variable is defined in both branches of an 'if',
337 * and used afterwards, the variables are merged.
343 print "Is", A, "bigger than", B,"? ", bigger
344 /* If a variable is not used after the 'if', no
345 * merge happens, so types can be different
348 double:string = "yes"
349 print A, "is more than twice", B, "?", double
352 print "double", B, "is", double
357 print "still", bigger // check for regression in scoping
364 print "GCD of", A, "and", B,"is", a
366 print a, "is not positive, cannot calculate GCD"
368 print b, "is not positive, cannot calculate GCD"
373 print "Fibonacci:", f1,f2,
383 print astr ++ " was the str"
385 print "I found the str over " ++ astr
387 /* Binary search... */
405 print "Yay, I found", target
407 print "Closest I found was", lo
409 ###### output: sayhello,55,33,hello,True
410 Hello World, what lovely oceans you have!
411 Is 55 bigger than 33 ? yes
414 GCD of 55 and 33 is 11
415 Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
417 Closest I found was 77.34375
419 ###### output: sayhello,12,60,there,False
420 Hello World, what lovely oceans you have!
421 Is 12 bigger than 60 ? no
424 GCD of 12 and 60 is 12
425 Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
426 I found the str over there
427 Closest I found was 77.34375
430 oceani_tests += "insert_sort"
431 ###### test: insert_sort
436 for i:=1; then i = i + 1; while i < size:
437 n := list[i-1] * list[i-1]
438 list[i] = (n / 100) % 10000
441 for i:=0; then i = i + 1; while i < size:
442 print "list[",i,"]=",list[i]
444 for i := 1; then i=i+1; while i < size:
445 for j:=i-1; then j=j-1; while j >= 0:
446 if list[j] > list[j+1]:
451 for i:=0; then i = i + 1; while i < size:
452 print "list[",i,"]=",list[i]
454 ###### output: insert_sort
570 We already have some array tests, but this is where we put other
571 ad-hoc things array related.
574 oceani_tests += arrays
582 bools[3] = strings[1] == "Hello"
583 bools[1] = strings[2] <= "there"
585 for i:=0; then i=i+1; while i<5:
589 ra[6] = 42 // mustn't crash
590 print '', bools[i], ra[j-1],
593 ###### output: arrays
594 False 0 True 1 False 4 False 9 False 16
598 Time to test if structure declarations and accesses work correctly.
601 oceani_tests += structs
608 name:string = "Hello"
610 active:Boolean = True
612 struct baz { a:number; b:Boolean; }
618 for i:=0; then i=i+1; while i < 4:
626 info[i].size[0] = i*i
628 info[i].active = False
630 for i:=0; then i=i+1; while i < 4:
631 print info[i].name, info[i].active, info[i].size[0]
632 info[0].thing.b = True
634 ###### output: structs
643 Test functions. They don't return anything, so we need to get them to print
646 oceani_tests += functions func_ret_type
648 ###### test: functions
668 func test(n:number; s:string)
685 for i:=0; then i = i + 1; while i < 5:
687 angular := to_polar(32, 23)
688 print angular.rho, angular.theta
690 ###### output: functions
695 4 3 . 2 .. 1 ... done
698 ###### test: func_ret_type
700 func double(n:number):number
716 for j:=10; then j = j - 3; while j > -5:
717 print answer("dou","ble"), j, "is", double(j)
719 ###### output: func_ret_type
728 A simple linked list example
731 oceani_tests += "linked_list,one,two,three,four"
733 ###### test: linked_list
741 func insert(list:@linkage; new:string)
743 while ?p.next and then p.next.this < new:
750 func printlist(list:@linkage)
752 print list@.next.this
753 list = list@.next.list
755 func freelist(list:@linkage)
756 if list.next != @nil:
757 lp:@linkage = list.next.list
761 func main(argv:[]string)
764 insert(list, "@start");
766 for i:=1; then i=i+1; while i < argv[]:
767 insert(list, argv[i])
768 insert(list, "Hello!")
772 ###### output: linked_list,one,two,three,four
781 ## Test code with syntax errors
783 Syntax errors aren't handled well yet - the result is almost always a
784 single message about the first error. So this section will be fairly
785 thin until we add proper parsing recovery in the face of common errors.
787 A special case of syntax errors is token errors, when a token is only
788 accepted because the parser doesn't know quite enough to reject it.
789 There are handled better as they are quite local, so a single test
790 program can trigger most of the possible errors.
792 To handle erronous code, we need a different set of tests, as we need to
793 capture `stderr`. The same test code will be used for type errors too.
794 As error messages contain the line number, and we don't want changes to
795 this file to change the reported numbers, we copy the code into a
796 separate file first, then run from there.
799 @for t in $(oceani_failing_tests); do \
800 echo -n "Test $$t ... "; \
801 ./md2c oceani-tests.mdc "output: $$t" | grep -v '^#' > .tmp.want; \
802 echo '``````' > .tmp.code; \
803 ./md2c oceani-tests.mdc "test: $$t" | grep -v '^#' >> .tmp.code; \
804 ./oceani .tmp.code > .tmp.have 2>&1; \
805 if ! cmp -s .tmp.want .tmp.have; then \
806 echo "FAILED"; diff -u .tmp.want .tmp.have ; exit 1; fi ;\
808 ./coverage_oceani --section "test: $$t" oceani-tests.mdc > /dev/null 2>&1 ;\
811 ###### combine test lists
812 oceani_valg_tests += $(oceani_failing_tests)
815 oceani_failing_tests := syn1
816 oceani_failing_tests += tokerr
821 if then else while do
824 .tmp.code:3:11: Syntax error in statement: then
828 a := 1i // imaginary numbers aren't understood
829 b:[2i]number // array sizes are handled separately
830 c:[3.14159]Boolean // array sizes must be integers
831 d:[1_000_000_000_000]number // they mustn't be huge
832 patn: string = "foo[ ,_]*bar"re // regexp strings are just a dream
835 This is a multiline string
836 With an unsupportable suffix
840 yy:[unknowable]number
842 zz:[zzsize]string // size must be constant, use ::=
844 // These numbers should be bad in all contexts: FIXME
847 ###### output: tokerr
848 .tmp.code:3:13: error: unsupported number suffix: 1i
849 .tmp.code:4:11: error: unsupported number suffix: 2i
850 .tmp.code:5:11: error: array size must be an integer: 3.14159
851 .tmp.code:6:11: error: array size is too large: 1_000_000_000_000
852 .tmp.code:7:23: error: unsupported string suffix: "foo[ ,_]*bar"re
853 .tmp.code:9:17: error: unsupported string suffix: """
854 This is a multiline string
855 With an unsupportable suffix
857 .tmp.code:15:12: error: name undeclared: unknowable
858 .tmp.code:17:12: error: array size must be a constant: zzsize
859 .tmp.code:20:12: error: unrecognised number: 00123
860 .tmp.code:14:11: error: type used but not declared: unknown
862 ## Tests for type errors
864 Type error don't cause parsing to abort, so we can fit many in the
865 one test program. Some type errors are found during the parse, others
866 during type analysis which doesn't run if parsing failed. So we cannot
867 fit everything in one.
869 These programs were generated by looking for the
870 various places that `type_err()` are called.
873 oceani_failing_tests += type_err1 type_err2 type_err3 type_err4 type_err5 type_err6
875 ###### test: type_err1
878 print "hello" ++ 5, 5 ++ "hello"
883 if 3 * 4 and not True: print "Weird"
887 ###### output: type_err1
888 .tmp.code:3:25: error: expected string found number
889 .tmp.code:3:28: error: expected string found number
890 .tmp.code:6:8: error: Cannot assign to a constant: b
891 .tmp.code:5:8: info: name was defined as a constant here
892 .tmp.code:8:11: error: Arithmetic returns number but Boolean expected
893 .tmp.code:9:20: error: expected number found label
894 .tmp.code:9:8: info: variable 'd' was set as number here.
895 .tmp.code:10:8: error: cannot assign to an rval
896 oceani: type error in program - not running.
898 ###### test: type_err2
909 ###### output: type_err2
910 .tmp.code:4:8: error: variable 'a' redeclared
911 .tmp.code:3:8: info: this is where 'a' was first declared
912 .tmp.code:5:8: error: variable 'a' redeclared
913 .tmp.code:3:8: info: this is where 'a' was first declared
914 .tmp.code:6:8: error: variable 'a' redeclared
915 .tmp.code:3:8: info: this is where 'a' was first declared
916 .tmp.code:7:8: error: variable 'a' redeclared
917 .tmp.code:3:8: info: this is where 'a' was first declared
918 .tmp.code:8:8: Variable declared with no type or value: c
919 .tmp.code:9:19: error: unsupported number format: 02
921 ###### test: type_err3
925 b:string = "hello"; d:Boolean
930 c = "hello" ++ (True and False)
932 print 45 + ( "Hello" ++ "there")
942 case "Hello": print "Hello"
944 a1:[5]number; a2:[5]number; a3:[10]number; a4:[5]string
958 // trigger 'labels not permitted' error message
959 while 1 if True else False:
962 print "one" ++ a4[], c[]
972 ###### output: type_err3
973 .tmp.code:8:12: error: expected number but variable 'c' is string
974 .tmp.code:7:8: info: this is where 'c' was set to string
975 .tmp.code:8:12: error: Arithmetic returns number but string expected
976 .tmp.code:7:8: info: variable 'c' was set as string here.
977 .tmp.code:9:24: error: Boolean operation found where string expected
978 .tmp.code:7:8: info: variable 'c' was set as string here.
979 .tmp.code:10:12: error: Comparison returns Boolean but string expected
980 .tmp.code:7:8: info: variable 'c' was set as string here.
981 .tmp.code:11:21: error: Concat returns string but number expected
982 .tmp.code:12:8: error: string cannot be indexed
983 .tmp.code:12:8: error: string cannot be indexed
984 .tmp.code:21:13: error: expected number found string
985 .tmp.code:17:16: error: expected number, found string
986 .tmp.code:24:8: error: cannot assign value of type [5]number
987 .tmp.code:25:13: error: expected [5]number but variable 'a3' is [10]number
988 .tmp.code:23:36: info: this is where 'a3' was set to [10]number
989 .tmp.code:25:8: error: cannot assign value of type [5]number
990 .tmp.code:23:8: info: variable 'a1' was set as [5]number here.
991 .tmp.code:26:13: error: expected [5]number but variable 'a4' is [5]string
992 .tmp.code:23:51: info: this is where 'a4' was set to [5]string
993 .tmp.code:26:8: error: cannot assign value of type [5]number
994 .tmp.code:23:8: info: variable 'a1' was set as [5]number here.
995 .tmp.code:27:16: error: expected number found string
996 .tmp.code:28:16: error: expected string found Boolean
997 .tmp.code:29:12: error: have number but need string
998 .tmp.code:7:8: info: variable 'c' was set as string here.
999 .tmp.code:32:8: error: variable used but not declared: foo
1000 .tmp.code:32:8: error: field reference on none is not supported
1001 .tmp.code:32:16: error: expected none found number
1002 .tmp.code:33:14: error: field reference on string is not supported
1003 .tmp.code:34:14: error: cannot find requested field in foo
1004 .tmp.code:35:17: error: have string but need number
1005 .tmp.code:38:29: error: expected number found Boolean
1006 .tmp.code:41:23: error: have number but need string
1007 .tmp.code:41:29: error: string cannot provide length
1008 .tmp.code:43:21: error: Can only convert string to number, not Boolean
1009 .tmp.code:43:8: info: variable 'x' was set as Boolean here.
1010 .tmp.code:49:13: error: expected [five]number but variable 'x2' is [four]number
1011 .tmp.code:48:8: info: this is where 'x2' was set to [four]number
1012 .tmp.code:49:8: error: cannot assign value of type [five]number
1013 .tmp.code:47:8: info: variable 'x1' was set as [five]number here.
1014 oceani: type error in program - not running.
1016 ###### test: type_err4
1021 ###### output: type_err4
1022 .tmp.code:3:14: error: variable used but not declared: b
1023 .tmp.code:3:16: error: expected none found number
1024 .tmp.code:3:14: info: variable 'b' was set as none here.
1025 oceani: type error in program - not running.
1027 ###### test: type_err5
1038 ###### output: type_err5
1039 .tmp.code:8:7: error: type already declared: foo
1040 .tmp.code:2:7: info: this is location of declartion: foo
1041 .tmp.code:10:13: Syntax error in struct field: :
1042 .tmp.code:5:7: error: type has recursive definition: baz
1043 .tmp.code:2:7: error: type has recursive definition: foo
1045 ###### test: type_err6
1053 ###### output: type_err6
1054 .tmp.code:4:12: error: '?' requires a testable value, not string
1055 .tmp.code:6:14: error: "??" requires a testable value, not string
1056 oceani: type error in program - not running.
1060 oceani_failing_tests += type_err_const type_err_const1 type_err_const2 missing_program bad_main
1062 ###### test: type_err_const
1065 bar ::= "string" + 56
1072 // trigger duplicate-main error
1077 ###### output: type_err_const
1078 .tmp.code:6:8: error: name already declared: bar
1079 .tmp.code:4:8: info: this is where 'bar' was first declared
1080 .tmp.code:8:8: error: variable 'foo' redeclared
1081 .tmp.code:3:8: info: this is where 'foo' was first declared
1082 .tmp.code:12:5: error: function 'main' redeclared
1083 .tmp.code:7:5: info: this is where 'main' was first declared
1084 .tmp.code:13:8: error: variable 'foo' redeclared
1085 .tmp.code:3:8: info: this is where 'foo' was first declared
1086 .tmp.code:4:16: error: expected number found string
1088 ###### test: type_err_const1
1096 ###### output: type_err_const1
1097 .tmp.code:3:12: Syntax error in constant: :
1098 .tmp.code:4:12: Syntax error in constant: :
1100 ###### test: type_err_const2
1105 ###### output: type_err_const2
1106 .tmp.code:3:8: error: const four cannot be resolved.
1107 .tmp.code:4:8: error: const two cannot be resolved.
1109 ###### test: missing_program
1113 ###### output: missing_program
1114 oceani: no main function found.
1116 ###### test: bad_main
1117 func main(foo:string)
1120 ###### output: bad_main
1121 .tmp.code:2:10: error: expected []string but variable 'foo' is string
1122 .tmp.code:2:10: info: this is where 'foo' was set to string
1123 oceani: main has wrong type.
1125 Test for type errors with functions
1128 oceani_failing_tests += func_err_args func_err_redeclare
1130 ###### test: func_err_args
1132 func test1(a:number; b:string; c:[3]Boolean)
1135 func test2(a:number; b:string; c:[3]Boolean)
1139 # use undefined names
1147 test1(1, "two", truth)
1149 test1(1, "lo", truth, 4)
1150 print test(), test1(1,2,3)
1154 func test4(a:number):string
1157 func test5(a:number):string
1164 func test6(a:number):foo
1169 func test7(a:@number)
1173 ###### output: func_err_args
1174 .tmp.code:40:14: error: cannot pass rval when reference expected
1175 .tmp.code:41:14: error: expected @number found string
1176 .tmp.code:34:5: error: function cannot return value of type foo
1177 .tmp.code:28:8: error: expected string, found none
1178 .tmp.code:25:8: error: expected string, found number
1179 .tmp.code:15:14: error: insufficient arguments to function.
1180 .tmp.code:16:14: error: expected number found string
1181 .tmp.code:16:22: error: expected string found number
1182 .tmp.code:16:14: error: insufficient arguments to function.
1183 .tmp.code:18:17: error: expected string found number
1184 .tmp.code:19:14: error: too many arguments to function.
1185 .tmp.code:20:14: error: attempt to call a non-function.
1186 .tmp.code:20:32: error: expected string found number
1187 .tmp.code:20:28: error: insufficient arguments to function.
1188 .tmp.code:21:20: error: expected "func test1" but variable 'test2' is "func test2"
1189 .tmp.code:5:5: info: this is where 'test2' was set to "func test2"
1190 .tmp.code:10:14: error: variable used but not declared: a
1191 .tmp.code:10:17: error: variable used but not declared: z
1192 oceani: type error in program - not running.
1194 ###### test: func_err_redeclare
1196 func test1(a:number; b:string; c:[3]Boolean)
1208 ###### output: func_err_redeclare
1209 .tmp.code:5:5: error: function 'test1' redeclared
1210 .tmp.code:2:5: info: this is where 'test1' was first declared
1211 .tmp.code:9:5: error: function 'test1' redeclared
1212 .tmp.code:2:5: info: this is where 'test1' was first declared
1214 Test for errors with references
1217 oceani_failing_tests += ref_err1 ref_err2
1219 ###### test: ref_err1
1227 ###### output: ref_err1
1228 .tmp.code:4:9: error: only "@free" makes sense here: foo
1229 .tmp.code:5:15: error: Only reference function is "@new()": old
1230 .tmp.code:6:19: error: Only reference value is "@nil": null
1232 ###### test: ref_err2
1238 if num == @nil or ref == ref2 or ref == 2 or ref.foo:
1242 ###### output: ref_err2
1243 .tmp.code:5:22: error: @new() can only be used with references, not number
1244 .tmp.code:5:8: info: variable 'num' was set as number here.
1245 .tmp.code:6:14: error: Cannot dereference number
1246 .tmp.code:7:19: error: @nil can only be used with reference, not number
1247 .tmp.code:7:33: error: expected @number but variable 'ref2' is @string
1248 .tmp.code:4:8: info: this is where 'ref2' was set to @string
1249 .tmp.code:7:48: error: expected @number found number
1250 .tmp.code:7:53: error: field reference on number is not supported
1251 .tmp.code:7:56: error: have none but need Boolean
1252 .tmp.code:8:17: error: @free can only be assigned a reference, not number
1253 .tmp.code:8:17: error: @free can only be assigned a reference, not number
1254 .tmp.code:9:8: error: Cannot assign an rval to a reference.
1255 oceani: type error in program - not running.
1257 ## Test erroneous command line args
1259 To improve coverage, we want to test correct handling of strange command
1260 line arguments. These tests won't use code, so the exiting test types
1261 won't work. So we need to be able to explicitly give the command line,
1262 and the expected output, and have that tested and the coverage assessed.
1263 Rather than having to spell out the whole command name, just give "cmd",
1264 and discard that. Requiring but discarding the command make an empty
1265 command list possible.
1268 @for t in $(oceani_special_tests); do \
1269 echo -n "Test $$t ... ";\
1270 i="$$IFS"; IFS=,; set $$t; IFS="$$i"; shift ;\
1271 ./md2c oceani-tests.mdc "output: $$t" | grep -v '^#' > .tmp.want; \
1272 ./oceani $${1+"$$@"} > .tmp.have 2>&1 ;\
1273 if ! cmp -s .tmp.want .tmp.have; then \
1274 echo "FAILED"; diff -u .tmp.want .tmp.have ; exit 1; fi ;\
1276 ./coverage_oceani $${1+"$$@"} > /dev/null 2>&1 ;\
1278 ###### valgrind test code
1279 @[ -n "$$SKIP_VALGRIND" ] || for t in $(oceani_special_tests); do\
1280 echo -n "Valgrind $$t.. "; \
1281 i="$$IFS"; IFS=,; set $$t; IFS="$$i"; shift ;\
1282 if valgrind --error-exitcode=42 --log-file=.tmp.valg ./oceani $${1+"$$@"} > .tmp.have 2>&1 ;\
1283 [ $$? -eq 42 ]; then \
1284 echo "FAILED"; cat .tmp.valg; exit 1; fi ; \
1285 if grep 'LEAK SUMMARY' .tmp.valg > /dev/null; then \
1286 echo "valgrind found LEAKS"; cat .tmp.valg ; exit 1 ; fi; \
1287 if grep 'in use at exit [1-9]' .tmp.valg > /dev/null; then \
1288 echo "valgrind found memory in use at exit"; cat .tmp.valg ; exit 1 ; fi; \
1293 oceani_special_tests += "cmd"
1294 oceani_special_tests += "cmd,-zyx"
1295 oceani_special_tests += "cmd,nofile"
1296 oceani_special_tests += "cmd,/dev/null"
1297 oceani_special_tests += "cmd,--section,toast:nothing,oceani-tests.mdc"
1300 oceani: no input file given
1302 ###### output: cmd,-zyx
1303 ./oceani: invalid option -- 'z'
1304 Usage: oceani --trace --print --noexec --brackets --section=SectionName prog.ocn
1306 ###### output: cmd,nofile
1307 oceani: cannot open nofile
1309 ###### output: cmd,/dev/null
1310 oceani: could not find any code in /dev/null
1312 ###### output: cmd,--section,toast:nothing,oceani-tests.mdc
1313 oceani: cannot find section toast:nothing