diff --git a/schemas/ParameterSettings.xsd b/schemas/ParameterSettings.xsd index d95a17d88..d3a888e63 100644 --- a/schemas/ParameterSettings.xsd +++ b/schemas/ParameterSettings.xsd @@ -18,8 +18,8 @@ - - + + @@ -27,8 +27,8 @@ - - + + @@ -43,7 +43,7 @@ - + diff --git a/test/functional-tests/Handle.cpp b/test/functional-tests/Handle.cpp index d7aafb9ab..1e93e3e43 100644 --- a/test/functional-tests/Handle.cpp +++ b/test/functional-tests/Handle.cpp @@ -43,6 +43,9 @@ #include #include +#include +#include +#include #include @@ -69,6 +72,8 @@ struct AllParamsPF : public ParameterFramework + + @@ -267,78 +272,7 @@ SCENARIO_METHOD(AllParamsPF, "Export all parameters", "[handler][structure][xml] } } -struct SettingsTestPF : public AllParamsPF -{ - static string parameterBlockNode(string name, string settings) - { - return node("ParameterBlock", name, settings); - }; - static string mkBasicSettings(string settings, string name) - { - return rootNode("ParameterBlock", "Name='" + name + "'", settings); - } - - static string fullXMLSettings(const string &basicSettings) - { - string settings = basicSettings; - settings += - parameterBlockNode("parameter_block", settings) + - parameterBlockNode("parameter_block_array", parameterBlockNode("0", settings) + - parameterBlockNode("1", settings)) + - parameterBlockNode("component_scalar", settings) + - parameterBlockNode("component_array", parameterBlockNode("0", settings) + - parameterBlockNode("1", settings)); - - return rootNode("SystemClass", "Name='test'", node("Subsystem", "test", settings, "")); - } - - static string fullBytesSettings(const string &basicSettings) - { - string fullSettings; - // We have the "basic params" repeated 7 times across the test - // structure - for (size_t i = 0; i < 7; ++i) { - fullSettings += basicSettings; - } - return fullSettings; - } - - /** Print Bytes as string separated hexadecimal number. */ - static string showBytes(const Bytes &bytes) - { - using namespace std; - ostringstream ss; - ss.exceptions(ostream::badbit | ostream::failbit); - for (auto byte : bytes) { - ss << hex << setw(2) << setfill('0') << int{byte} << ' '; - } - return ss.str(); - } - - static Bytes readBytes(const string &strBytes) - { - using namespace std; - istringstream ss{strBytes}; - ss.exceptions(istream::badbit | istream::failbit); - Bytes bytes(strBytes.size() / 3); - - for (auto &byte : bytes) { - uint16_t notCharByte; - ss >> hex >> setw(2) >> notCharByte; - byte = static_cast(notCharByte); - } - return bytes; - } - - static void checkBytesEq(const Bytes &result, const string &expect) - { - checkEq(showBytes(result), expect); - } - static void checkBytesEq(const Bytes &result, const Bytes &expect) - { - checkEq(showBytes(result), showBytes(expect)); - } -}; +///////////////////////////// Test settings /////////////////////////////////// static const char *defaultBasicSettingsXML = R"( 0 @@ -347,6 +281,7 @@ static const char *defaultBasicSettingsXML = R"( -10 -10 -10 -10 0.0000 0.0000 0.0000 0.0000 + 0 min eight eight eight eight @@ -366,6 +301,7 @@ static const char *testBasicSettingsXML = R"( -10 0 8 10 2.2500 7.1250 0.6875 -1.0000 + -1.4013e-45 five eight min eight min A string of 32 character.@@@@@@@ @@ -384,6 +320,7 @@ static const char *testRawHexBasicSettingsXML = R"( 0xFFFFFFF6 0x00000000 0x00000008 0x0000000A 0x24000000 0x72000000 0x0B000000 0xF0000000 + 0x80000001 five eight min eight min A string of 32 character.@@@@@@@ @@ -396,153 +333,242 @@ static const char *testRawHexBasicSettingsXML = R"( )"; -SCENARIO_METHOD(SettingsTestPF, "Export and import XML settings", "[handler][settings][xml]") -{ - WHEN ("Exporting root XML") { - auto getAsXML = [this](string path) { return ElementHandle(*this, path).getAsXML(); }; - CHECK(getAsXML("/") == getAsXML("/test")); - checkXMLEq(getAsXML("/"), fullXMLSettings(defaultBasicSettingsXML)); - } - - ElementHandle basicParams(*this, "/test/test/parameter_block"); - WHEN ("Exporting basic parameter XML") { - checkXMLEq(basicParams.getAsXML(), - mkBasicSettings(defaultBasicSettingsXML, "parameter_block")); - } - string testSettings = mkBasicSettings(testBasicSettingsXML, "parameter_block"); - string rawTestSettings = mkBasicSettings(testRawHexBasicSettingsXML, "parameter_block"); - - auto checkExport = [&] { - THEN ("Exported settings should be the ones imported") { - checkXMLEq(basicParams.getAsXML(), testSettings); - } - THEN ("Exported raw settings should be the ones imported") { - setRawValueSpace(true); - setHexOutputFormat(true); - checkXMLEq(basicParams.getAsXML(), rawTestSettings); - } - }; - WHEN ("Importing basic parameter XML") { - CHECK_NOTHROW(basicParams.setAsXML(testSettings)); - checkExport(); - } - WHEN ("Importing raw basic parameter XML") { - CHECK_NOTHROW(basicParams.setAsXML(rawTestSettings)); - checkExport(); - } -} - static const string defaultBasicSettingsBytes = "00 00 00 21 00 f6 ff ff ff f6 ff ff ff f6 ff ff ff f6 ff ff ff 00 00 00 00 " - "00 00 00 00 00 00 00 00 00 00 00 00 80 08 00 08 00 08 00 08 00 00 00 00 00 00 " + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 08 00 08 00 08 00 08 00 00 " "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " - "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "; + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "; static const string testBasicSettingsBytes = "01 00 01 64 00 f6 ff ff ff 00 00 00 00 08 00 00 00 0a 00 00 00 00 00 00 24 " - "00 00 00 72 00 00 00 0b 00 00 00 f0 05 08 00 01 80 08 00 01 80 41 20 73 74 72 " - "69 6e 67 20 6f 66 20 33 32 20 63 68 61 72 61 63 74 65 72 2e 40 40 40 40 40 40 " - "40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " - "00 00 00 00 00 00 00 8a 02 48 00 ff ff ff ff "; + "00 00 00 72 00 00 00 0b 00 00 00 f0 01 00 00 80 05 08 00 01 80 08 00 01 80 41 " + "20 73 74 72 69 6e 67 20 6f 66 20 33 32 20 63 68 61 72 61 63 74 65 72 2e 40 40 " + "40 40 40 40 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " + "00 00 00 00 00 00 00 00 00 00 00 8a 02 48 00 ff ff ff ff "; -SCENARIO_METHOD(SettingsTestPF, "Bijection of binary show and read", "[identity][test]") +struct SettingsTestPF : public AllParamsPF { - CHECK(showBytes(readBytes(testBasicSettingsBytes)) == testBasicSettingsBytes); -} + enum class Type { + xml, + rawHexXml, + binary + }; -SCENARIO_METHOD(SettingsTestPF, "Export and import root binary settings", - "[handler][settings][bytes]") -{ - ElementHandle root(*this, "/"); - ElementHandle systemClass(*this, "/"); + struct TestVector { + string description; + string path; + struct Value { + string description; + struct View { + Type type; + string value; + }; + list views; + }; + Value initial; + list values; + }; - THEN ("Root and system class should export the same binary") { - checkBytesEq(root.getAsBytes(), systemClass.getAsBytes()); - } - WHEN ("Exporting root binary") { - checkBytesEq(root.getAsBytes(), fullBytesSettings(defaultBasicSettingsBytes)); + static string parameterBlockNode(string name, string settings) + { + return node("ParameterBlock", name, settings); + }; + static string mkBasicSettings(string settings, string name) + { + return rootNode("ParameterBlock", "Name='" + name + "'", settings); } - WHEN ("Importing root binary") { - string rootTestSettings = fullBytesSettings(testBasicSettingsBytes); - REQUIRE_NOTHROW(root.setAsBytes(readBytes(rootTestSettings))); - THEN ("Exported settings should be the ones imported") { - checkBytesEq(root.getAsBytes(), rootTestSettings); + + const TestVector basicParamsTest = + { + "Basic parameters", + "/test/test/parameter_block_array/0", + { + "Default values", + { + { Type::xml, mkBasicSettings(defaultBasicSettingsXML, "0") }, + { Type::binary, defaultBasicSettingsBytes } + } + }, + { // values to test, for now there is only one set + { + "Arbitrary values", + { + { Type::xml, mkBasicSettings(testBasicSettingsXML, "0") }, + { Type::rawHexXml, mkBasicSettings(testRawHexBasicSettingsXML, "0") }, + { Type::binary, testBasicSettingsBytes } + } + }, } + }; + + static string fullXMLSettings(const string &basicSettings) + { + string settings = basicSettings; + settings += + parameterBlockNode("parameter_block", settings) + + parameterBlockNode("parameter_block_array", parameterBlockNode("0", settings) + + parameterBlockNode("1", settings)) + + parameterBlockNode("component_scalar", settings) + + parameterBlockNode("component_array", parameterBlockNode("0", settings) + + parameterBlockNode("1", settings)); + + return rootNode("SystemClass", "Name='test'", node("Subsystem", "test", settings, "")); } -} -SCENARIO_METHOD(SettingsTestPF, "Export and import basic binary settings", - "[handler][settings][bytes]") -{ - ElementHandle basicParams(*this, "/test/test/parameter_block"); - WHEN ("Exporting basic parameter binary") { - checkBytesEq(basicParams.getAsBytes(), defaultBasicSettingsBytes); + static string fullBytesSettings(const string &basicSettings) + { + string fullSettings; + // The "basic params" are repeated 7 times across the test structure + for (size_t i = 0; i < 7; ++i) { + fullSettings += basicSettings; + } + return fullSettings; } - WHEN ("Importing basic parameter binary") { - REQUIRE_NOTHROW(basicParams.setAsBytes(readBytes(testBasicSettingsBytes))); - THEN ("Exported settings should be the ones imported") { - checkBytesEq(basicParams.getAsBytes(), testBasicSettingsBytes); + + const TestVector rootTest = + { + "root parameters (== system class)", + "/", + { + "Default values", + { + { Type::xml, fullXMLSettings(defaultBasicSettingsXML) }, + { Type::binary, fullBytesSettings(defaultBasicSettingsBytes) } + } + }, + { // values to test, for now there is only one set + { + "Arbitrary values", + { + { Type::xml, fullXMLSettings(testBasicSettingsXML) }, + { Type::rawHexXml, fullXMLSettings(testRawHexBasicSettingsXML) }, + { Type::binary, fullBytesSettings(testBasicSettingsBytes) } + } + }, + } + }; + + const list testVectors = {basicParamsTest, rootTest, + { "system class parameters", "/test", rootTest.initial, rootTest.values } + }; + + void checkValue(ElementHandle &handle, TestVector::Value::View view) + { + THEN("Get the node value should return the expected " + to_string(view.type) + " one" ) { + switch (view.type) { + case Type::rawHexXml: + setRawValueSpace(true); + setHexOutputFormat(true); + case Type::xml: + checkXMLEq(handle.getAsXML(), view.value); + setRawValueSpace(false); + setHexOutputFormat(false); + break; + case Type::binary: + checkBytesEq(handle.getAsBytes(), view.value); + } } } -} -SCENARIO_METHOD(SettingsTestPF, "Export and import array binary settings", - "[handler][settings][bytes]") -{ - ElementHandle array(*this, "/test/test/parameter_block_array"); - ElementHandle elem0(*this, "/test/test/parameter_block_array/0"); - WHEN ("Importing one array element") { - REQUIRE_NOTHROW(elem0.setAsBytes(readBytes(testBasicSettingsBytes))); - THEN ("The other element should not have changed") { - checkBytesEq(array.getAsBytes(), testBasicSettingsBytes + defaultBasicSettingsBytes); + void setValue(ElementHandle &handle, TestVector::Value::View view) + { + switch (view.type) { + case Type::rawHexXml: + case Type::xml: + REQUIRE_NOTHROW(handle.setAsXML(view.value)); + break; + case Type::binary: + REQUIRE_NOTHROW(handle.setAsBytes(readBytes(view.value))); } + } -} -SCENARIO_METHOD(SettingsTestPF, "Import root in one format, export in an other", - "[handler][settings][bytes][xml]") -{ - ElementHandle root(*this, "/test"); - string rootBytesSettings = fullBytesSettings(testBasicSettingsBytes); - string rootXMLSettings = fullXMLSettings(testBasicSettingsXML); - - WHEN ("Importing root binary") { - REQUIRE_NOTHROW(root.setAsBytes(readBytes(rootBytesSettings))); - THEN ("Exported XML settings should be the ones imported") { - checkXMLEq(root.getAsXML(), rootXMLSettings); + static string to_string(Type type) + { + switch (type) { + case Type::xml: return "XML"; + case Type::rawHexXml: return "raw hexadecimal XML"; + case Type::binary: return "binary"; } } - WHEN ("Importing root XML") { - REQUIRE_NOTHROW(root.setAsXML(rootXMLSettings)); - THEN ("Exported bytes settings should be the ones imported") { - checkBytesEq(root.getAsBytes(), rootBytesSettings); + /** Print Bytes as string separated hexadecimal number. */ + static string showBytes(const Bytes &bytes) + { + using namespace std; + ostringstream ss; + ss.exceptions(ostream::badbit | ostream::failbit); + for (auto byte : bytes) { + ss << hex << setw(2) << setfill('0') << int{byte} << ' '; } + return ss.str(); } -} -SCENARIO_METHOD(SettingsTestPF, "Import basic params in one format, export in an other", - "[handler][settings][bytes][xml]") -{ - ElementHandle basicParams(*this, "/test/test/parameter_block_array/0"); - string basicXMLSettings = mkBasicSettings(testBasicSettingsXML, "0"); + static Bytes readBytes(const string &strBytes) + { + using namespace std; + istringstream ss{strBytes}; + ss.exceptions(istream::badbit | istream::failbit); + Bytes bytes(strBytes.size() / 3); - WHEN ("Importing basic parameters binary") { - REQUIRE_NOTHROW(basicParams.setAsBytes(readBytes(testBasicSettingsBytes))); - THEN ("Exported XML settings should be the ones imported") { - checkXMLEq(basicParams.getAsXML(), basicXMLSettings); + for (auto &byte : bytes) { + uint16_t notCharByte; + ss >> hex >> setw(2) >> notCharByte; + byte = static_cast(notCharByte); } + return bytes; } - WHEN ("Importing basic parameters XML") { - REQUIRE_NOTHROW(basicParams.setAsXML(basicXMLSettings)); - THEN ("Exported bytes settings should be the ones imported") { - checkBytesEq(basicParams.getAsBytes(), testBasicSettingsBytes); + static void checkBytesEq(const Bytes &result, const string &expect) + { + checkEq(showBytes(result), expect); + } + static void checkBytesEq(const Bytes &result, const Bytes &expect) + { + checkEq(showBytes(result), showBytes(expect)); + } +}; + + +SCENARIO_METHOD(SettingsTestPF, "Bijection of binary show and read", "[identity][test]") +{ + CHECK(showBytes(readBytes(testBasicSettingsBytes)) == testBasicSettingsBytes); +} + + +SCENARIO_METHOD(SettingsTestPF, "Test initial values", "[handler][settings][init]") +{ + for (auto &testVector : testVectors) { + GIVEN("The element " + testVector.path + ": " + testVector.description) { + ElementHandle handle(*this, testVector.path); + GIVEN("The initial value of this node: " + testVector.initial.description) { + for (auto &view : testVector.initial.views) { + checkValue(handle, view); + } + } + // Get a list of all possible values of the node + auto values = testVector.values; + values.push_back(testVector.initial); + // Set then get all values for each view + for (auto &value : values) { + GIVEN("A value" + value.description) { + for(auto &view : value.views) { + WHEN("Setting the value as " + to_string(view.type)) { + setValue(handle, view); + for(auto &view : value.views) { + checkValue(handle, view); + } + } + } + } + } } } } +//////////////////////////////// Test mapping ///////////////////////////////// + struct MappingPF : public ParameterFramework { MappingPF() : ParameterFramework{getConfig()} { REQUIRE_NOTHROW(start()); } diff --git a/xmlserializer/XmlElement.cpp b/xmlserializer/XmlElement.cpp index c54d97e70..7de1687f6 100644 --- a/xmlserializer/XmlElement.cpp +++ b/xmlserializer/XmlElement.cpp @@ -30,6 +30,9 @@ #include "XmlElement.h" #include #include "convert.hpp" + +#include +#include #include using std::string; @@ -204,6 +207,26 @@ void CXmlElement::setAttribute(const string &name, const string &va setAttribute(name, value.c_str()); } +template <> +void CXmlElement::setAttribute(const string &name, const float &value) +{ + std::ostringstream ss; + ss << std::setprecision(6) // max nb digit=`ceil(log10(2^23))=6`, 23=float fraction part + << value; + + setAttribute(name, ss.str()); +} + +template <> +void CXmlElement::setAttribute(const string &name, const double &value) +{ + std::ostringstream ss; + ss << std::setprecision(16) // max nb digit=`ceil(log10(2^52))=16`, 52=double fraction part + << value; + + setAttribute(name, ss.str()); +} + // This method exists for 2 reasons: // - at link time, all calls to setAttribute(const string&, const char [N]) // for any value of N will all resolve to this method; this prevents the