diff options
Diffstat (limited to 'tests/custom')
-rw-r--r-- | tests/custom/03_stdlib/29_require | 34 | ||||
-rw-r--r-- | tests/custom/03_stdlib/35_include | 32 | ||||
-rw-r--r-- | tests/custom/03_stdlib/36_render | 32 | ||||
-rw-r--r-- | tests/custom/03_stdlib/61_loadstring | 153 | ||||
-rw-r--r-- | tests/custom/03_stdlib/62_loadfile | 166 | ||||
-rw-r--r-- | tests/custom/03_stdlib/63_call | 102 |
6 files changed, 452 insertions, 67 deletions
diff --git a/tests/custom/03_stdlib/29_require b/tests/custom/03_stdlib/29_require index 4fb4216..a81edb4 100644 --- a/tests/custom/03_stdlib/29_require +++ b/tests/custom/03_stdlib/29_require @@ -119,20 +119,9 @@ A compilation error in the module triggers an exception. -- Testcase -- {% - try { - push(REQUIRE_SEARCH_PATH, TESTFILES_PATH + '/*.uc'); + push(REQUIRE_SEARCH_PATH, TESTFILES_PATH + '/*.uc'); - require("require.test.broken"); - } - catch (e) { - // Catch and rethrow exception with modified message to - // ensure stable test output. - e.message = replace(e.message, - /(compile module '.+require\/test\/broken\.uc')/, - "compile module '.../require/test/broken.uc'"); - - die(e); - } + require("require.test.broken"); %} -- End -- @@ -142,19 +131,18 @@ return { -- End -- -- Expect stderr -- -Unable to compile module '.../require/test/broken.uc': -Syntax error: Expecting label -In line 2, byte 10: - - `return {` - ^-- Near here - +Runtime error: Unable to compile source file './files/require/test/broken.uc': + | Syntax error: Expecting label + | In line 2, byte 10: + | + | `return {` + | ^-- Near here -In line 14, byte 8: +In line 4, byte 31: - ` die(e);` - Near here ---^ + ` require("require.test.broken");` + Near here -----------------------^ -- End -- diff --git a/tests/custom/03_stdlib/35_include b/tests/custom/03_stdlib/35_include index 1d428f1..83c34bb 100644 --- a/tests/custom/03_stdlib/35_include +++ b/tests/custom/03_stdlib/35_include @@ -132,18 +132,7 @@ A compilation error in the file triggers an exception. -- Testcase -- {% - try { - include("files/broken.uc"); - } - catch (e) { - // Catch and rethrow exception with modified message to - // ensure stable test output. - e.message = replace(e.message, - /(compile module '.+broken\.uc')/, - "compile module '.../broken.uc'"); - - die(e); - } + include("files/broken.uc"); %} -- End -- @@ -155,19 +144,18 @@ A compilation error in the file triggers an exception. -- End -- -- Expect stderr -- -Unable to compile module '.../broken.uc': -Syntax error: Expecting label -In line 3, byte 11: +Runtime error: Unable to compile source file './files/broken.uc': - ` return {` - Near here --^ + | Syntax error: Expecting label + | In line 3, byte 11: + | + | ` return {` + | Near here --^ +In line 2, byte 27: - -In line 12, byte 8: - - ` die(e);` - Near here ---^ + ` include("files/broken.uc");` + Near here -------------------^ -- End -- diff --git a/tests/custom/03_stdlib/36_render b/tests/custom/03_stdlib/36_render index 64ef08a..55a1105 100644 --- a/tests/custom/03_stdlib/36_render +++ b/tests/custom/03_stdlib/36_render @@ -126,18 +126,7 @@ A compilation error in the file triggers an exception. -- Testcase -- {% - try { - include("files/broken.uc"); - } - catch (e) { - // Catch and rethrow exception with modified message to - // ensure stable test output. - e.message = replace(e.message, - /(compile module '.+broken\.uc')/, - "compile module '.../broken.uc'"); - - die(e); - } + include("files/broken.uc"); %} -- End -- @@ -149,19 +138,18 @@ A compilation error in the file triggers an exception. -- End -- -- Expect stderr -- -Unable to compile module '.../broken.uc': -Syntax error: Expecting label -In line 3, byte 11: +Runtime error: Unable to compile source file './files/broken.uc': - ` return {` - Near here --^ + | Syntax error: Expecting label + | In line 3, byte 11: + | + | ` return {` + | Near here --^ +In line 2, byte 27: - -In line 12, byte 8: - - ` die(e);` - Near here ---^ + ` include("files/broken.uc");` + Near here -------------------^ -- End -- diff --git a/tests/custom/03_stdlib/61_loadstring b/tests/custom/03_stdlib/61_loadstring new file mode 100644 index 0000000..2bb1f50 --- /dev/null +++ b/tests/custom/03_stdlib/61_loadstring @@ -0,0 +1,153 @@ +The `loadstring()` function compiles the given string argument into a +ucode program and returns the resulting entry function. + +Throws an exception on compilation failure. + +Returns the compiled program entry function. + + +Compile a simple program with default options + +-- Testcase -- +{% + let fn = loadstring('return 1 + 1;\n'); + fn(); +%} +-- End -- + +-- Expect stdout -- +return 1 + 1; +-- End -- + + +Compile a program in raw mode + +-- Testcase -- +{% + let fn = loadstring('printf("%d\\n", 1 + 1);\n', { raw_mode: true }); + fn(); +%} +-- End -- + +-- Expect stdout -- +2 +-- End -- + + +Compile a program in template mode + +-- Testcase -- +{% + let fn = loadstring('{{ 1 + 1 }}\n', { raw_mode: false }); + fn(); +%} +-- End -- + +-- Expect stdout -- +2 +-- End -- + + +Override module search path during compilation (import should fail due to empty path) + +-- Testcase -- +{% + loadstring('import { readfile } from "fs";\n', { + raw_mode: true, + module_search_path: [] + }); +%} +-- End -- + +-- Expect stderr -- +Runtime error: Unable to compile source string: + + | Syntax error: Unable to resolve path for module 'fs' + | In line 1, byte 30: + | + | `import { readfile } from "fs";` + | Near here -------------------^ + +In line 5, byte 3: + + ` });` + ^-- Near here + + +-- End -- + + +Force dynamic loading of unknown extensions at compile time (should succeed) + +-- Testcase -- +{% + loadstring('import foo from "doesnotexist";\n', { + raw_mode: true, + force_dynlink_list: [ "doesnotexist" ] + }); + + print("OK\n"); +%} +-- End -- + +-- Expect stdout -- +OK +-- End -- + + +Compiling a syntax error (should fail with syntax error exception) + +-- Testcase -- +{% + loadstring('1 +', { raw_mode: true }); +%} +-- End -- + +-- Expect stderr -- +Runtime error: Unable to compile source string: + + | Syntax error: Expecting expression + | In line 1, byte 4: + | + | `1 +` + | ^-- Near here + +In line 2, byte 38: + + ` loadstring('1 +', { raw_mode: true });` + Near here ------------------------------^ + + +-- End -- + + +Test loading precompiled bytecode + +-- Testcase -- +{% + // utpl -c -o - -e $'Hello world\n' | hexdump -v -e '"" 16/1 "%02x " "\n"' + const program = hexdec(` + 23 21 2f 75 73 72 2f 62 69 6e 2f 65 6e 76 20 75 + 63 6f 64 65 0a 1b 75 63 62 00 00 00 03 00 00 00 + 01 00 00 00 0e 5b 2d 65 20 61 72 67 75 6d 65 6e + 74 5d 00 00 00 00 00 00 0d 48 65 6c 6c 6f 20 77 + 6f 72 6c 64 0a 00 00 00 00 00 00 00 03 8b 80 80 + 00 00 00 00 01 00 00 00 00 00 00 00 05 00 00 00 + 10 00 00 00 0c 48 65 6c 6c 6f 20 77 6f 72 6c 64 + 0a 00 00 00 01 00 00 00 70 00 00 00 05 6d 61 69 + 6e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 08 01 00 00 00 00 41 07 3c 00 00 00 + 01 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 + 00 00 00 00 01 00 00 00 00 00 00 00 05 00 00 00 + 10 00 00 00 08 28 63 61 6c 6c 65 65 29 00 00 00 + 00 00 00 00 01 40 00 00 00 + `); + + let fn = loadstring(program); + fn(); +%} +-- End -- + +-- Expect stdout -- +Hello world +-- End -- diff --git a/tests/custom/03_stdlib/62_loadfile b/tests/custom/03_stdlib/62_loadfile new file mode 100644 index 0000000..4926696 --- /dev/null +++ b/tests/custom/03_stdlib/62_loadfile @@ -0,0 +1,166 @@ +The `loadfile()` function operates similar to `loadstring()` but reads the +input to compile from the specified file path instead. + +It compiles the given file name into a ucode program and returns the resulting +entry function. + +Throws an exception on compilation or file i/o failure. + +Returns the compiled program entry function. + + +Compile a simple program with default options + +-- Testcase -- +{% + let fn = loadfile('./files/test1.uc'); + fn(); +%} +-- End -- + +-- File test1.uc -- +return 1 + 1; +-- End -- + +-- Expect stdout -- +return 1 + 1; +-- End -- + + +Compile a program in raw mode + +-- Testcase -- +{% + let fn = loadfile('./files/test2.uc', { raw_mode: true }); + fn(); +%} +-- End -- + +-- File test2.uc -- +printf("%d\n", 1 + 1); +-- End -- + +-- Expect stdout -- +2 +-- End -- + + +Compile a program in template mode + +-- Testcase -- +{% + let fn = loadfile('./files/test3.uc', { raw_mode: false }); + fn(); +%} +-- End -- + +-- File test3.uc -- +{{ 1 + 1 }} +-- End -- + +-- Expect stdout -- +2 +-- End -- + + +Override module search path during compilation (import should fail due to empty path) + +-- Testcase -- +{% + loadfile('./files/test4.uc', { + raw_mode: true, + module_search_path: [] + }); +%} +-- End -- + +-- File test4.uc -- +import { readfile } from "fs"; +-- End -- + +-- Expect stderr -- +Runtime error: Unable to compile source file './files/test4.uc': + + | Syntax error: Unable to resolve path for module 'fs' + | In line 1, byte 30: + | + | `import { readfile } from "fs";` + | Near here -------------------^ + +In line 5, byte 3: + + ` });` + ^-- Near here + + +-- End -- + + +Force dynamic loading of unknown extensions at compile time (should succeed) + +-- Testcase -- +{% + loadfile('./files/test5.uc', { + raw_mode: true, + force_dynlink_list: [ "doesnotexist" ] + }); + + print("OK\n"); +%} +-- End -- + +-- File test5.uc -- +import foo from "doesnotexist"; +-- End -- + +-- Expect stdout -- +OK +-- End -- + + +Compiling a syntax error (should fail with syntax error exception) + +-- Testcase -- +{% + loadfile('./files/test6.uc', { raw_mode: true }); +%} +-- End -- + +-- File test6.uc -- +1 + +-- End -- + +-- Expect stderr -- +Runtime error: Unable to compile source file './files/test6.uc': + + | Syntax error: Expecting expression + | In line 1, byte 5: + | + | `1 +` + | ^-- Near here + +In line 2, byte 49: + + ` loadfile('./files/test6.uc', { raw_mode: true });` + Near here -----------------------------------------^ + + +-- End -- + + +Test loading precompiled bytecode + +-- Testcase -- +{% + import { readlink } from 'fs'; + + system(`${readlink('/proc/self/exe')} -T, -c -o ./files/test7.uc -e 'Hello world\n'`); + + let fn = loadfile('./files/test7.uc'); + fn(); +%} +-- End -- + +-- Expect stdout -- +Hello world +-- End -- diff --git a/tests/custom/03_stdlib/63_call b/tests/custom/03_stdlib/63_call new file mode 100644 index 0000000..41064eb --- /dev/null +++ b/tests/custom/03_stdlib/63_call @@ -0,0 +1,102 @@ +The `call()` function allows invoking functions with a modified `this` context +and global environment. It's main use case is binding global variables for +dynamiclly loaded code at runtime. + +Returns `null` if the given function value is not callable. +Returns the value returned by the invoked function in all other cases. + + +Test modifying `this` context + +-- Testcase -- +{% + let o1 = { + name: "Object #1", + func: function() { + print(`This is ${this.name}\n`); + } + }; + + let o2 = { + name: "Object #2" + }; + + o1.func(); + call(o1.func, o2); +%} +-- End -- + +-- Expect stdout -- +This is Object #1 +This is Object #2 +-- End -- + + +Test modifying environment + +-- Testcase -- +{% + function fn() { + print("Hello world\n"); + } + + fn(); + call(fn, null, { print: (s) => printf("Overridden print(): %s", s) }); +%} +-- End -- + +-- Expect stdout -- +Hello world +Overridden print(): Hello world +-- End -- + + +Test isolating environment + +-- Testcase -- +{% + function fn() { + print("Hello world\n"); + } + + fn(); + call(fn, null, proto({}, {})); // should fail due to unavailable print +%} +-- End -- + +-- Expect stdout -- +Hello world +-- End -- + +-- Expect stderr -- +Type error: left-hand side is not a function +In fn(), line 3, byte 24: + called from function call ([C]) + called from anonymous function ([stdin]:7:30) + + ` print("Hello world\n");` + Near here -------------------^ + + +-- End -- + + +Test passing through arguments + +-- Testcase -- +{% + function fn(a, b) { + printf("The product of %d * %d is %d\n", a, b, a * b); + } + + fn(3, 4); + call(fn, null, null, 5, 6); + call((...args) => printf("Args: %J\n", args), null, null, 1, 2, 3, 4, 5, 6); +%} +-- End -- + +-- Expect stdout -- +The product of 3 * 4 is 12 +The product of 5 * 6 is 30 +Args: [ 1, 2, 3, 4, 5, 6 ] +-- End -- |