1 if (typeof(dojo
) != 'undefined') { dojo
.require('MochiKit.Base'); }
2 if (typeof(JSAN
) != 'undefined') { JSAN
.use('MochiKit.Base'); }
3 if (typeof(tests
) == 'undefined') { tests
= {}; }
5 tests
.test_Base = function (t
) {
7 var not_self
= {"toString": function () { return "not self"; } };
8 var self
= {"toString": function () { return "self"; } };
9 var func = function (arg
) { return this.toString() + " " + arg
; };
10 var boundFunc
= bind(func
, self
);
11 not_self
.boundFunc
= boundFunc
;
13 t
.is( isEmpty([], [], ""), true, "isEmpty true" )
14 t
.is( isEmpty([], [1], ""), true, "isEmpty true" )
15 t
.is( isNotEmpty([], [], ""), false, "isNotEmpty false" )
16 t
.is( isNotEmpty([], [1], ""), false, "isNotEmpty false" )
18 t
.is( isEmpty([1], [1], "1"), false, "isEmpty false" )
19 t
.is( isEmpty([1], [1], "1"), false, "isEmpty false" )
20 t
.is( isNotEmpty([1], [1], "1"), true, "isNotEmpty true" )
21 t
.is( isNotEmpty([1], [1], "1"), true, "isNotEmpty true" )
23 t
.is( boundFunc("foo"), "self foo", "boundFunc bound to self properly" );
24 t
.is( not_self
.boundFunc("foo"), "self foo", "boundFunc bound to self on another obj" );
25 t
.is( bind(boundFunc
, not_self
)("foo"), "not self foo", "boundFunc successfully rebound!" );
26 t
.is( bind(boundFunc
, undefined, "foo")(), "self foo", "boundFunc partial no self change" );
27 t
.is( bind(boundFunc
, not_self
, "foo")(), "not self foo", "boundFunc partial self change" );
30 not_self
= {"toString": function () { return "not self"; } };
31 self
= {"toString": function () { return "self"; } };
32 func = function (arg
) { return this.toString() + " " + arg
; };
33 var boundMethod
= method(self
, func
);
34 not_self
.boundMethod
= boundMethod
;
36 t
.is( boundMethod("foo"), "self foo", "boundMethod bound to self properly" );
37 t
.is( not_self
.boundMethod("foo"), "self foo", "boundMethod bound to self on another obj" );
38 t
.is( method(not_self
, boundMethod
)("foo"), "not self foo", "boundMethod successfully rebound!" );
39 t
.is( method(undefined, boundMethod
, "foo")(), "self foo", "boundMethod partial no self change" );
40 t
.is( method(not_self
, boundMethod
, "foo")(), "not self foo", "boundMethod partial self change" );
47 var O = function (value
) {
51 O
.prototype.func = function () {
55 var o
= new O("boring");
59 t
.is( o
.func(), "boring", "bindMethods doesn't break shit" );
60 t
.is( p
.func(), "boring", "bindMethods works on other objects" );
61 t
.is( func(), "boring", "bindMethods works on functions" );
64 t
.ok( p
instanceof O
, "cloned correct inheritance" );
66 t
.ok( q
instanceof O
, "clone-cloned correct inheritance" );
68 t
.is( p
.foo
, undefined, "clone-clone is copy-on-write" );
70 t
.is( o
.bar
, undefined, "clone is copy-on-write" );
71 t
.is( q
.bar
, "foo", "clone-clone has proper delegation" );
73 p
.func
= bind(p
.func
, null);
74 t
.is( p
.func(), "boring", "clone function calls correct" );
76 t
.is( q
.func(), "awesome", "clone really does work" );
78 // test boring boolean funcs
80 t
.is( isCallable(isCallable
), true, "isCallable returns true on itself" );
81 t
.is( isCallable(1), false, "isCallable returns false on numbers" );
83 t
.is( isUndefined(null), false, "null is not undefined" );
84 t
.is( isUndefined(""), false, "empty string is not undefined" );
85 t
.is( isUndefined(undefined), true, "undefined is undefined" );
86 t
.is( isUndefined({}.foo
), true, "missing property is undefined" );
88 t
.is( isUndefinedOrNull(null), true, "null is undefined or null" );
89 t
.is( isUndefinedOrNull(""), false, "empty string is not undefined or null" );
90 t
.is( isUndefinedOrNull(undefined), true, "undefined is undefined or null" );
91 t
.is( isUndefinedOrNull({}.foo
), true, "missing property is undefined or null" );
93 // test extension of arrays
96 var three
= [1, 2, 3];
99 t
.ok( objEqual(a
, [2, 3]), "extend to an empty array" );
101 t
.ok( objEqual(a
, [2, 3, 2, 3]), "extend to a non-empty array" );
104 t
.ok( objEqual(b
, three
), "extend of an empty array" );
106 t
.is( compare(1, 2), -1, "numbers compare lt" );
107 t
.is( compare(2, 1), 1, "numbers compare gt" );
108 t
.is( compare(1, 1), 0, "numbers compare eq" );
109 t
.is( compare([1], [1]), 0, "arrays compare eq" );
110 t
.is( compare([1], [1, 2]), -1, "arrays compare lt (length)" );
111 t
.is( compare([1, 2], [2, 1]), -1, "arrays compare lt (contents)" );
112 t
.is( compare([1, 2], [1]), 1, "arrays compare gt (length)" );
113 t
.is( compare([2, 1], [1, 1]), 1, "arrays compare gt (contents)" );
115 // test partial application
117 var func = function (a
, b
) {
118 if (arguments
.length
!= 2) {
121 return this.value
+ a
+ b
;
124 var self
= {"value": 1, "func": func
};
125 var self2
= {"value": 2};
126 t
.is( self
.func(2, 3), 6, "setup for test is correct" );
127 self
.funcTwo
= partial(self
.func
, 2);
128 t
.is( self
.funcTwo(3), 6, "partial application works" );
129 t
.is( self
.funcTwo(3), 6, "partial application works still" );
130 t
.is( bind(self
.funcTwo
, self2
)(3), 7, "rebinding partial works" );
131 self
.funcTwo
= bind(bind(self
.funcTwo
, self2
), null);
132 t
.is( self
.funcTwo(3), 6, "re-unbinding partial application works" );
136 // ... looks a lot like a DOM tree on purpose
138 "id": "nodeWalkTestTree",
146 {"ignored": "object"},
149 "test:skipchildren": "1",
150 "childNodes": [{"test:int": 6}]
159 var visitedNodes
= [];
160 nodeWalk(tree
, function (node
) {
161 var attr
= node
["test:int"];
163 visitedNodes
.push(attr
);
165 if (node
["test:skipchildren"]) {
168 return node
.childNodes
;
171 t
.ok( objEqual(visitedNodes
, ["1", "2", "3", "4", "5"]), "nodeWalk looks like it works");
174 var minusOne = function (x
) { return x
- 1; };
175 var res
= map(minusOne
, [1, 2, 3]);
176 t
.ok( objEqual(res
, [0, 1, 2]), "map works" );
178 var res2
= xmap(minusOne
, 1, 2, 3);
179 t
.ok( objEqual(res2
, res
), "xmap works" );
181 res
= map(operator
.add
, [1, 2, 3], [2, 4, 6]);
182 t
.ok( objEqual(res
, [3, 6, 9]), "map(fn, p, q) works" );
184 res
= map(operator
.add
, [1, 2, 3], [2, 4, 6, 8]);
185 t
.ok( objEqual(res
, [3, 6, 9]), "map(fn, p, q) works (q long)" );
187 res
= map(operator
.add
, [1, 2, 3, 4], [2, 4, 6]);
188 t
.ok( objEqual(res
, [3, 6, 9]), "map(fn, p, q) works (p long)" );
190 res
= map(null, [1, 2, 3], [2, 4, 6]);
191 t
.ok( objEqual(res
, [[1, 2], [2, 4], [3, 6]]), "map(null, p, q) works" );
193 res
= zip([1, 2, 3], [2, 4, 6]);
194 t
.ok( objEqual(res
, [[1, 2], [2, 4], [3, 6]]), "zip(p, q) works" );
196 res
= map(null, [1, 2, 3]);
197 t
.ok( objEqual(res
, [1, 2, 3]), "map(null, lst) works" );
202 t
.is( isNotEmpty("foo"), true, "3 char string is not empty" );
203 t
.is( isNotEmpty(""), false, "0 char string is empty" );
204 t
.is( isNotEmpty([1, 2, 3]), true, "3 element list is not empty" );
205 t
.is( isNotEmpty([]), false, "0 element list is empty" );
208 var greaterThanThis = function (x
) { return x
> this; };
209 var greaterThanOne = function (x
) { return x
> 1; };
210 var res
= filter(greaterThanOne
, [-1, 0, 1, 2, 3]);
211 t
.ok( objEqual(res
, [2, 3]), "filter works" );
212 var res
= filter(greaterThanThis
, [-1, 0, 1, 2, 3], 1);
213 t
.ok( objEqual(res
, [2, 3]), "filter self works" );
214 var res2
= xfilter(greaterThanOne
, -1, 0, 1, 2, 3);
215 t
.ok( objEqual(res2
, res
), "xfilter works" );
217 t
.is(objMax(1, 2, 9, 12, 42, -16, 16), 42, "objMax works (with numbers)");
218 t
.is(objMin(1, 2, 9, 12, 42, -16, 16), -16, "objMin works (with numbers)");
220 // test adapter registry
222 var R
= new AdapterRegistry();
223 R
.register("callable", isCallable
, function () { return "callable"; });
224 R
.register("arrayLike", isArrayLike
, function () { return "arrayLike"; });
225 t
.is( R
.match(function () {}), "callable", "registry found callable" );
226 t
.is( R
.match([]), "arrayLike", "registry found ArrayLike" );
229 t
.ok( false, "non-matching didn't raise!" );
231 t
.is( e
, NotFound
, "non-matching raised correctly" );
233 R
.register("undefinedOrNull", isUndefinedOrNull
, function () { return "undefinedOrNull" });
234 R
.register("undefined", isUndefined
, function () { return "undefined" });
235 t
.is( R
.match(undefined), "undefinedOrNull", "priorities are as documented" );
236 t
.ok( R
.unregister("undefinedOrNull"), "removed adapter" );
237 t
.is( R
.match(undefined), "undefined", "adapter was removed" );
238 R
.register("undefinedOrNull", isUndefinedOrNull
, function () { return "undefinedOrNull" }, true);
239 t
.is( R
.match(undefined), "undefinedOrNull", "override works" );
241 var a1
= {"a": 1, "b": 2, "c": 2};
242 var a2
= {"a": 2, "b": 1, "c": 2};
243 t
.is( keyComparator("a")(a1
, a2
), -1, "keyComparator 1 lt" );
244 t
.is( keyComparator("c")(a1
, a2
), 0, "keyComparator 1 eq" );
245 t
.is( keyComparator("c", "b")(a1
, a2
), 1, "keyComparator 2 eq gt" );
246 t
.is( keyComparator("c", "a")(a1
, a2
), -1, "keyComparator 2 eq lt" );
247 t
.is( reverseKeyComparator("a")(a1
, a2
), 1, "reverseKeyComparator" );
248 t
.is( compare(concat([1], [2], [3]), [1, 2, 3]), 0, "concat" );
249 t
.is( repr("foo"), '"foo"', "string repr" );
250 t
.is( repr(1), '1', "number repr" );
251 t
.is( listMin([1, 3, 5, 3, -1]), -1, "listMin" );
252 t
.is( objMin(1, 3, 5, 3, -1), -1, "objMin" );
253 t
.is( listMax([1, 3, 5, 3, -1]), 5, "listMax" );
254 t
.is( objMax(1, 3, 5, 3, -1), 5, "objMax" );
258 t
.is( compare(v
, ["a", "b", "c"]), 0, "keys" );
261 t
.is( compare(v
, [["a", 1], ["b", 2], ["c", 2]]), 0, "items" );
263 var StringMap = function() {};
270 t
.ok( false, "bad comparison registered!?" );
272 t
.ok( e
instanceof TypeError
, "bad comparison raised TypeError" );
275 t
.is( repr(a
), "[object Object]", "default repr for StringMap" );
276 var isStringMap = function () {
277 for (var i
= 0; i
< arguments
.length
; i
++) {
278 if (!(arguments
[i
] instanceof StringMap
)) {
285 registerRepr("stringMap",
288 return "StringMap(" + repr(items(obj
)) + ")";
292 t
.is( repr(a
), 'StringMap([["foo", "bar"]])', "repr worked" );
295 MochiKit
.Base
.reprRegistry
.unregister("stringMap");
297 t
.is( repr(a
), "[object Object]", "default repr for StringMap" );
299 registerComparator("stringMap",
302 // no sorted(...) in base
307 return compare(a
, b
);
311 t
.is( compare(a
, b
), 0, "registerComparator" );
313 update(a
, {"foo": "bar"}, {"wibble": "baz"}, undefined, null, {"grr": 1});
314 t
.is( a
.foo
, "bar", "update worked (first obj)" );
315 t
.is( a
.wibble
, "baz", "update worked (second obj)" );
316 t
.is( a
.grr
, 1, "update worked (skipped undefined and null)" );
317 t
.is( compare(a
, b
), 1, "update worked (comparison)" );
320 setdefault(a
, {"foo": "unf"}, {"bar": "web taco"} );
321 t
.is( a
.foo
, "bar", "setdefault worked (skipped existing)" );
322 t
.is( a
.bar
, "web taco", "setdefault worked (set non-existing)" );
324 var c
= items(merge({"foo": "bar"}, {"wibble": "baz"}));
326 t
.is( compare(c
, [["foo", "bar"], ["wibble", "baz"]]), 0, "merge worked" );
329 MochiKit
.Base
.comparatorRegistry
.unregister("stringMap");
333 t
.ok( false, "bad comparison registered!?" );
335 t
.ok( e
instanceof TypeError
, "bad comparison raised TypeError" );
338 var o
= {"__repr__": function () { return "__repr__"; }};
339 t
.is( repr(o
), "__repr__", "__repr__ protocol" );
340 t
.is( repr(MochiKit
.Base
), MochiKit
.Base
.__repr__(), "__repr__ protocol when repr is defined" );
341 var o
= {"NAME": "NAME"};
342 t
.is( repr(o
), "NAME", "NAME protocol (obj)" );
343 o = function () { return "TACO" };
345 t
.is( repr(o
), "NAME", "NAME protocol (func)" );
347 t
.is( repr(MochiKit
.Base
.nameFunctions
), "MochiKit.Base.nameFunctions", "test nameFunctions" );
350 t
.is( urlEncode("1+2=2").toUpperCase(), "1%2B2%3D2", "urlEncode" );
351 t
.is( queryString(["a", "b"], [1, "two"]), "a=1&b=two", "queryString");
352 t
.is( queryString({"a": 1}), "a=1", "one item alternate form queryString" );
353 var o
= {"a": 1, "b": 2, "c": function() {}};
354 var res
= queryString(o
).split("&");
356 t
.is( res
.join("&"), "a=1&b=2", "two item alternate form queryString, function skip" );
357 var res
= parseQueryString("1+1=2&b=3%3D2");
358 t
.is( res
["1 1"], "2", "parseQueryString pathological name" );
359 t
.is( res
.b
, "3=2", "parseQueryString second name:value pair" );
360 var res
= parseQueryString("foo=one&foo=two", true);
361 t
.is( res
["foo"].join(" "), "one two", "parseQueryString useArrays" );
362 var res
= parseQueryString("?foo=2&bar=1");
363 t
.is( res
["foo"], "2", "parseQueryString strip leading question mark");
365 t
.is( serializeJSON("foo\n\r\b\f\t"), "\"foo\\n\\r\\b\\f\\t\"", "string JSON" );
366 t
.is( serializeJSON(null), "null", "null JSON");
368 serializeJSON(undefined);
369 t
.ok(false, "undefined should not be serializable");
371 t
.ok(e
instanceof TypeError
, "undefined not serializable");
373 t
.is( serializeJSON(1), "1", "1 JSON");
374 t
.is( serializeJSON(1.23), "1.23", "1.23 JSON");
375 t
.is( serializeJSON(serializeJSON
), null, "function JSON (null, not string)" );
376 t
.is( serializeJSON([1, "2", 3.3]), "[1, \"2\", 3.3]", "array JSON" );
377 var res
= evalJSON(serializeJSON({"a":1, "b":2}));
378 t
.is( res
.a
, 1, "evalJSON on an object (1)" );
379 t
.is( res
.b
, 2, "evalJSON on an object (2)" );
380 var res
= {"a": 1, "b": 2, "json": function () { return this; }};
381 var res
= evalJSON(serializeJSON(res
));
382 t
.is( res
.a
, 1, "evalJSON on an object that jsons self (1)" );
383 t
.is( res
.b
, 2, "evalJSON on an object that jsons self (2)" );
384 var strJSON
= {"a": 1, "b": 2, "json": function () { return "json"; }};
385 t
.is( serializeJSON(strJSON
), "\"json\"", "json serialization calling" );
386 t
.is( serializeJSON([strJSON
]), "[\"json\"]", "json serialization calling in a structure" );
387 registerJSON("isDateLike",
390 return "this was a date";
393 t
.is( serializeJSON(new Date()), "\"this was a date\"", "json registry" );
394 MochiKit
.Base
.jsonRegistry
.unregister("isDateLike");
396 var a
= {"foo": {"bar": 12, "wibble": 13}};
397 var b
= {"foo": {"baz": 4, "bar": 16}, "bar": 4};
399 var expect
= [["bar", 16], ["baz", 4], ["wibble", 13]];
400 var got
= items(a
.foo
);
402 t
.is( repr(got
), repr(expect
), "updatetree merge" );
403 t
.is( a
.bar
, 4, "updatetree insert" );
406 t
.is( c(), 1, "counter starts at 1" );
407 t
.is( c(), 2, "counter increases" );
409 t
.is( c(), 2, "counter starts at 2" );
410 t
.is( c(), 3, "counter increases" );
412 t
.is( findValue([1, 2, 3], 4), -1, "findValue returns -1 on not found");
413 t
.is( findValue([1, 2, 3], 1), 0, "findValue returns correct index");
414 t
.is( findValue([1, 2, 3], 1, 1), -1, "findValue honors start");
415 t
.is( findValue([1, 2, 3], 2, 0, 1), -1, "findValue honors end");
416 t
.is( findIdentical([1, 2, 3], 4), -1, "findIdentical returns -1");
417 t
.is( findIdentical([1, 2, 3], 1), 0, "findIdentical returns correct index");
418 t
.is( findIdentical([1, 2, 3], 1, 1), -1, "findIdentical honors start");
419 t
.is( findIdentical([1, 2, 3], 2, 0, 1), -1, "findIdentical honors end");
420 t
.is( isNull(undefined), false, "isNull doesn't match undefined" );
422 var flat
= flattenArguments(1, "2", 3, [4, [5, [6, 7], 8, [], 9]]);
423 var expect
= [1, "2", 3, 4, 5, 6, 7, 8, 9];
424 t
.is( repr(flat
), repr(expect
), "flattenArguments" );
426 var fn = function () {
427 return [this, concat(arguments
)];
429 t
.is( methodcaller("toLowerCase")("FOO"), "foo", "methodcaller with a method name" );
430 t
.is( repr(methodcaller(fn
, 2, 3)(1)), "[1, [2, 3]]", "methodcaller with a function" );
432 var f1 = function (x
) { return [1, x
]; };
433 var f2 = function (x
) { return [2, x
]; };
434 var f3 = function (x
) { return [3, x
]; };
435 t
.is( repr(f1(f2(f3(4)))), "[1, [2, [3, 4]]]", "test the compose test" );
436 t
.is( repr(compose(f1
,f2
,f3
)(4)), "[1, [2, [3, 4]]]", "three fn composition works" );
437 t
.is( repr(compose(compose(f1
,f2
),f3
)(4)), "[1, [2, [3, 4]]]", "associative left" );
438 t
.is( repr(compose(f1
,compose(f2
,f3
))(4)), "[1, [2, [3, 4]]]", "associative right" );
442 t
.ok( false, "wrong compose argument not raised!" );
444 t
.is( e
.name
, 'TypeError', "wrong compose argument raised correctly" );
447 t
.is(camelize('one'), 'one', 'one word');
448 t
.is(camelize('one-two'), 'oneTwo', 'two words');
449 t
.is(camelize('one-two-three'), 'oneTwoThree', 'three words');
450 t
.is(camelize('1-one'), '1One', 'letter and word');
451 t
.is(camelize('one-'), 'one', 'trailing hyphen');
452 t
.is(camelize('-one'), 'One', 'starting hyphen');
453 t
.is(camelize('o-two'), 'oTwo', 'one character and word');
455 var flat
= flattenArray([1, "2", 3, [4, [5, [6, 7], 8, [], 9]]]);
456 var expect
= [1, "2", 3, 4, 5, 6, 7, 8, 9];
457 t
.is( repr(flat
), repr(expect
), "flattenArray" );
462 t
.ok( false, "no arguments didn't raise!" );
464 t
.is( e
.name
, 'TypeError', "no arguments raised correctly" );
466 t
.is( mean(1), 1, 'single argument (arg list)');
467 t
.is( mean([1]), 1, 'single argument (array)');
468 t
.is( mean(1,2,3), 2, 'three arguments (arg list)');
469 t
.is( mean([1,2,3]), 2, 'three arguments (array)');
470 t
.is( average(1), 1, 'test the average alias');
475 t
.ok( false, "no arguments didn't raise!" );
477 t
.is( e
.name
, 'TypeError', "no arguments raised correctly" );
479 t
.is( median(1), 1, 'single argument (arg list)');
480 t
.is( median([1]), 1, 'single argument (array)');
481 t
.is( median(3,1,2), 2, 'three arguments (arg list)');
482 t
.is( median([3,1,2]), 2, 'three arguments (array)');
483 t
.is( median(3,1,2,4), 2.5, 'four arguments (arg list)');
484 t
.is( median([3,1,2,4]), 2.5, 'four arguments (array)');
487 t
.is( serializeJSON(parseQueryString("")), "{}", "parseQueryString('')" );
488 t
.is( serializeJSON(parseQueryString("", true)), "{}", "parseQueryString('', true)" );
491 t
.is( queryString({ids
: [1,2,3]}), "ids=1&ids=2&ids=3", "queryString array value" );
492 t
.is( queryString({ids
: "123"}), "ids=123", "queryString string value" );
495 var o
= {a
: 1, b
: 2, c
: 4, d
: -1};
498 t
.is( repr(got
), repr([-1, 1, 2, 4]), "values()" );