• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "ParameterFramework.h"
32 
33 #include "TmpFile.hpp"
34 
35 #define CATCH_CONFIG_MAIN // This tells Catch to provide a main()
36 #include <catch.hpp>
37 
38 #include <string>
39 #include <memory>
40 #include <vector>
41 #include <array>
42 
43 #include <cstring>
44 #include <cerrno>
45 #include <climits>
46 
47 struct Test
48 {
49     /** @return true if str is empty. */
emptyTest50     bool empty(const char *str)
51     {
52         REQUIRE(str != NULL);
53         return *str == '\0';
54     }
55 
REQUIRE_FAILURETest56     void REQUIRE_FAILURE(bool success)
57     {
58         THEN ("It should be an error") {
59             INFO("Previous pfw log: \n" + logLines);
60             CAPTURE(pfwGetLastError(pfw));
61             CHECK(not success);
62             CHECK(not empty(pfwGetLastError(pfw)));
63         }
64     }
65 
REQUIRE_SUCCESSTest66     void REQUIRE_SUCCESS(bool success)
67     {
68         THEN ("It should be a success") {
69             INFO("Previous pfw log: \n" + logLines);
70             CAPTURE(pfwGetLastError(pfw));
71             CHECK(success);
72             CHECK(empty(pfwGetLastError(pfw)));
73         }
74     }
75 
76     /** Wrap utility::TmpFile to add an implicit convertion to the temporary file.
77      *
78      * This avoids dozens of .getPath() in the following tests. */
79     class TmpFile : private parameterFramework::utility::TmpFile
80     {
81     private:
82         using Base = parameterFramework::utility::TmpFile;
83 
84     public:
85         using Base::TmpFile;
86 
87         using Base::getPath;
88         /** Implicitly convert to the path of the temporary file. */
operator const char*() const89         operator const char *() const { return getPath().c_str(); }
90     };
91 
92     /** Log in logLines. */
logCbTest93     static void logCb(void *voidLogLines, PfwLogLevel level, const char *logLine)
94     {
95         std::string &logLines = *reinterpret_cast<std::string *>(voidLogLines);
96         switch (level) {
97         case pfwLogWarning:
98             logLines += "Warning: ";
99             break;
100         case pfwLogInfo:
101             logLines += "Info: ";
102         }
103         logLines += logLine;
104         logLines += '\n';
105     }
106 
107     /** Log buffer, will only be display in case of failure */
108     std::string logLines;
109 
110     /** Pfw handler used in the tests. */
111     PfwHandler *pfw;
112 };
113 
114 TEST_CASE_METHOD(Test, "Parameter-framework c api use")
115 {
116     // Create criteria
117     const char *letterList[] = {"a", "b", "c", NULL};
118     const char *numberList[] = {"1", "2", "3", NULL};
119     const PfwCriterion criteria[] = {
120         {"inclusiveCrit", true, letterList}, {"exclusiveCrit", false, numberList},
121     };
122     size_t criterionNb = sizeof(criteria) / sizeof(criteria[0]);
123     PfwLogger logger = {&logLines, logCb};
124 
125     // Create valid pfw config file
126     const char *intParameterPath = "/test/system/integer";
127     const char *stringParameterPath = "/test/system/string";
128     TmpFile system("<?xml version='1.0' encoding='UTF-8'?>\
129         <Subsystem Name='system' Type='Virtual'>\
130             <ComponentLibrary/>\
131             <InstanceDefinition>\
132                 <IntegerParameter Name='integer' Size='32' Signed='true' Max='100'/>\
133                 <StringParameter Name='string' MaxLength='9'/>\
134             </InstanceDefinition>\
135         </Subsystem>");
136     TmpFile libraries("<?xml version='1.0' encoding='UTF-8'?>\
137         <SystemClass Name='test'>\
138             <SubsystemInclude Path='" +
139                       system.getPath() + "'/>\
140         </SystemClass>");
141     TmpFile config("<?xml version='1.0' encoding='UTF-8'?>\
142         <ParameterFrameworkConfiguration\
143             SystemClassName='test' TuningAllowed='false'>\
144             <SubsystemPlugins/>\
145             <StructureDescriptionFileLocation Path='" +
146                    libraries.getPath() + "'/>\
147         </ParameterFrameworkConfiguration>");
148 
149     GIVEN ("A created parameter framework") {
150         pfw = pfwCreate();
151         REQUIRE(pfw != NULL);
152 
153         THEN ("Error message should be empty") {
154             CHECK(empty(pfwGetLastError(pfw)));
155         }
156 
157         WHEN ("The pfw is started without an existent file") {
158             REQUIRE_FAILURE(pfwStart(pfw, "/doNotExist", criteria, criterionNb, &logger));
159         }
160 
161         WHEN ("The pfw is started with duplicated criterion value") {
162             const PfwCriterion duplicatedCriteria[] = {
163                 {"duplicated name", true, letterList}, {"duplicated name", false, numberList},
164             };
165             REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 2, &logger));
166         }
167         WHEN ("The pfw is started with duplicated criterion value state") {
168             const char *values[] = {"a", "a", NULL};
169             const PfwCriterion duplicatedCriteria[] = {{"name", true, values}};
170 
171             WHEN ("Using test logger") {
172                 REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
173             }
174             WHEN ("Using default logger") {
175                 // Test coverage of default logger warning
176                 REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, NULL));
177             }
178         }
179         WHEN ("The pfw is started with NULL name criterion") {
180             const PfwCriterion duplicatedCriteria[] = {{NULL, true, letterList}};
181             REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
182         }
183         WHEN ("The pfw is started with NULL criterion state list") {
184             const PfwCriterion duplicatedCriteria[] = {{"name", true, NULL}};
185             REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
186         }
187         GIVEN ("A criteria with lots of values") {
188             // Build a criterion with as many value as there is bits in int.
189             std::vector<char> names(sizeof(int) * CHAR_BIT + 1, 'a');
190             names.back() = '\0';
191             std::vector<const char *> values(names.size());
192             for (size_t i = 0; i < values.size(); ++i) {
193                 values[i] = &names[i];
194             }
195             values.back() = NULL;
196             /* The pfw c api requires criterion values to be a NULL terminated
197              * array of string. Each string is a pointer to a NULL terminated
198              * array of char. The pfw requires each string to be different
199              * from all others, ie strcmp(values[i], values[j]) != 0 for any
200              * i j.
201              *
202              * In order to generate easily an array of different strings,
203              * instantiate one string (names) big enough
204              * (@see PfwCriterion::values).
205              * Then instantiate an array of pointer (values),
206              * each pointing to a different position in the previously
207              * created string.
208              *
209              * Representation of the names and values vectors.
210              *
211              * n = number of bit in an int
212              *            <--- n+1 elements --->
213              * names    = |a|a|a|a|...|a|a|a|\0|
214              *             ^ ^             ^
215              * values[0] = ´ |             |
216              * values[1] = --´             |
217              * ...                         |
218              * values[n - 1] =  -----------´
219              * values[n] = NULL
220              *
221              */
222             const PfwCriterion duplicatedCriteria[] = {{"name", true, &values[0]}};
223 
224             WHEN ("The pfw is started with a too long criterion state list") {
225                 REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
226             }
227             WHEN ("The pfw is started with max length criterion state list") {
228                 values[values.size() - 2] = NULL; // Hide last value
229                 REQUIRE_SUCCESS(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
230             }
231         }
232 
233         WHEN ("The pfw is started with zero criteria") {
234             REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, 0, &logger));
235         }
236 
237         WHEN ("The pfw is started twice a pfw") {
238             REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, &logger));
239             REQUIRE_FAILURE(pfwStart(pfw, config, criteria, criterionNb, &logger));
240         }
241 
242         WHEN ("The pfw is started without a logger callback") {
243             PfwLogger noLog = {NULL, NULL};
244             REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, &noLog));
245         }
246         WHEN ("The pfw is started with default logger") {
247             REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, NULL));
248         }
249 
250         WHEN ("Get criterion of a stopped pfw") {
251             int value;
252             REQUIRE_FAILURE(pfwGetCriterion(pfw, criteria[0].name, &value));
253         }
254         WHEN ("Set criterion of a stopped pfw") {
255             REQUIRE_FAILURE(pfwSetCriterion(pfw, criteria[0].name, 1));
256         }
257         WHEN ("Commit criteria of a stopped pfw") {
258             REQUIRE_FAILURE(pfwApplyConfigurations(pfw));
259         }
260 
261         WHEN ("Bind parameter with a stopped pfw") {
262             REQUIRE(pfwBindParameter(pfw, intParameterPath) == NULL);
263         }
264 
265         WHEN ("The pfw is started correctly") {
266             REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, &logger));
267             int value;
268 
269             WHEN ("Get not existing criterion") {
270                 REQUIRE_FAILURE(pfwGetCriterion(pfw, "Do not exist", &value));
271             }
272             THEN ("All criterion should value 0") {
273                 for (size_t i = 0; i < criterionNb; ++i) {
274                     const char *criterionName = criteria[i].name;
275                     CAPTURE(criterionName);
276                     REQUIRE_SUCCESS(pfwGetCriterion(pfw, criterionName, &value));
277                     REQUIRE(value == 0);
278                 }
279             }
280 
281             WHEN ("Set not existing criterion") {
282                 REQUIRE_FAILURE(pfwSetCriterion(pfw, "Do not exist", 3));
283             }
284             WHEN ("Set criterion value") {
285                 for (size_t i = 0; i < criterionNb; ++i) {
286                     const char *criterionName = criteria[i].name;
287                     CAPTURE(criterionName);
288                     REQUIRE_SUCCESS(pfwSetCriterion(pfw, criterionName, 3));
289                 }
290                 THEN ("Get criterion value should return what was set") {
291                     for (size_t i = 0; i < criterionNb; ++i) {
292                         const char *criterionName = criteria[i].name;
293                         CAPTURE(criterionName);
294                         REQUIRE_SUCCESS(pfwGetCriterion(pfw, criterionName, &value));
295                         REQUIRE(value == 3);
296                     }
297                 }
298                 WHEN ("Set a new value to a criterion without committing first") {
299                     const char *criterionName = criteria[0].name;
300                     REQUIRE_SUCCESS(pfwSetCriterion(pfw, criterionName, 0));
301                     THEN ("A warning message should have been displayed") {
302                         INFO("Previous pfw log: \n" + logLines);
303                         size_t logPos = logLines.find("Warning: Selection criterion "
304                                                       "'inclusiveCrit' has been modified 1 time(s)"
305                                                       " without any configuration application");
306                         CHECK(logPos != std::string::npos);
307                     }
308                 }
309             }
310             WHEN ("Commit criteria of a started pfw") {
311                 REQUIRE_SUCCESS(pfwApplyConfigurations(pfw));
312             }
313             WHEN ("Bind a non existing parameter") {
314                 REQUIRE_FAILURE(pfwBindParameter(pfw, "do/not/exist") != NULL);
315             }
316 
317             GIVEN ("An integer parameter handle") {
318                 PfwParameterHandler *param = pfwBindParameter(pfw, intParameterPath);
319                 REQUIRE_SUCCESS(param != NULL);
320 
321                 WHEN ("Set parameter out of range") {
322                     REQUIRE_FAILURE(pfwSetIntParameter(param, 101));
323                 }
324 
325                 WHEN ("Set parameter") {
326                     REQUIRE_SUCCESS(pfwSetIntParameter(param, 11));
327                     THEN ("Get parameter should return what was set") {
328                         REQUIRE_SUCCESS(pfwGetIntParameter(param, &value));
329                         REQUIRE(value == 11);
330                     }
331                 }
332 
333                 pfwUnbindParameter(param);
334             }
335 
336             GIVEN ("An string parameter handle") {
337                 PfwParameterHandler *param = pfwBindParameter(pfw, stringParameterPath);
338                 REQUIRE_SUCCESS(param != NULL);
339 
340                 WHEN ("Set parameter out of range") {
341                     REQUIRE_FAILURE(pfwSetStringParameter(param, "ko_1234567"));
342                 }
343 
344                 WHEN ("Set parameter") {
345                     char *value;
346                     REQUIRE_SUCCESS(pfwSetStringParameter(param, "ok"));
347                     THEN ("Get parameter should return what was set") {
348                         REQUIRE_SUCCESS(pfwGetStringParameter(param, &value));
349                         REQUIRE(value == std::string("ok"));
350                         pfwFree(value);
351                     }
352                 }
353 
354                 pfwUnbindParameter(param);
355             }
356         }
357 
358         pfwDestroy(pfw);
359     }
360 }
361