tailscale/util/set/set_test.go
Andrew Lytvynov 2c1f14d9e6
util/set: implement json.Marshaler/Unmarshaler (#10308)
Marshal as a JSON list instead of a map. Because set elements are
`comparable` and not `cmp.Ordered`, we cannot easily sort the items
before marshaling.

Updates #cleanup

Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
2023-11-20 08:00:31 -08:00

161 lines
3.2 KiB
Go

// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package set
import (
"encoding/json"
"slices"
"testing"
)
func TestSet(t *testing.T) {
s := Set[int]{}
s.Add(1)
s.Add(2)
if !s.Contains(1) {
t.Error("missing 1")
}
if !s.Contains(2) {
t.Error("missing 2")
}
if s.Contains(3) {
t.Error("shouldn't have 3")
}
if s.Len() != 2 {
t.Errorf("wrong len %d; want 2", s.Len())
}
more := []int{3, 4}
s.AddSlice(more)
if !s.Contains(3) {
t.Error("missing 3")
}
if !s.Contains(4) {
t.Error("missing 4")
}
if s.Contains(5) {
t.Error("shouldn't have 5")
}
if s.Len() != 4 {
t.Errorf("wrong len %d; want 4", s.Len())
}
es := s.Slice()
if len(es) != 4 {
t.Errorf("slice has wrong len %d; want 4", len(es))
}
for _, e := range []int{1, 2, 3, 4} {
if !slices.Contains(es, e) {
t.Errorf("slice missing %d (%#v)", e, es)
}
}
}
func TestSetOf(t *testing.T) {
s := SetOf[int]([]int{1, 2, 3, 4, 4, 1})
if s.Len() != 4 {
t.Errorf("wrong len %d; want 4", s.Len())
}
for _, n := range []int{1, 2, 3, 4} {
if !s.Contains(n) {
t.Errorf("should contain %d", n)
}
}
}
func TestEqual(t *testing.T) {
type test struct {
name string
a Set[int]
b Set[int]
expected bool
}
tests := []test{
{
"equal",
SetOf([]int{1, 2, 3, 4}),
SetOf([]int{1, 2, 3, 4}),
true,
},
{
"not equal",
SetOf([]int{1, 2, 3, 4}),
SetOf([]int{1, 2, 3, 5}),
false,
},
{
"different lengths",
SetOf([]int{1, 2, 3, 4, 5}),
SetOf([]int{1, 2, 3, 5}),
false,
},
}
for _, tt := range tests {
if tt.a.Equal(tt.b) != tt.expected {
t.Errorf("%s: failed", tt.name)
}
}
}
func TestClone(t *testing.T) {
s := SetOf[int]([]int{1, 2, 3, 4, 4, 1})
if s.Len() != 4 {
t.Errorf("wrong len %d; want 4", s.Len())
}
s2 := s.Clone()
if !s.Equal(s2) {
t.Error("clone not equal to original")
}
s.Add(100)
if s.Equal(s2) {
t.Error("clone is not distinct from original")
}
}
func TestSetJSONRoundTrip(t *testing.T) {
tests := []struct {
desc string
strings Set[string]
ints Set[int]
}{
{"empty", make(Set[string]), make(Set[int])},
{"nil", nil, nil},
{"one-item", SetOf([]string{"one"}), SetOf([]int{1})},
{"multiple-items", SetOf([]string{"one", "two", "three"}), SetOf([]int{1, 2, 3})},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
t.Run("strings", func(t *testing.T) {
buf, err := json.Marshal(tt.strings)
if err != nil {
t.Fatalf("json.Marshal: %v", err)
}
t.Logf("marshaled: %s", buf)
var s Set[string]
if err := json.Unmarshal(buf, &s); err != nil {
t.Fatalf("json.Unmarshal: %v", err)
}
if !s.Equal(tt.strings) {
t.Errorf("set changed after JSON marshal/unmarshal, before: %v, after: %v", tt.strings, s)
}
})
t.Run("ints", func(t *testing.T) {
buf, err := json.Marshal(tt.ints)
if err != nil {
t.Fatalf("json.Marshal: %v", err)
}
t.Logf("marshaled: %s", buf)
var s Set[int]
if err := json.Unmarshal(buf, &s); err != nil {
t.Fatalf("json.Unmarshal: %v", err)
}
if !s.Equal(tt.ints) {
t.Errorf("set changed after JSON marshal/unmarshal, before: %v, after: %v", tt.ints, s)
}
})
})
}
}