from __future__ import annotations import shutil from pathlib import Path from app.pipeline.file_manager import ( check_dir_write_access, create_run_context, move_file_to_error, next_run_number, scan_input_files, ) class FakeSamba: def __init__(self, root: Path) -> None: self.root = root def __enter__(self): return self def __exit__(self, exc_type, exc, tb): # noqa: ANN001 return False def _to_local(self, remote_path: str) -> Path: cleaned = remote_path.replace("/", "\\").strip("\\") return self.root / Path(cleaned) def path_exists(self, path: str) -> bool: return self._to_local(path).exists() def listdir(self, path: str) -> list[str]: target = self._to_local(path) if not target.exists(): return [] return [item.name for item in target.iterdir()] def is_file(self, path: str) -> bool: return self._to_local(path).is_file() def mkdir(self, path: str, parent: bool = False) -> None: target = self._to_local(path) if parent: target.mkdir(parents=True, exist_ok=True) else: target.mkdir(exist_ok=True) def copy(self, path_from: str, path_to: str, replace: bool = False) -> None: source = self._to_local(path_from) target = self._to_local(path_to) target.parent.mkdir(parents=True, exist_ok=True) if target.exists() and not replace: raise FileExistsError(path_to) shutil.copy2(source, target) def delete(self, path: str) -> None: target = self._to_local(path) if target.exists(): target.unlink() def rename(self, path_from: str, path_to: str, replace: bool = False) -> None: source = self._to_local(path_from) target = self._to_local(path_to) target.parent.mkdir(parents=True, exist_ok=True) if target.exists() and not replace: raise FileExistsError(path_to) source.rename(target) def open(self, path: str, mode: str = "rb"): target = self._to_local(path) target.parent.mkdir(parents=True, exist_ok=True) return target.open(mode) def test_scan_input_files_splits_valid_and_invalid(tmp_path: Path) -> None: samba = FakeSamba(tmp_path) in_dir = "Exchange\\SMBDEMO\\test" local_dir = tmp_path / "Exchange" / "SMBDEMO" / "test" local_dir.mkdir(parents=True) (local_dir / "SKO115FZ_01_123456789_20260616_X00001.xml").write_text( "ok", encoding="utf-8" ) (local_dir / "wrong_name.xml").write_text("bad", encoding="utf-8") result = scan_input_files(in_dir, samba) assert len(result.valid_files) == 1 assert len(result.invalid_files) == 1 def test_next_run_number_reads_existing_dirs(tmp_path: Path) -> None: samba = FakeSamba(tmp_path) out_day = ( tmp_path / "Exchange" / "SMBDEMO" / "Out" / "2026" / "06_2026" / "20260616" ) (out_day / "1").mkdir(parents=True) (out_day / "2").mkdir(parents=True) number = next_run_number("Exchange\\SMBDEMO\\Out\\2026\\06_2026\\20260616", samba) assert number == 3 def test_create_run_context_creates_paths(tmp_path: Path) -> None: samba = FakeSamba(tmp_path) context = create_run_context("Exchange\\SMBDEMO\\test", samba) assert context.run_number == 1 assert (tmp_path / Path(context.run_dir)).exists() assert (tmp_path / Path(context.error_dir)).exists() assert (tmp_path / Path(context.processed_dir)).exists() def test_move_file_to_error_adds_suffix_on_collision(tmp_path: Path) -> None: samba = FakeSamba(tmp_path) error_dir = tmp_path / "Exchange" / "SMBDEMO" / "Err" error_dir.mkdir(parents=True) (error_dir / "file.xml").write_text("existing", encoding="utf-8") source = tmp_path / "Exchange" / "SMBDEMO" / "test" / "file.xml" source.parent.mkdir(parents=True) source.write_text("new", encoding="utf-8") target = move_file_to_error( file_path="Exchange\\SMBDEMO\\test\\file.xml", file_name="file.xml", error_dir="Exchange\\SMBDEMO\\Err", samba_conn=samba, ) assert target.endswith("file_1.xml") assert (error_dir / "file_1.xml").exists() def test_check_dir_write_access_success(tmp_path: Path) -> None: samba = FakeSamba(tmp_path) target_dir = tmp_path / "Exchange" / "SMBDEMO" / "Out" target_dir.mkdir(parents=True) ok, error = check_dir_write_access( target_dir="Exchange\\SMBDEMO\\Out", samba_conn=samba, source_name="Out", ) assert ok is True assert error is None def test_check_dir_write_access_fails_without_open_or_upload(tmp_path: Path) -> None: class NoWriteSamba(FakeSamba): open = None # type: ignore[assignment] samba = NoWriteSamba(tmp_path) target_dir = tmp_path / "Exchange" / "SMBDEMO" / "Out" target_dir.mkdir(parents=True) ok, error = check_dir_write_access( target_dir="Exchange\\SMBDEMO\\Out", samba_conn=samba, source_name="Out", ) assert ok is False assert error is not None