From 50eec0025b482ad7b340c82f64749903b2fad4b8 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Fri, 20 Dec 2024 19:28:13 -0800 Subject: [PATCH] Add regression test for #15902 --- test/cli/run/syntax.test.ts | 340 ++++++++++++++++++++++++++++++++++++ 1 file changed, 340 insertions(+) create mode 100644 test/cli/run/syntax.test.ts diff --git a/test/cli/run/syntax.test.ts b/test/cli/run/syntax.test.ts new file mode 100644 index 00000000000000..8da864184f4d2a --- /dev/null +++ b/test/cli/run/syntax.test.ts @@ -0,0 +1,340 @@ +import { describe, expect, test } from "bun:test"; +import { bunEnv, bunExe, tempDirWithFiles } from "harness"; +import { join } from "path"; + +const exitCode0 = [ + " ", + "\n", + "\t", + "\r\n", + " ", + "\n\n\n", + "export default '\\u{000C}'", + "export default '\\u{200B}'", + "export default '\\u{200C}'", + "export default '\\u{200D}'", + "export default '\\u{FEFF}'", + '"use strict";', + '"use strict";\n', + "'use strict';", + '"use strict";\n\n', + '"use asm";', + '"use asm";\n', + "'use strict'; 'use asm';", + '"use strict"; "use strict";', + "// empty comment", + "/* empty block comment */", + "/** JSDoc comment */", + "//\n//\n//", + "/* \n Multi\n line\n comment\n */", + "-->", + "// TODO: ", + "/** @type {number} */", + "const a = 123;", + "let a;", + "var a = undefined;", + "const a = null;", + "const [a] = [];", + "const {a} = {};", + "const [...a] = [];", + "const {...a} = {};", + "let [a = 1] = [];", + "let {a: b = 1} = {};", + "``", + "`template`", + "`template${123}`", + "`${null}`", + "`${'`'}`", + "`\n`", + "`\n`", + "({});", + "({ a: 1 });", + "({ ['computed']: 1 });", + "({ get x() { return 1; } });", + "({ __proto__: null });", + "({ get [1+2](){}, set [1+2](x){} });", + "({ a: 1, ...{b: 2} });", + "[];", + "[,];", + "[,,];", + "[1,];", + "[,...[1]];", + "[,,...[1]];", + "[[[[[]]]]]", + "[...[...[...[]]]]", + "[1,,2,,3];", + "Array(1_000_000).fill(1);", + "()=>{};", + "async()=>{};", + "(function(){}).bind(null);", + "()=>()=>()=>1;", + "function f(a=1,{b}={},...c){};", + "async function* f(){await 1; yield 2;};", + "(async()=>await 1)();", + "class A{}", + "class A extends null{}", + "class A{#private=1}", + "class A{static{}}", + "class A{get #a(){} set #a(x){}}", + "class A{*#gen(){yield this.#p}#p=1}", + "class A extends class B{}{};", + "export {};", + "export default 1;", + "export default function(){};", + "import.meta.url;", + "const pi = Math.PI;", + "const hello = 'world';", + "const star = '⭐';", + "'\\u0000\\uFFFF';", + "'\\x00\\xFF';", + "const \\u{61} = 1;", + "'\\0';", + "'\\v\\f\\b';", + "'\\\r\n';", + "/./;", + "/[]/;", + "/[^]/;", + "/\\u{0}/u;", + "/[\\u0000-\\u{10FFFF}]/u;", + "/./gimsuyd;", + "/\\p{Script=Latin}/u;", + "/(?<=a)b/;", + "/(?/;", + "1n;", + "0n;", + "9007199254740991n;", + "0b1n;", + "0o7n;", + "0xFn;", + "1_2_3n;", + "BigInt(1);", + "-0n;", + "~0n;", + "0b1_0_1;", + "0o7_7_7;", + "0xF_F_F;", + "1_2_3_4;", + "try{}catch{}", + "try{}catch(e){}", + "try{}catch{}finally{}", + "try{}finally{}", + "try{throw 1}catch(e){}", + "try{throw new Error}catch{}", + "try{throw{}}catch({message}){}", + "try{throw null}catch(e){}", + "try{throw undefined}catch(e){}", + "try{throw function(){}}catch(e){}", + "function*g(){yield;}", + "function*g(){yield*g();}", + "async function*g(){yield;}", + "async function*g(){await 1;}", + "(async function*(){for await(x of y){}});", + "function*g(){try{yield}finally{}}", + "[...new Set];", + "for(x of[]){}", + "for await(x of[]){}", + "async function f(){for await(x of y){}}", + "void 0;", + "new (class{})();", + "(class extends null{});", + "(class{[Symbol.hasInstance](){}});", + "function*g(){yield yield yield;}", + "1..toString();", + "`${`${`${1}`}`}`", + "String.raw`\n`", + "String.raw`\\n`", + "`${`${function*(){yield 1}}`}`", + "`${class{}}${()=>{}}${/./}`", + "`${`${async()=>await 1}`}`", + "`${`${class{static{``}}}`}`", + "await import('bun');", + "await import('bun:ffi');", + "await import(import.meta.path);", + "/(?:)/", + "/\\b\\B\\d\\D\\w\\W\\s\\S/", + "/\\cA\\cZ\\ca\\cz/", + "/\\p{General_Category=Letter}/u", + "/\\p{Script_Extensions=Latin}/u", + "/(?<=(?=a)b)c/", + "/(?\\k/", + "/\\u{10FFFF}\\u{0000}/u", + "/[\\p{ASCII}--\\p{Decimal_Number}]/v", + "const [{a: [b = 1] = []} = [{a: [2]}]] = [];", + "let {a: {b: {c = 1} = {}} = {}} = {};", + "const [a, , ...{0: b, length}] = [];", + "const {[class{}.prop]: x} = {};", + "const {[()=>{}]: x} = {};", + "let {[/./]: x} = {};", + "const {[class extends null{}]: x} = {};", + "const {[function*(){}]: x} = {};", + "function f([a] = [1], {b} = {b: 2}, ...c){}", + "(function({[key]: value} = {}){})", + "(({[this?.prop]: x} = {})=>{})", + "function f(a = () => b, b = 1){}", + "(a = class{}, b = new a)=>{}", + "function f(a = new.target){}", + "for await(const x of async function*(){yield 1}()){}", + "for(const x of function*(){yield 1}()){}", + "for(const {[key]: x} of []){}", + "for(let [{a = 1} = {}] of []){}", + "do{continue}while(false);", + "label:do{break label}while(false);", + "outer:for(;;)inner:break outer;", + "block:{break block;}", + "while(false)with(null);", + "switch(0){case 1:default:case 2:}", + "try{throw async()=>{}}catch(e){await e}", + "try{throw class{}}catch(e){new e}", + "try{throw{[Symbol.iterator]:()=>{}}}catch(e){}", + "try{throw Object.create(null)}catch(e){}", + "try{throw new Proxy({},{})}catch(e){}", + "try{throw new WeakMap}catch(e){}", + "try{throw new Int32Array}catch(e){}", + "try{throw new SharedArrayBuffer(0)}catch(e){}", + "try{throw new WebAssembly.Module(new Uint8Array)}catch(e){}", + "void void void 0;", + "typeof typeof typeof 0;", + "delete (delete (delete 0));", + "await (await (await 1));", + "--{a:1}.a;", + "(class{}).prototype.constructor;", + "(()=>{}).prototype?.call;", + "(async()=>{}).prototype?.call;", + "(function*(){}).prototype.next;", + "(async function*(){}).prototype.next;", + "this?.prop?.[key]?.();", + "0b0_1_0_1;", + "0B0_1_0_1;", + "0o0_1_2_3;", + "0O0_1_2_3;", + "0x0_1_2_3;", + "0X0_1_2_3;", + "1_2_3.4_5_6;", + "1_2_3e1_2_3;", + "1_2_3E1_2_3;", + ".0_1_2_3;", + "0b1_0_1n;", + "0B1_0_1n;", + "0o1_2_3n;", + "0O1_2_3n;", + "0x1_2_3n;", + "0X1_2_3n;", + "1_2_3_4_5n;", + "BigInt(0b101);", + "BigInt(0o777);", + "BigInt(0xff);", + "for(const [,,...a] of [[]]){}", + "for(let {a: [b]} of []){}", + "for await(const [a = await 1] of []){}", + "for(const {[await 1]: x} of []){}", + "for(var {[class{}]: x} of []){}", + "for(let {[/./]: x} of []){}", + "for(const {[`${a}`]: x} of []){}", + "for await(const x of async function*(){yield*[1,2,3]}()){}", + "new class extends (await Promise.resolve(class{})){}", + "function*g(){yield yield*function*(){yield yield yield;}();}", + "async function*f(){yield await Promise.all([1,2,3])}", + "async function*f(){yield*[await 1,await 2]}", + "(async function(){await (async()=>1)()})();", + "async function*f(){for await(const x of async function*(){yield 1}())yield x}", + "async function f(){return await new Promise(r=>r(1))}", + "async function*f(){try{yield await 1}finally{await 2}}", + "(async()=>{for await(const x of[])for await(const y of[]){}})();", + "async function*f(){yield await(yield await(yield await 1))}", + "async function*f(){yield*async function*(){yield await 1}()}", + "export default await(async()=>1)();", + "function*g(){yield*{[Symbol.iterator]:function*(){yield 1}}}", + "function*g(){yield*{async*[Symbol.asyncIterator](){yield 1}}}", + "function*g(){yield*function*(){yield function*(){yield 1}}()}", + "function*g(){yield*{get[Symbol.iterator](){return function*(){yield 1}}}}", + "function*g(){yield*(class{static*[Symbol.iterator](){yield 1}});}", + "function*g(){yield*class{static*[Symbol.iterator](){yield 1}}}", + "function*g(){yield*{*[Symbol.iterator](){yield class{}}}}", + "function*g(){yield*{*[Symbol.iterator](){yield function(){}}}}", + "function*g(){yield*{*[Symbol.iterator](){yield async()=>{}}}}", + "function*g(){yield*{*[Symbol.iterator](){yield function*(){}}}}", + "({[function*(){yield 1}]:1});", + "({[async function*(){yield 1}]:1});", + "({[(()=>class{})()]:1});", + "({[new class{valueOf(){return 1}}]:2});", + "({[new class{[Symbol.toPrimitive](){return 1}}]:2});", + "({[new class{toString(){return '1'}}]:2});", + "({[new class{get [Symbol.toPrimitive](){return()=>1}}]:2});", + "({[new class{static{this.prototype.valueOf=()=>1}}]:2});", + "label:while(1)try{continue label}finally{break label}", + "new Proxy(class{},{construct(){return{}}});", + "new Proxy(function(){},{apply(){return{}}});", + "new Proxy({},{get(){return new Proxy({},{})}})", + "new Proxy([],{get(){return new Proxy({},{})}});", + "new Proxy(function(){},{construct(){return new Proxy({},{})}})", + "new Proxy(class{},{construct(){return new Proxy({},{})}})", + "new Proxy({},{get(){return function(){return new Proxy({},{})}}})", + "new Proxy(function(){},{apply(){return new Proxy(class{},{})}})", + "new Proxy(class{},{construct(){return new Proxy(function(){},{})}})", + "Reflect.get(new Proxy({},{}),'')", + "Reflect.set(new Proxy({},{}),'')", + "Reflect.has(new Proxy({},{}),'')", + "Reflect.deleteProperty(new Proxy({},{}),'')", + "Reflect.getOwnPropertyDescriptor(new Proxy({},{}),'')", + "Reflect.getPrototypeOf(new Proxy({},{}))", + "Reflect.setPrototypeOf(new Proxy({},{}),{})", + "Reflect.isExtensible(new Proxy({},{}))", + "Reflect.preventExtensions(new Proxy({},{}))", + "Promise.all([Promise.race([]),Promise.allSettled([])])", + "Promise.race([Promise.all([]),Promise.any([])])", + "Promise.allSettled([Promise.race([]),Promise.all([])])", + "Promise.any([Promise.allSettled([]),Promise.race([])])", + "Promise.resolve(Promise.reject().catch(()=>Promise.all([])))", + "new Function(`return function*(){${`yield${`yield${`yield`}`}`}}`)();", + "new Function(`return async()=>${`await${`await${`1`}`}`}`)();", + "new Function(`return class{${`*[Symbol.iterator](){${`yield 1`}}`}}`)();", + "new Function(`return class{${`async*[Symbol.asyncIterator](){${`yield 1`}}`}}`)();", + "new Function(`return class{${`get #a(){${`return 1`}}`}}`)();", + "new Function(`return class{${`set #a(v){${`this.#b=v`}}#b`}}`)();", + "new Function(`return class{${`#a;${`#b;${`#c`}`}`}}`)();", + "for await(let {...x} of async function*(){yield*[]}()){}", + "for await(const x of (async function*(){yield await 1})()){}", + "function f(){let a=b,b=1}", + "(function(){const[a=b,b=1]=[]})", + "(()=>{let{a=b,b=1}={}})", +]; + +describe("exit code 0", () => { + const fixturePath = tempDirWithFiles("fixture", { + [`package.json`]: `{ + "name": "test", + + }`, + "fixture.js": "export default 1", + }); + + for (let i = 0; i < exitCode0.length; i++) { + const source = exitCode0[i]; + + test(`file #${i}: ${JSON.stringify(source)}`, async () => { + await Bun.write(join(fixturePath, "fixture.js"), source); + await using proc = Bun.spawn([bunExe(), "./fixture.js"], { + stdout: "inherit", + env: bunEnv, + cwd: fixturePath, + stderr: "inherit", + stdin: "inherit", + }); + const exitCode = await proc.exited; + expect(exitCode).toBe(0); + }); + + test(`eval #${i}: ${JSON.stringify(source)}`, async () => { + await using proc = Bun.spawn([bunExe(), "--eval", source], { + stdout: "inherit", + env: bunEnv, + stderr: "inherit", + stdin: "inherit", + }); + const exitCode = await proc.exited; + expect(exitCode).toBe(0); + }); + } +});