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 47struct Test 48{ 49 /** @return true if str is empty. */ 50 bool empty(const char *str) 51 { 52 REQUIRE(str != NULL); 53 return *str == '\0'; 54 } 55 56 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 66 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. */ 89 operator const char *() const { return getPath().c_str(); } 90 }; 91 92 /** Log in logLines. */ 93 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 114TEST_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