Last active
September 29, 2023 08:13
-
-
Save weshouman/4803b5ba49c4776a991b357142cf5d73 to your computer and use it in GitHub Desktop.
A python wrapper to show differences using custom tools
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import unittest | |
import tempfile | |
import subprocess | |
# One could use vimdiff, meld, or even diff | |
def diff_with(test_func=None, tool='vimdiff'): | |
# The decorator was used with parentheses | |
# thus the test_func is not set, we need to call it ourself | |
if test_func is None: | |
return functools.partial(diff_with, tool=tool) | |
def diff_to_files(diff_str): | |
lines = diff_str.splitlines() | |
expected_lines = [] | |
actual_lines = [] | |
for line in lines: | |
if line.startswith('+ '): | |
expected_lines.append(line[2:]) | |
elif line.startswith('- '): | |
actual_lines.append(line[2:]) | |
elif line.startswith(' '): # Two spaces for common lines | |
expected_lines.append(line[2:]) | |
actual_lines.append(line[2:]) | |
return expected_lines, actual_lines | |
@functools.wraps(test_func) | |
def wrapper(test_case, *args, **kwargs): | |
# Call the original test function | |
try: | |
result = test_func(test_case, *args, **kwargs) | |
except AssertionError as e: | |
expected_lines, actual_lines = diff_to_files(str(e)) | |
expected = '\n'.join(expected_lines) | |
actual = '\n'.join(actual_lines) | |
with tempfile.NamedTemporaryFile(delete=False, mode='w', suffix='.txt', prefix='expected_') as f1, \ | |
tempfile.NamedTemporaryFile(delete=False, mode='w', suffix='.txt', prefix='actual_') as f2: | |
f1.write(expected) | |
f2.write(actual) | |
f1.flush() | |
f2.flush() | |
# Call the tool to show differences | |
subprocess.run([tool, f1.name, f2.name]) | |
raise # re-raise the original exception | |
return result | |
return wrapper | |
class TestUtilityFunctions(unittest.TestCase): | |
@diff_with # use the default tool defined above | |
def test_failed_default(self): | |
expected = "Hello\nWorld\n" | |
actual = "Hello\nUniverse\n" | |
self.assertEqual(expected, actual) | |
@diff_with(tool='meld') | |
def test_failed_custom(self): | |
expected = "Hello\nAll\n" | |
actual = "Hello\nEveryone\n" | |
self.assertEqual(expected, actual) | |
@diff_with # Should not trigger the diff tool if matched | |
def test_passed(self): | |
expected = "Hello\nWorld\n" | |
actual = "Hello\nWorld\n" | |
self.assertEqual(expected, actual) | |
if __name__ == "__main__": | |
unittest.main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment