1// Copyright 2015 Jean Niklas L'orange.  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 edn
6
7import (
8	"fmt"
9	"math/big"
10	"reflect"
11	"testing"
12)
13
14// your basic unit tests.. unfinished, probably.
15
16func TestIntReading(t *testing.T) {
17	intStrs := [...]string{"0", "1", "+100", "-982", "8223372036854775808", "-5N", "-0N"}
18	ints := [...]int64{0, 1, 100, -982, 8223372036854775808, -5, 0}
19	for i, istr := range intStrs {
20		var n int64
21		err := UnmarshalString(istr, &n)
22		if err != nil {
23			t.Errorf("int64 '%s' failed, but expected success", istr)
24		} else if n != ints[i] {
25			t.Errorf("int64 '%s' was decoded to %d, but expected %d", istr, n, ints[i])
26		}
27	}
28}
29
30func TestFloatReading(t *testing.T) {
31	for s, want := range map[string]float64{
32		"0.0":       0.0,
33		"0.0000001": 0.0000001,
34		"1E3":       1000.0,
35	} {
36		var have float64
37		err := UnmarshalString(s, &have)
38		if err != nil {
39			t.Errorf("float64 '%s' failed, but expected success", s)
40		} else if have != want {
41			t.Errorf("int64 '%s' was decoded to %f, but expected %f", s, have, want)
42		}
43	}
44}
45
46func TestBigIntReading(t *testing.T) {
47	const huge = "32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638215525166389647960126939249806625440700685819469589938384356951833568218188663"
48
49	bigIntStrs := [...]string{"0", "1", "-1N", "0N", huge + "N"}
50
51	_1 := func(v *big.Int, _ bool) *big.Int { return v }
52	bigInts := [...]*big.Int{
53		big.NewInt(0), big.NewInt(1), big.NewInt(-1),
54		big.NewInt(0), _1(big.NewInt(0).SetString(huge, 10)),
55	}
56	for i, istr := range bigIntStrs {
57		var n *big.Int
58		err := UnmarshalString(istr, &n)
59		if err != nil {
60			t.Errorf("*big.Int '%s' failed, but expected success", istr)
61		} else if n.Cmp(bigInts[i]) != 0 {
62			t.Errorf("*big.Int '%s' was decoded to %s, but expected %s", istr, n, bigInts[i])
63		}
64	}
65}
66
67func TestBigFloat(t *testing.T) {
68	const huge = "123456789123456789123456789123456789123456789123456789.123456789"
69
70	bigFloatStrs := [...]string{"0", "1M", "-0.1M", "1.1e-10M", huge + "M"}
71
72	bigFloat := func(s string) *big.Float {
73		f, _, err := big.ParseFloat(s, 10, 192, big.ToNearestEven)
74		if err != nil {
75			t.Fatal(err)
76		}
77		return f
78	}
79
80	bigFloats := [...]*big.Float{
81		bigFloat("0"), bigFloat("1"), bigFloat("-0.1"),
82		bigFloat("1.1e-10"), bigFloat(huge),
83	}
84	for i, istr := range bigFloatStrs {
85		var n *big.Float
86		err := UnmarshalString(istr, &n)
87		if err != nil {
88			t.Errorf("*big.Float '%s' failed, but expected success", istr)
89			t.Error(err)
90		} else if n.Cmp(bigFloats[i]) != 0 {
91			t.Errorf("*big.Float '%s' was decoded to %s, but expected %s", istr, n, bigFloats[i])
92		}
93	}
94}
95
96func TestArray(t *testing.T) {
97	stringArray := `("foo" "bar" "baz")`
98	stringExpected := [...]string{"foo", "bar", "baz"}
99	var sa [3]string
100	err := UnmarshalString(stringArray, &sa)
101	if err != nil {
102		t.Error(`expected '("foo" "bar" "baz")' to decode fine, but didn't`)
103	} else {
104		for i, expected := range stringExpected {
105			if expected != sa[i] {
106				t.Errorf(`Element %d in '("foo" "bar" "baz")' (%q) was encoded to %q`,
107					i, expected, sa[i])
108			}
109		}
110	}
111}
112
113func TestStruct(t *testing.T) {
114	type Animal struct {
115		Name string
116		Type string `edn:"kind"`
117	}
118	type Person struct {
119		Name      string
120		Birthyear int `edn:"born"`
121		Pets      []Animal
122	}
123	hans := `{:name "Hans",
124            :born 1970,
125            :pets [{:name "Cap'n Jack" :kind "Sparrow"}
126                   {:name "Freddy" :kind "Cockatiel"}]}`
127	goHans := Person{"Hans", 1970,
128		[]Animal{{"Cap'n Jack", "Sparrow"}, {"Freddy", "Cockatiel"}}}
129	var ednHans Person
130	err := UnmarshalString(hans, &ednHans)
131	if err != nil {
132		t.Error("Error when decoding Hans")
133	} else if !reflect.DeepEqual(goHans, ednHans) {
134		t.Error("EDN Hans is not equal to Go hans")
135	}
136}
137
138func TestRec(t *testing.T) {
139	type Node struct {
140		Left  *Node
141		Val   int
142		Right *Node
143	}
144	// here we're using symbols
145	tree := "{left {left {val 3} val 5 right nil} val 10 right {val 15 right {val 17}}}"
146	goTree := Node{Left: &Node{Left: &Node{Val: 3}, Val: 5, Right: nil},
147		Val: 10, Right: &Node{Val: 15, Right: &Node{Val: 17}}}
148	var ednTree Node
149	err := UnmarshalString(tree, &ednTree)
150	if err != nil {
151		t.Errorf("Couldn't unmarshal tree: %s", err.Error())
152	} else if !reflect.DeepEqual(goTree, ednTree) {
153		t.Error("Mismatch between the Go tree and the tree encoded as EDN")
154	}
155}
156
157func TestDiscard(t *testing.T) {
158	var s Symbol
159	discarding := "#_ #zap #_ xyz foo bar"
160	expected := Symbol("bar")
161	err := UnmarshalString(discarding, &s)
162	if err != nil {
163		t.Errorf("Expected '#_ #zap #_ xyz foo bar' to successfully read")
164		t.Log(err.Error())
165	} else if expected != s {
166		t.Error("Mismatch between the Go symbol and the symbol encoded as EDN")
167	}
168
169	discarding = "#_ #foo #foo #foo #_#_bar baz zip quux"
170	expected = Symbol("quux")
171	err = UnmarshalString(discarding, &s)
172	if err != nil {
173		t.Errorf("Expected '#_ #foo #foo #foo #_#_bar baz zip quux' to successfully read")
174		t.Log(err.Error())
175	} else if expected != s {
176		t.Error("Mismatch between the Go symbol and the symbol encoded as EDN")
177	}
178}
179
180// Test that we can read self-defined unmarshalEDNs
181type testUnmarshalEDN string
182
183func (t *testUnmarshalEDN) UnmarshalEDN(bs []byte) (err error) {
184	var kw Keyword
185	err = Unmarshal(bs, &kw)
186	if err == nil && string(kw) != "all" {
187		return fmt.Errorf("testUnmarshalEDN must be :all if it's a keyword, not %s", kw)
188	}
189	if err == nil {
190		*t = testUnmarshalEDN(kw)
191		return
192	}
193	// try to parse set of keywords
194	var m map[Keyword]bool
195	err = Unmarshal(bs, &m)
196	if err == nil {
197		*t = "set elements"
198	}
199	return
200}
201
202func TestUnmarshalEDN(t *testing.T) {
203	var tm testUnmarshalEDN
204	data := ":all"
205	expected := testUnmarshalEDN("all")
206	err := UnmarshalString(data, &tm)
207	if err != nil {
208		t.Errorf("Expected ':all' to successfully read into testUnmarshalEDN")
209		t.Log(err.Error())
210	} else if expected != tm {
211		t.Error("Mismatch between testUnmarshalEDN unmarshaling and the expected value")
212		t.Logf("Was %s, expected %s", tm, expected)
213	}
214
215	data = "#{:foo :bar :baz}"
216	expected = testUnmarshalEDN("set elements")
217	err = UnmarshalString(data, &tm)
218	if err != nil {
219		t.Errorf("Expected '#{:foo :bar :baz}' to successfully read into testUnmarshalEDN")
220		t.Log(err.Error())
221	} else if expected != tm {
222		t.Error("Mismatch between testUnmarshalEDN unmarshaling and the expected value")
223		t.Logf("Was %s, expected %s", tm, expected)
224	}
225
226	data = "#{:all #{:foo :bar :baz}}"
227
228	var tms map[testUnmarshalEDN]bool
229	err = UnmarshalString(data, &tms)
230	if err != nil {
231		t.Errorf("Expected '#{:all #{:foo :bar :baz}}' to successfully read into a map[testUnmarshalEDN]bool")
232		t.Log(err.Error())
233	} else {
234		fail := false
235		if len(tms) != 2 {
236			fail = true
237		}
238		if !tms[testUnmarshalEDN("all")] {
239			fail = true
240		}
241		if !tms[testUnmarshalEDN("set elements")] {
242			fail = true
243		}
244		if fail {
245			t.Error("Mismatch between testUnmarshalEDN unmarshaling and the expected value")
246			t.Logf("Was %s", tm)
247		}
248	}
249
250	data = "#{:foo :bar :baz :rock'n'roll :ain't_going-anywhere}"
251	expected = testUnmarshalEDN("set elements")
252	err = UnmarshalString(data, &tm)
253	if err != nil {
254		t.Errorf("Expected '%s' to successfully read into testUnmarshalEDN", data)
255		t.Log(err.Error())
256	} else if expected != tm {
257		t.Error("Mismatch between testUnmarshalEDN unmarshaling and the expected value")
258		t.Logf("Was %s, expected %s", tm, expected)
259	}
260}
261
262type vectorCounter int
263
264func (v *vectorCounter) UnmarshalEDN(bs []byte) (err error) {
265	var vec []interface{}
266	err = Unmarshal(bs, &vec)
267	if err != nil {
268		return
269	}
270	*v = vectorCounter(len(vec))
271	return
272}
273
274func TestVectorCounter(t *testing.T) {
275	var v vectorCounter
276	data := "[foo bar baz]"
277
278	var expected vectorCounter = 3
279	err := UnmarshalString(data, &v)
280	if err != nil {
281		t.Errorf("Expected '%s' to successfully read into vectorCounter", data)
282		t.Log(err.Error())
283	} else if expected != v {
284		t.Error("Mismatch between vectorCounter unmarshaling and the expected value")
285		t.Logf("Was %d, expected %d", v, expected)
286	}
287
288	data = "(a b c d e f)"
289	expected = 6
290	err = UnmarshalString(data, &v)
291	if err != nil {
292		t.Errorf("Expected '%s' to successfully read into vectorCounter", data)
293		t.Log(err.Error())
294	} else if expected != v {
295		t.Error("Mismatch between vectorCounter unmarshaling and the expected value")
296		t.Logf("Was %d, expected %d", v, expected)
297	}
298
299	data = `[[a b c][d e f g h],[#_3 z 2 \c]()["c d e"](2 3.0M)]`
300	var vs []vectorCounter
301	expected2 := []vectorCounter{3, 5, 3, 0, 1, 2}
302	err = UnmarshalString(data, &vs)
303	if err != nil {
304		t.Errorf("Expected '%s' to successfully read into []vectorCounter", data)
305		t.Log(err.Error())
306	} else if !reflect.DeepEqual(vs, expected2) {
307		t.Errorf("Mismatch between %#v and %#v", vs, expected2)
308	}
309
310	data = `{[a b c] "quux", [] "frob"}`
311	var vmap map[vectorCounter]string
312	expected3 := map[vectorCounter]string{3: "quux", 0: "frob"}
313	err = UnmarshalString(data, &vmap)
314	if err != nil {
315		t.Errorf("Expected '%s' to successfully read into map[vectorCounter]string", data)
316		t.Log(err.Error())
317	} else if !reflect.DeepEqual(vmap, expected3) {
318		t.Errorf("Mismatch between %#v and %#v", vmap, expected3)
319	}
320}
321
322type mapCounter int
323
324func (mc *mapCounter) UnmarshalEDN(bs []byte) (err error) {
325	var m map[interface{}]interface{}
326	err = Unmarshal(bs, &m)
327	if err != nil {
328		return
329	}
330	*mc = mapCounter(len(m))
331	return
332}
333
334func TestMapCounter(t *testing.T) {
335	var mc mapCounter
336	data := `{nil foo :a :b :c :d 1 0}`
337
338	var expected mapCounter = 4
339	err := UnmarshalString(data, &mc)
340	if err != nil {
341		t.Errorf("Expected '%s' to successfully read into mapCounter", data)
342		t.Log(err.Error())
343	} else if expected != mc {
344		t.Error("Mismatch between mapCounter unmarshaling and the expected value")
345		t.Logf("Was %d, expected %d", mc, expected)
346	}
347}
348
349func TestSliceSet(t *testing.T) {
350	var ss []string // no need to specify `edn:",set"` for this
351	data := `#{"a" "b" "c"}`
352	err := UnmarshalString(data, &ss)
353	if err != nil {
354		t.Errorf("Expected '%s' to succesfully read into a string slice", data)
355		t.Log(err.Error())
356	} else if !reflect.DeepEqual(ss, []string{"a", "b", "c"}) {
357		t.Error("Mismatch between string slice unmarshaling and expected value")
358		t.Logf(`Was %#v, expected []string{"a", "b", "c"}.`, ss)
359	}
360}
361
362type ExtraField struct {
363	Foo string
364}
365
366// TestExtraFields checks whether reading extra fields - in any order, is done
367// correctly.
368func TestExtraFields(t *testing.T) {
369	expected := ExtraField{Foo: "123"}
370	inputs := []string{
371		`{:foo "123" :extra "456"}`,
372		`{:extra "456" :foo "123"}`,
373		`{:foo "123" :extra 456}`,
374		`{:extra 456 :foo "123"}`,
375		`{nil 456 :foo "123"}`,
376	}
377	for _, input := range inputs {
378		var ef ExtraField
379		err := UnmarshalString(input, &ef)
380		if err != nil {
381			t.Errorf("Expected '%s' to succesfully read into an ExtraField type", input)
382			t.Log(err.Error())
383		} else if ef != expected {
384			t.Error("Mismatch between struct unmarshaling and expected value")
385			t.Logf(`Was %#v, expected %#v.`, ef, expected)
386		}
387	}
388}
389
390func TestNilSet(t *testing.T) {
391	inputs := []string{
392		`#{1 2 nil 3}`,
393		`#{nil}`,
394		`#{#{nil} #{nil 1}}`,
395		`#{nil 1 2}`,
396		`#{1 2 3 nil}`,
397	}
398	for _, input := range inputs {
399		var val []interface{}
400		err := UnmarshalString(input, &val)
401		if err != nil {
402			t.Errorf("Expected '%s' to succesfully read into []interface{}", input)
403			t.Log(err.Error())
404		}
405		var ival interface{}
406		err = UnmarshalString(input, &ival)
407		if err != nil {
408			t.Errorf("Expected '%s' to succesfully read into interface{}", input)
409			t.Log(err.Error())
410		}
411		var mval map[interface{}]bool
412		err = UnmarshalString(input, &mval)
413		if err != nil {
414			t.Errorf("Expected '%s' to succesfully read into map[interface{}]bool", input)
415			t.Log(err.Error())
416		}
417	}
418}
419
420func TestNilMap(t *testing.T) {
421	inputs := []string{
422		`{1 2 nil 3}`,
423		`{nil foo}`,
424		`{{nil nil} 2 nil 1}`,
425		`{nil 1 2 3}`,
426		`{1 2 3 nil}`,
427	}
428	for _, input := range inputs {
429		var ival interface{}
430		err := UnmarshalString(input, &ival)
431		if err != nil {
432			t.Errorf("Expected '%s' to succesfully read into interface{}", input)
433			t.Log(err.Error())
434		}
435		var mval map[interface{}]interface{}
436		err = UnmarshalString(input, &mval)
437		if err != nil {
438			t.Errorf("Expected '%s' to succesfully read into map[interface{}]interface{}", input)
439			t.Log(err.Error())
440		}
441	}
442}
443
444func TestNilNotFunnilyCoerced(t *testing.T) {
445	inputs := []string{
446		`{"1" 2 nil 3}`,
447	}
448	for _, input := range inputs {
449		var val map[string]int
450		err := UnmarshalString(input, &val)
451		if err == nil {
452			t.Errorf("Expected '%s' to error out when read into map[string]int", input)
453			t.Logf("Value is %#v", val)
454		}
455	}
456}
457
458func TestNilNotEmptyString(t *testing.T) {
459	input := "nil"
460	var val string
461	err := UnmarshalString(input, &val)
462	if err == nil {
463		t.Error("Expected nil to not be a string")
464	}
465}
466
467func TestUnhashableBigInt(t *testing.T) {
468	input := "#{0N}"
469	var val interface{}
470	if err := UnmarshalString(input, &val); err != nil {
471		_, unhashable := err.(*UnhashableError)
472		if !unhashable {
473			t.Errorf("unexpected parsing error: %q: %s", input, err)
474		}
475	} else {
476		t.Errorf("expected '%s' to be unparseable", input)
477	}
478}
479
480func TestUnhashableTaggedList(t *testing.T) {
481	input := "{#g()0}"
482	var val interface{}
483	if err := UnmarshalString(input, &val); err != nil {
484		_, unhashable := err.(*UnhashableError)
485		if !unhashable {
486			t.Errorf("unexpected parsing error: %q: %s", input, err)
487		}
488	} else {
489		t.Errorf("expected '%s' to be unparseable", input)
490	}
491}
492
493func TestJSONDecoding(t *testing.T) {
494	var jsonOnly struct {
495		Data string `json:"json"`
496	}
497	var jsonAndEdn struct {
498		Data string `json:"json" edn:"edn"`
499	}
500	inputData := `{:data"hi"}`
501	inputEDN := `{:edn"hi"}`
502	inputJSON := `{:json"hi"}`
503
504	testEmpty := func(obj interface{}, str *string, input string) {
505		*str = ""
506		if err := UnmarshalString(input, obj); err != nil {
507			t.Errorf("Expected %q to parse successfully into #%v", input, obj)
508			t.Log(err.Error())
509		}
510		if *str != "" {
511			t.Errorf("Expected %q to not parse into fields, but got %#v", input, obj)
512		}
513	}
514	testHi := func(obj interface{}, str *string, input string) {
515		*str = ""
516		if err := UnmarshalString(input, obj); err != nil {
517			t.Errorf("Expected %q to parse successfully into #%v", input, obj)
518			t.Log(err.Error())
519		}
520		if *str != "hi" {
521			t.Errorf(`Expected %q to not parse "hi" into .Data, but got %#v`, input, obj)
522		}
523	}
524
525	UseJSONAsFallback(false)
526
527	// json tag only
528	testHi(&jsonOnly, &jsonOnly.Data, inputData)
529	testEmpty(&jsonOnly, &jsonOnly.Data, inputEDN)
530	testEmpty(&jsonOnly, &jsonOnly.Data, inputJSON)
531	// json + edn tag
532	testEmpty(&jsonAndEdn, &jsonAndEdn.Data, inputData)
533	testHi(&jsonAndEdn, &jsonAndEdn.Data, inputEDN)
534	testEmpty(&jsonAndEdn, &jsonAndEdn.Data, inputJSON)
535
536	UseJSONAsFallback(true)
537
538	// json tag only
539	testEmpty(&jsonOnly, &jsonOnly.Data, inputData)
540	testEmpty(&jsonOnly, &jsonOnly.Data, inputEDN)
541	testHi(&jsonOnly, &jsonOnly.Data, inputJSON)
542	// json + edn tag
543	testEmpty(&jsonAndEdn, &jsonAndEdn.Data, inputData)
544	testHi(&jsonAndEdn, &jsonAndEdn.Data, inputEDN)
545	testEmpty(&jsonAndEdn, &jsonAndEdn.Data, inputJSON)
546
547	UseJSONAsFallback(false)
548
549	// json tag only
550	testHi(&jsonOnly, &jsonOnly.Data, inputData)
551	testEmpty(&jsonOnly, &jsonOnly.Data, inputEDN)
552	testEmpty(&jsonOnly, &jsonOnly.Data, inputJSON)
553	// json + edn tag
554	testEmpty(&jsonAndEdn, &jsonAndEdn.Data, inputData)
555	testHi(&jsonAndEdn, &jsonAndEdn.Data, inputEDN)
556	testEmpty(&jsonAndEdn, &jsonAndEdn.Data, inputJSON)
557}
558