Permalink
Browse files

Attempting to get foounit to run in a bunch of different environments

  • Loading branch information...
1 parent b862ce5 commit e792e32fde206c0f25f2b23959e5950767795a1e @foobarfighter committed Oct 13, 2010
Showing with 952 additions and 8 deletions.
  1. +1 −0 lib/foo-unit.js
  2. +4 −4 lib/generator/air.js
  3. +4 −4 lib/node.js
  4. +14 −0 scripts/run_air.sh
  5. +14 −0 scripts/run_node.sh
  6. +12 −0 spec/Spec-app.xml
  7. +64 −0 spec/Spec.html
  8. +64 −0 spec/Spec.html.template
  9. +63 −0 spec/air.js
  10. +533 −0 spec/foo-unit.js
  11. +115 −0 spec/node.js
  12. +55 −0 spec/specs/matchers_spec.js
  13. +9 −0 spec/suite.js
View
1 lib/foo-unit.js
@@ -522,6 +522,7 @@ var foo = (function (){
if (foo.env == 'node.js'){
var node = require(__dirname + '/node');
+ foo.unit.add = node.unit.add || foo.unit.add;
foo.require = node.require;
foo.unit.report = node.unit.report;
foo.unit.run = node.unit.run;
View
8 lib/generator/air.js
@@ -17,10 +17,10 @@ var AirGenerator = function (parsedOptions){
}
this.validate = function (){
- if (fsh.existsSync(this._destinationPath)){
- throw new Error('Cannot generate files because `' +
- this._destinationPath + '` already exists.');
- }
+ // if (fsh.existsSync(this._destinationPath)){
+ // throw new Error('Cannot generate files because `' +
+ // this._destinationPath + '` already exists.');
+ // }
}
this.run = function (){
View
8 lib/node.js
@@ -1,11 +1,8 @@
// TODO: This file provides methods to foo unit but cannot use it directly.
// Is this a problem?
-
var foo = exports;
var sys = require('sys');
-
-
////////////////////// HELPERS FOR PRINTING IN COLORS ///////////////////////
var putsRed = function (str){
sys.puts('\33[31m' + str + '\33[39m');
@@ -49,7 +46,7 @@ foo.require = function (file){
});
};
- file = _translate(file, { 'src': __dirname + '/../src' });
+ file = _translate(file, { 'src': __dirname + '/../lib' });
return require(file);
}
@@ -60,6 +57,9 @@ foo.unit = {
, failed: 0
, total: 0
+, preprocess: function (){
+}
+
, report: function (example){
this.total++;
View
14 scripts/run_air.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+cd `dirname $0`
+
+cd ..
+foounit generate air
+cd -
+
+
+cd ../spec
+foounit launch air
+cd -
+
+cd -
View
14 scripts/run_node.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+cd `dirname $0`
+
+cd ..
+foounit generate foo -t node
+cd -
+
+
+cd ../spec
+foounit launch node
+cd -
+
+cd -
View
12 spec/Spec-app.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<application xmlns="http://ns.adobe.com/air/application/2.0">
+ <id>foo.unit.SpecRunner</id>
+ <version>0.1</version>
+ <filename>Spec</filename>
+ <initialWindow>
+ <content>Spec.html</content>
+ <visible>true</visible>
+ <width>1024</width>
+ <height>800</height>
+ </initialWindow>
+</application>
View
64 spec/Spec.html
@@ -0,0 +1,64 @@
+<html>
+<head>
+ <title>Spec Suite</title>
+ <!-- Required vendor JS files -->
+ <script type="text/javascript" src="code/vendor/air/AIRAliases.js"></script>
+ <script type="text/javascript" src="code/vendor/air/AIRIntrospector.js"></script>
+ <script type="text/javascript" src="vendor/foo-unit/lib/foo-unit.js"></script>
+ <script type="text/javascript" src="vendor/foo-unit/lib/air.js"></script>
+
+ <script type="text/javascript">
+ foo.suite.src = 'foosrcroot.128634983773197883';
+ foo.suite.files = ["./specs/matchers_spec.js"];
+ </script>
+
+ <script type="text/javascript" src="suite.js"></script>
+
+ <style type="text/css">
+ html, body {
+ font-size: 12px;
+ }
+
+ body {
+ margin: 0 15px;
+ }
+
+ .pass, .fail {
+ border: 1px solid #ccc;
+ margin-bottom: 3px;
+ }
+
+ .pass {
+ color: #222;
+ background-color: #D0F5D1;
+ }
+
+ .fail {
+ color: #c00;
+ background-color: #F7BEC2;
+ }
+
+ .description {
+ padding: 4px;
+ }
+
+ .fail .description {
+ border-bottom: 1px solid #FCAEB8;
+ }
+
+ .failure-message {
+ background-color: #F2F0BB;
+ margin: 5px;
+ padding: 4px;
+ }
+
+ #header {
+ height: 14px;
+ }
+ </style>
+</head>
+<body>
+ <h3 id="header"></h3>
+ <div id="results"></div>
+</body>
+</html>
View
64 spec/Spec.html.template
@@ -0,0 +1,64 @@
+<html>
+<head>
+ <title>Spec Suite</title>
+ <!-- Required vendor JS files -->
+ <script type="text/javascript" src="code/vendor/air/AIRAliases.js"></script>
+ <script type="text/javascript" src="code/vendor/air/AIRIntrospector.js"></script>
+ <script type="text/javascript" src="vendor/foo-unit/lib/foo-unit.js"></script>
+ <script type="text/javascript" src="vendor/foo-unit/lib/air.js"></script>
+
+ <script type="text/javascript">
+ foo.suite.src = '${srclink}';
+ foo.suite.files = ${testfiles};
+ </script>
+
+ <script type="text/javascript" src="suite.js"></script>
+
+ <style type="text/css">
+ html, body {
+ font-size: 12px;
+ }
+
+ body {
+ margin: 0 15px;
+ }
+
+ .pass, .fail {
+ border: 1px solid #ccc;
+ margin-bottom: 3px;
+ }
+
+ .pass {
+ color: #222;
+ background-color: #D0F5D1;
+ }
+
+ .fail {
+ color: #c00;
+ background-color: #F7BEC2;
+ }
+
+ .description {
+ padding: 4px;
+ }
+
+ .fail .description {
+ border-bottom: 1px solid #FCAEB8;
+ }
+
+ .failure-message {
+ background-color: #F2F0BB;
+ margin: 5px;
+ padding: 4px;
+ }
+
+ #header {
+ height: 14px;
+ }
+ </style>
+</head>
+<body>
+ <h3 id="header"></h3>
+ <div id="results"></div>
+</body>
+</html>
View
63 spec/air.js
@@ -0,0 +1,63 @@
+foo.require = (function () {
+ var _requires = {};
+ var _translate = function(str){
+ var tvars = foo.suite;
+ return str.replace(/:(\w+)/g, function(match, ref){
+ return tvars[ref];
+ });
+ };
+
+ return function (path){
+ path = _translate(path);
+ if (_requires[path]) return;
+
+ console.debug('loading path: ' + path);
+
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', path, false);
+ xhr.send(null);
+ if (xhr.status == 200){
+ try {
+ window.eval.call(window, xhr.responseText);
+ } catch (e){
+ throw new Error('Could not eval file ' + path + ": " + e.message);
+ }
+ } else {
+ throw new Error('Could not find file: ' + path);
+ }
+
+ _requires[path] = true;
+ }
+})();
+
+
+// TODO: Make report template configurable
+// foo.suite.template = 'mytemplate.html';
+foo.unit.report = function (example){
+ function formatStack(stack){
+ return '<pre>' + stack.join("\n\t") + '</pre>';
+ }
+
+ var node = document.createElement('div');
+ var description = example.getFullDescription();
+ if (example.isSuccess()){
+ node.className = 'pass';
+ node.innerHTML = '<div class="description">' + description + '</div>';
+ } else {
+ node.className = 'fail';
+ var html = '<div class="description">' + description + '</div>';
+ html += '<div class="failure-message">' + example.getMessage() + '<br />' + formatStack(example.getStack()) + '</div>';
+ node.innerHTML = html;
+ }
+ var reportNode = document.getElementById('results');
+ reportNode.appendChild(node);
+}
+
+foo.unit.run = function (runners){
+ runners = runners || foo.unit.build();
+ for (var i = 0, ii = runners.length; i < ii; ++i){
+ var runner = runners[i];
+ runner.run();
+ foo.unit.report(runner);
+ }
+}
View
533 spec/foo-unit.js
@@ -0,0 +1,533 @@
+
+var foo = (function (){
+
+ // Utility functions
+ var mixin = function (target, source){
+ for (var prop in source){
+ if (source.hasOwnProperty(prop)){
+ target[prop] = source[prop];
+ }
+ }
+ return target;
+ };
+
+ var safeset = function (){
+ var topObj, modulePath, mixins = [], obj;
+
+ if (arguments.length <= 3){
+ topObj = arguments[0];
+ modulePath = arguments[1];
+ obj = arguments[2];
+ } else if (arguments.length == 4){
+ topObj = arguments[0];
+ modulePath = arguments[1];
+ mixins = arguments[2];
+ obj = arguments[3];
+ }
+
+ if (obj && mixins.length){
+ var target = obj;
+ if (typeof obj == 'function'){ target = obj.prototype; }
+ for (var i = 0, ii = mixins.length; i < ii; i++){
+ mixin(target, mixins[i]);
+ }
+ }
+
+ var modules = modulePath.split('.');
+ var parentObj = topObj;
+
+ for (var i = 0, ii = modules.length; i < ii; i++){
+ var part = modules[i];
+ if (!parentObj[part]){
+ if (i == modules.length - 1){
+ parentObj[part] = obj;
+ } else {
+ parentObj[part] = {};
+ }
+ } else if (i == modules.length - 1){
+ var target = parentObj[part];
+ parentObj[part] = mixin(obj, target);
+ }
+ parentObj = parentObj[part];
+ }
+ };
+
+ var sniff = function (ns){
+ try {
+ var sys = require('sys');
+
+ // Running under node
+ safeset(ns, 'global', global);
+ safeset(ns, 'puts', sys.puts);
+ safeset(ns, 'env', 'node.js');
+ safeset(ns, 'onload', function (func){ func.apply(foo.global, []); });
+ return;
+ } catch (e){}
+
+
+ safeset(ns, 'global', window);
+ safeset(ns, 'puts', function (){ console.log.apply(console, arguments); });
+ safeset(ns, 'env', 'browser');
+ safeset(ns, 'onload', function (func){ foo.global.onload = func; });
+ }
+
+ var setupConsole = function (){
+ // Set up console
+ var g = foo.global;
+ if (g.console){ return; }
+
+ if (g.air && g.air.Introspector && g.air.Introspector.Console){
+ g.console = air.Introspector.Console;
+ g.console.debug = console.log;
+ }
+ }
+
+ var foo = {};
+
+ // Determine the runtime environment and set
+ // environment specific variables
+ sniff(foo);
+ setupConsole();
+ safeset(foo, 'require');
+ safeset(foo, 'mixin', mixin);
+
+ // TODO: Should we pass a diff object to help highlight differences in objects?
+ var fm = function (str, not){
+ var negation = (not) ? 'not' : '';
+ return str.replace(':negation', negation);
+ }
+
+ var isArray = function (a){
+ return a && (a instanceof Array || typeof a == "array");
+ }
+
+ var isBoolean = function (obj){
+ return obj === true || obj === false;
+ }
+
+ var isObject = function (obj){
+ return typeof obj == 'object';
+ }
+
+ // FIXME: This code is shit. Really need to get tests on this
+ var deepEquality = function (actual, expected){
+ // Arrays
+ if (isArray(expected) && isArray(actual)){
+ if (actual.length != expected.length){ return false; }
+ for (var i = 0, ii = expected.length; i < ii; ++i){
+ if (!deepEquality(actual[i], expected[i])) { return false; }
+ }
+ return true;
+ }
+
+ // Objects
+ else if (isObject(expected) && isObject(actual)){
+ var expectedEquality = false, actualEquality = false;
+
+ for (var prop in expected){
+ //foo.puts('1: ' + prop + ': ' + actual[prop] + ', ' + expected[prop]);
+ expectedEquality = deepEquality(actual[prop], expected[prop]);
+ }
+ if (!expectedEquality){ return false; }
+
+ for (var prop in actual){
+ //foo.puts('2: ' + prop + ': ' + actual[prop] + ', ' + expected[prop]);
+ actualEquality = deepEquality(actual[prop], expected[prop]);
+ }
+ if (!actualEquality) { return false; }
+
+ return true;
+ }
+
+ // Booleans
+ // FIXME: The implicit cast should not work if we arent counting on 1 === true
+ else if (isBoolean(expected)){
+ return !!actual == expected;
+ }
+
+ else {
+ //foo.puts('3: ' + actual + ', ' + expected);
+ return actual == expected;
+ }
+ }
+
+ safeset(foo, 'unit.matchers', {
+ equal: {
+ failureMessage: function (not, actual, expected){
+ return fm('Expected ' + actual + ' to :negation equal ' + expected, not);
+ }
+
+ , match: function(actual, expected){
+ //foo.puts('deepEquality(actual, expected): ' + deepEquality(actual, expected));
+ return deepEquality(actual, expected);
+ }
+ }
+
+ , beLike: {
+ failureMessage: function (not, actual, expected){
+ return fm('Expected ' + actual + ' to :negation be like ' + expected, not);
+ }
+
+ , match: function (actual, expected){
+ if (isArray(actual) && isArray(expected)){
+ if (actual.length != expected.length){ return false; }
+ for (var i = 0, ii = expected.length; i < ii; ++i){
+ var found = false;
+ for (var j = 0, jj = actual.length; j < jj; ++j){
+ if (actual[j] == expected[i]){
+ found = true;
+ break;
+ }
+ }
+ if (!found){ return false; }
+ }
+ return true;
+ }
+
+ return actual == expected;
+ }
+ }
+
+ , beTrue: {
+ failureMessage: function (not, actual, expected){
+ return fm('Expected ' + actual + ' to :negation be true', not);
+ }
+
+ , match: function(actual, expected){
+ return actual === true;
+ }
+ }
+
+ , beFalse: {
+ failureMessage: function (not, actual, expected){
+ return fm('Expected ' + actual + ' to :negation be false', not);
+ }
+
+ , match: function(actual, expected){
+ return actual === false;
+ }
+ }
+
+ , beNull: {
+ failureMessage: function (not, actual){
+ return fm('Expected ' + actual + ' to :negation be null', not);
+ }
+
+ , match: function(actual, strict){
+ if (strict) return actual === null;
+ return actual == null;
+ }
+ }
+
+ , throwError: {
+ _actualMessage: null,
+
+ failureMessage: function (not, actual, expected){
+ return fm('Expected "' + this._actualMessage + '" to :negation throw an error with message: "' + expected + '"', not);
+ }
+
+ , match: function(actual, expected){
+ try {
+ actual();
+ } catch (e) {
+ this._actualMessage = e.message;
+ return e.message == expected;
+ }
+ return false;
+ }
+ }
+
+ , occur: {
+ // for expect(function() { return true; }).to(occur, in('10 seconds'));
+ }
+ });
+
+ // foo unit keywords
+ safeset(foo, 'unit.keywords', [foo.unit.matchers], {
+ describe: function (description, func){
+ var group = new foo.unit.ExampleGroup(this.getCurrentGroup(), description);
+ this.getCurrentGroup().addGroup(group);
+ this.setCurrentGroup(group);
+ func.apply(this, []);
+ this.setCurrentGroup(group.getParent());
+ }
+
+ , it: function (description, func){
+ var example = new foo.unit.Example(this.getCurrentGroup(), description, func);
+ this.getCurrentGroup().addExample(example, func);
+ }
+
+ , xit: function (description, func){
+ var example = new foo.unit.Example(this.getCurrentGroup(), description, func, true);
+ this.getCurrentGroup().addExample(example, func);
+ }
+
+ , expect: function (actual){
+ return new foo.unit.Expectation(actual);
+ }
+
+ , before: function (func){
+ this.getCurrentGroup().setBefore(func);
+ }
+
+ , after: function (func){
+ this.getCurrentGroup().setAfter(func);
+ }
+ });
+
+ safeset(foo, 'unit.Expectation', function (actual){
+ this._actual = actual;
+
+ this.to = function (matcher){
+ var args = [this._actual].concat(Array.prototype.slice.call(arguments, 1));
+ this.assert(false, matcher, args);
+ }
+
+ this.toNot = function (matcher){
+ var args = [this._actual].concat(Array.prototype.slice.call(arguments, 1));
+ this.assert(true, matcher, args);
+ }
+
+ this.assert = function (not, matcher, matcherArgs){
+ var matched = matcher.match.apply(matcher, matcherArgs);
+ if (!matched && !not){
+ var failureMessageArgs = [not].concat(matcherArgs);
+ throw new Error(matcher.failureMessage.apply(matcher, failureMessageArgs));
+ }
+ }
+ });
+
+ safeset(foo, 'unit.RunContext', function (){
+ });
+
+ // TODO: Add events handling for pass, fail and complete.
+ safeset(foo, 'unit.Runner', function (example, level){
+ this._example = example;
+ this._level = level;
+ this._passed = undefined;
+ this._pending = false;
+
+ this.run = function (){
+ if (this._example.isPending()){
+ this._pending = true;
+ return;
+ }
+
+ var befores = this._example.getBefores();
+ var afters = this._example.getAfters();
+ var test = this._example.getTest();
+ var context = new foo.unit.RunContext();
+
+ this._passed = true;
+ try {
+ for (var i = 0, ii = befores.length; i < ii; i++){
+ befores[i].apply(context, []);
+ }
+
+ test.apply(context, []);
+
+ for (var i = 0, ii = afters.length; i < ii; i++){
+ afters[i].apply(context, []);
+ }
+ } catch (e){
+ this._passed = false;
+ this._message = e.message;
+ this._stack = e.stack || [];
+
+ if (e.stackTrace){
+ for (var i = 0, ii = e.stackTrace.length; i < ii; ++i){
+ var frame = e.stackTrace[i];
+ var info = [frame.sourceURL, frame.functionName, frame.line].join(':');
+ this._stack.push(info);
+ }
+ }
+ }
+ }
+
+ this.getLevel = function (){
+ return this._level;
+ }
+
+ this.getFullDescription = function (){
+ return this._example.getFullDescription();
+ }
+
+ this.getMessage = function (){
+ return this._message;
+ }
+
+ this.getStack = function (){
+ return this._stack;
+ }
+
+ this.isSuccess = function (){
+ return this._passed;
+ }
+
+ this.isPending = function (){
+ return this._pending;
+ }
+ });
+
+ safeset(foo, 'unit.ExampleGroup', function(parentGroup, description){
+ this._groups = [];
+ this._examples = [];
+ this._before = null;
+ this._after = null;
+ this._parent = parentGroup;
+ this._description = description;
+
+ this.setBefore = function (before){
+ this._before = before;
+ }
+
+ this.getBefore = function (){
+ return this._before;
+ }
+
+ this.setAfter = function (after){
+ this._after = after;
+ }
+
+ this.getAfter = function (){
+ return this._after;
+ }
+
+ this.getParent = function (){
+ return this._parent;
+ }
+
+ this.getDescription = function (){
+ return this._description;
+ }
+
+ this.addGroup = function (group){
+ this._groups.push(group);
+ }
+
+ this.addExample = function (example){
+ this._examples.push(example);
+ }
+
+ this.getExamples = function (){
+ return this._examples;
+ }
+
+ this.getGroups = function (){
+ return this._groups;
+ }
+ });
+
+ safeset(foo, 'unit.Context', [foo.unit.keywords], function (group){
+ this._currentGroup = group;
+
+ this.getCurrentGroup = function (){
+ return this._currentGroup;
+ }
+
+ this.setCurrentGroup = function (currentGroup){
+ this._currentGroup = currentGroup;
+ }
+ });
+
+ safeset(foo, 'unit.Example', function (parentGroup, description, func, pending){
+ this._parent = parentGroup;
+ this._pending = pending;
+ this._description = description;
+ this._test = func;
+
+ this.getBefores = function (){
+ var befores = [];
+ for (var group = this.getParent(); group; group = group.getParent()){
+ var before = group.getBefore();
+ if (!before){ continue; }
+ befores.unshift(before);
+ }
+ return befores;
+ }
+
+ this.getAfters = function (){
+ var afters = [];
+ for (var group = this.getParent(); group; group = group.getParent()){
+ var after = group.getAfter();
+ if (!after){ continue; }
+ afters.unshift(after);
+ }
+ return afters;
+ }
+
+ this.getFullDescription = function (){
+ var exampleDescription = ' it ' + this.getDescription();
+ var description = exampleDescription;
+ for (var group = this.getParent(); group; group = group.getParent()){
+ var groupDescription = group.getDescription();
+ if (!groupDescription){ continue; }
+ var conjunction = description == exampleDescription ? '' : ' and ';
+ description = group.getDescription() + conjunction + description;
+ }
+ return description;
+ }
+
+ this.getTest = function (){
+ return this._test;
+ }
+
+ this.getParent = function (){
+ return this._parent;
+ }
+
+ this.getDescription = function (){
+ return this._description;
+ }
+
+ this.isPending = function (){
+ return this._pending;
+ }
+ });
+
+ safeset(foo, 'unit', {
+ _root: new foo.unit.ExampleGroup()
+
+ // NOTE: When you want to add a root level test use add
+ , add: function (func){
+ var group = new foo.unit.ExampleGroup(this._root);
+ this._root.addGroup(group);
+ func.apply(group, [new foo.unit.Context(group)]);
+ }
+
+ , build: function (group, level){
+ if (!group){return this.build(this._root, 0); }
+ var runners = [];
+
+ var examples = group.getExamples();
+ for (var i = 0, ii = examples.length; i < ii; i++){
+ var example = examples[i];
+ var runner = new foo.unit.Runner(example, level);
+ runners.push(runner);
+ }
+
+ var nextLevel = level+1;
+ var groups = group.getGroups();
+ for (var i = 0, ii = groups.length; i < ii; i++){
+ runners = runners.concat(this.build(groups[i], nextLevel));
+ }
+ return runners;
+ }
+ });
+
+ safeset(foo, 'suite.files', []);
+
+ return foo;
+})();
+
+if (foo.env == 'node.js'){
+ var node = require(__dirname + '/node');
+ foo.unit.add = node.unit.add || foo.unit.add;
+ foo.require = node.require;
+ foo.unit.report = node.unit.report;
+ foo.unit.run = node.unit.run;
+ foo.unit.exports = node.unit.exports;
+ foo.unit.files = node.unit.files;
+ module.exports = foo;
+}
+
View
115 spec/node.js
@@ -0,0 +1,115 @@
+// TODO: This file provides methods to foo unit but cannot use it directly.
+// Is this a problem?
+var foo = exports;
+var sys = require('sys');
+
+////////////////////// HELPERS FOR PRINTING IN COLORS ///////////////////////
+var putsRed = function (str){
+ sys.puts('\33[31m' + str + '\33[39m');
+}
+
+var printYellow = function (str){
+ sys.print('\33[33m' + str + '\33[39m');
+}
+
+var putsYellow = function (str){
+ sys.puts('\33[33m' + str + '\33[39m');
+}
+
+var printGreen = function (str){
+ sys.print('\33[32m' + str + '\33[39m');
+}
+
+var putsGreen = function (str){
+ sys.puts('\33[32m' + str + '\33[39m');
+}
+
+var highlightSpecs = function (stack){
+ var lines = stack.split("\n");
+ for (var i = 0, ii = lines.length; i < ii; ++i){
+ var line = lines[i];
+ if (line.match(/_spec\.js/)){
+ printYellow(line + "\n");
+ } else {
+ sys.puts(line);
+ }
+ }
+}
+
+////////////////////// REPORTING AND RUNNING ///////////////////////
+
+// Ummm... how should we resolve directory placeholders?
+foo.require = function (file){
+ var _translate = function(str, tvars){
+ return str.replace(/:(\w+)/g, function(match, ref){
+ return tvars[ref];
+ });
+ };
+
+ file = _translate(file, { 'src': __dirname + '/../lib' });
+ return require(file);
+}
+
+foo.unit = {
+ pendingDescriptions: []
+, pending: 0
+, passed: 0
+, failed: 0
+, total: 0
+
+, preprocess: function (){
+}
+
+, report: function (example){
+
+ this.total++;
+
+ if (example.isPending()){
+ printYellow('P');
+ this.pending++;
+ this.pendingDescriptions.push(example.getFullDescription());
+ } else if (example.isSuccess()){
+ printGreen('.');
+ this.passed++;
+ } else {
+ putsRed('F');
+ this.failed++;
+
+ var description = example.getFullDescription();
+ sys.puts(description);
+ sys.puts(new Array(description.length+1).join('='));
+ highlightSpecs(example.getStack());
+ }
+ }
+
+, run: function (runners){
+ sys.puts("running test suite: (" + runners.length + " runners)\n");
+
+ for (var i = 0, ii = runners.length; i < ii; ++i){
+ var runner = runners[i];
+ runner.run();
+ foo.unit.report(runner);
+ }
+
+ var fu = foo.unit;
+ if (fu.failed == 0){
+ putsGreen("\n\nPASSED!");
+ } else if (fu.failed > 0){
+ putsRed("\n\nFAILED!");
+ }
+
+ sys.puts(fu.total + ' examples, ' +
+ fu.passed + ' passed, ' +
+ fu.failed + ' failed, ' +
+ fu.pending + ' pending');
+
+ if (fu.pending){
+ putsYellow("\n** PENDING SPECS:");
+ for (var i = 0, ii = fu.pendingDescriptions.length; i < ii; ++i){
+ putsYellow('** ' + fu.pendingDescriptions[i]);
+ }
+ }
+
+ }
+}
+
View
55 spec/specs/matchers_spec.js
@@ -0,0 +1,55 @@
+//>>If foo.env('node', 'rubyracer')
+var foo = require(__dirname + '/../foo-unit')
+//>>End
+
+var testfoo = foo.require(':src/foo-unit');
+
+/*
+in node: testfoo gets mapped from exports to testfoo in this env
+in browser: assert that testfoo exists
+*/
+//foo.require(':src/foo-unit', 'testfoo');
+
+/*
+in node: exports gets mapped to foo
+ assert that foo.bar.Baz exists
+
+in browser: assert that foo.bar.Baz exists
+*/
+//foo.require(':src/foo-unit', 'foo.bar.Baz');
+
+/*
+in node: spec helper must export
+in browser: spec helper must have a spec ns
+*/
+//foo.require(':test/spec_helper.js', 'spec');
+
+/*
+Syntax implications:
+ in node:
+ - what if node exports more than one symbol?
+ in browser:
+ - require() calls need to be ommitted (proxy?)
+ in air:
+ - require() calls need to be stripped
+*/
+//foo.require(':src/foo-unit', 'foo.bar.Baz');
+
+foo.unit.add(function (cx){ with(cx){
+ describe('passing test', function (){
+ it('passes', function (){
+ expect(1).to(equal, 1);
+ });
+ });
+
+ describe('failing test', function (){
+ it('fails', function (){
+ expect(1).to(equal, 2);
+ });
+ });
+}});
+
+
+//>>If foo.env('node', 'rubyracer')
+module.exports = foo;
+//>>End
View
9 spec/suite.js
@@ -0,0 +1,9 @@
+
+// Require all suite files
+for (var i = 0, ii = foo.suite.files.length; i < ii; i++){
+ foo.require(foo.suite.files[i]);
+}
+
+window.onload = function (){
+ foo.unit.run();
+}

0 comments on commit e792e32

Please sign in to comment.