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