github.com/kamalshkeir/kencoding@v0.0.2-0.20230409043843-44b609a0475a/iso8601/valid_test.go (about) 1 package iso8601 2 3 import ( 4 "testing" 5 "time" 6 ) 7 8 func TestValidate(t *testing.T) { 9 tests := []struct { 10 value string 11 flags ValidFlags 12 valid bool 13 }{ 14 // valid 15 {"2018-01-01T23:42:59.123456789Z", Strict, true}, 16 {"2018-01-01T23:42:59.123456789+07:00", Strict, true}, 17 {"2018-01-01T23:42:59.123456789-07:00", Strict, true}, 18 {"2018-01-01T23:42:59.000+07:00", Strict, true}, 19 20 {"2018-01-01", Flexible, true}, 21 {"2018-01-01 23:42:59", Flexible, true}, 22 {"2018-01-01T23:42:59.123-0700", Flexible, true}, 23 24 // invalid 25 {"", Flexible, false}, // empty string 26 {"whatever", Flexible, false}, // not a time 27 {"2018-01-01", Strict, false}, // missing time 28 {"2018-01-01 23:42:59-0700", Strict, false}, // missing subsecond 29 {"2018-01-01T23:42:59.123456789+0700", Strict, false}, // don't allow numeric time zone 30 {"2018_01-01T23:42:59.123456789Z", Strict, false}, // invalid date separator (first) 31 {"2018-01_01T23:42:59.123456789Z", Strict, false}, // invalid date separator (second) 32 {"2018-01-01 23:42:59.123456789Z", Strict, false}, // invalid date-time separator 33 {"2018-01-01T23-42:59.123456789Z", Strict, false}, // invalid time separator (first) 34 {"2018-01-01T23:42-59.123456789Z", Strict, false}, // invalid time separator (second) 35 {"2018-01-01T23:42:59,123456789Z", Strict, false}, // invalid decimal separator 36 {"2018-01-01T23:42:59.123456789", Strict, false}, // missing timezone 37 {"18-01-01T23:42:59.123456789Z", Strict, false}, // 2-digit year 38 {"2018-1-01T23:42:59.123456789Z", Strict, false}, // 1-digit month 39 {"2018-01-1T23:42:59.123456789Z", Strict, false}, // 1-digit day 40 {"2018-01-01T3:42:59.123456789Z", Strict, false}, // 1-digit hour 41 {"2018-01-01T23:2:59.123456789Z", Strict, false}, // 1-digit minute 42 {"2018-01-01T23:42:9.123456789Z", Strict, false}, // 1-digit second 43 {"2018-01-01T23:42:59.Z", Strict, false}, // not enough subsecond digits 44 {"2018-01-01T23:42:59.1234567890Z", Strict, false}, // too many subsecond digits 45 {"2018-01-01T23:42:59.123456789+7:00", Strict, false}, // 1-digit timezone hour 46 {"2018-01-01T23:42:59.123456789+07:0", Strict, false}, // 1-digit timezone minute 47 {"2018-01-01_23:42:59", Flexible, false}, // invalid date-time separator (not a space) 48 } 49 50 for _, test := range tests { 51 if test.valid != Valid(test.value, test.flags) { 52 t.Errorf("%q expected Valid to return %t", test.value, test.valid) 53 } else if test.valid { 54 if !isIsoString(test.value) { 55 t.Errorf("behavior mismatch, isIsoString says %q must not be a valid date", test.value) 56 } 57 } else if test.flags != Strict { 58 if isIsoString(test.value) { 59 t.Errorf("behavior mismatch, isIsoString says %q must be a valid date", test.value) 60 } 61 } 62 } 63 } 64 65 func BenchmarkValidate(b *testing.B) { 66 b.Run("success", benchmarkValidateSuccess) 67 b.Run("failure", benchmarkValidateFailure) 68 } 69 70 func benchmarkValidateSuccess(b *testing.B) { 71 for i := 0; i < b.N; i++ { 72 if !Valid("2018-01-01T23:42:59.123456789Z", Flexible) { 73 b.Fatal("not valid") 74 } 75 } 76 } 77 78 func benchmarkValidateFailure(b *testing.B) { 79 for i := 0; i < b.N; i++ { 80 if Valid("2018-01-01T23:42:59 oops!", Flexible) { 81 b.Fatal("valid but should not") 82 } 83 } 84 } 85 86 func BenchmarkTimeParse(b *testing.B) { 87 b.Run("success", benchmarkTimeParseSuccess) 88 b.Run("failure", benchmarkTimeParseFailure) 89 } 90 91 func benchmarkTimeParseSuccess(b *testing.B) { 92 for i := 0; i < b.N; i++ { 93 if _, err := time.Parse(time.RFC3339Nano, "2018-01-01T23:42:59.123456789Z"); err != nil { 94 b.Fatal("not valid") 95 } 96 } 97 } 98 99 func benchmarkTimeParseFailure(b *testing.B) { 100 for i := 0; i < b.N; i++ { 101 if _, err := time.Parse(time.RFC3339Nano, "2018-01-01T23:42:59 oops!"); err == nil { 102 b.Fatal("valid but should not") 103 } 104 } 105 } 106 107 // ============================================================================= 108 // This code is extracted from a library we had that we are replacing with this 109 // package, we use it to verify that the behavior matches. 110 // ============================================================================= 111 var validDates = [...]string{ 112 time.RFC3339Nano, 113 time.RFC3339, 114 "2006-01-02T15:04:05.999-0700", 115 "2006-01-02 15:04:05", 116 "2006-01-02", 117 } 118 119 func isIsoString(str string) bool { 120 // Per RFC3339Nano Spec a date should never be more than 35 chars. 121 if len(str) > 36 { 122 return false 123 } 124 125 for _, format := range validDates { 126 if _, err := time.Parse(format, str); err == nil { 127 return true 128 } 129 } 130 131 return false 132 }