(commentLines.subList(0, index + 1)));
+ return index + 1;
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Tests whether a line is a comment, i.e. whether it starts with a comment
+ * character.
+ *
+ * @param line the line
+ * @return a flag if this is a comment line
+ */
+ static boolean isCommentLine(String line) {
+ String s = line.trim();
+ // blank lines are also treated as comment lines
+ return s.isEmpty() || COMMENT_CHARS.indexOf(s.charAt(0)) >= 0;
+ }
+
+ /**
+ * Unescapes any Java literals found in the String
to a
+ * Writer
.
This is a slightly modified version of the
+ * StringEscapeUtils.unescapeJava() function in commons-lang that doesn't
+ * drop escaped separators (i.e '\,').
+ *
+ * @param str the String
to unescape, may be null
+ * @return the processed string
+ * @throws IllegalArgumentException if the Writer is null
+ */
+ protected static String unescapeJava(String str) {
+ if (str == null) {
+ return null;
+ }
+ int sz = str.length();
+ StringBuilder out = new StringBuilder(sz);
+ StringBuilder unicode = new StringBuilder(UNICODE_LEN);
+ boolean hadSlash = false;
+ boolean inUnicode = false;
+ for (int i = 0; i < sz; i++) {
+ char ch = str.charAt(i);
+ if (inUnicode) {
+ // if in unicode, then we're reading unicode
+ // values in somehow
+ unicode.append(ch);
+ if (unicode.length() == UNICODE_LEN) {
+ // unicode now contains the four hex digits
+ // which represents our unicode character
+ try {
+ int value = Integer.parseInt(unicode.toString(), HEX_RADIX);
+ out.append((char) value);
+ unicode.setLength(0);
+ inUnicode = false;
+ hadSlash = false;
+ } catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException("Unable to parse unicode value: " + unicode, nfe);
+ }
+ }
+ continue;
+ }
+
+ if (hadSlash) {
+ // handle an escaped value
+ hadSlash = false;
+ switch (ch) {
+ case '\\':
+ out.append('\\');
+ break;
+ case '\'':
+ out.append('\'');
+ break;
+ case '\"':
+ out.append('"');
+ break;
+ case 'r':
+ out.append('\r');
+ break;
+ case 'f':
+ out.append('\f');
+ break;
+ case 't':
+ out.append('\t');
+ break;
+ case 'n':
+ out.append('\n');
+ break;
+ case 'b':
+ out.append('\b');
+ break;
+ case 'u':
+ // uh-oh, we're in unicode country....
+ inUnicode = true;
+ break;
+ default:
+ out.append(ch);
+ break;
+ }
+ continue;
+ } else if (ch == '\\') {
+ hadSlash = true;
+ continue;
+ }
+ out.append(ch);
+ }
+
+ if (hadSlash) {
+ // then we're in the weird case of a \ at the end of the
+ // string, let's output it anyway.
+ out.append('\\');
+ }
+
+ return out.toString();
+ }
+
+ /**
+ * Escapes the characters in a String
using Java String rules.
+ *
+ * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.)
+ *
+ * So a tab becomes the characters '\\'
and
+ * 't'
.
+ *
+ * The only difference between Java strings and JavaScript strings
+ * is that in JavaScript, a single quote must be escaped.
+ *
+ * Example:
+ *
+ * input string: He didn't say, "Stop!"
+ * output string: He didn't say, \"Stop!\"
+ *
+ *
+ *
+ * @param str String to escape values in, may be null
+ * @return String with escaped values, null
if null string input
+ */
+ @SuppressWarnings("checkstyle:MagicNumber")
+ protected static String escapeJava(String str) {
+ if (str == null) {
+ return null;
+ }
+ int sz = str.length();
+ StringBuilder out = new StringBuilder(sz * 2);
+ for (int i = 0; i < sz; i++) {
+ char ch = str.charAt(i);
+ // handle unicode
+ if (ch > 0xfff) {
+ out.append("\\u").append(hex(ch));
+ } else if (ch > 0xff) {
+ out.append("\\u0").append(hex(ch));
+ } else if (ch > 0x7f) {
+ out.append("\\u00").append(hex(ch));
+ } else if (ch < 32) {
+ switch (ch) {
+ case '\b':
+ out.append('\\');
+ out.append('b');
+ break;
+ case '\n':
+ out.append('\\');
+ out.append('n');
+ break;
+ case '\t':
+ out.append('\\');
+ out.append('t');
+ break;
+ case '\f':
+ out.append('\\');
+ out.append('f');
+ break;
+ case '\r':
+ out.append('\\');
+ out.append('r');
+ break;
+ default:
+ if (ch > 0xf) {
+ out.append("\\u00").append(hex(ch));
+ } else {
+ out.append("\\u000").append(hex(ch));
+ }
+ break;
+ }
+ } else {
+ switch (ch) {
+ case '"':
+ out.append('\\');
+ out.append('"');
+ break;
+ case '\\':
+ out.append('\\');
+ out.append('\\');
+ break;
+ default:
+ out.append(ch);
+ break;
+ }
+ }
+ }
+ return out.toString();
+ }
+
+ /**
+ * Returns an upper case hexadecimal String
for the given
+ * character.
+ *
+ * @param ch The character to convert.
+ * @return An upper case hexadecimal String
+ */
+ protected static String hex(char ch) {
+ return Integer.toHexString(ch).toUpperCase(Locale.ENGLISH);
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns false
if a null
array is passed in.
+ *
+ * @param array the array to search through
+ * @param valueToFind the value to find
+ * @return true
if the array contains the object
+ */
+ public static boolean contains(char[] array, char valueToFind) {
+ if (array == null) {
+ return false;
+ }
+ for (char c : array) {
+ if (valueToFind == c) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Escape the separators in the key.
+ *
+ * @param key the key
+ * @return the escaped key
+ */
+ private static String escapeKey(String key) {
+ StringBuilder newkey = new StringBuilder();
+
+ for (int i = 0; i < key.length(); i++) {
+ char c = key.charAt(i);
+
+ if (contains(SEPARATORS, c) || contains(WHITE_SPACE, c)) {
+ // escape the separator
+ newkey.append('\\');
+ newkey.append(c);
+ } else {
+ newkey.append(c);
+ }
+ }
+
+ return newkey.toString();
+ }
+
+ /**
+ * This class is used to read properties lines. These lines do
+ * not terminate with new-line chars but rather when there is no
+ * backslash sign a the end of the line. This is used to
+ * concatenate multiple lines for readability.
+ */
+ public static class PropertiesReader extends LineNumberReader {
+ /** Stores the comment lines for the currently processed property.*/
+ private final List commentLines;
+
+ /** Stores the value lines for the currently processed property.*/
+ private final List valueLines;
+
+ /** Stores the name of the last read property.*/
+ private String propertyName;
+
+ /** Stores the value of the last read property.*/
+ private String propertyValue;
+
+ private boolean maybeTyped;
+
+ /** Stores if the properties are typed or not */
+ Boolean typed;
+
+ /**
+ * Creates a new instance of PropertiesReader
and sets
+ * the underlaying reader and the list delimiter.
+ *
+ * @param reader the reader
+ */
+ public PropertiesReader(Reader reader, boolean maybeTyped) {
+ super(reader);
+ commentLines = new ArrayList();
+ valueLines = new ArrayList();
+ this.maybeTyped = maybeTyped;
+ }
+
+ /**
+ * Reads a property line. Returns null if Stream is
+ * at EOF. Concatenates lines ending with "\".
+ * Skips lines beginning with "#" or "!" and empty lines.
+ * The return value is a property definition (<name>
+ * = <value>
)
+ *
+ * @return A string containing a property value or null
+ *
+ * @throws IOException in case of an I/O error
+ */
+ public String readProperty() throws IOException {
+ commentLines.clear();
+ valueLines.clear();
+ StringBuilder buffer = new StringBuilder();
+
+ while (true) {
+ String line = readLine();
+ if (line == null) {
+ // EOF
+ return null;
+ }
+
+ if (isCommentLine(line)) {
+ commentLines.add(line);
+ continue;
+ }
+
+ boolean combine = checkCombineLines(line);
+ if (combine) {
+ line = line.substring(0, line.length() - 1);
+ }
+ valueLines.add(line);
+ while (line.length() > 0 && contains(WHITE_SPACE, line.charAt(0))) {
+ line = line.substring(1, line.length());
+ }
+ buffer.append(line);
+ if (!combine) {
+ break;
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Parses the next property from the input stream and stores the found
+ * name and value in internal fields. These fields can be obtained using
+ * the provided getter methods. The return value indicates whether EOF
+ * was reached (false) or whether further properties are
+ * available (true).
+ *
+ * @return a flag if further properties are available
+ * @throws IOException if an error occurs
+ */
+ public boolean nextProperty() throws IOException {
+ String line = readProperty();
+
+ if (line == null) {
+ return false; // EOF
+ }
+
+ // parse the line
+ String[] property = parseProperty(line);
+ boolean typed = false;
+ if (maybeTyped && property[1].length() >= 2) {
+ typed = property[1].matches(
+ "\\s*[TILFDXSCBilfdxscb]?(\\[[\\S\\s]*\\]|\\([\\S\\s]*\\)|\\{[\\S\\s]*\\}|\"[\\S\\s]*\")\\s*");
+ }
+ if (this.typed == null) {
+ this.typed = typed;
+ } else {
+ this.typed = this.typed & typed;
+ }
+ propertyName = unescapeJava(property[0]);
+ propertyValue = property[1];
+ return true;
+ }
+
+ /**
+ * Returns the comment lines that have been read for the last property.
+ *
+ * @return the comment lines for the last property returned by
+ * readProperty()
+ */
+ public List getCommentLines() {
+ return commentLines;
+ }
+
+ /**
+ * Returns the value lines that have been read for the last property.
+ *
+ * @return the raw value lines for the last property returned by
+ * readProperty()
+ */
+ public List getValueLines() {
+ return valueLines;
+ }
+
+ /**
+ * Returns the name of the last read property. This method can be called
+ * after {@link #nextProperty()}
was invoked and its
+ * return value was true.
+ *
+ * @return the name of the last read property
+ */
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+ /**
+ * Returns the value of the last read property. This method can be
+ * called after {@link #nextProperty()}
was invoked and
+ * its return value was true.
+ *
+ * @return the value of the last read property
+ */
+ public String getPropertyValue() {
+ return propertyValue;
+ }
+
+ /**
+ * Checks if the passed in line should be combined with the following.
+ * This is true, if the line ends with an odd number of backslashes.
+ *
+ * @param line the line
+ * @return a flag if the lines should be combined
+ */
+ private static boolean checkCombineLines(String line) {
+ int bsCount = 0;
+ for (int idx = line.length() - 1; idx >= 0 && line.charAt(idx) == '\\'; idx--) {
+ bsCount++;
+ }
+
+ return bsCount % 2 != 0;
+ }
+
+ /**
+ * Parse a property line and return the key and the value in an array.
+ *
+ * @param line the line to parse
+ * @return an array with the property's key and value
+ */
+ private static String[] parseProperty(String line) {
+ // sorry for this spaghetti code, please replace it as soon as
+ // possible with a regexp when the Java 1.3 requirement is dropped
+
+ String[] result = new String[2];
+ StringBuilder key = new StringBuilder();
+ StringBuilder value = new StringBuilder();
+
+ // state of the automaton:
+ // 0: key parsing
+ // 1: antislash found while parsing the key
+ // 2: separator crossing
+ // 3: white spaces
+ // 4: value parsing
+ int state = 0;
+
+ for (int pos = 0; pos < line.length(); pos++) {
+ char c = line.charAt(pos);
+
+ switch (state) {
+ case 0:
+ if (c == '\\') {
+ state = 1;
+ } else if (contains(WHITE_SPACE, c)) {
+ // switch to the separator crossing state
+ state = 2;
+ } else if (contains(SEPARATORS, c)) {
+ // switch to the value parsing state
+ state = 3;
+ } else {
+ key.append(c);
+ }
+
+ break;
+
+ case 1:
+ if (contains(SEPARATORS, c) || contains(WHITE_SPACE, c)) {
+ // this is an escaped separator or white space
+ key.append(c);
+ } else {
+ // another escaped character, the '\' is preserved
+ key.append('\\');
+ key.append(c);
+ }
+
+ // return to the key parsing state
+ state = 0;
+
+ break;
+
+ case 2:
+ if (contains(WHITE_SPACE, c)) {
+ // do nothing, eat all white spaces
+ state = 2;
+ } else if (contains(SEPARATORS, c)) {
+ // switch to the value parsing state
+ state = 3;
+ } else {
+ // any other character indicates we encoutered the beginning of the value
+ value.append(c);
+
+ // switch to the value parsing state
+ state = 4;
+ }
+
+ break;
+
+ case 3:
+ if (contains(WHITE_SPACE, c)) {
+ // do nothing, eat all white spaces
+ state = 3;
+ } else {
+ // any other character indicates we encoutered the beginning of the value
+ value.append(c);
+
+ // switch to the value parsing state
+ state = 4;
+ }
+
+ break;
+
+ case 4:
+ value.append(c);
+ break;
+
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+ result[0] = key.toString();
+ result[1] = value.toString();
+
+ return result;
+ }
+ } // class PropertiesReader
+
+ /**
+ * This class is used to write properties lines.
+ */
+ public static class PropertiesWriter extends FilterWriter {
+ private boolean typed;
+
+ /**
+ * Constructor.
+ *
+ * @param writer a Writer object providing the underlying stream
+ */
+ public PropertiesWriter(Writer writer, boolean typed) {
+ super(writer);
+ this.typed = typed;
+ }
+
+ /**
+ * Writes the given property and its value.
+ *
+ * @param key the property key
+ * @param value the property value
+ * @throws IOException if an error occurs
+ */
+ public void writeProperty(String key, String value) throws IOException {
+ write(escapeKey(key));
+ write(" = ");
+ write(typed ? value : escapeJava(value));
+ writeln(null);
+ }
+
+ /**
+ * Helper method for writing a line with the platform specific line
+ * ending.
+ *
+ * @param s the content of the line (may be null)
+ * @throws IOException if an error occurs
+ */
+ public void writeln(String s) throws IOException {
+ if (s != null) {
+ write(s);
+ }
+ write(LINE_SEPARATOR);
+ }
+ } // class PropertiesWriter
+
+ /**
+ * TODO
+ */
+ protected static class Layout {
+
+ private List commentLines;
+ private List valueLines;
+
+ public Layout() {}
+
+ public Layout(List commentLines, List valueLines) {
+ this.commentLines = commentLines;
+ this.valueLines = valueLines;
+ }
+
+ public List getCommentLines() {
+ return commentLines;
+ }
+
+ public void setCommentLines(List commentLines) {
+ this.commentLines = commentLines;
+ }
+
+ public List getValueLines() {
+ return valueLines;
+ }
+
+ public void setValueLines(List valueLines) {
+ this.valueLines = valueLines;
+ }
+
+ public void clearValue() {
+ this.valueLines = null;
+ }
+ } // class Layout
+}
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/props/PropertiesLoader.java b/maven-embedder/src/main/java/org/apache/maven/cli/props/PropertiesLoader.java
new file mode 100644
index 000000000000..996d2ea4b300
--- /dev/null
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/props/PropertiesLoader.java
@@ -0,0 +1,174 @@
+/*
+ * 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.cli.props;
+
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+
+import static org.apache.maven.cli.props.InterpolationHelper.substVars;
+
+public class PropertiesLoader {
+
+ public static final String INCLUDES_PROPERTY = "${includes}"; // mandatory includes
+
+ public static final String OPTIONALS_PROPERTY = "${optionals}"; // optionals include
+
+ public static final String OVERRIDE_PREFIX =
+ "maven.override."; // prefix that marks that system property should override defaults.
+
+ public static void loadProperties(
+ java.util.Properties properties,
+ Path path,
+ InterpolationHelper.SubstitutionCallback callback,
+ boolean escape)
+ throws Exception {
+ Properties sp = new Properties(false);
+ try {
+ sp.load(path);
+ } catch (NoSuchFileException ex) {
+ // ignore
+ }
+ properties.forEach(
+ (k, v) -> sp.put(k.toString(), escape ? InterpolationHelper.escape(v.toString()) : v.toString()));
+ substitute(sp, callback, INCLUDES_PROPERTY);
+ substitute(sp, callback, OPTIONALS_PROPERTY);
+ loadIncludes(INCLUDES_PROPERTY, true, path, sp);
+ loadIncludes(OPTIONALS_PROPERTY, false, path, sp);
+ substitute(sp, callback);
+ sp.forEach(properties::setProperty);
+ }
+
+ public static void substitute(Properties props, InterpolationHelper.SubstitutionCallback callback) {
+ for (Enumeration> e = props.propertyNames(); e.hasMoreElements(); ) {
+ String name = (String) e.nextElement();
+ String value = props.getProperty(name);
+ if (value == null) {
+ value = callback.getValue(name);
+ }
+ if (name.startsWith(OVERRIDE_PREFIX)) {
+ String overrideName = name.substring(OVERRIDE_PREFIX.length());
+ props.put(overrideName, substVars(value, name, null, props, callback));
+ } else {
+ props.put(name, substVars(value, name, null, props, callback));
+ }
+ }
+ props.keySet().removeIf(k -> k.startsWith(OVERRIDE_PREFIX));
+ }
+
+ private static void substitute(Properties props, InterpolationHelper.SubstitutionCallback callback, String name) {
+ String value = props.getProperty(name);
+ if (value == null) {
+ value = callback.getValue(name);
+ }
+ if (value != null) {
+ props.put(name, substVars(value, name, null, props, callback));
+ }
+ }
+
+ private static Properties loadPropertiesFile(Path path, boolean failIfNotFound) throws Exception {
+ Properties configProps = new Properties(null, false);
+ try {
+ configProps.load(path);
+ } catch (NoSuchFileException ex) {
+ if (failIfNotFound) {
+ throw ex;
+ }
+ } catch (Exception ex) {
+ System.err.println("Error loading config properties from " + path);
+ System.err.println("Main: " + ex);
+ return configProps;
+ }
+ loadIncludes(INCLUDES_PROPERTY, true, path, configProps);
+ loadIncludes(OPTIONALS_PROPERTY, false, path, configProps);
+ trimValues(configProps);
+ return configProps;
+ }
+
+ private static void loadIncludes(String propertyName, boolean mandatory, Path configProp, Properties configProps)
+ throws Exception {
+ String includes = configProps.get(propertyName);
+ if (includes != null) {
+ StringTokenizer st = new StringTokenizer(includes, "\" ", true);
+ if (st.countTokens() > 0) {
+ String location;
+ do {
+ location = nextLocation(st);
+ if (location != null) {
+ Path path = configProp.resolve(location);
+ Properties props = loadPropertiesFile(path, mandatory);
+ configProps.putAll(props);
+ }
+ } while (location != null);
+ }
+ }
+ configProps.remove(propertyName);
+ }
+
+ private static void trimValues(Properties configProps) {
+ configProps.replaceAll((k, v) -> v.trim());
+ }
+
+ private static String nextLocation(StringTokenizer st) {
+ String retVal = null;
+
+ if (st.countTokens() > 0) {
+ String tokenList = "\" ";
+ StringBuilder tokBuf = new StringBuilder(10);
+ String tok;
+ boolean inQuote = false;
+ boolean tokStarted = false;
+ boolean exit = false;
+ while ((st.hasMoreTokens()) && (!exit)) {
+ tok = st.nextToken(tokenList);
+ switch (tok) {
+ case "\"":
+ inQuote = !inQuote;
+ if (inQuote) {
+ tokenList = "\"";
+ } else {
+ tokenList = "\" ";
+ }
+ break;
+ case " ":
+ if (tokStarted) {
+ retVal = tokBuf.toString();
+ tokStarted = false;
+ tokBuf = new StringBuilder(10);
+ exit = true;
+ }
+ break;
+ default:
+ tokStarted = true;
+ tokBuf.append(tok.trim());
+ break;
+ }
+ }
+
+ // Handle case where end of token stream and
+ // still got data
+ if ((!exit) && (tokStarted)) {
+ retVal = tokBuf.toString();
+ }
+ }
+
+ return retVal;
+ }
+}
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
index 40e15ac38210..701da7654134 100644
--- a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
@@ -22,12 +22,16 @@
import java.io.File;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
+import com.google.common.jimfs.Configuration;
+import com.google.common.jimfs.Jimfs;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
@@ -51,6 +55,7 @@
import org.codehaus.plexus.DefaultPlexusContainer;
import org.codehaus.plexus.PlexusContainer;
import org.eclipse.aether.transfer.TransferListener;
+import org.hamcrest.CoreMatchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -578,6 +583,20 @@ public void findRootProjectWithAttribute() {
@Test
public void testPropertiesInterpolation() throws Exception {
+ FileSystem fs = Jimfs.newFileSystem(Configuration.windows());
+
+ Path mavenHome = fs.getPath("C:\\maven");
+ Files.createDirectories(mavenHome);
+ Path mavenConf = mavenHome.resolve("conf");
+ Files.createDirectories(mavenConf);
+ Path mavenUserProps = mavenConf.resolve("maven.properties");
+ Files.writeString(mavenUserProps, "${optionals} = ${session.rootDirectory}/.mvn/maven.properties\n");
+ Path rootDirectory = fs.getPath("C:\\myRootDirectory");
+ Path topDirectory = rootDirectory.resolve("myTopDirectory");
+ Path mvn = rootDirectory.resolve(".mvn");
+ Files.createDirectories(mvn);
+ Files.writeString(mvn.resolve("maven.properties"), "fro = ${bar}z\n" + "bar = chti${java.version}\n");
+
// Arrange
CliRequest request = new CliRequest(
new String[] {
@@ -592,20 +611,28 @@ public void testPropertiesInterpolation() throws Exception {
"validate"
},
null);
- request.rootDirectory = Paths.get("myRootDirectory");
- request.topDirectory = Paths.get("myTopDirectory");
+ request.rootDirectory = rootDirectory;
+ request.topDirectory = topDirectory;
+ System.setProperty("maven.conf", mavenConf.toString());
// Act
+ cli.setFileSystem(fs);
cli.cli(request);
cli.properties(request);
// Assert
+ assertThat(request.getUserProperties().getProperty("fro"), CoreMatchers.startsWith("chti"));
assertThat(request.getUserProperties().getProperty("valFound"), is("sbari"));
assertThat(request.getUserProperties().getProperty("valNotFound"), is("s${foz}i"));
- assertThat(request.getUserProperties().getProperty("valRootDirectory"), is("myRootDirectory/.mvn/foo"));
- assertThat(request.getUserProperties().getProperty("valTopDirectory"), is("myTopDirectory/pom.xml"));
- assertThat(request.getCommandLine().getOptionValue('f'), is("myRootDirectory/my-child"));
+ assertThat(request.getUserProperties().getProperty("valRootDirectory"), is("C:\\myRootDirectory/.mvn/foo"));
+ assertThat(
+ request.getUserProperties().getProperty("valTopDirectory"),
+ is("C:\\myRootDirectory\\myTopDirectory/pom.xml"));
+ assertThat(request.getCommandLine().getOptionValue('f'), is("C:\\myRootDirectory/my-child"));
assertThat(request.getCommandLine().getArgs(), equalTo(new String[] {"prefix:3.0.0:bar", "validate"}));
+
+ Path p = fs.getPath(request.getUserProperties().getProperty("valTopDirectory"));
+ assertThat(p.toString(), is("C:\\myRootDirectory\\myTopDirectory\\pom.xml"));
}
@ParameterizedTest