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