diff --git a/lib/jasmine-node/array-shuffler.js b/lib/jasmine-node/array-shuffler.js new file mode 100644 index 0000000..065065e --- /dev/null +++ b/lib/jasmine-node/array-shuffler.js @@ -0,0 +1,39 @@ +var previous; + +// MINSTD Lehmer random number generator +var MODULUS = Math.pow( 2, 31 ) - 1, MULTIPLIER = 48271, INCREMENT = 0; +var randInt = function() { + return previous = ( previous * MULTIPLIER + INCREMENT ) % MODULUS; +}; + +var rand = function( range ) { + if( range == 0 ) { + return 0; + } + + // Doesn't provide a very uniform distribution - but good enough + // for shuffling tests + return randInt() % range; +}; + +exports.seedRandom = function( seed ) { + var moduloSeed; + if( typeof seed != 'undefined' ) { + moduloSeed = seed % MODULUS; + } else { + moduloSeed = Math.floor( Math.random() * ( Math.pow( 2, 31 ) - 2 ) ); + } + console.log( 'Shuffling tests with seed ' + moduloSeed ); + previous = moduloSeed; +}; + +exports.shuffle = function( array ) { + // Fisher-Yates shuffle, as implemented by Durstenfeld + for( var i = array.length - 1; i > 0; i-- ) { + var swapIndex = rand( i - 1 ); + var temp = array[ swapIndex ]; + array[ swapIndex ] = array[ i ]; + array[ i ] = temp; + } +}; + diff --git a/lib/jasmine-node/cli.js b/lib/jasmine-node/cli.js index 4a1e525..9a1584d 100755 --- a/lib/jasmine-node/cli.js +++ b/lib/jasmine-node/cli.js @@ -33,6 +33,8 @@ var useRequireJs = false; var extensions = "js"; var match = '.'; var matchall = false; +var randomize = false; +var randomSeed; var autotest = false; var useHelpers = true; var forceExit = false; @@ -82,6 +84,13 @@ while(args.length) { case '--matchall': matchall = true; break; + case '--randomize': + randomize = true; + break; + case '--seed': + randomize = true; + randomSeed = parseInt( args.shift(), 10 ); + break; case '--junitreport': junitreport.report = true; break; @@ -240,6 +249,8 @@ var options = { teamcity: teamcity, useRequireJs: useRequireJs, regExpSpec: regExpSpec, + randomize: randomize, + randomSeed: randomSeed, junitreport: junitreport, includeStackTrace: includeStackTrace, growl: growl @@ -259,6 +270,8 @@ function help(){ , ' --noColor - do not use color coding for output' , ' -m, --match REGEXP - load only specs containing "REGEXPspec"' , ' --matchall - relax requirement of "spec" in spec file names' + , ' --randomize - shuffle the list of spec files before running' + , ' --seed SEED - shuffle the list of spec files using the supplied seed' , ' --verbose - print extra information per each test run' , ' --coffee - load coffee-script which allows execution .coffee files' , ' --junitreport - export tests results as junitreport xml format' diff --git a/lib/jasmine-node/index.js b/lib/jasmine-node/index.js index 625e81c..2dc6925 100755 --- a/lib/jasmine-node/index.js +++ b/lib/jasmine-node/index.js @@ -92,6 +92,8 @@ jasmine.executeSpecsInFolder = function(options){ var useRequireJs = options['useRequireJs']; var matcher = options['regExpSpec']; var junitreport = options['junitreport']; + var randomize = options['randomize']; + var randomSeed = options['randomSeed']; var includeStackTrace = options['includeStackTrace']; var growl = options['growl']; @@ -152,6 +154,19 @@ jasmine.executeSpecsInFolder = function(options){ } else { var specsList = specs.getSpecs(); + if (randomize) { + var arrayShuffler = require('./array-shuffler'); + arrayShuffler.seedRandom(randomSeed); + arrayShuffler.shuffle(specsList); + + if (isVerbose) { + console.log('Executing tests in this order:'); + for( var i = 0; i < specsList.length; i++ ) { + console.log( specsList[i].filename() ); + } + } + } + for (var i = 0, len = specsList.length; i < len; ++i) { var filename = specsList[i]; delete require.cache[filename.path()];