mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-10-31 00:01:40 +01:00 
			
		
		
		
	set.Of(1, 2, 3) is prettier than set.SetOf([]int{1, 2, 3}).
I was going to change the signature of SetOf but then I noticed its
name has stutter anyway, so I kept it for compatibility. People can
prefer to use set.Of for new code or slowly migrate.
Also add a lazy Make method, which I often find myself wanting,
without having to resort to uglier mak.Set(&set, k, struct{}{}).
Updates #cleanup
Change-Id: Ic6f3870115334efcbd65e79c437de2ad3edb7625
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
		
	
			
		
			
				
	
	
		
			170 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			170 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 := Of(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",
 | |
| 			Of(1, 2, 3, 4),
 | |
| 			Of(1, 2, 3, 4),
 | |
| 			true,
 | |
| 		},
 | |
| 		{
 | |
| 			"not equal",
 | |
| 			Of(1, 2, 3, 4),
 | |
| 			Of(1, 2, 3, 5),
 | |
| 			false,
 | |
| 		},
 | |
| 		{
 | |
| 			"different lengths",
 | |
| 			Of(1, 2, 3, 4, 5),
 | |
| 			Of(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 := Of(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", Of("one"), Of(1)},
 | |
| 		{"multiple-items", Of("one", "two", "three"), Of(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)
 | |
| 				}
 | |
| 			})
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestMake(t *testing.T) {
 | |
| 	var s Set[int]
 | |
| 	s.Make()
 | |
| 	s.Add(1)
 | |
| 	if !s.Contains(1) {
 | |
| 		t.Error("missing 1")
 | |
| 	}
 | |
| }
 |