test_redundant_test_docstring.py
1 from pathlib import Path 2 3 from clint.config import Config 4 from clint.index import SymbolIndex 5 from clint.linter import lint_file 6 from clint.rules.redundant_test_docstring import RedundantTestDocstring 7 8 9 def test_redundant_docstrings_are_flagged(index: SymbolIndex) -> None: 10 code = ''' 11 def test_feature_a(): 12 """ 13 This test verifies that feature A works correctly. 14 It has multiple lines of documentation. 15 """ 16 assert True 17 18 def test_feature_behavior(): 19 """Test feature.""" 20 assert True 21 22 def test_c(): 23 """Test the complex interaction between modules.""" 24 assert True 25 26 def test_validation_logic(): 27 """Test validation.""" 28 assert True 29 30 def test_feature_d(): 31 assert True 32 ''' 33 34 config = Config(select={RedundantTestDocstring.name}) 35 violations = lint_file(Path("test_something.py"), code, config, index) 36 # All single-line docstrings should be flagged 37 # (test_feature_behavior, test_c, and test_validation_logic) 38 assert len(violations) == 3 39 assert all(isinstance(v.rule, RedundantTestDocstring) for v in violations) 40 41 42 def test_docstring_word_overlap(index: SymbolIndex) -> None: 43 code = ''' 44 def test_very_long_function_name(): 45 """Short.""" 46 assert True 47 48 def test_short(): 49 """This is a much longer docstring than the function name.""" 50 assert True 51 52 def test_data_validation(): 53 """Test data validation""" 54 assert True 55 56 def test_multi(): 57 """Line 1 58 Line 2""" 59 assert True 60 61 def test_foo_bar_baz(): 62 """Test qux.""" 63 assert True 64 ''' 65 66 config = Config(select={RedundantTestDocstring.name}) 67 violations = lint_file(Path("test_length.py"), code, config, index) 68 # All single-line docstrings should be flagged 69 # (test_very_long_function_name, test_short, test_data_validation, test_foo_bar_baz) 70 assert len(violations) == 4 71 72 73 def test_class_docstrings_follow_same_rules(index: SymbolIndex) -> None: 74 code = ''' 75 class TestFeature: 76 """ 77 Tests for the Feature module. 78 Includes comprehensive test coverage. 79 """ 80 def test_method(self): 81 assert True 82 83 class TestFeatureImplementation: 84 """Test feature.""" 85 pass 86 87 class TestShort: 88 """This is a longer docstring than the class name TestShort.""" 89 pass 90 ''' 91 92 config = Config(select={RedundantTestDocstring.name}) 93 violations = lint_file(Path("test_classes.py"), code, config, index) 94 # Both classes with single-line docstrings should be flagged 95 assert len(violations) == 2 96 97 98 def test_non_test_files_are_ignored(index: SymbolIndex) -> None: 99 code = ''' 100 def test_something(): 101 """Short.""" 102 assert True 103 104 class TestFeature: 105 """Test.""" 106 pass 107 ''' 108 109 config = Config(select={RedundantTestDocstring.name}) 110 violations = lint_file(Path("regular_module.py"), code, config, index) 111 assert len(violations) == 0 112 113 114 def test_supports_test_suffix_files(index: SymbolIndex) -> None: 115 code = ''' 116 def test_feature_implementation(): 117 """Test feature.""" 118 assert True 119 120 class TestClassImplementation: 121 """Test class.""" 122 pass 123 ''' 124 125 config = Config(select={RedundantTestDocstring.name}) 126 violations = lint_file(Path("module_test.py"), code, config, index) 127 assert len(violations) == 2 128 129 130 def test_multiline_docstrings_are_always_allowed(index: SymbolIndex) -> None: 131 code = '''def test_with_multiline(): 132 """ 133 Multi-line. 134 """ 135 assert True 136 137 def test_with_multiline_compact(): 138 """Line 1 139 Line 2""" 140 assert True 141 142 class TestWithMultilineDoc: 143 """ 144 Multi 145 Line 146 """ 147 pass 148 149 class TestCompactMultiline: 150 """Line1 151 Line2""" 152 pass 153 ''' 154 155 config = Config(select={RedundantTestDocstring.name}) 156 violations = lint_file(Path("test_multiline.py"), code, config, index) 157 assert len(violations) == 0 158 159 160 def test_error_message_content(index: SymbolIndex) -> None: 161 code = '''def test_data_processing_validation(): 162 """Test data processing.""" 163 pass 164 165 class TestDataProcessingValidation: 166 """Test data processing.""" 167 pass 168 ''' 169 170 config = Config(select={RedundantTestDocstring.name}) 171 violations = lint_file(Path("test_messages.py"), code, config, index) 172 assert len(violations) == 2 173 174 func_violation = violations[0] 175 assert "rarely provide meaningful context" in func_violation.rule.message 176 assert "Consider removing it" in func_violation.rule.message 177 178 class_violation = violations[1] 179 assert "rarely provide meaningful context" in class_violation.rule.message 180 assert "Consider removing it" in class_violation.rule.message 181 182 183 def test_module_single_line_docstrings_are_flagged(index: SymbolIndex) -> None: 184 code = '''"""This is a test module.""" 185 def test_something(): 186 assert True 187 ''' 188 189 config = Config(select={RedundantTestDocstring.name}) 190 violations = lint_file(Path("test_module.py"), code, config, index) 191 assert len(violations) == 1 192 assert isinstance(violations[0].rule, RedundantTestDocstring) 193 assert "rarely provide meaningful context" in violations[0].rule.message 194 195 196 def test_module_multiline_docstrings_are_allowed(index: SymbolIndex) -> None: 197 code = '''""" 198 This is a test module. 199 It has multiple lines. 200 """ 201 def test_something(): 202 assert True 203 ''' 204 205 config = Config(select={RedundantTestDocstring.name}) 206 violations = lint_file(Path("test_module.py"), code, config, index) 207 assert len(violations) == 0 208 209 210 def test_module_without_docstring_is_not_flagged(index: SymbolIndex) -> None: 211 code = """def test_something(): 212 assert True 213 """ 214 215 config = Config(select={RedundantTestDocstring.name}) 216 violations = lint_file(Path("test_module.py"), code, config, index) 217 assert len(violations) == 0 218 219 220 def test_non_test_module_docstrings_are_ignored(index: SymbolIndex) -> None: 221 code = '''"""This is a regular module.""" 222 def some_function(): 223 pass 224 ''' 225 226 config = Config(select={RedundantTestDocstring.name}) 227 violations = lint_file(Path("regular_module.py"), code, config, index) 228 assert len(violations) == 0