1 //===- llvm/unittest/Support/BinaryStreamTest.cpp -------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/Support/BinaryByteStream.h" 11 #include "llvm/Support/BinaryItemStream.h" 12 #include "llvm/Support/BinaryStreamArray.h" 13 #include "llvm/Support/BinaryStreamReader.h" 14 #include "llvm/Support/BinaryStreamRef.h" 15 #include "llvm/Support/BinaryStreamWriter.h" 16 #include "gtest/gtest.h" 17 18 #include <unordered_map> 19 #include <utility> 20 21 using namespace llvm; 22 using namespace llvm::support; 23 24 #define EXPECT_NO_ERROR(Err) \ 25 { \ 26 auto E = Err; \ 27 EXPECT_FALSE(static_cast<bool>(E)); \ 28 if (E) \ 29 consumeError(std::move(E)); \ 30 } 31 32 #define ASSERT_NO_ERROR(Err) \ 33 { \ 34 auto E = Err; \ 35 ASSERT_FALSE(static_cast<bool>(E)); \ 36 if (E) \ 37 consumeError(std::move(E)); \ 38 } 39 40 #define EXPECT_ERROR(Err) \ 41 { \ 42 auto E = Err; \ 43 EXPECT_TRUE(static_cast<bool>(E)); \ 44 if (E) \ 45 consumeError(std::move(E)); \ 46 } 47 48 namespace { 49 50 class BrokenStream : public WritableBinaryStream { 51 public: 52 BrokenStream(MutableArrayRef<uint8_t> Data, endianness Endian, 53 uint32_t Align) 54 : Data(Data), PartitionIndex(alignDown(Data.size() / 2, Align)), 55 Endian(Endian) {} 56 57 endianness getEndian() const override { return Endian; } 58 59 Error readBytes(uint32_t Offset, uint32_t Size, 60 ArrayRef<uint8_t> &Buffer) override { 61 if (auto EC = checkOffset(Offset, Size)) 62 return EC; 63 uint32_t S = startIndex(Offset); 64 auto Ref = Data.drop_front(S); 65 if (Ref.size() >= Size) { 66 Buffer = Ref.take_front(Size); 67 return Error::success(); 68 } 69 70 uint32_t BytesLeft = Size - Ref.size(); 71 uint8_t *Ptr = Allocator.Allocate<uint8_t>(Size); 72 ::memcpy(Ptr, Ref.data(), Ref.size()); 73 ::memcpy(Ptr + Ref.size(), Data.data(), BytesLeft); 74 Buffer = makeArrayRef<uint8_t>(Ptr, Size); 75 return Error::success(); 76 } 77 78 Error readLongestContiguousChunk(uint32_t Offset, 79 ArrayRef<uint8_t> &Buffer) override { 80 if (auto EC = checkOffset(Offset, 1)) 81 return EC; 82 uint32_t S = startIndex(Offset); 83 Buffer = Data.drop_front(S); 84 return Error::success(); 85 } 86 87 uint32_t getLength() override { return Data.size(); } 88 89 Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> SrcData) override { 90 if (auto EC = checkOffset(Offset, SrcData.size())) 91 return EC; 92 if (SrcData.empty()) 93 return Error::success(); 94 95 uint32_t S = startIndex(Offset); 96 MutableArrayRef<uint8_t> Ref(Data); 97 Ref = Ref.drop_front(S); 98 if (Ref.size() >= SrcData.size()) { 99 ::memcpy(Ref.data(), SrcData.data(), SrcData.size()); 100 return Error::success(); 101 } 102 103 uint32_t BytesLeft = SrcData.size() - Ref.size(); 104 ::memcpy(Ref.data(), SrcData.data(), Ref.size()); 105 ::memcpy(&Data[0], SrcData.data() + Ref.size(), BytesLeft); 106 return Error::success(); 107 } 108 Error commit() override { return Error::success(); } 109 110 private: 111 uint32_t startIndex(uint32_t Offset) const { 112 return (Offset + PartitionIndex) % Data.size(); 113 } 114 115 uint32_t endIndex(uint32_t Offset, uint32_t Size) const { 116 return (startIndex(Offset) + Size - 1) % Data.size(); 117 } 118 119 // Buffer is organized like this: 120 // ------------------------------------------------- 121 // | N/2 | N/2+1 | ... | N-1 | 0 | 1 | ... | N/2-1 | 122 // ------------------------------------------------- 123 // So reads from the beginning actually come from the middle. 124 MutableArrayRef<uint8_t> Data; 125 uint32_t PartitionIndex = 0; 126 endianness Endian; 127 BumpPtrAllocator Allocator; 128 }; 129 130 constexpr endianness Endians[] = {big, little, native}; 131 constexpr uint32_t NumEndians = llvm::array_lengthof(Endians); 132 constexpr uint32_t NumStreams = 2 * NumEndians; 133 134 class BinaryStreamTest : public testing::Test { 135 136 public: 137 BinaryStreamTest() {} 138 139 void SetUp() override { 140 Streams.clear(); 141 Streams.resize(NumStreams); 142 for (uint32_t I = 0; I < NumStreams; ++I) 143 Streams[I].IsContiguous = (I % 2 == 0); 144 145 InputData.clear(); 146 OutputData.clear(); 147 } 148 149 protected: 150 struct StreamPair { 151 bool IsContiguous; 152 std::unique_ptr<BinaryStream> Input; 153 std::unique_ptr<WritableBinaryStream> Output; 154 }; 155 156 void initializeInput(ArrayRef<uint8_t> Input, uint32_t Align) { 157 InputData = Input; 158 159 BrokenInputData.resize(InputData.size()); 160 if (!Input.empty()) { 161 uint32_t PartitionIndex = alignDown(InputData.size() / 2, Align); 162 uint32_t RightBytes = InputData.size() - PartitionIndex; 163 uint32_t LeftBytes = PartitionIndex; 164 if (RightBytes > 0) 165 ::memcpy(&BrokenInputData[PartitionIndex], Input.data(), RightBytes); 166 if (LeftBytes > 0) 167 ::memcpy(&BrokenInputData[0], Input.data() + RightBytes, LeftBytes); 168 } 169 170 for (uint32_t I = 0; I < NumEndians; ++I) { 171 auto InByteStream = 172 llvm::make_unique<BinaryByteStream>(InputData, Endians[I]); 173 auto InBrokenStream = llvm::make_unique<BrokenStream>( 174 BrokenInputData, Endians[I], Align); 175 176 Streams[I * 2].Input = std::move(InByteStream); 177 Streams[I * 2 + 1].Input = std::move(InBrokenStream); 178 } 179 } 180 181 void initializeOutput(uint32_t Size, uint32_t Align) { 182 OutputData.resize(Size); 183 BrokenOutputData.resize(Size); 184 185 for (uint32_t I = 0; I < NumEndians; ++I) { 186 Streams[I * 2].Output = 187 llvm::make_unique<MutableBinaryByteStream>(OutputData, Endians[I]); 188 Streams[I * 2 + 1].Output = llvm::make_unique<BrokenStream>( 189 BrokenOutputData, Endians[I], Align); 190 } 191 } 192 193 void initializeOutputFromInput(uint32_t Align) { 194 for (uint32_t I = 0; I < NumEndians; ++I) { 195 Streams[I * 2].Output = 196 llvm::make_unique<MutableBinaryByteStream>(InputData, Endians[I]); 197 Streams[I * 2 + 1].Output = llvm::make_unique<BrokenStream>( 198 BrokenInputData, Endians[I], Align); 199 } 200 } 201 202 void initializeInputFromOutput(uint32_t Align) { 203 for (uint32_t I = 0; I < NumEndians; ++I) { 204 Streams[I * 2].Input = 205 llvm::make_unique<BinaryByteStream>(OutputData, Endians[I]); 206 Streams[I * 2 + 1].Input = llvm::make_unique<BrokenStream>( 207 BrokenOutputData, Endians[I], Align); 208 } 209 } 210 211 std::vector<uint8_t> InputData; 212 std::vector<uint8_t> BrokenInputData; 213 214 std::vector<uint8_t> OutputData; 215 std::vector<uint8_t> BrokenOutputData; 216 217 std::vector<StreamPair> Streams; 218 }; 219 220 // Tests that a we can read from a BinaryByteStream without a StreamReader. 221 TEST_F(BinaryStreamTest, BinaryByteStreamBounds) { 222 std::vector<uint8_t> InputData = {1, 2, 3, 4, 5}; 223 initializeInput(InputData, 1); 224 225 for (auto &Stream : Streams) { 226 ArrayRef<uint8_t> Buffer; 227 228 // 1. If the read fits it should work. 229 ASSERT_EQ(InputData.size(), Stream.Input->getLength()); 230 ASSERT_NO_ERROR(Stream.Input->readBytes(2, 1, Buffer)); 231 EXPECT_EQ(makeArrayRef(InputData).slice(2, 1), Buffer); 232 ASSERT_NO_ERROR(Stream.Input->readBytes(0, 4, Buffer)); 233 EXPECT_EQ(makeArrayRef(InputData).slice(0, 4), Buffer); 234 235 // 2. Reading past the bounds of the input should fail. 236 EXPECT_ERROR(Stream.Input->readBytes(4, 2, Buffer)); 237 } 238 } 239 240 TEST_F(BinaryStreamTest, StreamRefBounds) { 241 std::vector<uint8_t> InputData = {1, 2, 3, 4, 5}; 242 initializeInput(InputData, 1); 243 244 for (const auto &Stream : Streams) { 245 ArrayRef<uint8_t> Buffer; 246 BinaryStreamRef Ref(*Stream.Input); 247 248 // Read 1 byte from offset 2 should work 249 ASSERT_EQ(InputData.size(), Ref.getLength()); 250 ASSERT_NO_ERROR(Ref.readBytes(2, 1, Buffer)); 251 EXPECT_EQ(makeArrayRef(InputData).slice(2, 1), Buffer); 252 253 // Reading everything from offset 2 on. 254 ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer)); 255 if (Stream.IsContiguous) 256 EXPECT_EQ(makeArrayRef(InputData).slice(2), Buffer); 257 else 258 EXPECT_FALSE(Buffer.empty()); 259 260 // Reading 6 bytes from offset 0 is too big. 261 EXPECT_ERROR(Ref.readBytes(0, 6, Buffer)); 262 EXPECT_ERROR(Ref.readLongestContiguousChunk(6, Buffer)); 263 264 // Reading 1 byte from offset 2 after dropping 1 byte is the same as reading 265 // 1 byte from offset 3. 266 Ref = Ref.drop_front(1); 267 ASSERT_NO_ERROR(Ref.readBytes(2, 1, Buffer)); 268 if (Stream.IsContiguous) 269 EXPECT_EQ(makeArrayRef(InputData).slice(3, 1), Buffer); 270 else 271 EXPECT_FALSE(Buffer.empty()); 272 273 // Reading everything from offset 2 on after dropping 1 byte. 274 ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer)); 275 if (Stream.IsContiguous) 276 EXPECT_EQ(makeArrayRef(InputData).slice(3), Buffer); 277 else 278 EXPECT_FALSE(Buffer.empty()); 279 280 // Reading 2 bytes from offset 2 after dropping 2 bytes is the same as 281 // reading 2 bytes from offset 4, and should fail. 282 Ref = Ref.drop_front(1); 283 EXPECT_ERROR(Ref.readBytes(2, 2, Buffer)); 284 285 // But if we read the longest contiguous chunk instead, we should still 286 // get the 1 byte at the end. 287 ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer)); 288 EXPECT_EQ(makeArrayRef(InputData).take_back(), Buffer); 289 } 290 } 291 292 // Test that we can write to a BinaryStream without a StreamWriter. 293 TEST_F(BinaryStreamTest, MutableBinaryByteStreamBounds) { 294 std::vector<uint8_t> InputData = {'T', 'e', 's', 't', '\0'}; 295 initializeInput(InputData, 1); 296 initializeOutput(InputData.size(), 1); 297 298 // For every combination of input stream and output stream. 299 for (auto &Stream : Streams) { 300 MutableArrayRef<uint8_t> Buffer; 301 ASSERT_EQ(InputData.size(), Stream.Input->getLength()); 302 303 // 1. Try two reads that are supposed to work. One from offset 0, and one 304 // from the middle. 305 uint32_t Offsets[] = {0, 3}; 306 for (auto Offset : Offsets) { 307 uint32_t ExpectedSize = Stream.Input->getLength() - Offset; 308 309 // Read everything from Offset until the end of the input data. 310 ArrayRef<uint8_t> Data; 311 ASSERT_NO_ERROR(Stream.Input->readBytes(Offset, ExpectedSize, Data)); 312 ASSERT_EQ(ExpectedSize, Data.size()); 313 314 // Then write it to the destination. 315 ASSERT_NO_ERROR(Stream.Output->writeBytes(0, Data)); 316 317 // Then we read back what we wrote, it should match the corresponding 318 // slice of the original input data. 319 ArrayRef<uint8_t> Data2; 320 ASSERT_NO_ERROR(Stream.Output->readBytes(Offset, ExpectedSize, Data2)); 321 EXPECT_EQ(makeArrayRef(InputData).drop_front(Offset), Data2); 322 } 323 324 std::vector<uint8_t> BigData = {0, 1, 2, 3, 4}; 325 // 2. If the write is too big, it should fail. 326 EXPECT_ERROR(Stream.Output->writeBytes(3, BigData)); 327 } 328 } 329 330 // Test that FixedStreamArray works correctly. 331 TEST_F(BinaryStreamTest, FixedStreamArray) { 332 std::vector<uint32_t> Ints = {90823, 12908, 109823, 209823}; 333 ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(Ints.data()), 334 Ints.size() * sizeof(uint32_t)); 335 336 initializeInput(IntBytes, alignof(uint32_t)); 337 338 for (auto &Stream : Streams) { 339 MutableArrayRef<uint8_t> Buffer; 340 ASSERT_EQ(InputData.size(), Stream.Input->getLength()); 341 342 FixedStreamArray<uint32_t> Array(*Stream.Input); 343 auto Iter = Array.begin(); 344 ASSERT_EQ(Ints[0], *Iter++); 345 ASSERT_EQ(Ints[1], *Iter++); 346 ASSERT_EQ(Ints[2], *Iter++); 347 ASSERT_EQ(Ints[3], *Iter++); 348 ASSERT_EQ(Array.end(), Iter); 349 } 350 } 351 352 // Ensure FixedStreamArrayIterator::operator-> works. 353 // Added for coverage of r302257. 354 TEST_F(BinaryStreamTest, FixedStreamArrayIteratorArrow) { 355 std::vector<std::pair<uint32_t, uint32_t>> Pairs = {{867, 5309}, {555, 1212}}; 356 ArrayRef<uint8_t> PairBytes(reinterpret_cast<uint8_t *>(Pairs.data()), 357 Pairs.size() * sizeof(Pairs[0])); 358 359 initializeInput(PairBytes, alignof(uint32_t)); 360 361 for (auto &Stream : Streams) { 362 ASSERT_EQ(InputData.size(), Stream.Input->getLength()); 363 364 const FixedStreamArray<std::pair<uint32_t, uint32_t>> Array(*Stream.Input); 365 auto Iter = Array.begin(); 366 ASSERT_EQ(Pairs[0].first, Iter->first); 367 ASSERT_EQ(Pairs[0].second, Iter->second); 368 ++Iter; 369 ASSERT_EQ(Pairs[1].first, Iter->first); 370 ASSERT_EQ(Pairs[1].second, Iter->second); 371 ++Iter; 372 ASSERT_EQ(Array.end(), Iter); 373 } 374 } 375 376 // Test that VarStreamArray works correctly. 377 TEST_F(BinaryStreamTest, VarStreamArray) { 378 StringLiteral Strings("1. Test2. Longer Test3. Really Long Test4. Super " 379 "Extra Longest Test Of All"); 380 ArrayRef<uint8_t> StringBytes( 381 reinterpret_cast<const uint8_t *>(Strings.data()), Strings.size()); 382 initializeInput(StringBytes, 1); 383 384 struct StringExtractor { 385 public: 386 typedef uint32_t &ContextType; 387 static Error extract(BinaryStreamRef Stream, uint32_t &Len, StringRef &Item, 388 uint32_t &Index) { 389 if (Index == 0) 390 Len = strlen("1. Test"); 391 else if (Index == 1) 392 Len = strlen("2. Longer Test"); 393 else if (Index == 2) 394 Len = strlen("3. Really Long Test"); 395 else 396 Len = strlen("4. Super Extra Longest Test Of All"); 397 ArrayRef<uint8_t> Bytes; 398 if (auto EC = Stream.readBytes(0, Len, Bytes)) 399 return EC; 400 Item = 401 StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size()); 402 ++Index; 403 return Error::success(); 404 } 405 }; 406 407 for (auto &Stream : Streams) { 408 uint32_t Context = 0; 409 VarStreamArray<StringRef, StringExtractor> Array(*Stream.Input, Context); 410 auto Iter = Array.begin(); 411 ASSERT_EQ("1. Test", *Iter++); 412 ASSERT_EQ("2. Longer Test", *Iter++); 413 ASSERT_EQ("3. Really Long Test", *Iter++); 414 ASSERT_EQ("4. Super Extra Longest Test Of All", *Iter++); 415 ASSERT_EQ(Array.end(), Iter); 416 } 417 } 418 419 TEST_F(BinaryStreamTest, StreamReaderBounds) { 420 std::vector<uint8_t> Bytes; 421 422 initializeInput(Bytes, 1); 423 for (auto &Stream : Streams) { 424 StringRef S; 425 BinaryStreamReader Reader(*Stream.Input); 426 EXPECT_EQ(0U, Reader.bytesRemaining()); 427 EXPECT_ERROR(Reader.readFixedString(S, 1)); 428 } 429 430 Bytes.resize(5); 431 initializeInput(Bytes, 1); 432 for (auto &Stream : Streams) { 433 StringRef S; 434 BinaryStreamReader Reader(*Stream.Input); 435 EXPECT_EQ(Bytes.size(), Reader.bytesRemaining()); 436 EXPECT_NO_ERROR(Reader.readFixedString(S, 5)); 437 EXPECT_ERROR(Reader.readFixedString(S, 6)); 438 } 439 } 440 441 TEST_F(BinaryStreamTest, StreamReaderIntegers) { 442 support::ulittle64_t Little{908234}; 443 support::ubig32_t Big{28907823}; 444 short NS = 2897; 445 int NI = -89723; 446 unsigned long NUL = 902309023UL; 447 constexpr uint32_t Size = 448 sizeof(Little) + sizeof(Big) + sizeof(NS) + sizeof(NI) + sizeof(NUL); 449 450 initializeOutput(Size, alignof(support::ulittle64_t)); 451 initializeInputFromOutput(alignof(support::ulittle64_t)); 452 453 for (auto &Stream : Streams) { 454 BinaryStreamWriter Writer(*Stream.Output); 455 ASSERT_NO_ERROR(Writer.writeObject(Little)); 456 ASSERT_NO_ERROR(Writer.writeObject(Big)); 457 ASSERT_NO_ERROR(Writer.writeInteger(NS)); 458 ASSERT_NO_ERROR(Writer.writeInteger(NI)); 459 ASSERT_NO_ERROR(Writer.writeInteger(NUL)); 460 461 const support::ulittle64_t *Little2; 462 const support::ubig32_t *Big2; 463 short NS2; 464 int NI2; 465 unsigned long NUL2; 466 467 // 1. Reading fields individually. 468 BinaryStreamReader Reader(*Stream.Input); 469 ASSERT_NO_ERROR(Reader.readObject(Little2)); 470 ASSERT_NO_ERROR(Reader.readObject(Big2)); 471 ASSERT_NO_ERROR(Reader.readInteger(NS2)); 472 ASSERT_NO_ERROR(Reader.readInteger(NI2)); 473 ASSERT_NO_ERROR(Reader.readInteger(NUL2)); 474 ASSERT_EQ(0U, Reader.bytesRemaining()); 475 476 EXPECT_EQ(Little, *Little2); 477 EXPECT_EQ(Big, *Big2); 478 EXPECT_EQ(NS, NS2); 479 EXPECT_EQ(NI, NI2); 480 EXPECT_EQ(NUL, NUL2); 481 } 482 } 483 484 TEST_F(BinaryStreamTest, StreamReaderIntegerArray) { 485 // 1. Arrays of integers 486 std::vector<int> Ints = {1, 2, 3, 4, 5}; 487 ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(&Ints[0]), 488 Ints.size() * sizeof(int)); 489 490 initializeInput(IntBytes, alignof(int)); 491 for (auto &Stream : Streams) { 492 BinaryStreamReader Reader(*Stream.Input); 493 ArrayRef<int> IntsRef; 494 ASSERT_NO_ERROR(Reader.readArray(IntsRef, Ints.size())); 495 ASSERT_EQ(0U, Reader.bytesRemaining()); 496 EXPECT_EQ(makeArrayRef(Ints), IntsRef); 497 498 Reader.setOffset(0); 499 FixedStreamArray<int> FixedIntsRef; 500 ASSERT_NO_ERROR(Reader.readArray(FixedIntsRef, Ints.size())); 501 ASSERT_EQ(0U, Reader.bytesRemaining()); 502 ASSERT_EQ(Ints, std::vector<int>(FixedIntsRef.begin(), FixedIntsRef.end())); 503 } 504 } 505 506 TEST_F(BinaryStreamTest, StreamReaderEnum) { 507 enum class MyEnum : int64_t { Foo = -10, Bar = 0, Baz = 10 }; 508 509 std::vector<MyEnum> Enums = {MyEnum::Bar, MyEnum::Baz, MyEnum::Foo}; 510 511 initializeOutput(Enums.size() * sizeof(MyEnum), alignof(MyEnum)); 512 initializeInputFromOutput(alignof(MyEnum)); 513 for (auto &Stream : Streams) { 514 BinaryStreamWriter Writer(*Stream.Output); 515 for (auto Value : Enums) 516 ASSERT_NO_ERROR(Writer.writeEnum(Value)); 517 518 BinaryStreamReader Reader(*Stream.Input); 519 520 ArrayRef<MyEnum> Array; 521 FixedStreamArray<MyEnum> FSA; 522 523 for (size_t I = 0; I < Enums.size(); ++I) { 524 MyEnum Value; 525 ASSERT_NO_ERROR(Reader.readEnum(Value)); 526 EXPECT_EQ(Enums[I], Value); 527 } 528 ASSERT_EQ(0U, Reader.bytesRemaining()); 529 } 530 } 531 532 TEST_F(BinaryStreamTest, StreamReaderObject) { 533 struct Foo { 534 int X; 535 double Y; 536 char Z; 537 538 bool operator==(const Foo &Other) const { 539 return X == Other.X && Y == Other.Y && Z == Other.Z; 540 } 541 }; 542 543 std::vector<Foo> Foos; 544 Foos.push_back({-42, 42.42, 42}); 545 Foos.push_back({100, 3.1415, static_cast<char>(-89)}); 546 Foos.push_back({200, 2.718, static_cast<char>(-12) }); 547 548 const uint8_t *Bytes = reinterpret_cast<const uint8_t *>(&Foos[0]); 549 550 initializeInput(makeArrayRef(Bytes, 3 * sizeof(Foo)), alignof(Foo)); 551 552 for (auto &Stream : Streams) { 553 // 1. Reading object pointers. 554 BinaryStreamReader Reader(*Stream.Input); 555 const Foo *FPtrOut = nullptr; 556 const Foo *GPtrOut = nullptr; 557 const Foo *HPtrOut = nullptr; 558 ASSERT_NO_ERROR(Reader.readObject(FPtrOut)); 559 ASSERT_NO_ERROR(Reader.readObject(GPtrOut)); 560 ASSERT_NO_ERROR(Reader.readObject(HPtrOut)); 561 EXPECT_EQ(0U, Reader.bytesRemaining()); 562 EXPECT_EQ(Foos[0], *FPtrOut); 563 EXPECT_EQ(Foos[1], *GPtrOut); 564 EXPECT_EQ(Foos[2], *HPtrOut); 565 } 566 } 567 568 TEST_F(BinaryStreamTest, StreamReaderStrings) { 569 std::vector<uint8_t> Bytes = {'O', 'n', 'e', '\0', 'T', 'w', 'o', 570 '\0', 'T', 'h', 'r', 'e', 'e', '\0', 571 'F', 'o', 'u', 'r', '\0'}; 572 initializeInput(Bytes, 1); 573 574 for (auto &Stream : Streams) { 575 BinaryStreamReader Reader(*Stream.Input); 576 577 StringRef S1; 578 StringRef S2; 579 StringRef S3; 580 StringRef S4; 581 ASSERT_NO_ERROR(Reader.readCString(S1)); 582 ASSERT_NO_ERROR(Reader.readCString(S2)); 583 ASSERT_NO_ERROR(Reader.readCString(S3)); 584 ASSERT_NO_ERROR(Reader.readCString(S4)); 585 ASSERT_EQ(0U, Reader.bytesRemaining()); 586 587 EXPECT_EQ("One", S1); 588 EXPECT_EQ("Two", S2); 589 EXPECT_EQ("Three", S3); 590 EXPECT_EQ("Four", S4); 591 592 S1 = S2 = S3 = S4 = ""; 593 Reader.setOffset(0); 594 ASSERT_NO_ERROR(Reader.readFixedString(S1, 3)); 595 ASSERT_NO_ERROR(Reader.skip(1)); 596 ASSERT_NO_ERROR(Reader.readFixedString(S2, 3)); 597 ASSERT_NO_ERROR(Reader.skip(1)); 598 ASSERT_NO_ERROR(Reader.readFixedString(S3, 5)); 599 ASSERT_NO_ERROR(Reader.skip(1)); 600 ASSERT_NO_ERROR(Reader.readFixedString(S4, 4)); 601 ASSERT_NO_ERROR(Reader.skip(1)); 602 ASSERT_EQ(0U, Reader.bytesRemaining()); 603 604 EXPECT_EQ("One", S1); 605 EXPECT_EQ("Two", S2); 606 EXPECT_EQ("Three", S3); 607 EXPECT_EQ("Four", S4); 608 } 609 } 610 611 TEST_F(BinaryStreamTest, StreamWriterBounds) { 612 initializeOutput(5, 1); 613 614 for (auto &Stream : Streams) { 615 BinaryStreamWriter Writer(*Stream.Output); 616 617 // 1. Can write a string that exactly fills the buffer. 618 EXPECT_EQ(5U, Writer.bytesRemaining()); 619 EXPECT_NO_ERROR(Writer.writeFixedString("abcde")); 620 EXPECT_EQ(0U, Writer.bytesRemaining()); 621 622 // 2. Can write an empty string even when you're full 623 EXPECT_NO_ERROR(Writer.writeFixedString("")); 624 EXPECT_ERROR(Writer.writeFixedString("a")); 625 626 // 3. Can't write a string that is one character too long. 627 Writer.setOffset(0); 628 EXPECT_ERROR(Writer.writeFixedString("abcdef")); 629 } 630 } 631 632 TEST_F(BinaryStreamTest, StreamWriterIntegerArrays) { 633 // 3. Arrays of integers 634 std::vector<int> SourceInts = {1, 2, 3, 4, 5}; 635 ArrayRef<uint8_t> SourceBytes(reinterpret_cast<uint8_t *>(&SourceInts[0]), 636 SourceInts.size() * sizeof(int)); 637 638 initializeInput(SourceBytes, alignof(int)); 639 initializeOutputFromInput(alignof(int)); 640 641 for (auto &Stream : Streams) { 642 BinaryStreamReader Reader(*Stream.Input); 643 BinaryStreamWriter Writer(*Stream.Output); 644 ArrayRef<int> Ints; 645 ArrayRef<int> Ints2; 646 // First read them, then write them, then read them back. 647 ASSERT_NO_ERROR(Reader.readArray(Ints, SourceInts.size())); 648 ASSERT_NO_ERROR(Writer.writeArray(Ints)); 649 650 BinaryStreamReader ReaderBacker(*Stream.Output); 651 ASSERT_NO_ERROR(ReaderBacker.readArray(Ints2, SourceInts.size())); 652 653 EXPECT_EQ(makeArrayRef(SourceInts), Ints2); 654 } 655 } 656 657 TEST_F(BinaryStreamTest, StringWriterStrings) { 658 StringRef Strings[] = {"First", "Second", "Third", "Fourth"}; 659 660 size_t Length = 0; 661 for (auto S : Strings) 662 Length += S.size() + 1; 663 initializeOutput(Length, 1); 664 initializeInputFromOutput(1); 665 666 for (auto &Stream : Streams) { 667 BinaryStreamWriter Writer(*Stream.Output); 668 for (auto S : Strings) 669 ASSERT_NO_ERROR(Writer.writeCString(S)); 670 std::vector<StringRef> InStrings; 671 BinaryStreamReader Reader(*Stream.Input); 672 while (!Reader.empty()) { 673 StringRef S; 674 ASSERT_NO_ERROR(Reader.readCString(S)); 675 InStrings.push_back(S); 676 } 677 EXPECT_EQ(makeArrayRef(Strings), makeArrayRef(InStrings)); 678 } 679 } 680 } 681 682 namespace { 683 struct BinaryItemStreamObject { 684 explicit BinaryItemStreamObject(ArrayRef<uint8_t> Bytes) : Bytes(Bytes) {} 685 686 ArrayRef<uint8_t> Bytes; 687 }; 688 } 689 690 namespace llvm { 691 template <> struct BinaryItemTraits<BinaryItemStreamObject> { 692 static size_t length(const BinaryItemStreamObject &Item) { 693 return Item.Bytes.size(); 694 } 695 696 static ArrayRef<uint8_t> bytes(const BinaryItemStreamObject &Item) { 697 return Item.Bytes; 698 } 699 }; 700 } 701 702 namespace { 703 704 TEST_F(BinaryStreamTest, BinaryItemStream) { 705 std::vector<BinaryItemStreamObject> Objects; 706 707 struct Foo { 708 int X; 709 double Y; 710 }; 711 std::vector<Foo> Foos = {{1, 1.0}, {2, 2.0}, {3, 3.0}}; 712 BumpPtrAllocator Allocator; 713 for (const auto &F : Foos) { 714 uint8_t *Ptr = static_cast<uint8_t *>(Allocator.Allocate(sizeof(Foo), 715 alignof(Foo))); 716 MutableArrayRef<uint8_t> Buffer(Ptr, sizeof(Foo)); 717 MutableBinaryByteStream Stream(Buffer, llvm::support::big); 718 BinaryStreamWriter Writer(Stream); 719 ASSERT_NO_ERROR(Writer.writeObject(F)); 720 Objects.push_back(BinaryItemStreamObject(Buffer)); 721 } 722 723 BinaryItemStream<BinaryItemStreamObject> ItemStream(big); 724 ItemStream.setItems(Objects); 725 BinaryStreamReader Reader(ItemStream); 726 727 for (const auto &F : Foos) { 728 const Foo *F2; 729 ASSERT_NO_ERROR(Reader.readObject(F2)); 730 731 EXPECT_EQ(F.X, F2->X); 732 EXPECT_DOUBLE_EQ(F.Y, F2->Y); 733 } 734 } 735 736 } // end anonymous namespace 737