xref: /aosp_15_r20/external/emboss/runtime/cpp/test/emboss_enum_view_test.cc (revision 99e0aae7469b87d12f0ad23e61142c2d74c1ef70)
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 "runtime/cpp/emboss_enum_view.h"
16 
17 #include "gtest/gtest.h"
18 #include "runtime/cpp/emboss_prelude.h"
19 #include "runtime/cpp/emboss_text_util.h"
20 
21 namespace emboss {
22 namespace support {
23 namespace test {
24 
25 template </**/ ::std::size_t kBits>
26 using LittleEndianBitBlockN =
27     BitBlock<LittleEndianByteOrderer<ReadWriteContiguousBuffer>, kBits>;
28 
29 enum class Foo : ::std::int64_t {
30   kMin = -0x7fffffffffffffffL - 1,
31   kOne = 1,
32   kTwo = 2,
33   kBig = 0x0e0f10,
34   kBigBackwards = 0x100f0e,
35   kReallyBig = 0x090a0b0c0d0e0f10L,
36   kReallyBigBackwards = 0x100f0e0d0c0b0a09L,
37   k2to24MinusOne = (1L << 24) - 1,
38   k2to24 = 1L << 24,
39   kMax = 0x7fffffffffffffffL,
40 };
41 
TryToGetEnumFromName(const char * name,Foo * result)42 static inline bool TryToGetEnumFromName(const char *name, Foo *result) {
43   if (!strcmp("kMin", name)) {
44     *result = Foo::kMin;
45     return true;
46   }
47   if (!strcmp("kOne", name)) {
48     *result = Foo::kOne;
49     return true;
50   }
51   if (!strcmp("kTwo", name)) {
52     *result = Foo::kTwo;
53     return true;
54   }
55   if (!strcmp("kBig", name)) {
56     *result = Foo::kBig;
57     return true;
58   }
59   if (!strcmp("kBigBackwards", name)) {
60     *result = Foo::kBigBackwards;
61     return true;
62   }
63   if (!strcmp("kReallyBig", name)) {
64     *result = Foo::kReallyBig;
65     return true;
66   }
67   if (!strcmp("kReallyBigBackwards", name)) {
68     *result = Foo::kReallyBigBackwards;
69     return true;
70   }
71   if (!strcmp("k2to24MinusOne", name)) {
72     *result = Foo::k2to24MinusOne;
73     return true;
74   }
75   if (!strcmp("k2to24", name)) {
76     *result = Foo::k2to24;
77     return true;
78   }
79   if (!strcmp("kMax", name)) {
80     *result = Foo::kMax;
81     return true;
82   }
83   return false;
84 }
85 
TryToGetNameFromEnum(Foo value)86 static inline const char *TryToGetNameFromEnum(Foo value) {
87   switch (value) {
88     case Foo::kMin:
89       return "kMin";
90     case Foo::kOne:
91       return "kOne";
92     case Foo::kTwo:
93       return "kTwo";
94     case Foo::kBig:
95       return "kBig";
96     case Foo::kBigBackwards:
97       return "kBigBackwards";
98     case Foo::kReallyBig:
99       return "kReallyBig";
100     case Foo::kReallyBigBackwards:
101       return "kReallyBigBackwards";
102     case Foo::k2to24MinusOne:
103       return "k2to24MinusOne";
104     case Foo::k2to24:
105       return "k2to24";
106     case Foo::kMax:
107       return "kMax";
108     default:
109       return nullptr;
110   }
111 }
112 
113 template </**/ ::std::size_t kBits>
114 using FooViewN = EnumView<Foo, FixedSizeViewParameters<kBits, AllValuesAreOk>,
115                           LittleEndianBitBlockN<kBits>>;
116 
117 template <int kMaxBits>
CheckEnumViewSizeInBits()118 void CheckEnumViewSizeInBits() {
119   const int size_in_bits =
120       EnumView<Foo, FixedSizeViewParameters<kMaxBits, AllValuesAreOk>,
121                OffsetBitBlock<LittleEndianBitBlockN<64>>>::SizeInBits();
122   EXPECT_EQ(size_in_bits, kMaxBits);
123   return CheckEnumViewSizeInBits<kMaxBits - 1>();
124 }
125 
126 template <>
CheckEnumViewSizeInBits()127 void CheckEnumViewSizeInBits<0>() {
128   return;
129 }
130 
TEST(EnumView,SizeInBits)131 TEST(EnumView, SizeInBits) { CheckEnumViewSizeInBits<64>(); }
132 
TEST(EnumView,ValueType)133 TEST(EnumView, ValueType) {
134   using BitBlockType = OffsetBitBlock<LittleEndianBitBlockN<64>>;
135   EXPECT_TRUE(
136       (::std::is_same<Foo,
137                       EnumView<Foo, FixedSizeViewParameters<8, AllValuesAreOk>,
138                                BitBlockType>::ValueType>::value));
139   EXPECT_TRUE(
140       (::std::is_same<Foo,
141                       EnumView<Foo, FixedSizeViewParameters<6, AllValuesAreOk>,
142                                BitBlockType>::ValueType>::value));
143   EXPECT_TRUE(
144       (::std::is_same<Foo,
145                       EnumView<Foo, FixedSizeViewParameters<33, AllValuesAreOk>,
146                                BitBlockType>::ValueType>::value));
147   EXPECT_TRUE(
148       (::std::is_same<Foo,
149                       EnumView<Foo, FixedSizeViewParameters<64, AllValuesAreOk>,
150                                BitBlockType>::ValueType>::value));
151 }
152 
TEST(EnumView,CouldWriteValue)153 TEST(EnumView, CouldWriteValue) {
154   EXPECT_TRUE(FooViewN<64>::CouldWriteValue(Foo::kMax));
155   EXPECT_TRUE(FooViewN<64>::CouldWriteValue(Foo::kMax));
156   EXPECT_TRUE(FooViewN<24>::CouldWriteValue(Foo::k2to24MinusOne));
157   EXPECT_FALSE(FooViewN<24>::CouldWriteValue(Foo::k2to24));
158 }
159 
TEST(EnumView,ReadAndWriteWithSufficientBuffer)160 TEST(EnumView, ReadAndWriteWithSufficientBuffer) {
161   ::std::vector</**/ ::std::uint8_t> bytes = {
162       {0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08}};
163   auto enum64_view = FooViewN<64>{ReadWriteContiguousBuffer{bytes.data(), 8}};
164   EXPECT_EQ(Foo::kReallyBig, enum64_view.Read());
165   EXPECT_EQ(Foo::kReallyBig, enum64_view.UncheckedRead());
166   enum64_view.Write(Foo::kReallyBigBackwards);
167   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x09, 0x0a, 0x0b, 0x0c, 0x0d,
168                                                 0x0e, 0x0f, 0x10, 0x08}),
169             bytes);
170   enum64_view.UncheckedWrite(Foo::kReallyBig);
171   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x10, 0x0f, 0x0e, 0x0d, 0x0c,
172                                                 0x0b, 0x0a, 0x09, 0x08}),
173             bytes);
174   EXPECT_TRUE(enum64_view.TryToWrite(Foo::kReallyBigBackwards));
175   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x09, 0x0a, 0x0b, 0x0c, 0x0d,
176                                                 0x0e, 0x0f, 0x10, 0x08}),
177             bytes);
178   EXPECT_TRUE(enum64_view.Ok());
179   EXPECT_TRUE(enum64_view.IsComplete());
180 }
181 
TEST(EnumView,ReadAndWriteWithInsufficientBuffer)182 TEST(EnumView, ReadAndWriteWithInsufficientBuffer) {
183   ::std::vector</**/ ::std::uint8_t> bytes = {
184       {0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08}};
185   auto enum64_view = FooViewN<64>{ReadWriteContiguousBuffer{bytes.data(), 4}};
186   EXPECT_EQ(Foo::kReallyBig, enum64_view.UncheckedRead());
187 #if EMBOSS_CHECK_ABORTS
188   EXPECT_DEATH(enum64_view.Read(), "");
189   EXPECT_DEATH(enum64_view.Write(Foo::kReallyBigBackwards), "");
190 #endif  // EMBOSS_CHECK_ABORTS
191   EXPECT_FALSE(enum64_view.TryToWrite(Foo::kReallyBigBackwards));
192   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x10, 0x0f, 0x0e, 0x0d, 0x0c,
193                                                 0x0b, 0x0a, 0x09, 0x08}),
194             bytes);
195   enum64_view.UncheckedWrite(Foo::kReallyBigBackwards);
196   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x09, 0x0a, 0x0b, 0x0c, 0x0d,
197                                                 0x0e, 0x0f, 0x10, 0x08}),
198             bytes);
199   EXPECT_FALSE(enum64_view.Ok());
200   EXPECT_FALSE(enum64_view.IsComplete());
201 }
202 
TEST(EnumView,NonPowerOfTwoSize)203 TEST(EnumView, NonPowerOfTwoSize) {
204   ::std::vector</**/ ::std::uint8_t> bytes = {{0x10, 0x0f, 0x0e, 0x0d}};
205   auto enum24_view = FooViewN<24>{ReadWriteContiguousBuffer{bytes.data(), 3}};
206   EXPECT_EQ(Foo::kBig, enum24_view.Read());
207   EXPECT_EQ(Foo::kBig, enum24_view.UncheckedRead());
208   enum24_view.Write(Foo::kBigBackwards);
209   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x0e, 0x0f, 0x10, 0x0d}),
210             bytes);
211 #if EMBOSS_CHECK_ABORTS
212   EXPECT_DEATH(enum24_view.Write(Foo::k2to24), "");
213 #endif  // EMBOSS_CHECK_ABORTS
214   enum24_view.UncheckedWrite(Foo::k2to24);
215   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x00, 0x00, 0x00, 0x0d}),
216             bytes);
217   EXPECT_TRUE(enum24_view.Ok());
218   EXPECT_TRUE(enum24_view.IsComplete());
219 }
220 
TEST(EnumView,NonPowerOfTwoSizeInsufficientBuffer)221 TEST(EnumView, NonPowerOfTwoSizeInsufficientBuffer) {
222   ::std::vector</**/ ::std::uint8_t> bytes = {{0x10, 0x0f, 0x0e, 0x0d}};
223   auto enum24_view = FooViewN<24>{ReadWriteContiguousBuffer{bytes.data(), 2}};
224   EXPECT_EQ(Foo::kBig, enum24_view.UncheckedRead());
225 #if EMBOSS_CHECK_ABORTS
226   EXPECT_DEATH(enum24_view.Read(), "");
227   EXPECT_DEATH(enum24_view.Write(Foo::kBigBackwards), "");
228 #endif  // EMBOSS_CHECK_ABORTS
229   enum24_view.UncheckedWrite(Foo::kBigBackwards);
230   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x0e, 0x0f, 0x10, 0x0d}),
231             bytes);
232   EXPECT_FALSE(enum24_view.Ok());
233   EXPECT_FALSE(enum24_view.IsComplete());
234 }
235 
TEST(EnumView,UpdateFromText)236 TEST(EnumView, UpdateFromText) {
237   ::std::vector</**/ ::std::uint8_t> bytes = {
238       {0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08}};
239   const auto enum64_view =
240       FooViewN<64>{ReadWriteContiguousBuffer{bytes.data(), 8}};
241   EXPECT_TRUE(UpdateFromText(enum64_view, "kBig"));
242   EXPECT_EQ(Foo::kBig, enum64_view.Read());
243   EXPECT_TRUE(UpdateFromText(enum64_view, "k2to24"));
244   EXPECT_EQ(Foo::k2to24, enum64_view.Read());
245   EXPECT_FALSE(UpdateFromText(enum64_view, "k2to24M"));
246   EXPECT_EQ(Foo::k2to24, enum64_view.Read());
247   EXPECT_TRUE(UpdateFromText(enum64_view, "k2to24MinusOne"));
248   EXPECT_EQ(Foo::k2to24MinusOne, enum64_view.Read());
249   EXPECT_TRUE(UpdateFromText(enum64_view, "0x0e0f10"));
250   EXPECT_EQ(Foo::kBig, enum64_view.Read());
251   EXPECT_TRUE(UpdateFromText(enum64_view, "0x7654321"));
252   EXPECT_EQ(static_cast<Foo>(0x7654321), enum64_view.Read());
253   EXPECT_FALSE(UpdateFromText(enum64_view, "0y0"));
254   EXPECT_EQ(static_cast<Foo>(0x7654321), enum64_view.Read());
255   EXPECT_FALSE(UpdateFromText(enum64_view, "-x"));
256   EXPECT_EQ(static_cast<Foo>(0x7654321), enum64_view.Read());
257   EXPECT_TRUE(UpdateFromText(enum64_view, "-0x8000_0000_0000_0000"));
258   EXPECT_EQ(Foo::kMin, enum64_view.Read());
259 }
260 
TEST(EnumView,WriteToText)261 TEST(EnumView, WriteToText) {
262   ::std::vector</**/ ::std::uint8_t> bytes = {
263       {0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08}};
264   const auto enum64_view =
265       FooViewN<64>{ReadWriteContiguousBuffer{bytes.data(), 8}};
266   EXPECT_EQ("kReallyBig", WriteToString(enum64_view));
267   EXPECT_EQ("kReallyBig  # 651345242494996240",
268             WriteToString(enum64_view, TextOutputOptions().WithComments(true)));
269   EXPECT_EQ("kReallyBig  # 0x90a0b0c0d0e0f10",
270             WriteToString(
271                 enum64_view,
272                 TextOutputOptions().WithComments(true).WithNumericBase(16)));
273   enum64_view.Write(static_cast<Foo>(123));
274   EXPECT_EQ("123", WriteToString(enum64_view));
275   EXPECT_EQ("123",
276             WriteToString(enum64_view, TextOutputOptions().WithComments(true)));
277   EXPECT_EQ("0x7b",
278             WriteToString(
279                 enum64_view,
280                 TextOutputOptions().WithComments(true).WithNumericBase(16)));
281 }
282 
283 }  // namespace test
284 }  // namespace support
285 }  // namespace emboss
286