From 0bf0cbd4bcb170549c53fd39eda76bd358108bde Mon Sep 17 00:00:00 2001 From: Martijn van de Rijdt Date: Tue, 1 Mar 2016 13:56:25 -0700 Subject: [PATCH] converted tests to karma + mocha --- .travis.yml | 6 + Gruntfile.js | 16 + README.md | 5 + package.json | 16 + tests/tests.php => test/doc.xml | 68 +- test/helpers.js | 397 ++ test/karma.conf.js | 74 + test/spec/and-or-operators-native.spec.js | 157 + test/spec/axis-native.spec.js | 969 ++++ test/spec/before.spec.js | 40 + test/spec/boolean-functions-native.spec.js | 169 + test/spec/comparison-operator-native.spec.js | 430 ++ test/spec/create-expression-native.spec.js | 47 + test/spec/exceptions-native.spec.js | 39 + .../spec/expression-evaluation-native.spec.js | 52 + test/spec/namespace-resolver-native.spec.js | 133 + test/spec/node-name-native.spec.js | 181 + test/spec/node-type-native.spec.js | 78 + test/spec/nodeset-functions-native.spec.js | 286 ++ test/spec/nodeset-id-function-native.spec.js | 100 + test/spec/number-functions-native.spec.js | 211 + test/spec/number-operators-native.spec.js | 280 ++ test/spec/path-native.spec.js | 118 + test/spec/string-functions-native.spec.js | 383 ++ test/spec/union-operator-native.spec.js | 110 + tests/index.php | 73 - tests/run.js | 128 - tests/tests.js | 4454 ----------------- 28 files changed, 4331 insertions(+), 4689 deletions(-) create mode 100644 .travis.yml rename tests/tests.php => test/doc.xml (86%) create mode 100644 test/helpers.js create mode 100644 test/karma.conf.js create mode 100644 test/spec/and-or-operators-native.spec.js create mode 100644 test/spec/axis-native.spec.js create mode 100644 test/spec/before.spec.js create mode 100644 test/spec/boolean-functions-native.spec.js create mode 100644 test/spec/comparison-operator-native.spec.js create mode 100644 test/spec/create-expression-native.spec.js create mode 100644 test/spec/exceptions-native.spec.js create mode 100644 test/spec/expression-evaluation-native.spec.js create mode 100644 test/spec/namespace-resolver-native.spec.js create mode 100644 test/spec/node-name-native.spec.js create mode 100644 test/spec/node-type-native.spec.js create mode 100644 test/spec/nodeset-functions-native.spec.js create mode 100644 test/spec/nodeset-id-function-native.spec.js create mode 100644 test/spec/number-functions-native.spec.js create mode 100644 test/spec/number-operators-native.spec.js create mode 100644 test/spec/path-native.spec.js create mode 100644 test/spec/string-functions-native.spec.js create mode 100644 test/spec/union-operator-native.spec.js delete mode 100644 tests/index.php delete mode 100644 tests/run.js delete mode 100644 tests/tests.js 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'); -?> - - + xpath-test - +
@@ -66,13 +41,28 @@

3

4

+ +
+
+

1

+
+
+

2

+
+
+

3

+
+
+

4

+
+
aaa
bbbsss
cccddd
here is some text
-
' ?>
+
@@ -83,7 +73,7 @@
bbbsss
cccddd
here is some text
-
' ?>
+
@@ -117,10 +107,20 @@
some text
some text]]>
-
' ?>
+
+ +
+
+
+ +
+
-10
+
15
+
+
@@ -128,7 +128,7 @@
some text]]>
asdf
asdf
-
' ?>
asdf
+
asdf
@@ -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 NativeServe as "application/xhtml+xml"
RunNoNo
RunYesNo
RunNoYes
RunYesYes
-

-
-
- - 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