#!/usr/bin/env qore # -*- mode: qore; indent-tabs-mode: nil -*- # require all global variables to be declared with "our" %require-our # enable all warnings %enable-all-warnings # child programs do not inherit parent's restrictions %no-child-restrictions # require types to be declared %require-types # make sure we have the right version of qore %requires qore >= 0.8.1 # global variables needed for tests our Test $to("program-test.q"); our Test $ro("readonly"); our (hash $o, int $errors); our hash $thash; sub usage() { printf( "usage: %s [options] <iterations> -h,--help shows this help text -b,--backquote include backquote tests (slow) -t,--threads=ARG runs tests in ARG threads -v,--verbose=ARG sets verbosity level to ARG ", get_script_name()); exit(1); } const opts = ( "verbose" : "verbose,v:i+", "help" : "help,h", "bq" : "backquote,b", "threads" : "threads,t=i" ); sub parse_command_line() { my GetOpt $g(opts); $o = $g.parse(\$ARGV); if (exists $o."_ERRORS_") { printf("%s\n", $o."_ERRORS_"[0]); exit(1); } if ($o.help) usage(); $o.iters = shift $ARGV; if (elements $ARGV) { printf("error, excess arguments on command-line\n"); usage(); } if (!$o.iters) $o.iters = 1; if (!$o.threads) $o.threads = 1; } sub test_value(any $v1, any $v2, string $msg) { if ($v1 === $v2) { if ($o.verbose) printf("OK: %s test\n", $msg); } else { printf("ERROR: %s test failed! (%N != %N)\n", $msg, $v1, $v2); #printf("%s%s", dbg_node_info($v1), dbg_node_info($v2)); $errors++; } $thash.$msg = True; } int sub test1() { return 1;} int sub test2() { return 2; } list sub test3() { return (1, 2, 3); } sub array_helper(list $a) { $a[1][1] = 2; test_value($a[1][1], 2, "passed local array variable assignment"); } list sub list_return(any $var) { return (1, test2(), $var); } hash sub hash_return(any $var) { return ( "gee" : "whiz", "num" : test1(), "var" : $var ); } class Sort { int hash(hash $l, hash $r) { return $l.key1 <=> $r.key1; } } int sub hash_sort_callback(hash $l, hash $r) { return $l.key1 <=> $r.key1; } class SC; static int SC::hash_sort_callback(hash $l, hash $r) { return $l.key1 <=> $r.key1; } # array tests sub array_tests() { my (list $a, list $b, list $c, list $d); if ($o.verbose) print("%%%% array tests\n"); $a = 1, 2, 3, 4, 5; test_value(elements $a, 5, "elements operator"); test_value($a[1], 2, "single-dimentional list dereference"); $b = 1, 2, (3, 4, 5), 6, 7; test_value($b[2][1], 4, "multi-dimentional list dereference"); delete $b; test_value($b[2][1], NOTHING, "multi-dimentional list dereference after delete operator"); $b = $a; $a[1] = "hello"; test_value($a[1], "hello", "list dereference after list assignment and element reassignment"); test_value($b[1], 2, "list dereference of source list"); $a[0][1] = "hello"; $c[10]{"testing"} = "well then"; test_value($a[0][1], "hello", "second multi-dimentional list dereference"); test_value($a[1][500], NOTHING, "non-existant element deference"); test_value(int($c[10].testing), 0, "hash list element dereference"); test_value($c[10]{"testing"}, "well then", "hash element in list dereference"); $d = test1(), test2(); test_value($d[1], 2, "list element dereference with evaluation"); $b = $a = 1, 2, 3; delete $a[2]; test_value($a[2] != $b[2], True, "shared list element comparison after delete"); $a[1][1] = 3; test_value($a[1][1], 3, "array variable assignment before copy"); array_helper($a); test_value($a[1][1], 3, "array variable assignment after copy"); array_helper($a); test_value(list_return()[0], 1, "simple list return and deref(e)"); test_value(list_return()[1], 2, "list return with function element result and deref(e)"); test_value(list_return("gee")[2], "gee", "list return with local variable result and deref(e)"); $a = 1, 2, 3; $a += 4, 5, 6; test_value($a[3], 4, "first list list plus-equals concatenation"); $a += 7; test_value($a[6], 7, "list element plus-equals concatenation"); $a += list(8); test_value($a[7], 8, "second list list plus-equals concatenation"); $a = (1, 2, 3) + (4, 5, 6); test_value($a[3], 4, "first list list plus operator concatenation"); $a = 1, 2, 3; $b = 4, 5, 6; $c = $a + $b; test_value($c[4], 5, "second list list plus operator concatenation"); my list $l1 = ( 3, 2, 4, 1, 6, 5 ); my list $l2 = ( "one", "two", "three", "four", "five", "six" ); my list $hl = ( ( "key1" : 8, "key2" : "two" ), ( "key1" : 2, "key2" : "seven" ), ( "key1" : 7, "key2" : "six" ), ( "key1" : 1, "key2" : "eight" ), ( "key1" : 6, "key2" : "four" ), ( "key1" : 9, "key2" : "three" ), ( "key1" : 3, "key2" : "five" ), ( "key1" : 5, "key2" : "nine" ), ( "key1" : 4, "key2" : "one" ) ); my list $sorted_hl = ( ( "key1" : 1, "key2" : "eight" ), ( "key1" : 2, "key2" : "seven" ), ( "key1" : 3, "key2" : "five" ), ( "key1" : 4, "key2" : "one" ), ( "key1" : 5, "key2" : "nine" ), ( "key1" : 6, "key2" : "four" ), ( "key1" : 7, "key2" : "six" ), ( "key1" : 8, "key2" : "two" ), ( "key1" : 9, "key2" : "three" ) ); my list $stable_sorted_hl = ( ( "key1" : 1, "key2" : "eight" ), ( "key1" : 2, "key2" : "seven" ), ( "key1" : 3, "key2" : "five" ), ( "key1" : 3, "key2" : "five-o" ), ( "key1" : 4, "key2" : "one" ), ( "key1" : 5, "key2" : "nine" ), ( "key1" : 6, "key2" : "four" ), ( "key1" : 7, "key2" : "six" ), ( "key1" : 8, "key2" : "two" ), ( "key1" : 9, "key2" : "three" ) ); my Sort $s(); my code $hash_compare = int sub (hash $l, hash $r) { return $l.key1 <=> $r.key1; }; test_value(sort($l1), (1,2,3,4,5,6), "first sort()"); test_value(sort($l2), ("five", "four", "one", "six", "three", "two"), "second sort()"); test_value(sort($hl, \hash_sort_callback()), $sorted_hl, "sort() with function call reference callback"); test_value(sort($hl, \$s.hash()), $sorted_hl, "sort() with object method callback"); test_value(sort($hl, "hash_sort_callback"), $sorted_hl, "sort() with string function name callback"); test_value(sort($hl, $hash_compare), $sorted_hl, "sort() with closure callback"); my list $r_sorted_hl = reverse($sorted_hl); test_value(sortDescending($l1), (6,5,4,3,2,1), "first sortDescending()"); test_value(sortDescending($l2), ("two", "three", "six", "one", "four", "five"), "second sortDescending()"); test_value(sortDescending($hl, \SC::hash_sort_callback()), $r_sorted_hl, "first sortDescending() with callback"); test_value(sortDescending($hl, \$s.hash()), $r_sorted_hl, "second sortDescending() with callback"); test_value(sortDescending($hl, "hash_sort_callback"), $r_sorted_hl, "third sortDescending() with callback"); test_value(sortDescending($hl, $hash_compare), $r_sorted_hl, "sortDescending() with closure callback"); $hl += ( "key1" : 3, "key2" : "five-o" ); test_value(sortStable($hl, \hash_sort_callback()), $stable_sorted_hl, "first sortStable() with callback"); test_value(sortStable($hl, \$s.hash()), $stable_sorted_hl, "second sortStable() with callback"); test_value(sortStable($hl, "hash_sort_callback"), $stable_sorted_hl, "third sortStable() with callback"); test_value(sortStable($hl, $hash_compare), $stable_sorted_hl, "sortStable() with closure callback"); my list $r_stable_sorted_hl = reverse($stable_sorted_hl); test_value(sortDescendingStable($hl, \SC::hash_sort_callback()), $r_stable_sorted_hl, "first sortDescendingStable() with callback"); test_value(sortDescendingStable($hl, \$s.hash()), $r_stable_sorted_hl, "second sortDescendingStable() with callback"); test_value(sortDescendingStable($hl, "hash_sort_callback"), $r_stable_sorted_hl, "third sortDescendingStable() with callback"); test_value(sortDescendingStable($hl, $hash_compare), $r_stable_sorted_hl, "sortDescendingStable() with closure callback"); test_value(min($l1), 1, "simple min()"); test_value(max($l1), 6, "simple max()"); test_value(min($hl, \hash_sort_callback()), ( "key1" : 1, "key2" : "eight" ), "first min() with callback"); test_value(min($hl, \$s.hash()), ( "key1" : 1, "key2" : "eight" ), "second min() with callback"); test_value(min($hl, "hash_sort_callback"), ( "key1" : 1, "key2" : "eight" ), "third min() with callback"); test_value(max($hl, \SC::hash_sort_callback()), ( "key1" : 9, "key2" : "three" ), "first max() with callback"); test_value(max($hl, \$s.hash()), ( "key1" : 9, "key2" : "three" ), "second max() with callback"); test_value(max($hl, "hash_sort_callback"), ( "key1" : 9, "key2" : "three" ), "third max() with callback"); my string $v = shift $l2; test_value($l2, ("two","three","four","five","six"), "array shift"); unshift $l2, $v; test_value($l2, ("one","two","three","four","five","six"), "array unshift"); # list assignment tests my list $l[1] = "boo"; ($l[0], $l[1]) = "hi1"; test_value($l, ("hi1", NOTHING), "first list assigment"); ($l[0], $l[1]) = ("hi2", "shoo1"); test_value($l, ("hi2", "shoo1"), "second list assigment"); ($l[0], $l[1]) = ("hi3", "shoo2", "bean1"); test_value($l, ("hi3", "shoo2"), "third list assigment"); my int $v2 = pop $l1; test_value($v2, 5, "first pop"); test_value($l1, (3,2,4,1,6), "second pop"); push $l1, "hi"; # splice tests test_value($l1, (3,2,4,1,6,"hi"), "push"); splice $l1, 5; test_value($l1, (3,2,4,1,6), "first list splice"); splice $l1, 3, 1; test_value($l1, (3,2,4,6), "second list splice"); splice $l1, 1, 2, (4, 5, 5.5); test_value($l1, (3,4,5,5.5,6), "third list splice"); splice $l1, 0, 4, (10, 11, 12); test_value($l1, (10, 11, 12, 6), "third list splice"); splice $l1, 0, 1; test_value($l1, (11, 12, 6), "fourth list splice"); splice $l1, 5, 2, (1, 2, 3); test_value($l1, (11, 12, 6, 1, 2, 3), "fifth list splice"); splice $l1, -4, 2, 9; test_value($l1, (11, 12, 9, 2, 3), "sixth list splice"); splice $l1, -4, -2, (21, 22, 23); test_value($l1, (11, 21, 22, 23, 2, 3), "seventh list splice"); # extract tests test_value((extract $l1, 5), list(3), "first list extract"); test_value((extract $l1, 2, 2), (22, 23), "second list extract"); test_value((extract $l1, 1, 2, 4), (21, 2), "second list extract"); test_value($l1, (11, 4), "final list extract"); my string $astr = "hello"; test_value($astr[2], "l", "string element dereference"); my binary $bin = binary($astr); test_value($bin[4], ord("o"), "binary byte dereference"); } sub hash_tests() { if ($o.verbose) print("%%%% hash tests\n"); # hash tests my hash $b = ( "test" : 1, "gee" : 2, "well" : "string" ); test_value($b.gee, 2, "object dereference"); test_value(elements $b, 3, "elements operator on hash before delete"); delete $b{"gee"}; test_value(elements $b, 2, "elements operator on hash after delete"); $b{"test"} = "there"; my hash $d{"gee"}[25] = "I hope it works"; test_value($b.test, "there", "hash dereference after assignment"); test_value($b.test, "there", "object dereference after assignment"); test_value($b{"geez"}, NOTHING, "non-existant object dereference"); test_value(int($d.gee[25]), 0, "hash dereference of list element"); test_value($d{"gee"}[25], "I hope it works", "dereference of list member of hash"); my hash $c = ( "hi" : "there", "gee" : "whillakers" ); $d = $c; test_value($d == $c, True, "hash comparison"); test_value($d.gee, "whillakers", "hash dereference after entire hash assignment"); $c{"gee"} = "roo"; test_value($c{"gee"}, "roo", "original hash dereference after assignment to member of copied hash"); test_value($d.gee, "whillakers", "hash dereference of member of copied hash"); $d = ( "gee" : test1(), "howdy" : test2()); test_value($d.gee, 1, "hash dereference with evaluation"); test_value(hash_return(){"gee"}, "whiz", "simple hash return and dereference"); test_value(hash_return(){"num"}, 1, "hash return with function element result and dereference"); test_value(hash_return("hi there"){"var"}, "hi there", "hash return with local variable result and dereference"); my hash $a = ( "key" : 1, "unique" : 100, "asd" : "dasd" ); $b = ( "key" : 3, "new" : 45, "barn" : "door" ); $c = $a + $b; test_value($c.key, 3, "hash plus operator element override"); test_value($c."new", 45, "hash plus operator new element"); test_value($c.unique, 100, "hash plus operator unchanged element"); $a += $b; test_value($a.key, 3, "hash plus equals operator element override"); test_value($a."new", 45, "hash plus equals operator new element"); test_value($a.unique, 100, "hash plus equals operator unchanged element"); # test hash slice creation test_value($a.("unique", "new"), ("unique" : 100, "new" : 45), "hash slice creation"); my Test $ot(1, "two", 3.0); $ot += $a; test_value($ot.("unique", "new"), ("unique" : 100, "new" : 45), "hash slice creation from object"); # delete 3 keys from the $c hash $b = $c - "new" - "barn" - "asd"; test_value($b, ( "key" : 3, "unique" : 100 ), "hash minus operator"); $b = $c - ("new", "barn", "asd"); test_value($b, ( "key" : 3, "unique" : 100 ), "hash minus operator with list argument"); $b -= "unique"; test_value($b, ( "key" : 3 ), "hash minus-equals operator"); $c -= ( "new", "barn" ); test_value($c, ( "key": 3, "unique" : 100, "asd" : "dasd" ), "hash minus-equals operator with list argument"); my hash $nh += ( "new-hash" : 1 ); test_value($nh, ( "new-hash" : 1 ), "hash plus-equals, lhs NOTHING"); } sub global_variable_testa() { printf("user=%s\n", $ENV{"USER"}); } code sub map_closure(any $v) { return any sub(any $v1) { return $v * $v1; }; } # operator tests sub operator_test() { if ($o.verbose) print("%%%% operator tests\n"); my int $a = 1; test_value($a, 1, "variable assignment"); $a += 3; test_value($a, 4, "integer += operator"); $a -= 2; test_value($a, 2, "integer -= operator"); $a |= 1; test_value($a, 3, "|= operator"); $a &= 1; test_value($a, 1, "&= operator"); $a *= 10; test_value($a, 10, "integer *= operator"); my float $f = $a; $f *= 2.2; test_value($f, 22.0, "first float *= operator"); $f *= 2; test_value($f, 44.0, "second float *= operator"); $f /= 4.4; test_value($f, 10.0, "float /= operator"); $a = 10; $a /= 2; test_value($a, 5, "integer /= operator"); test_value(4 / 2, 2, "first / operator"); $a = 0xfdb4902a; $a ^= 0xbf40e848; test_value($a, 0x42f47862, "^= xor equals operator"); $a <<= 2; test_value($a, 0x10bd1e188, "<<= shift-left-equals operator"); $a >>= 3; test_value($a, 0x217a3c31, ">>= shift-right-equals operator"); $a = 1; test_value($a++, 1, "pre post-increment (++) operator"); test_value($a, 2, "post post-increment (++) operator"); test_value($a--, 2, "pre post-decrement (--) operator"); test_value($a, 1, "post post-decrement (--) operator"); test_value(++$a, 2, "pre-increment (++) operator"); test_value(--$a, 1, "pre-decrement (--) operator"); my string $astr = "hello" + " there"; test_value($astr, "hello there", "string concatenation"); $astr += " gee"; test_value($astr, "hello there gee", "string plus equals"); $f = 1.0; $f += 1.2; test_value($f, 2.2, "float += operator"); $f -= 1.1; test_value($f, 1.1, "float -= operator"); $f = 5.5 * 2.0; test_value($f, 11.0, "float * operator"); test_value(now() > (now() - 1D), True, "date > operator"); test_value(now() >= (now() - 1h), True, "date >= operator"); test_value((now() - 1m) < now(), True, "date < operator"); test_value((now() - 1M) <= now(), True, "date <= operator"); my date $bt = my date $at = now(); test_value($at, $bt, "date == operator"); $at = 2004-02-28-12:00:00; $at += 1D; test_value($at, 2004-02-29-12:00:00, "first date += operator"); $at -= (3h + 5m); test_value($at, 2004-02-29-08:55:00, "second date += operator"); my any $ni += 3.2; test_value($ni, 3.2, "float +=, lhs NOTHING"); delete $ni; $ni += "hello"; test_value($ni, "hello", "string +=, lhs NOTHING"); delete $ni; $ni -= 4.5; test_value($ni, -4.5, "float -=, lhs NOTHING"); delete $ni; $ni -= 4; test_value($ni, -4, "integer -=, lhs NOTHING"); # some array and hash tests in separate functions # get function closure with bound local variable (multiply by 2) my code $c = map_closure(2); # map function to list test_value((map $c($1), (1, 2, 3)), (2, 4, 6), "map operator using closure"); # map immediate expression to list test_value((map $1 * 2, (1, 2, 3)), (2, 4, 6), "map operator using expression"); # map function to list with optional select code as expression test_value((map $c($1), (1, 2, 3), $1 > 1), (4, 6), "map operator using closure with optional select expression"); # select all elements from list greater than 1 with expression test_value((select (1, 2, 3), $1 > 1), (2, 3), "select operator with expression"); # create a sinple closure to subtract the second argument from the first $c = any sub(any $x, any $y) { return $x - $y; }; # left fold function on list using closure test_value((foldl $c($1, $2), (2, 3, 4)), -5, "foldl operator with closure"); # left fold function on list using expression test_value((foldl $1 - $2, (2, 3, 4)), -5, "foldl operator with expression"); # right fold function on list using immediate closure test_value((foldr $c($1, $2), (2, 3, 4)), -1, "foldr operator with closure"); # right fold function on list using expression and implicit arguments test_value((foldr $1 - $2, (2, 3, 4)), -1, "foldr operator with expression"); my hash $h = ("test" : 1, "two" : 2.0, "three" : "three", "four" : False ); test_value(remove $h.two, 2.0, "first remove operator"); } sub no_parameter_test(any $p) { test_value($p, NOTHING, "non-existant parameter"); } sub parameter_and_shift_test(int $p) { test_value($p, 1, "parameter before shift"); test_value(shift $argv, 2, "shift on second parameter"); } sub one_parameter_shift_test() { test_value(shift $argv, 1, "one parameter shift"); } sub shift_test() { my list $var = (1, 2, 3, 4, "hello"); foreach my any $v in ($var) test_value($v, shift $argv, ("shift " + string($v) + " parameter")); } sub parameter_tests() { no_parameter_test(); parameter_and_shift_test(1, 2); shift_test(1, test3()[1], 3, 4, "hello"); one_parameter_shift_test(1); } bool sub short_circuit_test(string $op) { print("ERROR: %n logic short-circuiting is not working!\n", $op); $errors++; return False; } sub logic_message(string $op) { if ($o.verbose) printf("OK: %s logic test\n", $op); } # logic short-circuiting test sub logic_tests() { my any $a = 1; my any $b = 0; my int $c; if ($o.verbose) print("%%%% logic tests\n"); if ($a || short_circuit_test("or")) logic_message("short-circuit or"); if ($b && short_circuit_test("and")) $c = 1; else logic_message("short-circuit and"); if ($a && 1) logic_message("and"); if ($b || 1) logic_message("or"); test_value($b ? 0 : 1, 1, "first question-colon"); test_value($a ? 1 : 0, 1, "second question-colon"); $a = 1; $b = "1"; test_value($a == $b, True, "comparison with type conversion"); test_value($a === $b, False, "absolute comparison"); $a = 1, 2, 3, 4; $b = 1, 2, 3, 4; test_value($a == $b, True, "list comparison"); delete $b[3]; test_value($a == $b, False, "list comparison after delete"); $a[3] = ("gee" : 1, "whillakers" : 2, "list" : ( 1, 2, "three" )); $b[3] = $a[3]; test_value($a == $b, True, "complex list comparison"); test_value($a[3] == $b[3], True, "hash comparison"); test_value($a[3] != $b[3], False, "negative hash unequal comparison"); $a[3].chello = "hi"; test_value($a[3] == $b[3], False, "negative hash comparison"); test_value($a[3] != $b[3], True, "hash unequal comparison"); } sub printf_tests() { # some printf tests printf("field tests\n"); f_printf("f_printf: 5 character field with 7 char arg: %5s\n", "freddy1"); printf( " printf: 5 character field with 7 char arg: %5s\n", "freddy1"); printf("printf alignment tests\n"); f_printf("f_printf: 3 char arg left in 5 char field: %-5s\n", "abc"); printf( " printf: 3 char arg left in 5 char field: %-5s\n", "abc"); f_printf("f_printf: 3 char arg right in 5 char field: %5s\n", "abc"); printf( " printf: 3 char arg right in 5 char field: %5s\n", "abc"); } string sub switch_test(any $val) { my string $rv; switch ($val) { case 0: case "hello": case 1: $rv = "case 1"; break; case 2: $rv = "case 2"; default: return "default"; } return $rv; } string sub regex_switch_test(any $val) { my string $rv; switch ($val) { case /abc/: case /def/: case /barney/: $rv = "case 1"; break; case =~ /dinosaur/: $rv = "case 2"; break; case !~ /can/: $rv = "case 3"; break; default: return "default"; } return $rv; } string sub switch_with_relation_test(float $val) { my string $rv; switch ($val) { case < -1.0: $rv = "first switch"; break; case > 1.0: $rv = "second switch"; break; case <= -1.0: $rv = "third switch"; break; case >= 1.0: $rv = "fourth switch"; break; case 0.0: $rv = "fifth switch"; break; } return $rv; } sub statement_tests() { if ($o.verbose) print("%%%% statement tests\n"); # while test my int $a = 0; while ($a < 3) $a++; test_value($a, 3, "while"); # do while test $a = 0; do { $a++; } while ($a < 3); test_value($a, 3, "do while"); # for test my int $b = 0; for (my int $i = 0; $i < 3; $i++) $b++; test_value($a, 3, "for"); test_value($b, 3, "for exec"); # foreach tests $b = 0; my int $v; foreach $v in (1, 2, 3) $b++; test_value($v, 3, "foreach"); test_value($b, 3, "foreach exec"); my any $list = my list $x; test_value($x, NOTHING, "unassigned typed variable"); foreach my string $y in (\$list) $y = "test"; test_value($list, NOTHING, "first foreach reference"); $list = (1, 2, 3); foreach my any $y in (\$list) $y = "test"; test_value($list, ("test", "test", "test"), "second foreach reference"); $list = 1; foreach my any $y in (\$list) $y = "test"; test_value($list, "test", "third foreach reference"); # switch tests test_value(switch_test(1), "case 1", "first switch"); test_value(switch_test(2), "default", "second switch"); test_value(switch_test(3), "default", "third switch"); test_value(switch_test(0), "case 1", "fourth switch"); test_value(switch_test("hello"), "case 1", "fifth switch"); test_value(switch_test("testing"), "default", "sixth switch"); # switch with operators test_value(switch_with_relation_test(-2), "first switch", "first operator switch"); test_value(switch_with_relation_test(2), "second switch", "second operator switch"); test_value(switch_with_relation_test(-1.0), "third switch", "third operator switch"); test_value(switch_with_relation_test(1.0), "fourth switch", "fourth operator switch"); test_value(switch_with_relation_test(0), "fifth switch", "fifth operator switch"); # regex switch test_value(regex_switch_test("abc"), "case 1", "first regex switch"); test_value(regex_switch_test(), "case 3", "second regex switch"); test_value(regex_switch_test("BOOM"), "case 3", "third regex switch"); test_value(regex_switch_test("dinosaur"), "case 2", "fourth regex switch"); test_value(regex_switch_test("barney"), "case 1", "fifth regex switch"); test_value(regex_switch_test("canada"), "default", "sixth regex switch"); # on_exit tests try { $a = 1; on_exit $a = 2; $a = 3; throw False; } catch() { } my bool $err; my bool $success = False; try { $b = 100; on_exit { $b = 2; on_exit $b = 5; on_error $err = True; on_success $success = True; # we use "if (True)..." so we don't get an "unreachable-code" warning if (True) throw False; $b = -1; } $v = 100; on_exit $v = 99; # we use "if (True)..." so we don't get an "unreachable-code" warning if (True) throw False; on_exit $v = 101; } catch() { } test_value($a, 2, "first on_exit"); test_value($b, 5, "second on_exit"); test_value($v, 99, "third on_exit"); test_value($err, True, "on_error"); test_value($success, False, "on_success"); } int sub fibonacci(int $num) { if ($num == 2) return 2; return $num * fibonacci($num - 1); } # recursive function test sub recursive_function_test() { test_value(fibonacci(10), 3628800, "recursive function"); } sub backquote_tests() { test_value(`echo -n 1`, "1", "backquote"); } string sub sd(date $d) { return format_date("YYYY-MM-DD HH:mm:SS", $d); } sub test_date(date $d, int $y, int $w, int $day, int $n, reference $i) { my string $str = sprintf("%04d-W%02d-%d", $y, $w, $day); my hash $h = ( "year" : $y, "week" : $w, "day" : $day ); my date $d1; # subtract milliseconds from date to compare with timegm value if (my int $ms = get_milliseconds($d)) $d1 = $d - milliseconds($ms); else $d1 = $d; test_value($d1, date(int($d)), "date conversion " + $i); test_value(getISOWeekString($d), $str, "getISOWeekString() " + $i); test_value(getISOWeekHash($d), $h, "getISOWeekHash() " + $i); test_value(getISODayOfWeek($d), $day, "getDayOfWeek() " + $i); test_value(getDayNumber($d), $n, "getDayNumber() " + $i); test_value(getDateFromISOWeek($y, $w, $day), get_midnight($d), "getDateFromISOWeek() " + $i); # not all architectures support the timegm() system call #if ($d >= 1970-01-01 && $d < 2038-01-19) #test_value(timegm($d), int($d), "qore epoch conversion " + $i); $i++; } sub date_time_tests() { # here are the two formats for directly specifying date/time values: # ISO-8601 format (without timezone specification, currently qore does not support time zones) my date $date = 2004-02-01T12:30:00; # qore-specific date/time specification format ('-' instead of 'T' - more readable but non-standard) my date $ndate = 2004-03-02-12:30:00; test_value(format_date("YYYY-MM-DD HH:mm:SS", $date), "2004-02-01 12:30:00", "format_date()"); test_value($date - 5Y, 1999-02-01T12:30:00, "first date year subtraction"); test_value($date - 5M, 2003-09-01T12:30:00, "first date month subtraction"); test_value($date - 10D, 2004-01-22T12:30:00, "first date day subtraction"); test_value($date - 2h, 2004-02-01T10:30:00, "first date hour subtraction"); test_value($date - 25m, 2004-02-01T12:05:00, "first date minute subtraction"); test_value($date - 11s, 2004-02-01T12:29:49, "first date second subtraction"); test_value($date - 251ms, 2004-02-01T12:29:59.749, "first date millisecond subtraction"); test_value($date + 2Y, 2006-02-01T12:30:00, "first date year addition"); test_value($date + 5M, 2004-07-01T12:30:00, "first date month addition"); test_value($date + 10D, 2004-02-11T12:30:00, "first date day addition"); test_value($date + 2h, 2004-02-01T14:30:00, "first date hour addition"); test_value($date + 25m, 2004-02-01T12:55:00, "first date minute addition"); test_value($date + 11s, 2004-02-01T12:30:11, "first date second addition"); test_value($date + 251ms, 2004-02-01T12:30:00.251, "first date millisecond addition"); test_value($date - years(5), 1999-02-01-12:30:00, "second date year subtraction"); test_value($date - months(5), 2003-09-01-12:30:00, "second date month subtraction"); test_value($date - days(10), 2004-01-22-12:30:00, "second date day subtraction"); test_value($date - hours(2), 2004-02-01-10:30:00, "second date hour subtraction"); test_value($date - minutes(25), 2004-02-01-12:05:00, "second date minute subtraction"); test_value($date - seconds(11), 2004-02-01-12:29:49, "second date second subtraction"); test_value($date - milliseconds(500), 2004-02-01-12:29:59.5, "second date millisecond subtraction"); test_value($date + years(2), 2006-02-01-12:30:00, "second date year addition"); test_value($date + months(5), 2004-07-01-12:30:00, "second date month addition"); test_value($date + days(10), 2004-02-11-12:30:00, "second date day addition"); test_value($date + hours(2), 2004-02-01-14:30:00, "second date hour addition"); test_value($date + minutes(25), 2004-02-01-12:55:00, "second date minute addition"); test_value($date + seconds(11), 2004-02-01-12:30:11, "second date second addition"); test_value($date + milliseconds(578), 2004-02-01-12:30:00.578, "second date millisecond addition"); # testing ISO-8601 alternate period syntax (which is not very readable... :-( ) # date periods test_value($date - P0001-00-00T00:00:00, 2003-02-01T12:30:00, "third date year subtraction"); test_value($date - P1M, 2004-01-01T12:30:00, "third date month subtraction"); test_value($date - P0000-00-01, 2004-01-31T12:30:00, "third date day subtraction"); test_value($date + P1Y, 2005-02-01T12:30:00, "third date year addition"); test_value($date + P0000-01-00, 2004-03-01T12:30:00, "third date month addition"); test_value($date + P0000-00-01, 2004-02-02T12:30:00, "third date day addition"); # time periods test_value($date - P0000-00-00T01:00:00, 2004-02-01T11:30:00, "third date hour subtraction"); test_value($date - P00:01:00, 2004-02-01T12:29:00, "third date minute subtraction"); test_value($date - PT00:00:01, 2004-02-01T12:29:59, "third date second subtraction"); test_value($date + P01:00:00, 2004-02-01T13:30:00, "third date hour addition"); test_value($date + PT00:01:00, 2004-02-01T12:31:00, "third date minute addition"); test_value($date + P00:00:01, 2004-02-01T12:30:01, "third date second addition"); # arithmetic on dates with ms overflow test_value(2006-01-02T00:00:00.112, 2006-01-01T23:59:59.800 + 312ms, "third millisecond addition"); test_value(2006-01-01T23:59:59.800, 2006-01-02T00:00:00.112 - 312ms, "third millisecond subtraction"); test_value($date, localtime(mktime($date)), "localtime() and mktime()"); test_value($date - PT1H, 2004-02-01T11:30:00, "fourth date hour subtraction"); test_value($date + 30D, $ndate, "fourth date day addition"); test_value($ndate - 30D, $date, "fourth date day subtraction"); test_value($date + 23M, 2006-01-01T12:30:00, "fourth date month addition"); test_value($date - 4M, 2003-10-01T12:30:00, "fourth date month subtraction"); test_value($date, date("20040201123000"), "date function"); test_value(2001-01-01, date("2001-01", "YYYY-MM-DD"), "first date mask function"); test_value(2001-01-01, date("2001 Jan xx", "YYYY Mon DD"), "second date mask function"); test_value(2001-01-01T13:01, date("2001 JAN 01 13:01", "YYYY MON DD HH:mm"), "second date mask function"); # times without a date are assumed to be on Jan 1, 1970 test_value(11:25:27, 1970-01-01T11:25:27.000, "direct hour"); # test date conversion/calculation functions against known values my int $i = 1; test_date(1068-01-01, 1068, 1, 3, 1, \$i); test_date(1783-09-18, 1783, 38, 4, 261, \$i); test_date(1864-02-29, 1864, 9, 1, 60, \$i); test_date(1864-03-01, 1864, 9, 2, 61, \$i); test_date(1968-01-01T11:01:20, 1968, 1, 1, 1, \$i); test_date(1968-02-29, 1968, 9, 4, 60, \$i); test_date(1968-03-01, 1968, 9, 5, 61, \$i); test_date(1969-12-31T23:59:59.999, 1970, 1, 3, 365, \$i); test_date(1969-12-31T00:00:00.100, 1970, 1, 3, 365, \$i); test_date(1969-01-01T17:25:31.380, 1969, 1, 3, 1, \$i); # 10 test_date(1970-01-01, 1970, 1, 4, 1, \$i); test_date(1970-12-01T00:00:00, 1970, 49, 2, 335, \$i); test_date(1972-01-01, 1971, 52, 6, 1, \$i); test_date(1972-12-30, 1972, 52, 6, 365, \$i); test_date(1972-12-31, 1972, 52, 7, 366, \$i); test_date(2004-02-28, 2004, 9, 6, 59, \$i); test_date(2004-02-29, 2004, 9, 7, 60, \$i); test_date(2004-03-01, 2004, 10, 1, 61, \$i); test_date(2004-03-28, 2004, 13, 7, 88, \$i); test_date(2006-01-01, 2005, 52, 7, 1, \$i); # 20 test_date(2006-09-01, 2006, 35, 5, 244, \$i); test_date(2006-12-01, 2006, 48, 5, 335, \$i); test_date(2007-12-30, 2007, 52, 7, 364, \$i); test_date(2007-12-31, 2008, 1, 1, 365, \$i); test_date(2008-01-01, 2008, 1, 2, 1, \$i); test_date(2008-01-06, 2008, 1, 7, 6, \$i); test_date(2008-01-07, 2008, 2, 1, 7, \$i); test_date(2008-01-08, 2008, 2, 2, 8, \$i); test_date(2008-01-09, 2008, 2, 3, 9, \$i); test_date(2008-01-10, 2008, 2, 4, 10, \$i); # 30 test_date(2008-12-28, 2008, 52, 7, 363, \$i); test_date(2008-12-29, 2009, 1, 1, 364, \$i); test_date(2008-12-30, 2009, 1, 2, 365, \$i); test_date(2010-01-03, 2009, 53, 7, 3, \$i); test_date(2010-01-04, 2010, 1, 1, 4, \$i); test_date(2010-01-09, 2010, 1, 6, 9, \$i); test_date(2010-01-10, 2010, 1, 7, 10, \$i); test_date(2010-01-11, 2010, 2, 1, 11, \$i); test_date(2016-12-01, 2016, 48, 4, 336, \$i); test_date(2026-08-22, 2026, 34, 6, 234, \$i); # 40 test_date(2036-04-30, 2036, 18, 3, 121, \$i); test_date(2054-06-19, 2054, 25, 5, 170, \$i); test_date(2400-12-01, 2400, 48, 5, 336, \$i); test_date(2970-01-01, 2970, 1, 1, 1, \$i); test_date(9999-12-31, 9999, 52, 5, 365, \$i); test_date(9999-12-31T23:59:59.999, 9999, 52, 5, 365, \$i); # absolute date difference tests test_value(2006-01-02T11:34:28.344 - 2006-01-01, 35h + 34m + 28s +344ms, "date difference 1"); test_value(2099-04-21T19:20:02.106 - 1804-03-04T20:45:19.956, 2587078h + 34m + 42s + 150ms, "date difference 2"); } sub binary_tests() { my binary $b = binary("this is a test"); test_value(getByte($b, 3), ord("s"), "getByte()"); test_value($b, binary("this is a test"), "binary comparison"); test_value($b != binary("this is a test"), False, "binary negative comparison"); } sub string_tests() { my string $str = "Hi there, you there, pal"; my string $big = "GEE WHIZ"; test_value(strlen($str), 24, "strlen()"); test_value(toupper($str), "HI THERE, YOU THERE, PAL", "toupper()"); test_value(tolower($big), "gee whiz", "tolower()"); test_value(reverse($big), "ZIHW EEG", "reverse()"); # set up a string with UTF-8 multi-byte characters $str = "Über die Wolken läßt sich die Höhe begrüßen"; test_value(strlen($str), 49, "UTF-8 strlen()"); test_value(length($str), 43, "UTF-8 length()"); test_value(substr($str, 30), "Höhe begrüßen", "first UTF-8 substr()"); test_value(substr($str, -8), "begrüßen", "second UTF-8 substr()"); test_value(substr($str, 0, -39), "Über", "third UTF-8 substr()"); test_value(index($str, "läßt"), 16, "first UTF-8 index()"); test_value(index($str, "läßt", 1), 16, "second UTF-8 index()"); test_value(rindex($str, "ß"), 40, "first UTF-8 rindex()"); test_value(rindex($str, "ß", 25), 18, "second UTF-8 rindex()"); test_value(bindex($str, "läßt"), 17, "first UTF-8 bindex()"); test_value(bindex($str, "läßt", 1), 17, "second UTF-8 bindex()"); test_value(brindex($str, "ß"), 45, "first UTF-8 brindex()"); test_value(brindex($str, "ß", 25), 20, "second UTF-8 brindex()"); test_value(reverse($str), "neßürgeb ehöH eid hcis tßäl nekloW eid rebÜ", "UTF-8 reverse()"); test_value(index($str, "==="), -1, "negative index()"); test_value(rindex($str, "==="), -1, "negative rindex()"); test_value(bindex($str, "==="), -1, "negative bindex()"); test_value($str[31], "ö", "first UTF-8 string index dereference"); test_value($str[39], "ü", "second UTF-8 string index dereference"); # save string my string $ostr = $str; # convert the string to single-byte ISO-8859-1 characters and retest $str = convert_encoding($str, "ISO-8859-1"); test_value($str != $ostr, False, "string != operator with same text with different encodings"); test_value(strlen($str), 43, "ISO-8859-1 strlen()"); test_value(length($str), 43, "ISO-8859-1 length()"); test_value(substr($str, 30), convert_encoding("Höhe begrüßen", "ISO-8859-1"), "first ISO-8859-1 substr()"); test_value(substr($str, -8), convert_encoding("begrüßen", "ISO-8859-1"), "second ISO-8859-1 substr()"); test_value(substr($str, 0, -39), convert_encoding("Über", "ISO-8859-1"), "third ISO-8859-1 substr()"); test_value(index($str, convert_encoding("läßt", "ISO-8859-1")), 16, "first ISO-8859-1 index()"); test_value(index($str, convert_encoding("läßt", "ISO-8859-1"), 1), 16, "second ISO-8859-1 index()"); test_value(rindex($str, convert_encoding("ß", "ISO-8859-1")), 40, "first ISO-8859-1 rindex()"); test_value(rindex($str, convert_encoding("ß", "ISO-8859-1"), 25), 18, "second ISO-8859-1 rindex()"); test_value(ord($str, 1), 98, "ord()"); test_value(chr(104), "h", "chr()"); $str = "gee this is a long string"; my list $a = split(" ", $str); test_value($a[2], "is", "first string split()"); test_value($a[5], "string", "second string split()"); $a = split(binary(" "), binary($str)); test_value($a[2], binary("is"), "first binary split()"); test_value($a[5], binary("string"), "second binary split()"); $str = "äüößÄÖÜ"; # test length() with UTF-8 multi-byte characters test_value(length($str), 7, "length() with UTF-8 multi-byte characters"); test_value(strlen($str), 14, "strlen() with UTF-8 multi-byte characters"); # test charset encoding conversions my string $nstr = convert_encoding($str, "ISO-8859-1"); test_value(length($nstr), 7, "length() with ISO-8859-1 special characters"); test_value(strlen($nstr), 7, "strlen() with ISO-8859-1 special characters"); test_value($str, convert_encoding($nstr, "UTF-8"), "convert_encoding()"); # assign binary object my binary $x = <0abf83e8ca72d32c>; my string $b64 = makeBase64String($x); test_value($x, parseBase64String($b64), "first base64"); test_value("aGVsbG8=", makeBase64String("hello"), "makeBase64String()"); my string $hex = makeHexString($x); test_value($x, parseHexString($hex), "first hex"); # UTF-8 string splice tests $str = "äbcdéf"; splice $str, 5; test_value($str, "äbcdé", "first UTF-8 string splice"); splice $str, 3, 1; test_value($str, "äbcé", "second UTF-8 string splice"); splice $str, 1, 2, "GHI"; test_value($str, "äGHIé", "third UTF-8 string splice"); splice $str, 0, 4, "jkl"; test_value($str, "jklé", "fourth UTF-8 string splice"); splice $str, 0, 1; test_value($str, "klé", "fifth UTF-8 string splice"); splice $str, 5, 2, "MNO"; test_value($str, "kléMNO", "sixth UTF-8 string splice"); splice $str, -4, 2, "p"; test_value($str, "klpNO", "seventh UTF-8 string splice"); splice $str, -4, -2, "QRS"; test_value($str, "kQRSNO", "eighth UTF-8 string splice"); # UTF-8 string extract tests $str = "äbcdéf"; test_value((extract $str, 4), "éf", "first UTF-8 string extract"); test_value((extract $str, 1, 2), "bc", "second UTF-8 string extract"); test_value((extract $str, 1, 1, "bcdef"), "d", "third UTF-8 string extract"); test_value($str, "äbcdef", "final UTF-8 string extract"); # single-byte string splice tests $str = convert_encoding("äbcdéf", "ISO-8859-1"); splice $str, 5; test_value($str == "äbcdé", True, "first ISO-8859-1 string splice"); splice $str, 3, 1; test_value($str == "äbcé", True, "second ISO-8859-1 string splice"); splice $str, 1, 2, "GHI"; test_value($str == "äGHIé", True, "third ISO-8859-1 string splice"); splice $str, 0, 4, "jkl"; test_value($str == "jklé", True, "fouth ISO-8859-1 string splice"); splice $str, 0, 1; test_value($str == "klé", True, "fifth ISO-8859-1 string splice"); splice $str, 5, 2, "MNO"; test_value($str == "kléMNO", True, "sixth ISO-8859-1 string splice"); splice $str, -4, 2, "p"; test_value($str == "klpNO", True, "seventh ISO-8859-1 string splice"); splice $str, -4, -2, "QRS"; test_value($str == "kQRSNO", True, "eighth ISO-8859-1 string splice"); # UTF-8 string extract tests $str = convert_encoding("äbcdéf", "ISO-8859-1"); my string $val = extract $str, 4; test_value($val == "éf", True, "first UTF-8 string extract"); $val = extract $str, 1, 2; test_value($val == "bc", True, "second UTF-8 string extract"); $val = extract $str, 1, 1, "bcdef"; test_value($val == "d", True, "third UTF-8 string extract"); test_value($str == "äbcdef", True, "final UTF-8 string extract"); # join tests $str = join(":", "login","passwd",1,"gid","gcos","home","shell"); test_value($str, "login:passwd:1:gid:gcos:home:shell", "first join"); my list $l = ("login","passwd","uid","gid","gcos","home","shell"); $str = join(":", $l); test_value($str, "login:passwd:uid:gid:gcos:home:shell", "second join"); # transliteration tests $str = "Hello There"; test_value($str =~ tr/def/123/, "H2llo Th2r2", "first transliteration"); test_value($str =~ tr/a-z/0-9/, "H2999 T7292", "first range transliteration"); $str = "Hello There"; test_value($str =~ tr/a-z/A-Z/, "HELLO THERE", "second range transliteration"); test_value($str =~ tr/A-Z/a-z/, "hello there", "third range transliteration"); # regex subpattern extraction operator tests test_value("xmlns:wsdl" =~ x/(\w+):(\w+)/, ("xmlns", "wsdl"), "regex subpattern extraction"); test_value("xmlns-wsdl" =~ x/(\w+):(\w+)/, NOTHING, "negative regex subpattern extraction"); test_value(regex_extract("xmlns:wsdl", "(\\w+):(\\w+)"), ("xmlns", "wsdl"), "regex_extract()"); # regex operator tests test_value("hello" =~ /^hel*/, True, "regular expression positive match"); test_value("hello" =~ m/123*/, False, "regular expression negative match"); test_value("hello" =~ m/^HEL*/i, True, "regular expression case-insensitive positive match"); test_value("hello" =~ /^HEL*/, False, "regular expression case-insensitive negative match"); test_value("test\nx" =~ /test.x/s, True, "regular expression newline positive match"); test_value("test\nx" =~ /test.x/, False, "regular expression newline negative match"); test_value("hello" =~ /^ hel* #comment/x, True, "extended regular expression positive match"); test_value("hello" =~ /^ hel* #comment/, False, "extended regular expression negative match"); test_value("test\nx123" =~ /^x123/m, True, "multiline regular expression positive match"); test_value("test\nx123" =~ /^x123/, False, "multiline regular expression negative match"); # NOTE that escaping UTF-8 characters (\ä) doesn't work on PPC for some reason test_value("testäöüß" =~ /äöüß/, True, "regular expression UTF-8 match"); test_value("testäöüß" =~ /aouB/, False, "regular expression UTF-8 negative match"); test_value("hello" !~ /hel*/, False, "negative regular expression negative match"); test_value("hello" !~ /123*/, True, "negative regular expression positive match"); # regex substitution operator tests $l = ( "hello bar hi bar", "bar hello bar hi bar", "hello bar hi" ); test_value($l[0] =~ s/bar/foo/, "hello foo hi bar", "first non-global regular expression substitution"); test_value($l[1] =~ s/bar/foo/, "foo hello bar hi bar", "second non-global regular expression substitution"); test_value($l[2] =~ s/BAR/foo/i, "hello foo hi", "case-insensitive non-global regular expression substitution"); $l = ( "hello bar hi bar", "bar hello bar hi bar", "hello bar hi" ); test_value($l[0] =~ s/bar/foo/g, "hello foo hi foo", "first global regular expression substitution"); test_value($l[1] =~ s/bar/foo/g, "foo hello foo hi foo", "second global regular expression substitution"); test_value($l[2] =~ s/BAR/foo/ig, "hello foo hi", "case-insensitive global regular expression substitution"); my string $astr= "abc def"; $astr =~ s/(\w+) +(\w+)/$2, $1/; test_value($astr, "def, abc", "regular expression subpattern substitution"); # regex() tests test_value(regex("hello", "^hel*"), True, "regex() positive match"); test_value(regex("hello", "123*"), False, "regex() negative match"); test_value(regex("hello", "^HEL*", RE_Caseless), True, "regex() case-insensitive positive match"); test_value(regex("hello", "^HEL*"), False, "regex() case-insensitive negative match"); test_value(regex("test\nx", "test.x", RE_DotAll), True, "regex() newline positive match"); test_value(regex("test\nx", "test.x/"), False, "regex() newline negative match"); test_value(regex("hello", "^ hel* #comment", RE_Extended), True, "regex() extended positive match"); test_value(regex("hello", "^ hel* #comment"), False, "regex() extended negative match"); test_value(regex("test\nx123", "^x123", RE_MultiLine), True, "regex() multiline positive match"); test_value(regex("test\nx123", "^x123/"), False, "regex() multiline negative match"); test_value(regex("testäöüß", "\äöüß"), True, "regex() UTF-8 match"); test_value(regex("testäöüß", "aouB"), False, "regex() UTF-8 negative match"); # regex_subst() tests $l = ( "hello bar hi bar", "bar hello bar hi bar", "hello bar hi" ); test_value(regex_subst($l[0], "bar", "foo"), "hello foo hi bar", "first non-global regex_subst()"); test_value(regex_subst($l[1], "bar", "foo"), "foo hello bar hi bar", "second non-global regex_subst()"); test_value(regex_subst($l[2], "BAR", "foo", RE_Caseless), "hello foo hi", "case-insensitive non-global regex_subst()"); $l = ( "hello bar hi bar", "bar hello bar hi bar", "hello bar hi" ); test_value(regex_subst($l[0], "bar", "foo", RE_Global), "hello foo hi foo", "first global regex_subst()"); test_value(regex_subst($l[1], "bar", "foo", RE_Global), "foo hello foo hi foo", "second global regex_subst()"); test_value(regex_subst($l[2], "BAR", "foo", RE_Global|RE_Caseless), "hello foo hi", "case-insensitive global regex_subst()"); $astr = "abc def"; # note that the escape characters have to be escaped in the following pattern string test_value(regex_subst($astr, "(\\w+) +(\\w+)", "$2, $1"), "def, abc", "first subpattern regex_subst()"); # here we use single-quotes, so the escape characters do not have to be escaped test_value(regex_subst($astr, '(\w+) +(\w+)', "$2, $1"), "def, abc", "second subpattern regex_subst()"); # chomp tests $str = "hello\n"; chomp $str; test_value($str, "hello", "first string chomp"); $str += "\r\n"; chomp $str; test_value($str, "hello", "second string chomp"); $l = ( 1, "hello\n", 3.0, True, "test\r\n" ); chomp $l; test_value($l, ( 1, "hello", 3.0, True, "test" ), "list chomp"); my hash $h = ( "key1" : "hello\n", "key2" : 2045, "key3": "test\r\n", "key4" : 302.223 ); chomp $h; test_value($h, ( "key1" : "hello", "key2" : 2045, "key3": "test", "key4" : 302.223 ), "hash chomp"); $str = "hello\n"; chomp(\$str); test_value($str, "hello", "string reference chomp()"); $str = " \t\n hello \n \r \t \0 "; trim $str; test_value($str, "hello", "trim string operator test"); $str = " \t\n hello \n \r \t \0 "; trim(\$str); test_value($str, "hello", "trim string reference test"); $l = ( 1, " \r \t hello \n \r \v \t", 3.0, True, " test\r\n " ); trim $l; test_value($l, ( 1, "hello", 3.0, True, "test" ), "list trim"); $h = ( "key1" : " hello\n \r ", "key2" : 2045, "key3": " test\r \n \t\v ", "key4" : 302.223 ); trim $h; test_value($h, ( "key1" : "hello", "key2" : 2045, "key3": "test", "key4" : 302.223 ), "hash trim"); } sub pwd_tests() { # getpwuid(0).pw_name may not always be "root" # skip the test on windows if (Qore::PlatformOS !~ /cygwin/i) { test_value(getpwuid(0).pw_uid, 0, "getpwuid()"); my hash $h; # try to get passwd entry for uid 0, ignore exceptions try $h = getpwuid2(0); catch () {} test_value($h.pw_uid, 0, "getpwuid2()"); test_value(getpwnam("root").pw_uid, 0, "getpwnam()"); # try to get passwd entry for root, ignore exceptions try $h = getpwnam2("root"); catch () {} test_value($h.pw_uid, 0, "getpwnam2()"); test_value(getgrgid(0).gr_gid, 0, "getgrgid()"); # try to get group entry for gid 0, ignore exceptions try $h = getgrgid2(0); catch () {} test_value($h.gr_gid, 0, "getgrgid2()"); my string $gn = Qore::PlatformOS == "Darwin" ? "wheel" : "root"; test_value(getgrnam($gn).gr_gid, 0, "getgrnam()"); # try to get group entry for root, ignore exceptions try $h = getgrnam2($gn); catch () {} test_value($h.gr_gid, 0, "getgrnam2()"); } } any sub simple_shift() { return shift $argv; } sub misc_tests() { my hash $dh = ( "user" : "user", "pass" : "123pass@word", "db" : "dbname", "charset" : "utf8", "host" : "hostname" ); my string $ds = "user/123pass@word@dbname(utf8)%hostname"; test_value($dh, parseDatasource($ds), "first parseDatasource()"); test_value((1, 2), simple_shift((1, 2)), "list arg function call"); test_value(call_function("simple_shift", 1), 1, "call_function()"); test_value(call_builtin_function("type", 1), Type::Int, "call_builtin_function()"); test_value(existsFunction("simple_shift"), True, "existsFunction()"); test_value(functionType("simple_shift"), "user", "functionType() user"); test_value(functionType("printf"), "builtin", "functionType() builtin"); test_value(type(1), "integer", "type()"); my string $str1 = "&<>\""; my string $str2 = "&<>""; test_value(html_encode($str1), $str2, "html_encode()"); test_value(html_decode($str2), $str1, "html_decode()"); # note that '@' signs are legal in the password field as with datasources my string $url = "https://username:passw@rd@hostname:1044/path/is/here"; my hash $uh = ( "protocol" : "https", "username" : "username", "password" : "passw@rd", "host" : "hostname", "port" : 1044, "path" : "/path/is/here" ); test_value(parseURL($url), $uh, "parseURL()"); # test gzip my string $str = "This is a long string xxxxxxxxxxxxxxxxxxxxxxxxxxxx"; my binary $bstr = binary($str); my binary $c = compress($str); test_value($str, uncompress_to_string($c), "compress() and uncompress_to_string()"); test_value($bstr, uncompress_to_binary($c), "compress() and uncompress_to_binary()"); my binary $gz = gzip($str); test_value($str, gunzip_to_string($gz), "gzip() and gunzip_to_string()"); test_value($bstr, gunzip_to_binary($gz), "gzip() and gunzip_to_binary()"); # test bzip2 my binary $bz = bzip2($str); test_value($str, bunzip2_to_string($bz), "bzip2 and bunzip2_to_string"); test_value($bstr, bunzip2_to_binary($bz), "bzip2 and bunzip2_to_binary"); } sub math_tests() { test_value(ceil(2.7), 3.0, "ceil()"); test_value(floor(3.7), 3.0, "fllor()"); test_value(format_number(".,3", -48392093894.2349), "-48.392.093.894,235", "format_number()"); } sub lib_tests() { my string $pn = get_script_path(); test_value(stat($pn)[1], hstat($pn).inode, "stat() and hstat()"); test_value(hstat($pn).type, "REGULAR", "hstat()"); #my string $h = gethostname(); #test_value($h, gethostbyaddr(gethostbyname($h)), "host functions"); } sub file_tests() { test_value(is_file($ENV."_"), True, "is_file()"); test_value(is_executable($ENV."_"), True, "is_executable()"); test_value(is_dir("/"), True, "is_dir()"); test_value(is_writeable($ENV.HOME), True, "is_writable()"); test_value(is_readable($ENV.HOME), False, "is_readable()"); test_value(is_dev("/dev/null"), True, "is_dev()"); test_value(is_cdev("/dev/null"), True, "is_cdev()"); test_value(is_bdev("/dev/null"), False, "is_bdev()"); test_value(is_link("/"), False, "is_link()"); test_value(is_socket("/"), False, "is_socket()"); test_value(is_pipe("/"), False, "is_pipe()"); } sub io_tests() { test_value(sprintf("%04d-%.2f", 25, 101.239), "0025-101.24", "sprintf()"); test_value(vsprintf("%04d-%.2f", (25, 101.239)), "0025-101.24", "vsprintf()"); # check multi-byte character set support for f_*printf() test_value(f_sprintf("%3s", "niña"), "niñ", "UTF-8 f_sprintf()"); } string sub f1_test(string $x) { return type($x); } string sub f1_test(float $x) { return type($x); } string sub f_test(int $x) { return type($x); } string sub f_test(float $x) { return type($x); } sub overload_tests() { test_value(f_test(1), "integer", "first overload partial match"); test_value(f_test(1.1), "float", "second overload partial match"); test_value(f1_test(1), "float", "third overload partial match"); test_value(f1_test(1.1), "float", "fourth overload partial match"); test_value(f1_test("str"), "string", "fifth overload partial match"); my int $i = 1; test_value(f_test($i), "integer", "first runtime overload partial match"); test_value(f1_test($i), "float", "second runtime overload partial match"); my float $fi = 1.1; test_value(f_test($fi), "float", "third runtime overload partial match"); test_value(f1_test($fi), "float", "fourth runtime overload partial match"); } sub function_tests() { date_time_tests(); binary_tests(); string_tests(); pwd_tests(); misc_tests(); math_tests(); lib_tests(); io_tests(); overload_tests(); } int sub t(any $a) { return $a + 1; } class Test inherits Socket { private { int $.a; int $.b; } public { list $.data; hash $.t; int $.x; any $.key; any $.unique; any $.new; any $.barn; any $.asd; } constructor(any $a, any $b, any $c) { $.a = 1; $.b = 2; $.data = ($a, $b, $c); } any getData(int $elem) { if (exists $elem) return $.data[$elem]; return $.data; } string methodGate(string $m) { return $m; } string memberGate(string $m) { return "memberGate-" + $m; } memberNotification(string $m) { $.t.$m = $self.$m; } code closure(any $x) { my int $a = 1; # return a closure encapsulating the state of the object return string sub (any $y) { return sprintf("%s-%n-%n-%n", $.data[1], $x, $y, ++$a); }; } any argTest() { return $argv; } } sub class_test_Program() { my string $func = "namespace ITest { const val = 1.0; } $gv2 = 123; int sub t2(int $a) { return $a + 2; } int sub et(int $a) { return t($a); } string sub tot() { return getClassName($to); } Queue sub getObject() { return new Queue(); } sub deleteException() { $ro.getData(0); delete $ro; }"; my string $pf = "newfunc();"; my string $nf = "sub newfunc() { return True; }"; my Program $a = new Program(); $a.parsePending($pf, "pending test part1"); $a.parsePending($nf, "pending test part2"); $a.parseCommit(); $a.importFunction("t"); $a.importGlobalVariable("to"); $a.importGlobalVariable("ro", True); $a.parse($func, "test"); test_value($a.callFunction("newfunc"), True, "Program::parsePending()"); test_value($a.callFunction("t2", 1), 3, "Program::parse()"); test_value($a.callFunctionArgs("t2", list(int(2))), 4, "program imported function"); test_value($a.callFunction("et", 1), 2, "program imported function"); test_value($a.callFunction("tot", 1), "Test", "program imported object variable"); test_value($to.member, "memberGate-member", "program imported object member gate"); test_value($to.method(), "method", "program imported object method gate"); try $a.callFunction("deleteException"); catch ($ex) test_value($ex.err, "ACCESS-ERROR", "Program::importGlobalVariable() readonly"); my Queue $o = $a.callFunction("getObject"); delete $a; test_value(getClassName($o), "Queue", "class returned from deleted subprogram object"); } sub class_test_File() { return; /* # File test my File $f = new File(); $f.open($ENV."_"); my string $l = $f.readLine(); my int $p = $f.getPos(); $f.setPos(0); test_value($l, $f.readLine(), "File::readLine() and File::setPos()"); test_value($p, $f.getPos(), "File::getPos()"); */ } const cert_pem = "-----BEGIN CERTIFICATE----- MIIDAjCCAqygAwIBAgIJALLMpB2Hc61YMA0GCSqGSIb3DQEBBQUAMIGKMQswCQYD VQQGEwJDWjEPMA0GA1UECBMGUHJhZ3VlMQ8wDQYDVQQHEwZQcmFndWUxIjAgBgNV BAoTGVFvcmUgUHJvZ3JhbW1pbmcgTGFuZ3VhZ2UxFjAUBgNVBAMTDURhdmlkIE5p Y2hvbHMxHTAbBgkqhkiG9w0BCQEWDmRhdmlkQHFvcmUub3JnMB4XDTEwMDMxMDE0 MjcwN1oXDTExMDMxMDE0MjcwN1owgYoxCzAJBgNVBAYTAkNaMQ8wDQYDVQQIEwZQ cmFndWUxDzANBgNVBAcTBlByYWd1ZTEiMCAGA1UEChMZUW9yZSBQcm9ncmFtbWlu ZyBMYW5ndWFnZTEWMBQGA1UEAxMNRGF2aWQgTmljaG9sczEdMBsGCSqGSIb3DQEJ ARYOZGF2aWRAcW9yZS5vcmcwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAxvP3j5yN /7BxHxSCaJLYAAeGFo93jVtulzIPu3ULH9rzSiO3EPYeUOEQtpe3ks0tUu75BVDY OxiRSD3iy99/pQIDAQABo4HyMIHvMB0GA1UdDgQWBBSV/JWX0QUgmL+5885yMjh8 dS4T8DCBvwYDVR0jBIG3MIG0gBSV/JWX0QUgmL+5885yMjh8dS4T8KGBkKSBjTCB ijELMAkGA1UEBhMCQ1oxDzANBgNVBAgTBlByYWd1ZTEPMA0GA1UEBxMGUHJhZ3Vl MSIwIAYDVQQKExlRb3JlIFByb2dyYW1taW5nIExhbmd1YWdlMRYwFAYDVQQDEw1E YXZpZCBOaWNob2xzMR0wGwYJKoZIhvcNAQkBFg5kYXZpZEBxb3JlLm9yZ4IJALLM pB2Hc61YMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADQQAMZ6N0cjzTiaNx 1Jyrp3Agcc71xt47xSle5j3kDb0D7dn+HvgaNfDIW7cmDJIsiYnhxdMyezct06WS IcewTtsR -----END CERTIFICATE-----"; # certificate signature (literal binary value) const cert_sig = <0c67a374723cd389a371d49caba7702071cef5c6de3bc5295ee63de40dbd03edd9fe1ef81a35f0c85bb7260c922c8989e1c5d3327b372dd3a59221c7b04edb11>; const key_pem = "-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: BF-CBC,C73CE02812F598E4 TTpTQq7DR2GUFrpjMVh1QzQDNp2lut/tEJlcPlX0qo7JxS8vm3N4+9Wmq3GCGdGZ 3hs/bZ/aAZRxzDguxEV03Bxy+eqP2G/FyfpzesJL4m7bdr35P8ZKXn75PJbvDzhC 7uZOH1UaLP/8OHJ8u2gK8skRF0kCtnOMLKBJYmVQFMgnFmiIMtYEtd4UitMTcxVo Ax1m2IeIo5j3FxQ58zo2SG15p/qj470pKQD/fiLLjhFv30L4jQdWidDido4SkL1f dFVXOpkauGI4IjM2+yAqaV1LFqV0FeRyaGxyyPC9HJow5idZ4wZQyplwA0bV9GuS cu/KPgDZez9wrlFeb+MGLQE7tw+jKum8OVSFAjF5NfQLF2mRHlccOImuy5RBXIVq fL7VyL/oGoUX4w4wwpUZlMlx3VqnXAoyf7NLQ50RD0M= -----END RSA PRIVATE KEY-----"; const key_pass = "qore"; sub class_test_SSLCertificate() { my SSLCertificate $cert(cert_pem); test_value($cert.getSignature(), cert_sig, "SSLCertificate::getSignature()"); test_value($cert.getInfo().subject.emailAddress, "david@qore.org", "SSLCertificate::getInfo()"); } sub class_test_SSLPrivateKey() { my SSLPrivateKey $key(key_pem, key_pass); test_value($key.getVersion(), 1, "SSLPrivateKey::getVersion()"); test_value($key.getBitLength(), 512, "SSLPrivateKey::getBitLength()"); test_value($key.getType(), "RSA", "SSLPrivateKey::getType()"); test_value($key.getInfo().type, "RSA", "SSLPrivateKey::getInfo()"); } sub err(string $test) { test_value(True, False, $test); } sub check(string $err, string $test) { test_value($err, "PRIVATE-MEMBER", $test); } class Test2 { private { any $.a; } } sub class_library_tests() { my Test $t = new Test(1, "gee", 2); test_value($t.getData(1), "gee", "first object"); test_value(exists $t.testing, False, "memberGate() existence"); test_value($t.testing, "memberGate-testing", "memberGate() value"); test_value($t.test(), "test", "methodGate() value"); test_value($t instanceof Test, True, "first instanceof"); test_value($t instanceof Qore::Socket, True, "second instanceof"); # verify private member access protection my string $test = "object -= private member"; try { $t -= "a"; err($test); } catch($ex) { check($ex.err, $test); } $test = "object -= list of private members"; try { $t -= ("a", "b"); err($test); } catch($ex) { check($ex.err, $test); } my any $t1 = new Test(1, "gee", 2); $test = "delete object's private member"; try { delete $t1.a; err($test); } catch($ex) { check($ex.err, $test); } $test = "reassign object's private member"; try { $t1.a = 3; err($test); } catch($ex) { check($ex.err, $test); } my any $t2 = new Test2(); $test = "read object's private member"; try { my any $x = $t2.a + $x; err($test); } catch($ex) { check($ex.err, $test); } # test memberGate test_value($t.a, "memberGate-a", "object memberGate() methods"); # test memberNotification() $t.x = 1; # test object closure my code $c = $t.closure(1); test_value($c(2), "gee-1-2-2", "first object closure"); test_value($c(2), "gee-1-2-3", "second object closure"); test_value($t.t.x, 1, "memberNotification() method"); # test callObjectMethod*() test_value(callObjectMethod($t1, "argTest", 1, 2), (1, 2), "callObjectMethod()"); test_value(callObjectMethodArgs($t1, "argTest"), NOTHING, "first callObjectMethodArgs()"); test_value(callObjectMethodArgs($t1, "argTest", 1), list(1), "second callObjectMethodArgs()"); test_value(callObjectMethodArgs($t1, "argTest", (1, 2)), (1, 2), "third callObjectMethodArgs()"); class_test_File(); class_test_Program(); class_test_SSLCertificate(); class_test_SSLPrivateKey(); } # find and context tests sub context_tests() { my hash $q = ( "name" : ("david", "renata", "laura", "camilla", "isabella"), "age" : (37, 30, 7, 4, 1 ) ); # initial matrix my hash $t = ( "name" : ("david", "renata", "laura", "camilla", "isabella"), "key1" : (1, 2, 3, 4, 5), "key2" : (4, 5, 6, 7, 8), "key3" : (7, 8, 9, 0, 1), "key4" : (2, 3, 4, 5, 6), "key5" : (3, 4, 5, 6, 7) ); # resulting transposed matrix my hash $i = ( "david" : (1, 4, 7, 2, 3), "renata" : (2, 5, 8, 3, 4), "laura" : (3, 6, 9, 4, 5), "camilla" : (4, 7, 0, 5, 6), "isabella" : (5, 8, 1, 6, 7) ); my hash $h; context q ($q) sortBy (%name) context t ($t) where (%q:name == %name) sortBy (%key2) $h.%q:name = (%key1, %t:key2, %key3, %key4, %key5); test_value($h, $i, "context"); my int $age = find %age in $q where (%name == "david"); test_value($age, 37, "find"); my list $ages = find %age in $q where (%name == "david" || %name == "isabella"); test_value($ages, (37, 1), "list find"); context ($q) { test_value(%%, ("name" : "david", "age" : 37), "context row"); break; } } const a = "key"; const b = 1.0; const i = 1; const l = (1, 2, 3); const chash = ( a : "one", b : l ); const exp = elements l; const hexp2 = chash{b}; namespace NTest { const t1 = "hello"; namespace Type{ const i = 2; } const Type::hithere = 4.0; class T1; } namespace NTest { const t2 = 2; } const NTest::Type::val1 = 1; const Qore::myconst = 1; sub constant_tests() { test_value(i, 1, "simple constant"); test_value(type(Type::val1), "integer", "first namespace constant"); test_value(Qore::myconst, NTest::Type::val1, "second namespace constant"); test_value(NTest::Type::i, 2, "third namespace constant"); test_value(chash{b}, (1, 2, 3), "indirect constant"); test_value(exp, 3, "evaluated constant"); test_value(hexp2, (1, 2, 3), "evaluated constant hash"); } sub digest_tests() { my string $str = "Hello There This is a Test - 1234567890"; if (HAVE_MD2) test_value(MD2($str), "349ea9f6c9681278cf86955dabd72d31", "MD2 digest"); test_value(MD4($str), "675d84fbf5d63e0d68c04577c3298fdc", "MD4 digest"); test_value(MD5($str), "bcbece19c1fe41d8c9e2e6134665ba5b", "MD5 digest"); test_value(DSS($str), "f4bc2c85698aae8961d626e2c590852b2d081199", "DSS digest"); test_value(DSS1($str), "f4bc2c85698aae8961d626e2c590852b2d081199", "DSS1 digest"); test_value(SHA($str), "99910d63f10286e8dda3c4a57801996f48f25b4b", "SHA digest"); test_value(SHA1($str), "f4bc2c85698aae8961d626e2c590852b2d081199", "SHA1 digest"); test_value(RIPEMD160($str), "8f32702e0146d5db6145f36271a4ddf249c087ae", "RIPEMD-160 digest"); } sub crypto_tests() { my string $str = "Hello There This is a Test - 1234567890"; my string $key = "1234567812345abcabcdefgh"; my binary $x = des_ede_encrypt_cbc($str, $key); my string $xstr = des_ede_decrypt_cbc_to_string($x, $key); test_value($str, $xstr, "triple DES 2 key encrypt-decrypt"); $x = des_ede3_encrypt_cbc($str, $key); $xstr = des_ede3_decrypt_cbc_to_string($x, $key); test_value($str, $xstr, "triple DES 3 key encrypt-decrypt"); $x = desx_encrypt_cbc($str, $key); $xstr = desx_decrypt_cbc_to_string($x, $key); test_value($str, $xstr, "DESX encrypt-decrypt"); $x = blowfish_encrypt_cbc($str, $key); $xstr = blowfish_decrypt_cbc_to_string($x, $key); test_value($str, $xstr, "blowfish encrypt-decrypt"); $x = rc4_encrypt($str, $key); $xstr = rc4_decrypt_to_string($x, $key); test_value($str, $xstr, "rc4 encrypt-decrypt"); $x = rc2_encrypt_cbc($str, $key); $xstr = rc2_decrypt_cbc_to_string($x, $key); test_value($str, $xstr, "rc2 encrypt-decrypt"); $x = cast5_encrypt_cbc($str, $key); $xstr = cast5_decrypt_cbc_to_string($x, $key); test_value($str, $xstr, "CAST5 encrypt-decrypt"); my binary $bkey = des_random_key(); $x = des_encrypt_cbc($str, $bkey); $xstr = des_decrypt_cbc_to_string($x, $bkey); test_value($str, $xstr, "DES random single key encrypt-decrypt"); } list sub closures(string $x) { my int $a = 1; my code $inc = string sub (any $y) { return sprintf("%s-%n-%n", $x, $y, ++$a); }; my code $dec = string sub (any $y) { return sprintf("%s-%n-%n", $x, $y, --$a); }; return ($inc, $dec); } sub closure_tests() { my (code $inc, code $dec) = closures("test"); test_value($inc(5), "test-5-2", "first closure"); test_value($inc(7), "test-7-3", "second closure"); test_value($dec(3), "test-3-2", "third closure"); } sub do_tests() { on_exit $counter.dec(); try { for (my int $i = 0; $i < $o.iters; $i++) { if ($o.verbose) printf("TID %d: iteration %d\n", gettid(), $i); operator_test(); array_tests(); hash_tests(); logic_tests(); statement_tests(); recursive_function_test(); parameter_tests(); class_library_tests(); function_tests(); context_tests(); constant_tests(); crypto_tests(); digest_tests(); closure_tests(); if ($o.bq) backquote_tests(); } } catch () { ++$errors; rethrow; } } sub main() { parse_command_line(); printf("QORE v%s Test Script (%d thread%s, %d iteration%s per thread)\n", Qore::VersionString, $o.threads, $o.threads == 1 ? "" : "s", $o.iters, $o.iters == 1 ? "" : "s"); our Counter $counter = new Counter(); while ($o.threads--) { $counter.inc(); background do_tests(); } $counter.waitForZero(); my int $ntests = elements $thash; printf("%d error%s encountered in %d test%s.\n", $errors, $errors == 1 ? "" : "s", $ntests, $ntests == 1 ? "" : "s"); } main();