This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch GROOVY-11779 in repository https://gitbox.apache.org/repos/asf/groovy.git
commit c65df1f315f8b45ea2146795191f0eb9b9863e70 Author: Eric Milles <[email protected]> AuthorDate: Sun Nov 23 20:44:36 2025 -0600 minor refactor --- .../groovy/runtime/DefaultGroovyMethods.java | 23 ++++++---- .../{Groovy3658Bug.groovy => Groovy3658.groovy} | 28 ++++++------ src/test/groovy/groovy/ClosureMethodTest.groovy | 51 ++++++++++++++-------- src/test/groovy/groovy/ExpandoPropertyTest.groovy | 27 ++++++++---- 4 files changed, 80 insertions(+), 49 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java index ac078870e7..13b88d5ceb 100644 --- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java +++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java @@ -4603,28 +4603,35 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport { * Generates a detailed dump string of an object showing its class, * hashCode and all accessible fields. * + * <pre class="groovyTestCase"> + * assert null.dump() == 'null' + * </pre> + * * @param self an object * @return the dump representation * @since 1.0 */ public static String dump(Object self) { - if (self == null) { + if (self == null || self instanceof NullObject) { return "null"; } - StringBuilder buffer = new StringBuilder("<"); + StringBuilder buffer = new StringBuilder(64); + buffer.append('<'); Class<?> klass = self.getClass(); buffer.append(klass.getName()); - buffer.append("@"); + buffer.append('@'); buffer.append(Integer.toHexString(self.hashCode())); boolean groovyObject = self instanceof GroovyObject; while (klass != null) { for (Field field : klass.getDeclaredFields()) { - if (Modifier.isStatic(field.getModifiers()) || (groovyObject && "metaClass".equals(field.getName()))) { + String fieldName = field.getName(); + if (Modifier.isStatic(field.getModifiers()) + || (groovyObject && "metaClass".equals(fieldName))) { continue; } - buffer.append(" "); - buffer.append(field.getName()); - buffer.append("="); + buffer.append(' '); + buffer.append(fieldName); + buffer.append('='); if (!field.canAccess(self)) { // GROOVY-9144 if (!SystemUtil.getBooleanSafe("groovy.force.illegal.access") || ReflectionUtils.makeAccessibleInPrivilegedAction(field).isEmpty()) { @@ -4640,7 +4647,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport { } klass = klass.getSuperclass(); } - buffer.append(">"); + buffer.append('>'); return buffer.toString(); } diff --git a/src/test/groovy/bugs/Groovy3658Bug.groovy b/src/test/groovy/bugs/Groovy3658.groovy similarity index 67% rename from src/test/groovy/bugs/Groovy3658Bug.groovy rename to src/test/groovy/bugs/Groovy3658.groovy index fa12c0d283..54ab26b292 100644 --- a/src/test/groovy/bugs/Groovy3658Bug.groovy +++ b/src/test/groovy/bugs/Groovy3658.groovy @@ -18,22 +18,24 @@ */ package bugs -import groovy.test.GroovyTestCase +import org.junit.jupiter.api.Test -class Groovy3658Bug extends GroovyTestCase { +final class Groovy3658 { + + @Test void testConstructorWithParameterWithInitialValueAsStaticMethodCallResult() { - Groovy3658BugHelper bug2 = new Groovy3658BugHelper('person', 'tag') - assert bug2.dump() != null + Pogo pogo = new Pogo('person') + assert pogo.dump() != null + pogo = new Pogo('person', 'x') + assert pogo.dump() != null } -} -class Groovy3658BugHelper { - Groovy3658BugHelper(final String name1, final String name2 = f(name1)) { - this.name1 = name1 - this.name2 = name2 - } - static String f(String s) { - s + static class Pogo { + Pogo(String name1, String name2 = f(name1)) { + this.name1 = name1 + this.name2 = name2 + } + static String f(String s) { s } + final String name1, name2 } - final String name1, name2 } diff --git a/src/test/groovy/groovy/ClosureMethodTest.groovy b/src/test/groovy/groovy/ClosureMethodTest.groovy index 0fab4be429..92939ca6b7 100644 --- a/src/test/groovy/groovy/ClosureMethodTest.groovy +++ b/src/test/groovy/groovy/ClosureMethodTest.groovy @@ -18,14 +18,17 @@ */ package groovy -import groovy.test.GroovyTestCase import org.codehaus.groovy.runtime.DefaultGroovyMethods as DGM +import org.junit.jupiter.api.Test + +import static groovy.test.GroovyAssert.shouldFail /** * Tests the various Closure methods in Groovy */ -class ClosureMethodTest extends GroovyTestCase { +final class ClosureMethodTest { + @Test void testListCollect() { def list = [1, 2, 3, 4] def answer = list.collect { item -> return item * 2 } @@ -34,6 +37,7 @@ class ClosureMethodTest extends GroovyTestCase { assert answer == expected } + @Test void testMapCollect() { def map = [1: 2, 2: 4, 3: 6, 4: 8] def answer = map.collect { e -> return e.key + e.value } @@ -47,6 +51,7 @@ class ClosureMethodTest extends GroovyTestCase { assert answer.get(3) == 12 } + @Test void testObjectFindResult() { def oneToTenObjectIterator = { def i = 1 @@ -74,6 +79,7 @@ class ClosureMethodTest extends GroovyTestCase { } } + @Test void testListFind() { def list = ["a", "b", "c"] def answer = list.find { item -> item == "b" } @@ -82,6 +88,7 @@ class ClosureMethodTest extends GroovyTestCase { assert answer == null } + @Test void testListFindResult() { Collection<Integer> oneThroughFive = [1, 2, 3, 4, 5] @@ -110,6 +117,7 @@ class ClosureMethodTest extends GroovyTestCase { } } + @Test void testMapFind() { def map = [1: 2, 2: 4, 3: 6, 4: 8] def answer = map.find { entry -> entry.value == 6 } @@ -129,6 +137,7 @@ class ClosureMethodTest extends GroovyTestCase { assert answer.value == 4 } + @Test void testMapFindResult() { def oneThroughFourMap = [a: 1, b: 2, c: 3, d: 4] @@ -153,6 +162,7 @@ class ClosureMethodTest extends GroovyTestCase { } } + @Test void testListFindAll() { def list = [20, 5, 40, 2] def answer = list.findAll { item -> item < 10 } @@ -160,6 +170,7 @@ class ClosureMethodTest extends GroovyTestCase { assert answer == [5, 2] } + @Test void testMapFindAll() { def map = [1: 2, 2: 4, 3: 6, 4: 8] def answer = map.findAll { entry -> entry.value > 5 } @@ -173,6 +184,7 @@ class ClosureMethodTest extends GroovyTestCase { assert values == [6, 8], "Expected [6, 8] but was $values" } + @Test void testMapEach() { def count = 0 def map = [1: 2, 2: 4, 3: 6, 4: 8] @@ -182,6 +194,7 @@ class ClosureMethodTest extends GroovyTestCase { assert count == 50 } + @Test void testMapEachWith2Params() { def count = 0 def map = [1: 2, 2: 4, 3: 6, 4: 8] @@ -191,6 +204,7 @@ class ClosureMethodTest extends GroovyTestCase { assert count == 50 } + @Test void testListEach() { def count = 0 def list = [1, 2, 3, 4] @@ -200,6 +214,7 @@ class ClosureMethodTest extends GroovyTestCase { assert count == 20 } + @Test void testListEvery() { assert [1, 2, 3, 4].every { i -> return i < 5 } assert [1, 2, 7, 4].every { i -> i < 5 } == false @@ -207,6 +222,7 @@ class ClosureMethodTest extends GroovyTestCase { assert ![a: 1, b: 2, c: 3].every { k, v -> k < 'd' && v < 3 } } + @Test void testListAny() { assert [1, 2, 3, 4].any { i -> return i < 5 } assert [1, 2, 3, 4].any { i -> i > 3 } @@ -216,16 +232,19 @@ class ClosureMethodTest extends GroovyTestCase { assert !isThereAFourValue } + @Test void testJoin() { def value = [1, 2, 3].join('-') assert value == "1-2-3" } + @Test void testListReverse() { def value = [1, 2, 3, 4].reverse() assert value == [4, 3, 2, 1] } + @Test void testListInject() { def value = [1, 2, 3].inject('counting: ') { str, item -> str + item } assert value == "counting: 123" @@ -235,6 +254,7 @@ class ClosureMethodTest extends GroovyTestCase { assert value == 10 } + @Test void testOneArgListInject() { // Check basic functionality def value = [1, 2, 3].inject { c, item -> c + item } @@ -247,25 +267,20 @@ class ClosureMethodTest extends GroovyTestCase { assert value.inject { a, b -> a.intersect(b) } == ['tim'] // Check edges - try { + shouldFail(NoSuchElementException) { [].inject { a, b -> a + b } == null - fail("inject(Closure) on an empty list should throw a NoSuchElementException") - } - catch (NoSuchElementException e) { } assert [1].inject { a, b -> a + b } == 1 assert [1, 2].inject { a, b -> a + b } == 3 } + @Test void testOneArgObjectInject() { def value = ([1, 2, 3, 4] as Object[]).inject { c, item -> c + item } assert value == 10 - try { + shouldFail(NoSuchElementException) { ([] as Object[]).inject { c, item -> c + item } - fail("inject(Closure) on an empty Object[] should throw a NoSuchElementException") - } - catch (NoSuchElementException e) { } value = ([1] as Object[]).inject { c, item -> c + item } @@ -275,12 +290,9 @@ class ClosureMethodTest extends GroovyTestCase { def iter = [hasNext: { -> i < 5 }, next: { -> i++ }] as Iterator assert iter.inject { a, b -> a * b } == 24 - try { + shouldFail(NoSuchElementException) { iter = [hasNext: { -> false }, next: { -> null }] as Iterator iter.inject { a, b -> a * b } - fail("inject(Closure) on an exhausted iterator should throw a NoSuchElementException") - } - catch (NoSuchElementException e) { } i = 1 @@ -288,6 +300,7 @@ class ClosureMethodTest extends GroovyTestCase { assert iter.inject { a, b -> a * b } == 1 } + @Test void testOldAndNewStylesYieldSameResults() { def items = [1000, 200, 30, 4] def twice = { int x -> x * 2 } @@ -311,6 +324,7 @@ class ClosureMethodTest extends GroovyTestCase { addTwiceFourWays.inject(checkEqual) } + @Test void testObjectInject() { def value = [1: 1, 2: 2, 3: 3].inject('counting: ') { str, item -> str + item.value } assert value == "counting: 123" @@ -318,6 +332,7 @@ class ClosureMethodTest extends GroovyTestCase { assert value == 6 } + @Test void testIteratorInject() { def value = [1: 1, 2: 2, 3: 3].iterator().inject('counting: ') { str, item -> str + item.value } assert value == "counting: 123" @@ -325,16 +340,13 @@ class ClosureMethodTest extends GroovyTestCase { assert value == 6 } - void testDump() { - def text = dump() - assert text != null && text.startsWith("<") - } - + @Test void testInspect() { def text = [1, 2, 'three'].inspect() assert text == "[1, 2, 'three']" } + @Test void testTokenize() { def text = "hello-there-how-are-you" def answer = [] @@ -344,6 +356,7 @@ class ClosureMethodTest extends GroovyTestCase { assert answer == ['hello', 'there', 'how', 'are', 'you'] } + @Test void testUpto() { def answer = [] 1.upto(5) { answer.add(it) } diff --git a/src/test/groovy/groovy/ExpandoPropertyTest.groovy b/src/test/groovy/groovy/ExpandoPropertyTest.groovy index 8d97da8353..5bcddd8311 100644 --- a/src/test/groovy/groovy/ExpandoPropertyTest.groovy +++ b/src/test/groovy/groovy/ExpandoPropertyTest.groovy @@ -18,10 +18,13 @@ */ package groovy -import groovy.test.GroovyTestCase +import org.junit.jupiter.api.Test -class ExpandoPropertyTest extends GroovyTestCase { +import static groovy.test.GroovyAssert.shouldFail +final class ExpandoPropertyTest { + + @Test void testExpandoProperty() { def foo = new Expando() @@ -34,6 +37,7 @@ class ExpandoPropertyTest extends GroovyTestCase { assert foo.properties.size() == 2 } + @Test void testExpandoMethods() { def foo = new Expando() @@ -52,6 +56,7 @@ class ExpandoPropertyTest extends GroovyTestCase { shouldFail { foo.nameLength(1, 2) } } + @Test void testExpandoMethodCloning() { def foo = new Expando() def c = { @@ -64,12 +69,14 @@ class ExpandoPropertyTest extends GroovyTestCase { assert !(c.delegate instanceof Expando) } + @Test void testExpandoConstructorAndToString() { def foo = new Expando(type: "sometype", value: 42) assert foo.toString() == "{type=sometype, value=42}" assert "${foo}" == "{type=sometype, value=42}" } + @Test void testExpandoMethodOverrides() { def equals = { Object obj -> return obj.value == value } def foo = new Expando(type: "myfoo", value: 42, equals: equals) @@ -96,6 +103,7 @@ class ExpandoPropertyTest extends GroovyTestCase { assert foo.toString() == "Type: myfoo, Value: 42" } + @Test void testArrayAccessOnThis() { def a = new FancyExpando([a: 1, b: 2]) a.update([b: 5, a: 2]) @@ -104,20 +112,21 @@ class ExpandoPropertyTest extends GroovyTestCase { assert a.b == 5 } + @Test void testExpandoClassProperty() { def e = new Expando() e.class = "hello world" assert e.class == "hello world" } -} -class FancyExpando extends Expando { - FancyExpando(args) { super(args) } + static class FancyExpando extends Expando { + FancyExpando(args) { super(args) } - def update(args) { - for (e in args) this[e.key] = e.value // using 'this' - } + def update(args) { + for (e in args) this[e.key] = e.value // using 'this' + } - String toString() { dump() } + String toString() { dump() } + } }
