| /* |
| * Copyright (C) 2015 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| TestHarness = class TestHarness extends WebInspector.Object |
| { |
| constructor() |
| { |
| super(); |
| |
| this._logCount = 0; |
| this._failureObjects = new Map; |
| this._failureObjectIdentifier = 1; |
| } |
| |
| completeTest() |
| { |
| throw new Error("Must be implemented by subclasses."); |
| } |
| |
| addResult() |
| { |
| throw new Error("Must be implemented by subclasses."); |
| } |
| |
| debugLog() |
| { |
| throw new Error("Must be implemented by subclasses."); |
| } |
| |
| evaluateInPage(string, callback) |
| { |
| throw new Error("Must be implemented by subclasses."); |
| } |
| |
| debug() |
| { |
| throw new Error("Must be implemented by subclasses."); |
| } |
| |
| createAsyncSuite(name) |
| { |
| return new AsyncTestSuite(this, name); |
| } |
| |
| createSyncSuite(name) |
| { |
| return new SyncTestSuite(this, name); |
| } |
| |
| get logCount() |
| { |
| return this._logCount; |
| } |
| |
| log(message) |
| { |
| ++this._logCount; |
| |
| if (this.forceDebugLogging) |
| this.debugLog(message); |
| else |
| this.addResult(message); |
| } |
| |
| assert(condition, message) |
| { |
| if (condition) |
| return; |
| |
| let stringifiedMessage = TestHarness.messageAsString(message); |
| this.log("ASSERT: " + stringifiedMessage); |
| } |
| |
| expectThat(actual, message) |
| { |
| this._expect(TestHarness.ExpectationType.True, !!actual, message, actual); |
| } |
| |
| expectFalse(actual, message) |
| { |
| this._expect(TestHarness.ExpectationType.False, !actual, message, actual); |
| } |
| |
| expectNull(actual, message) |
| { |
| this._expect(TestHarness.ExpectationType.Null, actual === null, message, actual, null); |
| } |
| |
| expectNotNull(actual, message) |
| { |
| this._expect(TestHarness.ExpectationType.NotNull, actual !== null, message, actual); |
| } |
| |
| expectEqual(actual, expected, message) |
| { |
| this._expect(TestHarness.ExpectationType.Equal, expected === actual, message, actual, expected); |
| } |
| |
| expectNotEqual(actual, expected, message) |
| { |
| this._expect(TestHarness.ExpectationType.NotEqual, expected !== actual, message, actual, expected); |
| } |
| |
| expectShallowEqual(actual, expected, message) |
| { |
| this._expect(TestHarness.ExpectationType.ShallowEqual, Object.shallowEqual(actual, expected), message, actual, expected); |
| } |
| |
| expectNotShallowEqual(actual, expected, message) |
| { |
| this._expect(TestHarness.ExpectationType.NotShallowEqual, !Object.shallowEqual(actual, expected), message, actual, expected); |
| } |
| |
| expectEqualWithAccuracy(actual, expected, accuracy, message) |
| { |
| console.assert(typeof expected === "number"); |
| console.assert(typeof actual === "number"); |
| |
| this._expect(TestHarness.ExpectationType.EqualWithAccuracy, Math.abs(expected - actual) <= accuracy, message, actual, expected, accuracy); |
| } |
| |
| expectLessThan(actual, expected, message) |
| { |
| this._expect(TestHarness.ExpectationType.LessThan, actual < expected, message, actual, expected); |
| } |
| |
| expectLessThanOrEqual(actual, expected, message) |
| { |
| this._expect(TestHarness.ExpectationType.LessThanOrEqual, actual <= expected, message, actual, expected); |
| } |
| |
| expectGreaterThan(actual, expected, message) |
| { |
| this._expect(TestHarness.ExpectationType.GreaterThan, actual > expected, message, actual, expected); |
| } |
| |
| expectGreaterThanOrEqual(actual, expected, message) |
| { |
| this._expect(TestHarness.ExpectationType.GreaterThanOrEqual, actual >= expected, message, actual, expected); |
| } |
| |
| pass(message) |
| { |
| let stringifiedMessage = TestHarness.messageAsString(message); |
| this.log("PASS: " + stringifiedMessage); |
| } |
| |
| fail(message) |
| { |
| let stringifiedMessage = TestHarness.messageAsString(message); |
| this.log("FAIL: " + stringifiedMessage); |
| } |
| |
| // Protected |
| |
| static messageAsString(message) |
| { |
| if (message instanceof Element) |
| return message.textContent; |
| |
| return (typeof message !== "string") ? JSON.stringify(message) : message; |
| } |
| |
| // Private |
| |
| _expect(type, condition, message, ...values) |
| { |
| console.assert(values.length > 0, "Should have an 'actual' value."); |
| |
| if (!message || !condition) { |
| values = values.map(this._expectationValueAsString.bind(this)); |
| message = message || this._expectationMessageFormat(type).format(...values); |
| } |
| |
| if (condition) { |
| this.pass(message); |
| return; |
| } |
| |
| message += "\n Expected: " + this._expectedValueFormat(type).format(...values.slice(1)); |
| message += "\n Actual: " + values[0]; |
| |
| this.fail(message); |
| } |
| |
| _expectationValueAsString(value) |
| { |
| let instanceIdentifier = (object) => { |
| let id = this._failureObjects.get(object); |
| if (!id) { |
| id = this._failureObjectIdentifier++; |
| this._failureObjects.set(object, id); |
| } |
| return "#" + id; |
| }; |
| |
| const maximumValueStringLength = 200; |
| const defaultValueString = String(new Object); // [object Object] |
| |
| // Special case for numbers, since JSON.stringify converts Infinity and NaN to null. |
| if (typeof value === "number") |
| return value; |
| |
| try { |
| let valueString = JSON.stringify(value); |
| if (valueString.length <= maximumValueStringLength) |
| return valueString; |
| } catch (e) {} |
| |
| try { |
| let valueString = String(value); |
| if (valueString === defaultValueString && value.constructor && value.constructor.name !== "Object") |
| return value.constructor.name + " instance " + instanceIdentifier(value); |
| return valueString; |
| } catch (e) { |
| return defaultValueString; |
| } |
| } |
| |
| _expectationMessageFormat(type) |
| { |
| switch (type) { |
| case TestHarness.ExpectationType.True: |
| return "expectThat(%s)"; |
| case TestHarness.ExpectationType.False: |
| return "expectFalse(%s)"; |
| case TestHarness.ExpectationType.Null: |
| return "expectNull(%s)"; |
| case TestHarness.ExpectationType.NotNull: |
| return "expectNotNull(%s)"; |
| case TestHarness.ExpectationType.Equal: |
| return "expectEqual(%s, %s)"; |
| case TestHarness.ExpectationType.NotEqual: |
| return "expectNotEqual(%s, %s)"; |
| case TestHarness.ExpectationType.ShallowEqual: |
| return "expectShallowEqual(%s, %s)"; |
| case TestHarness.ExpectationType.NotShallowEqual: |
| return "expectNotShallowEqual(%s, %s)"; |
| case TestHarness.ExpectationType.EqualWithAccuracy: |
| return "expectEqualWithAccuracy(%s, %s, %s)"; |
| case TestHarness.ExpectationType.LessThan: |
| return "expectLessThan(%s, %s)"; |
| case TestHarness.ExpectationType.LessThanOrEqual: |
| return "expectLessThanOrEqual(%s, %s)"; |
| case TestHarness.ExpectationType.GreaterThan: |
| return "expectGreaterThan(%s, %s)"; |
| case TestHarness.ExpectationType.GreaterThanOrEqual: |
| return "expectGreaterThanOrEqual(%s, %s)"; |
| default: |
| console.error("Unknown TestHarness.ExpectationType type: " + type); |
| return null; |
| } |
| } |
| |
| _expectedValueFormat(type) |
| { |
| switch (type) { |
| case TestHarness.ExpectationType.True: |
| return "truthy"; |
| case TestHarness.ExpectationType.False: |
| return "falsey"; |
| case TestHarness.ExpectationType.NotNull: |
| return "not null"; |
| case TestHarness.ExpectationType.NotEqual: |
| case TestHarness.ExpectationType.NotShallowEqual: |
| return "not %s"; |
| case TestHarness.ExpectationType.EqualWithAccuracy: |
| return "%s +/- %s"; |
| case TestHarness.ExpectationType.LessThan: |
| return "less than %s"; |
| case TestHarness.ExpectationType.LessThanOrEqual: |
| return "less than or equal to %s"; |
| case TestHarness.ExpectationType.GreaterThan: |
| return "greater than %s"; |
| case TestHarness.ExpectationType.GreaterThanOrEqual: |
| return "greater than or equal to %s"; |
| default: |
| return "%s"; |
| } |
| } |
| }; |
| |
| TestHarness.ExpectationType = { |
| True: Symbol("expect-true"), |
| False: Symbol("expect-false"), |
| Null: Symbol("expect-null"), |
| NotNull: Symbol("expect-not-null"), |
| Equal: Symbol("expect-equal"), |
| NotEqual: Symbol("expect-not-equal"), |
| ShallowEqual: Symbol("expect-shallow-equal"), |
| NotShallowEqual: Symbol("expect-not-shallow-equal"), |
| EqualWithAccuracy: Symbol("expect-equal-with-accuracy"), |
| LessThan: Symbol("expect-less-than"), |
| LessThanOrEqual: Symbol("expect-less-than-or-equal"), |
| GreaterThan: Symbol("expect-greater-than"), |
| GreaterThanOrEqual: Symbol("expect-greater-than-or-equal"), |
| }; |