Coverage for tests / unit / ai / test_paths.py: 100%

43 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2026-04-03 18:53 +0000

1"""Tests for AI path utilities.""" 

2 

3from __future__ import annotations 

4 

5import os 

6from pathlib import PurePosixPath 

7 

8from assertpy import assert_that 

9 

10from lintro.ai.paths import ( 

11 OUTSIDE_WORKSPACE_SENTINEL, 

12 relative_path, 

13 resolve_workspace_file, 

14 resolve_workspace_root, 

15 to_provider_path, 

16) 

17 

18 

19def _normalize(path: str) -> str: 

20 """Normalize a path to POSIX form for cross-platform comparison.""" 

21 return str(PurePosixPath(path.replace("\\", "/"))) 

22 

23 

24def test_paths_relative_for_cwd_child(): 

25 """Verify absolute path under cwd is converted to a relative path.""" 

26 cwd = os.getcwd() 

27 abs_path = os.path.join(cwd, "src", "main.py") 

28 result = relative_path(abs_path) 

29 assert_that(_normalize(result)).is_equal_to("src/main.py") 

30 

31 

32def test_paths_already_relative(): 

33 """Verify an already-relative path is returned unchanged.""" 

34 result = relative_path("src/main.py") 

35 assert_that(_normalize(result)).is_equal_to("src/main.py") 

36 

37 

38def test_paths_relative_on_empty(): 

39 """Verify relative_path handles an empty string without raising.""" 

40 result = relative_path("") 

41 assert_that(result).is_type_of(str) 

42 

43 

44def test_paths_resolve_workspace_root_from_config(tmp_path): 

45 """Verify workspace root is resolved as the parent directory of the config file.""" 

46 config = tmp_path / ".lintro-config.yaml" 

47 config.write_text("ai:\n enabled: true\n", encoding="utf-8") 

48 

49 root = resolve_workspace_root(str(config)) 

50 assert_that(root).is_equal_to(tmp_path.resolve()) 

51 

52 

53def test_paths_resolve_workspace_file_accepts_inside(tmp_path): 

54 """Verify a file inside the workspace root resolves successfully.""" 

55 inside = tmp_path / "src" / "main.py" 

56 inside.parent.mkdir(parents=True) 

57 inside.write_text("x = 1\n", encoding="utf-8") 

58 

59 resolved = resolve_workspace_file(str(inside), tmp_path) 

60 assert_that(resolved).is_equal_to(inside.resolve()) 

61 

62 

63def test_paths_resolve_workspace_file_rejects_outside(tmp_path): 

64 """Paths outside the workspace root are rejected.""" 

65 outside = tmp_path.parent / "outside-lintro-paths.py" 

66 resolved = resolve_workspace_file(str(outside), tmp_path) 

67 assert_that(resolved).is_none() 

68 

69 

70def test_paths_to_provider_path_is_workspace_relative(tmp_path): 

71 """Verify to_provider_path returns a workspace-relative path.""" 

72 file_path = tmp_path / "pkg" / "module.py" 

73 file_path.parent.mkdir(parents=True) 

74 file_path.write_text("x = 1\n", encoding="utf-8") 

75 

76 provider_path = to_provider_path(str(file_path), tmp_path) 

77 assert_that(_normalize(provider_path)).is_equal_to("pkg/module.py") 

78 

79 

80def test_paths_to_provider_path_falls_back_without_leaking_absolute(tmp_path): 

81 """Absolute paths outside workspace return the sentinel marker.""" 

82 outside_path = str(tmp_path.parent / "secret" / "main.py") 

83 provider_path = to_provider_path(outside_path, tmp_path) 

84 assert_that(provider_path).is_equal_to(OUTSIDE_WORKSPACE_SENTINEL)