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.972) 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:[argc::]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
146 ###### output: valvar
148 23 12 35 11 276 1.916666667 11
149 False False True True False False True
151 False True True False False False
152 This is a string field theory This is a string field theory
156 z??False True w??False False
158 Next we change the value of variables
161 oceani_tests += "setvar"
168 a = (a + a) * (a + a)
172 ###### output: setvar
178 oceani_tests += "consts"
184 four ::= 2 + 2 ; five ::= 10/2
185 const pie ::= "I like Pie";
186 cake ::= "The cake is"
190 print "Hello World, what lovely oceans you have!"
191 print "are there", five, "?"
192 print pi, pie, "but", cake, "Tau is", tau
194 ###### output: consts
195 Hello World, what lovely oceans you have!
197 3.141592653 I like Pie but The cake is a lie Tau is 6.283185306
199 Test merging of variables from multiple cases
202 oceani_tests += varmerge
204 ###### test: varmerge
207 for i:=0; then i=i+1; while i < 5:
210 case 1: scratch:=42; num:="one"
217 for i:=0; then i=i+1; while i < 5:
224 // re-declare a CondScope variable
229 ###### output: varmerge
230 zero , one , two , three , many ,
233 ## Conditions and Loops
235 Now we need to test if/else and some different loops
238 oceani_tests += cond_loop
240 ###### test: cond_loop
248 for b:=1; then b=b+b; while b < 100:
251 // Newtons method for square root of 2
257 current := guess * guess
258 use +(current - target) > 0.000000001
260 guess = (guess + (target / guess) ) / 2
263 print "error is ", target - guess * guess
265 for j:=0; then j = j+3 ; while j < 10:
266 if j != 0 and then 20 / j > 3:
267 print "20 /", j," =", 20 / j
269 print "I won't calculate 20 /", j
270 pi ::= 3.1415926535897
271 if 355/113 == pi or else +(pi - 355/113) < 0.001:
273 print "lower" if 355/113 < pi else "higher"
275 if pi > 3 then print "pi exceeds three"; else print "need more pie"
276 if (pi < 3) { print "not enough pi" } else { print "pi sufficient" }
277 for { i := 0; sum := 0 }
283 print "sum 1..10 is", sum
292 ###### output: cond_loop
299 error is -4.510950445e-12
300 I won't calculate 20 / 0
303 I won't calculate 20 / 9
313 The demonstration code presented in the interpreted is suitable for the test suite.
314 Here I break it into two parts, keeping the array code separate.
317 oceani_tests += "sayhello,55,33,hello,True"
318 oceani_tests += "sayhello,12,60,there,False"
320 ###### test: sayhello
322 func main(av:[ac::number]string)
323 A := $av[1]; B := $av[2]
325 bbool := av[ac-1] == "True"
326 print "Hello World, what lovely oceans you have!"
327 /* When a variable is defined in both branches of an 'if',
328 * and used afterwards, the variables are merged.
334 print "Is", A, "bigger than", B,"? ", bigger
335 /* If a variable is not used after the 'if', no
336 * merge happens, so types can be different
339 double:string = "yes"
340 print A, "is more than twice", B, "?", double
343 print "double", B, "is", double
348 print "still", bigger // check for regression in scoping
355 print "GCD of", A, "and", B,"is", a
357 print a, "is not positive, cannot calculate GCD"
359 print b, "is not positive, cannot calculate GCD"
364 print "Fibonacci:", f1,f2,
374 print astr ++ " was the str"
376 print "I found the str over " ++ astr
378 /* Binary search... */
396 print "Yay, I found", target
398 print "Closest I found was", lo
400 ###### output: sayhello,55,33,hello,True
401 Hello World, what lovely oceans you have!
402 Is 55 bigger than 33 ? yes
405 GCD of 55 and 33 is 11
406 Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
408 Closest I found was 77.34375
410 ###### output: sayhello,12,60,there,False
411 Hello World, what lovely oceans you have!
412 Is 12 bigger than 60 ? no
415 GCD of 12 and 60 is 12
416 Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
417 I found the str over there
418 Closest I found was 77.34375
421 oceani_tests += "insert_sort"
422 ###### test: insert_sort
427 for i:=1; then i = i + 1; while i < size:
428 n := list[i-1] * list[i-1]
429 list[i] = (n / 100) % 10000
432 for i:=0; then i = i + 1; while i < size:
433 print "list[",i,"]=",list[i]
435 for i := 1; then i=i+1; while i < size:
436 for j:=i-1; then j=j-1; while j >= 0:
437 if list[j] > list[j+1]:
442 for i:=0; then i = i + 1; while i < size:
443 print "list[",i,"]=",list[i]
445 ###### output: insert_sort
561 We already have some array tests, but this is where we put other
562 ad-hoc things array related.
565 oceani_tests += arrays
573 bools[3] = strings[1] == "Hello"
574 bools[1] = strings[2] <= "there"
576 for i:=0; then i=i+1; while i<5:
580 ra[6] = 42 // mustn't crash
581 print '', bools[i], ra[j-1],
584 ###### output: arrays
585 False 0 True 1 False 4 False 9 False 16
589 Time to test if structure declarations and accesses work correctly.
592 oceani_tests += structs
601 active:Boolean = True
603 struct baz { a:number; b:Boolean; }
609 for i:=0; then i=i+1; while i < 4:
617 info[i].size[0] = i*i
619 info[i].active = False
621 for i:=0; then i=i+1; while i < 4:
622 print info[i].name, info[i].active, info[i].size[0]
623 info[0].thing.b = True
625 ###### output: structs
634 Test functions. They don't return anything, so we need to get them to print
637 oceani_tests += functions func_ret_type
639 ###### test: functions
659 func test(n:number; s:string)
676 for i:=0; then i = i + 1; while i < 5:
678 angular := to_polar(32, 23)
679 print angular.rho, angular.theta
681 ###### output: functions
686 4 3 . 2 .. 1 ... done
689 ###### test: func_ret_type
691 func double(n:number):number
707 for j:=10; then j = j - 3; while j > -5:
708 print answer("dou","ble"), j, "is", double(j)
710 ###### output: func_ret_type
719 A simple linked list example
722 oceani_tests += "linked_list,one,two,three,four"
724 ###### test: linked_list
732 func insert(list:@linkage; new:string)
734 while ?p.next and then p.next.this < new:
741 func printlist(list:@linkage)
743 print list@.next.this
744 list = list@.next.list
746 func freelist(list:@linkage)
747 if list.next != @nil:
748 lp:@linkage = list.next.list
752 func main(argv:[ac::]string)
755 insert(list, "@start");
757 for i:=1; then i=i+1; while i < ac:
758 insert(list, argv[i])
759 insert(list, "Hello!")
763 ###### output: linked_list,one,two,three,four
772 ## Test code with syntax errors
774 Syntax errors aren't handled well yet - the result is almost always a
775 single message about the first error. So this section will be fairly
776 thin until we add proper parsing recovery in the face of common errors.
778 A special case of syntax errors is token errors, when a token is only
779 accepted because the parser doesn't know quite enough to reject it.
780 There are handled better as they are quite local, so a single test
781 program can trigger most of the possible errors.
783 To handle erronous code, we need a different set of tests, as we need to
784 capture `stderr`. The same test code will be used for type errors too.
785 As error messages contain the line number, and we don't want changes to
786 this file to change the reported numbers, we copy the code into a
787 separate file first, then run from there.
790 @for t in $(oceani_failing_tests); do \
791 echo -n "Test $$t ... "; \
792 ./md2c oceani-tests.mdc "output: $$t" | grep -v '^#' > .tmp.want; \
793 echo '``````' > .tmp.code; \
794 ./md2c oceani-tests.mdc "test: $$t" | grep -v '^#' >> .tmp.code; \
795 ./oceani .tmp.code > .tmp.have 2>&1; \
796 if ! cmp -s .tmp.want .tmp.have; then \
797 echo "FAILED"; diff -u .tmp.want .tmp.have ; exit 1; fi ;\
799 ./coverage_oceani --section "test: $$t" oceani-tests.mdc > /dev/null 2>&1 ;\
802 ###### combine test lists
803 oceani_valg_tests += $(oceani_failing_tests)
806 oceani_failing_tests := syn1
807 oceani_failing_tests += tokerr
812 if then else while do
815 .tmp.code:3:11: Syntax error in statement: then
819 a := 1i // imaginary numbers aren't understood
820 b:[2i]number // array sizes are handled separately
821 c:[3.14159]Boolean // array sizes must be integers
822 d:[1_000_000_000_000]number // they mustn't be huge
823 patn: string = "foo[ ,_]*bar"re // regexp strings are just a dream
826 This is a multiline string
827 With an unsupportable suffix
831 yy:[unknowable]number
833 zz:[zzsize]string // size must be constant, use ::=
835 // These numbers should be bad in all contexts: FIXME
838 ###### output: tokerr
839 .tmp.code:3:13: error: unsupported number suffix: 1i
840 .tmp.code:4:11: error: unsupported number suffix: 2i
841 .tmp.code:5:11: error: array size must be an integer: 3.14159
842 .tmp.code:6:11: error: array size is too large: 1_000_000_000_000
843 .tmp.code:7:23: error: unsupported string suffix: "foo[ ,_]*bar"re
844 .tmp.code:9:17: error: unsupported string suffix: """
845 This is a multiline string
846 With an unsupportable suffix
848 .tmp.code:15:12: error: name undeclared: unknowable
849 .tmp.code:17:12: error: array size must be a constant: zzsize
850 .tmp.code:20:12: error: unrecognised number: 00123
851 .tmp.code:14:11: error: type used but not declared: unknown
853 ## Tests for type errors
855 Type error don't cause parsing to abort, so we can fit many in the
856 one test program. Some type errors are found during the parse, others
857 during type analysis which doesn't run if parsing failed. So we cannot
858 fit everything in one.
860 These programs were generated by looking for the
861 various places that `type_err()` are called.
864 oceani_failing_tests += type_err1 type_err2 type_err3 type_err4 type_err5 type_err6
866 ###### test: type_err1
869 print "hello" ++ 5, 5 ++ "hello"
874 if 3 * 4 and not True: print "Weird"
878 ###### output: type_err1
879 .tmp.code:3:25: error: expected string found number
880 .tmp.code:3:28: error: expected string found number
881 .tmp.code:6:8: error: Cannot assign to a constant: b
882 .tmp.code:5:8: info: name was defined as a constant here
883 .tmp.code:8:11: error: Arithmetic returns number but Boolean expected
884 .tmp.code:9:20: error: expected number found label
885 .tmp.code:9:8: info: variable 'd' was set as number here.
886 .tmp.code:10:8: error: cannot assign to an rval
887 oceani: type error in program - not running.
889 ###### test: type_err2
899 ###### output: type_err2
900 .tmp.code:4:8: error: variable 'a' redeclared
901 .tmp.code:3:8: info: this is where 'a' was first declared
902 .tmp.code:5:8: error: variable 'a' redeclared
903 .tmp.code:3:8: info: this is where 'a' was first declared
904 .tmp.code:6:8: error: variable 'a' redeclared
905 .tmp.code:3:8: info: this is where 'a' was first declared
906 .tmp.code:7:8: error: variable 'a' redeclared
907 .tmp.code:3:8: info: this is where 'a' was first declared
908 .tmp.code:8:8: Variable declared with no type or value: c
910 ###### test: type_err3
919 c = "hello" ++ (True and False)
921 print 45 + ( "Hello" ++ "there")
931 case "Hello": print "Hello"
933 a1:[5]number; a2:[5]number; a3:[10]number; a4:[5]string
947 // trigger 'labels not permitted' error message
948 while 1 if True else False:
952 ###### output: type_err3
953 .tmp.code:8:12: error: expected number but variable 'c' is string
954 .tmp.code:7:8: info: this is where 'c' was set to string
955 .tmp.code:8:12: error: Arithmetic returns number but string expected
956 .tmp.code:7:8: info: variable 'c' was set as string here.
957 .tmp.code:9:24: error: Boolean operation found where string expected
958 .tmp.code:7:8: info: variable 'c' was set as string here.
959 .tmp.code:10:12: error: Comparison returns Boolean but string expected
960 .tmp.code:7:8: info: variable 'c' was set as string here.
961 .tmp.code:11:21: error: Concat returns string but number expected
962 .tmp.code:12:8: error: string cannot be indexed
963 .tmp.code:12:8: error: string cannot be indexed
964 .tmp.code:21:13: error: expected number found string
965 .tmp.code:17:16: error: expected number, found string
966 .tmp.code:24:8: error: cannot assign value of type [5]number
967 .tmp.code:25:13: error: expected [5]number but variable 'a3' is [10]number
968 .tmp.code:23:36: info: this is where 'a3' was set to [10]number
969 .tmp.code:25:8: error: cannot assign value of type [5]number
970 .tmp.code:23:8: info: variable 'a1' was set as [5]number here.
971 .tmp.code:26:13: error: expected [5]number but variable 'a4' is [5]string
972 .tmp.code:23:51: info: this is where 'a4' was set to [5]string
973 .tmp.code:26:8: error: cannot assign value of type [5]number
974 .tmp.code:23:8: info: variable 'a1' was set as [5]number here.
975 .tmp.code:27:16: error: expected number found string
976 .tmp.code:28:16: error: expected string found Boolean
977 .tmp.code:29:12: error: have number but need string
978 .tmp.code:7:8: info: variable 'c' was set as string here.
979 .tmp.code:32:8: error: variable used but not declared: foo
980 .tmp.code:32:8: error: field reference on none is not supported
981 .tmp.code:32:16: error: expected none found number
982 .tmp.code:33:14: error: field reference on string is not supported
983 .tmp.code:34:14: error: cannot find requested field in foo
984 .tmp.code:35:17: error: have string but need number
985 .tmp.code:38:29: error: expected number found Boolean
986 oceani: type error in program - not running.
988 ###### test: type_err4
993 ###### output: type_err4
994 .tmp.code:3:14: error: variable used but not declared: b
995 .tmp.code:3:16: error: expected none found number
996 .tmp.code:3:14: info: variable 'b' was set as none here.
997 oceani: type error in program - not running.
999 ###### test: type_err5
1009 ###### output: type_err5
1010 .tmp.code:8:7: error: type already declared: foo
1011 .tmp.code:2:7: info: this is location of declartion: foo
1012 .tmp.code:5:7: error: type has recursive definition: baz
1013 .tmp.code:2:7: error: type has recursive definition: foo
1015 ###### test: type_err6
1023 ###### output: type_err6
1024 .tmp.code:4:12: error: '?' requires a testable value, not string
1025 .tmp.code:6:14: error: "??" requires a testable value, not string
1026 oceani: type error in program - not running.
1030 oceani_failing_tests += type_err_const type_err_const1 type_err_const2 missing_program bad_main
1032 ###### test: type_err_const
1035 bar ::= "string" + 56
1042 // trigger duplicate-main error
1047 ###### output: type_err_const
1048 .tmp.code:6:8: error: name already declared: bar
1049 .tmp.code:4:8: info: this is where 'bar' was first declared
1050 .tmp.code:8:8: error: variable 'foo' redeclared
1051 .tmp.code:3:8: info: this is where 'foo' was first declared
1052 .tmp.code:12:5: error: function 'main' redeclared
1053 .tmp.code:7:5: info: this is where 'main' was first declared
1054 .tmp.code:13:8: error: variable 'foo' redeclared
1055 .tmp.code:3:8: info: this is where 'foo' was first declared
1056 .tmp.code:4:16: error: expected number found string
1058 ###### test: type_err_const1
1066 ###### output: type_err_const1
1067 .tmp.code:3:12: Syntax error in constant: :
1068 .tmp.code:4:12: Syntax error in constant: :
1070 ###### test: type_err_const2
1075 ###### output: type_err_const2
1076 .tmp.code:3:8: error: const four cannot be resolved.
1077 .tmp.code:4:8: error: const two cannot be resolved.
1079 ###### test: missing_program
1083 ###### output: missing_program
1084 oceani: no main function found.
1086 ###### test: bad_main
1087 func main(foo:string)
1090 ###### output: bad_main
1091 .tmp.code:2:10: error: expected []string but variable 'foo' is string
1092 .tmp.code:2:10: info: this is where 'foo' was set to string
1093 oceani: main has wrong type.
1095 Test for type errors with functions
1098 oceani_failing_tests += func_err_args func_err_redeclare
1100 ###### test: func_err_args
1102 func test1(a:number; b:string; c:[3]Boolean)
1105 func test2(a:number; b:string; c:[3]Boolean)
1109 # use undefined names
1117 test1(1, "two", truth)
1119 test1(1, "lo", truth, 4)
1120 print test(), test1(1,2,3)
1124 func test4(a:number):string
1127 func test5(a:number):string
1134 func test6(a:number):foo
1139 func test7(a:@number)
1143 ###### output: func_err_args
1144 .tmp.code:40:14: error: cannot pass rval when reference expected
1145 .tmp.code:41:14: error: expected @number found string
1146 .tmp.code:34:5: error: function cannot return value of type foo
1147 .tmp.code:28:8: error: expected string, found none
1148 .tmp.code:25:8: error: expected string, found number
1149 .tmp.code:15:14: error: insufficient arguments to function.
1150 .tmp.code:16:14: error: expected number found string
1151 .tmp.code:16:22: error: expected string found number
1152 .tmp.code:16:14: error: insufficient arguments to function.
1153 .tmp.code:18:17: error: expected string found number
1154 .tmp.code:19:14: error: too many arguments to function.
1155 .tmp.code:20:14: error: attempt to call a non-function.
1156 .tmp.code:20:32: error: expected string found number
1157 .tmp.code:20:28: error: insufficient arguments to function.
1158 .tmp.code:21:20: error: expected "func test1" but variable 'test2' is "func test2"
1159 .tmp.code:5:5: info: this is where 'test2' was set to "func test2"
1160 .tmp.code:10:14: error: variable used but not declared: a
1161 .tmp.code:10:17: error: variable used but not declared: z
1162 oceani: type error in program - not running.
1164 ###### test: func_err_redeclare
1166 func test1(a:number; b:string; c:[3]Boolean)
1178 ###### output: func_err_redeclare
1179 .tmp.code:5:5: error: function 'test1' redeclared
1180 .tmp.code:2:5: info: this is where 'test1' was first declared
1181 .tmp.code:9:5: error: function 'test1' redeclared
1182 .tmp.code:2:5: info: this is where 'test1' was first declared
1184 Test for errors with references
1187 oceani_failing_tests += ref_err1 ref_err2
1189 ###### test: ref_err1
1197 ###### output: ref_err1
1198 .tmp.code:4:9: error: only "@free" makes sense here: foo
1199 .tmp.code:5:15: error: Only reference function is "@new()": old
1200 .tmp.code:6:19: error: Only reference value is "@nil": null
1202 ###### test: ref_err2
1208 if num == @nil or ref == ref2 or ref == 2 or ref.foo:
1212 ###### output: ref_err2
1213 .tmp.code:5:22: error: @new() can only be used with references, not number
1214 .tmp.code:5:8: info: variable 'num' was set as number here.
1215 .tmp.code:6:14: error: Cannot dereference number
1216 .tmp.code:7:19: error: @nil can only be used with reference, not number
1217 .tmp.code:7:33: error: expected @number but variable 'ref2' is @string
1218 .tmp.code:4:8: info: this is where 'ref2' was set to @string
1219 .tmp.code:7:48: error: expected @number found number
1220 .tmp.code:7:53: error: field reference on number is not supported
1221 .tmp.code:7:56: error: have none but need Boolean
1222 .tmp.code:8:17: error: @free can only be assigned a reference, not number
1223 .tmp.code:8:17: error: @free can only be assigned a reference, not number
1224 .tmp.code:9:8: error: Cannot assign an rval to a reference.
1225 oceani: type error in program - not running.
1227 ## Test erroneous command line args
1229 To improve coverage, we want to test correct handling of strange command
1230 line arguments. These tests won't use code, so the exiting test types
1231 won't work. So we need to be able to explicitly give the command line,
1232 and the expected output, and have that tested and the coverage assessed.
1233 Rather than having to spell out the whole command name, just give "cmd",
1234 and discard that. Requiring but discarding the command make an empty
1235 command list possible.
1238 @for t in $(oceani_special_tests); do \
1239 echo -n "Test $$t ... ";\
1240 i="$$IFS"; IFS=,; set $$t; IFS="$$i"; shift ;\
1241 ./md2c oceani-tests.mdc "output: $$t" | grep -v '^#' > .tmp.want; \
1242 ./oceani $${1+"$$@"} > .tmp.have 2>&1 ;\
1243 if ! cmp -s .tmp.want .tmp.have; then \
1244 echo "FAILED"; diff -u .tmp.want .tmp.have ; exit 1; fi ;\
1246 ./coverage_oceani $${1+"$$@"} > /dev/null 2>&1 ;\
1248 ###### valgrind test code
1249 @[ -n "$$SKIP_VALGRIND" ] || for t in $(oceani_special_tests); do\
1250 echo -n "Valgrind $$t.. "; \
1251 i="$$IFS"; IFS=,; set $$t; IFS="$$i"; shift ;\
1252 if valgrind --error-exitcode=42 --log-file=.tmp.valg ./oceani $${1+"$$@"} > .tmp.have 2>&1 ;\
1253 [ $$? -eq 42 ]; then \
1254 echo "FAILED"; cat .tmp.valg; exit 1; fi ; \
1255 if grep 'LEAK SUMMARY' .tmp.valg > /dev/null; then \
1256 echo "valgrind found LEAKS"; cat .tmp.valg ; exit 1 ; fi; \
1257 if grep 'in use at exit [1-9]' .tmp.valg > /dev/null; then \
1258 echo "valgrind found memory in use at exit"; cat .tmp.valg ; exit 1 ; fi; \
1263 oceani_special_tests += "cmd"
1264 oceani_special_tests += "cmd,-zyx"
1265 oceani_special_tests += "cmd,nofile"
1266 oceani_special_tests += "cmd,/dev/null"
1267 oceani_special_tests += "cmd,--section,toast:nothing,oceani-tests.mdc"
1270 oceani: no input file given
1272 ###### output: cmd,-zyx
1273 ./oceani: invalid option -- 'z'
1274 Usage: oceani --trace --print --noexec --brackets --section=SectionName prog.ocn
1276 ###### output: cmd,nofile
1277 oceani: cannot open nofile
1279 ###### output: cmd,/dev/null
1280 oceani: could not find any code in /dev/null
1282 ###### output: cmd,--section,toast:nothing,oceani-tests.mdc
1283 oceani: cannot find section toast:nothing