-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
conftest.py
84 lines (68 loc) · 3.81 KB
/
conftest.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
from collections import deque
from typing import Any
import pytest
from d8s_file_system import file_read, file_write
from d8s_python import python_function_blocks
from d8s_strings import string_remove_after, string_remove_from_start
FILL_OUTPUT_SIGNAL = 'fill'
FILL_OUTPUT_SIGNAL_IN_CONTEXT = f'== {FILL_OUTPUT_SIGNAL.__repr__()}'
RAISES_OUTPUT_SIGNAL = 'raises'
RAISES_OUTPUT_SIGNAL_IN_CONTEXT = f'== {RAISES_OUTPUT_SIGNAL.__repr__()}'
fill_values = deque()
def pytest_assertrepr_compare(config, op: str, left: object, right: object):
global fill_values
if right == FILL_OUTPUT_SIGNAL:
fill_values.append(left)
pytest.skip(f'{op} {right.__repr__()}')
def _update_test(file_path: str, function_name: str, new_assertion_value: Any) -> bool:
"""Update the test with the given function_name in the file at the given file_path with the new_assertion_value."""
test_file_content = file_read(file_path)
original_function_block = function_block = [
i for i in python_function_blocks(test_file_content) if function_name in i
][0]
function_block = function_block.replace(FILL_OUTPUT_SIGNAL_IN_CONTEXT, f'== {new_assertion_value.__repr__()}', 1)
test_file_content = test_file_content.replace(original_function_block, function_block, 1)
return file_write(file_path, test_file_content)
def _update_test_with_error(file_path: str, function_name: str, error_type: str, erroneous_assertion: str) -> bool:
"""Update the test with the given function_name in the file at the given file_path with the new_assertion_value."""
test_file_content = file_read(file_path)
original_function_block = function_block = [
i for i in python_function_blocks(test_file_content) if function_name in i
][0]
# TODO: currently, the indentation of the new assertion is hard coded; eventually, I would like to get the indentation from the original assertion
new_assertion = f'with pytest.raises({error_type}):\n {erroneous_assertion}'
full_erroneous_assertion = f'assert {erroneous_assertion} == \'{RAISES_OUTPUT_SIGNAL}\''
function_block = function_block.replace(full_erroneous_assertion, new_assertion, 1)
test_file_content = test_file_content.replace(original_function_block, function_block, 1)
return file_write(file_path, test_file_content)
def _get_erroneous_call(report_text: str) -> str:
"""."""
erroneous_line = [
line for line in report_text.splitlines() if line.startswith('> ') and RAISES_OUTPUT_SIGNAL_IN_CONTEXT in line
][0]
erroneous_assertion = erroneous_line.lstrip('> ')
erroneous_assertion = string_remove_from_start(erroneous_assertion, 'assert ')
erroneous_assertion = string_remove_after(erroneous_assertion, ' ==')
erroneous_assertion = erroneous_assertion.rstrip('= ')
return erroneous_assertion
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
global fill_values
# execute all other hooks to obtain the report object
outcome = yield
rep = outcome.get_result()
# we only look at actual failing test calls, not setup/teardown
if rep.when == "call" and rep.skipped:
if fill_values and (FILL_OUTPUT_SIGNAL_IN_CONTEXT in rep.longreprtext):
file_path = rep.fspath
function_name = item.name
new_assertion_value = fill_values.popleft()
_update_test(file_path, function_name, new_assertion_value)
elif rep.when == 'call' and rep.failed:
if RAISES_OUTPUT_SIGNAL_IN_CONTEXT in rep.longreprtext:
print('here!!!')
file_path = rep.fspath
function_name = item.name
error_type = rep.longreprtext.split(" ")[-1]
erroneous_assertion = _get_erroneous_call(rep.longreprtext)
_update_test_with_error(file_path, function_name, error_type, erroneous_assertion)