# -*- coding: utf-8 -*- """ Smoke test for: 彻底修复底层写入路径与掩膜联动 验证三件事(不依赖 GUI / 不实例化 Pipeline,避免触发 osgeo/gdal 导入): 1. pipeline.step10_map 内部对 output_image_path 的 override 逻辑正确: - 路径不在 visualization_dir 下 → 被强制重定向 - 路径在 visualization_dir 下 → 保留 - 路径为 None/空 → 用 forced 默认值 2. step11_map_panel.update_from_config 含 pipeline.get_step_output_dir('step1') 调用 3. _step_path_resolver._FALLBACK_DIR_TABLE['water_mask'] == '1_water_mask' """ import re import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] PIPELINE_FILE = ROOT / "src" / "core" / "water_quality_inversion_pipeline_GUI.py" PANEL_FILE = ROOT / "src" / "gui" / "panels" / "step11_map_panel.py" RESOLVER_FILE = ROOT / "src" / "gui" / "panels" / "_step_path_resolver.py" def test_step10_map_forced_override(): """纯文本级检查 step10_map 是否含强制重定向逻辑。""" text = PIPELINE_FILE.read_text(encoding="utf-8") # 找 def step10_map( 起点;用下一个 def (8 空格缩进) 作锚点截取函数体 m = re.search( r"def step10_map\([^\)]*\)[^\n]*:\n(.*?)(?=\n def |\nclass |\Z)", text, re.DOTALL, ) assert m, "找不到 step10_map 函数" body = m.group(1) # 关键标记 assert "forced_image_path" in body, "step10_map 应计算 forced_image_path" assert "强制重定向" in body, "step10_map 应有重定向提示文本" assert "self.visualization_dir" in body, "step10_map 应引用 self.visualization_dir" print("✅ step10_map 含强制 override 逻辑(forced_image_path + 重定向提示)") def test_step10_map_accepts_in_visualization_dir(): """模拟:当用户传入的路径已在 visualization_dir 内,应被保留(不被覆盖)。""" # 走 source 的逻辑分支:在 startswith 命中 → 保留原路径 norm_viz = "/work/14_visualization" candidates = [ ("/work/14_visualization/sub/foo.png", True), # 子目录 → 保留 ("/work/14_visualization/foo.png", True), # 自身 → 保留(== 情形走 else 分支) ("/work/11_12_13_predictions/foo.png", False), # 外部 → 强制重定向 ("/work/foo.png", False), ] for path, should_keep in candidates: norm_user = path.replace("\\", "/").rstrip("/") keep = norm_user.startswith(norm_viz + "/") or norm_user == norm_viz assert keep == should_keep, f"路径 {path!r} 判断错误:keep={keep}, expect={should_keep}" print("✅ step10_map 路径归属判断(startswith + ==)正确") def test_step11_panel_calls_pipeline_get_step_output_dir(): """验证 step11 panel 真的调用了 main_window.pipeline.get_step_output_dir('step1')。""" text = PANEL_FILE.read_text(encoding="utf-8") assert "get_step_output_dir('step1')" in text, \ "step11 panel 应调用 get_step_output_dir('step1')" assert "getattr(_win, 'pipeline', None)" in text or "getattr(main_window, 'pipeline'" in text, \ "step11 panel 应安全访问 main_window.pipeline(None 守护)" assert "resolve_subdir(self.work_dir, 'water_mask')" in text, \ "step11 panel 应有 resolve_subdir 兜底" # 不应硬编码具体掩膜文件名(应通过 glob 探测)—— 排除注释行 code_lines = [ ln for ln in text.splitlines() if ln.strip() and not ln.strip().startswith("#") ] code_only = "\n".join(code_lines) assert "water_mask_from_ndwi" not in code_only, \ "step11 panel 不应硬编码 water_mask_from_ndwi(应通过 glob 探测)" assert "water_mask_from_shp" not in code_only, \ "step11 panel 不应硬编码 water_mask_from_shp(应通过 glob 探测)" print("✅ step11 panel 含 pipeline.get_step_output_dir('step1') 调用 + 兜底 + 安全守护") def test_fallback_dir_table_water_mask(): """验证 _FALLBACK_DIR_TABLE['water_mask'] == '1_water_mask'。""" text = RESOLVER_FILE.read_text(encoding="utf-8") m = re.search(r"'water_mask'\s*:\s*'([^']+)'", text) assert m, "_FALLBACK_DIR_TABLE 缺 'water_mask' 键" assert m.group(1) == "1_water_mask", f"应为 1_water_mask,实为 {m.group(1)}" print(f"✅ _FALLBACK_DIR_TABLE['water_mask'] = {m.group(1)!r}") def test_panel_guard_does_not_overwrite_existing(): """验证 step11 panel 的新段不覆盖已有 boundary(feedback_never_overwrite_with_empty)。""" text = PANEL_FILE.read_text(encoding="utf-8") # 4.5 段必须先读 existing_boundary,再判断 m = re.search( r"# 4\.5\..*?(?=\n # 5\.)", text, re.DOTALL ) assert m, "找不到 4.5 段" body = m.group(0) assert "existing_boundary" in body, "4.5 段应读 existing_boundary" assert "if not existing_boundary" in body, "4.5 段应仅在空时填入" print("✅ step11 panel 4.5 段遵守 '非空值不覆盖' 原则") if __name__ == "__main__": print("=" * 60) print("Smoke test: 彻底修复底层写入路径与掩膜联动") print("=" * 60) test_step10_map_forced_override() test_step10_map_accepts_in_visualization_dir() test_step11_panel_calls_pipeline_get_step_output_dir() test_fallback_dir_table_water_mask() test_panel_guard_does_not_overwrite_existing() print("=" * 60) print("全部通过 ✅") sys.exit(0)