Skip to content

Commit a1b312a

Browse files
authored
Framework for CLI tests with examples (#14164)
* add AbstractJabKitTest for easier CLI testing refactored ArgumentProcessorTest * added utils for resources and refactored for old code to use them * Add CLI for pseudonymize * Add interface to get stdout and stderr from command line execution * add test for convert, new dependency for the test needed * added test for search cli * fix removed unneeded sout statements
1 parent 615c91b commit a1b312a

File tree

6 files changed

+336
-50
lines changed

6 files changed

+336
-50
lines changed

jabkit/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ dependencies {
5656

5757
javaModuleTesting.whitebox(testing.suites["test"]) {
5858
requires.add("org.junit.jupiter.api")
59+
requires.add("org.junit.jupiter.params")
5960
requires.add("org.jabref.testsupport")
6061
requires.add("org.mockito")
6162
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package org.jabref.cli;
2+
3+
import java.io.PrintWriter;
4+
import java.io.StringWriter;
5+
import java.net.URISyntaxException;
6+
import java.nio.file.Path;
7+
import java.util.EnumSet;
8+
import java.util.Objects;
9+
10+
import javafx.collections.FXCollections;
11+
12+
import org.jabref.logic.exporter.ExportPreferences;
13+
import org.jabref.logic.importer.ImportFormatPreferences;
14+
import org.jabref.logic.importer.ImporterPreferences;
15+
import org.jabref.logic.preferences.CliPreferences;
16+
import org.jabref.logic.search.SearchPreferences;
17+
import org.jabref.model.entry.BibEntryTypesManager;
18+
import org.jabref.model.search.SearchDisplayMode;
19+
import org.jabref.model.search.SearchFlags;
20+
21+
import org.junit.jupiter.api.BeforeEach;
22+
import org.mockito.Answers;
23+
import picocli.CommandLine;
24+
25+
import static org.mockito.Mockito.mock;
26+
import static org.mockito.Mockito.when;
27+
28+
public abstract class AbstractJabKitTest {
29+
protected final CliPreferences preferences = mock(CliPreferences.class, Answers.RETURNS_DEEP_STUBS);
30+
protected final BibEntryTypesManager entryTypesManager = mock(BibEntryTypesManager.class);
31+
protected final ImporterPreferences importerPreferences = mock(ImporterPreferences.class, Answers.RETURNS_DEEP_STUBS);
32+
protected final ExportPreferences exportPreferences = mock(ExportPreferences.class, Answers.RETURNS_DEEP_STUBS);
33+
protected final ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS);
34+
35+
protected CommandLine commandLine;
36+
37+
private StringWriter outWriter;
38+
private StringWriter errWriter;
39+
40+
@BeforeEach()
41+
void setup() {
42+
when(importerPreferences.getCustomImporters()).thenReturn(FXCollections.emptyObservableSet());
43+
when(exportPreferences.getCustomExporters()).thenReturn(FXCollections.emptyObservableList());
44+
45+
when(preferences.getExportPreferences()).thenReturn(exportPreferences);
46+
when(preferences.getImporterPreferences()).thenReturn(importerPreferences);
47+
when(preferences.getImportFormatPreferences()).thenReturn(importFormatPreferences);
48+
when(preferences.getSearchPreferences()).thenReturn(new SearchPreferences(
49+
SearchDisplayMode.FILTER,
50+
EnumSet.noneOf(SearchFlags.class),
51+
false,
52+
false,
53+
0,
54+
0,
55+
0));
56+
57+
ArgumentProcessor argumentProcessor = new ArgumentProcessor(preferences, entryTypesManager);
58+
commandLine = new CommandLine(argumentProcessor);
59+
60+
outWriter = new StringWriter();
61+
PrintWriter out = new PrintWriter(outWriter);
62+
errWriter = new StringWriter();
63+
PrintWriter err = new PrintWriter(errWriter);
64+
65+
commandLine.setOut(out);
66+
commandLine.setErr(err);
67+
}
68+
69+
/**
70+
* Returns the captured standard output from the command line execution.
71+
*
72+
* @return The captured stdout string.
73+
*/
74+
protected String getStandardOutput() {
75+
return outWriter.toString();
76+
}
77+
78+
/**
79+
* Returns the captured error output from the command line execution.
80+
*
81+
* @return The captured stderr string.
82+
*/
83+
protected String getErrorOutput() {
84+
return errWriter.toString();
85+
}
86+
87+
/**
88+
* Gets class resource as fully qualified string.
89+
* Useful for scenarios where you want a resource as a command line argument
90+
* <p>
91+
* Throws a runtime exception if the resource URL cannot be turned into a URI.
92+
*
93+
* @param resourceName the resource name
94+
* @return the class resource as fully qualified string
95+
*/
96+
String getClassResourceAsFullyQualifiedString(String resourceName) {
97+
return getClassResourceAsPath(resourceName).toAbsolutePath().toString();
98+
}
99+
100+
/**
101+
* Gets class resource as a path.
102+
* <p>
103+
* Throws a runtime exception if the resource URL cannot be turned into a URI.
104+
*
105+
* @param resourceName the resource name
106+
* @return the class resource as path
107+
*/
108+
Path getClassResourceAsPath(String resourceName) {
109+
try {
110+
return Path.of(Objects.requireNonNull(this.getClass().getResource(resourceName), "Could not find resource: " + resourceName).toURI())
111+
.toAbsolutePath();
112+
} catch (URISyntaxException e) {
113+
throw new RuntimeException(
114+
"Wrong resource name %s for class %s".formatted(resourceName, this.getClass()), e
115+
);
116+
}
117+
}
118+
}

jabkit/src/test/java/org/jabref/cli/ArgumentProcessorTest.java

Lines changed: 9 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import java.net.URISyntaxException;
77
import java.nio.file.Files;
88
import java.nio.file.Path;
9-
import java.util.EnumSet;
109
import java.util.List;
1110
import java.util.Objects;
1211

@@ -15,66 +14,26 @@
1514
import org.jabref.logic.exporter.BibDatabaseWriter;
1615
import org.jabref.logic.exporter.ExportPreferences;
1716
import org.jabref.logic.exporter.SelfContainedSaveConfiguration;
18-
import org.jabref.logic.importer.ImportFormatPreferences;
19-
import org.jabref.logic.importer.ImporterPreferences;
2017
import org.jabref.logic.importer.fileformat.BibtexImporter;
21-
import org.jabref.logic.preferences.CliPreferences;
22-
import org.jabref.logic.search.SearchPreferences;
2318
import org.jabref.model.entry.BibEntry;
24-
import org.jabref.model.entry.BibEntryTypesManager;
2519
import org.jabref.model.metadata.SaveOrder;
2620
import org.jabref.model.metadata.SelfContainedSaveOrder;
27-
import org.jabref.model.search.SearchDisplayMode;
28-
import org.jabref.model.search.SearchFlags;
2921
import org.jabref.model.util.DummyFileUpdateMonitor;
3022
import org.jabref.support.BibEntryAssert;
3123

32-
import org.junit.jupiter.api.BeforeEach;
3324
import org.junit.jupiter.api.Test;
3425
import org.junit.jupiter.api.io.TempDir;
35-
import org.mockito.Answers;
36-
import picocli.CommandLine;
3726

3827
import static org.junit.jupiter.api.Assertions.assertEquals;
3928
import static org.junit.jupiter.api.Assertions.assertTrue;
40-
import static org.mockito.Mockito.mock;
4129
import static org.mockito.Mockito.when;
4230

43-
class ArgumentProcessorTest {
44-
45-
private final CliPreferences preferences = mock(CliPreferences.class, Answers.RETURNS_DEEP_STUBS);
46-
private final BibEntryTypesManager entryTypesManager = mock(BibEntryTypesManager.class);
47-
private final ImporterPreferences importerPreferences = mock(ImporterPreferences.class, Answers.RETURNS_DEEP_STUBS);
48-
private final ExportPreferences exportPreferences = mock(ExportPreferences.class, Answers.RETURNS_DEEP_STUBS);
49-
private final ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS);
50-
51-
private CommandLine commandLine;
52-
53-
@BeforeEach()
54-
void setup() {
55-
when(importerPreferences.getCustomImporters()).thenReturn(FXCollections.emptyObservableSet());
56-
when(exportPreferences.getCustomExporters()).thenReturn(FXCollections.emptyObservableList());
57-
58-
when(preferences.getExportPreferences()).thenReturn(exportPreferences);
59-
when(preferences.getImporterPreferences()).thenReturn(importerPreferences);
60-
when(preferences.getImportFormatPreferences()).thenReturn(importFormatPreferences);
61-
when(preferences.getSearchPreferences()).thenReturn(new SearchPreferences(
62-
SearchDisplayMode.FILTER,
63-
EnumSet.noneOf(SearchFlags.class),
64-
false,
65-
false,
66-
0,
67-
0,
68-
0));
69-
70-
ArgumentProcessor argumentProcessor = new ArgumentProcessor(preferences, entryTypesManager);
71-
commandLine = new CommandLine(argumentProcessor);
72-
}
31+
class ArgumentProcessorTest extends AbstractJabKitTest {
7332

7433
@Test
7534
void auxImport(@TempDir Path tempDir) throws URISyntaxException {
76-
String fullBib = Path.of(ArgumentProcessorTest.class.getResource("origin.bib").toURI()).toAbsolutePath().toString();
77-
String auxFile = Path.of(ArgumentProcessorTest.class.getResource("paper.aux").toURI()).toAbsolutePath().toString();
35+
String fullBib = getClassResourceAsFullyQualifiedString("origin.bib");
36+
String auxFile = getClassResourceAsFullyQualifiedString("paper.aux");
7837

7938
Path outputBib = tempDir.resolve("output.bib").toAbsolutePath();
8039

@@ -87,7 +46,7 @@ void auxImport(@TempDir Path tempDir) throws URISyntaxException {
8746

8847
@Test
8948
void search(@TempDir Path tempDir) throws URISyntaxException, IOException {
90-
Path originBib = Path.of(Objects.requireNonNull(ArgumentProcessorTest.class.getResource("origin.bib")).toURI());
49+
Path originBib = getClassResourceAsPath("origin.bib");
9150
String originBibFile = originBib.toAbsolutePath().toString();
9251

9352
Path expectedBib = Path.of(
@@ -110,7 +69,7 @@ void search(@TempDir Path tempDir) throws URISyntaxException, IOException {
11069

11170
@Test
11271
void convertBibtexToTableRefsAsBib(@TempDir Path tempDir) throws URISyntaxException {
113-
Path originBib = Path.of(Objects.requireNonNull(ArgumentProcessorTest.class.getResource("origin.bib")).toURI());
72+
Path originBib = getClassResourceAsPath("origin.bib");
11473
String originBibFile = originBib.toAbsolutePath().toString();
11574

11675
Path outputHtml = tempDir.resolve("output.html").toAbsolutePath();
@@ -134,8 +93,8 @@ void convertBibtexToTableRefsAsBib(@TempDir Path tempDir) throws URISyntaxExcept
13493
}
13594

13695
@Test
137-
void checkConsistency() throws URISyntaxException {
138-
Path testBib = Path.of(Objects.requireNonNull(ArgumentProcessorTest.class.getResource("origin.bib")).toURI());
96+
void checkConsistency() {
97+
Path testBib = getClassResourceAsPath("origin.bib");
13998
String testBibFile = testBib.toAbsolutePath().toString();
14099

141100
List<String> args = List.of("check-consistency", "--input", testBibFile, "--output-format", "txt");
@@ -154,8 +113,8 @@ void checkConsistency() throws URISyntaxException {
154113
}
155114

156115
@Test
157-
void checkConsistencyPorcelain() throws URISyntaxException {
158-
Path testBib = Path.of(Objects.requireNonNull(ArgumentProcessorTest.class.getResource("origin.bib")).toURI());
116+
void checkConsistencyPorcelain() {
117+
Path testBib = getClassResourceAsPath("origin.bib");
159118
String testBibFile = testBib.toAbsolutePath().toString();
160119

161120
// "txt" is the default output format; thus not provided here
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package org.jabref.cli;
2+
3+
import java.io.IOException;
4+
import java.nio.file.Files;
5+
import java.nio.file.Path;
6+
import java.util.stream.Collectors;
7+
8+
import org.junit.jupiter.api.Test;
9+
import org.junit.jupiter.api.io.TempDir;
10+
import org.junit.jupiter.params.ParameterizedTest;
11+
import org.junit.jupiter.params.provider.CsvSource;
12+
13+
import static org.junit.jupiter.api.Assertions.assertEquals;
14+
import static org.junit.jupiter.api.Assertions.assertFalse;
15+
import static org.junit.jupiter.api.Assertions.assertTrue;
16+
17+
public class ConvertTest extends AbstractJabKitTest {
18+
@ParameterizedTest
19+
@CsvSource({"bibtex", "html",
20+
"simplehtml", "tablerefs",
21+
"oocsv", "hayagrivayaml",
22+
"iso690rtf"
23+
})
24+
void differentOutputFormatTest(String format, @TempDir Path tempDir) throws IOException {
25+
Path origin = getClassResourceAsPath("origin.bib").toAbsolutePath();
26+
Path newPath = tempDir.resolve("origin.bib");
27+
Files.copy(origin, newPath);
28+
Path outputPath = tempDir.resolve("output");
29+
30+
// assertEquals(commandLine.execute("convert", "--input=" + newPath, "--input-format=bibtex", "--output-format=" + format, "--output=" + outputPath), 0);
31+
commandLine.execute("convert",
32+
"--input=" + newPath, "--input-format=bibtex",
33+
"--output-format=" + format,
34+
"--output=" + outputPath);
35+
36+
assertTrue(outputPath.toFile().exists());
37+
}
38+
39+
@Test
40+
void simpleOutputTest(@TempDir Path tempDir) throws IOException {
41+
Path origin = getClassResourceAsPath("origin.bib").toAbsolutePath();
42+
Path newPath = tempDir.resolve("origin.bib");
43+
Files.copy(origin, newPath);
44+
Path outputPath = tempDir.resolve("output");
45+
46+
// assertEquals(commandLine.execute("convert", "--input=" + newPath, "--input-format=bibtex", "--output-format=" + format, "--output=" + outputPath), 0);
47+
commandLine.execute("convert",
48+
"--input=" + newPath, "--input-format=bibtex",
49+
"--output-format=bibtex",
50+
"--output=" + outputPath);
51+
52+
assertTrue(outputPath.toFile().exists());
53+
assertTrue(Files.readString(outputPath).contains("Darwin1888"));
54+
}
55+
56+
@Test
57+
void wrongOutputFormatFails(@TempDir Path tempDir) throws IOException {
58+
Path origin = getClassResourceAsPath("origin.bib").toAbsolutePath();
59+
Path newPath = tempDir.resolve("origin.bib");
60+
Files.copy(origin, newPath);
61+
Path outputPath = tempDir.resolve("output");
62+
63+
// assertEquals(commandLine.execute("convert", "--input=" + newPath, "--input-format=bibtex", "--output-format=" + format, "--output=" + outputPath), 0);
64+
commandLine.execute("convert",
65+
"--input=" + newPath, "--input-format=bibtex",
66+
"--output-format=ffasdfasd",
67+
"--output=" + outputPath);
68+
69+
assertFalse(outputPath.toFile().exists());
70+
}
71+
72+
@Test
73+
void noOutputGeneratesNothing(@TempDir Path tempDir) throws IOException {
74+
Path origin = getClassResourceAsPath("origin.bib").toAbsolutePath();
75+
Path newPath = tempDir.resolve("origin.bib");
76+
Files.copy(origin, newPath);
77+
78+
// assertEquals(commandLine.execute("convert", "--input=" + newPath, "--input-format=bibtex", "--output-format=" + format, "--output=" + outputPath), 0);
79+
commandLine.execute("convert",
80+
"--input=" + newPath, "--input-format=bibtex",
81+
"--output-format=bibtex");
82+
83+
assertEquals(1, Files.list(tempDir).collect(Collectors.toSet()).size());
84+
}
85+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package org.jabref.cli;
2+
3+
import java.io.IOException;
4+
import java.nio.charset.Charset;
5+
import java.nio.charset.StandardCharsets;
6+
import java.nio.file.Path;
7+
8+
import com.google.common.io.Files;
9+
import org.junit.jupiter.api.Test;
10+
import org.junit.jupiter.api.io.TempDir;
11+
12+
import static org.junit.jupiter.api.Assertions.assertFalse;
13+
import static org.junit.jupiter.api.Assertions.assertTrue;
14+
15+
public class PseudonymizeTest extends AbstractJabKitTest {
16+
@Test
17+
public void normalUsage(@TempDir Path tempDir) throws IOException {
18+
Path origin = getClassResourceAsPath("origin.bib").toAbsolutePath();
19+
Path output = tempDir.resolve("new.pseudo.bib");
20+
Path key = tempDir.resolve("new.pseudo.csv");
21+
commandLine.execute("pseudonymize", "--input=" + origin, "--output=" + output, "--key=" + key);
22+
assertTrue(output.toFile().exists());
23+
assertTrue(key.toFile().exists());
24+
assertFalse(Files.readLines(output.toFile(), Charset.defaultCharset()).stream().anyMatch((s) -> s.contains("Newton1999")));
25+
}
26+
27+
@Test
28+
public void automaticFileCreation(@TempDir Path tempDir) throws IOException {
29+
Path origin = getClassResourceAsPath("origin.bib");
30+
Path copy = tempDir.resolve("origin.bib");
31+
Files.copy(origin.toFile(), copy.toFile());
32+
commandLine.execute("pseudonymize", "--input=" + copy);
33+
Path output = tempDir.resolve("origin.pseudo.bib");
34+
Path key = tempDir.resolve("origin.pseudo.csv");
35+
assertTrue(output.toFile().exists());
36+
assertTrue(key.toFile().exists());
37+
}
38+
39+
@Test
40+
public void forceUsage(@TempDir Path tempDir) throws IOException {
41+
Path origin = getClassResourceAsPath("origin.bib").toAbsolutePath();
42+
Path output = tempDir.resolve("new.pseudo.bib");
43+
Path key = tempDir.resolve("new.pseudo.csv");
44+
Files.write("some".getBytes(StandardCharsets.UTF_8), output.toFile());
45+
commandLine.execute("pseudonymize", "-f", "--input=" + origin, "--output=" + output, "--key=" + key);
46+
assertTrue(output.toFile().exists());
47+
assertTrue(key.toFile().exists());
48+
assertTrue(Files.readLines(output.toFile(), Charset.defaultCharset()).size() > 1);
49+
}
50+
51+
@Test
52+
public void noForceUsage(@TempDir Path tempDir) throws IOException {
53+
Path origin = getClassResourceAsPath("origin.bib").toAbsolutePath();
54+
Path output = tempDir.resolve("new.pseudo.bib");
55+
Path key = tempDir.resolve("new.pseudo.csv");
56+
Files.write("some".getBytes(StandardCharsets.UTF_8), key.toFile());
57+
commandLine.execute("pseudonymize", "--input=" + origin, "--output=" + output, "--key=" + key);
58+
java.nio.file.Files.list(tempDir).forEach(System.out::println);
59+
assertTrue(output.toFile().exists());
60+
assertTrue(key.toFile().exists());
61+
assertFalse(Files.readLines(key.toFile(), Charset.defaultCharset()).size() > 1);
62+
}
63+
}

0 commit comments

Comments
 (0)