2020-04-03 23:11:33 +00:00
package utils
import (
2023-02-11 03:11:40 +00:00
"fmt"
"strings"
2020-04-03 23:11:33 +00:00
"testing"
"time"
2020-04-05 12:37:21 +00:00
"github.com/stretchr/testify/assert"
2020-04-03 23:11:33 +00:00
)
2023-02-11 03:11:40 +00:00
func TestParseDurationString ( t * testing . T ) {
testCases := [ ] struct {
name string
have [ ] string
raw bool
expected time . Duration
err string
} {
{ "ShouldParseStringsForMillisecond" , [ ] string { "%d ms" , "%d millisecond" , "%d milliseconds" } , false , time . Millisecond , "" } ,
{ "ShouldParseStringsForSecond" , [ ] string { "%d s" , "%d second" , "%d seconds" } , false , time . Second , "" } ,
{ "ShouldParseStringsForMinute" , [ ] string { "%d m" , "%d minute" , "%d minutes" } , false , time . Minute , "" } ,
{ "ShouldParseStringsForHour" , [ ] string { "%d h" , "%d hour" , "%d hours" } , false , time . Hour , "" } ,
{ "ShouldParseStringsForDay" , [ ] string { "%d d" , "%d day" , "%d days" } , false , time . Hour * HoursInDay , "" } ,
{ "ShouldParseStringsForWeek" , [ ] string { "%d w" , "%d week" , "%d weeks" } , false , time . Hour * HoursInWeek , "" } ,
{ "ShouldParseStringsForMonth" , [ ] string { "%d M" , "%d month" , "%d months" } , false , time . Hour * HoursInMonth , "" } ,
{ "ShouldParseStringsForYear" , [ ] string { "%d y" , "%d year" , "%d years" } , false , time . Hour * HoursInYear , "" } ,
{ "ShouldParseStringsDecimals" , [ ] string { "100" } , true , time . Second * 100 , "" } ,
{ "ShouldParseStringsDecimalNull" , [ ] string { "" } , true , time . Second * 0 , "" } ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
for _ , f := range tc . have {
if tc . raw {
t . Run ( f , func ( t * testing . T ) {
actual , actualErr := ParseDurationString ( f )
if tc . err == "" {
assert . NoError ( t , actualErr )
assert . Equal ( t , tc . expected , actual )
} else {
assert . EqualError ( t , actualErr , tc . err )
}
} )
} else {
for _ , d := range [ ] int { 1 , 5 , 20 } {
input := fmt . Sprintf ( f , d )
inputNoSpace := strings . ReplaceAll ( input , " " , "" )
t . Run ( inputNoSpace , func ( t * testing . T ) {
t . Run ( "WithSpaces" , func ( t * testing . T ) {
actual , actualErr := ParseDurationString ( input )
if tc . err == "" {
assert . NoError ( t , actualErr )
assert . Equal ( t , tc . expected * time . Duration ( d ) , actual )
} else {
assert . EqualError ( t , actualErr , tc . err )
}
t . Run ( "LeadingZeros" , func ( t * testing . T ) {
inputActual := reNumeric . ReplaceAllStringFunc ( input , func ( s string ) string {
return "000" + s
} )
actual , actualErr := ParseDurationString ( inputActual )
if tc . err == "" {
assert . NoError ( t , actualErr )
assert . Equal ( t , tc . expected * time . Duration ( d ) , actual )
} else {
assert . EqualError ( t , actualErr , tc . err )
}
} )
} )
t . Run ( "WithoutSpaces" , func ( t * testing . T ) {
actual , actualErr := ParseDurationString ( inputNoSpace )
if tc . err == "" {
assert . NoError ( t , actualErr )
assert . Equal ( t , tc . expected * time . Duration ( d ) , actual )
} else {
assert . EqualError ( t , actualErr , tc . err )
}
t . Run ( "LeadingZeros" , func ( t * testing . T ) {
inputActual := reNumeric . ReplaceAllStringFunc ( inputNoSpace , func ( s string ) string {
return "000" + s
} )
actual , actualErr := ParseDurationString ( inputActual )
if tc . err == "" {
assert . NoError ( t , actualErr )
assert . Equal ( t , tc . expected * time . Duration ( d ) , actual )
} else {
assert . EqualError ( t , actualErr , tc . err )
}
} )
} )
} )
}
}
}
} )
}
2020-04-03 23:11:33 +00:00
}
2022-03-02 06:40:26 +00:00
func TestParseDurationString_ShouldNotParseDurationStringWithOutOfOrderQuantitiesAndUnits ( t * testing . T ) {
2020-04-03 23:11:33 +00:00
duration , err := ParseDurationString ( "h1" )
2022-03-02 06:40:26 +00:00
2022-02-28 03:15:01 +00:00
assert . EqualError ( t , err , "could not parse 'h1' as a duration" )
2020-04-03 23:11:33 +00:00
assert . Equal ( t , time . Duration ( 0 ) , duration )
}
2022-03-02 06:40:26 +00:00
func TestParseDurationString_ShouldNotParseBadDurationString ( t * testing . T ) {
2020-04-03 23:11:33 +00:00
duration , err := ParseDurationString ( "10x" )
2022-03-02 06:40:26 +00:00
assert . EqualError ( t , err , "could not parse the units portion of '10x' in duration string '10x': the unit 'x' is not valid" )
2020-04-03 23:11:33 +00:00
assert . Equal ( t , time . Duration ( 0 ) , duration )
}
2023-02-11 03:11:40 +00:00
func TestParseDurationString_ShouldNotParseBadDurationStringAlt ( t * testing . T ) {
duration , err := ParseDurationString ( "10abcxyz" )
2022-03-02 06:40:26 +00:00
2023-02-11 03:11:40 +00:00
assert . EqualError ( t , err , "could not parse the units portion of '10abcxyz' in duration string '10abcxyz': the unit 'abcxyz' is not valid" )
assert . Equal ( t , time . Duration ( 0 ) , duration )
2022-03-02 06:40:26 +00:00
}
func TestParseDurationString_ShouldParseMultiUnitValues ( t * testing . T ) {
duration , err := ParseDurationString ( "1d3w10ms" )
assert . NoError ( t , err )
assert . Equal ( t ,
( time . Hour * time . Duration ( 24 ) ) +
( time . Hour * time . Duration ( 24 ) * time . Duration ( 7 ) * time . Duration ( 3 ) ) +
( time . Millisecond * time . Duration ( 10 ) ) , duration )
}
func TestParseDurationString_ShouldParseDuplicateUnitValues ( t * testing . T ) {
duration , err := ParseDurationString ( "1d4d2d" )
assert . NoError ( t , err )
assert . Equal ( t ,
( time . Hour * time . Duration ( 24 ) ) +
( time . Hour * time . Duration ( 24 ) * time . Duration ( 4 ) ) +
( time . Hour * time . Duration ( 24 ) * time . Duration ( 2 ) ) , duration )
}
func TestStandardizeDurationString_ShouldParseStringWithSpaces ( t * testing . T ) {
result , err := StandardizeDurationString ( "1d 1h 20m" )
assert . NoError ( t , err )
assert . Equal ( t , result , "24h1h20m" )
2020-04-03 23:11:33 +00:00
}
func TestShouldTimeIntervalsMakeSense ( t * testing . T ) {
assert . Equal ( t , Hour , time . Minute * 60 )
assert . Equal ( t , Day , Hour * 24 )
assert . Equal ( t , Week , Day * 7 )
assert . Equal ( t , Year , Day * 365 )
assert . Equal ( t , Month , Year / 12 )
}
2022-12-21 10:31:21 +00:00
func TestShouldConvertKnownUnixNanoTimeToKnownWin32Epoch ( t * testing . T ) {
exampleNanoTime := int64 ( 1626234411 * 1000000000 )
win32Epoch := uint64 ( 132707080110000000 )
assert . Equal ( t , win32Epoch , UnixNanoTimeToMicrosoftNTEpoch ( exampleNanoTime ) )
assert . Equal ( t , timeUnixEpochAsMicrosoftNTEpoch , UnixNanoTimeToMicrosoftNTEpoch ( 0 ) )
}
2023-02-11 03:11:40 +00:00
func TestParseTimeString ( t * testing . T ) {
testCases := [ ] struct {
name string
have string
index int
expected time . Time
err string
} {
{ "ShouldParseIntegerAsUnix" , "1675899060" , - 1 , time . Unix ( 1675899060 , 0 ) , "" } ,
{ "ShouldParseIntegerAsUnixMilli" , "1675899060000" , - 2 , time . Unix ( 1675899060 , 0 ) , "" } ,
{ "ShouldParseIntegerAsUnixMicro" , "1675899060000000" , - 3 , time . Unix ( 1675899060 , 0 ) , "" } ,
{ "ShouldNotParseSuperLargeInteger" , "9999999999999999999999999999999999999999" , - 999 , time . Unix ( 0 , 0 ) , "time value was detected as an integer but the integer could not be parsed: strconv.ParseInt: parsing \"9999999999999999999999999999999999999999\": value out of range" } ,
{ "ShouldParseSimpleTime" , "Jan 2 15:04:05 2006" , 0 , time . Unix ( 1136214245 , 0 ) , "" } ,
{ "ShouldNotParseInvalidTime" , "abc" , - 998 , time . Unix ( 0 , 0 ) , "failed to find a suitable time layout for time 'abc'" } ,
{ "ShouldMatchDate" , "2020-05-01" , 6 , time . Unix ( 1588291200 , 0 ) , "" } ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
index , actual , err := matchParseTimeStringWithLayouts ( tc . have , StandardTimeLayouts )
if tc . err == "" {
assert . NoError ( t , err )
assert . Equal ( t , tc . index , index )
assert . Equal ( t , tc . expected . UnixNano ( ) , actual . UnixNano ( ) )
} else {
assert . EqualError ( t , err , tc . err )
}
} )
}
}