1 /*
2  * Copyright (c) 2015, Intel Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this
9  * list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation and/or
13  * other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software without
17  * specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "Config.hpp"
32 #include "Test.hpp"
33 #include "Exception.hpp"
34 #include "TmpFile.hpp"
35 
36 #include "ParameterFramework.hpp"
37 #include "ElementHandle.hpp"
38 
39 #include <catch.hpp>
40 
41 #include <libxml/parser.h>
42 #include <libxml/tree.h>
43 
44 #include <string>
45 #include <list>
46 
47 #include <stdlib.h>
48 
49 using std::string;
50 using std::list;
51 using Bytes = std::vector<uint8_t>;
52 
53 namespace parameterFramework
54 {
55 
56 struct AllParamsPF : public ParameterFramework
57 {
AllParamsPFparameterFramework::AllParamsPF58     AllParamsPF() : ParameterFramework{getConfig()} { REQUIRE_NOTHROW(start()); }
59 
getBasicParamsparameterFramework::AllParamsPF60     string getBasicParams()
61     {
62         string structure = R"(
63             <BooleanParameter Name="bool" Description="bool"/>
64             <BooleanParameter ArrayLength="2" Name="bool_array" Description="bool-array"/>
65 
66             <IntegerParameter Signed="false" Min="33" Max="123" Size="16" Name="integer"/>
67             <IntegerParameter Signed="true" Min="-10" Max="10" Size="32" ArrayLength="4" Name="integer_array"/>
68 
69             <FixedPointParameter Size="32" Integral="3" Fractional="4" Name="fix_point"/>
70             <FixedPointParameter Size="32" Integral="3" Fractional="4" ArrayLength="3" Name="fix_point_array"/>
71 
72             <EnumParameter Size="8" Name="enum">
73                 <ValuePair Literal="min"  Numerical="-128"/>
74                 <ValuePair Literal="five" Numerical="5"/>
75                 <ValuePair Literal="max"  Numerical="127"/>
76             </EnumParameter>
77             <EnumParameter Size="16" ArrayLength="4" Name="enum_array">
78                 <ValuePair Literal="eight"  Numerical="8"/>
79                 <ValuePair Literal="min"  Numerical="-32767"/>
80             </EnumParameter>)";
81 
82         // String and bit parameter arrays are not supported
83         structure += R"(
84             <StringParameter MaxLength="63" Name="string"/>
85 
86             <BitParameterBlock Size="64" Name="bit_block">
87                 <BitParameter Pos="1"  Size="1"  Max="1"  Name="one"/>
88                 <BitParameter Pos="2"  Size="2"  Max="2"  Name="two"/>
89                 <BitParameter Pos="6"  Size="6"  Max="10" Name="six"/>
90                 <BitParameter Pos="16" Size="16" Max="99" Name="sixteen"/>
91                 <BitParameter Pos="32" Size="32" Max="4294967295" Name="thirty_two"/>
92             </BitParameterBlock>
93             )";
94         return structure;
95     }
96 
getConfigparameterFramework::AllParamsPF97     Config getConfig()
98     {
99         Config config;
100         config.components = nodeDesc("ComponentType", "component_type", getBasicParams());
101         config.instances =
102             getBasicParams() + nodeDesc("ParameterBlock", "parameter_block", getBasicParams()) +
103             nodeDesc("ParameterBlock", "parameter_block_array", getBasicParams(),
104                      "ArrayLength='2'") +
105             nodeDesc("Component", "component_scalar", "", "Type='component_type'") +
106             nodeDesc("Component", "component_array", "", "Type='component_type' ArrayLength='2'");
107         return config;
108     }
109 
checkStructureparameterFramework::AllParamsPF110     void checkStructure(const string &path, const string &expected)
111     {
112         CHECK_NOTHROW(checkXMLEq(ElementHandle{*this, path}.getStructureAsXML(), expected));
113     }
114 
115     /** Use libxml2 to pretty format xml.
116      * Equivalent of xmllint --format
117      */
canonicalizeXMLparameterFramework::AllParamsPF118     static string canonicalizeXML(const string &xml)
119     {
120         // Parse xml
121         // Might be better to specialize std::default_delete<xmlDoc>.
122         std::unique_ptr<xmlDoc, void (*)(xmlDoc *)> doc{
123             xmlReadMemory(xml.c_str(), (int)xml.length(), "structure.xml", nullptr,
124                           XML_PARSE_NOBLANKS),
125             xmlFreeDoc};
126         if (doc == nullptr) {
127             throw Exception{"Failed to parse document: " + xml};
128         }
129 
130         // Dump it formated
131         int size;
132 
133         // Need to use exception unsafe raw pointer as of libxml2 c api
134         xmlChar *unsafeFormated;
135 
136         // TODO: Should use canonicalization (aka c14n).
137         //       cf: http://xmlsoft.org/html/libxml-c14n.html
138         //           https://en.wikipedia.org/wiki/Canonical_XML
139         //       Additionally to what is listed on that page,
140         //       attributes are also ordered deterministically.
141         //       That would solve the workaround in the node function with pre/post attributes.
142         //       Unfortunately c14n is not available in appveyor (Windows CI) libxml2 prebuild
143         xmlDocDumpFormatMemoryEnc(doc.get(), &unsafeFormated, &size, "UTF-8", 1);
144         std::unique_ptr<xmlChar, void (*)(void *)> formated{unsafeFormated, xmlFree};
145 
146         if (formated == nullptr) {
147             throw Exception{"Could not dump xml: " + xml};
148         }
149 
150         return string{(char *)formated.get()};
151     }
152 
checkEqparameterFramework::AllParamsPF153     static void checkEq(const string &result, const string &expected)
154     {
155         CHECK(result == expected);
156 
157         // Pretty print the word differences with colors
158         // It does not matter if it fails as the test would still fail
159         // due to the above CHECK.
160         if (result != expected) {
161             utility::TmpFile resultFile(result);
162             utility::TmpFile expectedFile(expected);
163             string command = "git --no-pager diff --word-diff-regex='[^ <>]+'"
164                              "                    --color --no-index --exit-code " +
165                              resultFile.getPath() + ' ' + expectedFile.getPath();
166 
167             // `system` return -1 or 127 on failure, the command error code otherwise
168             // `git diff` return 1 if the files are the different (thanks to --exit-code)
169             auto status = system(command.c_str());
170 #ifdef WIFEXITED // Posix platform
171             bool success = WIFEXITED(status) and WEXITSTATUS(status) == 1;
172 #else
173             bool success = status == 1;
174 #endif
175             if (not success) {
176                 WARN("Warning: Failed to pretty-print the difference between "
177                      "actual and expected results with `git diff'");
178             }
179         }
180     }
181 
checkXMLEqparameterFramework::AllParamsPF182     static void checkXMLEq(const string &result, const string &expected)
183     {
184         checkEq(canonicalizeXML(result), canonicalizeXML(expected));
185     }
186 
nodeparameterFramework::AllParamsPF187     static string node(string tag, string name, string content, string attributes = "",
188                        string postAttributes = "")
189     {
190         return "<" + tag + " " + attributes + " Name='" + name + "' " + postAttributes + ">" +
191                content + "</" + tag + ">";
192     }
193     /** Node with a description.
194      * @param[in] maybeDescription If nullptr, description will be generated from the name
195      *                             Otherwise, the description.
196      */
nodeDescparameterFramework::AllParamsPF197     static string nodeDesc(string tag, string name, string content, string attributes = "",
198                            const char *maybeDescription = nullptr)
199     {
200         string description = "description_" + name;
201         if (maybeDescription != nullptr) {
202             description = maybeDescription;
203         }
204         return node(tag, name, content, attributes, "Description='" + description + "'");
205     }
206 
rootNodeparameterFramework::AllParamsPF207     static string rootNode(string name, string attributes, string content)
208     {
209         return '<' + name + ' ' + attributes + '>' + content + "</" + name + '>';
210     }
211 };
212 
213 SCENARIO_METHOD(AllParamsPF, "Export boolean", "[handler][structure][xml]")
214 {
215     string expected = rootNode("BooleanParameter", "Name='bool' Description='bool'", "");
216     checkStructure("/test/test/bool", expected);
217 }
218 
219 SCENARIO_METHOD(AllParamsPF, "Export component", "[handler][structure][xml]")
220 {
221     string expected = rootNode("ParameterBlock", "Name='component_scalar' "
222                                                  "Description='description_component_scalar'",
223                                getBasicParams());
224     checkStructure("/test/test/component_scalar", expected);
225 }
226 
227 SCENARIO_METHOD(AllParamsPF, "Export component array", "[handler][structure][xml]")
228 {
229     string expected = rootNode(
230         "ParameterBlock", "Name='component_array' Description='description_component_array'",
231         nodeDesc("ParameterBlock", "0", getBasicParams(), "", "description_component_array") +
232             nodeDesc("ParameterBlock", "1", getBasicParams(), "", "description_component_array"));
233     checkStructure("/test/test/component_array", expected);
234 }
235 
236 SCENARIO_METHOD(AllParamsPF, "Export all parameters", "[handler][structure][xml]")
237 {
238     string paramExpected = getBasicParams() +
239                            nodeDesc("ParameterBlock", "parameter_block", getBasicParams()) +
240                            nodeDesc("ParameterBlock", "parameter_block_array",
241                                     nodeDesc("ParameterBlock", "0", getBasicParams(), "",
242                                              // description is inherited from array
243                                              "description_parameter_block_array") +
244                                         nodeDesc("ParameterBlock", "1", getBasicParams(), "",
245                                                  "description_parameter_block_array")) +
246                            // Components should be exported as parameterBlock
247                            nodeDesc("ParameterBlock", "component_scalar", getBasicParams()) +
248                            nodeDesc("ParameterBlock", "component_array",
249                                     nodeDesc("ParameterBlock", "0", getBasicParams(), "",
250                                              // description is inherited from array
251                                              "description_component_array") +
252                                         nodeDesc("ParameterBlock", "1", getBasicParams(), "",
253                                                  "description_component_array"));
254 
255     WHEN ("Exporting subsystem") {
256         string expected = rootNode("Subsystem", "Name='test'", paramExpected);
257         checkStructure("/test/test", expected);
258     }
259 
260     WHEN ("Exporting systemClass") {
261         string expected = rootNode("SystemClass", "Name='test'",
262                                    "<Subsystem Name='test'>" + paramExpected + "</Subsystem>");
263 
264         // Awkwardly, the root and its first child are the same element
265         checkStructure("/test", expected);
266         checkStructure("/", expected);
267     }
268 }
269 
270 struct SettingsTestPF : public AllParamsPF
271 {
parameterBlockNodeparameterFramework::SettingsTestPF272     static string parameterBlockNode(string name, string settings)
273     {
274         return node("ParameterBlock", name, settings);
275     };
mkBasicSettingsparameterFramework::SettingsTestPF276     static string mkBasicSettings(string settings, string name)
277     {
278         return rootNode("ParameterBlock", "Name='" + name + "'", settings);
279     }
280 
fullXMLSettingsparameterFramework::SettingsTestPF281     static string fullXMLSettings(const string &basicSettings)
282     {
283         string settings = basicSettings;
284         settings +=
285             parameterBlockNode("parameter_block", settings) +
286             parameterBlockNode("parameter_block_array", parameterBlockNode("0", settings) +
287                                                             parameterBlockNode("1", settings)) +
288             parameterBlockNode("component_scalar", settings) +
289             parameterBlockNode("component_array", parameterBlockNode("0", settings) +
290                                                       parameterBlockNode("1", settings));
291 
292         return rootNode("SystemClass", "Name='test'", node("Subsystem", "test", settings, ""));
293     }
294 
fullBytesSettingsparameterFramework::SettingsTestPF295     static string fullBytesSettings(const string &basicSettings)
296     {
297         string fullSettings;
298         // We have the "basic params" repeated 7 times across the test
299         // structure
300         for (size_t i = 0; i < 7; ++i) {
301             fullSettings += basicSettings;
302         }
303         return fullSettings;
304     }
305 
306     /** Print Bytes as string separated hexadecimal number. */
showBytesparameterFramework::SettingsTestPF307     static string showBytes(const Bytes &bytes)
308     {
309         using namespace std;
310         ostringstream ss;
311         ss.exceptions(ostream::badbit | ostream::failbit);
312         for (auto byte : bytes) {
313             ss << hex << setw(2) << setfill('0') << int{byte} << ' ';
314         }
315         return ss.str();
316     }
317 
readBytesparameterFramework::SettingsTestPF318     static Bytes readBytes(const string &strBytes)
319     {
320         using namespace std;
321         istringstream ss{strBytes};
322         ss.exceptions(istream::badbit | istream::failbit);
323         Bytes bytes(strBytes.size() / 3);
324 
325         for (auto &byte : bytes) {
326             uint16_t notCharByte;
327             ss >> hex >> setw(2) >> notCharByte;
328             byte = static_cast<char>(notCharByte);
329         }
330         return bytes;
331     }
332 
checkBytesEqparameterFramework::SettingsTestPF333     static void checkBytesEq(const Bytes &result, const string &expect)
334     {
335         checkEq(showBytes(result), expect);
336     }
checkBytesEqparameterFramework::SettingsTestPF337     static void checkBytesEq(const Bytes &result, const Bytes &expect)
338     {
339         checkEq(showBytes(result), showBytes(expect));
340     }
341 };
342 
343 static const char *defaultBasicSettingsXML = R"(
344       <BooleanParameter Name="bool">0</BooleanParameter>
345       <BooleanParameter Name="bool_array">0 0</BooleanParameter>
346       <IntegerParameter Name="integer">33</IntegerParameter>
347       <IntegerParameter Name="integer_array">-10 -10 -10 -10</IntegerParameter>
348       <FixedPointParameter Name="fix_point">0.0000</FixedPointParameter>
349       <FixedPointParameter Name="fix_point_array">0.0000 0.0000 0.0000</FixedPointParameter>
350       <EnumParameter Name="enum">min</EnumParameter>
351       <EnumParameter Name="enum_array">eight eight eight eight</EnumParameter>
352       <StringParameter Name="string"></StringParameter>
353       <BitParameterBlock Name="bit_block">
354         <BitParameter Name="one">0</BitParameter>
355         <BitParameter Name="two">0</BitParameter>
356         <BitParameter Name="six">0</BitParameter>
357         <BitParameter Name="sixteen">0</BitParameter>
358         <BitParameter Name="thirty_two">0</BitParameter>
359       </BitParameterBlock>
360 )";
361 
362 static const char *testBasicSettingsXML = R"(
363       <BooleanParameter Name="bool">1</BooleanParameter>
364       <BooleanParameter Name="bool_array">0 1</BooleanParameter>
365       <IntegerParameter Name="integer">100</IntegerParameter>
366       <IntegerParameter Name="integer_array">-10 0 8 10</IntegerParameter>
367       <FixedPointParameter Name="fix_point">2.2500</FixedPointParameter>
368       <FixedPointParameter Name="fix_point_array">7.1250 0.6875 -1.0000</FixedPointParameter>
369       <EnumParameter Name="enum">five</EnumParameter>
370       <EnumParameter Name="enum_array">eight min eight min</EnumParameter>
371       <StringParameter Name="string">A string of 32 character.@@@@@@@</StringParameter>
372       <BitParameterBlock Name="bit_block">
373         <BitParameter Name="one">1</BitParameter>
374         <BitParameter Name="two">2</BitParameter>
375         <BitParameter Name="six">10</BitParameter>
376         <BitParameter Name="sixteen">72</BitParameter>
377         <BitParameter Name="thirty_two">4294967295</BitParameter>
378       </BitParameterBlock>
379 )";
380 static const char *testRawHexBasicSettingsXML = R"(
381       <BooleanParameter Name="bool">0x1</BooleanParameter>
382       <BooleanParameter Name="bool_array">0x0 0x1</BooleanParameter>
383       <IntegerParameter Name="integer">0x0064</IntegerParameter>
384       <IntegerParameter Name="integer_array">0xFFFFFFF6 0x00000000 0x00000008 0x0000000A</IntegerParameter>
385       <FixedPointParameter ValueSpace="Raw" Name="fix_point">0x24000000</FixedPointParameter>
386       <FixedPointParameter ValueSpace="Raw" Name="fix_point_array">0x72000000 0x0B000000 0xF0000000</FixedPointParameter>
387       <EnumParameter Name="enum">five</EnumParameter>
388       <EnumParameter Name="enum_array">eight min eight min</EnumParameter>
389       <StringParameter Name="string">A string of 32 character.@@@@@@@</StringParameter>
390       <BitParameterBlock Name="bit_block">
391         <BitParameter Name="one">0x1</BitParameter>
392         <BitParameter Name="two">0x2</BitParameter>
393         <BitParameter Name="six">0xA</BitParameter>
394         <BitParameter Name="sixteen">0x48</BitParameter>
395         <BitParameter Name="thirty_two">0xFFFFFFFF</BitParameter>
396       </BitParameterBlock>
397 )";
398 
399 SCENARIO_METHOD(SettingsTestPF, "Export and import XML settings", "[handler][settings][xml]")
400 {
401     WHEN ("Exporting root XML") {
__anona126b54a0102(string path) 402         auto getAsXML = [this](string path) { return ElementHandle(*this, path).getAsXML(); };
403         CHECK(getAsXML("/") == getAsXML("/test"));
404         checkXMLEq(getAsXML("/"), fullXMLSettings(defaultBasicSettingsXML));
405     }
406 
407     ElementHandle basicParams(*this, "/test/test/parameter_block");
408     WHEN ("Exporting basic parameter XML") {
409         checkXMLEq(basicParams.getAsXML(),
410                    mkBasicSettings(defaultBasicSettingsXML, "parameter_block"));
411     }
412     string testSettings = mkBasicSettings(testBasicSettingsXML, "parameter_block");
413     string rawTestSettings = mkBasicSettings(testRawHexBasicSettingsXML, "parameter_block");
414 
__anona126b54a0202null415     auto checkExport = [&] {
416         THEN ("Exported settings should be the ones imported") {
417             checkXMLEq(basicParams.getAsXML(), testSettings);
418         }
419         THEN ("Exported raw settings should be the ones imported") {
420             setRawValueSpace(true);
421             setHexOutputFormat(true);
422             checkXMLEq(basicParams.getAsXML(), rawTestSettings);
423         }
424     };
425     WHEN ("Importing basic parameter XML") {
426         CHECK_NOTHROW(basicParams.setAsXML(testSettings));
427         checkExport();
428     }
429     WHEN ("Importing raw basic parameter XML") {
430         CHECK_NOTHROW(basicParams.setAsXML(rawTestSettings));
431         checkExport();
432     }
433 }
434 
435 static const string defaultBasicSettingsBytes =
436     "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 "
437     "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 "
438     "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 "
439     "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 "
440     "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ";
441 
442 static const string testBasicSettingsBytes =
443     "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 "
444     "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 "
445     "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 "
446     "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 "
447     "00 00 00 00 00 00 00 8a 02 48 00 ff ff ff ff ";
448 
449 SCENARIO_METHOD(SettingsTestPF, "Bijection of binary show and read", "[identity][test]")
450 {
451     CHECK(showBytes(readBytes(testBasicSettingsBytes)) == testBasicSettingsBytes);
452 }
453 
454 SCENARIO_METHOD(SettingsTestPF, "Export and import root binary settings",
455                 "[handler][settings][bytes]")
456 {
457     ElementHandle root(*this, "/");
458     ElementHandle systemClass(*this, "/");
459 
460     THEN ("Root and system class should export the same binary") {
461         checkBytesEq(root.getAsBytes(), systemClass.getAsBytes());
462     }
463     WHEN ("Exporting root binary") {
464         checkBytesEq(root.getAsBytes(), fullBytesSettings(defaultBasicSettingsBytes));
465     }
466     WHEN ("Importing root binary") {
467         string rootTestSettings = fullBytesSettings(testBasicSettingsBytes);
468         REQUIRE_NOTHROW(root.setAsBytes(readBytes(rootTestSettings)));
469         THEN ("Exported settings should be the ones imported") {
470             checkBytesEq(root.getAsBytes(), rootTestSettings);
471         }
472     }
473 }
474 
475 SCENARIO_METHOD(SettingsTestPF, "Export and import basic binary settings",
476                 "[handler][settings][bytes]")
477 {
478     ElementHandle basicParams(*this, "/test/test/parameter_block");
479     WHEN ("Exporting basic parameter binary") {
480         checkBytesEq(basicParams.getAsBytes(), defaultBasicSettingsBytes);
481     }
482     WHEN ("Importing basic parameter binary") {
483         REQUIRE_NOTHROW(basicParams.setAsBytes(readBytes(testBasicSettingsBytes)));
484         THEN ("Exported settings should be the ones imported") {
485             checkBytesEq(basicParams.getAsBytes(), testBasicSettingsBytes);
486         }
487     }
488 }
489 
490 SCENARIO_METHOD(SettingsTestPF, "Export and import array binary settings",
491                 "[handler][settings][bytes]")
492 {
493     ElementHandle array(*this, "/test/test/parameter_block_array");
494     ElementHandle elem0(*this, "/test/test/parameter_block_array/0");
495     WHEN ("Importing one array element") {
496         REQUIRE_NOTHROW(elem0.setAsBytes(readBytes(testBasicSettingsBytes)));
497         THEN ("The other element should not have changed") {
498             checkBytesEq(array.getAsBytes(), testBasicSettingsBytes + defaultBasicSettingsBytes);
499         }
500     }
501 }
502 
503 SCENARIO_METHOD(SettingsTestPF, "Import root in one format, export in an other",
504                 "[handler][settings][bytes][xml]")
505 {
506     ElementHandle root(*this, "/test");
507     string rootBytesSettings = fullBytesSettings(testBasicSettingsBytes);
508     string rootXMLSettings = fullXMLSettings(testBasicSettingsXML);
509 
510     WHEN ("Importing root binary") {
511         REQUIRE_NOTHROW(root.setAsBytes(readBytes(rootBytesSettings)));
512         THEN ("Exported XML settings should be the ones imported") {
513             checkXMLEq(root.getAsXML(), rootXMLSettings);
514         }
515     }
516 
517     WHEN ("Importing root XML") {
518         REQUIRE_NOTHROW(root.setAsXML(rootXMLSettings));
519         THEN ("Exported bytes settings should be the ones imported") {
520             checkBytesEq(root.getAsBytes(), rootBytesSettings);
521         }
522     }
523 }
524 
525 SCENARIO_METHOD(SettingsTestPF, "Import basic params in one format, export in an other",
526                 "[handler][settings][bytes][xml]")
527 {
528     ElementHandle basicParams(*this, "/test/test/parameter_block_array/0");
529     string basicXMLSettings = mkBasicSettings(testBasicSettingsXML, "0");
530 
531     WHEN ("Importing basic parameters binary") {
532         REQUIRE_NOTHROW(basicParams.setAsBytes(readBytes(testBasicSettingsBytes)));
533         THEN ("Exported XML settings should be the ones imported") {
534             checkXMLEq(basicParams.getAsXML(), basicXMLSettings);
535         }
536     }
537 
538     WHEN ("Importing basic parameters XML") {
539         REQUIRE_NOTHROW(basicParams.setAsXML(basicXMLSettings));
540         THEN ("Exported bytes settings should be the ones imported") {
541             checkBytesEq(basicParams.getAsBytes(), testBasicSettingsBytes);
542         }
543     }
544 }
545 
546 struct MappingPF : public ParameterFramework
547 {
MappingPFparameterFramework::MappingPF548     MappingPF() : ParameterFramework{getConfig()} { REQUIRE_NOTHROW(start()); }
549 
550     struct TestVector
551     {
552         string path;
553         string humanReadable;
554         list<string> valid;
555         list<string> invalid;
556     };
557 
558     list<TestVector> testVectors = {
559         // clang-format off
560         {"/test/test",
561             {"rootK:rootV"},
562             {"root"},
563             {"param", "type", "instance", "derived"}},
564         {"/test/test/param",
565             {"rootK:rootV, paramK:paramV"},
566             {"root", "param"},
567             {"type", "derived", "instance"}},
568         {"/test/test/component",
569             {"rootK:rootV, typeK:typeV, derivedK:derivedV, instanceK:instanceV"},
570             {"root", "type", "derived", "instance"},
571             {"param"}}
572         // clang-format on
573     };
574 
getConfigparameterFramework::MappingPF575     Config getConfig()
576     {
577         Config config;
578         config.subsystemMapping = "rootK:rootV";
579         config.components = "<ComponentType   Name='componentType' Mapping='typeK:typeV'        />"
580                             "<ComponentType   Extends='componentType' Name='derivedComponentType' "
581                             "Mapping='derivedK:derivedV' />";
582         config.instances = "<BooleanParameter Name='param'         Mapping='paramK:paramV'      />"
583                            "<Component        Name='component'     Mapping='instanceK:instanceV'  "
584                            "           Type='derivedComponentType'                              />";
585         return config;
586     }
587 };
588 
589 SCENARIO_METHOD(MappingPF, "showMapping command", "[mapping]")
590 {
591     auto cmdHandler = std::unique_ptr<CommandHandlerInterface>(createCommandHandler());
592 
593     for (auto &testVector : testVectors) {
594         string output;
595         CHECK(cmdHandler->process("showMapping", {testVector.path}, output));
596         CHECK(output == testVector.humanReadable);
597     }
598 }
599 
600 SCENARIO_METHOD(MappingPF, "Mapping handle access", "[handler][mapping]")
601 {
602     GIVEN ("A PF with mappings") {
603         for (auto &test : testVectors) {
604             GIVEN ("An element handle of " + test.path) {
605                 ElementHandle handle(*this, test.path);
606 
607                 for (auto &valid : test.valid) {
608                     THEN ("The following mapping should exist: " + valid) {
609                         CHECK(handle.getMappingData(valid + "K") == valid + "V");
610                     }
611                 }
612 
613                 for (auto &invalid : test.invalid) {
614                     THEN ("The following mapping should not exist: " + invalid) {
615                         CHECK_THROWS_AS(handle.getMappingData(invalid + "K"), Exception);
616                     }
617                 }
618             }
619         }
620     }
621 }
622 
623 SCENARIO_METHOD(SettingsTestPF, "Handle Get/Set as various kinds", "[handler][dynamic]")
624 {
625     ElementHandle intScalar(*this, "/test/test/parameter_block/integer");
626     WHEN ("Setting a scalar integer") {
627         WHEN ("As an array") {
628             THEN ("It should fail") {
629                 CHECK_THROWS(intScalar.setAsIntegerArray({0, 0}));
630             }
631         }
632         WHEN ("As a scalalar") {
633             THEN ("It should succeed") {
634                 uint32_t expected = 111;
635                 CHECK_NOTHROW(intScalar.setAsInteger(expected));
636                 AND_THEN ("Getting it back should give the same value") {
637                     uint32_t back = 42;
638                     CHECK_NOTHROW(intScalar.getAsInteger(back));
639                     CHECK(back == expected);
640                 }
641             }
642         }
643     }
644 
645     ElementHandle intArray(*this, "/test/test/parameter_block/integer_array");
646     WHEN ("Setting a array integer") {
647         WHEN ("As a scalar") {
648             THEN ("It should fail") {
649                 CHECK_THROWS(intArray.setAsSignedInteger(0));
650             }
651         }
652         WHEN ("As a integer") {
653             THEN ("It should succeed") {
654                 const std::vector<int32_t> expected = {-9, 8, -7, 6};
655                 CHECK_NOTHROW(intArray.setAsSignedIntegerArray(expected));
656                 AND_THEN ("Getting it back should give the same value") {
657                     std::vector<int32_t> back = {-42, 42, 43, -43};
658                     CHECK_NOTHROW(intArray.getAsSignedIntegerArray(back));
659                     CHECK(back == expected);
660                 }
661             }
662         }
663     }
664 }
665 } // namespace parameterFramework
666