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