aboutsummaryrefslogtreecommitdiff
path: root/internal/sets/stringset_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/sets/stringset_test.go')
-rw-r--r--internal/sets/stringset_test.go425
1 files changed, 425 insertions, 0 deletions
diff --git a/internal/sets/stringset_test.go b/internal/sets/stringset_test.go
new file mode 100644
index 0000000..2ed452c
--- /dev/null
+++ b/internal/sets/stringset_test.go
@@ -0,0 +1,425 @@
+// 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 checkSameStringSet(t *testing.T, set *StringSet, unique []string) {
+ // Check that lengths are the same.
+ want := len(unique)
+ got := set.Len()
+
+ if got != want {
+ t.Errorf("NewStringSet(%v) want length %v, got %v", unique, want, got)
+ }
+
+ // Check that all strings 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 strings.
+ sort.Strings(unique)
+
+ for i, got := range set.Sorted() {
+ want := unique[i]
+
+ if got != want {
+ t.Errorf("Sorted(%d) want %v, got %v", i, want, got)
+ }
+ }
+}
+
+func TestNewStringSet(t *testing.T) {
+ empty := NewStringSet()
+ want := 0
+ got := empty.Len()
+
+ if got != want {
+ t.Errorf("NewStringSet() want length %v, got %v", want, got)
+ }
+
+ unique := []string{"a", "b", "c"}
+ set := NewStringSet(unique...)
+ checkSameStringSet(t, set, unique)
+
+ // Append an already-present element.
+ nonUnique := append(unique, unique[0])
+ set = NewStringSet(nonUnique...)
+
+ // Non-unique unique should collapse to one.
+ want = len(unique)
+ got = set.Len()
+
+ if got != want {
+ t.Errorf("NewStringSet(%v) want length %v, got %v", nonUnique, want, got)
+ }
+}
+
+func TestStringSet_Copy(t *testing.T) {
+ // Check both copies represent the same set.
+ base := []string{"a", "b", "c"}
+ orig := NewStringSet(base...)
+ cpy := orig.Copy()
+ checkSameStringSet(t, orig, base)
+ checkSameStringSet(t, cpy, base)
+
+ // Check the two copies are independent.
+ more := []string{"d"}
+ orig.Insert(more...)
+ more = append(base, more...)
+ checkSameStringSet(t, orig, more)
+ checkSameStringSet(t, cpy, base)
+}
+
+func TestStringSet_Insert(t *testing.T) {
+ unique := []string{"a", "b", "c"}
+ set := NewStringSet(unique...)
+
+ // Insert existing element, which should basically be a no-op.
+ set.Insert(unique[0])
+ checkSameStringSet(t, set, unique)
+
+ // Actually insert new unique elements.
+ additional := []string{"d", "e"}
+ longer := append(unique, additional...)
+ set.Insert(additional...)
+ checkSameStringSet(t, set, longer)
+}
+
+func TestStringSet_Delete(t *testing.T) {
+ unique := []string{"a", "b", "c"}
+ set := NewStringSet(unique...)
+
+ // Delete non-existent element, which should basically be a no-op.
+ set.Delete("z")
+ checkSameStringSet(t, set, unique)
+
+ // Actually delete existing elements.
+ set.Delete(unique[1:]...)
+ checkSameStringSet(t, set, unique[:1])
+}
+
+func TestStringSet_Intersect(t *testing.T) {
+ input1 := []string{"a", "c", "d", "e", "f"}
+ input2 := []string{"b", "c", "e"}
+
+ // Check Intersect(nil) returns an empty set.
+ setA := NewStringSet(input1...)
+ got := setA.Intersect(nil)
+ checkSameStringSet(t, got, []string{})
+ // Check that the receiver is unchanged.
+ checkSameStringSet(t, setA, input1)
+
+ // Check Intersect returns the correct result.
+ setB := NewStringSet(input2...)
+ got = setA.Intersect(setB)
+ want := []string{"c", "e"}
+ checkSameStringSet(t, got, want)
+ // Also check the sources are unchanged.
+ checkSameStringSet(t, setA, input1)
+ checkSameStringSet(t, setB, input2)
+
+ // Reverse the inputs and verify Intersect produces the same results.
+ setA = NewStringSet(input2...)
+ setB = NewStringSet(input1...)
+ got = setA.Intersect(setB)
+ checkSameStringSet(t, got, want)
+ // Check the sources are again unchanged.
+ checkSameStringSet(t, setA, input2)
+ checkSameStringSet(t, setB, input1)
+}
+
+func TestStringSet_Disjoint(t *testing.T) {
+ input1 := []string{"a", "c", "d", "e", "f"}
+ input2 := []string{"b", "c", "e"}
+ input3 := []string{"x", "y", "z"}
+
+ // Check that sets are always disjoint with the empty set or nil
+ setA := NewStringSet(input1...)
+ emptySet := NewStringSet()
+
+ 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.
+ checkSameStringSet(t, setA, input1)
+ checkSameStringSet(t, emptySet, []string{})
+
+ // Check two non-empty, non-nil disjoint sets.
+ setC := NewStringSet(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.
+ checkSameStringSet(t, setA, input1)
+ checkSameStringSet(t, setC, input3)
+
+ // Check that two intersecting sets are not Disjoint.
+ setB := NewStringSet(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.
+ checkSameStringSet(t, setA, input1)
+ checkSameStringSet(t, setB, input2)
+}
+
+func TestStringSet_Difference(t *testing.T) {
+ input1 := []string{"a", "c", "d", "e", "f"}
+ input2 := []string{"b", "c", "e"}
+ input3 := []string{"x", "y", "z"}
+
+ // Check Difference(nil) returns a copy of the receiver.
+ setA := NewStringSet(input1...)
+ got := setA.Difference(nil)
+ checkSameStringSet(t, got, input1)
+ // Check that the receiver is unchanged.
+ checkSameStringSet(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)
+ }
+
+ checkSameStringSet(t, got, []string{})
+ // Check that the receiver is unchanged.
+ checkSameStringSet(t, setA, input1)
+
+ // Check A - C simply returns elements in A if A and C are disjoint.
+ setC := NewStringSet(input3...)
+ got = setA.Difference(setC)
+ checkSameStringSet(t, got, input1)
+ // Also check the sources are unchanged.
+ checkSameStringSet(t, setA, input1)
+ checkSameStringSet(t, setC, input3)
+
+ // Check A - B returns elements in A not in B.
+ setB := NewStringSet(input2...)
+ got = setA.Difference(setB)
+ want := []string{"a", "d", "f"}
+ checkSameStringSet(t, got, want)
+
+ // Also check the sources are unchanged.
+ checkSameStringSet(t, setA, input1)
+ checkSameStringSet(t, setB, input2)
+
+ // Check B - A returns elements in B not in A.
+ got = setB.Difference(setA)
+ want = []string{"b"}
+ checkSameStringSet(t, got, want)
+ // Also check the sources are unchanged.
+ checkSameStringSet(t, setA, input1)
+ checkSameStringSet(t, setB, input2)
+}
+
+func TestStringSet_Unique(t *testing.T) {
+ input1 := []string{"a", "c", "d", "e", "f"}
+ input2 := []string{"b", "c", "e"}
+ input3 := []string{"x", "y", "z"}
+
+ // Check Unique(nil) returns a copy of the receiver.
+ setA := NewStringSet(input1...)
+ got := setA.Unique(nil)
+ checkSameStringSet(t, got, input1)
+ // Check that the receiver is unchanged.
+ checkSameStringSet(t, setA, input1)
+
+ // Check Unique returns only elements in A and B not in both A and B.
+ setB := NewStringSet(input2...)
+ got = setA.Unique(setB)
+ want := []string{"a", "b", "d", "f"}
+ checkSameStringSet(t, got, want)
+ // Also check the sources are unchanged.
+ checkSameStringSet(t, setA, input1)
+ checkSameStringSet(t, setB, input2)
+
+ // Check Unique of two disjoint sets is the Union of those sets.
+ setC := NewStringSet(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 = []string{"a", "b", "d", "f"}
+ checkSameStringSet(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.
+ checkSameStringSet(t, setA, input1)
+ checkSameStringSet(t, setB, input2)
+}
+
+func TestStringSet_Equal(t *testing.T) {
+ input1 := []string{"a", "c", "d", "e", "f"}
+ input2 := []string{"b", "c", "e"}
+ input3 := []string{"a", "c", "d", "e", "g"}
+
+ // Check Equal(nil) returns false.
+ setA := NewStringSet(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.
+ checkSameStringSet(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.
+ checkSameStringSet(t, setA, input1)
+
+ // Check Equal returns false for sets of non-equal length.
+ setB := NewStringSet(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.
+ checkSameStringSet(t, setA, input1)
+ checkSameStringSet(t, setB, input2)
+
+ // Check Equal returns false for equal-length sets with different elements.
+ setC := NewStringSet(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.
+ checkSameStringSet(t, setA, input1)
+ checkSameStringSet(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.
+ checkSameStringSet(t, setA, input1)
+
+ // Check Equal returns true for two separate equal sets.
+ anotherA := NewStringSet(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.
+ checkSameStringSet(t, setA, input1)
+ checkSameStringSet(t, anotherA, input1)
+
+ // Check for equality comparing to nil struct.
+ var nilSet *StringSet
+ 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 := NewStringSet()
+ 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 TestStringSet_Union(t *testing.T) {
+ input1 := []string{"a", "c", "d", "e", "f"}
+ input2 := []string{"b", "c", "e"}
+
+ // Check Union(nil) returns a copy of the receiver.
+ setA := NewStringSet(input1...)
+ got := setA.Union(nil)
+ checkSameStringSet(t, got, input1)
+ // Check that the receiver is unchanged.
+ checkSameStringSet(t, setA, input1)
+
+ // Check Union returns the correct result.
+ setB := NewStringSet(input2...)
+ got = setA.Union(setB)
+ want := []string{"a", "b", "c", "d", "e", "f"}
+ checkSameStringSet(t, got, want)
+ // Also check the sources are unchanged.
+ checkSameStringSet(t, setA, input1)
+ checkSameStringSet(t, setB, input2)
+
+ // Reverse the inputs and verify Union produces the same results.
+ setA = NewStringSet(input2...)
+ setB = NewStringSet(input1...)
+ got = setA.Union(setB)
+ checkSameStringSet(t, got, want)
+ // Check the sources are again unchanged.
+ checkSameStringSet(t, setA, input2)
+ checkSameStringSet(t, setB, input1)
+}