Skip to content

Commit

Permalink
feat(): add assert_with_ignore
Browse files Browse the repository at this point in the history
fix(): add compatibility with PY 3.5
  • Loading branch information
LuisFros committed May 7, 2021
1 parent fe2fd80 commit e9d6b51
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 1 deletion.
42 changes: 42 additions & 0 deletions snapshottest/ignore.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import re


def update_path(current_path, key_or_index, is_dict=False):
if is_dict:
if current_path == "":
return key_or_index
return "{}.{}".format(current_path,key_or_index)
else:
return "{}[{}]".format(current_path,key_or_index)


def clear_ignore_keys(data, ignore_keys, current_path=""):
if isinstance(data, dict):
for key, value in data.items():
temp_path = update_path(current_path, key, is_dict=True)
matched = match_ignored_key(key, data, ignore_keys, temp_path)
if not matched:
data[key] = clear_ignore_keys(value, ignore_keys, temp_path)
return data
elif isinstance(data, list):
for index, value in enumerate(data):
temp_path = update_path(current_path, index)
matched = match_ignored_key(index, data, ignore_keys, temp_path)
if not matched:
data[index] = clear_ignore_keys(value, ignore_keys, temp_path)
return data
elif isinstance(data, tuple):
return tuple(
clear_ignore_keys(value, ignore_keys, update_path(current_path, index))
for index, value in enumerate(data)
)
return data


def match_ignored_key(key_or_index, data, ignore_keys, temp_path):
for ignored in ignore_keys:
escaped = ignored.translate(str.maketrans({"[": r"\[", "]": r"\]"}))
if re.match("{}$".format(escaped), temp_path):
data[key_or_index] = None
return True
return False
56 changes: 56 additions & 0 deletions snapshottest/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .snapshot import Snapshot
from .formatter import Formatter
from .error import SnapshotNotFound
from .ignore import clear_ignore_keys


logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -266,6 +267,61 @@ def assert_match(self, value, name=""):
if not name:
self.snapshot_counter += 1

def assert_match_with_ignore(self, data, ignore_keys):
"""Extension of assert_match to ignore data.
Args:
data (dict,list,tuple): Data to be asserted
ignored_keys (list): List of strings containing path to be ignored,
special character "[.]" can be used to ignore multiple elements in list.
(See Example 2)
Returns:
None: Asserts if the values are the same
Raises:
AssertionError: If the snapshot is different than the incoming data
Examples:
Test examples at: apps/tests/utils/test_asserts.py
Example 1:
>>> data={"dict1": {"dict2": {"dict3": {"id": "importantId"} } } }
>>> ignore_keys=["dict1.dict2.dict3.id"]
>>> assert_match_with_ignore(data,ignore_keys)
# Will create the following snapshot
snapshots['example_snapshot'] = {
'dict1': {
'dict2': {
'dict3': {
'id': None,
'other': 'value'
}
}
}
}
---
Example 2:
>>> data=[
{
"name": "objectList",
"children": [
{"id": "random_string", "name": "child_1",},
{"id": "random_string2", "name": "child_2",},
],
}
]
>>> ignore_keys=["[0].children[.].id"]
>>> assert_match_with_ignore(data,ignore_keys)
# Will create the following snapshot
snapshots['example2_snapshot'] = [
{
"name": "objectList",
"children": [
{"id": None, "name": "child_1",},
{"id": None, "name": "child_2",},
],
}
]
"""

self.assert_match(clear_ignore_keys(data, ignore_keys))

def save_changes(self):
self.module.save()

Expand Down
27 changes: 27 additions & 0 deletions tests/test_ignore.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from time import time
from snapshottest.ignore import clear_ignore_keys

DATA = {
"name": {
"id": time(),
"first": "Manual",
"last": "gonazales",
"cities": ["1", "2", {"id": time()}],
}
}

DATA_EXPECTED = {
"name": {
"id": None,
"first": "Manual",
"last": "gonazales",
"cities": [None, "2", {"id": None}],
}
}


def test_clear_works():
clean_data = clear_ignore_keys(
DATA, ignore_keys=["name.id", "name.cities[0]", "name.cities[2].id"]
)
assert clean_data == DATA_EXPECTED
75 changes: 74 additions & 1 deletion tests/test_snapshot_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest
from collections import OrderedDict

from time import time
from snapshottest.module import SnapshotModule, SnapshotTest


Expand Down Expand Up @@ -121,3 +121,76 @@ def test_snapshot_does_not_match_other_values(snapshot_test, value, other_value)
with pytest.raises(AssertionError):
snapshot_test.assert_match(other_value)
assert_snapshot_test_failed(snapshot_test)


SNAPSHOTABLE_VALUES_WITH_IGNORE = [
{
"data": {"dict1": {"dict2": {"dict3": {"id": time(), "other": "value"}}}},
"ignore_keys": ["dict1.dict2.dict3.id"],
},
{
"data": [
{
"A": {
"id": time(),
"B": 1,
"C": 2,
"D": [0, 1, {"A": 1}],
}
},
{
"A": {
"id": time(),
"B": 2,
"C": 3,
"D": [0, 1, {"id": time()}],
}
},
],
"ignore_keys": ["[.].A.id", "[1].A.C[.].id"],
},
{
"data": {
"A": {
"id": [0, 1, 2, 3, time()],
"A": 1,
"B": 2,
"C": [
{"id": time()},
{"id": time(), "A": 0},
{"id": time()},
],
}
},
"ignore_keys": ["A.C[.].id", "A.id[4]"],
},
{
"data": {
"A": {
"A": {
"id": time(),
"A": 1,
"B": 2,
"C": 3,
"D": [
{"id": [0, time()]},
{"id": {"A": [time()]}, "B": 0},
{"id": time()},
],
}
}
},
"ignore_keys": ["A.A.id", "A.A.D.id[1]", "A.A.D.id.A[0"],
},
]


@pytest.mark.parametrize("values", SNAPSHOTABLE_VALUES_WITH_IGNORE, ids=repr)
def test_snapshot_with_ignore(snapshot_test, values):
data = values["data"]
ignore_keys = values["ignore_keys"]
snapshot_test.assert_match_with_ignore(data, ignore_keys)

snapshot_test.reinitialize()
snapshot_test.assert_match_with_ignore(data, ignore_keys)
assert_snapshot_test_succeeded(snapshot_test)

0 comments on commit e9d6b51

Please sign in to comment.