fishertools 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. fishertools/__init__.py +82 -0
  2. fishertools/config/__init__.py +24 -0
  3. fishertools/config/manager.py +247 -0
  4. fishertools/config/models.py +96 -0
  5. fishertools/config/parser.py +265 -0
  6. fishertools/decorators.py +93 -0
  7. fishertools/documentation/__init__.py +38 -0
  8. fishertools/documentation/api.py +242 -0
  9. fishertools/documentation/generator.py +502 -0
  10. fishertools/documentation/models.py +126 -0
  11. fishertools/documentation/visual.py +583 -0
  12. fishertools/errors/__init__.py +29 -0
  13. fishertools/errors/exceptions.py +191 -0
  14. fishertools/errors/explainer.py +303 -0
  15. fishertools/errors/formatters.py +386 -0
  16. fishertools/errors/models.py +228 -0
  17. fishertools/errors/patterns.py +119 -0
  18. fishertools/errors/recovery.py +467 -0
  19. fishertools/examples/__init__.py +22 -0
  20. fishertools/examples/models.py +118 -0
  21. fishertools/examples/repository.py +770 -0
  22. fishertools/helpers.py +116 -0
  23. fishertools/integration.py +451 -0
  24. fishertools/learn/__init__.py +18 -0
  25. fishertools/learn/examples.py +550 -0
  26. fishertools/learn/tips.py +281 -0
  27. fishertools/learning/__init__.py +32 -0
  28. fishertools/learning/core.py +349 -0
  29. fishertools/learning/models.py +112 -0
  30. fishertools/learning/progress.py +314 -0
  31. fishertools/learning/session.py +500 -0
  32. fishertools/learning/tutorial.py +626 -0
  33. fishertools/legacy/__init__.py +76 -0
  34. fishertools/legacy/deprecated.py +261 -0
  35. fishertools/legacy/deprecation.py +149 -0
  36. fishertools/safe/__init__.py +16 -0
  37. fishertools/safe/collections.py +242 -0
  38. fishertools/safe/files.py +240 -0
  39. fishertools/safe/strings.py +15 -0
  40. fishertools/utils.py +57 -0
  41. fishertools-0.2.1.dist-info/METADATA +256 -0
  42. fishertools-0.2.1.dist-info/RECORD +81 -0
  43. fishertools-0.2.1.dist-info/WHEEL +5 -0
  44. fishertools-0.2.1.dist-info/licenses/LICENSE +21 -0
  45. fishertools-0.2.1.dist-info/top_level.txt +2 -0
  46. tests/__init__.py +6 -0
  47. tests/conftest.py +25 -0
  48. tests/test_config/__init__.py +3 -0
  49. tests/test_config/test_basic_config.py +57 -0
  50. tests/test_config/test_config_error_handling.py +287 -0
  51. tests/test_config/test_config_properties.py +435 -0
  52. tests/test_documentation/__init__.py +3 -0
  53. tests/test_documentation/test_documentation_properties.py +253 -0
  54. tests/test_documentation/test_visual_documentation_properties.py +444 -0
  55. tests/test_errors/__init__.py +3 -0
  56. tests/test_errors/test_api.py +301 -0
  57. tests/test_errors/test_error_handling.py +354 -0
  58. tests/test_errors/test_explainer.py +173 -0
  59. tests/test_errors/test_formatters.py +338 -0
  60. tests/test_errors/test_models.py +248 -0
  61. tests/test_errors/test_patterns.py +270 -0
  62. tests/test_examples/__init__.py +3 -0
  63. tests/test_examples/test_example_repository_properties.py +204 -0
  64. tests/test_examples/test_specific_examples.py +303 -0
  65. tests/test_integration.py +298 -0
  66. tests/test_integration_enhancements.py +462 -0
  67. tests/test_learn/__init__.py +3 -0
  68. tests/test_learn/test_examples.py +221 -0
  69. tests/test_learn/test_tips.py +285 -0
  70. tests/test_learning/__init__.py +3 -0
  71. tests/test_learning/test_interactive_learning_properties.py +337 -0
  72. tests/test_learning/test_learning_system_properties.py +194 -0
  73. tests/test_learning/test_progress_tracking_properties.py +279 -0
  74. tests/test_legacy/__init__.py +3 -0
  75. tests/test_legacy/test_backward_compatibility.py +236 -0
  76. tests/test_legacy/test_deprecation_warnings.py +208 -0
  77. tests/test_safe/__init__.py +3 -0
  78. tests/test_safe/test_collections_properties.py +189 -0
  79. tests/test_safe/test_files.py +104 -0
  80. tests/test_structure.py +58 -0
  81. tests/test_structure_enhancements.py +115 -0
@@ -0,0 +1,435 @@
1
+ """
2
+ Property-based tests for configuration management.
3
+
4
+ Feature: fishertools-enhancements
5
+ """
6
+
7
+ import json
8
+ import tempfile
9
+ import os
10
+ from hypothesis import given, strategies as st, assume
11
+ import pytest
12
+
13
+ from fishertools.config.models import LearningConfig
14
+ from fishertools.config.manager import ConfigurationManager
15
+ from fishertools.config.parser import ConfigurationParser
16
+
17
+
18
+ def _is_valid_json(text: str) -> bool:
19
+ """Helper function to check if text is valid JSON."""
20
+ try:
21
+ json.loads(text)
22
+ return True
23
+ except (json.JSONDecodeError, ValueError):
24
+ return False
25
+
26
+
27
+ # Strategy for generating valid LearningConfig objects
28
+ @st.composite
29
+ def learning_config_strategy(draw):
30
+ """Generate valid LearningConfig objects for property testing."""
31
+ return LearningConfig(
32
+ default_level=draw(st.sampled_from(["beginner", "intermediate", "advanced"])),
33
+ explanation_verbosity=draw(st.sampled_from(["brief", "detailed", "comprehensive"])),
34
+ visual_aids_enabled=draw(st.booleans()),
35
+ diagram_style=draw(st.text(min_size=1, max_size=20, alphabet=st.characters(whitelist_categories=('Lu', 'Ll', 'Nd')))),
36
+ color_scheme=draw(st.text(min_size=1, max_size=20, alphabet=st.characters(whitelist_categories=('Lu', 'Ll', 'Nd')))),
37
+ progress_tracking_enabled=draw(st.booleans()),
38
+ save_progress_locally=draw(st.booleans()),
39
+ suggested_topics_count=draw(st.integers(min_value=1, max_value=10)),
40
+ max_examples_per_topic=draw(st.integers(min_value=1, max_value=20)),
41
+ exercise_difficulty_progression=draw(st.lists(
42
+ st.sampled_from(["beginner", "intermediate", "advanced"]),
43
+ min_size=1, max_size=5
44
+ )),
45
+ readthedocs_project=draw(st.one_of(
46
+ st.none(),
47
+ st.text(min_size=1, max_size=50, alphabet=st.characters(whitelist_categories=('Lu', 'Ll', 'Nd', 'Pc')))
48
+ )),
49
+ sphinx_theme=draw(st.text(min_size=1, max_size=30, alphabet=st.characters(whitelist_categories=('Lu', 'Ll', 'Nd', 'Pc')))),
50
+ enable_interactive_sessions=draw(st.booleans()),
51
+ session_timeout_minutes=draw(st.integers(min_value=1, max_value=180)),
52
+ max_hint_count=draw(st.integers(min_value=0, max_value=10))
53
+ )
54
+
55
+
56
+ # Strategy for generating valid configuration dictionaries
57
+ @st.composite
58
+ def valid_config_dict_strategy(draw):
59
+ """Generate valid configuration dictionaries for property testing."""
60
+ return {
61
+ "default_level": draw(st.sampled_from(["beginner", "intermediate", "advanced"])),
62
+ "explanation_verbosity": draw(st.sampled_from(["brief", "detailed", "comprehensive"])),
63
+ "visual_aids_enabled": draw(st.booleans()),
64
+ "diagram_style": draw(st.text(min_size=1, max_size=20, alphabet=st.characters(whitelist_categories=('Lu', 'Ll', 'Nd')))),
65
+ "color_scheme": draw(st.text(min_size=1, max_size=20, alphabet=st.characters(whitelist_categories=('Lu', 'Ll', 'Nd')))),
66
+ "progress_tracking_enabled": draw(st.booleans()),
67
+ "save_progress_locally": draw(st.booleans()),
68
+ "suggested_topics_count": draw(st.integers(min_value=1, max_value=10)),
69
+ "max_examples_per_topic": draw(st.integers(min_value=1, max_value=20)),
70
+ "exercise_difficulty_progression": draw(st.lists(
71
+ st.sampled_from(["beginner", "intermediate", "advanced"]),
72
+ min_size=1, max_size=5
73
+ )),
74
+ "readthedocs_project": draw(st.one_of(
75
+ st.none(),
76
+ st.text(min_size=1, max_size=50, alphabet=st.characters(whitelist_categories=('Lu', 'Ll', 'Nd', 'Pc')))
77
+ )),
78
+ "sphinx_theme": draw(st.text(min_size=1, max_size=30, alphabet=st.characters(whitelist_categories=('Lu', 'Ll', 'Nd', 'Pc')))),
79
+ "enable_interactive_sessions": draw(st.booleans()),
80
+ "session_timeout_minutes": draw(st.integers(min_value=1, max_value=180)),
81
+ "max_hint_count": draw(st.integers(min_value=0, max_value=10))
82
+ }
83
+
84
+
85
+ # Strategy for generating invalid configuration dictionaries
86
+ @st.composite
87
+ def invalid_config_dict_strategy(draw):
88
+ """Generate invalid configuration dictionaries for property testing."""
89
+ config = {}
90
+
91
+ # Add some valid fields
92
+ if draw(st.booleans()):
93
+ config["default_level"] = draw(st.sampled_from(["beginner", "intermediate", "advanced"]))
94
+
95
+ # Add invalid fields with wrong types or values
96
+ invalid_choices = draw(st.sampled_from([
97
+ "wrong_type_level",
98
+ "wrong_type_verbosity",
99
+ "wrong_type_bool",
100
+ "wrong_type_int",
101
+ "invalid_enum_value",
102
+ "missing_required"
103
+ ]))
104
+
105
+ if invalid_choices == "wrong_type_level":
106
+ config["default_level"] = draw(st.integers()) # Should be string
107
+ elif invalid_choices == "wrong_type_verbosity":
108
+ config["explanation_verbosity"] = draw(st.integers()) # Should be string
109
+ elif invalid_choices == "wrong_type_bool":
110
+ config["visual_aids_enabled"] = draw(st.text()) # Should be bool
111
+ elif invalid_choices == "wrong_type_int":
112
+ config["suggested_topics_count"] = draw(st.text()) # Should be int
113
+ elif invalid_choices == "invalid_enum_value":
114
+ config["default_level"] = draw(st.text().filter(lambda x: x not in ["beginner", "intermediate", "advanced"]))
115
+ config["explanation_verbosity"] = "detailed" # Add required field
116
+ elif invalid_choices == "missing_required":
117
+ # Don't add required fields
118
+ config["visual_aids_enabled"] = True
119
+
120
+ return config
121
+
122
+
123
+ class TestConfigurationRoundTrip:
124
+ """Property tests for configuration round-trip serialization."""
125
+
126
+ @given(config=learning_config_strategy())
127
+ def test_json_round_trip_property(self, config):
128
+ """
129
+ Property 8: Configuration Serialization Round-trip (JSON)
130
+
131
+ For any valid configuration object, parsing then formatting then parsing
132
+ should produce an equivalent configuration object.
133
+
134
+ Validates: Requirements 7.4
135
+ """
136
+ # Feature: fishertools-enhancements, Property 8: Configuration Serialization Round-trip
137
+
138
+ parser = ConfigurationParser()
139
+ manager = ConfigurationManager()
140
+
141
+ # Format config to JSON
142
+ json_content = parser.format_to_json(config)
143
+
144
+ # Parse JSON back to dict
145
+ parsed_dict = parser.parse_json(json_content)
146
+
147
+ # Convert back to LearningConfig
148
+ reconstructed_config = manager._dict_to_config(parsed_dict)
149
+
150
+ # Verify equivalence
151
+ assert reconstructed_config.default_level == config.default_level
152
+ assert reconstructed_config.explanation_verbosity == config.explanation_verbosity
153
+ assert reconstructed_config.visual_aids_enabled == config.visual_aids_enabled
154
+ assert reconstructed_config.diagram_style == config.diagram_style
155
+ assert reconstructed_config.color_scheme == config.color_scheme
156
+ assert reconstructed_config.progress_tracking_enabled == config.progress_tracking_enabled
157
+ assert reconstructed_config.save_progress_locally == config.save_progress_locally
158
+ assert reconstructed_config.suggested_topics_count == config.suggested_topics_count
159
+ assert reconstructed_config.max_examples_per_topic == config.max_examples_per_topic
160
+ assert reconstructed_config.exercise_difficulty_progression == config.exercise_difficulty_progression
161
+ assert reconstructed_config.readthedocs_project == config.readthedocs_project
162
+ assert reconstructed_config.sphinx_theme == config.sphinx_theme
163
+ assert reconstructed_config.enable_interactive_sessions == config.enable_interactive_sessions
164
+ assert reconstructed_config.session_timeout_minutes == config.session_timeout_minutes
165
+ assert reconstructed_config.max_hint_count == config.max_hint_count
166
+
167
+ @given(config=learning_config_strategy())
168
+ def test_yaml_round_trip_property(self, config):
169
+ """
170
+ Property 8: Configuration Serialization Round-trip (YAML)
171
+
172
+ For any valid configuration object, parsing then formatting then parsing
173
+ should produce an equivalent configuration object.
174
+
175
+ Validates: Requirements 7.4
176
+ """
177
+ # Feature: fishertools-enhancements, Property 8: Configuration Serialization Round-trip
178
+
179
+ parser = ConfigurationParser()
180
+ manager = ConfigurationManager()
181
+
182
+ try:
183
+ # Format config to YAML
184
+ yaml_content = parser.format_to_yaml(config)
185
+
186
+ # Parse YAML back to dict
187
+ parsed_dict = parser.parse_yaml(yaml_content)
188
+
189
+ # Convert back to LearningConfig
190
+ reconstructed_config = manager._dict_to_config(parsed_dict)
191
+
192
+ # Verify equivalence
193
+ assert reconstructed_config.default_level == config.default_level
194
+ assert reconstructed_config.explanation_verbosity == config.explanation_verbosity
195
+ assert reconstructed_config.visual_aids_enabled == config.visual_aids_enabled
196
+ assert reconstructed_config.diagram_style == config.diagram_style
197
+ assert reconstructed_config.color_scheme == config.color_scheme
198
+ assert reconstructed_config.progress_tracking_enabled == config.progress_tracking_enabled
199
+ assert reconstructed_config.save_progress_locally == config.save_progress_locally
200
+ assert reconstructed_config.suggested_topics_count == config.suggested_topics_count
201
+ assert reconstructed_config.max_examples_per_topic == config.max_examples_per_topic
202
+ assert reconstructed_config.exercise_difficulty_progression == config.exercise_difficulty_progression
203
+ assert reconstructed_config.readthedocs_project == config.readthedocs_project
204
+ assert reconstructed_config.sphinx_theme == config.sphinx_theme
205
+ assert reconstructed_config.enable_interactive_sessions == config.enable_interactive_sessions
206
+ assert reconstructed_config.session_timeout_minutes == config.session_timeout_minutes
207
+ assert reconstructed_config.max_hint_count == config.max_hint_count
208
+
209
+ except ValueError as e:
210
+ if "YAML support not available" in str(e):
211
+ pytest.skip("YAML support not available")
212
+ else:
213
+ raise
214
+
215
+ @given(config=learning_config_strategy())
216
+ def test_file_round_trip_property_json(self, config):
217
+ """
218
+ Property 8: Configuration Serialization Round-trip (File I/O JSON)
219
+
220
+ For any valid configuration object, saving to file then loading
221
+ should produce an equivalent configuration object.
222
+
223
+ Validates: Requirements 7.4
224
+ """
225
+ # Feature: fishertools-enhancements, Property 8: Configuration Serialization Round-trip
226
+
227
+ manager = ConfigurationManager()
228
+
229
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
230
+ temp_path = f.name
231
+
232
+ try:
233
+ # Save config to file
234
+ manager.save_config(config, temp_path)
235
+
236
+ # Load config from file
237
+ loaded_config = manager.load_config(temp_path)
238
+
239
+ # Verify equivalence
240
+ assert loaded_config.default_level == config.default_level
241
+ assert loaded_config.explanation_verbosity == config.explanation_verbosity
242
+ assert loaded_config.visual_aids_enabled == config.visual_aids_enabled
243
+ assert loaded_config.diagram_style == config.diagram_style
244
+ assert loaded_config.color_scheme == config.color_scheme
245
+ assert loaded_config.progress_tracking_enabled == config.progress_tracking_enabled
246
+ assert loaded_config.save_progress_locally == config.save_progress_locally
247
+ assert loaded_config.suggested_topics_count == config.suggested_topics_count
248
+ assert loaded_config.max_examples_per_topic == config.max_examples_per_topic
249
+ assert loaded_config.exercise_difficulty_progression == config.exercise_difficulty_progression
250
+ assert loaded_config.readthedocs_project == config.readthedocs_project
251
+ assert loaded_config.sphinx_theme == config.sphinx_theme
252
+ assert loaded_config.enable_interactive_sessions == config.enable_interactive_sessions
253
+ assert loaded_config.session_timeout_minutes == config.session_timeout_minutes
254
+ assert loaded_config.max_hint_count == config.max_hint_count
255
+
256
+ finally:
257
+ # Clean up
258
+ if os.path.exists(temp_path):
259
+ os.unlink(temp_path)
260
+
261
+ @given(config=learning_config_strategy())
262
+ def test_file_round_trip_property_yaml(self, config):
263
+ """
264
+ Property 8: Configuration Serialization Round-trip (File I/O YAML)
265
+
266
+ For any valid configuration object, saving to file then loading
267
+ should produce an equivalent configuration object.
268
+
269
+ Validates: Requirements 7.4
270
+ """
271
+ # Feature: fishertools-enhancements, Property 8: Configuration Serialization Round-trip
272
+
273
+ manager = ConfigurationManager()
274
+
275
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
276
+ temp_path = f.name
277
+
278
+ try:
279
+ # Save config to file
280
+ manager.save_config(config, temp_path)
281
+
282
+ # Load config from file
283
+ loaded_config = manager.load_config(temp_path)
284
+
285
+ # Verify equivalence
286
+ assert loaded_config.default_level == config.default_level
287
+ assert loaded_config.explanation_verbosity == config.explanation_verbosity
288
+ assert loaded_config.visual_aids_enabled == config.visual_aids_enabled
289
+ assert loaded_config.diagram_style == config.diagram_style
290
+ assert loaded_config.color_scheme == config.color_scheme
291
+ assert loaded_config.progress_tracking_enabled == config.progress_tracking_enabled
292
+ assert loaded_config.save_progress_locally == config.save_progress_locally
293
+ assert loaded_config.suggested_topics_count == config.suggested_topics_count
294
+ assert loaded_config.max_examples_per_topic == config.max_examples_per_topic
295
+ assert loaded_config.exercise_difficulty_progression == config.exercise_difficulty_progression
296
+ assert loaded_config.readthedocs_project == config.readthedocs_project
297
+ assert loaded_config.sphinx_theme == config.sphinx_theme
298
+ assert loaded_config.enable_interactive_sessions == config.enable_interactive_sessions
299
+ assert loaded_config.session_timeout_minutes == config.session_timeout_minutes
300
+ assert loaded_config.max_hint_count == config.max_hint_count
301
+
302
+ except ValueError as e:
303
+ if "YAML support not available" in str(e):
304
+ pytest.skip("YAML support not available")
305
+ else:
306
+ raise
307
+ finally:
308
+ # Clean up
309
+ if os.path.exists(temp_path):
310
+ os.unlink(temp_path)
311
+
312
+
313
+ class TestConfigurationParsingRobustness:
314
+ """Property tests for configuration parsing robustness."""
315
+
316
+ @given(config_dict=valid_config_dict_strategy())
317
+ def test_valid_config_parsing_property(self, config_dict):
318
+ """
319
+ Property 7: Configuration Parsing Robustness (Valid Configs)
320
+
321
+ For any valid configuration dictionary, the parser should successfully
322
+ parse it and validation should pass.
323
+
324
+ Validates: Requirements 7.1, 7.2, 7.5
325
+ """
326
+ # Feature: fishertools-enhancements, Property 7: Configuration Parsing Robustness
327
+
328
+ parser = ConfigurationParser()
329
+ manager = ConfigurationManager()
330
+
331
+ # Validation should pass for valid configs
332
+ validation_result = parser.validate_structure(config_dict)
333
+ assert validation_result.is_valid, f"Valid config failed validation: {validation_result.errors}"
334
+
335
+ # Should be able to convert to LearningConfig without errors
336
+ learning_config = manager._dict_to_config(config_dict)
337
+ assert isinstance(learning_config, LearningConfig)
338
+
339
+ # JSON serialization should work
340
+ json_content = parser.format_to_json(learning_config)
341
+ assert isinstance(json_content, str)
342
+ assert len(json_content) > 0
343
+
344
+ # JSON parsing should work
345
+ parsed_dict = parser.parse_json(json_content)
346
+ assert isinstance(parsed_dict, dict)
347
+
348
+ @given(config_dict=invalid_config_dict_strategy())
349
+ def test_invalid_config_parsing_property(self, config_dict):
350
+ """
351
+ Property 7: Configuration Parsing Robustness (Invalid Configs)
352
+
353
+ For any invalid configuration dictionary, the parser should detect
354
+ validation errors and provide descriptive error messages.
355
+
356
+ Validates: Requirements 7.1, 7.2, 7.5
357
+ """
358
+ # Feature: fishertools-enhancements, Property 7: Configuration Parsing Robustness
359
+
360
+ parser = ConfigurationParser()
361
+
362
+ # Validation should fail for invalid configs
363
+ validation_result = parser.validate_structure(config_dict)
364
+
365
+ # Should have validation errors
366
+ assert not validation_result.is_valid or len(validation_result.errors) > 0
367
+
368
+ # Error messages should be descriptive
369
+ for error in validation_result.errors:
370
+ assert isinstance(error.message, str)
371
+ assert len(error.message) > 0
372
+ assert isinstance(error.field_path, str)
373
+ assert len(error.field_path) > 0
374
+
375
+ def test_malformed_json_parsing_property(self):
376
+ """
377
+ Property 7: Configuration Parsing Robustness (Malformed JSON)
378
+
379
+ For any malformed JSON string, the parser should raise a ValueError
380
+ with a descriptive error message.
381
+
382
+ Validates: Requirements 7.1, 7.2, 7.5
383
+ """
384
+ # Feature: fishertools-enhancements, Property 7: Configuration Parsing Robustness
385
+
386
+ parser = ConfigurationParser()
387
+
388
+ # Test with known malformed JSON strings
389
+ malformed_examples = [
390
+ '{"key": value}', # Missing quotes around value
391
+ '{"key": "value",}', # Trailing comma
392
+ '{key: "value"}', # Missing quotes around key
393
+ '{"key": "value"', # Missing closing brace
394
+ '{"key": "value"}}', # Extra closing brace
395
+ '{"key": "value" "key2": "value2"}', # Missing comma
396
+ ]
397
+
398
+ for malformed_json in malformed_examples:
399
+ # Should raise ValueError for malformed JSON
400
+ with pytest.raises(ValueError) as exc_info:
401
+ parser.parse_json(malformed_json)
402
+
403
+ # Error message should be descriptive
404
+ error_message = str(exc_info.value)
405
+ assert "Invalid JSON configuration" in error_message
406
+ assert len(error_message) > 0
407
+
408
+ @given(config_dict=valid_config_dict_strategy())
409
+ def test_config_change_application_property(self, config_dict):
410
+ """
411
+ Property 7: Configuration Parsing Robustness (Dynamic Changes)
412
+
413
+ For any valid configuration, the system should be able to apply
414
+ configuration changes dynamically without errors.
415
+
416
+ Validates: Requirements 7.5
417
+ """
418
+ # Feature: fishertools-enhancements, Property 7: Configuration Parsing Robustness
419
+
420
+ manager = ConfigurationManager()
421
+
422
+ # Create LearningConfig from dict
423
+ learning_config = manager._dict_to_config(config_dict)
424
+
425
+ # Should be able to apply configuration without errors
426
+ manager.apply_config(learning_config)
427
+
428
+ # Should be able to retrieve current config
429
+ current_config = manager.get_current_config()
430
+ assert current_config is not None
431
+ assert isinstance(current_config, LearningConfig)
432
+
433
+ # Current config should match applied config
434
+ assert current_config.default_level == learning_config.default_level
435
+ assert current_config.explanation_verbosity == learning_config.explanation_verbosity
@@ -0,0 +1,3 @@
1
+ """
2
+ Tests for the documentation generation module.
3
+ """