Merge lp:~jjacobs/methanal/util-tests into lp:methanal
- util-tests
- Merge into trunk
Proposed by
Jonathan Jacobs
Status: | Merged |
---|---|
Approved by: | Tristan Seligmann |
Approved revision: | 112 |
Merged at revision: | not available |
Proposed branch: | lp:~jjacobs/methanal/util-tests |
Merge into: | lp:methanal |
Diff against target: |
454 lines 5 files modified
methanal/js/Methanal/Tests/DOMUtil.js (+0/-75) methanal/js/Methanal/Tests/MockBrowser.js (+102/-0) methanal/js/Methanal/Tests/TestUtil.js (+178/-5) methanal/js/Methanal/Tests/TestView.js (+2/-2) methanal/js/Methanal/Util.js (+16/-7) |
To merge this branch: | bzr merge lp:~jjacobs/methanal/util-tests |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tristan Seligmann | Approve | ||
Review via email: mp+13234@code.launchpad.net |
This proposal supersedes a proposal from 2009-10-12.
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Tristan Seligmann (mithrandi) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === removed file 'methanal/js/Methanal/Tests/DOMUtil.js' |
2 | --- methanal/js/Methanal/Tests/DOMUtil.js 2009-10-10 10:28:01 +0000 |
3 | +++ methanal/js/Methanal/Tests/DOMUtil.js 1970-01-01 00:00:00 +0000 |
4 | @@ -1,75 +0,0 @@ |
5 | -// import Divmod.MockBrowser |
6 | - |
7 | - |
8 | - |
9 | -/** |
10 | - * HTMLSelectElement mock implementation. |
11 | - */ |
12 | -Divmod.MockBrowser.Element.subclass( |
13 | - Methanal.Tests.DOMUtil, 'MockHTMLSelectElement').methods( |
14 | - function __init__(self) { |
15 | - Methanal.Tests.DOMUtil.MockHTMLSelectElement.upcall( |
16 | - self, '__init__', 'select'); |
17 | - self.options = []; |
18 | - }, |
19 | - |
20 | - |
21 | - /** |
22 | - * Add a new element to the collection of OPTION elements for this SELECT. |
23 | - */ |
24 | - function add(self, element, before) { |
25 | - var index = Methanal.Util.arrayIndexOf(self.options, before); |
26 | - if (index == -1) { |
27 | - index = self.options.length; |
28 | - self.options.push(element); |
29 | - } else { |
30 | - self.options.splice(index, 0, element); |
31 | - } |
32 | - element.index = index; |
33 | - }); |
34 | - |
35 | - |
36 | - |
37 | -/** |
38 | - * HTMLDocument mock implementation. |
39 | - */ |
40 | -Divmod.MockBrowser.Document.subclass( |
41 | - Methanal.Tests.DOMUtil, 'Document').methods( |
42 | - function __init__(self) { |
43 | - self._elementTags = {}; |
44 | - Methanal.Tests.DOMUtil.Document.upcall(self, '__init__'); |
45 | - }, |
46 | - |
47 | - |
48 | - /** |
49 | - * Register a new type for a tag name. |
50 | - */ |
51 | - function registerElementTag(self, tagName, type) { |
52 | - var old = self._elementTags[tagName]; |
53 | - self._elementTags[tagName] = type; |
54 | - return old; |
55 | - }, |
56 | - |
57 | - |
58 | - function createElement(self, tagName) { |
59 | - var el; |
60 | - if (self._elementTags[tagName]) { |
61 | - el = self._elementTags[tagName](); |
62 | - } else { |
63 | - el = Divmod.MockBrowser.Element(tagName); |
64 | - } |
65 | - el._setOwnerDocument(self); |
66 | - self._allElements.push(el); |
67 | - return el; |
68 | - }); |
69 | - |
70 | - |
71 | - |
72 | -// Only override Divmod's mock document. |
73 | -if (document instanceof Divmod.MockBrowser.Document) { |
74 | - if (!(document instanceof Methanal.Tests.DOMUtil.Document)) { |
75 | - document = Methanal.Tests.DOMUtil.Document(); |
76 | - document.registerElementTag( |
77 | - 'select', Methanal.Tests.DOMUtil.MockHTMLSelectElement); |
78 | - } |
79 | -} |
80 | |
81 | === added file 'methanal/js/Methanal/Tests/MockBrowser.js' |
82 | --- methanal/js/Methanal/Tests/MockBrowser.js 1970-01-01 00:00:00 +0000 |
83 | +++ methanal/js/Methanal/Tests/MockBrowser.js 2009-10-12 17:10:19 +0000 |
84 | @@ -0,0 +1,102 @@ |
85 | +// import Divmod.MockBrowser |
86 | + |
87 | + |
88 | + |
89 | +Divmod.MockBrowser.Element.subclass( |
90 | + Methanal.Tests.MockBrowser, 'Element').methods( |
91 | + function __init__(self, tagName) { |
92 | + Methanal.Tests.MockBrowser.Element.upcall(self, '__init__', tagName); |
93 | + self._updateChildProperties(); |
94 | + }, |
95 | + |
96 | + |
97 | + function _updateChildProperties(self) { |
98 | + self.firstChild = self.childNodes[0] || null; |
99 | + self.lastChild = self.childNodes[self.childNodes.length - 1] || null; |
100 | + }, |
101 | + |
102 | + |
103 | + function appendChild(self, child) { |
104 | + Methanal.Tests.MockBrowser.Element.upcall(self, 'appendChild', child); |
105 | + self._updateChildProperties(); |
106 | + }, |
107 | + |
108 | + |
109 | + function removeChild(self, child) { |
110 | + Methanal.Tests.MockBrowser.Element.upcall(self, 'removeChild', child); |
111 | + self._updateChildProperties(); |
112 | + }); |
113 | + |
114 | + |
115 | + |
116 | +/** |
117 | + * HTMLSelectElement mock implementation. |
118 | + */ |
119 | +Methanal.Tests.MockBrowser.Element.subclass( |
120 | + Methanal.Tests.MockBrowser, 'MockHTMLSelectElement').methods( |
121 | + function __init__(self) { |
122 | + Methanal.Tests.MockBrowser.MockHTMLSelectElement.upcall( |
123 | + self, '__init__', 'select'); |
124 | + self.options = []; |
125 | + }, |
126 | + |
127 | + |
128 | + /** |
129 | + * Add a new element to the collection of OPTION elements for this SELECT. |
130 | + */ |
131 | + function add(self, element, before) { |
132 | + var index = Methanal.Util.arrayIndexOf(self.options, before); |
133 | + if (index == -1) { |
134 | + index = self.options.length; |
135 | + self.options.push(element); |
136 | + } else { |
137 | + self.options.splice(index, 0, element); |
138 | + } |
139 | + element.index = index; |
140 | + }); |
141 | + |
142 | + |
143 | + |
144 | +/** |
145 | + * HTMLDocument mock implementation. |
146 | + */ |
147 | +Divmod.MockBrowser.Document.subclass( |
148 | + Methanal.Tests.MockBrowser, 'Document').methods( |
149 | + function __init__(self) { |
150 | + self._elementTags = {}; |
151 | + Methanal.Tests.MockBrowser.Document.upcall(self, '__init__'); |
152 | + }, |
153 | + |
154 | + |
155 | + /** |
156 | + * Register a new type for a tag name. |
157 | + */ |
158 | + function registerElementTag(self, tagName, type) { |
159 | + var old = self._elementTags[tagName]; |
160 | + self._elementTags[tagName] = type; |
161 | + return old; |
162 | + }, |
163 | + |
164 | + |
165 | + function createElement(self, tagName) { |
166 | + var el; |
167 | + if (self._elementTags[tagName]) { |
168 | + el = self._elementTags[tagName](); |
169 | + } else { |
170 | + el = Methanal.Tests.MockBrowser.Element(tagName); |
171 | + } |
172 | + el._setOwnerDocument(self); |
173 | + self._allElements.push(el); |
174 | + return el; |
175 | + }); |
176 | + |
177 | + |
178 | + |
179 | +// Only override Divmod's mock document. |
180 | +if (document instanceof Divmod.MockBrowser.Document) { |
181 | + if (!(document instanceof Methanal.Tests.MockBrowser.Document)) { |
182 | + document = Methanal.Tests.MockBrowser.Document(); |
183 | + document.registerElementTag( |
184 | + 'select', Methanal.Tests.MockBrowser.MockHTMLSelectElement); |
185 | + } |
186 | +} |
187 | |
188 | === modified file 'methanal/js/Methanal/Tests/TestUtil.js' |
189 | --- methanal/js/Methanal/Tests/TestUtil.js 2009-10-10 10:28:01 +0000 |
190 | +++ methanal/js/Methanal/Tests/TestUtil.js 2009-10-12 17:10:19 +0000 |
191 | @@ -1,11 +1,184 @@ |
192 | // import Divmod.UnitTest |
193 | -// import Divmod.MockBrowser |
194 | // import Methanal.Util |
195 | // import Methanal.Tests.Util |
196 | - |
197 | - |
198 | - |
199 | -Divmod.UnitTest.TestCase.subclass(Methanal.Tests.TestUtil, 'TestUtil').methods( |
200 | +// import Methanal.Tests.MockBrowser |
201 | + |
202 | + |
203 | + |
204 | +Methanal.Tests.Util.TestCase.subclass( |
205 | + Methanal.Tests.TestUtil, 'TestUtil').methods( |
206 | + /** |
207 | + * L{Methanal.Util.addElementClass} and L{Methanal.Util.removeElementClass} |
208 | + * add and remove values to an element's C{className} attribute. |
209 | + */ |
210 | + function test_addRemoveElementClass(self) { |
211 | + var node = document.createElement('div'); |
212 | + var addElementClass = Methanal.Util.addElementClass; |
213 | + var removeElementClass = Methanal.Util.removeElementClass; |
214 | + |
215 | + addElementClass(node, 'foo'); |
216 | + self.assertIdentical(node.className, 'foo'); |
217 | + addElementClass(node, 'foo'); |
218 | + self.assertIdentical(node.className, 'foo'); |
219 | + |
220 | + addElementClass(node, 'bar'); |
221 | + self.assertIdentical(node.className, 'foo bar'); |
222 | + |
223 | + removeElementClass(node, 'foo'); |
224 | + self.assertIdentical(node.className, 'bar'); |
225 | + |
226 | + removeElementClass(node, 'bar'); |
227 | + self.assertIdentical(node.className, ''); |
228 | + |
229 | + removeElementClass(node, 'bar'); |
230 | + self.assertIdentical(node.className, ''); |
231 | + }, |
232 | + |
233 | + |
234 | + /** |
235 | + * Create a DOM node with some children. |
236 | + */ |
237 | + function _makeNodeWithChildren(self) { |
238 | + var T = Methanal.Util.DOMBuilder(document); |
239 | + var node = T('div', {}, [ |
240 | + T('span', {}, ['hello ', |
241 | + T('strong', {}, 'world')]), |
242 | + T('em', {}, ['!'])]); |
243 | + self.assertIdentical(node.childNodes.length, 2); |
244 | + return node; |
245 | + }, |
246 | + |
247 | + |
248 | + /** |
249 | + * L{Methanal.Util.removeNodeContent} removes all of a node's children. |
250 | + */ |
251 | + function test_removeNodeContent(self) { |
252 | + var node = self._makeNodeWithChildren(); |
253 | + Methanal.Util.removeNodeContent(node); |
254 | + self.assertIdentical(node.childNodes.length, 0); |
255 | + }, |
256 | + |
257 | + |
258 | + /** |
259 | + * L{Methanal.Util.replaceNodeContent} replaces a node's children with |
260 | + * some other children. |
261 | + */ |
262 | + function test_replaceNodeContent(self) { |
263 | + var T = Methanal.Util.DOMBuilder(document); |
264 | + var node = self._makeNodeWithChildren(); |
265 | + var children = [T('strong', {}, ['yay'])]; |
266 | + Methanal.Util.replaceNodeContent(node, children); |
267 | + self.assertArraysEqual(node.childNodes, children); |
268 | + }, |
269 | + |
270 | + |
271 | + /** |
272 | + * L{Methanal.Util.replaceNodeText} replaces a node's content with a text |
273 | + * node. |
274 | + */ |
275 | + function test_replaceNodeText(self) { |
276 | + var node = self._makeNodeWithChildren(); |
277 | + Methanal.Util.replaceNodeText(node, 'hey'); |
278 | + self.assertIdentical(node.childNodes.length, 1); |
279 | + self.assertIsInstanceOf(node.firstChild, Divmod.MockBrowser.TextNode); |
280 | + }, |
281 | + |
282 | + |
283 | + /** |
284 | + * L{Methanal.Util.formatDecimal} pretty-prints a number with thousand |
285 | + * separators. |
286 | + */ |
287 | + function test_formatDecimal(self) { |
288 | + var formatDecimal = Methanal.Util.formatDecimal; |
289 | + self.assertIdentical(formatDecimal(1), '1'); |
290 | + self.assertIdentical(formatDecimal(100), '100'); |
291 | + self.assertIdentical(formatDecimal(1000), '1,000'); |
292 | + self.assertIdentical(formatDecimal(10000), '10,000'); |
293 | + self.assertIdentical(formatDecimal(1000000), '1,000,000'); |
294 | + |
295 | + self.assertIdentical(formatDecimal(1000.25), '1,000.25'); |
296 | + self.assertIdentical(formatDecimal(1000000.66), '1,000,000.66'); |
297 | + }, |
298 | + |
299 | + |
300 | + /** |
301 | + * L{Methanal.Util.cycle} produces a callable that iterates through |
302 | + * the original arguments indefinitely. |
303 | + */ |
304 | + function test_cycle(self) { |
305 | + var cycler = Methanal.Util.cycle(42, 5144, 'a'); |
306 | + self.assertIdentical(cycler(), 42); |
307 | + self.assertIdentical(cycler(), 5144); |
308 | + self.assertIdentical(cycler(), 'a'); |
309 | + self.assertIdentical(cycler(), 42); |
310 | + }, |
311 | + |
312 | + |
313 | + /** |
314 | + * L{Methanal.Util.arrayIndexOf} finds the first index of an element in an |
315 | + * array, or C{-1} if no such element exists. |
316 | + */ |
317 | + function test_arrayIndexOf(self) { |
318 | + var arrayIndexOf = Methanal.Util.arrayIndexOf; |
319 | + var a = ['x', 'y', 'z', 'x']; |
320 | + self.assertIdentical(arrayIndexOf(a, 'x'), 0); |
321 | + self.assertIdentical(arrayIndexOf(a, 'y'), 1); |
322 | + self.assertIdentical(arrayIndexOf(a, 'z'), 2); |
323 | + self.assertIdentical(arrayIndexOf(a, 'a'), -1); |
324 | + }, |
325 | + |
326 | + |
327 | + /** |
328 | + * L{Methanal.Util.nodeInserted} calls a widget's C{nodeInserted} method |
329 | + * and the C{nodeInserted} method of each child widget. |
330 | + */ |
331 | + function test_nodeInserted(self) { |
332 | + function makeWidget(childWidgets) { |
333 | + return { |
334 | + 'childWidgets': childWidgets, |
335 | + 'nodeInserted': function () { |
336 | + this.nodeInserted = true; |
337 | + }}; |
338 | + }; |
339 | + |
340 | + var childWidgets = []; |
341 | + for (var i = 0; i < 5; ++i) { |
342 | + childWidgets.push(makeWidget([])); |
343 | + } |
344 | + var widget = makeWidget(childWidgets); |
345 | + |
346 | + Methanal.Util.nodeInserted(widget); |
347 | + self.assertIdentical(widget.nodeInserted, true); |
348 | + for (var i = 0; i < childWidgets.length; ++i) { |
349 | + self.assertIdentical(childWidgets[i].nodeInserted, true); |
350 | + } |
351 | + }, |
352 | + |
353 | + |
354 | + /** |
355 | + * L{Methanal.Util.repr} converts an object to a human-readable string. |
356 | + */ |
357 | + function test_repr(self) { |
358 | + var repr = Methanal.Util.repr; |
359 | + self.assertIdentical(repr('a'), '"a"'); |
360 | + self.assertIdentical(repr('a"b"c'), '"a\\"b\\"c"'); |
361 | + self.assertIdentical(repr(1), '1'); |
362 | + self.assertIdentical(repr(null), 'null'); |
363 | + self.assertIdentical(repr(undefined), 'undefined'); |
364 | + self.assertIdentical(repr(repr), '<function repr>'); |
365 | + var a = [1, 2, 3, 'a', ['b', '"c"']]; |
366 | + self.assertIdentical(repr(a), '[1, 2, 3, "a", ["b", "\\"c\\""]]'); |
367 | + var o = {a: 1}; |
368 | + self.assertIdentical(repr(o), '{"a": 1}'); |
369 | + var o2 = {a: 1, b: 2}; |
370 | + self.assertIdentical(repr(o2), '{"a": 1, "b": 2}'); |
371 | + |
372 | + var type = Divmod.Class.subclass('Foo'); |
373 | + var i = type(); |
374 | + self.assertIdentical(repr(i), i.toString()); |
375 | + }, |
376 | + |
377 | + |
378 | /** |
379 | * L{Methanal.Util.strToInt} converts a base-10 integer value, represented |
380 | * as a C{String}, to an C{Integer}. |
381 | |
382 | === modified file 'methanal/js/Methanal/Tests/TestView.js' |
383 | --- methanal/js/Methanal/Tests/TestView.js 2009-10-10 10:28:01 +0000 |
384 | +++ methanal/js/Methanal/Tests/TestView.js 2009-10-12 17:10:19 +0000 |
385 | @@ -3,7 +3,7 @@ |
386 | // import Methanal.View |
387 | // import Methanal.Util |
388 | // import Methanal.Tests.Util |
389 | -// import Methanal.Tests.DOMUtil |
390 | +// import Methanal.Tests.MockBrowser |
391 | |
392 | |
393 | |
394 | @@ -374,7 +374,7 @@ |
395 | /** |
396 | * Mimic Internet Explorer's broken C{HTMLSelectElement.add} behaviour. |
397 | */ |
398 | -Methanal.Tests.DOMUtil.MockHTMLSelectElement.subclass( |
399 | +Methanal.Tests.MockBrowser.MockHTMLSelectElement.subclass( |
400 | Methanal.Tests.TestView, 'MockIEHTMLSelectElement').methods( |
401 | function add(self, element, before) { |
402 | if (before === null) { |
403 | |
404 | === modified file 'methanal/js/Methanal/Util.js' |
405 | --- methanal/js/Methanal/Util.js 2009-10-10 10:28:01 +0000 |
406 | +++ methanal/js/Methanal/Util.js 2009-10-12 17:10:19 +0000 |
407 | @@ -1,7 +1,3 @@ |
408 | -// import Nevow.Athena |
409 | - |
410 | - |
411 | - |
412 | /** |
413 | * Add a class to an element's "className" attribute. |
414 | * |
415 | @@ -95,7 +91,7 @@ |
416 | * |
417 | * @type node: DOM node |
418 | * |
419 | - * @type children: C{Array} |
420 | + * @type children: C{Array} of C{DOM nodes} |
421 | */ |
422 | Methanal.Util.replaceNodeContent = function replaceNodeContent(node, children) { |
423 | Methanal.Util.removeNodeContent(node); |
424 | @@ -107,7 +103,7 @@ |
425 | |
426 | |
427 | /** |
428 | - * Replace a node's text node with new text. |
429 | + * Replace all of a node's content with text. |
430 | * |
431 | * @type node: DOM node |
432 | * |
433 | @@ -308,7 +304,20 @@ |
434 | return '<function ' + o.name + '>'; |
435 | } |
436 | } else if (o instanceof Array) { |
437 | - return o.toSource(); |
438 | + var names = Methanal.Util.map(Methanal.Util.repr, o); |
439 | + return '[' + names.join(', ') + ']'; |
440 | + } else { |
441 | + if (o.constructor !== undefined && o.constructor.name !== undefined) { |
442 | + var typeName = o.constructor.name; |
443 | + if (typeName == 'Object') { |
444 | + var names = []; |
445 | + var repr = Methanal.Util.repr; |
446 | + for (var key in o) { |
447 | + names.push(repr(key) + ': ' + repr(o[key])); |
448 | + } |
449 | + return '{' + names.join(', ') + '}'; |
450 | + } |
451 | + } |
452 | } |
453 | return o.toString(); |
454 | }; |