@ -15,7 +15,6 @@ use boa_engine::{
use boa_gc ::{ Cell , Finalize , Gc , Trace } ;
use boa_gc ::{ Cell , Finalize , Gc , Trace } ;
use colored ::Colorize ;
use colored ::Colorize ;
use rayon ::prelude ::* ;
use rayon ::prelude ::* ;
use std ::panic ;
impl TestSuite {
impl TestSuite {
/// Runs the test suite.
/// Runs the test suite.
@ -169,27 +168,26 @@ impl Test {
error_type : _ ,
error_type : _ ,
}
}
) ) {
) ) {
let res = panic ::catch_unwind ( | | match self . expected_outcome {
let res = std ::panic ::catch_unwind ( | | match self . expected_outcome {
Outcome ::Positive = > {
Outcome ::Positive = > {
let mut context = Context ::default ( ) ;
let mut context = Context ::default ( ) ;
let async_result = AsyncResult ::default ( ) ;
if let Err ( e ) = self . set_up_env ( harness , & mut context , async_result . clone ( ) ) {
return ( false , e ) ;
}
let callback_obj = CallbackObject ::default ( ) ;
// TODO: timeout
// TODO: timeout
match self . set_up_env ( harness , & mut context , callback_obj . clone ( ) ) {
let value = match context . eval ( & test_content ) {
Ok ( _ ) = > {
Ok ( v ) = > v ,
let res = context . eval ( & test_content ) ;
Err ( e ) = > return ( false , format! ( "Uncaught {e}" ) ) ,
} ;
let passed = res . is_ok ( )
& & matches! ( * callback_obj . result . borrow ( ) , Some ( true ) | None ) ;
if let Err ( e ) = async_result . inner . borrow ( ) . as_ref ( ) {
let text = match res {
return ( false , format! ( "Uncaught {e}" ) ) ;
Ok ( val ) = > val . display ( ) . to_string ( ) ,
Err ( e ) = > format! ( "Uncaught {e}" , ) ,
} ;
( passed , text )
}
Err ( e ) = > ( false , e ) ,
}
}
( true , value . display ( ) . to_string ( ) )
}
}
Outcome ::Negative {
Outcome ::Negative {
phase : Phase ::Parse | Phase ::Early ,
phase : Phase ::Parse | Phase ::Early ,
@ -220,57 +218,47 @@ impl Test {
error_type ,
error_type ,
} = > {
} = > {
let mut context = Context ::default ( ) ;
let mut context = Context ::default ( ) ;
if let Err ( e ) = Parser ::new ( test_content . as_bytes ( ) ) . parse_all ( & mut context ) {
if let Err ( e ) = self . set_up_env ( harness , & mut context , AsyncResult ::default ( ) ) {
( false , format! ( "Uncaught {e}" ) )
return ( false , e ) ;
} else {
}
// TODO: timeout
let code = match Parser ::new ( test_content . as_bytes ( ) )
match self . set_up_env ( harness , & mut context , CallbackObject ::default ( ) ) {
. parse_all ( & mut context )
Ok ( _ ) = > match context . eval ( & test_content ) {
. map_err ( Into ::into )
Ok ( res ) = > ( false , res . display ( ) . to_string ( ) ) ,
. and_then ( | stmts | context . compile ( & stmts ) )
Err ( e ) = > {
{
let passed = if let Ok ( e ) = e . try_native ( & mut context ) {
Ok ( code ) = > code ,
match & e . kind {
Err ( e ) = > return ( false , format! ( "Uncaught {e}" ) ) ,
JsNativeErrorKind ::Syntax
} ;
if error_type = = ErrorType ::SyntaxError = >
{
// TODO: timeout
true
let e = match context . execute ( code ) {
}
Ok ( res ) = > return ( false , res . display ( ) . to_string ( ) ) ,
JsNativeErrorKind ::Reference
Err ( e ) = > e ,
if error_type = = ErrorType ::ReferenceError = >
} ;
{
if let Ok ( e ) = e . try_native ( & mut context ) {
true
match & e . kind {
}
JsNativeErrorKind ::Syntax if error_type = = ErrorType ::SyntaxError = > { }
JsNativeErrorKind ::Range
JsNativeErrorKind ::Reference
if error_type = = ErrorType ::RangeError = >
if error_type = = ErrorType ::ReferenceError = > { }
{
JsNativeErrorKind ::Range if error_type = = ErrorType ::RangeError = > { }
true
JsNativeErrorKind ::Type if error_type = = ErrorType ::TypeError = > { }
}
_ = > return ( false , format! ( "Uncaught {e}" ) ) ,
JsNativeErrorKind ::Type
if error_type = = ErrorType ::TypeError = >
{
true
}
_ = > false ,
}
} else {
e . as_opaque ( )
. expect ( "try_native cannot fail if e is not opaque" )
. as_object ( )
. and_then ( | o | o . get ( "constructor" , & mut context ) . ok ( ) )
. as_ref ( )
. and_then ( JsValue ::as_object )
. and_then ( | o | o . get ( "name" , & mut context ) . ok ( ) )
. as_ref ( )
. and_then ( JsValue ::as_string )
. map ( | s | s = = error_type . as_str ( ) )
. unwrap_or_default ( )
} ;
( passed , format! ( "Uncaught {e}" ) )
}
} ,
Err ( e ) = > ( false , e ) ,
}
}
( true , format! ( "Uncaught {e}" ) )
} else {
let passed = e
. as_opaque ( )
. expect ( "try_native cannot fail if e is not opaque" )
. as_object ( )
. and_then ( | o | o . get ( "constructor" , & mut context ) . ok ( ) )
. as_ref ( )
. and_then ( JsValue ::as_object )
. and_then ( | o | o . get ( "name" , & mut context ) . ok ( ) )
. as_ref ( )
. and_then ( JsValue ::as_string )
. map ( | s | s = = error_type . as_str ( ) )
. unwrap_or_default ( ) ;
( passed , format! ( "Uncaught {e}" ) )
}
}
}
}
} ) ;
} ) ;
@ -308,7 +296,7 @@ impl Test {
if matches! ( result , ( TestOutcomeResult ::Passed , _ ) ) {
if matches! ( result , ( TestOutcomeResult ::Passed , _ ) ) {
"." . green ( )
"." . green ( )
} else {
} else {
". " . red ( )
"F " . red ( )
}
}
) ;
) ;
}
}
@ -323,7 +311,7 @@ impl Test {
"Ignored" . yellow ( )
"Ignored" . yellow ( )
) ;
) ;
} else {
} else {
print! ( "{}" , ". " . yellow ( ) ) ;
print! ( "{}" , "- " . yellow ( ) ) ;
}
}
( TestOutcomeResult ::Ignored , String ::new ( ) )
( TestOutcomeResult ::Ignored , String ::new ( ) )
} ;
} ;
@ -351,10 +339,10 @@ impl Test {
& self ,
& self ,
harness : & Harness ,
harness : & Harness ,
context : & mut Context ,
context : & mut Context ,
callback_obj : CallbackObjec t,
async_result : AsyncResul t,
) -> Result < ( ) , String > {
) -> Result < ( ) , String > {
// Register the print() function.
// Register the print() function.
Self ::register_print_fn ( context , callback_obj ) ;
Self ::register_print_fn ( context , async_result ) ;
// add the $262 object.
// add the $262 object.
let _js262 = js262 ::init ( context ) ;
let _js262 = js262 ::init ( context ) ;
@ -392,10 +380,10 @@ impl Test {
}
}
/// Registers the print function in the context.
/// Registers the print function in the context.
fn register_print_fn ( context : & mut Context , callback_object : CallbackObjec t) {
fn register_print_fn ( context : & mut Context , async_result : AsyncResul t) {
// We use `FunctionBuilder` to define a closure with additional captures.
// We use `FunctionBuilder` to define a closure with additional captures.
let js_function =
let js_function =
FunctionBuilder ::closure_with_captures ( context , test262_print , callback_objec t)
FunctionBuilder ::closure_with_captures ( context , test262_print , async_resul t)
. name ( "print" )
. name ( "print" )
. length ( 1 )
. length ( 1 )
. build ( ) ;
. build ( ) ;
@ -409,9 +397,17 @@ impl Test {
}
}
/// Object which includes the result of the async operation.
/// Object which includes the result of the async operation.
#[ derive(Debug, Clone, Default, Trace, Finalize) ]
#[ derive(Debug, Clone, Trace, Finalize) ]
struct CallbackObject {
struct AsyncResult {
result : Gc < Cell < Option < bool > > > ,
inner : Gc < Cell < Result < ( ) , String > > > ,
}
impl Default for AsyncResult {
fn default ( ) -> Self {
Self {
inner : Gc ::new ( Cell ::new ( Ok ( ( ) ) ) ) ,
}
}
}
}
/// `print()` function required by the test262 suite.
/// `print()` function required by the test262 suite.
@ -419,14 +415,15 @@ struct CallbackObject {
fn test262_print (
fn test262_print (
_this : & JsValue ,
_this : & JsValue ,
args : & [ JsValue ] ,
args : & [ JsValue ] ,
captures : & mut CallbackObjec t,
async_result : & mut AsyncResul t,
_ context : & mut Context ,
context : & mut Context ,
) -> JsResult < JsValue > {
) -> JsResult < JsValue > {
if let Some ( message ) = args . get_or_undefined ( 0 ) . as_string ( ) {
let message = args
* captures . result . borrow_mut ( ) =
. get_or_undefined ( 0 )
Some ( message . to_std_string_escaped ( ) = = "Test262:AsyncTestComplete" ) ;
. to_string ( context ) ?
} else {
. to_std_string_escaped ( ) ;
* captures . result . borrow_mut ( ) = Some ( false ) ;
if message ! = "Test262:AsyncTestComplete" {
* async_result . inner . borrow_mut ( ) = Err ( message ) ;
}
}
Ok ( JsValue ::undefined ( ) )
Ok ( JsValue ::undefined ( ) )
}
}