121
|
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
|