1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/cbor/writer.h"
6
7 #include <limits>
8 #include <string>
9
10 #include "base/stl_util.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 /* Leveraging RFC 7049 examples from
15 https://github.com/cbor/test-vectors/blob/master/appendix_a.json. */
16 namespace cbor {
17
TEST(CBORWriterTest,TestWriteUint)18 TEST(CBORWriterTest, TestWriteUint) {
19 struct UintTestCase {
20 const int64_t value;
21 const base::StringPiece cbor;
22 };
23
24 static const UintTestCase kUintTestCases[] = {
25 // Reminder: must specify length when creating string pieces
26 // with null bytes, else the string will truncate prematurely.
27 {0, base::StringPiece("\x00", 1)},
28 {1, base::StringPiece("\x01")},
29 {10, base::StringPiece("\x0a")},
30 {23, base::StringPiece("\x17")},
31 {24, base::StringPiece("\x18\x18")},
32 {25, base::StringPiece("\x18\x19")},
33 {100, base::StringPiece("\x18\x64")},
34 {1000, base::StringPiece("\x19\x03\xe8")},
35 {1000000, base::StringPiece("\x1a\x00\x0f\x42\x40", 5)},
36 {0xFFFFFFFF, base::StringPiece("\x1a\xff\xff\xff\xff")},
37 {0x100000000,
38 base::StringPiece("\x1b\x00\x00\x00\x01\x00\x00\x00\x00", 9)},
39 {std::numeric_limits<int64_t>::max(),
40 base::StringPiece("\x1b\x7f\xff\xff\xff\xff\xff\xff\xff")}};
41
42 for (const UintTestCase& test_case : kUintTestCases) {
43 auto cbor = Writer::Write(Value(test_case.value));
44 ASSERT_TRUE(cbor.has_value());
45 EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor));
46 }
47 }
48
TEST(CBORWriterTest,TestWriteNegativeInteger)49 TEST(CBORWriterTest, TestWriteNegativeInteger) {
50 static const struct {
51 const int64_t negative_int;
52 const base::StringPiece cbor;
53 } kNegativeIntTestCases[] = {
54 {-1LL, base::StringPiece("\x20")},
55 {-10LL, base::StringPiece("\x29")},
56 {-23LL, base::StringPiece("\x36")},
57 {-24LL, base::StringPiece("\x37")},
58 {-25LL, base::StringPiece("\x38\x18")},
59 {-100LL, base::StringPiece("\x38\x63")},
60 {-1000LL, base::StringPiece("\x39\x03\xe7")},
61 {-4294967296LL, base::StringPiece("\x3a\xff\xff\xff\xff")},
62 {-4294967297LL,
63 base::StringPiece("\x3b\x00\x00\x00\x01\x00\x00\x00\x00", 9)},
64 {std::numeric_limits<int64_t>::min(),
65 base::StringPiece("\x3b\x7f\xff\xff\xff\xff\xff\xff\xff")},
66 };
67
68 for (const auto& test_case : kNegativeIntTestCases) {
69 SCOPED_TRACE(testing::Message() << "testing negative int at index: "
70 << test_case.negative_int);
71
72 auto cbor = Writer::Write(Value(test_case.negative_int));
73 ASSERT_TRUE(cbor.has_value());
74 EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor));
75 }
76 }
77
TEST(CBORWriterTest,TestWriteBytes)78 TEST(CBORWriterTest, TestWriteBytes) {
79 struct BytesTestCase {
80 const std::vector<uint8_t> bytes;
81 const base::StringPiece cbor;
82 };
83
84 static const BytesTestCase kBytesTestCases[] = {
85 {{}, base::StringPiece("\x40")},
86 {{0x01, 0x02, 0x03, 0x04}, base::StringPiece("\x44\x01\x02\x03\x04")},
87 };
88
89 for (const BytesTestCase& test_case : kBytesTestCases) {
90 auto cbor = Writer::Write(Value(test_case.bytes));
91 ASSERT_TRUE(cbor.has_value());
92 EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor));
93 }
94 }
95
TEST(CBORWriterTest,TestWriteString)96 TEST(CBORWriterTest, TestWriteString) {
97 struct StringTestCase {
98 const std::string string;
99 const base::StringPiece cbor;
100 };
101
102 static const StringTestCase kStringTestCases[] = {
103 {"", base::StringPiece("\x60")},
104 {"a", base::StringPiece("\x61\x61")},
105 {"IETF", base::StringPiece("\x64\x49\x45\x54\x46")},
106 {"\"\\", base::StringPiece("\x62\x22\x5c")},
107 {"\xc3\xbc", base::StringPiece("\x62\xc3\xbc")},
108 {"\xe6\xb0\xb4", base::StringPiece("\x63\xe6\xb0\xb4")},
109 {"\xf0\x90\x85\x91", base::StringPiece("\x64\xf0\x90\x85\x91")}};
110
111 for (const StringTestCase& test_case : kStringTestCases) {
112 SCOPED_TRACE(testing::Message()
113 << "testing encoding string : " << test_case.string);
114
115 auto cbor = Writer::Write(Value(test_case.string));
116 ASSERT_TRUE(cbor.has_value());
117 EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor));
118 }
119 }
120
TEST(CBORWriterTest,TestWriteArray)121 TEST(CBORWriterTest, TestWriteArray) {
122 static const uint8_t kArrayTestCaseCbor[] = {
123 // clang-format off
124 0x98, 0x19, // array of 25 elements
125 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
126 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
127 0x18, 0x18, 0x19,
128 // clang-format on
129 };
130 std::vector<Value> array;
131 for (int64_t i = 1; i <= 25; i++) {
132 array.push_back(Value(i));
133 }
134 auto cbor = Writer::Write(Value(array));
135 ASSERT_TRUE(cbor.has_value());
136 EXPECT_THAT(cbor.value(),
137 testing::ElementsAreArray(kArrayTestCaseCbor,
138 base::size(kArrayTestCaseCbor)));
139 }
140
TEST(CBORWriterTest,TestWriteMap)141 TEST(CBORWriterTest, TestWriteMap) {
142 static const uint8_t kMapTestCaseCbor[] = {
143 // clang-format off
144 0xb8, 0x19, // map of 25 pairs:
145 0x00, // key 0
146 0x61, 0x61, // value "a"
147
148 0x17, // key 23
149 0x61, 0x62, // value "b"
150
151 0x18, 0x18, // key 24
152 0x61, 0x63, // value "c"
153
154 0x18, 0xFF, // key 255
155 0x61, 0x64, // value "d"
156
157 0x19, 0x01, 0x00, // key 256
158 0x61, 0x65, // value "e"
159
160 0x19, 0xFF, 0xFF, // key 65535
161 0x61, 0x66, // value "f"
162
163 0x1A, 0x00, 0x01, 0x00, 0x00, // key 65536
164 0x61, 0x67, // value "g"
165
166 0x1A, 0xFF, 0xFF, 0xFF, 0xFF, // key 4294967295
167 0x61, 0x68, // value "h"
168
169 // key 4294967296
170 0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
171 0x61, 0x69, // value "i"
172
173 // key INT64_MAX
174 0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
175 0x61, 0x6a, // value "j"
176
177 0x20, // key -1
178 0x61, 0x6b, // value "k"
179
180 0x37, // key -24
181 0x61, 0x6c, // value "l"
182
183 0x38, 0x18, // key -25
184 0x61, 0x6d, // value "m"
185
186 0x38, 0xFF, // key -256
187 0x61, 0x6e, // value "n"
188
189 0x39, 0x01, 0x00, // key -257
190 0x61, 0x6f, // value "o"
191
192 0x3A, 0x00, 0x01, 0x00, 0x00, // key -65537
193 0x61, 0x70, // value "p"
194
195 0x3A, 0xFF, 0xFF, 0xFF, 0xFF, // key -4294967296
196 0x61, 0x71, // value "q"
197
198 // key -4294967297
199 0x3B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
200 0x61, 0x72, // value "r"
201
202 // key INT64_MIN
203 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
204 0x61, 0x73, // value "s"
205
206 0x41, 'a', // byte string "a"
207 0x02,
208
209 0x43, 'b', 'a', 'r', // byte string "bar"
210 0x03,
211
212 0x43, 'f', 'o', 'o', // byte string "foo"
213 0x04,
214
215 0x60, // key ""
216 0x61, 0x2e, // value "."
217
218 0x61, 0x65, // key "e"
219 0x61, 0x45, // value "E"
220
221 0x62, 0x61, 0x61, // key "aa"
222 0x62, 0x41, 0x41, // value "AA"
223 // clang-format on
224 };
225 Value::MapValue map;
226 // Shorter strings sort first in CTAP, thus the “aa” value should be
227 // serialised last in the map.
228 map[Value("aa")] = Value("AA");
229 map[Value("e")] = Value("E");
230 // The empty string is shorter than all others, so should appear first among
231 // the strings.
232 map[Value("")] = Value(".");
233 // Map keys are sorted by major type, by byte length, and then by
234 // byte-wise lexical order. So all integer type keys should appear before
235 // key "" and all positive integer keys should appear before negative integer
236 // keys.
237 map[Value(-1)] = Value("k");
238 map[Value(-24)] = Value("l");
239 map[Value(-25)] = Value("m");
240 map[Value(-256)] = Value("n");
241 map[Value(-257)] = Value("o");
242 map[Value(-65537)] = Value("p");
243 map[Value(int64_t(-4294967296))] = Value("q");
244 map[Value(int64_t(-4294967297))] = Value("r");
245 map[Value(std::numeric_limits<int64_t>::min())] = Value("s");
246 map[Value(Value::BinaryValue{'a'})] = Value(2);
247 map[Value(Value::BinaryValue{'b', 'a', 'r'})] = Value(3);
248 map[Value(Value::BinaryValue{'f', 'o', 'o'})] = Value(4);
249 map[Value(0)] = Value("a");
250 map[Value(23)] = Value("b");
251 map[Value(24)] = Value("c");
252 map[Value(std::numeric_limits<uint8_t>::max())] = Value("d");
253 map[Value(256)] = Value("e");
254 map[Value(std::numeric_limits<uint16_t>::max())] = Value("f");
255 map[Value(65536)] = Value("g");
256 map[Value(int64_t(std::numeric_limits<uint32_t>::max()))] = Value("h");
257 map[Value(int64_t(4294967296))] = Value("i");
258 map[Value(std::numeric_limits<int64_t>::max())] = Value("j");
259 auto cbor = Writer::Write(Value(map));
260 ASSERT_TRUE(cbor.has_value());
261 EXPECT_THAT(cbor.value(),
262 testing::ElementsAreArray(kMapTestCaseCbor,
263 base::size(kMapTestCaseCbor)));
264 }
265
TEST(CBORWriterTest,TestWriteMapWithArray)266 TEST(CBORWriterTest, TestWriteMapWithArray) {
267 static const uint8_t kMapArrayTestCaseCbor[] = {
268 // clang-format off
269 0xa2, // map of 2 pairs
270 0x61, 0x61, // "a"
271 0x01,
272
273 0x61, 0x62, // "b"
274 0x82, // array with 2 elements
275 0x02,
276 0x03,
277 // clang-format on
278 };
279 Value::MapValue map;
280 map[Value("a")] = Value(1);
281 Value::ArrayValue array;
282 array.push_back(Value(2));
283 array.push_back(Value(3));
284 map[Value("b")] = Value(array);
285 auto cbor = Writer::Write(Value(map));
286 ASSERT_TRUE(cbor.has_value());
287 EXPECT_THAT(cbor.value(),
288 testing::ElementsAreArray(kMapArrayTestCaseCbor,
289 base::size(kMapArrayTestCaseCbor)));
290 }
291
TEST(CBORWriterTest,TestWriteNestedMap)292 TEST(CBORWriterTest, TestWriteNestedMap) {
293 static const uint8_t kNestedMapTestCase[] = {
294 // clang-format off
295 0xa2, // map of 2 pairs
296 0x61, 0x61, // "a"
297 0x01,
298
299 0x61, 0x62, // "b"
300 0xa2, // map of 2 pairs
301 0x61, 0x63, // "c"
302 0x02,
303
304 0x61, 0x64, // "d"
305 0x03,
306 // clang-format on
307 };
308 Value::MapValue map;
309 map[Value("a")] = Value(1);
310 Value::MapValue nested_map;
311 nested_map[Value("c")] = Value(2);
312 nested_map[Value("d")] = Value(3);
313 map[Value("b")] = Value(nested_map);
314 auto cbor = Writer::Write(Value(map));
315 ASSERT_TRUE(cbor.has_value());
316 EXPECT_THAT(cbor.value(),
317 testing::ElementsAreArray(kNestedMapTestCase,
318 base::size(kNestedMapTestCase)));
319 }
320
TEST(CBORWriterTest,TestSignedExchangeExample)321 TEST(CBORWriterTest, TestSignedExchangeExample) {
322 // Example adopted from:
323 // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html
324 static const uint8_t kSignedExchangeExample[] = {
325 // clang-format off
326 0xa5, // map of 5 pairs
327 0x0a, // 10
328 0x01,
329
330 0x18, 0x64, // 100
331 0x02,
332
333 0x20, // -1
334 0x03,
335
336 0x61, 'z', // text string "z"
337 0x04,
338
339 0x62, 'a', 'a', // text string "aa"
340 0x05,
341
342 /*
343 0x81, 0x18, 0x64, // [100] (array as map key is not yet supported)
344 0x06,
345
346 0x81, 0x20, // [-1] (array as map key is not yet supported)
347 0x07,
348
349 0xf4, // false (boolean as map key is not yet supported)
350 0x08,
351 */
352 // clang-format on
353 };
354 Value::MapValue map;
355 map[Value(10)] = Value(1);
356 map[Value(100)] = Value(2);
357 map[Value(-1)] = Value(3);
358 map[Value("z")] = Value(4);
359 map[Value("aa")] = Value(5);
360
361 auto cbor = Writer::Write(Value(map));
362 ASSERT_TRUE(cbor.has_value());
363 EXPECT_THAT(cbor.value(),
364 testing::ElementsAreArray(kSignedExchangeExample,
365 base::size(kSignedExchangeExample)));
366 }
367
TEST(CBORWriterTest,TestWriteSimpleValue)368 TEST(CBORWriterTest, TestWriteSimpleValue) {
369 static const struct {
370 Value::SimpleValue simple_value;
371 const base::StringPiece cbor;
372 } kSimpleTestCase[] = {
373 {Value::SimpleValue::FALSE_VALUE, base::StringPiece("\xf4")},
374 {Value::SimpleValue::TRUE_VALUE, base::StringPiece("\xf5")},
375 {Value::SimpleValue::NULL_VALUE, base::StringPiece("\xf6")},
376 {Value::SimpleValue::UNDEFINED, base::StringPiece("\xf7")}};
377
378 for (const auto& test_case : kSimpleTestCase) {
379 auto cbor = Writer::Write(Value(test_case.simple_value));
380 ASSERT_TRUE(cbor.has_value());
381 EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor));
382 }
383 }
384
385 // For major type 0, 2, 3, empty CBOR array, and empty CBOR map, the nesting
386 // depth is expected to be 0 since the CBOR decoder does not need to parse
387 // any nested CBOR value elements.
TEST(CBORWriterTest,TestWriteSingleLayer)388 TEST(CBORWriterTest, TestWriteSingleLayer) {
389 const Value simple_uint = Value(1);
390 const Value simple_string = Value("a");
391 const std::vector<uint8_t> byte_data = {0x01, 0x02, 0x03, 0x04};
392 const Value simple_bytestring = Value(byte_data);
393 Value::ArrayValue empty_cbor_array;
394 Value::MapValue empty_cbor_map;
395 const Value empty_array_value = Value(empty_cbor_array);
396 const Value empty_map_value = Value(empty_cbor_map);
397 Value::ArrayValue simple_array;
398 simple_array.push_back(Value(2));
399 Value::MapValue simple_map;
400 simple_map[Value("b")] = Value(3);
401 const Value single_layer_cbor_map = Value(simple_map);
402 const Value single_layer_cbor_array = Value(simple_array);
403
404 EXPECT_TRUE(Writer::Write(simple_uint, 0).has_value());
405 EXPECT_TRUE(Writer::Write(simple_string, 0).has_value());
406 EXPECT_TRUE(Writer::Write(simple_bytestring, 0).has_value());
407
408 EXPECT_TRUE(Writer::Write(empty_array_value, 0).has_value());
409 EXPECT_TRUE(Writer::Write(empty_map_value, 0).has_value());
410
411 EXPECT_FALSE(Writer::Write(single_layer_cbor_array, 0).has_value());
412 EXPECT_TRUE(Writer::Write(single_layer_cbor_array, 1).has_value());
413
414 EXPECT_FALSE(Writer::Write(single_layer_cbor_map, 0).has_value());
415 EXPECT_TRUE(Writer::Write(single_layer_cbor_map, 1).has_value());
416 }
417
418 // Major type 5 nested CBOR map value with following structure.
419 // {"a": 1,
420 // "b": {"c": 2,
421 // "d": 3}}
TEST(CBORWriterTest,NestedMaps)422 TEST(CBORWriterTest, NestedMaps) {
423 Value::MapValue cbor_map;
424 cbor_map[Value("a")] = Value(1);
425 Value::MapValue nested_map;
426 nested_map[Value("c")] = Value(2);
427 nested_map[Value("d")] = Value(3);
428 cbor_map[Value("b")] = Value(nested_map);
429 EXPECT_TRUE(Writer::Write(Value(cbor_map), 2).has_value());
430 EXPECT_FALSE(Writer::Write(Value(cbor_map), 1).has_value());
431 }
432
433 // Testing Write() function for following CBOR structure with depth of 3.
434 // [1,
435 // 2,
436 // 3,
437 // {"a": 1,
438 // "b": {"c": 2,
439 // "d": 3}}]
TEST(CBORWriterTest,UnbalancedNestedContainers)440 TEST(CBORWriterTest, UnbalancedNestedContainers) {
441 Value::ArrayValue cbor_array;
442 Value::MapValue cbor_map;
443 Value::MapValue nested_map;
444
445 cbor_map[Value("a")] = Value(1);
446 nested_map[Value("c")] = Value(2);
447 nested_map[Value("d")] = Value(3);
448 cbor_map[Value("b")] = Value(nested_map);
449 cbor_array.push_back(Value(1));
450 cbor_array.push_back(Value(2));
451 cbor_array.push_back(Value(3));
452 cbor_array.push_back(Value(cbor_map));
453
454 EXPECT_TRUE(Writer::Write(Value(cbor_array), 3).has_value());
455 EXPECT_FALSE(Writer::Write(Value(cbor_array), 2).has_value());
456 }
457
458 // Testing Write() function for following CBOR structure.
459 // {"a": 1,
460 // "b": {"c": 2,
461 // "d": 3
462 // "h": { "e": 4,
463 // "f": 5,
464 // "g": [6, 7, [8]]}}}
465 // Since above CBOR contains 5 nesting levels. Thus, Write() is expected to
466 // return empty optional object when maximum nesting layer size is set to 4.
TEST(CBORWriterTest,OverlyNestedCBOR)467 TEST(CBORWriterTest, OverlyNestedCBOR) {
468 Value::MapValue map;
469 Value::MapValue nested_map;
470 Value::MapValue inner_nested_map;
471 Value::ArrayValue inner_array;
472 Value::ArrayValue array;
473
474 map[Value("a")] = Value(1);
475 nested_map[Value("c")] = Value(2);
476 nested_map[Value("d")] = Value(3);
477 inner_nested_map[Value("e")] = Value(4);
478 inner_nested_map[Value("f")] = Value(5);
479 inner_array.push_back(Value(6));
480 array.push_back(Value(6));
481 array.push_back(Value(7));
482 array.push_back(Value(inner_array));
483 inner_nested_map[Value("g")] = Value(array);
484 nested_map[Value("h")] = Value(inner_nested_map);
485 map[Value("b")] = Value(nested_map);
486
487 EXPECT_TRUE(Writer::Write(Value(map), 5).has_value());
488 EXPECT_FALSE(Writer::Write(Value(map), 4).has_value());
489 }
490
491 } // namespace cbor
492