From 69f54879ef38c7427758d2788b9d173e49b78d25 Mon Sep 17 00:00:00 2001 From: jhz <070jhz@proton.me> Date: Sun, 8 Jun 2025 01:43:16 +0200 Subject: [PATCH 1/5] Closes #13275 : export footer only for commands that support --output --- jabkit/src/main/java/org/jabref/JabKit.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jabkit/src/main/java/org/jabref/JabKit.java b/jabkit/src/main/java/org/jabref/JabKit.java index 151faa17e48..9475e5d2912 100644 --- a/jabkit/src/main/java/org/jabref/JabKit.java +++ b/jabkit/src/main/java/org/jabref/JabKit.java @@ -106,7 +106,7 @@ private static void applyUsageFooters(CommandLine commandLine, boolean hasInputOption = subCommand.getCommandSpec().options().stream() .anyMatch(opt -> Arrays.asList(opt.names()).contains("--input-format")); boolean hasOutputOption = subCommand.getCommandSpec().options().stream() - .anyMatch(opt -> Arrays.asList(opt.names()).contains("--output-format")); + .anyMatch(opt -> Arrays.asList(opt.names()).contains("--output")); String footerText = ""; footerText += hasInputOption ? inputFooter : ""; From b8e87bd2ef3858bd9fc46c851c82c26af8f4fe20 Mon Sep 17 00:00:00 2001 From: jhz <070jhz@proton.me> Date: Sun, 8 Jun 2025 13:00:56 +0200 Subject: [PATCH 2/5] change applyUsageFooters() visibility from private to package-private --- jabkit/src/main/java/org/jabref/JabKit.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jabkit/src/main/java/org/jabref/JabKit.java b/jabkit/src/main/java/org/jabref/JabKit.java index 9475e5d2912..a5c465f1fa9 100644 --- a/jabkit/src/main/java/org/jabref/JabKit.java +++ b/jabkit/src/main/java/org/jabref/JabKit.java @@ -91,10 +91,10 @@ public static void main(String[] args) { } } - private static void applyUsageFooters(CommandLine commandLine, - List> inputFormats, - List> outputFormats, - Set fetchers) { + static void applyUsageFooters(CommandLine commandLine, + List> inputFormats, + List> outputFormats, + Set fetchers) { String inputFooter = "\n" + Localization.lang("Available import formats:") + "\n" + StringUtil.alignStringTable(inputFormats); From f01c4af88105bc62c71d2d897710757919d7d0e2 Mon Sep 17 00:00:00 2001 From: jhz <070jhz@proton.me> Date: Sun, 8 Jun 2025 13:05:40 +0200 Subject: [PATCH 3/5] initial HelpOutputTest to verify footer visibility in CLI help --- .../test/java/org/jabref/HelpOutputTest.java | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 jabkit/src/test/java/org/jabref/HelpOutputTest.java diff --git a/jabkit/src/test/java/org/jabref/HelpOutputTest.java b/jabkit/src/test/java/org/jabref/HelpOutputTest.java new file mode 100644 index 00000000000..2f764cf5d17 --- /dev/null +++ b/jabkit/src/test/java/org/jabref/HelpOutputTest.java @@ -0,0 +1,69 @@ +package org.jabref; + +import javafx.collections.FXCollections; + +import org.jabref.cli.ArgumentProcessor; +import org.jabref.logic.exporter.ExportPreferences; +import org.jabref.logic.importer.ImportFormatPreferences; +import org.jabref.logic.importer.ImporterPreferences; +import org.jabref.logic.importer.WebFetchers; +import org.jabref.logic.preferences.CliPreferences; +import org.jabref.model.entry.BibEntryTypesManager; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Answers; +import picocli.CommandLine; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class HelpOutputTest { + + private CliPreferences preferences; + private BibEntryTypesManager entryTypesManager; + private CommandLine cmd; + + @BeforeEach + public void setUp() { + preferences = mock(CliPreferences.class, Answers.RETURNS_DEEP_STUBS); + entryTypesManager = mock(BibEntryTypesManager.class); + + ImporterPreferences importerPreferences = mock(ImporterPreferences.class, Answers.RETURNS_DEEP_STUBS); + ExportPreferences exportPreferences = mock(ExportPreferences.class, Answers.RETURNS_DEEP_STUBS); + ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); + + when(preferences.getImporterPreferences()).thenReturn(importerPreferences); + when(preferences.getExportPreferences()).thenReturn(exportPreferences); + when(preferences.getImportFormatPreferences()).thenReturn(importFormatPreferences); + + when(exportPreferences.getCustomExporters()).thenReturn(FXCollections.emptyObservableList()); + when(importerPreferences.getCustomImporters()).thenReturn(FXCollections.emptyObservableSet()); + + ArgumentProcessor argumentProcessor = new ArgumentProcessor(preferences, entryTypesManager); + cmd = new CommandLine(argumentProcessor); + + JabKit.applyUsageFooters( + cmd, + ArgumentProcessor.getAvailableImportFormats(preferences), + ArgumentProcessor.getAvailableExportFormats(preferences), + WebFetchers.getSearchBasedFetchers(preferences.getImportFormatPreferences(), preferences.getImporterPreferences()) + ); + } + + @Test + public void testExportFormatsFooterShownForOutputCommands() { + String help = cmd.getSubcommands().get("search").getUsageMessage(); + assertTrue(help.contains("Available export formats"), + "'Available export formats' should appear in 'search' command help"); + } + + @Test + public void testExportFormatsFooterNotShownForCommandsWithoutOutput() { + String help = cmd.getSubcommands().get("check-consistency").getUsageMessage(); + assertFalse(help.contains("Available export formats"), + "'Available export formats' should NOT appear in 'check-consistency' command help"); + } +} From fa1fea8cc3c9d7df2f99aa5d8ccaf70a59d822d0 Mon Sep 17 00:00:00 2001 From: jhz <070jhz@proton.me> Date: Sun, 8 Jun 2025 13:43:38 +0200 Subject: [PATCH 4/5] refactor test to cover all commands dynamically --- .../test/java/org/jabref/HelpOutputTest.java | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/jabkit/src/test/java/org/jabref/HelpOutputTest.java b/jabkit/src/test/java/org/jabref/HelpOutputTest.java index 2f764cf5d17..a7dec40f112 100644 --- a/jabkit/src/test/java/org/jabref/HelpOutputTest.java +++ b/jabkit/src/test/java/org/jabref/HelpOutputTest.java @@ -1,5 +1,7 @@ package org.jabref; +import java.util.Arrays; + import javafx.collections.FXCollections; import org.jabref.cli.ArgumentProcessor; @@ -15,8 +17,7 @@ import org.mockito.Answers; import picocli.CommandLine; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -54,16 +55,25 @@ public void setUp() { } @Test - public void testExportFormatsFooterShownForOutputCommands() { - String help = cmd.getSubcommands().get("search").getUsageMessage(); - assertTrue(help.contains("Available export formats"), - "'Available export formats' should appear in 'search' command help"); - } + public void testExportFormatFooterShownOnlyForCommandsWithOutputOption() { + cmd.getSubcommands().forEach((name, subCmd) -> { + CommandLine.Model.CommandSpec spec = subCmd.getCommandSpec(); + String helpMessage = subCmd.getUsageMessage(); - @Test - public void testExportFormatsFooterNotShownForCommandsWithoutOutput() { - String help = cmd.getSubcommands().get("check-consistency").getUsageMessage(); - assertFalse(help.contains("Available export formats"), - "'Available export formats' should NOT appear in 'check-consistency' command help"); + boolean hasOutputOption = spec.options().stream() + .anyMatch(opt -> Arrays.asList(opt.names()).contains("--output")); + + if ("fetch".equals(name)) { + // special case: expect footer NOT present + assertEquals(false, helpMessage.contains("Available export formats"), + "Did not expect 'Available export formats' in help for special case: " + name); + } else if (hasOutputOption) { + assertEquals(true, helpMessage.contains("Available export formats"), + "Expected 'Available export formats' in help for: " + name); + } else { + assertEquals(false, helpMessage.contains("Available export formats"), + "Did not expect 'Available export formats' in help for: " + name); + } + }); } } From 390f8e97e296657ba9b5d5dcfe317d059a32f9da Mon Sep 17 00:00:00 2001 From: jhz <070jhz@proton.me> Date: Tue, 10 Jun 2025 12:07:25 +0200 Subject: [PATCH 5/5] refine HelpOutputTest to check usageMessage footer directly --- .../test/java/org/jabref/HelpOutputTest.java | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/jabkit/src/test/java/org/jabref/HelpOutputTest.java b/jabkit/src/test/java/org/jabref/HelpOutputTest.java index a7dec40f112..da516643ea7 100644 --- a/jabkit/src/test/java/org/jabref/HelpOutputTest.java +++ b/jabkit/src/test/java/org/jabref/HelpOutputTest.java @@ -1,13 +1,17 @@ package org.jabref; import java.util.Arrays; +import java.util.List; +import java.util.Set; import javafx.collections.FXCollections; +import javafx.util.Pair; import org.jabref.cli.ArgumentProcessor; import org.jabref.logic.exporter.ExportPreferences; import org.jabref.logic.importer.ImportFormatPreferences; import org.jabref.logic.importer.ImporterPreferences; +import org.jabref.logic.importer.SearchBasedFetcher; import org.jabref.logic.importer.WebFetchers; import org.jabref.logic.preferences.CliPreferences; import org.jabref.model.entry.BibEntryTypesManager; @@ -45,34 +49,39 @@ public void setUp() { ArgumentProcessor argumentProcessor = new ArgumentProcessor(preferences, entryTypesManager); cmd = new CommandLine(argumentProcessor); - - JabKit.applyUsageFooters( - cmd, - ArgumentProcessor.getAvailableImportFormats(preferences), - ArgumentProcessor.getAvailableExportFormats(preferences), - WebFetchers.getSearchBasedFetchers(preferences.getImportFormatPreferences(), preferences.getImporterPreferences()) - ); } @Test public void testExportFormatFooterShownOnlyForCommandsWithOutputOption() { + List> inputFormats = ArgumentProcessor.getAvailableImportFormats(preferences); + List> outputFormats = ArgumentProcessor.getAvailableExportFormats(preferences); + Set fetchers = WebFetchers.getSearchBasedFetchers( + preferences.getImportFormatPreferences(), + preferences.getImporterPreferences() + ); + + JabKit.applyUsageFooters(cmd, inputFormats, outputFormats, fetchers); + cmd.getSubcommands().forEach((name, subCmd) -> { CommandLine.Model.CommandSpec spec = subCmd.getCommandSpec(); - String helpMessage = subCmd.getUsageMessage(); + String[] footer = subCmd.getCommandSpec().usageMessage().footer(); + String target = "Available export formats"; boolean hasOutputOption = spec.options().stream() .anyMatch(opt -> Arrays.asList(opt.names()).contains("--output")); + boolean containsExportFormats = Arrays.stream(footer) + .anyMatch(line -> line.contains(target)); if ("fetch".equals(name)) { // special case: expect footer NOT present - assertEquals(false, helpMessage.contains("Available export formats"), - "Did not expect 'Available export formats' in help for special case: " + name); + assertEquals(false, containsExportFormats, + "Did not expect 'Available export formats' in footer for special case: " + name); } else if (hasOutputOption) { - assertEquals(true, helpMessage.contains("Available export formats"), - "Expected 'Available export formats' in help for: " + name); + assertEquals(true, containsExportFormats, + "Expected 'Available export formats' in footer for: " + name); } else { - assertEquals(false, helpMessage.contains("Available export formats"), - "Did not expect 'Available export formats' in help for: " + name); + assertEquals(false, containsExportFormats, + "Did not expect 'Available export formats' in footer for: " + name); } }); }