1// Copyright 2023 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package http
6
7import (
8	"cmp"
9	"fmt"
10	"slices"
11	"strconv"
12	"testing"
13)
14
15func TestMapping(t *testing.T) {
16	var m mapping[int, string]
17	for i := 0; i < maxSlice; i++ {
18		m.add(i, strconv.Itoa(i))
19	}
20	if m.m != nil {
21		t.Fatal("m.m != nil")
22	}
23	for i := 0; i < maxSlice; i++ {
24		g, _ := m.find(i)
25		w := strconv.Itoa(i)
26		if g != w {
27			t.Fatalf("%d: got %s, want %s", i, g, w)
28		}
29	}
30	m.add(4, "4")
31	if m.s != nil {
32		t.Fatal("m.s != nil")
33	}
34	if m.m == nil {
35		t.Fatal("m.m == nil")
36	}
37	g, _ := m.find(4)
38	if w := "4"; g != w {
39		t.Fatalf("got %s, want %s", g, w)
40	}
41}
42
43func TestMappingEachPair(t *testing.T) {
44	var m mapping[int, string]
45	var want []entry[int, string]
46	for i := 0; i < maxSlice*2; i++ {
47		v := strconv.Itoa(i)
48		m.add(i, v)
49		want = append(want, entry[int, string]{i, v})
50
51	}
52
53	var got []entry[int, string]
54	m.eachPair(func(k int, v string) bool {
55		got = append(got, entry[int, string]{k, v})
56		return true
57	})
58	slices.SortFunc(got, func(e1, e2 entry[int, string]) int {
59		return cmp.Compare(e1.key, e2.key)
60	})
61	if !slices.Equal(got, want) {
62		t.Errorf("got %v, want %v", got, want)
63	}
64}
65
66func BenchmarkFindChild(b *testing.B) {
67	key := "articles"
68	children := []string{
69		"*",
70		"cmd.html",
71		"code.html",
72		"contrib.html",
73		"contribute.html",
74		"debugging_with_gdb.html",
75		"docs.html",
76		"effective_go.html",
77		"files.log",
78		"gccgo_contribute.html",
79		"gccgo_install.html",
80		"go-logo-black.png",
81		"go-logo-blue.png",
82		"go-logo-white.png",
83		"go1.1.html",
84		"go1.2.html",
85		"go1.html",
86		"go1compat.html",
87		"go_faq.html",
88		"go_mem.html",
89		"go_spec.html",
90		"help.html",
91		"ie.css",
92		"install-source.html",
93		"install.html",
94		"logo-153x55.png",
95		"Makefile",
96		"root.html",
97		"share.png",
98		"sieve.gif",
99		"tos.html",
100		"articles",
101	}
102	if len(children) != 32 {
103		panic("bad len")
104	}
105	for _, n := range []int{2, 4, 8, 16, 32} {
106		list := children[:n]
107		b.Run(fmt.Sprintf("n=%d", n), func(b *testing.B) {
108
109			b.Run("rep=linear", func(b *testing.B) {
110				var entries []entry[string, any]
111				for _, c := range list {
112					entries = append(entries, entry[string, any]{c, nil})
113				}
114				b.ResetTimer()
115				for i := 0; i < b.N; i++ {
116					findChildLinear(key, entries)
117				}
118			})
119			b.Run("rep=map", func(b *testing.B) {
120				m := map[string]any{}
121				for _, c := range list {
122					m[c] = nil
123				}
124				var x any
125				b.ResetTimer()
126				for i := 0; i < b.N; i++ {
127					x = m[key]
128				}
129				_ = x
130			})
131			b.Run(fmt.Sprintf("rep=hybrid%d", maxSlice), func(b *testing.B) {
132				var h mapping[string, any]
133				for _, c := range list {
134					h.add(c, nil)
135				}
136				var x any
137				b.ResetTimer()
138				for i := 0; i < b.N; i++ {
139					x, _ = h.find(key)
140				}
141				_ = x
142			})
143		})
144	}
145}
146
147func findChildLinear(key string, entries []entry[string, any]) any {
148	for _, e := range entries {
149		if key == e.key {
150			return e.value
151		}
152	}
153	return nil
154}
155