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