OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are |
| 4 // met: |
| 5 // |
| 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. |
| 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 |
| 28 // This file emulates Mocha test framework used in promises-aplus tests. |
| 29 |
| 30 var describe; |
| 31 var it; |
| 32 var specify; |
| 33 var before; |
| 34 var after; |
| 35 var beforeEach; |
| 36 var afterEach; |
| 37 var RunAllTests; |
| 38 |
| 39 var assert = require('assert'); |
| 40 |
| 41 (function() { |
| 42 var TIMEOUT = 1000; |
| 43 |
| 44 function PostMicrotask(fn) { |
| 45 var o = {}; |
| 46 Object.observe(o, function() { |
| 47 fn(); |
| 48 }); |
| 49 // Change something to enqueue a microtask. |
| 50 o.x = 'hello'; |
| 51 } |
| 52 |
| 53 var context = { |
| 54 beingDescribed: undefined, |
| 55 currentSuiteIndex: 0, |
| 56 suites: [] |
| 57 }; |
| 58 |
| 59 function Run() { |
| 60 function current() { |
| 61 while (context.currentSuiteIndex < context.suites.length && |
| 62 context.suites[context.currentSuiteIndex].hasRun) { |
| 63 ++context.currentSuiteIndex; |
| 64 } |
| 65 if (context.suites.length == context.currentSuiteIndex) { |
| 66 return undefined; |
| 67 } |
| 68 return context.suites[context.currentSuiteIndex]; |
| 69 } |
| 70 var suite = current(); |
| 71 if (!suite) { |
| 72 // done |
| 73 print('All tests have run.'); |
| 74 return; |
| 75 } |
| 76 suite.Run(); |
| 77 } |
| 78 |
| 79 RunAllTests = function() { |
| 80 context.currentSuiteIndex = 0; |
| 81 var numRegularTestCases = 0; |
| 82 for (var i = 0; i < context.suites.length; ++i) { |
| 83 numRegularTestCases += context.suites[i].numRegularTestCases(); |
| 84 } |
| 85 print(context.suites.length + ' suites and ' + numRegularTestCases + |
| 86 ' test cases are found'); |
| 87 Run(); |
| 88 }; |
| 89 |
| 90 function TestCase(name, before, fn, after, isRegular) { |
| 91 this.name = name; |
| 92 this.before = before; |
| 93 this.fn = fn; |
| 94 this.after = after; |
| 95 this.isRegular = isRegular; |
| 96 this.hasDone = false; |
| 97 } |
| 98 |
| 99 TestCase.prototype.RunFunction = function(suite, fn, postAction) { |
| 100 if (!fn) { |
| 101 postAction(); |
| 102 return; |
| 103 } |
| 104 try { |
| 105 if (fn.length === 0) { |
| 106 // synchronous |
| 107 fn(); |
| 108 postAction(); |
| 109 } else { |
| 110 // asynchronous |
| 111 fn(postAction); |
| 112 } |
| 113 } catch (e) { |
| 114 suite.ReportError(this, e); |
| 115 } |
| 116 } |
| 117 |
| 118 TestCase.prototype.MarkAsDone = function() { |
| 119 this.hasDone = true; |
| 120 clearTimeout(this.timer); |
| 121 } |
| 122 |
| 123 TestCase.prototype.Run = function(suite, postAction) { |
| 124 print('Running ' + suite.description + '#' + this.name + ' ...'); |
| 125 assert.clear(); |
| 126 |
| 127 this.timer = setTimeout(function() { |
| 128 suite.ReportError(this, Error('timeout')); |
| 129 }.bind(this), TIMEOUT); |
| 130 |
| 131 this.RunFunction(suite, this.before, function(e) { |
| 132 if (this.hasDone) { |
| 133 return; |
| 134 } |
| 135 if (e instanceof Error) { |
| 136 return suite.ReportError(this, e); |
| 137 } |
| 138 if (assert.fails.length > 0) { |
| 139 return suite.ReportError(this, assert.fails[0]); |
| 140 } |
| 141 this.RunFunction(suite, this.fn, function(e) { |
| 142 if (this.hasDone) { |
| 143 return; |
| 144 } |
| 145 if (e instanceof Error) { |
| 146 return suite.ReportError(this, e); |
| 147 } |
| 148 if (assert.fails.length > 0) { |
| 149 return suite.ReportError(this, assert.fails[0]); |
| 150 } |
| 151 this.RunFunction(suite, this.after, function(e) { |
| 152 if (this.hasDone) { |
| 153 return; |
| 154 } |
| 155 if (e instanceof Error) { |
| 156 return suite.ReportError(this, e); |
| 157 } |
| 158 if (assert.fails.length > 0) { |
| 159 return suite.ReportError(this, assert.fails[0]); |
| 160 } |
| 161 this.MarkAsDone(); |
| 162 if (this.isRegular) { |
| 163 print('PASS: ' + suite.description + '#' + this.name); |
| 164 } |
| 165 PostMicrotask(postAction); |
| 166 }.bind(this)); |
| 167 }.bind(this)); |
| 168 }.bind(this)); |
| 169 }; |
| 170 |
| 171 function TestSuite(described) { |
| 172 this.description = described.description; |
| 173 this.cases = []; |
| 174 this.currentIndex = 0; |
| 175 this.hasRun = false; |
| 176 |
| 177 if (described.before) { |
| 178 this.cases.push(new TestCase(this.description + ' :before', undefined, |
| 179 described.before, undefined, false)); |
| 180 } |
| 181 for (var i = 0; i < described.cases.length; ++i) { |
| 182 this.cases.push(new TestCase(described.cases[i].description, |
| 183 described.beforeEach, |
| 184 described.cases[i].fn, |
| 185 described.afterEach, |
| 186 true)); |
| 187 } |
| 188 if (described.after) { |
| 189 this.cases.push(new TestCase(this.description + ' :after', |
| 190 undefined, described.after, undefined, false)); |
| 191 } |
| 192 } |
| 193 |
| 194 TestSuite.prototype.Run = function() { |
| 195 this.hasRun = this.currentIndex === this.cases.length; |
| 196 if (this.hasRun) { |
| 197 PostMicrotask(Run); |
| 198 return; |
| 199 } |
| 200 |
| 201 // TestCase.prototype.Run cannot throw an exception. |
| 202 this.cases[this.currentIndex].Run(this, function() { |
| 203 ++this.currentIndex; |
| 204 PostMicrotask(Run); |
| 205 }.bind(this)); |
| 206 }; |
| 207 |
| 208 TestSuite.prototype.numRegularTestCases = function() { |
| 209 var n = 0; |
| 210 for (var i = 0; i < this.cases.length; ++i) { |
| 211 if (this.cases[i].isRegular) { |
| 212 ++n; |
| 213 } |
| 214 } |
| 215 return n; |
| 216 } |
| 217 |
| 218 TestSuite.prototype.ReportError = function(testCase, e) { |
| 219 if (testCase.hasDone) { |
| 220 return; |
| 221 } |
| 222 testCase.MarkAsDone(); |
| 223 this.hasRun = this.currentIndex === this.cases.length; |
| 224 print('FAIL: ' + this.description + '#' + testCase.name + ': ' + |
| 225 e.name + ' (' + e.message + ')'); |
| 226 ++this.currentIndex; |
| 227 PostMicrotask(Run); |
| 228 }; |
| 229 |
| 230 describe = function(description, fn) { |
| 231 var parent = context.beingDescribed; |
| 232 var incomplete = { |
| 233 cases: [], |
| 234 description: parent ? parent.description + ' ' + description : description, |
| 235 parent: parent, |
| 236 }; |
| 237 context.beingDescribed = incomplete; |
| 238 fn(); |
| 239 context.beingDescribed = parent; |
| 240 |
| 241 context.suites.push(new TestSuite(incomplete)); |
| 242 } |
| 243 |
| 244 specify = it = function(description, fn) { |
| 245 context.beingDescribed.cases.push({description: description, fn: fn}); |
| 246 } |
| 247 |
| 248 before = function(fn) { |
| 249 context.beingDescribed.before = fn; |
| 250 } |
| 251 |
| 252 after = function(fn) { |
| 253 context.beingDescribed.after = fn; |
| 254 } |
| 255 |
| 256 beforeEach = function(fn) { |
| 257 context.beingDescribed.beforeEach = fn; |
| 258 } |
| 259 |
| 260 afterEach = function(fn) { |
| 261 context.beingDescribed.afterEach = fn; |
| 262 } |
| 263 |
| 264 }()); |
OLD | NEW |