diff --git a/bindings/c/ParameterFramework.cpp b/bindings/c/ParameterFramework.cpp index 9d5102d74..4e8a6d9b1 100644 --- a/bindings/c/ParameterFramework.cpp +++ b/bindings/c/ParameterFramework.cpp @@ -32,7 +32,6 @@ #include #include -#include #include #include @@ -41,12 +40,12 @@ #include using std::string; -using core::criterion::CriterionInterface; +using core::criterion::Criterion; /** Rename long pfw types to short ones in pfw namespace. */ namespace pfw { - typedef std::map Criteria; + typedef std::map Criteria; typedef CParameterMgrPlatformConnector Pfw; } @@ -187,30 +186,19 @@ bool PfwHandler::createCriteria(const PfwCriterion criteriaArray[], size_t crite "\" already exist"); } - // Create criterion - CriterionInterface *newCriterion = (criterion.inclusive ? - pfw->createInclusiveCriterion(criterion.name) : - pfw->createExclusiveCriterion(criterion.name)); - assert(newCriterion != NULL); - // Add criterion values + // Create criterion values + core::criterion::Values values; for (size_t valueIndex = 0; criterion.values[valueIndex] != NULL; ++valueIndex) { - int value; - if (criterion.inclusive) { - // Check that (int)1 << valueIndex would not overflow (UB) - if(std::numeric_limits::max() >> valueIndex == 0) { - return status.failure("Too many values for criterion " + - string(criterion.name)); - } - value = 1 << valueIndex; - } else { - value = valueIndex; - } - const char * valueName = criterion.values[valueIndex]; - string error; - if(not newCriterion->addValuePair(value, valueName, error)) { - return status.failure("Could not add value " + string(valueName) + - " to criterion " + criterion.name + ": " + error); - } + values.emplace_back(criterion.values[valueIndex]); + } + // Create criterion + string error; + Criterion *newCriterion = (criterion.inclusive ? + pfw->createInclusiveCriterion(criterion.name, values, error) : + pfw->createExclusiveCriterion(criterion.name, values, error)); + if (newCriterion == nullptr) { + return status.failure("Could not create criterion '" + string(criterion.name) + + "': " + error); } // Add new criterion to criteria list criteria[criterion.name] = newCriterion; @@ -256,13 +244,13 @@ const char *pfwGetLastError(const PfwHandler *handle) return handle == NULL ? NULL : handle->lastStatus.msg().c_str(); } -static CriterionInterface *getCriterion(const pfw::Criteria &criteria, const string &name) +static Criterion *getCriterion(const pfw::Criteria &criteria, const string &name) { pfw::Criteria::const_iterator it = criteria.find(name); return it == criteria.end() ? NULL : it->second; } -bool pfwSetCriterion(PfwHandler *handle, const char name[], int value) +bool pfwSetCriterion(PfwHandler *handle, const char name[], const char **values) { if (handle == NULL) { return Status::failure(); } Status &status = handle->lastStatus; @@ -274,35 +262,64 @@ bool pfwSetCriterion(PfwHandler *handle, const char name[], int value) return status.failure("Can not set criterion \"" + string(name) + "\" as the parameter framework is not started."); } - CriterionInterface *criterion = getCriterion(handle->criteria, name); + Criterion *criterion = getCriterion(handle->criteria, name); if (criterion == NULL) { return status.failure("Can not set criterion " + string(name) + " as does not exist"); } - criterion->setCriterionState(value); - return status.success(); + core::criterion::State state{}; + for (size_t valueIndex = 0; values[valueIndex] != NULL; ++valueIndex) { + state.emplace(values[valueIndex]); + } + return status.forward(criterion->setState(state, status.msg())); } -bool pfwGetCriterion(const PfwHandler *handle, const char name[], int *value) +const char **pfwGetCriterion(const PfwHandler *handle, const char name[]) { - if (handle == NULL) { return Status::failure(); } + if (handle == NULL) { return NULL; } Status &status = handle->lastStatus; if (name == NULL) { - return status.failure("char *name of the criterion is NULL, " - "while getting a criterion."); + status.failure("char *name of the criterion is NULL, while getting a criterion."); + return NULL; } if (handle->pfw == NULL) { - return status.failure("Can not get criterion \"" + string(name) + - "\" as the parameter framework is not started."); - } - if (value == NULL) { - return status.failure("Can not get criterion \"" + string(name) + - "\" as the out value is NULL."); + status.failure("Can not get criterion \"" + string(name) + + "\" as the parameter framework is not started."); + return NULL; } - CriterionInterface *criterion = getCriterion(handle->criteria, name); + Criterion *criterion = getCriterion(handle->criteria, name); if (criterion == NULL) { - return status.failure("Can not get criterion " + string(name) + " as it does not exist"); + status.failure("Can not get criterion " + string(name) + " as it does not exist"); + return NULL; } - *value = criterion->getCriterionState(); - return status.success(); + core::criterion::State state = criterion->getState(); + + // Allocating one slot for each criterion value plus one for the NULL end delimiter + const char **values = static_cast(malloc((state.size() + 1) * sizeof(char*))); + if (values == nullptr) { + status.failure("Can not get criterion " + string(name) + " as there is no memory left"); + return NULL; + } + + size_t i = 0; + for (auto &critValue : state) { + values[i] = strdup(critValue.c_str()); + if (values[i] == nullptr) { + status.failure("Can not get criterion " + string(name) + + " as there is no memory left (errno: " + strerror(errno) + ")"); + return NULL; + } + ++i; + } + values[i] = NULL; + return values; +} + +void pfwCriterionValueFree(const char **value) +{ + const char **valueSav = value; + while(*value != NULL) { + std::free(*const_cast(value++)); + } + std::free(valueSav); } bool pfwApplyConfigurations(const PfwHandler *handle) diff --git a/bindings/c/ParameterFramework.h b/bindings/c/ParameterFramework.h index 20cc82072..bad02d0dd 100644 --- a/bindings/c/ParameterFramework.h +++ b/bindings/c/ParameterFramework.h @@ -156,25 +156,36 @@ const char *pfwGetLastError(const PfwHandler *handle) NONNULL; /** Set a criterion value given its name and value. * @param handle[in] @see PfwHandler * @param name[in] The name of the criterion that need to be changed. - * @param value If the criterion is exclusive, the index of the new value. - * If the criterion is inclusive, a bit field where each bit - * correspond to the value index. + * @param value If the criterion is exclusive, an array containing the new value. + * If the criterion is inclusive, an array containing all new values. * For an inclusive criterion defined as such: { "Red", "Green", "Blue", NULL } - * to set the value Green and Blue, value has to be 1<<1 | 1<<2 = 0b110 = 6. + * to set the value Green and Blue, value has to be ["Green", "Blue", NULL]. * For an exclusive criterion defined as such: { "Car", "Boat", "Plane", NULL } - * to set the value Plane, value has to be 2. + * to set the value Plane, value has to be ["Plane", NULL]. * * Criterion change do not have impact on the parameters value * (no configuration applied) until the changes are committed using pfwApplyConfigurations. * * @return true on success and false on failure. */ -bool pfwSetCriterion(PfwHandler *handle, const char name[], int value) NONNULL USERESULT; +bool pfwSetCriterion(PfwHandler *handle, const char name[], const char **values) NONNULL USERESULT; /** Get a criterion value given its name. - * Same usage as pfwSetCriterion except that value is an out param. + * @param handle[in] @see PfwHandler + * @param name[in] The name of the criterion that need to be changed. + * @return an NULL terminated array of char* which store criterion values if success + * NULL otherwise * Get criterion will return the last value setted with pfwSetCriterion independantly of pfwCommitCritenio. + * The callee MUST free the returned value array using pfwCriterionValueFree after use. + */ +const char **pfwGetCriterion(const PfwHandler *handle, const char name[]) NONNULL USERESULT; + +/** Frees the memory space of criterion value array, + * which must have been returned by a previous call to pfwGetCriterion. + * + * @param value[in] pointer to the memory to free. + * @see man 3 free for usage. */ -bool pfwGetCriterion(const PfwHandler *handle, const char name[], int *value) NONNULL USERESULT; +void pfwCriterionValueFree(const char **value); /** Commit criteria change and change parameters according to the configurations. * Criterion do not have impact on the parameters value when changed, diff --git a/bindings/c/Test.cpp b/bindings/c/Test.cpp index ab564917f..db063ff4f 100644 --- a/bindings/c/Test.cpp +++ b/bindings/c/Test.cpp @@ -182,18 +182,6 @@ TEST_CASE_METHOD(Test, "Parameter-framework c api use") { }; 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)); @@ -204,8 +192,8 @@ TEST_CASE_METHOD(Test, "Parameter-framework c api use") { } GIVEN("A criteria with lots of values") { - // Build a criterion with as many value as there is bits in int. - std::vector names(sizeof(int) * CHAR_BIT + 1, 'a'); + // Build a criterion with a lot of value + std::vector names(300, 'a'); names.back() = '\0'; std::vector values(names.size()); for(size_t i = 0; i < values.size(); ++i) { @@ -240,11 +228,7 @@ TEST_CASE_METHOD(Test, "Parameter-framework c api use") { */ 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 + WHEN("The pfw is started with a long criterion state list") { REQUIRE_SUCCESS(pfwStart(pfw, config, duplicatedCriteria, 1, &logger)); } } @@ -267,11 +251,11 @@ TEST_CASE_METHOD(Test, "Parameter-framework c api use") { } WHEN("Get criterion of a stopped pfw") { - int value; - REQUIRE_FAILURE(pfwGetCriterion(pfw, criteria[0].name, &value)); + REQUIRE_FAILURE(pfwGetCriterion(pfw, criteria[0].name) != NULL); } WHEN("Set criterion of a stopped pfw") { - REQUIRE_FAILURE(pfwSetCriterion(pfw, criteria[0].name, 1)); + std::vector value{"1", NULL}; + REQUIRE_FAILURE(pfwSetCriterion(pfw, criteria[0].name, value.data())); } WHEN("Commit criteria of a stopped pfw") { REQUIRE_FAILURE(pfwApplyConfigurations(pfw)); @@ -284,55 +268,63 @@ TEST_CASE_METHOD(Test, "Parameter-framework c api use") { WHEN("The pfw is started correctly") { REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, &logger)); - int value; + int value = 0; WHEN("Get criterion without an handle") { - REQUIRE(not pfwGetCriterion(NULL, criteria[0].name, &value)); + REQUIRE(pfwGetCriterion(NULL, criteria[0].name) == NULL); } 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)); + REQUIRE_FAILURE(pfwGetCriterion(pfw, NULL) != NULL); } WHEN("Get not existing criterion") { - REQUIRE_FAILURE(pfwGetCriterion(pfw, "Do not exist", &value)); + REQUIRE_FAILURE(pfwGetCriterion(pfw, "Do not exist") != NULL); } - THEN("All criterion should value 0") { + THEN("All criterion should have their default value") { 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); + const char **criterionGetValue = pfwGetCriterion(pfw, criterionName); + REQUIRE_SUCCESS(criterionGetValue != NULL); + REQUIRE(criterionGetValue != NULL); + if (criteria[i].inclusive) { + REQUIRE(criterionGetValue[0] == NULL); + } else { + REQUIRE(std::string(criterionGetValue[0]) == "1"); + } + pfwCriterionValueFree(criterionGetValue); } } WHEN("Set criterion without an handle") { - REQUIRE(not pfwSetCriterion(NULL, criteria[0].name, 1)); + std::vector setValue{"1", NULL}; + REQUIRE(not pfwSetCriterion(NULL, criteria[0].name, setValue.data())); } WHEN("Set criterion without a name") { - REQUIRE_FAILURE(pfwSetCriterion(pfw, NULL, 2)); + std::vector setValue{"2", NULL}; + REQUIRE_FAILURE(pfwSetCriterion(pfw, NULL, setValue.data())); } WHEN("Set not existing criterion") { - REQUIRE_FAILURE(pfwSetCriterion(pfw, "Do not exist", 3)); + std::vector setValue{"3", NULL}; + REQUIRE_FAILURE(pfwSetCriterion(pfw, "Do not exist", setValue.data())); } WHEN("Set criterion value") { for(size_t i = 0; i < criterionNb; ++i) { + std::vector setValue{(criteria[i].inclusive ? "b" : "2"), NULL}; 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); + REQUIRE_SUCCESS(pfwSetCriterion(pfw, criterionName, setValue.data())); + THEN("Get criterion value should return what was set") { + const char**criterionGetValue = pfwGetCriterion(pfw, criterionName); + REQUIRE_SUCCESS(criterionGetValue != NULL); + REQUIRE(std::string(criterionGetValue[0]) == + (criteria[i].inclusive ? "b" : "2")); + pfwCriterionValueFree(criterionGetValue); } } WHEN("Set a new value to a criterion without committing first") { + std::vector setValue{"a", NULL}; const char *criterionName = criteria[0].name; - REQUIRE_SUCCESS(pfwSetCriterion(pfw, criterionName, 0)); + REQUIRE_SUCCESS(pfwSetCriterion(pfw, criterionName, setValue.data())); THEN("A warning message should have been displayed") { INFO("Previous pfw log: \n" + logLines); size_t logPos = logLines.find("Warning: Selection criterion " diff --git a/bindings/python/pfw.i b/bindings/python/pfw.i index 0c3c93e39..49988822c 100644 --- a/bindings/python/pfw.i +++ b/bindings/python/pfw.i @@ -46,16 +46,24 @@ %include "std_string.i" %include "std_vector.i" +%include "std_list.i" +%include "std_set.i" %include "typemaps.i" -// We need to tell SWIG that std::vector is a vector of strings +// We need to tell SWIG that +// std::vector is a vector of strings, +// std::list is a list of strings, +// std::set is a set of strings namespace std { %template(StringVector) vector; + %template(StringList) list; + %template(StringSet) set; } // Tells swig that 'std::string& strError' must be treated as output parameters // TODO: make it return a tuple instead of a list %apply std::string &OUTPUT { std::string& strError }; +%apply std::string &OUTPUT { std::string& errorOutput }; // Automatic python docstring generation // FIXME: because of the typemap above, the output type is wrong for methods @@ -80,14 +88,17 @@ public: void setLogger(ILogger* pLogger); - core::criterion::CriterionInterface* - createExclusiveCriterion(const std::string& name); + core::criterion::Criterion* + createExclusiveCriterion(const std::string& name, + const core::criterion::Values& values, + std::string& errorOutput); - core::criterion::CriterionInterface* - createInclusiveCriterion(const std::string& name); + core::criterion::Criterion* + createInclusiveCriterion(const std::string& name, + const core::criterion::Values& values, + std::string& errorOutput); - core::criterion::CriterionInterface* - getSelectionCriterion(const std::string& name); + core::criterion::Criterion* getCriterion(const std::string& name); // Configuration application void applyConfigurations(); @@ -202,30 +213,23 @@ namespace core namespace criterion { -class CriterionInterface +typedef std::string Value ; +typedef std::list Values; +typedef std::set State; + +class Criterion { %{ -#include +#include %} public: - virtual void setCriterionState(int iState) = 0; - virtual int getCriterionState() const = 0; - virtual std::string getCriterionName() const = 0; - virtual bool addValuePair(int numericalValue, - const std::string& literalValue, - std::string& strError) = 0; -%apply int &OUTPUT { int& numericalValue }; - virtual bool getNumericalValue(const std::string& literalValue, int& numericalValue) const = 0; -%clear int& numericalValue; -%apply std::string &OUTPUT { std::string& literalValue }; - virtual bool getLiteralValue(int numericalValue, std::string& literalValue) const = 0; -%clear std::string& literalValue; - virtual std::string getFormattedState() const = 0; - virtual bool isInclusive() const = 0; + virtual bool setState(const State& state, std::string& errorOutput) = 0; + virtual State getState() const = 0; + virtual std::string getName() const = 0; protected: - virtual ~CriterionInterface() {} + virtual ~Criterion() {} }; } /** criterion namespace */ diff --git a/bindings/python/sample.py b/bindings/python/sample.py index 939c8e17a..cccaf814c 100755 --- a/bindings/python/sample.py +++ b/bindings/python/sample.py @@ -48,20 +48,25 @@ def __init__(self): mylogger = MyLogger() pfw.setLogger(mylogger); -mood = pfw.createExclusiveCriterion("Mood") -for numerical, literal in enumerate(["mad", "sad", "glad"]): - success, error = mood.addValuePair(numerical, literal) - if not success: - logging.error("Can't create the 'Mood' criterion: %s" % error) +mood, error = pfw.createExclusiveCriterion("Mood", ("mad", "sad", "glad")) +if not mood: + logging.error("Can't create the 'Mood' criterion: {}".format(error)) -colors = pfw.createInclusiveCriterion("Colors") -for numerical, literal in enumerate(["red", "green", "blue"]): - success, error = colors.addValuePair(1 << numerical, literal) - if not success: - logging.error("Can't create the 'Colors' criterion: %s" % error) +colors, error = pfw.createInclusiveCriterion("Colors", ("red", "green", "blue")) +if not colors: + logging.error("Can't create the 'Colors' criterion: {}".format(error)) ok, error = pfw.start() + if not ok: print("Error while starting the pfw: {}".format(error)) +ok, error = mood.setState(["sad"]) +if not ok: + print("Error while setting 'mood' criterion: {}".format(error)) + +ok, error = colors.setState(["red", "green"]) +if not ok: + print("Error while setting 'colors' criterion: {}".format(error)) + raw_input("[Press enter to exit]") diff --git a/parameter/ConfigurableDomain.cpp b/parameter/ConfigurableDomain.cpp index 8542a50ec..7f84cf5f8 100644 --- a/parameter/ConfigurableDomain.cpp +++ b/parameter/ConfigurableDomain.cpp @@ -771,7 +771,7 @@ bool CConfigurableDomain::getElementSequence(const string& strConfiguration, str bool CConfigurableDomain::setApplicationRule(const string& strConfiguration, const string& strApplicationRule, - const core::criterion::Criteria& criteria, + const core::criterion::internal::Criteria& criteria, string& strError) { // Find Domain configuration diff --git a/parameter/ConfigurableDomain.h b/parameter/ConfigurableDomain.h index 4cfd65ed7..54c11f690 100644 --- a/parameter/ConfigurableDomain.h +++ b/parameter/ConfigurableDomain.h @@ -88,7 +88,7 @@ class CConfigurableDomain : public CBinarySerializableElement */ bool setApplicationRule(const std::string& strConfiguration, const std::string& strApplicationRule, - const core::criterion::Criteria& criteria, + const core::criterion::internal::Criteria& criteria, std::string& strError); bool clearApplicationRule(const std::string& strConfiguration, std::string& strError); diff --git a/parameter/ConfigurableDomains.cpp b/parameter/ConfigurableDomains.cpp index edfd8b787..ee1a2d22d 100644 --- a/parameter/ConfigurableDomains.cpp +++ b/parameter/ConfigurableDomains.cpp @@ -465,7 +465,7 @@ bool CConfigurableDomains::getElementSequence(const string& strDomain, const str bool CConfigurableDomains::setApplicationRule(const string& strDomain, const string& strConfiguration, const string& strApplicationRule, - const core::criterion::Criteria& criteria, + const core::criterion::internal::Criteria& criteria, string& strError) { CConfigurableDomain* domain = findConfigurableDomain(strDomain, strError); diff --git a/parameter/ConfigurableDomains.h b/parameter/ConfigurableDomains.h index a582c582a..6483943a2 100644 --- a/parameter/ConfigurableDomains.h +++ b/parameter/ConfigurableDomains.h @@ -133,7 +133,7 @@ class CConfigurableDomains : public CBinarySerializableElement bool setApplicationRule(const std::string& strDomain, const std::string& strConfiguration, const std::string& strApplicationRule, - const core::criterion::Criteria& criteria, + const core::criterion::internal::Criteria& criteria, std::string& strError); bool clearApplicationRule(const std::string& strDomain, const std::string& strConfiguration, std::string& strError); diff --git a/parameter/DomainConfiguration.cpp b/parameter/DomainConfiguration.cpp index c7c7ebbc7..dfc35c71e 100644 --- a/parameter/DomainConfiguration.cpp +++ b/parameter/DomainConfiguration.cpp @@ -289,7 +289,7 @@ void CDomainConfiguration::getElementSequence(string& strResult) const // Application rule bool CDomainConfiguration::setApplicationRule(const string& strApplicationRule, - const core::criterion::Criteria& criteria, + const core::criterion::internal::Criteria& criteria, string& strError) { // Parser diff --git a/parameter/DomainConfiguration.h b/parameter/DomainConfiguration.h index f561d8ddc..28ac1fcd3 100644 --- a/parameter/DomainConfiguration.h +++ b/parameter/DomainConfiguration.h @@ -69,7 +69,7 @@ class CDomainConfiguration : public CBinarySerializableElement * @result true is success false otherwise */ bool setApplicationRule(const std::string& strApplicationRule, - const core::criterion::Criteria& criteria, + const core::criterion::internal::Criteria& criteria, std::string& strError); void clearApplicationRule(); diff --git a/parameter/ParameterMgr.cpp b/parameter/ParameterMgr.cpp index 20021764e..8e645f64b 100644 --- a/parameter/ParameterMgr.cpp +++ b/parameter/ParameterMgr.cpp @@ -113,6 +113,7 @@ using std::ifstream; // FIXME: integrate ParameterMgr to core namespace using namespace core; +using namespace core::criterion::internal; // Used for remote processor server creation typedef IRemoteProcessorServerInterface* (*CreateRemoteProcessorServer)(uint16_t uiPort, IRemoteCommandHandler* pCommandHandler); @@ -464,7 +465,7 @@ bool CParameterMgr::load(string& strError) LOG_CONTEXT("Criterion states"); list criteria; - _criteria.listSelectionCriteria(criteria, true, false); + _criteria.listCriteria(criteria, true, false); info() << criteria; } @@ -722,23 +723,24 @@ bool CParameterMgr::xmlParse(CXmlElementSerializingContext& elementSerializingCo return true; } -criterion::Criterion* CParameterMgr::createExclusiveCriterion(const string& name) +Criterion* CParameterMgr::createExclusiveCriterion(const string& name, + const criterion::Values& values, + std::string& error) { - // Propagate - return _criteria.createExclusiveCriterion(name, _logger); + return _criteria.createExclusiveCriterion(name, values, _logger, error); } -criterion::Criterion* CParameterMgr::createInclusiveCriterion(const string& name) +Criterion* CParameterMgr::createInclusiveCriterion(const string& name, + const criterion::Values& values, + std::string& error) { - // Propagate - return _criteria.createInclusiveCriterion(name, _logger); + return _criteria.createInclusiveCriterion(name, values, _logger, error); } -// Selection criterion retrieval -criterion::Criterion* CParameterMgr::getSelectionCriterion(const string& strName) +Criterion* CParameterMgr::getCriterion(const string& strName) { // Propagate - return _criteria.getSelectionCriterion(strName); + return _criteria.getCriterion(strName); } // Configuration application @@ -911,7 +913,7 @@ CParameterMgr::CCommandHandler::CommandStatus CParameterMgr::statusCommandProces /// Criteria states CUtility::appendTitle(strResult, "Selection Criteria:"); list lstrSelectionCriteria; - _criteria.listSelectionCriteria(lstrSelectionCriteria, false, true); + _criteria.listCriteria(lstrSelectionCriteria, false, true); // Concatenate the criterion list as the command result string strCriteriaStates; CUtility::asString(lstrSelectionCriteria, strCriteriaStates); @@ -1081,7 +1083,7 @@ CParameterMgr::CCommandHandler::CommandStatus CParameterMgr::listCriteriaCommand } if (strOutputFormat == "XML") { - if (!exportElementToXMLString(&_criteria, "SelectionCriteria", strResult)) { + if (!exportElementToXMLString(&_criteria, "Criteria", strResult)) { return CCommandHandler::EFailed; } @@ -1094,7 +1096,7 @@ CParameterMgr::CCommandHandler::CommandStatus CParameterMgr::listCriteriaCommand bool bHumanReadable = strOutputFormat.empty(); list lstrResult; - _criteria.listSelectionCriteria(lstrResult, true, bHumanReadable); + _criteria.listCriteria(lstrResult, true, bHumanReadable); // Concatenate the criterion list as the command result CUtility::asString(lstrResult, strResult); diff --git a/parameter/ParameterMgr.h b/parameter/ParameterMgr.h index d1ab19fa6..cba8526f5 100644 --- a/parameter/ParameterMgr.h +++ b/parameter/ParameterMgr.h @@ -108,20 +108,36 @@ class CParameterMgr /** Create a new Exclusive criterion * - * @param[in] name, the criterion name - * @return raw pointer on the created criterion + * @param[in] name the criterion name + * @param[in] values available value pairs for the created criterion + * @param[out] error the string describing the error if an error occurred + * undefined otherwise + * @return raw pointer on the created criterion, nullptr if the method fail */ - core::criterion::Criterion* createExclusiveCriterion(const std::string& name); + core::criterion::internal::Criterion* + createExclusiveCriterion(const std::string& name, + const core::criterion::Values& values, + std::string& error); /** Create a new Inclusive criterion * - * @param[in] name, the criterion name - * @return raw pointer on the created criterion + * @param[in] name the criterion name + * @param[in] values available value pairs for the created criterion + * @param[out] error the string describing the error if an error occurred + * undefined otherwise + * @return raw pointer on the created criterion, nullptr if the method fail */ - core::criterion::Criterion* createInclusiveCriterion(const std::string& name); + core::criterion::internal::Criterion* + createInclusiveCriterion(const std::string& name, + const core::criterion::Values& values, + std::string& error); - // Selection criterion retrieval - core::criterion::Criterion* getSelectionCriterion(const std::string& strName); + /** Criterion retrieval + * + * @param[in] strName the criterion name + * @return the pointer on the desired criterion, nullptr otherwise + */ + core::criterion::internal::Criterion* getCriterion(const std::string& strName); // Configuration application void applyConfigurations(); @@ -747,7 +763,7 @@ class CParameterMgr CParameterFrameworkConfiguration _pfwConfiguration; /** Selection Criteria used in application rules */ - core::criterion::Criteria _criteria; + core::criterion::internal::Criteria _criteria; /** Subsystems handler */ CSystemClass _systemClass; diff --git a/parameter/ParameterMgrFullConnector.cpp b/parameter/ParameterMgrFullConnector.cpp index 38ffb9648..b50dde1fc 100644 --- a/parameter/ParameterMgrFullConnector.cpp +++ b/parameter/ParameterMgrFullConnector.cpp @@ -34,7 +34,9 @@ #include using std::string; -using core::criterion::CriterionInterface; +using core::criterion::Criterion; + +using namespace core; CParameterMgrFullConnector::CParameterMgrFullConnector(const string& strConfigurationFilePath) : _pParameterMgrLogger(new CParameterMgrLogger(*this)), @@ -84,20 +86,25 @@ CParameterHandle* CParameterMgrFullConnector::createParameterHandle(const string return _pParameterMgr->createParameterHandle(strPath, strError); } -CriterionInterface* CParameterMgrFullConnector::createExclusiveCriterion(const string& name) +Criterion* +CParameterMgrFullConnector::createExclusiveCriterion(const string& name, + const criterion::Values& values, + std::string& error) { - return _pParameterMgr->createExclusiveCriterion(name); + return _pParameterMgr->createExclusiveCriterion(name, values, error); } -CriterionInterface* CParameterMgrFullConnector::createInclusiveCriterion(const string& name) +Criterion* +CParameterMgrFullConnector::createInclusiveCriterion(const string& name, + const criterion::Values& values, + std::string& error) { - return _pParameterMgr->createInclusiveCriterion(name); + return _pParameterMgr->createInclusiveCriterion(name, values, error); } -CriterionInterface* CParameterMgrFullConnector::getSelectionCriterion( - const string& strName) +Criterion* CParameterMgrFullConnector::getCriterion(const string& strName) { - return _pParameterMgr->getSelectionCriterion(strName); + return _pParameterMgr->getCriterion(strName); } bool CParameterMgrFullConnector::getForceNoRemoteInterface() const @@ -303,7 +310,7 @@ bool CParameterMgrFullConnector::removeConfigurableElementFromDomain(const strin strConfigurableElementPath, strError); } -bool CParameterMgrFullConnector::split(const string& strDomain, +bool CParameterMgrFullConnector::split(const string& strDomain, const string& strConfigurableElementPath, string& strError) { return _pParameterMgr->split(strDomain, strConfigurableElementPath, strError); diff --git a/parameter/ParameterMgrPlatformConnector.cpp b/parameter/ParameterMgrPlatformConnector.cpp index c10001a8d..87bf0e967 100644 --- a/parameter/ParameterMgrPlatformConnector.cpp +++ b/parameter/ParameterMgrPlatformConnector.cpp @@ -33,7 +33,9 @@ #include using std::string; -using core::criterion::CriterionInterface; +using core::criterion::Criterion; + +using namespace core; // Construction CParameterMgrPlatformConnector::CParameterMgrPlatformConnector( @@ -50,24 +52,27 @@ CParameterMgrPlatformConnector::~CParameterMgrPlatformConnector() delete _pParameterMgrLogger; } -CriterionInterface* CParameterMgrPlatformConnector::createExclusiveCriterion(const string& name) +Criterion* CParameterMgrPlatformConnector::createExclusiveCriterion(const string& name, + const criterion::Values& values, + std::string& error) { assert(!_bStarted); - return _pParameterMgr->createExclusiveCriterion(name); + return _pParameterMgr->createExclusiveCriterion(name, values, error); } -CriterionInterface* CParameterMgrPlatformConnector::createInclusiveCriterion(const string& name) +Criterion* CParameterMgrPlatformConnector::createInclusiveCriterion(const string& name, + const criterion::Values& values, + std::string& error) { assert(!_bStarted); - return _pParameterMgr->createInclusiveCriterion(name); + return _pParameterMgr->createInclusiveCriterion(name, values, error); } -CriterionInterface* -CParameterMgrPlatformConnector::getSelectionCriterion(const string& strName) const +Criterion* CParameterMgrPlatformConnector::getCriterion(const string& strName) const { - return _pParameterMgr->getSelectionCriterion(strName); + return _pParameterMgr->getCriterion(strName); } // Configuration application diff --git a/parameter/RuleParser.cpp b/parameter/RuleParser.cpp index 939eb7500..23bd94a47 100644 --- a/parameter/RuleParser.cpp +++ b/parameter/RuleParser.cpp @@ -45,7 +45,8 @@ const char* CRuleParser::_acDelimiters[CRuleParser::ENbStatuses] = { "" // EDone }; -CRuleParser::CRuleParser(const string& strApplicationRule, const criterion::Criteria& criteria) : +CRuleParser::CRuleParser(const string& strApplicationRule, + const criterion::internal::Criteria& criteria) : _strApplicationRule(strApplicationRule), mCriteria(criteria), _uiCurrentPos(0), @@ -221,7 +222,7 @@ const string& CRuleParser::getType() const } // Criteria defintion -const criterion::Criteria& CRuleParser::getCriteria() const +const criterion::internal::Criteria& CRuleParser::getCriteria() const { return mCriteria; } diff --git a/parameter/RuleParser.h b/parameter/RuleParser.h index 7130fca32..6ca5bb5ba 100644 --- a/parameter/RuleParser.h +++ b/parameter/RuleParser.h @@ -53,7 +53,7 @@ class CRuleParser }; CRuleParser(const std::string& strApplicationRule, - const core::criterion::Criteria& criteria); + const core::criterion::internal::Criteria& criteria); ~CRuleParser(); // Parse @@ -69,7 +69,7 @@ class CRuleParser const std::string& getType() const; /** Criteria getter */ - const core::criterion::Criteria& getCriteria() const; + const core::criterion::internal::Criteria& getCriteria() const; // Root rule CCompoundRule* grabRootRule(); @@ -82,7 +82,7 @@ class CRuleParser std::string _strApplicationRule; /** Criteria definition */ - const core::criterion::Criteria& mCriteria; + const core::criterion::internal::Criteria& mCriteria; /** String iterator */ std::string::size_type _uiCurrentPos; diff --git a/parameter/SelectionCriterionRule.cpp b/parameter/SelectionCriterionRule.cpp index b4b03f62f..b0cf33108 100644 --- a/parameter/SelectionCriterionRule.cpp +++ b/parameter/SelectionCriterionRule.cpp @@ -40,7 +40,7 @@ using std::string; CSelectionCriterionRule::CSelectionCriterionRule() : - _pSelectionCriterion(NULL), mMatchesWhenVerb(""), _iMatchValue(0) + _pSelectionCriterion(NULL), mMatchesWhenVerb(""), mMatchState{} { } @@ -63,7 +63,7 @@ void CSelectionCriterionRule::logValue(string& strValue, CErrorContext& errorCon bool CSelectionCriterionRule::parse(CRuleParser& ruleParser, string& strError) { // Criterion - _pSelectionCriterion = ruleParser.getCriteria().getSelectionCriterion(ruleParser.getType()); + _pSelectionCriterion = ruleParser.getCriteria().getCriterion(ruleParser.getType()); // Check existence if (!_pSelectionCriterion) { @@ -89,22 +89,19 @@ bool CSelectionCriterionRule::parse(CRuleParser& ruleParser, string& strError) // Matches when if (!_pSelectionCriterion->isMatchMethodAvailable(mMatchesWhenVerb)) { - strError = "Matche type: " + mMatchesWhenVerb + " incompatible with " + - (_pSelectionCriterion->isInclusive() ? "inclusive" : "exclusive") + - " criterion: " + _pSelectionCriterion->getCriterionName(); + strError = "Matche type: " + mMatchesWhenVerb + " incompatible with criterion: " + + _pSelectionCriterion->getName(); return false; } - // Value - if (!_pSelectionCriterion->getNumericalValue(strValue, _iMatchValue)) { + if (!setMatchState(strValue)) { strError = "Value error: \"" + strValue + "\" is not part of criterion \"" + - _pSelectionCriterion->getCriterionName() + "\""; + _pSelectionCriterion->getName() + "\""; return false; } - return true; } @@ -112,15 +109,13 @@ bool CSelectionCriterionRule::parse(CRuleParser& ruleParser, string& strError) void CSelectionCriterionRule::dump(string& strResult) const { // Criterion - strResult += _pSelectionCriterion->getCriterionName(); + strResult += _pSelectionCriterion->getName(); strResult += " "; // Verb strResult += mMatchesWhenVerb; strResult += " "; // Value - string strValue; - _pSelectionCriterion->getLiteralValue(_iMatchValue, strValue); - strResult += strValue; + strResult += mMatchState.empty() ? gEmptyRule : *mMatchState.begin(); } // Rule check @@ -128,7 +123,7 @@ bool CSelectionCriterionRule::matches() const { assert(_pSelectionCriterion); - return _pSelectionCriterion->match(mMatchesWhenVerb, _iMatchValue); + return _pSelectionCriterion->match(mMatchesWhenVerb, mMatchState); } // From IXmlSink @@ -141,7 +136,7 @@ bool CSelectionCriterionRule::fromXml(const CXmlElement& xmlElement, CXmlSeriali string strSelectionCriterion = xmlElement.getAttributeString("SelectionCriterion"); _pSelectionCriterion = - xmlDomainImportContext.getCriteria().getSelectionCriterion(strSelectionCriterion); + xmlDomainImportContext.getCriteria().getCriterion(strSelectionCriterion); // Check existence if (!_pSelectionCriterion) { @@ -159,7 +154,7 @@ bool CSelectionCriterionRule::fromXml(const CXmlElement& xmlElement, CXmlSeriali xmlDomainImportContext.setError("Wrong MatchesWhen attribute " + mMatchesWhenVerb + " in " + getKind() + " " + xmlElement.getPath() + ": " + - _pSelectionCriterion->getCriterionName()); + _pSelectionCriterion->getName()); return false; } @@ -167,13 +162,12 @@ bool CSelectionCriterionRule::fromXml(const CXmlElement& xmlElement, CXmlSeriali // Get Value string strValue = xmlElement.getAttributeString("Value"); - if (!_pSelectionCriterion->getNumericalValue(strValue, _iMatchValue)) { + if (!setMatchState(strValue)) { xmlDomainImportContext.setError("Wrong Value attribute value " + strValue + " in " + getKind() + " " + xmlElement.getPath()); return false; } - // Done return true; } @@ -186,15 +180,24 @@ void CSelectionCriterionRule::toXml(CXmlElement& xmlElement, CXmlSerializingCont assert(_pSelectionCriterion); // Set selection criterion - xmlElement.setAttributeString("SelectionCriterion", _pSelectionCriterion->getCriterionName()); + xmlElement.setAttributeString("SelectionCriterion", _pSelectionCriterion->getName()); // Set MatchesWhen xmlElement.setAttributeString("MatchesWhen", mMatchesWhenVerb); // Set Value - string strValue; - - _pSelectionCriterion->getLiteralValue(_iMatchValue, strValue); + xmlElement.setAttributeString("Value", mMatchState.empty() ? gEmptyRule : *mMatchState.begin()); +} - xmlElement.setAttributeString("Value", strValue); +bool CSelectionCriterionRule::setMatchState(const std::string &value) +{ + if (value == gEmptyRule) { + mMatchState.clear(); + return true; + } + if (!_pSelectionCriterion->isValueAvailable(value)) { + return false; + } + mMatchState = {value}; + return true; } diff --git a/parameter/SelectionCriterionRule.h b/parameter/SelectionCriterionRule.h index 6a57d5b76..f642f90e7 100644 --- a/parameter/SelectionCriterionRule.h +++ b/parameter/SelectionCriterionRule.h @@ -62,8 +62,16 @@ class CSelectionCriterionRule : public CRule // Content dumping virtual void logValue(std::string& strValue, CErrorContext& errorContext) const; private: + + /** Internal helper to set the criterion state we want to match + * + * @param[in] value the criterion value we want to put in the state + * @return true if sucess, false otherwise + */ + bool setMatchState(const std::string &value); + // Selection criterion - const core::criterion::Criterion* _pSelectionCriterion; + const core::criterion::internal::Criterion* _pSelectionCriterion; /** Method name used to match the criterion state * @@ -73,7 +81,10 @@ class CSelectionCriterionRule : public CRule */ std::string mMatchesWhenVerb; - // Value - int32_t _iMatchValue; + /** Criterion State to match to validate the rule */ + core::criterion::State mMatchState; + + /** Empty criterion state denomination */ + static constexpr const char *gEmptyRule = "none"; }; diff --git a/parameter/XmlDomainImportContext.h b/parameter/XmlDomainImportContext.h index 3a41b09ba..258147f89 100644 --- a/parameter/XmlDomainImportContext.h +++ b/parameter/XmlDomainImportContext.h @@ -41,7 +41,7 @@ class CXmlDomainImportContext : public CXmlDomainSerializingContext CXmlDomainImportContext(std::string& strError, bool bWithSettings, CSystemClass& systemClass, - const core::criterion::Criteria& criteria) + const core::criterion::internal::Criteria& criteria) : base(strError, bWithSettings), _systemClass(systemClass), mCriteria(criteria), _bAutoValidationRequired(true) {} @@ -52,7 +52,7 @@ class CXmlDomainImportContext : public CXmlDomainSerializingContext return _systemClass; } - const core::criterion::Criteria& getCriteria() const + const core::criterion::internal::Criteria& getCriteria() const { return mCriteria; } @@ -75,7 +75,7 @@ class CXmlDomainImportContext : public CXmlDomainSerializingContext CSystemClass& _systemClass; /** Selection criteria definition for rule creation */ - const core::criterion::Criteria& mCriteria; + const core::criterion::internal::Criteria& mCriteria; // Auto validation of configurations bool _bAutoValidationRequired; diff --git a/parameter/criterion/CMakeLists.txt b/parameter/criterion/CMakeLists.txt index 31462c6a5..2ec813b97 100644 --- a/parameter/criterion/CMakeLists.txt +++ b/parameter/criterion/CMakeLists.txt @@ -44,7 +44,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") # Client headers install(FILES - include/criterion/client/CriterionInterface.h + include/criterion/client/Criterion.h DESTINATION "include/parameter/client/criterion") if(BUILD_TESTING) diff --git a/parameter/criterion/include/criterion/Criteria.h b/parameter/criterion/include/criterion/Criteria.h index b1589c1f0..9e3308b3d 100644 --- a/parameter/criterion/include/criterion/Criteria.h +++ b/parameter/criterion/include/criterion/Criteria.h @@ -42,6 +42,8 @@ namespace core { namespace criterion { +namespace internal +{ /** Criteria Handler */ class Criteria : public IXmlSource @@ -52,34 +54,44 @@ class Criteria : public IXmlSource /** Create a new Exclusive criterion * * @param[in] name the criterion name + * @param[in] values available values the criterion can take * @param[in] logger the application main logger - * @return raw pointer on the created criterion + * @param[out] error the string containing the error description in case of failure + * undefined otherwise + * @return raw pointer on the created criterion, nullptr in case of failure */ Criterion* createExclusiveCriterion(const std::string& name, - core::log::Logger& logger); + const Values& values, + core::log::Logger& logger, + std::string& error); /** Create a new Inclusive criterion * * @param[in] name the criterion name + * @param[in] values available values the criterion can take * @param[in] logger the application main logger - * @return raw pointer on the created criterion + * @param[out] error the string containing the error description in case of failure + * undefined otherwise + * @return raw pointer on the created criterion, nullptr in case of failure */ Criterion* createInclusiveCriterion(const std::string& name, - core::log::Logger& logger); + const Values& values, + core::log::Logger& logger, + std::string& error); /** Criterion Retrieval * * @param[in] name the criterion name * @result pointer to the desired criterion object */ - Criterion* getSelectionCriterion(const std::string& name); + Criterion* getCriterion(const std::string& name); /** Const Criterion Retrieval * * @param[in] name the criterion name * @result pointer to the desired const criterion object */ - const Criterion* getSelectionCriterion(const std::string& name) const; + const Criterion* getCriterion(const std::string& name) const; /** List available criteria * @@ -87,9 +99,7 @@ class Criteria : public IXmlSource * @param[in] withTypeInfo indicates if we want to retrieve criterion type information * @param[in] humanReadable indicates the formatage we want to use */ - void listSelectionCriteria(std::list& results, - bool withTypeInfo, - bool humanReadable) const; + void listCriteria(std::list& results, bool withTypeInfo, bool humanReadable) const; /** Reset the modified status of criteria */ void resetModifiedStatus(); @@ -127,9 +137,25 @@ class Criteria : public IXmlSource */ Criterion* getCriterionPointer(const std::string& name) const; + /** Helper to register a new Criterion + * + * @param[in] name the criterion name + * @param[in] values available values the criterion can take + * @param[in] logger the application main logger + * @param[out] error the string containing the error description in case of failure + * undefined otherwise + * @return raw pointer on the created criterion, nullptr in case of failure + */ + template + Criterion* addCriterion(const std::string& name, + const Values& values, + core::log::Logger& logger, + std::string& error); + /** Criteria instance container */ CriteriaMap mCriteria; }; +} /** internal namespace */ } /** criterion namespace */ } /** core namespace */ diff --git a/parameter/criterion/include/criterion/Criterion.h b/parameter/criterion/include/criterion/Criterion.h index 4296ffdc7..d013ea629 100644 --- a/parameter/criterion/include/criterion/Criterion.h +++ b/parameter/criterion/include/criterion/Criterion.h @@ -29,51 +29,59 @@ */ #pragma once -#include "client/CriterionInterface.h" +#include "client/Criterion.h" #include "XmlSource.h" #include #include +#include #include #include +#include namespace core { namespace criterion { +namespace internal +{ /** Criterion object used to apply rules based on system state */ -class Criterion : public IXmlSource, public CriterionInterface +class Criterion : public IXmlSource, public criterion::Criterion { public: + /** Indicates an error at the Criterion creation */ + using InvalidCriterionError = std::runtime_error; + /** @param[in] name the criterion name + * @param[in] values available values the criterion can take * @param[in] logger the main application logger + * + * @throw InvalidCriterionError if there is less than 2 values provided. */ - Criterion(const std::string& name, core::log::Logger& logger); + Criterion(const std::string& name, + const criterion::Values& values, + core::log::Logger& logger); // @{ - /** @see CriterionInterface */ - virtual void setCriterionState(int iState) override final; - - virtual int getCriterionState() const override final; - - virtual std::string getCriterionName() const override final; - - virtual bool isInclusive() const override; + /** @see Criterion */ + virtual bool setState(const State& state, std::string& error) override; - virtual bool addValuePair(int numericalValue, - const std::string& literalValue, - std::string& error) override; + virtual State getState() const override final; - bool getLiteralValue(int numericalValue, std::string& literalValue) const override final; - - virtual bool getNumericalValue(const std::string& literalValue, - int& numericalValue) const override; - - virtual std::string getFormattedState() const override; + virtual std::string getName() const override final; // @} + /** Check if the current criterion has been modified + * If the set of the current value is requested, the set will succeed but the criterion + * will be marqued as unchanged. If the set action succeed with a new value, the criterion + * will be marqued as modified. This status can be retrieve through this method. + * + * @return true if the criterion has been modified, else otherwise + */ bool hasBeenModified() const; + + /** Reset the modified status of the criterion */ void resetModifiedStatus(); /** Request criterion state match with a desired method @@ -84,7 +92,7 @@ class Criterion : public IXmlSource, public CriterionInterface * * @throw std::out_of_range if the desired match method does not exist */ - bool match(const std::string& method, int32_t state) const; + bool match(const std::string& method, const State& state) const; /** Check if a match method is available for this criterion * @@ -93,7 +101,14 @@ class Criterion : public IXmlSource, public CriterionInterface */ bool isMatchMethodAvailable(const std::string& method) const; - std::string getFormattedDescription(bool bWithTypeInfo, bool bHumanReadable) const; + /** Retrieve a properly formatted description of the Criterion + * + * @param[in] bWithTypeInfo true if user want type info in the description, false otherwise + * @param[in] bHumanReadable true if the description must have a human readable format + * false if it must be easier to parse + * @return the string containing the desired description + */ + std::string getFormattedDescription(bool withTypeInfo, bool humanReadable) const; /** List different values a criterion can have * @@ -101,6 +116,13 @@ class Criterion : public IXmlSource, public CriterionInterface */ std::string listPossibleValues() const; + /** Check the avaibility of a given value for this criterion + * + * @param[in] value the value we want to check the avaibility + * @return true if the value is available, false otherwise + */ + bool isValueAvailable(const Value &value) const; + /** Export to XML * * @param[in] xmlElement The XML element to export to @@ -115,14 +137,11 @@ class Criterion : public IXmlSource, public CriterionInterface * and returns a boolean which indicates if the current state match the state given in * parameter. */ - typedef std::function MatchMethod; + typedef std::function MatchMethod; /** Match method container, MatchMethod are indexed by their name */ typedef std::map MatchMethods; - /** Internal type which associate literal and numerical value */ - typedef std::map ValuePairs; - /** Initializer constructor * This Constructor initialize class members and should be called by derived class * in order to add functionalities @@ -130,36 +149,61 @@ class Criterion : public IXmlSource, public CriterionInterface * @param[in] name the criterion name * @param[in] logger the main application logger * @param[in] derivedValuePairs initial value pairs of derived classes + * @param[in] defaultState the default state chosen by the derived class * @param[in] derivedMatchMethods match methods of derived classes */ Criterion(const std::string& name, core::log::Logger& logger, - const ValuePairs& derivedValuePairs, + const criterion::Values& derivedValuePairs, + const State& defaultState, const MatchMethods& derivedMatchMethods); + /** Criterion value collection + * Internally, values are stored in a set. Nevertheless, the Values type exposed + * to the client is a list to let him have the control of the values order. + * Without that, client will not be able to choose the criterion default value. + */ + using Values = std::set; /** Contains pair association between literal and numerical value */ - ValuePairs mValuePairs; + const Values mValues; /** Available criterion match methods */ const MatchMethods mMatchMethods; - /** Current state - * - * FIXME: Use bit set object instead + /** Current state */ + State mState; + + /** Register a modification of the criterion + * Client need to be informed when the criterion has been modified + * and how many times. + * This method helps to count and log modifications. */ - int32_t mState; + void stateModificationsEvent(); private: + /** Return description of the Criterion type for serialization purpose */ + virtual const std::string getKind() const; + + /** Retrieve formatted current criterion state + * + * @return formatted string of criterion state + */ + virtual std::string getFormattedState() const; + /** Counter to know how many modifications have been applied to this criterion */ - uint32_t _uiNbModifications; + uint32_t mNbModifications; /** Application logger */ - core::log::Logger& _logger; + core::log::Logger& mLogger; /** Criterion name */ const std::string mName; + + /** Criterion default state */ + const State mDefaultState; }; +} /** internal namespace */ } /** criterion namespace */ } /** core namespace */ diff --git a/parameter/criterion/include/criterion/InclusiveCriterion.h b/parameter/criterion/include/criterion/InclusiveCriterion.h index 9b8ef1c04..39523cd91 100644 --- a/parameter/criterion/include/criterion/InclusiveCriterion.h +++ b/parameter/criterion/include/criterion/InclusiveCriterion.h @@ -35,32 +35,37 @@ namespace core { namespace criterion { +namespace internal +{ /** Criterion we can take several state values at the same time */ class InclusiveCriterion final : public Criterion { public: - /** @param[in] name, the criterion name */ - InclusiveCriterion(const std::string& name, core::log::Logger& logger); + /** @param[in] name, the criterion name + * @param[in] values available values the criterion can take + * @param[in] logger the application main logger + */ + InclusiveCriterion(const std::string& name, + const criterion::Values& values, + core::log::Logger& logger); - // @{ - /** @see CriterionInterface */ - bool isInclusive() const override; + /** @see Criterion */ + bool setState(const State& state, std::string& error) override; - bool addValuePair(int numericalValue, - const std::string& literalValue, - std::string& error) override; +private: - bool getNumericalValue(const std::string& literalValue, - int& numericalValue) const override; + // @{ + /** @see Criterion */ + virtual const std::string getKind() const override; - std::string getFormattedState() const override; - // @} + virtual std::string getFormattedState() const override; + // @{ -private: /** Inclusive criterion state delimiter. */ static const std::string gDelimiter; }; +} /** internal namespace */ } /** criterion namespace */ } /** core namespace */ diff --git a/parameter/criterion/include/criterion/client/Criterion.h b/parameter/criterion/include/criterion/client/Criterion.h new file mode 100644 index 000000000..5c5f4d56c --- /dev/null +++ b/parameter/criterion/include/criterion/client/Criterion.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011-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. + */ +#pragma once + +#include +#include +#include + +namespace core +{ +namespace criterion +{ +/** Type which represent a criterion state part */ +using Value = std::string; + +/** Criterion value collection + * When the criterion will be created, it will be checked that no internal values + * are duplicated (i.e that we have a set of value). Nevertheless, we decided to + * use a list to store values in order to let the user choose the value order. + * This is important as the first value will be chosen as default one. + * @see createExclusiveCriterion + */ +using Values = std::list; + +/** Criterion state representation */ +using State = std::set; + +/** Client criterion interface used for interacting with the system state + * Allows client to set or retrieve a Criterion state. + */ +class Criterion +{ +public: + /** Set a new state to the criterion + * The state should only be composed of registered values. + * If the requested state is already set, the function will succeed but no modification + * will be registered. + * + * @param[in] state the state to set + * @param[out] error the string describing the error if an error occurred + * undefined otherwise + * @return true if in case of success, false otherwise + */ + virtual bool setState(const State& state, std::string& error) = 0; + + /** Retrieve the current criterion state */ + virtual State getState() const = 0; + + /** Retrieve Criterion name */ + virtual std::string getName() const = 0; + +protected: + virtual ~Criterion() {} +}; + +} /** criterion namespace */ +} /** core namespace */ diff --git a/parameter/criterion/include/criterion/client/CriterionInterface.h b/parameter/criterion/include/criterion/client/CriterionInterface.h deleted file mode 100644 index 91093bba5..000000000 --- a/parameter/criterion/include/criterion/client/CriterionInterface.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2011-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. - */ -#pragma once - -#include - -namespace core -{ -namespace criterion -{ - -/** Client criterion interface used for interacting with the system state - * Allows client to set or retrieve a Criterion state. - */ -class CriterionInterface -{ -public: - virtual void setCriterionState(int iState) = 0; - virtual int getCriterionState() const = 0; - virtual std::string getCriterionName() const = 0; - - /** Add a new pair [literal, numerical] which represents a criterion - * - * @param[in] numericalValue the numerical value of the criterion - * @param[in] literalValue the literal value of the criterion - * @param[out] error string containing error information we can provide to client - * @return true if succeed false otherwise - */ - virtual bool addValuePair(int numericalValue, - const std::string& literalValue, - std::string& error) = 0; - - /** Retrieve the numerical value from the literal representation of the criterion type. - * - * @param[in] literalValue: criterion state value represented as a stream. If the criterion is - * inclusive, it supports more than one criterion type value delimited - * by the "|" symbol. - * @param[out] numericalValue: criterion state value represented as an integer. - * - * @return true if a numerical value is retrieved from the literal one, false otherwise. - */ - virtual bool getNumericalValue(const std::string& literalValue, int& numericalValue) const = 0; - - /** Retrieve the numerical value from the literal representation of the criterion type. - * - * @param[in] numericalValue: criterion state value represented as an integer. - * @param[out] literalValue: criterion state value represented as a stream. If the criterion is - * inclusive, it supports more than one criterion type value delimited - * by the "|" symbol. - * - * @return true if a numerical value is retrieved from the literal one, false otherwise. - */ - virtual bool getLiteralValue(int numericalValue, std::string& literalValue) const = 0; - - /** Retrieve formatted current criterion state - * - * @return formatted string of criterion state - */ - virtual std::string getFormattedState() const = 0; - - /** Retrieve Criterion type - * - * @return true if the criterion is Inclusive, false if it is Exclusive - */ - virtual bool isInclusive() const = 0; - -protected: - virtual ~CriterionInterface() {} -}; - -} /** criterion namespace */ -} /** core namespace */ diff --git a/parameter/criterion/src/Criteria.cpp b/parameter/criterion/src/Criteria.cpp index 891d58fe5..f9ccd190f 100644 --- a/parameter/criterion/src/Criteria.cpp +++ b/parameter/criterion/src/Criteria.cpp @@ -36,6 +36,8 @@ namespace core { namespace criterion { +namespace internal +{ Criteria::Criteria() : mCriteria() { @@ -52,31 +54,35 @@ Criterion* Criteria::getCriterionPointer(const std::string& name) const } } -Criterion* Criteria::createExclusiveCriterion(const std::string& name, core::log::Logger& logger) +Criterion* Criteria::createExclusiveCriterion(const std::string& name, + const Values& values, + core::log::Logger& logger, + std::string& error) { - mCriteria.emplace(name, CriterionWrapper(new Criterion(name, logger))); - return getCriterionPointer(name); + return addCriterion(name, values, logger, error); } -Criterion* Criteria::createInclusiveCriterion(const std::string& name, core::log::Logger& logger) +Criterion* Criteria::createInclusiveCriterion(const std::string& name, + const Values& values, + core::log::Logger& logger, + std::string& error) { - mCriteria.emplace(name, CriterionWrapper(new InclusiveCriterion(name, logger))); - return getCriterionPointer(name); + return addCriterion(name, values, logger, error); } -Criterion* Criteria::getSelectionCriterion(const std::string& name) +Criterion* Criteria::getCriterion(const std::string& name) { return getCriterionPointer(name); } -const Criterion* Criteria::getSelectionCriterion(const std::string& name) const +const Criterion* Criteria::getCriterion(const std::string& name) const { return getCriterionPointer(name); } -void Criteria::listSelectionCriteria(std::list& results, - bool withTypeInfo, - bool humanReadable) const +void Criteria::listCriteria(std::list& results, + bool withTypeInfo, + bool humanReadable) const { for (auto& criterion : mCriteria) { results.push_back(criterion.second->getFormattedDescription(withTypeInfo, humanReadable)); @@ -96,10 +102,28 @@ void Criteria::toXml(CXmlElement& xmlElement, for (auto& criterion : mCriteria) { CXmlElement xmlChildElement; - xmlElement.createChild(xmlChildElement, "SelectionCriterion"); + xmlElement.createChild(xmlChildElement, "Criterion"); criterion.second->toXml(xmlChildElement, serializingContext); } } +template +Criterion* Criteria::addCriterion(const std::string& name, + const Values& values, + core::log::Logger& logger, + std::string& error) +{ + try { + Criterion* criterion(new CriterionType(name, values, logger)); + mCriteria.emplace(name, CriterionWrapper(criterion)); + return criterion; + } + catch (Criterion::InvalidCriterionError& e) { + error = e.what(); + return nullptr; + } +} + +} /** internal namespace */ } /** criterion namespace */ } /** core namespace */ diff --git a/parameter/criterion/src/Criterion.cpp b/parameter/criterion/src/Criterion.cpp index 872926eeb..d269a1df4 100644 --- a/parameter/criterion/src/Criterion.cpp +++ b/parameter/criterion/src/Criterion.cpp @@ -33,126 +33,153 @@ #include #include +#include namespace core { namespace criterion { +namespace internal +{ -Criterion::Criterion(const std::string& name, core::log::Logger& logger) - : Criterion(name, logger, {}, {}) +Criterion::Criterion(const std::string& name, + const criterion::Values& values, + core::log::Logger& logger) + : Criterion(name, logger, values, (values.empty() ? State{""} : State{*values.begin()}), {}) { + if (mValues.size() < 2) { + throw InvalidCriterionError("Not enough values were provided for exclusive criterion '" + + mName + "' which needs at least 2 values"); + } } Criterion::Criterion(const std::string& name, core::log::Logger& logger, - const ValuePairs& derivedValuePairs, + const criterion::Values& values, + const State& defaultState, const MatchMethods& derivedMatchMethods) - : mValuePairs(derivedValuePairs), + : mValues(values.begin(), values.end()), mMatchMethods(CUtility::merge(MatchMethods{ - {"Is", [&](int state){ return mState == state; }}, - {"IsNot", [&](int state){ return mState != state; }}}, + {"Is", [&](const State& state){ return mState == state; }}, + {"IsNot", [&](const State& state){ return mState != state; }}}, derivedMatchMethods)), - mState(0), _uiNbModifications(0), _logger(logger), mName(name) + mState(defaultState), mNbModifications(0), mLogger(logger), mName(name), + mDefaultState(defaultState) { } bool Criterion::hasBeenModified() const { - return _uiNbModifications != 0; + return mNbModifications != 0; } void Criterion::resetModifiedStatus() { - _uiNbModifications = 0; + mNbModifications = 0; } -void Criterion::setCriterionState(int iState) +bool Criterion::setState(const State& state, std::string& error) { - // Check for a change - if (mState != iState) { - - mState = iState; + if (state.size() > 1) { + error = "Exclusive criterion '" + mName + "' can't be set with more than one value"; + return false; + } - _logger.info() << "Selection criterion changed event: " - << getFormattedDescription(false, false); + State oldState = mState; + if (state.empty()) { + mState = mDefaultState; + } else { + // Check that the state contains a registered value + if (mValues.count(*state.begin()) != 1) { + error = "Exclusive criterion '" + mName + "' can't be set with '" + + *state.begin() + "' value which is not registered"; + return false; + } + mState = state; + } - // Check if the previous criterion value has been taken into account - // (i.e. at least one Configuration was applied - // since the last criterion change) - if (_uiNbModifications != 0) { + if (mState != oldState) { + stateModificationsEvent(); + } - _logger.warning() << "Selection criterion '" << mName - << "' has been modified " << _uiNbModifications - << " time(s) without any configuration application"; - } + return true; +} - // Track the number of modifications for this criterion - _uiNbModifications++; +void Criterion::stateModificationsEvent() +{ + mLogger.info() << "Selection criterion changed event: " + << getFormattedDescription(false, false); + // Check if the previous criterion value has been taken into account + // (i.e. at least one Configuration was applied + // since the last criterion change) + if (mNbModifications != 0) { + mLogger.warning() << "Selection criterion '" << mName + << "' has been modified " << mNbModifications + << " time(s) without any configuration application"; } + // Track the number of modifications for this criterion + mNbModifications++; } -int Criterion::getCriterionState() const +core::criterion::State Criterion::getState() const { return mState; } -std::string Criterion::getCriterionName() const +std::string Criterion::getName() const { return mName; } -std::string Criterion::getFormattedDescription(bool bWithTypeInfo, bool bHumanReadable) const +std::string Criterion::getFormattedDescription(bool withTypeInfo, bool humanReadable) const { - std::string strFormattedDescription; - std::string typeName = isInclusive() ? "Inclusive" : "Exclusive"; - - if (bHumanReadable) { + std::string description; + if (humanReadable) { - if (bWithTypeInfo) { + if (withTypeInfo) { // Display type info - CUtility::appendTitle(strFormattedDescription, mName + ":"); + CUtility::appendTitle(description, mName + ":"); // States - strFormattedDescription += "Possible states "; + description += "Possible states "; // Type Kind - strFormattedDescription += "("; - strFormattedDescription += typeName; - strFormattedDescription += "): "; + description += "("; + description += getKind(); + description += "): "; // States - strFormattedDescription += listPossibleValues() + "\n"; + description += listPossibleValues() + "\n"; // Current State - strFormattedDescription += "Current state"; + description += "Current state"; } else { // Name only - strFormattedDescription = mName; + description = mName; } // Current State - strFormattedDescription += " = " + getFormattedState(); + description += " = " + getFormattedState(); } else { // Name - strFormattedDescription = "Criterion name: " + mName; + description = "Criterion name: " + mName; - if (bWithTypeInfo) { + if (withTypeInfo) { // Type Kind - strFormattedDescription += ", type kind: "; - strFormattedDescription += typeName; + description += ", type kind: "; + description += getKind(); } // Current State - strFormattedDescription += ", current state: " + getFormattedState(); + description += ", current state: " + getFormattedState(); - if (bWithTypeInfo) { + if (withTypeInfo) { // States - strFormattedDescription += ", states: " + listPossibleValues(); + description += ", states: " + listPossibleValues(); } } - return strFormattedDescription; + return description; } void Criterion::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const @@ -160,72 +187,25 @@ void Criterion::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializi (void)serializingContext; xmlElement.setAttributeString("Value", getFormattedState()); xmlElement.setAttributeString("Name", mName); - xmlElement.setAttributeString("Kind", isInclusive() ? "Inclusive" : "Exclusive"); + xmlElement.setAttributeString("Kind", getKind()); - for (auto& valuePair : mValuePairs) { - CXmlElement childValuePairElement; + for (auto& value : mValues) { + CXmlElement childValueElement; - xmlElement.createChild(childValuePairElement, "ValuePair"); - childValuePairElement.setAttributeString("Literal", valuePair.first); - childValuePairElement.setAttributeSignedInteger("Numerical", valuePair.second); + xmlElement.createChild(childValueElement, "Value"); + childValueElement.setTextContent(value); } } -bool Criterion::isInclusive() const +const std::string Criterion::getKind() const { - return false; -} - -bool Criterion::addValuePair(int numericalValue, - const std::string& literalValue, - std::string& error) -{ - // Check already inserted - if (mValuePairs.count(literalValue) == 1) { - - std::ostringstream errorBuf; - errorBuf << "Rejecting value pair association (literal already present): 0x" - << std::hex << numericalValue << " - " << literalValue - << " for criterion '" << getCriterionName() << "'"; - error = errorBuf.str(); - - return false; - } - mValuePairs[literalValue] = numericalValue; - - return true; -} - -bool Criterion::getNumericalValue(const std::string& literalValue, - int& numericalValue) const -{ - try { - numericalValue = mValuePairs.at(literalValue); - return true; - } - catch (std::out_of_range&) { - return false; - } -} - -bool Criterion::getLiteralValue(int numericalValue, std::string& literalValue) const -{ - for (auto& value : mValuePairs) { - if (value.second == numericalValue) { - literalValue = value.first; - return true; - } - } - return false; + return "Exclusive"; } std::string Criterion::getFormattedState() const { - std::string formattedState; - if (!getLiteralValue(mState, formattedState)) { - formattedState = ""; - } - return formattedState; + assert(!mState.empty()); + return *mState.begin(); } std::string Criterion::listPossibleValues() const @@ -234,21 +214,26 @@ std::string Criterion::listPossibleValues() const // Get comma separated list of values bool first = true; - for (auto& value : mValuePairs) { + for (auto& value : mValues) { if (first) { first = false; } else { possibleValues += ", "; } - possibleValues += value.first; + possibleValues += value; } possibleValues += "}"; return possibleValues; } -bool Criterion::match(const std::string& method, int32_t state) const +bool Criterion::isValueAvailable(const Value &value) const +{ + return mValues.count(value) == 1; +} + +bool Criterion::match(const std::string& method, const State& state) const { return mMatchMethods.at(method)(state); } @@ -258,5 +243,6 @@ bool Criterion::isMatchMethodAvailable(const std::string& method) const return mMatchMethods.count(method) == 1; } +} /** internal namespace */ } /** criterion namespace */ } /** core namespace */ diff --git a/parameter/criterion/src/InclusiveCriterion.cpp b/parameter/criterion/src/InclusiveCriterion.cpp index aabe4e7f1..023e806ad 100644 --- a/parameter/criterion/src/InclusiveCriterion.cpp +++ b/parameter/criterion/src/InclusiveCriterion.cpp @@ -28,104 +28,77 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "criterion/InclusiveCriterion.h" -#include "Tokenizer.h" #include #include +#include namespace core { namespace criterion { +namespace internal +{ const std::string InclusiveCriterion::gDelimiter = "|"; -InclusiveCriterion::InclusiveCriterion(const std::string& name, core::log::Logger& logger) - : Criterion(name, logger, - {{"none", 0}}, - {{"Includes", [&](int state){ return (mState & state) == state; }}, - {"Excludes", [&](int state){ return (mState & state) == 0; }}}) +InclusiveCriterion::InclusiveCriterion(const std::string& name, + const criterion::Values& values, + core::log::Logger& logger) + : Criterion(name, logger, values, {}, + {{"Includes", [&](const State& state) { + return std::includes(mState.begin(), mState.end(), + state.begin(), state.end()); }}, + {"Excludes", [&](const State& state) { + State inter; + std::set_intersection(mState.begin(), mState.end(), + state.begin(), state.end(), + std::inserter(inter, inter.begin())); + return inter.empty(); }}}) { + if (mValues.size() < 1) { + throw InvalidCriterionError("Not enough values were provided for inclusive criterion '" + + getName() + "' which needs at least 1 values"); + } } -bool InclusiveCriterion::isInclusive() const +const std::string InclusiveCriterion::getKind() const { - return true; + return "Inclusive"; } -bool InclusiveCriterion::addValuePair(int numericalValue, - const std::string& literalValue, - std::string& error) +std::string InclusiveCriterion::getFormattedState() const { - // Check 1 bit set only for inclusive types - // FIXME: unclear test, need rework - if (!numericalValue || (numericalValue & (numericalValue - 1))) { - std::ostringstream errorBuf; - errorBuf << "Rejecting value pair association: 0x" << std::hex << numericalValue - << " - " << literalValue << " for criterion '" << getCriterionName() << "'"; - error = errorBuf.str(); - - return false; + if (mState.empty()) { + return "none"; } - return Criterion::addValuePair(numericalValue, literalValue, error); -} - -bool InclusiveCriterion::getNumericalValue(const std::string& literalValue, - int& numericalValue) const -{ - Tokenizer tok(literalValue, gDelimiter); - std::vector literalValues = tok.split(); - numericalValue = 0; - - // Looping on each std::string delimited by "|" token and adding the associated value - for (std::string atomicLiteral : literalValues) { - - int atomicNumerical = 0; - if (!Criterion::getNumericalValue(atomicLiteral, atomicNumerical)) { - return false; + std::string formattedState; + for (auto &value : mState) { + if (*mState.begin() != value) { + formattedState += gDelimiter; } - numericalValue |= atomicNumerical; + formattedState += value; } - return true; + return formattedState; } -std::string InclusiveCriterion::getFormattedState() const +bool InclusiveCriterion::setState(const State& state, std::string& error) { - std::string formattedState; - if (mState == 0) { - // Default inclusive criterion state is always present - getLiteralValue(0, formattedState); - return formattedState; - } - - uint32_t bit; - bool first = true; - - // Need to go through all set bit - for (bit = 0; bit < sizeof(mState) * 8; bit++) { - int singleBitValue = mState & (1 << bit); - // Check if current bit is set - if (!singleBitValue) { - continue; - } - // Simple translation - std::string atomicState; - if (!getLiteralValue(singleBitValue, atomicState)) { - // Numeric value not part supported values for this criterion type. - continue; - } - - if (first) { - first = false; - } else { - formattedState += gDelimiter; + // Check for a change + if (mState != state) { + // Check that the state contains only registered values + if (!std::includes(mValues.begin(), mValues.end(), state.begin(), state.end())) { + error = "Inclusive criterion '" + getName() + + "' can't be set because some values are not registered"; + return false; } - - formattedState += atomicState; + mState = state; + stateModificationsEvent(); } - return formattedState; + return true; } +} /** internal namespace */ } /** criterion namespace */ } /** core namespace */ diff --git a/parameter/criterion/test/CriterionUnitTest.cpp b/parameter/criterion/test/CriterionUnitTest.cpp index 926ed6ff8..5cfc0f65d 100644 --- a/parameter/criterion/test/CriterionUnitTest.cpp +++ b/parameter/criterion/test/CriterionUnitTest.cpp @@ -52,12 +52,14 @@ #include #include #include -#include #include #include +using core::criterion::State; +using core::criterion::Values; + using namespace core; -using namespace core::criterion; +using namespace core::criterion::internal; /** Raw logging class Helper */ class TestLogger : public log::ILogger @@ -136,7 +138,7 @@ struct CriteriaTest : LoggingTest { for (auto& description : mDescriptions) { desireds.push_back(description.criterion->getFormattedDescription(true, true)); } - mCriteria.listSelectionCriteria(results, human, typeInfo); + mCriteria.listCriteria(results, human, typeInfo); THEN("Each criterion description should be in the listing") { for (const auto& result : results) { @@ -169,108 +171,80 @@ struct CriteriaTest : LoggingTest { /** Test fixtures for Criterion */ struct CriterionTest : public LoggingTest { - using CriterionValues = std::map; + + bool mIsInclusive = false; /** Help to generate some values */ - CriterionValues generateCriterionValues(bool isInclusive, size_t nbValues) + Values generateCriterionValues(size_t nbValues) { - // 0 is invalid for inclusive criterion - int offset = isInclusive ? 1 : 0; - CriterionValues criterionValues; - - for (size_t i = offset; i < nbValues; i++) { - // Inclusive criterion should have only one be set - int numericalValue = isInclusive ? 1 << i : i; - criterionValues.emplace("Crit_" + std::to_string(numericalValue), numericalValue); - } + Values values; - return criterionValues; - } - - void checkUnknownValueGet(Criterion& criterion) - { - WHEN("Getting a literal value from an unknown numerical one") - { - std::string result; - std::string literalValue; - REQUIRE_FAILURE(criterion.getLiteralValue(2, literalValue)); - CHECK(literalValue.empty()); - } - WHEN("Getting a numerical value from an unknown literal one") - { - std::string result; - int numericalValue = 0; - REQUIRE_FAILURE(criterion.getNumericalValue("UnknowValue", numericalValue)); - CHECK(numericalValue == 0); + for (size_t i = 0; i < nbValues; i++) { + values.emplace_back("C" + std::to_string(i)); } - } - void checkExistingValueInsertion(Criterion& criterion) - { - WHEN("Adding an existing literal value") - { - std::string result; - std::string literalValue = "DoubleState"; - REQUIRE_SUCCESS(criterion.addValuePair(1, literalValue, result), result); - REQUIRE_FAILURE(criterion.addValuePair(2, literalValue, result), result); - } - // FIXME - // WHEN("Adding an existing numerical value") { - // std::string result; - // int numericalValue = 1; - // REQUIRE_SUCCESS(criterion.addValuePair(numericalValue, "State1", result), result); - // REQUIRE_FAILURE(criterion.addValuePair(numericalValue, "State2", result), result); - // } + return values; } void checkInclusiveCriterionSet(Criterion& criterion) { - // CriterionValues contains 31 value as defined previously + std::string error; + // Criterion contains 300 value as defined previously WHEN("Setting many inclusive value at the same time") { - std::bitset<31> stateMask("001001001001001"); - std::bitset<31> subStateMask("000001001000001"); - std::bitset<31> almostSubStateMask("100001001000001"); - std::bitset<31> excludeMask("010000010010000"); + State state{"C1", "C3", "C4", "C7", "C10"}; + State subState{"C1", "C7", "C10"}; + State almostSubState{"C1", "C7", "C10", "C15"}; + State exclude{"C5", "C8", "C15"}; - CAPTURE(stateMask.to_ulong()); - criterion.setCriterionState(stateMask.to_ulong()); + REQUIRE_SUCCESS(criterion.setState(state, error), error); - WHEN("Matching with 'Includes' a mask contained in the state mask") + WHEN("Matching with 'Includes' a state contained in the current state") + { + REQUIRE_SUCCESS(criterion.match("Includes", subState)); + } + WHEN("Matching with 'Includes' a state with not all its bit set in the current state") { - REQUIRE_SUCCESS(criterion.match("Includes", subStateMask.to_ulong())); + REQUIRE_FAILURE(criterion.match("Includes", almostSubState)); } - WHEN("Matching with 'Includes' a mask with not all its bit set in the current state") + WHEN("Matching with 'Includes' a state with no common bit with the current state") { - REQUIRE_FAILURE(criterion.match("Includes", almostSubStateMask.to_ulong())); + REQUIRE_FAILURE(criterion.match("Includes", exclude)); } - WHEN("Matching with 'Includes' a mask with no common bit with the current state") + WHEN("Matching with 'Excludes' a state contained in the current state") { - REQUIRE_FAILURE(criterion.match("Includes", excludeMask.to_ulong())); + REQUIRE_FAILURE(criterion.match("Excludes", subState)); } - WHEN("Matching with 'Excludes' a mask contained in the state mask") + WHEN("Matching with 'Excludes' a state with not all its bit set in the current state") { - REQUIRE_FAILURE(criterion.match("Excludes", subStateMask.to_ulong())); + REQUIRE_FAILURE(criterion.match("Excludes", almostSubState)); } - WHEN("Matching with 'Excludes' a mask with not all its bit set in the current state") + WHEN("Matching with 'Excludes' a state with no common bit with the current state") { - REQUIRE_FAILURE(criterion.match("Excludes", almostSubStateMask.to_ulong())); + REQUIRE_SUCCESS(criterion.match("Excludes", exclude)); } - WHEN("Matching with 'Excludes' a mask with no common bit with the current state") + } + WHEN("Setting many inclusive values with some unknown") { + REQUIRE_FAILURE(criterion.setState(State{"666", "777", "C1", "C7", "C10"}, error), + error); + THEN("Criterion should not be modified") { - REQUIRE_SUCCESS(criterion.match("Excludes", excludeMask.to_ulong())); + CHECK(not criterion.hasBeenModified()); } } } - void checkExclusiveCriterionSet(Criterion& criterion, CriterionValues& criterionValues) + void checkExclusiveCriterionSet(Criterion& criterion, Values& values) { + std::string error; WHEN("Setting the current value") { - int currentState = criterion.getCriterionState(); - CAPTURE(currentState); + State currentState = criterion.getState(); + if (not currentState.empty()) { + CAPTURE(*currentState.begin()); + } std::string oldLog = mRawLogger.getLog(); - criterion.setCriterionState(currentState); + REQUIRE_SUCCESS(criterion.setState(currentState, error), error); THEN("Criterion should not be modified") { CHECK(not criterion.hasBeenModified()); @@ -281,17 +255,16 @@ struct CriterionTest : public LoggingTest { } } - for (auto& value : criterionValues) { - if (value.second != criterion.getCriterionState()) { + for (auto& value : values) { + if (State{value} != criterion.getState()) { WHEN("Setting a new value") { - CAPTURE(value.second); - criterion.setCriterionState(value.second); + CAPTURE(value); + REQUIRE_SUCCESS(criterion.setState(State{value}, error), error); THEN("State should have been updated") { - CHECK(criterion.getCriterionState() == value.second); - CHECK(criterion.getFormattedState() == value.first); + CHECK(criterion.getState() == State{value}); } THEN("Criterion should be modified") { @@ -299,11 +272,11 @@ struct CriterionTest : public LoggingTest { } THEN("Criterion Is match method should be valid") { - CHECK(criterion.match("Is", value.second)); + CHECK(criterion.match("Is", State{value})); } THEN("Criterion IsNot match method should not be valid") { - CHECK(not criterion.match("IsNot", value.second)); + CHECK(not criterion.match("IsNot", State{value})); } THEN("Criterion update event should be logged") { @@ -318,8 +291,8 @@ struct CriterionTest : public LoggingTest { WHEN("Setting many value in a raw") { // Set value which are valid for inclusive or exclusive criterion - criterion.setCriterionState(2); - criterion.setCriterionState(4); + REQUIRE_SUCCESS(criterion.setState(State{"C2"}, error), error); + REQUIRE_SUCCESS(criterion.setState(State{"C4"}, error), error); THEN("Criterion should be modified") { CHECK(criterion.hasBeenModified()); @@ -327,7 +300,7 @@ struct CriterionTest : public LoggingTest { THEN("Criterion multi modification should be logged") { size_t logPos = mRawLogger.getLog().find("Warning: Selection criterion '" + - criterion.getCriterionName() + + criterion.getName() + "' has been modified 1 time(s) without any" " configuration application"); CHECK(logPos != std::string::npos); @@ -341,31 +314,52 @@ struct CriterionTest : public LoggingTest { } } } + WHEN("Setting an unknown value") { + REQUIRE_FAILURE(criterion.setState(State{"Unknown"}, error), error); + THEN("Criterion should not be modified") + { + CHECK(not criterion.hasBeenModified()); + } + } + WHEN("Setting no value") { + REQUIRE_SUCCESS(criterion.setState(State{}, error), error); + THEN("State should have been updated") + { + if (mIsInclusive) { + CHECK(criterion.getState() == State{}); + } else { + CHECK(criterion.getState() == State{"C0"}); + } + } + } + if (!mIsInclusive) { + WHEN("Setting more than one value in an exclusive criterion") + { + REQUIRE_FAILURE(criterion.setState(State{"C1", "C2", "C3"}, error), error); + } + } } void checkSerialization(Criterion& criterion) { - std::string kind = criterion.isInclusive() ? "Inclusive" : "Exclusive"; + std::string defaultValue = mIsInclusive ? "none" : "a"; + std::string kind = mIsInclusive ? "Inclusive" : "Exclusive"; WHEN("Serializing through xml") { - std::string defaultValue = criterion.isInclusive() ? "none" : "<none>"; - std::string defaultState = criterion.isInclusive() ? - R"()" : ""; std::string xmlDescription = R"( - - - - )" + - defaultState + - ""; + a + b + c)" + + ""; std::string result; - xmlSerialize(result, &criterion, "SelectionCriterion"); + xmlSerialize(result, &criterion, "Criterion"); // Remove whitespaces as they are not relevant in xml removeWhitespaces(result); removeWhitespaces(xmlDescription); @@ -376,12 +370,10 @@ struct CriterionTest : public LoggingTest { } } - std::string defaultState = (criterion.isInclusive() ? "none" : ""); - std::string defaultStateType = criterion.isInclusive() ? ", none}" : "}"; WHEN("Serializing through Csv") { - std::string nameInfo = "Criterion name: " + criterion.getCriterionName(); - std::string currentStateInfo = std::string(", current state: ") + defaultState; + std::string nameInfo = "Criterion name: " + criterion.getName(); + std::string currentStateInfo = std::string(", current state: ") + defaultValue; THEN("Generated csv match expectation") { @@ -393,7 +385,7 @@ struct CriterionTest : public LoggingTest { THEN("Generated csv with type information match expectation") { std::string csvDescription = nameInfo + ", type kind: " + kind + currentStateInfo + - ", states: {a, b, c" + defaultStateType; + ", states: {a, b, c}"; std::string dump = criterion.getFormattedDescription(true, false); CHECK(dump == csvDescription); } @@ -402,35 +394,32 @@ struct CriterionTest : public LoggingTest { { THEN("Generated description match expectation") { - std::string description = criterion.getCriterionName() + " = " + defaultState; + std::string description = criterion.getName() + " = " + defaultValue; std::string dump = criterion.getFormattedDescription(false, true); CHECK(dump == description); } THEN("Generated description with type information match expectation") { - std::string defaultStateHuman = criterion.isInclusive() ? ", none}" : "}"; - std::string description = criterion.getCriterionName() + ":"; + std::string description = criterion.getName() + ":"; std::string titleDecorator(description.length(), '='); description = "\n" + description + "\n" + titleDecorator + - "\nPossible states (" + kind + "): {a, b, c" + defaultStateType + - "\n" + "Current state = " + defaultState; + "\nPossible states (" + kind + "): {a, b, c}" + + "\n" + "Current state = " + defaultValue; std::string dump = criterion.getFormattedDescription(true, true); CHECK(dump == description); } } } - void checkDisplay(Criterion& criterion) + template + void checkDisplay(const std::string& criterionName) { - std::string possibleValues = std::string("{a, b, c") + - (criterion.isInclusive() ? ", none" : "") + "}"; - WHEN("Adding some criterion value") + WHEN("Wanting to serialize it") { - std::string result; - REQUIRE_SUCCESS(criterion.addValuePair(2, "a", result), result); - REQUIRE_SUCCESS(criterion.addValuePair(4, "b", result), result); - REQUIRE_SUCCESS(criterion.addValuePair(8, "c", result), result); + Values values = { "a", "b", "c" }; + CriterionType criterion(criterionName, values, mLogger); + std::string possibleValues = "{a, b, c}"; THEN("Possible values match all values added in the criterion") { CHECK(criterion.listPossibleValues() == possibleValues); @@ -438,76 +427,42 @@ struct CriterionTest : public LoggingTest { checkSerialization(criterion); - if (criterion.isInclusive()) { - std::bitset<31> validStateMask("1110"); + if (mIsInclusive) { + State validState{"a", "b", "c"}; + std::string error; WHEN("Setting some criterion value") { - criterion.setCriterionState(validStateMask.to_ulong()); + REQUIRE_SUCCESS(criterion.setState(validState, error), error); THEN("Formatted state contains all set values") { - std::string formattedState = "a|b|c"; - CHECK(criterion.getFormattedState() == formattedState); + CHECK(criterion.getState() == validState); } } WHEN("Setting a mask containing unknown values") { - std::bitset<31> erroneousStateMask("10101010101110"); - criterion.setCriterionState(erroneousStateMask.to_ulong()); - THEN("Formatted state take into account only registered values") - { - std::string formattedState = "a|b|c"; - CHECK(criterion.getFormattedState() == formattedState); - } - // Check matching in this special configuration - WHEN("Matching with 'Includes' the mask corresponding to the formatted one") - { - REQUIRE_SUCCESS(criterion.match("Includes", validStateMask.to_ulong())); - } - // FIXME: correct set state in order to avoid this case - // WHEN("Matching with 'Is' the mask corresponding to the formatted one") { - // REQUIRE_SUCCESS(criterion.match("Is", validStateMask.to_ulong())); - // } + State erroneousState { "a", "b", "C", "6", "8", "10", "12", "14" }; + REQUIRE_FAILURE(criterion.setState(erroneousState, error), error); } } } } - void checkInsertionBijectivity(Criterion& criterion) + void checkInsertionBijectivity(Criterion& criterion, Values values) { - WHEN("Adding some criterion value") - { - /** Generate 31 values, no more because inclusive criterion cannot handle it - * Unbounded values are tested later for inclusive criterion - */ - CriterionValues criterionValues = generateCriterionValues(criterion.isInclusive(), 31); - - for (auto& value : criterionValues) { - std::string result; - REQUIRE_SUCCESS(criterion.addValuePair(value.second, value.first, result), result); - - THEN("Numerical value should correspond") - { - int numericalValue; - REQUIRE_SUCCESS(criterion.getNumericalValue(value.first, numericalValue)); - CHECK(numericalValue == value.second); - } - THEN("Literal value should correspond") - { - std::string literalValue; - REQUIRE_SUCCESS(criterion.getLiteralValue(value.second, literalValue)); - CHECK(literalValue == value.first); - } - } - - checkExclusiveCriterionSet(criterion, criterionValues); - if (criterion.isInclusive()) { - // Inclusive criterion has a more evolved setting behavior - checkInclusiveCriterionSet(criterion); + for (auto& value : values) { + WHEN("Verifying that an added values is effectively available") + { + REQUIRE_SUCCESS(criterion.isValueAvailable(value)); } } + checkExclusiveCriterionSet(criterion, values); + if (mIsInclusive) { + // Inclusive criterion has a more evolved setting behavior + checkInclusiveCriterionSet(criterion); + } } - void checkCriterionBasicBehavior(Criterion& criterion, std::string name) + void checkCriterionBasicBehavior(Criterion& criterion, std::string name, Values values) { using MatchMethods = std::vector; /** key indicates if it's available for exclusive criterion */ @@ -526,14 +481,14 @@ struct CriterionTest : public LoggingTest { * criterion */ bool isAuthorizedMethod = criterion.isMatchMethodAvailable(matchMethod) or - not (criterion.isInclusive() or matcher.first); + not (mIsInclusive or matcher.first); CHECK(isAuthorizedMethod); } } } WHEN("Undefined match method is requested") { - REQUIRE_THROWS_AS(criterion.match("InvalidMatch", 0), std::out_of_range); + REQUIRE_THROWS_AS(criterion.match("InvalidMatch", State{"C0"}), std::out_of_range); } THEN("The criterion has not been modified") @@ -542,96 +497,64 @@ struct CriterionTest : public LoggingTest { } THEN("The criterion has the good name") { - CHECK(criterion.getCriterionName() == name); + CHECK(criterion.getName() == name); } - checkInsertionBijectivity(criterion); - checkExistingValueInsertion(criterion); - checkUnknownValueGet(criterion); - checkDisplay(criterion); + checkInsertionBijectivity(criterion, values); } + template + void checkNoValue(const std::string& criterionName) + { + WHEN("Creating it with no value") + { + REQUIRE_THROWS_AS(CriterionType criterion(criterionName, {}, mLogger), + Criterion::InvalidCriterionError); + } + } }; SCENARIO_METHOD(CriterionTest, "Criterion lifecycle", "[criterion]") { - GIVEN("An exclusive criterion") + GIVEN("Some criterion values") { - const std::string criterionName = "ExclusiveCriterion"; - Criterion criterion(criterionName, mLogger); - - THEN("The criterion is not inclusive") - { - CHECK(not criterion.isInclusive()); - } - THEN("There is no available states") - { - CHECK(criterion.listPossibleValues() == "{}"); - } - THEN("No state is currently set") - { - CHECK(criterion.getFormattedState() == ""); - } - - checkCriterionBasicBehavior(criterion, criterionName); - - WHEN("We add an negative numerical value") - { - std::string result; - // FIXME: allow only positive numerical value - REQUIRE_SUCCESS(criterion.addValuePair(-3, "Negative", result), result); - } - WHEN("We add a random numerical value") + const Values values = generateCriterionValues(300); + GIVEN("An exclusive criterion") { - std::string result; - std::default_random_engine generator; - // FIXME: use uint32_t internally instead - // Criterion State type is int32_t - std::uniform_int_distribution dist; - int32_t numericalValue = dist(generator); - CAPTURE(numericalValue); - REQUIRE_SUCCESS(criterion.addValuePair(numericalValue, "Random", result), result); + const std::string criterionName = "ExclusiveCriterion"; + mIsInclusive = false; + WHEN("Creating it with some values") + { + Criterion criterion(criterionName, values, mLogger); + checkCriterionBasicBehavior(criterion, criterionName, values); + } + WHEN("Creating it with only one value") + { + REQUIRE_THROWS_AS(Criterion criterion(criterionName, {"A"}, mLogger), + Criterion::InvalidCriterionError); + } + checkNoValue(criterionName); + checkDisplay(criterionName); } - } - - GIVEN("An inclusive criterion") - { - const std::string criterionName = "InclusiveCriterion"; - InclusiveCriterion criterion(criterionName, mLogger); - THEN("The criterion is inclusive") + GIVEN("An inclusive criterion") { - CHECK(criterion.isInclusive()); - } - THEN("Default state is available") - { - const std::string defaultState = "none"; - CHECK(criterion.listPossibleValues() == "{" + defaultState + "}"); - int numericalValue; - REQUIRE_SUCCESS(criterion.getNumericalValue(defaultState, numericalValue)); - CHECK(numericalValue == 0); - std::string literalValue; - REQUIRE_SUCCESS(criterion.getLiteralValue(0, literalValue)); - CHECK(literalValue == defaultState); - } - THEN("Default state is set") - { - CHECK(criterion.getCriterionState() == 0); - CHECK(criterion.getFormattedState() == "none"); - } + const std::string criterionName = "InclusiveCriterion"; + mIsInclusive = true; + WHEN("Creating it with some values") + { + InclusiveCriterion criterion(criterionName, values, mLogger); - checkCriterionBasicBehavior(criterion, criterionName); + THEN("Default state is set") + { + CHECK(criterion.getState() == State{}); + } - WHEN("We add a state with 0 as numerical value") - { - std::string result; - REQUIRE_FAILURE(criterion.addValuePair(0, "Crit_0", result), result); - } - WHEN("We add a numerical value with more than one bit set") - { - std::string result; - REQUIRE_FAILURE(criterion.addValuePair(3, "InvalidMask", result), result); + checkCriterionBasicBehavior(criterion, criterionName, values); + } + checkNoValue(criterionName); + checkDisplay(criterionName); } } } @@ -641,30 +564,43 @@ SCENARIO_METHOD(CriteriaTest, "Criteria Use", "[criterion]") GIVEN("A criteria object") { + WHEN("Adding invalid criteria") + { + std::string error; + REQUIRE_FAILURE(mCriteria.createInclusiveCriterion("InvalidInclusive", {}, + mLogger, error), + error); + REQUIRE_FAILURE(mCriteria.createExclusiveCriterion("InvalidExclusive", {}, + mLogger, error), + error); + } WHEN("Adding some criteria") { - + Values values = { "State", "State2" }; for (auto& description : mDescriptions) { + std::string error; Criterion* addedCriterion = (description.isInclusive ? mCriteria.createInclusiveCriterion(description.name, - mLogger) : + values, mLogger, + error) : mCriteria.createExclusiveCriterion(description.name, - mLogger)); + values, mLogger, + error)); + REQUIRE_SUCCESS(addedCriterion != nullptr, error); description.criterion = addedCriterion; THEN("Added criteria match the request") { CAPTURE(description.name); - CHECK(addedCriterion->isInclusive() == description.isInclusive); - CHECK(addedCriterion->getCriterionName() == description.name); + CHECK(addedCriterion->getName() == description.name); } } WHEN("Retrieving added criteria") { for (auto& description : mDescriptions) { CAPTURE(description.name); - CHECK(mCriteria.getSelectionCriterion(description.name) == + CHECK(mCriteria.getCriterion(description.name) == description.criterion); - const Criterion* criterion = mCriteria.getSelectionCriterion(description.name); + const Criterion* criterion = mCriteria.getCriterion(description.name); CHECK(criterion == description.criterion); } } @@ -673,15 +609,13 @@ SCENARIO_METHOD(CriteriaTest, "Criteria Use", "[criterion]") /** FIXME: nullptr in check expression is not available in * Ubuntu catch version for now. We should upgrade it one day. */ - CHECK(mCriteria.getSelectionCriterion("Unknown") == NULL); + CHECK(mCriteria.getCriterion("Unknown") == NULL); } WHEN("Modifying criteria") { for (auto& description : mDescriptions) { - std::string result; - REQUIRE_SUCCESS(description.criterion->addValuePair(1, "State", result), - result); - description.criterion->setCriterionState(1); + std::string error; + REQUIRE_SUCCESS(description.criterion->setState(State{"State2"}, error), error); CHECK(description.criterion->hasBeenModified()); } WHEN("Resetting criteria status") @@ -706,19 +640,27 @@ SCENARIO_METHOD(CriteriaTest, "Criteria Use", "[criterion]") { std::string xmlDescription = R"( - - - - - - - - - - )"; + + + State + State2 + + + State + State2 + + + State + State2 + + + State + State2 + + )"; std::string result; - xmlSerialize(result, &mCriteria, "SelectionCriteria"); + xmlSerialize(result, &mCriteria, "Criteria"); // Remove whitespaces as they are not relevant in xml removeWhitespaces(result); diff --git a/parameter/include/ParameterMgrFullConnector.h b/parameter/include/ParameterMgrFullConnector.h index f78765dd6..a53e0efcd 100644 --- a/parameter/include/ParameterMgrFullConnector.h +++ b/parameter/include/ParameterMgrFullConnector.h @@ -31,7 +31,7 @@ #include "ParameterHandle.h" #include "ParameterMgrLoggerForward.h" -#include +#include #include #include @@ -75,23 +75,37 @@ class CParameterMgrFullConnector * Should be called before start * * @param[in] name, the criterion name - * @return raw pointer on the criterion interface + * @param[in] values available value pairs for the created criterion + * @param[out] error the string describing the error if an error occurred + * undefined otherwise + * @return raw pointer on the criterion interface, nullptr if the method fail */ - core::criterion::CriterionInterface* - createExclusiveCriterion(const std::string& name); + core::criterion::Criterion* + createExclusiveCriterion(const std::string& name, + const core::criterion::Values& values, + std::string& error); /** Create a new Inclusive criterion * Beware returned objects shall not be deleted by client. * Should be called before start * * @param[in] name, the criterion name - * @return raw pointer on the criterion interface + * @param[in] values available value pairs for the created criterion + * @param[out] error the string describing the error if an error occurred + * undefined otherwise + * @return raw pointer on the criterion interface, nullptr if the method fail */ - core::criterion::CriterionInterface* - createInclusiveCriterion(const std::string& name); + core::criterion::Criterion* + createInclusiveCriterion(const std::string& name, + const core::criterion::Values& values, + std::string& error); - core::criterion::CriterionInterface* - getSelectionCriterion(const std::string& strName); + /** Criterion retrieval + * + * @param[in] strName the criterion name + * @return the pointer on the desired criterion, nullptr otherwise + */ + core::criterion::Criterion* getCriterion(const std::string& strName); /** Is the remote interface forcefully disabled ? */ diff --git a/parameter/include/ParameterMgrPlatformConnector.h b/parameter/include/ParameterMgrPlatformConnector.h index e9a838296..20f33fede 100644 --- a/parameter/include/ParameterMgrPlatformConnector.h +++ b/parameter/include/ParameterMgrPlatformConnector.h @@ -31,7 +31,7 @@ #include "ParameterHandle.h" #include "ParameterMgrLoggerForward.h" -#include +#include class CParameterMgr; @@ -58,24 +58,37 @@ class CParameterMgrPlatformConnector * Should be called before start * * @param[in] name, the criterion name - * @return raw pointer on the criterion interface + * @param[in] values available value pairs for the created criterion + * @param[out] error the string describing the error if an error occurred + * undefined otherwise + * @return raw pointer on the criterion interface, nullptr if the method fail */ - core::criterion::CriterionInterface* - createExclusiveCriterion(const std::string& name); + core::criterion::Criterion* + createExclusiveCriterion(const std::string& name, + const core::criterion::Values& values, + std::string& error); /** Create a new Inclusive criterion * Beware returned objects shall not be deleted by client. * Should be called before start * * @param[in] name, the criterion name - * @return raw pointer on the criterion interface + * @param[in] values available value pairs for the created criterion + * @param[out] error the string describing the error if an error occurred + * undefined otherwise + * @return raw pointer on the criterion interface, nullptr if the method fail */ - core::criterion::CriterionInterface* - createInclusiveCriterion(const std::string& name); + core::criterion::Criterion* + createInclusiveCriterion(const std::string& name, + const core::criterion::Values& values, + std::string& error); - // Selection criterion retrieval - core::criterion::CriterionInterface* - getSelectionCriterion(const std::string& strName) const; + /** Criterion retrieval + * + * @param[in] strName the criterion name + * @return the pointer on the desired criterion, nullptr otherwise + */ + core::criterion::Criterion* getCriterion(const std::string& strName) const; // Logging // Should be called before start diff --git a/test/test-platform/TestPlatform.cpp b/test/test-platform/TestPlatform.cpp index cdc103988..317ddf178 100644 --- a/test/test-platform/TestPlatform.cpp +++ b/test/test-platform/TestPlatform.cpp @@ -41,7 +41,7 @@ #include "RemoteProcessorServer.h" using std::string; -using core::criterion::CriterionInterface; +using core::criterion::Criterion; class CParameterMgrPlatformConnectorLogger : public CParameterMgrPlatformConnector::ILogger { @@ -71,22 +71,22 @@ CTestPlatform::CTestPlatform(const string& strClass, int iPortNumber, sem_t& exi 0, "", "Exit TestPlatform"); _pCommandHandler->addCommandParser( "createExclusiveCriterionFromStateList", - &CTestPlatform::createExclusiveCriterionFromStateList, + &CTestPlatform::createCriterionFromStateList, 2, " ", "Create inclusive selection criterion from state name list"); _pCommandHandler->addCommandParser( "createInclusiveCriterionFromStateList", - &CTestPlatform::createInclusiveCriterionFromStateList, + &CTestPlatform::createCriterionFromStateList, 2, " ", "Create exclusive selection criterion from state name list"); _pCommandHandler->addCommandParser( "createExclusiveCriterion", - &CTestPlatform::createExclusiveCriterion, + &CTestPlatform::createCriterionCommand, 2, " ", "Create inclusive selection criterion"); _pCommandHandler->addCommandParser( "createInclusiveCriterion", - &CTestPlatform::createInclusiveCriterion, + &CTestPlatform::createCriterionCommand, 2, " ", "Create exclusive selection criterion"); _pCommandHandler->addCommandParser("start", &CTestPlatform::startParameterMgr, @@ -171,40 +171,24 @@ bool CTestPlatform::load(std::string& strError) } //////////////// Remote command parsers -/// Selection Criterion -CTestPlatform::CommandReturn -CTestPlatform::createExclusiveCriterionFromStateList(const IRemoteCommand& remoteCommand, - string& strResult) -{ - return createExclusiveCriterionFromStateList(remoteCommand.getArgument(0), - remoteCommand, strResult) ? - CTestPlatform::CCommandHandler::EDone : CTestPlatform::CCommandHandler::EFailed; -} - -CTestPlatform::CommandReturn CTestPlatform::createInclusiveCriterionFromStateList( - const IRemoteCommand& remoteCommand, string& strResult) -{ - return createInclusiveCriterionFromStateList(remoteCommand.getArgument(0), - remoteCommand, strResult) ? - CTestPlatform::CCommandHandler::EDone : CTestPlatform::CCommandHandler::EFailed; -} +/// Criterion -CTestPlatform::CommandReturn -CTestPlatform::createExclusiveCriterion(const IRemoteCommand& remoteCommand, - string& strResult) +template CTestPlatform::CommandReturn +CTestPlatform::createCriterionFromStateList(const IRemoteCommand& remoteCommand, + string& strResult) { - return createExclusiveCriterion(remoteCommand.getArgument(0), - strtoul(remoteCommand.getArgument(1).c_str(), NULL, 0), - strResult) ? + return createCriterion(remoteCommand.getArgument(0), + remoteCommand, strResult) ? CTestPlatform::CCommandHandler::EDone : CTestPlatform::CCommandHandler::EFailed; } -CTestPlatform::CommandReturn -CTestPlatform::createInclusiveCriterion(const IRemoteCommand& remoteCommand, string& strResult) +template CTestPlatform::CommandReturn +CTestPlatform::createCriterionCommand(const IRemoteCommand& remoteCommand, string& strResult) { - return createInclusiveCriterion(remoteCommand.getArgument(0), - strtoul(remoteCommand.getArgument(1).c_str(), NULL, 0), - strResult) ? + return createCriterion( + remoteCommand.getArgument(0), + (uint32_t) strtoul(remoteCommand.getArgument(1).c_str(), NULL, 0), + strResult) ? CTestPlatform::CCommandHandler::EDone : CTestPlatform::CCommandHandler::EFailed; } @@ -247,30 +231,33 @@ CTestPlatform::CommandReturn CTestPlatform::getter( CTestPlatform::CommandReturn CTestPlatform::setCriterionState( const IRemoteCommand& remoteCommand, string& strResult) { + // Get criterion name + std::string strCriterionName = remoteCommand.getArgument(0); - bool bSuccess; - - const char* pcState = remoteCommand.getArgument(1).c_str(); + Criterion* pCriterion = + _pParameterMgrPlatformConnector->getCriterion(strCriterionName); - char* pcStrEnd; + if (!pCriterion) { - // Reset errno to check if it is updated during the conversion (strtol/strtoul) - errno = 0; + strResult = "Unable to retrieve selection criterion: " + strCriterionName; - uint32_t state = strtoul(pcState, &pcStrEnd, 0); + return CTestPlatform::CCommandHandler::EFailed; + } - if (!errno && (*pcStrEnd == '\0')) { - // Sucessfull conversion, set criterion state by numerical state - bSuccess = setCriterionState(remoteCommand.getArgument(0), state, strResult); + // Get substate number, the first argument (index 0) is the criterion name + uint32_t uiNbSubStates = remoteCommand.getArgumentCount() - 1; - } else { - // Conversion failed, set criterion state by lexical state - bSuccess = setCriterionStateByLexicalSpace(remoteCommand, strResult); + core::criterion::State state{}; + for (uint32_t i = 1; i <= uiNbSubStates; i++) { + state.emplace(remoteCommand.getArgument(i)); } - return bSuccess ? CTestPlatform::CCommandHandler::EDone : CTestPlatform::CCommandHandler:: - EFailed; + // Set criterion new state + if (!pCriterion->setState(state, strResult)) { + return CTestPlatform::CCommandHandler::EFailed; + } + return CTestPlatform::CCommandHandler::EDone; } CTestPlatform::CommandReturn CTestPlatform::applyConfigurations(const IRemoteCommand& remoteCommand, @@ -286,216 +273,57 @@ CTestPlatform::CommandReturn CTestPlatform::applyConfigurations(const IRemoteCom //////////////// Remote command handlers -bool CTestPlatform::createExclusiveCriterionFromStateList(const string& strName, - const IRemoteCommand& remoteCommand, - string& strResult) +template +bool CTestPlatform::createCriterion(const string& name, + const IRemoteCommand& remoteCommand, + string& result) { assert(_pParameterMgrPlatformConnector != NULL); - CriterionInterface* pCriterion = - _pParameterMgrPlatformConnector->createExclusiveCriterion(strName); - - assert(pCriterion!= NULL); - - uint32_t uiNbStates = remoteCommand.getArgumentCount() - 1; - uint32_t uiState; + uint32_t nbStates = remoteCommand.getArgumentCount() - 1; - for (uiState = 0; uiState < uiNbStates; uiState++) { + using namespace core::criterion; + Values values; - const std::string& strValue = remoteCommand.getArgument(uiState + 1); + for (uint32_t state = 0; state < nbStates; state++) { - if (!pCriterion->addValuePair(uiState, strValue, strResult)) { - - strResult = "Unable to add value: " + strValue + ": " + strResult; - - return false; - } + const std::string& value = remoteCommand.getArgument(state + 1); + values.emplace_back(value); } - - - return true; + return createCriterion(name, values, result); } -bool CTestPlatform::createInclusiveCriterionFromStateList(const string& strName, - const IRemoteCommand& remoteCommand, - string& strResult) +template +bool CTestPlatform::createCriterion(const string& name, + uint32_t nbStates, + string& result) { - assert(_pParameterMgrPlatformConnector != NULL); - - CriterionInterface* pCriterion = - _pParameterMgrPlatformConnector->createInclusiveCriterion(strName); - - assert(pCriterion != NULL); - - uint32_t uiNbStates = remoteCommand.getArgumentCount() - 1; - - if (uiNbStates > 32) { - - strResult = "Maximum number of states for inclusive criterion is 32"; - - return false; - } - - uint32_t uiState; - - for (uiState = 0; uiState < uiNbStates; uiState++) { - - const std::string& strValue = remoteCommand.getArgument(uiState + 1); - - if (!pCriterion->addValuePair(0x1 << uiState, strValue, strResult)) { - - strResult = "Unable to add value: " + strValue + ": " + strResult; - - return false; - } + using namespace core::criterion; + Values values; + + for (uint32_t state = 0; state < nbStates; state++) { + // Generate value names, those name are legacy and should be uniformized + // after functionnal tests rework + values.emplace_back((isInclusive ? "State_0x" + std::to_string(state + 1) : + "State_" + std::to_string(state))); } - - return true; + return createCriterion(name, values, result); } - -bool CTestPlatform::createExclusiveCriterion(const string& strName, - uint32_t uiNbStates, - string& strResult) +template +bool CTestPlatform::createCriterion(const string& name, + const core::criterion::Values &values, + string& result) { - CriterionInterface* pCriterion = - _pParameterMgrPlatformConnector->createExclusiveCriterion(strName); - - uint32_t uistate; - - for (uistate = 0; uistate < uiNbStates; uistate++) { - - std::ostringstream ostrValue; - - ostrValue << "State_"; - ostrValue << uistate; - - if (!pCriterion->addValuePair(uistate, ostrValue.str(), strResult)) { + Criterion* criterion = (isInclusive ? + _pParameterMgrPlatformConnector->createInclusiveCriterion(name, values, result) : + _pParameterMgrPlatformConnector->createExclusiveCriterion(name, values, result)); - strResult = "Unable to add value: " - + ostrValue.str() + ": " + strResult; - - return false; - } - } - - return true; -} - -bool CTestPlatform::createInclusiveCriterion(const string& strName, - uint32_t uiNbStates, - string& strResult) -{ - CriterionInterface* pCriterion = - _pParameterMgrPlatformConnector->createInclusiveCriterion(strName); - - if (uiNbStates > 32) { - - strResult = "Maximum number of states for inclusive criterion is 32"; - - return false; - } - - uint32_t uiState; - - for (uiState = 0; uiState < uiNbStates; uiState++) { - - std::ostringstream ostrValue; - - ostrValue << "State_0x"; - ostrValue << (0x1 << uiState); - - if (!pCriterion->addValuePair(0x1 << uiState, ostrValue.str(), strResult)) { - - strResult = "Unable to add value: " - + ostrValue.str() + ": " + strResult; - - return false; - } - } - - return true; -} - -bool CTestPlatform::setCriterionState(const string& strName, uint32_t uiState, string& strResult) -{ - CriterionInterface* pCriterion = - _pParameterMgrPlatformConnector->getSelectionCriterion(strName); - - if (!pCriterion) { - - strResult = "Unable to retrieve selection criterion: " + strName; + if (criterion == nullptr) { return false; } - pCriterion->setCriterionState(uiState); - - return true; -} - -bool CTestPlatform::setCriterionStateByLexicalSpace(const IRemoteCommand& remoteCommand, - string& strResult) -{ - - // Get criterion name - std::string strCriterionName = remoteCommand.getArgument(0); - - CriterionInterface* pCriterion = - _pParameterMgrPlatformConnector->getSelectionCriterion(strCriterionName); - - if (!pCriterion) { - - strResult = "Unable to retrieve selection criterion: " + strCriterionName; - - return false; - } - - // Get substate number, the first argument (index 0) is the criterion name - uint32_t uiNbSubStates = remoteCommand.getArgumentCount() - 1; - - // Check that exclusive criterion has only one substate - if (!pCriterion->isInclusive() && uiNbSubStates != 1) { - - strResult = "Exclusive criterion " + strCriterionName + " can only have one state"; - - return false; - } - - /// Translate lexical state to numerical state - int iNumericalState = 0; - uint32_t uiLexicalSubStateIndex; - - // Parse lexical substates - std::string strLexicalState = ""; - - for (uiLexicalSubStateIndex = 1; - uiLexicalSubStateIndex <= uiNbSubStates; - uiLexicalSubStateIndex++) { - /* - * getNumericalValue method from CriterionInterface strip his parameter - * first parameter based on | sign. In case that the user uses multiple parameters - * to set InclusiveCriterion value, we aggregate all desired values to be sure - * they will be handled correctly. - */ - if (uiLexicalSubStateIndex != 1) { - strLexicalState += "|"; - } - strLexicalState += remoteCommand.getArgument(uiLexicalSubStateIndex); - } - - // Translate lexical to numerical substate - if (!pCriterion->getNumericalValue(strLexicalState, iNumericalState)) { - - strResult = "Unable to find lexical state \"" - + strLexicalState + "\" in criteria " + strCriterionName; - - return false; - } - - // Set criterion new state - pCriterion->setCriterionState(iNumericalState); - return true; } diff --git a/test/test-platform/TestPlatform.h b/test/test-platform/TestPlatform.h index d4f8cd82c..9a5b80f38 100644 --- a/test/test-platform/TestPlatform.h +++ b/test/test-platform/TestPlatform.h @@ -52,56 +52,36 @@ class CTestPlatform private: //////////////// Remote command parsers - /** Callback to create an Exclusive Criterion from possible state list + /** Callback to create a Criterion from possible state list * @see CCommandHandler::RemoteCommandParser for detail on each arguments and return * + * @tparam isInclusive true for creating inclusive criterion, false for an exclusive one * @param[in] remoteCommand the first argument should be the name of the criterion to create. * the following arguments should be criterion possible values */ - CommandReturn createExclusiveCriterionFromStateList(const IRemoteCommand& remoteCommand, - std::string& strResult); - - /** Callback to create an Inclusive Criterion from possible state list - * @see CCommandHandler::RemoteCommandParser for detail on each arguments and return - * - * @param[in] remoteCommand the first argument should be the name of the criterion to create. - * the following arguments should be criterion possible values - */ - CommandReturn createInclusiveCriterionFromStateList(const IRemoteCommand& remoteCommand, - std::string& strResult); + template + CommandReturn createCriterionFromStateList(const IRemoteCommand& remoteCommand, + std::string& strResult); - /** Callback to create an Exclusive Criterion + /** Callback to create a Criterion * @see CCommandHandler::RemoteCommandParser for detail on each arguments and return * + * @tparam isInclusive true for creating inclusive criterion, false for an exclusive one * @param[in] remoteCommand the first argument should be the name of the criterion to create. * the second argument should be criterion possible values number * * Generated states numerical value will be like: State_0xX, where X is the value number of the * state. */ - CommandReturn createExclusiveCriterion(const IRemoteCommand& remoteCommand, - std::string& strResult); - - /** Callback to create an Inclusive Criterion - * @see CCommandHandler::RemoteCommandParser for detail on each arguments and return - * - * @param[in] remoteCommand the first argument should be the name of the criterion to create. - * the second argument should be criterion possible values number - * - * Generated states numerical value will be like: State_X, where X is the value number of the - * state. - */ - CommandReturn createInclusiveCriterion(const IRemoteCommand& remoteCommand, - std::string& strResult); + template + CommandReturn createCriterionCommand(const IRemoteCommand& remoteCommand, + std::string& strResult); /** Callback to set a criterion's value, see CriterionInterface::setCriterionState. * @see CCommandHandler::RemoteCommandParser for detail on each arguments and return * * @param[in] remoteCommand the first argument should be the name of the criterion to set. - * if the criterion is provided in lexical space, - * the following arguments should be criterion new values - * if the criterion is provided in numerical space, - * the second argument should be the criterion new value + * the following arguments should be criterion new values */ CommandReturn setCriterionState( const IRemoteCommand& remoteCommand, std::string& strResult); @@ -165,46 +145,43 @@ class CTestPlatform // Commands - /** @see callback with the same name for details and other parameters + /** @see callback with the same arguments for details and other parameters * - * @param[out] strResult useful information that client may want to retrieve - * @return true if success, false otherwise - */ - bool createExclusiveCriterionFromStateList(const std::string& strName, - const IRemoteCommand& remoteCommand, - std::string& strResult); - - /** @see callback with the same name for details and other parameters + * @tparam isInclusive true for creating inclusive criterion, false for an exclusive one * - * @param[out] strResult useful information that client may want to retrieve + * @param[in] name the criterion name + * @param[out] result useful information that client may want to retrieve * @return true if success, false otherwise */ - bool createInclusiveCriterionFromStateList(const std::string& strName, - const IRemoteCommand& remoteCommand, - std::string& strResult); + template + bool createCriterion(const std::string& name, + const IRemoteCommand& command, + std::string& result); - /** @see callback with the same name for details and other parameters + /** Create a criterion by generating a given number of values * - * @param[in] uiNbValues number of possible state value the criterion can have - * @param[out] strResult useful information that client may want to retrieve + * @tparam isInclusive true for creating inclusive criterion, false for an exclusive one + * + * @param[in] name the criterion name + * @param[in] nbValues number of possible state value the criterion can have + * @param[out] result useful information that client may want to retrieve * @return true if success, false otherwise */ - bool createExclusiveCriterion(const std::string& strName, - uint32_t uiNbValues, - std::string& strResult); + template + bool createCriterion(const std::string& name, uint32_t nbValues, std::string& result); - /** @see callback with the same name for details and other parameters + /** Create a criterion with desired values + * @tparam isInclusive true for creating inclusive criterion, false for an exclusive one * - * @param[in] uiNbValues number of possible state value the criterion can have - * @param[out] strResult useful information that client may want to retrieve + * @param[in] name the criterion name + * @param[in] values criterion desired values + * @param[out] result useful information that client may want to retrieve * @return true if success, false otherwise */ - bool createInclusiveCriterion(const std::string& strName, - uint32_t uiNbValues, - std::string& strResult); - - bool setCriterionState(const std::string& strName, uint32_t uiState, std::string& strResult); - bool setCriterionStateByLexicalSpace(const IRemoteCommand& remoteCommand, std::string& strResult); + template + bool createCriterion(const std::string& name, + const core::criterion::Values &values, + std::string& result); // Connector CParameterMgrPlatformConnector* _pParameterMgrPlatformConnector;