Skip to main content
Glama

Jinni: Bring Your Project Into Context

by smat-dev
test_translate_wsl_path.py21.2 kB
import pytest import os # Added os for environ manipulation import platform import subprocess import shutil from urllib.parse import urlparse, ParseResult, quote # Added quote from typing import Optional # Added Optional from jinni.utils import _translate_wsl_path, _find_wslpath, _cached_wsl_to_unc, _get_default_wsl_distro # Import new helpers from functools import lru_cache # Import lru_cache import platform as real_platform from jinni.utils import ensure_no_nul # --- Test Cases for _translate_wsl_path --- # Helper to mock platform.system def mock_platform_system(system_name="Windows"): def func(): return system_name.capitalize() # Ensure consistent capitalization return func # Helper to mock urlparse def mock_urlparse(scheme="vscode-remote", netloc="wsl+Ubuntu", path="/home/user/project"): # Return a simple object that mimics ParseResult enough for the function class MockParseResult: def __init__(self, scheme, netloc, path): self.scheme = scheme self.netloc = netloc self.path = path return lambda url_str: MockParseResult(scheme, netloc, path) # --- Mocks for new internal functions --- # Mock _find_wslpath def mock_find_wslpath(path: Optional[str] = "/fake/wslpath"): @lru_cache(maxsize=1) def func(): return path return func # Mock _cached_wsl_to_unc def mock_cached_wsl_to_unc(win_path: Optional[str], fail_path: Optional[str] = None): @lru_cache(maxsize=256) def func(wslpath_exe, posix_path): if fail_path is not None and posix_path == fail_path: return None # Simulate failure for a specific path return win_path # Return success path otherwise return func # Mock for _get_default_wsl_distro def mock_get_default_wsl_distro(distro_name: Optional[str]): @lru_cache(maxsize=1) def func(): return distro_name return func # Mock for pathlib.Path().exists() used in fallback class MockPathExists: def __init__(self, path_str): self.path_str = str(path_str) # Ensure it's a string def exists(self): # This mock is specifically for the fallback logic. # It should return True only if the path being checked matches # the manually constructed UNC path expected in a fallback scenario. # We need to know the expected fallback path for the current test case. # This is tricky to do generically here. Instead, we'll rely on # specific mocking within the tests that need fallback verification. # By default, return False for simplicity in tests not explicitly testing fallback success. print(f"DEBUG: MockPathExists.exists called for: {self.path_str}") # Debug print return False # --- Existing Simple Tests (Adapt if needed) --- def test_translate_windows_path_no_change(monkeypatch): """Test a Windows path is not translated on Windows.""" monkeypatch.setattr(platform, "system", mock_platform_system("Windows")) win_path = "C:\\Users\\User\\Project" assert _translate_wsl_path(win_path) == win_path def test_translate_posix_path_wslpath_not_found(monkeypatch): """Test POSIX path translation when wslpath is not found (should raise RuntimeError).""" monkeypatch.setattr(platform, "system", mock_platform_system("Windows")) monkeypatch.setattr("jinni.utils._find_wslpath", mock_find_wslpath(None)) # Mock find failure monkeypatch.setattr("jinni.utils._get_default_wsl_distro", mock_get_default_wsl_distro(None)) # Mock no default distro monkeypatch.delenv("JINNI_ASSUME_WSL_DISTRO", raising=False) # Mock no env var # Mock Path(...).exists to always return False for the fallback check monkeypatch.setattr("jinni.utils.Path", MockPathExists) # Use the refined mock with pytest.raises(RuntimeError, match="Cannot map POSIX path"): _translate_wsl_path("/home/user/project") def test_translate_posix_path_wslpath_error(monkeypatch): """Test POSIX path translation when wslpath command fails (should raise RuntimeError).""" monkeypatch.setattr(platform, "system", mock_platform_system("Windows")) monkeypatch.setattr("jinni.utils._find_wslpath", mock_find_wslpath("/fake/wslpath")) monkeypatch.setattr("jinni.utils._cached_wsl_to_unc", mock_cached_wsl_to_unc(None)) # Mock wslpath call failure monkeypatch.setattr("jinni.utils._get_default_wsl_distro", mock_get_default_wsl_distro(None)) # Mock no default distro monkeypatch.delenv("JINNI_ASSUME_WSL_DISTRO", raising=False) # Mock no env var # Mock Path(...).exists to always return False for the fallback check monkeypatch.setattr("jinni.utils.Path", MockPathExists) # Use the refined mock with pytest.raises(RuntimeError, match="Cannot map POSIX path"): _translate_wsl_path("/home/user/project") def test_translate_vscode_non_wsl_uri_no_change(monkeypatch): """Test a non-WSL vscode-remote URI is not translated.""" monkeypatch.setattr(platform, "system", mock_platform_system("Windows")) # Standard urlparse is fine here, relies on scheme/netloc check uri = "vscode-remote://ssh+server/path/on/remote" assert _translate_wsl_path(uri) == uri def test_translate_posix_path_on_linux_no_change(monkeypatch): """Test POSIX path is not translated when running on Linux.""" monkeypatch.setattr(platform, "system", mock_platform_system("Linux")) path = "/home/user/project" assert _translate_wsl_path(path) == path def test_translate_vscode_wsl_uri_on_linux_no_change(monkeypatch): """Test vscode-remote WSL URI is STRIPPED when running on Linux/non-Windows.""" monkeypatch.setattr(platform, "system", mock_platform_system("Linux")) uri = "vscode-remote://wsl+Ubuntu/home/user/project" expected_stripped_path = "/home/user/project" assert _translate_wsl_path(uri) == expected_stripped_path def test_translate_unc_path_no_change(monkeypatch): """Test a UNC path (potentially already translated) is not re-translated.""" monkeypatch.setattr(platform, "system", mock_platform_system("Windows")) unc_path = r"\\wsl$\Ubuntu\home\user" assert _translate_wsl_path(unc_path) == unc_path unc_path_localhost = r"\\wsl.localhost\Ubuntu\home\user" assert _translate_wsl_path(unc_path_localhost) == unc_path_localhost def test_translate_empty_string_no_change(monkeypatch): """Test an empty string is handled gracefully.""" monkeypatch.setattr(platform, "system", mock_platform_system("Windows")) assert _translate_wsl_path("") == "" def test_translate_env_var_disables_translation(monkeypatch): """Test setting JINNI_NO_WSL_TRANSLATE=1 disables translation.""" monkeypatch.setenv("JINNI_NO_WSL_TRANSLATE", "1") monkeypatch.setattr(platform, "system", mock_platform_system("Windows")) posix_path = "/home/user/project" vscode_uri = "vscode-remote://wsl+Ubuntu/home/user/project" # No mocks for wslpath needed, should exit early assert _translate_wsl_path(posix_path) == posix_path assert _translate_wsl_path(vscode_uri) == vscode_uri def test_translate_platform_windows_lowercase(monkeypatch): """Test translation works if platform.system() returns lowercase 'windows'.""" monkeypatch.setattr(platform, "system", mock_platform_system("windows")) monkeypatch.setattr("jinni.utils._find_wslpath", mock_find_wslpath("/fake/wslpath")) monkeypatch.setattr("jinni.utils._cached_wsl_to_unc", mock_cached_wsl_to_unc(r"\\wsl$\Ubuntu\home\user\project")) assert _translate_wsl_path("/home/user/project") == r"\\wsl$\Ubuntu\home\user\project" def test_strip_wsl_uri_to_posix_on_linux(monkeypatch): """Test that percent-encoded + in authority is handled and VSCode WSL URIs are stripped to POSIX on Linux.""" monkeypatch.setattr(platform, "system", lambda: "Linux") # Should decode %2B to + and strip to /home/x assert _translate_wsl_path("vscode-remote://wsl%2Bubuntu/home/x") == "/home/x" # Should also work for normal + assert _translate_wsl_path("vscode-remote://wsl+ubuntu/home/y") == "/home/y" # Should also work for alternate vscode URI assert _translate_wsl_path("vscode://vscode-remote/wsl+ubuntu/home/z") == "/home/z" # Should return unchanged for normal POSIX path assert _translate_wsl_path("/home/unchanged") == "/home/unchanged" def test_translate_percent_encoded_plus_uri_on_windows(monkeypatch): """Test vscode-remote URI with %2B is translated to UNC on Windows.""" monkeypatch.setattr(platform, "system", mock_platform_system("Windows")) input_uri = "vscode-remote://wsl%2BUbuntu-20.04/mnt/c/project" # Use raw string for expected UNC path expected_unc = r"\\wsl$\Ubuntu-20.04\mnt\c\project" assert _translate_wsl_path(input_uri) == expected_unc def test_translate_percent_encoded_plus_uri_on_linux(monkeypatch): """Test vscode-remote URI with %2B is stripped to POSIX on Linux.""" monkeypatch.setattr(platform, "system", mock_platform_system("Linux")) input_uri = "vscode-remote://wsl%2BUbuntu-20.04/mnt/c/project" expected_posix = "/mnt/c/project" assert _translate_wsl_path(input_uri) == expected_posix # --- Parametrized Tests (Corrected with Raw Strings) --- @pytest.mark.parametrize( ("input_path", "mock_system", "mock_find_wslpath_ret", "mock_cached_wsl_ret", "expected_output", "env_vars", "mock_default_distro", "expected_fallback_exists_path", "expected_exception_type", "expected_exception_msg"), [ # --- Standard WSL Translations (Success) --- ("/home/alice/app", "Windows", "/fake/wslpath", r"\\wsl$\Ubuntu\home\alice\app", r"\\wsl$\Ubuntu\home\alice\app", None, None, None, None, None), ("vscode-remote://wsl+Ubuntu/home/alice/app", "Windows", None, None, r"\\wsl$\Ubuntu\home\alice\app", None, None, None, None, None), ("vscode-remote://wsl.localhost/Ubuntu/home/alice/app", "Windows", None, None, r"\\wsl$\Ubuntu\home\alice\app", None, None, None, None, None), ("vscode://vscode-remote/wsl+Ubuntu/home/alice/app", "Windows", None, None, r"\\wsl$\Ubuntu\home\alice\app", None, None, None, None, None), # --- Edge Cases & New Features (Success) --- ("vscode-remote://wsl+Ubuntu 22.04/mnt/c/Data", "Windows", None, None, r"\\wsl$\Ubuntu 22.04\mnt\c\Data", None, None, None, None, None), ("vscode-remote://wsl.localhost/Ubuntu 22.04/mnt/c/Data", "Windows", None, None, r"\\wsl$\Ubuntu 22.04\mnt\c\Data", None, None, None, None, None), ("vscode-remote://wsl+Ubuntu/home/user/My%20Project", "Windows", None, None, r"\\wsl$\Ubuntu\home\user\My Project", None, None, None, None, None), ("vscode://vscode-remote/wsl+Ubuntu", "Windows", None, None, r"\\wsl$\Ubuntu\\", None, None, None, None, None), ("vscode-remote://ssh-remote+myhost/path/to/proj", "Windows", None, None, "vscode-remote://ssh-remote+myhost/path/to/proj", None, None, None, None, None), (r"\\wsl$\Ubuntu\home\My Project\file.txt", "Windows", None, None, r"\\wsl$\Ubuntu\home\My Project\file.txt", None, None, None, None, None), ("vscode://vscode-remote/wsl+Ubuntu/home/user/.bashrc", "Windows", None, None, r"\\wsl$\Ubuntu\home\user\.bashrc", None, None, None, None, None), ("vscode://vscode-remote/wsl+Ubuntu", "Windows", None, None, r"\\wsl$\Ubuntu\\", None, None, None, None, None), ("vscode://vscode-remote/wsl+Ubuntu/", "Windows", None, None, r"\\wsl$\Ubuntu\\", None, None, None, None, None), ("vscode-remote://wsl.localhost/Debian/etc/passwd", "Windows", None, None, r"\\wsl$\Debian\etc\passwd", None, None, None, None, None), # --- Malformed URIs (ValueError expected) --- ("vscode-remote://wsl+/home/user/project", "Windows", None, None, None, None, None, None, ValueError, "missing distro name in WSL URI"), ("vscode-remote://wsl.localhost//home/user/project", "Windows", None, None, None, None, None, None, ValueError, "missing distro name in wsl.localhost URI path"), ("vscode://vscode-remote/wsl+/home/user", "Windows", None, None, None, None, None, None, ValueError, "missing distro name in alternate vscode URI authority"), ("vscode-remote://wsl.localhost/", "Windows", None, None, None, None, None, None, ValueError, "missing or invalid distro/path in wsl.localhost URI path"), # --- Non-Windows Platform (Should Strip/Not Translate - Success) --- ("/home/alice/app", "Linux", None, None, "/home/alice/app", None, None, None, None, None), ("vscode-remote://wsl+Ubuntu/home/alice/app", "macOS", None, None, "/home/alice/app", None, None, None, None, None), ("vscode-remote://wsl.localhost/Debian/tmp/file", "Linux", None, None, "/tmp/file", None, None, None, None, None), # --- Fallback Tests (Success) --- ("/home/alice/app", "Windows", None, None, r"\\wsl$\TestDistro\home\alice\app", {"JINNI_ASSUME_WSL_DISTRO": "TestDistro"}, None, r"\\wsl$\TestDistro\home\alice\app", None, None), ("/home/alice/app", "Windows", None, None, r"\\wsl$\DefaultDistro\home\alice\app", None, "DefaultDistro", r"\\wsl$\DefaultDistro\home\alice\app", None, None), ("/home/alice/app", "Windows", None, None, r"\\wsl$\TestDistro\home\alice\app", {"JINNI_ASSUME_WSL_DISTRO": "TestDistro"}, None, None, None, None), ("/home/alice/app", "Windows", None, None, r"\\wsl$\DefaultDistro\home\alice\app", None, "DefaultDistro", None, None, None), # --- Env Var Disables (Success, No Translation) --- ("/home/alice/app", "Windows", "/fake/wslpath", None, "/home/alice/app", {"JINNI_NO_WSL_TRANSLATE": "1"}, None, None, None, None), ("vscode-remote://wsl+Ubuntu/home/alice/app", "Windows", None, None, "vscode-remote://wsl+Ubuntu/home/alice/app", {"JINNI_NO_WSL_TRANSLATE": "1"}, None, None, None, None), ], ids=[ "posix_to_unc_wslpath_ok", "vscode_remote_wsl_plus_uri_to_unc", "vscode_remote_wsl_localhost_uri_to_unc", "vscode_alt_uri_wsl_plus_to_unc", "distro_with_spaces_wsl_plus", "distro_with_spaces_wsl_localhost", "path_with_encoded_spaces", "vscode_alt_uri_no_path_to_unc_root", "ssh_remote_uri_no_change", "unc_dollar_path_no_change", "vscode_uri_bashrc_to_unc", "vscode_uri_distro_only_to_unc_root", "vscode_uri_distro_slash_to_unc_root", "vscode_localhost_uri_path_to_unc", "malformed_uri_wsl_plus_empty_distro_raises_valueerror", "malformed_uri_wsl_localhost_empty_distro_raises_valueerror", "malformed_uri_alt_vscode_empty_distro_raises_valueerror", "malformed_uri_wsl_localhost_root_only_raises_valueerror", "posix_on_linux_no_change", "vscode_remote_uri_on_macos_strips", "vscode_localhost_uri_on_linux_strips", "fallback_success_no_wslpath_env_var_exists_ok", "fallback_success_no_wslpath_default_distro_exists_ok", "fallback_success_no_wslpath_env_var_exists_false", "fallback_success_no_wslpath_default_distro_exists_false", "env_var_disables_posix", "env_var_disables_vscode_uri", ] ) def test_translate_wsl_path_parametrized( request, monkeypatch, input_path, mock_system, mock_find_wslpath_ret, mock_cached_wsl_ret, expected_output, env_vars, mock_default_distro, expected_fallback_exists_path, expected_exception_type, expected_exception_msg ): """Parametrized test covering various inputs for _translate_wsl_path.""" # --- Environment Variables --- orig_env = os.environ.copy() if env_vars: for k, v in env_vars.items(): monkeypatch.setenv(k, v) else: # Ensure potentially interfering env vars are unset monkeypatch.delenv("JINNI_NO_WSL_TRANSLATE", raising=False) monkeypatch.delenv("JINNI_ASSUME_WSL_DISTRO", raising=False) # --- System and Helper Mocks --- monkeypatch.setattr(platform, "system", mock_platform_system(mock_system)) monkeypatch.setattr("jinni.utils._find_wslpath", mock_find_wslpath(mock_find_wslpath_ret)) monkeypatch.setattr("jinni.utils._get_default_wsl_distro", mock_get_default_wsl_distro(mock_default_distro)) # Mock _cached_wsl_to_unc behavior based on parameters # If mock_cached_wsl_ret is None, it means the call should fail (return None) monkeypatch.setattr("jinni.utils._cached_wsl_to_unc", mock_cached_wsl_to_unc(mock_cached_wsl_ret)) # --- Mock Path.exists() specifically for fallback testing --- class MockPath: def __init__(self, path_str): self.path_str = str(path_str) def exists(self): # Called ONLY during the manual fallback logic in _translate_wsl_path # Return True only if the path matches the specific expected UNC path for fallback success tests if expected_fallback_exists_path is not None and self.path_str == expected_fallback_exists_path: return True return False # Default to False for all other cases (incl. fallback failure tests) # Determine if this test case involves the manual fallback logic for POSIX paths on Windows is_windows = mock_system.lower() == "windows" is_posix_input = isinstance(input_path, str) and input_path.startswith("/") and not urlparse(input_path).scheme # Fallback happens if wslpath isn't found OR if it is found but _cached_wsl_to_unc returns None triggers_fallback = is_windows and is_posix_input and (not mock_find_wslpath_ret or mock_cached_wsl_ret is None) if triggers_fallback: monkeypatch.setattr("jinni.utils.Path", MockPath) # --- Patch _get_default_wsl_distro for specific cases --- if request.node.callspec.id in [ "fallback_success_no_wslpath_env_var_exists_ok", "fallback_success_no_wslpath_env_var_exists_false", ]: monkeypatch.setattr("jinni.utils._get_default_wsl_distro", lambda: "TestDistro") # --- Perform the Call and Assert --- if expected_exception_type: # Expecting an exception with pytest.raises(expected_exception_type, match=expected_exception_msg): _translate_wsl_path(input_path) else: # Expecting a successful return value result = _translate_wsl_path(input_path) assert result == expected_output # Restore environment (optional, monkeypatch usually handles this) for k, v in orig_env.items(): os.environ[k] = v for k in env_vars if env_vars else {}: if k not in orig_env: monkeypatch.delenv(k, raising=False) # --- New Specific Test Cases --- def test_strip_wsl_localhost_uri_on_linux(monkeypatch): """Test vscode-remote wsl.localhost URI is stripped on Linux.""" monkeypatch.setattr(platform, "system", mock_platform_system("Linux")) uri = "vscode-remote://wsl.localhost/Debian/tmp/my project" expected_stripped_path = "/tmp/my project" assert _translate_wsl_path(uri) == expected_stripped_path def test_fallback_runtime_error(monkeypatch): """Test RuntimeError is raised on Windows when no wslpath and no fallback works (mocked Path.exists=False).""" monkeypatch.setattr(platform, "system", mock_platform_system("Windows")) monkeypatch.setattr("jinni.utils._find_wslpath", mock_find_wslpath(None)) # No wslpath monkeypatch.setattr("jinni.utils._get_default_wsl_distro", mock_get_default_wsl_distro(None)) # No default distro monkeypatch.delenv("JINNI_ASSUME_WSL_DISTRO", raising=False) # No env var # Mock Path.exists to always return False for the fallback check # Simpler mock is sufficient here class MockPathFalse: def __init__(self, path_str): pass def exists(self): return False monkeypatch.setattr("jinni.utils.Path", MockPathFalse) with pytest.raises(RuntimeError, match="Cannot map POSIX path"): _translate_wsl_path("/home/user/some/path") def test_malformed_uri_value_error(monkeypatch): """Test ValueError is raised for malformed URIs with missing distros.""" monkeypatch.setattr(platform, "system", mock_platform_system("Windows")) # Test vscode-remote://wsl+ with pytest.raises(ValueError, match="missing distro name in WSL URI"): _translate_wsl_path("vscode-remote://wsl+/home/user") # Test vscode-remote://wsl.localhost/ with pytest.raises(ValueError, match="missing distro name in wsl.localhost URI path"): _translate_wsl_path("vscode-remote://wsl.localhost//home/user") # Test vscode://vscode-remote/wsl+ with pytest.raises(ValueError, match="missing distro name in alternate vscode URI authority"): _translate_wsl_path("vscode://vscode-remote/wsl+/home/user") # Test wsl.localhost with only root / (missing distro) with pytest.raises(ValueError, match="missing or invalid distro/path in wsl.localhost URI path"): _translate_wsl_path("vscode-remote://wsl.localhost/") # --- Test ensure_no_nul utility --- def test_ensure_no_nul(): # Should not raise ensure_no_nul("abc", "test-field") # Should raise ValueError on NUL with pytest.raises(ValueError): ensure_no_nul("a\x00b", "test-field")

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/smat-dev/jinni'

If you have feedback or need assistance with the MCP directory API, please join our Discord server