Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ENH TEST] Improve compare_folders error message #918

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 78 additions & 11 deletions test/nonregression/testing_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,27 +227,94 @@ def same_missing_modality_tsv(file1: PathLike, file2: PathLike) -> bool:
return mods[0] == mods[1]


def compare_folders(outdir: PathLike, refdir: PathLike, tmp_path: PathLike) -> bool:
def compare_folders(
output_dir: PathLike, reference_dir: PathLike, tmp_path: PathLike
) -> bool:
"""Compare the contents of the two input folders `output_dir` and `reference_dir`.

Parameters
----------
output_dir : PathLike
Path to the first folder to be compared.

reference_dir : PathLike
Path to the second folder to be compared.

tmp_path : PathLike
Path to a location where the files containing the trees will be written.

Returns
-------
bool :
True if the folders have the same files, under the same sub-folders.

Raises
------
ValueError :
If the folders have some differences. These differences will be
made explicit in the error message.
"""
from filecmp import cmp
from pathlib import PurePath

file_out = PurePath(tmp_path) / "file_out.txt"
file_ref = PurePath(tmp_path) / "file_ref.txt"
tree(outdir, file_out)
tree(refdir, file_ref)

tree(output_dir, file_out)
tree(reference_dir, file_ref)

if not cmp(file_out, file_ref):
with open(file_out, "r") as fin:
out_message = fin.read()
with open(file_ref, "r") as fin:
ref_message = fin.read()
raise ValueError(
"Comparison of out and ref directories shows mismatch :\n "
"OUT :\n" + out_message + "\n REF :\n" + ref_message
)
raise ValueError(_build_tree_mismatch_error_message(file_out, file_ref))

return True


def _build_tree_mismatch_error_message(file_out: PathLike, file_ref: PathLike) -> str:
"""Build the error message when two trees differ.

The message gives the content of each tree as well and highlights
the differences between them.
"""
with open(file_out, "r") as fin:
out_message = fin.read()
with open(file_ref, "r") as fin:
ref_message = fin.read()
lines_in_out = out_message.strip().split("\n")
lines_in_ref = ref_message.strip().split("\n")
lines_with_differences = [
(line_out, line_ref)
for line_out, line_ref in zip(lines_in_out, lines_in_ref)
if line_out != line_ref
]

return (
"Comparison of out and ref directories shows mismatch :\n "
f"The content of the OUT directory :\n{out_message}\n "
f"The content of the REF directory :\n{ref_message}\n "
f"There are {len(lines_with_differences)} lines with "
f"a mismatch :\n{_format_line_differences(lines_with_differences)}"
)


def _format_line_differences(lines: list) -> str:
"""Format the differences between two printed trees for error messaging."""
msg = ""
for line in lines:
left, right = line
msg += f"\t- {_format_tree_line(left)} != {_format_tree_line(right)}\n"

return msg


def _format_tree_line(line: str) -> str:
"""Format a line of the printed tree for error messaging."""
line = line.strip()
if line.startswith("+ "):
line = line.lstrip("+ ")

return line


def tree(dir_: PathLike, file_out: PathLike):
"""Creates a file (file_out) with a visual tree representing the file
hierarchy at a given directory
Expand Down
106 changes: 106 additions & 0 deletions test/unittests/test_testing_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,109 @@ def test_compare_folders_structures(
shutil.rmtree(tmp_path / "sub-02")
with pytest.raises(ValueError, match="/sub-02/bar.tsv not found !"):
compare_func(str(tmp_path), str(tmp_path / "hashes.pl"))


def test_compare_folders_empty(tmp_path):
from test.nonregression.testing_tools import compare_folders

dir1 = tmp_path / "folder1"
dir1.mkdir()
dir2 = tmp_path / "folder2"
dir2.mkdir()

assert compare_folders(dir1, dir2, tmp_path)


def test_compare_folders_empty_nested(tmp_path):
from test.nonregression.testing_tools import compare_folders

dir1 = tmp_path / "folder1" / "subfolder1"
dir1.mkdir(parents=True)
dir2 = tmp_path / "folder2" / "subfolder2"
dir2.mkdir(parents=True)

assert compare_folders(tmp_path / "folder1", tmp_path / "folder2", tmp_path)


def test_compare_folders(tmp_path):
from test.nonregression.testing_tools import compare_folders

dir1 = tmp_path / "folder1"
dir1.mkdir()
dir2 = tmp_path / "folder2"
dir2.mkdir()
(dir1 / "file1.txt").touch()
(dir2 / "file1.txt").touch()

assert compare_folders(dir1, dir2, tmp_path)


def test_compare_folders_errors(tmp_path):
from test.nonregression.testing_tools import compare_folders

dir1 = tmp_path / "folder1" / "subfolder1"
dir1.mkdir(parents=True)
dir2 = tmp_path / "folder2" / "subfolder2"
dir2.mkdir(parents=True)
(dir1 / "file2.txt").touch()
(dir2 / "file2.txt").touch()

assert compare_folders(dir1, dir2, tmp_path)

with pytest.raises(
ValueError,
match="- subfolder1 != subfolder2",
):
compare_folders(tmp_path / "folder1", tmp_path / "folder2", tmp_path)


def test_compare_folders_multiple_mismatches(tmp_path):
"""Test compare_folders with a more complex diff.

The full expected error message :

E ValueError: Comparison of out and ref directories shows mismatch :
E The content of the OUT directory :
E + subfolder1
E + file1.txt
E + subfolder2
E + file2.xt
E + subfolder3
E + file3.xt
E
E The content of the REF directory :
E + subfolder1
E + file1.txt
E + subfolder3
E + file4.xt
E + subfolder4
E + file2.xt
E
E There are 4 lines with a mismatch :
E - subfolder2 != subfolder3
E - file2.xt != file4.xt
E - subfolder3 != subfolder4
E - file3.xt != file2.xt
"""
from test.nonregression.testing_tools import compare_folders

dir1 = tmp_path / "folder1"
dir1.mkdir()
dir2 = tmp_path / "folder2"
dir2.mkdir()
for sub in (1, 2, 3):
(dir1 / f"subfolder{sub}").mkdir()
for sub in (1, 3, 4):
(dir2 / f"subfolder{sub}").mkdir()
(dir1 / "subfolder1" / "file1.txt").touch()
(dir2 / "subfolder1" / "file1.txt").touch()
(dir1 / "subfolder2" / "file2.xt").touch()
(dir2 / "subfolder4" / "file2.xt").touch()
(dir1 / "subfolder3" / "file3.xt").touch()
(dir2 / "subfolder3" / "file4.xt").touch()

with pytest.raises(
ValueError,
match="There are 4 lines with a mismatch",
):
compare_folders(dir1, dir2, tmp_path)
Loading