1package cbor
2
3import (
4	"bytes"
5	"encoding/hex"
6	"testing"
7	"time"
8)
9
10func TestDecodeInteger(t *testing.T) {
11	for _, tc := range integerTestCases {
12		gotv := decodeInteger(getReader(tc.binary))
13		if gotv != int64(tc.val) {
14			t.Errorf("decodeInteger(0x%s)=0x%d, want: 0x%d",
15				hex.EncodeToString([]byte(tc.binary)), gotv, tc.val)
16		}
17	}
18}
19
20func TestDecodeString(t *testing.T) {
21	for _, tt := range encodeStringTests {
22		got := decodeUTF8String(getReader(tt.binary))
23		if string(got) != "\""+tt.json+"\"" {
24			t.Errorf("DecodeString(0x%s)=%s, want:\"%s\"\n", hex.EncodeToString([]byte(tt.binary)), string(got),
25				hex.EncodeToString([]byte(tt.json)))
26		}
27	}
28}
29
30func TestDecodeArray(t *testing.T) {
31	for _, tc := range integerArrayTestCases {
32		buf := bytes.NewBuffer([]byte{})
33		array2Json(getReader(tc.binary), buf)
34		if buf.String() != tc.json {
35			t.Errorf("array2Json(0x%s)=%s, want: %s", hex.EncodeToString([]byte(tc.binary)), buf.String(), tc.json)
36		}
37	}
38	//Unspecified Length Array
39	var infiniteArrayTestCases = []struct {
40		in  string
41		out string
42	}{
43		{"\x9f\x20\x00\x18\xc8\x14\xff", "[-1,0,200,20]"},
44		{"\x9f\x38\xc7\x29\x18\xc8\x19\x01\x90\xff", "[-200,-10,200,400]"},
45		{"\x9f\x01\x02\x03\xff", "[1,2,3]"},
46		{"\x9f\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x18\x18\x19\xff",
47			"[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]"},
48	}
49	for _, tc := range infiniteArrayTestCases {
50		buf := bytes.NewBuffer([]byte{})
51		array2Json(getReader(tc.in), buf)
52		if buf.String() != tc.out {
53			t.Errorf("array2Json(0x%s)=%s, want: %s", hex.EncodeToString([]byte(tc.out)), buf.String(), tc.out)
54		}
55	}
56	for _, tc := range booleanArrayTestCases {
57		buf := bytes.NewBuffer([]byte{})
58		array2Json(getReader(tc.binary), buf)
59		if buf.String() != tc.json {
60			t.Errorf("array2Json(0x%s)=%s, want: %s", hex.EncodeToString([]byte(tc.binary)), buf.String(), tc.json)
61		}
62	}
63	//TODO add cases for arrays of other types
64}
65
66var infiniteMapDecodeTestCases = []struct {
67	bin  []byte
68	json string
69}{
70	{[]byte("\xbf\x64IETF\x20\xff"), "{\"IETF\":-1}"},
71	{[]byte("\xbf\x65Array\x84\x20\x00\x18\xc8\x14\xff"), "{\"Array\":[-1,0,200,20]}"},
72}
73
74var mapDecodeTestCases = []struct {
75	bin  []byte
76	json string
77}{
78	{[]byte("\xa2\x64IETF\x20"), "{\"IETF\":-1}"},
79	{[]byte("\xa2\x65Array\x84\x20\x00\x18\xc8\x14"), "{\"Array\":[-1,0,200,20]}"},
80}
81
82func TestDecodeMap(t *testing.T) {
83	for _, tc := range mapDecodeTestCases {
84		buf := bytes.NewBuffer([]byte{})
85		map2Json(getReader(string(tc.bin)), buf)
86		if buf.String() != tc.json {
87			t.Errorf("map2Json(0x%s)=%s, want: %s", hex.EncodeToString(tc.bin), buf.String(), tc.json)
88		}
89	}
90	for _, tc := range infiniteMapDecodeTestCases {
91		buf := bytes.NewBuffer([]byte{})
92		map2Json(getReader(string(tc.bin)), buf)
93		if buf.String() != tc.json {
94			t.Errorf("map2Json(0x%s)=%s, want: %s", hex.EncodeToString(tc.bin), buf.String(), tc.json)
95		}
96	}
97}
98
99func TestDecodeBool(t *testing.T) {
100	for _, tc := range booleanTestCases {
101		got := decodeSimpleFloat(getReader(tc.binary))
102		if string(got) != tc.json {
103			t.Errorf("decodeSimpleFloat(0x%s)=%s, want:%s", hex.EncodeToString([]byte(tc.binary)), string(got), tc.json)
104		}
105	}
106}
107
108func TestDecodeFloat(t *testing.T) {
109	for _, tc := range float32TestCases {
110		got, _ := decodeFloat(getReader(tc.binary))
111		if got != float64(tc.val) {
112			t.Errorf("decodeFloat(0x%s)=%f, want:%f", hex.EncodeToString([]byte(tc.binary)), got, tc.val)
113		}
114	}
115}
116
117func TestDecodeTimestamp(t *testing.T) {
118	decodeTimeZone, _ = time.LoadLocation("UTC")
119	for _, tc := range timeIntegerTestcases {
120		tm := decodeTagData(getReader(tc.binary))
121		if string(tm) != "\""+tc.rfcStr+"\"" {
122			t.Errorf("decodeFloat(0x%s)=%s, want:%s", hex.EncodeToString([]byte(tc.binary)), tm, tc.rfcStr)
123		}
124	}
125	for _, tc := range timeFloatTestcases {
126		tm := decodeTagData(getReader(tc.out))
127		//Since we convert to float and back - it may be slightly off - so
128		//we cannot check for exact equality instead, we'll check it is
129		//very close to each other Less than a Microsecond (lets not yet do nanosec)
130
131		got, _ := time.Parse(string(tm), string(tm))
132		want, _ := time.Parse(tc.rfcStr, tc.rfcStr)
133		if got.Sub(want) > time.Microsecond {
134			t.Errorf("decodeFloat(0x%s)=%s, want:%s", hex.EncodeToString([]byte(tc.out)), tm, tc.rfcStr)
135		}
136	}
137}
138
139func TestDecodeNetworkAddr(t *testing.T) {
140	for _, tc := range ipAddrTestCases {
141		d1 := decodeTagData(getReader(tc.binary))
142		if string(d1) != tc.text {
143			t.Errorf("decodeNetworkAddr(0x%s)=%s, want:%s", hex.EncodeToString([]byte(tc.binary)), d1, tc.text)
144		}
145	}
146}
147
148func TestDecodeMACAddr(t *testing.T) {
149	for _, tc := range macAddrTestCases {
150		d1 := decodeTagData(getReader(tc.binary))
151		if string(d1) != tc.text {
152			t.Errorf("decodeNetworkAddr(0x%s)=%s, want:%s", hex.EncodeToString([]byte(tc.binary)), d1, tc.text)
153		}
154	}
155}
156
157func TestDecodeIPPrefix(t *testing.T) {
158	for _, tc := range IPPrefixTestCases {
159		d1 := decodeTagData(getReader(tc.binary))
160		if string(d1) != tc.text {
161			t.Errorf("decodeIPPrefix(0x%s)=%s, want:%s", hex.EncodeToString([]byte(tc.binary)), d1, tc.text)
162		}
163	}
164}
165
166var compositeCborTestCases = []struct {
167	binary []byte
168	json   string
169}{
170	{[]byte("\xbf\x64IETF\x20\x65Array\x9f\x20\x00\x18\xc8\x14\xff\xff"), "{\"IETF\":-1,\"Array\":[-1,0,200,20]}\n"},
171	{[]byte("\xbf\x64IETF\x64YES!\x65Array\x9f\x20\x00\x18\xc8\x14\xff\xff"), "{\"IETF\":\"YES!\",\"Array\":[-1,0,200,20]}\n"},
172}
173
174func TestDecodeCbor2Json(t *testing.T) {
175	for _, tc := range compositeCborTestCases {
176		buf := bytes.NewBuffer([]byte{})
177		err := Cbor2JsonManyObjects(getReader(string(tc.binary)), buf)
178		if buf.String() != tc.json || err != nil {
179			t.Errorf("cbor2JsonManyObjects(0x%s)=%s, want: %s, err:%s", hex.EncodeToString(tc.binary), buf.String(), tc.json, err.Error())
180		}
181	}
182}
183
184var negativeCborTestCases = []struct {
185	binary []byte
186	errStr string
187}{
188	{[]byte("\xb9\x64IETF\x20\x65Array\x9f\x20\x00\x18\xc8\x14"), "Tried to Read 18 Bytes.. But hit end of file"},
189	{[]byte("\xbf\x64IETF\x20\x65Array\x9f\x20\x00\x18\xc8\x14"), "EOF"},
190	{[]byte("\xbf\x14IETF\x20\x65Array\x9f\x20\x00\x18\xc8\x14"), "Tried to Read 40736 Bytes.. But hit end of file"},
191	{[]byte("\xbf\x64IETF"), "EOF"},
192	{[]byte("\xbf\x64IETF\x20\x65Array\x9f\x20\x00\x18\xc8\xff\xff\xff"), "Invalid Additional Type: 31 in decodeSimpleFloat"},
193	{[]byte("\xbf\x64IETF\x20\x65Array"), "EOF"},
194	{[]byte("\xbf\x64"), "Tried to Read 4 Bytes.. But hit end of file"},
195}
196
197func TestDecodeNegativeCbor2Json(t *testing.T) {
198	for _, tc := range negativeCborTestCases {
199		buf := bytes.NewBuffer([]byte{})
200		err := Cbor2JsonManyObjects(getReader(string(tc.binary)), buf)
201		if err == nil || err.Error() != tc.errStr {
202			t.Errorf("Expected error got:%s, want:%s", err, tc.errStr)
203		}
204	}
205}
206