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