pax_global_header00006660000000000000000000000064120515030230014501gustar00rootroot0000000000000052 comment=c683d8877da94354c4dc428e7f64995afb377441 vows-0.7.0/000077500000000000000000000000001205150302300125035ustar00rootroot00000000000000vows-0.7.0/.gitignore000066400000000000000000000000261205150302300144710ustar00rootroot00000000000000node_modules .idea nulvows-0.7.0/.travis.yml000066400000000000000000000000551205150302300146140ustar00rootroot00000000000000language: node_js node_js: - 0.4 - 0.6 vows-0.7.0/LICENSE000066400000000000000000000020351205150302300135100ustar00rootroot00000000000000Copyright (c) 2009 cloudhead Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. vows-0.7.0/Makefile000066400000000000000000000001041205150302300141360ustar00rootroot00000000000000# # Run all tests # test: @@bin/vows test/* .PHONY: test install vows-0.7.0/README.md000066400000000000000000000040631205150302300137650ustar00rootroot00000000000000Vows ==== > Asynchronous BDD & continuous integration for node.js #### # introduction ------------ There are two reasons why we might want asynchronous testing. The first, and obvious reason is that node.js is asynchronous, and therefore our tests need to be. The second reason is to make test suites which target I/O libraries run much faster. _Vows_ is an experiment in making this possible, while adding a minimum of overhead. synopsis -------- var vows = require('vows'), assert = require('assert'); vows.describe('Deep Thought').addBatch({ 'An instance of DeepThought': { topic: new DeepThought, 'should know the answer to the ultimate question of life': function (deepThought) { assert.equal (deepThought.question('what is the answer to the universe?'), 42); } } }); coverage reporting ------------------ Code coverage reporting is available if _instrumented_ code is detected. Currently only _instrumentation_ via [node-jscoverage](https://github.com/visionmedia/node-jscoverage) is supported. When _instrumented_ code is detected and coverage reporting is enabled using any of the `--cover-plain`, `--cover-html`, or `--cover-json` options a code coverage map is generated. ### downloading and installing [node-jscoverage](https://github.com/visionmedia/node-jscoverage) [node-jscoverage](https://github.com/visionmedia/node-jscoverage) is a binary package that needs to be compiled from source: $ git clone https://github.com/visionmedia/node-jscoverage.git $ cd node-jscoverage/ $ ./configure checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes [...] $ make && sudo make install ### instrumenting with jscoverage $ jscoverage myfile.js myfile-instrumented.js installation ------------ $ npm install vows documentation ------------- Head over to authors ------- Alexis Sellier <>, Charlie Robbins, *...and many others* vows-0.7.0/bin/000077500000000000000000000000001205150302300132535ustar00rootroot00000000000000vows-0.7.0/bin/vows000077500000000000000000000463321205150302300142070ustar00rootroot00000000000000#!/usr/bin/env node var path = require('path'), fs = require('fs'), util = require('util'), wildcard = require('../lib/utils/wildcard').wildcard, events = require('events'); // // Attempt to load Coffee-Script. If it's not available, continue on our // merry way, if it is available, start searching for `*.coffee` scripts too. // var fileExt, specFileExt; try { var coffee = require('coffee-script'); fileExt = /\.(js|coffee)$/; specFileExt = /[.(-|_)]((t|T)est|(s|S)pec)\.(js|coffee)$/; } catch (_) { fileExt = /\.js$/; specFileExt = /[.(-|_)]((t|T)est|(s|S)pec)\.js$/; } var inspect = require('eyes').inspector({ stream: null, styles: { string: 'grey', regexp: 'grey' } }); var vows = require('../lib/vows'); var cutils = require('../lib/vows/console'); var stylize = require('../lib/vows/console').stylize; var _reporter = require('../lib/vows/reporters/dot-matrix'), reporter = { name: _reporter.name }; var _coverage; var nodeMinorVersion = parseInt(process.version.split('.')[1], 10); var help = [ "usage: vows [FILE, ...] [options]", "", "options:", " -v, --verbose Enable verbose output", " -w, --watch Watch mode", " -s, --silent Don't report", " -i, --isolate Run each test in it's own vows process", " -m PATTERN Only run tests matching the PATTERN string", " -r PATTERN Only run tests matching the PATTERN regexp", " --json Use JSON reporter", " --spec Use Spec reporter", " --tap Use TAP reporter", " --dot-matrix Use Dot-Matrix reporter", " --xunit Use xUnit reporter", " --cover-plain Print plain coverage map if detected", " --cover-html Write coverage map to \"coverage.html\"", " --cover-json Write unified coverage map to \"coverage.json\"", " --cover-xml Write coverage map to \"coverage.xml\" in Emma xml", " --no-color Don't use terminal colors", " --version Show version", " -h, --help You're staring at it" ].join('\n'); var options = { reporter: reporter, matcher: /.*/, watch: false, coverage: false, isolate: false, shuffle: false, nocolor: !process.stdout.isTTY }; var files = []; var wildcardFiles = []; // Get rid of process runner // ('node' in most cases) var arg, args = [], argv = process.argv.slice(2); // Current directory index, // and path of test folder. var root, testFolder; // // Parse command-line parameters // while (arg = argv.shift()) { if (arg === __filename) { continue } if (arg[0] !== '-') { args.push(arg); } else { arg = arg.match(/^--?(.+)/)[1]; if (arg[0] === 'r') { options.matcher = new(RegExp)(argv.shift()); } else if (arg[0] === 'm') { options.matcher = (function (str) { // Create an escaped RegExp var specials = '. * + ? | ( ) [ ] { } \\ ^ ? ! = : $'.split(' ').join('|\\'), regex = new(RegExp)('(\\' + specials + ')', 'g'); return new(RegExp)(str.replace(regex, '\\$1')); })(argv.shift()); } else if (arg in options) { options[arg] = true; } else { switch (arg) { case 'json': _reporter = require('../lib/vows/reporters/json'); break; case 'spec': _reporter = require('../lib/vows/reporters/spec'); break; case 'tap': _reporter = require('../lib/vows/reporters/tap'); break; case 'dot-matrix': _reporter = require('../lib/vows/reporters/dot-matrix'); break; case 'silent': case 's': _reporter = require('../lib/vows/reporters/silent'); break; case 'xunit': _reporter = require('../lib/vows/reporters/xunit'); break; case 'cover-plain': options.coverage = true; _coverage = require('../lib/vows/coverage/report-plain'); break; case 'cover-html': options.coverage = true; _coverage = require('../lib/vows/coverage/report-html'); break; case 'cover-json': options.coverage = true; _coverage = require('../lib/vows/coverage/report-json'); break; case 'cover-xml': options.coverage = true; _coverage = require('../lib/vows/coverage/report-xml'); break; case 'verbose': case 'v': options.verbose = true; break; case 'watch': case 'w': options.watch = true; break; case 'supress-stdout': options.supressStdout = true; break; case 'shuffle': options.shuffle = true; break; case 'isolate': case 'i': options.isolate = true; break; case 'no-color': options.nocolor = true; break; case 'color': options.nocolor = false; break; case 'no-error': options.error = false; break; case 'version': console.log('vows ' + vows.version); process.exit(0); case 'help': case 'h': console.log(help); process.exit(0); break; } } } } if (options.nocolor) { cutils.nocolor = true; inspect = require('eyes').inspector({ stream: null, styles: false }); } if (options.supressStdout) { _reporter.setStream && _reporter.setStream(process.stdout); var devNullStream = null; if(process.platform === 'win32'){ devNullStream = fs.createWriteStream('nul'); } else { devNullStream = fs.createWriteStream('/dev/null'); } process.__defineGetter__('stdout', function () { return devNullStream; }); } if (options.watch) { options.reporter = reporter = require('../lib/vows/reporters/watch'); } msg('bin', 'argv', args); msg('bin', 'options', { reporter: options.reporter.name, matcher: options.matcher }); if (args.length === 0 || options.watch) { msg('bin', 'discovering', 'folder structure'); root = fs.readdirSync('.'); if (root.indexOf('test') !== -1) { testFolder = 'test'; } else if (root.indexOf('spec') !== -1) { testFolder = 'spec'; } else { abort("runner", "couldn't find test folder"); } msg('bin', 'discovered', "./" + testFolder); if (args.length === 0) { args = paths(testFolder).filter(function (f) { return specFileExt.test(f); }); if (options.watch) { args = args.concat(paths('lib'), paths('src')); } } } if (! options.watch) { reporter.report = function (data, filename) { switch (data[0]) { case 'subject': case 'vow': case 'context': case 'error': _reporter.report(data, filename); break; case 'end': (options.verbose || _reporter.name === 'json') && _reporter.report(data); break; case 'finish': options.verbose ? _reporter.print('\n') : _reporter.print(' '); break; } }; reporter.reset = function () { _reporter.reset && _reporter.reset() }; reporter.print = _reporter.print; // add full path if necessary files = args.map(function (a) { return (!a.match(/^[\/|c|C]/)) ? path.join(process.cwd(), a) : a; }); // preprocess the list of files for any wildcards. win32 does not handle wildcards before calling vows // any paths not containing wildcards are simple returned by wildcard() files.forEach(function(a) { if(a.indexOf('*') !== -1) { wildcardFiles = wildcardFiles.concat(wildcard(a)); } else { wildcardFiles.push(a); } }); // now set up the file list for vows including all the wildcard files files = wildcardFiles.map(function (a) { return a.replace(fileExt, ''); }); if (options.shuffle) { var source = files.slice(0); files.length = 0; while (source.length) { files.push(source.splice(Math.floor(Math.random() * source.length), 1)[0]); } } runSuites(importSuites(files), function (results) { var status = results.errored ? 2 : (results.broken ? 1 : 0); !options.verbose && _reporter.print('\n'); msg('runner', 'finish'); _reporter.report(['finish', results], { write: function (str) { util.print(str.replace(/^\n\n/, '\n')); } }); try { if (options.coverage === true && _$jscoverage !== undefined) { _coverage.report(_$jscoverage); } } catch (err) { // ignore the undefined jscoverage } if (process.stdout.write('')) { // Check if stdout is drained process.exit(status); } else { process.stdout.on('drain', function () { process.exit(status); }); } }); } else { // // Watch mode // (function () { var pendulum = [ '. ', '.. ', '... ', ' ...', ' ..', ' .', ' .', ' ..', '... ', '.. ', '. ' ]; var strobe = ['.', ' ']; var status, cue, current = 0, running = 0, lastRun, colors = ['32m', '33m', '31m'], timer = setInterval(tick, 100); process.on('uncaughtException', exception); process.on('exit', cleanup); process.on('SIGINT', function () { process.exit(0); }); process.on('SIGQUIT', function () { changed(); }); cursorHide(); // Run every 100ms function tick() { if (running && (cue !== strobe)) { cue = strobe, current = 0; } else if (!running && (cue !== pendulum)) { cue = pendulum, current = 0; } eraseLine(); lastRun && !running && esc(colors[status.errored ? 2 : (status.broken ? 1 : 0)]); print(cue[current]); if (current == cue.length - 1) { current = -1 } current ++; esc('39m'); cursorRestore(); } // // Utility functions // function print(str) { util.print(str) } function esc(str) { print("\x1b[" + str) } function eraseLine() { esc("0K") } function cursorRestore() { esc("0G") } function cursorHide() { esc("?25l") } function cursorShow() { esc("?25h") } function cleanup() { eraseLine(), cursorShow(), clearInterval(timer), print('\n') } function exception(err) { print(err.stack || err.message || JSON.stringify(err)), running = 0} // // Get a matching test for a given file // function getMatchingTest(file, join) { join || (join = '-'); var testFile; if (specFileExt.test(file)) { testFile = path.join(testFolder, file); } else { var root, extension; _s = file.split('.'), root = _s[0], extension = _s[1]; testFile = path.join(testFolder, root + join + testFolder + "." + extension); } try { fs.statSync(testFile); } catch (e) { if (join == '-') { return getMatchingTest(file, '_'); } else { msg('watcher', 'no equivalence found, running all tests.'); testFile = null; } } return testFile; } // // Called when a file has been modified. // Run the matching tests and change the status. // function changed(file) { status = { honored: 0, broken: 0, errored: 0, pending: 0 }; msg('watcher', 'detected change in', file); file = getMatchingTest(file); var files = (specFileExt.test(file) ? [file] : paths(testFolder)).map(function (p) { return path.join(process.cwd(), p); }).filter(function (p) { return specFileExt.test(p); }).map(function (p) { var cache = require.main.moduleCache || require.cache; if (cache[p]) { delete(cache[p]) } return p; }).map(function (p) { return p.replace(fileExt, ''); }); running ++; runSuites(importSuites(files), function (results) { delete(results.time); print(cutils.result(results).join('') + '\n\n'); lastRun = new(Date); status = results; running --; }); } msg('watcher', 'watching', args); // // Watch all relevant files, // and call `changed()` on change. // args.forEach(function (p) { fs.watchFile(p, function (current, previous) { if (new(Date)(current.mtime).valueOf() === new(Date)(previous.mtime).valueOf()) { return } else { changed(p); } }); }); })(); } function runSuites(suites, callback) { var results = { honored: 0, broken: 0, errored: 0, pending: 0, total: 0, time: 0 }; reporter.reset(); (function run(suites, callback) { var suite = suites.shift(); if (suite) { msg('runner', "running", suite.subject + ' ', options.watch ? false : true); suite.run(options, function (result) { Object.keys(result).forEach(function (k) { results[k] += result[k]; }); run(suites, callback); }); } else { callback(results); } })(suites, callback); } function importSuites(files) { msg(options.watcher ? 'watcher' : 'runner', 'loading', files); var spawn = require('child_process').spawn; function cwdname(f) { return f.replace(process.cwd() + '/', '') + '.js'; } function wrapSpawn(f) { f = cwdname(f); return function (options, callback) { var args = [process.argv[1], '--json', f], result; // --supress-stdout stops the stream too early on win32 if(process.platform !== 'win32') { args.push( '--supress-stdout'); } var p = spawn(process.execPath, args); // // AvianFlu, you broke the API! OH NOEZ. // Anyway. // Since node 0.7.something, semantics of child process events // changed - `exit` event is emitted when child process exits // and `close` event is emitted when child's streams stdio streams // are closed. `exit` event is emitted before `close` event, and // since we use child's stdio streams, we shouldn't rely on `exit` // event. // p.on(nodeMinorVersion >= 7 ? 'close' : 'exit', function (code) { callback( !result ? {errored: 1, total: 1} : result ); }); var buffer = []; p.stdout.on('data', function (data) { data = data.toString().split(/\n/g); if (data.length == 1) { buffer.push(data[0]); } else { data[0] = buffer.concat(data[0]).join(''); buffer = [data.pop()]; data.forEach(function (data) { if (data && data !== 'undefined') { try { data = JSON.parse(data); // on win32 we may get back console.log strings which break JSON.parse if (data && data[0] === 'finish') { result = data[1]; } else { reporter.report(data); } } catch(e) { } } }); } }); p.stderr.pipe(process.stderr); } } return files.reduce(options.isolate ? function (suites, f) { return suites.concat({ run: wrapSpawn(f) }); } : function (suites, f) { //f = path.join(process.cwd(), path.relative(process.cwd(),f)); var obj = require(f); return suites.concat(Object.keys(obj).map(function (s) { obj[s]._filename = cwdname(f); return obj[s]; })); }, []) } // // Recursively traverse a hierarchy, returning // a list of all relevant .js files. // function paths(dir) { var paths = []; try { fs.statSync(dir) } catch (e) { return [] } (function traverse(dir, stack) { stack.push(dir); var dirPath = stack.join('/'); fs.readdirSync(stack.join('/')).forEach(function (file) { // // Skip dotfiles and `vendor` directory before `fs.stat()`ing them. // Not doing so causes race conditions with Emacs buffer files // (`.#filename.js`). // if (file[0] == '.' || file === 'vendor') { return; } var path = stack.concat([file]).join('/'), stat = fs.statSync(path); if (stat.isFile() && fileExt.test(file)) { paths.push(path); } else if (stat.isDirectory()) { traverse(file, stack); } }); stack.pop(); })(dir || '.', []); return paths; } function msg(cmd, subject, str, p) { if (options.verbose) { util[p ? 'print' : 'puts']( stylize('vows ', 'green') + stylize(cmd, 'bold') + ' ' + subject + ' ' + (str ? (typeof(str) === 'string' ? str : inspect(str)) : '') ); } } function abort(cmd, str) { console.log(stylize('vows ', 'red') + stylize(cmd, 'bold') + ' ' + str); console.log(stylize('vows ', 'red') + stylize(cmd, 'bold') + ' exiting'); process.exit(-1); } vows-0.7.0/lib/000077500000000000000000000000001205150302300132515ustar00rootroot00000000000000vows-0.7.0/lib/assert/000077500000000000000000000000001205150302300145525ustar00rootroot00000000000000vows-0.7.0/lib/assert/error.js000066400000000000000000000105071205150302300162440ustar00rootroot00000000000000/** This software contains code adapted from Mocha (https://github.com/visionmedia/mocha) by TJ Holowaychuk and is used herein under the following MIT license: Copyright (c) 2011-2012 TJ Holowaychuk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ var stylize = require('../vows/console').stylize; var inspect = require('../vows/console').inspect; var diff = require('diff'); /** * Pad the given `str` to `len`. * * @param {String} str * @param {String} len * @return {String} * @api private */ function pad(str, len) { str = String(str); return Array(len - str.length + 1).join(' ') + str; } /** * Color lines for `str`, using the color `name`. * * @param {String} name * @param {String} str * @return {String} * @api private */ function styleLines(str, name) { return str.split('\n').map(function(str){ return stylize(str, name); }).join('\n'); } /** * Return a character diff for `err`. * * @param {Error} err * @return {String} * @api private */ function errorDiff(err, type) { return diff['diff' + type](err.actual, err.expected).map(function(str){ if (/^(\n+)$/.test(str.value)) str.value = Array(++RegExp.$1.length).join(''); if (str.added) return styleLines(str.value, 'green'); if (str.removed) return styleLines(str.value, 'red'); return str.value; }).join(''); } require('assert').AssertionError.prototype.toString = function () { var that = this, source; if (this.stack) { source = this.stack.match(/([a-zA-Z0-9._-]+\.(?:js|coffee))(:\d+):\d+/); } function parse(str) { var actual = that.actual, expected = that.expected, msg, len; if ( 'string' === typeof actual && 'string' === typeof expected ) { len = Math.max(actual.length, expected.length); if (len < 20) msg = errorDiff(that, 'Chars'); else msg = errorDiff(that, 'Words'); // linenos var lines = msg.split('\n'); if (lines.length > 4) { var width = String(lines.length).length; msg = lines.map(function(str, i){ return pad(++i, width) + ' |' + ' ' + str; }).join('\n'); } // legend msg = '\n' + stylize('actual', 'green') + ' ' + stylize('expected', 'red') + '\n\n' + msg + '\n'; // indent msg = msg.replace(/^/gm, ' '); return msg; } actual = inspect(actual, {showHidden: actual instanceof Error}); if (expected instanceof Function) { expected = expected.name; } else { expected = inspect(expected, {showHidden: actual instanceof Error}); } return str.replace(/{actual}/g, actual). replace(/{operator}/g, stylize(that.operator, 'bold')). replace(/{expected}/g, expected); } if (this.message) { var msg = stylize(parse(this.message), 'yellow'); if (source) { msg += stylize(' // ' + source[1] + source[2], 'grey'); } return msg; } else { return stylize([ this.expected, this.operator, this.actual ].join(' '), 'yellow'); } }; vows-0.7.0/lib/assert/macros.js000066400000000000000000000173171205150302300164050ustar00rootroot00000000000000var assert = require('assert'), utils = require('./utils'); var messages = { 'equal' : "expected {expected},\n\tgot\t {actual} ({operator})", 'notEqual' : "didn't expect {actual} ({operator})" }; messages['strictEqual'] = messages['deepEqual'] = messages['equal']; messages['notStrictEqual'] = messages['notDeepEqual'] = messages['notEqual']; for (var key in messages) { assert[key] = (function (key, callback) { return function (actual, expected, message) { callback(actual, expected, message || messages[key]); }; })(key, assert[key]); } assert.epsilon = function (eps, actual, expected, message) { if (Math.abs(actual - expected) > eps) { assert.fail(actual, expected, message || "expected {expected} \u00B1"+ eps +", but was {actual}"); } }; assert.ok = (function (callback) { return function (actual, message) { callback(actual, message || "expected expression to evaluate to {expected}, but was {actual}"); }; })(assert.ok); assert.match = function (actual, expected, message) { if (! expected.test(actual)) { assert.fail(actual, expected, message || "expected {actual} to match {expected}", "match", assert.match); } }; assert.matches = assert.match; assert.isTrue = function (actual, message) { if (actual !== true) { assert.fail(actual, true, message || "expected {expected}, got {actual}", "===", assert.isTrue); } }; assert.isFalse = function (actual, message) { if (actual !== false) { assert.fail(actual, false, message || "expected {expected}, got {actual}", "===", assert.isFalse); } }; assert.isZero = function (actual, message) { if (actual !== 0) { assert.fail(actual, 0, message || "expected {expected}, got {actual}", "===", assert.isZero); } }; assert.isNotZero = function (actual, message) { if (actual === 0) { assert.fail(actual, 0, message || "expected non-zero value, got {actual}", "===", assert.isNotZero); } }; assert.greater = function (actual, expected, message) { if (actual <= expected) { assert.fail(actual, expected, message || "expected {actual} to be greater than {expected}", ">", assert.greater); } }; assert.lesser = function (actual, expected, message) { if (actual >= expected) { assert.fail(actual, expected, message || "expected {actual} to be lesser than {expected}", "<", assert.lesser); } }; assert.inDelta = function (actual, expected, delta, message) { var lower = expected - delta; var upper = expected + delta; if (actual < lower || actual > upper) { assert.fail(actual, expected, message || "expected {actual} to be in within *" + delta.toString() + "* of {expected}", null, assert.inDelta); } }; // // Inclusion // assert.include = function (actual, expected, message) { if ((function (obj) { if (isArray(obj) || isString(obj)) { return obj.indexOf(expected) === -1; } else if (isObject(actual)) { return ! obj.hasOwnProperty(expected); } return true; })(actual)) { assert.fail(actual, expected, message || "expected {actual} to include {expected}", "include", assert.include); } }; assert.includes = assert.include; assert.deepInclude = function (actual, expected, message) { if (!isArray(actual)) { return assert.include(actual, expected, message); } if (!actual.some(function (item) { return utils.deepEqual(item, expected) })) { assert.fail(actual, expected, message || "expected {actual} to include {expected}", "include", assert.deepInclude); } }; assert.deepIncludes = assert.deepInclude; // // Length // assert.isEmpty = function (actual, message) { if ((isObject(actual) && Object.keys(actual).length > 0) || actual.length > 0) { assert.fail(actual, 0, message || "expected {actual} to be empty", "length", assert.isEmpty); } }; assert.isNotEmpty = function (actual, message) { if ((isObject(actual) && Object.keys(actual).length === 0) || actual.length === 0) { assert.fail(actual, 0, message || "expected {actual} to be not empty", "length", assert.isNotEmpty); } }; assert.lengthOf = function (actual, expected, message) { var len = isObject(actual) ? Object.keys(actual).length : actual.length; if (len !== expected) { assert.fail(actual, expected, message || "expected {actual} to have {expected} element(s)", "length", assert.length); } }; // // Type // assert.isArray = function (actual, message) { assertTypeOf(actual, 'array', message || "expected {actual} to be an Array", assert.isArray); }; assert.isObject = function (actual, message) { assertTypeOf(actual, 'object', message || "expected {actual} to be an Object", assert.isObject); }; assert.isNumber = function (actual, message) { if (isNaN(actual)) { assert.fail(actual, 'number', message || "expected {actual} to be of type {expected}", "isNaN", assert.isNumber); } else { assertTypeOf(actual, 'number', message || "expected {actual} to be a Number", assert.isNumber); } }; assert.isBoolean = function (actual, message) { if (actual !== true && actual !== false) { assert.fail(actual, 'boolean', message || "expected {actual} to be a Boolean", "===", assert.isBoolean); } }; assert.isNaN = function (actual, message) { if (actual === actual) { assert.fail(actual, 'NaN', message || "expected {actual} to be NaN", "===", assert.isNaN); } }; assert.isNull = function (actual, message) { if (actual !== null) { assert.fail(actual, null, message || "expected {expected}, got {actual}", "===", assert.isNull); } }; assert.isNotNull = function (actual, message) { if (actual === null) { assert.fail(actual, null, message || "expected non-null value, got {actual}", "===", assert.isNotNull); } }; assert.isUndefined = function (actual, message) { if (actual !== undefined) { assert.fail(actual, undefined, message || "expected {actual} to be {expected}", "===", assert.isUndefined); } }; assert.isDefined = function (actual, message) { if(actual === undefined) { assert.fail(actual, 0, message || "expected {actual} to be defined", "===", assert.isDefined); } }; assert.isString = function (actual, message) { assertTypeOf(actual, 'string', message || "expected {actual} to be a String", assert.isString); }; assert.isFunction = function (actual, message) { assertTypeOf(actual, 'function', message || "expected {actual} to be a Function", assert.isFunction); }; assert.typeOf = function (actual, expected, message) { assertTypeOf(actual, expected, message, assert.typeOf); }; assert.instanceOf = function (actual, expected, message) { if (! (actual instanceof expected)) { assert.fail(actual, expected, message || "expected {actual} to be an instance of {expected}", "instanceof", assert.instanceOf); } }; // // Utility functions // function assertTypeOf(actual, expected, message, caller) { if (typeOf(actual) !== expected) { assert.fail(actual, expected, message || "expected {actual} to be of type {expected}", "typeOf", caller); } }; function isArray (obj) { return Array.isArray(obj); } function isString (obj) { return typeof(obj) === 'string' || obj instanceof String; } function isObject (obj) { return typeof(obj) === 'object' && obj && !isArray(obj); } // A better `typeof` function typeOf(value) { var s = typeof(value), types = [Object, Array, String, RegExp, Number, Function, Boolean, Date]; if (s === 'object' || s === 'function') { if (value) { types.forEach(function (t) { if (value instanceof t) { s = t.name.toLowerCase() } }); } else { s = 'null' } } return s; } vows-0.7.0/lib/assert/utils.js000066400000000000000000000035611205150302300162550ustar00rootroot00000000000000 // Taken from node/lib/assert.js exports.deepEqual = function (actual, expected) { if (actual === expected) { return true; } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { if (actual.length != expected.length) return false; for (var i = 0; i < actual.length; i++) { if (actual[i] !== expected[i]) return false; } return true; } else if (actual instanceof Date && expected instanceof Date) { return actual.getTime() === expected.getTime(); } else if (typeof actual != 'object' && typeof expected != 'object') { return actual == expected; } else { return objEquiv(actual, expected); } } // Taken from node/lib/assert.js exports.notDeepEqual = function (actual, expected, message) { if (exports.deepEqual(actual, expected)) { fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); } } // Taken from node/lib/assert.js function isUndefinedOrNull(value) { return value === null || value === undefined; } // Taken from node/lib/assert.js function isArguments(object) { return Object.prototype.toString.call(object) == '[object Arguments]'; } // Taken from node/lib/assert.js function objEquiv(a, b) { if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) return false; if (a.prototype !== b.prototype) return false; if (isArguments(a)) { if (!isArguments(b)) { return false; } a = pSlice.call(a); b = pSlice.call(b); return exports.deepEqual(a, b); } try { var ka = Object.keys(a), kb = Object.keys(b), key, i; } catch (e) { return false; } if (ka.length != kb.length) return false; ka.sort(); kb.sort(); for (i = ka.length - 1; i >= 0; i--) { if (ka[i] != kb[i]) return false; } for (i = ka.length - 1; i >= 0; i--) { key = ka[i]; if (!exports.deepEqual(a[key], b[key])) return false; } return true; } vows-0.7.0/lib/utils/000077500000000000000000000000001205150302300144115ustar00rootroot00000000000000vows-0.7.0/lib/utils/wildcard.js000066400000000000000000000062511205150302300165440ustar00rootroot00000000000000/** * (C) Microsoft Open Technologies, Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var PATH = require('path'); var fs = require('fs'); /** * @type {Function} wildcard(pattern) * wildcard searches for files matching pattern. * * @pattern {String} search pattern with optional * wildcards * @return an array containing the paths to the matching files */ var wildcard = exports.wildcard = function(pattern) { // process pattern string for * wildcard var matchers = [], tokens, path; var index = pattern.indexOf('*'); if(index === -1) { return [pattern]; } path = pattern.substr(0, index-1); pattern = pattern.substr(index); pattern = pattern.replace(/\*/g, '(?=.*)'); tokens = pattern.split(PATH.sep); // create matcher regex for each path component in pattern tokens.forEach(function(token, index, array) { var matcher = {}; matcher.index = index; matcher.isDir = index < array.length -1; matcher.regex = new RegExp(token); matchers.push(matcher); }); return process(path, matchers); }; // searches starting from the path directory and returns files matching wildcard pattern // search only proceeds to directory depth equal to the numbe rof matchers. var process = function(path, matchers) { var files = []; var traverse = function(path, level) { var dirs, matcher; // check we have not exceeded search directory depth if(level >= matchers.length) { return; } // read the dirs and files from the current path dirs = fs.readdirSync(path); matcher = matchers[level]; // check if each dir or file matches the matcher for the current directory level for(var i = 0; i < dirs.length; i++) { var dir = dirs[i]; if(dir.match(matcher.regex) === null) { continue; } var pathName = PATH.join(path,dir); var stats = fs.statSync(pathName); if(stats.isDirectory()) { if(matcher.isDir) { traverse(pathName, level + 1); } else { continue; } } else if(level === matchers.length - 1) { // found a matching file if(stats.isFile()) { files.push(pathName); } } } }; traverse(path, 0); return files; }; //var pattern = '/Users/stammen/dev/microsoft/pkgcloud/test/*/*/*-test.js'; // //var result = wildcard(pattern); //console.log(result); //console.log(result.length); vows-0.7.0/lib/vows.js000066400000000000000000000175441205150302300146200ustar00rootroot00000000000000// // Vows.js - asynchronous event-based BDD for node.js // // usage: // // var vows = require('vows'); // // vows.describe('Deep Thought').addBatch({ // "An instance of DeepThought": { // topic: new DeepThought, // // "should know the answer to the ultimate question of life": function (deepThought) { // assert.equal (deepThought.question('what is the answer to the universe?'), 42); // } // } // }).run(); // var util = require('util'), path = require('path'), events = require('events'), vows = exports; // Options vows.options = { Emitter: events.EventEmitter, reporter: require('./vows/reporters/dot-matrix'), matcher: /.*/, error: true // Handle "error" event }; vows.__defineGetter__('reporter', function () { return vows.options.reporter; }); var stylize = require('./vows/console').stylize; var console = vows.console = require('./vows/console'); vows.inspect = require('./vows/console').inspect; vows.prepare = require('./vows/extras').prepare; vows.tryEnd = require('./vows/suite').tryEnd; // // Assertion Macros & Extensions // require('./assert/error'); require('./assert/macros'); // // Suite constructor // var Suite = require('./vows/suite').Suite; // // This function gets added to events.EventEmitter.prototype, by default. // It's essentially a wrapper around `on`, which adds all the specification // goodness. // function addVow(vow) { var batch = vow.batch, event = vow.binding.context.event || 'success', self = this; batch.total ++; batch.vows.push(vow); // always set a listener on the event this.on(event, function () { var args = Array.prototype.slice.call(arguments); // If the vow is a sub-event then we know it is an // emitted event. So I don't muck with the arguments // However the legacy behavior: // If the callback is expecting two or more arguments, // pass the error as the first (null) and the result after. if (!(this.ctx && this.ctx.isEvent) && vow.callback.length >= 2 && batch.suite.options.error) { args.unshift(null); } runTest(args, this.ctx); vows.tryEnd(batch); }); if (event !== 'error') { this.on("error", function (err) { if (vow.callback.length >= 2 || !batch.suite.options.error) { runTest(arguments, this.ctx); } else { output('errored', { type: 'promise', error: err.stack || err.message || JSON.stringify(err) }); } vows.tryEnd(batch); }); } // in case an event fired before we could listen if (this._vowsEmitedEvents && this._vowsEmitedEvents.hasOwnProperty(event)) { // make sure no one is messing with me if (Array.isArray(this._vowsEmitedEvents[event])) { // I don't think I need to optimize for one event, // I think it is more important to make sure I check the vow n times self._vowsEmitedEvents[event].forEach(function(args) { runTest(args, self.ctx); }); } else { // initial conditions problem throw new Error('_vowsEmitedEvents[' + event + '] is not an Array') } vows.tryEnd(batch); } return this; function runTest(args, ctx) { if (vow.callback instanceof String) { return output('pending'); } if (vow.binding.context.isEvent && vow.binding.context.after) { var after = vow.binding.context.after; // only need to check order. I won't get here if the after event // has never been emitted if (self._vowsEmitedEventsOrder.indexOf(after) > self._vowsEmitedEventsOrder.indexOf(event)) { output('broken', event + ' emitted before ' + after); return; } } // Run the test, and try to catch `AssertionError`s and other exceptions; // increment counters accordingly. try { vow.callback.apply(ctx === global || !ctx ? vow.binding : ctx, args); output('honored'); } catch (e) { if (e.name && e.name.match(/AssertionError/)) { output('broken', e.toString().replace(/\`/g, '`')); } else { output('errored', e.stack || e.message || e); } } } function output(status, exception) { batch[status] ++; vow.status = status; if (vow.context && batch.lastContext !== vow.context) { batch.lastContext = vow.context; batch.suite.report(['context', vow.context]); } batch.suite.report(['vow', { title: vow.description, context: vow.context, status: status, exception: exception || null }]); } }; // // On exit, check that all promises have been fired. // If not, report an error message. // process.on('exit', function () { var results = { honored: 0, broken: 0, errored: 0, pending: 0, total: 0 }, failure; vows.suites.forEach(function (s) { if ((s.results.total > 0) && (s.results.time === null)) { s.reporter.print('\n\n'); s.reporter.report(['error', { error: "Asynchronous Error", suite: s }]); } s.batches.forEach(function (b) { var unFired = []; b.vows.forEach(function (vow) { if (! vow.status) { if (unFired.indexOf(vow.context) === -1) { unFired.push(vow.context); } } }); if (unFired.length > 0) { util.print('\n') } unFired.forEach(function (title) { s.reporter.report(['error', { error: "callback not fired", context: title, batch: b, suite: s }]); }); if (b.status === 'begin') { failure = true; results.errored ++; results.total ++; } Object.keys(results).forEach(function (k) { results[k] += b[k] }); }); }); if (failure) { util.puts(console.result(results)); process.exit(1); } }); vows.suites = []; // We need the old emit function so we can hook it // and do magic to deal with events that have fired var oldEmit = vows.options.Emitter.prototype.emit; // // Create a new test suite // vows.describe = function (subject) { var suite = new(Suite)(subject); this.options.Emitter.prototype.addVow = addVow; // just in case someone emit's before I get to it this.options.Emitter.prototype.emit = function (event) { this._vowsEmitedEvents = this._vowsEmitedEvents || {}; this._vowsEmitedEventsOrder = this._vowsEmitedEventsOrder || []; // slice off the event var args = Array.prototype.slice.call(arguments, 1); // if multiple events are fired, add or push if (this._vowsEmitedEvents.hasOwnProperty(event)) { this._vowsEmitedEvents[event].push(args); } else { this._vowsEmitedEvents[event] = [args]; } // push the event onto a stack so I have an order this._vowsEmitedEventsOrder.push(event); return oldEmit.apply(this, arguments); } this.suites.push(suite); // // Add any additional arguments as batches if they're present // if (arguments.length > 1) { for (var i = 1, l = arguments.length; i < l; ++i) { suite.addBatch(arguments[i]); } } return suite; }; vows.version = JSON.parse(require('fs') .readFileSync(path.join(__dirname, '..', 'package.json'))) .version vows-0.7.0/lib/vows/000077500000000000000000000000001205150302300142475ustar00rootroot00000000000000vows-0.7.0/lib/vows/console.js000066400000000000000000000105571205150302300162570ustar00rootroot00000000000000var eyes = require('eyes').inspector({ stream: null, styles: false }); // Stylize a string this.stylize = function stylize(str, style) { if (module.exports.nocolor) { return str; } var styles = { 'bold' : [1, 22], 'italic' : [3, 23], 'underline' : [4, 24], 'cyan' : [96, 39], 'yellow' : [33, 39], 'green' : [32, 39], 'red' : [31, 39], 'grey' : [90, 39], 'green-hi' : [92, 32], }; return '\033[' + styles[style][0] + 'm' + str + '\033[' + styles[style][1] + 'm'; }; var $ = this.$ = function (str) { str = new(String)(str); ['bold', 'grey', 'yellow', 'red', 'green', 'white', 'cyan', 'italic'].forEach(function (style) { Object.defineProperty(str, style, { get: function () { return exports.$(exports.stylize(this, style)); } }); }); return str; }; this.puts = function (options) { var stylize = exports.stylize; options.stream || (options.stream = process.stdout); options.tail = options.tail || ''; return function (args) { args = Array.prototype.slice.call(arguments); if (!options.raw) { args = args.map(function (a) { return a.replace(/`([^`]+)`/g, function (_, capture) { return stylize(capture, 'italic') }) .replace(/\*([^*]+)\*/g, function (_, capture) { return stylize(capture, 'bold') }) .replace(/\n/g, function (_, capture) { return ' \n ' } ); }); } return options.stream.write(args.join('\n') + options.tail); }; }; this.result = function (event) { var result = [], buffer = [], time = '', header; var complete = event.honored + event.pending + event.errored + event.broken; var status = (event.errored && 'errored') || (event.broken && 'broken') || (event.honored && 'honored') || (event.pending && 'pending'); if (event.total === 0) { return [$("Could not find any tests to run.").bold.red]; } event.honored && result.push($(event.honored).bold + " honored"); event.broken && result.push($(event.broken).bold + " broken"); event.errored && result.push($(event.errored).bold + " errored"); event.pending && result.push($(event.pending).bold + " pending"); if (complete < event.total) { result.push($(event.total - complete).bold + " dropped"); } result = result.join(' ∙ '); header = { honored: '✓ ' + $('OK').bold.green, broken: '✗ ' + $('Broken').bold.yellow, errored: '✗ ' + $('Errored').bold.red, pending: '- ' + $('Pending').bold.cyan }[status] + ' » '; if (typeof(event.time) === 'number') { time = ' (' + event.time.toFixed(3) + 's)'; time = this.stylize(time, 'grey'); } buffer.push(header + result + time + '\n'); return buffer; }; this.inspect = function inspect(val) { if (module.exports.nocolor) { return eyes(val); } return '\033[1m' + eyes(val) + '\033[22m'; }; this.error = function (obj) { var string = '✗ ' + $('Errored ').red + '» '; string += $(obj.error).red.bold + '\n'; string += (obj.context ? ' in ' + $(obj.context).red + '\n': ''); string += ' in ' + $(obj.suite.subject).red + '\n'; string += ' in ' + $(obj.suite._filename).red; return string; }; this.contextText = function (event) { return ' ' + event; }; this.vowText = function (event) { var buffer = []; buffer.push(' ' + { honored: ' ✓ ', broken: ' ✗ ', errored: ' ✗ ', pending: ' - ' }[event.status] + this.stylize(event.title, ({ honored: 'green', broken: 'yellow', errored: 'red', pending: 'cyan' })[event.status])); if (event.status === 'broken') { buffer.push(' » ' + event.exception); } else if (event.status === 'errored') { if (event.exception.type === 'promise') { buffer.push(' » ' + this.stylize("An unexpected error was caught: " + this.stylize(event.exception.error, 'bold'), 'red')); } else { buffer.push(' ' + this.stylize(event.exception, 'red')); } } return buffer.join('\n'); }; vows-0.7.0/lib/vows/context.js000066400000000000000000000052761205150302300163030ustar00rootroot00000000000000 this.Context = function (vow, ctx, env) { var that = this; this.tests = vow.callback; this.topics = (ctx.topics || []).slice(0); this.emitter = null; this.env = env || {}; this.env.context = this; this.env.callback = function (/* arguments */) { var ctx = this; var args = Array.prototype.slice.call(arguments); var emit = (function (args) { // // Convert callback-style results into events. // if (vow.batch.suite.options.error) { return function () { var e = args.shift(); that.emitter.ctx = ctx; // We handle a special case, where the first argument is a // boolean, in which case we treat it as a result, and not // an error. This is useful for `path.exists` and other // functions like it, which only pass a single boolean // parameter instead of the more common (error, result) pair. if (typeof(e) === 'boolean' && args.length === 0) { that.emitter.emit.call(that.emitter, 'success', e); } else { if (e) { that.emitter.emit.apply(that.emitter, ['error', e].concat(args)) } else { that.emitter.emit.apply(that.emitter, ['success'].concat(args)) } } }; } else { return function () { that.emitter.ctx = ctx; that.emitter.emit.apply(that.emitter, ['success'].concat(args)); }; } })(args.slice(0)); // If `this.callback` is called synchronously, // the emitter will not have been set yet, // so we defer the emition, that way it'll behave // asynchronously. if (that.emitter) { emit() } else { process.nextTick(emit) } }; this.name = vow.description; // events is an alias for on if (this.name === 'events') { this.name = vow.description = 'on'; } // if this is a sub-event context AND it's context was an event, // then I must enforce event order. // this will not do a good job of handling pin-pong events if (this.name === 'on' && ctx.isEvent) { this.after = ctx.name; } if (ctx.name === 'on') { this.isEvent = true; this.event = this.name; this.after = ctx.after; } else { this.isEvent = false; this.event = 'success'; } this.title = [ ctx.title || '', vow.description || '' ].join(/^[#.:]/.test(vow.description) ? '' : ' ').trim(); }; vows-0.7.0/lib/vows/coverage/000077500000000000000000000000001205150302300160425ustar00rootroot00000000000000vows-0.7.0/lib/vows/coverage/file.js000066400000000000000000000012071205150302300173170ustar00rootroot00000000000000 exports.coverage = function (filename, data) { var ret = { filename: filename, coverage: 0, hits: 0, misses: 0, sloc : 0 }; var source = data.source; ret.source = source.map(function (line, num) { num++; if (data[num] === 0) { ret.misses++; ret.sloc++; } else if (data[num] !== undefined) { ret.hits++; ret.sloc++; } return { line: line, coverage: (data[num] === undefined ? '' : data[num]) }; }); ret.coverage = (ret.hits / ret.sloc) * 100; return ret; };vows-0.7.0/lib/vows/coverage/fragments/000077500000000000000000000000001205150302300200305ustar00rootroot00000000000000vows-0.7.0/lib/vows/coverage/fragments/coverage-foot.html000066400000000000000000000000271205150302300234550ustar00rootroot00000000000000 vows-0.7.0/lib/vows/coverage/fragments/coverage-head.html000066400000000000000000000401211205150302300234060ustar00rootroot00000000000000 Coverage
vows-0.7.0/lib/vows/coverage/report-html.js000066400000000000000000000117121205150302300206570ustar00rootroot00000000000000/** This software contains code adapted from Mocha (https://github.com/visionmedia/mocha) by TJ Holowaychuk and is used herein under the following MIT license: Copyright (c) 20011-2012 TJ Holowaychuk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ var util = require('util'), path = require('path'), fs = require('fs'), file = require('./file'); this.name = 'coverage-report-html'; function getCoverageClass( data ) { var highCoverage= (data.coverage >= 80); var okCoverage= (!highCoverage && data.coverage >=60); var coverageClass= ''; if( highCoverage ) coverageClass= 'high'; else if( okCoverage) coverageClass= 'medium'; else coverageClass= 'low'; return coverageClass; } this.report = function (coverageMap) { var out, head, foot, files = [], summary = { hits: 0, misses: 0, sloc: 0 }; try { out = fs.openSync("coverage.html", "w"); head = fs.readFileSync(__dirname + "/fragments/coverage-head.html", "utf8"); foot = fs.readFileSync(__dirname + "/fragments/coverage-foot.html", "utf8"); } catch (error) { util.print("Error: Unable to write to file coverage.html\n"); return; } fs.writeSync(out, head); for (var filename in coverageMap) { if (coverageMap.hasOwnProperty(filename)) { var data = file.coverage(filename, coverageMap[filename]); data.filename = filename; files.push(data); summary.hits += data.hits; summary.misses += data.misses; summary.sloc += data.sloc; } } summary.coverage = (summary.hits / summary.sloc) * 100; fs.writeSync(out, '

Coverage

'); fs.writeSync(out, '
' + '
' + summary.hits + '
' + summary.misses + '
' + summary.sloc + '
' + summary.coverage.toFixed(0) + "%
"); files.forEach(function (data) { var coverageClass = getCoverageClass(data); fs.writeSync(out, '
'); fs.writeSync(out, '

' + data.filename + '

\n'); fs.writeSync(out, '
' + '
' + data.hits + '
' + data.misses + '
' + data.sloc + '
' + data.coverage.toFixed(0) + "%
"); fs.writeSync(out, ''); for (var i = 0, l = data.source.length; i < l; i++) { var line = data.source[i], klass = (line.coverage === 0 ? 'miss' : 'hit'); fs.writeSync(out, ''); } fs.writeSync(out, "
LineHitsSource
' + i + '' + line.coverage + '' + line.line + '
\n"); fs.writeSync(out, "
\n"); }); fs.writeSync(out, foot); fs.close(out); }; vows-0.7.0/lib/vows/coverage/report-json.js000066400000000000000000000027461205150302300206730ustar00rootroot00000000000000var util = require('util'), fs = require('fs'), file = require('./file'); this.name = 'coverage-report-json'; this.report = function (coverageMap) { var output = { meta: { "generator": "vowsjs", "generated": new Date().toString(), "instrumentation": "node-jscoverage", "file-version": "1.0" }, files: [ ], coverage: [ ] }; for (var filename in coverageMap) { if (coverageMap.hasOwnProperty(filename)) { var data = file.coverage(filename, coverageMap[filename]); var coverage = { file: filename, coverage: data.coverage.toFixed(2), hits: data.hits, misses: data.misses, sloc: data.sloc, source: { } }; for (var i = 0; i < data.source.length; i++) { coverage.source[i + 1] = { line: data.source[i].line, coverage: data.source[i].coverage }; } output.coverage.push(coverage); output.files.push(filename); } } try { out = fs.openSync("coverage.json", "w"); fs.writeSync(out, JSON.stringify(output)); fs.close(out); } catch (error) { util.print("Error: Unable to write to file coverage.json\n"); return; } }; vows-0.7.0/lib/vows/coverage/report-plain.js000066400000000000000000000017121205150302300210150ustar00rootroot00000000000000var util = require('util'), file = require('./file'); this.name = 'coverage-report-plain'; function lpad(str, width) { str = String(str); var n = width - str.length; if (n < 1) { return str; } while (n--) { str = ' ' + str; } return str; } this.report = function (coverageMap) { for (var filename in coverageMap) { if (coverageMap.hasOwnProperty(filename)) { var data = file.coverage(filename, coverageMap[filename]); util.print(filename + ":\n"); util.print("[ hits: " + data.hits + ", misses: " + data.misses); util.print(", sloc: " + data.sloc + ", coverage: " + data.coverage.toFixed(2) + "% ]\n"); for (var i = 0; i < data.source.length; i++) { util.print(lpad(data.source[i].coverage, 5) + " | " + data.source[i].line + "\n"); } util.print("\n"); } } }; vows-0.7.0/lib/vows/coverage/report-xml.js000066400000000000000000000054371205150302300205220ustar00rootroot00000000000000var fs = require('fs'), file = require('./file'); this.name = 'coverage-report-xml'; this.report = function (coverageMap) { var all = { xml: '', packages: 0, files: 0, lines: 0, hits: 0 }, data = {}; // group data by path for (var filename in coverageMap) { if (coverageMap.hasOwnProperty(filename)) { var pkg = (filename.indexOf('/') > 0) ? filename.substr(0, filename.lastIndexOf('/')) : filename; if (!data[pkg]) { data[pkg] = {}; } data[pkg][ (filename.indexOf('/')) ? filename.substr(filename.lastIndexOf('/') + 1, filename.length) : filename ] = file.coverage(filename, coverageMap[filename]); } } // generate groups xml-fragment for (var pkg in data) { if (data.hasOwnProperty(pkg)) { var pkgStat = { xml: '', files: 0, lines: 0, hits: 0 }; all.xml += '\t\n'; for (var filename in data[pkg]) { if (data[pkg].hasOwnProperty(filename)) { pkgStat.files += 1; pkgStat.lines += data[pkg][filename].sloc; pkgStat.hits += data[pkg][filename].hits; pkgStat.xml += '\t\t\n' + '\t\t\t\n' + '\t\t\n'; } } all.packages += 1; all.files += pkgStat.files; all.lines += pkgStat.lines; all.hits += pkgStat.hits; all.xml += '\t\t\n' + pkgStat.xml + '\t\n'; } } all.xml = '\n' + '\n\n' + '\t\n' + '\t\n' + '\t\n' + '\t\n' + '\t\n' + '\n\n' + '\n' + '\t\n' + all.xml + '\n\n\n'; fs.writeFileSync('coverage.xml', all.xml); }; vows-0.7.0/lib/vows/extras.js000066400000000000000000000016111205150302300161120ustar00rootroot00000000000000var events = require('events'); // // Wrap a Node.js style async function into an EventEmmitter // this.prepare = function (obj, targets) { targets.forEach(function (target) { if (target in obj) { obj[target] = (function (fun) { return function () { var args = Array.prototype.slice.call(arguments); var ee = new(events.EventEmitter); args.push(function (err /* [, data] */) { var args = Array.prototype.slice.call(arguments, 1); if (err) { ee.emit.apply(ee, ['error', err].concat(args)) } else { ee.emit.apply(ee, ['success'].concat(args)) } }); fun.apply(obj, args); return ee; }; })(obj[target]); } }); return obj; }; vows-0.7.0/lib/vows/reporters/000077500000000000000000000000001205150302300162745ustar00rootroot00000000000000vows-0.7.0/lib/vows/reporters/dot-matrix.js000066400000000000000000000034721205150302300207300ustar00rootroot00000000000000var options = { tail: '' }, console = require('../../vows/console'), stylize = console.stylize, puts = console.puts(options); // // Console reporter // var messages = [], lastContext; this.name = 'dot-matrix'; this.setStream = function (s) { options.stream = s; }; this.reset = function () { messages = []; lastContext = null; }; this.report = function (data) { var event = data[1]; switch (data[0]) { case 'subject': // messages.push(stylize(event, 'underline') + '\n'); break; case 'context': break; case 'vow': if (event.status === 'honored') { puts(stylize('·', 'green')); } else if (event.status === 'pending') { puts(stylize('-', 'cyan')); } else { if (lastContext !== event.context) { lastContext = event.context; messages.push(' ' + event.context); } if (event.status === 'broken') { puts(stylize('✗', 'yellow')); messages.push(console.vowText(event)); } else if (event.status === 'errored') { puts(stylize('✗', 'red')); messages.push(console.vowText(event)); } messages.push(''); } break; case 'end': puts(' '); break; case 'finish': if (messages.length) { puts('\n\n' + messages.join('\n')); } else { puts(''); } puts(console.result(event).join('\n')); break; case 'error': puts(console.error(event)); break; } }; this.print = function (str) { puts(str); }; vows-0.7.0/lib/vows/reporters/json.js000066400000000000000000000013231205150302300176020ustar00rootroot00000000000000var options = { tail: '\n', raw: true }; var console = require('../../vows/console'); var puts = console.puts(options); // // Console JSON reporter // this.name = 'json'; this.setStream = function (s) { options.stream = s; }; function removeCircularSuite(obj, suite) { var result = {}; if (typeof obj !== 'object' || obj === null) return obj; Object.keys(obj).forEach(function(key) { if (obj[key] === suite) { result[key] = {}; } else { result[key] = removeCircularSuite(obj[key], suite || obj.suite); } }); return result; }; this.report = function (obj) { puts(JSON.stringify(removeCircularSuite(obj))); }; this.print = function (str) {}; vows-0.7.0/lib/vows/reporters/silent.js000066400000000000000000000002251205150302300201270ustar00rootroot00000000000000// // Silent reporter - "Shhh" // this.name = 'silent'; this.reset = function () {}; this.report = function () {}; this.print = function () {}; vows-0.7.0/lib/vows/reporters/spec.js000066400000000000000000000016511205150302300175670ustar00rootroot00000000000000var util = require('util'); var options = { tail: '\n' }; var console = require('../../vows/console'); var stylize = console.stylize, puts = console.puts(options); // // Console reporter // this.name = 'spec'; this.setStream = function (s) { options.stream = s; }; this.report = function (data) { var event = data[1]; switch (data[0]) { case 'subject': puts('\n♢ ' + stylize(event, 'bold') + '\n'); break; case 'context': puts(console.contextText(event)); break; case 'vow': puts(console.vowText(event)); break; case 'end': util.print('\n'); break; case 'finish': puts(console.result(event).join('\n')); break; case 'error': puts(console.error(event)); break; } }; this.print = function (str) { util.print(str); }; vows-0.7.0/lib/vows/reporters/tap.js000066400000000000000000000047011205150302300174200ustar00rootroot00000000000000var options = { tail: "\n" }; var console = require("../console"); var stylize = console.stylize; var puts = console.puts(options); // // TAP Reporter // this.name = "tap"; this.setSTream = function setStream(s) { options.stream = s; }; var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; var TapInterface = (function() { function TapInterface() { this.genOutput_ = __bind(this.genOutput_, this); this.testCount = __bind(this.testCount, this); this.bailOut = __bind(this.bailOut, this); this.skip = __bind(this.skip, this); this.notOk = __bind(this.notOk, this); this.ok = __bind(this.ok, this); this.count_ = 0; } TapInterface.prototype.ok = function(description) { return this.genOutput_("ok", ++this.count_, "- " + description); }; TapInterface.prototype.notOk = function(description) { return this.genOutput_("not ok", ++this.count_, "- " + description); }; TapInterface.prototype.skip = function(description) { return this.genOutput_("ok", ++this.count_, "# SKIP " + description); }; TapInterface.prototype.bailOut = function(reason) { return "Bail out!" + (reason !== null ? " " + reason : ""); }; TapInterface.prototype.testCount = function() { return "1.." + this.count_; }; TapInterface.prototype.genOutput_ = function(status, testNumber, description) { return "" + status + " " + testNumber + " " + description; }; return TapInterface; })(); var tap = new TapInterface(); this.report = function report(data) { var type = data[0]; var event = data[1]; switch (type) { case "subject": puts("# " + stylize(event, "bold")); break; case "context": puts("# " + event); break; case "vow": switch (event.status) { case "honored": puts(tap.ok(event.title)); break; case "pending": puts(tap.skip(event.title)); break; case "broken": puts(tap.notOk(event.title + "\n# " + event.exception)); break; case "errored": puts(tap.notOk(event.title)); puts(tap.bailOut(event.exception)); break; } break; case "end": puts("\n"); break; case "finish": puts(tap.testCount()); break; case "error": puts("#> Errored"); puts("# " + JSON.stringify(data)); break; } }; this.print = function print(str) { require("util").print(str); }; vows-0.7.0/lib/vows/reporters/watch.js000066400000000000000000000016501205150302300177420ustar00rootroot00000000000000var options = {}; var console = require('../../vows/console'); var spec = require('../../vows/reporters/spec'); var stylize = console.stylize, puts = console.puts(options); // // Console reporter // var lastContext; this.name = 'watch'; this.setStream = function (s) { options.stream = s; }; this.reset = function () { lastContext = null; }; this.report = function (data) { var event = data[1]; switch (data[0]) { case 'vow': if (['honored', 'pending'].indexOf(event.status) === -1) { if (lastContext !== event.context) { lastContext = event.context; puts(console.contextText(event.context)); } puts(console.vowText(event)); puts(''); } break; case 'error': puts(console.error(event)); break; } }; this.print = function (str) {}; vows-0.7.0/lib/vows/reporters/xunit.js000066400000000000000000000054661205150302300200140ustar00rootroot00000000000000// xunit outoput for vows, so we can run things under hudson // // The translation to xunit is simple. Most likely more tags/attributes can be // added, see: http://ant.1045680.n5.nabble.com/schema-for-junit-xml-output-td1375274.html // var puts = require('util').puts; var buffer = [], curSubject = null; function xmlEnc(value) { return !value ? value : String(value).replace(/&/g, "&") .replace(/>/g, ">") .replace(/'; } function cdata(data) { return ''; } this.name = 'xunit'; this.report = function (data) { var event = data[1]; switch (data[0]) { case 'subject': curSubject = event; break; case 'context': break; case 'vow': switch (event.status) { case 'honored': buffer.push(tag('testcase', {classname: curSubject, name: event.context + ': ' + event.title}, true)); break; case 'broken': var err = tag('error', {type: 'vows.event.broken', message: 'Broken test'}, false, cdata(event.exception)); buffer.push(tag('testcase', {classname: curSubject, name: event.context + ': ' + event.title}, false, err)); break; case 'errored': var skip = tag('skipped', {type: 'vows.event.errored', message: 'Errored test'}, false, cdata(event.exception)); buffer.push(tag('testcase', {classname: curSubject, name: event.context + ': ' + event.title}, false, skip)); break; case 'pending': // nop break; } break; case 'end': buffer.push(end('testcase')); break; case 'finish': buffer.unshift(tag('testsuite', {name: 'Vows test', tests: event.total, timestamp: (new Date()).toUTCString(), errors: event.errored, failures: event.broken, skip: event.pending, time: event.time})); buffer.push(end('testsuite')); puts(buffer.join('\n')); break; case 'error': break; } }; this.print = function (str) { }; vows-0.7.0/lib/vows/suite.js000066400000000000000000000323201205150302300157360ustar00rootroot00000000000000var events = require('events'), path = require('path'); var vows = require('../vows'); var Context = require('../vows/context').Context; this.Suite = function (subject) { this.subject = subject; this.matcher = /.*/; this.reporter = require('./reporters/dot-matrix'); this.batches = []; this.options = { error: true }; this.reset(); }; this.Suite.prototype = new(function () { this.reset = function () { this.results = { honored: 0, broken: 0, errored: 0, pending: 0, total: 0, time: null }; this.batches.forEach(function (b) { b.lastContext = null; b.remaining = b._remaining; b.honored = b.broken = b.errored = b.total = b.pending = 0; b.vows.forEach(function (vow) { vow.status = null }); b.teardowns = []; }); }; this.addBatch = function (tests) { this.batches.push({ tests: tests, suite: this, vows: [], remaining: 0, _remaining: 0, honored: 0, broken: 0, errored: 0, pending: 0, total: 0, teardowns: [] }); return this; }; this.addVows = this.addBatch; this.parseBatch = function (batch, matcher) { var tests = batch.tests; if ('topic' in tests) { throw new(Error)("missing top-level context."); } // Count the number of vows/promises expected to fire, // so we know when the tests are over. // We match the keys against `matcher`, to decide // whether or not they should be included in the test. // Any key, including assertion function keys can be matched. // If a child matches, then the n parent topics must not be skipped. (function count(tests, _match) { var match = false; var keys = Object.keys(tests).filter(function (k) { return k !== 'topic' && k !== 'teardown'; }); for (var i = 0, key; i < keys.length; i++) { key = keys[i]; // If the parent node, or this one matches. match = _match || matcher.test(key); if (typeof(tests[key]) === 'object') { match = count(tests[key], match); } else { if (typeof(tests[key]) === 'string') { tests[key] = new(String)(tests[key]); } if (! match) { tests[key]._skip = true; } } } // If any of the children matched, // don't skip this node. for (var i = 0; i < keys.length; i++) { if (! tests[keys[i]]._skip) { match = true } } if (match) { batch.remaining ++ } else { tests._skip = true } return match; })(tests, false); batch._remaining = batch.remaining; }; this.runBatch = function (batch) { var topic, tests = batch.tests, promise = batch.promise = new(events.EventEmitter); var that = this; batch.status = 'begin'; // The test runner, it calls itself recursively, passing the // previous context to the inner contexts. This is so the `topic` // functions have access to all the previous context topics in their // arguments list. // It is defined and invoked at the same time. // If it encounters a `topic` function, it waits for the returned // promise to emit (the topic), at which point it runs the functions under it, // passing the topic as an argument. (function run(ctx, lastTopic) { var old = false; topic = ctx.tests.topic; if (typeof(topic) === 'function') { if (ctx.isEvent || ctx.name === 'on') { throw new Error('Event context cannot contain a topic'); } // Run the topic, passing the previous context topics // If topic `throw`s an exception, pass it down as a value try { topic = topic.apply(ctx.env, ctx.topics); } catch (ex) { if(/ReferenceError/.test(ex)) throw ex; topic = ex; } if (typeof(topic) === 'undefined') { ctx._callback = true } } // If this context has a topic, store it in `lastTopic`, // if not, use the last topic, passed down by a parent // context. if (typeof(topic) !== 'undefined' || ctx._callback) { lastTopic = topic; } else { old = true; topic = lastTopic; } // If the topic doesn't return an event emitter (such as a promise), // we create it ourselves, and emit the value on the next tick. if (! (topic && topic.constructor === events.EventEmitter)) { // If the context is a traditional vow, then a topic can ONLY // be an EventEmitter. However if the context is a sub-event // then the topic may be an instanceof EventEmitter if (!ctx.isEvent || (ctx.isEvent && !(topic instanceof events.EventEmitter))) { ctx.emitter = new(events.EventEmitter); if (! ctx._callback) { process.nextTick(function (val) { return function () { ctx.emitter.emit("success", val) }; }(topic)); } // if I have a callback, push the new topic back up to // lastTopic if (ctx._callback) { lastTopic = topic = ctx.emitter; } else { topic = ctx.emitter; } } } topic.on(ctx.event, function (val) { // Once the topic fires, add the return value // to the beginning of the topics list, so it // becomes the first argument for the next topic. // If we're using the parent topic, no need to // prepend it to the topics list, or we'll get // duplicates. if (!old || ctx.isEvent) { Array.prototype.unshift.apply(ctx.topics, arguments) }; }); if (topic.setMaxListeners) { topic.setMaxListeners(Infinity) } // Now run the tests, or sub-contexts Object.keys(ctx.tests).filter(function (k) { return ctx.tests[k] && k !== 'topic' && k !== 'teardown' && !ctx.tests[k]._skip; }).forEach(function (item) { // Create a new evaluation context, // inheriting from the parent one. var env = Object.create(ctx.env); env.suite = that; // Holds the current test or context var vow = Object.create({ callback: ctx.tests[item], context: ctx.title, description: item, binding: ctx.env, status: null, batch: batch }); // If we encounter a function, add it to the callbacks // of the `topic` function, so it'll get called once the // topic fires. // If we encounter an object literal, we recurse, sending it // our current context. if ((typeof(vow.callback) === 'function') || (vow.callback instanceof String)) { topic.addVow(vow); } else if (typeof(vow.callback) === 'object') { // If there's a setup stage, we have to wait for it to fire, // before calling the inner context. // If the event has already fired, the context is 'on' or // there is no setup stage, just run the inner context // synchronously. if (topic && ctx.name !== 'on' && (!topic._vowsEmitedEvents || !topic._vowsEmitedEvents.hasOwnProperty(ctx.event))) { topic.on(ctx.event, function (ctx) { return function (val) { return run(new(Context)(vow, ctx, env), lastTopic); }; }(ctx)); } else { run(new(Context)(vow, ctx, env), lastTopic); } } }); // Teardown if (ctx.tests.teardown) { batch.teardowns.push(ctx); } if (! ctx.tests._skip) { batch.remaining --; } // Check if we're done running the tests exports.tryEnd(batch); // This is our initial, empty context })(new(Context)({ callback: tests, context: null, description: null }, {})); return promise; }; this.report = function () { return this.reporter.report.apply(this.reporter, arguments); }; this.run = function (options, callback) { var that = this, start; options = options || {}; Object.keys(options).forEach(function (k) { that.options[k] = options[k]; }); this.matcher = this.options.matcher || this.matcher; this.reporter = this.options.reporter || this.reporter; this.batches.forEach(function (batch) { that.parseBatch(batch, that.matcher); }); this.reset(); start = new(Date); if (this.batches.filter(function (b) { return b.remaining > 0 }).length) { this.report(['subject', this.subject]); } return (function run(batches) { var batch = batches.shift(); if (batch) { // If the batch has no vows to run, // go to the next one. if (batch.remaining === 0) { run(batches); } else { that.runBatch(batch).on('end', function () { run(batches); }); } } else { that.results.time = (new(Date) - start) / 1000; that.report(['finish', that.results]); if (callback) { callback(that.results) } if (that.results.honored + that.results.pending === that.results.total) { return 0; } else { return 1; } } })(this.batches.slice(0)); }; this.runParallel = function () {}; this.export = function (module, options) { var that = this; Object.keys(options || {}).forEach(function (k) { that.options[k] = options[k]; }); if (require.main === module) { return this.run(); } else { return module.exports[this.subject] = this; } }; this.exportTo = function (module, options) { // Alias, for JSLint return this.export(module, options); }; }); // // Checks if all the tests in the batch have been run, // and triggers the next batch (if any), by emitting the 'end' event. // this.tryEnd = function (batch) { var result, style, time; if (batch.honored + batch.broken + batch.errored + batch.pending === batch.total && batch.remaining === 0) { Object.keys(batch).forEach(function (k) { (k in batch.suite.results) && (batch.suite.results[k] += batch[k]); }); if (batch.teardowns) { for (var i = batch.teardowns.length - 1, ctx; i >= 0; i--) { runTeardown(batch.teardowns[i]); } maybeFinish(); } function runTeardown(teardown) { var env = Object.create(teardown.env); Object.defineProperty(env, "callback", { get: function () { teardown.awaitingCallback = true; return function () { teardown.awaitingCallback = false; maybeFinish(); }; } }); teardown.tests.teardown.apply(env, teardown.topics); } function maybeFinish() { var pending = batch.teardowns.filter(function (teardown) { return teardown.awaitingCallback; }); if (pending.length === 0) { finish(); } } function finish() { batch.status = 'end'; batch.suite.report(['end']); batch.promise.emit('end', batch.honored, batch.broken, batch.errored, batch.pending); } } }; vows-0.7.0/package.json000066400000000000000000000011711205150302300147710ustar00rootroot00000000000000{ "name" : "vows", "description" : "Asynchronous BDD & continuous integration for node.js", "url" : "http://vowsjs.org", "keywords" : ["testing", "spec", "test", "BDD"], "author" : "Alexis Sellier ", "contributors" : [{ "name": "Charlie Robbins", "email": "charlie.robbins@gmail.com" }], "dependencies" : {"eyes": ">=0.1.6", "diff": "~1.0.3"}, "main" : "./lib/vows", "bin" : {"vows": "./bin/vows"}, "directories" : {"test": "./test", "bin": "./bin"}, "version" : "0.7.0", "scripts" : {"test": "node ./bin/vows --spec"} } vows-0.7.0/test/000077500000000000000000000000001205150302300134625ustar00rootroot00000000000000vows-0.7.0/test/VowsCamelCaseTest.js000066400000000000000000000004651205150302300173610ustar00rootroot00000000000000var vows = require('../lib/vows'), assert = require('assert'); vows.describe("Vows test file with camel case").addBatch({ "The test file": { topic: function () { return { flag: true }; }, "is run": function (topic) { assert.isTrue(topic.flag); } } }).export(module); vows-0.7.0/test/assert-test.js000066400000000000000000000106511205150302300163010ustar00rootroot00000000000000var vows = require('../lib/vows'); var assert = require('assert'); vows.describe('vows/assert').addBatch({ "The Assertion module": { "`equal`": function () { assert.equal("hello world", "hello world"); assert.equal(1, true); }, "`epsilon`": function() { assert.epsilon(1e-5, 0.1+0.2, 0.3); }, "`match`": function () { assert.match("hello world", /^[a-z]+ [a-z]+$/); }, "`lengthOf`": function () { assert.lengthOf("hello world", 11); assert.lengthOf([1, 2, 3], 3); assert.lengthOf({goo: true, gies: false}, 2); }, "`isDefined`": function () { assert.isDefined(null); assertError(assert.isDefined, undefined); }, "`include`": function () { assert.include("hello world", "world"); assert.include([0, 42, 0], 42); assert.include({goo:true}, 'goo'); }, "`deepInclude`": function () { assert.deepInclude([{a:'b'},{c:'d'}], {a:'b'}); assert.deepInclude("hello world", "world"); assert.deepInclude({goo:true}, 'goo'); }, "`typeOf`": function () { assert.typeOf('goo', 'string'); assert.typeOf(42, 'number'); assert.typeOf([], 'array'); assert.typeOf({}, 'object'); assert.typeOf(false, 'boolean'); }, "`instanceOf`": function () { assert.instanceOf([], Array); assert.instanceOf(function () {}, Function); }, "`isArray`": function () { assert.isArray([]); assertError(assert.isArray, {}); }, "`isString`": function () { assert.isString(""); }, "`isObject`": function () { assert.isObject({}); assertError(assert.isObject, []); }, "`isNumber`": function () { assert.isNumber(0); }, "`isBoolean`": function (){ assert.isBoolean(true); assert.isBoolean(false); assertError(assert.isBoolean, 0); }, "`isNan`": function () { assert.isNaN(0/0); }, "`isTrue`": function () { assert.isTrue(true); assertError(assert.isTrue, 1); }, "`isFalse`": function () { assert.isFalse(false); assertError(assert.isFalse, 0); }, "`isZero`": function () { assert.isZero(0); assertError(assert.isZero, null); }, "`isNotZero`": function () { assert.isNotZero(1); }, "`isUndefined`": function () { assert.isUndefined(undefined); assertError(assert.isUndefined, null); }, "`isDefined`": function () { assert.isDefined(null); assertError(assert.isDefined, undefined); }, "`isNull`": function () { assert.isNull(null); assertError(assert.isNull, 0); assertError(assert.isNull, undefined); }, "`isNotNull`": function () { assert.isNotNull(0); }, "`greater` and `lesser`": function () { assert.greater(5, 4); assert.lesser(4, 5); }, "`inDelta`": function () { assert.inDelta(42, 40, 5); assert.inDelta(42, 40, 2); assert.inDelta(42, 42, 0); assert.inDelta(3.1, 3.0, 0.2); assertError(assert.inDelta, [42, 40, 1]); }, "`isEmpty`": function () { assert.isEmpty({}); assert.isEmpty([]); assert.isEmpty(""); }, "`isNotEmpty`": function () { assert.isNotEmpty({goo:true}); assert.isNotEmpty([1]); assert.isNotEmpty(" "); assertError(assert.isNotEmpty, {}); assertError(assert.isNotEmpty, []); assertError(assert.isNotEmpty, ""); } } }).export(module); function assertError(assertion, args, fail) { if (!Array.isArray(args)) { args = [args]; } try { assertion.apply(null, args); fail = true; } catch (e) {/* Success */} fail && assert.fail(args.join(' '), assert.AssertionError, "expected an AssertionError for {actual}", "assertError", assertError); } vows-0.7.0/test/fixtures/000077500000000000000000000000001205150302300153335ustar00rootroot00000000000000vows-0.7.0/test/fixtures/isolate/000077500000000000000000000000001205150302300167735ustar00rootroot00000000000000vows-0.7.0/test/fixtures/isolate/failing.js000066400000000000000000000006461205150302300207500ustar00rootroot00000000000000var vows = require('../../../lib/vows'), assert = require('assert'); var obvious; vows.describe('failing').addBatch({ 'Obvious test': obvious = { topic: function () { this.callback(null, false); }, 'should work': function (result) { assert.ok(result); } // but it won't }, 'Obvious test #2': obvious, 'Obvious test #3': obvious, 'Obvious test #4': obvious }).export(module); vows-0.7.0/test/fixtures/isolate/log.js000066400000000000000000000006551205150302300201200ustar00rootroot00000000000000var vows = require('../../../lib/vows'), assert = require('assert'); var obvious; vows.describe('stderr').addBatch({ 'Obvious test': obvious = { topic: function () { this.callback(null, true); }, 'should work': function (result) { console.log('oh no!'); assert.ok(result); } }, 'Obvious test #2': obvious, 'Obvious test #3': obvious, 'Obvious test #4': obvious }).export(module); vows-0.7.0/test/fixtures/isolate/passing.js000066400000000000000000000006211205150302300207740ustar00rootroot00000000000000var vows = require('../../../lib/vows'), assert = require('assert'); var obvious; vows.describe('passing').addBatch({ 'Obvious test': obvious = { topic: function () { this.callback(null, true); }, 'should work': function (result) { assert.ok(result); } }, 'Obvious test #2': obvious, 'Obvious test #3': obvious, 'Obvious test #4': obvious }).export(module); vows-0.7.0/test/fixtures/isolate/stderr.js000066400000000000000000000006571205150302300206440ustar00rootroot00000000000000var vows = require('../../../lib/vows'), assert = require('assert'); var obvious; vows.describe('stderr').addBatch({ 'Obvious test': obvious = { topic: function () { this.callback(null, true); }, 'should work': function (result) { console.error('oh no!'); assert.ok(result); } }, 'Obvious test #2': obvious, 'Obvious test #3': obvious, 'Obvious test #4': obvious }).export(module); vows-0.7.0/test/fixtures/supress-stdout/000077500000000000000000000000001205150302300203575ustar00rootroot00000000000000vows-0.7.0/test/fixtures/supress-stdout/output.js000066400000000000000000000005231205150302300222550ustar00rootroot00000000000000var vows = require('../../../lib/vows'), assert = require('assert'); vows.describe('output').addBatch({ 'outputting': { topic: function () { console.log('goo'); this.callback(null, true); }, 'should work': function (result) { console.log('goo'); assert.ok(result); } }, }).export(module); vows-0.7.0/test/isolate-test.js000066400000000000000000000100151205150302300164320ustar00rootroot00000000000000var vows = require('../lib/vows'), assert = require('assert'), path = require('path'), os = require('os'), exec = require('child_process').exec; function generateTopic(args, file) { return function () { var cmd = '"' + process.execPath + '"' + ' ./bin/vows' + ' -i ' + (args || '') + ' ./test/fixtures/isolate/' + file, options = {cwd: path.resolve(__dirname + '/../')}, callback = this.callback; exec(cmd, options, function (err, stdout, stderr) { callback(null, { err: err, stdout: stdout, stderr: stderr }); }); } } function assertExecOk(r) { assert.isNull(r.err); } function assertExecNotOk(r) { assert.isNotNull(r.err); } function parseResults(stdout) { var results = stdout.split('\n'); // win32 may console.log data which need to filter out invalid JSON at start of results //TODO: do we need to filter out any console.log data as we are expecting only valid json // any console.log used for dedugging may break parseResults if(process.platform === 'win32') { while(results.length > 0 && results[0].charAt(0) !== '{') { results.shift(); } } return results.map(function (s) { if (!s) return; return JSON.parse(s); }).filter(function (s) {return s}); } function assertResultTypePresent(results, type) { assert.ok(results.some(function (result) { return result[0] == type; })); } function assertResultsFinish(results, expected) { var finish = results[results.length - 1]; assert.equal(finish[0], 'finish'); finish = finish[1]; Object.keys(expected).forEach(function (key) { assert.equal(finish[key], expected[key]); }); } vows.describe('vows/isolate').addBatch({ 'Running vows with -i flag for test/fixtures/isolate/': { 'passing.js': { 'with default reporter': { topic: generateTopic(null, 'passing.js'), 'should be ok': assertExecOk }, 'with json reporter': { topic: generateTopic('--json', 'passing.js'), 'should be ok': assertExecOk, 'should have correct output': function (r) { var results = parseResults(r.stdout) assertResultTypePresent(results, 'subject'); assertResultTypePresent(results, 'end'); assertResultsFinish(results, { total: 4, honored: 4 }); } } }, 'failing.js': { 'with json reporter': { topic: generateTopic('--json', 'failing.js'), 'should be not ok': assertExecNotOk, 'should have correct output though': function (r) { var results = parseResults(r.stdout); assertResultsFinish(results, { total: 4, broken: 4 }); } } }, 'stderr.js': { 'with json reporter': { topic: generateTopic('--json', 'stderr.js'), 'should be ok': assertExecOk, 'should have stderr': function (r) { assert.equal(r.stderr, ['oh no!', 'oh no!', 'oh no!', 'oh no!', ''].join('\n')); }, 'should have correct output': function (r) { var results= parseResults(r.stdout); assertResultsFinish(results, { total: 4, honored: 4 }); } } }, 'log.js': { 'with json reporter': { topic: generateTopic('--json', 'log.js'), 'should be ok': assertExecOk, 'should have correct output': function (r) { var results= parseResults(r.stdout); assertResultsFinish(results, { total: 4, honored: 4 }); } } }, 'all tests (*)': { 'with json reporter': { topic: generateTopic('--json', '*'), 'should be not ok': assertExecNotOk, 'should have correct output': function (r) { var results= parseResults(r.stdout); assertResultsFinish(results, { total: 16, broken: 4, honored: 12 }); } } } } }).export(module); vows-0.7.0/test/supress-stdout-test.js000066400000000000000000000030161205150302300200210ustar00rootroot00000000000000var assert = require('assert'), path = require('path'), vows = require('../lib/vows'), exec = require('child_process').exec; function generateTopic(supress) { return function () { var cmd = '"' + process.execPath + '"' + ' ./bin/vows ' + (supress ? '--supress-stdout ' : '') + './test/fixtures/supress-stdout/output.js', options = {cwd: path.resolve(__dirname + '/../')}, callback = this.callback; exec(cmd, options, function (err, stdout) { callback(null, {err: err, stdout: stdout}); }); }; } vows.describe('vows/supress-stdout').addBatch({ 'Running vows for test/fixtures/supress-stdout/output.js': { 'with --supress-stdout flag': { topic: generateTopic(true), 'should be ok': function (result) { assert.isNull(result.err); }, 'should not contain output from stdout': function (result) { assert.equal(result.stdout.toString().indexOf('goo'), -1); // console.log output? // nope, just Chuck Testa! } }, 'without --supress-stdout flag': { topic: generateTopic(), 'should be ok': function (result) { assert.isNull(result.err); }, 'should contain output from stdout': function (result) { assert.notEqual(result.stdout.toString().indexOf('goo'), -1); } } } }).export(module); vows-0.7.0/test/vows-error-test.js000066400000000000000000000023321205150302300171220ustar00rootroot00000000000000var path = require('path'), events = require('events'), assert = require('assert'), fs = require('fs'), vows = require('../lib/vows'); function doSomethingAsync(callback) { var err = null; var testValue = 'a'; process.nextTick(function() { callback(err, testValue); }); } function doSomethingAsyncWithError(callback) { var err = true; var testValue = 'a'; process.nextTick(function() { callback(err, testValue); }); } vows.describe('vows/error').addBatch({ 'Generate success response to async function': { topic: function() { doSomethingAsync(this.callback) }, 'Validate success': function(err, testValue) { assert.ok(!err); }, 'Validate testValue': function(err, testValue) { assert.equal(testValue, 'a'); } }, 'Generate error response to async function': { topic: function() { doSomethingAsyncWithError(this.callback) }, 'Validate error': function(err, testValue) { assert.ok(err); }, 'Validate testValue': function(err, testValue) { // This assertion fails. It shouldn't. assert.equal(testValue, 'a'); } } }).export(module)vows-0.7.0/test/vows-test.js000066400000000000000000000402711205150302300157770ustar00rootroot00000000000000var path = require('path'), events = require('events'), assert = require('assert'), fs = require('fs'), vows = require('../lib/vows'); var api = vows.prepare({ get: function (id, callback) { process.nextTick(function () { callback(null, id) }); }, version: function () { return '1.0' } }, ['get']); var promiser = function (val) { return function () { var promise = new(events.EventEmitter); process.nextTick(function () { promise.emit('success', val) }); return promise; } }; vows.describe("Vows").addBatch({ "A context": { topic: promiser("hello world"), "with a nested context": { topic: function (parent) { this.state = 42; return promiser(parent)(); }, "has access to the environment": function () { assert.equal(this.state, 42); }, "and a sub nested context": { topic: function () { return this.state; }, "has access to the parent environment": function (r) { assert.equal(r, 42); assert.equal(this.state, 42); }, "has access to the parent context object": function (r) { assert.ok(Array.isArray(this.context.topics)); assert.include(this.context.topics, "hello world"); } } } }, "A nested context": { topic: promiser(1), ".": { topic: function (a) { return promiser(2)() }, ".": { topic: function (b, a) { return promiser(3)() }, ".": { topic: function (c, b, a) { return promiser([4, c, b, a])() }, "should have access to the parent topics": function (topics) { assert.equal(topics.join(), [4, 3, 2, 1].join()); } }, "from": { topic: function (c, b, a) { return promiser([4, c, b, a])() }, "the parent topics": function(topics) { assert.equal(topics.join(), [4, 3, 2, 1].join()); } } } } }, "Nested contexts with callback-style async": { topic: function () { fs.stat(__dirname + '/vows-test.js', this.callback); }, 'after a successful `fs.stat`': { topic: function (stat) { fs.open(__dirname + '/vows-test.js', "r", stat.mode, this.callback); }, 'after a successful `fs.open`': { topic: function (fd, stat) { fs.read(fd, stat.size, 0, "utf8", this.callback); }, 'after a successful `fs.read`': function (data) { assert.match (data, /after a successful `fs.read`/); } } } }, "A nested context with no topics": { topic: 45, ".": { ".": { "should pass the value down": function (topic) { assert.equal(topic, 45); } } } }, "A Nested context with topic gaps": { topic: 45, ".": { ".": { topic: 101, ".": { ".": { topic: function (prev, prev2) { return this.context.topics.slice(0); }, "should pass the topics down": function (topics) { assert.lengthOf(topics, 2); assert.equal(topics[0], 101); assert.equal(topics[1], 45); } } } } } }, "A non-promise return value": { topic: function () { return 1 }, "should be converted to a promise": function (val) { assert.equal(val, 1); } }, "A 'prepared' interface": { "with a wrapped function": { topic: function () { return api.get(42) }, "should work as expected": function (val) { assert.equal(val, 42); } }, "with a non-wrapped function": { topic: function () { return api.version() }, "should work as expected": function (val) { assert.equal(val, '1.0'); } } }, "A non-function topic": { topic: 45, "should work as expected": function (topic) { assert.equal(topic, 45); } }, "A non-function topic with a falsy value": { topic: 0, "should work as expected": function (topic) { assert.equal(topic, 0); } }, "A topic returning a function": { topic: function () { return function () { return 42 }; }, "should work as expected": function (topic) { assert.isFunction(topic); assert.equal(topic(), 42); }, "in a sub-context": { "should work as expected": function (topic) { assert.isFunction(topic); assert.equal(topic(), 42); }, } }, "A topic with a function that errors": { topic: function() { throw("Something wrong here"); }, "should error out": function(topic) { assert.equal(topic, "Something wrong here"); } }, "A topic emitting an error": { topic: function () { var promise = new(events.EventEmitter); process.nextTick(function () { promise.emit("error", 404); }); return promise; }, "shouldn't raise an exception if the test expects it": function (e, res) { assert.equal(e, 404); assert.ok(! res); } }, "A topic not emitting an error": { topic: function () { var promise = new(events.EventEmitter); process.nextTick(function () { promise.emit("success", true); }); return promise; }, "should pass `null` as first argument, if the test is expecting an error": function (e, res) { assert.strictEqual(e, null); assert.equal(res, true); }, "should pass the result as first argument if the test isn't expecting an error": function (res) { assert.equal(res, true); } }, "A topic with callback-style async": { "when successful": { topic: function () { var that = this; process.nextTick(function () { that.callback(null, "OK"); }); }, "should work like an event-emitter": function (res) { assert.equal(res, "OK"); }, "should assign `null` to the error argument": function (e, res) { assert.strictEqual(e, null); assert.equal(res, "OK"); } }, "when unsuccessful": { topic: function () { function async(callback) { process.nextTick(function () { callback("ERROR"); }); } async(this.callback); }, "should have a non-null error value": function (e, res) { assert.equal(e, "ERROR"); }, "should work like an event-emitter": function (e, res) { assert.equal(res, undefined); } }, "using this.callback synchronously": { topic: function () { this.callback(null, 'hello'); }, "should work the same as returning a value": function (res) { assert.equal(res, 'hello'); } }, "using this.callback with a user context": { topic: function () { this.callback.call({ boo: true }, null, 'hello'); }, "should give access to the user context": function (res) { assert.isTrue(this.boo); } }, "passing this.callback to a function": { topic: function () { this.boo = true; var async = function (callback) { callback(null); }; async(this.callback); }, "should give access to the topic context": function () { assert.isTrue(this.boo); } }, "with multiple arguments": { topic: function () { this.callback(null, 1, 2, 3); }, "should pass them to the vow": function (e, a, b, c) { assert.strictEqual(e, null); assert.strictEqual(a, 1); assert.strictEqual(b, 2); assert.strictEqual(c, 3); }, "and a sub-topic": { topic: function (a, b, c) { return [a, b, c]; }, "should receive them too": function (val) { assert.deepEqual(val, [1, 2, 3]); } } } } }).addBatch({ "A Sibling context": { "'A', with `this.foo = true`": { topic: function () { this.foo = true; return this; }, "should have `this.foo` set to true": function (res) { assert.equal(res.foo, true); } }, "'B', with nothing set": { topic: function () { return this; }, "shouldn't have access to `this.foo`": function (e, res) { assert.isUndefined(res.foo); } } } }).addBatch({ "A 2nd batch": { topic: function () { var p = new(events.EventEmitter); setTimeout(function () { p.emit("success"); }, 100); return p; }, "should run after the first": function () {} } }).addBatch({ "A 3rd batch": { topic: true, "should run last": function () {} } }).addBatch({}).export(module); vows.describe("Vows with a single batch", { "This is a batch that's added as the optional parameter to describe()": { topic: true, "And a vow": function () {} } }).export(module); vows.describe("Vows with multiple batches added as optional parameters", { "First batch": { topic: true, "should be run first": function () {} } }, { "Second batch": { topic: true, "should be run second": function () {} } }).export(module); vows.describe("Vows with teardowns").addBatch({ "A context": { topic: function () { return { flag: true }; }, "And a vow": function (topic) { assert.isTrue(topic.flag); }, "And another vow": function (topic) { assert.isTrue(topic.flag); }, "And a final vow": function (topic) { assert.isTrue(topic.flag); }, 'subcontext': { 'nested': function (_, topic) { assert.isTrue(topic.flag); } }, teardown: function (topic) { topic.flag = false; }, "with a subcontext" : { topic: function (topic) { var that = this; process.nextTick(function () { that.callback(null, topic); }); }, "Waits for the subcontext before teardown" : function(topic) { assert.isTrue(topic.flag); } } } }).export(module); vows.describe("Vows with sub events").addBatch({ "A context with sub-events": { topic: function () { var topic = new(events.EventEmitter); topic.emit('before', 'before'); process.nextTick(function () { topic.emit('request', 'request_data'); }); process.nextTick(function () { topic.emit('end', 'end_data'); }); process.nextTick(function () { topic.emit('nested', 'empty_nest'); }); process.nextTick(function () { topic.emit('success', 'legacey_data'); }); return topic; }, on: { "before": { "will catch events emited before the topic returns" : function (ret) { assert.strictEqual(ret, 'before'); } }, "request": { "will catch request": function (ret) { assert.strictEqual(ret, 'request_data'); }, on: { on: { "end": { "will require that 'end' is emitted after 'request'": function (ret) { assert.strictEqual(ret, 'end_data'); // TODO need a test that fails to prove this works } } } } }, on: { on: { "nested": { "will catch nested, even if it is in empty nested 'on'": function (ret) { assert.strictEqual(ret, 'empty_nest') } } } } }, "will catch the legacy success event": function (err, ret) { assert.strictEqual(ret, 'legacey_data'); } }, "Sub-events emitted by children of EventEmitter": { topic: function() { var MyEmitter = function () { events.EventEmitter.call(this); }; require('util').inherits(MyEmitter, events.EventEmitter); var topic = new(MyEmitter); process.nextTick(function () { topic.emit('success', 'Legacy Does not Catch'); }); return topic; }, "will return the emitter for traditional vows" : function (err, ret) { assert.ok(ret instanceof events.EventEmitter); }, // events is an alias for on events: { "success" : { "will catch the event" : function (ret) { assert.strictEqual(ret, 'Legacy Does not Catch'); }, "will change events to on in the title" : function() { assert.strictEqual(this.context.title, 'Sub-events emitted by children of EventEmitter on success'); } } } } }).export(module); var tornDown = false vows.describe("Vows with asynchonous teardowns").addBatch({ "Context with long-running teardown": { "is run first": function () {}, teardown: function () { var callback = this.callback; setTimeout(function () { tornDown = true; callback(); }, 100); } } }).addBatch({ "The next batch": { "is not run until the teardown is complete": function () { assert.ok(tornDown); } } }).export(module); vows.describe('Async topic is passed to vows with topic-less subcontext').addBatch({ 'Async 42': { topic: function () { var callback = this.callback; process.nextTick(function () { callback(null, 42); }); }, 'equals 42': function (topic) { assert.equal(topic, 42); }, 'has the property that': { 'it is equal to 42': function (topic) { // <-- This vow fails, topic is undefined!? assert.equal(topic, 42); } }, 'plus 1': { topic: function (parentTopic) { return parentTopic + 1; }, 'equals 43': function (topic) { assert.equal(topic, 43); } } } })['export'](module); vows-0.7.0/test/vows_underscore_test.js000066400000000000000000000004651205150302300203130ustar00rootroot00000000000000var vows = require('../lib/vows'), assert = require('assert'); vows.describe("Vows test file with underscore").addBatch({ "The test file": { topic: function () { return { flag: true }; }, "is run": function (topic) { assert.isTrue(topic.flag); } } }).export(module);