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()
+ }
+}