• 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 for fields and structs with dynamic sizes.
16 #include <stdint.h>
17 
18 #include <vector>
19 
20 #include "gtest/gtest.h"
21 #include "testdata/dynamic_size.emb.h"
22 
23 namespace emboss {
24 namespace test {
25 namespace {
26 
27 static constexpr ::std::array</**/ ::std::uint8_t, 16> kMessage = {{
28     0x02,                                // 0:1   header_length = 2
29     0x06,                                // 1:2   message_length = 6
30     0x01, 0x02, 0x03, 0x04, 0x05, 0x06,  // 2:8   message
31     0x07, 0x08, 0x09, 0x0a,              // 8:12  crc32
32     0x00, 0x00, 0x00, 0x00,              // Extra, unused bytes.
33 }};
34 
35 // MessageView::SizeInBytes() returns the expected value.
TEST(MessageView,DynamicSizeIsCorrect)36 TEST(MessageView, DynamicSizeIsCorrect) {
37   auto view = MessageView(&kMessage);
38   EXPECT_EQ(12U, view.SizeInBytes());
39 }
40 
41 // Fields read the correct values.
TEST(MessageView,FieldsAreCorrect)42 TEST(MessageView, FieldsAreCorrect) {
43   auto view = MessageView(&kMessage);
44   EXPECT_EQ(2U, view.header_length().Read());
45   EXPECT_EQ(6U, view.message_length().Read());
46   EXPECT_EQ(1U, view.message()[0].Read());
47   EXPECT_EQ(2U, view.message()[1].Read());
48   EXPECT_EQ(3U, view.message()[2].Read());
49   EXPECT_EQ(4U, view.message()[3].Read());
50   EXPECT_EQ(5U, view.message()[4].Read());
51   EXPECT_EQ(6U, view.message()[5].Read());
52   EXPECT_EQ(6U, view.message().SizeInBytes());
53 #if EMBOSS_CHECK_ABORTS
54   EXPECT_DEATH(view.message()[6].Read(), "");
55 #endif  // EMBOSS_CHECK_ABORTS
56   EXPECT_EQ(0x0a090807U, view.crc32().Read());
57 }
58 
59 // The zero-length padding field works as expected.
TEST(MessageView,PaddingFieldWorks)60 TEST(MessageView, PaddingFieldWorks) {
61   auto view = MessageView(&kMessage);
62   EXPECT_EQ(0U, view.padding().SizeInBytes());
63 #if EMBOSS_CHECK_ABORTS
64   EXPECT_DEATH(view.padding()[0].Read(), "");
65 #endif  // EMBOSS_CHECK_ABORTS
66 }
67 
68 static constexpr ::std::array</**/ ::std::uint8_t, 16> kPaddedMessage = {{
69     0x06,                    // 0:1    header_length = 6
70     0x04,                    // 1:2    message_length = 4
71     0x01, 0x02, 0x03, 0x04,  // 2:6    padding
72     0x05, 0x06, 0x07, 0x08,  // 6:10   message
73     0x09, 0x0a, 0x0b, 0x0c,  // 10:14  crc32
74     0x00, 0x00,              // Extra, unused bytes.
75 }};
76 
77 // Fields read the correct values.
TEST(MessageView,PaddedMessageFieldsAreCorrect)78 TEST(MessageView, PaddedMessageFieldsAreCorrect) {
79   auto view = MessageView(&kPaddedMessage);
80   EXPECT_EQ(6U, view.header_length().Read());
81   EXPECT_EQ(4U, view.message_length().Read());
82   EXPECT_EQ(1U, view.padding()[0].Read());
83   EXPECT_EQ(2U, view.padding()[1].Read());
84   EXPECT_EQ(3U, view.padding()[2].Read());
85   EXPECT_EQ(4U, view.padding()[3].Read());
86   EXPECT_EQ(4U, view.padding().SizeInBytes());
87 #if EMBOSS_CHECK_ABORTS
88   EXPECT_DEATH(view.padding()[4].Read(), "");
89 #endif  // EMBOSS_CHECK_ABORTS
90   EXPECT_EQ(5U, view.message()[0].Read());
91   EXPECT_EQ(6U, view.message()[1].Read());
92   EXPECT_EQ(7U, view.message()[2].Read());
93   EXPECT_EQ(8U, view.message()[3].Read());
94   EXPECT_EQ(4U, view.message().SizeInBytes());
95 #if EMBOSS_CHECK_ABORTS
96   EXPECT_DEATH(view.message()[4].Read(), "");
97 #endif  // EMBOSS_CHECK_ABORTS
98   EXPECT_EQ(0x0c0b0a09U, view.crc32().Read());
99 }
100 
101 // Writes to fields produce the correct byte values.
TEST(MessageView,Writer)102 TEST(MessageView, Writer) {
103   ::std::uint8_t buffer[kPaddedMessage.size()] = {0};
104   auto writer = MessageWriter(buffer, sizeof buffer);
105 
106   // Write values that should match kMessage.
107   writer.header_length().Write(2);
108   writer.message_length().Write(6);
109   EXPECT_EQ(6, writer.message_length().Read());
110   for (int i = 0; i < writer.message_length().Read(); ++i) {
111     writer.message()[i].Write(i + 1);
112   }
113   EXPECT_EQ(12U, writer.SizeInBytes());
114 #if EMBOSS_CHECK_ABORTS
115   EXPECT_DEATH(writer.message()[writer.message_length().Read()].Read(), "");
116   EXPECT_DEATH(writer.padding()[0].Read(), "");
117 #endif  // EMBOSS_CHECK_ABORTS
118   writer.crc32().Write(0x0a090807);
119   EXPECT_EQ(
120       ::std::vector</**/ ::std::uint8_t>(kMessage.begin(), kMessage.end()),
121       ::std::vector</**/ ::std::uint8_t>(buffer, buffer + kMessage.size()));
122 
123   // Update values to match kPaddedMessage.  Only update values that are
124   // different.
125   auto writer2 = MessageWriter(buffer, sizeof buffer);
126   writer2.header_length().Write(6);
127   // Writes made through one writer should be immediately visible to the other.
128   EXPECT_EQ(6U, writer.header_length().Read());
129   EXPECT_EQ(6U, writer2.header_length().Read());
130   writer2.message_length().Write(4);
131   // The message() field is now pointing to a different place; it should read
132   // the data that was already there.
133   EXPECT_EQ(5U, writer2.message()[0].Read());
134   // The padding bytes are already set to the correct values; do not update
135   // them.
136   for (int i = 0; i < writer2.message_length().Read(); ++i) {
137     writer2.padding()[i].Write(i + 1);
138   }
139   writer2.crc32().Write(0x0c0b0a09);
140   EXPECT_EQ(::std::vector</**/ ::std::uint8_t>(kPaddedMessage.begin(),
141                                                kPaddedMessage.end()),
142             ::std::vector</**/ ::std::uint8_t>(buffer,
143                                                buffer + kPaddedMessage.size()));
144 }
145 
TEST(MessageView,MakeFromPointerArrayIterator)146 TEST(MessageView, MakeFromPointerArrayIterator) {
147   ::std::array<const ::std::array</**/ ::std::uint8_t, 16> *, 2> buffers = {
148       {&kMessage, &kPaddedMessage}};
149   // Ensure that the weird const-reference-to-pointer type returned by iteration
150   // over a std::array of std::arrays actually compiles.
151   for (const auto &buffer : buffers) {
152     auto view = MakeMessageView(buffer);
153     // Message length is 4 or 6, depending on the iteration.
154     EXPECT_TRUE(view.message_length().Read() == 4 ||
155                 view.message_length().Read() == 6);
156   }
157 }
158 
159 static const ::std::uint8_t kThreeByFiveImage[46] = {
160     0x03,              // 0:1  size
161     0x01, 0x02, 0x03,  // pixels[0][0]
162     0x04, 0x05, 0x06,  // pixels[0][1]
163     0x07, 0x08, 0x09,  // pixels[0][2]
164     0x0a, 0x0b, 0x0c,  // pixels[0][3]
165     0x0d, 0x0e, 0x0f,  // pixels[0][4]
166     0x10, 0x11, 0x12,  // pixels[1][0]
167     0x13, 0x14, 0x15,  // pixels[1][1]
168     0x16, 0x17, 0x18,  // pixels[1][2]
169     0x19, 0x1a, 0x1b,  // pixels[1][3]
170     0x1c, 0x1d, 0x1e,  // pixels[1][4]
171     0x1f, 0x20, 0x21,  // pixels[2][0]
172     0x22, 0x23, 0x24,  // pixels[2][1]
173     0x25, 0x26, 0x27,  // pixels[2][2]
174     0x28, 0x29, 0x2a,  // pixels[2][3]
175     0x2b, 0x2c, 0x2d,  // pixels[2][4]
176 };
177 
178 // A variable-sized array of fixed-size arrays of fixed-size arrays reads
179 // correct values.
TEST(ImageView,PixelsAreCorrect)180 TEST(ImageView, PixelsAreCorrect) {
181   auto view = ImageView(kThreeByFiveImage, sizeof kThreeByFiveImage);
182   int counter = 1;
183   for (int x = 0; x < view.size().Read(); ++x) {
184     for (int y = 0; y < 5; ++y) {
185       for (int channel = 0; channel < 3; ++channel) {
186         EXPECT_EQ(counter, view.pixels()[x][y][channel].Read())
187             << "x: " << x << "; y: " << y << "; channel: " << channel;
188         ++counter;
189       }
190     }
191   }
192 }
193 
TEST(ImageView,WritePixels)194 TEST(ImageView, WritePixels) {
195   ::std::uint8_t buffer[sizeof kThreeByFiveImage];
196   auto writer = ImageWriter(buffer, sizeof buffer);
197   writer.size().Write(3);
198   int counter = 1;
199   for (int x = 0; x < writer.size().Read(); ++x) {
200     for (int y = 0; y < 5; ++y) {
201       for (int channel = 0; channel < 3; ++channel) {
202         writer.pixels()[x][y][channel].Write(counter);
203         ++counter;
204       }
205     }
206   }
207   EXPECT_EQ(
208       ::std::vector</**/ ::std::uint8_t>(
209           kThreeByFiveImage, kThreeByFiveImage + sizeof kThreeByFiveImage),
210       ::std::vector</**/ ::std::uint8_t>(buffer, buffer + sizeof buffer));
211 }
212 
213 static const ::std::uint8_t kTwoRegionsAFirst[10] = {
214     0x04,                    // 0:1   a_start
215     0x02,                    // 1:2   a_size
216     0x06,                    // 2:3   b_start
217     0x0a,                    // 3:4   b_end
218     0x11, 0x22,              // 4:6   region_a
219     0x33, 0x44, 0x55, 0x66,  // 6:10  region_b
220 };
221 
222 // With two dynamically-positioned regions, having the binary locations match
223 // the order of their declarations works.
TEST(TwoRegionsView,RegionAFirstWorks)224 TEST(TwoRegionsView, RegionAFirstWorks) {
225   auto view = TwoRegionsView(kTwoRegionsAFirst, sizeof kTwoRegionsAFirst);
226   EXPECT_EQ(10U, view.SizeInBytes());
227   EXPECT_EQ(4U, view.a_start().Read());
228   EXPECT_EQ(2U, view.a_size().Read());
229   EXPECT_EQ(6U, view.b_start().Read());
230   EXPECT_EQ(10U, view.b_end().Read());
231   EXPECT_EQ(0x11U, view.region_a()[0].Read());
232   EXPECT_EQ(0x22U, view.region_a()[1].Read());
233   EXPECT_EQ(0x33U, view.region_b()[0].Read());
234   EXPECT_EQ(0x66U, view.region_b()[3].Read());
235 }
236 
237 static const ::std::uint8_t kTwoRegionsBFirst[14] = {
238     0x0a,                    // 0:1    a_start
239     0x04,                    // 1:2    a_size
240     0x04,                    // 2:3    b_start
241     0x06,                    // 3:4    b_end
242     0x11, 0x22,              // 4:6    region_b
243     0xff, 0xff, 0xff, 0xff,  // 6:10   unmapped
244     0x33, 0x44, 0x55, 0x66,  // 10:14  region_a
245 };
246 
247 // With two dynamically-positioned regions, having the binary locations opposite
248 // of the order of their declarations works.
TEST(TwoRegionsView,RegionBFirstWorks)249 TEST(TwoRegionsView, RegionBFirstWorks) {
250   auto view = TwoRegionsView(kTwoRegionsBFirst, sizeof kTwoRegionsBFirst);
251   EXPECT_EQ(14U, view.SizeInBytes());
252   EXPECT_EQ(10U, view.a_start().Read());
253   EXPECT_EQ(4U, view.a_size().Read());
254   EXPECT_EQ(4U, view.b_start().Read());
255   EXPECT_EQ(6U, view.b_end().Read());
256   EXPECT_EQ(0x33U, view.region_a()[0].Read());
257   EXPECT_EQ(0x66U, view.region_a()[3].Read());
258   EXPECT_EQ(0x11U, view.region_b()[0].Read());
259   EXPECT_EQ(0x22U, view.region_b()[1].Read());
260 }
261 
262 static const ::std::uint8_t kTwoRegionsAAndBOverlap[8] = {
263     0x05,                    // 0:1  a_start
264     0x02,                    // 1:2  a_size
265     0x04,                    // 2:3  b_start
266     0x08,                    // 3:4  b_end
267     0x11, 0x22, 0x33, 0x44,  // 4:8  region_a / region_b
268 };
269 
270 // With two dynamically-positioned regions, having the binary locations overlap
271 // works.
TEST(TwoRegionsView,RegionAAndBOverlappedWorks)272 TEST(TwoRegionsView, RegionAAndBOverlappedWorks) {
273   auto view =
274       TwoRegionsView(kTwoRegionsAAndBOverlap, sizeof kTwoRegionsAAndBOverlap);
275   EXPECT_EQ(8U, view.SizeInBytes());
276   EXPECT_EQ(5U, view.a_start().Read());
277   EXPECT_EQ(2U, view.a_size().Read());
278   EXPECT_EQ(4U, view.b_start().Read());
279   EXPECT_EQ(8U, view.b_end().Read());
280   EXPECT_EQ(0x22U, view.region_a()[0].Read());
281   EXPECT_EQ(0x33U, view.region_a()[1].Read());
282   EXPECT_EQ(0x11U, view.region_b()[0].Read());
283   EXPECT_EQ(0x22U, view.region_b()[1].Read());
284   EXPECT_EQ(0x33U, view.region_b()[2].Read());
285   EXPECT_EQ(0x44U, view.region_b()[3].Read());
286 }
287 
TEST(TwoRegionsView,Write)288 TEST(TwoRegionsView, Write) {
289   ::std::uint8_t buffer[64];
290   auto writer = TwoRegionsWriter(buffer, sizeof buffer);
291   writer.a_start().Write(4);
292   writer.a_size().Write(2);
293   writer.b_start().Write(6);
294   writer.b_end().Write(10);
295   writer.region_a()[0].Write(0x11);
296   writer.region_a()[1].Write(0x22);
297   writer.region_b()[0].Write(0x33);
298   writer.region_b()[1].Write(0x44);
299   writer.region_b()[2].Write(0x55);
300   writer.region_b()[3].Write(0x66);
301   EXPECT_EQ(
302       ::std::vector</**/ ::std::uint8_t>(
303           kTwoRegionsAFirst, kTwoRegionsAFirst + sizeof kTwoRegionsAFirst),
304       ::std::vector</**/ ::std::uint8_t>(buffer,
305                                          buffer + sizeof kTwoRegionsAFirst));
306 
307   writer.a_start().Write(10);
308   writer.a_size().Write(4);
309   writer.b_start().Write(4);
310   writer.b_end().Write(6);
311   writer.region_a()[0].Write(0x33);
312   writer.region_a()[1].Write(0x44);
313   writer.region_a()[2].Write(0x55);
314   writer.region_a()[3].Write(0x66);
315   writer.region_b()[0].Write(0x11);
316   writer.region_b()[1].Write(0x22);
317   // Set the unmapped region correctly.
318   buffer[6] = 0xff;
319   buffer[7] = 0xff;
320   buffer[8] = 0xff;
321   buffer[9] = 0xff;
322   EXPECT_EQ(
323       ::std::vector</**/ ::std::uint8_t>(
324           kTwoRegionsBFirst, kTwoRegionsBFirst + sizeof kTwoRegionsBFirst),
325       ::std::vector</**/ ::std::uint8_t>(buffer,
326                                          buffer + sizeof kTwoRegionsBFirst));
327 
328   writer.a_start().Write(5);
329   writer.a_size().Write(2);
330   writer.b_start().Write(4);
331   writer.b_end().Write(8);
332   writer.region_b()[0].Write(0x11);
333   writer.region_b()[1].Write(0xff);
334   writer.region_b()[2].Write(0xee);
335   writer.region_b()[3].Write(0x44);
336   EXPECT_EQ(0xffU, writer.region_a()[0].Read());
337   EXPECT_EQ(0xeeU, writer.region_a()[1].Read());
338   writer.region_a()[0].Write(0x22);
339   writer.region_a()[1].Write(0x33);
340   EXPECT_EQ(0x22U, writer.region_b()[1].Read());
341   EXPECT_EQ(0x33U, writer.region_b()[2].Read());
342   EXPECT_EQ(::std::vector</**/ ::std::uint8_t>(
343                 kTwoRegionsAAndBOverlap,
344                 kTwoRegionsAAndBOverlap + sizeof kTwoRegionsAAndBOverlap),
345             ::std::vector</**/ ::std::uint8_t>(
346                 buffer, buffer + sizeof kTwoRegionsAAndBOverlap));
347 }
348 
349 static const ::std::uint8_t kMultipliedSize[299] = {
350     0x09,  // 0:1    width == 9
351     0x21,  // 1:2    height == 33
352     // 9 x 33 == 297-byte block for data.
353     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 2:11
354     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 11:20
355     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 20:29
356     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 29:38
357     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 38:47
358     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 47:56
359     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 56:65
360     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 65:74
361     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 74:83
362     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 83:92
363     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 92:101
364     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 101:110
365     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 110:119
366     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 119:128
367     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 128:137
368     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 137:146
369     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 146:155
370     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 155:164
371     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 164:173
372     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 173:182
373     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 182:191
374     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 191:200
375     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 200:209
376     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 209:218
377     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 218:227
378     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 227:236
379     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 236:245
380     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 245:254
381     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 254:263
382     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 263:272
383     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 272:281
384     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 281:290
385     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,  // 290:299
386 };
387 
388 // A structure with two 8-bit fields whose values are multiplied to get the
389 // length of an array works, even when the length of the array is too big to
390 // fit in 8 bits.
TEST(MultipliedSizeView,MultipliedSizesUseWideEnoughArithmetic)391 TEST(MultipliedSizeView, MultipliedSizesUseWideEnoughArithmetic) {
392   auto view = MultipliedSizeView(kMultipliedSize, sizeof kMultipliedSize);
393   EXPECT_EQ(299U, view.SizeInBytes());
394   EXPECT_EQ(9U, view.width().Read());
395   EXPECT_EQ(33U, view.height().Read());
396   EXPECT_EQ(1U, view.data()[0].Read());
397   EXPECT_EQ(0xffU, view.data()[296].Read());
398 }
399 
400 static const ::std::uint8_t kNegativeTermsInSizesAMinusBIsBiggest[7] = {
401     0x07,  // 0:1  a
402     0x01,  // 1:2  b
403     0x02,  // 2:3  c
404     // 3:a-b   == 3:6  a_minus_b
405     // 3:a-2*b == 3:5  a_minus_2b
406     // 3:a-b-c == 3:4  a_minus_b_minus_c
407     // 3:10-a  == 3:3  ten_minus_a
408     // 3:a-2*c == 3:3  a_minus_2c
409     // 3:a-c   == 3:5  a_minus_c
410     0x11,
411     0x22,
412     0x33,
413     0x44,
414 };
415 
416 // Given a variety of potential sizes for a structure, the correct one is
417 // selected.
TEST(NegativeTermsInSizes,AMinusBIsBiggest)418 TEST(NegativeTermsInSizes, AMinusBIsBiggest) {
419   auto view =
420       NegativeTermsInSizesView(kNegativeTermsInSizesAMinusBIsBiggest,
421                                sizeof kNegativeTermsInSizesAMinusBIsBiggest);
422   EXPECT_EQ(6U, view.SizeInBytes());
423   EXPECT_EQ(7U, view.a().Read());
424   EXPECT_EQ(1U, view.b().Read());
425   EXPECT_EQ(2U, view.c().Read());
426   EXPECT_EQ(0x33U, view.a_minus_b()[2].Read());
427 }
428 
429 static const ::std::uint8_t kNegativeTermsInSizesAMinusCIsBiggest[7] = {
430     0x07,  // 0:1  a
431     0x02,  // 1:2  b
432     0x01,  // 2:3  c
433     // 3:a-b   == 3:5  a_minus_b
434     // 3:a-2*b == 3:3  a_minus_2b
435     // 3:a-b-c == 3:4  a_minus_b_minus_c
436     // 3:10-a  == 3:3  ten_minus_a
437     // 3:a-2*c == 3:5  a_minus_2c
438     // 3:a-c   == 3:6  a_minus_c
439     0x11,
440     0x22,
441     0x33,
442     0x44,
443 };
444 
445 // Given a variety of potential sizes for a structure, the correct one is
446 // selected.
TEST(NegativeTermsInSizes,AMinusCIsBiggest)447 TEST(NegativeTermsInSizes, AMinusCIsBiggest) {
448   auto view =
449       NegativeTermsInSizesView(kNegativeTermsInSizesAMinusCIsBiggest,
450                                sizeof kNegativeTermsInSizesAMinusCIsBiggest);
451   EXPECT_EQ(6U, view.SizeInBytes());
452   EXPECT_EQ(7U, view.a().Read());
453   EXPECT_EQ(2U, view.b().Read());
454   EXPECT_EQ(1U, view.c().Read());
455   EXPECT_EQ(0x33U, view.a_minus_c()[2].Read());
456   EXPECT_TRUE(view.a_minus_b().IsComplete());
457   EXPECT_TRUE(view.a_minus_2b().IsComplete());
458 }
459 
460 static const ::std::uint8_t kNegativeTermsInSizesTenMinusAIsBiggest[7] = {
461     0x04,  // 0:1  a
462     0x00,  // 1:2  b
463     0x00,  // 2:3  c
464     // 3:a-b   == 3:4  a_minus_b
465     // 3:a-2*b == 3:4  a_minus_2b
466     // 3:a-b-c == 3:4  a_minus_b_minus_c
467     // 3:10-a  == 3:6  ten_minus_a
468     // 3:a-2*c == 3:4  a_minus_2c
469     // 3:a-c   == 3:4  a_minus_c
470     0x11,
471     0x22,
472     0x33,
473     0x44,
474 };
475 
476 // Given a variety of potential sizes for a structure, the correct one is
477 // selected.
TEST(NegativeTermsInSizes,TenMinusAIsBiggest)478 TEST(NegativeTermsInSizes, TenMinusAIsBiggest) {
479   auto view =
480       NegativeTermsInSizesView(kNegativeTermsInSizesTenMinusAIsBiggest,
481                                sizeof kNegativeTermsInSizesTenMinusAIsBiggest);
482   EXPECT_EQ(6U, view.SizeInBytes());
483   EXPECT_EQ(4U, view.a().Read());
484   EXPECT_EQ(0U, view.b().Read());
485   EXPECT_EQ(0U, view.c().Read());
486   EXPECT_EQ(0x33U, view.ten_minus_a()[2].Read());
487   EXPECT_TRUE(view.a_minus_b().IsComplete());
488   EXPECT_TRUE(view.a_minus_2b().IsComplete());
489 }
490 
491 static const ::std::uint8_t kNegativeTermsEndWouldBeNegative[10] = {
492     0x00,  // 0:1  a
493     0x02,  // 1:2  b
494     0x02,  // 2:3  c
495     // 3:a-b   == 3:-2  a_minus_b
496     // 3:a-2*b == 3:-4  a_minus_2b
497     // 3:a-b-c == 3:-4  a_minus_b_minus_c
498     // 3:10-a  == 3:10  ten_minus_a
499     // 3:a-2*c == 3:-4  a_minus_2c
500     // 3:a-c   == 3:-2  a_minus_c
501     0x11,
502     0x22,
503     0x33,
504     0x44,
505     0x55,
506     0x66,
507     0x77,
508 };
509 
510 // Given a variety of potential sizes for a structure, some of which would be
511 // negative, the correct one is selected.
TEST(NegativeTermsInSizes,NegativeEnd)512 TEST(NegativeTermsInSizes, NegativeEnd) {
513   auto view = NegativeTermsInSizesView(kNegativeTermsEndWouldBeNegative,
514                                        sizeof kNegativeTermsEndWouldBeNegative);
515   EXPECT_EQ(10U, view.SizeInBytes());
516   EXPECT_TRUE(view.SizeIsKnown());
517   EXPECT_EQ(0U, view.a().Read());
518   EXPECT_EQ(2U, view.b().Read());
519   EXPECT_EQ(2U, view.c().Read());
520   EXPECT_EQ(0x77U, view.ten_minus_a()[6].Read());
521   EXPECT_FALSE(view.a_minus_b().IsComplete());
522   EXPECT_FALSE(view.a_minus_2b().IsComplete());
523 }
524 
525 // If a field's offset is negative, the field is not Ok() and !IsComplete().
TEST(NegativeTermInLocation,NegativeLocation)526 TEST(NegativeTermInLocation, NegativeLocation) {
527   ::std::array<char, 256> bytes = {15};
528   auto view = MakeNegativeTermInLocationView(&bytes);
529   EXPECT_FALSE(view.Ok());
530   EXPECT_TRUE(view.a().Ok());
531   EXPECT_TRUE(view.IsComplete());
532   EXPECT_FALSE(view.b().IsComplete());
533   EXPECT_FALSE(view.b().Ok());
534 }
535 
536 static const ::std::uint8_t kChainedSizeInOrder[4] = {
537     0x01,  // 0:1  a
538     0x02,  // 1:2  b
539     0x03,  // 2:3  c
540     0x04,  // 3:4  d
541 };
542 
543 // Fields are readable, even through multiple levels of indirection.
TEST(ChainedSize,ChainedSizeInOrder)544 TEST(ChainedSize, ChainedSizeInOrder) {
545   auto view = ChainedSizeView(kChainedSizeInOrder, sizeof kChainedSizeInOrder);
546   ASSERT_TRUE(view.SizeIsKnown());
547   EXPECT_EQ(4U, view.SizeInBytes());
548   ASSERT_TRUE(view.a().IsComplete());
549   EXPECT_EQ(1U, view.a().Read());
550   ASSERT_TRUE(view.b().IsComplete());
551   EXPECT_EQ(2U, view.b().Read());
552   ASSERT_TRUE(view.c().IsComplete());
553   EXPECT_EQ(3U, view.c().Read());
554   ASSERT_TRUE(view.d().IsComplete());
555   EXPECT_EQ(4U, view.d().Read());
556 }
557 
558 static const ::std::uint8_t kChainedSizeNotInOrder[4] = {
559     0x03,  // 0:1  a
560     0x04,  // 1:2  d
561     0x01,  // 2:3  c
562     0x02,  // 3:4  b
563 };
564 
565 // Fields are readable, even through multiple levels of indirection, when their
566 // placement in the binary structure is not in the same order.
TEST(ChainedSize,ChainedSizeNotInOrder)567 TEST(ChainedSize, ChainedSizeNotInOrder) {
568   auto view =
569       ChainedSizeView(kChainedSizeNotInOrder, sizeof kChainedSizeNotInOrder);
570   ASSERT_TRUE(view.Ok());
571   ASSERT_TRUE(view.SizeIsKnown());
572   EXPECT_EQ(4U, view.SizeInBytes());
573   ASSERT_TRUE(view.a().IsComplete());
574   EXPECT_EQ(3U, view.a().Read());
575   ASSERT_TRUE(view.b().IsComplete());
576   EXPECT_EQ(2U, view.b().Read());
577   ASSERT_TRUE(view.c().IsComplete());
578   EXPECT_EQ(1U, view.c().Read());
579   ASSERT_TRUE(view.d().IsComplete());
580   EXPECT_EQ(4U, view.d().Read());
581 }
582 
583 // Fields are readable, even through multiple levels of indirection.
TEST(ChainedSize,Write)584 TEST(ChainedSize, Write) {
585   ::std::uint8_t buffer[4] = {0};
586   auto writer = ChainedSizeWriter(buffer, sizeof buffer);
587   writer.a().Write(1);
588   writer.b().Write(2);
589   writer.c().Write(3);
590   writer.d().Write(4);
591   EXPECT_EQ(::std::vector</**/ ::std::uint8_t>(
592                 kChainedSizeInOrder,
593                 kChainedSizeInOrder + sizeof kChainedSizeInOrder),
594             ::std::vector</**/ ::std::uint8_t>(buffer, buffer + sizeof buffer));
595   writer.a().Write(3);
596   writer.b().Write(2);
597   writer.c().Write(1);
598   writer.d().Write(4);
599   EXPECT_EQ(::std::vector</**/ ::std::uint8_t>(
600                 kChainedSizeNotInOrder,
601                 kChainedSizeNotInOrder + sizeof kChainedSizeNotInOrder),
602             ::std::vector</**/ ::std::uint8_t>(buffer, buffer + sizeof buffer));
603 }
604 
605 static const ::std::uint8_t kChainedSizeTooShortForD[3] = {
606     0x01,  // 0:1  a
607     0x02,  // 1:2  b
608     0x03,  // 2:3  c
609            // d is missing
610 };
611 
612 // When a structure is partial, fields whose locations are available are still
613 // readable, and the SizeInBytes method can be called as long as all of the
614 // fields required to calculate the size are readable, even if other fields are
615 // not.
TEST(ChainedSize,ChainedSizeTooShortForD)616 TEST(ChainedSize, ChainedSizeTooShortForD) {
617   auto view = ChainedSizeView(kChainedSizeTooShortForD,
618                               sizeof kChainedSizeTooShortForD);
619   ASSERT_FALSE(view.Ok());
620   ASSERT_TRUE(view.SizeIsKnown());
621   EXPECT_EQ(4U, view.SizeInBytes());
622   ASSERT_TRUE(view.a().IsComplete());
623   EXPECT_EQ(1U, view.a().Read());
624   ASSERT_TRUE(view.b().IsComplete());
625   EXPECT_EQ(2U, view.b().Read());
626   ASSERT_TRUE(view.c().IsComplete());
627   EXPECT_EQ(3U, view.c().Read());
628   ASSERT_FALSE(view.d().IsComplete());
629 }
630 
631 static const ::std::uint8_t kChainedSizeTooShortForC[2] = {
632     0x01,  // 0:1  a
633     0x02,  // 1:2  b
634            // c is missing
635            // d is missing
636 };
637 
638 // When not all fields required to compute SizeInBytes() can be read,
639 // SizeIsKnown() returns false.
TEST(ChainedSize,ChainedSizeTooShortForC)640 TEST(ChainedSize, ChainedSizeTooShortForC) {
641   auto view = ChainedSizeView(kChainedSizeTooShortForC,
642                               sizeof kChainedSizeTooShortForC);
643   ASSERT_FALSE(view.Ok());
644   EXPECT_FALSE(view.SizeIsKnown());
645   ASSERT_TRUE(view.a().IsComplete());
646   EXPECT_EQ(1U, view.a().Read());
647   ASSERT_TRUE(view.b().IsComplete());
648   EXPECT_EQ(2U, view.b().Read());
649   ASSERT_FALSE(view.c().IsComplete());
650   ASSERT_FALSE(view.d().IsComplete());
651 }
652 
653 // A structure with static size and two end-aligned fields compiles and returns
654 // the correct size.
TEST(FinalFieldOverlaps,FinalSizeIsCorrect)655 TEST(FinalFieldOverlaps, FinalSizeIsCorrect) {
656   ASSERT_EQ(5U, FinalFieldOverlapsView::SizeInBytes());
657 }
658 
659 static const ::std::uint8_t kDynamicFinalFieldOverlapsDynamicFieldIsLast[12] = {
660     0x0a,                                            // 0:1  a
661     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 1:9 padding
662     0x01,                                            // 9:10  b
663     0x02,  // 10:11 (a:a+1)  low byte of c
664     0x03,  // 11:12 (a+1:a+2)  d; high byte of c
665 };
666 
667 static const ::std::uint8_t kDynamicFinalFieldOverlapsStaticFieldIsLast[10] = {
668     0x07,                                // 0:1  a
669     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 1:7 padding
670     0x02,                                // 7:8 (a:a+1)  low byte of c
671     0x03,                                // 8:9 (a+1:a+2)  d; high byte of c
672     0x01,                                // 9:10  b
673 };
674 
675 // A structure with dynamic size and two end-aligned fields compiles and returns
676 // the correct size.
TEST(DynamicFinalFieldOverlaps,FinalSizeIsCorrect)677 TEST(DynamicFinalFieldOverlaps, FinalSizeIsCorrect) {
678   auto dynamic_last_view = DynamicFinalFieldOverlapsView(
679       kDynamicFinalFieldOverlapsDynamicFieldIsLast,
680       sizeof kDynamicFinalFieldOverlapsDynamicFieldIsLast);
681   ASSERT_EQ(12U, dynamic_last_view.SizeInBytes());
682   auto static_last_view = DynamicFinalFieldOverlapsView(
683       kDynamicFinalFieldOverlapsStaticFieldIsLast,
684       sizeof kDynamicFinalFieldOverlapsStaticFieldIsLast);
685   ASSERT_EQ(10U, static_last_view.SizeInBytes());
686 }
687 
TEST(DynamicFieldDependsOnLaterField,DynamicLocationIsNotKnown)688 TEST(DynamicFieldDependsOnLaterField, DynamicLocationIsNotKnown) {
689   ::std::uint8_t bytes[5] = {0x04, 0x03, 0x02, 0x01, 0x00};
690   auto view = MakeDynamicFieldDependsOnLaterFieldView(bytes, 4);
691   EXPECT_FALSE(view.b().Ok());
692   view = MakeDynamicFieldDependsOnLaterFieldView(bytes, 5);
693   EXPECT_TRUE(view.b().Ok());
694   EXPECT_EQ(3U, view.b().Read());
695 }
696 
TEST(DynamicFieldDoesNotAffectSize,DynamicFieldDoesNotAffectSize)697 TEST(DynamicFieldDoesNotAffectSize, DynamicFieldDoesNotAffectSize) {
698   EXPECT_EQ(256U, DynamicFieldDoesNotAffectSizeView::SizeInBytes());
699 }
700 
701 }  // namespace
702 }  // namespace test
703 }  // namespace emboss
704