tck-lambdas 0.3.4 → 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,804 @@
1
+ var xpath = require('./xpath.js')
2
+ , dom = require('xmldom').DOMParser
3
+ , assert = require('assert');
4
+
5
+ module.exports = {
6
+ 'api': function(test) {
7
+ assert.ok(xpath.evaluate, 'evaluate api ok.');
8
+ assert.ok(xpath.select, 'select api ok.');
9
+ assert.ok(xpath.parse, 'parse api ok.');
10
+ test.done();
11
+ },
12
+
13
+ 'evaluate': function(test) {
14
+ var xml = '<book><title>Harry Potter</title></book>';
15
+ var doc = new dom().parseFromString(xml);
16
+ var nodes = xpath.evaluate('//title', doc, null, xpath.XPathResult.ANY_TYPE, null).nodes;
17
+ assert.equal('title', nodes[0].localName);
18
+ assert.equal('Harry Potter', nodes[0].firstChild.data);
19
+ assert.equal('<title>Harry Potter</title>', nodes[0].toString());
20
+ test.done();
21
+ },
22
+
23
+ 'select': function(test) {
24
+ var xml = '<book><title>Harry Potter</title></book>';
25
+ var doc = new dom().parseFromString(xml);
26
+ var nodes = xpath.select('//title', doc);
27
+ assert.equal('title', nodes[0].localName);
28
+ assert.equal('Harry Potter', nodes[0].firstChild.data);
29
+ assert.equal('<title>Harry Potter</title>', nodes[0].toString());
30
+ test.done();
31
+ },
32
+
33
+ 'select single node': function(test) {
34
+ var xml = '<book><title>Harry Potter</title></book>';
35
+ var doc = new dom().parseFromString(xml);
36
+
37
+ assert.equal('title', xpath.select('//title[1]', doc)[0].localName);
38
+
39
+ test.done();
40
+ },
41
+
42
+ 'select text node': function (test) {
43
+ var xml = '<book><title>Harry</title><title>Potter</title></book>';
44
+ var doc = new dom().parseFromString(xml);
45
+
46
+ assert.deepEqual('book', xpath.select('local-name(/book)', doc));
47
+ assert.deepEqual('Harry,Potter', xpath.select('//title/text()', doc).toString());
48
+
49
+ test.done();
50
+ },
51
+
52
+ 'select number node': function(test) {
53
+ var xml = '<book><title>Harry</title><title>Potter</title></book>';
54
+ var doc = new dom().parseFromString(xml);
55
+
56
+ assert.deepEqual(2, xpath.select('count(//title)', doc));
57
+
58
+ test.done();
59
+ },
60
+
61
+ 'select xpath with namespaces': function (test) {
62
+ var xml = '<book><title xmlns="myns">Harry Potter</title></book>';
63
+ var doc = new dom().parseFromString(xml);
64
+
65
+ var nodes = xpath.select('//*[local-name(.)="title" and namespace-uri(.)="myns"]', doc);
66
+ assert.equal('title', nodes[0].localName);
67
+ assert.equal('myns', nodes[0].namespaceURI) ;
68
+
69
+ test.done();
70
+ },
71
+
72
+ 'select xpath with namespaces, using a resolver': function (test) {
73
+ var xml = '<book xmlns:testns="http://example.com/test"><testns:title>Harry Potter</testns:title><testns:field testns:type="author">JKR</testns:field></book>';
74
+ var doc = new dom().parseFromString(xml);
75
+
76
+ var resolver = {
77
+ mappings: {
78
+ 'testns': 'http://example.com/test'
79
+ },
80
+ lookupNamespaceURI: function(prefix) {
81
+ return this.mappings[prefix];
82
+ }
83
+ }
84
+
85
+ var nodes = xpath.selectWithResolver('//testns:title/text()', doc, resolver);
86
+ assert.equal('Harry Potter', xpath.selectWithResolver('//testns:title/text()', doc, resolver)[0].nodeValue);
87
+ assert.equal('JKR', xpath.selectWithResolver('//testns:field[@testns:type="author"]/text()', doc, resolver)[0].nodeValue);
88
+
89
+ test.done();
90
+ },
91
+
92
+ 'select xpath with default namespace, using a resolver': function (test) {
93
+ var xml = '<book xmlns="http://example.com/test"><title>Harry Potter</title><field type="author">JKR</field></book>';
94
+ var doc = new dom().parseFromString(xml);
95
+
96
+ var resolver = {
97
+ mappings: {
98
+ 'testns': 'http://example.com/test'
99
+ },
100
+ lookupNamespaceURI: function(prefix) {
101
+ return this.mappings[prefix];
102
+ }
103
+ }
104
+
105
+ var nodes = xpath.selectWithResolver('//testns:title/text()', doc, resolver);
106
+ assert.equal('Harry Potter', xpath.selectWithResolver('//testns:title/text()', doc, resolver)[0].nodeValue);
107
+ assert.equal('JKR', xpath.selectWithResolver('//testns:field[@type="author"]/text()', doc, resolver)[0].nodeValue);
108
+
109
+ test.done();
110
+ },
111
+
112
+ 'select xpath with namespaces, prefixes different in xml and xpath, using a resolver': function (test) {
113
+ var xml = '<book xmlns:testns="http://example.com/test"><testns:title>Harry Potter</testns:title><testns:field testns:type="author">JKR</testns:field></book>';
114
+ var doc = new dom().parseFromString(xml);
115
+
116
+ var resolver = {
117
+ mappings: {
118
+ 'ns': 'http://example.com/test'
119
+ },
120
+ lookupNamespaceURI: function(prefix) {
121
+ return this.mappings[prefix];
122
+ }
123
+ }
124
+
125
+ var nodes = xpath.selectWithResolver('//ns:title/text()', doc, resolver);
126
+ assert.equal('Harry Potter', xpath.selectWithResolver('//ns:title/text()', doc, resolver)[0].nodeValue);
127
+ assert.equal('JKR', xpath.selectWithResolver('//ns:field[@ns:type="author"]/text()', doc, resolver)[0].nodeValue);
128
+
129
+ test.done();
130
+ },
131
+
132
+ 'select xpath with namespaces, using namespace mappings': function (test) {
133
+ var xml = '<book xmlns:testns="http://example.com/test"><testns:title>Harry Potter</testns:title><testns:field testns:type="author">JKR</testns:field></book>';
134
+ var doc = new dom().parseFromString(xml);
135
+ var select = xpath.useNamespaces({'testns': 'http://example.com/test'});
136
+
137
+ assert.equal('Harry Potter', select('//testns:title/text()', doc)[0].nodeValue);
138
+ assert.equal('JKR', select('//testns:field[@testns:type="author"]/text()', doc)[0].nodeValue);
139
+
140
+ test.done();
141
+ },
142
+
143
+
144
+ 'select attribute': function (test) {
145
+ var xml = '<author name="J. K. Rowling"></author>';
146
+ var doc = new dom().parseFromString(xml);
147
+
148
+ var author = xpath.select1('/author/@name', doc).value;
149
+ assert.equal('J. K. Rowling', author);
150
+
151
+ test.done();
152
+ }
153
+
154
+ // https://github.com/goto100/xpath/issues/37
155
+ ,'select multiple attributes': function (test) {
156
+ var xml = '<authors><author name="J. K. Rowling" /><author name="Saeed Akl" /></authors>';
157
+ var doc = new dom().parseFromString(xml);
158
+
159
+ var authors = xpath.select('/authors/author/@name', doc);
160
+ assert.equal(2, authors.length);
161
+ assert.equal('J. K. Rowling', authors[0].value);
162
+
163
+ // https://github.com/goto100/xpath/issues/41
164
+ doc = new dom().parseFromString('<chapters><chapter v="1"/><chapter v="2"/><chapter v="3"/></chapters>');
165
+ var nodes = xpath.select("/chapters/chapter/@v", doc);
166
+ var values = nodes.map(function(n) { return n.value; });
167
+
168
+ assert.equal(3, values.length);
169
+ assert.equal("1", values[0]);
170
+ assert.equal("2", values[1]);
171
+ assert.equal("3", values[2]);
172
+
173
+ test.done();
174
+ }
175
+
176
+ ,'XPathException acts like Error': function (test) {
177
+ try {
178
+ xpath.evaluate('1', null, null, null);
179
+ assert.fail(null, null, 'evaluate() should throw exception');
180
+ } catch (e) {
181
+ assert.ok('code' in e, 'must have a code');
182
+ assert.ok('stack' in e, 'must have a stack');
183
+ }
184
+
185
+ test.done();
186
+ },
187
+
188
+ 'string() with no arguments': function (test) {
189
+ var doc = new dom().parseFromString('<book>Harry Potter</book>');
190
+
191
+ var rootElement = xpath.select1('/book', doc);
192
+ assert.ok(rootElement, 'rootElement is null');
193
+
194
+ assert.equal('Harry Potter', xpath.select1('string()', doc));
195
+
196
+ test.done();
197
+ },
198
+
199
+ 'string value of document fragment': function (test) {
200
+ var doc = new dom().parseFromString('<n />');
201
+ var docFragment = doc.createDocumentFragment();
202
+
203
+ var el = doc.createElement("book");
204
+ docFragment.appendChild(el);
205
+
206
+ var testValue = "Harry Potter";
207
+
208
+ el.appendChild(doc.createTextNode(testValue));
209
+
210
+ assert.equal(testValue, xpath.select1("string()", docFragment));
211
+
212
+ test.done();
213
+ },
214
+
215
+ 'compare string of a number with a number': function (test) {
216
+ assert.ok(xpath.select1('"000" = 0'), '000');
217
+ assert.ok(xpath.select1('"45.0" = 45'), '45');
218
+
219
+ test.done();
220
+ },
221
+
222
+ 'string(boolean) is a string': function (test) {
223
+ assert.equal('string', typeof xpath.select1('string(true())'));
224
+ assert.equal('string', typeof xpath.select1('string(false())'));
225
+ assert.equal('string', typeof xpath.select1('string(1 = 2)'));
226
+ assert.ok(xpath.select1('"true" = string(true())'), '"true" = string(true())');
227
+
228
+ test.done();
229
+ },
230
+
231
+ 'string should downcast to boolean': function (test) {
232
+ assert.equal(false, xpath.select1('"false" = false()'), '"false" = false()');
233
+ assert.equal(true, xpath.select1('"a" = true()'), '"a" = true()');
234
+ assert.equal(true, xpath.select1('"" = false()'), '"" = false()');
235
+
236
+ test.done();
237
+ },
238
+
239
+ 'string(number) is a string': function (test) {
240
+ assert.equal('string', typeof xpath.select1('string(45)'));
241
+ assert.ok(xpath.select1('"45" = string(45)'), '"45" = string(45)');
242
+
243
+ test.done();
244
+ },
245
+
246
+ 'correct string to number conversion': function (test) {
247
+ assert.equal(45.2, xpath.select1('number("45.200")'));
248
+ assert.equal(55.0, xpath.select1('number("000055")'));
249
+ assert.equal(65.0, xpath.select1('number(" 65 ")'));
250
+
251
+ assert.equal(true, xpath.select1('"" != 0'), '"" != 0');
252
+ assert.equal(false, xpath.select1('"" = 0'), '"" = 0');
253
+ assert.equal(false, xpath.select1('0 = ""'), '0 = ""');
254
+ assert.equal(false, xpath.select1('0 = " "'), '0 = " "');
255
+
256
+ assert.ok(Number.isNaN(xpath.select('number("")')), 'number("")');
257
+ assert.ok(Number.isNaN(xpath.select('number("45.8g")')), 'number("45.8g")');
258
+ assert.ok(Number.isNaN(xpath.select('number("2e9")')), 'number("2e9")');
259
+ assert.ok(Number.isNaN(xpath.select('number("+33")')), 'number("+33")');
260
+
261
+ test.done();
262
+ },
263
+
264
+ 'local-name() and name() of processing instruction': function (test) {
265
+ var xml = '<?book-record added="2015-01-16" author="J.K. Rowling" ?><book>Harry Potter</book>';
266
+ var doc = new dom().parseFromString(xml);
267
+ var expectedName = 'book-record';
268
+ var localName = xpath.select('local-name(/processing-instruction())', doc);
269
+ var name = xpath.select('name(/processing-instruction())', doc);
270
+
271
+ assert.deepEqual(expectedName, localName, 'local-name() - "' + expectedName + '" !== "' + localName + '"');
272
+ assert.deepEqual(expectedName, name, 'name() - "' + expectedName + '" !== "' + name + '"');
273
+
274
+ test.done();
275
+ },
276
+
277
+ 'evaluate substring-after': function (test) {
278
+ var xml = '<classmate>Hermione</classmate>';
279
+ var doc = new dom().parseFromString(xml);
280
+
281
+ var part = xpath.select('substring-after(/classmate, "Her")', doc);
282
+ assert.deepEqual('mione', part);
283
+
284
+ test.done();
285
+ }
286
+
287
+ ,'parsed expression with no options': function (test) {
288
+ var parsed = xpath.parse('5 + 7');
289
+
290
+ assert.equal(typeof parsed, "object", "parse() should return an object");
291
+ assert.equal(typeof parsed.evaluate, "function", "parsed.evaluate should be a function");
292
+ assert.equal(typeof parsed.evaluateNumber, "function", "parsed.evaluateNumber should be a function");
293
+
294
+ assert.equal(parsed.evaluateNumber(), 12);
295
+
296
+ // evaluating twice should yield the same result
297
+ assert.equal(parsed.evaluateNumber(), 12);
298
+
299
+ test.done();
300
+ }
301
+
302
+ ,'select1() on parsed expression': function (test) {
303
+ var xml = '<book><title>Harry Potter</title></book>';
304
+ var doc = new dom().parseFromString(xml);
305
+ var parsed = xpath.parse('/*/title');
306
+
307
+ assert.equal(typeof parsed, 'object', 'parse() should return an object');
308
+
309
+ assert.equal(typeof parsed.select1, 'function', 'parsed.select1 should be a function');
310
+
311
+ var single = parsed.select1({ node: doc });
312
+
313
+ assert.equal('title', single.localName);
314
+ assert.equal('Harry Potter', single.firstChild.data);
315
+ assert.equal('<title>Harry Potter</title>', single.toString());
316
+
317
+ test.done();
318
+ }
319
+
320
+ ,'select() on parsed expression': function (test) {
321
+ var xml = '<book><title>Harry Potter</title></book>';
322
+ var doc = new dom().parseFromString(xml);
323
+ var parsed = xpath.parse('/*/title');
324
+
325
+ assert.equal(typeof parsed, 'object', 'parse() should return an object');
326
+
327
+ assert.equal(typeof parsed.select, 'function', 'parsed.select should be a function');
328
+
329
+ var nodes = parsed.select({ node: doc });
330
+
331
+ assert.ok(nodes, 'parsed.select() should return a value');
332
+ assert.equal(1, nodes.length);
333
+ assert.equal('title', nodes[0].localName);
334
+ assert.equal('Harry Potter', nodes[0].firstChild.data);
335
+ assert.equal('<title>Harry Potter</title>', nodes[0].toString());
336
+
337
+ test.done();
338
+ }
339
+
340
+ ,'evaluateString(), and evaluateNumber() on parsed expression with node': function (test) {
341
+ var xml = '<book><title>Harry Potter</title><numVolumes>7</numVolumes></book>';
342
+ var doc = new dom().parseFromString(xml);
343
+ var parsed = xpath.parse('/*/numVolumes');
344
+
345
+ assert.equal(typeof parsed, 'object', 'parse() should return an object');
346
+
347
+ assert.equal(typeof parsed.evaluateString, 'function', 'parsed.evaluateString should be a function');
348
+ assert.equal('7', parsed.evaluateString({ node: doc }));
349
+
350
+ assert.equal(typeof parsed.evaluateBoolean, 'function', 'parsed.evaluateBoolean should be a function');
351
+ assert.equal(true, parsed.evaluateBoolean({ node: doc }));
352
+
353
+ assert.equal(typeof parsed.evaluateNumber, 'function', 'parsed.evaluateNumber should be a function');
354
+ assert.equal(7, parsed.evaluateNumber({ node: doc }));
355
+
356
+ test.done();
357
+ }
358
+
359
+ ,'evaluateBoolean() on parsed empty node set and boolean expressions': function (test) {
360
+ var xml = '<book><title>Harry Potter</title></book>';
361
+ var doc = new dom().parseFromString(xml);
362
+ var context = { node: doc };
363
+
364
+ function evaluate(path) {
365
+ return xpath.parse(path).evaluateBoolean({ node: doc });
366
+ }
367
+
368
+ assert.equal(false, evaluate('/*/myrtle'), 'boolean value of empty node set should be false');
369
+
370
+ assert.equal(true, evaluate('not(/*/myrtle)'), 'not() of empty nodeset should be true');
371
+
372
+ assert.equal(true, evaluate('/*/title'), 'boolean value of non-empty nodeset should be true');
373
+
374
+ assert.equal(true, evaluate('/*/title = "Harry Potter"'), 'title equals Harry Potter');
375
+
376
+ assert.equal(false, evaluate('/*/title != "Harry Potter"'), 'title != Harry Potter should be false');
377
+
378
+ assert.equal(false, evaluate('/*/title = "Percy Jackson"'), 'title should not equal Percy Jackson');
379
+
380
+ test.done();
381
+ }
382
+
383
+ ,'namespaces with parsed expression': function (test) {
384
+ var xml = '<characters xmlns:ps="http://philosophers-stone.com" xmlns:cs="http://chamber-secrets.com">' +
385
+ '<ps:character>Quirrell</ps:character><ps:character>Fluffy</ps:character>' +
386
+ '<cs:character>Myrtle</cs:character><cs:character>Tom Riddle</cs:character>' +
387
+ '</characters>';
388
+ var doc = new dom().parseFromString(xml);
389
+
390
+ var expr = xpath.parse('/characters/c:character');
391
+ var countExpr = xpath.parse('count(/characters/c:character)');
392
+ var csns = 'http://chamber-secrets.com';
393
+
394
+ function resolve(prefix) {
395
+ if (prefix === 'c') {
396
+ return csns;
397
+ }
398
+ }
399
+
400
+ function testContext(context, description) {
401
+ try {
402
+ var value = expr.evaluateString(context);
403
+ var count = countExpr.evaluateNumber(context);
404
+
405
+ assert.equal('Myrtle', value, description + ' - string value - ' + value);
406
+ assert.equal(2, count, description + ' map - count - ' + count);
407
+ } catch(e) {
408
+ e.message = description + ': ' + (e.message || '');
409
+ throw e;
410
+ }
411
+ }
412
+
413
+ testContext({
414
+ node: doc,
415
+ namespaces: {
416
+ c: csns
417
+ }
418
+ }, 'Namespace map');
419
+
420
+ testContext({
421
+ node: doc,
422
+ namespaces: resolve
423
+ }, 'Namespace function');
424
+
425
+ testContext({
426
+ node: doc,
427
+ namespaces: {
428
+ getNamespace: resolve
429
+ }
430
+ }, 'Namespace object');
431
+
432
+ test.done();
433
+ }
434
+
435
+ ,'custom functions': function (test) {
436
+ var xml = '<book><title>Harry Potter</title></book>';
437
+ var doc = new dom().parseFromString(xml);
438
+
439
+ var parsed = xpath.parse('concat(double(/*/title), " is cool")');
440
+
441
+ function doubleString(context, value) {
442
+ assert.equal(2, arguments.length);
443
+ var str = value.stringValue();
444
+ return str + str;
445
+ }
446
+
447
+ function functions(name, namespace) {
448
+ if(name === 'double') {
449
+ return doubleString;
450
+ }
451
+ return null;
452
+ }
453
+
454
+ function testContext(context, description) {
455
+ try{
456
+ var actual = parsed.evaluateString(context);
457
+ var expected = 'Harry PotterHarry Potter is cool';
458
+ assert.equal(expected, actual, description + ' - ' + expected + ' != ' + actual);
459
+ } catch (e) {
460
+ e.message = description + ": " + (e.message || '');
461
+ throw e;
462
+ }
463
+ }
464
+
465
+ testContext({
466
+ node: doc,
467
+ functions: functions
468
+ }, 'Functions function');
469
+
470
+ testContext({
471
+ node: doc,
472
+ functions: {
473
+ getFunction: functions
474
+ }
475
+ }, 'Functions object');
476
+
477
+ testContext({
478
+ node: doc,
479
+ functions: {
480
+ double: doubleString
481
+ }
482
+ }, 'Functions map');
483
+
484
+ test.done();
485
+ }
486
+
487
+ ,'custom function namespaces': function (test) {
488
+ var xml = '<book><title>Harry Potter</title><friend>Ron</friend><friend>Hermione</friend><friend>Neville</friend></book>';
489
+ var doc = new dom().parseFromString(xml);
490
+
491
+ var parsed = xpath.parse('concat(hp:double(/*/title), " is 2 cool ", hp:square(2), " school")');
492
+ var hpns = 'http://harry-potter.com';
493
+
494
+ var namespaces = {
495
+ hp: hpns
496
+ };
497
+
498
+ var context = {
499
+ node: doc,
500
+ namespaces: {
501
+ hp: hpns
502
+ },
503
+ functions: function (name, namespace) {
504
+ if (namespace === hpns) {
505
+ switch (name) {
506
+ case "double":
507
+ return function (context, value) {
508
+ assert.equal(2, arguments.length);
509
+ var str = value.stringValue();
510
+ return str + str;
511
+ };
512
+ case "square":
513
+ return function (context, value) {
514
+ var num = value.numberValue();
515
+ return num * num;
516
+ };
517
+
518
+ case "xor":
519
+ return function (context, l, r) {
520
+ assert.equal(3, arguments.length);
521
+ var lbool = l.booleanValue();
522
+ var rbool = r.booleanValue();
523
+ return (lbool || rbool) && !(lbool && rbool);
524
+ };
525
+
526
+ case "second":
527
+ return function (context, nodes) {
528
+ var nodesArr = nodes.toArray();
529
+ var second = nodesArr[1];
530
+ return second ? [second] : [];
531
+ };
532
+ }
533
+ }
534
+ return null;
535
+ }
536
+ };
537
+
538
+ assert.equal('Harry PotterHarry Potter is 2 cool 4 school', parsed.evaluateString(context));
539
+
540
+ assert.equal(false, xpath.parse('hp:xor(false(), false())').evaluateBoolean(context));
541
+ assert.equal(true, xpath.parse('hp:xor(false(), true())').evaluateBoolean(context));
542
+ assert.equal(true, xpath.parse('hp:xor(true(), false())').evaluateBoolean(context));
543
+ assert.equal(false, xpath.parse('hp:xor(true(), true())').evaluateBoolean(context));
544
+
545
+ assert.equal('Hermione', xpath.parse('hp:second(/*/friend)').evaluateString(context));
546
+ assert.equal(1, xpath.parse('count(hp:second(/*/friend))').evaluateNumber(context));
547
+ assert.equal(0, xpath.parse('count(hp:second(/*/friendz))').evaluateNumber(context));
548
+
549
+ test.done();
550
+ }
551
+
552
+ ,'xpath variables': function (test) {
553
+ var xml = '<book><title>Harry Potter</title><volumes>7</volumes></book>';
554
+ var doc = new dom().parseFromString(xml);
555
+
556
+ var variables = {
557
+ title: 'Harry Potter',
558
+ notTitle: 'Percy Jackson',
559
+ houses: 4
560
+ };
561
+
562
+ function variableFunction(name) {
563
+ return variables[name];
564
+ }
565
+
566
+ function testContext(context, description) {
567
+ try{
568
+ assert.equal(true, xpath.parse('$title = /*/title').evaluateBoolean(context));
569
+ assert.equal(false, xpath.parse('$notTitle = /*/title').evaluateBoolean(context));
570
+ assert.equal(11, xpath.parse('$houses + /*/volumes').evaluateNumber(context));
571
+ } catch (e) {
572
+ e.message = description + ": " + (e.message || '');
573
+ throw e;
574
+ }
575
+ }
576
+
577
+ testContext({
578
+ node: doc,
579
+ variables: variableFunction
580
+ }, 'Variables function');
581
+
582
+ testContext({
583
+ node: doc,
584
+ variables: {
585
+ getVariable: variableFunction
586
+ }
587
+ }, 'Variables object');
588
+
589
+ testContext({
590
+ node: doc,
591
+ variables: variables
592
+ }, 'Variables map');
593
+
594
+ test.done();
595
+ }
596
+
597
+ ,'xpath variable namespaces': function (test) {
598
+ var xml = '<book><title>Harry Potter</title><volumes>7</volumes></book>';
599
+ var doc = new dom().parseFromString(xml);
600
+ var hpns = 'http://harry-potter.com';
601
+
602
+ var context = {
603
+ node: doc,
604
+ namespaces: {
605
+ hp: hpns
606
+ },
607
+ variables: function(name, namespace) {
608
+ if (namespace === hpns) {
609
+ switch (name) {
610
+ case 'title': return 'Harry Potter';
611
+ case 'houses': return 4;
612
+ case 'false': return false;
613
+ case 'falseStr': return 'false';
614
+ }
615
+ } else if (namespace === '') {
616
+ switch (name) {
617
+ case 'title': return 'World';
618
+ }
619
+ }
620
+
621
+ return null;
622
+ }
623
+ };
624
+
625
+ assert.equal(true, xpath.parse('$hp:title = /*/title').evaluateBoolean(context));
626
+ assert.equal(false, xpath.parse('$title = /*/title').evaluateBoolean(context));
627
+ assert.equal('World', xpath.parse('$title').evaluateString(context));
628
+ assert.equal(false, xpath.parse('$hp:false').evaluateBoolean(context));
629
+ assert.notEqual(false, xpath.parse('$hp:falseStr').evaluateBoolean(context));
630
+ assert.throws(function () {
631
+ xpath.parse('$hp:hello').evaluateString(context);
632
+ }, function (err) {
633
+ return err.message === 'Undeclared variable: $hp:hello';
634
+ });
635
+
636
+ test.done();
637
+ }
638
+
639
+ ,"detect unterminated string literals": function (test) {
640
+ function testUnterminated(path) {
641
+ assert.throws(function () {
642
+ xpath.evaluate('"hello');
643
+ }, function (err) {
644
+ return err.message.indexOf('Unterminated') !== -1;
645
+ });
646
+ }
647
+
648
+ testUnterminated('"Hello');
649
+ testUnterminated("'Hello");
650
+ testUnterminated('self::text() = "\""');
651
+ testUnterminated('"\""');
652
+
653
+ test.done();
654
+ }
655
+
656
+ ,"string value for CDATA sections": function (test) {
657
+ var xml = "<people><person><![CDATA[Harry Potter]]></person><person>Ron <![CDATA[Weasley]]></person></people>",
658
+ doc = new dom().parseFromString(xml),
659
+ person1 = xpath.parse("/people/person").evaluateString({ node: doc }),
660
+ person2 = xpath.parse("/people/person/text()").evaluateString({ node: doc }),
661
+ person3 = xpath.select("string(/people/person/text())", doc);
662
+ person4 = xpath.parse("/people/person[2]").evaluateString({ node: doc });
663
+
664
+ assert.equal(person1, 'Harry Potter');
665
+ assert.equal(person2, 'Harry Potter');
666
+ assert.equal(person3, 'Harry Potter');
667
+ assert.equal(person4, 'Ron Weasley');
668
+
669
+ test.done();
670
+ }
671
+
672
+ ,"string value of various node types": function (test) {
673
+ var xml = "<book xmlns:hp='http://harry'><!-- This describes the Harry Potter Book --><?author name='J.K. Rowling' ?><title lang='en'><![CDATA[Harry Potter & the Philosopher's Stone]]></title><character>Harry Potter</character></book>",
674
+ doc = new dom().parseFromString(xml),
675
+ allText = xpath.parse('.').evaluateString({ node: doc }),
676
+ ns = xpath.parse('*/namespace::*[name() = "hp"]').evaluateString({ node: doc }),
677
+ title = xpath.parse('*/title').evaluateString({ node: doc }),
678
+ child = xpath.parse('*/*').evaluateString({ node: doc }),
679
+ titleLang = xpath.parse('*/*/@lang').evaluateString({ node: doc }),
680
+ pi = xpath.parse('*/processing-instruction()').evaluateString({ node: doc }),
681
+ comment = xpath.parse('*/comment()').evaluateString({ node: doc });
682
+
683
+ assert.equal(allText, "Harry Potter & the Philosopher's StoneHarry Potter");
684
+ assert.equal(ns, 'http://harry');
685
+ assert.equal(title, "Harry Potter & the Philosopher's Stone");
686
+ assert.equal(child, "Harry Potter & the Philosopher's Stone");
687
+ assert.equal(titleLang, 'en');
688
+ assert.equal(pi.trim(), "name='J.K. Rowling'");
689
+ assert.equal(comment, ' This describes the Harry Potter Book ');
690
+
691
+ test.done();
692
+ }
693
+
694
+ ,"exposes custom types": function (test) {
695
+ assert.ok(xpath.XPath, "xpath.XPath");
696
+ assert.ok(xpath.XPathParser, "xpath.XPathParser");
697
+ assert.ok(xpath.XPathResult, "xpath.XPathResult");
698
+
699
+ assert.ok(xpath.Step, "xpath.Step");
700
+ assert.ok(xpath.NodeTest, "xpath.NodeTest");
701
+ assert.ok(xpath.BarOperation, "xpath.BarOperation");
702
+
703
+ assert.ok(xpath.NamespaceResolver, "xpath.NamespaceResolver");
704
+ assert.ok(xpath.FunctionResolver, "xpath.FunctionResolver");
705
+ assert.ok(xpath.VariableResolver, "xpath.VariableResolver");
706
+
707
+ assert.ok(xpath.Utilities, "xpath.Utilities");
708
+
709
+ assert.ok(xpath.XPathContext, "xpath.XPathContext");
710
+ assert.ok(xpath.XNodeSet, "xpath.XNodeSet");
711
+ assert.ok(xpath.XBoolean, "xpath.XBoolean");
712
+ assert.ok(xpath.XString, "xpath.XString");
713
+ assert.ok(xpath.XNumber, "xpath.XNumber");
714
+
715
+ test.done();
716
+ }
717
+
718
+ ,"work with nodes created using DOM1 createElement()": function (test) {
719
+ var doc = new dom().parseFromString('<book />');
720
+
721
+ doc.documentElement.appendChild(doc.createElement('characters'));
722
+
723
+ assert.ok(xpath.select1('/book/characters', doc));
724
+
725
+ assert.equal(xpath.select1('local-name(/book/characters)', doc), 'characters');
726
+
727
+ test.done();
728
+ }
729
+
730
+ ,"preceding:: axis works on document fragments": function (test) {
731
+ var doc = new dom().parseFromString('<n />'),
732
+ df = doc.createDocumentFragment(),
733
+ root = doc.createElement('book');
734
+
735
+ df.appendChild(root);
736
+
737
+ for (var i = 0; i < 10; i += 1) {
738
+ root.appendChild(doc.createElement('chapter'));
739
+ }
740
+
741
+ var chapter = xpath.select1("book/chapter[5]", df);
742
+
743
+ assert.ok(chapter, 'chapter');
744
+
745
+ assert.equal(xpath.select("count(preceding::chapter)", chapter), 4);
746
+
747
+ test.done();
748
+ }
749
+
750
+ ,"node set sorted and unsorted arrays": function (test) {
751
+ var doc = new dom().parseFromString('<book><character>Harry</character><character>Ron</character><character>Hermione</character></book>'),
752
+ path = xpath.parse("/*/*[3] | /*/*[2] | /*/*[1]")
753
+ nset = path.evaluateNodeSet({ node: doc }),
754
+ sorted = nset.toArray(),
755
+ unsorted = nset.toUnsortedArray();
756
+
757
+ assert.equal(sorted.length, 3);
758
+ assert.equal(unsorted.length, 3);
759
+
760
+ assert.equal(sorted[0].textContent, 'Harry');
761
+ assert.equal(sorted[1].textContent, 'Ron');
762
+ assert.equal(sorted[2].textContent, 'Hermione');
763
+
764
+ assert.notEqual(sorted[0], unsorted[0], "first nodeset element equal");
765
+
766
+ test.done();
767
+ }
768
+
769
+ ,'meaningful error for invalid function': function(test) {
770
+ var path = xpath.parse('invalidFunc()');
771
+
772
+ assert.throws(function () {
773
+ path.evaluateString();
774
+ }, function (err) {
775
+ return err.message.indexOf('invalidFunc') !== -1;
776
+ });
777
+
778
+ var path2 = xpath.parse('funcs:invalidFunc()');
779
+
780
+ assert.throws(function () {
781
+ path2.evaluateString({
782
+ namespaces: {
783
+ funcs: 'myfunctions'
784
+ }
785
+ });
786
+ }, function (err) {
787
+ return err.message.indexOf('invalidFunc') !== -1;
788
+ });
789
+
790
+ test.done();
791
+ }
792
+
793
+ // https://github.com/goto100/xpath/issues/32
794
+ ,'supports contains() function on attributes': function (test) {
795
+ var doc = new dom().parseFromString("<books><book title='Harry Potter and the Philosopher\"s Stone' /><book title='Harry Potter and the Chamber of Secrets' /></books>"),
796
+ andTheBooks = xpath.select("/books/book[contains(@title, ' ')]", doc),
797
+ secretBooks = xpath.select("/books/book[contains(@title, 'Secrets')]", doc);
798
+
799
+ assert.equal(andTheBooks.length, 2);
800
+ assert.equal(secretBooks.length, 1);
801
+
802
+ test.done();
803
+ }
804
+ }