Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
33 changes: 33 additions & 0 deletions tests/test_path_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
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=Path("any"), target=tmp_path / "nonexistent")
45 changes: 23 additions & 22 deletions tests/test_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,42 @@

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"
assert (
Project.hash_path("/") == "8a5edab28263"
if not is_windows()
else "c1dfd96eea9"
)

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 +54,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