Skip to content

Commit f691a74

Browse files
committed
feat: support days/weeks in serpent.Duration
Signed-off-by: Danny Kopping <[email protected]>
1 parent 659f3c4 commit f691a74

File tree

4 files changed

+157
-1
lines changed

4 files changed

+157
-1
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/pion/udp v0.1.4
1414
github.com/spf13/pflag v1.0.5
1515
github.com/stretchr/testify v1.8.4
16+
github.com/xhit/go-str2duration/v2 v2.1.0
1617
golang.org/x/crypto v0.19.0
1718
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
1819
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
8181
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
8282
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
8383
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
84+
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
85+
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
8486
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
8587
go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
8688
go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=

values.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"time"
1414

1515
"github.com/spf13/pflag"
16+
str2duration "github.com/xhit/go-str2duration/v2"
1617
"golang.org/x/xerrors"
1718
"gopkg.in/yaml.v3"
1819
)
@@ -262,7 +263,16 @@ func DurationOf(d *time.Duration) *Duration {
262263
}
263264

264265
func (d *Duration) Set(v string) error {
265-
dd, err := time.ParseDuration(v)
266+
// Try [str2duration.ParseDuration] first, which supports days and weeks.
267+
// If it fails, fall back to [time.ParseDuration] for backward compatibility.
268+
dd, err := str2duration.ParseDuration(v)
269+
if err == nil {
270+
*d = Duration(dd)
271+
return nil
272+
}
273+
274+
// Fallback to standard [time.ParseDuration].
275+
dd, err = time.ParseDuration(v)
266276
*d = Duration(dd)
267277
return err
268278
}

values_test.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package serpent_test
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/stretchr/testify/require"
8+
9+
serpent "github.com/coder/serpent"
10+
)
11+
12+
func TestDuration(t *testing.T) {
13+
t.Parallel()
14+
15+
tests := []struct {
16+
name string
17+
input string
18+
expected time.Duration
19+
wantErr bool
20+
}{
21+
// Standard time.Duration formats (should still work)
22+
{
23+
name: "Nanoseconds",
24+
input: "100ns",
25+
expected: 100 * time.Nanosecond,
26+
},
27+
{
28+
name: "Microseconds",
29+
input: "100us",
30+
expected: 100 * time.Microsecond,
31+
},
32+
{
33+
name: "Milliseconds",
34+
input: "100ms",
35+
expected: 100 * time.Millisecond,
36+
},
37+
{
38+
name: "Seconds",
39+
input: "30s",
40+
expected: 30 * time.Second,
41+
},
42+
{
43+
name: "Minutes",
44+
input: "5m",
45+
expected: 5 * time.Minute,
46+
},
47+
{
48+
name: "Hours",
49+
input: "2h",
50+
expected: 2 * time.Hour,
51+
},
52+
{
53+
name: "Combined",
54+
input: "1h30m",
55+
expected: 90 * time.Minute,
56+
},
57+
// New formats with days and weeks support
58+
{
59+
name: "Days",
60+
input: "1d",
61+
expected: 24 * time.Hour,
62+
},
63+
{
64+
name: "MultipleDays",
65+
input: "7d",
66+
expected: 7 * 24 * time.Hour,
67+
},
68+
{
69+
name: "Weeks",
70+
input: "1w",
71+
expected: 7 * 24 * time.Hour,
72+
},
73+
{
74+
name: "MultipleWeeks",
75+
input: "2w",
76+
expected: 14 * 24 * time.Hour,
77+
},
78+
{
79+
name: "CombinedWithDays",
80+
input: "1d12h",
81+
expected: 36 * time.Hour,
82+
},
83+
{
84+
name: "CombinedWithWeeks",
85+
input: "1w2d",
86+
expected: (7 + 2) * 24 * time.Hour,
87+
},
88+
{
89+
name: "ComplexCombination",
90+
input: "2w3d4h5m6s",
91+
expected: (14 + 3) * 24 * time.Hour + 4*time.Hour + 5*time.Minute + 6*time.Second,
92+
},
93+
// Error cases
94+
{
95+
name: "Invalid",
96+
input: "invalid",
97+
wantErr: true,
98+
},
99+
{
100+
name: "Empty",
101+
input: "",
102+
wantErr: true,
103+
},
104+
}
105+
106+
for _, tt := range tests {
107+
t.Run(tt.name, func(t *testing.T) {
108+
t.Parallel()
109+
110+
var d serpent.Duration
111+
err := d.Set(tt.input)
112+
113+
if tt.wantErr {
114+
require.Error(t, err)
115+
return
116+
}
117+
118+
require.NoError(t, err)
119+
require.Equal(t, tt.expected, d.Value())
120+
121+
// Verify String() returns a parseable value
122+
str := d.String()
123+
var d2 serpent.Duration
124+
err = d2.Set(str)
125+
require.NoError(t, err)
126+
require.Equal(t, d.Value(), d2.Value(), "String() should return a parseable value")
127+
})
128+
}
129+
}
130+
131+
func TestDurationOf(t *testing.T) {
132+
t.Parallel()
133+
134+
td := 5 * time.Minute
135+
d := serpent.DurationOf(&td)
136+
require.NotNil(t, d)
137+
require.Equal(t, td, d.Value())
138+
139+
// Test modification through pointer
140+
newVal := 10 * time.Minute
141+
*d = serpent.Duration(newVal)
142+
require.Equal(t, newVal, time.Duration(td))
143+
}

0 commit comments

Comments
 (0)