import json from pathlib import Path from pygui.backend.data.file_browser import FileBrowser def _write_csv(path, wafer_id="P00001"): path.write_text( f"Wafer ID={wafer_id}\n" "Acquisition Date=03/26/2025\n" "Label,1,2,3\n" "X (mm),0,10,-10\n" "Y (mm),10,-10,-10\n" "data\n" "0.0,149.0,148.5,150.6\n" ) def _write_raw_zwafer_export(path, wafer_id="P00001", chamber="Chamber A", comments="test run"): """A raw fixture-export CSV, as ZWaferParser/ImportZWaferCSV expect it: row-indexed data rows (leading column dropped on import), unlike the already-normalized `{serial}-{timestamp}.csv` files _write_csv produces.""" path.write_text( f"Wafer ID={wafer_id}\n" "Acquisition Date=03/26/2025\n" f"Chamber={chamber}\n" f"Comments={comments}\n" "Label,1,2,3\n" "X (mm),0,10,-10\n" "Y (mm),10,-10,-10\n" "data\n" "0.0,149.0,148.5,150.6\n" "1.0,149.2,148.7,150.9\n" ) def test_recorded_live_file_flagged_as_recording(qapp, tmp_path): """Files named live__.csv (SessionController.startRecording) must be distinguishable in the browser from read-memory dumps.""" _write_csv(tmp_path / "live_P00001_20260706_143022.csv") _write_csv(tmp_path / "P00002-20260706_143500.csv") browser = FileBrowser() browser._set_current_directory(tmp_path) browser.refreshFiles() files_by_name = {Path(row["fileName"]).name: row for row in browser.files} assert files_by_name["live_P00001_20260706_143022.csv"]["isRecording"] is True assert files_by_name["P00002-20260706_143500.csv"]["isRecording"] is False def test_set_current_directory_updates_dir_and_refreshes(qapp, tmp_path): """setCurrentDirectory (no native dialog) is how the Status tab's save-dir picker keeps the Source panel pointed at the same folder.""" _write_csv(tmp_path / "P00003-20260706_143500.csv") browser = FileBrowser() browser.setCurrentDirectory(str(tmp_path)) assert browser.currentDirectory == str(tmp_path) assert len(browser.files) == 1 assert Path(browser.files[0]["fileName"]).name == "P00003-20260706_143500.csv" def test_import_zwafer_csv_writes_normalized_file_and_sidecar(qapp, tmp_path): """Mirrors C#'s ImportZWaferCSV (Form1.cs:1711): strip the leading row-index column, rename to {serial}-{timestamp}.csv (no Z prefix — matches this app's other write paths), write a metadata sidecar, and refresh the file list.""" source_dir = tmp_path / "incoming" source_dir.mkdir() source = source_dir / "raw_export.csv" _write_raw_zwafer_export(source) browser = FileBrowser() browser._set_current_directory(tmp_path) signals = [] browser.importFinished.connect(lambda path, message: signals.append((path, message))) browser.importZWaferCsv(str(source)) new_path = tmp_path / "P00001-20250326_000000.csv" assert new_path.exists() assert new_path.read_text().splitlines() == [ "1,2,3", "149.0,148.5,150.6", "149.2,148.7,150.9", ] sidecar = json.loads((tmp_path / "P00001-20250326_000000.csv.json").read_text()) assert sidecar["wafer"] == "P00001" assert sidecar["chamber"] == "Chamber A" assert sidecar["notes"] == "test run" assert len(signals) == 1 assert signals[0][0] == str(new_path) assert any(Path(row["fileName"]).name == new_path.name for row in browser.files) def test_import_zwafer_csv_blocks_reimporting_same_source(qapp, tmp_path): """Re-importing the identical source file must be blocked, not overwritten — the output filename is derived from the source's own acquisition-date header, so a second import of the same file collides on purpose.""" source_dir = tmp_path / "incoming" source_dir.mkdir() source = source_dir / "raw_export.csv" _write_raw_zwafer_export(source) browser = FileBrowser() browser._set_current_directory(tmp_path) signals = [] browser.importFinished.connect(lambda path, message: signals.append((path, message))) browser.importZWaferCsv(str(source)) browser.importZWaferCsv(str(source)) assert len(signals) == 2 assert signals[1][0] == "" assert "already" in signals[1][1].lower() def test_import_zwafer_csv_without_date_header_still_blocks_duplicate(qapp, tmp_path): """No fallback to wall-clock time: a source missing 'Acquisition Date=' must still get a deterministic filename, so re-importing it a second time is blocked instead of silently succeeding with a fresh timestamp.""" source_dir = tmp_path / "incoming" source_dir.mkdir() source = source_dir / "raw_export.csv" source.write_text( "Wafer ID=P00002\n" "Label,1,2,3\n" "X (mm),0,10,-10\n" "Y (mm),10,-10,-10\n" "data\n" "0.0,149.0,148.5,150.6\n" ) browser = FileBrowser() browser._set_current_directory(tmp_path) signals = [] browser.importFinished.connect(lambda path, message: signals.append((path, message))) browser.importZWaferCsv(str(source)) browser.importZWaferCsv(str(source)) assert len(signals) == 2 assert signals[0][0] != "" # first import succeeds assert signals[1][0] == "" # second is blocked assert "already" in signals[1][1].lower() def test_import_zwafer_csv_reports_missing_source(qapp, tmp_path): browser = FileBrowser() browser._set_current_directory(tmp_path) signals = [] browser.importFinished.connect(lambda path, message: signals.append((path, message))) browser.importZWaferCsv(str(tmp_path / "missing.csv")) assert len(signals) == 1 assert signals[0][0] == ""