author | Giulio Cesare Solaroli <giulio.cesare@clipperz.com> | 2011-10-02 23:56:18 (UTC) |
---|---|---|
committer | Giulio Cesare Solaroli <giulio.cesare@clipperz.com> | 2011-10-02 23:56:18 (UTC) |
commit | ef68436ac04da078ffdcacd7e1f785473a303d45 (patch) (unidiff) | |
tree | c403752d66a2c4775f00affd4fa8431b29c5b68c /frontend/gamma/tests/SimpleTest | |
parent | 597ecfbc0249d83e1b856cbd558340c01237a360 (diff) | |
download | clipperz-ef68436ac04da078ffdcacd7e1f785473a303d45.zip clipperz-ef68436ac04da078ffdcacd7e1f785473a303d45.tar.gz clipperz-ef68436ac04da078ffdcacd7e1f785473a303d45.tar.bz2 |
First version of the newly restructured repository
Diffstat (limited to 'frontend/gamma/tests/SimpleTest') (more/less context) (ignore whitespace changes)
-rw-r--r-- | frontend/gamma/tests/SimpleTest/SimpleTest.Async.js | 169 | ||||
-rw-r--r-- | frontend/gamma/tests/SimpleTest/SimpleTest.js | 424 | ||||
-rw-r--r-- | frontend/gamma/tests/SimpleTest/TestRunner.js | 233 | ||||
-rw-r--r-- | frontend/gamma/tests/SimpleTest/test.css | 28 |
4 files changed, 854 insertions, 0 deletions
diff --git a/frontend/gamma/tests/SimpleTest/SimpleTest.Async.js b/frontend/gamma/tests/SimpleTest/SimpleTest.Async.js new file mode 100644 index 0000000..040cdbf --- a/dev/null +++ b/frontend/gamma/tests/SimpleTest/SimpleTest.Async.js | |||
@@ -0,0 +1,169 @@ | |||
1 | /* | ||
2 | |||
3 | Copyright 2008-2011 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz's Javascript Crypto Library. | ||
6 | Javascript Crypto Library provides web developers with an extensive | ||
7 | and efficient set of cryptographic functions. The library aims to | ||
8 | obtain maximum execution speed while preserving modularity and | ||
9 | reusability. | ||
10 | For further information about its features and functionalities please | ||
11 | refer to http://www.clipperz.com | ||
12 | |||
13 | * Javascript Crypto Library is free software: you can redistribute | ||
14 | it and/or modify it under the terms of the GNU Affero General Public | ||
15 | License as published by the Free Software Foundation, either version | ||
16 | 3 of the License, or (at your option) any later version. | ||
17 | |||
18 | * Javascript Crypto Library is distributed in the hope that it will | ||
19 | be useful, but WITHOUT ANY WARRANTY; without even the implied | ||
20 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
21 | See the GNU Affero General Public License for more details. | ||
22 | |||
23 | * You should have received a copy of the GNU Affero General Public | ||
24 | License along with Javascript Crypto Library. If not, see | ||
25 | <http://www.gnu.org/licenses/>. | ||
26 | |||
27 | */ | ||
28 | |||
29 | MochiKit.Base.update(Clipperz.Async.Deferred.prototype, { | ||
30 | /* | ||
31 | '_addTest': function(anExpectedValue, aDescription, isDeep, aResult) { | ||
32 | if (isDeep) { | ||
33 | SimpleTest.isDeeply(aResult, anExpectedValue, aDescription); | ||
34 | } else { | ||
35 | SimpleTest.is(aResult, anExpectedValue, aDescription); | ||
36 | } | ||
37 | |||
38 | return aResult; | ||
39 | }, | ||
40 | */ | ||
41 | 'addTest': function (anExpectedValue, aDescription, isDeep) { | ||
42 | // this.addMethod(this, '_addTest', anExpectedValue, aDescription, isDeep); | ||
43 | // this.addCallback(Clipperz.Async.test, anExpectedValue, aDescription, isDeep); | ||
44 | |||
45 | if (isDeep) { | ||
46 | // SimpleTest.isDeeply(aResult, anExpectedValue, aDescription); | ||
47 | this.addCallback(Clipperz.Async.Test.isDeeply(anExpectedValue, aDescription)); | ||
48 | } else { | ||
49 | // SimpleTest.is(aResult, anExpectedValue, aDescription); | ||
50 | this.addCallback(Clipperz.Async.Test.is(anExpectedValue, aDescription)); | ||
51 | } | ||
52 | }, | ||
53 | |||
54 | //------------------------------------------------------------------------- | ||
55 | |||
56 | 'shouldSucceed': function (aDescription) { | ||
57 | this.addCallbackPass(SimpleTest.ok, true, aDescription); | ||
58 | this.addErrbackPass (SimpleTest.ok, false, aDescription); | ||
59 | this.addBoth(MochiKit.Async.succeed, null); | ||
60 | }, | ||
61 | |||
62 | 'shouldFail': function (aDescription) { | ||
63 | this.addCallbackPass(SimpleTest.ok, false, aDescription); | ||
64 | this.addErrbackPass (SimpleTest.ok, true, aDescription); | ||
65 | this.addBoth(MochiKit.Async.succeed, null); | ||
66 | }, | ||
67 | |||
68 | //------------------------------------------------------------------------- | ||
69 | |||
70 | }); | ||
71 | |||
72 | |||
73 | Clipperz.Async.Test = {}; | ||
74 | MochiKit.Base.update(Clipperz.Async.Test, { | ||
75 | |||
76 | 'is': function (anExpectedResult, aDescription) { | ||
77 | return MochiKit.Base.partial(function (anExpectedResult, aDescription, aResult) { | ||
78 | SimpleTest.is(aResult, anExpectedResult, aDescription); | ||
79 | |||
80 | return aResult; | ||
81 | }, anExpectedResult, aDescription); | ||
82 | }, | ||
83 | |||
84 | //------------------------------------------------------------------------- | ||
85 | |||
86 | 'ok': function (aDescription) { | ||
87 | return MochiKit.Base.partial(function (aDescription, aResult) { | ||
88 | SimpleTest.ok(aResult, aDescription); | ||
89 | |||
90 | return aResult; | ||
91 | }, aDescription); | ||
92 | }, | ||
93 | |||
94 | //------------------------------------------------------------------------- | ||
95 | |||
96 | 'fail': function(aDescription) { | ||
97 | return MochiKit.Base.partial(function (aDescription, aResult) { | ||
98 | SimpleTest.ok(!aResult, aDescription); | ||
99 | |||
100 | return aResult; | ||
101 | }, aDescription); | ||
102 | }, | ||
103 | |||
104 | //------------------------------------------------------------------------- | ||
105 | |||
106 | 'isDeeply': function (anExpectedResult, aDescription) { | ||
107 | return MochiKit.Base.partial(function (anExpectedResult, aDescription, aResult) { | ||
108 | SimpleTest.isDeeply(aResult, anExpectedResult, aDescription); | ||
109 | |||
110 | return aResult; | ||
111 | }, anExpectedResult, aDescription); | ||
112 | }, | ||
113 | |||
114 | //------------------------------------------------------------------------- | ||
115 | __syntaxFix__: "syntax fix" | ||
116 | }); | ||
117 | |||
118 | |||
119 | SimpleTest.runDeferredTests = function (aName, aTestSet, aTestArguments) { | ||
120 | try { | ||
121 | var deferredTests; | ||
122 | var aTestName; | ||
123 | var title; | ||
124 | |||
125 | deferredTests = new Clipperz.Async.Deferred(aName + " <deferred test set>", aTestArguments); | ||
126 | |||
127 | title = aName; | ||
128 | |||
129 | aTestName = window.location.href.match(/#.*/); | ||
130 | if (aTestName && (aTestName != '#')) { | ||
131 | aTestName = aTestName[0].slice(1); | ||
132 | if (aTestName in aTestSet) { | ||
133 | //Clipperz.log("single test execution, via fragment identifier", aTestName); | ||
134 | title += ' [' + aTestName + ']'; | ||
135 | deferredTests.addCallback(aTestSet[aTestName], aTestArguments); | ||
136 | deferredTests.addErrback(SimpleTest.ok, false, aTestName); | ||
137 | } else { | ||
138 | title = 'WRONG TEST NAME' | ||
139 | deferredTests.addBoth(is, aTestName, null, "Wrong test name selected to run"); | ||
140 | } | ||
141 | } else { | ||
142 | for (aTestName in aTestSet) { | ||
143 | deferredTests.addCallback(aTestSet[aTestName], aTestArguments); | ||
144 | deferredTests.addErrback(SimpleTest.ok, false, aTestName); | ||
145 | deferredTests.addBoth(MochiKit.Async.wait, 0.5); | ||
146 | } | ||
147 | deferredTests.addBoth(is, true, true, "FINISH: completed the full stack of tests"); | ||
148 | } | ||
149 | |||
150 | MochiKit.DOM.currentDocument().title = title; | ||
151 | |||
152 | deferredTests.addBoth(SimpleTest.finish); | ||
153 | deferredTests.callback(); | ||
154 | |||
155 | SimpleTest.waitForExplicitFinish(); | ||
156 | } catch (err) { | ||
157 | var s = "test suite failure!\n"; | ||
158 | var o = {}; | ||
159 | var k = null; | ||
160 | for (k in err) { | ||
161 | // ensure unique keys?! | ||
162 | if (!o[k]) { | ||
163 | s += k + ": " + err[k] + "\n"; | ||
164 | o[k] = err[k]; | ||
165 | } | ||
166 | } | ||
167 | ok ( false, s ); | ||
168 | } | ||
169 | } | ||
diff --git a/frontend/gamma/tests/SimpleTest/SimpleTest.js b/frontend/gamma/tests/SimpleTest/SimpleTest.js new file mode 100644 index 0000000..418954f --- a/dev/null +++ b/frontend/gamma/tests/SimpleTest/SimpleTest.js | |||
@@ -0,0 +1,424 @@ | |||
1 | /** | ||
2 | * SimpleTest, a partial Test.Simple/Test.More API compatible test library. | ||
3 | * | ||
4 | * Why? | ||
5 | * | ||
6 | * Test.Simple doesn't work on IE < 6. | ||
7 | * TODO: | ||
8 | * * Support the Test.Simple API used by MochiKit, to be able to test MochiKit | ||
9 | * itself against IE 5.5 | ||
10 | * | ||
11 | **/ | ||
12 | |||
13 | if (typeof(SimpleTest) == "undefined") { | ||
14 | var SimpleTest = {}; | ||
15 | } | ||
16 | |||
17 | // Check to see if the TestRunner is present and has logging | ||
18 | if (typeof(parent) != "undefined" && parent.TestRunner) { | ||
19 | SimpleTest._logEnabled = parent.TestRunner.logEnabled; | ||
20 | } | ||
21 | |||
22 | SimpleTest._tests = []; | ||
23 | SimpleTest._stopOnLoad = true; | ||
24 | SimpleTest._scopeCopy = {}; | ||
25 | |||
26 | /** | ||
27 | * Saves a copy of the specified scope variables. | ||
28 | */ | ||
29 | SimpleTest.saveScope = function (scope) { | ||
30 | SimpleTest._scopeCopy = {}; | ||
31 | for (var k in scope) { | ||
32 | SimpleTest._scopeCopy[k] = scope[k]; | ||
33 | } | ||
34 | } | ||
35 | |||
36 | /** | ||
37 | * Verifies the specified scope against the stored copy and reports | ||
38 | * any differences as test failures. | ||
39 | */ | ||
40 | SimpleTest.verifyScope = function (scope) { | ||
41 | var filter = ['test', '_firebug','_FirebugConsole','XMLHttpRequest','Audio', | ||
42 | 'XSLTProcessor','Option','Image','scrollMaxX','scrollMaxY', | ||
43 | 'clipboardData']; | ||
44 | for (var k in scope) { | ||
45 | if (MochiKit.Base.findValue(filter, k) < 0) { | ||
46 | var v = scope[k]; | ||
47 | var old = SimpleTest._scopeCopy[k]; | ||
48 | if (v !== old && typeof(old) === "undefined") { | ||
49 | SimpleTest.ok(false, "scope modified, variable " + k + " was added"); | ||
50 | } else if (v !== old) { | ||
51 | SimpleTest.ok(false, "scope modified, variable " + k + " changed from: " + old + ", to: " + v); | ||
52 | } | ||
53 | } | ||
54 | } | ||
55 | for (var k in SimpleTest._scopeCopy) { | ||
56 | if (!(k in scope)) { | ||
57 | SimpleTest.ok(false, "scope modified, variable " + k + " has been removed"); | ||
58 | } | ||
59 | } | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * Something like assert. | ||
64 | */ | ||
65 | SimpleTest.ok = function (condition, name, diag) { | ||
66 | var test = {'result': !!condition, 'name': name, 'diag': diag || ""}; | ||
67 | if (SimpleTest._logEnabled) { | ||
68 | var msg = test.result ? "PASS" : "FAIL"; | ||
69 | msg += " | " + test.name; | ||
70 | if (test.result) { | ||
71 | parent.TestRunner.logger.log(msg); | ||
72 | } else { | ||
73 | msg += " | " + test.diag; | ||
74 | parent.TestRunner.logger.error(msg); | ||
75 | } | ||
76 | } | ||
77 | SimpleTest._tests.push(test); | ||
78 | }; | ||
79 | |||
80 | /** | ||
81 | * Roughly equivalent to ok(a==b, name) | ||
82 | */ | ||
83 | SimpleTest.is = function (a, b, name) { | ||
84 | var repr = MochiKit.Base.repr; | ||
85 | SimpleTest.ok(a == b, name, "got " + repr(a) + ", expected " + repr(b)); | ||
86 | }; | ||
87 | |||
88 | /** | ||
89 | * Roughly equivalent to ok(compare(a,b)==0, name) | ||
90 | */ | ||
91 | SimpleTest.eq = function (a, b, name) { | ||
92 | var base = MochiKit.Base; | ||
93 | var repr = base.repr; | ||
94 | try { | ||
95 | SimpleTest.ok(base.compare(a, b) == 0, name, "got " + repr(a) + ", expected " + repr(b)); | ||
96 | } catch (e) { | ||
97 | SimpleTest.ok(false, name, "exception in compare: " + repr(e)); | ||
98 | } | ||
99 | }; | ||
100 | |||
101 | |||
102 | /** | ||
103 | * Makes a test report, returns it as a DIV element. | ||
104 | **/ | ||
105 | SimpleTest.report = function () { | ||
106 | var DIV = MochiKit.DOM.DIV; | ||
107 | var passed = 0; | ||
108 | var failed = 0; | ||
109 | var results = MochiKit.Base.map( | ||
110 | function (test) { | ||
111 | var cls, msg; | ||
112 | if (test.result) { | ||
113 | passed++; | ||
114 | cls = "test_ok"; | ||
115 | msg = "ok - " + test.name; | ||
116 | } else { | ||
117 | failed++; | ||
118 | cls = "test_not_ok"; | ||
119 | msg = "not ok - " + test.name; | ||
120 | if (test.diag != null && test.diag != "") { | ||
121 | msg += ": " + test.diag; | ||
122 | } | ||
123 | } | ||
124 | return DIV({"class": cls}, msg); | ||
125 | }, | ||
126 | SimpleTest._tests | ||
127 | ); | ||
128 | var summary_class = ((failed == 0) ? 'all_pass' : 'some_fail'); | ||
129 | return DIV({'class': 'tests_report'}, | ||
130 | DIV({'class': 'tests_summary ' + summary_class}, | ||
131 | DIV({'class': 'tests_passed'}, "Passed: " + passed), | ||
132 | DIV({'class': 'tests_failed'}, "Failed: " + failed)), | ||
133 | results | ||
134 | ); | ||
135 | }; | ||
136 | |||
137 | /** | ||
138 | * Toggle element visibility | ||
139 | **/ | ||
140 | SimpleTest.toggle = function(el) { | ||
141 | if (MochiKit.Style.getStyle(el, 'display') == 'block') { | ||
142 | el.style.display = 'none'; | ||
143 | } else { | ||
144 | el.style.display = 'block'; | ||
145 | } | ||
146 | }; | ||
147 | |||
148 | /** | ||
149 | * Toggle visibility for divs with a specific class. | ||
150 | **/ | ||
151 | SimpleTest.toggleByClass = function (cls) { | ||
152 | var elems = MochiKit.DOM.getElementsByTagAndClassName('div', cls); | ||
153 | MochiKit.Base.map(SimpleTest.toggle, elems); | ||
154 | return false; | ||
155 | }; | ||
156 | |||
157 | /** | ||
158 | * Shows the report in the browser | ||
159 | **/ | ||
160 | |||
161 | SimpleTest.showReport = function() { | ||
162 | var base = MochiKit.Base; | ||
163 | var dom = MochiKit.DOM; | ||
164 | var togglePassed = dom.A({'href': '#'}, "Toggle passed tests"); | ||
165 | var toggleFailed = dom.A({'href': '#'}, "Toggle failed tests"); | ||
166 | togglePassed.onclick = base.partial(SimpleTest.toggleByClass, 'test_ok'); | ||
167 | toggleFailed.onclick = base.partial(SimpleTest.toggleByClass, 'test_not_ok'); | ||
168 | var body = document.getElementsByTagName("body")[0]; | ||
169 | var firstChild = body.childNodes[0]; | ||
170 | var addNode; | ||
171 | if (firstChild) { | ||
172 | addNode = function (el) { | ||
173 | body.insertBefore(el, firstChild); | ||
174 | }; | ||
175 | } else { | ||
176 | addNode = function (el) { | ||
177 | body.appendChild(el) | ||
178 | }; | ||
179 | } | ||
180 | addNode(togglePassed); | ||
181 | addNode(dom.SPAN(null, " ")); | ||
182 | addNode(toggleFailed); | ||
183 | addNode(SimpleTest.report()); | ||
184 | }; | ||
185 | |||
186 | /** | ||
187 | * Tells SimpleTest to don't finish the test when the document is loaded, | ||
188 | * useful for asynchronous tests. | ||
189 | * | ||
190 | * When SimpleTest.waitForExplicitFinish is called, | ||
191 | * explicit SimpleTest.finish() is required. | ||
192 | **/ | ||
193 | SimpleTest.waitForExplicitFinish = function () { | ||
194 | SimpleTest._stopOnLoad = false; | ||
195 | }; | ||
196 | |||
197 | /** | ||
198 | * Talks to the TestRunner if being ran on a iframe and the parent has a | ||
199 | * TestRunner object. | ||
200 | **/ | ||
201 | SimpleTest.talkToRunner = function () { | ||
202 | if (typeof(parent) != "undefined" && parent.TestRunner) { | ||
203 | parent.TestRunner.testFinished(document); | ||
204 | } | ||
205 | }; | ||
206 | |||
207 | /** | ||
208 | * Finishes the tests. This is automatically called, except when | ||
209 | * SimpleTest.waitForExplicitFinish() has been invoked. | ||
210 | **/ | ||
211 | SimpleTest.finish = function () { | ||
212 | SimpleTest.showReport(); | ||
213 | SimpleTest.talkToRunner(); | ||
214 | }; | ||
215 | |||
216 | |||
217 | MochiKit.DOM.addLoadEvent(function() { | ||
218 | if (SimpleTest._stopOnLoad) { | ||
219 | SimpleTest.finish(); | ||
220 | } | ||
221 | }); | ||
222 | |||
223 | // --------------- Test.Builder/Test.More isDeeply() ----------------- | ||
224 | |||
225 | |||
226 | SimpleTest.DNE = {dne: 'Does not exist'}; | ||
227 | SimpleTest.LF = "\r\n"; | ||
228 | SimpleTest._isRef = function (object) { | ||
229 | var type = typeof(object); | ||
230 | return type == 'object' || type == 'function'; | ||
231 | }; | ||
232 | |||
233 | |||
234 | SimpleTest._deepCheck = function (e1, e2, stack, seen) { | ||
235 | var ok = false; | ||
236 | // Either they're both references or both not. | ||
237 | var sameRef = !(!SimpleTest._isRef(e1) ^ !SimpleTest._isRef(e2)); | ||
238 | if (e1 == null && e2 == null) { | ||
239 | ok = true; | ||
240 | } else if (e1 != null ^ e2 != null) { | ||
241 | ok = false; | ||
242 | } else if (e1 == SimpleTest.DNE ^ e2 == SimpleTest.DNE) { | ||
243 | ok = false; | ||
244 | } else if (sameRef && e1 == e2) { | ||
245 | // Handles primitives and any variables that reference the same | ||
246 | // object, including functions. | ||
247 | ok = true; | ||
248 | } else if (SimpleTest.isa(e1, 'Array') && SimpleTest.isa(e2, 'Array')) { | ||
249 | ok = SimpleTest._eqArray(e1, e2, stack, seen); | ||
250 | } else if (typeof e1 == "object" && typeof e2 == "object") { | ||
251 | ok = SimpleTest._eqAssoc(e1, e2, stack, seen); | ||
252 | } else { | ||
253 | // If we get here, they're not the same (function references must | ||
254 | // always simply rererence the same function). | ||
255 | stack.push({ vals: [e1, e2] }); | ||
256 | ok = false; | ||
257 | } | ||
258 | return ok; | ||
259 | }; | ||
260 | |||
261 | SimpleTest._eqArray = function (a1, a2, stack, seen) { | ||
262 | // Return if they're the same object. | ||
263 | if (a1 == a2) return true; | ||
264 | |||
265 | // JavaScript objects have no unique identifiers, so we have to store | ||
266 | // references to them all in an array, and then compare the references | ||
267 | // directly. It's slow, but probably won't be much of an issue in | ||
268 | // practice. Start by making a local copy of the array to as to avoid | ||
269 | // confusing a reference seen more than once (such as [a, a]) for a | ||
270 | // circular reference. | ||
271 | for (var j = 0; j < seen.length; j++) { | ||
272 | if (seen[j][0] == a1) { | ||
273 | return seen[j][1] == a2; | ||
274 | } | ||
275 | } | ||
276 | |||
277 | // If we get here, we haven't seen a1 before, so store it with reference | ||
278 | // to a2. | ||
279 | seen.push([ a1, a2 ]); | ||
280 | |||
281 | var ok = true; | ||
282 | // Only examines enumerable attributes. Only works for numeric arrays! | ||
283 | // Associative arrays return 0. So call _eqAssoc() for them, instead. | ||
284 | var max = a1.length > a2.length ? a1.length : a2.length; | ||
285 | if (max == 0) return SimpleTest._eqAssoc(a1, a2, stack, seen); | ||
286 | for (var i = 0; i < max; i++) { | ||
287 | var e1 = i > a1.length - 1 ? SimpleTest.DNE : a1[i]; | ||
288 | var e2 = i > a2.length - 1 ? SimpleTest.DNE : a2[i]; | ||
289 | stack.push({ type: 'Array', idx: i, vals: [e1, e2] }); | ||
290 | if (ok = SimpleTest._deepCheck(e1, e2, stack, seen)) { | ||
291 | stack.pop(); | ||
292 | } else { | ||
293 | break; | ||
294 | } | ||
295 | } | ||
296 | return ok; | ||
297 | }; | ||
298 | |||
299 | SimpleTest._eqAssoc = function (o1, o2, stack, seen) { | ||
300 | // Return if they're the same object. | ||
301 | if (o1 == o2) return true; | ||
302 | |||
303 | // JavaScript objects have no unique identifiers, so we have to store | ||
304 | // references to them all in an array, and then compare the references | ||
305 | // directly. It's slow, but probably won't be much of an issue in | ||
306 | // practice. Start by making a local copy of the array to as to avoid | ||
307 | // confusing a reference seen more than once (such as [a, a]) for a | ||
308 | // circular reference. | ||
309 | seen = seen.slice(0); | ||
310 | for (var j = 0; j < seen.length; j++) { | ||
311 | if (seen[j][0] == o1) { | ||
312 | return seen[j][1] == o2; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | // If we get here, we haven't seen o1 before, so store it with reference | ||
317 | // to o2. | ||
318 | seen.push([ o1, o2 ]); | ||
319 | |||
320 | // They should be of the same class. | ||
321 | |||
322 | var ok = true; | ||
323 | // Only examines enumerable attributes. | ||
324 | var o1Size = 0; for (var i in o1) o1Size++; | ||
325 | var o2Size = 0; for (var i in o2) o2Size++; | ||
326 | var bigger = o1Size > o2Size ? o1 : o2; | ||
327 | for (var i in bigger) { | ||
328 | var e1 = o1[i] == undefined ? SimpleTest.DNE : o1[i]; | ||
329 | var e2 = o2[i] == undefined ? SimpleTest.DNE : o2[i]; | ||
330 | stack.push({ type: 'Object', idx: i, vals: [e1, e2] }); | ||
331 | if (ok = SimpleTest._deepCheck(e1, e2, stack, seen)) { | ||
332 | stack.pop(); | ||
333 | } else { | ||
334 | break; | ||
335 | } | ||
336 | } | ||
337 | return ok; | ||
338 | }; | ||
339 | |||
340 | SimpleTest._formatStack = function (stack) { | ||
341 | var variable = '$Foo'; | ||
342 | for (var i = 0; i < stack.length; i++) { | ||
343 | var entry = stack[i]; | ||
344 | var type = entry['type']; | ||
345 | var idx = entry['idx']; | ||
346 | if (idx != null) { | ||
347 | if (/^\d+$/.test(idx)) { | ||
348 | // Numeric array index. | ||
349 | variable += '[' + idx + ']'; | ||
350 | } else { | ||
351 | // Associative array index. | ||
352 | idx = idx.replace("'", "\\'"); | ||
353 | variable += "['" + idx + "']"; | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | |||
358 | var vals = stack[stack.length-1]['vals'].slice(0, 2); | ||
359 | var vars = [ | ||
360 | variable.replace('$Foo', 'got'), | ||
361 | variable.replace('$Foo', 'expected') | ||
362 | ]; | ||
363 | |||
364 | var out = "Structures begin differing at:" + SimpleTest.LF; | ||
365 | for (var i = 0; i < vals.length; i++) { | ||
366 | var val = vals[i]; | ||
367 | if (val == null) { | ||
368 | val = 'undefined'; | ||
369 | } else { | ||
370 | val == SimpleTest.DNE ? "Does not exist" : "'" + val + "'"; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | out += vars[0] + ' = ' + vals[0] + SimpleTest.LF; | ||
375 | out += vars[1] + ' = ' + vals[1] + SimpleTest.LF; | ||
376 | |||
377 | return ' ' + out; | ||
378 | }; | ||
379 | |||
380 | |||
381 | SimpleTest.isDeeply = function (it, as, name) { | ||
382 | var ok; | ||
383 | // ^ is the XOR operator. | ||
384 | if (SimpleTest._isRef(it) ^ SimpleTest._isRef(as)) { | ||
385 | // One's a reference, one isn't. | ||
386 | ok = false; | ||
387 | } else if (!SimpleTest._isRef(it) && !SimpleTest._isRef(as)) { | ||
388 | // Neither is an object. | ||
389 | ok = SimpleTest.is(it, as, name); | ||
390 | } else { | ||
391 | // We have two objects. Do a deep comparison. | ||
392 | var stack = [], seen = []; | ||
393 | if ( SimpleTest._deepCheck(it, as, stack, seen)) { | ||
394 | ok = SimpleTest.ok(true, name); | ||
395 | } else { | ||
396 | ok = SimpleTest.ok(false, name, SimpleTest._formatStack(stack)); | ||
397 | } | ||
398 | } | ||
399 | return ok; | ||
400 | }; | ||
401 | |||
402 | SimpleTest.typeOf = function (object) { | ||
403 | var c = Object.prototype.toString.apply(object); | ||
404 | var name = c.substring(8, c.length - 1); | ||
405 | if (name != 'Object') return name; | ||
406 | // It may be a non-core class. Try to extract the class name from | ||
407 | // the constructor function. This may not work in all implementations. | ||
408 | if (/function ([^(\s]+)/.test(Function.toString.call(object.constructor))) { | ||
409 | return RegExp.$1; | ||
410 | } | ||
411 | // No idea. :-( | ||
412 | return name; | ||
413 | }; | ||
414 | |||
415 | SimpleTest.isa = function (object, clas) { | ||
416 | return SimpleTest.typeOf(object) == clas; | ||
417 | }; | ||
418 | |||
419 | |||
420 | |||
421 | // Global symbols: | ||
422 | var ok = SimpleTest.ok; | ||
423 | var is = SimpleTest.is; | ||
424 | var isDeeply = SimpleTest.isDeeply; | ||
diff --git a/frontend/gamma/tests/SimpleTest/TestRunner.js b/frontend/gamma/tests/SimpleTest/TestRunner.js new file mode 100644 index 0000000..81a36cf --- a/dev/null +++ b/frontend/gamma/tests/SimpleTest/TestRunner.js | |||
@@ -0,0 +1,233 @@ | |||
1 | /** | ||
2 | * TestRunner: A test runner for SimpleTest | ||
3 | * TODO: | ||
4 | * | ||
5 | * * Avoid moving iframes: That causes reloads on mozilla and opera. | ||
6 | * | ||
7 | * | ||
8 | **/ | ||
9 | var TestRunner = {}; | ||
10 | TestRunner.logEnabled = false; | ||
11 | TestRunner._iframes = {}; | ||
12 | TestRunner._iframeDocuments = {}; | ||
13 | TestRunner._iframeRows = {}; | ||
14 | TestRunner._currentTest = 0; | ||
15 | TestRunner._urls = []; | ||
16 | TestRunner._testsDiv = DIV(); | ||
17 | TestRunner._progressDiv = DIV(); | ||
18 | TestRunner._summaryDiv = DIV(null, | ||
19 | H1(null, "Tests Summary"), | ||
20 | TABLE(null, | ||
21 | THEAD(null, | ||
22 | TR(null, | ||
23 | TH(null, "Test"), | ||
24 | TH(null, "Passed"), | ||
25 | TH(null, "Failed") | ||
26 | ) | ||
27 | ), | ||
28 | TFOOT(/*null, TR(null, TH(null, "-"), TH(null, "--"), TH(null, "---"))*/), | ||
29 | TBODY() | ||
30 | ) | ||
31 | ); | ||
32 | |||
33 | /** | ||
34 | * This function is called after generating the summary. | ||
35 | **/ | ||
36 | TestRunner.onComplete = null; | ||
37 | |||
38 | /** | ||
39 | * If logEnabled is true, this is the logger that will be used. | ||
40 | **/ | ||
41 | TestRunner.logger = MochiKit.Logging.logger; | ||
42 | |||
43 | /** | ||
44 | * Toggle element visibility | ||
45 | **/ | ||
46 | TestRunner._toggle = function(el) { | ||
47 | if (el.className == "noshow") { | ||
48 | el.className = ""; | ||
49 | el.style.cssText = ""; | ||
50 | } else { | ||
51 | el.className = "noshow"; | ||
52 | el.style.cssText = "width:0px; height:0px; border:0px;"; | ||
53 | } | ||
54 | }; | ||
55 | |||
56 | |||
57 | /** | ||
58 | * Creates the iframe that contains a test | ||
59 | **/ | ||
60 | TestRunner._makeIframe = function (url) { | ||
61 | var iframe = document.createElement('iframe'); | ||
62 | iframe.src = url; | ||
63 | iframe.name = url; | ||
64 | iframe.width = "500"; | ||
65 | var tbody = TestRunner._summaryDiv.getElementsByTagName("tbody")[0]; | ||
66 | var tr = TR(null, TD({'colspan': '3'}, iframe)); | ||
67 | iframe._row = tr; | ||
68 | tbody.appendChild(tr); | ||
69 | return iframe; | ||
70 | }; | ||
71 | |||
72 | /** | ||
73 | * TestRunner entry point. | ||
74 | * | ||
75 | * The arguments are the URLs of the test to be ran. | ||
76 | * | ||
77 | **/ | ||
78 | TestRunner.runTests = function (/*url...*/) { | ||
79 | if (TestRunner.logEnabled) | ||
80 | TestRunner.logger.log("SimpleTest START"); | ||
81 | |||
82 | var body = document.getElementsByTagName("body")[0]; | ||
83 | appendChildNodes(body, | ||
84 | TestRunner._testsDiv, | ||
85 | TestRunner._progressDiv, | ||
86 | TestRunner._summaryDiv | ||
87 | ); | ||
88 | for (var i = 0; i < arguments.length; i++) { | ||
89 | TestRunner._urls.push(arguments[i]); | ||
90 | } | ||
91 | |||
92 | TestRunner.runNextTest(); | ||
93 | }; | ||
94 | |||
95 | /** | ||
96 | * Run the next test. If no test remains, calls makeSummary | ||
97 | **/ | ||
98 | TestRunner.runNextTest = function() { | ||
99 | if (TestRunner._currentTest < TestRunner._urls.length) { | ||
100 | var url = TestRunner._urls[TestRunner._currentTest]; | ||
101 | var progress = SPAN(null, | ||
102 | "Running ", A({href:url}, url), "..." | ||
103 | ); | ||
104 | |||
105 | if (TestRunner.logEnabled) | ||
106 | TestRunner.logger.log(scrapeText(progress)); | ||
107 | |||
108 | TestRunner._progressDiv.appendChild(progress); | ||
109 | TestRunner._iframes[url] = TestRunner._makeIframe(url); | ||
110 | } else { | ||
111 | TestRunner.makeSummary(); | ||
112 | if (TestRunner.onComplete) { | ||
113 | TestRunner.onComplete(); | ||
114 | } | ||
115 | } | ||
116 | }; | ||
117 | |||
118 | /** | ||
119 | * This stub is called by SimpleTest when a test is finished. | ||
120 | **/ | ||
121 | TestRunner.testFinished = function (doc) { | ||
122 | appendChildNodes(TestRunner._progressDiv, SPAN(null, "Done"), BR()); | ||
123 | var finishedURL = TestRunner._urls[TestRunner._currentTest]; | ||
124 | |||
125 | if (TestRunner.logEnabled) | ||
126 | TestRunner.logger.debug("SimpleTest finished " + finishedURL); | ||
127 | |||
128 | TestRunner._iframeDocuments[finishedURL] = doc; | ||
129 | // TestRunner._iframes[finishedURL].style.display = "none"; | ||
130 | if (finishedURL != null) { | ||
131 | TestRunner._toggle(TestRunner._iframes[finishedURL]); | ||
132 | TestRunner._currentTest++; | ||
133 | TestRunner.runNextTest(); | ||
134 | } | ||
135 | }; | ||
136 | |||
137 | /** | ||
138 | * Display the summary in the browser | ||
139 | **/ | ||
140 | /* | ||
141 | TestRunner.makeSummary = function() { | ||
142 | if (TestRunner.logEnabled) | ||
143 | TestRunner.logger.log("SimpleTest FINISHED"); | ||
144 | var rows = []; | ||
145 | for (var url in TestRunner._iframeDocuments) { | ||
146 | var doc = TestRunner._iframeDocuments[url]; | ||
147 | var nOK = withDocument(doc, | ||
148 | partial(getElementsByTagAndClassName, 'div', 'test_ok') | ||
149 | ).length; | ||
150 | var nNotOK = withDocument(doc, | ||
151 | partial(getElementsByTagAndClassName, 'div', 'test_not_ok') | ||
152 | ).length; | ||
153 | var toggle = partial(TestRunner._toggle, TestRunner._iframes[url]); | ||
154 | var jsurl = "TestRunner._toggle(TestRunner._iframes['" + url + "'])"; | ||
155 | var row = TR( | ||
156 | {'style': {'backgroundColor': nNotOK > 0 ? "#f00":"#0f0"}}, | ||
157 | TD(null, url), | ||
158 | TD(null, nOK), | ||
159 | TD(null, nNotOK) | ||
160 | ); | ||
161 | row.onclick = toggle; | ||
162 | var tbody = TestRunner._summaryDiv.getElementsByTagName("tbody")[0]; | ||
163 | tbody.insertBefore(row, TestRunner._iframes[url]._row) | ||
164 | } | ||
165 | }; | ||
166 | */ | ||
167 | |||
168 | TestRunner.makeSummary = function() { | ||
169 | var base = MochiKit.Base; | ||
170 | var dom = MochiKit.DOM; | ||
171 | var iter = MochiKit.Iter; | ||
172 | vartotal_Ok, total_not_Ok; | ||
173 | |||
174 | total_Ok = 0; | ||
175 | total_not_Ok = 0; | ||
176 | |||
177 | if (TestRunner.logEnabled) | ||
178 | TestRunner.logger.log("SimpleTest FINISHED"); | ||
179 | var rows = []; | ||
180 | for (var url in TestRunner._iframeDocuments) { | ||
181 | var doc = TestRunner._iframeDocuments[url]; | ||
182 | var nOK = withDocument(doc, | ||
183 | partial(getElementsByTagAndClassName, 'div', 'test_ok') | ||
184 | ).length; | ||
185 | var nNotOK = withDocument(doc, | ||
186 | partial(getElementsByTagAndClassName, 'div', 'test_not_ok') | ||
187 | ).length; | ||
188 | var toggle = partial(TestRunner._toggle, TestRunner._iframes[url]); | ||
189 | var jsurl = "TestRunner._toggle(TestRunner._iframes['" + url + "'])"; | ||
190 | var row = TR( | ||
191 | {'style': {'backgroundColor': nNotOK > 0 ? "#f00":"#0f0"}}, | ||
192 | TD(null, url), | ||
193 | TD(null, nOK), | ||
194 | TD(null, nNotOK) | ||
195 | ); | ||
196 | row.onclick = toggle; | ||
197 | var tbody = TestRunner._summaryDiv.getElementsByTagName("tbody")[0]; | ||
198 | tbody.insertBefore(row, TestRunner._iframes[url]._row); | ||
199 | |||
200 | total_Ok += nOK; | ||
201 | total_not_Ok += nNotOK; | ||
202 | } | ||
203 | |||
204 | { | ||
205 | var tfoot = TestRunner._summaryDiv.getElementsByTagName("tfoot")[0]; | ||
206 | tfoot.appendChild(TR(null, | ||
207 | TH(null, ""), | ||
208 | TH({'style':"color:green;"}, total_Ok), | ||
209 | TH({'style':"color:" + ((total_not_Ok == 0) ? 'black' : 'red') + ";"}, total_not_Ok) | ||
210 | )); | ||
211 | } | ||
212 | |||
213 | var testRunnerResults; | ||
214 | var i, c; | ||
215 | |||
216 | testRunnerResults = dom.DIV({'style': 'display:none; visibility:hidden;'}, null); | ||
217 | |||
218 | c = total_Ok; | ||
219 | for (i=0; i<c; i++) { | ||
220 | dom.appendChildNodes(testRunnerResults, dom.DIV({'class': 'test_ok'}, "ok")); | ||
221 | } | ||
222 | |||
223 | c = total_not_Ok; | ||
224 | for (i=0; i<c; i++) { | ||
225 | dom.appendChildNodes(testRunnerResults, dom.DIV({'class': 'test_not_ok'}, "fail")); | ||
226 | } | ||
227 | |||
228 | document.getElementsByTagName("body")[0].appendChild(testRunnerResults); | ||
229 | |||
230 | if (typeof(parent) != "undefined" && parent.TestRunner) { | ||
231 | parent.TestRunner.testFinished(document); | ||
232 | } | ||
233 | }; | ||
diff --git a/frontend/gamma/tests/SimpleTest/test.css b/frontend/gamma/tests/SimpleTest/test.css new file mode 100644 index 0000000..38a4014 --- a/dev/null +++ b/frontend/gamma/tests/SimpleTest/test.css | |||
@@ -0,0 +1,28 @@ | |||
1 | .test_ok { | ||
2 | color: green; | ||
3 | display: none; | ||
4 | } | ||
5 | .test_not_ok { | ||
6 | color: red; | ||
7 | display: block; | ||
8 | } | ||
9 | |||
10 | .test_ok, .test_not_ok { | ||
11 | border-bottom-width: 2px; | ||
12 | border-bottom-style: solid; | ||
13 | border-bottom-color: black; | ||
14 | } | ||
15 | |||
16 | .all_pass { | ||
17 | background-color: lime; | ||
18 | } | ||
19 | |||
20 | .some_fail { | ||
21 | background-color: red; | ||
22 | } | ||
23 | |||
24 | .tests_report { | ||
25 | border-width: 2px; | ||
26 | border-style: solid; | ||
27 | width: 20em; | ||
28 | } | ||