github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/pkg/fftypes/timeutils_test.go (about) 1 // Copyright © 2021 Kaleido, Inc. 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 package fftypes 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "testing" 23 "time" 24 25 "github.com/stretchr/testify/assert" 26 ) 27 28 type UTTimeTest struct { 29 T1 *FFTime `json:"t1"` 30 T2 *FFTime `json:"t2,omitempty"` 31 T3 *FFTime `json:"t3,omitempty"` 32 T4 *FFTime `json:"t4"` 33 T5 *FFTime `json:"t5,omitempty"` 34 T6 *FFTime `json:"t6,omitempty"` 35 T7 *FFTime `json:"t7,omitempty"` 36 } 37 38 func TestFFTimeJSONSerialization(t *testing.T) { 39 now := Now() 40 zeroTime := ZeroTime() 41 assert.True(t, time.Time(zeroTime).IsZero()) 42 t6 := UnixTime(1621103852123456789) 43 t7 := UnixTime(1621103797) 44 utTimeTest := &UTTimeTest{ 45 T1: nil, 46 T2: nil, 47 T3: &zeroTime, 48 T4: &zeroTime, 49 T5: now, 50 T6: t6, 51 T7: t7, 52 } 53 b, err := json.Marshal(&utTimeTest) 54 assert.NoError(t, err) 55 assert.Equal(t, fmt.Sprintf( 56 `{"t1":null,"t3":null,"t4":null,"t5":"%s","t6":"2021-05-15T18:37:32.123456789Z","t7":"2021-05-15T18:36:37Z"}`, 57 time.Time(*now).UTC().Format(time.RFC3339Nano)), string(b)) 58 59 var utTimeTest2 UTTimeTest 60 err = json.Unmarshal(b, &utTimeTest2) 61 assert.NoError(t, err) 62 assert.Nil(t, utTimeTest.T1) 63 assert.Nil(t, utTimeTest.T2) 64 assert.Nil(t, nil, utTimeTest.T3) 65 assert.Nil(t, nil, utTimeTest.T4) 66 assert.Equal(t, *now, *utTimeTest.T5) 67 assert.Equal(t, *t6, *utTimeTest.T6) 68 assert.Equal(t, *t7, *utTimeTest.T7) 69 } 70 71 func TestFFTimeJSONUnmarshalFail(t *testing.T) { 72 var utTimeTest UTTimeTest 73 err := json.Unmarshal([]byte(`{"t1": "!Badness"}`), &utTimeTest) 74 assert.Regexp(t, "FF10165", err) 75 } 76 77 func TestFFTimeDatabaseSerialization(t *testing.T) { 78 now := Now() 79 zero := ZeroTime() 80 81 var ft *FFTime = &zero 82 v, err := ft.Value() 83 assert.NoError(t, err) 84 assert.Equal(t, int64(0), v) 85 86 ft = now 87 v, err = ft.Value() 88 assert.NoError(t, err) 89 assert.Equal(t, now.UnixNano(), v) 90 91 ft = UnixTime(1621103852123456789) 92 v, err = ft.Value() 93 assert.NoError(t, err) 94 assert.Equal(t, int64(1621103852123456789), v) 95 96 ft = UnixTime(1621103797) 97 v, err = ft.Value() 98 assert.NoError(t, err) 99 assert.Equal(t, int64(1621103797000000000), v) 100 101 } 102 103 func TestStringZero(t *testing.T) { 104 var ft *FFTime 105 assert.Equal(t, int64(0), ft.UnixNano()) 106 zero := ZeroTime() 107 ft = &zero 108 assert.Equal(t, "", ft.String()) // empty string rather than epoch 1970 time 109 } 110 111 func TestFFTimeParseValue(t *testing.T) { 112 113 var ft FFTime 114 115 // Unix Nanosecs 116 err := ft.Scan("1621108144123456789") 117 assert.NoError(t, err) 118 assert.Equal(t, "2021-05-15T19:49:04.123456789Z", ft.String()) 119 120 // Unix Millis 121 err = ft.Scan("1621108144123") 122 assert.NoError(t, err) 123 assert.Equal(t, "2021-05-15T19:49:04.123Z", ft.String()) 124 125 // Unix Secs 126 err = ft.Scan("1621108144") 127 assert.NoError(t, err) 128 assert.Equal(t, "2021-05-15T19:49:04Z", ft.String()) 129 130 // RFC3339 Secs - timezone to UTC 131 err = ft.Scan("2021-05-15T19:49:04-05:00") 132 assert.NoError(t, err) 133 assert.Equal(t, "2021-05-16T00:49:04Z", ft.String()) 134 135 // RFC3339 Nanosecs 136 err = ft.Scan("2021-05-15T19:49:04.123456789Z") 137 assert.NoError(t, err) 138 assert.Equal(t, "2021-05-15T19:49:04.123456789Z", ft.String()) 139 140 // A bad string 141 err = ft.Scan("!a supported time format") 142 assert.Regexp(t, "FF10165", err) 143 144 // Nil 145 err = ft.Scan(nil) 146 assert.NoError(t, nil, err) 147 assert.True(t, time.Time(ft).IsZero()) 148 149 // Zero 150 err = ft.Scan(int64(0)) 151 assert.NoError(t, nil, err) 152 assert.True(t, time.Time(ft).IsZero()) 153 154 // Unix time 155 err = ft.Scan(int64(1621108144123)) 156 assert.NoError(t, nil, err) 157 assert.Equal(t, "2021-05-15T19:49:04.123Z", ft.String()) 158 159 // A bad type 160 err = ft.Scan(false) 161 assert.Regexp(t, "FF10125", err) 162 163 } 164 165 func TestFFDurationJSONSerialization(t *testing.T) { 166 var utDurationTest struct { 167 D1 *FFDuration `json:"d1"` 168 D2 *FFDuration `json:"d2,omitempty"` 169 D3 FFDuration `json:"d3"` 170 D4 FFDuration `json:"d4"` 171 D5 FFDuration `json:"d5"` 172 D6 FFDuration `json:"d6"` 173 D7 FFDuration `json:"d7"` 174 } 175 jsonToParse := []byte(` 176 { 177 "d1": null, 178 "d3": 12345, 179 "d4": "12345", 180 "d5": "0", 181 "d6": "1h15s", 182 "d7": "-24h" 183 } 184 `) 185 err := json.Unmarshal(jsonToParse, &utDurationTest) 186 assert.NoError(t, err) 187 assert.Nil(t, utDurationTest.D1) 188 assert.Nil(t, utDurationTest.D2) 189 assert.Equal(t, FFDuration(12345)*FFDuration(time.Millisecond), utDurationTest.D3) 190 assert.Equal(t, FFDuration(12345)*FFDuration(time.Millisecond), utDurationTest.D4) 191 assert.Equal(t, FFDuration(0), utDurationTest.D5) 192 assert.Equal(t, FFDuration(1)*FFDuration(time.Hour)+FFDuration(15)*FFDuration(time.Second), utDurationTest.D6) 193 assert.Equal(t, FFDuration(-24)*FFDuration(time.Hour), utDurationTest.D7) 194 195 b, err := json.Marshal(&utDurationTest) 196 assert.NoError(t, err) 197 assert.Equal(t, `{"d1":null,"d3":"12.345s","d4":"12.345s","d5":"0s","d6":"1h0m15s","d7":"-24h0m0s"}`, string(b)) 198 199 jsonToParse = []byte(`{"d1": false}`) 200 err = json.Unmarshal(jsonToParse, &utDurationTest) 201 assert.Error(t, err) 202 203 jsonToParse = []byte(`{"d1": "1 year"}`) 204 err = json.Unmarshal(jsonToParse, &utDurationTest) 205 assert.Error(t, err) 206 } 207 208 func TestFFDurationParseValue(t *testing.T) { 209 210 var fd FFDuration 211 212 err := fd.Scan("1h") 213 assert.NoError(t, err) 214 assert.Equal(t, "1h0m0s", fd.String()) 215 216 err = fd.Scan(nil) 217 assert.NoError(t, err) 218 assert.Equal(t, FFDuration(0), fd) 219 220 err = fd.Scan(12345) 221 assert.NoError(t, err) 222 assert.Equal(t, FFDuration(12345)*FFDuration(time.Millisecond), fd) 223 224 err = fd.Scan(int64(12345)) 225 assert.NoError(t, err) 226 assert.Equal(t, FFDuration(12345)*FFDuration(time.Millisecond), fd) 227 228 err = fd.Scan(false) 229 assert.Regexp(t, "FF10125", err) 230 231 err = fd.Scan("1 year") 232 assert.Regexp(t, "FF10167", err) 233 234 var pfd *FFDuration 235 v, err := pfd.Value() 236 assert.NoError(t, err) 237 assert.Equal(t, "", v) 238 239 pfd = &fd 240 *pfd = FFDuration(12345) * FFDuration(time.Millisecond) 241 v, err = pfd.Value() 242 assert.NoError(t, err) 243 assert.Equal(t, "12.345s", v) 244 245 } 246 247 func TestDurationParsing(t *testing.T) { 248 assert.Zero(t, ParseToDuration("!a duration")) 249 assert.Zero(t, ParseToDuration("")) 250 assert.Equal(t, "15ms", ParseToDuration("15ms").String()) 251 }