• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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