1 | //===- llvm/unittest/Support/BinaryStreamTest.cpp -------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/Support/Allocator.h" |
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 | |
21 | using namespace llvm; |
22 | using namespace llvm::support; |
23 | |
24 | namespace { |
25 | |
26 | class BrokenStream : public WritableBinaryStream { |
27 | public: |
28 | BrokenStream(MutableArrayRef<uint8_t> Data, endianness Endian, uint32_t Align) |
29 | : Data(Data), PartitionIndex(alignDown(Value: Data.size() / 2, Align)), |
30 | Endian(Endian) {} |
31 | |
32 | endianness getEndian() const override { return Endian; } |
33 | |
34 | Error readBytes(uint64_t Offset, uint64_t Size, |
35 | ArrayRef<uint8_t> &Buffer) override { |
36 | if (auto EC = checkOffsetForRead(Offset, DataSize: Size)) |
37 | return EC; |
38 | uint64_t S = startIndex(Offset); |
39 | auto Ref = Data.drop_front(N: S); |
40 | if (Ref.size() >= Size) { |
41 | Buffer = Ref.take_front(N: Size); |
42 | return Error::success(); |
43 | } |
44 | |
45 | uint64_t BytesLeft = Size - Ref.size(); |
46 | uint8_t *Ptr = Allocator.Allocate<uint8_t>(Num: Size); |
47 | ::memcpy(dest: Ptr, src: Ref.data(), n: Ref.size()); |
48 | ::memcpy(dest: Ptr + Ref.size(), src: Data.data(), n: BytesLeft); |
49 | Buffer = ArrayRef<uint8_t>(Ptr, Size); |
50 | return Error::success(); |
51 | } |
52 | |
53 | Error readLongestContiguousChunk(uint64_t Offset, |
54 | ArrayRef<uint8_t> &Buffer) override { |
55 | if (auto EC = checkOffsetForRead(Offset, DataSize: 1)) |
56 | return EC; |
57 | uint64_t S = startIndex(Offset); |
58 | Buffer = Data.drop_front(N: S); |
59 | return Error::success(); |
60 | } |
61 | |
62 | uint64_t getLength() override { return Data.size(); } |
63 | |
64 | Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> SrcData) override { |
65 | if (auto EC = checkOffsetForWrite(Offset, DataSize: SrcData.size())) |
66 | return EC; |
67 | if (SrcData.empty()) |
68 | return Error::success(); |
69 | |
70 | uint64_t S = startIndex(Offset); |
71 | MutableArrayRef<uint8_t> Ref(Data); |
72 | Ref = Ref.drop_front(N: S); |
73 | if (Ref.size() >= SrcData.size()) { |
74 | ::memcpy(dest: Ref.data(), src: SrcData.data(), n: SrcData.size()); |
75 | return Error::success(); |
76 | } |
77 | |
78 | uint64_t BytesLeft = SrcData.size() - Ref.size(); |
79 | ::memcpy(dest: Ref.data(), src: SrcData.data(), n: Ref.size()); |
80 | ::memcpy(dest: &Data[0], src: SrcData.data() + Ref.size(), n: BytesLeft); |
81 | return Error::success(); |
82 | } |
83 | Error commit() override { return Error::success(); } |
84 | |
85 | private: |
86 | uint64_t startIndex(uint64_t Offset) const { |
87 | return (Offset + PartitionIndex) % Data.size(); |
88 | } |
89 | |
90 | uint64_t endIndex(uint64_t Offset, uint64_t Size) const { |
91 | return (startIndex(Offset) + Size - 1) % Data.size(); |
92 | } |
93 | |
94 | // Buffer is organized like this: |
95 | // ------------------------------------------------- |
96 | // | N/2 | N/2+1 | ... | N-1 | 0 | 1 | ... | N/2-1 | |
97 | // ------------------------------------------------- |
98 | // So reads from the beginning actually come from the middle. |
99 | MutableArrayRef<uint8_t> Data; |
100 | uint32_t PartitionIndex = 0; |
101 | endianness Endian; |
102 | BumpPtrAllocator Allocator; |
103 | }; |
104 | |
105 | constexpr llvm::endianness Endians[] = { |
106 | llvm::endianness::big, llvm::endianness::little, llvm::endianness::native}; |
107 | constexpr uint32_t NumEndians = std::size(Endians); |
108 | constexpr uint32_t NumStreams = 2 * NumEndians; |
109 | |
110 | class BinaryStreamTest : public testing::Test { |
111 | |
112 | public: |
113 | BinaryStreamTest() {} |
114 | |
115 | void SetUp() override { |
116 | Streams.clear(); |
117 | Streams.resize(new_size: NumStreams); |
118 | for (uint32_t I = 0; I < NumStreams; ++I) |
119 | Streams[I].IsContiguous = (I % 2 == 0); |
120 | |
121 | InputData.clear(); |
122 | OutputData.clear(); |
123 | } |
124 | |
125 | protected: |
126 | struct StreamPair { |
127 | bool IsContiguous; |
128 | std::unique_ptr<BinaryStream> Input; |
129 | std::unique_ptr<WritableBinaryStream> Output; |
130 | }; |
131 | |
132 | void initializeInput(ArrayRef<uint8_t> Input, uint32_t Align) { |
133 | InputData = Input; |
134 | |
135 | BrokenInputData.resize(new_size: InputData.size()); |
136 | if (!Input.empty()) { |
137 | uint64_t PartitionIndex = alignDown(Value: InputData.size() / 2, Align); |
138 | uint64_t RightBytes = InputData.size() - PartitionIndex; |
139 | uint64_t LeftBytes = PartitionIndex; |
140 | if (RightBytes > 0) |
141 | ::memcpy(dest: &BrokenInputData[PartitionIndex], src: Input.data(), n: RightBytes); |
142 | if (LeftBytes > 0) |
143 | ::memcpy(dest: &BrokenInputData[0], src: Input.data() + RightBytes, n: LeftBytes); |
144 | } |
145 | |
146 | for (uint32_t I = 0; I < NumEndians; ++I) { |
147 | auto InByteStream = |
148 | std::make_unique<BinaryByteStream>(args&: InputData, args: Endians[I]); |
149 | auto InBrokenStream = std::make_unique<BrokenStream>( |
150 | args&: BrokenInputData, args: Endians[I], args&: Align); |
151 | |
152 | Streams[I * 2].Input = std::move(InByteStream); |
153 | Streams[I * 2 + 1].Input = std::move(InBrokenStream); |
154 | } |
155 | } |
156 | |
157 | void initializeOutput(uint64_t Size, uint32_t Align) { |
158 | OutputData.resize(new_size: Size); |
159 | BrokenOutputData.resize(new_size: Size); |
160 | |
161 | for (uint32_t I = 0; I < NumEndians; ++I) { |
162 | Streams[I * 2].Output = |
163 | std::make_unique<MutableBinaryByteStream>(args&: OutputData, args: Endians[I]); |
164 | Streams[I * 2 + 1].Output = std::make_unique<BrokenStream>( |
165 | args&: BrokenOutputData, args: Endians[I], args&: Align); |
166 | } |
167 | } |
168 | |
169 | void initializeOutputFromInput(uint32_t Align) { |
170 | for (uint32_t I = 0; I < NumEndians; ++I) { |
171 | Streams[I * 2].Output = |
172 | std::make_unique<MutableBinaryByteStream>(args&: InputData, args: Endians[I]); |
173 | Streams[I * 2 + 1].Output = std::make_unique<BrokenStream>( |
174 | args&: BrokenInputData, args: Endians[I], args&: Align); |
175 | } |
176 | } |
177 | |
178 | void initializeInputFromOutput(uint32_t Align) { |
179 | for (uint32_t I = 0; I < NumEndians; ++I) { |
180 | Streams[I * 2].Input = |
181 | std::make_unique<BinaryByteStream>(args&: OutputData, args: Endians[I]); |
182 | Streams[I * 2 + 1].Input = std::make_unique<BrokenStream>( |
183 | args&: BrokenOutputData, args: Endians[I], args&: Align); |
184 | } |
185 | } |
186 | |
187 | std::vector<uint8_t> InputData; |
188 | std::vector<uint8_t> BrokenInputData; |
189 | |
190 | std::vector<uint8_t> OutputData; |
191 | std::vector<uint8_t> BrokenOutputData; |
192 | |
193 | std::vector<StreamPair> Streams; |
194 | }; |
195 | |
196 | // Tests that a we can read from a BinaryByteStream without a StreamReader. |
197 | TEST_F(BinaryStreamTest, BinaryByteStreamBounds) { |
198 | std::vector<uint8_t> InputData = {1, 2, 3, 4, 5}; |
199 | initializeInput(Input: InputData, Align: 1); |
200 | |
201 | for (auto &Stream : Streams) { |
202 | ArrayRef<uint8_t> Buffer; |
203 | |
204 | // 1. If the read fits it should work. |
205 | ASSERT_EQ(InputData.size(), Stream.Input->getLength()); |
206 | ASSERT_THAT_ERROR(Stream.Input->readBytes(2, 1, Buffer), Succeeded()); |
207 | EXPECT_EQ(ArrayRef(InputData).slice(2, 1), Buffer); |
208 | ASSERT_THAT_ERROR(Stream.Input->readBytes(0, 4, Buffer), Succeeded()); |
209 | EXPECT_EQ(ArrayRef(InputData).slice(0, 4), Buffer); |
210 | |
211 | // 2. Reading past the bounds of the input should fail. |
212 | EXPECT_THAT_ERROR(Stream.Input->readBytes(4, 2, Buffer), Failed()); |
213 | } |
214 | } |
215 | |
216 | TEST_F(BinaryStreamTest, StreamRefBounds) { |
217 | std::vector<uint8_t> InputData = {1, 2, 3, 4, 5}; |
218 | initializeInput(Input: InputData, Align: 1); |
219 | |
220 | for (const auto &Stream : Streams) { |
221 | ArrayRef<uint8_t> Buffer; |
222 | BinaryStreamRef Ref(*Stream.Input); |
223 | |
224 | // Read 1 byte from offset 2 should work |
225 | ASSERT_EQ(InputData.size(), Ref.getLength()); |
226 | ASSERT_THAT_ERROR(Ref.readBytes(2, 1, Buffer), Succeeded()); |
227 | EXPECT_EQ(ArrayRef(InputData).slice(2, 1), Buffer); |
228 | |
229 | // Reading everything from offset 2 on. |
230 | ASSERT_THAT_ERROR(Ref.readLongestContiguousChunk(2, Buffer), Succeeded()); |
231 | if (Stream.IsContiguous) |
232 | EXPECT_EQ(ArrayRef(InputData).slice(2), Buffer); |
233 | else |
234 | EXPECT_FALSE(Buffer.empty()); |
235 | |
236 | // Reading 6 bytes from offset 0 is too big. |
237 | EXPECT_THAT_ERROR(Ref.readBytes(0, 6, Buffer), Failed()); |
238 | EXPECT_THAT_ERROR(Ref.readLongestContiguousChunk(6, Buffer), Failed()); |
239 | |
240 | // Reading 1 byte from offset 2 after dropping 1 byte is the same as reading |
241 | // 1 byte from offset 3. |
242 | Ref = Ref.drop_front(N: 1); |
243 | ASSERT_THAT_ERROR(Ref.readBytes(2, 1, Buffer), Succeeded()); |
244 | if (Stream.IsContiguous) |
245 | EXPECT_EQ(ArrayRef(InputData).slice(3, 1), Buffer); |
246 | else |
247 | EXPECT_FALSE(Buffer.empty()); |
248 | |
249 | // Reading everything from offset 2 on after dropping 1 byte. |
250 | ASSERT_THAT_ERROR(Ref.readLongestContiguousChunk(2, Buffer), Succeeded()); |
251 | if (Stream.IsContiguous) |
252 | EXPECT_EQ(ArrayRef(InputData).slice(3), Buffer); |
253 | else |
254 | EXPECT_FALSE(Buffer.empty()); |
255 | |
256 | // Reading 2 bytes from offset 2 after dropping 2 bytes is the same as |
257 | // reading 2 bytes from offset 4, and should fail. |
258 | Ref = Ref.drop_front(N: 1); |
259 | EXPECT_THAT_ERROR(Ref.readBytes(2, 2, Buffer), Failed()); |
260 | |
261 | // But if we read the longest contiguous chunk instead, we should still |
262 | // get the 1 byte at the end. |
263 | ASSERT_THAT_ERROR(Ref.readLongestContiguousChunk(2, Buffer), Succeeded()); |
264 | EXPECT_EQ(ArrayRef(InputData).take_back(), Buffer); |
265 | } |
266 | } |
267 | |
268 | TEST_F(BinaryStreamTest, StreamRefDynamicSize) { |
269 | StringRef Strings[] = {"1" , "2" , "3" , "4" }; |
270 | AppendingBinaryByteStream Stream(llvm::endianness::little); |
271 | |
272 | BinaryStreamWriter Writer(Stream); |
273 | BinaryStreamReader Reader(Stream); |
274 | const uint8_t *Byte; |
275 | StringRef Str; |
276 | |
277 | // When the stream is empty, it should report a 0 length and we should get an |
278 | // error trying to read even 1 byte from it. |
279 | BinaryStreamRef ConstRef(Stream); |
280 | EXPECT_EQ(0U, ConstRef.getLength()); |
281 | EXPECT_THAT_ERROR(Reader.readObject(Byte), Failed()); |
282 | |
283 | // But if we write to it, its size should increase and we should be able to |
284 | // read not just a byte, but the string that was written. |
285 | EXPECT_THAT_ERROR(Writer.writeCString(Strings[0]), Succeeded()); |
286 | EXPECT_EQ(2U, ConstRef.getLength()); |
287 | EXPECT_THAT_ERROR(Reader.readObject(Byte), Succeeded()); |
288 | |
289 | Reader.setOffset(0); |
290 | EXPECT_THAT_ERROR(Reader.readCString(Str), Succeeded()); |
291 | EXPECT_EQ(Str, Strings[0]); |
292 | |
293 | // If we drop some bytes from the front, we should still track the length as |
294 | // the |
295 | // underlying stream grows. |
296 | BinaryStreamRef Dropped = ConstRef.drop_front(N: 1); |
297 | EXPECT_EQ(1U, Dropped.getLength()); |
298 | |
299 | EXPECT_THAT_ERROR(Writer.writeCString(Strings[1]), Succeeded()); |
300 | EXPECT_EQ(4U, ConstRef.getLength()); |
301 | EXPECT_EQ(3U, Dropped.getLength()); |
302 | |
303 | // If we drop zero bytes from the back, we should continue tracking the |
304 | // length. |
305 | Dropped = Dropped.drop_back(N: 0); |
306 | EXPECT_THAT_ERROR(Writer.writeCString(Strings[2]), Succeeded()); |
307 | EXPECT_EQ(6U, ConstRef.getLength()); |
308 | EXPECT_EQ(5U, Dropped.getLength()); |
309 | |
310 | // If we drop non-zero bytes from the back, we should stop tracking the |
311 | // length. |
312 | Dropped = Dropped.drop_back(N: 1); |
313 | EXPECT_THAT_ERROR(Writer.writeCString(Strings[3]), Succeeded()); |
314 | EXPECT_EQ(8U, ConstRef.getLength()); |
315 | EXPECT_EQ(4U, Dropped.getLength()); |
316 | } |
317 | |
318 | TEST_F(BinaryStreamTest, DropOperations) { |
319 | std::vector<uint8_t> InputData = {1, 2, 3, 4, 5, 4, 3, 2, 1}; |
320 | auto RefData = ArrayRef(InputData); |
321 | initializeInput(Input: InputData, Align: 1); |
322 | |
323 | ArrayRef<uint8_t> Result; |
324 | BinaryStreamRef Original(InputData, llvm::endianness::little); |
325 | ASSERT_EQ(InputData.size(), Original.getLength()); |
326 | |
327 | EXPECT_THAT_ERROR(Original.readBytes(0, InputData.size(), Result), |
328 | Succeeded()); |
329 | EXPECT_EQ(RefData, Result); |
330 | |
331 | auto Dropped = Original.drop_front(N: 2); |
332 | EXPECT_THAT_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result), |
333 | Succeeded()); |
334 | EXPECT_EQ(RefData.drop_front(2), Result); |
335 | |
336 | Dropped = Original.drop_back(N: 2); |
337 | EXPECT_THAT_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result), |
338 | Succeeded()); |
339 | EXPECT_EQ(RefData.drop_back(2), Result); |
340 | |
341 | Dropped = Original.keep_front(N: 2); |
342 | EXPECT_THAT_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result), |
343 | Succeeded()); |
344 | EXPECT_EQ(RefData.take_front(2), Result); |
345 | |
346 | Dropped = Original.keep_back(N: 2); |
347 | EXPECT_THAT_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result), |
348 | Succeeded()); |
349 | EXPECT_EQ(RefData.take_back(2), Result); |
350 | |
351 | Dropped = Original.drop_symmetric(N: 2); |
352 | EXPECT_THAT_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result), |
353 | Succeeded()); |
354 | EXPECT_EQ(RefData.drop_front(2).drop_back(2), Result); |
355 | } |
356 | |
357 | // Test that we can write to a BinaryStream without a StreamWriter. |
358 | TEST_F(BinaryStreamTest, MutableBinaryByteStreamBounds) { |
359 | std::vector<uint8_t> InputData = {'T', 'e', 's', 't', '\0'}; |
360 | initializeInput(Input: InputData, Align: 1); |
361 | initializeOutput(Size: InputData.size(), Align: 1); |
362 | |
363 | // For every combination of input stream and output stream. |
364 | for (auto &Stream : Streams) { |
365 | ASSERT_EQ(InputData.size(), Stream.Input->getLength()); |
366 | |
367 | // 1. Try two reads that are supposed to work. One from offset 0, and one |
368 | // from the middle. |
369 | uint32_t Offsets[] = {0, 3}; |
370 | for (auto Offset : Offsets) { |
371 | uint64_t ExpectedSize = Stream.Input->getLength() - Offset; |
372 | |
373 | // Read everything from Offset until the end of the input data. |
374 | ArrayRef<uint8_t> Data; |
375 | ASSERT_THAT_ERROR(Stream.Input->readBytes(Offset, ExpectedSize, Data), |
376 | Succeeded()); |
377 | ASSERT_EQ(ExpectedSize, Data.size()); |
378 | |
379 | // Then write it to the destination. |
380 | ASSERT_THAT_ERROR(Stream.Output->writeBytes(0, Data), Succeeded()); |
381 | |
382 | // Then we read back what we wrote, it should match the corresponding |
383 | // slice of the original input data. |
384 | ArrayRef<uint8_t> Data2; |
385 | ASSERT_THAT_ERROR(Stream.Output->readBytes(Offset, ExpectedSize, Data2), |
386 | Succeeded()); |
387 | EXPECT_EQ(ArrayRef(InputData).drop_front(Offset), Data2); |
388 | } |
389 | |
390 | std::vector<uint8_t> BigData = {0, 1, 2, 3, 4}; |
391 | // 2. If the write is too big, it should fail. |
392 | EXPECT_THAT_ERROR(Stream.Output->writeBytes(3, BigData), Failed()); |
393 | } |
394 | } |
395 | |
396 | TEST_F(BinaryStreamTest, AppendingStream) { |
397 | AppendingBinaryByteStream Stream(llvm::endianness::little); |
398 | EXPECT_EQ(0U, Stream.getLength()); |
399 | |
400 | std::vector<uint8_t> InputData = {'T', 'e', 's', 't', 'T', 'e', 's', 't'}; |
401 | auto Test = ArrayRef(InputData).take_front(N: 4); |
402 | // Writing past the end of the stream is an error. |
403 | EXPECT_THAT_ERROR(Stream.writeBytes(4, Test), Failed()); |
404 | |
405 | // Writing exactly at the end of the stream is ok. |
406 | EXPECT_THAT_ERROR(Stream.writeBytes(0, Test), Succeeded()); |
407 | EXPECT_EQ(Test, Stream.data()); |
408 | |
409 | // And now that the end of the stream is where we couldn't write before, now |
410 | // we can write. |
411 | EXPECT_THAT_ERROR(Stream.writeBytes(4, Test), Succeeded()); |
412 | EXPECT_EQ(MutableArrayRef<uint8_t>(InputData), Stream.data()); |
413 | } |
414 | |
415 | // Test that FixedStreamArray works correctly. |
416 | TEST_F(BinaryStreamTest, FixedStreamArray) { |
417 | std::vector<uint32_t> Ints = {90823, 12908, 109823, 209823}; |
418 | ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(Ints.data()), |
419 | Ints.size() * sizeof(uint32_t)); |
420 | |
421 | initializeInput(Input: IntBytes, Align: alignof(uint32_t)); |
422 | |
423 | for (auto &Stream : Streams) { |
424 | ASSERT_EQ(InputData.size(), Stream.Input->getLength()); |
425 | |
426 | FixedStreamArray<uint32_t> Array(*Stream.Input); |
427 | auto Iter = Array.begin(); |
428 | ASSERT_EQ(Ints[0], *Iter++); |
429 | ASSERT_EQ(Ints[1], *Iter++); |
430 | ASSERT_EQ(Ints[2], *Iter++); |
431 | ASSERT_EQ(Ints[3], *Iter++); |
432 | ASSERT_EQ(Array.end(), Iter); |
433 | } |
434 | } |
435 | |
436 | // Ensure FixedStreamArrayIterator::operator-> works. |
437 | // Added for coverage of r302257. |
438 | TEST_F(BinaryStreamTest, FixedStreamArrayIteratorArrow) { |
439 | std::vector<std::pair<uint32_t, uint32_t>> Pairs = {{867, 5309}, {555, 1212}}; |
440 | ArrayRef<uint8_t> PairBytes(reinterpret_cast<uint8_t *>(Pairs.data()), |
441 | Pairs.size() * sizeof(Pairs[0])); |
442 | |
443 | initializeInput(Input: PairBytes, Align: alignof(uint32_t)); |
444 | |
445 | for (auto &Stream : Streams) { |
446 | ASSERT_EQ(InputData.size(), Stream.Input->getLength()); |
447 | |
448 | const FixedStreamArray<std::pair<uint32_t, uint32_t>> Array(*Stream.Input); |
449 | auto Iter = Array.begin(); |
450 | ASSERT_EQ(Pairs[0].first, Iter->first); |
451 | ASSERT_EQ(Pairs[0].second, Iter->second); |
452 | ++Iter; |
453 | ASSERT_EQ(Pairs[1].first, Iter->first); |
454 | ASSERT_EQ(Pairs[1].second, Iter->second); |
455 | ++Iter; |
456 | ASSERT_EQ(Array.end(), Iter); |
457 | } |
458 | } |
459 | |
460 | // Test that VarStreamArray works correctly. |
461 | TEST_F(BinaryStreamTest, VarStreamArray) { |
462 | StringLiteral Strings("1. Test2. Longer Test3. Really Long Test4. Super " |
463 | "Extra Longest Test Of All" ); |
464 | ArrayRef<uint8_t> StringBytes( |
465 | reinterpret_cast<const uint8_t *>(Strings.data()), Strings.size()); |
466 | initializeInput(Input: StringBytes, Align: 1); |
467 | |
468 | struct { |
469 | public: |
470 | Error operator()(BinaryStreamRef Stream, uint32_t &Len, StringRef &Item) { |
471 | if (Index == 0) |
472 | Len = strlen(s: "1. Test" ); |
473 | else if (Index == 1) |
474 | Len = strlen(s: "2. Longer Test" ); |
475 | else if (Index == 2) |
476 | Len = strlen(s: "3. Really Long Test" ); |
477 | else |
478 | Len = strlen(s: "4. Super Extra Longest Test Of All" ); |
479 | ArrayRef<uint8_t> Bytes; |
480 | if (auto EC = Stream.readBytes(Offset: 0, Size: Len, Buffer&: Bytes)) |
481 | return EC; |
482 | Item = |
483 | StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size()); |
484 | ++Index; |
485 | return Error::success(); |
486 | } |
487 | |
488 | uint32_t Index = 0; |
489 | }; |
490 | |
491 | for (auto &Stream : Streams) { |
492 | VarStreamArray<StringRef, StringExtractor> Array(*Stream.Input); |
493 | auto Iter = Array.begin(); |
494 | ASSERT_EQ("1. Test" , *Iter++); |
495 | ASSERT_EQ("2. Longer Test" , *Iter++); |
496 | ASSERT_EQ("3. Really Long Test" , *Iter++); |
497 | ASSERT_EQ("4. Super Extra Longest Test Of All" , *Iter++); |
498 | ASSERT_EQ(Array.end(), Iter); |
499 | } |
500 | } |
501 | |
502 | TEST_F(BinaryStreamTest, StreamReaderBounds) { |
503 | std::vector<uint8_t> Bytes; |
504 | |
505 | initializeInput(Input: Bytes, Align: 1); |
506 | for (auto &Stream : Streams) { |
507 | StringRef S; |
508 | BinaryStreamReader Reader(*Stream.Input); |
509 | EXPECT_EQ(0U, Reader.bytesRemaining()); |
510 | EXPECT_THAT_ERROR(Reader.readFixedString(S, 1), Failed()); |
511 | } |
512 | |
513 | Bytes.resize(new_size: 5); |
514 | initializeInput(Input: Bytes, Align: 1); |
515 | for (auto &Stream : Streams) { |
516 | StringRef S; |
517 | BinaryStreamReader Reader(*Stream.Input); |
518 | EXPECT_EQ(Bytes.size(), Reader.bytesRemaining()); |
519 | EXPECT_THAT_ERROR(Reader.readFixedString(S, 5), Succeeded()); |
520 | EXPECT_THAT_ERROR(Reader.readFixedString(S, 6), Failed()); |
521 | } |
522 | } |
523 | |
524 | TEST_F(BinaryStreamTest, StreamReaderIntegers) { |
525 | support::ulittle64_t Little{908234}; |
526 | support::ubig32_t Big{28907823}; |
527 | short NS = 2897; |
528 | int NI = -89723; |
529 | unsigned long NUL = 902309023UL; |
530 | constexpr uint32_t Size = |
531 | sizeof(Little) + sizeof(Big) + sizeof(NS) + sizeof(NI) + sizeof(NUL); |
532 | |
533 | initializeOutput(Size, Align: alignof(support::ulittle64_t)); |
534 | initializeInputFromOutput(Align: alignof(support::ulittle64_t)); |
535 | |
536 | for (auto &Stream : Streams) { |
537 | BinaryStreamWriter Writer(*Stream.Output); |
538 | ASSERT_THAT_ERROR(Writer.writeObject(Little), Succeeded()); |
539 | ASSERT_THAT_ERROR(Writer.writeObject(Big), Succeeded()); |
540 | ASSERT_THAT_ERROR(Writer.writeInteger(NS), Succeeded()); |
541 | ASSERT_THAT_ERROR(Writer.writeInteger(NI), Succeeded()); |
542 | ASSERT_THAT_ERROR(Writer.writeInteger(NUL), Succeeded()); |
543 | |
544 | const support::ulittle64_t *Little2; |
545 | const support::ubig32_t *Big2; |
546 | short NS2; |
547 | int NI2; |
548 | unsigned long NUL2; |
549 | |
550 | // 1. Reading fields individually. |
551 | BinaryStreamReader Reader(*Stream.Input); |
552 | ASSERT_THAT_ERROR(Reader.readObject(Little2), Succeeded()); |
553 | ASSERT_THAT_ERROR(Reader.readObject(Big2), Succeeded()); |
554 | ASSERT_THAT_ERROR(Reader.readInteger(NS2), Succeeded()); |
555 | ASSERT_THAT_ERROR(Reader.readInteger(NI2), Succeeded()); |
556 | ASSERT_THAT_ERROR(Reader.readInteger(NUL2), Succeeded()); |
557 | ASSERT_EQ(0U, Reader.bytesRemaining()); |
558 | |
559 | EXPECT_EQ(Little, *Little2); |
560 | EXPECT_EQ(Big, *Big2); |
561 | EXPECT_EQ(NS, NS2); |
562 | EXPECT_EQ(NI, NI2); |
563 | EXPECT_EQ(NUL, NUL2); |
564 | } |
565 | } |
566 | |
567 | TEST_F(BinaryStreamTest, StreamReaderIntegerArray) { |
568 | // 1. Arrays of integers |
569 | std::vector<int> Ints = {1, 2, 3, 4, 5}; |
570 | ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(&Ints[0]), |
571 | Ints.size() * sizeof(int)); |
572 | |
573 | initializeInput(Input: IntBytes, Align: alignof(int)); |
574 | for (auto &Stream : Streams) { |
575 | BinaryStreamReader Reader(*Stream.Input); |
576 | ArrayRef<int> IntsRef; |
577 | ASSERT_THAT_ERROR(Reader.readArray(IntsRef, Ints.size()), Succeeded()); |
578 | ASSERT_EQ(0U, Reader.bytesRemaining()); |
579 | EXPECT_EQ(ArrayRef(Ints), IntsRef); |
580 | |
581 | Reader.setOffset(0); |
582 | FixedStreamArray<int> FixedIntsRef; |
583 | ASSERT_THAT_ERROR(Reader.readArray(FixedIntsRef, Ints.size()), Succeeded()); |
584 | ASSERT_EQ(0U, Reader.bytesRemaining()); |
585 | ASSERT_EQ(Ints, std::vector<int>(FixedIntsRef.begin(), FixedIntsRef.end())); |
586 | } |
587 | } |
588 | |
589 | TEST_F(BinaryStreamTest, StreamReaderEnum) { |
590 | enum class MyEnum : int64_t { Foo = -10, Bar = 0, Baz = 10 }; |
591 | |
592 | std::vector<MyEnum> Enums = {MyEnum::Bar, MyEnum::Baz, MyEnum::Foo}; |
593 | |
594 | initializeOutput(Size: Enums.size() * sizeof(MyEnum), Align: alignof(MyEnum)); |
595 | initializeInputFromOutput(Align: alignof(MyEnum)); |
596 | for (auto &Stream : Streams) { |
597 | BinaryStreamWriter Writer(*Stream.Output); |
598 | for (auto Value : Enums) |
599 | ASSERT_THAT_ERROR(Writer.writeEnum(Value), Succeeded()); |
600 | |
601 | BinaryStreamReader Reader(*Stream.Input); |
602 | |
603 | FixedStreamArray<MyEnum> FSA; |
604 | |
605 | for (size_t I = 0; I < Enums.size(); ++I) { |
606 | MyEnum Value; |
607 | ASSERT_THAT_ERROR(Reader.readEnum(Value), Succeeded()); |
608 | EXPECT_EQ(Enums[I], Value); |
609 | } |
610 | ASSERT_EQ(0U, Reader.bytesRemaining()); |
611 | } |
612 | } |
613 | |
614 | TEST_F(BinaryStreamTest, StreamReaderULEB128) { |
615 | std::vector<uint64_t> TestValues = { |
616 | 0, // Zero |
617 | 0x7F, // One byte |
618 | 0xFF, // One byte, all-ones |
619 | 0xAAAA, // Two bytes |
620 | 0xAAAAAAAA, // Four bytes |
621 | 0xAAAAAAAAAAAAAAAA, // Eight bytes |
622 | 0xffffffffffffffff // Eight bytess, all-ones |
623 | }; |
624 | |
625 | // Conservatively assume a 10-byte encoding for each of our LEB128s, with no |
626 | // alignment requirement. |
627 | initializeOutput(Size: 10 * TestValues.size(), Align: 1); |
628 | initializeInputFromOutput(Align: 1); |
629 | |
630 | for (auto &Stream : Streams) { |
631 | // Write fields. |
632 | BinaryStreamWriter Writer(*Stream.Output); |
633 | for (const auto &Value : TestValues) |
634 | ASSERT_THAT_ERROR(Writer.writeULEB128(Value), Succeeded()); |
635 | |
636 | // Read fields. |
637 | BinaryStreamReader Reader(*Stream.Input); |
638 | std::vector<uint64_t> Results; |
639 | Results.resize(new_size: TestValues.size()); |
640 | for (unsigned I = 0; I != TestValues.size(); ++I) |
641 | ASSERT_THAT_ERROR(Reader.readULEB128(Results[I]), Succeeded()); |
642 | |
643 | for (unsigned I = 0; I != TestValues.size(); ++I) |
644 | EXPECT_EQ(TestValues[I], Results[I]); |
645 | } |
646 | } |
647 | |
648 | TEST_F(BinaryStreamTest, StreamReaderSLEB128) { |
649 | std::vector<int64_t> TestValues = { |
650 | 0, // Zero |
651 | 0x7F, // One byte |
652 | -0x7F, // One byte, negative |
653 | 0xFF, // One byte, all-ones |
654 | 0xAAAA, // Two bytes |
655 | -0xAAAA, // Two bytes, negative |
656 | 0xAAAAAAAA, // Four bytes |
657 | -0xAAAAAAAA, // Four bytes, negative |
658 | 0x2AAAAAAAAAAAAAAA, // Eight bytes |
659 | -0x7ffffffffffffff // Eight bytess, negative |
660 | }; |
661 | |
662 | // Conservatively assume a 10-byte encoding for each of our LEB128s, with no |
663 | // alignment requirement. |
664 | initializeOutput(Size: 10 * TestValues.size(), Align: 1); |
665 | initializeInputFromOutput(Align: 1); |
666 | |
667 | for (auto &Stream : Streams) { |
668 | // Write fields. |
669 | BinaryStreamWriter Writer(*Stream.Output); |
670 | for (const auto &Value : TestValues) |
671 | ASSERT_THAT_ERROR(Writer.writeSLEB128(Value), Succeeded()); |
672 | |
673 | // Read fields. |
674 | BinaryStreamReader Reader(*Stream.Input); |
675 | std::vector<int64_t> Results; |
676 | Results.resize(new_size: TestValues.size()); |
677 | for (unsigned I = 0; I != TestValues.size(); ++I) |
678 | ASSERT_THAT_ERROR(Reader.readSLEB128(Results[I]), Succeeded()); |
679 | |
680 | for (unsigned I = 0; I != TestValues.size(); ++I) |
681 | EXPECT_EQ(TestValues[I], Results[I]); |
682 | } |
683 | } |
684 | |
685 | TEST_F(BinaryStreamTest, StreamReaderObject) { |
686 | struct Foo { |
687 | int X; |
688 | double Y; |
689 | char Z; |
690 | |
691 | bool operator==(const Foo &Other) const { |
692 | return X == Other.X && Y == Other.Y && Z == Other.Z; |
693 | } |
694 | }; |
695 | |
696 | std::vector<Foo> Foos; |
697 | Foos.push_back(x: {.X: -42, .Y: 42.42, .Z: 42}); |
698 | Foos.push_back(x: {.X: 100, .Y: 3.1415, .Z: static_cast<char>(-89)}); |
699 | Foos.push_back(x: {.X: 200, .Y: 2.718, .Z: static_cast<char>(-12) }); |
700 | |
701 | const uint8_t *Bytes = reinterpret_cast<const uint8_t *>(&Foos[0]); |
702 | |
703 | initializeInput(Input: ArrayRef(Bytes, 3 * sizeof(Foo)), Align: alignof(Foo)); |
704 | |
705 | for (auto &Stream : Streams) { |
706 | // 1. Reading object pointers. |
707 | BinaryStreamReader Reader(*Stream.Input); |
708 | const Foo *FPtrOut = nullptr; |
709 | const Foo *GPtrOut = nullptr; |
710 | const Foo *HPtrOut = nullptr; |
711 | ASSERT_THAT_ERROR(Reader.readObject(FPtrOut), Succeeded()); |
712 | ASSERT_THAT_ERROR(Reader.readObject(GPtrOut), Succeeded()); |
713 | ASSERT_THAT_ERROR(Reader.readObject(HPtrOut), Succeeded()); |
714 | EXPECT_EQ(0U, Reader.bytesRemaining()); |
715 | EXPECT_EQ(Foos[0], *FPtrOut); |
716 | EXPECT_EQ(Foos[1], *GPtrOut); |
717 | EXPECT_EQ(Foos[2], *HPtrOut); |
718 | } |
719 | } |
720 | |
721 | TEST_F(BinaryStreamTest, StreamReaderStrings) { |
722 | std::vector<uint8_t> Bytes = {'O', 'n', 'e', '\0', 'T', 'w', 'o', |
723 | '\0', 'T', 'h', 'r', 'e', 'e', '\0', |
724 | 'F', 'o', 'u', 'r', '\0'}; |
725 | initializeInput(Input: Bytes, Align: 1); |
726 | |
727 | for (auto &Stream : Streams) { |
728 | BinaryStreamReader Reader(*Stream.Input); |
729 | |
730 | StringRef S1; |
731 | StringRef S2; |
732 | StringRef S3; |
733 | StringRef S4; |
734 | ASSERT_THAT_ERROR(Reader.readCString(S1), Succeeded()); |
735 | ASSERT_THAT_ERROR(Reader.readCString(S2), Succeeded()); |
736 | ASSERT_THAT_ERROR(Reader.readCString(S3), Succeeded()); |
737 | ASSERT_THAT_ERROR(Reader.readCString(S4), Succeeded()); |
738 | ASSERT_EQ(0U, Reader.bytesRemaining()); |
739 | |
740 | EXPECT_EQ("One" , S1); |
741 | EXPECT_EQ("Two" , S2); |
742 | EXPECT_EQ("Three" , S3); |
743 | EXPECT_EQ("Four" , S4); |
744 | |
745 | S1 = S2 = S3 = S4 = "" ; |
746 | Reader.setOffset(0); |
747 | ASSERT_THAT_ERROR(Reader.readFixedString(S1, 3), Succeeded()); |
748 | ASSERT_THAT_ERROR(Reader.skip(1), Succeeded()); |
749 | ASSERT_THAT_ERROR(Reader.readFixedString(S2, 3), Succeeded()); |
750 | ASSERT_THAT_ERROR(Reader.skip(1), Succeeded()); |
751 | ASSERT_THAT_ERROR(Reader.readFixedString(S3, 5), Succeeded()); |
752 | ASSERT_THAT_ERROR(Reader.skip(1), Succeeded()); |
753 | ASSERT_THAT_ERROR(Reader.readFixedString(S4, 4), Succeeded()); |
754 | ASSERT_THAT_ERROR(Reader.skip(1), Succeeded()); |
755 | ASSERT_EQ(0U, Reader.bytesRemaining()); |
756 | |
757 | EXPECT_EQ("One" , S1); |
758 | EXPECT_EQ("Two" , S2); |
759 | EXPECT_EQ("Three" , S3); |
760 | EXPECT_EQ("Four" , S4); |
761 | } |
762 | } |
763 | |
764 | TEST_F(BinaryStreamTest, StreamWriterBounds) { |
765 | initializeOutput(Size: 5, Align: 1); |
766 | |
767 | for (auto &Stream : Streams) { |
768 | BinaryStreamWriter Writer(*Stream.Output); |
769 | |
770 | // 1. Can write a string that exactly fills the buffer. |
771 | EXPECT_EQ(5U, Writer.bytesRemaining()); |
772 | EXPECT_THAT_ERROR(Writer.writeFixedString("abcde" ), Succeeded()); |
773 | EXPECT_EQ(0U, Writer.bytesRemaining()); |
774 | |
775 | // 2. Can write an empty string even when you're full |
776 | EXPECT_THAT_ERROR(Writer.writeFixedString("" ), Succeeded()); |
777 | EXPECT_THAT_ERROR(Writer.writeFixedString("a" ), Failed()); |
778 | |
779 | // 3. Can't write a string that is one character too long. |
780 | Writer.setOffset(0); |
781 | EXPECT_THAT_ERROR(Writer.writeFixedString("abcdef" ), Failed()); |
782 | } |
783 | } |
784 | |
785 | TEST_F(BinaryStreamTest, StreamWriterIntegerArrays) { |
786 | // 3. Arrays of integers |
787 | std::vector<int> SourceInts = {1, 2, 3, 4, 5}; |
788 | ArrayRef<uint8_t> SourceBytes(reinterpret_cast<uint8_t *>(&SourceInts[0]), |
789 | SourceInts.size() * sizeof(int)); |
790 | |
791 | initializeInput(Input: SourceBytes, Align: alignof(int)); |
792 | initializeOutputFromInput(Align: alignof(int)); |
793 | |
794 | for (auto &Stream : Streams) { |
795 | BinaryStreamReader Reader(*Stream.Input); |
796 | BinaryStreamWriter Writer(*Stream.Output); |
797 | ArrayRef<int> Ints; |
798 | ArrayRef<int> Ints2; |
799 | // First read them, then write them, then read them back. |
800 | ASSERT_THAT_ERROR(Reader.readArray(Ints, SourceInts.size()), Succeeded()); |
801 | ASSERT_THAT_ERROR(Writer.writeArray(Ints), Succeeded()); |
802 | |
803 | BinaryStreamReader ReaderBacker(*Stream.Output); |
804 | ASSERT_THAT_ERROR(ReaderBacker.readArray(Ints2, SourceInts.size()), |
805 | Succeeded()); |
806 | |
807 | EXPECT_EQ(ArrayRef(SourceInts), Ints2); |
808 | } |
809 | } |
810 | |
811 | TEST_F(BinaryStreamTest, StreamWriterStrings) { |
812 | StringRef Strings[] = {"First" , "Second" , "Third" , "Fourth" }; |
813 | |
814 | size_t Length = 0; |
815 | for (auto S : Strings) |
816 | Length += S.size() + 1; |
817 | initializeOutput(Size: Length, Align: 1); |
818 | initializeInputFromOutput(Align: 1); |
819 | |
820 | for (auto &Stream : Streams) { |
821 | BinaryStreamWriter Writer(*Stream.Output); |
822 | for (auto S : Strings) |
823 | ASSERT_THAT_ERROR(Writer.writeCString(S), Succeeded()); |
824 | std::vector<StringRef> InStrings; |
825 | BinaryStreamReader Reader(*Stream.Input); |
826 | while (!Reader.empty()) { |
827 | StringRef S; |
828 | ASSERT_THAT_ERROR(Reader.readCString(S), Succeeded()); |
829 | InStrings.push_back(x: S); |
830 | } |
831 | EXPECT_EQ(ArrayRef(Strings), ArrayRef(InStrings)); |
832 | } |
833 | } |
834 | |
835 | TEST_F(BinaryStreamTest, StreamWriterPadToAlignment) { |
836 | // This test may seem excessive but it is checking for past bugs and corner |
837 | // cases by making sure that the stream is allowed to grow and that |
838 | // both multiple pad chunks and single chunk extensions work. |
839 | AppendingBinaryByteStream Stream(llvm::endianness::little); |
840 | BinaryStreamWriter Writer(Stream); |
841 | |
842 | // Offset 0: '0' |
843 | EXPECT_THAT_ERROR(Writer.writeInteger('0'), Succeeded()); |
844 | // Offset 1..110: 0 |
845 | EXPECT_THAT_ERROR(Writer.padToAlignment(111), Succeeded()); |
846 | // Offset 111: '*' |
847 | EXPECT_THAT_ERROR(Writer.writeInteger('*'), Succeeded()); |
848 | // Offset 112..120: 0 |
849 | EXPECT_THAT_ERROR(Writer.padToAlignment(11), Succeeded()); |
850 | |
851 | BinaryStreamReader Reader(Stream); |
852 | char c; |
853 | // Offset 0 |
854 | EXPECT_THAT_ERROR(Reader.readInteger<char>(c), Succeeded()); |
855 | EXPECT_EQ('0', c); |
856 | // Offset 1..110 |
857 | for (int i = 0; i < 110; ++i) { |
858 | char c; |
859 | EXPECT_THAT_ERROR(Reader.readInteger<char>(c), Succeeded()); |
860 | EXPECT_EQ('\0', c); |
861 | } |
862 | // Offset 111 |
863 | EXPECT_THAT_ERROR(Reader.readInteger<char>(c), Succeeded()); |
864 | EXPECT_EQ('*', c); |
865 | // Offset 112..120 |
866 | for (int i = 0; i < 9; ++i) { |
867 | char c; |
868 | EXPECT_THAT_ERROR(Reader.readInteger<char>(c), Succeeded()); |
869 | EXPECT_EQ('\0', c); |
870 | } |
871 | |
872 | // EOF. |
873 | EXPECT_THAT_ERROR(Reader.readInteger<char>(c), Failed()); |
874 | } |
875 | |
876 | TEST_F(BinaryStreamTest, StreamWriterAppend) { |
877 | StringRef Strings[] = {"First" , "Second" , "Third" , "Fourth" }; |
878 | AppendingBinaryByteStream Stream(llvm::endianness::little); |
879 | BinaryStreamWriter Writer(Stream); |
880 | |
881 | for (auto &Str : Strings) { |
882 | EXPECT_THAT_ERROR(Writer.writeCString(Str), Succeeded()); |
883 | } |
884 | |
885 | BinaryStreamReader Reader(Stream); |
886 | for (auto &Str : Strings) { |
887 | StringRef S; |
888 | EXPECT_THAT_ERROR(Reader.readCString(S), Succeeded()); |
889 | EXPECT_EQ(Str, S); |
890 | } |
891 | } |
892 | } |
893 | |
894 | namespace { |
895 | struct BinaryItemStreamObject { |
896 | explicit BinaryItemStreamObject(ArrayRef<uint8_t> Bytes) : Bytes(Bytes) {} |
897 | |
898 | ArrayRef<uint8_t> Bytes; |
899 | }; |
900 | } |
901 | |
902 | namespace llvm { |
903 | template <> struct BinaryItemTraits<BinaryItemStreamObject> { |
904 | static size_t length(const BinaryItemStreamObject &Item) { |
905 | return Item.Bytes.size(); |
906 | } |
907 | |
908 | static ArrayRef<uint8_t> bytes(const BinaryItemStreamObject &Item) { |
909 | return Item.Bytes; |
910 | } |
911 | }; |
912 | } |
913 | |
914 | namespace { |
915 | |
916 | TEST_F(BinaryStreamTest, BinaryItemStream) { |
917 | std::vector<BinaryItemStreamObject> Objects; |
918 | |
919 | struct Foo { |
920 | int X; |
921 | double Y; |
922 | }; |
923 | std::vector<Foo> Foos = {{.X: 1, .Y: 1.0}, {.X: 2, .Y: 2.0}, {.X: 3, .Y: 3.0}}; |
924 | BumpPtrAllocator Allocator; |
925 | for (const auto &F : Foos) { |
926 | uint8_t *Ptr = static_cast<uint8_t *>(Allocator.Allocate(Size: sizeof(Foo), |
927 | Alignment: alignof(Foo))); |
928 | MutableArrayRef<uint8_t> Buffer(Ptr, sizeof(Foo)); |
929 | MutableBinaryByteStream Stream(Buffer, llvm::endianness::big); |
930 | BinaryStreamWriter Writer(Stream); |
931 | ASSERT_THAT_ERROR(Writer.writeObject(F), Succeeded()); |
932 | Objects.push_back(x: BinaryItemStreamObject(Buffer)); |
933 | } |
934 | |
935 | BinaryItemStream<BinaryItemStreamObject> ItemStream(llvm::endianness::big); |
936 | ItemStream.setItems(Objects); |
937 | BinaryStreamReader Reader(ItemStream); |
938 | |
939 | for (const auto &F : Foos) { |
940 | const Foo *F2; |
941 | ASSERT_THAT_ERROR(Reader.readObject(F2), Succeeded()); |
942 | |
943 | EXPECT_EQ(F.X, F2->X); |
944 | EXPECT_DOUBLE_EQ(F.Y, F2->Y); |
945 | } |
946 | } |
947 | |
948 | } // end anonymous namespace |
949 | |