diff --git a/Gruntfile.js b/Gruntfile.js index afcd67b..71ab1c6 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -28,7 +28,9 @@ module.exports = function(grunt) { "src/About.js" ], browserFileList = coreFileList.slice(), - nodeFileList = coreFileList.slice(); + nodeFileList = coreFileList.slice(), + pkg, + bower; browserFileList.push( "src/Environment/Browser.js" @@ -37,9 +39,16 @@ module.exports = function(grunt) { "src/Environment/Node.js" ); + pkg = grunt.file.readJSON("package.json"); + bower = grunt.file.readJSON("bower.json"); + + if (pkg.version !== bower.version) { + grunt.fail.fatal("package.json and bower.json versions do not match"); + } + // Project configuration. grunt.initConfig({ - pkg: grunt.file.readJSON("package.json"), + pkg: pkg, watch: { files: ["src/**/*.js"], diff --git a/src/Utils.js b/src/Utils.js index f14358e..2f77603 100644 --- a/src/Utils.js +++ b/src/Utils.js @@ -240,26 +240,50 @@ TinCan client library @private */ parseURL: function (url) { - var parts = String(url).split("?"), - pairs, - pair, - i, - params = {} - ; - if (parts.length === 2) { - pairs = parts[1].split("&"); - for (i = 0; i < pairs.length; i += 1) { - pair = pairs[i].split("="); - if (pair.length === 2 && pair[0]) { - params[pair[0]] = decodeURIComponent(pair[1]); - } + // + // see http://stackoverflow.com/a/21553982 + // and http://stackoverflow.com/a/2880929 + // + var reURLInformation, + match, + result, + paramMatch, + pl = /\+/g, // Regex for replacing addition symbol with a space + search = /([^&=]+)=?([^&]*)/g, + decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }; + + reURLInformation = new RegExp( + [ + "^(https?:)//", // protocol + "(([^:/?#]*)(?::([0-9]+))?)", // host (hostname and port) + "(/[^?#]*)", // pathname + "(\\?[^#]*|)", // search + "(#.*|)$" // hash + ].join("") + ); + match = url.match(reURLInformation); + result = { + protocol: match[1], + host: match[2], + hostname: match[3], + port: match[4], + pathname: match[5], + search: match[6], + hash: match[7], + params: {} + }; + + // 'path' is for backwards compatibility + result.path = result.protocol + "//" + result.host + result.pathname; + + if (result.search !== "") { + // extra parens to let jshint know this is an expression + while ((paramMatch = search.exec(result.search.substring(1)))) { + result.params[decode(paramMatch[1])] = decode(paramMatch[2]); } } - return { - path: parts[0], - params: params - }; + return result; }, /** diff --git a/test/index.html b/test/index.html index 1878ab6..bccff38 100644 --- a/test/index.html +++ b/test/index.html @@ -20,42 +20,59 @@ -

Full Suite

-Complete Test - -

Single Test Files

- - -

Special Conditions

- +
+

Full Suite

+ Complete Test + +

Single Test Files

+ + +

Special Conditions

+ +
+
+

Configuration

+

+
+ + + + diff --git a/test/js/unit/Utils.js b/test/js/unit/Utils.js index 3d9aff7..becebd5 100644 --- a/test/js/unit/Utils.js +++ b/test/js/unit/Utils.js @@ -91,24 +91,80 @@ deepEqual( result, { + protocol: "http:", + host: "tincanapi.com:8080", + hostname: "tincanapi.com", + port: "8080", + pathname: "/TinCanJS/Test/TinCan.Utils_parseURL/test", + search: "", + hash: "", params: {}, path: "http://tincanapi.com:8080/TinCanJS/Test/TinCan.Utils_parseURL/test" }, - "return value: no params" + "return value: no params" ); result = TinCan.Utils.parseURL("http://tincanapi.com:8080/TinCanJS/Test/TinCan.Utils_parseURL/test?paramA=1¶mB=2"); deepEqual( result, { + protocol: "http:", + host: "tincanapi.com:8080", + hostname: "tincanapi.com", + port: "8080", + pathname: "/TinCanJS/Test/TinCan.Utils_parseURL/test", + search: "?paramA=1¶mB=2", + hash: "", params: { paramA: "1", paramB: "2" }, path: "http://tincanapi.com:8080/TinCanJS/Test/TinCan.Utils_parseURL/test" }, - "return value: with params" - ); + "return value: with params" + ); + + result = TinCan.Utils.parseURL("https://tincanapi.com/TinCanJS/Test/TinCan.Utils_parseURL/test?paramA=1¶mB=2&weirdParam=odd?secondQuestionMark#withHash"); + deepEqual( + result, + { + protocol: "https:", + host: "tincanapi.com", + hostname: "tincanapi.com", + port: undefined, + pathname: "/TinCanJS/Test/TinCan.Utils_parseURL/test", + search: "?paramA=1¶mB=2&weirdParam=odd?secondQuestionMark", + hash: "#withHash", + params: { + paramA: "1", + paramB: "2", + weirdParam: "odd?secondQuestionMark" + }, + path: "https://tincanapi.com/TinCanJS/Test/TinCan.Utils_parseURL/test" + }, + "return value: with odd params, https no port, and hash" + ); + + result = TinCan.Utils.parseURL("http://tincanapi.com:8080/TinCanJS/Test/TinCan.Utils_parseURL/test?paramA=1¶mB=2¶mC=%23isahashsymbol#theRealHash"); + deepEqual( + result, + { + protocol: "http:", + host: "tincanapi.com:8080", + hostname: "tincanapi.com", + port: "8080", + pathname: "/TinCanJS/Test/TinCan.Utils_parseURL/test", + search: "?paramA=1¶mB=2¶mC=%23isahashsymbol", + hash: "#theRealHash", + params: { + paramA: "1", + paramB: "2", + paramC: "#isahashsymbol" + }, + path: "http://tincanapi.com:8080/TinCanJS/Test/TinCan.Utils_parseURL/test" + }, + "return value: with params" + ); } ); test( diff --git a/test/node-runner.js b/test/node-runner.js index 1489adc..7af05ef 100644 --- a/test/node-runner.js +++ b/test/node-runner.js @@ -1,4 +1,48 @@ -var testRunner = require("qunit"); +var testRunner = require("qunit"), + args = process.argv.slice(2), + tests, + isJSUnitFile = /^js\/unit\//, + isAbsoluteFile = /^\//; + +if (args.length) { + tests = args; +} +else { + tests = [ + "State.js", + "ActivityProfile.js", + "AgentProfile.js", + "StatementsResult.js", + "Agent.js", + "Group.js", + "Activity.js", + "ActivityDefinition.js", + "ContextActivities.js", + "Context.js", + "InteractionComponent.js", + "Result.js", + "Score.js", + "Statement.js", + "StatementRef.js", + "SubStatement.js", + "Verb.js", + "Utils.js", + "TinCan.js", + "TinCan-async.js", + "LRS.js", + "About.js" + ]; +} + +for (i = 0; i < tests.length; i += 1) { + if (isJSUnitFile.test(tests[i])) { + tests[i] = __dirname + "/" + tests[i]; + continue; + } + if (! isAbsoluteFile.test(tests[i])) { + tests[i] = __dirname + "/js/unit/" + tests[i]; + } +} testRunner.setup( { @@ -31,30 +75,7 @@ testRunner.run( { path: __dirname + "/config.js", namespace: "TinCanTestCfg" } ], code: { path: __dirname + "/../build/tincan-node.js", namespace: "TinCan" }, - tests: [ - __dirname + "/js/unit/State.js" - , __dirname + "/js/unit/ActivityProfile.js" - , __dirname + "/js/unit/AgentProfile.js" - , __dirname + "/js/unit/StatementsResult.js" - , __dirname + "/js/unit/Agent.js" - , __dirname + "/js/unit/Group.js" - , __dirname + "/js/unit/Activity.js" - , __dirname + "/js/unit/ActivityDefinition.js" - , __dirname + "/js/unit/ContextActivities.js" - , __dirname + "/js/unit/Context.js" - , __dirname + "/js/unit/InteractionComponent.js" - , __dirname + "/js/unit/Result.js" - , __dirname + "/js/unit/Score.js" - , __dirname + "/js/unit/Statement.js" - , __dirname + "/js/unit/StatementRef.js" - , __dirname + "/js/unit/SubStatement.js" - , __dirname + "/js/unit/Verb.js" - , __dirname + "/js/unit/Utils.js" - , __dirname + "/js/unit/TinCan.js" - , __dirname + "/js/unit/TinCan-async.js" - , __dirname + "/js/unit/LRS.js" - , __dirname + "/js/unit/About.js" - ] + tests: tests }, function (err, report) { if (err) {