-
Notifications
You must be signed in to change notification settings - Fork 58
Expand file tree
/
Copy pathtest_rule_manager.py
More file actions
312 lines (219 loc) · 11.7 KB
/
Copy pathtest_rule_manager.py
File metadata and controls
312 lines (219 loc) · 11.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
import pytest
from pathlib import Path
from unittest.mock import patch, MagicMock
from notebook_intelligence.rule_manager import RuleManager
from notebook_intelligence.ruleset import Rule, RuleSet, RuleContext
class TestRuleManager:
def test_init(self, temp_rules_directory):
manager = RuleManager(temp_rules_directory)
assert str(manager.rules_directory) == temp_rules_directory
assert isinstance(manager.ruleset, RuleSet)
assert manager._loaded is False
def test_discover_rules_empty_directory(self, temp_rules_directory):
manager = RuleManager(temp_rules_directory)
rules = manager.discover_rules()
assert len(rules) == 0
def test_discover_rules_nonexistent_directory(self, tmp_path):
nonexistent_dir = tmp_path / "nonexistent"
manager = RuleManager(str(nonexistent_dir))
rules = manager.discover_rules()
assert len(rules) == 0
def test_discover_rules_with_populated_directory(self, populated_rules_directory):
manager = RuleManager(populated_rules_directory)
rules = manager.discover_rules()
# Should find 2 global rules + 2 mode-specific rules
assert len(rules) == 4
# Check that rules are sorted by filename
filenames = [rule.filename for rule in rules]
assert filenames == sorted(filenames)
def test_load_global_rules(self, populated_rules_directory):
manager = RuleManager(populated_rules_directory)
rules_path = Path(populated_rules_directory)
global_rules = manager._load_global_rules(rules_path)
assert len(global_rules) == 2
assert all(rule.mode is None for rule in global_rules)
# Check specific rules
python_rule = next((r for r in global_rules if "python" in r.filename), None)
assert python_rule is not None
assert "Python Best Practices" in python_rule.content
def test_load_mode_rules(self, populated_rules_directory):
manager = RuleManager(populated_rules_directory)
rules_path = Path(populated_rules_directory)
mode_rules = manager._load_mode_rules(rules_path)
assert len(mode_rules) == 2
# Check mode assignments
ask_rules = [r for r in mode_rules if r.mode == "ask"]
agent_rules = [r for r in mode_rules if r.mode == "agent"]
assert len(ask_rules) == 1
assert len(agent_rules) == 1
assert "Ask Mode Guidelines" in ask_rules[0].content
assert "Agent Mode Standards" in agent_rules[0].content
def test_load_mode_rules_no_modes_directory(self, temp_rules_directory):
manager = RuleManager(temp_rules_directory)
rules_path = Path(temp_rules_directory)
mode_rules = manager._load_mode_rules(rules_path)
assert len(mode_rules) == 0
def test_load_mode_rules_invalid_mode_directory(self, temp_rules_directory):
# Create an invalid mode directory
rules_path = Path(temp_rules_directory)
invalid_mode_dir = rules_path / "modes" / "invalid_mode"
invalid_mode_dir.mkdir(parents=True)
# Add a rule file in the invalid mode
rule_content = """---
apply: always
active: true
---
# Invalid mode rule"""
with open(invalid_mode_dir / "invalid.md", 'w') as f:
f.write(rule_content)
manager = RuleManager(temp_rules_directory)
with patch('notebook_intelligence.rule_manager.log') as mock_log:
mode_rules = manager._load_mode_rules(rules_path)
# Should skip invalid mode and log warning
assert len(mode_rules) == 0
mock_log.warning.assert_called()
def test_load_rules(self, populated_rules_directory):
manager = RuleManager(populated_rules_directory)
ruleset = manager.load_rules()
assert manager._loaded is True
assert isinstance(ruleset, RuleSet)
assert len(ruleset.global_rules) == 2
assert "ask" in ruleset.mode_rules
assert "agent" in ruleset.mode_rules
assert len(ruleset.mode_rules["ask"]) == 1
assert len(ruleset.mode_rules["agent"]) == 1
def test_load_rules_force_reload(self, populated_rules_directory):
manager = RuleManager(populated_rules_directory)
# Load rules first time
first_ruleset = manager.load_rules()
assert manager._loaded is True
# Load again without force_reload (should return cached)
second_ruleset = manager.load_rules()
assert second_ruleset is first_ruleset
# Force reload should create new ruleset
third_ruleset = manager.load_rules(force_reload=True)
assert third_ruleset is not first_ruleset
assert len(third_ruleset.get_all_rules()) == len(first_ruleset.get_all_rules())
def test_get_applicable_rules(self, populated_rules_directory, sample_rule_context):
manager = RuleManager(populated_rules_directory)
applicable_rules = manager.get_applicable_rules(sample_rule_context)
# Should get global rules + ask mode rules that match *.ipynb
assert len(applicable_rules) > 0
# Check that we get both global and mode-specific rules
rule_modes = {rule.mode for rule in applicable_rules}
assert None in rule_modes # Global rules
assert "ask" in rule_modes # Ask mode rules
def test_get_applicable_rules_auto_loads(self, populated_rules_directory, sample_rule_context):
manager = RuleManager(populated_rules_directory)
assert manager._loaded is False
# Getting applicable rules should auto-load
applicable_rules = manager.get_applicable_rules(sample_rule_context)
assert manager._loaded is True
assert isinstance(applicable_rules, list)
def test_validate_rule_file_valid(self, populated_rules_directory):
manager = RuleManager(populated_rules_directory)
rule_file = Path(populated_rules_directory) / "01-python.md"
result = manager.validate_rule_file(str(rule_file))
assert result['valid'] is True
assert len(result['errors']) == 0
assert result['rule'] is not None
assert isinstance(result['rule'], Rule)
def test_validate_rule_file_nonexistent(self, temp_rules_directory):
manager = RuleManager(temp_rules_directory)
result = manager.validate_rule_file("nonexistent.md")
assert result['valid'] is False
assert len(result['errors']) == 1
assert "File not found" in result['errors'][0]
def test_validate_rule_file_invalid_yaml(self, invalid_rules_directory):
manager = RuleManager(invalid_rules_directory)
rule_file = Path(invalid_rules_directory) / "invalid-yaml.md"
result = manager.validate_rule_file(str(rule_file))
assert result['valid'] is False
assert len(result['errors']) == 1
assert "Invalid rule format" in result['errors'][0]
def test_validate_rule_file_no_content_warning(self, tmp_path):
# Create rule with empty content
rule_content = """---
apply: always
active: true
---
"""
rule_file = tmp_path / "empty_content.md"
rule_file.write_text(rule_content)
manager = RuleManager(str(tmp_path))
result = manager.validate_rule_file(str(rule_file))
assert result['valid'] is True
assert len(result['warnings']) >= 1 # May have multiple warnings
assert any("no content" in warning for warning in result['warnings'])
def test_get_rule_by_filename(self, populated_rules_directory):
manager = RuleManager(populated_rules_directory)
rule = manager.get_rule_by_filename("01-python.md")
assert rule is not None
assert rule.filename == "01-python.md"
assert "Python Best Practices" in rule.content
def test_get_rule_by_filename_not_found(self, populated_rules_directory):
manager = RuleManager(populated_rules_directory)
rule = manager.get_rule_by_filename("nonexistent.md")
assert rule is None
def test_toggle_rule(self, populated_rules_directory):
manager = RuleManager(populated_rules_directory)
manager.load_rules()
# Find a rule to toggle
rule = manager.get_rule_by_filename("01-python.md")
original_state = rule.active
# Toggle the rule
result = manager.toggle_rule("01-python.md", not original_state)
assert result is True
assert rule.active == (not original_state)
def test_toggle_rule_not_found(self, populated_rules_directory):
manager = RuleManager(populated_rules_directory)
result = manager.toggle_rule("nonexistent.md", False)
assert result is False
def test_get_rules_summary(self, populated_rules_directory):
manager = RuleManager(populated_rules_directory)
summary = manager.get_rules_summary()
assert summary['total_rules'] == 4
assert summary['active_rules'] == 4 # All rules are active by default
assert summary['global_rules'] == 2
assert 'ask' in summary['mode_rules']
assert 'agent' in summary['mode_rules']
assert summary['rules_directory'] == populated_rules_directory
def test_format_rules_for_llm_empty_list(self, temp_rules_directory):
manager = RuleManager(temp_rules_directory)
formatted = manager.format_rules_for_llm([])
assert formatted == ""
def test_format_rules_for_llm_with_rules(self, populated_rules_directory):
manager = RuleManager(populated_rules_directory)
manager.load_rules()
# Get some rules to format - use .ipynb file to match ask mode rules
context = RuleContext(filename="test.ipynb", mode="ask")
applicable_rules = manager.get_applicable_rules(context)
formatted = manager.format_rules_for_llm(applicable_rules)
assert "# Global Rules" in formatted
# Check that we have content from the rules
assert "Python Best Practices" in formatted
# May or may not have ask mode rules depending on file patterns
assert len(formatted) > 0
class TestRuleManagerErrorHandling:
def test_load_rules_with_invalid_files(self, invalid_rules_directory):
manager = RuleManager(invalid_rules_directory)
with patch('notebook_intelligence.rule_manager.log') as mock_log:
rules = manager.discover_rules()
# Should handle invalid files gracefully
mock_log.error.assert_called()
# Should still return rules that could be loaded
assert isinstance(rules, list)
def test_load_rules_with_permission_error(self, tmp_path):
# Create a rules directory we can't read
rules_dir = tmp_path / "no_permission"
rules_dir.mkdir()
# Create a rule file
rule_file = rules_dir / "test.md"
rule_file.write_text("# Test rule")
manager = RuleManager(str(rules_dir))
# Mock a permission error
with patch('pathlib.Path.glob', side_effect=PermissionError("Permission denied")):
with patch('notebook_intelligence.rule_manager.log') as mock_log:
rules = manager._load_global_rules(rules_dir)
# Should handle permission errors gracefully
assert len(rules) == 0