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