1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "m3u8_unit_test.h"
16 #include "http_server_demo.h"
17 
18 #include <new>
19 #define LOCAL true
20 
21 using namespace OHOS;
22 using namespace OHOS::Media;
23 namespace OHOS::Media::Plugins::HttpPlugin {
24 using namespace testing::ext;
25 using namespace std;
26 constexpr uint32_t MAX_LOOP = 16;
27 std::unique_ptr<MediaAVCodec::HttpServerDemo> g_server = nullptr;
SetUpTestCase(void)28 void M3u8UnitTest::SetUpTestCase(void) {}
29 
TearDownTestCase(void)30 void M3u8UnitTest::TearDownTestCase(void) {}
31 
SetUp(void)32 void M3u8UnitTest::SetUp(void)
33 {
34     g_server = std::make_unique<MediaAVCodec::HttpServerDemo>();
35     g_server->StartServer();
36 }
37 
TearDown(void)38 void M3u8UnitTest::TearDown(void)
39 {
40     g_server->StopServer();
41     g_server = nullptr;
42 }
43 
44 HWTEST_F(M3u8UnitTest, Init_Tag_Updaters_Map_001, TestSize.Level1)
45 {
46     double duration = testM3u8->GetDuration();
47     bool isLive = testM3u8->IsLive();
48     EXPECT_GE(duration, 0.0);
49     EXPECT_EQ(isLive, false);
50 }
51 
52 HWTEST_F(M3u8UnitTest, is_live_001, TestSize.Level1)
53 {
54     EXPECT_EQ(testM3u8->GetDuration(), 0.0);
55 }
56 
57 HWTEST_F(M3u8UnitTest, ConstructorTest, TestSize.Level1)
58 {
59     M3U8 m3u8(testUri, testName);
60     // 检查 URI 和名称是否正确设置
61     ASSERT_EQ(m3u8.uri_, testUri);
62     ASSERT_EQ(m3u8.name_, testName);
63     // 这里可以添加更多的断言来检查初始化的状态
64 }
65 
66 // 测试 Update 方法
67 HWTEST_F(M3u8UnitTest, UpdateTest, TestSize.Level1)
68 {
69     M3U8 m3u8("http://example.com/test.m3u8", "TestPlaylist");
70     std::string testPlaylist = "#EXTM3U\n#EXT-X-TARGETDURATION:10\n...";
71 
72     // 测试有效的播放列表更新
73     EXPECT_TRUE(m3u8.Update(testPlaylist, true));
74 
75     // 测试当播放列表不变时的更新
76     EXPECT_TRUE(m3u8.Update(testPlaylist, true));
77 
78     // 测试无效的播放列表更新
79     EXPECT_FALSE(m3u8.Update("Invalid Playlist", true));
80 }
81 
82 HWTEST_F(M3u8UnitTest, UPDATE_FROM_TAGS_TEST, TestSize.Level1)
83 {
84     M3U8 m3u8("http://example.com/test.m3u8", "TestPlaylist");
85     //
86     std::list<std::shared_ptr<Tag>> tags;
87     m3u8.UpdateFromTags(tags);
88     EXPECT_TRUE(m3u8.bLive_);
89     m3u8.isDecryptAble_ = true;
90     m3u8.UpdateFromTags(tags);
91     //
92     EXPECT_TRUE(m3u8.bLive_);
93     EXPECT_EQ(m3u8.files_.size(), 0);
94     m3u8.isDecryptAble_ = false;
95     m3u8.UpdateFromTags(tags);
96 
97     //
98     EXPECT_TRUE(m3u8.bLive_);
99     EXPECT_EQ(m3u8.files_.size(), 0);
100 }
101 
102 HWTEST_F(M3u8UnitTest, TEST_CONSTRUCTOR_WITH_NULL_KEY_AND_IV, TestSize.Level1)
103 {
104     M3U8Fragment m3u8("http://example.com", 10.0, 1, false);
105     M3U8Fragment fragment(m3u8, nullptr, nullptr);
106     EXPECT_EQ(fragment.duration_, 10.0);
107     EXPECT_EQ(fragment.sequence_, 1);
108     EXPECT_EQ(fragment.discont_, false);
109     //
110 
111     for (int i = 0; i < static_cast<int>(MAX_LOOP); i++) {
112         EXPECT_NE(fragment.iv_[i], -1);
113         EXPECT_NE(fragment.key_[i], -1);
114     }
115 }
116 
117 HWTEST_F(M3u8UnitTest, TEST_CONSTRUCTOR_WITH_VALID_KEY_AND_IV, TestSize.Level1)
118 {
119     M3U8Fragment m3u8("http://example.com", 10.0, 1, false);
120     uint8_t key[MAX_LOOP] = {1, 2, 3, 4, 5};
121     uint8_t iv[MAX_LOOP] = {6, 7, 8, 9, 10};
122     M3U8Fragment fragment(m3u8, key, iv);
123     EXPECT_EQ(fragment.uri_, "http://example.com");
124     EXPECT_EQ(fragment.duration_, 10.0);
125     EXPECT_EQ(fragment.sequence_, 1);
126     EXPECT_EQ(fragment.discont_, false);
127     //
128     for (int i = 0; i < 5; i++) {
129         EXPECT_EQ(fragment.iv_[i], iv[i]);
130     }
131 }
132 
133 HWTEST_F(M3u8UnitTest, TEST_CONSTRUCTOR, TestSize.Level1)
134 {
135     M3U8 m3u8("http://example.com/test.m3u8", "Test M3U8");
136 
137     // check url
138     EXPECT_EQ(m3u8.uri_, "http://example.com/test.m3u8");
139 
140     //check name
141     EXPECT_EQ(m3u8.name_, "Test M3U8");
142 
143     //check updaters map
144     EXPECT_FALSE(m3u8.tagUpdatersMap_.empty());
145 }
146 
147 HWTEST_F(M3u8UnitTest, TEST_EMPTY_URI, TestSize.Level1)
148 {
149     M3U8 m3u8("", "Test M3U8");
150 
151     // check url
152     EXPECT_EQ(m3u8.uri_, "");
153 
154     //check name
155     EXPECT_EQ(m3u8.name_, "Test M3U8");
156 
157     //check updaters map
158     EXPECT_FALSE(m3u8.tagUpdatersMap_.empty());
159 }
160 
161 HWTEST_F(M3u8UnitTest, TEST_EMPTY_NAME, TestSize.Level1)
162 {
163     M3U8 m3u8("http://example.com/test.m3u8", "");
164 
165     // check url
166     EXPECT_EQ(m3u8.uri_, "http://example.com/test.m3u8");
167 
168     //check name
169     EXPECT_EQ(m3u8.name_, "");
170 
171     //check updaters map
172     EXPECT_FALSE(m3u8.tagUpdatersMap_.empty());
173 }
174 
175 // test get ext
176 HWTEST_F(M3u8UnitTest, GET_EXT_INF_TEST, TestSize.Level1)
177 {
178     M3U8 m3u8("http://example.com/test.m3u8", "");
179     auto tag = std::make_shared<AttributesTag>(HlsTag::EXTXDISCONTINUITY, "123");
180     auto attr1 =  std::make_shared<Attribute>("DURATION", "3.5");
181     tag->AddAttribute(attr1);
182     double duration;
183     m3u8.GetExtInf(tag, duration);
184     //check name
185     EXPECT_DOUBLE_EQ(3.5, duration);
186 }
187 
188 HWTEST_F(M3u8UnitTest, PARSE_KEY_METHOD_ATTRIBUTE, TestSize.Level1)
189 {
190     M3U8 m3u8("http://example.com/test.m3u8", "");
191     auto tag = std::make_shared<AttributesTag>(HlsTag::EXTXDISCONTINUITY, "123");
192     auto attr1 =  std::make_shared<Attribute>("METHOD", "AES-128");
193     tag->AddAttribute(attr1);
194     m3u8.ParseKey(tag);
195     EXPECT_EQ(*m3u8.method_, "AES-128");
196 }
197 
198 HWTEST_F(M3u8UnitTest, PARSE_KEY_URI_ATTRIBUTE, TestSize.Level1)
199 {
200     M3U8 m3u8("http://example.com/test.m3u8", "");
201     auto tag = std::make_shared<AttributesTag>(HlsTag::EXTXDISCONTINUITY, "123");
202     auto attr1 =  std::make_shared<Attribute>("URI", "http://example.com/key.bin");
203     tag->AddAttribute(attr1);
204     m3u8.ParseKey(tag);
205     EXPECT_EQ(*m3u8.keyUri_, "http://example.com/key.bin");
206 }
207 
208 HWTEST_F(M3u8UnitTest, PARSE_KEY_IV_ATTRIBUTE, TestSize.Level1)
209 {
210     M3U8 m3u8("http://example.com/test.m3u8", "");
211     auto tag = std::make_shared<AttributesTag>(HlsTag::EXTXDISCONTINUITY, "123");
212     auto attr1 =  std::make_shared<Attribute>("IV", "0x12345678");
213     tag->AddAttribute(attr1);
214     m3u8.ParseKey(tag);
215     uint8_t vec[4] {0x12, 0x34, 0x56, 0x78};
216     EXPECT_NE(m3u8.iv_, vec);
217 }
218 
219 HWTEST_F(M3u8UnitTest, PARSE_KEY_NO_ATTRIBUTE, TestSize.Level1)
220 {
221     M3U8 m3u8("http://example.com/test.m3u8", "");
222     auto tag = std::make_shared<AttributesTag>(HlsTag::EXTXDISCONTINUITY, "123");
223     m3u8.ParseKey(tag);
224     EXPECT_EQ(m3u8.method_, nullptr);
225     EXPECT_EQ(m3u8.keyUri_, nullptr);
226     uint8_t vec[4] {0, 0, 0, 0};
227     EXPECT_NE(m3u8.iv_, vec);
228 }
229 
230 HWTEST_F(M3u8UnitTest, SAVE_DATA_VALID_DATA, TestSize.Level1)
231 {
232     M3U8 m3u8("http://example.com/test.m3u8", "");
233     uint8_t data[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
234     uint32_t len = 10;
235 
236     bool result = m3u8.SaveData(data, len);
237 
238     EXPECT_TRUE(result);
239     EXPECT_EQ(m3u8.keyLen_, len);
240     EXPECT_TRUE(m3u8.isDecryptKeyReady_);
241 }
242 
243 HWTEST_F(M3u8UnitTest, SAVE_DATA_INVALID_DATA, TestSize.Level1)
244 {
245     M3U8 m3u8("http://example.com/test.m3u8", "");
246     uint8_t data[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
247     uint32_t len = 10;
248 
249     bool result = m3u8.SaveData(data, len);
250 
251     EXPECT_TRUE(result);
252     EXPECT_EQ(m3u8.keyLen_, len);
253     EXPECT_TRUE(m3u8.isDecryptKeyReady_);
254 }
255 
256 HWTEST_F(M3u8UnitTest, SAVE_DATA_EXVEEDS_MAX_LOOP, TestSize.Level1)
257 {
258     M3U8 m3u8("http://example.com/test.m3u8", "");
259     uint8_t data[MAX_LOOP + 1];
260     uint32_t len = MAX_LOOP + 1;
261 
262     bool result = m3u8.SaveData(data, len);
263 
264     EXPECT_FALSE(result);
265     EXPECT_EQ(m3u8.keyLen_, 0);
266     EXPECT_FALSE(m3u8.isDecryptKeyReady_);
267 }
268 
269 HWTEST_F(M3u8UnitTest, SET_DRM_INFO_NULL_KEY_URI, TestSize.Level1)
270 {
271     M3U8 m3u8("http://example.com/test.m3u8", "");
272     std::multimap<std::string, std::vector<uint8_t>> drmInfo;
273     EXPECT_FALSE(m3u8.SetDrmInfo(drmInfo));
274 }
275 
276 HWTEST_F(M3u8UnitTest, SET_DRM_INFO_INVALID_KEY_URI, TestSize.Level1)
277 {
278     M3U8 m3u8("http://example.com/test.m3u8", "");
279     m3u8.keyUri_ = std::make_shared<std::string>("invalid");
280     std::multimap<std::string, std::vector<uint8_t>> drmInfo;
281     EXPECT_FALSE(m3u8.SetDrmInfo(drmInfo));
282 }
283 
284 HWTEST_F(M3u8UnitTest, SET_DRM_INFO_VALID_KEY_URI, TestSize.Level1)
285 {
286     M3U8 m3u8("http://example.com/test.m3u8", "");
287     m3u8.keyUri_ = std::make_shared<std::string>("base64,valid");
288     std::multimap<std::string, std::vector<uint8_t>> drmInfo;
289     EXPECT_FALSE(m3u8.SetDrmInfo(drmInfo));
290 }
291 
292 HWTEST_F(M3u8UnitTest, SET_DRM_INFO_PSSH_SIZE_SMALL, TestSize.Level1)
293 {
294     M3U8 m3u8("http://example.com/test.m3u8", "");
295     m3u8.keyUri_ = std::make_shared<std::string>("base64,valid");
296     std::multimap<std::string, std::vector<uint8_t>> drmInfo;
297     EXPECT_FALSE(m3u8.SetDrmInfo(drmInfo));
298 }
299 
300 HWTEST_F(M3u8UnitTest, SET_DRM_INFO_PSSH_SIZE_VALID, TestSize.Level1)
301 {
302     M3U8 m3u8("http://example.com/test.m3u8", "");
303     m3u8.keyUri_ = std::make_shared<std::string>("base64,valid");
304     std::multimap<std::string, std::vector<uint8_t>> drmInfo;
305     EXPECT_FALSE(m3u8.SetDrmInfo(drmInfo));
306 }
307 
308 HWTEST_F(M3u8UnitTest, SET_DRM_INFOS, TestSize.Level1)
309 {
310     M3U8 m3u8("http://example.com/test.m3u8", "");
311     std::multimap<std::string, std::vector<uint8_t>> drmInfo;
312 
313     // test no DRM info
314     m3u8.StoreDrmInfos(drmInfo);
315     EXPECT_TRUE(m3u8.localDrmInfos_.empty());
316 
317     // test new drm info
318     std::vector<uint8_t> pssh = {1, 2, 3, 4, 5};
319     drmInfo.insert(std::make_pair("uuid1", pssh));
320     m3u8.StoreDrmInfos(drmInfo);
321     EXPECT_EQ(1, m3u8.localDrmInfos_.size());
322     EXPECT_EQ(pssh, m3u8.localDrmInfos_.begin()->second);
323 
324     // test existed drm info
325     drmInfo.insert(std::make_pair("uuid1", pssh));
326     m3u8.StoreDrmInfos(drmInfo);
327     EXPECT_EQ(1, m3u8.localDrmInfos_.size());
328     EXPECT_EQ(pssh, m3u8.localDrmInfos_.begin()->second);
329 
330     // test diff drm info
331     std::vector<uint8_t> pssh2 = {6, 7, 8, 9, 10};
332     drmInfo.insert(std::make_pair("uuid1", pssh2));
333     m3u8.StoreDrmInfos(drmInfo);
334     EXPECT_EQ(2, m3u8.localDrmInfos_.size());
335     EXPECT_EQ(pssh2, (++m3u8.localDrmInfos_.begin())->second);
336 }
337 
338 HWTEST_F(M3u8UnitTest, TestPlaylistStartWithEXTM3U, TestSize.Level1)
339 {
340     M3U8MasterPlaylist playlist("#EXTM3U", "uri");
341     EXPECT_EQ(playlist.playList_, "#EXTM3U");
342 }
343 
344 HWTEST_F(M3u8UnitTest, TestPlaylistNotStartWithEXTM3U, TestSize.Level1)
345 {
346     M3U8MasterPlaylist playlist("playlist", "uri");
347     EXPECT_EQ(playlist.playList_, "playlist");
348 }
349 
350 HWTEST_F(M3u8UnitTest, TestPlaylistContainsEXTINF, TestSize.Level1)
351 {
352     M3U8MasterPlaylist playlist("\n#EXTM3U:", "uri");
353     EXPECT_EQ(playlist.playList_, "\n#EXTM3U:");
354 }
355 
356 HWTEST_F(M3u8UnitTest, TestPlaylistNotContainsEXTINF, TestSize.Level1)
357 {
358     M3U8MasterPlaylist playlist("playlist", "uri");
359     EXPECT_EQ(playlist.playList_, "playlist");
360 }
361 
362 HWTEST_F(M3u8UnitTest, UpdateMediaPlaylistTest, TestSize.Level1)
363 {
364     M3U8MasterPlaylist playlist("playlist", "uri");
365     playlist.UpdateMediaPlaylist();
366 
367     // test variants contains new stream
368     EXPECT_EQ(1, playlist.variants_.size());
369 
370     // test defaultVariant_ point new stream
371     EXPECT_EQ(playlist.variants_.front(), playlist.defaultVariant_);
372 
373     // test duration updated
374     EXPECT_EQ(0, playlist.duration_);
375 
376     // test bLive_ updated
377     EXPECT_FALSE(playlist.bLive_);
378 
379     // isSimple updated
380     EXPECT_TRUE(playlist.isSimple_);
381 }
382 
383 HWTEST_F(M3u8UnitTest, UpdateMasterPlaylist_default, TestSize.Level1)
384 {
385     M3U8MasterPlaylist playlist("test", "http://test.com/test");
386     playlist.UpdateMediaPlaylist();
387     EXPECT_EQ(playlist.defaultVariant_, playlist.variants_.front());
388 }
389 // 测试 IsLive 方法
390 HWTEST_F(M3u8UnitTest, IS_LIVE_TEST, TestSize.Level1)
391 {
392     M3U8 m3u8(testUri, "LivePlaylist");
393     EXPECT_FALSE(m3u8.IsLive());
394 }
395 
396 // 测试 M3U8Fragment 构造函数
397 HWTEST_F(M3u8UnitTest, M3U8FragmentConstructorTest, TestSize.Level1)
398 {
399     double testDuration = 10.0;
400     int testSequence = 1;
401     bool testDiscont = false;
402     M3U8Fragment fragment(testUri, testDuration, testSequence, testDiscont);
403     ASSERT_EQ(fragment.uri_, testUri);
404     ASSERT_DOUBLE_EQ(fragment.duration_, testDuration);
405     ASSERT_EQ(fragment.sequence_, testSequence);
406     ASSERT_EQ(fragment.discont_, testDiscont);
407 }
408 
409 HWTEST_F(M3u8UnitTest, ParseKeyTest, TestSize.Level1)
410 {
411     auto attributesTag = std::make_shared<AttributesTag>(HlsTag::EXTINF, "1234");
412     auto uriAttr = std::make_shared<Attribute>("METHOD", "\"SAMPLE-AES\"");
413     attributesTag->AddAttribute(uriAttr);
414     auto uriAttr1 = std::make_shared<Attribute>("URI", "\"https://example.com/key\"");
415     attributesTag->AddAttribute(uriAttr1);
416     auto uriAttr2 = std::make_shared<Attribute>("IV", "\"0123456789ABCDEF\"");
417     attributesTag->AddAttribute(uriAttr2);
418 
419     testM3u8->ParseKey(attributesTag);
420 
421     // 验证 method_, keyUri_ 和 iv_ 是否正确设置
422     auto testStr = std::make_shared<std::string>("SAMPLE-AES");
423     ASSERT_EQ(*(testM3u8->method_), *testStr);
424     auto testStr1 = std::make_shared<std::string>("https://example.com/key");
425     ASSERT_EQ(*(testM3u8->keyUri_), *testStr1);
426 }
427 
428 HWTEST_F(M3u8UnitTest, SaveDataTest, TestSize.Level1)
429 {
430     uint8_t data[] = {0x01, 0x02, 0x03, 0x04};
431     bool result = testM3u8->SaveData(data, sizeof(data));
432     ASSERT_TRUE(result);
433 
434     // 验证 key_ 成员变量中的数据是否与传入的数据一致
435     for (size_t i = 0; i < sizeof(data); ++i) {
436         ASSERT_EQ(testM3u8->key_[i], data[i]);
437     }
438 
439     // 验证 keyLen_ 是否被正确设置
440     ASSERT_EQ(testM3u8->keyLen_, sizeof(data));
441 }
442 
443 HWTEST_F(M3u8UnitTest, SetDrmInfoTest, TestSize.Level1)
444 {
445     std::multimap<std::string, std::vector<uint8_t>> drmInfo;
446     // 设置 keyUri_ 为有效的 base64 编码字符串
447     testM3u8->keyUri_ = std::make_shared<std::string>("base64,VALID_BASE64_ENCODED_STRING");
448 
449     bool result = testM3u8->SetDrmInfo(drmInfo);
450     ASSERT_FALSE(result);
451     ASSERT_TRUE(drmInfo.empty());
452     // 验证 drmInfo 是否包含预期的 UUID 和解码后的数据
453 }
454 
455 HWTEST_F(M3u8UnitTest, StoreDrmInfosTest, TestSize.Level1)
456 {
457     std::multimap<std::string, std::vector<uint8_t>> drmInfo = { { "uuid1", { 1, 2, 3 } }, { "uuid2", { 4, 5, 6 } } };
458     testM3u8->StoreDrmInfos(drmInfo);
459     // 验证 localDrmInfos_ 是否正确包含了 drmInfo 的内容
460     for (const auto &item : drmInfo) {
461         auto range = testM3u8->localDrmInfos_.equal_range(item.first);
462         ASSERT_NE(range.first, testM3u8->localDrmInfos_.end());
463         ASSERT_EQ(range.first->second, item.second);
464     }
465 }
466 
467 HWTEST_F(M3u8UnitTest, ProcessDrmInfosTest, TestSize.Level1)
468 {
469     testM3u8->keyUri_ = std::make_shared<std::string>("base64,VALID_BASE64_ENCODED_STRING");
470     testM3u8->ProcessDrmInfos();
471     // 验证 isDecryptAble_ 是否根据 DRM 信息的处理结果正确设置
472     ASSERT_EQ(testM3u8->isDecryptAble_, testM3u8->localDrmInfos_.empty());
473 }
474 
475 }