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