hopjs
Version:
A RESTful declarative API framework, with stub generators for Shell, and Android
869 lines (699 loc) • 29.8 kB
JavaScript
/**
Testing module
@module Hop
@submodule Test
**/
var Hop = require('./api');
var assert = require('assert');
if(process.env.NODE_ENV!="production"){
Hop.enableUnitTests=true;
}
Hop.TestCases={};
/**
Holds testing utility functions
*All of the functions in this class must be usable with (function).toString() for embedding*
@class Hop.TestUtils
**/
Hop.TestUtils={};
/**
Test to insure that all the input object properties are the same as the output object properties
* The output object may have more properties then are in the input object
* The output object must have all of the same properties, with the same value as the input object
*This function is designed to be usable with (function).toString() for embedding*
@param {object} input The input object
@param {object} output The output object
@method Hop.TestUtils.objectCovers
@static
**/
Hop.TestUtils.objectCovers=function(input,output){
var recurse=function(input,output){
if(typeof input!=typeof output){
return false;
} else {
if(input instanceof Array){
for(var i in input){
var found=false;
for(var j in output){
if(recurse(input[i],output[j])){
found=true;
}
}
if(!found){
return false;
}
}
return true;
} else if(typeof input=="object") {
for(var inputProp in input){
if(input!=null && output==null)
return false;
else if(typeof input[inputProp]!=typeof output[inputProp])
return false;
if(input[inputProp] instanceof Array){
var res = recurse(input[inputProp],output[inputProp]);
if(res==false)
return false;
} else if(typeof input[inputProp]=="object"){
var res = recurse(input[inputProp],output[inputProp]);
if(res==false)
return false;
} else if(input[inputProp]!==output[inputProp])
return false
}
return true;
} else {
return (input==output);
}
}
}
return recurse(input,output);
}
assert.equal(Hop.TestUtils.objectCovers([1,2,3,4],[1,2,3,4,5]),true);
assert.equal(Hop.TestUtils.objectCovers([1,2,3,4],[1,2,4,5]),false);
assert.equal(Hop.TestUtils.objectCovers("hello","hello"),true);
assert.equal(Hop.TestUtils.objectCovers({a:1},{a:1}),true);
assert.equal(Hop.TestUtils.objectCovers({a:1},{b:1}),false);
assert.equal(Hop.TestUtils.objectCovers({a:1,b:1},{a:1,b:1,c:3}),true);
assert.equal(Hop.TestUtils.objectCovers({a:1, b:{ k:3} },{a:1, b:{ k:3}}),true);
assert.equal(Hop.TestUtils.objectCovers({a:1, b:{ k:3} },{a:1, b:{ k:8}}),false);
assert.equal(Hop.TestUtils.objectCovers({a:1, b:{ k:3}, complex: [ 1, '3','A',{ a:1 },{ b:5, c:[1,2,3,'5']}]}, {a:1, b:{ k:3}, complex: [ 1, '3','A',{ a:1 },{ b:5, c:[1,2,3,'5']}]}),true);
assert.equal(Hop.TestUtils.objectCovers({a:1, b:{ k:3}, complex: [ 1, '3','A',{ a:1 },{ b:5, c:[1,2,3,'5']}]}, {a:1, b:{ k:3} }),false);
assert.equal(Hop.TestUtils.objectCovers({a:1, b:{ k:3}, complex: [ 1, '3','A',{ a:1 },{ b:5, c:[1,2,3,'5']}]}, {a:1, b:{ k:3}, complex: [ 1, '3','A',{ a:1 },{ b:5, c:[1,2,3]}]}),false);
assert.equal(Hop.TestUtils.objectCovers([ { name:'foo' }, {name:'bar',roles:['a','b','c'], thing:{ a:1, b:2}}], [ { name:'foo' }, {name:'bar',roles:['a','b','c'], thing:{ a:1, b:2}}]),true);
assert.equal(Hop.TestUtils.objectCovers([ { name:'foo' }, {name:'bar',roles:['a','b','c'], thing:{ a:1, b:2}}], [ { name:'foo' }, {name:'bar',roles:['a','b','c'], thing:{ a:1, b:5}}]),false);
assert.equal(Hop.TestUtils.objectCovers([ { name:'foo' }, {name:'bar',roles:['a','b','c'], thing:{ a:1, b:2}}], [{name:'bar',roles:['a','b','c'], thing:{ a:1, b:5}}]),false);
/**
Test to ensure that the output object has a specific property with a specific value
*This function is designed to be usable with (function).toString() for embedding*
@param {Object} output The output object
@param {String} propertyName The property to test (supports dotted notation)
@param {Object} [propertyValue] The expected object value
@return bool
@static
@method Hop.TestUtils.inputSameAsOutput
**/
Hop.TestUtils.outputHasProperty=function(output,propertyName,propertyValue){
var propertyStack = propertyName.split(".");
var findProperty=function(output,propertyStack){
var prop = propertyStack.shift();
if(propertyStack.length==0){
return output[prop];
} else {
if(typeof output[prop]=="object")
return findProperty(output[prop],propertyStack);
else return undefined;
}
}
var value = findProperty(output,propertyStack);
if(typeof propertyValue!="undefined"){
return value==propertyValue;
} else {
return (typeof value!="undefined");
}
}
assert.equal(Hop.TestUtils.outputHasProperty({a:1},"a",1),true);
assert.equal(Hop.TestUtils.outputHasProperty({a:1},"a"),true);
assert.equal(Hop.TestUtils.outputHasProperty({a:1},"b"),false);
assert.equal(Hop.TestUtils.outputHasProperty({a:1, b:1},"b"),true);
assert.equal(Hop.TestUtils.outputHasProperty({a:1, b:1, c:{d:{e:"hello"}}},"c.d.e"),true);
assert.equal(Hop.TestUtils.outputHasProperty({a:1, b:1, c:{d:{e:"hello"}}},"c.d.e",3),false);
assert.equal(Hop.TestUtils.outputHasProperty({a:1, b:1, c:{d:{e:"hello"}}},"c.k.e"),false);
/**
Test to ensure that the array contains the specified value
*This function is designed to be usable with (function).toString() for embedding*
@param {Object} array The output array
@param {Object value The expected object value
@return bool
@static
@method Hop.TestUtils.arrayContains
**/
Hop.TestUtils.arrayContains=function(array,value){
for(var i in array){
var v=array[i];
if(Hop.TestUtils.objectCovers(value,v)){
return true;
}
}
return false;
}
assert.equal(Hop.TestUtils.arrayContains(["A","b","c","d"],"a"),false);
assert.equal(Hop.TestUtils.arrayContains(["A","b","c","d"],"A"),true);
assert.equal(Hop.TestUtils.arrayContains(["A","b","c","d", { a: 1, b: 2}],{a:1,b:2}),true);
assert.equal(Hop.TestUtils.arrayContains(["A","b","c","d", { a: 1, b: 2,c:3}],{a:1,b:2}),true);
assert.equal(Hop.TestUtils.arrayContains(["A","b","c","d", { a: 1, b: 2}],{a:1,b:2,c:3}),false);
/**
Loads a value for later usage as part of a test
@static
@method Hop.TestUtils.loadValue
**/
Hop.TestUtils.loadValue=function(name){
if(typeof name=="string"){
if(typeof Hop.TestUtils!="undefined" && typeof Hop.TestUtils._savedValues!="undefined"){
with(Hop.TestUtils._savedValues){
try {
return eval(name);
} catch(e){
Hop.error(e);
return undefined;
}
}
//return Hop.TestUtils._savedValues[name];
}
}
else return undefined;
}
/**
Clears all saved values, this is called at the completion of a test case
@static
@method Hop.TestUtils.clearValues
**/
Hop.TestUtils.clearValues=function(){
Hop.TestUtils._savedValues={};
delete Hop.TestUtils._savedValues;
}
/**
Saves a value for later usage as part of a test
@static
@method Hop.TestUtils.saveValue
**/
Hop.TestUtils.saveValue=function(name,value){
if(typeof Hop.TestUtils._savedValues=="undefined")
Hop.TestUtils._savedValues={};
Hop.TestUtils._savedValues[name]=value;
}
/**
Resolve a values within an array or object based upon saved values
This function will search for strings matching #{.+#} and replace
the object property or array value with the resolved value from a saved value.
Values are resolved like so:
@example
with(savedValues){
return eval(inputString);
}
@examples
#{savedUser.name}
#{savedUsers[1].name}
#{undefined} // will return undefined
@static
@method Hop.TestUtils.resolve
**/
Hop.TestUtils.resolve=function(object,checkSavedObjects){
if(typeof object=="string" && checkSavedObjects==true){
if(typeof Hop.TestUtils._savedValues!="undefined" && typeof Hop.TestUtils._savedValues[object]!="undefined"){
return Hop.TestUtils._savedValues[object];
}
}
if(object instanceof Array){
return object.map(function(item){
return Hop.TestUtils.resolve(item);
});
} else if(typeof object=="object"){
for(var propName in object){
var prop = object[propName];
object[propName]=Hop.TestUtils.resolve(prop);
}
return object;
} else if(typeof object=="string"){
var m = /^\#\{(.+)\}$/.exec(object);
if(m && m.length>1){
with(Hop.TestUtils._savedValues){
return eval(m[1]);
}
} else {
return object;
}
} else return object;
}
Hop.TestUtils.saveValue("Foo",{ a:1, b:2, c:true, d:"Bar"});
Hop.TestUtils.saveValue("Foos",[{ a:1, b:2, c:true, d:"Bar"},"a"]);
assert.deepEqual(Hop.TestUtils.resolve({ a:"#{Foo.d}"}), {a:"Bar"});
assert.deepEqual(Hop.TestUtils.resolve({ a:"#{Foo.c}"}), {a:true});
assert.deepEqual(Hop.TestUtils.resolve({ a:"#{Foo.e}"}), {a:undefined});
assert.deepEqual(Hop.TestUtils.resolve({ a:"#{Foo.a}", b:[1,2,3,"#{Foo.b}"]}), {a:1, b:[1,2,3,2]});
assert.deepEqual(Hop.TestUtils.resolve({ a:"#{Foo.a}", b:[1,2,3,"#{Foo.b}"], e: { a:{ a: 44, j:['a','b','c','d']}}}), {a:1, b:[1,2,3,2],e: { a:{ a: 44, j:['a','b','c','d']}}});
assert.equal(Hop.TestUtils.resolve("#{Foo.d}"),"Bar");
assert.deepEqual(Hop.TestUtils.resolve("Foo",true),{ a:1, b:2, c:true, d:"Bar"});
assert.equal(Hop.TestUtils.resolve(4),4);
assert.equal(Hop.TestUtils.resolve("#{undefined}"),undefined);
assert.equal(Hop.TestUtils.resolve("#{Foos[1]}"),"a");
assert.deepEqual(Hop.TestUtils.resolve("#{Foo}"),{ a:1, b:2, c:true, d:"Bar"});
Hop.TestUtils.clearValues();
/**
Return the value of the named property in the object
The property name may be in dotted form
@param {Object} object
@param {String} property
@static
@method Hop.TestUtils.getProperty
**/
Hop.TestUtils.getProperty=function(object,property){
with(object){
return eval(property);
}
}
/**
Utility function to copy an object, primarly used by .with
@static
@method Hop.TestUtils.extendTo
**/
Hop.TestUtils.extendTo=function(toObj,fromObj){
var result = JSON.parse(JSON.stringify(toObj));
var copyProps = function(toObj,fromObj){
for(var propName in fromObj){
var prop = fromObj[propName];
if(prop!=null && typeof prop == "object" && typeof toObj[propName]=="object"){
copyProps(toObj[propName],fromObj[propName]);
} else {
toObj[propName]=prop;
}
}
}
copyProps(result,fromObj);
return result;
}
assert.deepEqual(Hop.TestUtils.extendTo({array:[1,3,4]},{array:null}),{array:null});
/**
Define a test case for a specific method
@param {string} name the name of the method to test, this must be the same as a defined API method, and may also contain a commnet appened after a :
@param {function} lambda The lambda defining the test
@example
Hop.defineTestCase("User.authenticate: Test Authentication",function(test){
var validUser = { email:"test@test.com", username:"TestUser" };
test.do("User.create").with(validUser).noError();
test.do("User.authenticate").with(validUser).noError();
test.do("User.authenticate").with({password:"BOB"},validUser).containsError("Permission denied");
});
@for Hop
@method defineTestCase
@static
**/
Hop.defineTestCase=function(name,onTest){
if(!Hop.enableUnitTests)
return;
if(name.indexOf(":")!=-1){
var method=name.split(":")[0];
method = Hop.Method.findMethod(method);
} else {
var method = Hop.Method.findMethod(name);
}
delete Hop._checksum;
if(!method)
throw "Invalid test case name specified, must be named after a defined method";
method.addAfterTemplate("Doc","test/postDocMethod.comb");
var obj = Hop.Object.findObject(name);
obj.addAfterTemplate("Doc","test/postDocObject.comb");
Hop.addBeforeTemplate("Doc","test/preDocHop.comb");
Hop.addAfterTemplate("Doc","test/postDocHop.comb");
var test = new Hop.TestCase(name,onTest);
}
/**
Used to impelement the .do interface for defineTest
so .do("MyClass.myFunc") is implemented by this class
@param {string} funcName The name of the function this test should call
@class Hop.TestTask
@constructor
**/
Hop.TestTask = function(funcName){
this.funcName=funcName;
this.inputObject=undefined;
this.test=[];
}
Hop.TestTask.prototype.getInputObject=function(){
return this.inputObject;
}
/**
Defines the input to be used for the API call
This may either be a JavaScript Object or a named value (as created by .saveOutputAs)
@example
test.do("Object.method").with({a:1, b:2});
@example
test.do("Object.method").with("savedValue");
@example
test.do("Object.method").with("savedValue",{a: 6} );
@param {Mixed} inputValue The input value to use. Can be an object or string
@param {Object} extend The object to extend the input value with. Can be an object or string
@chainable
@method with
**/
Hop.TestTask.prototype.with=function(){
var args = Array.prototype.slice.call(arguments,0);
var containsValue=false;
for(var i in args){
if(typeof args[i] == "string")
containsValue=true;
}
if(!containsValue){
var obj = args[0];
for(var i=1;i<args.length;i++){
obj = Hop.TestUtils.extendTo(obj,args[i]);
}
this.inputObject=obj;
} else {
this.inputObjectFunc="function(){"+
"var args = "+JSON.stringify(args)+";"+
"var obj = args[0];"+
"if(typeof obj=='string'){ obj = Hop.TestUtils.loadValue(obj); }"+
"for(var i=1;i<args.length;i++){"+
"if(typeof obj=='string'){ obj = Hop.TestUtils.loadValue(obj); }"+
"if(typeof args[i]=='string'){ args[i] = Hop.TestUtils.loadValue(args[i]); }"+
"obj = Hop.TestUtils.extendTo(obj,args[i]);"+
"}"+
"obj = Hop.TestUtils.resolve(obj,true);"+
"return obj;"+
"}";
}
return this;
}
/**
Save the output into a name variable for usage later
@param {string} name The name of the value to save
@chainable
@method saveOutputAs
**/
Hop.TestTask.saveOutputAs={ pass:"The output was saved", fail: "The output was not saved" };
Hop.TestTask.prototype.saveOutputAs=function(value){
var testFunc=function(input,err,output,value){ Hop.TestUtils.saveValue(value,output); return true; }
this.test.push({ type:"saveOutputAs", testFunc: testFunc.toString(), value:value});
return this;
}
/**
Require that the function does not return an error
*This will not test the result in anyway, since having both a null error and null result is acceptable*
@chainable
@method noError
**/
Hop.TestTask.noError={ pass:"No error was recieved", fail: "An unexpected error was recieved" };
Hop.TestTask.prototype.noError=function(){
var testFunc=function(input,err,output){ return (err==null); }
this.test.push({ type:"noError", testFunc: testFunc.toString()});
return this;
}
/**
Require that the specified property has been changed from what was in the input
*This test will also insure that the error is null and that the result is not null*
@param {String} value The name of the property in the output
@chainable
@method outputPropertyChanged
**/
Hop.TestTask.outputPropertyChanged={ pass:"The property changed as expected", fail: "The output property didn't change as expected" };
Hop.TestTask.prototype.outputPropertyChanged=function(value){
var testFunc=function(input,err,output,value){ return (err==null && input!=null && output!=null && Hop.TestUtils.getProperty(input,value)!=Hop.TestUtils.getProperty(output,value)); }
this.test.push({ type: "outputPropertyChanged", testFunc: testFunc.toString(), value:value });
return this;
}
/**
Require that the input object is contained within the output object
This will test to insure that the output object minially contains all the same parameters as the input object
@chainable
@method inputSameAsOutput
**/
Hop.TestTask.inputSameAsOutput={ pass:"The output was the same as the input", fail: "The output was not the same as the input" };
Hop.TestTask.prototype.inputSameAsOutput=function(){
var testFunc=function(input,err,output){ return Hop.TestUtils.objectCovers(input,output); }
this.test.push({ type: "inputSameAsOutput", testFunc: testFunc.toString() });
return this;
}
/**
Test to insure the output is null
@chainable
@method outputIsNull
**/
Hop.TestTask.outputIsNull={ pass:"The output was null", fail: "The output was not null" };
Hop.TestTask.prototype.outputIsNull=function(){
var testFunc=function(input,err,output){ return output==null; }
this.test.push({ type:"outputIsNull", testFunc: testFunc.toString() });
return this;
}
/**
Test to insure the output is not null
*This test will also insure that the error is null*
@chainable
@method outputNotNull
**/
Hop.TestTask.outputNotNull={ pass:"The output was not null", fail: "The output was null, or there was also an error" };
Hop.TestTask.prototype.outputNotNull=function(){
var testFunc=function(input,err,output){ return (err==null && output!=null); };
this.test.push({ type:"outputNotNull", testFunc: testFunc.toString() });
return this;
}
/**
Test to insure that the output does not contain a specific object
This test will insure that the output does not contain a specific object
@param {Object} value The object that shouldn't appear in the output
@chainable
@method outputDoesntContain
**/
Hop.TestTask.outputDoesntContain={ pass:"The output does not contain the specified value", fail: "The output contained the specified value" };
Hop.TestTask.prototype.outputDoesntContain=function(value){
var testFunc=function(input,err,output,value){ value=Hop.TestUtils.resolve(value,true); return (output!=null && !Hop.TestUtils.objectCovers(value,output)); };
this.test.push({ type:"outputDoesntContain", value: value, testFunc: testFunc.toString() });
return this;
}
/**
Test to insure that the output contains a specific object
This test will insure that the output is a superset of the specified object
@param {Object} value The object to compare the output to
@chainable
@method outputContains
**/
Hop.TestTask.outputContains={ pass:"The output contains the expected value", fail: "The output did not contain the expected value, or was null" };
Hop.TestTask.prototype.outputContains=function(value){
var testFunc=function(input,err,output,value){ value=Hop.TestUtils.resolve(value,true); return (output!=null && Hop.TestUtils.objectCovers(value,output)); };
this.test.push({ type:"outputContains", value: value, testFunc: testFunc.toString() });
return this;
}
/**
Insure that an error exists
*This will also test to insure the output is null*
@chainable
@method hasError
**/
Hop.TestTask.hasError={ pass:"An error was detected", fail: "An error was not detected" };
Hop.TestTask.prototype.hasError=function(){
var testFunc=function(input,err,output){ return (err!=null && output==null); }
this.test.push({ type:"hasError", testFunc:testFunc.toString() });
return this;
}
/**
Insure the error contains a specific string
*This will also test to insure the output is null*
@param {String} value The string to insure the error contains
@chainable
@method errorContains
**/
Hop.TestTask.errorContains={ pass:"The error contained the expected value", fail: "The error did not contain the expected value, or unexpectedly had an output" };
Hop.TestTask.prototype.errorContains=function(value){
var testFunc=function(input,err,output,value){ return (err!=null && output==null && (typeof err.indexOf=="function") && err.indexOf(value)!=-1); }
this.test.push({ type:"errorContains", value: value, testFunc:testFunc.toString() });
return this;
}
/**
Insure that the output has a specified property
This will test for existence of a specific property
@param {String} property The name of the property
@chainable
@method outputHasProperty
**/
Hop.TestTask.outputHasProperty={ pass:"The output had the expected property", fail: "The output did not have the expected property, or an error occured" };
Hop.TestTask.prototype.outputHasProperty=function(value){
var testFunc=function(input,err,output,value){ return (err==null && output!=null && Hop.TestUtils.outputHasProperty(output,value)); }
this.test.push({ type:"outputHasProperty", value: value, testFunc:testFunc.toString() });
return this;
}
/**
Test the output to make sure it is the same as the specified object or saved object
@example
Test.do("User.save").with(user).outputSameAs({ name:'foo', email:'bar@bar.com'});
Test.do("User.save").with(user).outputSameAs("#{savedUser}");
Test.do("User.save").with(user).outputSameAs("#{savedUsers[1]}");
@param {String} savedValue The name of the saved result
@chainable
@method outputSameAs
**/
Hop.TestTask.outputSameAs={ pass:"The output was the same as expected", fail: "The output was not the same as expected" };
Hop.TestTask.prototype.outputSameAs=function(value){
var testFunc=function(input,err,output,value){ var value = Hop.TestUtils.resolve(value,true); return (err==null && Hop.TestUtils.objectCovers(value,output)); }
this.test.push({ type:"outputSameAs", value: value, testFunc:testFunc.toString() });
return this;
}
/**
Test the output to make sure it an array with a maximum length
@param {String} length The maximum length of the array
@chainable
@method outputIsArrayWithMaxLength
**/
Hop.TestTask.outputIsArrayWithMaxLength={ pass:"The output was an array with expected length", fail: "The output was not an array with the expected length, or an error occured" };
Hop.TestTask.prototype.outputIsArrayWithMaxLength=function(value){
var testFunc=function(input,err,output,value){ return (output instanceof Array && err==null && output.length<=Hop.TestUtils.resolve(value,true)); }
this.test.push({ type:"outputIsArrayWithMaxLength", value: value, testFunc:testFunc.toString() });
return this;
}
/**
Test the output to make sure it an array with a minimum length
@param {String} length The minimum length of the array
@chainable
@method outputIsArrayWithMinLength
**/
Hop.TestTask.outputIsArrayWithMinLength={ pass:"The output was an array with expected length", fail: "The output was not an array with the expected length, or an error occured" };
Hop.TestTask.prototype.outputIsArrayWithMinLength=function(value){
var testFunc=function(input,err,output,value){ return (output instanceof Array && err==null && output.length>=Hop.TestUtils.resolve(value,true)); }
this.test.push({ type:"outputIsArrayWithMinLength", value: value, testFunc:testFunc.toString() });
return this;
}
/**
Test the output to make sure it an array with a specified length
@param {String} length The length of the array
@chainable
@method outputIsArrayWithLength
**/
Hop.TestTask.outputIsArrayWithLength={ pass:"The output was an array with expected length", fail: "The output was not an array with the expected length, or an error occured" };
Hop.TestTask.prototype.outputIsArrayWithLength=function(value){
var testFunc=function(input,err,output,value){ return (output instanceof Array && err==null && output.length==Hop.TestUtils.resolve(value,true)); }
this.test.push({ type:"outputIsArrayWithLength", value: value, testFunc:testFunc.toString() });
return this;
}
/**
Test the output to make sure it is an array
@chainable
@method outputIsArray
**/
Hop.TestTask.outputIsArray={ pass:"The output was an array", fail: "The output was not an array, or an error occured" };
Hop.TestTask.prototype.outputIsArray=function(value){
var testFunc=function(input,err,output,value){ return (output instanceof Array && err==null); }
this.test.push({ type:"outputIsArray", value: value, testFunc:testFunc.toString() });
return this;
}
/**
Test the output array doesnt contain the specified value
@chainable
@method outputArrayDoesntContains
**/
Hop.TestTask.outputArrayDoesntContain={ pass:"The output array did not contained the specified value", fail: "The output array contained the specified value, or an error occured" };
Hop.TestTask.prototype.outputArrayDoesntContain=function(value){
var testFunc=function(input,err,output,value){ if(output instanceof Array && err==null){ value = Hop.TestUtils.resolve(value,true); return !Hop.TestUtils.arrayContains(output,value); } else return false; }
this.test.push({ type:"outputArrayDoesntContain", value: value, testFunc:testFunc.toString() });
return this;
}
/**
Test the output array contains the specified value
@chainable
@method outputArrayContains
**/
Hop.TestTask.outputArrayContains={ pass:"The output array contained the specified value", fail: "The output array did not contain the specified value, or an error occured" };
Hop.TestTask.prototype.outputArrayContains=function(value){
var testFunc=function(input,err,output,value){ if(output instanceof Array && err==null){ value = Hop.TestUtils.resolve(value,true); return Hop.TestUtils.arrayContains(output,value); } else return false; }
this.test.push({ type:"outputArrayContains", value: value, testFunc:testFunc.toString() });
return this;
}
/**
Test to see that the specified array contains the specified value
@param {String} property
@param {Object} value
@chainable
@method arrayContains
**/
Hop.TestTask.arrayContains={ pass: "The array contains the specified value", fail:"The array does not contain the specified value, or an error occured" };
Hop.TestTask.prototype.arrayContains=function(property,tv){
var value = { property: property, tv: tv };
var testFunc=function(input,err,output,value){ if(output){ var p = Hop.TestUtils.getProperty(output,value.property); if(p instanceof Array) { var v = Hop.TestUtils.resolve(value.tv,true); return Hop.TestUtils.arrayContains(p,v); }} return false; }
this.test.push({ type:"arrayContains", value: value, testFunc: testFunc.toString() });
return this;
}
/**
Test to see that the specified array does not contain the specified value
@param {String} property
@param {Object} value
@chainable
@method arrayDoesntContains
**/
Hop.TestTask.arrayDoesntContain={ pass: "The array does not contain the specified value", fail:"The array contains the specified value, or an error occured" };
Hop.TestTask.prototype.arrayDoesntContain=function(property,tv){
var value = { property: property, tv: tv };
var testFunc=function(input,err,output,value){ if(output){ var p = Hop.TestUtils.getProperty(output,value.property); if(p instanceof Array) { var v = Hop.TestUtils.resolve(value.tv,true); return !Hop.TestUtils.arrayContains(p,v); }} return false; }
this.test.push({ type:"arrayDoesntContain", value: value, testFunc: testFunc.toString() });
return this;
}
/**
TestCase Class
This is the underlying class which is used in defineTestCase
*To construct a new test case use defineTestCase instead*
*The name of the case must alway be the name of a method, but may be followed by a description*
@example
Hop.defineTestCase("Object.Method",function()...);
Hop.defineTestCase("Object.Method: Do a specific test",function()...);
@param {String} name The name of the test case, this must always start with the name of a defined method, but may also include a description seperated by a ':'
@param {Function} onTest The function defining the test case
@class Hop.TestCase
@constructor
**/
Hop.TestCase=function(name,onTest){
this.name=name;
this.uses=[];
this.tasks=[];
onTest(this);
Hop.TestCases[name]=this;
}
/**
Create a special object to instruct Hop to use a file provide by a URL as a test input value
@param {String} url url to fetch file from (this should be a url on the local server)
@static
@method fileFromURL
**/
Hop.TestCase.prototype.fileFromURL=function(url){
return { _fileFromURL: url };
}
Hop.TestCase.standAloneSupport=function(options){
return Hop.renderTemplate("test/standalone.comb")({ Hop: Hop, supportCode:true });
}
Hop.TestCase.toStandAlone=function(){
var str="";
str+=Hop.TestCase.standAloneSupport();
for(var i in Hop.TestCases){
str+=Hop.TestCases[i].toStandAlone();
}
return str;
}
Hop.TestCase.prototype.toStandAlone=function(){
return Hop.renderTemplate("test/standalone.comb")(this);
}
Hop.TestCase.prototype.use=function(urlOrService){
this.uses.push(urlOrService);
return null;
}
//This is a fairly nasty hack, which will be resolved in the next version of HopJS.
Hop.TestCase.prototype.until=function(apiName, options){
var until = new Hop.TestTask(apiName);
until.until=options;
this.tasks.push(until);
return this.tasks[this.tasks.length-1];
}
Hop.TestCase.prototype.do=function(apiName){
this.tasks.push(new Hop.TestTask(apiName));
return this.tasks[this.tasks.length-1];
}
Hop.TestCase.prototype.task=function(onTask){
this.tasks.push(onTask);
return this.tasks[this.tasks.length-1];
}
Hop.TestService={
wait:function(input,onComplete){
setTimeout(function(){
return onComplete(null,true);
},input.duration*1000);
},
log:function(input,onComplete){
Hop.log(input.msg);
return onComplete(null,true);
},
exit:function(input,onComplete){
process.exit(-1);
return onComplete(null,true);
}
}
if(Hop.enableUnitTests){
Hop.defineClass("TestService",Hop.TestService,function(api){
api.get("wait","/hopjs/test/wait").demand("duration");
api.get("log","/hopjs/test/log").demand("msg");
api.get("exit","/hopjs/test/exit");
});
}