diff --git a/crates/oxc_minifier/src/ast_passes/collapse_variable_declarations.rs b/crates/oxc_minifier/src/ast_passes/collapse_variable_declarations.rs index 65ccc811f346bb..eafea69032af68 100644 --- a/crates/oxc_minifier/src/ast_passes/collapse_variable_declarations.rs +++ b/crates/oxc_minifier/src/ast_passes/collapse_variable_declarations.rs @@ -235,19 +235,7 @@ impl<'a> CollapseVariableDeclarations { /// #[cfg(test)] mod test { - use oxc_allocator::Allocator; - - use crate::tester; - - fn test(source_text: &str, expected: &str) { - let allocator = Allocator::default(); - let mut pass = super::CollapseVariableDeclarations::new(); - tester::test(&allocator, source_text, expected, &mut pass); - } - - fn test_same(source_text: &str) { - test(source_text, source_text); - } + use crate::tester::{test, test_same}; mod join_vars { use super::{test, test_same}; diff --git a/crates/oxc_minifier/src/ast_passes/convert_to_dotted_properties.rs b/crates/oxc_minifier/src/ast_passes/convert_to_dotted_properties.rs index 1fe050b916ea39..6f7b3f8caaed35 100644 --- a/crates/oxc_minifier/src/ast_passes/convert_to_dotted_properties.rs +++ b/crates/oxc_minifier/src/ast_passes/convert_to_dotted_properties.rs @@ -67,19 +67,7 @@ impl<'a> ConvertToDottedProperties { #[cfg(test)] mod test { - use oxc_allocator::Allocator; - - use crate::tester; - - fn test(source_text: &str, expected: &str) { - let allocator = Allocator::default(); - let mut pass = super::ConvertToDottedProperties::new(false); - tester::test(&allocator, source_text, expected, &mut pass); - } - - fn test_same(source_text: &str) { - test(source_text, source_text); - } + use crate::tester::{test, test_same}; #[test] fn test_computed_to_member_expression() { diff --git a/crates/oxc_minifier/src/ast_passes/exploit_assigns.rs b/crates/oxc_minifier/src/ast_passes/exploit_assigns.rs index 074f9a2f98cad9..492d023a7f96dc 100644 --- a/crates/oxc_minifier/src/ast_passes/exploit_assigns.rs +++ b/crates/oxc_minifier/src/ast_passes/exploit_assigns.rs @@ -32,19 +32,7 @@ impl ExploitAssigns { /// #[cfg(test)] mod test { - use oxc_allocator::Allocator; - - use crate::tester; - - fn test(source_text: &str, expected: &str) { - let allocator = Allocator::default(); - let mut pass = super::ExploitAssigns::new(); - tester::test(&allocator, source_text, expected, &mut pass); - } - - fn test_same(source_text: &str) { - test(source_text, source_text); - } + use crate::tester::{test, test_same}; #[test] #[ignore] diff --git a/crates/oxc_minifier/src/ast_passes/minimize_exit_points.rs b/crates/oxc_minifier/src/ast_passes/minimize_exit_points.rs index 8b7c7255f6146b..f81c0e93b023f5 100644 --- a/crates/oxc_minifier/src/ast_passes/minimize_exit_points.rs +++ b/crates/oxc_minifier/src/ast_passes/minimize_exit_points.rs @@ -43,111 +43,99 @@ impl<'a> MinimizeExitPoints { #[cfg(test)] mod test { - use oxc_allocator::Allocator; - - use crate::tester; - - fn fold(source_text: &str, expected: &str) { - let allocator = Allocator::default(); - let mut pass = super::MinimizeExitPoints::new(); - tester::test(&allocator, source_text, expected, &mut pass); - } - - fn fold_same(source_text: &str) { - fold(source_text, source_text); - } + use crate::tester::{test, test_same}; #[test] #[ignore] fn test_break_optimization() { - fold("f:{if(true){a();break f;}else;b();}", "f:{if(true){a()}else{b()}}"); - fold("f:{if(false){a();break f;}else;b();break f;}", "f:{if(false){a()}else{b()}}"); - fold("f:{if(a()){b();break f;}else;c();}", "f:{if(a()){b();}else{c();}}"); - fold("f:{if(a()){b()}else{c();break f;}}", "f:{if(a()){b()}else{c();}}"); - fold("f:{if(a()){b();break f;}else;}", "f:{if(a()){b();}else;}"); - fold("f:{if(a()){break f;}else;}", "f:{if(a()){}else;}"); + test("f:{if(true){a();break f;}else;b();}", "f:{if(true){a()}else{b()}}"); + test("f:{if(false){a();break f;}else;b();break f;}", "f:{if(false){a()}else{b()}}"); + test("f:{if(a()){b();break f;}else;c();}", "f:{if(a()){b();}else{c();}}"); + test("f:{if(a()){b()}else{c();break f;}}", "f:{if(a()){b()}else{c();}}"); + test("f:{if(a()){b();break f;}else;}", "f:{if(a()){b();}else;}"); + test("f:{if(a()){break f;}else;}", "f:{if(a()){}else;}"); - fold("f:while(a())break f;", "f:while(a())break f"); - fold_same("f:for(x in a())break f"); + test("f:while(a())break f;", "f:while(a())break f"); + test_same("f:for(x in a())break f"); - fold_same("f:{while(a())break;}"); - fold_same("f:{for(x in a())break}"); + test_same("f:{while(a())break;}"); + test_same("f:{for(x in a())break}"); - fold("f:try{break f;}catch(e){break f;}", "f:try{}catch(e){}"); - fold( + test("f:try{break f;}catch(e){break f;}", "f:try{}catch(e){}"); + test( "f:try{if(a()){break f;}else{break f;} break f;}catch(e){}", "f:try{if(a()){}else{}}catch(e){}", ); - fold("f:g:break f", ""); - fold("f:g:{if(a()){break f;}else{break f;} break f;}", "f:g:{if(a()){}else{}}"); - fold("function f() { a: break a; }", "function f() {}"); - fold("function f() { a: { break a; } }", "function f() { a: {} }"); + test("f:g:break f", ""); + test("f:g:{if(a()){break f;}else{break f;} break f;}", "f:g:{if(a()){}else{}}"); + test("function f() { a: break a; }", "function f() {}"); + test("function f() { a: { break a; } }", "function f() { a: {} }"); } #[test] fn test_function_return_optimization1() { - fold("function f(){return}", "function f(){}"); + test("function f(){return}", "function f(){}"); } #[test] #[ignore] fn test_function_return_optimization2() { - fold("function f(){if(a()){b();if(c())return;}}", "function f(){if(a()){b();if(c());}}"); - fold("function f(){if(x)return; x=3; return; }", "function f(){if(x); else x=3}"); - fold( + test("function f(){if(a()){b();if(c())return;}}", "function f(){if(a()){b();if(c());}}"); + test("function f(){if(x)return; x=3; return; }", "function f(){if(x); else x=3}"); + test( "function f(){if(true){a();return;}else;b();}", "function f(){if(true){a();}else{b();}}", ); - fold( + test( "function f(){if(false){a();return;}else;b();return;}", "function f(){if(false){a();}else{b();}}", ); - fold( + test( "function f(){if(a()){b();return;}else;c();}", "function f(){if(a()){b();}else{c();}}", ); - fold("function f(){if(a()){b()}else{c();return;}}", "function f(){if(a()){b()}else{c();}}"); - fold("function f(){if(a()){b();return;}else;}", "function f(){if(a()){b();}else;}"); - fold( + test("function f(){if(a()){b()}else{c();return;}}", "function f(){if(a()){b()}else{c();}}"); + test("function f(){if(a()){b();return;}else;}", "function f(){if(a()){b();}else;}"); + test( "function f(){if(a()){return;}else{return;} return;}", "function f(){if(a()){}else{}}", ); - fold( + test( "function f(){if(a()){return;}else{return;} b();}", "function f(){if(a()){}else{return;b()}}", ); - fold( + test( "function f(){ if (x) return; if (y) return; if (z) return; w(); }", "function f() { if (x) {} else { if (y) {} else { if (z) {} else w(); }} }", ); - fold("function f(){while(a())return;}", "function f(){while(a())return}"); - fold_same("function f(){for(x in a())return}"); + test("function f(){while(a())return;}", "function f(){while(a())return}"); + test_same("function f(){for(x in a())return}"); - fold("function f(){while(a())break;}", "function f(){while(a())break}"); - fold_same("function f(){for(x in a())break}"); + test("function f(){while(a())break;}", "function f(){while(a())break}"); + test_same("function f(){for(x in a())break}"); - fold( + test( "function f(){try{return;}catch(e){throw 9;}finally{return}}", "function f(){try{}catch(e){throw 9;}finally{return}}", ); - fold_same("function f(){try{throw 9;}finally{return;}}"); + test_same("function f(){try{throw 9;}finally{return;}}"); - fold("function f(){try{return;}catch(e){return;}}", "function f(){try{}catch(e){}}"); - fold( + test("function f(){try{return;}catch(e){return;}}", "function f(){try{}catch(e){}}"); + test( "function f(){try{if(a()){return;}else{return;} return;}catch(e){}}", "function f(){try{if(a()){}else{}}catch(e){}}", ); - fold("function f(){g:return}", "function f(){}"); - fold( + test("function f(){g:return}", "function f(){}"); + test( "function f(){g:if(a()){return;}else{return;} return;}", "function f(){g:if(a()){}else{}}", ); - fold( + test( "function f(){try{g:if(a()){throw 9;} return;}finally{return}}", "function f(){try{g:if(a()){throw 9;}}finally{return}}", ); @@ -155,7 +143,7 @@ mod test { #[test] fn test_function_return_scoped() { - fold_same( + test_same( "function f(a) { if (a) { const a = Math.random(); @@ -171,49 +159,49 @@ mod test { #[test] #[ignore] fn test_while_continue_optimization() { - fold("while(true){if(x)continue; x=3; continue; }", "while(true)if(x);else x=3"); - fold_same("while(true){a();continue;b();}"); - fold( + test("while(true){if(x)continue; x=3; continue; }", "while(true)if(x);else x=3"); + test_same("while(true){a();continue;b();}"); + test( "while(true){if(true){a();continue;}else;b();}", "while(true){if(true){a();}else{b()}}", ); - fold( + test( "while(true){if(false){a();continue;}else;b();continue;}", "while(true){if(false){a()}else{b();}}", ); - fold( + test( "while(true){if(a()){b();continue;}else;c();}", "while(true){if(a()){b();}else{c();}}", ); - fold( + test( "while(true){if(a()){b();}else{c();continue;}}", "while(true){if(a()){b();}else{c();}}", ); - fold("while(true){if(a()){b();continue;}else;}", "while(true){if(a()){b();}else;}"); - fold( + test("while(true){if(a()){b();continue;}else;}", "while(true){if(a()){b();}else;}"); + test( "while(true){if(a()){continue;}else{continue;} continue;}", "while(true){if(a()){}else{}}", ); - fold( + test( "while(true){if(a()){continue;}else{continue;} b();}", "while(true){if(a()){}else{continue;b();}}", ); - fold("while(true)while(a())continue;", "while(true)while(a());"); - fold("while(true)for(x in a())continue", "while(true)for(x in a());"); + test("while(true)while(a())continue;", "while(true)while(a());"); + test("while(true)for(x in a())continue", "while(true)for(x in a());"); - fold("while(true)while(a())break;", "while(true)while(a())break"); - fold_same("while(true)for(x in a())break"); + test("while(true)while(a())break;", "while(true)while(a())break"); + test_same("while(true)for(x in a())break"); - fold("while(true){try{continue;}catch(e){continue;}}", "while(true){try{}catch(e){}}"); - fold( + test("while(true){try{continue;}catch(e){continue;}}", "while(true){try{}catch(e){}}"); + test( "while(true){try{if(a()){continue;}else{continue;} continue;}catch(e){}}", "while(true){try{if(a()){}else{}}catch(e){}}", ); - fold("while(true){g:continue}", "while(true){}"); + test("while(true){g:continue}", "while(true){}"); // This case could be improved. - fold( + test( "while(true){g:if(a()){continue;}else{continue;} continue;}", "while(true){g:if(a());else;}", ); @@ -222,148 +210,148 @@ mod test { #[test] #[ignore] fn test_do_continue_optimization() { - fold("do{if(x)continue; x=3; continue; }while(true)", "do if(x); else x=3; while(true)"); - fold_same("do{a();continue;b()}while(true)"); - fold( + test("do{if(x)continue; x=3; continue; }while(true)", "do if(x); else x=3; while(true)"); + test_same("do{a();continue;b()}while(true)"); + test( "do{if(true){a();continue;}else;b();}while(true)", "do{if(true){a();}else{b();}}while(true)", ); - fold( + test( "do{if(false){a();continue;}else;b();continue;}while(true)", "do{if(false){a();}else{b();}}while(true)", ); - fold( + test( "do{if(a()){b();continue;}else;c();}while(true)", "do{if(a()){b();}else{c()}}while(true)", ); - fold( + test( "do{if(a()){b();}else{c();continue;}}while(true)", "do{if(a()){b();}else{c();}}while(true)", ); - fold("do{if(a()){b();continue;}else;}while(true)", "do{if(a()){b();}else;}while(true)"); - fold( + test("do{if(a()){b();continue;}else;}while(true)", "do{if(a()){b();}else;}while(true)"); + test( "do{if(a()){continue;}else{continue;} continue;}while(true)", "do{if(a()){}else{}}while(true)", ); - fold( + test( "do{if(a()){continue;}else{continue;} b();}while(true)", "do{if(a()){}else{continue; b();}}while(true)", ); - fold("do{while(a())continue;}while(true)", "do while(a());while(true)"); - fold("do{for(x in a())continue}while(true)", "do for(x in a());while(true)"); + test("do{while(a())continue;}while(true)", "do while(a());while(true)"); + test("do{for(x in a())continue}while(true)", "do for(x in a());while(true)"); - fold("do{while(a())break;}while(true)", "do while(a())break;while(true)"); - fold_same("do for(x in a())break;while(true)"); + test("do{while(a())break;}while(true)", "do while(a())break;while(true)"); + test_same("do for(x in a())break;while(true)"); - fold("do{try{continue;}catch(e){continue;}}while(true)", "do{try{}catch(e){}}while(true)"); - fold( + test("do{try{continue;}catch(e){continue;}}while(true)", "do{try{}catch(e){}}while(true)"); + test( "do{try{if(a()){continue;}else{continue;} continue;}catch(e){}}while(true)", "do{try{if(a()){}else{}}catch(e){}}while(true)", ); - fold("do{g:continue}while(true)", "do{}while(true)"); + test("do{g:continue}while(true)", "do{}while(true)"); // This case could be improved. - fold( + test( "do{g:if(a()){continue;}else{continue;} continue;}while(true)", "do{g:if(a());else;}while(true)", ); - fold("do { foo(); continue; } while(false)", "do { foo(); } while(false)"); - fold("do { foo(); break; } while(false)", "do { foo(); } while(false)"); + test("do { foo(); continue; } while(false)", "do { foo(); } while(false)"); + test("do { foo(); break; } while(false)", "do { foo(); } while(false)"); - fold("do{break}while(!new Date());", "do{}while(!new Date());"); + test("do{break}while(!new Date());", "do{}while(!new Date());"); - fold_same("do { foo(); switch (x) { case 1: break; default: f()}; } while(false)"); + test_same("do { foo(); switch (x) { case 1: break; default: f()}; } while(false)"); } #[test] #[ignore] fn test_for_continue_optimization() { - fold("for(x in y){if(x)continue; x=3; continue; }", "for(x in y)if(x);else x=3"); - fold_same("for(x in y){a();continue;b()}"); - fold("for(x in y){if(true){a();continue;}else;b();}", "for(x in y){if(true)a();else b();}"); - fold( + test("for(x in y){if(x)continue; x=3; continue; }", "for(x in y)if(x);else x=3"); + test_same("for(x in y){a();continue;b()}"); + test("for(x in y){if(true){a();continue;}else;b();}", "for(x in y){if(true)a();else b();}"); + test( "for(x in y){if(false){a();continue;}else;b();continue;}", "for(x in y){if(false){a();}else{b()}}", ); - fold( + test( "for(x in y){if(a()){b();continue;}else;c();}", "for(x in y){if(a()){b();}else{c();}}", ); - fold( + test( "for(x in y){if(a()){b();}else{c();continue;}}", "for(x in y){if(a()){b();}else{c();}}", ); - fold("for(x of y){if(x)continue; x=3; continue; }", "for(x of y)if(x);else x=3"); - fold_same("for(x of y){a();continue;b()}"); - fold("for(x of y){if(true){a();continue;}else;b();}", "for(x of y){if(true)a();else b();}"); - fold( + test("for(x of y){if(x)continue; x=3; continue; }", "for(x of y)if(x);else x=3"); + test_same("for(x of y){a();continue;b()}"); + test("for(x of y){if(true){a();continue;}else;b();}", "for(x of y){if(true)a();else b();}"); + test( "for(x of y){if(false){a();continue;}else;b();continue;}", "for(x of y){if(false){a();}else{b()}}", ); - fold( + test( "for(x of y){if(a()){b();continue;}else;c();}", "for(x of y){if(a()){b();}else{c();}}", ); - fold( + test( "for(x of y){if(a()){b();}else{c();continue;}}", "for(x of y){if(a()){b();}else{c();}}", ); - fold( + test( "async () => { for await (x of y){if(x)continue; x=3; continue; }}", "async () => { for await (x of y)if(x);else x=3 }", ); - fold_same("async () => { for await (x of y){a();continue;b()}}"); - fold( + test_same("async () => { for await (x of y){a();continue;b()}}"); + test( "async () => { for await (x of y){if(true){a();continue;}else;b();}}", "async () => { for await (x of y){if(true)a();else b();}}", ); - fold( + test( "async () => { for await (x of y){if(false){a();continue;}else;b();continue;}}", "async () => { for await (x of y){if(false){a();}else{b()}}}", ); - fold( + test( "async () => { for await (x of y){if(a()){b();continue;}else;c();}}", "async () => { for await (x of y){if(a()){b();}else{c();}}}", ); - fold( + test( "async () => { for await (x of y){if(a()){b();}else{c();continue;}}}", "async () => { for await (x of y){if(a()){b();}else{c();}}}", ); - fold( + test( "for(x=0;x a; }", "function f() { if (x) {} else { var a = 3; var b = () => a;} }", ); - fold( + test( "function f() { if (x) { if (y) {return;} let c = 3; } }", "function f() { if (x) { if (y) {} else { var c = 3; } } }", ); @@ -441,11 +429,11 @@ mod test { #[test] #[ignore] - fn test_dont_fold_block_scoped_variables_in_loops() { + fn test_dont_test_block_scoped_variables_in_loops() { // Don't move block-scoped declarations into inner blocks inside a loop, since converting // let/const declarations to vars in a loop can cause incorrect semantics. // See the following test case for an example. - fold_same( + test_same( "function f(param) { let arr = []; for (let x of param) { @@ -458,10 +446,10 @@ mod test { ); // Additional tests for different kinds of loops. - fold_same("function f() { while (true) { if (true) {return;} let c = 3; } }"); - fold_same("function f() { do { if (true) {return;} let c = 3; } while (x); }"); - fold_same("function f() { for (;;) { if (true) { return; } let c = 3; } }"); - fold_same("function f(y) { for(x in []){ if(x) { return; } let c = 3; } }"); - fold_same("async function f(y) { for await (x in []){ if(x) { return; } let c = 3; } }"); + test_same("function f() { while (true) { if (true) {return;} let c = 3; } }"); + test_same("function f() { do { if (true) {return;} let c = 3; } while (x); }"); + test_same("function f() { for (;;) { if (true) { return; } let c = 3; } }"); + test_same("function f(y) { for(x in []){ if(x) { return; } let c = 3; } }"); + test_same("async function f(y) { for await (x in []){ if(x) { return; } let c = 3; } }"); } } diff --git a/crates/oxc_minifier/src/ast_passes/normalize.rs b/crates/oxc_minifier/src/ast_passes/normalize.rs index a8e847a2a30bc0..0c52fbbd3d8cad 100644 --- a/crates/oxc_minifier/src/ast_passes/normalize.rs +++ b/crates/oxc_minifier/src/ast_passes/normalize.rs @@ -175,22 +175,7 @@ impl<'a> Normalize { #[cfg(test)] mod test { - use oxc_allocator::Allocator; - - use super::NormalizeOptions; - use crate::{tester, CompressOptions}; - - fn test(source_text: &str, expected: &str) { - let allocator = Allocator::default(); - let compress_options = CompressOptions { - drop_debugger: true, - drop_console: true, - ..CompressOptions::default() - }; - let options = NormalizeOptions { convert_while_to_fors: true }; - let mut pass = super::Normalize::new(options, compress_options); - tester::test(&allocator, source_text, expected, &mut pass); - } + use crate::tester::test; #[test] fn test_while() { diff --git a/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs b/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs index cc7c8d0ff649af..515f93d6fdfc20 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs @@ -726,25 +726,13 @@ impl<'a, 'b> PeepholeFoldConstants { /// #[cfg(test)] mod test { - use oxc_allocator::Allocator; - static MAX_SAFE_FLOAT: f64 = 9_007_199_254_740_991_f64; static NEG_MAX_SAFE_FLOAT: f64 = -9_007_199_254_740_991_f64; static MAX_SAFE_INT: i64 = 9_007_199_254_740_991_i64; static NEG_MAX_SAFE_INT: i64 = -9_007_199_254_740_991_i64; - use crate::tester; - - fn test(source_text: &str, expected: &str) { - let allocator = Allocator::default(); - let mut pass = super::PeepholeFoldConstants::new(); - tester::test(&allocator, source_text, expected, &mut pass); - } - - fn test_same(source_text: &str) { - test(source_text, source_text); - } + use crate::tester::{test, test_same}; #[test] fn test_comparison() { diff --git a/crates/oxc_minifier/src/ast_passes/peephole_minimize_conditions.rs b/crates/oxc_minifier/src/ast_passes/peephole_minimize_conditions.rs index 585b1f9e32a278..1c6d3fb9f63457 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_minimize_conditions.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_minimize_conditions.rs @@ -860,106 +860,85 @@ impl<'a> PeepholeMinimizeConditions { /// #[cfg(test)] mod test { - use oxc_allocator::Allocator; - use oxc_syntax::es_target::ESTarget; - - use crate::tester; - - fn test(source_text: &str, positive: &str) { - let allocator = Allocator::default(); - let mut pass = super::PeepholeMinimizeConditions::new(ESTarget::ES2025); - tester::test(&allocator, source_text, positive, &mut pass); - } - - fn test_same(source_text: &str) { - test(source_text, source_text); - } - - fn fold_same(js: &str) { - test_same(js); - } - - fn fold(js: &str, expected: &str) { - test(js, expected); - } + use crate::tester::{test, test_same}; /** Check that removing blocks with 1 child works */ #[test] fn test_fold_one_child_blocks() { // late = false; - fold("function f(){if(x)a();x=3}", "function f(){x&&a();x=3}"); - fold("function f(){if(x)a?.();x=3}", "function f(){x&&a?.();x=3}"); + test("function f(){if(x)a();x=3}", "function f(){x&&a();x=3}"); + test("function f(){if(x)a?.();x=3}", "function f(){x&&a?.();x=3}"); - fold("function f(){if(x){a()}x=3}", "function f(){x&&a();x=3}"); - fold("function f(){if(x){a?.()}x=3}", "function f(){x&&a?.();x=3}"); + test("function f(){if(x){a()}x=3}", "function f(){x&&a();x=3}"); + test("function f(){if(x){a?.()}x=3}", "function f(){x&&a?.();x=3}"); - // fold("function f(){if(x){return 3}}", "function f(){if(x)return 3}"); - fold("function f(){if(x){a()}}", "function f(){x&&a()}"); - // fold("function f(){if(x){throw 1}}", "function f(){if(x)throw 1;}"); + // test("function f(){if(x){return 3}}", "function f(){if(x)return 3}"); + test("function f(){if(x){a()}}", "function f(){x&&a()}"); + // test("function f(){if(x){throw 1}}", "function f(){if(x)throw 1;}"); // Try it out with functions - fold("function f(){if(x){foo()}}", "function f(){x&&foo()}"); - fold("function f(){if(x){foo()}else{bar()}}", "function f(){x?foo():bar()}"); + test("function f(){if(x){foo()}}", "function f(){x&&foo()}"); + test("function f(){if(x){foo()}else{bar()}}", "function f(){x?foo():bar()}"); // Try it out with properties and methods - fold("function f(){if(x){a.b=1}}", "function f(){x&&(a.b=1)}"); - fold("function f(){if(x){a.b*=1}}", "function f(){x&&(a.b*=1)}"); - fold("function f(){if(x){a.b+=1}}", "function f(){x&&(a.b+=1)}"); - fold("function f(){if(x){++a.b}}", "function f(){x&&++a.b}"); - fold("function f(){if(x){a.foo()}}", "function f(){x&&a.foo()}"); - fold("function f(){if(x){a?.foo()}}", "function f(){x&&a?.foo()}"); + test("function f(){if(x){a.b=1}}", "function f(){x&&(a.b=1)}"); + test("function f(){if(x){a.b*=1}}", "function f(){x&&(a.b*=1)}"); + test("function f(){if(x){a.b+=1}}", "function f(){x&&(a.b+=1)}"); + test("function f(){if(x){++a.b}}", "function f(){x&&++a.b}"); + test("function f(){if(x){a.foo()}}", "function f(){x&&a.foo()}"); + test("function f(){if(x){a?.foo()}}", "function f(){x&&a?.foo()}"); // Try it out with throw/catch/finally [which should not change] - fold_same("function f(){try{foo()}catch(e){bar(e)}finally{baz()}}"); + test_same("function f(){try{foo()}catch(e){bar(e)}finally{baz()}}"); // Try it out with switch statements - fold_same("function f(){switch(x){case 1:break}}"); + test_same("function f(){switch(x){case 1:break}}"); // Do while loops stay in a block if that's where they started - fold_same("function f(){if(e1){do foo();while(e2)}else foo2()}"); + test_same("function f(){if(e1){do foo();while(e2)}else foo2()}"); // Test an obscure case with do and while - // fold("if(x){do{foo()}while(y)}else bar()", "if(x){do foo();while(y)}else bar()"); + // test("if(x){do{foo()}while(y)}else bar()", "if(x){do foo();while(y)}else bar()"); // Play with nested IFs - fold("function f(){if(x){if(y)foo()}}", "function f(){x && (y && foo())}"); - fold("function f(){if(x){if(y)foo();else bar()}}", "function f(){x&&(y?foo():bar())}"); - fold("function f(){if(x){if(y)foo()}else bar()}", "function f(){x?y&&foo():bar()}"); - fold( + test("function f(){if(x){if(y)foo()}}", "function f(){x && (y && foo())}"); + test("function f(){if(x){if(y)foo();else bar()}}", "function f(){x&&(y?foo():bar())}"); + test("function f(){if(x){if(y)foo()}else bar()}", "function f(){x?y&&foo():bar()}"); + test( "function f(){if(x){if(y)foo();else bar()}else{baz()}}", "function f(){x?y?foo():bar():baz()}", ); - // fold("if(e1){while(e2){if(e3){foo()}}}else{bar()}", "if(e1)while(e2)e3&&foo();else bar()"); + // test("if(e1){while(e2){if(e3){foo()}}}else{bar()}", "if(e1)while(e2)e3&&foo();else bar()"); - // fold("if(e1){with(e2){if(e3){foo()}}}else{bar()}", "if(e1)with(e2)e3&&foo();else bar()"); + // test("if(e1){with(e2){if(e3){foo()}}}else{bar()}", "if(e1)with(e2)e3&&foo();else bar()"); - // fold("if(a||b){if(c||d){var x;}}", "if(a||b)if(c||d)var x"); - // fold("if(x){ if(y){var x;}else{var z;} }", "if(x)if(y)var x;else var z"); + // test("if(a||b){if(c||d){var x;}}", "if(a||b)if(c||d)var x"); + // test("if(x){ if(y){var x;}else{var z;} }", "if(x)if(y)var x;else var z"); // NOTE - technically we can remove the blocks since both the parent // and child have elses. But we don't since it causes ambiguities in // some cases where not all descendent ifs having elses - // fold( + // test( // "if(x){ if(y){var x;}else{var z;} }else{var w}", // "if(x)if(y)var x;else var z;else var w", // ); - // fold("if (x) {var x;}else { if (y) { var y;} }", "if(x)var x;else if(y)var y"); + // test("if (x) {var x;}else { if (y) { var y;} }", "if(x)var x;else if(y)var y"); // Here's some of the ambiguous cases - // fold( + // test( // "if(a){if(b){f1();f2();}else if(c){f3();}}else {if(d){f4();}}", // "if(a)if(b){f1();f2()}else c&&f3();else d&&f4()", // ); - fold_same("function f(){foo()}"); - fold_same("switch(x){case y: foo()}"); - fold_same("try{foo()}catch(ex){bar()}finally{baz()}"); + test_same("function f(){foo()}"); + test_same("switch(x){case y: foo()}"); + test_same("try{foo()}catch(ex){bar()}finally{baz()}"); // Dot not fold `let` and `const`. // Lexical declaration cannot appear in a single-statement context. - fold_same("if (foo) { const bar = 1 } else { const baz = 1 }"); - fold_same("if (foo) { let bar = 1 } else { let baz = 1 }"); - // fold( + test_same("if (foo) { const bar = 1 } else { const baz = 1 }"); + test_same("if (foo) { let bar = 1 } else { let baz = 1 }"); + // test( // "if (foo) { var bar = 1 } else { var baz = 1 }", // "if (foo) var bar = 1; else var baz = 1;", // ); @@ -967,32 +946,32 @@ mod test { #[test] fn test_fold_returns() { - fold("function f(){if(x)return 1;else return 2}", "function f(){return x?1:2}"); - fold("function f(){if(x)return 1;return 2}", "function f(){return x?1:2}"); - fold("function f(){if(x)return;return 2}", "function f(){return x?void 0:2}"); - fold("function f(){if(x)return 1+x;else return 2-x}", "function f(){return x?1+x:2-x}"); - fold("function f(){if(x)return 1+x;return 2-x}", "function f(){return x?1+x:2-x}"); - fold( + test("function f(){if(x)return 1;else return 2}", "function f(){return x?1:2}"); + test("function f(){if(x)return 1;return 2}", "function f(){return x?1:2}"); + test("function f(){if(x)return;return 2}", "function f(){return x?void 0:2}"); + test("function f(){if(x)return 1+x;else return 2-x}", "function f(){return x?1+x:2-x}"); + test("function f(){if(x)return 1+x;return 2-x}", "function f(){return x?1+x:2-x}"); + test( "function f(){if(x)return y += 1;else return y += 2}", "function f(){return x?(y+=1):(y+=2)}", ); - fold("function f(){if(x)return;else return 2-x}", "function f(){return x?void 0:2-x}"); - fold("function f(){if(x)return;return 2-x}", "function f(){return x?void 0:2-x}"); - fold("function f(){if(x)return x;else return}", "function f(){if(x)return x;return;}"); - fold("function f(){if(x)return x;return}", "function f(){if(x)return x;return}"); + test("function f(){if(x)return;else return 2-x}", "function f(){return x?void 0:2-x}"); + test("function f(){if(x)return;return 2-x}", "function f(){return x?void 0:2-x}"); + test("function f(){if(x)return x;else return}", "function f(){if(x)return x;return;}"); + test("function f(){if(x)return x;return}", "function f(){if(x)return x;return}"); - fold_same("function f(){for(var x in y) { return x.y; } return k}"); + test_same("function f(){for(var x in y) { return x.y; } return k}"); } #[test] #[ignore] fn test_combine_ifs1() { - fold( + test( "function f() {if (x) return 1; if (y) return 1}", "function f() {if (x||y) return 1;}", ); - fold( + test( "function f() {if (x) return 1; if (y) foo(); else return 1}", "function f() {if ((!x)&&y) foo(); else return 1;}", ); @@ -1002,12 +981,12 @@ mod test { #[ignore] fn test_combine_ifs2() { // combinable but not yet done - fold_same("function f() {if (x) throw 1; if (y) throw 1}"); + test_same("function f() {if (x) throw 1; if (y) throw 1}"); // Can't combine, side-effect - fold("function f(){ if (x) g(); if (y) g() }", "function f(){ x&&g(); y&&g() }"); - fold("function f(){ if (x) g?.(); if (y) g?.() }", "function f(){ x&&g?.(); y&&g?.() }"); + test("function f(){ if (x) g(); if (y) g() }", "function f(){ x&&g(); y&&g() }"); + test("function f(){ if (x) g?.(); if (y) g?.() }", "function f(){ x&&g?.(); y&&g?.() }"); // Can't combine, side-effect - fold( + test( "function f(){ if (x) y = 0; if (y) y = 0; }", "function f(){ x&&(y = 0); y&&(y = 0); }", ); @@ -1016,30 +995,30 @@ mod test { #[test] #[ignore] fn test_combine_ifs3() { - fold_same("function f() {if (x) return 1; if (y) {g();f()}}"); + test_same("function f() {if (x) return 1; if (y) {g();f()}}"); } /** Try to minimize assignments */ #[test] #[ignore] fn test_fold_assignments() { - fold("function f(){if(x)y=3;else y=4;}", "function f(){y=x?3:4}"); - fold("function f(){if(x)y=1+a;else y=2+a;}", "function f(){y=x?1+a:2+a}"); + test("function f(){if(x)y=3;else y=4;}", "function f(){y=x?3:4}"); + test("function f(){if(x)y=1+a;else y=2+a;}", "function f(){y=x?1+a:2+a}"); // and operation assignments - fold("function f(){if(x)y+=1;else y+=2;}", "function f(){y+=x?1:2}"); - fold("function f(){if(x)y-=1;else y-=2;}", "function f(){y-=x?1:2}"); - fold("function f(){if(x)y%=1;else y%=2;}", "function f(){y%=x?1:2}"); - fold("function f(){if(x)y|=1;else y|=2;}", "function f(){y|=x?1:2}"); + test("function f(){if(x)y+=1;else y+=2;}", "function f(){y+=x?1:2}"); + test("function f(){if(x)y-=1;else y-=2;}", "function f(){y-=x?1:2}"); + test("function f(){if(x)y%=1;else y%=2;}", "function f(){y%=x?1:2}"); + test("function f(){if(x)y|=1;else y|=2;}", "function f(){y|=x?1:2}"); // Don't fold if the 2 ops don't match. - fold_same("function f(){x ? y-=1 : y+=2}"); + test_same("function f(){x ? y-=1 : y+=2}"); // Don't fold if the 2 LHS don't match. - fold_same("function f(){x ? y-=1 : z-=1}"); + test_same("function f(){x ? y-=1 : z-=1}"); // Don't fold if there are potential effects. - fold_same("function f(){x ? y().a=3 : y().a=4}"); + test_same("function f(){x ? y().a=3 : y().a=4}"); } #[test] @@ -1048,19 +1027,19 @@ mod test { // enableNormalize(); // TODO(bradfordcsmith): Stop normalizing the expected output or document why it is necessary. // enableNormalizeExpectedOutput(); - fold("if (a) { x = 1; x++ } else { x = 2; x++ }", "x=(a) ? 1 : 2; x++"); - fold( + test("if (a) { x = 1; x++ } else { x = 2; x++ }", "x=(a) ? 1 : 2; x++"); + test( concat!( "if (a) { x = 1; x++; y += 1; z = pi; }", " else { x = 2; x++; y += 1; z = pi; }" ), "x=(a) ? 1 : 2; x++; y += 1; z = pi;", ); - fold( + test( concat!("function z() {", "if (a) { foo(); return !0 } else { goo(); return !0 }", "}"), "function z() {(a) ? foo() : goo(); return !0}", ); - fold( + test( concat!( "function z() {if (a) { foo(); x = true; return true ", "} else { goo(); x = true; return true }}" @@ -1068,7 +1047,7 @@ mod test { "function z() {(a) ? foo() : goo(); x = true; return true}", ); - fold( + test( concat!( "function z() {", " if (a) { bar(); foo(); return true }", @@ -1108,20 +1087,20 @@ mod test { #[test] fn test_not_cond() { - fold("function f(){if(!x)foo()}", "function f(){x||foo()}"); - fold("function f(){if(!x)b=1}", "function f(){x||(b=1)}"); - // fold("if(!x)z=1;else if(y)z=2", "x ? y&&(z=2) : z=1;"); - // fold("if(x)y&&(z=2);else z=1;", "x ? y&&(z=2) : z=1"); - fold("function f(){if(!(x=1))a.b=1}", "function f(){(x=1)||(a.b=1)}"); + test("function f(){if(!x)foo()}", "function f(){x||foo()}"); + test("function f(){if(!x)b=1}", "function f(){x||(b=1)}"); + // test("if(!x)z=1;else if(y)z=2", "x ? y&&(z=2) : z=1;"); + // test("if(x)y&&(z=2);else z=1;", "x ? y&&(z=2) : z=1"); + test("function f(){if(!(x=1))a.b=1}", "function f(){(x=1)||(a.b=1)}"); } #[test] #[ignore] fn test_and_parentheses_count() { - fold("function f(){if(x||y)a.foo()}", "function f(){(x||y)&&a.foo()}"); - fold("function f(){if(x.a)x.a=0}", "function f(){x.a&&(x.a=0)}"); - fold("function f(){if(x?.a)x.a=0}", "function f(){x?.a&&(x.a=0)}"); - fold_same("function f(){if(x()||y()){x()||y()}}"); + test("function f(){if(x||y)a.foo()}", "function f(){(x||y)&&a.foo()}"); + test("function f(){if(x.a)x.a=0}", "function f(){x.a&&(x.a=0)}"); + test("function f(){if(x?.a)x.a=0}", "function f(){x?.a&&(x.a=0)}"); + test_same("function f(){if(x()||y()){x()||y()}}"); } #[test] @@ -1129,62 +1108,62 @@ mod test { fn test_fold_logical_op_string_compare() { // side-effects // There is two way to parse two &&'s and both are correct. - fold("if (foo() && false) z()", "(foo(), 0) && z()"); + test("if (foo() && false) z()", "(foo(), 0) && z()"); } #[test] #[ignore] fn test_fold_not() { - fold("while(!(x==y)){a=b;}", "while(x!=y){a=b;}"); - fold("while(!(x!=y)){a=b;}", "while(x==y){a=b;}"); - fold("while(!(x===y)){a=b;}", "while(x!==y){a=b;}"); - fold("while(!(x!==y)){a=b;}", "while(x===y){a=b;}"); + test("while(!(x==y)){a=b;}", "while(x!=y){a=b;}"); + test("while(!(x!=y)){a=b;}", "while(x==y){a=b;}"); + test("while(!(x===y)){a=b;}", "while(x!==y){a=b;}"); + test("while(!(x!==y)){a=b;}", "while(x===y){a=b;}"); // Because !(x=NaN don't fold < and > cases. - fold_same("while(!(x>y)){a=b;}"); - fold_same("while(!(x>=y)){a=b;}"); - fold_same("while(!(xy)){a=b;}"); + test_same("while(!(x>=y)){a=b;}"); + test_same("while(!(x !!x;"); } @@ -1193,69 +1172,69 @@ mod test { #[ignore] fn test_minimize_while_condition() { // This test uses constant folding logic, so is only here for completeness. - fold("while(!!true) foo()", "while(1) foo()"); + test("while(!!true) foo()", "while(1) foo()"); // These test tryMinimizeCondition - fold("while(!!x) foo()", "while(x) foo()"); - fold("while(!(!x&&!y)) foo()", "while(x||y) foo()"); - fold("while(x||!!y) foo()", "while(x||y) foo()"); - fold("while(!(!!x&&y)) foo()", "while(!x||!y) foo()"); - fold("while(!(!x&&y)) foo()", "while(x||!y) foo()"); - fold("while(!(x||!y)) foo()", "while(!x&&y) foo()"); - fold("while(!(x||y)) foo()", "while(!x&&!y) foo()"); - fold("while(!(!x||y-z)) foo()", "while(x&&!(y-z)) foo()"); - fold("while(!(!(x/y)||z+w)) foo()", "while(x/y&&!(z+w)) foo()"); - fold_same("while(!(x+y||z)) foo()"); - fold_same("while(!(x&&y*z)) foo()"); - fold("while(!(!!x&&y)) foo()", "while(!x||!y) foo()"); - fold("while(x&&!0) foo()", "while(x) foo()"); - fold("while(x||!1) foo()", "while(x) foo()"); - fold("while(!((x,y)&&z)) foo()", "while((x,!y)||!z) foo()"); + test("while(!!x) foo()", "while(x) foo()"); + test("while(!(!x&&!y)) foo()", "while(x||y) foo()"); + test("while(x||!!y) foo()", "while(x||y) foo()"); + test("while(!(!!x&&y)) foo()", "while(!x||!y) foo()"); + test("while(!(!x&&y)) foo()", "while(x||!y) foo()"); + test("while(!(x||!y)) foo()", "while(!x&&y) foo()"); + test("while(!(x||y)) foo()", "while(!x&&!y) foo()"); + test("while(!(!x||y-z)) foo()", "while(x&&!(y-z)) foo()"); + test("while(!(!(x/y)||z+w)) foo()", "while(x/y&&!(z+w)) foo()"); + test_same("while(!(x+y||z)) foo()"); + test_same("while(!(x&&y*z)) foo()"); + test("while(!(!!x&&y)) foo()", "while(!x||!y) foo()"); + test("while(x&&!0) foo()", "while(x) foo()"); + test("while(x||!1) foo()", "while(x) foo()"); + test("while(!((x,y)&&z)) foo()", "while((x,!y)||!z) foo()"); } #[test] #[ignore] fn test_minimize_demorgan_remove_leading_not() { - fold("if(!(!a||!b)&&c) foo()", "((a&&b)&&c)&&foo()"); - fold("if(!(x&&y)) foo()", "x&&y||foo()"); - fold("if(!(x||y)) foo()", "(x||y)||foo()"); + test("if(!(!a||!b)&&c) foo()", "((a&&b)&&c)&&foo()"); + test("if(!(x&&y)) foo()", "x&&y||foo()"); + test("if(!(x||y)) foo()", "(x||y)||foo()"); } #[test] #[ignore] fn test_minimize_demorgan1() { - fold("if(!a&&!b)foo()", "(a||b)||foo()"); + test("if(!a&&!b)foo()", "(a||b)||foo()"); } #[test] #[ignore] fn test_minimize_demorgan2() { // Make sure trees with cloned functions are marked as changed - fold("(!(a&&!((function(){})())))||foo()", "!a||(function(){})()||foo()"); + test("(!(a&&!((function(){})())))||foo()", "!a||(function(){})()||foo()"); } #[test] #[ignore] fn test_minimize_demorgan2b() { // Make sure unchanged trees with functions are not marked as changed - fold_same("!a||(function(){})()||foo()"); + test_same("!a||(function(){})()||foo()"); } #[test] #[ignore] fn test_minimize_demorgan3() { - fold("if((!a||!b)&&(c||d)) foo()", "(a&&b||!c&&!d)||foo()"); + test("if((!a||!b)&&(c||d)) foo()", "(a&&b||!c&&!d)||foo()"); } #[test] #[ignore] fn test_minimize_demorgan5() { - fold("if((!a||!b)&&c) foo()", "(a&&b||!c)||foo()"); + test("if((!a||!b)&&c) foo()", "(a&&b||!c)||foo()"); } #[test] #[ignore] fn test_minimize_demorgan11() { - fold( + test( "if (x && (y===2 || !f()) && (y===3 || !h())) foo()", "(!x || y!==2 && f() || y!==3 && h()) || foo()", ); @@ -1264,7 +1243,7 @@ mod test { #[test] #[ignore] fn test_minimize_demorgan20a() { - fold( + test( "if (0===c && (2===a || 1===a)) f(); else g()", "if (0!==c || 2!==a && 1!==a) g(); else f()", ); @@ -1273,109 +1252,109 @@ mod test { #[test] #[ignore] fn test_minimize_demorgan20b() { - fold("if (0!==c || 2!==a && 1!==a) g(); else f()", "(0!==c || 2!==a && 1!==a) ? g() : f()"); + test("if (0!==c || 2!==a && 1!==a) g(); else f()", "(0!==c || 2!==a && 1!==a) ? g() : f()"); } #[test] fn test_preserve_if() { - fold_same("if(!a&&!b)for(;f(););"); + test_same("if(!a&&!b)for(;f(););"); } #[test] fn test_no_swap_with_dangling_else() { - fold_same("if(!x) {for(;;)foo(); for(;;)bar()} else if(y) for(;;) f()"); - fold_same("if(!a&&!b) {for(;;)foo(); for(;;)bar()} else if(y) for(;;) f()"); + test_same("if(!x) {for(;;)foo(); for(;;)bar()} else if(y) for(;;) f()"); + test_same("if(!a&&!b) {for(;;)foo(); for(;;)bar()} else if(y) for(;;) f()"); } #[test] fn test_minimize_hook() { - fold("x ? x : y", "x || y"); - fold_same("x.y ? x.y : x.z"); - fold_same("x?.y ? x?.y : x.z"); - fold_same("x?.y ? x?.y : x?.z"); + test("x ? x : y", "x || y"); + test_same("x.y ? x.y : x.z"); + test_same("x?.y ? x?.y : x.z"); + test_same("x?.y ? x?.y : x?.z"); - fold_same("x() ? x() : y()"); - fold_same("x?.() ? x?.() : y()"); + test_same("x() ? x() : y()"); + test_same("x?.() ? x?.() : y()"); - fold("!x ? foo() : bar()", "x ? bar() : foo()"); + test("!x ? foo() : bar()", "x ? bar() : foo()"); // TODO - // fold("while(!(x ? y : z)) foo();", "while(x ? !y : !z) foo();"); - // fold("(x ? !y : !z) ? foo() : bar()", "(x ? y : z) ? bar() : foo()"); + // test("while(!(x ? y : z)) foo();", "while(x ? !y : !z) foo();"); + // test("(x ? !y : !z) ? foo() : bar()", "(x ? y : z) ? bar() : foo()"); } #[test] #[ignore] fn test_minimize_comma() { - fold("while(!(inc(), test())) foo();", "while(inc(), !test()) foo();"); - fold("(inc(), !test()) ? foo() : bar()", "(inc(), test()) ? bar() : foo()"); + test("while(!(inc(), test())) foo();", "while(inc(), !test()) foo();"); + test("(inc(), !test()) ? foo() : bar()", "(inc(), test()) ? bar() : foo()"); } #[test] #[ignore] fn test_minimize_expr_result() { - fold("!x||!y", "x&&y"); - fold("if(!(x&&!y)) foo()", "(!x||y)&&foo()"); - fold("if(!x||y) foo()", "(!x||y)&&foo()"); - fold("(!x||y)&&foo()", "x&&!y||!foo()"); + test("!x||!y", "x&&y"); + test("if(!(x&&!y)) foo()", "(!x||y)&&foo()"); + test("if(!x||y) foo()", "(!x||y)&&foo()"); + test("(!x||y)&&foo()", "x&&!y||!foo()"); } #[test] #[ignore] fn test_minimize_demorgan21() { - fold("if (0===c && (2===a || 1===a)) f()", "(0!==c || 2!==a && 1!==a) || f()"); + test("if (0===c && (2===a || 1===a)) f()", "(0!==c || 2!==a && 1!==a) || f()"); } #[test] #[ignore] fn test_minimize_and_or1() { - fold("if ((!a || !b) && (d || e)) f()", "(a&&b || !d&&!e) || f()"); + test("if ((!a || !b) && (d || e)) f()", "(a&&b || !d&&!e) || f()"); } #[test] fn test_minimize_for_condition() { // This test uses constant folding logic, so is only here for completeness. // These could be simplified to "for(;;) ..." - fold("for(;!!true;) foo()", "for(;true;) foo()"); + test("for(;!!true;) foo()", "for(;true;) foo()"); // Verify function deletion tracking. - // fold("if(!!true||function(){}) {}", "if(1) {}"); + // test("if(!!true||function(){}) {}", "if(1) {}"); // Don't bother with FOR inits as there are normalized out. - fold("for(!!true;;) foo()", "for(true;;) foo()"); + test("for(!!true;;) foo()", "for(true;;) foo()"); // These test tryMinimizeCondition - fold("for(;!!x;) foo()", "for(;x;) foo()"); + test("for(;!!x;) foo()", "for(;x;) foo()"); - fold_same("for(a in b) foo()"); - fold_same("for(a in {}) foo()"); - fold_same("for(a in []) foo()"); - fold("for(a in !!true) foo()", "for(a in true) foo()"); + test_same("for(a in b) foo()"); + test_same("for(a in {}) foo()"); + test_same("for(a in []) foo()"); + test("for(a in !!true) foo()", "for(a in true) foo()"); - fold_same("for(a of b) foo()"); - fold_same("for(a of {}) foo()"); - fold_same("for(a of []) foo()"); - fold("for(a of !!true) foo()", "for(a of true) foo()"); + test_same("for(a of b) foo()"); + test_same("for(a of {}) foo()"); + test_same("for(a of []) foo()"); + test("for(a of !!true) foo()", "for(a of true) foo()"); } #[test] fn test_minimize_condition_example1() { // Based on a real failing code sample. - fold("if(!!(f() > 20)) {foo();foo()}", "if(f() > 20){foo();foo()}"); + test("if(!!(f() > 20)) {foo();foo()}", "if(f() > 20){foo();foo()}"); } #[test] #[ignore] fn test_fold_loop_break_late() { // late = true; - fold("for(;;) if (a) break", "for(;!a;);"); - fold_same("for(;;) if (a) { f(); break }"); - fold("for(;;) if (a) break; else f()", "for(;!a;) { { f(); } }"); - fold("for(;a;) if (b) break", "for(;a && !b;);"); - fold("for(;a;) { if (b) break; if (c) break; }", "for(;(a && !b);) if (c) break;"); - fold("for(;(a && !b);) if (c) break;", "for(;(a && !b) && !c;);"); - fold("for(;;) { if (foo) { break; var x; } } x;", "var x; for(;!foo;) {} x;"); + test("for(;;) if (a) break", "for(;!a;);"); + test_same("for(;;) if (a) { f(); break }"); + test("for(;;) if (a) break; else f()", "for(;!a;) { { f(); } }"); + test("for(;a;) if (b) break", "for(;a && !b;);"); + test("for(;a;) { if (b) break; if (c) break; }", "for(;(a && !b);) if (c) break;"); + test("for(;(a && !b);) if (c) break;", "for(;(a && !b) && !c;);"); + test("for(;;) { if (foo) { break; var x; } } x;", "var x; for(;!foo;) {} x;"); // 'while' is normalized to 'for' // enableNormalize(); - fold("while(true) if (a) break", "for(;1&&!a;);"); + test("while(true) if (a) break", "for(;1&&!a;);"); // disableNormalize(); } @@ -1383,36 +1362,36 @@ mod test { #[ignore] fn test_fold_loop_break_early() { // late = false; - fold_same("for(;;) if (a) break"); - fold_same("for(;;) if (a) { f(); break }"); - fold_same("for(;;) if (a) break; else f()"); - fold_same("for(;a;) if (b) break"); - fold_same("for(;a;) { if (b) break; if (c) break; }"); + test_same("for(;;) if (a) break"); + test_same("for(;;) if (a) { f(); break }"); + test_same("for(;;) if (a) break; else f()"); + test_same("for(;a;) if (b) break"); + test_same("for(;a;) { if (b) break; if (c) break; }"); - fold_same("while(1) if (a) break"); + test_same("while(1) if (a) break"); // enableNormalize(); - fold_same("for (; 1; ) if (a) break"); + test_same("for (; 1; ) if (a) break"); } #[test] #[ignore] fn test_fold_conditional_var_declaration() { - fold("if(x) var y=1;else y=2", "var y=x?1:2"); - fold("if(x) y=1;else var y=2", "var y=x?1:2"); + test("if(x) var y=1;else y=2", "var y=x?1:2"); + test("if(x) y=1;else var y=2", "var y=x?1:2"); - fold_same("if(x) var y = 1; z = 2"); - fold_same("if(x||y) y = 1; var z = 2"); + test_same("if(x) var y = 1; z = 2"); + test_same("if(x||y) y = 1; var z = 2"); - fold_same("if(x) { var y = 1; print(y)} else y = 2 "); - fold_same("if(x) var y = 1; else {y = 2; print(y)}"); + test_same("if(x) { var y = 1; print(y)} else y = 2 "); + test_same("if(x) var y = 1; else {y = 2; print(y)}"); } #[test] #[ignore] fn test_fold_if_with_lower_operators_inside() { - fold("if (x + (y=5)) z && (w,z);", "x + (y=5) && (z && (w,z))"); - fold("if (!(x+(y=5))) z && (w,z);", "x + (y=5) || z && (w,z)"); - fold( + test("if (x + (y=5)) z && (w,z);", "x + (y=5) && (z && (w,z))"); + test("if (!(x+(y=5))) z && (w,z);", "x + (y=5) || z && (w,z)"); + test( "if (x + (y=5)) if (z && (w,z)) for(;;) foo();", "if (x + (y=5) && (z && (w,z))) for(;;) foo();", ); @@ -1426,66 +1405,66 @@ mod test { // TODO(bradfordcsmith): Stop normalizing the expected output or document why it is necessary. // enableNormalizeExpectedOutput(); - fold("function f() { while(x) { return }}", "function f() { while(x) { break }}"); + test("function f() { while(x) { return }}", "function f() { while(x) { break }}"); - fold_same("function f() { while(x) { return 5 } }"); + test_same("function f() { while(x) { return 5 } }"); - fold_same("function f() { a: { return 5 } }"); + test_same("function f() { a: { return 5 } }"); - fold( + test( "function f() { while(x) { return 5} return 5}", "function f() { while(x) { break } return 5}", ); - fold( + test( "function f() { while(x) { return x} return x}", "function f() { while(x) { break } return x}", ); - fold( + test( "function f() { while(x) { if (y) { return }}}", "function f() { while(x) { if (y) { break }}}", ); - fold( + test( "function f() { while(x) { if (y) { return }} return}", "function f() { while(x) { if (y) { break }}}", ); - fold( + test( "function f() { while(x) { if (y) { return 5 }} return 5}", "function f() { while(x) { if (y) { break }} return 5}", ); // It doesn't matter if x is changed between them. We are still returning // x at whatever x value current holds. The whole x = 1 is skipped. - fold( + test( "function f() { while(x) { if (y) { return x } x = 1} return x}", "function f() { while(x) { if (y) { break } x = 1} return x}", ); - fold( + test( "function f() { while(x) { if (y) { return x } return x} return x}", "function f() { while(x) { if (y) {} break }return x}", ); // A break here only breaks out of the inner loop. - fold_same("function f() { while(x) { while (y) { return } } }"); + test_same("function f() { while(x) { while (y) { return } } }"); - fold_same("function f() { while(1) { return 7} return 5}"); + test_same("function f() { while(1) { return 7} return 5}"); - fold_same(concat!( + test_same(concat!( "function f() {", " try { while(x) {return f()}} catch (e) { } return f()}" )); - fold_same(concat!( + test_same(concat!( "function f() {", " try { while(x) {return f()}} finally {alert(1)} return f()}" )); // Both returns has the same handler - fold( + test( concat!( "function f() {", " try { while(x) { return f() } return f() } catch (e) { } }" @@ -1494,14 +1473,14 @@ mod test { ); // We can't fold this because it'll change the order of when foo is called. - fold_same(concat!( + test_same(concat!( "function f() {", " try { while(x) { return foo() } } finally { alert(1) } ", " return foo()}" )); // This is fine, we have no side effect in the return value. - fold( + test( concat!( "function f() {", " try { while(x) { return 1 } } finally { alert(1) } return 1}" @@ -1512,9 +1491,9 @@ mod test { ), ); - fold_same("function f() { try{ return a } finally { a = 2 } return a; }"); + test_same("function f() { try{ return a } finally { a = 2 } return a; }"); - fold( + test( "function f() { switch(a){ case 1: return a; default: g();} return a;}", "function f() { switch(a){ case 1: break; default: g();} return a; }", ); @@ -1528,83 +1507,83 @@ mod test { // TODO(bradfordcsmith): Stop normalizing the expected output or document why it is necessary. // enableNormalizeExpectedOutput(); - fold_same("function f() { while(x) { throw Error }}"); + test_same("function f() { while(x) { throw Error }}"); - fold( + test( "function f() { while(x) { throw Error } throw Error }", "function f() { while(x) { break } throw Error}", ); - fold_same("function f() { while(x) { throw Error(1) } throw Error(2)}"); - fold_same("function f() { while(x) { throw Error(1) } return Error(2)}"); + test_same("function f() { while(x) { throw Error(1) } throw Error(2)}"); + test_same("function f() { while(x) { throw Error(1) } return Error(2)}"); - fold_same("function f() { while(x) { throw 5 } }"); + test_same("function f() { while(x) { throw 5 } }"); - fold_same("function f() { a: { throw 5 } }"); + test_same("function f() { a: { throw 5 } }"); - fold( + test( "function f() { while(x) { throw 5} throw 5}", "function f() { while(x) { break } throw 5}", ); - fold( + test( "function f() { while(x) { throw x} throw x}", "function f() { while(x) { break } throw x}", ); - fold_same("function f() { while(x) { if (y) { throw Error }}}"); + test_same("function f() { while(x) { if (y) { throw Error }}}"); - fold( + test( "function f() { while(x) { if (y) { throw Error }} throw Error}", "function f() { while(x) { if (y) { break }} throw Error}", ); - fold( + test( "function f() { while(x) { if (y) { throw 5 }} throw 5}", "function f() { while(x) { if (y) { break }} throw 5}", ); // It doesn't matter if x is changed between them. We are still throwing // x at whatever x value current holds. The whole x = 1 is skipped. - fold( + test( "function f() { while(x) { if (y) { throw x } x = 1} throw x}", "function f() { while(x) { if (y) { break } x = 1} throw x}", ); - fold( + test( "function f() { while(x) { if (y) { throw x } throw x} throw x}", "function f() { while(x) { if (y) {} break }throw x}", ); // A break here only breaks out of the inner loop. - fold_same("function f() { while(x) { while (y) { throw Error } } }"); + test_same("function f() { while(x) { while (y) { throw Error } } }"); - fold_same("function f() { while(1) { throw 7} throw 5}"); + test_same("function f() { while(1) { throw 7} throw 5}"); - fold_same(concat!( + test_same(concat!( "function f() {", " try { while(x) {throw f()}} catch (e) { } throw f()}" )); - fold_same(concat!( + test_same(concat!( "function f() {", " try { while(x) {throw f()}} finally {alert(1)} throw f()}" )); // Both throws has the same handler - fold( + test( concat!("function f() {", " try { while(x) { throw f() } throw f() } catch (e) { } }"), concat!("function f() {", " try { while(x) { break } throw f() } catch (e) { } }"), ); // We can't fold this because it'll change the order of when foo is called. - fold_same(concat!( + test_same(concat!( "function f() {", " try { while(x) { throw foo() } } finally { alert(1) } ", " throw foo()}" )); // This is fine, we have no side effect in the throw value. - fold( + test( concat!( "function f() {", " try { while(x) { throw 1 } } finally { alert(1) } throw 1}" @@ -1615,9 +1594,9 @@ mod test { ), ); - fold_same("function f() { try{ throw a } finally { a = 2 } throw a; }"); + test_same("function f() { try{ throw a } finally { a = 2 } throw a; }"); - fold( + test( "function f() { switch(a){ case 1: throw a; default: g();} throw a;}", "function f() { switch(a){ case 1: break; default: g();} throw a; }", ); @@ -1629,30 +1608,30 @@ mod test { // late = false; // enableNormalize(); - fold("function f() { return; }", "function f(){}"); - fold_same("function f() { return a; }"); - fold( + test("function f() { return; }", "function f(){}"); + test_same("function f() { return a; }"); + test( "function f() { if (x) { return a } return a; }", "function f() { if (x) {} return a; }", ); - fold_same("function f() { try { if (x) { return a } } catch(e) {} return a; }"); - fold_same("function f() { try { if (x) {} } catch(e) {} return 1; }"); + test_same("function f() { try { if (x) { return a } } catch(e) {} return a; }"); + test_same("function f() { try { if (x) {} } catch(e) {} return 1; }"); // finally clauses may have side effects - fold_same("function f() { try { if (x) { return a } } finally { a++ } return a; }"); + test_same("function f() { try { if (x) { return a } } finally { a++ } return a; }"); // but they don't matter if the result doesn't have side effects and can't // be affect by side-effects. - fold( + test( "function f() { try { if (x) { return 1 } } finally {} return 1; }", "function f() { try { if (x) {} } finally {} return 1; }", ); - fold( + test( "function f() { switch(a){ case 1: return a; } return a; }", "function f() { switch(a){ case 1: } return a; }", ); - fold( + test( concat!( "function f() { switch(a){ ", " case 1: return a; case 2: return a; } return a; }" @@ -1667,32 +1646,32 @@ mod test { // late = false; // enableNormalize(); - fold_same("function f() { throw a; }"); - fold("function f() { if (x) { throw a } throw a; }", "function f() { if (x) {} throw a; }"); - fold_same("function f() { try { if (x) {throw a} } catch(e) {} throw a; }"); - fold_same("function f() { try { if (x) {throw 1} } catch(e) {f()} throw 1; }"); - fold_same("function f() { try { if (x) {throw 1} } catch(e) {f()} throw 1; }"); - fold_same("function f() { try { if (x) {throw 1} } catch(e) {throw 1}}"); - fold( + test_same("function f() { throw a; }"); + test("function f() { if (x) { throw a } throw a; }", "function f() { if (x) {} throw a; }"); + test_same("function f() { try { if (x) {throw a} } catch(e) {} throw a; }"); + test_same("function f() { try { if (x) {throw 1} } catch(e) {f()} throw 1; }"); + test_same("function f() { try { if (x) {throw 1} } catch(e) {f()} throw 1; }"); + test_same("function f() { try { if (x) {throw 1} } catch(e) {throw 1}}"); + test( "function f() { try { if (x) {throw 1} } catch(e) {throw 1} throw 1; }", "function f() { try { if (x) {throw 1} } catch(e) {} throw 1; }", ); // finally clauses may have side effects - fold_same("function f() { try { if (x) { throw a } } finally { a++ } throw a; }"); + test_same("function f() { try { if (x) { throw a } } finally { a++ } throw a; }"); // but they don't matter if the result doesn't have side effects and can't // be affect by side-effects. - fold( + test( "function f() { try { if (x) { throw 1 } } finally {} throw 1; }", "function f() { try { if (x) {} } finally {} throw 1; }", ); - fold( + test( "function f() { switch(a){ case 1: throw a; } throw a; }", "function f() { switch(a){ case 1: } throw a; }", ); - fold( + test( concat!("function f() { switch(a){ ", "case 1: throw a; case 2: throw a; } throw a; }"), concat!("function f() { switch(a){ case 1: break; case 2: } throw a; }"), ); @@ -1701,29 +1680,29 @@ mod test { #[test] #[ignore] fn test_nested_if_combine() { - fold("if(x)if(y){while(1){}}", "if(x&&y){while(1){}}"); - fold("if(x||z)if(y){while(1){}}", "if((x||z)&&y){while(1){}}"); - fold("if(x)if(y||z){while(1){}}", "if((x)&&(y||z)){while(1){}}"); - fold_same("if(x||z)if(y||z){while(1){}}"); - fold("if(x)if(y){if(z){while(1){}}}", "if(x&&(y&&z)){while(1){}}"); + test("if(x)if(y){while(1){}}", "if(x&&y){while(1){}}"); + test("if(x||z)if(y){while(1){}}", "if((x||z)&&y){while(1){}}"); + test("if(x)if(y||z){while(1){}}", "if((x)&&(y||z)){while(1){}}"); + test_same("if(x||z)if(y||z){while(1){}}"); + test("if(x)if(y){if(z){while(1){}}}", "if(x&&(y&&z)){while(1){}}"); } // See: http://blickly.github.io/closure-compiler-issues/#291 #[test] #[ignore] fn test_issue291() { - fold("if (true) { f.onchange(); }", "if (1) f.onchange();"); - fold_same("if (f) { f.onchange(); }"); - fold_same("if (f) { f.bar(); } else { f.onchange(); }"); - fold("if (f) { f.bonchange(); }", "f && f.bonchange();"); - fold_same("if (f) { f['x'](); }"); + test("if (true) { f.onchange(); }", "if (1) f.onchange();"); + test_same("if (f) { f.onchange(); }"); + test_same("if (f) { f.bar(); } else { f.onchange(); }"); + test("if (f) { f.bonchange(); }", "f && f.bonchange();"); + test_same("if (f) { f['x'](); }"); // optional versions - fold("if (true) { f?.onchange(); }", "if (1) f?.onchange();"); - fold_same("if (f) { f?.onchange(); }"); - fold_same("if (f) { f?.bar(); } else { f?.onchange(); }"); - fold("if (f) { f?.bonchange(); }", "f && f?.bonchange();"); - fold_same("if (f) { f?.['x'](); }"); + test("if (true) { f?.onchange(); }", "if (1) f?.onchange();"); + test_same("if (f) { f?.onchange(); }"); + test_same("if (f) { f?.bar(); } else { f?.onchange(); }"); + test("if (f) { f?.bonchange(); }", "f && f?.bonchange();"); + test_same("if (f) { f?.['x'](); }"); } #[test] diff --git a/crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs b/crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs index a9d66b7e6fab51..1f86811d5d9eff 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs @@ -591,198 +591,178 @@ impl<'a, 'b> PeepholeRemoveDeadCode { /// #[cfg(test)] mod test { - use oxc_allocator::Allocator; - - use crate::tester; - - fn test(source_text: &str, positive: &str) { - let allocator = Allocator::default(); - let mut pass = super::PeepholeRemoveDeadCode::new(false); - tester::test(&allocator, source_text, positive, &mut pass); - } - - fn test_same(source_text: &str) { - test(source_text, source_text); - } - - fn fold_same(js: &str) { - test_same(js); - } - - fn fold(js: &str, expected: &str) { - test(js, expected); - } + use crate::tester::{test, test_same}; #[test] fn test_fold_block() { - fold("{{foo()}}", "foo()"); - fold("{foo();{}}", "foo()"); - fold("{{foo()}{}}", "foo()"); - // fold("{{foo()}{bar()}}", "foo();bar()"); - fold("{if(false)foo(); {bar()}}", "bar()"); - fold("{if(false)if(false)if(false)foo(); {bar()}}", "bar()"); - - fold("{'hi'}", ""); - fold("{x==3}", "x == 3"); - fold("{`hello ${foo}`}", "`hello ${foo}`"); - fold("{ (function(){x++}) }", ""); - fold_same("function f(){return;}"); - fold("function f(){return 3;}", "function f(){return 3}"); - // fold_same("function f(){if(x)return; x=3; return; }"); - // fold("{x=3;;;y=2;;;}", "x=3;y=2"); + test("{{foo()}}", "foo()"); + test("{foo();{}}", "foo()"); + test("{{foo()}{}}", "foo()"); + // test("{{foo()}{bar()}}", "foo();bar()"); + test("{if(false)foo(); {bar()}}", "bar()"); + test("{if(false)if(false)if(false)foo(); {bar()}}", "bar()"); + + test("{'hi'}", ""); + test("{x==3}", "x == 3"); + test("{`hello ${foo}`}", "`hello ${foo}`"); + test("{ (function(){x++}) }", ""); + test_same("function f(){return;}"); + test("function f(){return 3;}", "function f(){return 3}"); + // test_same("function f(){if(x)return; x=3; return; }"); + // test("{x=3;;;y=2;;;}", "x=3;y=2"); // Cases to test for empty block. - // fold("while(x()){x}", "while(x());"); - fold("while(x()){x()}", "for(;x();)x()"); - // fold("for(x=0;x<100;x++){x}", "for(x=0;x<100;x++);"); - // fold("for(x in y){x}", "for(x in y);"); - // fold("for (x of y) {x}", "for(x of y);"); - fold("for (let x = 1; x <10; x++ ) {}", "for (let x = 1; x <10; x++ );"); - fold("for (var x = 1; x <10; x++ ) {}", "for (var x = 1; x <10; x++ );"); - fold("do { } while (true)", "do;while(true)"); + // test("while(x()){x}", "while(x());"); + test("while(x()){x()}", "for(;x();)x()"); + // test("for(x=0;x<100;x++){x}", "for(x=0;x<100;x++);"); + // test("for(x in y){x}", "for(x in y);"); + // test("for (x of y) {x}", "for(x of y);"); + test("for (let x = 1; x <10; x++ ) {}", "for (let x = 1; x <10; x++ );"); + test("for (var x = 1; x <10; x++ ) {}", "for (var x = 1; x <10; x++ );"); + test("do { } while (true)", "do;while(true)"); } #[test] fn test_remove_no_op_labelled_statement() { - fold("a: break a;", ""); - fold("a: { break a; }", ""); + test("a: break a;", ""); + test("a: { break a; }", ""); - fold( + test( // "a: { break a; console.log('unreachable'); }", // "", ); - fold( + test( // "a: { break a; var x = 1; } x = 2;", // "var x; x = 2;", ); - fold_same("b: { var x = 1; } x = 2;"); - fold_same("a: b: { var x = 1; } x = 2;"); - fold("foo:;", ""); + test_same("b: { var x = 1; } x = 2;"); + test_same("a: b: { var x = 1; } x = 2;"); + test("foo:;", ""); } #[test] fn test_fold_useless_for() { - fold("for(;false;) { foo() }", ""); - fold("for(;void 0;) { foo() }", ""); - fold("for(;undefined;) { foo() }", ""); - fold("for(;true;) foo() ", "for(;;) foo() "); - fold_same("for(;;) foo()"); - fold("for(;false;) { var a = 0; }", "var a"); - fold("for(;false;) { const a = 0; }", ""); - fold("for(;false;) { let a = 0; }", ""); + test("for(;false;) { foo() }", ""); + test("for(;void 0;) { foo() }", ""); + test("for(;undefined;) { foo() }", ""); + test("for(;true;) foo() ", "for(;;) foo() "); + test_same("for(;;) foo()"); + test("for(;false;) { var a = 0; }", "var a"); + test("for(;false;) { const a = 0; }", ""); + test("for(;false;) { let a = 0; }", ""); // Make sure it plays nice with minimizing - fold("for(;false;) { foo(); continue }", ""); + test("for(;false;) { foo(); continue }", ""); - fold("for (var { c, x: [d] } = {}; 0;);", "var { c, x: [d] } = {};"); - fold("for (var se = [1, 2]; false;);", "var se = [1, 2];"); - fold("for (var se = [1, 2]; false;) { var a = 0; }", "var se = [1, 2], a;"); + test("for (var { c, x: [d] } = {}; 0;);", "var { c, x: [d] } = {};"); + test("for (var se = [1, 2]; false;);", "var se = [1, 2];"); + test("for (var se = [1, 2]; false;) { var a = 0; }", "var se = [1, 2], a;"); - fold("for (foo = bar; false;) {}", "for (foo = bar; false;);"); - // fold("l1:for(;false;) { }", ""); + test("for (foo = bar; false;) {}", "for (foo = bar; false;);"); + // test("l1:for(;false;) { }", ""); } #[test] fn test_minimize_loop_with_constant_condition_vanilla_for() { - fold("for(;true;) foo()", "for(;;) foo()"); - fold("for(;0;) foo()", ""); - fold("for(;0.0;) foo()", ""); - fold("for(;NaN;) foo()", ""); - fold("for(;null;) foo()", ""); - fold("for(;undefined;) foo()", ""); - fold("for(;'';) foo()", ""); + test("for(;true;) foo()", "for(;;) foo()"); + test("for(;0;) foo()", ""); + test("for(;0.0;) foo()", ""); + test("for(;NaN;) foo()", ""); + test("for(;null;) foo()", ""); + test("for(;undefined;) foo()", ""); + test("for(;'';) foo()", ""); } #[test] #[ignore] fn test_object_literal() { - fold("({})", ""); - fold("({a:1})", ""); - fold("({a:foo()})", "foo()"); - fold("({'a':foo()})", "foo()"); + test("({})", ""); + test("({a:1})", ""); + test("({a:foo()})", "foo()"); + test("({'a':foo()})", "foo()"); // Object-spread may trigger getters. - fold_same("({...a})"); - fold_same("({...foo()})"); + test_same("({...a})"); + test_same("({...foo()})"); - fold("({ [bar()]: foo() })", "bar(), foo()"); - fold_same("({ ...baz, [bar()]: foo() })"); + test("({ [bar()]: foo() })", "bar(), foo()"); + test_same("({ ...baz, [bar()]: foo() })"); } #[test] fn test_array_literal() { - fold("([])", ""); - fold("([1])", ""); - fold("([a])", "[a]"); - fold("var a; ([a])", "var a;"); - fold("([foo()])", "foo()"); - fold_same("baz.map((v) => [v])"); + test("([])", ""); + test("([1])", ""); + test("([a])", "[a]"); + test("var a; ([a])", "var a;"); + test("([foo()])", "foo()"); + test_same("baz.map((v) => [v])"); } #[test] fn test_array_literal_containing_spread() { - fold_same("([...c])"); - fold("([4, ...c, a])", "([...c], a)"); - fold("var a; ([4, ...c, a])", "var a; ([...c])"); - fold("([foo(), ...c, bar()])", "(foo(), [...c], bar())"); - fold("([...a, b, ...c])", "([...a, b, ...c])"); - fold("var b; ([...a, b, ...c])", "var b; ([...a, ...c])"); - fold_same("([...b, ...c])"); // It would also be fine if the spreads were split apart. + test_same("([...c])"); + test("([4, ...c, a])", "([...c], a)"); + test("var a; ([4, ...c, a])", "var a; ([...c])"); + test("([foo(), ...c, bar()])", "(foo(), [...c], bar())"); + test("([...a, b, ...c])", "([...a, b, ...c])"); + test("var b; ([...a, b, ...c])", "var b; ([...a, ...c])"); + test_same("([...b, ...c])"); // It would also be fine if the spreads were split apart. } #[test] fn test_fold_unary_expression_statement() { - fold("typeof x", ""); - fold("typeof x?.y", "x?.y"); - fold("typeof x.y", "x.y"); - fold("typeof x.y.z()", "x.y.z()"); - fold("void x", "x"); - fold("void x?.y", "x?.y"); - fold("void x.y", "x.y"); - fold("void x.y.z()", "x.y.z()"); + test("typeof x", ""); + test("typeof x?.y", "x?.y"); + test("typeof x.y", "x.y"); + test("typeof x.y.z()", "x.y.z()"); + test("void x", "x"); + test("void x?.y", "x?.y"); + test("void x.y", "x.y"); + test("void x.y.z()", "x.y.z()"); // Removed in `MinimizeConditions`, to keep this pass idempotent for DCE. - fold_same("!x"); - fold_same("!x?.y"); - fold_same("!x.y"); - fold_same("!x.y.z()"); - fold_same("-x.y.z()"); + test_same("!x"); + test_same("!x?.y"); + test_same("!x.y"); + test_same("!x.y.z()"); + test_same("-x.y.z()"); - fold_same("delete x"); - fold_same("delete x.y"); - fold_same("delete x.y.z()"); - fold_same("+0n"); // Uncaught TypeError: Cannot convert a BigInt value to a number + test_same("delete x"); + test_same("delete x.y"); + test_same("delete x.y.z()"); + test_same("+0n"); // Uncaught TypeError: Cannot convert a BigInt value to a number } #[test] fn test_fold_sequence_expr() { - fold("('foo', 'bar', 'baz')", ""); - fold("('foo', 'bar', baz())", "baz()"); - fold("('foo', bar(), baz())", "bar(), baz()"); - fold("(() => {}, bar(), baz())", "bar(), baz()"); - fold("(function k() {}, k(), baz())", "k(), baz()"); - fold_same("(0, o.f)();"); - fold("var obj = Object((null, 2, 3), 1, 2);", "var obj = Object(3, 1, 2);"); - fold_same("(0 instanceof 0, foo)"); - fold_same("(0 in 0, foo)"); - fold_same("React.useEffect(() => (isMountRef.current = false, () => { isMountRef.current = true; }), [])"); + test("('foo', 'bar', 'baz')", ""); + test("('foo', 'bar', baz())", "baz()"); + test("('foo', bar(), baz())", "bar(), baz()"); + test("(() => {}, bar(), baz())", "bar(), baz()"); + test("(function k() {}, k(), baz())", "k(), baz()"); + test_same("(0, o.f)();"); + test("var obj = Object((null, 2, 3), 1, 2);", "var obj = Object(3, 1, 2);"); + test_same("(0 instanceof 0, foo)"); + test_same("(0 in 0, foo)"); + test_same("React.useEffect(() => (isMountRef.current = false, () => { isMountRef.current = true; }), [])"); } #[test] fn test_fold_try_statement() { - fold_same("try { throw 0 } catch (e) { foo() }"); - fold_same("try {} catch (e) { var foo }"); - fold("try {} catch (e) { foo() }", ""); - fold("try {} catch (e) { foo() } finally {}", ""); - fold("try {} finally { foo() }", "{ foo() }"); - fold("try {} catch (e) { foo() } finally { bar() }", "{ bar() }"); - fold("try {} finally { var x = foo() }", "{ var x = foo() }"); - fold("try {} catch (e) { foo() } finally { var x = bar() }", "{ var x = bar() }"); - fold("try {} finally { let x = foo() }", "{ let x = foo() }"); - fold("try {} catch (e) { foo() } finally { let x = bar() }", "{ let x = bar();}"); - fold("try {} catch () { } finally {}", ""); + test_same("try { throw 0 } catch (e) { foo() }"); + test_same("try {} catch (e) { var foo }"); + test("try {} catch (e) { foo() }", ""); + test("try {} catch (e) { foo() } finally {}", ""); + test("try {} finally { foo() }", "{ foo() }"); + test("try {} catch (e) { foo() } finally { bar() }", "{ bar() }"); + test("try {} finally { var x = foo() }", "{ var x = foo() }"); + test("try {} catch (e) { foo() } finally { var x = bar() }", "{ var x = bar() }"); + test("try {} finally { let x = foo() }", "{ let x = foo() }"); + test("try {} catch (e) { foo() } finally { let x = bar() }", "{ let x = bar();}"); + test("try {} catch () { } finally {}", ""); } #[test] @@ -803,8 +783,8 @@ mod test { #[test] fn test_fold_iife() { - fold_same("var k = () => {}"); - fold_same("var k = function () {}"); + test_same("var k = () => {}"); + test_same("var k = function () {}"); // test("var a = (() => {})()", "var a = /* @__PURE__ */ (() => {})();"); test("(() => {})()", ""); // test("(() => a())()", "a();"); diff --git a/crates/oxc_minifier/src/ast_passes/peephole_replace_known_methods.rs b/crates/oxc_minifier/src/ast_passes/peephole_replace_known_methods.rs index 6d5fce88dd8444..fcfbd7b75d54e0 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_replace_known_methods.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_replace_known_methods.rs @@ -488,325 +488,305 @@ impl<'a> PeepholeReplaceKnownMethods { /// Port from: #[cfg(test)] mod test { - use oxc_allocator::Allocator; - - use crate::tester; - - fn test(source_text: &str, positive: &str) { - let allocator = Allocator::default(); - let mut pass = super::PeepholeReplaceKnownMethods::new(); - tester::test(&allocator, source_text, positive, &mut pass); - } - - fn test_same(source_text: &str) { - test(source_text, source_text); - } - - fn fold_same(js: &str) { - test_same(js); - } - - fn fold(js: &str, expected: &str) { - test(js, expected); - } + use crate::tester::{test, test_same}; #[test] fn test_string_index_of() { - fold("x = 'abcdef'.indexOf('g')", "x = -1"); - fold("x = 'abcdef'.indexOf('b')", "x = 1"); - fold("x = 'abcdefbe'.indexOf('b', 2)", "x = 6"); - fold("x = 'abcdef'.indexOf('bcd')", "x = 1"); - fold("x = 'abcdefsdfasdfbcdassd'.indexOf('bcd', 4)", "x = 13"); + test("x = 'abcdef'.indexOf('g')", "x = -1"); + test("x = 'abcdef'.indexOf('b')", "x = 1"); + test("x = 'abcdefbe'.indexOf('b', 2)", "x = 6"); + test("x = 'abcdef'.indexOf('bcd')", "x = 1"); + test("x = 'abcdefsdfasdfbcdassd'.indexOf('bcd', 4)", "x = 13"); - fold("x = 'abcdef'.lastIndexOf('b')", "x = 1"); - fold("x = 'abcdefbe'.lastIndexOf('b')", "x = 6"); - fold("x = 'abcdefbe'.lastIndexOf('b', 5)", "x = 1"); + test("x = 'abcdef'.lastIndexOf('b')", "x = 1"); + test("x = 'abcdefbe'.lastIndexOf('b')", "x = 6"); + test("x = 'abcdefbe'.lastIndexOf('b', 5)", "x = 1"); // Both elements must be strings. Don't do anything if either one is not // string. // TODO: cast first arg to a string, and fold if possible. - // fold("x = 'abc1def'.indexOf(1)", "x = 3"); - // fold("x = 'abcNaNdef'.indexOf(NaN)", "x = 3"); - // fold("x = 'abcundefineddef'.indexOf(undefined)", "x = 3"); - // fold("x = 'abcnulldef'.indexOf(null)", "x = 3"); - // fold("x = 'abctruedef'.indexOf(true)", "x = 3"); + // test("x = 'abc1def'.indexOf(1)", "x = 3"); + // test("x = 'abcNaNdef'.indexOf(NaN)", "x = 3"); + // test("x = 'abcundefineddef'.indexOf(undefined)", "x = 3"); + // test("x = 'abcnulldef'.indexOf(null)", "x = 3"); + // test("x = 'abctruedef'.indexOf(true)", "x = 3"); // The following test case fails with JSC_PARSE_ERROR. Hence omitted. - // fold_same("x = 1.indexOf('bcd');"); - fold_same("x = NaN.indexOf('bcd')"); - fold_same("x = undefined.indexOf('bcd')"); - fold_same("x = null.indexOf('bcd')"); - fold_same("x = true.indexOf('bcd')"); - fold_same("x = false.indexOf('bcd')"); + // test_same("x = 1.indexOf('bcd');"); + test_same("x = NaN.indexOf('bcd')"); + test_same("x = undefined.indexOf('bcd')"); + test_same("x = null.indexOf('bcd')"); + test_same("x = true.indexOf('bcd')"); + test_same("x = false.indexOf('bcd')"); // Avoid dealing with regex or other types. - fold_same("x = 'abcdef'.indexOf(/b./)"); - fold_same("x = 'abcdef'.indexOf({a:2})"); - fold_same("x = 'abcdef'.indexOf([1,2])"); + test_same("x = 'abcdef'.indexOf(/b./)"); + test_same("x = 'abcdef'.indexOf({a:2})"); + test_same("x = 'abcdef'.indexOf([1,2])"); // Template Strings - fold_same("x = `abcdef`.indexOf('b')"); - fold_same("x = `Hello ${name}`.indexOf('a')"); - fold_same("x = tag `Hello ${name}`.indexOf('a')"); + test_same("x = `abcdef`.indexOf('b')"); + test_same("x = `Hello ${name}`.indexOf('a')"); + test_same("x = tag `Hello ${name}`.indexOf('a')"); } #[test] #[ignore] fn test_string_join_add_sparse() { - fold("x = [,,'a'].join(',')", "x = ',,a'"); + test("x = [,,'a'].join(',')", "x = ',,a'"); } #[test] #[ignore] fn test_no_string_join() { - fold_same("x = [].join(',',2)"); - fold_same("x = [].join(f)"); + test_same("x = [].join(',',2)"); + test_same("x = [].join(f)"); } #[test] #[ignore] fn test_string_join_add() { - fold("x = ['a', 'b', 'c'].join('')", "x = \"abc\""); - fold("x = [].join(',')", "x = \"\""); - fold("x = ['a'].join(',')", "x = \"a\""); - fold("x = ['a', 'b', 'c'].join(',')", "x = \"a,b,c\""); - fold("x = ['a', foo, 'b', 'c'].join(',')", "x = [\"a\",foo,\"b,c\"].join()"); - fold("x = [foo, 'a', 'b', 'c'].join(',')", "x = [foo,\"a,b,c\"].join()"); - fold("x = ['a', 'b', 'c', foo].join(',')", "x = [\"a,b,c\",foo].join()"); + test("x = ['a', 'b', 'c'].join('')", "x = \"abc\""); + test("x = [].join(',')", "x = \"\""); + test("x = ['a'].join(',')", "x = \"a\""); + test("x = ['a', 'b', 'c'].join(',')", "x = \"a,b,c\""); + test("x = ['a', foo, 'b', 'c'].join(',')", "x = [\"a\",foo,\"b,c\"].join()"); + test("x = [foo, 'a', 'b', 'c'].join(',')", "x = [foo,\"a,b,c\"].join()"); + test("x = ['a', 'b', 'c', foo].join(',')", "x = [\"a,b,c\",foo].join()"); // Works with numbers - fold("x = ['a=', 5].join('')", "x = \"a=5\""); - fold("x = ['a', '5'].join(7)", "x = \"a75\""); + test("x = ['a=', 5].join('')", "x = \"a=5\""); + test("x = ['a', '5'].join(7)", "x = \"a75\""); // Works on boolean - fold("x = ['a=', false].join('')", "x = \"a=false\""); - fold("x = ['a', '5'].join(true)", "x = \"atrue5\""); - fold("x = ['a', '5'].join(false)", "x = \"afalse5\""); + test("x = ['a=', false].join('')", "x = \"a=false\""); + test("x = ['a', '5'].join(true)", "x = \"atrue5\""); + test("x = ['a', '5'].join(false)", "x = \"afalse5\""); // Only optimize if it's a size win. - fold( + test( "x = ['a', '5', 'c'].join('a very very very long chain')", "x = [\"a\",\"5\",\"c\"].join(\"a very very very long chain\")", ); // Template strings - fold("x = [`a`, `b`, `c`].join(``)", "x = 'abc'"); - fold("x = [`a`, `b`, `c`].join('')", "x = 'abc'"); + test("x = [`a`, `b`, `c`].join(``)", "x = 'abc'"); + test("x = [`a`, `b`, `c`].join('')", "x = 'abc'"); // TODO(user): Its possible to fold this better. - fold_same("x = ['', foo].join('-')"); - fold_same("x = ['', foo, ''].join()"); + test_same("x = ['', foo].join('-')"); + test_same("x = ['', foo, ''].join()"); - fold( + test( "x = ['', '', foo, ''].join(',')", // "x = [ ',' , foo, ''].join()", ); - fold( + test( "x = ['', '', foo, '', ''].join(',')", // "x = [ ',', foo, ','].join()", ); - fold( + test( "x = ['', '', foo, '', '', bar].join(',')", // "x = [ ',', foo, ',', bar].join()", ); - fold( + test( "x = [1,2,3].join('abcdef')", // "x = '1abcdef2abcdef3'", ); - fold("x = [1,2].join()", "x = '1,2'"); - fold("x = [null,undefined,''].join(',')", "x = ',,'"); - fold("x = [null,undefined,0].join(',')", "x = ',,0'"); + test("x = [1,2].join()", "x = '1,2'"); + test("x = [null,undefined,''].join(',')", "x = ',,'"); + test("x = [null,undefined,0].join(',')", "x = ',,0'"); // This can be folded but we don't currently. - fold_same("x = [[1,2],[3,4]].join()"); // would like: "x = '1,2,3,4'" + test_same("x = [[1,2],[3,4]].join()"); // would like: "x = '1,2,3,4'" } #[test] #[ignore] fn test_string_join_add_b1992789() { - fold("x = ['a'].join('')", "x = \"a\""); - fold_same("x = [foo()].join('')"); - fold_same("[foo()].join('')"); - fold("[null].join('')", "''"); + test("x = ['a'].join('')", "x = \"a\""); + test_same("x = [foo()].join('')"); + test_same("[foo()].join('')"); + test("[null].join('')", "''"); } #[test] fn test_fold_string_replace() { - fold("'c'.replace('c','x')", "'x'"); - fold("'ac'.replace('c','x')", "'ax'"); - fold("'ca'.replace('c','x')", "'xa'"); - fold("'ac'.replace('c','xxx')", "'axxx'"); - fold("'ca'.replace('c','xxx')", "'xxxa'"); + test("'c'.replace('c','x')", "'x'"); + test("'ac'.replace('c','x')", "'ax'"); + test("'ca'.replace('c','x')", "'xa'"); + test("'ac'.replace('c','xxx')", "'axxx'"); + test("'ca'.replace('c','xxx')", "'xxxa'"); // only one instance replaced - fold("'acaca'.replace('c','x')", "'axaca'"); - fold("'ab'.replace('','x')", "'xab'"); + test("'acaca'.replace('c','x')", "'axaca'"); + test("'ab'.replace('','x')", "'xab'"); - fold_same("'acaca'.replace(/c/,'x')"); // this will affect the global RegExp props - fold_same("'acaca'.replace(/c/g,'x')"); // this will affect the global RegExp props + test_same("'acaca'.replace(/c/,'x')"); // this will affect the global RegExp props + test_same("'acaca'.replace(/c/g,'x')"); // this will affect the global RegExp props // not a literal - fold_same("x.replace('x','c')"); - - fold_same("'Xyz'.replace('Xyz', '$$')"); // would fold to '$' - fold_same("'PreXyzPost'.replace('Xyz', '$&')"); // would fold to 'PreXyzPost' - fold_same("'PreXyzPost'.replace('Xyz', '$`')"); // would fold to 'PrePrePost' - fold_same("'PreXyzPost'.replace('Xyz', '$\\'')"); // would fold to 'PrePostPost' - fold_same("'PreXyzPostXyz'.replace('Xyz', '$\\'')"); // would fold to 'PrePostXyzPostXyz' - fold_same("'123'.replace('2', '$`')"); // would fold to '113' + test_same("x.replace('x','c')"); + + test_same("'Xyz'.replace('Xyz', '$$')"); // would fold to '$' + test_same("'PreXyzPost'.replace('Xyz', '$&')"); // would fold to 'PreXyzPost' + test_same("'PreXyzPost'.replace('Xyz', '$`')"); // would fold to 'PrePrePost' + test_same("'PreXyzPost'.replace('Xyz', '$\\'')"); // would fold to 'PrePostPost' + test_same("'PreXyzPostXyz'.replace('Xyz', '$\\'')"); // would fold to 'PrePostXyzPostXyz' + test_same("'123'.replace('2', '$`')"); // would fold to '113' } #[test] fn test_fold_string_replace_all() { - fold("x = 'abcde'.replaceAll('bcd','c')", "x = 'ace'"); - fold("x = 'abcde'.replaceAll('c','xxx')", "x = 'abxxxde'"); - fold("x = 'abcde'.replaceAll('xxx','c')", "x = 'abcde'"); - fold("'ab'.replaceAll('','x')", "'xaxbx'"); + test("x = 'abcde'.replaceAll('bcd','c')", "x = 'ace'"); + test("x = 'abcde'.replaceAll('c','xxx')", "x = 'abxxxde'"); + test("x = 'abcde'.replaceAll('xxx','c')", "x = 'abcde'"); + test("'ab'.replaceAll('','x')", "'xaxbx'"); - fold("x = 'c_c_c'.replaceAll('c','x')", "x = 'x_x_x'"); + test("x = 'c_c_c'.replaceAll('c','x')", "x = 'x_x_x'"); - fold_same("x = 'acaca'.replaceAll(/c/,'x')"); // this should throw - fold_same("x = 'acaca'.replaceAll(/c/g,'x')"); // this will affect the global RegExp props + test_same("x = 'acaca'.replaceAll(/c/,'x')"); // this should throw + test_same("x = 'acaca'.replaceAll(/c/g,'x')"); // this will affect the global RegExp props // not a literal - fold_same("x.replaceAll('x','c')"); - - fold_same("'Xyz'.replaceAll('Xyz', '$$')"); // would fold to '$' - fold_same("'PreXyzPost'.replaceAll('Xyz', '$&')"); // would fold to 'PreXyzPost' - fold_same("'PreXyzPost'.replaceAll('Xyz', '$`')"); // would fold to 'PrePrePost' - fold_same("'PreXyzPost'.replaceAll('Xyz', '$\\'')"); // would fold to 'PrePostPost' - fold_same("'PreXyzPostXyz'.replaceAll('Xyz', '$\\'')"); // would fold to 'PrePostXyzPost' - fold_same("'123'.replaceAll('2', '$`')"); // would fold to '113' + test_same("x.replaceAll('x','c')"); + + test_same("'Xyz'.replaceAll('Xyz', '$$')"); // would fold to '$' + test_same("'PreXyzPost'.replaceAll('Xyz', '$&')"); // would fold to 'PreXyzPost' + test_same("'PreXyzPost'.replaceAll('Xyz', '$`')"); // would fold to 'PrePrePost' + test_same("'PreXyzPost'.replaceAll('Xyz', '$\\'')"); // would fold to 'PrePostPost' + test_same("'PreXyzPostXyz'.replaceAll('Xyz', '$\\'')"); // would fold to 'PrePostXyzPost' + test_same("'123'.replaceAll('2', '$`')"); // would fold to '113' } #[test] fn test_fold_string_substring() { - fold("x = 'abcde'.substring(0,2)", "x = 'ab'"); - fold("x = 'abcde'.substring(1,2)", "x = 'b'"); - fold("x = 'abcde'.substring(2)", "x = 'cde'"); + test("x = 'abcde'.substring(0,2)", "x = 'ab'"); + test("x = 'abcde'.substring(1,2)", "x = 'b'"); + test("x = 'abcde'.substring(2)", "x = 'cde'"); // we should be leaving negative, out-of-bound, and inverted indices alone for now - fold_same("x = 'abcde'.substring(-1)"); - fold_same("x = 'abcde'.substring(1, -2)"); - fold_same("x = 'abcde'.substring(1, 2, 3)"); - fold_same("x = 'abcde'.substring(2, 0)"); - fold_same("x = 'a'.substring(0, 2)"); + test_same("x = 'abcde'.substring(-1)"); + test_same("x = 'abcde'.substring(1, -2)"); + test_same("x = 'abcde'.substring(1, 2, 3)"); + test_same("x = 'abcde'.substring(2, 0)"); + test_same("x = 'a'.substring(0, 2)"); // Template strings - fold_same("x = `abcdef`.substring(0,2)"); - fold_same("x = `abcdef ${abc}`.substring(0,2)"); + test_same("x = `abcdef`.substring(0,2)"); + test_same("x = `abcdef ${abc}`.substring(0,2)"); } #[test] fn test_fold_string_slice() { - fold("x = 'abcde'.slice(0,2)", "x = 'ab'"); - fold("x = 'abcde'.slice(1,2)", "x = 'b'"); - fold("x = 'abcde'.slice(2)", "x = 'cde'"); + test("x = 'abcde'.slice(0,2)", "x = 'ab'"); + test("x = 'abcde'.slice(1,2)", "x = 'b'"); + test("x = 'abcde'.slice(2)", "x = 'cde'"); // we should be leaving negative, out-of-bound, and inverted indices alone for now - fold_same("x = 'abcde'.slice(-1)"); - fold_same("x = 'abcde'.slice(1, -2)"); - fold_same("x = 'abcde'.slice(1, 2, 3)"); - fold_same("x = 'abcde'.slice(2, 0)"); - fold_same("x = 'a'.slice(0, 2)"); + test_same("x = 'abcde'.slice(-1)"); + test_same("x = 'abcde'.slice(1, -2)"); + test_same("x = 'abcde'.slice(1, 2, 3)"); + test_same("x = 'abcde'.slice(2, 0)"); + test_same("x = 'a'.slice(0, 2)"); // Template strings - fold_same("x = `abcdef`.slice(0,2)"); - fold_same("x = `abcdef ${abc}`.slice(0,2)"); + test_same("x = `abcdef`.slice(0,2)"); + test_same("x = `abcdef ${abc}`.slice(0,2)"); } #[test] fn test_fold_string_char_at() { - fold("x = 'abcde'.charAt(0)", "x = 'a'"); - fold("x = 'abcde'.charAt(1)", "x = 'b'"); - fold("x = 'abcde'.charAt(2)", "x = 'c'"); - fold("x = 'abcde'.charAt(3)", "x = 'd'"); - fold("x = 'abcde'.charAt(4)", "x = 'e'"); - fold("x = 'abcde'.charAt(5)", "x = ''"); - fold("x = 'abcde'.charAt(-1)", "x = ''"); - fold("x = 'abcde'.charAt()", "x = 'a'"); - fold_same("x = 'abcde'.charAt(0, ++z)"); - fold_same("x = 'abcde'.charAt(y)"); - fold_same("x = 'abcde'.charAt(null)"); // or x = 'a' - fold_same("x = 'abcde'.charAt(true)"); // or x = 'b' - // fold("x = '\\ud834\udd1e'.charAt(0)", "x = '\\ud834'"); - // fold("x = '\\ud834\udd1e'.charAt(1)", "x = '\\udd1e'"); + test("x = 'abcde'.charAt(0)", "x = 'a'"); + test("x = 'abcde'.charAt(1)", "x = 'b'"); + test("x = 'abcde'.charAt(2)", "x = 'c'"); + test("x = 'abcde'.charAt(3)", "x = 'd'"); + test("x = 'abcde'.charAt(4)", "x = 'e'"); + test("x = 'abcde'.charAt(5)", "x = ''"); + test("x = 'abcde'.charAt(-1)", "x = ''"); + test("x = 'abcde'.charAt()", "x = 'a'"); + test_same("x = 'abcde'.charAt(0, ++z)"); + test_same("x = 'abcde'.charAt(y)"); + test_same("x = 'abcde'.charAt(null)"); // or x = 'a' + test_same("x = 'abcde'.charAt(true)"); // or x = 'b' + // test("x = '\\ud834\udd1e'.charAt(0)", "x = '\\ud834'"); + // test("x = '\\ud834\udd1e'.charAt(1)", "x = '\\udd1e'"); // Template strings - fold_same("x = `abcdef`.charAt(0)"); - fold_same("x = `abcdef ${abc}`.charAt(0)"); + test_same("x = `abcdef`.charAt(0)"); + test_same("x = `abcdef ${abc}`.charAt(0)"); } #[test] fn test_fold_string_char_code_at() { - fold("x = 'abcde'.charCodeAt()", "x = 97"); - fold("x = 'abcde'.charCodeAt(0)", "x = 97"); - fold("x = 'abcde'.charCodeAt(1)", "x = 98"); - fold("x = 'abcde'.charCodeAt(2)", "x = 99"); - fold("x = 'abcde'.charCodeAt(3)", "x = 100"); - fold("x = 'abcde'.charCodeAt(4)", "x = 101"); - fold_same("x = 'abcde'.charCodeAt(5)"); - fold("x = 'abcde'.charCodeAt(-1)", "x = NaN"); - fold_same("x = 'abcde'.charCodeAt(y)"); - fold("x = 'abcde'.charCodeAt()", "x = 97"); - fold("x = 'abcde'.charCodeAt(0, ++z)", "x = 97"); - fold("x = 'abcde'.charCodeAt(null)", "x = 97"); - fold("x = 'abcde'.charCodeAt(true)", "x = 98"); - // fold("x = '\\ud834\udd1e'.charCodeAt(0)", "x = 55348"); - // fold("x = '\\ud834\udd1e'.charCodeAt(1)", "x = 56606"); - fold_same("x = `abcdef`.charCodeAt(0)"); - fold_same("x = `abcdef ${abc}`.charCodeAt(0)"); + test("x = 'abcde'.charCodeAt()", "x = 97"); + test("x = 'abcde'.charCodeAt(0)", "x = 97"); + test("x = 'abcde'.charCodeAt(1)", "x = 98"); + test("x = 'abcde'.charCodeAt(2)", "x = 99"); + test("x = 'abcde'.charCodeAt(3)", "x = 100"); + test("x = 'abcde'.charCodeAt(4)", "x = 101"); + test_same("x = 'abcde'.charCodeAt(5)"); + test("x = 'abcde'.charCodeAt(-1)", "x = NaN"); + test_same("x = 'abcde'.charCodeAt(y)"); + test("x = 'abcde'.charCodeAt()", "x = 97"); + test("x = 'abcde'.charCodeAt(0, ++z)", "x = 97"); + test("x = 'abcde'.charCodeAt(null)", "x = 97"); + test("x = 'abcde'.charCodeAt(true)", "x = 98"); + // test("x = '\\ud834\udd1e'.charCodeAt(0)", "x = 55348"); + // test("x = '\\ud834\udd1e'.charCodeAt(1)", "x = 56606"); + test_same("x = `abcdef`.charCodeAt(0)"); + test_same("x = `abcdef ${abc}`.charCodeAt(0)"); } #[test] #[ignore] fn test_fold_string_split() { // late = false; - fold("x = 'abcde'.split('foo')", "x = ['abcde']"); - fold("x = 'abcde'.split()", "x = ['abcde']"); - fold("x = 'abcde'.split(null)", "x = ['abcde']"); - fold("x = 'a b c d e'.split(' ')", "x = ['a','b','c','d','e']"); - fold("x = 'a b c d e'.split(' ', 0)", "x = []"); - fold("x = 'abcde'.split('cd')", "x = ['ab','e']"); - fold("x = 'a b c d e'.split(' ', 1)", "x = ['a']"); - fold("x = 'a b c d e'.split(' ', 3)", "x = ['a','b','c']"); - fold("x = 'a b c d e'.split(null, 1)", "x = ['a b c d e']"); - fold("x = 'aaaaa'.split('a')", "x = ['', '', '', '', '', '']"); - fold("x = 'xyx'.split('x')", "x = ['', 'y', '']"); + test("x = 'abcde'.split('foo')", "x = ['abcde']"); + test("x = 'abcde'.split()", "x = ['abcde']"); + test("x = 'abcde'.split(null)", "x = ['abcde']"); + test("x = 'a b c d e'.split(' ')", "x = ['a','b','c','d','e']"); + test("x = 'a b c d e'.split(' ', 0)", "x = []"); + test("x = 'abcde'.split('cd')", "x = ['ab','e']"); + test("x = 'a b c d e'.split(' ', 1)", "x = ['a']"); + test("x = 'a b c d e'.split(' ', 3)", "x = ['a','b','c']"); + test("x = 'a b c d e'.split(null, 1)", "x = ['a b c d e']"); + test("x = 'aaaaa'.split('a')", "x = ['', '', '', '', '', '']"); + test("x = 'xyx'.split('x')", "x = ['', 'y', '']"); // Empty separator - fold("x = 'abcde'.split('')", "x = ['a','b','c','d','e']"); - fold("x = 'abcde'.split('', 3)", "x = ['a','b','c']"); + test("x = 'abcde'.split('')", "x = ['a','b','c','d','e']"); + test("x = 'abcde'.split('', 3)", "x = ['a','b','c']"); // Empty separator AND empty string - fold("x = ''.split('')", "x = []"); + test("x = ''.split('')", "x = []"); // Separator equals string - fold("x = 'aaa'.split('aaa')", "x = ['','']"); - fold("x = ' '.split(' ')", "x = ['','']"); + test("x = 'aaa'.split('aaa')", "x = ['','']"); + test("x = ' '.split(' ')", "x = ['','']"); - fold_same("x = 'abcde'.split(/ /)"); - fold_same("x = 'abcde'.split(' ', -1)"); + test_same("x = 'abcde'.split(/ /)"); + test_same("x = 'abcde'.split(' ', -1)"); // Template strings - fold_same("x = `abcdef`.split()"); - fold_same("x = `abcdef ${abc}`.split()"); + test_same("x = `abcdef`.split()"); + test_same("x = `abcdef ${abc}`.split()"); // late = true; - // fold_same("x = 'a b c d e'.split(' ')"); + // test_same("x = 'a b c d e'.split(' ')"); } #[test] #[ignore] fn test_join_bug() { - fold("var x = [].join();", "var x = '';"); - fold_same("var x = [x].join();"); - fold_same("var x = [x,y].join();"); - fold_same("var x = [x,y,z].join();"); + test("var x = [].join();", "var x = '';"); + test_same("var x = [x].join();"); + test_same("var x = [x,y].join();"); + test_same("var x = [x,y,z].join();"); - // fold_same( + // test_same( // lines( // "shape['matrix'] = [", // " Number(headingCos2).toFixed(4),", @@ -821,35 +801,35 @@ mod test { #[test] #[ignore] fn test_join_spread1() { - fold_same("var x = [...foo].join('');"); - fold_same("var x = [...someMap.keys()].join('');"); - fold_same("var x = [foo, ...bar].join('');"); - fold_same("var x = [...foo, bar].join('');"); - fold_same("var x = [...foo, 'bar'].join('');"); - fold_same("var x = ['1', ...'2', '3'].join('');"); - fold_same("var x = ['1', ...['2'], '3'].join('');"); + test_same("var x = [...foo].join('');"); + test_same("var x = [...someMap.keys()].join('');"); + test_same("var x = [foo, ...bar].join('');"); + test_same("var x = [...foo, bar].join('');"); + test_same("var x = [...foo, 'bar'].join('');"); + test_same("var x = ['1', ...'2', '3'].join('');"); + test_same("var x = ['1', ...['2'], '3'].join('');"); } #[test] #[ignore] fn test_join_spread2() { - fold("var x = [...foo].join(',');", "var x = [...foo].join();"); - fold("var x = [...someMap.keys()].join(',');", "var x = [...someMap.keys()].join();"); - fold("var x = [foo, ...bar].join(',');", "var x = [foo, ...bar].join();"); - fold("var x = [...foo, bar].join(',');", "var x = [...foo, bar].join();"); - fold("var x = [...foo, 'bar'].join(',');", "var x = [...foo, 'bar'].join();"); - fold("var x = ['1', ...'2', '3'].join(',');", "var x = ['1', ...'2', '3'].join();"); - fold("var x = ['1', ...['2'], '3'].join(',');", "var x = ['1', ...['2'], '3'].join();"); + test("var x = [...foo].join(',');", "var x = [...foo].join();"); + test("var x = [...someMap.keys()].join(',');", "var x = [...someMap.keys()].join();"); + test("var x = [foo, ...bar].join(',');", "var x = [foo, ...bar].join();"); + test("var x = [...foo, bar].join(',');", "var x = [...foo, bar].join();"); + test("var x = [...foo, 'bar'].join(',');", "var x = [...foo, 'bar'].join();"); + test("var x = ['1', ...'2', '3'].join(',');", "var x = ['1', ...'2', '3'].join();"); + test("var x = ['1', ...['2'], '3'].join(',');", "var x = ['1', ...['2'], '3'].join();"); } #[test] fn test_to_upper() { - fold("'a'.toUpperCase()", "'A'"); - fold("'A'.toUpperCase()", "'A'"); - fold("'aBcDe'.toUpperCase()", "'ABCDE'"); + test("'a'.toUpperCase()", "'A'"); + test("'A'.toUpperCase()", "'A'"); + test("'aBcDe'.toUpperCase()", "'ABCDE'"); - fold_same("`abc`.toUpperCase()"); - fold_same("`a ${bc}`.toUpperCase()"); + test_same("`abc`.toUpperCase()"); + test_same("`a ${bc}`.toUpperCase()"); /* * Make sure things aren't totally broken for non-ASCII strings, non-exhaustive. @@ -863,25 +843,25 @@ mod test { *
  • graphemes that change case in a position sentitive way * */ - fold("'\u{0049}'.toUpperCase()", "'\u{0049}'"); - fold("'\u{0069}'.toUpperCase()", "'\u{0049}'"); - fold("'\u{0130}'.toUpperCase()", "'\u{0130}'"); - fold("'\u{0131}'.toUpperCase()", "'\u{0049}'"); - fold("'\u{0049}\u{0307}'.toUpperCase()", "'\u{0049}\u{0307}'"); - fold("'ß'.toUpperCase()", "'SS'"); - fold("'SS'.toUpperCase()", "'SS'"); - fold("'σ'.toUpperCase()", "'Σ'"); - fold("'σς'.toUpperCase()", "'ΣΣ'"); + test("'\u{0049}'.toUpperCase()", "'\u{0049}'"); + test("'\u{0069}'.toUpperCase()", "'\u{0049}'"); + test("'\u{0130}'.toUpperCase()", "'\u{0130}'"); + test("'\u{0131}'.toUpperCase()", "'\u{0049}'"); + test("'\u{0049}\u{0307}'.toUpperCase()", "'\u{0049}\u{0307}'"); + test("'ß'.toUpperCase()", "'SS'"); + test("'SS'.toUpperCase()", "'SS'"); + test("'σ'.toUpperCase()", "'Σ'"); + test("'σς'.toUpperCase()", "'ΣΣ'"); } #[test] fn test_to_lower() { - fold("'A'.toLowerCase()", "'a'"); - fold("'a'.toLowerCase()", "'a'"); - fold("'aBcDe'.toLowerCase()", "'abcde'"); + test("'A'.toLowerCase()", "'a'"); + test("'a'.toLowerCase()", "'a'"); + test("'aBcDe'.toLowerCase()", "'abcde'"); - fold_same("`ABC`.toLowerCase()"); - fold_same("`A ${BC}`.toLowerCase()"); + test_same("`ABC`.toLowerCase()"); + test_same("`A ${BC}`.toLowerCase()"); /* * Make sure things aren't totally broken for non-ASCII strings, non-exhaustive. @@ -896,275 +876,275 @@ mod test { *
  • graphemes that change case in a position sentitive way * */ - fold("'\u{0049}'.toLowerCase()", "'\u{0069}'"); - fold("'\u{0069}'.toLowerCase()", "'\u{0069}'"); - fold("'\u{0130}'.toLowerCase()", "'\u{0069}\u{0307}'"); - fold("'\u{0131}'.toLowerCase()", "'\u{0131}'"); - fold("'\u{0049}\u{0307}'.toLowerCase()", "'\u{0069}\u{0307}'"); - fold("'ß'.toLowerCase()", "'ß'"); - fold("'SS'.toLowerCase()", "'ss'"); - fold("'Σ'.toLowerCase()", "'σ'"); - fold("'ΣΣ'.toLowerCase()", "'σς'"); + test("'\u{0049}'.toLowerCase()", "'\u{0069}'"); + test("'\u{0069}'.toLowerCase()", "'\u{0069}'"); + test("'\u{0130}'.toLowerCase()", "'\u{0069}\u{0307}'"); + test("'\u{0131}'.toLowerCase()", "'\u{0131}'"); + test("'\u{0049}\u{0307}'.toLowerCase()", "'\u{0069}\u{0307}'"); + test("'ß'.toLowerCase()", "'ß'"); + test("'SS'.toLowerCase()", "'ss'"); + test("'Σ'.toLowerCase()", "'σ'"); + test("'ΣΣ'.toLowerCase()", "'σς'"); } #[test] #[ignore] fn test_fold_math_functions_bug() { - fold_same("Math[0]()"); + test_same("Math[0]()"); } #[test] #[ignore] fn test_fold_math_functions_abs() { - fold_same("Math.abs(Math.random())"); - - fold("Math.abs('-1')", "1"); - fold("Math.abs(-2)", "2"); - fold("Math.abs(null)", "0"); - fold("Math.abs('')", "0"); - fold("Math.abs([])", "0"); - fold("Math.abs([2])", "2"); - fold("Math.abs([1,2])", "NaN"); - fold("Math.abs({})", "NaN"); - fold("Math.abs('string');", "NaN"); + test_same("Math.abs(Math.random())"); + + test("Math.abs('-1')", "1"); + test("Math.abs(-2)", "2"); + test("Math.abs(null)", "0"); + test("Math.abs('')", "0"); + test("Math.abs([])", "0"); + test("Math.abs([2])", "2"); + test("Math.abs([1,2])", "NaN"); + test("Math.abs({})", "NaN"); + test("Math.abs('string');", "NaN"); } #[test] #[ignore] fn test_fold_math_functions_imul() { - fold_same("Math.imul(Math.random(),2)"); - fold("Math.imul(-1,1)", "-1"); - fold("Math.imul(2,2)", "4"); - fold("Math.imul(2)", "0"); - fold("Math.imul(2,3,5)", "6"); - fold("Math.imul(0xfffffffe, 5)", "-10"); - fold("Math.imul(0xffffffff, 5)", "-5"); - fold("Math.imul(0xfffffffffffff34f, 0xfffffffffff342)", "13369344"); - fold("Math.imul(0xfffffffffffff34f, -0xfffffffffff342)", "-13369344"); - fold("Math.imul(NaN, 2)", "0"); + test_same("Math.imul(Math.random(),2)"); + test("Math.imul(-1,1)", "-1"); + test("Math.imul(2,2)", "4"); + test("Math.imul(2)", "0"); + test("Math.imul(2,3,5)", "6"); + test("Math.imul(0xfffffffe, 5)", "-10"); + test("Math.imul(0xffffffff, 5)", "-5"); + test("Math.imul(0xfffffffffffff34f, 0xfffffffffff342)", "13369344"); + test("Math.imul(0xfffffffffffff34f, -0xfffffffffff342)", "-13369344"); + test("Math.imul(NaN, 2)", "0"); } #[test] #[ignore] fn test_fold_math_functions_ceil() { - fold_same("Math.ceil(Math.random())"); + test_same("Math.ceil(Math.random())"); - fold("Math.ceil(1)", "1"); - fold("Math.ceil(1.5)", "2"); - fold("Math.ceil(1.3)", "2"); - fold("Math.ceil(-1.3)", "-1"); + test("Math.ceil(1)", "1"); + test("Math.ceil(1.5)", "2"); + test("Math.ceil(1.3)", "2"); + test("Math.ceil(-1.3)", "-1"); } #[test] #[ignore] fn test_fold_math_functions_floor() { - fold_same("Math.floor(Math.random())"); + test_same("Math.floor(Math.random())"); - fold("Math.floor(1)", "1"); - fold("Math.floor(1.5)", "1"); - fold("Math.floor(1.3)", "1"); - fold("Math.floor(-1.3)", "-2"); + test("Math.floor(1)", "1"); + test("Math.floor(1.5)", "1"); + test("Math.floor(1.3)", "1"); + test("Math.floor(-1.3)", "-2"); } #[test] #[ignore] fn test_fold_math_functions_fround() { - fold_same("Math.fround(Math.random())"); + test_same("Math.fround(Math.random())"); - fold("Math.fround(NaN)", "NaN"); - fold("Math.fround(Infinity)", "Infinity"); - fold("Math.fround(1)", "1"); - fold("Math.fround(0)", "0"); + test("Math.fround(NaN)", "NaN"); + test("Math.fround(Infinity)", "Infinity"); + test("Math.fround(1)", "1"); + test("Math.fround(0)", "0"); } #[test] #[ignore] // @GwtIncompatible // TODO(b/155511629): Enable this test for J2CL fn test_fold_math_functions_fround_j2cl() { - fold_same("Math.fround(1.2)"); + test_same("Math.fround(1.2)"); } #[test] #[ignore] fn test_fold_math_functions_round() { - fold_same("Math.round(Math.random())"); - fold("Math.round(NaN)", "NaN"); - fold("Math.round(3.5)", "4"); - fold("Math.round(-3.5)", "-3"); + test_same("Math.round(Math.random())"); + test("Math.round(NaN)", "NaN"); + test("Math.round(3.5)", "4"); + test("Math.round(-3.5)", "-3"); } #[test] #[ignore] fn test_fold_math_functions_sign() { - fold_same("Math.sign(Math.random())"); - fold("Math.sign(NaN)", "NaN"); - fold("Math.sign(3.5)", "1"); - fold("Math.sign(-3.5)", "-1"); + test_same("Math.sign(Math.random())"); + test("Math.sign(NaN)", "NaN"); + test("Math.sign(3.5)", "1"); + test("Math.sign(-3.5)", "-1"); } #[test] #[ignore] fn test_fold_math_functions_trunc() { - fold_same("Math.trunc(Math.random())"); - fold("Math.sign(NaN)", "NaN"); - fold("Math.trunc(3.5)", "3"); - fold("Math.trunc(-3.5)", "-3"); + test_same("Math.trunc(Math.random())"); + test("Math.sign(NaN)", "NaN"); + test("Math.trunc(3.5)", "3"); + test("Math.trunc(-3.5)", "-3"); } #[test] #[ignore] fn test_fold_math_functions_clz32() { - fold("Math.clz32(0)", "32"); + test("Math.clz32(0)", "32"); let mut x = 1; for i in (0..=31).rev() { - fold(&format!("{x}.leading_zeros()"), &i.to_string()); - fold(&format!("{}.leading_zeros()", 2 * x - 1), &i.to_string()); + test(&format!("{x}.leading_zeros()"), &i.to_string()); + test(&format!("{}.leading_zeros()", 2 * x - 1), &i.to_string()); x *= 2; } - fold("Math.clz32('52')", "26"); - fold("Math.clz32([52])", "26"); - fold("Math.clz32([52, 53])", "32"); + test("Math.clz32('52')", "26"); + test("Math.clz32([52])", "26"); + test("Math.clz32([52, 53])", "32"); // Overflow cases - fold("Math.clz32(0x100000000)", "32"); - fold("Math.clz32(0x100000001)", "31"); + test("Math.clz32(0x100000000)", "32"); + test("Math.clz32(0x100000001)", "31"); // NaN -> 0 - fold("Math.clz32(NaN)", "32"); - fold("Math.clz32('foo')", "32"); - fold("Math.clz32(Infinity)", "32"); + test("Math.clz32(NaN)", "32"); + test("Math.clz32('foo')", "32"); + test("Math.clz32(Infinity)", "32"); } #[test] #[ignore] fn test_fold_math_functions_max() { - fold_same("Math.max(Math.random(), 1)"); + test_same("Math.max(Math.random(), 1)"); - fold("Math.max()", "-Infinity"); - fold("Math.max(0)", "0"); - fold("Math.max(0, 1)", "1"); - fold("Math.max(0, 1, -1, 200)", "200"); + test("Math.max()", "-Infinity"); + test("Math.max(0)", "0"); + test("Math.max(0, 1)", "1"); + test("Math.max(0, 1, -1, 200)", "200"); } #[test] #[ignore] fn test_fold_math_functions_min() { - fold_same("Math.min(Math.random(), 1)"); + test_same("Math.min(Math.random(), 1)"); - fold("Math.min()", "Infinity"); - fold("Math.min(3)", "3"); - fold("Math.min(0, 1)", "0"); - fold("Math.min(0, 1, -1, 200)", "-1"); + test("Math.min()", "Infinity"); + test("Math.min(3)", "3"); + test("Math.min(0, 1)", "0"); + test("Math.min(0, 1, -1, 200)", "-1"); } #[test] #[ignore] fn test_fold_math_functions_pow() { - fold("Math.pow(1, 2)", "1"); - fold("Math.pow(2, 0)", "1"); - fold("Math.pow(2, 2)", "4"); - fold("Math.pow(2, 32)", "4294967296"); - fold("Math.pow(Infinity, 0)", "1"); - fold("Math.pow(Infinity, 1)", "Infinity"); - fold("Math.pow('a', 33)", "NaN"); + test("Math.pow(1, 2)", "1"); + test("Math.pow(2, 0)", "1"); + test("Math.pow(2, 2)", "4"); + test("Math.pow(2, 32)", "4294967296"); + test("Math.pow(Infinity, 0)", "1"); + test("Math.pow(Infinity, 1)", "Infinity"); + test("Math.pow('a', 33)", "NaN"); } #[test] #[ignore] fn test_fold_number_functions_is_safe_integer() { - fold("Number.isSafeInteger(1)", "true"); - fold("Number.isSafeInteger(1.5)", "false"); - fold("Number.isSafeInteger(9007199254740991)", "true"); - fold("Number.isSafeInteger(9007199254740992)", "false"); - fold("Number.isSafeInteger(-9007199254740991)", "true"); - fold("Number.isSafeInteger(-9007199254740992)", "false"); + test("Number.isSafeInteger(1)", "true"); + test("Number.isSafeInteger(1.5)", "false"); + test("Number.isSafeInteger(9007199254740991)", "true"); + test("Number.isSafeInteger(9007199254740992)", "false"); + test("Number.isSafeInteger(-9007199254740991)", "true"); + test("Number.isSafeInteger(-9007199254740992)", "false"); } #[test] #[ignore] fn test_fold_number_functions_is_finite() { - fold("Number.isFinite(1)", "true"); - fold("Number.isFinite(1.5)", "true"); - fold("Number.isFinite(NaN)", "false"); - fold("Number.isFinite(Infinity)", "false"); - fold("Number.isFinite(-Infinity)", "false"); - fold_same("Number.isFinite('a')"); + test("Number.isFinite(1)", "true"); + test("Number.isFinite(1.5)", "true"); + test("Number.isFinite(NaN)", "false"); + test("Number.isFinite(Infinity)", "false"); + test("Number.isFinite(-Infinity)", "false"); + test_same("Number.isFinite('a')"); } #[test] #[ignore] fn test_fold_number_functions_is_nan() { - fold("Number.isNaN(1)", "false"); - fold("Number.isNaN(1.5)", "false"); - fold("Number.isNaN(NaN)", "true"); - fold_same("Number.isNaN('a')"); + test("Number.isNaN(1)", "false"); + test("Number.isNaN(1.5)", "false"); + test("Number.isNaN(NaN)", "true"); + test_same("Number.isNaN('a')"); // unknown function may have side effects - fold_same("Number.isNaN(+(void unknown()))"); + test_same("Number.isNaN(+(void unknown()))"); } #[test] #[ignore] fn test_fold_parse_numbers() { // Template Strings - fold_same("x = parseInt(`123`)"); - fold_same("x = parseInt(` 123`)"); - fold_same("x = parseInt(`12 ${a}`)"); - fold_same("x = parseFloat(`1.23`)"); + test_same("x = parseInt(`123`)"); + test_same("x = parseInt(` 123`)"); + test_same("x = parseInt(`12 ${a}`)"); + test_same("x = parseFloat(`1.23`)"); // setAcceptedLanguage(LanguageMode.ECMASCRIPT5); - fold("x = parseInt('123')", "x = 123"); - fold("x = parseInt(' 123')", "x = 123"); - fold("x = parseInt('123', 10)", "x = 123"); - fold("x = parseInt('0xA')", "x = 10"); - fold("x = parseInt('0xA', 16)", "x = 10"); - fold("x = parseInt('07', 8)", "x = 7"); - fold("x = parseInt('08')", "x = 8"); - fold("x = parseInt('0')", "x = 0"); - fold("x = parseInt('-0')", "x = -0"); - fold("x = parseFloat('0')", "x = 0"); - fold("x = parseFloat('1.23')", "x = 1.23"); - fold("x = parseFloat('-1.23')", "x = -1.23"); - fold("x = parseFloat('1.2300')", "x = 1.23"); - fold("x = parseFloat(' 0.3333')", "x = 0.3333"); - fold("x = parseFloat('0100')", "x = 100"); - fold("x = parseFloat('0100.000')", "x = 100"); + test("x = parseInt('123')", "x = 123"); + test("x = parseInt(' 123')", "x = 123"); + test("x = parseInt('123', 10)", "x = 123"); + test("x = parseInt('0xA')", "x = 10"); + test("x = parseInt('0xA', 16)", "x = 10"); + test("x = parseInt('07', 8)", "x = 7"); + test("x = parseInt('08')", "x = 8"); + test("x = parseInt('0')", "x = 0"); + test("x = parseInt('-0')", "x = -0"); + test("x = parseFloat('0')", "x = 0"); + test("x = parseFloat('1.23')", "x = 1.23"); + test("x = parseFloat('-1.23')", "x = -1.23"); + test("x = parseFloat('1.2300')", "x = 1.23"); + test("x = parseFloat(' 0.3333')", "x = 0.3333"); + test("x = parseFloat('0100')", "x = 100"); + test("x = parseFloat('0100.000')", "x = 100"); // Mozilla Dev Center test cases - fold("x = parseInt(' 0xF', 16)", "x = 15"); - fold("x = parseInt(' F', 16)", "x = 15"); - fold("x = parseInt('17', 8)", "x = 15"); - fold("x = parseInt('015', 10)", "x = 15"); - fold("x = parseInt('1111', 2)", "x = 15"); - fold("x = parseInt('12', 13)", "x = 15"); - fold("x = parseInt(15.99, 10)", "x = 15"); - fold("x = parseInt(-15.99, 10)", "x = -15"); + test("x = parseInt(' 0xF', 16)", "x = 15"); + test("x = parseInt(' F', 16)", "x = 15"); + test("x = parseInt('17', 8)", "x = 15"); + test("x = parseInt('015', 10)", "x = 15"); + test("x = parseInt('1111', 2)", "x = 15"); + test("x = parseInt('12', 13)", "x = 15"); + test("x = parseInt(15.99, 10)", "x = 15"); + test("x = parseInt(-15.99, 10)", "x = -15"); // Java's Integer.parseInt("-15.99", 10) throws an exception, because of the decimal point. - fold_same("x = parseInt('-15.99', 10)"); - fold("x = parseFloat('3.14')", "x = 3.14"); - fold("x = parseFloat(3.14)", "x = 3.14"); - fold("x = parseFloat(-3.14)", "x = -3.14"); - fold("x = parseFloat('-3.14')", "x = -3.14"); - fold("x = parseFloat('-0')", "x = -0"); + test_same("x = parseInt('-15.99', 10)"); + test("x = parseFloat('3.14')", "x = 3.14"); + test("x = parseFloat(3.14)", "x = 3.14"); + test("x = parseFloat(-3.14)", "x = -3.14"); + test("x = parseFloat('-3.14')", "x = -3.14"); + test("x = parseFloat('-0')", "x = -0"); // Valid calls - unable to fold - fold_same("x = parseInt('FXX123', 16)"); - fold_same("x = parseInt('15*3', 10)"); - fold_same("x = parseInt('15e2', 10)"); - fold_same("x = parseInt('15px', 10)"); - fold_same("x = parseInt('-0x08')"); - fold_same("x = parseInt('1', -1)"); - fold_same("x = parseFloat('3.14more non-digit characters')"); - fold_same("x = parseFloat('314e-2')"); - fold_same("x = parseFloat('0.0314E+2')"); - fold_same("x = parseFloat('3.333333333333333333333333')"); + test_same("x = parseInt('FXX123', 16)"); + test_same("x = parseInt('15*3', 10)"); + test_same("x = parseInt('15e2', 10)"); + test_same("x = parseInt('15px', 10)"); + test_same("x = parseInt('-0x08')"); + test_same("x = parseInt('1', -1)"); + test_same("x = parseFloat('3.14more non-digit characters')"); + test_same("x = parseFloat('314e-2')"); + test_same("x = parseFloat('0.0314E+2')"); + test_same("x = parseFloat('3.333333333333333333333333')"); // Invalid calls - fold_same("x = parseInt('0xa', 10)"); - fold_same("x = parseInt('')"); + test_same("x = parseInt('0xa', 10)"); + test_same("x = parseInt('')"); // setAcceptedLanguage(LanguageMode.ECMASCRIPT3); - fold_same("x = parseInt('08')"); + test_same("x = parseInt('08')"); } #[test] @@ -1172,8 +1152,8 @@ mod test { fn test_fold_parse_octal_numbers() { // setAcceptedLanguage(LanguageMode.ECMASCRIPT5); - fold("x = parseInt('021', 8)", "x = 17"); - fold("x = parseInt('-021', 8)", "x = -17"); + test("x = parseInt('021', 8)", "x = 17"); + test("x = parseInt('-021', 8)", "x = -17"); } #[test] @@ -1184,132 +1164,132 @@ mod test { // disableCompareJsDoc(); fold_string_typed("a.substring(0, 1)", "a.charAt(0)"); - fold_same_string_typed("a.substring(-4, -3)"); - fold_same_string_typed("a.substring(i, j + 1)"); - fold_same_string_typed("a.substring(i, i + 1)"); - fold_same_string_typed("a.substring(1, 2, 3)"); - fold_same_string_typed("a.substring()"); - fold_same_string_typed("a.substring(1)"); - fold_same_string_typed("a.substring(1, 3, 4)"); - fold_same_string_typed("a.substring(-1, 3)"); - fold_same_string_typed("a.substring(2, 1)"); - fold_same_string_typed("a.substring(3, 1)"); + test_same_string_typed("a.substring(-4, -3)"); + test_same_string_typed("a.substring(i, j + 1)"); + test_same_string_typed("a.substring(i, i + 1)"); + test_same_string_typed("a.substring(1, 2, 3)"); + test_same_string_typed("a.substring()"); + test_same_string_typed("a.substring(1)"); + test_same_string_typed("a.substring(1, 3, 4)"); + test_same_string_typed("a.substring(-1, 3)"); + test_same_string_typed("a.substring(2, 1)"); + test_same_string_typed("a.substring(3, 1)"); fold_string_typed("a.slice(4, 5)", "a.charAt(4)"); - fold_same_string_typed("a.slice(-2, -1)"); + test_same_string_typed("a.slice(-2, -1)"); fold_string_typed("var /** number */ i; a.slice(0, 1)", "var /** number */ i; a.charAt(0)"); - fold_same_string_typed("a.slice(i, j + 1)"); - fold_same_string_typed("a.slice(i, i + 1)"); - fold_same_string_typed("a.slice(1, 2, 3)"); - fold_same_string_typed("a.slice()"); - fold_same_string_typed("a.slice(1)"); - fold_same_string_typed("a.slice(1, 3, 4)"); - fold_same_string_typed("a.slice(-1, 3)"); - fold_same_string_typed("a.slice(2, 1)"); - fold_same_string_typed("a.slice(3, 1)"); + test_same_string_typed("a.slice(i, j + 1)"); + test_same_string_typed("a.slice(i, i + 1)"); + test_same_string_typed("a.slice(1, 2, 3)"); + test_same_string_typed("a.slice()"); + test_same_string_typed("a.slice(1)"); + test_same_string_typed("a.slice(1, 3, 4)"); + test_same_string_typed("a.slice(-1, 3)"); + test_same_string_typed("a.slice(2, 1)"); + test_same_string_typed("a.slice(3, 1)"); // enableTypeCheck(); - fold_same("function f(/** ? */ a) { a.substring(0, 1); }"); - // fold_same(lines( + test_same("function f(/** ? */ a) { a.substring(0, 1); }"); + // test_same(lines( // "/** @constructor */ function A() {};", // "A.prototype.substring = function(begin, end) {};", // "function f(/** !A */ a) { a.substring(0, 1); }", // )); - // fold_same(lines( + // test_same(lines( // "/** @constructor */ function A() {};", // "A.prototype.slice = function(begin, end) {};", // "function f(/** !A */ a) { a.slice(0, 1); }", // )); // useTypes = false; - fold_same_string_typed("a.substring(0, 1)"); - fold_same_string_typed("''.substring(i, i + 1)"); + test_same_string_typed("a.substring(0, 1)"); + test_same_string_typed("''.substring(i, i + 1)"); } #[test] fn test_fold_concat_chaining() { // array - fold("[1,2].concat(1).concat(2,['abc']).concat('abc')", "[1,2,1,2,'abc','abc']"); - fold("[].concat(['abc']).concat(1).concat([2,3])", "['abc',1,2,3]"); + test("[1,2].concat(1).concat(2,['abc']).concat('abc')", "[1,2,1,2,'abc','abc']"); + test("[].concat(['abc']).concat(1).concat([2,3])", "['abc',1,2,3]"); - fold("var x, y; [1].concat(x).concat(y)", "var x, y; [1].concat(x, y)"); - fold("var y; [1].concat(x).concat(y)", "var y; [1].concat(x, y)"); // x might have a getter that updates y, but that side effect is preserved correctly - fold("var x; [1].concat(x.a).concat(x)", "var x; [1].concat(x.a, x)"); // x.a might have a getter that updates x, but that side effect is preserved correctly + test("var x, y; [1].concat(x).concat(y)", "var x, y; [1].concat(x, y)"); + test("var y; [1].concat(x).concat(y)", "var y; [1].concat(x, y)"); // x might have a getter that updates y, but that side effect is preserved correctly + test("var x; [1].concat(x.a).concat(x)", "var x; [1].concat(x.a, x)"); // x.a might have a getter that updates x, but that side effect is preserved correctly // string - fold("'1'.concat(1).concat(2,['abc']).concat('abc')", "'1'.concat(1,2,['abc'],'abc')"); - fold("''.concat(['abc']).concat(1).concat([2,3])", "''.concat(['abc'],1,[2,3])"); - fold_same("''.concat(1)"); + test("'1'.concat(1).concat(2,['abc']).concat('abc')", "'1'.concat(1,2,['abc'],'abc')"); + test("''.concat(['abc']).concat(1).concat([2,3])", "''.concat(['abc'],1,[2,3])"); + test_same("''.concat(1)"); - fold("var x, y; ''.concat(x).concat(y)", "var x, y; ''.concat(x, y)"); - fold("var y; ''.concat(x).concat(y)", "var y; ''.concat(x, y)"); // x might have a getter that updates y, but that side effect is preserved correctly - fold("var x; ''.concat(x.a).concat(x)", "var x; ''.concat(x.a, x)"); // x.a might have a getter that updates x, but that side effect is preserved correctly + test("var x, y; ''.concat(x).concat(y)", "var x, y; ''.concat(x, y)"); + test("var y; ''.concat(x).concat(y)", "var y; ''.concat(x, y)"); // x might have a getter that updates y, but that side effect is preserved correctly + test("var x; ''.concat(x.a).concat(x)", "var x; ''.concat(x.a, x)"); // x.a might have a getter that updates x, but that side effect is preserved correctly // other - fold_same("obj.concat([1,2]).concat(1)"); + test_same("obj.concat([1,2]).concat(1)"); } #[test] fn test_remove_array_literal_from_front_of_concat() { - fold("[].concat([1,2,3],1)", "[1,2,3,1]"); + test("[].concat([1,2,3],1)", "[1,2,3,1]"); - fold_same("[1,2,3].concat(foo())"); + test_same("[1,2,3].concat(foo())"); // Call method with the same name as Array.prototype.concat - fold_same("obj.concat([1,2,3])"); + test_same("obj.concat([1,2,3])"); - fold("[].concat(1,[1,2,3])", "[1,1,2,3]"); - fold("[].concat(1)", "[1]"); - fold("[].concat([1])", "[1]"); + test("[].concat(1,[1,2,3])", "[1,1,2,3]"); + test("[].concat(1)", "[1]"); + test("[].concat([1])", "[1]"); // Chained folding of empty array lit - fold("[].concat([], [1,2,3], [4])", "[1,2,3,4]"); - fold("[].concat([]).concat([1]).concat([2,3])", "[1,2,3]"); + test("[].concat([], [1,2,3], [4])", "[1,2,3,4]"); + test("[].concat([]).concat([1]).concat([2,3])", "[1,2,3]"); - fold("[].concat(1, x)", "[1].concat(x)"); // x might be an array or an object with `Symbol.isConcatSpreadable` - fold("[].concat(1, ...x)", "[1].concat(...x)"); - fold_same("[].concat(x, 1)"); + test("[].concat(1, x)", "[1].concat(x)"); // x might be an array or an object with `Symbol.isConcatSpreadable` + test("[].concat(1, ...x)", "[1].concat(...x)"); + test_same("[].concat(x, 1)"); } #[test] #[ignore] fn test_array_of_spread() { - fold("x = Array.of(...['a', 'b', 'c'])", "x = [...['a', 'b', 'c']]"); - fold("x = Array.of(...['a', 'b', 'c',])", "x = [...['a', 'b', 'c']]"); - fold("x = Array.of(...['a'], ...['b', 'c'])", "x = [...['a'], ...['b', 'c']]"); - fold("x = Array.of('a', ...['b', 'c'])", "x = ['a', ...['b', 'c']]"); - fold("x = Array.of('a', ...['b', 'c'])", "x = ['a', ...['b', 'c']]"); + test("x = Array.of(...['a', 'b', 'c'])", "x = [...['a', 'b', 'c']]"); + test("x = Array.of(...['a', 'b', 'c',])", "x = [...['a', 'b', 'c']]"); + test("x = Array.of(...['a'], ...['b', 'c'])", "x = [...['a'], ...['b', 'c']]"); + test("x = Array.of('a', ...['b', 'c'])", "x = ['a', ...['b', 'c']]"); + test("x = Array.of('a', ...['b', 'c'])", "x = ['a', ...['b', 'c']]"); } #[test] #[ignore] fn test_array_of_no_spread() { - fold("x = Array.of('a', 'b', 'c')", "x = ['a', 'b', 'c']"); - fold("x = Array.of('a', ['b', 'c'])", "x = ['a', ['b', 'c']]"); - fold("x = Array.of('a', ['b', 'c'],)", "x = ['a', ['b', 'c']]"); + test("x = Array.of('a', 'b', 'c')", "x = ['a', 'b', 'c']"); + test("x = Array.of('a', ['b', 'c'])", "x = ['a', ['b', 'c']]"); + test("x = Array.of('a', ['b', 'c'],)", "x = ['a', ['b', 'c']]"); } #[test] #[ignore] fn test_array_of_no_args() { - fold("x = Array.of()", "x = []"); + test("x = Array.of()", "x = []"); } #[test] #[ignore] fn test_array_of_no_change() { - fold_same("x = Array.of.apply(window, ['a', 'b', 'c'])"); - fold_same("x = ['a', 'b', 'c']"); - fold_same("x = [Array.of, 'a', 'b', 'c']"); + test_same("x = Array.of.apply(window, ['a', 'b', 'c'])"); + test_same("x = ['a', 'b', 'c']"); + test_same("x = [Array.of, 'a', 'b', 'c']"); } #[test] #[ignore] fn test_fold_array_bug() { - fold_same("Array[123]()"); + test_same("Array[123]()"); } - fn fold_same_string_typed(js: &str) { + fn test_same_string_typed(js: &str) { fold_string_typed(js, js); } diff --git a/crates/oxc_minifier/src/ast_passes/peephole_substitute_alternate_syntax.rs b/crates/oxc_minifier/src/ast_passes/peephole_substitute_alternate_syntax.rs index 68ee28ca4cce5c..26a5f70cf773f9 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_substitute_alternate_syntax.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_substitute_alternate_syntax.rs @@ -1229,21 +1229,12 @@ impl<'a, 'b> PeepholeSubstituteAlternateSyntax { /// Port from #[cfg(test)] mod test { - use oxc_allocator::Allocator; use oxc_syntax::es_target::ESTarget; - use crate::tester; - - fn test(source_text: &str, expected: &str) { - let allocator = Allocator::default(); - let target = ESTarget::ESNext; - let mut pass = super::PeepholeSubstituteAlternateSyntax::new(target, false); - tester::test(&allocator, source_text, expected, &mut pass); - } - - fn test_same(source_text: &str) { - test(source_text, source_text); - } + use crate::{ + tester::{run, test, test_same}, + CompressOptions, + }; #[test] fn test_fold_return_result() { @@ -1386,11 +1377,12 @@ mod test { // This case is not supported, since the minifier does not support with statements // test_same("var x; with (z) { x = x || 1 }"); - let allocator = Allocator::default(); let target = ESTarget::ES2019; - let mut pass = super::PeepholeSubstituteAlternateSyntax::new(target, false); let code = "var x; x = x || 1"; - tester::test(&allocator, code, code, &mut pass); + assert_eq!( + run(code, Some(CompressOptions { target, ..CompressOptions::default() })), + run(code, None) + ); } #[test] @@ -1867,11 +1859,12 @@ mod test { // foo() might have a side effect test_same("foo().a || (foo().a = 3)"); - let allocator = Allocator::default(); let target = ESTarget::ES2019; - let mut pass = super::PeepholeSubstituteAlternateSyntax::new(target, false); let code = "x || (x = 3)"; - tester::test(&allocator, code, code, &mut pass); + assert_eq!( + run(code, Some(CompressOptions { target, ..CompressOptions::default() })), + run(code, None) + ); } #[test] @@ -2000,10 +1993,11 @@ mod test { test_same("try {} catch([e]) {}"); test_same("try {} catch({e}) {}"); - let allocator = Allocator::default(); let target = ESTarget::ES2018; - let mut pass = super::PeepholeSubstituteAlternateSyntax::new(target, false); let code = "try {} catch(e) {}"; - tester::test(&allocator, code, code, &mut pass); + assert_eq!( + run(code, Some(CompressOptions { target, ..CompressOptions::default() })), + run(code, None) + ); } } diff --git a/crates/oxc_minifier/src/ast_passes/remove_unused_code.rs b/crates/oxc_minifier/src/ast_passes/remove_unused_code.rs index b3c2e68ef58ba3..b38c712ab3429f 100644 --- a/crates/oxc_minifier/src/ast_passes/remove_unused_code.rs +++ b/crates/oxc_minifier/src/ast_passes/remove_unused_code.rs @@ -70,19 +70,7 @@ impl RemoveUnusedCode { #[cfg(test)] mod test { - use oxc_allocator::Allocator; - - use crate::tester; - - fn test(source_text: &str, expected: &str) { - let allocator = Allocator::default(); - let mut pass = super::RemoveUnusedCode::new(); - tester::test(&allocator, source_text, expected, &mut pass); - } - - fn test_same(source_text: &str) { - test(source_text, source_text); - } + use crate::tester::{test, test_same}; #[test] fn simple() { diff --git a/crates/oxc_minifier/src/ast_passes/statement_fusion.rs b/crates/oxc_minifier/src/ast_passes/statement_fusion.rs index 0c108052a68d0d..caa549371cd8fa 100644 --- a/crates/oxc_minifier/src/ast_passes/statement_fusion.rs +++ b/crates/oxc_minifier/src/ast_passes/statement_fusion.rs @@ -194,19 +194,7 @@ fn can_merge_block_stmt_member(node: &Statement) -> bool { #[cfg(test)] mod test { - use oxc_allocator::Allocator; - - use crate::tester; - - fn test(source_text: &str, expected: &str) { - let allocator = Allocator::default(); - let mut pass = super::StatementFusion::new(); - tester::test(&allocator, source_text, expected, &mut pass); - } - - fn test_same(source_text: &str) { - test(source_text, source_text); - } + use crate::tester::{test, test_same}; fn fuse(before: &str, after: &str) { test( diff --git a/crates/oxc_minifier/src/tester.rs b/crates/oxc_minifier/src/tester.rs index 7218fc13f13512..797f662169678e 100644 --- a/crates/oxc_minifier/src/tester.rs +++ b/crates/oxc_minifier/src/tester.rs @@ -1,59 +1,31 @@ use oxc_allocator::Allocator; use oxc_codegen::{CodeGenerator, CodegenOptions}; use oxc_parser::Parser; -use oxc_semantic::SemanticBuilder; use oxc_span::SourceType; -use oxc_traverse::ReusableTraverseCtx; -use crate::{ - ast_passes::{CompressorPass, Normalize, NormalizeOptions}, - CompressOptions, -}; +use crate::{CompressOptions, Compressor}; -pub fn test<'a, P: CompressorPass<'a>>( - allocator: &'a Allocator, - source_text: &'a str, - expected: &'a str, - pass: &mut P, -) { - test_impl(allocator, source_text, expected, pass, false); +pub fn test_same(source_text: &str) { + test(source_text, source_text); } -pub fn test_impl<'a, P: CompressorPass<'a>>( - allocator: &'a Allocator, - source_text: &'a str, - expected: &'a str, - pass: &mut P, - remove_whitespace: bool, -) { - let result = run(allocator, source_text, Some(pass), remove_whitespace); - let expected = run::

    (allocator, expected, None, remove_whitespace); +pub fn test(source_text: &str, expected: &str) { + let result = run(source_text, Some(CompressOptions::default())); + let expected = run(expected, None); assert_eq!(result, expected, "\nfor source\n{source_text}\nexpect\n{expected}\ngot\n{result}"); } -fn run<'a, P: CompressorPass<'a>>( - allocator: &'a Allocator, - source_text: &'a str, - pass: Option<&mut P>, - remove_whitespace: bool, -) -> String { +pub fn run(source_text: &str, options: Option) -> String { + let allocator = Allocator::default(); let source_type = SourceType::mjs(); - let mut program = Parser::new(allocator, source_text, source_type).parse().program; - - if let Some(pass) = pass { - let (symbols, scopes) = - SemanticBuilder::new().build(&program).semantic.into_symbol_table_and_scope_tree(); - let mut ctx = ReusableTraverseCtx::new(scopes, symbols, allocator); - let normalize_options = NormalizeOptions { convert_while_to_fors: true }; - Normalize::new(normalize_options, CompressOptions::all_false()) - .build(&mut program, &mut ctx); - pass.build(&mut program, &mut ctx); + let mut program = Parser::new(&allocator, source_text, source_type).parse().program; + if let Some(options) = options { + Compressor::new(&allocator, options).build(&mut program); } - CodeGenerator::new() .with_options(CodegenOptions { single_quote: true, - minify: remove_whitespace, + minify: false, ..CodegenOptions::default() }) .build(&program)