1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_FORMATS_HLS_PLAYLIST_TEST_BUILDER_H_
#define MEDIA_FORMATS_HLS_PLAYLIST_TEST_BUILDER_H_
#include <type_traits>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/location.h"
#include "media/formats/hls/playlist.h"
#include "media/formats/hls/source_string.h"
#include "media/formats/hls/tags.h"
#include "media/formats/hls/types.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace media::hls {
// Base helper for building playlist test cases. This should be extended by a
// playlist-type specific builder with additional methods for creating
// assertions specific to that type of playlist, and parameterized by the type
// of playlist.
template <typename PlaylistT>
class PlaylistTestBuilder {
public:
static_assert(std::is_base_of_v<Playlist, PlaylistT>);
// Sets the URI for the playlist being built.
void SetUri(GURL uri) { uri_ = std::move(uri); }
// Sets the expected version for the playlist being built.
void SetVersion(types::DecimalInteger version) { version_ = version; }
// Appends fragments of text to the playlist, without a trailing newline.
template <typename... T>
void Append(base::StringPiece text1, T&&... rem) {
for (auto text : {text1, base::StringPiece(rem)...}) {
source_.append(text.data(), text.size());
}
}
// Appends fragments of text to the playlist, followed by a newline.
template <typename... T>
void AppendLine(base::StringPiece part1, T&&... rem) {
this->Append(part1, std::forward<T>(rem)..., "\n");
}
// Adds a new expectation for the playlist, which will be checked during
// `ExpectOk`.
template <typename Fn, typename Arg>
void ExpectPlaylist(Fn fn,
Arg arg,
base::Location location = base::Location::Current()) {
playlist_expectations_.push_back(base::BindRepeating(
[](Fn fn, Arg arg, const base::Location& from,
const PlaylistT& playlist) { fn(arg, from, playlist); },
std::move(fn), std::move(arg), std::move(location)));
}
protected:
// Attempts to parse the playlist as-is, checking for the given
// error code.
template <typename... Args>
void ExpectError(ParseStatusCode code,
const base::Location& from,
Args&&... args) const {
auto result =
PlaylistT::Parse(source_, uri_, version_, std::forward<Args>(args)...);
ASSERT_TRUE(result.has_error()) << from.ToString();
auto actual_code = std::move(result).error().code();
EXPECT_EQ(actual_code, code)
<< "Error: " << ParseStatusCodeToString(actual_code) << "\n"
<< "Expected Error: " << ParseStatusCodeToString(code) << "\n"
<< from.ToString();
}
// Attempts to parse the playlist as-is, checking all playlist and segment
// expectations.
template <typename... Args>
void ExpectOk(const base::Location& from, Args&&... args) const {
auto result =
PlaylistT::Parse(source_, uri_, version_, std::forward<Args>(args)...);
ASSERT_TRUE(result.has_value())
<< "Error: "
<< ParseStatusCodeToString(std::move(result).error().code()) << "\n"
<< from.ToString();
auto playlist = std::move(result).value();
// Ensure that playlist has expected version
EXPECT_EQ(playlist.GetVersion(), version_) << from.ToString();
for (const auto& expectation : playlist_expectations_) {
expectation.Run(playlist);
}
this->VerifyExpectations(playlist, from);
}
private:
virtual void VerifyExpectations(const PlaylistT&,
const base::Location& from) const = 0;
std::vector<base::RepeatingCallback<void(const PlaylistT&)>>
playlist_expectations_;
GURL uri_ = GURL("http://localhost/playlist.m3u8");
types::DecimalInteger version_ = Playlist::kDefaultVersion;
std::string source_;
};
// Checks the playlist's `AreSegmentsIndependent` property against the given
// value.
inline void HasIndependentSegments(bool value,
const base::Location& from,
const Playlist& playlist) {
EXPECT_EQ(playlist.AreSegmentsIndependent(), value) << from.ToString();
}
} // namespace media::hls
#endif // MEDIA_FORMATS_HLS_PLAYLIST_TEST_BUILDER_H_
|