1// Copyright (c) 2012 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.
4
5#include "media/webm/cluster_builder.h"
6#include "media/webm/webm_constants.h"
7#include "media/webm/webm_parser.h"
8#include "testing/gmock/include/gmock/gmock.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11using ::testing::InSequence;
12using ::testing::Return;
13using ::testing::ReturnNull;
14using ::testing::StrictMock;
15using ::testing::_;
16
17namespace media {
18
19enum { kBlockCount = 5 };
20
21class MockWebMParserClient : public WebMParserClient {
22 public:
23  virtual ~MockWebMParserClient() {}
24
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&));
32};
33
34class WebMParserTest : public testing::Test {
35 protected:
36  StrictMock<MockWebMParserClient> client_;
37};
38
39static scoped_ptr<Cluster> CreateCluster(int block_count) {
40  ClusterBuilder cb;
41  cb.SetClusterTimecode(0);
42
43  for (int i = 0; i < block_count; i++) {
44    uint8 data[] = { 0x00 };
45    cb.AddSimpleBlock(0, i, 0, data, sizeof(data));
46  }
47
48  return cb.Finish();
49}
50
51static void CreateClusterExpectations(int block_count,
52                                      bool is_complete_cluster,
53                                      MockWebMParserClient* client) {
54
55  InSequence s;
56  EXPECT_CALL(*client, OnListStart(kWebMIdCluster)).WillOnce(Return(client));
57  EXPECT_CALL(*client, OnUInt(kWebMIdTimecode, 0))
58      .WillOnce(Return(true));
59
60  for (int i = 0; i < block_count; i++) {
61    EXPECT_CALL(*client, OnBinary(kWebMIdSimpleBlock, _, _))
62        .WillOnce(Return(true));
63  }
64
65  if (is_complete_cluster)
66    EXPECT_CALL(*client, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
67}
68
69TEST_F(WebMParserTest, EmptyCluster) {
70  const uint8 kEmptyCluster[] = {
71    0x1F, 0x43, 0xB6, 0x75, 0x80  // CLUSTER (size = 0)
72  };
73  int size = sizeof(kEmptyCluster);
74
75  InSequence s;
76  EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
77  EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
78
79  WebMListParser parser(kWebMIdCluster, &client_);
80  int result = parser.Parse(kEmptyCluster, size);
81  EXPECT_EQ(size, result);
82  EXPECT_TRUE(parser.IsParsingComplete());
83}
84
85TEST_F(WebMParserTest, EmptyClusterInSegment) {
86  const uint8 kBuffer[] = {
87    0x18, 0x53, 0x80, 0x67, 0x85,  // SEGMENT (size = 5)
88    0x1F, 0x43, 0xB6, 0x75, 0x80,  // CLUSTER (size = 0)
89  };
90  int size = sizeof(kBuffer);
91
92  InSequence s;
93  EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&client_));
94  EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
95  EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
96  EXPECT_CALL(client_, OnListEnd(kWebMIdSegment)).WillOnce(Return(true));
97
98  WebMListParser parser(kWebMIdSegment, &client_);
99  int result = parser.Parse(kBuffer, size);
100  EXPECT_EQ(size, result);
101  EXPECT_TRUE(parser.IsParsingComplete());
102}
103
104// Test the case where a non-list child element has a size
105// that is beyond the end of the parent.
106TEST_F(WebMParserTest, ChildNonListLargerThanParent) {
107  const uint8 kBuffer[] = {
108    0x1F, 0x43, 0xB6, 0x75, 0x81,  // CLUSTER (size = 1)
109    0xE7, 0x81, 0x01,  // Timecode (size=1, value=1)
110  };
111  int size = sizeof(kBuffer);
112
113  InSequence s;
114  EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
115
116  WebMListParser parser(kWebMIdCluster, &client_);
117  int result = parser.Parse(kBuffer, size);
118  EXPECT_EQ(-1, result);
119  EXPECT_FALSE(parser.IsParsingComplete());
120}
121
122// Test the case where a list child element has a size
123// that is beyond the end of the parent.
124TEST_F(WebMParserTest, ChildListLargerThanParent) {
125  const uint8 kBuffer[] = {
126    0x18, 0x53, 0x80, 0x67, 0x85,  // SEGMENT (size = 5)
127    0x1F, 0x43, 0xB6, 0x75, 0x81, 0x11  // CLUSTER (size = 1)
128  };
129  int size = sizeof(kBuffer);
130
131  InSequence s;
132  EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&client_));
133
134  WebMListParser parser(kWebMIdSegment, &client_);
135  int result = parser.Parse(kBuffer, size);
136  EXPECT_EQ(-1, result);
137  EXPECT_FALSE(parser.IsParsingComplete());
138}
139
140// Expecting to parse a Cluster, but get a Segment.
141TEST_F(WebMParserTest, ListIdDoesNotMatch) {
142  const uint8 kBuffer[] = {
143    0x18, 0x53, 0x80, 0x67, 0x80,  // SEGMENT (size = 0)
144  };
145  int size = sizeof(kBuffer);
146
147  WebMListParser parser(kWebMIdCluster, &client_);
148  int result = parser.Parse(kBuffer, size);
149  EXPECT_EQ(-1, result);
150  EXPECT_FALSE(parser.IsParsingComplete());
151}
152
153TEST_F(WebMParserTest, InvalidElementInList) {
154  const uint8 kBuffer[] = {
155    0x18, 0x53, 0x80, 0x67, 0x82,  // SEGMENT (size = 2)
156    0xAE, 0x80,  // TrackEntry (size = 0)
157  };
158  int size = sizeof(kBuffer);
159
160  InSequence s;
161  EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&client_));
162
163  WebMListParser parser(kWebMIdSegment, &client_);
164  int result = parser.Parse(kBuffer, size);
165  EXPECT_EQ(-1, result);
166  EXPECT_FALSE(parser.IsParsingComplete());
167}
168
169TEST_F(WebMParserTest, VoidAndCRC32InList) {
170  const uint8 kBuffer[] = {
171    0x18, 0x53, 0x80, 0x67, 0x99,  // SEGMENT (size = 25)
172    0xEC, 0x83, 0x00, 0x00, 0x00,  // Void (size = 3)
173    0xBF, 0x83, 0x00, 0x00, 0x00,  // CRC32 (size = 3)
174    0x1F, 0x43, 0xB6, 0x75, 0x8A,  // CLUSTER (size = 10)
175    0xEC, 0x83, 0x00, 0x00, 0x00,  // Void (size = 3)
176    0xBF, 0x83, 0x00, 0x00, 0x00,  // CRC32 (size = 3)
177  };
178  int size = sizeof(kBuffer);
179
180  InSequence s;
181  EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&client_));
182  EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
183  EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
184  EXPECT_CALL(client_, OnListEnd(kWebMIdSegment)).WillOnce(Return(true));
185
186  WebMListParser parser(kWebMIdSegment, &client_);
187  int result = parser.Parse(kBuffer, size);
188  EXPECT_EQ(size, result);
189  EXPECT_TRUE(parser.IsParsingComplete());
190}
191
192
193TEST_F(WebMParserTest, ParseListElementWithSingleCall) {
194  scoped_ptr<Cluster> cluster(CreateCluster(kBlockCount));
195  CreateClusterExpectations(kBlockCount, true, &client_);
196
197  WebMListParser parser(kWebMIdCluster, &client_);
198  int result = parser.Parse(cluster->data(), cluster->size());
199  EXPECT_EQ(cluster->size(), result);
200  EXPECT_TRUE(parser.IsParsingComplete());
201}
202
203TEST_F(WebMParserTest, ParseListElementWithMultipleCalls) {
204  scoped_ptr<Cluster> cluster(CreateCluster(kBlockCount));
205  CreateClusterExpectations(kBlockCount, true, &client_);
206
207  const uint8* data = cluster->data();
208  int size = cluster->size();
209  int default_parse_size = 3;
210  WebMListParser parser(kWebMIdCluster, &client_);
211  int parse_size = std::min(default_parse_size, size);
212
213  while (size > 0) {
214    int result = parser.Parse(data, parse_size);
215    ASSERT_GE(result, 0);
216    ASSERT_LE(result, parse_size);
217
218    if (result == 0) {
219      // The parser needs more data so increase the parse_size a little.
220      EXPECT_FALSE(parser.IsParsingComplete());
221      parse_size += default_parse_size;
222      parse_size = std::min(parse_size, size);
223      continue;
224    }
225
226    parse_size = default_parse_size;
227
228    data += result;
229    size -= result;
230
231    EXPECT_EQ((size == 0), parser.IsParsingComplete());
232  }
233  EXPECT_TRUE(parser.IsParsingComplete());
234}
235
236TEST_F(WebMParserTest, Reset) {
237  InSequence s;
238  scoped_ptr<Cluster> cluster(CreateCluster(kBlockCount));
239
240  // First expect all but the last block.
241  CreateClusterExpectations(kBlockCount - 1, false, &client_);
242
243  // Now expect all blocks.
244  CreateClusterExpectations(kBlockCount, true, &client_);
245
246  WebMListParser parser(kWebMIdCluster, &client_);
247
248  // Send slightly less than the full cluster so all but the last block is
249  // parsed.
250  int result = parser.Parse(cluster->data(), cluster->size() - 1);
251  EXPECT_GT(result, 0);
252  EXPECT_LT(result, cluster->size());
253  EXPECT_FALSE(parser.IsParsingComplete());
254
255  parser.Reset();
256
257  // Now parse a whole cluster to verify that all the blocks will get parsed.
258  result = parser.Parse(cluster->data(), cluster->size());
259  EXPECT_EQ(result, cluster->size());
260  EXPECT_TRUE(parser.IsParsingComplete());
261}
262
263// Test the case where multiple clients are used for different lists.
264TEST_F(WebMParserTest, MultipleClients) {
265  const uint8 kBuffer[] = {
266    0x18, 0x53, 0x80, 0x67, 0x94,  // SEGMENT (size = 20)
267    0x16, 0x54, 0xAE, 0x6B, 0x85,  //   TRACKS (size = 5)
268    0xAE, 0x83,                    //     TRACKENTRY (size = 3)
269    0xD7, 0x81, 0x01,              //       TRACKNUMBER (size = 1)
270    0x1F, 0x43, 0xB6, 0x75, 0x85,  //   CLUSTER (size = 5)
271    0xEC, 0x83, 0x00, 0x00, 0x00,  //     Void (size = 3)
272  };
273  int size = sizeof(kBuffer);
274
275  StrictMock<MockWebMParserClient> c1_;
276  StrictMock<MockWebMParserClient> c2_;
277  StrictMock<MockWebMParserClient> c3_;
278
279  InSequence s;
280  EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&c1_));
281  EXPECT_CALL(c1_, OnListStart(kWebMIdTracks)).WillOnce(Return(&c2_));
282  EXPECT_CALL(c2_, OnListStart(kWebMIdTrackEntry)).WillOnce(Return(&c3_));
283  EXPECT_CALL(c3_, OnUInt(kWebMIdTrackNumber, 1)).WillOnce(Return(true));
284  EXPECT_CALL(c2_, OnListEnd(kWebMIdTrackEntry)).WillOnce(Return(true));
285  EXPECT_CALL(c1_, OnListEnd(kWebMIdTracks)).WillOnce(Return(true));
286  EXPECT_CALL(c1_, OnListStart(kWebMIdCluster)).WillOnce(Return(&c2_));
287  EXPECT_CALL(c1_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
288  EXPECT_CALL(client_, OnListEnd(kWebMIdSegment)).WillOnce(Return(true));
289
290  WebMListParser parser(kWebMIdSegment, &client_);
291  int result = parser.Parse(kBuffer, size);
292  EXPECT_EQ(size, result);
293  EXPECT_TRUE(parser.IsParsingComplete());
294}
295
296// Test the case where multiple clients are used for different lists.
297TEST_F(WebMParserTest, InvalidClient) {
298  const uint8 kBuffer[] = {
299    0x18, 0x53, 0x80, 0x67, 0x85,  // SEGMENT (size = 20)
300    0x16, 0x54, 0xAE, 0x6B, 0x80,  //   TRACKS (size = 5)
301  };
302  int size = sizeof(kBuffer);
303
304  InSequence s;
305  EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(ReturnNull());
306
307  WebMListParser parser(kWebMIdSegment, &client_);
308  int result = parser.Parse(kBuffer, size);
309  EXPECT_EQ(-1, result);
310  EXPECT_FALSE(parser.IsParsingComplete());
311}
312
313TEST_F(WebMParserTest, ReservedIds) {
314  const uint8 k1ByteReservedId[] = { 0xFF, 0x81 };
315  const uint8 k2ByteReservedId[] = { 0x7F, 0xFF, 0x81 };
316  const uint8 k3ByteReservedId[] = { 0x3F, 0xFF, 0xFF, 0x81 };
317  const uint8 k4ByteReservedId[] = { 0x1F, 0xFF, 0xFF, 0xFF, 0x81 };
318  const uint8* kBuffers[] = {
319    k1ByteReservedId,
320    k2ByteReservedId,
321    k3ByteReservedId,
322    k4ByteReservedId
323  };
324
325  for (size_t i = 0; i < arraysize(kBuffers); i++) {
326    int id;
327    int64 element_size;
328    int buffer_size = 2 + i;
329    EXPECT_EQ(buffer_size, WebMParseElementHeader(kBuffers[i], buffer_size,
330                                                  &id, &element_size));
331    EXPECT_EQ(id, kWebMReservedId);
332    EXPECT_EQ(element_size, 1);
333  }
334}
335
336TEST_F(WebMParserTest, ReservedSizes) {
337  const uint8 k1ByteReservedSize[] = { 0xA3, 0xFF };
338  const uint8 k2ByteReservedSize[] = { 0xA3, 0x7F, 0xFF };
339  const uint8 k3ByteReservedSize[] = { 0xA3, 0x3F, 0xFF, 0xFF };
340  const uint8 k4ByteReservedSize[] = { 0xA3, 0x1F, 0xFF, 0xFF, 0xFF };
341  const uint8 k5ByteReservedSize[] = { 0xA3, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF };
342  const uint8 k6ByteReservedSize[] = { 0xA3, 0x07, 0xFF, 0xFF, 0xFF, 0xFF,
343                                       0xFF };
344  const uint8 k7ByteReservedSize[] = { 0xA3, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
345                                       0xFF };
346  const uint8 k8ByteReservedSize[] = { 0xA3, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
347                                       0xFF, 0xFF };
348  const uint8* kBuffers[] = {
349    k1ByteReservedSize,
350    k2ByteReservedSize,
351    k3ByteReservedSize,
352    k4ByteReservedSize,
353    k5ByteReservedSize,
354    k6ByteReservedSize,
355    k7ByteReservedSize,
356    k8ByteReservedSize
357  };
358
359  for (size_t i = 0; i < arraysize(kBuffers); i++) {
360    int id;
361    int64 element_size;
362    int buffer_size = 2 + i;
363    EXPECT_EQ(buffer_size, WebMParseElementHeader(kBuffers[i], buffer_size,
364                                                  &id, &element_size));
365    EXPECT_EQ(id, 0xA3);
366    EXPECT_EQ(element_size, kWebMUnknownSize);
367  }
368}
369
370TEST_F(WebMParserTest, ZeroPaddedStrings) {
371  const uint8 kBuffer[] = {
372    0x1A, 0x45, 0xDF, 0xA3, 0x91,  // EBMLHEADER (size = 17)
373    0x42, 0x82, 0x80,  // DocType (size = 0)
374    0x42, 0x82, 0x81, 0x00,  // DocType (size = 1) ""
375    0x42, 0x82, 0x81, 'a',  // DocType (size = 1) "a"
376    0x42, 0x82, 0x83, 'a', 0x00, 0x00  // DocType (size = 3) "a"
377  };
378  int size = sizeof(kBuffer);
379
380  InSequence s;
381  EXPECT_CALL(client_, OnListStart(kWebMIdEBMLHeader))
382      .WillOnce(Return(&client_));
383  EXPECT_CALL(client_, OnString(kWebMIdDocType, "")).WillOnce(Return(true));
384  EXPECT_CALL(client_, OnString(kWebMIdDocType, "")).WillOnce(Return(true));
385  EXPECT_CALL(client_, OnString(kWebMIdDocType, "a")).WillOnce(Return(true));
386  EXPECT_CALL(client_, OnString(kWebMIdDocType, "a")).WillOnce(Return(true));
387  EXPECT_CALL(client_, OnListEnd(kWebMIdEBMLHeader)).WillOnce(Return(true));
388
389  WebMListParser parser(kWebMIdEBMLHeader, &client_);
390  int result = parser.Parse(kBuffer, size);
391  EXPECT_EQ(size, result);
392  EXPECT_TRUE(parser.IsParsingComplete());
393}
394
395}  // namespace media
396