]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani-tests.mdc
oceani: make anon types more formal
[ocean] / csrc / oceani-tests.mdc
index 87a7aa99a548b876a4ef5962b446d03f0ec74800..58fde75620d45c479b8840abea87fc5db643eca7 100644 (file)
@@ -35,6 +35,8 @@ arguments separated from the name by commas.  For each test, there is a section
 
        oceani_tests :=
        ## test list
 
        oceani_tests :=
        ## test list
+       oceani_valg_tests := $(oceani_tests)
+       ## combine test lists
 
        tests:: oceani_test_suite
        oceani_test_suite: oceani coverage_oceani
 
        tests:: oceani_test_suite
        oceani_test_suite: oceani coverage_oceani
@@ -78,17 +80,13 @@ arguments separated from the name by commas.  For each test, there is a section
                @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 || true
                @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 || true
-               @ 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
                @rm -f .tmp*
 
                @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; \
                    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; \
                       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; \
@@ -96,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
                       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)
 
        coverage_oceani: oceani.c
                $(CC) $(CFLAGS) --coverage -fprofile-dir=coverage -o coverage_oceani oceani.c $(LDLIBS)
@@ -110,7 +113,7 @@ calculations on them.
 
 ###### test: 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
                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
@@ -147,7 +150,7 @@ Next we change the value of variables
 
 ###### test: setvar
 
 
 ###### test: setvar
 
-       program:
+       func main()
                a := 4
                a = a * a
                a = (a + a) * (a + a)
                a := 4
                a = a * a
                a = (a + a) * (a + a)
@@ -163,14 +166,14 @@ Now some contants
        oceani_tests += "consts"
 
 ###### test: consts
        oceani_tests += "consts"
 
 ###### test: consts
-       const:
+       const
                pi ::= 3.141 592 653
                four ::= 2 + 2 ; five ::= 10/2
        const pie ::= "I like Pie";
                cake ::= "The cake is"
                  ++ " a lie"
 
                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 "Hello World, what lovely oceans you have!"
                print "are there", five, "?"
                print pi, pie, "but", cake
@@ -187,19 +190,32 @@ Test merging of variables from multiple cases
 
 ###### test: varmerge
 
 
 ###### test: varmerge
 
-       program:
+       func main()
                for i:=0; then i=i+1; while i < 5:
                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"
                                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 , 
                        print num,", ",
                print
 
 ###### output: varmerge
        zero , one , two , three , many , 
+       0 , 1 , 4 , 9 , 16 , 
 
 ## Conditions and Loops
 
 
 ## Conditions and Loops
 
@@ -210,11 +226,11 @@ Now we need to test if/else and some different loops
 
 ###### test: cond_loop
 
 
 ###### test: cond_loop
 
-       program:
+       func main()
                a := 4
                if a < 5:
                        print "Success"
                a := 4
                if a < 5:
                        print "Success"
-               else:
+               else
                        print "Failure"
                for b:=1; then b=b+b; while b < 100:
                        print '', b,
                        print "Failure"
                for b:=1; then b=b+b; while b < 100:
                        print '', b,
@@ -222,12 +238,12 @@ Now we need to test if/else and some different loops
                // Newtons method for square root of 2
                target ::= 2
                guess := target
                // Newtons method for square root of 2
                target ::= 2
                guess := target
-               for:
+               for
                        count: number = 0
                        count: number = 0
-               while:
+               while
                        current := guess * guess
                        use +(current - target) > 0.000000001
                        current := guess * guess
                        use +(current - target) > 0.000000001
-               do:
+               do
                        guess = (guess + (target / guess) ) / 2
                        print count, guess
                        count = count + 1
                        guess = (guess + (target / guess) ) / 2
                        print count, guess
                        count = count + 1
@@ -236,7 +252,7 @@ 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
                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 "I won't calculate 20 /", j
                pi ::= 3.1415926535897
                if 355/113 == pi or else +(pi - 355/113) < 0.001:
@@ -249,9 +265,16 @@ Now we need to test if/else and some different loops
                then { i = i+1 }
                while i <= 10:
                        sum = sum + i
                then { i = i+1 }
                while i <= 10:
                        sum = sum + i
-               else:
+               else
                        pass
                        print "sum 1..10 is", sum
                        pass
                        print "sum 1..10 is", sum
+               if
+                       PI1 := 22/7
+                       use PI1 < pi
+               then
+                       print "Smaller"
+               else
+                       print 'larger'
 
 ###### output: cond_loop
        Success
 
 ###### output: cond_loop
        Success
@@ -270,6 +293,7 @@ Now we need to test if/else and some different loops
        pi exceeds three
        pi sufficient
        sum 1..10 is 55
        pi exceeds three
        pi sufficient
        sum 1..10 is 55
+       larger
 
 ## Say Hello
 
 
 ## Say Hello
 
@@ -282,14 +306,17 @@ Here I break it into two parts, keeping the array code separate.
 
 ###### test: sayhello
 
 
 ###### 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"
                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
                        bigger := "no"
                print "Is", A, "bigger than", B,"? ", bigger
                /* If a variable is not used after the 'if', no
@@ -298,26 +325,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
                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
                        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
                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"
                                        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"
 
                        print b, "is not positive, cannot calculate GCD"
 
-               for:
+               for
                        togo := 10
                        f1 := 1; f2 := 1
                        print "Fibonacci:", f1,f2,
                        togo := 10
                        f1 := 1; f2 := 1
                        print "Fibonacci:", f1,f2,
@@ -331,34 +359,36 @@ Here I break it into two parts, keeping the array code separate.
 
                if bbool:
                        print astr ++ " was the str"
 
                if bbool:
                        print astr ++ " was the str"
-               else:
+               else
                        print "I found the str over " ++ astr
 
                /* Binary search... */
                        print "I found the str over " ++ astr
 
                /* Binary search... */
-               for:
+               for
                        lo:= 0; hi := 100
                        target := 77
                        lo:= 0; hi := 100
                        target := 77
-               while:
+               while
                        mid := (lo + hi) / 2
                        if mid == target:
                                use Found
                        if mid < target:
                                lo = mid
                        mid := (lo + hi) / 2
                        if mid == target:
                                use Found
                        if mid < target:
                                lo = mid
-                       else:
+                       else
                                hi = mid
                        if hi - lo < 1:
                                hi = mid
                        if hi - lo < 1:
+                               lo = mid
                                use GiveUp
                        use True
                                use GiveUp
                        use True
-               do: pass
+               do pass
                case Found:
                        print "Yay, I found", target
                case GiveUp:
                case Found:
                        print "Yay, I found", target
                case GiveUp:
-                       print "Closest I found was", mid
+                       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
 
 ###### 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
        GCD of 55 and 33 is 11
        Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
        hello was the str
@@ -368,6 +398,7 @@ Here I break it into two parts, keeping the array code separate.
        Hello World, what lovely oceans you have!
        Is 12 bigger than 60 ?  no
        double 60 is 120
        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
        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
@@ -376,7 +407,7 @@ Here I break it into two parts, keeping the array code separate.
 ###### test list
        oceani_tests += "insert_sort"
 ###### test: insert_sort
 ###### test list
        oceani_tests += "insert_sort"
 ###### test: insert_sort
-       program:
+       func main()
                size::=55
                list:[size]number
                list[0] = 1_234
                size::=55
                list:[size]number
                list[0] = 1_234
@@ -522,7 +553,7 @@ ad-hoc things array related.
 
 ###### test: arrays
 
 
 ###### test: arrays
 
-       program:
+       func main()
                bools:[5]Boolean
                strings:[4]string
 
                bools:[5]Boolean
                strings:[4]string
 
@@ -530,11 +561,15 @@ ad-hoc things array related.
                bools[1] = strings[2] <= "there"
 
                for i:=0; then i=i+1; while i<5:
                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
                print
 
 ###### output: arrays
-        False True False False False
+        False 0 True 1 False 4 False 9 False 16
 
 ## Structures
 
 
 ## Structures
 
@@ -545,14 +580,16 @@ Time to test if structure declarations and accesses work correctly.
 
 ###### test: structs
 
 
 ###### test: structs
 
-       struct foo:
-               size:[3]number
+       const three ::= 3
+       struct foo
+               size:[three]number
                name:string
                name:string
-               active:Boolean
+               active:Boolean = True
 
        struct baz { a:number; b:Boolean; }
 
 
        struct baz { a:number; b:Boolean; }
 
-       program:
+       func main
+       do
                info:[4]foo
 
                for i:=0; then i=i+1; while i < 4:
                info:[4]foo
 
                for i:=0; then i=i+1; while i < 4:
@@ -560,11 +597,12 @@ Time to test if structure declarations and accesses work correctly.
                        case 2: nm:= "peter"
                        case 0: nm:= "bob"
                        case 1: nm:= "jane"
                        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].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]
 
                for i:=0; then i=i+1; while i < 4:
                        print info[i].name, info[i].active, info[i].size[0]
@@ -576,6 +614,91 @@ Time to test if structure declarations and accesses work correctly.
        peter False 4
        janine False 9
 
        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
+
 ## Test code with syntax errors
 
 Syntax errors aren't handled well yet - the result is almost always a
 ## Test code with syntax errors
 
 Syntax errors aren't handled well yet - the result is almost always a
@@ -606,20 +729,23 @@ separate file first, then run from there.
            ./coverage_oceani --section "test: $$t" oceani-tests.mdc > /dev/null 2>&1 ;\
        done || true
 
            ./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
 
 ###### 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: Syntax error in statement: then
 
 ###### test: tokerr
                if then else while do
 
 ###### output: syn1
        .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
                a := 1i  // imaginary numbers aren't understood
                b:[2i]number // array sizes are handled separately
                c:[3.14159]Boolean // array sizes must be integers
@@ -669,7 +795,7 @@ various places that `type_err()` are called.
 
 ###### test: type_err1
 
 
 ###### test: type_err1
 
-       program:
+       func main()
                print "hello" ++ 5, 5 ++ "hello"
 
                b ::= 3
                print "hello" ++ 5, 5 ++ "hello"
 
                b ::= 3
@@ -689,7 +815,7 @@ various places that `type_err()` are called.
 
 ###### test: type_err2
 
 
 ###### test: type_err2
 
-       program:
+       func main()
                a := 1
                a := 2
                a ::= 3
                a := 1
                a := 2
                a ::= 3
@@ -710,11 +836,11 @@ various places that `type_err()` are called.
 
 ###### test: type_err3
 
 
 ###### test: type_err3
 
-       struct foo:
+       struct foo
                a: number
                b:string = "hello"
 
                a: number
                b:string = "hello"
 
-       program:
+       func main()
                c := "hello"
                c = c + 1
                c = "hello" ++ (True and False)
                c := "hello"
                c = c + 1
                c = "hello" ++ (True and False)
@@ -722,11 +848,11 @@ various places that `type_err()` are called.
                print 45 + ( "Hello" ++ "there")
                c[5] = 1
 
                print 45 + ( "Hello" ++ "there")
                c[5] = 1
 
-               while:
+               while
                        use 1
                        use True
                        use "Hello"
                        use 1
                        use True
                        use "Hello"
-               do:
+               do
                        print
                case 1: print "one"
                case "Hello": print "Hello"
                        print
                case 1: print "one"
                case "Hello": print "Hello"
@@ -742,6 +868,13 @@ various places that `type_err()` are called.
                bar:foo
                foo.c = 43
                print c.foo
                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
 
 ###### output: type_err3
        .tmp.code:8:12: error: expected number but variable 'c' is string
@@ -771,10 +904,13 @@ various places that `type_err()` are called.
        .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
        .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
+       .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 (labels not permitted) found Boolean
        oceani: type error in program - not running.
 
 ###### test: type_err4
        oceani: type error in program - not running.
 
 ###### test: type_err4
-       program:
+       func main()
                a:=1; b=2; c::=3
                print a, b, c
 
                a:=1; b=2; c::=3
                print a, b, c
 
@@ -785,30 +921,39 @@ various places that `type_err()` are called.
        oceani: type error in program - not running.
 
 ###### test list
        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 missing_program bad_main
 
 ###### test: type_err_const
 
 ###### test: type_err_const
-       const:
+       const
                foo :: number = 45
                bar ::= "string" + 56
                foo :: number = 45
                bar ::= "string" + 56
-       const:
+       const
                bar ::= "baz"
                bar ::= "baz"
-       program:
+       func main()
                foo := 4
                print foo, bar
 
                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
 ###### 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
 
 ###### test: type_err_const1
 
 ###### test: type_err_const1
-       const:
+       const
                foo : number = 45
                bar := "string"
                foo : number = 45
                bar := "string"
-       program:
+       func main()
                foo := 4
                print foo, bar
 
                foo := 4
                print foo, bar
 
@@ -816,6 +961,105 @@ various places that `type_err()` are called.
        .tmp.code:3:12: Syntax error in constant: :
        .tmp.code:4:12: Syntax error in constant: :
 
        .tmp.code:3:12: Syntax error in constant: :
        .tmp.code:4:12: Syntax error in constant: :
 
+###### 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:??:??: error: expected []string but variable 'foo' is string
+       .tmp.code:??:??: info: this is where 'NOTVAR' 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:14: 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 *invalid*type* but variable 'test2' is *invalid*type*
+       .tmp.code:??:??: info: this is where 'NOTVAR' was set to *invalid*type*
+       .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 erroneous command line args
 
 To improve coverage, we want to test correct handling of strange command
 ## Test erroneous command line args
 
 To improve coverage, we want to test correct handling of strange command
@@ -837,6 +1081,19 @@ command list possible.
            echo  "passed"; \
            ./coverage_oceani $${1+"$$@"} > /dev/null 2>&1 ;\
        done || true
            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"
 
 ###### test list
        oceani_special_tests += "cmd"
@@ -850,7 +1107,7 @@ command list possible.
 
 ###### output: cmd,-zyx
        ./oceani: invalid option -- 'z'
 
 ###### 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
 
 ###### output: cmd,nofile
        oceani: cannot open nofile