@@ -107,17 +107,19 @@ tmp_dir=$(mktemp -d "${TMPDIR:-/tmp}/quickjs-oxide-fixture-gates.XXXXXX")
107107trap ' rm -rf -- "$tmp_dir"' EXIT HUP INT TERM
108108rows=$tmp_dir /rows.tsv
109109
110- expected_header=$' case_id\t fixture\t expected\t fixture_sha256\t expected_sha256\t mode\t transcript\t completion\t label'
110+ expected_header=$' case_id\t fixture\t expected\t fixture_sha256\t expected_sha256\t mode\t transcript\t completion\t prepared_sha256 \ t label'
111111header=$( sed -n ' 1p' " $registry " )
112112[[ " $header " == " $expected_header " ]] || die " unsupported fixture registry schema"
113+ [[ " $( tail -c 1 " $registry " | wc -l | tr -d ' [:space:]' ) " == 1 ]] \
114+ || die " fixture registry must end with a newline"
113115
114116tail -n +2 " $registry " | while IFS= read -r line; do
115117 [[ -n " $line " ]] || die " fixture registry contains a blank row"
116118 [[ " $line " != * $' \r ' * && " $line " != * $' \t ' ]] \
117119 || die " fixture registry contains non-canonical whitespace"
118120 field_count=$( awk -F ' \t' ' { print NF }' <<< " $line" )
119- [[ " $field_count " == 9 ]] || die " fixture registry row must have 9 columns"
120- IFS=$' \t ' read -r id fixture expected fixture_sha expected_sha mode transcript completion label <<< " $line"
121+ [[ " $field_count " == 10 ]] || die " fixture registry row must have 10 columns"
122+ IFS=$' \t ' read -r id fixture expected fixture_sha expected_sha mode transcript completion prepared_sha label <<< " $line"
121123 [[ " $id " =~ ^r3[a-z0-9]+$ ]] || die " invalid fixture case id: $id "
122124 [[ " $fixture " =~ ^tests/fixtures/[a-z0-9_]+\. js$ ]] \
123125 || die " invalid fixture path for $id : $fixture "
@@ -130,6 +132,7 @@ tail -n +2 "$registry" | while IFS= read -r line; do
130132 || die " expected transcript does not match fixture: $id "
131133 [[ " $fixture_sha " =~ ^[0-9a-f]{64}$ ]] || die " invalid fixture hash for $id "
132134 [[ " $expected_sha " =~ ^[0-9a-f]{64}$ ]] || die " invalid expected hash for $id "
135+ [[ " $prepared_sha " =~ ^[0-9a-f]{64}$ ]] || die " invalid prepared hash for $id "
133136 [[ " $label " =~ ^[a-z0-9]+ (-[a-z0-9]+)* $ ]] || die " invalid label for $id "
134137 case $mode in
135138 value)
@@ -145,6 +148,8 @@ tail -n +2 "$registry" | while IFS= read -r line; do
145148 direct)
146149 [[ " $transcript " == - && " $completion " == - ]] \
147150 || die " invalid direct-mode fields for $id "
151+ [[ " $prepared_sha " == " $fixture_sha " ]] \
152+ || die " direct fixture prepared hash must equal its source hash: $id "
148153 ;;
149154 * ) die " invalid fixture mode for $id : $mode " ;;
150155 esac
@@ -155,9 +160,9 @@ tail -n +2 "$registry" | while IFS= read -r line; do
155160 [[ " $last_line " == " $completion ;" ]] \
156161 || die " promise fixture does not end with $completion ;: $id "
157162 fi
158- printf ' %s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
163+ printf ' %s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\ n' \
159164 " $id " " $fixture " " $expected " " $fixture_sha " " $expected_sha " \
160- " $mode " " $transcript " " $completion " " $label "
165+ " $mode " " $transcript " " $completion " " $prepared_sha " " $ label"
161166done > " $rows "
162167
163168[[ -s " $rows " ]] || die " fixture registry has no cases"
@@ -169,11 +174,6 @@ sort -c -t $'\t' -k1,1 "$rows" \
169174 || die " fixture registry cases must be sorted by id"
170175case_count=$( wc -l < " $rows " | tr -d ' [:space:]' )
171176
172- if $validate_only ; then
173- echo " QuickJS fixture registry passed: $case_count authenticated cases."
174- exit 0
175- fi
176-
177177if [[ " $selection " == case ]] && ! awk -F ' \t' -v id=" $case_id " ' $1 == id { found=1 } END { exit !found }' " $rows " ; then
178178 die " unknown fixture case: $case_id "
179179fi
@@ -182,6 +182,54 @@ if [[ "$selection" == case ]]; then
182182 selected_count=1
183183fi
184184
185+ prepare_case () {
186+ local row=$1
187+ local fixture_sha expected_sha
188+ IFS=$' \t ' read -r fixture_case_id fixture_relative expected_relative \
189+ fixture_sha expected_sha fixture_mode fixture_transcript \
190+ fixture_completion fixture_prepared_sha fixture_label <<< " $row"
191+ fixture_path=$root /$fixture_relative
192+ expected_path=$root /$expected_relative
193+ engine_fixture=$fixture_path
194+
195+ case $fixture_mode in
196+ value)
197+ engine_fixture=$tmp_dir /$fixture_case_id .js
198+ {
199+ cat " $fixture_path "
200+ printf ' \nprint(%s.join("\\n"));\n' " $fixture_transcript "
201+ } > " $engine_fixture "
202+ quickjs_args=(--script " $engine_fixture " )
203+ oxide_args=(--print-result " $fixture_path " )
204+ ;;
205+ promise)
206+ engine_fixture=$tmp_dir /$fixture_case_id .js
207+ {
208+ sed ' $d' " $fixture_path "
209+ printf ' \n%s.then(\n' " $fixture_completion "
210+ printf ' function () { print(%s.join("\\n")); },\n' " $fixture_transcript "
211+ printf ' function (error) { throw error; }\n'
212+ printf ' );\n'
213+ } > " $engine_fixture "
214+ quickjs_args=(--std --script " $engine_fixture " )
215+ oxide_args=(" $engine_fixture " )
216+ ;;
217+ direct)
218+ quickjs_args=(--std --script " $fixture_path " )
219+ oxide_args=(" $fixture_path " )
220+ ;;
221+ esac
222+ verify_hash " $engine_fixture " " $fixture_prepared_sha "
223+ }
224+
225+ if $validate_only ; then
226+ while IFS= read -r row; do
227+ prepare_case " $row "
228+ done < " $rows "
229+ echo " QuickJS fixture registry passed: $case_count authenticated cases and drivers."
230+ exit 0
231+ fi
232+
185233oracle=$( " $script_dir /build-quickjs-oracle.sh" )
186234[[ -x " $oracle " ]] || die " pinned QuickJS oracle is not executable: $oracle "
187235if [[ -n " $oxide " && ! -x " $oxide " ]]; then
@@ -220,63 +268,28 @@ compare_transcript() {
220268
221269run_case () {
222270 local row=$1
223- local id fixture expected fixture_sha expected_sha mode transcript completion label
224- local fixture_path expected_path engine_fixture
225271 local quickjs_out quickjs_err oxide_out oxide_err
226- local -a quickjs_args oxide_args
227- IFS=$' \t ' read -r id fixture expected fixture_sha expected_sha mode transcript completion label <<< " $row"
228- fixture_path=$root /$fixture
229- expected_path=$root /$expected
230- engine_fixture=$fixture_path
231-
232- case $mode in
233- value)
234- engine_fixture=$tmp_dir /$id .js
235- {
236- cat " $fixture_path "
237- printf ' \nprint(%s.join("\\n"));\n' " $transcript "
238- } > " $engine_fixture "
239- quickjs_args=(--script " $engine_fixture " )
240- oxide_args=(--print-result " $fixture_path " )
241- ;;
242- promise)
243- engine_fixture=$tmp_dir /$id .js
244- {
245- sed ' $d' " $fixture_path "
246- printf ' \n%s.then(\n' " $completion "
247- printf ' function () { print(%s.join("\\n")); },\n' " $transcript "
248- printf ' function (error) { throw error; }\n'
249- printf ' );\n'
250- } > " $engine_fixture "
251- quickjs_args=(--std --script " $engine_fixture " )
252- oxide_args=(" $engine_fixture " )
253- ;;
254- direct)
255- quickjs_args=(--std --script " $fixture_path " )
256- oxide_args=(" $fixture_path " )
257- ;;
258- esac
259-
260- quickjs_out=$tmp_dir /$id .quickjs.out
261- quickjs_err=$tmp_dir /$id .quickjs.err
262- run_engine " pinned QuickJS 2026-06-04 ($id )" " $oracle " \
272+ prepare_case " $row "
273+ quickjs_out=$tmp_dir /$fixture_case_id .quickjs.out
274+ quickjs_err=$tmp_dir /$fixture_case_id .quickjs.err
275+ run_engine " pinned QuickJS 2026-06-04 ($fixture_case_id )" " $oracle " \
263276 " $quickjs_out " " $quickjs_err " " ${quickjs_args[@]} "
264- compare_transcript " pinned QuickJS 2026-06-04 ($id )" " $expected_path " " $quickjs_out "
277+ compare_transcript " pinned QuickJS 2026-06-04 ($fixture_case_id )" " $expected_path " " $quickjs_out "
265278
266279 if [[ -n " $oxide " ]]; then
267- oxide_out=$tmp_dir /$id .oxide.out
268- oxide_err=$tmp_dir /$id .oxide.err
269- run_engine " quickjs-oxide ($id )" " $oxide " \
280+ oxide_out=$tmp_dir /$fixture_case_id .oxide.out
281+ oxide_err=$tmp_dir /$fixture_case_id .oxide.err
282+ run_engine " quickjs-oxide ($fixture_case_id )" " $oxide " \
270283 " $oxide_out " " $oxide_err " " ${oxide_args[@]} "
271- compare_transcript " quickjs-oxide ($id )" " $expected_path " " $oxide_out "
284+ compare_transcript " quickjs-oxide ($fixture_case_id )" " $expected_path " " $oxide_out "
272285 if ! cmp -s -- " $quickjs_out " " $oxide_out " ; then
273- echo " error: quickjs-oxide differs from pinned QuickJS 2026-06-04 ($id )" >&2
286+ echo " error: quickjs-oxide differs from pinned QuickJS 2026-06-04 ($fixture_case_id )" >&2
274287 diff -u -- " $quickjs_out " " $oxide_out " >&2 || true
275288 exit 1
276289 fi
277- echo " $id $label differential passed"
290+ echo " $fixture_case_id $fixture_label differential passed"
278291 else
279- echo " $id $label oracle passed"
292+ echo " $fixture_case_id $fixture_label oracle passed"
280293 fi
281294}
282295
0 commit comments