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