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