/adei/ui

To get this branch, use:
bzr branch http://darksoft.org/webbzr/adei/ui

« back to all changes in this revision

Viewing changes to includes/scriptaculous.1.7.0/unittest.js

  • Committer: Suren A. Chilingaryan
  • Date: 2008-04-02 10:23:22 UTC
  • Revision ID: csa@dside.dyndns.org-20080402102322-okib92sicg2dx3o3
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// script.aculo.us unittest.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
 
2
 
 
3
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
 
4
//           (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com)
 
5
//           (c) 2005, 2006 Michael Schuerig (http://www.schuerig.de/michael/)
 
6
//
 
7
// script.aculo.us is freely distributable under the terms of an MIT-style license.
 
8
// For details, see the script.aculo.us web site: http://script.aculo.us/
 
9
 
 
10
// experimental, Firefox-only
 
11
Event.simulateMouse = function(element, eventName) {
 
12
  var options = Object.extend({
 
13
    pointerX: 0,
 
14
    pointerY: 0,
 
15
    buttons:  0,
 
16
    ctrlKey:  false,
 
17
    altKey:   false,
 
18
    shiftKey: false,
 
19
    metaKey:  false
 
20
  }, arguments[2] || {});
 
21
  var oEvent = document.createEvent("MouseEvents");
 
22
  oEvent.initMouseEvent(eventName, true, true, document.defaultView, 
 
23
    options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY, 
 
24
    options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, 0, $(element));
 
25
  
 
26
  if(this.mark) Element.remove(this.mark);
 
27
  this.mark = document.createElement('div');
 
28
  this.mark.appendChild(document.createTextNode(" "));
 
29
  document.body.appendChild(this.mark);
 
30
  this.mark.style.position = 'absolute';
 
31
  this.mark.style.top = options.pointerY + "px";
 
32
  this.mark.style.left = options.pointerX + "px";
 
33
  this.mark.style.width = "5px";
 
34
  this.mark.style.height = "5px;";
 
35
  this.mark.style.borderTop = "1px solid red;"
 
36
  this.mark.style.borderLeft = "1px solid red;"
 
37
  
 
38
  if(this.step)
 
39
    alert('['+new Date().getTime().toString()+'] '+eventName+'/'+Test.Unit.inspect(options));
 
40
  
 
41
  $(element).dispatchEvent(oEvent);
 
42
};
 
43
 
 
44
// Note: Due to a fix in Firefox 1.0.5/6 that probably fixed "too much", this doesn't work in 1.0.6 or DP2.
 
45
// You need to downgrade to 1.0.4 for now to get this working
 
46
// See https://bugzilla.mozilla.org/show_bug.cgi?id=289940 for the fix that fixed too much
 
47
Event.simulateKey = function(element, eventName) {
 
48
  var options = Object.extend({
 
49
    ctrlKey: false,
 
50
    altKey: false,
 
51
    shiftKey: false,
 
52
    metaKey: false,
 
53
    keyCode: 0,
 
54
    charCode: 0
 
55
  }, arguments[2] || {});
 
56
 
 
57
  var oEvent = document.createEvent("KeyEvents");
 
58
  oEvent.initKeyEvent(eventName, true, true, window, 
 
59
    options.ctrlKey, options.altKey, options.shiftKey, options.metaKey,
 
60
    options.keyCode, options.charCode );
 
61
  $(element).dispatchEvent(oEvent);
 
62
};
 
63
 
 
64
Event.simulateKeys = function(element, command) {
 
65
  for(var i=0; i<command.length; i++) {
 
66
    Event.simulateKey(element,'keypress',{charCode:command.charCodeAt(i)});
 
67
  }
 
68
};
 
69
 
 
70
var Test = {}
 
71
Test.Unit = {};
 
72
 
 
73
// security exception workaround
 
74
Test.Unit.inspect = Object.inspect;
 
75
 
 
76
Test.Unit.Logger = Class.create();
 
77
Test.Unit.Logger.prototype = {
 
78
  initialize: function(log) {
 
79
    this.log = $(log);
 
80
    if (this.log) {
 
81
      this._createLogTable();
 
82
    }
 
83
  },
 
84
  start: function(testName) {
 
85
    if (!this.log) return;
 
86
    this.testName = testName;
 
87
    this.lastLogLine = document.createElement('tr');
 
88
    this.statusCell = document.createElement('td');
 
89
    this.nameCell = document.createElement('td');
 
90
    this.nameCell.className = "nameCell";
 
91
    this.nameCell.appendChild(document.createTextNode(testName));
 
92
    this.messageCell = document.createElement('td');
 
93
    this.lastLogLine.appendChild(this.statusCell);
 
94
    this.lastLogLine.appendChild(this.nameCell);
 
95
    this.lastLogLine.appendChild(this.messageCell);
 
96
    this.loglines.appendChild(this.lastLogLine);
 
97
  },
 
98
  finish: function(status, summary) {
 
99
    if (!this.log) return;
 
100
    this.lastLogLine.className = status;
 
101
    this.statusCell.innerHTML = status;
 
102
    this.messageCell.innerHTML = this._toHTML(summary);
 
103
    this.addLinksToResults();
 
104
  },
 
105
  message: function(message) {
 
106
    if (!this.log) return;
 
107
    this.messageCell.innerHTML = this._toHTML(message);
 
108
  },
 
109
  summary: function(summary) {
 
110
    if (!this.log) return;
 
111
    this.logsummary.innerHTML = this._toHTML(summary);
 
112
  },
 
113
  _createLogTable: function() {
 
114
    this.log.innerHTML =
 
115
    '<div id="logsummary"></div>' +
 
116
    '<table id="logtable">' +
 
117
    '<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' +
 
118
    '<tbody id="loglines"></tbody>' +
 
119
    '</table>';
 
120
    this.logsummary = $('logsummary')
 
121
    this.loglines = $('loglines');
 
122
  },
 
123
  _toHTML: function(txt) {
 
124
    return txt.escapeHTML().replace(/\n/g,"<br/>");
 
125
  },
 
126
  addLinksToResults: function(){ 
 
127
    $$("tr.failed .nameCell").each( function(td){ // todo: limit to children of this.log
 
128
      td.title = "Run only this test"
 
129
      Event.observe(td, 'click', function(){ window.location.search = "?tests=" + td.innerHTML;});
 
130
    });
 
131
    $$("tr.passed .nameCell").each( function(td){ // todo: limit to children of this.log
 
132
      td.title = "Run all tests"
 
133
      Event.observe(td, 'click', function(){ window.location.search = "";});
 
134
    });
 
135
  }
 
136
}
 
137
 
 
138
Test.Unit.Runner = Class.create();
 
139
Test.Unit.Runner.prototype = {
 
140
  initialize: function(testcases) {
 
141
    this.options = Object.extend({
 
142
      testLog: 'testlog'
 
143
    }, arguments[1] || {});
 
144
    this.options.resultsURL = this.parseResultsURLQueryParameter();
 
145
    this.options.tests      = this.parseTestsQueryParameter();
 
146
    if (this.options.testLog) {
 
147
      this.options.testLog = $(this.options.testLog) || null;
 
148
    }
 
149
    if(this.options.tests) {
 
150
      this.tests = [];
 
151
      for(var i = 0; i < this.options.tests.length; i++) {
 
152
        if(/^test/.test(this.options.tests[i])) {
 
153
          this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases["setup"], testcases["teardown"]));
 
154
        }
 
155
      }
 
156
    } else {
 
157
      if (this.options.test) {
 
158
        this.tests = [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases["setup"], testcases["teardown"])];
 
159
      } else {
 
160
        this.tests = [];
 
161
        for(var testcase in testcases) {
 
162
          if(/^test/.test(testcase)) {
 
163
            this.tests.push(
 
164
               new Test.Unit.Testcase(
 
165
                 this.options.context ? ' -> ' + this.options.titles[testcase] : testcase, 
 
166
                 testcases[testcase], testcases["setup"], testcases["teardown"]
 
167
               ));
 
168
          }
 
169
        }
 
170
      }
 
171
    }
 
172
    this.currentTest = 0;
 
173
    this.logger = new Test.Unit.Logger(this.options.testLog);
 
174
    setTimeout(this.runTests.bind(this), 1000);
 
175
  },
 
176
  parseResultsURLQueryParameter: function() {
 
177
    return window.location.search.parseQuery()["resultsURL"];
 
178
  },
 
179
  parseTestsQueryParameter: function(){
 
180
    if (window.location.search.parseQuery()["tests"]){
 
181
        return window.location.search.parseQuery()["tests"].split(',');
 
182
    };
 
183
  },
 
184
  // Returns:
 
185
  //  "ERROR" if there was an error,
 
186
  //  "FAILURE" if there was a failure, or
 
187
  //  "SUCCESS" if there was neither
 
188
  getResult: function() {
 
189
    var hasFailure = false;
 
190
    for(var i=0;i<this.tests.length;i++) {
 
191
      if (this.tests[i].errors > 0) {
 
192
        return "ERROR";
 
193
      }
 
194
      if (this.tests[i].failures > 0) {
 
195
        hasFailure = true;
 
196
      }
 
197
    }
 
198
    if (hasFailure) {
 
199
      return "FAILURE";
 
200
    } else {
 
201
      return "SUCCESS";
 
202
    }
 
203
  },
 
204
  postResults: function() {
 
205
    if (this.options.resultsURL) {
 
206
      new Ajax.Request(this.options.resultsURL, 
 
207
        { method: 'get', parameters: 'result=' + this.getResult(), asynchronous: false });
 
208
    }
 
209
  },
 
210
  runTests: function() {
 
211
    var test = this.tests[this.currentTest];
 
212
    if (!test) {
 
213
      // finished!
 
214
      this.postResults();
 
215
      this.logger.summary(this.summary());
 
216
      return;
 
217
    }
 
218
    if(!test.isWaiting) {
 
219
      this.logger.start(test.name);
 
220
    }
 
221
    test.run();
 
222
    if(test.isWaiting) {
 
223
      this.logger.message("Waiting for " + test.timeToWait + "ms");
 
224
      setTimeout(this.runTests.bind(this), test.timeToWait || 1000);
 
225
    } else {
 
226
      this.logger.finish(test.status(), test.summary());
 
227
      this.currentTest++;
 
228
      // tail recursive, hopefully the browser will skip the stackframe
 
229
      this.runTests();
 
230
    }
 
231
  },
 
232
  summary: function() {
 
233
    var assertions = 0;
 
234
    var failures = 0;
 
235
    var errors = 0;
 
236
    var messages = [];
 
237
    for(var i=0;i<this.tests.length;i++) {
 
238
      assertions +=   this.tests[i].assertions;
 
239
      failures   +=   this.tests[i].failures;
 
240
      errors     +=   this.tests[i].errors;
 
241
    }
 
242
    return (
 
243
      (this.options.context ? this.options.context + ': ': '') + 
 
244
      this.tests.length + " tests, " + 
 
245
      assertions + " assertions, " + 
 
246
      failures   + " failures, " +
 
247
      errors     + " errors");
 
248
  }
 
249
}
 
250
 
 
251
Test.Unit.Assertions = Class.create();
 
252
Test.Unit.Assertions.prototype = {
 
253
  initialize: function() {
 
254
    this.assertions = 0;
 
255
    this.failures   = 0;
 
256
    this.errors     = 0;
 
257
    this.messages   = [];
 
258
  },
 
259
  summary: function() {
 
260
    return (
 
261
      this.assertions + " assertions, " + 
 
262
      this.failures   + " failures, " +
 
263
      this.errors     + " errors" + "\n" +
 
264
      this.messages.join("\n"));
 
265
  },
 
266
  pass: function() {
 
267
    this.assertions++;
 
268
  },
 
269
  fail: function(message) {
 
270
    this.failures++;
 
271
    this.messages.push("Failure: " + message);
 
272
  },
 
273
  info: function(message) {
 
274
    this.messages.push("Info: " + message);
 
275
  },
 
276
  error: function(error) {
 
277
    this.errors++;
 
278
    this.messages.push(error.name + ": "+ error.message + "(" + Test.Unit.inspect(error) +")");
 
279
  },
 
280
  status: function() {
 
281
    if (this.failures > 0) return 'failed';
 
282
    if (this.errors > 0) return 'error';
 
283
    return 'passed';
 
284
  },
 
285
  assert: function(expression) {
 
286
    var message = arguments[1] || 'assert: got "' + Test.Unit.inspect(expression) + '"';
 
287
    try { expression ? this.pass() : 
 
288
      this.fail(message); }
 
289
    catch(e) { this.error(e); }
 
290
  },
 
291
  assertEqual: function(expected, actual) {
 
292
    var message = arguments[2] || "assertEqual";
 
293
    try { (expected == actual) ? this.pass() :
 
294
      this.fail(message + ': expected "' + Test.Unit.inspect(expected) + 
 
295
        '", actual "' + Test.Unit.inspect(actual) + '"'); }
 
296
    catch(e) { this.error(e); }
 
297
  },
 
298
  assertInspect: function(expected, actual) {
 
299
    var message = arguments[2] || "assertInspect";
 
300
    try { (expected == actual.inspect()) ? this.pass() :
 
301
      this.fail(message + ': expected "' + Test.Unit.inspect(expected) + 
 
302
        '", actual "' + Test.Unit.inspect(actual) + '"'); }
 
303
    catch(e) { this.error(e); }
 
304
  },
 
305
  assertEnumEqual: function(expected, actual) {
 
306
    var message = arguments[2] || "assertEnumEqual";
 
307
    try { $A(expected).length == $A(actual).length && 
 
308
      expected.zip(actual).all(function(pair) { return pair[0] == pair[1] }) ?
 
309
        this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) + 
 
310
          ', actual ' + Test.Unit.inspect(actual)); }
 
311
    catch(e) { this.error(e); }
 
312
  },
 
313
  assertNotEqual: function(expected, actual) {
 
314
    var message = arguments[2] || "assertNotEqual";
 
315
    try { (expected != actual) ? this.pass() : 
 
316
      this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); }
 
317
    catch(e) { this.error(e); }
 
318
  },
 
319
  assertIdentical: function(expected, actual) { 
 
320
    var message = arguments[2] || "assertIdentical"; 
 
321
    try { (expected === actual) ? this.pass() : 
 
322
      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +  
 
323
        '", actual "' + Test.Unit.inspect(actual) + '"'); } 
 
324
    catch(e) { this.error(e); } 
 
325
  },
 
326
  assertNotIdentical: function(expected, actual) { 
 
327
    var message = arguments[2] || "assertNotIdentical"; 
 
328
    try { !(expected === actual) ? this.pass() : 
 
329
      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +  
 
330
        '", actual "' + Test.Unit.inspect(actual) + '"'); } 
 
331
    catch(e) { this.error(e); } 
 
332
  },
 
333
  assertNull: function(obj) {
 
334
    var message = arguments[1] || 'assertNull'
 
335
    try { (obj==null) ? this.pass() : 
 
336
      this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); }
 
337
    catch(e) { this.error(e); }
 
338
  },
 
339
  assertMatch: function(expected, actual) {
 
340
    var message = arguments[2] || 'assertMatch';
 
341
    var regex = new RegExp(expected);
 
342
    try { (regex.exec(actual)) ? this.pass() :
 
343
      this.fail(message + ' : regex: "' +  Test.Unit.inspect(expected) + ' did not match: ' + Test.Unit.inspect(actual) + '"'); }
 
344
    catch(e) { this.error(e); }
 
345
  },
 
346
  assertHidden: function(element) {
 
347
    var message = arguments[1] || 'assertHidden';
 
348
    this.assertEqual("none", element.style.display, message);
 
349
  },
 
350
  assertNotNull: function(object) {
 
351
    var message = arguments[1] || 'assertNotNull';
 
352
    this.assert(object != null, message);
 
353
  },
 
354
  assertType: function(expected, actual) {
 
355
    var message = arguments[2] || 'assertType';
 
356
    try { 
 
357
      (actual.constructor == expected) ? this.pass() : 
 
358
      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +  
 
359
        '", actual "' + (actual.constructor) + '"'); }
 
360
    catch(e) { this.error(e); }
 
361
  },
 
362
  assertNotOfType: function(expected, actual) {
 
363
    var message = arguments[2] || 'assertNotOfType';
 
364
    try { 
 
365
      (actual.constructor != expected) ? this.pass() : 
 
366
      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +  
 
367
        '", actual "' + (actual.constructor) + '"'); }
 
368
    catch(e) { this.error(e); }
 
369
  },
 
370
  assertInstanceOf: function(expected, actual) {
 
371
    var message = arguments[2] || 'assertInstanceOf';
 
372
    try { 
 
373
      (actual instanceof expected) ? this.pass() : 
 
374
      this.fail(message + ": object was not an instance of the expected type"); }
 
375
    catch(e) { this.error(e); } 
 
376
  },
 
377
  assertNotInstanceOf: function(expected, actual) {
 
378
    var message = arguments[2] || 'assertNotInstanceOf';
 
379
    try { 
 
380
      !(actual instanceof expected) ? this.pass() : 
 
381
      this.fail(message + ": object was an instance of the not expected type"); }
 
382
    catch(e) { this.error(e); } 
 
383
  },
 
384
  assertRespondsTo: function(method, obj) {
 
385
    var message = arguments[2] || 'assertRespondsTo';
 
386
    try {
 
387
      (obj[method] && typeof obj[method] == 'function') ? this.pass() : 
 
388
      this.fail(message + ": object doesn't respond to [" + method + "]"); }
 
389
    catch(e) { this.error(e); }
 
390
  },
 
391
  assertReturnsTrue: function(method, obj) {
 
392
    var message = arguments[2] || 'assertReturnsTrue';
 
393
    try {
 
394
      var m = obj[method];
 
395
      if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)];
 
396
      m() ? this.pass() : 
 
397
      this.fail(message + ": method returned false"); }
 
398
    catch(e) { this.error(e); }
 
399
  },
 
400
  assertReturnsFalse: function(method, obj) {
 
401
    var message = arguments[2] || 'assertReturnsFalse';
 
402
    try {
 
403
      var m = obj[method];
 
404
      if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)];
 
405
      !m() ? this.pass() : 
 
406
      this.fail(message + ": method returned true"); }
 
407
    catch(e) { this.error(e); }
 
408
  },
 
409
  assertRaise: function(exceptionName, method) {
 
410
    var message = arguments[2] || 'assertRaise';
 
411
    try { 
 
412
      method();
 
413
      this.fail(message + ": exception expected but none was raised"); }
 
414
    catch(e) {
 
415
      ((exceptionName == null) || (e.name==exceptionName)) ? this.pass() : this.error(e); 
 
416
    }
 
417
  },
 
418
  assertElementsMatch: function() {
 
419
    var expressions = $A(arguments), elements = $A(expressions.shift());
 
420
    if (elements.length != expressions.length) {
 
421
      this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length + ' expressions');
 
422
      return false;
 
423
    }
 
424
    elements.zip(expressions).all(function(pair, index) {
 
425
      var element = $(pair.first()), expression = pair.last();
 
426
      if (element.match(expression)) return true;
 
427
      this.fail('assertElementsMatch: (in index ' + index + ') expected ' + expression.inspect() + ' but got ' + element.inspect());
 
428
    }.bind(this)) && this.pass();
 
429
  },
 
430
  assertElementMatches: function(element, expression) {
 
431
    this.assertElementsMatch([element], expression);
 
432
  },
 
433
  benchmark: function(operation, iterations) {
 
434
    var startAt = new Date();
 
435
    (iterations || 1).times(operation);
 
436
    var timeTaken = ((new Date())-startAt);
 
437
    this.info((arguments[2] || 'Operation') + ' finished ' + 
 
438
       iterations + ' iterations in ' + (timeTaken/1000)+'s' );
 
439
    return timeTaken;
 
440
  },
 
441
  _isVisible: function(element) {
 
442
    element = $(element);
 
443
    if(!element.parentNode) return true;
 
444
    this.assertNotNull(element);
 
445
    if(element.style && Element.getStyle(element, 'display') == 'none')
 
446
      return false;
 
447
    
 
448
    return this._isVisible(element.parentNode);
 
449
  },
 
450
  assertNotVisible: function(element) {
 
451
    this.assert(!this._isVisible(element), Test.Unit.inspect(element) + " was not hidden and didn't have a hidden parent either. " + ("" || arguments[1]));
 
452
  },
 
453
  assertVisible: function(element) {
 
454
    this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1]));
 
455
  },
 
456
  benchmark: function(operation, iterations) {
 
457
    var startAt = new Date();
 
458
    (iterations || 1).times(operation);
 
459
    var timeTaken = ((new Date())-startAt);
 
460
    this.info((arguments[2] || 'Operation') + ' finished ' + 
 
461
       iterations + ' iterations in ' + (timeTaken/1000)+'s' );
 
462
    return timeTaken;
 
463
  }
 
464
}
 
465
 
 
466
Test.Unit.Testcase = Class.create();
 
467
Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), {
 
468
  initialize: function(name, test, setup, teardown) {
 
469
    Test.Unit.Assertions.prototype.initialize.bind(this)();
 
470
    this.name           = name;
 
471
    
 
472
    if(typeof test == 'string') {
 
473
      test = test.gsub(/(\.should[^\(]+\()/,'#{0}this,');
 
474
      test = test.gsub(/(\.should[^\(]+)\(this,\)/,'#{1}(this)');
 
475
      this.test = function() {
 
476
        eval('with(this){'+test+'}');
 
477
      }
 
478
    } else {
 
479
      this.test = test || function() {};
 
480
    }
 
481
    
 
482
    this.setup          = setup || function() {};
 
483
    this.teardown       = teardown || function() {};
 
484
    this.isWaiting      = false;
 
485
    this.timeToWait     = 1000;
 
486
  },
 
487
  wait: function(time, nextPart) {
 
488
    this.isWaiting = true;
 
489
    this.test = nextPart;
 
490
    this.timeToWait = time;
 
491
  },
 
492
  run: function() {
 
493
    try {
 
494
      try {
 
495
        if (!this.isWaiting) this.setup.bind(this)();
 
496
        this.isWaiting = false;
 
497
        this.test.bind(this)();
 
498
      } finally {
 
499
        if(!this.isWaiting) {
 
500
          this.teardown.bind(this)();
 
501
        }
 
502
      }
 
503
    }
 
504
    catch(e) { this.error(e); }
 
505
  }
 
506
});
 
507
 
 
508
// *EXPERIMENTAL* BDD-style testing to please non-technical folk
 
509
// This draws many ideas from RSpec http://rspec.rubyforge.org/
 
510
 
 
511
Test.setupBDDExtensionMethods = function(){
 
512
  var METHODMAP = {
 
513
    shouldEqual:     'assertEqual',
 
514
    shouldNotEqual:  'assertNotEqual',
 
515
    shouldEqualEnum: 'assertEnumEqual',
 
516
    shouldBeA:       'assertType',
 
517
    shouldNotBeA:    'assertNotOfType',
 
518
    shouldBeAn:      'assertType',
 
519
    shouldNotBeAn:   'assertNotOfType',
 
520
    shouldBeNull:    'assertNull',
 
521
    shouldNotBeNull: 'assertNotNull',
 
522
    
 
523
    shouldBe:        'assertReturnsTrue',
 
524
    shouldNotBe:     'assertReturnsFalse',
 
525
    shouldRespondTo: 'assertRespondsTo'
 
526
  };
 
527
  Test.BDDMethods = {};
 
528
  for(m in METHODMAP) {
 
529
    Test.BDDMethods[m] = eval(
 
530
      'function(){'+
 
531
      'var args = $A(arguments);'+
 
532
      'var scope = args.shift();'+
 
533
      'scope.'+METHODMAP[m]+'.apply(scope,(args || []).concat([this])); }');
 
534
  }
 
535
  [Array.prototype, String.prototype, Number.prototype].each(
 
536
    function(p){ Object.extend(p, Test.BDDMethods) }
 
537
  );
 
538
}
 
539
 
 
540
Test.context = function(name, spec, log){
 
541
  Test.setupBDDExtensionMethods();
 
542
  
 
543
  var compiledSpec = {};
 
544
  var titles = {};
 
545
  for(specName in spec) {
 
546
    switch(specName){
 
547
      case "setup":
 
548
      case "teardown":
 
549
        compiledSpec[specName] = spec[specName];
 
550
        break;
 
551
      default:
 
552
        var testName = 'test'+specName.gsub(/\s+/,'-').camelize();
 
553
        var body = spec[specName].toString().split('\n').slice(1);
 
554
        if(/^\{/.test(body[0])) body = body.slice(1);
 
555
        body.pop();
 
556
        body = body.map(function(statement){ 
 
557
          return statement.strip()
 
558
        });
 
559
        compiledSpec[testName] = body.join('\n');
 
560
        titles[testName] = specName;
 
561
    }
 
562
  }
 
563
  new Test.Unit.Runner(compiledSpec, { titles: titles, testLog: log || 'testlog', context: name });
 
564
};
 
 
b'\\ No newline at end of file'