• 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 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