summaryrefslogtreecommitdiff
path: root/js/dojo-1.6/dojox/testing/DocTest.xd.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/dojo-1.6/dojox/testing/DocTest.xd.js')
-rw-r--r--js/dojo-1.6/dojox/testing/DocTest.xd.js295
1 files changed, 295 insertions, 0 deletions
diff --git a/js/dojo-1.6/dojox/testing/DocTest.xd.js b/js/dojo-1.6/dojox/testing/DocTest.xd.js
new file mode 100644
index 0000000..7e3c550
--- /dev/null
+++ b/js/dojo-1.6/dojox/testing/DocTest.xd.js
@@ -0,0 +1,295 @@
+/*
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
+ Available via Academic Free License >= 2.1 OR the modified BSD license.
+ see: http://dojotoolkit.org/license for details
+*/
+
+
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojox.testing.DocTest"],
+["require", "dojo.string"]],
+defineResource: function(dojo, dijit, dojox){if(!dojo._hasResource["dojox.testing.DocTest"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.testing.DocTest"] = true;
+dojo.provide("dojox.testing.DocTest");
+dojo.require("dojo.string");
+
+
+
+dojo.declare(
+ "dojox.testing.DocTest",
+ null,
+ {
+ // summary:
+ // This class executes doctests.
+ // description:
+ // DocTests are tests that are defined inside the comment.
+ // A doctest looks as if it was copied from the shell (which it mostly is).
+ // A doctest is executed when the following conditions match:
+ // 1) all lines are comments
+ // 2) the line always starts with spaces/tabs followed by "//"
+ // and at least one space
+ // 3) the line(s) of the test to execute starts with ">>>"
+ // preceeded by what is described in 2)
+ // 4) the first line after 3) starting without ">>>" is the exptected result.
+ // preceeded by what is described in 2)
+ // 5) the test sequence is terminated by an empty line, or the next
+ // test in the following line, or a new line that does not start as described in 2)
+ // (simple said: is not a comment)
+ // preceeded by what is described in 2)
+ //
+ // I.e. the following is a simple doctest, that will actually also be run
+ // if you run this class against this file here:
+ // >>> 1+1 // A simple test case. Terminated by an empty line
+ // 2
+ //
+ // >>> 1==2
+ // false
+ // >>> "a"+"b" // Also without the empty line before, this is a new test.
+ // "ab"
+ //
+ // >>> var anything = "anything" // Multiple commands for one test.
+ // >>> "something"==anything
+ // false
+ //
+ // DocTests are great for inline documenting a class or method, they also
+ // are very helpful in understanding what the class/method actually does.
+ // They don't make sense everywhere, but sometimes they are really handy.
+
+
+ // TODO:
+ // - using console.log() in a test prints something on the
+ // console (if you do it on the console) but its not accepted
+ // yet to be the test result, may be override console.log!?
+ // i.e. here i wanted to: dojo.forEach(["one", 2],
+ // function(el, index) {console.log(el, index)}) that works on
+ // the console, but not as a docTest :-(
+ // - surround the eval for each test case singlely with a
+ // try-catch, to to catch syntax errors etc (though the
+ // shouldn't happen if you copy the test from the shell :-))
+
+
+ errors: [],
+
+ getTests:function(/*String*/moduleName){
+ // summary: Extract the tests from the given module or string.
+ // examples:
+ // >>> dojo.isArray(new dojox.testing.DocTest().getTests("dojox.testing.DocTest")) // Use the module name to extract the tests from.
+ // true
+ var path = dojo.moduleUrl(moduleName).path;
+ // TODO:
+ // this needs to be done better, this is pretty simple and
+ // surely not dummy proof
+ var file = path.substring(0, path.length-1)+".js";
+ var xhr = dojo.xhrGet({url:file, handleAs:"text"});
+ // Make loading synchronously, mainly so we can use it in doh.
+ var data = dojo._getText(file);
+ return this._getTestsFromString(data, true);
+ },
+
+ getTestsFromString:function(/*String*/data){
+ // examples:
+ // >>> (new dojox.testing.DocTest().getTestsFromString(">>> 1+1\n2\n>>> 2+2\n4")).length // Do tests from strings get detected properly?
+ // 2
+ return this._getTestsFromString(data, false);
+ },
+
+ _getTestsFromString:function(/*String*/data, /*Boolean*/insideComments){
+ // summary: Parse the given string for tests.
+ // insideComments: Boolean, if false "data" contains only the pure tests, comments already stripped.
+ var trim = dojo.hitch(dojo.string, "trim");
+ var lines = data.split("\n");
+ var len = lines.length;
+ var tests = [];
+ var test = {
+ commands: [],
+ expectedResult: [],
+ line: null
+ };
+ for(var i=0; i<len+1; i++){
+ // Trim the line, so we don't have to worry about leading
+ // spaces or tabs, bla bla ...
+ var l = trim(lines[i] || ""); // The '|| ""' makes sure tests that have no preceeding \n are taken into account too.
+ // TODO:
+ // detect tests that dont match the condition: commands,
+ // result, empty line. esp the empty line might be missing
+ // or be tolerant and accept a new test starting on the
+ // next line, which would allow to omit the empty line!?
+ if((insideComments && l.match(/^\/\/\s+>>>\s.*/)) || l.match(/^\s*>>>\s.*/)){
+ if(!test.line){
+ test.line = i+1;
+ }
+ // Find the test commands.
+ if(test.expectedResult.length>0){
+ // Start a new test right after the expected result,
+ // without an empty line.
+ tests.push({
+ commands: test.commands,
+ expectedResult: test.expectedResult.join("\n"),
+ line: test.line
+ });
+ test = {commands:[], expectedResult:[], line:i+1};
+ }
+ l = insideComments ? trim(l).substring(2, l.length) : l; // Remove the leading slashes.
+ l = trim(l).substring(3, l.length); // Remove the ">>>".
+ test.commands.push(trim(l));
+ }else if((!insideComments || l.match(/^\/\/\s+.*/)) && test.commands.length && test.expectedResult.length==0){
+ // Detect the lines after the ">>>"-lines, the exptected result.
+ l = insideComments ? trim(l).substring(3, l.length) : l; // Remove the leading slashes.
+ test.expectedResult.push(trim(l));
+ }else if(test.commands.length>0 && test.expectedResult.length){
+ if(!insideComments || l.match(/^\/\/\s*$/)){
+ // Detect the empty line.
+ tests.push({
+ commands: test.commands,
+ expectedResult: test.expectedResult.join("\n"),
+ line: test.line
+ });
+ }
+ if(insideComments && !l.match(/^\/\//)){
+ // If the next line is not a comment at all (doesn't start with "//").
+ tests.push({
+ commands: test.commands,
+ expectedResult: test.expectedResult.join("\n"),
+ line:test.line
+ });
+ }
+ test = {
+ commands: [],
+ expectedResult: [],
+ line:0
+ };
+ }
+ }
+ return tests;
+ },
+
+ run: function(moduleName){
+ // summary:
+ // Run the doctests in the module given.
+ // example:
+ // doctest = new dojox.testing.DocTest();
+ // doctest.run("dojox.testing.DocTest");
+ // doctest.errors should finally be an empty array.
+ // // The above is not a doctest, because it just would
+ // // execute itself in a never ending loop.
+ //
+ // >>> true==true // Test a new line terminating the test.
+ // true
+ //
+ // >>> true==true // Test a new test terminating the test.
+ // true
+ // >>> true==true // Test a "not a comment"-line, especially an empty line terminating the test.
+ // true
+
+ // Make sure the result as printed on the console is the same as what
+ // is returned by the test. An array is printed as follows on the console.
+ // >>> [1,2,3,4]
+ // [1,2,3,4]
+ //
+ // Test a "not a comment"-line, with some real code(!) terminating the test.
+ // This used to be a bug, so make sure the line below the test is real
+ // from this method! Don't write a test after it, always above!
+ // >>> true==true // Test code on new line terminating the test.
+ // true
+
+ this.errors = [];
+
+ var tests = this.getTests(moduleName);
+ if(tests){
+ this._run(tests);
+ }
+ },
+
+ _run: function(/*Array*/tests){
+ // summary:
+ // Each element in the array contains the test in the first element,
+ // and the expected result in the second element.
+ // tests:
+ // Make sure that the types are compared properly. There used to be
+ // the bug that a return value false was compared to "false" which
+ // made the test fail. This is fixed and should be verified by the
+ // following tests.
+ // >>> false
+ // false
+ //
+ // >>> "false"
+ // "false"
+ //
+ // >>> true
+ // true
+ //
+ // >>> 1
+ // 1
+ //
+ // >>> "s"
+ // "s"
+ //
+ // >>> dojo.toJson({one:1})
+ // "{"one":1}"
+ //
+ var len = tests.length;
+ this.tests = len;
+ var oks = 0;
+ for(var i=0; i<len; i++){
+ var t = tests[i];
+ var res = this.runTest(t.commands, t.expectedResult);
+ var msg = "Test "+(i+1)+": ";
+ var viewCommands = t.commands.join(" ");
+ // Show the first part of the test command.
+ viewCommands = (viewCommands.length > 50 ?
+ viewCommands.substr(0,50) + "..." :
+ viewCommands
+ );
+ if(res.success){
+ // the last if-condition, dojo.toJson() adds a quote sign "
+ // before and after the result, may be we remove it and
+ // test the result again
+ console.info(msg+"OK: "+viewCommands);
+ oks += 1;
+ }else{
+ this.errors.push({
+ commands: t.commands,
+ actual: res.actualResult,
+ expected: t.expectedResult
+ });
+ console.error(msg+"Failed: "+viewCommands, {
+ commands: t.commands,
+ actualResult: res.actualResult,
+ expectedResult: t.expectedResult
+ });
+ }
+ }
+ console.info(len+" tests ran.", oks+" Success,", this.errors.length+" Errors");
+ },
+
+ runTest: function(commands, expected){
+ var ret = {
+ success: false,
+ actualResult: null
+ };
+ // Concat multiple commands with new lines, so "//" comments at
+ // the end of a line don't deactivate the next line (which it
+ // would if we only concatenated with ";").
+ var cmds = commands.join("\n");
+ ret.actualResult = eval(cmds);
+ if( (String(ret.actualResult)==expected) ||
+ (dojo.toJson(ret.actualResult)==expected) ||
+ (
+ (expected.charAt(0)=='"')&&
+ (expected.charAt(expected.length-1)=='"')&&
+ (String(ret.actualResult)==expected.substring(1, expected.length-1))
+ )
+ ){
+ // the last if-condition, dojo.toJson() adds a quote sign "
+ // before and after the result, may be we remove it and test
+ // the result again
+ ret.success = true;
+ }
+ return ret;
+ }
+ }
+);
+
+}
+
+}};});