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 typedef uint32_t &ContextType; 420 static Error extract(BinaryStreamRef Stream, uint32_t &Len, StringRef &Item, 421 uint32_t &Index) { 422 if (Index == 0) 423 Len = strlen("1. Test"); 424 else if (Index == 1) 425 Len = strlen("2. Longer Test"); 426 else if (Index == 2) 427 Len = strlen("3. Really Long Test"); 428 else 429 Len = strlen("4. Super Extra Longest Test Of All"); 430 ArrayRef<uint8_t> Bytes; 431 if (auto EC = Stream.readBytes(0, Len, Bytes)) 432 return EC; 433 Item = 434 StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size()); 435 ++Index; 436 return Error::success(); 437 } 438 }; 439 440 for (auto &Stream : Streams) { 441 uint32_t Context = 0; 442 VarStreamArray<StringRef, StringExtractor> Array(*Stream.Input, Context); 443 auto Iter = Array.begin(); 444 ASSERT_EQ("1. Test", *Iter++); 445 ASSERT_EQ("2. Longer Test", *Iter++); 446 ASSERT_EQ("3. Really Long Test", *Iter++); 447 ASSERT_EQ("4. Super Extra Longest Test Of All", *Iter++); 448 ASSERT_EQ(Array.end(), Iter); 449 } 450 } 451 452 TEST_F(BinaryStreamTest, StreamReaderBounds) { 453 std::vector<uint8_t> Bytes; 454 455 initializeInput(Bytes, 1); 456 for (auto &Stream : Streams) { 457 StringRef S; 458 BinaryStreamReader Reader(*Stream.Input); 459 EXPECT_EQ(0U, Reader.bytesRemaining()); 460 EXPECT_ERROR(Reader.readFixedString(S, 1)); 461 } 462 463 Bytes.resize(5); 464 initializeInput(Bytes, 1); 465 for (auto &Stream : Streams) { 466 StringRef S; 467 BinaryStreamReader Reader(*Stream.Input); 468 EXPECT_EQ(Bytes.size(), Reader.bytesRemaining()); 469 EXPECT_NO_ERROR(Reader.readFixedString(S, 5)); 470 EXPECT_ERROR(Reader.readFixedString(S, 6)); 471 } 472 } 473 474 TEST_F(BinaryStreamTest, StreamReaderIntegers) { 475 support::ulittle64_t Little{908234}; 476 support::ubig32_t Big{28907823}; 477 short NS = 2897; 478 int NI = -89723; 479 unsigned long NUL = 902309023UL; 480 constexpr uint32_t Size = 481 sizeof(Little) + sizeof(Big) + sizeof(NS) + sizeof(NI) + sizeof(NUL); 482 483 initializeOutput(Size, alignof(support::ulittle64_t)); 484 initializeInputFromOutput(alignof(support::ulittle64_t)); 485 486 for (auto &Stream : Streams) { 487 BinaryStreamWriter Writer(*Stream.Output); 488 ASSERT_NO_ERROR(Writer.writeObject(Little)); 489 ASSERT_NO_ERROR(Writer.writeObject(Big)); 490 ASSERT_NO_ERROR(Writer.writeInteger(NS)); 491 ASSERT_NO_ERROR(Writer.writeInteger(NI)); 492 ASSERT_NO_ERROR(Writer.writeInteger(NUL)); 493 494 const support::ulittle64_t *Little2; 495 const support::ubig32_t *Big2; 496 short NS2; 497 int NI2; 498 unsigned long NUL2; 499 500 // 1. Reading fields individually. 501 BinaryStreamReader Reader(*Stream.Input); 502 ASSERT_NO_ERROR(Reader.readObject(Little2)); 503 ASSERT_NO_ERROR(Reader.readObject(Big2)); 504 ASSERT_NO_ERROR(Reader.readInteger(NS2)); 505 ASSERT_NO_ERROR(Reader.readInteger(NI2)); 506 ASSERT_NO_ERROR(Reader.readInteger(NUL2)); 507 ASSERT_EQ(0U, Reader.bytesRemaining()); 508 509 EXPECT_EQ(Little, *Little2); 510 EXPECT_EQ(Big, *Big2); 511 EXPECT_EQ(NS, NS2); 512 EXPECT_EQ(NI, NI2); 513 EXPECT_EQ(NUL, NUL2); 514 } 515 } 516 517 TEST_F(BinaryStreamTest, StreamReaderIntegerArray) { 518 // 1. Arrays of integers 519 std::vector<int> Ints = {1, 2, 3, 4, 5}; 520 ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(&Ints[0]), 521 Ints.size() * sizeof(int)); 522 523 initializeInput(IntBytes, alignof(int)); 524 for (auto &Stream : Streams) { 525 BinaryStreamReader Reader(*Stream.Input); 526 ArrayRef<int> IntsRef; 527 ASSERT_NO_ERROR(Reader.readArray(IntsRef, Ints.size())); 528 ASSERT_EQ(0U, Reader.bytesRemaining()); 529 EXPECT_EQ(makeArrayRef(Ints), IntsRef); 530 531 Reader.setOffset(0); 532 FixedStreamArray<int> FixedIntsRef; 533 ASSERT_NO_ERROR(Reader.readArray(FixedIntsRef, Ints.size())); 534 ASSERT_EQ(0U, Reader.bytesRemaining()); 535 ASSERT_EQ(Ints, std::vector<int>(FixedIntsRef.begin(), FixedIntsRef.end())); 536 } 537 } 538 539 TEST_F(BinaryStreamTest, StreamReaderEnum) { 540 enum class MyEnum : int64_t { Foo = -10, Bar = 0, Baz = 10 }; 541 542 std::vector<MyEnum> Enums = {MyEnum::Bar, MyEnum::Baz, MyEnum::Foo}; 543 544 initializeOutput(Enums.size() * sizeof(MyEnum), alignof(MyEnum)); 545 initializeInputFromOutput(alignof(MyEnum)); 546 for (auto &Stream : Streams) { 547 BinaryStreamWriter Writer(*Stream.Output); 548 for (auto Value : Enums) 549 ASSERT_NO_ERROR(Writer.writeEnum(Value)); 550 551 BinaryStreamReader Reader(*Stream.Input); 552 553 ArrayRef<MyEnum> Array; 554 FixedStreamArray<MyEnum> FSA; 555 556 for (size_t I = 0; I < Enums.size(); ++I) { 557 MyEnum Value; 558 ASSERT_NO_ERROR(Reader.readEnum(Value)); 559 EXPECT_EQ(Enums[I], Value); 560 } 561 ASSERT_EQ(0U, Reader.bytesRemaining()); 562 } 563 } 564 565 TEST_F(BinaryStreamTest, StreamReaderObject) { 566 struct Foo { 567 int X; 568 double Y; 569 char Z; 570 571 bool operator==(const Foo &Other) const { 572 return X == Other.X && Y == Other.Y && Z == Other.Z; 573 } 574 }; 575 576 std::vector<Foo> Foos; 577 Foos.push_back({-42, 42.42, 42}); 578 Foos.push_back({100, 3.1415, static_cast<char>(-89)}); 579 Foos.push_back({200, 2.718, static_cast<char>(-12) }); 580 581 const uint8_t *Bytes = reinterpret_cast<const uint8_t *>(&Foos[0]); 582 583 initializeInput(makeArrayRef(Bytes, 3 * sizeof(Foo)), alignof(Foo)); 584 585 for (auto &Stream : Streams) { 586 // 1. Reading object pointers. 587 BinaryStreamReader Reader(*Stream.Input); 588 const Foo *FPtrOut = nullptr; 589 const Foo *GPtrOut = nullptr; 590 const Foo *HPtrOut = nullptr; 591 ASSERT_NO_ERROR(Reader.readObject(FPtrOut)); 592 ASSERT_NO_ERROR(Reader.readObject(GPtrOut)); 593 ASSERT_NO_ERROR(Reader.readObject(HPtrOut)); 594 EXPECT_EQ(0U, Reader.bytesRemaining()); 595 EXPECT_EQ(Foos[0], *FPtrOut); 596 EXPECT_EQ(Foos[1], *GPtrOut); 597 EXPECT_EQ(Foos[2], *HPtrOut); 598 } 599 } 600 601 TEST_F(BinaryStreamTest, StreamReaderStrings) { 602 std::vector<uint8_t> Bytes = {'O', 'n', 'e', '\0', 'T', 'w', 'o', 603 '\0', 'T', 'h', 'r', 'e', 'e', '\0', 604 'F', 'o', 'u', 'r', '\0'}; 605 initializeInput(Bytes, 1); 606 607 for (auto &Stream : Streams) { 608 BinaryStreamReader Reader(*Stream.Input); 609 610 StringRef S1; 611 StringRef S2; 612 StringRef S3; 613 StringRef S4; 614 ASSERT_NO_ERROR(Reader.readCString(S1)); 615 ASSERT_NO_ERROR(Reader.readCString(S2)); 616 ASSERT_NO_ERROR(Reader.readCString(S3)); 617 ASSERT_NO_ERROR(Reader.readCString(S4)); 618 ASSERT_EQ(0U, Reader.bytesRemaining()); 619 620 EXPECT_EQ("One", S1); 621 EXPECT_EQ("Two", S2); 622 EXPECT_EQ("Three", S3); 623 EXPECT_EQ("Four", S4); 624 625 S1 = S2 = S3 = S4 = ""; 626 Reader.setOffset(0); 627 ASSERT_NO_ERROR(Reader.readFixedString(S1, 3)); 628 ASSERT_NO_ERROR(Reader.skip(1)); 629 ASSERT_NO_ERROR(Reader.readFixedString(S2, 3)); 630 ASSERT_NO_ERROR(Reader.skip(1)); 631 ASSERT_NO_ERROR(Reader.readFixedString(S3, 5)); 632 ASSERT_NO_ERROR(Reader.skip(1)); 633 ASSERT_NO_ERROR(Reader.readFixedString(S4, 4)); 634 ASSERT_NO_ERROR(Reader.skip(1)); 635 ASSERT_EQ(0U, Reader.bytesRemaining()); 636 637 EXPECT_EQ("One", S1); 638 EXPECT_EQ("Two", S2); 639 EXPECT_EQ("Three", S3); 640 EXPECT_EQ("Four", S4); 641 } 642 } 643 644 TEST_F(BinaryStreamTest, StreamWriterBounds) { 645 initializeOutput(5, 1); 646 647 for (auto &Stream : Streams) { 648 BinaryStreamWriter Writer(*Stream.Output); 649 650 // 1. Can write a string that exactly fills the buffer. 651 EXPECT_EQ(5U, Writer.bytesRemaining()); 652 EXPECT_NO_ERROR(Writer.writeFixedString("abcde")); 653 EXPECT_EQ(0U, Writer.bytesRemaining()); 654 655 // 2. Can write an empty string even when you're full 656 EXPECT_NO_ERROR(Writer.writeFixedString("")); 657 EXPECT_ERROR(Writer.writeFixedString("a")); 658 659 // 3. Can't write a string that is one character too long. 660 Writer.setOffset(0); 661 EXPECT_ERROR(Writer.writeFixedString("abcdef")); 662 } 663 } 664 665 TEST_F(BinaryStreamTest, StreamWriterIntegerArrays) { 666 // 3. Arrays of integers 667 std::vector<int> SourceInts = {1, 2, 3, 4, 5}; 668 ArrayRef<uint8_t> SourceBytes(reinterpret_cast<uint8_t *>(&SourceInts[0]), 669 SourceInts.size() * sizeof(int)); 670 671 initializeInput(SourceBytes, alignof(int)); 672 initializeOutputFromInput(alignof(int)); 673 674 for (auto &Stream : Streams) { 675 BinaryStreamReader Reader(*Stream.Input); 676 BinaryStreamWriter Writer(*Stream.Output); 677 ArrayRef<int> Ints; 678 ArrayRef<int> Ints2; 679 // First read them, then write them, then read them back. 680 ASSERT_NO_ERROR(Reader.readArray(Ints, SourceInts.size())); 681 ASSERT_NO_ERROR(Writer.writeArray(Ints)); 682 683 BinaryStreamReader ReaderBacker(*Stream.Output); 684 ASSERT_NO_ERROR(ReaderBacker.readArray(Ints2, SourceInts.size())); 685 686 EXPECT_EQ(makeArrayRef(SourceInts), Ints2); 687 } 688 } 689 690 TEST_F(BinaryStreamTest, StringWriterStrings) { 691 StringRef Strings[] = {"First", "Second", "Third", "Fourth"}; 692 693 size_t Length = 0; 694 for (auto S : Strings) 695 Length += S.size() + 1; 696 initializeOutput(Length, 1); 697 initializeInputFromOutput(1); 698 699 for (auto &Stream : Streams) { 700 BinaryStreamWriter Writer(*Stream.Output); 701 for (auto S : Strings) 702 ASSERT_NO_ERROR(Writer.writeCString(S)); 703 std::vector<StringRef> InStrings; 704 BinaryStreamReader Reader(*Stream.Input); 705 while (!Reader.empty()) { 706 StringRef S; 707 ASSERT_NO_ERROR(Reader.readCString(S)); 708 InStrings.push_back(S); 709 } 710 EXPECT_EQ(makeArrayRef(Strings), makeArrayRef(InStrings)); 711 } 712 } 713 } 714 715 namespace { 716 struct BinaryItemStreamObject { 717 explicit BinaryItemStreamObject(ArrayRef<uint8_t> Bytes) : Bytes(Bytes) {} 718 719 ArrayRef<uint8_t> Bytes; 720 }; 721 } 722 723 namespace llvm { 724 template <> struct BinaryItemTraits<BinaryItemStreamObject> { 725 static size_t length(const BinaryItemStreamObject &Item) { 726 return Item.Bytes.size(); 727 } 728 729 static ArrayRef<uint8_t> bytes(const BinaryItemStreamObject &Item) { 730 return Item.Bytes; 731 } 732 }; 733 } 734 735 namespace { 736 737 TEST_F(BinaryStreamTest, BinaryItemStream) { 738 std::vector<BinaryItemStreamObject> Objects; 739 740 struct Foo { 741 int X; 742 double Y; 743 }; 744 std::vector<Foo> Foos = {{1, 1.0}, {2, 2.0}, {3, 3.0}}; 745 BumpPtrAllocator Allocator; 746 for (const auto &F : Foos) { 747 uint8_t *Ptr = static_cast<uint8_t *>(Allocator.Allocate(sizeof(Foo), 748 alignof(Foo))); 749 MutableArrayRef<uint8_t> Buffer(Ptr, sizeof(Foo)); 750 MutableBinaryByteStream Stream(Buffer, llvm::support::big); 751 BinaryStreamWriter Writer(Stream); 752 ASSERT_NO_ERROR(Writer.writeObject(F)); 753 Objects.push_back(BinaryItemStreamObject(Buffer)); 754 } 755 756 BinaryItemStream<BinaryItemStreamObject> ItemStream(big); 757 ItemStream.setItems(Objects); 758 BinaryStreamReader Reader(ItemStream); 759 760 for (const auto &F : Foos) { 761 const Foo *F2; 762 ASSERT_NO_ERROR(Reader.readObject(F2)); 763 764 EXPECT_EQ(F.X, F2->X); 765 EXPECT_DOUBLE_EQ(F.Y, F2->Y); 766 } 767 } 768 769 } // end anonymous namespace 770