xref: /aosp_15_r20/system/media/tests/elementwise_op_basic_tests.cpp (revision b9df5ad1c9ac98a7fefaac271a55f7ae3db05414)
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 }