1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package org.eluder.coveralls.maven.plugin.parser;
26
27 import java.io.File;
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.HashSet;
32 import java.util.List;
33 import java.util.Set;
34
35 import org.eluder.coveralls.maven.plugin.CoverageFixture;
36 import org.eluder.coveralls.maven.plugin.CoverageParser;
37 import org.eluder.coveralls.maven.plugin.ProcessingException;
38 import org.eluder.coveralls.maven.plugin.domain.Branch;
39 import org.eluder.coveralls.maven.plugin.domain.Source;
40 import org.eluder.coveralls.maven.plugin.source.ChainingSourceCallback;
41 import org.eluder.coveralls.maven.plugin.source.SourceCallback;
42 import org.eluder.coveralls.maven.plugin.source.SourceLoader;
43 import org.eluder.coveralls.maven.plugin.source.UniqueSourceCallback;
44 import org.eluder.coveralls.maven.plugin.util.TestIoUtil;
45 import org.junit.jupiter.api.Assertions;
46 import org.junit.jupiter.api.BeforeEach;
47 import org.junit.jupiter.api.Test;
48 import org.junit.jupiter.api.extension.ExtendWith;
49 import org.mockito.ArgumentCaptor;
50 import org.mockito.Mock;
51 import org.mockito.Mockito;
52 import org.mockito.junit.jupiter.MockitoExtension;
53 import org.mockito.stubbing.Answer;
54
55
56
57
58 @ExtendWith(MockitoExtension.class)
59 public abstract class AbstractCoverageParserTest {
60
61
62 @Mock
63 SourceLoader sourceLoaderMock;
64
65
66 @Mock
67 SourceCallback sourceCallbackMock;
68
69
70
71
72 public AbstractCoverageParserTest() {
73
74 }
75
76
77
78
79
80
81
82 @BeforeEach
83 void init() throws IOException {
84 for (final List<String> coverageFile : this.getCoverageFixture()) {
85 final var name = this.sourceName(coverageFile.get(0));
86 final var content = TestIoUtil.readFileContent(TestIoUtil.getFile(name));
87 Mockito.lenient().when(this.sourceLoaderMock.load(name)).then(this.sourceAnswer(name, content));
88 }
89 }
90
91
92
93
94
95
96
97
98
99 String sourceName(final String coverageFile) {
100 return coverageFile;
101 }
102
103
104
105
106
107
108
109
110
111
112
113 Answer<Source> sourceAnswer(final String name, final String content) {
114 return invocation -> new Source(name, content, TestIoUtil.getSha512DigestHex(content));
115 }
116
117
118
119
120
121
122
123
124
125 @Test
126 void parseCoverage() throws ProcessingException, IOException {
127 for (final String coverageResource : this.getCoverageResources()) {
128 final var parser = this.createCoverageParser(TestIoUtil.getFile(coverageResource), this.sourceLoaderMock);
129 parser.parse(this.sourceCallbackMock);
130 }
131
132 final var fixture = this.getCoverageFixture();
133
134 final ArgumentCaptor<Source> captor = ArgumentCaptor.forClass(Source.class);
135 Mockito.verify(this.sourceCallbackMock, Mockito.atLeast(CoverageFixture.getTotalFiles(fixture)))
136 .onSource(captor.capture());
137
138 final var sourceCollector = new SourceCollector();
139 final var uniqueSourceCallback = new UniqueSourceCallback(sourceCollector);
140 final var classifierRemover = new ClassifierRemover(uniqueSourceCallback);
141 classifierRemover.onBegin();
142 for (final Source source : captor.getAllValues()) {
143 classifierRemover.onSource(source);
144 }
145 classifierRemover.onComplete();
146
147 for (final List<String> coverageFile : fixture) {
148 AbstractCoverageParserTest.assertCoverage(sourceCollector.sources, coverageFile.get(0),
149 Integer.parseInt(coverageFile.get(1)), this.toIntegerSet(coverageFile.get(2)),
150 this.toIntegerSet(coverageFile.get(3)), this.toIntegerSet(coverageFile.get(4)),
151 this.toIntegerSet(coverageFile.get(5)));
152 }
153 }
154
155
156
157
158
159
160
161
162
163
164
165 protected abstract CoverageParser createCoverageParser(File coverageFile, SourceLoader sourceLoader);
166
167
168
169
170
171
172 protected abstract List<String> getCoverageResources();
173
174
175
176
177
178
179 protected abstract List<List<String>> getCoverageFixture();
180
181
182
183
184
185
186
187
188
189 Set<Integer> toIntegerSet(final String commaSeparated) {
190 if (commaSeparated.isEmpty()) {
191 return Set.of();
192 }
193 final var split = commaSeparated.split(",", -1);
194 final Set<Integer> values = new HashSet<>();
195 for (final String value : split) {
196 values.add(Integer.valueOf(value));
197 }
198 return values;
199 }
200
201
202
203
204 static class SourceCollector implements SourceCallback {
205
206
207 private final List<Source> sources = new ArrayList<>();
208
209 @Override
210 public void onBegin() {
211
212 }
213
214 @Override
215 public void onSource(Source source) {
216 this.sources.add(source);
217 }
218
219 @Override
220 public void onComplete() {
221
222 }
223 }
224
225
226
227
228 static class ClassifierRemover extends ChainingSourceCallback {
229
230
231
232
233
234
235
236 public ClassifierRemover(SourceCallback chained) {
237 super(chained);
238 }
239
240 @Override
241 protected void onSourceInternal(Source source) {
242 source.setClassifier(null);
243 }
244 }
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264 static void assertCoverage(final Collection<Source> sources, final String name, final int lines,
265 final Set<Integer> coveredLines, final Set<Integer> missedLines, final Set<Integer> coveredBranches,
266 final Set<Integer> missedBranches) {
267
268 Source tested = null;
269 for (final Source source : sources) {
270 if (source.getName().endsWith(name)) {
271 tested = source;
272 break;
273 }
274 }
275 if (tested == null) {
276 Assertions.fail("Expected source " + name + " not found from coverage report");
277 }
278 if (tested.getCoverage().length != lines) {
279 Assertions.fail("Expected " + lines + " lines for " + name + " was " + tested.getCoverage().length);
280 }
281 for (var i = 0; i < tested.getCoverage().length; i++) {
282 final var lineNumber = i + 1;
283 final var message = name + " line " + lineNumber + " coverage";
284 if (coveredLines.contains(lineNumber)) {
285 Assertions.assertTrue(tested.getCoverage()[i] > 0, message);
286 } else if (missedLines.contains(lineNumber)) {
287 Assertions.assertEquals(0, tested.getCoverage()[i], message);
288 } else {
289 Assertions.assertNull(tested.getCoverage()[i], message);
290 }
291 }
292 for (final Branch b : tested.getBranchesList()) {
293 final var message = name + " branch " + b.getBranchNumber() + " coverage in line " + b.getLineNumber();
294 if (b.getHits() > 0) {
295 Assertions.assertTrue(coveredBranches.contains(b.getLineNumber()), message);
296 } else {
297 Assertions.assertTrue(missedBranches.contains(b.getLineNumber()), message);
298 }
299 }
300 }
301
302 }