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 // Tests of generated code for virtual fields.
16 #include <stdint.h>
17
18 #include <type_traits>
19 #include <utility>
20 #include <vector>
21
22 #include "gtest/gtest.h"
23 #include "testdata/virtual_field.emb.h"
24
25 namespace emboss {
26 namespace test {
27 namespace {
28
29 // Check that the constant methods are generated as constexpr free functions in
30 // the type's aliased namespace, and have the appropriate values.
31 static_assert(StructureWithConstants::ten() == 10,
32 "StructureWithConstants::ten() == 10");
33 static_assert(StructureWithConstants::twenty() == 20,
34 "StructureWithConstants::twenty() == 20");
35 static_assert(StructureWithConstants::four_billion() == 4000000000U,
36 "StructureWithConstants::four_billion() == 4000000000U");
37 static_assert(StructureWithConstants::ten_billion() == 10000000000L,
38 "StructureWithConstants::ten_billion() == 10000000000L");
39 static_assert(StructureWithConstants::minus_ten_billion() == -10000000000L,
40 "StructureWithConstants::minus_ten_billion() == -10000000000L");
41
42 // Check the return types of the static Read methods.
43 static_assert(::std::is_same</**/ ::std::int32_t,
44 decltype(StructureWithConstants::ten())>::value,
45 "StructureWithConstants::ten() returns ::std::int8_t");
46 static_assert(::std::is_same</**/ ::std::int32_t,
47 decltype(StructureWithConstants::twenty())>::value,
48 "StructureWithConstants::twenty() returns ::std::int8_t");
49 static_assert(
50 ::std::is_same</**/ ::std::uint32_t,
51 decltype(StructureWithConstants::four_billion())>::value,
52 "StructureWithConstants::four_billion() returns ::std::uint32_t");
53 static_assert(
54 ::std::is_same</**/ ::std::int64_t,
55 decltype(StructureWithConstants::ten_billion())>::value,
56 "StructureWithConstants::ten_billion() returns ::std::int64_t");
57
TEST(Constants,ValuesOnView)58 TEST(Constants, ValuesOnView) {
59 ::std::array<char, 4> values = {0, 0, 0, 0};
60 const auto view = MakeStructureWithConstantsView(&values);
61 EXPECT_TRUE(view.Ok());
62 EXPECT_EQ(10, view.ten().Read());
63 EXPECT_EQ(10, view.alias_of_ten().Read());
64 EXPECT_EQ(10, view.alias_of_alias_of_ten().Read());
65 EXPECT_EQ(20, view.twenty().Read());
66 EXPECT_EQ(4000000000U, view.four_billion().Read());
67 EXPECT_EQ(10000000000L, view.ten_billion().Read());
68 EXPECT_EQ(0U, view.value().Read());
69 EXPECT_EQ(0U, view.alias_of_value().Read());
70 EXPECT_EQ(0U, view.alias_of_alias_of_value().Read());
71 view.alias_of_alias_of_value().Write(10);
72 EXPECT_EQ(10U, view.value().Read());
73 EXPECT_EQ(10U, view.alias_of_value().Read());
74 EXPECT_EQ(10U, view.alias_of_alias_of_value().Read());
75 }
76
TEST(Computed,Values)77 TEST(Computed, Values) {
78 ::std::array<char, 8> values = {5, 0, 0, 0, 50, 0, 0, 0};
79 const auto view = MakeStructureWithComputedValuesView(&values);
80 EXPECT_EQ(5U, view.value().Read());
81 EXPECT_EQ(10U, view.doubled().Read());
82 EXPECT_EQ(15U, view.plus_ten().Read());
83 EXPECT_EQ(50, view.value2().Read());
84 EXPECT_EQ(100, view.signed_doubled().Read());
85 EXPECT_EQ(60, view.signed_plus_ten().Read());
86 EXPECT_EQ(250, view.product().Read());
87 view.value2().Write(-50);
88 EXPECT_EQ(-100, view.signed_doubled().Read());
89 EXPECT_EQ(-40, view.signed_plus_ten().Read());
90 EXPECT_EQ(-250, view.product().Read());
91 }
92
93 #if EMBOSS_CHECK_ABORTS
TEST(Computed,ReadFailsWhenUnderlyingFieldIsNotOk)94 TEST(Computed, ReadFailsWhenUnderlyingFieldIsNotOk) {
95 ::std::array<char, 0> values = {};
96 const auto view = MakeStructureWithComputedValuesView(&values);
97 EXPECT_DEATH(view.value().Read(), "");
98 EXPECT_DEATH(view.doubled().Read(), "");
99 }
100 #endif // EMBOSS_CHECK_ABORTS
101
102 // Check the return types of nonstatic Read methods.
103 static_assert(
104 ::std::is_same</**/ ::std::int64_t,
105 decltype(MakeStructureWithComputedValuesView("x", 1)
106 .doubled()
107 .Read())>::value,
108 "StructureWithComputedValuesView::doubled().Read() should return "
109 "::std::int64_t.");
110 // Check the return types of nonstatic Read methods.
111 static_assert(
112 ::std::is_same</**/ ::std::int64_t,
113 decltype(MakeStructureWithComputedValuesView("x", 1)
114 .product()
115 .Read())>::value,
116 "StructureWithComputedValuesView::product().Read() should return "
117 "::std::int64_t.");
118
TEST(Constants,TextFormatWrite)119 TEST(Constants, TextFormatWrite) {
120 ::std::array<char, 4> values = {5, 0, 0, 0};
121 const auto view = MakeStructureWithConstantsView(&values);
122 // TODO(bolms): Provide a way of marking fields as "not for text format," so
123 // that end users can choose whether to use an alias or an original field or
124 // both in the text format.
125 EXPECT_EQ("{ value: 5, alias_of_value: 5, alias_of_alias_of_value: 5 }",
126 ::emboss::WriteToString(view));
127 EXPECT_EQ(
128 "{\n"
129 " # ten: 10 # 0xa\n"
130 " # twenty: 20 # 0x14\n"
131 " # four_billion: 4_000_000_000 # 0xee6b_2800\n"
132 " # ten_billion: 10_000_000_000 # 0x2_540b_e400\n"
133 " # minus_ten_billion: -10_000_000_000 # -0x2_540b_e400\n"
134 " value: 5 # 0x5\n"
135 " alias_of_value: 5 # 0x5\n"
136 " alias_of_alias_of_value: 5 # 0x5\n"
137 " # alias_of_ten: 10 # 0xa\n"
138 " # alias_of_alias_of_ten: 10 # 0xa\n"
139 "}",
140 ::emboss::WriteToString(view, ::emboss::MultilineText()));
141 }
142
TEST(Computed,TextFormatWrite)143 TEST(Computed, TextFormatWrite) {
144 ::std::array<char, 8> values = {5, 0, 0, 0, 50, 0, 0, 0};
145 const auto view = MakeStructureWithComputedValuesView(&values);
146 EXPECT_EQ("{ value: 5, plus_ten: 15, value2: 50, signed_plus_ten: 60 }",
147 ::emboss::WriteToString(view));
148 EXPECT_EQ(
149 "{\n"
150 " value: 5 # 0x5\n"
151 " # doubled: 10 # 0xa\n"
152 " plus_ten: 15 # 0xf\n"
153 " value2: 50 # 0x32\n"
154 " # signed_doubled: 100 # 0x64\n"
155 " signed_plus_ten: 60 # 0x3c\n"
156 " # product: 250 # 0xfa\n"
157 "}",
158 ::emboss::WriteToString(view, ::emboss::MultilineText()));
159 }
160
TEST(Constants,TextFormatRead)161 TEST(Constants, TextFormatRead) {
162 ::std::array<char, 4> values = {5, 0, 0, 0};
163 const auto view = MakeStructureWithConstantsView(&values);
164 EXPECT_TRUE(::emboss::UpdateFromText(view, "{ value: 50 }"));
165 EXPECT_EQ(50, values[0]);
166 EXPECT_FALSE(::emboss::UpdateFromText(view, "{ ten: 50 }"));
167 // TODO(bolms): Should this be allowed?
168 EXPECT_FALSE(::emboss::UpdateFromText(view, "{ ten: 10 }"));
169 }
170
TEST(Computed,TextFormatRead)171 TEST(Computed, TextFormatRead) {
172 ::std::array<char, 8> values = {5, 0, 0, 0, 50, 0, 0, 0};
173 const auto view = MakeStructureWithComputedValuesView(&values);
174 EXPECT_TRUE(::emboss::UpdateFromText(view, "{ value: 50, value2: 5 }"));
175 EXPECT_EQ(50, values[0]);
176 EXPECT_EQ(5, values[4]);
177 EXPECT_FALSE(::emboss::UpdateFromText(view, "{ product: 10 }"));
178 // TODO(bolms): Make Emboss automatically infer write_transform for
179 // easily-reversible cases like `field * 2`.
180 EXPECT_FALSE(::emboss::UpdateFromText(view, "{ doubled: 10 }"));
181 }
182
TEST(ConditionalVirtual,ConditionChecks)183 TEST(ConditionalVirtual, ConditionChecks) {
184 ::std::array<char, 4> values = {5, 0, 0, 0};
185 const auto view = MakeStructureWithConditionalValueView(&values);
186 EXPECT_TRUE(view.has_two_x().Value());
187 EXPECT_TRUE(view.has_x_plus_one().Value());
188 EXPECT_EQ(10, view.two_x().Read());
189 EXPECT_EQ(6, view.x_plus_one().Read());
190 EXPECT_EQ(10, view.two_x().UncheckedRead());
191 EXPECT_EQ(6, view.x_plus_one().UncheckedRead());
192 view.x().Write(0x80000000U);
193 EXPECT_FALSE(view.has_two_x().Value());
194 #if EMBOSS_CHECK_ABORTS
195 EXPECT_DEATH(view.two_x().Read(), "");
196 #endif // EMBOSS_CHECK_ABORTS
197 EXPECT_TRUE(view.has_x_plus_one().Value());
198 EXPECT_EQ(0x80000001U, view.x_plus_one().Read());
199 }
200
TEST(ConditionalVirtual,UncheckedRead)201 TEST(ConditionalVirtual, UncheckedRead) {
202 ::std::array<char, 4> values = {5, 0, 0, 0};
203 const auto view = MakeStructureWithConditionalValueView(&values[0], 1);
204 EXPECT_FALSE(view.Ok());
205 EXPECT_FALSE(view.x().Ok());
206 #if EMBOSS_CHECK_ABORTS
207 EXPECT_DEATH(view.two_x().Read(), "");
208 #endif // EMBOSS_CHECK_ABORTS
209 EXPECT_EQ(0, view.two_x().UncheckedRead());
210 }
211
TEST(ConditionalVirtual,TextFormatWrite)212 TEST(ConditionalVirtual, TextFormatWrite) {
213 ::std::array<unsigned char, 4> values = {0, 0, 0, 0x80};
214 const auto view = MakeStructureWithConditionalValueView(&values);
215 EXPECT_EQ("{ x: 2147483648, x_plus_one: 2147483649 }",
216 ::emboss::WriteToString(view));
217 EXPECT_EQ(
218 "{\n"
219 " x: 2_147_483_648 # 0x8000_0000\n"
220 " x_plus_one: 2_147_483_649 # 0x8000_0001\n"
221 "}",
222 ::emboss::WriteToString(view, ::emboss::MultilineText()));
223 view.x().Write(5);
224 EXPECT_EQ("{ x: 5, x_plus_one: 6 }", ::emboss::WriteToString(view));
225 EXPECT_EQ(
226 "{\n"
227 " x: 5 # 0x5\n"
228 " # two_x: 10 # 0xa\n"
229 " x_plus_one: 6 # 0x6\n"
230 "}",
231 ::emboss::WriteToString(view, ::emboss::MultilineText()));
232 }
233
TEST(VirtualInCondition,ConditionCheck)234 TEST(VirtualInCondition, ConditionCheck) {
235 ::std::array<char, 8> values = {5, 0, 0, 0, 50, 0, 0, 0};
236 const auto view = MakeStructureWithValueInConditionView(&values);
237 EXPECT_TRUE(view.has_if_two_x_lt_100().Value());
238 view.x().Write(75);
239 EXPECT_FALSE(view.has_if_two_x_lt_100().Value());
240 }
241
TEST(VirtualInLocation,Offset)242 TEST(VirtualInLocation, Offset) {
243 ::std::array<char, 8> values = {5, 0, 0, 0, 50, 0, 0, 0};
244 const auto view = MakeStructureWithValuesInLocationView(&values);
245 EXPECT_FALSE(view.Ok());
246 view.x().Write(2);
247 EXPECT_TRUE(view.Ok());
248 EXPECT_EQ(50U, view.offset_two_x().Read());
249 EXPECT_EQ(50U, view.size_two_x().Read());
250 view.x().Write(1);
251 EXPECT_FALSE(view.Ok());
252 EXPECT_EQ(50 * 0x10000U, view.offset_two_x().Read());
253 view.x().Write(0);
254 EXPECT_EQ(0U, view.offset_two_x().Read());
255 }
256
TEST(BooleanVirtual,TrueAndFalse)257 TEST(BooleanVirtual, TrueAndFalse) {
258 ::std::array<char, 4> values = {5, 0, 0, 0};
259 const auto view = MakeStructureWithBoolValueView(&values);
260 EXPECT_TRUE(view.Ok());
261 EXPECT_FALSE(view.x_is_ten().Read());
262 view.x().Write(10);
263 EXPECT_TRUE(view.x_is_ten().Read());
264 }
265
TEST(EnumVirtual,SmallAndLarge)266 TEST(EnumVirtual, SmallAndLarge) {
267 ::std::array<char, 4> values = {5, 0, 0, 0};
268 const auto view = MakeStructureWithEnumValueView(&values);
269 EXPECT_TRUE(view.Ok());
270 EXPECT_EQ(StructureWithEnumValue::Category::SMALL, view.x_size().Read());
271 view.x().Write(100);
272 EXPECT_EQ(StructureWithEnumValue::Category::LARGE, view.x_size().Read());
273 }
274
TEST(BitsVirtual,Sum)275 TEST(BitsVirtual, Sum) {
276 ::std::array<char, 4> values = {5, 0, 10, 0};
277 const auto view = MakeStructureWithBitsWithValueView(&values);
278 EXPECT_TRUE(view.Ok());
279 EXPECT_EQ(5, view.b().a().Read());
280 EXPECT_EQ(5, view.alias_of_b_a().Read());
281 EXPECT_EQ(10, view.b().b().Read());
282 EXPECT_EQ(15, view.b().sum().Read());
283 EXPECT_EQ(15, view.alias_of_b_sum().Read());
284 view.alias_of_b_a().Write(20);
285 EXPECT_EQ(20, view.b().a().Read());
286 EXPECT_EQ(20, view.alias_of_b_a().Read());
287 EXPECT_EQ(20, values[0]);
288 }
289
TEST(ForeignConstants,ForeignConstants)290 TEST(ForeignConstants, ForeignConstants) {
291 static_assert(StructureUsingForeignConstants::one_hundred() == 100,
292 "StructureUsingForeignConstants::one_hundred() == 100");
293 ::std::array<char, 14> values = {5, 0, 0, 0, 10, 0, 0, 0, 15, 0, 20, 0, 0, 0};
294 const auto view = MakeStructureUsingForeignConstantsView(&values);
295 EXPECT_TRUE(view.Ok());
296 EXPECT_EQ(20U, view.x().Read());
297 EXPECT_EQ(100, view.one_hundred().Read());
298 }
299
TEST(HasField,HasField)300 TEST(HasField, HasField) {
301 ::std::array<char, 3> values = {0, 0, 0};
302 const auto view = MakeHasFieldView(&values);
303 EXPECT_FALSE(view.Ok()); // There is not enough information to determine if
304 // view.has_y(), so the view is not Ok().
305 view.z().Write(11);
306 EXPECT_TRUE(view.Ok());
307 EXPECT_FALSE(view.has_y().Value());
308 EXPECT_TRUE(view.has_x().Value());
309 EXPECT_FALSE(view.x().has_y().Value());
310 EXPECT_FALSE(view.x_has_y().Read());
311 EXPECT_FALSE(view.x_has_y().UncheckedRead());
312 view.x().v().Write(11);
313 EXPECT_TRUE(view.Ok());
314 EXPECT_TRUE(view.has_y().Value());
315 EXPECT_TRUE(view.has_x().Value());
316 EXPECT_TRUE(view.x().has_y().Value());
317 EXPECT_TRUE(view.x_has_y().Read());
318 EXPECT_TRUE(view.x_has_y().UncheckedRead());
319 }
320
TEST(RestrictedAlias,RestrictedAlias)321 TEST(RestrictedAlias, RestrictedAlias) {
322 ::std::array<char, 5> values = {1, 2, 3, 4, 5};
323 const auto view = MakeRestrictedAliasView(&values);
324 EXPECT_TRUE(view.Ok());
325 EXPECT_TRUE(view.has_a_b().Value());
326 EXPECT_TRUE(view.a_b().Ok());
327 EXPECT_FALSE(view.has_a_b_alias().Value());
328 EXPECT_FALSE(view.a_b_alias().Ok());
329 EXPECT_FALSE(view.a_b_alias().a().Ok());
330 EXPECT_FALSE(view.a_b_alias().b().Ok());
331 view.alias_switch().Write(11);
332 EXPECT_TRUE(view.has_a_b().Value());
333 EXPECT_TRUE(view.a_b().Ok());
334 EXPECT_TRUE(view.has_a_b_alias().Value());
335 EXPECT_TRUE(view.a_b_alias().Ok());
336 }
337
TEST(VirtualWithConditionalComponent,ReadWhenAllPresent)338 TEST(VirtualWithConditionalComponent, ReadWhenAllPresent) {
339 ::std::array<char, 2> values = {0, 0};
340 const auto view = MakeVirtualUnconditionallyUsesConditionalView(&values);
341 EXPECT_TRUE(view.x_nor_xc().Read());
342 EXPECT_TRUE(view.x_nor_xc().UncheckedRead());
343 }
344
TEST(VirtualWithConditionalComponent,ReadWhenNotAllPresent)345 TEST(VirtualWithConditionalComponent, ReadWhenNotAllPresent) {
346 ::std::array<char, 2> values = {1, 0};
347 const auto view = MakeVirtualUnconditionallyUsesConditionalView(&values);
348 EXPECT_FALSE(view.x_nor_xc().Read());
349 EXPECT_FALSE(view.x_nor_xc().UncheckedRead());
350 }
351
TEST(IntrinsicSize,SizeInBytes)352 TEST(IntrinsicSize, SizeInBytes) {
353 ::std::array<char, 1> values = {10};
354 const auto view = MakeUsesSizeView(&values);
355 EXPECT_TRUE(view.Ok());
356 EXPECT_TRUE(view.IntrinsicSizeInBytes().Ok());
357 EXPECT_EQ(1, view.IntrinsicSizeInBytes().Read());
358 EXPECT_EQ(1, UsesSizeView::IntrinsicSizeInBytes().Read());
359 EXPECT_EQ(1, UsesSize::IntrinsicSizeInBytes());
360 EXPECT_TRUE(view.r().IntrinsicSizeInBits().Ok());
361 EXPECT_EQ(8, view.r().IntrinsicSizeInBits().Read());
362 EXPECT_EQ(8, UsesSize::R::IntrinsicSizeInBits());
363 EXPECT_EQ(values[0], view.r().q().Read());
364 EXPECT_EQ(values[0] + 1, view.r_q_plus_byte_size().Read());
365 EXPECT_EQ(values[0] + 8, view.r().q_plus_bit_size().Read());
366 }
367
TEST(VirtualFields,SizeInBytes)368 TEST(VirtualFields, SizeInBytes) {
369 const ::std::array</**/ ::std::uint8_t, 8> values = {0x11, 0x11, 0x11, 0x11,
370 0x22, 0x22, 0x22, 0x22};
371 const auto view = MakeUsesExternalSizeView(&values);
372 EXPECT_TRUE(view.Ok());
373 EXPECT_EQ(8U, view.SizeInBytes());
374 EXPECT_EQ(view.x().SizeInBytes(), 4U);
375 EXPECT_EQ(view.y().SizeInBytes(), 4U);
376 EXPECT_EQ(view.x().value().Read(), 0x11111111U);
377 EXPECT_EQ(view.y().value().Read(), 0x22222222U);
378 EXPECT_TRUE(view.IntrinsicSizeInBytes().Ok());
379 EXPECT_EQ(8, UsesExternalSizeView::IntrinsicSizeInBytes().Read());
380 EXPECT_EQ(8, UsesExternalSize::MaxSizeInBytes());
381 }
382
TEST(WriteTransform,Write)383 TEST(WriteTransform, Write) {
384 ::std::array<char, 1> values = {0};
385 const auto view = MakeImplicitWriteBackView(&values);
386
387 view.x_plus_ten().Write(11);
388 EXPECT_EQ(1, view.x().Read());
389 EXPECT_EQ(11, view.x_plus_ten().Read());
390
391 view.ten_plus_x().Write(12);
392 EXPECT_EQ(2, view.x().Read());
393 EXPECT_EQ(12, view.ten_plus_x().Read());
394
395 EXPECT_TRUE((::std::is_same<decltype(view.x_minus_ten())::ValueType,
396 ::std::int32_t>::value));
397
398 view.x_minus_ten().Write(-7);
399 EXPECT_EQ(3, view.x().Read());
400 EXPECT_EQ(-7, view.x_minus_ten().Read());
401
402 view.ten_minus_x().Write(6);
403 EXPECT_EQ(4, view.x().Read());
404 EXPECT_EQ(6, view.ten_minus_x().Read());
405
406 view.ten_minus_x_plus_ten().Write(4);
407 EXPECT_EQ(16, view.x().Read());
408 EXPECT_EQ(4, view.ten_minus_x_plus_ten().Read());
409 }
410
TEST(WriteTransform,CouldWriteValue)411 TEST(WriteTransform, CouldWriteValue) {
412 ::std::array<char, 1> values = {0};
413 const auto view = MakeImplicitWriteBackView(&values);
414 EXPECT_EQ(0, view.x().Read());
415 // x is UInt:8, so has range [0, 255].
416
417 EXPECT_FALSE(view.x_plus_ten().CouldWriteValue(9));
418 EXPECT_TRUE(view.x_plus_ten().CouldWriteValue(10));
419 EXPECT_TRUE(view.x_plus_ten().CouldWriteValue(265));
420 EXPECT_FALSE(view.x_plus_ten().CouldWriteValue(266));
421
422 EXPECT_FALSE(view.ten_plus_x().CouldWriteValue(9));
423 EXPECT_TRUE(view.ten_plus_x().CouldWriteValue(10));
424 EXPECT_TRUE(view.ten_plus_x().CouldWriteValue(265));
425 EXPECT_FALSE(view.ten_plus_x().CouldWriteValue(266));
426
427 EXPECT_FALSE(view.x_minus_ten().CouldWriteValue(-11));
428 EXPECT_TRUE(view.x_minus_ten().CouldWriteValue(-10));
429 EXPECT_TRUE(view.x_minus_ten().CouldWriteValue(245));
430 EXPECT_FALSE(view.x_minus_ten().CouldWriteValue(246));
431
432 EXPECT_FALSE(view.ten_minus_x().CouldWriteValue(-246));
433 EXPECT_TRUE(view.ten_minus_x().CouldWriteValue(-245));
434 EXPECT_TRUE(view.ten_minus_x().CouldWriteValue(10));
435 EXPECT_FALSE(view.ten_minus_x().CouldWriteValue(11));
436
437 EXPECT_FALSE(view.ten_minus_x_plus_ten().CouldWriteValue(-236));
438 EXPECT_TRUE(view.ten_minus_x_plus_ten().CouldWriteValue(-235));
439 EXPECT_TRUE(view.ten_minus_x_plus_ten().CouldWriteValue(20));
440 EXPECT_FALSE(view.ten_minus_x_plus_ten().CouldWriteValue(21));
441 }
442
443 } // namespace
444 } // namespace test
445 } // namespace emboss
446