diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..6ca3727
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,6 @@
+sudo: false
+language: node_js
+node_js:
+ - "4"
+before_script:
+ - npm install -g grunt-cli
diff --git a/Gruntfile.js b/Gruntfile.js
index 10ac137..e59a14e 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -37,6 +37,21 @@ module.exports = function(grunt) {
src: 'dist/xpathjs.js',
dest: 'dist/xpathjs.min.js'
}
+ },
+
+ karma: {
+ options: {
+ singleRun: true,
+ reporters: ['dots']
+ },
+ headless: {
+ configFile: 'test/karma.conf.js',
+ browsers: ['PhantomJS']
+ },
+ browsers: {
+ configFile: 'test/karma.conf.js',
+ browsers: ['Chrome', 'Firefox', 'Safari', 'Opera']
+ }
}
});
@@ -45,6 +60,7 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-peg');
+ grunt.loadNpmTasks('grunt-karma');
grunt.registerTask('dist', [
'clean:dist',
diff --git a/README.md b/README.md
index 9f8133b..c9e7cd4 100644
--- a/README.md
+++ b/README.md
@@ -99,3 +99,8 @@ cd xpathjs
npm install
grunt dist
```
+
+Test
+----------
+
+Run tests headlessly with `grunt karma:headless` and in browsers with `grunt karma:browsers`.
diff --git a/package.json b/package.json
index 3e48a02..ebfae1e 100644
--- a/package.json
+++ b/package.json
@@ -6,13 +6,29 @@
"license": "AGPL-3.0",
+ "scripts": {
+ "test": "grunt karma:headless"
+ },
+
"repository": {
"type": "git",
"url": "https://github.com/andrejpavlovic/xpathjs.git"
},
"devDependencies": {
+ "chai": "^2.1.1",
"grunt": "~0.4.5",
+ "grunt-karma": "^0.10.1",
+ "grunt-mocha-test": "^0.12.7",
+ "karma": "^0.12.31",
+ "karma-chai": "^0.1.0",
+ "karma-chrome-launcher": "^0.1.7",
+ "karma-firefox-launcher": "^0.1.4",
+ "karma-mocha": "^0.1.10",
+ "karma-opera-launcher": "^0.1.0",
+ "karma-phantomjs-launcher": "^0.1.4",
+ "karma-safari-launcher": "^0.1.1",
+ "mocha": "^2.1.0",
"grunt-contrib-clean": "1.0.0",
"grunt-contrib-concat": "1.0.0",
"grunt-contrib-uglify": "0.11.1",
diff --git a/tests/tests.php b/test/doc.xml
similarity index 86%
rename from tests/tests.php
rename to test/doc.xml
index aa656b6..8d7f5f4 100644
--- a/tests/tests.php
+++ b/test/doc.xml
@@ -1,35 +1,10 @@
-.
- */
-
-$serve_xml = !empty($_GET['xml']);
-
-if ($serve_xml)
- header('Content-Type: application/xhtml+xml');
-?>
-
-
+
@@ -128,7 +128,7 @@
-
+
@@ -206,13 +206,13 @@
asdf
asdfsdf sdf
- ' ?>
+
sdfsdf
some text]]>
- ' ?>
+
@@ -244,7 +244,7 @@
some text
-
' ?>
+
diff --git a/test/helpers.js b/test/helpers.js
new file mode 100644
index 0000000..fc30137
--- /dev/null
+++ b/test/helpers.js
@@ -0,0 +1,397 @@
+/* global doc, win, expect, docEvaluate, XMLHttpRequest */
+"use strict";
+
+var helpers = {
+ getNextChildElementNode: function(parentNode) {
+ var childNode = parentNode.firstChild;
+ while (childNode.nodeName == '#text') {
+ childNode = childNode.nextSibling;
+ }
+ return childNode;
+ },
+
+ setAttribute: function(node, namespace, name, value) {
+ if (node.setAttributeNS) {
+ // for XML documents
+ node.setAttributeNS(namespace, name, value);
+ } else {
+ // normal HTML documents
+ node.setAttribute(name, value);
+ }
+ },
+
+ xhtmlResolver: {
+ lookupNamespaceURI: function(prefix) {
+ var namespaces = {
+ 'xhtml': 'http://www.w3.org/1999/xhtml',
+ 'ns2': 'http://asdf/'
+ };
+
+ if (namespaces[prefix]) {
+ return namespaces[prefix];
+ }
+
+ var resolver = documentCreateNSResolver(doc.documentElement);
+ return resolver.lookupNamespaceURI(prefix);
+ }
+ },
+
+ getComparableNode: function(node) {
+ switch (node.nodeType) {
+ case 2: // attribute
+ case 13: // namespace
+ // TODO: IE support
+ //return node.ownerElement;
+ throw new Error('Internal Error: getComparableNode - Node type not implemented: ' + node.nodeType);
+ break;
+
+ case 3: // text
+ case 4: // CDATASection
+ case 7: // processing instruction
+ case 8: // comment
+ return node.parentNode;
+ break;
+
+ case 1: // element
+ case 9: // document
+ // leave as is
+ return node;
+ break;
+
+ default:
+ throw new Error('Internal Error: getComparableNode - Node type not supported: ' + node.nodeType);
+ break;
+ }
+ },
+
+ /**
+ * @see http://ejohn.org/blog/comparing-document-position/
+ */
+ comparePosition: function(a, b) {
+ var a2,
+ b2,
+ result,
+ ancestor,
+ i,
+ item;
+
+ // check for native implementation
+ if (a.compareDocumentPosition) {
+ return a.compareDocumentPosition(b);
+ }
+
+ if (a === b) {
+ return 0;
+ }
+
+ a2 = helpers.getComparableNode(a);
+ b2 = helpers.getComparableNode(b);
+
+ // handle document case
+ if (a2.nodeType === 9) {
+ if (b2.nodeType === 9) {
+ if (a2 !== b2) {
+ return 1; // different documents
+ } else {
+ result = 0; // same nodes
+ }
+ } else {
+ if (a2 !== b2.ownerDocument) {
+ return 1; // different documents
+ } else {
+ result = 4 + 16; // a2 before b2, a2 contains b2
+ }
+ }
+ } else {
+ if (b2.nodeType === 9) {
+ if (b2 !== a2.ownerDocument) {
+ return 1; // different documents
+ } else {
+ result = 2 + 8; // b2 before a2, b2 contains a2
+ }
+ } else {
+ if (a2.ownerDocument !== b2.ownerDocument) {
+ return 1; // different documents
+ } else {
+ // do a contains comparison for element nodes
+ if (!a2.contains || typeof a2.sourceIndex === 'undefined' || !b2.contains || typeof b2.sourceIndex === 'undefined') {
+ throw new Error('Cannot compare elements. Neither "compareDocumentPosition" nor "contains" available.');
+ } else {
+ result =
+ (a2 != b2 && a2.contains(b2) && 16) +
+ (a2 != b2 && b2.contains(a2) && 8) +
+ (a2.sourceIndex >= 0 && b2.sourceIndex >= 0 ? (a2.sourceIndex < b2.sourceIndex && 4) + (a2.sourceIndex > b2.sourceIndex && 2) : 1) +
+ 0;
+ }
+ }
+ }
+ }
+
+ if (a === a2) {
+ if (b === b2) {
+ return result;
+ } else {
+ // if a contains b2 or a == b2
+ if (result === 0 || (result & 16) === 16) {
+ // return result
+ return result;
+ }
+ // else if b2 contains a
+ else if ((result & 8) === 8) {
+ // find (ancestor-or-self::a) that is direct child of b2
+ ancestor = a;
+ while (ancestor.parentNode !== b2) {
+ ancestor = ancestor.parentNode;
+ }
+
+ // return "a pre b" or "b pre a" depending on which is occurs first in b2.childNodes
+ for (i = 0; i < b2.childNodes.length; i++) {
+ item = b2.childNodes.item(i);
+ if (item === ancestor) {
+ return 4;
+ } else if (item === b) {
+ return 2;
+ }
+ }
+
+ throw new Error('Internal Error: should not get to here. 1');
+ } else {
+ // return result
+ return result;
+ }
+ }
+ } else {
+ if (b === b2) {
+ // if b contains a2 or b == a2
+ if (result === 0 || (result & 8) === 8) {
+ // return result
+ return result;
+ }
+ // else if a2 contains b
+ else if ((result & 16) === 16) {
+ // find (ancestor-or-self::b) that is direct child of a2
+ ancestor = b;
+ while (ancestor.parentNode !== a2) {
+ ancestor = ancestor.parentNode;
+ }
+
+ // return "a pre b" or "b pre a" depending on which is occurs first in a2.childNodes
+ for (i = 0; i < a2.childNodes.length; i++) {
+ item = a2.childNodes.item(i);
+ if (item === ancestor) {
+ return 2;
+ } else if (item === a) {
+ return 4;
+ }
+ }
+
+ throw new Error('Internal Error: should not get to here. 2');
+ } else {
+ // return result
+ return result;
+ }
+ } else {
+ // if a2 contains b2
+ if ((result & 16) === 16) {
+ // return "a pre b" or "b pre a" depending on a or (ancestor-or-self::b2) occurs first in a2.childNodes
+ ancestor = b2;
+ while (ancestor.parentNode !== a2) {
+ ancestor = ancestor.parentNode;
+ }
+
+ for (i = 0; i < a2.childNodes.length; i++) {
+ item = a2.childNodes.item(i);
+ if (item === ancestor) {
+ return 2;
+ } else if (item === a) {
+ return 4;
+ }
+ }
+
+ throw new Error('Internal Error: should not get to here. 3');
+ }
+ // else if b2 contains a2
+ if ((result & 8) === 8) {
+ // return "a pre b" or "b pre a" depending on b or (ancestor-or-self::a2) occurs first in b2.childNodes
+ ancestor = a2;
+ while (ancestor.parentNode !== b2) {
+ ancestor = ancestor.parentNode;
+ }
+
+ for (i = 0; i < b2.childNodes.length; i++) {
+ item = b2.childNodes.item(i);
+ if (item === ancestor) {
+ return 4;
+ } else if (item === b) {
+ return 2;
+ }
+ }
+
+ throw new Error('Internal Error: should not get to here. 3');
+ }
+ // else if a2 === b2
+ else if (result === 0) {
+ // return "a pre b" or "b pre a" depending on a or b occurs first in a2.childNodes
+ for (i = 0; i < a2.childNodes.length; i++) {
+ item = a2.childNodes.item(i);
+ if (item === b) {
+ return 2;
+ } else if (item === a) {
+ return 4;
+ }
+ } //
+
+ throw new Error('Internal Error: should not get to here. 4');
+ }
+ // else
+ else {
+ // return result
+ return result;
+ }
+ }
+ }
+
+ throw new Error('Internal Error: should not get to here. 5');
+ },
+
+ getAllNodes: function(node) {
+ var nodes = [],
+ i;
+
+ node = (node || doc);
+
+ nodes.push(node);
+
+ for (i = 0; i < node.childNodes.length; i++) {
+ nodes.push.apply(nodes, helpers.getAllNodes(node.childNodes.item(i)));
+ }
+
+ return nodes;
+ }
+ },
+ documentEvaluate = function(expression, contextNode, resolver, type, result) {
+ return docEvaluate.call(doc, expression, contextNode, resolver, type, result);
+ },
+
+ documentCreateExpression = function(expression, resolver) {
+ return doc.createExpression.call(doc, expression, resolver);
+ },
+
+ documentCreateNSResolver = function(node) {
+ return doc.createNSResolver.call(doc, node);
+ },
+
+ filterAttributes = function(attributes) {
+ var i, name,
+ specifiedAttributes = [];
+
+ for (i = 0; i < attributes.length; i++) {
+ if (!attributes[i].specified) {
+ // ignore non-specified attributes
+ continue;
+ }
+
+ name = attributes[i].nodeName.split(':');
+
+ if (name[0] === 'xmlns') {
+ // ignore namespaces
+ continue;
+ }
+
+ specifiedAttributes.push(attributes[i]);
+ }
+
+ return specifiedAttributes;
+ },
+
+ filterSpecifiedAttributes = function(attributes) {
+ var specifiedAttributes = [],
+ i,
+ name;
+
+ for (i = 0; i < attributes.length; i++) {
+ if (!attributes[i].specified) {
+ // ignore non-specified attributes
+ continue;
+ }
+
+ specifiedAttributes.push(attributes[i]);
+ }
+
+ return specifiedAttributes;
+ },
+
+ checkNodeResultNamespace = function(expression, contextNode, expectedResult, resolver) {
+ var j, result, item, res;
+
+ res = (!resolver) ? null : resolver;
+
+ result = documentEvaluate(expression, contextNode, res, win.XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+
+ expect(result.snapshotLength).to.equal(expectedResult.length);
+
+ for (j = 0; j < result.snapshotLength; j++) {
+ item = result.snapshotItem(j);
+ expect(item.nodeName).to.equal('#namespace');
+ expect(item.localName).to.equal(expectedResult[j][0]);
+ expect(item.namespaceURI).to.equal(expectedResult[j][1]);
+ }
+ },
+
+ checkNodeResult = function(expression, contextNode, expectedResult, resolver) {
+ var result, j, item, res;
+
+ res = (!resolver) ? null : resolver;
+
+ result = documentEvaluate(expression, contextNode, res, win.XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+
+ expect(result.snapshotLength).to.equal(expectedResult.length);
+
+ for (j = 0; j < result.snapshotLength; j++) {
+ item = result.snapshotItem(j);
+ expect(item).to.deep.equal(expectedResult[j]);
+ }
+ },
+
+ parseNamespacesFromAttributes = function(attributes, namespaces) {
+ var i,
+ name;
+
+ for (i = attributes.length - 1; i >= 0; i--) {
+ name = attributes.item(i).nodeName.split(':');
+
+ if (name[0] === 'xmlns') {
+ if (name.length == 1) {
+ namespaces.unshift(['', attributes.item(i).nodeValue]);
+ } else {
+ namespaces.push([name[1], attributes.item(i).nodeValue]);
+ }
+ }
+ }
+ },
+
+ snapshotToArray = function(result) {
+ var i,
+ nodes = [];
+
+ for (i = 0; i < result.snapshotLength; i++) {
+ nodes.push(result.snapshotItem(i));
+ }
+
+ return nodes;
+ };
+/*
+loadXMLFile = function(url, callback) {
+ var xhr = new XMLHttpRequest();
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == 4 && this.status == 200) {
+ callback(this.response);
+ }
+ };
+
+ xhr.open('GET', url);
+ xhr.responseType = 'text';
+ xhr.send();
+};
+*/
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..2efc7b4
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,74 @@
+// Karma configuration
+// Generated on Wed Mar 04 2015 15:02:33 GMT-0700 (MST)
+
+'use strict';
+
+module.exports = function(config) {
+ config.set({
+
+ // base path that will be used to resolve all patterns (eg. files, exclude)
+ basePath: '..',
+
+
+ // frameworks to use
+ // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+ frameworks: ['mocha', 'chai'],
+
+
+ // list of files / patterns to load in the browser
+ files: [{
+ pattern: 'dist/**/*.js',
+ included: false
+ }, {
+ pattern: 'test/**/*.xml',
+ watched: true,
+ served: true,
+ included: false
+ },
+ 'test/helpers.js',
+ 'test/**/*.spec.js',
+ ],
+
+
+ // list of files to exclude
+ exclude: [],
+
+
+ // preprocess matching files before serving them to the browser
+ // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+ preprocessors: {},
+
+
+ // test results reporter to use
+ // possible values: 'dots', 'progress'
+ // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+ reporters: ['progress'],
+
+
+ // web server port
+ port: 9877,
+
+
+ // enable / disable colors in the output (reporters and logs)
+ colors: true,
+
+
+ // level of logging
+ // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+ logLevel: config.LOG_DEBUG,
+
+
+ // enable / disable watching file and executing tests whenever any file changes
+ autoWatch: false,
+
+
+ // start these browsers
+ // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+ //browsers: ['Chrome', 'PhantomJS'],
+
+
+ // Continuous Integration mode
+ // if true, Karma captures browsers, runs the tests and exits
+ singleRun: false
+ });
+};
diff --git a/test/spec/and-or-operators-native.spec.js b/test/spec/and-or-operators-native.spec.js
new file mode 100644
index 0000000..151c91c
--- /dev/null
+++ b/test/spec/and-or-operators-native.spec.js
@@ -0,0 +1,157 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, documentEvaluate, documentCreateNSResolver, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+describe('and/or operators', function() {
+
+ /**
+ * These absent-spacing tests seem weird to me. Am surprised that this works and that this is required to work.
+ */
+ it('and works without spacing', function() {
+ var result = documentEvaluate("1and1", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+ });
+
+ it('and works without spacing AFTER and', function() {
+ var result = documentEvaluate("1 and1", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+ });
+
+ it('and works with linebreak/tab spacing', function() {
+ var result = documentEvaluate("1 and\r\n\t1", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+ });
+
+ it('and works without spacing BEFORE and', function() {
+ var result = documentEvaluate("1and 1", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+ });
+
+ it('and works with numbers-as-string', function() {
+ var result = documentEvaluate("'1'and'1'", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+ });
+
+ it('And (capitalized) fails miserably', function() {
+ var test = function() {
+ documentEvaluate("1 And 1", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ };
+ // does not throw instance of Error
+ expect(test).to.throw();
+ });
+
+ it('and without potential spacing issues works', function() {
+ [
+ ["true() and true()", true],
+ ["false() and true()", false],
+ ["true() and false()", false],
+ ["false() and false()", false],
+ ["1 and 1", true],
+ ["0 and 1", false],
+ ["-1 and 0", false],
+ ["0 and 0", false],
+ ["1 and -1", true],
+ ["1 and (1 div 0)", true],
+ ["(-1 div 0) and 1", true],
+ ["number('') and 1", false],
+ ["number('') and 0", false],
+ ["1 and 1 and 0", false],
+ ["1 and 1 and true()", true],
+ ["false() and 1 and true()", false]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(t[1]);
+ });
+ });
+
+ it('and laziness', function() {
+ [
+ ["false() and $some-made-up-var", false],
+ ["false() and $some-made-up-var and true()", false],
+ ["true() and false() and $some-made-up-var", false]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(t[1]);
+ });
+ });
+
+ it('or works without spacing', function() {
+ var result = documentEvaluate("1or1", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+ });
+
+ it('or works without spacing AFTER or', function() {
+ var result = documentEvaluate("1 or1", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+ });
+
+ it('or works with newline/tab spacing', function() {
+ var result = documentEvaluate("1 or\r\n\t1", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+ });
+
+ it('or works without spacing BEFORE or', function() {
+ var result = documentEvaluate("1or 1", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+ });
+
+ it('or works with numbers-as-string', function() {
+ var result = documentEvaluate("'1'or'1'", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+ });
+
+ it('And (capitalized) fails miserably', function() {
+ var test = function() {
+ documentEvaluate("1 OR 1", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ };
+ // does not throw instance of Error
+ expect(test).to.throw();
+ });
+
+ it('or without potential spacing issues works', function() {
+ [
+ ["true() or true()", true],
+ ["false() or true()", true],
+ ["true() or false()", true],
+ ["false() or false()", false],
+ ["1 or 1", true],
+ ["0 or 1", true],
+ ["0 or -1", true],
+ ["0 or 0", false],
+ ["1 or -1", true],
+ ["1 or (1 div 0)", true],
+ ["(-1 div 0) or 1", true],
+ ["number('') or 1", true],
+ ["number('') or 0", false],
+ ["1 or 1 or 0", true],
+ ["1 or 1 or true()", true],
+ ["false() or 0 or 0", false]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(t[1]);
+ });
+ });
+
+ it('or laziness', function() {
+ [
+ ["true() or $some-made-up-var", true],
+ ["true() or $some-made-up-var and true()", true],
+ ["false() or true() or $some-made-up-var", true]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(t[1]);
+ });
+ });
+
+ it('or/and precendence rules are applied correctly', function() {
+ [
+ ["true() or true() and false()", true],
+ ["true() and false() or true()", true],
+ ["false() and false() or false()", false],
+ ["0 or 1 and 0", false],
+ ["0 or 1 and 0+1", true]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(t[1]);
+ });
+ });
+});
diff --git a/test/spec/axis-native.spec.js b/test/spec/axis-native.spec.js
new file mode 100644
index 0000000..0444b67
--- /dev/null
+++ b/test/spec/axis-native.spec.js
@@ -0,0 +1,969 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, documentEvaluate, documentCreateNSResolver, checkNodeResult, checkNodeResultNamespace, parseNamespacesFromAttributes, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+describe('axes', function() {
+
+ var h;
+
+ before(function() {
+
+ h = {
+ getNodeAttribute: function() {
+ var attribute,
+ node = doc.getElementById('testStepAxisNodeAttribute'),
+ i;
+
+ for (i = 0; i < node.attributes.length; i++) {
+ if (node.attributes[i].specified) {
+ attribute = node.attributes[i];
+ break;
+ }
+ }
+
+ expect(attribute).is.an('object');
+
+ return attribute;
+ },
+
+ getNodeComment: function() {
+ return doc.getElementById('testStepAxisNodeComment').firstChild;
+ },
+
+ getNodeCData: function() {
+ return doc.getElementById('testStepAxisNodeCData').firstChild;
+ },
+
+ getNodeProcessingInstruction: function() {
+ return doc.getElementById('testStepAxisNodeProcessingInstruction').firstChild;
+ },
+
+ getNodeNamespace: function() {
+ var result;
+
+ result = documentEvaluate("namespace::node()", doc.getElementById('testStepAxisNodeNamespace'), null, win.XPathResult.ANY_UNORDERED_NODE_TYPE, null);
+ return result.singleNodeValue;
+ },
+
+ followingSiblingNodes: function(node) {
+ var nodes = [],
+ i;
+
+ while (node = node.nextSibling) {
+ nodes.push(node);
+ }
+
+ return nodes;
+ },
+
+ precedingSiblingNodes: function(node) {
+ var nodes = [],
+ i;
+
+ while (node = node.previousSibling) {
+ if (node.nodeType == 10)
+ continue;
+ nodes.push(node);
+ }
+
+ nodes.reverse();
+
+ return nodes;
+ },
+
+ followingNodes: function(node) {
+ var nodes = [],
+ i,
+ nodesAll,
+ result,
+ node2;
+
+ nodesAll = helpers.getAllNodes();
+
+ for (i = 0; i < nodesAll.length; i++) {
+ node2 = nodesAll[i]; //
+ if (node2.nodeType == 10) // document type node
+ continue; //
+ result = helpers.comparePosition(node, node2);
+ if (4 === result) {
+ nodes.push(node2);
+ }
+ }
+
+ return nodes;
+ },
+
+ precedingNodes: function(node) {
+ var nodes = [],
+ i,
+ nodesAll,
+ result,
+ node2;
+
+ nodesAll = helpers.getAllNodes();
+
+ for (i = 0; i < nodesAll.length; i++) {
+ node2 = nodesAll[i];
+
+ if (node2.nodeType == 10) // document type node
+ continue;
+
+ result = helpers.comparePosition(node, node2);
+ if (2 == result) {
+ nodes.push(node2);
+ }
+ }
+
+ return nodes;
+ }
+
+ };
+ });
+
+ describe('self axis', function() {
+
+ it('works with document context', function() {
+ checkNodeResult("self::node()", doc, [doc]);
+ });
+
+ it('works with documentElement context', function() {
+ checkNodeResult("self::node()", doc.documentElement, [doc.documentElement]);
+ });
+
+ it('works with element context', function() {
+ checkNodeResult("self::node()", doc.getElementById('testStepAxisChild'), [doc.getElementById('testStepAxisChild')]);
+ });
+
+ it('works with element attribute context', function() {
+ checkNodeResult("self::node()", h.getNodeAttribute(), [h.getNodeAttribute()]);
+ });
+
+ it('works with CData context', function() {
+ checkNodeResult("self::node()", h.getNodeCData(), [h.getNodeCData()]);
+ });
+
+ it('works with comment context', function() {
+ checkNodeResult("self::node()", h.getNodeComment(), [h.getNodeComment()]);
+ });
+
+ it('works with node processing instruction context', function() {
+ checkNodeResult("self::node()", h.getNodeProcessingInstruction(), [h.getNodeProcessingInstruction()]);
+ });
+
+ xit('works with node namespace context', function() {
+ checkNodeResult("self::node()", h.getNodeNamespace(), [h.getNodeNamespace()]);
+ });
+
+ it('works with document fragment context', function() {
+ var fragment = doc.createDocumentFragment();
+ var test = function() {
+ checkNodeResult("self::node()", fragment, [fragment]);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ });
+
+ describe('child axis', function() {
+
+ it('works with document context', function() {
+ var i, expectedResult = [];
+
+ for (i = 0; i < doc.childNodes.length; i++) {
+ if (doc.childNodes.item(i).nodeType == 1 ||
+ doc.childNodes.item(i).nodeType == 8) {
+ expectedResult.push(doc.childNodes.item(i));
+ }
+ }
+
+ checkNodeResult("child::node()", doc, expectedResult);
+ });
+
+ it('works with documentElement context', function() {
+ checkNodeResult("child::node()", doc.documentElement, doc.documentElement.childNodes);
+ });
+
+ it('works with element context', function() {
+ checkNodeResult("child::node()", doc.getElementById('testStepAxisChild'),
+ doc.getElementById('testStepAxisChild').childNodes);
+ });
+
+ it('works with attribute context', function() {
+ checkNodeResult("child::node()", h.getNodeAttribute(), []);
+ });
+
+ it('works with CData context', function() {
+ checkNodeResult("child::node()", h.getNodeCData(), []);
+ });
+
+ it('works with a comment context', function() {
+ checkNodeResult("child::node()", h.getNodeComment(), []);
+ });
+
+ it('works with a processing instruction context', function() {
+ checkNodeResult("child::node()", h.getNodeProcessingInstruction(), []);
+ });
+
+ xit('works with a namespace context', function() {
+ checkNodeResult("child::node()", this.getNodeNamespace(), []);
+ });
+
+ });
+
+ describe('descendendant axis', function() {
+
+ it('works with Element context', function() {
+ var descendantNodes = function(node) {
+ var nodes = [],
+ i;
+
+ for (i = 0; i < node.childNodes.length; i++) {
+ nodes.push(node.childNodes.item(i));
+ nodes.push.apply(nodes, descendantNodes(node.childNodes.item(i)));
+ }
+
+ return nodes;
+ };
+
+ checkNodeResult("descendant::node()", doc.getElementById('testStepAxisDescendant'),
+ descendantNodes(doc.getElementById('testStepAxisDescendant')));
+ });
+
+ it('works with attribute context', function() {
+ checkNodeResult("descendant::node()", h.getNodeAttribute(), []);
+ });
+
+ it('works with CData context', function() {
+ checkNodeResult("descendant::node()", h.getNodeCData(), []);
+ });
+
+ it('works with a comment context', function() {
+ checkNodeResult("descendant::node()", h.getNodeComment(), []);
+ });
+
+ it('works with a processing instruction context', function() {
+ checkNodeResult("descendant::node()", h.getNodeProcessingInstruction(), []);
+ });
+
+ xit('works with namespace context', function() {
+ checkNodeResult("descendant::node()", h.getNodeNamespace(), []);
+ });
+
+ });
+
+ describe('descendant-or-self axis', function() {
+
+ it('works with element context', function() {
+ var nodes,
+ descendantNodes = function(node) {
+ var nodes = [],
+ i;
+ for (i = 0; i < node.childNodes.length; i++) {
+ nodes.push(node.childNodes.item(i));
+ nodes.push.apply(nodes, descendantNodes(node.childNodes.item(i)));
+ }
+ return nodes;
+ };
+ nodes = descendantNodes(doc.getElementById('testStepAxisDescendant'));
+ nodes.unshift(doc.getElementById('testStepAxisDescendant'));
+ checkNodeResult("descendant-or-self::node()", doc.getElementById('testStepAxisDescendant'), nodes);
+ });
+
+ it('works with attribute context', function() {
+ checkNodeResult("descendant-or-self::node()", h.getNodeAttribute(), [
+ h.getNodeAttribute()
+ ]);
+ });
+
+ it('works with CDATA context', function() {
+ checkNodeResult("descendant-or-self::node()", h.getNodeCData(), [
+ h.getNodeCData()
+ ]);
+ });
+
+ it('works with a comment context', function() {
+ checkNodeResult("descendant-or-self::node()", h.getNodeComment(), [
+ h.getNodeComment()
+ ]);
+ });
+
+ it('works with element context', function() {
+ checkNodeResult("descendant-or-self::node()", h.getNodeProcessingInstruction(), [
+ h.getNodeProcessingInstruction()
+ ]);
+ });
+
+ xit('works with a namspace context', function() {
+ checkNodeResult("descendant-or-self::node()", h.getNodeNamespace(), [
+ h.getNodeNamespace()
+ ]);
+ });
+
+ });
+
+ describe('parent axis', function() {
+
+ it('works with a document context', function() {
+ checkNodeResult("parent::node()", doc, []);
+ });
+
+ it('works with a documentElement context', function() {
+ checkNodeResult("parent::node()", doc.documentElement, [doc]);
+ });
+
+ it('works with an element context', function() {
+ checkNodeResult("parent::node()", doc.getElementById('testStepAxisNodeElement'), [doc.getElementById('StepAxisCase')]);
+ });
+
+ it('works with an attribute context', function() {
+ checkNodeResult("parent::node()", h.getNodeAttribute(), [doc.getElementById('testStepAxisNodeAttribute')]);
+ });
+
+ it('works with a CData context', function() {
+ checkNodeResult("parent::node()", h.getNodeCData(), [doc.getElementById('testStepAxisNodeCData')]);
+ });
+
+ it('works with a comment context', function() {
+ checkNodeResult("parent::node()", h.getNodeComment(), [doc.getElementById('testStepAxisNodeComment')]);
+ });
+
+ it('works with a processing instruction', function() {
+ checkNodeResult("parent::node()", h.getNodeProcessingInstruction(), [doc.getElementById('testStepAxisNodeProcessingInstruction')]);
+ });
+
+ xit('works with a namespace', function() {
+ checkNodeResult("parent::node()", h.getNodeNamespace(), [doc.getElementById('testStepAxisNodeNamespace')]);
+ });
+
+ });
+
+ describe('ancestor axis', function() {
+
+ it('works for a cocument context', function() {
+ checkNodeResult("ancestor::node()", doc, []);
+ });
+
+ it('works for a documentElement context', function() {
+ checkNodeResult("ancestor::node()", doc.documentElement, [
+ doc
+ ]);
+ });
+
+ it('works for an element context', function() {
+ checkNodeResult("ancestor::node()", doc.getElementById('testStepAxisNodeElement'), [
+ doc,
+ doc.documentElement,
+ doc.querySelector('body'),
+ doc.getElementById('StepAxisCase')
+ ]);
+ });
+
+ it('works for an attribute context', function() {
+ checkNodeResult("ancestor::node()", h.getNodeAttribute(), [
+ doc,
+ doc.documentElement,
+ doc.querySelector('body'),
+ doc.getElementById('StepAxisCase'),
+ doc.getElementById('testStepAxisNodeAttribute')
+ ]);
+ });
+
+ it('works for a CDATA context', function() {
+ checkNodeResult("ancestor::node()", h.getNodeCData(), [
+ doc,
+ doc.documentElement,
+ doc.querySelector('body'),
+ doc.getElementById('StepAxisCase'),
+ doc.getElementById('testStepAxisNodeCData')
+ ]);
+ });
+
+ it('works for a comment context', function() {
+ checkNodeResult("ancestor::node()", h.getNodeComment(), [
+ doc,
+ doc.documentElement,
+ doc.querySelector('body'),
+ doc.getElementById('StepAxisCase'),
+ doc.getElementById('testStepAxisNodeComment')
+ ]);
+ });
+
+ it('works for a processing instruction context', function() {
+ checkNodeResult("ancestor::node()", h.getNodeProcessingInstruction(), [
+ doc,
+ doc.documentElement,
+ doc.querySelector('body'),
+ doc.getElementById('StepAxisCase'),
+ doc.getElementById('testStepAxisNodeProcessingInstruction')
+ ]);
+ });
+
+ xit('works for a namespace context ', function() {
+ checkNodeResult("ancestor::node()", h.getNodeNamespace(), [
+ doc,
+ doc.documentElement,
+ doc.querySelector('body'),
+ doc.getElementById('StepAxisCase'),
+ doc.getElementById('testStepAxisNodeNamespace')
+ ]);
+ });
+
+ });
+
+ describe('ancestor-or-self axis', function() {
+
+ it('works for document context', function() {
+ checkNodeResult("ancestor-or-self::node()", doc, [
+ doc
+ ]);
+ });
+
+ it('works for documentElement context', function() {
+ checkNodeResult("ancestor-or-self::node()", doc.documentElement, [
+ doc,
+ doc.documentElement
+ ]);
+ });
+
+ it('works for an element context', function() {
+ checkNodeResult("ancestor-or-self::node()", doc.getElementById('testStepAxisNodeElement'), [
+ doc,
+ doc.documentElement,
+ doc.querySelector('body'),
+ doc.getElementById('StepAxisCase'),
+ doc.getElementById('testStepAxisNodeElement')
+ ]);
+ });
+
+ it('works for an attribute context', function() {
+ checkNodeResult("ancestor-or-self::node()", h.getNodeAttribute(), [
+ doc,
+ doc.documentElement,
+ doc.querySelector('body'),
+ doc.getElementById('StepAxisCase'),
+ doc.getElementById('testStepAxisNodeAttribute'),
+ h.getNodeAttribute()
+ ]);
+ });
+
+ it('works for a CDATA context', function() {
+ checkNodeResult("ancestor-or-self::node()", h.getNodeCData(), [
+ doc,
+ doc.documentElement,
+ doc.querySelector('body'),
+ doc.getElementById('StepAxisCase'),
+ doc.getElementById('testStepAxisNodeCData'),
+ h.getNodeCData()
+ ]);
+ });
+
+ it('works for a comment context', function() {
+ checkNodeResult("ancestor-or-self::node()", h.getNodeComment(), [
+ doc,
+ doc.documentElement,
+ doc.querySelector('body'),
+ doc.getElementById('StepAxisCase'),
+ doc.getElementById('testStepAxisNodeComment'),
+ h.getNodeComment()
+ ]);
+ });
+
+ it('works for processingInstruction context', function() {
+ checkNodeResult("ancestor-or-self::node()", h.getNodeProcessingInstruction(), [
+ doc,
+ doc.documentElement,
+ doc.querySelector('body'),
+ doc.getElementById('StepAxisCase'),
+ doc.getElementById('testStepAxisNodeProcessingInstruction'),
+ h.getNodeProcessingInstruction()
+ ]);
+ });
+
+ xit('works for namespace context', function() {
+ checkNodeResult("ancestor-or-self::node()", h.getNodeNamespace(), [
+ doc,
+ doc.documentElement,
+ doc.querySelector('body'),
+ doc.getElementById('StepAxisCase'),
+ doc.getElementById('testStepAxisNodeNamespace'),
+ h.getNodeNamespace()
+ ]);
+ });
+
+ });
+
+ describe('following-sibling axis', function() {
+
+ it('works for a document context', function() {
+ checkNodeResult("following-sibling::node()", doc, []);
+ });
+
+ it('works for a documentElement context', function() {
+ checkNodeResult("following-sibling::node()", doc.documentElement, h.followingSiblingNodes(doc.documentElement));
+ });
+
+ it('works for an element: context', function() {
+ checkNodeResult("following-sibling::node()", doc.getElementById('testStepAxisNodeElement'), h.followingSiblingNodes(doc.getElementById('testStepAxisNodeElement')));
+ });
+
+ it('works for an attribute context', function() {
+ checkNodeResult("following-sibling::node()", h.getNodeAttribute(), []);
+ });
+
+ it('works for a CDATA context', function() {
+ checkNodeResult("following-sibling::node()", h.getNodeCData(), h.followingSiblingNodes(h.getNodeCData()));
+ });
+
+ it('works for a comment context', function() {
+ checkNodeResult("following-sibling::node()", h.getNodeComment(), h.followingSiblingNodes(h.getNodeComment()));
+ });
+
+ it('works for a processing instruction', function() {
+ checkNodeResult("following-sibling::node()", h.getNodeProcessingInstruction(), h.followingSiblingNodes(h.getNodeProcessingInstruction()));
+ });
+
+ xit('works for a namespace context', function() {
+ checkNodeResult("following-sibling::node()", h.getNodeNamespace(), []);
+ });
+
+ });
+
+
+ describe('preceding-sibling axis', function() {
+
+ it('works for a document context', function() {
+ checkNodeResult("preceding-sibling::node()", doc, []);
+ });
+
+ it('works for a documentElement context', function() {
+ checkNodeResult("preceding-sibling::node()", doc.documentElement, h.precedingSiblingNodes(doc.documentElement));
+ });
+
+ it('works for a Element context', function() {
+ checkNodeResult("preceding-sibling::node()", doc.getElementById('testStepAxisNodeElement'), h.precedingSiblingNodes(doc.getElementById('testStepAxisNodeElement')));
+ });
+
+ it('works for a Attribute context', function() {
+ checkNodeResult("preceding-sibling::node()", h.getNodeAttribute(), []);
+ });
+
+ it('works for a CData context', function() {
+ checkNodeResult("preceding-sibling::node()", h.getNodeCData(), h.precedingSiblingNodes(h.getNodeCData()));
+ });
+
+ it('works for a Comment context', function() {
+ checkNodeResult("preceding-sibling::node()", h.getNodeComment(), h.precedingSiblingNodes(h.getNodeComment()));
+ });
+
+ it('works for a ProcessingInstruction context', function() {
+ checkNodeResult("preceding-sibling::node()", h.getNodeProcessingInstruction(), h.precedingSiblingNodes(h.getNodeProcessingInstruction()));
+ });
+
+ xit('works for a Namespace context', function() {
+ checkNodeResult("preceding-sibling::node()", h.getNodeNamespace(), []);
+ });
+
+ });
+
+ describe('following axis', function() {
+
+ it('works for a document context', function() {
+ checkNodeResult("following::node()", doc, []);
+ });
+
+ it('works for a documentElement context', function() {
+ checkNodeResult("following::node()", doc.documentElement, h.followingNodes(doc.documentElement));
+ });
+
+ it('works for an element context', function() {
+ checkNodeResult("following::node()", doc.getElementById('testStepAxisNodeElement'), h.followingNodes(doc.getElementById('testStepAxisNodeElement')));
+ });
+
+ it('works for an attribute context', function() {
+ checkNodeResult("following::node()", h.getNodeAttribute(), h.followingNodes(doc.getElementById('testStepAxisNodeAttribute')));
+ });
+
+ it('works for a CDATA context', function() {
+ checkNodeResult("following::node()", h.getNodeCData(), h.followingNodes(h.getNodeCData()));
+ });
+
+ it('works for a comment context', function() {
+ checkNodeResult("following::node()", h.getNodeComment(), h.followingNodes(h.getNodeComment()));
+ });
+
+ it('works for a processing instruction context', function() {
+ checkNodeResult("following::node()", h.getNodeProcessingInstruction(), h.followingNodes(h.getNodeProcessingInstruction()));
+ });
+
+ xit('works for a namespace context', function() {
+ checkNodeResult("following::node()", h.getNodeNamespace(), h.followingNodes(doc.getElementById('testStepAxisNodeNamespace')));
+ });
+
+ });
+
+ describe('preceding axis', function() {
+
+ it('works for a document context', function() {
+ checkNodeResult("preceding::node()", doc, []);
+ });
+
+ it('works for a documentElement context', function() {
+ checkNodeResult("preceding::node()", doc.documentElement, h.precedingNodes(doc.documentElement));
+ });
+
+ it('works for an element context', function() {
+ checkNodeResult("preceding::node()", doc.getElementById('testStepAxisNodeElement'), h.precedingNodes(doc.getElementById('testStepAxisNodeElement')));
+ });
+
+ it('works for an attribute context', function() {
+ checkNodeResult("preceding::node()", h.getNodeAttribute(), h.precedingNodes(doc.getElementById('testStepAxisNodeAttribute')));
+ });
+
+ it('works for a CDATA context', function() {
+ checkNodeResult("preceding::node()", h.getNodeCData(), h.precedingNodes(h.getNodeCData()));
+ });
+
+ it('works for a Comment context', function() {
+ checkNodeResult("preceding::node()", h.getNodeComment(), h.precedingNodes(h.getNodeComment()));
+ });
+
+ it('works for a processing instruction context', function() {
+ checkNodeResult("preceding::node()", h.getNodeProcessingInstruction(), h.precedingNodes(h.getNodeProcessingInstruction()));
+ });
+
+ xit('works for a Namespace context', function() {
+ checkNodeResult("preceding::node()", h.getNodeNamespace(), h.precedingNodes(doc.getElementById('testStepAxisNodeNamespace')));
+ });
+
+ });
+
+ describe('attribute axis', function() {
+
+ it('works for a document context', function() {
+ checkNodeResult("attribute::node()", doc, []);
+ });
+
+ it('works for an attribute context', function() {
+ checkNodeResult("attribute::node()", h.getNodeAttribute(), []);
+ });
+
+ it('works for a CDATA context', function() {
+ checkNodeResult("attribute::node()", h.getNodeCData(), []);
+ });
+
+ it('works for a comment context', function() {
+ checkNodeResult("attribute::node()", h.getNodeComment(), []);
+ });
+
+ it('works for a processing instruction context', function() {
+ checkNodeResult("attribute::node()", h.getNodeProcessingInstruction(), []);
+ });
+
+ xit('works for a namespace context', function() {
+ checkNodeResult("attribute::node()", h.getNodeNamespace(), []);
+ });
+
+ it('works for a 0 context', function() {
+ checkNodeResult("attribute::node()", doc.getElementById('testStepAxisNodeAttribute0'), filterAttributes(doc.getElementById('testStepAxisNodeAttribute0').attributes));
+ });
+
+ it('works for a 1 context', function() {
+ checkNodeResult("attribute::node()", doc.getElementById('testStepAxisNodeAttribute1'), filterAttributes(doc.getElementById('testStepAxisNodeAttribute1').attributes));
+ });
+
+ it('works for a 3: context', function() {
+ checkNodeResult("attribute::node()", doc.getElementById('testStepAxisNodeAttribute3'), filterAttributes(doc.getElementById('testStepAxisNodeAttribute3').attributes));
+ });
+
+ it('works for a StartXml context', function() {
+ checkNodeResult("attribute::node()", doc.getElementById('testStepAxisNodeAttributeStartXml'), filterAttributes(doc.getElementById('testStepAxisNodeAttributeStartXml').attributes));
+ });
+
+ });
+
+ describe('namespace axis', function() {
+
+ it('works for a document context', function() {
+ checkNodeResultNamespace("namespace::node()", doc, []);
+ });
+
+ it('works for an attribute context', function() {
+ checkNodeResultNamespace("namespace::node()", h.getNodeAttribute(), []);
+ });
+
+ it('works for a CDATA context', function() {
+ checkNodeResultNamespace("namespace::node()", h.getNodeCData(), []);
+ });
+
+ it('works for a comment context', function() {
+ checkNodeResultNamespace("namespace::node()", h.getNodeComment(), []);
+ });
+
+ it('works for a processing instruction context', function() {
+ checkNodeResultNamespace("namespace::node()", h.getNodeProcessingInstruction(), []);
+ });
+
+ it('works for a namespace context', function() {
+ checkNodeResultNamespace("namespace::node()", h.getNodeNamespace(), []);
+ });
+
+ it('works for a document element context', function() {
+ checkNodeResultNamespace("namespace::node()", doc.documentElement, [
+ ['', 'http://www.w3.org/1999/xhtml'],
+ ['ev', 'http://some-namespace.com/nss'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace']
+ ]);
+ });
+
+ it('works for a 0 context', function() {
+ checkNodeResultNamespace("namespace::node()", doc.getElementById('testStepAxisNodeNamespace0'), [
+ ['', 'http://www.w3.org/1999/xhtml'],
+ ['ev', 'http://some-namespace.com/nss'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace']
+ ]);
+ });
+
+ it('works for a 1 context', function() {
+ checkNodeResultNamespace("namespace::node()", doc.getElementById('testStepAxisNodeNamespace1'), [
+ ['', 'http://www.w3.org/1999/xhtml'],
+ ['a', 'asdf'],
+ ['ev', 'http://some-namespace.com/nss'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace']
+ ]);
+ });
+
+ it('works for a 1 default context', function() {
+ checkNodeResultNamespace("namespace::node()", doc.getElementById('testStepAxisNodeNamespace1defaultContainer').firstChild, [
+ ['', 'asdf'],
+ ['ev', 'http://some-namespace.com/nss'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace']
+ ]);
+ });
+
+ it('works for a 1 default 2 context', function() {
+ checkNodeResultNamespace("namespace::node()", doc.getElementById('testStepAxisNodeNamespace1defaultContainer2').firstChild, [
+ ['ev', 'http://some-namespace.com/nss'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace']
+ ]);
+ });
+
+ it('works for a 3 context', function() {
+ var namespaces = [],
+ contextNode = doc.getElementById('testStepAxisNodeNamespace3');
+
+ namespaces.push(['', 'http://www.w3.org/1999/xhtml']);
+ parseNamespacesFromAttributes(contextNode.attributes, namespaces);
+ namespaces.push(['ev', 'http://some-namespace.com/nss']);
+ namespaces.push(['xml', 'http://www.w3.org/XML/1998/namespace']);
+
+ checkNodeResultNamespace("namespace::node()", contextNode, namespaces);
+ });
+
+ it('works for a 3 default context', function() {
+ var namespaces = [],
+ contextNode = doc.getElementById('testStepAxisNodeNamespace3defaultContainer').firstChild;
+
+ parseNamespacesFromAttributes(contextNode.attributes, namespaces);
+ namespaces.push(['ev', 'http://some-namespace.com/nss']);
+ namespaces.push(['xml', 'http://www.w3.org/XML/1998/namespace']);
+
+ checkNodeResultNamespace("namespace::node()", contextNode, namespaces);
+ });
+
+ it('works with an element context that overrides the namespace', function() {
+ checkNodeResultNamespace("namespace::node()", doc.getElementById('testStepAxisNodeNamespaceXmlOverride'), [
+ ['', 'http://www.w3.org/1999/xhtml'],
+ ['ev', 'http://some-other-namespace/'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace']
+ ]);
+ });
+
+ it('works with "NoNamespaceNodeSharingAmongstElements" context', function() {
+ var j, result, result2, item, item2, expectedResult;
+
+ expectedResult = [
+ ['', 'http://www.w3.org/1999/xhtml'],
+ ['a', 'asdf'],
+ ['ev', 'http://some-namespace.com/nss'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace']
+ ];
+
+ result = documentEvaluate("namespace::node()", doc.getElementById('testStepAxisNodeNamespace1'), null, win.XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+ result2 = documentEvaluate("namespace::node()", doc.getElementById('testStepAxisNodeNamespace1b'), null, win.XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); //
+ expect(result.snapshotLength).to.equal(expectedResult.length);
+ expect(result2.snapshotLength).to.equal(expectedResult.length);
+
+ for (j = 0; j < result.snapshotLength; j++) {
+ item = result.snapshotItem(j);
+ item2 = result2.snapshotItem(j);
+
+ expect(item.nodeName).to.equal('#namespace');
+ expect(item2.nodeName).to.equal('#namespace');
+
+ expect(item.localName).to.equal(expectedResult[j][0]);
+ expect(item2.localName).to.equal(expectedResult[j][0]);
+
+ expect(item.namespaceURI).to.equal(expectedResult[j][1]);
+ expect(item2.namespaceURI).to.equal(expectedResult[j][1]);
+
+ expect(item2).to.not.deep.equal(item);
+ }
+ });
+
+ it('works with "SameNamespaceNodeOnSameElement" context', function() {
+ var j, result, result2, item, item2, expectedResult;
+
+ expectedResult = [
+ ['', 'http://www.w3.org/1999/xhtml'],
+ ['a', 'asdf'],
+ ['ev', 'http://some-namespace.com/nss'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace']
+ ];
+
+ result = documentEvaluate("namespace::node()", doc.getElementById('testStepAxisNodeNamespace1'), null, win.XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+ result2 = documentEvaluate("namespace::node()", doc.getElementById('testStepAxisNodeNamespace1'), null, win.XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+
+ for (j = 0; j < result.snapshotLength; j++) {
+ item = result.snapshotItem(j);
+ item2 = result2.snapshotItem(j);
+
+ expect(item.nodeName).to.equal('#namespace');
+ expect(item.localName).to.equal(expectedResult[j][0]);
+ expect(item.namespaceURI).to.equal(expectedResult[j][1]);
+ expect(item2).to.deep.equal(item);
+ }
+ });
+
+ });
+
+ describe('attribute && namespace axes', function() {
+
+ it('works for Attrib1Ns1', function() {
+ var attributes = [],
+ i,
+ contextNode;
+
+ contextNode = doc.getElementById('testStepAxisNodeAttrib1Ns1');
+
+ for (i = 0; i < contextNode.attributes.length; i++) {
+ if (!contextNode.attributes[i].specified) {
+ continue;
+ }
+ if (contextNode.attributes.item(i).nodeName.substring(0, 5) !== 'xmlns') {
+ attributes.push(contextNode.attributes.item(i));
+ }
+ }
+
+ checkNodeResult("attribute::node()", contextNode, attributes); //
+
+ checkNodeResultNamespace("namespace::node()", contextNode, [
+ ['', 'http://www.w3.org/1999/xhtml'],
+ ['a', 'asdf'],
+ ['ev', 'http://some-namespace.com/nss'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace']
+ ]);
+ });
+
+ it('works for Attrib1Ns1reversed', function() {
+ var attributes = [],
+ i,
+ contextNode;
+
+ contextNode = doc.getElementById('testStepAxisNodeAttrib1Ns1reversed');
+
+ for (i = 0; i < contextNode.attributes.length; i++) {
+ if (!contextNode.attributes[i].specified) {
+ continue;
+ }
+ if (contextNode.attributes.item(i).nodeName.substring(0, 5) !== 'xmlns') {
+ attributes.push(contextNode.attributes.item(i));
+ }
+ }
+
+ checkNodeResult("attribute::node()", contextNode, attributes);
+
+ checkNodeResultNamespace("namespace::node()", contextNode, [
+ ['', 'http://www.w3.org/1999/xhtml'],
+ ['a', 'asdf'],
+ ['ev', 'http://some-namespace.com/nss'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace']
+ ]);
+ });
+
+ it('works for NodeAttrib2Ns1', function() {
+ var attributes = [],
+ i,
+ contextNode;
+
+ contextNode = doc.getElementById('testStepAxisNodeAttrib2Ns1');
+
+ for (i = 0; i < contextNode.attributes.length; i++) {
+ if (!contextNode.attributes[i].specified) {
+ continue;
+ }
+ if (contextNode.attributes.item(i).nodeName.substring(0, 5) !== 'xmlns') {
+ attributes.push(contextNode.attributes.item(i));
+ }
+ }
+
+ checkNodeResult("attribute::node()", contextNode, attributes); //
+ checkNodeResultNamespace("namespace::node()", contextNode, [
+ ['', 'http://www.w3.org/1999/xhtml'],
+ ['c', 'asdf3'],
+ ['ev', 'http://some-namespace.com/nss'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace']
+ ]);
+ });
+
+ it('works for Attrib2Ns1reversed', function() {
+ var attributes = [],
+ i,
+ contextNode;
+
+ contextNode = doc.getElementById('testStepAxisNodeAttrib2Ns1reversedContainer').firstChild;
+
+ for (i = 0; i < contextNode.attributes.length; i++) {
+ if (!contextNode.attributes[i].specified) {
+ continue;
+ }
+ if (contextNode.attributes.item(i).nodeName.substring(0, 5) !== 'xmlns') {
+ attributes.push(contextNode.attributes.item(i));
+ }
+ }
+
+ checkNodeResult("attribute::node()", contextNode, attributes);
+
+ checkNodeResultNamespace("namespace::node()", contextNode, [
+ ['', 'asdf'],
+ ['ev', 'http://some-namespace.com/nss'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace']
+ ]);
+ });
+
+ it('works for NodeAttrib2Ns2', function() {
+ var attributes = [],
+ i,
+ contextNode;
+
+ contextNode = doc.getElementById('testStepAxisNodeAttrib2Ns2Container').firstChild;
+
+ for (i = 0; i < contextNode.attributes.length; i++) {
+ if (!contextNode.attributes[i].specified) {
+ continue;
+ }
+ if (contextNode.attributes.item(i).nodeName.substring(0, 5) !== 'xmlns') {
+ attributes.push(contextNode.attributes.item(i));
+ }
+ }
+
+ checkNodeResult("attribute::node()", contextNode, attributes);
+
+ checkNodeResultNamespace("namespace::node()", contextNode, [
+ ['', 'asdf2'],
+ ['a', 'asdf'],
+ ['ev', 'http://some-namespace.com/nss'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace']
+ ]);
+
+ });
+ });
+});
diff --git a/test/spec/before.spec.js b/test/spec/before.spec.js
new file mode 100644
index 0000000..4c35dfd
--- /dev/null
+++ b/test/spec/before.spec.js
@@ -0,0 +1,40 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, documentEvaluate, window, document, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+var doc, win, docEvaluate;
+
+before(function(done) {
+ console.log('running before');
+
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('id', 'testdoc');
+ iframe.setAttribute('src', '/base/test/doc.xml');
+
+ iframe.onload = function() {
+ var script = document.createElement('script');
+ // TODO: should load parser and engine separately to facilitate development
+ script.setAttribute('src', '/base/dist/xpathjs.js');
+
+ script.onload = function() {
+ win = iframe.contentWindow;
+ doc = win.document;
+ win.XPathJS.bindDomLevel3XPath();
+ docEvaluate = doc.evaluate;
+ done();
+ };
+
+ iframe.contentWindow.document.querySelector('body').appendChild(script);
+ };
+ document.body.appendChild(iframe);
+
+ /*
+ loadXMLFile('/base/test/doc.xml', function(xmlStr) {
+ var parser = new window.DOMParser();
+ win = window;
+ win.XPathJS.bindDomLevel3XPath();
+ doc = parser.parseFromString(xmlStr, "text/xml");
+ docEvaluate = win.document.evaluate;
+ done();
+ });*/
+
+});
diff --git a/test/spec/boolean-functions-native.spec.js b/test/spec/boolean-functions-native.spec.js
new file mode 100644
index 0000000..bc388c2
--- /dev/null
+++ b/test/spec/boolean-functions-native.spec.js
@@ -0,0 +1,169 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, documentEvaluate, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+describe('native boolean functions', function() {
+
+ it('true()', function() {
+ var result = documentEvaluate("true()", doc, helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+ });
+
+ it('true() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("true(1)", doc, helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('false()', function() {
+ var result = documentEvaluate("false()", doc, helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(false);
+ });
+
+ it('true() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("false('a')", doc, helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('boolean()', function() {
+ var result;
+
+ result = documentEvaluate("boolean('a')", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+
+ result = documentEvaluate("boolean('')", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(false);
+ });
+
+ it('boolean() conversion of booleans', function() {
+ var result;
+
+ result = documentEvaluate("boolean(true())", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+
+ result = documentEvaluate("boolean(false())", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(false);
+ });
+
+ it('boolean() conversion of numbers', function() {
+ var result;
+
+ result = documentEvaluate("boolean(1)", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+
+ result = documentEvaluate("boolean(-1)", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+
+ result = documentEvaluate("boolean(1 div 0)", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+
+ result = documentEvaluate("boolean(0.1)", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+
+ result = documentEvaluate("boolean('0.0001')", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+
+ result = documentEvaluate("boolean(0)", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(false);
+
+ result = documentEvaluate("boolean(0.0)", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(false);
+
+ result = documentEvaluate("boolean(number(''))", doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(false);
+ });
+
+ it('boolean() conversion of nodeset', function() {
+ var result;
+
+ result = documentEvaluate("boolean(/xhtml:html)", doc, helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+
+ result = documentEvaluate("boolean(/asdf)", doc, helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(false);
+
+ result = documentEvaluate("boolean(self::node())", doc.getElementById('FunctionBooleanEmptyNode'), helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+
+ result = documentEvaluate("boolean(//xhtml:article)", doc, helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(false);
+ });
+
+ it('boolean() fails when too few arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("boolean()", doc, helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('boolean() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("boolean(1, 2)", doc, helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('not()', function() {
+ var result;
+
+ result = documentEvaluate("not(true())", doc, helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(false);
+
+ result = documentEvaluate("not(false())", doc, helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(true);
+
+ result = documentEvaluate("not(1)", doc, helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(false);
+ });
+
+ it('not() fails when too few arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("not()", doc, helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('not() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("not(1, 2)", doc, helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('lang()', function() {
+ [
+ ["lang('en')", doc.documentElement, true],
+ ["lang('EN')", doc.documentElement, true],
+ ["lang('EN-us')", doc.documentElement, true],
+ ["lang('EN-us-boont')", doc.documentElement, false], //
+ // hierarchy check
+ ["lang('EN')", doc.querySelector('body'), true],
+ ["lang('sr')", doc.getElementById('testLang2'), true],
+ ["lang('sr-Cyrl-bg')", doc.getElementById('testLang2'), true],
+ ["lang('fr')", doc.getElementById('testLang2'), false], //
+ // node check
+ ["lang('sl')", doc.getElementById('testLang3'), true], //
+ // attribute node check
+ ["lang('sr-Cyrl-bg')", filterAttributes(doc.getElementById('testLang4').attributes)[0], true]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], t[1], helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(t[2]);
+ });
+ });
+
+ it('lang() fails when too few arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("lang()", doc, helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('lang() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("lang(1, 2)", doc, helpers.xhtmlResolver, win.XPathResult.BOOLEAN_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+});
diff --git a/test/spec/comparison-operator-native.spec.js b/test/spec/comparison-operator-native.spec.js
new file mode 100644
index 0000000..4d1a2ab
--- /dev/null
+++ b/test/spec/comparison-operator-native.spec.js
@@ -0,0 +1,430 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, DOMException, XPathException, documentEvaluate, documentCreateExpression, documentCreateNSResolver, checkNodeResult, checkNodeResultNamespace, parseNamespacesFromAttributes, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+describe('Comparison operator', function() {
+
+ it('correctly evaluates = and !=', function() {
+ var result, input, i, expr, j, k,
+ ops = ['=', '!='];
+
+ input = [
+ [
+ ["1", "1"],
+ [true, false], doc
+ ],
+ [
+ ["1", "0"],
+ [false, true], doc
+ ],
+ [
+ ["1", "'1'"],
+ [true, false], doc
+ ],
+ [
+ ["1", "'0'"],
+ [false, true], doc
+ ],
+ [
+ ["1", "true()"],
+ [true, false], doc
+ ],
+ [
+ ["1", "false()"],
+ [false, true], doc
+ ],
+ [
+ ["0", "false()"],
+ [true, false], doc
+ ],
+ [
+ ["-10", "*"],
+ [false, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["4", "*"],
+ [true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["4.3", "*"],
+ [false, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["0", "*"],
+ [false, false], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')
+ ],
+
+ [
+ ["true()", "true()"],
+ [true, false], doc
+ ],
+ [
+ ["false()", "false()"],
+ [true, false], doc
+ ],
+ [
+ ["true()", "false()"],
+ [false, true], doc
+ ],
+ [
+ ["true()", "'1'"],
+ [true, false], doc
+ ],
+ [
+ ["true()", "''"],
+ [false, true], doc
+ ],
+ [
+ ["false()", "'0'"],
+ [false, true], doc
+ ],
+ [
+ ["false()", "''"],
+ [true, false], doc
+ ],
+ [
+ ["true()", "*"],
+ [true, false], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["false()", "*"],
+ [false, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["true()", "*"],
+ [false, true], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')
+ ],
+ [
+ ["false()", "*"],
+ [true, false], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')
+ ],
+
+ [
+ ["'1a'", "'1a'"],
+ [true, false], doc
+ ],
+ [
+ ["'1'", "'0'"],
+ [false, true], doc
+ ],
+ [
+ ["''", "''"],
+ [true, false], doc
+ ],
+ [
+ ["''", "'0'"],
+ [false, true], doc
+ ],
+ [
+ ["'aaa'", "*"],
+ [true, true], doc.getElementById('ComparisonOperatorCaseNodesetStrings')
+ ],
+ [
+ ["'bb'", "*"],
+ [false, true], doc.getElementById('ComparisonOperatorCaseNodesetStrings')
+ ],
+ [
+ ["''", "*"],
+ [false, true], doc.getElementById('ComparisonOperatorCaseNodesetStrings')
+ ],
+ [
+ ["''", "*"],
+ [false, false], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')
+ ],
+
+ [
+ ["id('ComparisonOperatorCaseNodesetNegative5to5')/*", "id('ComparisonOperatorCaseNodesetEmpty')/*"],
+ [false, false], doc
+ ],
+ [
+ ["id('ComparisonOperatorCaseNodesetNegative5to5')/*", "id('ComparisonOperatorCaseNodeset4to8')/*"],
+ [true, true], doc
+ ],
+ [
+ ["id('ComparisonOperatorCaseNodesetNegative5to5')/*", "id('ComparisonOperatorCaseNodeset6to10')/*"],
+ [false, true], doc
+ ]
+ ];
+
+ for (k = 0; k < ops.length; k++) // different operators
+ {
+ for (j = 0; j < 2; j++) // switch parameter order
+ {
+ for (i = 0; i < input.length; i++) // all cases
+ {
+ expr = input[i][0][j % 2] + " " + ops[k] + " " + input[i][0][(j + 1) % 2];
+ result = documentEvaluate(expr, input[i][2], null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(input[i][1][k]);
+ }
+ }
+ }
+ });
+
+ it('correctly evaluates <, <=, > and >=', function() {
+ var result, input, i, expr, k,
+ ops = ['<', '<=', '>', '>='];
+
+ input = [
+ [
+ ["1", "2"],
+ [true, true, false, false], doc
+ ],
+ [
+ ["1", "1"],
+ [false, true, false, true], doc
+ ],
+ [
+ ["1", "0"],
+ [false, false, true, true], doc
+ ],
+ [
+ ["1", "'2'"],
+ [true, true, false, false], doc
+ ],
+ [
+ ["1", "'1'"],
+ [false, true, false, true], doc
+ ],
+ [
+ ["1", "'0'"],
+ [false, false, true, true], doc
+ ],
+ [
+ ["2", "true()"],
+ [false, false, true, true], doc
+ ],
+ [
+ ["1", "true()"],
+ [false, true, false, true], doc
+ ],
+ [
+ ["1", "false()"],
+ [false, false, true, true], doc
+ ],
+ [
+ ["0", "false()"],
+ [false, true, false, true], doc
+ ],
+ [
+ ["0", "true()"],
+ [true, true, false, false], doc
+ ],
+ [
+ ["-10", "*"],
+ [true, true, false, false], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["10", "*"],
+ [false, false, true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["5", "*"],
+ [false, true, true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["2", "*"],
+ [true, true, true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["0", "*"],
+ [false, false, false, false], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')
+ ],
+
+ [
+ ["true()", "2"],
+ [true, true, false, false], doc
+ ],
+ [
+ ["true()", "1"],
+ [false, true, false, true], doc
+ ],
+ [
+ ["false()", "1"],
+ [true, true, false, false], doc
+ ],
+ [
+ ["false()", "0"],
+ [false, true, false, true], doc
+ ],
+ [
+ ["true()", "0"],
+ [false, false, true, true], doc
+ ],
+ [
+ ["true()", "true()"],
+ [false, true, false, true], doc
+ ],
+ [
+ ["true()", "false()"],
+ [false, false, true, true], doc
+ ],
+ [
+ ["false()", "false()"],
+ [false, true, false, true], doc
+ ],
+ [
+ ["false()", "true()"],
+ [true, true, false, false], doc
+ ],
+ [
+ ["true()", "'1'"],
+ [false, true, false, true], doc
+ ],
+ [
+ ["true()", "''"],
+ [false, false, false, false], doc
+ ],
+ [
+ ["false()", "'0'"],
+ [false, true, false, true], doc
+ ],
+ [
+ ["false()", "''"],
+ [false, false, false, false], doc
+ ],
+ [
+ ["true()", "*"],
+ [false, true, false, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["true()", "*"],
+ [false, false, true, true], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')
+ ],
+ [
+ ["false()", "*"],
+ [true, true, false, false], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["false()", "*"],
+ [false, true, false, true], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')
+ ],
+
+ [
+ ["'2'", "1"],
+ [false, false, true, true], doc
+ ],
+ [
+ ["'1'", "1"],
+ [false, true, false, true], doc
+ ],
+ [
+ ["'0'", "1"],
+ [true, true, false, false], doc
+ ],
+ [
+ ["'1'", "true()"],
+ [false, true, false, true], doc
+ ],
+ [
+ ["''", "true()"],
+ [false, false, false, false], doc
+ ],
+ [
+ ["'0'", "false()"],
+ [false, true, false, true], doc
+ ],
+ [
+ ["''", "false()"],
+ [false, false, false, false], doc
+ ],
+ [
+ ["'1a'", "'1a'"],
+ [false, false, false, false], doc
+ ],
+ [
+ ["'1'", "'0'"],
+ [false, false, true, true], doc
+ ],
+ [
+ ["''", "''"],
+ [false, false, false, false], doc
+ ],
+ [
+ ["''", "'0'"],
+ [false, false, false, false], doc
+ ],
+ [
+ ["'4'", "*"],
+ [true, true, true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["'aaa'", "*"],
+ [false, false, false, false], doc.getElementById('ComparisonOperatorCaseNodesetStrings')
+ ],
+ [
+ ["''", "*"],
+ [false, false, false, false], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')
+ ],
+
+ [
+ ["*", "-10"],
+ [false, false, true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["*", "10"],
+ [true, true, false, false], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["*", "5"],
+ [true, true, false, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["*", "2"],
+ [true, true, true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["*", "0"],
+ [false, false, false, false], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')
+ ],
+ [
+ ["*", "true()"],
+ [false, true, false, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["*", "true()"],
+ [true, true, false, false], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')
+ ],
+ [
+ ["*", "false()"],
+ [false, false, true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["*", "false()"],
+ [false, true, false, true], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')
+ ],
+ [
+ ["*", "'4'"],
+ [true, true, true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')
+ ],
+ [
+ ["*", "'aaa'"],
+ [false, false, false, false], doc.getElementById('ComparisonOperatorCaseNodesetStrings')
+ ],
+ [
+ ["*", "''"],
+ [false, false, false, false], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')
+ ],
+ [
+ ["id('ComparisonOperatorCaseNodesetNegative5to5')/*", "id('ComparisonOperatorCaseNodesetEmpty')/*"],
+ [false, false, false, false], doc
+ ],
+ [
+ ["id('ComparisonOperatorCaseNodesetNegative5to5')/*", "id('ComparisonOperatorCaseNodeset4to8')/*"],
+ [true, true, true, true], doc
+ ],
+ [
+ ["id('ComparisonOperatorCaseNodesetNegative5to5')/*", "id('ComparisonOperatorCaseNodeset6to10')/*"],
+ [true, true, false, false], doc
+ ]
+ ];
+
+ for (k = 0; k < ops.length; k++) // different operators
+ {
+ for (i = 0; i < input.length; i++) // all cases
+ {
+ expr = input[i][0][0] + " " + ops[k] + " " + input[i][0][1];
+ result = documentEvaluate(expr, input[i][2], null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(input[i][1][k]);
+ }
+ }
+ });
+});
diff --git a/test/spec/create-expression-native.spec.js b/test/spec/create-expression-native.spec.js
new file mode 100644
index 0000000..c1b150e
--- /dev/null
+++ b/test/spec/create-expression-native.spec.js
@@ -0,0 +1,47 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, DOMException, XPathException, documentEvaluate, documentCreateExpression, documentCreateNSResolver, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+describe('creating expressions', function() {
+
+ it('parses', function() {
+ var resolver = documentCreateNSResolver(doc.documentElement);
+ var expression = documentCreateExpression('1', resolver);
+
+ expect(expression).to.be.an.instanceOf(win.XPathExpression);
+ });
+
+ it('throws invalid expression exceptions', function() {
+ var resolver = documentCreateNSResolver(doc.documentElement);
+ var test = function() {
+ documentCreateExpression('aa&&aa', resolver);
+ };
+
+ expect(test).to.throw(win.XPathException.INVALID_EXPRESSION_ERR); //,/DOM XPath Exception 51/);
+ });
+
+ it('throws exception when parsing without a resolver', function() {
+ var test = function() {
+ documentCreateExpression('xml:node');
+ };
+
+ expect(test).to.throw(win.XPathException.NAMESPACE_ERR);
+ });
+
+ it('parses with a namespace', function() {
+ var test = function() {
+ var resolver = documentCreateNSResolver(doc.documentElement);
+ var expression = documentCreateExpression('node1 | xml:node2 | ev:node2', resolver);
+ };
+
+ expect(test).not.to.throw();
+ });
+
+ it('throws an exception if namespace is incorrect', function() {
+ var resolver = documentCreateNSResolver(doc.documentElement);
+ var test = function() {
+ documentCreateExpression('as:node1 | ev:node2', resolver);
+ };
+
+ expect(test).to.throw(win.DOMException.NAMESPACE_ERR); //,/DOM Exception 14/);
+ });
+});
diff --git a/test/spec/exceptions-native.spec.js b/test/spec/exceptions-native.spec.js
new file mode 100644
index 0000000..eb28406
--- /dev/null
+++ b/test/spec/exceptions-native.spec.js
@@ -0,0 +1,39 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, documentEvaluate, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+describe('xpath exceptions', function() {
+
+ it('Exception constants have expected values', function() {
+ expect(win.XPathException.INVALID_EXPRESSION_ERR).to.equal(51);
+ expect(win.XPathException.TYPE_ERR).to.equal(52);
+ });
+
+ it('Constructor is constructing nicely with a message', function() {
+ var message = 'here is the message';
+ var ex = new win.XPathException(win.XPathException.INVALID_EXPRESSION_ERR, message);
+
+ // check code
+ expect(ex.code).to.equal(win.XPathException.INVALID_EXPRESSION_ERR);
+ expect(ex.code).to.equal(51);
+
+ // check message
+ expect(ex.message).to.equal(message);
+
+ // check toString
+ expect(ex.toString).to.be.an.instanceOf(win.Function);
+ expect(ex.toString()).to.equal('XPathException: "' + ex.message + '", code: "' + ex.code + '", name: "INVALID_EXPRESSION_ERR"');
+ });
+
+ it('Constructor is constructing nicely without a message', function() {
+ var ex = new win.XPathException(win.XPathException.INVALID_EXPRESSION_ERR);
+ expect(ex.message).to.equal("");
+ });
+
+ it('Constructor throws exception when wrong arguments provided', function() {
+ var test = function() {
+ new win.XPathException(99, 'message goes here');
+ };
+ expect(test).to.throw(win.Error, /Unsupported XPathException code: 99/);
+ });
+
+});
diff --git a/test/spec/expression-evaluation-native.spec.js b/test/spec/expression-evaluation-native.spec.js
new file mode 100644
index 0000000..15208e5
--- /dev/null
+++ b/test/spec/expression-evaluation-native.spec.js
@@ -0,0 +1,52 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, documentEvaluate, documentCreateNSResolver, checkNodeResult, checkNodeResultNamespace, parseNamespacesFromAttributes, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+describe('XPath expression evaluation', function() {
+
+ it('works with different types of context paramaters', function() {
+ var result;
+
+ [
+ [".", doc, 9], // Document
+ [".", doc.documentElement, 1], // Element
+ [".", doc.getElementById('testContextNodeParameter'), 1], // Element
+ [".", filterAttributes(doc.getElementById('testContextNodeParameter').attributes)[0], 2], // Attribute
+ [".", doc.getElementById('testContextNodeParameterText').firstChild, 3], // Text
+
+ // TODO: See for more details http://reference.sitepoint.com/javascript/CDATASection
+ // [".", doc.getElementById('testContextNodeParameterCData').firstChild, 4] // CDATASection
+
+ // TODO: See for more details http://reference.sitepoint.com/javascript/ProcessingInstruction
+ //[".", doc.getElementById('testContextNodeParameterProcessingInstruction').firstChild, 7], // ProcessingInstruction
+
+ [".", doc.getElementById('testContextNodeParameterComment').firstChild, 8] // Comment
+ ].forEach(function(t) {
+ expect(t[1].nodeType).to.equal(t[2]);
+ result = documentEvaluate(t[0], t[1], null, win.XPathResult.ANY_UNORDERED_NODE_TYPE, null);
+ expect(result.singleNodeValue).to.equal(t[1]);
+ });
+ });
+
+ it('works with different context paramater namespaces', function() {
+ var result, item;
+
+ // get a namespace node
+ result = documentEvaluate("namespace::node()", doc.getElementById('testContextNodeParameterNamespace'), null, win.XPathResult.ANY_UNORDERED_NODE_TYPE, null);
+ item = result.singleNodeValue;
+ expect(item).to.not.equal(null);
+ expect(item.nodeType).to.equal(13);
+
+ // use namespacenode as a context node
+ result = documentEvaluate(".", item, null, win.XPathResult.ANY_UNORDERED_NODE_TYPE, null);
+ expect(result.singleNodeValue).to.equal(item);
+ });
+
+
+ it('fails if the context is document fragment', function() {
+ var test = function() {
+ documentEvaluate(".", doc.createDocumentFragment(), null, win.XPathResult.ANY_UNORDERED_NODE_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+});
diff --git a/test/spec/namespace-resolver-native.spec.js b/test/spec/namespace-resolver-native.spec.js
new file mode 100644
index 0000000..7a96494
--- /dev/null
+++ b/test/spec/namespace-resolver-native.spec.js
@@ -0,0 +1,133 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, documentEvaluate, documentCreateNSResolver, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+describe('namespace resolver', function() {
+
+ it('looks up the namespaceURIElement', function() {
+ var node = doc.getElementById("testXPathNSResolverNode");
+ var resolver = documentCreateNSResolver(node);
+
+ // check type
+ expect(resolver).to.be.an.instanceOf(win.XPathNSResolver);
+ expect(resolver.lookupNamespaceURI).to.be.a('function');
+
+ // check preconfigured namespaces
+ expect(resolver.lookupNamespaceURI('xml')).to.equal('http://www.w3.org/XML/1998/namespace');
+ expect(resolver.lookupNamespaceURI('xmlns')).to.equal('http://www.w3.org/2000/xmlns/');
+
+ // check namespaces on current element
+ expect(resolver.lookupNamespaceURI('xforms')).to.equal('http://www.w3.org/2002/xforms');
+ expect(resolver.lookupNamespaceURI('nsnotexists')).to.equal(null);
+
+ // check default namespace
+ resolver = documentCreateNSResolver(helpers.getNextChildElementNode(node));
+ expect(resolver.lookupNamespaceURI('')).to.equal('http://www.w3.org/TR/REC-html40');
+ //Y.Assert.areSame('http://www.w3.org/TR/REC-html40', resolver.lookupNamespaceURI(''));
+ });
+
+ it('looks up the namespaceURIDocument', function() {
+ var resolver = documentCreateNSResolver(doc);
+
+ expect(resolver).to.be.an.instanceOf(win.XPathNSResolver);
+
+ expect(resolver.lookupNamespaceURI).to.be.a('function');
+
+ expect(resolver.lookupNamespaceURI('ev')).to.equal('http://some-namespace.com/nss');
+ });
+
+ it('looks up the namespaceURIDocumentElement', function() {
+ var node = doc.documentElement;
+ var resolver = documentCreateNSResolver(node);
+
+ expect(resolver).to.be.an.instanceOf(win.XPathNSResolver);
+ expect(resolver.lookupNamespaceURI).to.be.a('function');
+
+ expect(resolver.lookupNamespaceURI('ev')).to.equal('http://some-namespace.com/nss');
+ expect(resolver.lookupNamespaceURI('')).to.equal('http://www.w3.org/1999/xhtml');
+
+ // Make sure default xhtml namespace is correct
+ node.removeAttribute('xmlns');
+ expect(resolver.lookupNamespaceURI('')).to.equal(null);
+
+ // Change default root namespace
+ helpers.setAttribute(node, 'http://www.w3.org/2000/xmlns/', 'xmlns', 'some-namespace');
+ expect(resolver.lookupNamespaceURI('')).to.equal('some-namespace');
+
+ // Revert back to default xhtml namespace
+ helpers.setAttribute(node, 'http://www.w3.org/2000/xmlns/', 'xmlns', 'http://www.w3.org/1999/xhtml');
+ expect(resolver.lookupNamespaceURI('')).to.equal('http://www.w3.org/1999/xhtml');
+ });
+
+ it('looks up the namespaceURIAttribute', function() {
+ var attribute, i, resolver,
+ node = doc.documentElement;
+
+ // Check parent nodes for namespace prefix declarations
+ for (i = 0; i < node.attributes.length; i++) {
+ if (node.attributes[i].specified) {
+ attribute = node.attributes[i];
+ break;
+ }
+ }
+
+ expect(attribute).to.be.an('object');
+
+ resolver = documentCreateNSResolver(attribute);
+ expect(resolver.lookupNamespaceURI('ev')).to.equal('http://some-namespace.com/nss');
+
+ // Check parent nodes for default namespace declaration
+ attribute = null;
+ node = doc.getElementById("testXPathNSResolverNode");
+
+ for (i = 0; i < node.attributes.length; i++) {
+ if (node.attributes[i].specified) {
+ attribute = node.attributes[i];
+ break;
+ }
+ }
+
+ expect(attribute).to.be.an('object');
+
+ resolver = documentCreateNSResolver(attribute);
+ expect(resolver.lookupNamespaceURI('xforms')).to.equal('http://www.w3.org/2002/xforms');
+ });
+
+ it('looks up namespaceURIs that have changed', function() {
+ var node = helpers.getNextChildElementNode(doc.getElementById("testXPathNSResolverNode"));
+ var resolver = documentCreateNSResolver(node);
+
+ expect(resolver.lookupNamespaceURI('')).to.equal('http://www.w3.org/TR/REC-html40');
+
+ // Remove default namespace
+ node.removeAttribute('xmlns');
+ expect(resolver.lookupNamespaceURI('')).to.equal('http://www.w3.org/1999/xhtml');
+
+ // Change default namespace to some other namespace
+ helpers.setAttribute(node, 'http://www.w3.org/2000/xmlns/', 'xmlns', 'some-namespace');
+ expect(resolver.lookupNamespaceURI('')).to.equal('some-namespace');
+
+ // No default namespace
+ helpers.setAttribute(node, 'http://www.w3.org/2000/xmlns/', 'xmlns', '');
+ expect(resolver.lookupNamespaceURI('')).to.equal('');
+
+ // Back to original
+ helpers.setAttribute(node, 'http://www.w3.org/2000/xmlns/', 'xmlns', 'http://www.w3.org/TR/REC-html40');
+ expect(resolver.lookupNamespaceURI('')).to.equal('http://www.w3.org/TR/REC-html40');
+ });
+
+ it('looks up a hierarchical namespaceURI', function() {
+ var node = doc.getElementById("testXPathNSResolverNode");
+ var resolver = documentCreateNSResolver(node);
+
+ // check prefix in parents
+ expect(resolver.lookupNamespaceURI('ev')).to.equal('http://some-namespace.com/nss');
+
+ // check default prefix in parents
+ expect(resolver.lookupNamespaceURI('')).to.equal('http://www.w3.org/1999/xhtml');
+
+ resolver = documentCreateNSResolver(
+ helpers.getNextChildElementNode(helpers.getNextChildElementNode(node))
+ );
+ expect(resolver.lookupNamespaceURI('')).to.equal('http://www.w3.org/TR/REC-html40');
+ });
+});
diff --git a/test/spec/node-name-native.spec.js b/test/spec/node-name-native.spec.js
new file mode 100644
index 0000000..3f1962f
--- /dev/null
+++ b/test/spec/node-name-native.spec.js
@@ -0,0 +1,181 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, DOMException, XPathException, documentEvaluate, documentCreateExpression, documentCreateNSResolver, checkNodeResult, checkNodeResultNamespace, parseNamespacesFromAttributes, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+describe('node name for', function() {
+ var h;
+
+ before(function() {
+
+ h = {
+ filterElementNodes: function(nodes) {
+ var elementNodes = [],
+ i;
+
+ for (i = 0; i < nodes.length; i++) {
+ if (nodes[i].nodeType == 1) {
+ elementNodes.push(nodes[i]);
+ }
+ }
+
+ return elementNodes;
+ }
+ };
+ });
+
+ it('any attribute', function() {
+ var node = doc.getElementById('StepNodeTestCaseNameTestAttribute');
+ checkNodeResult("attribute::*", node, filterAttributes(node.attributes));
+ });
+
+ it('any namespace', function() {
+ var node = doc.getElementById('StepNodeTestCaseNameTestNamespace'),
+ namespaces = [];
+
+ namespaces.push(['', 'http://www.w3.org/1999/xhtml']);
+ parseNamespacesFromAttributes(node.attributes, namespaces);
+ namespaces.push(['ev', 'http://some-namespace.com/nss']);
+ namespaces.push(['xml', 'http://www.w3.org/XML/1998/namespace']);
+
+ checkNodeResultNamespace("namespace::*", node, namespaces);
+ });
+
+ it('any child', function() {
+ var node = doc.getElementById('StepNodeTestCaseNameTestChild');
+ checkNodeResult("child::*", node, h.filterElementNodes(node.childNodes));
+ });
+
+ it('any ancestor-or-self', function() {
+ var node = doc.getElementById('StepNodeTestCaseNameTestAttribute'),
+ attributes = filterAttributes(node.attributes);
+
+ checkNodeResult("ancestor-or-self::*", attributes[0], [
+ doc.documentElement,
+ doc.querySelector('body'),
+ doc.getElementById('StepNodeTestCaseNameTest'),
+ doc.getElementById('StepNodeTestCaseNameTestAttribute')
+ ]);
+ });
+
+ it('any attribute with specific namespace', function() {
+ var node = doc.getElementById('StepNodeTestCaseNameTestAttribute'),
+ attributes = filterAttributes(node.attributes),
+ i,
+ name;
+
+ for (i = attributes.length - 1; i >= 0; i--) {
+ name = attributes[i].nodeName.split(':');
+
+ if (name[0] != 'ev') {
+ attributes.splice(i, 1);
+ }
+ }
+
+ expect(attributes).to.have.length(2);
+
+ checkNodeResult("attribute::ev:*", node, attributes, helpers.xhtmlResolver);
+ });
+
+ it('any namespace with a specific namespace (?)', function() {
+ var node = doc.getElementById('StepNodeTestCaseNameTestNamespace');
+ checkNodeResultNamespace("namespace::ns2:*", node, [], helpers.xhtmlResolver);
+ });
+
+ it('any child with specific namespace', function() {
+ var node = doc.getElementById('StepNodeTestCaseNameTestChild'),
+ nodesFinal = [];
+
+ nodesFinal = [
+ node.childNodes[0],
+ node.childNodes[1],
+ node.childNodes[2]
+ ];
+
+ checkNodeResult("child::ns2:*", node, nodesFinal, helpers.xhtmlResolver);
+ });
+
+ it('attribute with a specific name and namespace', function() {
+ var node = doc.getElementById('StepNodeTestCaseNameTestAttribute'),
+ attributes = filterAttributes(node.attributes),
+ i,
+ name;
+
+ for (i = attributes.length - 1; i >= 0; i--) {
+ name = attributes[i].nodeName.split(':');
+ if (name[0] != 'ev' || name[1] != 'attrib2') {
+ attributes.splice(i, 1);
+ }
+ }
+
+ expect(attributes).to.have.length(1);
+
+ checkNodeResult("attribute::ev:attrib2", node, attributes, helpers.xhtmlResolver);
+ });
+
+ it('specific namespace with a specific namespace', function() {
+ var node = doc.getElementById('StepNodeTestCaseNameTestNamespace');
+ checkNodeResultNamespace("namespace::ns2:ns2", node, [], helpers.xhtmlResolver);
+ });
+
+ it('specific child name with a specific namespace', function() {
+ var node = doc.getElementById('StepNodeTestCaseNameTestChild'),
+ nodesFinal = [];
+
+ nodesFinal = [
+ node.childNodes[0],
+ node.childNodes[1]
+ ];
+
+ checkNodeResult("child::ns2:div", node, nodesFinal, helpers.xhtmlResolver);
+ });
+
+ it('attribute with a specific name', function() {
+ var node = doc.getElementById('StepNodeTestCaseNameTestAttribute'),
+ attributes = filterAttributes(node.attributes),
+ i,
+ name;
+
+ for (i = attributes.length - 1; i >= 0; i--) {
+ name = attributes[i].nodeName.split(':');
+
+ if (name[0] != 'attrib3') {
+ attributes.splice(i, 1);
+ }
+ }
+
+ expect(attributes).to.have.length(1);
+
+ checkNodeResult("attribute::attrib3", node, attributes, helpers.xhtmlResolver);
+ });
+
+ it('namespace with specific name', function() {
+ var node = doc.getElementById('StepNodeTestCaseNameTestNamespace');
+
+ checkNodeResultNamespace("namespace::ns2", node, [
+ [
+ 'ns2',
+ 'http://asdf/'
+ ]
+ ], helpers.xhtmlResolver);
+ });
+
+ it('child with specific (namespaced) name', function() {
+ checkNodeResult("child::html", doc, [], helpers.xhtmlResolver);
+ checkNodeResult("child::xhtml:html", doc, [doc.documentElement], helpers.xhtmlResolver);
+ });
+
+ it('ancestor with specific name and namespace', function() {
+ checkNodeResult("ancestor::xhtml:div", doc.getElementById('StepNodeTestCaseNameTest3'), [
+ doc.getElementById('StepNodeTestCaseNameTest'),
+ doc.getElementById('StepNodeTestCaseNameTest1'),
+ doc.getElementById('StepNodeTestCaseNameTest2')
+ ], helpers.xhtmlResolver);
+ });
+
+ it('ancestor with specific name without a default namespace', function() {
+ checkNodeResult("ancestor::div", doc.getElementById('StepNodeTestCaseNameTestNoNamespace').firstChild.firstChild.firstChild, [
+ doc.getElementById('StepNodeTestCaseNameTestNoNamespace').firstChild,
+ doc.getElementById('StepNodeTestCaseNameTestNoNamespace').firstChild.firstChild
+ ], helpers.xhtmlResolver);
+ });
+
+});
diff --git a/test/spec/node-type-native.spec.js b/test/spec/node-type-native.spec.js
new file mode 100644
index 0000000..4f22f10
--- /dev/null
+++ b/test/spec/node-type-native.spec.js
@@ -0,0 +1,78 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, DOMException, XPathException, documentEvaluate, documentCreateExpression, documentCreateNSResolver, checkNodeResult, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+describe('node-type', function() {
+
+ it('"node" is supported', function() {
+ var node = doc.getElementById('StepNodeTestNodeTypeCase');
+ checkNodeResult("child::node()", node, node.childNodes);
+ });
+
+ it('"text" is supported', function() {
+ var node = doc.getElementById('StepNodeTestNodeTypeCase'),
+ nodes = [],
+ i;
+
+ for (i = 0; i < node.childNodes.length; i++) {
+ switch (node.childNodes[i].nodeType) {
+ case 3: // text
+ case 4: // cdata
+ nodes.push(node.childNodes[i]);
+ break;
+ }
+ }
+
+ checkNodeResult("child::text()", node, nodes);
+ });
+
+ it('"comment" is supported', function() {
+ var node = doc.getElementById('StepNodeTestNodeTypeCase'),
+ nodes = [],
+ i;
+
+ for (i = 0; i < node.childNodes.length; i++) {
+ switch (node.childNodes[i].nodeType) {
+ case 8: // comment
+ nodes.push(node.childNodes[i]);
+ break;
+ }
+ }
+
+ checkNodeResult("child::comment()", node, nodes);
+ });
+
+ it('"processing-instruction any" is supported', function() {
+ var node = doc.getElementById('StepNodeTestNodeTypeCase'),
+ nodes = [],
+ i;
+
+ for (i = 0; i < node.childNodes.length; i++) {
+ switch (node.childNodes[i].nodeType) {
+ case 7: // processing instruction
+ nodes.push(node.childNodes[i]);
+ break;
+ }
+ }
+
+ checkNodeResult("child::processing-instruction()", node, nodes);
+ });
+
+ it('"processing-instruction specific" is supported', function() {
+ var node = doc.getElementById('StepNodeTestNodeTypeCase'),
+ nodes = [],
+ i;
+
+ for (i = 0; i < node.childNodes.length; i++) {
+ switch (node.childNodes[i].nodeType) {
+ case 7: // processing instruction
+ if (node.childNodes[i].nodeName == 'custom-process-instruct') {
+ nodes.push(node.childNodes[i]);
+ }
+ break;
+ }
+ }
+
+ checkNodeResult("child::processing-instruction('custom-process-instruct')", node, nodes);
+ });
+
+});
diff --git a/test/spec/nodeset-functions-native.spec.js b/test/spec/nodeset-functions-native.spec.js
new file mode 100644
index 0000000..8ed542d
--- /dev/null
+++ b/test/spec/nodeset-functions-native.spec.js
@@ -0,0 +1,286 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, documentEvaluate, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+describe('native nodeset functions', function() {
+
+ it('last()', function() {
+ [
+ ["last()", 1],
+ ["xhtml:p[last()]", 4],
+ ["xhtml:p[last()-last()+1]", 1]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc.getElementById('testFunctionNodeset2'), helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[1]);
+ });
+ });
+
+ it('last() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("last(1)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('position()', function() {
+ [
+ ["position()", 1],
+ ["*[position()=last()]", 4],
+ ["*[position()=2]", 2],
+ ["xhtml:p[position()=2]", 2]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc.getElementById('testFunctionNodeset2'), helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[1]);
+
+ });
+
+ [
+ ["*[position()=-1]", ""]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc.getElementById('testFunctionNodeset2'), helpers.xhtmlResolver, win.XPathResult.STRING_TYPE, null);
+ expect(result.stringValue).to.equal(t[1]);
+ });
+ });
+
+ it('position() fails when too many args are provided', function() {
+ var test = function() {
+ documentEvaluate("position(1)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('count()', function() {
+ [
+ ["count(xhtml:p)", 4],
+ ["count(p)", 0]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc.getElementById('testFunctionNodeset2'), helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[1]);
+ });
+
+ /*
+ [
+ ["count(.)", doc.getElementsByName('##########'),1]
+ ].forEach(function(t){
+ var result = documentEvaluate(t[0], t[1], helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[2]);
+ });
+ */
+ });
+
+ it('count() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("count(1, 2)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('count() fails when too few arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("count()", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('count() fails when incorrect argument type is provided', function() {
+ var test = function() {
+ documentEvaluate("count(1)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('local-name()', function() {
+ var result, input, i, node,
+ nodeWithAttributes = doc.getElementById('testFunctionNodesetAttribute'),
+ nodeAttributes = filterAttributes(nodeWithAttributes.attributes),
+ nodeAttributesIndex;
+
+ for (i = 0; i < nodeAttributes.length; i++) {
+ if (nodeAttributes[i].nodeName == 'ev:class') {
+ nodeAttributesIndex = i;
+ break;
+ }
+ }
+
+ input = [
+ ["local-name(/htmlnot)", doc, ""], // empty
+ ["local-name()", doc, ""], // document
+ ["local-name()", doc.documentElement, "html"], // element
+ ["local-name(self::node())", doc.getElementById('testFunctionNodesetElement'), "div"], // element
+ ["local-name()", doc.getElementById('testFunctionNodesetElement'), "div"], // element
+ ["local-name()", doc.getElementById('testFunctionNodesetElementPrefix').firstChild, "div2"], // element
+ ["local-name(node())", doc.getElementById('testFunctionNodesetElementNested'), "span"], // element nested
+ ["local-name(self::node())", doc.getElementById('testFunctionNodesetElementNested'), "div"], // element nested
+ ["local-name()", doc.getElementById('testFunctionNodesetComment').firstChild, ""], // comment
+ ["local-name()", doc.getElementById('testFunctionNodesetText').firstChild, ""], // text
+ ["local-name(attribute::node())", nodeWithAttributes, nodeAttributes[0].nodeName], // attribute
+ ["local-name(attribute::node()[" + (nodeAttributesIndex + 1) + "])", nodeWithAttributes, 'class'] // attribute
+ ];
+
+ // Processing Instruction
+ node = doc.getElementById('testFunctionNodesetProcessingInstruction').firstChild;
+ if (node && node.nodeType == 7) {
+ input.push(["local-name()", node, 'xml-stylesheet']);
+ }
+
+ // CDATASection
+ node = doc.getElementById('testFunctionNodesetCData').firstChild;
+ if (node && node.nodeType == 4) {
+ input.push(["local-name()", node, '']);
+ }
+
+ for (i = 0; i < input.length; i++) {
+ result = documentEvaluate(input[i][0], input[i][1], null, win.XPathResult.STRING_TYPE, null);
+ expect(result.stringValue.toLowerCase()).to.equal(input[i][2]);
+ }
+ });
+
+ it('local-name() with namespace', function() {
+ var nodeWithAttributes = doc.getElementById('testFunctionNodesetAttribute');
+
+ [
+ ["local-name(namespace::node())", doc.getElementById('testFunctionNodesetNamespace'), ""],
+ ["local-name(namespace::node()[2])", doc.getElementById('testFunctionNodesetNamespace'), "asdf"]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], t[1], null, win.XPathResult.STRING_TYPE, null);
+ expect(result.stringValue.toLowerCase()).to.equal(t[2]);
+ });
+ });
+
+ it('local-name() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("local-name(1, 2)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('local-name() fails when the wrong type argument is provided', function() {
+ var test = function() {
+ documentEvaluate("local-name(1)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('namespace-uri()', function() {
+ var result, input, i, node,
+ nodeWithAttributes = doc.getElementById('testFunctionNodesetAttribute'),
+ nodeAttributes = filterAttributes(nodeWithAttributes.attributes),
+ nodeAttributesIndex;
+
+ for (i = 0; i < nodeAttributes.length; i++) {
+ if (nodeAttributes[i].nodeName == 'ev:class') {
+ nodeAttributesIndex = i;
+ break;
+ }
+ }
+
+ input = [
+ ["namespace-uri(/htmlnot)", doc, ""], // empty
+ ["namespace-uri()", doc, ""], // document
+ ["namespace-uri()", doc.documentElement, "http://www.w3.org/1999/xhtml"], // element
+ ["namespace-uri(self::node())", doc.getElementById('testFunctionNodesetElement'), "http://www.w3.org/1999/xhtml"], // element
+ ["namespace-uri()", doc.getElementById('testFunctionNodesetElement'), "http://www.w3.org/1999/xhtml"], // element
+ ["namespace-uri(node())", doc.getElementById('testFunctionNodesetElementNested'), "http://www.w3.org/1999/xhtml"], // element nested
+ ["namespace-uri(self::node())", doc.getElementById('testFunctionNodesetElementNested'), "http://www.w3.org/1999/xhtml"], // element nested
+ ["namespace-uri()", doc.getElementById('testFunctionNodesetElementPrefix').firstChild, "http://some-namespace.com/nss"], // element
+ ["namespace-uri()", doc.getElementById('testFunctionNodesetComment').firstChild, ""], // comment
+ ["namespace-uri()", doc.getElementById('testFunctionNodesetText').firstChild, ""], // text
+ ["namespace-uri(attribute::node())", nodeWithAttributes, ''], // attribute
+ ["namespace-uri(attribute::node()[" + (nodeAttributesIndex + 1) + "])", nodeWithAttributes, 'http://some-namespace.com/nss'], // attribute
+ ["namespace-uri(namespace::node())", doc.getElementById('testFunctionNodesetNamespace'), ""], // namespace
+ ["namespace-uri(namespace::node()[2])", doc.getElementById('testFunctionNodesetNamespace'), ""] // namespace
+ ];
+
+ // Processing Instruction
+ node = doc.getElementById('testFunctionNodesetProcessingInstruction').firstChild;
+ if (node && node.nodeType == 7) {
+ input.push(["namespace-uri()", node, '']);
+ }
+
+ // CDATASection
+ node = doc.getElementById('testFunctionNodesetCData').firstChild;
+ if (node && node.nodeType == 4) {
+ input.push(["namespace-uri()", node, '']);
+ }
+
+ for (i = 0; i < input.length; i++) {
+ result = documentEvaluate(input[i][0], input[i][1], null, win.XPathResult.STRING_TYPE, null);
+ expect(result.stringValue).to.equal(input[i][2]);
+ }
+ });
+
+ it('namespace-uri() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("namespace-uri(1, 2)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('namespace-uri() fails when wrong type of argument is provided', function() {
+ var test = function() {
+ documentEvaluate("namespace-uri(1)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('name()', function() {
+ var result, input, i, node,
+ nodeWithAttributes = doc.getElementById('testFunctionNodesetAttribute'),
+ nodeAttributes = filterAttributes(nodeWithAttributes.attributes),
+ nodeAttributesIndex;
+
+ for (i = 0; i < nodeAttributes.length; i++) {
+ if (nodeAttributes[i].nodeName == 'ev:class') {
+ nodeAttributesIndex = i;
+ break;
+ }
+ }
+
+ input = [
+ ["name(/htmlnot)", doc, ""], // empty
+ ["name()", doc, ""], // document
+ ["name()", doc.documentElement, "html"], // element
+ ["name(self::node())", doc.getElementById('testFunctionNodesetElement'), "div"], // element
+ ["name()", doc.getElementById('testFunctionNodesetElement'), "div"], // element
+ ["name(node())", doc.getElementById('testFunctionNodesetElementNested'), "span"], // element nested
+ ["name(self::node())", doc.getElementById('testFunctionNodesetElementNested'), "div"], // element nested
+ ["name()", doc.getElementById('testFunctionNodesetElementPrefix').firstChild, "ev:div2"], // element
+ ["name()", doc.getElementById('testFunctionNodesetComment').firstChild, ""], // comment
+ ["name()", doc.getElementById('testFunctionNodesetText').firstChild, ""], // text
+ ["name(attribute::node())", nodeWithAttributes, nodeAttributes[0].nodeName], // attribute
+ ["name(attribute::node()[" + (nodeAttributesIndex + 1) + "])", nodeWithAttributes, 'ev:class'], // attribute
+ ["name(namespace::node())", doc.getElementById('testFunctionNodesetNamespace'), ""], // namespace
+ ["name(namespace::node()[2])", doc.getElementById('testFunctionNodesetNamespace'), "asdf"] // namespace
+ ];
+
+ // Processing Instruction
+ node = doc.getElementById('testFunctionNodesetProcessingInstruction').firstChild;
+ if (node && node.nodeType == 7) {
+ input.push(["name()", node, 'xml-stylesheet']);
+ }
+
+ // CDATASection
+ node = doc.getElementById('testFunctionNodesetCData').firstChild;
+ if (node && node.nodeType == 4) {
+ input.push(["name()", node, '']);
+ }
+
+ for (i = 0; i < input.length; i++) {
+ result = documentEvaluate(input[i][0], input[i][1], null, win.XPathResult.STRING_TYPE, null);
+ expect(result.stringValue).to.equal(input[i][2]);
+ }
+ });
+
+ it('name() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("name(1, 2)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('name() fails when the wrong argument type is provided', function() {
+ var test = function() {
+ documentEvaluate("name(1)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+});
diff --git a/test/spec/nodeset-id-function-native.spec.js b/test/spec/nodeset-id-function-native.spec.js
new file mode 100644
index 0000000..e32cda0
--- /dev/null
+++ b/test/spec/nodeset-id-function-native.spec.js
@@ -0,0 +1,100 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, DOMException, XPathException, documentEvaluate, documentCreateExpression, documentCreateNSResolver, checkNodeResult, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+// TODO: move these to nodeset-native.spec.js? Why are these separate?
+
+describe('nodeset id() function', function() {
+
+ it('works for a simple case', function() {
+ var node = doc.getElementById('FunctionNodesetIdCaseSimple');
+ expect(node).to.be.an('object');
+
+ checkNodeResult("id('FunctionNodesetIdCaseSimple')", doc, [
+ node
+ ]);
+ });
+
+ it('works if ID is provided in duplicate', function() {
+ var node = doc.getElementById('FunctionNodesetIdCaseSimple');
+ expect(node).to.be.an('object');
+
+ checkNodeResult("id('FunctionNodesetIdCaseSimple FunctionNodesetIdCaseSimple')", doc, [
+ node
+ ]);
+ });
+
+ it('returns empty result for non-existing ID', function() {
+ checkNodeResult("id('FunctionNodesetIdCaseSimpleDoesNotExist')", doc, []);
+ });
+
+ it('returns empty result if the default namespace for the node is empty', function() {
+ var node = doc.getElementById('FunctionNodesetIdCaseNoDefaultNamespaceContainer').firstChild;
+ expect(node).to.be.an('object');
+
+ checkNodeResult("id('FunctionNodesetIdCaseNoDefaultNamespace')", doc, []);
+ });
+
+ it('works if the default namespace for the node is the XHTML namespace', function() {
+ var node = doc.getElementById('FunctionNodesetIdCaseXhtmlDefaultNamespaceContainer').firstChild;
+ expect(node).to.be.an('object');
+
+ checkNodeResult("id('FunctionNodesetIdCaseXhtmlDefaultNamespace')", doc, [
+ node
+ ]);
+ });
+
+ it('works if the namespace of the id attribute is the XHTML namespace', function() {
+ var node = doc.getElementById('FunctionNodesetIdCaseXhtmlNamespaceContainer').firstChild;
+ expect(node).to.be.an('object');
+
+ checkNodeResult("id('FunctionNodesetIdCaseXhtmlNamespace')", doc, [
+ node
+ ]);
+ });
+
+ it('works if the namespace of the id attribute is defined in the parent container', function() {
+ var node = doc.getElementById('FunctionNodesetIdCaseXhtmlNamespaceParentContainer').firstChild;
+ expect(node).to.be.an('object');
+
+ checkNodeResult("id('FunctionNodesetIdCaseXhtmlNamespaceParent')", doc, [
+ node
+ ]);
+ });
+
+ it('works if the id attribute has the xml namespace alias', function() {
+ var node = doc.getElementById('FunctionNodesetIdXmlNamespaceContainer').firstChild;
+ expect(node).to.be.an('object');
+
+ checkNodeResult("id('FunctionNodesetIdXmlNamespace')", doc, [
+ node
+ ]);
+ });
+
+ it('works if multiple space-separated IDs are provided as the parameter', function() {
+ checkNodeResult("id('FunctionNodesetIdCaseMultiple1 FunctionNodesetIdCaseMultiple2 FunctionNodesetIdCaseMultiple3')", doc, [
+ doc.getElementById('FunctionNodesetIdCaseMultiple1'),
+ doc.getElementById('FunctionNodesetIdCaseMultiple2'),
+ doc.getElementById('FunctionNodesetIdCaseMultiple3')
+ ]);
+ });
+
+ it('works if multiple space/newline/table-separated IDs are provided as the parameter', function() {
+ checkNodeResult("id(' FunctionNodesetIdCaseMultiple1 sss FunctionNodesetIdCaseMultiple2\r\n\tFunctionNodesetIdCaseMultiple3\t')", doc, [
+ doc.getElementById('FunctionNodesetIdCaseMultiple1'),
+ doc.getElementById('FunctionNodesetIdCaseMultiple2'),
+ doc.getElementById('FunctionNodesetIdCaseMultiple3')
+ ]);
+ });
+
+ it('works if a nodeset is provided as the argument (by using the content of the nodeset)', function() {
+ checkNodeResult("id(.)", doc.getElementById('FunctionNodesetIdCaseNodeset'), []);
+
+ // this test is tricky, the argument is the CONTENT of the FunctionNodesetIdCaseNodeset element!
+ checkNodeResult("id(child::*)", doc.getElementById('FunctionNodesetIdCaseNodeset'), [
+ doc.getElementById('FunctionNodesetIdCaseMultiple1'),
+ doc.getElementById('FunctionNodesetIdCaseMultiple2'),
+ doc.getElementById('FunctionNodesetIdCaseMultiple3'),
+ doc.getElementById('FunctionNodesetIdCaseMultiple4')
+ ]);
+ });
+});
diff --git a/test/spec/number-functions-native.spec.js b/test/spec/number-functions-native.spec.js
new file mode 100644
index 0000000..53a794e
--- /dev/null
+++ b/test/spec/number-functions-native.spec.js
@@ -0,0 +1,211 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, documentEvaluate, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+describe('native number functions', function() {
+
+
+ describe('number() conversion of convertible numbers, strings, booleans', function() {
+ var test = function(t) {
+ it('works for ' + t[0], function() {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[1]);
+ });
+ };
+
+ // of numbers
+ [
+ ['number(-1.0)', -1],
+ ['number(1)', 1],
+ ['number(0.199999)', 0.199999],
+ ['number(-0.199999)', -0.199999],
+ ['number(- 0.199999)', -0.199999],
+ ['number(0.0)', 0],
+ ['number(.0)', 0],
+ ['number(0.)', 0]
+ ].forEach(test);
+
+ // of booleans
+ [
+ ['number(true())', 1],
+ ['number(false())', 0]
+ ].forEach(test);
+
+ // of strings
+ [
+ ["number('-1.0')", -1],
+ ["number('1')", 1],
+ ["number('0.199999')", 0.199999],
+ ["number('-0.9991')", -0.9991],
+ ["number('0.0')", 0],
+ ["number('.0')", 0],
+ ["number('.112')", 0.112],
+ ["number('0.')", 0],
+ ["number(' 1.1')", 1.1],
+ ["number('1.1 ')", 1.1],
+ ["number('1.1 \n ')", 1.1],
+ ["number(' 1.1 \n\r\n ')", 1.1]
+ ].forEach(test);
+ });
+
+ it('number() conversions returns NaN if not convertible', function() {
+ [
+ ["number('asdf')", NaN],
+ ["number('1asdf')", NaN],
+ ["number('1.1sd')", NaN],
+ ["number('.1sd')", NaN],
+ ["number(' . ')", NaN]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.be.a('number');
+ expect(result.numberValue).to.deep.equal(NaN);
+ });
+ });
+
+ it('number() conversion of nodesets', function() {
+ [
+ ["number(self::node())", doc.getElementById('FunctionNumberCaseNumber'), 123],
+ ["number(*)", doc.getElementById('FunctionNumberCaseNumberMultiple'), -10],
+ ["number()", doc.getElementById('FunctionNumberCaseNumber'), 123]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], t[1], null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[2]);
+ });
+
+ [
+ ["number()", doc.getElementById('FunctionNumberCaseNotNumber')]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], t[1], null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.be.a('number');
+ expect(result.numberValue).to.deep.equal(NaN);
+ });
+ });
+
+ it('number() conversion fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("number(1, 2)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('sum()', function() {
+ [
+ ["sum(self::*)", doc.getElementById('FunctionNumberCaseNumber'), 123],
+ ["sum(*)", doc.getElementById('FunctionNumberCaseNumberMultiple'), 100]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], t[1], null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[2]);
+ });
+
+ [
+ ["sum(node())", doc.getElementById('FunctionNumberCaseNotNumberMultiple')],
+ ["sum(*)", doc.getElementById('FunctionSumCaseJavarosa')]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], t[1], null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.be.a('number');
+ expect(result.numberValue).to.deep.equal(NaN);
+ });
+ });
+
+ it('sum() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("sum(1, 2)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('sum() fails when too few arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("sum()", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('floor()', function() {
+ [
+ ["floor(-1.55)", -2],
+ ["floor(2.44)", 2],
+ ["floor(0.001)", 0],
+ ["floor(1.5)", 1],
+ ["floor(5)", 5],
+ ["floor(1.00)", 1],
+ ["floor(-1.05)", -2]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[1]);
+ });
+ });
+
+ it('floor() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("floor(1, 2)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('floor failes when too few arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("floor()", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('ceiling()', function() {
+ [
+ ["ceiling(-1.55)", -1],
+ ["ceiling(2.44)", 3],
+ ["ceiling(0.001)", 1],
+ ["ceiling(1.5)", 2],
+ ["ceiling(5)", 5],
+ ["ceiling(1.00)", 1],
+ ["ceiling(-1.05)", -1]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[1]);
+ });
+ });
+
+ it('ceiling() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("ceiling(1, 2)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('ceiling() fails when not enough arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("ceiling()", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('round()', function() {
+ [
+ ["round(-1.55)", -2],
+ ["round(2.44)", 2],
+ ["round(0.001)", 0],
+ ["round(1.5)", 2],
+ ["round(5)", 5],
+ ["round(1.00)", 1],
+ ["round(-1.05)", -1]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[1]);
+ });
+ });
+
+ // behaviour changed in OpenRosa
+ xit('round() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("round(1, 2)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('round() fails when too few arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("round()", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+});
diff --git a/test/spec/number-operators-native.spec.js b/test/spec/number-operators-native.spec.js
new file mode 100644
index 0000000..382b602
--- /dev/null
+++ b/test/spec/number-operators-native.spec.js
@@ -0,0 +1,280 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, documentEvaluate, documentCreateNSResolver, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+describe('number operators', function() {
+
+ it('+ works', function() {
+ [
+ ["1+1", 2],
+ ["0+1", 1],
+ ["0+0", 0],
+ ["0+-0", 0],
+ ["-1 + 1", 0],
+ ["-1 +-1", -2],
+ ["1.05+2.05", 3.0999999999999996],
+ [".5 \n +.5+.3", 1.3],
+ ["5+4+1+-1+-4", 5],
+ ["'1'+'1'", 2],
+ [".55+ 0.56", 1.11],
+ ["1.0+1.0", 2],
+ ["true()+true()", 2],
+ ["false()+1", 1],
+ ["(1 div 0) + 1", Number.POSITIVE_INFINITY],
+ ["(-1 div 0) + 1", Number.NEGATIVE_INFINITY],
+ ["1 + (-1 div 0)", Number.NEGATIVE_INFINITY]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[1]);
+ });
+
+ [
+ ["number('a') + 0"],
+ ["0 + number('a')"]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.be.a('number');
+ expect(result.numberValue).to.deep.equal(NaN);
+ });
+ });
+
+ it('- without spacing works', function() {
+ var result = documentEvaluate("1-1", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(0);
+ });
+
+ it('- with spacing works', function() {
+ var result = documentEvaluate("1 - 1", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(0);
+ });
+
+ it('- with combo with/without spacing 1 works', function() {
+ var result = documentEvaluate("1 -1", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(0);
+ });
+
+ it('- with combo with/without spacing 2 works', function() {
+ var result = documentEvaluate("1- 1", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(0);
+
+ });
+
+ it('- with string without spacing BEFORE - fails', function() {
+ var test = function() {
+ documentEvaluate("asdf- asdf", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw();
+ });
+
+ it('- with string without spacing AFTER - fails ', function() {
+ var result = documentEvaluate("asdf -asdf", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.be.a('number');
+ expect(result.numberValue).to.deep.equal(NaN);
+ });
+
+ it('- with strings', function() {
+ var result = documentEvaluate("asdf - asdf", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.be.a('number');
+ expect(result.numberValue).to.deep.equal(NaN);
+ });
+
+ it('- works as expected', function() {
+ [
+ ["1-1", 0],
+ ["0 -1", -1],
+ ["0-0", 0],
+ ["0- -0", 0],
+ ["-1-1", -2],
+ ["-1 --1", 0],
+ ["1.05-2.05", -0.9999999999999998],
+ [".5-.5-.3", -0.3],
+ ["5- 4-1--1--4", 5],
+ ["'1'-'1'", 0],
+ [".55 - 0.56", -0.010000000000000009],
+ ["1.0-1.0", 0],
+ ["true() \n\r\t -true()", 0],
+ ["false()-1", -1],
+ ["(1 div 0) - 1", Number.POSITIVE_INFINITY],
+ ["(-1 div 0) - 1", Number.NEGATIVE_INFINITY]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[1]);
+ });
+
+ [
+ ["number('a') - 0"],
+ ["0 - number('a')"]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.be.a('number');
+ expect(result.numberValue).to.deep.equal(NaN);
+ });
+ });
+
+ it('mod without spacing works', function() {
+ var result = documentEvaluate("1mod1", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(0);
+ });
+
+ it('mod without spacing AFTER mod works', function() {
+ var result = documentEvaluate("1 mod1", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(0);
+ });
+
+ it('mod without spacing BEFORE mod works', function() {
+ var result = documentEvaluate("1mod 1", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(0);
+ });
+
+ it('mod with numbers-as-string works', function() {
+ var result = documentEvaluate("'1'mod'1'", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(0);
+ });
+
+ it('mod without spacing after mod and a string fails', function() {
+ var test = function() {
+ documentEvaluate("'1' mod/html'", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw();
+ });
+
+ it('mod without spacing before mod and a string works', function() {
+ var result = documentEvaluate("'1'mod '1'", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(0);
+ });
+
+ it('mod works as expected', function() {
+ [
+ ["5 mod 2", 1],
+ ["5 mod -2 ", 1],
+ ["-5 mod 2", -1],
+ [" -5 mod -2 ", -1],
+ ["5 mod 1.5", 0.5],
+ ["6.4 mod 2.1", 0.10000000000000009],
+ ["5.3 mod 1.1", 0.8999999999999995],
+ ["-0.4 mod .2", 0],
+ ["1 mod -1", 0],
+ ["0 mod 1", 0],
+ ["10 mod (1 div 0)", 10],
+ ["-10 mod (-1 div 0)", -10]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[1]);
+ });
+
+ [
+ ["0 mod 0"],
+ ["1 mod 0"],
+ ["(1 div 0) mod 1"],
+ ["(-1 div 0) mod 1"]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.be.a('number');
+ expect(result.numberValue).to.deep.equal(NaN);
+ });
+ });
+
+ it('div without spacing', function() {
+ var result = documentEvaluate("1div1", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(1);
+ });
+
+ it('div without spacing AFTER div', function() {
+ var result = documentEvaluate("1 div1", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(1);
+ });
+
+ it('div without spacing BEFORE div', function() {
+ var result = documentEvaluate("1div 1", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(1);
+ });
+
+ it('div without spacing and numbers-as-string', function() {
+ var result = documentEvaluate("'1'div'1'", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(1);
+ });
+
+ it('div without spacing AFTER div and number-as-string', function() {
+ var result = documentEvaluate("'1' div'1'", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(1);
+ });
+
+ it('div without spacing BEFORE div and number-as-string', function() {
+ var result = documentEvaluate("'1'div '1'", doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(1);
+ });
+
+ it('div works as expected', function() {
+ [
+ ["1div 1", 1],
+ ["0 div 1", 0],
+ ["-1 div 1", -1],
+ ["-1 div 1", -1],
+ ["1.05 div 2.05", 0.5121951219512195],
+ [".5 div .5 div .3", 3.3333333333333335],
+ ["5 div 4 div 1 div -1 div -4", 0.3125],
+ ["'1' div '1'", 1],
+ [".55 div 0.56", 0.9821428571428571],
+ ["1.0 div 1.0", 1],
+ ["true() div true()", 1],
+ ["false() div 1", 0],
+ ["1 div 0", Number.POSITIVE_INFINITY],
+ ["-1 div 0", Number.NEGATIVE_INFINITY]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[1]);
+ });
+
+ [
+ ["0 div 0"],
+ ["0 div -0"],
+ ["number('a') div 0"]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.be.a('number');
+ expect(result.numberValue).to.deep.equal(NaN);
+ });
+ });
+
+ it('* works as expected', function() {
+ [
+ ["1*1", 1],
+ ["9 * 2", 18],
+ ["9 * -1", -9],
+ ["-10 *-11", 110],
+ ["-1 * 1", -1],
+ ["0*0", 0],
+ ["0*1", 0],
+ ["-1*0", 0],
+ ["-15.*1.5", -22.5],
+ ["1.5 * 3", 4.5],
+ ["(1 div 0) * 1", Number.POSITIVE_INFINITY],
+ ["(-1 div 0) * -1", Number.POSITIVE_INFINITY],
+ ["(1 div 0) * -1", Number.NEGATIVE_INFINITY]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[1]);
+ });
+
+ [
+ ["number('a') * 0"]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.be.a('number');
+ expect(result.numberValue).to.deep.equal(NaN);
+ });
+ });
+
+ it('*,+,-,mod,div precendence rules are applied correctly', function() {
+ [
+ ["1+2*3", 7],
+ ["2*3+1", 7],
+ ["1-10 mod 3 div 3", 0.6666666666666667],
+ ["4-3*4+5-1", -4],
+ ["(4-3)*4+5-1", 8],
+ ["8 div 2 + 4", 8]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[1]);
+ });
+ });
+});
diff --git a/test/spec/path-native.spec.js b/test/spec/path-native.spec.js
new file mode 100644
index 0000000..4304c04
--- /dev/null
+++ b/test/spec/path-native.spec.js
@@ -0,0 +1,118 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, DOMException, XPathException, documentEvaluate, documentCreateExpression, documentCreateNSResolver, checkNodeResult, checkNodeResultNamespace, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+
+describe('location path', function() {
+ var h;
+
+ before(function() {
+ h = {
+ oneNamespaceNode: function(node) {
+ var result, item;
+
+ result = documentEvaluate("namespace::node()", node, null, win.XPathResult.ANY_UNORDERED_NODE_TYPE, null);
+ item = result.singleNodeValue;
+ expect(item).to.not.equal(null);
+ expect(item.nodeType).to.equal(13);
+
+ return item;
+ }
+ };
+ });
+
+ it('root', function() {
+ var i, node,
+ input = [
+ [doc, [doc]], // Document
+ [doc.documentElement, [doc]], // Element
+ [doc.getElementById('LocationPathCase'), [doc]], // Element
+ [doc.getElementById('LocationPathCaseText').firstChild, [doc]], // Text
+ [doc.getElementById('LocationPathCaseComment').firstChild, [doc]], // Comment
+ [filterAttributes(doc.getElementById('LocationPathCaseAttribute').attributes)[0],
+ [doc]
+ ] // Attribute
+ ];
+
+ // ProcessingInstruction
+ node = doc.getElementById('LocationPathCaseProcessingInstruction').firstChild;
+ if (node && node.nodeType == 7) {
+ input.push([node, [doc]]);
+ }
+
+ // CDATASection
+ node = doc.getElementById('LocationPathCaseCData').firstChild;
+ if (node && node.nodeType == 4) {
+ input.push([node, [doc]]);
+ }
+
+ for (i = 0; i < input.length; i++) {
+ checkNodeResult("/", input[i][0], input[i][1]);
+ }
+ });
+
+ it('root namespace', function() {
+ var input = [h.oneNamespaceNode(doc.getElementById('LocationPathCaseNamespace')), [doc]]; // XPathNamespace
+ checkNodeResult("/", input[0], input[1]);
+ });
+
+ it('root node', function() {
+ checkNodeResult("/html", doc, [], helpers.xhtmlResolver);
+ checkNodeResult("/xhtml:html", doc, [doc.documentElement], helpers.xhtmlResolver);
+ checkNodeResult("/xhtml:html", doc.getElementById('LocationPathCase'), [doc.documentElement], helpers.xhtmlResolver);
+ checkNodeResult("/htmlnot", doc.getElementById('LocationPathCase'), [], helpers.xhtmlResolver);
+ });
+
+ it('root node node', function() {
+ checkNodeResult("/xhtml:html/xhtml:body", doc.getElementById('LocationPathCase'), [doc.querySelector('body')], helpers.xhtmlResolver);
+ });
+
+ it('node (node)', function() {
+ checkNodeResult("html", doc, [], helpers.xhtmlResolver);
+ checkNodeResult("xhtml:html", doc, [doc.documentElement], helpers.xhtmlResolver);
+ checkNodeResult("xhtml:html/xhtml:body", doc, [doc.querySelector('body')], helpers.xhtmlResolver);
+ });
+
+ xit('node attribute', function() {
+ var node = doc.getElementById('LocationPathCaseAttributeParent');
+
+ checkNodeResult("child::*/attribute::*", node, [
+ filterAttributes(node.childNodes[0].attributes)[0],
+ filterAttributes(node.childNodes[1].attributes)[0],
+ filterAttributes(node.childNodes[1].attributes)[1],
+ filterAttributes(node.childNodes[2].attributes)[0],
+ filterAttributes(node.childNodes[3].attributes)[0]
+ ], helpers.xhtmlResolver);
+ });
+
+ xit('node namespace', function() {
+ var node = doc.getElementById('LocationPathCaseNamespaceParent'); //
+
+ checkNodeResultNamespace("child::* /namespace::*", node, [
+ ['', 'http://asdss/'],
+ ['ev', 'http://some-namespace.com/nss'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace'],
+ ['', 'http://www.w3.org/1999/xhtml'],
+ ['ab', 'hello/world2'],
+ ['a2', 'hello/world'],
+ ['aa', 'http://saa/'],
+ ['ev', 'http://some-namespace.com/nss'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace'],
+ ['', 'http://www.w3.org/1999/xhtml'],
+ ['ev', 'http://some-namespace.com/nss'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace'],
+ ['', 'http://www.w3.org/1999/xhtml'],
+ ['aa', 'http://saa/'],
+ ['ev', 'http://some-namespace.com/nss'],
+ ['xml', 'http://www.w3.org/XML/1998/namespace']
+ ], helpers.xhtmlResolver);
+ });
+
+ it('duplicates handled correctly', function() {
+ checkNodeResult("ancestor-or-self::* /ancestor-or-self::*", doc.getElementById('LocationPathCaseDuplicates'), [
+ doc.documentElement,
+ doc.querySelector('body'),
+ doc.getElementById('LocationPathCase'),
+ doc.getElementById('LocationPathCaseDuplicates')
+ ], helpers.xhtmlResolver);
+ });
+});
diff --git a/test/spec/string-functions-native.spec.js b/test/spec/string-functions-native.spec.js
new file mode 100644
index 0000000..657b6e2
--- /dev/null
+++ b/test/spec/string-functions-native.spec.js
@@ -0,0 +1,383 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, documentEvaluate, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+describe('native string functions', function() {
+
+ describe('string() conversion of strings, numbers, booleans', function() {
+ var test = function(t) {
+ it('works for ' + t[0], function() {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.STRING_TYPE, null);
+ expect(result.stringValue).to.equal(t[1]);
+ });
+ };
+
+ // of strings
+ [
+ ["string('-1.0')", "-1.0"],
+ ["string('1')", "1"],
+ ["string(' \nhello \n\r')", " \nhello \n\r"],
+ ["string('')", ""],
+ ["string('As Df')", "As Df"]
+ ].forEach(test);
+
+ // of numbers
+ [
+ ["string(number('-1.0a'))", "NaN"],
+ ["string(0)", "0"],
+ ["string(-0)", "0"],
+ ["string(1 div 0)", "Infinity"],
+ ["string(-1 div 0)", "-Infinity"],
+ ["string(-123)", "-123"],
+ ["string(123)", "123"],
+ ["string(123.)", "123"],
+ ["string(123.0)", "123"],
+ ["string(.123)", "0.123"],
+ ["string(-0.1000)", "-0.1"],
+ ["string(1.1)", "1.1"],
+ ["string(-1.1)", "-1.1"]
+ ].forEach(test);
+
+ // of booleans
+ [
+ ["string(true())", "true"],
+ ["string(false())", "false"]
+ ].forEach(test);
+ });
+
+
+ it('string() conversion of nodesets', function() {
+ var result, input, i, node,
+ nodeWithAttributes = doc.getElementById('FunctionStringCaseStringNodesetAttribute');
+
+ input = [
+ ["string(/htmlnot)", doc, ""], // empty
+ ["string(self::node())", doc.getElementById('FunctionStringCaseStringNodesetElement'), "aaa"], // element
+ ["string()", doc.getElementById('FunctionStringCaseStringNodesetElement'), "aaa"], // element
+ ["string(node())", doc.getElementById('FunctionStringCaseStringNodesetElementNested'), "bbb"], // element nested
+ ["string(self::node())", doc.getElementById('FunctionStringCaseStringNodesetElementNested'), "bbbssscccddd"], // element nested
+ ["string()", doc.getElementById('FunctionStringCaseStringNodesetElementNested'), "bbbssscccddd"], // element nested
+ ["string()", doc.getElementById('FunctionStringCaseStringNodesetComment').firstChild, " hello world "], // comment
+ ["string()", doc.getElementById('FunctionStringCaseStringNodesetText').firstChild, "here is some text"], // text
+ ["string(attribute::node()[1])", nodeWithAttributes, filterAttributes(nodeWithAttributes.attributes)[0].nodeValue], // attribute
+ ["string(attribute::node()[3])", nodeWithAttributes, filterAttributes(nodeWithAttributes.attributes)[2].nodeValue] // attribute
+ ];
+
+ // Processing Instruction
+ node = doc.getElementById('FunctionStringCaseStringNodesetProcessingInstruction').firstChild;
+ if (node && node.nodeType == 7) {
+ input.push(["string()", node, 'type="text/xml" href="test.xsl"']);
+ }
+ // CDATASection
+ node = doc.getElementById('FunctionStringCaseStringNodesetCData').firstChild;
+ if (node && node.nodeType == 4) {
+ input.push(["string()", node, 'some cdata']);
+ }
+
+ for (i = 0; i < input.length; i++) {
+ result = documentEvaluate(input[i][0], input[i][1], null, win.XPathResult.STRING_TYPE, null);
+ expect(result.stringValue).to.equal(input[i][2]);
+ }
+ });
+
+ it('string conversion of nodeset with namepace', function() {
+ var result = documentEvaluate("string(namespace::node())", doc.getElementById('FunctionStringCaseStringNodesetNamespace'), null, win.XPathResult.STRING_TYPE, null);
+ expect(result.stringValue).to.equal("http://www.w3.org/1999/xhtml");
+ });
+
+ it('string conversion fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("string(1, 2)", doc, helpers.xhtmlResolver, win.XPathResult.STRING_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('concat()', function() {
+ [
+ ["concat(0, 0)", "00"],
+ ["concat('', '', 'b')", "b"],
+ ["concat('a', '', 'c')", "ac"],
+ ["concat('a', 'b', 'c', 'd', 'e')", "abcde"]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.STRING_TYPE, null);
+ expect(result.stringValue).to.equal(t[1]);
+ });
+ });
+
+ //in javarosa this needs to return ''
+ xit('concat() fails when not enough arguments provided', function() {
+ var test = function() {
+ documentEvaluate("concat()", doc, helpers.xhtmlResolver, win.XPathResult.STRING_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+
+ test = function() {
+ documentEvaluate("concat(1)", doc, helpers.xhtmlResolver, win.XPathResult.STRING_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('starts-with', function() {
+ [
+ ["starts-with('', '')", true],
+ ["starts-with('a', '')", true],
+ ["starts-with('a', 'a')", true],
+ ["starts-with('a', 'b')", false],
+ ["starts-with('ba', 'b')", true],
+ ["starts-with('', 'b')", false]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(t[1]);
+ });
+ });
+
+ it('starts-with() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("starts-with(1, 2, 3)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('start-with() fails when not enough arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("starts-with()", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+
+ test = function() {
+ documentEvaluate("starts-with(1)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('contains()', function() {
+ [
+ ["contains('', '')", true],
+ ["contains('', 'a')", false],
+ ["contains('a', 'a')", true],
+ ["contains('a', '')", true],
+ ["contains('asdf', 'sd')", true],
+ ["contains('asdf', 'af')", false]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.BOOLEAN_TYPE, null);
+ expect(result.booleanValue).to.equal(t[1]);
+ });
+ });
+
+ it('contains() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("contains(1, 2, 3)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('contains() fails when too few arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("contains()", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+
+ test = function() {
+ documentEvaluate("contains(1)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('substring-before()', function() {
+ [
+ ["substring-before('', '')", ''],
+ ["substring-before('', 'a')", ''],
+ ["substring-before('a', '')", ''],
+ ["substring-before('a', 'a')", ''],
+ ["substring-before('ab', 'a')", ''],
+ ["substring-before('ab', 'b')", 'a'],
+ ["substring-before('abb', 'b')", 'a'],
+ ["substring-before('ab', 'c')", '']
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.STRING_TYPE, null);
+ expect(result.stringValue).to.equal(t[1]);
+ });
+ });
+
+ it('substring-before() fails with too many arguments', function() {
+ var test = function() {
+ documentEvaluate("substring-before(1, 2, 3)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('substring-before() with too few arguments', function() {
+ var test = function() {
+ documentEvaluate("substring-before()", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ test = function() {
+ documentEvaluate("substring-before(1)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('substring-after()', function() {
+ [
+ ["substring-after('', '')", ''],
+ ["substring-after('', 'a')", ''],
+ ["substring-after('a', '')", 'a'],
+ ["substring-after('a', 'a')", ''],
+ ["substring-after('ab', 'a')", 'b'],
+ ["substring-after('aab', 'a')", 'ab'],
+ ["substring-after('ab', 'b')", ''],
+ ["substring-after('ab', 'c')", '']
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.STRING_TYPE, null);
+ expect(result.stringValue).to.equal(t[1]);
+ });
+ });
+
+ it('substring-after() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("substring-after(1, 2, 3)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('substring-after() fails when too few arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("substring-after()", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+
+ test = function() {
+ documentEvaluate("substring-after(1)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('substring()', function() {
+ [
+ ["substring('12345', 2, 3)", '234'],
+ ["substring('12345', 2)", '2345'],
+ ["substring('12345', -1)", '12345'],
+ ["substring('12345', 1 div 0)", ''],
+ ["substring('12345', 0 div 0)", ''],
+ ["substring('12345', -1 div 0)", '12345'],
+ ["substring('12345', 1.5, 2.6)", '234'],
+ ["substring('12345', 1.3, 2.3)", '12'],
+ ["substring('12345', 0, 3)", '12'],
+ ["substring('12345', 0, -1 div 0)", ''],
+ ["substring('12345', 0 div 0, 3)", ''],
+ ["substring('12345', 1, 0 div 0)", ''],
+ ["substring('12345', -42, 1 div 0)", '12345'],
+ ["substring('12345', -1 div 0, 1 div 0)", '']
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.STRING_TYPE, null);
+ expect(result.stringValue).to.equal(t[1]);
+ });
+ });
+
+ it('substring() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("substring(1, 2, 3, 4)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('substring() fails when too few arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("substring()", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+
+ test = function() {
+ documentEvaluate("substring(1)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('string-length()', function() {
+ [
+ ["string-length('')", 0, doc],
+ ["string-length(' ')", 1, doc],
+ ["string-length('\r\n')", 2, doc],
+ ["string-length('a')", 1, doc],
+ ["string-length()", 0, doc.getElementById('FunctionStringCaseStringLength1')],
+ ["string-length()", 4, doc.getElementById('FunctionStringCaseStringLength2')]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], t[2], null, win.XPathResult.NUMBER_TYPE, null);
+ expect(result.numberValue).to.equal(t[1]);
+ });
+ });
+
+ it('string-length() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("string-length(1, 2)", doc, helpers.xhtmlResolver, win.XPathResult.NUMBER_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('normalize-space', function() {
+ [
+ ["normalize-space('')", '', doc],
+ ["normalize-space(' ')", '', doc],
+ ["normalize-space(' a')", 'a', doc],
+ ["normalize-space(' a ')", 'a', doc],
+ ["normalize-space(' a b ')", 'a b', doc],
+ ["normalize-space(' a b ')", 'a b', doc],
+ ["normalize-space(' \r\n\t')", '', doc],
+ ["normalize-space(' \f\v ')", '\f\v', doc],
+ ["normalize-space('\na \f \r\v b\r\n ')", 'a \f \v b', doc],
+ ["normalize-space()", '', doc.getElementById('FunctionStringCaseStringNormalizeSpace1')],
+ ["normalize-space()", '', doc.getElementById('FunctionStringCaseStringNormalizeSpace2')],
+ ["normalize-space()", 'a b', doc.getElementById('FunctionStringCaseStringNormalizeSpace3')],
+ ["normalize-space()", 'a bc c', doc.getElementById('FunctionStringCaseStringNormalizeSpace4')]
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], t[2], null, win.XPathResult.STRING_TYPE, null);
+ expect(result.stringValue).to.equal(t[1]);
+ });
+ });
+
+ it('normalize-space() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("normalize-space(1,2)", doc, helpers.xhtmlResolver, win.XPathResult.STRING_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('translate()', function() {
+ [
+ ["translate('', '', '')", ''],
+ ["translate('a', '', '')", 'a'],
+ ["translate('a', 'a', '')", ''],
+ ["translate('a', 'b', '')", 'a'],
+ ["translate('ab', 'a', 'A')", 'Ab'],
+ ["translate('ab', 'a', 'AB')", 'Ab'],
+ ["translate('aabb', 'ab', 'ba')", 'bbaa'],
+ ["translate('aa', 'aa', 'bc')", 'bb']
+ ].forEach(function(t) {
+ var result = documentEvaluate(t[0], doc, null, win.XPathResult.STRING_TYPE, null);
+ expect(result.stringValue).to.equal(t[1]);
+ });
+ });
+
+ it('translate() fails when too many arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("translate(1, 2, 3, 4)", doc, helpers.xhtmlResolver, win.XPathResult.STRING_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+
+ it('translate() fails when too few arguments are provided', function() {
+ var test = function() {
+ documentEvaluate("translate()", doc, helpers.xhtmlResolver, win.XPathResult.STRING_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+
+ test = function() {
+ documentEvaluate("translate(1)", doc, helpers.xhtmlResolver, win.XPathResult.STRING_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+
+ test = function() {
+ documentEvaluate("translate(1,2)", doc, helpers.xhtmlResolver, win.XPathResult.STRING_TYPE, null);
+ };
+ expect(test).to.throw(win.Error);
+ });
+});
diff --git a/test/spec/union-operator-native.spec.js b/test/spec/union-operator-native.spec.js
new file mode 100644
index 0000000..1680c53
--- /dev/null
+++ b/test/spec/union-operator-native.spec.js
@@ -0,0 +1,110 @@
+/* global define, describe, xdescribe, require, it, xit, before, after, beforeEach, afterEach, expect, Blob, doc, win, docEvaluate, DOMException, XPathException, documentEvaluate, documentCreateExpression, documentCreateNSResolver, snapshotToArray, checkNodeResult, checkNodeResultNamespace, parseNamespacesFromAttributes, window, filterAttributes, loadXMLFile, helpers, XPathJS*/
+"use strict";
+
+describe('Union operator', function() {
+
+ it('combines elements', function() {
+ checkNodeResult("id('eee40') | id('eee20') | id('eee25') | id('eee10') | id('eee30') | id('eee50')", doc, [
+ doc.getElementById('eee10'),
+ doc.getElementById('eee20'),
+ doc.getElementById('eee25'),
+ doc.getElementById('eee30'),
+ doc.getElementById('eee40'),
+ doc.getElementById('eee50')
+ ]);
+ });
+
+ it('combines elements and attributes', function() {
+ checkNodeResult("id('eee40')/attribute::*[1] | id('eee30')", doc, [
+ doc.getElementById('eee30'),
+ filterAttributes(doc.getElementById('eee40').attributes)[0]
+ ]);
+ });
+
+ it('combines elements and attributes if they refer to the same element', function() {
+ checkNodeResult("id('eee40')/attribute::*[1] | id('eee40')", doc, [
+ doc.getElementById('eee40'),
+ filterAttributes(doc.getElementById('eee40').attributes)[0]
+ ]);
+ });
+
+ it('combines elements and attributs if they refer to different trees', function() {
+ checkNodeResult("id('eee40')/attribute::*[1] | id('eee20')", doc, [
+ doc.getElementById('eee20'),
+ filterAttributes(doc.getElementById('eee40').attributes)[0]
+ ]);
+ });
+
+ it('combines elements and attributes if the attribute is on a parent element in the same tree', function() {
+ checkNodeResult("id('eee40') | id('eee30')/attribute::*[1]", doc, [
+ filterAttributes(doc.getElementById('eee30').attributes)[0],
+ doc.getElementById('eee40')
+ ]);
+ });
+
+ it('combines elements and attributes if both are (on) elements under the same parent', function() {
+ checkNodeResult("id('eee40') | id('eee35')/attribute::*[1]", doc, [
+ filterAttributes(doc.getElementById('eee35').attributes)[0],
+ doc.getElementById('eee40')
+ ]);
+ });
+
+ it('combines attributes that live on different elements', function() {
+ checkNodeResult("id('eee35')/attribute::*[1] | id('eee40')/attribute::*[1]", doc, [
+ filterAttributes(doc.getElementById('eee35').attributes)[0],
+ filterAttributes(doc.getElementById('eee40').attributes)[0]
+ ]);
+ });
+
+ it('combines attributes that live on descendent elements', function() {
+ checkNodeResult("id('eee30')/attribute::*[1] | id('eee40')/attribute::*[1]", doc, [
+ filterAttributes(doc.getElementById('eee30').attributes)[0],
+ filterAttributes(doc.getElementById('eee40').attributes)[0]
+ ]);
+ });
+
+ it('combines attributes that live on descendent element (reversed)', function() {
+ checkNodeResult("id('eee40')/attribute::*[1] | id('eee30')/attribute::*[1]", doc, [
+ filterAttributes(doc.getElementById('eee30').attributes)[0],
+ filterAttributes(doc.getElementById('eee40').attributes)[0]
+ ]);
+ });
+
+ it('combines different attributes on the same element', function() {
+ checkNodeResult("id('eee40')/attribute::*[2] | id('eee40')/attribute::*[1]", doc, [
+ filterAttributes(doc.getElementById('eee40').attributes)[0],
+ filterAttributes(doc.getElementById('eee40').attributes)[1]
+ ]);
+ });
+
+ it('combines a namespace and attribute on the same element', function() {
+ var result = documentEvaluate("id('nss25')/namespace::*", doc, null, win.XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+
+ checkNodeResult("id('nss25')/namespace::* | id('nss25')/attribute::*", doc,
+ snapshotToArray(result).concat(
+ filterAttributes(doc.getElementById('nss25').attributes)
+ )
+ );
+ });
+
+ it('combines two namespaces on the same element', function() {
+ var result = documentEvaluate("id('nss40')/namespace::*", doc, null, win.XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); //
+
+ checkNodeResult("id('nss40')/namespace::* | id('nss40')/namespace::*", doc,
+ snapshotToArray(result)
+ );
+ });
+
+ it('combines a namespace and attribute', function() {
+ var result = documentEvaluate("id('nss40')/namespace::*", doc, null, win.XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); //
+
+ checkNodeResult("id('nss40')/namespace::* | id('nss25')/attribute::* | id('nss25')", doc, [
+ doc.getElementById('nss25')
+ ].concat(
+ filterAttributes(doc.getElementById('nss25').attributes)
+ ).concat(
+ snapshotToArray(result)
+ ));
+ });
+
+});
diff --git a/tests/index.php b/tests/index.php
deleted file mode 100644
index 20df236..0000000
--- a/tests/index.php
+++ /dev/null
@@ -1,73 +0,0 @@
-.
- */
-?>
-
-
-
-
-
xpath-test
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- | |
- Use Native |
- Serve as "application/xhtml+xml" |
-
-
- | Run |
- No |
- No |
-
-
- | Run |
- Yes |
- No |
-
-
- | Run |
- No |
- Yes |
-
-
- | Run |
- Yes |
- Yes |
-
-
-
-
-
-
-
diff --git a/tests/run.js b/tests/run.js
deleted file mode 100644
index fd6f881..0000000
--- a/tests/run.js
+++ /dev/null
@@ -1,128 +0,0 @@
-/**
- * Copyright (C) 2011 Andrej Pavlovic
- *
- * This file is part of XPathJS.
- *
- * XPathJS is free software: you can redistribute it and/or modify it under
- * the terms of the GNU Affero General Public License as published by the Free
- * Software Foundation, version 3 of the License.
- *
- * XPathJS is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Affero General Public License along
- * with this program. If not, see
.
- */
-
-YUI().use("node", "test-console", function (Y) {
-
- Y.on("domready", init);
-
- function init()
- {
- var useNative = !!getParameterFromUrl(location.href, "native"),
- useXml = !!getParameterFromUrl(location.href, "xml"),
- testUrl = "tests.php?native=" + ((useNative) ? 1 : 0) + "&xml=" + ((useXml) ? 1 : 0)
- ;
-
- // highlight current settings
- Y.one(".setting" + ((useNative) ? 1 : 0) + ((useXml) ? 1 : 0))
- .addClass("setting-current")
- ;
-
- var iframe = Y.one(document.createElement('iframe'))
- .setStyle('display', 'none')
- .appendTo(Y.one("#testContainer")),
- iframeLoaded = function() {
- attachScripts(iframe._node.contentWindow, useNative, useXml);
- }
- ;
-
- // @see http://www.nczonline.net/blog/2009/09/15/iframes-onload-and-documentdomain/
- if (iframe._node.attachEvent) {
- iframe._node.attachEvent("onload", iframeLoaded);
- } else {
- iframe.set('onload', iframeLoaded);
- }
-
- iframe.set('src', testUrl);
- }
-
- function attachScripts(win, useNative, useXml) {
- var scripts = [
- "http://yui.yahooapis.com/3.5.0/build/yui/yui-min.js",
- "tests.js"
- ];
-
- if (!useNative) {
- scripts.push("../src/engine.js");
- scripts.push("../dist/parser.js");
- }
-
- // load all xpath scripts for this library
- Y.Get.script(scripts, {
- onSuccess: function (e) {
- // remove script tags
- e.purge();
-
- if (!useNative) {
- // initialize xpathjs
- win.XPathJS.bindDomLevel3XPath(
- win.XPathJS.createDomLevel3XPathBindings({
- 'case-sensitive': (useXml) ? true : false
- })
- );
- }
-
- runTests(win);
- },
- win: win
- });
- }
-
- function runTests(win) {
- //create the console
- var r = new Y.Test.Console({
- newestOnTop : false,
- style: 'inline', // to anchor in the example content
- height: '500px',
- width: '100%',
- consoleLimit: 1000,
- filters: {
- pass: true
- }
- });
-
- /**
- * @see http://yuilibrary.com/projects/yui3/ticket/2531085
- */
- Y.Console.FOOTER_TEMPLATE = Y.Console.FOOTER_TEMPLATE.replace('id="{id_guid}">', 'id="{id_guid}" />');
-
- r.render('#testLogger');
-
- win.YUI({useBrowserConsole: false}).use('xpathjs-test', "node", "test", "event", function (Y2) {
-
- Y2.on("yui:log", function(e) {
- Y.log(e.msg, e.cat, e.src);
- });
-
- Y2.Test.Runner.add(Y2.XPathJS.Test.generateTestSuite(win, win.document, win.document.evaluate));
-
- //run the tests
- Y2.Test.Runner.run();
- });
- }
-
- function getParameterFromUrl(url, param) {
- var regexp = new RegExp("(?:\\?|&)" + param + "(?:$|&|=)([^]*)");
- value = regexp.exec(url)
- ;
-
- if (value === null)
- return 0;
-
- return parseInt(value[1]);
- }
-});
diff --git a/tests/tests.js b/tests/tests.js
deleted file mode 100644
index 3fbf008..0000000
--- a/tests/tests.js
+++ /dev/null
@@ -1,4454 +0,0 @@
-/**
- * Copyright (C) 2011 Andrej Pavlovic
- *
- * This file is part of XPathJS.
- *
- * XPathJS is free software: you can redistribute it and/or modify it under
- * the terms of the GNU Affero General Public License as published by the Free
- * Software Foundation, version 3 of the License.
- *
- * XPathJS is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Affero General Public License along
- * with this program. If not, see
.
- */
-
-YUI.add('xpathjs-test', function (Y) {
-
- Y.namespace("XPathJS.Test");
-
- Y.XPathJS.Test.generateTestSuite = function(win, doc, docEvaluate)
- {
- var tests = {},
- helpers = {
- getNextChildElementNode: function(parentNode)
- {
- var childNode = parentNode.firstChild;
- while(childNode.nodeName == '#text')
- {
- childNode = childNode.nextSibling;
- }
- return childNode;
- },
-
- setAttribute: function(node, namespace, name, value)
- {
- if (node.setAttributeNS)
- {
- // for XML documents
- node.setAttributeNS(namespace, name, value);
- }
- else
- {
- // normal HTML documents
- node.setAttribute(name, value);
- }
- },
-
- xhtmlResolver: {
- lookupNamespaceURI: function(prefix) {
- var namespaces = {
- 'xhtml': 'http://www.w3.org/1999/xhtml',
- 'ns2' : 'http://asdf/'
- }
-
- if (namespaces[prefix])
- {
- return namespaces[prefix];
- }
-
- var resolver = documentCreateNSResolver(doc.documentElement);
- return resolver.lookupNamespaceURI(prefix);
- }
- },
-
- getComparableNode: function(node)
- {
- switch(node.nodeType)
- {
- case 2: // attribute
- case 13: // namespace
- // TODO: IE support
- //return node.ownerElement;
- throw new Error('Internal Error: getComparableNode - Node type not implemented: ' + node.nodeType);
- break;
-
- case 3: // text
- case 4: // CDATASection
- case 7: // processing instruction
- case 8: // comment
- return node.parentNode;
- break;
-
- case 1: // element
- case 9: // document
- // leave as is
- return node;
- break;
-
- default:
- throw new Error('Internal Error: getComparableNode - Node type not supported: ' + node.nodeType);
- break;
- }
- },
-
- /**
- * @see http://ejohn.org/blog/comparing-document-position/
- */
- comparePosition: function(a, b)
- {
- var a2,
- b2,
- result,
- ancestor,
- i,
- item
- ;
-
- // check for native implementation
- if (a.compareDocumentPosition)
- {
- return a.compareDocumentPosition(b);
- }
-
- if (a === b)
- {
- return 0;
- }
-
- a2 = helpers.getComparableNode(a);
- b2 = helpers.getComparableNode(b);
-
- // handle document case
- if (a2.nodeType === 9)
- {
- if (b2.nodeType === 9)
- {
- if (a2 !== b2)
- {
- return 1; // different documents
- }
- else
- {
- result = 0; // same nodes
- }
- }
- else
- {
- if (a2 !== b2.ownerDocument)
- {
- return 1; // different documents
- }
- else
- {
- result = 4 + 16; // a2 before b2, a2 contains b2
- }
- }
- }
- else
- {
- if (b2.nodeType === 9)
- {
- if (b2 !== a2.ownerDocument)
- {
- return 1; // different documents
- }
- else
- {
- result = 2 + 8 // b2 before a2, b2 contains a2
- }
- }
- else
- {
- if (a2.ownerDocument !== b2.ownerDocument)
- {
- return 1; // different documents
- }
- else
- {
- // do a contains comparison for element nodes
- if (!a2.contains || typeof a2.sourceIndex === 'undefined' || !b2.contains || typeof b2.sourceIndex === 'undefined')
- {
- throw new Error('Cannot compare elements. Neither "compareDocumentPosition" nor "contains" available.');
- }
- else
- {
- result =
- (a2 != b2 && a2.contains(b2) && 16) +
- (a2 != b2 && b2.contains(a2) && 8) +
- (a2.sourceIndex >= 0 && b2.sourceIndex >= 0
- ? (a2.sourceIndex < b2.sourceIndex && 4) + (a2.sourceIndex > b2.sourceIndex && 2)
- : 1 ) +
- 0 ;
- }
- }
- }
- }
-
- if (a === a2)
- {
- if (b === b2)
- {
- return result;
- }
- else
- {
- // if a contains b2 or a == b2
- if (result === 0 || (result & 16) === 16)
- {
- // return result
- return result;
- }
- // else if b2 contains a
- else if ((result & 8) === 8)
- {
- // find (ancestor-or-self::a) that is direct child of b2
- ancestor = a;
- while (ancestor.parentNode !== b2)
- {
- ancestor = ancestor.parentNode;
- }
-
- // return "a pre b" or "b pre a" depending on which is occurs first in b2.childNodes
- for(i=0; i
1 && specifiedAttributes[0].compareDocumentPosition) {
- specifiedAttributes.sort(function(a, b) {
- var position = a.compareDocumentPosition(b);
-
- if ((position & 2) == 2) return 1;
- else if ((position & 4) == 4) return -1;
- else return 0;
- });
- }
-
- return specifiedAttributes;
- },
-
- filterAttributes = function(attributes)
- {
- var specifiedAttributes = removeUnspecifiedAttributesAndSort(attributes),
- nonNamespaceAttributes = [],
- i,
- name
- ;
-
- // get only specified attributes
- for(i=0; i < specifiedAttributes.length; i++)
- {
- name = specifiedAttributes[i].nodeName.split(':');
-
- if (name[0] === 'xmlns')
- {
- // ignore namespaces
- continue;
- }
-
- nonNamespaceAttributes.push(specifiedAttributes[i]);
- }
-
- return nonNamespaceAttributes;
- },
-
- checkNodeResultNamespace = function(expression, contextNode, expectedResult, resolver)
- {
- var j, result, item, res;
-
- res = (!resolver) ? null : resolver;
-
- result = documentEvaluate(expression, contextNode, res, win.XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
-
- Y.Assert.areSame(expectedResult.length, result.snapshotLength);
-
- for (j = 0; j < result.snapshotLength; j++) {
- item = result.snapshotItem(j);
- Y.Assert.areSame('#namespace', item.nodeName);
- Y.Assert.areSame(expectedResult[j][0], item.localName);
- Y.Assert.areSame(expectedResult[j][1], item.namespaceURI);
- }
- },
-
- checkNodeResult = function(expression, contextNode, expectedResult, resolver)
- {
- var result, j, item, res;
-
- res = (!resolver) ? null : resolver;
-
- result = documentEvaluate(expression, contextNode, res, win.XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
-
- Y.Assert.areSame(expectedResult.length, result.snapshotLength);
-
- for (j = 0; j < result.snapshotLength; j++) {
- item = result.snapshotItem(j);
- Y.Assert.areSame(expectedResult[j], item);
- }
- },
-
- parseNamespacesFromAttributes = function(attributes, namespaces)
- {
- var i,
- name,
- attributes = removeUnspecifiedAttributesAndSort(attributes)
- ;
-
- for(i=attributes.length-1; i>=0; i--)
- {
- name = attributes[i].nodeName.split(':');
-
- if (name[0] === 'xmlns')
- {
- if (name.length == 1)
- {
- namespaces.unshift([ '', attributes[i].nodeValue ]);
- }
- else
- {
- namespaces.push([ name[1], attributes[i].nodeValue ]);
- }
- }
- }
- },
-
- snapshotToArray = function(result) {
- var nodes = [], i;
-
- for (i=0; i < result.snapshotLength; i++)
- {
- nodes.push(result.snapshotItem(i));
- }
-
- return nodes;
- }
- ;
-
- tests.FunctionStringCase = new Y.Test.Case({
-
- name: "String Function Tests",
-
- _should: {
- error: {
- testStringExceptionTooManyArgs: true,
- testNormalizeSpaceExceptionTooManyArgs: true,
- testConcatExceptionNotEnoughArgs1: true,
- testConcatExceptionNotEnoughArgs2: true,
- testStartsWithTooManyArgs: true,
- testStartsWithNotEnoughArgs1: true,
- testStartsWithNotEnoughArgs2: true,
- testContainsWithTooManyArgs: true,
- testContainsWithNotEnoughArgs1: true,
- testContainsWithNotEnoughArgs2: true,
- testSubstringBeforeWithTooManyArgs: true,
- testSubstringBeforeWithNotEnoughArgs1: true,
- testSubstringBeforeWithNotEnoughArgs2: true,
- testSubstringAfterWithTooManyArgs: true,
- testSubstringAfterWithNotEnoughArgs1: true,
- testSubstringAfterWithNotEnoughArgs2: true,
- testSubstringWithTooManyArgs: true,
- testSubstringWithNotEnoughArgs1: true,
- testSubstringWithNotEnoughArgs2: true,
- testStringLengthWithTooManyArgs: true,
- testNormalizeSpaceExceptionTooManyArgs: true,
- testTranslateExceptionTooManyArgs: true,
- testTranslateExceptionNotEnoughArgs1: true,
- testTranslateExceptionNotEnoughArgs2: true,
- testTranslateExceptionNotEnoughArgs3: true
- },
- ignore: {
- }
- },
-
- testStringString: function() {
- var result, input, i;
-
- input = [
- ["string('-1.0')", "-1.0"],
- ["string('1')", "1"],
- ["string(' \nhello \n\r')", " \nhello \n\r"],
- ["string('')", ""],
- ["string('As Df')", "As Df"]
- ];
-
- for(i=0; i=0;i--)
- {
- name = attributes[i].nodeName.split(':')
-
- if (name[0] != 'ev')
- {
- attributes.splice(i, 1);
- }
- }
-
- Y.Assert.areSame(2, attributes.length);
-
- checkNodeResult("attribute::ev:*", node, attributes, helpers.xhtmlResolver);
- },
-
- testNamespaceAnyNamespace: function()
- {
- var node = doc.getElementById('StepNodeTestCaseNameTestNamespace')
- ;
-
- checkNodeResultNamespace("namespace::ns2:*", node, [], helpers.xhtmlResolver);
- },
-
- testNamespaceAnyChild: function()
- {
- var node = doc.getElementById('StepNodeTestCaseNameTestChild'),
- nodesFinal = []
- ;
-
- nodesFinal = [
- node.childNodes[0],
- node.childNodes[1],
- node.childNodes[2]
- ];
-
- checkNodeResult("child::ns2:*", node, nodesFinal, helpers.xhtmlResolver);
- },
-
- testNamespaceNameAttribute: function()
- {
- var node = doc.getElementById('StepNodeTestCaseNameTestAttribute'),
- attributes = filterAttributes(node.attributes),
- i,
- name
- ;
-
- for(i=attributes.length-1; i>=0;i--)
- {
- name = attributes[i].nodeName.split(':')
-
- if (name[0] != 'ev' || name[1] != 'attrib2')
- {
- attributes.splice(i, 1);
- }
- }
-
- Y.Assert.areSame(1, attributes.length);
-
- checkNodeResult("attribute::ev:attrib2", node, attributes, helpers.xhtmlResolver);
- },
-
- testNamespaceNameNamespace: function()
- {
- var node = doc.getElementById('StepNodeTestCaseNameTestNamespace')
- ;
-
- checkNodeResultNamespace("namespace::ns2:ns2", node, [], helpers.xhtmlResolver);
- },
-
- testNamespaceNameChild: function()
- {
- var node = doc.getElementById('StepNodeTestCaseNameTestChild'),
- nodesFinal = []
- ;
-
- nodesFinal = [
- node.childNodes[0],
- node.childNodes[1]
- ];
-
- checkNodeResult("child::ns2:div", node, nodesFinal, helpers.xhtmlResolver);
- },
-
- testNameAttribute: function()
- {
- var node = doc.getElementById('StepNodeTestCaseNameTestAttribute'),
- attributes = filterAttributes(node.attributes),
- i,
- name
- ;
-
- for(i=attributes.length-1; i>=0;i--)
- {
- name = attributes[i].nodeName.split(':')
-
- if (name[0] != 'attrib3')
- {
- attributes.splice(i, 1);
- }
- }
-
- Y.Assert.areSame(1, attributes.length);
-
- checkNodeResult("attribute::attrib3", node, attributes, helpers.xhtmlResolver);
- },
-
- testNameNamespace: function()
- {
- var node = doc.getElementById('StepNodeTestCaseNameTestNamespace')
- ;
-
-
- checkNodeResultNamespace("namespace::ns2", node, [[
- 'ns2',
- 'http://asdf/'
- ]], helpers.xhtmlResolver);
- },
-
- testNameChild: function()
- {
- checkNodeResult("child::html", doc, [], helpers.xhtmlResolver);
- checkNodeResult("child::xhtml:html", doc, [doc.documentElement], helpers.xhtmlResolver);
- },
-
- testAncestorNodeName: function()
- {
- checkNodeResult("ancestor::xhtml:div", doc.getElementById('StepNodeTestCaseNameTest3'), [
- doc.getElementById('StepNodeTestCaseNameTest'),
- doc.getElementById('StepNodeTestCaseNameTest1'),
- doc.getElementById('StepNodeTestCaseNameTest2')
- ], helpers.xhtmlResolver);
- },
-
- testAncestorNodeNameNoDefaultNamespace: function()
- {
- checkNodeResult("ancestor::div", doc.getElementById('StepNodeTestCaseNameTestNoNamespace').firstChild.firstChild.firstChild, [
- doc.getElementById('StepNodeTestCaseNameTestNoNamespace').firstChild,
- doc.getElementById('StepNodeTestCaseNameTestNoNamespace').firstChild.firstChild
- ], helpers.xhtmlResolver);
- }
- });
-
- tests.LocationPathCase = new Y.Test.Case({
- name: 'Location Path Tests',
-
- setUp: function()
- {
- this.oneNamespaceNode = function(node)
- {
- var result, item;
-
- result = documentEvaluate("namespace::node()", node, null, win.XPathResult.ANY_UNORDERED_NODE_TYPE, null);
- item = result.singleNodeValue;
- Y.Assert.isNotNull(item);
- Y.Assert.areSame(item.nodeType, 13);
-
- return item;
- }
- },
-
- tearDown: function()
- {
- },
-
- _should: {
- error: {
- },
- ignore: {
- testNodeAttribute: true,
- testNodeNamespace: true
- }
- },
-
- testRoot: function()
- {
- var input = [
- [doc, [doc]], // Document
- [doc.documentElement, [doc]], // Element
- [doc.getElementById('LocationPathCase'), [doc]], // Element
- [doc.getElementById('LocationPathCaseText').firstChild, [doc]], // Text
- [doc.getElementById('LocationPathCaseComment').firstChild, [doc]], // Comment
- [filterAttributes(doc.getElementById('LocationPathCaseAttribute').attributes)[0], [doc]] // Attribute
- ],
- i,
- node
- ;
-
- // ProcessingInstruction
- node = doc.getElementById('LocationPathCaseProcessingInstruction').firstChild;
- if (node && node.nodeType == 7)
- {
- input.push([node, [doc]]);
- }
-
- // CDATASection
- node = doc.getElementById('LocationPathCaseCData').firstChild
- if (node && node.nodeType == 4)
- {
- input.push([node, [doc]]);
- }
-
- for(i=0; i < input.length; i++)
- {
- checkNodeResult("/", input[i][0], input[i][1]);
- }
- },
-
- testRootNamespace: function()
- {
- var input = [this.oneNamespaceNode(doc.getElementById('LocationPathCaseNamespace')), [doc]] // XPathNamespace
- ;
-
- checkNodeResult("/", input[0], input[1]);
- },
-
- testRootNode: function()
- {
- checkNodeResult("/html", doc, [], helpers.xhtmlResolver);
- checkNodeResult("/xhtml:html", doc, [doc.documentElement], helpers.xhtmlResolver);
- checkNodeResult("/xhtml:html", doc.getElementById('LocationPathCase'), [doc.documentElement], helpers.xhtmlResolver);
- checkNodeResult("/htmlnot", doc.getElementById('LocationPathCase'), [], helpers.xhtmlResolver);
- },
-
- testRootNodeNode: function()
- {
- checkNodeResult("/xhtml:html/xhtml:body", doc.getElementById('LocationPathCase'), [doc.body], helpers.xhtmlResolver);
- },
-
- testNodeNode: function()
- {
- checkNodeResult("html", doc, [], helpers.xhtmlResolver);
- checkNodeResult("xhtml:html", doc, [doc.documentElement], helpers.xhtmlResolver);
- checkNodeResult("xhtml:html/xhtml:body", doc, [doc.body], helpers.xhtmlResolver);
- },
-
- testNodeAttribute: function()
- {
- var node = doc.getElementById('LocationPathCaseAttributeParent')
- ;
-
- checkNodeResult("child::*/attribute::*", node, [
- filterAttributes(node.childNodes[0].attributes)[0],
- filterAttributes(node.childNodes[1].attributes)[0],
- filterAttributes(node.childNodes[1].attributes)[1],
- filterAttributes(node.childNodes[2].attributes)[0],
- filterAttributes(node.childNodes[3].attributes)[0]
- ], helpers.xhtmlResolver);
- },
-
- testNodeNamespace: function()
- {
- var node = doc.getElementById('LocationPathCaseNamespaceParent')
- ;
-
- checkNodeResultNamespace("child::* /namespace::*", node, [
- ['', 'http://asdss/'],
- ['ev', 'http://some-namespace.com/nss'],
- ['xml', 'http://www.w3.org/XML/1998/namespace'],
- ['', 'http://www.w3.org/1999/xhtml'],
- ['ab', 'hello/world2'],
- ['a2', 'hello/world'],
- ['aa', 'http://saa/'],
- ['ev', 'http://some-namespace.com/nss'],
- ['xml', 'http://www.w3.org/XML/1998/namespace'],
- ['', 'http://www.w3.org/1999/xhtml'],
- ['ev', 'http://some-namespace.com/nss'],
- ['xml', 'http://www.w3.org/XML/1998/namespace'],
- ['', 'http://www.w3.org/1999/xhtml'],
- ['aa', 'http://saa/'],
- ['ev', 'http://some-namespace.com/nss'],
- ['xml', 'http://www.w3.org/XML/1998/namespace']
- ], helpers.xhtmlResolver);
- },
-
- testDuplicates: function()
- {
- checkNodeResult("ancestor-or-self::* /ancestor-or-self::*", doc.getElementById('LocationPathCaseDuplicates'), [
- doc.documentElement,
- doc.body,
- doc.getElementById('LocationPathCase'),
- doc.getElementById('LocationPathCaseDuplicates')
- ], helpers.xhtmlResolver);
- }
- });
-
-
- tests.ComparisonOperatorCase = new Y.Test.Case({
- name: 'Comparison Operator Tests',
-
- _should: {
- error: {
- testAndLetterCase: true,
- testOrLetterCase: true
- },
- ignore: {
- }
- },
-
- testEqualsAndNotEquals: function() {
- var result, input, i, expr, j, k,
- ops = ['=', '!=']
- ;
-
- input = [
- [["1", "1"], [true, false], doc],
- [["1", "0"], [false, true], doc],
- [["1", "'1'"], [true, false], doc],
- [["1", "'0'"], [false, true], doc],
- [["1", "true()"], [true, false], doc],
- [["1", "false()"], [false, true], doc],
- [["0", "false()"], [true, false], doc],
- [["-10", "*"], [false, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["4", "*"], [true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["4.3", "*"], [false, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["0", "*"], [false, false], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')],
-
- [["true()", "true()"], [true, false], doc],
- [["false()", "false()"], [true, false], doc],
- [["true()", "false()"], [false, true], doc],
- [["true()", "'1'"], [true, false], doc],
- [["true()", "''"], [false, true], doc],
- [["false()", "'0'"], [false, true], doc],
- [["false()", "''"], [true, false], doc],
- [["true()", "*"], [true, false], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["false()", "*"], [false, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["true()", "*"], [false, true], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')],
- [["false()", "*"], [true, false], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')],
-
- [["'1a'", "'1a'"], [true, false], doc],
- [["'1'", "'0'"], [false, true], doc],
- [["''", "''"], [true, false], doc],
- [["''", "'0'"], [false, true], doc],
- [["'aaa'", "*"], [true, true], doc.getElementById('ComparisonOperatorCaseNodesetStrings')],
- [["'bb'", "*"], [false, true], doc.getElementById('ComparisonOperatorCaseNodesetStrings')],
- [["''", "*"], [false, true], doc.getElementById('ComparisonOperatorCaseNodesetStrings')],
- [["''", "*"], [false, false], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')],
-
- [["id('ComparisonOperatorCaseNodesetNegative5to5')/*", "id('ComparisonOperatorCaseNodesetEmpty')/*"], [false, false], doc],
- [["id('ComparisonOperatorCaseNodesetNegative5to5')/*", "id('ComparisonOperatorCaseNodeset4to8')/*"], [true, true], doc],
- [["id('ComparisonOperatorCaseNodesetNegative5to5')/*", "id('ComparisonOperatorCaseNodeset6to10')/*"], [false, true], doc]
- ];
-
- for(k=0; k < ops.length; k++) // different operators
- {
- for(j=0; j < 2; j++) // switch parameter order
- {
- for(i=0; i', '>=']
- ;
-
- input = [
- [["1", "2"], [true, true, false, false], doc],
- [["1", "1"], [false, true, false, true], doc],
- [["1", "0"], [false, false, true, true], doc],
- [["1", "'2'"], [true, true, false, false], doc],
- [["1", "'1'"], [false, true, false, true], doc],
- [["1", "'0'"], [false, false, true, true], doc],
- [["2", "true()"], [false, false, true, true], doc],
- [["1", "true()"], [false, true, false, true], doc],
- [["1", "false()"], [false, false, true, true], doc],
- [["0", "false()"], [false, true, false, true], doc],
- [["0", "true()"], [true, true, false, false], doc],
- [["-10", "*"], [true, true, false, false], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["10", "*"], [false, false, true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["5", "*"], [false, true, true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["2", "*"], [true, true, true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["0", "*"], [false, false, false, false], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')],
-
- [["true()", "2"], [true, true, false, false], doc],
- [["true()", "1"], [false, true, false, true], doc],
- [["false()", "1"], [true, true, false, false], doc],
- [["false()", "0"], [false, true, false, true], doc],
- [["true()", "0"], [false, false, true, true], doc],
- [["true()", "true()"], [false, true, false, true], doc],
- [["true()", "false()"], [false, false, true, true], doc],
- [["false()", "false()"], [false, true, false, true], doc],
- [["false()", "true()"], [true, true, false, false], doc],
- [["true()", "'1'"], [false, true, false, true], doc],
- [["true()", "''"], [false, false, false, false], doc],
- [["false()", "'0'"], [false, true, false, true], doc],
- [["false()", "''"], [false, false, false, false], doc],
- [["true()", "*"], [false, true, false, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["true()", "*"], [false, false, true, true], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')],
- [["false()", "*"], [true, true, false, false], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["false()", "*"], [false, true, false, true], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')],
-
- [["'2'", "1"], [false, false, true, true], doc],
- [["'1'", "1"], [false, true, false, true], doc],
- [["'0'", "1"], [true, true, false, false], doc],
- [["'1'", "true()"], [false, true, false, true], doc],
- [["''", "true()"], [false, false, false, false], doc],
- [["'0'", "false()"], [false, true, false, true], doc],
- [["''", "false()"], [false, false, false, false], doc],
- [["'1a'", "'1a'"], [false, false, false, false], doc],
- [["'1'", "'0'"], [false, false, true, true], doc],
- [["''", "''"], [false, false, false, false], doc],
- [["''", "'0'"], [false, false, false, false], doc],
- [["'4'", "*"], [true, true, true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["'aaa'", "*"], [false, false, false, false], doc.getElementById('ComparisonOperatorCaseNodesetStrings')],
- [["''", "*"], [false, false, false, false], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')],
-
- [["*", "-10"], [false, false, true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["*", "10"], [true, true, false, false], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["*", "5"], [true, true, false, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["*", "2"], [true, true, true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["*", "0"], [false, false, false, false], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')],
- [["*", "true()"], [false, true, false, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["*", "true()"], [true, true, false, false], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')],
- [["*", "false()"], [false, false, true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["*", "false()"], [false, true, false, true], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')],
- [["*", "'4'"], [true, true, true, true], doc.getElementById('ComparisonOperatorCaseNodesetNegative5to5')],
- [["*", "'aaa'"], [false, false, false, false], doc.getElementById('ComparisonOperatorCaseNodesetStrings')],
- [["*", "''"], [false, false, false, false], doc.getElementById('ComparisonOperatorCaseNodesetEmpty')],
- [["id('ComparisonOperatorCaseNodesetNegative5to5')/*", "id('ComparisonOperatorCaseNodesetEmpty')/*"], [false, false, false, false], doc],
- [["id('ComparisonOperatorCaseNodesetNegative5to5')/*", "id('ComparisonOperatorCaseNodeset4to8')/*"], [true, true, true, true], doc],
- [["id('ComparisonOperatorCaseNodesetNegative5to5')/*", "id('ComparisonOperatorCaseNodeset6to10')/*"], [true, true, false, false], doc]
- ];
-
- for(k=0; k < ops.length; k++) // different operators
- {
- for(i=0; i