Skip to content

Commit 70bd38d

Browse files
authored
Merge pull request #122 from lguerard/fix/119-listdir-matching-tests
Add tests for `pathtools.listdir_matching`
2 parents ad505f8 + a10dfbb commit 70bd38d

2 files changed

Lines changed: 224 additions & 9 deletions

File tree

src/imcflibs/pathtools.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,9 @@ def listdir_matching(
231231
if not regex_compiled:
232232
if candidate.lower().endswith(suffix.lower()):
233233
if fullpath:
234-
matching_files.append(os.path.join(dirpath, candidate))
234+
matching_files.append(
235+
os.path.abspath(os.path.join(dirpath, candidate))
236+
)
235237
else:
236238
rel = os.path.relpath(
237239
os.path.join(dirpath, candidate), path
@@ -240,7 +242,9 @@ def listdir_matching(
240242
else:
241243
if regex_compiled.match(candidate):
242244
if fullpath:
243-
matching_files.append(os.path.join(dirpath, candidate))
245+
matching_files.append(
246+
os.path.abspath(os.path.join(dirpath, candidate))
247+
)
244248
else:
245249
rel = os.path.relpath(
246250
os.path.join(dirpath, candidate), path
@@ -252,13 +256,17 @@ def listdir_matching(
252256
if not regex_compiled:
253257
if candidate.lower().endswith(suffix.lower()):
254258
if fullpath:
255-
matching_files.append(os.path.join(path, candidate))
259+
matching_files.append(
260+
os.path.abspath(os.path.join(path, candidate))
261+
)
256262
else:
257263
matching_files.append(candidate)
258264
else:
259265
if regex_compiled.match(candidate):
260266
if fullpath:
261-
matching_files.append(os.path.join(path, candidate))
267+
matching_files.append(
268+
os.path.abspath(os.path.join(path, candidate))
269+
)
262270
else:
263271
matching_files.append(candidate)
264272

tests/test_pathtools.py

Lines changed: 212 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
"""Tests for `imcflibs.pathtools`."""
22
# -*- coding: utf-8 -*-
33

4-
from imcflibs.pathtools import parse_path
5-
from imcflibs.pathtools import jython_fiji_exists
6-
from imcflibs.pathtools import image_basename
7-
from imcflibs.pathtools import gen_name_from_orig
8-
from imcflibs.pathtools import derive_out_dir
4+
import os
5+
6+
from imcflibs.pathtools import (
7+
create_directory,
8+
derive_out_dir,
9+
find_dirs_containing_filetype,
10+
folder_size,
11+
gen_name_from_orig,
12+
image_basename,
13+
join2,
14+
join_files_with_channel_suffix,
15+
jython_fiji_exists,
16+
listdir_matching,
17+
parse_path,
18+
)
919

1020

1121
def test_parse_path():
@@ -114,3 +124,200 @@ def test_derive_out_dir():
114124
assert derive_out_dir("/foo", "none") == "/foo"
115125
assert derive_out_dir("/foo", "NONE") == "/foo"
116126
assert derive_out_dir("/foo", "/bar") == "/bar"
127+
128+
129+
def test_listdir_matching_various(tmpdir):
130+
"""Test non-recursive, recursive, fullpath, regex and sorting behaviour."""
131+
base = tmpdir.mkdir("base")
132+
133+
# create mixed files
134+
base.join("a.TIF").write("x")
135+
base.join("b.tif").write("x")
136+
base.join("c.png").write("x")
137+
138+
# non-recursive, suffix match (case-insensitive)
139+
res = listdir_matching(str(base), ".tif")
140+
assert set(res) == {"a.TIF", "b.tif"}
141+
142+
# fullpath returns absolute paths
143+
res_full = listdir_matching(str(base), ".tif", fullpath=True)
144+
assert all(os.path.isabs(x) for x in res_full)
145+
assert os.path.join(str(base), "a.TIF") in res_full
146+
assert os.path.join(str(base), "b.tif") in res_full
147+
148+
# recursive with relative paths
149+
sub = base.mkdir("sub")
150+
sub.join("s.TIF").write("x")
151+
res_rec = listdir_matching(str(base), ".tif", recursive=True)
152+
# should include the file from subdir as a relative path
153+
assert "sub/s.TIF" in [p.replace(os.sep, "/") for p in res_rec]
154+
155+
# recursive with fullpath
156+
res_rec_full = listdir_matching(str(base), ".tif", recursive=True, fullpath=True)
157+
assert all(os.path.isabs(x) for x in res_rec_full)
158+
assert os.path.join(str(sub), "s.TIF") in res_rec_full
159+
160+
# regex matching
161+
res_regex = listdir_matching(str(base), r".*\.tif$", regex=True)
162+
assert set(res_regex) >= {"a.TIF", "b.tif"}
163+
164+
# sorting: create names that sort differently lexicographically
165+
base.join("img2.tif").write("x")
166+
base.join("img10.tif").write("x")
167+
base.join("img1.tif").write("x")
168+
res_sorted = listdir_matching(str(base), ".tif", sort=True)
169+
# expected alphanumeric order
170+
assert res_sorted.index("img1.tif") < res_sorted.index("img2.tif")
171+
assert res_sorted.index("img2.tif") < res_sorted.index("img10.tif")
172+
173+
174+
def test_listdir_matching_invalid_regex(tmpdir):
175+
"""Invalid regular expressions should result in an empty list."""
176+
base = tmpdir.mkdir("base_invalid_regex")
177+
base.join("a.tif").write("x")
178+
179+
# invalid regex should not raise but simply return an empty list
180+
res = listdir_matching(str(base), "([", regex=True)
181+
assert res == []
182+
183+
184+
def test_listdir_matching_recursive_regex_fullpath(tmpdir):
185+
"""Recursive search with regex and fullpath should return absolute paths."""
186+
base = tmpdir.mkdir("base_recursive")
187+
sub = base.mkdir("subdir")
188+
sub.join("s.tif").write("x")
189+
190+
# recursive + regex + fullpath should return absolute path including subdir
191+
res = listdir_matching(
192+
str(base), r".*\.tif$", regex=True, recursive=True, fullpath=True
193+
)
194+
assert any(os.path.isabs(x) for x in res)
195+
expected = os.path.abspath(os.path.join(str(sub), "s.tif"))
196+
assert expected in res
197+
198+
199+
def test_find_dirs_containing_filetype(tmpdir):
200+
"""Test find_dirs_containing_filetype function."""
201+
base = tmpdir.mkdir("find_dirs")
202+
sub1 = base.mkdir("sub1")
203+
sub2 = base.mkdir("sub2")
204+
sub1.join("file1.tif").write("x")
205+
sub2.join("file2.png").write("x")
206+
sub2.join("file3.tif").write("x")
207+
208+
res = find_dirs_containing_filetype(str(base), ".tif")
209+
# find_dirs_containing_filetype appends a "/" to the dirname
210+
expected_sub1 = str(sub1) + "/"
211+
expected_sub2 = str(sub2) + "/"
212+
assert expected_sub1 in res
213+
assert expected_sub2 in res
214+
assert len(res) == 2
215+
216+
217+
def test_folder_size(tmpdir):
218+
"""Test folder_size function."""
219+
base = tmpdir.mkdir("folder_size")
220+
base.join("file1.txt").write("123") # 3 bytes
221+
sub = base.mkdir("sub")
222+
sub.join("file2.txt").write("12345") # 5 bytes
223+
# Total should be 8 bytes
224+
225+
assert folder_size(str(base)) == 8
226+
227+
228+
def test_join_files_with_channel_suffix():
229+
"""Test join_files_with_channel_suffix function."""
230+
files = ["file1.tif", "file2.tif"]
231+
232+
# nchannels = 1 (no suffixed copies added)
233+
assert join_files_with_channel_suffix(files, 1) == files
234+
235+
# nchannels = 3 (original then _0 and _1 copies)
236+
res = join_files_with_channel_suffix(files, 3)
237+
expected = [
238+
"file1.tif",
239+
"file2.tif",
240+
"file1_0.tif",
241+
"file2_0.tif",
242+
"file1_1.tif",
243+
"file2_1.tif",
244+
]
245+
assert res == expected
246+
247+
# Empty files list
248+
assert join_files_with_channel_suffix([], 3) == ""
249+
250+
# nchannels as string
251+
assert join_files_with_channel_suffix(["a.tif"], "2") == ["a.tif", "a_0.tif"]
252+
253+
# nchannels as invalid string (fall back to [0])
254+
assert join_files_with_channel_suffix(["a.tif"], "foo") == ["a.tif", "a_0.tif"]
255+
256+
257+
def test_create_directory(tmpdir):
258+
"""Test create_directory function."""
259+
new_dir = tmpdir.join("new_dir")
260+
assert not os.path.exists(str(new_dir))
261+
create_directory(str(new_dir))
262+
assert os.path.exists(str(new_dir))
263+
# Test creating existing directory (should not fail)
264+
create_directory(str(new_dir))
265+
assert os.path.exists(str(new_dir))
266+
267+
268+
def test_join2():
269+
"""Test join2 function."""
270+
assert join2("/foo", "bar") == "/foo/bar"
271+
assert join2("/foo/", "bar") == "/foo/bar"
272+
assert join2("/foo", "/bar") == "/foo/bar"
273+
# test with double backslashes which should be sanitized
274+
assert join2("C:\\Temp", "file.txt") == "C:/Temp/file.txt"
275+
276+
277+
def test_listdir_matching_recursive_with_subfolders(tmpdir):
278+
"""Test recursive listdir_matching ensures paths are correctly combined."""
279+
base = tmpdir.mkdir("base_rec_sf")
280+
sub = base.mkdir("subfolder")
281+
sub.join("test.tif").write("x")
282+
283+
# non-recursive path join (uses path + candidate)
284+
res = listdir_matching(str(base), ".tif", fullpath=True, recursive=False)
285+
assert res == []
286+
287+
# recursive path join (uses dirpath + candidate)
288+
res_rec = listdir_matching(str(base), ".tif", fullpath=True, recursive=True)
289+
expected = os.path.abspath(os.path.join(str(sub), "test.tif"))
290+
assert expected in res_rec
291+
292+
# recursive path join with regex and fullpath
293+
res_rec_regex = listdir_matching(
294+
str(base), r".*\.tif$", fullpath=True, recursive=True, regex=True
295+
)
296+
assert expected in res_rec_regex
297+
298+
# recursive path join with regex and NOT fullpath
299+
res_rec_regex_rel = listdir_matching(
300+
str(base), r".*\.tif$", fullpath=False, recursive=True, regex=True
301+
)
302+
assert "subfolder/test.tif" in [p.replace(os.sep, "/") for p in res_rec_regex_rel]
303+
304+
# non-recursive path join with regex and fullpath
305+
sub_file = sub.join("test2.tif").write("x")
306+
res_nonrec_regex = listdir_matching(
307+
str(sub), r".*\.tif$", fullpath=True, recursive=False, regex=True
308+
)
309+
expected_nonrec = os.path.abspath(os.path.join(str(sub), "test2.tif"))
310+
assert expected_nonrec in res_nonrec_regex
311+
312+
313+
def test_create_directory(tmpdir):
314+
"""Test create_directory function."""
315+
new_dir = os.path.join(str(tmpdir), "new_dir")
316+
assert not os.path.exists(new_dir)
317+
create_directory(new_dir)
318+
assert os.path.exists(new_dir)
319+
assert os.path.isdir(new_dir)
320+
321+
# Calling again should not raise (exist_ok behavior)
322+
create_directory(new_dir)
323+
assert os.path.exists(new_dir)

0 commit comments

Comments
 (0)