1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <array>
16 #include <string>
17 #if __cplusplus >= 201703L
18 #include <cstddef> // std::byte
19 #include <string_view>
20 #endif // __cplusplus >= 201703L
21 #include <vector>
22
23 #include "gtest/gtest.h"
24 #include "runtime/cpp/emboss_memory_util.h"
25 #include "runtime/cpp/emboss_prelude.h"
26
27 namespace emboss {
28 namespace support {
29 namespace test {
30
31 using ::emboss::prelude::IntView;
32 using ::emboss::prelude::UIntView;
33
34 template </**/ ::std::size_t kBits>
35 using BigEndianBitBlockN =
36 BitBlock<BigEndianByteOrderer<ReadWriteContiguousBuffer>, kBits>;
37
38 template </**/ ::std::size_t kBits>
39 using LittleEndianBitBlockN =
40 BitBlock<LittleEndianByteOrderer<ReadWriteContiguousBuffer>, kBits>;
41
42 template <typename T, typename... Args>
init_array(Args &&...args)43 std::array<T, sizeof...(Args)> constexpr init_array(Args &&...args) {
44 return {T(std::forward<Args>(args))...};
45 }
46
47 template <typename Container, typename... Args>
init_container(Args &&...args)48 auto constexpr init_container(Args &&...args) -> Container {
49 using CharType =
50 typename ::std::remove_reference<decltype(*Container().data())>::type;
51 return {CharType(std::forward<Args>(args))...};
52 }
53
TEST(GreatestCommonDivisor,GreatestCommonDivisor)54 TEST(GreatestCommonDivisor, GreatestCommonDivisor) {
55 EXPECT_EQ(4U, GreatestCommonDivisor(12, 20));
56 EXPECT_EQ(4U, GreatestCommonDivisor(20, 12));
57 EXPECT_EQ(4U, GreatestCommonDivisor(20, 4));
58 EXPECT_EQ(6U, GreatestCommonDivisor(12, 78));
59 EXPECT_EQ(6U, GreatestCommonDivisor(6, 0));
60 EXPECT_EQ(6U, GreatestCommonDivisor(0, 6));
61 EXPECT_EQ(3U, GreatestCommonDivisor(9, 6));
62 EXPECT_EQ(0U, GreatestCommonDivisor(0, 0));
63 }
64
65 // Because MemoryAccessor's parameters are template parameters, it is not
66 // possible to loop through them directly. Instead, TestMemoryAccessor tests
67 // a particular MemoryAccessor's methods, then calls the next template to test
68 // the next set of template parameters to MemoryAccessor.
69 template <typename CharT, ::std::size_t kAlignment, ::std::size_t kOffset,
70 ::std::size_t kBits>
TestMemoryAccessor()71 void TestMemoryAccessor() {
72 alignas(kAlignment) auto bytes =
73 init_array<CharT>(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08);
74 EXPECT_EQ(
75 0x0807060504030201UL & (~0x0UL >> (64 - kBits)),
76 (MemoryAccessor<CharT, kAlignment, kOffset, kBits>::ReadLittleEndianUInt(
77 bytes.data())))
78 << "kAlignment = " << kAlignment << "; kOffset = " << kOffset
79 << "; kBits = " << kBits;
80 EXPECT_EQ(
81 0x0102030405060708UL >> (64 - kBits),
82 (MemoryAccessor<CharT, kAlignment, kOffset, kBits>::ReadBigEndianUInt(
83 bytes.data())))
84 << "kAlignment = " << kAlignment << "; kOffset = " << kOffset
85 << "; kBits = " << kBits;
86
87 MemoryAccessor<CharT, kAlignment, kOffset, kBits>::WriteLittleEndianUInt(
88 bytes.data(), 0x7172737475767778UL & (~0x0UL >> (64 - kBits)));
89 auto expected_vector_after_write = init_container<std::vector<CharT>>(
90 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71);
91 for (int i = kBits / 8; i < 8; ++i) {
92 expected_vector_after_write[i] = CharT(i + 1);
93 }
94 EXPECT_EQ(expected_vector_after_write,
95 ::std::vector<CharT>(std::begin(bytes), std::end(bytes)))
96 << "kAlignment = " << kAlignment << "; kOffset = " << kOffset
97 << "; kBits = " << kBits;
98
99 MemoryAccessor<CharT, kAlignment, kOffset, kBits>::WriteBigEndianUInt(
100 bytes.data(), 0x7172737475767778UL >> (64 - kBits));
101 expected_vector_after_write = init_container<std::vector<CharT>>(
102 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78);
103 for (int i = kBits / 8; i < 8; ++i) {
104 expected_vector_after_write[i] = CharT(i + 1);
105 }
106 EXPECT_EQ(expected_vector_after_write,
107 ::std::vector<CharT>(std::begin(bytes), std::end(bytes)))
108 << "kAlignment = " << kAlignment << "; kOffset = " << kOffset
109 << "; kBits = " << kBits;
110
111 // Recursively iterate the template:
112 //
113 // For every kAlignment/kOffset pair, check kBits from 64 to 8 in increments
114 // of 8.
115 //
116 // If kBits is 8, reset kBits to 64 and go to the next kAlignment/kOffset
117 // pair.
118 //
119 // For each kAlignment, try all kOffsets from 0 to kAlignment - 1.
120 //
121 // If kBits is 8 and kOffset is kAlignment - 1, reset kBits to 64, kOffset to
122 // 0, and halve kAlignment.
123 //
124 // Base cases below handle kAlignment == 0, terminating the recursion.
125 TestMemoryAccessor<
126 CharT,
127 kBits == 8 && kAlignment == kOffset + 1 ? kAlignment / 2 : kAlignment,
128 kBits == 8 ? kAlignment == kOffset + 1 ? 0 : kOffset + 1 : kOffset,
129 kBits == 8 ? 64 : kBits - 8>();
130 }
131
132 template <>
TestMemoryAccessor()133 void TestMemoryAccessor<char, 0, 0, 64>() {}
134
135 #if __cplusplus >= 201703L
136 template <>
TestMemoryAccessor()137 void TestMemoryAccessor<std::byte, 0, 0, 64>() {}
138 #endif
139
140 template <>
TestMemoryAccessor()141 void TestMemoryAccessor<unsigned char, 0, 0, 64>() {}
142
TEST(MemoryAccessor,LittleEndianReads)143 TEST(MemoryAccessor, LittleEndianReads) {
144 TestMemoryAccessor<char, 8, 0, 64>();
145 #if __cplusplus >= 201703L
146 TestMemoryAccessor<std::byte, 8, 0, 64>();
147 #endif
148 TestMemoryAccessor<unsigned char, 8, 0, 64>();
149 }
150
TEST(ContiguousBuffer,OffsetStorageType)151 TEST(ContiguousBuffer, OffsetStorageType) {
152 EXPECT_TRUE((::std::is_same<
153 ContiguousBuffer<char, 2, 0>,
154 ContiguousBuffer<char, 2, 0>::OffsetStorageType<2, 0>>::value));
155 EXPECT_TRUE((::std::is_same<
156 ContiguousBuffer<char, 2, 0>,
157 ContiguousBuffer<char, 2, 0>::OffsetStorageType<0, 0>>::value));
158 EXPECT_TRUE((::std::is_same<
159 ContiguousBuffer<char, 2, 0>,
160 ContiguousBuffer<char, 2, 0>::OffsetStorageType<4, 0>>::value));
161 EXPECT_TRUE((::std::is_same<
162 ContiguousBuffer<char, 2, 0>,
163 ContiguousBuffer<char, 4, 0>::OffsetStorageType<2, 0>>::value));
164 EXPECT_TRUE((::std::is_same<
165 ContiguousBuffer<char, 2, 0>,
166 ContiguousBuffer<char, 4, 2>::OffsetStorageType<2, 0>>::value));
167 EXPECT_TRUE((::std::is_same<
168 ContiguousBuffer<char, 2, 0>,
169 ContiguousBuffer<char, 4, 1>::OffsetStorageType<2, 1>>::value));
170 EXPECT_TRUE((::std::is_same<
171 ContiguousBuffer<char, 4, 2>,
172 ContiguousBuffer<char, 4, 1>::OffsetStorageType<4, 1>>::value));
173 EXPECT_TRUE((::std::is_same<
174 ContiguousBuffer<char, 4, 1>,
175 ContiguousBuffer<char, 4, 3>::OffsetStorageType<0, 2>>::value));
176 EXPECT_TRUE((::std::is_same<
177 ContiguousBuffer<char, 4, 1>,
178 ContiguousBuffer<char, 4, 3>::OffsetStorageType<4, 2>>::value));
179 EXPECT_TRUE((::std::is_same<
180 ContiguousBuffer<char, 4, 1>,
181 ContiguousBuffer<char, 4, 3>::OffsetStorageType<8, 6>>::value));
182 EXPECT_TRUE((::std::is_same<
183 ContiguousBuffer<char, 4, 1>,
184 ContiguousBuffer<char, 4, 3>::OffsetStorageType<12, 6>>::value));
185 EXPECT_TRUE((::std::is_same<
186 ContiguousBuffer<char, 1, 0>,
187 ContiguousBuffer<char, 4, 1>::OffsetStorageType<3, 1>>::value));
188 }
189
190 // Minimal class that forwards to std::allocator. Used to test that
191 // ReadOnlyContiguousBuffer can be constructed from std::vector<> and
192 // std::basic_string<> with non-default trailing template parameters.
193 template <class T>
194 struct NonstandardAllocator {
195 using value_type =
196 typename ::std::allocator_traits<::std::allocator<T>>::value_type;
197 using pointer =
198 typename ::std::allocator_traits<::std::allocator<T>>::pointer;
199 using const_pointer =
200 typename ::std::allocator_traits<::std::allocator<T>>::const_pointer;
201 using reference = typename ::std::allocator<T>::value_type &;
202 using const_reference =
203 const typename ::std::allocator_traits<::std::allocator<T>>::value_type &;
204 using size_type =
205 typename ::std::allocator_traits<::std::allocator<T>>::size_type;
206 using difference_type =
207 typename ::std::allocator_traits<::std::allocator<T>>::difference_type;
208
209 template <class U>
210 struct rebind {
211 using other = NonstandardAllocator<U>;
212 };
213
214 NonstandardAllocator() = default;
215 // This constructor is *not* explicit in order to conform to the requirements
216 // for an allocator.
217 template <class U>
NonstandardAllocatoremboss::support::test::NonstandardAllocator218 NonstandardAllocator(const NonstandardAllocator<U> &) {} // NOLINT
219
allocateemboss::support::test::NonstandardAllocator220 T *allocate(::std::size_t n) { return ::std::allocator<T>().allocate(n); }
deallocateemboss::support::test::NonstandardAllocator221 void deallocate(T *p, ::std::size_t n) {
222 ::std::allocator<T>().deallocate(p, n);
223 }
224
max_sizeemboss::support::test::NonstandardAllocator225 static size_type max_size() {
226 return ::std::numeric_limits<size_type>::max() / sizeof(value_type);
227 }
228 };
229
230 template <class T, class U>
operator ==(const NonstandardAllocator<T> &,const NonstandardAllocator<U> &)231 bool operator==(const NonstandardAllocator<T> &,
232 const NonstandardAllocator<U> &) {
233 return true;
234 }
235
236 template <class T, class U>
operator !=(const NonstandardAllocator<T> &,const NonstandardAllocator<U> &)237 bool operator!=(const NonstandardAllocator<T> &,
238 const NonstandardAllocator<U> &) {
239 return false;
240 }
241
242 // ContiguousBuffer tests for std::vector, std::array, and std::string types.
243 template <typename T>
244 class ReadOnlyContiguousBufferTest : public ::testing::Test {};
245 typedef ::testing::Types<
246 /**/ ::std::vector<char>, ::std::array<char, 8>,
247 ::std::vector<unsigned char>,
248 #if __cplusplus >= 201703L
249 ::std::vector<std::byte>,
250 #endif
251 ::std::string, ::std::basic_string<char>,
252 ::std::vector<unsigned char, NonstandardAllocator<unsigned char>>,
253 ::std::basic_string<char, ::std::char_traits<char>,
254 NonstandardAllocator<char>>>
255 ReadOnlyContiguousContainerTypes;
256 TYPED_TEST_SUITE(ReadOnlyContiguousBufferTest,
257 ReadOnlyContiguousContainerTypes);
258
TYPED_TEST(ReadOnlyContiguousBufferTest,ConstructionFromContainers)259 TYPED_TEST(ReadOnlyContiguousBufferTest, ConstructionFromContainers) {
260 const TypeParam bytes =
261 init_container<TypeParam>(0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01);
262 using CharType =
263 typename ::std::remove_reference<decltype(*bytes.data())>::type;
264 const auto buffer = ContiguousBuffer<const CharType, 1, 0>{&bytes};
265 EXPECT_EQ(bytes.size(), buffer.SizeInBytes());
266 EXPECT_TRUE(buffer.Ok());
267 EXPECT_EQ(0x0807060504030201UL, buffer.template ReadBigEndianUInt<64>());
268
269 const auto offset_buffer = buffer.template GetOffsetStorage<1, 0>(4, 4);
270 EXPECT_EQ(4U, offset_buffer.SizeInBytes());
271 EXPECT_EQ(0x04030201U, offset_buffer.template ReadBigEndianUInt<32>());
272
273 // The size of the resulting buffer should be the minimum of the available
274 // size and the requested size.
275 EXPECT_EQ(bytes.size() - 4,
276 (buffer.template GetOffsetStorage<1, 0>(2, bytes.size() - 4)
277 .SizeInBytes()));
278 EXPECT_EQ(
279 0U,
280 (buffer.template GetOffsetStorage<1, 0>(bytes.size(), 4).SizeInBytes()));
281 }
282
283 // ContiguousBuffer tests for std::vector and std::array types.
284 template <typename T>
285 class ReadWriteContiguousBufferTest : public ::testing::Test {};
286 typedef ::testing::Types</**/ ::std::vector<char>, ::std::array<char, 8>,
287 #if __cplusplus >= 201703L
288 ::std::vector<std::byte>,
289 #endif
290 ::std::vector<unsigned char>>
291 ReadWriteContiguousContainerTypes;
292 TYPED_TEST_SUITE(ReadWriteContiguousBufferTest,
293 ReadWriteContiguousContainerTypes);
294
TYPED_TEST(ReadWriteContiguousBufferTest,ConstructionFromContainers)295 TYPED_TEST(ReadWriteContiguousBufferTest, ConstructionFromContainers) {
296 TypeParam bytes =
297 init_container<TypeParam>(0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01);
298 using CharType =
299 typename ::std::remove_reference<decltype(*bytes.data())>::type;
300 const auto buffer = ContiguousBuffer<CharType, 1, 0>{&bytes};
301
302 // Read and Ok methods should work just as in ReadOnlyContiguousBuffer.
303 EXPECT_EQ(bytes.size(), buffer.SizeInBytes());
304 EXPECT_TRUE(buffer.Ok());
305 EXPECT_EQ(0x0807060504030201UL, buffer.template ReadBigEndianUInt<64>());
306
307 buffer.template WriteBigEndianUInt<64>(0x0102030405060708UL);
308 EXPECT_EQ((init_container<TypeParam>(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
309 0x08)),
310 bytes);
311
312 bytes[4] = static_cast<CharType>(255);
313 EXPECT_EQ(0x1020304ff060708UL, buffer.template ReadBigEndianUInt<64>());
314 }
315
TEST(ContiguousBuffer,ReturnTypeOfReadUInt)316 TEST(ContiguousBuffer, ReturnTypeOfReadUInt) {
317 const auto buffer = ContiguousBuffer<char, 1, 0>();
318
319 EXPECT_TRUE((::std::is_same<decltype(buffer.ReadBigEndianUInt<64>()),
320 ::std::uint64_t>::value));
321 EXPECT_TRUE((::std::is_same<decltype(buffer.ReadBigEndianUInt<48>()),
322 ::std::uint64_t>::value));
323 EXPECT_TRUE((::std::is_same<decltype(buffer.ReadBigEndianUInt<32>()),
324 ::std::uint32_t>::value));
325 EXPECT_TRUE((::std::is_same<decltype(buffer.ReadBigEndianUInt<16>()),
326 ::std::uint16_t>::value));
327 EXPECT_TRUE((::std::is_same<decltype(buffer.ReadBigEndianUInt<8>()),
328 ::std::uint8_t>::value));
329
330 EXPECT_TRUE((::std::is_same<decltype(buffer.ReadLittleEndianUInt<64>()),
331 ::std::uint64_t>::value));
332 EXPECT_TRUE((::std::is_same<decltype(buffer.ReadLittleEndianUInt<48>()),
333 ::std::uint64_t>::value));
334 EXPECT_TRUE((::std::is_same<decltype(buffer.ReadLittleEndianUInt<32>()),
335 ::std::uint32_t>::value));
336 EXPECT_TRUE((::std::is_same<decltype(buffer.ReadLittleEndianUInt<16>()),
337 ::std::uint16_t>::value));
338 EXPECT_TRUE((::std::is_same<decltype(buffer.ReadLittleEndianUInt<8>()),
339 ::std::uint8_t>::value));
340
341 EXPECT_TRUE((::std::is_same<decltype(buffer.UncheckedReadBigEndianUInt<64>()),
342 ::std::uint64_t>::value));
343 EXPECT_TRUE((::std::is_same<decltype(buffer.UncheckedReadBigEndianUInt<48>()),
344 ::std::uint64_t>::value));
345 EXPECT_TRUE((::std::is_same<decltype(buffer.UncheckedReadBigEndianUInt<32>()),
346 ::std::uint32_t>::value));
347 EXPECT_TRUE((::std::is_same<decltype(buffer.UncheckedReadBigEndianUInt<16>()),
348 ::std::uint16_t>::value));
349 EXPECT_TRUE((::std::is_same<decltype(buffer.UncheckedReadBigEndianUInt<8>()),
350 ::std::uint8_t>::value));
351
352 EXPECT_TRUE(
353 (::std::is_same<decltype(buffer.UncheckedReadLittleEndianUInt<64>()),
354 ::std::uint64_t>::value));
355 EXPECT_TRUE(
356 (::std::is_same<decltype(buffer.UncheckedReadLittleEndianUInt<48>()),
357 ::std::uint64_t>::value));
358 EXPECT_TRUE(
359 (::std::is_same<decltype(buffer.UncheckedReadLittleEndianUInt<32>()),
360 ::std::uint32_t>::value));
361 EXPECT_TRUE(
362 (::std::is_same<decltype(buffer.UncheckedReadLittleEndianUInt<16>()),
363 ::std::uint16_t>::value));
364 EXPECT_TRUE(
365 (::std::is_same<decltype(buffer.UncheckedReadLittleEndianUInt<8>()),
366 ::std::uint8_t>::value));
367 }
368
TEST(ReadOnlyContiguousBuffer,Methods)369 TEST(ReadOnlyContiguousBuffer, Methods) {
370 const ::std::vector</**/ ::std::uint8_t> bytes = {
371 {0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05,
372 0x04, 0x03, 0x02, 0x01}};
373 const auto buffer = ReadOnlyContiguousBuffer{bytes.data(), bytes.size() - 4};
374 #if EMBOSS_CHECK_ABORTS
375 EXPECT_DEATH(buffer.ReadBigEndianUInt<64>(), "");
376 #endif // EMBOSS_CHECK_ABORTS
377 EXPECT_TRUE(buffer.Ok());
378 EXPECT_EQ(bytes.size() - 4, buffer.SizeInBytes());
379 EXPECT_EQ(0x100f0e0d0c0b0a09UL, buffer.UncheckedReadBigEndianUInt<64>());
380 EXPECT_EQ(0x090a0b0c0d0e0f10UL, buffer.UncheckedReadLittleEndianUInt<64>());
381
382 const auto offset_buffer = buffer.GetOffsetStorage<1, 0>(4, 4);
383 EXPECT_EQ(0x0c0b0a09U, offset_buffer.ReadBigEndianUInt<32>());
384 EXPECT_EQ(0x090a0b0cU, offset_buffer.ReadLittleEndianUInt<32>());
385 EXPECT_EQ(0x0c0b0a0908070605UL,
386 offset_buffer.UncheckedReadBigEndianUInt<64>());
387 EXPECT_EQ(4U, offset_buffer.SizeInBytes());
388 EXPECT_TRUE(offset_buffer.Ok());
389
390 const auto small_offset_buffer = buffer.GetOffsetStorage<1, 0>(4, 1);
391 EXPECT_EQ(0x0cU, small_offset_buffer.ReadBigEndianUInt<8>());
392 EXPECT_EQ(0x0cU, small_offset_buffer.ReadLittleEndianUInt<8>());
393 EXPECT_EQ(1U, small_offset_buffer.SizeInBytes());
394 EXPECT_TRUE(small_offset_buffer.Ok());
395
396 EXPECT_FALSE(ReadOnlyContiguousBuffer().Ok());
397 EXPECT_FALSE(
398 (ReadOnlyContiguousBuffer{static_cast<char *>(nullptr), 12}.Ok()));
399 #if EMBOSS_CHECK_ABORTS
400 EXPECT_DEATH((ReadOnlyContiguousBuffer{static_cast<char *>(nullptr), 4}
401 .ReadBigEndianUInt<32>()),
402 "");
403 #endif // EMBOSS_CHECK_ABORTS
404 EXPECT_EQ(0U, ReadOnlyContiguousBuffer().SizeInBytes());
405 EXPECT_EQ(0U, (ReadOnlyContiguousBuffer{static_cast<char *>(nullptr), 12}
406 .SizeInBytes()));
407 #if EMBOSS_CHECK_ABORTS
408 EXPECT_DEATH(
409 (ReadOnlyContiguousBuffer{bytes.data(), 0}.ReadBigEndianUInt<8>()), "");
410 #endif // EMBOSS_CHECK_ABORTS
411
412 // The size of the resulting buffer should be the minimum of the available
413 // size and the requested size.
414 EXPECT_EQ(bytes.size() - 8,
415 (buffer.GetOffsetStorage<1, 0>(4, bytes.size() - 4).SizeInBytes()));
416 EXPECT_EQ(4U, (buffer.GetOffsetStorage<1, 0>(0, 4).SizeInBytes()));
417 EXPECT_EQ(0U, (buffer.GetOffsetStorage<1, 0>(bytes.size(), 4).SizeInBytes()));
418 EXPECT_FALSE((ReadOnlyContiguousBuffer().GetOffsetStorage<1, 0>(0, 0).Ok()));
419 }
420
TEST(ReadWriteContiguousBuffer,Methods)421 TEST(ReadWriteContiguousBuffer, Methods) {
422 ::std::vector</**/ ::std::uint8_t> bytes = {
423 {0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}};
424 const auto buffer = ReadWriteContiguousBuffer{bytes.data(), bytes.size() - 4};
425 // Read and Ok methods should work just as in ReadOnlyContiguousBuffer.
426 EXPECT_TRUE(buffer.Ok());
427 EXPECT_EQ(bytes.size() - 4U, buffer.SizeInBytes());
428 EXPECT_EQ(0x0c0b0a0908070605UL, buffer.ReadBigEndianUInt<64>());
429
430 buffer.WriteBigEndianUInt<64>(0x05060708090a0b0c);
431 EXPECT_EQ(
432 (::std::vector</**/ ::std::uint8_t>{0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
433 0x0b, 0x0c, 0x04, 0x03, 0x02, 0x01}),
434 bytes);
435 buffer.WriteLittleEndianUInt<64>(0x05060708090a0b0c);
436 EXPECT_EQ(
437 (::std::vector</**/ ::std::uint8_t>{0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
438 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}),
439 bytes);
440
441 const auto offset_buffer = buffer.GetOffsetStorage<1, 0>(4, 4);
442 offset_buffer.WriteBigEndianUInt<32>(0x05060708);
443 EXPECT_EQ(
444 (::std::vector</**/ ::std::uint8_t>{0x0c, 0x0b, 0x0a, 0x09, 0x05, 0x06,
445 0x07, 0x08, 0x04, 0x03, 0x02, 0x01}),
446 bytes);
447 offset_buffer.WriteLittleEndianUInt<32>(0x05060708);
448 EXPECT_EQ(
449 (::std::vector</**/ ::std::uint8_t>{0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
450 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}),
451 bytes);
452
453 const auto small_offset_buffer = buffer.GetOffsetStorage<1, 0>(4, 1);
454 small_offset_buffer.WriteBigEndianUInt<8>(0x80);
455 EXPECT_EQ(
456 (::std::vector</**/ ::std::uint8_t>{0x0c, 0x0b, 0x0a, 0x09, 0x80, 0x07,
457 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}),
458 bytes);
459 small_offset_buffer.WriteLittleEndianUInt<8>(0x08);
460 EXPECT_EQ(
461 (::std::vector</**/ ::std::uint8_t>{0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
462 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}),
463 bytes);
464
465 #if EMBOSS_CHECK_ABORTS
466 EXPECT_DEATH(ReadWriteContiguousBuffer().ReadLittleEndianUInt<8>(), "");
467 EXPECT_DEATH(
468 (ReadWriteContiguousBuffer{static_cast<unsigned char *>(nullptr), 1}
469 .ReadLittleEndianUInt<8>()),
470 "");
471 EXPECT_DEATH(
472 (ReadWriteContiguousBuffer{static_cast<unsigned char *>(nullptr), 1}
473 .WriteLittleEndianUInt<8>(0xff)),
474 "");
475 #endif // EMBOSS_CHECK_ABORTS
476 }
477
TEST(ContiguousBuffer,AssignmentFromCompatibleContiguousBuffers)478 TEST(ContiguousBuffer, AssignmentFromCompatibleContiguousBuffers) {
479 alignas(4) char data[8];
480 ContiguousBuffer<const unsigned char, 1, 0> buffer;
481 buffer = ContiguousBuffer<char, 4, 1>(data + 1, sizeof data - 1);
482 EXPECT_TRUE(buffer.Ok());
483 EXPECT_EQ(buffer.data(), reinterpret_cast<unsigned char *>(data + 1));
484
485 ContiguousBuffer<const unsigned char, 2, 1> aligned_buffer;
486 aligned_buffer =
487 ContiguousBuffer<unsigned char, 4, 3>(data + 3, sizeof data - 3);
488 EXPECT_TRUE(aligned_buffer.Ok());
489 EXPECT_EQ(aligned_buffer.data(), reinterpret_cast<unsigned char *>(data + 3));
490 }
491
TEST(ContiguousBuffer,ConstructionFromCompatibleContiguousBuffers)492 TEST(ContiguousBuffer, ConstructionFromCompatibleContiguousBuffers) {
493 alignas(4) char data[8];
494 ContiguousBuffer<const unsigned char, 1, 0> buffer{
495 ContiguousBuffer<char, 4, 1>(data + 1, sizeof data - 1)};
496 EXPECT_TRUE(buffer.Ok());
497 EXPECT_EQ(buffer.data(), reinterpret_cast<unsigned char *>(data + 1));
498
499 ContiguousBuffer<const char, 2, 1> aligned_buffer{
500 ContiguousBuffer<unsigned char, 4, 3>(data + 3, sizeof data - 3)};
501 EXPECT_TRUE(aligned_buffer.Ok());
502 EXPECT_EQ(aligned_buffer.data(), reinterpret_cast<char *>(data + 3));
503 }
504
TEST(ContiguousBuffer,ToString)505 TEST(ContiguousBuffer, ToString) {
506 const ::std::vector</**/ ::std::uint8_t> bytes = {
507 {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}};
508 const auto buffer = ReadOnlyContiguousBuffer{bytes.data(), bytes.size() - 4};
509 auto str = buffer.ToString</**/ ::std::string>();
510 EXPECT_TRUE((::std::is_same</**/ ::std::string, decltype(str)>::value));
511 EXPECT_EQ(str, "abcd");
512 #if __cplusplus >= 201703L
513 auto str_view = buffer.ToString</**/ ::std::string_view>();
514 EXPECT_TRUE(
515 (::std::is_same</**/ ::std::string_view, decltype(str_view)>::value));
516 EXPECT_EQ(str_view, "abcd");
517 #endif // __cplusplus >= 201703L
518 }
519
TEST(LittleEndianByteOrderer,Methods)520 TEST(LittleEndianByteOrderer, Methods) {
521 ::std::vector</**/ ::std::uint8_t> bytes = {
522 {21, 22, 1, 2, 3, 4, 5, 6, 7, 8, 23, 24}};
523 const int buffer_start = 2;
524 const auto buffer = LittleEndianByteOrderer<ReadWriteContiguousBuffer>{
525 ReadWriteContiguousBuffer{bytes.data() + buffer_start, 8}};
526 EXPECT_EQ(8U, buffer.SizeInBytes());
527 EXPECT_TRUE(buffer.Ok());
528 EXPECT_EQ(0x0807060504030201UL, buffer.ReadUInt<64>());
529 EXPECT_EQ(0x0807060504030201UL, buffer.UncheckedReadUInt<64>());
530 #if EMBOSS_CHECK_ABORTS
531 EXPECT_DEATH(buffer.ReadUInt<56>(), "");
532 #endif // EMBOSS_CHECK_ABORTS
533 EXPECT_EQ(0x07060504030201UL, buffer.UncheckedReadUInt<56>());
534 buffer.WriteUInt<64>(0x0102030405060708);
535 EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{21, 22, 8, 7, 6, 5, 4, 3, 2, 1,
536 23, 24}),
537 bytes);
538 buffer.UncheckedWriteUInt<64>(0x0807060504030201);
539 EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{21, 22, 1, 2, 3, 4, 5, 6, 7, 8,
540 23, 24}),
541 bytes);
542 #if EMBOSS_CHECK_ABORTS
543 EXPECT_DEATH(buffer.WriteUInt<56>(0x77777777777777), "");
544 #endif // EMBOSS_CHECK_ABORTS
545
546 EXPECT_FALSE(LittleEndianByteOrderer<ReadOnlyContiguousBuffer>().Ok());
547 EXPECT_EQ(0U,
548 LittleEndianByteOrderer<ReadOnlyContiguousBuffer>().SizeInBytes());
549 EXPECT_EQ(bytes[1], (LittleEndianByteOrderer<ReadOnlyContiguousBuffer>{
550 ReadOnlyContiguousBuffer{bytes.data() + 1, 0}}
551 .UncheckedReadUInt<8>()));
552 EXPECT_TRUE((LittleEndianByteOrderer<ReadOnlyContiguousBuffer>{
553 ReadOnlyContiguousBuffer{bytes.data(), 0}}
554 .Ok()));
555 }
556
TEST(BigEndianByteOrderer,Methods)557 TEST(BigEndianByteOrderer, Methods) {
558 ::std::vector</**/ ::std::uint8_t> bytes = {
559 {21, 22, 1, 2, 3, 4, 5, 6, 7, 8, 23, 24}};
560 const int buffer_start = 2;
561 const auto buffer = BigEndianByteOrderer<ReadWriteContiguousBuffer>{
562 ReadWriteContiguousBuffer{bytes.data() + buffer_start, 8}};
563 EXPECT_EQ(8U, buffer.SizeInBytes());
564 EXPECT_TRUE(buffer.Ok());
565 EXPECT_EQ(0x0102030405060708UL, buffer.ReadUInt<64>());
566 EXPECT_EQ(0x0102030405060708UL, buffer.UncheckedReadUInt<64>());
567 #if EMBOSS_CHECK_ABORTS
568 EXPECT_DEATH(buffer.ReadUInt<56>(), "");
569 #endif // EMBOSS_CHECK_ABORTS
570 EXPECT_EQ(0x01020304050607UL, buffer.UncheckedReadUInt<56>());
571 buffer.WriteUInt<64>(0x0807060504030201);
572 EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{21, 22, 8, 7, 6, 5, 4, 3, 2, 1,
573 23, 24}),
574 bytes);
575 buffer.UncheckedWriteUInt<64>(0x0102030405060708);
576 EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{21, 22, 1, 2, 3, 4, 5, 6, 7, 8,
577 23, 24}),
578 bytes);
579 #if EMBOSS_CHECK_ABORTS
580 EXPECT_DEATH(buffer.WriteUInt<56>(0x77777777777777), "");
581 #endif // EMBOSS_CHECK_ABORTS
582
583 EXPECT_FALSE(BigEndianByteOrderer<ReadOnlyContiguousBuffer>().Ok());
584 EXPECT_EQ(0U, BigEndianByteOrderer<ReadOnlyContiguousBuffer>().SizeInBytes());
585 EXPECT_EQ(bytes[1], (BigEndianByteOrderer<ReadOnlyContiguousBuffer>{
586 ReadOnlyContiguousBuffer{bytes.data() + 1, 0}}
587 .UncheckedReadUInt<8>()));
588 EXPECT_TRUE((BigEndianByteOrderer<ReadOnlyContiguousBuffer>{
589 ReadOnlyContiguousBuffer{bytes.data(), 0}}
590 .Ok()));
591 }
592
TEST(NullByteOrderer,Methods)593 TEST(NullByteOrderer, Methods) {
594 ::std::uint8_t bytes[] = {0xdb, 0x0f, 0x0e, 0x0d};
595 const auto buffer = NullByteOrderer<ReadWriteContiguousBuffer>{
596 ReadWriteContiguousBuffer{bytes, 1}};
597 EXPECT_EQ(bytes[0], buffer.ReadUInt<8>());
598 EXPECT_EQ(bytes[0], buffer.UncheckedReadUInt<8>());
599 // NullByteOrderer::UncheckedRead ignores its argument.
600 EXPECT_EQ(bytes[0], buffer.UncheckedReadUInt<8>());
601 buffer.WriteUInt<8>(0x24);
602 EXPECT_EQ(0x24U, bytes[0]);
603 buffer.UncheckedWriteUInt<8>(0x25);
604 EXPECT_EQ(0x25U, bytes[0]);
605 EXPECT_EQ(1U, buffer.SizeInBytes());
606 EXPECT_TRUE(buffer.Ok());
607
608 EXPECT_FALSE(NullByteOrderer<ReadOnlyContiguousBuffer>().Ok());
609 EXPECT_EQ(0U, NullByteOrderer<ReadOnlyContiguousBuffer>().SizeInBytes());
610 #if EMBOSS_CHECK_ABORTS
611 EXPECT_DEATH((NullByteOrderer<ReadOnlyContiguousBuffer>{
612 ReadOnlyContiguousBuffer{bytes, 0}}
613 .ReadUInt<8>()),
614 "");
615 EXPECT_DEATH((NullByteOrderer<ReadOnlyContiguousBuffer>{
616 ReadOnlyContiguousBuffer{bytes, 2}}
617 .ReadUInt<8>()),
618 "");
619 #endif // EMBOSS_CHECK_ABORTS
620 EXPECT_EQ(bytes[0], (NullByteOrderer<ReadOnlyContiguousBuffer>{
621 ReadOnlyContiguousBuffer{bytes, 0}}
622 .UncheckedReadUInt<8>()));
623 EXPECT_TRUE((NullByteOrderer<ReadOnlyContiguousBuffer>{
624 ReadOnlyContiguousBuffer{bytes, 0}}
625 .Ok()));
626 }
627
TEST(BitBlock,BigEndianMethods)628 TEST(BitBlock, BigEndianMethods) {
629 ::std::uint8_t bytes[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
630 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
631 const auto big_endian =
632 BigEndianBitBlockN<64>{ReadWriteContiguousBuffer{bytes + 4, 8}};
633 EXPECT_EQ(64U, big_endian.SizeInBits());
634 EXPECT_TRUE(big_endian.Ok());
635 EXPECT_EQ(0x05060708090a0b0cUL, big_endian.ReadUInt());
636 EXPECT_EQ(0x05060708090a0b0cUL, big_endian.UncheckedReadUInt());
637 EXPECT_FALSE(BigEndianBitBlockN<64>().Ok());
638 EXPECT_EQ(64U, BigEndianBitBlockN<64>().SizeInBits());
639 EXPECT_FALSE(
640 (BigEndianBitBlockN<64>{ReadWriteContiguousBuffer{bytes, 0}}.Ok()));
641 }
642
TEST(BitBlock,LittleEndianMethods)643 TEST(BitBlock, LittleEndianMethods) {
644 ::std::uint8_t bytes[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
645 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
646 const auto little_endian =
647 LittleEndianBitBlockN<64>{ReadWriteContiguousBuffer{bytes + 4, 8}};
648 EXPECT_EQ(64U, little_endian.SizeInBits());
649 EXPECT_TRUE(little_endian.Ok());
650 EXPECT_EQ(0x0c0b0a0908070605UL, little_endian.ReadUInt());
651 EXPECT_EQ(0x0c0b0a0908070605UL, little_endian.UncheckedReadUInt());
652 EXPECT_FALSE(LittleEndianBitBlockN<64>().Ok());
653 EXPECT_EQ(64U, LittleEndianBitBlockN<64>().SizeInBits());
654 EXPECT_FALSE(
655 (LittleEndianBitBlockN<64>{ReadWriteContiguousBuffer{bytes, 0}}.Ok()));
656 }
657
TEST(BitBlock,GetOffsetStorage)658 TEST(BitBlock, GetOffsetStorage) {
659 ::std::uint8_t bytes[] = {0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09,
660 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
661 const auto bit_block =
662 LittleEndianBitBlockN<64>{ReadWriteContiguousBuffer{bytes, 8}};
663 const OffsetBitBlock<LittleEndianBitBlockN<64>> offset_block =
664 bit_block.GetOffsetStorage<1, 0>(4, 8);
665 EXPECT_EQ(8U, offset_block.SizeInBits());
666 EXPECT_EQ(0xf1U, offset_block.ReadUInt());
667 EXPECT_EQ(bit_block.SizeInBits(),
668 (bit_block.GetOffsetStorage<1, 0>(8, bit_block.SizeInBits())
669 .SizeInBits()));
670 EXPECT_FALSE(
671 (bit_block.GetOffsetStorage<1, 0>(8, bit_block.SizeInBits()).Ok()));
672 EXPECT_EQ(10U, (bit_block.GetOffsetStorage<1, 0>(bit_block.SizeInBits(), 10)
673 .SizeInBits()));
674 }
675
TEST(OffsetBitBlock,Methods)676 TEST(OffsetBitBlock, Methods) {
677 ::std::vector</**/ ::std::uint8_t> bytes = {
678 {0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09}};
679 const auto bit_block =
680 LittleEndianBitBlockN<64>{ReadWriteContiguousBuffer{&bytes}};
681 EXPECT_FALSE((bit_block.GetOffsetStorage<1, 0>(0, 96).Ok()));
682 EXPECT_TRUE((bit_block.GetOffsetStorage<1, 0>(0, 64).Ok()));
683
684 const auto offset_block = bit_block.GetOffsetStorage<1, 0>(8, 48);
685 EXPECT_FALSE((offset_block.GetOffsetStorage<1, 0>(40, 16).Ok()));
686 EXPECT_EQ(0x0a0b0c0d0e0fUL, offset_block.ReadUInt());
687 EXPECT_EQ(0x0a0b0c0d0e0fUL, offset_block.UncheckedReadUInt());
688 offset_block.WriteUInt(0x0f0e0d0c0b0a);
689 EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x10, 0x0a, 0x0b, 0x0c, 0x0d,
690 0x0e, 0x0f, 0x09}),
691 bytes);
692 offset_block.UncheckedWriteUInt(0x0a0b0c0d0e0f);
693 EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x10, 0x0f, 0x0e, 0x0d, 0x0c,
694 0x0b, 0x0a, 0x09}),
695 bytes);
696 #if EMBOSS_CHECK_ABORTS
697 EXPECT_DEATH(offset_block.WriteUInt(0x10f0e0d0c0b0a), "");
698 #endif // EMBOSS_CHECK_ABORTS
699 offset_block.UncheckedWriteUInt(0x10f0e0d0c0b0a);
700 EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x10, 0x0a, 0x0b, 0x0c, 0x0d,
701 0x0e, 0x0f, 0x09}),
702 bytes);
703
704 const auto offset_offset_block = offset_block.GetOffsetStorage<1, 0>(16, 16);
705 EXPECT_FALSE((offset_offset_block.GetOffsetStorage<1, 0>(8, 16).Ok()));
706 EXPECT_EQ(0x0d0cU, offset_offset_block.ReadUInt());
707 EXPECT_EQ(0x0d0cU, offset_offset_block.UncheckedReadUInt());
708 offset_offset_block.WriteUInt(0x0c0d);
709 EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x10, 0x0a, 0x0b, 0x0d, 0x0c,
710 0x0e, 0x0f, 0x09}),
711 bytes);
712 offset_offset_block.UncheckedWriteUInt(0x0d0c);
713 EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x10, 0x0a, 0x0b, 0x0c, 0x0d,
714 0x0e, 0x0f, 0x09}),
715 bytes);
716 #if EMBOSS_CHECK_ABORTS
717 EXPECT_DEATH(offset_offset_block.WriteUInt(0x10c0d), "");
718 #endif // EMBOSS_CHECK_ABORTS
719 offset_offset_block.UncheckedWriteUInt(0x20c0d);
720 EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x10, 0x0a, 0x0b, 0x0d, 0x0c,
721 0x0e, 0x0f, 0x09}),
722 bytes);
723
724 const auto null_offset_block = OffsetBitBlock<BigEndianBitBlockN<32>>();
725 EXPECT_FALSE(null_offset_block.Ok());
726 EXPECT_EQ(0U, null_offset_block.SizeInBits());
727 }
728
729 } // namespace test
730 } // namespace support
731 } // namespace emboss
732