blob: 7b49ee7cbbfc95e0e19866d3bd275d4b7925cb7e [file] [log] [blame]
Wyatt Hepler05ca54c2020-09-02 17:04:59 -07001// 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
22namespace pw::bytes {
23namespace {
24
25constexpr 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
39static_assert(ConvertOrderTo(std::endian::native, uint8_t{0x12}) == uint8_t{0x12});
40static_assert(ConvertOrderTo(std::endian::native, uint16_t{0x0011}) == uint16_t{0x0011});
41static_assert(ConvertOrderTo(std::endian::native, uint32_t{0x33221100}) == uint32_t{0x33221100});
42static_assert(ConvertOrderTo(std::endian::native, uint64_t{0x0011223344556677}) == uint64_t{0x0011223344556677});
43
44// Convert signed to native endianness
45static_assert(ConvertOrderTo(std::endian::native, int8_t{0x12}) == int8_t{0x12});
46static_assert(ConvertOrderTo(std::endian::native, int16_t{0x0011}) == int16_t{0x0011});
47static_assert(ConvertOrderTo(std::endian::native, int32_t{0x33221100}) == int32_t{0x33221100});
48static_assert(ConvertOrderTo(std::endian::native, int64_t{0x0011223344556677}) == int64_t{0x0011223344556677});
49
50// Convert unsigned from native endianness
51static_assert(ConvertOrderFrom(std::endian::native, uint8_t{0x12}) == uint8_t{0x12});
52static_assert(ConvertOrderFrom(std::endian::native, uint16_t{0x0011}) == uint16_t{0x0011});
53static_assert(ConvertOrderFrom(std::endian::native, uint32_t{0x33221100}) == uint32_t{0x33221100});
54static_assert(ConvertOrderFrom(std::endian::native, uint64_t{0x0011223344556677}) == uint64_t{0x0011223344556677});
55
56// Convert signed from native endianness
57static_assert(ConvertOrderFrom(std::endian::native, int8_t{0x12}) == int8_t{0x12});
58static_assert(ConvertOrderFrom(std::endian::native, int16_t{0x0011}) == int16_t{0x0011});
59static_assert(ConvertOrderFrom(std::endian::native, int32_t{0x33221100}) == int32_t{0x33221100});
60static_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
65static_assert(ConvertOrderTo(kNonNative, uint8_t{0x12}) == uint8_t{0x12});
66static_assert(ConvertOrderTo(kNonNative, uint16_t{0x0011}) == uint16_t{0x1100});
67static_assert(ConvertOrderTo(kNonNative, uint32_t{0x33221100}) == uint32_t{0x00112233});
68static_assert(ConvertOrderTo(kNonNative, uint64_t{0x0011223344556677}) == uint64_t{0x7766554433221100});
69
70// Convert signed to non-native endianness
71static_assert(ConvertOrderTo(kNonNative, int8_t{0x12}) == int8_t{0x12});
72static_assert(ConvertOrderTo(kNonNative, int16_t{0x0011}) == int16_t{0x1100});
73static_assert(ConvertOrderTo(kNonNative, int32_t{0x33221100}) == int32_t{0x00112233});
74static_assert(ConvertOrderTo(kNonNative, int64_t{0x0011223344556677}) == int64_t{0x7766554433221100});
75
76// Convert unsigned from non-native endianness
77static_assert(ConvertOrderFrom(kNonNative, uint8_t{0x12}) == uint8_t{0x12});
78static_assert(ConvertOrderFrom(kNonNative, uint16_t{0x0011}) == uint16_t{0x1100});
79static_assert(ConvertOrderFrom(kNonNative, uint32_t{0x33221100}) == uint32_t{0x00112233});
80static_assert(ConvertOrderFrom(kNonNative, uint64_t{0x0011223344556677}) == uint64_t{0x7766554433221100});
81
82// Convert signed from non-native endianness
83static_assert(ConvertOrderFrom(kNonNative, int8_t{0x12}) == int8_t{0x12});
84static_assert(ConvertOrderFrom(kNonNative, int16_t{0x0011}) == int16_t{0x1100});
85static_assert(ConvertOrderFrom(kNonNative, int32_t{0x33221100}) == int32_t{0x00112233});
86static_assert(ConvertOrderFrom(kNonNative, int64_t{0x0011223344556677}) == int64_t{0x7766554433221100});
87
88// clang-format on
89
90template <typename T, typename U>
91constexpr 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
110static_assert(Equal(CopyInOrder(std::endian::little, '?'),
111 Array<'?'>()));
112static_assert(Equal(CopyInOrder(std::endian::little, uint8_t{0x10}),
113 Array<0x10>()));
114static_assert(Equal(CopyInOrder(std::endian::little, static_cast<int8_t>(0x10)),
115 Array<0x10>()));
116
117// 8-bit big
118static_assert(Equal(CopyInOrder(std::endian::big, '?'),
119 Array<'?'>()));
120static_assert(Equal(CopyInOrder(std::endian::big, static_cast<uint8_t>(0x10)),
121 Array<0x10>()));
122static_assert(Equal(CopyInOrder(std::endian::big, static_cast<int8_t>(0x10)),
123 Array<0x10>()));
124
125// 16-bit little
126static_assert(Equal(CopyInOrder(std::endian::little, uint16_t{0xAB12}),
127 Array<0x12, 0xAB>()));
128static_assert(Equal(CopyInOrder(std::endian::little, static_cast<int16_t>(0xAB12)),
129 Array<0x12, 0xAB>()));
130
131// 16-bit big
132static_assert(Equal(CopyInOrder(std::endian::big, uint16_t{0xAB12}),
133 Array<0xAB, 0x12>()));
134static_assert(Equal(CopyInOrder(std::endian::big, static_cast<int16_t>(0xAB12)),
135 Array<0xAB, 0x12>()));
136
137// 32-bit little
138static_assert(Equal(CopyInOrder(std::endian::little, uint32_t{0xAABBCCDD}),
139 Array<0xDD, 0xCC, 0xBB, 0xAA>()));
140static_assert(Equal(CopyInOrder(std::endian::little, static_cast<int32_t>(0xAABBCCDD)),
141 Array<0xDD, 0xCC, 0xBB, 0xAA>()));
142
143// 32-bit big
144static_assert(Equal(CopyInOrder(std::endian::big, uint32_t{0xAABBCCDD}),
145 Array<0xAA, 0xBB, 0xCC, 0xDD>()));
146static_assert(Equal(CopyInOrder(std::endian::big, static_cast<int32_t>(0xAABBCCDD)),
147 Array<0xAA, 0xBB, 0xCC, 0xDD>()));
148
149// 64-bit little
150static_assert(Equal(CopyInOrder(std::endian::little, uint64_t{0xAABBCCDD11223344}),
151 Array<0x44, 0x33, 0x22, 0x11, 0xDD, 0xCC, 0xBB, 0xAA>()));
152static_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
156static_assert(Equal(CopyInOrder(std::endian::big, uint64_t{0xAABBCCDD11223344}),
157 Array<0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22, 0x33, 0x44>()));
158static_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
Wyatt Hepler3cd2cd42020-09-13 22:23:47 -0700163constexpr const char* kNumber = "\x11\x22\x33\x44\xaa\xbb\xcc\xdd";
164
165TEST(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
175TEST(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
185TEST(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
195TEST(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
205TEST(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
215TEST(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
225TEST(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
239TEST(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
253TEST(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
259TEST(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
265TEST(ReadInOrder, BoundsChecking_Ok) {
266 constexpr auto buffer = Array<1, 2, 3, 4>();
Prashanth Swaminathanf40762d2021-02-02 19:16:45 -0800267 uint16_t value = 0;
Wyatt Hepler3cd2cd42020-09-13 22:23:47 -0700268 EXPECT_TRUE(ReadInOrder(std::endian::little, buffer, value));
269 EXPECT_EQ(0x0201, value);
270}
271
272TEST(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
Wyatt Hepler05ca54c2020-09-02 17:04:59 -0700279} // namespace
280} // namespace pw::bytes