Skip to content
This repository has been archived by the owner on Aug 16, 2020. It is now read-only.

Commit

Permalink
deployment 786516a
Browse files Browse the repository at this point in the history
  • Loading branch information
ianb committed Apr 11, 2013
1 parent 0fed5ef commit b315102
Show file tree
Hide file tree
Showing 14 changed files with 155 additions and 178 deletions.
38 changes: 38 additions & 0 deletions bin/doctest
@@ -0,0 +1,38 @@
#!/usr/bin/env node

var path = require('path');
var fs = require('fs');
var root = path.join(path.dirname(fs.realpathSync(__filename)), '..');

// FIXME: Not sure this is the best way to go about this, or if we should
// just require("doctest")?
var doctest = require(root + '/doctest');

function main(filename) {
var runner = new doctest.Runner({Reporter: doctest.ConsoleReporter});
runner.globs = runner.evalInit();
var parser = new doctest.TextParser.fromFile(runner, process.argv[2]);
parser.parse();
runner.run();

var reporter = runner.reporter;
return reporter;
}

function showReport(reporter) {
console.log('Successes:', reporter.successes);
console.log('Failures:', reporter.failures);
if ((! reporter.successes) || reporter.failures) {
// Set exit code to number of failures (if any). It gives a nice failures
// summary when running under make. E.g.: `make: *** [doctest] Error 2`
process.exit(reporter.failures || 1);
}
}

var filename = process.argv[2];
if (! filename) {
console.log("Error: you did not give a filename");
console.log("Usage:", process.argv[1], "FILENAME");
process.exit(500);
}
showReport(main(filename));
68 changes: 53 additions & 15 deletions doctest.js
Expand Up @@ -51,7 +51,7 @@ Example.prototype = {
this.consoleOutput = [];
var globs = this.runner.evalInit();
try {
this.result = this.runner.evaller(this.expr, globs);
this.result = this.runner.evaller(this.expr, globs, this.filename);
} catch (e) {
if (e['doctest.abort']) {
return;
Expand Down Expand Up @@ -664,7 +664,9 @@ Runner.prototype = {
},

evalInit: function () {
var self = this;
if (typeof this.globs != "undefined") {
return this.globs;
}
this.logGrouped = false;
this._abortCalled = false;
var globs = {
Expand Down Expand Up @@ -695,7 +697,9 @@ Runner.prototype = {
}
}
}
return globs;
var context = require('vm').Script.createContext();
extend(context, globs);
return context;
} else {
extend(console, consoleOverwrites);
window.onerror = this.windowOnerror;
Expand Down Expand Up @@ -817,14 +821,45 @@ Runner.prototype = {
}
},

evaller: function (expr, context) {
evaller: function (expr, context, filename) {
var e = eval;
var result;
if (context) {
if (typeof global != "undefined") {
extend(global, context);
if (typeof window == "undefined") {
var vm = require('vm');
vm.runInThisContext(expr);

if (! (context instanceof vm.Script.createContext().constructor)) {
throw "context must be created with vm.Script.createContext()";
}

// Prepare context to evaluate `expr` in. Mostly follows CoffeeScript
// [eval function](http://git.io/coffee-script-eval).
context.global = context.root = context.GLOBAL = context;
context.__filename = typeof filename != "undefined" ? filename : __filename;
context.__dirname = require('path').dirname(context.__filename);
context.module = module;
context.require = require;

// Set `module.filename` to script file name and evaluate the script.
// Now, if the script executes `require('./something')`, it will look
// up `'./something'` relative to script path.
//
// We restore `module.filename` afterwards, because `module` object
// is reused. The other approach is to create a new `module` instance.
// CoffeeScript [eval][1] [works this way][2]. Unfortunately it
// [uses private Node API][3] to do it.
//
// [1]: http://git.io/coffee-script-eval
// [2]: https://github.com/jashkenas/coffee-script/pull/1487
// [3]: http://git.io/coffee-script-eval-comment
var prevfilename = module.filename;
module.filename = context.__filename;
try {
vm.runInContext(expr, context, context.__filename);
} finally {
module.filename = prevfilename;
}

} else {
with (context) {
result = eval(expr);
Expand Down Expand Up @@ -932,8 +967,10 @@ Runner.prototype = {
examples: null,
Example: Example,
exampleOptions: null,
makeExample: function (text, expected) {
return new this.Example(this, text, expected, this.exampleOptions);
makeExample: function (text, expected, filename) {
var options = {filename: filename};
extend(options, this.exampleOptions);
return new this.Example(this, text, expected, options);
},
matcher: null,
Matcher: Matcher,
Expand Down Expand Up @@ -1245,7 +1282,7 @@ HTMLParser.prototype = {
}
if (! result.length) {
// No sections
return null;
return [{header: '', body: text}];
}
var last = text.substr(pos, text.length-pos);
result[result.length-1].body = last;
Expand All @@ -1254,7 +1291,7 @@ HTMLParser.prototype = {

};

var TextParser = exports.TextParser = function (runner, text) {
var TextParser = exports.TextParser = function (runner, text, filename) {
if (typeof esprima == "undefined") {
if (typeof require != "undefined") {
esprima = require("./esprima/esprima.js");
Expand All @@ -1264,18 +1301,19 @@ var TextParser = exports.TextParser = function (runner, text) {
}
this.runner = runner;
this.text = text;
this.filename = filename;
};

TextParser.fromFile = function (runner, filename) {
if (typeof filename != "string") {
throw "You did you give a filename for the second argument: " + filename;
throw "You did not give a filename for the second argument: " + filename;
}
if (typeof require == "undefined") {
throw "This method only works in Node, with the presence of require()";
}
var fs = require('fs');
var text = fs.readFileSync(filename, 'UTF-8');
return new TextParser(runner, text);
return new TextParser(runner, text, filename);
};

TextParser.prototype = {
Expand All @@ -1296,13 +1334,13 @@ TextParser.prototype = {
var end = comment.range[1];
var example = this.text.substr(pos, start-pos);
var output = comment.value.replace(/^\s*=>\s*/, '');
var ex = this.runner.makeExample(example, output);
var ex = this.runner.makeExample(example, output, this.filename);
this.runner.examples.push(ex);
pos = end;
}
var last = this.text.substr(pos, this.text.length-pos);
if (strip(last)) {
this.runner.examples.push(this.runner.makeExample(last, ''));
this.runner.examples.push(this.runner.makeExample(last, '', this.filename));
}
}
};
Expand Down
6 changes: 3 additions & 3 deletions examples/examples-2.html
Expand Up @@ -28,7 +28,7 @@
Error: whatever
</pre>

<pre class="commenttest">
<pre class="test">
print(1+2)
/* =>
3
Expand All @@ -44,9 +44,9 @@
/* => hey you! */
</pre>

<pre class="commenttest" href="./examples-2.js"></pre>
<pre class="test" href="./examples-2.js"></pre>

<pre class="commenttest">
<pre class="test">
function stop() {
throw Abort();
}
Expand Down
2 changes: 1 addition & 1 deletion examples/long-running-tests.html
Expand Up @@ -16,7 +16,7 @@
<li>sections in the tests that will make them run in sequence</li>
</ul>

<pre class="commenttest" href="long-running-tests.js"></pre>
<pre class="test" href="long-running-tests.js"></pre>

</body>
</html>
12 changes: 0 additions & 12 deletions examples/node-example.js

This file was deleted.

10 changes: 5 additions & 5 deletions index.html
Expand Up @@ -51,7 +51,7 @@ <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->A Humane Javascript

<p>An example (note: these are live examples &mdash; you can also try your own via the <a href="try.html">live demo</a>):

<pre class="commenttest">
<pre class="test">
function capitalize(words) {
return words.replace(/\b[a-z]/g, function (m) {
return m[0].toUpperCase();
Expand All @@ -68,7 +68,7 @@ <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->A Humane Javascript

<p>This is similar to something like <code>assertEqual(capitalize('some words'), 'Some Words')</code> &mdash; there's a kind of "equal" check every time you print something. Instead of doing stuff then testing every detail of what happened or what was returned, testing almost happens for you &mdash; you print out what you are interested in, and you can even punt: you can start by simply exercising everything that matters, and then inspecting that what happens is what you expect, and copying those results into the test. For instance:

<pre class="commenttest">
<pre class="test">
function getProperties(obj) {
var result = [];
for (i in obj) {
Expand All @@ -89,7 +89,7 @@ <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->A Humane Javascript

<p>Look: the first example worked great, <code>["a", "b"]</code>. The second example though wasn't right at all. <code>"0"</code>? Once we have a better idea we can adjust those tests:

<pre class="commenttest">
<pre class="test">
function getProperties(obj) {
var result = [];
for (i in obj) {
Expand Down Expand Up @@ -120,7 +120,7 @@ <h3>Async testing made easy!</h3>

<p>The core feature here is <code>wait()</code> &mdash; this lets you register a callback that will tell the test runner when this block of code is fully finished. An example:

<pre class="commenttest">
<pre class="test">
var now = Date.now();
var done = false;

Expand All @@ -143,7 +143,7 @@ <h3>Mocking with Spy</h3>

<p>In addition there's a simply mocking framework in doctest with Spy. This lets you create a function that records over time it is called &mdash; and each time it is called it prints out how it is called. It also makes it easy to wait on the Spy to be called:

<pre class="commenttest">
<pre class="test">
var button = $('&lt;button>&lt;/button>');
$('body').append(button);
button.click(Spy('button.click'));
Expand Down
7 changes: 5 additions & 2 deletions package.json
@@ -1,7 +1,10 @@
{
"name": "doctest",
"version": "0.3",
"name": "doctestjs",
"version": "0.3.0",
"main": "doctest",
"bin": {
"doctest": "./bin/doctest"
},
"description": "Example-based testing framework",
"keywords": [],
"author": {
Expand Down

0 comments on commit b315102

Please sign in to comment.