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 178ce1eeaf groovysh additional tests (cont'd)
178ce1eeaf is described below

commit 178ce1eeaf8a5c46d3a8fde33118d943a28e296a
Author: Paul King <[email protected]>
AuthorDate: Sat May 9 23:11:02 2026 +1000

    groovysh additional tests (cont'd)
---
 .../groovy/groovysh/commands/HelpFlagTest.groovy   | 82 ++++++++++++++++++
 .../groovy/groovysh/commands/ResetTest.groovy      | 75 ++++++++++++++++
 .../groovy/groovysh/commands/VarsTest.groovy       | 99 ++++++++++++++++++++++
 3 files changed, 256 insertions(+)

diff --git 
a/subprojects/groovy-groovysh/src/test/groovy/org/apache/groovy/groovysh/commands/HelpFlagTest.groovy
 
b/subprojects/groovy-groovysh/src/test/groovy/org/apache/groovy/groovysh/commands/HelpFlagTest.groovy
new file mode 100644
index 0000000000..8c0c386388
--- /dev/null
+++ 
b/subprojects/groovy-groovysh/src/test/groovy/org/apache/groovy/groovysh/commands/HelpFlagTest.groovy
@@ -0,0 +1,82 @@
+/*
+ *  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.groovysh.commands
+
+import org.junit.jupiter.api.DynamicTest
+import org.junit.jupiter.api.TestFactory
+
+import java.util.stream.Stream
+
+/**
+ * Cheap blanket coverage for every Groovy command's {@code --help} flag.
+ * One dynamic test per registered command — adding a new command without
+ * wiring its {@code CmdDesc} or {@code maybePrintHelp} call surfaces here
+ * immediately rather than waiting for a user to type {@code /yourcmd --help}.
+ *
+ * <p>The set of names comes from {@link 
org.jline.console.CommandRegistry#commandNames}
+ * at runtime, so the test self-adjusts to environment-conditional commands
+ * (e.g. {@code /grab} only registers when Ivy is on the classpath).
+ */
+class HelpFlagTest extends SystemTestSupport {
+
+    @TestFactory
+    Stream<DynamicTest> everyRegisteredCommandRespondsToHelpFlag() {
+        def names = (groovy.commandNames() as List).toSorted()
+        assert !names.empty, 'no Groovy commands registered'
+        return names.stream().map { String name ->
+            DynamicTest.dynamicTest("$name --help") {
+                int printerBefore = printer.output.size()
+                int terminalBefore = terminalOutput().length()
+                try {
+                    system.execute("$name --help")
+                } catch (Exception e) {
+                    throw new AssertionError("'$name --help' threw: 
$e.message", e)
+                }
+                int printerAfter = printer.output.size()
+                int terminalAfter = terminalOutput().length()
+                // Help can land on either sink: maybePrintHelp goes through
+                // the printer; commands that delegate to JLine's parseOptions
+                // (e.g. /doc) write to the terminal. Either is acceptable.
+                assert printerAfter > printerBefore || terminalAfter > 
terminalBefore,
+                        "'$name --help' produced no output via printer or 
terminal"
+            }
+        }
+    }
+
+    @TestFactory
+    Stream<DynamicTest> everyRegisteredCommandRespondsToShortHelpFlag() {
+        // Same enumeration, exercising the `-?` shorthand. maybePrintHelp
+        // checks both forms; this confirms neither rots.
+        def names = (groovy.commandNames() as List).toSorted()
+        return names.stream().map { String name ->
+            DynamicTest.dynamicTest("$name -?") {
+                int printerBefore = printer.output.size()
+                int terminalBefore = terminalOutput().length()
+                try {
+                    system.execute("$name -?")
+                } catch (Exception e) {
+                    throw new AssertionError("'$name -?' threw: $e.message", e)
+                }
+                assert printer.output.size() > printerBefore
+                        || terminalOutput().length() > terminalBefore,
+                        "'$name -?' produced no output via printer or terminal"
+            }
+        }
+    }
+}
diff --git 
a/subprojects/groovy-groovysh/src/test/groovy/org/apache/groovy/groovysh/commands/ResetTest.groovy
 
b/subprojects/groovy-groovysh/src/test/groovy/org/apache/groovy/groovysh/commands/ResetTest.groovy
new file mode 100644
index 0000000000..91199b8f60
--- /dev/null
+++ 
b/subprojects/groovy-groovysh/src/test/groovy/org/apache/groovy/groovysh/commands/ResetTest.groovy
@@ -0,0 +1,75 @@
+/*
+ *  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.groovysh.commands
+
+import org.junit.jupiter.api.Test
+
+/**
+ * Tests for the {@code /reset} command, which clears the engine's tracked
+ * imports / types / methods / variable-snippets via {@link
+ * org.apache.groovy.groovysh.jline.GroovyEngine#reset}.
+ */
+class ResetTest extends SystemTestSupport {
+
+    @Test
+    void resetClearsTypesMethodsVariablesAndImports() {
+        // Populate every tracked map so /reset has something to do. The
+        // fixture engine starts empty — anything left after /reset is a leak.
+        system.execute('class C {}')
+        system.execute('def square(int x) { x * x }')
+        system.execute('int n = 42')
+        system.execute('import java.awt.Point')
+
+        assert engine.types.containsKey('C')
+        assert engine.methodNames.contains('square')
+        assert engine.variables.containsKey('n')
+        assert !engine.imports.isEmpty()
+
+        system.execute('/reset')
+
+        assert engine.types.isEmpty()
+        assert engine.methodNames.isEmpty()
+        assert engine.variables.isEmpty()
+        assert engine.imports.isEmpty()
+    }
+
+    @Test
+    void resetIsIdempotent() {
+        // Two resets in a row on a virgin engine — no exception, state stays
+        // empty. Guards against a future engine.reset() that assumes prior
+        // state existed.
+        system.execute('/reset')
+        system.execute('/reset')
+        assert engine.types.isEmpty()
+        assert engine.methodNames.isEmpty()
+    }
+
+    @Test
+    void resetDoesNotEvictBindingVariables() {
+        // /reset clears *tracked source* (the buffer) but should not touch
+        // shared/binding variables. Users rely on this so that values
+        // computed in the REPL survive a buffer wipe.
+        engine.put('keepMe', 'still here')
+        system.execute('class Tmp {}')
+        system.execute('/reset')
+        assert engine.types.isEmpty()
+        assert engine.hasVariable('keepMe')
+        assert engine.execute('keepMe') == 'still here'
+    }
+}
diff --git 
a/subprojects/groovy-groovysh/src/test/groovy/org/apache/groovy/groovysh/commands/VarsTest.groovy
 
b/subprojects/groovy-groovysh/src/test/groovy/org/apache/groovy/groovysh/commands/VarsTest.groovy
new file mode 100644
index 0000000000..988e501b39
--- /dev/null
+++ 
b/subprojects/groovy-groovysh/src/test/groovy/org/apache/groovy/groovysh/commands/VarsTest.groovy
@@ -0,0 +1,99 @@
+/*
+ *  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.groovysh.commands
+
+import org.junit.jupiter.api.Test
+
+/**
+ * Tests for the {@code /vars} command, which lists or removes tracked
+ * <em>typed</em> variable declarations (the snippets matched by
+ * {@code GroovyEngine.PATTERN_VAR_DEF}). Unscoped assignments like
+ * {@code x = 5} create binding/shared variables and don't show up in
+ * {@code /vars} — those are observable via {@code GroovyEngine.hasVariable},
+ * not via this command.
+ */
+class VarsTest extends SystemTestSupport {
+
+    @Test
+    void varsListsTrackedTypedDeclarations() {
+        // Empty registry initially.
+        system.execute('/vars')
+        def initial = printer.output.join()
+        assert !initial.contains('int n = 42')
+
+        system.execute('int n = 42')
+        system.execute('def msg = "hi"')
+
+        assert engine.variables.keySet() == ['n', 'msg'] as Set
+
+        printer.output.clear()
+        system.execute('/vars')
+        def listing = printer.output.join()
+        assert listing.contains('int n = 42')
+        assert listing.contains('def msg = "hi"')
+    }
+
+    @Test
+    void varsByNameShowsOnlyThatSource() {
+        system.execute('int n = 42')
+        system.execute('def msg = "hi"')
+
+        printer.output.clear()
+        system.execute('/vars n')
+        def out = printer.output.join()
+        assert out.contains('int n = 42')
+        assert !out.contains('def msg = "hi"')
+    }
+
+    @Test
+    void varsDeleteRemovesTheTrackedDeclaration() {
+        system.execute('int n = 42')
+        system.execute('def msg = "hi"')
+        assert engine.variables.containsKey('n')
+
+        system.execute('/vars -d n')
+
+        assert !engine.variables.containsKey('n')
+        assert engine.variables.containsKey('msg')
+    }
+
+    @Test
+    void varsDeleteUnknownNameIsHarmless() {
+        // /vars -d on an unknown variable should not throw or corrupt the
+        // registry — mirrors the pattern other delete-by-name commands
+        // promise (TypesTest, MethodsTest).
+        system.execute('int n = 42')
+        def before = engine.variables.keySet().toSet()
+        system.execute('/vars -d noSuchVar')
+        assert engine.variables.keySet().toSet() == before
+    }
+
+    @Test
+    void varsDeleteAllEmptiesTheRegistry() {
+        // The wildcard '*' clears every tracked declaration in one go, per
+        // maybeRemoveItem's name == '*' branch.
+        system.execute('int n = 42')
+        system.execute('def msg = "hi"')
+        assert engine.variables.size() == 2
+
+        system.execute('/vars -d *')
+
+        assert engine.variables.isEmpty()
+    }
+}

Reply via email to