1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/formats/webm/cluster_builder.h"
6 #include "media/formats/webm/webm_constants.h"
7 #include "media/formats/webm/webm_parser.h"
8 #include "testing/gmock/include/gmock/gmock.h"
9 #include "testing/gtest/include/gtest/gtest.h"
11 using ::testing::InSequence
;
12 using ::testing::Return
;
13 using ::testing::ReturnNull
;
14 using ::testing::StrictMock
;
19 enum { kBlockCount
= 5 };
21 class MockWebMParserClient
: public WebMParserClient
{
23 virtual ~MockWebMParserClient() {}
25 // WebMParserClient methods.
26 MOCK_METHOD1(OnListStart
, WebMParserClient
*(int));
27 MOCK_METHOD1(OnListEnd
, bool(int));
28 MOCK_METHOD2(OnUInt
, bool(int, int64
));
29 MOCK_METHOD2(OnFloat
, bool(int, double));
30 MOCK_METHOD3(OnBinary
, bool(int, const uint8
*, int));
31 MOCK_METHOD2(OnString
, bool(int, const std::string
&));
34 class WebMParserTest
: public testing::Test
{
36 StrictMock
<MockWebMParserClient
> client_
;
39 static scoped_ptr
<Cluster
> CreateCluster(int block_count
) {
41 cb
.SetClusterTimecode(0);
43 for (int i
= 0; i
< block_count
; i
++) {
44 uint8 data
[] = { 0x00 };
45 cb
.AddSimpleBlock(0, i
, 0, data
, sizeof(data
));
51 static void CreateClusterExpectations(int block_count
,
52 bool is_complete_cluster
,
53 MockWebMParserClient
* client
) {
56 EXPECT_CALL(*client
, OnListStart(kWebMIdCluster
)).WillOnce(Return(client
));
57 EXPECT_CALL(*client
, OnUInt(kWebMIdTimecode
, 0))
58 .WillOnce(Return(true));
60 for (int i
= 0; i
< block_count
; i
++) {
61 EXPECT_CALL(*client
, OnBinary(kWebMIdSimpleBlock
, _
, _
))
62 .WillOnce(Return(true));
65 if (is_complete_cluster
)
66 EXPECT_CALL(*client
, OnListEnd(kWebMIdCluster
)).WillOnce(Return(true));
69 TEST_F(WebMParserTest
, EmptyCluster
) {
70 const uint8 kEmptyCluster
[] = {
71 0x1F, 0x43, 0xB6, 0x75, 0x80 // CLUSTER (size = 0)
73 int size
= sizeof(kEmptyCluster
);
76 EXPECT_CALL(client_
, OnListStart(kWebMIdCluster
)).WillOnce(Return(&client_
));
77 EXPECT_CALL(client_
, OnListEnd(kWebMIdCluster
)).WillOnce(Return(true));
79 WebMListParser
parser(kWebMIdCluster
, &client_
);
80 EXPECT_EQ(size
, parser
.Parse(kEmptyCluster
, size
));
81 EXPECT_TRUE(parser
.IsParsingComplete());
84 TEST_F(WebMParserTest
, EmptyClusterInSegment
) {
85 const uint8 kBuffer
[] = {
86 0x18, 0x53, 0x80, 0x67, 0x85, // SEGMENT (size = 5)
87 0x1F, 0x43, 0xB6, 0x75, 0x80, // CLUSTER (size = 0)
89 int size
= sizeof(kBuffer
);
92 EXPECT_CALL(client_
, OnListStart(kWebMIdSegment
)).WillOnce(Return(&client_
));
93 EXPECT_CALL(client_
, OnListStart(kWebMIdCluster
)).WillOnce(Return(&client_
));
94 EXPECT_CALL(client_
, OnListEnd(kWebMIdCluster
)).WillOnce(Return(true));
95 EXPECT_CALL(client_
, OnListEnd(kWebMIdSegment
)).WillOnce(Return(true));
97 WebMListParser
parser(kWebMIdSegment
, &client_
);
98 EXPECT_EQ(size
, parser
.Parse(kBuffer
, size
));
99 EXPECT_TRUE(parser
.IsParsingComplete());
102 // Test the case where a non-list child element has a size
103 // that is beyond the end of the parent.
104 TEST_F(WebMParserTest
, ChildNonListLargerThanParent
) {
105 const uint8 kBuffer
[] = {
106 0x1F, 0x43, 0xB6, 0x75, 0x81, // CLUSTER (size = 1)
107 0xE7, 0x81, 0x01, // Timecode (size=1, value=1)
111 EXPECT_CALL(client_
, OnListStart(kWebMIdCluster
)).WillOnce(Return(&client_
));
113 WebMListParser
parser(kWebMIdCluster
, &client_
);
114 EXPECT_EQ(-1, parser
.Parse(kBuffer
, sizeof(kBuffer
)));
115 EXPECT_FALSE(parser
.IsParsingComplete());
118 // Test the case where a list child element has a size
119 // that is beyond the end of the parent.
120 TEST_F(WebMParserTest
, ChildListLargerThanParent
) {
121 const uint8 kBuffer
[] = {
122 0x18, 0x53, 0x80, 0x67, 0x85, // SEGMENT (size = 5)
123 0x1F, 0x43, 0xB6, 0x75, 0x81, 0x11 // CLUSTER (size = 1)
127 EXPECT_CALL(client_
, OnListStart(kWebMIdSegment
)).WillOnce(Return(&client_
));
129 WebMListParser
parser(kWebMIdSegment
, &client_
);
130 EXPECT_EQ(-1, parser
.Parse(kBuffer
, sizeof(kBuffer
)));
131 EXPECT_FALSE(parser
.IsParsingComplete());
134 // Expecting to parse a Cluster, but get a Segment.
135 TEST_F(WebMParserTest
, ListIdDoesNotMatch
) {
136 const uint8 kBuffer
[] = {
137 0x18, 0x53, 0x80, 0x67, 0x80, // SEGMENT (size = 0)
140 WebMListParser
parser(kWebMIdCluster
, &client_
);
141 EXPECT_EQ(-1, parser
.Parse(kBuffer
, sizeof(kBuffer
)));
142 EXPECT_FALSE(parser
.IsParsingComplete());
145 TEST_F(WebMParserTest
, InvalidElementInList
) {
146 const uint8 kBuffer
[] = {
147 0x18, 0x53, 0x80, 0x67, 0x82, // SEGMENT (size = 2)
148 0xAE, 0x80, // TrackEntry (size = 0)
152 EXPECT_CALL(client_
, OnListStart(kWebMIdSegment
)).WillOnce(Return(&client_
));
154 WebMListParser
parser(kWebMIdSegment
, &client_
);
155 EXPECT_EQ(-1, parser
.Parse(kBuffer
, sizeof(kBuffer
)));
156 EXPECT_FALSE(parser
.IsParsingComplete());
159 // Test specific case of InvalidElementInList to verify EBMLHEADER within
160 // known-sized cluster causes parse error.
161 TEST_F(WebMParserTest
, InvalidEBMLHeaderInCluster
) {
162 const uint8 kBuffer
[] = {
163 0x1F, 0x43, 0xB6, 0x75, 0x85, // CLUSTER (size = 5)
164 0x1A, 0x45, 0xDF, 0xA3, 0x80, // EBMLHEADER (size = 0)
168 EXPECT_CALL(client_
, OnListStart(kWebMIdCluster
)).WillOnce(Return(&client_
));
170 WebMListParser
parser(kWebMIdCluster
, &client_
);
171 EXPECT_EQ(-1, parser
.Parse(kBuffer
, sizeof(kBuffer
)));
172 EXPECT_FALSE(parser
.IsParsingComplete());
175 // Verify that EBMLHEADER ends a preceding "unknown"-sized CLUSTER.
176 TEST_F(WebMParserTest
, UnknownSizeClusterFollowedByEBMLHeader
) {
177 const uint8 kBuffer
[] = {
178 0x1F, 0x43, 0xB6, 0x75, 0xFF, // CLUSTER (size = unknown; really 0 due to:)
179 0x1A, 0x45, 0xDF, 0xA3, 0x80, // EBMLHEADER (size = 0)
183 EXPECT_CALL(client_
, OnListStart(kWebMIdCluster
)).WillOnce(Return(&client_
));
184 EXPECT_CALL(client_
, OnListEnd(kWebMIdCluster
)).WillOnce(Return(true));
186 WebMListParser
parser(kWebMIdCluster
, &client_
);
188 // List parse should consume the CLUSTER but not the EBMLHEADER.
189 EXPECT_EQ(5, parser
.Parse(kBuffer
, sizeof(kBuffer
)));
190 EXPECT_TRUE(parser
.IsParsingComplete());
193 TEST_F(WebMParserTest
, VoidAndCRC32InList
) {
194 const uint8 kBuffer
[] = {
195 0x18, 0x53, 0x80, 0x67, 0x99, // SEGMENT (size = 25)
196 0xEC, 0x83, 0x00, 0x00, 0x00, // Void (size = 3)
197 0xBF, 0x83, 0x00, 0x00, 0x00, // CRC32 (size = 3)
198 0x1F, 0x43, 0xB6, 0x75, 0x8A, // CLUSTER (size = 10)
199 0xEC, 0x83, 0x00, 0x00, 0x00, // Void (size = 3)
200 0xBF, 0x83, 0x00, 0x00, 0x00, // CRC32 (size = 3)
202 int size
= sizeof(kBuffer
);
205 EXPECT_CALL(client_
, OnListStart(kWebMIdSegment
)).WillOnce(Return(&client_
));
206 EXPECT_CALL(client_
, OnListStart(kWebMIdCluster
)).WillOnce(Return(&client_
));
207 EXPECT_CALL(client_
, OnListEnd(kWebMIdCluster
)).WillOnce(Return(true));
208 EXPECT_CALL(client_
, OnListEnd(kWebMIdSegment
)).WillOnce(Return(true));
210 WebMListParser
parser(kWebMIdSegment
, &client_
);
211 EXPECT_EQ(size
, parser
.Parse(kBuffer
, size
));
212 EXPECT_TRUE(parser
.IsParsingComplete());
216 TEST_F(WebMParserTest
, ParseListElementWithSingleCall
) {
217 scoped_ptr
<Cluster
> cluster(CreateCluster(kBlockCount
));
218 CreateClusterExpectations(kBlockCount
, true, &client_
);
220 WebMListParser
parser(kWebMIdCluster
, &client_
);
221 EXPECT_EQ(cluster
->size(), parser
.Parse(cluster
->data(), cluster
->size()));
222 EXPECT_TRUE(parser
.IsParsingComplete());
225 TEST_F(WebMParserTest
, ParseListElementWithMultipleCalls
) {
226 scoped_ptr
<Cluster
> cluster(CreateCluster(kBlockCount
));
227 CreateClusterExpectations(kBlockCount
, true, &client_
);
229 const uint8
* data
= cluster
->data();
230 int size
= cluster
->size();
231 int default_parse_size
= 3;
232 WebMListParser
parser(kWebMIdCluster
, &client_
);
233 int parse_size
= std::min(default_parse_size
, size
);
236 int result
= parser
.Parse(data
, parse_size
);
237 ASSERT_GE(result
, 0);
238 ASSERT_LE(result
, parse_size
);
241 // The parser needs more data so increase the parse_size a little.
242 EXPECT_FALSE(parser
.IsParsingComplete());
243 parse_size
+= default_parse_size
;
244 parse_size
= std::min(parse_size
, size
);
248 parse_size
= default_parse_size
;
253 EXPECT_EQ((size
== 0), parser
.IsParsingComplete());
255 EXPECT_TRUE(parser
.IsParsingComplete());
258 TEST_F(WebMParserTest
, Reset
) {
260 scoped_ptr
<Cluster
> cluster(CreateCluster(kBlockCount
));
262 // First expect all but the last block.
263 CreateClusterExpectations(kBlockCount
- 1, false, &client_
);
265 // Now expect all blocks.
266 CreateClusterExpectations(kBlockCount
, true, &client_
);
268 WebMListParser
parser(kWebMIdCluster
, &client_
);
270 // Send slightly less than the full cluster so all but the last block is
272 int result
= parser
.Parse(cluster
->data(), cluster
->size() - 1);
273 EXPECT_GT(result
, 0);
274 EXPECT_LT(result
, cluster
->size());
275 EXPECT_FALSE(parser
.IsParsingComplete());
279 // Now parse a whole cluster to verify that all the blocks will get parsed.
280 EXPECT_EQ(cluster
->size(), parser
.Parse(cluster
->data(), cluster
->size()));
281 EXPECT_TRUE(parser
.IsParsingComplete());
284 // Test the case where multiple clients are used for different lists.
285 TEST_F(WebMParserTest
, MultipleClients
) {
286 const uint8 kBuffer
[] = {
287 0x18, 0x53, 0x80, 0x67, 0x94, // SEGMENT (size = 20)
288 0x16, 0x54, 0xAE, 0x6B, 0x85, // TRACKS (size = 5)
289 0xAE, 0x83, // TRACKENTRY (size = 3)
290 0xD7, 0x81, 0x01, // TRACKNUMBER (size = 1)
291 0x1F, 0x43, 0xB6, 0x75, 0x85, // CLUSTER (size = 5)
292 0xEC, 0x83, 0x00, 0x00, 0x00, // Void (size = 3)
294 int size
= sizeof(kBuffer
);
296 StrictMock
<MockWebMParserClient
> c1_
;
297 StrictMock
<MockWebMParserClient
> c2_
;
298 StrictMock
<MockWebMParserClient
> c3_
;
301 EXPECT_CALL(client_
, OnListStart(kWebMIdSegment
)).WillOnce(Return(&c1_
));
302 EXPECT_CALL(c1_
, OnListStart(kWebMIdTracks
)).WillOnce(Return(&c2_
));
303 EXPECT_CALL(c2_
, OnListStart(kWebMIdTrackEntry
)).WillOnce(Return(&c3_
));
304 EXPECT_CALL(c3_
, OnUInt(kWebMIdTrackNumber
, 1)).WillOnce(Return(true));
305 EXPECT_CALL(c2_
, OnListEnd(kWebMIdTrackEntry
)).WillOnce(Return(true));
306 EXPECT_CALL(c1_
, OnListEnd(kWebMIdTracks
)).WillOnce(Return(true));
307 EXPECT_CALL(c1_
, OnListStart(kWebMIdCluster
)).WillOnce(Return(&c2_
));
308 EXPECT_CALL(c1_
, OnListEnd(kWebMIdCluster
)).WillOnce(Return(true));
309 EXPECT_CALL(client_
, OnListEnd(kWebMIdSegment
)).WillOnce(Return(true));
311 WebMListParser
parser(kWebMIdSegment
, &client_
);
312 EXPECT_EQ(size
, parser
.Parse(kBuffer
, size
));
313 EXPECT_TRUE(parser
.IsParsingComplete());
316 // Test the case where multiple clients are used for different lists.
317 TEST_F(WebMParserTest
, InvalidClient
) {
318 const uint8 kBuffer
[] = {
319 0x18, 0x53, 0x80, 0x67, 0x85, // SEGMENT (size = 20)
320 0x16, 0x54, 0xAE, 0x6B, 0x80, // TRACKS (size = 5)
324 EXPECT_CALL(client_
, OnListStart(kWebMIdSegment
)).WillOnce(ReturnNull());
326 WebMListParser
parser(kWebMIdSegment
, &client_
);
327 EXPECT_EQ(-1, parser
.Parse(kBuffer
, sizeof(kBuffer
)));
328 EXPECT_FALSE(parser
.IsParsingComplete());
331 TEST_F(WebMParserTest
, ReservedIds
) {
332 const uint8 k1ByteReservedId
[] = { 0xFF, 0x81 };
333 const uint8 k2ByteReservedId
[] = { 0x7F, 0xFF, 0x81 };
334 const uint8 k3ByteReservedId
[] = { 0x3F, 0xFF, 0xFF, 0x81 };
335 const uint8 k4ByteReservedId
[] = { 0x1F, 0xFF, 0xFF, 0xFF, 0x81 };
336 const uint8
* kBuffers
[] = {
343 for (size_t i
= 0; i
< arraysize(kBuffers
); i
++) {
346 int buffer_size
= 2 + i
;
347 EXPECT_EQ(buffer_size
, WebMParseElementHeader(kBuffers
[i
], buffer_size
,
348 &id
, &element_size
));
349 EXPECT_EQ(id
, kWebMReservedId
);
350 EXPECT_EQ(element_size
, 1);
354 TEST_F(WebMParserTest
, ReservedSizes
) {
355 const uint8 k1ByteReservedSize
[] = { 0xA3, 0xFF };
356 const uint8 k2ByteReservedSize
[] = { 0xA3, 0x7F, 0xFF };
357 const uint8 k3ByteReservedSize
[] = { 0xA3, 0x3F, 0xFF, 0xFF };
358 const uint8 k4ByteReservedSize
[] = { 0xA3, 0x1F, 0xFF, 0xFF, 0xFF };
359 const uint8 k5ByteReservedSize
[] = { 0xA3, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF };
360 const uint8 k6ByteReservedSize
[] = { 0xA3, 0x07, 0xFF, 0xFF, 0xFF, 0xFF,
362 const uint8 k7ByteReservedSize
[] = { 0xA3, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
364 const uint8 k8ByteReservedSize
[] = { 0xA3, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
366 const uint8
* kBuffers
[] = {
377 for (size_t i
= 0; i
< arraysize(kBuffers
); i
++) {
380 int buffer_size
= 2 + i
;
381 EXPECT_EQ(buffer_size
, WebMParseElementHeader(kBuffers
[i
], buffer_size
,
382 &id
, &element_size
));
384 EXPECT_EQ(element_size
, kWebMUnknownSize
);
388 TEST_F(WebMParserTest
, ZeroPaddedStrings
) {
389 const uint8 kBuffer
[] = {
390 0x1A, 0x45, 0xDF, 0xA3, 0x91, // EBMLHEADER (size = 17)
391 0x42, 0x82, 0x80, // DocType (size = 0)
392 0x42, 0x82, 0x81, 0x00, // DocType (size = 1) ""
393 0x42, 0x82, 0x81, 'a', // DocType (size = 1) "a"
394 0x42, 0x82, 0x83, 'a', 0x00, 0x00 // DocType (size = 3) "a"
396 int size
= sizeof(kBuffer
);
399 EXPECT_CALL(client_
, OnListStart(kWebMIdEBMLHeader
))
400 .WillOnce(Return(&client_
));
401 EXPECT_CALL(client_
, OnString(kWebMIdDocType
, "")).WillOnce(Return(true));
402 EXPECT_CALL(client_
, OnString(kWebMIdDocType
, "")).WillOnce(Return(true));
403 EXPECT_CALL(client_
, OnString(kWebMIdDocType
, "a")).WillOnce(Return(true));
404 EXPECT_CALL(client_
, OnString(kWebMIdDocType
, "a")).WillOnce(Return(true));
405 EXPECT_CALL(client_
, OnListEnd(kWebMIdEBMLHeader
)).WillOnce(Return(true));
407 WebMListParser
parser(kWebMIdEBMLHeader
, &client_
);
408 EXPECT_EQ(size
, parser
.Parse(kBuffer
, size
));
409 EXPECT_TRUE(parser
.IsParsingComplete());