From a7d9a86641e9e793c29e670394f7219536d7eb72 Mon Sep 17 00:00:00 2001 From: Thomas Nixon Date: Mon, 10 Oct 2022 10:08:11 +0100 Subject: [PATCH 1/8] fix typo in comment --- include/adm/elements/screen_edge_lock.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/adm/elements/screen_edge_lock.hpp b/include/adm/elements/screen_edge_lock.hpp index 76273d0c..cf346eea 100644 --- a/include/adm/elements/screen_edge_lock.hpp +++ b/include/adm/elements/screen_edge_lock.hpp @@ -8,7 +8,7 @@ namespace adm { - /// @brief Tag for NamedTyoe ::ScreenEdge + /// @brief Tag for NamedType ::ScreenEdge struct ScreenEdgeTag {}; /** * @brief NamedType for the screen edge From b817d8cff8773e201745fd896ccf7b58ef8d1cd5 Mon Sep 17 00:00:00 2001 From: Thomas Nixon Date: Mon, 10 Oct 2022 10:08:19 +0100 Subject: [PATCH 2/8] fix typo in comment --- include/adm/elements/time.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/adm/elements/time.hpp b/include/adm/elements/time.hpp index 4c86fe0a..65116ecb 100644 --- a/include/adm/elements/time.hpp +++ b/include/adm/elements/time.hpp @@ -33,7 +33,7 @@ namespace adm { } /// normalised fraction, such that numerator and denominator have no common - /// fractors + /// factors ADM_EXPORT FractionalTime normalised() const; private: From fc8f26c8bbf32636288a84c55c2166ac0a967782 Mon Sep 17 00:00:00 2001 From: Thomas Nixon Date: Wed, 2 Nov 2022 15:45:39 +0000 Subject: [PATCH 3/8] fix typo in comment --- include/adm/utilities/object_creation.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/adm/utilities/object_creation.hpp b/include/adm/utilities/object_creation.hpp index 432a35a1..a4e3fe16 100644 --- a/include/adm/utilities/object_creation.hpp +++ b/include/adm/utilities/object_creation.hpp @@ -57,7 +57,7 @@ namespace adm { ADM_EXPORT SimpleObjectHolder createSimpleObject(const std::string& name); /** - * @brief Create and add `AudioObject` hierarchie for single + * @brief Create and add `AudioObject` hierarchy for single * `TypeDefinition::OBJECTS`-type element * * same as `createSimpleObject`, but the elements are automatically added to From b9bffa41da22b05c8b1ea4d2e32c013c039c2385 Mon Sep 17 00:00:00 2001 From: Thomas Nixon Date: Mon, 10 Oct 2022 11:32:47 +0100 Subject: [PATCH 4/8] accept non-shared-pointer types in check_vector_param --- tests/helper/parameter_checks.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/helper/parameter_checks.hpp b/tests/helper/parameter_checks.hpp index 82074b38..1ba8ef86 100644 --- a/tests/helper/parameter_checks.hpp +++ b/tests/helper/parameter_checks.hpp @@ -162,7 +162,7 @@ namespace adm_test { } template - void check_vector_param(std::shared_ptr element, + void check_vector_param(ElementT element, detail::CanBeSetTo modifiedVal) { detail::check_vector_impl(detail::get_from_shared(element), modifiedVal.get()); From 95d9abd90bfa55741fac703d302df8c1dee6debc Mon Sep 17 00:00:00 2001 From: Thomas Nixon Date: Mon, 10 Oct 2022 14:46:33 +0100 Subject: [PATCH 5/8] add utility for checking required options passed to constructors --- include/adm/detail/named_option_helper.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/adm/detail/named_option_helper.hpp b/include/adm/detail/named_option_helper.hpp index 46bd7092..f9f31721 100644 --- a/include/adm/detail/named_option_helper.hpp +++ b/include/adm/detail/named_option_helper.hpp @@ -17,5 +17,17 @@ namespace adm { setNamedOptionHelper(std::forward(element), std::move(args)...); } + /// check that the first template type is present in the remainder + template + constexpr bool optionInList() { + return false; + } + + template + constexpr bool optionInList() { + using ParamT = std::remove_const_t>; + return std::is_same::value || optionInList(); + } + } // namespace detail } // namespace adm From e9491317e23320629aa7b9f68e4be5f97e06b08a Mon Sep 17 00:00:00 2001 From: Thomas Nixon Date: Mon, 10 Oct 2022 14:56:31 +0100 Subject: [PATCH 6/8] add parseValue with default parser --- include/adm/private/xml_parser_helper.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/adm/private/xml_parser_helper.hpp b/include/adm/private/xml_parser_helper.hpp index c8b71fde..d45e8362 100644 --- a/include/adm/private/xml_parser_helper.hpp +++ b/include/adm/private/xml_parser_helper.hpp @@ -313,6 +313,11 @@ namespace adm { } } + template + NT parseValue(NodePtr node) { + return parseValue(node, detail::parseDefault); + } + template void setValue(NodePtr node, Target& target, Callable parser) { detail::invokeSet(target, parseValue(node, parser)); From dad326078dbfb4387c73550d1a24e63ea05d1e6c Mon Sep 17 00:00:00 2001 From: Thomas Nixon Date: Mon, 10 Oct 2022 16:43:13 +0100 Subject: [PATCH 7/8] implement profileList --- include/adm/document.hpp | 23 +++- include/adm/elements.hpp | 1 + include/adm/elements/profile_list.hpp | 116 ++++++++++++++++++++ include/adm/private/rapidxml_formatter.hpp | 2 + include/adm/private/xml_parser.hpp | 2 + src/CMakeLists.txt | 1 + src/document.cpp | 4 + src/elements/profile_list.cpp | 11 ++ src/private/rapidxml_formatter.cpp | 11 ++ src/private/xml_parser.cpp | 22 ++++ src/private/xml_writer.cpp | 1 + tests/CMakeLists.txt | 1 + tests/profile_list_tests.cpp | 68 ++++++++++++ tests/test_data/profile_list.accepted.xml | 14 +++ tests/test_data/xml_parser/profile_list.xml | 13 +++ 15 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 include/adm/elements/profile_list.hpp create mode 100644 src/elements/profile_list.cpp create mode 100644 tests/profile_list_tests.cpp create mode 100644 tests/test_data/profile_list.accepted.xml create mode 100644 tests/test_data/xml_parser/profile_list.xml diff --git a/include/adm/document.hpp b/include/adm/document.hpp index 3d7a3ed8..b48b87ad 100644 --- a/include/adm/document.hpp +++ b/include/adm/document.hpp @@ -4,18 +4,28 @@ #include #include #include "adm/elements.hpp" +#include "adm/detail/auto_base.hpp" #include "adm/detail/id_assigner.hpp" #include "adm/export.h" namespace adm { + namespace detail { + extern template class ADM_EXPORT_TEMPLATE_METHODS + OptionalParameter; + + using DocumentBase = HasParameters>; + } // namespace detail + /** * @ingroup main * @brief Class representation of a whole ADM document * @headerfile document.hpp * */ - class Document : public std::enable_shared_from_this { + class Document : public std::enable_shared_from_this, + private detail::DocumentBase, + public detail::AddWrapperMethods { public: /** * @brief Static helper function to create an Document @@ -202,6 +212,12 @@ namespace adm { const AudioTrackUidId &trackUidId) const; ///@} + using detail::DocumentBase::set; + using detail::AddWrapperMethods::get; + using detail::AddWrapperMethods::has; + using detail::AddWrapperMethods::isDefault; + using detail::AddWrapperMethods::unset; + private: ADM_EXPORT Document(); ADM_EXPORT Document(const Document &) = default; @@ -251,6 +267,11 @@ namespace adm { template bool checkParent(const std::shared_ptr &element, const char *type); + using detail::DocumentBase::get; + using detail::DocumentBase::has; + + friend class detail::AddWrapperMethods; + std::vector> audioProgrammes_; std::vector> audioContents_; std::vector> audioObjects_; diff --git a/include/adm/elements.hpp b/include/adm/elements.hpp index d6172373..9fdf9366 100644 --- a/include/adm/elements.hpp +++ b/include/adm/elements.hpp @@ -26,6 +26,7 @@ #include "adm/elements/audio_track_format.hpp" #include "adm/elements/audio_stream_format.hpp" #include "adm/elements/audio_track_uid.hpp" +#include "adm/elements/profile_list.hpp" #include "adm/elements/audio_block_format_direct_speakers.hpp" #include "adm/elements/audio_block_format_matrix.hpp" diff --git a/include/adm/elements/profile_list.hpp b/include/adm/elements/profile_list.hpp new file mode 100644 index 00000000..245a54a9 --- /dev/null +++ b/include/adm/elements/profile_list.hpp @@ -0,0 +1,116 @@ +#pragma once +#include +#include "adm/detail/auto_base.hpp" +#include "adm/detail/named_option_helper.hpp" +#include "adm/detail/optional_comparison.hpp" + +namespace adm { + struct ProfileValueTag {}; + using ProfileValue = detail::NamedType; + + struct ProfileNameTag {}; + using ProfileName = detail::NamedType; + + struct ProfileVersionTag {}; + using ProfileVersion = detail::NamedType; + + struct ProfileLevelTag {}; + using ProfileLevel = detail::NamedType; + + struct ProfileTag {}; + + namespace detail { + extern template class ADM_EXPORT_TEMPLATE_METHODS + RequiredParameter; + extern template class ADM_EXPORT_TEMPLATE_METHODS + RequiredParameter; + extern template class ADM_EXPORT_TEMPLATE_METHODS + RequiredParameter; + extern template class ADM_EXPORT_TEMPLATE_METHODS + RequiredParameter; + + using ProfileBase = HasParameters< + RequiredParameter, RequiredParameter, + RequiredParameter, RequiredParameter>; + } // namespace detail + + class Profile : private detail::ProfileBase, + public detail::AddWrapperMethods { + public: + using tag = ProfileTag; + + template + explicit Profile(Parameters... namedArgs) { + detail::setNamedOptionHelper(this, std::move(namedArgs)...); + static_assert(detail::optionInList(), + "ProfileValue must be specified"); + static_assert(detail::optionInList(), + "ProfileName must be specified"); + static_assert(detail::optionInList(), + "ProfileVersion must be specified"); + static_assert(detail::optionInList(), + "ProfileLevel must be specified"); + } + + using detail::ProfileBase::set; + using detail::AddWrapperMethods::get; + using detail::AddWrapperMethods::has; + using detail::AddWrapperMethods::isDefault; + using detail::AddWrapperMethods::unset; + + private: + using detail::ProfileBase::get; + using detail::ProfileBase::has; + + friend class detail::AddWrapperMethods; + }; + + inline bool operator==(const Profile &a, const Profile &b) { + return detail::optionalsEqual(a, b); + } + + inline bool operator!=(const Profile &a, const Profile &b) { + return !(a == b); + } + + struct ProfilesTag {}; + + using Profiles = std::vector; + ADD_TRAIT(Profiles, ProfilesTag); + + namespace detail { + extern template class ADM_EXPORT_TEMPLATE_METHODS VectorParameter; + + using ProfileListBase = HasParameters>; + } // namespace detail + + struct ProfileceListTag {}; + + class ProfileList : private detail::ProfileListBase, + public detail::AddWrapperMethods { + public: + using tag = ProfileceListTag; + + template + explicit ProfileList(Parameters... namedArgs) { + detail::setNamedOptionHelper(this, std::move(namedArgs)...); + } + + using detail::ProfileListBase::set; + using detail::AddWrapperMethods::get; + using detail::AddWrapperMethods::has; + using detail::AddWrapperMethods::isDefault; + using detail::AddWrapperMethods::unset; + using detail::ProfileListBase::add; + using detail::ProfileListBase::remove; + + private: + using detail::ProfileListBase::get; + using detail::ProfileListBase::has; + using detail::ProfileListBase::isDefault; + using detail::ProfileListBase::unset; + + friend class detail::AddWrapperMethods; + }; +} // namespace adm diff --git a/include/adm/private/rapidxml_formatter.hpp b/include/adm/private/rapidxml_formatter.hpp index d14012c7..6f9c8313 100644 --- a/include/adm/private/rapidxml_formatter.hpp +++ b/include/adm/private/rapidxml_formatter.hpp @@ -47,6 +47,8 @@ namespace adm { const std::shared_ptr trackFormat); void formatAudioTrackUid( XmlNode &node, const std::shared_ptr trackUid); + void formatProfileList(XmlNode &node, const ProfileList &profileList); + void formatProfile(XmlNode &node, const Profile &profile); void formatBlockFormatDirectSpeakers( XmlNode &node, const AudioBlockFormatDirectSpeakers &audioBlock); diff --git a/include/adm/private/xml_parser.hpp b/include/adm/private/xml_parser.hpp index 64929521..f5bfbf63 100644 --- a/include/adm/private/xml_parser.hpp +++ b/include/adm/private/xml_parser.hpp @@ -64,6 +64,7 @@ namespace adm { HeadphoneVirtualise parseHeadphoneVirtualise(NodePtr node); AudioBlockFormatHoa parseAudioBlockFormatHoa(NodePtr node); AudioBlockFormatBinaural parseAudioBlockFormatBinaural(NodePtr node); + Profile parseProfile(NodePtr node); NodePtr findAudioFormatExtendedNodeEbuCore(NodePtr root); NodePtr findAudioFormatExtendedNodeFullRecursive(NodePtr root); @@ -94,6 +95,7 @@ namespace adm { std::shared_ptr parseAudioPackFormat(NodePtr node); std::shared_ptr parseAudioTrackUid(NodePtr node); std::shared_ptr parseAudioChannelFormat(NodePtr node); + ProfileList parseProfileList(NodePtr node); rapidxml::file<> xmlFile_; ParserOptions options_; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 931a0dfb..81283ff8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -48,6 +48,7 @@ add_library(adm elements/position.cpp elements/position_offset.cpp elements/position_interaction_range.cpp + elements/profile_list.cpp elements/screen_edge_lock.cpp elements/speaker_position.cpp elements/type_descriptor.cpp diff --git a/src/document.cpp b/src/document.cpp index 58099975..c88cbfd5 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -9,6 +9,10 @@ #include namespace adm { + namespace detail { + template class OptionalParameter; + } // namespace detail + Document::Document() { idAssigner_.document(this); } std::shared_ptr Document::create() { diff --git a/src/elements/profile_list.cpp b/src/elements/profile_list.cpp new file mode 100644 index 00000000..62bd7249 --- /dev/null +++ b/src/elements/profile_list.cpp @@ -0,0 +1,11 @@ +#include "adm/elements/profile_list.hpp" + +namespace adm { + namespace detail { + template class RequiredParameter; + template class RequiredParameter; + template class RequiredParameter; + template class RequiredParameter; + template class VectorParameter; + } // namespace detail +} // namespace adm diff --git a/src/private/rapidxml_formatter.cpp b/src/private/rapidxml_formatter.cpp index c1931a70..e38eee6f 100644 --- a/src/private/rapidxml_formatter.cpp +++ b/src/private/rapidxml_formatter.cpp @@ -672,5 +672,16 @@ namespace adm { trackUid, "audioPackFormatIDRef"); } + void formatProfileList(XmlNode &node, const ProfileList &profileList) { + node.addVectorElements(&profileList, "profile", &formatProfile); + } + + void formatProfile(XmlNode &node, const Profile &profile) { + node.setValue(profile.get()); + node.addAttribute(&profile, "profileName"); + node.addAttribute(&profile, "profileVersion"); + node.addAttribute(&profile, "profileLevel"); + } + } // namespace xml } // namespace adm diff --git a/src/private/xml_parser.cpp b/src/private/xml_parser.cpp index ee79c944..55d2aa55 100644 --- a/src/private/xml_parser.cpp +++ b/src/private/xml_parser.cpp @@ -76,6 +76,11 @@ namespace adm { add(parseAudioStreamFormat(node)); } else if (nodeName == "audioTrackFormat") { add(parseAudioTrackFormat(node)); + } else if (nodeName == "profileList") { + if (document_->has()) + throw error::XmlParsingError( + "found more than one profileList element"); + document_->set(parseProfileList(node)); } } resolveReferences(programmeContentRefs_); @@ -460,6 +465,23 @@ namespace adm { return audioTrackUid; } + ProfileList XmlParser::parseProfileList(NodePtr node) { + ProfileList profileList; + + addOptionalElements(node, "profile", profileList, &parseProfile); + + return profileList; + } + + Profile parseProfile(NodePtr node) { + auto value = parseValue(node); + auto name = parseAttribute(node, "profileName"); + auto version = parseAttribute(node, "profileVersion"); + auto level = parseAttribute(node, "profileLevel"); + + return Profile{value, name, version, level}; + } + AudioBlockFormatDirectSpeakers parseAudioBlockFormatDirectSpeakers( NodePtr node) { AudioBlockFormatDirectSpeakers audioBlockFormat; diff --git a/src/private/xml_writer.cpp b/src/private/xml_writer.cpp index a68bca19..29a95d68 100644 --- a/src/private/xml_writer.cpp +++ b/src/private/xml_writer.cpp @@ -38,6 +38,7 @@ namespace adm { root = xmlDocument.addEbuStructure(); } // clang-format off + root.addOptionalElement(document, "profileList", &formatProfileList); root.addBaseElements(document, "audioProgramme", &formatAudioProgramme); root.addBaseElements(document, "audioContent", &formatAudioContent); root.addBaseElements(document, "audioObject", &formatAudioObject); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8b4a396b..610f484c 100755 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -64,6 +64,7 @@ add_adm_test("object_divergence_tests") add_adm_test("position_interaction_range_tests") add_adm_test("position_tests") add_adm_test("position_offset_tests") +add_adm_test("profile_list_tests") add_adm_test("route_tracer_tests") add_adm_test("screen_edge_lock_tests") add_adm_test("speaker_position_tests") diff --git a/tests/profile_list_tests.cpp b/tests/profile_list_tests.cpp new file mode 100644 index 00000000..8301fee1 --- /dev/null +++ b/tests/profile_list_tests.cpp @@ -0,0 +1,68 @@ +#include +#include "adm/elements/profile_list.hpp" +#include "helper/parameter_checks.hpp" +#include "adm/document.hpp" +#include "adm/parse.hpp" +#include "adm/write.hpp" +#include "helper/file_comparator.hpp" + +using namespace adm; +using namespace adm_test; + +TEST_CASE("Profile parameters") { + Profile profile{ + ProfileValue{"value"}, + ProfileName{"name"}, + ProfileVersion{"version"}, + ProfileLevel{"level"}, + }; + + check_required_param(profile, + hasDefaultOf(ProfileValue{"value"}), + canBeSetTo(ProfileValue{"value2"})); + check_required_param(profile, hasDefaultOf(ProfileName{"name"}), + canBeSetTo(ProfileName{"name2"})); + check_required_param(profile, + hasDefaultOf(ProfileVersion{"version"}), + canBeSetTo(ProfileVersion{"version2"})); + check_required_param(profile, + hasDefaultOf(ProfileLevel{"level"}), + canBeSetTo(ProfileLevel{"level2"})); +} + +TEST_CASE("ProfileList parameters") { + ProfileList profileList; + + Profile profile{ + ProfileValue{"value"}, + ProfileName{"name"}, + ProfileVersion{"version"}, + ProfileLevel{"level"}, + }; + + check_vector_param(profileList, canBeSetTo(Profiles{profile})); +} + +TEST_CASE("xml/profileList") { + auto document = parseXml("xml_parser/profile_list.xml"); + + REQUIRE(document->has()); + auto profileList = document->get(); + auto profiles = profileList.get(); + REQUIRE(profiles.size() == 2); + + CHECK(profiles.at(0).get() == "value1"); + CHECK(profiles.at(0).get() == "name1"); + CHECK(profiles.at(0).get() == "version1"); + CHECK(profiles.at(0).get() == "level1"); + + CHECK(profiles.at(1).get() == "value2"); + CHECK(profiles.at(1).get() == "name2"); + CHECK(profiles.at(1).get() == "version2"); + CHECK(profiles.at(1).get() == "level2"); + + std::stringstream xml; + writeXml(xml, document); + + CHECK_THAT(xml.str(), EqualsXmlFile("profile_list")); +} diff --git a/tests/test_data/profile_list.accepted.xml b/tests/test_data/profile_list.accepted.xml new file mode 100644 index 00000000..9644e85a --- /dev/null +++ b/tests/test_data/profile_list.accepted.xml @@ -0,0 +1,14 @@ + + + + + + + value1 + value2 + + + + + + diff --git a/tests/test_data/xml_parser/profile_list.xml b/tests/test_data/xml_parser/profile_list.xml new file mode 100644 index 00000000..78049f11 --- /dev/null +++ b/tests/test_data/xml_parser/profile_list.xml @@ -0,0 +1,13 @@ + + + + + + + value1 + value2 + + + + + From c9c168b3f349625734ba836f3d6f9794d7e5560e Mon Sep 17 00:00:00 2001 From: Thomas Nixon Date: Fri, 4 Nov 2022 11:00:44 +0000 Subject: [PATCH 8/8] add audioFormatExtended version --- include/adm/document.hpp | 14 ++++++++++++- src/document.cpp | 1 + src/private/xml_parser.cpp | 2 ++ src/private/xml_writer.cpp | 1 + tests/CMakeLists.txt | 1 + tests/test_data/version.accepted.xml | 9 ++++++++ tests/test_data/xml_parser/version.xml | 9 ++++++++ tests/version_tests.cpp | 29 ++++++++++++++++++++++++++ 8 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 tests/test_data/version.accepted.xml create mode 100644 tests/test_data/xml_parser/version.xml create mode 100644 tests/version_tests.cpp diff --git a/include/adm/document.hpp b/include/adm/document.hpp index b48b87ad..62a8fd0c 100644 --- a/include/adm/document.hpp +++ b/include/adm/document.hpp @@ -2,19 +2,29 @@ #pragma once #include +#include #include #include "adm/elements.hpp" #include "adm/detail/auto_base.hpp" #include "adm/detail/id_assigner.hpp" +#include "adm/detail/named_type.hpp" #include "adm/export.h" namespace adm { + /// tag for version + struct VersionTag {}; + /// NamedType for audioFormatExtended version attribute + using Version = detail::NamedType; + namespace detail { extern template class ADM_EXPORT_TEMPLATE_METHODS OptionalParameter; + extern template class ADM_EXPORT_TEMPLATE_METHODS + OptionalParameter; - using DocumentBase = HasParameters>; + using DocumentBase = HasParameters, + OptionalParameter>; } // namespace detail /** @@ -269,6 +279,8 @@ namespace adm { using detail::DocumentBase::get; using detail::DocumentBase::has; + using detail::DocumentBase::isDefault; + using detail::DocumentBase::unset; friend class detail::AddWrapperMethods; diff --git a/src/document.cpp b/src/document.cpp index c88cbfd5..2091ff14 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -11,6 +11,7 @@ namespace adm { namespace detail { template class OptionalParameter; + template class OptionalParameter; } // namespace detail Document::Document() { idAssigner_.document(this); } diff --git a/src/private/xml_parser.cpp b/src/private/xml_parser.cpp index 55d2aa55..4d9da1c0 100644 --- a/src/private/xml_parser.cpp +++ b/src/private/xml_parser.cpp @@ -97,6 +97,8 @@ namespace adm { resolveReference(streamFormatChannelFormatRef_); resolveReference(streamFormatPackFormatRef_); resolveReferences(streamFormatTrackFormatRefs_); + + setOptionalAttribute(root, "version", document_); } else { throw error::XmlParsingError("audioFormatExtended node not found"); } diff --git a/src/private/xml_writer.cpp b/src/private/xml_writer.cpp index 29a95d68..01506b99 100644 --- a/src/private/xml_writer.cpp +++ b/src/private/xml_writer.cpp @@ -38,6 +38,7 @@ namespace adm { root = xmlDocument.addEbuStructure(); } // clang-format off + root.addOptionalAttribute(document, "version"); root.addOptionalElement(document, "profileList", &formatProfileList); root.addBaseElements(document, "audioProgramme", &formatAudioProgramme); root.addBaseElements(document, "audioContent", &formatAudioContent); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 610f484c..b3319516 100755 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -69,6 +69,7 @@ add_adm_test("route_tracer_tests") add_adm_test("screen_edge_lock_tests") add_adm_test("speaker_position_tests") add_adm_test("type_descriptor_tests") +add_adm_test("version_tests") add_adm_test("xml_audio_block_format_objects_tests") add_adm_test("xml_loudness_metadata_tests") add_adm_test("xml_parser_audio_block_format_direct_speakers_tests") diff --git a/tests/test_data/version.accepted.xml b/tests/test_data/version.accepted.xml new file mode 100644 index 00000000..edc7e1af --- /dev/null +++ b/tests/test_data/version.accepted.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/tests/test_data/xml_parser/version.xml b/tests/test_data/xml_parser/version.xml new file mode 100644 index 00000000..1f8b60ca --- /dev/null +++ b/tests/test_data/xml_parser/version.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/tests/version_tests.cpp b/tests/version_tests.cpp new file mode 100644 index 00000000..462c54b7 --- /dev/null +++ b/tests/version_tests.cpp @@ -0,0 +1,29 @@ +#include +#include "adm/elements/profile_list.hpp" +#include "helper/parameter_checks.hpp" +#include "adm/document.hpp" +#include "adm/parse.hpp" +#include "adm/write.hpp" +#include "helper/file_comparator.hpp" + +using namespace adm; +using namespace adm_test; + +TEST_CASE("version") { + auto document = Document::create(); + + check_optional_param(document, + canBeSetTo(Version{"ITU-R_BS.2076-2"})); +} + +TEST_CASE("xml/version") { + auto document = parseXml("xml_parser/version.xml"); + + REQUIRE(document->has()); + REQUIRE(document->get().get() == "ITU-R_BS.2076-2"); + + std::stringstream xml; + writeXml(xml, document); + + CHECK_THAT(xml.str(), EqualsXmlFile("version")); +}