Commit 68692cf
authored
fix(StringTools): edge cases in split_up, remove_quotes, append_codepoint, escape_detect (#1364)
🤖 _AI text below_ 🤖
Part of #1357
Fixes four verified string-handling edge cases in
`include/CLI/impl/StringTools_inl.hpp`, all confirmed against the
current code.
### 1. `split_up` dropped the character after a closing quote/bracket
When a token started with a bracket/quote, the code did
`output.push_back(str.substr(0, end + 1))` then unconditionally `str =
str.substr(end + 2)`, assuming `str[end + 1]` was a delimiter. For e.g.
`split_up("\"abc\"def")` the `d` vanished. Now we only skip position
`end + 1` when it is an actual delimiter (the local `find_ws`
predicate); otherwise we resume from `end + 1`, so the remainder starts
the next token and no characters are lost. New tests `SplitUp:
TrailingAfterQuote`, `TrailingAfterBracket`, and `DelimiterAfterQuote`
in `tests/HelpersTest.cpp`.
### 2. `remove_quotes(std::vector<std::string>&)` called
`front()`/`back()` on empty strings (UB)
The App parse path erases empty strings first, but `generate_parents`
(`Config_inl.hpp`) does not: `split_up(section, '.')` on a section like
`[a..b]` yields empty segments that reached `arg.front()` on `""`. Fixed
by skipping empty strings in the loop. New test `StringBased:
EmptySectionSegment` in `tests/ConfigFileTest.cpp` parses `[a..b]` and
asserts it does not crash and still finds the value.
### 3. `append_codepoint` silently emitted nothing for code points above
0x10FFFF
A `\U` escape computing a code >= 0x110000 fell off the end of the
if/else ladder and disappeared, unlike the surrogate case which throws.
Added a final `else` that throws `std::invalid_argument`. Also corrected
the surrogate error message (was "are not valid UTF-8" -> "are not valid
code points", since these are invalid code points, not bad UTF-8). New
assertions in `StringTools: unicode_literals` cover `\U00110000`,
`\UFFFFFFFF`, and the largest valid point `\U0010FFFF`.
### 4. `escape_detect` unsigned wraparound at offset 0
When the trigger char (`=`/`:`) is the first character,
`str.find_last_of("-/ \"'\`", offset - 1)` passed `npos` and searched
the whole string (including characters after the trigger), potentially
matching a later `-`/`/` and wrongly rewriting the leading char. Now
returns `offset + 1` early when `offset == 0`. New test `StringTools:
escape_detect`.
### Test change (old lossy behavior)
`AppTest.cpp` `OneStringEqualVersionSingleStringQuotedEscapedCharacters`
had a stray trailing `"` after a closing backtick-literal: ``
-m=`"quoted\n string"`" ``. That unbalanced quote was previously
silently swallowed by the `split_up` bug (item 1). With the fix it is
preserved as a token and rejected as an unexpected argument. The
trailing `"` is malformed input, so I removed it from the test input;
the meaningful assertions are unchanged.
All tests pass: full `ctest` is 24/24 green (HelpersTest,
ConfigFileTest, StringParseTest, AppTest included).
🤖 Generated with [Claude Code](https://claude.com/claude-code)1 parent 5c0ba6a commit 68692cf
4 files changed
Lines changed: 95 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
254 | 254 | | |
255 | 255 | | |
256 | 256 | | |
257 | | - | |
| 257 | + | |
258 | 258 | | |
259 | 259 | | |
260 | 260 | | |
| |||
266 | 266 | | |
267 | 267 | | |
268 | 268 | | |
| 269 | + | |
| 270 | + | |
269 | 271 | | |
270 | 272 | | |
271 | 273 | | |
| |||
416 | 418 | | |
417 | 419 | | |
418 | 420 | | |
419 | | - | |
420 | | - | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
421 | 432 | | |
422 | 433 | | |
423 | 434 | | |
| |||
442 | 453 | | |
443 | 454 | | |
444 | 455 | | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
445 | 460 | | |
446 | 461 | | |
447 | 462 | | |
| |||
542 | 557 | | |
543 | 558 | | |
544 | 559 | | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
545 | 563 | | |
546 | 564 | | |
547 | 565 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
432 | 432 | | |
433 | 433 | | |
434 | 434 | | |
435 | | - | |
| 435 | + | |
436 | 436 | | |
437 | 437 | | |
438 | 438 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
93 | 93 | | |
94 | 94 | | |
95 | 95 | | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
96 | 121 | | |
97 | 122 | | |
98 | 123 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
216 | 216 | | |
217 | 217 | | |
218 | 218 | | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
219 | 238 | | |
220 | 239 | | |
221 | 240 | | |
| |||
477 | 496 | | |
478 | 497 | | |
479 | 498 | | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
480 | 504 | | |
481 | 505 | | |
482 | 506 | | |
| |||
1215 | 1239 | | |
1216 | 1240 | | |
1217 | 1241 | | |
| 1242 | + | |
| 1243 | + | |
| 1244 | + | |
| 1245 | + | |
| 1246 | + | |
| 1247 | + | |
| 1248 | + | |
| 1249 | + | |
| 1250 | + | |
| 1251 | + | |
| 1252 | + | |
| 1253 | + | |
| 1254 | + | |
| 1255 | + | |
| 1256 | + | |
| 1257 | + | |
| 1258 | + | |
| 1259 | + | |
| 1260 | + | |
| 1261 | + | |
| 1262 | + | |
| 1263 | + | |
| 1264 | + | |
| 1265 | + | |
1218 | 1266 | | |
1219 | 1267 | | |
1220 | 1268 | | |
| |||
0 commit comments