Skip to content

Commit

Permalink
Merge pull request #37 from joseph-roitman/unsupported-values-error
Browse files Browse the repository at this point in the history
Useful unsupported values errors
  • Loading branch information
joseph-roitman authored Sep 13, 2021
2 parents 33f208e + 327f662 commit e0a0329
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 9 deletions.
28 changes: 19 additions & 9 deletions pytest_snapshot/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ def _file_encode(string: str) -> bytes:
Returns the bytes that would be in a file created using ``path.write_text(string)``.
See universal newlines documentation.
"""
if '\r' in string:
raise ValueError('''\
Snapshot testing strings containing "\\r" is not supported.
To snapshot test non-standard newlines you should convert the tested value to bytes.
Warning: git may decide to modify the newlines in the snapshot file.
To avoid this read \
https://docs.github.com/en/get-started/getting-started-with-git/configuring-git-to-handle-line-endings''')

return string.replace('\n', os.linesep).encode()


Expand Down Expand Up @@ -153,25 +161,27 @@ def assert_match(self, value: Union[str, bytes], snapshot_name: Union[str, Path]

if snapshot_path.is_file():
encoded_expected_value = snapshot_path.read_bytes()
expected_value = decode(encoded_expected_value)
elif snapshot_path.exists():
raise AssertionError('snapshot exists but is not a file: {}'.format(shorten_path(snapshot_path)))
else:
encoded_expected_value = None
expected_value = None

if self._snapshot_update:
encoded_value = encode(value)
snapshot_path.parent.mkdir(parents=True, exist_ok=True)
if encoded_expected_value is not None:
if encoded_expected_value != encoded_value:
snapshot_path.write_bytes(encoded_value)
self._updated_snapshots.append(snapshot_path)
else:
if encoded_expected_value is None or encoded_value != encoded_expected_value:
decoded_encoded_value = decode(encoded_value)
if decoded_encoded_value != value:
raise ValueError("value is not supported by pytest-snapshot's serializer.")

snapshot_path.parent.mkdir(parents=True, exist_ok=True)
snapshot_path.write_bytes(encoded_value)
self._created_snapshots.append(snapshot_path)
if encoded_expected_value is None:
self._created_snapshots.append(snapshot_path)
else:
self._updated_snapshots.append(snapshot_path)
else:
if encoded_expected_value is not None:
expected_value = decode(encoded_expected_value)
try:
compare(value, expected_value)
except AssertionError as e:
Expand Down
77 changes: 77 additions & 0 deletions tests/test_assert_match.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import pytest

from pytest_snapshot.plugin import _file_encode
from tests.utils import assert_pytest_passes


Expand Down Expand Up @@ -301,3 +302,79 @@ def test_sth(snapshot):
assert encoded_snapshot == expected_encoded_snapshot

assert_pytest_passes(testdir) # assert that snapshot update worked


def test_assert_match_unsupported_value_existing_snapshot(testdir, basic_case_dir):
"""
Test that when running tests without --snapshot-update, we don't tell the user that the value is unsupported.
We instead tell the user that the value does not equal the snapshot. This behaviour is more helpful.
"""
basic_case_dir.join('newline.txt').write_binary(_file_encode('\n'))
testdir.makepyfile(r"""
def test_sth(snapshot):
snapshot.snapshot_dir = 'case_dir'
snapshot.assert_match('\r', 'newline.txt')
""")
result = testdir.runpytest('-v')
result.stdout.fnmatch_lines([
'*::test_sth FAILED*',
'E* AssertionError: value does not match the expected value in snapshot case_dir?newline.txt',
"E* - '\\n'",
"E* + '\\r'",
])
assert result.ret == 1


def test_assert_match_unsupported_value_update_existing_snapshot(testdir, basic_case_dir):
basic_case_dir.join('newline.txt').write_binary(_file_encode('\n'))
testdir.makepyfile(r"""
import os
from unittest import mock
def _file_encode(string: str) -> bytes:
return string.replace('\n', os.linesep).encode()
def test_sth(snapshot):
snapshot.snapshot_dir = 'case_dir'
with mock.patch('pytest_snapshot.plugin._file_encode', _file_encode):
snapshot.assert_match('\r', 'newline.txt')
""")
result = testdir.runpytest('-v', '--snapshot-update')
result.stdout.fnmatch_lines([
'*::test_sth FAILED*',
"E* ValueError: value is not supported by pytest-snapshot's serializer.",
])
assert result.ret == 1


def test_assert_match_unsupported_value_create_snapshot(testdir, basic_case_dir):
testdir.makepyfile(r"""
import os
from unittest import mock
def _file_encode(string: str) -> bytes:
return string.replace('\n', os.linesep).encode()
def test_sth(snapshot):
snapshot.snapshot_dir = 'case_dir'
with mock.patch('pytest_snapshot.plugin._file_encode', _file_encode):
snapshot.assert_match('\r', 'newline.txt')
""")
result = testdir.runpytest('-v', '--snapshot-update')
result.stdout.fnmatch_lines([
'*::test_sth FAILED*',
"E* ValueError: value is not supported by pytest-snapshot's serializer.",
])
assert result.ret == 1


def test_assert_match_unsupported_value_slash_r(testdir, basic_case_dir):
testdir.makepyfile(r"""
def test_sth(snapshot):
snapshot.snapshot_dir = 'case_dir'
snapshot.assert_match('\r', 'newline.txt')
""")
result = testdir.runpytest('-v', '--snapshot-update')
result.stdout.fnmatch_lines([
'*::test_sth FAILED*',
'E* ValueError: Snapshot testing strings containing "\\r" is not supported.'
])
assert result.ret == 1

0 comments on commit e0a0329

Please sign in to comment.