e37ca634318cca3bbd06e749f71afd95e12bc566
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Models / AuditTestGroup.js
1 /*
2  * Copyright (C) 2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WI.AuditTestGroup = class AuditTestGroup extends WI.AuditTestBase
27 {
28     constructor(name, tests, {description} = {})
29     {
30         console.assert(Array.isArray(tests));
31
32         super(name, {description});
33
34         this._tests = tests;
35
36         for (let test of this._tests) {
37             test.addEventListener(WI.AuditTestBase.Event.Completed, this._handleTestCompleted, this);
38             test.addEventListener(WI.AuditTestBase.Event.Progress, this._handleTestProgress, this);
39         }
40     }
41
42     // Static
43
44     static async fromPayload(payload)
45     {
46         if (typeof payload !== "object" || payload === null)
47             return null;
48
49         let {type, name, tests, description} = payload;
50
51         if (type !== WI.AuditTestGroup.TypeIdentifier)
52             return null;
53
54         if (typeof name !== "string")
55             return null;
56
57         if (!Array.isArray(tests))
58             return null;
59
60         tests = await Promise.all(tests.map(async (test) => {
61             let testCase = await WI.AuditTestCase.fromPayload(test);
62             if (testCase)
63                 return testCase;
64
65             let testGroup = await WI.AuditTestGroup.fromPayload(test);
66             if (testGroup)
67                 return testGroup;
68
69             return null;
70         }));
71         tests = tests.filter((test) => !!test);
72         if (!tests.length)
73             return null;
74
75         let options = {};
76         if (typeof description === "string")
77             options.description = description;
78
79         return new WI.AuditTestGroup(name, tests, options);
80     }
81
82     // Public
83
84     get tests() { return this._tests; }
85
86     stop()
87     {
88         // Called from WI.AuditManager.
89
90         for (let test of this._tests)
91             test.stop();
92
93         super.stop();
94     }
95
96     clearResult(options = {})
97     {
98         let cleared = !!this._result;
99         for (let test of this._tests) {
100             if (test.clearResult(options))
101                 cleared = true;
102         }
103
104         return super.clearResult({
105             ...options,
106             suppressResultClearedEvent: !cleared,
107         });
108     }
109
110     toJSON()
111     {
112         let json = super.toJSON();
113         json.tests = this._tests.map((testCase) => testCase.toJSON());
114         return json;
115     }
116
117     // Protected
118
119     async run()
120     {
121         let count = this._tests.length;
122         for (let index = 0; index < count && this._runningState === WI.AuditManager.RunningState.Active; ++index) {
123             let test = this._tests[index];
124
125             await test.start();
126
127             if (test instanceof WI.AuditTestCase)
128                 this.dispatchEventToListeners(WI.AuditTestBase.Event.Progress, {index, count});
129         }
130
131         this._updateResult();
132     }
133
134     // Private
135
136     _updateResult()
137     {
138         let results = this._tests.map((test) => test.result).filter((result) => !!result);
139         if (!results.length)
140             return;
141
142         this._result = new WI.AuditTestGroupResult(this.name, results, {
143             description: this.description,
144         });
145     }
146
147     _handleTestCompleted(event)
148     {
149         if (this._runningState === WI.AuditManager.RunningState.Active)
150             return;
151
152         this._updateResult();
153         this.dispatchEventToListeners(WI.AuditTestBase.Event.Completed);
154     }
155
156     _handleTestProgress(event)
157     {
158         if (this._runningState !== WI.AuditManager.RunningState.Active)
159             return;
160
161         let walk = (tests) => {
162             let count = 0;
163             for (let test of tests) {
164                 if (test instanceof WI.AuditTestCase)
165                     ++count;
166                 else if (test instanceof WI.AuditTestGroup)
167                     count += walk(test.tests);
168             }
169             return count;
170         };
171
172         this.dispatchEventToListeners(WI.AuditTestBase.Event.Progress, {
173             index: event.data.index + walk(this.tests.slice(0, this.tests.indexOf(event.target))),
174             count: walk(this.tests),
175         });
176     }
177 };
178
179 WI.AuditTestGroup.TypeIdentifier = "test-group";