Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/uvlink/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ def get_uvlink_dir(*subpaths: str | Path) -> Path:
Returns:
Path: Absolute path to the uvlink data directory or provided subpath.
"""
base = Path(os.environ.get("XDG_DATA_HOME", "~/.local/share")).expanduser()
default_path = Path.home() / ".local" / "share"
base = Path(os.environ.get("XDG_DATA_HOME", default_path)).expanduser()
root = base / "uvlink"
for sp in subpaths:
root /= Path(sp)
Expand Down
3 changes: 1 addition & 2 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,7 @@ def test_ls(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
assert "Is Linked" in result.stdout

# Verify cache location message
assert "Cache Location:" in result.stdout
assert "uvlink/cache" in result.stdout
assert f"Cache Location: {cache_dir}" in result.stdout

# Verify both projects appear and have correct linked status
output_lines = result.stdout.split("\n")
Expand Down
35 changes: 35 additions & 0 deletions tests/test_path_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from pathlib import Path

import pytest

from uvlink.path_utils import create_symlink, create_windows_junction, is_windows


def test_create_symlink(tmp_path: Path):
target_dir = tmp_path / "target"
symlink_dir = tmp_path / "symlink"
create_symlink(symlink=symlink_dir, target=target_dir)

assert symlink_dir.exists()
assert symlink_dir.is_symlink() or (is_windows() and symlink_dir.is_junction())
assert symlink_dir.resolve() == target_dir.resolve()


@pytest.mark.skipif(
not is_windows(), reason="Windows junctions are only applicable on Windows."
)
def test_create_windows_junction(tmp_path: Path):
target_dir = tmp_path
symlink_dir = tmp_path / "symlink"
create_windows_junction(symlink=symlink_dir, target=target_dir)

assert symlink_dir.exists()
assert symlink_dir.is_junction()
assert symlink_dir.resolve() == target_dir.resolve()


def test_create_windows_junction_invalid_target(tmp_path: Path):
with pytest.raises(ValueError):
create_windows_junction(
symlink=tmp_path / "any", target=tmp_path / "nonexistent"
)
42 changes: 20 additions & 22 deletions tests/test_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,39 @@

import pytest

from uvlink.path_utils import create_symlink
from uvlink.path_utils import create_symlink, is_windows
from uvlink.project import Project


class TestProject:
def test_hash_path(self):
assert Project.hash_path("/") == "8a5edab28263"
expected_hash = "d0023e7cb6a9" if is_windows() else "8a5edab28263"
assert Project.hash_path("/") == expected_hash

def test_project_init_path_resolution_with_tilde(self) -> None:
"""Test with tilde expansion and parent directory (e.g., "~/../xxx")."""
user_home_path = Path.home()
test_dir = user_home_path / "test_project"

# Test ~/test_project resolves correctly
p2 = Project(project_dir="~/test_project")
assert p2.project_dir == test_dir.resolve()
assert p2.project_dir.is_absolute()

# Test ~/.. resolves to parent of HOME
p3 = Project(project_dir="~/..")
assert p3.project_dir == user_home_path.parent.resolve()
assert p3.project_dir.is_absolute()

def test_project_init(self, tmp_path: Path) -> None:
p = Project(project_dir=tmp_path)
# Project.resolve() normalizes the path, so compare with resolved tmp_path
assert p.project_dir == tmp_path.resolve()
assert p.project_name == tmp_path.name
assert p.venv_type == ".venv"
assert "uvlink/cache" in str(p.project_cache_dir)
assert "uvlink/cache" in p.project_cache_dir.as_posix()

def test_project_init_path_resolution(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
def test_project_init_path_resolution(self, tmp_path: Path) -> None:
"""Test that Project resolves relative paths and parent directory references."""
# Create a subdirectory to test relative paths with parent directory references
subdir = tmp_path / "subdir" / "nested"
Expand All @@ -37,22 +51,6 @@ def test_project_init_path_resolution(
assert p1.project_dir.is_absolute()
assert p1.project_name == tmp_path.name

# Test with tilde expansion and parent directory (e.g., "~/../xxx")
# Mock HOME to be tmp_path for reliable testing
monkeypatch.setenv("HOME", str(tmp_path))
test_dir = tmp_path / "test_project"
test_dir.mkdir(exist_ok=True)

# Test ~/test_project resolves correctly
p2 = Project(project_dir="~/test_project")
assert p2.project_dir == test_dir.resolve()
assert p2.project_dir.is_absolute()

# Test ~/.. resolves to parent of HOME
p3 = Project(project_dir="~/..")
assert p3.project_dir == tmp_path.parent.resolve()
assert p3.project_dir.is_absolute()

# Test symlink resolution
# Create a target directory and a symlink pointing to it
target_dir = tmp_path / "target"
Expand Down