1package pt
2
3import (
4	"testing"
5)
6
7func stringSlicesEqual(a, b []string) bool {
8	if len(a) != len(b) {
9		return false
10	}
11	for i := range a {
12		if a[i] != b[i] {
13			return false
14		}
15	}
16	return true
17}
18
19func argsEqual(a, b Args) bool {
20	for k, av := range a {
21		bv := b[k]
22		if !stringSlicesEqual(av, bv) {
23			return false
24		}
25	}
26	for k, bv := range b {
27		av := a[k]
28		if !stringSlicesEqual(av, bv) {
29			return false
30		}
31	}
32	return true
33}
34
35func TestArgsGet(t *testing.T) {
36	args := Args{
37		"a": []string{},
38		"b": []string{"value"},
39		"c": []string{"v1", "v2", "v3"},
40	}
41	var uninit Args
42
43	var v string
44	var ok bool
45
46	// Get on nil map should be the same as Get on empty map.
47	v, ok = uninit.Get("a")
48	if !(v == "" && !ok) {
49		t.Errorf("unexpected result from Get on nil Args: %q %v", v, ok)
50	}
51
52	v, ok = args.Get("a")
53	if ok {
54		t.Errorf("Unexpected Get success for %q", "a")
55	}
56	if v != "" {
57		t.Errorf("Get failure returned other than %q: %q", "", v)
58	}
59	v, ok = args.Get("b")
60	if !ok {
61		t.Errorf("Unexpected Get failure for %q", "b")
62	}
63	if v != "value" {
64		t.Errorf("Get(%q) → %q (expected %q)", "b", v, "value")
65	}
66	v, ok = args.Get("c")
67	if !ok {
68		t.Errorf("Unexpected Get failure for %q", "c")
69	}
70	if v != "v1" {
71		t.Errorf("Get(%q) → %q (expected %q)", "c", v, "v1")
72	}
73	v, ok = args.Get("d")
74	if ok {
75		t.Errorf("Unexpected Get success for %q", "d")
76	}
77}
78
79func TestArgsAdd(t *testing.T) {
80	args := make(Args)
81	expected := Args{}
82	if !argsEqual(args, expected) {
83		t.Fatalf("%q != %q", args, expected)
84	}
85	args.Add("k1", "v1")
86	expected = Args{"k1": []string{"v1"}}
87	if !argsEqual(args, expected) {
88		t.Fatalf("%q != %q", args, expected)
89	}
90	args.Add("k2", "v2")
91	expected = Args{"k1": []string{"v1"}, "k2": []string{"v2"}}
92	if !argsEqual(args, expected) {
93		t.Fatalf("%q != %q", args, expected)
94	}
95	args.Add("k1", "v3")
96	expected = Args{"k1": []string{"v1", "v3"}, "k2": []string{"v2"}}
97	if !argsEqual(args, expected) {
98		t.Fatalf("%q != %q", args, expected)
99	}
100}
101
102func TestParseClientParameters(t *testing.T) {
103	badTests := [...]string{
104		"key",
105		"key\\",
106		"=value",
107		"==value",
108		"==key=value",
109		"key=value\\",
110		"a=b;key=value\\",
111		"a;b=c",
112		";",
113		"key=value;",
114		";key=value",
115		"key\\=value",
116	}
117	goodTests := [...]struct {
118		input    string
119		expected Args
120	}{
121		{
122			"",
123			Args{},
124		},
125		{
126			"key=",
127			Args{"key": []string{""}},
128		},
129		{
130			"key==",
131			Args{"key": []string{"="}},
132		},
133		{
134			"key=value",
135			Args{"key": []string{"value"}},
136		},
137		{
138			"a=b=c",
139			Args{"a": []string{"b=c"}},
140		},
141		{
142			"a=bc==",
143			Args{"a": []string{"bc=="}},
144		},
145		{
146			"key=a\nb",
147			Args{"key": []string{"a\nb"}},
148		},
149		{
150			"key=value\\;",
151			Args{"key": []string{"value;"}},
152		},
153		{
154			"key=\"value\"",
155			Args{"key": []string{"\"value\""}},
156		},
157		{
158			"key=\"\"value\"\"",
159			Args{"key": []string{"\"\"value\"\""}},
160		},
161		{
162			"\"key=value\"",
163			Args{"\"key": []string{"value\""}},
164		},
165		{
166			"key=value;key=value",
167			Args{"key": []string{"value", "value"}},
168		},
169		{
170			"key=value1;key=value2",
171			Args{"key": []string{"value1", "value2"}},
172		},
173		{
174			"key1=value1;key2=value2;key1=value3",
175			Args{"key1": []string{"value1", "value3"}, "key2": []string{"value2"}},
176		},
177		{
178			"\\;=\\;;\\\\=\\;",
179			Args{";": []string{";"}, "\\": []string{";"}},
180		},
181		{
182			"a\\=b=c",
183			Args{"a=b": []string{"c"}},
184		},
185		{
186			"shared-secret=rahasia;secrets-file=/tmp/blob",
187			Args{"shared-secret": []string{"rahasia"}, "secrets-file": []string{"/tmp/blob"}},
188		},
189		{
190			"rocks=20;height=5.6",
191			Args{"rocks": []string{"20"}, "height": []string{"5.6"}},
192		},
193	}
194
195	for _, input := range badTests {
196		_, err := parseClientParameters(input)
197		if err == nil {
198			t.Errorf("%q unexpectedly succeeded", input)
199		}
200	}
201
202	for _, test := range goodTests {
203		args, err := parseClientParameters(test.input)
204		if err != nil {
205			t.Errorf("%q unexpectedly returned an error: %s", test.input, err)
206		}
207		if !argsEqual(args, test.expected) {
208			t.Errorf("%q → %q (expected %q)", test.input, args, test.expected)
209		}
210	}
211}
212
213func optsEqual(a, b map[string]Args) bool {
214	for k, av := range a {
215		bv, ok := b[k]
216		if !ok || !argsEqual(av, bv) {
217			return false
218		}
219	}
220	for k, bv := range b {
221		av, ok := a[k]
222		if !ok || !argsEqual(av, bv) {
223			return false
224		}
225	}
226	return true
227}
228
229func TestParseServerTransportOptions(t *testing.T) {
230	badTests := [...]string{
231		"t\\",
232		":=",
233		"t:=",
234		":k=",
235		":=v",
236		"t:=v",
237		"t:=v",
238		"t:k\\",
239		"t:k=v;",
240		"abc",
241		"t:",
242		"key=value",
243		"=value",
244		"t:k=v\\",
245		"t1:k=v;t2:k=v\\",
246		"t:=key=value",
247		"t:==key=value",
248		"t:;key=value",
249		"t:key\\=value",
250	}
251	goodTests := [...]struct {
252		input    string
253		expected map[string]Args
254	}{
255		{
256			"",
257			map[string]Args{},
258		},
259		{
260			"t:k=v",
261			map[string]Args{
262				"t": {"k": []string{"v"}},
263			},
264		},
265		{
266			"t:k=v=v",
267			map[string]Args{
268				"t": {"k": []string{"v=v"}},
269			},
270		},
271		{
272			"t:k=vv==",
273			map[string]Args{
274				"t": {"k": []string{"vv=="}},
275			},
276		},
277		{
278			"t1:k=v1;t2:k=v2;t1:k=v3",
279			map[string]Args{
280				"t1": {"k": []string{"v1", "v3"}},
281				"t2": {"k": []string{"v2"}},
282			},
283		},
284		{
285			"t\\:1:k=v;t\\=2:k=v;t\\;3:k=v;t\\\\4:k=v",
286			map[string]Args{
287				"t:1":  {"k": []string{"v"}},
288				"t=2":  {"k": []string{"v"}},
289				"t;3":  {"k": []string{"v"}},
290				"t\\4": {"k": []string{"v"}},
291			},
292		},
293		{
294			"t:k\\:1=v;t:k\\=2=v;t:k\\;3=v;t:k\\\\4=v",
295			map[string]Args{
296				"t": {
297					"k:1":  []string{"v"},
298					"k=2":  []string{"v"},
299					"k;3":  []string{"v"},
300					"k\\4": []string{"v"},
301				},
302			},
303		},
304		{
305			"t:k=v\\:1;t:k=v\\=2;t:k=v\\;3;t:k=v\\\\4",
306			map[string]Args{
307				"t": {"k": []string{"v:1", "v=2", "v;3", "v\\4"}},
308			},
309		},
310		{
311			"trebuchet:secret=nou;trebuchet:cache=/tmp/cache;ballista:secret=yes",
312			map[string]Args{
313				"trebuchet": {"secret": []string{"nou"}, "cache": []string{"/tmp/cache"}},
314				"ballista":  {"secret": []string{"yes"}},
315			},
316		},
317	}
318
319	for _, input := range badTests {
320		_, err := parseServerTransportOptions(input)
321		if err == nil {
322			t.Errorf("%q unexpectedly succeeded", input)
323		}
324	}
325
326	for _, test := range goodTests {
327		opts, err := parseServerTransportOptions(test.input)
328		if err != nil {
329			t.Errorf("%q unexpectedly returned an error: %s", test.input, err)
330		}
331		if !optsEqual(opts, test.expected) {
332			t.Errorf("%q → %q (expected %q)", test.input, opts, test.expected)
333		}
334	}
335}
336
337func TestEncodeSmethodArgs(t *testing.T) {
338	tests := [...]struct {
339		args     Args
340		expected string
341	}{
342		{
343			nil,
344			"",
345		},
346		{
347			Args{},
348			"",
349		},
350		{
351			Args{"j": []string{"v1", "v2", "v3"}, "k": []string{"v1", "v2", "v3"}},
352			"j=v1,j=v2,j=v3,k=v1,k=v2,k=v3",
353		},
354		{
355			Args{"=,\\": []string{"=", ",", "\\"}},
356			"\\=\\,\\\\=\\=,\\=\\,\\\\=\\,,\\=\\,\\\\=\\\\",
357		},
358		{
359			Args{"secret": []string{"yes"}},
360			"secret=yes",
361		},
362		{
363			Args{"secret": []string{"nou"}, "cache": []string{"/tmp/cache"}},
364			"cache=/tmp/cache,secret=nou",
365		},
366	}
367
368	for _, test := range tests {
369		encoded := encodeSmethodArgs(test.args)
370		if encoded != test.expected {
371			t.Errorf("%q → %q (expected %q)", test.args, encoded, test.expected)
372		}
373	}
374}
375