diff --git a/src/it-repo/dummy-parent5-1.0.0.pom b/src/it-repo/dummy-parent5-1.0.0.pom
new file mode 100644
index 0000000000..fa778abe72
--- /dev/null
+++ b/src/it-repo/dummy-parent5-1.0.0.pom
@@ -0,0 +1,10 @@
+
+ 4.0.0
+
+ localhost
+ dummy-parent5
+ 1.0.0
+ pom
+
+
diff --git a/src/it-repo/dummy-parent5-2.0.0-rc1.pom b/src/it-repo/dummy-parent5-2.0.0-rc1.pom
new file mode 100644
index 0000000000..ddaaab726e
--- /dev/null
+++ b/src/it-repo/dummy-parent5-2.0.0-rc1.pom
@@ -0,0 +1,10 @@
+
+ 4.0.0
+
+ localhost
+ dummy-parent5
+ 2.0.0-rc1
+ pom
+
+
diff --git a/src/it/it-resolve-ranges-issue-454/invoker.properties b/src/it/it-resolve-ranges-issue-454/invoker.properties
new file mode 100644
index 0000000000..e616e229f3
--- /dev/null
+++ b/src/it/it-resolve-ranges-issue-454/invoker.properties
@@ -0,0 +1,2 @@
+invoker.goals = ${project.groupId}:${project.artifactId}:${project.version}:resolve-ranges
+invoker.mavenOpts = -DallowMajorUpdates=false
diff --git a/src/it/it-resolve-ranges-issue-454/pom.xml b/src/it/it-resolve-ranges-issue-454/pom.xml
new file mode 100644
index 0000000000..7dd7e4af92
--- /dev/null
+++ b/src/it/it-resolve-ranges-issue-454/pom.xml
@@ -0,0 +1,20 @@
+
+ 4.0.0
+
+ localhost
+ test-artifact
+ 1.0.0
+
+
+ [1.0.0,)
+
+
+
+ localhost
+ dummy-parent5
+ ${ver}
+
+
+
+
diff --git a/src/it/it-resolve-ranges-issue-454/verify.groovy b/src/it/it-resolve-ranges-issue-454/verify.groovy
new file mode 100644
index 0000000000..e9182fd7f3
--- /dev/null
+++ b/src/it/it-resolve-ranges-issue-454/verify.groovy
@@ -0,0 +1,3 @@
+pom = new File( basedir, "pom.xml" ).text
+
+assert !( pom =~ /2.0.0-rc1/ )
diff --git a/src/it/it-update-parent-issue-454/invoker.properties b/src/it/it-update-parent-issue-454/invoker.properties
new file mode 100644
index 0000000000..ea39882c84
--- /dev/null
+++ b/src/it/it-update-parent-issue-454/invoker.properties
@@ -0,0 +1,2 @@
+invoker.goals = ${project.groupId}:${project.artifactId}:${project.version}:update-parent
+invoker.mavenOpts = -DallowMajorUpdates=false
diff --git a/src/it/it-update-parent-issue-454/pom.xml b/src/it/it-update-parent-issue-454/pom.xml
new file mode 100644
index 0000000000..fee0e8da8f
--- /dev/null
+++ b/src/it/it-update-parent-issue-454/pom.xml
@@ -0,0 +1,14 @@
+
+ 4.0.0
+
+ test-artifact
+ 1.0.0
+
+
+ localhost
+ dummy-parent5
+ 1.0.0
+
+
+
diff --git a/src/it/it-update-parent-issue-454/verify.groovy b/src/it/it-update-parent-issue-454/verify.groovy
new file mode 100644
index 0000000000..e9182fd7f3
--- /dev/null
+++ b/src/it/it-update-parent-issue-454/verify.groovy
@@ -0,0 +1,3 @@
+pom = new File( basedir, "pom.xml" ).text
+
+assert !( pom =~ /2.0.0-rc1/ )
diff --git a/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojo.java b/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojo.java
index 9cb0e812e0..4716c72cd2 100644
--- a/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojo.java
+++ b/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojo.java
@@ -104,7 +104,7 @@ public class UpdatePropertiesMojo extends AbstractVersionsDependencyUpdaterMojo
*/
@Parameter( property = "allowMajorUpdates",
defaultValue = "true" )
- protected boolean allowMajorUpdates;
+ protected boolean allowMajorUpdates = true;
/**
* Whether to allow the minor version number to be changed.
@@ -113,7 +113,7 @@ public class UpdatePropertiesMojo extends AbstractVersionsDependencyUpdaterMojo
*/
@Parameter( property = "allowMinorUpdates",
defaultValue = "true" )
- protected boolean allowMinorUpdates;
+ protected boolean allowMinorUpdates = true;
/**
* Whether to allow the incremental version number to be changed.
@@ -122,7 +122,7 @@ public class UpdatePropertiesMojo extends AbstractVersionsDependencyUpdaterMojo
*/
@Parameter( property = "allowIncrementalUpdates",
defaultValue = "true" )
- protected boolean allowIncrementalUpdates;
+ protected boolean allowIncrementalUpdates = true;
// -------------------------- STATIC METHODS --------------------------
diff --git a/src/main/java/org/codehaus/mojo/versions/UpdatePropertyMojo.java b/src/main/java/org/codehaus/mojo/versions/UpdatePropertyMojo.java
index ea7e4c002c..a6dac741b3 100644
--- a/src/main/java/org/codehaus/mojo/versions/UpdatePropertyMojo.java
+++ b/src/main/java/org/codehaus/mojo/versions/UpdatePropertyMojo.java
@@ -61,7 +61,7 @@ public class UpdatePropertyMojo
* @since 1.3
*/
@Parameter( property = "property" )
- private String property = null;
+ protected String property = null;
/**
* The new version to set the property to (can be a version range to find a version within).
diff --git a/src/main/java/org/codehaus/mojo/versions/api/PropertyVersions.java b/src/main/java/org/codehaus/mojo/versions/api/PropertyVersions.java
index 7d4621e630..9b25e60462 100644
--- a/src/main/java/org/codehaus/mojo/versions/api/PropertyVersions.java
+++ b/src/main/java/org/codehaus/mojo/versions/api/PropertyVersions.java
@@ -34,16 +34,19 @@
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
import org.apache.maven.artifact.versioning.ArtifactVersion;
+import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
import org.apache.maven.artifact.versioning.Restriction;
import org.apache.maven.artifact.versioning.VersionRange;
import org.apache.maven.project.MavenProject;
import org.codehaus.mojo.versions.Property;
+import org.codehaus.mojo.versions.ordering.BoundArtifactVersion;
import org.codehaus.mojo.versions.ordering.InvalidSegmentException;
import org.codehaus.mojo.versions.ordering.VersionComparator;
import static java.util.Optional.empty;
+import static org.codehaus.mojo.versions.api.Segment.SUBINCREMENTAL;
/**
* Manages a property that is associated with one or more artifacts.
@@ -320,22 +323,21 @@ public ArtifactVersion getNewestVersion( String currentVersion, Property propert
* Retrieves the newest artifact version for the given property-denoted artifact or {@code null} if no newer
* version could be found.
*
- * @param currentVersion current version of the artifact
+ * @param versionString current version of the artifact
* @param property property name indicating the artifact
* @param allowSnapshots whether snapshots should be considered
* @param reactorProjects collection of reactor projects
* @param helper VersionHelper object
* @param allowDowngrade whether downgrades should be allowed
- * @param unchangedSegment indicates the (0-based) most major segment which needs to stay unchanged;
- * -1 means that the whole version can be changed
+ * @param upperBoundSegment the upper bound segment; empty() means no upper bound
* @return newest artifact version fulfilling the criteria or null if no newer version could be found
* @throws InvalidSegmentException thrown if the {@code unchangedSegment} is not valid (e.g. greater than the number
* of segments in the version string)
* @throws InvalidVersionSpecificationException thrown if the version string in the property is not valid
*/
- public ArtifactVersion getNewestVersion( String currentVersion, Property property, boolean allowSnapshots,
+ public ArtifactVersion getNewestVersion( String versionString, Property property, boolean allowSnapshots,
Collection reactorProjects, VersionsHelper helper,
- boolean allowDowngrade, Optional unchangedSegment )
+ boolean allowDowngrade, Optional upperBoundSegment )
throws InvalidSegmentException, InvalidVersionSpecificationException
{
final boolean includeSnapshots = !property.isBanSnapshots() && allowSnapshots;
@@ -346,24 +348,33 @@ public ArtifactVersion getNewestVersion( String currentVersion, Property propert
? VersionRange.createFromVersionSpec( property.getVersion() ) : null;
helper.getLog().debug( "Property ${" + property.getName() + "}: Restricting results to " + range );
- ArtifactVersion lowerBound = helper.createArtifactVersion( currentVersion );
- if ( allowDowngrade )
- {
- Optional updatedVersion = getLowerBound( lowerBound, unchangedSegment );
- lowerBound = updatedVersion.map( helper::createArtifactVersion ).orElse( null );
- }
+
+ ArtifactVersion currentVersion = new DefaultArtifactVersion( versionString );
+ ArtifactVersion lowerBound = allowDowngrade
+ ? getLowerBound( currentVersion, upperBoundSegment )
+ .map( DefaultArtifactVersion::new )
+ .orElse( null )
+ : currentVersion;
if ( helper.getLog().isDebugEnabled() )
{
helper.getLog().debug( "lowerBoundArtifactVersion: " + lowerBound );
}
- ArtifactVersion upperBound = null;
- if ( unchangedSegment.isPresent() )
+ ArtifactVersion upperBound =
+ !upperBoundSegment.isPresent()
+ ? null
+ : upperBoundSegment
+ .map( s -> (ArtifactVersion) new BoundArtifactVersion( currentVersion,
+ s.isMajorTo( SUBINCREMENTAL )
+ ? Segment.of( s.value() + 1 )
+ : s ) )
+ .orElse( null );
+ if ( helper.getLog().isDebugEnabled() )
{
- upperBound = getVersionComparator().incrementSegment( lowerBound, unchangedSegment.get() );
helper.getLog().debug( "Property ${" + property.getName() + "}: upperBound is: " + upperBound );
}
- Restriction restriction = new Restriction( lowerBound, false, upperBound, false );
+
+ Restriction restriction = new Restriction( lowerBound, allowDowngrade, upperBound, allowDowngrade );
ArtifactVersion result = getNewestVersion( range, restriction, includeSnapshots );
helper.getLog().debug( "Property ${" + property.getName() + "}: Current winner is: " + result );
diff --git a/src/test/java/org/codehaus/mojo/versions/ResolveRangesMojoTest.java b/src/test/java/org/codehaus/mojo/versions/ResolveRangesMojoTest.java
new file mode 100644
index 0000000000..9faaf25077
--- /dev/null
+++ b/src/test/java/org/codehaus/mojo/versions/ResolveRangesMojoTest.java
@@ -0,0 +1,33 @@
+package org.codehaus.mojo.versions;
+/*
+ * 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.
+ */
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link ResolveRangesMojo}
+ */
+public class ResolveRangesMojoTest
+{
+ @Test
+ public void testDependencyRangesMajorUpdatesFalse()
+ {
+
+ }
+}
diff --git a/src/test/java/org/codehaus/mojo/versions/UpdatePropertiesMojoTest.java b/src/test/java/org/codehaus/mojo/versions/UpdatePropertiesMojoTest.java
new file mode 100644
index 0000000000..3877397f16
--- /dev/null
+++ b/src/test/java/org/codehaus/mojo/versions/UpdatePropertiesMojoTest.java
@@ -0,0 +1,70 @@
+package org.codehaus.mojo.versions;
+/*
+ * 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.
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import org.codehaus.mojo.versions.change.VersionChange;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+/**
+ * Unit tests for {@link UpdatePropertiesMojo}
+ */
+public class UpdatePropertiesMojoTest extends UpdatePropertiesMojoTestBase
+{
+ @Test
+ public void testAllowMajorUpdates() throws Exception
+ {
+ Files.copy( Paths.get( "src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml" ),
+ Paths.get( pomDir.toString(), "pom.xml" ), REPLACE_EXISTING );
+ setUpMojo( "update-properties" ).execute();
+ assertThat( changeRecorder.getChanges(), Matchers.hasItem( new VersionChange( "default-group",
+ "default-artifact", "1.0.0", "2.0.0-M1" ) ) );
+ }
+
+ @Test
+ public void testAllowMinorUpdates() throws Exception
+ {
+ Files.copy( Paths.get( "src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml" ),
+ Paths.get( pomDir.toString(), "pom.xml" ), REPLACE_EXISTING );
+ UpdatePropertiesMojo mojo = setUpMojo( "update-properties" );
+ mojo.allowMajorUpdates = false;
+ mojo.execute();
+ assertThat( changeRecorder.getChanges(), Matchers.hasItem( new VersionChange( "default-group",
+ "default-artifact", "1.0.0", "1.1.0-alpha" ) ) );
+ }
+
+ @Test
+ public void testAllowIncrementalUpdates() throws Exception
+ {
+ Files.copy( Paths.get( "src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml" ),
+ Paths.get( pomDir.toString(), "pom.xml" ), REPLACE_EXISTING );
+ UpdatePropertiesMojo mojo = setUpMojo( "update-properties" );
+ mojo.allowMajorUpdates = false;
+ mojo.allowMinorUpdates = false;
+ mojo.execute();
+ assertThat( changeRecorder.getChanges(), Matchers.hasItem( new VersionChange( "default-group",
+ "default-artifact", "1.0.0", "1.0.1-rc1" ) ) );
+ }
+}
diff --git a/src/test/java/org/codehaus/mojo/versions/UpdatePropertiesMojoTestBase.java b/src/test/java/org/codehaus/mojo/versions/UpdatePropertiesMojoTestBase.java
new file mode 100644
index 0000000000..431bc30906
--- /dev/null
+++ b/src/test/java/org/codehaus/mojo/versions/UpdatePropertiesMojoTestBase.java
@@ -0,0 +1,84 @@
+package org.codehaus.mojo.versions;
+/*
+ * 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.
+ */
+
+import java.nio.file.Path;
+import java.util.HashMap;
+
+import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
+import org.apache.maven.plugin.Mojo;
+import org.apache.maven.plugin.testing.AbstractMojoTestCase;
+import org.apache.maven.plugin.testing.MojoRule;
+import org.apache.maven.plugin.testing.stubs.StubArtifactRepository;
+import org.codehaus.mojo.versions.utils.TestChangeRecorder;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+
+import static org.codehaus.mojo.versions.utils.MockUtils.mockArtifactMetadataSource;
+import static org.codehaus.mojo.versions.utils.TestUtils.createTempDir;
+import static org.codehaus.mojo.versions.utils.TestUtils.tearDownTempDir;
+
+/**
+ * Base class for {@link UpdatePropertiesMojo} and {@link UpdatePropertyMojo} test suites
+ */
+public abstract class UpdatePropertiesMojoTestBase extends AbstractMojoTestCase
+{
+ @Rule
+ public MojoRule mojoRule = new MojoRule( this );
+ protected Path pomDir;
+ protected ArtifactMetadataSource artifactMetadataSource;
+ protected TestChangeRecorder changeRecorder;
+
+ @Before
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ pomDir = createTempDir( "update-property" );
+ changeRecorder = new TestChangeRecorder();
+ artifactMetadataSource = mockArtifactMetadataSource( new HashMap()
+ {{
+ put( "default-artifact", new String[] {"1.0.0", "1.0.1-rc1", "1.1.0-alpha", "2.0.0-M1"} );
+ }} );
+ }
+
+ @After
+ public void tearDown() throws Exception
+ {
+ try
+ {
+ tearDownTempDir( pomDir );
+ }
+ finally
+ {
+ super.tearDown();
+ }
+ }
+
+ @SuppressWarnings( "unchecked" )
+ protected T setUpMojo( String goal ) throws Exception
+ {
+ T mojo = (T) mojoRule.lookupConfiguredMojo( pomDir.toFile(), goal );
+ setVariableValueToObject( mojo, "localRepository", new StubArtifactRepository( pomDir.toString() ) );
+ setVariableValueToObject( mojo, "artifactMetadataSource", artifactMetadataSource );
+ setVariableValueToObject( mojo, "changeRecorder", changeRecorder );
+ setVariableValueToObject( mojo, "generateBackupPoms", false );
+ return (T) mojo;
+ }
+}
diff --git a/src/test/java/org/codehaus/mojo/versions/UpdatePropertyMojoTest.java b/src/test/java/org/codehaus/mojo/versions/UpdatePropertyMojoTest.java
new file mode 100644
index 0000000000..8e1ec84eab
--- /dev/null
+++ b/src/test/java/org/codehaus/mojo/versions/UpdatePropertyMojoTest.java
@@ -0,0 +1,74 @@
+package org.codehaus.mojo.versions;
+/*
+ * 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.
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import org.codehaus.mojo.versions.change.VersionChange;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+/**
+ * Unit tests for {@link UpdatePropertiesMojo}
+ */
+public class UpdatePropertyMojoTest extends UpdatePropertiesMojoTestBase
+{
+ @Test
+ public void testAllowMajorUpdates() throws Exception
+ {
+ Files.copy( Paths.get( "src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml" ),
+ Paths.get( pomDir.toString(), "pom.xml" ), REPLACE_EXISTING );
+ UpdatePropertyMojo mojo = setUpMojo( "update-property" );
+ mojo.property = "artifact-version";
+ mojo.execute();
+ assertThat( changeRecorder.getChanges(), Matchers.hasItem( new VersionChange( "default-group",
+ "default-artifact", "1.0.0", "2.0.0-M1" ) ) );
+ }
+
+ @Test
+ public void testAllowMinorUpdates() throws Exception
+ {
+ Files.copy( Paths.get( "src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml" ),
+ Paths.get( pomDir.toString(), "pom.xml" ), REPLACE_EXISTING );
+ UpdatePropertyMojo mojo = setUpMojo( "update-property" );
+ mojo.property = "artifact-version";
+ mojo.allowMajorUpdates = false;
+ mojo.execute();
+ assertThat( changeRecorder.getChanges(), Matchers.hasItem( new VersionChange( "default-group",
+ "default-artifact", "1.0.0", "1.1.0-alpha" ) ) );
+ }
+
+ @Test
+ public void testAllowIncrementalUpdates() throws Exception
+ {
+ Files.copy( Paths.get( "src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml" ),
+ Paths.get( pomDir.toString(), "pom.xml" ), REPLACE_EXISTING );
+ UpdatePropertyMojo mojo = setUpMojo( "update-property" );
+ mojo.property = "artifact-version";
+ mojo.allowMajorUpdates = false;
+ mojo.allowMinorUpdates = false;
+ mojo.execute();
+ assertThat( changeRecorder.getChanges(), Matchers.hasItem( new VersionChange( "default-group",
+ "default-artifact", "1.0.0", "1.0.1-rc1" ) ) );
+ }
+}
diff --git a/src/test/java/org/codehaus/mojo/versions/utils/TestUtils.java b/src/test/java/org/codehaus/mojo/versions/utils/TestUtils.java
new file mode 100644
index 0000000000..6e45c91b97
--- /dev/null
+++ b/src/test/java/org/codehaus/mojo/versions/utils/TestUtils.java
@@ -0,0 +1,74 @@
+package org.codehaus.mojo.versions.utils;
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+
+import static java.nio.file.FileVisitResult.CONTINUE;
+import static org.apache.commons.text.CaseUtils.toCamelCase;
+
+/**
+ * Auxiliary test utilities
+ */
+public class TestUtils
+{
+ /**
+ * Creates a temporary directory with the given name
+ * @param name name of the directory to create
+ * @return {@linkplain Path} object pointing to the directory
+ * @throws IOException should the I/O operation fail
+ */
+ public static Path createTempDir( String name ) throws IOException
+ {
+ return Files.createTempDirectory( toCamelCase( name, false ) );
+ }
+
+ /**
+ * Deletes the given directory together with all its contents
+ * @param dir directory to delete
+ * @throws IOException should an I/O operation fail
+ */
+ public static void tearDownTempDir( Path dir ) throws IOException
+ {
+ if ( dir != null && Files.exists( dir ) )
+ {
+ Files.walkFileTree( dir, new SimpleFileVisitor()
+ {
+ @Override
+ public FileVisitResult visitFile( Path file, BasicFileAttributes attrs ) throws IOException
+ {
+ Files.delete( file );
+ return CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory( Path dir, IOException exc ) throws IOException
+ {
+ Files.delete( dir );
+ return CONTINUE;
+ }
+ } );
+ }
+ }
+}
diff --git a/src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml b/src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml
new file mode 100644
index 0000000000..58175f864e
--- /dev/null
+++ b/src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml
@@ -0,0 +1,21 @@
+
+ 4.0.0
+
+ default-group
+ test-artifact
+ 1.0.0
+
+
+ 1.0.0
+
+
+
+
+ default-group
+ default-artifact
+ ${artifact-version}
+
+
+
+