633b70b126
This fuzzer randomly generates calls to regexp builtins, runs each on the slow and fast path, and verifies that their result is the same. Change-Id: Ia91b0c8afcdaf64835a9bb7b9a470610fbb75fc8 Reviewed-on: https://chromium-review.googlesource.com/833922 Commit-Queue: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Yang Guo <yangguo@chromium.org> Cr-Commit-Position: refs/heads/master@{#50670}
189 lines
5.7 KiB
JavaScript
189 lines
5.7 KiB
JavaScript
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// Stripped-down version of test/mjsunit/mjsunit.js that only contains
|
|
// assertEquals.S
|
|
var assertEquals;
|
|
|
|
(function () {
|
|
var ObjectPrototypeToString = Object.prototype.toString;
|
|
var NumberPrototypeValueOf = Number.prototype.valueOf;
|
|
var BooleanPrototypeValueOf = Boolean.prototype.valueOf;
|
|
var StringPrototypeValueOf = String.prototype.valueOf;
|
|
var DatePrototypeValueOf = Date.prototype.valueOf;
|
|
var RegExpPrototypeToString = RegExp.prototype.toString;
|
|
var ArrayPrototypeForEach = Array.prototype.forEach;
|
|
var ArrayPrototypeJoin = Array.prototype.join;
|
|
var ArrayPrototypeMap = Array.prototype.map;
|
|
var ArrayPrototypePush = Array.prototype.push;
|
|
|
|
var BigIntPrototypeValueOf;
|
|
try {
|
|
BigIntPrototypeValueOf = BigInt.prototype.valueOf;
|
|
} catch(e) {}
|
|
|
|
function classOf(object) {
|
|
var string = ObjectPrototypeToString.call(object);
|
|
return string.substring(8, string.length - 1);
|
|
}
|
|
|
|
function ValueOf(value) {
|
|
switch (classOf(value)) {
|
|
case "Number":
|
|
return NumberPrototypeValueOf.call(value);
|
|
case "BigInt":
|
|
return BigIntPrototypeValueOf.call(value);
|
|
case "String":
|
|
return StringPrototypeValueOf.call(value);
|
|
case "Boolean":
|
|
return BooleanPrototypeValueOf.call(value);
|
|
case "Date":
|
|
return DatePrototypeValueOf.call(value);
|
|
default:
|
|
return value;
|
|
}
|
|
}
|
|
|
|
|
|
function PrettyPrint(value) {
|
|
switch (typeof value) {
|
|
case "string":
|
|
return JSON.stringify(value);
|
|
case "bigint":
|
|
return String(value) + "n";
|
|
case "number":
|
|
if (value === 0 && (1 / value) < 0) return "-0";
|
|
// FALLTHROUGH.
|
|
case "boolean":
|
|
case "undefined":
|
|
case "function":
|
|
case "symbol":
|
|
return String(value);
|
|
case "object":
|
|
if (value === null) return "null";
|
|
var objectClass = classOf(value);
|
|
switch (objectClass) {
|
|
case "Number":
|
|
case "BigInt":
|
|
case "String":
|
|
case "Boolean":
|
|
case "Date":
|
|
return objectClass + "(" + PrettyPrint(ValueOf(value)) + ")";
|
|
case "RegExp":
|
|
return RegExpPrototypeToString.call(value);
|
|
case "Array":
|
|
var mapped = ArrayPrototypeMap.call(value, PrettyPrintArrayElement);
|
|
var joined = ArrayPrototypeJoin.call(mapped, ",");
|
|
return "[" + joined + "]";
|
|
case "Uint8Array":
|
|
case "Int8Array":
|
|
case "Int16Array":
|
|
case "Uint16Array":
|
|
case "Uint32Array":
|
|
case "Int32Array":
|
|
case "Float32Array":
|
|
case "Float64Array":
|
|
var joined = ArrayPrototypeJoin.call(value, ",");
|
|
return objectClass + "([" + joined + "])";
|
|
case "Object":
|
|
break;
|
|
default:
|
|
return objectClass + "()";
|
|
}
|
|
var name = value.constructor.name;
|
|
if (name) return name + "()";
|
|
return "Object()";
|
|
default:
|
|
return "-- unknown value --";
|
|
}
|
|
}
|
|
|
|
function PrettyPrintArrayElement(value, index, array) {
|
|
if (value === undefined && !(index in array)) return "";
|
|
return PrettyPrint(value);
|
|
}
|
|
|
|
failWithMessage = function failWithMessage(message) {
|
|
throw new Error(message);
|
|
}
|
|
|
|
function formatFailureText(expectedText, found, name_opt) {
|
|
var message = "Fail" + "ure";
|
|
if (name_opt) {
|
|
message += " (" + name_opt + ")";
|
|
}
|
|
|
|
var foundText = PrettyPrint(found);
|
|
if (expectedText.length <= 40 && foundText.length <= 40) {
|
|
message += ": expected <" + expectedText + "> found <" + foundText + ">";
|
|
} else {
|
|
message += ":\nexpected:\n" + expectedText + "\nfound:\n" + foundText;
|
|
}
|
|
return message;
|
|
}
|
|
|
|
function fail(expectedText, found, name_opt) {
|
|
return failWithMessage(formatFailureText(expectedText, found, name_opt));
|
|
}
|
|
|
|
function deepObjectEquals(a, b) {
|
|
var aProps = Object.keys(a);
|
|
aProps.sort();
|
|
var bProps = Object.keys(b);
|
|
bProps.sort();
|
|
if (!deepEquals(aProps, bProps)) {
|
|
return false;
|
|
}
|
|
for (var i = 0; i < aProps.length; i++) {
|
|
if (!deepEquals(a[aProps[i]], b[aProps[i]])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function deepEquals(a, b) {
|
|
if (a === b) {
|
|
// Check for -0.
|
|
if (a === 0) return (1 / a) === (1 / b);
|
|
return true;
|
|
}
|
|
if (typeof a !== typeof b) return false;
|
|
if (typeof a === "number") return isNaN(a) && isNaN(b);
|
|
if (typeof a !== "object" && typeof a !== "function") return false;
|
|
// Neither a nor b is primitive.
|
|
var objectClass = classOf(a);
|
|
if (objectClass !== classOf(b)) return false;
|
|
if (objectClass === "RegExp") {
|
|
// For RegExp, just compare pattern and flags using its toString.
|
|
return RegExpPrototypeToString.call(a) ===
|
|
RegExpPrototypeToString.call(b);
|
|
}
|
|
// Functions are only identical to themselves.
|
|
if (objectClass === "Function") return false;
|
|
if (objectClass === "Array") {
|
|
var elementCount = 0;
|
|
if (a.length !== b.length) {
|
|
return false;
|
|
}
|
|
for (var i = 0; i < a.length; i++) {
|
|
if (!deepEquals(a[i], b[i])) return false;
|
|
}
|
|
return true;
|
|
}
|
|
if (objectClass === "String" || objectClass === "Number" ||
|
|
objectClass === "BigInt" || objectClass === "Boolean" ||
|
|
objectClass === "Date") {
|
|
if (ValueOf(a) !== ValueOf(b)) return false;
|
|
}
|
|
return deepObjectEquals(a, b);
|
|
}
|
|
|
|
assertEquals = function assertEquals(expected, found, name_opt) {
|
|
if (!deepEquals(found, expected)) {
|
|
fail(PrettyPrint(expected), found, name_opt);
|
|
}
|
|
};
|
|
})();
|