From 832d871055aadb4173623f2ebb3d97eecd81400c Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Mon, 5 Feb 2018 20:19:10 -0600 Subject: [PATCH 01/10] version bump --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index fc5cb54f..046d4c85 100644 --- a/build/build.xml +++ b/build/build.xml @@ -9,7 +9,7 @@ - + From 01ca3ef8db12e9f3a2316cd1c7c29526087feded Mon Sep 17 00:00:00 2001 From: Brandon Brown Date: Mon, 5 Mar 2018 11:52:38 -0600 Subject: [PATCH 02/10] Fix for new version of Lucee There is a new key "position" added to the struct which is not a simple value. --- system/mockutils/MockGenerator.cfc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/mockutils/MockGenerator.cfc b/system/mockutils/MockGenerator.cfc index 08aeb05c..cca52b98 100644 --- a/system/mockutils/MockGenerator.cfc +++ b/system/mockutils/MockGenerator.cfc @@ -330,7 +330,7 @@ Description : // iterate over the values of the function for( local.fncKey in local.oMD[ x ] ){ // Do Simple values only - if( NOT local.fncKey eq "parameters" ){ + if( isSimpleValue(local.oMD[ x ][ local.fncKey ]) ){ udfOut.append(' #lcase( local.fncKey )#="#local.oMD[ x ][ local.fncKey ]#"'); } } @@ -370,4 +370,4 @@ Description : - \ No newline at end of file + From f047798d19ec82ab63527e6e5371f7bfcbf08da1 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 12 Mar 2018 15:19:38 -0700 Subject: [PATCH 03/10] add sort criteria to test browser file and folder list --- test-browser/index.cfm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-browser/index.cfm b/test-browser/index.cfm index 68f2fd66..1c27daa1 100644 --- a/test-browser/index.cfm +++ b/test-browser/index.cfm @@ -32,7 +32,7 @@ - + From cad73973d2ce9feac5a33e3b475c94d7283dfa4f Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 11 Apr 2018 15:40:45 -0500 Subject: [PATCH 04/10] some refactoring to use invoke() instead of evaluate() TESTBOX-219 #resolve --- system/Assertion.cfc | 224 ++++++++++++++--------------- system/BaseSpec.cfc | 5 +- system/CollectionExpectation.cfc | 16 ++- system/Expectation.cfc | 34 ++--- system/runners/BDDRunner.cfc | 11 +- system/runners/UnitRunner.cfc | 14 +- system/util/XMLConverter.cfc | 2 +- tests/specs/BDDTest.cfc | 4 +- tests/specs/NestedDescribeTest.cfc | 35 ++++- 9 files changed, 186 insertions(+), 159 deletions(-) diff --git a/system/Assertion.cfc b/system/Assertion.cfc index 7d27019a..2f1541f3 100644 --- a/system/Assertion.cfc +++ b/system/Assertion.cfc @@ -8,7 +8,7 @@ component{ /** * Fail assertion - * @message.hint The message to send in the failure + * @message The message to send in the failure */ function fail( message="" ){ arguments.message = ( len( arguments.message ) ? arguments.message : "A test failure occurred" ); @@ -17,8 +17,8 @@ component{ /** * Assert that the passed expression is true - * @expression.hint The expression to test - * @message.hint The message to send in the failure + * @expression The expression to test + * @message The message to send in the failure */ function assert( required boolean expression, message="" ){ return isTrue( arguments.expression, arguments.message ); @@ -26,8 +26,8 @@ component{ /** * Assert something is true - * @actual.hint The actual data to test - * @message.hint The message to send in the failure + * @actual The actual data to test + * @message The message to send in the failure */ function isTrue( required boolean actual, message="" ){ arguments.message = ( len( arguments.message ) ? arguments.message : "Expected [#arguments.actual#] to be true" ); @@ -39,8 +39,8 @@ component{ /** * Assert something is false - * @actual.hint The actual data to test - * @message.hint The message to send in the failure + * @actual The actual data to test + * @message The message to send in the failure */ function isFalse( required boolean actual, message="" ){ arguments.message = ( len( arguments.message ) ? arguments.message : "Expected [#arguments.actual#] to be false" ); @@ -52,9 +52,9 @@ component{ /** * Assert something is equal to each other, no case is required - * @expected.hint The expected data - * @actual.hint The actual data to test - * @message.hint The message to send in the failure + * @expected The expected data + * @actual The actual data to test + * @message The message to send in the failure */ function isEqual( any expected, any actual, message="" ){ // validate equality @@ -68,9 +68,9 @@ component{ /** * Assert something is not equal to each other, no case is required - * @expected.hint The expected data - * @actual.hint The actual data to test - * @message.hint The message to send in the failure + * @expected The expected data + * @actual The actual data to test + * @message The message to send in the failure */ function isNotEqual( any expected, any actual, message="" ){ arguments.message = ( len( arguments.message ) ? @@ -84,9 +84,9 @@ component{ /** * Assert an object is the same instance as another object - * @expected.hint The expected data - * @actual.hint The actual data to test - * @message.hint The message to send in the failure + * @expected The expected data + * @actual The actual data to test + * @message The message to send in the failure */ function isSameInstance( required any expected, required any actual, message="" ){ var expectedIdentityHashCode = getIdentityHashCode( arguments.expected ); @@ -101,9 +101,9 @@ component{ /** * Assert an object is not the same instance as another object - * @expected.hint The expected data - * @actual.hint The actual data to test - * @message.hint The message to send in the failure + * @expected The expected data + * @actual The actual data to test + * @message The message to send in the failure */ function isNotSameInstance( required any expected, required any actual, message="" ){ var expectedIdentityHashCode = getIdentityHashCode( arguments.expected ); @@ -118,9 +118,9 @@ component{ /** * Assert strings are equal to each other with case. - * @expected.hint The expected data - * @actual.hint The actual data to test - * @message.hint The message to send in the failure + * @expected The expected data + * @actual The actual data to test + * @message The message to send in the failure */ function isEqualWithCase( string expected, string actual, message="" ){ arguments.message = ( len( arguments.message ) ? arguments.message : "Expected [#getStringName( arguments.expected )#] but received [#getStringName( arguments.actual )#]" ); @@ -135,8 +135,8 @@ component{ /** * Assert something is null - * @actual.hint The actual data to test - * @message.hint The message to send in the failure + * @actual The actual data to test + * @message The message to send in the failure */ function null( any actual, message="" ){ // equalize with case @@ -150,8 +150,8 @@ component{ /** * Assert something is not null - * @actual.hint The actual data to test - * @message.hint The message to send in the failure + * @actual The actual data to test + * @message The message to send in the failure */ function notNull( any actual, message="" ){ // equalize with case @@ -163,9 +163,9 @@ component{ /** * Assert the type of the incoming actual data, it uses the internal ColdFusion isValid() function behind the scenes - * @type.hint The type to check, valid types are: array, binary, boolean, component, date, time, float, numeric, integer, query, string, struct, url, uuid - * @actual.hint The actual data to check - * @message.hint The message to send in the failure + * @type The type to check, valid types are: array, binary, boolean, component, date, time, float, numeric, integer, query, string, struct, url, uuid + * @actual The actual data to check + * @message The message to send in the failure */ function typeOf( required string type, required any actual, message=""){ arguments.message = ( len( arguments.message ) ? arguments.message : "Actual data [#getStringName( arguments.actual )#] is not of this type: [#arguments.type#]" ); @@ -175,9 +175,9 @@ component{ /** * Assert that is NOT a type of the incoming actual data, it uses the internal ColdFusion isValid() function behind the scenes - * @type.hint The type to check, valid types are: array, binary, boolean, component, date, time, float, numeric, integer, query, string, struct, url, uuid - * @actual.hint The actual data to check - * @message.hint The message to send in the failure + * @type The type to check, valid types are: array, binary, boolean, component, date, time, float, numeric, integer, query, string, struct, url, uuid + * @actual The actual data to check + * @message The message to send in the failure */ function notTypeOf( required string type, required any actual, message=""){ arguments.message = ( len( arguments.message ) ? arguments.message : "Actual data [#getStringName( arguments.actual )#] is actually of this type: [#arguments.type#]" ); @@ -187,9 +187,9 @@ component{ /** * Assert that the actual object is of the expected instance type - * @actual.hint The actual data to check - * @typeName.hint The typename to check - * @message.hint The message to send in the failure + * @actual The actual data to check + * @typeName The typename to check + * @message The message to send in the failure */ function instanceOf( required any actual, required string typeName, message=""){ arguments.message = ( len( arguments.message ) ? arguments.message : "The actual data is not of type [#arguments.typeName#]" ); @@ -199,9 +199,9 @@ component{ /** * Assert that the actual object is NOT of the expected instance type - * @actual.hint The actual data to check - * @typeName.hint The typename to check - * @message.hint The message to send in the failure + * @actual The actual data to check + * @typeName The typename to check + * @message The message to send in the failure */ function notInstanceOf( required any actual, required string typeName, message=""){ arguments.message = ( len( arguments.message ) ? arguments.message : "The actual data is actually of type [#arguments.typeName#]" ); @@ -211,9 +211,9 @@ component{ /** * Assert that the actual data matches the incoming regular expression with no case sensitivity - * @actual.hint The actual data to check - * @regex.hint The regex to check with - * @message.hint The message to send in the failure + * @actual The actual data to check + * @regex The regex to check with + * @message The message to send in the failure */ function match( required string actual, required string regex, message=""){ arguments.message = ( len( arguments.message ) ? arguments.message : "The actual [#arguments.actual.toString()#] does not match [#arguments.regex#]" ); @@ -223,9 +223,9 @@ component{ /** * Assert that the actual data matches the incoming regular expression with case sensitivity - * @actual.hint The actual data to check - * @regex.hint The regex to check with - * @message.hint The message to send in the failure + * @actual The actual data to check + * @regex The regex to check with + * @message The message to send in the failure */ function matchWithCase( required string actual, required string regex, message=""){ arguments.message = ( len( arguments.message ) ? arguments.message : "The actual [#arguments.actual.toString()#] does not match [#arguments.regex#]" ); @@ -235,9 +235,9 @@ component{ /** * Assert that the actual data does NOT match the incoming regular expression with no case sensitivity - * @actual.hint The actual data to check - * @regex.hint The regex to check with - * @message.hint The message to send in the failure + * @actual The actual data to check + * @regex The regex to check with + * @message The message to send in the failure */ function notMatch( required string actual, required string regex, message=""){ arguments.message = ( len( arguments.message ) ? arguments.message : "The actual [#arguments.actual.toString()#] actually matches [#arguments.regex#]" ); @@ -247,9 +247,9 @@ component{ /** * Assert that a given key exists in the passed in struct/object - * @target.hint The target object/struct - * @key.hint The key to check for existence - * @message.hint The message to send in the failure + * @target The target object/struct + * @key The key to check for existence + * @message The message to send in the failure */ function key( required any target, required string key, message=""){ arguments.message = ( len( arguments.message ) ? arguments.message : "The key [#arguments.key#] does not exist in the target object. Found keys are [#structKeyArray( arguments.target ).toString()#]" ); @@ -259,9 +259,9 @@ component{ /** * Assert that a given key DOES NOT exist in the passed in struct/object - * @target.hint The target object/struct - * @key.hint The key to check for existence - * @message.hint The message to send in the failure + * @target The target object/struct + * @key The key to check for existence + * @message The message to send in the failure */ function notKey( required any target, required string key, message=""){ arguments.message = ( len( arguments.message ) ? arguments.message : "The key [#arguments.key#] exists in the target object. Found keys are [#structKeyArray( arguments.target ).toString()#]" ); @@ -271,9 +271,9 @@ component{ /** * Assert that a given key exists in the passed in struct by searching the entire nested structure - * @target.hint The target object/struct - * @key.hint The key to check for existence anywhere in the nested structure - * @message.hint The message to send in the failure + * @target The target object/struct + * @key The key to check for existence anywhere in the nested structure + * @message The message to send in the failure */ function deepKey( required struct target, required string key, message=""){ arguments.message = ( len( arguments.message ) ? arguments.message : "The key [#arguments.key#] does not exist anywhere in the target object." ); @@ -283,9 +283,9 @@ component{ /** * Assert that a given key DOES NOT exists in the passed in struct by searching the entire nested structure - * @target.hint The target object/struct - * @key.hint The key to check for existence anywhere in the nested structure - * @message.hint The message to send in the failure + * @target The target object/struct + * @key The key to check for existence anywhere in the nested structure + * @message The message to send in the failure */ function notDeepKey( required struct target, required string key, message=""){ var results = structFindKey( arguments.target, arguments.key ); @@ -298,9 +298,9 @@ component{ /** * Assert the size of a given string, array, structure or query - * @target.hint The target object to check the length for, this can be a string, array, structure or query - * @length.hint The length to check - * @message.hint The message to send in the failure + * @target The target object to check the length for, this can be a string, array, structure or query + * @length The length to check + * @message The message to send in the failure */ function lengthOf( required any target, required string length, message=""){ var aLength = getTargetLength( arguments.target ); @@ -314,9 +314,9 @@ component{ /** * Assert the size of a given string, array, structure or query - * @target.hint The target object to check the length for, this can be a string, array, structure or query - * @length.hint The length to check - * @message.hint The message to send in the failure + * @target The target object to check the length for, this can be a string, array, structure or query + * @length The length to check + * @message The message to send in the failure */ function notLengthOf( required any target, required string length, message=""){ var aLength = getTargetLength( arguments.target ); @@ -330,8 +330,8 @@ component{ /** * Assert that a a given string, array, structure or query is empty - * @target.hint The target object to check the length for, this can be a string, array, structure or query - * @message.hint The message to send in the failure + * @target The target object to check the length for, this can be a string, array, structure or query + * @message The message to send in the failure */ function isEmpty( required any target, message=""){ var aLength = getTargetLength( arguments.target ); @@ -345,8 +345,8 @@ component{ /** * Assert that a a given string, array, structure or query is not empty - * @target.hint The target object to check the length for, this can be a string, array, structure or query - * @message.hint The message to send in the failure + * @target The target object to check the length for, this can be a string, array, structure or query + * @message The message to send in the failure */ function isNotEmpty( required any target, message=""){ var aLength = getTargetLength( arguments.target ); @@ -360,10 +360,10 @@ component{ /** * Assert that the passed in function will throw an exception - * @target.hint The target function to execute and check for exceptions - * @type.hint Match this type with the exception thrown - * @regex.hint Match this regex against the message + detail of the exception - * @message.hint The message to send in the failure + * @target The target function to execute and check for exceptions + * @type Match this type with the exception thrown + * @regex Match this regex against the message + detail of the exception + * @message The message to send in the failure */ function throws( required any target, type="", regex=".*", message="" ){ @@ -396,10 +396,10 @@ component{ /** * Assert that the passed in function will NOT throw an exception, an exception of a specified type or exception message regex - * @target.hint The target function to execute and check for exceptions - * @type.hint Match this type with the exception thrown - * @regex.hint Match this regex against the message+detail of the exception - * @message.hint The message to send in the failure + * @target The target function to execute and check for exceptions + * @type Match this type with the exception thrown + * @regex Match this regex against the message+detail of the exception + * @message The message to send in the failure */ function notThrows( required any target, type="", regex="", message="" ){ try{ @@ -428,11 +428,11 @@ component{ /** * Assert that the passed in actual number or date is expected to be close to it within +/- a passed delta and optional datepart - * @expected.hint The expected number or date - * @actual.hint The actual number or date - * @delta.hint The +/- delta to range it - * @datepart.hint If passed in values are dates, then you can use the datepart to evaluate it - * @message.hint The message to send in the failure + * @expected The expected number or date + * @actual The actual number or date + * @delta The +/- delta to range it + * @datepart If passed in values are dates, then you can use the datepart to evaluate it + * @message The message to send in the failure */ function closeTo( required any expected, required any actual, required any delta, datePart="", message=""){ arguments.message = ( len( arguments.message ) ? arguments.message : "The actual [#arguments.actual#] is not in range of [#arguments.expected#] by +/- [#arguments.delta#]" ); @@ -454,10 +454,10 @@ component{ /** * Assert that the passed in actual number or date is between the passed in min and max values - * @actual.hint The actual number or date to evaluate - * @min.hint The expected min number or date - * @max.hint The expected max number or date - * @message.hint The message to send in the failure + * @actual The actual number or date to evaluate + * @min The expected min number or date + * @max The expected max number or date + * @message The message to send in the failure */ function between( required any actual, required any min, required any max, message=""){ arguments.message = ( len( arguments.message ) ? arguments.message : "The actual [#arguments.actual#] is not between [#arguments.min#] and [#arguments.max#]" ); @@ -487,9 +487,9 @@ component{ /** * Assert that the given "needle" argument exists in the incoming string or array with no case-sensitivity - * @target.hint The target object to check if the incoming needle exists in. This can be a string or array - * @needle.hint The substring to find in a string or the value to find in an array - * @message.hint The message to send in the failure + * @target The target object to check if the incoming needle exists in. This can be a string or array + * @needle The substring to find in a string or the value to find in an array + * @message The message to send in the failure */ function includes( required any target, required any needle, message="" ){ arguments.message = ( len( arguments.message ) ? arguments.message : "The needle [#arguments.needle#] was not found in [#arguments.target.toString()#]" ); @@ -508,9 +508,9 @@ component{ /** * Assert that the given "needle" argument exists in the incoming string or array with case-sensitivity - * @target.hint The target object to check if the incoming needle exists in. This can be a string or array - * @needle.hint The substring to find in a string or the value to find in an array - * @message.hint The message to send in the failure + * @target The target object to check if the incoming needle exists in. This can be a string or array + * @needle The substring to find in a string or the value to find in an array + * @message The message to send in the failure */ function includesWithCase( required any target, required any needle, message="" ){ arguments.message = ( len( arguments.message ) ? arguments.message : "The needle [#arguments.needle#] was not found in [#arguments.target.toString()#]" ); @@ -529,9 +529,9 @@ component{ /** * Assert that the given "needle" argument does not exist in the incoming string or array with case-sensitivity - * @target.hint The target object to check if the incoming needle exists in. This can be a string or array - * @needle.hint The substring to find in a string or the value to find in an array - * @message.hint The message to send in the failure + * @target The target object to check if the incoming needle exists in. This can be a string or array + * @needle The substring to find in a string or the value to find in an array + * @message The message to send in the failure */ function notIncludesWithCase( required any target, required any needle, message="" ){ arguments.message = ( len( arguments.message ) ? arguments.message : "The needle [#arguments.needle#] was found in [#arguments.target.toString()#]" ); @@ -550,9 +550,9 @@ component{ /** * Assert that the given "needle" argument exists in the incoming string or array with no case-sensitivity - * @target.hint The target object to check if the incoming needle exists in. This can be a string or array - * @needle.hint The substring to find in a string or the value to find in an array - * @message.hint The message to send in the failure + * @target The target object to check if the incoming needle exists in. This can be a string or array + * @needle The substring to find in a string or the value to find in an array + * @message The message to send in the failure */ function notIncludes( required any target, required any needle, message="" ){ arguments.message = ( len( arguments.message ) ? arguments.message : "The needle [#arguments.needle#] was found in [#arguments.target.toString()#]" ); @@ -571,9 +571,9 @@ component{ /** * Assert that the actual value is greater than the target value - * @actual.hint The actual value - * @target.hint The target value - * @message.hint The message to send in the failure + * @actual The actual value + * @target The target value + * @message The message to send in the failure */ function isGT( required any actual, required any target, message="" ){ arguments.message = ( len( arguments.message ) ? arguments.message : "The actual [#arguments.actual#] is not greater than [#arguments.target#]" ); @@ -587,9 +587,9 @@ component{ /** * Assert that the actual value is greater than or equal the target value - * @actual.hint The actual value - * @target.hint The target value - * @message.hint The message to send in the failure + * @actual The actual value + * @target The target value + * @message The message to send in the failure */ function isGTE( required any actual, required any target, message="" ){ arguments.message = ( len( arguments.message ) ? arguments.message : "The actual [#arguments.actual#] is not greater than or equal to [#arguments.target#]" ); @@ -603,9 +603,9 @@ component{ /** * Assert that the actual value is less than the target value - * @actual.hint The actual value - * @target.hint The target value - * @message.hint The message to send in the failure + * @actual The actual value + * @target The target value + * @message The message to send in the failure */ function isLT( required any actual, required any target, message="" ){ arguments.message = ( len( arguments.message ) ? arguments.message : "The actual [#arguments.actual#] is not less than [#arguments.target#]" ); @@ -619,9 +619,9 @@ component{ /** * Assert that the actual value is less than or equal the target value - * @actual.hint The actual value - * @target.hint The target value - * @message.hint The message to send in the failure + * @actual The actual value + * @target The target value + * @message The message to send in the failure */ function isLTE( required any actual, required any target, message="" ){ arguments.message = ( len( arguments.message ) ? arguments.message : "The actual [#arguments.actual#] is not less than or equal to [#arguments.target#]" ); @@ -652,8 +652,8 @@ component{ /** * Assert something is JSON - * @actual.hint The actual data to test - * @message.hint The message to send in the failure + * @actual The actual data to test + * @message The message to send in the failure */ function isJSON( required any actual, message="" ){ arguments.message = ( len( arguments.message ) ? arguments.message : "Expected [#arguments.actual#] to be json" ); diff --git a/system/BaseSpec.cfc b/system/BaseSpec.cfc index e13ba30c..3a66e151 100644 --- a/system/BaseSpec.cfc +++ b/system/BaseSpec.cfc @@ -559,8 +559,7 @@ component{ * @actual The actual value, it should be an array or a struct. */ CollectionExpectation function expectAll( required any actual ){ - var cExpectation = new CollectionExpectation( spec=this, assertions=this.$assert, collection=arguments.actual ); - return cExpectation; + return new CollectionExpectation( spec=this, assertions=this.$assert, collection=arguments.actual ); } /** @@ -980,7 +979,7 @@ component{ // Execute Spec try{ - evaluate( "this.#arguments.spec.name#()" ); + invoke( this, arguments.spec.name ); // Where we expecting an exception and it did not throw? if( hasExpectedException( arguments.spec.name, arguments.runner ) ){ diff --git a/system/CollectionExpectation.cfc b/system/CollectionExpectation.cfc index b8015af3..bf0e8a16 100644 --- a/system/CollectionExpectation.cfc +++ b/system/CollectionExpectation.cfc @@ -14,21 +14,31 @@ component accessors="true"{ // The assertions reference property name="assert"; + /** + * Constructor + * + * @spec The target spec + * @assertions The assertions library + * @collection The collection target + */ function init( required spec, required any assertions, required collection ){ variables.actual = arguments.collection; variables.spec = arguments.spec; - variables.assert = arguments.assertions; + variables.assert = arguments.assertions; + + return this; } function onMissingMethod( string missingMethodName, any missingMethodArguments ){ if( isArray( variables.actual ) ){ for( var e in variables.actual ){ - evaluate( "variables.spec.expect( e ).#missingMethodName#( argumentCollection=missingMethodArguments )" ); + // Using evaluate since invoke looses track of positiona argument collections + evaluate( "variables.spec.expect( e ).#arguments.missingMethodName#( argumentCollection=arguments.missingMethodArguments )" ); } } else if( isStruct( variables.actual ) ){ for( var k in variables.actual ){ var e = variables.actual[ k ]; - evaluate( "variables.spec.expect( e ).#missingMethodName#( argumentCollection=missingMethodArguments )" ); + evaluate( "variables.spec.expect( e ).#arguments.missingMethodName#( argumentCollection=arguments.missingMethodArguments )" ); } } else { variables.assert.fail( "expectAll() actual is neither array nor struct" ); diff --git a/system/Expectation.cfc b/system/Expectation.cfc index cd3b90ed..3b2e8556 100644 --- a/system/Expectation.cfc +++ b/system/Expectation.cfc @@ -28,7 +28,7 @@ component accessors="true"{ * @assertions The TestBox assertions object: testbox.system.Assertion * @mockbox A reference to MockBox */ - function init( + function init( required any spec, required any assertions, required any mockBox @@ -56,7 +56,7 @@ component accessors="true"{ return( !results ? variables.assert.fail( this.message ) : this ); }; } - + /** * Fail an assertion * @message The message to fail with. @@ -69,7 +69,7 @@ component accessors="true"{ * Process dynamic expectations like any matcher starting with the word "not" is negated */ function onMissingMethod( required missingMethodName, required missingMethodArguments ){ - + // detect negation if( left( arguments.missingMethodName, 3 ) eq "not" ){ // remove NOT @@ -90,8 +90,10 @@ component accessors="true"{ } // execute the dynamic method - var results = evaluate( "#arguments.missingMethodName#( argumentCollection=arguments.missingMethodArguments )" ); - if( !isNull( results ) ){ return results; } + var results = invoke( this, arguments.missingMethodName, arguments.missingMethodArguments ); + if( !isNull( results ) ){ + return results; + } // throw exception //throw(type="InvalidMethod", message="The dynamic/static method: #arguments.missingMethodName# does not exist in this CFC", detail="Available methods are #structKeyArray( this ).toString()#"); @@ -104,7 +106,7 @@ component accessors="true"{ this.isNot = true; return this; } - + /** * Assert something is true * @actual The actual data to test @@ -135,7 +137,7 @@ component accessors="true"{ } return this; } - + /** * Assert something is equal to each other, no case is required * @expected The expected data @@ -157,9 +159,9 @@ component accessors="true"{ return this; } - + /** - * Assert strings are equal to each other with case. + * Assert strings are equal to each other with case. * @expected The expected data * @message The message to send in the failure */ @@ -180,13 +182,13 @@ component accessors="true"{ function toBeNull( message="" ){ if( this.isNot ){ if( !isNull( this.actual ) ){ return this; } - arguments.message = ( len( arguments.message ) ? + arguments.message = ( len( arguments.message ) ? arguments.message : "Expected the actual value to be NOT null but it was null" ); } else { if( isNull( this.actual ) ){ return this; } - arguments.message = ( len( arguments.message ) ? + arguments.message = ( len( arguments.message ) ? arguments.message : "Expected a null value but got [#variables.assert.getStringName( this.actual )#] instead" ); - + } variables.assert.fail( arguments.message ); } @@ -443,7 +445,7 @@ component accessors="true"{ arguments.message = ( len( arguments.message ) ? arguments.message : "The actual [#this.actual#] is not less than [#arguments.target#]" ); if( this.isNot ){ variables.assert.isGTE( this.actual, arguments.target, arguments.message ); - } else { + } else { variables.assert.isLT( this.actual, arguments.target, arguments.message ); } return this; @@ -474,7 +476,7 @@ component accessors="true"{ if( isJSON( this.actual ) ){ fail( arguments.message ); } - } else { + } else { variables.assert.isJSON( this.actual, arguments.message ); } return this; @@ -487,9 +489,9 @@ component accessors="true"{ */ function toSatisfy( required any target, message="" ){ arguments.message = ( len( arguments.message ) ? arguments.message : "The actual [#this.actual#] does not pass the truth test" ); - + var isPassed = arguments.target( this.actual ); - if( this.isNot ){ + if( this.isNot ){ isPassed = !isPassed; } if( !isPassed ){ diff --git a/system/runners/BDDRunner.cfc b/system/runners/BDDRunner.cfc index c701c629..ef47da4a 100644 --- a/system/runners/BDDRunner.cfc +++ b/system/runners/BDDRunner.cfc @@ -65,13 +65,11 @@ component extends="testbox.system.runners.BaseRunner" implements="testbox.system ); for ( var beforeAllMethod in beforeAllAnnotationMethods ){ - // We use evalute here for two reasons: - // 1. We want the scopes to be the target class, not this one. - // 2. We want this code to be cross-platform ( hence no cfinvoke() ) - Evaluate( "arguments.target.#beforeAllMethod.name#()" ); + invoke( arguments.target, "#beforeAllMethod.name#" ); } // Iterate over found test suites and test them, if nested suites, then this will recurse as well. + //writeDump( var=testSuites );abort; for( var thisSuite in testSuites ){ // verify call backs if( structKeyExists( arguments.callbacks, "onSuiteStart" ) ){ @@ -105,10 +103,7 @@ component extends="testbox.system.runners.BaseRunner" implements="testbox.system ); for ( var afterAllMethod in afterAllAnnotationMethods ){ - // We use evalute here for two reasons: - // 1. We want the scopes to be the target class, not this one. - // 2. We want this code to be cross-platform ( hence no cfinvoke() ) - Evaluate( "arguments.target.#afterAllMethod.name#()" ); + invoke( arguments.target, "#afterAllMethod.name#" ); } } catch( Any e ) { diff --git a/system/runners/UnitRunner.cfc b/system/runners/UnitRunner.cfc index 4484ac26..ea1e89c9 100644 --- a/system/runners/UnitRunner.cfc +++ b/system/runners/UnitRunner.cfc @@ -60,10 +60,7 @@ component extends="testbox.system.runners.BaseRunner" implements="testbox.system ); for ( var beforeAllMethod in beforeAllAnnotationMethods ){ - // We use evalute here for two reasons: - // 1. We want the scopes to be the target class, not this one. - // 2. We want this code to be cross-platform ( hence no cfinvoke() ) - Evaluate( "arguments.target.#beforeAllMethod.name#()" ); + invoke( arguments.target, "#beforeAllMethod.name#" ); } if( structKeyExists( arguments.target, "beforeTests" ) ){ arguments.target.beforeTests(); } @@ -100,10 +97,7 @@ component extends="testbox.system.runners.BaseRunner" implements="testbox.system ); for ( var afterAllMethod in afterAllAnnotationMethods ){ - // We use evalute here for two reasons: - // 1. We want the scopes to be the target class, not this one. - // 2. We want this code to be cross-platform ( hence no cfinvoke() ) - Evaluate( "arguments.target.#afterAllMethod.name#()" ); + invoke( arguments.target, "#afterAllMethod.name#" ); } if( structKeyExists( arguments.target, "afterTests" ) ){ arguments.target.afterTests(); } @@ -274,7 +268,7 @@ component extends="testbox.system.runners.BaseRunner" implements="testbox.system // skip constraint for suite? if( !isBoolean( suite.skip ) && isCustomFunction( arguments.target[ suite.skip ] ) ){ - suite.skip = evaluate( "arguments.target.#suite.skip#()" ); + suite.skip = invoke( arguments.target, "#suite.skip#" ); } // check them. @@ -314,7 +308,7 @@ component extends="testbox.system.runners.BaseRunner" implements="testbox.system // skip constraint? if( !isBoolean( spec.skip ) && isCustomFunction( arguments.target[ spec.skip ] ) ){ - spec.skip = evaluate( "arguments.target.#spec.skip#()" ); + spec.skip = invoke( arguments.target, "#spec.skip#" ); } // do we have labels applied? diff --git a/system/util/XMLConverter.cfc b/system/util/XMLConverter.cfc index c59dc1de..a86967f3 100644 --- a/system/util/XMLConverter.cfc +++ b/system/util/XMLConverter.cfc @@ -256,7 +256,7 @@ Modifications OR md.properties[x]["marshal"] EQ true ){ thisName = md.properties[x].name; - thisValue = evaluate("target.get#thisName#()"); + thisValue = invoke( target, "get#thisName#" ); // Value Defined? if( not isDefined("thisValue") ){ diff --git a/tests/specs/BDDTest.cfc b/tests/specs/BDDTest.cfc index dedc4441..f155537e 100644 --- a/tests/specs/BDDTest.cfc +++ b/tests/specs/BDDTest.cfc @@ -133,8 +133,8 @@ component extends="testbox.system.BaseSpec"{ }); it( "can test a collection", function(){ - expectAll( [ 2, 4, 6, 8] ).toSatisfy( function(x){ return 0 == x%2; }); - expectAll( { a:2, b:4, c:6} ).toSatisfy( function(x){ return 0 == x%2; }); + expectAll( [ 2, 4, 6, 8] ).toSatisfy( function(x){ return 0 == x%2; } ); + expectAll( { a:2, b:4, c:6} ).toSatisfy( function(x){ return 0 == x%2; } ); // and we can chain matchers expectAll( [ 2, 4, 6, 8 ] ) .toBeGTE( 2 ) diff --git a/tests/specs/NestedDescribeTest.cfc b/tests/specs/NestedDescribeTest.cfc index 4068475f..d216ddfa 100644 --- a/tests/specs/NestedDescribeTest.cfc +++ b/tests/specs/NestedDescribeTest.cfc @@ -2,7 +2,7 @@ * My BDD Test */ component extends="testbox.system.BaseSpec"{ - + /*********************************** LIFE CYCLE Methods ***********************************/ // executes before all suites+specs in the run() method @@ -17,12 +17,39 @@ component extends="testbox.system.BaseSpec"{ function run(){ describe( "Outer describe", function(){ - describe( "Inner describe", function(){ - it( "Tests are ONLY in inner it()", function(){ + + describe( "Inner describe", function(){ + it( "Tests are ONLY in inner it()", function(){ expect( true ).toBe( true ); }); }); + + + story( "I want pricing details", function(){ + var sailingsData = [ + { name="AmaWaterways", Cruise_ID="749053", CrzCode="AM", API_Sail_ID="13732", API_Length=7, API_Port_Count=7, API_Sail_Date="10/08/2019" }, + { name="Avalon", Cruise_ID="767012", CrzCode="AV", API_Sail_ID="WDB091010APS", API_Length=7, API_Port_Count=9, API_Sail_Date="10/10/2019" }, + { name="Azamara", Cruise_ID="721541", CrzCode="AZ", API_Sail_ID="JR01191027JR07M398", API_Length=7, API_Port_Count=7, API_Sail_Date="10/27/2019" }, + { name="Celebrity", Cruise_ID="708821", CrzCode="CB", API_Sail_ID="SL01190117SL14K095", API_Length=14, API_Port_Count=9, API_Sail_Date="01/17/2019" } + ].each( function( item ){ + + given( "[#item.name#] valid incoming arguments for a #item.name# sailing", function(){ + then( then="[#item.name#] I get a response with inErrorStatus=false", data=item, body=function( data ){ + + debug( "Starting to process #data.name#" ); + + sleep( randRange( 500, 2000 ) ); + + debug( "==>Finalized process #data.name#" ); + + }); + }); + + } ); + + }); + }); } - + } \ No newline at end of file From aa2c76e0a158588a078ca811d2bc186ba1c36f80 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 11 Apr 2018 15:44:38 -0500 Subject: [PATCH 05/10] TESTBOX-220 #resolve some speed improvements by not using createuuid anymore --- system/BaseSpec.cfc | 2 +- system/TestResult.cfc | 6 +++--- system/runners/BDDRunner.cfc | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/system/BaseSpec.cfc b/system/BaseSpec.cfc index 3a66e151..f4b763bc 100644 --- a/system/BaseSpec.cfc +++ b/system/BaseSpec.cfc @@ -28,7 +28,7 @@ component{ // Expected Exception holder, only use on synchronous testing. this.$expectedException = {}; // Internal testing ID - this.$testID = createUUID(); + this.$testID = hash( getTickCount() + randRange( 1, 10000000 ) ); // Debug buffer this.$debugBuffer = []; // Current Executing Spec diff --git a/system/TestResult.cfc b/system/TestResult.cfc index e25a9b74..4a19d706 100644 --- a/system/TestResult.cfc +++ b/system/TestResult.cfc @@ -150,7 +150,7 @@ component accessors="true"{ // setup stats data for incoming bundle var stats = { // bundle id - "id" = createUUID(), + "id" = hash( getTickCount() + randRange( 1, 10000000 ) ), // The bundle name "name" = arguments.name, // Path of the bundle @@ -241,7 +241,7 @@ component accessors="true"{ // setup stats data for incoming suite var stats = { // suite id - "id" = createUUID(), + "id" = hash( getTickCount() + randRange( 1, 10000000 ) ), // parent suite id "parentID" = "", // bundle id @@ -313,7 +313,7 @@ component accessors="true"{ // spec stats var stats = { // suite id - "id" = createUUID(), + "id" = hash( getTickCount() + randRange( 1, 10000000 ) ), // suite id "suiteID" = arguments.suiteStats.id, // name of the spec diff --git a/system/runners/BDDRunner.cfc b/system/runners/BDDRunner.cfc index ef47da4a..f3516667 100644 --- a/system/runners/BDDRunner.cfc +++ b/system/runners/BDDRunner.cfc @@ -177,7 +177,7 @@ component extends="testbox.system.runners.BaseRunner" implements="testbox.system // is this async or not? if( arguments.suite.asyncAll ){ // prepare thread name - var thisThreadName = variables.testBox.getUtility().slugify( "tb-" & thisSpec.name & "-#createUUID()#" ); + var thisThreadName = variables.testBox.getUtility().slugify( "tb-" & thisSpec.name & "-#hash( getTickCount() + randRange( 1, 10000000 ) )#" ); // append to used thread names arrayAppend( threadNames, thisThreadName ); // thread it From 9fcda489a03a78f563958ee36fda5006c2cce4ac Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 11 Apr 2018 15:45:22 -0500 Subject: [PATCH 06/10] TESTBOX-220 some speed improvements by not using createuuid anymore --- system/runners/UnitRunner.cfc | 2 +- tests/specs/NestedDescribeTest.cfc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system/runners/UnitRunner.cfc b/system/runners/UnitRunner.cfc index ea1e89c9..7c61394d 100644 --- a/system/runners/UnitRunner.cfc +++ b/system/runners/UnitRunner.cfc @@ -163,7 +163,7 @@ component extends="testbox.system.runners.BaseRunner" implements="testbox.system // is this async or not? if( arguments.suite.asyncAll ){ // prepare thread name - var thisThreadName = variables.testBox.getUtility().slugify( "tb-" & thisSpec.name & "-#createUUID()#" ); + var thisThreadName = variables.testBox.getUtility().slugify( "tb-" & thisSpec.name & "-#hash( getTickCount() + randRange( 1, 10000000 ) )#" ); // append to used thread names arrayAppend( threadNames, thisThreadName ); // thread it diff --git a/tests/specs/NestedDescribeTest.cfc b/tests/specs/NestedDescribeTest.cfc index d216ddfa..72ac7b02 100644 --- a/tests/specs/NestedDescribeTest.cfc +++ b/tests/specs/NestedDescribeTest.cfc @@ -40,7 +40,7 @@ component extends="testbox.system.BaseSpec"{ sleep( randRange( 500, 2000 ) ); - debug( "==>Finalized process #data.name#" ); + debug( "==> Finalized process #data.name#" ); }); }); From dd88b0741acd250367122d23e367019d704dc897 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Fri, 13 Apr 2018 10:27:25 -0500 Subject: [PATCH 07/10] TESTBOX-221 #resolve Complete refactoring of around,before,after each executions to support concurrency --- system/BaseSpec.cfc | 120 ++++++++++---------- system/runners/BDDRunner.cfc | 3 +- system/util/Util.cfc | 26 ++--- tests/specs/BDDLifecycleAnnotationsTest.cfc | 1 + tests/specs/BDDLifecycleTest.cfc | 10 +- tests/specs/NestedDescribeTest.cfc | 4 +- 6 files changed, 86 insertions(+), 78 deletions(-) diff --git a/system/BaseSpec.cfc b/system/BaseSpec.cfc index f4b763bc..cb6cf2fc 100644 --- a/system/BaseSpec.cfc +++ b/system/BaseSpec.cfc @@ -759,29 +759,29 @@ component{ parentSuite = parentSuite.parentRef; } - var annotationMethods = this.$utility.getAnnotatedMethods( + // Incorporate annotated methods + this.$utility.getAnnotatedMethods( annotation = "beforeEach", metadata = getMetadata( this ) - ); - - for( var method in annotationMethods ){ - arrayAppend( reverseTree, { - beforeEach = this[ method.name ], + ).each( function( item ){ + reverseTree.append( { + beforeEach = this[ arguments.item.name ], beforeEachData = {} } ); - } - - // Execute reverse tree - var treeLen = arrayLen( reverseTree ); - if( treeLen gt 0 ){ - for( var x=treeLen; x gte 1; x-- ){ - var thisContext = reverseTree[ x ]; - thisContext.beforeEach( - currentSpec = arguments.spec.name, - data = thisContext.beforeEachData - ); - } - } + } ); + + // sort tree backwards + reverseTree.sort( function( a, b ){ + return -1; + } ); + + // Execute it + reverseTree.each( function( item ){ + item.beforeEach( + currentSpec = spec.name, + data = item.beforeEachData + ); + }); // execute beforeEach() arguments.suite.beforeEach( @@ -812,50 +812,49 @@ component{ // do we have nested suites? If so, traverse the tree to build reverse execution map var parentSuite = arguments.suite.parentRef; while( !isSimpleValue( parentSuite ) ){ - arrayAppend( reverseTree, { + reverseTree.append( { name = parentSuite.name, body = parentSuite.aroundEach, data = parentSuite.aroundEachData, labels = parentSuite.labels, order = 0, skip = parentSuite.skip - } ); + } ); // go deep parentSuite = parentSuite.parentRef; } - var annotationMethods = this.$utility.getAnnotatedMethods( + annotatedMethods = this.$utility.getAnnotatedMethods( annotation = "aroundEach", metadata = getMetadata( this ) ); - for( var method in annotationMethods ){ - arrayAppend( reverseTree, { - name = method.name, - body = this[ method.name ], + // Discover annotated methods and add to reverseTree + this.$utility.getAnnotatedMethods( + annotation = "aroundEach", + metadata = getMetadata( this ) + ).each( function( item ){ + reverseTree.append( { + name = arguments.item.name, + body = this[ arguments.item.name ], data = {}, labels = {}, order = 0, skip = false } ); - } + } ); // Sort the closures from the oldest parent down to the current spec - var correctOrderTree = []; - var treeLen = arrayLen( reverseTree ); - if( treeLen gt 0 ){ - for( var x = treeLen; x gte 1; x-- ){ - arrayAppend( correctOrderTree, reverseTree[ x ] ); - } - } + reverseTree.sort( function( a, b ){ + return -1; + } ); // Build a function that will execute down the tree var specStack = generateAroundEachClosuresStack( - closures = correctOrderTree, + closures = reverseTree, suite = arguments.suite, spec = arguments.spec ); - // Run the specs specStack(); @@ -868,18 +867,17 @@ component{ * @suite The target suite * @spec The target spec */ - function generateAroundEachClosuresStack( array closures, required suite, required spec ) { + function generateAroundEachClosuresStack( array closures, required suite, required spec, closureIndex=1 ) { - thread.closures = arguments.closures; - thread.suite = arguments.suite; - thread.spec = arguments.spec; + thread.closures = arguments.closures; + thread.suite = arguments.suite; + thread.spec = arguments.spec; // Get closure data from stack and pop it - var nextClosure = thread.closures[ 1 ]; - arrayDeleteAt( thread.closures, 1 ); + var nextClosure = thread.closures[ closureIndex ]; // Check if we have more in the stack or empty - if( arrayLen( thread.closures ) == 0 ){ + if( thread.closures.len() == closureIndex ){ // Return the closure of execution for a single spec ONLY return function(){ // Execute the body of the spec @@ -888,23 +886,25 @@ component{ } // Get next Spec in stack - var nextSpecInfo = thread.closures[ 1 ]; + var nextSpecInfo = thread.closures[ ++closureIndex ]; // Return generated closure return function() { nextClosure.body( - { - name = nextSpecInfo.name, - body = generateAroundEachClosuresStack( + spec = { + name = nextSpecInfo.name, + body = generateAroundEachClosuresStack( thread.closures, thread.suite, - thread.spec + thread.spec, + closureIndex ), - data = nextSpecInfo.data, + data = nextSpecInfo.data, labels = nextSpecInfo.labels, - order = nextSpecInfo.order, - skip = nextSpecInfo.skip + order = nextSpecInfo.order, + skip = nextSpecInfo.skip }, - thread.suite + suite = thread.suite, + data = nextClosure.data ); }; } @@ -934,12 +934,16 @@ component{ var annotationMethods = this.$utility.getAnnotatedMethods( annotation = "afterEach", metadata = getMetadata( this ) - ); - - for( var method in annotationMethods ){ - var afterEachMethod = this[ method.name ]; - afterEachMethod( currentSpec = arguments.spec.name, data = {} ); - } + ).each( function( item ){ + invoke( + this, + item.name, + { + currentSpec = spec.name, + data = {} + } + ); + } ); return this; } diff --git a/system/runners/BDDRunner.cfc b/system/runners/BDDRunner.cfc index f3516667..f561cbd2 100644 --- a/system/runners/BDDRunner.cfc +++ b/system/runners/BDDRunner.cfc @@ -69,13 +69,11 @@ component extends="testbox.system.runners.BaseRunner" implements="testbox.system } // Iterate over found test suites and test them, if nested suites, then this will recurse as well. - //writeDump( var=testSuites );abort; for( var thisSuite in testSuites ){ // verify call backs if( structKeyExists( arguments.callbacks, "onSuiteStart" ) ){ arguments.callbacks.onSuiteStart( arguments.target, arguments.testResults, thisSuite ); } - // Test Suite testSuite( target=arguments.target, @@ -171,6 +169,7 @@ component extends="testbox.system.runners.BaseRunner" implements="testbox.system thread.testResults = arguments.testResults; thread.suiteStats = suiteStats; thread.target = arguments.target; + // iterate over suite specs and test them for( var thisSpec in arguments.suite.specs ){ diff --git a/system/util/Util.cfc b/system/util/Util.cfc index e09722b3..568167a2 100644 --- a/system/util/Util.cfc +++ b/system/util/Util.cfc @@ -123,23 +123,23 @@ component{ ) { var lifecycleMethods = []; - if( StructKeyExists( arguments.metadata, "functions" ) ){ - var funcs = arguments.metadata.functions; - for ( var func in funcs ){ - if ( StructKeyExists( func, annotation ) ){ - ArrayAppend( lifecycleMethods, func ); + if( structKeyExists( arguments.metadata, "functions" ) ){ + + for( var thisFunction in arguments.metadata.functions ){ + if( structKeyExists( thisFunction, annotation ) ){ + lifecycleMethods.append( thisFunction ); } } + } - if( StructKeyExists( arguments.metadata, "extends" ) ){ - // recursively call up the inheritance chain - lifecycleMethods.addAll( - getAnnotatedMethods( - arguments.annotation, - arguments.metadata.extends - ) - ); + if( structKeyExists( arguments.metadata, "extends" ) ){ + getAnnotatedMethods( + arguments.annotation, + arguments.metadata.extends + ).each( function( item ){ + lifecycleMethods.append( arguments.item ); + } ); } return lifecycleMethods; diff --git a/tests/specs/BDDLifecycleAnnotationsTest.cfc b/tests/specs/BDDLifecycleAnnotationsTest.cfc index 01a4bc7d..6a649c52 100644 --- a/tests/specs/BDDLifecycleAnnotationsTest.cfc +++ b/tests/specs/BDDLifecycleAnnotationsTest.cfc @@ -7,6 +7,7 @@ component extends="tests.utils.ExampleParentTestCase"{ function beforeAll(){ variables.counter = 0; + // After annotated class this should be 1 } function afterAll(){ diff --git a/tests/specs/BDDLifecycleTest.cfc b/tests/specs/BDDLifecycleTest.cfc index 465eba09..5888ad13 100644 --- a/tests/specs/BDDLifecycleTest.cfc +++ b/tests/specs/BDDLifecycleTest.cfc @@ -22,16 +22,17 @@ component extends="testbox.system.BaseSpec"{ // before each spec in THIS suite group beforeEach(function( currentSpec ){ coldbox++; - debug( "beforeEach #arguments.currentSpec#: coldbox = #coldbox#" ); + debug( "beforeEach (A Suite) #arguments.currentSpec#" ); }); // after each spec in THIS suite group afterEach(function( currentSpec ){ - debug( "afterEach #arguments.currentSpec#: coldbox = #coldbox#" ); + debug( "afterEach (A Suite) #arguments.currentSpec#: coldbox = #coldbox#" ); }); // around each spec in THIS suite group aroundEach(function( spec ){ + debug( "aroundEach (A Suite) #arguments.spec.name#" ); // execute the spec manually now, we can decorate things here too. spec.body(); }); @@ -45,11 +46,12 @@ component extends="testbox.system.BaseSpec"{ // before each spec in THIS suite group beforeEach(function( currentSpec ){ coldbox = coldbox * 2; - debug( "beforeEach #arguments.currentSpec#: coldbox = #coldbox#" ); + debug( "beforeEach (A nested suite) #arguments.currentSpec#: coldbox = #coldbox#" ); }); // around each spec in THIS suite group aroundEach(function( spec ){ + debug( "aroundEach (A nested suite) #arguments.spec.name#" ); // execute the spec manually now, we can decorate things here too. spec.body(); }); @@ -62,7 +64,7 @@ component extends="testbox.system.BaseSpec"{ // before each spec in THIS suite group beforeEach(function( currentSpec ){ coldbox++; - debug( "beforeEach #arguments.currentSpec#: coldbox = #coldbox#" ); + debug( "beforeEach (Another nested suite) #arguments.currentSpec#: coldbox = #coldbox#" ); }); it( "before should be 11", function(){ diff --git a/tests/specs/NestedDescribeTest.cfc b/tests/specs/NestedDescribeTest.cfc index 72ac7b02..72336406 100644 --- a/tests/specs/NestedDescribeTest.cfc +++ b/tests/specs/NestedDescribeTest.cfc @@ -31,7 +31,9 @@ component extends="testbox.system.BaseSpec"{ { name="Avalon", Cruise_ID="767012", CrzCode="AV", API_Sail_ID="WDB091010APS", API_Length=7, API_Port_Count=9, API_Sail_Date="10/10/2019" }, { name="Azamara", Cruise_ID="721541", CrzCode="AZ", API_Sail_ID="JR01191027JR07M398", API_Length=7, API_Port_Count=7, API_Sail_Date="10/27/2019" }, { name="Celebrity", Cruise_ID="708821", CrzCode="CB", API_Sail_ID="SL01190117SL14K095", API_Length=14, API_Port_Count=9, API_Sail_Date="01/17/2019" } - ].each( function( item ){ + ]; + + sailingsData.each( function( item ){ given( "[#item.name#] valid incoming arguments for a #item.name# sailing", function(){ then( then="[#item.name#] I get a response with inErrorStatus=false", data=item, body=function( data ){ From 989ea71bddccadf6a70a5d4f53c9897e7def1363 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Fri, 20 Apr 2018 14:07:50 -0500 Subject: [PATCH 08/10] TESTBOX-222 #resolve Heap issues and stack overflow issues when normalizing ORM entities in mocking arguments --- system/MockBox.cfc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/system/MockBox.cfc b/system/MockBox.cfc index 3eebca71..82296f29 100644 --- a/system/MockBox.cfc +++ b/system/MockBox.cfc @@ -298,17 +298,17 @@ Description : if( len( this._mockCurrentMethod ) ){ var args = arguments; - return this.$callback( function(){ + return this.$callback( function(){ throw( type = structKeyExists( args, "type" ) ? args.type : "", message = structKeyExists( args, "message" ) ? args.message : "", detail = structKeyExists( args, "detail" ) ? args.detail : "", errorCode = structKeyExists( args, "errorCode" ) ? args.errorCode : "0" - ); + ); } ); } - throw( + throw( type = "MockFactory.IllegalStateException", message = "No current method name set", detail = "This method was probably called without chaining it to a $() call. Ex: obj.$().$throws(), or obj.$('method').$args().$throws()" @@ -536,7 +536,7 @@ Description : } else if( isObject( argOrderedTree[ arg ] ) and isInstanceOf( argOrderedTree[ arg ], "Component" ) ){ // If an object and CFC, just use serializeJSON - serializedArgs &= serializeJSON( argOrderedTree[ arg ] ); + serializedArgs &= serializeJSON( getMetadata( argOrderedTree[ arg ] ) ); } else{ // Get obj rep From c0ea8ed1835ad6bb37cb5f18bc7cdea37f99bbcc Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Fri, 20 Apr 2018 14:10:44 -0500 Subject: [PATCH 09/10] updated readme fixes --- readme.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 4f8aa214..c940342e 100755 --- a/readme.md +++ b/readme.md @@ -12,29 +12,37 @@ TestBox is a Behavior Driven Development (BDD) and Test Driven Development (TDD) framework for ColdFusion (CFML). It also includes mocking and stubbing capabilities via its internal MockBox library. ## LICENSE + Apache License, Version 2.0. ## IMPORTANT LINKS + Source + - https://github.com/Ortus-Solutions/TestBox Bug Tracking + - https://ortussolutions.atlassian.net/browse/TESTBOX Support Forum + - https://groups.google.com/a/ortussolutions.com/forum/#!forum/testbox Documentation + - https://testbox.ortusbooks.com - https://testbox.ortusbooks.com/content/primers/bdd/index.html - https://testbox.ortusbooks.com/content/primers/xunit/index.html Official Site + - https://www.ortussolutions.com/products/testbox ## SYSTEM REQUIREMENTS + - Lucee 4.5+ (xUnit + BDD) -- ColdFusion 10+ (xUnit + BDD) +- ColdFusion 11+ (xUnit + BDD) ## TESTBOX INSTALLATION You can visit the TestBox documentation page to view all of its features and @@ -42,7 +50,7 @@ capabilities. To install TestBox just drop it in your web root as `/testbox` or create a mapping in your CFML administrator or `Application.cfc` that points to the directory you installed TestBox and create the mapping `/testbox` that points to it. -You can also use [CommandBox](http://www.ortussolutions.com/products/commandbox) to install and leverage TestBox for commandline executions, test generations, watchers and much more: +You can also use [CommandBox](https://www.ortussolutions.com/products/commandbox) to install and leverage TestBox for commandline executions, test generations, watchers and much more: **Stable Release** From cb943332c60f482b383598db1a3f3a900c3fb66c Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Fri, 20 Apr 2018 14:14:31 -0500 Subject: [PATCH 10/10] more debugging and also only publish on one engine. --- .travis.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7272a110..2dc8b651 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,14 +29,12 @@ before_install: install: # Install Commandbox - sudo apt-get update && sudo apt-get --assume-yes install jq commandbox ant-optional - # Test that the box binary is available and ready for our tests - - box version + # Install dependencies + - box install && box install commandbox-cfconfig,commandbox-dotenv # If using auto-publish, you will need to provide your API token with this line: - box config set endpoints.forgebox.APIToken=$FORGEBOX_API_TOKEN > /dev/null script: - # run our dependency install to ensure the workbench is in place - - box install # Execute build via ANT - ant -DisTravis=true -Dcfengine=$ENGINE -Dbuild.number=$TRAVIS_BUILD_NUMBER -Dbuild.branch=$TRAVIS_BRANCH -f build/build.xml # Set Current Version @@ -45,10 +43,13 @@ script: after_failure: - cd $TRAVIS_BUILD_DIR + # Get response from test server to see what went wrong + - curl http://localhost:49616/tests/runner.cfm?reporter=text # Display the contents of our root directory # Spit out our Commandbox log in case we need to debug - box server log name=$ENGINE - cat `box system-log` + - ls -l $TRAVIS_BUILD_DIR/apidocs deploy: # Binary Deployments @@ -84,4 +85,5 @@ deploy: acl: public_read after_deploy: - - cd $TRAVIS_BUILD_DIR/build-testbox/testbox && box forgebox publish \ No newline at end of file + - cd $TRAVIS_BUILD_DIR/build-testbox/testbox + - if [ ${ENGINE} = 'lucee@4.5' ]; then box forgebox publish; fi \ No newline at end of file