Browse Source

tests for data_def.cc

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/parkinglot@708 e5f2f494-b856-4b98-b285-d166d9295462
Jelte Jansen 15 years ago
parent
commit
80707c7c0d

+ 1 - 0
configure.ac

@@ -184,6 +184,7 @@ AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
            src/bin/msgq/run_msgq.sh
            src/bin/auth/config.h
            src/bin/parkinglot/config.h
+           src/lib/config/cpp/data_def_unittests_config.h
            src/lib/dns/cpp/gen-rdatacode.py
           ], [
            chmod +x src/bin/cfgmgr/run_b10-cfgmgr.sh

+ 14 - 2
src/lib/config/cpp/Makefile.am

@@ -1,7 +1,19 @@
 AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/ext -Wall -Werror
 
-lib_LIBRARIES = libclient.a
-libclient_a_SOURCES = data_def.h data_def.cc ccsession.cc ccsession.h
+lib_LIBRARIES = libcfgclient.a
+libcfgclient_a_SOURCES = data_def.h data_def.cc ccsession.cc ccsession.h
 
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES = data_def_unittests.cc run_unittests.cc
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+run_unittests_LDADD = libcfgclient.a $(GTEST_LDADD)
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/cpp/libdns.la
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/cpp/libcc.a
+endif
+
+noinst_PROGRAMS = $(TESTS)
 
 

+ 22 - 1
src/lib/config/cpp/data_def.cc

@@ -3,6 +3,8 @@
 
 #include <sstream>
 #include <iostream>
+#include <fstream>
+#include <cerrno>
 
 #include <boost/foreach.hpp>
 
@@ -88,13 +90,14 @@ check_config_item(const ElementPtr& spec) {
     // todo: add stuff for type map
     if (getType_value(spec->get("item_type")->stringValue()) == Element::map) {
         check_leaf_item(spec, "map_item_spec", Element::list, true);
-        check_config_item_list(spec);
+        check_config_item_list(spec->get("map_item_spec"));
     }
 }
 
 static void
 check_config_item_list(const ElementPtr& spec) {
     if (spec->getType() != Element::list) {
+        std::cout << "[XX] ERROR IN: " << spec << std::endl;
         throw DataDefinitionError("config_data is not a list of elements");
     }
     BOOST_FOREACH(ElementPtr item, spec->listValue()) {
@@ -144,6 +147,24 @@ check_definition(const ElementPtr& def)
     }
 }
 
+DataDefinition::DataDefinition(const std::string& file_name,
+                               const bool check)
+                               throw(ParseError, DataDefinitionError) {
+    std::ifstream file;
+
+    file.open(file_name.c_str());
+    if (!file) {
+        std::stringstream errs;
+        errs << "Error opening " << file_name << ": " << strerror(errno);
+        throw DataDefinitionError(errs.str());
+    }
+
+    definition = Element::createFromString(file, file_name);
+    if (check) {
+        check_definition(definition);
+    }
+}
+
 DataDefinition::DataDefinition(std::istream& in, const bool check)
                                throw(ParseError, DataDefinitionError) {
     definition = Element::createFromString(in);

+ 15 - 2
src/lib/config/cpp/data_def.h

@@ -39,9 +39,22 @@ namespace isc { namespace data {
         /// the specification
         /// \param e The Element containing the data specification
         explicit DataDefinition(ElementPtr e) : definition(e) {};
+
+        /// Creates a \c DataDefinition instance from the contents
+        /// of the file given by file_name.
+        /// If check is true, and the definition is not of the correct
+        /// form, a DataDefinitionError is thrown. If the file could
+        /// not be parse, a ParseError is thrown.
+        /// \param file_name The file to be opened and parsed
+        /// \param check If true, the data definition in the file is
+        /// checked to be of the correct form
+        DataDefinition(const std::string& file_name, const bool check = true)
+                       throw(ParseError, DataDefinitionError);
+
         // todo: make check default false, or leave out option completely and always check?
-        /// Creates a \c DataDefinition instance from the given .spec
-        /// file stream. If check is true, and the definition is not of
+        /// Creates a \c DataDefinition instance from the given input
+        /// stream that contains the contents of a .spec file.
+        /// If check is true, and the definition is not of
         /// the correct form, a DataDefinitionError is thrown. If the
         /// file could not be parsed, a ParseError is thrown.
         /// \param in The std::istream containing the .spec file data

+ 70 - 0
src/lib/config/cpp/data_def_unittests.cc

@@ -0,0 +1,70 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <gtest/gtest.h>
+
+#include <data_def.h>
+
+#include "data_def_unittests_config.h"
+
+using namespace isc::data;
+
+std::string specfile(const std::string name) {
+    return std::string(TEST_DATA_PATH) + "/" + name;
+}
+
+void
+data_def_error(const std::string& file,
+               const std::string& error1,
+               const std::string& error2 = "",
+               const std::string& error3 = "")
+{
+    EXPECT_THROW(DataDefinition(specfile(file)), DataDefinitionError);
+    try {
+        DataDefinition dd = DataDefinition(specfile(file));
+    } catch (DataDefinitionError dde) {
+        std::string ddew = dde.what();
+        EXPECT_EQ(error1 + error2 + error3, ddew);
+    }
+}
+
+TEST(DataDefinition, Specfiles) {
+    // Tests whether we can open specfiles and if we get the
+    // right parse errors
+    DataDefinition dd = DataDefinition(specfile("spec1.spec"));
+    EXPECT_EQ(dd.getDefinition()->get("data_specification")
+                                ->get("module_name")
+                                ->stringValue(), "Spec1");
+    dd = DataDefinition(specfile("spec2.spec"));
+    EXPECT_EQ(dd.getDefinition()->get("data_specification")
+                                ->get("config_data")->size(), 6);
+    data_def_error("doesnotexist",
+                   "Error opening ",
+                   specfile("doesnotexist"),
+                   ": No such file or directory");
+    data_def_error("spec3.spec",
+                   "item_name missing in {\"item_default\": 1, \"item_optional\": False, \"item_type\": \"integer\"}");
+    data_def_error("spec4.spec",
+                   "item_type missing in {\"item_default\": 1, \"item_name\": \"item1\", \"item_optional\": False}");
+    data_def_error("spec5.spec",
+                   "item_optional missing in {\"item_default\": 1, \"item_name\": \"item1\", \"item_type\": \"integer\"}");
+    data_def_error("spec6.spec",
+                   "item_default missing in {\"item_name\": \"item1\", \"item_optional\": False, \"item_type\": \"integer\"}");
+    data_def_error("spec7.spec",
+                   "module_name missing in {}");
+    data_def_error("spec8.spec",
+                   "Data specification does not contain data_specification element");
+}

+ 1 - 0
src/lib/config/cpp/data_def_unittests_config.h.in

@@ -0,0 +1 @@
+#define TEST_DATA_PATH "@abs_srcdir@/../testdata"

+ 24 - 0
src/lib/config/cpp/run_unittests.cc

@@ -0,0 +1,24 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <gtest/gtest.h>
+
+int
+main(int argc, char* argv[])
+{
+    ::testing::InitGoogleTest(&argc, argv);
+    return (RUN_ALL_TESTS());
+}

+ 13 - 2
src/lib/config/python/isc/config/datadefinition.py

@@ -65,6 +65,11 @@ class DataDefinition:
         return self._data_spec["data_specification"]["module_name"]
 
 def _check(data_spec):
+    """Checks the full specification. This is a dict that contains the
+       element "data_specification", which is in itself a dict that
+       must contain at least a "module_name" (string) and optionally
+       a "config_data" and a "commands" element, both of which are lists
+       of dicts. Raises a DataDefinitionError if there is a problem."""
     if type(data_spec) != dict:
         raise DataDefinitionError("data specification not a dict")
     if "data_specification" not in data_spec:
@@ -81,12 +86,17 @@ def _checkConfigSpec(config_data):
     # config data is a list of items represented by dicts that contain
     # things like "item_name", depending on the type they can have
     # specific subitems
+    """Checks a list that contains the configuration part of the
+       specification. Raises a DataDefinitionError if there is a
+       problem."""
     if type(config_data) != list:
         raise DataDefinitionError("config_data is not a list of items")
     for config_item in config_data:
         _checkItemSpec(config_item)
 
 def _checkCommandSpec(commands):
+    """Checks the list that contains a set of commands. Raises a
+       DataDefinitionError is there is an error"""
     if type(commands) != list:
         raise DataDefinitionError("commands is not a list of commands")
     for command in commands:
@@ -110,8 +120,9 @@ def _checkCommandSpec(commands):
     pass
 
 def _checkItemSpec(config_item):
-    # checks the dict that defines one config item
-    # (i.e. containing "item_name", "item_type", etc
+    """Checks the dict that defines one config item
+       (i.e. containing "item_name", "item_type", etc.
+       Raises a DataDefinitionError if there is an error"""
     if type(config_item) != dict:
         raise DataDefinitionError("item spec not a dict")
     if "item_name" not in config_item:

+ 6 - 0
src/lib/config/testdata/spec1.spec

@@ -0,0 +1,6 @@
+{
+  "data_specification": {
+    "module_name": "Spec1"
+  }
+}
+

+ 55 - 0
src/lib/config/testdata/spec2.spec

@@ -0,0 +1,55 @@
+{
+  "data_specification": {
+    "module_name": "Spec2",
+    "config_data": [
+      { "item_name": "item1",
+        "item_type": "integer",
+        "item_optional": False,
+        "item_default": 1
+      },
+      { "item_name": "item2",
+        "item_type": "real",
+        "item_optional": False,
+        "item_default": 1.1
+      },
+      { "item_name": "item3",
+        "item_type": "boolean",
+        "item_optional": False,
+        "item_default": True
+      },
+      { "item_name": "item4",
+        "item_type": "string",
+        "item_optional": False,
+        "item_default": "test"
+      },
+      { "item_name": "item5",
+        "item_type": "list",
+        "item_optional": False,
+        "item_default": [ "a", "b" ],
+        "list_item_spec": {
+          "item_name": "list_element",
+          "item_type": "string",
+          "item_optional": False,
+          "item_default": ""
+        }
+      },
+      { "item_name": "item6",
+        "item_type": "map",
+        "item_optional": False,
+        "item_default": {},
+        "map_item_spec": [
+          { "item_name": "value1",
+            "item_type": "string",
+            "item_optional": True,
+            "item_default": "default"
+          },
+          { "item_name": "value2",
+            "item_type": "integer",
+            "item_optional": True
+          }
+        ]
+      }
+    ]
+  }
+}
+

+ 13 - 0
src/lib/config/testdata/spec3.spec

@@ -0,0 +1,13 @@
+{
+  "data_specification": {
+    "module_name": "Spec2",
+    "config_data": [
+      {
+        "item_type": "integer",
+        "item_optional": False,
+        "item_default": 1
+      }
+    ]
+  }
+}
+

+ 12 - 0
src/lib/config/testdata/spec4.spec

@@ -0,0 +1,12 @@
+{
+  "data_specification": {
+    "module_name": "Spec2",
+    "config_data": [
+      { "item_name": "item1",
+        "item_optional": False,
+        "item_default": 1
+      }
+    ]
+  }
+}
+

+ 12 - 0
src/lib/config/testdata/spec5.spec

@@ -0,0 +1,12 @@
+{
+  "data_specification": {
+    "module_name": "Spec2",
+    "config_data": [
+      { "item_name": "item1",
+        "item_type": "integer",
+        "item_default": 1
+      }
+    ]
+  }
+}
+

+ 12 - 0
src/lib/config/testdata/spec6.spec

@@ -0,0 +1,12 @@
+{
+  "data_specification": {
+    "module_name": "Spec2",
+    "config_data": [
+      { "item_name": "item1",
+        "item_type": "integer",
+        "item_optional": False
+      }
+    ]
+  }
+}
+

+ 5 - 0
src/lib/config/testdata/spec7.spec

@@ -0,0 +1,5 @@
+{
+  "data_specification": {
+  }
+}
+

+ 3 - 0
src/lib/config/testdata/spec8.spec

@@ -0,0 +1,3 @@
+{
+}
+