1// Copyright 2018 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 "encoding.h" 6 7#include <array> 8#include <clocale> 9#include <cmath> 10#include <cstdlib> 11#include <cstring> 12#include <iomanip> 13#include <iostream> 14#include <sstream> 15#include <string> 16 17#include "encoding_test_helper.h" 18 19using testing::ElementsAreArray; 20 21namespace v8_inspector_protocol_encoding { 22 23class TestPlatform : public json::Platform { 24 bool StrToD(const char* str, double* result) const override { 25 // This is not thread-safe 26 // (see https://en.cppreference.com/w/cpp/locale/setlocale) 27 // but good enough for a unittest. 28 const char* saved_locale = std::setlocale(LC_NUMERIC, nullptr); 29 char* end; 30 *result = std::strtod(str, &end); 31 std::setlocale(LC_NUMERIC, saved_locale); 32 if (errno == ERANGE) { 33 // errno must be reset, e.g. see the example here: 34 // https://en.cppreference.com/w/cpp/string/byte/strtof 35 errno = 0; 36 return false; 37 } 38 return end == str + strlen(str); 39 } 40 41 std::unique_ptr<char[]> DToStr(double value) const override { 42 std::stringstream ss; 43 ss.imbue(std::locale("C")); 44 ss << value; 45 std::string str = ss.str(); 46 std::unique_ptr<char[]> result(new char[str.size() + 1]); 47 memcpy(result.get(), str.c_str(), str.size() + 1); 48 return result; 49 } 50}; 51 52const json::Platform& GetTestPlatform() { 53 static TestPlatform* platform = new TestPlatform; 54 return *platform; 55} 56 57// ============================================================================= 58// span - sequence of bytes 59// ============================================================================= 60 61template <typename T> 62class SpanTest : public ::testing::Test {}; 63 64using TestTypes = ::testing::Types<uint8_t, uint16_t>; 65TYPED_TEST_SUITE(SpanTest, TestTypes); 66 67TYPED_TEST(SpanTest, Empty) { 68 span<TypeParam> empty; 69 EXPECT_TRUE(empty.empty()); 70 EXPECT_EQ(0u, empty.size()); 71 EXPECT_EQ(0u, empty.size_bytes()); 72 EXPECT_EQ(empty.begin(), empty.end()); 73} 74 75TYPED_TEST(SpanTest, SingleItem) { 76 TypeParam single_item = 42; 77 span<TypeParam> singular(&single_item, 1); 78 EXPECT_FALSE(singular.empty()); 79 EXPECT_EQ(1u, singular.size()); 80 EXPECT_EQ(sizeof(TypeParam), singular.size_bytes()); 81 EXPECT_EQ(singular.begin() + 1, singular.end()); 82 EXPECT_EQ(42, singular[0]); 83} 84 85TYPED_TEST(SpanTest, FiveItems) { 86 std::vector<TypeParam> test_input = {31, 32, 33, 34, 35}; 87 span<TypeParam> five_items(test_input.data(), 5); 88 EXPECT_FALSE(five_items.empty()); 89 EXPECT_EQ(5u, five_items.size()); 90 EXPECT_EQ(sizeof(TypeParam) * 5, five_items.size_bytes()); 91 EXPECT_EQ(five_items.begin() + 5, five_items.end()); 92 EXPECT_EQ(31, five_items[0]); 93 EXPECT_EQ(32, five_items[1]); 94 EXPECT_EQ(33, five_items[2]); 95 EXPECT_EQ(34, five_items[3]); 96 EXPECT_EQ(35, five_items[4]); 97 span<TypeParam> three_items = five_items.subspan(2); 98 EXPECT_EQ(3u, three_items.size()); 99 EXPECT_EQ(33, three_items[0]); 100 EXPECT_EQ(34, three_items[1]); 101 EXPECT_EQ(35, three_items[2]); 102 span<TypeParam> two_items = five_items.subspan(2, 2); 103 EXPECT_EQ(2u, two_items.size()); 104 EXPECT_EQ(33, two_items[0]); 105 EXPECT_EQ(34, two_items[1]); 106} 107 108TEST(SpanFromTest, FromConstCharAndLiteral) { 109 // Testing this is useful because strlen(nullptr) is undefined. 110 EXPECT_EQ(nullptr, SpanFrom(nullptr).data()); 111 EXPECT_EQ(0u, SpanFrom(nullptr).size()); 112 113 const char* kEmpty = ""; 114 EXPECT_EQ(kEmpty, reinterpret_cast<const char*>(SpanFrom(kEmpty).data())); 115 EXPECT_EQ(0u, SpanFrom(kEmpty).size()); 116 117 const char* kFoo = "foo"; 118 EXPECT_EQ(kFoo, reinterpret_cast<const char*>(SpanFrom(kFoo).data())); 119 EXPECT_EQ(3u, SpanFrom(kFoo).size()); 120 121 EXPECT_EQ(3u, SpanFrom("foo").size()); 122} 123 124// ============================================================================= 125// Status and Error codes 126// ============================================================================= 127 128TEST(StatusTest, StatusToASCIIString) { 129 Status ok_status; 130 EXPECT_EQ("OK", ok_status.ToASCIIString()); 131 Status json_error(Error::JSON_PARSER_COLON_EXPECTED, 42); 132 EXPECT_EQ("JSON: colon expected at position 42", json_error.ToASCIIString()); 133 Status cbor_error(Error::CBOR_TRAILING_JUNK, 21); 134 EXPECT_EQ("CBOR: trailing junk at position 21", cbor_error.ToASCIIString()); 135} 136 137namespace cbor { 138 139// ============================================================================= 140// Detecting CBOR content 141// ============================================================================= 142 143TEST(IsCBORMessage, SomeSmokeTests) { 144 std::vector<uint8_t> empty; 145 EXPECT_FALSE(IsCBORMessage(SpanFrom(empty))); 146 std::vector<uint8_t> hello = {'H', 'e', 'l', 'o', ' ', 't', 147 'h', 'e', 'r', 'e', '!'}; 148 EXPECT_FALSE(IsCBORMessage(SpanFrom(hello))); 149 std::vector<uint8_t> example = {0xd8, 0x5a, 0, 0, 0, 0}; 150 EXPECT_TRUE(IsCBORMessage(SpanFrom(example))); 151 std::vector<uint8_t> one = {0xd8, 0x5a, 0, 0, 0, 1, 1}; 152 EXPECT_TRUE(IsCBORMessage(SpanFrom(one))); 153} 154 155// ============================================================================= 156// Encoding individual CBOR items 157// cbor::CBORTokenizer - for parsing individual CBOR items 158// ============================================================================= 159 160// 161// EncodeInt32 / CBORTokenTag::INT32 162// 163TEST(EncodeDecodeInt32Test, Roundtrips23) { 164 // This roundtrips the int32_t value 23 through the pair of EncodeInt32 / 165 // CBORTokenizer; this is interesting since 23 is encoded as a single byte. 166 std::vector<uint8_t> encoded; 167 EncodeInt32(23, &encoded); 168 // first three bits: major type = 0; remaining five bits: additional info = 169 // value 23. 170 EXPECT_THAT(encoded, ElementsAreArray(std::array<uint8_t, 1>{{23}})); 171 172 // Reverse direction: decode with CBORTokenizer. 173 CBORTokenizer tokenizer(SpanFrom(encoded)); 174 EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag()); 175 EXPECT_EQ(23, tokenizer.GetInt32()); 176 tokenizer.Next(); 177 EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag()); 178} 179 180TEST(EncodeDecodeInt32Test, RoundtripsUint8) { 181 // This roundtrips the int32_t value 42 through the pair of EncodeInt32 / 182 // CBORTokenizer. This is different from Roundtrip23 because 42 is encoded 183 // in an extra byte after the initial one. 184 std::vector<uint8_t> encoded; 185 EncodeInt32(42, &encoded); 186 // first three bits: major type = 0; 187 // remaining five bits: additional info = 24, indicating payload is uint8. 188 EXPECT_THAT(encoded, ElementsAreArray(std::array<uint8_t, 2>{{24, 42}})); 189 190 // Reverse direction: decode with CBORTokenizer. 191 CBORTokenizer tokenizer(SpanFrom(encoded)); 192 EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag()); 193 EXPECT_EQ(42, tokenizer.GetInt32()); 194 tokenizer.Next(); 195 EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag()); 196} 197 198TEST(EncodeDecodeInt32Test, RoundtripsUint16) { 199 // 500 is encoded as a uint16 after the initial byte. 200 std::vector<uint8_t> encoded; 201 EncodeInt32(500, &encoded); 202 // 1 for initial byte, 2 for uint16. 203 EXPECT_EQ(3u, encoded.size()); 204 // first three bits: major type = 0; 205 // remaining five bits: additional info = 25, indicating payload is uint16. 206 EXPECT_EQ(25, encoded[0]); 207 EXPECT_EQ(0x01, encoded[1]); 208 EXPECT_EQ(0xf4, encoded[2]); 209 210 // Reverse direction: decode with CBORTokenizer. 211 CBORTokenizer tokenizer(SpanFrom(encoded)); 212 EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag()); 213 EXPECT_EQ(500, tokenizer.GetInt32()); 214 tokenizer.Next(); 215 EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag()); 216} 217 218TEST(EncodeDecodeInt32Test, RoundtripsInt32Max) { 219 // std::numeric_limits<int32_t> is encoded as a uint32 after the initial byte. 220 std::vector<uint8_t> encoded; 221 EncodeInt32(std::numeric_limits<int32_t>::max(), &encoded); 222 // 1 for initial byte, 4 for the uint32. 223 // first three bits: major type = 0; 224 // remaining five bits: additional info = 26, indicating payload is uint32. 225 EXPECT_THAT( 226 encoded, 227 ElementsAreArray(std::array<uint8_t, 5>{{26, 0x7f, 0xff, 0xff, 0xff}})); 228 229 // Reverse direction: decode with CBORTokenizer. 230 CBORTokenizer tokenizer(SpanFrom(encoded)); 231 EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag()); 232 EXPECT_EQ(std::numeric_limits<int32_t>::max(), tokenizer.GetInt32()); 233 tokenizer.Next(); 234 EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag()); 235} 236 237TEST(EncodeDecodeInt32Test, RoundtripsInt32Min) { 238 // std::numeric_limits<int32_t> is encoded as a uint32 (4 unsigned bytes) 239 // after the initial byte, which effectively carries the sign by 240 // designating the token as NEGATIVE. 241 std::vector<uint8_t> encoded; 242 EncodeInt32(std::numeric_limits<int32_t>::min(), &encoded); 243 // 1 for initial byte, 4 for the uint32. 244 // first three bits: major type = 1; 245 // remaining five bits: additional info = 26, indicating payload is uint32. 246 EXPECT_THAT(encoded, ElementsAreArray(std::array<uint8_t, 5>{ 247 {1 << 5 | 26, 0x7f, 0xff, 0xff, 0xff}})); 248 249 // Reverse direction: decode with CBORTokenizer. 250 CBORTokenizer tokenizer(SpanFrom(encoded)); 251 EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag()); 252 EXPECT_EQ(std::numeric_limits<int32_t>::min(), tokenizer.GetInt32()); 253 // It's nice to see how the min int32 value reads in hex: 254 // That is, -1 minus the unsigned payload (0x7fffffff, see above). 255 int32_t expected = -1 - 0x7fffffff; 256 EXPECT_EQ(expected, tokenizer.GetInt32()); 257 tokenizer.Next(); 258 EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag()); 259} 260 261TEST(EncodeDecodeInt32Test, CantRoundtripUint32) { 262 // 0xdeadbeef is a value which does not fit below 263 // std::numerical_limits<int32_t>::max(), so we can't encode 264 // it with EncodeInt32. However, CBOR does support this, so we 265 // encode it here manually with the internal routine, just to observe 266 // that it's considered an invalid int32 by CBORTokenizer. 267 std::vector<uint8_t> encoded; 268 internals::WriteTokenStart(MajorType::UNSIGNED, 0xdeadbeef, &encoded); 269 // 1 for initial byte, 4 for the uint32. 270 // first three bits: major type = 0; 271 // remaining five bits: additional info = 26, indicating payload is uint32. 272 EXPECT_THAT( 273 encoded, 274 ElementsAreArray(std::array<uint8_t, 5>{{26, 0xde, 0xad, 0xbe, 0xef}})); 275 276 // Now try to decode; we treat this as an invalid INT32. 277 CBORTokenizer tokenizer(SpanFrom(encoded)); 278 // 0xdeadbeef is > std::numerical_limits<int32_t>::max(). 279 EXPECT_EQ(CBORTokenTag::ERROR_VALUE, tokenizer.TokenTag()); 280 EXPECT_EQ(Error::CBOR_INVALID_INT32, tokenizer.Status().error); 281} 282 283TEST(EncodeDecodeInt32Test, DecodeErrorCases) { 284 struct TestCase { 285 std::vector<uint8_t> data; 286 std::string msg; 287 }; 288 std::vector<TestCase> tests{{ 289 TestCase{ 290 {24}, 291 "additional info = 24 would require 1 byte of payload (but it's 0)"}, 292 TestCase{{27, 0xaa, 0xbb, 0xcc}, 293 "additional info = 27 would require 8 bytes of payload (but " 294 "it's 3)"}, 295 TestCase{{29}, "additional info = 29 isn't recognized"}, 296 TestCase{{1 << 5 | 27, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 297 "Max UINT64 payload is outside the allowed range"}, 298 TestCase{{1 << 5 | 26, 0xff, 0xff, 0xff, 0xff}, 299 "Max UINT32 payload is outside the allowed range"}, 300 TestCase{{1 << 5 | 26, 0x80, 0x00, 0x00, 0x00}, 301 "UINT32 payload w/ high bit set is outside the allowed range"}, 302 }}; 303 for (const TestCase& test : tests) { 304 SCOPED_TRACE(test.msg); 305 CBORTokenizer tokenizer(SpanFrom(test.data)); 306 EXPECT_EQ(CBORTokenTag::ERROR_VALUE, tokenizer.TokenTag()); 307 EXPECT_EQ(Error::CBOR_INVALID_INT32, tokenizer.Status().error); 308 } 309} 310 311TEST(EncodeDecodeInt32Test, RoundtripsMinus24) { 312 // This roundtrips the int32_t value -24 through the pair of EncodeInt32 / 313 // CBORTokenizer; this is interesting since -24 is encoded as 314 // a single byte as NEGATIVE, and it tests the specific encoding 315 // (note how for unsigned the single byte covers values up to 23). 316 // Additional examples are covered in RoundtripsAdditionalExamples. 317 std::vector<uint8_t> encoded; 318 EncodeInt32(-24, &encoded); 319 // first three bits: major type = 1; remaining five bits: additional info = 320 // value 23. 321 EXPECT_THAT(encoded, ElementsAreArray(std::array<uint8_t, 1>{{1 << 5 | 23}})); 322 323 // Reverse direction: decode with CBORTokenizer. 324 CBORTokenizer tokenizer(SpanFrom(encoded)); 325 EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag()); 326 EXPECT_EQ(-24, tokenizer.GetInt32()); 327 tokenizer.Next(); 328 EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag()); 329} 330 331TEST(EncodeDecodeInt32Test, RoundtripsAdditionalNegativeExamples) { 332 std::vector<int32_t> examples = {-1, 333 -10, 334 -24, 335 -25, 336 -300, 337 -30000, 338 -300 * 1000, 339 -1000 * 1000, 340 -1000 * 1000 * 1000, 341 std::numeric_limits<int32_t>::min()}; 342 for (int32_t example : examples) { 343 SCOPED_TRACE(std::string("example ") + std::to_string(example)); 344 std::vector<uint8_t> encoded; 345 EncodeInt32(example, &encoded); 346 CBORTokenizer tokenizer(SpanFrom(encoded)); 347 EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag()); 348 EXPECT_EQ(example, tokenizer.GetInt32()); 349 tokenizer.Next(); 350 EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag()); 351 } 352} 353 354// 355// EncodeString16 / CBORTokenTag::STRING16 356// 357TEST(EncodeDecodeString16Test, RoundtripsEmpty) { 358 // This roundtrips the empty utf16 string through the pair of EncodeString16 / 359 // CBORTokenizer. 360 std::vector<uint8_t> encoded; 361 EncodeString16(span<uint16_t>(), &encoded); 362 EXPECT_EQ(1u, encoded.size()); 363 // first three bits: major type = 2; remaining five bits: additional info = 364 // size 0. 365 EXPECT_EQ(2 << 5, encoded[0]); 366 367 // Reverse direction: decode with CBORTokenizer. 368 CBORTokenizer tokenizer(SpanFrom(encoded)); 369 EXPECT_EQ(CBORTokenTag::STRING16, tokenizer.TokenTag()); 370 span<uint8_t> decoded_string16_wirerep = tokenizer.GetString16WireRep(); 371 EXPECT_TRUE(decoded_string16_wirerep.empty()); 372 tokenizer.Next(); 373 EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag()); 374} 375 376// On the wire, we STRING16 is encoded as little endian (least 377// significant byte first). The host may or may not be little endian, 378// so this routine follows the advice in 379// https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html. 380std::vector<uint16_t> String16WireRepToHost(span<uint8_t> in) { 381 // must be even number of bytes. 382 CHECK_EQ(in.size() & 1, 0u); 383 std::vector<uint16_t> host_out; 384 for (size_t ii = 0; ii < in.size(); ii += 2) 385 host_out.push_back(in[ii + 1] << 8 | in[ii]); 386 return host_out; 387} 388 389TEST(EncodeDecodeString16Test, RoundtripsHelloWorld) { 390 // This roundtrips the hello world message which is given here in utf16 391 // characters. 0xd83c, 0xdf0e: UTF16 encoding for the "Earth Globe Americas" 392 // character, . 393 std::array<uint16_t, 10> msg{ 394 {'H', 'e', 'l', 'l', 'o', ',', ' ', 0xd83c, 0xdf0e, '.'}}; 395 std::vector<uint8_t> encoded; 396 EncodeString16(span<uint16_t>(msg.data(), msg.size()), &encoded); 397 // This will be encoded as BYTE_STRING of length 20, so the 20 is encoded in 398 // the additional info part of the initial byte. Payload is two bytes for each 399 // UTF16 character. 400 uint8_t initial_byte = /*major type=*/2 << 5 | /*additional info=*/20; 401 std::array<uint8_t, 21> encoded_expected = { 402 {initial_byte, 'H', 0, 'e', 0, 'l', 0, 'l', 0, 'o', 0, 403 ',', 0, ' ', 0, 0x3c, 0xd8, 0x0e, 0xdf, '.', 0}}; 404 EXPECT_THAT(encoded, ElementsAreArray(encoded_expected)); 405 406 // Now decode to complete the roundtrip. 407 CBORTokenizer tokenizer(SpanFrom(encoded)); 408 EXPECT_EQ(CBORTokenTag::STRING16, tokenizer.TokenTag()); 409 std::vector<uint16_t> decoded = 410 String16WireRepToHost(tokenizer.GetString16WireRep()); 411 EXPECT_THAT(decoded, ElementsAreArray(msg)); 412 tokenizer.Next(); 413 EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag()); 414 415 // For bonus points, we look at the decoded message in UTF8 as well so we can 416 // easily see it on the terminal screen. 417 std::string utf8_decoded = UTF16ToUTF8(SpanFrom(decoded)); 418 EXPECT_EQ("Hello, .", utf8_decoded); 419} 420 421TEST(EncodeDecodeString16Test, Roundtrips500) { 422 // We roundtrip a message that has 250 16 bit values. Each of these are just 423 // set to their index. 250 is interesting because the cbor spec uses a 424 // BYTE_STRING of length 500 for one of their examples of how to encode the 425 // start of it (section 2.1) so it's easy for us to look at the first three 426 // bytes closely. 427 std::vector<uint16_t> two_fifty; 428 for (uint16_t ii = 0; ii < 250; ++ii) 429 two_fifty.push_back(ii); 430 std::vector<uint8_t> encoded; 431 EncodeString16(span<uint16_t>(two_fifty.data(), two_fifty.size()), &encoded); 432 EXPECT_EQ(3u + 250u * 2, encoded.size()); 433 // Now check the first three bytes: 434 // Major type: 2 (BYTE_STRING) 435 // Additional information: 25, indicating size is represented by 2 bytes. 436 // Bytes 1 and 2 encode 500 (0x01f4). 437 EXPECT_EQ(2 << 5 | 25, encoded[0]); 438 EXPECT_EQ(0x01, encoded[1]); 439 EXPECT_EQ(0xf4, encoded[2]); 440 441 // Now decode to complete the roundtrip. 442 CBORTokenizer tokenizer(SpanFrom(encoded)); 443 EXPECT_EQ(CBORTokenTag::STRING16, tokenizer.TokenTag()); 444 std::vector<uint16_t> decoded = 445 String16WireRepToHost(tokenizer.GetString16WireRep()); 446 EXPECT_THAT(decoded, ElementsAreArray(two_fifty)); 447 tokenizer.Next(); 448 EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag()); 449} 450 451TEST(EncodeDecodeString16Test, ErrorCases) { 452 struct TestCase { 453 std::vector<uint8_t> data; 454 std::string msg; 455 }; 456 std::vector<TestCase> tests{ 457 {TestCase{{2 << 5 | 1, 'a'}, 458 "length must be divisible by 2 (but it's 1)"}, 459 TestCase{{2 << 5 | 29}, "additional info = 29 isn't recognized"}, 460 TestCase{{2 << 5 | 9, 1, 2, 3, 4, 5, 6, 7, 8}, 461 "length (9) points just past the end of the test case"}, 462 TestCase{{2 << 5 | 27, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 463 'a', 'b', 'c'}, 464 "large length pointing past the end of the test case"}}}; 465 for (const TestCase& test : tests) { 466 SCOPED_TRACE(test.msg); 467 CBORTokenizer tokenizer(SpanFrom(test.data)); 468 EXPECT_EQ(CBORTokenTag::ERROR_VALUE, tokenizer.TokenTag()); 469 EXPECT_EQ(Error::CBOR_INVALID_STRING16, tokenizer.Status().error); 470 } 471} 472 473// 474// EncodeString8 / CBORTokenTag::STRING8 475// 476TEST(EncodeDecodeString8Test, RoundtripsHelloWorld) { 477 // This roundtrips the hello world message which is given here in utf8 478 // characters. is a four byte utf8 character. 479 std::string utf8_msg = "Hello, ."; 480 std::vector<uint8_t> msg(utf8_msg.begin(), utf8_msg.end()); 481 std::vector<uint8_t> encoded; 482 EncodeString8(SpanFrom(utf8_msg), &encoded); 483 // This will be encoded as STRING of length 12, so the 12 is encoded in 484 // the additional info part of the initial byte. Payload is one byte per 485 // utf8 byte. 486 uint8_t initial_byte = /*major type=*/3 << 5 | /*additional info=*/12; 487 std::array<uint8_t, 13> encoded_expected = {{initial_byte, 'H', 'e', 'l', 'l', 488 'o', ',', ' ', 0xF0, 0x9f, 0x8c, 489 0x8e, '.'}}; 490 EXPECT_THAT(encoded, ElementsAreArray(encoded_expected)); 491 492 // Now decode to complete the roundtrip. 493 CBORTokenizer tokenizer(SpanFrom(encoded)); 494 EXPECT_EQ(CBORTokenTag::STRING8, tokenizer.TokenTag()); 495 std::vector<uint8_t> decoded(tokenizer.GetString8().begin(), 496 tokenizer.GetString8().end()); 497 EXPECT_THAT(decoded, ElementsAreArray(msg)); 498 tokenizer.Next(); 499 EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag()); 500} 501 502TEST(EncodeDecodeString8Test, ErrorCases) { 503 struct TestCase { 504 std::vector<uint8_t> data; 505 std::string msg; 506 }; 507 std::vector<TestCase> tests{ 508 {TestCase{{3 << 5 | 29}, "additional info = 29 isn't recognized"}, 509 TestCase{{3 << 5 | 9, 1, 2, 3, 4, 5, 6, 7, 8}, 510 "length (9) points just past the end of the test case"}, 511 TestCase{{3 << 5 | 27, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 512 'a', 'b', 'c'}, 513 "large length pointing past the end of the test case"}}}; 514 for (const TestCase& test : tests) { 515 SCOPED_TRACE(test.msg); 516 CBORTokenizer tokenizer(SpanFrom(test.data)); 517 EXPECT_EQ(CBORTokenTag::ERROR_VALUE, tokenizer.TokenTag()); 518 EXPECT_EQ(Error::CBOR_INVALID_STRING8, tokenizer.Status().error); 519 } 520} 521 522TEST(EncodeFromLatin1Test, ConvertsToUTF8IfNeeded) { 523 std::vector<std::pair<std::string, std::string>> examples = { 524 {"Hello, world.", "Hello, world."}, 525 {"Above: \xDC" 526 "ber", 527 "Above: Über"}, 528 {"\xA5 500 are about \xA3 3.50; a y with umlaut is \xFF", 529 "¥ 500 are about £ 3.50; a y with umlaut is ÿ"}}; 530 531 for (const auto& example : examples) { 532 const std::string& latin1 = example.first; 533 const std::string& expected_utf8 = example.second; 534 std::vector<uint8_t> encoded; 535 EncodeFromLatin1(SpanFrom(latin1), &encoded); 536 CBORTokenizer tokenizer(SpanFrom(encoded)); 537 EXPECT_EQ(CBORTokenTag::STRING8, tokenizer.TokenTag()); 538 std::vector<uint8_t> decoded(tokenizer.GetString8().begin(), 539 tokenizer.GetString8().end()); 540 std::string decoded_str(decoded.begin(), decoded.end()); 541 EXPECT_THAT(decoded_str, testing::Eq(expected_utf8)); 542 } 543} 544 545TEST(EncodeFromUTF16Test, ConvertsToUTF8IfEasy) { 546 std::vector<uint16_t> ascii = {'e', 'a', 's', 'y'}; 547 std::vector<uint8_t> encoded; 548 EncodeFromUTF16(span<uint16_t>(ascii.data(), ascii.size()), &encoded); 549 550 CBORTokenizer tokenizer(SpanFrom(encoded)); 551 EXPECT_EQ(CBORTokenTag::STRING8, tokenizer.TokenTag()); 552 std::vector<uint8_t> decoded(tokenizer.GetString8().begin(), 553 tokenizer.GetString8().end()); 554 std::string decoded_str(decoded.begin(), decoded.end()); 555 EXPECT_THAT(decoded_str, testing::Eq("easy")); 556} 557 558TEST(EncodeFromUTF16Test, EncodesAsString16IfNeeded) { 559 // Since this message contains non-ASCII characters, the routine is 560 // forced to encode as UTF16. We see this below by checking that the 561 // token tag is STRING16. 562 std::vector<uint16_t> msg = {'H', 'e', 'l', 'l', 'o', 563 ',', ' ', 0xd83c, 0xdf0e, '.'}; 564 std::vector<uint8_t> encoded; 565 EncodeFromUTF16(span<uint16_t>(msg.data(), msg.size()), &encoded); 566 567 CBORTokenizer tokenizer(SpanFrom(encoded)); 568 EXPECT_EQ(CBORTokenTag::STRING16, tokenizer.TokenTag()); 569 std::vector<uint16_t> decoded = 570 String16WireRepToHost(tokenizer.GetString16WireRep()); 571 std::string utf8_decoded = UTF16ToUTF8(SpanFrom(decoded)); 572 EXPECT_EQ("Hello, .", utf8_decoded); 573} 574 575// 576// EncodeBinary / CBORTokenTag::BINARY 577// 578TEST(EncodeDecodeBinaryTest, RoundtripsHelloWorld) { 579 std::vector<uint8_t> binary = {'H', 'e', 'l', 'l', 'o', ',', ' ', 580 'w', 'o', 'r', 'l', 'd', '.'}; 581 std::vector<uint8_t> encoded; 582 EncodeBinary(span<uint8_t>(binary.data(), binary.size()), &encoded); 583 // So, on the wire we see that the binary blob travels unmodified. 584 EXPECT_THAT( 585 encoded, 586 ElementsAreArray(std::array<uint8_t, 15>{ 587 {(6 << 5 | 22), // tag 22 indicating base64 interpretation in JSON 588 (2 << 5 | 13), // BYTE_STRING (type 2) of length 13 589 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.'}})); 590 std::vector<uint8_t> decoded; 591 CBORTokenizer tokenizer(SpanFrom(encoded)); 592 EXPECT_EQ(CBORTokenTag::BINARY, tokenizer.TokenTag()); 593 EXPECT_EQ(0, static_cast<int>(tokenizer.Status().error)); 594 decoded = std::vector<uint8_t>(tokenizer.GetBinary().begin(), 595 tokenizer.GetBinary().end()); 596 EXPECT_THAT(decoded, ElementsAreArray(binary)); 597 tokenizer.Next(); 598 EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag()); 599} 600 601TEST(EncodeDecodeBinaryTest, ErrorCases) { 602 struct TestCase { 603 std::vector<uint8_t> data; 604 std::string msg; 605 }; 606 std::vector<TestCase> tests{{TestCase{ 607 {6 << 5 | 22, // tag 22 indicating base64 interpretation in JSON 608 2 << 5 | 27, // BYTE_STRING (type 2), followed by 8 bytes length 609 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 610 "large length pointing past the end of the test case"}}}; 611 for (const TestCase& test : tests) { 612 SCOPED_TRACE(test.msg); 613 CBORTokenizer tokenizer(SpanFrom(test.data)); 614 EXPECT_EQ(CBORTokenTag::ERROR_VALUE, tokenizer.TokenTag()); 615 EXPECT_EQ(Error::CBOR_INVALID_BINARY, tokenizer.Status().error); 616 } 617} 618 619// 620// EncodeDouble / CBORTokenTag::DOUBLE 621// 622TEST(EncodeDecodeDoubleTest, RoundtripsWikipediaExample) { 623 // https://en.wikipedia.org/wiki/Double-precision_floating-point_format 624 // provides the example of a hex representation 3FD5 5555 5555 5555, which 625 // approximates 1/3. 626 627 const double kOriginalValue = 1.0 / 3; 628 std::vector<uint8_t> encoded; 629 EncodeDouble(kOriginalValue, &encoded); 630 // first three bits: major type = 7; remaining five bits: additional info = 631 // value 27. This is followed by 8 bytes of payload (which match Wikipedia). 632 EXPECT_THAT( 633 encoded, 634 ElementsAreArray(std::array<uint8_t, 9>{ 635 {7 << 5 | 27, 0x3f, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}})); 636 637 // Reverse direction: decode and compare with original value. 638 CBORTokenizer tokenizer(SpanFrom(encoded)); 639 EXPECT_EQ(CBORTokenTag::DOUBLE, tokenizer.TokenTag()); 640 EXPECT_THAT(tokenizer.GetDouble(), testing::DoubleEq(kOriginalValue)); 641 tokenizer.Next(); 642 EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag()); 643} 644 645TEST(EncodeDecodeDoubleTest, RoundtripsAdditionalExamples) { 646 std::vector<double> examples = {0.0, 647 1.0, 648 -1.0, 649 3.1415, 650 std::numeric_limits<double>::min(), 651 std::numeric_limits<double>::max(), 652 std::numeric_limits<double>::infinity(), 653 std::numeric_limits<double>::quiet_NaN()}; 654 for (double example : examples) { 655 SCOPED_TRACE(std::string("example ") + std::to_string(example)); 656 std::vector<uint8_t> encoded; 657 EncodeDouble(example, &encoded); 658 CBORTokenizer tokenizer(SpanFrom(encoded)); 659 EXPECT_EQ(CBORTokenTag::DOUBLE, tokenizer.TokenTag()); 660 if (std::isnan(example)) 661 EXPECT_TRUE(std::isnan(tokenizer.GetDouble())); 662 else 663 EXPECT_THAT(tokenizer.GetDouble(), testing::DoubleEq(example)); 664 tokenizer.Next(); 665 EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag()); 666 } 667} 668 669// ============================================================================= 670// cbor::NewCBOREncoder - for encoding from a streaming parser 671// ============================================================================= 672 673void EncodeUTF8ForTest(const std::string& key, std::vector<uint8_t>* out) { 674 EncodeString8(SpanFrom(key), out); 675} 676TEST(JSONToCBOREncoderTest, SevenBitStrings) { 677 // When a string can be represented as 7 bit ASCII, the encoder will use the 678 // STRING (major Type 3) type, so the actual characters end up as bytes on the 679 // wire. 680 std::vector<uint8_t> encoded; 681 Status status; 682 std::unique_ptr<StreamingParserHandler> encoder = 683 NewCBOREncoder(&encoded, &status); 684 std::vector<uint16_t> utf16 = {'f', 'o', 'o'}; 685 encoder->HandleString16(span<uint16_t>(utf16.data(), utf16.size())); 686 EXPECT_EQ(Error::OK, status.error); 687 // Here we assert that indeed, seven bit strings are represented as 688 // bytes on the wire, "foo" is just "foo". 689 EXPECT_THAT(encoded, 690 ElementsAreArray(std::array<uint8_t, 4>{ 691 {/*major type 3*/ 3 << 5 | /*length*/ 3, 'f', 'o', 'o'}})); 692} 693 694TEST(JsonCborRoundtrip, EncodingDecoding) { 695 // Hits all the cases except binary and error in StreamingParserHandler, first 696 // parsing a JSON message into CBOR, then parsing it back from CBOR into JSON. 697 std::string json = 698 "{" 699 "\"string\":\"Hello, \\ud83c\\udf0e.\"," 700 "\"double\":3.1415," 701 "\"int\":1," 702 "\"negative int\":-1," 703 "\"bool\":true," 704 "\"null\":null," 705 "\"array\":[1,2,3]" 706 "}"; 707 std::vector<uint8_t> encoded; 708 Status status; 709 std::unique_ptr<StreamingParserHandler> encoder = 710 NewCBOREncoder(&encoded, &status); 711 span<uint8_t> ascii_in = SpanFrom(json); 712 json::ParseJSON(GetTestPlatform(), ascii_in, encoder.get()); 713 std::vector<uint8_t> expected = { 714 0xd8, // envelope 715 0x5a, // byte string with 32 bit length 716 0, 0, 0, 94, // length is 94 bytes 717 }; 718 expected.push_back(0xbf); // indef length map start 719 EncodeString8(SpanFrom("string"), &expected); 720 // This is followed by the encoded string for "Hello, ." 721 // So, it's the same bytes that we tested above in 722 // EncodeDecodeString16Test.RoundtripsHelloWorld. 723 expected.push_back(/*major type=*/2 << 5 | /*additional info=*/20); 724 for (uint8_t ch : std::array<uint8_t, 20>{ 725 {'H', 0, 'e', 0, 'l', 0, 'l', 0, 'o', 0, 726 ',', 0, ' ', 0, 0x3c, 0xd8, 0x0e, 0xdf, '.', 0}}) 727 expected.push_back(ch); 728 EncodeString8(SpanFrom("double"), &expected); 729 EncodeDouble(3.1415, &expected); 730 EncodeString8(SpanFrom("int"), &expected); 731 EncodeInt32(1, &expected); 732 EncodeString8(SpanFrom("negative int"), &expected); 733 EncodeInt32(-1, &expected); 734 EncodeString8(SpanFrom("bool"), &expected); 735 expected.push_back(7 << 5 | 21); // RFC 7049 Section 2.3, Table 2: true 736 EncodeString8(SpanFrom("null"), &expected); 737 expected.push_back(7 << 5 | 22); // RFC 7049 Section 2.3, Table 2: null 738 EncodeString8(SpanFrom("array"), &expected); 739 expected.push_back(0xd8); // envelope 740 expected.push_back(0x5a); // byte string with 32 bit length 741 // the length is 5 bytes (that's up to end indef length array below). 742 for (uint8_t ch : std::array<uint8_t, 4>{{0, 0, 0, 5}}) 743 expected.push_back(ch); 744 expected.push_back(0x9f); // RFC 7049 Section 2.2.1, indef length array start 745 expected.push_back(1); // Three UNSIGNED values (easy since Major Type 0) 746 expected.push_back(2); 747 expected.push_back(3); 748 expected.push_back(0xff); // End indef length array 749 expected.push_back(0xff); // End indef length map 750 EXPECT_TRUE(status.ok()); 751 EXPECT_THAT(encoded, ElementsAreArray(expected)); 752 753 // And now we roundtrip, decoding the message we just encoded. 754 std::string decoded; 755 std::unique_ptr<StreamingParserHandler> json_encoder = 756 NewJSONEncoder(&GetTestPlatform(), &decoded, &status); 757 ParseCBOR(span<uint8_t>(encoded.data(), encoded.size()), json_encoder.get()); 758 EXPECT_EQ(Error::OK, status.error); 759 EXPECT_EQ(json, decoded); 760} 761 762TEST(JsonCborRoundtrip, MoreRoundtripExamples) { 763 std::vector<std::string> examples = { 764 // Tests that after closing a nested objects, additional key/value pairs 765 // are considered. 766 "{\"foo\":{\"bar\":1},\"baz\":2}", "{\"foo\":[1,2,3],\"baz\":2}"}; 767 for (const std::string& json : examples) { 768 SCOPED_TRACE(std::string("example: ") + json); 769 std::vector<uint8_t> encoded; 770 Status status; 771 std::unique_ptr<StreamingParserHandler> encoder = 772 NewCBOREncoder(&encoded, &status); 773 span<uint8_t> ascii_in = SpanFrom(json); 774 ParseJSON(GetTestPlatform(), ascii_in, encoder.get()); 775 std::string decoded; 776 std::unique_ptr<StreamingParserHandler> json_writer = 777 NewJSONEncoder(&GetTestPlatform(), &decoded, &status); 778 ParseCBOR(span<uint8_t>(encoded.data(), encoded.size()), json_writer.get()); 779 EXPECT_EQ(Error::OK, status.error); 780 EXPECT_EQ(json, decoded); 781 } 782} 783 784TEST(JSONToCBOREncoderTest, HelloWorldBinary_WithTripToJson) { 785 // The StreamingParserHandler::HandleBinary is a special case: The JSON parser 786 // will never call this method, because JSON does not natively support the 787 // binary type. So, we can't fully roundtrip. However, the other direction 788 // works: binary will be rendered in JSON, as a base64 string. So, we make 789 // calls to the encoder directly here, to construct a message, and one of 790 // these calls is ::HandleBinary, to which we pass a "binary" string 791 // containing "Hello, world.". 792 std::vector<uint8_t> encoded; 793 Status status; 794 std::unique_ptr<StreamingParserHandler> encoder = 795 NewCBOREncoder(&encoded, &status); 796 encoder->HandleMapBegin(); 797 // Emit a key. 798 std::vector<uint16_t> key = {'f', 'o', 'o'}; 799 encoder->HandleString16(SpanFrom(key)); 800 // Emit the binary payload, an arbitrary array of bytes that happens to 801 // be the ascii message "Hello, world.". 802 encoder->HandleBinary(SpanFrom(std::vector<uint8_t>{ 803 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.'})); 804 encoder->HandleMapEnd(); 805 EXPECT_EQ(Error::OK, status.error); 806 807 // Now drive the json writer via the CBOR decoder. 808 std::string decoded; 809 std::unique_ptr<StreamingParserHandler> json_writer = 810 NewJSONEncoder(&GetTestPlatform(), &decoded, &status); 811 ParseCBOR(SpanFrom(encoded), json_writer.get()); 812 EXPECT_EQ(Error::OK, status.error); 813 EXPECT_EQ(Status::npos(), status.pos); 814 // "Hello, world." in base64 is "SGVsbG8sIHdvcmxkLg==". 815 EXPECT_EQ("{\"foo\":\"SGVsbG8sIHdvcmxkLg==\"}", decoded); 816} 817 818// ============================================================================= 819// cbor::ParseCBOR - for receiving streaming parser events for CBOR messages 820// ============================================================================= 821 822TEST(ParseCBORTest, ParseEmptyCBORMessage) { 823 // An envelope starting with 0xd8, 0x5a, with the byte length 824 // of 2, containing a map that's empty (0xbf for map 825 // start, and 0xff for map end). 826 std::vector<uint8_t> in = {0xd8, 0x5a, 0, 0, 0, 2, 0xbf, 0xff}; 827 std::string out; 828 Status status; 829 std::unique_ptr<StreamingParserHandler> json_writer = 830 NewJSONEncoder(&GetTestPlatform(), &out, &status); 831 ParseCBOR(span<uint8_t>(in.data(), in.size()), json_writer.get()); 832 EXPECT_EQ(Error::OK, status.error); 833 EXPECT_EQ("{}", out); 834} 835 836TEST(ParseCBORTest, ParseCBORHelloWorld) { 837 const uint8_t kPayloadLen = 27; 838 std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen}; 839 bytes.push_back(0xbf); // start indef length map. 840 EncodeString8(SpanFrom("msg"), &bytes); // key: msg 841 // Now write the value, the familiar "Hello, ." where the globe is expressed 842 // as two utf16 chars. 843 bytes.push_back(/*major type=*/2 << 5 | /*additional info=*/20); 844 for (uint8_t ch : std::array<uint8_t, 20>{ 845 {'H', 0, 'e', 0, 'l', 0, 'l', 0, 'o', 0, 846 ',', 0, ' ', 0, 0x3c, 0xd8, 0x0e, 0xdf, '.', 0}}) 847 bytes.push_back(ch); 848 bytes.push_back(0xff); // stop byte 849 EXPECT_EQ(kPayloadLen, bytes.size() - 6); 850 851 std::string out; 852 Status status; 853 std::unique_ptr<StreamingParserHandler> json_writer = 854 NewJSONEncoder(&GetTestPlatform(), &out, &status); 855 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 856 EXPECT_EQ(Error::OK, status.error); 857 EXPECT_EQ("{\"msg\":\"Hello, \\ud83c\\udf0e.\"}", out); 858} 859 860TEST(ParseCBORTest, UTF8IsSupportedInKeys) { 861 const uint8_t kPayloadLen = 11; 862 std::vector<uint8_t> bytes = {cbor::InitialByteForEnvelope(), 863 cbor::InitialByteFor32BitLengthByteString(), 864 0, 865 0, 866 0, 867 kPayloadLen}; 868 bytes.push_back(cbor::EncodeIndefiniteLengthMapStart()); 869 // Two UTF16 chars. 870 EncodeString8(SpanFrom(""), &bytes); 871 // Can be encoded as a single UTF16 char. 872 EncodeString8(SpanFrom("☾"), &bytes); 873 bytes.push_back(cbor::EncodeStop()); 874 EXPECT_EQ(kPayloadLen, bytes.size() - 6); 875 876 std::string out; 877 Status status; 878 std::unique_ptr<StreamingParserHandler> json_writer = 879 NewJSONEncoder(&GetTestPlatform(), &out, &status); 880 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 881 EXPECT_EQ(Error::OK, status.error); 882 EXPECT_EQ("{\"\\ud83c\\udf0e\":\"\\u263e\"}", out); 883} 884 885TEST(ParseCBORTest, NoInputError) { 886 std::vector<uint8_t> in = {}; 887 std::string out; 888 Status status; 889 std::unique_ptr<StreamingParserHandler> json_writer = 890 NewJSONEncoder(&GetTestPlatform(), &out, &status); 891 ParseCBOR(span<uint8_t>(in.data(), in.size()), json_writer.get()); 892 EXPECT_EQ(Error::CBOR_NO_INPUT, status.error); 893 EXPECT_EQ("", out); 894} 895 896TEST(ParseCBORTest, InvalidStartByteError) { 897 // Here we test that some actual json, which usually starts with {, 898 // is not considered CBOR. CBOR messages must start with 0x5a, the 899 // envelope start byte. 900 std::string json = "{\"msg\": \"Hello, world.\"}"; 901 std::string out; 902 Status status; 903 std::unique_ptr<StreamingParserHandler> json_writer = 904 NewJSONEncoder(&GetTestPlatform(), &out, &status); 905 ParseCBOR(SpanFrom(json), json_writer.get()); 906 EXPECT_EQ(Error::CBOR_INVALID_START_BYTE, status.error); 907 EXPECT_EQ("", out); 908} 909 910TEST(ParseCBORTest, UnexpectedEofExpectedValueError) { 911 constexpr uint8_t kPayloadLen = 5; 912 std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 913 0xbf}; // map start 914 // A key; so value would be next. 915 EncodeString8(SpanFrom("key"), &bytes); 916 EXPECT_EQ(kPayloadLen, bytes.size() - 6); 917 std::string out; 918 Status status; 919 std::unique_ptr<StreamingParserHandler> json_writer = 920 NewJSONEncoder(&GetTestPlatform(), &out, &status); 921 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 922 EXPECT_EQ(Error::CBOR_UNEXPECTED_EOF_EXPECTED_VALUE, status.error); 923 EXPECT_EQ(bytes.size(), status.pos); 924 EXPECT_EQ("", out); 925} 926 927TEST(ParseCBORTest, UnexpectedEofInArrayError) { 928 constexpr uint8_t kPayloadLen = 8; 929 std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 930 0xbf}; // The byte for starting a map. 931 // A key; so value would be next. 932 EncodeString8(SpanFrom("array"), &bytes); 933 bytes.push_back(0x9f); // byte for indefinite length array start. 934 EXPECT_EQ(kPayloadLen, bytes.size() - 6); 935 std::string out; 936 Status status; 937 std::unique_ptr<StreamingParserHandler> json_writer = 938 NewJSONEncoder(&GetTestPlatform(), &out, &status); 939 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 940 EXPECT_EQ(Error::CBOR_UNEXPECTED_EOF_IN_ARRAY, status.error); 941 EXPECT_EQ(bytes.size(), status.pos); 942 EXPECT_EQ("", out); 943} 944 945TEST(ParseCBORTest, UnexpectedEofInMapError) { 946 constexpr uint8_t kPayloadLen = 1; 947 std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 948 0xbf}; // The byte for starting a map. 949 EXPECT_EQ(kPayloadLen, bytes.size() - 6); 950 std::string out; 951 Status status; 952 std::unique_ptr<StreamingParserHandler> json_writer = 953 NewJSONEncoder(&GetTestPlatform(), &out, &status); 954 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 955 EXPECT_EQ(Error::CBOR_UNEXPECTED_EOF_IN_MAP, status.error); 956 EXPECT_EQ(7u, status.pos); 957 EXPECT_EQ("", out); 958} 959 960TEST(ParseCBORTest, InvalidMapKeyError) { 961 constexpr uint8_t kPayloadLen = 2; 962 std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 963 0, 0, kPayloadLen, // envelope 964 0xbf, // map start 965 7 << 5 | 22}; // null (not a valid map key) 966 EXPECT_EQ(kPayloadLen, bytes.size() - 6); 967 std::string out; 968 Status status; 969 std::unique_ptr<StreamingParserHandler> json_writer = 970 NewJSONEncoder(&GetTestPlatform(), &out, &status); 971 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 972 EXPECT_EQ(Error::CBOR_INVALID_MAP_KEY, status.error); 973 EXPECT_EQ(7u, status.pos); 974 EXPECT_EQ("", out); 975} 976 977std::vector<uint8_t> MakeNestedCBOR(int depth) { 978 std::vector<uint8_t> bytes; 979 std::vector<EnvelopeEncoder> envelopes; 980 for (int ii = 0; ii < depth; ++ii) { 981 envelopes.emplace_back(); 982 envelopes.back().EncodeStart(&bytes); 983 bytes.push_back(0xbf); // indef length map start 984 EncodeString8(SpanFrom("key"), &bytes); 985 } 986 EncodeString8(SpanFrom("innermost_value"), &bytes); 987 for (int ii = 0; ii < depth; ++ii) { 988 bytes.push_back(0xff); // stop byte, finishes map. 989 envelopes.back().EncodeStop(&bytes); 990 envelopes.pop_back(); 991 } 992 return bytes; 993} 994 995TEST(ParseCBORTest, StackLimitExceededError) { 996 { // Depth 3: no stack limit exceeded error and is easy to inspect. 997 std::vector<uint8_t> bytes = MakeNestedCBOR(3); 998 std::string out; 999 Status status; 1000 std::unique_ptr<StreamingParserHandler> json_writer = 1001 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1002 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 1003 EXPECT_EQ(Error::OK, status.error); 1004 EXPECT_EQ(Status::npos(), status.pos); 1005 EXPECT_EQ("{\"key\":{\"key\":{\"key\":\"innermost_value\"}}}", out); 1006 } 1007 { // Depth 300: no stack limit exceeded. 1008 std::vector<uint8_t> bytes = MakeNestedCBOR(300); 1009 std::string out; 1010 Status status; 1011 std::unique_ptr<StreamingParserHandler> json_writer = 1012 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1013 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 1014 EXPECT_EQ(Error::OK, status.error); 1015 EXPECT_EQ(Status::npos(), status.pos); 1016 } 1017 1018 // We just want to know the length of one opening map so we can compute 1019 // where the error is encountered. So we look at a small example and find 1020 // the second envelope start. 1021 std::vector<uint8_t> small_example = MakeNestedCBOR(3); 1022 size_t opening_segment_size = 1; // Start after the first envelope start. 1023 while (opening_segment_size < small_example.size() && 1024 small_example[opening_segment_size] != 0xd8) 1025 opening_segment_size++; 1026 1027 { // Depth 301: limit exceeded. 1028 std::vector<uint8_t> bytes = MakeNestedCBOR(301); 1029 std::string out; 1030 Status status; 1031 std::unique_ptr<StreamingParserHandler> json_writer = 1032 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1033 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 1034 EXPECT_EQ(Error::CBOR_STACK_LIMIT_EXCEEDED, status.error); 1035 EXPECT_EQ(opening_segment_size * 301, status.pos); 1036 } 1037 { // Depth 320: still limit exceeded, and at the same pos as for 1001 1038 std::vector<uint8_t> bytes = MakeNestedCBOR(320); 1039 std::string out; 1040 Status status; 1041 std::unique_ptr<StreamingParserHandler> json_writer = 1042 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1043 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 1044 EXPECT_EQ(Error::CBOR_STACK_LIMIT_EXCEEDED, status.error); 1045 EXPECT_EQ(opening_segment_size * 301, status.pos); 1046 } 1047} 1048 1049TEST(ParseCBORTest, UnsupportedValueError) { 1050 constexpr uint8_t kPayloadLen = 6; 1051 std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 1052 0xbf}; // map start 1053 EncodeString8(SpanFrom("key"), &bytes); 1054 size_t error_pos = bytes.size(); 1055 bytes.push_back(6 << 5 | 5); // tags aren't supported yet. 1056 EXPECT_EQ(kPayloadLen, bytes.size() - 6); 1057 1058 std::string out; 1059 Status status; 1060 std::unique_ptr<StreamingParserHandler> json_writer = 1061 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1062 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 1063 EXPECT_EQ(Error::CBOR_UNSUPPORTED_VALUE, status.error); 1064 EXPECT_EQ(error_pos, status.pos); 1065 EXPECT_EQ("", out); 1066} 1067 1068TEST(ParseCBORTest, InvalidString16Error) { 1069 constexpr uint8_t kPayloadLen = 11; 1070 std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 1071 0xbf}; // map start 1072 EncodeString8(SpanFrom("key"), &bytes); 1073 size_t error_pos = bytes.size(); 1074 // a BYTE_STRING of length 5 as value; since we interpret these as string16, 1075 // it's going to be invalid as each character would need two bytes, but 1076 // 5 isn't divisible by 2. 1077 bytes.push_back(2 << 5 | 5); 1078 for (int ii = 0; ii < 5; ++ii) 1079 bytes.push_back(' '); 1080 EXPECT_EQ(kPayloadLen, bytes.size() - 6); 1081 std::string out; 1082 Status status; 1083 std::unique_ptr<StreamingParserHandler> json_writer = 1084 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1085 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 1086 EXPECT_EQ(Error::CBOR_INVALID_STRING16, status.error); 1087 EXPECT_EQ(error_pos, status.pos); 1088 EXPECT_EQ("", out); 1089} 1090 1091TEST(ParseCBORTest, InvalidString8Error) { 1092 constexpr uint8_t kPayloadLen = 6; 1093 std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 1094 0xbf}; // map start 1095 EncodeString8(SpanFrom("key"), &bytes); 1096 size_t error_pos = bytes.size(); 1097 // a STRING of length 5 as value, but we're at the end of the bytes array 1098 // so it can't be decoded successfully. 1099 bytes.push_back(3 << 5 | 5); 1100 EXPECT_EQ(kPayloadLen, bytes.size() - 6); 1101 std::string out; 1102 Status status; 1103 std::unique_ptr<StreamingParserHandler> json_writer = 1104 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1105 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 1106 EXPECT_EQ(Error::CBOR_INVALID_STRING8, status.error); 1107 EXPECT_EQ(error_pos, status.pos); 1108 EXPECT_EQ("", out); 1109} 1110 1111TEST(ParseCBORTest, InvalidBinaryError) { 1112 constexpr uint8_t kPayloadLen = 9; 1113 std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 1114 0xbf}; // map start 1115 EncodeString8(SpanFrom("key"), &bytes); 1116 size_t error_pos = bytes.size(); 1117 bytes.push_back(6 << 5 | 22); // base64 hint for JSON; indicates binary 1118 bytes.push_back(2 << 5 | 10); // BYTE_STRING (major type 2) of length 10 1119 // Just two garbage bytes, not enough for the binary. 1120 bytes.push_back(0x31); 1121 bytes.push_back(0x23); 1122 EXPECT_EQ(kPayloadLen, bytes.size() - 6); 1123 std::string out; 1124 Status status; 1125 std::unique_ptr<StreamingParserHandler> json_writer = 1126 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1127 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 1128 EXPECT_EQ(Error::CBOR_INVALID_BINARY, status.error); 1129 EXPECT_EQ(error_pos, status.pos); 1130 EXPECT_EQ("", out); 1131} 1132 1133TEST(ParseCBORTest, InvalidDoubleError) { 1134 constexpr uint8_t kPayloadLen = 8; 1135 std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 1136 0xbf}; // map start 1137 EncodeString8(SpanFrom("key"), &bytes); 1138 size_t error_pos = bytes.size(); 1139 bytes.push_back(7 << 5 | 27); // initial byte for double 1140 // Just two garbage bytes, not enough to represent an actual double. 1141 bytes.push_back(0x31); 1142 bytes.push_back(0x23); 1143 EXPECT_EQ(kPayloadLen, bytes.size() - 6); 1144 std::string out; 1145 Status status; 1146 std::unique_ptr<StreamingParserHandler> json_writer = 1147 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1148 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 1149 EXPECT_EQ(Error::CBOR_INVALID_DOUBLE, status.error); 1150 EXPECT_EQ(error_pos, status.pos); 1151 EXPECT_EQ("", out); 1152} 1153 1154TEST(ParseCBORTest, InvalidSignedError) { 1155 constexpr uint8_t kPayloadLen = 14; 1156 std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 1157 0xbf}; // map start 1158 EncodeString8(SpanFrom("key"), &bytes); 1159 size_t error_pos = bytes.size(); 1160 // uint64_t max is a perfectly fine value to encode as CBOR unsigned, 1161 // but we don't support this since we only cover the int32_t range. 1162 internals::WriteTokenStart(MajorType::UNSIGNED, 1163 std::numeric_limits<uint64_t>::max(), &bytes); 1164 EXPECT_EQ(kPayloadLen, bytes.size() - 6); 1165 std::string out; 1166 Status status; 1167 std::unique_ptr<StreamingParserHandler> json_writer = 1168 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1169 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 1170 EXPECT_EQ(Error::CBOR_INVALID_INT32, status.error); 1171 EXPECT_EQ(error_pos, status.pos); 1172 EXPECT_EQ("", out); 1173} 1174 1175TEST(ParseCBORTest, TrailingJunk) { 1176 constexpr uint8_t kPayloadLen = 35; 1177 std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 1178 0xbf}; // map start 1179 EncodeString8(SpanFrom("key"), &bytes); 1180 EncodeString8(SpanFrom("value"), &bytes); 1181 bytes.push_back(0xff); // Up to here, it's a perfectly fine msg. 1182 size_t error_pos = bytes.size(); 1183 EncodeString8(SpanFrom("trailing junk"), &bytes); 1184 1185 internals::WriteTokenStart(MajorType::UNSIGNED, 1186 std::numeric_limits<uint64_t>::max(), &bytes); 1187 EXPECT_EQ(kPayloadLen, bytes.size() - 6); 1188 std::string out; 1189 Status status; 1190 std::unique_ptr<StreamingParserHandler> json_writer = 1191 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1192 ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); 1193 EXPECT_EQ(Error::CBOR_TRAILING_JUNK, status.error); 1194 EXPECT_EQ(error_pos, status.pos); 1195 EXPECT_EQ("", out); 1196} 1197 1198// ============================================================================= 1199// cbor::AppendString8EntryToMap - for limited in-place editing of messages 1200// ============================================================================= 1201 1202template <typename T> 1203class AppendString8EntryToMapTest : public ::testing::Test {}; 1204 1205using ContainerTestTypes = ::testing::Types<std::vector<uint8_t>, std::string>; 1206TYPED_TEST_SUITE(AppendString8EntryToMapTest, ContainerTestTypes); 1207 1208TYPED_TEST(AppendString8EntryToMapTest, AppendsEntrySuccessfully) { 1209 constexpr uint8_t kPayloadLen = 12; 1210 std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 1211 0xbf}; // map start 1212 size_t pos_before_payload = bytes.size() - 1; 1213 EncodeString8(SpanFrom("key"), &bytes); 1214 EncodeString8(SpanFrom("value"), &bytes); 1215 bytes.push_back(0xff); // A perfectly fine cbor message. 1216 EXPECT_EQ(kPayloadLen, bytes.size() - pos_before_payload); 1217 1218 TypeParam msg(bytes.begin(), bytes.end()); 1219 1220 Status status = 1221 AppendString8EntryToCBORMap(SpanFrom("foo"), SpanFrom("bar"), &msg); 1222 EXPECT_EQ(Error::OK, status.error); 1223 EXPECT_EQ(Status::npos(), status.pos); 1224 std::string out; 1225 std::unique_ptr<StreamingParserHandler> json_writer = 1226 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1227 ParseCBOR(SpanFrom(msg), json_writer.get()); 1228 EXPECT_EQ("{\"key\":\"value\",\"foo\":\"bar\"}", out); 1229 EXPECT_EQ(Error::OK, status.error); 1230 EXPECT_EQ(Status::npos(), status.pos); 1231} 1232 1233TYPED_TEST(AppendString8EntryToMapTest, AppendThreeEntries) { 1234 std::vector<uint8_t> encoded = { 1235 0xd8, 0x5a, 0, 0, 0, 2, EncodeIndefiniteLengthMapStart(), EncodeStop()}; 1236 EXPECT_EQ(Error::OK, AppendString8EntryToCBORMap(SpanFrom("key"), 1237 SpanFrom("value"), &encoded) 1238 .error); 1239 EXPECT_EQ(Error::OK, AppendString8EntryToCBORMap(SpanFrom("key1"), 1240 SpanFrom("value1"), &encoded) 1241 .error); 1242 EXPECT_EQ(Error::OK, AppendString8EntryToCBORMap(SpanFrom("key2"), 1243 SpanFrom("value2"), &encoded) 1244 .error); 1245 TypeParam msg(encoded.begin(), encoded.end()); 1246 std::string out; 1247 Status status; 1248 std::unique_ptr<StreamingParserHandler> json_writer = 1249 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1250 ParseCBOR(SpanFrom(msg), json_writer.get()); 1251 EXPECT_EQ("{\"key\":\"value\",\"key1\":\"value1\",\"key2\":\"value2\"}", out); 1252 EXPECT_EQ(Error::OK, status.error); 1253 EXPECT_EQ(Status::npos(), status.pos); 1254} 1255 1256TYPED_TEST(AppendString8EntryToMapTest, MapStartExpected_Error) { 1257 std::vector<uint8_t> bytes = { 1258 0xd8, 0x5a, 0, 0, 0, 1, EncodeIndefiniteLengthArrayStart()}; 1259 TypeParam msg(bytes.begin(), bytes.end()); 1260 Status status = 1261 AppendString8EntryToCBORMap(SpanFrom("key"), SpanFrom("value"), &msg); 1262 EXPECT_EQ(Error::CBOR_MAP_START_EXPECTED, status.error); 1263 EXPECT_EQ(6u, status.pos); 1264} 1265 1266TYPED_TEST(AppendString8EntryToMapTest, MapStopExpected_Error) { 1267 std::vector<uint8_t> bytes = { 1268 0xd8, 0x5a, 0, 0, 0, 2, EncodeIndefiniteLengthMapStart(), 42}; 1269 TypeParam msg(bytes.begin(), bytes.end()); 1270 Status status = 1271 AppendString8EntryToCBORMap(SpanFrom("key"), SpanFrom("value"), &msg); 1272 EXPECT_EQ(Error::CBOR_MAP_STOP_EXPECTED, status.error); 1273 EXPECT_EQ(7u, status.pos); 1274} 1275 1276TYPED_TEST(AppendString8EntryToMapTest, InvalidEnvelope_Error) { 1277 { // Second byte is wrong. 1278 std::vector<uint8_t> bytes = { 1279 0x5a, 0, 0, 0, 2, EncodeIndefiniteLengthMapStart(), EncodeStop(), 0}; 1280 TypeParam msg(bytes.begin(), bytes.end()); 1281 Status status = 1282 AppendString8EntryToCBORMap(SpanFrom("key"), SpanFrom("value"), &msg); 1283 EXPECT_EQ(Error::CBOR_INVALID_ENVELOPE, status.error); 1284 EXPECT_EQ(0u, status.pos); 1285 } 1286 { // Second byte is wrong. 1287 std::vector<uint8_t> bytes = { 1288 0xd8, 0x7a, 0, 0, 0, 2, EncodeIndefiniteLengthMapStart(), EncodeStop()}; 1289 TypeParam msg(bytes.begin(), bytes.end()); 1290 Status status = 1291 AppendString8EntryToCBORMap(SpanFrom("key"), SpanFrom("value"), &msg); 1292 EXPECT_EQ(Error::CBOR_INVALID_ENVELOPE, status.error); 1293 EXPECT_EQ(0u, status.pos); 1294 } 1295 { // Invalid envelope size example. 1296 std::vector<uint8_t> bytes = { 1297 0xd8, 0x5a, 0, 0, 0, 3, EncodeIndefiniteLengthMapStart(), EncodeStop(), 1298 }; 1299 TypeParam msg(bytes.begin(), bytes.end()); 1300 Status status = 1301 AppendString8EntryToCBORMap(SpanFrom("key"), SpanFrom("value"), &msg); 1302 EXPECT_EQ(Error::CBOR_INVALID_ENVELOPE, status.error); 1303 EXPECT_EQ(0u, status.pos); 1304 } 1305 { // Invalid envelope size example. 1306 std::vector<uint8_t> bytes = { 1307 0xd8, 0x5a, 0, 0, 0, 1, EncodeIndefiniteLengthMapStart(), EncodeStop(), 1308 }; 1309 TypeParam msg(bytes.begin(), bytes.end()); 1310 Status status = 1311 AppendString8EntryToCBORMap(SpanFrom("key"), SpanFrom("value"), &msg); 1312 EXPECT_EQ(Error::CBOR_INVALID_ENVELOPE, status.error); 1313 EXPECT_EQ(0u, status.pos); 1314 } 1315} 1316} // namespace cbor 1317 1318namespace json { 1319 1320// ============================================================================= 1321// json::NewJSONEncoder - for encoding streaming parser events as JSON 1322// ============================================================================= 1323 1324void WriteUTF8AsUTF16(StreamingParserHandler* writer, const std::string& utf8) { 1325 writer->HandleString16(SpanFrom(UTF8ToUTF16(SpanFrom(utf8)))); 1326} 1327 1328TEST(JsonStdStringWriterTest, HelloWorld) { 1329 std::string out; 1330 Status status; 1331 std::unique_ptr<StreamingParserHandler> writer = 1332 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1333 writer->HandleMapBegin(); 1334 WriteUTF8AsUTF16(writer.get(), "msg1"); 1335 WriteUTF8AsUTF16(writer.get(), "Hello, ."); 1336 std::string key = "msg1-as-utf8"; 1337 std::string value = "Hello, ."; 1338 writer->HandleString8(SpanFrom(key)); 1339 writer->HandleString8(SpanFrom(value)); 1340 WriteUTF8AsUTF16(writer.get(), "msg2"); 1341 WriteUTF8AsUTF16(writer.get(), "\\\b\r\n\t\f\""); 1342 WriteUTF8AsUTF16(writer.get(), "nested"); 1343 writer->HandleMapBegin(); 1344 WriteUTF8AsUTF16(writer.get(), "double"); 1345 writer->HandleDouble(3.1415); 1346 WriteUTF8AsUTF16(writer.get(), "int"); 1347 writer->HandleInt32(-42); 1348 WriteUTF8AsUTF16(writer.get(), "bool"); 1349 writer->HandleBool(false); 1350 WriteUTF8AsUTF16(writer.get(), "null"); 1351 writer->HandleNull(); 1352 writer->HandleMapEnd(); 1353 WriteUTF8AsUTF16(writer.get(), "array"); 1354 writer->HandleArrayBegin(); 1355 writer->HandleInt32(1); 1356 writer->HandleInt32(2); 1357 writer->HandleInt32(3); 1358 writer->HandleArrayEnd(); 1359 writer->HandleMapEnd(); 1360 EXPECT_TRUE(status.ok()); 1361 EXPECT_EQ( 1362 "{\"msg1\":\"Hello, \\ud83c\\udf0e.\"," 1363 "\"msg1-as-utf8\":\"Hello, \\ud83c\\udf0e.\"," 1364 "\"msg2\":\"\\\\\\b\\r\\n\\t\\f\\\"\"," 1365 "\"nested\":{\"double\":3.1415,\"int\":-42," 1366 "\"bool\":false,\"null\":null},\"array\":[1,2,3]}", 1367 out); 1368} 1369 1370TEST(JsonStdStringWriterTest, RepresentingNonFiniteValuesAsNull) { 1371 // JSON can't represent +Infinity, -Infinity, or NaN. 1372 // So in practice it's mapped to null. 1373 std::string out; 1374 Status status; 1375 std::unique_ptr<StreamingParserHandler> writer = 1376 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1377 writer->HandleMapBegin(); 1378 writer->HandleString8(SpanFrom("Infinity")); 1379 writer->HandleDouble(std::numeric_limits<double>::infinity()); 1380 writer->HandleString8(SpanFrom("-Infinity")); 1381 writer->HandleDouble(-std::numeric_limits<double>::infinity()); 1382 writer->HandleString8(SpanFrom("NaN")); 1383 writer->HandleDouble(std::numeric_limits<double>::quiet_NaN()); 1384 writer->HandleMapEnd(); 1385 EXPECT_TRUE(status.ok()); 1386 EXPECT_EQ("{\"Infinity\":null,\"-Infinity\":null,\"NaN\":null}", out); 1387} 1388 1389TEST(JsonStdStringWriterTest, BinaryEncodedAsJsonString) { 1390 // The encoder emits binary submitted to StreamingParserHandler::HandleBinary 1391 // as base64. The following three examples are taken from 1392 // https://en.wikipedia.org/wiki/Base64. 1393 { 1394 std::string out; 1395 Status status; 1396 std::unique_ptr<StreamingParserHandler> writer = 1397 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1398 writer->HandleBinary(SpanFrom(std::vector<uint8_t>({'M', 'a', 'n'}))); 1399 EXPECT_TRUE(status.ok()); 1400 EXPECT_EQ("\"TWFu\"", out); 1401 } 1402 { 1403 std::string out; 1404 Status status; 1405 std::unique_ptr<StreamingParserHandler> writer = 1406 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1407 writer->HandleBinary(SpanFrom(std::vector<uint8_t>({'M', 'a'}))); 1408 EXPECT_TRUE(status.ok()); 1409 EXPECT_EQ("\"TWE=\"", out); 1410 } 1411 { 1412 std::string out; 1413 Status status; 1414 std::unique_ptr<StreamingParserHandler> writer = 1415 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1416 writer->HandleBinary(SpanFrom(std::vector<uint8_t>({'M'}))); 1417 EXPECT_TRUE(status.ok()); 1418 EXPECT_EQ("\"TQ==\"", out); 1419 } 1420 { // "Hello, world.", verified with base64decode.org. 1421 std::string out; 1422 Status status; 1423 std::unique_ptr<StreamingParserHandler> writer = 1424 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1425 writer->HandleBinary(SpanFrom(std::vector<uint8_t>( 1426 {'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.'}))); 1427 EXPECT_TRUE(status.ok()); 1428 EXPECT_EQ("\"SGVsbG8sIHdvcmxkLg==\"", out); 1429 } 1430} 1431 1432TEST(JsonStdStringWriterTest, HandlesErrors) { 1433 // When an error is sent via HandleError, it saves it in the provided 1434 // status and clears the output. 1435 std::string out; 1436 Status status; 1437 std::unique_ptr<StreamingParserHandler> writer = 1438 NewJSONEncoder(&GetTestPlatform(), &out, &status); 1439 writer->HandleMapBegin(); 1440 WriteUTF8AsUTF16(writer.get(), "msg1"); 1441 writer->HandleError(Status{Error::JSON_PARSER_VALUE_EXPECTED, 42}); 1442 EXPECT_EQ(Error::JSON_PARSER_VALUE_EXPECTED, status.error); 1443 EXPECT_EQ(42u, status.pos); 1444 EXPECT_EQ("", out); 1445} 1446 1447// We'd use Gmock but unfortunately it only handles copyable return types. 1448class MockPlatform : public Platform { 1449 public: 1450 // Not implemented. 1451 bool StrToD(const char* str, double* result) const override { return false; } 1452 1453 // A map with pre-registered responses for DToSTr. 1454 std::map<double, std::string> dtostr_responses_; 1455 1456 std::unique_ptr<char[]> DToStr(double value) const override { 1457 auto it = dtostr_responses_.find(value); 1458 CHECK(it != dtostr_responses_.end()); 1459 const std::string& str = it->second; 1460 std::unique_ptr<char[]> response(new char[str.size() + 1]); 1461 memcpy(response.get(), str.c_str(), str.size() + 1); 1462 return response; 1463 } 1464}; 1465 1466TEST(JsonStdStringWriterTest, DoubleToString) { 1467 // This "broken" platform responds without the leading 0 before the 1468 // decimal dot, so it'd be invalid JSON. 1469 MockPlatform platform; 1470 platform.dtostr_responses_[.1] = ".1"; 1471 platform.dtostr_responses_[-.7] = "-.7"; 1472 1473 std::string out; 1474 Status status; 1475 std::unique_ptr<StreamingParserHandler> writer = 1476 NewJSONEncoder(&platform, &out, &status); 1477 writer->HandleArrayBegin(); 1478 writer->HandleDouble(.1); 1479 writer->HandleDouble(-.7); 1480 writer->HandleArrayEnd(); 1481 EXPECT_EQ("[0.1,-0.7]", out); 1482} 1483 1484// ============================================================================= 1485// json::ParseJSON - for receiving streaming parser events for JSON 1486// ============================================================================= 1487 1488class Log : public StreamingParserHandler { 1489 public: 1490 void HandleMapBegin() override { log_ << "map begin\n"; } 1491 1492 void HandleMapEnd() override { log_ << "map end\n"; } 1493 1494 void HandleArrayBegin() override { log_ << "array begin\n"; } 1495 1496 void HandleArrayEnd() override { log_ << "array end\n"; } 1497 1498 void HandleString8(span<uint8_t> chars) override { 1499 log_ << "string8: " << std::string(chars.begin(), chars.end()) << "\n"; 1500 } 1501 1502 void HandleString16(span<uint16_t> chars) override { 1503 log_ << "string16: " << UTF16ToUTF8(chars) << "\n"; 1504 } 1505 1506 void HandleBinary(span<uint8_t> bytes) override { 1507 // JSON doesn't have native support for arbitrary bytes, so our parser will 1508 // never call this. 1509 CHECK(false); 1510 } 1511 1512 void HandleDouble(double value) override { 1513 log_ << "double: " << value << "\n"; 1514 } 1515 1516 void HandleInt32(int32_t value) override { log_ << "int: " << value << "\n"; } 1517 1518 void HandleBool(bool value) override { log_ << "bool: " << value << "\n"; } 1519 1520 void HandleNull() override { log_ << "null\n"; } 1521 1522 void HandleError(Status status) override { status_ = status; } 1523 1524 std::string str() const { return status_.ok() ? log_.str() : ""; } 1525 1526 Status status() const { return status_; } 1527 1528 private: 1529 std::ostringstream log_; 1530 Status status_; 1531}; 1532 1533class JsonParserTest : public ::testing::Test { 1534 protected: 1535 Log log_; 1536}; 1537 1538TEST_F(JsonParserTest, SimpleDictionary) { 1539 std::string json = "{\"foo\": 42}"; 1540 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1541 EXPECT_TRUE(log_.status().ok()); 1542 EXPECT_EQ( 1543 "map begin\n" 1544 "string16: foo\n" 1545 "int: 42\n" 1546 "map end\n", 1547 log_.str()); 1548} 1549 1550TEST_F(JsonParserTest, UsAsciiDelCornerCase) { 1551 // DEL (0x7f) is a 7 bit US-ASCII character, and while it is a control 1552 // character according to Unicode, it's not considered a control 1553 // character in https://tools.ietf.org/html/rfc7159#section-7, so 1554 // it can be placed directly into the JSON string, without JSON escaping. 1555 std::string json = "{\"foo\": \"a\x7f\"}"; 1556 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1557 EXPECT_TRUE(log_.status().ok()); 1558 EXPECT_EQ( 1559 "map begin\n" 1560 "string16: foo\n" 1561 "string16: a\x7f\n" 1562 "map end\n", 1563 log_.str()); 1564} 1565 1566TEST_F(JsonParserTest, Whitespace) { 1567 std::string json = "\n {\n\"msg\"\n: \v\"Hello, world.\"\t\r}\t"; 1568 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1569 EXPECT_TRUE(log_.status().ok()); 1570 EXPECT_EQ( 1571 "map begin\n" 1572 "string16: msg\n" 1573 "string16: Hello, world.\n" 1574 "map end\n", 1575 log_.str()); 1576} 1577 1578TEST_F(JsonParserTest, NestedDictionary) { 1579 std::string json = "{\"foo\": {\"bar\": {\"baz\": 1}, \"bar2\": 2}}"; 1580 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1581 EXPECT_TRUE(log_.status().ok()); 1582 EXPECT_EQ( 1583 "map begin\n" 1584 "string16: foo\n" 1585 "map begin\n" 1586 "string16: bar\n" 1587 "map begin\n" 1588 "string16: baz\n" 1589 "int: 1\n" 1590 "map end\n" 1591 "string16: bar2\n" 1592 "int: 2\n" 1593 "map end\n" 1594 "map end\n", 1595 log_.str()); 1596} 1597 1598TEST_F(JsonParserTest, Doubles) { 1599 std::string json = "{\"foo\": 3.1415, \"bar\": 31415e-4}"; 1600 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1601 EXPECT_TRUE(log_.status().ok()); 1602 EXPECT_EQ( 1603 "map begin\n" 1604 "string16: foo\n" 1605 "double: 3.1415\n" 1606 "string16: bar\n" 1607 "double: 3.1415\n" 1608 "map end\n", 1609 log_.str()); 1610} 1611 1612TEST_F(JsonParserTest, Unicode) { 1613 // Globe character. 0xF0 0x9F 0x8C 0x8E in utf8, 0xD83C 0xDF0E in utf16. 1614 std::string json = "{\"msg\": \"Hello, \\uD83C\\uDF0E.\"}"; 1615 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1616 EXPECT_TRUE(log_.status().ok()); 1617 EXPECT_EQ( 1618 "map begin\n" 1619 "string16: msg\n" 1620 "string16: Hello, .\n" 1621 "map end\n", 1622 log_.str()); 1623} 1624 1625TEST_F(JsonParserTest, Unicode_ParseUtf16) { 1626 // Globe character. utf8: 0xF0 0x9F 0x8C 0x8E; utf16: 0xD83C 0xDF0E. 1627 // Crescent moon character. utf8: 0xF0 0x9F 0x8C 0x99; utf16: 0xD83C 0xDF19. 1628 1629 // We provide the moon with json escape, but the earth as utf16 input. 1630 // Either way they arrive as utf8 (after decoding in log_.str()). 1631 std::vector<uint16_t> json = 1632 UTF8ToUTF16(SpanFrom("{\"space\": \" \\uD83C\\uDF19.\"}")); 1633 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1634 EXPECT_TRUE(log_.status().ok()); 1635 EXPECT_EQ( 1636 "map begin\n" 1637 "string16: space\n" 1638 "string16: .\n" 1639 "map end\n", 1640 log_.str()); 1641} 1642 1643TEST_F(JsonParserTest, Unicode_ParseUtf8) { 1644 // Used below: 1645 // гласность - example for 2 byte utf8, Russian word "glasnost" 1646 // 屋 - example for 3 byte utf8, Chinese word for "house" 1647 // - example for 4 byte utf8: 0xF0 0x9F 0x8C 0x8E; utf16: 0xD83C 0xDF0E. 1648 // - example for escapes: utf8: 0xF0 0x9F 0x8C 0x99; utf16: 0xD83C 0xDF19. 1649 1650 // We provide the moon with json escape, but the earth as utf8 input. 1651 // Either way they arrive as utf8 (after decoding in log_.str()). 1652 std::string json = 1653 "{" 1654 "\"escapes\": \"\\uD83C\\uDF19\"," 1655 "\"2 byte\":\"гласность\"," 1656 "\"3 byte\":\"屋\"," 1657 "\"4 byte\":\"\"" 1658 "}"; 1659 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1660 EXPECT_TRUE(log_.status().ok()); 1661 EXPECT_EQ( 1662 "map begin\n" 1663 "string16: escapes\n" 1664 "string16: \n" 1665 "string16: 2 byte\n" 1666 "string16: гласность\n" 1667 "string16: 3 byte\n" 1668 "string16: 屋\n" 1669 "string16: 4 byte\n" 1670 "string16: \n" 1671 "map end\n", 1672 log_.str()); 1673} 1674 1675TEST_F(JsonParserTest, UnprocessedInputRemainsError) { 1676 // Trailing junk after the valid JSON. 1677 std::string json = "{\"foo\": 3.1415} junk"; 1678 size_t junk_idx = json.find("junk"); 1679 EXPECT_NE(junk_idx, std::string::npos); 1680 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1681 EXPECT_EQ(Error::JSON_PARSER_UNPROCESSED_INPUT_REMAINS, log_.status().error); 1682 EXPECT_EQ(junk_idx, log_.status().pos); 1683 EXPECT_EQ("", log_.str()); 1684} 1685 1686std::string MakeNestedJson(int depth) { 1687 std::string json; 1688 for (int ii = 0; ii < depth; ++ii) 1689 json += "{\"foo\":"; 1690 json += "42"; 1691 for (int ii = 0; ii < depth; ++ii) 1692 json += "}"; 1693 return json; 1694} 1695 1696TEST_F(JsonParserTest, StackLimitExceededError_BelowLimit) { 1697 // kStackLimit is 300 (see json_parser.cc). First let's 1698 // try with a small nested example. 1699 std::string json_3 = MakeNestedJson(3); 1700 ParseJSON(GetTestPlatform(), SpanFrom(json_3), &log_); 1701 EXPECT_TRUE(log_.status().ok()); 1702 EXPECT_EQ( 1703 "map begin\n" 1704 "string16: foo\n" 1705 "map begin\n" 1706 "string16: foo\n" 1707 "map begin\n" 1708 "string16: foo\n" 1709 "int: 42\n" 1710 "map end\n" 1711 "map end\n" 1712 "map end\n", 1713 log_.str()); 1714} 1715 1716TEST_F(JsonParserTest, StackLimitExceededError_AtLimit) { 1717 // Now with kStackLimit (300). 1718 std::string json_limit = MakeNestedJson(300); 1719 ParseJSON(GetTestPlatform(), 1720 span<uint8_t>(reinterpret_cast<const uint8_t*>(json_limit.data()), 1721 json_limit.size()), 1722 &log_); 1723 EXPECT_TRUE(log_.status().ok()); 1724} 1725 1726TEST_F(JsonParserTest, StackLimitExceededError_AboveLimit) { 1727 // Now with kStackLimit + 1 (301) - it exceeds in the innermost instance. 1728 std::string exceeded = MakeNestedJson(301); 1729 ParseJSON(GetTestPlatform(), SpanFrom(exceeded), &log_); 1730 EXPECT_EQ(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, log_.status().error); 1731 EXPECT_EQ(strlen("{\"foo\":") * 301, log_.status().pos); 1732} 1733 1734TEST_F(JsonParserTest, StackLimitExceededError_WayAboveLimit) { 1735 // Now way past the limit. Still, the point of exceeding is 301. 1736 std::string far_out = MakeNestedJson(320); 1737 ParseJSON(GetTestPlatform(), SpanFrom(far_out), &log_); 1738 EXPECT_EQ(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, log_.status().error); 1739 EXPECT_EQ(strlen("{\"foo\":") * 301, log_.status().pos); 1740} 1741 1742TEST_F(JsonParserTest, NoInputError) { 1743 std::string json = ""; 1744 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1745 EXPECT_EQ(Error::JSON_PARSER_NO_INPUT, log_.status().error); 1746 EXPECT_EQ(0u, log_.status().pos); 1747 EXPECT_EQ("", log_.str()); 1748} 1749 1750TEST_F(JsonParserTest, InvalidTokenError) { 1751 std::string json = "|"; 1752 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1753 EXPECT_EQ(Error::JSON_PARSER_INVALID_TOKEN, log_.status().error); 1754 EXPECT_EQ(0u, log_.status().pos); 1755 EXPECT_EQ("", log_.str()); 1756} 1757 1758TEST_F(JsonParserTest, InvalidNumberError) { 1759 // Mantissa exceeds max (the constant used here is int64_t max). 1760 std::string json = "1E9223372036854775807"; 1761 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1762 EXPECT_EQ(Error::JSON_PARSER_INVALID_NUMBER, log_.status().error); 1763 EXPECT_EQ(0u, log_.status().pos); 1764 EXPECT_EQ("", log_.str()); 1765} 1766 1767TEST_F(JsonParserTest, InvalidStringError) { 1768 // \x22 is an unsupported escape sequence 1769 std::string json = "\"foo\\x22\""; 1770 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1771 EXPECT_EQ(Error::JSON_PARSER_INVALID_STRING, log_.status().error); 1772 EXPECT_EQ(0u, log_.status().pos); 1773 EXPECT_EQ("", log_.str()); 1774} 1775 1776TEST_F(JsonParserTest, UnexpectedArrayEndError) { 1777 std::string json = "[1,2,]"; 1778 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1779 EXPECT_EQ(Error::JSON_PARSER_UNEXPECTED_ARRAY_END, log_.status().error); 1780 EXPECT_EQ(5u, log_.status().pos); 1781 EXPECT_EQ("", log_.str()); 1782} 1783 1784TEST_F(JsonParserTest, CommaOrArrayEndExpectedError) { 1785 std::string json = "[1,2 2"; 1786 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1787 EXPECT_EQ(Error::JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED, 1788 log_.status().error); 1789 EXPECT_EQ(5u, log_.status().pos); 1790 EXPECT_EQ("", log_.str()); 1791} 1792 1793TEST_F(JsonParserTest, StringLiteralExpectedError) { 1794 // There's an error because the key bar, a string, is not terminated. 1795 std::string json = "{\"foo\": 3.1415, \"bar: 31415e-4}"; 1796 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1797 EXPECT_EQ(Error::JSON_PARSER_STRING_LITERAL_EXPECTED, log_.status().error); 1798 EXPECT_EQ(16u, log_.status().pos); 1799 EXPECT_EQ("", log_.str()); 1800} 1801 1802TEST_F(JsonParserTest, ColonExpectedError) { 1803 std::string json = "{\"foo\", 42}"; 1804 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1805 EXPECT_EQ(Error::JSON_PARSER_COLON_EXPECTED, log_.status().error); 1806 EXPECT_EQ(6u, log_.status().pos); 1807 EXPECT_EQ("", log_.str()); 1808} 1809 1810TEST_F(JsonParserTest, UnexpectedMapEndError) { 1811 std::string json = "{\"foo\": 42, }"; 1812 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1813 EXPECT_EQ(Error::JSON_PARSER_UNEXPECTED_MAP_END, log_.status().error); 1814 EXPECT_EQ(12u, log_.status().pos); 1815 EXPECT_EQ("", log_.str()); 1816} 1817 1818TEST_F(JsonParserTest, CommaOrMapEndExpectedError) { 1819 // The second separator should be a comma. 1820 std::string json = "{\"foo\": 3.1415: \"bar\": 0}"; 1821 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1822 EXPECT_EQ(Error::JSON_PARSER_COMMA_OR_MAP_END_EXPECTED, log_.status().error); 1823 EXPECT_EQ(14u, log_.status().pos); 1824 EXPECT_EQ("", log_.str()); 1825} 1826 1827TEST_F(JsonParserTest, ValueExpectedError) { 1828 std::string json = "}"; 1829 ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); 1830 EXPECT_EQ(Error::JSON_PARSER_VALUE_EXPECTED, log_.status().error); 1831 EXPECT_EQ(0u, log_.status().pos); 1832 EXPECT_EQ("", log_.str()); 1833} 1834 1835template <typename T> 1836class ConvertJSONToCBORTest : public ::testing::Test {}; 1837 1838using ContainerTestTypes = ::testing::Types<std::vector<uint8_t>, std::string>; 1839TYPED_TEST_SUITE(ConvertJSONToCBORTest, ContainerTestTypes); 1840 1841TYPED_TEST(ConvertJSONToCBORTest, RoundTripValidJson) { 1842 std::string json_in = "{\"msg\":\"Hello, world.\",\"lst\":[1,2,3]}"; 1843 TypeParam json(json_in.begin(), json_in.end()); 1844 TypeParam cbor; 1845 { 1846 Status status = ConvertJSONToCBOR(GetTestPlatform(), SpanFrom(json), &cbor); 1847 EXPECT_EQ(Error::OK, status.error); 1848 EXPECT_EQ(Status::npos(), status.pos); 1849 } 1850 TypeParam roundtrip_json; 1851 { 1852 Status status = 1853 ConvertCBORToJSON(GetTestPlatform(), SpanFrom(cbor), &roundtrip_json); 1854 EXPECT_EQ(Error::OK, status.error); 1855 EXPECT_EQ(Status::npos(), status.pos); 1856 } 1857 EXPECT_EQ(json, roundtrip_json); 1858} 1859 1860TYPED_TEST(ConvertJSONToCBORTest, RoundTripValidJson16) { 1861 std::vector<uint16_t> json16 = { 1862 '{', '"', 'm', 's', 'g', '"', ':', '"', 'H', 'e', 'l', 'l', 1863 'o', ',', ' ', 0xd83c, 0xdf0e, '.', '"', ',', '"', 'l', 's', 't', 1864 '"', ':', '[', '1', ',', '2', ',', '3', ']', '}'}; 1865 TypeParam cbor; 1866 { 1867 Status status = ConvertJSONToCBOR( 1868 GetTestPlatform(), span<uint16_t>(json16.data(), json16.size()), &cbor); 1869 EXPECT_EQ(Error::OK, status.error); 1870 EXPECT_EQ(Status::npos(), status.pos); 1871 } 1872 TypeParam roundtrip_json; 1873 { 1874 Status status = 1875 ConvertCBORToJSON(GetTestPlatform(), SpanFrom(cbor), &roundtrip_json); 1876 EXPECT_EQ(Error::OK, status.error); 1877 EXPECT_EQ(Status::npos(), status.pos); 1878 } 1879 std::string json = "{\"msg\":\"Hello, \\ud83c\\udf0e.\",\"lst\":[1,2,3]}"; 1880 TypeParam expected_json(json.begin(), json.end()); 1881 EXPECT_EQ(expected_json, roundtrip_json); 1882} 1883} // namespace json 1884} // namespace v8_inspector_protocol_encoding 1885