tck-lambdas 0.3.4 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +42 -12
- data/lib/tck/lambdas/chistacojs/source/chistacojs.js +9 -5
- data/lib/tck/lambdas/chistacojs/source/chistescortos.js +2 -3
- data/lib/tck/lambdas/chistacojs/source/chyton.js +24 -0
- data/lib/tck/lambdas/chistacojs/source/conf.js +7 -0
- data/lib/tck/lambdas/chistacojs/source/node_modules/xmldom/__package__.js +4 -0
- data/lib/tck/lambdas/chistacojs/source/node_modules/xmldom/component.json +10 -0
- data/lib/tck/lambdas/chistacojs/source/node_modules/xmldom/dom-parser.js +249 -0
- data/lib/tck/lambdas/chistacojs/source/node_modules/xmldom/dom.js +1147 -0
- data/lib/tck/lambdas/chistacojs/source/node_modules/xmldom/package.json +101 -0
- data/lib/tck/lambdas/chistacojs/source/node_modules/xmldom/readme.md +219 -0
- data/lib/tck/lambdas/chistacojs/source/node_modules/xmldom/sax.js +586 -0
- data/lib/tck/lambdas/chistacojs/source/node_modules/xpath/README.md +96 -0
- data/lib/tck/lambdas/chistacojs/source/node_modules/xpath/package.json +71 -0
- data/lib/tck/lambdas/chistacojs/source/node_modules/xpath/test.js +804 -0
- data/lib/tck/lambdas/chistacojs/source/node_modules/xpath/xpath.js +4693 -0
- data/lib/tck/lambdas/chistacojs/source/refreshing_matter.js +2 -3
- data/lib/tck/lambdas/chistacojs/test/succeeded/chyton_module.json +1 -0
- data/lib/tck/lambdas/version.rb +1 -1
- metadata +15 -3
- data/lib/tck/lambdas/chistacojs/chistaco_diario.zip +0 -0
@@ -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
|
+
}
|