from tests.support.paths import PROJECT_ROOT import importlib.util from unittest.mock import patch import pytest SCRIPT_PATH = PROJECT_ROOT / "tools" / "nodes" / "cli.py" def load_launcher(): specification = importlib.util.spec_from_file_location( "node_asset_launcher", SCRIPT_PATH, ) module = importlib.util.module_from_spec(specification) specification.loader.exec_module(module) return module def test_blender_path_prefers_explicit_path(tmp_path): launcher = load_launcher() executable = tmp_path / "blender" executable.touch() with patch.dict("os.environ", {"BLENDER_BIN": "ignored"}): assert launcher.blender_path(executable) == executable def test_blender_path_reads_environment(tmp_path): launcher = load_launcher() executable = tmp_path / "blender" executable.touch() with patch.dict("os.environ", {"BLENDER_BIN": str(executable)}): assert launcher.blender_path() == executable def test_blender_path_reads_project_dotenv(tmp_path): launcher = load_launcher() executable = tmp_path / "Blender 4.5" / "blender.exe" executable.parent.mkdir() executable.touch() env_path = tmp_path / ".env" env_path.write_text( f'BLENDER_BIN="{executable}"\n', encoding="utf-8", ) with patch.dict("os.environ", {}, clear=True), patch.object( launcher, "PROJECT_ROOT", tmp_path, ): assert launcher.blender_path() == executable def test_blender_path_reports_missing_configuration(tmp_path): launcher = load_launcher() with patch.dict("os.environ", {}, clear=True), patch.object( launcher.shutil, "which", return_value=None, ), patch.object( launcher, "PROJECT_ROOT", tmp_path, ): with pytest.raises(RuntimeError, match="Blender not found"): launcher.blender_path() @pytest.mark.parametrize("arguments,modules,run_tests", [ (["build"], ("tools.nodes.build", "tools.nodes.check"), True), (["check", "--skip-tests"], ("tools.nodes.check",), False), (["preview", "--fragment"], ("tools.nodes.preview.export",), False), ]) def test_commands_dispatch_requested_work(monkeypatch, tmp_path, arguments, modules, run_tests): launcher = load_launcher() output = tmp_path / "node groups.html" command = ["node-group", *arguments] if arguments[0] == "preview": command += ["--output", str(output)] monkeypatch.setattr("sys.argv", command) monkeypatch.setattr(launcher, "blender_path", lambda _: "blender") with ( patch.object(launcher, "run_blender_modules") as blender, patch.object(launcher, "run") as run, patch.object(launcher.webbrowser, "open") as open_browser, ): launcher.main() if arguments[0] == "preview": blender.assert_called_once_with("blender", modules, ["--output", str(output), "--fragment"]) open_browser.assert_not_called() else: blender.assert_called_once_with("blender", modules) if run_tests: run.assert_called_once_with((launcher.sys.executable, "-m", "pytest")) else: run.assert_not_called()