Skip to content

Commit 454cb78

Browse files
committed
add tests for dpath validator
1 parent 41f376b commit 454cb78

File tree

2 files changed

+116
-8
lines changed

2 files changed

+116
-8
lines changed

airbyte_cdk/sources/declarative/validators/dpath_validator.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,27 @@ def validate(self, input_data: dict[str, Any]) -> None:
3939
:param input_data: Dictionary containing the data to validate
4040
:raises ValueError: If the path doesn't exist or validation fails
4141
"""
42-
try:
43-
path = [path.eval(input_data) for path in self._field_path]
44-
value = dpath.util.get(input_data, path)
45-
self.strategy.validate(value)
46-
except KeyError:
47-
raise ValueError(f"Path '{self.field_path}' not found in the input data")
48-
except Exception as e:
49-
raise ValueError(f"Error validating path '{self.field_path}': {e}")
42+
path = [path.eval({}) for path in self._field_path]
43+
44+
if len(path) == 0:
45+
raise ValueError("Field path is empty")
46+
47+
if "*" in path:
48+
try:
49+
values = dpath.values(input_data, path)
50+
except KeyError as e:
51+
raise KeyError(f"Error validating path '{self.field_path}': {e}")
52+
for value in values:
53+
try:
54+
self.strategy.validate(value)
55+
except Exception as e:
56+
raise ValueError(f"Error validating value '{value}': {e}")
57+
else:
58+
try:
59+
value = dpath.get(input_data, path)
60+
except KeyError as e:
61+
raise KeyError(f"Error validating path '{self.field_path}': {e}")
62+
try:
63+
self.strategy.validate(value)
64+
except Exception as e:
65+
raise ValueError(f"Error validating value '{value}': {e}")
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import pytest
2+
from unittest import TestCase
3+
4+
from airbyte_cdk.sources.declarative.validators.dpath_validator import DpathValidator
5+
from airbyte_cdk.sources.declarative.validators.validation_strategy import ValidationStrategy
6+
7+
8+
class MockValidationStrategy(ValidationStrategy):
9+
def __init__(self, should_fail=False, error_message="Validation failed"):
10+
self.should_fail = should_fail
11+
self.error_message = error_message
12+
self.validate_called = False
13+
self.validated_value = None
14+
15+
def validate(self, value):
16+
self.validate_called = True
17+
self.validated_value = value
18+
if self.should_fail:
19+
raise ValueError(self.error_message)
20+
21+
22+
class TestDpathValidator(TestCase):
23+
def test_given_valid_path_and_input_validate_is_successful(self):
24+
strategy = MockValidationStrategy()
25+
validator = DpathValidator(field_path=["user", "profile", "email"], strategy=strategy)
26+
27+
test_data = {"user": {"profile": {"email": "[email protected]", "name": "Test User"}}}
28+
29+
validator.validate(test_data)
30+
31+
assert strategy.validate_called
32+
assert strategy.validated_value
33+
34+
def test_given_invalid_path_when_validate_then_raise_key_error(self):
35+
strategy = MockValidationStrategy()
36+
validator = DpathValidator(field_path=["user", "profile", "phone"], strategy=strategy)
37+
38+
test_data = {"user": {"profile": {"email": "[email protected]"}}}
39+
40+
with pytest.raises(KeyError) as context:
41+
validator.validate(test_data)
42+
assert "Error validating path" in str(context.exception)
43+
assert not strategy.validate_called
44+
45+
def test_given_strategy_fails_when_validate_then_raise_value_error(self):
46+
error_message = "Invalid email format"
47+
strategy = MockValidationStrategy(should_fail=True, error_message=error_message)
48+
validator = DpathValidator(field_path=["user", "email"], strategy=strategy)
49+
50+
test_data = {"user": {"email": "invalid-email"}}
51+
52+
with pytest.raises(ValueError) as context:
53+
validator.validate(test_data)
54+
55+
assert "Error validating value" in str(context.exception)
56+
assert error_message in str(context.exception)
57+
assert strategy.validate_called
58+
assert strategy.validated_value == "invalid-email"
59+
60+
def test_given_empty_path_list_when_validate_then_validate_raises_exception(self):
61+
strategy = MockValidationStrategy()
62+
validator = DpathValidator(field_path=[], strategy=strategy)
63+
test_data = {"key": "value"}
64+
65+
with pytest.raises(ValueError):
66+
validator.validate(test_data)
67+
68+
def test_given_empty_input_data_when_validate_then_validate_raises_exception(self):
69+
strategy = MockValidationStrategy()
70+
validator = DpathValidator(field_path=["data", "field"], strategy=strategy)
71+
72+
test_data = {}
73+
74+
with pytest.raises(KeyError):
75+
validator.validate(test_data)
76+
77+
def test_path_with_wildcard_when_validate_then_validate_is_successful(self):
78+
strategy = MockValidationStrategy()
79+
validator = DpathValidator(field_path=["users", "*", "email"], strategy=strategy)
80+
81+
test_data = {
82+
"users": {
83+
"user1": {"email": "[email protected]", "name": "User One"},
84+
"user2": {"email": "[email protected]", "name": "User Two"},
85+
}
86+
}
87+
88+
validator.validate(test_data)
89+
90+
assert strategy.validate_called
91+
assert strategy.validated_value in ["[email protected]", "[email protected]"]
92+
self.assertIn(strategy.validated_value, ["[email protected]", "[email protected]"])

0 commit comments

Comments
 (0)