You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2026/06/03 22:10:53 UTC

(groovy) branch master updated: GROOVY-12059: groovy-contracts: test nested closures in postconditions

This is an automated email from the ASF dual-hosted git repository.

paulk-asert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new 13b009a324 GROOVY-12059: groovy-contracts: test nested closures in postconditions
13b009a324 is described below

commit 13b009a3243716c000d3ceb7db681883d98bf76b
Author: Paul King <pa...@asert.com.au>
AuthorDate: Thu Jun 4 08:09:51 2026 +1000

    GROOVY-12059: groovy-contracts: test nested closures in postconditions
    
    The fix already covered @Ensures (the method/constructor path in
    AnnotationClosureVisitor recomputes variable scopes for both pre- and
    postconditions), but the original commit only added nested-closure tests
    for @Invariant and @Requires. This adds the matching @Ensures coverage:
    nested closures with an explicit parameter, the implicit 'it', and
    references to both the method parameter and 'result'.
    
    Assisted-by: Claude Opus 4.8 (1M context) <no...@anthropic.com>
---
 .../post/NestedClosurePostconditionTests.groovy    | 73 ++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/subprojects/groovy-contracts/src/test/groovy/org/apache/groovy/contracts/tests/post/NestedClosurePostconditionTests.groovy b/subprojects/groovy-contracts/src/test/groovy/org/apache/groovy/contracts/tests/post/NestedClosurePostconditionTests.groovy
new file mode 100644
index 0000000000..e97b7c9be0
--- /dev/null
+++ b/subprojects/groovy-contracts/src/test/groovy/org/apache/groovy/contracts/tests/post/NestedClosurePostconditionTests.groovy
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.contracts.tests.post
+
+import org.apache.groovy.contracts.PostconditionViolation
+import org.apache.groovy.contracts.tests.basic.BaseTestClass
+import org.junit.jupiter.api.Test
+
+// GROOVY-12059: postconditions may contain nested closures that declare their own parameters,
+// use the implicit 'it', and reference the enclosing method's parameters / result.
+class NestedClosurePostconditionTests extends BaseTestClass {
+
+    def source = '''
+import groovy.contracts.*
+
+class A {
+
+  @Ensures({ result -> result.every { n -> n > 0 } })
+  List<Integer> incExplicit(List<Integer> ns) { ns.collect { it + 1 } }
+
+  @Ensures({ result -> result.every { it > 0 } })
+  List<Integer> incImplicit(List<Integer> ns) { ns.collect { it + 1 } }
+
+  @Ensures({ result -> result.indices.every { result[it] > ns[it] } })
+  List<Integer> incIndexed(List<Integer> ns) { ns.collect { it + 1 } }
+}
+'''
+
+    @Test
+    void nested_closure_with_explicit_parameter() {
+        def a = create_instance_of(source)
+
+        assert a.incExplicit([1, 2, 3]) == [2, 3, 4]
+
+        shouldFail PostconditionViolation, {
+            a.incExplicit([-1, -2, -3])
+        }
+    }
+
+    @Test
+    void nested_closure_with_implicit_it() {
+        def a = create_instance_of(source)
+
+        assert a.incImplicit([1, 2, 3]) == [2, 3, 4]
+
+        shouldFail PostconditionViolation, {
+            a.incImplicit([-1, -2, -3])
+        }
+    }
+
+    @Test
+    void nested_closure_referencing_method_parameter_and_result() {
+        def a = create_instance_of(source)
+
+        assert a.incIndexed([1, 2, 3]) == [2, 3, 4]
+    }
+}