Coverage for tests / integration / conftest.py: 68%

38 statements  

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

1"""Shared fixtures for integration tests.""" 

2 

3import os 

4import tempfile 

5from collections.abc import Callable, Generator 

6from pathlib import Path 

7 

8import pytest 

9 

10 

11@pytest.fixture 

12def temp_project_dir() -> Generator[Path, None, None]: 

13 """Create a temporary directory structure for integration testing. 

14 

15 Yields: 

16 Path: Path to the temporary project directory. 

17 """ 

18 with tempfile.TemporaryDirectory() as tmpdir: 

19 project_dir = Path(tmpdir) 

20 # Create a basic project structure 

21 (project_dir / "pyproject.toml").write_text( 

22 """[tool.lintro] 

23line_length = 88 

24 

25[tool.ruff] 

26line-length = 88 

27""", 

28 ) 

29 (project_dir / "src").mkdir() 

30 (project_dir / "tests").mkdir() 

31 

32 # Change to the temp directory for the test 

33 original_cwd = os.getcwd() 

34 os.chdir(project_dir) 

35 try: 

36 yield project_dir 

37 finally: 

38 os.chdir(original_cwd) 

39 

40 

41@pytest.fixture 

42def lintro_test_mode(monkeypatch: pytest.MonkeyPatch) -> str: 

43 """Set LINTRO_TEST_MODE=1 environment variable for tests. 

44 

45 This disables config injection and other test-incompatible features. 

46 

47 Args: 

48 monkeypatch: Pytest monkeypatch fixture for environment manipulation. 

49 

50 Returns: 

51 str: The test mode value that was set. 

52 """ 

53 monkeypatch.setenv("LINTRO_TEST_MODE", "1") 

54 return "1" 

55 

56 

57@pytest.fixture 

58def skip_if_tool_unavailable() -> Callable[[str], None]: 

59 """Skip test if required tool is not available in PATH. 

60 

61 Returns: 

62 callable: Function that takes a tool_name (str) parameter and can be used 

63 to skip tests for unavailable tools. 

64 """ 

65 

66 def _skip_if_unavailable(tool_name: str) -> None: 

67 """Skip the current test if tool is not available. 

68 

69 Args: 

70 tool_name: Name of the tool to check for availability. 

71 """ 

72 import shutil 

73 

74 if not shutil.which(tool_name): 

75 pytest.skip(f"Tool '{tool_name}' not available in PATH") 

76 

77 return _skip_if_unavailable 

78 

79 

80@pytest.fixture 

81def get_plugin(lintro_test_mode: str) -> Callable[[str], object]: 

82 """Factory fixture to get a fresh plugin instance by name. 

83 

84 This fixture ensures LINTRO_TEST_MODE is set before getting the plugin, 

85 which disables config injection and other test-incompatible features. 

86 

87 Creates a fresh instance to avoid test pollution from shared state. 

88 

89 Args: 

90 lintro_test_mode: The test mode fixture (dependency). 

91 

92 Returns: 

93 callable: Function that takes a tool name and returns a fresh plugin instance. 

94 """ 

95 from lintro.plugins.registry import ToolRegistry 

96 

97 def _get_plugin(name: str) -> object: 

98 """Get a fresh plugin instance by name. 

99 

100 Args: 

101 name: Name of the tool to get. 

102 

103 Returns: 

104 A fresh plugin instance (not the cached singleton). 

105 """ 

106 name_lower = name.lower() 

107 # Get the class from the registry and create a new instance 

108 # to avoid test pollution from modified options on the cached instance 

109 if name_lower not in ToolRegistry._tools: 

110 ToolRegistry._ensure_discovered() 

111 plugin_class = ToolRegistry._tools[name_lower] 

112 return plugin_class() 

113 

114 return _get_plugin