diff --git a/src/it/mrm/repository/mph183-boot-bom-1.0.pom b/src/it/mrm/repository/mph183-boot-bom-1.0.pom new file mode 100644 index 00000000..ef5d2f0d --- /dev/null +++ b/src/it/mrm/repository/mph183-boot-bom-1.0.pom @@ -0,0 +1,45 @@ + + + + + + 4.0.0 + + org.apache.maven.plugins.help.it + mph183-boot-bom + 1.0 + pom + + + 2.1 + + + + + + org.apache.maven.plugins.help.it + mph183-tool-bom + ${mph183-tool.version} + pom + import + + + + diff --git a/src/it/mrm/repository/mph183-tool-bom-2.1.pom b/src/it/mrm/repository/mph183-tool-bom-2.1.pom new file mode 100644 index 00000000..b0ae8b14 --- /dev/null +++ b/src/it/mrm/repository/mph183-tool-bom-2.1.pom @@ -0,0 +1,39 @@ + + + + + + 4.0.0 + + org.apache.maven.plugins.help.it + mph183-tool-bom + 2.1 + pom + + + + + org.apache.maven.plugins.help.it + mph183-tool-lib1 + 2.1 + + + + diff --git a/src/it/mrm/repository/mph183-tool-lib1-2.1.pom b/src/it/mrm/repository/mph183-tool-lib1-2.1.pom new file mode 100644 index 00000000..4d64ad95 --- /dev/null +++ b/src/it/mrm/repository/mph183-tool-lib1-2.1.pom @@ -0,0 +1,28 @@ + + + + + + 4.0.0 + + org.apache.maven.plugins.help.it + mph183-tool-lib1 + 2.1 + diff --git a/src/it/projects/effective-pom-with-bom/invoker.properties b/src/it/projects/effective-pom-with-bom/invoker.properties new file mode 100644 index 00000000..bd7c354f --- /dev/null +++ b/src/it/projects/effective-pom-with-bom/invoker.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +invoker.goals = ${project.groupId}:${project.artifactId}:${project.version}:effective-pom \ No newline at end of file diff --git a/src/it/projects/effective-pom-with-bom/pom.xml b/src/it/projects/effective-pom-with-bom/pom.xml new file mode 100644 index 00000000..5b2cc839 --- /dev/null +++ b/src/it/projects/effective-pom-with-bom/pom.xml @@ -0,0 +1,47 @@ + + + + + + 4.0.0 + + org.apache.maven.plugins.help.it + mph183 + 1.0 + + + + + org.apache.maven.plugins.help.it + mph183-boot-bom + 1.0 + pom + import + + + + + + + org.apache.maven.plugins.help.it + mph183-tool-lib1 + + + diff --git a/src/it/projects/effective-pom-with-bom/test.properties b/src/it/projects/effective-pom-with-bom/test.properties new file mode 100644 index 00000000..a03a0265 --- /dev/null +++ b/src/it/projects/effective-pom-with-bom/test.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +output = result.txt +verbose = true \ No newline at end of file diff --git a/src/main/java/org/apache/maven/plugins/help/DefaultInputLocationFormatter.java b/src/main/java/org/apache/maven/plugins/help/DefaultInputLocationFormatter.java new file mode 100644 index 00000000..856c6dd1 --- /dev/null +++ b/src/main/java/org/apache/maven/plugins/help/DefaultInputLocationFormatter.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.plugins.help; + +import org.apache.maven.model.InputLocation; +import org.apache.maven.model.InputSource; +import org.codehaus.plexus.util.StringUtils; + +/** + * Maven 3.x-based implementation of {@link InputLocation.StringFormatter}. + */ +public class DefaultInputLocationFormatter extends InputLocation.StringFormatter { + @Override + public String toString(InputLocation location) { + InputSource source = location.getSource(); + + String s = source.getModelId(); // by default, display modelId + + if (StringUtils.isBlank(s) || s.contains("[unknown-version]")) { + // unless it is blank or does not provide version information + s = source.toString(); + } + + return '}' + s + ((location.getLineNumber() >= 0) ? ", line " + location.getLineNumber() : "") + ' '; + } +} diff --git a/src/main/java/org/apache/maven/plugins/help/EffectivePomMojo.java b/src/main/java/org/apache/maven/plugins/help/EffectivePomMojo.java index c38e2c53..384cdabc 100644 --- a/src/main/java/org/apache/maven/plugins/help/EffectivePomMojo.java +++ b/src/main/java/org/apache/maven/plugins/help/EffectivePomMojo.java @@ -24,8 +24,6 @@ import java.util.List; import java.util.Properties; -import org.apache.maven.model.InputLocation; -import org.apache.maven.model.InputSource; import org.apache.maven.model.Model; import org.apache.maven.model.io.xpp3.MavenXpp3Writer; import org.apache.maven.model.io.xpp3.MavenXpp3WriterEx; @@ -176,7 +174,7 @@ private void writeEffectivePom(MavenProject project, XMLWriter writer) throws Mo try { if (verbose) { MavenXpp3WriterEx mavenXpp3WriterEx = new MavenXpp3WriterEx(); - mavenXpp3WriterEx.setStringFormatter(new InputLocationStringFormatter()); + mavenXpp3WriterEx.setStringFormatter(InputLocationFormatterFactory.produce(getLog(), project)); mavenXpp3WriterEx.write(sWriter, pom); } else { new MavenXpp3Writer().write(sWriter, pom); @@ -203,20 +201,4 @@ private static void cleanModel(Model pom) { properties.putAll(pom.getProperties()); pom.setProperties(properties); } - - private static class InputLocationStringFormatter extends InputLocation.StringFormatter { - @Override - public String toString(InputLocation location) { - InputSource source = location.getSource(); - - String s = source.getModelId(); // by default, display modelId - - if (StringUtils.isBlank(s) || s.contains("[unknown-version]")) { - // unless it is blank or does not provide version information - s = source.toString(); - } - - return '}' + s + ((location.getLineNumber() >= 0) ? ", line " + location.getLineNumber() : "") + ' '; - } - } } diff --git a/src/main/java/org/apache/maven/plugins/help/ImportedFromLocationFormatter.java b/src/main/java/org/apache/maven/plugins/help/ImportedFromLocationFormatter.java new file mode 100644 index 00000000..868bd5b5 --- /dev/null +++ b/src/main/java/org/apache/maven/plugins/help/ImportedFromLocationFormatter.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.plugins.help; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Set; + +import org.apache.maven.model.Dependency; +import org.apache.maven.model.InputLocation; +import org.apache.maven.model.InputSource; +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.util.StringUtils; + +/** + * Implementation of {@link InputLocation.StringFormatter}. Enhances the default implementation with support for + * following "references" (caused by e.g. dependency management imports). + */ +public class ImportedFromLocationFormatter extends InputLocation.StringFormatter { + private final Method getImportedFromMethod; + private final MavenProject project; + + public ImportedFromLocationFormatter(final Method getImportedFromMethod, final MavenProject project) { + this.getImportedFromMethod = getImportedFromMethod; + this.project = project; + } + + @Override + public String toString(InputLocation location) { + InputSource source = location.getSource(); + + String s = source.getModelId(); // by default, display modelId + + if (StringUtils.isBlank(s) || s.contains("[unknown-version]")) { + // unless it is blank or does not provide version information + s = source.toString(); + } + + InputLocation importedFrom = getImportedFrom(location); + + StringBuilder p = new StringBuilder(); + + while (importedFrom != null + && !source.toString().equals(importedFrom.getSource().toString())) { + p.append(" from ").append(importedFrom.getSource().getModelId()); + importedFrom = getImportedFrom(importedFrom); + } + + return '}' + s + ((location.getLineNumber() >= 0) ? ", line " + location.getLineNumber() : "") + p; + } + + protected InputLocation getImportedFrom(final InputLocation location) { + try { + InputLocation result = (InputLocation) getImportedFromMethod.invoke(location); + + if (result == null && project != null) { + for (Dependency dependency : project.getDependencyManagement().getDependencies()) { + // Until a new maven api model is released, we need to use reflection to access the locations + Set locationKeys = getLocationKeys(dependency); + for (Object key : locationKeys) { + if (!(key instanceof String)) { + throw new RuntimeException( + "Expected a String, got " + key.getClass().getName()); + } + + InputLocation dependencyLocation = dependency.getLocation(key); + if (dependencyLocation != null + && dependencyLocation.toString().equals(location.toString())) { + result = (InputLocation) Dependency.class + .getMethod("getImportedFrom") + .invoke(dependency); + break; + } + } + } + } + + return result; + } catch (IllegalAccessException + | InvocationTargetException + | NoSuchMethodException + | NoSuchFieldException + | ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + private Set getLocationKeys(Dependency dependency) + throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException { + Field delegateField = Class.forName("org.apache.maven.model.BaseObject").getDeclaredField("delegate"); + delegateField.setAccessible(true); + Object delegate = delegateField.get(dependency); + delegateField.setAccessible(false); + + Field locationsField = delegate.getClass().getDeclaredField("locations"); + locationsField.setAccessible(true); + Object locations = locationsField.get(delegate); + locationsField.setAccessible(false); + + if (!(locations instanceof Map)) { + throw new RuntimeException( + "Expected a Map, got " + locations.getClass().getName()); + } + + return ((Map) locations).keySet(); + } +} diff --git a/src/main/java/org/apache/maven/plugins/help/InputLocationFormatterFactory.java b/src/main/java/org/apache/maven/plugins/help/InputLocationFormatterFactory.java new file mode 100644 index 00000000..048758c0 --- /dev/null +++ b/src/main/java/org/apache/maven/plugins/help/InputLocationFormatterFactory.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.plugins.help; + +import java.lang.reflect.Method; + +import org.apache.maven.model.InputLocation; +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.project.MavenProject; + +/** + * Selects the most suitable implementation for {@link InputLocation.StringFormatter}. + */ +public class InputLocationFormatterFactory { + static Class inputLocationClass = InputLocation.class; + + public static InputLocation.StringFormatter produce(final Log log, final MavenProject project) { + try { + // This method was introduced in Maven 4. + Method getImportedFromMethod = inputLocationClass.getDeclaredMethod("getImportedFrom"); + return new ImportedFromLocationFormatter(getImportedFromMethod, project); + } catch (NoSuchMethodException nsme) { + // Fallback to pre-Maven 4 implementation. + log.info("Unable to print chain of POM imports, falling back to printing the source POM " + + "without import information. This feature is available in Maven 4.0.0+."); + return new DefaultInputLocationFormatter(); + } + } +} diff --git a/src/test/java/org/apache/maven/plugins/help/DefaultInputLocationFormatterTest.java b/src/test/java/org/apache/maven/plugins/help/DefaultInputLocationFormatterTest.java new file mode 100644 index 00000000..288e4932 --- /dev/null +++ b/src/test/java/org/apache/maven/plugins/help/DefaultInputLocationFormatterTest.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.plugins.help; + +import org.apache.maven.model.InputLocation; +import org.apache.maven.model.InputSource; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.StringContains.containsString; + +public class DefaultInputLocationFormatterTest { + private final InputLocation.StringFormatter formatter = new DefaultInputLocationFormatter(); + + @Test + public void withLineNumberShouldIncludeLineNumber() { + // Arrange + final InputSource source = new InputSource(); + source.setModelId("foo:bar:1.0-SNAPSHOT"); + source.setLocation("/tmp/project/pom.xml"); + final InputLocation location = new InputLocation(3, 5, source); + + // Act + final String result = formatter.toString(location); + + // Assert + assertThat(result, containsString("line 3")); + } + + @Test + public void withoutLineNumberShouldNotIncludeLineNumber() { + // Arrange + final InputSource source = new InputSource(); + source.setModelId("foo:bar:1.0-SNAPSHOT"); + source.setLocation("/tmp/project/pom.xml"); + final InputLocation location = new InputLocation(-1, -1, source); + + // Act + final String result = formatter.toString(location); + + // Assert + assertThat(result, not(containsString("line"))); + } + + @Test + public void withModelIdShouldIncludeModelId() { + // Arrange + final InputSource source = new InputSource(); + source.setModelId("foo:bar:1.0-SNAPSHOT"); + source.setLocation("/tmp/project/pom.xml"); + final InputLocation location = new InputLocation(3, 5, source); + + // Act + final String result = formatter.toString(location); + + // Assert + assertThat(result, containsString("foo:bar:1.0-SNAPSHOT")); + } + + @Test + public void withoutModelIdShouldIncludeUnknownVersion() { + // Arrange + final InputSource source = new InputSource(); + source.setLocation("/tmp/project/pom.xml"); + final InputLocation location = new InputLocation(3, 5, source); + + // Act + final String result = formatter.toString(location); + + // Assert + assertThat(result, not(containsString("foo:bar:1.0-SNAPSHOT"))); + } +} diff --git a/src/test/java/org/apache/maven/plugins/help/ImportedFromLocationFormatterTest.java b/src/test/java/org/apache/maven/plugins/help/ImportedFromLocationFormatterTest.java new file mode 100644 index 00000000..0112ef17 --- /dev/null +++ b/src/test/java/org/apache/maven/plugins/help/ImportedFromLocationFormatterTest.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.plugins.help; + +import java.util.Stack; + +import org.apache.maven.model.InputLocation; +import org.apache.maven.model.InputSource; +import org.apache.maven.project.MavenProject; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class ImportedFromLocationFormatterTest { + + @Test + public void testImportedFromSingleLocation() { + // Arrange + final MavenProject project = new MavenProject(); + final ImportedFromLocationFormatter formatter = new ImportedFromLocationFormatterMock(project); + + final InputSource source = new InputSource(); + source.setModelId("org.example:MPG-183-project:1-SNAPSHOT"); + final InputLocation location = new InputLocation(7, 5, source); + + // Act + final String result = formatter.toString(location); + + // Assert + assertEquals("}org.example:MPG-183-project:1-SNAPSHOT, line 7", result); + } + + @Test + public void testImportedFromDifferentLocation() { + // Arrange + final InputSource importedFromSource = new InputSource(); + importedFromSource.setModelId("org.example:MPG-183-bom2:1-SNAPSHOT"); + final InputLocation importedFrom = new InputLocation(7, 5, importedFromSource); + + final MavenProject project = new MavenProject(); + final ImportedFromLocationFormatter formatter = new ImportedFromLocationFormatterMock(project, importedFrom); + + final InputSource source = new InputSource(); + source.setModelId("org.example:MPG-183-bom1:1-SNAPSHOT"); + final InputLocation location = new InputLocation(7, 5, source); + + // Act + final String result = formatter.toString(location); + + // Assert + assertEquals("}org.example:MPG-183-bom1:1-SNAPSHOT, line 7 from org.example:MPG-183-bom2:1-SNAPSHOT", result); + } + + @Test + public void testImportedFromDoNotPrintSameLocationTwice() { + // Arrange + final InputSource importedFromSource = new InputSource(); + importedFromSource.setModelId("org.example:MPG-183-bom:1-SNAPSHOT"); + final InputLocation importedFrom = new InputLocation(7, 5, importedFromSource); + + final MavenProject project = new MavenProject(); + final ImportedFromLocationFormatter formatter = new ImportedFromLocationFormatterMock(project, importedFrom); + + final InputSource source = new InputSource(); + source.setModelId("org.example:MPG-183-bom:1-SNAPSHOT"); + final InputLocation location = new InputLocation(7, 5, source); + + // Act + final String result = formatter.toString(location); + + // Assert + assertEquals("}org.example:MPG-183-bom:1-SNAPSHOT, line 7", result); + } + + @Test + public void testImportedFromMultiLevelPrintsWithFrom() { + // Arrange + final ImportedFromLocationFormatter formatter = createMultiImportedFromFormatter(); + + final InputSource source = new InputSource(); + source.setModelId("org.example:MPG-183-project:1-SNAPSHOT"); + final InputLocation location = new InputLocation(7, 5, source); + + // Act + final String result = formatter.toString(location); + + // Assert + String expected = + "}org.example:MPG-183-project:1-SNAPSHOT, line 7 from org.example:MPG-183-bom-2:1-SNAPSHOT from org.example:MPG-183-bom-1:1-SNAPSHOT"; + assertEquals(expected, result); + } + + private static ImportedFromLocationFormatter createMultiImportedFromFormatter() { + final InputSource importedFromSource1 = new InputSource(); + importedFromSource1.setModelId("org.example:MPG-183-bom-1:1-SNAPSHOT"); + final InputLocation importedFrom1 = new InputLocation(7, 5, importedFromSource1); + + final InputSource importedFromSource2 = new InputSource(); + importedFromSource2.setModelId("org.example:MPG-183-bom-2:1-SNAPSHOT"); + final InputLocation importedFrom2 = new InputLocation(7, 5, importedFromSource2); + + return new ImportedFromLocationFormatterMock(new MavenProject(), importedFrom1, importedFrom2); + } + + private static class ImportedFromLocationFormatterMock extends ImportedFromLocationFormatter { + private final Stack mockedImportedFrom; + + public ImportedFromLocationFormatterMock(MavenProject project) { + this(project, new Stack<>()); + } + + public ImportedFromLocationFormatterMock(MavenProject project, Stack mockedImportedFrom) { + super(null, project); + this.mockedImportedFrom = mockedImportedFrom; + } + + public ImportedFromLocationFormatterMock(MavenProject project, InputLocation... mockedImportedFrom) { + super(null, project); + + this.mockedImportedFrom = new Stack<>(); + for (InputLocation location : mockedImportedFrom) { + this.mockedImportedFrom.push(location); + } + } + + @Override + protected InputLocation getImportedFrom(InputLocation location) { + return !mockedImportedFrom.isEmpty() ? mockedImportedFrom.pop() : null; + } + } +} diff --git a/src/test/java/org/apache/maven/plugins/help/InputLocationFormatterFactoryTest.java b/src/test/java/org/apache/maven/plugins/help/InputLocationFormatterFactoryTest.java new file mode 100644 index 00000000..f383abb8 --- /dev/null +++ b/src/test/java/org/apache/maven/plugins/help/InputLocationFormatterFactoryTest.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.plugins.help; + +import org.apache.maven.model.InputLocation; +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.project.MavenProject; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.*; + +public class InputLocationFormatterFactoryTest { + @Test + public void whenNoSuchMethodThrownReturnsDefaultInputLocationFormatter() { + // Arrange + final Log log = mock(Log.class); + final MavenProject project = mock(MavenProject.class); + + // Act + final InputLocation.StringFormatter result = InputLocationFormatterFactory.produce(log, project); + + // Assert + assertThat(result, instanceOf(DefaultInputLocationFormatter.class)); + } + + @Test + public void whenMethodExistsReturnsMaven4InputLocationFormatter() { + // Arrange + InputLocationFormatterFactory.inputLocationClass = InputLocationStub.class; + + final Log log = mock(Log.class); + final MavenProject project = mock(MavenProject.class); + + // Act + final InputLocation.StringFormatter result = InputLocationFormatterFactory.produce(log, project); + + // Assert + assertThat(result, instanceOf(ImportedFromLocationFormatter.class)); + } + + private static class InputLocationStub { + public String getImportedFrom() { + return ""; + } + } +}