]> ocean-lang.org Git - ocean/blob - csrc/oceani-tests.mdc
oceani-tests: use LALR to check for conflicts.
[ocean] / csrc / oceani-tests.mdc
1 # Ocean Interpreter test code
2
3 Regular testing is, of course, important for developing any software.
4 The Ocean interpreted is no exception.  This document allows easy
5 testing by providing:
6
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.
10
11 Three different sorts of tests are run.  As soon as any fail, the whole
12 test stops.
13
14 1/ Each program is run and the output is compared against the expected
15     output
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
18     memory.
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.
29
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.
33
34 ###### File: oceani-tests.mk
35
36         oceani_tests :=
37         ## test list
38
39         tests:: oceani_test_suite
40         oceani_test_suite: oceani coverage_oceani
41                 @echo -n Checking grammar ...
42                 @./parsergen --report --LALR --tag Parser oceani.mdc | grep " - no conflicts" > /dev/null || \
43                     { echo "Grammar contains conflicts, please review" ; exit 1; }
44                 @echo ok
45                 @rm -rf coverage; mkdir -p coverage
46                 @cp *.gcno coverage
47                 @for T in $(oceani_tests); do \
48                     echo -n "Test $$T.. "; \
49                     i="$$IFS"; IFS=,; set $$T; IFS="$$i"; t=$$1; shift; \
50                     ./md2c oceani-tests.mdc "output: $$T" | grep -v '^#' > .tmp.want; \
51                     ./oceani --section "test: $$t" oceani-tests.mdc $${1+"$$@"} > .tmp.have; \
52                     if ! cmp -s .tmp.want .tmp.have; then \
53                        echo "FAILED"; diff -u .tmp.want .tmp.have ; exit 1; fi ;\
54                     echo -n "printing.. "; \
55                     echo '``````' > .tmp.code1; echo '``````' > .tmp.code2 ;\
56                     ./oceani --noexec --print --section "test: $$t" oceani-tests.mdc >> .tmp.code1; \
57                     ./oceani --noexec --print .tmp.code1 >> .tmp.code2 ;\
58                     if ! cmp -s .tmp.code1 .tmp.code2; then \
59                        echo " Failed"; diff -u .tmp.code1 .tmp.code2; exit 1 ; fi ; \
60                     echo -n "exec-after-print.. "; \
61                     ./oceani .tmp.code1 $${1+"$$@"} > .tmp.have ; \
62                     if ! cmp -s .tmp.want .tmp.have; then \
63                        echo " FAILED"; diff -u .tmp.want .tmp.have; exit 1;fi; \
64                     echo " all passed"; \
65                     ./coverage_oceani --print --section "test: $$t" oceani-tests.mdc $${1+"$$@"} > /dev/null ; \
66                     ./coverage_oceani -tpbn --section "test: $$t" oceani-tests.mdc > /dev/null 2>&1; \
67                 done
68
69                 ## test code
70
71                 @gcov -o coverage oceani.mdc > /dev/null 2> /dev/null
72                 @mv *.gcov coverage ; [ -f .gcov ] && mv .gcov coverage
73                 @ awk '/NOTEST/ { next } /^ *[1-9]/ {ran+=1} /^ *###/ {skip+=1} \
74                     END {printf "coverage: %6.2f%%\n", ran * 100 / (ran + skip); \
75                          if (ran < (ran + skip) *0.94) exit(1) }' \
76                         coverage/oceani.mdc.gcov
77                 @rm -f .tmp*
78
79                 @for T in $(oceani_tests); do \
80                     echo -n "Valgrind $$T.. "; \
81                     i="$$IFS"; IFS=,; set $$T; IFS="$$i"; t=$$1; shift; \
82                     if ! valgrind --error-exitcode=1 --log-file=.tmp.valg ./oceani --section "test: $$t" oceani-tests.mdc $${1+"$$@"} \
83                          > /dev/null 2>&1 ; then \
84                        echo "FAILED"; cat .tmp.valg; exit 1; fi ; \
85                     if grep 'LEAK SUMMARY' .tmp.valg > /dev/null; then \
86                        echo "valgrind found LEAKS"; cat .tmp.valg ; exit 1 ; fi; \
87                     if grep 'in use at exit [1-9]' .tmp.valg > /dev/null; then \
88                        echo "valgrind found memory in use at exit"; cat .tmp.valg ; exit 1 ; fi; \
89                     echo " passed"; \
90                 done
91
92         coverage_oceani: oceani.c
93                 $(CC) $(CFLAGS) --coverage -fprofile-dir=coverage -o coverage_oceani oceani.c $(LDLIBS)
94
95 ## Values and variables
96
97 The first test stores values in variables and performs various
98 calculations on them.
99
100 ###### test list
101        oceani_tests += "valvar"
102
103 ###### test: valvar
104
105         program:
106                 a := 23; b:=12 ; b1 := -b
107                 print a, b, a+b, a-b, a*b, a/b, a%b
108                 print a<b, a<=b, a>b, a>=b, a<a, a==b, a==a
109                 print +a, +b, +b1, -a, -b, -b1
110                 x := True; y := False
111                 print x and y, x or y, x and x, y or y, x and not x, x < y
112
113                 c ::= "This is a string"
114                 d ::= " field theory"
115                 print c, d, c++d
116
117                 aconst :: string = "unchanging"
118
119                 // Check wrapping
120                 print
121                   a + b
122                   + (a*2)
123                   + b1
124                   + b
125
126 ###### output: valvar
127
128         23 12 35 11 276 1.91667 11
129         False False True True False False True
130         23 12 12 -23 -12 12
131         False True True False False False
132         This is a string  field theory This is a string field theory
133         81
134
135 Next we change the value of variables
136
137 ###### test list
138        oceani_tests += "setvar"
139
140 ###### test: setvar
141
142         program:
143                 a := 4
144                 a = a * a
145                 a = (a + a) * (a + a)
146                 a = a * a * a
147                 print a, a/a
148
149 ###### output: setvar
150         1.07374e+09 1
151
152 Now some contants
153
154 ###### test list
155         oceani_tests += "consts"
156
157 ###### test: consts
158         const:
159                 pi ::= 3.141 592 653
160                 four ::= 2 + 2 ; five ::= 10/2
161         const pie ::= "I like Pie";
162                 cake ::= "The cake is"
163                   ++ " a lie"
164
165         program:
166                 print "Hello World, what lovely oceans you have!"
167                 print "are there", five, "?"
168                 print pi, pie, "but", cake
169
170 ###### output: consts
171         Hello World, what lovely oceans you have!
172         are there 5 ?
173         3.14159 I like Pie but The cake is a lie
174
175 Test merging of variables from multiple cases
176
177 ###### test list
178         oceani_tests += varmerge
179
180 ###### test: varmerge
181
182         program:
183                 for i:=0; then i=i+1; while i < 5:
184                         switch i
185                                 case 0: num:="zero"
186                                 case 1: num:="one"
187                                 case 2: num:="two"
188                                 case 3: num:="three"
189                                 else:   num:="many"
190                         print num,", ",
191                 print
192
193 ###### output: varmerge
194         zero , one , two , three , many , 
195
196 ## Conditions and Loops
197
198 Now we need to test if/else and some different loops
199
200 ###### test list
201        oceani_tests += cond_loop
202
203 ###### test: cond_loop
204
205         program:
206                 a := 4
207                 if a < 5:
208                         print "Success"
209                 else:
210                         print "Failure"
211                 for b:=1; then b=b+b; while b < 100:
212                         print '', b,
213                 print
214                 // Newtons method for square root of 2
215                 target ::= 2
216                 guess := target
217                 for:
218                         count: number = 0
219                 while:
220                         current := guess * guess
221                         use +(current - target) > 0.000000001
222                 do:
223                         guess = (guess + (target / guess) ) / 2
224                         print count, guess
225                         count = count + 1
226                 print "error is ", target - guess * guess
227
228                 for j:=0; then j = j+3 ; while j < 10:
229                         if j != 0 and then 20 / j > 3:
230                                 print "20 /", j," =", 20 / j
231                         else:
232                                 print "I won't calculate 20 /", j
233                 pi ::= 3.1415926535897
234                 if 355/113 == pi or else +(pi - 355/113) < 0.001:
235                         print "Close enough"
236                 print "lower" if 355/113 < pi else "higher"
237
238 ###### output: cond_loop
239         Success
240          1 2 4 8 16 32 64
241         0 1.5
242         1 1.41667
243         2 1.41422
244         3 1.41421
245         error is  -4.51095e-12
246         I won't calculate 20 / 0
247         20 / 3  = 6.66667
248         20 / 6  = 3.33333
249         I won't calculate 20 / 9
250         Close enough
251         higher
252
253 ## Say Hello
254
255 The demonstration code presented in the interpreted is suitable for the test suite.
256 Here I break it into two parts, keeping the array code separate.
257
258 ###### test list
259         oceani_tests += "sayhello,55,33,hello,True"
260         oceani_tests += "sayhello,12,60,there,False"
261
262 ###### test: sayhello
263
264         program A B astr bbool:
265                 print "Hello World, what lovely oceans you have!"
266                 /* When a variable is defined in both branches of an 'if',
267                  * and used afterwards, the variables are merged.
268                  */
269                 if A > B:
270                         bigger := "yes"
271                 else:
272                         bigger := "no"
273                 print "Is", A, "bigger than", B,"? ", bigger
274                 /* If a variable is not used after the 'if', no
275                  * merge happens, so types can be different
276                  */
277                 if A > B * 2:
278                         double:string = "yes"
279                         print A, "is more than twice", B, "?", double
280                 else:
281                         double := B*2
282                         print "double", B, "is", double
283
284                 a : number
285                 a = A;
286                 b:number = B
287                 if a > 0 and b > 0:
288                         while a != b:
289                                 if a < b:
290                                         b = b - a
291                                 else:
292                                         a = a - b
293                         print "GCD of", A, "and", B,"is", a
294                 else if a <= 0:
295                         print a, "is not positive, cannot calculate GCD"
296                 else:
297                         print b, "is not positive, cannot calculate GCD"
298
299                 for:
300                         togo := 10
301                         f1 := 1; f2 := 1
302                         print "Fibonacci:", f1,f2,
303                 then togo = togo - 1
304                 while togo > 0:
305                         f3 := f1 + f2
306                         print "", f3,
307                         f1 = f2
308                         f2 = f3
309                 print ""
310
311                 if bbool:
312                         print astr ++ " was the str"
313                 else:
314                         print "I found the str over " ++ astr
315
316                 /* Binary search... */
317                 for:
318                         lo:= 0; hi := 100
319                         target := 77
320                 while:
321                         mid := (lo + hi) / 2
322                         if mid == target:
323                                 use Found
324                         if mid < target:
325                                 lo = mid
326                         else:
327                                 hi = mid
328                         if hi - lo < 1:
329                                 use GiveUp
330                         use True
331                 do: pass
332                 case Found:
333                         print "Yay, I found", target
334                 case GiveUp:
335                         print "Closest I found was", mid
336
337 ###### output: sayhello,55,33,hello,True
338         Hello World, what lovely oceans you have!
339         Is 55 bigger than 33 ?  yes
340         double 33 is 66
341         GCD of 55 and 33 is 11
342         Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
343         hello was the str
344         Closest I found was 77.3438
345
346 ###### output: sayhello,12,60,there,False
347         Hello World, what lovely oceans you have!
348         Is 12 bigger than 60 ?  no
349         double 60 is 120
350         GCD of 12 and 60 is 12
351         Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
352         I found the str over there
353         Closest I found was 77.3438
354
355 ###### test list
356         oceani_tests += "insert_sort"
357 ###### test: insert_sort
358         program:
359                 size::=55
360                 list:[size]number
361                 list[0] = 1_234
362                 for i:=1; then i = i + 1; while i < size:
363                         n := list[i-1] * list[i-1]
364                         list[i] = (n / 100) % 10000
365
366                 print "Before sort:"
367                 for i:=0; then i = i + 1; while i < size:
368                         print "list[",i,"]=",list[i]
369
370                 for i := 1; then i=i+1; while i < size:
371                         for j:=i-1; then j=j-1; while j >= 0:
372                                 if list[j] > list[j+1]:
373                                         t:= list[j]
374                                         list[j] = list[j+1]
375                                         list[j+1] = t
376                 print "After sort:"
377                 for i:=0; then i = i + 1; while i < size:
378                         print "list[",i,"]=",list[i]
379
380 ###### output: insert_sort
381         Before sort:
382         list[ 0 ]= 1234
383         list[ 1 ]= 5227
384         list[ 2 ]= 3215
385         list[ 3 ]= 3362
386         list[ 4 ]= 3030
387         list[ 5 ]= 1809
388         list[ 6 ]= 2724
389         list[ 7 ]= 4201
390         list[ 8 ]= 6484
391         list[ 9 ]= 422
392         list[ 10 ]= 1780
393         list[ 11 ]= 1684
394         list[ 12 ]= 8358
395         list[ 13 ]= 8561
396         list[ 14 ]= 2907
397         list[ 15 ]= 4506
398         list[ 16 ]= 3040
399         list[ 17 ]= 2416
400         list[ 18 ]= 8370
401         list[ 19 ]= 569
402         list[ 20 ]= 3237
403         list[ 21 ]= 4781
404         list[ 22 ]= 8579
405         list[ 23 ]= 5992
406         list[ 24 ]= 9040
407         list[ 25 ]= 7216
408         list[ 26 ]= 706
409         list[ 27 ]= 4984
410         list[ 28 ]= 8402
411         list[ 29 ]= 5936
412         list[ 30 ]= 2360
413         list[ 31 ]= 5696
414         list[ 32 ]= 4444
415         list[ 33 ]= 7491
416         list[ 34 ]= 1150
417         list[ 35 ]= 3225
418         list[ 36 ]= 4006
419         list[ 37 ]= 480
420         list[ 38 ]= 2304
421         list[ 39 ]= 3084
422         list[ 40 ]= 5110
423         list[ 41 ]= 1121
424         list[ 42 ]= 2566
425         list[ 43 ]= 5843
426         list[ 44 ]= 1406
427         list[ 45 ]= 9768
428         list[ 46 ]= 4138
429         list[ 47 ]= 1230
430         list[ 48 ]= 5129
431         list[ 49 ]= 3066
432         list[ 50 ]= 4003
433         list[ 51 ]= 240
434         list[ 52 ]= 576
435         list[ 53 ]= 3317
436         list[ 54 ]= 24
437         After sort:
438         list[ 0 ]= 24
439         list[ 1 ]= 240
440         list[ 2 ]= 422
441         list[ 3 ]= 480
442         list[ 4 ]= 569
443         list[ 5 ]= 576
444         list[ 6 ]= 706
445         list[ 7 ]= 1121
446         list[ 8 ]= 1150
447         list[ 9 ]= 1230
448         list[ 10 ]= 1234
449         list[ 11 ]= 1406
450         list[ 12 ]= 1684
451         list[ 13 ]= 1780
452         list[ 14 ]= 1809
453         list[ 15 ]= 2304
454         list[ 16 ]= 2360
455         list[ 17 ]= 2416
456         list[ 18 ]= 2566
457         list[ 19 ]= 2724
458         list[ 20 ]= 2907
459         list[ 21 ]= 3030
460         list[ 22 ]= 3040
461         list[ 23 ]= 3066
462         list[ 24 ]= 3084
463         list[ 25 ]= 3215
464         list[ 26 ]= 3225
465         list[ 27 ]= 3237
466         list[ 28 ]= 3317
467         list[ 29 ]= 3362
468         list[ 30 ]= 4003
469         list[ 31 ]= 4006
470         list[ 32 ]= 4138
471         list[ 33 ]= 4201
472         list[ 34 ]= 4444
473         list[ 35 ]= 4506
474         list[ 36 ]= 4781
475         list[ 37 ]= 4984
476         list[ 38 ]= 5110
477         list[ 39 ]= 5129
478         list[ 40 ]= 5227
479         list[ 41 ]= 5696
480         list[ 42 ]= 5843
481         list[ 43 ]= 5936
482         list[ 44 ]= 5992
483         list[ 45 ]= 6484
484         list[ 46 ]= 7216
485         list[ 47 ]= 7491
486         list[ 48 ]= 8358
487         list[ 49 ]= 8370
488         list[ 50 ]= 8402
489         list[ 51 ]= 8561
490         list[ 52 ]= 8579
491         list[ 53 ]= 9040
492         list[ 54 ]= 9768
493
494 ## Arrays
495
496 We already have some array tests, but this is where we put other
497 ad-hoc things array related.
498
499 ###### test list
500         oceani_tests += arrays
501
502 ###### test: arrays
503
504         program:
505                 bools:[5]Boolean
506                 strings:[4]string
507
508                 bools[3] = strings[1] == "Hello"
509                 bools[1] = strings[2] <= "there"
510
511                 for i:=0; then i=i+1; while i<5:
512                         print '', bools[i],
513                 print
514
515 ###### output: arrays
516          False True False False False
517
518 ## Structures
519
520 Time to test if structure declarations and accesses work correctly.
521
522 ###### test list
523         oceani_tests += structs
524
525 ###### test: structs
526
527         struct foo:
528                 size:[3]number
529                 name:string
530                 active:Boolean
531
532         struct baz { a:number; b:Boolean; }
533
534         program:
535                 info:[4]foo
536
537                 for i:=0; then i=i+1; while i < 4:
538                         switch i
539                         case 2: nm:= "peter"
540                         case 0: nm:= "bob"
541                         case 1: nm:= "jane"
542                         else: nm:= "janine"
543
544                         info[i].name = nm
545                         info[i].size[0] = i*i
546                         info[i].active = nm == "jane"
547
548                 for i:=0; then i=i+1; while i < 4:
549                         print info[i].name, info[i].active, info[i].size[0]
550
551 ###### output: structs
552
553         bob False 0
554         jane True 1
555         peter False 4
556         janine False 9
557
558 ## Test code with syntax errors
559
560 Syntax errors aren't handled well yet - the result is almost always a
561 single message about the first error.  So this section will be fairly
562 thin until we add proper parsing recovery in the face of common errors.
563
564 A special case of syntax errors is token errors, when a token is only
565 accepted because the parser doesn't know quite enough to reject it.
566 There are handled better as they are quite local, so a single test
567 program can trigger most of the possible errors.
568
569 To handle erronous code, we need a different set of tests, as we need to
570 capture `stderr`. The same test code will be used for type errors too.
571 As error messages contain the line number, and we don't want changes to
572 this file to change the reported numbers, we copy the code into a
573 separate file first, then run from there.
574
575 ###### test code
576         @for t in $(oceani_failing_tests); do \
577             echo -n "Test $$t ... "; \
578             ./md2c oceani-tests.mdc "output: $$t" | grep -v '^#' > .tmp.want; \
579             echo '``````' > .tmp.code; \
580             ./md2c oceani-tests.mdc "test: $$t" | grep -v '^#' >> .tmp.code; \
581             ./oceani .tmp.code > .tmp.have 2>&1; \
582             if ! cmp -s .tmp.want .tmp.have; then \
583                echo "FAILED"; diff -u .tmp.want .tmp.have ; exit 1; fi ;\
584             echo  "passed"; \
585             ./coverage_oceani --section "test: $$t" oceani-tests.mdc > /dev/null 2>&1 ;\
586         done || true
587
588 ###### test list
589         oceani_failing_tests := syn1
590         oceani_failing_tests += tokerr
591
592 ###### test: syn1
593
594         program:
595                 if then else while do
596
597 ###### output: syn1
598         .tmp.code:3:11: error: unhandled parse error: then
599         oceani: no program found.
600
601 ###### test: tokerr
602         program:
603                 a := 1i  // imaginary numbers aren't understood
604                 b:[2i]number // array sizes are handled separately
605                 c:[3.14159]Boolean // array sizes must be integers
606                 d:[1_000_000_000_000]number // they mustn't be huge
607                 patn: string = "foo[ ,_]*bar"re // regexp strings are just a dream
608
609                 multi := """
610                 This is a multiline string
611                 With an unsupportable suffix
612                 """Aa
613
614                 xx:unknown = 24
615                 yy:[unknowable]number
616                 zzsize := 4
617                 zz:[zzsize]string // size must be constant, use ::=
618
619                 // These numbers should be bad in all contexts: FIXME
620                 aa:[00123]number
621
622 ###### output: tokerr
623         .tmp.code:3:13: error: unsupported number suffix: 1i
624         .tmp.code:4:11: error: unsupported number suffix: 2i
625         .tmp.code:5:11: error: array size must be an integer: 3.14159
626         .tmp.code:6:11: error: array size is too large: 1_000_000_000_000
627         .tmp.code:7:23: error: unsupported string suffix: "foo[ ,_]*bar"re
628         .tmp.code:9:17: error: unsupported string suffix: """
629                 This is a multiline string
630                 With an unsupportable suffix
631                 """Aa
632         .tmp.code:14:11: error: undefined type: unknown
633         .tmp.code:15:12: error: name undeclared: unknowable
634         .tmp.code:17:12: error: array size must be a constant: zzsize
635         .tmp.code:20:12: error: unrecognised number: 00123
636
637 ## Tests for type errors
638
639 Type error don't cause parsing to abort, so we can fit many in the
640 one test program.  Some type errors are found during the parse, others
641 during type analysis which doesn't run if parsing failed.  So we cannot
642 fit everything in one.
643
644 These programs were generated by looking for the
645 various places that `type_err()` are called.
646
647 ###### test list
648         oceani_failing_tests += type_err1 type_err2 type_err3 type_err4
649
650 ###### test: type_err1
651
652         program:
653                 print "hello" ++ 5, 5 ++ "hello"
654
655                 b ::= 3
656                 b = b + 1
657
658                 if 3 * 4 and not True: print "Weird"
659
660 ###### output: type_err1
661         .tmp.code:3:25: error: expected string found number
662         .tmp.code:3:28: error: expected string found number
663         .tmp.code:6:8: error: Cannot assign to a constant: b
664         .tmp.code:5:8: info: name was defined as a constant here
665         .tmp.code:6:8: error: Cannot assign to a constant: b
666         .tmp.code:5:8: info: name was defined as a constant here
667         .tmp.code:8:11: error: Arithmetic returns number but Boolean expected
668         oceani: type error in program - not running.
669
670 ###### test: type_err2
671
672         program:
673                 a := 1
674                 a := 2
675                 a ::= 3
676                 a:number = 4
677                 a ::number = 5
678                 c:
679
680 ###### output: type_err2
681         .tmp.code:4:8: error: variable 'a' redeclared
682         .tmp.code:3:8: info: this is where 'a' was first declared
683         .tmp.code:5:8: error: variable 'a' redeclared
684         .tmp.code:3:8: info: this is where 'a' was first declared
685         .tmp.code:6:8: error: variable 'a' redeclared
686         .tmp.code:3:8: info: this is where 'a' was first declared
687         .tmp.code:7:8: error: variable 'a' redeclared
688         .tmp.code:3:8: info: this is where 'a' was first declared
689         .tmp.code:8:8: Variable declared with no type or value: c
690
691 ###### test: type_err3
692
693         struct foo:
694                 a: number
695                 b:string = "hello"
696
697         program:
698                 c := "hello"
699                 c = c + 1
700                 c = "hello" ++ (True and False)
701                 c = 4 < 5
702                 print 45 + ( "Hello" ++ "there")
703                 c[5] = 1
704
705                 while:
706                         use 1
707                         use True
708                         use "Hello"
709                 do:
710                         print
711                 case 1: print "one"
712                 case "Hello": print "Hello"
713
714                 a1:[5]number; a2:[5]number; a3:[10]number; a4:[5]string
715                 a1 = a2
716                 a1 = a3
717                 a1 = a4
718                 a1[2] = "hello"
719                 a4[1] = True
720                 c = a2[3]
721
722                 bar:foo
723                 foo.c = 43
724                 print c.foo
725
726 ###### output: type_err3
727         .tmp.code:8:12: error: expected number but variable 'c' is string
728         .tmp.code:7:8: info: this is where 'c' was set to string
729         .tmp.code:8:12: error: Arithmetic returns number but string expected
730         .tmp.code:7:8: info: variable 'c' was set as string here.
731         .tmp.code:9:24: error: Boolean operation found where string expected
732         .tmp.code:10:12: error: Comparison returns Boolean but string expected
733         .tmp.code:7:8: info: variable 'c' was set as string here.
734         .tmp.code:11:21: error: Concat returns string but number expected
735         .tmp.code:12:8: error: string cannot be indexed
736         .tmp.code:12:8: error: string cannot be indexed
737         .tmp.code:21:13: error: expected number found string
738         .tmp.code:17:16: error: expected number, found string
739         .tmp.code:24:8: error: cannot assign value of type [5]number
740         .tmp.code:25:13: error: expected [5]number but variable 'a3' is [10]number
741         .tmp.code:23:36: info: this is where 'a3' was set to [10]number
742         .tmp.code:25:8: error: cannot assign value of type [5]number
743         .tmp.code:26:13: error: expected [5]number but variable 'a4' is [5]string
744         .tmp.code:23:51: info: this is where 'a4' was set to [5]string
745         .tmp.code:26:8: error: cannot assign value of type [5]number
746         .tmp.code:27:16: error: expected number found string
747         .tmp.code:28:16: error: expected string found Boolean
748         .tmp.code:29:12: error: have number but need string
749         .tmp.code:7:8: info: variable 'c' was set as string here.
750         .tmp.code:32:8: error: field reference attempted on label, not a struct
751         .tmp.code:32:16: error: expected none found number
752         .tmp.code:33:14: error: field reference attempted on string, not a struct
753         oceani: type error in program - not running.
754
755 ###### test: type_err4
756         program:
757                 a:=1; b=2; c::=3
758                 print a, b, c
759
760 ###### output: type_err4
761         .tmp.code:3:14: error: expected *unknown*type* (labels not permitted) but variable 'b' is label
762         .tmp.code:3:14: info: this is where 'b' was set to label
763         .tmp.code:3:16: error: expected label found number
764         .tmp.code:3:14: info: variable 'b' was set as label here.
765         .tmp.code:4:17: error: expected *unknown*type* (labels not permitted) but variable 'b' is label
766         .tmp.code:3:14: info: this is where 'b' was set to label
767         oceani: type error in program - not running.
768
769 ###### test list
770         oceani_failing_tests += type_err_const type_err_const1
771
772 ###### test: type_err_const
773         const:
774                 foo :: number = 45
775                 bar ::= "string" + 56
776         const:
777                 bar ::= "baz"
778         program:
779                 foo := 4
780                 print foo, bar
781
782 ###### output: type_err_const
783         .tmp.code:4:16: error: expected number found string
784         .tmp.code:6:8: error: name already declared: bar
785         .tmp.code:4:8: info: this is where 'bar' was first declared
786         .tmp.code:8:8: error: variable 'foo' redeclared
787         .tmp.code:3:8: info: this is where 'foo' was first declared
788
789 ###### test: type_err_const1
790         const:
791                 foo : number = 45
792                 bar := "string"
793         program:
794                 foo := 4
795                 print foo, bar
796
797 ###### output: type_err_const1
798         .tmp.code:3:12: error: unhandled parse error: :
799         oceani: no program found.
800
801 ## Test erroneous command line args
802
803 To improve coverage, we want to test correct handling of strange command
804 line arguments.  These tests won't use code, so the exiting test types
805 won't work.  So we need to be able to explicitly give the command line,
806 and the expected output, and have that tested and the coverage assessed.
807 Rather than having to spell out the whole command name, just give "cmd",
808 and discard that.  Requiring but discarding the command make an empty
809 command list possible.
810
811 ###### test code
812         @for t in $(oceani_special_tests); do \
813             echo -n "Test $$t ... ";\
814             i="$$IFS"; IFS=,; set $$t; IFS="$$i"; shift ;\
815             ./md2c oceani-tests.mdc "output: $$t" | grep -v '^#' > .tmp.want; \
816             ./oceani $${1+"$$@"} > .tmp.have 2>&1 ;\
817             if ! cmp -s .tmp.want .tmp.have; then \
818                echo "FAILED"; diff -u .tmp.want .tmp.have ; exit 1; fi ;\
819             echo  "passed"; \
820             ./coverage_oceani $${1+"$$@"} > /dev/null 2>&1 ;\
821         done || true
822
823 ###### test list
824         oceani_special_tests += "cmd"
825         oceani_special_tests += "cmd,-zyx"
826         oceani_special_tests += "cmd,nofile"
827         oceani_special_tests += "cmd,/dev/null"
828         oceani_special_tests += "cmd,--section,toast:nothing,oceani-tests.mdc"
829
830 ###### output: cmd
831         oceani: no input file given
832
833 ###### output: cmd,-zyx
834         ./oceani: invalid option -- 'z'
835         Usage: oceani --trace --print --noexec --brackets--section=SectionName prog.ocn
836
837 ###### output: cmd,nofile
838         oceani: cannot open nofile
839
840 ###### output: cmd,/dev/null
841         oceani: could not find any code in /dev/null
842
843 ###### output: cmd,--section,toast:nothing,oceani-tests.mdc
844         oceani: cannot find section toast:nothing