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