From db5b2a474011fb9bb8646ca6eb2dd8428dfc01d2 Mon Sep 17 00:00:00 2001 From: Rintaro Kuroiwa Date: Mon, 30 Dec 2013 15:05:27 -0800 Subject: [PATCH] Unit test for MPD builder Initial checkin, very small coverage. Change-Id: I60f3fd768d5b8dca7a84f051e57f59a654272e53 --- mpd/base/mpd_builder.cc | 2 +- mpd/base/mpd_builder_unittest.cc | 147 ++++++++++++ mpd/base/xml/scoped_xml_ptr.h | 8 + mpd/mpd.gyp | 25 +- mpd/test/schema/DASH-MPD.xsd | 390 +++++++++++++++++++++++++++++++ mpd/test/schema/xlink.xsd | 270 +++++++++++++++++++++ mpd/test/schema/xml.xsd | 117 ++++++++++ 7 files changed, 955 insertions(+), 4 deletions(-) create mode 100644 mpd/base/mpd_builder_unittest.cc create mode 100644 mpd/test/schema/DASH-MPD.xsd create mode 100644 mpd/test/schema/xlink.xsd create mode 100644 mpd/test/schema/xml.xsd diff --git a/mpd/base/mpd_builder.cc b/mpd/base/mpd_builder.cc index 3e1e730579..549b2c816b 100644 --- a/mpd/base/mpd_builder.cc +++ b/mpd/base/mpd_builder.cc @@ -165,7 +165,7 @@ uint32 MpdBuilder::GetStaticMpdDuration(XmlNode* mpd_node) { xmlNodePtr period_node = xmlFirstElementChild(mpd_node->GetRawPtr()); DCHECK(period_node); - DCHECK_NE(strcmp(reinterpret_cast(period_node->name), "Period"), + DCHECK_EQ(strcmp(reinterpret_cast(period_node->name), "Period"), 0); // TODO(rkuroiwa): Update this so that the duration for each Representation is diff --git a/mpd/base/mpd_builder_unittest.cc b/mpd/base/mpd_builder_unittest.cc new file mode 100644 index 0000000000..619b2a6211 --- /dev/null +++ b/mpd/base/mpd_builder_unittest.cc @@ -0,0 +1,147 @@ +#include "base/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/strings/string_util.h" +#include "mpd/base/mpd_builder.h" +#include "mpd/base/xml/scoped_xml_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/libxml/src/include/libxml/parser.h" + +namespace dash_packager { +namespace { + +// This was validated at a validator site below as well. +// http://www-itec.uni-klu.ac.at/dash/?page_id=605# +const char kValidMpd[] = "\n\ +\n\ + http://cdn1.example.com/\n\ + \n\ + \n\ + \n\ + \n\ + something.mp4\n\ + \n\ + \n\ + \n\ + \n\ + somethingelse.mp4\n\ + \n\ + \n\ + \n\ + \n\ +\n\ +"; +const size_t kValidMpdSize = arraysize(kValidMpd) - 1; // Exclude '\0'. + +base::FilePath GetSchemaPath() { + base::FilePath file_path; + CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &file_path)); + + file_path = file_path.Append(FILE_PATH_LITERAL("mpd")) + .Append(FILE_PATH_LITERAL("test")) + .Append(FILE_PATH_LITERAL("schema")) + .Append(FILE_PATH_LITERAL("DASH-MPD.xsd")); + return file_path; +} + +std::string GetPathContent(const base::FilePath& file_path) { + std::string content; + bool file_read_to_string = file_util::ReadFileToString(file_path, &content); + DCHECK(file_read_to_string); + return content; +} + +bool ValidateMpdSchema(const std::string& mpd) { + xml::ScopedXmlPtr::type doc(xmlParseMemory(mpd.data(), mpd.size())); + if (!doc) { + LOG(ERROR) << "Failed to parse mpd into an xml doc."; + return false; + } + + base::FilePath schema_path = GetSchemaPath(); + std::string schema_str = GetPathContent(schema_path); + + // First, I need to load the schema as a xmlDoc so that I can pass the path of + // the DASH-MPD.xsd. Then it can resolve the relative path included from the + // XSD when creating xmlSchemaParserCtxt. + xml::ScopedXmlPtr::type schema_as_doc( + xmlReadMemory(schema_str.data(), + schema_str.size(), + schema_path.value().c_str(), + NULL, + 0)); + DCHECK(schema_as_doc); + xml::ScopedXmlPtr::type schema_parser_ctxt( + xmlSchemaNewDocParserCtxt(schema_as_doc.get())); + DCHECK(schema_parser_ctxt); + + xml::ScopedXmlPtr::type schema( + xmlSchemaParse(schema_parser_ctxt.get())); + DCHECK(schema); + + xml::ScopedXmlPtr::type valid_ctxt( + xmlSchemaNewValidCtxt(schema.get())); + DCHECK(valid_ctxt); + int validation_result = + xmlSchemaValidateDoc(valid_ctxt.get(), doc.get()); + DLOG(INFO) << "XSD validation result: " << validation_result; + return validation_result == 0; +} + +} // namespace + +// Check if the schema validation works. If not, then most of the tests would +// probably fail. +TEST(MpdSchemaMetaTest, CheckSchemaValidatorWorks) { + ASSERT_TRUE(ValidateMpdSchema(std::string(kValidMpd, kValidMpdSize))); +} + +// TODO(rkuroiwa): MPD builder does not build a valid MPD yet. Enable these when +// its done. Make sure to compare against a known MPD to validate. +// A normal use case where there are 2 adaptation sets and 2 representations. +TEST(MpdBuilder, DISABLED_VOD_Normal) { + MpdBuilder mpd(MpdBuilder::kStatic); + AdaptationSet* adaptation_set = mpd.AddAdaptationSet(); + ASSERT_TRUE(adaptation_set); + + AdaptationSet* adaptation_set2 = mpd.AddAdaptationSet(); + ASSERT_TRUE(adaptation_set2); + + MediaInfo media_info; + media_info.set_bandwidth(100); + ASSERT_TRUE(adaptation_set->AddRepresentation(media_info)); + ASSERT_TRUE(adaptation_set2->AddRepresentation(media_info)); + + std::string mpd_doc; + ASSERT_TRUE(mpd.ToString(&mpd_doc)); + ASSERT_TRUE(ValidateMpdSchema(mpd_doc)); +} + +// Different media duration should not error. +TEST(MpdBuilder, DISABLED_VOD_DifferentMediaDuration) { + MpdBuilder mpd(MpdBuilder::kStatic); + AdaptationSet* adaptation_set = mpd.AddAdaptationSet(); + ASSERT_TRUE(adaptation_set); + + MediaInfo media_info; + media_info.set_bandwidth(20000); + media_info.set_media_duration_seconds(100); + ASSERT_TRUE(adaptation_set->AddRepresentation(media_info)); + + media_info.set_media_duration_seconds(101); + ASSERT_TRUE(adaptation_set->AddRepresentation(media_info)); + + std::string mpd_doc; + ASSERT_TRUE(mpd.ToString(&mpd_doc)); + ASSERT_TRUE(ValidateMpdSchema(mpd_doc)); +} + +} // namespace dash_packager diff --git a/mpd/base/xml/scoped_xml_ptr.h b/mpd/base/xml/scoped_xml_ptr.h index 6aeee3ab47..051290751d 100644 --- a/mpd/base/xml/scoped_xml_ptr.h +++ b/mpd/base/xml/scoped_xml_ptr.h @@ -5,12 +5,20 @@ #include "base/memory/scoped_ptr.h" #include "third_party/libxml/src/include/libxml/tree.h" +#include "third_party/libxml/src/include/libxml/xmlschemas.h" namespace dash_packager { namespace xml { struct XmlDeleter { // Called by scoped_ptr. http://goo.gl/YaLbcS + inline void operator()(xmlSchemaParserCtxtPtr ptr) const { + xmlSchemaFreeParserCtxt(ptr); + } + inline void operator()(xmlSchemaValidCtxtPtr ptr) const { + xmlSchemaFreeValidCtxt(ptr); + } + inline void operator()(xmlSchemaPtr ptr) const { xmlSchemaFree(ptr); } inline void operator()(xmlNodePtr ptr) const { xmlFreeNode(ptr); } inline void operator()(xmlDocPtr ptr) const { xmlFreeDoc(ptr); } inline void operator()(xmlChar* ptr) const { xmlFree(ptr); } diff --git a/mpd/mpd.gyp b/mpd/mpd.gyp index 4f61d99884..210b33a42e 100644 --- a/mpd/mpd.gyp +++ b/mpd/mpd.gyp @@ -1,6 +1,11 @@ # GYP file for any MPD generation targets. { + 'target_defaults': { + 'include_dirs': [ + '..', + ], + }, 'targets': [ { 'target_name': 'media_info_proto', @@ -28,14 +33,28 @@ 'base/xml/xml_node.cc', 'base/xml/xml_node.h', ], - 'include_dirs': [ - '..', - ], 'dependencies': [ '../base/base.gyp:base', '../third_party/libxml/libxml.gyp:libxml', 'media_info_proto', ], + 'export_dependent_settings': [ + '../third_party/libxml/libxml.gyp:libxml', + 'media_info_proto', + ], + }, + { + 'target_name': 'mpd_unittest', + 'type': 'executable', + 'sources': [ + 'base/mpd_builder_unittest.cc', + ], + 'dependencies': [ + '../base/base.gyp:base', + '../base/base.gyp:run_all_unittests', + '../testing/gtest.gyp:gtest', + 'mpd_builder', + ], }, ], } diff --git a/mpd/test/schema/DASH-MPD.xsd b/mpd/test/schema/DASH-MPD.xsd new file mode 100644 index 0000000000..e0eeeddaeb --- /dev/null +++ b/mpd/test/schema/DASH-MPD.xsd @@ -0,0 +1,390 @@ + + + + + + + Media Presentation Description + + This Schema defines the Media Presentation Description for MPEG-DASH. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mpd/test/schema/xlink.xsd b/mpd/test/schema/xlink.xsd new file mode 100644 index 0000000000..6f4d0a274d --- /dev/null +++ b/mpd/test/schema/xlink.xsd @@ -0,0 +1,270 @@ + + + + + This schema document provides attribute declarations and +attribute group, complex type and simple type definitions which can be used in +the construction of user schemas to define the structure of particular linking +constructs, e.g. + + + + + + + ... + + ... + + + ... +]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Intended for use as the type of user-declared elements to make them + simple links. + + + + + + + + + + + + + + + + + + + + + + + + + Intended for use as the type of user-declared elements to make them + extended links. + Note that the elements referenced in the content model are all abstract. + The intention is that by simply declaring elements with these as their + substitutionGroup, all the right things will happen. + + + + + + + + + + + + + + xml:lang is not required, but provides much of the + motivation for title elements in addition to attributes, and so + is provided here for convenience. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + label is not required, but locators have no particular + XLink function if they are not labeled. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + from and to have default behavior when values are missing + + + + + + + + + + + + + + + + + diff --git a/mpd/test/schema/xml.xsd b/mpd/test/schema/xml.xsd new file mode 100644 index 0000000000..d662b4236c --- /dev/null +++ b/mpd/test/schema/xml.xsd @@ -0,0 +1,117 @@ + + + + + + + See http://www.w3.org/XML/1998/namespace.html and + http://www.w3.org/TR/REC-xml for information about this namespace. + + This schema document describes the XML namespace, in a form + suitable for import by other schema documents. + + Note that local names in this namespace are intended to be defined + only by the World Wide Web Consortium or its subgroups. The + following names are currently defined in this namespace and should + not be used with conflicting semantics by any Working Group, + specification, or document instance: + + base (as an attribute name): denotes an attribute whose value + provides a URI to be used as the base for interpreting any + relative URIs in the scope of the element on which it + appears; its value is inherited. This name is reserved + by virtue of its definition in the XML Base specification. + + lang (as an attribute name): denotes an attribute whose value + is a language code for the natural language of the content of + any element; its value is inherited. This name is reserved + by virtue of its definition in the XML specification. + + space (as an attribute name): denotes an attribute whose + value is a keyword indicating what whitespace processing + discipline is intended for the content of the element; its + value is inherited. This name is reserved by virtue of its + definition in the XML specification. + + Father (in any context at all): denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and + XML Coordination groups: + + In appreciation for his vision, leadership and dedication + the W3C XML Plenary on this 10th day of February, 2000 + reserves for Jon Bosak in perpetuity the XML name + xml:Father + + + + + This schema defines attributes and an attribute group + suitable for use by + schemas wishing to allow xml:base, xml:lang or xml:space attributes + on elements they define. + + To enable this, such a schema must import this schema + for the XML namespace, e.g. as follows: + <schema . . .> + . . . + <import namespace="http://www.w3.org/XML/1998/namespace" + schemaLocation="http://www.w3.org/2001/03/xml.xsd"/> + + Subsequently, qualified reference to any of the attributes + or the group defined below will have the desired effect, e.g. + + <type . . .> + . . . + <attributeGroup ref="xml:specialAttrs"/> + + will define a type which will schema-validate an instance + element with any of those attributes + + + + In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + http://www.w3.org/2001/03/xml.xsd. + At the date of issue it can also be found at + http://www.w3.org/2001/xml.xsd. + The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML Schema + itself. In other words, if the XML Schema namespace changes, the version + of this document at + http://www.w3.org/2001/xml.xsd will change + accordingly; the version at + http://www.w3.org/2001/03/xml.xsd will not change. + + + + + + In due course, we should install the relevant ISO 2- and 3-letter + codes as the enumerated possible values . . . + + + + + + + + + + + + + + + See http://www.w3.org/TR/xmlbase/ for + information about this attribute. + + + + + + + + + +