1// Copyright 2020 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 label_test
6
7import (
8	"bytes"
9	"fmt"
10	"runtime"
11	"testing"
12	"unsafe"
13
14	"golang.org/x/tools/internal/event/keys"
15	"golang.org/x/tools/internal/event/label"
16)
17
18var (
19	AKey = keys.NewString("A", "")
20	BKey = keys.NewString("B", "")
21	CKey = keys.NewString("C", "")
22	A    = AKey.Of("a")
23	B    = BKey.Of("b")
24	C    = CKey.Of("c")
25	all  = []label.Label{A, B, C}
26)
27
28func TestList(t *testing.T) {
29	for _, test := range []struct {
30		name   string
31		labels []label.Label
32		expect string
33	}{{
34		name: "empty",
35	}, {
36		name:   "single",
37		labels: []label.Label{A},
38		expect: `A="a"`,
39	}, {
40		name:   "invalid",
41		labels: []label.Label{{}},
42		expect: ``,
43	}, {
44		name:   "two",
45		labels: []label.Label{A, B},
46		expect: `A="a", B="b"`,
47	}, {
48		name:   "three",
49		labels: []label.Label{A, B, C},
50		expect: `A="a", B="b", C="c"`,
51	}, {
52		name:   "missing A",
53		labels: []label.Label{{}, B, C},
54		expect: `B="b", C="c"`,
55	}, {
56		name:   "missing B",
57		labels: []label.Label{A, {}, C},
58		expect: `A="a", C="c"`,
59	}, {
60		name:   "missing C",
61		labels: []label.Label{A, B, {}},
62		expect: `A="a", B="b"`,
63	}, {
64		name:   "missing AB",
65		labels: []label.Label{{}, {}, C},
66		expect: `C="c"`,
67	}, {
68		name:   "missing AC",
69		labels: []label.Label{{}, B, {}},
70		expect: `B="b"`,
71	}, {
72		name:   "missing BC",
73		labels: []label.Label{A, {}, {}},
74		expect: `A="a"`,
75	}} {
76		t.Run(test.name, func(t *testing.T) {
77			got := printList(label.NewList(test.labels...))
78			if got != test.expect {
79				t.Errorf("got %q want %q", got, test.expect)
80			}
81		})
82	}
83}
84
85func TestFilter(t *testing.T) {
86	for _, test := range []struct {
87		name    string
88		labels  []label.Label
89		filters []label.Key
90		expect  string
91	}{{
92		name:   "no filters",
93		labels: all,
94		expect: `A="a", B="b", C="c"`,
95	}, {
96		name:    "no labels",
97		filters: []label.Key{AKey},
98		expect:  ``,
99	}, {
100		name:    "filter A",
101		labels:  all,
102		filters: []label.Key{AKey},
103		expect:  `B="b", C="c"`,
104	}, {
105		name:    "filter B",
106		labels:  all,
107		filters: []label.Key{BKey},
108		expect:  `A="a", C="c"`,
109	}, {
110		name:    "filter C",
111		labels:  all,
112		filters: []label.Key{CKey},
113		expect:  `A="a", B="b"`,
114	}, {
115		name:    "filter AC",
116		labels:  all,
117		filters: []label.Key{AKey, CKey},
118		expect:  `B="b"`,
119	}} {
120		t.Run(test.name, func(t *testing.T) {
121			labels := label.NewList(test.labels...)
122			got := printList(label.Filter(labels, test.filters...))
123			if got != test.expect {
124				t.Errorf("got %q want %q", got, test.expect)
125			}
126		})
127	}
128}
129
130func TestMap(t *testing.T) {
131	for _, test := range []struct {
132		name   string
133		labels []label.Label
134		keys   []label.Key
135		expect string
136	}{{
137		name:   "no labels",
138		keys:   []label.Key{AKey},
139		expect: `nil`,
140	}, {
141		name:   "match A",
142		labels: all,
143		keys:   []label.Key{AKey},
144		expect: `A="a"`,
145	}, {
146		name:   "match B",
147		labels: all,
148		keys:   []label.Key{BKey},
149		expect: `B="b"`,
150	}, {
151		name:   "match C",
152		labels: all,
153		keys:   []label.Key{CKey},
154		expect: `C="c"`,
155	}, {
156		name:   "match ABC",
157		labels: all,
158		keys:   []label.Key{AKey, BKey, CKey},
159		expect: `A="a", B="b", C="c"`,
160	}, {
161		name:   "missing A",
162		labels: []label.Label{{}, B, C},
163		keys:   []label.Key{AKey, BKey, CKey},
164		expect: `nil, B="b", C="c"`,
165	}, {
166		name:   "missing B",
167		labels: []label.Label{A, {}, C},
168		keys:   []label.Key{AKey, BKey, CKey},
169		expect: `A="a", nil, C="c"`,
170	}, {
171		name:   "missing C",
172		labels: []label.Label{A, B, {}},
173		keys:   []label.Key{AKey, BKey, CKey},
174		expect: `A="a", B="b", nil`,
175	}} {
176		t.Run(test.name, func(t *testing.T) {
177			lm := label.NewMap(test.labels...)
178			got := printMap(lm, test.keys)
179			if got != test.expect {
180				t.Errorf("got %q want %q", got, test.expect)
181			}
182		})
183	}
184}
185
186func TestMapMerge(t *testing.T) {
187	for _, test := range []struct {
188		name   string
189		maps   []label.Map
190		keys   []label.Key
191		expect string
192	}{{
193		name:   "no maps",
194		keys:   []label.Key{AKey},
195		expect: `nil`,
196	}, {
197		name:   "one map",
198		maps:   []label.Map{label.NewMap(all...)},
199		keys:   []label.Key{AKey},
200		expect: `A="a"`,
201	}, {
202		name:   "invalid map",
203		maps:   []label.Map{label.NewMap()},
204		keys:   []label.Key{AKey},
205		expect: `nil`,
206	}, {
207		name:   "two maps",
208		maps:   []label.Map{label.NewMap(B, C), label.NewMap(A)},
209		keys:   []label.Key{AKey, BKey, CKey},
210		expect: `A="a", B="b", C="c"`,
211	}, {
212		name:   "invalid start map",
213		maps:   []label.Map{label.NewMap(), label.NewMap(B, C)},
214		keys:   []label.Key{AKey, BKey, CKey},
215		expect: `nil, B="b", C="c"`,
216	}, {
217		name:   "invalid mid map",
218		maps:   []label.Map{label.NewMap(A), label.NewMap(), label.NewMap(C)},
219		keys:   []label.Key{AKey, BKey, CKey},
220		expect: `A="a", nil, C="c"`,
221	}, {
222		name:   "invalid end map",
223		maps:   []label.Map{label.NewMap(A, B), label.NewMap()},
224		keys:   []label.Key{AKey, BKey, CKey},
225		expect: `A="a", B="b", nil`,
226	}, {
227		name:   "three maps one nil",
228		maps:   []label.Map{label.NewMap(A), label.NewMap(B), nil},
229		keys:   []label.Key{AKey, BKey, CKey},
230		expect: `A="a", B="b", nil`,
231	}, {
232		name:   "two maps one nil",
233		maps:   []label.Map{label.NewMap(A, B), nil},
234		keys:   []label.Key{AKey, BKey, CKey},
235		expect: `A="a", B="b", nil`,
236	}} {
237		t.Run(test.name, func(t *testing.T) {
238			tagMap := label.MergeMaps(test.maps...)
239			got := printMap(tagMap, test.keys)
240			if got != test.expect {
241				t.Errorf("got %q want %q", got, test.expect)
242			}
243		})
244	}
245}
246
247func printList(list label.List) string {
248	buf := &bytes.Buffer{}
249	for index := 0; list.Valid(index); index++ {
250		l := list.Label(index)
251		if !l.Valid() {
252			continue
253		}
254		if buf.Len() > 0 {
255			buf.WriteString(", ")
256		}
257		fmt.Fprint(buf, l)
258	}
259	return buf.String()
260}
261
262func printMap(lm label.Map, keys []label.Key) string {
263	buf := &bytes.Buffer{}
264	for _, key := range keys {
265		if buf.Len() > 0 {
266			buf.WriteString(", ")
267		}
268		fmt.Fprint(buf, lm.Find(key))
269	}
270	return buf.String()
271}
272
273func TestAttemptedStringCorruption(t *testing.T) {
274	defer func() {
275		r := recover()
276		if _, ok := r.(*runtime.TypeAssertionError); !ok {
277			t.Fatalf("wanted to recover TypeAssertionError, got %T", r)
278		}
279	}()
280
281	var x uint64 = 12390
282	p := unsafe.Pointer(&x)
283	l := label.OfValue(AKey, p)
284	_ = l.UnpackString()
285}
286