1package cbor
2
3import (
4	"encoding/hex"
5	"net"
6	"testing"
7)
8
9var enc = Encoder{}
10
11func TestAppendNil(t *testing.T) {
12	s := enc.AppendNil([]byte{})
13	got := string(s)
14	want := "\xf6"
15	if got != want {
16		t.Errorf("appendNull() = 0x%s, want: 0x%s", hex.EncodeToString(s),
17			hex.EncodeToString([]byte(want)))
18	}
19}
20
21var booleanTestCases = []struct {
22	val    bool
23	binary string
24	json   string
25}{
26	{true, "\xf5", "true"},
27	{false, "\xf4", "false"},
28}
29
30func TestAppendBool(t *testing.T) {
31	for _, tc := range booleanTestCases {
32		s := enc.AppendBool([]byte{}, tc.val)
33		got := string(s)
34		if got != tc.binary {
35			t.Errorf("AppendBool(%s)=0x%s, want: 0x%s",
36				tc.json, hex.EncodeToString(s),
37				hex.EncodeToString([]byte(tc.binary)))
38		}
39	}
40}
41
42var booleanArrayTestCases = []struct {
43	val    []bool
44	binary string
45	json   string
46}{
47	{[]bool{true, false, true}, "\x83\xf5\xf4\xf5", "[true,false,true]"},
48	{[]bool{true, false, false, true, false, true}, "\x86\xf5\xf4\xf4\xf5\xf4\xf5", "[true,false,false,true,false,true]"},
49}
50
51func TestAppendBoolArray(t *testing.T) {
52	for _, tc := range booleanArrayTestCases {
53		s := enc.AppendBools([]byte{}, tc.val)
54		got := string(s)
55		if got != tc.binary {
56			t.Errorf("AppendBools(%s)=0x%s, want: 0x%s",
57				tc.json, hex.EncodeToString(s),
58				hex.EncodeToString([]byte(tc.binary)))
59		}
60	}
61}
62
63var integerTestCases = []struct {
64	val    int
65	binary string
66}{
67	// Value included in the type.
68	{0, "\x00"},
69	{1, "\x01"},
70	{2, "\x02"},
71	{3, "\x03"},
72	{8, "\x08"},
73	{9, "\x09"},
74	{10, "\x0a"},
75	{22, "\x16"},
76	{23, "\x17"},
77	// Value in 1 byte.
78	{24, "\x18\x18"},
79	{25, "\x18\x19"},
80	{26, "\x18\x1a"},
81	{100, "\x18\x64"},
82	{254, "\x18\xfe"},
83	{255, "\x18\xff"},
84	// Value in 2 bytes.
85	{256, "\x19\x01\x00"},
86	{257, "\x19\x01\x01"},
87	{1000, "\x19\x03\xe8"},
88	{0xFFFF, "\x19\xff\xff"},
89	// Value in 4 bytes.
90	{0x10000, "\x1a\x00\x01\x00\x00"},
91	{0x7FFFFFFE, "\x1a\x7f\xff\xff\xfe"},
92	{1000000, "\x1a\x00\x0f\x42\x40"},
93	// Negative number test cases.
94	// Value included in the type.
95	{-1, "\x20"},
96	{-2, "\x21"},
97	{-3, "\x22"},
98	{-10, "\x29"},
99	{-21, "\x34"},
100	{-22, "\x35"},
101	{-23, "\x36"},
102	{-24, "\x37"},
103	// Value in 1 byte.
104	{-25, "\x38\x18"},
105	{-26, "\x38\x19"},
106	{-100, "\x38\x63"},
107	{-254, "\x38\xfd"},
108	{-255, "\x38\xfe"},
109	{-256, "\x38\xff"},
110	// Value in 2 bytes.
111	{-257, "\x39\x01\x00"},
112	{-258, "\x39\x01\x01"},
113	{-1000, "\x39\x03\xe7"},
114	// Value in 4 bytes.
115	{-0x10001, "\x3a\x00\x01\x00\x00"},
116	{-0x7FFFFFFE, "\x3a\x7f\xff\xff\xfd"},
117	{-1000000, "\x3a\x00\x0f\x42\x3f"},
118
119}
120
121func TestAppendInt(t *testing.T) {
122	for _, tc := range integerTestCases {
123		s := enc.AppendInt([]byte{}, tc.val)
124		got := string(s)
125		if got != tc.binary {
126			t.Errorf("AppendInt(0x%x)=0x%s, want: 0x%s",
127				tc.val, hex.EncodeToString(s),
128				hex.EncodeToString([]byte(tc.binary)))
129		}
130	}
131}
132
133var integerArrayTestCases = []struct {
134	val    []int
135	binary string
136	json   string
137}{
138	{[]int{-1, 0, 200, 20}, "\x84\x20\x00\x18\xc8\x14", "[-1,0,200,20]"},
139	{[]int{-200, -10, 200, 400}, "\x84\x38\xc7\x29\x18\xc8\x19\x01\x90", "[-200,-10,200,400]"},
140	{[]int{1, 2, 3}, "\x83\x01\x02\x03", "[1,2,3]"},
141	{[]int{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},
142		"\x98\x19\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",
143		"[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]"},
144}
145
146func TestAppendIntArray(t *testing.T) {
147	for _, tc := range integerArrayTestCases {
148		s := enc.AppendInts([]byte{}, tc.val)
149		got := string(s)
150		if got != tc.binary {
151			t.Errorf("AppendInts(%s)=0x%s, want: 0x%s",
152				tc.json, hex.EncodeToString(s),
153				hex.EncodeToString([]byte(tc.binary)))
154		}
155	}
156}
157
158var float32TestCases = []struct {
159	val    float32
160	binary string
161}{
162	{0.0, "\xfa\x00\x00\x00\x00"},
163	{-0.0, "\xfa\x00\x00\x00\x00"},
164	{1.0, "\xfa\x3f\x80\x00\x00"},
165	{1.5, "\xfa\x3f\xc0\x00\x00"},
166	{65504.0, "\xfa\x47\x7f\xe0\x00"},
167	{-4.0, "\xfa\xc0\x80\x00\x00"},
168	{0.00006103515625, "\xfa\x38\x80\x00\x00"},
169}
170
171func TestAppendFloat32(t *testing.T) {
172	for _, tc := range float32TestCases {
173		s := enc.AppendFloat32([]byte{}, tc.val)
174		got := string(s)
175		if got != tc.binary {
176			t.Errorf("AppendFloat32(%f)=0x%s, want: 0x%s",
177				tc.val, hex.EncodeToString(s),
178				hex.EncodeToString([]byte(tc.binary)))
179		}
180	}
181}
182
183var ipAddrTestCases = []struct {
184	ipaddr net.IP
185	text   string // ASCII representation of ipaddr
186	binary string // CBOR representation of ipaddr
187}{
188	{net.IP{10, 0, 0, 1}, "\"10.0.0.1\"", "\xd9\x01\x04\x44\x0a\x00\x00\x01"},
189	{net.IP{0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x0, 0x0, 0x0, 0x0, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34},
190		"\"2001:db8:85a3::8a2e:370:7334\"",
191		"\xd9\x01\x04\x50\x20\x01\x0d\xb8\x85\xa3\x00\x00\x00\x00\x8a\x2e\x03\x70\x73\x34"},
192}
193
194func TestAppendNetworkAddr(t *testing.T) {
195	for _, tc := range ipAddrTestCases {
196		s := enc.AppendIPAddr([]byte{}, tc.ipaddr)
197		got := string(s)
198		if got != tc.binary {
199			t.Errorf("AppendIPAddr(%s)=0x%s, want: 0x%s",
200				tc.ipaddr, hex.EncodeToString(s),
201				hex.EncodeToString([]byte(tc.binary)))
202		}
203	}
204}
205
206var macAddrTestCases = []struct {
207	macaddr net.HardwareAddr
208	text    string // ASCII representation of macaddr
209	binary  string // CBOR representation of macaddr
210}{
211	{net.HardwareAddr{0x12, 0x34, 0x56, 0x78, 0x90, 0xab}, "\"12:34:56:78:90:ab\"", "\xd9\x01\x04\x46\x12\x34\x56\x78\x90\xab"},
212	{net.HardwareAddr{0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3}, "\"20:01:0d:b8:85:a3\"", "\xd9\x01\x04\x46\x20\x01\x0d\xb8\x85\xa3"},
213}
214
215func TestAppendMacAddr(t *testing.T) {
216	for _, tc := range macAddrTestCases {
217		s := enc.AppendMACAddr([]byte{}, tc.macaddr)
218		got := string(s)
219		if got != tc.binary {
220			t.Errorf("AppendMACAddr(%s)=0x%s, want: 0x%s",
221				tc.macaddr.String(), hex.EncodeToString(s),
222				hex.EncodeToString([]byte(tc.binary)))
223		}
224	}
225}
226
227var IPPrefixTestCases = []struct {
228	pfx    net.IPNet
229	text   string // ASCII representation of pfx
230	binary string // CBOR representation of pfx
231}{
232	{net.IPNet{IP: net.IP{0, 0, 0, 0}, Mask: net.CIDRMask(0, 32)}, "\"0.0.0.0/0\"", "\xd9\x01\x05\xa1\x44\x00\x00\x00\x00\x00"},
233	{net.IPNet{IP: net.IP{192, 168, 0, 100}, Mask: net.CIDRMask(24, 32)}, "\"192.168.0.100/24\"",
234		"\xd9\x01\x05\xa1\x44\xc0\xa8\x00\x64\x18\x18"},
235}
236
237func TestAppendIPPrefix(t *testing.T) {
238	for _, tc := range IPPrefixTestCases {
239		s := enc.AppendIPPrefix([]byte{}, tc.pfx)
240		got := string(s)
241		if got != tc.binary {
242			t.Errorf("AppendIPPrefix(%s)=0x%s, want: 0x%s",
243				tc.pfx.String(), hex.EncodeToString(s),
244				hex.EncodeToString([]byte(tc.binary)))
245		}
246	}
247}
248
249func BenchmarkAppendInt(b *testing.B) {
250	type st struct {
251		sz  byte
252		val int64
253	}
254	tests := map[string]st{
255		"int-Positive": {sz: 0, val: 10000},
256		"int-Negative": {sz: 0, val: -10000},
257		"uint8":        {sz: 1, val: 100},
258		"uint16":       {sz: 2, val: 0xfff},
259		"uint32":       {sz: 4, val: 0xffffff},
260		"uint64":       {sz: 8, val: 0xffffffffff},
261		"int8":         {sz: 21, val: -120},
262		"int16":        {sz: 22, val: -1200},
263		"int32":        {sz: 23, val: 32000},
264		"int64":        {sz: 24, val: 0xffffffffff},
265	}
266	for name, str := range tests {
267		b.Run(name, func(b *testing.B) {
268			buf := make([]byte, 0, 100)
269			for i := 0; i < b.N; i++ {
270				switch str.sz {
271				case 0:
272					_ = enc.AppendInt(buf, int(str.val))
273				case 1:
274					_ = enc.AppendUint8(buf, uint8(str.val))
275				case 2:
276					_ = enc.AppendUint16(buf, uint16(str.val))
277				case 4:
278					_ = enc.AppendUint32(buf, uint32(str.val))
279				case 8:
280					_ = enc.AppendUint64(buf, uint64(str.val))
281				case 21:
282					_ = enc.AppendInt8(buf, int8(str.val))
283				case 22:
284					_ = enc.AppendInt16(buf, int16(str.val))
285				case 23:
286					_ = enc.AppendInt32(buf, int32(str.val))
287				case 24:
288					_ = enc.AppendInt64(buf, int64(str.val))
289				}
290			}
291		})
292	}
293}
294
295func BenchmarkAppendFloat(b *testing.B) {
296	type st struct {
297		sz  byte
298		val float64
299	}
300	tests := map[string]st{
301		"Float32": {sz: 4, val: 10000.12345},
302		"Float64": {sz: 8, val: -10000.54321},
303	}
304	for name, str := range tests {
305		b.Run(name, func(b *testing.B) {
306			buf := make([]byte, 0, 100)
307			for i := 0; i < b.N; i++ {
308				switch str.sz {
309				case 4:
310					_ = enc.AppendFloat32(buf, float32(str.val))
311				case 8:
312					_ = enc.AppendFloat64(buf, str.val)
313				}
314			}
315		})
316	}
317}
318