// Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause package nocasemaps import ( "strings" "testing" qt "github.com/frankban/quicktest" xmaps "golang.org/x/exp/maps" ) func pair[A, B any](a A, b B) (out struct { A A B B }) { out.A = a out.B = b return out } func Test(t *testing.T) { c := qt.New(t) m := make(map[string]int) Set(m, "hello", 1) c.Assert(m, qt.DeepEquals, map[string]int{"hello": 1}) Set(m, "HeLlO", 2) c.Assert(m, qt.DeepEquals, map[string]int{"hello": 2}) c.Assert(Get(m, "hello"), qt.Equals, 2) c.Assert(pair(GetOk(m, "hello")), qt.Equals, pair(2, true)) c.Assert(Get(m, "HeLlO"), qt.Equals, 2) c.Assert(pair(GetOk(m, "HeLlO")), qt.Equals, pair(2, true)) c.Assert(Get(m, "HELLO"), qt.Equals, 2) c.Assert(pair(GetOk(m, "HELLO")), qt.Equals, pair(2, true)) c.Assert(Get(m, "missing"), qt.Equals, 0) c.Assert(pair(GetOk(m, "missing")), qt.Equals, pair(0, false)) Set(m, "foo", 3) Set(m, "BAR", 4) Set(m, "bAz", 5) c.Assert(m, qt.DeepEquals, map[string]int{"hello": 2, "foo": 3, "bar": 4, "baz": 5}) Delete(m, "foo") c.Assert(m, qt.DeepEquals, map[string]int{"hello": 2, "bar": 4, "baz": 5}) Delete(m, "bar") c.Assert(m, qt.DeepEquals, map[string]int{"hello": 2, "baz": 5}) Delete(m, "BAZ") c.Assert(m, qt.DeepEquals, map[string]int{"hello": 2}) // test cases for AppendSliceElem with int slices appendTestInt := make(map[string][]int) Set(appendTestInt, "firsT", []int{7}) c.Assert(appendTestInt, qt.DeepEquals, map[string][]int{"first": {7}}) AppendSliceElem(appendTestInt, "firsT", 77) c.Assert(appendTestInt, qt.DeepEquals, map[string][]int{"first": {7, 77}}) Set(appendTestInt, "SeCOnd", []int{56}) c.Assert(appendTestInt, qt.DeepEquals, map[string][]int{"first": {7, 77}, "second": {56}}) AppendSliceElem(appendTestInt, "seCOnd", 563, 23) c.Assert(appendTestInt, qt.DeepEquals, map[string][]int{"first": {7, 77}, "second": {56, 563, 23}}) // test cases for AppendSliceElem with string slices appendTestString := make(map[string][]string) Set(appendTestString, "firsTSTRING", []string{"hi"}) c.Assert(appendTestString, qt.DeepEquals, map[string][]string{"firststring": {"hi"}}) AppendSliceElem(appendTestString, "firsTSTRING", "hello", "bye") c.Assert(appendTestString, qt.DeepEquals, map[string][]string{"firststring": {"hi", "hello", "bye"}}) } var lowerTests = []struct{ in, want string }{ {"", ""}, {"abc", "abc"}, {"AbC123", "abc123"}, {"azAZ09_", "azaz09_"}, {"longStrinGwitHmixofsmaLLandcAps", "longstringwithmixofsmallandcaps"}, {"renan bastos 93 AOSDAJDJAIDJAIDAJIaidsjjaidijadsjiadjiOOKKO", "renan bastos 93 aosdajdjaidjaidajiaidsjjaidijadsjiadjiookko"}, {"LONG\u2C6FSTRING\u2C6FWITH\u2C6FNONASCII\u2C6FCHARS", "long\u0250string\u0250with\u0250nonascii\u0250chars"}, {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char {"A\u0080\U0010FFFF", "a\u0080\U0010FFFF"}, // test utf8.RuneSelf and utf8.MaxRune } func TestAppendToLower(t *testing.T) { for _, tt := range lowerTests { got := string(appendToLower(nil, tt.in)) if got != tt.want { t.Errorf("appendToLower(%q) = %q, want %q", tt.in, got, tt.want) } } } func FuzzAppendToLower(f *testing.F) { for _, tt := range lowerTests { f.Add(tt.in) } f.Fuzz(func(t *testing.T, in string) { got := string(appendToLower(nil, in)) want := strings.ToLower(in) if got != want { t.Errorf("appendToLower(%q) = %q, want %q", in, got, want) } }) } var ( testLower = "production-server" testUpper = "PRODUCTION-SERVER" testMap = make(map[string]int) testValue = 5 testSink int ) func Benchmark(b *testing.B) { for i, key := range []string{testLower, testUpper} { b.Run([]string{"Lower", "Upper"}[i], func(b *testing.B) { b.Run("Get", func(b *testing.B) { b.Run("Naive", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { testSink = testMap[strings.ToLower(key)] } }) b.Run("NoCase", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { testSink = Get(testMap, key) } }) }) b.Run("Set", func(b *testing.B) { b.Run("Naive", func(b *testing.B) { b.ReportAllocs() testMap[strings.ToLower(key)] = testValue for i := 0; i < b.N; i++ { testMap[strings.ToLower(key)] = testValue } xmaps.Clear(testMap) }) b.Run("NoCase", func(b *testing.B) { b.ReportAllocs() Set(testMap, key, testValue) for i := 0; i < b.N; i++ { Set(testMap, key, testValue) } xmaps.Clear(testMap) }) }) b.Run("Delete", func(b *testing.B) { b.Run("Naive", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { delete(testMap, strings.ToLower(key)) } }) b.Run("NoCase", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { Delete(testMap, key) } }) }) }) } }