1
2
3
4
5 package liveness
6
7 import (
8 "flag"
9 "fmt"
10 "math/rand"
11 "os"
12 "sort"
13 "testing"
14 )
15
16 func TestMain(m *testing.M) {
17 flag.Parse()
18 os.Exit(m.Run())
19 }
20
21 func TestMakeAndPrint(t *testing.T) {
22 testcases := []struct {
23 inp []int
24 exp string
25 err bool
26 }{
27 {
28 inp: []int{0, 1, 2, 3},
29 exp: "[0,1) [2,3)",
30 },
31 {
32 inp: []int{0, 1, 1, 2},
33 exp: "[0,1) [1,2)",
34 },
35 {
36 inp: []int{0},
37 err: true,
38 exp: "odd number of elems 1",
39 },
40 {
41
42 inp: []int{0, 0},
43 err: true,
44 exp: "bad range elem 0:0, en<=st",
45 },
46 {
47
48 inp: []int{0, 9, 3, 12},
49 err: true,
50 exp: "bad range elem 3:12 overlaps prev 0:9",
51 },
52 {
53
54 inp: []int{10, 11, 3, 4},
55 err: true,
56 exp: "range start not ordered 3:4 less than prev 10:11",
57 },
58 }
59
60 for k, tc := range testcases {
61 is, err := makeIntervals(tc.inp...)
62 want := tc.exp
63 if err != nil {
64 if !tc.err {
65 t.Fatalf("unexpected error on tc:%d %+v -> %v", k, tc.inp, err)
66 } else {
67 got := fmt.Sprintf("%v", err)
68 if got != want {
69 t.Fatalf("bad error on tc:%d %+v got %q want %q", k, tc.inp, got, want)
70 }
71 }
72 continue
73 } else if tc.err {
74 t.Fatalf("missing error on tc:%d %+v return was %q", k, tc.inp, is.String())
75 }
76 got := is.String()
77 if got != want {
78 t.Fatalf("exp mismatch on tc:%d %+v got %q want %q", k, tc.inp, got, want)
79 }
80 }
81 }
82
83 func TestIntervalOverlap(t *testing.T) {
84 testcases := []struct {
85 i1, i2 Interval
86 exp bool
87 }{
88 {
89 i1: Interval{st: 0, en: 1},
90 i2: Interval{st: 0, en: 1},
91 exp: true,
92 },
93 {
94 i1: Interval{st: 0, en: 1},
95 i2: Interval{st: 1, en: 2},
96 exp: false,
97 },
98 {
99 i1: Interval{st: 9, en: 10},
100 i2: Interval{st: 1, en: 2},
101 exp: false,
102 },
103 {
104 i1: Interval{st: 0, en: 10},
105 i2: Interval{st: 5, en: 6},
106 exp: true,
107 },
108 }
109
110 for _, tc := range testcases {
111 want := tc.exp
112 got := tc.i1.Overlaps(tc.i2)
113 if want != got {
114 t.Fatalf("Overlaps([%d,%d), [%d,%d)): got %v want %v",
115 tc.i1.st, tc.i1.en, tc.i2.st, tc.i2.en, got, want)
116 }
117 }
118 }
119
120 func TestIntervalAdjacent(t *testing.T) {
121 testcases := []struct {
122 i1, i2 Interval
123 exp bool
124 }{
125 {
126 i1: Interval{st: 0, en: 1},
127 i2: Interval{st: 0, en: 1},
128 exp: false,
129 },
130 {
131 i1: Interval{st: 0, en: 1},
132 i2: Interval{st: 1, en: 2},
133 exp: true,
134 },
135 {
136 i1: Interval{st: 1, en: 2},
137 i2: Interval{st: 0, en: 1},
138 exp: true,
139 },
140 {
141 i1: Interval{st: 0, en: 10},
142 i2: Interval{st: 0, en: 3},
143 exp: false,
144 },
145 }
146
147 for k, tc := range testcases {
148 want := tc.exp
149 got := tc.i1.adjacent(tc.i2)
150 if want != got {
151 t.Fatalf("tc=%d adjacent([%d,%d), [%d,%d)): got %v want %v",
152 k, tc.i1.st, tc.i1.en, tc.i2.st, tc.i2.en, got, want)
153 }
154 }
155 }
156
157 func TestIntervalMerge(t *testing.T) {
158 testcases := []struct {
159 i1, i2 Interval
160 exp Interval
161 err bool
162 }{
163 {
164
165 i1: Interval{st: 0, en: 1},
166 i2: Interval{st: 2, en: 3},
167 err: true,
168 },
169 {
170
171 i1: Interval{st: 0, en: 1},
172 i2: Interval{st: 0, en: 1},
173 exp: Interval{st: 0, en: 1},
174 err: false,
175 },
176 {
177
178 i1: Interval{st: 0, en: 1},
179 i2: Interval{st: 1, en: 2},
180 exp: Interval{st: 0, en: 2},
181 err: false,
182 },
183 {
184
185 i1: Interval{st: 0, en: 5},
186 i2: Interval{st: 3, en: 10},
187 exp: Interval{st: 0, en: 10},
188 err: false,
189 },
190 {
191
192 i1: Interval{st: 9, en: 15},
193 i2: Interval{st: 3, en: 11},
194 exp: Interval{st: 3, en: 15},
195 err: false,
196 },
197 }
198
199 for k, tc := range testcases {
200 var dst Interval
201 dstp := &dst
202 dst = tc.i1
203 err := dstp.MergeInto(tc.i2)
204 if (err != nil) != tc.err {
205 t.Fatalf("tc=%d MergeInto([%d,%d) <= [%d,%d)): got err=%v want err=%v", k, tc.i1.st, tc.i1.en, tc.i2.st, tc.i2.en, err, tc.err)
206 }
207 if err != nil {
208 continue
209 }
210 want := tc.exp.String()
211 got := dst.String()
212 if want != got {
213 t.Fatalf("tc=%d MergeInto([%d,%d) <= [%d,%d)): got %v want %v",
214 k, tc.i1.st, tc.i1.en, tc.i2.st, tc.i2.en, got, want)
215 }
216 }
217 }
218
219 func TestIntervalsOverlap(t *testing.T) {
220 testcases := []struct {
221 inp1, inp2 []int
222 exp bool
223 }{
224 {
225
226 inp1: []int{},
227 inp2: []int{1, 2},
228 exp: false,
229 },
230 {
231
232 inp1: []int{9, 10},
233 inp2: []int{},
234 exp: false,
235 },
236 {
237
238 inp1: []int{1, 2},
239 inp2: []int{2, 3},
240 exp: false,
241 },
242 {
243
244 inp1: []int{2, 3},
245 inp2: []int{1, 2},
246 exp: false,
247 },
248 {
249
250 inp1: []int{1, 2, 3, 4},
251 inp2: []int{2, 3, 5, 6},
252 exp: false,
253 },
254 {
255
256 inp1: []int{2, 3, 5, 6},
257 inp2: []int{1, 2, 3, 4},
258 exp: false,
259 },
260 {
261
262 inp1: []int{1, 3},
263 inp2: []int{2, 9, 10, 11},
264 exp: true,
265 },
266 {
267
268 inp1: []int{18, 29},
269 inp2: []int{2, 9, 10, 19},
270 exp: true,
271 },
272 }
273
274 for k, tc := range testcases {
275 is1, err1 := makeIntervals(tc.inp1...)
276 if err1 != nil {
277 t.Fatalf("unexpected error on tc:%d %+v: %v", k, tc.inp1, err1)
278 }
279 is2, err2 := makeIntervals(tc.inp2...)
280 if err2 != nil {
281 t.Fatalf("unexpected error on tc:%d %+v: %v", k, tc.inp2, err2)
282 }
283 got := is1.Overlaps(is2)
284 want := tc.exp
285 if got != want {
286 t.Fatalf("overlaps mismatch on tc:%d %+v %+v got %v want %v", k, tc.inp1, tc.inp2, got, want)
287 }
288 }
289 }
290
291 var seedflag = flag.Int64("seed", 101, "Random seed")
292 var trialsflag = flag.Int64("trials", 10000, "Number of trials")
293 var segsflag = flag.Int64("segs", 4, "Max segments within interval")
294 var limitflag = flag.Int64("limit", 20, "Limit of interval max end")
295
296
297
298
299 func TestRandomIntervalsOverlap(t *testing.T) {
300 rand.Seed(*seedflag)
301
302
303
304 mk := func() Intervals {
305 vals := rand.Perm(int(*limitflag))
306
307 segs := rand.Intn(int(*segsflag))
308 picked := vals[:(segs * 2)]
309 sort.Ints(picked)
310 ii, err := makeIntervals(picked...)
311 if err != nil {
312 t.Fatalf("makeIntervals(%+v) returns err %v", picked, err)
313 }
314 return ii
315 }
316
317 brute := func(i1, i2 Intervals) bool {
318 for i := range i1 {
319 for j := range i2 {
320 if i1[i].Overlaps(i2[j]) {
321 return true
322 }
323 }
324 }
325 return false
326 }
327
328 for k := range *trialsflag {
329
330
331 i1, i2 := mk(), mk()
332 got := i1.Overlaps(i2)
333 want := brute(i1, i2)
334 if got != want {
335 t.Fatalf("overlap mismatch on t:%d %v %v got %v want %v",
336 k, i1, i2, got, want)
337 }
338 }
339 }
340
341 func TestIntervalsMerge(t *testing.T) {
342 testcases := []struct {
343 inp1, inp2 []int
344 exp []int
345 }{
346 {
347
348 inp1: []int{},
349 inp2: []int{1, 2},
350 exp: []int{1, 2},
351 },
352 {
353
354 inp1: []int{1, 2},
355 inp2: []int{},
356 exp: []int{1, 2},
357 },
358 {
359
360 inp1: []int{1, 2},
361 inp2: []int{2, 3},
362 exp: []int{1, 3},
363 },
364 {
365
366 inp1: []int{1, 5},
367 inp2: []int{2, 10},
368 exp: []int{1, 10},
369 },
370 {
371
372 inp1: []int{1, 2},
373 inp2: []int{11, 12},
374 exp: []int{1, 2, 11, 12},
375 },
376 {
377
378 inp1: []int{1, 2, 3, 4, 5, 6},
379 inp2: []int{2, 3, 4, 5, 6, 7},
380 exp: []int{1, 7},
381 },
382 }
383
384 for k, tc := range testcases {
385 is1, err1 := makeIntervals(tc.inp1...)
386 if err1 != nil {
387 t.Fatalf("unexpected error on tc:%d %+v: %v", k, tc.inp1, err1)
388 }
389 is2, err2 := makeIntervals(tc.inp2...)
390 if err2 != nil {
391 t.Fatalf("unexpected error on tc:%d %+v: %v", k, tc.inp2, err2)
392 }
393 m := is1.Merge(is2)
394 wis, werr := makeIntervals(tc.exp...)
395 if werr != nil {
396 t.Fatalf("unexpected error on tc:%d %+v: %v", k, tc.exp, werr)
397 }
398 want := wis.String()
399 got := m.String()
400 if want != got {
401 t.Fatalf("k=%d Merge(%s, %s): got %v want %v",
402 k, is1, is2, m, want)
403 }
404 }
405 }
406
407 func TestBuilder(t *testing.T) {
408 type posLiveKill struct {
409 pos int
410 becomesLive, isKill bool
411 }
412 testcases := []struct {
413 inp []posLiveKill
414 exp []int
415 aerr, ferr bool
416 }{
417
418 {
419 inp: []posLiveKill{
420 posLiveKill{pos: 10, becomesLive: true},
421 posLiveKill{pos: 18, isKill: true},
422 },
423 aerr: true,
424 },
425
426 {
427 inp: []posLiveKill{
428 posLiveKill{pos: -1, becomesLive: true},
429 },
430 aerr: true,
431 },
432
433 {
434 exp: nil,
435 },
436
437 {
438 inp: []posLiveKill{
439 posLiveKill{pos: 10, becomesLive: true},
440 posLiveKill{pos: 9, isKill: true},
441 },
442 exp: []int{10, 11},
443 },
444
445 {
446 inp: []posLiveKill{
447 posLiveKill{pos: 11, becomesLive: true},
448 posLiveKill{pos: 10, becomesLive: true},
449 posLiveKill{pos: 9, isKill: true},
450 posLiveKill{pos: 4, becomesLive: true},
451 posLiveKill{pos: 1, isKill: true},
452 },
453 exp: []int{2, 5, 10, 12},
454 },
455
456 {
457 inp: []posLiveKill{
458 posLiveKill{pos: 20, isKill: true},
459 posLiveKill{pos: 19, isKill: true},
460 posLiveKill{pos: 17, becomesLive: true},
461 posLiveKill{pos: 14, becomesLive: true},
462 posLiveKill{pos: 10, isKill: true},
463 posLiveKill{pos: 4, becomesLive: true},
464 posLiveKill{pos: 0, isKill: true},
465 },
466 exp: []int{1, 5, 11, 18},
467 },
468 }
469
470 for k, tc := range testcases {
471 var c IntervalsBuilder
472 var aerr error
473 for _, event := range tc.inp {
474 if event.becomesLive {
475 if err := c.Live(event.pos); err != nil {
476 aerr = err
477 break
478 }
479 }
480 if event.isKill {
481 if err := c.Kill(event.pos); err != nil {
482 aerr = err
483 break
484 }
485 }
486 }
487 if (aerr != nil) != tc.aerr {
488 t.Fatalf("k=%d add err mismatch: tc.aerr:%v aerr!=nil:%v",
489 k, tc.aerr, (aerr != nil))
490 }
491 if tc.aerr {
492 continue
493 }
494 ii, ferr := c.Finish()
495 if ferr != nil {
496 if tc.ferr {
497 continue
498 }
499 t.Fatalf("h=%d finish err mismatch: tc.ferr:%v ferr!=nil:%v", k, tc.ferr, ferr != nil)
500 }
501 got := ii.String()
502 wis, werr := makeIntervals(tc.exp...)
503 if werr != nil {
504 t.Fatalf("unexpected error on tc:%d %+v: %v", k, tc.exp, werr)
505 }
506 want := wis.String()
507 if want != got {
508 t.Fatalf("k=%d Ctor test: got %v want %v", k, got, want)
509 }
510 }
511 }
512
513
514
515
516 func makeIntervals(nums ...int) (Intervals, error) {
517 var r Intervals
518 if len(nums)&1 != 0 {
519 return r, fmt.Errorf("odd number of elems %d", len(nums))
520 }
521 for i := 0; i < len(nums); i += 2 {
522 st := nums[i]
523 en := nums[i+1]
524 r = append(r, Interval{st: st, en: en})
525 }
526 return r, check(r)
527 }
528
View as plain text