Home | History | Annotate | Download | only in c
      1 /*
      2  * Copyright (c) 2015, Intel Corporation
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without modification,
      6  * are permitted provided that the following conditions are met:
      7  *
      8  * 1. Redistributions of source code must retain the above copyright notice, this
      9  * list of conditions and the following disclaimer.
     10  *
     11  * 2. Redistributions in binary form must reproduce the above copyright notice,
     12  * this list of conditions and the following disclaimer in the documentation and/or
     13  * other materials provided with the distribution.
     14  *
     15  * 3. Neither the name of the copyright holder nor the names of its contributors
     16  * may be used to endorse or promote products derived from this software without
     17  * specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
     23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "ParameterFramework.h"
     32 
     33 #include "TmpFile.hpp"
     34 
     35 #define CATCH_CONFIG_MAIN // This tells Catch to provide a main()
     36 #include <catch.hpp>
     37 
     38 #include <string>
     39 #include <memory>
     40 #include <vector>
     41 #include <array>
     42 
     43 #include <cstring>
     44 #include <cerrno>
     45 #include <climits>
     46 
     47 struct Test
     48 {
     49     /** @return true if str is empty. */
     50     bool empty(const char *str)
     51     {
     52         REQUIRE(str != NULL);
     53         return *str == '\0';
     54     }
     55 
     56     void REQUIRE_FAILURE(bool success)
     57     {
     58         THEN ("It should be an error") {
     59             INFO("Previous pfw log: \n" + logLines);
     60             CAPTURE(pfwGetLastError(pfw));
     61             CHECK(not success);
     62             CHECK(not empty(pfwGetLastError(pfw)));
     63         }
     64     }
     65 
     66     void REQUIRE_SUCCESS(bool success)
     67     {
     68         THEN ("It should be a success") {
     69             INFO("Previous pfw log: \n" + logLines);
     70             CAPTURE(pfwGetLastError(pfw));
     71             CHECK(success);
     72             CHECK(empty(pfwGetLastError(pfw)));
     73         }
     74     }
     75 
     76     /** Wrap utility::TmpFile to add an implicit convertion to the temporary file.
     77      *
     78      * This avoids dozens of .getPath() in the following tests. */
     79     class TmpFile : private parameterFramework::utility::TmpFile
     80     {
     81     private:
     82         using Base = parameterFramework::utility::TmpFile;
     83 
     84     public:
     85         using Base::TmpFile;
     86 
     87         using Base::getPath;
     88         /** Implicitly convert to the path of the temporary file. */
     89         operator const char *() const { return getPath().c_str(); }
     90     };
     91 
     92     /** Log in logLines. */
     93     static void logCb(void *voidLogLines, PfwLogLevel level, const char *logLine)
     94     {
     95         std::string &logLines = *reinterpret_cast<std::string *>(voidLogLines);
     96         switch (level) {
     97         case pfwLogWarning:
     98             logLines += "Warning: ";
     99             break;
    100         case pfwLogInfo:
    101             logLines += "Info: ";
    102         }
    103         logLines += logLine;
    104         logLines += '\n';
    105     }
    106 
    107     /** Log buffer, will only be display in case of failure */
    108     std::string logLines;
    109 
    110     /** Pfw handler used in the tests. */
    111     PfwHandler *pfw;
    112 };
    113 
    114 TEST_CASE_METHOD(Test, "Parameter-framework c api use")
    115 {
    116     // Create criteria
    117     const char *letterList[] = {"a", "b", "c", NULL};
    118     const char *numberList[] = {"1", "2", "3", NULL};
    119     const PfwCriterion criteria[] = {
    120         {"inclusiveCrit", true, letterList}, {"exclusiveCrit", false, numberList},
    121     };
    122     size_t criterionNb = sizeof(criteria) / sizeof(criteria[0]);
    123     PfwLogger logger = {&logLines, logCb};
    124 
    125     // Create valid pfw config file
    126     const char *intParameterPath = "/test/system/integer";
    127     const char *stringParameterPath = "/test/system/string";
    128     TmpFile system("<?xml version='1.0' encoding='UTF-8'?>\
    129         <Subsystem Name='system' Type='Virtual'>\
    130             <ComponentLibrary/>\
    131             <InstanceDefinition>\
    132                 <IntegerParameter Name='integer' Size='32' Signed='true' Max='100'/>\
    133                 <StringParameter Name='string' MaxLength='9'/>\
    134             </InstanceDefinition>\
    135         </Subsystem>");
    136     TmpFile libraries("<?xml version='1.0' encoding='UTF-8'?>\
    137         <SystemClass Name='test'>\
    138             <SubsystemInclude Path='" +
    139                       system.getPath() + "'/>\
    140         </SystemClass>");
    141     TmpFile config("<?xml version='1.0' encoding='UTF-8'?>\
    142         <ParameterFrameworkConfiguration\
    143             SystemClassName='test' TuningAllowed='false'>\
    144             <SubsystemPlugins/>\
    145             <StructureDescriptionFileLocation Path='" +
    146                    libraries.getPath() + "'/>\
    147         </ParameterFrameworkConfiguration>");
    148 
    149     GIVEN ("A created parameter framework") {
    150         pfw = pfwCreate();
    151         REQUIRE(pfw != NULL);
    152 
    153         THEN ("Error message should be empty") {
    154             CHECK(empty(pfwGetLastError(pfw)));
    155         }
    156 
    157         WHEN ("The pfw is started without an existent file") {
    158             REQUIRE_FAILURE(pfwStart(pfw, "/doNotExist", criteria, criterionNb, &logger));
    159         }
    160 
    161         WHEN ("The pfw is started with duplicated criterion value") {
    162             const PfwCriterion duplicatedCriteria[] = {
    163                 {"duplicated name", true, letterList}, {"duplicated name", false, numberList},
    164             };
    165             REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 2, &logger));
    166         }
    167         WHEN ("The pfw is started with duplicated criterion value state") {
    168             const char *values[] = {"a", "a", NULL};
    169             const PfwCriterion duplicatedCriteria[] = {{"name", true, values}};
    170 
    171             WHEN ("Using test logger") {
    172                 REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
    173             }
    174             WHEN ("Using default logger") {
    175                 // Test coverage of default logger warning
    176                 REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, NULL));
    177             }
    178         }
    179         WHEN ("The pfw is started with NULL name criterion") {
    180             const PfwCriterion duplicatedCriteria[] = {{NULL, true, letterList}};
    181             REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
    182         }
    183         WHEN ("The pfw is started with NULL criterion state list") {
    184             const PfwCriterion duplicatedCriteria[] = {{"name", true, NULL}};
    185             REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
    186         }
    187         GIVEN ("A criteria with lots of values") {
    188             // Build a criterion with as many value as there is bits in int.
    189             std::vector<char> names(sizeof(int) * CHAR_BIT + 1, 'a');
    190             names.back() = '\0';
    191             std::vector<const char *> values(names.size());
    192             for (size_t i = 0; i < values.size(); ++i) {
    193                 values[i] = &names[i];
    194             }
    195             values.back() = NULL;
    196             /* The pfw c api requires criterion values to be a NULL terminated
    197              * array of string. Each string is a pointer to a NULL terminated
    198              * array of char. The pfw requires each string to be different
    199              * from all others, ie strcmp(values[i], values[j]) != 0 for any
    200              * i j.
    201              *
    202              * In order to generate easily an array of different strings,
    203              * instantiate one string (names) big enough
    204              * (@see PfwCriterion::values).
    205              * Then instantiate an array of pointer (values),
    206              * each pointing to a different position in the previously
    207              * created string.
    208              *
    209              * Representation of the names and values vectors.
    210              *
    211              * n = number of bit in an int
    212              *            <--- n+1 elements --->
    213              * names    = |a|a|a|a|...|a|a|a|\0|
    214              *             ^ ^             ^
    215              * values[0] =  |             |
    216              * values[1] = --             |
    217              * ...                         |
    218              * values[n - 1] =  -----------
    219              * values[n] = NULL
    220              *
    221              */
    222             const PfwCriterion duplicatedCriteria[] = {{"name", true, &values[0]}};
    223 
    224             WHEN ("The pfw is started with a too long criterion state list") {
    225                 REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
    226             }
    227             WHEN ("The pfw is started with max length criterion state list") {
    228                 values[values.size() - 2] = NULL; // Hide last value
    229                 REQUIRE_SUCCESS(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
    230             }
    231         }
    232 
    233         WHEN ("The pfw is started with zero criteria") {
    234             REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, 0, &logger));
    235         }
    236 
    237         WHEN ("The pfw is started twice a pfw") {
    238             REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, &logger));
    239             REQUIRE_FAILURE(pfwStart(pfw, config, criteria, criterionNb, &logger));
    240         }
    241 
    242         WHEN ("The pfw is started without a logger callback") {
    243             PfwLogger noLog = {NULL, NULL};
    244             REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, &noLog));
    245         }
    246         WHEN ("The pfw is started with default logger") {
    247             REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, NULL));
    248         }
    249 
    250         WHEN ("Get criterion of a stopped pfw") {
    251             int value;
    252             REQUIRE_FAILURE(pfwGetCriterion(pfw, criteria[0].name, &value));
    253         }
    254         WHEN ("Set criterion of a stopped pfw") {
    255             REQUIRE_FAILURE(pfwSetCriterion(pfw, criteria[0].name, 1));
    256         }
    257         WHEN ("Commit criteria of a stopped pfw") {
    258             REQUIRE_FAILURE(pfwApplyConfigurations(pfw));
    259         }
    260 
    261         WHEN ("Bind parameter with a stopped pfw") {
    262             REQUIRE(pfwBindParameter(pfw, intParameterPath) == NULL);
    263         }
    264 
    265         WHEN ("The pfw is started correctly") {
    266             REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, &logger));
    267             int value;
    268 
    269             WHEN ("Get not existing criterion") {
    270                 REQUIRE_FAILURE(pfwGetCriterion(pfw, "Do not exist", &value));
    271             }
    272             THEN ("All criterion should value 0") {
    273                 for (size_t i = 0; i < criterionNb; ++i) {
    274                     const char *criterionName = criteria[i].name;
    275                     CAPTURE(criterionName);
    276                     REQUIRE_SUCCESS(pfwGetCriterion(pfw, criterionName, &value));
    277                     REQUIRE(value == 0);
    278                 }
    279             }
    280 
    281             WHEN ("Set not existing criterion") {
    282                 REQUIRE_FAILURE(pfwSetCriterion(pfw, "Do not exist", 3));
    283             }
    284             WHEN ("Set criterion value") {
    285                 for (size_t i = 0; i < criterionNb; ++i) {
    286                     const char *criterionName = criteria[i].name;
    287                     CAPTURE(criterionName);
    288                     REQUIRE_SUCCESS(pfwSetCriterion(pfw, criterionName, 3));
    289                 }
    290                 THEN ("Get criterion value should return what was set") {
    291                     for (size_t i = 0; i < criterionNb; ++i) {
    292                         const char *criterionName = criteria[i].name;
    293                         CAPTURE(criterionName);
    294                         REQUIRE_SUCCESS(pfwGetCriterion(pfw, criterionName, &value));
    295                         REQUIRE(value == 3);
    296                     }
    297                 }
    298                 WHEN ("Set a new value to a criterion without committing first") {
    299                     const char *criterionName = criteria[0].name;
    300                     REQUIRE_SUCCESS(pfwSetCriterion(pfw, criterionName, 0));
    301                     THEN ("A warning message should have been displayed") {
    302                         INFO("Previous pfw log: \n" + logLines);
    303                         size_t logPos = logLines.find("Warning: Selection criterion "
    304                                                       "'inclusiveCrit' has been modified 1 time(s)"
    305                                                       " without any configuration application");
    306                         CHECK(logPos != std::string::npos);
    307                     }
    308                 }
    309             }
    310             WHEN ("Commit criteria of a started pfw") {
    311                 REQUIRE_SUCCESS(pfwApplyConfigurations(pfw));
    312             }
    313             WHEN ("Bind a non existing parameter") {
    314                 REQUIRE_FAILURE(pfwBindParameter(pfw, "do/not/exist") != NULL);
    315             }
    316 
    317             GIVEN ("An integer parameter handle") {
    318                 PfwParameterHandler *param = pfwBindParameter(pfw, intParameterPath);
    319                 REQUIRE_SUCCESS(param != NULL);
    320 
    321                 WHEN ("Set parameter out of range") {
    322                     REQUIRE_FAILURE(pfwSetIntParameter(param, 101));
    323                 }
    324 
    325                 WHEN ("Set parameter") {
    326                     REQUIRE_SUCCESS(pfwSetIntParameter(param, 11));
    327                     THEN ("Get parameter should return what was set") {
    328                         REQUIRE_SUCCESS(pfwGetIntParameter(param, &value));
    329                         REQUIRE(value == 11);
    330                     }
    331                 }
    332 
    333                 pfwUnbindParameter(param);
    334             }
    335 
    336             GIVEN ("An string parameter handle") {
    337                 PfwParameterHandler *param = pfwBindParameter(pfw, stringParameterPath);
    338                 REQUIRE_SUCCESS(param != NULL);
    339 
    340                 WHEN ("Set parameter out of range") {
    341                     REQUIRE_FAILURE(pfwSetStringParameter(param, "ko_1234567"));
    342                 }
    343 
    344                 WHEN ("Set parameter") {
    345                     char *value;
    346                     REQUIRE_SUCCESS(pfwSetStringParameter(param, "ok"));
    347                     THEN ("Get parameter should return what was set") {
    348                         REQUIRE_SUCCESS(pfwGetStringParameter(param, &value));
    349                         REQUIRE(value == std::string("ok"));
    350                         pfwFree(value);
    351                     }
    352                 }
    353 
    354                 pfwUnbindParameter(param);
    355             }
    356         }
    357 
    358         pfwDestroy(pfw);
    359     }
    360 }
    361