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

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


The following commit(s) were added to refs/heads/master by this push:
     new 0072930827 fix(marshall): HoconTokenizer =+ two-char-lookahead guard 
was a bug (TODO-137)
0072930827 is described below

commit 007293082747814ed373b9025c053aa20cb2885d
Author: James Bognar <[email protected]>
AuthorDate: Thu May 28 16:23:40 2026 -0400

    fix(marshall): HoconTokenizer =+ two-char-lookahead guard was a bug 
(TODO-137)
    
    The c == '=' && peekChar() != '+' guard prevented EQUALS from being
    emitted when followed by '+', causing IOException on any =+ sequence.
    The += operator is handled by an independent c == '+' && peekChar() == '='
    branch (reads '+' first), so the lookahead on the '=' branch was never
    needed. Removed the guard and added an explanatory comment.
    
    2 regression tests: g13_equalsFollowedByPlus and
    g14_equalsAndPlusEqualsDontInterfere. Note: foo=+bar still fails
    ('+' is in UNQUOTED_FORBIDDEN) — tracked separately as MAYBE-136.
---
 .../org/apache/juneau/hocon/HoconTokenizer.java    |  5 ++++-
 .../apache/juneau/hocon/HoconTokenizer_Test.java   | 23 ++++++++++++++++++++++
 juneau-utest/test-run-history.tsv                  |  1 +
 3 files changed, 28 insertions(+), 1 deletion(-)

diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/hocon/HoconTokenizer.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/hocon/HoconTokenizer.java
index 247be064ee..75d1f0964b 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/hocon/HoconTokenizer.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/hocon/HoconTokenizer.java
@@ -351,7 +351,10 @@ public class HoconTokenizer {
                if (c == ':') {
                        return Token.of(TokenType.COLON);
                }
-               if (c == '=' && peekChar() != '+')
+               // '=' is always the EQUALS token regardless of the next 
character.
+               // The '+=' (PLUS_EQUALS) operator is handled by the check 
below, which reads '+' first;
+               // the two-char sequence '=+' is therefore never mistaken for a 
partial '+='.
+               if (c == '=')
                        return Token.of(TokenType.EQUALS);
                if (c == '+' && peekChar() == '=') {
                        readChar();
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/hocon/HoconTokenizer_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/hocon/HoconTokenizer_Test.java
index 013925ad6f..9db659da43 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/hocon/HoconTokenizer_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/hocon/HoconTokenizer_Test.java
@@ -155,4 +155,27 @@ class HoconTokenizer_Test extends TestBase {
                t.skipWhitespaceAndComments();
                assertEquals(UNQUOTED_STRING, t.read().type());
        }
+
+       // Regression test for the '=+' lookahead bug (TODO-137).
+       // '=' is always EQUALS regardless of the following character; the '+=' 
(PLUS_EQUALS)
+       // operator is handled by a separate branch that reads '+' first, so 
'=+' is never
+       // confused with a partial '+='.
+       @Test
+       void g13_equalsFollowedByPlus() throws Exception {
+               // '=' when the next char is '+' must still emit EQUALS, not 
throw.
+               var t = tokenizer("=+");
+               assertEquals(EQUALS, t.read().type());
+               // '+' alone is in UNQUOTED_FORBIDDEN and has no continuation; 
reading it throws.
+               assertThrows(IOException.class, t::read);
+       }
+
+       // Confirm '+=', '=', and their interleaving all tokenize independently 
after the fix.
+       @Test
+       void g14_equalsAndPlusEqualsDontInterfere() throws Exception {
+               var t = tokenizer("= +=");
+               assertEquals(EQUALS, t.read().type());
+               t.skipWhitespaceAndComments();
+               assertEquals(PLUS_EQUALS, t.read().type());
+               assertEquals(EOF, t.read().type());
+       }
 }
diff --git a/juneau-utest/test-run-history.tsv 
b/juneau-utest/test-run-history.tsv
index 2219556d48..dfb1419683 100644
--- a/juneau-utest/test-run-history.tsv
+++ b/juneau-utest/test-run-history.tsv
@@ -48,3 +48,4 @@ timestamp     git_sha branch  tests_run       failures        
errors  skipped surefire_sec    wall_sec
 2026-05-28T13:16:22Z   8a0a2edbf7ca    master  125869  0       0       21      
82.9    112     3
 2026-05-28T19:24:27Z   a26b6978a5bc    master  125889  0       0       21      
160
 2026-05-28T20:05:34Z   60e4b5a8e813    master  125889  0       0       21      
136
+2026-05-28T20:22:45Z   5e454b3a7988    master  125891  0       0       21      
141

Reply via email to