Files
rclone/fs/parsetime_test.go
kevin dee8b7e285 fs: accept multi-unit relative times like 1d12h in Time options
The docs say Time options take the same relative forms as Duration
options, with "1d12h" as an example, but ParseTime only tried
time.ParseDuration and single-suffix values, so --max-age style
Time options such as --s3-version-at 1d12h were rejected.
2026-10-31 12:24:46 +00:00

181 lines
5.5 KiB
Go

package fs
import (
"encoding/json"
"fmt"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// Check it satisfies the interfaces
var (
_ Flagger = (*Time)(nil)
_ FlaggerNP = Time{}
)
func TestParseTime(t *testing.T) {
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 time.Time
err bool
}{
{"", time.Time{}, true},
{"1ms", now.Add(-time.Millisecond), false},
{"1s", now.Add(-time.Second), false},
{"1", now.Add(-time.Second), false},
{"1m", now.Add(-time.Minute), false},
{"1.5m", now.Add(-(3 * time.Minute) / 2), false},
{"1h", now.Add(-time.Hour), false},
{"1d", now.Add(-time.Hour * 24), false},
{"1w", now.Add(-time.Hour * 24 * 7), false},
{"1M", now.Add(-time.Hour * 24 * 30), false},
{"1y", now.Add(-time.Hour * 24 * 365), false},
{"1.5y", now.Add(-time.Hour * 24 * 365 * 3 / 2), false},
{"-1.5y", now.Add(time.Hour * 24 * 365 * 3 / 2), false},
{"-1s", now.Add(time.Second), false},
{"-1", now.Add(time.Second), false},
{"0", now, false},
{"100", now.Add(-100 * time.Second), false},
{"-100", now.Add(100 * time.Second), false},
{"1.s", now.Add(-time.Second), false},
{"1x", time.Time{}, true},
{"-1x", time.Time{}, true},
{"off", time.Time{}, false},
{"1h2m3s", now.Add(-(time.Hour + 2*time.Minute + 3*time.Second)), false},
{"1d12h", now.Add(-time.Hour * 36), false},
{"1w2d", now.Add(-time.Hour * 24 * 9), false},
{"2001-02-03", time.Date(2001, 2, 3, 0, 0, 0, 0, time.Local), false},
{"2001-02-03 10:11:12", time.Date(2001, 2, 3, 10, 11, 12, 0, time.Local), false},
{"2001-08-03 10:11:12", time.Date(2001, 8, 3, 10, 11, 12, 0, time.Local), false},
{"2001-02-03T10:11:12", time.Date(2001, 2, 3, 10, 11, 12, 0, time.Local), false},
{"2001-02-03T10:11:12.123Z", time.Date(2001, 2, 3, 10, 11, 12, 123000000, time.UTC), false},
{"2001-02-03T10:11:12.123+00:00", time.Date(2001, 2, 3, 10, 11, 12, 123000000, time.UTC), false},
} {
parsedTime, err := ParseTime(test.in)
if test.err {
require.Error(t, err, test.in)
} else {
require.NoError(t, err, test.in)
}
assert.True(t, test.want.Equal(parsedTime), "%v should be parsed as %v instead of %v", test.in, test.want, parsedTime)
}
}
func TestTimeString(t *testing.T) {
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 time.Time
want string
}{
{now, "2020-09-05T08:15:05.00000025Z"},
{time.Date(2021, 8, 5, 8, 15, 5, 0, time.UTC), "2021-08-05T08:15:05Z"},
{time.Time{}, "off"},
} {
got := Time(test.in).String()
assert.Equal(t, test.want, got)
// Test the reverse
reverse, err := ParseTime(test.want)
assert.NoError(t, err)
assert.Equal(t, test.in, reverse)
}
}
func TestTimeScan(t *testing.T) {
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 Time
}{
{"17m", Time(now.Add(-17 * time.Minute))},
{"-12h", Time(now.Add(12 * time.Hour))},
{"0", Time(now)},
{"off", Time(time.Time{})},
{"2022-03-26T17:48:19Z", Time(time.Date(2022, 03, 26, 17, 48, 19, 0, time.UTC))},
{"2022-03-26 17:48:19", Time(time.Date(2022, 03, 26, 17, 48, 19, 0, time.Local))},
} {
var got Time
n, err := fmt.Sscan(test.in, &got)
require.NoError(t, err)
assert.Equal(t, 1, n)
assert.Equal(t, test.want, got)
}
}
func TestParseTimeUnmarshalJSON(t *testing.T) {
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 time.Time
err bool
}{
{`""`, time.Time{}, true},
{"0", time.Time{}, true},
{"1", time.Time{}, true},
{"1", time.Time{}, true},
{`"2022-03-26T17:48:19Z"`, time.Date(2022, 03, 26, 17, 48, 19, 0, time.UTC), false},
{`"0"`, now, false},
{`"1ms"`, now.Add(-time.Millisecond), false},
{`"1s"`, now.Add(-time.Second), false},
{`"1"`, now.Add(-time.Second), false},
{`"1m"`, now.Add(-time.Minute), false},
{`"1h"`, now.Add(-time.Hour), false},
{`"-1h"`, now.Add(time.Hour), false},
{`"1d"`, now.Add(-time.Hour * 24), false},
{`"1w"`, now.Add(-time.Hour * 24 * 7), false},
{`"1M"`, now.Add(-time.Hour * 24 * 30), false},
{`"1y"`, now.Add(-time.Hour * 24 * 365), false},
{`"off"`, time.Time{}, false},
{`"error"`, time.Time{}, true},
{"error", time.Time{}, true},
} {
var parsedTime Time
err := json.Unmarshal([]byte(test.in), &parsedTime)
if test.err {
require.Error(t, err, test.in)
} else {
require.NoError(t, err, test.in)
}
assert.Equal(t, Time(test.want), parsedTime, test.in)
}
}
func TestParseTimeMarshalJSON(t *testing.T) {
for _, test := range []struct {
in time.Time
want string
err bool
}{
{time.Time{}, `"0001-01-01T00:00:00Z"`, false},
{time.Date(2022, 03, 26, 17, 48, 19, 0, time.UTC), `"2022-03-26T17:48:19Z"`, false},
} {
gotBytes, err := json.Marshal(test.in)
got := string(gotBytes)
if test.err {
require.Error(t, err, test.in)
} else {
require.NoError(t, err, test.in)
}
assert.Equal(t, test.want, got, test.in)
}
}