moved to root
This commit is contained in:
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 INC. 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 INC. 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.
|
||||
*/
|
||||
|
||||
WI.AuditTestGroup = class AuditTestGroup extends WI.AuditTestBase
|
||||
{
|
||||
constructor(name, tests, options = {})
|
||||
{
|
||||
console.assert(Array.isArray(tests), tests);
|
||||
|
||||
// Set disabled once `_tests` is set so that it propagates.
|
||||
let disabled = options.disabled;
|
||||
options.disabled = false;
|
||||
|
||||
super(name, options);
|
||||
|
||||
this._tests = [];
|
||||
for (let test of tests)
|
||||
this.addTest(test);
|
||||
|
||||
if (disabled)
|
||||
this.updateDisabled(true);
|
||||
}
|
||||
|
||||
// Static
|
||||
|
||||
static async fromPayload(payload)
|
||||
{
|
||||
if (typeof payload !== "object" || payload === null)
|
||||
return null;
|
||||
|
||||
if (payload.type !== WI.AuditTestGroup.TypeIdentifier)
|
||||
return null;
|
||||
|
||||
if (typeof payload.name !== "string") {
|
||||
WI.AuditManager.synthesizeError(WI.UIString("\u0022%s\u0022 has a non-string \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("name")));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!Array.isArray(payload.tests)) {
|
||||
WI.AuditManager.synthesizeError(WI.UIString("\u0022%s\u0022 has a non-array \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("tests")));
|
||||
return null;
|
||||
}
|
||||
|
||||
let tests = await Promise.all(payload.tests.map(async (test) => {
|
||||
let testCase = await WI.AuditTestCase.fromPayload(test);
|
||||
if (testCase)
|
||||
return testCase;
|
||||
|
||||
let testGroup = await WI.AuditTestGroup.fromPayload(test);
|
||||
if (testGroup)
|
||||
return testGroup;
|
||||
|
||||
return null;
|
||||
}));
|
||||
tests = tests.filter((test) => !!test);
|
||||
if (!tests.length)
|
||||
return null;
|
||||
|
||||
let options = {};
|
||||
|
||||
if (typeof payload.description === "string")
|
||||
options.description = payload.description;
|
||||
else if ("description" in payload)
|
||||
WI.AuditManager.synthesizeWarning(WI.UIString("\u0022%s\u0022 has a non-string \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("description")));
|
||||
|
||||
if (typeof payload.supports === "number")
|
||||
options.supports = payload.supports;
|
||||
else if ("supports" in payload)
|
||||
WI.AuditManager.synthesizeWarning(WI.UIString("\u0022%s\u0022 has a non-number \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("supports")));
|
||||
|
||||
if (typeof payload.setup === "string")
|
||||
options.setup = payload.setup;
|
||||
else if ("setup" in payload)
|
||||
WI.AuditManager.synthesizeWarning(WI.UIString("\u0022%s\u0022 has a non-string \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("setup")));
|
||||
|
||||
if (typeof payload.disabled === "boolean")
|
||||
options.disabled = payload.disabled;
|
||||
|
||||
return new WI.AuditTestGroup(payload.name, tests, options);
|
||||
}
|
||||
|
||||
// Public
|
||||
|
||||
get tests() { return this._tests; }
|
||||
|
||||
addTest(test)
|
||||
{
|
||||
console.assert(test instanceof WI.AuditTestBase, test);
|
||||
console.assert(!this._tests.includes(test), test);
|
||||
console.assert(!test._parent, test);
|
||||
|
||||
this._tests.push(test);
|
||||
test._parent = this;
|
||||
|
||||
test.addEventListener(WI.AuditTestBase.Event.Completed, this._handleTestCompleted, this);
|
||||
test.addEventListener(WI.AuditTestBase.Event.DisabledChanged, this._handleTestDisabledChanged, this);
|
||||
test.addEventListener(WI.AuditTestBase.Event.Progress, this._handleTestProgress, this);
|
||||
if (this.editable) {
|
||||
test.addEventListener(WI.AuditTestBase.Event.SupportedChanged, this._handleTestSupportedChanged, this);
|
||||
test.addEventListener(WI.AuditTestBase.Event.TestChanged, this._handleTestChanged, this);
|
||||
}
|
||||
|
||||
this.dispatchEventToListeners(WI.AuditTestGroup.Event.TestAdded, {test});
|
||||
|
||||
this.determineIfSupported();
|
||||
|
||||
if (this._checkDisabled(test))
|
||||
test.updateDisabled(true, {silent: true});
|
||||
}
|
||||
|
||||
removeTest(test)
|
||||
{
|
||||
console.assert(this.editable);
|
||||
console.assert(WI.auditManager.editing);
|
||||
console.assert(test instanceof WI.AuditTestBase, test);
|
||||
console.assert(test.editable, test);
|
||||
console.assert(this._tests.includes(test), test);
|
||||
console.assert(test._parent === this, test);
|
||||
|
||||
test.removeEventListener(WI.AuditTestBase.Event.Completed, this._handleTestCompleted, this);
|
||||
test.removeEventListener(WI.AuditTestBase.Event.DisabledChanged, this._handleTestDisabledChanged, this);
|
||||
test.removeEventListener(WI.AuditTestBase.Event.Progress, this._handleTestProgress, this);
|
||||
test.removeEventListener(WI.AuditTestBase.Event.SupportedChanged, this._handleTestSupportedChanged, this);
|
||||
test.removeEventListener(WI.AuditTestBase.Event.TestChanged, this._handleTestChanged, this);
|
||||
|
||||
this._tests.remove(test);
|
||||
test._parent = null;
|
||||
|
||||
this.dispatchEventToListeners(WI.AuditTestGroup.Event.TestRemoved, {test});
|
||||
|
||||
this.determineIfSupported();
|
||||
|
||||
this._checkDisabled();
|
||||
}
|
||||
|
||||
stop()
|
||||
{
|
||||
// Called from WI.AuditManager.
|
||||
|
||||
for (let test of this._tests)
|
||||
test.stop();
|
||||
|
||||
super.stop();
|
||||
}
|
||||
|
||||
clearResult(options = {})
|
||||
{
|
||||
let cleared = !!this.result;
|
||||
|
||||
if (!options.excludeTests && this._tests) {
|
||||
for (let test of this._tests) {
|
||||
if (test.clearResult(options))
|
||||
cleared = true;
|
||||
}
|
||||
}
|
||||
|
||||
return super.clearResult({
|
||||
...options,
|
||||
suppressResultChangedEvent: !cleared,
|
||||
});
|
||||
}
|
||||
|
||||
toJSON(key)
|
||||
{
|
||||
let json = super.toJSON(key);
|
||||
json.tests = this._tests.map((testCase) => testCase.toJSON(key));
|
||||
return json;
|
||||
}
|
||||
|
||||
// Protected
|
||||
|
||||
async run()
|
||||
{
|
||||
let count = this._tests.length;
|
||||
for (let index = 0; index < count && this._runningState === WI.AuditManager.RunningState.Active; ++index) {
|
||||
let test = this._tests[index];
|
||||
if (test.disabled || !test.supported)
|
||||
continue;
|
||||
|
||||
await test.start();
|
||||
|
||||
if (test instanceof WI.AuditTestCase)
|
||||
this.dispatchEventToListeners(WI.AuditTestBase.Event.Progress, {index, count});
|
||||
}
|
||||
|
||||
this.updateResult();
|
||||
}
|
||||
|
||||
determineIfSupported(options = {})
|
||||
{
|
||||
if (this._tests) {
|
||||
for (let test of this._tests)
|
||||
test.determineIfSupported({...options, warn: false, silent: true});
|
||||
}
|
||||
|
||||
return super.determineIfSupported(options);
|
||||
}
|
||||
|
||||
updateSupported(supported, options = {})
|
||||
{
|
||||
if (this._tests && (!supported || this._tests.every((test) => !test.supported))) {
|
||||
supported = false;
|
||||
|
||||
for (let test of this._tests)
|
||||
test.updateSupported(supported, {silent: true});
|
||||
}
|
||||
|
||||
super.updateSupported(supported, options);
|
||||
}
|
||||
|
||||
updateDisabled(disabled, options = {})
|
||||
{
|
||||
if (!options.excludeTests && this._tests) {
|
||||
for (let test of this._tests)
|
||||
test.updateDisabled(disabled, options);
|
||||
}
|
||||
|
||||
super.updateDisabled(disabled, options);
|
||||
}
|
||||
|
||||
updateResult()
|
||||
{
|
||||
let results = this._tests.map((test) => test.result).filter((result) => !!result);
|
||||
if (!results.length)
|
||||
return;
|
||||
|
||||
super.updateResult(new WI.AuditTestGroupResult(this.name, results, {
|
||||
description: this.description,
|
||||
}));
|
||||
}
|
||||
|
||||
// Private
|
||||
|
||||
_checkDisabled(test)
|
||||
{
|
||||
let testDisabled = !test || !test.supported || test.disabled;
|
||||
let enabledTestCount = this._tests.filter((existing) => existing.supported && !existing.disabled).length;
|
||||
|
||||
if (testDisabled && !enabledTestCount)
|
||||
this.updateDisabled(true);
|
||||
else if (!testDisabled && enabledTestCount === 1)
|
||||
this.updateDisabled(false, {excludeTests: true});
|
||||
else {
|
||||
// Don't change `disabled`, as we're currently in an "indeterminate" state.
|
||||
this.dispatchEventToListeners(WI.AuditTestBase.Event.DisabledChanged);
|
||||
}
|
||||
|
||||
return this.disabled;
|
||||
}
|
||||
|
||||
_handleTestCompleted(event)
|
||||
{
|
||||
if (this._runningState === WI.AuditManager.RunningState.Active)
|
||||
return;
|
||||
|
||||
this.updateResult();
|
||||
|
||||
this.dispatchEventToListeners(WI.AuditTestBase.Event.Completed);
|
||||
}
|
||||
|
||||
_handleTestDisabledChanged(event)
|
||||
{
|
||||
this._checkDisabled(event.target);
|
||||
}
|
||||
|
||||
_handleTestProgress(event)
|
||||
{
|
||||
if (this._runningState !== WI.AuditManager.RunningState.Active)
|
||||
return;
|
||||
|
||||
let walk = (tests) => {
|
||||
let count = 0;
|
||||
for (let test of tests) {
|
||||
if (test.disabled || !test.supported)
|
||||
continue;
|
||||
|
||||
if (test instanceof WI.AuditTestCase)
|
||||
++count;
|
||||
else if (test instanceof WI.AuditTestGroup)
|
||||
count += walk(test.tests);
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
this.dispatchEventToListeners(WI.AuditTestBase.Event.Progress, {
|
||||
index: event.data.index + walk(this._tests.slice(0, this._tests.indexOf(event.target))),
|
||||
count: walk(this._tests),
|
||||
});
|
||||
}
|
||||
|
||||
_handleTestSupportedChanged(event)
|
||||
{
|
||||
this.determineIfSupported();
|
||||
}
|
||||
|
||||
_handleTestChanged(event)
|
||||
{
|
||||
console.assert(WI.auditManager.editing);
|
||||
|
||||
this.clearResult({excludeTests: true});
|
||||
|
||||
this.dispatchEventToListeners(WI.AuditTestBase.Event.TestChanged);
|
||||
}
|
||||
};
|
||||
|
||||
WI.AuditTestGroup.TypeIdentifier = "test-group";
|
||||
|
||||
WI.AuditTestGroup.Event = {
|
||||
TestAdded: "audit-test-group-test-added",
|
||||
TestRemoved: "audit-test-group-test-removed",
|
||||
};
|
||||
Reference in New Issue
Block a user