This is an automated email from the ASF dual-hosted git repository. borinquenkid pushed a commit to branch test/document-datamapping-core-finders in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 6d5de5bda6ad2219aa9dd13cf8c024354075f2f7 Author: Walter Duque de Estrada <[email protected]> AuthorDate: Sat Aug 15 14:11:04 2026 -0500 Address contrarian review of the finders composition refactor - Fix a dangling Javadoc cross-reference in SingleResultFinderSpec to a nonexistent "field-ordering note". - Add an explicit 0 * query.projections() assertion in RxListResultFinderSpec so the "no distinct()" quirk documented in RxListResultFinder's class Javadoc is self-verifying rather than incidental. - Add a createFinderInvocation-level test for the And/Or literal-split quirk in DynamicFinderSpec; previously only buildMatchSpec (the compile-time matcher) exercised it, leaving the actual runtime path finders call unverified. Co-Authored-By: Claude Sonnet 5 <[email protected]> --- .../grails/datastore/gorm/finders/DynamicFinderSpec.groovy | 14 ++++++++++++++ .../datastore/gorm/finders/SingleResultFinderSpec.groovy | 7 ++++--- .../grails/gorm/rx/finders/RxListResultFinderSpec.groovy | 3 +++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/finders/DynamicFinderSpec.groovy b/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/finders/DynamicFinderSpec.groovy index 71d4738907..360024a4ae 100644 --- a/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/finders/DynamicFinderSpec.groovy +++ b/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/finders/DynamicFinderSpec.groovy @@ -288,6 +288,20 @@ class DynamicFinderSpec extends Specification { thrown(MissingMethodException) } + void "createFinderInvocation's naive literal split on the And/Or operator can split inside an unrelated property name"() { + when: + // Mirrors the "buildMatchSpec's naive literal split..." test above, but through the actual + // runtime entry point real finders call, proving the split logic really is identical - not + // merely asserted to be by comment. "findByAndroidVersionAndTitle" is meant to be + // "androidVersion And title", but querySequence.split("And") splits on every literal + // occurrence of "And", including the one starting "AndroidVersion" itself, producing an + // empty leading segment. + findByGrammar.createFinderInvocation(FinderTestEntity, 'findByAndroidVersionAndTitle', null, ['x', 'y'] as Object[]) + + then: + thrown(IllegalArgumentException) + } + void "createFinderInvocation rethrows a ConversionException as MissingMethodException for a non-Basic property"() { given: // "age" (a plain Integer, non-Basic property) with an argument that genuinely needs diff --git a/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/finders/SingleResultFinderSpec.groovy b/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/finders/SingleResultFinderSpec.groovy index d62ec34abe..c7cbfa7dfc 100644 --- a/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/finders/SingleResultFinderSpec.groovy +++ b/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/finders/SingleResultFinderSpec.groovy @@ -34,9 +34,10 @@ import spock.lang.Unroll * Exercises {@link SingleResultFinder} - the composed replacement for the deleted * AbstractFindByFinder/FindByFinder/FindByBooleanFinder/FindOrCreateByFinder/FindOrSaveByFinder * class hierarchy. Every factory method builds its own {@link DynamicFinder} grammar instance - * (never shared across finders - see {@code DynamicFinderSpec}'s field-ordering note for why that - * matters), so each test constructs the specific factory under test directly rather than reusing - * a single shared field. + * (never shared across finders, since a shared instance would be a real thread-safety hazard + * given finder instances are long-lived and invoked from arbitrary request threads), so each + * test constructs the specific factory under test directly rather than reusing a single shared + * field. */ class SingleResultFinderSpec extends Specification { diff --git a/grails-datamapping-rx/src/test/groovy/org/grails/gorm/rx/finders/RxListResultFinderSpec.groovy b/grails-datamapping-rx/src/test/groovy/org/grails/gorm/rx/finders/RxListResultFinderSpec.groovy index bd11405c3b..e96cca8f39 100644 --- a/grails-datamapping-rx/src/test/groovy/org/grails/gorm/rx/finders/RxListResultFinderSpec.groovy +++ b/grails-datamapping-rx/src/test/groovy/org/grails/gorm/rx/finders/RxListResultFinderSpec.groovy @@ -92,6 +92,9 @@ class RxListResultFinderSpec extends Specification { 1 * query.add({ Query.Criterion it -> it instanceof Query.Junction }) 1 * query.findAll() >> observable 0 * query.findAll(_) + // Unlike the synchronous ListResultFinder, RxListResultFinder never applies a distinct() + // projection - a pre-existing sync/rx inconsistency this refactor preserves, not fixes. + 0 * query.projections() result.is(observable) }
