Skip to content

Commit

Permalink
fix: yaml multiline string should be read successfully (#62)
Browse files Browse the repository at this point in the history
* fix: yaml multiline string should be read successfully

* wip: more string tests

* fix: support empty snapshot

* refactor: protected not private  method

* revert: 0331796

oops meant to do the opposite

Co-authored-by: Emmanuel Ogbizi <[email protected]>
  • Loading branch information
Noah and iamogbz authored Dec 27, 2019
1 parent a15276c commit 868164a
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 60 deletions.
15 changes: 7 additions & 8 deletions src/syrupy/serializers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,13 @@ def create_or_update_snapshot(self, data: "SerializableData", index: int) -> Non
self.write(data, index=index)
self.post_write(data, index=index)

@final
@abstractmethod
def delete_snapshot_from_file(self, snapshot_file: str, snapshot_name: str) -> None:
"""
Utility method for removing a snapshot from a snapshot file.
Remove a snapshot from a snapshot file.
If the snapshot file will be empty remove the entire file.
"""
self._write_snapshot_or_remove_file(snapshot_file, snapshot_name, None)
raise NotImplementedError

def pre_read(self, index: int = 0) -> None:
pass
Expand All @@ -119,7 +120,7 @@ def pre_write(self, data: "SerializableData", index: int = 0) -> None:
@final
def write(self, data: "SerializableData", index: int = 0) -> None:
"""
Override `_write_snapshot_or_remove_file` in subclass to change behaviour
Override `_write_snapshot_to_file` in subclass to change behaviour
"""
snapshot_file = self.get_filepath(index)
snapshot_name = self.get_snapshot_name(index)
Expand All @@ -129,7 +130,7 @@ def write(self, data: "SerializableData", index: int = 0) -> None:
f" '{self.test_location.testname}'"
)
warnings.warn(warning_msg)
self._write_snapshot_or_remove_file(snapshot_file, snapshot_name, data)
self._write_snapshot_to_file(snapshot_file, snapshot_name, data)

def post_write(self, data: "SerializableData", index: int = 0) -> None:
pass
Expand Down Expand Up @@ -170,12 +171,10 @@ def _read_snapshot_from_file(
raise NotImplementedError

@abstractmethod
def _write_snapshot_or_remove_file(
def _write_snapshot_to_file(
self, snapshot_file: str, snapshot_name: str, data: "SerializableData"
) -> None:
"""
Adds the snapshot data to the snapshots read from the file
or removes the snapshot entry if data is `None`.
If the snapshot file will be empty remove the entire file.
"""
raise NotImplementedError
10 changes: 5 additions & 5 deletions src/syrupy/serializers/raw_single.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ def _read_file(self, filepath: str) -> Any:
except FileNotFoundError:
return None

def _write_snapshot_or_remove_file(
def _write_snapshot_to_file(
self, snapshot_file: str, snapshot_name: str, data: "SerializableData"
) -> None:
if data:
self.__write_file(snapshot_file, data)
else:
os.remove(snapshot_file)
self.__write_file(snapshot_file, data)

def delete_snapshot_from_file(self, snapshot_file: str, snapshot_name: str) -> None:
os.remove(snapshot_file)

def __write_file(self, filepath: str, data: "SerializableData") -> None:
with open(filepath, "wb") as f:
Expand Down
28 changes: 13 additions & 15 deletions src/syrupy/serializers/yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,18 @@ def _read_snapshot_from_file(
raw_snapshots = self._read_raw_file(snapshot_file)
return raw_snapshots.get(snapshot_name, None)

def _write_snapshot_or_remove_file(
def _write_snapshot_to_file(
self, snapshot_file: str, snapshot_name: str, data: "SerializableData"
) -> None:
"""
Adds the snapshot data to the snapshots read from the file
or removes the snapshot entry if data is `None`.
If the snapshot file will be empty remove the entire file.
"""
snapshots = self._read_file(snapshot_file)
if data is None and snapshot_name in snapshots:
snapshots = self.__read_file(snapshot_file)
snapshots[snapshot_name] = snapshots.get(snapshot_name, {})
snapshots[snapshot_name][self._data_key] = data
self.__write_file(snapshot_file, snapshots)

def delete_snapshot_from_file(self, snapshot_file: str, snapshot_name: str) -> None:
snapshots = self.__read_file(snapshot_file)
if snapshot_name in snapshots:
del snapshots[snapshot_name]
else:
snapshots[snapshot_name] = snapshots.get(snapshot_name, {})
snapshots[snapshot_name][self._data_key] = data

if snapshots:
self.__write_file(snapshot_file, snapshots)
Expand All @@ -67,7 +65,7 @@ def __write_file(self, filepath: str, data: "SerializableData") -> None:
with open(filepath, "w") as f:
yaml.dump(data, f, allow_unicode=True)

def _read_file(self, filepath: str) -> Any:
def __read_file(self, filepath: str) -> Any:
"""
Read the snapshot data from the snapshot file into a python instance.
"""
Expand All @@ -89,12 +87,12 @@ def _read_raw_file(self, filepath: str) -> Dict[str, str]:
with open(filepath, "r") as f:
test_name = None
for line in f:
indent = len(line) - len(line.lstrip(" "))
if not indent:
if line[0] not in (" ", "\n") and line[-2] == ":":
test_name = line[:-2] # newline & colon
snapshots[test_name] = ""
elif test_name is not None:
snapshots[test_name] += line[2:]
offset = min(len(line) - 1, 2)
snapshots[test_name] += line[offset:]
except FileNotFoundError:
pass

Expand Down
5 changes: 0 additions & 5 deletions src/syrupy/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,6 @@ def remove_unused_snapshots(
self._serializers[snapshot_file].delete_snapshot_from_file(
snapshot_file, snapshot_name
)
if (
os.path.exists(snapshot_file)
and snapshot_file not in used_snapshot_files
):
os.remove(snapshot_file)

def _collate_snapshots(self) -> None:
"""
Expand Down
40 changes: 28 additions & 12 deletions tests/__snapshots__/test_snapshots.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,40 +18,56 @@ test_dict[actual1]:
d:
- '1'
- 2
test_empty_snapshot:
data: null
test_empty_snapshot.1:
data: ''
test_multiple_snapshots:
data: First.
test_multiple_snapshots.1:
data: Second.
test_multiple_snapshots.2:
data: Third.
test_parametrized_with_special_char[Backslash \\u U]:
data: Backslash \u U
test_parametrized_with_special_char[Escaped \\n]:
data: Escaped \n
test_raw_string:
data: Raw string
test_set:
data: !!set
a: null
is: null
set: null
this: null
test_simple_string:
data: Loreeeeeem ipsum.
test_tuples:
test_string[0]:
data: ''
test_string[1]:
data: Raw string
test_string[2]:
data: Escaped \n
test_string[3]:
data: Backslash \u U
test_string[4]:
data: πŸ₯žπŸπŸ―
test_string[5]:
data: 'singleline:'
test_string[6]:
data: '- singleline'
test_string[7]:
data: 'multi-line
line 2
line 3'
test_string[8]:
data: "multi-line\nline 2\n line 3"
test_tuple:
data: !!python/tuple
- this
- is
- !!python/tuple
- a
- tuple
test_tuples.1:
test_tuple.1:
data: !!python/object/new:tests.test_snapshots.ExampleTuple
- this
- is
- a
- !!set
named: null
tuple: null
test_unicode_string:
data: πŸ₯žπŸπŸ―
5 changes: 4 additions & 1 deletion tests/test_plugin_custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ def get_snapshot_name(self, index = 0):
def _read_snapshot_from_file(self, file, name):
pass
def _write_snapshot_or_remove_file(self, file, name, data):
def _write_snapshot_to_file(self, file, name, data):
pass
def delete_snapshot_from_file(self, file, name):
pass
Expand Down
35 changes: 21 additions & 14 deletions tests/test_snapshots.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,28 @@ def test_non_snapshots(snapshot):
assert "Lorem ipsum." == "Muspi merol."


def test_simple_string(snapshot):
assert "Loreeeeeem ipsum." == snapshot
def test_empty_snapshot(snapshot):
assert snapshot == None # noqa: E711
assert snapshot == ""


def test_raw_string(snapshot):
assert r"Raw string" == snapshot


def test_unicode_string(snapshot):
assert "πŸ₯žπŸπŸ―" == snapshot
@pytest.mark.parametrize(
"actual",
[
"",
r"Raw string",
r"Escaped \n",
r"Backslash \u U",
"πŸ₯žπŸπŸ―",
"singleline:",
"- singleline",
"multi-line\nline 2\nline 3",
"multi-line\nline 2\n line 3",
],
ids=lambda x: "",
)
def test_string(snapshot, actual):
assert snapshot == actual


def test_multiple_snapshots(snapshot):
Expand All @@ -26,11 +38,6 @@ def test_multiple_snapshots(snapshot):
snapshot("Third.")


@pytest.mark.parametrize("expected", [r"Escaped \n", r"Backslash \u U"])
def test_parametrized_with_special_char(snapshot, expected):
assert expected == snapshot


@pytest.mark.parametrize(
"actual",
[
Expand All @@ -49,7 +56,7 @@ def test_set(snapshot):
ExampleTuple = namedtuple("ExampleTuple", ["a", "b", "c", "d"])


def test_tuples(snapshot):
def test_tuple(snapshot):
assert snapshot == ("this", "is", ("a", "tuple"))
assert snapshot == ExampleTuple(a="this", b="is", c="a", d={"named", "tuple"})

Expand Down

0 comments on commit 868164a

Please sign in to comment.