Skip to content

Commit 9adb351

Browse files
committed
Refactor code to improve testability and code coverage
1 parent 6a11f3a commit 9adb351

File tree

6 files changed

+199
-81
lines changed

6 files changed

+199
-81
lines changed

src/main/java/de/donnerbart/split/TestSplit.java

Lines changed: 11 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
66
import com.github.javaparser.ast.expr.AnnotationExpr;
77
import com.github.javaparser.ast.nodeTypes.NodeWithName;
8-
import de.donnerbart.split.model.Split;
8+
import de.donnerbart.split.model.Splits;
99
import de.donnerbart.split.model.TestCase;
1010
import de.donnerbart.split.model.TestSuite;
1111
import org.jetbrains.annotations.NotNull;
@@ -20,13 +20,10 @@
2020
import java.nio.file.Path;
2121
import java.nio.file.SimpleFileVisitor;
2222
import java.nio.file.attribute.BasicFileAttributes;
23-
import java.util.ArrayList;
2423
import java.util.Comparator;
2524
import java.util.HashSet;
26-
import java.util.List;
2725
import java.util.Set;
2826
import java.util.function.Consumer;
29-
import java.util.stream.Collectors;
3027

3128
import static de.donnerbart.split.util.FormatUtil.formatTime;
3229

@@ -38,7 +35,6 @@ public class TestSplit {
3835

3936
private static final @NotNull Logger LOG = LoggerFactory.getLogger(TestSplit.class);
4037

41-
private final int splitIndex;
4238
private final int splitTotal;
4339
private final @NotNull String glob;
4440
private final @Nullable String excludeGlob;
@@ -50,7 +46,6 @@ public class TestSplit {
5046
private final @NotNull Consumer<Integer> exitCodeConsumer;
5147

5248
public TestSplit(
53-
final int splitIndex,
5449
final int splitTotal,
5550
final @NotNull String glob,
5651
final @Nullable String excludeGlob,
@@ -60,7 +55,6 @@ public TestSplit(
6055
final @NotNull Path workingDirectory,
6156
final boolean debug,
6257
final @NotNull Consumer<Integer> exitCodeConsumer) {
63-
this.splitIndex = splitIndex;
6458
this.splitTotal = splitTotal;
6559
this.glob = glob;
6660
this.excludeGlob = excludeGlob;
@@ -72,17 +66,7 @@ public TestSplit(
7266
this.exitCodeConsumer = exitCodeConsumer;
7367
}
7468

75-
public @NotNull List<String> run() throws Exception {
76-
LOG.info("Split index {} (total: {})", splitIndex, splitTotal);
77-
LOG.info("Working directory: {}", workingDirectory);
78-
LOG.info("Glob: {}", glob);
79-
if (excludeGlob != null) {
80-
LOG.info("Exclude glob: {}", excludeGlob);
81-
}
82-
if (junitGlob != null) {
83-
LOG.info("JUnit glob: {}", junitGlob);
84-
}
85-
LOG.info("Output format: {}", formatOption);
69+
public @NotNull Splits run() throws Exception {
8670
final var testPaths = getPaths(workingDirectory, glob, excludeGlob);
8771
final var classNames = fileToClassName(testPaths, exitCodeConsumer);
8872
if (classNames.isEmpty()) {
@@ -134,25 +118,20 @@ public TestSplit(
134118

135119
// split tests
136120
LOG.debug("Splitting {} tests", testCases.size());
137-
final var splits = new ArrayList<Split>(splitTotal);
138-
for (int i = 0; i < splitTotal; i++) {
139-
splits.add(new Split(i));
140-
}
141-
testCases.stream()
142-
.sorted(Comparator.reverseOrder())
143-
.forEach(testCase -> splits.stream().sorted().findFirst().ifPresent(split -> {
144-
LOG.debug("Adding test {} to split #{}", testCase.name(), split.index());
145-
split.add(testCase);
146-
}));
121+
final var splits = new Splits(splitTotal, formatOption);
122+
testCases.stream().sorted(Comparator.reverseOrder()).forEach(testCase -> {
123+
final var split = splits.add(testCase);
124+
LOG.debug("Adding test {} to split #{}", testCase.name(), split.index());
125+
});
147126

148127
if (debug) {
149128
if (splitTotal > 1) {
150-
final var fastestSplit = splits.stream().min(Comparator.naturalOrder()).orElseThrow();
129+
final var fastestSplit = splits.getFastest();
151130
LOG.debug("Fastest test plan is #{} with {} tests ({})",
152131
fastestSplit.formatIndex(),
153132
fastestSplit.tests().size(),
154133
formatTime(fastestSplit.totalRecordedTime()));
155-
final var slowestSplit = splits.stream().max(Comparator.naturalOrder()).orElseThrow();
134+
final var slowestSplit = splits.getSlowest();
156135
LOG.debug("Slowest test plan is #{} with {} tests ({})",
157136
slowestSplit.formatIndex(),
158137
slowestSplit.tests().size(),
@@ -161,19 +140,9 @@ public TestSplit(
161140
formatTime(slowestSplit.totalRecordedTime() - fastestSplit.totalRecordedTime()));
162141
}
163142
LOG.debug("Test splits:");
164-
splits.stream().sorted(Comparator.reverseOrder()).forEach(n -> LOG.debug(n.toString()));
143+
splits.forEach(split -> LOG.debug(split.toString()));
165144
}
166-
final var split = splits.get(splitIndex);
167-
LOG.info("This test split has {} tests ({})", split.tests().size(), formatTime(split.totalRecordedTime()));
168-
return split.tests()
169-
.stream()
170-
.sorted(Comparator.reverseOrder())
171-
.map(TestCase::name)
172-
.map(test -> switch (formatOption) {
173-
case LIST -> test;
174-
case GRADLE -> "--tests " + test;
175-
})
176-
.collect(Collectors.toList());
145+
return splits;
177146
}
178147

179148
private static @NotNull Set<Path> getPaths(

src/main/java/de/donnerbart/split/TestSplitMain.java

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import ch.qos.logback.classic.Level;
44
import com.beust.jcommander.JCommander;
5+
import de.donnerbart.split.model.Splits;
56
import org.jetbrains.annotations.NotNull;
67
import org.jetbrains.annotations.Nullable;
78
import org.jetbrains.annotations.VisibleForTesting;
@@ -12,16 +13,27 @@
1213
import java.nio.file.Path;
1314
import java.nio.file.Paths;
1415
import java.util.Objects;
16+
import java.util.function.Consumer;
17+
18+
import static de.donnerbart.split.util.FormatUtil.formatTime;
1519

1620
public class TestSplitMain {
1721

22+
private static final @NotNull Logger LOG = LoggerFactory.getLogger(TestSplitMain.class);
23+
1824
public static void main(final @Nullable String @NotNull [] args) throws Exception {
25+
run(System::exit, args);
26+
}
27+
28+
@VisibleForTesting
29+
static @NotNull Splits run(final @NotNull Consumer<Integer> exitConsumer, final @Nullable String @NotNull [] args)
30+
throws Exception {
1931
final var arguments = new Arguments();
2032
final var jCommander = JCommander.newBuilder().addObject(arguments).build();
2133
jCommander.parse(args);
2234
if (arguments.help) {
2335
jCommander.usage();
24-
System.exit(0);
36+
exitConsumer.accept(0);
2537
}
2638
if (arguments.debug) {
2739
final var root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
@@ -32,10 +44,19 @@ public static void main(final @Nullable String @NotNull [] args) throws Exceptio
3244
.toAbsolutePath()
3345
.normalize();
3446
if (!validateArguments(arguments, workingDirectory)) {
35-
System.exit(1);
47+
exitConsumer.accept(1);
48+
}
49+
LOG.info("Split index {} (total: {})", arguments.splitIndex, arguments.splitTotal);
50+
LOG.info("Working directory: {}", workingDirectory);
51+
LOG.info("Glob: {}", arguments.glob);
52+
if (arguments.excludeGlob != null) {
53+
LOG.info("Exclude glob: {}", arguments.excludeGlob);
54+
}
55+
if (arguments.junitGlob != null) {
56+
LOG.info("JUnit glob: {}", arguments.junitGlob);
3657
}
37-
final var testSplit = new TestSplit(arguments.splitIndex,
38-
arguments.splitTotal,
58+
LOG.info("Output format: {}", arguments.formatOption);
59+
final var testSplit = new TestSplit(arguments.splitTotal,
3960
arguments.glob,
4061
arguments.excludeGlob,
4162
arguments.junitGlob,
@@ -44,21 +65,25 @@ public static void main(final @Nullable String @NotNull [] args) throws Exceptio
4465
workingDirectory,
4566
arguments.debug,
4667
System::exit);
47-
System.out.print(String.join(" ", testSplit.run()));
68+
final var splits = testSplit.run();
69+
final var split = splits.get(arguments.splitIndex);
70+
LOG.info("This test split has {} tests ({})", split.tests().size(), formatTime(split.totalRecordedTime()));
71+
System.out.print(String.join(" ", splits.get(arguments.splitIndex).sortedTests()));
72+
return splits;
4873
}
4974

5075
@VisibleForTesting
5176
static boolean validateArguments(final @NotNull Arguments arguments, final @NotNull Path workingDirectory) {
5277
if (arguments.splitTotal < 1) {
53-
System.out.println("--split-total must be greater than 0");
78+
LOG.error("--split-total must be greater than 0");
5479
return false;
5580
}
5681
if (arguments.splitIndex > arguments.splitTotal - 1) {
57-
System.out.println("--split-index must lesser than --split-total");
82+
LOG.error("--split-index must lesser than --split-total");
5883
return false;
5984
}
6085
if (!Files.exists(workingDirectory)) {
61-
System.out.println("Working directory does not exist: " + arguments.workingDirectory);
86+
LOG.error("Working directory does not exist: {}", arguments.workingDirectory);
6287
return false;
6388
}
6489
return true;

src/main/java/de/donnerbart/split/model/Split.java

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,35 @@
11
package de.donnerbart.split.model;
22

3+
import de.donnerbart.split.FormatOption;
34
import de.donnerbart.split.util.FormatUtil;
45
import org.jetbrains.annotations.NotNull;
56
import org.jetbrains.annotations.Nullable;
67

8+
import java.util.Comparator;
79
import java.util.HashSet;
10+
import java.util.List;
811
import java.util.Objects;
912
import java.util.Set;
1013
import java.util.stream.Collectors;
1114

1215
public class Split implements Comparable<Split> {
1316

1417
private final @NotNull Set<TestCase> tests = new HashSet<>();
18+
private final @NotNull FormatOption formatOption;
1519
private final int index;
1620

1721
private double totalRecordedTime;
1822

19-
public Split(final int index) {
23+
public Split(final @NotNull FormatOption formatOption, final int index) {
24+
this.formatOption = formatOption;
2025
this.index = index;
2126
}
2227

28+
public void add(final @NotNull TestCase testCase) {
29+
tests.add(testCase);
30+
totalRecordedTime += testCase.time();
31+
}
32+
2333
public int index() {
2434
return index;
2535
}
@@ -28,14 +38,24 @@ public int index() {
2838
return String.format("%02d", index);
2939
}
3040

31-
public double totalRecordedTime() {
32-
return totalRecordedTime;
33-
}
34-
3541
public @NotNull Set<TestCase> tests() {
3642
return tests;
3743
}
3844

45+
public @NotNull List<String> sortedTests() {
46+
return tests.stream() //
47+
.sorted(Comparator.reverseOrder()) //
48+
.map(TestCase::name) //
49+
.map(test -> switch (formatOption) {
50+
case LIST -> test;
51+
case GRADLE -> "--tests " + test;
52+
}).collect(Collectors.toList());
53+
}
54+
55+
public double totalRecordedTime() {
56+
return totalRecordedTime;
57+
}
58+
3959
@Override
4060
public int compareTo(final @NotNull Split o) {
4161
final var compareTime = Double.compare(totalRecordedTime, o.totalRecordedTime);
@@ -75,9 +95,4 @@ public String toString() {
7595
tests.stream().map(TestCase::name).collect(Collectors.joining(", ")) +
7696
'}';
7797
}
78-
79-
public void add(final @NotNull TestCase testCase) {
80-
tests.add(testCase);
81-
totalRecordedTime += testCase.time();
82-
}
8398
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package de.donnerbart.split.model;
2+
3+
import de.donnerbart.split.FormatOption;
4+
import org.jetbrains.annotations.NotNull;
5+
6+
import java.util.ArrayList;
7+
import java.util.Comparator;
8+
import java.util.List;
9+
import java.util.function.Consumer;
10+
11+
public class Splits {
12+
13+
private final @NotNull List<Split> splits;
14+
15+
public Splits(final int splitTotal, final @NotNull FormatOption formatOption) {
16+
this.splits = new ArrayList<>(splitTotal);
17+
for (int i = 0; i < splitTotal; i++) {
18+
splits.add(new Split(formatOption, i));
19+
}
20+
}
21+
22+
public @NotNull Split add(final @NotNull TestCase testCase) {
23+
final var split = splits.stream().sorted().findFirst().orElseThrow();
24+
split.add(testCase);
25+
return split;
26+
}
27+
28+
public @NotNull Split get(final int index) {
29+
return splits.get(index);
30+
}
31+
32+
public @NotNull Split getFastest() {
33+
return splits.stream().min(Comparator.naturalOrder()).orElseThrow();
34+
}
35+
36+
public @NotNull Split getSlowest() {
37+
return splits.stream().max(Comparator.naturalOrder()).orElseThrow();
38+
}
39+
40+
public void forEach(final @NotNull Consumer<Split> consumer) {
41+
splits.stream().sorted(Comparator.reverseOrder()).forEach(consumer);
42+
}
43+
44+
public int size() {
45+
return splits.size();
46+
}
47+
}

0 commit comments

Comments
 (0)