test(time): expand is_rfc3339_fulldate coverage for length, digit-slot, separator, and leap branches#2684
test(time): expand is_rfc3339_fulldate coverage for length, digit-slot, separator, and leap branches#2684vtushar06 wants to merge 1 commit into
Conversation
…t, separator, and leap branches Signed-off-by: Tushar Verma <tusharmyself06@gmail.com>
🤖 Augment PR SummarySummary: Expands unit test coverage for Changes:
Notes: Intended as coverage-only; the existing implementation is expected to already pass all added tests. 🤖 Was this summary useful? React with 👍 or 👎 |
|
|
||
| TEST(first_separator_nul) { | ||
| EXPECT_FALSE(sourcemeta::core::is_rfc3339_fulldate( | ||
| std::string_view("2020\x0001-01", 10))); |
There was a problem hiding this comment.
In C++, \x.. escapes consume all following hex digits, so "2020\x0001-01" is not "2020\0" "01-01" and can also make std::string_view(..., 10) point past the end of the literal (UB/out-of-bounds reads under sanitizers). This likely means these NUL-slot tests are not exercising the intended 10-byte inputs.
Severity: high
Other Locations
test/time/rfc3339_fulldate_test.cc:641test/time/rfc3339_fulldate_test.cc:646test/time/rfc3339_fulldate_test.cc:671test/time/rfc3339_fulldate_test.cc:696test/time/rfc3339_fulldate_test.cc:721test/time/rfc3339_fulldate_test.cc:771test/time/rfc3339_fulldate_test.cc:821
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
| } | ||
|
|
||
| TEST(ten_byte_bengali_digit_in_day) { | ||
| EXPECT_FALSE(sourcemeta::core::is_rfc3339_fulldate("2020-01\xe0\xa7\xa8")); |
There was a problem hiding this comment.
"2020-01\xe0\xa7\xa8" is missing the '-' before the day, so the Bengali bytes land in the second separator slot (value[7]) rather than in a day digit slot; if the intent is day-digit coverage, this test may not cover it.
Severity: low
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
2 issues found across 1 file
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="test/time/rfc3339_fulldate_test.cc">
<violation number="1" location="test/time/rfc3339_fulldate_test.cc:343">
P1: The string literal `"2020\x0001\x0001"` does not produce null bytes at separator positions 4 and 7. Both `\x0001` escapes are parsed as single bytes with value 0x01, producing a 6-char literal. `string_view(..., 10)` reads 4 bytes past the null terminator (UB). The test accidentally passes because `value[4]` (0x01 ≠ '-') triggers early return, but does not test null-byte separators as intended.</violation>
<violation number="2" location="test/time/rfc3339_fulldate_test.cc:421">
P3: The test name says "bengali_digit_in_day" but the string `"2020-01\xe0\xa7\xa8"` places the Bengali bytes starting at position 7 (the second separator slot), not positions 8–9 (the day-digit slots). The missing `-` before the day means this test exercises the separator check rather than the day-digit non-ASCII branch. If day-digit coverage is the goal, a different construction is needed (e.g., `"2020-01-\xe0\xa7"` for a 10-byte string with the multi-byte sequence starting in the day field).</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| } | ||
|
|
||
| TEST(length_11_trailing_nul) { | ||
| EXPECT_FALSE(sourcemeta::core::is_rfc3339_fulldate( |
There was a problem hiding this comment.
P1: The string literal "2020\x0001\x0001" does not produce null bytes at separator positions 4 and 7. Both \x0001 escapes are parsed as single bytes with value 0x01, producing a 6-char literal. string_view(..., 10) reads 4 bytes past the null terminator (UB). The test accidentally passes because value[4] (0x01 ≠ '-') triggers early return, but does not test null-byte separators as intended.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At test/time/rfc3339_fulldate_test.cc, line 343:
<comment>The string literal `"2020\x0001\x0001"` does not produce null bytes at separator positions 4 and 7. Both `\x0001` escapes are parsed as single bytes with value 0x01, producing a 6-char literal. `string_view(..., 10)` reads 4 bytes past the null terminator (UB). The test accidentally passes because `value[4]` (0x01 ≠ '-') triggers early return, but does not test null-byte separators as intended.</comment>
<file context>
@@ -266,3 +266,1114 @@ TEST(invalid_bengali_digit_in_year) {
+}
+
+TEST(length_11_trailing_nul) {
+ EXPECT_FALSE(sourcemeta::core::is_rfc3339_fulldate(
+ std::string_view("2020-01-01\x00", 11)));
+}
</file context>
| } | ||
|
|
||
| TEST(ten_byte_bengali_digit_in_day) { | ||
| EXPECT_FALSE(sourcemeta::core::is_rfc3339_fulldate("2020-01\xe0\xa7\xa8")); |
There was a problem hiding this comment.
P3: The test name says "bengali_digit_in_day" but the string "2020-01\xe0\xa7\xa8" places the Bengali bytes starting at position 7 (the second separator slot), not positions 8–9 (the day-digit slots). The missing - before the day means this test exercises the separator check rather than the day-digit non-ASCII branch. If day-digit coverage is the goal, a different construction is needed (e.g., "2020-01-\xe0\xa7" for a 10-byte string with the multi-byte sequence starting in the day field).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At test/time/rfc3339_fulldate_test.cc, line 421:
<comment>The test name says "bengali_digit_in_day" but the string `"2020-01\xe0\xa7\xa8"` places the Bengali bytes starting at position 7 (the second separator slot), not positions 8–9 (the day-digit slots). The missing `-` before the day means this test exercises the separator check rather than the day-digit non-ASCII branch. If day-digit coverage is the goal, a different construction is needed (e.g., `"2020-01-\xe0\xa7"` for a 10-byte string with the multi-byte sequence starting in the day field).</comment>
<file context>
@@ -266,3 +266,1114 @@ TEST(invalid_bengali_digit_in_year) {
+}
+
+TEST(ten_byte_bengali_digit_in_day) {
+ EXPECT_FALSE(sourcemeta::core::is_rfc3339_fulldate("2020-01\xe0\xa7\xa8"));
+}
+
</file context>
I added 265 tests to
test/time/rfc3339_fulldate_test.cc. Core already passes all ofthem, so this is coverage, not a fix. I organised them by the branches in
src/core/time/rfc3339_fulldate.ccrather than by input shape, so everyifin thefunction has assertions on both sides of it.
I measured the gap instead of guessing at it. I built single-branch mutants of
is_rfc3339_fulldateand checked which ones the existing 66 tests can distinguish fromthe real function. The existing file kills 3 of 10 usable mutants; with these additions
it kills 10 of 10. The seven that only the new tests catch:
is_digitalso accepts any byte>= 0x80date-fullyeardigit checkvalue.size() != 10beforeis_digitrunsvalue[4] != '-'never checked"2024/01/15"changes both separators, so the second check still rejects itvalue[7] != '-'never checked!is_digit(value[3])dropped"YYYY-01-01"fails onvalue[0]first!is_digit(value[6])dropped!is_digit(value[9])dropped._/What is new
value.size() != 10) - lengths 1-7, 9, 11, 12, 13, 20 and 1000, plusevery terminator variant (LF, CR, CRLF, TAB, NUL, NBSP, U+2028, BOM, zero-width space)
in leading and trailing position.
is_digit- inputs of exactly 10 bytes carryingone non-ASCII sequence, one per UTF-8 encoded length (2-byte Arabic-Indic, 3-byte
Bengali and fullwidth, 4-byte mathematical bold), in the year, month, day and
separator slots, plus a lone continuation byte, a lone lead byte,
0xFF, and a C1control byte. Every non-ASCII case in the file today is 12 or more bytes and never
gets past the length guard.
8, 9, so no slot's check is load-bearing for another's.
':',';','<'after
date-month's first digit and':'through'?'afterdate-mday's, since':' - '0' == 10puts the field back inside its legal range.value[4]alone, atvalue[7]alone, and at both.date-monthrange - 00, 01, 02, 09, 10, 11, 12, 13, 14, 19, 20, 29, 30, 50, 90, 99.date-mdayper month - 00, 01, the section 5.7 maximum, maximum + 1, and 99 forall twelve months, plus February 28/29/30 in both a leap and a non-leap year.
is_leap_yearbranches - February 29 across 39 years covering all four branches(not divisible by 4; by 4 not 100; by 100 not 400; by 400), including 0, 1, 100, 400,
1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 9600, 9900 and 9996.
+/-on a four-digit year, on a five-digit year,on
0000, and10000-01-01unsigned.0000-01-01,0001-01-01,0001-12-31,9998-12-31,9999-01-01,9999-02-28.How I checked the expected values
I did not write the expected verdicts by hand. Every input was run through the real
is_rfc3339_fulldate, compiled straight from this branch's source, and theEXPECT_TRUE/
EXPECT_FALSEwas emitted from what the function actually returned - then the wholefile was compiled and run again to confirm.
sourcemeta_core_time_unitbuilds clean andreports 693 passed, 0 failed.
clang-formatis clean and the diff is additions only.Two inputs are emitted as
std::string_view("...", N)rather than a plain literal,because they contain an embedded NUL and a plain C string literal would truncate there -
the test would silently check a different, shorter input.
I also cross-checked the verdicts against an independent transcription of the ABNF (three
separate checkers written in different styles, agreeing with each other and with the
published JSON Schema Test Suite on all 309 of its
datestring cases) so the assertionsfollow RFC 3339 rather than Core's current behaviour.
RFC references
full-date = date-fullyear "-" date-month "-" date-mdaydate-mdayper monthDIGIT = %x30-39