Coverage for tests / config / test_init_command.py: 100%

67 statements  

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

1"""Tests for lintro init command.""" 

2 

3from pathlib import Path 

4 

5import pytest 

6from assertpy import assert_that 

7from click.testing import CliRunner 

8 

9from lintro.cli_utils.commands.init import ( 

10 DEFAULT_CONFIG_TEMPLATE, 

11 MINIMAL_CONFIG_TEMPLATE, 

12 init_command, 

13) 

14 

15 

16@pytest.fixture 

17def runner() -> CliRunner: 

18 """Create a Click test runner. 

19 

20 Returns: 

21 CliRunner: A Click test runner instance. 

22 """ 

23 return CliRunner() 

24 

25 

26def test_creates_minimal_template( 

27 runner: CliRunner, 

28 tmp_path: Path, 

29) -> None: 

30 """Should use minimal template with --minimal flag. 

31 

32 Args: 

33 runner: Click test runner instance. 

34 tmp_path: Temporary directory path for test files. 

35 """ 

36 with runner.isolated_filesystem(temp_dir=tmp_path): 

37 runner.invoke(init_command, ["--minimal"]) 

38 

39 config_file = Path(".lintro-config.yaml") 

40 content = config_file.read_text() 

41 

42 # Minimal template should be shorter 

43 assert_that(content).contains("# Lintro Configuration (Minimal)") 

44 # But still have core sections 

45 assert_that(content).contains("enforce:") 

46 assert_that(content).contains("tools:") 

47 # Minimal doesn't have all tools 

48 assert_that(content).does_not_contain("bandit:") 

49 

50 

51def test_refuses_to_overwrite_existing( 

52 runner: CliRunner, 

53 tmp_path: Path, 

54) -> None: 

55 """Should refuse to overwrite existing file without --force. 

56 

57 Args: 

58 runner: Click test runner instance. 

59 tmp_path: Temporary directory path for test files. 

60 """ 

61 with runner.isolated_filesystem(temp_dir=tmp_path): 

62 # Create existing file 

63 Path(".lintro-config.yaml").write_text("existing content") 

64 

65 result = runner.invoke(init_command) 

66 

67 assert_that(result.exit_code).is_equal_to(1) 

68 assert_that(result.output).contains("already exists") 

69 assert_that(result.output).contains("Use --force to overwrite") 

70 

71 # Original content should be preserved 

72 content = Path(".lintro-config.yaml").read_text() 

73 assert_that(content).is_equal_to("existing content") 

74 

75 

76def test_force_overwrites_existing( 

77 runner: CliRunner, 

78 tmp_path: Path, 

79) -> None: 

80 """Should overwrite existing file with --force. 

81 

82 Args: 

83 runner: Click test runner instance. 

84 tmp_path: Temporary directory path for test files. 

85 """ 

86 with runner.isolated_filesystem(temp_dir=tmp_path): 

87 # Create existing file 

88 Path(".lintro-config.yaml").write_text("existing content") 

89 

90 result = runner.invoke(init_command, ["--force"]) 

91 

92 assert_that(result.exit_code).is_equal_to(0) 

93 assert_that(result.output).contains("Created .lintro-config.yaml") 

94 

95 # Should have new template content 

96 content = Path(".lintro-config.yaml").read_text() 

97 assert_that(content).contains("enforce:") 

98 

99 

100def test_custom_output_path( 

101 runner: CliRunner, 

102 tmp_path: Path, 

103) -> None: 

104 """Should create file at custom path with --output. 

105 

106 Args: 

107 runner: Click test runner instance. 

108 tmp_path: Temporary directory path for test files. 

109 """ 

110 with runner.isolated_filesystem(temp_dir=tmp_path): 

111 result = runner.invoke( 

112 init_command, 

113 ["--output", "custom-config.yaml"], 

114 ) 

115 

116 assert_that(result.exit_code).is_equal_to(0) 

117 assert_that(result.output).contains("Created custom-config.yaml") 

118 

119 config_file = Path("custom-config.yaml") 

120 assert_that(config_file.exists()).is_true() 

121 

122 

123def test_shows_next_steps( 

124 runner: CliRunner, 

125 tmp_path: Path, 

126) -> None: 

127 """Should show helpful next steps. 

128 

129 Args: 

130 runner: Click test runner instance. 

131 tmp_path: Temporary directory path for test files. 

132 """ 

133 with runner.isolated_filesystem(temp_dir=tmp_path): 

134 result = runner.invoke(init_command) 

135 

136 assert_that(result.output).contains("Next steps:") 

137 assert_that(result.output).contains("lintro config") 

138 assert_that(result.output).contains("lintro check") 

139 

140 

141def test_default_template_is_valid_yaml() -> None: 

142 """Default template should be valid YAML.""" 

143 import yaml 

144 

145 parsed = yaml.safe_load(DEFAULT_CONFIG_TEMPLATE) 

146 

147 assert_that(parsed).contains("enforce") 

148 assert_that(parsed).contains("execution") 

149 assert_that(parsed).contains("tools") 

150 

151 

152def test_minimal_template_is_valid_yaml() -> None: 

153 """Minimal template should be valid YAML.""" 

154 import yaml 

155 

156 parsed = yaml.safe_load(MINIMAL_CONFIG_TEMPLATE) 

157 

158 assert_that(parsed).contains("enforce") 

159 assert_that(parsed).contains("tools") 

160 

161 

162def test_default_template_has_sensible_defaults() -> None: 

163 """Default template should have sensible default values.""" 

164 import yaml 

165 

166 parsed = yaml.safe_load(DEFAULT_CONFIG_TEMPLATE) 

167 

168 assert_that(parsed["enforce"]["line_length"]).is_equal_to(88) 

169 assert_that(parsed["enforce"]["target_python"]).is_equal_to("py313") 

170 assert_that(parsed["execution"]["tool_order"]).is_equal_to("priority") 

171 assert_that(parsed["tools"]["ruff"]["enabled"]).is_true() 

172 assert_that(parsed["defaults"]["mypy"]["strict"]).is_true() 

173 assert_that(parsed["defaults"]["mypy"]["ignore_missing_imports"]).is_true()