comparison unittests/Support/BinaryStreamTest.cpp @ 121:803732b1fca8

LLVM 5.0
author kono
date Fri, 27 Oct 2017 17:07:41 +0900
parents
children 3a76565eade5
comparison
equal deleted inserted replaced
120:1172e4bd9c6f 121:803732b1fca8
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