Skip to content

Commit ea8ccd3

Browse files
committed
refactor(tests): share array oracle support
1 parent f2e5bf4 commit ea8ccd3

15 files changed

Lines changed: 244 additions & 2732 deletions

tests/oracle/array/oracle_array_concat.rs

Lines changed: 3 additions & 196 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
use super::support::*;
2+
13
use std::ffi::OsStr;
24
use std::process::Command;
35

46
use quickjs_oxide::{
5-
CallableRef, CompleteOrdinaryPropertyDescriptor, Context, JsString, ObjectRef, Runtime,
6-
RuntimeError, Value,
7+
CompleteOrdinaryPropertyDescriptor, Context, JsString, ObjectRef, Runtime, RuntimeError, Value,
78
};
89

910
// This target pins QuickJS 2026-06-04's `js_array_concat`, including
@@ -534,84 +535,6 @@ fn array_concat_species_boxing_results_and_errors_use_pinned_realms() {
534535
);
535536
}
536537

537-
fn compare_value_cases(group: &str, cases: &[(&str, &str)]) {
538-
let Some(oracle) = std::env::var_os("QJS_ORACLE") else {
539-
eprintln!("SKIP {group} differential: set QJS_ORACLE to upstream qjs");
540-
return;
541-
};
542-
for &(description, source) in cases {
543-
let expected = observe_oracle(&oracle, source, description);
544-
let runtime = Runtime::new();
545-
let mut context = runtime.new_context();
546-
assert_eq!(
547-
observe_rust_eval(&runtime, &mut context, source, description),
548-
expected,
549-
"{group} drifted for {description}: {source:?}",
550-
);
551-
}
552-
}
553-
554-
fn observe_rust_eval(
555-
runtime: &Runtime,
556-
context: &mut Context,
557-
source: &str,
558-
description: &str,
559-
) -> String {
560-
match context.eval(source) {
561-
Ok(value) => format!(
562-
"return|{}|{}",
563-
value_type(runtime, &value),
564-
primitive_value_text(value),
565-
),
566-
Err(RuntimeError::Exception) => {
567-
let exception = context
568-
.take_exception()
569-
.unwrap_or_else(|error| panic!("take Rust exception for {description}: {error}"))
570-
.unwrap_or_else(|| panic!("Rust exception was missing for {description}"));
571-
match exception {
572-
Value::Object(error) => format!(
573-
"throw|object|{}|{}",
574-
error_string_property(runtime, context, &error, "name", description),
575-
error_string_property(runtime, context, &error, "message", description),
576-
),
577-
value => format!(
578-
"throw|{}|{}",
579-
value_type(runtime, &value),
580-
primitive_value_text(value),
581-
),
582-
}
583-
}
584-
Err(error) => panic!("Rust engine failure for {description} ({source:?}): {error}"),
585-
}
586-
}
587-
588-
fn observe_oracle(oracle: &OsStr, source: &str, description: &str) -> String {
589-
let wrapper = r#"
590-
try {
591-
var value = std.evalScript(scriptArgs[0]);
592-
print('return|' + typeof value + '|' + String(value));
593-
} catch (error) {
594-
if (error !== null && typeof error === 'object')
595-
print('throw|object|' + error.name + '|' + error.message);
596-
else
597-
print('throw|' + typeof error + '|' + String(error));
598-
}
599-
"#;
600-
let output = Command::new(oracle)
601-
.args(["--std", "-e", wrapper, source])
602-
.output()
603-
.unwrap_or_else(|error| panic!("could not run QuickJS for {description}: {error}"));
604-
assert!(
605-
output.status.success(),
606-
"QuickJS observer failed for {description}: {}",
607-
String::from_utf8_lossy(&output.stderr),
608-
);
609-
String::from_utf8(output.stdout)
610-
.unwrap_or_else(|error| panic!("QuickJS output was not UTF-8 for {description}: {error}"))
611-
.trim_end()
612-
.to_owned()
613-
}
614-
615538
fn rust_graph_observations() -> Vec<String> {
616539
let runtime = Runtime::new();
617540
let mut context = runtime.new_context();
@@ -738,119 +661,3 @@ fn method_metadata(
738661
runtime.is_constructor(callable.as_object()).unwrap(),
739662
)
740663
}
741-
742-
fn data_descriptor_bits(descriptor: &CompleteOrdinaryPropertyDescriptor) -> String {
743-
let CompleteOrdinaryPropertyDescriptor::Data {
744-
writable,
745-
enumerable,
746-
configurable,
747-
..
748-
} = descriptor
749-
else {
750-
panic!("expected a data descriptor");
751-
};
752-
format!(
753-
"D{}{}{}",
754-
Number(*writable),
755-
Number(*enumerable),
756-
Number(*configurable),
757-
)
758-
}
759-
760-
fn property_callable(
761-
runtime: &Runtime,
762-
context: &mut Context,
763-
object: &ObjectRef,
764-
name: &str,
765-
) -> CallableRef {
766-
let key = runtime.intern_property_key(name).unwrap();
767-
let Value::Object(function) = context
768-
.get_property(object, &key)
769-
.unwrap_or_else(|error| panic!("read callable {name}: {error}"))
770-
else {
771-
panic!("{name} was not an object");
772-
};
773-
runtime
774-
.as_callable(&function)
775-
.unwrap()
776-
.unwrap_or_else(|| panic!("{name} was not callable"))
777-
}
778-
779-
fn eval_object(context: &mut Context, source: &str, description: &str) -> ObjectRef {
780-
let Value::Object(object) = context
781-
.eval(source)
782-
.unwrap_or_else(|error| panic!("Rust rejected {description} ({source:?}): {error}"))
783-
else {
784-
panic!("Rust {description} did not evaluate to an object");
785-
};
786-
object
787-
}
788-
789-
fn take_exception_object(context: &mut Context, description: &str) -> ObjectRef {
790-
let Value::Object(error) = context
791-
.take_exception()
792-
.unwrap_or_else(|failure| panic!("take {description}: {failure}"))
793-
.unwrap_or_else(|| panic!("{description} was missing"))
794-
else {
795-
panic!("{description} was not an object");
796-
};
797-
error
798-
}
799-
800-
fn error_string_property(
801-
runtime: &Runtime,
802-
context: &mut Context,
803-
error: &ObjectRef,
804-
name: &str,
805-
description: &str,
806-
) -> String {
807-
let key = runtime.intern_property_key(name).unwrap();
808-
let Value::String(value) = context
809-
.get_property(error, &key)
810-
.unwrap_or_else(|failure| panic!("read Error.{name} for {description}: {failure}"))
811-
else {
812-
panic!("Error.{name} was not a string for {description}");
813-
};
814-
value.to_utf8_lossy()
815-
}
816-
817-
fn value_type(runtime: &Runtime, value: &Value) -> &'static str {
818-
match value {
819-
Value::Undefined => "undefined",
820-
Value::Null => "object",
821-
Value::Bool(_) => "boolean",
822-
Value::Int(_) | Value::Float(_) => "number",
823-
Value::BigInt(_) => "bigint",
824-
Value::String(_) => "string",
825-
Value::Object(object) => {
826-
if runtime.as_callable(object).unwrap().is_some() {
827-
"function"
828-
} else {
829-
"object"
830-
}
831-
}
832-
Value::Symbol(_) => "symbol",
833-
}
834-
}
835-
836-
fn primitive_value_text(value: Value) -> String {
837-
match value {
838-
Value::Undefined => "undefined".to_owned(),
839-
Value::Null => "null".to_owned(),
840-
Value::Bool(value) => value.to_string(),
841-
Value::Int(value) => value.to_string(),
842-
Value::Float(value) => quickjs_oxide::value::number_to_string(value),
843-
Value::BigInt(value) => value.to_string(),
844-
Value::String(value) => value.to_utf8_lossy(),
845-
Value::Object(_) => "<object>".to_owned(),
846-
Value::Symbol(_) => "<symbol>".to_owned(),
847-
}
848-
}
849-
850-
struct Number(bool);
851-
852-
impl std::fmt::Display for Number {
853-
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
854-
formatter.write_str(if self.0 { "1" } else { "0" })
855-
}
856-
}

0 commit comments

Comments
 (0)