| // 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" |
| ) |
| |
| // 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{ |
| empty(), |
| } |
| |
| 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(empty()) { |
| tt.Errorf("%v eq %v: got %t, want %t", x, empty(), 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, negEmpty, hasZero, posEmpty := x.split() |
| 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 testBruteForceAgrees(x IntRange, y IntRange, opKey string) error { |
| brute, bruteOK := bruteForce(x, y, opKey) |
| got, gotOK := intOperators[opKey](x, y) |
| 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) { |
| ints := []*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, |
| } |
| |
| for _, opKey := range intOperatorsKeys { |
| |
| for _, x0 := range ints { |
| for _, x1 := range ints { |
| x := IntRange{x0, x1} |
| |
| for _, y0 := range ints { |
| for _, y1 := range ints { |
| y := IntRange{y0, y1} |
| |
| if err := testBruteForceAgrees(x, y, opKey); err != nil { |
| tt.Fatalf("%v %s %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 %s %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, s := s[:i], 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("package code: got %v, %t, want %v, %t", got, gotOK, want, wantOK) |
| } |
| return nil |
| } |
| |
| var intOperators = map[string]func(IntRange, IntRange) (IntRange, bool){ |
| "+": func(x IntRange, y IntRange) (z IntRange, ok bool) { return x.Add(y), true }, |
| "-": func(x IntRange, y IntRange) (z IntRange, ok bool) { return x.Sub(y), true }, |
| "*": func(x IntRange, y IntRange) (z IntRange, ok bool) { return x.Mul(y), true }, |
| "/": IntRange.Quo, |
| "<<": IntRange.Lsh, |
| ">>": IntRange.Rsh, |
| "&": IntRange.And, |
| "|": IntRange.Or, |
| } |
| |
| var intOperatorsKeys []string |
| |
| func init() { |
| for k := range intOperators { |
| intOperatorsKeys = append(intOperatorsKeys, k) |
| } |
| sort.Strings(intOperatorsKeys) |
| } |
| |
| 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] == invalid", |
| "[ 3, 3] & [ 0, 0] == [ 0, 0]", |
| "[ 0, 0] & [ -7, 7] == invalid", |
| "[ 0, 2] & [ 0, 5] == [ 0, 2]", |
| "[ 3, 6] & [ 10, 15] == [ 0, 6]", |
| "[ 3, +∞) & [ -4, -2] == invalid", |
| "[ 3, +∞) & [ 10, 15] == [ 0, 15]", |
| "[ 3, +∞) & ( -∞, 15] == invalid", |
| "[ 3, 6] & ( -∞, 15] == invalid", |
| "[ 3, 6] & ( -∞, +∞) == invalid", |
| "( -∞, +∞) & ( -∞, +∞) == invalid", |
| "( -∞, +∞) & [ 1, 2] == invalid", |
| "( -∞, +∞) & [ 0, 0] == invalid", |
| "[ 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] == invalid", |
| "[ -1, 4] & [ 0, 3] == invalid", |
| "[ 0, 4] & [ 0, 3] == [ 0, 3]", |
| "[ 1, 4] & [ 0, 3] == [ 0, 3]", |
| |
| "[ -3, -1] & [ 2, 3] == invalid", |
| "[ -1, 4] & [ 2, 3] == invalid", |
| "[ 0, 4] & [ 2, 3] == [ 0, 3]", |
| "[ 1, 4] & [ 2, 3] == [ 0, 3]", |
| |
| "[ -9, +∞) & [ 2, +∞) == invalid", |
| "[ -1, +∞) & [ 2, +∞) == invalid", |
| "[ 0, +∞) & [ 2, +∞) == [ 0, +∞)", |
| "[ 1, +∞) & [ 2, +∞) == [ 0, +∞)", |
| "[ 7, +∞) & [ 2, +∞) == [ 0, +∞)", |
| "[ -1, 1] & ( -∞, +∞) == invalid", |
| "[ 0, 0] & ( -∞, +∞) == invalid", |
| "[ 1, 1] & ( -∞, +∞) == invalid", |
| |
| "[ 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]", |
| ) |
| } |
| |
| func TestOpOr(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, 7]", |
| "[ 3, 6] | [ 10, 15] == [ 11, 15]", |
| "[ 3, +∞) | [ -4, -2] == invalid", |
| "[ 3, +∞) | [ 10, 15] == [ 10, +∞)", |
| "[ 3, +∞) | ( -∞, 15] == invalid", |
| "[ 3, 6] | ( -∞, 15] == invalid", |
| "[ 3, 6] | ( -∞, +∞) == invalid", |
| "( -∞, +∞) | ( -∞, +∞) == invalid", |
| "( -∞, +∞) | [ 1, 2] == invalid", |
| "( -∞, +∞) | [ 0, 0] == invalid", |
| "[ 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] == invalid", |
| "[ -1, 4] | [ 0, 3] == invalid", |
| "[ 0, 4] | [ 0, 3] == [ 0, 7]", |
| "[ 1, 4] | [ 0, 3] == [ 1, 7]", |
| |
| "[ -3, -1] | [ 2, 3] == invalid", |
| "[ -1, 4] | [ 2, 3] == invalid", |
| "[ 0, 4] | [ 2, 3] == [ 2, 7]", |
| "[ 1, 4] | [ 2, 3] == [ 2, 7]", |
| |
| "[ -9, +∞) | [ 2, +∞) == invalid", |
| "[ -1, +∞) | [ 2, +∞) == invalid", |
| "[ 0, +∞) | [ 2, +∞) == [ 2, +∞)", |
| "[ 1, +∞) | [ 2, +∞) == [ 2, +∞)", |
| "[ 7, +∞) | [ 2, +∞) == [ 7, +∞)", |
| "[ -1, 1] | ( -∞, +∞) == invalid", |
| "[ 0, 0] | ( -∞, +∞) == invalid", |
| "[ 1, 1] | ( -∞, +∞) == invalid", |
| |
| "[ 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, +∞)", |
| ) |
| } |