1 /*
2 * Copyright 2020 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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "audio_utils_metadata_tests"
19
20 #define METADATA_TESTING
21
22 #include <audio_utils/Metadata.h>
23 #include <gtest/gtest.h>
24 #include <log/log.h>
25
26 #include <error.h>
27 #include <iostream>
28
29 using namespace android::audio_utils::metadata;
30
31 // Preferred: Key in header - a constexpr which is created by the compiler.
32 inline constexpr CKey<std::string> ITS_NAME_IS("its_name_is");
33
34 // Not preferred: Key which is created at run-time.
35 inline const Key<std::string> MY_NAME_IS("my_name_is");
36
37 // The Metadata table
38 inline constexpr CKey<Data> TABLE("table");
39
40 #ifdef METADATA_TESTING
41
42 // Validate recursive typing on "Datum".
43 inline constexpr CKey<std::vector<Datum>> VECTOR("vector");
44 inline constexpr CKey<std::pair<Datum, Datum>> PAIR("pair");
45
46 // Validate that we move instead of copy.
47 inline constexpr CKey<MoveCount> MOVE_COUNT("MoveCount");
48
49 // Validate recursive container support.
50 inline constexpr CKey<std::vector<std::vector<std::pair<std::string, short>>>> FUNKY("funky");
51
52 // Validate structured binding parceling.
53 inline constexpr CKey<Arbitrary> ARBITRARY("arbitrary");
54 #endif
55
toString(const ByteString & bs)56 std::string toString(const ByteString &bs) {
57 std::stringstream ss;
58 ss << "{\n" << std::hex;
59 if (bs.size() > 0) {
60 for (size_t i = 0; ; ++i) {
61 if ((i & 7) == 0) {
62 ss << " ";
63 }
64 ss << "0x" << std::setfill('0') << std::setw(2) << (unsigned)bs[i];
65 if (i == bs.size() - 1) {
66 break;
67 } else if ((i & 7) == 7) {
68 ss << ",\n";
69 } else {
70 ss << ", ";
71 }
72 }
73 }
74 ss << "\n}\n";
75 return ss.str();
76 }
77
TEST(metadata_tests,basic_datum)78 TEST(metadata_tests, basic_datum) {
79 Datum d;
80 d = "abc";
81 //ASSERT_EQ("abc", std::any_cast<const char *>(d));
82 ASSERT_EQ("abc", std::any_cast<std::string>(d));
83 //d = std::vector<int>();
84
85 Datum lore((int32_t) 10);
86 d = lore;
87 ASSERT_EQ(10, std::any_cast<int32_t>(d));
88
89 // TODO: should we enable Datum to copy from std::any if the types
90 // are correct? The problem is how to signal failure.
91 std::any arg = (int)1;
92 // Datum invalid = arg; // this doesn't work.
93
94 struct dummy {
95 int value = 0;
96 };
97
98 // check apply with a void function
99 {
100 // try to apply with an invalid argument
101 int value = 0;
102
103 arg = dummy{}; // not an expected type, apply will fail with false.
104 std::any result;
105
106 ASSERT_FALSE(primitive_metadata_types::apply([&](auto *t __unused) {
107 value++;
108 }, &arg, &result));
109
110 ASSERT_EQ(0, value); // never invoked.
111 ASSERT_FALSE(result.has_value()); // no value returned.
112
113 // try to apply with a valid argument.
114 arg = (int)1;
115
116 ASSERT_TRUE(primitive_metadata_types::apply([&](auto *t __unused) {
117 value++;
118 }, &arg, &result));
119
120 ASSERT_EQ(1, value); // invoked once.
121 ASSERT_FALSE(result.has_value()); // no value returned (function returns void).
122 }
123
124 // check apply with a function that returns 2.
125 {
126 int value = 0;
127 arg = (int)1;
128 std::any result;
129
130 ASSERT_TRUE(primitive_metadata_types::apply([&](auto *t __unused) {
131 value++;
132 return (int32_t)2;
133 }, &arg, &result));
134
135 ASSERT_EQ(1, value); // invoked once.
136 ASSERT_EQ(2, std::any_cast<int32_t>(result)); // 2 returned
137 }
138
139 #ifdef METADATA_TESTING
140 // Checks the number of moves versus copies as the datum flows through Data.
141 // the counters should increment each time a MoveCount gets copied or
142 // moved.
143
144 // Datum mc = MoveCount();
145
146 Datum mc{MoveCount()};
147 ASSERT_TRUE(1 >= std::any_cast<MoveCount>(mc).mMoveCount); // no more than 1 move.
148 ASSERT_EQ(0, std::any_cast<MoveCount>(&mc)->mCopyCount); // no copies
149 ASSERT_EQ(1, std::any_cast<MoveCount>(mc).mCopyCount); // Note: any_cast on value copies.
150
151
152 // serialize
153 ByteString bs;
154 ASSERT_TRUE(copyToByteString(mc, bs));
155 // deserialize
156 size_t idx = 0;
157 Datum parceled;
158 ASSERT_TRUE(copyFromByteString(&parceled, bs, idx, nullptr /* unknowns */));
159
160 // everything OK with the received data?
161 ASSERT_EQ(bs.size(), idx); // no data left over.
162 ASSERT_TRUE(parceled.has_value()); // we have a value.
163
164 // confirm no copies.
165 ASSERT_TRUE(2 >= std::any_cast<MoveCount>(&parceled)->mMoveCount); // no more than 2 moves.
166 ASSERT_EQ(0, std::any_cast<MoveCount>(&parceled)->mCopyCount);
167 #endif
168 }
169
TEST(metadata_tests,basic_data)170 TEST(metadata_tests, basic_data) {
171 Data d;
172 d.emplace("int32", (int32_t)1);
173 d.emplace("int64", (int64_t)2);
174 d.emplace("float", (float)3.1f);
175 d.emplace("double", (double)4.11);
176 d.emplace("string", "hello");
177 d["string2"] = "world";
178
179 // Put with typed keys
180 d.put(MY_NAME_IS, "neo");
181 d[ITS_NAME_IS] = "spot";
182
183 ASSERT_EQ(1, std::any_cast<int32_t>(d["int32"]));
184 ASSERT_EQ(2, std::any_cast<int64_t>(d["int64"]));
185 ASSERT_EQ(3.1f, std::any_cast<float>(d["float"]));
186 ASSERT_EQ(4.11, std::any_cast<double>(d["double"]));
187 ASSERT_EQ("hello", std::any_cast<std::string>(d["string"]));
188 ASSERT_EQ("world", std::any_cast<std::string>(d["string2"]));
189
190 // Get with typed keys
191 ASSERT_EQ("neo", *d.get_ptr(MY_NAME_IS));
192 ASSERT_EQ("spot", *d.get_ptr(ITS_NAME_IS));
193
194 ASSERT_EQ("neo", d[MY_NAME_IS]);
195 ASSERT_EQ("spot", d[ITS_NAME_IS]);
196
197 ByteString bs = byteStringFromData(d);
198 Data data = dataFromByteString(bs);
199 ASSERT_EQ((size_t)8, data.size());
200
201 ASSERT_EQ(1, std::any_cast<int32_t>(data["int32"]));
202 ASSERT_EQ(2, std::any_cast<int64_t>(data["int64"]));
203 ASSERT_EQ(3.1f, std::any_cast<float>(data["float"]));
204 ASSERT_EQ(4.11, std::any_cast<double>(data["double"]));
205 ASSERT_EQ("hello", std::any_cast<std::string>(data["string"]));
206 ASSERT_EQ("neo", *data.get_ptr(MY_NAME_IS));
207 ASSERT_EQ("spot", *data.get_ptr(ITS_NAME_IS));
208
209 data[MY_NAME_IS] = "one";
210 ASSERT_EQ("one", data[MY_NAME_IS]);
211
212 // Keys are typed, so this fails to compile.
213 // data->put(MY_NAME_IS, 10);
214
215 #ifdef METADATA_TESTING
216 // Checks the number of moves versus copies as the Datum goes to
217 // Data and then parceled and unparceled.
218 // The counters should increment each time a MoveCount gets copied or
219 // moved.
220 {
221 Data d2;
222 d2[MOVE_COUNT] = MoveCount(); // should be moved.
223
224 ASSERT_TRUE(1 >= d2[MOVE_COUNT].mMoveCount); // no more than one move.
225 ASSERT_EQ(0, d2[MOVE_COUNT].mCopyCount); // no copies
226
227 ByteString bs = byteStringFromData(d2);
228 Data d3 = dataFromByteString(bs);
229
230 ASSERT_EQ(0, d3[MOVE_COUNT].mCopyCount); // no copies
231 ASSERT_TRUE(2 >= d3[MOVE_COUNT].mMoveCount); // no more than 2 moves after parceling
232 }
233 #endif
234 }
235
TEST(metadata_tests,complex_data)236 TEST(metadata_tests, complex_data) {
237 Data small;
238 Data big;
239
240 small[MY_NAME_IS] = "abc";
241 #ifdef METADATA_TESTING
242 small[MOVE_COUNT] = MoveCount{};
243 #endif
244 big[TABLE] = small; // ONE COPY HERE of the MoveCount (embedded in small).
245
246 #ifdef METADATA_TESTING
247 big[VECTOR] = std::vector<Datum>{small, small};
248 big[PAIR] = std::make_pair<Datum, Datum>(small, small);
249 ASSERT_EQ(1, big[TABLE][MOVE_COUNT].mCopyCount); // one copy done for small.
250
251 big[FUNKY] = std::vector<std::vector<std::pair<std::string, short>>>{
252 {{"a", 1}, {"b", 2}},
253 {{"c", 3}, {"d", 4}},
254 };
255
256 // struct Arbitrary { int i0; std::vector<int> v1; std::pair<int, int> p2; };
257 big[ARBITRARY] = Arbitrary{0, {1, 2, 3}, {4, 5}};
258 #endif
259
260 // Try round-trip conversion to a ByteString.
261 ByteString bs = byteStringFromData(big);
262 Data data = dataFromByteString(bs);
263 #ifdef METADATA_TESTING
264 ASSERT_EQ((size_t)5, data.size());
265 #else
266 ASSERT_EQ((size_t)1, data.size());
267 #endif
268
269 // Nested tables make sense.
270 ASSERT_EQ("abc", data[TABLE][MY_NAME_IS]);
271
272 #ifdef METADATA_TESTING
273 // TODO: Maybe we don't need the vector or the pair.
274 ASSERT_EQ("abc", std::any_cast<Data>(data[VECTOR][1])[MY_NAME_IS]);
275 ASSERT_EQ("abc", std::any_cast<Data>(data[PAIR].first)[MY_NAME_IS]);
276 ASSERT_EQ(1, data[TABLE][MOVE_COUNT].mCopyCount); // no additional copies.
277
278 auto funky = data[FUNKY];
279 ASSERT_EQ("a", funky[0][0].first);
280 ASSERT_EQ(4, funky[1][1].second);
281
282 auto arbitrary = data[ARBITRARY];
283 ASSERT_EQ(0, arbitrary.i0);
284 ASSERT_EQ(2, arbitrary.v1[1]);
285 ASSERT_EQ(4, arbitrary.p2.first);
286 #endif
287 }
288
289 // DO NOT CHANGE THIS after R, but add a new test.
TEST(metadata_tests,compatibility_R)290 TEST(metadata_tests, compatibility_R) {
291 Data d;
292 d.emplace("i32", (int32_t)1);
293 d.emplace("i64", (int64_t)2);
294 d.emplace("float", (float)3.1f);
295 d.emplace("double", (double)4.11);
296 Data s;
297 s.emplace("string", "hello");
298 d.emplace("data", s);
299
300 ByteString bs = byteStringFromData(d);
301 ALOGD("%s", toString(bs).c_str());
302
303 // Since we use a map instead of a hashmap
304 // layout order of elements is precisely defined.
305 ByteString reference = {
306 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
307 0x64, 0x61, 0x74, 0x61, 0x06, 0x00, 0x00, 0x00,
308 0x1f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
309 0x06, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69,
310 0x6e, 0x67, 0x05, 0x00, 0x00, 0x00, 0x09, 0x00,
311 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x68, 0x65,
312 0x6c, 0x6c, 0x6f, 0x06, 0x00, 0x00, 0x00, 0x64,
313 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x04, 0x00, 0x00,
314 0x00, 0x08, 0x00, 0x00, 0x00, 0x71, 0x3d, 0x0a,
315 0xd7, 0xa3, 0x70, 0x10, 0x40, 0x05, 0x00, 0x00,
316 0x00, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x03, 0x00,
317 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x66, 0x66,
318 0x46, 0x40, 0x03, 0x00, 0x00, 0x00, 0x69, 0x33,
319 0x32, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
320 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
321 0x00, 0x69, 0x36, 0x34, 0x02, 0x00, 0x00, 0x00,
322 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
323 0x00, 0x00, 0x00, 0x00
324 };
325 ASSERT_EQ(reference, bs);
326
327 Data decoded = dataFromByteString(bs);
328
329 // TODO: data equality.
330 // ASSERT_EQ(decoded, d);
331
332 ASSERT_EQ(1, std::any_cast<int32_t>(decoded["i32"]));
333 ASSERT_EQ(2, std::any_cast<int64_t>(decoded["i64"]));
334 ASSERT_EQ(3.1f, std::any_cast<float>(decoded["float"]));
335 ASSERT_EQ(4.11, std::any_cast<double>(decoded["double"]));
336 Data decoded_s = std::any_cast<Data>(decoded["data"]);
337
338 ASSERT_EQ("hello", std::any_cast<std::string>(s["string"]));
339
340 {
341 ByteString unknownData = reference;
342 unknownData[12] = 0xff;
343 Data decoded2 = dataFromByteString(unknownData);
344 ASSERT_EQ((size_t)0, decoded2.size());
345
346 ByteStringUnknowns unknowns;
347 Data decoded3 = dataFromByteString(unknownData, &unknowns);
348 ASSERT_EQ((size_t)4, decoded3.size());
349 ASSERT_EQ((size_t)1, unknowns.size());
350 ASSERT_EQ((unsigned)0xff, unknowns[0]);
351 }
352
353 {
354 ByteString unknownDouble = reference;
355 ASSERT_EQ(0x4, unknownDouble[0x3d]);
356 unknownDouble[0x3d] = 0xfe;
357 Data decoded2 = dataFromByteString(unknownDouble);
358 ASSERT_EQ((size_t)0, decoded2.size());
359
360 ByteStringUnknowns unknowns;
361 Data decoded3 = dataFromByteString(unknownDouble, &unknowns);
362 ASSERT_EQ((size_t)4, decoded3.size());
363 ASSERT_EQ((size_t)1, unknowns.size());
364 ASSERT_EQ((unsigned)0xfe, unknowns[0]);
365 }
366 };
367
TEST(metadata_tests,bytestring_examples)368 TEST(metadata_tests, bytestring_examples) {
369 ByteString bs;
370
371 copyToByteString((int32_t)123, bs);
372 ALOGD("123 -> %s", toString(bs).c_str());
373 const ByteString ref1{ 0x7b, 0x00, 0x00, 0x00 };
374 ASSERT_EQ(ref1, bs);
375
376 bs.clear();
377 // for copyToByteString use std::string instead of char array.
378 copyToByteString(std::string("hi"), bs);
379 ALOGD("\"hi\" -> %s", toString(bs).c_str());
380 const ByteString ref2{ 0x02, 0x00, 0x00, 0x00, 0x68, 0x69 };
381 ASSERT_EQ(ref2, bs);
382
383 bs.clear();
384 Data d;
385 d.emplace("hello", "world");
386 d.emplace("value", (int32_t)1000);
387 copyToByteString(d, bs);
388 ALOGD("{{\"hello\", \"world\"}, {\"value\", 1000}} -> %s", toString(bs).c_str());
389 const ByteString ref3{
390 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
391 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x05, 0x00, 0x00,
392 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
393 0x00, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x05, 0x00,
394 0x00, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x01,
395 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe8,
396 0x03, 0x00, 0x00};
397 ASSERT_EQ(ref3, bs);
398 };
399
400 // Test C API
TEST(metadata_tests,c)401 TEST(metadata_tests, c) {
402 audio_metadata_t *metadata = audio_metadata_create();
403 Data d;
404 d.emplace("i32", (int32_t)1);
405 d.emplace("i64", (int64_t)2);
406 d.emplace("float", (float)3.1f);
407 d.emplace("double", (double)4.11);
408 Data s;
409 s.emplace("string", "hello");
410 d.emplace("data", s);
411
412 audio_metadata_put(metadata, "i32", (int32_t)1);
413 audio_metadata_put(metadata, "i64", (int64_t)2);
414 audio_metadata_put(metadata, "float", (float)3.1f);
415 audio_metadata_put(metadata, "double", (double)4.11);
416 audio_metadata_t *data = audio_metadata_create();
417 audio_metadata_put(data, "string", "hello");
418 audio_metadata_put(metadata, "data", data);
419 audio_metadata_destroy(data);
420
421 int32_t i32Val;
422 int64_t i64Val;
423 float floatVal;
424 double doubleVal;
425 char *strVal = nullptr;
426 audio_metadata_t *dataVal = nullptr;
427 ASSERT_EQ(0, audio_metadata_get(metadata, "i32", &i32Val));
428 ASSERT_EQ(1, i32Val);
429 ASSERT_EQ(0, audio_metadata_get(metadata, "i64", &i64Val));
430 ASSERT_EQ(2, i64Val);
431 ASSERT_EQ(0, audio_metadata_get(metadata, "float", &floatVal));
432 ASSERT_EQ(3.1f, floatVal);
433 ASSERT_EQ(0, audio_metadata_get(metadata, "double", &doubleVal));
434 ASSERT_EQ(4.11, doubleVal);
435 ASSERT_EQ(0, audio_metadata_get(metadata, "data", &dataVal));
436 ASSERT_NE(dataVal, nullptr);
437 ASSERT_EQ(0, audio_metadata_get(dataVal, "string", &strVal));
438 ASSERT_EQ(0, strcmp("hello", strVal));
439 free(strVal);
440 audio_metadata_destroy(dataVal);
441 dataVal = nullptr;
442 ASSERT_EQ(-ENOENT, audio_metadata_get(metadata, "non_exist_key", &i32Val));
443 audio_metadata_t *nullMetadata = nullptr;
444 ASSERT_EQ(-EINVAL, audio_metadata_get(nullMetadata, "i32", &i32Val));
445 char *nullKey = nullptr;
446 ASSERT_EQ(-EINVAL, audio_metadata_get(metadata, nullKey, &i32Val));
447 int *nullI32Val = nullptr;
448 ASSERT_EQ(-EINVAL, audio_metadata_get(metadata, "i32", nullI32Val));
449
450 uint8_t *bs = nullptr;
451 size_t length = byte_string_from_audio_metadata(metadata, &bs);
452 ASSERT_EQ(byteStringFromData(d).size(), ByteString(bs, length).size());
453 audio_metadata_t *metadataFromBs = audio_metadata_from_byte_string(bs, length);
454 free(bs);
455 bs = nullptr;
456 length = byte_string_from_audio_metadata(metadataFromBs, &bs);
457 ASSERT_EQ(byteStringFromData(d), ByteString(bs, length));
458 free(bs);
459 bs = nullptr;
460 audio_metadata_destroy(metadataFromBs);
461 ASSERT_EQ(-EINVAL, byte_string_from_audio_metadata(nullMetadata, &bs));
462 uint8_t **nullBs = nullptr;
463 ASSERT_EQ(-EINVAL, byte_string_from_audio_metadata(metadata, nullBs));
464
465 ASSERT_EQ(1, audio_metadata_erase(metadata, "data"));
466 audio_metadata_get(metadata, "data", dataVal);
467 ASSERT_EQ(nullptr, dataVal);
468 ASSERT_EQ(0, audio_metadata_erase(metadata, "data"));
469 ASSERT_EQ(-EINVAL, audio_metadata_erase(nullMetadata, "key"));
470 ASSERT_EQ(-EINVAL, audio_metadata_erase(metadata, nullKey));
471
472 audio_metadata_destroy(metadata);
473 };
474