2018-01-12 16:30:54 +00:00
package fs
import (
2020-12-11 17:48:09 +00:00
"encoding/json"
2018-05-14 15:32:27 +00:00
"fmt"
2020-05-11 12:25:39 +00:00
"strings"
2018-01-12 16:30:54 +00:00
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
2023-09-27 12:58:27 +00:00
// Check it satisfies the interfaces
var (
2024-07-08 11:14:28 +00:00
_ Flagger = ( * Duration ) ( nil )
_ FlaggerNP = Duration ( 0 )
2023-09-27 12:58:27 +00:00
)
2018-01-12 16:30:54 +00:00
func TestParseDuration ( t * testing . T ) {
2020-09-06 23:50:16 +00:00
now := time . Date ( 2020 , 9 , 5 , 8 , 15 , 5 , 250 , time . UTC )
getNow := func ( ) time . Time {
return now
}
2018-01-12 16:30:54 +00:00
for _ , test := range [ ] struct {
in string
2018-03-12 20:52:42 +00:00
want time . Duration
2018-01-12 16:30:54 +00:00
err bool
} {
{ "0" , 0 , false } ,
{ "" , 0 , true } ,
2018-03-12 20:52:42 +00:00
{ "1ms" , time . Millisecond , false } ,
{ "1s" , time . Second , false } ,
{ "1m" , time . Minute , false } ,
2018-05-14 15:32:27 +00:00
{ "1.5m" , ( 3 * time . Minute ) / 2 , false } ,
2018-03-12 20:52:42 +00:00
{ "1h" , time . Hour , false } ,
{ "1d" , time . Hour * 24 , false } ,
{ "1w" , time . Hour * 24 * 7 , false } ,
{ "1M" , time . Hour * 24 * 30 , false } ,
{ "1y" , time . Hour * 24 * 365 , false } ,
{ "1.5y" , time . Hour * 24 * 365 * 3 / 2 , false } ,
{ "-1s" , - time . Second , false } ,
{ "1.s" , time . Second , false } ,
2018-01-12 16:30:54 +00:00
{ "1x" , 0 , true } ,
2018-03-12 20:52:42 +00:00
{ "off" , time . Duration ( DurationOff ) , false } ,
2018-05-14 15:32:27 +00:00
{ "1h2m3s" , time . Hour + 2 * time . Minute + 3 * time . Second , false } ,
2022-03-28 10:47:27 +00:00
{ "2001-02-03" , now . Sub ( time . Date ( 2001 , 2 , 3 , 0 , 0 , 0 , 0 , time . Local ) ) , false } ,
{ "2001-02-03 10:11:12" , now . Sub ( time . Date ( 2001 , 2 , 3 , 10 , 11 , 12 , 0 , time . Local ) ) , false } ,
{ "2001-08-03 10:11:12" , now . Sub ( time . Date ( 2001 , 8 , 3 , 10 , 11 , 12 , 0 , time . Local ) ) , false } ,
{ "2001-02-03T10:11:12" , now . Sub ( time . Date ( 2001 , 2 , 3 , 10 , 11 , 12 , 0 , time . Local ) ) , false } ,
2020-09-06 23:50:16 +00:00
{ "2001-02-03T10:11:12.123Z" , now . Sub ( time . Date ( 2001 , 2 , 3 , 10 , 11 , 12 , 123 , time . UTC ) ) , false } ,
2022-03-28 10:47:27 +00:00
{ "2001-02-03T10:11:12.123+00:00" , now . Sub ( time . Date ( 2001 , 2 , 3 , 10 , 11 , 12 , 123 , time . UTC ) ) , false } ,
2018-01-12 16:30:54 +00:00
} {
2020-09-06 23:50:16 +00:00
duration , err := parseDurationFromNow ( test . in , getNow )
2018-01-12 16:30:54 +00:00
if test . err {
require . Error ( t , err )
} else {
require . NoError ( t , err )
}
2020-05-11 12:25:39 +00:00
if strings . HasPrefix ( test . in , "2001-" ) {
ok := duration > test . want - time . Second && duration < test . want + time . Second
assert . True ( t , ok , test . in )
} else {
assert . Equal ( t , test . want , duration )
}
2018-03-12 20:52:42 +00:00
}
}
func TestDurationString ( t * testing . T ) {
2020-09-06 23:50:16 +00:00
now := time . Date ( 2020 , 9 , 5 , 8 , 15 , 5 , 250 , time . UTC )
getNow := func ( ) time . Time {
return now
}
2018-03-12 20:52:42 +00:00
for _ , test := range [ ] struct {
in time . Duration
want string
} {
2018-04-06 18:04:31 +00:00
{ time . Duration ( 0 ) , "0s" } ,
2018-03-12 20:52:42 +00:00
{ time . Second , "1s" } ,
{ time . Minute , "1m0s" } ,
2018-05-14 15:32:27 +00:00
{ time . Millisecond , "1ms" } ,
{ time . Second , "1s" } ,
{ ( 3 * time . Minute ) / 2 , "1m30s" } ,
{ time . Hour , "1h0m0s" } ,
{ time . Hour * 24 , "1d" } ,
{ time . Hour * 24 * 7 , "1w" } ,
{ time . Hour * 24 * 30 , "1M" } ,
{ time . Hour * 24 * 365 , "1y" } ,
{ time . Hour * 24 * 365 * 3 / 2 , "1.5y" } ,
{ - time . Second , "-1s" } ,
{ time . Second , "1s" } ,
2018-03-12 20:52:42 +00:00
{ time . Duration ( DurationOff ) , "off" } ,
2018-05-14 15:32:27 +00:00
{ time . Hour + 2 * time . Minute + 3 * time . Second , "1h2m3s" } ,
{ time . Hour * 24 , "1d" } ,
{ time . Hour * 24 * 7 , "1w" } ,
{ time . Hour * 24 * 30 , "1M" } ,
{ time . Hour * 24 * 365 , "1y" } ,
{ time . Hour * 24 * 365 * 3 / 2 , "1.5y" } ,
{ - time . Hour * 24 * 365 * 3 / 2 , "-1.5y" } ,
2018-03-12 20:52:42 +00:00
} {
got := Duration ( test . in ) . String ( )
assert . Equal ( t , test . want , got )
2018-05-14 15:32:27 +00:00
// Test the reverse
2020-09-06 23:50:16 +00:00
reverse , err := parseDurationFromNow ( test . want , getNow )
2018-05-14 15:32:27 +00:00
assert . NoError ( t , err )
assert . Equal ( t , test . in , reverse )
2018-01-12 16:30:54 +00:00
}
}
2018-05-14 15:32:27 +00:00
2019-07-01 11:09:19 +00:00
func TestDurationReadableString ( t * testing . T ) {
for _ , test := range [ ] struct {
2022-08-19 09:40:43 +00:00
negative bool
in time . Duration
wantLong string
wantShort string
2019-07-01 11:09:19 +00:00
} {
// Edge Cases
2022-08-19 09:40:43 +00:00
{ false , time . Duration ( DurationOff ) , "off" , "off" } ,
2019-07-01 11:09:19 +00:00
// Base Cases
2022-08-19 09:40:43 +00:00
{ false , time . Duration ( 0 ) , "0s" , "0s" } ,
{ true , time . Millisecond , "1ms" , "1ms" } ,
{ true , time . Second , "1s" , "1s" } ,
{ true , time . Minute , "1m" , "1m" } ,
{ true , ( 3 * time . Minute ) / 2 , "1m30s" , "1m30s" } ,
{ true , time . Hour , "1h" , "1h" } ,
{ true , time . Hour * 24 , "1d" , "1d" } ,
{ true , time . Hour * 24 * 7 , "1w" , "1w" } ,
{ true , time . Hour * 24 * 365 , "1y" , "1y" } ,
2019-07-01 11:09:19 +00:00
// Composite Cases
2022-08-19 09:40:43 +00:00
{ true , time . Hour + 2 * time . Minute + 3 * time . Second , "1h2m3s" , "1h2m3s" } ,
{ true , time . Hour * 24 * ( 365 + 14 ) , "1y2w" , "1y2w" } ,
{ true , time . Hour * 24 * 4 + time . Hour * 3 + time . Minute * 2 + time . Second , "4d3h2m1s" , "4d3h2m" } ,
{ true , time . Hour * 24 * ( 365 * 3 + 7 * 2 + 1 ) , "3y2w1d" , "3y2w1d" } ,
{ true , time . Hour * 24 * ( 365 * 3 + 7 * 2 + 1 ) + time . Hour * 2 + time . Second , "3y2w1d2h1s" , "3y2w1d" } ,
{ true , time . Hour * 24 * ( 365 * 3 + 7 * 2 + 1 ) + time . Second , "3y2w1d1s" , "3y2w1d" } ,
{ true , time . Hour * 24 * ( 365 + 7 * 2 + 3 ) + time . Hour * 4 + time . Minute * 5 + time . Second * 6 + time . Millisecond * 7 , "1y2w3d4h5m6s7ms" , "1y2w3d" } ,
{ true , time . Duration ( DurationOff ) / time . Millisecond * time . Millisecond , "292y24w3d23h47m16s853ms" , "292y24w3d" } , // Should have been 854ms but some precision are lost with floating point calculations
2019-07-01 11:09:19 +00:00
} {
got := Duration ( test . in ) . ReadableString ( )
2022-08-19 09:40:43 +00:00
assert . Equal ( t , test . wantLong , got )
got = Duration ( test . in ) . ShortReadableString ( )
assert . Equal ( t , test . wantShort , got )
2019-07-01 11:09:19 +00:00
// Test Negative Case
if test . negative {
got = Duration ( - test . in ) . ReadableString ( )
2022-08-19 09:40:43 +00:00
assert . Equal ( t , "-" + test . wantLong , got )
got = Duration ( - test . in ) . ShortReadableString ( )
assert . Equal ( t , "-" + test . wantShort , got )
2019-07-01 11:09:19 +00:00
}
}
}
2018-05-14 15:32:27 +00:00
func TestDurationScan ( t * testing . T ) {
2022-08-05 14:23:44 +00:00
now := time . Date ( 2020 , 9 , 5 , 8 , 15 , 5 , 250 , time . UTC )
oldTimeNowFunc := timeNowFunc
timeNowFunc = func ( ) time . Time { return now }
defer func ( ) { timeNowFunc = oldTimeNowFunc } ( )
for _ , test := range [ ] struct {
in string
want Duration
} {
{ "17m" , Duration ( 17 * time . Minute ) } ,
{ "-12h" , Duration ( - 12 * time . Hour ) } ,
{ "0" , Duration ( 0 ) } ,
{ "off" , DurationOff } ,
{ "2022-03-26T17:48:19Z" , Duration ( now . Sub ( time . Date ( 2022 , 03 , 26 , 17 , 48 , 19 , 0 , time . UTC ) ) ) } ,
{ "2022-03-26 17:48:19" , Duration ( now . Sub ( time . Date ( 2022 , 03 , 26 , 17 , 48 , 19 , 0 , time . Local ) ) ) } ,
} {
var got Duration
n , err := fmt . Sscan ( test . in , & got )
require . NoError ( t , err )
assert . Equal ( t , 1 , n )
assert . Equal ( t , test . want , got )
}
2018-05-14 15:32:27 +00:00
}
2020-12-11 17:48:09 +00:00
func TestParseUnmarshalJSON ( t * testing . T ) {
for _ , test := range [ ] struct {
in string
want time . Duration
err bool
} {
{ ` "" ` , 0 , true } ,
{ ` "0" ` , 0 , false } ,
{ ` "1ms" ` , time . Millisecond , false } ,
{ ` "1s" ` , time . Second , false } ,
{ ` "1m" ` , time . Minute , false } ,
{ ` "1h" ` , time . Hour , false } ,
{ ` "1d" ` , time . Hour * 24 , false } ,
{ ` "1w" ` , time . Hour * 24 * 7 , false } ,
{ ` "1M" ` , time . Hour * 24 * 30 , false } ,
{ ` "1y" ` , time . Hour * 24 * 365 , false } ,
{ ` "off" ` , time . Duration ( DurationOff ) , false } ,
{ ` "error" ` , 0 , true } ,
{ "0" , 0 , false } ,
{ "1000000" , time . Millisecond , false } ,
{ "1000000000" , time . Second , false } ,
{ "60000000000" , time . Minute , false } ,
{ "3600000000000" , time . Hour , false } ,
{ "9223372036854775807" , time . Duration ( DurationOff ) , false } ,
{ "error" , 0 , true } ,
} {
var duration Duration
err := json . Unmarshal ( [ ] byte ( test . in ) , & duration )
if test . err {
require . Error ( t , err , test . in )
} else {
require . NoError ( t , err , test . in )
}
assert . Equal ( t , Duration ( test . want ) , duration , test . in )
}
}
2024-03-13 18:08:59 +00:00
func TestUnmarshalJSON ( t * testing . T ) {
tests := [ ] struct {
name string
input string
want Duration
wantErr bool
} {
{ "off string" , ` "off" ` , DurationOff , false } ,
{ "max int64" , ` 9223372036854775807 ` , DurationOff , false } ,
{ "duration string" , ` "1h" ` , Duration ( time . Hour ) , false } ,
{ "invalid string" , ` "invalid" ` , 0 , true } ,
{ "negative int" , ` -1 ` , Duration ( - 1 ) , false } ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
var d Duration
err := json . Unmarshal ( [ ] byte ( tt . input ) , & d )
if ( err != nil ) != tt . wantErr {
t . Errorf ( "UnmarshalJSON() error = %v, wantErr %v" , err , tt . wantErr )
return
}
if d != tt . want {
t . Errorf ( "UnmarshalJSON() got = %v, want %v" , d , tt . want )
}
} )
}
}