1// Copyright 2015-2017 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	"testing"
9	"testing/quick"
10)
11
12func TestRunes(t *testing.T) {
13	rStr := `[\a \b \c \newline \space \tab \ŋ \' \" \u002c \u002C]`
14	var runes []Rune
15	err := UnmarshalString(rStr, &runes)
16	if err != nil {
17		t.Errorf("Reading `%s` failed with following error:", rStr)
18		t.Error(err.Error())
19	} else {
20		actualRunes := []Rune{
21			'a', 'b', 'c', '\n', ' ', '\t', 'ŋ', '\'', '"', ',', ',',
22		}
23		for i := range actualRunes {
24			if actualRunes[i] != runes[i] {
25				t.Errorf("Expected rune at position %d to be %q, but was %q", i, actualRunes[i], runes[i])
26			}
27		}
28	}
29}
30
31func TestQuickRunes(t *testing.T) {
32	f := func(s string) bool {
33		good := true
34		for _, r := range []rune(s) {
35			bs, err := Marshal(Rune(r))
36			if err != nil {
37				t.Log(err)
38				good = false
39				continue
40			}
41			var res Rune
42			err = Unmarshal(bs, &res)
43			if err != nil {
44				t.Log(err)
45				good = false
46				continue
47			}
48			if rune(res) != r {
49				good = false
50			}
51		}
52		return good
53	}
54	conf := quick.Config{MaxCountScale: 100}
55	if testing.Short() {
56		conf.MaxCountScale = 5
57	}
58	if err := quick.Check(f, &conf); err != nil {
59		t.Error(err)
60	}
61}
62
63func TestTagRunes(t *testing.T) {
64	type Foo struct {
65		Value rune `edn:",rune"`
66	}
67	f := Foo{Value: ' '}
68	bs, err := Marshal(f)
69	if err != nil {
70		t.Fatal(err)
71	}
72	if string(bs) != `{:value\space}` {
73		t.Errorf("Expected result to be `{:value\\space}`, but was `%s`", string(bs))
74	}
75	f.Value = '\''
76	bs, err = Marshal(f)
77	if err != nil {
78		t.Fatal(err)
79	}
80	if string(bs) != `{:value\'}` {
81		t.Errorf("Expected result to be `{:value\\'}`, but was `%s`", string(bs))
82	}
83}
84
85func TestSpacing(t *testing.T) {
86	type Foo struct {
87		Value Rune `edn:",sym"`
88		Data  Rune `edn:",sym"`
89	}
90	f := Foo{Value: Rune('a'), Data: Rune('b')}
91	bs, err := Marshal(f)
92	if err != nil {
93		t.Fatal(err)
94	}
95	if string(bs) != `{value \a data \b}` {
96		t.Errorf("Expected result to be `{value \\a data \\b}`, but was `%s`", string(bs))
97	}
98}
99
100func TestMarshalRawMessageValue(t *testing.T) {
101	type Foo struct {
102		SomeVal   string `edn:"some-val"`
103		Leftovers RawMessage
104		OtherVal  string `edn:"other-val"`
105	}
106
107	f := Foo{
108		SomeVal:   "egg",
109		Leftovers: []byte(`[\space #foo bar :baz 100 {#{} 1.0 "zap" nil}]`),
110		OtherVal:  "spam",
111	}
112	bs, err := Marshal(f)
113	if err != nil {
114		t.Fatal(err)
115	}
116	if string(bs) != `{:some-val"egg":leftovers [\space #foo bar :baz 100{#{}1.0"zap"nil}] :other-val"spam"}` {
117		t.Errorf("Expected result to be `{:some-val\"egg\":leftovers [\\space #foo bar :baz 100{#{}1.0\"zap\"nil}] :other-val\"spam\"}`, but was `%s`", string(bs))
118	}
119}
120
121func TestUnmarshalRawMessageValue(t *testing.T) {
122	type Foo struct {
123		SomeVal   string `edn:"some-val"`
124		Leftovers RawMessage
125		OtherVal  string `edn:"other-val"`
126	}
127	const raw = `{
128  :some-val"egg"
129  :leftovers [\space #foo bar :baz 100{#{} 1.0 "zap" nil}]
130  :other-val"spam"
131}`
132	var f Foo
133	err := UnmarshalString(raw, &f)
134	if err != nil {
135		t.Fatal(err)
136	}
137	if string(f.Leftovers) != `[\space #foo bar :baz 100{#{} 1.0 "zap" nil}]` {
138		t.Errorf("Expected result to be `[\\space #foo bar :baz 100{#{} 1.0 \"zap\" nil}]`, but was `%s`", string(f.Leftovers))
139	}
140}
141