summaryrefslogtreecommitdiffhomepage
path: root/tests/custom/03_stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'tests/custom/03_stdlib')
-rw-r--r--tests/custom/03_stdlib/29_require34
-rw-r--r--tests/custom/03_stdlib/35_include32
-rw-r--r--tests/custom/03_stdlib/36_render32
-rw-r--r--tests/custom/03_stdlib/61_loadstring153
-rw-r--r--tests/custom/03_stdlib/62_loadfile166
-rw-r--r--tests/custom/03_stdlib/63_call102
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 --