github.com/mailgun/holster/v4@v4.20.0/clock/rfc822_test.go (about) 1 package clock 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "testing" 7 "time" 8 9 "github.com/stretchr/testify/assert" 10 "gopkg.in/yaml.v3" 11 ) 12 13 type testStruct struct { 14 Time RFC822Time `json:"ts" yaml:"ts"` 15 } 16 17 func TestRFC822New(t *testing.T) { 18 stdTime, err := Parse(RFC3339, "2019-08-29T11:20:07.123456+03:00") 19 assert.NoError(t, err) 20 21 rfc822TimeFromTime := NewRFC822Time(stdTime) 22 rfc822TimeFromUnix := NewRFC822TimeFromUnix(stdTime.Unix()) 23 assert.True(t, rfc822TimeFromTime.Equal(rfc822TimeFromUnix.Time), 24 "want=%s, got=%s", rfc822TimeFromTime.Time, rfc822TimeFromUnix.Time) 25 26 // Parsing from numerical offset to abbreviated offset is not always reliable. In this 27 // context Go will fallback to the known numerical offset. 28 assert.Equal(t, "Thu, 29 Aug 2019 11:20:07 +0300", rfc822TimeFromTime.String()) 29 assert.Equal(t, "Thu, 29 Aug 2019 08:20:07 UTC", rfc822TimeFromUnix.String()) 30 } 31 32 // NewRFC822Time truncates to second precision. 33 func TestRFC822SecondPrecision(t *testing.T) { 34 stdTime1, err := Parse(RFC3339, "2019-08-29T11:20:07.111111+03:00") 35 assert.NoError(t, err) 36 stdTime2, err := Parse(RFC3339, "2019-08-29T11:20:07.999999+03:00") 37 assert.NoError(t, err) 38 assert.False(t, stdTime1.Equal(stdTime2)) 39 40 rfc822Time1 := NewRFC822Time(stdTime1) 41 rfc822Time2 := NewRFC822Time(stdTime2) 42 assert.True(t, rfc822Time1.Equal(rfc822Time2.Time), 43 "want=%s, got=%s", rfc822Time1.Time, rfc822Time2.Time) 44 } 45 46 func TestRFC822YAMLMarshaler(t *testing.T) { 47 rfcTime := NewRFC822Time(Date(1955, November, 12, 6, 38, 0, 0, UTC)) 48 ts := testStruct{Time: rfcTime} 49 encoded, err := yaml.Marshal(ts) 50 assert.NoError(t, err) 51 assert.Equal(t, "ts: Sat, 12 Nov 1955 06:38:00 UTC\n", string(encoded)) 52 53 var decoded testStruct 54 err = yaml.Unmarshal(encoded, &decoded) 55 assert.NoError(t, err) 56 assert.Equal(t, rfcTime, decoded.Time) 57 } 58 59 // Marshaled representation is truncated down to second precision. 60 func TestRFC822Marshaling(t *testing.T) { 61 stdTime, err := Parse(RFC3339Nano, "2019-08-29T11:20:07.123456789+03:30") 62 assert.NoError(t, err) 63 64 ts := testStruct{Time: NewRFC822Time(stdTime)} 65 encoded, err := json.Marshal(&ts) 66 assert.NoError(t, err) 67 assert.Equal(t, `{"ts":"Thu, 29 Aug 2019 11:20:07 +0330"}`, string(encoded)) 68 } 69 70 func TestRFC822Unmarshaling(t *testing.T) { 71 for i, tc := range []struct { 72 inRFC822 string 73 outRFC3339 string 74 outRFC822 string 75 }{{ 76 inRFC822: "Thu, 29 Aug 2019 11:20:07 GMT", 77 outRFC3339: "2019-08-29T11:20:07Z", 78 outRFC822: "Thu, 29 Aug 2019 11:20:07 GMT", 79 }, { 80 inRFC822: "Thu, 29 Aug 2019 11:20:07 MSK", 81 // Extrapolating the numerical offset from an abbreviated offset is unreliable. In 82 // this test case the RFC3339 will have the incorrect result due to limitation in 83 // Go's time parser. 84 outRFC3339: "2019-08-29T11:20:07Z", 85 outRFC822: "Thu, 29 Aug 2019 11:20:07 MSK", 86 }, { 87 inRFC822: "Thu, 29 Aug 2019 11:20:07 -0000", 88 outRFC3339: "2019-08-29T11:20:07Z", 89 outRFC822: "Thu, 29 Aug 2019 11:20:07 -0000", 90 }, { 91 inRFC822: "Thu, 29 Aug 2019 11:20:07 +0000", 92 outRFC3339: "2019-08-29T11:20:07Z", 93 outRFC822: "Thu, 29 Aug 2019 11:20:07 +0000", 94 }, { 95 inRFC822: "Thu, 29 Aug 2019 11:20:07 +0300", 96 outRFC3339: "2019-08-29T11:20:07+03:00", 97 outRFC822: "Thu, 29 Aug 2019 11:20:07 +0300", 98 }, { 99 inRFC822: "Thu, 29 Aug 2019 11:20:07 +0330", 100 outRFC3339: "2019-08-29T11:20:07+03:30", 101 outRFC822: "Thu, 29 Aug 2019 11:20:07 +0330", 102 }, { 103 inRFC822: "Sun, 01 Sep 2019 11:20:07 +0300", 104 outRFC3339: "2019-09-01T11:20:07+03:00", 105 outRFC822: "Sun, 01 Sep 2019 11:20:07 +0300", 106 }, { 107 inRFC822: "Sun, 1 Sep 2019 11:20:07 +0300", 108 outRFC3339: "2019-09-01T11:20:07+03:00", 109 outRFC822: "Sun, 01 Sep 2019 11:20:07 +0300", 110 }, { 111 inRFC822: "Sun, 1 Sep 2019 11:20:07 +0300", 112 outRFC3339: "2019-09-01T11:20:07+03:00", 113 outRFC822: "Sun, 01 Sep 2019 11:20:07 +0300", 114 }, { 115 inRFC822: "Sun, 1 Sep 2019 11:20:07 UTC", 116 outRFC3339: "2019-09-01T11:20:07Z", 117 outRFC822: "Sun, 01 Sep 2019 11:20:07 UTC", 118 }, { 119 inRFC822: "Sun, 1 Sep 2019 11:20:07 UTC", 120 outRFC3339: "2019-09-01T11:20:07Z", 121 outRFC822: "Sun, 01 Sep 2019 11:20:07 UTC", 122 }, { 123 inRFC822: "Sun, 1 Sep 2019 11:20:07 GMT", 124 outRFC3339: "2019-09-01T11:20:07Z", 125 outRFC822: "Sun, 01 Sep 2019 11:20:07 GMT", 126 }, { 127 inRFC822: "Fri, 21 Nov 1997 09:55:06 -0600 (MDT)", 128 outRFC3339: "1997-11-21T09:55:06-06:00", 129 outRFC822: "Fri, 21 Nov 1997 09:55:06 MDT", 130 }} { 131 t.Run(tc.inRFC822, func(t *testing.T) { 132 tcDesc := fmt.Sprintf("Test case #%d: %v", i, tc) 133 var ts testStruct 134 135 inEncoded := []byte(fmt.Sprintf(`{"ts":%q}`, tc.inRFC822)) 136 err := json.Unmarshal(inEncoded, &ts) 137 assert.NoError(t, err, tcDesc) 138 assert.Equal(t, tc.outRFC3339, ts.Time.Format(RFC3339), tcDesc) 139 140 actualEncoded, err := json.Marshal(&ts) 141 assert.NoError(t, err, tcDesc) 142 outEncoded := fmt.Sprintf(`{"ts":%q}`, tc.outRFC822) 143 assert.Equal(t, outEncoded, string(actualEncoded), tcDesc) 144 }) 145 } 146 } 147 148 func TestRFC822UnmarshalingError(t *testing.T) { 149 for _, tc := range []struct { 150 inEncoded string 151 outError string 152 }{{ 153 inEncoded: `{"ts": "Thu, 29 Aug 2019 11:20:07"}`, 154 outError: `parsing time "Thu, 29 Aug 2019 11:20:07" as "January 2 2006 15:04 -0700 (MST)": cannot parse "Thu, 29 Aug 2019 11:20:07" as "January"`, 155 }, { 156 inEncoded: `{"ts": "foo"}`, 157 outError: `parsing time "foo" as "January 2 2006 15:04 -0700 (MST)": cannot parse "foo" as "January"`, 158 }, { 159 inEncoded: `{"ts": 42}`, 160 outError: "invalid syntax", 161 }} { 162 t.Run(tc.inEncoded, func(t *testing.T) { 163 var ts testStruct 164 err := json.Unmarshal([]byte(tc.inEncoded), &ts) 165 assert.EqualError(t, err, tc.outError) 166 }) 167 } 168 } 169 170 func TestParseRFC822Time(t *testing.T) { 171 for _, tt := range []struct { 172 rfc822Time string 173 }{ 174 {"Thu, 3 Jun 2021 12:01:05 MST"}, 175 {"Thu, 3 Jun 2021 12:01:05 -0700"}, 176 {"Thu, 3 Jun 2021 12:01:05 -0700 (MST)"}, 177 {"2 Jun 2021 17:06:41 GMT"}, 178 {"2 Jun 2021 17:06:41 -0700"}, 179 {"2 Jun 2021 17:06:41 -0700 (MST)"}, 180 {"Mon, 30 August 2021 11:05:00 -0400"}, 181 {"Thu, 3 June 2021 12:01:05 MST"}, 182 {"Thu, 3 June 2021 12:01:05 -0700"}, 183 {"Thu, 3 June 2021 12:01:05 -0700 (MST)"}, 184 {"2 June 2021 17:06:41 GMT"}, 185 {"2 June 2021 17:06:41 -0700"}, 186 {"2 June 2021 17:06:41 -0700 (MST)"}, 187 {"Wed, Nov 03 2021 17:48:06 CST"}, 188 {"Wed, November 03 2021 17:48:06 CST"}, 189 190 // Timestamps without seconds. 191 {"Sun, 31 Oct 2021 12:10 -5000"}, 192 {"Thu, 3 Jun 2021 12:01 MST"}, 193 {"Thu, 3 Jun 2021 12:01 -0700"}, 194 {"Thu, 3 Jun 2021 12:01 -0700 (MST)"}, 195 {"2 Jun 2021 17:06 GMT"}, 196 {"2 Jun 2021 17:06 -0700"}, 197 {"2 Jun 2021 17:06 -0700 (MST)"}, 198 {"Mon, 30 August 2021 11:05 -0400"}, 199 {"Thu, 3 June 2021 12:01 MST"}, 200 {"Thu, 3 June 2021 12:01 -0700"}, 201 {"Thu, 3 June 2021 12:01 -0700 (MST)"}, 202 {"2 June 2021 17:06 GMT"}, 203 {"2 June 2021 17:06 -0700"}, 204 {"2 June 2021 17:06 -0700 (MST)"}, 205 {"Wed, Nov 03 2021 17:48 CST"}, 206 {"Wed, November 03 2021 17:48 CST"}, 207 } { 208 t.Run(tt.rfc822Time, func(t *testing.T) { 209 _, err := ParseRFC822Time(tt.rfc822Time) 210 assert.NoError(t, err) 211 }) 212 } 213 } 214 215 func TestStringWithOffset(t *testing.T) { 216 now := time.Now().UTC() 217 r := NewRFC822Time(now) 218 assert.Equal(t, now.Format(time.RFC1123Z), r.StringWithOffset()) 219 }