Пример #1
0
    def test_pattern_value(self):
        # this tests a invalid regexp pattern
        with pytest.raises(RuleError) as r:
            Rule(schema={"type": "str", "pattern": "/@/\\"})
        assert str(
            r.value
        ) == "<RuleError: error code 4: Syntax error when compiling regex pattern: None: Path: '/'>"
        assert r.value.error_key == 'pattern.syntax_error'

        # Test that pattern keyword is not allowed when using a map
        # with self.assertRaisesRegexp(RuleError, ".+map\.pattern.+"):
        with pytest.raises(RuleError) as r:
            Rule(
                schema={
                    "type": "map",
                    "pattern": "^[a-z]+$",
                    "allowempty": True,
                    "mapping": {
                        "name": {
                            "type": "str"
                        }
                    }
                })
        assert str(
            r.value
        ) == "<RuleError: error code 4: Keyword pattern is not allowed inside map: Path: '/'>"
        assert r.value.error_key == 'pattern.not_allowed_in_map'

        # Test that pattern value must be string otherwise exception is raised
        with pytest.raises(RuleError) as r:
            Rule(schema={"type": "str", "pattern": 1})
        assert str(
            r.value
        ) == "<RuleError: error code 4: Value of pattern keyword: '1' is not a string: Path: '/'>"
        assert r.value.error_key == 'pattern.not_string'
Пример #2
0
    def test_assert_value(self):
        with pytest.raises(RuleError) as r:
            Rule(schema={
                "type": "seq",
                "sequence": [{
                    "type": "str",
                    "assert": 1
                }]
            })
        assert str(
            r.value
        ) == "<RuleError: error code 4: Value: '1' for keyword 'assert' is not a string: Path: '/sequence/0'>"
        assert r.value.error_key == 'assert.not_str'

        # Test that invalid characters is not present
        with pytest.raises(RuleError) as r:
            Rule(
                schema={
                    "type": "seq",
                    "sequence": [{
                        "type": "str",
                        "assert": "__import__"
                    }]
                })
        assert str(
            r.value
        ) == "<RuleError: error code 4: Value: '__import__' contain invalid content that is not allowed to be present in assertion keyword: Path: '/sequence/0'>"  # NOQA: E501
        assert r.value.error_key == 'assert.unsupported_content'
Пример #3
0
    def test_type_value(self):
        # TODO: This test is currently semi broken, partial schemas might be somewhat broken possibly
        # # Test that when only having a schema; rule it should throw error
        # with pytest.raises(RuleError) as r:
        #     Rule(schema={"schema;fooone": {"type": "map", "mapping": {"foo": {"type": "str"}}}})
        # assert str(r.value) == "<RuleError: error code 4: Key 'type' not found in schema rule: Path: '/'>"
        # assert r.value.error_key == 'type.missing'

        # Test a valid rule with both "str" and "unicode" types work
        r = Rule(schema={"type": str("str")})
        r = Rule(schema={"type": unicode("str")})

        # Test that type key must be string otherwise exception is raised
        with pytest.raises(RuleError) as r:
            Rule(schema={"type": 1})
        assert str(
            r.value
        ) == "<RuleError: error code 4: Key 'type' in schema rule is not a string type (found int): Path: '/'>"
        assert r.value.error_key == 'type.not_string'

        # this tests that the type key must be a string
        with pytest.raises(RuleError) as r:
            Rule(schema={"type": 1}, parent=None)
        assert str(
            r.value
        ) == "<RuleError: error code 4: Key 'type' in schema rule is not a string type (found int): Path: '/'>"
        assert r.value.error_key == 'type.not_string'
Пример #4
0
    def test_build_sequence_multiple_values(self):
        """
        Test with multiple values.
        """
        # Test basic sequence rule
        r = Rule(schema={
            'type': 'seq',
            'sequence': [{
                'type': 'str'
            }, {
                'type': 'int'
            }]
        })
        assert r._type == "seq"
        assert r._matching == "any"
        assert len(r._sequence) == 2
        assert isinstance(r._sequence, list)
        assert all([
            isinstance(r._sequence[i], Rule) for i in range(len(r._sequence))
        ])
        assert r._sequence[0]._type == "str"
        assert r._sequence[1]._type == "int"

        # Test sequence without explicit type
        r = Rule(schema={'sequence': [{'type': 'str'}, {'type': 'int'}]})
        assert r._type == "seq"
        assert r._matching == "any"
        assert len(r._sequence) == 2
        assert isinstance(r._sequence, list)
        assert all([
            isinstance(r._sequence[i], Rule) for i in range(len(r._sequence))
        ])
        assert r._sequence[0]._type == "str"
        assert r._sequence[1]._type == "int"
Пример #5
0
    def _start_validate(self, value=None):
        path = ""
        errors = []
        done = []

        s = {}

        # Look for schema; tags so they can be parsed before the root rule is parsed
        for k, v in self.schema.items():
            if k.startswith("schema;"):
                Log.debug("Found partial schema; : {}".format(v))
                r = Rule(schema=v)
                Log.debug(" Partial schema : {}".format(r))
                pykwalify.partial_schemas[k.split(";", 1)[1]] = r
            else:
                # readd all items that is not schema; so they can be parsed
                s[k] = v

        self.schema = s

        Log.debug("Building root rule object")
        root_rule = Rule(schema=self.schema)
        self.root_rule = root_rule
        Log.debug("Done building root rule")
        Log.debug("Root rule: {}".format(self.root_rule))

        self._validate(value, root_rule, path, errors, done)

        return errors
Пример #6
0
    def test_mapping(self):
        # This tests mapping with a nested type and pattern
        r = Rule(
            schema={
                "type": "map",
                "mapping": {
                    "name": {
                        "type": "str",
                        "pattern": ".+@.+"
                    }
                }
            })
        assert r._type == "map", "rule type is not map"
        assert isinstance(r._mapping, dict), "mapping is not dict"
        assert r._mapping[
            "name"]._type == "str", "nested mapping is not of string type"
        assert r._mapping[
            "name"]._pattern is not None, "nested mapping has no pattern var set"
        assert r._mapping[
            "name"]._pattern == ".+@.+", "pattern is not set to correct value"

        # when type is specefied, 'mapping' key must be present
        with pytest.raises(SchemaConflict) as ex:
            Rule(schema={"type": "map"})
        assert ex.value.msg.startswith(
            "map.nomapping"), "Wrong exception was raised"
Пример #7
0
    def test_type_value(self):
        # Test that when only having a schema; rule it should throw error
        with pytest.raises(RuleError) as r:
            Rule(
                schema={
                    "schema;fooone": {
                        "type": "map",
                        "mapping": {
                            "foo": {
                                "type": "str"
                            }
                        }
                    }
                })
        assert str(
            r.value
        ) == "<RuleError: error code 4: Key 'type' not found in schema rule: Path: '/'>"
        assert r.value.error_key == 'type.missing'

        # Test that type key must be string otherwise exception is raised
        with pytest.raises(RuleError) as r:
            Rule(schema={"type": 1})
        assert str(
            r.value
        ) == "<RuleError: error code 4: Key 'type' in schema rule is not a string type: Path: '/'>"
        assert r.value.error_key == 'type.not_string'

        # this tests that the type key must be a string
        with pytest.raises(RuleError) as r:
            Rule(schema={"type": 1}, parent=None)
        assert str(
            r.value
        ) == "<RuleError: error code 4: Key 'type' in schema rule is not a string type: Path: '/'>"
        assert r.value.error_key == 'type.not_string'
Пример #8
0
    def _start_validate(self, value=None):
        """
        """
        path = ""
        self.errors = []
        done = []

        s = {}

        # Look for schema; tags so they can be parsed before the root rule is parsed
        for k, v in self.schema.items():
            if k.startswith("schema;"):
                log.debug(u"Found partial schema; : %s", v)
                r = Rule(schema=v)
                log.debug(u" Partial schema : %s", r)
                pykwalify.partial_schemas[k.split(";", 1)[1]] = r
            else:
                # readd all items that is not schema; so they can be parsed
                s[k] = v

        self.schema = s

        log.debug(u"Building root rule object")
        root_rule = Rule(schema=self.schema)
        self.root_rule = root_rule
        log.debug(u"Done building root rule")
        log.debug(u"Root rule: %s", self.root_rule)

        self._validate(value, root_rule, path, done)
Пример #9
0
 def test_date_and_format_value(self):
     r = Rule(schema={"type": "date", "format": "%y"})
     assert r.format is not None, "date var not set proper"
     assert isinstance(r.format, list), "date format should be a list"
     with pytest.raises(RuleError) as r:
         Rule(schema={"type": "date", "format": 1})
     assert str(
         r.value
     ) == "<RuleError: error code 4: Value of format keyword: '1' must be a string or list or string values: Path: '/'>"
     with pytest.raises(RuleError) as r:
         Rule(schema={"type": "map", "format": "%y"})
     assert str(
         r.value
     ) == "<RuleError: error code 4: Keyword format is only allowed when used with the following types: ('date',): Path: '/'>"
Пример #10
0
    def test_unique_value(self):
        # this tests that this cannot be used in the root level
        with pytest.raises(RuleError) as r:
            Rule(schema={"type": "str", "unique": True})
        assert str(
            r.value
        ) == "<RuleError: error code 4: Keyword 'unique' can't be on root level of schema: Path: '/'>"
        assert r.value.error_key == 'unique.not_on_root_level'

        # this tests that unique cannot be used at root level
        with pytest.raises(RuleError) as r:
            Rule(schema={"type": "seq", "unique": True})
        assert str(
            r.value
        ) == "<RuleError: error code 4: Type of the value: 'seq' for 'unique' keyword is not a scalar type: Path: '/'>"
        assert r.value.error_key == 'unique.not_scalar'
Пример #11
0
 def test_nullable_value(self):
     # Test that nullable value must be bool otherwise exception is raised
     with pytest.raises(RuleError) as r:
         Rule(schema={"type": "str", "nullable": "foobar"})
     assert str(
         r.value
     ) == "<RuleError: error code 4: Value: 'foobar' for nullable keyword must be a boolean: Path: '/'>"
     assert r.value.error_key == 'nullable.not_bool'
Пример #12
0
 def test_required_value(self):
     # Test that required value must be bool otherwise exception is raised
     with pytest.raises(RuleError) as r:
         Rule(schema={"type": "str", "required": "foobar"})
     assert str(
         r.value
     ) == "<RuleError: error code 4: Value: 'foobar' for required keyword must be a boolean: Path: '/'>"
     assert r.value.error_key == 'required.not_bool'
Пример #13
0
 def test_unkknown_key(self):
     # Test that providing an unknown key raises exception
     with pytest.raises(RuleError) as r:
         Rule(schema={"type": "str", "foobar": True})
     assert str(
         r.value
     ) == "<RuleError: error code 4: Unknown key: foobar found: Path: '/'>"
     assert r.value.error_key == 'key.unknown'
Пример #14
0
    def test_length(self):
        r = Rule(schema={"type": "int", "length": {"max": 10, "min": 1}})
        assert r.length is not None, "length var not set proper"
        assert isinstance(r.length, dict), "range var is not of dict type"

        # this tests that the range key must be a dict
        with pytest.raises(RuleError) as r:
            Rule(schema={"type": "int", "length": []})
        assert str(
            r.value
        ) == "<RuleError: error code 4: Length value is not a dict type: '[]': Path: '/'>"
        assert r.value.error_key == 'length.not_map'

        with pytest.raises(RuleError) as r:
            Rule(schema={"type": "str", "length": {"max": "z"}})
        assert str(
            r.value
        ) == "<RuleError: error code 4: Value: 'z' for 'max' keyword is not a number: Path: '/'>"
        assert r.value.error_key == 'length.max.not_number'

        # this tests that min is bigger then max that should not be possible
        with pytest.raises(RuleError) as r:
            Rule(schema={"type": "int", "length": {"max": 10, "min": 11}})
        assert str(
            r.value
        ) == "<RuleError: error code 4: Value for 'max' can't be less then value for 'min'. 10 < 11: Path: '/'>"
        assert r.value.error_key == 'length.max_lt_min'

        # test that min-ex is bigger then max-ex, that should not be possible
        with pytest.raises(RuleError) as r:
            Rule(schema={
                "type": "int",
                "length": {
                    "max-ex": 10,
                    "min-ex": 11
                }
            })
        assert str(
            r.value
        ) == "<RuleError: error code 4: Value for 'max-ex' can't be less then value for 'min-ex'. 10 <= 11: Path: '/'>"
        assert r.value.error_key == 'length.max-ex_le_min-ex'

        # test that a string has non negative boundaries
        with pytest.raises(RuleError) as r:
            Rule(schema={"type": "str", "length": {"max": -1, "min": -2}})
        assert str(
            r.value
        ) == "<RuleError: error code 4: Value for 'min' can't be negative in case of type str.: Path: '/'>"
        assert r.value.error_key == 'length.min_negative'

        # test that a seq has non negative boundaries
        with pytest.raises(RuleError) as r:
            Rule(schema={"type": "seq", "length": {"max": 3, "min": -2}})
        assert str(
            r.value
        ) == "<RuleError: error code 4: Value for 'min' can't be negative in case of type seq.: Path: '/'>"
        assert r.value.error_key == 'length.min_negative'
Пример #15
0
 def test_allow_empty_map(self):
     r = Rule(
         schema={
             "type": "map",
             "allowempty": True,
             "mapping": {
                 "name": {
                     "type": "str"
                 }
             }
         })
     assert r._allowempty_map is True
Пример #16
0
    def _start_validate(self, value=None):
        path = ""
        errors = []
        done = []

        Log.debug("Building root rule object")
        root_rule = Rule(schema=self.schema)
        self.root_rule = root_rule
        Log.debug("Done building root rule")

        self._validate(value, root_rule, path, errors, done)

        return errors
Пример #17
0
    def test_sequence(self):
        # Test basic sequence rule
        r = Rule(schema={"type": "seq", "sequence": [{"type": "str"}]})
        assert r._type == "seq"
        assert isinstance(r._sequence, list)
        assert isinstance(r._sequence[0], Rule)
        assert r._sequence[0]._type == "str"

        # Test sequence without explicit type
        r = Rule(schema={"sequence": [{"type": "str"}]})
        assert r._type == "seq"
        assert isinstance(r._sequence, list)
        assert isinstance(r._sequence[0], Rule)
        assert r._sequence[0]._type == "str"

        # Test short name 'seq'
        r = Rule(schema={"seq": [{"type": "str"}]})
        assert r._type == "seq"
        assert isinstance(r._sequence, list)
        assert isinstance(r._sequence[0], Rule)
        assert r._sequence[0]._type == "str"

        # Test error is raised when sequence key is missing
        with pytest.raises(SchemaConflict) as ex:
            Rule(schema={"type": "seq"})
        assert ex.value.msg.startswith(
            "seq.nosequence"), "Wrong exception was raised"

        # sequence and pattern can't be used at same time
        with pytest.raises(SchemaConflict) as ex:
            Rule(schema={
                "type": "seq",
                "sequence": [{
                    "type": "str"
                }],
                "pattern": "..."
            })
        assert ex.value.msg.startswith(
            "seq.conflict :: pattern"), "Wrong exception was raised"
Пример #18
0
 def test_assert_value(self):
     # this test the NYI exception for the assert key
     with pytest.raises(RuleError) as r:
         Rule(schema={
             "type": "seq",
             "sequence": [{
                 "type": "str",
                 "assert": "foobar"
             }]
         })
     assert str(
         r.value
     ) == "<RuleError: error code 4: Keyword assert is not yet implemented: Path: '/sequence/0'>"
     assert r.value.error_key == 'assert.NotYetImplemented'
Пример #19
0
    def test_enum_value(self):
        # this tests the various valid enum types
        Rule(schema={"type": "int", "enum": [1, 2, 3]})
        Rule(schema={"type": "bool", "enum": [True, False]})
        r = Rule(schema={"type": "str", "enum": ["a", "b", "c"]})
        assert r._enum is not None, "enum var is not set proper"
        assert isinstance(r._enum, list), "enum is not set to a list"
        assert len(r._enum) == 3, "invalid length of enum entries"

        # this tests the missmatch between the type and the data inside a enum
        with pytest.raises(RuleError) as r:
            Rule(schema={"type": "str", "enum": [1, 2, 3]})
        assert str(r.value).startswith(
            "<RuleError: error code 4: Item: '1' in enum is not of correct class type:"
        )
        assert r.value.error_key == 'enum.type.unmatch'

        with pytest.raises(RuleError) as r:
            Rule(schema={"type": "str", "enum": True})
        assert str(
            r.value
        ) == "<RuleError: error code 4: Enum is not a sequence: Path: '/'>"
        assert r.value.error_key == 'enum.not_seq'
Пример #20
0
 def test_matching_rule(self):
     # Test that exception is raised when a invalid matching rule is used
     with pytest.raises(RuleError) as r:
         Rule(
             schema={
                 "type": "map",
                 "matching-rule": "foobar",
                 "mapping": {
                     "regex;.+": {
                         "type": "seq",
                         "sequence": [{
                             "type": "str"
                         }]
                     }
                 }
             })
     assert str(
         r.value
     ) == "<RuleError: error code 4: Specified rule in key: foobar is not part of allowed rule set : ['any', 'all']: Path: '/'>"
     assert r.value.error_key == 'matching_rule.not_allowed'
Пример #21
0
    def test_sequence(self):
        # this tests seq type with a internal type of str
        r = Rule(schema={"type": "seq", "sequence": [{"type": "str"}]})
        assert r._type is not None, "rule not contain type var"
        assert r._type == "seq", "type not 'seq'"
        assert r._sequence is not None, "rule not contain sequence var"
        assert isinstance(r._sequence, list), "rule is not a list"

        # Test basic sequence rule
        r = Rule(schema={"type": "seq", "sequence": [{"type": "str"}]})
        assert r._type == "seq"
        assert isinstance(r._sequence, list)
        assert isinstance(r._sequence[0], Rule)
        assert r._sequence[0]._type == "str"

        # Test sequence without explicit type
        r = Rule(schema={"sequence": [{"type": "str"}]})
        assert r._type == "seq"
        assert isinstance(r._sequence, list)
        assert isinstance(r._sequence[0], Rule)
        assert r._sequence[0]._type == "str"

        # Test short name 'seq'
        r = Rule(schema={"seq": [{"type": "str"}]})
        assert r._type == "seq"
        assert isinstance(r._sequence, list)
        assert isinstance(r._sequence[0], Rule)
        assert r._sequence[0]._type == "str"

        # Test error is raised when sequence key is missing
        with pytest.raises(SchemaConflict) as ex:
            Rule(schema={"type": "seq"})
        assert str(
            ex.value
        ) == "<SchemaConflict: error code 5: Type is sequence but no sequence alias found on same level: Path: '/'>"

        # sequence and pattern can't be used at same time
        with pytest.raises(SchemaConflict) as ex:
            Rule(schema={
                "type": "seq",
                "sequence": [{
                    "type": "str"
                }],
                "pattern": "..."
            })
        assert str(
            ex.value
        ) == "<SchemaConflict: error code 5: Sequence and pattern can't be on the same level in the schema: Path: '/'>"
Пример #22
0
 def test_schema(self):
     # Test that when using both schema; and include tag that it throw an error because schema; tags should be parsed via Core()
     with pytest.raises(RuleError) as r:
         Rule(
             schema={
                 "schema;str": {
                     "type": "map",
                     "mapping": {
                         "foo": {
                             "type": "str"
                         }
                     }
                 },
                 "type": "map",
                 "mapping": {
                     "foo": {
                         "include": "str"
                     }
                 }
             })
     assert str(
         r.value
     ) == "<RuleError: error code 4: Schema is only allowed on top level of schema file: Path: '/'>"
     assert r.value.error_key == 'schema.not.toplevel'
Пример #23
0
    def test_check_conflicts(self):
        # TODO: This do not work and enum schema conflict is not raised... RuleError: <RuleError: error code 4: enum.notscalar>
        # with pytest.raises(SchemaConflict) as ex:
        #     r = Rule(schema={"type": "seq", "sequence": [{"type": "str"}], "enum": [1, 2, 3]})
        # assert ex.value.msg.startswith("seq.conflict :: enum"), "Wrong exception was raised"

        # Test sequence and mapping can't be used at same level
        with pytest.raises(SchemaConflict) as ex:
            Rule(
                schema={
                    "type": "seq",
                    "sequence": [{
                        "type": "str"
                    }],
                    "mapping": {
                        "name": {
                            "type": "str",
                            "pattern": ".+@.+"
                        }
                    }
                })
        assert str(
            ex.value
        ) == "<SchemaConflict: error code 5: Sequence and mapping can't be on the same level in the schema: Path: '/'>"
        assert ex.value.error_key == 'seq.conflict.mapping'

        # Mapping and sequence can't used at same time
        with pytest.raises(SchemaConflict) as ex:
            Rule(
                schema={
                    "type": "map",
                    "mapping": {
                        "foo": {
                            "type": "str"
                        }
                    },
                    "sequence": [{
                        "type": "str"
                    }]
                })
        assert str(
            ex.value
        ) == "<SchemaConflict: error code 5: Mapping and sequence can't be on the same level in the schema: Path: '/'>"
        assert ex.value.error_key == 'map.conflict.sequence'

        # scalar type and sequence can't be used at same time
        with pytest.raises(SchemaConflict) as ex:
            Rule(schema={"type": "int", "sequence": [{"type": "str"}]})
        assert str(
            ex.value
        ) == "<SchemaConflict: error code 5: Scalar and sequence can't be on the same level in the schema: Path: '/'>"
        assert ex.value.error_key == 'scalar.conflict.sequence'

        # scalar type and mapping can't be used at same time
        with pytest.raises(SchemaConflict) as ex:
            Rule(schema={"type": "int", "mapping": {"foo": {"type": "str"}}})
        assert str(
            ex.value
        ) == "<SchemaConflict: error code 5: Scalar and mapping can't be on the same level in the schema: Path: '/'>"
        assert ex.value.error_key == 'scalar.conflict.mapping'

        # scalar type and enum can't be used at same time
        with pytest.raises(SchemaConflict) as ex:
            Rule(schema={
                "type": "int",
                "enum": [1, 2, 3],
                "range": {
                    "max": 10,
                    "min": 1
                }
            })
        assert str(
            ex.value
        ) == "<SchemaConflict: error code 5: Enum and range can't be on the same level in the schema: Path: '/'>"
        assert ex.value.error_key == 'enum.conflict.range'
Пример #24
0
    def test_mapping(self):
        # This tests mapping with a nested type and pattern
        r = Rule(
            schema={
                "type": "map",
                "mapping": {
                    "name": {
                        "type": "str",
                        "pattern": ".+@.+"
                    }
                }
            })
        assert r._type == "map", "rule type is not map"
        assert isinstance(r._mapping, dict), "mapping is not dict"
        assert r._mapping[
            "name"]._type == "str", "nested mapping is not of string type"
        assert r._mapping[
            "name"]._pattern is not None, "nested mapping has no pattern var set"
        assert r._mapping[
            "name"]._pattern == ".+@.+", "pattern is not set to correct value"

        # when type is specefied, 'mapping' key must be present
        with pytest.raises(SchemaConflict) as ex:
            Rule(schema={"type": "map"})
        assert str(
            ex.value
        ) == "<SchemaConflict: error code 5: Type is mapping but no mapping alias found on same level: Path: '/'>"

        # 'map' and 'enum' can't be used at same time
        # TODO: This do not work because it currently raises RuleError: <RuleError: error code 4: enum.notscalar>
        # with pytest.raises(SchemaConflict):
        #     r = Rule(schema={"type": "map", "enum": [1, 2, 3]})

        # Test that 'map' and 'mapping' can't be at the same level
        with pytest.raises(RuleError) as r:
            Rule(
                schema={
                    "map": {
                        "stream": {
                            "type": "any"
                        }
                    },
                    "mapping": {
                        "seams": {
                            "type": "any"
                        }
                    }
                })
        assert str(
            r.value
        ) == "<RuleError: error code 4: Keywords 'map' and 'mapping' can't be used on the same level: Path: '/'>"
        assert r.value.error_key == 'mapping.duplicate_keywords'

        # This will test that a invalid regex will throw error when parsing rules
        with pytest.raises(RuleError) as r:
            Rule(
                schema={
                    "type": "map",
                    "matching-rule": "any",
                    "mapping": {
                        "regex;(+": {
                            "type": "seq",
                            "sequence": [{
                                "type": "str"
                            }]
                        }
                    }
                })
        assert str(
            r.value
        ) == "<RuleError: error code 4: Unable to compile regex '(+': Path: '/'>"
        assert r.value.error_key == 'mapping.regex.compile_error'

        # this tests map/dict but with no elements
        with pytest.raises(RuleError) as r:
            Rule(schema={"type": "map", "mapping": {}})
        assert str(
            r.value
        ) == "<RuleError: error code 4: Mapping do not contain any elements: Path: '/'>"
        assert r.value.error_key == 'mapping.no_elements'
Пример #25
0
    def testRuleClass(self):
        # this tests seq type with a internal type of str
        r = Rule(schema={"type": "seq", "sequence": [{"type": "str"}]})
        self.assertTrue(r._type is not None, msg="rule not contain type var")
        self.assertTrue(r._type == "seq", msg="type not 'seq'")
        self.assertTrue(r._sequence is not None,
                        msg="rule not contain sequence var")
        self.assertTrue(isinstance(r._sequence, list),
                        msg="rule is not a list")

        # this tests that the type key must be a string
        with self.assertRaises(RuleError):
            Rule(schema={"type": 1}, parent=None)

        # Test the name value
        r = Rule(schema={"type": "seq", "sequence": [{"type": "str"}]})
        self.assertTrue(r._sequence[0]._type == "str",
                        msg="first item in sequences type is not str")

        # This tests mapping with a nested type and pattern
        r = Rule(
            schema={
                "type": "map",
                "mapping": {
                    "name": {
                        "type": "str",
                        "pattern": ".+@.+"
                    }
                }
            })
        self.assertTrue(r._type == "map", msg="rule type is not map")
        self.assertTrue(isinstance(r._mapping, dict),
                        msg="mapping is not dict")
        self.assertTrue(r._mapping["name"]._type == "str",
                        msg="nested mapping is not of string type")
        self.assertTrue(r._mapping["name"]._pattern is not None,
                        msg="nested mapping has no pattern var set")
        self.assertTrue(r._mapping["name"]._pattern == ".+@.+",
                        msg="pattern is not set to correct value")

        # this tests a invalid regexp pattern
        with self.assertRaises(RuleError):
            Rule(schema={"type": "str", "pattern": "/@/\\"})

        # this tests the various valid enum types
        r = Rule(schema={"type": "int", "enum": [1, 2, 3]})
        r = Rule(schema={"type": "bool", "enum": [True, False]})
        r = Rule(schema={"type": "str", "enum": ["a", "b", "c"]})
        self.assertTrue(r._enum is not None, msg="enum var is not set proper")
        self.assertTrue(isinstance(r._enum, list),
                        msg="enum is not set to a list")
        self.assertTrue(len(r._enum) == 3,
                        msg="invalid length of enum entries")

        # this tests the missmatch between the type and the data inside a enum
        with self.assertRaises(RuleError):
            Rule(schema={"type": "str", "enum": [1, 2, 3]})

        # this test the NYI exception for the assert key
        with self.assertRaises(RuleError):
            Rule(schema={
                "type": "seq",
                "sequence": [{
                    "type": "str",
                    "assert": "foobar"
                }]
            })

        r = Rule(schema={"type": "int", "range": {"max": 10, "min": 1}})
        self.assertTrue(r._range is not None, msg="range var not set proper")
        self.assertTrue(isinstance(r._range, dict),
                        msg="range var is not of dict type")

        # this tests that the range key must be a dict
        with self.assertRaises(RuleError):
            Rule(schema={"type": "int", "range": []})

        Rule(schema={"type": "str", "range": {"max": "z", "min": "a"}})

        # this tests that the range values is not for the string but only for int.
        # min/max must be the same type as the value of the type key
        with self.assertRaises(RuleError):
            Rule(schema={"type": "str", "range": {"max": 10, "min": 1}})

        # this tests that min is bigger then max that should not be possible
        with self.assertRaises(RuleError):
            Rule(schema={"type": "int", "range": {"max": 10, "min": 11}})

        # this tests that length works with str type
        r = Rule(schema={"type": "str", "length": {"max": 16, "min": 8}})
        self.assertTrue(r._length is not None, msg="lenght var not set proper")
        self.assertTrue(isinstance(r._length, dict),
                        msg="length var is not of dict type")

        # this tests that length do not work with int type
        with self.assertRaises(RuleError):
            Rule(schema={"type": "int", "length": {"max": 10, "min": 11}})

        # this tests that min cannot be above max even with correct type
        with self.assertRaises(RuleError):
            Rule(schema={"type": "str", "length": {"max": 10, "min": 11}})

        # this tests that this cannot be used in the root level
        with self.assertRaises(RuleError):
            Rule(schema={"type": "str", "unique": True})

        # this tests that unique cannot be used at root level
        with self.assertRaises(RuleError):
            Rule(schema={"type": "seq", "unique": True})

        # this tests map/dict but with no elements
        with self.assertRaises(RuleError):
            Rule(schema={"type": "map", "mapping": {}})

        # This will test that a invalid regex will throw error when parsing rules
        with self.assertRaises(RuleError):
            Rule(
                schema={
                    "type": "map",
                    "matching-rule": "any",
                    "mapping": {
                        "regex;(+": {
                            "type": "seq",
                            "sequence": [{
                                "type": "str"
                            }]
                        }
                    }
                })
Пример #26
0
    def testRuleClass(self):
        # this tests seq type with a internal type of str
        r = Rule(schema={"type": "seq", "sequence": [{"type": "str"}]})
        self.assertTrue(r._type is not None, msg="rule not contain type var")
        self.assertTrue(r._type == "seq", msg="type not 'seq'")
        self.assertTrue(r._sequence is not None,
                        msg="rule not contain sequence var")
        self.assertTrue(isinstance(r._sequence, list),
                        msg="rule is not a list")

        # this tests that the type key must be a string
        with self.assertRaises(RuleError):
            Rule(schema={"type": 1}, parent=None)

        # Test the name value
        r = Rule(schema={"type": "seq", "sequence": [{"type": "str"}]})
        self.assertTrue(r._sequence[0]._type == "str",
                        msg="first item in sequences type is not str")

        # This tests mapping with a nested type and pattern
        r = Rule(
            schema={
                "type": "map",
                "mapping": {
                    "name": {
                        "type": "str",
                        "pattern": ".+@.+"
                    }
                }
            })
        self.assertTrue(r._type == "map", msg="rule type is not map")
        self.assertTrue(isinstance(r._mapping, dict),
                        msg="mapping is not dict")
        self.assertTrue(r._mapping["name"]._type == "str",
                        msg="nested mapping is not of string type")
        self.assertTrue(r._mapping["name"]._pattern is not None,
                        msg="nested mapping has no pattern var set")
        self.assertTrue(r._mapping["name"]._pattern == ".+@.+",
                        msg="pattern is not set to correct value")

        # this tests a invalid regexp pattern
        with self.assertRaises(RuleError):
            Rule(schema={"type": "str", "pattern": "/@/\\"})

        # this tests the various valid enum types
        r = Rule(schema={"type": "int", "enum": [1, 2, 3]})
        r = Rule(schema={"type": "bool", "enum": [True, False]})
        r = Rule(schema={"type": "str", "enum": ["a", "b", "c"]})
        self.assertTrue(r._enum is not None, msg="enum var is not set proper")
        self.assertTrue(isinstance(r._enum, list),
                        msg="enum is not set to a list")
        self.assertTrue(len(r._enum) == 3,
                        msg="invalid length of enum entries")

        # this tests the missmatch between the type and the data inside a enum
        with self.assertRaises(RuleError):
            Rule(schema={"type": "str", "enum": [1, 2, 3]})

        # this test the NYI exception for the assert key
        with self.assertRaises(RuleError):
            Rule(schema={
                "type": "seq",
                "sequence": [{
                    "type": "str",
                    "assert": "foobar"
                }]
            })

        r = Rule(schema={"type": "int", "range": {"max": 10, "min": 1}})
        self.assertTrue(r._range is not None, msg="range var not set proper")
        self.assertTrue(isinstance(r._range, dict),
                        msg="range var is not of dict type")

        # this tests that the range key must be a dict
        with self.assertRaises(RuleError):
            Rule(schema={"type": "int", "range": []})

        with self.assertRaises(RuleError):
            Rule(schema={"type": "str", "range": {"max": "z", "min": "a"}})

        # this tests that min is bigger then max that should not be possible
        with self.assertRaises(RuleError):
            Rule(schema={"type": "int", "range": {"max": 10, "min": 11}})

        # test that min-ex is bigger then max-ex, that should not be possible
        with self.assertRaises(RuleError):
            Rule(schema={"type": "int", "range": {"max-ex": 10, "min-ex": 11}})

        # this tests that this cannot be used in the root level
        with self.assertRaises(RuleError):
            Rule(schema={"type": "str", "unique": True})

        # this tests that unique cannot be used at root level
        with self.assertRaises(RuleError):
            Rule(schema={"type": "seq", "unique": True})

        # this tests map/dict but with no elements
        with self.assertRaises(RuleError):
            Rule(schema={"type": "map", "mapping": {}})

        # This will test that a invalid regex will throw error when parsing rules
        with self.assertRaises(RuleError):
            Rule(
                schema={
                    "type": "map",
                    "matching-rule": "any",
                    "mapping": {
                        "regex;(+": {
                            "type": "seq",
                            "sequence": [{
                                "type": "str"
                            }]
                        }
                    }
                })

        # Test that pattern keyword is not allowed when using a map
        with self.assertRaisesRegexp(RuleError, ".+map\.pattern.+"):
            Rule(
                schema={
                    "type": "map",
                    "pattern": "^[a-z]+$",
                    "allowempty": True,
                    "mapping": {
                        "name": {
                            "type": "str"
                        }
                    }
                })

        # Test that when only having a schema; rule it should throw error
        with self.assertRaises(RuleError):
            Rule(
                schema={
                    "schema;fooone": {
                        "type": "map",
                        "mapping": {
                            "foo": {
                                "type": "str"
                            }
                        }
                    }
                })

        # Test that when using both schema; and include tag that it throw an error because schema; tags should be parsed via Core()
        with self.assertRaises(RuleError):
            Rule(
                schema={
                    "schema;str": {
                        "type": "map",
                        "mapping": {
                            "foo": {
                                "type": "str"
                            }
                        }
                    },
                    "type": "map",
                    "mapping": {
                        "foo": {
                            "include": "str"
                        }
                    }
                })

        # Test that exception is raised when a invalid matching rule is used
        with pytest.raises(RuleError) as ex:
            Rule(
                schema={
                    "type": "map",
                    "matching-rule": "foobar",
                    "mapping": {
                        "regex;.+": {
                            "type": "seq",
                            "sequence": [{
                                "type": "str"
                            }]
                        }
                    }
                })
        assert ex.value.msg.startswith(
            "Specefied rule in key : foobar is not part of allowed rule set")

        # Test that providing an unknown key raises exception
        with pytest.raises(RuleError) as ex:
            Rule(schema={"type": "str", "foobar": True})
        assert ex.value.msg.startswith("Unknown key: foobar found")

        # Test that type key must be string otherwise exception is raised
        with pytest.raises(RuleError) as ex:
            Rule(schema={"type": 1})
        assert ex.value.msg.startswith(
            "key 'type' in schema rule is not a string type")

        # Test that required value must be bool otherwise exception is raised
        with pytest.raises(RuleError) as ex:
            Rule(schema={"type": "str", "required": "foobar"})
        assert ex.value.msg.startswith("required.notbool : foobar")

        # Test that pattern value must be string otherwise exception is raised
        with pytest.raises(RuleError) as ex:
            Rule(schema={"type": "str", "pattern": 1})
        assert ex.value.msg.startswith("pattern.notstr : 1 :")

        with pytest.raises(RuleError) as ex:
            Rule(schema={"type": "str", "enum": True})
        assert ex.value.msg.startswith("enum.notseq")

        # Test that 'map' and 'mapping' can't be at the same level
        with pytest.raises(RuleError) as ex:
            Rule(
                schema={
                    "map": {
                        "stream": {
                            "type": "any"
                        }
                    },
                    "mapping": {
                        "seams": {
                            "type": "any"
                        }
                    }
                })
        assert ex.value.msg.startswith("mapping.multiple-use")
Пример #27
0
    def test_schema_conflicts(self):
        # TODO: Each exception must be checked what key is raised withiin it...

        # Test error is raised when sequence key is missing
        with pytest.raises(SchemaConflict) as ex:
            r = Rule(schema={"type": "seq"})
        assert ex.value.msg.startswith(
            "seq.nosequence"), "Wrong exception was raised"

        # TODO: This do not work and enum schema conflict is not raised... RuleError: <RuleError: error code 4: enum.notscalar>
        # with pytest.raises(SchemaConflict) as ex:
        #     r = Rule(schema={"type": "seq", "sequence": [{"type": "str"}], "enum": [1, 2, 3]})
        # assert ex.value.msg.startswith("seq.conflict :: enum"), "Wrong exception was raised"

        with pytest.raises(SchemaConflict) as ex:
            r = Rule(schema={
                "type": "seq",
                "sequence": [{
                    "type": "str"
                }],
                "pattern": "..."
            })
        assert ex.value.msg.startswith(
            "seq.conflict :: pattern"), "Wrong exception was raised"

        with pytest.raises(SchemaConflict) as ex:
            r = Rule(
                schema={
                    "type": "seq",
                    "sequence": [{
                        "type": "str"
                    }],
                    "mapping": {
                        "name": {
                            "type": "str",
                            "pattern": ".+@.+"
                        }
                    }
                })
        assert ex.value.msg.startswith(
            "seq.conflict :: mapping"), "Wrong exception was raised"

        with pytest.raises(SchemaConflict) as ex:
            r = Rule(schema={"type": "map"})
        assert ex.value.msg.startswith(
            "map.nomapping"), "Wrong exception was raised"

        # TODO: This do not work because it currently raises RuleError: <RuleError: error code 4: enum.notscalar>
        # with pytest.raises(SchemaConflict):
        #     r = Rule(schema={"type": "map", "enum": [1, 2, 3]})

        with pytest.raises(SchemaConflict) as ex:
            r = Rule(
                schema={
                    "type": "map",
                    "mapping": {
                        "foo": {
                            "type": "str"
                        }
                    },
                    "sequence": [{
                        "type": "str"
                    }]
                })
        assert ex.value.msg.startswith(
            "map.conflict :: mapping"), "Wrong exception was raised"

        with pytest.raises(SchemaConflict) as ex:
            r = Rule(schema={"type": "int", "sequence": [{"type": "str"}]})
        assert ex.value.msg.startswith(
            "scalar.conflict :: sequence"), "Wrong exception was raised"

        with pytest.raises(SchemaConflict) as ex:
            r = Rule(schema={
                "type": "int",
                "mapping": {
                    "foo": {
                        "type": "str"
                    }
                }
            })
        assert ex.value.msg.startswith(
            "scalar.conflict :: mapping"), "Wrong exception was raised"

        with pytest.raises(SchemaConflict) as ex:
            r = Rule(schema={
                "type": "int",
                "enum": [1, 2, 3],
                "range": {
                    "max": 10,
                    "min": 1
                }
            })
        assert ex.value.msg.startswith(
            "enum.conflict :: range"), "Wrong exception was raised"
Пример #28
0
 def test_name_value(self):
     with pytest.raises(RuleError) as r:
         Rule(schema={'type': 'str', 'name': {}})
     assert str(
         r.value
     ) == "<RuleError: error code 4: Value: {} for keyword name must be a string: Path: '/'>"
Пример #29
0
    def _validate_mapping(self, value, rule, path, done=None):
        """
        """
        log.debug(u"Validate mapping")
        log.debug(u" Mapping : Data: %s", value)
        log.debug(u" Mapping : Rule: %s", rule)
        log.debug(u" Mapping : RuleType: %s", rule.type)
        log.debug(u" Mapping : Path: %s", path)
        log.debug(u" Mapping : Seq: %s", rule.sequence)
        log.debug(u" Mapping : Map: %s", rule.mapping)

        if not isinstance(value, dict):
            self.errors.append(SchemaError.SchemaErrorEntry(
                u"Value '{value}' is not a dict. Value path: '{path}'",
                path,
                value,
            ))
            return

        if rule.mapping is None:
            log.debug(u" + No rule to apply, prolly because of allowempty: True")
            return

        # Handle 'func' argument on this mapping
        self._handle_func(value, rule, path, done)

        m = rule.mapping
        log.debug(u"   Mapping: Rule-Mapping: %s", m)

        if rule.range is not None:
            r = rule.range

            self._validate_range(
                r.get("max"),
                r.get("min"),
                r.get("max-ex"),
                r.get("min-ex"),
                len(value),
                path,
                "map",
            )

        for k, rr in m.items():
            # Handle if the value of the key contains a include keyword
            if rr.include_name is not None:
                include_name = rr.include_name
                partial_schema_rule = pykwalify.partial_schemas.get(include_name)

                if not partial_schema_rule:
                    self.errors.append(SchemaError.SchemaErrorEntry(
                        msg=u"Cannot find partial schema with name '{include_name}'. Existing partial schemas: '{existing_schemas}'. Path: '{path}'",
                        path=path,
                        value=value,
                        include_name=include_name,
                        existing_schemas=", ".join(sorted(pykwalify.partial_schemas.keys()))))
                    return

                include_rule = Rule()
                include_rule.mapping = {k: partial_schema_rule}
                include_rule.regex_mappings = []

                return self._validate(value, include_rule, u"{0}".format(path), done)

            # Find out if this is a regex rule
            is_regex_rule = False
            required_regex = ""
            for regex_rule in rule.regex_mappings:
                if k == "regex;({})".format(regex_rule.map_regex_rule) or k == "re;({})".format(regex_rule.map_regex_rule):
                    is_regex_rule = True
                    required_regex = regex_rule.map_regex_rule

            # Check for the presense of the required key
            is_present = False
            if not is_regex_rule:
                is_present = k in value
            else:
                is_present = any([re.search(required_regex, v) for v in value])

            # Specifying =: as key is considered the "default" if no other keys match
            if rr.required and not is_present and k != "=":
                self.errors.append(SchemaError.SchemaErrorEntry(
                    msg=u"Cannot find required key '{key}'. Path: '{path}'",
                    path=path,
                    value=value,
                    key=k))
            if k not in value and rr.default is not None:
                value[k] = rr.default

        for k, v in value.items():
            # If no other case was a match, check if a default mapping is valid/present and use
            # that one instead
            r = m.get(k, m.get('='))
            log.debug(u"  Mapping-value : %s", m)
            log.debug(u"  Mapping-value : %s %s", k, v)
            log.debug(u"  Mapping-value : %s", r)

            regex_mappings = [(regex_rule, re.search(regex_rule.map_regex_rule, str(k))) for regex_rule in rule.regex_mappings]
            log.debug(u"  Mapping-value: Mapping Regex matches: %s", regex_mappings)

            if r is not None:
                # validate recursively
                log.debug(u"  Mapping-value: Core Map: validate recursively: %s", r)
                self._validate(v, r, u"{0}/{1}".format(path, k), done)
            elif any(regex_mappings):
                sub_regex_result = []

                # Found at least one that matches a mapping regex
                for mm in regex_mappings:
                    if mm[1]:
                        log.debug(u"  Mapping-value: Matching regex patter: %s", mm[0])
                        self._validate(v, mm[0], "{0}/{1}".format(path, k), done)
                        sub_regex_result.append(True)
                    else:
                        sub_regex_result.append(False)

                if rule.matching_rule == "any":
                    if any(sub_regex_result):
                        log.debug(u"  Mapping-value: Matched at least one regex")
                    else:
                        log.debug(u"  Mapping-value: No regex matched")
                        self.errors.append(SchemaError.SchemaErrorEntry(
                            msg=u"Key '{key}' does not match any regex '{regex}'. Path: '{path}'",
                            path=path,
                            value=value,
                            key=k,
                            regex="' or '".join(sorted([mm[0].map_regex_rule for mm in regex_mappings]))))
                elif rule.matching_rule == "all":
                    if all(sub_regex_result):
                        log.debug(u"  Mapping-value: Matched all regex rules")
                    else:
                        log.debug(u"  Mapping-value: Did not match all regex rules")
                        self.errors.append(SchemaError.SchemaErrorEntry(
                            msg=u"Key '{key}' does not match all regex '{regex}'. Path: '{path}'",
                            path=path,
                            value=value,
                            key=k,
                            regex="' and '".join(sorted([mm[0].map_regex_rule for mm in regex_mappings]))))
                else:
                    log.debug(u"  Mapping-value: No mapping rule defined")
            else:
                if not rule.allowempty_map:
                    self.errors.append(SchemaError.SchemaErrorEntry(
                        msg=u"Key '{key}' was not defined. Path: '{path}'",
                        path=path,
                        value=value,
                        key=k))
Пример #30
0
 def test_example_value(self):
     with pytest.raises(RuleError) as r:
         Rule(schema={'type': 'str', 'example': []})
     assert str(
         r.value
     ) == "<RuleError: error code 4: Value: [] for keyword example must be a string: Path: '/'>"