|  | // Copyright 2018 The Wuffs Authors. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //    https://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | package interval | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "math/big" | 
|  | "math/rand" | 
|  | "sort" | 
|  | "strconv" | 
|  | "strings" | 
|  | "testing" | 
|  | "unicode/utf8" | 
|  | ) | 
|  |  | 
|  | var fromNeg7ToPos7 = []*big.Int{ | 
|  | big.NewInt(-7), | 
|  | big.NewInt(-6), | 
|  | big.NewInt(-5), | 
|  | big.NewInt(-4), | 
|  | big.NewInt(-3), | 
|  | big.NewInt(-2), | 
|  | big.NewInt(-1), | 
|  | big.NewInt(+0), | 
|  | big.NewInt(+1), | 
|  | big.NewInt(+2), | 
|  | big.NewInt(+3), | 
|  | big.NewInt(+4), | 
|  | big.NewInt(+5), | 
|  | big.NewInt(+6), | 
|  | big.NewInt(+7), | 
|  | nil, | 
|  | } | 
|  |  | 
|  | var fromNeg3ToPos3 = []*big.Int{ | 
|  | big.NewInt(-3), | 
|  | big.NewInt(-2), | 
|  | big.NewInt(-1), | 
|  | big.NewInt(+0), | 
|  | big.NewInt(+1), | 
|  | big.NewInt(+2), | 
|  | big.NewInt(+3), | 
|  | nil, | 
|  | } | 
|  |  | 
|  | // TestMotivatingExample tests the "motivating example" given in the package | 
|  | // doc comment. | 
|  | func TestMotivatingExample(tt *testing.T) { | 
|  | i := IntRange{big.NewInt(0), big.NewInt(255)} | 
|  | j := IntRange{big.NewInt(0), big.NewInt(3)} | 
|  | four := IntRange{big.NewInt(4), big.NewInt(4)} | 
|  | got := four.Mul(i).Add(j) | 
|  | want := IntRange{big.NewInt(0), big.NewInt(1023)} | 
|  | if !got.Eq(want) { | 
|  | tt.Fatalf("got %v, want %v", got, want) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestBigIntShifts(tt *testing.T) { | 
|  | // These alternative implementations always take the fallback code path of | 
|  | // bigIntLsh and bigIntRsh. This test checks that those fallback paths give | 
|  | // the same results as *big.Int's Lsh and Rsh methods. There are fallback | 
|  | // and non-fallback code paths in interval.go because those *big.Int | 
|  | // methods aren't applicable if j's value doesn't fit in a uint. | 
|  |  | 
|  | alternativeBigIntLsh := func(i *big.Int, j *big.Int) *big.Int { | 
|  | // Fallback code path, copy-pasted from interval.go. | 
|  | k := big.NewInt(2) | 
|  | k.Exp(k, j, nil) | 
|  | k.Mul(i, k) | 
|  | return k | 
|  | } | 
|  |  | 
|  | alternativeBigIntRsh := func(i *big.Int, j *big.Int) *big.Int { | 
|  | // Fallback code path, copy-pasted from interval.go. | 
|  | k := big.NewInt(2) | 
|  | k.Exp(k, j, nil) | 
|  | k.Div(i, k) // This is explicitly Div, not Quo. | 
|  | return k | 
|  | } | 
|  |  | 
|  | xs := []*big.Int{ | 
|  | big.NewInt(-9), | 
|  | big.NewInt(-8), | 
|  | big.NewInt(-7), | 
|  |  | 
|  | big.NewInt(-2), | 
|  | big.NewInt(-1), | 
|  | big.NewInt(+0), | 
|  | big.NewInt(+1), | 
|  | big.NewInt(+2), | 
|  |  | 
|  | big.NewInt(+7), | 
|  | big.NewInt(+8), | 
|  | big.NewInt(+9), | 
|  | } | 
|  |  | 
|  | ys := []*big.Int{ | 
|  | big.NewInt(+0), | 
|  | big.NewInt(+1), | 
|  | big.NewInt(+2), | 
|  | big.NewInt(+3), | 
|  | big.NewInt(+4), | 
|  | } | 
|  |  | 
|  | for _, x := range xs { | 
|  | for _, y := range ys { | 
|  | { | 
|  | got := bigIntLsh(x, y) | 
|  | want := alternativeBigIntLsh(x, y) | 
|  | if got.Cmp(want) != 0 { | 
|  | tt.Errorf("%v << %v: got %v, want %v", x, y, got, want) | 
|  | } | 
|  | } | 
|  |  | 
|  | { | 
|  | got := bigIntRsh(x, y) | 
|  | want := alternativeBigIntRsh(x, y) | 
|  | if got.Cmp(want) != 0 { | 
|  | tt.Errorf("%v >> %v: got %v, want %v", x, y, got, want) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func trimLeadingSpaces(s string) string { | 
|  | for ; len(s) > 0 && s[0] == ' '; s = s[1:] { | 
|  | } | 
|  | return s | 
|  | } | 
|  |  | 
|  | func trimTrailingSpaces(s string) string { | 
|  | for ; len(s) > 0 && s[len(s)-1] == ' '; s = s[:len(s)-1] { | 
|  | } | 
|  | return s | 
|  | } | 
|  |  | 
|  | func parseInt(s string) (x *big.Int, remaining string, err error) { | 
|  | s = trimLeadingSpaces(s) | 
|  | i := 0 | 
|  | for ; i < len(s); i++ { | 
|  | if c := s[i]; c == ')' || c == ',' || c == ']' { | 
|  | break | 
|  | } | 
|  | } | 
|  | s, remaining = trimTrailingSpaces(s[:i]), s[i:] | 
|  | switch s { | 
|  | case "-∞", "+∞": | 
|  | // No-op. | 
|  | default: | 
|  | n, err := strconv.Atoi(s) | 
|  | if err != nil { | 
|  | return nil, "", fmt.Errorf("parseInt(%q): %v", s, err) | 
|  | } | 
|  | x = big.NewInt(int64(n)) | 
|  | } | 
|  | return x, remaining, nil | 
|  | } | 
|  |  | 
|  | // parseInterval parses a string like "[-3, +4] etcetera", returning the | 
|  | // interval itself and the remaining string " etcetera". | 
|  | // | 
|  | // It also parses infinite (unbounded) intervals like "[0, +∞)", and the | 
|  | // special syntax "[...empty..]" for an empty interval (one that contains no | 
|  | // elements). | 
|  | func parseInterval(s string) (x IntRange, remaining string, err error) { | 
|  | const emptySyntax = "[...empty..]" | 
|  | s = trimLeadingSpaces(s) | 
|  | if strings.HasPrefix(s, emptySyntax) { | 
|  | s = s[len(emptySyntax):] | 
|  | return IntRange{big.NewInt(+1), big.NewInt(-1)}, s, nil | 
|  | } | 
|  |  | 
|  | if s[0] != '(' && s[0] != '[' { | 
|  | return IntRange{}, "", fmt.Errorf("expected '(' or '['") | 
|  | } | 
|  | s = s[1:] | 
|  | x0, s, err := parseInt(s) | 
|  | if err != nil { | 
|  | return IntRange{}, "", err | 
|  | } | 
|  | if s[0] != ',' { | 
|  | return IntRange{}, "", fmt.Errorf("expected ','") | 
|  | } | 
|  | s = s[1:] | 
|  | x1, s, err := parseInt(s) | 
|  | if err != nil { | 
|  | return IntRange{}, "", err | 
|  | } | 
|  | if s[0] != ')' && s[0] != ']' { | 
|  | return IntRange{}, "", fmt.Errorf("expected ')' or ']'") | 
|  | } | 
|  | s = s[1:] | 
|  | if x0 != nil && x1 != nil && x0.Cmp(x1) > 0 { | 
|  | return IntRange{}, "", fmt.Errorf("invalid empty interval") | 
|  | } | 
|  | return IntRange{x0, x1}, s, nil | 
|  | } | 
|  |  | 
|  | func TestContainsEtc(tt *testing.T) { | 
|  | testCases := []struct { | 
|  | s  string | 
|  | cn uint32 | 
|  | cz uint32 | 
|  | cp uint32 | 
|  | }{ | 
|  | {"<empty-->", 0, 0, 0}, | 
|  | {"<empty0->", 0, 0, 0}, | 
|  | {"<empty+->", 0, 0, 0}, | 
|  | {"<empty+0>", 0, 0, 0}, | 
|  | {"<empty++>", 0, 0, 0}, | 
|  |  | 
|  | {"(-∞, -1]", 1, 0, 0}, | 
|  | {"(-∞,  0]", 1, 1, 0}, | 
|  | {"(-∞, +1]", 1, 1, 1}, | 
|  | {"(-∞, +∞)", 1, 1, 1}, | 
|  |  | 
|  | {"[-1, -1]", 1, 0, 0}, | 
|  | {"[-1,  0]", 1, 1, 0}, | 
|  | {"[-1, +1]", 1, 1, 1}, | 
|  | {"[-1, +∞)", 1, 1, 1}, | 
|  |  | 
|  | {"[ 0,  0]", 0, 1, 0}, | 
|  | {"[ 0, +1]", 0, 1, 1}, | 
|  | {"[ 0, +∞)", 0, 1, 1}, | 
|  |  | 
|  | {"[+1, +1]", 0, 0, 1}, | 
|  | {"[+1, +∞)", 0, 0, 1}, | 
|  | } | 
|  |  | 
|  | // eqTestCases is appended to throughout the "range testCases" loop, but it | 
|  | // always contains exactly one empty IntRange. | 
|  | eqTestCases := []IntRange{ | 
|  | makeEmptyRange(), | 
|  | } | 
|  |  | 
|  | for _, tc := range testCases { | 
|  | x := IntRange{} | 
|  | switch tc.s { | 
|  | case "<empty-->": | 
|  | x = IntRange{big.NewInt(-1), big.NewInt(-2)} | 
|  | case "<empty0->": | 
|  | x = IntRange{big.NewInt(00), big.NewInt(-2)} | 
|  | case "<empty+->": | 
|  | x = IntRange{big.NewInt(+2), big.NewInt(-2)} | 
|  | case "<empty+0>": | 
|  | x = IntRange{big.NewInt(+2), big.NewInt(00)} | 
|  | case "<empty++>": | 
|  | x = IntRange{big.NewInt(+2), big.NewInt(+1)} | 
|  | default: | 
|  | err := error(nil) | 
|  | x, _, err = parseInterval(tc.s) | 
|  | if err != nil { | 
|  | tt.Errorf("%s: %v", tc.s, err) | 
|  | continue | 
|  | } | 
|  | } | 
|  |  | 
|  | if got, want := x.ContainsNegative(), tc.cn != 0; got != want { | 
|  | tt.Errorf("%s.ContainsNegative(): got %t, want %t", tc.s, got, want) | 
|  | } | 
|  | if got, want := x.ContainsZero(), tc.cz != 0; got != want { | 
|  | tt.Errorf("%s.ContainsZero(): got %t, want %t", tc.s, got, want) | 
|  | } | 
|  | if got, want := x.ContainsPositive(), tc.cp != 0; got != want { | 
|  | tt.Errorf("%s.ContainsPositive(): got %t, want %t", tc.s, got, want) | 
|  | } | 
|  |  | 
|  | if got, want := x.Empty(), strings.Contains(tc.s, "empty"); got != want { | 
|  | tt.Errorf("%s.Empty(): got %t, want %t", tc.s, got, want) | 
|  | } else if !got { | 
|  | eqTestCases = append(eqTestCases, x) | 
|  | } else if !x.Eq(sharedEmptyRange) { | 
|  | tt.Errorf("%v eq %v: got %t, want %t", x, sharedEmptyRange, got, want) | 
|  | } | 
|  |  | 
|  | if got, want := x.justZero(), tc.s == "[ 0,  0]"; got != want { | 
|  | tt.Errorf("%s.justZero(): got %t, want %t", tc.s, got, want) | 
|  | } | 
|  | } | 
|  |  | 
|  | for i, x := range eqTestCases { | 
|  | for j, y := range eqTestCases { | 
|  | got := x.Eq(y) | 
|  | want := i == j | 
|  | if got != want { | 
|  | tt.Errorf("%v eq %v: got %t, want %t", x, y, got, want) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | for _, x := range eqTestCases { | 
|  | neg, pos, hasNeg, hasZero, hasPos := x.split3Ways() | 
|  | negEmpty, posEmpty := !hasNeg, !hasPos | 
|  | if got, want := neg.Empty(), negEmpty; got != want { | 
|  | tt.Errorf("%v: neg.Empty() == %t, negEmpty == %t", x, got, want) | 
|  | } | 
|  | if got, want := !x.ContainsNegative(), negEmpty; got != want { | 
|  | tt.Errorf("%v: !x.ContainsNegative() == %t, negEmpty == %t", x, got, want) | 
|  | } | 
|  | if got, want := x.ContainsZero(), hasZero; got != want { | 
|  | tt.Errorf("%v: x.ContainsZero() == %t, hasZero == %t", x, got, want) | 
|  | } | 
|  | if got, want := !x.ContainsPositive(), posEmpty; got != want { | 
|  | tt.Errorf("%v: !x.ContainsPositive() == %t, posEmpty == %t", x, got, want) | 
|  | } | 
|  | if got, want := pos.Empty(), posEmpty; got != want { | 
|  | tt.Errorf("%v: pos.Empty() == %t, posEmpty == %t", x, got, want) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func shareBigIntPointers(x IntRange, y IntRange) bool { | 
|  | return ((x[0] == y[0]) && (x[0] != nil)) || | 
|  | ((x[0] == y[1]) && (x[0] != nil)) || | 
|  | ((x[1] == y[0]) && (x[1] != nil)) || | 
|  | ((x[1] == y[1]) && (x[1] != nil)) | 
|  | } | 
|  |  | 
|  | func testBruteForceAgrees(x IntRange, y IntRange, opKey rune) error { | 
|  | brute, bruteOK := bruteForce(x, y, opKey) | 
|  | got, gotOK := intOperators[opKey](x, y) | 
|  | if shareBigIntPointers(got, x) || shareBigIntPointers(got, y) { | 
|  | return fmt.Errorf("*big.Int pointers (pointing to mutable state) were re-used") | 
|  | } | 
|  | if !got.Eq(brute) || gotOK != bruteOK { | 
|  | return fmt.Errorf("got %v, %t, brute force gave %v, %t", got, gotOK, brute, bruteOK) | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func TestBruteForceAgreesSystematically(tt *testing.T) { | 
|  | for _, opKey := range intOperatorsKeys { | 
|  | for _, x0 := range fromNeg7ToPos7 { | 
|  | for _, x1 := range fromNeg7ToPos7 { | 
|  | x := IntRange{x0, x1} | 
|  |  | 
|  | for _, y0 := range fromNeg7ToPos7 { | 
|  | for _, y1 := range fromNeg7ToPos7 { | 
|  | y := IntRange{y0, y1} | 
|  |  | 
|  | if err := testBruteForceAgrees(x, y, opKey); err != nil { | 
|  | tt.Fatalf("%v %c %v: %v", x, opKey, y, err) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestBruteForceAgreesRandomly(tt *testing.T) { | 
|  | gen := func(rng *rand.Rand) *big.Int { | 
|  | r := rng.Intn(2*riRadius+2) - (riRadius + 1) | 
|  | if r == -(riRadius + 1) { | 
|  | return nil | 
|  | } | 
|  | return big.NewInt(int64(r)) | 
|  | } | 
|  |  | 
|  | rng := rand.New(rand.NewSource(0)) | 
|  | for _, opKey := range intOperatorsKeys { | 
|  | for i := 0; i < 10000; i++ { | 
|  | x := IntRange{gen(rng), gen(rng)} | 
|  | y := IntRange{gen(rng), gen(rng)} | 
|  | if err := testBruteForceAgrees(x, y, opKey); err != nil { | 
|  | tt.Fatalf("%v %c %v: %v", x, opKey, y, err) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func testOp(tt *testing.T, testCases ...string) { | 
|  | for _, tc := range testCases { | 
|  | if err := testOp1(tc); err != nil { | 
|  | tt.Errorf("%q: %v", tc, err) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func testOp1(s string) error { | 
|  | x, s, err := parseInterval(s) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | s = trimLeadingSpaces(s) | 
|  |  | 
|  | i := 0 | 
|  | for ; i < len(s) && s[i] != ' '; i++ { | 
|  | } | 
|  | opKey, _ := utf8.DecodeRuneInString(s[:i]) | 
|  | s = s[i:] | 
|  |  | 
|  | y, s, err := parseInterval(s) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | s = trimLeadingSpaces(s) | 
|  | if !strings.HasPrefix(s, "==") { | 
|  | return fmt.Errorf(`expected "=="`) | 
|  | } | 
|  | s = s[2:] | 
|  | s = trimLeadingSpaces(s) | 
|  | want, wantOK := IntRange{}, false | 
|  | if s == "invalid" { | 
|  | s = "" | 
|  | } else { | 
|  | wantOK = true | 
|  | want, s, err = parseInterval(s) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | s = trimLeadingSpaces(s) | 
|  | if s != "" { | 
|  | return fmt.Errorf("trailing specification %q", s) | 
|  | } | 
|  | } | 
|  |  | 
|  | if err := testBruteForceAgrees(x, y, opKey); err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | got, gotOK := intOperators[opKey](x, y) | 
|  | if !got.Eq(want) || gotOK != wantOK { | 
|  | return fmt.Errorf("got %v, %t, want %v, %t", got, gotOK, want, wantOK) | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | var intOperators = map[rune]func(IntRange, IntRange) (IntRange, bool){ | 
|  | '∪': IntRange.TryUnite, | 
|  | '∩': IntRange.TryIntersect, | 
|  | '+': IntRange.TryAdd, | 
|  | '-': IntRange.TrySub, | 
|  | '*': IntRange.TryMul, | 
|  | '/': IntRange.TryQuo, | 
|  | '«': IntRange.TryLsh, | 
|  | '»': IntRange.TryRsh, | 
|  | '&': IntRange.TryAnd, | 
|  | '|': IntRange.TryOr, | 
|  | } | 
|  |  | 
|  | var intOperatorsKeys []rune | 
|  |  | 
|  | func init() { | 
|  | for k := range intOperators { | 
|  | intOperatorsKeys = append(intOperatorsKeys, k) | 
|  | } | 
|  | sort.Slice(intOperatorsKeys, func(i, j int) bool { | 
|  | return intOperatorsKeys[i] < intOperatorsKeys[j] | 
|  | }) | 
|  | } | 
|  |  | 
|  | func TestOpUnite(tt *testing.T) { | 
|  | testOp(tt, | 
|  | "[   3,    3]  ∪  [  -5,   -5]  ==  [  -5,    3]", | 
|  | "[   3,    3]  ∪  [   0,    0]  ==  [   0,    3]", | 
|  | "[   0,    0]  ∪  [  -7,    7]  ==  [  -7,    7]", | 
|  | "[   0,    2]  ∪  [   0,    5]  ==  [   0,    5]", | 
|  | "[   3,    6]  ∪  [  10,   15]  ==  [   3,   15]", | 
|  | "[   3,   +∞)  ∪  [  -4,   -2]  ==  [  -4,   +∞)", | 
|  | "[   3,   +∞)  ∪  [  10,   15]  ==  [   3,   +∞)", | 
|  | "[   3,   +∞)  ∪  (  -∞,   15]  ==  (  -∞,   +∞)", | 
|  | "[   3,    6]  ∪  (  -∞,   15]  ==  (  -∞,   15]", | 
|  | "[   3,    6]  ∪  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  ∪  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  ∪  [   1,    2]  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  ∪  [   0,    0]  ==  (  -∞,   +∞)", | 
|  | "[   3,    6]  ∪  [...empty..]  ==  [   3,    6]", | 
|  | "[...empty..]  ∪  [  10,   15]  ==  [  10,   15]", | 
|  | "[...empty..]  ∪  [...empty..]  ==  [...empty..]", | 
|  | "(  -∞,   +∞)  ∪  [...empty..]  ==  (  -∞,   +∞)", | 
|  | ) | 
|  | } | 
|  |  | 
|  | func TestOpIntersect(tt *testing.T) { | 
|  | testOp(tt, | 
|  | "[   3,    3]  ∩  [  -5,   -5]  ==  [...empty..]", | 
|  | "[   3,    3]  ∩  [   0,    0]  ==  [...empty..]", | 
|  | "[   0,    0]  ∩  [  -7,    7]  ==  [   0,    0]", | 
|  | "[   0,    2]  ∩  [   0,    5]  ==  [   0,    2]", | 
|  | "[   3,    6]  ∩  [  10,   15]  ==  [...empty..]", | 
|  | "[   3,   +∞)  ∩  [  -4,   -2]  ==  [...empty..]", | 
|  | "[   3,   +∞)  ∩  [  10,   15]  ==  [  10,   15]", | 
|  | "[   3,   +∞)  ∩  (  -∞,   15]  ==  [   3,   15]", | 
|  | "[   3,    6]  ∩  (  -∞,   15]  ==  [   3,    6]", | 
|  | "[   3,    6]  ∩  (  -∞,   +∞)  ==  [   3,    6]", | 
|  | "(  -∞,   +∞)  ∩  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  ∩  [   1,    2]  ==  [   1,    2]", | 
|  | "(  -∞,   +∞)  ∩  [   0,    0]  ==  [   0,    0]", | 
|  | "[   3,    6]  ∩  [...empty..]  ==  [...empty..]", | 
|  | "[...empty..]  ∩  [  10,   15]  ==  [...empty..]", | 
|  | "[...empty..]  ∩  [...empty..]  ==  [...empty..]", | 
|  | "(  -∞,   +∞)  ∩  [...empty..]  ==  [...empty..]", | 
|  | ) | 
|  | } | 
|  |  | 
|  | func TestOpAdd(tt *testing.T) { | 
|  | testOp(tt, | 
|  | "[   3,    3]  +  [  -5,   -5]  ==  [  -2,   -2]", | 
|  | "[   3,    3]  +  [   0,    0]  ==  [   3,    3]", | 
|  | "[   0,    0]  +  [  -7,    7]  ==  [  -7,    7]", | 
|  | "[   0,    2]  +  [   0,    5]  ==  [   0,    7]", | 
|  | "[   3,    6]  +  [  10,   15]  ==  [  13,   21]", | 
|  | "[   3,   +∞)  +  [  -4,   -2]  ==  [  -1,   +∞)", | 
|  | "[   3,   +∞)  +  [  10,   15]  ==  [  13,   +∞)", | 
|  | "[   3,   +∞)  +  (  -∞,   15]  ==  (  -∞,   +∞)", | 
|  | "[   3,    6]  +  (  -∞,   15]  ==  (  -∞,   21]", | 
|  | "[   3,    6]  +  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  +  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  +  [   1,    2]  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  +  [   0,    0]  ==  (  -∞,   +∞)", | 
|  | "[   3,    6]  +  [...empty..]  ==  [...empty..]", | 
|  | "[...empty..]  +  [  10,   15]  ==  [...empty..]", | 
|  | "[...empty..]  +  [...empty..]  ==  [...empty..]", | 
|  | "(  -∞,   +∞)  +  [...empty..]  ==  [...empty..]", | 
|  | ) | 
|  | } | 
|  |  | 
|  | func TestOpSub(tt *testing.T) { | 
|  | testOp(tt, | 
|  | "[   3,    3]  -  [  -5,   -5]  ==  [   8,    8]", | 
|  | "[   3,    3]  -  [   0,    0]  ==  [   3,    3]", | 
|  | "[   0,    0]  -  [  -7,    7]  ==  [  -7,    7]", | 
|  | "[   0,    2]  -  [   0,    5]  ==  [  -5,    2]", | 
|  | "[   3,    6]  -  [  10,   15]  ==  [ -12,   -4]", | 
|  | "[   3,   +∞)  -  [  -4,   -2]  ==  [   5,   +∞)", | 
|  | "[   3,   +∞)  -  [  10,   15]  ==  [ -12,   +∞)", | 
|  | "[   3,   +∞)  -  (  -∞,   15]  ==  (  -∞,   +∞)", | 
|  | "[   3,    6]  -  (  -∞,   15]  ==  [ -12,   +∞)", | 
|  | "[   3,    6]  -  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  -  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  -  [   1,    2]  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  -  [   0,    0]  ==  (  -∞,   +∞)", | 
|  | "[   3,    6]  -  [...empty..]  ==  [...empty..]", | 
|  | "[...empty..]  -  [  10,   15]  ==  [...empty..]", | 
|  | "[...empty..]  -  [...empty..]  ==  [...empty..]", | 
|  | "(  -∞,   +∞)  -  [...empty..]  ==  [...empty..]", | 
|  | ) | 
|  | } | 
|  |  | 
|  | func TestOpMul(tt *testing.T) { | 
|  | testOp(tt, | 
|  | "[   3,    3]  *  [  -5,   -5]  ==  [ -15,  -15]", | 
|  | "[   3,    3]  *  [   0,    0]  ==  [   0,    0]", | 
|  | "[   0,    0]  *  [  -7,    7]  ==  [   0,    0]", | 
|  | "[   0,    2]  *  [   0,    5]  ==  [   0,   10]", | 
|  | "[   3,    6]  *  [  10,   15]  ==  [  30,   90]", | 
|  | "[   3,   +∞)  *  [  -4,   -2]  ==  (  -∞,   -6]", | 
|  | "[   3,   +∞)  *  [  10,   15]  ==  [  30,   +∞)", | 
|  | "[   3,   +∞)  *  (  -∞,   15]  ==  (  -∞,   +∞)", | 
|  | "[   3,    6]  *  (  -∞,   15]  ==  (  -∞,   90]", | 
|  | "[   3,    6]  *  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  *  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  *  [   1,    2]  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  *  [   0,    0]  ==  [   0,    0]", | 
|  | "[   3,    6]  *  [...empty..]  ==  [...empty..]", | 
|  | "[...empty..]  *  [  10,   15]  ==  [...empty..]", | 
|  | "[...empty..]  *  [...empty..]  ==  [...empty..]", | 
|  | "(  -∞,   +∞)  *  [...empty..]  ==  [...empty..]", | 
|  |  | 
|  | "[  -3,   -1]  *  [ -11,  -10]  ==  [  10,   33]", | 
|  | "[  -3,    0]  *  [ -11,  -10]  ==  [   0,   33]", | 
|  | "[  -3,    1]  *  [ -11,  -10]  ==  [ -11,   33]", | 
|  | "[  -3,    4]  *  [ -11,  -10]  ==  [ -44,   33]", | 
|  | "[  -1,    4]  *  [ -11,  -10]  ==  [ -44,   11]", | 
|  | "[   0,    4]  *  [ -11,  -10]  ==  [ -44,    0]", | 
|  | "[   1,    4]  *  [ -11,  -10]  ==  [ -44,  -10]", | 
|  |  | 
|  | "[  -3,   -1]  *  [  -6,    2]  ==  [  -6,   18]", | 
|  | "[  -3,    0]  *  [  -6,    2]  ==  [  -6,   18]", | 
|  | "[  -3,    1]  *  [  -6,    2]  ==  [  -6,   18]", | 
|  | "[  -3,    4]  *  [  -6,    2]  ==  [ -24,   18]", | 
|  | "[  -1,    4]  *  [  -6,    2]  ==  [ -24,    8]", | 
|  | "[   0,    4]  *  [  -6,    2]  ==  [ -24,    8]", | 
|  | "[   1,    4]  *  [  -6,    2]  ==  [ -24,    8]", | 
|  |  | 
|  | "[  -3,   -1]  *  [   0,    3]  ==  [  -9,    0]", | 
|  | "[  -3,    0]  *  [   0,    3]  ==  [  -9,    0]", | 
|  | "[  -3,    1]  *  [   0,    3]  ==  [  -9,    3]", | 
|  | "[  -3,    4]  *  [   0,    3]  ==  [  -9,   12]", | 
|  | "[  -1,    4]  *  [   0,    3]  ==  [  -3,   12]", | 
|  | "[   0,    4]  *  [   0,    3]  ==  [   0,   12]", | 
|  | "[   1,    4]  *  [   0,    3]  ==  [   0,   12]", | 
|  |  | 
|  | "[  -3,   -1]  *  [   2,    3]  ==  [  -9,   -2]", | 
|  | "[  -3,    0]  *  [   2,    3]  ==  [  -9,    0]", | 
|  | "[  -3,    1]  *  [   2,    3]  ==  [  -9,    3]", | 
|  | "[  -3,    4]  *  [   2,    3]  ==  [  -9,   12]", | 
|  | "[  -1,    4]  *  [   2,    3]  ==  [  -3,   12]", | 
|  | "[   0,    4]  *  [   2,    3]  ==  [   0,   12]", | 
|  | "[   1,    4]  *  [   2,    3]  ==  [   2,   12]", | 
|  |  | 
|  | "[  -9,   +∞)  *  [   2,   +∞)  ==  (  -∞,   +∞)", | 
|  | "[  -1,   +∞)  *  [   2,   +∞)  ==  (  -∞,   +∞)", | 
|  | "[   0,   +∞)  *  [   2,   +∞)  ==  [   0,   +∞)", | 
|  | "[   1,   +∞)  *  [   2,   +∞)  ==  [   2,   +∞)", | 
|  | "[   7,   +∞)  *  [   2,   +∞)  ==  [  14,   +∞)", | 
|  | "[  -1,    1]  *  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | "[   0,    0]  *  (  -∞,   +∞)  ==  [   0,    0]", | 
|  | "[   1,    1]  *  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | ) | 
|  | } | 
|  |  | 
|  | func TestOpQuo(tt *testing.T) { | 
|  | testOp(tt, | 
|  | "[   3,    3]  /  [  -5,   -5]  ==  [   0,    0]", | 
|  | "[   3,    3]  /  [   0,    0]  ==  invalid", | 
|  | "[   0,    0]  /  [  -7,    7]  ==  invalid", | 
|  | "[   0,    2]  /  [   0,    5]  ==  invalid", | 
|  | "[   3,    6]  /  [  10,   15]  ==  [   0,    0]", | 
|  | "[   3,   +∞)  /  [  -4,   -2]  ==  (  -∞,    0]", | 
|  | "[   3,   +∞)  /  [  10,   15]  ==  [   0,   +∞)", | 
|  | "[   3,   +∞)  /  (  -∞,   15]  ==  invalid", | 
|  | "[   3,    6]  /  (  -∞,   15]  ==  invalid", | 
|  | "[   3,    6]  /  (  -∞,   +∞)  ==  invalid", | 
|  | "(  -∞,   +∞)  /  (  -∞,   +∞)  ==  invalid", | 
|  | "(  -∞,   +∞)  /  [   1,    2]  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  /  [   0,    0]  ==  invalid", | 
|  | "[   3,    6]  /  [...empty..]  ==  [...empty..]", | 
|  | "[...empty..]  /  [  10,   15]  ==  [...empty..]", | 
|  | "[...empty..]  /  [...empty..]  ==  [...empty..]", | 
|  | "(  -∞,   +∞)  /  [...empty..]  ==  [...empty..]", | 
|  |  | 
|  | "[   1,    4]  /  [ -11,  -10]  ==  [   0,    0]", | 
|  |  | 
|  | "[   1,    4]  /  [  -6,    2]  ==  invalid", | 
|  |  | 
|  | "[  -3,   -1]  /  [   1,    3]  ==  [  -3,    0]", | 
|  | "[  -3,    0]  /  [   1,    3]  ==  [  -3,    0]", | 
|  | "[  -3,    1]  /  [   1,    3]  ==  [  -3,    1]", | 
|  | "[  -3,    4]  /  [   1,    3]  ==  [  -3,    4]", | 
|  | "[  -1,    4]  /  [   1,    3]  ==  [  -1,    4]", | 
|  | "[   0,    4]  /  [   1,    3]  ==  [   0,    4]", | 
|  | "[   1,    4]  /  [   1,    3]  ==  [   0,    4]", | 
|  |  | 
|  | "[  -3,   -1]  /  [   2,    3]  ==  [  -1,    0]", | 
|  | "[  -3,    0]  /  [   2,    3]  ==  [  -1,    0]", | 
|  | "[  -3,    1]  /  [   2,    3]  ==  [  -1,    0]", | 
|  | "[  -3,    4]  /  [   2,    3]  ==  [  -1,    2]", | 
|  | "[  -1,    4]  /  [   2,    3]  ==  [   0,    2]", | 
|  | "[   0,    4]  /  [   2,    3]  ==  [   0,    2]", | 
|  | "[   1,    4]  /  [   2,    3]  ==  [   0,    2]", | 
|  |  | 
|  | "[  -9,   +∞)  /  [   2,   +∞)  ==  [  -4,   +∞)", | 
|  | "[  -1,   +∞)  /  [   2,   +∞)  ==  [   0,   +∞)", | 
|  | "[   0,   +∞)  /  [   2,   +∞)  ==  [   0,   +∞)", | 
|  | "[   1,   +∞)  /  [   2,   +∞)  ==  [   0,   +∞)", | 
|  | "[   7,   +∞)  /  [   2,   +∞)  ==  [   0,   +∞)", | 
|  | "[  -1,    1]  /  (  -∞,   +∞)  ==  invalid", | 
|  | "[   0,    0]  /  (  -∞,   +∞)  ==  invalid", | 
|  | "[   1,    1]  /  (  -∞,   +∞)  ==  invalid", | 
|  | ) | 
|  | } | 
|  |  | 
|  | func TestOpLsh(tt *testing.T) { | 
|  | testOp(tt, | 
|  | "[   3,    3]  «  [  -5,   -5]  ==  invalid", | 
|  | "[   3,    3]  «  [   0,    0]  ==  [   3,    3]", | 
|  | "[   0,    0]  «  [  -7,    7]  ==  invalid", | 
|  | "[   0,    2]  «  [   0,    5]  ==  [   0,   64]", | 
|  | "[   3,    6]  «  [  10,   15]  ==  [3072, 196608]", | 
|  | "[   3,   +∞)  «  [  -4,   -2]  ==  invalid", | 
|  | "[   3,   +∞)  «  [  10,   15]  ==  [3072,   +∞)", | 
|  | "[   3,   +∞)  «  (  -∞,   15]  ==  invalid", | 
|  | "[   3,    6]  «  (  -∞,   15]  ==  invalid", | 
|  | "[   3,    6]  «  (  -∞,   +∞)  ==  invalid", | 
|  | "(  -∞,   +∞)  «  (  -∞,   +∞)  ==  invalid", | 
|  | "(  -∞,   +∞)  «  [   1,    2]  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  «  [   0,    0]  ==  (  -∞,   +∞)", | 
|  | "[   3,    6]  «  [...empty..]  ==  [...empty..]", | 
|  | "[...empty..]  «  [  10,   15]  ==  [...empty..]", | 
|  | "[...empty..]  «  [...empty..]  ==  [...empty..]", | 
|  | "(  -∞,   +∞)  «  [...empty..]  ==  [...empty..]", | 
|  |  | 
|  | "[   1,    4]  «  [ -11,  -10]  ==  invalid", | 
|  |  | 
|  | "[   1,    4]  «  [  -6,    2]  ==  invalid", | 
|  |  | 
|  | "[  -3,   -1]  «  [   0,    3]  ==  [ -24,   -1]", | 
|  | "[  -3,    0]  «  [   0,    3]  ==  [ -24,    0]", | 
|  | "[  -3,    1]  «  [   0,    3]  ==  [ -24,    8]", | 
|  | "[  -3,    4]  «  [   0,    3]  ==  [ -24,   32]", | 
|  | "[  -1,    4]  «  [   0,    3]  ==  [  -8,   32]", | 
|  | "[   0,    4]  «  [   0,    3]  ==  [   0,   32]", | 
|  | "[   1,    4]  «  [   0,    3]  ==  [   1,   32]", | 
|  |  | 
|  | "[  -3,   -1]  «  [   2,    3]  ==  [ -24,   -4]", | 
|  | "[  -3,    0]  «  [   2,    3]  ==  [ -24,    0]", | 
|  | "[  -3,    1]  «  [   2,    3]  ==  [ -24,    8]", | 
|  | "[  -3,    4]  «  [   2,    3]  ==  [ -24,   32]", | 
|  | "[  -1,    4]  «  [   2,    3]  ==  [  -8,   32]", | 
|  | "[   0,    4]  «  [   2,    3]  ==  [   0,   32]", | 
|  | "[   1,    4]  «  [   2,    3]  ==  [   4,   32]", | 
|  |  | 
|  | "[  -9,   +∞)  «  [   2,   +∞)  ==  (  -∞,   +∞)", | 
|  | "[  -1,   +∞)  «  [   2,   +∞)  ==  (  -∞,   +∞)", | 
|  | "[   0,   +∞)  «  [   2,   +∞)  ==  [   0,   +∞)", | 
|  | "[   1,   +∞)  «  [   2,   +∞)  ==  [   4,   +∞)", | 
|  | "[   7,   +∞)  «  [   2,   +∞)  ==  [  28,   +∞)", | 
|  | "[  -1,    1]  «  (  -∞,   +∞)  ==  invalid", | 
|  | "[   0,    0]  «  (  -∞,   +∞)  ==  invalid", | 
|  | "[   1,    1]  «  (  -∞,   +∞)  ==  invalid", | 
|  | ) | 
|  | } | 
|  |  | 
|  | func TestOpRsh(tt *testing.T) { | 
|  | testOp(tt, | 
|  | "[   3,    3]  »  [  -5,   -5]  ==  invalid", | 
|  | "[   3,    3]  »  [   0,    0]  ==  [   3,    3]", | 
|  | "[   0,    0]  »  [  -7,    7]  ==  invalid", | 
|  | "[   0,    2]  »  [   0,    5]  ==  [   0,    2]", | 
|  | "[   3,    6]  »  [  10,   15]  ==  [   0,    0]", | 
|  | "[   3,   +∞)  »  [  -4,   -2]  ==  invalid", | 
|  | "[   3,   +∞)  »  [  10,   15]  ==  [   0,   +∞)", | 
|  | "[   3,   +∞)  »  (  -∞,   15]  ==  invalid", | 
|  | "[   3,    6]  »  (  -∞,   15]  ==  invalid", | 
|  | "[   3,    6]  »  (  -∞,   +∞)  ==  invalid", | 
|  | "(  -∞,   +∞)  »  (  -∞,   +∞)  ==  invalid", | 
|  | "(  -∞,   +∞)  »  [   1,    2]  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  »  [   0,    0]  ==  (  -∞,   +∞)", | 
|  | "[   3,    6]  »  [...empty..]  ==  [...empty..]", | 
|  | "[...empty..]  »  [  10,   15]  ==  [...empty..]", | 
|  | "[...empty..]  »  [...empty..]  ==  [...empty..]", | 
|  | "(  -∞,   +∞)  »  [...empty..]  ==  [...empty..]", | 
|  |  | 
|  | "[   1,    4]  »  [ -11,  -10]  ==  invalid", | 
|  |  | 
|  | "[   1,    4]  »  [  -6,    2]  ==  invalid", | 
|  |  | 
|  | "[  -3,   -1]  »  [   0,    3]  ==  [  -3,   -1]", | 
|  | "[  -3,    0]  »  [   0,    3]  ==  [  -3,    0]", | 
|  | "[  -3,    1]  »  [   0,    3]  ==  [  -3,    1]", | 
|  | "[  -3,    4]  »  [   0,    3]  ==  [  -3,    4]", | 
|  | "[  -1,    4]  »  [   0,    3]  ==  [  -1,    4]", | 
|  | "[   0,    4]  »  [   0,    3]  ==  [   0,    4]", | 
|  | "[   1,    4]  »  [   0,    3]  ==  [   0,    4]", | 
|  |  | 
|  | "[  -3,   -1]  »  [   1,    3]  ==  [  -2,   -1]", | 
|  | "[  -3,    0]  »  [   1,    3]  ==  [  -2,    0]", | 
|  | "[  -3,    1]  »  [   1,    3]  ==  [  -2,    0]", | 
|  | "[  -3,    4]  »  [   1,    3]  ==  [  -2,    2]", | 
|  | "[  -1,    4]  »  [   1,    3]  ==  [  -1,    2]", | 
|  | "[   0,    4]  »  [   1,    3]  ==  [   0,    2]", | 
|  | "[   1,    4]  »  [   1,    3]  ==  [   0,    2]", | 
|  |  | 
|  | "[  -9,   +∞)  »  [   2,   +∞)  ==  [  -3,   +∞)", | 
|  | "[  -1,   +∞)  »  [   2,   +∞)  ==  [  -1,   +∞)", | 
|  | "[   0,   +∞)  »  [   2,   +∞)  ==  [   0,   +∞)", | 
|  | "[   1,   +∞)  »  [   2,   +∞)  ==  [   0,   +∞)", | 
|  | "[   7,   +∞)  »  [   2,   +∞)  ==  [   0,   +∞)", | 
|  | "[  -1,    1]  »  (  -∞,   +∞)  ==  invalid", | 
|  | "[   0,    0]  »  (  -∞,   +∞)  ==  invalid", | 
|  | "[   1,    1]  »  (  -∞,   +∞)  ==  invalid", | 
|  | ) | 
|  | } | 
|  |  | 
|  | func TestOpAnd(tt *testing.T) { | 
|  | testOp(tt, | 
|  | "[   3,    3]  &  [  -5,   -5]  ==  [   3,    3]", | 
|  | "[   3,    3]  &  [   0,    0]  ==  [   0,    0]", | 
|  | "[   0,    0]  &  [  -7,    7]  ==  [   0,    0]", | 
|  | "[   0,    2]  &  [   0,    5]  ==  [   0,    2]", | 
|  | "[   3,    6]  &  [  10,   15]  ==  [   0,    6]", | 
|  | "[   3,   +∞)  &  [  -4,   -2]  ==  [   0,   +∞)", | 
|  | "[   3,   +∞)  &  [  10,   15]  ==  [   0,   15]", | 
|  | "[   3,   +∞)  &  (  -∞,   15]  ==  [   0,   +∞)", | 
|  | "[   3,    6]  &  (  -∞,   15]  ==  [   0,    6]", | 
|  | "[   3,    6]  &  (  -∞,   +∞)  ==  [   0,    6]", | 
|  | "(  -∞,   +∞)  &  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  &  [   1,    2]  ==  [   0,    2]", | 
|  | "(  -∞,   +∞)  &  [   0,    0]  ==  [   0,    0]", | 
|  | "[   3,    6]  &  [...empty..]  ==  [...empty..]", | 
|  | "[...empty..]  &  [  10,   15]  ==  [...empty..]", | 
|  | "[...empty..]  &  [...empty..]  ==  [...empty..]", | 
|  | "(  -∞,   +∞)  &  [...empty..]  ==  [...empty..]", | 
|  |  | 
|  | "[   1,    4]  &  [ -11,  -10]  ==  [   0,    4]", | 
|  |  | 
|  | "[   1,    4]  &  [  -6,    2]  ==  [   0,    4]", | 
|  |  | 
|  | "[  -3,   -1]  &  [   0,    3]  ==  [   0,    3]", | 
|  | "[  -1,    4]  &  [   0,    3]  ==  [   0,    3]", | 
|  | "[   0,    4]  &  [   0,    3]  ==  [   0,    3]", | 
|  | "[   1,    4]  &  [   0,    3]  ==  [   0,    3]", | 
|  |  | 
|  | "[  -3,   -1]  &  [   2,    3]  ==  [   0,    3]", | 
|  | "[  -1,    4]  &  [   2,    3]  ==  [   0,    3]", | 
|  | "[   0,    4]  &  [   2,    3]  ==  [   0,    3]", | 
|  | "[   1,    4]  &  [   2,    3]  ==  [   0,    3]", | 
|  |  | 
|  | "[  -9,   +∞)  &  [   2,   +∞)  ==  [   0,   +∞)", | 
|  | "[  -1,   +∞)  &  [   2,   +∞)  ==  [   0,   +∞)", | 
|  | "[   0,   +∞)  &  [   2,   +∞)  ==  [   0,   +∞)", | 
|  | "[   1,   +∞)  &  [   2,   +∞)  ==  [   0,   +∞)", | 
|  | "[   7,   +∞)  &  [   2,   +∞)  ==  [   0,   +∞)", | 
|  | "[  -1,    1]  &  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | "[   0,    0]  &  (  -∞,   +∞)  ==  [   0,    0]", | 
|  | "[   1,    1]  &  (  -∞,   +∞)  ==  [   0,    1]", | 
|  |  | 
|  | "[   1,    3]  &  [   4,    9]  ==  [   0,    3]", | 
|  | "[   3,    4]  &  [   5,    6]  ==  [   1,    4]", | 
|  | "[   4,    5]  &  [   6,    7]  ==  [   4,    5]", | 
|  | "[   7,    7]  &  [  12,   14]  ==  [   4,    6]", | 
|  |  | 
|  | "[   5,    6]  &  [   6,    7]  ==  [   4,    6]", | 
|  | "[   5,    6]  &  [   6,    8]  ==  [   0,    6]", | 
|  | "[   5,    9]  &  [   6,    8]  ==  [   0,    8]", | 
|  | "[   5,    9]  &  [   6,    9]  ==  [   0,    9]", | 
|  |  | 
|  | "[   5,    6]  &  [   3,   +∞)  ==  [   0,    6]", | 
|  | "[   5,    9]  &  [   3,   +∞)  ==  [   0,    9]", | 
|  | "[   5,    6]  &  [   7,   +∞)  ==  [   0,    6]", | 
|  | "[   5,    9]  &  [   7,   +∞)  ==  [   0,    9]", | 
|  | "[   5,    6]  &  [   8,   +∞)  ==  [   0,    6]", | 
|  | "[   5,    9]  &  [   8,   +∞)  ==  [   0,    9]", | 
|  | "[   5,    6]  &  [   9,   +∞)  ==  [   0,    6]", | 
|  | "[   5,    9]  &  [   9,   +∞)  ==  [   0,    9]", | 
|  | "[   5,    6]  &  [  12,   +∞)  ==  [   0,    6]", | 
|  | "[   5,    9]  &  [  12,   +∞)  ==  [   0,    9]", | 
|  |  | 
|  | "(  -∞,   -3]  &  [  -3,   -2]  ==  (  -∞,   -3]", | 
|  | "[   2,   +∞)  &  [   1,    2]  ==  [   0,    2]", | 
|  | ) | 
|  | } | 
|  |  | 
|  | func TestOpOr(tt *testing.T) { | 
|  | testOp(tt, | 
|  | "[   3,    3]  |  [  -5,   -5]  ==  [  -5,   -5]", | 
|  | "[   3,    3]  |  [   0,    0]  ==  [   3,    3]", | 
|  | "[   0,    0]  |  [  -7,    7]  ==  [  -7,    7]", | 
|  | "[   0,    2]  |  [   0,    5]  ==  [   0,    7]", | 
|  | "[   3,    6]  |  [  10,   15]  ==  [  11,   15]", | 
|  | "[   3,   +∞)  |  [  -4,   -2]  ==  [  -4,   -1]", | 
|  | "[   3,   +∞)  |  [  10,   15]  ==  [  10,   +∞)", | 
|  | "[   3,   +∞)  |  (  -∞,   15]  ==  (  -∞,   +∞)", | 
|  | "[   3,    6]  |  (  -∞,   15]  ==  (  -∞,   15]", | 
|  | "[   3,    6]  |  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  |  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  |  [   1,    2]  ==  (  -∞,   +∞)", | 
|  | "(  -∞,   +∞)  |  [   0,    0]  ==  (  -∞,   +∞)", | 
|  | "[   3,    6]  |  [...empty..]  ==  [...empty..]", | 
|  | "[...empty..]  |  [  10,   15]  ==  [...empty..]", | 
|  | "[...empty..]  |  [...empty..]  ==  [...empty..]", | 
|  | "(  -∞,   +∞)  |  [...empty..]  ==  [...empty..]", | 
|  |  | 
|  | "[   1,    4]  |  [ -11,  -10]  ==  [ -11,   -9]", | 
|  |  | 
|  | "[   1,    4]  |  [  -6,    2]  ==  [  -6,    6]", | 
|  |  | 
|  | "[  -3,   -1]  |  [   0,    3]  ==  [  -3,   -1]", | 
|  | "[  -1,    4]  |  [   0,    3]  ==  [  -1,    7]", | 
|  | "[   0,    4]  |  [   0,    3]  ==  [   0,    7]", | 
|  | "[   1,    4]  |  [   0,    3]  ==  [   1,    7]", | 
|  |  | 
|  | "[  -3,   -1]  |  [   2,    3]  ==  [  -2,   -1]", | 
|  | "[  -1,    4]  |  [   2,    3]  ==  [  -1,    7]", | 
|  | "[   0,    4]  |  [   2,    3]  ==  [   2,    7]", | 
|  | "[   1,    4]  |  [   2,    3]  ==  [   2,    7]", | 
|  |  | 
|  | "[  -9,   +∞)  |  [   2,   +∞)  ==  [  -9,   +∞)", | 
|  | "[  -1,   +∞)  |  [   2,   +∞)  ==  [  -1,   +∞)", | 
|  | "[   0,   +∞)  |  [   2,   +∞)  ==  [   2,   +∞)", | 
|  | "[   1,   +∞)  |  [   2,   +∞)  ==  [   2,   +∞)", | 
|  | "[   7,   +∞)  |  [   2,   +∞)  ==  [   7,   +∞)", | 
|  | "[  -1,    1]  |  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | "[   0,    0]  |  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  | "[   1,    1]  |  (  -∞,   +∞)  ==  (  -∞,   +∞)", | 
|  |  | 
|  | "[   1,    3]  |  [   4,    9]  ==  [   5,   11]", | 
|  | "[   3,    4]  |  [   5,    6]  ==  [   5,    7]", | 
|  | "[   4,    5]  |  [   6,    7]  ==  [   6,    7]", | 
|  | "[   7,    7]  |  [  12,   14]  ==  [  15,   15]", | 
|  |  | 
|  | "[   5,    6]  |  [   6,    7]  ==  [   6,    7]", | 
|  | "[   5,    6]  |  [   6,    8]  ==  [   6,   14]", | 
|  | "[   5,    9]  |  [   6,    8]  ==  [   6,   15]", | 
|  | "[   5,    9]  |  [   6,    9]  ==  [   6,   15]", | 
|  |  | 
|  | "[   5,    6]  |  [   3,   +∞)  ==  [   5,   +∞)", | 
|  | "[   5,    9]  |  [   3,   +∞)  ==  [   5,   +∞)", | 
|  | "[   5,    6]  |  [   7,   +∞)  ==  [   7,   +∞)", | 
|  | "[   5,    9]  |  [   7,   +∞)  ==  [   7,   +∞)", | 
|  | "[   5,    6]  |  [   8,   +∞)  ==  [  13,   +∞)", | 
|  | "[   5,    9]  |  [   8,   +∞)  ==  [   8,   +∞)", | 
|  | "[   5,    6]  |  [   9,   +∞)  ==  [  13,   +∞)", | 
|  | "[   5,    9]  |  [   9,   +∞)  ==  [   9,   +∞)", | 
|  | "[   5,    6]  |  [  12,   +∞)  ==  [  13,   +∞)", | 
|  | "[   5,    9]  |  [  12,   +∞)  ==  [  12,   +∞)", | 
|  |  | 
|  | "(  -∞,   -3]  |  [  -3,   -2]  ==  [  -3,   -1]", | 
|  | "[   2,   +∞)  |  [   1,    2]  ==  [   2,   +∞)", | 
|  | ) | 
|  | } | 
|  |  | 
|  | func TestOpAndWithMinusOne(tt *testing.T) { | 
|  | minusOne := IntRange{big.NewInt(-1), big.NewInt(-1)} | 
|  | for _, x0 := range fromNeg3ToPos3 { | 
|  | for _, x1 := range fromNeg3ToPos3 { | 
|  | x := IntRange{x0, x1} | 
|  | want := x | 
|  |  | 
|  | if got := x.And(minusOne); !got.Eq(want) { | 
|  | tt.Fatalf("%v & -1: got %v, want %v", x, got, want) | 
|  | } | 
|  | if got := minusOne.And(x); !got.Eq(want) { | 
|  | tt.Fatalf("-1 & %v: got %v, want %v", x, got, want) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestOpAndWithZero(tt *testing.T) { | 
|  | zero := IntRange{big.NewInt(+0), big.NewInt(+0)} | 
|  | for _, x0 := range fromNeg3ToPos3 { | 
|  | for _, x1 := range fromNeg3ToPos3 { | 
|  | x := IntRange{x0, x1} | 
|  | want := zero | 
|  | if x.Empty() { | 
|  | want = sharedEmptyRange | 
|  | } | 
|  |  | 
|  | if got := x.And(zero); !got.Eq(want) { | 
|  | tt.Fatalf("%v & +0: got %v, want %v", x, got, want) | 
|  | } | 
|  | if got := zero.And(x); !got.Eq(want) { | 
|  | tt.Fatalf("+0 & %v: got %v, want %v", x, got, want) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestOpOrWithMinusOne(tt *testing.T) { | 
|  | minusOne := IntRange{big.NewInt(-1), big.NewInt(-1)} | 
|  | for _, x0 := range fromNeg3ToPos3 { | 
|  | for _, x1 := range fromNeg3ToPos3 { | 
|  | x := IntRange{x0, x1} | 
|  | want := minusOne | 
|  | if x.Empty() { | 
|  | want = sharedEmptyRange | 
|  | } | 
|  |  | 
|  | if got := x.Or(minusOne); !got.Eq(want) { | 
|  | tt.Fatalf("%v | -1: got %v, want %v", x, got, want) | 
|  | } | 
|  | if got := minusOne.Or(x); !got.Eq(want) { | 
|  | tt.Fatalf("-1 | %v: got %v, want %v", x, got, want) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestOpOrWithZero(tt *testing.T) { | 
|  | zero := IntRange{big.NewInt(+0), big.NewInt(+0)} | 
|  | for _, x0 := range fromNeg3ToPos3 { | 
|  | for _, x1 := range fromNeg3ToPos3 { | 
|  | x := IntRange{x0, x1} | 
|  | want := x | 
|  |  | 
|  | if got := x.Or(zero); !got.Eq(want) { | 
|  | tt.Fatalf("%v | +0: got %v, want %v", x, got, want) | 
|  | } | 
|  | if got := zero.Or(x); !got.Eq(want) { | 
|  | tt.Fatalf("+0 | %v: got %v, want %v", x, got, want) | 
|  | } | 
|  | } | 
|  | } | 
|  | } |