import { OnigurumaRegExp } from 'bun'; import { expect, it, test } from 'bun:test'; import { gc as gcTrace } from "./gc"; it("OnigurumaRegExp.prototype.exec()", () => { let a1 = new OnigurumaRegExp('(foo)', 'gd') let a1_1 = a1.exec('table football, foosball'); a1_1 = a1.exec('table football, foosball'); let a2 = new RegExp('(foo)', 'dg') let a2_1 = a2.exec('table football, foosball'); a2_1 = a2.exec('table football, foosball'); expect(a1_1[0]).toBe(a2_1[0]); expect(a1_1[1]).toBe(a2_1[1]); expect(a1_1.index).toBe(a2_1.index); expect(a1_1.input).toBe(a2_1.input); expect(a1.lastIndex).toBe(a2.lastIndex); expect(a1_1.groups).toBe(a2_1.groups); expect(a1_1.indices[0][0]).toBe(a2_1.indices[0][0]); expect(a1_1.indices[0][1]).toBe(a2_1.indices[0][1]); expect(a1_1.indices[1][0]).toBe(a2_1.indices[1][0]); expect(a1_1.indices[1][1]).toBe(a2_1.indices[1][1]); }); test("OnigurumaRegExp flag order", () => { expect(new OnigurumaRegExp('a', 'gd').toString()).toBe('/a/dg'); expect(new OnigurumaRegExp('a', 'ydmg').toString()).toBe('/a/dgmy'); }); test("OnigurumaRegExp.prototype.source", () => { let a1 = new OnigurumaRegExp('(foo)', 'gd') let a2 = new RegExp('(foo)', 'dg') expect(a1.source).toBe(a2.source); expect(new OnigurumaRegExp('/').source).toBe('\\/'); expect(new RegExp('/').source).toBe('\\/'); expect(new OnigurumaRegExp().source).toBe(new RegExp().source); expect(new OnigurumaRegExp('').source).toBe(new RegExp('').source); expect(new OnigurumaRegExp('a').source).toBe(new RegExp('a').source); expect(new OnigurumaRegExp('a', 'g').source).toBe(new RegExp('a', 'g').source); expect(new OnigurumaRegExp('/').source).toBe(new RegExp('/').source); expect(new OnigurumaRegExp('\n').source).toBe(new RegExp('\n').source); expect(new OnigurumaRegExp('\r').source).toBe(new RegExp('\r').source); }); test("OnigurumaRegExp.prototype.toString()", () => { expect(new OnigurumaRegExp().toString()).toBe(new RegExp().toString()); expect(new OnigurumaRegExp('').toString()).toBe(new RegExp('').toString()); expect(new OnigurumaRegExp('a').toString()).toBe(new RegExp('a').toString()); expect(new OnigurumaRegExp('a', 'g').toString()).toBe(new RegExp('a', 'g').toString()); expect(new OnigurumaRegExp('/').toString()).toBe(new RegExp('/').toString()); expect(new OnigurumaRegExp('\n').toString()).toBe(new RegExp('\n').toString()); expect(new OnigurumaRegExp('\r').toString()).toBe(new RegExp('\r').toString()); expect(new OnigurumaRegExp('jf/\.a.,voejpjoajglz;/qwjopeiv\\/\/\\/jpoqaj/Zdkj').toString()).toBe(new RegExp('jf/\.a.,voejpjoajglz;/qwjopeiv\\/\/\\/jpoqaj/Zdkj').toString()); }); test('OnigurumaRegExp flags', () => { // multiline option for (const RegExpConstructor of [OnigurumaRegExp, RegExp]) { expect(new RegExpConstructor('boat').test('sailor\nboat')).toBe(true); expect(new RegExpConstructor('^boat').test('sailor\nboat')).toBe(false); expect(new RegExpConstructor('^boat', 'm').test('sailor\nboat')).toBe(true); } // sticky option for (const RegExpConstructor of [RegExp]) { let str2 = 'sailor'; let h3 = new RegExpConstructor('or'); let h4 = new RegExpConstructor('or', 'y'); expect(h3.test(str2)).toBe(true); expect(h4.test(str2)).toBe(false); let g1 = new RegExpConstructor('sail'); let g2 = new RegExpConstructor('sail', 'y'); expect(g1.test(str2)).toBe(true); expect(g2.test(str2)).toBe(true); } // case insensitive option for (const RegExpConstructor of [OnigurumaRegExp, RegExp]) { expect(new RegExpConstructor('Is ThIs SqL?').test('IS THIS SQL?')).toBe(false); expect(new RegExpConstructor('Is ThIs SqL?', 'i').test('IS THIS SQL?')).toBe(true); } // dotall option for (const RegExpConstructor of [OnigurumaRegExp, RegExp]) { expect(new RegExpConstructor('a.b').test('a\nb')).toBe(false); expect(new RegExpConstructor('a.b', 's').test('a\nb')).toBe(true); } // indices option for (const RegExpConstructor of [OnigurumaRegExp, RegExp]) { expect(new RegExpConstructor('a', 'g').exec('a').indices).toBe(undefined); expect(new RegExpConstructor('a', 'gd').exec('a').index).toBe(0); expect(new RegExpConstructor('a', 'dg').exec('a').index).toBe(0); } }); test('OnigurumaRegExp.lastIndex', () => { for (const RegExpConstructor of [RegExp, OnigurumaRegExp]) { let a = new RegExpConstructor('foo', 'g'); expect(a.lastIndex).toBe(0); a.lastIndex = 1; expect(a.lastIndex).toBe(1); a.lastIndex = 0; expect(a.lastIndex).toBe(0); a.lastIndex = 1; expect(a.lastIndex).toBe(1); a.test('kfjekf'); expect(a.lastIndex).toBe(0); a.test('o'); expect(a.lastIndex).toBe(0); } let p1 = new OnigurumaRegExp('a'); expect(p1.lastIndex).toBe(0); p1.lastIndex = 2; expect(p1.lastIndex).toBe(2); let p2 = new OnigurumaRegExp('b'); expect(p2.lastIndex).toBe(0); p2.lastIndex = 2348; expect(p2.lastIndex).toBe(2348); expect(p1.lastIndex).toBe(2); for (const RegExpConstructor of [RegExp, OnigurumaRegExp]) { let a = new RegExpConstructor('foo', 'g'); a.lastIndex = 33; expect(a.lastIndex).toBe(33); a.compile('bar'); expect(a.lastIndex).toBe(0); a.lastIndex = 44; expect(a.lastIndex).toBe(44); } for (const RegExpConstructor of [OnigurumaRegExp]) { let a = new RegExpConstructor('foo', 'g'); expect(a.lastIndex).toBe(0); a.test('kfjekfoofjekf'); expect(a.lastIndex).toBe(8); a.test('kejfkjs'); expect(a.lastIndex).toBe(0); a.exec('kfjekfoofjekf'); expect(a.lastIndex).toBe(8); a.exec('kejfkjs'); expect(a.lastIndex).toBe(0); } }); test('OnigurumaRegExp errors', () => { let r = new OnigurumaRegExp('a', 'igsym'); let b = new OnigurumaRegExp('l', 'm'); try { r.compile(b, 'g'); } catch (e) { expect(e.message).toBe('Cannot supply flags when constructing one RegExp from another.'); } try { r.compile('ll', 'a'); } catch (e) { expect(e.message).toBe('Invalid flags supplied to RegExp constructor.'); } try { new OnigurumaRegExp('c', 'a'); } catch (e) { expect(e.message).toBe('Invalid flags supplied to RegExp constructor.'); } const invalidRegExpError = 'Invalid regular expression: '; try { new OnigurumaRegExp('?', 'g'); } catch (e) { expect(e.message.substring(0, invalidRegExpError.length)).toBe(invalidRegExpError); } try { new OnigurumaRegExp('?'); } catch (e) { expect(e.message.substring(0, invalidRegExpError.length)).toBe(invalidRegExpError); } try { r.compile('?', 'g'); } catch (e) { expect(e.message.substring(0, invalidRegExpError.length)).toBe(invalidRegExpError); } try { r.compile('?'); } catch (e) { expect(e.message.substring(0, invalidRegExpError.length)).toBe(invalidRegExpError); } try { new OnigurumaRegExp('\\'); } catch (e) { expect(e.message.substring(0, invalidRegExpError.length)).toBe(invalidRegExpError); } }) test('OnigurumaRegExp random', () => { expect(new OnigurumaRegExp("love").test("I love JavaScript")).toBe(true); expect(new RegExp("love").test("I love JavaScript")).toBe(true); expect(new OnigurumaRegExp('a').test('sailor')).toBe(true); expect(new OnigurumaRegExp('or').test('sailor')).toBe(true); expect(new RegExp('a').test('sailor')).toBe(true); expect(new RegExp('or').test('sailor')).toBe(true); expect(new OnigurumaRegExp('a').test('a')).toBe(true); expect(new OnigurumaRegExp('a').test('b')).toBe(false); expect(new OnigurumaRegExp('a', 'i').test('a')).toBe(true); expect(new OnigurumaRegExp('a', 'i').test('A')).toBe(true); expect(new OnigurumaRegExp('a', 'g').test('A')).toBe(false); expect(new OnigurumaRegExp('A', 'i').test('a')).toBe(true); expect(new OnigurumaRegExp('A', 'g').test('a')).toBe(false); expect(new OnigurumaRegExp('afasdfebadf', 'i').test('b')).toBe(false); let r = new OnigurumaRegExp('a', 'g'); expect(r.source).toBe('a'); expect(r.flags).toBe('g') expect(r.toString()).toBe('/a/g'); r.compile('b', 'i'); expect(r.source).toBe('b'); expect(r.flags).toBe('i'); expect(r.toString()).toBe('/b/i'); let b = new OnigurumaRegExp('l', 'm'); expect(r.compile(b)).toBe(undefined); expect(r.source).toBe('l'); expect(r.flags).toBe('m'); expect(r.toString()).toBe('/l/m'); expect(new OnigurumaRegExp('a', 'd').hasIndices).toBe(true); expect(new OnigurumaRegExp('a', 'i').hasIndices).toBe(false); expect(new OnigurumaRegExp('a', 's').dotAll).toBe(true); expect(new OnigurumaRegExp('a', 'i').dotAll).toBe(false); expect(new OnigurumaRegExp('a', 'i').ignoreCase).toBe(true); expect(new OnigurumaRegExp('a', 's').ignoreCase).toBe(false); expect(new OnigurumaRegExp('a', 'g').global).toBe(true); expect(new OnigurumaRegExp('a', 's').global).toBe(false); expect(new OnigurumaRegExp('a', 'm').multiline).toBe(true); expect(new OnigurumaRegExp('a', 's').multiline).toBe(false); expect(new OnigurumaRegExp('a', 'y').sticky).toBe(true); expect(new OnigurumaRegExp('a', 'i').sticky).toBe(false); expect(new OnigurumaRegExp('a', 'u').unicode).toBe(true); expect(new OnigurumaRegExp('a', 'd').unicode).toBe(false); expect(new RegExp('a', 'd').hasIndices).toBe(true); expect(new RegExp('a', 'i').hasIndices).toBe(false); expect(new RegExp('a', 's').dotAll).toBe(true); expect(new RegExp('a', 'i').dotAll).toBe(false); expect(new RegExp('a', 'i').ignoreCase).toBe(true); expect(new RegExp('a', 's').ignoreCase).toBe(false); expect(new RegExp('a', 'g').global).toBe(true); expect(new RegExp('a', 's').global).toBe(false); expect(new RegExp('a', 'm').multiline).toBe(true); expect(new RegExp('a', 's').multiline).toBe(false); expect(new RegExp('a', 'y').sticky).toBe(true); expect(new RegExp('a', 'i').sticky).toBe(false); expect(new RegExp('a', 'u').unicode).toBe(true); expect(new RegExp('a', 'd').unicode).toBe(false); }); it("String.prototype.replace", () => { for (let RegExpConstructor of [OnigurumaRegExp, RegExp]) { const r = new RegExpConstructor('a', 'g'); expect('a'.replace(r, 'b')).toBe('b'); expect('a'.replace(r, () => 'b')).toBe('b'); expect('a'.replace(r, (match, offset, string) => { expect(match).toBe('a'); expect(offset).toBe(0); expect(string).toBe('a'); return 'b'; })).toBe('b'); } expect('aaaaaa'.replace(new OnigurumaRegExp('a', 'g'), 'b')).toBe('bbbbbb'); expect('aaaaaa'.replace(new OnigurumaRegExp('a'), 'b')).toBe('baaaaa'); // case sensitive expect('aaaaaa'.replace(new OnigurumaRegExp('A', 'i'), 'b')).toBe('baaaaa'); expect('aaaaaa'.replace(new OnigurumaRegExp('A'), 'b')).toBe('aaaaaa'); expect('aaaaaa'.replace(new RegExp('a', 'g'), 'b')).toBe('bbbbbb'); expect('aaaaaa'.replace(new RegExp('a'), 'b')).toBe('baaaaa'); }); it("Strings.prototype.match", () => { let str = 'The rain in SPAIN stays mainly in the plain'; for (let RegExpConstructor of [OnigurumaRegExp, RegExp]) { let r1 = new RegExpConstructor('ain', 'g'); let m1 = str.match(r1); expect(m1[0]).toBe('ain'); expect(m1[1]).toBe('ain'); expect(m1[2]).toBe('ain'); r1.compile('ain', 'ig'); m1 = str.match(r1); expect(m1[0]).toBe('ain'); expect(m1[1]).toBe('AIN'); expect(m1[2]).toBe('ain'); expect(m1[3]).toBe('ain'); } }); it("String.prototype.matchAll", () => { let str = 'test1test2'; for (let RegExpConstructor of [RegExp, OnigurumaRegExp]) { const regexp = new RegExpConstructor('t(e)(st(\d?))', 'g'); const array = [...str.matchAll(regexp)]; expect(array[0][0]).toBe('test'); expect(array[0][1]).toBe('e'); expect(array[0][2]).toBe('st'); expect(array[0][3]).toBe(''); expect(array[1][0]).toBe('test'); expect(array[1][1]).toBe('e'); expect(array[1][2]).toBe('st'); expect(array[1][3]).toBe(''); } }); it("String.prototype.search", () => { let str = 'The rain in SPAIN stays mainly in the plain'; for (let RegExpConstructor of [OnigurumaRegExp, RegExp]) { let r1 = new RegExpConstructor('ain', 'g'); expect(str.search(r1)).toBe(5); r1.compile('ain', 'ig'); expect(str.search(r1)).toBe(5); } }); it("String.prototype.split", () => { let str = 'Hello World. How are you doing?'; for (let RegExpConstructor of [RegExp, OnigurumaRegExp]) { let r1 = new RegExpConstructor('\\s', 'g'); let m1 = str.split(r1); expect(m1[0]).toBe('Hello'); expect(m1[1]).toBe('World.'); expect(m1[2]).toBe('How'); expect(m1[3]).toBe('are'); expect(m1[4]).toBe('you'); expect(m1[5]).toBe('doing?'); } }); it("lookbehinds", () => { expect(/\d+(?=%)/.source).toBe('\\d+(?=%)'); expect(/\d+(?!%)/.source).toBe('\\d+(?!%)'); expect(/(?<=\$)\d+/.source).toBe('(?<=\\$)\\d+'); expect(/(?