mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-28 23:25:14 +08:00
100 lines
3.6 KiB
Bash
100 lines
3.6 KiB
Bash
#!/bin/sh
|
|
# SPDX-License-Identifier: GPL-2.0-only
|
|
#
|
|
# ucode grammar canary.
|
|
#
|
|
# The package has to parse on the ucode that ImmortalWrt/OpenWrt snapshots
|
|
# ship (2026.01.16~85922056 at the time of writing), and that ucode is
|
|
# STRICTER than current upstream HEAD:
|
|
#
|
|
# * `export function name() { ... }` must be terminated by ';'
|
|
# (upstream relaxed this in b885dd0f, whose own test suite uses the
|
|
# semicolon-free form; openwrt/openwrt@main now pins that revision)
|
|
# * object destructuring (`const { a } = x;`) is rejected
|
|
#
|
|
# A toolchain built from ucode's default branch therefore accepts code that
|
|
# no router can parse, and the whole suite stays green while the package is
|
|
# dead on arrival. That is exactly how the A/B refactor shipped five modules
|
|
# (config/loader.uc, subscription/{filter,decoder,fetcher,repository}.uc) that
|
|
# failed to compile on a target, plus an update_subscriptions.uc that used
|
|
# destructuring.
|
|
#
|
|
# This check pins the *dialect* rather than a revision: it asserts that the
|
|
# ucode under test still rejects those two constructs, so a permissive
|
|
# toolchain fails here instead of hiding a target regression. It also asserts
|
|
# that the constructs the package legitimately relies on still compile, so
|
|
# pinning ucode to something too old fails here too.
|
|
#
|
|
# Set HP_ALLOW_PERMISSIVE_UCODE=1 to demote the "must be rejected" failures to
|
|
# warnings when deliberately probing a newer ucode.
|
|
#
|
|
# Usage: sh tests/ucode/test_ucode_grammar.sh
|
|
|
|
WORK="$(mktemp -d "${TMPDIR:-/tmp}/hp-ucode-grammar.XXXXXX")" || exit 1
|
|
trap 'rm -rf "$WORK"' EXIT INT TERM
|
|
|
|
if ! command -v ucode > "/dev/null" 2>&1; then
|
|
echo "NOT RUN: ucode is not on PATH"
|
|
exit 2
|
|
fi
|
|
|
|
FAILED=0
|
|
ALLOW_PERMISSIVE="${HP_ALLOW_PERMISSIVE_UCODE:-0}"
|
|
|
|
# compile <name> <source...> : write a module and try to load it. `export`
|
|
# is only legal in a module, so the probe must go through `import` rather than
|
|
# `ucode -c` on the file directly.
|
|
compiles() {
|
|
name="$1"
|
|
shift
|
|
file="$WORK/$name.uc"
|
|
printf '%s\n' "$*" > "$file"
|
|
ucode -e "import * as m from \"$file\";" >/dev/null 2>&1
|
|
}
|
|
|
|
# --- constructs the package relies on: these MUST compile -----------------
|
|
|
|
accept() {
|
|
name="$1"
|
|
src="$2"
|
|
if compiles "$name" "$src"; then
|
|
echo "PASS: $name compiles"
|
|
else
|
|
echo "FAIL: $name does not compile (toolchain too old or broken)"
|
|
FAILED=1
|
|
fi
|
|
}
|
|
|
|
# --- constructs the target rejects: these MUST fail ----------------------
|
|
|
|
reject() {
|
|
name="$1"
|
|
src="$2"
|
|
if compiles "$name" "$src"; then
|
|
if [ "$ALLOW_PERMISSIVE" = "1" ]; then
|
|
echo "WARN: $name compiles (permissive ucode allowed by HP_ALLOW_PERMISSIVE_UCODE=1)"
|
|
else
|
|
echo "FAIL: $name compiles, but the target ucode rejects it"
|
|
echo " the toolchain is more permissive than ImmortalWrt/OpenWrt 2026.01.16"
|
|
echo " (pin tests/toolchain/build-ucode-*.sh UCODE_REV to a strict revision)"
|
|
FAILED=1
|
|
fi
|
|
else
|
|
echo "PASS: $name rejected by ucode (matches the target)"
|
|
fi
|
|
}
|
|
|
|
accept exported_function_strict 'export function f() { return 1; };'
|
|
accept plain_function 'function g() { return 1; }'
|
|
accept const_export 'export const c = 1;'
|
|
accept computed_key_object "export const t = { ['a']: 1 };"
|
|
accept optional_chaining_and_nullish 'export function g(o) { return o?.a ?? 1; };'
|
|
accept object_spread 'export function h() { return { ...{ a: 1 } }; };'
|
|
accept template_literal 'export function i(v) { return `x${v}`; };'
|
|
|
|
reject exported_function_without_semicolon 'export function f() { return 1; }'
|
|
reject object_destructuring 'export function h(o) { const { a } = o; return a; };'
|
|
reject array_destructuring 'export function i(a) { const [x] = a; return x; };'
|
|
|
|
exit $FAILED
|