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