xref: /aosp_15_r20/frameworks/av/media/module/id3/test/ID3Test.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1 /*
2  * Copyright (C) 2019 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 "ID3Test"
19 #include <utils/Log.h>
20 
21 #include <ctype.h>
22 #include <string>
23 #include <sys/stat.h>
24 #include <datasource/FileSource.h>
25 
26 #include <media/stagefright/foundation/hexdump.h>
27 #include <media/MediaExtractorPluginHelper.h>
28 #include <ID3.h>
29 
30 #include "ID3TestEnvironment.h"
31 
32 
33 using namespace android;
34 
35 static ID3TestEnvironment *gEnv = nullptr;
36 
37 class ID3tagTest : public ::testing::TestWithParam<string> {};
38 class ID3versionTest : public ::testing::TestWithParam<pair<string, int>> {};
39 class ID3textTagTest : public ::testing::TestWithParam<pair<string, int>> {};
40 class ID3albumArtTest : public ::testing::TestWithParam<pair<string, bool>> {};
41 class ID3multiAlbumArtTest : public ::testing::TestWithParam<pair<string, int>> {};
42 
TEST_P(ID3tagTest,TagTest)43 TEST_P(ID3tagTest, TagTest) {
44     string path = gEnv->getRes() + GetParam();
45     ALOGV(" =====   TagTest for %s", path.c_str());
46     sp<FileSource> file = new FileSource(path.c_str());
47     ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
48     DataSourceHelper helper(file->wrap());
49     ID3 tag(&helper);
50     ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
51 
52     ID3::Iterator it(tag, nullptr);
53     while (!it.done()) {
54         String8 id;
55         it.getID(&id);
56         ASSERT_GT(id.length(), 0) << "Found an ID3 tag of 0 size";
57         ALOGV("Found ID tag: %s\n", String8(id).c_str());
58         it.next();
59     }
60 }
61 
TEST_P(ID3versionTest,VersionTest)62 TEST_P(ID3versionTest, VersionTest) {
63     int versionNumber = GetParam().second;
64     string path = gEnv->getRes() + GetParam().first;
65     ALOGV(" =====   VersionTest for %s", path.c_str());
66     sp<android::FileSource> file = new FileSource(path.c_str());
67     ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
68 
69     DataSourceHelper helper(file->wrap());
70     ID3 tag(&helper);
71     ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
72     ASSERT_EQ(tag.version(), versionNumber)
73             << "Found version: " << tag.version() << " Expected version: " << versionNumber;
74 }
75 
TEST_P(ID3textTagTest,TextTagTest)76 TEST_P(ID3textTagTest, TextTagTest) {
77     int numTextFrames = GetParam().second;
78     string path = gEnv->getRes() + GetParam().first;
79     ALOGV(" =====   TextTagTest for %s", path.c_str());
80     sp<android::FileSource> file = new FileSource(path.c_str());
81     ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
82 
83     DataSourceHelper helper(file->wrap());
84     ID3 tag(&helper);
85     ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
86     int countTextFrames = 0;
87     ID3::Iterator it(tag, nullptr);
88     if (tag.version() != ID3::ID3_V1 && tag.version() != ID3::ID3_V1_1) {
89         while (!it.done()) {
90             String8 id;
91             it.getID(&id);
92             ASSERT_GT(id.length(), 0) << "Found an ID3 tag of 0 size";
93             if (id[0] == 'T') {
94                 String8 text;
95                 countTextFrames++;
96                 it.getString(&text);
97                 ALOGV("Found text frame %s : %s \n", id.c_str(), text.c_str());
98             }
99             it.next();
100         }
101     } else {
102         while (!it.done()) {
103             String8 id;
104             String8 text;
105             it.getID(&id);
106             ASSERT_GT(id.length(), 0) << "Found an ID3 tag of 0 size";
107             it.getString(&text);
108             // if the tag has a value
109             if (strcmp(text.c_str(), "")) {
110                 countTextFrames++;
111                 ALOGV("ID: %s\n", id.c_str());
112                 ALOGV("Text string: %s\n", text.c_str());
113             }
114             it.next();
115         }
116     }
117     ASSERT_EQ(countTextFrames, numTextFrames)
118             << "Expected " << numTextFrames << " text frames, found " << countTextFrames;
119 }
120 
TEST_P(ID3albumArtTest,AlbumArtTest)121 TEST_P(ID3albumArtTest, AlbumArtTest) {
122     bool albumArtPresent = GetParam().second;
123     string path = gEnv->getRes() + GetParam().first;
124     ALOGV(" =====   AlbumArt for %s", path.c_str());
125     sp<android::FileSource> file = new FileSource(path.c_str());
126     ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
127 
128     DataSourceHelper helper(file->wrap());
129     ID3 tag(&helper);
130     ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
131     size_t dataSize;
132     String8 mime;
133     const void *data = tag.getAlbumArt(&dataSize, &mime);
134 
135     if (albumArtPresent) {
136         if (data) {
137             ALOGV("Found album art: size = %zu mime = %s \n", dataSize, mime.c_str());
138         }
139         ASSERT_NE(data, nullptr) << "Expected album art, found none! " << path;
140     } else {
141         ASSERT_EQ(data, nullptr) << "Found album art when expected none!";
142     }
143 
144 #if (LOG_NDEBUG == 0)
145     hexdump(data, dataSize > 128 ? 128 : dataSize);
146 #endif
147 }
148 
TEST_P(ID3multiAlbumArtTest,MultiAlbumArtTest)149 TEST_P(ID3multiAlbumArtTest, MultiAlbumArtTest) {
150     int numAlbumArt = GetParam().second;
151     string path = gEnv->getRes() + GetParam().first;
152     sp<android::FileSource> file = new FileSource(path.c_str());
153     ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
154 
155     DataSourceHelper helper(file->wrap());
156     ID3 tag(&helper);
157     ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
158     int count = 0;
159     ID3::Iterator it(tag, nullptr);
160     while (!it.done()) {
161         String8 id;
162         it.getID(&id);
163         ASSERT_GT(id.length(), 0) << "Found an ID3 tag of 0 size";
164         // Check if the tag is an "APIC/PIC" tag.
165         if (String8(id) == "APIC" || String8(id) == "PIC") {
166             count++;
167             size_t dataSize;
168             String8 mime;
169             const void *data = tag.getAlbumArt(&dataSize, &mime);
170             if (data) {
171                 ALOGV("Found album art: size = %zu mime = %s \n", dataSize, mime.c_str());
172 #if (LOG_NDEBUG == 0)
173                 hexdump(data, dataSize > 128 ? 128 : dataSize);
174 #endif
175             }
176             ASSERT_NE(data, nullptr) << "Expected album art, found none! " << path;
177         }
178         it.next();
179     }
180     ASSERT_EQ(count, numAlbumArt) << "Found " << count << " album arts, expected " << numAlbumArt
181                                   << " album arts! \n";
182 }
183 
184 // we have a test asset with large album art -- which is larger than our 3M cap
185 // that we inserted intentionally in the ID3 parsing routine.
186 // Rather than have it fail all the time, we have wrapped it under an #ifdef
187 // so that the tests will pass.
188 #undef  TEST_LARGE
189 
190 
191 // it appears that bbb_2sec_v24_unsynchronizedAllFrames.mp3 is not a legal file,
192 // so we've commented it out of the list of files to be tested
193 //
194 
195 INSTANTIATE_TEST_SUITE_P(id3TestAll, ID3tagTest,
196                          ::testing::Values("bbb_1sec_v23.mp3",
197                                            "bbb_1sec_1_image.mp3",
198                                            "bbb_1sec_2_image.mp3",
199                                            "bbb_2sec_v24.mp3",
200                                            "bbb_2sec_1_image.mp3",
201                                            "bbb_2sec_2_image.mp3",
202                                            "bbb_2sec_largeSize.mp3",
203                                            "bbb_1sec_v23_3tags.mp3",
204                                            "bbb_1sec_v1_5tags.mp3",
205                                            "bbb_2sec_v24_unsynchronizedOneFrame.mp3",
206                                            "idv24_unsynchronized.mp3"));
207 
208 INSTANTIATE_TEST_SUITE_P(
209         id3TestAll, ID3versionTest,
210         ::testing::Values(make_pair("bbb_1sec_v23.mp3", ID3::ID3_V2_3),
211                           make_pair("bbb_1sec_1_image.mp3", ID3::ID3_V2_3),
212                           make_pair("bbb_1sec_2_image.mp3", ID3::ID3_V2_3),
213                           make_pair("bbb_2sec_v24.mp3", ID3::ID3_V2_4),
214                           make_pair("bbb_2sec_1_image.mp3", ID3::ID3_V2_4),
215                           make_pair("bbb_2sec_2_image.mp3", ID3::ID3_V2_4),
216 #if TEST_LARGE
217                           make_pair("bbb_2sec_largeSize.mp3", ID3::ID3_V2_4), // FAIL
218 #endif
219                           make_pair("bbb_1sec_v23_3tags.mp3", ID3::ID3_V2_3),
220                           make_pair("bbb_1sec_v1_5tags.mp3", ID3::ID3_V1_1),
221                           make_pair("bbb_1sec_v1_3tags.mp3", ID3::ID3_V1_1),
222                           make_pair("bbb_2sec_v24_unsynchronizedOneFrame.mp3", ID3::ID3_V2_4),
223                           make_pair("idv24_unsynchronized.mp3", ID3::ID3_V2_4)));
224 
225 INSTANTIATE_TEST_SUITE_P(
226         id3TestAll, ID3textTagTest,
227         ::testing::Values(
228                 make_pair("bbb_1sec_v23.mp3", 1),
229                 make_pair("bbb_1sec_1_image.mp3", 1),
230                 make_pair("bbb_1sec_2_image.mp3", 1),
231                 make_pair("bbb_2sec_v24.mp3", 1),
232                 make_pair("bbb_2sec_1_image.mp3", 1),
233                 make_pair("bbb_2sec_2_image.mp3", 1),
234 #if TEST_LARGE
235                 make_pair("bbb_2sec_largeSize.mp3", 1), // FAIL
236 #endif
237                 make_pair("bbb_1sec_v23_3tags.mp3", 3),
238                 make_pair("bbb_1sec_v1_5tags.mp3", 5),
239                 make_pair("bbb_1sec_v1_3tags.mp3", 3),
240                 make_pair("bbb_2sec_v24_unsynchronizedOneFrame.mp3", 3)
241                 ));
242 
243 INSTANTIATE_TEST_SUITE_P(id3TestAll, ID3albumArtTest,
244                          ::testing::Values(make_pair("bbb_1sec_v23.mp3", false),
245                                            make_pair("bbb_1sec_1_image.mp3", true),
246                                            make_pair("bbb_1sec_2_image.mp3", true),
247                                            make_pair("bbb_2sec_v24.mp3", false),
248                                            make_pair("bbb_2sec_1_image.mp3", true),
249                                            make_pair("bbb_2sec_2_image.mp3", true),
250 #if TEST_LARGE
251                                            make_pair("bbb_2sec_largeSize.mp3", true), // FAIL
252 #endif
253                                            make_pair("bbb_1sec_v1_5tags.mp3", false),
254                                            make_pair("idv24_unsynchronized.mp3", true)
255                                            ));
256 
257 INSTANTIATE_TEST_SUITE_P(id3TestAll, ID3multiAlbumArtTest,
258                          ::testing::Values(make_pair("bbb_1sec_v23.mp3", 0),
259                                            make_pair("bbb_2sec_v24.mp3", 0),
260 #if TEST_LARGE
261                                            make_pair("bbb_2sec_largeSize.mp3", 3), // FAIL
262 #endif
263                                            make_pair("bbb_1sec_1_image.mp3", 1),
264                                            make_pair("bbb_2sec_1_image.mp3", 1),
265                                            make_pair("bbb_1sec_2_image.mp3", 2),
266                                            make_pair("bbb_2sec_2_image.mp3", 2)
267                                            ));
268 
main(int argc,char ** argv)269 int main(int argc, char **argv) {
270     gEnv = new ID3TestEnvironment();
271     ::testing::AddGlobalTestEnvironment(gEnv);
272     ::testing::InitGoogleTest(&argc, argv);
273     int status = gEnv->initFromOptions(argc, argv);
274     if (status == 0) {
275         status = RUN_ALL_TESTS();
276         ALOGI("ID3 Test result = %d\n", status);
277     }
278     return status;
279 }
280