1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5/** 6 * Tests that an observation matches the expected value. 7 * @param {Object} expected The expected value. 8 * @param {Object} observed The actual value. 9 * @param {string=} opt_message Optional message to include with a test 10 * failure. 11 */ 12function assertEquals(expected, observed, opt_message) { 13 if (observed !== expected) { 14 var message = 'Assertion Failed\n Observed: ' + observed + 15 '\n Expected: ' + expected; 16 if (opt_message) 17 message = message + '\n ' + opt_message; 18 throw new Error(message); 19 } 20} 21 22/** 23 * Verifies that a test result is true. 24 * @param {boolean} observed The observed value. 25 * @param {string=} opt_message Optional message to include with a test 26 * failure. 27 */ 28function assertTrue(observed, opt_message) { 29 assertEquals(true, observed, opt_message); 30} 31 32/** 33 * Verifies that a test result is false. 34 * @param {boolean} observed The observed value. 35 * @param {string=} opt_message Optional message to include with a test 36 * failure. 37 */ 38function assertFalse(observed, opt_message) { 39 assertEquals(false, observed, opt_message); 40} 41 42/** 43 * Verifies that the observed and reference values differ. 44 * @param {Object} reference The target value for comparison. 45 * @param {Object} observed The test result. 46 * @param {string=} opt_message Optional message to include with a test 47 * failure. 48 */ 49function assertNotEqual(reference, observed, opt_message) { 50 if (observed === reference) { 51 var message = 'Assertion Failed\n Observed: ' + observed + 52 '\n Reference: ' + reference; 53 if (opt_message) 54 message = message + '\n ' + opt_message; 55 throw new Error(message); 56 } 57} 58 59/** 60 * Verifies that a test evaluation results in an exception. 61 * @param {!Function} f The test function. 62 */ 63function assertThrows(f) { 64 var triggeredError = false; 65 try { 66 f(); 67 } catch(err) { 68 triggeredError = true; 69 } 70 if (!triggeredError) 71 throw new Error('Assertion Failed: throw expected.'); 72} 73 74/** 75 * Verifies that the contents of the expected and observed arrays match. 76 * @param {!Array} expected The expected result. 77 * @param {!Array} observed The actual result. 78 */ 79function assertArrayEquals(expected, observed) { 80 var v1 = Array.prototype.slice.call(expected); 81 var v2 = Array.prototype.slice.call(observed); 82 var equal = v1.length == v2.length; 83 if (equal) { 84 for (var i = 0; i < v1.length; i++) { 85 if (v1[i] !== v2[i]) { 86 equal = false; 87 break; 88 } 89 } 90 } 91 if (!equal) { 92 var message = 93 ['Assertion Failed', 'Observed: ' + v2, 'Expected: ' + v1].join('\n '); 94 throw new Error(message); 95 } 96} 97 98/** 99 * Verifies that the expected and observed result have the same content. 100 * @param {*} expected The expected result. 101 * @param {*} observed The actual result. 102 */ 103function assertDeepEquals(expected, observed, opt_message) { 104 if (typeof expected == 'object' && expected != null) { 105 assertNotEqual(null, observed); 106 for (var key in expected) { 107 assertTrue(key in observed, opt_message); 108 assertDeepEquals(expected[key], observed[key], opt_message); 109 } 110 for (var key in observed) { 111 assertTrue(key in expected, opt_message); 112 } 113 } else { 114 assertEquals(expected, observed, opt_message); 115 } 116} 117 118/** 119 * Defines runTests. 120 */ 121(function(exports) { 122 /** 123 * List of test cases. 124 * @type {Array.<string>} List of function names for tests to run. 125 */ 126 var testCases = []; 127 128 /** 129 * Indicates if all tests have run successfully. 130 * @type {boolean} 131 */ 132 var cleanTestRun = true; 133 134 /** 135 * Armed during setup of a test to call the matching tear down code. 136 * @type {Function} 137 */ 138 var pendingTearDown = null; 139 140 /** 141 * Runs all functions starting with test and reports success or 142 * failure of the test suite. 143 */ 144 function runTests() { 145 for (var name in window) { 146 if (typeof window[name] == 'function' && /^test/.test(name)) 147 testCases.push(name); 148 } 149 if (!testCases.length) { 150 console.error('Failed to find test cases.'); 151 cleanTestRun = false; 152 } 153 continueTesting(); 154 } 155 156 /** 157 * Runs the next test in the queue. Reports the test results if the queue is 158 * empty. 159 * @param {boolean=} opt_asyncTestFailure Optional parameter indicated if the 160 * last asynchronous test failed. 161 */ 162 function continueTesting(opt_asyncTestFailure) { 163 if (opt_asyncTestFailure) 164 cleanTestRun = false; 165 var done = false; 166 if (pendingTearDown) { 167 pendingTearDown(); 168 pendingTearDown = null; 169 } 170 if (testCases.length > 0) { 171 var fn = testCases.pop(); 172 var isAsyncTest = window[fn].length; 173 try { 174 if (window.setUp) 175 window.setUp(); 176 pendingTearDown = window.tearDown; 177 window[fn](continueTesting); 178 } catch(err) { 179 console.error('Failure in test ' + fn + '\n' + err); 180 console.log(err.stack); 181 cleanTestRun = false; 182 } 183 // Asynchronous tests must manually call continueTesting when complete. 184 if (!isAsyncTest) 185 continueTesting(); 186 } else { 187 done = true; 188 endTests(cleanTestRun); 189 } 190 if (!done) { 191 domAutomationController.setAutomationId(1); 192 domAutomationController.send('PENDING'); 193 } 194 }; 195 196 exports.runTests = runTests; 197})(this); 198 199/** 200 * Signals completion of a test. 201 * @param {boolean} success Indicates if the test completed successfully. 202 */ 203function endTests(success) { 204 domAutomationController.setAutomationId(1); 205 domAutomationController.send(success ? 'SUCCESS' : 'FAILURE'); 206} 207 208window.onerror = function() { 209 endTests(false); 210}; 211