public void Properties() { EcmaValue iterator = RegExp.Construct(".").Invoke(Symbol.MatchAll, ""); EcmaValue proto = Object.Invoke("getPrototypeOf", iterator); That(proto, Has.OwnProperty(WellKnownSymbol.ToStringTag, "RegExp String Iterator", EcmaPropertyAttributes.Configurable)); }
public void Constructor(RuntimeFunction ctor) { IsConstructorWLength(ctor, "RegExp", 2, RegExp.Prototype); It("should not throw TypeError when pattern has a [[RegExpMatcher]] internal slot", () => { EcmaValue re = RegExp.Construct(RegExp.Construct(), "g"); That(re["global"], Is.EqualTo(true)); }); It("should return its input argument if ToBoolean(@@match) is true and constructor is RegExp", () => { EcmaValue obj = new EcmaObject(); obj["constructor"] = RegExp; obj[WellKnownSymbol.Match] = true; Case((RegExp, obj), obj); obj[WellKnownSymbol.Match] = "string"; Case((RegExp, obj), obj); obj[WellKnownSymbol.Match] = new EcmaArray(); Case((RegExp, obj), obj); obj[WellKnownSymbol.Match] = new Symbol(); Case((RegExp, obj), obj); obj[WellKnownSymbol.Match] = 86; Case((RegExp, obj), obj); EcmaValue re1 = RegExp.Construct("(?:)"); re1[WellKnownSymbol.Match] = false; Case((RegExp, re1), Is.Not.EqualTo(re1)); EcmaValue re2 = RegExp.Construct("(?:)"); re2["constructor"] = Null; Case((RegExp, re2), Is.Not.EqualTo(re2)); });
public void Exec(RuntimeFunction exec) { IsUnconstructableFunctionWLength(exec, "exec", 1); IsAbruptedFromToPrimitive(exec.Bind(RegExp.Construct())); RequireThisRegExpObject(); It("should coerce its argument to string", () => { object undefined = Undefined; VerifyMatch(@"1|12", "123", new[] { "1" }, 0); VerifyMatch(@"1|12", 1.01, new[] { "1" }, 0); VerifyMatch(@"2|12", Number.Construct(1.012), new[] { "12" }, 3); VerifyMatch(@"\.14", CreateObject(toString: () => EcmaMath.PI), new[] { ".14" }, 1); VerifyMatch(@"t[a-b|q-s]", true, new[] { "tr" }, 0); VerifyMatch(@"AL|se", Boolean.Construct(), new[] { "se" }, 3); VerifyMatch(@"LS", "i", CreateObject(toString: () => false), new[] { "ls" }, 2); VerifyMatch(@"ll|l", Null, new[] { "ll" }, 2); VerifyMatch(@"nd|ne", Undefined, new[] { "nd" }, 1); VerifyMatch(@"((1)|(12))((3)|(23))", String.Construct("123"), new[] { "123", "1", "1", undefined, "23", undefined, "23" }, 0); VerifyMatch(@"a[a-z]{2,4}", Object.Construct("abcdefghi"), new[] { "abcde" }, 0); VerifyMatch(@"a[a-z]{2,4}?", CreateObject(toString: () => "abcdefghi"), new[] { "abc" }, 0); VerifyMatch(@"(aa|aabaac|ba|b|c)*", CreateObject(toString: () => new EcmaObject(), valueOf: () => "aabaac"), new[] { "aaba", "ba" }, 0); }); It("should read and reset lastIndex to 0 when global is set and the match fails", () => { EcmaValue re = RegExp.Construct("a", "g"); int lastIndexReads = 0; re["lastIndex"] = CreateObject(valueOf: () => { lastIndexReads++; return(42); }); Case((re, "abc"), Null); That(re["lastIndex"], Is.EqualTo(0)); That(lastIndexReads, Is.EqualTo(1)); lastIndexReads = 0; re["lastIndex"] = CreateObject(valueOf: () => { lastIndexReads++; return(-1); }); Case((re, "nbc"), Null); That(re["lastIndex"], Is.EqualTo(0)); That(lastIndexReads, Is.EqualTo(1)); });
public static void VerifyMatch(EcmaValue pattern, EcmaValue flags, EcmaValue input, object[] expected, int index) { EcmaValue re = default; That(() => re = RegExp.Construct(pattern, flags), Throws.Nothing, FormatArguments(Undefined, new[] { pattern, flags })); RuntimeObject fn = TestContext.CurrentContext.Test.Arguments.FirstOrDefault() as RuntimeObject; if (fn == null || fn.IsIntrinsicFunction(WellKnownObject.RegExpPrototype, "test")) { fn = re.ToObject().GetMethod("exec"); } EcmaValue actual = fn.Call(re, input); if (expected != null) { That(actual, Is.EquivalentTo(expected), "RegExp={0}, Input={1}", re, input); That(actual["index"], Is.EqualTo(index), "RegExp={0}, Input={1}", re, input); } else { That(actual, Is.EqualTo(Null), "RegExp={0}, Input={1}", re, input); } }
public void Next(RuntimeFunction next) { IsUnconstructableFunctionWLength(next, "next", 0); It("should throw a TypeError if this value does not have all of the internal slots", () => { EcmaValue iterator = RegExp.Construct(".").Invoke(Symbol.MatchAll, ""); That(() => iterator["next"].Call(Undefined), Throws.TypeError); That(() => iterator["next"].Call(Null), Throws.TypeError); That(() => iterator["next"].Call(1), Throws.TypeError); That(() => iterator["next"].Call(false), Throws.TypeError); That(() => iterator["next"].Call(""), Throws.TypeError); That(() => iterator["next"].Call(new Symbol()), Throws.TypeError); That(() => Object.Invoke("create", iterator).Invoke("next"), Throws.TypeError); }); It("should iterate over matches", () => { EcmaValue iterator = RegExp.Construct("\\w").Invoke(Symbol.MatchAll, "*a*b*"); VerifyIteratorResult(iterator.Invoke("next"), false, v => VerifyMatchObject(v, new[] { "a" }, 1, "*a*b*")); VerifyIteratorResult(iterator.Invoke("next"), true); iterator = RegExp.Construct("\\w", "g").Invoke(Symbol.MatchAll, "*a*b*"); VerifyIteratorResult(iterator.Invoke("next"), false, v => VerifyMatchObject(v, new[] { "a" }, 1, "*a*b*")); VerifyIteratorResult(iterator.Invoke("next"), false, v => VerifyMatchObject(v, new[] { "b" }, 3, "*a*b*")); VerifyIteratorResult(iterator.Invoke("next"), true); }); It("should not throw if exec is not callable", () => { foreach (EcmaValue value in new[] { Undefined, Null, 4, true, new Symbol() }) { using (TempProperty(RegExp.Prototype, "exec", value)) { EcmaValue iterator = RegExp.Construct("\\w", "g").Invoke(Symbol.MatchAll, "*a*b*"); VerifyIteratorResult(iterator.Invoke("next"), false, v => VerifyMatchObject(v, new[] { "a" }, 1, "*a*b*")); VerifyIteratorResult(iterator.Invoke("next"), false, v => VerifyMatchObject(v, new[] { "b" }, 3, "*a*b*")); VerifyIteratorResult(iterator.Invoke("next"), true); } } }); It("should re-throw errors thrown coercing RegExp's lastIndex to a length", () => { EcmaValue iterator = RegExp.Construct(".", "g").Invoke(Symbol.MatchAll, ""); using (TempProperty(RegExp.Prototype, "exec", FunctionLiteral(() => Return(This.ToObject()["lastIndex"] = CreateObject(valueOf: ThrowTest262Exception), EcmaArray.Of(""))))) { Case(iterator, Throws.Test262); } }); It("should return abrupt from calling exec", () => { EcmaValue iterator = RegExp.Construct(".").Invoke(Symbol.MatchAll, ""); using (TempProperty(RegExp.Prototype, "exec", ThrowTest262Exception)) { Case(iterator, Throws.Test262); } }); It("should return abrupt from getting exec", () => { EcmaValue iterator = RegExp.Construct(".").Invoke(Symbol.MatchAll, ""); using (TempProperty(RegExp.Prototype, "exec", new EcmaPropertyDescriptor(ThrowTest262Exception, Null))) { Case(iterator, Throws.Test262); } }); It("should return abrupt from accessing the first match", () => { EcmaValue iterator = RegExp.Construct(".").Invoke(Symbol.MatchAll, ""); using (TempProperty(RegExp.Prototype, "exec", FunctionLiteral(() => CreateObject((0, get: ThrowTest262Exception, set: null))))) { Case(iterator, Throws.Test262); } });
public static void VerifyMatch(EcmaValue pattern, EcmaValue flags, EcmaValue input, bool success) { That(RegExp.Construct(pattern, flags).Invoke("test", input), Is.EqualTo(success), FormatArguments(pattern, new[] { input })); }
public static void Throw(string pattern, string flags) { That(() => RegExp.Construct(pattern, flags), Throws.SyntaxError, pattern); }
public void CharacterClassEscape() { It("should detect a-z, A-Z, 0-9, _ using \\w", () => { EcmaValue re = RegExp.Construct("\\w"); string wordChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; string result = ""; for (int j = 0x0000; j < 0x10000; j++) { EcmaValue str = String.Invoke("fromCharCode", j); if (re.Invoke("test", str)) { result += (string)str; } } That(result, Is.EqualTo(wordChars)); }); It("should detect characters other than a-z, A-Z, 0-9, _ using \\W", () => { EcmaValue re = RegExp.Construct("\\W"); string wordChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; string result = ""; for (int j = 0x0000; j < 0x10000; j++) { EcmaValue str = String.Invoke("fromCharCode", j); if (!(bool)re.Invoke("test", str)) { result += (string)str; } } That(result, Is.EqualTo(wordChars)); }); It("should detect non WhiteSpace using \\S", () => { EcmaValue re = RegExp.Construct("\\S"); int[] whitespaceChars = { 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x0020, 0x00A0, 0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x2028, 0x2029, 0x202F, 0x205F, 0x3000 }; List <int> result = new List <int>(); for (int j = 0x0000; j < 0x10000; j++) { if (j == 0x180E) { continue; } // Skip 0x180E, current test in a separate file if (j == 0xFEFF) { continue; } // Ignore BOM if (!(bool)re.Invoke("test", String.Invoke("fromCharCode", j))) { result.Add(j); } } That(result, Is.EquivalentTo(whitespaceChars)); // The Mongolian Vowel Separator (u180e) became a non whitespace character since Unicode 6.3.0 VerifyMatch(re, "\u180E", true); }); It("should only recognize \\p{name} and \\P{name} escape sequence when [[Unicode]] flag is present", () => { VerifyMatch("\\p{Ll}", "a", false); VerifyMatch("\\P{Ll}", "A", false); VerifyMatch("\\p{Ll}", "u", "a", true); VerifyMatch("\\P{Ll}", "u", "A", true); }); }
public void ToString(RuntimeFunction toString) { IsUnconstructableFunctionWLength(toString, "toString", 0); EcmaValue obj = new EcmaObject(); DefineProperty(obj, Symbol.ToStringTag, get: ThrowTest262Exception); Case(obj, Throws.Test262); EcmaValue args = default; FunctionLiteral(() => args = Arguments).Call(); Case(args, "[object Arguments]"); Case(new EcmaArray(), "[object Array]"); Case(true, "[object Boolean]"); Case(Boolean.Call(_, true), "[object Boolean]"); Case(Boolean.Construct(true), "[object Boolean]"); Case(Object.Call(_, true), "[object Boolean]"); Case(Object.Call(_, Boolean.Call(true)), "[object Boolean]"); Case(Object.Call(_, Boolean.Construct(true)), "[object Boolean]"); Case(new EcmaDate(), "[object Date]"); Case(Object.Call(_, new EcmaDate()), "[object Date]"); Case(FunctionLiteral(() => Undefined), "[object Function]"); Case(Null, "[object Null]"); Case(42, "[object Number]"); Case(Number.Call(_, 42), "[object Number]"); Case(Number.Construct(42), "[object Number]"); Case(Object.Call(_, 42), "[object Number]"); Case(Object.Call(_, Number.Call(42)), "[object Number]"); Case(Object.Call(_, Number.Construct(42)), "[object Number]"); Case(Object.Prototype, "[object Object]"); Case(new EcmaObject(), "[object Object]"); Case(RegExp.Construct("."), "[object RegExp]"); Case("", "[object String]"); Case(String.Call(_, ""), "[object String]"); Case(String.Construct(""), "[object String]"); Case(Object.Call(_, ""), "[object String]"); Case(Object.Call(_, String.Call("")), "[object String]"); Case(Object.Call(_, String.Construct("")), "[object String]"); Case(Undefined, "[object Undefined]"); Case(Proxy.Construct(Array.Construct(), Object.Construct()), "[object Array]"); // Non-string values of `@@toStringTag` property are ignored Case(CreateObject((Symbol.ToStringTag, Undefined)), "[object Object]"); Case(CreateObject((Symbol.ToStringTag, Null)), "[object Object]"); Case(CreateObject((Symbol.ToStringTag, Symbol.ToStringTag)), "[object Object]"); Case(CreateObject((Symbol.ToStringTag, 42)), "[object Object]"); Case(CreateObject((Symbol.ToStringTag, String.Construct(""))), "[object Object]"); Case(CreateObject((Symbol.ToStringTag, new EcmaObject())), "[object Object]"); Case(CreateObject((Symbol.ToStringTag, FunctionLiteral(() => ""))), "[object Object]"); }