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