github.com/go-chrono/chrono@v0.0.0-20240102183611-532f0d0d7c34/duration_test.go (about) 1 package chrono_test 2 3 import ( 4 "reflect" 5 "runtime" 6 "strings" 7 "testing" 8 9 "github.com/go-chrono/chrono" 10 ) 11 12 func TestDurationOf(t *testing.T) { 13 for _, tt := range []struct { 14 name string 15 of chrono.Extent 16 nsec float64 17 }{ 18 { 19 name: "of positive nanoseconds", 20 of: 90000000 * chrono.Nanosecond, 21 nsec: 90000000, 22 }, 23 { 24 name: "of positive microsecond", 25 of: 90000 * chrono.Microsecond, 26 nsec: 90000000, 27 }, 28 { 29 name: "of positive milliseconds", 30 of: 90 * chrono.Millisecond, 31 nsec: 90000000, 32 }, 33 { 34 name: "of positive seconds", 35 of: 9 * chrono.Second, 36 nsec: 9000000000, 37 }, 38 { 39 name: "of positive minutes", 40 of: 150 * chrono.Minute, 41 nsec: 9000000000000, 42 }, 43 { 44 name: "of positive hours", 45 of: 2 * chrono.Hour, 46 nsec: 7200000000000, 47 }, 48 { 49 name: "of negative nanoseconds", 50 of: -90000000 * chrono.Nanosecond, 51 nsec: -90000000, 52 }, 53 { 54 name: "of negative microsecond", 55 of: -90000 * chrono.Microsecond, 56 nsec: -90000000, 57 }, 58 { 59 name: "of negative milliseconds", 60 of: -90 * chrono.Millisecond, 61 nsec: -90000000, 62 }, 63 { 64 name: "of negative seconds", 65 of: -9 * chrono.Second, 66 nsec: -9000000000, 67 }, 68 { 69 name: "of negative minutes", 70 of: -150 * chrono.Minute, 71 nsec: -9000000000000, 72 }, 73 { 74 name: "of negative hours", 75 of: -2 * chrono.Hour, 76 nsec: -7200000000000, 77 }, 78 } { 79 t.Run(tt.name, func(t *testing.T) { 80 d := chrono.DurationOf(tt.of) 81 if out := d.Nanoseconds(); out != tt.nsec { 82 t.Errorf("d.Nanoseconds() = %f, want %f", out, tt.nsec) 83 } 84 }) 85 } 86 } 87 88 func TestDuration_units(t *testing.T) { 89 for _, tt := range []struct { 90 name string 91 of chrono.Extent 92 f func(chrono.Duration) float64 93 expected float64 94 }{ 95 { 96 name: "positive nanoseconds", 97 of: 9000000000000 * chrono.Nanosecond, 98 f: chrono.Duration.Nanoseconds, 99 expected: 9000000000000, 100 }, 101 { 102 name: "positive microseconds", 103 of: 9500 * chrono.Nanosecond, 104 f: chrono.Duration.Microseconds, 105 expected: 9.5, 106 }, 107 { 108 name: "positive milliseconds", 109 of: 9500 * chrono.Microsecond, 110 f: chrono.Duration.Milliseconds, 111 expected: 9.5, 112 }, 113 { 114 name: "positive seconds", 115 of: 9500 * chrono.Millisecond, 116 f: chrono.Duration.Seconds, 117 expected: 9.5, 118 }, 119 { 120 name: "positive minutes", 121 of: 90 * chrono.Second, 122 f: chrono.Duration.Minutes, 123 expected: 1.5, 124 }, 125 { 126 name: "positive hours", 127 of: 90 * chrono.Minute, 128 f: chrono.Duration.Hours, 129 expected: 1.5, 130 }, 131 { 132 name: "negative nanoseconds", 133 of: -9000000000000 * chrono.Nanosecond, 134 f: chrono.Duration.Nanoseconds, 135 expected: -9000000000000, 136 }, 137 { 138 name: "negative microseconds", 139 of: -9500 * chrono.Nanosecond, 140 f: chrono.Duration.Microseconds, 141 expected: -9.5, 142 }, 143 { 144 name: "negative milliseconds", 145 of: -9500 * chrono.Microsecond, 146 f: chrono.Duration.Milliseconds, 147 expected: -9.5, 148 }, 149 { 150 name: "negative seconds", 151 of: -9500 * chrono.Millisecond, 152 f: chrono.Duration.Seconds, 153 expected: -9.5, 154 }, 155 { 156 name: "negative minutes", 157 of: -90 * chrono.Second, 158 f: chrono.Duration.Minutes, 159 expected: -1.5, 160 }, 161 { 162 name: "negative hours", 163 of: -90 * chrono.Minute, 164 f: chrono.Duration.Hours, 165 expected: -1.5, 166 }, 167 } { 168 t.Run(tt.name, func(t *testing.T) { 169 d := chrono.DurationOf(tt.of) 170 if out := tt.f(d); out != tt.expected { 171 t.Errorf("%v() = %f, want %f", runtime.FuncForPC(reflect.ValueOf(tt.f).Pointer()).Name(), out, tt.expected) 172 } 173 }) 174 } 175 } 176 177 func TestDuration_Compare(t *testing.T) { 178 for _, tt := range []struct { 179 name string 180 d chrono.Duration 181 d2 chrono.Duration 182 expected int 183 }{ 184 {"seconds less", chrono.DurationOf(1 * chrono.Hour), chrono.DurationOf(2 * chrono.Hour), -1}, 185 {"seconds more", chrono.DurationOf(2 * chrono.Hour), chrono.DurationOf(1 * chrono.Hour), 1}, 186 {"nanos less", chrono.DurationOf(1 * chrono.Nanosecond), chrono.DurationOf(2 * chrono.Nanosecond), -1}, 187 {"nanos more", chrono.DurationOf(2 * chrono.Nanosecond), chrono.DurationOf(1 * chrono.Nanosecond), 1}, 188 {"equal", chrono.DurationOf(chrono.Minute), chrono.DurationOf(chrono.Minute), 0}, 189 } { 190 t.Run(tt.name, func(t *testing.T) { 191 if v := tt.d.Compare(tt.d2); v != tt.expected { 192 t.Errorf("d.Compare(d2) = %d, want %d", v, tt.expected) 193 } 194 }) 195 } 196 } 197 198 func TestDuration_Add(t *testing.T) { 199 for _, tt := range []struct { 200 name string 201 d1 chrono.Duration 202 d2 chrono.Duration 203 expected chrono.Duration 204 }{ 205 { 206 name: "add", 207 d1: chrono.DurationOf((1 * chrono.Hour) + (750 * chrono.Millisecond)), 208 d2: chrono.DurationOf((1 * chrono.Hour) + (550 * chrono.Millisecond)), 209 expected: chrono.DurationOf((2 * chrono.Hour) + (1 * chrono.Second) + (300 * chrono.Millisecond)), 210 }, 211 { 212 name: "add nanoseconds component", 213 d1: chrono.DurationOf(750 * chrono.Millisecond), 214 d2: chrono.DurationOf(550 * chrono.Millisecond), 215 expected: chrono.DurationOf((1 * chrono.Second) + (300 * chrono.Millisecond)), 216 }, 217 { 218 name: "add both components", 219 d1: chrono.DurationOf((1 * chrono.Hour) + (750 * chrono.Millisecond)), 220 d2: chrono.DurationOf((1 * chrono.Hour) + (550 * chrono.Millisecond)), 221 expected: chrono.DurationOf((2 * chrono.Hour) + (1 * chrono.Second) + (300 * chrono.Millisecond)), 222 }, 223 { 224 name: "minus seconds component", 225 d1: chrono.DurationOf(2 * chrono.Hour), 226 d2: chrono.DurationOf(-1 * chrono.Hour), 227 expected: chrono.DurationOf(1 * chrono.Hour), 228 }, 229 { 230 name: "minus nanoseconds component", 231 d1: chrono.DurationOf(750 * chrono.Millisecond), 232 d2: chrono.DurationOf(-550 * chrono.Millisecond), 233 expected: chrono.DurationOf(200 * chrono.Millisecond), 234 }, 235 { 236 name: "minus both components", 237 d1: chrono.DurationOf((2 * chrono.Hour) + (750 * chrono.Millisecond)), 238 d2: chrono.DurationOf(-((1 * chrono.Hour) + (550 * chrono.Millisecond))), 239 expected: chrono.DurationOf((1 * chrono.Hour) + (200 * chrono.Millisecond)), 240 }, 241 } { 242 t.Run(tt.name, func(t *testing.T) { 243 t.Run("d1.Add(d2)", func(t *testing.T) { 244 if ok := tt.d1.CanAdd(tt.d2); !ok { 245 t.Error("d1.CanAdd(d2) = false, want true") 246 } 247 248 if added := tt.d1.Add(tt.d2); added.Compare(tt.expected) != 0 { 249 t.Errorf("d1.Add(d2) = %v, want %v", added, tt.expected) 250 } 251 }) 252 253 t.Run("d2.Add(d1)", func(t *testing.T) { 254 if ok := tt.d2.CanAdd(tt.d1); !ok { 255 t.Error("d2.CanAdd(d1) = false, want true") 256 } 257 258 if added := tt.d2.Add(tt.d1); added.Compare(tt.expected) != 0 { 259 t.Errorf("d2.Add(d1) = %v, want %v", added, tt.expected) 260 } 261 }) 262 }) 263 } 264 265 for _, tt := range []struct { 266 name string 267 d1 chrono.Duration 268 d2 chrono.Duration 269 }{ 270 { 271 name: "overflow", 272 d1: chrono.MaxDuration(), 273 d2: chrono.DurationOf(1 * chrono.Nanosecond), 274 }, 275 { 276 name: "underflow", 277 d1: chrono.MinDuration(), 278 d2: chrono.DurationOf(-1 * chrono.Nanosecond), 279 }, 280 } { 281 t.Run(tt.name, func(t *testing.T) { 282 t.Run("d1.Add(d2)", func(t *testing.T) { 283 if ok := tt.d1.CanAdd(tt.d2); ok { 284 t.Error("d1.CanAdd(d2) = true, want false") 285 } 286 287 func() { 288 defer func() { 289 if r := recover(); r == nil { 290 t.Error("expecting panic that didn't occur") 291 } 292 }() 293 294 tt.d1.Add(tt.d2) 295 }() 296 }) 297 298 t.Run("d2.Add(d1)", func(t *testing.T) { 299 if ok := tt.d2.CanAdd(tt.d1); ok { 300 t.Error("d2.CanAdd(d1) = true, want false") 301 } 302 303 func() { 304 defer func() { 305 if r := recover(); r == nil { 306 t.Error("expecting panic that didn't occur") 307 } 308 }() 309 310 tt.d2.Add(tt.d1) 311 }() 312 }) 313 }) 314 } 315 } 316 317 func TestDuration_Format(t *testing.T) { 318 for _, tt := range formatDurationCases { 319 t.Run(tt.name, func(t *testing.T) { 320 t.Run("positive", func(t *testing.T) { 321 d := chrono.DurationOf(tt.of) 322 if out := d.Format(tt.exclusive...); out != tt.expected { 323 t.Errorf("formatted duration = %s, want %s", out, tt.expected) 324 } 325 }) 326 327 t.Run("negative", func(t *testing.T) { 328 expected := tt.expected 329 if tt.of != 0 { 330 expected = "-" + expected 331 } 332 333 d := chrono.DurationOf(tt.of * -1) 334 if out := d.Format(tt.exclusive...); out != expected { 335 t.Errorf("formatted duration = %s, want %s", out, expected) 336 } 337 }) 338 }) 339 } 340 } 341 342 func TestDuration_Parse(t *testing.T) { 343 for _, tt := range parseDurationCases { 344 t.Run(tt.name, func(t *testing.T) { 345 for _, sign := range []string{"", "+", "-"} { 346 t.Run(sign, func(t *testing.T) { 347 input := sign + tt.input 348 expected := tt.expected 349 if sign == "-" { 350 expected *= -1 351 } 352 353 run := func() { 354 var d chrono.Duration 355 if err := d.Parse(input); err != nil { 356 t.Errorf("failed to parse duation: %v", err) 357 } else if d.Compare(chrono.DurationOf(expected)) != 0 { 358 t.Errorf("parsed duration = %v, want %v", d, expected) 359 } 360 } 361 362 t.Run("dots", func(t *testing.T) { 363 run() 364 }) 365 366 t.Run("commas", func(t *testing.T) { 367 tt.input = strings.ReplaceAll(tt.input, ".", ",") 368 run() 369 }) 370 }) 371 } 372 }) 373 } 374 375 t.Run("overflows", func(t *testing.T) { 376 var d chrono.Duration 377 if err := d.Parse("PT2562047788015216H"); err == nil { 378 t.Error("expecting error but got nil") 379 } 380 }) 381 382 t.Run("underflows", func(t *testing.T) { 383 var d chrono.Duration 384 if err := d.Parse("PT-2562047788015215H"); err == nil { 385 t.Error("expecting error but got nil") 386 } 387 }) 388 } 389 390 func TestDuration_Units(t *testing.T) { 391 d := chrono.DurationOf(12*chrono.Hour + 34*chrono.Minute + 56*chrono.Second + 7*chrono.Nanosecond) 392 393 hours, mins, secs, nsec := d.Units() 394 if hours != 12 { 395 t.Errorf("expecting 12 hours, got %d", hours) 396 } 397 398 if mins != 34 { 399 t.Errorf("expecting 34 mins, got %d", mins) 400 } 401 402 if secs != 56 { 403 t.Errorf("expecting 56 secs, got %d", secs) 404 } 405 406 if nsec != 7 { 407 t.Errorf("expecting 7 nsecs, got %d", nsec) 408 } 409 }