blob: 492f8eb7b166520ad4fabc37d3084ffad5449aa1 [file] [log] [blame]
// 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, +∞)",
)
}