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_F(BinaryStreamTest, DropOperations) { 293 std::vector<uint8_t> InputData = {1, 2, 3, 4, 5, 4, 3, 2, 1}; 294 auto RefData = makeArrayRef(InputData); 295 initializeInput(InputData, 1); 296 297 ArrayRef<uint8_t> Result; 298 BinaryStreamRef Original(InputData, support::little); 299 ASSERT_EQ(InputData.size(), Original.getLength()); 300 301 EXPECT_NO_ERROR(Original.readBytes(0, InputData.size(), Result)); 302 EXPECT_EQ(RefData, Result); 303 304 auto Dropped = Original.drop_front(2); 305 EXPECT_NO_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result)); 306 EXPECT_EQ(RefData.drop_front(2), Result); 307 308 Dropped = Original.drop_back(2); 309 EXPECT_NO_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result)); 310 EXPECT_EQ(RefData.drop_back(2), Result); 311 312 Dropped = Original.keep_front(2); 313 EXPECT_NO_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result)); 314 EXPECT_EQ(RefData.take_front(2), Result); 315 316 Dropped = Original.keep_back(2); 317 EXPECT_NO_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result)); 318 EXPECT_EQ(RefData.take_back(2), Result); 319 320 Dropped = Original.drop_symmetric(2); 321 EXPECT_NO_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result)); 322 EXPECT_EQ(RefData.drop_front(2).drop_back(2), Result); 323 } 324 325 // Test that we can write to a BinaryStream without a StreamWriter. 326 TEST_F(BinaryStreamTest, MutableBinaryByteStreamBounds) { 327 std::vector<uint8_t> InputData = {'T', 'e', 's', 't', '\0'}; 328 initializeInput(InputData, 1); 329 initializeOutput(InputData.size(), 1); 330 331 // For every combination of input stream and output stream. 332 for (auto &Stream : Streams) { 333 MutableArrayRef<uint8_t> Buffer; 334 ASSERT_EQ(InputData.size(), Stream.Input->getLength()); 335 336 // 1. Try two reads that are supposed to work. One from offset 0, and one 337 // from the middle. 338 uint32_t Offsets[] = {0, 3}; 339 for (auto Offset : Offsets) { 340 uint32_t ExpectedSize = Stream.Input->getLength() - Offset; 341 342 // Read everything from Offset until the end of the input data. 343 ArrayRef<uint8_t> Data; 344 ASSERT_NO_ERROR(Stream.Input->readBytes(Offset, ExpectedSize, Data)); 345 ASSERT_EQ(ExpectedSize, Data.size()); 346 347 // Then write it to the destination. 348 ASSERT_NO_ERROR(Stream.Output->writeBytes(0, Data)); 349 350 // Then we read back what we wrote, it should match the corresponding 351 // slice of the original input data. 352 ArrayRef<uint8_t> Data2; 353 ASSERT_NO_ERROR(Stream.Output->readBytes(Offset, ExpectedSize, Data2)); 354 EXPECT_EQ(makeArrayRef(InputData).drop_front(Offset), Data2); 355 } 356 357 std::vector<uint8_t> BigData = {0, 1, 2, 3, 4}; 358 // 2. If the write is too big, it should fail. 359 EXPECT_ERROR(Stream.Output->writeBytes(3, BigData)); 360 } 361 } 362 363 // Test that FixedStreamArray works correctly. 364 TEST_F(BinaryStreamTest, FixedStreamArray) { 365 std::vector<uint32_t> Ints = {90823, 12908, 109823, 209823}; 366 ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(Ints.data()), 367 Ints.size() * sizeof(uint32_t)); 368 369 initializeInput(IntBytes, alignof(uint32_t)); 370 371 for (auto &Stream : Streams) { 372 MutableArrayRef<uint8_t> Buffer; 373 ASSERT_EQ(InputData.size(), Stream.Input->getLength()); 374 375 FixedStreamArray<uint32_t> Array(*Stream.Input); 376 auto Iter = Array.begin(); 377 ASSERT_EQ(Ints[0], *Iter++); 378 ASSERT_EQ(Ints[1], *Iter++); 379 ASSERT_EQ(Ints[2], *Iter++); 380 ASSERT_EQ(Ints[3], *Iter++); 381 ASSERT_EQ(Array.end(), Iter); 382 } 383 } 384 385 // Ensure FixedStreamArrayIterator::operator-> works. 386 // Added for coverage of r302257. 387 TEST_F(BinaryStreamTest, FixedStreamArrayIteratorArrow) { 388 std::vector<std::pair<uint32_t, uint32_t>> Pairs = {{867, 5309}, {555, 1212}}; 389 ArrayRef<uint8_t> PairBytes(reinterpret_cast<uint8_t *>(Pairs.data()), 390 Pairs.size() * sizeof(Pairs[0])); 391 392 initializeInput(PairBytes, alignof(uint32_t)); 393 394 for (auto &Stream : Streams) { 395 ASSERT_EQ(InputData.size(), Stream.Input->getLength()); 396 397 const FixedStreamArray<std::pair<uint32_t, uint32_t>> Array(*Stream.Input); 398 auto Iter = Array.begin(); 399 ASSERT_EQ(Pairs[0].first, Iter->first); 400 ASSERT_EQ(Pairs[0].second, Iter->second); 401 ++Iter; 402 ASSERT_EQ(Pairs[1].first, Iter->first); 403 ASSERT_EQ(Pairs[1].second, Iter->second); 404 ++Iter; 405 ASSERT_EQ(Array.end(), Iter); 406 } 407 } 408 409 // Test that VarStreamArray works correctly. 410 TEST_F(BinaryStreamTest, VarStreamArray) { 411 StringLiteral Strings("1. Test2. Longer Test3. Really Long Test4. Super " 412 "Extra Longest Test Of All"); 413 ArrayRef<uint8_t> StringBytes( 414 reinterpret_cast<const uint8_t *>(Strings.data()), Strings.size()); 415 initializeInput(StringBytes, 1); 416 417 struct StringExtractor { 418 public: 419 Error operator()(BinaryStreamRef Stream, uint32_t &Len, StringRef &Item) { 420 if (Index == 0) 421 Len = strlen("1. Test"); 422 else if (Index == 1) 423 Len = strlen("2. Longer Test"); 424 else if (Index == 2) 425 Len = strlen("3. Really Long Test"); 426 else 427 Len = strlen("4. Super Extra Longest Test Of All"); 428 ArrayRef<uint8_t> Bytes; 429 if (auto EC = Stream.readBytes(0, Len, Bytes)) 430 return EC; 431 Item = 432 StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size()); 433 ++Index; 434 return Error::success(); 435 } 436 437 uint32_t Index = 0; 438 }; 439 440 for (auto &Stream : Streams) { 441 VarStreamArray<StringRef, StringExtractor> Array(*Stream.Input); 442 auto Iter = Array.begin(); 443 ASSERT_EQ("1. Test", *Iter++); 444 ASSERT_EQ("2. Longer Test", *Iter++); 445 ASSERT_EQ("3. Really Long Test", *Iter++); 446 ASSERT_EQ("4. Super Extra Longest Test Of All", *Iter++); 447 ASSERT_EQ(Array.end(), Iter); 448 } 449 } 450 451 TEST_F(BinaryStreamTest, StreamReaderBounds) { 452 std::vector<uint8_t> Bytes; 453 454 initializeInput(Bytes, 1); 455 for (auto &Stream : Streams) { 456 StringRef S; 457 BinaryStreamReader Reader(*Stream.Input); 458 EXPECT_EQ(0U, Reader.bytesRemaining()); 459 EXPECT_ERROR(Reader.readFixedString(S, 1)); 460 } 461 462 Bytes.resize(5); 463 initializeInput(Bytes, 1); 464 for (auto &Stream : Streams) { 465 StringRef S; 466 BinaryStreamReader Reader(*Stream.Input); 467 EXPECT_EQ(Bytes.size(), Reader.bytesRemaining()); 468 EXPECT_NO_ERROR(Reader.readFixedString(S, 5)); 469 EXPECT_ERROR(Reader.readFixedString(S, 6)); 470 } 471 } 472 473 TEST_F(BinaryStreamTest, StreamReaderIntegers) { 474 support::ulittle64_t Little{908234}; 475 support::ubig32_t Big{28907823}; 476 short NS = 2897; 477 int NI = -89723; 478 unsigned long NUL = 902309023UL; 479 constexpr uint32_t Size = 480 sizeof(Little) + sizeof(Big) + sizeof(NS) + sizeof(NI) + sizeof(NUL); 481 482 initializeOutput(Size, alignof(support::ulittle64_t)); 483 initializeInputFromOutput(alignof(support::ulittle64_t)); 484 485 for (auto &Stream : Streams) { 486 BinaryStreamWriter Writer(*Stream.Output); 487 ASSERT_NO_ERROR(Writer.writeObject(Little)); 488 ASSERT_NO_ERROR(Writer.writeObject(Big)); 489 ASSERT_NO_ERROR(Writer.writeInteger(NS)); 490 ASSERT_NO_ERROR(Writer.writeInteger(NI)); 491 ASSERT_NO_ERROR(Writer.writeInteger(NUL)); 492 493 const support::ulittle64_t *Little2; 494 const support::ubig32_t *Big2; 495 short NS2; 496 int NI2; 497 unsigned long NUL2; 498 499 // 1. Reading fields individually. 500 BinaryStreamReader Reader(*Stream.Input); 501 ASSERT_NO_ERROR(Reader.readObject(Little2)); 502 ASSERT_NO_ERROR(Reader.readObject(Big2)); 503 ASSERT_NO_ERROR(Reader.readInteger(NS2)); 504 ASSERT_NO_ERROR(Reader.readInteger(NI2)); 505 ASSERT_NO_ERROR(Reader.readInteger(NUL2)); 506 ASSERT_EQ(0U, Reader.bytesRemaining()); 507 508 EXPECT_EQ(Little, *Little2); 509 EXPECT_EQ(Big, *Big2); 510 EXPECT_EQ(NS, NS2); 511 EXPECT_EQ(NI, NI2); 512 EXPECT_EQ(NUL, NUL2); 513 } 514 } 515 516 TEST_F(BinaryStreamTest, StreamReaderIntegerArray) { 517 // 1. Arrays of integers 518 std::vector<int> Ints = {1, 2, 3, 4, 5}; 519 ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(&Ints[0]), 520 Ints.size() * sizeof(int)); 521 522 initializeInput(IntBytes, alignof(int)); 523 for (auto &Stream : Streams) { 524 BinaryStreamReader Reader(*Stream.Input); 525 ArrayRef<int> IntsRef; 526 ASSERT_NO_ERROR(Reader.readArray(IntsRef, Ints.size())); 527 ASSERT_EQ(0U, Reader.bytesRemaining()); 528 EXPECT_EQ(makeArrayRef(Ints), IntsRef); 529 530 Reader.setOffset(0); 531 FixedStreamArray<int> FixedIntsRef; 532 ASSERT_NO_ERROR(Reader.readArray(FixedIntsRef, Ints.size())); 533 ASSERT_EQ(0U, Reader.bytesRemaining()); 534 ASSERT_EQ(Ints, std::vector<int>(FixedIntsRef.begin(), FixedIntsRef.end())); 535 } 536 } 537 538 TEST_F(BinaryStreamTest, StreamReaderEnum) { 539 enum class MyEnum : int64_t { Foo = -10, Bar = 0, Baz = 10 }; 540 541 std::vector<MyEnum> Enums = {MyEnum::Bar, MyEnum::Baz, MyEnum::Foo}; 542 543 initializeOutput(Enums.size() * sizeof(MyEnum), alignof(MyEnum)); 544 initializeInputFromOutput(alignof(MyEnum)); 545 for (auto &Stream : Streams) { 546 BinaryStreamWriter Writer(*Stream.Output); 547 for (auto Value : Enums) 548 ASSERT_NO_ERROR(Writer.writeEnum(Value)); 549 550 BinaryStreamReader Reader(*Stream.Input); 551 552 ArrayRef<MyEnum> Array; 553 FixedStreamArray<MyEnum> FSA; 554 555 for (size_t I = 0; I < Enums.size(); ++I) { 556 MyEnum Value; 557 ASSERT_NO_ERROR(Reader.readEnum(Value)); 558 EXPECT_EQ(Enums[I], Value); 559 } 560 ASSERT_EQ(0U, Reader.bytesRemaining()); 561 } 562 } 563 564 TEST_F(BinaryStreamTest, StreamReaderObject) { 565 struct Foo { 566 int X; 567 double Y; 568 char Z; 569 570 bool operator==(const Foo &Other) const { 571 return X == Other.X && Y == Other.Y && Z == Other.Z; 572 } 573 }; 574 575 std::vector<Foo> Foos; 576 Foos.push_back({-42, 42.42, 42}); 577 Foos.push_back({100, 3.1415, static_cast<char>(-89)}); 578 Foos.push_back({200, 2.718, static_cast<char>(-12) }); 579 580 const uint8_t *Bytes = reinterpret_cast<const uint8_t *>(&Foos[0]); 581 582 initializeInput(makeArrayRef(Bytes, 3 * sizeof(Foo)), alignof(Foo)); 583 584 for (auto &Stream : Streams) { 585 // 1. Reading object pointers. 586 BinaryStreamReader Reader(*Stream.Input); 587 const Foo *FPtrOut = nullptr; 588 const Foo *GPtrOut = nullptr; 589 const Foo *HPtrOut = nullptr; 590 ASSERT_NO_ERROR(Reader.readObject(FPtrOut)); 591 ASSERT_NO_ERROR(Reader.readObject(GPtrOut)); 592 ASSERT_NO_ERROR(Reader.readObject(HPtrOut)); 593 EXPECT_EQ(0U, Reader.bytesRemaining()); 594 EXPECT_EQ(Foos[0], *FPtrOut); 595 EXPECT_EQ(Foos[1], *GPtrOut); 596 EXPECT_EQ(Foos[2], *HPtrOut); 597 } 598 } 599 600 TEST_F(BinaryStreamTest, StreamReaderStrings) { 601 std::vector<uint8_t> Bytes = {'O', 'n', 'e', '\0', 'T', 'w', 'o', 602 '\0', 'T', 'h', 'r', 'e', 'e', '\0', 603 'F', 'o', 'u', 'r', '\0'}; 604 initializeInput(Bytes, 1); 605 606 for (auto &Stream : Streams) { 607 BinaryStreamReader Reader(*Stream.Input); 608 609 StringRef S1; 610 StringRef S2; 611 StringRef S3; 612 StringRef S4; 613 ASSERT_NO_ERROR(Reader.readCString(S1)); 614 ASSERT_NO_ERROR(Reader.readCString(S2)); 615 ASSERT_NO_ERROR(Reader.readCString(S3)); 616 ASSERT_NO_ERROR(Reader.readCString(S4)); 617 ASSERT_EQ(0U, Reader.bytesRemaining()); 618 619 EXPECT_EQ("One", S1); 620 EXPECT_EQ("Two", S2); 621 EXPECT_EQ("Three", S3); 622 EXPECT_EQ("Four", S4); 623 624 S1 = S2 = S3 = S4 = ""; 625 Reader.setOffset(0); 626 ASSERT_NO_ERROR(Reader.readFixedString(S1, 3)); 627 ASSERT_NO_ERROR(Reader.skip(1)); 628 ASSERT_NO_ERROR(Reader.readFixedString(S2, 3)); 629 ASSERT_NO_ERROR(Reader.skip(1)); 630 ASSERT_NO_ERROR(Reader.readFixedString(S3, 5)); 631 ASSERT_NO_ERROR(Reader.skip(1)); 632 ASSERT_NO_ERROR(Reader.readFixedString(S4, 4)); 633 ASSERT_NO_ERROR(Reader.skip(1)); 634 ASSERT_EQ(0U, Reader.bytesRemaining()); 635 636 EXPECT_EQ("One", S1); 637 EXPECT_EQ("Two", S2); 638 EXPECT_EQ("Three", S3); 639 EXPECT_EQ("Four", S4); 640 } 641 } 642 643 TEST_F(BinaryStreamTest, StreamWriterBounds) { 644 initializeOutput(5, 1); 645 646 for (auto &Stream : Streams) { 647 BinaryStreamWriter Writer(*Stream.Output); 648 649 // 1. Can write a string that exactly fills the buffer. 650 EXPECT_EQ(5U, Writer.bytesRemaining()); 651 EXPECT_NO_ERROR(Writer.writeFixedString("abcde")); 652 EXPECT_EQ(0U, Writer.bytesRemaining()); 653 654 // 2. Can write an empty string even when you're full 655 EXPECT_NO_ERROR(Writer.writeFixedString("")); 656 EXPECT_ERROR(Writer.writeFixedString("a")); 657 658 // 3. Can't write a string that is one character too long. 659 Writer.setOffset(0); 660 EXPECT_ERROR(Writer.writeFixedString("abcdef")); 661 } 662 } 663 664 TEST_F(BinaryStreamTest, StreamWriterIntegerArrays) { 665 // 3. Arrays of integers 666 std::vector<int> SourceInts = {1, 2, 3, 4, 5}; 667 ArrayRef<uint8_t> SourceBytes(reinterpret_cast<uint8_t *>(&SourceInts[0]), 668 SourceInts.size() * sizeof(int)); 669 670 initializeInput(SourceBytes, alignof(int)); 671 initializeOutputFromInput(alignof(int)); 672 673 for (auto &Stream : Streams) { 674 BinaryStreamReader Reader(*Stream.Input); 675 BinaryStreamWriter Writer(*Stream.Output); 676 ArrayRef<int> Ints; 677 ArrayRef<int> Ints2; 678 // First read them, then write them, then read them back. 679 ASSERT_NO_ERROR(Reader.readArray(Ints, SourceInts.size())); 680 ASSERT_NO_ERROR(Writer.writeArray(Ints)); 681 682 BinaryStreamReader ReaderBacker(*Stream.Output); 683 ASSERT_NO_ERROR(ReaderBacker.readArray(Ints2, SourceInts.size())); 684 685 EXPECT_EQ(makeArrayRef(SourceInts), Ints2); 686 } 687 } 688 689 TEST_F(BinaryStreamTest, StringWriterStrings) { 690 StringRef Strings[] = {"First", "Second", "Third", "Fourth"}; 691 692 size_t Length = 0; 693 for (auto S : Strings) 694 Length += S.size() + 1; 695 initializeOutput(Length, 1); 696 initializeInputFromOutput(1); 697 698 for (auto &Stream : Streams) { 699 BinaryStreamWriter Writer(*Stream.Output); 700 for (auto S : Strings) 701 ASSERT_NO_ERROR(Writer.writeCString(S)); 702 std::vector<StringRef> InStrings; 703 BinaryStreamReader Reader(*Stream.Input); 704 while (!Reader.empty()) { 705 StringRef S; 706 ASSERT_NO_ERROR(Reader.readCString(S)); 707 InStrings.push_back(S); 708 } 709 EXPECT_EQ(makeArrayRef(Strings), makeArrayRef(InStrings)); 710 } 711 } 712 } 713 714 namespace { 715 struct BinaryItemStreamObject { 716 explicit BinaryItemStreamObject(ArrayRef<uint8_t> Bytes) : Bytes(Bytes) {} 717 718 ArrayRef<uint8_t> Bytes; 719 }; 720 } 721 722 namespace llvm { 723 template <> struct BinaryItemTraits<BinaryItemStreamObject> { 724 static size_t length(const BinaryItemStreamObject &Item) { 725 return Item.Bytes.size(); 726 } 727 728 static ArrayRef<uint8_t> bytes(const BinaryItemStreamObject &Item) { 729 return Item.Bytes; 730 } 731 }; 732 } 733 734 namespace { 735 736 TEST_F(BinaryStreamTest, BinaryItemStream) { 737 std::vector<BinaryItemStreamObject> Objects; 738 739 struct Foo { 740 int X; 741 double Y; 742 }; 743 std::vector<Foo> Foos = {{1, 1.0}, {2, 2.0}, {3, 3.0}}; 744 BumpPtrAllocator Allocator; 745 for (const auto &F : Foos) { 746 uint8_t *Ptr = static_cast<uint8_t *>(Allocator.Allocate(sizeof(Foo), 747 alignof(Foo))); 748 MutableArrayRef<uint8_t> Buffer(Ptr, sizeof(Foo)); 749 MutableBinaryByteStream Stream(Buffer, llvm::support::big); 750 BinaryStreamWriter Writer(Stream); 751 ASSERT_NO_ERROR(Writer.writeObject(F)); 752 Objects.push_back(BinaryItemStreamObject(Buffer)); 753 } 754 755 BinaryItemStream<BinaryItemStreamObject> ItemStream(big); 756 ItemStream.setItems(Objects); 757 BinaryStreamReader Reader(ItemStream); 758 759 for (const auto &F : Foos) { 760 const Foo *F2; 761 ASSERT_NO_ERROR(Reader.readObject(F2)); 762 763 EXPECT_EQ(F.X, F2->X); 764 EXPECT_DOUBLE_EQ(F.Y, F2->Y); 765 } 766 } 767 768 } // end anonymous namespace 769