1 package opt
2
3 import (
4 "sort"
5 "testing"
6 "time"
7
8 gocmp "github.com/google/go-cmp/cmp"
9 "gotest.tools/v3/assert"
10 )
11
12 func TestDurationWithThreshold(t *testing.T) {
13 var testcases = []struct {
14 name string
15 x, y, threshold time.Duration
16 expected bool
17 }{
18 {
19 name: "delta is threshold",
20 threshold: time.Second,
21 x: 3 * time.Second,
22 y: 2 * time.Second,
23 expected: true,
24 },
25 {
26 name: "delta is negative threshold",
27 threshold: time.Second,
28 x: 2 * time.Second,
29 y: 3 * time.Second,
30 expected: true,
31 },
32 {
33 name: "delta within threshold",
34 threshold: time.Second,
35 x: 300 * time.Millisecond,
36 y: 100 * time.Millisecond,
37 expected: true,
38 },
39 {
40 name: "delta within negative threshold",
41 threshold: time.Second,
42 x: 100 * time.Millisecond,
43 y: 300 * time.Millisecond,
44 expected: true,
45 },
46 {
47 name: "delta outside threshold",
48 threshold: time.Second,
49 x: 5 * time.Second,
50 y: 300 * time.Millisecond,
51 },
52 {
53 name: "delta outside negative threshold",
54 threshold: time.Second,
55 x: 300 * time.Millisecond,
56 y: 5 * time.Second,
57 },
58 {
59 name: "x is 0",
60 threshold: time.Second,
61 y: 5 * time.Millisecond,
62 },
63 {
64 name: "y is 0",
65 threshold: time.Second,
66 x: 5 * time.Millisecond,
67 },
68 }
69 for _, testcase := range testcases {
70 t.Run(testcase.name, func(t *testing.T) {
71 actual := cmpDuration(testcase.threshold)(testcase.x, testcase.y)
72 assert.Equal(t, actual, testcase.expected)
73 })
74 }
75 }
76
77 func TestTimeWithThreshold(t *testing.T) {
78 var now = time.Now()
79
80 var testcases = []struct {
81 name string
82 x, y time.Time
83 threshold time.Duration
84 expected bool
85 }{
86 {
87 name: "delta is threshold",
88 threshold: time.Minute,
89 x: now,
90 y: now.Add(time.Minute),
91 expected: true,
92 },
93 {
94 name: "delta is negative threshold",
95 threshold: time.Minute,
96 x: now,
97 y: now.Add(-time.Minute),
98 expected: true,
99 },
100 {
101 name: "delta within threshold",
102 threshold: time.Hour,
103 x: now,
104 y: now.Add(time.Minute),
105 expected: true,
106 },
107 {
108 name: "delta within negative threshold",
109 threshold: time.Hour,
110 x: now,
111 y: now.Add(-time.Minute),
112 expected: true,
113 },
114 {
115 name: "delta outside threshold",
116 threshold: time.Second,
117 x: now,
118 y: now.Add(time.Minute),
119 },
120 {
121 name: "delta outside negative threshold",
122 threshold: time.Second,
123 x: now,
124 y: now.Add(-time.Minute),
125 },
126 {
127 name: "x is 0",
128 threshold: time.Second,
129 y: now,
130 },
131 {
132 name: "y is 0",
133 threshold: time.Second,
134 x: now,
135 },
136 }
137 for _, testcase := range testcases {
138 t.Run(testcase.name, func(t *testing.T) {
139 actual := cmpTime(testcase.threshold)(testcase.x, testcase.y)
140 assert.Equal(t, actual, testcase.expected)
141 })
142 }
143 }
144
145 type node struct {
146 Value nodeValue
147 Labels map[string]node
148 Children []node
149 Ref *node
150 }
151
152 type nodeValue struct {
153 Value int
154 }
155
156 type pathRecorder struct {
157 filter func(p gocmp.Path) bool
158 matches []string
159 }
160
161 func (p *pathRecorder) record(path gocmp.Path) bool {
162 if p.filter(path) {
163 p.matches = append(p.matches, path.GoString())
164 }
165 return false
166 }
167
168 func matchPaths(fixture interface{}, filter func(gocmp.Path) bool) []string {
169 rec := &pathRecorder{filter: filter}
170 gocmp.Equal(fixture, fixture, gocmp.FilterPath(rec.record, gocmp.Ignore()))
171 sort.Strings(rec.matches)
172 return rec.matches
173 }
174
175 func TestPathStringFromStruct(t *testing.T) {
176 fixture := node{
177 Ref: &node{
178 Children: []node{
179 {},
180 {
181 Labels: map[string]node{
182 "first": {Value: nodeValue{Value: 3}},
183 },
184 },
185 },
186 },
187 }
188
189 spec := "Ref.Children.Labels.Value"
190 matches := matchPaths(fixture, PathString(spec))
191 expected := []string{
192 `{opt.node}.Ref.Children[1].Labels["first"].Value`,
193 `{opt.node}.Ref.Children[1].Labels["first"].Value`,
194 }
195 assert.DeepEqual(t, matches, expected)
196 }
197
198 func TestPathStringFromSlice(t *testing.T) {
199 fixture := []node{
200 {
201 Ref: &node{
202 Children: []node{
203 {},
204 {
205 Labels: map[string]node{
206 "first": {},
207 "second": {
208 Ref: &node{Value: nodeValue{Value: 3}},
209 },
210 },
211 },
212 },
213 },
214 },
215 }
216
217 spec := "Ref.Children.Labels.Ref.Value"
218 matches := matchPaths(fixture, PathString(spec))
219 expected := []string{
220 `{[]opt.node}[0].Ref.Children[1].Labels["second"].Ref.Value`,
221 `{[]opt.node}[0].Ref.Children[1].Labels["second"].Ref.Value`,
222 `{[]opt.node}[0].Ref.Children[1].Labels["second"].Ref.Value`,
223 `{[]opt.node}[0].Ref.Children[1].Labels["second"].Ref.Value`,
224 }
225 assert.DeepEqual(t, matches, expected)
226 }
227
228 func TestPathField(t *testing.T) {
229 fixture := node{
230 Value: nodeValue{Value: 3},
231 Children: []node{
232 {},
233 {Value: nodeValue{Value: 2}},
234 {Ref: &node{Value: nodeValue{Value: 9}}},
235 },
236 }
237
238 filter := PathField(nodeValue{}, "Value")
239 matches := matchPaths(fixture, filter)
240 expected := []string{
241 "{opt.node}.Children[0].Value.Value",
242 "{opt.node}.Children[0].Value.Value",
243 "{opt.node}.Children[1].Value.Value",
244 "{opt.node}.Children[1].Value.Value",
245 "{opt.node}.Children[2].Ref.Value.Value",
246 "{opt.node}.Children[2].Ref.Value.Value",
247 "{opt.node}.Children[2].Value.Value",
248 "{opt.node}.Children[2].Value.Value",
249 "{opt.node}.Value.Value",
250 }
251 assert.DeepEqual(t, matches, expected)
252 }
253
254 func TestPathDebug(t *testing.T) {
255 fixture := node{
256 Value: nodeValue{Value: 3},
257 Children: []node{
258 {Ref: &node{Value: nodeValue{Value: 9}}},
259 },
260 Labels: map[string]node{
261 "label1": {},
262 },
263 }
264 assert.Check(t, gocmp.Equal(fixture, fixture, gocmp.FilterPath(PathDebug, gocmp.Ignore())))
265 }
266
View as plain text