. "$BST_LIB" # duktape 2.7.0 -- an embeddable ECMAScript engine. Two things ship and both are # covered here: /usr/bin/duk, the command-line interpreter, and libduktape.a + # duktape.h/duk_config.h for embedders. # # Neither is what meta-oe's recipe builds. Upstream's do_compile runs only # Makefile.sharedlibrary, and -shared cannot link on this static-only arm, so the # port swapped in upstream's own Makefile.cmdline plus a static archive. That is # what this suite has to keep honest: `duk` must really be an ECMAScript engine, # and the archive must really carry the compiled engine. # # SHAPE: one duk process runs data/selftest_duktape.js and prints a DUKCASE line # per case, which the loop below turns into result lines in a SINGLE pass. duk # costs ~1 s per start-up here (wasm instantiation of a 4.4 MB module) against the # runner's 60 s per-suite cap, so only cases that genuinely need their own process # get one -- exit codes, stdin, file arguments, bytecode. The payload's case names # are not re-listed here: DUK-COUNT plus the payload-all-ok gate below catch a # truncated run, which is what a per-name list would have been for. # # NOTHING HERE MAY RUN AN UNBOUNDED SCRIPT. A compute-bound duk is never preempted # on this kernel: the console dies, an on-target `timeout` around it does not fire, # and the machine must be reloaded in the browser. Note especially that # `function f(n){return f(n+1);}` is NOT a stack-overflow test here -- duktape does # proper tail calls, so it is an infinite loop. The payload's bounded # tail-call-flat / rec-nontail-rangeerror pair covers both halves safely. require duk duktape/present tmp=${TMPDIR:-/tmp}/bst-duk.$$ cap=$tmp.out mkdir -p "$tmp.d" # ---- the engine: one process, many assertions ------------------------------ duk "$BST_DATA/selftest_duktape.js" > "$cap" 2>&1 rc=$? # Whole-payload gate: names the offending case in the detail line. if [ "$rc" -eq 0 ] && grep -q '^ALL-DUK-OK$' "$cap"; then bst_ok duktape/payload-all-ok else bst_notok duktape/payload-all-ok "rc=$rc $(_bst_1line "$(grep 'FAIL' "$cap" 2>/dev/null | head -3)")" fi # The payload must have reached its end and reported every case it counted. An # uncaught throw mid-payload would exit duk early, and without this the missing # cases would simply not be reported rather than failing. emitted=$(grep -c '^DUKCASE ' "$cap" 2>/dev/null || echo 0) counted=$(awk '/^DUK-COUNT /{print $2}' "$cap" 2>/dev/null) check_eq duktape/payload-case-count "$counted" "$emitted" # One pass over the capture -> one result line per payload case. Done in the shell # rather than as a grep per name because a process per case does not fit the cap. while read -r kw name verdict detail; do [ "$kw" = "DUKCASE" ] || continue if [ "$verdict" = "ok" ]; then bst_ok "duktape/$name" else bst_notok "duktape/$name" "$(_bst_1line "$verdict $detail")" fi done < "$cap" # ---- the command line: cases that need their own process ------------------- check_out duktape/cli-eval "eval-ok" duk -e 'print("eval-ok");' printf 'print("from-file", 7*6);\n' > "$tmp.d/t.js" check_out duktape/cli-file "from-file 42" duk "$tmp.d/t.js" printf 'print("from-stdin");\n' > "$tmp.d/in.js" check_out duktape/cli-run-stdin "from-stdin" sh -c "duk --run-stdin < '$tmp.d/in.js'" # Bytecode: -c dumps compiled bytecode, -b loads it back. The pair is the only # path here that exercises duk_dump_function/duk_load_function on wasm32. duk -c "$tmp.d/t.bc" "$tmp.d/t.js" >/dev/null 2>&1 check duktape/cli-bytecode-written test -s "$tmp.d/t.bc" check_out duktape/cli-bytecode-run "from-file 42" duk -b "$tmp.d/t.bc" # An uncaught error prints a stack trace and exits 1. Asserted as rc + text # SEPARATELY because check_out requires exit 0, and the whole point of these # three is that duk exits NON-zero -- a script driving duk depends on that. check_rc duktape/cli-uncaught-rc 1 duk -e 'throw new Error("boom");' check duktape/cli-uncaught-msg sh -c "duk -e 'throw new Error(\"boom\");' 2>&1 | grep -q boom" check_rc duktape/cli-nofile-rc 1 duk "$tmp.d/does-not-exist.js" check_rc duktape/cli-syntaxerr-rc 1 duk -e 'function (' # Any unrecognised dash-option falls through to usage_exit(), which prints the # usage to stderr and exits 1. A bare `duk` is deliberately NOT tested: with no # file, no -e and no --run-stdin it enters INTERACTIVE mode and would block on the # console until the suite hit its timeout. check_rc duktape/cli-usage-rc 1 duk --help check duktape/cli-usage-text sh -c "duk --help 2>&1 | grep -q 'Usage: duk'" # ---- the embeddable half: -dev + -staticdev payload ------------------------ # # Static-only distro, and there is no on-target C compiler, so -- as for libyaml, # libinih and the other archive-only ports -- the assertion is that the shipped # payload is real: the header with its guard, version macro and declared API; the # pkg-config file describing the library this image actually ships; and the # archive carrying the compiled engine's exported symbols in its index. inc=/usr/include/duktape.h cfg=/usr/include/duk_config.h pc=/usr/lib/pkgconfig/duktape.pc lib=/usr/lib/libduktape.a check duktape/header-present test -f "$inc" check duktape/header-nonempty test -s "$inc" check_out duktape/header-guard "define DUKTAPE_H_INCLUDED" cat "$inc" check_out duktape/header-version "define DUK_VERSION" cat "$inc" check_out duktape/header-version-num "20700" cat "$inc" check duktape/config-present test -f "$cfg" check_out duktape/config-guard "DUK_CONFIG_H_INCLUDED" cat "$cfg" # The C API a caller needs to embed the engine at all: heap lifecycle, getting # code in, moving values across the value stack, calling back out, and errors. # One grep over the header for all of them, so this is a pass not a process each. missing=$(for f in duk_create_heap duk_destroy_heap duk_eval_raw duk_compile_raw \ duk_call duk_safe_call duk_new duk_push_string duk_push_int \ duk_push_object duk_push_c_function duk_get_string \ duk_get_number duk_to_string duk_pop duk_json_encode \ duk_json_decode duk_throw_raw duk_get_prop_string \ duk_put_prop_string duk_get_top duk_set_top; do grep -q "$f" "$inc" || printf '%s ' "$f" done) check_eq duktape/header-api-complete "" "$missing" check duktape/pc-present test -f "$pc" check_out duktape/pc-name "Name: duktape" cat "$pc" check_out duktape/pc-version "Version: 2.7.0" cat "$pc" check_out duktape/pc-libs "-lduktape" cat "$pc" # @PREFIX@/@LIBDIR@/@VERSION@ must be substituted; ${prefix} must NOT be -- that # is a pkg-config variable reference the file is supposed to carry literally, and # it is what makes libdir follow a --define-prefix relocation. check_out duktape/pc-prefix "prefix=/usr" cat "$pc" check_out duktape/pc-libdir 'libdir=${prefix}/lib' cat "$pc" check_out duktape/pc-incdir 'includedir=${prefix}/include' cat "$pc" check duktape/pc-no-placeholders sh -c "! grep -q '@[A-Z_]*@' '$pc'" check duktape/lib-present test -f "$lib" check duktape/lib-nonempty test -s "$lib" check_out duktape/lib-archive "!" head -c 8 "$lib" # Flatten to printable text once: GNU grep suppresses matches inside binary data # and busybox tr does not handle [:print:] under -c, so the octal range is the # formulation both greps and both trs agree on (same as the libyaml suite). flat=$tmp.flat tr -c '\40-\176\n' ' ' < "$lib" > "$flat" 2>/dev/null # duktape ships as a single amalgamated translation unit, so there is exactly one # member -- that is the shape, not a partial compile. check duktape/lib-member-duktape grep -q "duktape.o" "$flat" # Exported symbols spanning the same API surface asserted on the header, so the # index is evidence the wasm32 compile really produced the engine rather than an # archive that merely exists. One pass, as above. # (duk_create_heap_default is deliberately absent from this list: it is a macro # over duk_create_heap in duktape.h, so it is never an archive symbol.) missing=$(for s in duk_create_heap duk_destroy_heap duk_eval_raw \ duk_compile_raw duk_call duk_safe_call duk_push_string \ duk_push_c_function duk_get_string duk_to_string \ duk_json_encode duk_json_decode duk_get_prop_string \ duk_put_prop_string duk_throw_raw; do grep -q "$s" "$flat" || printf '%s ' "$s" done) check_eq duktape/lib-symbols-complete "" "$missing" # The archive must not carry the build directory. duktape.c is compiled by hand in # the bbappend (upstream ships no static-library makefile), and naming the source # absolutely there puts TMPDIR in the DWARF compilation-unit name -- which nothing # strips, since the distro sets INHIBIT_PACKAGE_STRIP. This is the on-target guard # for the do_package_qa buildpaths warning that mistake produced. check duktape/lib-no-buildpath sh -c "! grep -q '/tmp-glibc/work/' '$flat'" # Static-only is distro policy AND the whole reason this port exists: meta-oe's # recipe builds only a shared library and wasmld refuses it. A libduktape.so here # would mean the bbappend's do_compile override was lost. check duktape/no-shared sh -c 'set -- /usr/lib/libduktape.so*; [ ! -e "$1" ]' check duktape/no-shared-dbg sh -c 'set -- /usr/lib/libduktaped.so*; [ ! -e "$1" ]' rm -rf "$tmp.d" "$cap" "$flat"