LCOV - code coverage report
Current view: top level - src/libs/tools/src - backendparser.cpp (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 43 43 100.0 %
Date: 2019-09-12 12:28:41 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief Tests for the Backend parser class
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  *
       8             :  */
       9             : 
      10             : #include <backendparser.hpp>
      11             : 
      12             : #include <functional>
      13             : 
      14             : #include <string>
      15             : 
      16             : #include <keyset.hpp>
      17             : 
      18             : #include <toolexcept.hpp>
      19             : 
      20             : 
      21             : namespace kdb
      22             : {
      23             : 
      24             : namespace tools
      25             : {
      26             : 
      27             : 
      28             : /**
      29             :  * @brief Parse a string containing information to create a KeySet
      30             :  *
      31             :  * @param pluginArguments comma (,) to separate key=value, contains no whitespaces
      32             :  *
      33             :  * @return newly created keyset with the information found in the string
      34             :  */
      35        1755 : KeySet parsePluginArguments (std::string const & pluginArguments, std::string const & basepath)
      36             : {
      37        1755 :         KeySet ks;
      38        3510 :         std::istringstream sstream (pluginArguments);
      39             : 
      40        3510 :         std::string keyName;
      41        1755 :         std::string value;
      42             : 
      43             :         // read until the next '=', this will be the keyname
      44        4125 :         while (std::getline (sstream, keyName, '='))
      45             :         {
      46             :                 // read until a ',' or the end of line
      47             :                 // if nothing is read because the '=' is the last character
      48             :                 // in the config string, consider the value empty
      49         410 :                 if (!std::getline (sstream, value, ',')) value = "";
      50             : 
      51        1025 :                 ks.append (Key (basepath + "/" + keyName, KEY_VALUE, value.c_str (), KEY_END));
      52             :         }
      53        1755 :         return ks;
      54             : }
      55             : 
      56           4 : PluginSpecVector parseArguments (std::initializer_list<std::string> cmdline)
      57             : {
      58           4 :         return parseArguments (cmdline.begin (), cmdline.end ());
      59             : }
      60             : 
      61             : 
      62             : /**
      63             :  * @brief Parse a complete commandline
      64             :  *
      65             :  * @param cmdline contains space separated plugins with optional plugin configurations
      66             :  *
      67             :  * @note currently whitespaces are not allowed within pluginname or config, use
      68             :  * iterator interface parseArguments() if you need it.
      69             :  *
      70             :  * @see parseArguments()
      71             :  * @return a parsed PluginSpecVector
      72             :  */
      73         876 : PluginSpecVector parseArguments (std::string const & cmdline)
      74             : {
      75        1752 :         std::vector<std::string> args;
      76        1752 :         std::istringstream sstream (cmdline);
      77         876 :         std::string argument;
      78        2804 :         while (std::getline (sstream, argument, ' '))
      79             :         {
      80         526 :                 args.push_back (argument);
      81             :         }
      82        2581 :         return parseArguments (args.begin (), args.end ());
      83             : }
      84             : 
      85             : 
      86             : namespace detail
      87             : {
      88             : 
      89             : /**
      90             :  * @brief Process a single argument and add it to PluginSpecVector
      91             :  *
      92             :  * @internal
      93             :  *
      94             :  * @param [in,out] arguments current list of processed arguments
      95             :  * @param [in,out] counter current counter, to be modified when argument is added
      96             :  * @param argument the argument to parse and add
      97             :  */
      98         807 : void processArgument (PluginSpecVector & arguments, size_t & counter, std::string argument)
      99             : {
     100             :         // ignore empty or useless arguments (whitespace , only)
     101         807 :         if (argument.empty ()) return;
     102        2868 :         if (std::all_of (argument.begin (), argument.end (), [](char c) { return std::isspace (c) || c == ','; })) return;
     103             : 
     104         693 :         if (argument.find ('=') == std::string::npos)
     105             :         {
     106             :                 // we have a plugin
     107        2797 :                 PluginSpec ps (argument);
     108         553 :                 if (argument.find ('#') == std::string::npos)
     109             :                 {
     110         409 :                         ps.setRefNumber (counter++);
     111         409 :                         arguments.push_back (ps);
     112             :                 }
     113             :                 else
     114             :                 {
     115         144 :                         arguments.push_back (ps);
     116             :                 }
     117             :         }
     118             :         else
     119             :         {
     120             :                 // we have a plugin's configuration
     121         146 :                 if (arguments.empty ()) throw ParseException ("config for plugin (" + argument + ") without previous plugin name");
     122         750 :                 arguments.back ().appendConfig (parsePluginArguments (argument));
     123             :         }
     124             : }
     125             : 
     126             : /**
     127             :  * @brief Fix refnames after parsing
     128             :  *
     129             :  * @internal
     130             :  *
     131             :  * @param arguments to fix
     132             :  */
     133        1109 : void fixArguments (PluginSpecVector & arguments)
     134             : {
     135             :         // fix refnames of single occurrences for backwards compatibility and cleaner names
     136        4863 :         for (auto & a : arguments)
     137             :         {
     138        1836 :                 size_t nr = std::count_if (arguments.begin (), arguments.end (),
     139        3546 :                                            [&a](PluginSpec const & spec) { return spec.getName () == a.getName (); });
     140         459 :                 if (nr == 1 && a.isRefNumber ())
     141             :                 {
     142         690 :                         a.setRefName (a.getName ());
     143             :                 }
     144             : 
     145             :                 size_t identical =
     146        2295 :                         std::count_if (arguments.begin (), arguments.end (), std::bind (PluginSpecRefName (), a, std::placeholders::_1));
     147         459 :                 if (identical > 1)
     148             :                 {
     149          96 :                         throw ParseException ("identical reference names found for plugin: " + a.getFullName ());
     150             :                 }
     151             :         }
     152             : 
     153             :         // now fix counter to be minimal
     154        1077 :         size_t counter = 0;
     155        4721 :         for (auto & a : arguments)
     156             :         {
     157         413 :                 if (a.isRefNumber ())
     158             :                 {
     159          14 :                         a.setRefNumber (counter++);
     160             :                 }
     161             :         }
     162        1077 : }
     163             : } // namespace detail
     164             : } // namespace tools
     165             : } // namespace kdb

Generated by: LCOV version 1.13