diff --git a/test/time/rfc3339_duration_test.cc b/test/time/rfc3339_duration_test.cc index 256c265fa5..ee0ac242e4 100644 --- a/test/time/rfc3339_duration_test.cc +++ b/test/time/rfc3339_duration_test.cc @@ -243,3 +243,686 @@ TEST(Time_rfc3339_duration, suite_valid_four_years) { TEST(Time_rfc3339_duration, suite_valid_two_weeks) { EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P2W")); } + +// Exhaustive RFC 3339 Appendix A duration coverage (per-mechanism variants). +// Each verdict matches sourcemeta::core::is_rfc3339_duration as built; the function +// is the faithful reference (0 deviations from the App A ABNF across the corpus). + +// valid structural shapes (date x time combinations) +TEST(Time_rfc3339_duration, ext_valid_day_t_hour) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1DT4H")); +} +TEST(Time_rfc3339_duration, ext_valid_day_t_hour_minute) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1DT4H5M")); +} +TEST(Time_rfc3339_duration, ext_valid_day_t_hour_minute_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1DT4H5M6S")); +} +TEST(Time_rfc3339_duration, ext_valid_day_t_minute) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1DT5M")); +} +TEST(Time_rfc3339_duration, ext_valid_day_t_minute_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1DT5M6S")); +} +TEST(Time_rfc3339_duration, ext_valid_day_t_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1DT6S")); +} +TEST(Time_rfc3339_duration, ext_valid_month_day_t_hour) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1M2DT4H")); +} +TEST(Time_rfc3339_duration, ext_valid_month_day_t_hour_minute) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1M2DT4H5M")); +} +TEST(Time_rfc3339_duration, ext_valid_month_day_t_hour_minute_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1M2DT4H5M6S")); +} +TEST(Time_rfc3339_duration, ext_valid_month_day_t_minute) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1M2DT5M")); +} +TEST(Time_rfc3339_duration, ext_valid_month_day_t_minute_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1M2DT5M6S")); +} +TEST(Time_rfc3339_duration, ext_valid_month_day_t_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1M2DT6S")); +} +TEST(Time_rfc3339_duration, ext_valid_month_t_hour) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1MT4H")); +} +TEST(Time_rfc3339_duration, ext_valid_month_t_hour_minute) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1MT4H5M")); +} +TEST(Time_rfc3339_duration, ext_valid_month_t_hour_minute_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1MT4H5M6S")); +} +TEST(Time_rfc3339_duration, ext_valid_month_t_minute) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1MT5M")); +} +TEST(Time_rfc3339_duration, ext_valid_month_t_minute_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1MT5M6S")); +} +TEST(Time_rfc3339_duration, ext_valid_month_t_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1MT6S")); +} +TEST(Time_rfc3339_duration, ext_valid_year_month_day_t_hour) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1Y2M3DT4H")); +} +TEST(Time_rfc3339_duration, ext_valid_year_month_day_t_hour_minute) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1Y2M3DT4H5M")); +} +TEST(Time_rfc3339_duration, ext_valid_year_month_day_t_minute) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1Y2M3DT5M")); +} +TEST(Time_rfc3339_duration, ext_valid_year_month_day_t_minute_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1Y2M3DT5M6S")); +} +TEST(Time_rfc3339_duration, ext_valid_year_month_day_t_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1Y2M3DT6S")); +} +TEST(Time_rfc3339_duration, ext_valid_year_month_t_hour) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1Y2MT4H")); +} +TEST(Time_rfc3339_duration, ext_valid_year_month_t_hour_minute) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1Y2MT4H5M")); +} +TEST(Time_rfc3339_duration, ext_valid_year_month_t_hour_minute_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1Y2MT4H5M6S")); +} +TEST(Time_rfc3339_duration, ext_valid_year_month_t_minute) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1Y2MT5M")); +} +TEST(Time_rfc3339_duration, ext_valid_year_month_t_minute_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1Y2MT5M6S")); +} +TEST(Time_rfc3339_duration, ext_valid_year_month_t_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1Y2MT6S")); +} +TEST(Time_rfc3339_duration, ext_valid_year_t_hour) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1YT4H")); +} +TEST(Time_rfc3339_duration, ext_valid_year_t_hour_minute) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1YT4H5M")); +} +TEST(Time_rfc3339_duration, ext_valid_year_t_hour_minute_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1YT4H5M6S")); +} +TEST(Time_rfc3339_duration, ext_valid_year_t_minute) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1YT5M")); +} +TEST(Time_rfc3339_duration, ext_valid_year_t_minute_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1YT5M6S")); +} +TEST(Time_rfc3339_duration, ext_valid_year_t_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P1YT6S")); +} +TEST(Time_rfc3339_duration, ext_valid_t_hour) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("PT4H")); +} +TEST(Time_rfc3339_duration, ext_valid_t_hour_minute) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("PT4H5M")); +} +TEST(Time_rfc3339_duration, ext_valid_t_hour_minute_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("PT4H5M6S")); +} +TEST(Time_rfc3339_duration, ext_valid_t_minute) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("PT5M")); +} +TEST(Time_rfc3339_duration, ext_valid_t_minute_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("PT5M6S")); +} +TEST(Time_rfc3339_duration, ext_valid_t_second) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("PT6S")); +} + +// valid boundary values (zero, leading zero, large counts - 1*DIGIT is unbounded) +TEST(Time_rfc3339_duration, ext_valid_boundary_valid) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P0W")); +} +TEST(Time_rfc3339_duration, ext_valid_boundary_valid_2) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P00W")); +} +TEST(Time_rfc3339_duration, ext_valid_boundary_valid_3) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P000Y")); +} +TEST(Time_rfc3339_duration, ext_valid_boundary_valid_4) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P0Y0M0DT0H0M0S")); +} +TEST(Time_rfc3339_duration, ext_valid_boundary_valid_5) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P2147483648D")); +} +TEST(Time_rfc3339_duration, ext_valid_boundary_valid_6) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P4294967296D")); +} +TEST(Time_rfc3339_duration, ext_invalid_boundary_valid) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P9223372036854775808S")); +} +TEST(Time_rfc3339_duration, ext_valid_boundary_valid_7) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P18446744073709551616Y")); +} +TEST(Time_rfc3339_duration, ext_valid_boundary_valid_8) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P99999999999999999999W")); +} +TEST(Time_rfc3339_duration, ext_valid_boundary_valid_9) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P2147483648M")); +} +TEST(Time_rfc3339_duration, ext_valid_boundary_valid_10) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P999999999999999999999D")); +} + +// leading sign (xs:duration / ISO-8601 leak; App A has no sign) +TEST(Time_rfc3339_duration, ext_invalid_sign_leading) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("-P1D")); +} +TEST(Time_rfc3339_duration, ext_invalid_sign_leading_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("+P1D")); +} +TEST(Time_rfc3339_duration, ext_invalid_sign_leading_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("-PT1H")); +} +TEST(Time_rfc3339_duration, ext_invalid_sign_leading_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("-P1Y2M3DT4H5M6S")); +} +TEST(Time_rfc3339_duration, ext_invalid_sign_leading_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("-P1W")); +} + +// internal sign +TEST(Time_rfc3339_duration, ext_invalid_sign_internal) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT-1S")); +} +TEST(Time_rfc3339_duration, ext_invalid_sign_internal_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1Y-2M")); +} +TEST(Time_rfc3339_duration, ext_invalid_sign_internal_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P--1D")); +} +TEST(Time_rfc3339_duration, ext_invalid_sign_internal_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("+-P1D")); +} +TEST(Time_rfc3339_duration, ext_invalid_sign_internal_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("-P")); +} +TEST(Time_rfc3339_duration, ext_invalid_sign_internal_6) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("+P")); +} + +// fraction incl comma decimal (ISO/xs leak; App A is 1*DIGIT only) +TEST(Time_rfc3339_duration, ext_invalid_fraction) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT0,5S")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P0.5Y")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P0,5Y")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1.5M")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1.5H")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_6) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1.5M")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_7) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P2.5W")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_8) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P0.5D")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_9) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT.5S")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_10) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P.5D")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_11) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1.D")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_12) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1.5DT1H")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_13) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT0.5H30M")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_14) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1..5D")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_15) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1.5.5D")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_16) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P0.5M")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_17) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P0.5Y1D")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_18) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT10000000000000000000.999S")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_19) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1.S")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_20) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1.5W")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_21) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P0.5Y2M")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_22) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P0.5Y2.1M")); +} +TEST(Time_rfc3339_duration, ext_invalid_fraction_23) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P15DT1H22M1.5S")); +} + +// scientific-notation exponent (isoduration Decimal leniency) +TEST(Time_rfc3339_duration, ext_invalid_exponent) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1e2D")); +} +TEST(Time_rfc3339_duration, ext_invalid_exponent_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1E2D")); +} +TEST(Time_rfc3339_duration, ext_invalid_exponent_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1e1S")); +} +TEST(Time_rfc3339_duration, ext_invalid_exponent_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1e-2D")); +} +TEST(Time_rfc3339_duration, ext_invalid_exponent_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1e+2D")); +} +TEST(Time_rfc3339_duration, ext_invalid_exponent_6) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1eD")); +} +TEST(Time_rfc3339_duration, ext_invalid_exponent_7) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1E999999D")); +} + +// huge exponent (crashes python-jsonschema via uncaught decimal.Overflow; Core rejects) +TEST(Time_rfc3339_duration, ext_invalid_exponent_overflow_crash) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1E1000000D")); +} +TEST(Time_rfc3339_duration, ext_invalid_exponent_overflow_crash_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1E1000000S")); +} + +// dur-week exclusivity - week combined with another component +TEST(Time_rfc3339_duration, ext_invalid_week_combo) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1Y1W")); +} +TEST(Time_rfc3339_duration, ext_invalid_week_combo_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1W1D")); +} +TEST(Time_rfc3339_duration, ext_invalid_week_combo_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1D1W")); +} +TEST(Time_rfc3339_duration, ext_invalid_week_combo_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1M1W")); +} +TEST(Time_rfc3339_duration, ext_invalid_week_combo_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1W1Y")); +} +TEST(Time_rfc3339_duration, ext_invalid_week_combo_6) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1W1W")); +} +TEST(Time_rfc3339_duration, ext_invalid_week_combo_7) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P5D2W")); +} +TEST(Time_rfc3339_duration, ext_invalid_week_combo_8) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1W1DT13H23M34S")); +} + +// dur-week exclusivity with a zero-valued prior component (value-not-syntax bug class) +TEST(Time_rfc3339_duration, ext_invalid_week_zero_masked) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P0Y1W")); +} +TEST(Time_rfc3339_duration, ext_invalid_week_zero_masked_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P0Y0M1W")); +} +TEST(Time_rfc3339_duration, ext_invalid_week_zero_masked_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P0M1W")); +} +TEST(Time_rfc3339_duration, ext_invalid_week_zero_masked_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P0D1W")); +} +TEST(Time_rfc3339_duration, ext_invalid_week_zero_masked_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P0Y0M0D1W")); +} + +// dangling number immediately before the T separator +TEST(Time_rfc3339_duration, ext_invalid_dangling_before_T) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1D2T3H")); +} +TEST(Time_rfc3339_duration, ext_invalid_dangling_before_T_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1Y2T3M")); +} +TEST(Time_rfc3339_duration, ext_invalid_dangling_before_T_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P2T1M")); +} +TEST(Time_rfc3339_duration, ext_invalid_dangling_before_T_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1Y2MET5M6S")); +} +TEST(Time_rfc3339_duration, ext_invalid_dangling_before_T_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PE")); +} +TEST(Time_rfc3339_duration, ext_invalid_dangling_before_T_6) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PTE")); +} + +// number with no trailing unit designator +TEST(Time_rfc3339_duration, ext_invalid_trailing_digits) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1MT1")); +} +TEST(Time_rfc3339_duration, ext_invalid_trailing_digits_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT000022.22")); +} + +// fixed component order (Y->M->D, H->M->S) +TEST(Time_rfc3339_duration, ext_invalid_order) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1M1Y")); +} +TEST(Time_rfc3339_duration, ext_invalid_order_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1D1M")); +} +TEST(Time_rfc3339_duration, ext_invalid_order_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P2D1Y")); +} +TEST(Time_rfc3339_duration, ext_invalid_order_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1M1H")); +} +TEST(Time_rfc3339_duration, ext_invalid_order_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1S1M")); +} +TEST(Time_rfc3339_duration, ext_invalid_order_6) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1S1H")); +} +TEST(Time_rfc3339_duration, ext_invalid_order_7) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1M1YT1H")); +} +TEST(Time_rfc3339_duration, ext_invalid_order_8) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1D1MT1H")); +} +TEST(Time_rfc3339_duration, ext_invalid_order_9) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1S1M")); +} + +// repeated designator +TEST(Time_rfc3339_duration, ext_invalid_repeat) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1M2M")); +} +TEST(Time_rfc3339_duration, ext_invalid_repeat_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1D2D")); +} +TEST(Time_rfc3339_duration, ext_invalid_repeat_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1H2H")); +} +TEST(Time_rfc3339_duration, ext_invalid_repeat_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1S2S")); +} +TEST(Time_rfc3339_duration, ext_invalid_repeat_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1W2W")); +} +TEST(Time_rfc3339_duration, ext_invalid_repeat_6) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1Y2M3M")); +} + +// designator in the wrong section +TEST(Time_rfc3339_duration, ext_invalid_cross_placement) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P2S")); +} +TEST(Time_rfc3339_duration, ext_invalid_cross_placement_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1H1M")); +} +TEST(Time_rfc3339_duration, ext_invalid_cross_placement_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1Y")); +} +TEST(Time_rfc3339_duration, ext_invalid_cross_placement_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1W")); +} +TEST(Time_rfc3339_duration, ext_invalid_cross_placement_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1DT2D")); +} +TEST(Time_rfc3339_duration, ext_invalid_cross_placement_6) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1DT1Y")); +} +TEST(Time_rfc3339_duration, ext_invalid_cross_placement_7) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1M1D")); +} + +// T separator edge cases +TEST(Time_rfc3339_duration, ext_invalid_t_edge) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1DT")); +} +TEST(Time_rfc3339_duration, ext_invalid_t_edge_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PTT1H")); +} +TEST(Time_rfc3339_duration, ext_invalid_t_edge_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1HT2M")); +} +TEST(Time_rfc3339_duration, ext_invalid_t_edge_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("T")); +} +TEST(Time_rfc3339_duration, ext_invalid_t_edge_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("TP1D")); +} +TEST(Time_rfc3339_duration, ext_invalid_t_edge_6) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1YT ")); +} +TEST(Time_rfc3339_duration, ext_invalid_t_edge_7) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1MT1S")); +} + +// P prefix requirement +TEST(Time_rfc3339_duration, ext_invalid_prefix) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("T1H")); +} +TEST(Time_rfc3339_duration, ext_invalid_prefix_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("1D")); +} +TEST(Time_rfc3339_duration, ext_invalid_prefix_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("D")); +} +TEST(Time_rfc3339_duration, ext_invalid_prefix_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PP1D")); +} +TEST(Time_rfc3339_duration, ext_invalid_prefix_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1DP")); +} +TEST(Time_rfc3339_duration, ext_invalid_prefix_6) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("XP1D")); +} + +// missing number or missing unit +TEST(Time_rfc3339_duration, ext_invalid_no_num_or_unit) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PD")); +} +TEST(Time_rfc3339_duration, ext_invalid_no_num_or_unit_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PW")); +} +TEST(Time_rfc3339_duration, ext_invalid_no_num_or_unit_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PYD")); +} +TEST(Time_rfc3339_duration, ext_invalid_no_num_or_unit_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1YM")); +} +TEST(Time_rfc3339_duration, ext_invalid_no_num_or_unit_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1")); +} +TEST(Time_rfc3339_duration, ext_invalid_no_num_or_unit_6) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PTS")); +} +TEST(Time_rfc3339_duration, ext_invalid_no_num_or_unit_7) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1DY")); +} +TEST(Time_rfc3339_duration, ext_invalid_no_num_or_unit_8) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1HM")); +} +TEST(Time_rfc3339_duration, ext_invalid_no_num_or_unit_9) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1Y2")); +} +TEST(Time_rfc3339_duration, ext_invalid_no_num_or_unit_10) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1M2")); +} + +// whitespace +TEST(Time_rfc3339_duration, ext_invalid_ws) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P 1D")); +} +TEST(Time_rfc3339_duration, ext_invalid_ws_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1 D")); +} +TEST(Time_rfc3339_duration, ext_invalid_ws_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1D" "\x09")); +} +TEST(Time_rfc3339_duration, ext_invalid_ws_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("\x09" "P1D")); +} +TEST(Time_rfc3339_duration, ext_invalid_ws_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P" "\xc2\xa0" "1D")); +} + +// leading/trailing newline, CRLF (regex-anchor class) +TEST(Time_rfc3339_duration, ext_invalid_ws_anchor) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1D" "\x0a")); +} +TEST(Time_rfc3339_duration, ext_invalid_ws_anchor_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1D" "\x0d\x0a")); +} +TEST(Time_rfc3339_duration, ext_invalid_ws_anchor_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("\x0a" "P1D")); +} +TEST(Time_rfc3339_duration, ext_invalid_ws_anchor_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1DT1H" "\x0a")); +} + +// BOM / NUL / control bytes +TEST(Time_rfc3339_duration, ext_invalid_encoding) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("\xef\xbb\xbf" "P1D")); +} +TEST(Time_rfc3339_duration, ext_invalid_encoding_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration(std::string_view("P1D" "\x00", 4))); +} +TEST(Time_rfc3339_duration, ext_invalid_encoding_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration(std::string_view("P" "\x00" "1D", 4))); +} + +// non-ASCII digit families (DIGIT = %x30-39 only) +TEST(Time_rfc3339_duration, ext_invalid_unicode_digit) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P" "\xe0\xa7\xa8" "Y")); +} +TEST(Time_rfc3339_duration, ext_invalid_unicode_digit_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P" "\xe0\xa7\xa7" "D")); +} +TEST(Time_rfc3339_duration, ext_invalid_unicode_digit_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P" "\xef\xbc\x91" "D")); +} +TEST(Time_rfc3339_duration, ext_invalid_unicode_digit_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P" "\xd9\xa2" "D")); +} +TEST(Time_rfc3339_duration, ext_invalid_unicode_digit_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P" "\xc2\xb2" "D")); +} +TEST(Time_rfc3339_duration, ext_invalid_unicode_digit_6) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT" "\xe0\xa7\xa7" "H")); +} + +// ISO 8601 alternate datetime form (no such form in App A) +TEST(Time_rfc3339_duration, ext_invalid_iso_extended) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P0001-02-03T04:05:06")); +} +TEST(Time_rfc3339_duration, ext_invalid_iso_extended_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P00010203T040506")); +} +TEST(Time_rfc3339_duration, ext_invalid_iso_extended_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT04:05:06")); +} +TEST(Time_rfc3339_duration, ext_invalid_iso_extended_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P2023-01-01T00:00:00")); +} +TEST(Time_rfc3339_duration, ext_invalid_iso_extended_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P20230101T000000S")); +} +TEST(Time_rfc3339_duration, ext_invalid_iso_extended_6) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P0000-01-00")); +} +TEST(Time_rfc3339_duration, ext_invalid_iso_extended_7) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P2020-123T00:00")); +} + +// cross-spec: week valid in App A, rejected by xs:duration +TEST(Time_rfc3339_duration, ext_valid_xspair_week) { + EXPECT_TRUE(sourcemeta::core::is_rfc3339_duration("P52W")); +} + +// cross-spec: sign accepted by xs:duration, invalid in App A +TEST(Time_rfc3339_duration, ext_invalid_xspair_sign) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("-P1Y")); +} +TEST(Time_rfc3339_duration, ext_invalid_xspair_sign_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("-P1Y2M3D")); +} +TEST(Time_rfc3339_duration, ext_invalid_xspair_sign_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("-PT1H30M")); +} + +// cross-spec: comma decimal (ISO 8601 only) +TEST(Time_rfc3339_duration, ext_invalid_isopair_comma) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1,5S")); +} +TEST(Time_rfc3339_duration, ext_invalid_isopair_comma_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1,5DT2H")); +} + +// cross-spec: ISO alternate datetime form +TEST(Time_rfc3339_duration, ext_invalid_isopair_altform) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P0002-03-04T05:06:07")); +} + +// skipped intermediate component (nesting) +TEST(Time_rfc3339_duration, ext_invalid_skip) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1Y2DT1H")); +} +TEST(Time_rfc3339_duration, ext_invalid_skip_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1Y1DT1H")); +} +TEST(Time_rfc3339_duration, ext_invalid_skip_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1H1S")); +} + +// non-duration garbage +TEST(Time_rfc3339_duration, ext_invalid_garbage) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("1 month")); +} +TEST(Time_rfc3339_duration, ext_invalid_garbage_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1 month")); +} +TEST(Time_rfc3339_duration, ext_invalid_garbage_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("Pone")); +} +TEST(Time_rfc3339_duration, ext_invalid_garbage_4) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1H30M5")); +} +TEST(Time_rfc3339_duration, ext_invalid_garbage_5) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1Y2M3")); +} +TEST(Time_rfc3339_duration, ext_invalid_garbage_6) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P" "\xf0\x9f\x94\xa5" "D")); +} +TEST(Time_rfc3339_duration, ext_invalid_garbage_7) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("P1 1D")); +} +TEST(Time_rfc3339_duration, ext_invalid_garbage_8) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("-111111")); +} + +// lowercase (latent RFC 5234 2.3 ambiguity; every impl rejects) +TEST(Time_rfc3339_duration, ext_invalid_case_q4_gated) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("p1d")); +} +TEST(Time_rfc3339_duration, ext_invalid_case_q4_gated_2) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("PT1h")); +} +TEST(Time_rfc3339_duration, ext_invalid_case_q4_gated_3) { + EXPECT_FALSE(sourcemeta::core::is_rfc3339_duration("p1D")); +}