Skip to content
This repository was archived by the owner on Aug 5, 2022. It is now read-only.

Commit d80f11e

Browse files
committed
Merge pull request #96 from clero/criterion_rework
Criterion API rework Previous criterion API was error prone in many point: - exposition of internal components of a criterion - no check when setting a criterion - inclusive criterion were limited to 31 values - no check for inclusive criterion limit - Liskov principle was broken due to isInclusive method This rework introduces a new criterion API which corrects those issues.
2 parents 1702db4 + 5947963 commit d80f11e

34 files changed

+1030
-1139
lines changed

bindings/c/ParameterFramework.cpp

Lines changed: 62 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
#include <ParameterMgrPlatformConnector.h>
3333

3434
#include <iostream>
35-
#include <limits>
3635
#include <string>
3736
#include <map>
3837

@@ -41,12 +40,12 @@
4140
#include <cstdlib>
4241

4342
using std::string;
44-
using core::criterion::CriterionInterface;
43+
using core::criterion::Criterion;
4544

4645
/** Rename long pfw types to short ones in pfw namespace. */
4746
namespace pfw
4847
{
49-
typedef std::map<string, CriterionInterface *> Criteria;
48+
typedef std::map<string, Criterion*> Criteria;
5049
typedef CParameterMgrPlatformConnector Pfw;
5150
}
5251

@@ -187,30 +186,19 @@ bool PfwHandler::createCriteria(const PfwCriterion criteriaArray[], size_t crite
187186
"\" already exist");
188187
}
189188

190-
// Create criterion
191-
CriterionInterface *newCriterion = (criterion.inclusive ?
192-
pfw->createInclusiveCriterion(criterion.name) :
193-
pfw->createExclusiveCriterion(criterion.name));
194-
assert(newCriterion != NULL);
195-
// Add criterion values
189+
// Create criterion values
190+
core::criterion::Values values;
196191
for (size_t valueIndex = 0; criterion.values[valueIndex] != NULL; ++valueIndex) {
197-
int value;
198-
if (criterion.inclusive) {
199-
// Check that (int)1 << valueIndex would not overflow (UB)
200-
if(std::numeric_limits<int>::max() >> valueIndex == 0) {
201-
return status.failure("Too many values for criterion " +
202-
string(criterion.name));
203-
}
204-
value = 1 << valueIndex;
205-
} else {
206-
value = valueIndex;
207-
}
208-
const char * valueName = criterion.values[valueIndex];
209-
string error;
210-
if(not newCriterion->addValuePair(value, valueName, error)) {
211-
return status.failure("Could not add value " + string(valueName) +
212-
" to criterion " + criterion.name + ": " + error);
213-
}
192+
values.emplace_back(criterion.values[valueIndex]);
193+
}
194+
// Create criterion
195+
string error;
196+
Criterion *newCriterion = (criterion.inclusive ?
197+
pfw->createInclusiveCriterion(criterion.name, values, error) :
198+
pfw->createExclusiveCriterion(criterion.name, values, error));
199+
if (newCriterion == nullptr) {
200+
return status.failure("Could not create criterion '" + string(criterion.name) +
201+
"': " + error);
214202
}
215203
// Add new criterion to criteria list
216204
criteria[criterion.name] = newCriterion;
@@ -256,13 +244,13 @@ const char *pfwGetLastError(const PfwHandler *handle)
256244
return handle == NULL ? NULL : handle->lastStatus.msg().c_str();
257245
}
258246

259-
static CriterionInterface *getCriterion(const pfw::Criteria &criteria, const string &name)
247+
static Criterion *getCriterion(const pfw::Criteria &criteria, const string &name)
260248
{
261249
pfw::Criteria::const_iterator it = criteria.find(name);
262250
return it == criteria.end() ? NULL : it->second;
263251
}
264252

265-
bool pfwSetCriterion(PfwHandler *handle, const char name[], int value)
253+
bool pfwSetCriterion(PfwHandler *handle, const char name[], const char **values)
266254
{
267255
if (handle == NULL) { return Status::failure(); }
268256
Status &status = handle->lastStatus;
@@ -274,35 +262,64 @@ bool pfwSetCriterion(PfwHandler *handle, const char name[], int value)
274262
return status.failure("Can not set criterion \"" + string(name) +
275263
"\" as the parameter framework is not started.");
276264
}
277-
CriterionInterface *criterion = getCriterion(handle->criteria, name);
265+
Criterion *criterion = getCriterion(handle->criteria, name);
278266
if (criterion == NULL) {
279267
return status.failure("Can not set criterion " + string(name) + " as does not exist");
280268
}
281-
criterion->setCriterionState(value);
282-
return status.success();
269+
core::criterion::State state{};
270+
for (size_t valueIndex = 0; values[valueIndex] != NULL; ++valueIndex) {
271+
state.emplace(values[valueIndex]);
272+
}
273+
return status.forward(criterion->setState(state, status.msg()));
283274
}
284-
bool pfwGetCriterion(const PfwHandler *handle, const char name[], int *value)
275+
const char **pfwGetCriterion(const PfwHandler *handle, const char name[])
285276
{
286-
if (handle == NULL) { return Status::failure(); }
277+
if (handle == NULL) { return NULL; }
287278
Status &status = handle->lastStatus;
288279
if (name == NULL) {
289-
return status.failure("char *name of the criterion is NULL, "
290-
"while getting a criterion.");
280+
status.failure("char *name of the criterion is NULL, while getting a criterion.");
281+
return NULL;
291282
}
292283
if (handle->pfw == NULL) {
293-
return status.failure("Can not get criterion \"" + string(name) +
294-
"\" as the parameter framework is not started.");
295-
}
296-
if (value == NULL) {
297-
return status.failure("Can not get criterion \"" + string(name) +
298-
"\" as the out value is NULL.");
284+
status.failure("Can not get criterion \"" + string(name) +
285+
"\" as the parameter framework is not started.");
286+
return NULL;
299287
}
300-
CriterionInterface *criterion = getCriterion(handle->criteria, name);
288+
Criterion *criterion = getCriterion(handle->criteria, name);
301289
if (criterion == NULL) {
302-
return status.failure("Can not get criterion " + string(name) + " as it does not exist");
290+
status.failure("Can not get criterion " + string(name) + " as it does not exist");
291+
return NULL;
303292
}
304-
*value = criterion->getCriterionState();
305-
return status.success();
293+
core::criterion::State state = criterion->getState();
294+
295+
// Allocating one slot for each criterion value plus one for the NULL end delimiter
296+
const char **values = static_cast<const char**>(malloc((state.size() + 1) * sizeof(char*)));
297+
if (values == nullptr) {
298+
status.failure("Can not get criterion " + string(name) + " as there is no memory left");
299+
return NULL;
300+
}
301+
302+
size_t i = 0;
303+
for (auto &critValue : state) {
304+
values[i] = strdup(critValue.c_str());
305+
if (values[i] == nullptr) {
306+
status.failure("Can not get criterion " + string(name) +
307+
" as there is no memory left (errno: " + strerror(errno) + ")");
308+
return NULL;
309+
}
310+
++i;
311+
}
312+
values[i] = NULL;
313+
return values;
314+
}
315+
316+
void pfwCriterionValueFree(const char **value)
317+
{
318+
const char **valueSav = value;
319+
while(*value != NULL) {
320+
std::free(*const_cast<char**>(value++));
321+
}
322+
std::free(valueSav);
306323
}
307324

308325
bool pfwApplyConfigurations(const PfwHandler *handle)

bindings/c/ParameterFramework.h

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,25 +156,36 @@ const char *pfwGetLastError(const PfwHandler *handle) NONNULL;
156156
/** Set a criterion value given its name and value.
157157
* @param handle[in] @see PfwHandler
158158
* @param name[in] The name of the criterion that need to be changed.
159-
* @param value If the criterion is exclusive, the index of the new value.
160-
* If the criterion is inclusive, a bit field where each bit
161-
* correspond to the value index.
159+
* @param value If the criterion is exclusive, an array containing the new value.
160+
* If the criterion is inclusive, an array containing all new values.
162161
* For an inclusive criterion defined as such: { "Red", "Green", "Blue", NULL }
163-
* to set the value Green and Blue, value has to be 1<<1 | 1<<2 = 0b110 = 6.
162+
* to set the value Green and Blue, value has to be ["Green", "Blue", NULL].
164163
* For an exclusive criterion defined as such: { "Car", "Boat", "Plane", NULL }
165-
* to set the value Plane, value has to be 2.
164+
* to set the value Plane, value has to be ["Plane", NULL].
166165
*
167166
* Criterion change do not have impact on the parameters value
168167
* (no configuration applied) until the changes are committed using pfwApplyConfigurations.
169168
*
170169
* @return true on success and false on failure.
171170
*/
172-
bool pfwSetCriterion(PfwHandler *handle, const char name[], int value) NONNULL USERESULT;
171+
bool pfwSetCriterion(PfwHandler *handle, const char name[], const char **values) NONNULL USERESULT;
173172
/** Get a criterion value given its name.
174-
* Same usage as pfwSetCriterion except that value is an out param.
173+
* @param handle[in] @see PfwHandler
174+
* @param name[in] The name of the criterion that need to be changed.
175+
* @return an NULL terminated array of char* which store criterion values if success
176+
* NULL otherwise
175177
* Get criterion will return the last value setted with pfwSetCriterion independantly of pfwCommitCritenio.
178+
* The callee MUST free the returned value array using pfwCriterionValueFree after use.
179+
*/
180+
const char **pfwGetCriterion(const PfwHandler *handle, const char name[]) NONNULL USERESULT;
181+
182+
/** Frees the memory space of criterion value array,
183+
* which must have been returned by a previous call to pfwGetCriterion.
184+
*
185+
* @param value[in] pointer to the memory to free.
186+
* @see man 3 free for usage.
176187
*/
177-
bool pfwGetCriterion(const PfwHandler *handle, const char name[], int *value) NONNULL USERESULT;
188+
void pfwCriterionValueFree(const char **value);
178189

179190
/** Commit criteria change and change parameters according to the configurations.
180191
* Criterion do not have impact on the parameters value when changed,

bindings/c/Test.cpp

Lines changed: 36 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -182,18 +182,6 @@ TEST_CASE_METHOD(Test, "Parameter-framework c api use") {
182182
};
183183
REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 2, &logger));
184184
}
185-
WHEN("The pfw is started with duplicated criterion value state") {
186-
const char * values[] = {"a", "a", NULL};
187-
const PfwCriterion duplicatedCriteria[] = {{"name", true, values}};
188-
189-
WHEN("Using test logger") {
190-
REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
191-
}
192-
WHEN("Using default logger") {
193-
// Test coverage of default logger warning
194-
REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, NULL));
195-
}
196-
}
197185
WHEN("The pfw is started with NULL name criterion") {
198186
const PfwCriterion duplicatedCriteria[] = {{NULL, true, letterList}};
199187
REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
@@ -204,8 +192,8 @@ TEST_CASE_METHOD(Test, "Parameter-framework c api use") {
204192
}
205193
GIVEN("A criteria with lots of values")
206194
{
207-
// Build a criterion with as many value as there is bits in int.
208-
std::vector<char> names(sizeof(int) * CHAR_BIT + 1, 'a');
195+
// Build a criterion with a lot of value
196+
std::vector<char> names(300, 'a');
209197
names.back() = '\0';
210198
std::vector<const char *> values(names.size());
211199
for(size_t i = 0; i < values.size(); ++i) {
@@ -240,11 +228,7 @@ TEST_CASE_METHOD(Test, "Parameter-framework c api use") {
240228
*/
241229
const PfwCriterion duplicatedCriteria[] = {{"name", true, &values[0]}};
242230

243-
WHEN("The pfw is started with a too long criterion state list") {
244-
REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
245-
}
246-
WHEN("The pfw is started with max length criterion state list") {
247-
values[values.size() - 2] = NULL; // Hide last value
231+
WHEN("The pfw is started with a long criterion state list") {
248232
REQUIRE_SUCCESS(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
249233
}
250234
}
@@ -267,11 +251,11 @@ TEST_CASE_METHOD(Test, "Parameter-framework c api use") {
267251
}
268252

269253
WHEN("Get criterion of a stopped pfw") {
270-
int value;
271-
REQUIRE_FAILURE(pfwGetCriterion(pfw, criteria[0].name, &value));
254+
REQUIRE_FAILURE(pfwGetCriterion(pfw, criteria[0].name) != NULL);
272255
}
273256
WHEN("Set criterion of a stopped pfw") {
274-
REQUIRE_FAILURE(pfwSetCriterion(pfw, criteria[0].name, 1));
257+
std::vector<const char*> value{"1", NULL};
258+
REQUIRE_FAILURE(pfwSetCriterion(pfw, criteria[0].name, value.data()));
275259
}
276260
WHEN("Commit criteria of a stopped pfw") {
277261
REQUIRE_FAILURE(pfwApplyConfigurations(pfw));
@@ -284,55 +268,63 @@ TEST_CASE_METHOD(Test, "Parameter-framework c api use") {
284268
WHEN("The pfw is started correctly")
285269
{
286270
REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, &logger));
287-
int value;
271+
int value = 0;
288272

289273
WHEN("Get criterion without an handle") {
290-
REQUIRE(not pfwGetCriterion(NULL, criteria[0].name, &value));
274+
REQUIRE(pfwGetCriterion(NULL, criteria[0].name) == NULL);
291275
}
292276
WHEN("Get criterion without a name") {
293-
REQUIRE_FAILURE(pfwGetCriterion(pfw, NULL, &value));
294-
}
295-
WHEN("Get criterion without an output value") {
296-
REQUIRE_FAILURE(pfwGetCriterion(pfw, criteria[0].name, NULL));
277+
REQUIRE_FAILURE(pfwGetCriterion(pfw, NULL) != NULL);
297278
}
298279
WHEN("Get not existing criterion") {
299-
REQUIRE_FAILURE(pfwGetCriterion(pfw, "Do not exist", &value));
280+
REQUIRE_FAILURE(pfwGetCriterion(pfw, "Do not exist") != NULL);
300281
}
301-
THEN("All criterion should value 0") {
282+
THEN("All criterion should have their default value") {
302283
for(size_t i = 0; i < criterionNb; ++i) {
303284
const char *criterionName = criteria[i].name;
304285
CAPTURE(criterionName);
305-
REQUIRE_SUCCESS(pfwGetCriterion(pfw, criterionName, &value));
306-
REQUIRE(value == 0);
286+
const char **criterionGetValue = pfwGetCriterion(pfw, criterionName);
287+
REQUIRE_SUCCESS(criterionGetValue != NULL);
288+
REQUIRE(criterionGetValue != NULL);
289+
if (criteria[i].inclusive) {
290+
REQUIRE(criterionGetValue[0] == NULL);
291+
} else {
292+
REQUIRE(std::string(criterionGetValue[0]) == "1");
293+
}
294+
pfwCriterionValueFree(criterionGetValue);
307295
}
308296
}
309297

310298
WHEN("Set criterion without an handle") {
311-
REQUIRE(not pfwSetCriterion(NULL, criteria[0].name, 1));
299+
std::vector<const char*> setValue{"1", NULL};
300+
REQUIRE(not pfwSetCriterion(NULL, criteria[0].name, setValue.data()));
312301
}
313302
WHEN("Set criterion without a name") {
314-
REQUIRE_FAILURE(pfwSetCriterion(pfw, NULL, 2));
303+
std::vector<const char*> setValue{"2", NULL};
304+
REQUIRE_FAILURE(pfwSetCriterion(pfw, NULL, setValue.data()));
315305
}
316306
WHEN("Set not existing criterion") {
317-
REQUIRE_FAILURE(pfwSetCriterion(pfw, "Do not exist", 3));
307+
std::vector<const char*> setValue{"3", NULL};
308+
REQUIRE_FAILURE(pfwSetCriterion(pfw, "Do not exist", setValue.data()));
318309
}
319310
WHEN("Set criterion value") {
320311
for(size_t i = 0; i < criterionNb; ++i) {
312+
std::vector<const char*> setValue{(criteria[i].inclusive ? "b" : "2"), NULL};
321313
const char *criterionName = criteria[i].name;
322314
CAPTURE(criterionName);
323-
REQUIRE_SUCCESS(pfwSetCriterion(pfw, criterionName, 3));
324-
}
325-
THEN("Get criterion value should return what was set") {
326-
for(size_t i = 0; i < criterionNb; ++i) {
327-
const char *criterionName = criteria[i].name;
328-
CAPTURE(criterionName);
329-
REQUIRE_SUCCESS(pfwGetCriterion(pfw, criterionName, &value));
330-
REQUIRE(value == 3);
315+
REQUIRE_SUCCESS(pfwSetCriterion(pfw, criterionName, setValue.data()));
316+
THEN("Get criterion value should return what was set") {
317+
const char**criterionGetValue = pfwGetCriterion(pfw, criterionName);
318+
REQUIRE_SUCCESS(criterionGetValue != NULL);
319+
REQUIRE(std::string(criterionGetValue[0]) ==
320+
(criteria[i].inclusive ? "b" : "2"));
321+
pfwCriterionValueFree(criterionGetValue);
331322
}
332323
}
333324
WHEN("Set a new value to a criterion without committing first") {
325+
std::vector<const char*> setValue{"a", NULL};
334326
const char *criterionName = criteria[0].name;
335-
REQUIRE_SUCCESS(pfwSetCriterion(pfw, criterionName, 0));
327+
REQUIRE_SUCCESS(pfwSetCriterion(pfw, criterionName, setValue.data()));
336328
THEN("A warning message should have been displayed") {
337329
INFO("Previous pfw log: \n" + logLines);
338330
size_t logPos = logLines.find("Warning: Selection criterion "

0 commit comments

Comments
 (0)