Bug 1918529 - fix some subpixel misalignment issues with gfx.webrender.svg-filter...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / deqp / framework / common / tcuTestCase.js
blob55913f43664f801f52694f02d3b91e2452a43f81
1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES Utilities
3 * ------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
21 /**
22 * This class allows one to create a hierarchy of tests and iterate over them.
23 * It replaces TestCase and TestCaseGroup classes.
25 'use strict';
26 goog.provide('framework.common.tcuTestCase');
27 goog.require('framework.common.tcuSkipList');
29 goog.scope(function() {
31 var tcuTestCase = framework.common.tcuTestCase;
32 var tcuSkipList = framework.common.tcuSkipList;
34 tcuTestCase.getQueryVal = function(key) {
35 const queryVars = window.location.search.substring(1).split('&');
36 for (let kv of queryVars) {
37 kv = kv.split('=');
38 if (decodeURIComponent(kv[0]) === key)
39 return decodeURIComponent(kv[1]);
41 return null;
44 tcuTestCase.isQuickMode = () => tcuTestCase.getQueryVal('quick') === '1';
45 tcuTestCase.isQuietMode = () => tcuTestCase.getQueryVal('quiet') === '1';
47 /**
48 * Reads the filter parameter from the URL to filter tests.
49 * @return {?string }
51 tcuTestCase.getFilter = () => tcuTestCase.getQueryVal('filter');
53 /**
54 * Indicates the state of an iteration operation.
55 * @enum {number}
57 tcuTestCase.IterateResult = {
58 STOP: 0,
59 CONTINUE: 1
62 /****************************************
63 * Runner
64 ***************************************/
66 /**
67 * A simple state machine.
68 * The purpose of this this object is to break
69 * long tests into small chunks that won't cause a timeout
70 * @constructor
72 tcuTestCase.Runner = function() {
73 /** @type {tcuTestCase.DeqpTest} */ this.currentTest = null;
74 /** @type {tcuTestCase.DeqpTest} */ this.nextTest = null;
75 /** @type {tcuTestCase.DeqpTest} */ this.testCases = null;
76 /** @type {?string } */ this.filter = tcuTestCase.getFilter();
79 /**
80 * @param {tcuTestCase.DeqpTest} root The root test of the test tree.
82 tcuTestCase.Runner.prototype.setRoot = function(root) {
83 this.currentTest = null;
84 this.testCases = root;
87 tcuTestCase.Runner.prototype.setRange = function(range) {
88 this.range = range;
91 /**
92 * Searches the test tree for the next executable test
93 * @return {?tcuTestCase.DeqpTest }
95 tcuTestCase.Runner.prototype.next = function() {
97 // First time? Use root test
98 if (!this.currentTest) {
99 this.currentTest = this.testCases;
101 // Root is executable? Use it
102 if (this.currentTest.isExecutable())
103 return this.currentTest;
106 // Should we proceed with the next test?
107 if (tcuTestCase.lastResult == tcuTestCase.IterateResult.STOP) {
108 // Look for next executable test
109 do {
110 if (this.range)
111 this.currentTest = this.currentTest.nextInRange(this.filter, this.range);
112 else
113 this.currentTest = this.currentTest.next(this.filter);
114 } while (this.currentTest && !this.currentTest.isExecutable());
117 return this.currentTest;
121 * Schedule the callback to be run ASAP
122 * @param {function()} callback Callback to schedule
124 tcuTestCase.Runner.prototype.runCallback = function(callback) {
125 setTimeout(function() {
126 callback();
127 }.bind(this), 0);
131 * Call this function at the end of the test
133 tcuTestCase.Runner.prototype.terminate = function() {
134 finishTest();
135 if (!tcuTestCase.isQuietMode()) {
136 console.log('finishTest() after (in ms):', performance.now());
140 tcuTestCase.runner = new tcuTestCase.Runner();
142 /** @type {tcuTestCase.IterateResult} */ tcuTestCase.lastResult = tcuTestCase.IterateResult.STOP;
144 /***************************************
145 * DeqpTest
146 ***************************************/
149 * Assigns name, description and specification to test
150 * @constructor
151 * @param {?string} name
152 * @param {?string} description
153 * @param {Object=} spec
155 tcuTestCase.DeqpTest = function(name, description, spec) {
156 this.name = name || '';
157 this.description = description || '';
158 this.spec = spec;
159 this.currentTestNdx = 0;
160 this.parentTest = null;
161 this.childrenTests = [];
162 this.executeAlways = false;
166 * Abstract init function(each particular test will implement it, or not)
168 tcuTestCase.DeqpTest.prototype.init = function() {};
171 * Abstract deinit function(each particular test will implement it, or not)
173 tcuTestCase.DeqpTest.prototype.deinit = function() {};
176 * Abstract iterate function(each particular test will implement it, or not)
177 * @return {tcuTestCase.IterateResult}
179 tcuTestCase.DeqpTest.prototype.iterate = function() { return tcuTestCase.IterateResult.STOP; };
182 * Checks if the test is executable
183 * @return {boolean}
185 tcuTestCase.DeqpTest.prototype.isExecutable = function() {
186 return this.childrenTests.length == 0 || this.executeAlways;
190 * Checks if the test is a leaf
192 tcuTestCase.DeqpTest.prototype.isLeaf = function() {
193 return this.childrenTests.length == 0;
197 * Marks the test as always executable
199 tcuTestCase.DeqpTest.prototype.makeExecutable = function() {
200 this.executeAlways = true;
204 * Adds a child test to the test's children
205 * @param {tcuTestCase.DeqpTest} test
207 tcuTestCase.DeqpTest.prototype.addChild = function(test) {
208 test.parentTest = this;
209 this.childrenTests.push(test);
213 * Sets the whole children tests array
214 * @param {Array<tcuTestCase.DeqpTest>} tests
216 tcuTestCase.DeqpTest.prototype.setChildren = function(tests) {
217 for (var test in tests)
218 tests[test].parentTest = this;
219 this.childrenTests = tests;
223 * Returns the next test in the hierarchy of tests
225 * @param {?string } pattern Optional pattern to search for
226 * @return {tcuTestCase.DeqpTest}
228 tcuTestCase.DeqpTest.prototype.next = function(pattern) {
229 return this._nextHonoringSkipList(pattern);
233 * Returns the next test in the hierarchy of tests, honoring the
234 * skip list, and reporting skipped tests.
236 * @param {?string } pattern Optional pattern to search for
237 * @return {tcuTestCase.DeqpTest}
239 tcuTestCase.DeqpTest.prototype._nextHonoringSkipList = function(pattern) {
240 var tryAgain = false;
241 var test = null;
242 do {
243 tryAgain = false;
244 test = this._nextIgnoringSkipList(pattern);
245 if (test != null) {
246 // See whether the skip list vetoes the execution of
247 // this test.
248 var fullTestName = test.fullName();
249 var skipDisposition = tcuSkipList.getSkipStatus(fullTestName);
250 if (skipDisposition.skip) {
251 tryAgain = true;
252 setCurrentTestName(fullTestName);
253 checkMessage(false, 'Skipping test due to tcuSkipList: ' + fullTestName);
256 } while (tryAgain);
257 return test;
262 * Returns the next test in the hierarchy of tests, ignoring the
263 * skip list.
265 * @param {?string } pattern Optional pattern to search for
266 * @return {tcuTestCase.DeqpTest}
268 tcuTestCase.DeqpTest.prototype._nextIgnoringSkipList = function(pattern) {
269 if (pattern)
270 return this._findIgnoringSkipList(pattern);
272 var test = null;
274 //Look for the next child
275 if (this.currentTestNdx < this.childrenTests.length) {
276 test = this.childrenTests[this.currentTestNdx];
277 this.currentTestNdx++;
280 // If no more children, get the next brother
281 if (test == null && this.parentTest != null) {
282 test = this.parentTest._nextIgnoringSkipList(null);
285 return test;
289 * Returns the next test in the hierarchy of tests
290 * whose 1st level is in the given range
292 * @param {?string } pattern Optional pattern to search for
293 * @param {Array<number>} range
294 * @return {tcuTestCase.DeqpTest}
296 tcuTestCase.DeqpTest.prototype.nextInRange = function(pattern, range) {
297 while (true) {
298 var test = this._nextHonoringSkipList(pattern);
299 if (!test)
300 return null;
301 var topLevelId = tcuTestCase.runner.testCases.currentTestNdx - 1;
302 if (topLevelId >= range[0] && topLevelId < range[1])
303 return test;
308 * Returns the full name of the test
310 * @return {string} Full test name.
312 tcuTestCase.DeqpTest.prototype.fullName = function() {
313 if (this.parentTest) {
314 var parentName = this.parentTest.fullName();
315 if (parentName)
316 return parentName + '.' + this.name;
318 return this.name;
322 * Returns the description of the test
324 * @return {string} Test description.
326 tcuTestCase.DeqpTest.prototype.getDescription = function() {
327 return this.description;
331 * Find a test with a matching name. Fast-forwards to a test whose
332 * full name matches the given pattern.
334 * @param {string} pattern Regular expression to search for
335 * @return {?tcuTestCase.DeqpTest } Found test or null.
337 tcuTestCase.DeqpTest.prototype.find = function(pattern) {
338 return this._findHonoringSkipList(pattern);
342 * Find a test with a matching name. Fast-forwards to a test whose
343 * full name matches the given pattern, honoring the skip list, and
344 * reporting skipped tests.
346 * @param {string} pattern Regular expression to search for
347 * @return {?tcuTestCase.DeqpTest } Found test or null.
349 tcuTestCase.DeqpTest.prototype._findHonoringSkipList = function(pattern) {
350 var tryAgain = false;
351 var test = null;
352 do {
353 tryAgain = false;
354 test = this._findIgnoringSkipList(pattern);
355 if (test != null) {
356 // See whether the skip list vetoes the execution of
357 // this test.
358 var fullTestName = test.fullName();
359 var skipDisposition = tcuSkipList.getSkipStatus(fullTestName);
360 if (skipDisposition.skip) {
361 tryAgain = true;
362 checkMessage(false, 'Skipping test due to tcuSkipList: ' + fullTestName);
365 } while (tryAgain);
366 return test;
370 * Find a test with a matching name. Fast-forwards to a test whose
371 * full name matches the given pattern.
373 * @param {string} pattern Regular expression to search for
374 * @return {?tcuTestCase.DeqpTest } Found test or null.
376 tcuTestCase.DeqpTest.prototype._findIgnoringSkipList = function(pattern) {
377 var test = this;
378 while (true) {
379 test = test._nextIgnoringSkipList(null);
380 if (!test)
381 break;
382 if (test.fullName().match(pattern) || test.executeAlways)
383 break;
385 return test;
389 * Reset the iterator.
391 tcuTestCase.DeqpTest.prototype.reset = function() {
392 this.currentTestNdx = 0;
394 for (var i = 0; i < this.childrenTests.length; i++)
395 this.childrenTests[i].reset();
399 * Defines a new test
401 * @param {?string} name Short test name
402 * @param {?string} description Description of the test
403 * @param {Object=} spec Test specification
405 * @return {tcuTestCase.DeqpTest} The new test
407 tcuTestCase.newTest = function(name, description, spec) {
408 var test = new tcuTestCase.DeqpTest(name, description, spec);
410 return test;
414 * Defines a new executable test so it gets run even if it's not a leaf
416 * @param {string} name Short test name
417 * @param {string} description Description of the test
418 * @param {Object=} spec Test specification
420 * @return {tcuTestCase.DeqpTest} The new test
422 tcuTestCase.newExecutableTest = function(name, description, spec) {
423 var test = tcuTestCase.newTest(name, description, spec);
424 test.makeExecutable();
426 return test;
430 * Run through the test cases giving time to system operation.
432 tcuTestCase.runTestCases = function() {
433 var state = tcuTestCase.runner;
435 if (state.next()) {
436 try {
437 // If proceeding with the next test, prepare it.
438 var fullTestName = state.currentTest.fullName();
439 var inited = true;
440 if (tcuTestCase.lastResult == tcuTestCase.IterateResult.STOP) {
441 // Update current test name
442 setCurrentTestName(fullTestName);
443 bufferedLogToConsole('Init testcase: ' + fullTestName); //Show also in console so we can see which test crashed the browser's tab
445 // Initialize particular test
446 inited = state.currentTest.init();
447 inited = inited === undefined ? true : inited;
449 //If it's a leaf test, notify of it's execution.
450 if (state.currentTest.isLeaf() && inited)
451 debug('<hr/><br/>Start testcase: ' + fullTestName);
454 if (inited) {
455 // Run the test, save the result.
457 const debug = tcuTestCase._debug = tcuTestCase._debug || (() => {
458 function LapStopwatch() {
459 this.lap = function() {
460 const now = performance.now();
461 const ret = now - this.last;
462 this.last = now;
463 return ret;
465 this.lap();
467 return {
468 stopwatch: new LapStopwatch(),
469 testDoneCount: 0,
471 })();
472 const overheadDur = debug.stopwatch.lap();
474 tcuTestCase.lastResult = state.currentTest.iterate();
476 const testDur = debug.stopwatch.lap();
477 debug.testDoneCount += 1;
478 console.log(
479 `[test ${debug.testDoneCount}] Ran in ${testDur}ms`,
480 `(+ ${overheadDur}ms overhead)`,
482 } else {
483 // Skip uninitialized test.
484 tcuTestCase.lastResult = tcuTestCase.IterateResult.STOP;
487 // Cleanup
488 if (tcuTestCase.lastResult == tcuTestCase.IterateResult.STOP)
489 state.currentTest.deinit();
491 catch (err) {
492 // If the exception was not thrown by a test check, log it, but don't throw it again
493 if (!(err instanceof TestFailedException)) {
494 //Stop execution of current test.
495 tcuTestCase.lastResult = tcuTestCase.IterateResult.STOP;
496 try {
497 // Cleanup
498 if (tcuTestCase.lastResult == tcuTestCase.IterateResult.STOP)
499 state.currentTest.deinit();
500 } catch (cerr) {
501 bufferedLogToConsole('Error while cleaning up test: ' + cerr);
503 var msg = err;
504 if (err.message)
505 msg = err.message;
506 testFailedOptions(msg, false);
508 bufferedLogToConsole(err);
511 tcuTestCase.runner.runCallback(tcuTestCase.runTestCases);
512 } else {
513 tcuTestCase.runner.terminate();