X-Git-Url: https://ocean-lang.org/code/?a=blobdiff_plain;f=csrc%2Foceani-tests.mdc;h=5366bf92ddf60e1045c5b0ed3a9bc6bee6cc560f;hb=5b077f5f80cd36fed3b006dd5b0b1cc9025c1b22;hp=d0b14190e7a31ff1fc59a0f7c1c0c6bdbcff7279;hpb=4e5c62ce299f422fa51b96245f74f652e3511433;p=ocean diff --git a/csrc/oceani-tests.mdc b/csrc/oceani-tests.mdc index d0b1419..5366bf9 100644 --- a/csrc/oceani-tests.mdc +++ b/csrc/oceani-tests.mdc @@ -38,26 +38,30 @@ arguments separated from the name by commas. For each test, there is a section tests:: oceani_test_suite oceani_test_suite: oceani coverage_oceani + @echo -n Checking grammar ... + @./parsergen --report --LALR --tag Parser oceani.mdc | grep " - no conflicts" > /dev/null || \ + { echo "Grammar contains conflicts, please review" ; exit 1; } + @echo ok @rm -rf coverage; mkdir -p coverage @cp *.gcno coverage @for T in $(oceani_tests); do \ - echo -n "Test $$T ... "; \ + echo -n "Test $$T.. "; \ i="$$IFS"; IFS=,; set $$T; IFS="$$i"; t=$$1; shift; \ ./md2c oceani-tests.mdc "output: $$T" | grep -v '^#' > .tmp.want; \ ./oceani --section "test: $$t" oceani-tests.mdc $${1+"$$@"} > .tmp.have; \ if ! cmp -s .tmp.want .tmp.have; then \ echo "FAILED"; diff -u .tmp.want .tmp.have ; exit 1; fi ;\ - echo -n "passed ... "; \ - if ! valgrind ./oceani --section "test: $$t" oceani-tests.mdc $${1+"$$@"} \ - > /dev/null 2> .tmp.valg; then \ - echo "valgrind FAILED"; cat .tmp.valg; exit 1; fi ; \ - echo -n "valgrind passed ... "; \ + echo -n "printing.. "; \ echo '``````' > .tmp.code1; echo '``````' > .tmp.code2 ;\ ./oceani --noexec --print --section "test: $$t" oceani-tests.mdc >> .tmp.code1; \ ./oceani --noexec --print .tmp.code1 >> .tmp.code2 ;\ if ! cmp -s .tmp.code1 .tmp.code2; then \ - echo "Printing Failed"; diff -u .tmp.code1 .tmp.code2; exit1 ; fi ; \ - echo "Printing passed"; \ + echo " Failed"; diff -u .tmp.code1 .tmp.code2; exit 1 ; fi ; \ + echo -n "exec-after-print.. "; \ + ./oceani .tmp.code1 $${1+"$$@"} > .tmp.have ; \ + if ! cmp -s .tmp.want .tmp.have; then \ + echo " FAILED"; diff -u .tmp.want .tmp.have; exit 1;fi; \ + echo " all passed"; \ ./coverage_oceani --print --section "test: $$t" oceani-tests.mdc $${1+"$$@"} > /dev/null ; \ ./coverage_oceani -tpbn --section "test: $$t" oceani-tests.mdc > /dev/null 2>&1; \ done @@ -66,12 +70,25 @@ arguments separated from the name by commas. For each test, there is a section @gcov -o coverage oceani.mdc > /dev/null 2> /dev/null @mv *.gcov coverage ; [ -f .gcov ] && mv .gcov coverage - @ awk '/^ *[1-9]/ {ran+=1} /^ *###/ {skip+=1} \ + @ awk '/NOTEST/ { next } /^ *[1-9]/ {ran+=1} /^ *###/ {skip+=1} \ END {printf "coverage: %6.2f%%\n", ran * 100 / (ran + skip); \ - if (ran < (ran + skip) *0.8) exit(1) }' \ + if (ran < (ran + skip) *0.94) exit(1) }' \ coverage/oceani.mdc.gcov @rm -f .tmp* + @for T in $(oceani_tests); do \ + echo -n "Valgrind $$T.. "; \ + i="$$IFS"; IFS=,; set $$T; IFS="$$i"; t=$$1; shift; \ + if ! valgrind --error-exitcode=1 --log-file=.tmp.valg ./oceani --section "test: $$t" oceani-tests.mdc $${1+"$$@"} \ + > /dev/null 2>&1 ; then \ + echo "FAILED"; cat .tmp.valg; exit 1; fi ; \ + if grep 'LEAK SUMMARY' .tmp.valg > /dev/null; then \ + echo "valgrind found LEAKS"; cat .tmp.valg ; exit 1 ; fi; \ + if grep 'in use at exit [1-9]' .tmp.valg > /dev/null; then \ + echo "valgrind found memory in use at exit"; cat .tmp.valg ; exit 1 ; fi; \ + echo " passed"; \ + done + coverage_oceani: oceani.c $(CC) $(CFLAGS) --coverage -fprofile-dir=coverage -o coverage_oceani oceani.c $(LDLIBS) @@ -83,23 +100,37 @@ calculations on them. ###### test list oceani_tests += "valvar" - ###### test: valvar program: - a := 23; b:=12 + a := 23; b:=12 ; b1 := -b print a, b, a+b, a-b, a*b, a/b, a%b print ab, a>=b, a 3: + print "20 /", j," =", 20 / j + else: + print "I won't calculate 20 /", j + pi ::= 3.1415926535897 + if 355/113 == pi or else +(pi - 355/113) < 0.001: + print "Close enough" + print "lower" if 355/113 < pi else "higher" + ###### output: cond_loop Success 1 2 4 8 16 32 64 @@ -158,6 +243,12 @@ Now we need to test if/else and some different loops 2 1.41422 3 1.41421 error is -4.51095e-12 + I won't calculate 20 / 0 + 20 / 3 = 6.66667 + 20 / 6 = 3.33333 + I won't calculate 20 / 9 + Close enough + higher ## Say Hello @@ -165,12 +256,12 @@ The demonstration code presented in the interpreted is suitable for the test sui Here I break it into two parts, keeping the array code separate. ###### test list - oceani_tests += "sayhello,55,33" - oceani_tests += "sayhello,12,60" + oceani_tests += "sayhello,55,33,hello,True" + oceani_tests += "sayhello,12,60,there,False" ###### test: sayhello - program A B: + program A B astr bbool: print "Hello World, what lovely oceans you have!" /* When a variable is defined in both branches of an 'if', * and used afterwards, the variables are merged. @@ -217,6 +308,11 @@ Here I break it into two parts, keeping the array code separate. f2 = f3 print "" + if bbool: + print astr ++ " was the str" + else: + print "I found the str over " ++ astr + /* Binary search... */ for: lo:= 0; hi := 100 @@ -238,20 +334,22 @@ Here I break it into two parts, keeping the array code separate. case GiveUp: print "Closest I found was", mid -###### output: sayhello,55,33 +###### output: sayhello,55,33,hello,True Hello World, what lovely oceans you have! Is 55 bigger than 33 ? yes double 33 is 66 GCD of 55 and 33 is 11 Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144 + hello was the str Closest I found was 77.3438 -###### output: sayhello,12,60 +###### output: sayhello,12,60,there,False Hello World, what lovely oceans you have! Is 12 bigger than 60 ? no double 60 is 120 GCD of 12 and 60 is 12 Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144 + I found the str over there Closest I found was 77.3438 ###### test list @@ -260,7 +358,7 @@ Here I break it into two parts, keeping the array code separate. program: size::=55 list:[size]number - list[0] = 1234 + list[0] = 1_234 for i:=1; then i = i + 1; while i < size: n := list[i-1] * list[i-1] list[i] = (n / 100) % 10000 @@ -393,6 +491,70 @@ Here I break it into two parts, keeping the array code separate. list[ 53 ]= 9040 list[ 54 ]= 9768 +## Arrays + +We already have some array tests, but this is where we put other +ad-hoc things array related. + +###### test list + oceani_tests += arrays + +###### test: arrays + + program: + bools:[5]Boolean + strings:[4]string + + bools[3] = strings[1] == "Hello" + bools[1] = strings[2] <= "there" + + for i:=0; then i=i+1; while i<5: + print '', bools[i], + print + +###### output: arrays + False True False False False + +## Structures + +Time to test if structure declarations and accesses work correctly. + +###### test list + oceani_tests += structs + +###### test: structs + + struct foo: + size:[3]number + name:string + active:Boolean + + struct baz { a:number; b:Boolean; } + + program: + info:[4]foo + + for i:=0; then i=i+1; while i < 4: + switch i + case 2: nm:= "peter" + case 0: nm:= "bob" + case 1: nm:= "jane" + else: nm:= "janine" + + info[i].name = nm + info[i].size[0] = i*i + info[i].active = nm == "jane" + + for i:=0; then i=i+1; while i < 4: + print info[i].name, info[i].active, info[i].size[0] + +###### output: structs + + bob False 0 + jane True 1 + peter False 4 + janine False 9 + ## Test code with syntax errors Syntax errors aren't handled well yet - the result is almost always a @@ -433,7 +595,7 @@ separate file first, then run from there. if then else while do ###### output: syn1 - .tmp.code:3:11: error: unhandled parse error: then + .tmp.code:3:11: Syntax error in statement: then ###### test: tokerr program: @@ -453,6 +615,9 @@ separate file first, then run from there. zzsize := 4 zz:[zzsize]string // size must be constant, use ::= + // These numbers should be bad in all contexts: FIXME + aa:[00123]number + ###### output: tokerr .tmp.code:3:13: error: unsupported number suffix: 1i .tmp.code:4:11: error: unsupported number suffix: 2i @@ -466,6 +631,169 @@ separate file first, then run from there. .tmp.code:14:11: error: undefined type: unknown .tmp.code:15:12: error: name undeclared: unknowable .tmp.code:17:12: error: array size must be a constant: zzsize + .tmp.code:20:12: error: unrecognised number: 00123 + +## Tests for type errors + +Type error don't cause parsing to abort, so we can fit many in the +one test program. Some type errors are found during the parse, others +during type analysis which doesn't run if parsing failed. So we cannot +fit everything in one. + +These programs were generated by looking for the +various places that `type_err()` are called. + +###### test list + oceani_failing_tests += type_err1 type_err2 type_err3 type_err4 + +###### test: type_err1 + + program: + print "hello" ++ 5, 5 ++ "hello" + + b ::= 3 + b = b + 1 + + if 3 * 4 and not True: print "Weird" + +###### output: type_err1 + .tmp.code:3:25: error: expected string found number + .tmp.code:3:28: error: expected string found number + .tmp.code:6:8: error: Cannot assign to a constant: b + .tmp.code:5:8: info: name was defined as a constant here + .tmp.code:6:8: error: Cannot assign to a constant: b + .tmp.code:5:8: info: name was defined as a constant here + .tmp.code:8:11: error: Arithmetic returns number but Boolean expected + oceani: type error in program - not running. + +###### test: type_err2 + + program: + a := 1 + a := 2 + a ::= 3 + a:number = 4 + a ::number = 5 + c: + +###### output: type_err2 + .tmp.code:4:8: error: variable 'a' redeclared + .tmp.code:3:8: info: this is where 'a' was first declared + .tmp.code:5:8: error: variable 'a' redeclared + .tmp.code:3:8: info: this is where 'a' was first declared + .tmp.code:6:8: error: variable 'a' redeclared + .tmp.code:3:8: info: this is where 'a' was first declared + .tmp.code:7:8: error: variable 'a' redeclared + .tmp.code:3:8: info: this is where 'a' was first declared + .tmp.code:8:8: Variable declared with no type or value: c + +###### test: type_err3 + + struct foo: + a: number + b:string = "hello" + + program: + c := "hello" + c = c + 1 + c = "hello" ++ (True and False) + c = 4 < 5 + print 45 + ( "Hello" ++ "there") + c[5] = 1 + + while: + use 1 + use True + use "Hello" + do: + print + case 1: print "one" + case "Hello": print "Hello" + + a1:[5]number; a2:[5]number; a3:[10]number; a4:[5]string + a1 = a2 + a1 = a3 + a1 = a4 + a1[2] = "hello" + a4[1] = True + c = a2[3] + + bar:foo + foo.c = 43 + print c.foo + +###### output: type_err3 + .tmp.code:8:12: error: expected number but variable 'c' is string + .tmp.code:7:8: info: this is where 'c' was set to string + .tmp.code:8:12: error: Arithmetic returns number but string expected + .tmp.code:7:8: info: variable 'c' was set as string here. + .tmp.code:9:24: error: Boolean operation found where string expected + .tmp.code:10:12: error: Comparison returns Boolean but string expected + .tmp.code:7:8: info: variable 'c' was set as string here. + .tmp.code:11:21: error: Concat returns string but number expected + .tmp.code:12:8: error: string cannot be indexed + .tmp.code:12:8: error: string cannot be indexed + .tmp.code:21:13: error: expected number found string + .tmp.code:17:16: error: expected number, found string + .tmp.code:24:8: error: cannot assign value of type [5]number + .tmp.code:25:13: error: expected [5]number but variable 'a3' is [10]number + .tmp.code:23:36: info: this is where 'a3' was set to [10]number + .tmp.code:25:8: error: cannot assign value of type [5]number + .tmp.code:26:13: error: expected [5]number but variable 'a4' is [5]string + .tmp.code:23:51: info: this is where 'a4' was set to [5]string + .tmp.code:26:8: error: cannot assign value of type [5]number + .tmp.code:27:16: error: expected number found string + .tmp.code:28:16: error: expected string found Boolean + .tmp.code:29:12: error: have number but need string + .tmp.code:7:8: info: variable 'c' was set as string here. + .tmp.code:32:8: error: variable used but not declared: foo + .tmp.code:32:8: error: field reference attempted on none, not a struct + .tmp.code:32:16: error: expected none found number + .tmp.code:33:14: error: field reference attempted on string, not a struct + oceani: type error in program - not running. + +###### test: type_err4 + program: + a:=1; b=2; c::=3 + print a, b, c + +###### output: type_err4 + .tmp.code:3:14: error: variable used but not declared: b + .tmp.code:3:16: error: expected none found number + .tmp.code:3:14: info: variable 'b' was set as none here. + oceani: type error in program - not running. + +###### test list + oceani_failing_tests += type_err_const type_err_const1 + +###### test: type_err_const + const: + foo :: number = 45 + bar ::= "string" + 56 + const: + bar ::= "baz" + program: + foo := 4 + print foo, bar + +###### output: type_err_const + .tmp.code:4:16: error: expected number found string + .tmp.code:6:8: error: name already declared: bar + .tmp.code:4:8: info: this is where 'bar' was first declared + .tmp.code:8:8: error: variable 'foo' redeclared + .tmp.code:3:8: info: this is where 'foo' was first declared + +###### test: type_err_const1 + const: + foo : number = 45 + bar := "string" + program: + foo := 4 + print foo, bar + +###### output: type_err_const1 + .tmp.code:3:12: Syntax error in constant: : + .tmp.code:4:8: Syntax error in constant: bar ## Test erroneous command line args @@ -489,7 +817,6 @@ command list possible. ./coverage_oceani $${1+"$$@"} > /dev/null 2>&1 ;\ done || true - ###### test list oceani_special_tests += "cmd" oceani_special_tests += "cmd,-zyx" @@ -512,4 +839,3 @@ command list possible. ###### output: cmd,--section,toast:nothing,oceani-tests.mdc oceani: cannot find section toast:nothing -