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 "brackets.. "; \
70 echo '``````' > .tmp.code2b ; echo '``````' > .tmp.code2c ;\
71 ./oceani --noexec --print --brackets .tmp.code1 >> .tmp.code2b || exit 1; \
72 ./oceani -npb .tmp.code2b >> .tmp.code2c || exit 1 ; \
73 if ! cmp -s .tmp.code2b .tmp.code2c; then \
74 echo " Failed"; diff -u .tmp.code2b .tmp.code2c; exit 1; fi; \
75 echo -n "exec-after-print.. "; \
76 ./oceani .tmp.code1 $${1+"$$@"} > .tmp.have ; \
77 if ! cmp -s .tmp.want .tmp.have; then \
78 echo " FAILED"; diff -u .tmp.want .tmp.have; exit 1;fi; \
80 ./coverage_oceani --print --section "test: $$t" oceani-tests.mdc $${1+"$$@"} > /dev/null ; \
81 ./coverage_oceani -tpbn --section "test: $$t" oceani-tests.mdc > /dev/null 2>&1; \
86 @for i in coverage/#*.gcda; do mv $$i coverage/$${i##*#}; done
87 @gcov -o coverage oceani.mdc > /dev/null 2> /dev/null
88 @mv *.gcov coverage ; [ -f .gcov ] && mv .gcov coverage || true
91 @[ -n "$$SKIP_VALGRIND" ] || for T in $(oceani_valg_tests); do \
92 echo -n "Valgrind $$T.. "; \
93 i="$$IFS"; IFS=,; set $$T; IFS="$$i"; t=$$1; shift; \
94 if valgrind --error-exitcode=42 --log-file=.tmp.valg ./oceani --section "test: $$t" oceani-tests.mdc $${1+"$$@"} \
95 > /dev/null 2>&1 ; [ $$? -eq 42 ] ; then \
96 echo "FAILED"; cat .tmp.valg; exit 1; fi ; \
97 if grep 'LEAK SUMMARY' .tmp.valg > /dev/null; then \
98 echo "valgrind found LEAKS"; cat .tmp.valg ; exit 1 ; fi; \
99 if grep 'in use at exit [1-9]' .tmp.valg > /dev/null; then \
100 echo "valgrind found memory in use at exit"; cat .tmp.valg ; exit 1 ; fi; \
103 ## valgrind test code
104 @[ -n "$$SKIP_COVERAGE_CHECK" ] || awk '/NOTEST/ { next } /^ *[1-9]/ {ran+=1} /^ *###/ {skip+=1} \
105 END {printf "coverage: %6.2f%%\n", ran * 100 / (ran + skip); \
106 if (ran < (ran + skip) *0.99) exit(1) }' \
107 coverage/oceani.mdc.gcov
109 coverage_oceani: oceani.c
110 $(CC) $(CFLAGS) --coverage -fprofile-dir=coverage -o coverage_oceani oceani.c $(LDLIBS)
112 ## Values and variables
114 The first test stores values in variables and performs various
115 calculations on them.
118 oceani_tests += "valvar"
122 func main(argv:[]string)
123 a := 23; b:=12 ; b1 := -b
124 print a, b, a+b, a-b, a*b, a/b, a%b
125 print a<b, a<=b, a>b, a>=b, a<a, a==b, a==a
126 print +a, +b, +b1, -a, -b, -b1
127 x := True; y := False
128 print x and y, x or y, x and x, y or y, x and not x, x < y
130 c ::= "This is a string"
131 d ::= " field theory"
134 aconst :: string = "unchanging"
148 print "z??False", z??False, "w??False", w??False
151 print $"-34.56", $"not-a-number"
153 if True { pass; pass }
155 ###### output: valvar
157 23 12 35 11 276 1.916666667 11
158 False False True True False False True
160 False True True False False False
161 This is a string field theory This is a string field theory
165 z??False True w??False False
167 Unsupported suffix: 4i
170 Next we change the value of variables
173 oceani_tests += "setvar"
180 a = (a + a) * (a + a)
184 ###### output: setvar
190 oceani_tests += "consts"
196 four ::= 2 + 2 ; five ::= 10/2
197 const pie ::= "I like Pie";
198 cake ::= "The cake is"
202 print "Hello World, what lovely oceans you have!"
203 print "are there", five, "?"
204 print pi, pie, "but", cake, "Tau is", tau
206 ###### output: consts
207 Hello World, what lovely oceans you have!
209 3.141592653 I like Pie but The cake is a lie Tau is 6.283185306
211 Test merging of variables from multiple cases
214 oceani_tests += varmerge
216 ###### test: varmerge
219 for i:=0; then i=i+1; while i < 5:
222 case 1: scratch:=42; num:="one"
229 for i:=0; then i=i+1; while i < 5:
231 case 0: num:="zero" ;
233 case 2 { num:="two" } case 3 { num:="three" }
235 // re-declare a CondScope variable
240 ###### output: varmerge
241 zero , one , two , three , many ,
244 ## Conditions and Loops
246 Now we need to test if/else and some different loops
249 oceani_tests += cond_loop
251 ###### test: cond_loop
259 for b:=1; then b=b+b; while b < 100:
262 // Newtons method for square root of 2
268 current := guess * guess
269 use +(current - target) > 0.000000001
271 guess = (guess + (target / guess) ) / 2
274 print "error is ", target - guess * guess
276 for j:=0; then j = j+3 ; while j < 10:
277 if j != 0 and 20 / j > 3:
278 print "20 /", j," =", 20 / j
280 print "I won't calculate 20 /", j
281 pi ::= 3.1415926535897
282 if 355/113 == pi or +(pi - 355/113) < 0.001:
284 print "lower" if 355/113 < pi else "higher"
285 print "higher" if 355/113 > pi else "lower"
287 if pi > 3 then print "pi exceeds three"; else print "need more pie"
288 if (pi < 3) { print "not enough pi" } else { print "pi sufficient" }
289 for { i := 0; sum := 0 }
295 print "sum 1..10 is", sum
304 // different parsing options
317 ###### output: cond_loop
324 error is -4.510950445e-12
325 I won't calculate 20 / 0
328 I won't calculate 20 / 9
339 The demonstration code presented in the interpreted is suitable for the test suite.
340 Here I break it into two parts, keeping the array code separate.
343 oceani_tests += "sayhello,55,33,hello,True"
344 oceani_tests += "sayhello,12,60,there,False"
346 ###### test: sayhello
348 func main(av:[]string)
349 A := $av[1]; B := $av[2]
352 bbool := av[l-1] == "True"
353 print "Hello World, what lovely oceans you have!"
354 /* When a variable is defined in both branches of an 'if',
355 * and used afterwards, the variables are merged.
361 print "Is", A, "bigger than", B,"? ", bigger
362 /* If a variable is not used after the 'if', no
363 * merge happens, so types can be different
366 double:string = "yes"
367 print A, "is more than twice", B, "?", double
370 print "double", B, "is", double
375 print "still", bigger // check for regression in scoping
382 print "GCD of", A, "and", B,"is", a
384 print a, "is not positive, cannot calculate GCD"
386 print b, "is not positive, cannot calculate GCD"
391 print "Fibonacci:", f1,f2,
401 print astr ++ " was the str"
403 print "I found the str over " ++ astr
405 /* Binary search... */
423 print "Yay, I found", target
425 print "Closest I found was", lo
427 ###### output: sayhello,55,33,hello,True
428 Hello World, what lovely oceans you have!
429 Is 55 bigger than 33 ? yes
432 GCD of 55 and 33 is 11
433 Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
435 Closest I found was 77.34375
437 ###### output: sayhello,12,60,there,False
438 Hello World, what lovely oceans you have!
439 Is 12 bigger than 60 ? no
442 GCD of 12 and 60 is 12
443 Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
444 I found the str over there
445 Closest I found was 77.34375
448 oceani_tests += "insert_sort"
449 ###### test: insert_sort
454 for i:=1; then i = i + 1; while i < size:
455 n := list[i-1] * list[i-1]
456 list[i] = (n / 100) % 10000
459 for i:=0; then i = i + 1; while i < size:
460 print "list[",i,"]=",list[i]
462 for i := 1; then i=i+1; while i < size:
463 for j:=i-1; then j=j-1; while j >= 0:
464 if list[j] > list[j+1]:
469 for i:=0; then i = i + 1; while i < size:
470 print "list[",i,"]=",list[i]
472 ###### output: insert_sort
588 We already have some array tests, but this is where we put other
589 ad-hoc things array related.
592 oceani_tests += arrays
600 bools[3] = strings[1] == "Hello"
601 bools[1] = strings[2] <= "there"
603 for i:=0; then i=i+1; while i<5:
607 ra[6] = 42 // mustn't crash
608 print '', bools[i], ra[j-1],
611 ###### output: arrays
612 False 0 True 1 False 4 False 9 False 16
616 Time to test if structure declarations and accesses work correctly.
619 oceani_tests += structs
626 name:string = "Hello"
628 active:Boolean = True
630 struct baz { a:number; b:Boolean; }
635 struct bat2 a:string; b:Boolean
641 for i:=0; then i=i+1; while i < 4:
649 info[i].size[0] = i*i
651 info[i].active = False
653 for i:=0; then i=i+1; while i < 4:
654 print info[i].name, info[i].active, info[i].size[0]
655 info[0].thing.b = True
659 ###### output: structs
668 Test functions. They don't return anything, so we need to get them to print
671 oceani_tests += functions func_ret_type
673 ###### test: functions
693 func test(n:number; s:string)
710 for i:=0; then i = i + 1; while i < 5:
712 angular := to_polar(32, 23)
713 print angular.rho, angular.theta
715 func test2(n:number; s:string;) : (ret:number)
724 // exercise the parsing options
728 func t2 (a:string) {print "string"}
731 ###### output: functions
736 4 3 . 2 .. 1 ... done
739 ###### test: func_ret_type
741 func double(n:number):number
757 for j:=10; then j = j - 3; while j > -5:
758 print answer("dou","ble"), j, "is", double(j)
760 ###### output: func_ret_type
769 A simple linked list example
772 oceani_tests += "linked_list,one,two,three,four"
774 ###### test: linked_list
782 func insert(list:@linkage; new:string)
784 while ?p.next and p.next.this < new:
791 func printlist(list:@linkage)
793 print list@.next.this
794 list = list@.next.list
796 func freelist(list:@linkage)
797 if list.next != @nil:
798 lp:@linkage = list.next.list
802 func main(argv:[]string)
805 insert(list, "@start");
807 for i:=1; then i=i+1; while i < argv[]:
808 insert(list, argv[i])
809 insert(list, "Hello!")
813 ###### output: linked_list,one,two,three,four
822 ## Test code with syntax errors
824 Syntax errors aren't handled well yet - the result is almost always a
825 single message about the first error. So this section will be fairly
826 thin until we add proper parsing recovery in the face of common errors.
828 A special case of syntax errors is token errors, when a token is only
829 accepted because the parser doesn't know quite enough to reject it.
830 There are handled better as they are quite local, so a single test
831 program can trigger most of the possible errors.
833 To handle erronous code, we need a different set of tests, as we need to
834 capture `stderr`. The same test code will be used for type errors too.
835 As error messages contain the line number, and we don't want changes to
836 this file to change the reported numbers, we copy the code into a
837 separate file first, then run from there.
840 @for t in $(oceani_failing_tests); do \
841 echo -n "Test $$t ... "; \
842 ./md2c oceani-tests.mdc "output: $$t" | grep -v '^#' > .tmp.want; \
843 echo '``````' > .tmp.code; \
844 ./md2c oceani-tests.mdc "test: $$t" | grep -v '^#' >> .tmp.code; \
845 ./oceani .tmp.code > .tmp.have 2>&1; \
846 if ! cmp -s .tmp.want .tmp.have; then \
847 echo "FAILED"; diff -u .tmp.want .tmp.have ; exit 1; fi ;\
849 ./coverage_oceani --section "test: $$t" oceani-tests.mdc > /dev/null 2>&1 ;\
852 ###### combine test lists
853 oceani_valg_tests += $(oceani_failing_tests)
856 oceani_failing_tests := syn1
857 oceani_failing_tests += tokerr
862 if then else while do
865 .tmp.code:3:11: Syntax error in statement: then
869 a := 1i // imaginary numbers aren't understood
870 b:[2i]number // array sizes are handled separately
871 c:[3.14159]Boolean // array sizes must be integers
872 d:[1_000_000_000_000]number // they mustn't be huge
873 patn: string = "foo[ ,_]*bar"re // regexp strings are just a dream
876 This is a multiline string
877 With an unsupportable suffix
881 yy:[unknowable]number
883 zz:[zzsize]string // size must be constant, use ::=
885 // These numbers should be bad in all contexts: FIXME
888 ###### output: tokerr
889 .tmp.code:3:13: error: unsupported number suffix: 1i
890 .tmp.code:4:11: error: unsupported number suffix: 2i
891 .tmp.code:5:11: error: array size must be an integer: 3.14159
892 .tmp.code:6:11: error: array size is too large: 1_000_000_000_000
893 .tmp.code:7:23: error: unsupported string suffix: "foo[ ,_]*bar"re
894 .tmp.code:9:17: error: unsupported string suffix: """
895 This is a multiline string
896 With an unsupportable suffix
898 .tmp.code:15:12: error: name undeclared: unknowable
899 .tmp.code:17:12: error: array size must be a constant: zzsize
900 .tmp.code:20:12: error: unrecognised number: 00123
901 .tmp.code:14:11: error: type used but not declared: unknown
903 ## Tests for type errors
905 Type error don't cause parsing to abort, so we can fit many in the
906 one test program. Some type errors are found during the parse, others
907 during type analysis which doesn't run if parsing failed. So we cannot
908 fit everything in one.
910 These programs were generated by looking for the
911 various places that `type_err()` are called.
914 oceani_failing_tests += type_err1 type_err2 type_err3 type_err4 type_err5 type_err6
916 ###### test: type_err1
919 print "hello" ++ 5, 5 ++ "hello"
920 hello := "there"; print 4+hello
924 if 3 * 4 and not True: print "Weird"
928 ###### output: type_err1
929 .tmp.code:3:25: error: expected string found number
930 .tmp.code:3:28: error: expected string found number
931 .tmp.code:4:34: error: expected number but variable 'hello' is string
932 .tmp.code:4:8: info: this is where 'hello' was set to string
933 .tmp.code:6:8: error: Cannot assign to a constant: b
934 .tmp.code:5:8: info: name was defined as a constant here
935 .tmp.code:8:11: error: Arithmetic returns number but Boolean expected
936 .tmp.code:9:20: error: expected number found label
937 .tmp.code:9:8: info: variable 'd' was set as number here.
938 .tmp.code:10:8: error: cannot assign to an rval
939 oceani: type error in program - not running.
941 ###### test: type_err2
952 ###### output: type_err2
953 .tmp.code:4:8: error: variable 'a' redeclared
954 .tmp.code:3:8: info: this is where 'a' was first declared
955 .tmp.code:5:8: error: variable 'a' redeclared
956 .tmp.code:3:8: info: this is where 'a' was first declared
957 .tmp.code:6:8: error: variable 'a' redeclared
958 .tmp.code:3:8: info: this is where 'a' was first declared
959 .tmp.code:7:8: error: variable 'a' redeclared
960 .tmp.code:3:8: info: this is where 'a' was first declared
961 .tmp.code:8:8: Variable declared with no type or value: c
962 .tmp.code:9:19: error: unsupported number format: 02
964 ###### test: type_err3
968 b:string = "hello"; d:Boolean
973 c = "hello" ++ (True and False)
975 print 45 + ( "Hello" ++ "there")
985 case "Hello": print "Hello"
987 a1:[5]number; a2:[5]number; a3:[10]number; a4:[5]string
1001 // trigger 'labels not permitted' error message
1002 while 1 if True else False:
1005 print "one" ++ a4[], c[]
1015 ###### output: type_err3
1016 .tmp.code:8:12: error: expected number but variable 'c' is string
1017 .tmp.code:7:8: info: this is where 'c' was set to string
1018 .tmp.code:8:12: error: Arithmetic returns number but string expected
1019 .tmp.code:7:8: info: variable 'c' was set as string here.
1020 .tmp.code:9:24: error: Boolean operation found where string expected
1021 .tmp.code:7:8: info: variable 'c' was set as string here.
1022 .tmp.code:10:12: error: Comparison returns Boolean but string expected
1023 .tmp.code:7:8: info: variable 'c' was set as string here.
1024 .tmp.code:11:21: error: Concat returns string but number expected
1025 .tmp.code:12:8: error: string cannot be indexed
1026 .tmp.code:12:8: error: string cannot be indexed
1027 .tmp.code:21:13: error: expected number found string
1028 .tmp.code:17:16: error: expected number, found string
1029 .tmp.code:24:8: error: cannot assign value of type [5]number
1030 .tmp.code:25:13: error: expected [5]number but variable 'a3' is [10]number
1031 .tmp.code:23:36: info: this is where 'a3' was set to [10]number
1032 .tmp.code:25:8: error: cannot assign value of type [5]number
1033 .tmp.code:23:8: info: variable 'a1' was set as [5]number here.
1034 .tmp.code:26:13: error: expected [5]number but variable 'a4' is [5]string
1035 .tmp.code:23:51: info: this is where 'a4' was set to [5]string
1036 .tmp.code:26:8: error: cannot assign value of type [5]number
1037 .tmp.code:23:8: info: variable 'a1' was set as [5]number here.
1038 .tmp.code:27:16: error: expected number found string
1039 .tmp.code:28:16: error: expected string found Boolean
1040 .tmp.code:29:12: error: have number but need string
1041 .tmp.code:7:8: info: variable 'c' was set as string here.
1042 .tmp.code:32:8: error: variable used but not declared: foo
1043 .tmp.code:32:8: error: field reference on none is not supported
1044 .tmp.code:32:16: error: expected none found number
1045 .tmp.code:33:14: error: field reference on string is not supported
1046 .tmp.code:34:14: error: cannot find requested field in foo
1047 .tmp.code:35:17: error: have string but need number
1048 .tmp.code:38:29: error: expected number found Boolean
1049 .tmp.code:41:23: error: have number but need string
1050 .tmp.code:41:29: error: string cannot provide length
1051 .tmp.code:43:21: error: Can only convert string to number, not Boolean
1052 .tmp.code:43:8: info: variable 'x' was set as Boolean here.
1053 .tmp.code:49:13: error: expected [five]number but variable 'x2' is [four]number
1054 .tmp.code:48:8: info: this is where 'x2' was set to [four]number
1055 .tmp.code:49:8: error: cannot assign value of type [five]number
1056 .tmp.code:47:8: info: variable 'x1' was set as [five]number here.
1057 oceani: type error in program - not running.
1059 ###### test: type_err4
1064 ###### output: type_err4
1065 .tmp.code:3:14: error: variable used but not declared: b
1066 .tmp.code:3:16: error: expected none found number
1067 .tmp.code:3:14: info: variable 'b' was set as none here.
1068 oceani: type error in program - not running.
1070 ###### test: type_err5
1081 ###### output: type_err5
1082 .tmp.code:8:7: error: type already declared: foo
1083 .tmp.code:2:7: info: this is location of declartion: foo
1084 .tmp.code:10:13: Syntax error in struct field: :
1085 .tmp.code:5:7: error: type has recursive definition: baz
1086 .tmp.code:2:7: error: type has recursive definition: foo
1088 ###### test: type_err6
1096 ###### output: type_err6
1097 .tmp.code:4:12: error: '?' requires a testable value, not string
1098 .tmp.code:6:14: error: "??" requires a testable value, not string
1099 oceani: type error in program - not running.
1103 oceani_failing_tests += type_err_const type_err_const1 type_err_const2 missing_program bad_main
1105 ###### test: type_err_const
1108 bar ::= "string" + 56
1115 // trigger duplicate-main error
1120 ###### output: type_err_const
1121 .tmp.code:6:8: error: name already declared: bar
1122 .tmp.code:4:8: info: this is where 'bar' was first declared
1123 .tmp.code:8:8: error: variable 'foo' redeclared
1124 .tmp.code:3:8: info: this is where 'foo' was first declared
1125 .tmp.code:12:5: error: function 'main' redeclared
1126 .tmp.code:7:5: info: this is where 'main' was first declared
1127 .tmp.code:13:8: error: variable 'foo' redeclared
1128 .tmp.code:3:8: info: this is where 'foo' was first declared
1129 .tmp.code:4:16: error: expected number found string
1131 ###### test: type_err_const1
1139 ###### output: type_err_const1
1140 .tmp.code:3:12: Syntax error in constant: :
1141 .tmp.code:4:12: Syntax error in constant: :
1143 ###### test: type_err_const2
1148 ###### output: type_err_const2
1149 .tmp.code:3:8: error: const four cannot be resolved.
1150 .tmp.code:4:8: error: const two cannot be resolved.
1152 ###### test: missing_program
1156 ###### output: missing_program
1157 oceani: no main function found.
1159 ###### test: bad_main
1160 func main(foo:string)
1163 ###### output: bad_main
1164 .tmp.code:2:10: error: expected []string but variable 'foo' is string
1165 .tmp.code:2:10: info: this is where 'foo' was set to string
1166 oceani: main has wrong type.
1168 Test for type errors with functions
1171 oceani_failing_tests += func_err_args func_err_redeclare
1173 ###### test: func_err_args
1175 func test1(a:number; b:string; c:[3]Boolean)
1178 func test2(a:number; b:string; c:[3]Boolean)
1182 # use undefined names
1190 test1(1, "two", truth)
1192 test1(1, "lo", truth, 4)
1193 print test(), test1(1,2,3)
1197 func test4(a:number):string
1200 func test5(a:number):string
1207 func test6(a:number):foo
1212 func test7(a:@number)
1216 ###### output: func_err_args
1217 .tmp.code:40:14: error: cannot pass rval when reference expected
1218 .tmp.code:41:14: error: expected @number found string
1219 .tmp.code:34:5: error: function cannot return value of type foo
1220 .tmp.code:28:8: error: expected string, found none
1221 .tmp.code:25:8: error: expected string, found number
1222 .tmp.code:15:14: error: insufficient arguments to function.
1223 .tmp.code:16:14: error: expected number found string
1224 .tmp.code:16:22: error: expected string found number
1225 .tmp.code:16:14: error: insufficient arguments to function.
1226 .tmp.code:18:17: error: expected string found number
1227 .tmp.code:19:14: error: too many arguments to function.
1228 .tmp.code:20:14: error: attempt to call a non-function.
1229 .tmp.code:20:32: error: expected string found number
1230 .tmp.code:20:28: error: insufficient arguments to function.
1231 .tmp.code:21:20: error: expected "func test1" but variable 'test2' is "func test2"
1232 .tmp.code:5:5: info: this is where 'test2' was set to "func test2"
1233 .tmp.code:10:14: error: variable used but not declared: a
1234 .tmp.code:10:17: error: variable used but not declared: z
1235 oceani: type error in program - not running.
1237 ###### test: func_err_redeclare
1239 func test1(a:number; b:string; c:[3]Boolean)
1251 ###### output: func_err_redeclare
1252 .tmp.code:5:5: error: function 'test1' redeclared
1253 .tmp.code:2:5: info: this is where 'test1' was first declared
1254 .tmp.code:9:5: error: function 'test1' redeclared
1255 .tmp.code:2:5: info: this is where 'test1' was first declared
1257 Test for errors with references
1260 oceani_failing_tests += ref_err1 ref_err2
1262 ###### test: ref_err1
1270 ###### output: ref_err1
1271 .tmp.code:4:9: error: only "@free" makes sense here: foo
1272 .tmp.code:5:15: error: Only reference function is "@new()": old
1273 .tmp.code:6:19: error: Only reference value is "@nil": null
1275 ###### test: ref_err2
1281 if num == @nil or ref == ref2 or ref == 2 or ref.foo:
1285 ###### output: ref_err2
1286 .tmp.code:5:22: error: @new() can only be used with references, not number
1287 .tmp.code:5:8: info: variable 'num' was set as number here.
1288 .tmp.code:6:14: error: Cannot dereference number
1289 .tmp.code:7:19: error: @nil can only be used with reference, not number
1290 .tmp.code:7:33: error: expected @number but variable 'ref2' is @string
1291 .tmp.code:4:8: info: this is where 'ref2' was set to @string
1292 .tmp.code:7:48: error: expected @number found number
1293 .tmp.code:7:53: error: field reference on number is not supported
1294 .tmp.code:7:56: error: have none but need Boolean
1295 .tmp.code:8:17: error: @free can only be assigned a reference, not number
1296 .tmp.code:8:17: error: @free can only be assigned a reference, not number
1297 .tmp.code:9:8: error: Cannot assign an rval to a reference.
1298 oceani: type error in program - not running.
1300 ## Test erroneous command line args
1302 To improve coverage, we want to test correct handling of strange command
1303 line arguments. These tests won't use code, so the exiting test types
1304 won't work. So we need to be able to explicitly give the command line,
1305 and the expected output, and have that tested and the coverage assessed.
1306 Rather than having to spell out the whole command name, just give "cmd",
1307 and discard that. Requiring but discarding the command make an empty
1308 command list possible.
1311 @for t in $(oceani_special_tests); do \
1312 echo -n "Test $$t ... ";\
1313 i="$$IFS"; IFS=,; set $$t; IFS="$$i"; shift ;\
1314 ./md2c oceani-tests.mdc "output: $$t" | grep -v '^#' > .tmp.want; \
1315 ./oceani $${1+"$$@"} > .tmp.have 2>&1 ;\
1316 if ! cmp -s .tmp.want .tmp.have; then \
1317 echo "FAILED"; diff -u .tmp.want .tmp.have ; exit 1; fi ;\
1319 ./coverage_oceani $${1+"$$@"} > /dev/null 2>&1 ;\
1321 ###### valgrind test code
1322 @[ -n "$$SKIP_VALGRIND" ] || for t in $(oceani_special_tests); do\
1323 echo -n "Valgrind $$t.. "; \
1324 i="$$IFS"; IFS=,; set $$t; IFS="$$i"; shift ;\
1325 if valgrind --error-exitcode=42 --log-file=.tmp.valg ./oceani $${1+"$$@"} > .tmp.have 2>&1 ;\
1326 [ $$? -eq 42 ]; then \
1327 echo "FAILED"; cat .tmp.valg; exit 1; fi ; \
1328 if grep 'LEAK SUMMARY' .tmp.valg > /dev/null; then \
1329 echo "valgrind found LEAKS"; cat .tmp.valg ; exit 1 ; fi; \
1330 if grep 'in use at exit [1-9]' .tmp.valg > /dev/null; then \
1331 echo "valgrind found memory in use at exit"; cat .tmp.valg ; exit 1 ; fi; \
1336 oceani_special_tests += "cmd"
1337 oceani_special_tests += "cmd,-zyx"
1338 oceani_special_tests += "cmd,nofile"
1339 oceani_special_tests += "cmd,/dev/null"
1340 oceani_special_tests += "cmd,--section,toast:nothing,oceani-tests.mdc"
1343 oceani: no input file given
1345 ###### output: cmd,-zyx
1346 ./oceani: invalid option -- 'z'
1347 Usage: oceani --trace --print --noexec --brackets --section=SectionName prog.ocn
1349 ###### output: cmd,nofile
1350 oceani: cannot open nofile
1352 ###### output: cmd,/dev/null
1353 oceani: could not find any code in /dev/null
1355 ###### output: cmd,--section,toast:nothing,oceani-tests.mdc
1356 oceani: cannot find section toast:nothing