• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2018 The Wuffs Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package interval
16
17import (
18	"fmt"
19	"math/big"
20	"math/rand"
21	"sort"
22	"strconv"
23	"strings"
24	"testing"
25)
26
27// TestMotivatingExample tests the "motivating example" given in the package
28// doc comment.
29func TestMotivatingExample(tt *testing.T) {
30	i := IntRange{big.NewInt(0), big.NewInt(255)}
31	j := IntRange{big.NewInt(0), big.NewInt(3)}
32	four := IntRange{big.NewInt(4), big.NewInt(4)}
33	got := four.Mul(i).Add(j)
34	want := IntRange{big.NewInt(0), big.NewInt(1023)}
35	if !got.Eq(want) {
36		tt.Fatalf("got %v, want %v", got, want)
37	}
38}
39
40func TestBigIntShifts(tt *testing.T) {
41	// These alternative implementations always take the fallback code path of
42	// bigIntLsh and bigIntRsh. This test checks that those fallback paths give
43	// the same results as *big.Int's Lsh and Rsh methods. There are fallback
44	// and non-fallback code paths in interval.go because those *big.Int
45	// methods aren't applicable if j's value doesn't fit in a uint.
46
47	alternativeBigIntLsh := func(i *big.Int, j *big.Int) *big.Int {
48		// Fallback code path, copy-pasted from interval.go.
49		k := big.NewInt(2)
50		k.Exp(k, j, nil)
51		k.Mul(i, k)
52		return k
53	}
54
55	alternativeBigIntRsh := func(i *big.Int, j *big.Int) *big.Int {
56		// Fallback code path, copy-pasted from interval.go.
57		k := big.NewInt(2)
58		k.Exp(k, j, nil)
59		k.Div(i, k) // This is explicitly Div, not Quo.
60		return k
61	}
62
63	xs := []*big.Int{
64		big.NewInt(-9),
65		big.NewInt(-8),
66		big.NewInt(-7),
67
68		big.NewInt(-2),
69		big.NewInt(-1),
70		big.NewInt(+0),
71		big.NewInt(+1),
72		big.NewInt(+2),
73
74		big.NewInt(+7),
75		big.NewInt(+8),
76		big.NewInt(+9),
77	}
78
79	ys := []*big.Int{
80		big.NewInt(+0),
81		big.NewInt(+1),
82		big.NewInt(+2),
83		big.NewInt(+3),
84		big.NewInt(+4),
85	}
86
87	for _, x := range xs {
88		for _, y := range ys {
89			{
90				got := bigIntLsh(x, y)
91				want := alternativeBigIntLsh(x, y)
92				if got.Cmp(want) != 0 {
93					tt.Errorf("%v << %v: got %v, want %v", x, y, got, want)
94				}
95			}
96
97			{
98				got := bigIntRsh(x, y)
99				want := alternativeBigIntRsh(x, y)
100				if got.Cmp(want) != 0 {
101					tt.Errorf("%v >> %v: got %v, want %v", x, y, got, want)
102				}
103			}
104		}
105	}
106}
107
108func trimLeadingSpaces(s string) string {
109	for ; len(s) > 0 && s[0] == ' '; s = s[1:] {
110	}
111	return s
112}
113
114func trimTrailingSpaces(s string) string {
115	for ; len(s) > 0 && s[len(s)-1] == ' '; s = s[:len(s)-1] {
116	}
117	return s
118}
119
120func parseInt(s string) (x *big.Int, remaining string, err error) {
121	s = trimLeadingSpaces(s)
122	i := 0
123	for ; i < len(s); i++ {
124		if c := s[i]; c == ')' || c == ',' || c == ']' {
125			break
126		}
127	}
128	s, remaining = trimTrailingSpaces(s[:i]), s[i:]
129	switch s {
130	case "-∞", "+∞":
131		// No-op.
132	default:
133		n, err := strconv.Atoi(s)
134		if err != nil {
135			return nil, "", fmt.Errorf("parseInt(%q): %v", s, err)
136		}
137		x = big.NewInt(int64(n))
138	}
139	return x, remaining, nil
140}
141
142// parseInterval parses a string like "[-3, +4] etcetera", returning the
143// interval itself and the remaining string " etcetera".
144//
145// It also parses infinite (unbounded) intervals like "[0, +∞)", and the
146// special syntax "[...empty..]" for an empty interval (one that contains no
147// elements).
148func parseInterval(s string) (x IntRange, remaining string, err error) {
149	const emptySyntax = "[...empty..]"
150	s = trimLeadingSpaces(s)
151	if strings.HasPrefix(s, emptySyntax) {
152		s = s[len(emptySyntax):]
153		return IntRange{big.NewInt(+1), big.NewInt(-1)}, s, nil
154	}
155
156	if s[0] != '(' && s[0] != '[' {
157		return IntRange{}, "", fmt.Errorf("expected '(' or '['")
158	}
159	s = s[1:]
160	x0, s, err := parseInt(s)
161	if err != nil {
162		return IntRange{}, "", err
163	}
164	if s[0] != ',' {
165		return IntRange{}, "", fmt.Errorf("expected ','")
166	}
167	s = s[1:]
168	x1, s, err := parseInt(s)
169	if err != nil {
170		return IntRange{}, "", err
171	}
172	if s[0] != ')' && s[0] != ']' {
173		return IntRange{}, "", fmt.Errorf("expected ')' or ']'")
174	}
175	s = s[1:]
176	if x0 != nil && x1 != nil && x0.Cmp(x1) > 0 {
177		return IntRange{}, "", fmt.Errorf("invalid empty interval")
178	}
179	return IntRange{x0, x1}, s, nil
180}
181
182func TestContainsEtc(tt *testing.T) {
183	testCases := []struct {
184		s  string
185		cn uint32
186		cz uint32
187		cp uint32
188	}{
189		{"<empty-->", 0, 0, 0},
190		{"<empty0->", 0, 0, 0},
191		{"<empty+->", 0, 0, 0},
192		{"<empty+0>", 0, 0, 0},
193		{"<empty++>", 0, 0, 0},
194
195		{"(-∞, -1]", 1, 0, 0},
196		{"(-∞,  0]", 1, 1, 0},
197		{"(-∞, +1]", 1, 1, 1},
198		{"(-∞, +∞)", 1, 1, 1},
199
200		{"[-1, -1]", 1, 0, 0},
201		{"[-1,  0]", 1, 1, 0},
202		{"[-1, +1]", 1, 1, 1},
203		{"[-1, +∞)", 1, 1, 1},
204
205		{"[ 0,  0]", 0, 1, 0},
206		{"[ 0, +1]", 0, 1, 1},
207		{"[ 0, +∞)", 0, 1, 1},
208
209		{"[+1, +1]", 0, 0, 1},
210		{"[+1, +∞)", 0, 0, 1},
211	}
212
213	// eqTestCases is appended to throughout the "range testCases" loop, but it
214	// always contains exactly one empty IntRange.
215	eqTestCases := []IntRange{
216		empty(),
217	}
218
219	for _, tc := range testCases {
220		x := IntRange{}
221		switch tc.s {
222		case "<empty-->":
223			x = IntRange{big.NewInt(-1), big.NewInt(-2)}
224		case "<empty0->":
225			x = IntRange{big.NewInt(00), big.NewInt(-2)}
226		case "<empty+->":
227			x = IntRange{big.NewInt(+2), big.NewInt(-2)}
228		case "<empty+0>":
229			x = IntRange{big.NewInt(+2), big.NewInt(00)}
230		case "<empty++>":
231			x = IntRange{big.NewInt(+2), big.NewInt(+1)}
232		default:
233			err := error(nil)
234			x, _, err = parseInterval(tc.s)
235			if err != nil {
236				tt.Errorf("%s: %v", tc.s, err)
237				continue
238			}
239		}
240
241		if got, want := x.ContainsNegative(), tc.cn != 0; got != want {
242			tt.Errorf("%s.ContainsNegative(): got %t, want %t", tc.s, got, want)
243		}
244		if got, want := x.ContainsZero(), tc.cz != 0; got != want {
245			tt.Errorf("%s.ContainsZero(): got %t, want %t", tc.s, got, want)
246		}
247		if got, want := x.ContainsPositive(), tc.cp != 0; got != want {
248			tt.Errorf("%s.ContainsPositive(): got %t, want %t", tc.s, got, want)
249		}
250
251		if got, want := x.Empty(), strings.Contains(tc.s, "empty"); got != want {
252			tt.Errorf("%s.Empty(): got %t, want %t", tc.s, got, want)
253		} else if !got {
254			eqTestCases = append(eqTestCases, x)
255		} else if !x.Eq(empty()) {
256			tt.Errorf("%v eq %v: got %t, want %t", x, empty(), got, want)
257		}
258
259		if got, want := x.justZero(), tc.s == "[ 0,  0]"; got != want {
260			tt.Errorf("%s.justZero(): got %t, want %t", tc.s, got, want)
261		}
262	}
263
264	for i, x := range eqTestCases {
265		for j, y := range eqTestCases {
266			got := x.Eq(y)
267			want := i == j
268			if got != want {
269				tt.Errorf("%v eq %v: got %t, want %t", x, y, got, want)
270			}
271		}
272	}
273
274	for _, x := range eqTestCases {
275		neg, pos, negEmpty, hasZero, posEmpty := x.split()
276		if got, want := neg.Empty(), negEmpty; got != want {
277			tt.Errorf("%v: neg.Empty() == %t, negEmpty == %t", x, got, want)
278		}
279		if got, want := !x.ContainsNegative(), negEmpty; got != want {
280			tt.Errorf("%v: !x.ContainsNegative() == %t, negEmpty == %t", x, got, want)
281		}
282		if got, want := x.ContainsZero(), hasZero; got != want {
283			tt.Errorf("%v: x.ContainsZero() == %t, hasZero == %t", x, got, want)
284		}
285		if got, want := !x.ContainsPositive(), posEmpty; got != want {
286			tt.Errorf("%v: !x.ContainsPositive() == %t, posEmpty == %t", x, got, want)
287		}
288		if got, want := pos.Empty(), posEmpty; got != want {
289			tt.Errorf("%v: pos.Empty() == %t, posEmpty == %t", x, got, want)
290		}
291	}
292}
293
294func testBruteForceAgrees(x IntRange, y IntRange, opKey string) error {
295	brute, bruteOK := bruteForce(x, y, opKey)
296	got, gotOK := intOperators[opKey](x, y)
297	if !got.Eq(brute) || gotOK != bruteOK {
298		return fmt.Errorf("got %v, %t, brute force gave %v, %t", got, gotOK, brute, bruteOK)
299	}
300	return nil
301}
302
303func TestBruteForceAgreesSystematically(tt *testing.T) {
304	ints := []*big.Int{
305		big.NewInt(-7),
306		big.NewInt(-6),
307		big.NewInt(-5),
308		big.NewInt(-4),
309		big.NewInt(-3),
310		big.NewInt(-2),
311		big.NewInt(-1),
312		big.NewInt(+0),
313		big.NewInt(+1),
314		big.NewInt(+2),
315		big.NewInt(+3),
316		big.NewInt(+4),
317		big.NewInt(+5),
318		big.NewInt(+6),
319		big.NewInt(+7),
320		nil,
321	}
322
323	for _, opKey := range intOperatorsKeys {
324
325		for _, x0 := range ints {
326			for _, x1 := range ints {
327				x := IntRange{x0, x1}
328
329				for _, y0 := range ints {
330					for _, y1 := range ints {
331						y := IntRange{y0, y1}
332
333						if err := testBruteForceAgrees(x, y, opKey); err != nil {
334							tt.Fatalf("%v %s %v: %v", x, opKey, y, err)
335						}
336					}
337				}
338			}
339		}
340	}
341}
342
343func TestBruteForceAgreesRandomly(tt *testing.T) {
344	gen := func(rng *rand.Rand) *big.Int {
345		r := rng.Intn(2*riRadius+2) - (riRadius + 1)
346		if r == -(riRadius + 1) {
347			return nil
348		}
349		return big.NewInt(int64(r))
350	}
351
352	rng := rand.New(rand.NewSource(0))
353	for _, opKey := range intOperatorsKeys {
354		for i := 0; i < 10000; i++ {
355			x := IntRange{gen(rng), gen(rng)}
356			y := IntRange{gen(rng), gen(rng)}
357			if err := testBruteForceAgrees(x, y, opKey); err != nil {
358				tt.Fatalf("%v %s %v: %v", x, opKey, y, err)
359			}
360		}
361	}
362}
363
364func testOp(tt *testing.T, testCases ...string) {
365	for _, tc := range testCases {
366		if err := testOp1(tc); err != nil {
367			tt.Errorf("%q: %v", tc, err)
368		}
369	}
370}
371
372func testOp1(s string) error {
373	x, s, err := parseInterval(s)
374	if err != nil {
375		return err
376	}
377	s = trimLeadingSpaces(s)
378
379	i := 0
380	for ; i < len(s) && s[i] != ' '; i++ {
381	}
382	opKey, s := s[:i], s[i:]
383
384	y, s, err := parseInterval(s)
385	if err != nil {
386		return err
387	}
388	s = trimLeadingSpaces(s)
389	if !strings.HasPrefix(s, "==") {
390		return fmt.Errorf(`expected "=="`)
391	}
392	s = s[2:]
393	s = trimLeadingSpaces(s)
394	want, wantOK := IntRange{}, false
395	if s == "invalid" {
396		s = ""
397	} else {
398		wantOK = true
399		want, s, err = parseInterval(s)
400		if err != nil {
401			return err
402		}
403		s = trimLeadingSpaces(s)
404		if s != "" {
405			return fmt.Errorf("trailing specification %q", s)
406		}
407	}
408
409	if err := testBruteForceAgrees(x, y, opKey); err != nil {
410		return err
411	}
412
413	got, gotOK := intOperators[opKey](x, y)
414	if !got.Eq(want) || gotOK != wantOK {
415		return fmt.Errorf("package code: got %v, %t, want %v, %t", got, gotOK, want, wantOK)
416	}
417	return nil
418}
419
420var intOperators = map[string]func(IntRange, IntRange) (IntRange, bool){
421	"+":  func(x IntRange, y IntRange) (z IntRange, ok bool) { return x.Add(y), true },
422	"-":  func(x IntRange, y IntRange) (z IntRange, ok bool) { return x.Sub(y), true },
423	"*":  func(x IntRange, y IntRange) (z IntRange, ok bool) { return x.Mul(y), true },
424	"/":  IntRange.Quo,
425	"<<": IntRange.Lsh,
426	">>": IntRange.Rsh,
427	"&":  IntRange.And,
428	"|":  IntRange.Or,
429}
430
431var intOperatorsKeys []string
432
433func init() {
434	for k := range intOperators {
435		intOperatorsKeys = append(intOperatorsKeys, k)
436	}
437	sort.Strings(intOperatorsKeys)
438}
439
440func TestOpAdd(tt *testing.T) {
441	testOp(tt,
442		"[   3,    3]   +  [  -5,   -5]  ==  [  -2,   -2]",
443		"[   3,    3]   +  [   0,    0]  ==  [   3,    3]",
444		"[   0,    0]   +  [  -7,    7]  ==  [  -7,    7]",
445		"[   0,    2]   +  [   0,    5]  ==  [   0,    7]",
446		"[   3,    6]   +  [  10,   15]  ==  [  13,   21]",
447		"[   3,   +∞)   +  [  -4,   -2]  ==  [  -1,   +∞)",
448		"[   3,   +∞)   +  [  10,   15]  ==  [  13,   +∞)",
449		"[   3,   +∞)   +  (  -∞,   15]  ==  (  -∞,   +∞)",
450		"[   3,    6]   +  (  -∞,   15]  ==  (  -∞,   21]",
451		"[   3,    6]   +  (  -∞,   +∞)  ==  (  -∞,   +∞)",
452		"(  -∞,   +∞)   +  (  -∞,   +∞)  ==  (  -∞,   +∞)",
453		"(  -∞,   +∞)   +  [   1,    2]  ==  (  -∞,   +∞)",
454		"(  -∞,   +∞)   +  [   0,    0]  ==  (  -∞,   +∞)",
455		"[   3,    6]   +  [...empty..]  ==  [...empty..]",
456		"[...empty..]   +  [  10,   15]  ==  [...empty..]",
457		"[...empty..]   +  [...empty..]  ==  [...empty..]",
458		"(  -∞,   +∞)   +  [...empty..]  ==  [...empty..]",
459	)
460}
461
462func TestOpSub(tt *testing.T) {
463	testOp(tt,
464		"[   3,    3]   -  [  -5,   -5]  ==  [   8,    8]",
465		"[   3,    3]   -  [   0,    0]  ==  [   3,    3]",
466		"[   0,    0]   -  [  -7,    7]  ==  [  -7,    7]",
467		"[   0,    2]   -  [   0,    5]  ==  [  -5,    2]",
468		"[   3,    6]   -  [  10,   15]  ==  [ -12,   -4]",
469		"[   3,   +∞)   -  [  -4,   -2]  ==  [   5,   +∞)",
470		"[   3,   +∞)   -  [  10,   15]  ==  [ -12,   +∞)",
471		"[   3,   +∞)   -  (  -∞,   15]  ==  (  -∞,   +∞)",
472		"[   3,    6]   -  (  -∞,   15]  ==  [ -12,   +∞)",
473		"[   3,    6]   -  (  -∞,   +∞)  ==  (  -∞,   +∞)",
474		"(  -∞,   +∞)   -  (  -∞,   +∞)  ==  (  -∞,   +∞)",
475		"(  -∞,   +∞)   -  [   1,    2]  ==  (  -∞,   +∞)",
476		"(  -∞,   +∞)   -  [   0,    0]  ==  (  -∞,   +∞)",
477		"[   3,    6]   -  [...empty..]  ==  [...empty..]",
478		"[...empty..]   -  [  10,   15]  ==  [...empty..]",
479		"[...empty..]   -  [...empty..]  ==  [...empty..]",
480		"(  -∞,   +∞)   -  [...empty..]  ==  [...empty..]",
481	)
482}
483
484func TestOpMul(tt *testing.T) {
485	testOp(tt,
486		"[   3,    3]   *  [  -5,   -5]  ==  [ -15,  -15]",
487		"[   3,    3]   *  [   0,    0]  ==  [   0,    0]",
488		"[   0,    0]   *  [  -7,    7]  ==  [   0,    0]",
489		"[   0,    2]   *  [   0,    5]  ==  [   0,   10]",
490		"[   3,    6]   *  [  10,   15]  ==  [  30,   90]",
491		"[   3,   +∞)   *  [  -4,   -2]  ==  (  -∞,   -6]",
492		"[   3,   +∞)   *  [  10,   15]  ==  [  30,   +∞)",
493		"[   3,   +∞)   *  (  -∞,   15]  ==  (  -∞,   +∞)",
494		"[   3,    6]   *  (  -∞,   15]  ==  (  -∞,   90]",
495		"[   3,    6]   *  (  -∞,   +∞)  ==  (  -∞,   +∞)",
496		"(  -∞,   +∞)   *  (  -∞,   +∞)  ==  (  -∞,   +∞)",
497		"(  -∞,   +∞)   *  [   1,    2]  ==  (  -∞,   +∞)",
498		"(  -∞,   +∞)   *  [   0,    0]  ==  [   0,    0]",
499		"[   3,    6]   *  [...empty..]  ==  [...empty..]",
500		"[...empty..]   *  [  10,   15]  ==  [...empty..]",
501		"[...empty..]   *  [...empty..]  ==  [...empty..]",
502		"(  -∞,   +∞)   *  [...empty..]  ==  [...empty..]",
503
504		"[  -3,   -1]   *  [ -11,  -10]  ==  [  10,   33]",
505		"[  -3,    0]   *  [ -11,  -10]  ==  [   0,   33]",
506		"[  -3,    1]   *  [ -11,  -10]  ==  [ -11,   33]",
507		"[  -3,    4]   *  [ -11,  -10]  ==  [ -44,   33]",
508		"[  -1,    4]   *  [ -11,  -10]  ==  [ -44,   11]",
509		"[   0,    4]   *  [ -11,  -10]  ==  [ -44,    0]",
510		"[   1,    4]   *  [ -11,  -10]  ==  [ -44,  -10]",
511
512		"[  -3,   -1]   *  [  -6,    2]  ==  [  -6,   18]",
513		"[  -3,    0]   *  [  -6,    2]  ==  [  -6,   18]",
514		"[  -3,    1]   *  [  -6,    2]  ==  [  -6,   18]",
515		"[  -3,    4]   *  [  -6,    2]  ==  [ -24,   18]",
516		"[  -1,    4]   *  [  -6,    2]  ==  [ -24,    8]",
517		"[   0,    4]   *  [  -6,    2]  ==  [ -24,    8]",
518		"[   1,    4]   *  [  -6,    2]  ==  [ -24,    8]",
519
520		"[  -3,   -1]   *  [   0,    3]  ==  [  -9,    0]",
521		"[  -3,    0]   *  [   0,    3]  ==  [  -9,    0]",
522		"[  -3,    1]   *  [   0,    3]  ==  [  -9,    3]",
523		"[  -3,    4]   *  [   0,    3]  ==  [  -9,   12]",
524		"[  -1,    4]   *  [   0,    3]  ==  [  -3,   12]",
525		"[   0,    4]   *  [   0,    3]  ==  [   0,   12]",
526		"[   1,    4]   *  [   0,    3]  ==  [   0,   12]",
527
528		"[  -3,   -1]   *  [   2,    3]  ==  [  -9,   -2]",
529		"[  -3,    0]   *  [   2,    3]  ==  [  -9,    0]",
530		"[  -3,    1]   *  [   2,    3]  ==  [  -9,    3]",
531		"[  -3,    4]   *  [   2,    3]  ==  [  -9,   12]",
532		"[  -1,    4]   *  [   2,    3]  ==  [  -3,   12]",
533		"[   0,    4]   *  [   2,    3]  ==  [   0,   12]",
534		"[   1,    4]   *  [   2,    3]  ==  [   2,   12]",
535
536		"[  -9,   +∞)   *  [   2,   +∞)  ==  (  -∞,   +∞)",
537		"[  -1,   +∞)   *  [   2,   +∞)  ==  (  -∞,   +∞)",
538		"[   0,   +∞)   *  [   2,   +∞)  ==  [   0,   +∞)",
539		"[   1,   +∞)   *  [   2,   +∞)  ==  [   2,   +∞)",
540		"[   7,   +∞)   *  [   2,   +∞)  ==  [  14,   +∞)",
541		"[  -1,    1]   *  (  -∞,   +∞)  ==  (  -∞,   +∞)",
542		"[   0,    0]   *  (  -∞,   +∞)  ==  [   0,    0]",
543		"[   1,    1]   *  (  -∞,   +∞)  ==  (  -∞,   +∞)",
544	)
545}
546
547func TestOpQuo(tt *testing.T) {
548	testOp(tt,
549		"[   3,    3]   /  [  -5,   -5]  ==  [   0,    0]",
550		"[   3,    3]   /  [   0,    0]  ==  invalid",
551		"[   0,    0]   /  [  -7,    7]  ==  invalid",
552		"[   0,    2]   /  [   0,    5]  ==  invalid",
553		"[   3,    6]   /  [  10,   15]  ==  [   0,    0]",
554		"[   3,   +∞)   /  [  -4,   -2]  ==  (  -∞,    0]",
555		"[   3,   +∞)   /  [  10,   15]  ==  [   0,   +∞)",
556		"[   3,   +∞)   /  (  -∞,   15]  ==  invalid",
557		"[   3,    6]   /  (  -∞,   15]  ==  invalid",
558		"[   3,    6]   /  (  -∞,   +∞)  ==  invalid",
559		"(  -∞,   +∞)   /  (  -∞,   +∞)  ==  invalid",
560		"(  -∞,   +∞)   /  [   1,    2]  ==  (  -∞,   +∞)",
561		"(  -∞,   +∞)   /  [   0,    0]  ==  invalid",
562		"[   3,    6]   /  [...empty..]  ==  [...empty..]",
563		"[...empty..]   /  [  10,   15]  ==  [...empty..]",
564		"[...empty..]   /  [...empty..]  ==  [...empty..]",
565		"(  -∞,   +∞)   /  [...empty..]  ==  [...empty..]",
566
567		"[   1,    4]   /  [ -11,  -10]  ==  [   0,    0]",
568
569		"[   1,    4]   /  [  -6,    2]  ==  invalid",
570
571		"[  -3,   -1]   /  [   1,    3]  ==  [  -3,    0]",
572		"[  -3,    0]   /  [   1,    3]  ==  [  -3,    0]",
573		"[  -3,    1]   /  [   1,    3]  ==  [  -3,    1]",
574		"[  -3,    4]   /  [   1,    3]  ==  [  -3,    4]",
575		"[  -1,    4]   /  [   1,    3]  ==  [  -1,    4]",
576		"[   0,    4]   /  [   1,    3]  ==  [   0,    4]",
577		"[   1,    4]   /  [   1,    3]  ==  [   0,    4]",
578
579		"[  -3,   -1]   /  [   2,    3]  ==  [  -1,    0]",
580		"[  -3,    0]   /  [   2,    3]  ==  [  -1,    0]",
581		"[  -3,    1]   /  [   2,    3]  ==  [  -1,    0]",
582		"[  -3,    4]   /  [   2,    3]  ==  [  -1,    2]",
583		"[  -1,    4]   /  [   2,    3]  ==  [   0,    2]",
584		"[   0,    4]   /  [   2,    3]  ==  [   0,    2]",
585		"[   1,    4]   /  [   2,    3]  ==  [   0,    2]",
586
587		"[  -9,   +∞)   /  [   2,   +∞)  ==  [  -4,   +∞)",
588		"[  -1,   +∞)   /  [   2,   +∞)  ==  [   0,   +∞)",
589		"[   0,   +∞)   /  [   2,   +∞)  ==  [   0,   +∞)",
590		"[   1,   +∞)   /  [   2,   +∞)  ==  [   0,   +∞)",
591		"[   7,   +∞)   /  [   2,   +∞)  ==  [   0,   +∞)",
592		"[  -1,    1]   /  (  -∞,   +∞)  ==  invalid",
593		"[   0,    0]   /  (  -∞,   +∞)  ==  invalid",
594		"[   1,    1]   /  (  -∞,   +∞)  ==  invalid",
595	)
596}
597
598func TestOpLsh(tt *testing.T) {
599	testOp(tt,
600		"[   3,    3]  <<  [  -5,   -5]  ==  invalid",
601		"[   3,    3]  <<  [   0,    0]  ==  [   3,    3]",
602		"[   0,    0]  <<  [  -7,    7]  ==  invalid",
603		"[   0,    2]  <<  [   0,    5]  ==  [   0,   64]",
604		"[   3,    6]  <<  [  10,   15]  ==  [3072, 196608]",
605		"[   3,   +∞)  <<  [  -4,   -2]  ==  invalid",
606		"[   3,   +∞)  <<  [  10,   15]  ==  [3072,   +∞)",
607		"[   3,   +∞)  <<  (  -∞,   15]  ==  invalid",
608		"[   3,    6]  <<  (  -∞,   15]  ==  invalid",
609		"[   3,    6]  <<  (  -∞,   +∞)  ==  invalid",
610		"(  -∞,   +∞)  <<  (  -∞,   +∞)  ==  invalid",
611		"(  -∞,   +∞)  <<  [   1,    2]  ==  (  -∞,   +∞)",
612		"(  -∞,   +∞)  <<  [   0,    0]  ==  (  -∞,   +∞)",
613		"[   3,    6]  <<  [...empty..]  ==  [...empty..]",
614		"[...empty..]  <<  [  10,   15]  ==  [...empty..]",
615		"[...empty..]  <<  [...empty..]  ==  [...empty..]",
616		"(  -∞,   +∞)  <<  [...empty..]  ==  [...empty..]",
617
618		"[   1,    4]  <<  [ -11,  -10]  ==  invalid",
619
620		"[   1,    4]  <<  [  -6,    2]  ==  invalid",
621
622		"[  -3,   -1]  <<  [   0,    3]  ==  [ -24,   -1]",
623		"[  -3,    0]  <<  [   0,    3]  ==  [ -24,    0]",
624		"[  -3,    1]  <<  [   0,    3]  ==  [ -24,    8]",
625		"[  -3,    4]  <<  [   0,    3]  ==  [ -24,   32]",
626		"[  -1,    4]  <<  [   0,    3]  ==  [  -8,   32]",
627		"[   0,    4]  <<  [   0,    3]  ==  [   0,   32]",
628		"[   1,    4]  <<  [   0,    3]  ==  [   1,   32]",
629
630		"[  -3,   -1]  <<  [   2,    3]  ==  [ -24,   -4]",
631		"[  -3,    0]  <<  [   2,    3]  ==  [ -24,    0]",
632		"[  -3,    1]  <<  [   2,    3]  ==  [ -24,    8]",
633		"[  -3,    4]  <<  [   2,    3]  ==  [ -24,   32]",
634		"[  -1,    4]  <<  [   2,    3]  ==  [  -8,   32]",
635		"[   0,    4]  <<  [   2,    3]  ==  [   0,   32]",
636		"[   1,    4]  <<  [   2,    3]  ==  [   4,   32]",
637
638		"[  -9,   +∞)  <<  [   2,   +∞)  ==  (  -∞,   +∞)",
639		"[  -1,   +∞)  <<  [   2,   +∞)  ==  (  -∞,   +∞)",
640		"[   0,   +∞)  <<  [   2,   +∞)  ==  [   0,   +∞)",
641		"[   1,   +∞)  <<  [   2,   +∞)  ==  [   4,   +∞)",
642		"[   7,   +∞)  <<  [   2,   +∞)  ==  [  28,   +∞)",
643		"[  -1,    1]  <<  (  -∞,   +∞)  ==  invalid",
644		"[   0,    0]  <<  (  -∞,   +∞)  ==  invalid",
645		"[   1,    1]  <<  (  -∞,   +∞)  ==  invalid",
646	)
647}
648
649func TestOpRsh(tt *testing.T) {
650	testOp(tt,
651		"[   3,    3]  >>  [  -5,   -5]  ==  invalid",
652		"[   3,    3]  >>  [   0,    0]  ==  [   3,    3]",
653		"[   0,    0]  >>  [  -7,    7]  ==  invalid",
654		"[   0,    2]  >>  [   0,    5]  ==  [   0,    2]",
655		"[   3,    6]  >>  [  10,   15]  ==  [   0,    0]",
656		"[   3,   +∞)  >>  [  -4,   -2]  ==  invalid",
657		"[   3,   +∞)  >>  [  10,   15]  ==  [   0,   +∞)",
658		"[   3,   +∞)  >>  (  -∞,   15]  ==  invalid",
659		"[   3,    6]  >>  (  -∞,   15]  ==  invalid",
660		"[   3,    6]  >>  (  -∞,   +∞)  ==  invalid",
661		"(  -∞,   +∞)  >>  (  -∞,   +∞)  ==  invalid",
662		"(  -∞,   +∞)  >>  [   1,    2]  ==  (  -∞,   +∞)",
663		"(  -∞,   +∞)  >>  [   0,    0]  ==  (  -∞,   +∞)",
664		"[   3,    6]  >>  [...empty..]  ==  [...empty..]",
665		"[...empty..]  >>  [  10,   15]  ==  [...empty..]",
666		"[...empty..]  >>  [...empty..]  ==  [...empty..]",
667		"(  -∞,   +∞)  >>  [...empty..]  ==  [...empty..]",
668
669		"[   1,    4]  >>  [ -11,  -10]  ==  invalid",
670
671		"[   1,    4]  >>  [  -6,    2]  ==  invalid",
672
673		"[  -3,   -1]  >>  [   0,    3]  ==  [  -3,   -1]",
674		"[  -3,    0]  >>  [   0,    3]  ==  [  -3,    0]",
675		"[  -3,    1]  >>  [   0,    3]  ==  [  -3,    1]",
676		"[  -3,    4]  >>  [   0,    3]  ==  [  -3,    4]",
677		"[  -1,    4]  >>  [   0,    3]  ==  [  -1,    4]",
678		"[   0,    4]  >>  [   0,    3]  ==  [   0,    4]",
679		"[   1,    4]  >>  [   0,    3]  ==  [   0,    4]",
680
681		"[  -3,   -1]  >>  [   1,    3]  ==  [  -2,   -1]",
682		"[  -3,    0]  >>  [   1,    3]  ==  [  -2,    0]",
683		"[  -3,    1]  >>  [   1,    3]  ==  [  -2,    0]",
684		"[  -3,    4]  >>  [   1,    3]  ==  [  -2,    2]",
685		"[  -1,    4]  >>  [   1,    3]  ==  [  -1,    2]",
686		"[   0,    4]  >>  [   1,    3]  ==  [   0,    2]",
687		"[   1,    4]  >>  [   1,    3]  ==  [   0,    2]",
688
689		"[  -9,   +∞)  >>  [   2,   +∞)  ==  [  -3,   +∞)",
690		"[  -1,   +∞)  >>  [   2,   +∞)  ==  [  -1,   +∞)",
691		"[   0,   +∞)  >>  [   2,   +∞)  ==  [   0,   +∞)",
692		"[   1,   +∞)  >>  [   2,   +∞)  ==  [   0,   +∞)",
693		"[   7,   +∞)  >>  [   2,   +∞)  ==  [   0,   +∞)",
694		"[  -1,    1]  >>  (  -∞,   +∞)  ==  invalid",
695		"[   0,    0]  >>  (  -∞,   +∞)  ==  invalid",
696		"[   1,    1]  >>  (  -∞,   +∞)  ==  invalid",
697	)
698}
699
700func TestOpAnd(tt *testing.T) {
701	testOp(tt,
702		"[   3,    3]   &  [  -5,   -5]  ==  invalid",
703		"[   3,    3]   &  [   0,    0]  ==  [   0,    0]",
704		"[   0,    0]   &  [  -7,    7]  ==  invalid",
705		"[   0,    2]   &  [   0,    5]  ==  [   0,    2]",
706		"[   3,    6]   &  [  10,   15]  ==  [   0,    6]",
707		"[   3,   +∞)   &  [  -4,   -2]  ==  invalid",
708		"[   3,   +∞)   &  [  10,   15]  ==  [   0,   15]",
709		"[   3,   +∞)   &  (  -∞,   15]  ==  invalid",
710		"[   3,    6]   &  (  -∞,   15]  ==  invalid",
711		"[   3,    6]   &  (  -∞,   +∞)  ==  invalid",
712		"(  -∞,   +∞)   &  (  -∞,   +∞)  ==  invalid",
713		"(  -∞,   +∞)   &  [   1,    2]  ==  invalid",
714		"(  -∞,   +∞)   &  [   0,    0]  ==  invalid",
715		"[   3,    6]   &  [...empty..]  ==  [...empty..]",
716		"[...empty..]   &  [  10,   15]  ==  [...empty..]",
717		"[...empty..]   &  [...empty..]  ==  [...empty..]",
718		"(  -∞,   +∞)   &  [...empty..]  ==  [...empty..]",
719
720		"[   1,    4]   &  [ -11,  -10]  ==  invalid",
721
722		"[   1,    4]   &  [  -6,    2]  ==  invalid",
723
724		"[  -3,   -1]   &  [   0,    3]  ==  invalid",
725		"[  -1,    4]   &  [   0,    3]  ==  invalid",
726		"[   0,    4]   &  [   0,    3]  ==  [   0,    3]",
727		"[   1,    4]   &  [   0,    3]  ==  [   0,    3]",
728
729		"[  -3,   -1]   &  [   2,    3]  ==  invalid",
730		"[  -1,    4]   &  [   2,    3]  ==  invalid",
731		"[   0,    4]   &  [   2,    3]  ==  [   0,    3]",
732		"[   1,    4]   &  [   2,    3]  ==  [   0,    3]",
733
734		"[  -9,   +∞)   &  [   2,   +∞)  ==  invalid",
735		"[  -1,   +∞)   &  [   2,   +∞)  ==  invalid",
736		"[   0,   +∞)   &  [   2,   +∞)  ==  [   0,   +∞)",
737		"[   1,   +∞)   &  [   2,   +∞)  ==  [   0,   +∞)",
738		"[   7,   +∞)   &  [   2,   +∞)  ==  [   0,   +∞)",
739		"[  -1,    1]   &  (  -∞,   +∞)  ==  invalid",
740		"[   0,    0]   &  (  -∞,   +∞)  ==  invalid",
741		"[   1,    1]   &  (  -∞,   +∞)  ==  invalid",
742
743		"[   1,    3]   &  [   4,    9]  ==  [   0,    3]",
744		"[   3,    4]   &  [   5,    6]  ==  [   1,    4]",
745		"[   4,    5]   &  [   6,    7]  ==  [   4,    5]",
746		"[   7,    7]   &  [  12,   14]  ==  [   4,    6]",
747
748		"[   5,    6]   &  [   6,    7]  ==  [   4,    6]",
749		"[   5,    6]   &  [   6,    8]  ==  [   0,    6]",
750		"[   5,    9]   &  [   6,    8]  ==  [   0,    8]",
751		"[   5,    9]   &  [   6,    9]  ==  [   0,    9]",
752
753		"[   5,    6]   &  [   3,   +∞)  ==  [   0,    6]",
754		"[   5,    9]   &  [   3,   +∞)  ==  [   0,    9]",
755		"[   5,    6]   &  [   7,   +∞)  ==  [   0,    6]",
756		"[   5,    9]   &  [   7,   +∞)  ==  [   0,    9]",
757		"[   5,    6]   &  [   8,   +∞)  ==  [   0,    6]",
758		"[   5,    9]   &  [   8,   +∞)  ==  [   0,    9]",
759		"[   5,    6]   &  [   9,   +∞)  ==  [   0,    6]",
760		"[   5,    9]   &  [   9,   +∞)  ==  [   0,    9]",
761		"[   5,    6]   &  [  12,   +∞)  ==  [   0,    6]",
762		"[   5,    9]   &  [  12,   +∞)  ==  [   0,    9]",
763	)
764}
765
766func TestOpOr(tt *testing.T) {
767	testOp(tt,
768		"[   3,    3]   |  [  -5,   -5]  ==  invalid",
769		"[   3,    3]   |  [   0,    0]  ==  [   3,    3]",
770		"[   0,    0]   |  [  -7,    7]  ==  invalid",
771		"[   0,    2]   |  [   0,    5]  ==  [   0,    7]",
772		"[   3,    6]   |  [  10,   15]  ==  [  11,   15]",
773		"[   3,   +∞)   |  [  -4,   -2]  ==  invalid",
774		"[   3,   +∞)   |  [  10,   15]  ==  [  10,   +∞)",
775		"[   3,   +∞)   |  (  -∞,   15]  ==  invalid",
776		"[   3,    6]   |  (  -∞,   15]  ==  invalid",
777		"[   3,    6]   |  (  -∞,   +∞)  ==  invalid",
778		"(  -∞,   +∞)   |  (  -∞,   +∞)  ==  invalid",
779		"(  -∞,   +∞)   |  [   1,    2]  ==  invalid",
780		"(  -∞,   +∞)   |  [   0,    0]  ==  invalid",
781		"[   3,    6]   |  [...empty..]  ==  [...empty..]",
782		"[...empty..]   |  [  10,   15]  ==  [...empty..]",
783		"[...empty..]   |  [...empty..]  ==  [...empty..]",
784		"(  -∞,   +∞)   |  [...empty..]  ==  [...empty..]",
785
786		"[   1,    4]   |  [ -11,  -10]  ==  invalid",
787
788		"[   1,    4]   |  [  -6,    2]  ==  invalid",
789
790		"[  -3,   -1]   |  [   0,    3]  ==  invalid",
791		"[  -1,    4]   |  [   0,    3]  ==  invalid",
792		"[   0,    4]   |  [   0,    3]  ==  [   0,    7]",
793		"[   1,    4]   |  [   0,    3]  ==  [   1,    7]",
794
795		"[  -3,   -1]   |  [   2,    3]  ==  invalid",
796		"[  -1,    4]   |  [   2,    3]  ==  invalid",
797		"[   0,    4]   |  [   2,    3]  ==  [   2,    7]",
798		"[   1,    4]   |  [   2,    3]  ==  [   2,    7]",
799
800		"[  -9,   +∞)   |  [   2,   +∞)  ==  invalid",
801		"[  -1,   +∞)   |  [   2,   +∞)  ==  invalid",
802		"[   0,   +∞)   |  [   2,   +∞)  ==  [   2,   +∞)",
803		"[   1,   +∞)   |  [   2,   +∞)  ==  [   2,   +∞)",
804		"[   7,   +∞)   |  [   2,   +∞)  ==  [   7,   +∞)",
805		"[  -1,    1]   |  (  -∞,   +∞)  ==  invalid",
806		"[   0,    0]   |  (  -∞,   +∞)  ==  invalid",
807		"[   1,    1]   |  (  -∞,   +∞)  ==  invalid",
808
809		"[   1,    3]   |  [   4,    9]  ==  [   5,   11]",
810		"[   3,    4]   |  [   5,    6]  ==  [   5,    7]",
811		"[   4,    5]   |  [   6,    7]  ==  [   6,    7]",
812		"[   7,    7]   |  [  12,   14]  ==  [  15,   15]",
813
814		"[   5,    6]   |  [   6,    7]  ==  [   6,    7]",
815		"[   5,    6]   |  [   6,    8]  ==  [   6,   14]",
816		"[   5,    9]   |  [   6,    8]  ==  [   6,   15]",
817		"[   5,    9]   |  [   6,    9]  ==  [   6,   15]",
818
819		"[   5,    6]   |  [   3,   +∞)  ==  [   5,   +∞)",
820		"[   5,    9]   |  [   3,   +∞)  ==  [   5,   +∞)",
821		"[   5,    6]   |  [   7,   +∞)  ==  [   7,   +∞)",
822		"[   5,    9]   |  [   7,   +∞)  ==  [   7,   +∞)",
823		"[   5,    6]   |  [   8,   +∞)  ==  [  13,   +∞)",
824		"[   5,    9]   |  [   8,   +∞)  ==  [   8,   +∞)",
825		"[   5,    6]   |  [   9,   +∞)  ==  [  13,   +∞)",
826		"[   5,    9]   |  [   9,   +∞)  ==  [   9,   +∞)",
827		"[   5,    6]   |  [  12,   +∞)  ==  [  13,   +∞)",
828		"[   5,    9]   |  [  12,   +∞)  ==  [  12,   +∞)",
829	)
830}
831