This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/master by this push:
     new 09fdd6a6e8 Fix ConditionParser to handle newlines before && operator 
(#12038)
09fdd6a6e8 is described below

commit 09fdd6a6e841c30a73adf26ac9b715c286f3bf99
Author: Blasius Patrick <[email protected]>
AuthorDate: Sat Jun 13 17:02:25 2026 +0700

    Fix ConditionParser to handle newlines before && operator (#12038)
    
    * Fix ConditionParser to handle newlines before && operator
    
    Fix for https://github.com/apache/maven/issues/11882
    
    The tokenize() method only treated space as whitespace, so newlines
    became standalone tokens. When a line break appeared before &&,
    the operator was parsed as two separate & tokens instead of one &&.
    
    Added \n, \r, \t to whitespace handling and properly tokenize &&
    as a single operator token regardless of surrounding whitespace.
    
    Signed-off-by: Blasius Patrick <[email protected]>
    
    * Update 
impl/maven-impl/src/main/java/org/apache/maven/impl/model/profile/ConditionParser.java
    
    Co-authored-by: Guillaume Nodet <[email protected]>
    
    * Update 
impl/maven-impl/src/main/java/org/apache/maven/impl/model/profile/ConditionParser.java
    
    Co-authored-by: Guillaume Nodet <[email protected]>
    
    * Update 
impl/maven-impl/src/test/java/org/apache/maven/impl/model/profile/ConditionParserTest.java
    
    Co-authored-by: Guillaume Nodet <[email protected]>
    
    * fix: handle || operator and remove & from X= lookahead
    
    Address review feedback from gnodet on PR #12038:
    - Remove c == '&' from the >=/<= /==/!= lookahead (&= is not valid)
    - Add || tokenization symmetrically with &&
    - Add regression tests for || with line breaks
    
    Fixes apache/maven#11882
    
    Signed-off-by: Blasius Patrick <[email protected]>
    
    ---------
    
    Signed-off-by: Blasius Patrick <[email protected]>
    Co-authored-by: Guillaume Nodet <[email protected]>
---
 .../maven/impl/model/profile/ConditionParser.java  | 21 ++++++++--
 .../impl/model/profile/ConditionParserTest.java    | 48 ++++++++++++++++++++++
 2 files changed, 66 insertions(+), 3 deletions(-)

diff --git 
a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/profile/ConditionParser.java
 
b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/profile/ConditionParser.java
index f596946aa2..2f6a075f87 100644
--- 
a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/profile/ConditionParser.java
+++ 
b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/profile/ConditionParser.java
@@ -129,18 +129,33 @@ private List<String> tokenize(String expression) {
                 }
                 quoteType = c;
                 sb.append(c);
-            } else if (c == ' ' || c == '(' || c == ')' || c == ',' || c == 
'+' || c == '>' || c == '<' || c == '='
-                    || c == '!') {
+            } else if (Character.isWhitespace(c)
+                    || c == '('
+                    || c == ')'
+                    || c == ','
+                    || c == '+'
+                    || c == '>'
+                    || c == '<'
+                    || c == '='
+                    || c == '!'
+                    || c == '&'
+                    || c == '|') {
                 if (!sb.isEmpty()) {
                     tokens.add(sb.toString());
                     sb.setLength(0);
                 }
-                if (c != ' ') {
+                if (!Character.isWhitespace(c)) {
                     if ((c == '>' || c == '<' || c == '=' || c == '!')
                             && i + 1 < expression.length()
                             && expression.charAt(i + 1) == '=') {
                         tokens.add(c + "=");
                         i++; // Skip the next character
+                    } else if (c == '&' && i + 1 < expression.length() && 
expression.charAt(i + 1) == '&') {
+                        tokens.add("&&");
+                        i++; // Skip the next character
+                    } else if (c == '|' && i + 1 < expression.length() && 
expression.charAt(i + 1) == '|') {
+                        tokens.add("||");
+                        i++; // Skip the next character
                     } else {
                         tokens.add(String.valueOf(c));
                     }
diff --git 
a/impl/maven-impl/src/test/java/org/apache/maven/impl/model/profile/ConditionParserTest.java
 
b/impl/maven-impl/src/test/java/org/apache/maven/impl/model/profile/ConditionParserTest.java
index 56d2cbb3ae..990af0d7e3 100644
--- 
a/impl/maven-impl/src/test/java/org/apache/maven/impl/model/profile/ConditionParserTest.java
+++ 
b/impl/maven-impl/src/test/java/org/apache/maven/impl/model/profile/ConditionParserTest.java
@@ -262,6 +262,54 @@ void testPropertyAlias() {
         assertThrows(RuntimeException.class, () -> parser.parse("${unclosed"));
     }
 
+    @Test
+    void testAmpersandAmpersandTokenizerMultiline() {
+        // Regression test for https://github.com/apache/maven/issues/11882
+        // The && operator was not being tokenized correctly when a line break 
appeared before it.
+        // Uses ${os.name} and ${os.arch} which are set to 'windows' and 
'amd64' in the mock context.
+
+        // Case 1: Basic && without line breaks (baseline - always worked)
+        assertTrue((Boolean) parser.parse("${os.arch} == 'amd64' && ${os.name} 
== 'windows'"));
+
+        // Case 2: Line break BEFORE && - this was the bug from issue #11882
+        // In the issue, CDATA content had a line break before &&:
+        // <condition><![CDATA[exists( '.profile-2' )\n&& missing( 
'.profile-1' )]]></condition>
+        assertTrue((Boolean) parser.parse("${os.arch} == 'amd64'\n&& 
${os.name} == 'windows'"));
+
+        // Case 3: Line break AFTER &&
+        assertTrue((Boolean) parser.parse("${os.arch} == 'amd64' 
&&\n${os.name} == 'windows'"));
+
+        // Case 4: Line breaks on both sides
+        assertTrue((Boolean) parser.parse("${os.arch} == 
'amd64'\n&&\n${os.name} == 'windows'"));
+
+        // Case 5: Multiple && with line break before first && (like 
bad-profile-2d in issue)
+        assertTrue(
+                (Boolean) parser.parse("${os.arch} == 'amd64'\n&& ${os.name} 
== 'windows' && ${os.name} == 'windows'"));
+    }
+
+    @Test
+    void testPipePipeTokenizerMultiline() {
+        // Regression test for https://github.com/apache/maven/issues/11882
+        // The || operator was not being tokenized correctly when a line break 
appeared before it.
+        // Uses ${os.name} which is set to 'windows' in the mock context.
+
+        // Case 1: Basic || without line breaks (baseline)
+        assertTrue((Boolean) parser.parse("${os.arch} == 'amd64' || ${os.name} 
== 'windows'"));
+
+        // Case 2: Line break BEFORE ||
+        assertTrue((Boolean) parser.parse("${os.arch} == 'amd64'\n|| 
${os.name} == 'windows'"));
+
+        // Case 3: Line break AFTER ||
+        assertTrue((Boolean) parser.parse("${os.arch} == 'amd64' 
||\n${os.name} == 'windows'"));
+
+        // Case 4: Line breaks on both sides
+        assertTrue((Boolean) parser.parse("${os.arch} == 
'amd64'\n||\n${os.name} == 'windows'"));
+
+        // Case 5: Mixed && and || with line breaks
+        assertTrue(
+                (Boolean) parser.parse("${os.arch} == 'amd64'\n&& ${os.name} 
== 'windows' || ${os.name} == 'windows'"));
+    }
+
     @Test
     void testNestedPropertyAlias() {
         functions.put("property", args -> {

Reply via email to