Skip to content
This repository
Browse code

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

  • Loading branch information...
commit e792e32fde206c0f25f2b23959e5950767795a1e 1 parent b862ce5
Bob Remeika authored October 13, 2010
1  lib/foo-unit.js
@@ -522,6 +522,7 @@ var foo = (function (){
522 522
 
523 523
 if (foo.env == 'node.js'){
524 524
   var node         = require(__dirname + '/node');
  525
+  foo.unit.add     = node.unit.add || foo.unit.add;
525 526
   foo.require      = node.require;
526 527
   foo.unit.report  = node.unit.report;
527 528
   foo.unit.run     = node.unit.run;
8  lib/generator/air.js
@@ -17,10 +17,10 @@ var AirGenerator = function (parsedOptions){
17 17
   }
18 18
 
19 19
   this.validate = function (){
20  
-    if (fsh.existsSync(this._destinationPath)){
21  
-      throw new Error('Cannot generate files because `' +
22  
-        this._destinationPath + '` already exists.');
23  
-    }
  20
+    // if (fsh.existsSync(this._destinationPath)){
  21
+    //   throw new Error('Cannot generate files because `' +
  22
+    //     this._destinationPath + '` already exists.');
  23
+    // }
24 24
   }
25 25
 
26 26
   this.run = function (){
8  lib/node.js
... ...
@@ -1,11 +1,8 @@
1 1
 // TODO: This file provides methods to foo unit but cannot use it directly.
2 2
 // Is this a problem?
3  
-
4 3
 var foo = exports;
5 4
 var sys = require('sys');
6 5
 
7  
-
8  
-
9 6
 //////////////////////  HELPERS FOR PRINTING IN COLORS ///////////////////////
10 7
 var putsRed = function (str){
11 8
   sys.puts('\33[31m' + str + '\33[39m');
@@ -49,7 +46,7 @@ foo.require = function (file){
49 46
       });
50 47
   };
51 48
 
52  
-  file = _translate(file, { 'src': __dirname + '/../src' });
  49
+  file = _translate(file, { 'src': __dirname + '/../lib' });
53 50
   return require(file);
54 51
 }
55 52
 
@@ -60,6 +57,9 @@ foo.unit = {
60 57
 , failed:  0
61 58
 , total:   0
62 59
 
  60
+, preprocess: function (){
  61
+}
  62
+
63 63
 , report: function (example){
64 64
 
65 65
     this.total++;
14  scripts/run_air.sh
... ...
@@ -0,0 +1,14 @@
  1
+#!/usr/bin/env bash
  2
+
  3
+cd `dirname $0`
  4
+
  5
+cd ..
  6
+foounit generate air
  7
+cd -
  8
+
  9
+
  10
+cd ../spec
  11
+foounit launch air
  12
+cd -
  13
+
  14
+cd -
14  scripts/run_node.sh
... ...
@@ -0,0 +1,14 @@
  1
+#!/usr/bin/env bash
  2
+
  3
+cd `dirname $0`
  4
+
  5
+cd ..
  6
+foounit generate foo -t node
  7
+cd -
  8
+
  9
+
  10
+cd ../spec
  11
+foounit launch node
  12
+cd -
  13
+
  14
+cd -
12  spec/Spec-app.xml
... ...
@@ -0,0 +1,12 @@
  1
+<?xml version="1.0" encoding="UTF-8"?> 
  2
+<application xmlns="http://ns.adobe.com/air/application/2.0"> 
  3
+  <id>foo.unit.SpecRunner</id> 
  4
+  <version>0.1</version> 
  5
+  <filename>Spec</filename> 
  6
+  <initialWindow> 
  7
+    <content>Spec.html</content> 
  8
+    <visible>true</visible> 
  9
+    <width>1024</width> 
  10
+    <height>800</height> 
  11
+  </initialWindow> 
  12
+</application>
64  spec/Spec.html
... ...
@@ -0,0 +1,64 @@
  1
+<html> 
  2
+<head> 
  3
+  <title>Spec Suite</title>
  4
+  <!-- Required vendor JS files -->
  5
+  <script type="text/javascript" src="code/vendor/air/AIRAliases.js"></script>
  6
+  <script type="text/javascript" src="code/vendor/air/AIRIntrospector.js"></script>
  7
+  <script type="text/javascript" src="vendor/foo-unit/lib/foo-unit.js"></script>
  8
+  <script type="text/javascript" src="vendor/foo-unit/lib/air.js"></script>
  9
+
  10
+  <script type="text/javascript">
  11
+    foo.suite.src = 'foosrcroot.128634983773197883';
  12
+    foo.suite.files = ["./specs/matchers_spec.js"];
  13
+  </script>
  14
+
  15
+  <script type="text/javascript" src="suite.js"></script>
  16
+
  17
+  <style type="text/css">
  18
+    html, body {
  19
+      font-size: 12px;
  20
+    }
  21
+
  22
+    body {
  23
+      margin: 0 15px;
  24
+    }
  25
+
  26
+    .pass, .fail {
  27
+      border: 1px solid #ccc;
  28
+      margin-bottom: 3px;
  29
+    }
  30
+
  31
+    .pass {
  32
+      color: #222;
  33
+      background-color: #D0F5D1;
  34
+    }
  35
+
  36
+    .fail {
  37
+      color: #c00;
  38
+      background-color: #F7BEC2;
  39
+    }
  40
+
  41
+    .description {
  42
+      padding: 4px;
  43
+    }
  44
+    
  45
+    .fail .description {
  46
+      border-bottom: 1px solid #FCAEB8;
  47
+    }
  48
+
  49
+    .failure-message {
  50
+      background-color: #F2F0BB;
  51
+      margin: 5px;
  52
+      padding: 4px;
  53
+    }
  54
+
  55
+    #header {
  56
+      height: 14px;
  57
+    }
  58
+  </style>
  59
+</head>
  60
+<body>
  61
+  <h3 id="header"></h3>
  62
+  <div id="results"></div>
  63
+</body>
  64
+</html>
64  spec/Spec.html.template
... ...
@@ -0,0 +1,64 @@
  1
+<html> 
  2
+<head> 
  3
+  <title>Spec Suite</title>
  4
+  <!-- Required vendor JS files -->
  5
+  <script type="text/javascript" src="code/vendor/air/AIRAliases.js"></script>
  6
+  <script type="text/javascript" src="code/vendor/air/AIRIntrospector.js"></script>
  7
+  <script type="text/javascript" src="vendor/foo-unit/lib/foo-unit.js"></script>
  8
+  <script type="text/javascript" src="vendor/foo-unit/lib/air.js"></script>
  9
+
  10
+  <script type="text/javascript">
  11
+    foo.suite.src = '${srclink}';
  12
+    foo.suite.files = ${testfiles};
  13
+  </script>
  14
+
  15
+  <script type="text/javascript" src="suite.js"></script>
  16
+
  17
+  <style type="text/css">
  18
+    html, body {
  19
+      font-size: 12px;
  20
+    }
  21
+
  22
+    body {
  23
+      margin: 0 15px;
  24
+    }
  25
+
  26
+    .pass, .fail {
  27
+      border: 1px solid #ccc;
  28
+      margin-bottom: 3px;
  29
+    }
  30
+
  31
+    .pass {
  32
+      color: #222;
  33
+      background-color: #D0F5D1;
  34
+    }
  35
+
  36
+    .fail {
  37
+      color: #c00;
  38
+      background-color: #F7BEC2;
  39
+    }
  40
+
  41
+    .description {
  42
+      padding: 4px;
  43
+    }
  44
+    
  45
+    .fail .description {
  46
+      border-bottom: 1px solid #FCAEB8;
  47
+    }
  48
+
  49
+    .failure-message {
  50
+      background-color: #F2F0BB;
  51
+      margin: 5px;
  52
+      padding: 4px;
  53
+    }
  54
+
  55
+    #header {
  56
+      height: 14px;
  57
+    }
  58
+  </style>
  59
+</head>
  60
+<body>
  61
+  <h3 id="header"></h3>
  62
+  <div id="results"></div>
  63
+</body>
  64
+</html>
63  spec/air.js
... ...
@@ -0,0 +1,63 @@
  1
+foo.require = (function () {
  2
+  var _requires  = {};
  3
+  var _translate = function(str){
  4
+    var tvars = foo.suite;
  5
+    return str.replace(/:(\w+)/g, function(match, ref){
  6
+        return tvars[ref];
  7
+      });
  8
+    };
  9
+
  10
+  return function (path){
  11
+    path = _translate(path); 
  12
+    if (_requires[path]) return;
  13
+
  14
+    console.debug('loading path: ' + path);
  15
+
  16
+    var xhr = new XMLHttpRequest();
  17
+    xhr.open('GET', path, false);
  18
+    xhr.send(null);
  19
+    if (xhr.status == 200){
  20
+      try {
  21
+        window.eval.call(window, xhr.responseText);
  22
+      } catch (e){
  23
+        throw new Error('Could not eval file ' + path + ": " + e.message);
  24
+      }
  25
+    } else {
  26
+      throw new Error('Could not find file: ' + path);
  27
+    }
  28
+
  29
+    _requires[path] = true;
  30
+  }
  31
+})();
  32
+
  33
+
  34
+// TODO: Make report template configurable
  35
+// foo.suite.template = 'mytemplate.html';
  36
+foo.unit.report = function (example){
  37
+  function formatStack(stack){
  38
+    return '<pre>' + stack.join("\n\t") + '</pre>';
  39
+  }
  40
+
  41
+  var node = document.createElement('div');
  42
+  var description = example.getFullDescription();
  43
+  if (example.isSuccess()){
  44
+    node.className = 'pass';
  45
+    node.innerHTML = '<div class="description">' + description + '</div>';
  46
+  } else {
  47
+    node.className = 'fail';
  48
+    var html = '<div class="description">' + description + '</div>';
  49
+    html += '<div class="failure-message">' + example.getMessage() + '<br />' + formatStack(example.getStack()) + '</div>';
  50
+    node.innerHTML = html;
  51
+  }
  52
+  var reportNode = document.getElementById('results');
  53
+  reportNode.appendChild(node);
  54
+}
  55
+
  56
+foo.unit.run = function (runners){
  57
+  runners = runners || foo.unit.build();
  58
+  for (var i = 0, ii = runners.length; i < ii; ++i){
  59
+    var runner = runners[i];
  60
+    runner.run();
  61
+    foo.unit.report(runner);
  62
+  }
  63
+}
533  spec/foo-unit.js
... ...
@@ -0,0 +1,533 @@
  1
+
  2
+var foo = (function (){
  3
+
  4
+  // Utility functions
  5
+  var mixin = function (target, source){
  6
+    for (var prop in source){
  7
+      if (source.hasOwnProperty(prop)){
  8
+        target[prop] = source[prop];
  9
+      }
  10
+    }
  11
+    return target;
  12
+  };
  13
+
  14
+  var safeset = function (){
  15
+    var topObj, modulePath, mixins = [], obj;
  16
+
  17
+    if (arguments.length <= 3){
  18
+      topObj     = arguments[0];
  19
+      modulePath = arguments[1];
  20
+      obj        = arguments[2];
  21
+    } else if (arguments.length == 4){
  22
+      topObj     = arguments[0];
  23
+      modulePath = arguments[1];
  24
+      mixins     = arguments[2];
  25
+      obj        = arguments[3];
  26
+    }
  27
+
  28
+    if (obj && mixins.length){
  29
+      var target = obj;
  30
+      if (typeof obj == 'function'){ target = obj.prototype; }
  31
+      for (var i = 0, ii = mixins.length; i < ii; i++){
  32
+        mixin(target, mixins[i]);
  33
+      }
  34
+    }
  35
+
  36
+    var modules = modulePath.split('.');
  37
+    var parentObj = topObj;
  38
+
  39
+    for (var i = 0, ii = modules.length; i < ii; i++){
  40
+      var part = modules[i];
  41
+      if (!parentObj[part]){
  42
+        if (i == modules.length - 1){
  43
+          parentObj[part] = obj;
  44
+        } else {
  45
+          parentObj[part] = {};
  46
+        }
  47
+      } else if (i == modules.length - 1){
  48
+        var target = parentObj[part];
  49
+        parentObj[part] = mixin(obj, target);
  50
+      }
  51
+      parentObj = parentObj[part];
  52
+    }
  53
+  };
  54
+
  55
+  var sniff = function (ns){
  56
+    try {
  57
+      var sys = require('sys');
  58
+
  59
+      // Running under node
  60
+      safeset(ns, 'global', global);
  61
+      safeset(ns, 'puts',   sys.puts);
  62
+      safeset(ns, 'env',    'node.js');
  63
+      safeset(ns, 'onload', function (func){ func.apply(foo.global, []); });
  64
+      return;
  65
+    } catch (e){}
  66
+
  67
+    
  68
+    safeset(ns, 'global', window);
  69
+    safeset(ns, 'puts',   function (){ console.log.apply(console, arguments); }); 
  70
+    safeset(ns, 'env',    'browser');
  71
+    safeset(ns, 'onload', function (func){ foo.global.onload = func; });
  72
+  }
  73
+
  74
+  var setupConsole = function (){
  75
+    // Set up console
  76
+    var g = foo.global;
  77
+    if (g.console){ return; }
  78
+
  79
+    if (g.air && g.air.Introspector && g.air.Introspector.Console){
  80
+      g.console = air.Introspector.Console;
  81
+      g.console.debug = console.log;
  82
+    }
  83
+  }
  84
+
  85
+  var foo = {};
  86
+
  87
+  // Determine the runtime environment and set
  88
+  // environment specific variables
  89
+  sniff(foo);
  90
+  setupConsole();
  91
+  safeset(foo, 'require');
  92
+  safeset(foo, 'mixin', mixin);
  93
+
  94
+  // TODO: Should we pass a diff object to help highlight differences in objects?
  95
+  var fm = function (str, not){
  96
+    var negation = (not) ? 'not' : '';
  97
+    return str.replace(':negation', negation);
  98
+  }
  99
+
  100
+  var isArray = function (a){
  101
+    return a && (a instanceof Array || typeof a == "array");
  102
+  }
  103
+  
  104
+  var isBoolean = function (obj){
  105
+    return obj === true || obj === false;
  106
+  }
  107
+
  108
+  var isObject = function (obj){
  109
+    return typeof obj == 'object';
  110
+  }
  111
+
  112
+  // FIXME: This code is shit.  Really need to get tests on this
  113
+  var deepEquality = function (actual, expected){
  114
+    // Arrays
  115
+    if (isArray(expected) && isArray(actual)){
  116
+      if (actual.length != expected.length){ return false; }
  117
+      for (var i = 0, ii = expected.length; i < ii; ++i){
  118
+        if (!deepEquality(actual[i], expected[i])) { return false; }
  119
+      }
  120
+      return true;
  121
+    }
  122
+
  123
+    // Objects 
  124
+    else if (isObject(expected) && isObject(actual)){
  125
+      var expectedEquality = false, actualEquality = false;
  126
+
  127
+      for (var prop in expected){
  128
+        //foo.puts('1: ' + prop + ': ' + actual[prop] + ', ' + expected[prop]);
  129
+        expectedEquality = deepEquality(actual[prop], expected[prop]);
  130
+      }
  131
+      if (!expectedEquality){ return false; }
  132
+
  133
+      for (var prop in actual){
  134
+        //foo.puts('2: ' + prop + ': ' + actual[prop] + ', ' + expected[prop]);
  135
+        actualEquality = deepEquality(actual[prop], expected[prop]);
  136
+      }
  137
+      if (!actualEquality) { return false; }
  138
+
  139
+      return true;
  140
+    }
  141
+
  142
+    // Booleans
  143
+    // FIXME: The implicit cast should not work if we arent counting on 1 === true
  144
+    else if (isBoolean(expected)){
  145
+      return !!actual == expected;
  146
+    }
  147
+
  148
+    else {
  149
+      //foo.puts('3: ' + actual + ', ' + expected);
  150
+      return actual == expected;
  151
+    }
  152
+  }
  153
+
  154
+  safeset(foo, 'unit.matchers', {
  155
+    equal: {
  156
+      failureMessage: function (not, actual, expected){
  157
+        return fm('Expected ' + actual + ' to :negation equal ' + expected, not);
  158
+      }
  159
+
  160
+      , match: function(actual, expected){
  161
+        //foo.puts('deepEquality(actual, expected): ' + deepEquality(actual, expected));
  162
+        return deepEquality(actual, expected);
  163
+      }
  164
+    }
  165
+
  166
+    , beLike: {
  167
+      failureMessage: function (not, actual, expected){
  168
+        return fm('Expected ' + actual + ' to :negation be like ' + expected, not);
  169
+      }
  170
+
  171
+      , match: function (actual, expected){
  172
+        if (isArray(actual) && isArray(expected)){
  173
+          if (actual.length != expected.length){ return false; }
  174
+          for (var i = 0, ii = expected.length; i < ii; ++i){
  175
+            var found = false;
  176
+            for (var j = 0, jj = actual.length; j < jj; ++j){
  177
+              if (actual[j] == expected[i]){
  178
+                found = true;
  179
+                break;
  180
+              }
  181
+            }
  182
+            if (!found){ return false; }
  183
+          }
  184
+          return true;
  185
+        }
  186
+
  187
+        return actual == expected;
  188
+      }
  189
+    }
  190
+
  191
+    , beTrue: {
  192
+      failureMessage: function (not, actual, expected){
  193
+        return fm('Expected ' + actual + ' to :negation be true', not);
  194
+      }
  195
+
  196
+      , match: function(actual, expected){
  197
+        return actual === true;
  198
+      }
  199
+    }
  200
+
  201
+    , beFalse: {
  202
+      failureMessage: function (not, actual, expected){
  203
+        return fm('Expected ' + actual + ' to :negation be false', not);
  204
+      }
  205
+
  206
+      , match: function(actual, expected){
  207
+        return actual === false;
  208
+      }
  209
+    }
  210
+
  211
+    , beNull: {
  212
+      failureMessage: function (not, actual){
  213
+        return fm('Expected ' + actual + ' to :negation be null', not);
  214
+      }
  215
+
  216
+      , match: function(actual, strict){
  217
+        if (strict) return actual === null;
  218
+        return actual == null;
  219
+      }
  220
+    }
  221
+
  222
+    , throwError: {
  223
+      _actualMessage: null,
  224
+
  225
+      failureMessage: function (not, actual, expected){
  226
+        return fm('Expected "' + this._actualMessage + '" to :negation throw an error with message: "' + expected + '"', not);
  227
+      }
  228
+
  229
+      , match: function(actual, expected){
  230
+        try {
  231
+          actual();
  232
+        } catch (e) {
  233
+          this._actualMessage = e.message;
  234
+          return e.message == expected;
  235
+        }
  236
+        return false;
  237
+      }
  238
+    }
  239
+
  240
+    , occur: {
  241
+      // for expect(function() { return true; }).to(occur, in('10 seconds'));
  242
+    }
  243
+  });
  244
+
  245
+  // foo unit keywords
  246
+  safeset(foo, 'unit.keywords', [foo.unit.matchers], {
  247
+    describe: function (description, func){
  248
+      var group = new foo.unit.ExampleGroup(this.getCurrentGroup(), description);
  249
+      this.getCurrentGroup().addGroup(group);
  250
+      this.setCurrentGroup(group);
  251
+      func.apply(this, []);
  252
+      this.setCurrentGroup(group.getParent());
  253
+    }
  254
+
  255
+    , it: function (description, func){
  256
+      var example = new foo.unit.Example(this.getCurrentGroup(), description, func); 
  257
+      this.getCurrentGroup().addExample(example, func);
  258
+    }
  259
+
  260
+    , xit: function (description, func){
  261
+      var example = new foo.unit.Example(this.getCurrentGroup(), description, func, true); 
  262
+      this.getCurrentGroup().addExample(example, func);
  263
+    }
  264
+
  265
+    , expect: function (actual){
  266
+      return new foo.unit.Expectation(actual);
  267
+    }
  268
+
  269
+    , before: function (func){
  270
+      this.getCurrentGroup().setBefore(func);
  271
+    }
  272
+
  273
+    , after: function (func){
  274
+      this.getCurrentGroup().setAfter(func);
  275
+    }
  276
+  });
  277
+
  278
+  safeset(foo, 'unit.Expectation', function (actual){
  279
+    this._actual = actual;
  280
+
  281
+    this.to = function (matcher){
  282
+      var args = [this._actual].concat(Array.prototype.slice.call(arguments, 1));
  283
+      this.assert(false, matcher, args);
  284
+    }
  285
+
  286
+    this.toNot = function (matcher){
  287
+      var args = [this._actual].concat(Array.prototype.slice.call(arguments, 1));
  288
+      this.assert(true, matcher, args);
  289
+    }
  290
+
  291
+    this.assert = function (not, matcher, matcherArgs){
  292
+      var matched = matcher.match.apply(matcher, matcherArgs);
  293
+      if (!matched && !not){
  294
+        var failureMessageArgs = [not].concat(matcherArgs);
  295
+        throw new Error(matcher.failureMessage.apply(matcher, failureMessageArgs));
  296
+      }
  297
+    }
  298
+  });
  299
+
  300
+  safeset(foo, 'unit.RunContext', function (){
  301
+  });
  302
+
  303
+  // TODO: Add events handling for pass, fail and complete.
  304
+  safeset(foo, 'unit.Runner', function (example, level){
  305
+    this._example = example;
  306
+    this._level = level;
  307
+    this._passed = undefined;
  308
+    this._pending = false;
  309
+
  310
+    this.run = function (){
  311
+      if (this._example.isPending()){
  312
+        this._pending = true;
  313
+        return;
  314
+      }
  315
+
  316
+      var befores = this._example.getBefores();
  317
+      var afters = this._example.getAfters();
  318
+      var test = this._example.getTest();
  319
+      var context = new foo.unit.RunContext();
  320
+
  321
+      this._passed = true; 
  322
+      try {
  323
+        for (var i = 0, ii = befores.length; i < ii; i++){
  324
+          befores[i].apply(context, []);
  325
+        }
  326
+
  327
+        test.apply(context, []);
  328
+
  329
+        for (var i = 0, ii = afters.length; i < ii; i++){
  330
+          afters[i].apply(context, []);
  331
+        }
  332
+      } catch (e){
  333
+        this._passed = false;
  334
+        this._message = e.message;
  335
+        this._stack = e.stack || [];
  336
+
  337
+        if (e.stackTrace){
  338
+          for (var i = 0, ii = e.stackTrace.length; i < ii; ++i){
  339
+            var frame = e.stackTrace[i];
  340
+            var info = [frame.sourceURL, frame.functionName, frame.line].join(':');
  341
+            this._stack.push(info);
  342
+          }
  343
+        }
  344
+      }
  345
+    }
  346
+
  347
+    this.getLevel = function (){
  348
+      return this._level;
  349
+    }
  350
+
  351
+    this.getFullDescription = function (){
  352
+      return this._example.getFullDescription();
  353
+    }
  354
+
  355
+    this.getMessage = function (){
  356
+      return this._message;
  357
+    }
  358
+
  359
+    this.getStack = function (){
  360
+      return this._stack;
  361
+    }
  362
+
  363
+    this.isSuccess = function (){
  364
+      return this._passed;
  365
+    }
  366
+
  367
+    this.isPending = function (){
  368
+      return this._pending;
  369
+    }
  370
+  });
  371
+
  372
+  safeset(foo, 'unit.ExampleGroup', function(parentGroup, description){
  373
+    this._groups = [];
  374
+    this._examples = [];
  375
+    this._before = null;
  376
+    this._after  = null;
  377
+    this._parent = parentGroup;
  378
+    this._description = description;
  379
+
  380
+    this.setBefore = function (before){
  381
+      this._before = before;
  382
+    }
  383
+
  384
+    this.getBefore = function (){
  385
+      return this._before;
  386
+    }
  387
+
  388
+    this.setAfter = function (after){
  389
+      this._after = after;
  390
+    }
  391
+
  392
+    this.getAfter = function (){
  393
+      return this._after;
  394
+    }
  395
+
  396
+    this.getParent = function (){
  397
+      return this._parent;
  398
+    }
  399
+
  400
+    this.getDescription = function (){
  401
+      return this._description;
  402
+    }
  403
+
  404
+    this.addGroup = function (group){
  405
+      this._groups.push(group);
  406
+    }
  407
+
  408
+    this.addExample = function (example){
  409
+      this._examples.push(example);
  410
+    }
  411
+
  412
+    this.getExamples = function (){
  413
+      return this._examples;
  414
+    }
  415
+
  416
+    this.getGroups = function (){
  417
+      return this._groups;
  418
+    }
  419
+  });
  420
+
  421
+  safeset(foo, 'unit.Context', [foo.unit.keywords], function (group){
  422
+    this._currentGroup = group;
  423
+
  424
+    this.getCurrentGroup = function (){
  425
+      return this._currentGroup;
  426
+    }
  427
+
  428
+    this.setCurrentGroup = function (currentGroup){
  429
+      this._currentGroup = currentGroup;
  430
+    }
  431
+  });
  432
+
  433
+  safeset(foo, 'unit.Example', function (parentGroup, description, func, pending){
  434
+    this._parent = parentGroup;
  435
+    this._pending = pending;
  436
+    this._description = description;
  437
+    this._test = func;
  438
+
  439
+    this.getBefores = function (){
  440
+      var befores = [];
  441
+      for (var group = this.getParent(); group; group = group.getParent()){
  442
+        var before = group.getBefore();
  443
+        if (!before){ continue; }
  444
+        befores.unshift(before);
  445
+      }
  446
+      return befores;
  447
+    }
  448
+
  449
+    this.getAfters = function (){
  450
+      var afters = [];
  451
+      for (var group = this.getParent(); group; group = group.getParent()){
  452
+        var after = group.getAfter();
  453
+        if (!after){ continue; }
  454
+        afters.unshift(after);
  455
+      }
  456
+      return afters;
  457
+    }
  458
+
  459
+    this.getFullDescription = function (){
  460
+      var exampleDescription = ' it ' + this.getDescription();
  461
+      var description = exampleDescription;
  462
+      for (var group = this.getParent(); group; group = group.getParent()){
  463
+        var groupDescription = group.getDescription();
  464
+        if (!groupDescription){ continue; }
  465
+        var conjunction = description == exampleDescription ? '' : ' and ';
  466
+        description = group.getDescription() + conjunction + description;
  467
+      }
  468
+      return description;
  469
+    }
  470
+
  471
+    this.getTest = function (){
  472
+      return this._test;
  473
+    }
  474
+
  475
+    this.getParent = function (){
  476
+      return this._parent;
  477
+    }
  478
+
  479
+    this.getDescription = function (){
  480
+      return this._description;
  481
+    }
  482
+
  483
+    this.isPending = function (){
  484
+      return this._pending;
  485
+    }
  486
+  });
  487
+
  488
+  safeset(foo, 'unit', {
  489
+    _root: new foo.unit.ExampleGroup()
  490
+
  491
+    // NOTE: When you want to add a root level test use add
  492
+    , add: function (func){
  493
+      var group = new foo.unit.ExampleGroup(this._root);
  494
+      this._root.addGroup(group);
  495
+      func.apply(group, [new foo.unit.Context(group)]);
  496
+    }
  497
+
  498
+    , build: function (group, level){
  499
+      if (!group){return this.build(this._root, 0); }
  500
+      var runners = [];
  501
+     
  502
+      var examples = group.getExamples();
  503
+      for (var i = 0, ii = examples.length; i < ii; i++){
  504
+        var example = examples[i];
  505
+        var runner = new foo.unit.Runner(example, level);
  506
+        runners.push(runner);
  507
+      }
  508
+
  509
+      var nextLevel = level+1;
  510
+      var groups = group.getGroups();
  511
+      for (var i = 0, ii = groups.length; i < ii; i++){
  512
+        runners = runners.concat(this.build(groups[i], nextLevel));
  513
+      }
  514
+      return runners;
  515
+    }
  516
+  });
  517
+
  518
+  safeset(foo, 'suite.files', []);
  519
+
  520
+  return foo;
  521
+})();
  522
+
  523
+if (foo.env == 'node.js'){
  524
+  var node         = require(__dirname + '/node');
  525
+  foo.unit.add     = node.unit.add || foo.unit.add;
  526
+  foo.require      = node.require;
  527
+  foo.unit.report  = node.unit.report;
  528
+  foo.unit.run     = node.unit.run;
  529
+  foo.unit.exports = node.unit.exports;
  530
+  foo.unit.files   = node.unit.files;
  531
+  module.exports   = foo;
  532
+}
  533
+
115  spec/node.js
... ...
@@ -0,0 +1,115 @@
  1
+// TODO: This file provides methods to foo unit but cannot use it directly.
  2
+// Is this a problem?
  3
+var foo = exports;
  4
+var sys = require('sys');
  5
+
  6
+//////////////////////  HELPERS FOR PRINTING IN COLORS ///////////////////////
  7
+var putsRed = function (str){
  8
+  sys.puts('\33[31m' + str + '\33[39m');
  9
+}
  10
+
  11
+var printYellow = function (str){
  12
+  sys.print('\33[33m' + str + '\33[39m');
  13
+}
  14
+
  15
+var putsYellow = function (str){
  16
+  sys.puts('\33[33m' + str + '\33[39m');
  17
+}
  18
+
  19
+var printGreen = function (str){
  20
+  sys.print('\33[32m' + str + '\33[39m');
  21
+}
  22
+
  23
+var putsGreen = function (str){
  24
+  sys.puts('\33[32m' + str + '\33[39m');
  25
+}
  26
+
  27
+var highlightSpecs = function (stack){
  28
+  var lines = stack.split("\n");
  29
+  for (var i = 0, ii = lines.length; i < ii; ++i){
  30
+    var line = lines[i];
  31
+    if (line.match(/_spec\.js/)){
  32
+      printYellow(line + "\n");
  33
+    } else {
  34
+      sys.puts(line);
  35
+    }
  36
+  }
  37
+}
  38
+
  39
+//////////////////////  REPORTING AND RUNNING ///////////////////////
  40
+
  41
+// Ummm... how should we resolve directory placeholders?
  42
+foo.require = function (file){
  43
+  var _translate = function(str, tvars){
  44
+    return str.replace(/:(\w+)/g, function(match, ref){
  45
+        return tvars[ref];
  46
+      });
  47
+  };
  48
+
  49
+  file = _translate(file, { 'src': __dirname + '/../lib' });
  50
+  return require(file);
  51
+}
  52
+
  53
+foo.unit = {
  54
+  pendingDescriptions: []
  55
+, pending: 0
  56
+, passed:  0
  57
+, failed:  0
  58
+, total:   0
  59
+
  60
+, preprocess: function (){
  61
+}
  62
+
  63
+, report: function (example){
  64
+
  65
+    this.total++;
  66
+
  67
+    if (example.isPending()){
  68
+      printYellow('P');
  69
+      this.pending++;
  70
+      this.pendingDescriptions.push(example.getFullDescription());
  71
+    } else if (example.isSuccess()){
  72
+      printGreen('.');
  73
+      this.passed++;
  74
+    } else {
  75
+      putsRed('F');
  76
+      this.failed++;
  77
+
  78
+      var description = example.getFullDescription();
  79
+      sys.puts(description);
  80
+      sys.puts(new Array(description.length+1).join('='));
  81
+      highlightSpecs(example.getStack());
  82
+    } 
  83
+  }
  84
+
  85
+, run: function (runners){
  86
+    sys.puts("running test suite: (" + runners.length + " runners)\n");
  87
+
  88
+    for (var i = 0, ii = runners.length; i < ii; ++i){
  89
+      var runner = runners[i];
  90
+      runner.run();
  91
+      foo.unit.report(runner);
  92
+    }
  93
+
  94
+    var fu = foo.unit;
  95
+    if (fu.failed == 0){
  96
+      putsGreen("\n\nPASSED!");
  97
+    } else if (fu.failed > 0){
  98
+      putsRed("\n\nFAILED!");
  99
+    }
  100
+
  101
+    sys.puts(fu.total + ' examples, ' +
  102
+      fu.passed + ' passed, ' +
  103
+      fu.failed + ' failed, ' +
  104
+      fu.pending + ' pending');
  105
+
  106
+    if (fu.pending){
  107
+      putsYellow("\n** PENDING SPECS:");
  108
+      for (var i = 0, ii = fu.pendingDescriptions.length; i < ii; ++i){
  109
+        putsYellow('** ' + fu.pendingDescriptions[i]);
  110
+      }
  111
+    }
  112
+
  113
+  }
  114
+}
  115
+
55  spec/specs/matchers_spec.js
... ...
@@ -0,0 +1,55 @@
  1
+//>>If foo.env('node', 'rubyracer')
  2
+var foo = require(__dirname + '/../foo-unit')
  3
+//>>End
  4
+
  5
+var testfoo = foo.require(':src/foo-unit');
  6
+
  7
+/*
  8
+in node:    testfoo gets mapped from exports to testfoo in this env
  9
+in browser: assert that testfoo exists
  10
+*/
  11
+//foo.require(':src/foo-unit', 'testfoo');
  12
+
  13
+/*
  14
+in node:    exports gets mapped to foo
  15
+            assert that foo.bar.Baz exists
  16
+
  17
+in browser: assert that foo.bar.Baz exists
  18
+*/
  19
+//foo.require(':src/foo-unit', 'foo.bar.Baz');
  20
+
  21
+/*
  22
+in node:    spec helper must export
  23
+in browser: spec helper must have a spec ns
  24
+*/
  25
+//foo.require(':test/spec_helper.js', 'spec');
  26
+
  27
+/*
  28
+Syntax implications:
  29
+  in node:
  30
+    - what if node exports more than one symbol?
  31
+  in browser:
  32
+    - require() calls need to be ommitted (proxy?)
  33
+  in air:
  34
+    - require() calls need to be stripped
  35
+*/
  36
+//foo.require(':src/foo-unit', 'foo.bar.Baz');
  37
+
  38
+foo.unit.add(function (cx){ with(cx){
  39
+  describe('passing test', function (){
  40
+    it('passes', function (){
  41
+      expect(1).to(equal, 1);
  42
+    });
  43
+  });
  44
+
  45
+  describe('failing test', function (){
  46
+    it('fails', function (){
  47
+      expect(1).to(equal, 2);
  48
+    });
  49
+  });
  50
+}});
  51
+
  52
+
  53
+//>>If foo.env('node', 'rubyracer')
  54
+module.exports = foo;
  55
+//>>End
9  spec/suite.js
... ...
@@ -0,0 +1,9 @@
  1
+
  2
+// Require all suite files
  3
+for (var i = 0, ii = foo.suite.files.length; i < ii; i++){
  4
+  foo.require(foo.suite.files[i]);
  5
+}
  6
+
  7
+window.onload = function (){
  8
+  foo.unit.run();
  9
+}

0 notes on commit e792e32

Please sign in to comment.
Something went wrong with that request. Please try again.