[svn] commit: r720 - in /branches/parkinglot/src/lib/config/python/isc/config: datadefinition.py datadefinition_test.py
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Feb 4 13:37:28 UTC 2010
Author: jelte
Date: Thu Feb 4 13:37:28 2010
New Revision: 720
Log:
- implemented tests for DataDefinition.validate(data)
- implemented DataDefinition.validate(data)
(has one more feature than the cpp version, you can optionally pass it
a list where it stores errors it finds, for user feedback)
Modified:
branches/parkinglot/src/lib/config/python/isc/config/datadefinition.py
branches/parkinglot/src/lib/config/python/isc/config/datadefinition_test.py
Modified: branches/parkinglot/src/lib/config/python/isc/config/datadefinition.py
==============================================================================
--- branches/parkinglot/src/lib/config/python/isc/config/datadefinition.py (original)
+++ branches/parkinglot/src/lib/config/python/isc/config/datadefinition.py Thu Feb 4 13:37:28 2010
@@ -18,6 +18,8 @@
# definition. It is the python equivalent of data_def.h
#
import ast
+
+import isc.cc.data
# file objects are passed around as _io.TextIOWrapper objects
# import that so we can check those types
@@ -36,11 +38,25 @@
else:
raise DataDefinitionError("Not a str or file-like object")
- def validate(self, data):
+ def validate(self, data, errors = None):
"""Check whether the given piece of data conforms to this
- data definition"""
- # "TODO"
- return True
+ data definition. If so, it returns True. If not, it will
+ return false. If errors is given, and is an array, a string
+ describing the error will be appended to it. The current
+ version stops as soon as there is one error so this list
+ will not be exhaustive."""
+ data_def = self.get_definition()
+ if 'data_specification' not in data_def:
+ if errors:
+ errors.append("Data definition has no data_specification element")
+ return False
+ data_def = data_def['data_specification']
+ if 'config_data' not in data_def:
+ if errors:
+ errors.append("The is no config_data for this specification")
+ return False
+ errors = []
+ return _validate_spec_list(data_def['config_data'], data, errors)
def __read_data_spec_file(self, file, check = True):
"""Reads the data spec from the given file object.
@@ -102,20 +118,22 @@
if type(command) != dict:
raise DataDefinitionError("command in commands list is not a dict")
if "command_name" not in command:
- raise DataDefitionError("no command_name in command item")
+ raise DataDefinitionError("no command_name in command item")
command_name = command["command_name"]
if type(command_name) != str:
raise DataDefinitionError("command_name not a string: " + str(type(command_name)))
if "command_description" in command:
if type(command["command_description"]) != str:
- raise DataDefitionError("command_description not a string in " + command_name)
+ raise DataDefinitionError("command_description not a string in " + command_name)
if "command_args" in command:
if type(command["command_args"]) != list:
- raise DataDefitionError("command_args is not a list in " + command_name)
+ raise DataDefinitionError("command_args is not a list in " + command_name)
for command_arg in command["command_args"]:
if type(command_arg) != dict:
raise DataDefinitionError("command argument not a dict in " + command_name)
_check_item_spec(command_arg)
+ else:
+ raise DataDefinitionError("command_args missing in " + command_name)
pass
def _check_item_spec(config_item):
@@ -134,17 +152,19 @@
item_type = config_item["item_type"]
if type(item_type) != str:
raise DataDefinitionError("item_type in " + item_name + " is not a string: " + str(type(item_type)))
- if item_type not in ["integer", "real", "boolean", "string", "list", "map"]:
+ if item_type not in ["integer", "real", "boolean", "string", "list", "map", "any"]:
raise DataDefinitionError("unknown item_type in " + item_name + ": " + item_type)
if "item_optional" in config_item:
if type(config_item["item_optional"]) != bool:
raise DataDefinitionError("item_default in " + item_name + " is not a boolean")
if not config_item["item_optional"] and "item_default" not in config_item:
raise DataDefinitionError("no default value for non-optional item " + item_name)
+ else:
+ raise DataDefinitionError("item_optional not in item " + item_name)
if "item_default" in config_item:
item_default = config_item["item_default"]
- if (item_type == "int" and type(item_default) != int) or \
- (item_type == "real" and type(item_default) != double) or \
+ if (item_type == "integer" and type(item_default) != int) or \
+ (item_type == "real" and type(item_default) != float) or \
(item_type == "boolean" and type(item_default) != bool) or \
(item_type == "string" and type(item_default) != str) or \
(item_type == "list" and type(item_default) != list) or \
@@ -167,3 +187,69 @@
raise DataDefinitionError("map_item_spec element is not a dict")
_check_item_spec(map_item)
+
+def _validate_type(spec, value, errors):
+ """Returns true if the value is of the correct type given the
+ specification"""
+ data_type = spec['item_type']
+ if data_type == "integer" and type(value) != int:
+ if errors:
+ errors.append(str(value) + " should be an integer")
+ return False
+ elif data_type == "real" and type(value) != float:
+ if errors:
+ errors.append(str(value) + " should be a real")
+ return False
+ elif data_type == "boolean" and type(value) != bool:
+ if errors:
+ errors.append(str(value) + " should be a boolean")
+ return False
+ elif data_type == "string" and type(value) != str:
+ if errors:
+ errors.append(str(value) + " should be a string")
+ return False
+ elif data_type == "list" and type(value) != list:
+ if errors:
+ errors.append(str(value) + " should be a list, not a " + str(value.__class__.__name__))
+ return False
+ elif data_type == "map" and type(value) != dict:
+ if errors:
+ errors.append(str(value) + " should be a map")
+ return False
+ else:
+ return True
+
+def _validate_item(spec, data, errors):
+ if not _validate_type(spec, data, errors):
+ return False
+ elif type(data) == list:
+ list_spec = spec['list_item_spec']
+ for data_el in data:
+ if not _validate_type(list_spec, data_el, errors):
+ return False
+ if list_spec['item_type'] == "map":
+ if not _validate_item(list_spec, data_el, errors):
+ return False
+ elif type(data) == dict:
+ if not _validate_spec_list(spec['map_item_spec'], data, errors):
+ return False
+ return True
+
+def _validate_spec(spec, data, errors):
+ item_name = spec['item_name']
+ item_optional = spec['item_optional']
+
+ if item_name in data:
+ return _validate_item(spec, data[item_name], errors)
+ elif not item_optional:
+ if errors:
+ errors.append("non-optional item " + item_name + " missing")
+ return False
+ else:
+ return True
+
+def _validate_spec_list(data_spec, data, errors):
+ for spec_item in data_spec:
+ if not _validate_spec(spec_item, data, errors):
+ return False
+ return True
Modified: branches/parkinglot/src/lib/config/python/isc/config/datadefinition_test.py
==============================================================================
--- branches/parkinglot/src/lib/config/python/isc/config/datadefinition_test.py (original)
+++ branches/parkinglot/src/lib/config/python/isc/config/datadefinition_test.py Thu Feb 4 13:37:28 2010
@@ -19,8 +19,8 @@
import unittest
import os
-from isc.config import DataDefinition
-
+from isc.config import DataDefinition, DataDefinitionError
+import isc.cc.data
class TestDataDefinition(unittest.TestCase):
@@ -30,6 +30,9 @@
def spec_file(self, filename):
return(self.data_path + os.sep + filename)
+
+ def read_spec_file(self, filename):
+ return DataDefinition(self.spec_file(filename))
def spec1(self, dd):
data_def = dd.get_definition()
@@ -48,7 +51,42 @@
self.spec1(dd)
def test_bad_specfiles(self):
- self.assertRaises(DataDefinition(self.spec_file("spec3.spec")))
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec3.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec4.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec5.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec6.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec7.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec8.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec9.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec10.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec11.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec12.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec13.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec14.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec15.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec16.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec17.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec18.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec19.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec20.spec")
+ self.assertRaises(DataDefinitionError, self.read_spec_file, "spec21.spec")
+
+ def validate_data(self, specfile_name, datafile_name):
+ dd = DataDefinition(self.spec_file(specfile_name));
+ data_file = open(self.spec_file(datafile_name))
+ data_str = data_file.read()
+ data = isc.cc.data.parse_value_str(data_str)
+ return dd.validate(data)
+
+ def test_data_validation(self):
+ self.assertEqual(True, self.validate_data("spec22.spec", "data22_1.data"))
+ self.assertEqual(False, self.validate_data("spec22.spec", "data22_2.data"))
+ self.assertEqual(False, self.validate_data("spec22.spec", "data22_3.data"))
+ self.assertEqual(False, self.validate_data("spec22.spec", "data22_4.data"))
+ self.assertEqual(False, self.validate_data("spec22.spec", "data22_5.data"))
+ self.assertEqual(True, self.validate_data("spec22.spec", "data22_6.data"))
+ self.assertEqual(True, self.validate_data("spec22.spec", "data22_7.data"))
+ self.assertEqual(False, self.validate_data("spec22.spec", "data22_8.data"))
if __name__ == '__main__':
unittest.main()
More information about the bind10-changes
mailing list