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