439 lines
12 KiB
Go
439 lines
12 KiB
Go
// Copyright 2017 Google Inc.
|
|
//
|
|
// 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
|
|
//
|
|
// http://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 sets
|
|
|
|
import (
|
|
"sort"
|
|
"testing"
|
|
)
|
|
|
|
func checkSameIntSet(t *testing.T, set *IntSet, unique []int) {
|
|
// Check that lengths are the same.
|
|
want := len(unique)
|
|
got := set.Len()
|
|
|
|
if got != want {
|
|
t.Errorf("NewIntSet(%v) want length %v, got %v", unique, want, got)
|
|
}
|
|
|
|
// Check that all ints are present in set.
|
|
for _, s := range unique {
|
|
want := true
|
|
got := set.Contains(s)
|
|
|
|
if got != want {
|
|
t.Errorf("Contains(%v) want %v, got %v", s, want, got)
|
|
}
|
|
}
|
|
|
|
// Check that all elements are present in ints.
|
|
sort.Ints(unique)
|
|
|
|
for i, got := range set.Sorted() {
|
|
want := unique[i]
|
|
if got != want {
|
|
t.Errorf("Sorted(%d) want %v, got %v", i, want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
type enumTest int
|
|
|
|
const (
|
|
et0 enumTest = iota
|
|
et1
|
|
et2
|
|
et3
|
|
et4
|
|
)
|
|
|
|
func TestNewIntSet(t *testing.T) {
|
|
empty := NewIntSet()
|
|
want := 0
|
|
got := empty.Len()
|
|
|
|
if got != want {
|
|
t.Errorf("NewIntSet() want length %v, got %v", want, got)
|
|
}
|
|
|
|
unique := []int{0, 1, 2}
|
|
set := NewIntSet(unique...)
|
|
checkSameIntSet(t, set, unique)
|
|
|
|
// Append an already-present element.
|
|
nonUnique := append(unique, unique[0])
|
|
set = NewIntSet(nonUnique...)
|
|
|
|
// Non-unique unique should collapse to one.
|
|
want = len(unique)
|
|
got = set.Len()
|
|
|
|
if got != want {
|
|
t.Errorf("NewIntSet(%v) want length %v, got %v", nonUnique, want, got)
|
|
}
|
|
|
|
// Initialize with enum values cast to int.
|
|
set = NewIntSet(int(et0), int(et1), int(et2))
|
|
checkSameIntSet(t, set, unique)
|
|
}
|
|
|
|
func TestIntSet_Copy(t *testing.T) {
|
|
// Check both copies represent the same set.
|
|
base := []int{1, 2, 3}
|
|
orig := NewIntSet(base...)
|
|
cpy := orig.Copy()
|
|
checkSameIntSet(t, orig, base)
|
|
checkSameIntSet(t, cpy, base)
|
|
|
|
// Check the two copies are independent.
|
|
more := []int{4}
|
|
orig.Insert(more...)
|
|
more = append(base, more...)
|
|
checkSameIntSet(t, orig, more)
|
|
checkSameIntSet(t, cpy, base)
|
|
}
|
|
|
|
func TestIntSet_Insert(t *testing.T) {
|
|
unique := []int{0, 1, 2}
|
|
set := NewIntSet(unique...)
|
|
|
|
// Insert existing element, which should basically be a no-op.
|
|
set.Insert(unique[0])
|
|
checkSameIntSet(t, set, unique)
|
|
|
|
// Actually insert new unique elements (cast from enum values this time).
|
|
additional := []int{int(et3), int(et4)}
|
|
longer := append(unique, additional...)
|
|
set.Insert(additional...)
|
|
checkSameIntSet(t, set, longer)
|
|
}
|
|
|
|
func TestIntSet_Delete(t *testing.T) {
|
|
unique := []int{0, 1, 2}
|
|
set := NewIntSet(unique...)
|
|
|
|
// Delete non-existent element, which should basically be a no-op.
|
|
set.Delete(int(et4))
|
|
checkSameIntSet(t, set, unique)
|
|
|
|
// Actually delete existing elements.
|
|
set.Delete(unique[1:]...)
|
|
checkSameIntSet(t, set, unique[:1])
|
|
}
|
|
|
|
func TestIntSet_Intersect(t *testing.T) {
|
|
input1 := []int{1, 3, 4, 5, 6}
|
|
input2 := []int{2, 3, 5}
|
|
|
|
// Check Intersect(nil) returns an empty set.
|
|
setA := NewIntSet(input1...)
|
|
got := setA.Intersect(nil)
|
|
checkSameIntSet(t, got, []int{})
|
|
// Check that the receiver is unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
|
|
// Check Intersect returns the correct result.
|
|
setB := NewIntSet(input2...)
|
|
got = setA.Intersect(setB)
|
|
want := []int{3, 5}
|
|
checkSameIntSet(t, got, want)
|
|
// Also check the sources are unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
checkSameIntSet(t, setB, input2)
|
|
|
|
// Reverse the inputs and verify Intersect produces the same results.
|
|
setA = NewIntSet(input2...)
|
|
setB = NewIntSet(input1...)
|
|
got = setA.Intersect(setB)
|
|
checkSameIntSet(t, got, want)
|
|
// Check the sources are again unchanged.
|
|
checkSameIntSet(t, setA, input2)
|
|
checkSameIntSet(t, setB, input1)
|
|
}
|
|
|
|
func TestIntSet_Disjoint(t *testing.T) {
|
|
input1 := []int{1, 3, 4, 5, 6}
|
|
input2 := []int{2, 3, 5}
|
|
input3 := []int{98, 99, 100}
|
|
|
|
// Check that sets are always disjoint with the empty set or nil
|
|
setA := NewIntSet(input1...)
|
|
emptySet := NewIntSet()
|
|
|
|
if disjoint := setA.Disjoint(nil); !disjoint {
|
|
t.Errorf("Disjoint(%s, %v) want %v, got %v", setA, nil, true, disjoint)
|
|
}
|
|
|
|
if disjoint := setA.Disjoint(emptySet); !disjoint {
|
|
t.Errorf("Disjoint(%s, %s) want %v, got %v", setA, emptySet, true, disjoint)
|
|
}
|
|
|
|
if disjoint := emptySet.Disjoint(setA); !disjoint {
|
|
t.Errorf("Disjoint(%s, %s) want %v, got %v", emptySet, setA, true, disjoint)
|
|
}
|
|
|
|
if disjoint := emptySet.Disjoint(emptySet); !disjoint {
|
|
t.Errorf("Disjoint(%s, %s) want %v, got %v", emptySet, emptySet, true, disjoint)
|
|
}
|
|
|
|
// Also check the sources are unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
checkSameIntSet(t, emptySet, []int{})
|
|
|
|
// Check two non-empty, non-nil disjoint sets.
|
|
setC := NewIntSet(input3...)
|
|
|
|
if disjoint := setA.Disjoint(setC); !disjoint {
|
|
t.Errorf("Disjoint(%s, %s) want %v, got %v", setA, setC, true, disjoint)
|
|
}
|
|
|
|
// Also check the sources are unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
checkSameIntSet(t, setC, input3)
|
|
|
|
// Check that two intersecting sets are not Disjoint.
|
|
setB := NewIntSet(input2...)
|
|
|
|
if disjoint := setA.Disjoint(setB); disjoint {
|
|
t.Errorf("Disjoint(%s, %s) want %v, got %v", setA, setB, false, disjoint)
|
|
}
|
|
|
|
// Also check the sources are unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
checkSameIntSet(t, setB, input2)
|
|
}
|
|
|
|
func TestIntSet_Difference(t *testing.T) {
|
|
input1 := []int{1, 3, 4, 5, 6}
|
|
input2 := []int{2, 3, 5}
|
|
input3 := []int{98, 99, 100}
|
|
|
|
// Check Difference(nil) returns a copy of the receiver.
|
|
setA := NewIntSet(input1...)
|
|
got := setA.Difference(nil)
|
|
checkSameIntSet(t, got, input1)
|
|
// Check that the receiver is unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
|
|
// Check A - A returns the empty set.
|
|
got = setA.Difference(setA)
|
|
|
|
if !got.Empty() {
|
|
t.Errorf("Difference(%s, %s).Empty() want %v, got %v",
|
|
setA, setA, true, false)
|
|
}
|
|
|
|
checkSameIntSet(t, got, []int{})
|
|
// Check that the receiver is unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
|
|
// Check A - C simply returns elements in A if A and C are disjoint.
|
|
setC := NewIntSet(input3...)
|
|
got = setA.Difference(setC)
|
|
checkSameIntSet(t, got, input1)
|
|
// Also check the sources are unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
checkSameIntSet(t, setC, input3)
|
|
|
|
// Check A - B returns elements in A not in B.
|
|
setB := NewIntSet(input2...)
|
|
got = setA.Difference(setB)
|
|
want := []int{1, 4, 6}
|
|
checkSameIntSet(t, got, want)
|
|
|
|
// Also check the sources are unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
checkSameIntSet(t, setB, input2)
|
|
|
|
// Check B - A returns elements in B not in A.
|
|
got = setB.Difference(setA)
|
|
want = []int{2}
|
|
checkSameIntSet(t, got, want)
|
|
// Also check the sources are unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
checkSameIntSet(t, setB, input2)
|
|
}
|
|
|
|
func TestIntSet_Unique(t *testing.T) {
|
|
input1 := []int{1, 3, 4, 5, 6}
|
|
input2 := []int{2, 3, 5}
|
|
input3 := []int{98, 99, 100}
|
|
|
|
// Check Unique(nil) returns a copy of the receiver.
|
|
setA := NewIntSet(input1...)
|
|
got := setA.Unique(nil)
|
|
checkSameIntSet(t, got, input1)
|
|
// Check that the receiver is unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
|
|
// Check Unique returns only elements in A and B not in both A and B.
|
|
setB := NewIntSet(input2...)
|
|
got = setA.Unique(setB)
|
|
want := []int{1, 2, 4, 6}
|
|
checkSameIntSet(t, got, want)
|
|
// Also check the sources are unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
checkSameIntSet(t, setB, input2)
|
|
|
|
// Check Unique of two disjoint sets is the Union of those sets.
|
|
setC := NewIntSet(input3...)
|
|
got = setA.Unique(setC)
|
|
union := setA.Union(setC)
|
|
|
|
if equal := union.Equal(got); !equal {
|
|
t.Errorf("Union of disjoint Equal(%s, %s) want %v, got %v",
|
|
union, got, true, equal)
|
|
}
|
|
|
|
// Check Unique is the Union of A - B and B - A.
|
|
aNotInB := setA.Difference(setB)
|
|
bNotInA := setB.Difference(setA)
|
|
union = aNotInB.Union(bNotInA)
|
|
want = []int{1, 2, 4, 6}
|
|
checkSameIntSet(t, union, want)
|
|
got = setA.Unique(setB)
|
|
|
|
if equal := union.Equal(got); !equal {
|
|
t.Errorf("Union of differences Equal(%s, %s) want %v, got %v",
|
|
union, got, true, equal)
|
|
}
|
|
|
|
// Also check the sources are unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
checkSameIntSet(t, setB, input2)
|
|
}
|
|
|
|
func TestIntSet_Equal(t *testing.T) {
|
|
input1 := []int{1, 3, 4, 5, 6}
|
|
input2 := []int{2, 3, 5}
|
|
input3 := []int{1, 3, 4, 5, 7}
|
|
|
|
// Check Equal(nil) returns false.
|
|
setA := NewIntSet(input1...)
|
|
|
|
if equal := setA.Equal(nil); equal {
|
|
t.Errorf("Equal(%s, %v) want %v, got %v", setA, nil, false, true)
|
|
}
|
|
|
|
// Check that the receiver is unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
|
|
// Check Equal returns true for a set and itself.
|
|
if equal := setA.Equal(setA); !equal {
|
|
t.Errorf("Equal(%s, %s) want %v, got %v", setA, setA, true, false)
|
|
}
|
|
|
|
// Check that the receiver is unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
|
|
// Check Equal returns false for sets of non-equal length.
|
|
setB := NewIntSet(input2...)
|
|
|
|
if equal := setA.Equal(setB); equal {
|
|
t.Errorf("Equal(%s, %s) want %v, got %v", setA, setB, false, true)
|
|
}
|
|
|
|
// Also check the sources are unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
checkSameIntSet(t, setB, input2)
|
|
|
|
// Check Equal returns false for equal-length sets with different elements.
|
|
setC := NewIntSet(input3...)
|
|
|
|
if equal := setA.Equal(setC); equal {
|
|
t.Errorf("Equal(%s, %s) want %v, got %v", setA, setC, false, true)
|
|
}
|
|
|
|
if equal := setC.Equal(setA); equal {
|
|
t.Errorf("Equal(%s, %s) want %v, got %v", setC, setA, false, true)
|
|
}
|
|
|
|
// Also check the sources are unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
checkSameIntSet(t, setC, input3)
|
|
|
|
// Check Equal returns true for a set with itself.
|
|
if equal := setA.Equal(setA); !equal {
|
|
t.Errorf("Equal(%s, %s) want %v, got %v", setA, setA, true, false)
|
|
}
|
|
|
|
// Also check the source is unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
|
|
// Check Equal returns true for two separate equal sets.
|
|
anotherA := NewIntSet(input1...)
|
|
|
|
if equal := setA.Equal(anotherA); !equal {
|
|
t.Errorf("Equal(%s, %s) want %v, got %v", setA, anotherA, true, false)
|
|
}
|
|
|
|
// Also check the sources are unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
checkSameIntSet(t, anotherA, input1)
|
|
|
|
// Check for equality comparing to nil struct.
|
|
var nilSet *IntSet
|
|
if equal := nilSet.Equal(setA); equal {
|
|
t.Errorf("Equal(%s, %s) want %v, got %v", nilSet, setA, false, true)
|
|
}
|
|
if equal := setA.Equal(nilSet); equal {
|
|
t.Errorf("Equal(%s, %s) want %v, got %v", setA, nilSet, false, true)
|
|
}
|
|
if equal := nilSet.Equal(nilSet); !equal {
|
|
t.Errorf("Equal(%s, %s) want %v, got %v", nilSet, nilSet, true, false)
|
|
}
|
|
|
|
// Edge case: consider the empty set to be different than the nil set.
|
|
emptySet := NewIntSet()
|
|
if equal := nilSet.Equal(emptySet); equal {
|
|
t.Errorf("Equal(%s, %s) want %v, got %v", nilSet, emptySet, false, true)
|
|
}
|
|
if equal := emptySet.Equal(nilSet); equal {
|
|
t.Errorf("Equal(%s, %s) want %v, got %v", emptySet, nilSet, false, true)
|
|
}
|
|
if equal := emptySet.Equal(emptySet); !equal {
|
|
t.Errorf("Equal(%s, %s) want %v, got %v", emptySet, emptySet, true, false)
|
|
}
|
|
}
|
|
|
|
func TestIntSet_Union(t *testing.T) {
|
|
input1 := []int{1, 3, 4, 5, 6}
|
|
input2 := []int{2, 3, 5}
|
|
|
|
// Check Union(nil) returns a copy of the receiver.
|
|
setA := NewIntSet(input1...)
|
|
got := setA.Union(nil)
|
|
checkSameIntSet(t, got, input1)
|
|
// Check that the receiver is unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
|
|
// Check Union returns the correct result.
|
|
setB := NewIntSet(input2...)
|
|
got = setA.Union(setB)
|
|
want := []int{1, 2, 3, 4, 5, 6}
|
|
checkSameIntSet(t, got, want)
|
|
// Also check the sources are unchanged.
|
|
checkSameIntSet(t, setA, input1)
|
|
checkSameIntSet(t, setB, input2)
|
|
|
|
// Reverse the inputs and verify Union produces the same results.
|
|
setA = NewIntSet(input2...)
|
|
setB = NewIntSet(input1...)
|
|
got = setA.Union(setB)
|
|
checkSameIntSet(t, got, want)
|
|
// Check the sources are again unchanged.
|
|
checkSameIntSet(t, setA, input2)
|
|
checkSameIntSet(t, setB, input1)
|
|
}
|