]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani-tests.mdc
oceani: discard Rnolabel
[ocean] / csrc / oceani-tests.mdc
index 04b9458dbf422cc4659fcc8596cba089a66043c9..fc26950189e93bdc61e11e590a4d29429f294c2b 100644 (file)
@@ -35,11 +35,15 @@ arguments separated from the name by commas.  For each test, there is a section
 
        oceani_tests :=
        ## test list
+       oceani_valg_tests := $(oceani_tests)
+       ## combine test lists
 
        tests:: oceani_test_suite
        oceani_test_suite: oceani coverage_oceani
-               @./parsergen --report --LR1 --tag Parser oceani.mdc | grep " - no conflicts" > /dev/null || \
-                   { echo "Grammar container conflicts, please review" ; exit 1; }
+               @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 \
@@ -52,9 +56,16 @@ arguments separated from the name by commas.  For each test, there is a section
                    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 ;\
+                   ./oceani --noexec --print .tmp.code1 >> .tmp.code2 || exit 1;\
                    if ! cmp -s .tmp.code1 .tmp.code2; then \
                       echo " Failed"; diff -u .tmp.code1 .tmp.code2; exit 1 ; fi ; \
+                   echo -n "extra-newlines.. "; \
+                   sed -e 'i\
+                   ' .tmp.code1 > .tmp.code1a; \
+                   echo '``````' > .tmp.code2a ;\
+                   ./oceani --noexec --print .tmp.code1a >> .tmp.code2a || exit 1;\
+                   if ! cmp -s .tmp.code1 .tmp.code2a; then \
+                      echo " Failed"; diff -u .tmp.code1 .tmp.code2a; exit 1; fi ; \
                    echo -n "exec-after-print.. "; \
                    ./oceani .tmp.code1 $${1+"$$@"} > .tmp.have ; \
                    if ! cmp -s .tmp.want .tmp.have; then \
@@ -66,19 +77,16 @@ arguments separated from the name by commas.  For each test, there is a section
 
                ## test code
 
+               @for i in coverage/#*.gcda; do mv $$i coverage/$${i##*#}; done
                @gcov -o coverage oceani.mdc > /dev/null 2> /dev/null
-               @mv *.gcov coverage ; [ -f .gcov ] && mv .gcov coverage
-               @ awk '/NOTEST/ { next } /^ *[1-9]/ {ran+=1} /^ *###/ {skip+=1} \
-                   END {printf "coverage: %6.2f%%\n", ran * 100 / (ran + skip); \
-                        if (ran < (ran + skip) *0.94) exit(1) }' \
-                       coverage/oceani.mdc.gcov
+               @mv *.gcov coverage ; [ -f .gcov ] && mv .gcov coverage || true
                @rm -f .tmp*
 
-               @for T in $(oceani_tests); do \
+               @[ -n "$$SKIP_VALGRIND" ] || for T in $(oceani_valg_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 \
+                   if valgrind --error-exitcode=42 --log-file=.tmp.valg ./oceani --section "test: $$t" oceani-tests.mdc $${1+"$$@"} \
+                        > /dev/null 2>&1 ; [ $$? -eq 42 ] ; 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; \
@@ -86,6 +94,11 @@ arguments separated from the name by commas.  For each test, there is a section
                       echo "valgrind found memory in use at exit"; cat .tmp.valg ; exit 1 ; fi; \
                    echo " passed"; \
                done
+               ## valgrind test code
+               @[ -n "$$SKIP_COVERAGE_CHECK" ] || awk '/NOTEST/ { next } /^ *[1-9]/ {ran+=1} /^ *###/ {skip+=1} \
+                   END {printf "coverage: %6.2f%%\n", ran * 100 / (ran + skip); \
+                        if (ran < (ran + skip) *0.972) exit(1) }' \
+                       coverage/oceani.mdc.gcov
 
        coverage_oceani: oceani.c
                $(CC) $(CFLAGS) --coverage -fprofile-dir=coverage -o coverage_oceani oceani.c $(LDLIBS)
@@ -98,10 +111,9 @@ calculations on them.
 ###### test list
        oceani_tests += "valvar"
 
-
 ###### test: valvar
 
-       program:
+       func main(argv:[argc::]string)
                a := 23; b:=12 ; b1 := -b
                print a, b, a+b, a-b, a*b, a/b, a%b
                print a<b, a<=b, a>b, a>=b, a<a, a==b, a==a
@@ -122,14 +134,26 @@ calculations on them.
                  + b1
                  + b
 
+               z:Boolean= True
+               w:Boolean = False
+               if ?z:
+                       print "w??z", w??z
+                       print "z??w", z??w
+                       print "z??False", z??False, "w??False", w??False
+               if ?w:
+                       print "Weird?"
+
 ###### output: valvar
 
-       23 12 35 11 276 1.91667 11
+       23 12 35 11 276 1.916666667 11
        False False True True False False True
        23 12 12 -23 -12 12
        False True True False False False
        This is a string  field theory This is a string field theory
        81
+       w??z True
+       z??w True
+       z??False True w??False False
 
 Next we change the value of variables
 
@@ -138,7 +162,7 @@ Next we change the value of variables
 
 ###### test: setvar
 
-       program:
+       func main()
                a := 4
                a = a * a
                a = (a + a) * (a + a)
@@ -146,7 +170,7 @@ Next we change the value of variables
                print a, a/a
 
 ###### output: setvar
-       1.07374e+09 1
+       1073741824 1
 
 Now some contants
 
@@ -154,22 +178,23 @@ Now some contants
        oceani_tests += "consts"
 
 ###### test: consts
-       const:
-               pi ::= 3.1415926
+       const
+               tau ::= pi * 2
+               pi ::= 3.141 592 653
                four ::= 2 + 2 ; five ::= 10/2
        const pie ::= "I like Pie";
                cake ::= "The cake is"
                  ++ " a lie"
 
-       program:
+       func main()
                print "Hello World, what lovely oceans you have!"
                print "are there", five, "?"
-               print pi, pie, "but", cake
+               print pi, pie, "but", cake, "Tau is", tau
 
 ###### output: consts
        Hello World, what lovely oceans you have!
        are there 5 ?
-       3.14159 I like Pie but The cake is a lie
+       3.141592653 I like Pie but The cake is a lie Tau is 6.283185306
 
 Test merging of variables from multiple cases
 
@@ -178,19 +203,32 @@ Test merging of variables from multiple cases
 
 ###### test: varmerge
 
-       program:
+       func main()
                for i:=0; then i=i+1; while i < 5:
-                       switch i
+                       switch i:
+                               case 0: num:="zero"
+                               case 1: scratch:=42; num:="one"
+                               case 2: num:="two"
+                               case 3: num:="three"
+                               else    num:="many"
+                       print num,", ",
+               print
+
+               for i:=0; then i=i+1; while i < 5:
+                       switch i:
                                case 0: num:="zero"
                                case 1: num:="one"
                                case 2: num:="two"
                                case 3: num:="three"
-                               else:   num:="many"
+                               else    num:="many"
+                       // re-declare a CondScope variable
+                       num := i*i
                        print num,", ",
                print
 
 ###### output: varmerge
        zero , one , two , three , many , 
+       0 , 1 , 4 , 9 , 16 , 
 
 ## Conditions and Loops
 
@@ -201,11 +239,11 @@ Now we need to test if/else and some different loops
 
 ###### test: cond_loop
 
-       program:
+       func main()
                a := 4
                if a < 5:
                        print "Success"
-               else:
+               else
                        print "Failure"
                for b:=1; then b=b+b; while b < 100:
                        print '', b,
@@ -213,12 +251,12 @@ Now we need to test if/else and some different loops
                // Newtons method for square root of 2
                target ::= 2
                guess := target
-               for:
+               for
                        count: number = 0
-               while:
+               while
                        current := guess * guess
                        use +(current - target) > 0.000000001
-               do:
+               do
                        guess = (guess + (target / guess) ) / 2
                        print count, guess
                        count = count + 1
@@ -227,27 +265,48 @@ Now we need to test if/else and some different loops
                for j:=0; then j = j+3 ; while j < 10:
                        if j != 0 and then 20 / j > 3:
                                print "20 /", j," =", 20 / j
-                       else:
+                       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"
 
+               if pi > 3 then print "pi exceeds three"; else print "need more pie"
+               if (pi < 3) { print "not enough pi" } else { print "pi sufficient" }
+               for { i := 0; sum := 0 }
+               then { i = i+1 }
+               while i <= 10:
+                       sum = sum + i
+               else
+                       pass
+                       print "sum 1..10 is", sum
+               if
+                       PI1 := 22/7
+                       use PI1 < pi
+               then
+                       print "Smaller"
+               else
+                       print 'larger'
+
 ###### output: cond_loop
        Success
         1 2 4 8 16 32 64
        0 1.5
-       1 1.41667
-       2 1.41422
-       3 1.41421
-       error is  -4.51095e-12
+       1 1.416666667
+       2 1.414215686
+       3 1.414213562
+       error is  -4.510950445e-12
        I won't calculate 20 / 0
-       20 / 3  = 6.66667
-       20 / 6  = 3.33333
+       20 / 3  = 6.666666667
+       20 / 6  = 3.333333333
        I won't calculate 20 / 9
        Close enough
        higher
+       pi exceeds three
+       pi sufficient
+       sum 1..10 is 55
+       larger
 
 ## Say Hello
 
@@ -260,14 +319,17 @@ Here I break it into two parts, keeping the array code separate.
 
 ###### test: sayhello
 
-       program A B astr bbool:
+       func main(av:[ac::number]string)
+               A := $av[1]; B := $av[2]
+               astr := av[3]
+               bbool := av[ac-1] == "True"
                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.
                 */
                if A > B:
                        bigger := "yes"
-               else:
+               else
                        bigger := "no"
                print "Is", A, "bigger than", B,"? ", bigger
                /* If a variable is not used after the 'if', no
@@ -276,26 +338,27 @@ Here I break it into two parts, keeping the array code separate.
                if A > B * 2:
                        double:string = "yes"
                        print A, "is more than twice", B, "?", double
-               else:
+               else
                        double := B*2
                        print "double", B, "is", double
 
                a : number
                a = A;
                b:number = B
+               print "still", bigger // check for regression in scoping
                if a > 0 and b > 0:
                        while a != b:
                                if a < b:
                                        b = b - a
-                               else:
+                               else
                                        a = a - b
                        print "GCD of", A, "and", B,"is", a
                else if a <= 0:
                        print a, "is not positive, cannot calculate GCD"
-               else:
+               else
                        print b, "is not positive, cannot calculate GCD"
 
-               for:
+               for
                        togo := 10
                        f1 := 1; f2 := 1
                        print "Fibonacci:", f1,f2,
@@ -309,55 +372,58 @@ Here I break it into two parts, keeping the array code separate.
 
                if bbool:
                        print astr ++ " was the str"
-               else:
+               else
                        print "I found the str over " ++ astr
 
                /* Binary search... */
-               for:
+               for
                        lo:= 0; hi := 100
                        target := 77
-               while:
+               while
                        mid := (lo + hi) / 2
                        if mid == target:
-                               use Found
+                               use .Found
                        if mid < target:
                                lo = mid
-                       else:
+                       else
                                hi = mid
                        if hi - lo < 1:
-                               use GiveUp
+                               lo = mid
+                               use .GiveUp
                        use True
-               do: pass
-               case Found:
+               do pass
+               case .Found:
                        print "Yay, I found", target
-               case GiveUp:
-                       print "Closest I found was", mid
+               case .GiveUp:
+                       print "Closest I found was", lo
 
 ###### output: sayhello,55,33,hello,True
        Hello World, what lovely oceans you have!
        Is 55 bigger than 33 ?  yes
        double 33 is 66
+       still yes
        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
+       Closest I found was 77.34375
 
 ###### output: sayhello,12,60,there,False
        Hello World, what lovely oceans you have!
        Is 12 bigger than 60 ?  no
        double 60 is 120
+       still no
        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
+       Closest I found was 77.34375
 
 ###### test list
        oceani_tests += "insert_sort"
 ###### test: insert_sort
-       program:
+       func main()
                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
@@ -500,7 +566,7 @@ ad-hoc things array related.
 
 ###### test: arrays
 
-       program:
+       func main()
                bools:[5]Boolean
                strings:[4]string
 
@@ -508,11 +574,15 @@ ad-hoc things array related.
                bools[1] = strings[2] <= "there"
 
                for i:=0; then i=i+1; while i<5:
-                       print '', bools[i],
+                       j ::= i
+                       ra:[j]number
+                       ra[i-1] = i*i
+                       ra[6] = 42 // mustn't crash
+                       print '', bools[i], ra[j-1],
                print
 
 ###### output: arrays
-        False True False False False
+        False 0 True 1 False 4 False 9 False 16
 
 ## Structures
 
@@ -523,14 +593,17 @@ Time to test if structure declarations and accesses work correctly.
 
 ###### test: structs
 
-       struct foo:
-               size:[3]number
+       const three ::= 3
+       struct foo
+               size:[three]number
                name:string
-               active:Boolean
+               thing:baz
+               active:Boolean = True
 
        struct baz { a:number; b:Boolean; }
 
-       program:
+       func main
+       do
                info:[4]foo
 
                for i:=0; then i=i+1; while i < 4:
@@ -538,14 +611,16 @@ Time to test if structure declarations and accesses work correctly.
                        case 2: nm:= "peter"
                        case 0: nm:= "bob"
                        case 1: nm:= "jane"
-                       else: nm:= "janine"
+                       else    nm:= "janine"
 
                        info[i].name = nm
                        info[i].size[0] = i*i
-                       info[i].active = nm == "jane"
+                       if nm != "jane":
+                               info[i].active = False
 
                for i:=0; then i=i+1; while i < 4:
                        print info[i].name, info[i].active, info[i].size[0]
+               info[0].thing.b = True
 
 ###### output: structs
 
@@ -554,6 +629,148 @@ Time to test if structure declarations and accesses work correctly.
        peter False 4
        janine False 9
 
+## Functions
+
+Test functions.  They don't return anything, so we need to get them to print
+
+###### test list
+       oceani_tests += functions func_ret_type
+
+###### test: functions
+
+       func test1
+               t: Boolean
+       do
+               if t:
+                       print "true"
+
+       func noarg
+       do
+               pass
+
+       func twoarg
+               a:number
+               b:string
+       do
+               while a > 0:
+                       print b
+                       a = a - 1
+
+       func test(n:number; s:string)
+               if n >= 1:
+                       print n,s,
+                       test(n-1, "."++s)
+               else
+                       print "done"
+
+       func to_polar
+               x:number; y:number
+       return
+               rho:number
+               theta:number
+       do
+               rho = x + y
+               theta = x - y
+
+       func main()
+               for i:=0; then i = i + 1; while i < 5:
+                       test(i, " ")
+               angular := to_polar(32, 23)
+               print angular.rho, angular.theta
+
+###### output: functions
+       done
+       1  done
+       2  1 . done
+       3  2 . 1 .. done
+       4  3 . 2 .. 1 ... done
+       55 9
+
+###### test: func_ret_type
+
+       func double(n:number):number
+               use n+n
+
+       func answer
+               prefix:string
+               suffix:string
+       return string
+       do
+               use prefix ++ suffix
+
+       func noarg_returns
+       return Boolean
+       do
+               use 22/7 == 3.14159
+
+       func main()
+               for j:=10; then j = j - 3; while j > -5:
+                       print answer("dou","ble"), j, "is", double(j)
+
+###### output: func_ret_type
+       double 10 is 20
+       double 7 is 14
+       double 4 is 8
+       double 1 is 2
+       double -2 is -4
+
+## References
+
+A simple linked list example
+
+###### test list
+       oceani_tests += "linked_list,one,two,three,four"
+
+###### test: linked_list
+
+       struct node
+               next: @node
+               this: string
+
+       func insert(list:@node; new:string):@node
+               p:=list
+               prev := @nil
+               while ?p and then p.this < new:
+                       prev = p
+                       p = p.next
+               if ?prev:
+                       prev.next = @new()
+                       prev.next.next = p
+                       prev.next.this = new
+               else
+                       list = @new()
+                       list.next = p
+                       list.this = new
+               use list
+
+       func printlist(list:@node)
+               while ?list:
+                       print list@.this
+                       list = list@.next
+
+       func freelist(list:@node)
+               if list != @nil:
+                       freelist(list.next)
+                       @free = list
+
+       func main(argv:[ac::]string)
+               list := insert(@nil, "@start")
+               list = insert(list, "~end")
+               for i:=1; then i=i+1; while i < ac:
+                       list = insert(list, argv[i])
+               list = insert(list, "Hello!")
+               printlist(list)
+               freelist(list)
+
+###### output: linked_list,one,two,three,four
+       @start
+       Hello!
+       four
+       one
+       three
+       two
+       ~end
+
 ## Test code with syntax errors
 
 Syntax errors aren't handled well yet - the result is almost always a
@@ -584,21 +801,23 @@ separate file first, then run from there.
            ./coverage_oceani --section "test: $$t" oceani-tests.mdc > /dev/null 2>&1 ;\
        done || true
 
+###### combine test lists
+       oceani_valg_tests += $(oceani_failing_tests)
+
 ###### test list
        oceani_failing_tests := syn1
        oceani_failing_tests += tokerr
 
 ###### test: syn1
 
-       program:
+       func main()
                if then else while do
 
 ###### output: syn1
-       .tmp.code:3:11: error: unhandled parse error: then
-       oceani: no program found.
+       .tmp.code:3:11: Syntax error in statement: then
 
 ###### test: tokerr
-       program:
+       func main()
                a := 1i  // imaginary numbers aren't understood
                b:[2i]number // array sizes are handled separately
                c:[3.14159]Boolean // array sizes must be integers
@@ -628,10 +847,10 @@ separate file first, then run from there.
                This is a multiline string
                With an unsupportable suffix
                """Aa
-       .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
+       .tmp.code:14:11: error: type used but not declared: unknown
 
 ## Tests for type errors
 
@@ -644,17 +863,18 @@ 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
+       oceani_failing_tests += type_err1 type_err2 type_err3 type_err4 type_err5 type_err6
 
 ###### test: type_err1
 
-       program:
+       func main()
                print "hello" ++ 5, 5 ++ "hello"
 
                b ::= 3
                b = b + 1
 
                if 3 * 4 and not True: print "Weird"
+               d:number = .fred
 
 ###### output: type_err1
        .tmp.code:3:25: error: expected string found number
@@ -664,11 +884,13 @@ various places that `type_err()` are called.
        .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
+       .tmp.code:9:20: error: expected number found label
+       .tmp.code:9:8: info: variable 'd' was set as number here.
        oceani: type error in program - not running.
 
 ###### test: type_err2
 
-       program:
+       func main()
                a := 1
                a := 2
                a ::= 3
@@ -689,11 +911,11 @@ various places that `type_err()` are called.
 
 ###### test: type_err3
 
-       struct foo:
+       struct foo
                a: number
                b:string = "hello"
 
-       program:
+       func main()
                c := "hello"
                c = c + 1
                c = "hello" ++ (True and False)
@@ -701,11 +923,11 @@ various places that `type_err()` are called.
                print 45 + ( "Hello" ++ "there")
                c[5] = 1
 
-               while:
+               while
                        use 1
                        use True
                        use "Hello"
-               do:
+               do
                        print
                case 1: print "one"
                case "Hello": print "Hello"
@@ -721,6 +943,13 @@ various places that `type_err()` are called.
                bar:foo
                foo.c = 43
                print c.foo
+               print bar.c
+               print bar.b + 42
+
+               // trigger 'labels not permitted' error message
+               while 1 if True else False:
+                       print
+               case 2: print "two"
 
 ###### output: type_err3
        .tmp.code:8:12: error: expected number but variable 'c' is string
@@ -746,57 +975,245 @@ various places that `type_err()` are called.
        .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: field reference attempted on label, not a struct
+       .tmp.code:32:8: error: variable used but not declared: foo
+       .tmp.code:32:8: error: field reference on none is not supported
        .tmp.code:32:16: error: expected none found number
-       .tmp.code:33:14: error: field reference attempted on string, not a struct
+       .tmp.code:33:14: error: field reference on string is not supported
+       .tmp.code:34:14: error: cannot find requested field in foo
+       .tmp.code:35:17: error: have string but need number
+       .tmp.code:38:29: error: expected number found Boolean
        oceani: type error in program - not running.
 
 ###### test: type_err4
-       program:
+       func main()
                a:=1; b=2; c::=3
                print a, b, c
 
 ###### output: type_err4
-       .tmp.code:3:14: error: expected *unknown*type* (labels not permitted) but variable 'b' is label
-       .tmp.code:3:14: info: this is where 'b' was set to label
-       .tmp.code:3:16: error: expected label found number
-       .tmp.code:3:14: info: variable 'b' was set as label here.
-       .tmp.code:4:17: error: expected *unknown*type* (labels not permitted) but variable 'b' is label
-       .tmp.code:3:14: info: this is where 'b' was set to label
+       .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: type_err5
+       struct foo
+               bar:baz
+               a:number
+       struct baz
+               bat:foo
+               b:string
+       struct foo
+               c:number
+
+###### output: type_err5
+       .tmp.code:8:7: error: type already declared: foo
+       .tmp.code:2:7: info: this is location of declartion: foo
+       .tmp.code:2:7: error: type has recursive definition: foo
+       .tmp.code:5:7: error: type has recursive definition: baz
+
+###### test: type_err6
+
+       func main()
+               a:= "hello"
+               if ?a:
+                       print "no"
+               print a ?? "there"
+
+###### output: type_err6
+       .tmp.code:4:12: error: '?' requires a testable value, not string
+       .tmp.code:6:14: error: "??" requires a testable value, not string
        oceani: type error in program - not running.
 
+
 ###### test list
-       oceani_failing_tests += type_err_const type_err_const1
+       oceani_failing_tests += type_err_const type_err_const1 type_err_const2 missing_program bad_main
 
 ###### test: type_err_const
-       const:
+       const
                foo :: number = 45
                bar ::= "string" + 56
-       const:
+       const
                bar ::= "baz"
-       program:
+       func main()
                foo := 4
                print foo, bar
 
+       // trigger duplicate-main error
+       func main()
+               foo := 6
+               print bar, foo
+
 ###### 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
+       .tmp.code:12:5: error: function 'main' redeclared
+       .tmp.code:7:5: info: this is where 'main' was first declared
+       .tmp.code:13:8: error: variable 'foo' redeclared
+       .tmp.code:3:8: info: this is where 'foo' was first declared
+       .tmp.code:4:16: error: expected number found string
 
 ###### test: type_err_const1
-       const:
+       const
                foo : number = 45
                bar := "string"
-       program:
+       func main()
                foo := 4
                print foo, bar
 
 ###### output: type_err_const1
-       .tmp.code:3:12: error: unhandled parse error: :
-       oceani: no program found.
+       .tmp.code:3:12: Syntax error in constant: :
+       .tmp.code:4:12: Syntax error in constant: :
+
+###### test: type_err_const2
+       const
+               four ::= two + two
+               two ::= four / 2
+       
+###### output: type_err_const2
+       .tmp.code:3:8: error: const four cannot be resolved.
+       .tmp.code:4:8: error: const two cannot be resolved.
+
+###### test: missing_program
+       const
+               foo::="bar"
+
+###### output: missing_program
+       oceani: no main function found.
+
+###### test: bad_main
+       func main(foo:string)
+               print foo
+
+###### output: bad_main
+       .tmp.code:2:10: error: expected []string but variable 'foo' is string
+       .tmp.code:2:10: info: this is where 'foo' was set to string
+       oceani: main has wrong type.
+
+Test for type errors with functions
+
+###### test list
+       oceani_failing_tests += func_err_args func_err_redeclare
+
+###### test: func_err_args
+
+       func test1(a:number; b:string; c:[3]Boolean)
+               print a, b, c[1]
+
+       func test2(a:number; b:string; c:[3]Boolean)
+               print a, b, c[1]
+
+       func test3()
+               # use undefined names
+               print a, z
+
+       func main()
+               truth:[3]Boolean
+               truth[1] = True
+               test1(1,"hello")
+               test1("hello",1)
+               test1(1, "two", truth)
+               test1(1, 2, truth)
+               test1(1, "lo", truth, 4)
+               print test(), test1(1,2,3)
+               if test1 == test2:
+                       pass
+
+       func test4(a:number):string
+               use a * a
+
+       func test5(a:number):string
+               print a
 
+       struct foo
+               a: number
+               b:string = "hello"
+
+       func test6(a:number):foo
+               b:foo
+               b.a = a
+               use b
+
+###### output: func_err_args
+       .tmp.code:34:5: error: function cannot return value of type foo
+       .tmp.code:28:8: error: expected string, found none
+       .tmp.code:25:8: error: expected string, found number
+       .tmp.code:15:14: error: insufficient arguments to function.
+       .tmp.code:16:14: error: expected number found string
+       .tmp.code:16:22: error: expected string found number
+       .tmp.code:16:14: error: insufficient arguments to function.
+       .tmp.code:18:17: error: expected string found number
+       .tmp.code:19:14: error: too many arguments to function.
+       .tmp.code:20:14: error: attempt to call a non-function.
+       .tmp.code:20:32: error: expected string found number
+       .tmp.code:20:28: error: insufficient arguments to function.
+       .tmp.code:21:20: error: expected "func test1" but variable 'test2' is "func test2"
+       .tmp.code:5:5: info: this is where 'test2' was set to "func test2"
+       .tmp.code:10:14: error: variable used but not declared: a
+       .tmp.code:10:17: error: variable used but not declared: z
+       oceani: type error in program - not running.
+
+###### test: func_err_redeclare
+
+       func test1(a:number; b:string; c:[3]Boolean)
+               print a, b, c[1]
+
+       func test1
+       do
+               pass
+
+       func test1
+               b:Boolean
+       do
+               pass
+
+###### output: func_err_redeclare
+       .tmp.code:5:5: error: function 'test1' redeclared
+       .tmp.code:2:5: info: this is where 'test1' was first declared
+       .tmp.code:9:5: error: function 'test1' redeclared
+       .tmp.code:2:5: info: this is where 'test1' was first declared
+
+Test for errors with references
+
+###### test list
+       oceani_failing_tests += ref_err1 ref_err2
+
+###### test: ref_err1
+       func main()
+               ref:@number
+               @foo = ref
+               ref = @old()
+               if ref == @null:
+                       print "null"
+
+###### output: ref_err1
+       .tmp.code:4:9: error: only "@free" makes sense here: foo
+       .tmp.code:5:15: error: Only reference function is "@new()": old
+       .tmp.code:6:19: error: Only reference value is "@nil": null
+
+###### test: ref_err2
+       func main()
+               ref:@number
+               ref2:@string
+               num:number = @new()
+               print num@
+               if num == @nil or ref == ref2 or ref == 2 or ref.foo:
+                       @free = num
+
+###### output: ref_err2
+       .tmp.code:5:22: error: @new() can only be used with references, not number
+       .tmp.code:5:8: info: variable 'num' was set as number here.
+       .tmp.code:6:14: error: Cannot dereference number
+       .tmp.code:7:19: error: @nil can only be used with reference, not number
+       .tmp.code:7:33: error: expected @number but variable 'ref2' is @string
+       .tmp.code:4:8: info: this is where 'ref2' was set to @string
+       .tmp.code:7:48: error: expected @number found number
+       .tmp.code:7:53: error: field reference on number is not supported
+       .tmp.code:7:56: error: have none but need Boolean
+       .tmp.code:8:17: error: @free can only be assigned a reference, not number
+       .tmp.code:8:17: error: @free can only be assigned a reference, not number
+       oceani: type error in program - not running.
 
 ## Test erroneous command line args
 
@@ -819,7 +1236,19 @@ command list possible.
            echo  "passed"; \
            ./coverage_oceani $${1+"$$@"} > /dev/null 2>&1 ;\
        done || true
-
+###### valgrind test code
+       @[ -n "$$SKIP_VALGRIND" ] || for t in $(oceani_special_tests); do\
+           echo -n "Valgrind $$t.. "; \
+           i="$$IFS"; IFS=,; set $$t; IFS="$$i"; shift ;\
+           if valgrind --error-exitcode=42 --log-file=.tmp.valg ./oceani $${1+"$$@"} > .tmp.have 2>&1 ;\
+              [ $$? -eq 42 ]; 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
 
 ###### test list
        oceani_special_tests += "cmd"
@@ -833,7 +1262,7 @@ command list possible.
 
 ###### output: cmd,-zyx
        ./oceani: invalid option -- 'z'
-       Usage: oceani --trace --print --noexec --brackets--section=SectionName prog.ocn
+       Usage: oceani --trace --print --noexec --brackets --section=SectionName prog.ocn
 
 ###### output: cmd,nofile
        oceani: cannot open nofile