Merge pull request #117 from jannon/SmartTestRunner

Upgrade testing framework
This commit is contained in:
Jannon Frank 2012-05-06 03:59:43 -07:00
commit 7d97a17421
290 changed files with 20075 additions and 2299 deletions

View File

@ -72,12 +72,18 @@ JavaScript. Luckily it comes with a full-on debugger included that can be much
more useful than a simple stack trace. To invoke JSDoc with the debugger try the more useful than a simple stack trace. To invoke JSDoc with the debugger try the
following command: following command:
jsdoc --debug
or the long form version:
$ java -classpath lib/js.jar \ $ java -classpath lib/js.jar \
org.mozilla.javascript.tools.debugger.Main -debug \ org.mozilla.javascript.tools.debugger.Main -debug \
-modules node_modules -modules rhino_modules -modules . \ -modules node_modules -modules rhino_modules -modules . \
jsdoc.js \ jsdoc.js \
your/script.js your/script.js
Note: ```--debug``` must be the first argument to the short form command
This will open a debugging window. Choose "Break on Exceptions" from the "Debug" This will open a debugging window. Choose "Break on Exceptions" from the "Debug"
menu, then press the "Run" button. If there is an error, you should see exactly menu, then press the "Run" button. If there is an error, you should see exactly
where it is in the source code. where it is in the source code.

21
jsdoc
View File

@ -4,6 +4,23 @@
SOURCE="$0" SOURCE="$0"
while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done
BASEDIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" BASEDIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
java -classpath ${BASEDIR}/lib/js.jar org.mozilla.javascript.tools.shell.Main -modules ${BASEDIR}/node_modules -modules ${BASEDIR}/rhino_modules -modules ${BASEDIR} ${BASEDIR}/jsdoc.js --dirname=${BASEDIR} $@
#java -classpath ${BASEDIR}/lib/js.jar org.mozilla.javascript.tools.debugger.Main -debug -modules ${BASEDIR}/node_modules -modules ${BASEDIR}/rhino_modules -modules ${BASEDIR} ${BASEDIR}/jsdoc.js --dirname=${BASEDIR} $@ if test $1 = "--debug"
then
CMD="org.mozilla.javascript.tools.debugger.Main -debug"
shift
else
CMD="org.mozilla.javascript.tools.shell.Main"
fi
#Conditionally execute different command lines depending on whether we're running tests or not
if test $1 = "-T"
then
echo "Running Tests"
java -classpath ${BASEDIR}/lib/js.jar ${CMD} -opt -1 -modules ${BASEDIR}/node_modules -modules ${BASEDIR}/rhino_modules -modules ${BASEDIR} ${BASEDIR}/jsdoc.js --dirname=${BASEDIR} $@
else
echo "Running Normal"
java -classpath ${BASEDIR}/lib/js.jar ${CMD} -modules ${BASEDIR}/node_modules -modules ${BASEDIR}/rhino_modules -modules ${BASEDIR} ${BASEDIR}/jsdoc.js --dirname=${BASEDIR} $@
fi
#java -classpath ${BASEDIR}/lib/js.jar ${CMD} -modules ${BASEDIR}/node_modules -modules ${BASEDIR}/rhino_modules -modules ${BASEDIR} ${BASEDIR}/jsdoc.js --dirname=${BASEDIR} $@

View File

@ -82,8 +82,9 @@ try { main(); }
catch(e) { catch(e) {
if (e.rhinoException != null) { if (e.rhinoException != null) {
e.rhinoException.printStackTrace(); e.rhinoException.printStackTrace();
} } else {
else throw e; throw e;
}
} }
finally { env.run.finish = new Date(); } finally { env.run.finish = new Date(); }
@ -128,6 +129,33 @@ function exit(n) {
java.lang.System.exit(n); java.lang.System.exit(n);
} }
function installPlugins(plugins, p) {
var dictionary = require('jsdoc/tag/dictionary'),
parser = p || app.jsdoc.parser;
// allow user-defined plugins to...
for (var i = 0, leni = plugins.length; i < leni; i++) {
var plugin = require(plugins[i]);
//...register event handlers
if (plugin.handlers) {
for (var eventName in plugin.handlers) {
parser.on(eventName, plugin.handlers[eventName]);
}
}
//...define tags
if (plugin.defineTags) {
plugin.defineTags(dictionary);
}
//...add a node visitor
if (plugin.nodeVisitor) {
parser.addNodeVisitor(plugin.nodeVisitor);
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
@ -144,7 +172,6 @@ function main() {
} }
}, },
resolver, resolver,
dictionary = require('jsdoc/tag/dictionary'),
fs = require('fs'); fs = require('fs');
env.opts = jsdoc.opts.parser.parse(env.args); env.opts = jsdoc.opts.parser.parse(env.args);
@ -192,34 +219,13 @@ function main() {
if (env.opts.help) { if (env.opts.help) {
console.log( jsdoc.opts.parser.help() ); console.log( jsdoc.opts.parser.help() );
exit(0); exit(0);
} } else if (env.opts.test) {
else if (env.opts.test) {
include('test/runner.js'); include('test/runner.js');
exit(0); exit(0);
} }
// allow user-defined plugins to...
if (env.conf.plugins) { if (env.conf.plugins) {
for (var i = 0, leni = env.conf.plugins.length; i < leni; i++) { installPlugins(env.conf.plugins);
var plugin = require(env.conf.plugins[i]);
//...register event handlers
if (plugin.handlers) {
for (var eventName in plugin.handlers) {
app.jsdoc.parser.on(eventName, plugin.handlers[eventName]);
}
}
//...define tags
if (plugin.defineTags) {
plugin.defineTags(dictionary);
}
//...add a node visitor
if (plugin.nodeVisitor) {
app.jsdoc.parser.addNodeVisitor(plugin.nodeVisitor);
}
}
} }
// any source file named package.json is treated special // any source file named package.json is treated special

View File

@ -33,4 +33,3 @@ process = {
}, },
argv: [__dirname + '/jsdoc.js'].concat(Array.prototype.slice.call(arguments, 0)) argv: [__dirname + '/jsdoc.js'].concat(Array.prototype.slice.call(arguments, 0))
}; };

67
node_modules/common/args.js generated vendored
View File

@ -14,21 +14,23 @@
*/ */
exports.ArgParser = function() { exports.ArgParser = function() {
this._options = []; this._options = [];
} this._shortNameIndex = {};
this._longNameIndex = {};
};
exports.ArgParser.prototype._getOptionByShortName = function(name) { exports.ArgParser.prototype._getOptionByShortName = function(name) {
for (var i = this._options.length; i--;) { if (this._shortNameIndex.hasOwnProperty(name)) {
if (this._options[i].shortName === name) { return this._options[i]; } return this._options[this._shortNameIndex[name]];
} }
return null; return null;
} };
exports.ArgParser.prototype._getOptionByLongName = function(name) { exports.ArgParser.prototype._getOptionByLongName = function(name) {
for (var i = this._options.length; i--;) { if (this._longNameIndex.hasOwnProperty(name)) {
if (this._options[i].longName === name) { return this._options[i]; } return this._options[this._longNameIndex[name]];
} }
return null; return null;
} };
/** /**
* Provide information about a legal option. * Provide information about a legal option.
@ -40,8 +42,14 @@
* myParser.addOption('t', 'template', true, 'The path to the template.'); * myParser.addOption('t', 'template', true, 'The path to the template.');
* myParser.addOption('h', 'help', false, 'Show the help message.'); * myParser.addOption('h', 'help', false, 'Show the help message.');
*/ */
exports.ArgParser.prototype.addOption = function(shortName, longName, hasValue, helpText) { exports.ArgParser.prototype.addOption = function(shortName, longName, hasValue, helpText, canHaveMultiple) {
this._options.push({shortName: shortName, longName: longName, hasValue: hasValue, helpText: helpText}); this._options.push({shortName: shortName, longName: longName, hasValue: hasValue, helpText: helpText, canHaveMultiple: (canHaveMultiple || false)});
if (shortName) {
this._shortNameIndex[shortName] = this._options.length - 1;
}
if (longName) {
this._longNameIndex[longName] = this._options.length - 1;
}
}; };
/** /**
@ -49,28 +57,30 @@
@returns {string} @returns {string}
*/ */
exports.ArgParser.prototype.help = function() { exports.ArgParser.prototype.help = function() {
var help = 'OPTIONS:\n', var helpArr = ['OPTIONS:'],
option; option, optionHelp;
for (var i = 0, leni = this._options.length; i < leni; i++) { for (var i = 0, leni = this._options.length; i < leni; i++) {
option = this._options[i]; option = this._options[i];
optionHelp = '\t';
if (option.shortName) { if (option.shortName) {
help += '-' + option.shortName + (option.longName? ' or ' : ''); optionHelp += '-' + option.shortName + (option.longName ? ', ' : '');
} }
if (option.longName) { if (option.longName) {
help += '--' + option.longName; optionHelp += '--' + option.longName;
} }
if (option.hasValue) { if (option.hasValue) {
help += ' <value>'; optionHelp += ' <value>';
} }
help += ' ' + option.helpText + '\n'; optionHelp += '\t\t' + option.helpText;
helpArr.push(optionHelp);
} }
return help; return helpArr.join('\n');
}; };
/** /**
@ -82,15 +92,15 @@
provided, or `true` if the option accepts no value. provided, or `true` if the option accepts no value.
*/ */
exports.ArgParser.prototype.parse = function(args, defaults) { exports.ArgParser.prototype.parse = function(args, defaults) {
var result = defaults || {}; var util = require('common/util'),
result = defaults && util.mixin({}, defaults) || {};
result._ = []; result._ = [];
for (var i = 0, leni = args.length; i < leni; i++) { for (var i = 0, leni = args.length; i < leni; i++) {
var arg = '' + args[i], var arg = '' + args[i],
next = (i < leni-1)? '' + args[i+1] : null, next = (i < leni-1)? '' + args[i+1] : null,
option, option,
shortName, shortName = null,
longName, longName,
name, name,
value = null; value = null;
@ -128,7 +138,18 @@
name = option.longName; name = option.longName;
} }
result[name] = value; // Allow for multiple options of the same type to be present
if (option.canHaveMultiple && result.hasOwnProperty(name)) {
var val = result[name];
if (val instanceof Array) {
val.push(value);
} else {
result[name] = [val, value];
}
}
else {
result[name] = value;
}
} }
else { else {
result._.push(arg); result._.push(arg);
@ -136,5 +157,5 @@
} }
return result; return result;
} };
})(); })();

View File

@ -342,3 +342,32 @@ Lastly, the visitors are executed in the order the plugins are listed in the
conf.json file. A plugin can stop later plugins from visiting a node by conf.json file. A plugin can stop later plugins from visiting a node by
setting a ```stopPropagation``` property on the event object (e.stopPropagation = true). setting a ```stopPropagation``` property on the event object (e.stopPropagation = true).
A plugin can stop the event from firing setting a ```preventDefault``` property. A plugin can stop the event from firing setting a ```preventDefault``` property.
Packaging JSDoc 3 Plugins
----
The JSDoc 3 Jakefile has an ```install``` task that can be used to install a plugin
into the jsdoc 3 installation. So running the following will install the plugin:
$>jake install[path/to/YourPluginFolder]
_note: on some systems (like MacOS X), you may need to quote the target name and parameters_:
$>jake 'install[path/to/YourPluginFolder]'
The task is passed a directory that should look something like the following:
YourPluginFolder
|- plugins
| |- YourPlugin.js
| \- test
| |- fixtures
| | \- YourFixtures.js
| \- specs
| \- YourTests.js
\- templates
\- YourTemplate
\- publish.js
Basically everything is copied over into the jsdoc installation directory, the
directory should contain anything you want to put there.

View File

@ -1,6 +1,6 @@
/** /**
@overview Demonstrate how to modify the source code before the parser sees it. @overview Demonstrate how to modify the source code before the parser sees it.
@module plugins/comentConvert @module plugins/commentConvert
@author Michael Mathews <micmath@gmail.com> @author Michael Mathews <micmath@gmail.com>
*/ */

View File

@ -8,6 +8,7 @@
exports.handlers = { exports.handlers = {
/** /**
Translate HTML tags in descriptions into safe entities. Translate HTML tags in descriptions into safe entities.
Replaces <, & and newlines
*/ */
newDoclet: function(e) { newDoclet: function(e) {
if (e.doclet.description) { if (e.doclet.description) {

View File

@ -6,12 +6,12 @@
exports.handlers = { exports.handlers = {
/// /**
/// Remove rails tags from the source input (e.g. <% foo bar %>) * Remove rails tags from the source input (e.g. <% foo bar %>)
/// @param e * @param e
/// @param e.filename * @param e.filename
/// @param e.source * @param e.source
/// */
beforeParse: function(e) { beforeParse: function(e) {
if (e.filename.match(/\.erb$/)) { if (e.filename.match(/\.erb$/)) {
e.source = e.source.replace(/<%.*%>/g, ""); e.source = e.source.replace(/<%.*%>/g, "");

View File

@ -8,6 +8,7 @@ exports.handlers = {
Support @source tag. Expected value like: Support @source tag. Expected value like:
{ "filename": "myfile.js", "lineno": 123 } { "filename": "myfile.js", "lineno": 123 }
Modifies the corresponding meta values on the given doclet. Modifies the corresponding meta values on the given doclet.
@source { "filename": "sourcetag.js", "lineno": 13 }
*/ */
newDoclet: function(e) { newDoclet: function(e) {
var tags = e.doclet.tags, var tags = e.doclet.tags,

View File

@ -0,0 +1,20 @@
/**
@overview Strips the rails template tags from a js.erb file
@module plugins/railsTemplate
@author Jannon Frank <jannon@jannon.net>
*/
exports.handlers = {
/**
* Remove rails tags from the source input (e.g. <% foo bar %>)
* @param e
* @param e.filename
* @param e.source
*/
beforeParse: function(e) {
if (e.filename.match(/\.erb$/)) {
e.source = e.source.replace(/<%.*%> /g, "");
}
}
};

View File

@ -0,0 +1,13 @@
describe("commentConvert plugin", function() {
var parser = new (require("jsdoc/src/parser")).Parser(),
plugin = require('plugins/commentConvert'),
docSet;
installPlugins(['plugins/commentConvert'], parser);
docSet = jasmine.getDocSetFromFile("plugins/commentConvert.js", parser);
it("should convert '///-style comments into jsdoc comments", function() {
var doclet = docSet.getByLongname("module:plugins/commentConvert.handlers.beforeParse");
expect(doclet.length).toEqual(1);
});
});

View File

@ -0,0 +1,13 @@
describe("escapeHtml plugin", function() {
var parser = new (require("jsdoc/src/parser")).Parser(),
plugin = require('plugins/escapeHtml'),
docSet;
installPlugins(['plugins/escapeHtml'], parser);
docSet = jasmine.getDocSetFromFile("plugins/escapeHtml.js", parser);
it("should escape '&', '<' and newlines in doclet descriptions", function() {
var doclet = docSet.getByLongname("module:plugins/escapeHtml.handlers.newDoclet");
expect(doclet[0].description).toEqual("Translate HTML tags in descriptions into safe entities.<br> Replaces &lt;, &amp; and newlines");
});
});

View File

@ -0,0 +1,22 @@
/**
@overview Translate doclet descriptions from MarkDown into HTML.
@module plugins/markdown
@author Michael Mathews <micmath@gmail.com>
*/
var mdParser = require('evilstreak/markdown');
exports.handlers = {
/**
Translate markdown syntax in a new doclet's description into HTML. Is run
by JSDoc 3 whenever a "newDoclet" event fires.
*/
newDoclet: function(e) {
if (e.doclet.description) {
e.doclet.description = mdParser.toHTML(e.doclet.description)
.replace( /&amp;/g, "&" ) // because markdown escapes these
.replace( /&lt;/g, "<" )
.replace( /&gt;/g, ">" );
}
}
};

View File

@ -0,0 +1,15 @@
describe("railsTemplate plugin", function() {
var parser = new (require("jsdoc/src/parser")).Parser(),
plugin = require('plugins/railsTemplate');
installPlugins(['plugins/railsTemplate'], parser);
require('jsdoc/src/handlers').attachTo(parser);
it("should remove <% %> rails template tags from the source of *.erb files", function() {
var path = require("path"),
docSet = parser.parse([path.join(__dirname, "plugins/test/fixtures/railsTemplate.js.erb")]);
expect(docSet[2].description).toEqual("Remove rails tags from the source input (e.g. )");
});
});

View File

@ -0,0 +1,13 @@
describe("shout plugin", function() {
var parser = new (require("jsdoc/src/parser")).Parser(),
plugin = require('plugins/shout'),
docSet;
installPlugins(['plugins/shout'], parser);
docSet = jasmine.getDocSetFromFile("plugins/shout.js", parser);
it("should make the description uppercase", function() {
var doclet = docSet.getByLongname("module:plugins/shout.handlers.newDoclet");
expect(doclet[0].description).toEqual("MAKE YOUR DESCRIPTIONS MORE SHOUTIER.");
});
});

View File

@ -0,0 +1,15 @@
describe("sourcetag plugin", function() {
var parser = new (require("jsdoc/src/parser")).Parser(),
plugin = require('plugins/sourcetag'),
docSet;
installPlugins(['plugins/sourcetag'], parser);
docSet = jasmine.getDocSetFromFile("plugins/sourcetag.js", parser);
it("should set the lineno and filename of the doclet's meta property", function() {
var doclet = docSet.getByLongname("module:plugins/sourcetag.handlers.newDoclet");
expect(doclet[0].meta).toBeDefined();
expect(doclet[0].meta.filename).toEqual("sourcetag.js");
expect(doclet[0].meta.lineno).toEqual(13);
});
});

View File

@ -13,6 +13,11 @@ var readdirSync = exports.readdirSync = function(path) {
files = dir.list(); files = dir.list();
//Convert files to Javascript strings so they play nice with node modules
files = files.map(function(fileName) {
return String(fileName);
});
return files; return files;
}; };
@ -58,21 +63,21 @@ var ls = exports.ls = function(dir, recurse, _allFiles, _path) {
return _allFiles; return _allFiles;
}; };
var stat = exports.stat = function(path, encoding) { var stat = exports.stat = exports.statSync = function(path, encoding) {
var f = new java.io.File(path) var f = new java.io.File(path);
return { return {
isFile: function() { isFile: function() {
return f.isFile(); return f.isFile();
}, },
isDir: function() { isDirectory: function() {
return f.isDirectory(); return f.isDirectory();
} }
} };
}; };
exports.mkPath = function(/**Array*/ path) { exports.mkPath = function(/**Array*/ path) {
if (path.constructor != Array) path = path.split(/[\\\/]/); if (path.constructor != Array){path = path.split(/[\\\/]/);}
var make = ""; var make = "";
for (var i = 0, l = path.length; i < l; i++) { for (var i = 0, l = path.length; i < l; i++) {
make += path[i] + '/'; make += path[i] + '/';
@ -116,7 +121,7 @@ var toDir = exports.toDir = function(path) {
}; };
exports.copyFile = function(inFile, outDir, fileName) { exports.copyFile = function(inFile, outDir, fileName) {
if (fileName == null) fileName = toFile(inFile); if (fileName == null){fileName = toFile(inFile);}
outDir = toDir(outDir); outDir = toDir(outDir);
@ -136,7 +141,7 @@ exports.copyFile = function(inFile, outDir, fileName) {
var toFile = exports.toFile = function(path) { var toFile = exports.toFile = function(path) {
var parts = path.split(/[\\\/]/); var parts = path.split(/[\\\/]/);
return parts.pop(); return parts.pop();
} };
exports.writeFileSync = function(filename, data, encoding) { exports.writeFileSync = function(filename, data, encoding) {
encoding = encoding || 'utf-8'; encoding = encoding || 'utf-8';

View File

@ -27,9 +27,13 @@ argParser.addOption('X', 'explain', false, 'Dump all found doclet internals
argParser.addOption('q', 'query', true, 'Provide a querystring to define custom variable names/values to add to the options hash.'); argParser.addOption('q', 'query', true, 'Provide a querystring to define custom variable names/values to add to the options hash.');
argParser.addOption('u', 'tutorials', true, 'Directory in which JSDoc should search for tutorials.'); argParser.addOption('u', 'tutorials', true, 'Directory in which JSDoc should search for tutorials.');
//TODO [-R, recurseonly] = a number representing the depth to recurse
//TODO [-f, filter] = a regex to filter on <-- this can be better defined in the configs?
// TODO [-R, recurseonly] = a number representing the depth to recurse //Here are options specific to tests
// TODO [-f, filter] = a regex to filter on <-- this can be better defined in the configs? argParser.addOption(null, 'verbose', false, 'Display verbose output for tests');
argParser.addOption(null, 'match', true, 'only run tests containing <value>', true);
argParser.addOption(null, 'coffee', false, 'load coffee-script which allows execution .coffee files');
/** /**
Set the options for this app. Set the options for this app.

View File

@ -183,5 +183,5 @@ exports.attachTo = function(parser) {
} }
} }
} }
} };

View File

@ -25,7 +25,7 @@ exports.Parser = function() {
} }
}; };
this._visitors = []; this._visitors = [];
} };
require('common/util').mixin(exports.Parser.prototype, require('common/events')); require('common/util').mixin(exports.Parser.prototype, require('common/events'));
/** /**
@ -72,7 +72,7 @@ exports.Parser.prototype.parse = function(sourceFiles, encoding) {
} }
return this._resultBuffer; return this._resultBuffer;
} };
/** /**
* @returns {Array<Doclet>} The accumulated results of any calls to parse. * @returns {Array<Doclet>} The accumulated results of any calls to parse.

View File

@ -1,11 +1,29 @@
var isWindows = java.lang.System.getProperty("os.name").toLowerCase().contains("windows");
var fileSeparator = java.lang.System.getProperty("file.separator");
/**
* Returns everything on a path except for the last item
* e.g. if the path was 'path/to/something', the return value would be 'path/to'
*/
exports.basename = function(path) { exports.basename = function(path) {
var parts = path.split('/'); var parts = path.split(fileSeparator);
parts.pop(); parts.pop();
path = parts.join('/'); path = parts.join(fileSeparator);
return path; return path;
}; };
/**
* Returns the last item on a path
*/
exports.filename = function(path) {
var parts = path.split(fileSeparator);
if (parts.length > 0) {
return parts.pop();
}
return null;
};
exports.existsSync = function(path) { exports.existsSync = function(path) {
var file = new java.io.File(path); var file = new java.io.File(path);
@ -15,3 +33,114 @@ exports.existsSync = function(path) {
return false; return false;
}; };
//Code below taken from node
//resolves . and .. elements in a path array with directory names there
//must be no slashes, empty elements, or device names (c:\) in the array
//(so also no leading and trailing slashes - it does not distinguish
//relative and absolute paths)
function normalizeArray(parts, allowAboveRoot) {
// if the path tries to go above the root, `up` ends up > 0
var up = 0;
for ( var i = parts.length - 1; i >= 0; i--) {
var last = parts[i];
if (last == '.') {
parts.splice(i, 1);
} else if (last === '..') {
parts.splice(i, 1);
up++;
} else if (up) {
parts.splice(i, 1);
up--;
}
}
// if the path is allowed to go above the root, restore leading ..s
if (allowAboveRoot) {
for (; up--; up) {
parts.unshift('..');
}
}
return parts;
}
if (isWindows) {
// Regex to split a windows path into three parts: [*, device, slash,
// tail] windows-only
var splitDeviceRe =
/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?([\\\/])?([\s\S]*?)$/;
// windows version
exports.normalize = function(path) {
var result = splitDeviceRe.exec(path),
device = result[1] || '',
isUnc = device && device.charAt(1) !== ':',
isAbsolute = !!result[2] || isUnc, // UNC paths are always absolute
tail = result[3],
trailingSlash = /[\\\/]$/.test(tail);
// Normalize the tail path
tail = normalizeArray(tail.split(/[\\\/]+/).filter(function(p) {
return !!p;
}), !isAbsolute).join('\\');
if (!tail && !isAbsolute) {
tail = '.';
}
if (tail && trailingSlash) {
tail += '\\';
}
return device + (isAbsolute ? '\\' : '') + tail;
};
//windows version
exports.join = function() {
function f(p) {
return p && typeof p === 'string';
}
var paths = Array.prototype.slice.call(arguments, 0).filter(f);
var joined = paths.join('\\');
// Make sure that the joined path doesn't start with two slashes
// - it will be mistaken for an unc path by normalize() -
// unless the paths[0] also starts with two slashes
if (/^[\\\/]{2}/.test(joined) && !/^[\\\/]{2}/.test(paths[0])) {
joined = joined.slice(1);
}
return exports.normalize(joined);
};
} else {
// path.normalize(path)
// posix version
exports.normalize = function(path) {
var isAbsolute = path.charAt(0) === '/',
trailingSlash = path.slice(-1) === '/';
// Normalize the path
path = normalizeArray(path.split('/').filter(function(p) {
return !!p;
}), !isAbsolute).join('/');
if (!path && !isAbsolute) {
path = '.';
}
if (path && trailingSlash) {
path += '/';
}
return (isAbsolute ? '/' : '') + path;
};
// posix version
exports.join = function() {
var paths = Array.prototype.slice.call(arguments, 0);
return exports.normalize(paths.filter(function(p, index) {
return p && typeof p === 'string';
}).join('/'));
};
}

View File

@ -1,7 +1,45 @@
From the project root, run the following command in the terminal: Testing JSDoc 3
===============
java -jar lib/js.jar -modules rhino_modules -modules node_modules jsdoc.js -T Running Tests
-------------
TODO: Running tests is easy. Just change your working directory to the jsdoc folder
and run the following command on Windows:
More info for contributors about how tests work and about plugin/template tests jsdoc -T
... or on a Max OSX or *nix platform:
./jsdoc -T
If you can't get the short-form commands to work, try invoking Java directly:
java -cp lib/js.jar org.mozilla.javascript.tools.shell.Main -opt -1 \
-modules node_modules -modules rhino_modules -modules . \
jsdoc.js -T
Writing Tests
-------------
Adding tests is pretty easy, too. You can write tests for jsdoc itself (to
make sure tags and the parser, etc. are working properly), tests for plugins, and/or
tests for templates.
JSDoc 3 uses Jasmine (https://github.com/pivotal/jasmine) as its testing framework.
Take a look at that project's wiki for documentation on writing tests in general.
### Tests for JSDoc
Take a look at the files in the ```test``` directory for many examples of
writing tests for JSDoc itself. the ```test\fixtures``` directory hold fixtures
for use in the tests and the ```test\specs``` directory holds the tests themselves.
### Tests for plugins
Tests for plugins are found in ```plugins\test``` directory. Plugins containing
tests that were installed with the Jakefile install task will be run automatically.
### Tests for templates
TODO

56
test/async-callback.js Normal file
View File

@ -0,0 +1,56 @@
(function() {
var withoutAsync = {};
["it", "beforeEach", "afterEach"].forEach(function(jasmineFunction) {
withoutAsync[jasmineFunction] = jasmine.Env.prototype[jasmineFunction];
return jasmine.Env.prototype[jasmineFunction] = function() {
var args = Array.prototype.slice.call(arguments, 0);
var timeout = null;
if (isLastArgumentATimeout(args)) {
timeout = args.pop();
}
if (isLastArgumentAnAsyncSpecFunction(args))
{
var specFunction = args.pop();
args.push(function() {
return asyncSpec(specFunction, this, timeout);
});
}
return withoutAsync[jasmineFunction].apply(this, args);
};
});
function isLastArgumentATimeout(args)
{
return args.length > 0 && (typeof args[args.length-1]) === "number";
}
function isLastArgumentAnAsyncSpecFunction(args)
{
return args.length > 0 && (typeof args[args.length-1]) === "function" && args[args.length-1].length > 0;
}
function asyncSpec(specFunction, spec, timeout) {
if (timeout == null){timeout = jasmine.DEFAULT_TIMEOUT_INTERVAL || 1000;}
var done = false;
spec.runs(function() {
try {
return specFunction(function(error) {
done = true;
if (error != null) {
return spec.fail(error);
}
});
} catch (e) {
done = true;
throw e;
}
});
return spec.waitsFor(function() {
if (done === true) {
return true;
}
}, "spec to complete", timeout);
};
}).call(this);

View File

@ -1,4 +0,0 @@
// Simple inheritance model with correct constructor
function Test() {}
function Test2() { Test.call(this); }
Test2.prototype = Object.create(Test.prototype, {constructor: {value: Test2}});

View File

@ -1,17 +0,0 @@
Call(
{
methodA: function()
{
this.id = this.createUUID();
},
valueOf: function()
{
return this.id;
},
toString: function()
{
return this.id;
}
});

22
test/fixtures/objectpropertykeys.js vendored Normal file
View File

@ -0,0 +1,22 @@
Call(
{
methodA: function()
{
this.id = this.createUUID();
},
valueOf: function()
{
return this.id;
},
toString: function()
{
return this.id;
}
});
//Simple inheritance model with correct constructor
function Test() {}
function Test2() { Test.call(this); }
Test2.prototype = Object.create(Test.prototype, {constructor: {value: Test2}});

10
test/fixtures/plugins.js vendored Normal file
View File

@ -0,0 +1,10 @@
/**
* @name virtual
*/
var foo = "bar";
/**
* @foo bar
*/
var test = "tada";

Some files were not shown because too many files have changed in this diff Show More