]> ocean-lang.org Git - ocean/blob - csrc/oceani-tests.mdc
oceani-tests: add tests for str/bool command line args
[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
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,hello,True"
251         oceani_tests += "sayhello,12,60,there,False"
252
253 ###### test: sayhello
254
255         program A B astr bbool:
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                 if bbool:
303                         print astr ++ " was the str"
304                 else:
305                         print "I found the str over " ++ astr
306
307                 /* Binary search... */
308                 for:
309                         lo:= 0; hi := 100
310                         target := 77
311                 while:
312                         mid := (lo + hi) / 2
313                         if mid == target:
314                                 use Found
315                         if mid < target:
316                                 lo = mid
317                         else:
318                                 hi = mid
319                         if hi - lo < 1:
320                                 use GiveUp
321                         use True
322                 do: pass
323                 case Found:
324                         print "Yay, I found", target
325                 case GiveUp:
326                         print "Closest I found was", mid
327
328 ###### output: sayhello,55,33,hello,True
329         Hello World, what lovely oceans you have!
330         Is 55 bigger than 33 ?  yes
331         double 33 is 66
332         GCD of 55 and 33 is 11
333         Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
334         hello was the str
335         Closest I found was 77.3438
336
337 ###### output: sayhello,12,60,there,False
338         Hello World, what lovely oceans you have!
339         Is 12 bigger than 60 ?  no
340         double 60 is 120
341         GCD of 12 and 60 is 12
342         Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
343         I found the str over there
344         Closest I found was 77.3438
345
346 ###### test list
347         oceani_tests += "insert_sort"
348 ###### test: insert_sort
349         program:
350                 size::=55
351                 list:[size]number
352                 list[0] = 1234
353                 for i:=1; then i = i + 1; while i < size:
354                         n := list[i-1] * list[i-1]
355                         list[i] = (n / 100) % 10000
356
357                 print "Before sort:"
358                 for i:=0; then i = i + 1; while i < size:
359                         print "list[",i,"]=",list[i]
360
361                 for i := 1; then i=i+1; while i < size:
362                         for j:=i-1; then j=j-1; while j >= 0:
363                                 if list[j] > list[j+1]:
364                                         t:= list[j]
365                                         list[j] = list[j+1]
366                                         list[j+1] = t
367                 print "After sort:"
368                 for i:=0; then i = i + 1; while i < size:
369                         print "list[",i,"]=",list[i]
370
371 ###### output: insert_sort
372         Before sort:
373         list[ 0 ]= 1234
374         list[ 1 ]= 5227
375         list[ 2 ]= 3215
376         list[ 3 ]= 3362
377         list[ 4 ]= 3030
378         list[ 5 ]= 1809
379         list[ 6 ]= 2724
380         list[ 7 ]= 4201
381         list[ 8 ]= 6484
382         list[ 9 ]= 422
383         list[ 10 ]= 1780
384         list[ 11 ]= 1684
385         list[ 12 ]= 8358
386         list[ 13 ]= 8561
387         list[ 14 ]= 2907
388         list[ 15 ]= 4506
389         list[ 16 ]= 3040
390         list[ 17 ]= 2416
391         list[ 18 ]= 8370
392         list[ 19 ]= 569
393         list[ 20 ]= 3237
394         list[ 21 ]= 4781
395         list[ 22 ]= 8579
396         list[ 23 ]= 5992
397         list[ 24 ]= 9040
398         list[ 25 ]= 7216
399         list[ 26 ]= 706
400         list[ 27 ]= 4984
401         list[ 28 ]= 8402
402         list[ 29 ]= 5936
403         list[ 30 ]= 2360
404         list[ 31 ]= 5696
405         list[ 32 ]= 4444
406         list[ 33 ]= 7491
407         list[ 34 ]= 1150
408         list[ 35 ]= 3225
409         list[ 36 ]= 4006
410         list[ 37 ]= 480
411         list[ 38 ]= 2304
412         list[ 39 ]= 3084
413         list[ 40 ]= 5110
414         list[ 41 ]= 1121
415         list[ 42 ]= 2566
416         list[ 43 ]= 5843
417         list[ 44 ]= 1406
418         list[ 45 ]= 9768
419         list[ 46 ]= 4138
420         list[ 47 ]= 1230
421         list[ 48 ]= 5129
422         list[ 49 ]= 3066
423         list[ 50 ]= 4003
424         list[ 51 ]= 240
425         list[ 52 ]= 576
426         list[ 53 ]= 3317
427         list[ 54 ]= 24
428         After sort:
429         list[ 0 ]= 24
430         list[ 1 ]= 240
431         list[ 2 ]= 422
432         list[ 3 ]= 480
433         list[ 4 ]= 569
434         list[ 5 ]= 576
435         list[ 6 ]= 706
436         list[ 7 ]= 1121
437         list[ 8 ]= 1150
438         list[ 9 ]= 1230
439         list[ 10 ]= 1234
440         list[ 11 ]= 1406
441         list[ 12 ]= 1684
442         list[ 13 ]= 1780
443         list[ 14 ]= 1809
444         list[ 15 ]= 2304
445         list[ 16 ]= 2360
446         list[ 17 ]= 2416
447         list[ 18 ]= 2566
448         list[ 19 ]= 2724
449         list[ 20 ]= 2907
450         list[ 21 ]= 3030
451         list[ 22 ]= 3040
452         list[ 23 ]= 3066
453         list[ 24 ]= 3084
454         list[ 25 ]= 3215
455         list[ 26 ]= 3225
456         list[ 27 ]= 3237
457         list[ 28 ]= 3317
458         list[ 29 ]= 3362
459         list[ 30 ]= 4003
460         list[ 31 ]= 4006
461         list[ 32 ]= 4138
462         list[ 33 ]= 4201
463         list[ 34 ]= 4444
464         list[ 35 ]= 4506
465         list[ 36 ]= 4781
466         list[ 37 ]= 4984
467         list[ 38 ]= 5110
468         list[ 39 ]= 5129
469         list[ 40 ]= 5227
470         list[ 41 ]= 5696
471         list[ 42 ]= 5843
472         list[ 43 ]= 5936
473         list[ 44 ]= 5992
474         list[ 45 ]= 6484
475         list[ 46 ]= 7216
476         list[ 47 ]= 7491
477         list[ 48 ]= 8358
478         list[ 49 ]= 8370
479         list[ 50 ]= 8402
480         list[ 51 ]= 8561
481         list[ 52 ]= 8579
482         list[ 53 ]= 9040
483         list[ 54 ]= 9768
484
485 ## Arrays
486
487 We already have some array tests, but this is where we put other
488 ad-hoc things array related.
489
490 ###### test list
491         oceani_tests += arrays
492
493 ###### test: arrays
494
495         program:
496                 bools:[5]Boolean
497                 strings:[4]string
498
499                 bools[3] = strings[1] == "Hello"
500                 bools[1] = strings[2] <= "there"
501
502                 for i:=0; then i=i+1; while i<5:
503                         print '', bools[i],
504                 print
505
506 ###### output: arrays
507          False True False False False
508
509 ## Structures
510
511 Time to test if structure declarations and accesses work correctly.
512
513 ###### test list
514         oceani_tests += structs
515
516 ###### test: structs
517
518         struct foo:
519                 size:[3]number
520                 name:string
521                 active:Boolean
522
523         struct baz { a:number; b:Boolean; }
524
525         program:
526                 info:[4]foo
527
528                 for i:=0; then i=i+1; while i < 4:
529                         switch i
530                         case 2: nm:= "peter"
531                         case 0: nm:= "bob"
532                         case 1: nm:= "jane"
533                         else: nm:= "janine"
534
535                         info[i].name = nm
536                         info[i].size[0] = i*i
537                         info[i].active = nm == "jane"
538
539                 for i:=0; then i=i+1; while i < 4:
540                         print info[i].name, info[i].active, info[i].size[0]
541
542 ###### output: structs
543
544         bob False 0
545         jane True 1
546         peter False 4
547         janine False 9
548
549 ## Test code with syntax errors
550
551 Syntax errors aren't handled well yet - the result is almost always a
552 single message about the first error.  So this section will be fairly
553 thin until we add proper parsing recovery in the face of common errors.
554
555 A special case of syntax errors is token errors, when a token is only
556 accepted because the parser doesn't know quite enough to reject it.
557 There are handled better as they are quite local, so a single test
558 program can trigger most of the possible errors.
559
560 To handle erronous code, we need a different set of tests, as we need to
561 capture `stderr`. The same test code will be used for type errors too.
562 As error messages contain the line number, and we don't want changes to
563 this file to change the reported numbers, we copy the code into a
564 separate file first, then run from there.
565
566 ###### test code
567         @for t in $(oceani_failing_tests); do \
568             echo -n "Test $$t ... "; \
569             ./md2c oceani-tests.mdc "output: $$t" | grep -v '^#' > .tmp.want; \
570             echo '``````' > .tmp.code; \
571             ./md2c oceani-tests.mdc "test: $$t" | grep -v '^#' >> .tmp.code; \
572             ./oceani .tmp.code > .tmp.have 2>&1; \
573             if ! cmp -s .tmp.want .tmp.have; then \
574                echo "FAILED"; diff -u .tmp.want .tmp.have ; exit 1; fi ;\
575             echo  "passed"; \
576             ./coverage_oceani --section "test: $$t" oceani-tests.mdc > /dev/null 2>&1 ;\
577         done || true
578
579 ###### test list
580         oceani_failing_tests := syn1
581         oceani_failing_tests += tokerr
582
583 ###### test: syn1
584
585         program:
586                 if then else while do
587
588 ###### output: syn1
589         .tmp.code:3:11: error: unhandled parse error: then
590         oceani: no program found.
591
592 ###### test: tokerr
593         program:
594                 a := 1i  // imaginary numbers aren't understood
595                 b:[2i]number // array sizes are handled separately
596                 c:[3.14159]Boolean // array sizes must be integers
597                 d:[1_000_000_000_000]number // they mustn't be huge
598                 patn: string = "foo[ ,_]*bar"re // regexp strings are just a dream
599
600                 multi := """
601                 This is a multiline string
602                 With an unsupportable suffix
603                 """Aa
604
605                 xx:unknown = 24
606                 yy:[unknowable]number
607                 zzsize := 4
608                 zz:[zzsize]string // size must be constant, use ::=
609
610                 // These numbers should be bad in all contexts: FIXME
611                 aa:[00123]number
612
613 ###### output: tokerr
614         .tmp.code:3:13: error: unsupported number suffix: 1i
615         .tmp.code:4:11: error: unsupported number suffix: 2i
616         .tmp.code:5:11: error: array size must be an integer: 3.14159
617         .tmp.code:6:11: error: array size is too large: 1_000_000_000_000
618         .tmp.code:7:23: error: unsupported string suffix: "foo[ ,_]*bar"re
619         .tmp.code:9:17: error: unsupported string suffix: """
620                 This is a multiline string
621                 With an unsupportable suffix
622                 """Aa
623         .tmp.code:14:11: error: undefined type: unknown
624         .tmp.code:15:12: error: name undeclared: unknowable
625         .tmp.code:17:12: error: array size must be a constant: zzsize
626         .tmp.code:20:12: error: unrecognised number: 00123
627
628 ## Tests for type errors
629
630 Type error don't cause parsing to abort, so we can fit many in the
631 one test program.  Some type errors are found during the parse, others
632 during type analysis which doesn't run if parsing failed.  So we cannot
633 fit everything in one.
634
635 These programs were generated by looking for the
636 various places that `type_err()` are called.
637
638 ###### test list
639         oceani_failing_tests += type_err1 type_err2 type_err3 type_err4
640
641 ###### test: type_err1
642
643         program:
644                 print "hello" ++ 5, 5 ++ "hello"
645
646                 b ::= 3
647                 b = b + 1
648
649                 if 3 * 4 and not True: print "Weird"
650
651 ###### output: type_err1
652         .tmp.code:3:25: error: expected string found number
653         .tmp.code:3:28: error: expected string found number
654         .tmp.code:6:8: error: Cannot assign to a constant: b
655         .tmp.code:5:8: info: name was defined as a constant here
656         .tmp.code:6:8: error: Cannot assign to a constant: b
657         .tmp.code:5:8: info: name was defined as a constant here
658         .tmp.code:8:11: error: Arithmetic returns number but Boolean expected
659         oceani: type error in program - not running.
660
661 ###### test: type_err2
662
663         program:
664                 a := 1
665                 a := 2
666                 a ::= 3
667                 a:number = 4
668                 a ::number = 5
669                 c:
670
671 ###### output: type_err2
672         .tmp.code:4:8: error: variable 'a' redeclared
673         .tmp.code:3:8: info: this is where 'a' was first declared
674         .tmp.code:5:8: error: variable 'a' redeclared
675         .tmp.code:3:8: info: this is where 'a' was first declared
676         .tmp.code:6:8: error: variable 'a' redeclared
677         .tmp.code:3:8: info: this is where 'a' was first declared
678         .tmp.code:7:8: error: variable 'a' redeclared
679         .tmp.code:3:8: info: this is where 'a' was first declared
680         .tmp.code:8:8: Variable declared with no type or value: c
681
682 ###### test: type_err3
683
684         struct foo:
685                 a: number
686                 b:string = "hello"
687
688         program:
689                 c := "hello"
690                 c = c + 1
691                 c = "hello" ++ (True and False)
692                 c = 4 < 5
693                 print 45 + ( "Hello" ++ "there")
694                 c[5] = 1
695
696                 while:
697                         use 1
698                         use True
699                         use "Hello"
700                 do:
701                         print
702                 case 1: print "one"
703                 case "Hello": print "Hello"
704
705                 a1:[5]number; a2:[5]number; a3:[10]number; a4:[5]string
706                 a1 = a2
707                 a1 = a3
708                 a1 = a4
709                 a1[2] = "hello"
710                 a4[1] = True
711                 c = a2[3]
712
713                 bar:foo
714                 foo.c = 43
715                 print c.foo
716
717 ###### output: type_err3
718         .tmp.code:8:12: error: expected number but variable 'c' is string
719         .tmp.code:7:8: info: this is where 'c' was set to string
720         .tmp.code:8:12: error: Arithmetic returns number but string expected
721         .tmp.code:7:8: info: variable 'c' was set as string here.
722         .tmp.code:9:24: error: Boolean operation found where string expected
723         .tmp.code:10:12: error: Comparison returns Boolean but string expected
724         .tmp.code:7:8: info: variable 'c' was set as string here.
725         .tmp.code:11:21: error: Concat returns string but number expected
726         .tmp.code:12:8: error: string cannot be indexed
727         .tmp.code:12:8: error: string cannot be indexed
728         .tmp.code:21:13: error: expected number found string
729         .tmp.code:17:16: error: expected number, found string
730         .tmp.code:24:8: error: cannot assign value of type [5]number
731         .tmp.code:25:13: error: expected [5]number but variable 'a3' is [10]number
732         .tmp.code:23:36: info: this is where 'a3' was set to [10]number
733         .tmp.code:25:8: error: cannot assign value of type [5]number
734         .tmp.code:26:13: error: expected [5]number but variable 'a4' is [5]string
735         .tmp.code:23:51: info: this is where 'a4' was set to [5]string
736         .tmp.code:26:8: error: cannot assign value of type [5]number
737         .tmp.code:27:16: error: expected number found string
738         .tmp.code:28:16: error: expected string found Boolean
739         .tmp.code:29:12: error: have number but need string
740         .tmp.code:7:8: info: variable 'c' was set as string here.
741         .tmp.code:32:8: error: field reference attempted on label, not a struct
742         .tmp.code:32:16: error: expected none found number
743         .tmp.code:33:14: error: field reference attempted on string, not a struct
744         oceani: type error in program - not running.
745
746 ###### test: type_err4
747         program:
748                 a:=1; b=2; c::=3
749                 print a, b, c
750
751 ###### output: type_err4
752         .tmp.code:3:14: error: expected *unknown*type* (labels not permitted) but variable 'b' is label
753         .tmp.code:3:14: info: this is where 'b' was set to label
754         .tmp.code:3:16: error: expected label found number
755         .tmp.code:3:14: info: variable 'b' was set as label here.
756         .tmp.code:4:17: error: expected *unknown*type* (labels not permitted) but variable 'b' is label
757         .tmp.code:3:14: info: this is where 'b' was set to label
758         oceani: type error in program - not running.
759
760 ###### test list
761         oceani_failing_tests += type_err_const type_err_const1
762
763 ###### test: type_err_const
764         const:
765                 foo :: number = 45
766                 bar ::= "string" + 56
767         const:
768                 bar ::= "baz"
769         program:
770                 foo := 4
771                 print foo, bar
772
773 ###### output: type_err_const
774         .tmp.code:4:16: error: expected number found string
775         .tmp.code:6:8: error: name already declared: bar
776         .tmp.code:4:8: info: this is where 'bar' was first declared
777         .tmp.code:8:8: error: variable 'foo' redeclared
778         .tmp.code:3:8: info: this is where 'foo' was first declared
779
780 ###### test: type_err_const1
781         const:
782                 foo : number = 45
783                 bar := "string"
784         program:
785                 foo := 4
786                 print foo, bar
787
788 ###### output: type_err_const1
789         .tmp.code:3:12: error: unhandled parse error: :
790         oceani: no program found.
791
792
793 ## Test erroneous command line args
794
795 To improve coverage, we want to test correct handling of strange command
796 line arguments.  These tests won't use code, so the exiting test types
797 won't work.  So we need to be able to explicitly give the command line,
798 and the expected output, and have that tested and the coverage assessed.
799 Rather than having to spell out the whole command name, just give "cmd",
800 and discard that.  Requiring but discarding the command make an empty
801 command list possible.
802
803 ###### test code
804         @for t in $(oceani_special_tests); do \
805             echo -n "Test $$t ... ";\
806             i="$$IFS"; IFS=,; set $$t; IFS="$$i"; shift ;\
807             ./md2c oceani-tests.mdc "output: $$t" | grep -v '^#' > .tmp.want; \
808             ./oceani $${1+"$$@"} > .tmp.have 2>&1 ;\
809             if ! cmp -s .tmp.want .tmp.have; then \
810                echo "FAILED"; diff -u .tmp.want .tmp.have ; exit 1; fi ;\
811             echo  "passed"; \
812             ./coverage_oceani $${1+"$$@"} > /dev/null 2>&1 ;\
813         done || true
814
815
816 ###### test list
817         oceani_special_tests += "cmd"
818         oceani_special_tests += "cmd,-zyx"
819         oceani_special_tests += "cmd,nofile"
820         oceani_special_tests += "cmd,/dev/null"
821         oceani_special_tests += "cmd,--section,toast:nothing,oceani-tests.mdc"
822
823 ###### output: cmd
824         oceani: no input file given
825
826 ###### output: cmd,-zyx
827         ./oceani: invalid option -- 'z'
828         Usage: oceani --trace --print --noexec --brackets--section=SectionName prog.ocn
829
830 ###### output: cmd,nofile
831         oceani: cannot open nofile
832
833 ###### output: cmd,/dev/null
834         oceani: could not find any code in /dev/null
835
836 ###### output: cmd,--section,toast:nothing,oceani-tests.mdc
837         oceani: cannot find section toast:nothing