Advertisement
rplantiko

Simple Function Tests

Aug 9th, 2014
771
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ---------------------------------------------------------------------
  2. // Mocking all function calls from within the function under test
  3. // ---------------------------------------------------------------------
  4. module.exports = function(test){
  5.  
  6.   var _call_history, _mock;  
  7.  
  8. // Overall Setup: Define all functions in a global namespace  
  9.   var fnames = extend({},test.defaults);
  10.   test.cases.forEach(function(testCase){
  11.       extend( fnames,Object.keys(testCase.fixture))
  12.       });
  13.   Object.keys(fnames).forEach( function(fname) {
  14.       global[fname] = function() {
  15.       return mock({ fname:fname, args:arguments });
  16.       }      
  17.     });
  18.    
  19.    if (!test.cases || test.cases.length === 0) {
  20.      console.log("No test cases");
  21.      return;
  22.      } else {
  23.      console.log("1.." + test.cases.length);
  24.      }  
  25.                
  26. // Now process each individual test case                
  27.   test.cases.forEach( function(testCase, testCaseIndex) {
  28.     var msg = "";
  29.     try {
  30.       setup(testCase.fixture);
  31.       rval = test.func();
  32.       assert_call_history(testCase.expected_history);
  33.       assert_equals(testCase.expected_rval,rval);
  34.     } catch (e) { msg = e; }
  35.     console.log(
  36.       result_line( testCase.name, testCaseIndex+1, msg)
  37.       );
  38.     if (testCase.log_history)
  39.       console.log( callHistoryToString( call_history ));
  40.     function result_line( name, index, msg) {
  41.       var result = msg ? "not ok" : "ok"
  42.       result += " " + index + " - " + name;
  43.       if (msg) result += ": " + msg;
  44.       return result;
  45.       }
  46.     });
  47.    
  48.   function setup(fixture) {
  49.     call_history = [];    
  50.     _mock = extend({},test.defaults);
  51.     extend(_mock,fixture);
  52.     }  
  53.    
  54.   function callHistoryToString( callHistory ) {
  55.     return '[\n' +
  56.       callHistory.map( function(fc) {
  57.         return (fc instanceof FunctionCall) ?
  58.                     fc.toString() :
  59.                     (new FunctionCall(fc)).toString() }
  60.         ).join('\n') +
  61.       '\n]';  
  62.     }  
  63.    
  64.   function assert_call_history(expected_history) {
  65.     var epos = 0,
  66.         $break = "break",
  67.         stoppedAsExpected = true;
  68.    
  69.     if (!expected_history) return;
  70.    
  71.     try {
  72.       call_history.forEach( function(fcall, cpos) {
  73.         if (epos < expected_history.length) {
  74.           if (expected_history.stop) {
  75.             stoppedAsExpected = false;
  76.             throw $break;
  77.           }
  78.           if (fcall.equals( expected_history[epos] )){
  79.             epos++;  // Found, OK
  80.           }
  81.         }
  82.       });
  83.     } catch (e) {
  84.       if (e != $break) throw e;
  85.       }
  86.    
  87.     var expectedHistoryLength = expected_history.reduce(
  88.       function(acc,next) {
  89.         if (!(next.stop))acc++
  90.         return acc
  91.         },0);      
  92.    
  93.     if (epos < expectedHistoryLength) {
  94.       console.log( callHistoryToString( call_history ) );
  95.       console.log( callHistoryToString( expected_history ) );
  96.       if (!stoppedAsExpected)
  97.         throw "Call sequence continued after stop mark";
  98.       else
  99.         throw "Call sequence not as expected";
  100.     }  
  101.   }
  102.  
  103.   function assert_equals( exp, act ) {
  104.     if (exp!==act) {
  105.       throw 'Expected value "' + exp + '" <> actual value "' + act + '"';
  106.       }
  107.     }
  108.  
  109.   function mock(func) {
  110.     var fval,rval;
  111.     if ((fval = _mock[func.fname])) {
  112.       if (func.args.length === 0)
  113.         rval = fval;
  114.       else if (func.args.length == 1)
  115.         rval = fval[func.args[0]];
  116.       }
  117.     call_history.push(new FunctionCall(func.fname,func.args,rval));
  118.     return rval;  
  119.     }  
  120.    
  121.   function extend(destination, source) {
  122.     for (var property in source) {
  123.       if (typeof source[property] === "object" &&
  124.           source[property] !== null && destination[property]) {
  125.         extend(destination[property], source[property]);
  126.       } else {
  127.         destination[property] = source[property];
  128.       }
  129.     }
  130.     return destination;
  131.   }
  132.      
  133. };
  134.  
  135. // --- An object type for logging function calls  
  136.   function FunctionCall( fname, args, returnValue ) {
  137.     if (typeof arguments[0] == "object") {
  138.       FunctionCall.call( this,
  139.         arguments[0].fname,
  140.         arguments[0].args,
  141.         arguments[0].returnValue);        
  142.       }
  143.     else {
  144.       this.fname = fname;
  145.       if (args) {
  146.         this.args  =
  147.           (args instanceof Array) ?
  148.            args : Array.prototype.slice.call( args );
  149.       } else
  150.         this.args = [];
  151.       this.returnValue = returnValue;
  152.       }
  153.     }
  154.   FunctionCall.prototype.equals = function( fcall2 ) {
  155.     return this.fname == fcall2.fname &&
  156.            this.args.every( function(arg,i) {
  157.               return arg == fcall2.args[i]
  158.               })
  159.     }
  160.   FunctionCall.prototype.toString = function() {
  161.     var result = this.fname + "(" +
  162.       (this.args.length > 0 ? '"' + this.args.join('","') + '"' : '') +
  163.       ")";
  164.     if (this.returnValue !== null) result += '-> ' + this.returnValue;  
  165.     return result;      
  166.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement