summaryrefslogtreecommitdiffstats
path: root/media/formats/webm/webm_parser_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'media/formats/webm/webm_parser_unittest.cc')
-rw-r--r--media/formats/webm/webm_parser_unittest.cc412
1 files changed, 412 insertions, 0 deletions
diff --git a/media/formats/webm/webm_parser_unittest.cc b/media/formats/webm/webm_parser_unittest.cc
new file mode 100644
index 0000000..a1249e8
--- /dev/null
+++ b/media/formats/webm/webm_parser_unittest.cc
@@ -0,0 +1,412 @@
+// Copyright 2014 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.
+
+#include "media/formats/webm/cluster_builder.h"
+#include "media/formats/webm/webm_constants.h"
+#include "media/formats/webm/webm_parser.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::ReturnNull;
+using ::testing::StrictMock;
+using ::testing::_;
+
+namespace media {
+
+enum { kBlockCount = 5 };
+
+class MockWebMParserClient : public WebMParserClient {
+ public:
+ virtual ~MockWebMParserClient() {}
+
+ // WebMParserClient methods.
+ MOCK_METHOD1(OnListStart, WebMParserClient*(int));
+ MOCK_METHOD1(OnListEnd, bool(int));
+ MOCK_METHOD2(OnUInt, bool(int, int64));
+ MOCK_METHOD2(OnFloat, bool(int, double));
+ MOCK_METHOD3(OnBinary, bool(int, const uint8*, int));
+ MOCK_METHOD2(OnString, bool(int, const std::string&));
+};
+
+class WebMParserTest : public testing::Test {
+ protected:
+ StrictMock<MockWebMParserClient> client_;
+};
+
+static scoped_ptr<Cluster> CreateCluster(int block_count) {
+ ClusterBuilder cb;
+ cb.SetClusterTimecode(0);
+
+ for (int i = 0; i < block_count; i++) {
+ uint8 data[] = { 0x00 };
+ cb.AddSimpleBlock(0, i, 0, data, sizeof(data));
+ }
+
+ return cb.Finish();
+}
+
+static void CreateClusterExpectations(int block_count,
+ bool is_complete_cluster,
+ MockWebMParserClient* client) {
+
+ InSequence s;
+ EXPECT_CALL(*client, OnListStart(kWebMIdCluster)).WillOnce(Return(client));
+ EXPECT_CALL(*client, OnUInt(kWebMIdTimecode, 0))
+ .WillOnce(Return(true));
+
+ for (int i = 0; i < block_count; i++) {
+ EXPECT_CALL(*client, OnBinary(kWebMIdSimpleBlock, _, _))
+ .WillOnce(Return(true));
+ }
+
+ if (is_complete_cluster)
+ EXPECT_CALL(*client, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
+}
+
+TEST_F(WebMParserTest, EmptyCluster) {
+ const uint8 kEmptyCluster[] = {
+ 0x1F, 0x43, 0xB6, 0x75, 0x80 // CLUSTER (size = 0)
+ };
+ int size = sizeof(kEmptyCluster);
+
+ InSequence s;
+ EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
+ EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
+
+ WebMListParser parser(kWebMIdCluster, &client_);
+ EXPECT_EQ(size, parser.Parse(kEmptyCluster, size));
+ EXPECT_TRUE(parser.IsParsingComplete());
+}
+
+TEST_F(WebMParserTest, EmptyClusterInSegment) {
+ const uint8 kBuffer[] = {
+ 0x18, 0x53, 0x80, 0x67, 0x85, // SEGMENT (size = 5)
+ 0x1F, 0x43, 0xB6, 0x75, 0x80, // CLUSTER (size = 0)
+ };
+ int size = sizeof(kBuffer);
+
+ InSequence s;
+ EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&client_));
+ EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
+ EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
+ EXPECT_CALL(client_, OnListEnd(kWebMIdSegment)).WillOnce(Return(true));
+
+ WebMListParser parser(kWebMIdSegment, &client_);
+ EXPECT_EQ(size, parser.Parse(kBuffer, size));
+ EXPECT_TRUE(parser.IsParsingComplete());
+}
+
+// Test the case where a non-list child element has a size
+// that is beyond the end of the parent.
+TEST_F(WebMParserTest, ChildNonListLargerThanParent) {
+ const uint8 kBuffer[] = {
+ 0x1F, 0x43, 0xB6, 0x75, 0x81, // CLUSTER (size = 1)
+ 0xE7, 0x81, 0x01, // Timecode (size=1, value=1)
+ };
+
+ InSequence s;
+ EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
+
+ WebMListParser parser(kWebMIdCluster, &client_);
+ EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
+ EXPECT_FALSE(parser.IsParsingComplete());
+}
+
+// Test the case where a list child element has a size
+// that is beyond the end of the parent.
+TEST_F(WebMParserTest, ChildListLargerThanParent) {
+ const uint8 kBuffer[] = {
+ 0x18, 0x53, 0x80, 0x67, 0x85, // SEGMENT (size = 5)
+ 0x1F, 0x43, 0xB6, 0x75, 0x81, 0x11 // CLUSTER (size = 1)
+ };
+
+ InSequence s;
+ EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&client_));
+
+ WebMListParser parser(kWebMIdSegment, &client_);
+ EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
+ EXPECT_FALSE(parser.IsParsingComplete());
+}
+
+// Expecting to parse a Cluster, but get a Segment.
+TEST_F(WebMParserTest, ListIdDoesNotMatch) {
+ const uint8 kBuffer[] = {
+ 0x18, 0x53, 0x80, 0x67, 0x80, // SEGMENT (size = 0)
+ };
+
+ WebMListParser parser(kWebMIdCluster, &client_);
+ EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
+ EXPECT_FALSE(parser.IsParsingComplete());
+}
+
+TEST_F(WebMParserTest, InvalidElementInList) {
+ const uint8 kBuffer[] = {
+ 0x18, 0x53, 0x80, 0x67, 0x82, // SEGMENT (size = 2)
+ 0xAE, 0x80, // TrackEntry (size = 0)
+ };
+
+ InSequence s;
+ EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&client_));
+
+ WebMListParser parser(kWebMIdSegment, &client_);
+ EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
+ EXPECT_FALSE(parser.IsParsingComplete());
+}
+
+// Test specific case of InvalidElementInList to verify EBMLHEADER within
+// known-sized cluster causes parse error.
+TEST_F(WebMParserTest, InvalidEBMLHeaderInCluster) {
+ const uint8 kBuffer[] = {
+ 0x1F, 0x43, 0xB6, 0x75, 0x85, // CLUSTER (size = 5)
+ 0x1A, 0x45, 0xDF, 0xA3, 0x80, // EBMLHEADER (size = 0)
+ };
+
+ InSequence s;
+ EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
+
+ WebMListParser parser(kWebMIdCluster, &client_);
+ EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
+ EXPECT_FALSE(parser.IsParsingComplete());
+}
+
+// Verify that EBMLHEADER ends a preceding "unknown"-sized CLUSTER.
+TEST_F(WebMParserTest, UnknownSizeClusterFollowedByEBMLHeader) {
+ const uint8 kBuffer[] = {
+ 0x1F, 0x43, 0xB6, 0x75, 0xFF, // CLUSTER (size = unknown; really 0 due to:)
+ 0x1A, 0x45, 0xDF, 0xA3, 0x80, // EBMLHEADER (size = 0)
+ };
+
+ InSequence s;
+ EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
+ EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
+
+ WebMListParser parser(kWebMIdCluster, &client_);
+
+ // List parse should consume the CLUSTER but not the EBMLHEADER.
+ EXPECT_EQ(5, parser.Parse(kBuffer, sizeof(kBuffer)));
+ EXPECT_TRUE(parser.IsParsingComplete());
+}
+
+TEST_F(WebMParserTest, VoidAndCRC32InList) {
+ const uint8 kBuffer[] = {
+ 0x18, 0x53, 0x80, 0x67, 0x99, // SEGMENT (size = 25)
+ 0xEC, 0x83, 0x00, 0x00, 0x00, // Void (size = 3)
+ 0xBF, 0x83, 0x00, 0x00, 0x00, // CRC32 (size = 3)
+ 0x1F, 0x43, 0xB6, 0x75, 0x8A, // CLUSTER (size = 10)
+ 0xEC, 0x83, 0x00, 0x00, 0x00, // Void (size = 3)
+ 0xBF, 0x83, 0x00, 0x00, 0x00, // CRC32 (size = 3)
+ };
+ int size = sizeof(kBuffer);
+
+ InSequence s;
+ EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&client_));
+ EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
+ EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
+ EXPECT_CALL(client_, OnListEnd(kWebMIdSegment)).WillOnce(Return(true));
+
+ WebMListParser parser(kWebMIdSegment, &client_);
+ EXPECT_EQ(size, parser.Parse(kBuffer, size));
+ EXPECT_TRUE(parser.IsParsingComplete());
+}
+
+
+TEST_F(WebMParserTest, ParseListElementWithSingleCall) {
+ scoped_ptr<Cluster> cluster(CreateCluster(kBlockCount));
+ CreateClusterExpectations(kBlockCount, true, &client_);
+
+ WebMListParser parser(kWebMIdCluster, &client_);
+ EXPECT_EQ(cluster->size(), parser.Parse(cluster->data(), cluster->size()));
+ EXPECT_TRUE(parser.IsParsingComplete());
+}
+
+TEST_F(WebMParserTest, ParseListElementWithMultipleCalls) {
+ scoped_ptr<Cluster> cluster(CreateCluster(kBlockCount));
+ CreateClusterExpectations(kBlockCount, true, &client_);
+
+ const uint8* data = cluster->data();
+ int size = cluster->size();
+ int default_parse_size = 3;
+ WebMListParser parser(kWebMIdCluster, &client_);
+ int parse_size = std::min(default_parse_size, size);
+
+ while (size > 0) {
+ int result = parser.Parse(data, parse_size);
+ ASSERT_GE(result, 0);
+ ASSERT_LE(result, parse_size);
+
+ if (result == 0) {
+ // The parser needs more data so increase the parse_size a little.
+ EXPECT_FALSE(parser.IsParsingComplete());
+ parse_size += default_parse_size;
+ parse_size = std::min(parse_size, size);
+ continue;
+ }
+
+ parse_size = default_parse_size;
+
+ data += result;
+ size -= result;
+
+ EXPECT_EQ((size == 0), parser.IsParsingComplete());
+ }
+ EXPECT_TRUE(parser.IsParsingComplete());
+}
+
+TEST_F(WebMParserTest, Reset) {
+ InSequence s;
+ scoped_ptr<Cluster> cluster(CreateCluster(kBlockCount));
+
+ // First expect all but the last block.
+ CreateClusterExpectations(kBlockCount - 1, false, &client_);
+
+ // Now expect all blocks.
+ CreateClusterExpectations(kBlockCount, true, &client_);
+
+ WebMListParser parser(kWebMIdCluster, &client_);
+
+ // Send slightly less than the full cluster so all but the last block is
+ // parsed.
+ int result = parser.Parse(cluster->data(), cluster->size() - 1);
+ EXPECT_GT(result, 0);
+ EXPECT_LT(result, cluster->size());
+ EXPECT_FALSE(parser.IsParsingComplete());
+
+ parser.Reset();
+
+ // Now parse a whole cluster to verify that all the blocks will get parsed.
+ EXPECT_EQ(cluster->size(), parser.Parse(cluster->data(), cluster->size()));
+ EXPECT_TRUE(parser.IsParsingComplete());
+}
+
+// Test the case where multiple clients are used for different lists.
+TEST_F(WebMParserTest, MultipleClients) {
+ const uint8 kBuffer[] = {
+ 0x18, 0x53, 0x80, 0x67, 0x94, // SEGMENT (size = 20)
+ 0x16, 0x54, 0xAE, 0x6B, 0x85, // TRACKS (size = 5)
+ 0xAE, 0x83, // TRACKENTRY (size = 3)
+ 0xD7, 0x81, 0x01, // TRACKNUMBER (size = 1)
+ 0x1F, 0x43, 0xB6, 0x75, 0x85, // CLUSTER (size = 5)
+ 0xEC, 0x83, 0x00, 0x00, 0x00, // Void (size = 3)
+ };
+ int size = sizeof(kBuffer);
+
+ StrictMock<MockWebMParserClient> c1_;
+ StrictMock<MockWebMParserClient> c2_;
+ StrictMock<MockWebMParserClient> c3_;
+
+ InSequence s;
+ EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&c1_));
+ EXPECT_CALL(c1_, OnListStart(kWebMIdTracks)).WillOnce(Return(&c2_));
+ EXPECT_CALL(c2_, OnListStart(kWebMIdTrackEntry)).WillOnce(Return(&c3_));
+ EXPECT_CALL(c3_, OnUInt(kWebMIdTrackNumber, 1)).WillOnce(Return(true));
+ EXPECT_CALL(c2_, OnListEnd(kWebMIdTrackEntry)).WillOnce(Return(true));
+ EXPECT_CALL(c1_, OnListEnd(kWebMIdTracks)).WillOnce(Return(true));
+ EXPECT_CALL(c1_, OnListStart(kWebMIdCluster)).WillOnce(Return(&c2_));
+ EXPECT_CALL(c1_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
+ EXPECT_CALL(client_, OnListEnd(kWebMIdSegment)).WillOnce(Return(true));
+
+ WebMListParser parser(kWebMIdSegment, &client_);
+ EXPECT_EQ(size, parser.Parse(kBuffer, size));
+ EXPECT_TRUE(parser.IsParsingComplete());
+}
+
+// Test the case where multiple clients are used for different lists.
+TEST_F(WebMParserTest, InvalidClient) {
+ const uint8 kBuffer[] = {
+ 0x18, 0x53, 0x80, 0x67, 0x85, // SEGMENT (size = 20)
+ 0x16, 0x54, 0xAE, 0x6B, 0x80, // TRACKS (size = 5)
+ };
+
+ InSequence s;
+ EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(ReturnNull());
+
+ WebMListParser parser(kWebMIdSegment, &client_);
+ EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
+ EXPECT_FALSE(parser.IsParsingComplete());
+}
+
+TEST_F(WebMParserTest, ReservedIds) {
+ const uint8 k1ByteReservedId[] = { 0xFF, 0x81 };
+ const uint8 k2ByteReservedId[] = { 0x7F, 0xFF, 0x81 };
+ const uint8 k3ByteReservedId[] = { 0x3F, 0xFF, 0xFF, 0x81 };
+ const uint8 k4ByteReservedId[] = { 0x1F, 0xFF, 0xFF, 0xFF, 0x81 };
+ const uint8* kBuffers[] = {
+ k1ByteReservedId,
+ k2ByteReservedId,
+ k3ByteReservedId,
+ k4ByteReservedId
+ };
+
+ for (size_t i = 0; i < arraysize(kBuffers); i++) {
+ int id;
+ int64 element_size;
+ int buffer_size = 2 + i;
+ EXPECT_EQ(buffer_size, WebMParseElementHeader(kBuffers[i], buffer_size,
+ &id, &element_size));
+ EXPECT_EQ(id, kWebMReservedId);
+ EXPECT_EQ(element_size, 1);
+ }
+}
+
+TEST_F(WebMParserTest, ReservedSizes) {
+ const uint8 k1ByteReservedSize[] = { 0xA3, 0xFF };
+ const uint8 k2ByteReservedSize[] = { 0xA3, 0x7F, 0xFF };
+ const uint8 k3ByteReservedSize[] = { 0xA3, 0x3F, 0xFF, 0xFF };
+ const uint8 k4ByteReservedSize[] = { 0xA3, 0x1F, 0xFF, 0xFF, 0xFF };
+ const uint8 k5ByteReservedSize[] = { 0xA3, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF };
+ const uint8 k6ByteReservedSize[] = { 0xA3, 0x07, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF };
+ const uint8 k7ByteReservedSize[] = { 0xA3, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF };
+ const uint8 k8ByteReservedSize[] = { 0xA3, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF };
+ const uint8* kBuffers[] = {
+ k1ByteReservedSize,
+ k2ByteReservedSize,
+ k3ByteReservedSize,
+ k4ByteReservedSize,
+ k5ByteReservedSize,
+ k6ByteReservedSize,
+ k7ByteReservedSize,
+ k8ByteReservedSize
+ };
+
+ for (size_t i = 0; i < arraysize(kBuffers); i++) {
+ int id;
+ int64 element_size;
+ int buffer_size = 2 + i;
+ EXPECT_EQ(buffer_size, WebMParseElementHeader(kBuffers[i], buffer_size,
+ &id, &element_size));
+ EXPECT_EQ(id, 0xA3);
+ EXPECT_EQ(element_size, kWebMUnknownSize);
+ }
+}
+
+TEST_F(WebMParserTest, ZeroPaddedStrings) {
+ const uint8 kBuffer[] = {
+ 0x1A, 0x45, 0xDF, 0xA3, 0x91, // EBMLHEADER (size = 17)
+ 0x42, 0x82, 0x80, // DocType (size = 0)
+ 0x42, 0x82, 0x81, 0x00, // DocType (size = 1) ""
+ 0x42, 0x82, 0x81, 'a', // DocType (size = 1) "a"
+ 0x42, 0x82, 0x83, 'a', 0x00, 0x00 // DocType (size = 3) "a"
+ };
+ int size = sizeof(kBuffer);
+
+ InSequence s;
+ EXPECT_CALL(client_, OnListStart(kWebMIdEBMLHeader))
+ .WillOnce(Return(&client_));
+ EXPECT_CALL(client_, OnString(kWebMIdDocType, "")).WillOnce(Return(true));
+ EXPECT_CALL(client_, OnString(kWebMIdDocType, "")).WillOnce(Return(true));
+ EXPECT_CALL(client_, OnString(kWebMIdDocType, "a")).WillOnce(Return(true));
+ EXPECT_CALL(client_, OnString(kWebMIdDocType, "a")).WillOnce(Return(true));
+ EXPECT_CALL(client_, OnListEnd(kWebMIdEBMLHeader)).WillOnce(Return(true));
+
+ WebMListParser parser(kWebMIdEBMLHeader, &client_);
+ EXPECT_EQ(size, parser.Parse(kBuffer, size));
+ EXPECT_TRUE(parser.IsParsingComplete());
+}
+
+} // namespace media