1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // 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, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_bytes/endian.h"
16
17 #include <array>
18 #include <cstddef>
19
20 #include "gtest/gtest.h"
21
22 namespace pw::bytes {
23 namespace {
24
25 constexpr endian kNonNative =
26 (endian::native == endian::little) ? endian::big : endian::little;
27
28 // ConvertOrderTo/From
29 //
30 // ConvertOrderTo and ConvertOrderFrom are implemented identically, but are
31 // provided as separate functions to improve readability where they are used.
32 //
33 // clang-format off
34
35 // Native endianess conversions (should do nothing)
36
37 // Convert unsigned to native endianness
38 static_assert(ConvertOrderTo(endian::native, uint8_t{0x12}) == uint8_t{0x12});
39 static_assert(ConvertOrderTo(endian::native, uint16_t{0x0011}) == uint16_t{0x0011});
40 static_assert(ConvertOrderTo(endian::native, uint32_t{0x33221100}) == uint32_t{0x33221100});
41 static_assert(ConvertOrderTo(endian::native, uint64_t{0x0011223344556677}) == uint64_t{0x0011223344556677});
42
43 // Convert signed to native endianness
44 static_assert(ConvertOrderTo(endian::native, int8_t{0x12}) == int8_t{0x12});
45 static_assert(ConvertOrderTo(endian::native, int16_t{0x0011}) == int16_t{0x0011});
46 static_assert(ConvertOrderTo(endian::native, int32_t{0x33221100}) == int32_t{0x33221100});
47 static_assert(ConvertOrderTo(endian::native, int64_t{0x0011223344556677}) == int64_t{0x0011223344556677});
48
49 // Convert unsigned from native endianness
50 static_assert(ConvertOrderFrom(endian::native, uint8_t{0x12}) == uint8_t{0x12});
51 static_assert(ConvertOrderFrom(endian::native, uint16_t{0x0011}) == uint16_t{0x0011});
52 static_assert(ConvertOrderFrom(endian::native, uint32_t{0x33221100}) == uint32_t{0x33221100});
53 static_assert(ConvertOrderFrom(endian::native, uint64_t{0x0011223344556677}) == uint64_t{0x0011223344556677});
54
55 // Convert signed from native endianness
56 static_assert(ConvertOrderFrom(endian::native, int8_t{0x12}) == int8_t{0x12});
57 static_assert(ConvertOrderFrom(endian::native, int16_t{0x0011}) == int16_t{0x0011});
58 static_assert(ConvertOrderFrom(endian::native, int32_t{0x33221100}) == int32_t{0x33221100});
59 static_assert(ConvertOrderFrom(endian::native, int64_t{0x0011223344556677}) == int64_t{0x0011223344556677});
60
61 // Non-native endianess conversions (should reverse byte order)
62
63 // Convert unsigned to non-native endianness
64 static_assert(ConvertOrderTo(kNonNative, uint8_t{0x12}) == uint8_t{0x12});
65 static_assert(ConvertOrderTo(kNonNative, uint16_t{0x0011}) == uint16_t{0x1100});
66 static_assert(ConvertOrderTo(kNonNative, uint32_t{0x33221100}) == uint32_t{0x00112233});
67 static_assert(ConvertOrderTo(kNonNative, uint64_t{0x0011223344556677}) == uint64_t{0x7766554433221100});
68
69 // Convert signed to non-native endianness
70 static_assert(ConvertOrderTo(kNonNative, int8_t{0x12}) == int8_t{0x12});
71 static_assert(ConvertOrderTo(kNonNative, int16_t{0x0011}) == int16_t{0x1100});
72 static_assert(ConvertOrderTo(kNonNative, int32_t{0x33221100}) == int32_t{0x00112233});
73 static_assert(ConvertOrderTo(kNonNative, int64_t{0x0011223344556677}) == int64_t{0x7766554433221100});
74
75 // Convert unsigned from non-native endianness
76 static_assert(ConvertOrderFrom(kNonNative, uint8_t{0x12}) == uint8_t{0x12});
77 static_assert(ConvertOrderFrom(kNonNative, uint16_t{0x0011}) == uint16_t{0x1100});
78 static_assert(ConvertOrderFrom(kNonNative, uint32_t{0x33221100}) == uint32_t{0x00112233});
79 static_assert(ConvertOrderFrom(kNonNative, uint64_t{0x0011223344556677}) == uint64_t{0x7766554433221100});
80
81 // Convert signed from non-native endianness
82 static_assert(ConvertOrderFrom(kNonNative, int8_t{0x12}) == int8_t{0x12});
83 static_assert(ConvertOrderFrom(kNonNative, int16_t{0x0011}) == int16_t{0x1100});
84 static_assert(ConvertOrderFrom(kNonNative, int32_t{0x33221100}) == int32_t{0x00112233});
85 static_assert(ConvertOrderFrom(kNonNative, int64_t{0x0011223344556677}) == int64_t{0x7766554433221100});
86
87 // clang-format on
88
89 template <typename T, typename U>
Equal(const T & lhs,const U & rhs)90 constexpr bool Equal(const T& lhs, const U& rhs) {
91 if (sizeof(lhs) != sizeof(rhs) || std::size(lhs) != std::size(rhs)) {
92 return false;
93 }
94
95 for (size_t i = 0; i < std::size(lhs); ++i) {
96 if (lhs[i] != rhs[i]) {
97 return false;
98 }
99 }
100
101 return true;
102 }
103
104 // CopyInOrder copies a value to a std::array with the specified endianness.
105 //
106 // clang-format off
107
108 // 8-bit little
109 static_assert(Equal(CopyInOrder(endian::little, '?'),
110 Array<'?'>()));
111 static_assert(Equal(CopyInOrder(endian::little, uint8_t{0x10}),
112 Array<0x10>()));
113 static_assert(Equal(CopyInOrder(endian::little, static_cast<int8_t>(0x10)),
114 Array<0x10>()));
115
116 // 8-bit big
117 static_assert(Equal(CopyInOrder(endian::big, '?'),
118 Array<'?'>()));
119 static_assert(Equal(CopyInOrder(endian::big, static_cast<uint8_t>(0x10)),
120 Array<0x10>()));
121 static_assert(Equal(CopyInOrder(endian::big, static_cast<int8_t>(0x10)),
122 Array<0x10>()));
123
124 // 16-bit little
125 static_assert(Equal(CopyInOrder(endian::little, uint16_t{0xAB12}),
126 Array<0x12, 0xAB>()));
127 static_assert(Equal(CopyInOrder(endian::little, static_cast<int16_t>(0xAB12)),
128 Array<0x12, 0xAB>()));
129
130 // 16-bit big
131 static_assert(Equal(CopyInOrder(endian::big, uint16_t{0xAB12}),
132 Array<0xAB, 0x12>()));
133 static_assert(Equal(CopyInOrder(endian::big, static_cast<int16_t>(0xAB12)),
134 Array<0xAB, 0x12>()));
135
136 // 32-bit little
137 static_assert(Equal(CopyInOrder(endian::little, uint32_t{0xAABBCCDD}),
138 Array<0xDD, 0xCC, 0xBB, 0xAA>()));
139 static_assert(Equal(CopyInOrder(endian::little, static_cast<int32_t>(0xAABBCCDD)),
140 Array<0xDD, 0xCC, 0xBB, 0xAA>()));
141
142 // 32-bit big
143 static_assert(Equal(CopyInOrder(endian::big, uint32_t{0xAABBCCDD}),
144 Array<0xAA, 0xBB, 0xCC, 0xDD>()));
145 static_assert(Equal(CopyInOrder(endian::big, static_cast<int32_t>(0xAABBCCDD)),
146 Array<0xAA, 0xBB, 0xCC, 0xDD>()));
147
148 // 64-bit little
149 static_assert(Equal(CopyInOrder(endian::little, uint64_t{0xAABBCCDD11223344}),
150 Array<0x44, 0x33, 0x22, 0x11, 0xDD, 0xCC, 0xBB, 0xAA>()));
151 static_assert(Equal(CopyInOrder(endian::little, static_cast<int64_t>(0xAABBCCDD11223344ull)),
152 Array<0x44, 0x33, 0x22, 0x11, 0xDD, 0xCC, 0xBB, 0xAA>()));
153
154 // 64-bit big
155 static_assert(Equal(CopyInOrder(endian::big, uint64_t{0xAABBCCDD11223344}),
156 Array<0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22, 0x33, 0x44>()));
157 static_assert(Equal(CopyInOrder(endian::big, static_cast<int64_t>(0xAABBCCDD11223344ull)),
158 Array<0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22, 0x33, 0x44>()));
159
160 // clang-format on
161
162 constexpr const char* kNumber = "\x11\x22\x33\x44\xaa\xbb\xcc\xdd";
163
164 TEST(ReadInOrder, 8Bit_Big) {
165 EXPECT_EQ(ReadInOrder<uint8_t>(endian::big, "\0"), 0u);
166 EXPECT_EQ(ReadInOrder<uint8_t>(endian::big, "\x80"), 0x80u);
167 EXPECT_EQ(ReadInOrder<uint8_t>(endian::big, kNumber), 0x11u);
168
169 EXPECT_EQ(ReadInOrder<int8_t>(endian::big, "\0"), 0);
170 EXPECT_EQ(ReadInOrder<int8_t>(endian::big, "\x80"), -128);
171 EXPECT_EQ(ReadInOrder<int8_t>(endian::big, kNumber), 0x11);
172 }
173
174 TEST(ReadInOrder, 8Bit_Little) {
175 EXPECT_EQ(ReadInOrder<uint8_t>(endian::little, "\0"), 0u);
176 EXPECT_EQ(ReadInOrder<uint8_t>(endian::little, "\x80"), 0x80u);
177 EXPECT_EQ(ReadInOrder<uint8_t>(endian::little, kNumber), 0x11u);
178
179 EXPECT_EQ(ReadInOrder<int8_t>(endian::little, "\0"), 0);
180 EXPECT_EQ(ReadInOrder<int8_t>(endian::little, "\x80"), -128);
181 EXPECT_EQ(ReadInOrder<int8_t>(endian::little, kNumber), 0x11);
182 }
183
184 TEST(ReadInOrder, 16Bit_Big) {
185 EXPECT_EQ(ReadInOrder<uint16_t>(endian::big, "\0\0"), 0u);
186 EXPECT_EQ(ReadInOrder<uint16_t>(endian::big, "\x80\0"), 0x8000u);
187 EXPECT_EQ(ReadInOrder<uint16_t>(endian::big, kNumber), 0x1122u);
188
189 EXPECT_EQ(ReadInOrder<int16_t>(endian::big, "\0\0"), 0);
190 EXPECT_EQ(ReadInOrder<int16_t>(endian::big, "\x80\0"), -32768);
191 EXPECT_EQ(ReadInOrder<int16_t>(endian::big, kNumber), 0x1122);
192 }
193
194 TEST(ReadInOrder, 16Bit_Little) {
195 EXPECT_EQ(ReadInOrder<uint16_t>(endian::little, "\0\0"), 0u);
196 EXPECT_EQ(ReadInOrder<uint16_t>(endian::little, "\x80\0"), 0x80u);
197 EXPECT_EQ(ReadInOrder<uint16_t>(endian::little, kNumber), 0x2211u);
198
199 EXPECT_EQ(ReadInOrder<int16_t>(endian::little, "\0\0"), 0);
200 EXPECT_EQ(ReadInOrder<int16_t>(endian::little, "\x80\0"), 0x80);
201 EXPECT_EQ(ReadInOrder<int16_t>(endian::little, kNumber), 0x2211);
202 }
203
204 TEST(ReadInOrder, 32Bit_Big) {
205 EXPECT_EQ(ReadInOrder<uint32_t>(endian::big, "\0\0\0\0"), 0u);
206 EXPECT_EQ(ReadInOrder<uint32_t>(endian::big, "\x80\0\0\0"), 0x80000000u);
207 EXPECT_EQ(ReadInOrder<uint32_t>(endian::big, kNumber), 0x11223344u);
208
209 EXPECT_EQ(ReadInOrder<int32_t>(endian::big, "\0\0\0\0"), 0);
210 EXPECT_EQ(ReadInOrder<int32_t>(endian::big, "\x80\0\0\0"), -2147483648);
211 EXPECT_EQ(ReadInOrder<int32_t>(endian::big, kNumber), 0x11223344);
212 }
213
214 TEST(ReadInOrder, 32Bit_Little) {
215 EXPECT_EQ(ReadInOrder<uint32_t>(endian::little, "\0\0\0\0"), 0u);
216 EXPECT_EQ(ReadInOrder<uint32_t>(endian::little, "\x80\0\0\0"), 0x80u);
217 EXPECT_EQ(ReadInOrder<uint32_t>(endian::little, kNumber), 0x44332211u);
218
219 EXPECT_EQ(ReadInOrder<int32_t>(endian::little, "\0\0\0\0"), 0);
220 EXPECT_EQ(ReadInOrder<int32_t>(endian::little, "\x80\0\0\0"), 0x80);
221 EXPECT_EQ(ReadInOrder<int32_t>(endian::little, kNumber), 0x44332211);
222 }
223
224 TEST(ReadInOrder, 64Bit_Big) {
225 EXPECT_EQ(ReadInOrder<uint64_t>(endian::big, "\0\0\0\0\0\0\0\0"), 0u);
226 EXPECT_EQ(ReadInOrder<uint64_t>(endian::big, "\x80\0\0\0\0\0\0\0"),
227 0x80000000'00000000llu);
228 EXPECT_EQ(ReadInOrder<uint64_t>(endian::big, kNumber), 0x11223344AABBCCDDu);
229
230 EXPECT_EQ(ReadInOrder<int64_t>(endian::big, "\0\0\0\0\0\0\0\0"), 0);
231 EXPECT_EQ(ReadInOrder<int64_t>(endian::big, "\x80\0\0\0\0\0\0\0"),
232 static_cast<int64_t>(1llu << 63));
233 EXPECT_EQ(ReadInOrder<int64_t>(endian::big, kNumber), 0x11223344AABBCCDD);
234 }
235
236 TEST(ReadInOrder, 64Bit_Little) {
237 EXPECT_EQ(ReadInOrder<uint64_t>(endian::little, "\0\0\0\0\0\0\0\0"), 0u);
238 EXPECT_EQ(ReadInOrder<uint64_t>(endian::little, "\x80\0\0\0\0\0\0\0"), 0x80u);
239 EXPECT_EQ(ReadInOrder<uint64_t>(endian::little, kNumber),
240 0xDDCCBBAA44332211u);
241
242 EXPECT_EQ(ReadInOrder<int64_t>(endian::little, "\0\0\0\0\0\0\0\0"), 0);
243 EXPECT_EQ(ReadInOrder<int64_t>(endian::little, "\x80\0\0\0\0\0\0\0"), 0x80);
244 EXPECT_EQ(ReadInOrder<int64_t>(endian::little, kNumber),
245 static_cast<int64_t>(0xDDCCBBAA44332211));
246 }
247
TEST(ReadInOrder,StdArray)248 TEST(ReadInOrder, StdArray) {
249 std::array<std::byte, 4> buffer = Array<1, 2, 3, 4>();
250 EXPECT_EQ(0x04030201, ReadInOrder<int32_t>(endian::little, buffer));
251 EXPECT_EQ(0x01020304, ReadInOrder<int32_t>(endian::big, buffer));
252 }
253
TEST(ReadInOrder,CArray)254 TEST(ReadInOrder, CArray) {
255 char buffer[5] = {1, 2, 3, 4, 99};
256 EXPECT_EQ(0x04030201, ReadInOrder<int32_t>(endian::little, buffer));
257 EXPECT_EQ(0x01020304, ReadInOrder<int32_t>(endian::big, buffer));
258 }
259
TEST(ReadInOrder,BoundsChecking_Ok)260 TEST(ReadInOrder, BoundsChecking_Ok) {
261 constexpr auto buffer = Array<1, 2, 3, 4>();
262 uint16_t value = 0;
263 EXPECT_TRUE(ReadInOrder(endian::little, buffer, value));
264 EXPECT_EQ(0x0201, value);
265 }
266
TEST(ReadInOrder,BoundsChecking_TooSmall)267 TEST(ReadInOrder, BoundsChecking_TooSmall) {
268 constexpr auto buffer = Array<1, 2, 3>();
269 int32_t value = 0;
270 EXPECT_FALSE(ReadInOrder(endian::little, buffer, value));
271 EXPECT_EQ(0, value);
272 }
273
TEST(ReadInOrder,PartialLittleEndian)274 TEST(ReadInOrder, PartialLittleEndian) {
275 constexpr auto buffer = Array<1, 2, 3, 4>();
276
277 EXPECT_EQ(0x00000000, ReadInOrder<int32_t>(endian::little, buffer.data(), 0));
278 EXPECT_EQ(0x00000001, ReadInOrder<int32_t>(endian::little, buffer.data(), 1));
279 EXPECT_EQ(0x00000201, ReadInOrder<int32_t>(endian::little, buffer.data(), 2));
280 EXPECT_EQ(0x00030201, ReadInOrder<int32_t>(endian::little, buffer.data(), 3));
281 EXPECT_EQ(0x04030201, ReadInOrder<int32_t>(endian::little, buffer.data(), 4));
282 EXPECT_EQ(0x04030201, ReadInOrder<int32_t>(endian::little, buffer.data(), 5));
283 EXPECT_EQ(0x04030201,
284 ReadInOrder<int32_t>(endian::little, buffer.data(), 100));
285 }
286
TEST(ReadInOrder,PartialBigEndian)287 TEST(ReadInOrder, PartialBigEndian) {
288 constexpr auto buffer = Array<1, 2, 3, 4>();
289
290 EXPECT_EQ(0x00000000, ReadInOrder<int32_t>(endian::big, buffer.data(), 0));
291 EXPECT_EQ(0x01000000, ReadInOrder<int32_t>(endian::big, buffer.data(), 1));
292 EXPECT_EQ(0x01020000, ReadInOrder<int32_t>(endian::big, buffer.data(), 2));
293 EXPECT_EQ(0x01020300, ReadInOrder<int32_t>(endian::big, buffer.data(), 3));
294 EXPECT_EQ(0x01020304, ReadInOrder<int32_t>(endian::big, buffer.data(), 4));
295 EXPECT_EQ(0x01020304, ReadInOrder<int32_t>(endian::big, buffer.data(), 5));
296 EXPECT_EQ(0x01020304, ReadInOrder<int32_t>(endian::big, buffer.data(), 100));
297 }
298
299 } // namespace
300 } // namespace pw::bytes
301