LCOV - code coverage report
Current view: top level - config - module_spec.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 201 206 97.6 %
Date: 2012-05-15 Functions: 27 27 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 436 669 65.2 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2010, 2011  Internet Systems Consortium.
       2                 :            : //
       3                 :            : // Permission to use, copy, modify, and distribute this software for any
       4                 :            : // purpose with or without fee is hereby granted, provided that the above
       5                 :            : // copyright notice and this permission notice appear in all copies.
       6                 :            : //
       7                 :            : // THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
       8                 :            : // DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
       9                 :            : // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
      10                 :            : // INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
      11                 :            : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
      12                 :            : // FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
      13                 :            : // NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
      14                 :            : // WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      15                 :            : 
      16                 :            : #include <config/module_spec.h>
      17                 :            : 
      18                 :            : #include <sstream>
      19                 :            : #include <iostream>
      20                 :            : #include <fstream>
      21                 :            : #include <cerrno>
      22                 :            : 
      23                 :            : #include <boost/foreach.hpp>
      24                 :            : 
      25                 :            : // todo: add more context to thrown ModuleSpecErrors?
      26                 :            : 
      27                 :            : using namespace isc::data;
      28                 :            : using namespace isc::config;
      29                 :            : 
      30                 :            : namespace {
      31                 :            : //
      32                 :            : // Private functions
      33                 :            : //
      34                 :            : 
      35                 :            : void
      36                 :      12026 : check_leaf_item(ConstElementPtr spec, const std::string& name,
      37                 :            :                 Element::types type, bool mandatory)
      38                 :            : {
      39         [ +  + ]:      12026 :     if (spec->contains(name)) {
      40         [ +  + ]:      23386 :         if (spec->get(name)->getType() == type) {
      41                 :      11993 :             return;
      42                 :            :         } else {
      43 [ +  - ][ +  - ]:         30 :             isc_throw(ModuleSpecError,
         [ +  - ][ +  - ]
                 [ +  - ]
      44                 :            :                       name + " not of type " + Element::typeToName(type));
      45                 :            :         }
      46         [ +  + ]:        333 :     } else if (mandatory) {
      47                 :            :         // todo: want parent item name, and perhaps some info about location
      48                 :            :         // in list? or just catch and throw new...
      49                 :            :         // or make this part non-throwing and check return value...
      50 [ +  - ][ +  - ]:         36 :         isc_throw(ModuleSpecError, name + " missing in " + spec->str());
         [ +  - ][ +  - ]
                 [ +  - ]
      51                 :            :     }
      52                 :            : }
      53                 :            : 
      54                 :            : void check_config_item_list(ConstElementPtr spec);
      55                 :            : 
      56                 :            : void
      57                 :       2496 : check_config_item(ConstElementPtr spec) {
      58         [ +  + ]:       7488 :     check_leaf_item(spec, "item_name", Element::string, true);
      59         [ +  + ]:       7482 :     check_leaf_item(spec, "item_type", Element::string, true);
      60         [ +  + ]:       7476 :     check_leaf_item(spec, "item_optional", Element::boolean, true);
      61                 :            :     check_leaf_item(spec, "item_default",
      62 [ +  - ][ +  - ]:       7470 :                     Element::nameToType(spec->get("item_type")->stringValue()),
      63 [ +  - ][ +  - ]:       4980 :                     !spec->get("item_optional")->boolValue()
      64 [ +  - ][ +  + ]:       7462 :                    );
         [ +  - ][ +  + ]
      65                 :            : 
      66                 :            :     // if list, check the list specification
      67 [ +  - ][ +  - ]:       4944 :     if (Element::nameToType(spec->get("item_type")->stringValue()) == Element::list) {
         [ +  - ][ +  + ]
      68         [ +  - ]:       1044 :         check_leaf_item(spec, "list_item_spec", Element::map, true);
      69 [ +  - ][ +  - ]:        696 :         check_config_item(spec->get("list_item_spec"));
      70                 :            :     }
      71                 :            : 
      72 [ +  - ][ +  - ]:       4944 :     if (spec->get("item_type")->stringValue() == "map") {
         [ +  - ][ +  + ]
      73         [ +  - ]:        999 :         check_leaf_item(spec, "map_item_spec", Element::list, true);
      74 [ +  - ][ +  - ]:        666 :         check_config_item_list(spec->get("map_item_spec"));
      75 [ +  - ][ +  - ]:       4278 :     } else if (spec->get("item_type")->stringValue() == "named_set") {
         [ +  - ][ +  + ]
      76         [ +  - ]:          6 :         check_leaf_item(spec, "named_set_item_spec", Element::map, true);
      77 [ +  - ][ +  - ]:          4 :         check_config_item(spec->get("named_set_item_spec"));
      78                 :            :     }
      79                 :       2472 : }
      80                 :            : 
      81                 :            : void
      82                 :        641 : check_config_item_list(ConstElementPtr spec) {
      83         [ +  + ]:        641 :     if (spec->getType() != Element::list) {
      84 [ +  - ][ +  - ]:          4 :         isc_throw(ModuleSpecError, "config_data is not a list of elements");
      85                 :            :     }
      86   [ +  +  +  - ]:       8335 :     BOOST_FOREACH(ConstElementPtr item, spec->listValue()) {
         [ +  - ][ +  + ]
                 [ +  + ]
      87         [ +  + ]:       1942 :         check_config_item(item);
      88                 :            :     }
      89                 :        615 : }
      90                 :            : 
      91                 :            : // checks whether the given element is a valid statistics specification
      92                 :            : // returns false if the specification is bad
      93                 :            : bool
      94                 :         61 : check_format(ConstElementPtr value, ConstElementPtr format_name) {
      95                 :            :     typedef std::map<std::string, std::string> format_types;
      96                 :            :     format_types time_formats;
      97                 :            :     // TODO: should be added other format types if necessary
      98                 :            :     time_formats.insert(
      99 [ +  - ][ +  - ]:        122 :         format_types::value_type("date-time", "%Y-%m-%dT%H:%M:%SZ") );
                 [ +  - ]
     100                 :            :     time_formats.insert(
     101 [ +  - ][ +  - ]:        122 :         format_types::value_type("date", "%Y-%m-%d") );
                 [ +  - ]
     102                 :            :     time_formats.insert(
     103 [ +  - ][ +  - ]:        122 :         format_types::value_type("time", "%H:%M:%S") );
                 [ +  - ]
     104 [ +  + ][ +  - ]:        335 :     BOOST_FOREACH (const format_types::value_type& f, time_formats) {
         [ +  - ][ +  + ]
                 [ +  + ]
     105 [ +  - ][ +  + ]:        128 :         if (format_name->stringValue() == f.first) {
     106                 :            :             struct tm tm;
     107                 :         55 :             std::vector<char> buf(32);
     108                 :            :             memset(&tm, 0, sizeof(tm));
     109                 :            :             // reverse check
     110                 :        110 :             return (strptime(value->stringValue().c_str(),
     111 [ +  - ][ #  # ]:         55 :                              f.second.c_str(), &tm) != NULL
     112                 :         36 :                     && strftime(&buf[0], buf.size(),
     113                 :         36 :                                 f.second.c_str(), &tm) != 0
     114                 :         72 :                     && strncmp(value->stringValue().c_str(),
     115   [ +  +  +  -  :        127 :                                &buf[0], buf.size()) == 0);
           +  - ][ +  + ]
                 [ +  + ]
     116                 :            :         }
     117                 :            :     }
     118                 :            :     return (false);
     119                 :            : }
     120                 :            : 
     121                 :            : void check_statistics_item_list(ConstElementPtr spec);
     122                 :            : 
     123                 :            : void
     124                 :         67 : check_statistics_item_list(ConstElementPtr spec) {
     125         [ +  + ]:         67 :     if (spec->getType() != Element::list) {
     126 [ +  - ][ +  - ]:          6 :         isc_throw(ModuleSpecError, "statistics is not a list of elements");
     127                 :            :     }
     128   [ +  +  +  - ]:        811 :     BOOST_FOREACH(ConstElementPtr item, spec->listValue()) {
         [ +  - ][ +  + ]
                 [ +  + ]
     129         [ +  - ]:        204 :         check_config_item(item);
     130                 :            :         // additional checks for statistics
     131 [ +  - ][ +  + ]:        612 :         check_leaf_item(item, "item_title", Element::string, true);
     132 [ +  - ][ +  + ]:        609 :         check_leaf_item(item, "item_description", Element::string, true);
     133 [ +  - ][ +  - ]:        606 :         check_leaf_item(item, "item_format", Element::string, false);
     134                 :            :         // checks name of item_format and validation of item_default
     135 [ +  - ][ +  - ]:        460 :         if (item->contains("item_format")
         [ +  + ][ +  + ]
         [ +  + ][ #  # ]
     136 [ +  - ][ +  - ]:        258 :             && item->contains("item_default")) {
         [ +  + ][ #  # ]
     137         [ +  + ]:        156 :             if(!check_format(item->get("item_default"),
     138         [ +  - ]:        156 :                              item->get("item_format"))) {
           [ +  -  +  - ]
         [ +  - ][ +  - ]
     139 [ +  - ][ +  - ]:        277 :                 isc_throw(ModuleSpecError, 
                 [ +  - ]
     140                 :            :                     "item_default not valid type of item_format");
     141                 :            :             }
     142                 :            :         }
     143                 :            :     }
     144                 :         41 : }
     145                 :            : 
     146                 :            : void
     147                 :         91 : check_command(ConstElementPtr spec) {
     148         [ +  + ]:        273 :     check_leaf_item(spec, "command_name", Element::string, true);
     149         [ +  + ]:        267 :     check_leaf_item(spec, "command_args", Element::list, true);
     150 [ +  - ][ +  + ]:        170 :     check_config_item_list(spec->get("command_args"));
     151                 :         83 : }
     152                 :            : 
     153                 :            : void
     154                 :        204 : check_command_list(ConstElementPtr spec) {
     155         [ +  + ]:        204 :     if (spec->getType() != Element::list) {
     156 [ +  - ][ +  - ]:          4 :         isc_throw(ModuleSpecError, "commands is not a list of elements");
     157                 :            :     }
     158   [ +  +  +  - ]:        542 :     BOOST_FOREACH(ConstElementPtr item, spec->listValue()) {
         [ +  - ][ +  + ]
                 [ +  + ]
     159         [ +  + ]:         91 :         check_command(item);
     160                 :            :     }
     161                 :        194 : }
     162                 :            : 
     163                 :            : void
     164                 :        295 : check_data_specification(ConstElementPtr spec) {
     165         [ +  + ]:        885 :     check_leaf_item(spec, "module_name", Element::string, true);
     166         [ +  + ]:        873 :     check_leaf_item(spec, "module_description", Element::string, false);
     167                 :            :     // config_data is not mandatory; module could just define
     168                 :            :     // commands and have no config
     169 [ +  - ][ +  + ]:        290 :     if (spec->contains("config_data")) {
     170 [ +  - ][ +  + ]:        446 :         check_config_item_list(spec->get("config_data"));
     171                 :            :     }
     172 [ +  - ][ +  + ]:        266 :     if (spec->contains("commands")) {
     173 [ +  - ][ +  + ]:        408 :         check_command_list(spec->get("commands"));
     174                 :            :     }
     175 [ +  - ][ +  + ]:        256 :     if (spec->contains("statistics")) {
     176 [ +  - ][ +  + ]:        134 :         check_statistics_item_list(spec->get("statistics"));
     177                 :            :     }
     178                 :        230 : }
     179                 :            : 
     180                 :            : // checks whether the given element is a valid module specification
     181                 :            : // throws a ModuleSpecError if the specification is bad
     182                 :            : void
     183                 :        295 : check_module_specification(ConstElementPtr def) {
     184                 :            :     try {
     185         [ +  + ]:        295 :         check_data_specification(def);
     186         [ +  + ]:         69 :     } catch (const TypeError& te) {
     187 [ -  + ][ -  + ]:          8 :         isc_throw(ModuleSpecError, te.what());
                 [ -  + ]
     188                 :            :     }
     189                 :        230 : }
     190                 :            : }
     191                 :            : 
     192                 :            : namespace isc {
     193                 :            : namespace config {
     194                 :            : //
     195                 :            : // Public functions
     196                 :            : //
     197                 :            : 
     198                 :        295 : ModuleSpec::ModuleSpec(ConstElementPtr module_spec_element,
     199                 :            :                        const bool check)
     200                 :          0 :                        throw(ModuleSpecError)
     201                 :            :                        
     202                 :            : {
     203         [ +  - ]:        295 :     module_specification = module_spec_element;
     204         [ +  - ]:        295 :     if (check) {
     205         [ +  + ]:        295 :         check_module_specification(module_specification);
     206                 :            :     }
     207                 :        230 : }
     208                 :            : 
     209                 :            : ConstElementPtr
     210                 :          2 : ModuleSpec::getCommandsSpec() const {
     211 [ +  - ][ +  + ]:          2 :     if (module_specification->contains("commands")) {
     212         [ +  - ]:          1 :         return (module_specification->get("commands"));
     213                 :            :     } else {
     214                 :            :         return (ElementPtr());
     215                 :            :     }
     216                 :            : }
     217                 :            : 
     218                 :            : ConstElementPtr
     219                 :         64 : ModuleSpec::getConfigSpec() const {
     220 [ +  - ][ +  + ]:         64 :     if (module_specification->contains("config_data")) {
     221         [ +  - ]:         63 :         return (module_specification->get("config_data"));
     222                 :            :     } else {
     223                 :            :         return (ElementPtr());
     224                 :            :     }
     225                 :            : }
     226                 :            : 
     227                 :            : ConstElementPtr
     228                 :          2 : ModuleSpec::getStatisticsSpec() const {
     229 [ +  - ][ +  + ]:          2 :     if (module_specification->contains("statistics")) {
     230         [ +  - ]:          1 :         return (module_specification->get("statistics"));
     231                 :            :     } else {
     232                 :            :         return (ElementPtr());
     233                 :            :     }
     234                 :            : }
     235                 :            : 
     236                 :            : const std::string
     237                 :         33 : ModuleSpec::getModuleName() const {
     238 [ +  - ][ +  - ]:         66 :     return (module_specification->get("module_name")->stringValue());
     239                 :            : }
     240                 :            : 
     241                 :            : const std::string
     242                 :          2 : ModuleSpec::getModuleDescription() const {
     243 [ +  - ][ +  + ]:          2 :     if (module_specification->contains("module_description")) {
     244 [ +  - ][ +  - ]:          2 :         return (module_specification->get("module_description")->stringValue());
     245                 :            :     } else {
     246                 :          2 :         return (std::string(""));
     247                 :            :     }
     248                 :            : }
     249                 :            : 
     250                 :            : bool
     251                 :        154 : ModuleSpec::validateConfig(ConstElementPtr data, const bool full) const {
     252         [ +  - ]:        154 :     ConstElementPtr spec = module_specification->find("config_data");
     253         [ +  - ]:        308 :     return (validateSpecList(spec, data, full, ElementPtr()));
     254                 :            : }
     255                 :            : 
     256                 :            : bool
     257                 :          2 : ModuleSpec::validateStatistics(ConstElementPtr data, const bool full) const {
     258         [ +  - ]:          2 :     ConstElementPtr spec = module_specification->find("statistics");
     259         [ +  - ]:          4 :     return (validateSpecList(spec, data, full, ElementPtr()));
     260                 :            : }
     261                 :            : 
     262                 :            : bool
     263                 :         12 : ModuleSpec::validateCommand(const std::string& command,
     264                 :            :                              ConstElementPtr args,
     265                 :            :                              ElementPtr errors) const
     266                 :            : {
     267         [ +  + ]:         12 :     if (args->getType() != Element::map) {
     268                 :          1 :         errors->add(Element::create("args for command " +
     269 [ +  - ][ +  - ]:          3 :                                     command + " is not a map"));
                 [ +  - ]
     270                 :          1 :         return (false);
     271                 :            :     }
     272                 :            : 
     273         [ +  - ]:         11 :     ConstElementPtr commands_spec = module_specification->find("commands");
     274         [ -  + ]:         11 :     if (!commands_spec) {
     275                 :            :         // there are no commands according to the spec.
     276 [ #  # ][ #  # ]:          0 :         errors->add(Element::create("The given module has no commands"));
     277                 :            :         return (false);
     278                 :            :     }
     279                 :            : 
     280 [ +  - ][ +  + ]:         53 :     BOOST_FOREACH(ConstElementPtr cur_command, commands_spec->listValue()) {
         [ +  - ][ +  - ]
         [ +  + ][ +  + ]
     281 [ +  - ][ +  - ]:         36 :         if (cur_command->get("command_name")->stringValue() == command) {
         [ +  - ][ +  + ]
     282                 :         20 :             return (validateSpecList(cur_command->get("command_args"),
     283 [ +  - ][ +  - ]:         10 :                                        args, true, errors));
                 [ +  - ]
     284                 :            :         }
     285                 :            :     }
     286                 :            : 
     287                 :            :     // this command is unknown
     288 [ +  - ][ +  - ]:          3 :     errors->add(Element::create("Unknown command " + command));
                 [ +  - ]
     289                 :            :     return (false);
     290                 :            : }
     291                 :            : 
     292                 :            : bool
     293                 :         10 : ModuleSpec::validateConfig(ConstElementPtr data, const bool full,
     294                 :            :                             ElementPtr errors) const
     295                 :            : {
     296         [ +  - ]:         10 :     ConstElementPtr spec = module_specification->find("config_data");
     297         [ +  - ]:         20 :     return (validateSpecList(spec, data, full, errors));
     298                 :            : }
     299                 :            : 
     300                 :            : bool
     301                 :          1 : ModuleSpec::validateStatistics(ConstElementPtr data, const bool full,
     302                 :            :                                ElementPtr errors) const
     303                 :            : {
     304         [ +  - ]:          1 :     ConstElementPtr spec = module_specification->find("statistics");
     305         [ +  - ]:          2 :     return (validateSpecList(spec, data, full, errors));
     306                 :            : }
     307                 :            : 
     308                 :            : ModuleSpec
     309                 :         83 : moduleSpecFromFile(const std::string& file_name, const bool check)
     310                 :          0 :                    throw(JSONError, ModuleSpecError)
     311                 :            : {
     312 [ +  - ][ +  - ]:        166 :     std::ifstream file;
                 [ +  - ]
     313                 :            : 
     314         [ +  - ]:         83 :     file.open(file_name.c_str());
     315         [ +  + ]:         83 :     if (!file) {
     316         [ +  - ]:          4 :         std::stringstream errs;
     317 [ +  - ][ +  - ]:          2 :         errs << "Error opening " << file_name << ": " << strerror(errno);
         [ +  - ][ +  - ]
     318 [ +  - ][ +  - ]:          6 :         isc_throw(ModuleSpecError, errs.str());
                 [ +  - ]
     319                 :            :     }
     320                 :            : 
     321         [ +  - ]:         81 :     ConstElementPtr module_spec_element = Element::fromJSON(file, file_name);
     322 [ +  - ][ +  - ]:         81 :     if (module_spec_element->contains("module_spec")) {
                 [ +  + ]
     323 [ +  - ][ +  - ]:        189 :         return (ModuleSpec(module_spec_element->get("module_spec"), check));
                 [ +  + ]
     324                 :            :     } else {
     325 [ +  - ][ +  - ]:          4 :         isc_throw(ModuleSpecError, "No module_spec in specification");
                 [ +  - ]
     326                 :            :     }
     327                 :            : }
     328                 :            : 
     329                 :            : ModuleSpec
     330                 :         40 : moduleSpecFromFile(std::ifstream& in, const bool check)
     331                 :          0 :                    throw(JSONError, ModuleSpecError)
     332                 :            : {
     333         [ +  - ]:         40 :     ConstElementPtr module_spec_element = Element::fromJSON(in);
     334 [ +  - ][ +  - ]:         40 :     if (module_spec_element->contains("module_spec")) {
                 [ +  + ]
     335 [ +  - ][ +  - ]:        114 :         return (ModuleSpec(module_spec_element->get("module_spec"), check));
                 [ +  - ]
     336                 :            :     } else {
     337 [ +  - ][ +  - ]:          4 :         isc_throw(ModuleSpecError, "No module_spec in specification");
                 [ +  - ]
     338                 :            :     }
     339                 :            : }
     340                 :            : 
     341                 :            : 
     342                 :            : namespace {
     343                 :            : //
     344                 :            : // private functions
     345                 :            : //
     346                 :            : 
     347                 :            : //
     348                 :            : // helper functions for validation
     349                 :            : //
     350                 :            : bool
     351                 :        299 : check_type(ConstElementPtr spec, ConstElementPtr element) {
     352                 :        299 :     std::string cur_item_type;
     353 [ +  - ][ +  - ]:        897 :     cur_item_type = spec->get("item_type")->stringValue();
                 [ +  - ]
     354 [ +  - ][ +  + ]:        299 :     if (cur_item_type == "any") {
     355                 :            :         return (true);
     356                 :            :     }
     357   [ +  +  +  +  :        295 :     switch (element->getType()) {
                +  +  - ]
     358                 :            :         case Element::integer:
     359         [ +  - ]:         67 :             return (cur_item_type == "integer");
     360                 :            :             break;
     361                 :            :         case Element::real:
     362         [ +  - ]:         11 :             return (cur_item_type == "real");
     363                 :            :             break;
     364                 :            :         case Element::boolean:
     365         [ +  - ]:         26 :             return (cur_item_type == "boolean");
     366                 :            :             break;
     367                 :            :         case Element::string:
     368         [ +  - ]:         86 :             return (cur_item_type == "string");
     369                 :            :             break;
     370                 :            :         case Element::list:
     371         [ +  - ]:         31 :             return (cur_item_type == "list");
     372                 :            :             break;
     373                 :            :         case Element::map:
     374         [ +  - ]:         74 :             return (cur_item_type == "map" ||
     375 [ +  + ][ +  - ]:         74 :                     cur_item_type == "named_set");
                 [ +  - ]
     376                 :            :             break;
     377                 :            :     }
     378                 :            :     return (false);
     379                 :            : }
     380                 :            : }
     381                 :            : 
     382                 :            : bool
     383                 :        237 : ModuleSpec::validateItem(ConstElementPtr spec, ConstElementPtr data,
     384                 :            :                           const bool full, ElementPtr errors) const
     385                 :            : {
     386   [ +  -  +  + ]:        474 :     if (!check_type(spec, data)) {
     387                 :            :         // we should do some proper error feedback here
     388                 :            :         // std::cout << "type mismatch; not " << spec->get("item_type") << ": " << data << std::endl;
     389                 :            :         // std::cout << spec << std::endl;
     390         [ +  + ]:         10 :         if (errors) {
     391         [ +  - ]:          6 :             errors->add(Element::create("Type mismatch"));
     392                 :            :         }
     393                 :            :         return (false);
     394                 :            :     }
     395         [ +  + ]:        227 :     if (data->getType() == Element::list) {
     396         [ +  - ]:         30 :         ConstElementPtr list_spec = spec->get("list_item_spec");
     397 [ +  - ][ +  + ]:        251 :         BOOST_FOREACH(ConstElementPtr list_el, data->listValue()) {
         [ +  - ][ +  - ]
         [ +  + ][ +  + ]
     398 [ +  - ][ +  + ]:        124 :             if (!check_type(list_spec, list_el)) {
     399         [ -  + ]:          1 :                 if (errors) {
     400 [ #  # ][ #  # ]:          0 :                     errors->add(Element::create("Type mismatch"));
     401                 :            :                 }
     402                 :            :                 return (false);
     403                 :            :             }
     404 [ +  - ][ +  - ]:        122 :             if (list_spec->get("item_type")->stringValue() == "map") {
         [ +  - ][ +  - ]
                 [ +  + ]
     405 [ +  - ][ +  + ]:        106 :                 if (!validateItem(list_spec, list_el, full, errors)) {
     406                 :            :                     return (false);
     407                 :            :                 }
     408                 :            :             }
     409                 :            :         }
     410                 :            :     }
     411         [ +  + ]:        218 :     if (data->getType() == Element::map) {
     412                 :            :         // either a normal 'map' or a 'named set' (determined by which
     413                 :            :         // subspecification it has)
     414 [ +  - ][ +  + ]:         52 :         if (spec->contains("map_item_spec")) {
     415 [ +  - ][ +  - ]:        150 :             if (!validateSpecList(spec->get("map_item_spec"), data, full, errors)) {
         [ +  - ][ +  + ]
     416                 :            :                 return (false);
     417                 :            :             }
     418                 :            :         } else {
     419                 :            :             typedef std::pair<std::string, ConstElementPtr> maptype;
     420                 :            : 
     421 [ +  + ][ +  - ]:          9 :             BOOST_FOREACH(maptype m, data->mapValue()) {
         [ +  - ][ +  + ]
                 [ +  + ]
     422 [ +  - ][ +  - ]:         12 :                 if (!validateItem(spec->get("named_set_item_spec"), m.second, full, errors)) {
         [ +  - ][ +  + ]
     423                 :            :                     return (false);
     424                 :            :                 }
     425                 :            :             }
     426                 :            :         }
     427                 :            :     }
     428 [ +  - ][ +  + ]:        208 :     if (spec->contains("item_format")) {
     429 [ +  - ][ +  - ]:         27 :         if (!check_format(data, spec->get("item_format"))) {
                 [ +  + ]
     430         [ +  + ]:          6 :             if (errors) {
     431         [ +  - ]:          6 :                 errors->add(Element::create("Format mismatch"));
     432                 :            :             }
     433                 :            :             return (false);
     434                 :            :         }
     435                 :            :     }
     436                 :            :     return (true);
     437                 :            : }
     438                 :            : 
     439                 :            : // spec is a map with item_name etc, data is a map
     440                 :            : bool
     441                 :        404 : ModuleSpec::validateSpec(ConstElementPtr spec, ConstElementPtr data,
     442                 :            :                           const bool full, ElementPtr errors) const
     443                 :            : {
     444 [ +  - ][ +  - ]:       1212 :     std::string item_name = spec->get("item_name")->stringValue();
     445 [ +  - ][ +  - ]:        808 :     bool optional = spec->get("item_optional")->boolValue();
                 [ +  - ]
     446                 :            :     ConstElementPtr data_el;
     447 [ +  - ][ +  - ]:        404 :     data_el = data->get(item_name);
     448                 :            :     
     449         [ +  + ]:        404 :     if (data_el) {
     450 [ +  - ][ +  + ]:        422 :         if (!validateItem(spec, data_el, full, errors)) {
     451                 :            :             return (false);
     452                 :            :         }
     453                 :            :     } else {
     454 [ +  + ][ +  + ]:        193 :         if (!optional && full) {
     455         [ +  + ]:        148 :             if (errors) {
     456 [ +  - ][ +  - ]:          2 :                 errors->add(Element::create("Non-optional value missing"));
     457                 :            :             }
     458                 :            :             return (false);
     459                 :            :         }
     460                 :            :     }
     461                 :            :     return (true);
     462                 :            : }
     463                 :            : 
     464                 :            : // spec is a list of maps, data is a map
     465                 :            : bool
     466                 :        227 : ModuleSpec::validateSpecList(ConstElementPtr spec, ConstElementPtr data,
     467                 :            :                                const bool full, ElementPtr errors) const
     468                 :            : {
     469                 :        227 :     bool validated = true;
     470   [ +  +  +  - ]:       1843 :     BOOST_FOREACH(ConstElementPtr cur_spec_el, spec->listValue()) {
         [ +  - ][ +  + ]
                 [ +  + ]
     471 [ +  - ][ +  + ]:        808 :         if (!validateSpec(cur_spec_el, data, full, errors)) {
     472                 :        404 :             validated = false;
     473                 :            :         }
     474                 :            :     }
     475                 :            : 
     476                 :            :     typedef std::pair<std::string, ConstElementPtr> maptype;
     477                 :            :     
     478 [ +  + ][ +  - ]:       1274 :     BOOST_FOREACH(maptype m, data->mapValue()) {
         [ +  - ][ +  + ]
                 [ +  + ]
     479                 :        349 :         bool found = false;
     480                 :            :         // Ignore 'version' as a config element
     481 [ +  - ][ +  + ]:        349 :         if (m.first.compare("version") != 0) {
     482 [ +  - ][ +  + ]:       4722 :             BOOST_FOREACH(ConstElementPtr cur_spec_el, spec->listValue()) {
         [ +  - ][ +  - ]
         [ +  + ][ +  + ]
     483 [ +  - ][ +  - ]:       2254 :                 if (cur_spec_el->get("item_name")->stringValue().compare(m.first) == 0) {
         [ +  - ][ +  + ]
     484                 :       1127 :                     found = true;
     485                 :            :                 }
     486                 :            :             }
     487         [ +  + ]:        214 :             if (!found) {
     488                 :          3 :                 validated = false;
     489         [ +  + ]:          3 :                 if (errors) {
     490 [ +  - ][ +  - ]:        567 :                     errors->add(Element::create("Unknown item " + m.first));
                 [ +  - ]
     491                 :            :                 }
     492                 :            :             }
     493                 :            :         }
     494                 :            :     }
     495                 :            : 
     496                 :        227 :     return (validated);
     497                 :            : }
     498                 :            : 
     499                 :            : }
     500                 :        232 : }

Generated by: LCOV version 1.9