• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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