Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,18 @@ jobs:
cfengine: [ "boxlang@1", "boxlang-cfml@1", "lucee@6", "lucee@7", "adobe@2023", "adobe@2025" ]
jdkVersion: [ "21" ]
experimental: [ false ]
fullNull: [ false ]
include:
- cfengine: "boxlang@be"
commandbox_version: "6.3.1"
jdkVersion: "21"
experimental: true
fullNull: false
- cfengine: "adobe@2023"
commandbox_version: "6.3.1"
jdkVersion: "21"
experimental: false
fullNull: true
steps:
- name: Checkout Repository
uses: actions/checkout@v7
Expand All @@ -48,10 +55,14 @@ jobs:
box install --production

- name: Start ${{ matrix.cfengine }}/${{ matrix.jdkVersion }} Server
env:
FULL_NULL: ${{ matrix.fullNull }}
run: |
box server start serverConfigFile="server-${{ matrix.cfengine }}.json" --noSaveSettings --debug

- name: Run Tests
env:
FULL_NULL: ${{ matrix.fullNull }}
run: |
box task run taskfile=build/Build target=runTests

Expand All @@ -60,13 +71,13 @@ jobs:
if: always()
with:
junit_files: tests/results/**/*.xml
check_name: "${{ matrix.cfengine }} ${{ matrix.jdkVersion }} Test Results"
check_name: "${{ matrix.cfengine }} ${{ matrix.jdkVersion }} fullNull=${{ matrix.fullNull }} Test Results"

- name: Upload Test Results Artifacts
if: always()
uses: actions/upload-artifact@v7
with:
name: testbox-test-results-${{ matrix.cfengine }}-${{ matrix.jdkVersion }}
name: testbox-test-results-${{ matrix.cfengine }}-${{ matrix.jdkVersion }}-${{ matrix.fullNull }}
path: |
tests/results/**/*

Expand All @@ -79,7 +90,7 @@ jobs:
if: ${{ failure() }}
uses: actions/upload-artifact@v7
with:
name: Failure Debugging Info - ${{ matrix.cfengine }} - ${{ matrix.jdkVersion }}
name: Failure Debugging Info - ${{ matrix.cfengine }} - ${{ matrix.jdkVersion }} - ${{ matrix.fullNull }}
path: |
.engine/**/logs/*
.engine/**/WEB-INF/cfusion/logs/*
Expand Down
8 changes: 4 additions & 4 deletions system/BaseSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -1691,7 +1691,7 @@ component {
*/
function getCBMockData(){
// Lazy Load it
if ( isNull( variables.$cbMockData ) ) {
if ( !structKeyExists( variables, "$cbMockData" ) || isNull( variables.$cbMockData ) ) {
variables.$cbMockData = new testbox.system.modules.cbMockData.models.MockData();
}
return variables.$cbMockData;
Expand All @@ -1704,7 +1704,7 @@ component {
*/
function getUtility(){
// Lazy Load it
if ( isNull( variables.$utility ) ) {
if ( !structKeyExists( variables, "$utility" ) || isNull( variables.$utility ) ) {
variables.$utility = new testbox.system.util.Util();
}
return variables.$utility;
Expand All @@ -1717,7 +1717,7 @@ component {
*/
function getEnv(){
// Lazy Load it
if ( isNull( variables.$env ) ) {
if ( !structKeyExists( variables, "$env" ) || isNull( variables.$env ) ) {
variables.$env = new testbox.system.util.Env();
}
return variables.$env;
Expand All @@ -1732,7 +1732,7 @@ component {
*/
function getMockBox( string generationPath = "" ){
// Lazy Load it
if ( isNull( this.$mockbox ) ) {
if ( !structKeyExists( this, "$mockbox" ) || isNull( this.$mockbox ) ) {
variables.$mockbox = this.$mockbox = new testbox.system.MockBox( arguments.generationPath );
} else {
// Generation path updates
Expand Down
18 changes: 9 additions & 9 deletions system/TestBox.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ component accessors="true" {
*/
function getEnv(){
// Lazy Load it
if ( isNull( variables.env ) ) {
if ( !structKeyExists( variables, "env" ) || isNull( variables.env ) ) {
variables.env = new testbox.system.util.Env();
}
return variables.env;
Expand Down Expand Up @@ -405,16 +405,16 @@ component accessors="true" {
);

// Verify URL conventions for bundle, suites and specs exclusions.
if ( !isNull( url.testBundles ) ) {
if ( structKeyExists( url, "testBundles" ) && !isNull( url.testBundles ) ) {
testBundles.append( listToArray( urlDecode( url.testBundles ) ), true );
}
if ( !isNull( url.testSuites ) ) {
if ( structKeyExists( url, "testSuites" ) && !isNull( url.testSuites ) ) {
arguments.testSuites.append( listToArray( urlDecode( url.testSuites ) ), true );
}
if ( !isNull( url.testSpecs ) ) {
if ( structKeyExists( url, "testSpecs" ) && !isNull( url.testSpecs ) ) {
arguments.testSpecs.append( listToArray( urlDecode( url.testSpecs ) ), true );
}
if ( !isNull( url.testMethod ) ) {
if ( structKeyExists( url, "testMethod" ) && !isNull( url.testMethod ) ) {
arguments.testSpecs.append( listToArray( urlDecode( url.testMethod ) ), true );
}

Expand Down Expand Up @@ -524,16 +524,16 @@ component accessors="true" {
isSimpleValue( arguments.testSpecs ) ? listToArray( arguments.testSpecs ) : arguments.testSpecs
);

if ( !isNull( url.testBundles ) ) {
if ( structKeyExists( url, "testBundles" ) && !isNull( url.testBundles ) ) {
arguments.testBundles.append( listToArray( urlDecode( url.testBundles ) ), true );
}
if ( !isNull( url.testSuites ) ) {
if ( structKeyExists( url, "testSuites" ) && !isNull( url.testSuites ) ) {
arguments.testSuites.append( listToArray( urlDecode( url.testSuites ) ), true );
}
if ( !isNull( url.testSpecs ) ) {
if ( structKeyExists( url, "testSpecs" ) && !isNull( url.testSpecs ) ) {
arguments.testSpecs.append( listToArray( urlDecode( url.testSpecs ) ), true );
}
if ( !isNull( url.testMethod ) ) {
if ( structKeyExists( url, "testMethod" ) && !isNull( url.testMethod ) ) {
arguments.testSpecs.append( listToArray( urlDecode( url.testMethod ) ), true );
}

Expand Down
4 changes: 2 additions & 2 deletions system/coverage/CoverageReporter.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,10 @@ component accessors="true" {
* @opts The options to validate and extend/default.
*/
private struct function setDefaultOptions( struct opts = {} ){
if ( isNull( opts.outputDir ) ) {
if ( !structKeyExists( opts, "outputDir" ) || isNull( opts.outputDir ) ) {
opts.outputDir = "";
}
if ( isNull( opts.isBatched ) ) {
if ( !structKeyExists( opts, "isBatched" ) || isNull( opts.isBatched ) ) {
opts.isBatched = false;
}
return opts;
Expand Down
29 changes: 15 additions & 14 deletions system/coverage/CoverageService.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -136,21 +136,21 @@ component accessors="true" {
* @opts The options to default and check
*/
private function setDefaultOptions( struct opts = {} ){
if ( isNull( opts.enabled ) ) {
if ( !structKeyExists( opts, "enabled" ) || isNull( opts.enabled ) ) {
opts.enabled = true;
}

if ( isNull( opts.sonarQube ) ) {
if ( !structKeyExists( opts, "sonarQube" ) || isNull( opts.sonarQube ) ) {
opts.sonarQube = {};
}
if ( isNull( opts.sonarQube.XMLOutputPath ) ) {
if ( !structKeyExists( opts.sonarQube, "XMLOutputPath" ) || isNull( opts.sonarQube.XMLOutputPath ) ) {
opts.sonarQube.XMLOutputPath = "";
}

if ( isNull( opts.browser ) ) {
if ( !structKeyExists( opts, "browser" ) || isNull( opts.browser ) ) {
opts.browser = {};
}
if ( isNull( opts.browser.outputDir ) ) {
if ( !structKeyExists( opts.browser, "outputDir" ) || isNull( opts.browser.outputDir ) ) {
opts.browser.outputDir = "";
}

Expand All @@ -172,34 +172,35 @@ component accessors="true" {
}
}

if ( isNull( opts.coverageTresholds ) ) {
if ( !structKeyExists( opts, "coverageTresholds" ) || isNull( opts.coverageTresholds ) ) {
opts.coverageTresholds = {};
}
if ( isNull( opts.coverageTresholds.good ) ) {
if ( !structKeyExists( opts.coverageTresholds, "good" ) || isNull( opts.coverageTresholds.good ) ) {
opts.coverageTresholds.good = 85;
}
if ( isNull( opts.coverageTresholds.bad ) ) {
if ( !structKeyExists( opts.coverageTresholds, "bad" ) || isNull( opts.coverageTresholds.bad ) ) {
opts.coverageTresholds.bad = 50;
}

if ( isNull( opts.pathToCapture ) ) {
if ( !structKeyExists( opts, "pathToCapture" ) || isNull( opts.pathToCapture ) ) {
opts.pathToCapture = "";
}
if ( isNull( opts.whitelist ) ) {
if ( !structKeyExists( opts, "whitelist" ) || isNull( opts.whitelist ) ) {
opts.whitelist = "";
}
if ( isNull( opts.blacklist ) ) {
if ( !structKeyExists( opts, "blacklist" ) || isNull( opts.blacklist ) ) {
opts.blacklist = "";
}
if ( isNull( opts.isBatched ) ) {
if ( !structKeyExists( opts, "isBatched" ) || isNull( opts.isBatched ) ) {
opts.isBatched = false;
}

// If no path provided to capture
if ( !len( opts.pathToCapture ) ) {
// Look for a /root mapping which is a common ColdBox convention
if ( !isNull( getApplicationMetadata().mappings ) ) {
var mappings = getApplicationMetadata().mappings;
var appMetadata = getApplicationMetadata();
if ( structKeyExists( appMetadata, "mappings" ) && !isNull( appMetadata.mappings ) ) {
var mappings = appMetadata.mappings;
} else {
var mappings = {};
}
Expand Down
8 changes: 5 additions & 3 deletions system/mockutils/MockGenerator.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -101,18 +101,20 @@ component accessors="true" {
udfOut.append( " " );

// Is it required?
if ( !isNull( thisParam.required ) && thisParam.required ) {
if ( structKeyExists( thisParam, "required" ) && !isNull( thisParam.required ) && thisParam.required ) {
udfOut.append( "required " );
}

// If we have a type, add it
if ( !isNull( thisParam.type ) ) {
if ( structKeyExists( thisParam, "type" ) && !isNull( thisParam.type ) ) {
udfOut.append( thisParam.type & " " );
}

// Param name and default
udfOut.append( thisParam.name & " " );
if ( !isNull( thisParam.default ) && thisParam.default != "[runtime expression]" ) {
if (
structKeyExists( thisParam, "default" ) && !isNull( thisParam.default ) && thisParam.default != "[runtime expression]"
) {
udfOut.append( "= " & outputQuotedValue( thisParam.default ) & " " );
}

Expand Down
2 changes: 1 addition & 1 deletion system/runners/BDDRunner.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ component
e,
arguments.target,
arguments.testResults,
isNull( thisSuite ) ? {} : thisSuite
!structKeyExists( local, "thisSuite" ) || isNull( local.thisSuite ) ? {} : local.thisSuite
]
);
}
Expand Down
2 changes: 1 addition & 1 deletion system/runners/BaseRunner.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ component {
var md = getMetadata( arguments.target )
var md = md.keyExists( "annotations" ) ? md.annotations : md

if ( isNull( md.skip ) ) {
if ( !structKeyExists( md, "skip" ) || isNull( md.skip ) ) {
return false
}

Expand Down
2 changes: 1 addition & 1 deletion system/util/CFMappingHelper.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ component {
*/
CFMappingHelper function addCustomTagPath( required path ){
var appMetadata = getApplicationMetadata();
if ( isNull( appMetadata.customTagPaths ) ) {
if ( !structKeyExists( appMetadata, "customTagPaths" ) || isNull( appMetadata.customTagPaths ) ) {
appMetadata.customTagPaths = "";
}
getPageContext()
Expand Down
2 changes: 1 addition & 1 deletion system/util/Env.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ component singleton {
* Retrieve an instance of Java System
*/
function getJavaSystem(){
if ( isNull( variables.javaSystem ) ) {
if ( !structKeyExists( variables, "javaSystem" ) || isNull( variables.javaSystem ) ) {
variables.javaSystem = createObject( "java", "java.lang.System" );
}
return variables.javaSystem;
Expand Down
2 changes: 1 addition & 1 deletion system/util/Util.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ component {
*/
private function getEngineMappingHelper(){
// Lazy load the helper
if ( isNull( variables.engineMappingHelper ) ) {
if ( !structKeyExists( variables, "engineMappingHelper" ) || isNull( variables.engineMappingHelper ) ) {
if ( server.keyExists( "boxlang" ) ) {
variables.engineMappingHelper = new BoxLangMappingHelper();
} else if ( listFindNoCase( "Lucee", server.coldfusion.productname ) ) {
Expand Down
29 changes: 29 additions & 0 deletions tests/specs/FullNullSupportTest.cfc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Regression coverage for public TestBox flows when missing values are real nulls.
*/
component extends="testbox.system.BaseSpec" {

function run(){
describe( "Full null support", function(){
it( "lazy loads public helper services from an uninitialized state", function(){
expect( getCBMockData() ).toBeComponent();
expect( getUtility() ).toBeComponent();
expect( getEnv() ).toBeComponent();
expect( getMockBox() ).toBeComponent();
} );

it( "discovers tests without optional URL filters", function(){
var discovery = new testbox.system.TestBox(
bundles = [ "tests.specs.BaseTest" ],
options = { "coverage" : { "enabled" : false } }
).dryRun();

expect( discovery ).toBeStruct().toHaveKey( "bundles,filters,summary" );
expect( discovery.filters.testBundles ).toBeEmpty();
expect( discovery.filters.testSuites ).toBeEmpty();
expect( discovery.filters.testSpecs ).toBeEmpty();
} );
} );
}

}
10 changes: 10 additions & 0 deletions tests/specs/coverage/CoverageServiceTest.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ component extends="testbox.system.BaseSpec" {
expect( mockGenerator.$never( "generateData" ) ).toBeTrue();
} );
} );

it( "applies defaults when optional coverage settings are omitted", function(){
var options = new system.coverage.CoverageService( { "enabled" : false } ).getCoverageOptions();

expect( options.browser.outputDir ).toBe( "" );
expect( options.coverageTresholds ).toBe( { "good" : 85, "bad" : 50 } );
expect( options.sonarQube.XMLOutputPath ).toBe( "" );
expect( options.isBatched ).toBeFalse();
} );

describe( "enabled coverage, disabled coverage batching", function(){
beforeEach( function(){
if ( structKeyExists( variables, "model" ) ) {
Expand Down
Loading