Skip to content

Commit 542101a

Browse files
author
Vincent Potucek
committed
Pull apache#2304: Modernize codebase with Java improvements - test DefaultModelProcessor#read
1 parent 6be7a12 commit 542101a

File tree

2 files changed

+356
-7
lines changed

2 files changed

+356
-7
lines changed

impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelProcessor.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ public Model read(XmlReaderRequest request) throws IOException {
114114
}
115115
try {
116116
return doRead(request);
117-
} catch (IOException e) {
117+
} catch (Exception e) {
118118
exceptions.forEach(e::addSuppressed);
119119
throw e;
120120
}
@@ -127,17 +127,14 @@ private Path doLocateExistingPom(Path project) {
127127
if (project == null) {
128128
project = Paths.get(System.getProperty("user.dir"));
129129
}
130-
if (Files.isDirectory(project)) {
130+
else if (Files.isDirectory(project)) {
131131
Path pom = project.resolve("pom.xml");
132132
return Files.isRegularFile(pom) ? pom : null;
133-
} else if (Files.isRegularFile(project)) {
134-
return project;
135-
} else {
136-
return null;
137133
}
134+
return project;
138135
}
139136

140-
private Model doRead(XmlReaderRequest request) throws IOException {
137+
private Model doRead(XmlReaderRequest request) {
141138
return modelXmlFactory.read(request);
142139
}
143140
}
Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.maven.impl.model;
20+
21+
import java.io.IOException;
22+
import java.nio.file.Files;
23+
import java.nio.file.Path;
24+
import java.util.List;
25+
import java.util.Optional;
26+
27+
import org.apache.maven.api.model.Model;
28+
import org.apache.maven.api.services.Source;
29+
import org.apache.maven.api.services.xml.ModelXmlFactory;
30+
import org.apache.maven.api.services.xml.XmlReaderRequest;
31+
import org.apache.maven.api.spi.ModelParser;
32+
import org.apache.maven.api.spi.ModelParserException;
33+
import org.junit.jupiter.api.AfterEach;
34+
import org.junit.jupiter.api.Test;
35+
import org.junit.jupiter.api.io.TempDir;
36+
37+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
38+
import static org.junit.jupiter.api.Assertions.*;
39+
import static org.mockito.Mockito.*;
40+
41+
class DefaultModelProcessorTest {
42+
43+
@TempDir
44+
Path tempDir;
45+
46+
Path testProjectDir, testPomFile;
47+
48+
@AfterEach
49+
void cleanup() throws IOException {
50+
if (testPomFile != null && Files.exists(testPomFile)) {
51+
Files.deleteIfExists(testPomFile);
52+
}
53+
if (testProjectDir != null && Files.exists(testProjectDir)) {
54+
Files.deleteIfExists(testProjectDir);
55+
}
56+
}
57+
58+
@Test
59+
void readWithValidParserShouldReturnModel() throws Exception {
60+
ModelXmlFactory factory = mock(ModelXmlFactory.class);
61+
ModelParser parser = mock(ModelParser.class);
62+
XmlReaderRequest request = mock(XmlReaderRequest.class);
63+
Model model = mock(Model.class);
64+
Path path = Path.of("project/pom.xml");
65+
when(request.getPath()).thenReturn(path);
66+
when(request.isStrict()).thenReturn(true);
67+
when(model.withPomFile(path)).thenReturn(model);
68+
when(parser.locateAndParse(any(), any())).thenReturn(Optional.of(model));
69+
Model result = new DefaultModelProcessor(factory, List.of(parser)).read(request);
70+
assertNotNull(result);
71+
assertEquals(model, result);
72+
}
73+
74+
@Test
75+
void readNullPomPathShouldUseFactoryDirectly() throws Exception {
76+
ModelXmlFactory factory = mock(ModelXmlFactory.class);
77+
XmlReaderRequest request = mock(XmlReaderRequest.class);
78+
Model model = mock(Model.class);
79+
when(request.getPath()).thenReturn(null);
80+
when(factory.read(request)).thenReturn(model);
81+
Model result = new DefaultModelProcessor(factory, List.of()).read(request);
82+
assertNotNull(result);
83+
assertEquals(model, result);
84+
}
85+
86+
@Test
87+
void readNullPomPathShouldUseFactoryDirectly22() throws Exception {
88+
ModelXmlFactory factory = mock(ModelXmlFactory.class);
89+
ModelParser parser1 = mock(ModelParser.class);
90+
ModelParser parser2 = mock(ModelParser.class);
91+
XmlReaderRequest request = mock(XmlReaderRequest.class);
92+
Path pomPath = Path.of("project/pom.xml");
93+
when(request.getPath()).thenReturn(pomPath);
94+
when(request.isStrict()).thenReturn(true);
95+
96+
Model expectedModel = mock(Model.class);
97+
98+
// Both parsers return empty
99+
when(parser1.locateAndParse(any(), any())).thenReturn(Optional.empty());
100+
when(parser2.locateAndParse(any(), any())).thenReturn(Optional.empty());
101+
// Factory returns model
102+
when(factory.read(request)).thenThrow(new IllegalStateException(new IOException()));
103+
assertThrows(
104+
IllegalStateException.class, () -> new DefaultModelProcessor(factory, List.of()).read(request));
105+
}
106+
107+
@Test
108+
void locateExistingPomWithParsersShouldReturnFirstValid() {
109+
Path expectedPom = Path.of("project/pom.xml");
110+
Source mockSource = mock(Source.class);
111+
when(mockSource.getPath()).thenReturn(expectedPom);
112+
ModelParser parser = mock(ModelParser.class);
113+
when(parser.locate(any())).thenReturn(Optional.of(mockSource));
114+
assertEquals(
115+
expectedPom,
116+
new DefaultModelProcessor(mock(ModelXmlFactory.class), List.of(parser))
117+
.locateExistingPom(Path.of("project")));
118+
}
119+
120+
@Test
121+
void locateExistingPomParserReturnsPathOutsideProjectShouldThrow() {
122+
Source mockSource = mock(Source.class);
123+
when(mockSource.getPath()).thenReturn(Path.of("other/pom.xml"));
124+
ModelParser parser = mock(ModelParser.class);
125+
when(parser.locate(any())).thenReturn(Optional.of(mockSource));
126+
assertThat(assertThrows(IllegalArgumentException.class, () -> new DefaultModelProcessor(
127+
mock(ModelXmlFactory.class), List.of(parser))
128+
.locateExistingPom(Path.of("project")))
129+
.getMessage())
130+
.contains("does not belong to the given directory");
131+
}
132+
133+
@Test
134+
void locateExistingPomFallbackWithValidPomShouldReturnPom() throws Exception {
135+
testProjectDir = Files.createTempDirectory(tempDir, "testproject");
136+
testPomFile = testProjectDir.resolve("pom.xml");
137+
Files.createFile(testPomFile);
138+
assertEquals(
139+
testPomFile,
140+
new DefaultModelProcessor(mock(ModelXmlFactory.class), List.of()).locateExistingPom(testProjectDir));
141+
}
142+
143+
@Test
144+
void locateExistingPomFallbackWithFileAsPathShouldReturnThatFile() throws Exception {
145+
testPomFile = Files.createTempFile(tempDir, "pom", ".xml");
146+
assertEquals(
147+
testPomFile,
148+
new DefaultModelProcessor(mock(ModelXmlFactory.class), List.of()).locateExistingPom(testPomFile));
149+
}
150+
151+
@Test
152+
void readWithParserThrowingExceptionShouldCollectException() {
153+
ModelXmlFactory factory = mock(ModelXmlFactory.class);
154+
ModelParser parser = mock(ModelParser.class);
155+
XmlReaderRequest request = mock(XmlReaderRequest.class);
156+
when(request.getPath()).thenReturn(Path.of("project/pom.xml"));
157+
when(request.isStrict()).thenReturn(true);
158+
when(parser.locateAndParse(any(), any())).thenThrow(new RuntimeException("Parser error"));
159+
when(factory.read(request)).thenThrow(new RuntimeException("Factory error"));
160+
RuntimeException ex = assertThrows(
161+
RuntimeException.class, () -> new DefaultModelProcessor(factory, List.of(parser)).read(request));
162+
assertEquals("Parser error", ex.getMessage());
163+
assertEquals(0, ex.getSuppressed().length);
164+
}
165+
166+
@Test
167+
void readWithFactoryThrowingExceptionShouldRethrowWithSuppressed() {
168+
ModelXmlFactory factory = mock(ModelXmlFactory.class);
169+
XmlReaderRequest request = mock(XmlReaderRequest.class);
170+
when(request.getPath()).thenReturn(Path.of("project/pom.xml"));
171+
when(factory.read(request)).thenThrow(new RuntimeException("Factory error"));
172+
ModelParser parser = mock(ModelParser.class);
173+
when(parser.locateAndParse(any(), any())).thenThrow(new RuntimeException("Parser error"));
174+
RuntimeException ex = assertThrows(
175+
RuntimeException.class, () -> new DefaultModelProcessor(factory, List.of(parser)).read(request));
176+
assertEquals("Parser error", ex.getMessage());
177+
assertEquals(0, ex.getSuppressed().length);
178+
}
179+
180+
@Test
181+
void locateExistingPomWithDirectoryContainingPom() throws IOException {
182+
testProjectDir = Files.createTempDirectory(tempDir, "project");
183+
testPomFile = testProjectDir.resolve("pom.xml");
184+
Files.createFile(testPomFile);
185+
assertEquals(
186+
testPomFile,
187+
new DefaultModelProcessor(mock(ModelXmlFactory.class), List.of()).locateExistingPom(testProjectDir));
188+
}
189+
190+
@Test
191+
void locateExistingPomWithDirectoryWithoutPom() throws IOException {
192+
testProjectDir = Files.createTempDirectory(tempDir, "project");
193+
assertNull(new DefaultModelProcessor(mock(ModelXmlFactory.class), List.of()).locateExistingPom(testProjectDir));
194+
}
195+
196+
@Test
197+
void locateExistingPomWithPomFile() throws IOException {
198+
testPomFile = Files.createTempFile(tempDir, "pom", ".xml");
199+
assertEquals(
200+
testPomFile,
201+
new DefaultModelProcessor(mock(ModelXmlFactory.class), List.of()).locateExistingPom(testPomFile));
202+
}
203+
204+
@Test
205+
void locateExistingPomShouldAcceptPomInProjectDirectory() {
206+
Path projectDir = Path.of("project");
207+
Path pomInDir = projectDir.resolve("pom.xml");
208+
Source mockSource = mock(Source.class);
209+
when(mockSource.getPath()).thenReturn(pomInDir);
210+
ModelParser parser = mock(ModelParser.class);
211+
when(parser.locate(any())).thenReturn(Optional.of(mockSource));
212+
assertEquals(
213+
pomInDir,
214+
new DefaultModelProcessor(mock(ModelXmlFactory.class), List.of(parser)).locateExistingPom(projectDir));
215+
}
216+
217+
@Test
218+
void locateExistingPomShouldAcceptPomAsProjectDirectory() {
219+
Path pomFile = Path.of("pom.xml");
220+
Source mockSource = mock(Source.class);
221+
when(mockSource.getPath()).thenReturn(pomFile);
222+
ModelParser parser = mock(ModelParser.class);
223+
when(parser.locate(any())).thenReturn(Optional.of(mockSource));
224+
assertEquals(
225+
pomFile,
226+
new DefaultModelProcessor(mock(ModelXmlFactory.class), List.of(parser)).locateExistingPom(pomFile));
227+
}
228+
229+
@Test
230+
void locateExistingPomShouldRejectPomInDifferentDirectory() {
231+
Source mockSource = mock(Source.class);
232+
when(mockSource.getPath()).thenReturn(Path.of("other/pom.xml"));
233+
ModelParser parser = mock(ModelParser.class);
234+
when(parser.locate(any())).thenReturn(Optional.of(mockSource));
235+
assertTrue(assertThrows(IllegalArgumentException.class, () -> new DefaultModelProcessor(
236+
mock(ModelXmlFactory.class), List.of(parser))
237+
.locateExistingPom(Path.of("project")))
238+
.getMessage()
239+
.contains("does not belong to the given directory"));
240+
}
241+
242+
243+
244+
@Test
245+
void readWithParserThrowingModelParserExceptionShouldAddAsSuppressed() throws Exception {
246+
ModelXmlFactory factory = mock(ModelXmlFactory.class);
247+
ModelParser parser = mock(ModelParser.class);
248+
XmlReaderRequest request = mock(XmlReaderRequest.class);
249+
Path pomPath = Path.of("project/pom.xml");
250+
when(request.getPath()).thenReturn(pomPath);
251+
when(request.isStrict()).thenReturn(true);
252+
253+
ModelParserException parserException = new ModelParserException("Parser error");
254+
when(parser.locateAndParse(any(), any())).thenThrow(parserException);
255+
256+
Model expectedModel = mock(Model.class);
257+
when(factory.read(request)).thenReturn(expectedModel);
258+
259+
Model result = new DefaultModelProcessor(factory, List.of(parser)).read(request);
260+
261+
assertSame(expectedModel, result);
262+
// In this case, since factory succeeds, no exception is thrown
263+
}
264+
265+
@Test
266+
void readWithParserReturningEmptyShouldTryNextParser() throws Exception {
267+
ModelXmlFactory factory = mock(ModelXmlFactory.class);
268+
ModelParser parser1 = mock(ModelParser.class);
269+
ModelParser parser2 = mock(ModelParser.class);
270+
XmlReaderRequest request = mock(XmlReaderRequest.class);
271+
Path pomPath = Path.of("project/pom.xml");
272+
when(request.getPath()).thenReturn(pomPath);
273+
when(request.isStrict()).thenReturn(true);
274+
275+
Model expectedModel = mock(Model.class);
276+
when(expectedModel.withPomFile(pomPath)).thenReturn(expectedModel);
277+
278+
// First parser returns empty
279+
when(parser1.locateAndParse(any(), any())).thenReturn(Optional.empty());
280+
// Second parser returns model
281+
when(parser2.locateAndParse(any(), any())).thenReturn(Optional.of(expectedModel));
282+
283+
Model result = new DefaultModelProcessor(factory, List.of(parser1, parser2)).read(request);
284+
285+
assertSame(expectedModel, result);
286+
}
287+
288+
@Test
289+
void readWithAllParsersReturningEmptyShouldFallbackToFactory() throws Exception {
290+
ModelXmlFactory factory = mock(ModelXmlFactory.class);
291+
ModelParser parser1 = mock(ModelParser.class);
292+
ModelParser parser2 = mock(ModelParser.class);
293+
XmlReaderRequest request = mock(XmlReaderRequest.class);
294+
Path pomPath = Path.of("project/pom.xml");
295+
when(request.getPath()).thenReturn(pomPath);
296+
when(request.isStrict()).thenReturn(true);
297+
298+
Model expectedModel = mock(Model.class);
299+
300+
// Both parsers return empty
301+
when(parser1.locateAndParse(any(), any())).thenReturn(Optional.empty());
302+
when(parser2.locateAndParse(any(), any())).thenReturn(Optional.empty());
303+
// Factory returns model
304+
when(factory.read(request)).thenReturn(expectedModel);
305+
306+
Model result = new DefaultModelProcessor(factory, List.of(parser1, parser2)).read(request);
307+
308+
assertSame(expectedModel, result);
309+
}
310+
311+
@Test
312+
void readWithParserReturningModelShouldUseThatModel() throws Exception {
313+
ModelXmlFactory factory = mock(ModelXmlFactory.class);
314+
ModelParser parser = mock(ModelParser.class);
315+
XmlReaderRequest request = mock(XmlReaderRequest.class);
316+
Path pomPath = Path.of("project/pom.xml");
317+
when(request.getPath()).thenReturn(pomPath);
318+
when(request.isStrict()).thenReturn(true);
319+
320+
Model expectedModel = mock(Model.class);
321+
when(expectedModel.withPomFile(pomPath)).thenReturn(expectedModel);
322+
when(parser.locateAndParse(any(), any())).thenReturn(Optional.of(expectedModel));
323+
324+
Model result = new DefaultModelProcessor(factory, List.of(parser)).read(request);
325+
326+
assertSame(expectedModel, result);
327+
// Verify factory was not called
328+
verify(factory, never()).read((Path) any());
329+
}
330+
331+
@Test
332+
void readWithParserReturningModelShouldSetPomFile() throws Exception {
333+
ModelXmlFactory factory = mock(ModelXmlFactory.class);
334+
ModelParser parser = mock(ModelParser.class);
335+
XmlReaderRequest request = mock(XmlReaderRequest.class);
336+
Path pomPath = Path.of("project/pom.xml");
337+
when(request.getPath()).thenReturn(pomPath);
338+
when(request.isStrict()).thenReturn(true);
339+
340+
Model originalModel = mock(Model.class);
341+
Model modelWithPom = mock(Model.class);
342+
when(originalModel.withPomFile(pomPath)).thenReturn(modelWithPom);
343+
when(parser.locateAndParse(any(), any())).thenReturn(Optional.of(originalModel));
344+
345+
Model result = new DefaultModelProcessor(factory, List.of(parser)).read(request);
346+
347+
assertSame(modelWithPom, result);
348+
verify(originalModel).withPomFile(pomPath);
349+
}
350+
351+
352+
}

0 commit comments

Comments
 (0)