Add sqldb and set packages
This commit is contained in:
		
							parent
							
								
									0df8b1ec84
								
							
						
					
					
						commit
						b06910f223
					
				
							
								
								
									
										13
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
i:
 | 
			
		||||
	@go install ./...
 | 
			
		||||
 | 
			
		||||
gen:
 | 
			
		||||
	@go run set/internal/gen/main.go -tpl=set/internal/impl -dest=set
 | 
			
		||||
 | 
			
		||||
test:
 | 
			
		||||
	@go test ./...
 | 
			
		||||
 | 
			
		||||
dbtest:
 | 
			
		||||
	@go test ./sqldb -dsn="root:@(127.0.0.1:3306)/sqldb_pkg_test"
 | 
			
		||||
 | 
			
		||||
fulltest: test dbtest
 | 
			
		||||
							
								
								
									
										119
									
								
								set/internal/gen/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								set/internal/gen/main.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,119 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"flag"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"log"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"path"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type genericType struct {
 | 
			
		||||
	name     string
 | 
			
		||||
	testVals []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var types = []genericType{
 | 
			
		||||
	// Int
 | 
			
		||||
	{name: reflect.Int.String(), testVals: []string{"1", "2", "3", "4", "5"}},
 | 
			
		||||
	{name: reflect.Int8.String(), testVals: []string{"1", "2", "3", "4", "5"}},
 | 
			
		||||
	{name: reflect.Int16.String(), testVals: []string{"1", "2", "3", "4", "5"}},
 | 
			
		||||
	{name: reflect.Int32.String(), testVals: []string{"1", "2", "3", "4", "5"}},
 | 
			
		||||
	{name: reflect.Int64.String(), testVals: []string{"1", "2", "3", "4", "5"}},
 | 
			
		||||
	// Uint
 | 
			
		||||
	{name: reflect.Uint.String(), testVals: []string{"1", "2", "3", "4", "5"}},
 | 
			
		||||
	{name: reflect.Uint8.String(), testVals: []string{"1", "2", "3", "4", "5"}},
 | 
			
		||||
	{name: reflect.Uint16.String(), testVals: []string{"1", "2", "3", "4", "5"}},
 | 
			
		||||
	{name: reflect.Uint32.String(), testVals: []string{"1", "2", "3", "4", "5"}},
 | 
			
		||||
	{name: reflect.Uint64.String(), testVals: []string{"1", "2", "3", "4", "5"}},
 | 
			
		||||
	// String
 | 
			
		||||
	{name: reflect.String.String(), testVals: []string{`"1"`, `"2"`, `"3"`, `"4"`, `"5"`}},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	tplDir := flag.String("tpl", "", "Path to template directory")
 | 
			
		||||
	destDir := flag.String("dest", "", "Path to destination directory")
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
 | 
			
		||||
	if *tplDir == "" {
 | 
			
		||||
		log.Println("Template directory is not specified")
 | 
			
		||||
		flag.Usage()
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
	if *destDir == "" {
 | 
			
		||||
		log.Println("Destination directory is not specified")
 | 
			
		||||
		flag.Usage()
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	implSource, err := ioutil.ReadFile(path.Join(*tplDir, "set.go"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalf("Failed to read source file at %s: %v", path.Join(*tplDir, "set.go"), err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	testSource, err := ioutil.ReadFile(path.Join(*tplDir, "set_test.go"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalf("Failed to read test file at %s: %v", path.Join(*tplDir, "set_test.go"), err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, typ := range types {
 | 
			
		||||
		log.Printf("Generating package for type %s\n", typ.name)
 | 
			
		||||
		err := generate(*destDir, implSource, testSource, typ)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Fatalf("Failed to generate a package for type %s: %v", typ.name, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	err = gofmt(*destDir)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalf("Formatting failed: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Println("Set packages were successfully generated")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func generate(destDir string, implSource, testSource []byte, typ genericType) error {
 | 
			
		||||
	pkgDir := path.Join(destDir, fmt.Sprintf("set%s", typ.name))
 | 
			
		||||
	err := os.RemoveAll(pkgDir)
 | 
			
		||||
	if err != nil && !os.IsNotExist(err) {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err = os.Mkdir(pkgDir, 0777)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err = ioutil.WriteFile(path.Join(pkgDir, "set.go"), renderBytes(implSource, typ), 0755)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err = ioutil.WriteFile(path.Join(pkgDir, "set_test.go"), renderBytes(testSource, typ), 0755)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func renderBytes(src []byte, typ genericType) []byte {
 | 
			
		||||
	return []byte(render(string(src), typ))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func render(src string, typ genericType) string {
 | 
			
		||||
	const genericTypeName = "TypeName"
 | 
			
		||||
	// Replace test constants
 | 
			
		||||
	src = strings.Replace(src, "One   TypeName = 1", "One   TypeName = "+typ.testVals[0], 1)
 | 
			
		||||
	src = strings.Replace(src, "Two   TypeName = 2", "Two   TypeName = "+typ.testVals[1], 1)
 | 
			
		||||
	src = strings.Replace(src, "Three TypeName = 3", "Three TypeName = "+typ.testVals[2], 1)
 | 
			
		||||
	src = strings.Replace(src, "Four  TypeName = 4", "Four  TypeName = "+typ.testVals[3], 1)
 | 
			
		||||
	src = strings.Replace(src, "Five  TypeName = 5", "Five  TypeName = "+typ.testVals[4], 1)
 | 
			
		||||
	// Replace the type name
 | 
			
		||||
	src = strings.Replace(src, genericTypeName, typ.name, -1)
 | 
			
		||||
	return src
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func gofmt(dir string) error {
 | 
			
		||||
	out, err := exec.Command("gofmt", "-w", "-l", dir).CombinedOutput()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Println("gofmt returned:", string(out))
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								set/internal/impl/set.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								set/internal/impl/set.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Set is a set of TypeName.
 | 
			
		||||
type Set struct {
 | 
			
		||||
	items map[TypeName]struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a new TypeName set.
 | 
			
		||||
func New(items ...TypeName) *Set {
 | 
			
		||||
	s := &Set{items: make(map[TypeName]struct{}, len(items))}
 | 
			
		||||
	s.Add(items...)
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add adds given items to the set.
 | 
			
		||||
func (s *Set) Add(items ...TypeName) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		s.items[item] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove delete given items from the set.
 | 
			
		||||
func (s *Set) Remove(items ...TypeName) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		delete(s.items, item)
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Has returns true if all the given items are included in the set.
 | 
			
		||||
func (s *Set) Has(items ...TypeName) bool {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		if _, ok := s.items[item]; !ok {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Len returns the size of the set.
 | 
			
		||||
func (s *Set) Len() int {
 | 
			
		||||
	return len(s.items)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Slice returns items of the set as a slice.
 | 
			
		||||
func (s *Set) Slice() []TypeName {
 | 
			
		||||
	sl := make([]TypeName, len(s.items))
 | 
			
		||||
	i := 0
 | 
			
		||||
	for item := range s.items {
 | 
			
		||||
		sl[i] = item
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	return sl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SortedSlice returns items of the set as a slice sorted ascending.
 | 
			
		||||
func (s *Set) SortedSlice() []TypeName {
 | 
			
		||||
	ss := s.Slice()
 | 
			
		||||
	sort.Slice(ss, func(i, j int) bool {
 | 
			
		||||
		return ss[i] < ss[j]
 | 
			
		||||
	})
 | 
			
		||||
	return ss
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String implements fmt.Stringer interface.
 | 
			
		||||
func (s *Set) String() string {
 | 
			
		||||
	return fmt.Sprintf("[%v]", s.Slice())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										114
									
								
								set/internal/impl/set_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								set/internal/impl/set_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,114 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp/cmpopts"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	One   TypeName = 1
 | 
			
		||||
	Two   TypeName = 2
 | 
			
		||||
	Three TypeName = 3
 | 
			
		||||
	Four  TypeName = 4
 | 
			
		||||
	Five  TypeName = 5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNew(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		t.Fatal("Set is nil")
 | 
			
		||||
	}
 | 
			
		||||
	if s.Len() != 3 {
 | 
			
		||||
		t.Errorf("Expected set to contain 3 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []TypeName{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAdd(t *testing.T) {
 | 
			
		||||
	s := New()
 | 
			
		||||
	if s.Len() != 0 {
 | 
			
		||||
		t.Errorf("Expected set to be empty, got %d items", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	s.Add(One)
 | 
			
		||||
	s.Add(Two, Three)
 | 
			
		||||
	for _, item := range []TypeName{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemove(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three, Four, Five)
 | 
			
		||||
	s.Remove(One, Two)
 | 
			
		||||
	s.Remove(Three)
 | 
			
		||||
	if s.Len() != 2 {
 | 
			
		||||
		t.Errorf("Expected set to contain 2 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []TypeName{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); ok {
 | 
			
		||||
			t.Errorf("Set is expected to not contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []TypeName{Four, Five} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHas(t *testing.T) {
 | 
			
		||||
	s := New(One, Two)
 | 
			
		||||
	table := map[TypeName]bool{
 | 
			
		||||
		One:   true,
 | 
			
		||||
		Two:   true,
 | 
			
		||||
		Three: false,
 | 
			
		||||
		Four:  false,
 | 
			
		||||
		Five:  false,
 | 
			
		||||
	}
 | 
			
		||||
	for v, exp := range table {
 | 
			
		||||
		if res := s.Has(v); res != exp {
 | 
			
		||||
			t.Errorf("Item: %v, In: %v, Expected: %v", v, res, exp)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLen(t *testing.T) {
 | 
			
		||||
	table := map[*Set]int{
 | 
			
		||||
		New():                                  0,
 | 
			
		||||
		New(One):                               1,
 | 
			
		||||
		New(Two, Three):                        2,
 | 
			
		||||
		New(One, Two, Three, Four, Five, Five): 5,
 | 
			
		||||
	}
 | 
			
		||||
	for s, exp := range table {
 | 
			
		||||
		if res := s.Len(); res != exp {
 | 
			
		||||
			t.Errorf("Expected set %s to have length %d, got %d", s, exp, res)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.Slice()
 | 
			
		||||
	exp := []TypeName{One, Two, Three}
 | 
			
		||||
	ignoreOrder := cmpopts.SortSlices(func(a, b TypeName) bool { return a < b })
 | 
			
		||||
	if !cmp.Equal(exp, out, ignoreOrder) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSortedSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.SortedSlice()
 | 
			
		||||
	exp := []TypeName{One, Two, Three}
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										4
									
								
								set/internal/impl/type.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								set/internal/impl/type.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
// TypeName is a type placeholder.
 | 
			
		||||
type TypeName int
 | 
			
		||||
							
								
								
									
										74
									
								
								set/setint/set.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										74
									
								
								set/setint/set.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Set is a set of int.
 | 
			
		||||
type Set struct {
 | 
			
		||||
	items map[int]struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a new int set.
 | 
			
		||||
func New(items ...int) *Set {
 | 
			
		||||
	s := &Set{items: make(map[int]struct{}, len(items))}
 | 
			
		||||
	s.Add(items...)
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add adds given items to the set.
 | 
			
		||||
func (s *Set) Add(items ...int) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		s.items[item] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove delete given items from the set.
 | 
			
		||||
func (s *Set) Remove(items ...int) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		delete(s.items, item)
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Has returns true if all the given items are included in the set.
 | 
			
		||||
func (s *Set) Has(items ...int) bool {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		if _, ok := s.items[item]; !ok {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Len returns the size of the set.
 | 
			
		||||
func (s *Set) Len() int {
 | 
			
		||||
	return len(s.items)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Slice returns items of the set as a slice.
 | 
			
		||||
func (s *Set) Slice() []int {
 | 
			
		||||
	sl := make([]int, len(s.items))
 | 
			
		||||
	i := 0
 | 
			
		||||
	for item := range s.items {
 | 
			
		||||
		sl[i] = item
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	return sl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SortedSlice returns items of the set as a slice sorted ascending.
 | 
			
		||||
func (s *Set) SortedSlice() []int {
 | 
			
		||||
	ss := s.Slice()
 | 
			
		||||
	sort.Slice(ss, func(i, j int) bool {
 | 
			
		||||
		return ss[i] < ss[j]
 | 
			
		||||
	})
 | 
			
		||||
	return ss
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String implements fmt.Stringer interface.
 | 
			
		||||
func (s *Set) String() string {
 | 
			
		||||
	return fmt.Sprintf("[%v]", s.Slice())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								set/setint/set_test.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										116
									
								
								set/setint/set_test.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,116 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp/cmpopts"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	One   int = 1
 | 
			
		||||
	Two   int = 2
 | 
			
		||||
	Three int = 3
 | 
			
		||||
	Four  int = 4
 | 
			
		||||
	Five  int = 5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNew(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		t.Fatal("Set is nil")
 | 
			
		||||
	}
 | 
			
		||||
	if s.Len() != 3 {
 | 
			
		||||
		t.Errorf("Expected set to contain 3 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []int{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAdd(t *testing.T) {
 | 
			
		||||
	s := New()
 | 
			
		||||
	if s.Len() != 0 {
 | 
			
		||||
		t.Errorf("Expected set to be empty, got %d items", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	s.Add(One)
 | 
			
		||||
	s.Add(Two, Three)
 | 
			
		||||
	for _, item := range []int{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemove(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three, Four, Five)
 | 
			
		||||
	s.Remove(One, Two)
 | 
			
		||||
	s.Remove(Three)
 | 
			
		||||
	if s.Len() != 2 {
 | 
			
		||||
		t.Errorf("Expected set to contain 2 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []int{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); ok {
 | 
			
		||||
			t.Errorf("Set is expected to not contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []int{Four, Five} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHas(t *testing.T) {
 | 
			
		||||
	s := New(One, Two)
 | 
			
		||||
	table := map[int]bool{
 | 
			
		||||
		One:   true,
 | 
			
		||||
		Two:   true,
 | 
			
		||||
		Three: false,
 | 
			
		||||
		Four:  false,
 | 
			
		||||
		Five:  false,
 | 
			
		||||
	}
 | 
			
		||||
	for v, exp := range table {
 | 
			
		||||
		if res := s.Has(v); res != exp {
 | 
			
		||||
			t.Errorf("Item: %v, In: %v, Expected: %v", v, res, exp)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLen(t *testing.T) {
 | 
			
		||||
	table := map[*Set]int{
 | 
			
		||||
		New():                                  0,
 | 
			
		||||
		New(One):                               1,
 | 
			
		||||
		New(Two, Three):                        2,
 | 
			
		||||
		New(One, Two, Three, Four, Five, Five): 5,
 | 
			
		||||
	}
 | 
			
		||||
	for s, exp := range table {
 | 
			
		||||
		if res := s.Len(); res != exp {
 | 
			
		||||
			t.Errorf("Expected set %s to have length %d, got %d", s, exp, res)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.Slice()
 | 
			
		||||
	exp := []int{One, Two, Three}
 | 
			
		||||
	ignoreOrder := cmpopts.SortSlices(func(a, b int) bool {
 | 
			
		||||
		return a < b
 | 
			
		||||
	})
 | 
			
		||||
	if !cmp.Equal(exp, out, ignoreOrder) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSortedSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.SortedSlice()
 | 
			
		||||
	exp := []int{One, Two, Three}
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								set/setint16/set.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										74
									
								
								set/setint16/set.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Set is a set of int16.
 | 
			
		||||
type Set struct {
 | 
			
		||||
	items map[int16]struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a new int16 set.
 | 
			
		||||
func New(items ...int16) *Set {
 | 
			
		||||
	s := &Set{items: make(map[int16]struct{}, len(items))}
 | 
			
		||||
	s.Add(items...)
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add adds given items to the set.
 | 
			
		||||
func (s *Set) Add(items ...int16) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		s.items[item] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove delete given items from the set.
 | 
			
		||||
func (s *Set) Remove(items ...int16) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		delete(s.items, item)
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Has returns true if all the given items are included in the set.
 | 
			
		||||
func (s *Set) Has(items ...int16) bool {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		if _, ok := s.items[item]; !ok {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Len returns the size of the set.
 | 
			
		||||
func (s *Set) Len() int {
 | 
			
		||||
	return len(s.items)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Slice returns items of the set as a slice.
 | 
			
		||||
func (s *Set) Slice() []int16 {
 | 
			
		||||
	sl := make([]int16, len(s.items))
 | 
			
		||||
	i := 0
 | 
			
		||||
	for item := range s.items {
 | 
			
		||||
		sl[i] = item
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	return sl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SortedSlice returns items of the set as a slice sorted ascending.
 | 
			
		||||
func (s *Set) SortedSlice() []int16 {
 | 
			
		||||
	ss := s.Slice()
 | 
			
		||||
	sort.Slice(ss, func(i, j int) bool {
 | 
			
		||||
		return ss[i] < ss[j]
 | 
			
		||||
	})
 | 
			
		||||
	return ss
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String implements fmt.Stringer interface.
 | 
			
		||||
func (s *Set) String() string {
 | 
			
		||||
	return fmt.Sprintf("[%v]", s.Slice())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								set/setint16/set_test.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										116
									
								
								set/setint16/set_test.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,116 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp/cmpopts"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	One   int16 = 1
 | 
			
		||||
	Two   int16 = 2
 | 
			
		||||
	Three int16 = 3
 | 
			
		||||
	Four  int16 = 4
 | 
			
		||||
	Five  int16 = 5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNew(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		t.Fatal("Set is nil")
 | 
			
		||||
	}
 | 
			
		||||
	if s.Len() != 3 {
 | 
			
		||||
		t.Errorf("Expected set to contain 3 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []int16{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAdd(t *testing.T) {
 | 
			
		||||
	s := New()
 | 
			
		||||
	if s.Len() != 0 {
 | 
			
		||||
		t.Errorf("Expected set to be empty, got %d items", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	s.Add(One)
 | 
			
		||||
	s.Add(Two, Three)
 | 
			
		||||
	for _, item := range []int16{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemove(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three, Four, Five)
 | 
			
		||||
	s.Remove(One, Two)
 | 
			
		||||
	s.Remove(Three)
 | 
			
		||||
	if s.Len() != 2 {
 | 
			
		||||
		t.Errorf("Expected set to contain 2 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []int16{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); ok {
 | 
			
		||||
			t.Errorf("Set is expected to not contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []int16{Four, Five} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHas(t *testing.T) {
 | 
			
		||||
	s := New(One, Two)
 | 
			
		||||
	table := map[int16]bool{
 | 
			
		||||
		One:   true,
 | 
			
		||||
		Two:   true,
 | 
			
		||||
		Three: false,
 | 
			
		||||
		Four:  false,
 | 
			
		||||
		Five:  false,
 | 
			
		||||
	}
 | 
			
		||||
	for v, exp := range table {
 | 
			
		||||
		if res := s.Has(v); res != exp {
 | 
			
		||||
			t.Errorf("Item: %v, In: %v, Expected: %v", v, res, exp)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLen(t *testing.T) {
 | 
			
		||||
	table := map[*Set]int{
 | 
			
		||||
		New():                                  0,
 | 
			
		||||
		New(One):                               1,
 | 
			
		||||
		New(Two, Three):                        2,
 | 
			
		||||
		New(One, Two, Three, Four, Five, Five): 5,
 | 
			
		||||
	}
 | 
			
		||||
	for s, exp := range table {
 | 
			
		||||
		if res := s.Len(); res != exp {
 | 
			
		||||
			t.Errorf("Expected set %s to have length %d, got %d", s, exp, res)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.Slice()
 | 
			
		||||
	exp := []int16{One, Two, Three}
 | 
			
		||||
	ignoreOrder := cmpopts.SortSlices(func(a, b int16) bool {
 | 
			
		||||
		return a < b
 | 
			
		||||
	})
 | 
			
		||||
	if !cmp.Equal(exp, out, ignoreOrder) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSortedSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.SortedSlice()
 | 
			
		||||
	exp := []int16{One, Two, Three}
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								set/setint32/set.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										74
									
								
								set/setint32/set.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Set is a set of int32.
 | 
			
		||||
type Set struct {
 | 
			
		||||
	items map[int32]struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a new int32 set.
 | 
			
		||||
func New(items ...int32) *Set {
 | 
			
		||||
	s := &Set{items: make(map[int32]struct{}, len(items))}
 | 
			
		||||
	s.Add(items...)
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add adds given items to the set.
 | 
			
		||||
func (s *Set) Add(items ...int32) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		s.items[item] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove delete given items from the set.
 | 
			
		||||
func (s *Set) Remove(items ...int32) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		delete(s.items, item)
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Has returns true if all the given items are included in the set.
 | 
			
		||||
func (s *Set) Has(items ...int32) bool {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		if _, ok := s.items[item]; !ok {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Len returns the size of the set.
 | 
			
		||||
func (s *Set) Len() int {
 | 
			
		||||
	return len(s.items)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Slice returns items of the set as a slice.
 | 
			
		||||
func (s *Set) Slice() []int32 {
 | 
			
		||||
	sl := make([]int32, len(s.items))
 | 
			
		||||
	i := 0
 | 
			
		||||
	for item := range s.items {
 | 
			
		||||
		sl[i] = item
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	return sl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SortedSlice returns items of the set as a slice sorted ascending.
 | 
			
		||||
func (s *Set) SortedSlice() []int32 {
 | 
			
		||||
	ss := s.Slice()
 | 
			
		||||
	sort.Slice(ss, func(i, j int) bool {
 | 
			
		||||
		return ss[i] < ss[j]
 | 
			
		||||
	})
 | 
			
		||||
	return ss
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String implements fmt.Stringer interface.
 | 
			
		||||
func (s *Set) String() string {
 | 
			
		||||
	return fmt.Sprintf("[%v]", s.Slice())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								set/setint32/set_test.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										116
									
								
								set/setint32/set_test.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,116 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp/cmpopts"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	One   int32 = 1
 | 
			
		||||
	Two   int32 = 2
 | 
			
		||||
	Three int32 = 3
 | 
			
		||||
	Four  int32 = 4
 | 
			
		||||
	Five  int32 = 5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNew(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		t.Fatal("Set is nil")
 | 
			
		||||
	}
 | 
			
		||||
	if s.Len() != 3 {
 | 
			
		||||
		t.Errorf("Expected set to contain 3 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []int32{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAdd(t *testing.T) {
 | 
			
		||||
	s := New()
 | 
			
		||||
	if s.Len() != 0 {
 | 
			
		||||
		t.Errorf("Expected set to be empty, got %d items", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	s.Add(One)
 | 
			
		||||
	s.Add(Two, Three)
 | 
			
		||||
	for _, item := range []int32{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemove(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three, Four, Five)
 | 
			
		||||
	s.Remove(One, Two)
 | 
			
		||||
	s.Remove(Three)
 | 
			
		||||
	if s.Len() != 2 {
 | 
			
		||||
		t.Errorf("Expected set to contain 2 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []int32{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); ok {
 | 
			
		||||
			t.Errorf("Set is expected to not contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []int32{Four, Five} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHas(t *testing.T) {
 | 
			
		||||
	s := New(One, Two)
 | 
			
		||||
	table := map[int32]bool{
 | 
			
		||||
		One:   true,
 | 
			
		||||
		Two:   true,
 | 
			
		||||
		Three: false,
 | 
			
		||||
		Four:  false,
 | 
			
		||||
		Five:  false,
 | 
			
		||||
	}
 | 
			
		||||
	for v, exp := range table {
 | 
			
		||||
		if res := s.Has(v); res != exp {
 | 
			
		||||
			t.Errorf("Item: %v, In: %v, Expected: %v", v, res, exp)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLen(t *testing.T) {
 | 
			
		||||
	table := map[*Set]int{
 | 
			
		||||
		New():                                  0,
 | 
			
		||||
		New(One):                               1,
 | 
			
		||||
		New(Two, Three):                        2,
 | 
			
		||||
		New(One, Two, Three, Four, Five, Five): 5,
 | 
			
		||||
	}
 | 
			
		||||
	for s, exp := range table {
 | 
			
		||||
		if res := s.Len(); res != exp {
 | 
			
		||||
			t.Errorf("Expected set %s to have length %d, got %d", s, exp, res)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.Slice()
 | 
			
		||||
	exp := []int32{One, Two, Three}
 | 
			
		||||
	ignoreOrder := cmpopts.SortSlices(func(a, b int32) bool {
 | 
			
		||||
		return a < b
 | 
			
		||||
	})
 | 
			
		||||
	if !cmp.Equal(exp, out, ignoreOrder) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSortedSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.SortedSlice()
 | 
			
		||||
	exp := []int32{One, Two, Three}
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								set/setint64/set.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										74
									
								
								set/setint64/set.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Set is a set of int64.
 | 
			
		||||
type Set struct {
 | 
			
		||||
	items map[int64]struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a new int64 set.
 | 
			
		||||
func New(items ...int64) *Set {
 | 
			
		||||
	s := &Set{items: make(map[int64]struct{}, len(items))}
 | 
			
		||||
	s.Add(items...)
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add adds given items to the set.
 | 
			
		||||
func (s *Set) Add(items ...int64) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		s.items[item] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove delete given items from the set.
 | 
			
		||||
func (s *Set) Remove(items ...int64) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		delete(s.items, item)
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Has returns true if all the given items are included in the set.
 | 
			
		||||
func (s *Set) Has(items ...int64) bool {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		if _, ok := s.items[item]; !ok {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Len returns the size of the set.
 | 
			
		||||
func (s *Set) Len() int {
 | 
			
		||||
	return len(s.items)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Slice returns items of the set as a slice.
 | 
			
		||||
func (s *Set) Slice() []int64 {
 | 
			
		||||
	sl := make([]int64, len(s.items))
 | 
			
		||||
	i := 0
 | 
			
		||||
	for item := range s.items {
 | 
			
		||||
		sl[i] = item
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	return sl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SortedSlice returns items of the set as a slice sorted ascending.
 | 
			
		||||
func (s *Set) SortedSlice() []int64 {
 | 
			
		||||
	ss := s.Slice()
 | 
			
		||||
	sort.Slice(ss, func(i, j int) bool {
 | 
			
		||||
		return ss[i] < ss[j]
 | 
			
		||||
	})
 | 
			
		||||
	return ss
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String implements fmt.Stringer interface.
 | 
			
		||||
func (s *Set) String() string {
 | 
			
		||||
	return fmt.Sprintf("[%v]", s.Slice())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								set/setint64/set_test.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										116
									
								
								set/setint64/set_test.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,116 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp/cmpopts"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	One   int64 = 1
 | 
			
		||||
	Two   int64 = 2
 | 
			
		||||
	Three int64 = 3
 | 
			
		||||
	Four  int64 = 4
 | 
			
		||||
	Five  int64 = 5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNew(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		t.Fatal("Set is nil")
 | 
			
		||||
	}
 | 
			
		||||
	if s.Len() != 3 {
 | 
			
		||||
		t.Errorf("Expected set to contain 3 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []int64{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAdd(t *testing.T) {
 | 
			
		||||
	s := New()
 | 
			
		||||
	if s.Len() != 0 {
 | 
			
		||||
		t.Errorf("Expected set to be empty, got %d items", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	s.Add(One)
 | 
			
		||||
	s.Add(Two, Three)
 | 
			
		||||
	for _, item := range []int64{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemove(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three, Four, Five)
 | 
			
		||||
	s.Remove(One, Two)
 | 
			
		||||
	s.Remove(Three)
 | 
			
		||||
	if s.Len() != 2 {
 | 
			
		||||
		t.Errorf("Expected set to contain 2 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []int64{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); ok {
 | 
			
		||||
			t.Errorf("Set is expected to not contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []int64{Four, Five} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHas(t *testing.T) {
 | 
			
		||||
	s := New(One, Two)
 | 
			
		||||
	table := map[int64]bool{
 | 
			
		||||
		One:   true,
 | 
			
		||||
		Two:   true,
 | 
			
		||||
		Three: false,
 | 
			
		||||
		Four:  false,
 | 
			
		||||
		Five:  false,
 | 
			
		||||
	}
 | 
			
		||||
	for v, exp := range table {
 | 
			
		||||
		if res := s.Has(v); res != exp {
 | 
			
		||||
			t.Errorf("Item: %v, In: %v, Expected: %v", v, res, exp)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLen(t *testing.T) {
 | 
			
		||||
	table := map[*Set]int{
 | 
			
		||||
		New():                                  0,
 | 
			
		||||
		New(One):                               1,
 | 
			
		||||
		New(Two, Three):                        2,
 | 
			
		||||
		New(One, Two, Three, Four, Five, Five): 5,
 | 
			
		||||
	}
 | 
			
		||||
	for s, exp := range table {
 | 
			
		||||
		if res := s.Len(); res != exp {
 | 
			
		||||
			t.Errorf("Expected set %s to have length %d, got %d", s, exp, res)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.Slice()
 | 
			
		||||
	exp := []int64{One, Two, Three}
 | 
			
		||||
	ignoreOrder := cmpopts.SortSlices(func(a, b int64) bool {
 | 
			
		||||
		return a < b
 | 
			
		||||
	})
 | 
			
		||||
	if !cmp.Equal(exp, out, ignoreOrder) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSortedSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.SortedSlice()
 | 
			
		||||
	exp := []int64{One, Two, Three}
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								set/setint8/set.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										74
									
								
								set/setint8/set.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Set is a set of int8.
 | 
			
		||||
type Set struct {
 | 
			
		||||
	items map[int8]struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a new int8 set.
 | 
			
		||||
func New(items ...int8) *Set {
 | 
			
		||||
	s := &Set{items: make(map[int8]struct{}, len(items))}
 | 
			
		||||
	s.Add(items...)
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add adds given items to the set.
 | 
			
		||||
func (s *Set) Add(items ...int8) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		s.items[item] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove delete given items from the set.
 | 
			
		||||
func (s *Set) Remove(items ...int8) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		delete(s.items, item)
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Has returns true if all the given items are included in the set.
 | 
			
		||||
func (s *Set) Has(items ...int8) bool {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		if _, ok := s.items[item]; !ok {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Len returns the size of the set.
 | 
			
		||||
func (s *Set) Len() int {
 | 
			
		||||
	return len(s.items)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Slice returns items of the set as a slice.
 | 
			
		||||
func (s *Set) Slice() []int8 {
 | 
			
		||||
	sl := make([]int8, len(s.items))
 | 
			
		||||
	i := 0
 | 
			
		||||
	for item := range s.items {
 | 
			
		||||
		sl[i] = item
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	return sl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SortedSlice returns items of the set as a slice sorted ascending.
 | 
			
		||||
func (s *Set) SortedSlice() []int8 {
 | 
			
		||||
	ss := s.Slice()
 | 
			
		||||
	sort.Slice(ss, func(i, j int) bool {
 | 
			
		||||
		return ss[i] < ss[j]
 | 
			
		||||
	})
 | 
			
		||||
	return ss
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String implements fmt.Stringer interface.
 | 
			
		||||
func (s *Set) String() string {
 | 
			
		||||
	return fmt.Sprintf("[%v]", s.Slice())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								set/setint8/set_test.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										116
									
								
								set/setint8/set_test.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,116 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp/cmpopts"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	One   int8 = 1
 | 
			
		||||
	Two   int8 = 2
 | 
			
		||||
	Three int8 = 3
 | 
			
		||||
	Four  int8 = 4
 | 
			
		||||
	Five  int8 = 5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNew(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		t.Fatal("Set is nil")
 | 
			
		||||
	}
 | 
			
		||||
	if s.Len() != 3 {
 | 
			
		||||
		t.Errorf("Expected set to contain 3 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []int8{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAdd(t *testing.T) {
 | 
			
		||||
	s := New()
 | 
			
		||||
	if s.Len() != 0 {
 | 
			
		||||
		t.Errorf("Expected set to be empty, got %d items", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	s.Add(One)
 | 
			
		||||
	s.Add(Two, Three)
 | 
			
		||||
	for _, item := range []int8{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemove(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three, Four, Five)
 | 
			
		||||
	s.Remove(One, Two)
 | 
			
		||||
	s.Remove(Three)
 | 
			
		||||
	if s.Len() != 2 {
 | 
			
		||||
		t.Errorf("Expected set to contain 2 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []int8{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); ok {
 | 
			
		||||
			t.Errorf("Set is expected to not contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []int8{Four, Five} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHas(t *testing.T) {
 | 
			
		||||
	s := New(One, Two)
 | 
			
		||||
	table := map[int8]bool{
 | 
			
		||||
		One:   true,
 | 
			
		||||
		Two:   true,
 | 
			
		||||
		Three: false,
 | 
			
		||||
		Four:  false,
 | 
			
		||||
		Five:  false,
 | 
			
		||||
	}
 | 
			
		||||
	for v, exp := range table {
 | 
			
		||||
		if res := s.Has(v); res != exp {
 | 
			
		||||
			t.Errorf("Item: %v, In: %v, Expected: %v", v, res, exp)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLen(t *testing.T) {
 | 
			
		||||
	table := map[*Set]int{
 | 
			
		||||
		New():                                  0,
 | 
			
		||||
		New(One):                               1,
 | 
			
		||||
		New(Two, Three):                        2,
 | 
			
		||||
		New(One, Two, Three, Four, Five, Five): 5,
 | 
			
		||||
	}
 | 
			
		||||
	for s, exp := range table {
 | 
			
		||||
		if res := s.Len(); res != exp {
 | 
			
		||||
			t.Errorf("Expected set %s to have length %d, got %d", s, exp, res)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.Slice()
 | 
			
		||||
	exp := []int8{One, Two, Three}
 | 
			
		||||
	ignoreOrder := cmpopts.SortSlices(func(a, b int8) bool {
 | 
			
		||||
		return a < b
 | 
			
		||||
	})
 | 
			
		||||
	if !cmp.Equal(exp, out, ignoreOrder) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSortedSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.SortedSlice()
 | 
			
		||||
	exp := []int8{One, Two, Three}
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								set/setstring/set.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										74
									
								
								set/setstring/set.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Set is a set of string.
 | 
			
		||||
type Set struct {
 | 
			
		||||
	items map[string]struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a new string set.
 | 
			
		||||
func New(items ...string) *Set {
 | 
			
		||||
	s := &Set{items: make(map[string]struct{}, len(items))}
 | 
			
		||||
	s.Add(items...)
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add adds given items to the set.
 | 
			
		||||
func (s *Set) Add(items ...string) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		s.items[item] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove delete given items from the set.
 | 
			
		||||
func (s *Set) Remove(items ...string) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		delete(s.items, item)
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Has returns true if all the given items are included in the set.
 | 
			
		||||
func (s *Set) Has(items ...string) bool {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		if _, ok := s.items[item]; !ok {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Len returns the size of the set.
 | 
			
		||||
func (s *Set) Len() int {
 | 
			
		||||
	return len(s.items)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Slice returns items of the set as a slice.
 | 
			
		||||
func (s *Set) Slice() []string {
 | 
			
		||||
	sl := make([]string, len(s.items))
 | 
			
		||||
	i := 0
 | 
			
		||||
	for item := range s.items {
 | 
			
		||||
		sl[i] = item
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	return sl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SortedSlice returns items of the set as a slice sorted ascending.
 | 
			
		||||
func (s *Set) SortedSlice() []string {
 | 
			
		||||
	ss := s.Slice()
 | 
			
		||||
	sort.Slice(ss, func(i, j int) bool {
 | 
			
		||||
		return ss[i] < ss[j]
 | 
			
		||||
	})
 | 
			
		||||
	return ss
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String implements fmt.Stringer interface.
 | 
			
		||||
func (s *Set) String() string {
 | 
			
		||||
	return fmt.Sprintf("[%v]", s.Slice())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								set/setstring/set_test.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										116
									
								
								set/setstring/set_test.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,116 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp/cmpopts"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	One   string = "1"
 | 
			
		||||
	Two   string = "2"
 | 
			
		||||
	Three string = "3"
 | 
			
		||||
	Four  string = "4"
 | 
			
		||||
	Five  string = "5"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNew(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		t.Fatal("Set is nil")
 | 
			
		||||
	}
 | 
			
		||||
	if s.Len() != 3 {
 | 
			
		||||
		t.Errorf("Expected set to contain 3 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []string{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAdd(t *testing.T) {
 | 
			
		||||
	s := New()
 | 
			
		||||
	if s.Len() != 0 {
 | 
			
		||||
		t.Errorf("Expected set to be empty, got %d items", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	s.Add(One)
 | 
			
		||||
	s.Add(Two, Three)
 | 
			
		||||
	for _, item := range []string{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemove(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three, Four, Five)
 | 
			
		||||
	s.Remove(One, Two)
 | 
			
		||||
	s.Remove(Three)
 | 
			
		||||
	if s.Len() != 2 {
 | 
			
		||||
		t.Errorf("Expected set to contain 2 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []string{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); ok {
 | 
			
		||||
			t.Errorf("Set is expected to not contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []string{Four, Five} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHas(t *testing.T) {
 | 
			
		||||
	s := New(One, Two)
 | 
			
		||||
	table := map[string]bool{
 | 
			
		||||
		One:   true,
 | 
			
		||||
		Two:   true,
 | 
			
		||||
		Three: false,
 | 
			
		||||
		Four:  false,
 | 
			
		||||
		Five:  false,
 | 
			
		||||
	}
 | 
			
		||||
	for v, exp := range table {
 | 
			
		||||
		if res := s.Has(v); res != exp {
 | 
			
		||||
			t.Errorf("Item: %v, In: %v, Expected: %v", v, res, exp)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLen(t *testing.T) {
 | 
			
		||||
	table := map[*Set]int{
 | 
			
		||||
		New():                                  0,
 | 
			
		||||
		New(One):                               1,
 | 
			
		||||
		New(Two, Three):                        2,
 | 
			
		||||
		New(One, Two, Three, Four, Five, Five): 5,
 | 
			
		||||
	}
 | 
			
		||||
	for s, exp := range table {
 | 
			
		||||
		if res := s.Len(); res != exp {
 | 
			
		||||
			t.Errorf("Expected set %s to have length %d, got %d", s, exp, res)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.Slice()
 | 
			
		||||
	exp := []string{One, Two, Three}
 | 
			
		||||
	ignoreOrder := cmpopts.SortSlices(func(a, b string) bool {
 | 
			
		||||
		return a < b
 | 
			
		||||
	})
 | 
			
		||||
	if !cmp.Equal(exp, out, ignoreOrder) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSortedSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.SortedSlice()
 | 
			
		||||
	exp := []string{One, Two, Three}
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								set/setuint/set.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										74
									
								
								set/setuint/set.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Set is a set of uint.
 | 
			
		||||
type Set struct {
 | 
			
		||||
	items map[uint]struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a new uint set.
 | 
			
		||||
func New(items ...uint) *Set {
 | 
			
		||||
	s := &Set{items: make(map[uint]struct{}, len(items))}
 | 
			
		||||
	s.Add(items...)
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add adds given items to the set.
 | 
			
		||||
func (s *Set) Add(items ...uint) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		s.items[item] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove delete given items from the set.
 | 
			
		||||
func (s *Set) Remove(items ...uint) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		delete(s.items, item)
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Has returns true if all the given items are included in the set.
 | 
			
		||||
func (s *Set) Has(items ...uint) bool {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		if _, ok := s.items[item]; !ok {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Len returns the size of the set.
 | 
			
		||||
func (s *Set) Len() int {
 | 
			
		||||
	return len(s.items)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Slice returns items of the set as a slice.
 | 
			
		||||
func (s *Set) Slice() []uint {
 | 
			
		||||
	sl := make([]uint, len(s.items))
 | 
			
		||||
	i := 0
 | 
			
		||||
	for item := range s.items {
 | 
			
		||||
		sl[i] = item
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	return sl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SortedSlice returns items of the set as a slice sorted ascending.
 | 
			
		||||
func (s *Set) SortedSlice() []uint {
 | 
			
		||||
	ss := s.Slice()
 | 
			
		||||
	sort.Slice(ss, func(i, j int) bool {
 | 
			
		||||
		return ss[i] < ss[j]
 | 
			
		||||
	})
 | 
			
		||||
	return ss
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String implements fmt.Stringer interface.
 | 
			
		||||
func (s *Set) String() string {
 | 
			
		||||
	return fmt.Sprintf("[%v]", s.Slice())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								set/setuint/set_test.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										116
									
								
								set/setuint/set_test.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,116 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp/cmpopts"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	One   uint = 1
 | 
			
		||||
	Two   uint = 2
 | 
			
		||||
	Three uint = 3
 | 
			
		||||
	Four  uint = 4
 | 
			
		||||
	Five  uint = 5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNew(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		t.Fatal("Set is nil")
 | 
			
		||||
	}
 | 
			
		||||
	if s.Len() != 3 {
 | 
			
		||||
		t.Errorf("Expected set to contain 3 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []uint{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAdd(t *testing.T) {
 | 
			
		||||
	s := New()
 | 
			
		||||
	if s.Len() != 0 {
 | 
			
		||||
		t.Errorf("Expected set to be empty, got %d items", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	s.Add(One)
 | 
			
		||||
	s.Add(Two, Three)
 | 
			
		||||
	for _, item := range []uint{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemove(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three, Four, Five)
 | 
			
		||||
	s.Remove(One, Two)
 | 
			
		||||
	s.Remove(Three)
 | 
			
		||||
	if s.Len() != 2 {
 | 
			
		||||
		t.Errorf("Expected set to contain 2 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []uint{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); ok {
 | 
			
		||||
			t.Errorf("Set is expected to not contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []uint{Four, Five} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHas(t *testing.T) {
 | 
			
		||||
	s := New(One, Two)
 | 
			
		||||
	table := map[uint]bool{
 | 
			
		||||
		One:   true,
 | 
			
		||||
		Two:   true,
 | 
			
		||||
		Three: false,
 | 
			
		||||
		Four:  false,
 | 
			
		||||
		Five:  false,
 | 
			
		||||
	}
 | 
			
		||||
	for v, exp := range table {
 | 
			
		||||
		if res := s.Has(v); res != exp {
 | 
			
		||||
			t.Errorf("Item: %v, In: %v, Expected: %v", v, res, exp)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLen(t *testing.T) {
 | 
			
		||||
	table := map[*Set]int{
 | 
			
		||||
		New():                                  0,
 | 
			
		||||
		New(One):                               1,
 | 
			
		||||
		New(Two, Three):                        2,
 | 
			
		||||
		New(One, Two, Three, Four, Five, Five): 5,
 | 
			
		||||
	}
 | 
			
		||||
	for s, exp := range table {
 | 
			
		||||
		if res := s.Len(); res != exp {
 | 
			
		||||
			t.Errorf("Expected set %s to have length %d, got %d", s, exp, res)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.Slice()
 | 
			
		||||
	exp := []uint{One, Two, Three}
 | 
			
		||||
	ignoreOrder := cmpopts.SortSlices(func(a, b uint) bool {
 | 
			
		||||
		return a < b
 | 
			
		||||
	})
 | 
			
		||||
	if !cmp.Equal(exp, out, ignoreOrder) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSortedSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.SortedSlice()
 | 
			
		||||
	exp := []uint{One, Two, Three}
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								set/setuint16/set.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										74
									
								
								set/setuint16/set.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Set is a set of uint16.
 | 
			
		||||
type Set struct {
 | 
			
		||||
	items map[uint16]struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a new uint16 set.
 | 
			
		||||
func New(items ...uint16) *Set {
 | 
			
		||||
	s := &Set{items: make(map[uint16]struct{}, len(items))}
 | 
			
		||||
	s.Add(items...)
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add adds given items to the set.
 | 
			
		||||
func (s *Set) Add(items ...uint16) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		s.items[item] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove delete given items from the set.
 | 
			
		||||
func (s *Set) Remove(items ...uint16) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		delete(s.items, item)
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Has returns true if all the given items are included in the set.
 | 
			
		||||
func (s *Set) Has(items ...uint16) bool {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		if _, ok := s.items[item]; !ok {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Len returns the size of the set.
 | 
			
		||||
func (s *Set) Len() int {
 | 
			
		||||
	return len(s.items)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Slice returns items of the set as a slice.
 | 
			
		||||
func (s *Set) Slice() []uint16 {
 | 
			
		||||
	sl := make([]uint16, len(s.items))
 | 
			
		||||
	i := 0
 | 
			
		||||
	for item := range s.items {
 | 
			
		||||
		sl[i] = item
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	return sl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SortedSlice returns items of the set as a slice sorted ascending.
 | 
			
		||||
func (s *Set) SortedSlice() []uint16 {
 | 
			
		||||
	ss := s.Slice()
 | 
			
		||||
	sort.Slice(ss, func(i, j int) bool {
 | 
			
		||||
		return ss[i] < ss[j]
 | 
			
		||||
	})
 | 
			
		||||
	return ss
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String implements fmt.Stringer interface.
 | 
			
		||||
func (s *Set) String() string {
 | 
			
		||||
	return fmt.Sprintf("[%v]", s.Slice())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								set/setuint16/set_test.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										116
									
								
								set/setuint16/set_test.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,116 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp/cmpopts"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	One   uint16 = 1
 | 
			
		||||
	Two   uint16 = 2
 | 
			
		||||
	Three uint16 = 3
 | 
			
		||||
	Four  uint16 = 4
 | 
			
		||||
	Five  uint16 = 5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNew(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		t.Fatal("Set is nil")
 | 
			
		||||
	}
 | 
			
		||||
	if s.Len() != 3 {
 | 
			
		||||
		t.Errorf("Expected set to contain 3 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []uint16{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAdd(t *testing.T) {
 | 
			
		||||
	s := New()
 | 
			
		||||
	if s.Len() != 0 {
 | 
			
		||||
		t.Errorf("Expected set to be empty, got %d items", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	s.Add(One)
 | 
			
		||||
	s.Add(Two, Three)
 | 
			
		||||
	for _, item := range []uint16{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemove(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three, Four, Five)
 | 
			
		||||
	s.Remove(One, Two)
 | 
			
		||||
	s.Remove(Three)
 | 
			
		||||
	if s.Len() != 2 {
 | 
			
		||||
		t.Errorf("Expected set to contain 2 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []uint16{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); ok {
 | 
			
		||||
			t.Errorf("Set is expected to not contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []uint16{Four, Five} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHas(t *testing.T) {
 | 
			
		||||
	s := New(One, Two)
 | 
			
		||||
	table := map[uint16]bool{
 | 
			
		||||
		One:   true,
 | 
			
		||||
		Two:   true,
 | 
			
		||||
		Three: false,
 | 
			
		||||
		Four:  false,
 | 
			
		||||
		Five:  false,
 | 
			
		||||
	}
 | 
			
		||||
	for v, exp := range table {
 | 
			
		||||
		if res := s.Has(v); res != exp {
 | 
			
		||||
			t.Errorf("Item: %v, In: %v, Expected: %v", v, res, exp)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLen(t *testing.T) {
 | 
			
		||||
	table := map[*Set]int{
 | 
			
		||||
		New():                                  0,
 | 
			
		||||
		New(One):                               1,
 | 
			
		||||
		New(Two, Three):                        2,
 | 
			
		||||
		New(One, Two, Three, Four, Five, Five): 5,
 | 
			
		||||
	}
 | 
			
		||||
	for s, exp := range table {
 | 
			
		||||
		if res := s.Len(); res != exp {
 | 
			
		||||
			t.Errorf("Expected set %s to have length %d, got %d", s, exp, res)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.Slice()
 | 
			
		||||
	exp := []uint16{One, Two, Three}
 | 
			
		||||
	ignoreOrder := cmpopts.SortSlices(func(a, b uint16) bool {
 | 
			
		||||
		return a < b
 | 
			
		||||
	})
 | 
			
		||||
	if !cmp.Equal(exp, out, ignoreOrder) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSortedSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.SortedSlice()
 | 
			
		||||
	exp := []uint16{One, Two, Three}
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								set/setuint32/set.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										74
									
								
								set/setuint32/set.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Set is a set of uint32.
 | 
			
		||||
type Set struct {
 | 
			
		||||
	items map[uint32]struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a new uint32 set.
 | 
			
		||||
func New(items ...uint32) *Set {
 | 
			
		||||
	s := &Set{items: make(map[uint32]struct{}, len(items))}
 | 
			
		||||
	s.Add(items...)
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add adds given items to the set.
 | 
			
		||||
func (s *Set) Add(items ...uint32) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		s.items[item] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove delete given items from the set.
 | 
			
		||||
func (s *Set) Remove(items ...uint32) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		delete(s.items, item)
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Has returns true if all the given items are included in the set.
 | 
			
		||||
func (s *Set) Has(items ...uint32) bool {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		if _, ok := s.items[item]; !ok {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Len returns the size of the set.
 | 
			
		||||
func (s *Set) Len() int {
 | 
			
		||||
	return len(s.items)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Slice returns items of the set as a slice.
 | 
			
		||||
func (s *Set) Slice() []uint32 {
 | 
			
		||||
	sl := make([]uint32, len(s.items))
 | 
			
		||||
	i := 0
 | 
			
		||||
	for item := range s.items {
 | 
			
		||||
		sl[i] = item
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	return sl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SortedSlice returns items of the set as a slice sorted ascending.
 | 
			
		||||
func (s *Set) SortedSlice() []uint32 {
 | 
			
		||||
	ss := s.Slice()
 | 
			
		||||
	sort.Slice(ss, func(i, j int) bool {
 | 
			
		||||
		return ss[i] < ss[j]
 | 
			
		||||
	})
 | 
			
		||||
	return ss
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String implements fmt.Stringer interface.
 | 
			
		||||
func (s *Set) String() string {
 | 
			
		||||
	return fmt.Sprintf("[%v]", s.Slice())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								set/setuint32/set_test.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										116
									
								
								set/setuint32/set_test.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,116 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp/cmpopts"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	One   uint32 = 1
 | 
			
		||||
	Two   uint32 = 2
 | 
			
		||||
	Three uint32 = 3
 | 
			
		||||
	Four  uint32 = 4
 | 
			
		||||
	Five  uint32 = 5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNew(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		t.Fatal("Set is nil")
 | 
			
		||||
	}
 | 
			
		||||
	if s.Len() != 3 {
 | 
			
		||||
		t.Errorf("Expected set to contain 3 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []uint32{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAdd(t *testing.T) {
 | 
			
		||||
	s := New()
 | 
			
		||||
	if s.Len() != 0 {
 | 
			
		||||
		t.Errorf("Expected set to be empty, got %d items", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	s.Add(One)
 | 
			
		||||
	s.Add(Two, Three)
 | 
			
		||||
	for _, item := range []uint32{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemove(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three, Four, Five)
 | 
			
		||||
	s.Remove(One, Two)
 | 
			
		||||
	s.Remove(Three)
 | 
			
		||||
	if s.Len() != 2 {
 | 
			
		||||
		t.Errorf("Expected set to contain 2 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []uint32{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); ok {
 | 
			
		||||
			t.Errorf("Set is expected to not contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []uint32{Four, Five} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHas(t *testing.T) {
 | 
			
		||||
	s := New(One, Two)
 | 
			
		||||
	table := map[uint32]bool{
 | 
			
		||||
		One:   true,
 | 
			
		||||
		Two:   true,
 | 
			
		||||
		Three: false,
 | 
			
		||||
		Four:  false,
 | 
			
		||||
		Five:  false,
 | 
			
		||||
	}
 | 
			
		||||
	for v, exp := range table {
 | 
			
		||||
		if res := s.Has(v); res != exp {
 | 
			
		||||
			t.Errorf("Item: %v, In: %v, Expected: %v", v, res, exp)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLen(t *testing.T) {
 | 
			
		||||
	table := map[*Set]int{
 | 
			
		||||
		New():                                  0,
 | 
			
		||||
		New(One):                               1,
 | 
			
		||||
		New(Two, Three):                        2,
 | 
			
		||||
		New(One, Two, Three, Four, Five, Five): 5,
 | 
			
		||||
	}
 | 
			
		||||
	for s, exp := range table {
 | 
			
		||||
		if res := s.Len(); res != exp {
 | 
			
		||||
			t.Errorf("Expected set %s to have length %d, got %d", s, exp, res)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.Slice()
 | 
			
		||||
	exp := []uint32{One, Two, Three}
 | 
			
		||||
	ignoreOrder := cmpopts.SortSlices(func(a, b uint32) bool {
 | 
			
		||||
		return a < b
 | 
			
		||||
	})
 | 
			
		||||
	if !cmp.Equal(exp, out, ignoreOrder) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSortedSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.SortedSlice()
 | 
			
		||||
	exp := []uint32{One, Two, Three}
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								set/setuint64/set.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										74
									
								
								set/setuint64/set.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Set is a set of uint64.
 | 
			
		||||
type Set struct {
 | 
			
		||||
	items map[uint64]struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a new uint64 set.
 | 
			
		||||
func New(items ...uint64) *Set {
 | 
			
		||||
	s := &Set{items: make(map[uint64]struct{}, len(items))}
 | 
			
		||||
	s.Add(items...)
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add adds given items to the set.
 | 
			
		||||
func (s *Set) Add(items ...uint64) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		s.items[item] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove delete given items from the set.
 | 
			
		||||
func (s *Set) Remove(items ...uint64) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		delete(s.items, item)
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Has returns true if all the given items are included in the set.
 | 
			
		||||
func (s *Set) Has(items ...uint64) bool {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		if _, ok := s.items[item]; !ok {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Len returns the size of the set.
 | 
			
		||||
func (s *Set) Len() int {
 | 
			
		||||
	return len(s.items)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Slice returns items of the set as a slice.
 | 
			
		||||
func (s *Set) Slice() []uint64 {
 | 
			
		||||
	sl := make([]uint64, len(s.items))
 | 
			
		||||
	i := 0
 | 
			
		||||
	for item := range s.items {
 | 
			
		||||
		sl[i] = item
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	return sl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SortedSlice returns items of the set as a slice sorted ascending.
 | 
			
		||||
func (s *Set) SortedSlice() []uint64 {
 | 
			
		||||
	ss := s.Slice()
 | 
			
		||||
	sort.Slice(ss, func(i, j int) bool {
 | 
			
		||||
		return ss[i] < ss[j]
 | 
			
		||||
	})
 | 
			
		||||
	return ss
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String implements fmt.Stringer interface.
 | 
			
		||||
func (s *Set) String() string {
 | 
			
		||||
	return fmt.Sprintf("[%v]", s.Slice())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								set/setuint64/set_test.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										116
									
								
								set/setuint64/set_test.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,116 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp/cmpopts"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	One   uint64 = 1
 | 
			
		||||
	Two   uint64 = 2
 | 
			
		||||
	Three uint64 = 3
 | 
			
		||||
	Four  uint64 = 4
 | 
			
		||||
	Five  uint64 = 5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNew(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		t.Fatal("Set is nil")
 | 
			
		||||
	}
 | 
			
		||||
	if s.Len() != 3 {
 | 
			
		||||
		t.Errorf("Expected set to contain 3 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []uint64{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAdd(t *testing.T) {
 | 
			
		||||
	s := New()
 | 
			
		||||
	if s.Len() != 0 {
 | 
			
		||||
		t.Errorf("Expected set to be empty, got %d items", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	s.Add(One)
 | 
			
		||||
	s.Add(Two, Three)
 | 
			
		||||
	for _, item := range []uint64{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemove(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three, Four, Five)
 | 
			
		||||
	s.Remove(One, Two)
 | 
			
		||||
	s.Remove(Three)
 | 
			
		||||
	if s.Len() != 2 {
 | 
			
		||||
		t.Errorf("Expected set to contain 2 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []uint64{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); ok {
 | 
			
		||||
			t.Errorf("Set is expected to not contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []uint64{Four, Five} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHas(t *testing.T) {
 | 
			
		||||
	s := New(One, Two)
 | 
			
		||||
	table := map[uint64]bool{
 | 
			
		||||
		One:   true,
 | 
			
		||||
		Two:   true,
 | 
			
		||||
		Three: false,
 | 
			
		||||
		Four:  false,
 | 
			
		||||
		Five:  false,
 | 
			
		||||
	}
 | 
			
		||||
	for v, exp := range table {
 | 
			
		||||
		if res := s.Has(v); res != exp {
 | 
			
		||||
			t.Errorf("Item: %v, In: %v, Expected: %v", v, res, exp)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLen(t *testing.T) {
 | 
			
		||||
	table := map[*Set]int{
 | 
			
		||||
		New():                                  0,
 | 
			
		||||
		New(One):                               1,
 | 
			
		||||
		New(Two, Three):                        2,
 | 
			
		||||
		New(One, Two, Three, Four, Five, Five): 5,
 | 
			
		||||
	}
 | 
			
		||||
	for s, exp := range table {
 | 
			
		||||
		if res := s.Len(); res != exp {
 | 
			
		||||
			t.Errorf("Expected set %s to have length %d, got %d", s, exp, res)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.Slice()
 | 
			
		||||
	exp := []uint64{One, Two, Three}
 | 
			
		||||
	ignoreOrder := cmpopts.SortSlices(func(a, b uint64) bool {
 | 
			
		||||
		return a < b
 | 
			
		||||
	})
 | 
			
		||||
	if !cmp.Equal(exp, out, ignoreOrder) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSortedSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.SortedSlice()
 | 
			
		||||
	exp := []uint64{One, Two, Three}
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								set/setuint8/set.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										74
									
								
								set/setuint8/set.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Set is a set of uint8.
 | 
			
		||||
type Set struct {
 | 
			
		||||
	items map[uint8]struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a new uint8 set.
 | 
			
		||||
func New(items ...uint8) *Set {
 | 
			
		||||
	s := &Set{items: make(map[uint8]struct{}, len(items))}
 | 
			
		||||
	s.Add(items...)
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add adds given items to the set.
 | 
			
		||||
func (s *Set) Add(items ...uint8) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		s.items[item] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove delete given items from the set.
 | 
			
		||||
func (s *Set) Remove(items ...uint8) *Set {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		delete(s.items, item)
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Has returns true if all the given items are included in the set.
 | 
			
		||||
func (s *Set) Has(items ...uint8) bool {
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		if _, ok := s.items[item]; !ok {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Len returns the size of the set.
 | 
			
		||||
func (s *Set) Len() int {
 | 
			
		||||
	return len(s.items)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Slice returns items of the set as a slice.
 | 
			
		||||
func (s *Set) Slice() []uint8 {
 | 
			
		||||
	sl := make([]uint8, len(s.items))
 | 
			
		||||
	i := 0
 | 
			
		||||
	for item := range s.items {
 | 
			
		||||
		sl[i] = item
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	return sl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SortedSlice returns items of the set as a slice sorted ascending.
 | 
			
		||||
func (s *Set) SortedSlice() []uint8 {
 | 
			
		||||
	ss := s.Slice()
 | 
			
		||||
	sort.Slice(ss, func(i, j int) bool {
 | 
			
		||||
		return ss[i] < ss[j]
 | 
			
		||||
	})
 | 
			
		||||
	return ss
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String implements fmt.Stringer interface.
 | 
			
		||||
func (s *Set) String() string {
 | 
			
		||||
	return fmt.Sprintf("[%v]", s.Slice())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								set/setuint8/set_test.go
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										116
									
								
								set/setuint8/set_test.go
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,116 @@
 | 
			
		||||
package impl
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp/cmpopts"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	One   uint8 = 1
 | 
			
		||||
	Two   uint8 = 2
 | 
			
		||||
	Three uint8 = 3
 | 
			
		||||
	Four  uint8 = 4
 | 
			
		||||
	Five  uint8 = 5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNew(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		t.Fatal("Set is nil")
 | 
			
		||||
	}
 | 
			
		||||
	if s.Len() != 3 {
 | 
			
		||||
		t.Errorf("Expected set to contain 3 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []uint8{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAdd(t *testing.T) {
 | 
			
		||||
	s := New()
 | 
			
		||||
	if s.Len() != 0 {
 | 
			
		||||
		t.Errorf("Expected set to be empty, got %d items", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	s.Add(One)
 | 
			
		||||
	s.Add(Two, Three)
 | 
			
		||||
	for _, item := range []uint8{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemove(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three, Four, Five)
 | 
			
		||||
	s.Remove(One, Two)
 | 
			
		||||
	s.Remove(Three)
 | 
			
		||||
	if s.Len() != 2 {
 | 
			
		||||
		t.Errorf("Expected set to contain 2 items, got %d", s.Len())
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []uint8{One, Two, Three} {
 | 
			
		||||
		if ok := s.Has(item); ok {
 | 
			
		||||
			t.Errorf("Set is expected to not contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range []uint8{Four, Five} {
 | 
			
		||||
		if ok := s.Has(item); !ok {
 | 
			
		||||
			t.Errorf("Set is expected to contain item %q", item)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHas(t *testing.T) {
 | 
			
		||||
	s := New(One, Two)
 | 
			
		||||
	table := map[uint8]bool{
 | 
			
		||||
		One:   true,
 | 
			
		||||
		Two:   true,
 | 
			
		||||
		Three: false,
 | 
			
		||||
		Four:  false,
 | 
			
		||||
		Five:  false,
 | 
			
		||||
	}
 | 
			
		||||
	for v, exp := range table {
 | 
			
		||||
		if res := s.Has(v); res != exp {
 | 
			
		||||
			t.Errorf("Item: %v, In: %v, Expected: %v", v, res, exp)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLen(t *testing.T) {
 | 
			
		||||
	table := map[*Set]int{
 | 
			
		||||
		New():                                  0,
 | 
			
		||||
		New(One):                               1,
 | 
			
		||||
		New(Two, Three):                        2,
 | 
			
		||||
		New(One, Two, Three, Four, Five, Five): 5,
 | 
			
		||||
	}
 | 
			
		||||
	for s, exp := range table {
 | 
			
		||||
		if res := s.Len(); res != exp {
 | 
			
		||||
			t.Errorf("Expected set %s to have length %d, got %d", s, exp, res)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.Slice()
 | 
			
		||||
	exp := []uint8{One, Two, Three}
 | 
			
		||||
	ignoreOrder := cmpopts.SortSlices(func(a, b uint8) bool {
 | 
			
		||||
		return a < b
 | 
			
		||||
	})
 | 
			
		||||
	if !cmp.Equal(exp, out, ignoreOrder) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSortedSlice(t *testing.T) {
 | 
			
		||||
	s := New(One, Two, Three)
 | 
			
		||||
	out := s.SortedSlice()
 | 
			
		||||
	exp := []uint8{One, Two, Three}
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Retured slice does not match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										106
									
								
								sqldb/conn.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								sqldb/conn.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,106 @@
 | 
			
		||||
package sqldb
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/juju/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Conn represents database connection.
 | 
			
		||||
type Conn struct {
 | 
			
		||||
	db *sql.DB
 | 
			
		||||
 | 
			
		||||
	beforeCallbacks []BeforeCallback
 | 
			
		||||
	afterCallbacks  []AfterCallback
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	// BeforeCallback is a kind of function that can be called before a query is
 | 
			
		||||
	// executed.
 | 
			
		||||
	BeforeCallback func(ctx context.Context, query string)
 | 
			
		||||
	// AfterCallback is a kind of function that can be called after a query was
 | 
			
		||||
	// executed.
 | 
			
		||||
	AfterCallback func(ctx context.Context, query string, took time.Duration, err error)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Flavor defines a kind of SQL database.
 | 
			
		||||
type Flavor string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// MySQL is the MySQL SQL flavor.
 | 
			
		||||
	MySQL Flavor = "mysql"
 | 
			
		||||
	// PostgreSQL is the PostgreSQL SQL flavor.
 | 
			
		||||
	PostgreSQL Flavor = "postgresql"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Connect establishes a new database connection.
 | 
			
		||||
func Connect(ctx context.Context, f Flavor, dsn string) (*Conn, error) {
 | 
			
		||||
	conn, err := sql.Open(string(f), dsn)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Annotate(err, "Failed to establish connection")
 | 
			
		||||
	}
 | 
			
		||||
	err = conn.PingContext(ctx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Annotate(err, "Connection is not responding")
 | 
			
		||||
	}
 | 
			
		||||
	return &Conn{db: conn}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Exec executes a query and does not expect any result.
 | 
			
		||||
func (c *Conn) Exec(ctx context.Context, query string, args ...interface{}) Result {
 | 
			
		||||
	c.callBefore(ctx, query)
 | 
			
		||||
	startedAt := time.Now()
 | 
			
		||||
	res, err := c.db.ExecContext(ctx, query, args...)
 | 
			
		||||
	c.callAfter(ctx, query, time.Since(startedAt), err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return result{err: err}
 | 
			
		||||
	}
 | 
			
		||||
	return result{res: res}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Query executes a query and returns a result object that can later be used to
 | 
			
		||||
// retrieve values.
 | 
			
		||||
func (c *Conn) Query(ctx context.Context, query string, args ...interface{}) Result {
 | 
			
		||||
	var r result
 | 
			
		||||
	c.callBefore(ctx, query)
 | 
			
		||||
	startedAt := time.Now()
 | 
			
		||||
	r.rows, r.err = c.db.QueryContext(ctx, query, args...)
 | 
			
		||||
	c.callAfter(ctx, query, time.Since(startedAt), r.err)
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DB returns the underlying DB object.
 | 
			
		||||
func (c *Conn) DB() *sql.DB {
 | 
			
		||||
	return c.db
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close closes the connection.
 | 
			
		||||
func (c *Conn) Close() error {
 | 
			
		||||
	return c.db.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Before adds a callback function that would be called before a query is
 | 
			
		||||
// executed.
 | 
			
		||||
func (c *Conn) Before(cb BeforeCallback) {
 | 
			
		||||
	c.beforeCallbacks = append(c.beforeCallbacks, cb)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// After adds a callback function that would be called after a query was
 | 
			
		||||
// executed.
 | 
			
		||||
func (c *Conn) After(cb AfterCallback) {
 | 
			
		||||
	c.afterCallbacks = append(c.afterCallbacks, cb)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) callBefore(ctx context.Context, query string) {
 | 
			
		||||
	for _, cb := range c.beforeCallbacks {
 | 
			
		||||
		cb(ctx, query)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) callAfter(ctx context.Context, query string, took time.Duration, err error) {
 | 
			
		||||
	for _, cb := range c.afterCallbacks {
 | 
			
		||||
		cb(ctx, query, took, err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										312
									
								
								sqldb/result.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										312
									
								
								sqldb/result.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,312 @@
 | 
			
		||||
package sqldb
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Result represents query result.
 | 
			
		||||
type Result interface {
 | 
			
		||||
	// Load decodes rows into provided variable.
 | 
			
		||||
	Load(dest interface{}) Result
 | 
			
		||||
	// Error returns an error if one happened during query execution.
 | 
			
		||||
	Error() error
 | 
			
		||||
	// Rows returns original database rows object.
 | 
			
		||||
	Rows() *sql.Rows
 | 
			
		||||
	// LastInsertID returns the last inserted record ID for results obtained
 | 
			
		||||
	// from Exec calls.
 | 
			
		||||
	LastInsertID() int64
 | 
			
		||||
	// RowsAffected returns the number of rows affected for results obtained
 | 
			
		||||
	// from Exec calls.
 | 
			
		||||
	RowsAffected() int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type result struct {
 | 
			
		||||
	rows *sql.Rows
 | 
			
		||||
	res  sql.Result
 | 
			
		||||
	err  error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r result) Rows() *sql.Rows {
 | 
			
		||||
	return r.rows
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r result) Error() error {
 | 
			
		||||
	return r.err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r result) LastInsertID() int64 {
 | 
			
		||||
	if r.res == nil {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	id, err := r.res.LastInsertId()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return id
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r result) RowsAffected() int64 {
 | 
			
		||||
	if r.res == nil {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	ra, err := r.res.RowsAffected()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return ra
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r result) Load(dest interface{}) Result {
 | 
			
		||||
	if r.err != nil {
 | 
			
		||||
		return r
 | 
			
		||||
	}
 | 
			
		||||
	defer r.rows.Close()
 | 
			
		||||
 | 
			
		||||
	dtyp := reflect.TypeOf(dest)
 | 
			
		||||
	if dtyp.Kind() != reflect.Ptr {
 | 
			
		||||
		panic("Value must be a pointer")
 | 
			
		||||
	}
 | 
			
		||||
	dtyp = dtyp.Elem()
 | 
			
		||||
 | 
			
		||||
	switch dtyp.Kind() {
 | 
			
		||||
	case reflect.Struct:
 | 
			
		||||
		r.loadStruct(dtyp, dest)
 | 
			
		||||
	case reflect.Map:
 | 
			
		||||
		r.loadMap(dest.(*map[string]interface{}))
 | 
			
		||||
	case reflect.Slice:
 | 
			
		||||
		switch dtyp.Elem().Kind() {
 | 
			
		||||
		case reflect.Struct:
 | 
			
		||||
			r.loadSliceOfStructs(dtyp, dest)
 | 
			
		||||
		case reflect.Map:
 | 
			
		||||
			r.loadSliceOfMaps(dest.(*[]map[string]interface{}))
 | 
			
		||||
		default:
 | 
			
		||||
			r.loadSlice(dtyp, dest)
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		r.loadValue(dest)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if r.err == nil && r.rows.Err() != nil {
 | 
			
		||||
		return r.withError(r.rows.Err())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *result) loadValue(dest interface{}) {
 | 
			
		||||
	if r.rows.Next() {
 | 
			
		||||
		r.err = r.rows.Scan(dest)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *result) loadSlice(typ reflect.Type, dest interface{}) {
 | 
			
		||||
	vSlice := reflect.MakeSlice(typ, 0, 0)
 | 
			
		||||
	for r.rows.Next() {
 | 
			
		||||
		val := reflect.New(typ.Elem())
 | 
			
		||||
		r.err = r.rows.Scan(val.Interface())
 | 
			
		||||
		if r.err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		vSlice = reflect.Append(vSlice, val.Elem())
 | 
			
		||||
	}
 | 
			
		||||
	reflect.ValueOf(dest).Elem().Set(vSlice)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *result) loadMap(dest *map[string]interface{}) {
 | 
			
		||||
	if !r.rows.Next() {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cols, err := r.rows.Columns()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		r.err = err
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	colTypes, err := r.rows.ColumnTypes()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		r.err = err
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vals := make([]interface{}, len(cols))
 | 
			
		||||
	for i := range cols {
 | 
			
		||||
		vals[i] = newValue(colTypes[i])
 | 
			
		||||
	}
 | 
			
		||||
	err = r.rows.Scan(vals...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		r.err = err
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if *dest == nil {
 | 
			
		||||
		*dest = make(map[string]interface{}, len(cols))
 | 
			
		||||
	}
 | 
			
		||||
	for i, col := range cols {
 | 
			
		||||
		switch tval := vals[i].(type) {
 | 
			
		||||
		case *int64:
 | 
			
		||||
			(*dest)[col] = *tval
 | 
			
		||||
		case *string:
 | 
			
		||||
			(*dest)[col] = *tval
 | 
			
		||||
		case *bool:
 | 
			
		||||
			(*dest)[col] = *tval
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *result) loadSliceOfMaps(dest *[]map[string]interface{}) {
 | 
			
		||||
	cols, err := r.rows.Columns()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		r.err = err
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	colTypes, err := r.rows.ColumnTypes()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		r.err = err
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if *dest == nil {
 | 
			
		||||
		*dest = make([]map[string]interface{}, 0)
 | 
			
		||||
	}
 | 
			
		||||
	for r.rows.Next() {
 | 
			
		||||
		vals := make([]interface{}, len(cols))
 | 
			
		||||
		for i := range cols {
 | 
			
		||||
			vals[i] = newValue(colTypes[i])
 | 
			
		||||
		}
 | 
			
		||||
		err = r.rows.Scan(vals...)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			r.err = err
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		row := make(map[string]interface{}, len(cols))
 | 
			
		||||
		for i, col := range cols {
 | 
			
		||||
			switch tval := vals[i].(type) {
 | 
			
		||||
			case *int64:
 | 
			
		||||
				row[col] = *tval
 | 
			
		||||
			case *string:
 | 
			
		||||
				row[col] = *tval
 | 
			
		||||
			case *bool:
 | 
			
		||||
				row[col] = *tval
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		*dest = append(*dest, row)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *result) loadStruct(typ reflect.Type, dest interface{}) {
 | 
			
		||||
	if !r.rows.Next() {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cols, err := r.rows.Columns()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		r.err = err
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	val := reflect.ValueOf(dest).Elem()
 | 
			
		||||
	vals := make([]interface{}, len(cols))
 | 
			
		||||
	tm := tagMap(cols, val.Type())
 | 
			
		||||
	for i := range cols {
 | 
			
		||||
		if fi, ok := tm[i]; ok {
 | 
			
		||||
			fval := val.Field(fi)
 | 
			
		||||
			vals[i] = reflect.New(fval.Type()).Interface()
 | 
			
		||||
		} else {
 | 
			
		||||
			var dummy interface{}
 | 
			
		||||
			vals[i] = &dummy
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = r.rows.Scan(vals...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		r.err = err
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, fi := range tm {
 | 
			
		||||
		fval := val.Field(fi)
 | 
			
		||||
		fval.Set(reflect.ValueOf(vals[i]).Elem())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *result) loadSliceOfStructs(typ reflect.Type, dest interface{}) {
 | 
			
		||||
	cols, err := r.rows.Columns()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		r.err = err
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vSlice := reflect.ValueOf(dest).Elem()
 | 
			
		||||
	tSlice := vSlice.Type()
 | 
			
		||||
	tElem := tSlice.Elem()
 | 
			
		||||
	tm := tagMap(cols, tElem)
 | 
			
		||||
 | 
			
		||||
	for r.rows.Next() {
 | 
			
		||||
		vals := make([]interface{}, len(cols))
 | 
			
		||||
		val := reflect.New(tElem).Elem()
 | 
			
		||||
		for i := range cols {
 | 
			
		||||
			if fi, ok := tm[i]; ok {
 | 
			
		||||
				fval := val.Field(fi)
 | 
			
		||||
				vals[i] = reflect.New(fval.Type()).Interface()
 | 
			
		||||
			} else {
 | 
			
		||||
				var dummy interface{}
 | 
			
		||||
				vals[i] = &dummy
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err = r.rows.Scan(vals...)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			r.err = err
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for i, fi := range tm {
 | 
			
		||||
			fval := val.Field(fi)
 | 
			
		||||
			fval.Set(reflect.ValueOf(vals[i]).Elem())
 | 
			
		||||
		}
 | 
			
		||||
		vSlice.Set(reflect.Append(vSlice, val))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r result) withError(err error) Result {
 | 
			
		||||
	r.err = err
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newValue(typ *sql.ColumnType) interface{} {
 | 
			
		||||
	switch typ.DatabaseTypeName() {
 | 
			
		||||
	case "VARCHAR", "NVARCHAR", "TEXT":
 | 
			
		||||
		var s string
 | 
			
		||||
		return &s
 | 
			
		||||
	case "INT", "BIGINT":
 | 
			
		||||
		var i int64
 | 
			
		||||
		return &i
 | 
			
		||||
	case "BOOL":
 | 
			
		||||
		var b bool
 | 
			
		||||
		return &b
 | 
			
		||||
	default:
 | 
			
		||||
		panic(fmt.Errorf("Unsupported MySQL type: %s", typ.DatabaseTypeName()))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func tagMap(cols []string, typ reflect.Type) map[int]int {
 | 
			
		||||
	fieldIndices := map[string]int{}
 | 
			
		||||
	for i := 0; i < typ.NumField(); i++ {
 | 
			
		||||
		tag := typ.Field(i).Tag.Get("db")
 | 
			
		||||
		if tag != "" {
 | 
			
		||||
			fieldIndices[tag] = i
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	colFields := map[int]int{}
 | 
			
		||||
	for i, col := range cols {
 | 
			
		||||
		if fi, ok := fieldIndices[col]; ok {
 | 
			
		||||
			colFields[i] = fi
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return colFields
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								sqldb/result_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								sqldb/result_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
package sqldb
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestLoadSingleValue(t *testing.T) {
 | 
			
		||||
	ctx := context.Background()
 | 
			
		||||
	exp := int(1)
 | 
			
		||||
	var out int
 | 
			
		||||
	mustT(t, conn.Query(ctx, "SELECT 1").Load(&out))
 | 
			
		||||
	if exp != out {
 | 
			
		||||
		t.Errorf("Value doesn't match: expected %d, got %d", exp, out)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLoadSlice(t *testing.T) {
 | 
			
		||||
	ctx := context.Background()
 | 
			
		||||
	exp := []int{1, 2}
 | 
			
		||||
	var out []int
 | 
			
		||||
	mustT(t, conn.Query(ctx, "SELECT id FROM sqldb_test").Load(&out))
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Values dont't match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLoadMap(t *testing.T) {
 | 
			
		||||
	ctx := context.Background()
 | 
			
		||||
	exp := map[string]interface{}{"id": int64(1), "name": "Alice"}
 | 
			
		||||
	var out map[string]interface{}
 | 
			
		||||
	mustT(t, conn.Query(ctx, "SELECT * FROM sqldb_test WHERE id = 1").Load(&out))
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Record doesn't match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLoadSliceOfMaps(t *testing.T) {
 | 
			
		||||
	ctx := context.Background()
 | 
			
		||||
	exp := []map[string]interface{}{
 | 
			
		||||
		{"id": int64(1), "name": "Alice"},
 | 
			
		||||
		{"id": int64(2), "name": "Bob"},
 | 
			
		||||
	}
 | 
			
		||||
	var out []map[string]interface{}
 | 
			
		||||
	mustT(t, conn.Query(ctx, "SELECT * FROM sqldb_test ORDER BY id ASC").Load(&out))
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Records don't match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLoadStruct(t *testing.T) {
 | 
			
		||||
	ctx := context.Background()
 | 
			
		||||
	exp := record{ID: 1, Name: "Alice"}
 | 
			
		||||
	var out record
 | 
			
		||||
	mustT(t, conn.Query(ctx, "SELECT * FROM sqldb_test WHERE id = 1").Load(&out))
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Record doesn't match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLoadSliceOfStructs(t *testing.T) {
 | 
			
		||||
	ctx := context.Background()
 | 
			
		||||
	exp := []record{
 | 
			
		||||
		{ID: 1, Name: "Alice"},
 | 
			
		||||
		{ID: 2, Name: "Bob"},
 | 
			
		||||
	}
 | 
			
		||||
	var out []record
 | 
			
		||||
	mustT(t, conn.Query(ctx, "SELECT * FROM sqldb_test").Load(&out))
 | 
			
		||||
	if !cmp.Equal(exp, out) {
 | 
			
		||||
		t.Errorf("Records don't match: %s", cmp.Diff(exp, out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										77
									
								
								sqldb/sqldb_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								sqldb/sqldb_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,77 @@
 | 
			
		||||
package sqldb
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"flag"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"os"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	_ "github.com/go-sql-driver/mysql" // MySQL driver
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type record struct {
 | 
			
		||||
	ID   uint   `db:"id"`
 | 
			
		||||
	Name string `db:"name"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var conn *Conn
 | 
			
		||||
 | 
			
		||||
func TestMain(m *testing.M) {
 | 
			
		||||
	dsn := flag.String("dsn", "", "Database source name")
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
	if *dsn == "" {
 | 
			
		||||
		log.Println("Database source name is not provided, skipping package tests")
 | 
			
		||||
		os.Exit(0)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Println("Establishing connection to the test database")
 | 
			
		||||
	ctx := context.Background()
 | 
			
		||||
	var err error
 | 
			
		||||
	conn, err = Connect(ctx, MySQL, *dsn)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalf("Failed to connect: %v\n", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Println("Seeding database")
 | 
			
		||||
	must(conn.Exec(ctx, `
 | 
			
		||||
		DROP TABLE IF EXISTS sqldb_test
 | 
			
		||||
	`))
 | 
			
		||||
	must(conn.Exec(ctx, `
 | 
			
		||||
		CREATE TABLE sqldb_test (
 | 
			
		||||
			id int(11) UNSIGNED NOT NULL,
 | 
			
		||||
			name VARCHAR(10) DEFAULT '',
 | 
			
		||||
			PRIMARY KEY (id)
 | 
			
		||||
		) ENGINE=InnoDB DEFAULT CHARSET=ascii
 | 
			
		||||
	`))
 | 
			
		||||
	must(conn.Exec(ctx, `
 | 
			
		||||
		INSERT INTO sqldb_test (id, name) 
 | 
			
		||||
		VALUES
 | 
			
		||||
			(1, "Alice"),
 | 
			
		||||
			(2, "Bob")
 | 
			
		||||
	`))
 | 
			
		||||
 | 
			
		||||
	fmt.Println("Starting test suite")
 | 
			
		||||
	exitCode := m.Run()
 | 
			
		||||
	log.Println("Test suite finished")
 | 
			
		||||
	if err := conn.Close(); err != nil {
 | 
			
		||||
		log.Printf("Failed to close connection: %v\n", err)
 | 
			
		||||
	}
 | 
			
		||||
	os.Exit(exitCode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func mustT(t *testing.T, r Result) Result {
 | 
			
		||||
	t.Helper()
 | 
			
		||||
	if r.Error() != nil {
 | 
			
		||||
		t.Fatalf("Query failed: %v", r.Error())
 | 
			
		||||
	}
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func must(r Result) Result {
 | 
			
		||||
	if r.Error() != nil {
 | 
			
		||||
		log.Fatalf("Query failed: %v\n", r.Error())
 | 
			
		||||
	}
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user