blob: c450e60cbc38c807ab63f5b6c6b90b869d0f5529 [file] [log] [blame]
/*
* Copyright (c) 2015, Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ParameterFramework.h"
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main()
#include <catch.hpp>
#include <string>
#include <memory>
#include <vector>
#include <cstring>
#include <cerrno>
#include <climits>
extern "C"
{
#include <unistd.h>
}
struct Test
{
/** @return true if str is empty. */
bool empty(const char *str)
{
REQUIRE(str != NULL);
return *str == '\0';
}
void REQUIRE_FAILURE(bool success)
{
THEN("It should be an error") {
INFO("Previous pfw log: \n" + logLines);
CAPTURE(pfwGetLastError(pfw));
CHECK(not success);
CHECK(not empty(pfwGetLastError(pfw)));
}
}
void REQUIRE_SUCCESS(bool success)
{
THEN("It should be a success") {
INFO("Previous pfw log: \n" + logLines);
CAPTURE(pfwGetLastError(pfw));
CHECK(success);
CHECK(empty(pfwGetLastError(pfw)));
}
}
/** Class to create a temporary file */
class TmpFile
{
public:
TmpFile(const std::string &content) {
char tmpName[] = "./tmpPfwUnitTestXXXXXX";
mFd = mkstemp(tmpName);
CAPTURE(errno);
REQUIRE(mFd != -1);
mPath = tmpName;
write(mFd, content.c_str(), content.length());
}
~TmpFile() {
CHECK(close(mFd) != -1);
unlink(mPath.c_str());
}
operator const char *() const { return mPath.c_str(); }
const std::string &path() const { return mPath; }
private:
std::string mPath;
int mFd;
};
/** Log in logLines. */
static void logCb(void *voidLogLines, PfwLogLevel level, const char *logLine)
{
std::string &logLines = *reinterpret_cast<std::string *>(voidLogLines);
switch(level) {
case pfwLogWarning:
logLines += "Warning: ";
break;
case pfwLogInfo:
logLines += "Info: ";
}
logLines += logLine;
logLines += '\n';
}
/** Log buffer, will only be display in case of failure */
std::string logLines;
/** Pfw handler used in the tests. */
PfwHandler *pfw;
};
TEST_CASE_METHOD(Test, "Parameter-framework c api use") {
// Create criteria
const char *letterList[] = {"a", "b", "c", NULL};
const char *numberList[] = {"1", "2", "3", NULL};
const PfwCriterion criteria[] = {
{"inclusiveCrit", true, letterList},
{"exclusiveCrit", false, numberList},
};
size_t criterionNb = sizeof(criteria)/sizeof(criteria[0]);
PfwLogger logger = {&logLines, logCb};
// Create valid pfw config file
const char *intParameterPath = "/test/system/integer";
const char *stringParameterPath = "/test/system/string";
TmpFile system("<?xml version='1.0' encoding='UTF-8'?>\
<Subsystem Name='system' Type='Virtual' Endianness='Little'>\
<ComponentLibrary/>\
<InstanceDefinition>\
<IntegerParameter Name='integer' Size='32' Signed='true' Max='100'/>\
<StringParameter Name='string' MaxLength='9'/>\
</InstanceDefinition>\
</Subsystem>");
TmpFile libraries("<?xml version='1.0' encoding='UTF-8'?>\
<SystemClass Name='test'>\
<SubsystemInclude Path='" + system.path() + "'/>\
</SystemClass>");
TmpFile config("<?xml version='1.0' encoding='UTF-8'?>\
<ParameterFrameworkConfiguration\
SystemClassName='test' TuningAllowed='false'>\
<SubsystemPlugins/>\
<StructureDescriptionFileLocation Path='" + libraries.path() + "'/>\
</ParameterFrameworkConfiguration>");
GIVEN("A created parameter framework") {
pfw = pfwCreate();
REQUIRE(pfw != NULL);
THEN("Error message should be empty") {
CHECK(empty(pfwGetLastError(pfw)));
}
WHEN("The pfw is started without an handler") {
CHECK(not pfwStart(NULL, config, criteria, criterionNb, &logger));
}
WHEN("The pfw is started without a config path") {
REQUIRE_FAILURE(pfwStart(pfw, NULL, criteria, criterionNb, &logger));
}
WHEN("The pfw is started without an existent file") {
REQUIRE_FAILURE(pfwStart(pfw, "/doNotExist", criteria, criterionNb, &logger));
}
WHEN("The pfw is started without a criteria list") {
REQUIRE_FAILURE(pfwStart(pfw, config, NULL, criterionNb, &logger));
}
WHEN("The pfw is started with duplicated criterion value") {
const PfwCriterion duplicatedCriteria[] = {
{"duplicated name", true, letterList},
{"duplicated name", false, numberList},
};
REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 2, &logger));
}
WHEN("The pfw is started with duplicated criterion value state") {
const char * values[] = {"a", "a", NULL};
const PfwCriterion duplicatedCriteria[] = {{"name", true, values}};
WHEN("Using test logger") {
REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
}
WHEN("Using default logger") {
// Test coverage of default logger warning
REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, NULL));
}
}
WHEN("The pfw is started with NULL name criterion") {
const PfwCriterion duplicatedCriteria[] = {{NULL, true, letterList}};
REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
}
WHEN("The pfw is started with NULL criterion state list") {
const PfwCriterion duplicatedCriteria[] = {{"name", true, NULL}};
REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
}
GIVEN("A criteria with lots of values")
{
// Build a criterion with as many value as there is bits in int.
std::vector<char> names(sizeof(int) * CHAR_BIT + 1, 'a');
names.back() = '\0';
std::vector<const char *> values(names.size());
for(size_t i = 0; i < values.size(); ++i) {
values[i] = &names[i];
}
values.back() = NULL;
/* The pfw c api requires criterion values to be a NULL terminated
* array of string. Each string is a pointer to a NULL terminated
* array of char. The pfw requires each string to be different
* from all others, ie strcmp(values[i], values[j]) != 0 for any
* i j.
*
* In order to generate easily an array of different strings,
* instantiate one string (names) big enough
* (@see PfwCriterion::values).
* Then instantiate an array of pointer (values),
* each pointing to a different position in the previously
* created string.
*
* Representation of the names and values vectors.
*
* n = number of bit in an int
* <--- n+1 elements --->
* names = |a|a|a|a|...|a|a|a|\0|
* ^ ^ ^
* values[0] = ´ | |
* values[1] = --´ |
* ... |
* values[n - 1] = -----------´
* values[n] = NULL
*
*/
const PfwCriterion duplicatedCriteria[] = {{"name", true, &values[0]}};
WHEN("The pfw is started with a too long criterion state list") {
REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
}
WHEN("The pfw is started with max length criterion state list") {
values[values.size() - 2] = NULL; // Hide last value
REQUIRE_SUCCESS(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
}
}
WHEN("The pfw is started with zero criteria") {
REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, 0, &logger));
}
WHEN("The pfw is started twice a pfw") {
REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, &logger));
REQUIRE_FAILURE(pfwStart(pfw, config, criteria, criterionNb, &logger));
}
WHEN("The pfw is started without a logger callback") {
PfwLogger noLog = { NULL, NULL };
REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, &noLog));
}
WHEN("The pfw is started with default logger") {
REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, NULL));
}
WHEN("Get criterion of a stopped pfw") {
int value;
REQUIRE_FAILURE(pfwGetCriterion(pfw, criteria[0].name, &value));
}
WHEN("Set criterion of a stopped pfw") {
REQUIRE_FAILURE(pfwSetCriterion(pfw, criteria[0].name, 1));
}
WHEN("Commit criteria of a stopped pfw") {
REQUIRE_FAILURE(pfwApplyConfigurations(pfw));
}
WHEN("Bind parameter with a stopped pfw") {
REQUIRE(pfwBindParameter(pfw, intParameterPath) == NULL);
}
WHEN("The pfw is started correctly")
{
REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, &logger));
int value;
WHEN("Get criterion without an handle") {
REQUIRE(not pfwGetCriterion(NULL, criteria[0].name, &value));
}
WHEN("Get criterion without a name") {
REQUIRE_FAILURE(pfwGetCriterion(pfw, NULL, &value));
}
WHEN("Get criterion without an output value") {
REQUIRE_FAILURE(pfwGetCriterion(pfw, criteria[0].name, NULL));
}
WHEN("Get not existing criterion") {
REQUIRE_FAILURE(pfwGetCriterion(pfw, "Do not exist", &value));
}
THEN("All criterion should value 0") {
for(size_t i = 0; i < criterionNb; ++i) {
const char *criterionName = criteria[i].name;
CAPTURE(criterionName);
REQUIRE_SUCCESS(pfwGetCriterion(pfw, criterionName, &value));
REQUIRE(value == 0);
}
}
WHEN("Set criterion without an handle") {
REQUIRE(not pfwSetCriterion(NULL, criteria[0].name, 1));
}
WHEN("Set criterion without a name") {
REQUIRE_FAILURE(pfwSetCriterion(pfw, NULL, 2));
}
WHEN("Set not existing criterion") {
REQUIRE_FAILURE(pfwSetCriterion(pfw, "Do not exist", 3));
}
WHEN("Set criterion value") {
for(size_t i = 0; i < criterionNb; ++i) {
const char *criterionName = criteria[i].name;
CAPTURE(criterionName);
REQUIRE_SUCCESS(pfwSetCriterion(pfw, criterionName, 3));
}
THEN("Get criterion value should return what was set") {
for(size_t i = 0; i < criterionNb; ++i) {
const char *criterionName = criteria[i].name;
CAPTURE(criterionName);
REQUIRE_SUCCESS(pfwGetCriterion(pfw, criterionName, &value));
REQUIRE(value == 3);
}
}
}
WHEN("Commit criteria without a pfw") {
REQUIRE(not pfwApplyConfigurations(NULL));
}
WHEN("Commit criteria of a started pfw") {
REQUIRE_SUCCESS(pfwApplyConfigurations(pfw));
}
WHEN("Bind parameter without a pfw") {
REQUIRE(pfwBindParameter(NULL, intParameterPath) == NULL);
}
WHEN("Bind parameter without a path") {
REQUIRE_FAILURE(pfwBindParameter(pfw, NULL) != NULL);
}
WHEN("Bind a non existing parameter") {
REQUIRE_FAILURE(pfwBindParameter(pfw, "do/not/exist") != NULL);
}
WHEN("Set an int parameter without a parameter handle") {
REQUIRE(not pfwSetIntParameter(NULL, value));
}
WHEN("Get an int parameter without a parameter handle") {
REQUIRE(not pfwGetIntParameter(NULL, &value));
}
GIVEN("An integer parameter handle") {
PfwParameterHandler *param = pfwBindParameter(pfw, intParameterPath);
REQUIRE_SUCCESS(param != NULL);
WHEN("Get an int parameter without an output value") {
REQUIRE_FAILURE(pfwGetIntParameter(param, NULL));
}
WHEN("Set parameter out of range") {
REQUIRE_FAILURE(pfwSetIntParameter(param, 101));
}
WHEN("Set parameter") {
REQUIRE_SUCCESS(pfwSetIntParameter(param, 11));
THEN("Get parameter should return what was set") {
REQUIRE_SUCCESS(pfwGetIntParameter(param, &value));
REQUIRE(value == 11);
}
}
pfwUnbindParameter(param);
}
GIVEN("An string parameter handle") {
PfwParameterHandler *param = pfwBindParameter(pfw, stringParameterPath);
REQUIRE_SUCCESS(param != NULL);
WHEN("Get an int parameter without an output value") {
REQUIRE_FAILURE(pfwGetStringParameter(param, NULL));
}
WHEN("Set parameter out of range") {
REQUIRE_FAILURE(pfwSetStringParameter(param, "ko_1234567"));
}
WHEN("Set parameter") {
const char *value;
REQUIRE_SUCCESS(pfwSetStringParameter(param, "ok"));
THEN("Get parameter should return what was set") {
REQUIRE_SUCCESS(pfwGetStringParameter(param, &value));
REQUIRE(value == std::string("ok"));
pfwFree((void *)value);
}
}
pfwUnbindParameter(param);
}
}
pfwDestroy(pfw);
}
}
SCENARIO("Get last error without a pfw") {
THEN("Should return NULL") {
CHECK(pfwGetLastError(NULL) == NULL);
}
}