michael@0: /* michael@0: * Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/licenses/publicdomain/ michael@0: */ michael@0: michael@0: var BUGNUMBER = 640072; michael@0: var summary = michael@0: "Represent /a/.{lastIndex,global,source,multiline,sticky,ignoreCase} with " + michael@0: "plain old data properties"; michael@0: michael@0: print(BUGNUMBER + ": " + summary); michael@0: michael@0: /************** michael@0: * BEGIN TEST * michael@0: **************/ michael@0: michael@0: function checkDataProperty(obj, p, expect, msg) michael@0: { michael@0: var d = Object.getOwnPropertyDescriptor(obj, p); michael@0: michael@0: assertEq(d.value, expect.value, msg + ": bad value for " + p); michael@0: assertEq(d.writable, expect.writable, msg + ": bad writable for " + p); michael@0: assertEq(d.enumerable, expect.enumerable, msg + ": bad enumerable for " + p); michael@0: assertEq(d.configurable, expect.configurable, msg + ": bad configurable for " + p); michael@0: michael@0: // Try redefining the property using its initial values: these should all be michael@0: // silent no-ops. michael@0: Object.defineProperty(obj, p, { value: expect.value }); michael@0: Object.defineProperty(obj, p, { writable: expect.writable }); michael@0: Object.defineProperty(obj, p, { enumerable: expect.enumerable }); michael@0: Object.defineProperty(obj, p, { configurable: expect.configurable }); michael@0: michael@0: var d2 = Object.getOwnPropertyDescriptor(obj, p); michael@0: assertEq(d.value, d2.value, msg + ": value changed on redefinition of " + p + "?"); michael@0: assertEq(d.writable, d2.writable, msg + ": writable changed on redefinition of " + p + "?"); michael@0: assertEq(d.enumerable, d2.enumerable, msg + ": enumerable changed on redefinition of " + p + "?"); michael@0: assertEq(d.configurable, d2.configurable, msg + ": configurable changed on redefinition of " + p + "?"); michael@0: } michael@0: michael@0: michael@0: // Check a bunch of "empty" regular expressions first. michael@0: michael@0: var choices = [{ msg: "RegExp.prototype", michael@0: get: function() { return RegExp.prototype; } }, michael@0: { msg: "new RegExp()", michael@0: get: function() { return new RegExp(); } }, michael@0: { msg: "/(?:)/", michael@0: get: Function("return /(?:)/;") }]; michael@0: michael@0: function checkRegExp(r, msg, lastIndex, global, ignoreCase, multiline) michael@0: { michael@0: var expect; michael@0: michael@0: expect = { value: lastIndex, enumerable: false, configurable: false, writable: true }; michael@0: checkDataProperty(r, "lastIndex", expect, msg); michael@0: michael@0: // check source specially: its value is under-defined in the spec michael@0: var d = Object.getOwnPropertyDescriptor(r, "source"); michael@0: assertEq(d.writable, false, "bad writable: " + msg); michael@0: assertEq(d.enumerable, false, "bad enumerable: " + msg); michael@0: assertEq(d.configurable, false, "bad configurable: " + msg); michael@0: michael@0: expect = { value: global, enumerable: false, configurable: false, writable: false }; michael@0: checkDataProperty(r, "global", expect, msg); michael@0: michael@0: expect = { value: ignoreCase, enumerable: false, configurable: false, writable: false }; michael@0: checkDataProperty(r, "ignoreCase", expect, msg); michael@0: michael@0: expect = { value: multiline, enumerable: false, configurable: false, writable: false }; michael@0: checkDataProperty(r, "multiline", expect, msg); michael@0: } michael@0: michael@0: checkRegExp(RegExp.prototype, "RegExp.prototype", 0, false, false, false); michael@0: checkRegExp(new RegExp(), "new RegExp()", 0, false, false, false); michael@0: checkRegExp(/(?:)/, "/(?:)/", 0, false, false, false); michael@0: checkRegExp(Function("return /(?:)/;")(), 'Function("return /(?:)/;")()', 0, false, false, false); michael@0: michael@0: for (var i = 0; i < choices.length; i++) michael@0: { michael@0: var choice = choices[i]; michael@0: var msg = choice.msg; michael@0: var r = choice.get(); michael@0: michael@0: checkRegExp(r, msg, 0, false, false, false); michael@0: } michael@0: michael@0: // Now test less generic regular expressions michael@0: michael@0: checkRegExp(/a/gim, "/a/gim", 0, true, true, true); michael@0: michael@0: var r; michael@0: michael@0: do michael@0: { michael@0: r = /abcd/mg; michael@0: checkRegExp(r, "/abcd/mg initially", 0, true, false, true); michael@0: r.exec("abcdefg"); michael@0: checkRegExp(r, "/abcd/mg step 1", 4, true, false, true); michael@0: r.exec("abcdabcd"); michael@0: checkRegExp(r, "/abcd/mg step 2", 8, true, false, true); michael@0: r.exec("abcdabcd"); michael@0: checkRegExp(r, "/abcd/mg end", 0, true, false, true); michael@0: michael@0: r = /cde/ig; michael@0: checkRegExp(r, "/cde/ig initially", 0, true, true, false); michael@0: var obj = r.lastIndex = { valueOf: function() { return 2; } }; michael@0: checkRegExp(r, "/cde/ig after lastIndex", obj, true, true, false); michael@0: r.exec("aaacdef"); michael@0: checkRegExp(r, "/cde/ig after exec", 6, true, true, false); michael@0: Object.defineProperty(r, "lastIndex", { value: 3 }); michael@0: checkRegExp(r, "/cde/ig after define 3", 3, true, true, false); michael@0: Object.defineProperty(r, "lastIndex", { value: obj }); michael@0: checkRegExp(r, "/cde/ig after lastIndex", obj, true, true, false); michael@0: michael@0: michael@0: // Tricky bits of testing: make sure that redefining lastIndex doesn't change michael@0: // the slot where the lastIndex property is initially stored, even if michael@0: // the redefinition also changes writability. michael@0: r = /a/g; michael@0: checkRegExp(r, "/a/g initially", 0, true, false, false); michael@0: Object.defineProperty(r, "lastIndex", { value: 2 }); michael@0: r.exec("aabbbba"); michael@0: checkRegExp(r, "/a/g after first exec", 7, true, false, false); michael@0: assertEq(r.lastIndex, 7); michael@0: r.lastIndex = 2; michael@0: checkRegExp(r, "/a/g after assign", 2, true, false, false); michael@0: r.exec("aabbbba"); michael@0: assertEq(r.lastIndex, 7); // check in reverse order michael@0: checkRegExp(r, "/a/g after second exec", 7, true, false, false); michael@0: michael@0: r = /c/g; michael@0: r.lastIndex = 2; michael@0: checkRegExp(r, "/c/g initially", 2, true, false, false); michael@0: Object.defineProperty(r, "lastIndex", { writable: false }); michael@0: assertEq(Object.getOwnPropertyDescriptor(r, "lastIndex").writable, false); michael@0: try { r.exec("aabbbba"); } catch (e) { /* swallow error if thrown */ } michael@0: assertEq(Object.getOwnPropertyDescriptor(r, "lastIndex").writable, false); michael@0: assertEq(Object.getOwnPropertyDescriptor(r, "source").writable, false); michael@0: assertEq(Object.getOwnPropertyDescriptor(r, "global").value, true); michael@0: assertEq(Object.getOwnPropertyDescriptor(r, "global").writable, false); michael@0: assertEq(Object.getOwnPropertyDescriptor(r, "ignoreCase").value, false); michael@0: assertEq(Object.getOwnPropertyDescriptor(r, "ignoreCase").writable, false); michael@0: assertEq(Object.getOwnPropertyDescriptor(r, "multiline").value, false); michael@0: assertEq(Object.getOwnPropertyDescriptor(r, "multiline").writable, false); michael@0: } michael@0: while (Math.random() > 17); // fake loop to discourage RegExp object caching michael@0: michael@0: /******************************************************************************/ michael@0: michael@0: if (typeof reportCompare === "function") michael@0: reportCompare(true, true); michael@0: michael@0: print("All tests passed!");