You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pe...@apache.org on 2026/08/10 04:38:45 UTC

(celix) 15/35: Eliminate dead code and improve code coverage for string format checker.

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

PengZheng pushed a commit to branch feature/json-schema
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 02471885f18a6485920b4b44448a2cb91c472188
Author: PengZheng <ho...@gmail.com>
AuthorDate: Fri Aug 7 17:01:20 2026 +0800

    Eliminate dead code and improve code coverage for string format checker.
---
 libs/jansson_ext/gtest/src/test_format_check.cpp   | 35 ++++++++++++++++++++++
 .../gtest/src/test_format_check_extended.cpp       | 17 +++++++++--
 libs/jansson_ext/src/celix_string_format_check.c   | 26 +++++++++-------
 3 files changed, 65 insertions(+), 13 deletions(-)

diff --git a/libs/jansson_ext/gtest/src/test_format_check.cpp b/libs/jansson_ext/gtest/src/test_format_check.cpp
index 578eba60f..d7a5495fd 100644
--- a/libs/jansson_ext/gtest/src/test_format_check.cpp
+++ b/libs/jansson_ext/gtest/src/test_format_check.cpp
@@ -41,6 +41,13 @@ TEST(FormatCheckTest, DateTime) {
         {"date-time", "1985-04-12t23:20:50Z", true},       /* lowercase T */
         {"date-time", "1985-04-12T23:20:50+24:00", false}, /* offset too large */
         {"date-time", "not-a-date", false},
+        {"date-time", "2020-01-01", false},                  /* missing T separator */
+        {"date-time", "2020-01-01T10:30:00", false},         /* missing timezone */
+        {"date-time", "2020-01-01T+01:00", false},           /* empty time part */
+        {"date-time", "2020-01-01T10:30:00.123456789012345678901234567890Z", false}, /* time part >= 32 chars */
+        {"date-time", "2020-01-01T00:00:60Z", false},        /* leap second not at 23:59:60 UTC */
+        {"date-time", "2020-01-01T10:30:00+12x30", false},   /* malformed timezone */
+        {"date-time", "2020-01-01T10:30:00+1230", false},    /* timezone missing colon */
     };
 
     for (auto& c : cases) {
@@ -151,6 +158,34 @@ TEST(FormatCheckTest, UriInvalidChars) {
               celix_jansson_schema_default_format_check("uri", "http://example.com/path\"quote", nullptr));
 }
 
+TEST(FormatCheckTest, UriAuthority) {
+    /* Valid URIs */
+    EXPECT_EQ(CELIX_JANSSON_SCHEMA_OK,
+              celix_jansson_schema_default_format_check("uri", "http://[::1]:8080/", nullptr));
+    EXPECT_EQ(CELIX_JANSSON_SCHEMA_OK,
+              celix_jansson_schema_default_format_check("uri", "http://a%20b/", nullptr));
+    EXPECT_EQ(CELIX_JANSSON_SCHEMA_OK,
+              celix_jansson_schema_default_format_check("uri", "http://example.com:8080/", nullptr));
+    /* Invalid: empty URI */
+    EXPECT_NE(CELIX_JANSSON_SCHEMA_OK,
+              celix_jansson_schema_default_format_check("uri", "", nullptr));
+    /* Invalid: unclosed IPv6 literal */
+    EXPECT_NE(CELIX_JANSSON_SCHEMA_OK,
+              celix_jansson_schema_default_format_check("uri", "http://[::1", nullptr));
+    /* Invalid: bad percent-encoding in reg-name */
+    EXPECT_NE(CELIX_JANSSON_SCHEMA_OK,
+              celix_jansson_schema_default_format_check("uri", "http://a%zz/", nullptr));
+    /* Invalid: non-digit in port */
+    EXPECT_NE(CELIX_JANSSON_SCHEMA_OK,
+              celix_jansson_schema_default_format_check("uri", "http://example.com:8a80/", nullptr));
+    /* Invalid: space in query */
+    EXPECT_NE(CELIX_JANSSON_SCHEMA_OK,
+              celix_jansson_schema_default_format_check("uri", "http://a.b/?x y", nullptr));
+    /* Invalid: space in fragment */
+    EXPECT_NE(CELIX_JANSSON_SCHEMA_OK,
+              celix_jansson_schema_default_format_check("uri", "http://a.b/#x y", nullptr));
+}
+
 /* ── NULL argument guard ─────────────────────────────────────────────────── */
 
 TEST(FormatCheckTest, NullArgumentDispatch) {
diff --git a/libs/jansson_ext/gtest/src/test_format_check_extended.cpp b/libs/jansson_ext/gtest/src/test_format_check_extended.cpp
index c983eb75c..b330cedae 100644
--- a/libs/jansson_ext/gtest/src/test_format_check_extended.cpp
+++ b/libs/jansson_ext/gtest/src/test_format_check_extended.cpp
@@ -79,6 +79,7 @@ TEST(FormatCheckTest, Time) {
         {"12:60:00Z", false},    /* minute > 59 */
         {"12:34:56", false},     /* no timezone */
         {"12:34:56+24:00", false}, /* offset hour > 23 */
+        {"10:30:00+01:00x", false}, /* trailing garbage after timezone */
         {"", false},
     };
 
@@ -100,11 +101,16 @@ TEST(FormatCheckTest, Time) {
  */
 
 TEST(FormatCheckTest, Email) {
-    /* Only test clearly invalid inputs — the SMTP validator rejects
-     * seemingly valid addresses too, so positive cases are unreliable. */
+    /* NOTE: The Ragel-generated SMTP address validator (celix_smtp_address_validator.c)
+     * returns false for EVERY input — verified empirically with a probe harness, and
+     * consistent with the JSON Schema Test Suite treating email.json as expected-fail.
+     * The OK return path of check_email is therefore unreachable until the validator
+     * is fixed (separate investigation comparing with pboettch/json-schema-validator).
+     * Non-ASCII input fails earlier in is_ascii and is covered here. */
     EXPECT_NE(CELIX_JANSSON_SCHEMA_OK, celix_jansson_check_email("not-an-email"));
     EXPECT_NE(CELIX_JANSSON_SCHEMA_OK, celix_jansson_check_email("user@"));
     EXPECT_NE(CELIX_JANSSON_SCHEMA_OK, celix_jansson_check_email("@example.com"));
+    EXPECT_NE(CELIX_JANSSON_SCHEMA_OK, celix_jansson_check_email("\xc3\xbc@example.com")); /* ü@example.com — non-ASCII */
 }
 
 /* ── International Email (RFC 6531) ──────────────────────────────────────── */
@@ -112,6 +118,7 @@ TEST(FormatCheckTest, Email) {
 TEST(FormatCheckTest, IdnEmail) {
     EXPECT_NE(CELIX_JANSSON_SCHEMA_OK, celix_jansson_check_idn_email("not-an-email"));
     EXPECT_NE(CELIX_JANSSON_SCHEMA_OK, celix_jansson_check_idn_email("user@"));
+    EXPECT_NE(CELIX_JANSSON_SCHEMA_OK, celix_jansson_check_idn_email("\xc3\xbc@example.com"));
 }
 
 /* ── Hostname (RFC 3986 Appendix A labels) ──────────────────────────────── */
@@ -133,6 +140,11 @@ TEST(FormatCheckTest, Hostname) {
         {"a b.example", false},    /* space in label */
     };
 
+    /* 4 labels of 63 chars + 3 dots = 255 chars > 253 limit */
+    std::string long_label(63, 'a');
+    std::string long_host = long_label + "." + long_label + "." + long_label + "." + long_label;
+    EXPECT_EQ(CELIX_JANSSON_SCHEMA_ERROR_INVALID_ARGUMENT, celix_jansson_check_hostname(long_host.c_str()));
+
     for (auto& c : cases) {
         int rc = celix_jansson_check_hostname(c.value);
         if (c.valid)
@@ -159,6 +171,7 @@ TEST(FormatCheckTest, Ipv6) {
         {"2001:db8", false},       /* incomplete */
         {"2001:db8:::1", false},   /* triple colon */
         {"gggg:db8::1", false},    /* invalid hex */
+        {"fe80::1%eth0", false},   /* zone-id form (glibc's inet_pton rejects '%' itself) */
         {"", false},
     };
 
diff --git a/libs/jansson_ext/src/celix_string_format_check.c b/libs/jansson_ext/src/celix_string_format_check.c
index 0291d752d..76f310cfe 100644
--- a/libs/jansson_ext/src/celix_string_format_check.c
+++ b/libs/jansson_ext/src/celix_string_format_check.c
@@ -19,6 +19,7 @@
 #include "celix_string_format_check.h"
 #include "celix_smtp_address_validator.h"
 #include <arpa/inet.h>
+#include <assert.h>
 #include <ctype.h>
 #include <regex.h>
 #include <stdbool.h>
@@ -33,8 +34,8 @@ static int is_leap_year(int year) { return (year % 4 == 0 && year % 100 != 0) ||
 
 static int days_in_month(int year, int month) {
     static const int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-    if (month < 1 || month > 12)
-        return 0;
+    /* Caller (check_date_part) guarantees 1 <= month <= 12 */
+    assert(month >= 1 && month <= 12);
     if (month == 2 && is_leap_year(year))
         return 29;
     return days[month - 1];
@@ -54,8 +55,10 @@ static int check_date_part(const char* s) {
             return -1;
     }
     int year, month, day;
-    if (sscanf(s, "%4d-%2d-%2d", &year, &month, &day) != 3)
-        return -1;
+    /* All non-separator chars were validated as digits above, so the parse always succeeds */
+    int n = sscanf(s, "%4d-%2d-%2d", &year, &month, &day);
+    assert(n == 3);
+    (void)n;
     if (month < 1 || month > 12)
         return -1;
     if (day < 1 || day > days_in_month(year, month))
@@ -109,20 +112,19 @@ static int check_leap_second(int hour, int min, int sec, int offset_hour, int of
 }
 
 static int parse_timezone(const char* s, int* out_hh, int* out_mm) {
-    if (!s || *s == '\0')
-        return -1;
+    /* Callers pass the result of strpbrk(s, "+-Zz"), so s is non-NULL and non-empty */
+    assert(s != NULL && *s != '\0');
     if (*s == 'Z' || *s == 'z') {
         *out_hh = 0;
         *out_mm = 0;
         return 0;
     }
-    /* ±HH:MM */
+    /* ±HH:MM — s[0] is '+' or '-' (Z/z handled above) */
     int hh, mm;
     char sign;
     if (sscanf(s, "%c%2d:%2d", &sign, &hh, &mm) != 3)
         return -1;
-    if (sign != '+' && sign != '-')
-        return -1;
+    assert(sign == '+' || sign == '-');
     if (hh < 0 || hh > 23)
         return -1;
     if (mm < 0 || mm > 59)
@@ -309,8 +311,10 @@ int celix_jansson_check_ipv4(const char* value) {
         return CELIX_JANSSON_SCHEMA_ERROR_INVALID_ARGUMENT;
     /* Reject leading zeros (e.g., "192.168.01.001") */
     char octet[16];
-    if (snprintf(octet, sizeof(octet), "%u.%u.%u.%u", a, b, c, d) >= (int)sizeof(octet))
-        return CELIX_JANSSON_SCHEMA_ERROR_INVALID_ARGUMENT;
+    /* a,b,c,d <= 255 was validated above, so the formatted string always fits in octet */
+    int n = snprintf(octet, sizeof(octet), "%u.%u.%u.%u", a, b, c, d);
+    assert(n < (int)sizeof(octet));
+    (void)n;
     if (strcmp(value, octet) != 0)
         return CELIX_JANSSON_SCHEMA_ERROR_INVALID_ARGUMENT;
     return CELIX_JANSSON_SCHEMA_OK;