diff --git a/.github/patches/coldbox-full-null.patch b/.github/patches/coldbox-full-null.patch new file mode 100644 index 00000000..289b5063 --- /dev/null +++ b/.github/patches/coldbox-full-null.patch @@ -0,0 +1,105 @@ +diff --git a/tests/resources/app/coldbox/system/testing/VirtualApp.cfc b/tests/resources/app/coldbox/system/testing/VirtualApp.cfc +--- a/tests/resources/app/coldbox/system/testing/VirtualApp.cfc ++++ b/tests/resources/app/coldbox/system/testing/VirtualApp.cfc +@@ -94 +94 @@ +- return !isNull( application.cbController ); ++ return application.keyExists( "cbController" ) && !isNull( application.cbController ); +@@ -112 +112 @@ +- if ( !isNull( application.cbController ) ) { ++ if ( application.keyExists( "cbController" ) && !isNull( application.cbController ) ) { +diff --git a/tests/resources/app/coldbox/system/logging/config/LogBoxConfig.cfc b/tests/resources/app/coldbox/system/logging/config/LogBoxConfig.cfc +--- a/tests/resources/app/coldbox/system/logging/config/LogBoxConfig.cfc ++++ b/tests/resources/app/coldbox/system/logging/config/LogBoxConfig.cfc +@@ -64 +64 @@ +- if ( isNull( variables.utility ) ) { ++ if ( !variables.keyExists( "utility" ) || isNull( variables.utility ) ) { +diff --git a/tests/resources/app/coldbox/system/core/util/Util.cfc b/tests/resources/app/coldbox/system/core/util/Util.cfc +--- a/tests/resources/app/coldbox/system/core/util/Util.cfc ++++ b/tests/resources/app/coldbox/system/core/util/Util.cfc +@@ -296 +296 @@ +- if ( isNull( variables.mixerUtil ) ) { ++ if ( !variables.keyExists( "mixerUtil" ) || isNull( variables.mixerUtil ) ) { +diff --git a/tests/resources/app/coldbox/system/logging/Logger.cfc b/tests/resources/app/coldbox/system/logging/Logger.cfc +--- a/tests/resources/app/coldbox/system/logging/Logger.cfc ++++ b/tests/resources/app/coldbox/system/logging/Logger.cfc +@@ -399 +399 @@ +- if ( isNull( local.logEvent ) ) { ++ if ( !local.keyExists( "logEvent" ) || isNull( local.logEvent ) ) { +diff --git a/tests/resources/app/coldbox/system/core/delegates/Env.cfc b/tests/resources/app/coldbox/system/core/delegates/Env.cfc +--- a/tests/resources/app/coldbox/system/core/delegates/Env.cfc ++++ b/tests/resources/app/coldbox/system/core/delegates/Env.cfc +@@ -87 +87 @@ +- if ( isNull( variables.javaSystem ) ) { ++ if ( !variables.keyExists( "javaSystem" ) || isNull( variables.javaSystem ) ) { +diff --git a/tests/resources/app/coldbox/system/web/services/InterceptorService.cfc b/tests/resources/app/coldbox/system/web/services/InterceptorService.cfc +--- a/tests/resources/app/coldbox/system/web/services/InterceptorService.cfc ++++ b/tests/resources/app/coldbox/system/web/services/InterceptorService.cfc +@@ -194 +194 @@ +- if ( !isNull( arguments.interceptData ) ) { ++ if ( arguments.keyExists( "interceptData" ) && !isNull( arguments.interceptData ) ) { +diff --git a/tests/resources/app/coldbox/system/testing/BaseTestCase.cfc b/tests/resources/app/coldbox/system/testing/BaseTestCase.cfc +--- a/tests/resources/app/coldbox/system/testing/BaseTestCase.cfc ++++ b/tests/resources/app/coldbox/system/testing/BaseTestCase.cfc +@@ -162 +162 @@ +- if ( isNull( variables._ranBeforeAll ) ) { ++ if ( !variables.keyExists( "_ranBeforeAll" ) || isNull( variables._ranBeforeAll ) ) { +@@ -172 +172 @@ +- if ( isNull( variables._ranAfterAll ) ) { ++ if ( !variables.keyExists( "_ranAfterAll" ) || isNull( variables._ranAfterAll ) ) { +@@ -784 +784 @@ +- if ( !isNull( arguments.interceptData ) ) { ++ if ( arguments.keyExists( "interceptData" ) && !isNull( arguments.interceptData ) ) { +@@ -847 +847 @@ +- if ( isNull( variables.cbUtil ) ) { ++ if ( !variables.keyExists( "cbUtil" ) || isNull( variables.cbUtil ) ) { +@@ -859 +859 @@ +- if ( isNull( variables.env ) ) { ++ if ( !variables.keyExists( "env" ) || isNull( variables.env ) ) { +diff --git a/tests/resources/app/coldbox/system/ioc/Builder.cfc b/tests/resources/app/coldbox/system/ioc/Builder.cfc +--- a/tests/resources/app/coldbox/system/ioc/Builder.cfc ++++ b/tests/resources/app/coldbox/system/ioc/Builder.cfc +@@ -82 +82 @@ +- if ( isNull( variables.coldboxDSL ) ) { ++ if ( !variables.keyExists( "coldboxDSL" ) || isNull( variables.coldboxDSL ) ) { +@@ -94 +94 @@ +- if ( isNull( variables.cacheBoxDSL ) ) { ++ if ( !variables.keyExists( "cacheBoxDSL" ) || isNull( variables.cacheBoxDSL ) ) { +@@ -106 +106 @@ +- if ( isNull( variables.logBoxDSL ) ) { ++ if ( !variables.keyExists( "logBoxDSL" ) || isNull( variables.logBoxDSL ) ) { +diff --git a/tests/resources/app/coldbox/system/cache/store/ConcurrentStore.cfc b/tests/resources/app/coldbox/system/cache/store/ConcurrentStore.cfc +--- a/tests/resources/app/coldbox/system/cache/store/ConcurrentStore.cfc ++++ b/tests/resources/app/coldbox/system/cache/store/ConcurrentStore.cfc +@@ -261 +261 @@ +- if ( isNull( variables.collections ) ) { ++ if ( !variables.keyExists( "collections" ) || isNull( variables.collections ) ) { +diff --git a/tests/resources/app/coldbox/system/FrameworkSupertype.cfc b/tests/resources/app/coldbox/system/FrameworkSupertype.cfc +--- a/tests/resources/app/coldbox/system/FrameworkSupertype.cfc ++++ b/tests/resources/app/coldbox/system/FrameworkSupertype.cfc +@@ -621 +621 @@ +- if ( isNull( variables.asyncManager ) ) { ++ if ( !variables.keyExists( "asyncManager" ) || isNull( variables.asyncManager ) ) { +@@ -755 +755 @@ +- if ( isNull( variables.cbDateTimeHelper ) ) { ++ if ( !variables.keyExists( "cbDateTimeHelper" ) || isNull( variables.cbDateTimeHelper ) ) { +diff --git a/tests/resources/app/coldbox/system/core/util/Util.cfc b/tests/resources/app/coldbox/system/core/util/Util.cfc +--- a/tests/resources/app/coldbox/system/core/util/Util.cfc ++++ b/tests/resources/app/coldbox/system/core/util/Util.cfc +@@ -124 +124 @@ +- if ( isNull( variables.inetAddress ) ) { ++ if ( !variables.keyExists( "inetAddress" ) || isNull( variables.inetAddress ) ) { +diff --git a/tests/resources/app/coldbox/system/cache/config/CacheBoxConfig.cfc b/tests/resources/app/coldbox/system/cache/config/CacheBoxConfig.cfc +--- a/tests/resources/app/coldbox/system/cache/config/CacheBoxConfig.cfc ++++ b/tests/resources/app/coldbox/system/cache/config/CacheBoxConfig.cfc +@@ -107 +107 @@ +- if ( !isNull( cacheBoxDSL.logBoxConfig ) ) { ++ if ( structKeyExists( cacheBoxDSL, "logBoxConfig" ) && !isNull( cacheBoxDSL.logBoxConfig ) ) { +@@ -112 +112 @@ +- if ( !isNull( cacheBoxDSL.scopeRegistration ) ) { ++ if ( structKeyExists( cacheBoxDSL, "scopeRegistration" ) && !isNull( cacheBoxDSL.scopeRegistration ) ) { +@@ -117 +117 @@ +- if ( !isNull( cacheBoxDSL.caches ) ) { ++ if ( structKeyExists( cacheBoxDSL, "caches" ) && !isNull( cacheBoxDSL.caches ) ) { +@@ -125 +125 @@ +- if ( !isNull( cacheBoxDSL.listeners ) ) { ++ if ( structKeyExists( cacheBoxDSL, "listeners" ) && !isNull( cacheBoxDSL.listeners ) ) { diff --git a/.github/patches/coldbox7-full-null.patch b/.github/patches/coldbox7-full-null.patch new file mode 100644 index 00000000..0c098178 --- /dev/null +++ b/.github/patches/coldbox7-full-null.patch @@ -0,0 +1,51 @@ +diff --git a/tests/resources/app/coldbox/system/core/util/Util.cfc b/tests/resources/app/coldbox/system/core/util/Util.cfc +--- a/tests/resources/app/coldbox/system/core/util/Util.cfc ++++ b/tests/resources/app/coldbox/system/core/util/Util.cfc +@@ -12 +12 @@ +- if ( isNull( variables.engineMappingHelper ) ) { ++ if ( !variables.keyExists( "engineMappingHelper" ) || isNull( variables.engineMappingHelper ) ) { +diff --git a/tests/resources/app/coldbox/system/logging/LogEvent.cfc b/tests/resources/app/coldbox/system/logging/LogEvent.cfc +--- a/tests/resources/app/coldbox/system/logging/LogEvent.cfc ++++ b/tests/resources/app/coldbox/system/logging/LogEvent.cfc +@@ -61 +61 @@ +- if ( isNull( variables.xmlConverter ) ) { ++ if ( !variables.keyExists( "xmlConverter" ) || isNull( variables.xmlConverter ) ) { +@@ -68 +68 @@ +- if ( isNull( variables.util ) ) { ++ if ( !variables.keyExists( "util" ) || isNull( variables.util ) ) { +diff --git a/tests/resources/app/coldbox/system/cache/AbstractCacheBoxProvider.cfc b/tests/resources/app/coldbox/system/cache/AbstractCacheBoxProvider.cfc +--- a/tests/resources/app/coldbox/system/cache/AbstractCacheBoxProvider.cfc ++++ b/tests/resources/app/coldbox/system/cache/AbstractCacheBoxProvider.cfc +@@ -115 +115 @@ +- if ( isNull( variables.utility ) ) { ++ if ( !variables.keyExists( "utility" ) || isNull( variables.utility ) ) { +@@ -428 +428 @@ +- if ( isNull( variables.uuidHelper ) ) { ++ if ( !variables.keyExists( "uuidHelper" ) || isNull( variables.uuidHelper ) ) { +diff --git a/tests/resources/app/coldbox/system/cache/CacheFactory.cfc b/tests/resources/app/coldbox/system/cache/CacheFactory.cfc +--- a/tests/resources/app/coldbox/system/cache/CacheFactory.cfc ++++ b/tests/resources/app/coldbox/system/cache/CacheFactory.cfc +@@ -484 +484 @@ +- if ( isNull( variables.config ) ) { ++ if ( !variables.keyExists( "config" ) || isNull( variables.config ) ) { +diff --git a/tests/resources/app/coldbox/system/remote/ColdboxProxy.cfc b/tests/resources/app/coldbox/system/remote/ColdboxProxy.cfc +--- a/tests/resources/app/coldbox/system/remote/ColdboxProxy.cfc ++++ b/tests/resources/app/coldbox/system/remote/ColdboxProxy.cfc +@@ -342 +342 @@ +- if ( isNull( variables.util ) ) { ++ if ( !variables.keyExists( "util" ) || isNull( variables.util ) ) { +@@ -354 +354 @@ +- if ( isNull( variables.remotingUtil ) ) { ++ if ( !variables.keyExists( "remotingUtil" ) || isNull( variables.remotingUtil ) ) { +diff --git a/tests/resources/app/coldbox/system/web/context/RequestContext.cfc b/tests/resources/app/coldbox/system/web/context/RequestContext.cfc +--- a/tests/resources/app/coldbox/system/web/context/RequestContext.cfc ++++ b/tests/resources/app/coldbox/system/web/context/RequestContext.cfc +@@ -1576 +1576 @@ +- if ( isNull( variables.privateContext.response ) ) { ++ if ( !variables.privateContext.keyExists( "response" ) || isNull( variables.privateContext.response ) ) { +diff --git a/modules/str/modules/cbjavaloader/models/javaloader/JavaLoader.cfc b/modules/str/modules/cbjavaloader/models/javaloader/JavaLoader.cfc +--- a/modules/str/modules/cbjavaloader/models/javaloader/JavaLoader.cfc ++++ b/modules/str/modules/cbjavaloader/models/javaloader/JavaLoader.cfc +@@ -570 +570 @@ +- returntype="string" ++ returntype="void" diff --git a/.github/patches/testbox-full-null.patch b/.github/patches/testbox-full-null.patch new file mode 100644 index 00000000..ec53024c --- /dev/null +++ b/.github/patches/testbox-full-null.patch @@ -0,0 +1,63 @@ +diff --git a/testbox/system/coverage/CoverageService.cfc b/testbox/system/coverage/CoverageService.cfc +--- a/testbox/system/coverage/CoverageService.cfc ++++ b/testbox/system/coverage/CoverageService.cfc +@@ -175 +175 @@ +- if ( isNull( opts.coverageTresholds ) ) { ++ if ( !structKeyExists( opts, "coverageTresholds" ) || isNull( opts.coverageTresholds ) ) { +@@ -178 +178 @@ +- if ( isNull( opts.coverageTresholds.good ) ) { ++ if ( !structKeyExists( opts.coverageTresholds, "good" ) || isNull( opts.coverageTresholds.good ) ) { +@@ -181 +181 @@ +- if ( isNull( opts.coverageTresholds.bad ) ) { ++ if ( !structKeyExists( opts.coverageTresholds, "bad" ) || isNull( opts.coverageTresholds.bad ) ) { +diff --git a/testbox/system/TestBox.cfc b/testbox/system/TestBox.cfc +--- a/testbox/system/TestBox.cfc ++++ b/testbox/system/TestBox.cfc +@@ -408 +408 @@ +- if ( !isNull( url.testBundles ) ) { ++ if ( structKeyExists( url, "testBundles" ) && !isNull( url.testBundles ) ) { +@@ -411 +411 @@ +- if ( !isNull( url.testSuites ) ) { ++ if ( structKeyExists( url, "testSuites" ) && !isNull( url.testSuites ) ) { +@@ -414 +414 @@ +- if ( !isNull( url.testSpecs ) ) { ++ if ( structKeyExists( url, "testSpecs" ) && !isNull( url.testSpecs ) ) { +@@ -417 +417 @@ +- if ( !isNull( url.testMethod ) ) { ++ if ( structKeyExists( url, "testMethod" ) && !isNull( url.testMethod ) ) { +@@ -259 +259 @@ +- if ( isNull( variables.env ) ) { ++ if ( !structKeyExists( variables, "env" ) || isNull( variables.env ) ) { +diff --git a/testbox/system/util/Util.cfc b/testbox/system/util/Util.cfc +--- a/testbox/system/util/Util.cfc ++++ b/testbox/system/util/Util.cfc +@@ -203 +203 @@ +- if ( isNull( variables.engineMappingHelper ) ) { ++ if ( !structKeyExists( variables, "engineMappingHelper" ) || isNull( variables.engineMappingHelper ) ) { +diff --git a/testbox/system/util/Env.cfc b/testbox/system/util/Env.cfc +--- a/testbox/system/util/Env.cfc ++++ b/testbox/system/util/Env.cfc +@@ -87 +87 @@ +- if ( isNull( variables.javaSystem ) ) { ++ if ( !structKeyExists( variables, "javaSystem" ) || isNull( variables.javaSystem ) ) { +diff --git a/testbox/system/BaseSpec.cfc b/testbox/system/BaseSpec.cfc +--- a/testbox/system/BaseSpec.cfc ++++ b/testbox/system/BaseSpec.cfc +@@ -1627 +1627 @@ +- if ( isNull( variables.$cbMockData ) ) { ++ if ( !structKeyExists( variables, "$cbMockData" ) || isNull( variables.$cbMockData ) ) { +@@ -1640 +1640 @@ +- if ( isNull( variables.$utility ) ) { ++ if ( !structKeyExists( variables, "$utility" ) || isNull( variables.$utility ) ) { +@@ -1653 +1653 @@ +- if ( isNull( variables.$env ) ) { ++ if ( !structKeyExists( variables, "$env" ) || isNull( variables.$env ) ) { +@@ -1668 +1668 @@ +- if ( isNull( this.$mockbox ) ) { ++ if ( !structKeyExists( this, "$mockbox" ) || isNull( this.$mockbox ) ) { +diff --git a/testbox/system/runners/BDDRunner.cfc b/testbox/system/runners/BDDRunner.cfc +--- a/testbox/system/runners/BDDRunner.cfc ++++ b/testbox/system/runners/BDDRunner.cfc +@@ -159 +159 @@ +- isNull( thisSuite ) ? {} : thisSuite ++ !structKeyExists( local, "thisSuite" ) || isNull( local.thisSuite ) ? {} : local.thisSuite diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index be47a606..80f531c4 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -11,40 +11,51 @@ jobs: strategy: fail-fast: false matrix: - cfengine: ["lucee@5", "lucee@6", "adobe@2021", "adobe@2023", "adobe@2025", "boxlang-cfml@1"] + cfengine: ["lucee@5", "lucee@6", "adobe@2021", "adobe@2023", "adobe@2025", "boxlang@1", "boxlang-cfml@1"] coldbox: ["coldbox@^7", "coldbox@^8"] - experimental: [ false ] + experimental: [false] + fullNull: ["true", "false"] + exclude: + - cfengine: "boxlang@1" + coldbox: "coldbox@^7" + - cfengine: "adobe@2021" + coldbox: "coldbox@^8" + fullNull: "true" + - cfengine: "adobe@2023" + coldbox: "coldbox@^8" + fullNull: "true" + - cfengine: "adobe@2025" + coldbox: "coldbox@^8" + fullNull: "true" include: - cfengine: "lucee@be" coldbox: "coldbox@^7" experimental: true + fullNull: "true" - cfengine: "lucee@be" coldbox: "coldbox@^8" experimental: true + fullNull: "true" - cfengine: "lucee@be" coldbox: "coldbox@be" experimental: true + fullNull: "true" - cfengine: "adobe@be" coldbox: "coldbox@^7" experimental: true - - cfengine: "adobe@be" - coldbox: "coldbox@^8" - experimental: true - - cfengine: "adobe@be" - coldbox: "coldbox@be" - experimental: true - - cfengine: "boxlang@1" - coldbox: "coldbox@^8" - experimental: true + fullNull: "true" - cfengine: "boxlang@1" coldbox: "coldbox@be" experimental: true + fullNull: "true" - cfengine: "boxlang@be" coldbox: "coldbox@^8" experimental: true + fullNull: "true" - cfengine: "boxlang@be" coldbox: "coldbox@be" experimental: true + fullNull: "true" services: mysql: image: mysql:5.7 @@ -74,11 +85,17 @@ jobs: - name: Install dependencies run: | box install + git apply --unidiff-zero .github/patches/testbox-full-null.patch box config set modules.commandbox-dotenv.checkEnvPreServerStart=false box install ${{ matrix.coldbox }} --noSave + git apply --unidiff-zero .github/patches/coldbox-full-null.patch + if [ "${{ matrix.coldbox }}" = "coldbox@^7" ]; then + git apply --unidiff-zero .github/patches/coldbox7-full-null.patch + fi - name: Start server env: + FULL_NULL: ${{ matrix.fullNull }} DB_HOST: localhost DB_PORT: ${{ job.services.mysql.ports[3306] }} DB_NAME: quick @@ -90,9 +107,11 @@ jobs: - name: Run TestBox Tests env: + FULL_NULL: ${{ matrix.fullNull }} DB_HOST: localhost DB_PORT: ${{ job.services.mysql.ports[3306] }} DB_NAME: quick DB_USER: quick DB_PASSWORD: quick - run: box testbox run \ No newline at end of file + continue-on-error: ${{ matrix.experimental }} + run: box testbox run diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index c636f8b3..2e0ff33d 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -19,8 +19,31 @@ jobs: strategy: fail-fast: false matrix: - cfengine: ["lucee@5", "lucee@6", "adobe@2021", "adobe@2023", "adobe@2025", "boxlang-cfml@1"] + cfengine: ["lucee@5", "lucee@6", "adobe@2021", "adobe@2023", "adobe@2025", "boxlang@1", "boxlang-cfml@1"] coldbox: ["coldbox@^7", "coldbox@^8"] + experimental: [false] + fullNull: ["true", "false"] + exclude: + - cfengine: "boxlang@1" + coldbox: "coldbox@^7" + - cfengine: "adobe@2021" + coldbox: "coldbox@^8" + fullNull: "true" + - cfengine: "adobe@2023" + coldbox: "coldbox@^8" + fullNull: "true" + - cfengine: "adobe@2025" + coldbox: "coldbox@^8" + fullNull: "true" + include: + - cfengine: "adobe@be" + coldbox: "coldbox@^7" + experimental: true + fullNull: "true" + - cfengine: "boxlang@be" + coldbox: "coldbox@^8" + experimental: true + fullNull: "true" services: mysql: image: mysql:5.7 @@ -50,10 +73,17 @@ jobs: - name: Install dependencies run: | box install + git apply --unidiff-zero .github/patches/testbox-full-null.patch box config set modules.commandbox-dotenv.checkEnvPreServerStart=false + box install ${{ matrix.coldbox }} --noSave + git apply --unidiff-zero .github/patches/coldbox-full-null.patch + if [ "${{ matrix.coldbox }}" = "coldbox@^7" ]; then + git apply --unidiff-zero .github/patches/coldbox7-full-null.patch + fi - name: Start server env: + FULL_NULL: ${{ matrix.fullNull }} DB_HOST: localhost DB_PORT: ${{ job.services.mysql.ports[3306] }} DB_NAME: quick @@ -65,11 +95,13 @@ jobs: - name: Run TestBox Tests env: + FULL_NULL: ${{ matrix.fullNull }} DB_HOST: localhost DB_PORT: ${{ job.services.mysql.ports[3306] }} DB_NAME: quick DB_USER: quick DB_PASSWORD: quick + continue-on-error: ${{ matrix.experimental }} run: box testbox run format: @@ -97,4 +129,4 @@ jobs: - name: Commit Format Changes uses: stefanzweifel/git-auto-commit-action@v5.2.0 with: - commit_message: Apply cfformat changes \ No newline at end of file + commit_message: Apply cfformat changes diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8c7a0fcb..019adceb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,8 +14,21 @@ jobs: strategy: fail-fast: false matrix: - cfengine: ["lucee@5", "lucee@6", "adobe@2021", "adobe@2023", "adobe@2025", "boxlang-cfml@1"] + cfengine: ["lucee@5", "lucee@6", "adobe@2021", "adobe@2023", "adobe@2025", "boxlang@1", "boxlang-cfml@1"] coldbox: ["coldbox@^7", "coldbox@^8"] + fullNull: ["true", "false"] + exclude: + - cfengine: "boxlang@1" + coldbox: "coldbox@^7" + - cfengine: "adobe@2021" + coldbox: "coldbox@^8" + fullNull: "true" + - cfengine: "adobe@2023" + coldbox: "coldbox@^8" + fullNull: "true" + - cfengine: "adobe@2025" + coldbox: "coldbox@^8" + fullNull: "true" services: mysql: image: mysql:5.7 @@ -45,10 +58,17 @@ jobs: - name: Install dependencies run: | box install + git apply --unidiff-zero .github/patches/testbox-full-null.patch box config set modules.commandbox-dotenv.checkEnvPreServerStart=false + box install ${{ matrix.coldbox }} --noSave + git apply --unidiff-zero .github/patches/coldbox-full-null.patch + if [ "${{ matrix.coldbox }}" = "coldbox@^7" ]; then + git apply --unidiff-zero .github/patches/coldbox7-full-null.patch + fi - name: Start server env: + FULL_NULL: ${{ matrix.fullNull }} DB_HOST: localhost DB_PORT: ${{ job.services.mysql.ports[3306] }} DB_NAME: quick @@ -60,6 +80,7 @@ jobs: - name: Run TestBox Tests env: + FULL_NULL: ${{ matrix.fullNull }} DB_HOST: localhost DB_PORT: ${{ job.services.mysql.ports[3306] }} DB_NAME: quick diff --git a/box.json b/box.json index b2dcf301..e81e77df 100644 --- a/box.json +++ b/box.json @@ -35,7 +35,7 @@ }, "devDependencies":{ "coldbox":"^8.0.0", - "testbox":"^6.0.0", + "testbox":"^7.0.0", "cfcollection":"^3.6.4", "cfmigrations":"^5.0.0" }, diff --git a/models/BaseEntity.cfc b/models/BaseEntity.cfc index 59f422c1..cda9558b 100644 --- a/models/BaseEntity.cfc +++ b/models/BaseEntity.cfc @@ -2792,7 +2792,11 @@ component accessors="true" { var meta = {}; meta[ "originalMetadata" ] = util.getInheritedMetadata( this ); meta[ "localMetadata" ] = getMetadata( this ); - var hasAccessorsMetadata = false; + if ( server.keyExists( "boxlang" ) ) { + normalizeBoxLangMetadata( meta.originalMetadata ); + normalizeBoxLangMetadata( meta.localMetadata ); + } + var hasAccessorsMetadata = false; if ( meta.localMetadata.keyExists( "accessors" ) ) { hasAccessorsMetadata = lCase( trim( meta.localMetadata.accessors & "" ) ) == "true"; } @@ -2855,8 +2859,11 @@ component accessors="true" { } var baseEntityFunctionNames = variables._cache.getOrSet( "quick-metadata:BaseEntity", function() { + var baseEntityMetadata = server.keyExists( "boxlang" ) + ? getClassMetadata( "quick.models.BaseEntity" ) + : getComponentMetadata( "quick.models.BaseEntity" ); return arrayReduce( - getComponentMetadata( "quick.models.BaseEntity" ).functions, + baseEntityMetadata.functions, function( acc, func ) { arguments.acc[ arguments.func.name ] = ""; return arguments.acc; @@ -2917,9 +2924,63 @@ component accessors="true" { } variables._readonly = variables._meta.readonly; explodeAttributesMetadata( variables._meta.attributes ); + if ( server.keyExists( "boxlang" ) ) { + for ( + var attributeName in retrieveAttributeNames( + withVirtualAttributes = true, + withExcludedAttributes = true + ) + ) { + if ( variables.keyExists( attributeName ) && isNull( variables[ attributeName ] ) ) { + structDelete( variables, attributeName ); + } + } + } variables._casts = variables._meta.casts; } + /** + * Normalizes BoxLang metadata annotations to the keys Quick consumes. + */ + private void function normalizeBoxLangMetadata( required struct metadata ) { + if ( arguments.metadata.keyExists( "annotations" ) && isStruct( arguments.metadata.annotations ) ) { + for ( + var key in [ + "mapping", + "entityName", + "table", + "readonly", + "joincolumn", + "discriminatorValue", + "singleTableInheritance", + "datasource", + "grammar", + "discriminatorColumn" + ] + ) { + if ( arguments.metadata.annotations.keyExists( key ) && !isNull( arguments.metadata.annotations[ key ] ) ) { + arguments.metadata[ key ] = arguments.metadata.annotations[ key ]; + } + } + } + + if ( arguments.metadata.keyExists( "properties" ) && isArray( arguments.metadata.properties ) ) { + for ( var propertyMetadata in arguments.metadata.properties ) { + if ( propertyMetadata.keyExists( "annotations" ) && isStruct( propertyMetadata.annotations ) ) { + for ( var key in propertyMetadata.annotations ) { + if ( + propertyMetadata.annotations.keyExists( key ) && !isNull( + propertyMetadata.annotations[ key ] + ) + ) { + propertyMetadata[ key ] = propertyMetadata.annotations[ key ]; + } + } + } + } + } + } + /** * Creates an array of all the function names in the metadata. * diff --git a/models/KeyTypes/UUIDKeyType.cfc b/models/KeyTypes/UUIDKeyType.cfc index 33fa8a30..9339f2a6 100644 --- a/models/KeyTypes/UUIDKeyType.cfc +++ b/models/KeyTypes/UUIDKeyType.cfc @@ -16,7 +16,12 @@ component implements="KeyType" { .keyNames() .each( function( keyName ) { if ( entity.isNullAttribute( keyName ) ) { - entity.assignAttribute( keyName, createUUID() ); + var uuid = createUUID(); + var uuidParts = listToArray( uuid, "-" ); + if ( uuidParts.len() == 5 ) { + uuid = "#uuidParts[ 1 ]#-#uuidParts[ 2 ]#-#uuidParts[ 3 ]#-#uuidParts[ 4 ]##uuidParts[ 5 ]#"; + } + entity.assignAttribute( keyName, uuid ); } } ); } diff --git a/models/QuickBuilder.cfc b/models/QuickBuilder.cfc index c1404db8..c1600d03 100644 --- a/models/QuickBuilder.cfc +++ b/models/QuickBuilder.cfc @@ -887,6 +887,9 @@ component accessors="true" transientCache="false" { } } } + if ( !structKeyExists( arguments, "tableName" ) || isNull( arguments.tableName ) ) { + return getEntity().qualifyColumn( arguments.column ); + } return getEntity().qualifyColumn( argumentCollection = arguments ); } @@ -1519,7 +1522,7 @@ component accessors="true" transientCache="false" { * @return quick.models.BaseEntity */ public any function withoutGlobalScope( any name ) { - if ( !structKeyExists( arguments, "name" ) ) { + if ( !structKeyExists( arguments, "name" ) || isNull( arguments.name ) ) { variables._globalScopeExcludeAll = true; return this; } diff --git a/tests/Application.cfc b/tests/Application.cfc index 1f74ede0..e434a3d9 100644 --- a/tests/Application.cfc +++ b/tests/Application.cfc @@ -1,5 +1,6 @@ component { + this.enableNullSupport = shouldEnableFullNullSupport(); this.name = "ColdBoxTestingSuite" & hash(getCurrentTemplatePath()); this.sessionManagement = true; this.setClientCookies = true; @@ -27,6 +28,12 @@ component { this.datasource = "quick"; + private boolean function shouldEnableFullNullSupport() { + var system = createObject( "java", "java.lang.System" ); + var value = system.getEnv( "FULL_NULL" ); + return isNull( value ) ? false : !!value; + } + function onApplicationStart() { param url.reloadDatabase = true; } diff --git a/tests/resources/ModuleIntegrationSpec.cfc b/tests/resources/ModuleIntegrationSpec.cfc index 22851440..88f5c9ac 100644 --- a/tests/resources/ModuleIntegrationSpec.cfc +++ b/tests/resources/ModuleIntegrationSpec.cfc @@ -72,4 +72,19 @@ component extends="coldbox.system.testing.BaseTestCase" appMapping="/app" { return arraySlice( createObject( "java", "java.util.HashSet" ).init( arguments.items ).toArray(), 1 ); } + /** + * Formats database timestamps without relying on engine-specific date mask parsing. + */ + public string function formatTestTimestamp( required date timestamp ) { + return arrayToList( [ + year( arguments.timestamp ), + numberFormat( month( arguments.timestamp ), "00" ), + numberFormat( day( arguments.timestamp ), "00" ) + ], "-" ) & " " & arrayToList( [ + numberFormat( hour( arguments.timestamp ), "00" ), + numberFormat( minute( arguments.timestamp ), "00" ), + numberFormat( second( arguments.timestamp ), "00" ) + ], ":" ); + } + } diff --git a/tests/resources/database/migrations/2020_08_11_102347_create_countries_table.cfc b/tests/resources/database/migrations/2020_08_11_102347_create_countries_table.cfc index 82ccde2a..d94a6fac 100755 --- a/tests/resources/database/migrations/2020_08_11_102347_create_countries_table.cfc +++ b/tests/resources/database/migrations/2020_08_11_102347_create_countries_table.cfc @@ -12,14 +12,14 @@ component { { "id": "02B84D66-0AA0-F7FB-1F71AFC954843861", "name": "United States", - "created_date": createDateTime( 2017, 07, 28, 02, 07, 00 ), - "modified_date": createDateTime( 2017, 07, 28, 02, 07, 00 ) + "created_date": "2017-07-28 02:07:00", + "modified_date": "2017-07-28 02:07:00" }, { "id": "02BA2DB0-EB1E-3F85-5F283AB5E45608C6", "name": "Argentina", - "created_date": createDateTime( 2017, 07, 29, 03, 07, 00 ), - "modified_date": createDateTime( 2017, 07, 29, 03, 07, 00 ) + "created_date": "2017-07-29 03:07:00", + "modified_date": "2017-07-29 03:07:00" } ] ); } diff --git a/tests/resources/database/migrations/2020_08_11_102531_create_users_table.cfc b/tests/resources/database/migrations/2020_08_11_102531_create_users_table.cfc index 36805f9e..fa5db99d 100755 --- a/tests/resources/database/migrations/2020_08_11_102531_create_users_table.cfc +++ b/tests/resources/database/migrations/2020_08_11_102531_create_users_table.cfc @@ -31,8 +31,8 @@ component { "password": "5F4DCC3B5AA765D61D8327DEB882CF99", "country_id": "02B84D66-0AA0-F7FB-1F71AFC954843861", "team_id": 1, - "created_date": createDateTime( 2017, 07, 28, 02, 06, 36 ), - "modified_date": createDateTime( 2017, 07, 28, 02, 06, 36 ), + "created_date": "2017-07-28 02:06:36", + "modified_date": "2017-07-28 02:06:36", "type": "admin", "externalId": "1234", "streetOne": "123 Elm Street", @@ -50,8 +50,8 @@ component { "password": "5F4DCC3B5AA765D61D8327DEB882CF99", "country_id": "02B84D66-0AA0-F7FB-1F71AFC954843861", "team_id": 1, - "created_date": createDateTime( 2017, 07, 28, 02, 07, 16 ), - "modified_date": createDateTime( 2017, 07, 28, 02, 07, 16 ), + "created_date": "2017-07-28 02:07:16", + "modified_date": "2017-07-28 02:07:16", "type": "limited", "externalId": "6789", "streetOne": "123 Elm Street", @@ -69,8 +69,8 @@ component { "password": "5F4DCC3B5AA765D61D8327DEB882CF99", "country_id": { "value": "", "null": true }, "team_id": 1, - "created_date": createDateTime( 2017, 07, 28, 02, 08, 16 ), - "modified_date": createDateTime( 2017, 07, 28, 02, 08, 16 ), + "created_date": "2017-07-28 02:08:16", + "modified_date": "2017-07-28 02:08:16", "type": "limited", "externalId": "5555", "streetOne": "123 Elm Street", @@ -88,8 +88,8 @@ component { "password": "5F4DCC3B5AA765D61D8327DEB882CF99", "country_id": "02BA2DB0-EB1E-3F85-5F283AB5E45608C6", "team_id": 2, - "created_date": createDateTime( 2019, 06, 15, 12, 29, 36 ), - "modified_date": createDateTime( 2019, 06, 15, 12, 29, 36 ), + "created_date": "2019-06-15 12:29:36", + "modified_date": "2019-06-15 12:29:36", "type": "admin", "externalId": "1234", "streetOne": "123 Elm Street", @@ -107,8 +107,8 @@ component { "password": "5F4DCC3B5AA765D61D8327DEB882CF99", "country_id": "02BA2DB0-EB1E-3F85-5F283AB5E45608C6", "team_id": 3, - "created_date": createDateTime( 2020, 01, 14, 12, 29, 36 ), - "modified_date": createDateTime( 2020, 06, 22, 12, 29, 36 ), + "created_date": "2020-01-14 12:29:36", + "modified_date": "2020-06-22 12:29:36", "type": "limited", "externalId": { "value": "", "null": true }, "streetOne": "1725 Slough Avenue", diff --git a/tests/resources/database/migrations/2020_08_11_102557_create_my_posts_table.cfc b/tests/resources/database/migrations/2020_08_11_102557_create_my_posts_table.cfc index eb613ae5..8948c721 100755 --- a/tests/resources/database/migrations/2020_08_11_102557_create_my_posts_table.cfc +++ b/tests/resources/database/migrations/2020_08_11_102557_create_my_posts_table.cfc @@ -15,33 +15,33 @@ component { "post_pk": 1245, "user_id": 1, "body": "My awesome post body", - "created_date": createDateTime( 2017, 07, 28, 02, 07, 00 ), - "modified_date": createDateTime( 2017, 07, 28, 02, 07, 00 ), - "published_date": createDateTime( 2017, 07, 28, 02, 07, 00 ) + "created_date": "2017-07-28 02:07:00", + "modified_date": "2017-07-28 02:07:00", + "published_date": "2017-07-28 02:07:00" }, { "post_pk": 523526, "user_id": 1, "body": "My second awesome post body", - "created_date": createDateTime( 2017, 07, 28, 02, 07, 36 ), - "modified_date": createDateTime( 2017, 07, 28, 02, 07, 36 ), + "created_date": "2017-07-28 02:07:36", + "modified_date": "2017-07-28 02:07:36", "published_date": { "value": "", "null": true } }, { "post_pk": 7777, "user_id": { "value": "", "null": true }, "body": "My post with no author", - "created_date": createDateTime( 2017, 07, 30, 07, 00, 22 ), - "modified_date": createDateTime( 2017, 07, 30, 07, 00, 22 ), + "created_date": "2017-07-30 07:00:22", + "modified_date": "2017-07-30 07:00:22", "published_date": { "value": "", "null": true } }, { "post_pk": 321, "user_id": 4, "body": "My post with a different author", - "created_date": createDateTime( 2017, 08, 28, 14, 22, 22 ), - "modified_date": createDateTime( 2017, 08, 28, 14, 22, 22 ), - "published_date": createDateTime( 2017, 08, 28, 14, 22, 22 ) + "created_date": "2017-08-28 14:22:22", + "modified_date": "2017-08-28 14:22:22", + "published_date": "2017-08-28 14:22:22" } ] ); } diff --git a/tests/resources/database/migrations/2020_08_11_102605_create_videos_table.cfc b/tests/resources/database/migrations/2020_08_11_102605_create_videos_table.cfc index 0aac2d38..7549eb85 100755 --- a/tests/resources/database/migrations/2020_08_11_102605_create_videos_table.cfc +++ b/tests/resources/database/migrations/2020_08_11_102605_create_videos_table.cfc @@ -16,16 +16,16 @@ component { "url": "https://www.youtube.com/watch?v=JDzIypmP0eo", "title": "Building KiteTail with Adam Wathan", "description": "Awesome live coding experience", - "created_date": createDateTime( 2017, 06, 28, 02, 07, 36 ), - "modified_date": createDateTime( 2017, 06, 30, 12, 17, 24 ) + "created_date": "2017-06-28 02:07:36", + "modified_date": "2017-06-30 12:17:24" }, { "id": 1245, "url": "https://www.youtube.com/watch?v=BgAlQuqzl8o", "title": "Cello Wars", "description": "Star Wars Cello Parody", - "created_date": createDateTime( 2017, 07, 02, 04, 14, 22 ), - "modified_date": createDateTime( 2017, 07, 02, 04, 14, 22 ) + "created_date": "2017-07-02 04:14:22", + "modified_date": "2017-07-02 04:14:22" } ] ); } diff --git a/tests/resources/database/migrations/2020_08_11_102612_create_comments_table.cfc b/tests/resources/database/migrations/2020_08_11_102612_create_comments_table.cfc index 563cb72e..92e5fc4b 100755 --- a/tests/resources/database/migrations/2020_08_11_102612_create_comments_table.cfc +++ b/tests/resources/database/migrations/2020_08_11_102612_create_comments_table.cfc @@ -20,8 +20,8 @@ component { "commentable_type": "Post", "designation": "public", "user_id": 1, - "created_date": createDateTime( 2017, 07, 02, 04, 14, 22 ), - "modified_date": createDateTime( 2017, 07, 02, 04, 14, 22 ) + "created_date": "2017-07-02 04:14:22", + "modified_date": "2017-07-02 04:14:22" }, { "id": 2, @@ -30,8 +30,8 @@ component { "commentable_type": "Post", "designation": "public", "user_id": 2, - "created_date": createDateTime( 2017, 07, 04, 04, 14, 22 ), - "modified_date": createDateTime( 2017, 07, 04, 04, 14, 22 ) + "created_date": "2017-07-04 04:14:22", + "modified_date": "2017-07-04 04:14:22" }, { "id": 3, @@ -40,8 +40,8 @@ component { "commentable_type": "Video", "designation": "public", "user_id": 1, - "created_date": createDateTime( 2017, 07, 02, 04, 14, 22 ), - "modified_date": createDateTime( 2017, 07, 02, 04, 14, 22 ) + "created_date": "2017-07-02 04:14:22", + "modified_date": "2017-07-02 04:14:22" } ] ); } diff --git a/tests/resources/database/migrations/2020_08_11_102613_create_internal_comments_table.cfc b/tests/resources/database/migrations/2020_08_11_102613_create_internal_comments_table.cfc index 52b8614f..3acf31dc 100644 --- a/tests/resources/database/migrations/2020_08_11_102613_create_internal_comments_table.cfc +++ b/tests/resources/database/migrations/2020_08_11_102613_create_internal_comments_table.cfc @@ -19,8 +19,8 @@ component { "commentable_type": "Post", "designation": "internal", "user_id": 1, - "created_date": createDateTime( 2017, 07, 02, 04, 14, 22 ), - "modified_date": createDateTime( 2017, 07, 02, 04, 14, 22 ) + "created_date": "2017-07-02 04:14:22", + "modified_date": "2017-07-02 04:14:22" } ] ); diff --git a/tests/resources/database/migrations/2020_08_11_102636_create_links_table.cfc b/tests/resources/database/migrations/2020_08_11_102636_create_links_table.cfc index bfa5cd84..a7d8a2cd 100755 --- a/tests/resources/database/migrations/2020_08_11_102636_create_links_table.cfc +++ b/tests/resources/database/migrations/2020_08_11_102636_create_links_table.cfc @@ -12,7 +12,7 @@ component { { "link_id": 1, "link_url": "http://example.com/some-link", - "created_date": createDateTime( 2017, 07, 28, 02, 07, 00 ) + "created_date": "2017-07-28 02:07:00" } ] ); } diff --git a/tests/resources/database/migrations/2020_08_11_102640_create_referrals_table.cfc b/tests/resources/database/migrations/2020_08_11_102640_create_referrals_table.cfc index ce9ec89a..45dd65fb 100755 --- a/tests/resources/database/migrations/2020_08_11_102640_create_referrals_table.cfc +++ b/tests/resources/database/migrations/2020_08_11_102640_create_referrals_table.cfc @@ -12,8 +12,8 @@ component { { "id": 1, "type": "external", - "created_date": createDateTime( 2017, 07, 28, 02, 07, 00 ), - "modified_date": createDateTime( 2017, 07, 28, 02, 07, 00 ) + "created_date": "2017-07-28 02:07:00", + "modified_date": "2017-07-28 02:07:00" } ] ); } diff --git a/tests/resources/database/migrations/2020_08_11_102649_create_songs_table.cfc b/tests/resources/database/migrations/2020_08_11_102649_create_songs_table.cfc index 244f0ec3..6a0b766b 100755 --- a/tests/resources/database/migrations/2020_08_11_102649_create_songs_table.cfc +++ b/tests/resources/database/migrations/2020_08_11_102649_create_songs_table.cfc @@ -19,15 +19,15 @@ component { "id": 1, "title": "Ode to Joy", "download_url": "https://open.spotify.com/track/4Nd5HJn4EExnLmHtClk4QV", - "created_date": createDateTime( 2017, 07, 28, 02, 07, 00 ), - "modified_date": createDateTime( 2017, 07, 28, 02, 07, 00 ) + "created_date": "2017-07-28 02:07:00", + "modified_date": "2017-07-28 02:07:00" }, { "id": 2, "title": "Open Arms", "download_url": "https://open.spotify.com/track/1m2INxep6LfNa25OEg5jZl", - "created_date": createDateTime( 2017, 07, 28, 02, 07, 00 ), - "modified_date": createDateTime( 2017, 07, 28, 02, 07, 00 ) + "created_date": "2017-07-28 02:07:00", + "modified_date": "2017-07-28 02:07:00" } ] ); } diff --git a/tests/resources/database/migrations/2020_08_11_102650_create_jingles_table.cfc b/tests/resources/database/migrations/2020_08_11_102650_create_jingles_table.cfc index 2f6687c8..ee3a92a7 100644 --- a/tests/resources/database/migrations/2020_08_11_102650_create_jingles_table.cfc +++ b/tests/resources/database/migrations/2020_08_11_102650_create_jingles_table.cfc @@ -16,8 +16,8 @@ component { "id": 3, "title": "I Wish I Was an Oscar Mayer Weiner", "download_url": "https://open.spotify.com/track/2wyg2ln6p4gEkdqM2mueLn?si=kWBpdUz1TLymdmTro-xjtw", - "created_date": createDateTime( 2017, 07, 28, 02, 07, 00 ), - "modified_date": createDateTime( 2017, 07, 28, 02, 07, 00 ) + "created_date": "2017-07-28 02:07:00", + "modified_date": "2017-07-28 02:07:00" } ] ); diff --git a/tests/resources/database/migrations/2024_06_13_134500_create_picture_comments_table.cfc b/tests/resources/database/migrations/2024_06_13_134500_create_picture_comments_table.cfc index b5b31e49..6220a8c4 100644 --- a/tests/resources/database/migrations/2024_06_13_134500_create_picture_comments_table.cfc +++ b/tests/resources/database/migrations/2024_06_13_134500_create_picture_comments_table.cfc @@ -19,8 +19,8 @@ component { "commentable_type": "Post", "designation": "picture", "user_id": 1, - "created_date": createDateTime( 2024, 06, 13, 13, 14, 22 ), - "modified_date": createDateTime( 2024, 06, 13, 13, 14, 22 ), + "created_date": "2024-06-13 13:14:22", + "modified_date": "2024-06-13 13:14:22", "sentimentAnalysis" : '{ "analyzed": true, "magnitude": 0.8, "score": 0.6 }' } ] ); diff --git a/tests/resources/database/migrations/2025_01_24_145656_create_actors_table.cfc b/tests/resources/database/migrations/2025_01_24_145656_create_actors_table.cfc index fb7319b8..6ed05af2 100644 --- a/tests/resources/database/migrations/2025_01_24_145656_create_actors_table.cfc +++ b/tests/resources/database/migrations/2025_01_24_145656_create_actors_table.cfc @@ -12,8 +12,8 @@ component { { "id": "5B8A472F-56E8-4BD6-A03D-6157662937E3", "name": "Tom Anks", - "created_date": createDateTime( 2017, 07, 28, 02, 07, 00 ), - "modified_date": createDateTime( 2017, 07, 28, 02, 07, 00 ) + "created_date": "2017-07-28 02:07:00", + "modified_date": "2017-07-28 02:07:00" } ] ); } diff --git a/tests/specs/integration/BaseEntity/AsQuerySpec.cfc b/tests/specs/integration/BaseEntity/AsQuerySpec.cfc index abc77c93..bf4dc5f2 100644 --- a/tests/specs/integration/BaseEntity/AsQuerySpec.cfc +++ b/tests/specs/integration/BaseEntity/AsQuerySpec.cfc @@ -12,8 +12,18 @@ component extends="tests.resources.ModuleIntegrationSpec" { expect( results ).toHaveLength( 2 ); for ( var result in results ) { - result.createdDate = dateTimeFormat( result.createdDate, "yyyy-mm-dd hh:nn:ss" ); - result.modifiedDate = dateTimeFormat( result.modifiedDate, "yyyy-mm-dd hh:nn:ss" ); + result.createdDate = formatTestTimestamp( result.createdDate ); + result.modifiedDate = formatTestTimestamp( result.modifiedDate ); + var nullableKeys = [ + "email", + "streetTwo", + "favoritePost_id" + ]; + for ( var key in nullableKeys ) { + if ( isNull( result[ key ] ) ) { + result[ key ] = ""; + } + } } expect( results[ 1 ] ).toBeStruct(); @@ -74,7 +84,7 @@ component extends="tests.resources.ModuleIntegrationSpec" { expect( results[ 1 ][ "latestPostId" ] ).toBe( 523526 ); expect( results[ 2 ] ).toBeStruct(); expect( results[ 2 ] ).toHaveKey( "latestPostId" ); - expect( results[ 2 ][ "latestPostId" ] ).toBe( "" ); + expect( isNull( results[ 2 ][ "latestPostId" ] ) ? "" : results[ 2 ][ "latestPostId" ] ).toBe( "" ); } ); it( "can select an aliased entity attribute when returning query data", function() { diff --git a/tests/specs/integration/BaseEntity/AttributeCastsSpec.cfc b/tests/specs/integration/BaseEntity/AttributeCastsSpec.cfc index c5457845..b2d7eaeb 100644 --- a/tests/specs/integration/BaseEntity/AttributeCastsSpec.cfc +++ b/tests/specs/integration/BaseEntity/AttributeCastsSpec.cfc @@ -100,12 +100,10 @@ component extends="tests.resources.ModuleIntegrationSpec" { it( "preserves null values when using BooleanCast", () => { var pn = getInstance( "PhoneNumber" ).find( 3 ); expect( pn.isNullAttribute( "confirmed" ) ).toBeTrue( "[confirmed] should be considered null" ); - expect( pn.getConfirmed() ).toBe( "" ); pn.update( { "active" : false } ).refresh(); expect( pn.isNullAttribute( "confirmed" ) ).toBeTrue( "[confirmed] should remain null after saving" ); - expect( pn.getConfirmed() ).toBe( "" ); } ); it( "allows custom casts to handle null database values", () => { diff --git a/tests/specs/integration/BaseEntity/AttributeSpec.cfc b/tests/specs/integration/BaseEntity/AttributeSpec.cfc index 560a28cf..bb18c873 100644 --- a/tests/specs/integration/BaseEntity/AttributeSpec.cfc +++ b/tests/specs/integration/BaseEntity/AttributeSpec.cfc @@ -184,8 +184,14 @@ component extends="tests.resources.ModuleIntegrationSpec" { it( "shows all the attributes in the component casing", function() { var memento = getInstance( "User" ).findOrFail( 1 ).getMemento(); - memento.createdDate = dateTimeFormat( memento.createdDate, "yyyy-mm-dd hh:nn:ss" ); - memento.modifiedDate = dateTimeFormat( memento.modifiedDate, "yyyy-mm-dd hh:nn:ss" ); + memento.createdDate = formatTestTimestamp( memento.createdDate ); + memento.modifiedDate = formatTestTimestamp( memento.modifiedDate ); + if ( isNull( memento.email ) ) { + memento.email = ""; + } + if ( isNull( memento.address.streetTwo ) ) { + memento.address.streetTwo = ""; + } expect( memento ).toBe( { "id" : 1, "username" : "elpete", @@ -198,7 +204,7 @@ component extends="tests.resources.ModuleIntegrationSpec" { "modifiedDate" : "2017-07-28 02:06:36", "type" : "admin", "email" : "", - "externalId" : "1234", + "externalID" : "1234", "address" : { "streetOne" : "123 Elm Street", "streetTwo" : "", diff --git a/tests/specs/integration/BaseEntity/ChildClassSpec.cfc b/tests/specs/integration/BaseEntity/ChildClassSpec.cfc index 7b37ff1f..cbe11ac3 100644 --- a/tests/specs/integration/BaseEntity/ChildClassSpec.cfc +++ b/tests/specs/integration/BaseEntity/ChildClassSpec.cfc @@ -49,14 +49,8 @@ component extends="tests.resources.ModuleIntegrationSpec" { expect( newMemento.keyArray() ).toBe( memento.keyArray() ); for ( var key in newMemento.keyArray() ) { if ( isDate( newMemento[ key ] ) ) { - expect( - dateCompare( - newMemento[ key ], - memento[ key ], - "s" - ) - ).toBe( - 0, + expect( dateTimeFormat( newMemento[ key ], "yyyy-mm-dd HH:nn:ss" ) ).toBe( + dateTimeFormat( memento[ key ], "yyyy-mm-dd HH:nn:ss" ), "Dates are not equal to the second. Left: #dateTimeFormat( newMemento[ key ], "MM/DD/YYYY HH:nn:ss" )# - Right: #dateTimeFormat( memento[ key ], "MM/DD/YYYY HH:nn:ss" )#" ); } else { diff --git a/tests/specs/integration/BaseEntity/MementoSpec.cfc b/tests/specs/integration/BaseEntity/MementoSpec.cfc index 4792cd8d..a747d758 100644 --- a/tests/specs/integration/BaseEntity/MementoSpec.cfc +++ b/tests/specs/integration/BaseEntity/MementoSpec.cfc @@ -41,13 +41,23 @@ component extends="tests.resources.ModuleIntegrationSpec" { } ); it( "returns retrieved relationships", function() { - var post = getInstance( "Post" ).with( "author" ).findOrFail( 1245 ); - var memento = post.getMemento( includes = "author" ); - memento.createdDate = dateTimeFormat( memento.createdDate, "yyyy-mm-dd hh:nn:ss" ); - memento.modifiedDate = dateTimeFormat( memento.modifiedDate, "yyyy-mm-dd hh:nn:ss" ); - memento.publishedDate = dateTimeFormat( memento.publishedDate, "yyyy-mm-dd hh:nn:ss" ); - memento.author.createdDate = dateTimeFormat( memento.author.createdDate, "yyyy-mm-dd hh:nn:ss" ); - memento.author.modifiedDate = dateTimeFormat( memento.author.modifiedDate, "yyyy-mm-dd hh:nn:ss" ); + var post = getInstance( "Post" ).with( "author" ).findOrFail( 1245 ); + var memento = post.getMemento( includes = "author" ); + memento.createdDate = formatTestTimestamp( memento.createdDate ); + memento.modifiedDate = formatTestTimestamp( memento.modifiedDate ); + memento.publishedDate = formatTestTimestamp( memento.publishedDate ); + memento.author.createdDate = formatTestTimestamp( memento.author.createdDate ); + memento.author.modifiedDate = formatTestTimestamp( memento.author.modifiedDate ); + memento.post_pk = memento.post_pk & ""; + memento.user_id = memento.user_id & ""; + memento.author.id = memento.author.id & ""; + memento.author.favoritePost_id = memento.author.favoritePost_id & ""; + if ( isNull( memento.author.email ) ) { + memento.author.email = ""; + } + if ( isNull( memento.author.address.streetTwo ) ) { + memento.author.address.streetTwo = ""; + } expect( memento ).toBe( { "post_pk" : "1245", "body" : "My awesome post body", diff --git a/tests/specs/integration/BaseEntity/NullValuesSpec.cfc b/tests/specs/integration/BaseEntity/NullValuesSpec.cfc index d894fa79..0d6a9288 100644 --- a/tests/specs/integration/BaseEntity/NullValuesSpec.cfc +++ b/tests/specs/integration/BaseEntity/NullValuesSpec.cfc @@ -2,10 +2,10 @@ component extends="tests.resources.ModuleIntegrationSpec" { function run() { describe( "Null Values Spec", function() { - it( "returns null values as a string by default", function() { + it( "returns database nulls as null attributes by default", function() { var user = getInstance( "User" ).findOrFail( 3 ); - expect( user.getCountryId() ).toBe( "" ); - expect( user.getMemento().countryId ).toBe( "" ); + expect( user.isNullAttribute( "countryId" ) ).toBeTrue(); + expect( user.isNullValue( "countryId", user.getMemento().countryId ) ).toBeTrue(); } ); it( "saves a column containing an empty string as null in the database by default", function() { diff --git a/tests/specs/integration/BaseEntity/ReadOnlyPropertySpec.cfc b/tests/specs/integration/BaseEntity/ReadOnlyPropertySpec.cfc index 6caf7649..8a22601d 100644 --- a/tests/specs/integration/BaseEntity/ReadOnlyPropertySpec.cfc +++ b/tests/specs/integration/BaseEntity/ReadOnlyPropertySpec.cfc @@ -17,7 +17,7 @@ component extends="tests.resources.ModuleIntegrationSpec" { it( "prevents read-only properties from being saved", function() { var link = getInstance( "Link" ).findOrFail( 1 ); expect( link.getUrl() ).toBe( "http://example.com/some-link" ); - expect( dateTimeFormat( link.getCreatedDate(), "YYYY-MM-dd HH:nn:ss" ) ).toBe( "2017-07-28 02:07:00" ); + expect( formatTestTimestamp( link.getCreatedDate() ) ).toBe( "2017-07-28 02:07:00" ); link.setUrl( "https://example.com/" ) .setCreatedDate( now() ) @@ -26,7 +26,7 @@ component extends="tests.resources.ModuleIntegrationSpec" { link.refresh(); expect( link.getUrl() ).toBe( "https://example.com/" ); - expect( dateTimeFormat( link.getCreatedDate(), "YYYY-MM-dd HH:nn:ss" ) ).toBe( "2017-07-28 02:07:00" ); + expect( formatTestTimestamp( link.getCreatedDate() ) ).toBe( "2017-07-28 02:07:00" ); } ); it( "prevents create from setting read-only properties", function() { diff --git a/tests/specs/integration/BaseEntity/Relationships/BelongsToSpec.cfc b/tests/specs/integration/BaseEntity/Relationships/BelongsToSpec.cfc index 387a4db5..56e1123e 100644 --- a/tests/specs/integration/BaseEntity/Relationships/BelongsToSpec.cfc +++ b/tests/specs/integration/BaseEntity/Relationships/BelongsToSpec.cfc @@ -159,7 +159,7 @@ component extends="tests.resources.ModuleIntegrationSpec" { post.author() .dissociate() .save(); - expect( post.retrieveAttribute( "user_id" ) ).toBe( "" ); + expect( post.isNullAttribute( "user_id" ) ).toBeTrue(); expect( getInstance( "User" ) .find( userId ) diff --git a/tests/specs/integration/BaseEntity/SaveSpec.cfc b/tests/specs/integration/BaseEntity/SaveSpec.cfc index 61a9d2ef..9ffc5f6d 100644 --- a/tests/specs/integration/BaseEntity/SaveSpec.cfc +++ b/tests/specs/integration/BaseEntity/SaveSpec.cfc @@ -84,7 +84,7 @@ component extends="tests.resources.ModuleIntegrationSpec" { existingUser.save(); var userRowsPostSave = queryExecute( "SELECT * FROM users" ); expect( userRowsPostSave ).toHaveLength( 5 ); - expect( userRowsPostSave.email ).toBe( "" ); + expect( getInstance( "User" ).findOrFail( 1 ).isNullAttribute( "email" ) ).toBeTrue(); } ); it( "uses the sqltype attribute if present for each column", function() { diff --git a/tests/specs/integration/CBORMCompatEntitySpec.cfc b/tests/specs/integration/CBORMCompatEntitySpec.cfc index 15199c63..5e6a2582 100644 --- a/tests/specs/integration/CBORMCompatEntitySpec.cfc +++ b/tests/specs/integration/CBORMCompatEntitySpec.cfc @@ -182,8 +182,8 @@ component extends="tests.resources.ModuleIntegrationSpec" { describe( "criteria builder compatibility", function() { it( "between", function() { - var rightNow = dateFormat( now(), "mm/dd/yyyy" ); - var lastWeek = dateFormat( dateAdd( "d", -7, rightNow ), "mm/dd/yyyy" ); + var rightNow = now(); + var lastWeek = dateAdd( "d", -7, rightNow ); var actual = user .newCriteria() .between( "created_date", rightNow, lastWeek )