1 /*
2 * Copyright (c) 2023, Alliance for Open Media. All rights reserved
3 *
4 * This source code is subject to the terms of the BSD 3-Clause Clear License
5 * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
6 * License was not distributed with this source code in the LICENSE file, you
7 * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
8 * Alliance for Open Media Patent License 1.0 was not distributed with this
9 * source code in the PATENTS file, you can obtain it at
10 * www.aomedia.org/license/patent.
11 */
12 #include "iamf/common/utils/numeric_utils.h"
13
14 #include <array>
15 #include <cmath>
16 #include <cstddef>
17 #include <cstdint>
18 #include <fstream>
19 #include <ios>
20 #include <limits>
21 #include <optional>
22 #include <vector>
23
24 #include "absl/functional/any_invocable.h"
25 #include "absl/status/status.h"
26 #include "absl/status/status_matchers.h"
27 #include "absl/strings/string_view.h"
28 #include "absl/types/span.h"
29 #include "gmock/gmock.h"
30 #include "gtest/gtest.h"
31 #include "iamf/cli/tests/cli_test_utils.h"
32 #include "iamf/common/write_bit_buffer.h"
33 #include "iamf/obu/types.h"
34
35 namespace iamf_tools {
36 namespace {
37
38 using ::absl_testing::IsOk;
39 using ::absl_testing::StatusIs;
40 using ::testing::ElementsAreArray;
41 using ::testing::HasSubstr;
42
43 constexpr absl::string_view kOmitContext = "";
44 constexpr absl::string_view kCustomUserContext = "Custom User Context";
45
TEST(AddUint32CheckOverflow,SmallInput)46 TEST(AddUint32CheckOverflow, SmallInput) {
47 uint32_t result;
48 EXPECT_THAT(AddUint32CheckOverflow(1, 1, result), IsOk());
49 EXPECT_EQ(result, 2);
50 }
51
TEST(AddUint32CheckOverflow,MaxOutput)52 TEST(AddUint32CheckOverflow, MaxOutput) {
53 uint32_t result;
54 EXPECT_THAT(AddUint32CheckOverflow(
55 1, std::numeric_limits<uint32_t>::max() - 1, result),
56 IsOk());
57 EXPECT_EQ(result, std::numeric_limits<uint32_t>::max());
58 }
59
TEST(AddUint32CheckOverflow,Overflow)60 TEST(AddUint32CheckOverflow, Overflow) {
61 uint32_t result;
62 EXPECT_EQ(
63 AddUint32CheckOverflow(1, std::numeric_limits<uint32_t>::max(), result)
64 .code(),
65 absl::StatusCode::kInvalidArgument);
66 }
67
68 struct FloatToQ78FormatTestCase {
69 float test_val;
70 int16_t expected_val;
71 absl::StatusCode expected_status_code;
72 };
73
74 using FloatToQ78Format = ::testing::TestWithParam<FloatToQ78FormatTestCase>;
75
TEST_P(FloatToQ78Format,TestQ78Format)76 TEST_P(FloatToQ78Format, TestQ78Format) {
77 const FloatToQ78FormatTestCase& test_case = GetParam();
78
79 int16_t q7_8_value;
80 EXPECT_EQ(FloatToQ7_8(test_case.test_val, q7_8_value).code(),
81 test_case.expected_status_code);
82 if (test_case.expected_status_code == absl::StatusCode::kOk) {
83 EXPECT_EQ(q7_8_value, test_case.expected_val);
84 }
85 }
86
87 INSTANTIATE_TEST_SUITE_P(Positive, FloatToQ78Format,
88 testing::ValuesIn<FloatToQ78FormatTestCase>({
89 {0, 0, absl::StatusCode::kOk},
90 {0.00390625, 1, absl::StatusCode::kOk},
91 {0.390625, 100, absl::StatusCode::kOk},
92 {0.99609375, 255, absl::StatusCode::kOk},
93 {1, 256, absl::StatusCode::kOk},
94 {2, 512, absl::StatusCode::kOk},
95 {100, 25600, absl::StatusCode::kOk},
96 {127, 32512, absl::StatusCode::kOk},
97 {127.99609375, 32767, absl::StatusCode::kOk},
98 }));
99
100 INSTANTIATE_TEST_SUITE_P(FlooredRounding, FloatToQ78Format,
101 testing::ValuesIn<FloatToQ78FormatTestCase>({
102 {.00390624, 0, absl::StatusCode::kOk},
103 {.00390626, 1, absl::StatusCode::kOk},
104 }));
105
106 INSTANTIATE_TEST_SUITE_P(Negative, FloatToQ78Format,
107 testing::ValuesIn<FloatToQ78FormatTestCase>({
108 {-0.00390625, -1, absl::StatusCode::kOk},
109 {-1.0, -256, absl::StatusCode::kOk},
110 {-1.00390625, -257, absl::StatusCode::kOk},
111 {-4.0, -1024, absl::StatusCode::kOk},
112 {-16.0, -4096, absl::StatusCode::kOk},
113 {-64.0, -16384, absl::StatusCode::kOk},
114 {-127.99609375, -32767, absl::StatusCode::kOk},
115 }));
116
117 INSTANTIATE_TEST_SUITE_P(Max, FloatToQ78Format,
118 testing::ValuesIn<FloatToQ78FormatTestCase>({
119 {127.99609375, 32767, absl::StatusCode::kOk},
120 }));
121
122 INSTANTIATE_TEST_SUITE_P(Min, FloatToQ78Format,
123 testing::ValuesIn<FloatToQ78FormatTestCase>({
124 {-128.0, -32768, absl::StatusCode::kOk},
125 }));
126
127 INSTANTIATE_TEST_SUITE_P(Invalid, FloatToQ78Format,
128 testing::ValuesIn<FloatToQ78FormatTestCase>({
129 {128.0, 0, absl::StatusCode::kUnknown},
130 {-128.00390625, 0, absl::StatusCode::kUnknown},
131 {nanf(""), 0, absl::StatusCode::kUnknown},
132 }));
133
134 struct Q78ToFloatFormatTestCase {
135 int16_t test_val;
136 float expected_val;
137 };
138
139 using Q78ToFloatFormat = ::testing::TestWithParam<Q78ToFloatFormatTestCase>;
140
TEST_P(Q78ToFloatFormat,TestQ78Format)141 TEST_P(Q78ToFloatFormat, TestQ78Format) {
142 const Q78ToFloatFormatTestCase& test_case = GetParam();
143 EXPECT_EQ(Q7_8ToFloat(test_case.test_val), test_case.expected_val);
144 }
145
146 INSTANTIATE_TEST_SUITE_P(Positive, Q78ToFloatFormat,
147 testing::ValuesIn<Q78ToFloatFormatTestCase>({
148 {0, 0},
149 {1, 0.00390625},
150 {100, 0.390625},
151 {255, 0.99609375},
152 {256, 1},
153 {512, 2},
154 {25600, 100},
155 {32512, 127},
156 {32767, 127.99609375},
157 }));
158
159 INSTANTIATE_TEST_SUITE_P(Negative, Q78ToFloatFormat,
160 testing::ValuesIn<Q78ToFloatFormatTestCase>({
161 {-1, -0.00390625},
162 {-256, -1.0},
163 {-257, -1.00390625},
164 {-1024, -4.0},
165 {-4096, -16.0},
166 {-16384, -64.0},
167 {-32767, -127.99609375},
168 }));
169
170 INSTANTIATE_TEST_SUITE_P(Max, Q78ToFloatFormat,
171 testing::ValuesIn<Q78ToFloatFormatTestCase>({
172 {32767, 127.99609375},
173 }));
174
175 INSTANTIATE_TEST_SUITE_P(Min, Q78ToFloatFormat,
176 testing::ValuesIn<Q78ToFloatFormatTestCase>({
177 {-32768, -128.0},
178 }));
179
180 struct FloatToQ08FormatTestCase {
181 float test_val;
182 uint8_t expected_val;
183 absl::StatusCode expected_status_code;
184 };
185
186 using FloatToQ08Format = ::testing::TestWithParam<FloatToQ08FormatTestCase>;
187
TEST_P(FloatToQ08Format,TestQ08Format)188 TEST_P(FloatToQ08Format, TestQ08Format) {
189 const FloatToQ08FormatTestCase& test_case = GetParam();
190
191 uint8_t q0_8_value;
192 EXPECT_EQ(FloatToQ0_8(test_case.test_val, q0_8_value).code(),
193 test_case.expected_status_code);
194 if (test_case.expected_status_code == absl::StatusCode::kOk) {
195 EXPECT_EQ(q0_8_value, test_case.expected_val);
196 }
197 }
198
199 INSTANTIATE_TEST_SUITE_P(Basic, FloatToQ08Format,
200 testing::ValuesIn<FloatToQ08FormatTestCase>({
201 {0.00390625, 1, absl::StatusCode::kOk},
202 {0.390625, 100, absl::StatusCode::kOk},
203 }));
204
205 INSTANTIATE_TEST_SUITE_P(FlooredRounding, FloatToQ08Format,
206 testing::ValuesIn<FloatToQ08FormatTestCase>({
207 {.00390624, 0, absl::StatusCode::kOk},
208 {.00390626, 1, absl::StatusCode::kOk},
209 }));
210
211 INSTANTIATE_TEST_SUITE_P(Max, FloatToQ08Format,
212 testing::ValuesIn<FloatToQ08FormatTestCase>({
213 {0.99609375, 255, absl::StatusCode::kOk},
214 }));
215
216 INSTANTIATE_TEST_SUITE_P(Min, FloatToQ08Format,
217 testing::ValuesIn<FloatToQ08FormatTestCase>({
218 {0, 0, absl::StatusCode::kOk},
219 }));
220
221 INSTANTIATE_TEST_SUITE_P(Invalid, FloatToQ08Format,
222 testing::ValuesIn<FloatToQ08FormatTestCase>({
223 {-0.00390625, 0, absl::StatusCode::kUnknown},
224 {1, 0, absl::StatusCode::kUnknown},
225 {std::nanf(""), 0, absl::StatusCode::kUnknown},
226 }));
227
228 struct Q08ToFloatFormatTestCase {
229 uint8_t test_val;
230 float expected_val;
231 };
232
233 using Q08ToFloatFormat = ::testing::TestWithParam<Q08ToFloatFormatTestCase>;
234
TEST_P(Q08ToFloatFormat,TestQ78Format)235 TEST_P(Q08ToFloatFormat, TestQ78Format) {
236 const Q08ToFloatFormatTestCase& test_case = GetParam();
237 EXPECT_EQ(Q0_8ToFloat(test_case.test_val), test_case.expected_val);
238 }
239
240 INSTANTIATE_TEST_SUITE_P(Basic, Q08ToFloatFormat,
241 testing::ValuesIn<Q08ToFloatFormatTestCase>({
242 {0, 0},
243 {1, 0.00390625},
244 {100, 0.390625},
245 {255, 0.99609375},
246 }));
247
248 struct Int32ToNormalizedFloatingPointSymmetryTestCase {
249 int32_t test_val;
250 int32_t symmetric_val;
251 };
252
253 using Int32ToNormalizedFloatingPointSymmetry =
254 ::testing::TestWithParam<Int32ToNormalizedFloatingPointSymmetryTestCase>;
255
TEST_P(Int32ToNormalizedFloatingPointSymmetry,Int32ToNormalizedFloatSymmetry)256 TEST_P(Int32ToNormalizedFloatingPointSymmetry, Int32ToNormalizedFloatSymmetry) {
257 // `std::numeric_limits<int32_t>::min()` has no symmetric pair.
258 ASSERT_NE(GetParam().test_val, std::numeric_limits<int32_t>::min());
259
260 // All other values are symmetric with their negative.
261 ASSERT_EQ(GetParam().symmetric_val, -GetParam().test_val);
262
263 EXPECT_EQ(Int32ToNormalizedFloatingPoint<float>(GetParam().test_val),
264 -Int32ToNormalizedFloatingPoint<float>(GetParam().symmetric_val));
265
266 EXPECT_EQ(Int32ToNormalizedFloatingPoint<double>(GetParam().test_val),
267 -Int32ToNormalizedFloatingPoint<double>(GetParam().symmetric_val));
268
269 EXPECT_EQ(
270 Int32ToNormalizedFloatingPoint<InternalSampleType>(GetParam().test_val),
271 -Int32ToNormalizedFloatingPoint<InternalSampleType>(
272 GetParam().symmetric_val));
273 }
274
275 INSTANTIATE_TEST_SUITE_P(
276 OneAndNegativeOne, Int32ToNormalizedFloatingPointSymmetry,
277 testing::ValuesIn<Int32ToNormalizedFloatingPointSymmetryTestCase>({{1,
278 -1}}));
279
280 // There is one more negative than positive `int32_t`.
281 INSTANTIATE_TEST_SUITE_P(
282 MaxAndMinPlusOne, Int32ToNormalizedFloatingPointSymmetry,
283 testing::ValuesIn<Int32ToNormalizedFloatingPointSymmetryTestCase>(
284 {{std::numeric_limits<int32_t>::max(),
285 std::numeric_limits<int32_t>::min() + 1}}));
286
287 INSTANTIATE_TEST_SUITE_P(
288 ArbitraryXAndNegativeX, Int32ToNormalizedFloatingPointSymmetry,
289 testing::ValuesIn<Int32ToNormalizedFloatingPointSymmetryTestCase>({
290 {5, -5},
291 {99, -99},
292 {9999, -9999},
293 {999999, -999999},
294 {77777777, -77777777},
295 }));
296
297 INSTANTIATE_TEST_SUITE_P(
298 NegativePowersOfTwoAndPositivePowersOfTwo,
299 Int32ToNormalizedFloatingPointSymmetry,
300 testing::ValuesIn<Int32ToNormalizedFloatingPointSymmetryTestCase>({
301 {-4, 4},
302 {-64, 64},
303 {-128, 128},
304 {-1024, 1024},
305 {-67108864, 67108864},
306 {-1073741824, 1073741824},
307 }));
308
309 struct Int32ToNormalizedFloatingPointTestCase {
310 int32_t input_val;
311 float expected_val_as_float;
312 double expected_val_as_double;
313 };
314
315 using Int32ToNormalizedFloatingPointTest =
316 ::testing::TestWithParam<Int32ToNormalizedFloatingPointTestCase>;
317
TEST_P(Int32ToNormalizedFloatingPointTest,Int32ToNormalizedFloat)318 TEST_P(Int32ToNormalizedFloatingPointTest, Int32ToNormalizedFloat) {
319 EXPECT_FLOAT_EQ(Int32ToNormalizedFloatingPoint<float>(GetParam().input_val),
320 GetParam().expected_val_as_float);
321
322 EXPECT_NEAR(Int32ToNormalizedFloatingPoint<double>(GetParam().input_val),
323 GetParam().expected_val_as_double, .0000001);
324 }
325
326 INSTANTIATE_TEST_SUITE_P(
327 MaxGetsSquishedToOne, Int32ToNormalizedFloatingPointTest,
328 testing::ValuesIn<Int32ToNormalizedFloatingPointTestCase>(
329 {{std::numeric_limits<int32_t>::max(), 1.0f, 1.0}}));
330
331 INSTANTIATE_TEST_SUITE_P(
332 Zero, Int32ToNormalizedFloatingPointTest,
333 testing::ValuesIn<Int32ToNormalizedFloatingPointTestCase>({{0, 0.0f,
334 0.0}}));
335
336 INSTANTIATE_TEST_SUITE_P(
337 PositivePowersOf2, Int32ToNormalizedFloatingPointTest,
338 testing::ValuesIn<Int32ToNormalizedFloatingPointTestCase>({
339 {1 << 30, std::pow(2.0f, -1.0f), std::pow(2.0, -1.0)},
340 {1 << 29, std::pow(2.0f, -2.0f), std::pow(2.0, -2.0)},
341 {1 << 27, std::pow(2.0f, -4.0f), std::pow(2.0, -4.0)},
342 {1 << 23, std::pow(2.0f, -8.0f), std::pow(2.0, -8.0)},
343 {1 << 15, std::pow(2.0f, -16.0f), std::pow(2.0, -16.0)},
344 {1 << 6, std::pow(2.0f, -25.0f), std::pow(2.0, -25.0)},
345 {1 << 1, std::pow(2.0f, -30.0f), std::pow(2.0, -30.0)},
346 {1 << 0, std::pow(2.0f, -31.0f), std::pow(2.0, -31.0)},
347 }));
348
349 INSTANTIATE_TEST_SUITE_P(
350 MinMinusOneGetsSquishedToNegativeOne, Int32ToNormalizedFloatingPointTest,
351 testing::ValuesIn<Int32ToNormalizedFloatingPointTestCase>(
352 {{std::numeric_limits<int32_t>::min() + 1, -1.0f, -1.0}}));
353
354 INSTANTIATE_TEST_SUITE_P(
355 Min, Int32ToNormalizedFloatingPointTest,
356 testing::ValuesIn<Int32ToNormalizedFloatingPointTestCase>(
357 {{std::numeric_limits<int32_t>::min(), -1.0f, -1.0}}));
358
359 struct NormalizedFloatingPointToInt32SymmetryTestCase {
360 float test_val;
361 float symmetric_val;
362 };
363
364 using NormalizedFloatingPointToInt32SymmetryTest =
365 ::testing::TestWithParam<NormalizedFloatingPointToInt32SymmetryTestCase>;
366
TEST_P(NormalizedFloatingPointToInt32SymmetryTest,NormalizedFloatingPointToInt32SymmetryTest)367 TEST_P(NormalizedFloatingPointToInt32SymmetryTest,
368 NormalizedFloatingPointToInt32SymmetryTest) {
369 // +1.0 may have an irregular symmetric pair.
370 ASSERT_NE(GetParam().test_val, -1.0f);
371
372 // Most regular values are symmetric with their negative.
373 ASSERT_EQ(GetParam().symmetric_val, -GetParam().test_val);
374
375 int32_t test_val_result;
376 EXPECT_THAT(
377 NormalizedFloatingPointToInt32(GetParam().test_val, test_val_result),
378 IsOk());
379 int32_t symmetric_val_result;
380 EXPECT_THAT(NormalizedFloatingPointToInt32(GetParam().symmetric_val,
381 symmetric_val_result),
382 IsOk());
383 EXPECT_EQ(test_val_result, -symmetric_val_result);
384 }
385
386 INSTANTIATE_TEST_SUITE_P(
387 PositivePowersOfTwoAndNegativePowersOfTwo,
388 NormalizedFloatingPointToInt32SymmetryTest,
389 testing::ValuesIn<NormalizedFloatingPointToInt32SymmetryTestCase>({
390 {std::pow(2.0f, -1.0f), -std::pow(2.0f, -1.0f)},
391 {std::pow(2.0f, -2.0f), -std::pow(2.0f, -2.0f)},
392 {std::pow(2.0f, -4.0f), -std::pow(2.0f, -4.0f)},
393 {std::pow(2.0f, -8.0f), -std::pow(2.0f, -8.0f)},
394 {std::pow(2.0f, -16.0f), -std::pow(2.0f, -16.0f)},
395 }));
396
397 INSTANTIATE_TEST_SUITE_P(
398 Arbitrary, NormalizedFloatingPointToInt32SymmetryTest,
399 testing::ValuesIn<NormalizedFloatingPointToInt32SymmetryTestCase>({
400 {0.01f, -0.01f},
401 {0.12f, -0.12f},
402 {0.34f, -0.34f},
403 {0.99f, -0.99f},
404 }));
405
406 struct NormalizedFloatingPointToInt32TestCase {
407 float test_val;
408 int32_t expected_val;
409 };
410
411 using NormalizedFloatingPointToInt32Test =
412 ::testing::TestWithParam<NormalizedFloatingPointToInt32TestCase>;
413
TEST_P(NormalizedFloatingPointToInt32Test,NormalizedFloatingPointToInt32Test)414 TEST_P(NormalizedFloatingPointToInt32Test, NormalizedFloatingPointToInt32Test) {
415 int32_t result;
416 EXPECT_THAT(NormalizedFloatingPointToInt32(GetParam().test_val, result),
417 IsOk());
418 EXPECT_EQ(result, GetParam().expected_val);
419 }
420
421 INSTANTIATE_TEST_SUITE_P(
422 One, NormalizedFloatingPointToInt32Test,
423 testing::ValuesIn<NormalizedFloatingPointToInt32TestCase>(
424 {{1.0, std::numeric_limits<int32_t>::max()}}));
425
426 INSTANTIATE_TEST_SUITE_P(
427 NegativeOne, NormalizedFloatingPointToInt32Test,
428 testing::ValuesIn<NormalizedFloatingPointToInt32TestCase>(
429 {{-1.0, std::numeric_limits<int32_t>::min()}}));
430
431 INSTANTIATE_TEST_SUITE_P(
432 ClipsOverMax, NormalizedFloatingPointToInt32Test,
433 testing::ValuesIn<NormalizedFloatingPointToInt32TestCase>(
434 {{2.0, std::numeric_limits<int32_t>::max()}}));
435
436 INSTANTIATE_TEST_SUITE_P(
437 ClipsUnderMin, NormalizedFloatingPointToInt32Test,
438 testing::ValuesIn<NormalizedFloatingPointToInt32TestCase>(
439 {{-2.0, std::numeric_limits<int32_t>::min()}}));
440
441 INSTANTIATE_TEST_SUITE_P(
442 PositivePowersOf2, NormalizedFloatingPointToInt32Test,
443 testing::ValuesIn<NormalizedFloatingPointToInt32TestCase>(
444 {{std::pow(2.0f, -1.0f), 1 << 30},
445 {std::pow(2.0f, -2.0f), 1 << 29},
446 {std::pow(2.0f, -4.0f), 1 << 27},
447 {std::pow(2.0f, -8.0f), 1 << 23},
448 {std::pow(2.0f, -16.0f), 1 << 15},
449 {std::pow(2.0f, -25.0f), 1 << 6},
450 {std::pow(2.0f, -30.0f), 1 << 1},
451 {std::pow(2.0f, -31.0f), 1 << 0}}));
452
TEST(NormalizedFloatingPointToInt32MalformedOutput,InvalidFloatNan)453 TEST(NormalizedFloatingPointToInt32MalformedOutput, InvalidFloatNan) {
454 int32_t undefined_result;
455 EXPECT_FALSE(
456 NormalizedFloatingPointToInt32(std::nanf(""), undefined_result).ok());
457 }
458
TEST(NormalizedFloatingPointToInt32MalformedInfoput,InvalidDoubleNan)459 TEST(NormalizedFloatingPointToInt32MalformedInfoput, InvalidDoubleNan) {
460 int32_t undefined_result;
461 EXPECT_FALSE(
462 NormalizedFloatingPointToInt32(std::nan(""), undefined_result).ok());
463 }
464
TEST(NormalizedFloatingPointToInt32MalformedOutput,InvalidFloatInfinity)465 TEST(NormalizedFloatingPointToInt32MalformedOutput, InvalidFloatInfinity) {
466 int32_t undefined_result;
467 EXPECT_FALSE(NormalizedFloatingPointToInt32(
468 std::numeric_limits<float>::infinity(), undefined_result)
469 .ok());
470 }
471
TEST(NormalizedFloatingPointToInt32MalformedOutput,InvalidDoubleInfinity)472 TEST(NormalizedFloatingPointToInt32MalformedOutput, InvalidDoubleInfinity) {
473 int32_t undefined_result;
474 EXPECT_FALSE(NormalizedFloatingPointToInt32(
475 std::numeric_limits<double>::infinity(), undefined_result)
476 .ok());
477 }
478
TEST(StaticCastIfInRange,SucceedsIfStaticCastSucceeds)479 TEST(StaticCastIfInRange, SucceedsIfStaticCastSucceeds) {
480 constexpr int8_t input = 1;
481 int output;
482
483 EXPECT_THAT((StaticCastIfInRange<int8_t, int>(kOmitContext, input, output)),
484 IsOk());
485 EXPECT_EQ(output, input);
486 }
487
TEST(StaticCastIfInRange,FailsIfStaticCastWouldFail)488 TEST(StaticCastIfInRange, FailsIfStaticCastWouldFail) {
489 constexpr int input = std::numeric_limits<int8_t>::max() + 1;
490 int8_t output;
491
492 EXPECT_FALSE(
493 (StaticCastIfInRange<int, int8_t>(kOmitContext, input, output)).ok());
494 }
495
TEST(StaticCastIfInRange,MessageContainsContextOnError)496 TEST(StaticCastIfInRange, MessageContainsContextOnError) {
497 constexpr int input = std::numeric_limits<int8_t>::max() + 1;
498 int8_t output;
499
500 EXPECT_THAT(
501 (StaticCastIfInRange<int, int8_t>(kCustomUserContext, input, output))
502 .message(),
503 HasSubstr(kCustomUserContext));
504 }
505
506 struct StaticCastIfInRangeUint32ToUint8TestCase {
507 uint32_t test_val;
508 uint8_t expected_val;
509 absl::StatusCode expected_status_code;
510 };
511
512 using StaticCastIfInRangeUint32ToUint8Test =
513 ::testing::TestWithParam<StaticCastIfInRangeUint32ToUint8TestCase>;
514
TEST_P(StaticCastIfInRangeUint32ToUint8Test,TestUint32ToUint8)515 TEST_P(StaticCastIfInRangeUint32ToUint8Test, TestUint32ToUint8) {
516 const StaticCastIfInRangeUint32ToUint8TestCase& test_case = GetParam();
517
518 uint8_t result;
519 EXPECT_EQ((StaticCastIfInRange<uint32_t, uint8_t>(kOmitContext,
520 test_case.test_val, result)
521 .code()),
522 test_case.expected_status_code);
523 if (test_case.expected_status_code == absl::StatusCode::kOk) {
524 EXPECT_EQ(result, test_case.expected_val);
525 }
526 }
527
528 INSTANTIATE_TEST_SUITE_P(
529 Valid, StaticCastIfInRangeUint32ToUint8Test,
530 testing::ValuesIn<StaticCastIfInRangeUint32ToUint8TestCase>({
531 {0, 0, absl::StatusCode::kOk},
532 {255, 255, absl::StatusCode::kOk},
533 }));
534
535 INSTANTIATE_TEST_SUITE_P(
536 Invalid, StaticCastIfInRangeUint32ToUint8Test,
537 testing::ValuesIn<StaticCastIfInRangeUint32ToUint8TestCase>({
538 {256, 0, absl::StatusCode::kInvalidArgument},
539 {UINT32_MAX, 0, absl::StatusCode::kInvalidArgument},
540 }));
541
542 struct StaticCastIfInRangeUint32ToUint16TestCase {
543 uint32_t test_val;
544 uint16_t expected_val;
545 absl::StatusCode expected_status_code;
546 };
547
548 using StaticCastIfInRangeUint32ToUint16Test =
549 ::testing::TestWithParam<StaticCastIfInRangeUint32ToUint16TestCase>;
550
TEST_P(StaticCastIfInRangeUint32ToUint16Test,TestUint32ToUint16)551 TEST_P(StaticCastIfInRangeUint32ToUint16Test, TestUint32ToUint16) {
552 const StaticCastIfInRangeUint32ToUint16TestCase& test_case = GetParam();
553
554 uint16_t result;
555 EXPECT_EQ((StaticCastIfInRange<uint32_t, uint16_t>(kOmitContext,
556 test_case.test_val, result)
557 .code()),
558 test_case.expected_status_code);
559 if (test_case.expected_status_code == absl::StatusCode::kOk) {
560 EXPECT_EQ(result, test_case.expected_val);
561 }
562 }
563
564 INSTANTIATE_TEST_SUITE_P(
565 Valid, StaticCastIfInRangeUint32ToUint16Test,
566 testing::ValuesIn<StaticCastIfInRangeUint32ToUint16TestCase>({
567 {0, 0, absl::StatusCode::kOk},
568 {65535, 65535, absl::StatusCode::kOk},
569 }));
570
571 INSTANTIATE_TEST_SUITE_P(
572 Invalid, StaticCastIfInRangeUint32ToUint16Test,
573 testing::ValuesIn<StaticCastIfInRangeUint32ToUint16TestCase>({
574 {65536, 0, absl::StatusCode::kInvalidArgument},
575 {UINT32_MAX, 0, absl::StatusCode::kInvalidArgument},
576 }));
577
578 struct StaticCastIfInRangeInt32ToInt16TestCase {
579 int32_t test_val;
580 int16_t expected_val;
581 absl::StatusCode expected_status_code;
582 };
583
584 using StaticCastIfInRangeInt32ToInt16Test =
585 ::testing::TestWithParam<StaticCastIfInRangeInt32ToInt16TestCase>;
586
TEST_P(StaticCastIfInRangeInt32ToInt16Test,TestInt32ToInt16)587 TEST_P(StaticCastIfInRangeInt32ToInt16Test, TestInt32ToInt16) {
588 const StaticCastIfInRangeInt32ToInt16TestCase& test_case = GetParam();
589
590 int16_t result;
591 EXPECT_EQ((StaticCastIfInRange<int32_t, int16_t>(kOmitContext,
592 test_case.test_val, result)
593 .code()),
594 test_case.expected_status_code);
595 if (test_case.expected_status_code == absl::StatusCode::kOk) {
596 EXPECT_EQ(result, test_case.expected_val);
597 }
598 }
599
600 INSTANTIATE_TEST_SUITE_P(
601 Valid, StaticCastIfInRangeInt32ToInt16Test,
602 testing::ValuesIn<StaticCastIfInRangeInt32ToInt16TestCase>({
603 {-32768, -32768, absl::StatusCode::kOk},
604 {-1, -1, absl::StatusCode::kOk},
605 {0, 0, absl::StatusCode::kOk},
606 {32767, 32767, absl::StatusCode::kOk},
607 }));
608
609 INSTANTIATE_TEST_SUITE_P(
610 Invalid, StaticCastIfInRangeInt32ToInt16Test,
611 testing::ValuesIn<StaticCastIfInRangeInt32ToInt16TestCase>({
612 {INT32_MIN, 0, absl::StatusCode::kInvalidArgument},
613 {-32769, 0, absl::StatusCode::kInvalidArgument},
614 {32768, 0, absl::StatusCode::kInvalidArgument},
615 {INT32_MAX, 0, absl::StatusCode::kInvalidArgument},
616 }));
617
TEST(LittleEndianBytesToInt32Test,InvalidTooManyBytes)618 TEST(LittleEndianBytesToInt32Test, InvalidTooManyBytes) {
619 int32_t unused_result = 0;
620 absl::Status status =
621 LittleEndianBytesToInt32({1, 2, 3, 4, 5}, unused_result);
622
623 EXPECT_FALSE(status.ok());
624 EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
625 }
626
TEST(LittleEndianBytesToInt32Test,InvalidTooFewBytes)627 TEST(LittleEndianBytesToInt32Test, InvalidTooFewBytes) {
628 int32_t result = 0;
629 absl::Status status = LittleEndianBytesToInt32({}, result);
630
631 EXPECT_FALSE(status.ok());
632 EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
633 }
634
635 struct LittleEndianBytesToInt32TestCase {
636 std::vector<uint8_t> test_val;
637 int32_t expected_val;
638 };
639
640 using LittleEndianBytesToInt32Format =
641 ::testing::TestWithParam<LittleEndianBytesToInt32TestCase>;
642
TEST_P(LittleEndianBytesToInt32Format,TestLittleEndianBytesToInt32)643 TEST_P(LittleEndianBytesToInt32Format, TestLittleEndianBytesToInt32) {
644 const LittleEndianBytesToInt32TestCase& test_case = GetParam();
645
646 int32_t result;
647 EXPECT_THAT(LittleEndianBytesToInt32(test_case.test_val, result), IsOk());
648 EXPECT_EQ(result, test_case.expected_val);
649 }
650
651 INSTANTIATE_TEST_SUITE_P(OneByte, LittleEndianBytesToInt32Format,
652 ::testing::ValuesIn<LittleEndianBytesToInt32TestCase>({
653 {{0b00000000}, 0},
654 {{0x7f}, 0x7f000000},
655 {{0xff}, static_cast<int32_t>(0xff000000)},
656 {{0x80}, static_cast<int32_t>(0x80000000)},
657 }));
658
659 INSTANTIATE_TEST_SUITE_P(TwoBytes, LittleEndianBytesToInt32Format,
660 ::testing::ValuesIn<LittleEndianBytesToInt32TestCase>({
661 {{0x00, 0x00}, 0},
662 {{0x01, 0x02}, 0x02010000},
663 {{0xff, 0x7f}, static_cast<int32_t>(0x7fff0000)},
664 {{0xff, 0xff}, static_cast<int32_t>(0xffff0000)},
665 {{0x00, 0x80}, static_cast<int32_t>(0x80000000)},
666 }));
667
668 INSTANTIATE_TEST_SUITE_P(
669 ThreeBytes, LittleEndianBytesToInt32Format,
670 ::testing::ValuesIn<LittleEndianBytesToInt32TestCase>({
671 {{0x00, 0x00, 0x00}, 0},
672 {{0x01, 0x02, 0x03}, 0x03020100},
673 {{0xff, 0xff, 0x7f}, static_cast<int32_t>(0x7fffff00)},
674 {{0xff, 0xff, 0xff}, static_cast<int32_t>(0xffffff00)},
675 {{0x00, 0x00, 0x80}, static_cast<int32_t>(0x80000000)},
676 }));
677
678 INSTANTIATE_TEST_SUITE_P(
679 FourBytes, LittleEndianBytesToInt32Format,
680 ::testing::ValuesIn<LittleEndianBytesToInt32TestCase>({
681 {{0x00, 0x00, 0x00, 0x00}, 0},
682 {{0x01, 0x02, 0x03, 0x04}, 0x04030201},
683 {{0xff, 0xff, 0xff, 0x7f}, static_cast<int32_t>(0x7fffffff)},
684 {{0xff, 0xff, 0xff, 0xff}, static_cast<int32_t>(0xffffffff)},
685 {{0x00, 0x00, 0x00, 0x80}, static_cast<int32_t>(0x80000000)},
686 }));
687
TEST(BigEndianBytesToInt32Test,InvalidTooManyBytes)688 TEST(BigEndianBytesToInt32Test, InvalidTooManyBytes) {
689 int32_t unused_result = 0;
690 absl::Status status = BigEndianBytesToInt32({1, 2, 3, 4, 5}, unused_result);
691
692 EXPECT_FALSE(status.ok());
693 EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
694 }
695
TEST(BigEndianBytesToInt32Test,InvalidTooFewBytes)696 TEST(BigEndianBytesToInt32Test, InvalidTooFewBytes) {
697 int32_t result = 0;
698 absl::Status status = BigEndianBytesToInt32({}, result);
699
700 EXPECT_FALSE(status.ok());
701 EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
702 }
703
704 struct BigEndianBytesToInt32TestCase {
705 std::vector<uint8_t> test_val;
706 int32_t expected_val;
707 };
708
709 using BigEndianBytesToInt32Format =
710 ::testing::TestWithParam<BigEndianBytesToInt32TestCase>;
711
TEST_P(BigEndianBytesToInt32Format,TestBigEndianBytesToInt32)712 TEST_P(BigEndianBytesToInt32Format, TestBigEndianBytesToInt32) {
713 const BigEndianBytesToInt32TestCase& test_case = GetParam();
714
715 int32_t result;
716 EXPECT_THAT(BigEndianBytesToInt32(test_case.test_val, result), IsOk());
717 EXPECT_EQ(result, test_case.expected_val);
718 }
719
720 INSTANTIATE_TEST_SUITE_P(OneByte, BigEndianBytesToInt32Format,
721 ::testing::ValuesIn<BigEndianBytesToInt32TestCase>({
722 {{0b00000000}, 0},
723 {{0x7f}, 0x7f000000},
724 {{0xff}, static_cast<int32_t>(0xff000000)},
725 {{0x80}, static_cast<int32_t>(0x80000000)},
726 }));
727
728 INSTANTIATE_TEST_SUITE_P(TwoBytes, BigEndianBytesToInt32Format,
729 ::testing::ValuesIn<BigEndianBytesToInt32TestCase>({
730 {{0x00, 0x00}, 0},
731 {{0x02, 0x01}, 0x02010000},
732 {{0x7f, 0xff}, 0x7fff0000},
733 {{0xff, 0xff}, static_cast<int32_t>(0xffff0000)},
734 {{0x80, 0x00}, static_cast<int32_t>(0x80000000)},
735 }));
736
737 INSTANTIATE_TEST_SUITE_P(
738 ThreeBytes, BigEndianBytesToInt32Format,
739 ::testing::ValuesIn<BigEndianBytesToInt32TestCase>({
740 {{0x00, 0x00, 0x00}, 0},
741 {{0x03, 0x02, 0x01}, 0x03020100},
742 {{0x7f, 0xff, 0xff}, 0x7fffff00},
743 {{0xff, 0xff, 0xff}, static_cast<int32_t>(0xffffff00)},
744 {{0x80, 0x00, 0x00}, static_cast<int32_t>(0x80000000)},
745 }));
746
747 INSTANTIATE_TEST_SUITE_P(
748 FourBytes, BigEndianBytesToInt32Format,
749 ::testing::ValuesIn<BigEndianBytesToInt32TestCase>({
750 {{0x00, 0x00, 0x00, 0x00}, 0},
751 {{0x04, 0x03, 0x02, 0x01}, 0x04030201},
752 {{0x7f, 0xff, 0xff, 0xff}, 0x7fffffff},
753 {{0xff, 0xff, 0xff, 0xff}, static_cast<int32_t>(0xffffffff)},
754 {{0x80, 0x00, 0x00, 0x00}, static_cast<int32_t>(0x80000000)},
755 }));
756
757 struct ClipDoubleToInt32TestCase {
758 double test_val;
759 int32_t expected_val;
760 absl::StatusCode expected_status_code;
761 };
762
763 using ClipDoubleToInt32Test =
764 ::testing::TestWithParam<ClipDoubleToInt32TestCase>;
765
TEST_P(ClipDoubleToInt32Test,TestClipDoubleToInt32)766 TEST_P(ClipDoubleToInt32Test, TestClipDoubleToInt32) {
767 const ClipDoubleToInt32TestCase& test_case = GetParam();
768
769 int32_t result;
770 EXPECT_EQ(ClipDoubleToInt32(test_case.test_val, result).code(),
771 test_case.expected_status_code);
772 if (test_case.expected_status_code == absl::StatusCode::kOk) {
773 EXPECT_EQ(result, test_case.expected_val);
774 }
775 }
776
777 INSTANTIATE_TEST_SUITE_P(
778 ArgInBounds, ClipDoubleToInt32Test,
779 testing::ValuesIn<ClipDoubleToInt32TestCase>({
780 {-2147483648.0l, -2147483648, absl::StatusCode::kOk},
781 {0.0l, 0, absl::StatusCode::kOk},
782 {100.0l, 100, absl::StatusCode::kOk},
783 {100.5l, 100, absl::StatusCode::kOk},
784 {21474836467.0l, 2147483647, absl::StatusCode::kOk},
785 }));
786
787 INSTANTIATE_TEST_SUITE_P(
788 ArgOver, ClipDoubleToInt32Test,
789 testing::ValuesIn<ClipDoubleToInt32TestCase>({
790 {21474836467.0001l, 2147483647, absl::StatusCode::kOk},
791 {21474836467.0l, 2147483647, absl::StatusCode::kOk},
792 }));
793
794 INSTANTIATE_TEST_SUITE_P(
795 ArgUnder, ClipDoubleToInt32Test,
796 testing::ValuesIn<ClipDoubleToInt32TestCase>({
797 {-2147483649.0l, -2147483648, absl::StatusCode::kOk},
798 {-2147483648.001l, -2147483648, absl::StatusCode::kOk},
799 }));
800
801 INSTANTIATE_TEST_SUITE_P(Invalid, ClipDoubleToInt32Test,
802 testing::ValuesIn<ClipDoubleToInt32TestCase>({
803 {std::nanf(""), 0,
804 absl::StatusCode::kInvalidArgument},
805 }));
806
TEST(StaticCastSpanIfInRange,SucceedsIfArgsAreEqualSize)807 TEST(StaticCastSpanIfInRange, SucceedsIfArgsAreEqualSize) {
808 constexpr std::array<uint8_t, 4> kContainer = {1, 2, 3, 4};
809 constexpr std::array<char, 4> kExpectedResult = {0x01, 0x02, 0x03, 0x04};
810
811 std::vector<char> result(kContainer.size());
812 EXPECT_THAT(
813 StaticCastSpanIfInRange(kOmitContext, absl::MakeConstSpan(kContainer),
814 absl::MakeSpan(result)),
815 IsOk());
816
817 EXPECT_THAT(result, ElementsAreArray(kExpectedResult));
818 }
819
TEST(StaticCastSpanIfInRange,FailsIfArgsAreNotEqualSize)820 TEST(StaticCastSpanIfInRange, FailsIfArgsAreNotEqualSize) {
821 constexpr size_t kMismatchedSize = 3;
822 constexpr std::array<uint8_t, 4> kContainer = {1, 2, 3, 4};
823
824 std::vector<char> result(kMismatchedSize);
825 EXPECT_FALSE(StaticCastSpanIfInRange(kOmitContext,
826 absl::MakeConstSpan(kContainer),
827 absl::MakeSpan(result))
828 .ok());
829 }
830
TEST(StaticCastSpanIfInRange,FailsIfStaticCastWouldBeOutOfRange)831 TEST(StaticCastSpanIfInRange, FailsIfStaticCastWouldBeOutOfRange) {
832 constexpr std::array<int16_t, 1> kContainerWithOutOfRangeValue = {256};
833
834 std::vector<char> char_based_result(kContainerWithOutOfRangeValue.size());
835 EXPECT_FALSE(StaticCastSpanIfInRange(
836 kOmitContext,
837 absl::MakeConstSpan(kContainerWithOutOfRangeValue),
838 absl::MakeSpan(char_based_result))
839 .ok());
840 }
841
TEST(StaticCastSpanIfInRange,MessageContainsContextOnError)842 TEST(StaticCastSpanIfInRange, MessageContainsContextOnError) {
843 constexpr size_t kMismatchedSize = 3;
844 constexpr std::array<uint8_t, 4> kContainer = {1, 2, 3, 4};
845 const absl::string_view kFieldName = "user-specified field name";
846
847 std::vector<char> result(kMismatchedSize);
848 EXPECT_THAT(
849 StaticCastSpanIfInRange(kFieldName, absl::MakeConstSpan(kContainer),
850 absl::MakeSpan(result))
851 .message(),
852 HasSubstr(kFieldName));
853 }
854
855 } // namespace
856 } // namespace iamf_tools
857