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.99) 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:
225 case 0: num:="zero" ;
227 case 2 { num:="two" } case 3 { num:="three" }
229 // re-declare a CondScope variable
234 ###### output: varmerge
235 zero , one , two , three , many ,
238 ## Conditions and Loops
240 Now we need to test if/else and some different loops
243 oceani_tests += cond_loop
245 ###### test: cond_loop
253 for b:=1; then b=b+b; while b < 100:
256 // Newtons method for square root of 2
262 current := guess * guess
263 use +(current - target) > 0.000000001
265 guess = (guess + (target / guess) ) / 2
268 print "error is ", target - guess * guess
270 for j:=0; then j = j+3 ; while j < 10:
271 if j != 0 and then 20 / j > 3:
272 print "20 /", j," =", 20 / j
274 print "I won't calculate 20 /", j
275 pi ::= 3.1415926535897
276 if 355/113 == pi or else +(pi - 355/113) < 0.001:
278 print "lower" if 355/113 < pi else "higher"
279 print "higher" if 355/113 > pi else "lower"
281 if pi > 3 then print "pi exceeds three"; else print "need more pie"
282 if (pi < 3) { print "not enough pi" } else { print "pi sufficient" }
283 for { i := 0; sum := 0 }
289 print "sum 1..10 is", sum
298 ###### output: cond_loop
305 error is -4.510950445e-12
306 I won't calculate 20 / 0
309 I won't calculate 20 / 9
320 The demonstration code presented in the interpreted is suitable for the test suite.
321 Here I break it into two parts, keeping the array code separate.
324 oceani_tests += "sayhello,55,33,hello,True"
325 oceani_tests += "sayhello,12,60,there,False"
327 ###### test: sayhello
329 func main(av:[]string)
330 A := $av[1]; B := $av[2]
333 bbool := av[l-1] == "True"
334 print "Hello World, what lovely oceans you have!"
335 /* When a variable is defined in both branches of an 'if',
336 * and used afterwards, the variables are merged.
342 print "Is", A, "bigger than", B,"? ", bigger
343 /* If a variable is not used after the 'if', no
344 * merge happens, so types can be different
347 double:string = "yes"
348 print A, "is more than twice", B, "?", double
351 print "double", B, "is", double
356 print "still", bigger // check for regression in scoping
363 print "GCD of", A, "and", B,"is", a
365 print a, "is not positive, cannot calculate GCD"
367 print b, "is not positive, cannot calculate GCD"
372 print "Fibonacci:", f1,f2,
382 print astr ++ " was the str"
384 print "I found the str over " ++ astr
386 /* Binary search... */
404 print "Yay, I found", target
406 print "Closest I found was", lo
408 ###### output: sayhello,55,33,hello,True
409 Hello World, what lovely oceans you have!
410 Is 55 bigger than 33 ? yes
413 GCD of 55 and 33 is 11
414 Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
416 Closest I found was 77.34375
418 ###### output: sayhello,12,60,there,False
419 Hello World, what lovely oceans you have!
420 Is 12 bigger than 60 ? no
423 GCD of 12 and 60 is 12
424 Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
425 I found the str over there
426 Closest I found was 77.34375
429 oceani_tests += "insert_sort"
430 ###### test: insert_sort
435 for i:=1; then i = i + 1; while i < size:
436 n := list[i-1] * list[i-1]
437 list[i] = (n / 100) % 10000
440 for i:=0; then i = i + 1; while i < size:
441 print "list[",i,"]=",list[i]
443 for i := 1; then i=i+1; while i < size:
444 for j:=i-1; then j=j-1; while j >= 0:
445 if list[j] > list[j+1]:
450 for i:=0; then i = i + 1; while i < size:
451 print "list[",i,"]=",list[i]
453 ###### output: insert_sort
569 We already have some array tests, but this is where we put other
570 ad-hoc things array related.
573 oceani_tests += arrays
581 bools[3] = strings[1] == "Hello"
582 bools[1] = strings[2] <= "there"
584 for i:=0; then i=i+1; while i<5:
588 ra[6] = 42 // mustn't crash
589 print '', bools[i], ra[j-1],
592 ###### output: arrays
593 False 0 True 1 False 4 False 9 False 16
597 Time to test if structure declarations and accesses work correctly.
600 oceani_tests += structs
607 name:string = "Hello"
609 active:Boolean = True
611 struct baz { a:number; b:Boolean; }
616 struct bat2 a:string; b:Boolean
622 for i:=0; then i=i+1; while i < 4:
630 info[i].size[0] = i*i
632 info[i].active = False
634 for i:=0; then i=i+1; while i < 4:
635 print info[i].name, info[i].active, info[i].size[0]
636 info[0].thing.b = True
640 ###### output: structs
649 Test functions. They don't return anything, so we need to get them to print
652 oceani_tests += functions func_ret_type
654 ###### test: functions
674 func test(n:number; s:string)
691 for i:=0; then i = i + 1; while i < 5:
693 angular := to_polar(32, 23)
694 print angular.rho, angular.theta
696 func test2(n:number; s:string;) : (ret:number)
705 // exercise the parsing options
709 func t2 (a:string) {print "string"}
712 ###### output: functions
717 4 3 . 2 .. 1 ... done
720 ###### test: func_ret_type
722 func double(n:number):number
738 for j:=10; then j = j - 3; while j > -5:
739 print answer("dou","ble"), j, "is", double(j)
741 ###### output: func_ret_type
750 A simple linked list example
753 oceani_tests += "linked_list,one,two,three,four"
755 ###### test: linked_list
763 func insert(list:@linkage; new:string)
765 while ?p.next and then p.next.this < new:
772 func printlist(list:@linkage)
774 print list@.next.this
775 list = list@.next.list
777 func freelist(list:@linkage)
778 if list.next != @nil:
779 lp:@linkage = list.next.list
783 func main(argv:[]string)
786 insert(list, "@start");
788 for i:=1; then i=i+1; while i < argv[]:
789 insert(list, argv[i])
790 insert(list, "Hello!")
794 ###### output: linked_list,one,two,three,four
803 ## Test code with syntax errors
805 Syntax errors aren't handled well yet - the result is almost always a
806 single message about the first error. So this section will be fairly
807 thin until we add proper parsing recovery in the face of common errors.
809 A special case of syntax errors is token errors, when a token is only
810 accepted because the parser doesn't know quite enough to reject it.
811 There are handled better as they are quite local, so a single test
812 program can trigger most of the possible errors.
814 To handle erronous code, we need a different set of tests, as we need to
815 capture `stderr`. The same test code will be used for type errors too.
816 As error messages contain the line number, and we don't want changes to
817 this file to change the reported numbers, we copy the code into a
818 separate file first, then run from there.
821 @for t in $(oceani_failing_tests); do \
822 echo -n "Test $$t ... "; \
823 ./md2c oceani-tests.mdc "output: $$t" | grep -v '^#' > .tmp.want; \
824 echo '``````' > .tmp.code; \
825 ./md2c oceani-tests.mdc "test: $$t" | grep -v '^#' >> .tmp.code; \
826 ./oceani .tmp.code > .tmp.have 2>&1; \
827 if ! cmp -s .tmp.want .tmp.have; then \
828 echo "FAILED"; diff -u .tmp.want .tmp.have ; exit 1; fi ;\
830 ./coverage_oceani --section "test: $$t" oceani-tests.mdc > /dev/null 2>&1 ;\
833 ###### combine test lists
834 oceani_valg_tests += $(oceani_failing_tests)
837 oceani_failing_tests := syn1
838 oceani_failing_tests += tokerr
843 if then else while do
846 .tmp.code:3:11: Syntax error in statement: then
850 a := 1i // imaginary numbers aren't understood
851 b:[2i]number // array sizes are handled separately
852 c:[3.14159]Boolean // array sizes must be integers
853 d:[1_000_000_000_000]number // they mustn't be huge
854 patn: string = "foo[ ,_]*bar"re // regexp strings are just a dream
857 This is a multiline string
858 With an unsupportable suffix
862 yy:[unknowable]number
864 zz:[zzsize]string // size must be constant, use ::=
866 // These numbers should be bad in all contexts: FIXME
869 ###### output: tokerr
870 .tmp.code:3:13: error: unsupported number suffix: 1i
871 .tmp.code:4:11: error: unsupported number suffix: 2i
872 .tmp.code:5:11: error: array size must be an integer: 3.14159
873 .tmp.code:6:11: error: array size is too large: 1_000_000_000_000
874 .tmp.code:7:23: error: unsupported string suffix: "foo[ ,_]*bar"re
875 .tmp.code:9:17: error: unsupported string suffix: """
876 This is a multiline string
877 With an unsupportable suffix
879 .tmp.code:15:12: error: name undeclared: unknowable
880 .tmp.code:17:12: error: array size must be a constant: zzsize
881 .tmp.code:20:12: error: unrecognised number: 00123
882 .tmp.code:14:11: error: type used but not declared: unknown
884 ## Tests for type errors
886 Type error don't cause parsing to abort, so we can fit many in the
887 one test program. Some type errors are found during the parse, others
888 during type analysis which doesn't run if parsing failed. So we cannot
889 fit everything in one.
891 These programs were generated by looking for the
892 various places that `type_err()` are called.
895 oceani_failing_tests += type_err1 type_err2 type_err3 type_err4 type_err5 type_err6
897 ###### test: type_err1
900 print "hello" ++ 5, 5 ++ "hello"
905 if 3 * 4 and not True: print "Weird"
909 ###### output: type_err1
910 .tmp.code:3:25: error: expected string found number
911 .tmp.code:3:28: error: expected string found number
912 .tmp.code:6:8: error: Cannot assign to a constant: b
913 .tmp.code:5:8: info: name was defined as a constant here
914 .tmp.code:8:11: error: Arithmetic returns number but Boolean expected
915 .tmp.code:9:20: error: expected number found label
916 .tmp.code:9:8: info: variable 'd' was set as number here.
917 .tmp.code:10:8: error: cannot assign to an rval
918 oceani: type error in program - not running.
920 ###### test: type_err2
931 ###### output: type_err2
932 .tmp.code:4:8: error: variable 'a' redeclared
933 .tmp.code:3:8: info: this is where 'a' was first declared
934 .tmp.code:5:8: error: variable 'a' redeclared
935 .tmp.code:3:8: info: this is where 'a' was first declared
936 .tmp.code:6:8: error: variable 'a' redeclared
937 .tmp.code:3:8: info: this is where 'a' was first declared
938 .tmp.code:7:8: error: variable 'a' redeclared
939 .tmp.code:3:8: info: this is where 'a' was first declared
940 .tmp.code:8:8: Variable declared with no type or value: c
941 .tmp.code:9:19: error: unsupported number format: 02
943 ###### test: type_err3
947 b:string = "hello"; d:Boolean
952 c = "hello" ++ (True and False)
954 print 45 + ( "Hello" ++ "there")
964 case "Hello": print "Hello"
966 a1:[5]number; a2:[5]number; a3:[10]number; a4:[5]string
980 // trigger 'labels not permitted' error message
981 while 1 if True else False:
984 print "one" ++ a4[], c[]
994 ###### output: type_err3
995 .tmp.code:8:12: error: expected number but variable 'c' is string
996 .tmp.code:7:8: info: this is where 'c' was set to string
997 .tmp.code:8:12: error: Arithmetic returns number but string expected
998 .tmp.code:7:8: info: variable 'c' was set as string here.
999 .tmp.code:9:24: error: Boolean operation found where string expected
1000 .tmp.code:7:8: info: variable 'c' was set as string here.
1001 .tmp.code:10:12: error: Comparison returns Boolean but string expected
1002 .tmp.code:7:8: info: variable 'c' was set as string here.
1003 .tmp.code:11:21: error: Concat returns string but number expected
1004 .tmp.code:12:8: error: string cannot be indexed
1005 .tmp.code:12:8: error: string cannot be indexed
1006 .tmp.code:21:13: error: expected number found string
1007 .tmp.code:17:16: error: expected number, found string
1008 .tmp.code:24:8: error: cannot assign value of type [5]number
1009 .tmp.code:25:13: error: expected [5]number but variable 'a3' is [10]number
1010 .tmp.code:23:36: info: this is where 'a3' was set to [10]number
1011 .tmp.code:25:8: error: cannot assign value of type [5]number
1012 .tmp.code:23:8: info: variable 'a1' was set as [5]number here.
1013 .tmp.code:26:13: error: expected [5]number but variable 'a4' is [5]string
1014 .tmp.code:23:51: info: this is where 'a4' was set to [5]string
1015 .tmp.code:26:8: error: cannot assign value of type [5]number
1016 .tmp.code:23:8: info: variable 'a1' was set as [5]number here.
1017 .tmp.code:27:16: error: expected number found string
1018 .tmp.code:28:16: error: expected string found Boolean
1019 .tmp.code:29:12: error: have number but need string
1020 .tmp.code:7:8: info: variable 'c' was set as string here.
1021 .tmp.code:32:8: error: variable used but not declared: foo
1022 .tmp.code:32:8: error: field reference on none is not supported
1023 .tmp.code:32:16: error: expected none found number
1024 .tmp.code:33:14: error: field reference on string is not supported
1025 .tmp.code:34:14: error: cannot find requested field in foo
1026 .tmp.code:35:17: error: have string but need number
1027 .tmp.code:38:29: error: expected number found Boolean
1028 .tmp.code:41:23: error: have number but need string
1029 .tmp.code:41:29: error: string cannot provide length
1030 .tmp.code:43:21: error: Can only convert string to number, not Boolean
1031 .tmp.code:43:8: info: variable 'x' was set as Boolean here.
1032 .tmp.code:49:13: error: expected [five]number but variable 'x2' is [four]number
1033 .tmp.code:48:8: info: this is where 'x2' was set to [four]number
1034 .tmp.code:49:8: error: cannot assign value of type [five]number
1035 .tmp.code:47:8: info: variable 'x1' was set as [five]number here.
1036 oceani: type error in program - not running.
1038 ###### test: type_err4
1043 ###### output: type_err4
1044 .tmp.code:3:14: error: variable used but not declared: b
1045 .tmp.code:3:16: error: expected none found number
1046 .tmp.code:3:14: info: variable 'b' was set as none here.
1047 oceani: type error in program - not running.
1049 ###### test: type_err5
1060 ###### output: type_err5
1061 .tmp.code:8:7: error: type already declared: foo
1062 .tmp.code:2:7: info: this is location of declartion: foo
1063 .tmp.code:10:13: Syntax error in struct field: :
1064 .tmp.code:5:7: error: type has recursive definition: baz
1065 .tmp.code:2:7: error: type has recursive definition: foo
1067 ###### test: type_err6
1075 ###### output: type_err6
1076 .tmp.code:4:12: error: '?' requires a testable value, not string
1077 .tmp.code:6:14: error: "??" requires a testable value, not string
1078 oceani: type error in program - not running.
1082 oceani_failing_tests += type_err_const type_err_const1 type_err_const2 missing_program bad_main
1084 ###### test: type_err_const
1087 bar ::= "string" + 56
1094 // trigger duplicate-main error
1099 ###### output: type_err_const
1100 .tmp.code:6:8: error: name already declared: bar
1101 .tmp.code:4:8: info: this is where 'bar' was first declared
1102 .tmp.code:8:8: error: variable 'foo' redeclared
1103 .tmp.code:3:8: info: this is where 'foo' was first declared
1104 .tmp.code:12:5: error: function 'main' redeclared
1105 .tmp.code:7:5: info: this is where 'main' was first declared
1106 .tmp.code:13:8: error: variable 'foo' redeclared
1107 .tmp.code:3:8: info: this is where 'foo' was first declared
1108 .tmp.code:4:16: error: expected number found string
1110 ###### test: type_err_const1
1118 ###### output: type_err_const1
1119 .tmp.code:3:12: Syntax error in constant: :
1120 .tmp.code:4:12: Syntax error in constant: :
1122 ###### test: type_err_const2
1127 ###### output: type_err_const2
1128 .tmp.code:3:8: error: const four cannot be resolved.
1129 .tmp.code:4:8: error: const two cannot be resolved.
1131 ###### test: missing_program
1135 ###### output: missing_program
1136 oceani: no main function found.
1138 ###### test: bad_main
1139 func main(foo:string)
1142 ###### output: bad_main
1143 .tmp.code:2:10: error: expected []string but variable 'foo' is string
1144 .tmp.code:2:10: info: this is where 'foo' was set to string
1145 oceani: main has wrong type.
1147 Test for type errors with functions
1150 oceani_failing_tests += func_err_args func_err_redeclare
1152 ###### test: func_err_args
1154 func test1(a:number; b:string; c:[3]Boolean)
1157 func test2(a:number; b:string; c:[3]Boolean)
1161 # use undefined names
1169 test1(1, "two", truth)
1171 test1(1, "lo", truth, 4)
1172 print test(), test1(1,2,3)
1176 func test4(a:number):string
1179 func test5(a:number):string
1186 func test6(a:number):foo
1191 func test7(a:@number)
1195 ###### output: func_err_args
1196 .tmp.code:40:14: error: cannot pass rval when reference expected
1197 .tmp.code:41:14: error: expected @number found string
1198 .tmp.code:34:5: error: function cannot return value of type foo
1199 .tmp.code:28:8: error: expected string, found none
1200 .tmp.code:25:8: error: expected string, found number
1201 .tmp.code:15:14: error: insufficient arguments to function.
1202 .tmp.code:16:14: error: expected number found string
1203 .tmp.code:16:22: error: expected string found number
1204 .tmp.code:16:14: error: insufficient arguments to function.
1205 .tmp.code:18:17: error: expected string found number
1206 .tmp.code:19:14: error: too many arguments to function.
1207 .tmp.code:20:14: error: attempt to call a non-function.
1208 .tmp.code:20:32: error: expected string found number
1209 .tmp.code:20:28: error: insufficient arguments to function.
1210 .tmp.code:21:20: error: expected "func test1" but variable 'test2' is "func test2"
1211 .tmp.code:5:5: info: this is where 'test2' was set to "func test2"
1212 .tmp.code:10:14: error: variable used but not declared: a
1213 .tmp.code:10:17: error: variable used but not declared: z
1214 oceani: type error in program - not running.
1216 ###### test: func_err_redeclare
1218 func test1(a:number; b:string; c:[3]Boolean)
1230 ###### output: func_err_redeclare
1231 .tmp.code:5:5: error: function 'test1' redeclared
1232 .tmp.code:2:5: info: this is where 'test1' was first declared
1233 .tmp.code:9:5: error: function 'test1' redeclared
1234 .tmp.code:2:5: info: this is where 'test1' was first declared
1236 Test for errors with references
1239 oceani_failing_tests += ref_err1 ref_err2
1241 ###### test: ref_err1
1249 ###### output: ref_err1
1250 .tmp.code:4:9: error: only "@free" makes sense here: foo
1251 .tmp.code:5:15: error: Only reference function is "@new()": old
1252 .tmp.code:6:19: error: Only reference value is "@nil": null
1254 ###### test: ref_err2
1260 if num == @nil or ref == ref2 or ref == 2 or ref.foo:
1264 ###### output: ref_err2
1265 .tmp.code:5:22: error: @new() can only be used with references, not number
1266 .tmp.code:5:8: info: variable 'num' was set as number here.
1267 .tmp.code:6:14: error: Cannot dereference number
1268 .tmp.code:7:19: error: @nil can only be used with reference, not number
1269 .tmp.code:7:33: error: expected @number but variable 'ref2' is @string
1270 .tmp.code:4:8: info: this is where 'ref2' was set to @string
1271 .tmp.code:7:48: error: expected @number found number
1272 .tmp.code:7:53: error: field reference on number is not supported
1273 .tmp.code:7:56: error: have none but need Boolean
1274 .tmp.code:8:17: error: @free can only be assigned a reference, not number
1275 .tmp.code:8:17: error: @free can only be assigned a reference, not number
1276 .tmp.code:9:8: error: Cannot assign an rval to a reference.
1277 oceani: type error in program - not running.
1279 ## Test erroneous command line args
1281 To improve coverage, we want to test correct handling of strange command
1282 line arguments. These tests won't use code, so the exiting test types
1283 won't work. So we need to be able to explicitly give the command line,
1284 and the expected output, and have that tested and the coverage assessed.
1285 Rather than having to spell out the whole command name, just give "cmd",
1286 and discard that. Requiring but discarding the command make an empty
1287 command list possible.
1290 @for t in $(oceani_special_tests); do \
1291 echo -n "Test $$t ... ";\
1292 i="$$IFS"; IFS=,; set $$t; IFS="$$i"; shift ;\
1293 ./md2c oceani-tests.mdc "output: $$t" | grep -v '^#' > .tmp.want; \
1294 ./oceani $${1+"$$@"} > .tmp.have 2>&1 ;\
1295 if ! cmp -s .tmp.want .tmp.have; then \
1296 echo "FAILED"; diff -u .tmp.want .tmp.have ; exit 1; fi ;\
1298 ./coverage_oceani $${1+"$$@"} > /dev/null 2>&1 ;\
1300 ###### valgrind test code
1301 @[ -n "$$SKIP_VALGRIND" ] || for t in $(oceani_special_tests); do\
1302 echo -n "Valgrind $$t.. "; \
1303 i="$$IFS"; IFS=,; set $$t; IFS="$$i"; shift ;\
1304 if valgrind --error-exitcode=42 --log-file=.tmp.valg ./oceani $${1+"$$@"} > .tmp.have 2>&1 ;\
1305 [ $$? -eq 42 ]; then \
1306 echo "FAILED"; cat .tmp.valg; exit 1; fi ; \
1307 if grep 'LEAK SUMMARY' .tmp.valg > /dev/null; then \
1308 echo "valgrind found LEAKS"; cat .tmp.valg ; exit 1 ; fi; \
1309 if grep 'in use at exit [1-9]' .tmp.valg > /dev/null; then \
1310 echo "valgrind found memory in use at exit"; cat .tmp.valg ; exit 1 ; fi; \
1315 oceani_special_tests += "cmd"
1316 oceani_special_tests += "cmd,-zyx"
1317 oceani_special_tests += "cmd,nofile"
1318 oceani_special_tests += "cmd,/dev/null"
1319 oceani_special_tests += "cmd,--section,toast:nothing,oceani-tests.mdc"
1322 oceani: no input file given
1324 ###### output: cmd,-zyx
1325 ./oceani: invalid option -- 'z'
1326 Usage: oceani --trace --print --noexec --brackets --section=SectionName prog.ocn
1328 ###### output: cmd,nofile
1329 oceani: cannot open nofile
1331 ###### output: cmd,/dev/null
1332 oceani: could not find any code in /dev/null
1334 ###### output: cmd,--section,toast:nothing,oceani-tests.mdc
1335 oceani: cannot find section toast:nothing