1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <string>
18
19 #include <audio_utils/template_utils.h>
20 #include <gtest/gtest.h>
21 #include <log/log.h>
22 #include <system/elementwise_op.h>
23
24 using android::audio_utils::elementwise_clamp;
25 using android::audio_utils::elementwise_max;
26 using android::audio_utils::elementwise_min;
27 using android::audio_utils::kMaxStructMember;
28 using android::audio_utils::op_tuple_elements;
29
30 enum class OpTestEnum { E1, E2, E3 };
31
32 struct OpTestSSS {
33 double a;
34 bool b;
35 };
36
37 struct OpTestSS {
38 OpTestSSS sss;
39 int c;
40 std::vector<float> d;
41 OpTestEnum e;
42 };
43
44 struct OpTestS {
45 OpTestSS ss;
46 int f;
47 bool g;
48 std::string h;
49 };
50
operator <<(std::ostream & os,const OpTestEnum & e)51 std::ostream& operator<<(std::ostream& os, const OpTestEnum& e) {
52 switch (e) {
53 case OpTestEnum::E1: {
54 os << "E1";
55 break;
56 }
57 case OpTestEnum::E2: {
58 os << "E2";
59 break;
60 }
61 case OpTestEnum::E3: {
62 os << "E3";
63 break;
64 }
65 }
66 return os;
67 }
68
operator <<(std::ostream & os,const OpTestSSS & sss)69 std::ostream& operator<<(std::ostream& os, const OpTestSSS& sss) {
70 os << "a: " << sss.a << ", b: " << sss.b;
71 return os;
72 }
73
operator <<(std::ostream & os,const OpTestSS & ss)74 std::ostream& operator<<(std::ostream& os, const OpTestSS& ss) {
75 os << ss.sss << ", c: " << ss.c << ", d: [";
76 for (const auto& itor : ss.d) {
77 os << itor << " ";
78 }
79 os << "], e: " << ss.e;
80 return os;
81 }
82
operator <<(std::ostream & os,const OpTestS & s)83 std::ostream& operator<<(std::ostream& os, const OpTestS& s) {
84 os << s.ss << ", f: " << s.f << ", g: " << s.g << ", h" << s.h;
85 return os;
86 }
87
operator ==(const OpTestSSS & lhs,const OpTestSSS & rhs)88 constexpr bool operator==(const OpTestSSS& lhs, const OpTestSSS& rhs) {
89 return lhs.a == rhs.a && lhs.b == rhs.b;
90 }
91
operator ==(const OpTestSS & lhs,const OpTestSS & rhs)92 constexpr bool operator==(const OpTestSS& lhs, const OpTestSS& rhs) {
93 return lhs.sss == rhs.sss && lhs.c == rhs.c && lhs.d == rhs.d &&
94 lhs.e == rhs.e;
95 }
96
operator ==(const OpTestS & lhs,const OpTestS & rhs)97 constexpr bool operator==(const OpTestS& lhs, const OpTestS& rhs) {
98 return lhs.ss == rhs.ss && lhs.f == rhs.f && lhs.g == rhs.g && lhs.h == rhs.h;
99 }
100
101 const OpTestSSS sss1{.a = 1, .b = false};
102 const OpTestSSS sss2{.a = sss1.a + 1, .b = true};
103 const OpTestSSS sss3{.a = sss2.a + 1, .b = true};
104 const OpTestSSS sss_mixed{.a = sss1.a - 1, .b = true};
105 const OpTestSSS sss_clamped_1_3{.a = sss1.a, .b = true};
106 const OpTestSSS sss_clamped_2_3{.a = sss2.a, .b = true};
107
108 const OpTestSS ss1{.sss = sss1, .c = 1, .d = {1.f}, .e = OpTestEnum::E1};
109 const OpTestSS ss2{
110 .sss = sss2, .c = ss1.c + 1, .d = {ss1.d[0] + 1}, .e = OpTestEnum::E2};
111 const OpTestSS ss3{
112 .sss = sss3, .c = ss2.c + 1, .d = {ss2.d[0] + 1}, .e = OpTestEnum::E3};
113 const OpTestSS ss_mixed{
114 .sss = sss_mixed, .c = ss1.c - 1, .d = {ss3.d[0] + 1}, .e = OpTestEnum::E3};
115 const OpTestSS ss_clamped_1_3{
116 .sss = sss_clamped_1_3, .c = ss1.c, .d = {ss3.d[0]}, .e = OpTestEnum::E3};
117 const OpTestSS ss_clamped_2_3{
118 .sss = sss_clamped_2_3, .c = ss2.c, .d = {ss3.d[0]}, .e = OpTestEnum::E3};
119
120 const OpTestS s1{.ss = ss1, .f = 1, .g = false, .h = "s1"};
121 const OpTestS s2{.ss = ss2, .f = s1.f + 1, .g = false, .h = "s2"};
122 const OpTestS s3{.ss = ss3, .f = s2.f + 1, .g = true, .h = "s3"};
123 const OpTestS s_mixed{.ss = ss_mixed, .f = s1.f - 1, .g = true, .h = "mixed"};
124 const OpTestS s_clamped_1_3{
125 .ss = ss_clamped_1_3, .f = s1.f, .g = true, .h = "s1"};
126 const OpTestS s_clamped_2_3{
127 .ss = ss_clamped_2_3, .f = s2.f, .g = true, .h = "s2"};
128
129 // clamp a structure with range of min == max
TEST(ClampOpTest,elementwise_clamp)130 TEST(ClampOpTest, elementwise_clamp) {
131 std::optional<OpTestS> clamped;
132
133 clamped = elementwise_clamp(s2, s1, s3);
134 ASSERT_NE(clamped, std::nullopt);
135 EXPECT_EQ(*clamped, s2);
136
137 clamped = elementwise_clamp(s1, s2, s3);
138 ASSERT_NE(clamped, std::nullopt);
139 EXPECT_EQ(*clamped, s2);
140
141 clamped = elementwise_clamp(s3, s1, s2);
142 ASSERT_NE(clamped, std::nullopt);
143 EXPECT_EQ(*clamped, s2);
144 }
145
146 // clamp a structure with range of min == max
TEST(ClampOpTest,clamp_same_min_max)147 TEST(ClampOpTest, clamp_same_min_max) {
148 std::optional<OpTestS> clamped;
149
150 clamped = elementwise_clamp(s1, s1, s1);
151 ASSERT_NE(clamped, std::nullopt);
152 EXPECT_EQ(*clamped, s1);
153
154 clamped = elementwise_clamp(s2, s1, s1);
155 ASSERT_NE(clamped, std::nullopt);
156 EXPECT_EQ(*clamped, s1);
157
158 clamped = elementwise_clamp(s3, s1, s1);
159 ASSERT_NE(clamped, std::nullopt);
160 EXPECT_EQ(*clamped, s1);
161
162 clamped = elementwise_clamp(s1, s2, s2);
163 ASSERT_NE(clamped, std::nullopt);
164 EXPECT_EQ(*clamped, s2);
165
166 clamped = elementwise_clamp(s2, s2, s2);
167 ASSERT_NE(clamped, std::nullopt);
168 EXPECT_EQ(*clamped, s2);
169
170 clamped = elementwise_clamp(s3, s2, s2);
171 ASSERT_NE(clamped, std::nullopt);
172 EXPECT_EQ(*clamped, s2);
173
174 clamped = elementwise_clamp(s1, s3, s3);
175 ASSERT_NE(clamped, std::nullopt);
176 EXPECT_EQ(*clamped, s3);
177
178 clamped = elementwise_clamp(s2, s3, s3);
179 ASSERT_NE(clamped, std::nullopt);
180 EXPECT_EQ(*clamped, s3);
181
182 clamped = elementwise_clamp(s3, s3, s3);
183 ASSERT_NE(clamped, std::nullopt);
184 EXPECT_EQ(*clamped, s3);
185 }
186
187 // clamp a structure with invalid range (min > max)
TEST(ClampOpTest,clamp_invalid_range)188 TEST(ClampOpTest, clamp_invalid_range) {
189 EXPECT_EQ(std::nullopt, elementwise_clamp(s1, s2, s1));
190 EXPECT_EQ(std::nullopt, elementwise_clamp(s2, s3, s2));
191 EXPECT_EQ(std::nullopt, elementwise_clamp(s3, s3, s1));
192 }
193
194 // all members in p3 clamped to s2 but p3.ss.sss.a
TEST(ClampOpTest,clamp_to_max_a)195 TEST(ClampOpTest, clamp_to_max_a) {
196 OpTestS p3 = s3;
197 std::optional<OpTestS> clamped;
198
199 p3.ss.sss.a = s1.ss.sss.a;
200 clamped = elementwise_clamp(p3, s1, s2);
201 ASSERT_NE(clamped, std::nullopt);
202 // ensure p3.ss.sss.a is not clamped
203 EXPECT_EQ(clamped->ss.sss.a, s1.ss.sss.a);
204 // ensure all other members correctly clamped to max
205 clamped->ss.sss.a = s2.ss.sss.a;
206 EXPECT_EQ(*clamped, s2);
207 }
208
209 // all members in p3 clamped to s2 but p3.ss.sss.b
TEST(ClampOpTest,clamp_to_max_b)210 TEST(ClampOpTest, clamp_to_max_b) {
211 OpTestS p3 = s3;
212 std::optional<OpTestS> clamped;
213
214 p3.ss.sss.b = s1.ss.sss.b;
215 clamped = elementwise_clamp(p3, s1, s2);
216 ASSERT_NE(clamped, std::nullopt);
217 // ensure p3.ss.sss.b is not clamped
218 EXPECT_EQ(clamped->ss.sss.b, s1.ss.sss.b);
219 // ensure all other members correctly clamped to max
220 clamped->ss.sss.b = s2.ss.sss.b;
221 EXPECT_EQ(*clamped, s2);
222 }
223
224 // all members in p3 clamped to s2 but p3.ss.c
TEST(ClampOpTest,clamp_to_max_c)225 TEST(ClampOpTest, clamp_to_max_c) {
226 OpTestS p3 = s3;
227 std::optional<OpTestS> clamped;
228
229 p3.ss.c = s1.ss.c;
230 clamped = elementwise_clamp(p3, s1, s2);
231 ASSERT_NE(clamped, std::nullopt);
232 EXPECT_EQ(p3.ss.c, s1.ss.c);
233 // ensure p3.ss.c is not clamped
234 EXPECT_EQ(clamped->ss.c, s1.ss.c);
235 // ensure all other members correctly clamped to max
236 clamped->ss.c = s2.ss.c;
237 EXPECT_EQ(*clamped, s2);
238 }
239
240 // all members in p3 clamped to s2 but p3.ss.d
TEST(ClampOpTest,clamp_to_max_d)241 TEST(ClampOpTest, clamp_to_max_d) {
242 OpTestS p3 = s3;
243 std::optional<OpTestS> clamped;
244
245 p3.ss.d = s1.ss.d;
246 clamped = elementwise_clamp(p3, s1, s2);
247 ASSERT_NE(clamped, std::nullopt);
248 // ensure p3.ss.d is not clamped
249 EXPECT_EQ(clamped->ss.d, s1.ss.d);
250 // ensure all other members correctly clamped to max
251 clamped->ss.d = s2.ss.d;
252 EXPECT_EQ(*clamped, s2);
253 }
254
255 // all members in p3 clamped to s2 but p3.ss.e
TEST(ClampOpTest,clamp_to_max_e)256 TEST(ClampOpTest, clamp_to_max_e) {
257 OpTestS p3 = s3;
258 std::optional<OpTestS> clamped;
259
260 p3.ss.e = s1.ss.e;
261 clamped = elementwise_clamp(p3, s1, s2);
262 ASSERT_NE(clamped, std::nullopt);
263 // ensure p3.ss.e is not clamped
264 EXPECT_EQ(clamped->ss.e, s1.ss.e);
265 // ensure all other members correctly clamped to max
266 clamped->ss.e = s2.ss.e;
267 EXPECT_EQ(*clamped, s2);
268 }
269
270 // all members in p3 clamped to s2 but p3.f
TEST(ClampOpTest,clamp_to_max_f)271 TEST(ClampOpTest, clamp_to_max_f) {
272 OpTestS p3 = s3;
273 std::optional<OpTestS> clamped;
274
275 p3.f = s1.f;
276 clamped = elementwise_clamp(p3, s1, s2);
277 ASSERT_NE(clamped, std::nullopt);
278 // ensure p3.f is not clamped
279 EXPECT_EQ(clamped->f, s1.f);
280 // ensure all other members correctly clamped to max
281 clamped->f = s2.f;
282 EXPECT_EQ(*clamped, s2);
283 }
284
285 // all members in p3 clamped to s2 but p3.g
TEST(ClampOpTest,clamp_to_max_g)286 TEST(ClampOpTest, clamp_to_max_g) {
287 OpTestS p3 = s3;
288 std::optional<OpTestS> clamped;
289
290 p3.g = s1.g;
291 clamped = elementwise_clamp(p3, s1, s2);
292 ASSERT_NE(clamped, std::nullopt);
293 // ensure p3.g is not clamped
294 EXPECT_EQ(clamped->g, s1.g);
295 // ensure all other members correctly clamped to max
296 clamped->g = s2.g;
297 EXPECT_EQ(*clamped, s2);
298 }
299
300 // all members in p3 clamped to s2 but p3.h
TEST(ClampOpTest,clamp_to_max_h)301 TEST(ClampOpTest, clamp_to_max_h) {
302 OpTestS p3 = s3;
303 std::optional<OpTestS> clamped;
304
305 p3.h = s1.h;
306 clamped = elementwise_clamp(p3, s1, s2);
307 ASSERT_NE(clamped, std::nullopt);
308 // ensure p3.g is not clamped
309 EXPECT_EQ(clamped->h, s1.h);
310 // ensure all other members correctly clamped to max
311 clamped->h = s2.h;
312 EXPECT_EQ(*clamped, s2);
313 }
314
315 // all members in p1 clamped to s2 except p1.ss.sss.a
TEST(ClampOpTest,clamp_to_min_a)316 TEST(ClampOpTest, clamp_to_min_a) {
317 OpTestS p1 = s1;
318 p1.ss.sss.a = s3.ss.sss.a;
319 std::optional<OpTestS> clamped = elementwise_clamp(p1, s2, s3);
320 ASSERT_NE(clamped, std::nullopt);
321 // ensure p1.ss.sss.a is not clamped
322 EXPECT_EQ(clamped->ss.sss.a, s3.ss.sss.a);
323 // ensure all other members correctly clamped to max
324 clamped->ss.sss.a = s2.ss.sss.a;
325 EXPECT_EQ(*clamped, s2);
326 }
327
328 // all members in p1 clamped to s2 but p1.ss.sss.b
TEST(ClampOpTest,clamp_to_min_b)329 TEST(ClampOpTest, clamp_to_min_b) {
330 OpTestS p1 = s1;
331 p1.ss.sss.b = s3.ss.sss.b;
332 std::optional<OpTestS> clamped = elementwise_clamp(p1, s2, s3);
333 ASSERT_NE(clamped, std::nullopt);
334 // ensure p1.ss.sss.b is not clamped
335 EXPECT_EQ(clamped->ss.sss.b, s3.ss.sss.b);
336 // ensure all other members correctly clamped to max
337 clamped->ss.sss.b = s2.ss.sss.b;
338 EXPECT_EQ(*clamped, s2);
339 }
340
TEST(ClampOpTest,clamp_to_min_c)341 TEST(ClampOpTest, clamp_to_min_c) {
342 OpTestS p1 = s1;
343 p1.ss.c = s3.ss.c;
344 std::optional<OpTestS> clamped = elementwise_clamp(p1, s2, s3);
345 ASSERT_NE(clamped, std::nullopt);
346 EXPECT_EQ(p1.ss.c, s3.ss.c);
347 // ensure p1.ss.c is not clamped
348 EXPECT_EQ(clamped->ss.c, s3.ss.c);
349 // ensure all other members correctly clamped to max
350 clamped->ss.c = s2.ss.c;
351 EXPECT_EQ(*clamped, s2);
352 }
353
TEST(ClampOpTest,clamp_to_min_d)354 TEST(ClampOpTest, clamp_to_min_d) {
355 OpTestS p1 = s1;
356 p1.ss.d = s3.ss.d;
357 std::optional<OpTestS> clamped = elementwise_clamp(p1, s2, s3);
358 ASSERT_NE(clamped, std::nullopt);
359 // ensure p1.ss.d is not clamped
360 EXPECT_EQ(clamped->ss.d, s3.ss.d);
361 // ensure all other members correctly clamped to max
362 clamped->ss.d = s2.ss.d;
363 EXPECT_EQ(*clamped, s2);
364 }
365
TEST(ClampOpTest,clamp_to_min_e)366 TEST(ClampOpTest, clamp_to_min_e) {
367 OpTestS p1 = s1;
368 p1.ss.e = s3.ss.e;
369 std::optional<OpTestS> clamped = elementwise_clamp(p1, s2, s3);
370 ASSERT_NE(clamped, std::nullopt);
371 // ensure p1.ss.e is not clamped
372 EXPECT_EQ(clamped->ss.e, s3.ss.e);
373 // ensure all other members correctly clamped to max
374 clamped->ss.e = s2.ss.e;
375 EXPECT_EQ(*clamped, s2);
376 }
377
TEST(ClampOpTest,clamp_to_min_f)378 TEST(ClampOpTest, clamp_to_min_f) {
379 OpTestS p1 = s1;
380 p1.f = s3.f;
381 std::optional<OpTestS> clamped = elementwise_clamp(p1, s2, s3);
382 ASSERT_NE(clamped, std::nullopt);
383 // ensure p1.f is not clamped
384 EXPECT_EQ(clamped->f, s3.f);
385 // ensure all other members correctly clamped to max
386 clamped->f = s2.f;
387 EXPECT_EQ(*clamped, s2);
388 }
389
TEST(ClampOpTest,clamp_to_min_g)390 TEST(ClampOpTest, clamp_to_min_g) {
391 OpTestS p1 = s1;
392 p1.g = s3.g;
393 std::optional<OpTestS> clamped = elementwise_clamp(p1, s2, s3);
394 ASSERT_NE(clamped, std::nullopt);
395 // ensure p1.g is not clamped
396 EXPECT_EQ(clamped->g, s3.g);
397 // ensure all other members correctly clamped to max
398 clamped->g = s2.g;
399 EXPECT_EQ(*clamped, s2);
400 }
401
TEST(ClampOpTest,clamp_to_min_h)402 TEST(ClampOpTest, clamp_to_min_h) {
403 OpTestS p1 = s1;
404 p1.h = s3.h;
405 std::optional<OpTestS> clamped = elementwise_clamp(p1, s2, s3);
406 ASSERT_NE(clamped, std::nullopt);
407 // ensure p1.g is not clamped
408 EXPECT_EQ(clamped->h, s3.h);
409 // ensure all other members correctly clamped to max
410 clamped->h = s2.h;
411 EXPECT_EQ(*clamped, s2);
412 }
413
414 // test vector clamp with same size target and min/max
TEST(ClampOpTest,clamp_vector_same_size)415 TEST(ClampOpTest, clamp_vector_same_size) {
416 std::optional<OpTestS> clamped;
417 OpTestS target = s2, min = s1, max = s3;
418
419 min.ss.d = {1, 11, 21};
420 max.ss.d = {10, 20, 30};
421 target.ss.d = {0, 30, 21};
422 std::vector<float> expect = {1, 20, 21};
423 clamped = elementwise_clamp(target, min, max);
424 ASSERT_NE(clamped, std::nullopt);
425 EXPECT_EQ(clamped->ss.d, expect);
426
427 min.ss.d = {10, 11, 1};
428 max.ss.d = {10, 20, 30};
429 target.ss.d = {20, 20, 20};
430 expect = {10, 20, 20};
431 clamped = elementwise_clamp(target, min, max);
432 ASSERT_NE(clamped, std::nullopt);
433 EXPECT_EQ(clamped->ss.d, expect);
434
435 clamped = elementwise_clamp(target, min, min);
436 ASSERT_NE(clamped, std::nullopt);
437 EXPECT_EQ(*clamped, min);
438
439 clamped = elementwise_clamp(target, max, max);
440 ASSERT_NE(clamped, std::nullopt);
441 EXPECT_EQ(*clamped, max);
442 }
443
444 // test vector clamp with one element min and max
TEST(ClampOpTest,clamp_vector_one_member_min_max)445 TEST(ClampOpTest, clamp_vector_one_member_min_max) {
446 std::optional<OpTestS> clamped;
447 OpTestS target = s2, min = s1, max = s3;
448
449 min.ss.d = {10};
450 max.ss.d = {20};
451 target.ss.d = {0, 30, 20};
452 std::vector<float> expect = {10, 20, 20};
453
454 clamped = elementwise_clamp(target, min, max);
455 ASSERT_NE(clamped, std::nullopt);
456 EXPECT_EQ(clamped->ss.d, expect);
457 }
458
TEST(ClampOpTest,clamp_vector_one_min)459 TEST(ClampOpTest, clamp_vector_one_min) {
460 std::optional<OpTestS> clamped;
461 OpTestS target = s2, min = s1, max = s3;
462
463 min.ss.d = {0};
464 max.ss.d = {20, 10, 30};
465 target.ss.d = {-1, 30, 20};
466 std::vector<float> expect = {0, 10, 20};
467
468 clamped = elementwise_clamp(target, min, max);
469 ASSERT_NE(clamped, std::nullopt);
470 EXPECT_EQ(clamped->ss.d, expect);
471 }
472
TEST(ClampOpTest,clamp_vector_one_max)473 TEST(ClampOpTest, clamp_vector_one_max) {
474 std::optional<OpTestS> clamped;
475 OpTestS target = s2, min = s1, max = s3;
476
477 min.ss.d = {0, 10, 20};
478 max.ss.d = {20};
479 target.ss.d = {-1, 30, 20};
480 std::vector<float> expect = {0, 20, 20};
481
482 clamped = elementwise_clamp(target, min, max);
483 ASSERT_NE(clamped, std::nullopt);
484 EXPECT_EQ(clamped->ss.d, expect);
485 }
486
TEST(ClampOpTest,clamp_vector_invalid_range)487 TEST(ClampOpTest, clamp_vector_invalid_range) {
488 std::optional<OpTestS> clamped;
489 OpTestS target = s2, min = s1, max = s3;
490
491 target.ss.d = {-1, 30, 20};
492 std::vector<float> expect = {0, 20, 20};
493
494 min.ss.d = {0, 10};
495 max.ss.d = {20};
496 clamped = elementwise_clamp(target, min, max);
497 EXPECT_EQ(clamped, std::nullopt);
498
499 min.ss.d = {0, 10, 20};
500 max.ss.d = {};
501 clamped = elementwise_clamp(target, min, max);
502 EXPECT_EQ(clamped, std::nullopt);
503
504 min.ss.d = {};
505 max.ss.d = {0, 10, 20};
506 clamped = elementwise_clamp(target, min, max);
507 EXPECT_EQ(clamped, std::nullopt);
508
509 min.ss.d = {0, 10, 20};
510 max.ss.d = {0, 10, 10};
511 clamped = elementwise_clamp(target, min, max);
512 EXPECT_EQ(clamped, std::nullopt);
513
514 min.ss.d = {0, 10, 5, 10};
515 max.ss.d = {0, 10, 10};
516 clamped = elementwise_clamp(target, min, max);
517 EXPECT_EQ(clamped, std::nullopt);
518
519 min.ss.d = {};
520 max.ss.d = {};
521 target.ss.d = {};
522 clamped = elementwise_clamp(target, min, max);
523 EXPECT_EQ(clamped, std::nullopt);
524 }
525
TEST(ClampOpTest,clamp_string)526 TEST(ClampOpTest, clamp_string) {
527 std::optional<OpTestS> clamped;
528 OpTestS target = s2, min = s1, max = s3;
529
530 min.h = "";
531 max.h = "";
532 target.h = "";
533 clamped = elementwise_clamp(target, min, max);
534 EXPECT_EQ(*clamped, target);
535
536 min.h = "apple";
537 max.h = "pear";
538 target.h = "orange";
539 clamped = elementwise_clamp(target, min, max);
540 ASSERT_NE(clamped, std::nullopt);
541 EXPECT_EQ(clamped->h, std::clamp(target.h, min.h, max.h));
542 EXPECT_EQ(*clamped, target);
543
544 target.h = "aardvark";
545 clamped = elementwise_clamp(target, min, max);
546 ASSERT_NE(clamped, std::nullopt);
547 EXPECT_EQ(clamped->h, std::clamp(target.h, min.h, max.h));
548 target.h = clamped->h;
549 EXPECT_EQ(*clamped, target);
550
551 target.h = "zebra";
552 clamped = elementwise_clamp(target, min, max);
553 ASSERT_NE(clamped, std::nullopt);
554 EXPECT_EQ(clamped->h, std::clamp(target.h, min.h, max.h));
555 target.h = clamped->h;
556 EXPECT_EQ(*clamped, target);
557 }
558
559 // clamp a mixed structure in range
TEST(ClampOpTest,clamp_mixed)560 TEST(ClampOpTest, clamp_mixed) {
561 std::optional<OpTestS> clamped;
562
563 clamped = elementwise_clamp(s_mixed, s1, s3);
564 ASSERT_NE(clamped, std::nullopt);
565 EXPECT_EQ(*clamped, s_clamped_1_3);
566
567 clamped = elementwise_clamp(s_mixed, s2, s3);
568 ASSERT_NE(clamped, std::nullopt);
569 EXPECT_EQ(*clamped, s_clamped_2_3);
570 }
571
572 // clamp a mixed structure in range
TEST(ClampOpTest,clamp_primitive_type)573 TEST(ClampOpTest, clamp_primitive_type) {
574 std::optional<OpTestS> clamped;
575
576 clamped = elementwise_clamp(s_mixed, s1, s3);
577 ASSERT_NE(clamped, std::nullopt);
578 EXPECT_EQ(*clamped, s_clamped_1_3);
579
580 clamped = elementwise_clamp(s_mixed, s2, s3);
581 ASSERT_NE(clamped, std::nullopt);
582 EXPECT_EQ(*clamped, s_clamped_2_3);
583 }
584
585 // Template function to return an array of size N
586 template <size_t N>
getArrayN()587 auto getArrayN() {
588 return std::array<int, N>{};
589 }
590
591 // Recursive function to make a tuple of arrays up to size N
592 template <std::size_t N>
makeTupleOfArrays()593 auto makeTupleOfArrays() {
594 if constexpr (N == 1) {
595 return std::make_tuple(getArrayN<1>());
596 } else {
597 return std::tuple_cat(makeTupleOfArrays<N - 1>(),
598 std::make_tuple(getArrayN<N>()));
599 }
600 }
601
602 // test the clamp utility can handle structures with up to
603 // `android::audio_utils::kMaxStructMember` members
TEST(ClampOpTest,clamp_different_struct_members)604 TEST(ClampOpTest, clamp_different_struct_members) {
605 auto clampVerifyOp = [](auto&& arr) {
606 auto m1(arr), m2(arr), m3(arr);
607 m1.fill(1);
608 m2.fill(2);
609 m3.fill(3);
610
611 auto clamped = elementwise_clamp(m2, m1, m3);
612 ASSERT_NE(clamped, std::nullopt);
613 EXPECT_EQ(*clamped, m2);
614
615 clamped = elementwise_clamp(m1, m2, m3);
616 ASSERT_NE(clamped, std::nullopt);
617 EXPECT_EQ(*clamped, m2);
618
619 clamped = elementwise_clamp(m3, m1, m2);
620 ASSERT_NE(clamped, std::nullopt);
621 EXPECT_EQ(*clamped, m2);
622
623 // invalid range
624 EXPECT_EQ(elementwise_clamp(m3, m2, m1), std::nullopt);
625 EXPECT_EQ(elementwise_clamp(m3, m3, m1), std::nullopt);
626 EXPECT_EQ(elementwise_clamp(m3, m3, m2), std::nullopt);
627 };
628
629 auto arrays = makeTupleOfArrays<kMaxStructMember>();
630 for (size_t i = 0; i < kMaxStructMember; i++) {
631 op_tuple_elements(arrays, i, clampVerifyOp);
632 }
633 }
634
635 template <typename T>
MinMaxOpTestHelper(const T & a,const T & b,const T & expectedLower,const T & expectedUpper,const std::optional<T> & unexpected=std::nullopt)636 void MinMaxOpTestHelper(const T& a, const T& b, const T& expectedLower,
637 const T& expectedUpper,
638 const std::optional<T>& unexpected = std::nullopt) {
639 // lower
640 auto result = elementwise_min(a, b);
641 ASSERT_NE(unexpected, *result);
642 EXPECT_EQ(expectedLower, *result);
643
644 result = elementwise_min(b, a);
645 ASSERT_NE(unexpected, *result);
646 EXPECT_EQ(expectedLower, *result);
647
648 result = elementwise_min(a, a);
649 EXPECT_EQ(a, elementwise_min(a, a));
650 EXPECT_EQ(b, elementwise_min(b, b));
651
652 // upper
653 result = elementwise_max(a, b);
654 ASSERT_NE(unexpected, result);
655 EXPECT_EQ(expectedUpper, *result);
656
657 result = elementwise_max(b, a);
658 ASSERT_NE(unexpected, result);
659 EXPECT_EQ(expectedUpper, *result);
660
661 EXPECT_EQ(a, elementwise_max(a, a));
662 EXPECT_EQ(b, elementwise_max(b, b));
663 }
664
TEST(MinMaxOpTest,primitive_type_int)665 TEST(MinMaxOpTest, primitive_type_int) {
666 EXPECT_NO_FATAL_FAILURE(MinMaxOpTestHelper(1, 2, 1, 2));
667 }
668
TEST(MinMaxOpTest,primitive_type_float)669 TEST(MinMaxOpTest, primitive_type_float) {
670 EXPECT_NO_FATAL_FAILURE(MinMaxOpTestHelper(.1f, .2f, .1f, .2f));
671 }
672
TEST(MinMaxOpTest,primitive_type_string)673 TEST(MinMaxOpTest, primitive_type_string) {
674 std::string a = "ab", b = "ba";
675 EXPECT_NO_FATAL_FAILURE(
676 MinMaxOpTestHelper(a, b, std::min(a, b), std::max(a, b)));
677 a = "", b = "0";
678 EXPECT_NO_FATAL_FAILURE(
679 MinMaxOpTestHelper(a, b, std::min(a, b), std::max(a, b)));
680 a = "abc", b = "1234";
681 EXPECT_NO_FATAL_FAILURE(
682 MinMaxOpTestHelper(a, b, std::min(a, b), std::max(a, b)));
683 }
684
TEST(MinMaxOpTest,primitive_type_enum)685 TEST(MinMaxOpTest, primitive_type_enum) {
686 EXPECT_NO_FATAL_FAILURE(MinMaxOpTestHelper(OpTestEnum::E1, OpTestEnum::E2,
687 OpTestEnum::E1, OpTestEnum::E2));
688 EXPECT_NO_FATAL_FAILURE(MinMaxOpTestHelper(OpTestEnum::E3, OpTestEnum::E2,
689 OpTestEnum::E2, OpTestEnum::E3));
690 }
691
TEST(MinMaxOpTest,vector_same_size)692 TEST(MinMaxOpTest, vector_same_size) {
693 std::vector<int> v1, v2, expected_lower, expected_upper;
694 EXPECT_NO_FATAL_FAILURE(
695 MinMaxOpTestHelper(v1, v2, expected_lower, expected_upper));
696
697 v1 = {1}, v2 = {2}, expected_lower = {1}, expected_upper = {2};
698 EXPECT_NO_FATAL_FAILURE(
699 MinMaxOpTestHelper(v1, v2, expected_lower, expected_upper));
700
701 v1 = {3, 2, 3}, v2 = {2, 2, 2}, expected_lower = v2, expected_upper = v1;
702 EXPECT_NO_FATAL_FAILURE(
703 MinMaxOpTestHelper(v1, v2, expected_lower, expected_upper));
704
705 v1 = {3, 2, 3}, v2 = {1, 4, 1}, expected_lower = {1, 2, 1},
706 expected_upper = {3, 4, 3};
707 EXPECT_NO_FATAL_FAILURE(
708 MinMaxOpTestHelper(v1, v2, expected_lower, expected_upper));
709 }
710
TEST(MinMaxOpTest,vector_different_size_valid)711 TEST(MinMaxOpTest, vector_different_size_valid) {
712 std::vector<int> v1, v2({1}), expected_lower, expected_upper({1});
713 EXPECT_NO_FATAL_FAILURE(
714 MinMaxOpTestHelper(v1, v2, expected_lower, expected_upper));
715
716 v1 = {1, 2, 3, 1, 0, 5}, v2 = {2}, expected_lower = {1, 2, 2, 1, 0, 2},
717 expected_upper = {2, 2, 3, 2, 2, 5};
718 EXPECT_NO_FATAL_FAILURE(
719 MinMaxOpTestHelper(v1, v2, expected_lower, expected_upper));
720 }
721
722 // invalid vector size combination, expect std::nullopt
TEST(MinMaxOpTest,invalid_vector_size)723 TEST(MinMaxOpTest, invalid_vector_size) {
724 std::vector<int> v1 = {3, 2}, v2 = {2, 2, 2};
725 EXPECT_EQ(std::nullopt, elementwise_min(v1, v2));
726 EXPECT_EQ(std::nullopt, elementwise_min(v2, v1));
727 EXPECT_EQ(std::nullopt, elementwise_max(v1, v2));
728 EXPECT_EQ(std::nullopt, elementwise_max(v2, v1));
729 }
730
TEST(MinMaxOpTest,aggregate_type)731 TEST(MinMaxOpTest, aggregate_type) {
732 EXPECT_NO_FATAL_FAILURE(MinMaxOpTestHelper(sss1, sss2, sss1, sss2));
733 EXPECT_NO_FATAL_FAILURE(MinMaxOpTestHelper(sss2, sss3, sss2, sss3));
734 EXPECT_NO_FATAL_FAILURE(MinMaxOpTestHelper(sss1, sss3, sss1, sss3));
735
736 EXPECT_NO_FATAL_FAILURE(MinMaxOpTestHelper(ss1, ss2, ss1, ss2));
737 EXPECT_NO_FATAL_FAILURE(MinMaxOpTestHelper(ss2, ss3, ss2, ss3));
738 EXPECT_NO_FATAL_FAILURE(MinMaxOpTestHelper(ss1, ss3, ss1, ss3));
739
740 EXPECT_NO_FATAL_FAILURE(MinMaxOpTestHelper(s1, s2, s1, s2));
741 EXPECT_NO_FATAL_FAILURE(MinMaxOpTestHelper(s2, s3, s2, s3));
742 EXPECT_NO_FATAL_FAILURE(MinMaxOpTestHelper(s1, s3, s1, s3));
743 }
744
745 // invalid vector size combination in nested structure
TEST(MinMaxOpTest,invalid_vector_in_structure)746 TEST(MinMaxOpTest, invalid_vector_in_structure) {
747 auto tt1 = ss1, tt2 = ss2;
748 tt1.d = {.1f, .2f, .3f};
749 tt2.d = {.1f, .2f, .3f, .4f, .5f};
750
751 EXPECT_EQ(std::nullopt, elementwise_min(tt1, tt2));
752 EXPECT_EQ(std::nullopt, elementwise_min(tt2, tt1));
753 EXPECT_EQ(std::nullopt, elementwise_max(tt1, tt2));
754 EXPECT_EQ(std::nullopt, elementwise_max(tt2, tt1));
755
756 auto t1 = s1, t2 = s2;
757 t1.ss = tt1, t2.ss = tt2;
758 EXPECT_EQ(std::nullopt, elementwise_min(t1, t2));
759 EXPECT_EQ(std::nullopt, elementwise_min(t2, t1));
760 EXPECT_EQ(std::nullopt, elementwise_max(t1, t2));
761 EXPECT_EQ(std::nullopt, elementwise_max(t2, t1));
762 }
763
TEST(MinMaxOpTest,aggregate_different_members)764 TEST(MinMaxOpTest, aggregate_different_members) {
765 auto boundaryVerifyOp = [](auto&& arr) {
766 auto m1(arr), m2(arr);
767 m1.fill(1);
768 m2.fill(2);
769
770 auto lower = elementwise_min(m1, m2);
771 ASSERT_NE(lower, std::nullopt);
772 EXPECT_EQ(*lower, m1);
773
774 auto upper = elementwise_max(m1, m2);
775 ASSERT_NE(upper, std::nullopt);
776 EXPECT_EQ(*upper, m2);
777 };
778
779 auto arrays = makeTupleOfArrays<kMaxStructMember>();
780 for (size_t i = 0; i < kMaxStructMember; i++) {
781 op_tuple_elements(arrays, i, boundaryVerifyOp);
782 }
783 }