fancygit 1.0.0__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.
@@ -0,0 +1,507 @@
1
+ import pytest
2
+ from unittest.mock import patch, MagicMock, call
3
+ import sys
4
+ import os
5
+
6
+ # Add project root to path for imports
7
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
8
+
9
+ from fancygit import FancyGit
10
+
11
+ @pytest.mark.unit
12
+ class TestFancyGitCommands:
13
+ """Test cases for individual FancyGit commands"""
14
+
15
+ def setup_method(self):
16
+ """Setup method called before each test"""
17
+ # Mock all the loading methods to avoid file dependencies
18
+ with patch.object(FancyGit, '_load_commands', return_value=[
19
+ 'add', 'commit', 'push', 'pull', 'status', 'branch', 'checkout',
20
+ 'merge', 'rebase', 'reset', 'log', 'diff', 'stash', 'rm', 'mv',
21
+ 'welcome', 'confirmation', 'ai', 'colors', 'insights', 'visualize'
22
+ ]):
23
+ with patch.object(FancyGit, '_load_confirmation_state', return_value=False):
24
+ with patch.object(FancyGit, '_load_ai_analysis_state', return_value=False):
25
+ with patch.object(FancyGit, '_load_output_coloring_state', return_value=False):
26
+ with patch.object(FancyGit, '_load_animation_type', return_value='dots'):
27
+ self.fancy_git = FancyGit()
28
+
29
+ @patch('src.git_runner.GitRunner.run_git_command')
30
+ def test_add_command_success(self, mock_run_git):
31
+ """Test git add command success"""
32
+ mock_run_git.return_value = (0, "", "")
33
+
34
+ result = self.fancy_git.execute_command('add', 'test.txt')
35
+
36
+ assert result is True
37
+ mock_run_git.assert_called_once_with(['add', 'test.txt'])
38
+
39
+ @patch('src.git_runner.GitRunner.run_git_command')
40
+ def test_add_command_error(self, mock_run_git):
41
+ """Test git add command with error"""
42
+ mock_run_git.return_value = (1, "", "error: pathspec 'nonexistent.txt' did not match any files")
43
+
44
+ result = self.fancy_git.execute_command('add', 'nonexistent.txt')
45
+
46
+ assert result is False
47
+ mock_run_git.assert_called_once_with(['add', 'nonexistent.txt'])
48
+
49
+ @patch('src.git_runner.GitRunner.run_git_command')
50
+ def test_commit_command_success(self, mock_run_git):
51
+ """Test git commit command success"""
52
+ mock_run_git.return_value = (0, "[main 1234567] Test commit\n 1 file changed, 1 insertion(+)", "")
53
+
54
+ result = self.fancy_git.execute_command('commit', '-m', 'Test commit')
55
+
56
+ assert result is True
57
+ mock_run_git.assert_called_once_with(['commit', '-m', 'Test commit'])
58
+
59
+ @patch('src.git_runner.GitRunner.run_git_command')
60
+ def test_push_command_success(self, mock_run_git):
61
+ """Test git push command success"""
62
+ mock_run_git.return_value = (0, "Enumerating objects: 3, done.\nTo github.com:user/repo.git\n 1234567..abcdefg main -> main", "")
63
+
64
+ result = self.fancy_git.execute_command('push', 'origin', 'main')
65
+
66
+ assert result is True
67
+ mock_run_git.assert_called_once_with(['push', 'origin', 'main'])
68
+
69
+ @patch('src.git_runner.GitRunner.run_git_command')
70
+ def test_pull_command_success(self, mock_run_git):
71
+ """Test git pull command success"""
72
+ mock_run_git.return_value = (0, "Already up to date.", "")
73
+
74
+ result = self.fancy_git.execute_command('pull', 'origin', 'main')
75
+
76
+ assert result is True
77
+ mock_run_git.assert_called_once_with(['pull', 'origin', 'main'])
78
+
79
+ @patch('src.git_runner.GitRunner.run_git_command')
80
+ def test_status_command_success(self, mock_run_git):
81
+ """Test git status command success"""
82
+ mock_run_git.return_value = (0, "On branch main\nnothing to commit, working tree clean", "")
83
+
84
+ result = self.fancy_git.execute_command('status')
85
+
86
+ assert result is True
87
+ mock_run_git.assert_called_once_with(['status'])
88
+
89
+ @patch('src.git_runner.GitRunner.run_git_command')
90
+ def test_branch_command_success(self, mock_run_git):
91
+ """Test git branch command success"""
92
+ mock_run_git.return_value = (0, "* main\n feature-branch", "")
93
+
94
+ result = self.fancy_git.execute_command('branch')
95
+
96
+ assert result is True
97
+ mock_run_git.assert_called_once_with(['branch'])
98
+
99
+ @patch('src.git_runner.GitRunner.run_git_command')
100
+ def test_branch_create_command(self, mock_run_git):
101
+ """Test git branch creation command"""
102
+ mock_run_git.return_value = (0, "", "")
103
+
104
+ result = self.fancy_git.execute_command('branch', 'new-feature')
105
+
106
+ assert result is True
107
+ mock_run_git.assert_called_once_with(['branch', 'new-feature'])
108
+
109
+ @patch('src.git_runner.GitRunner.run_git_command')
110
+ def test_checkout_command_success(self, mock_run_git):
111
+ """Test git checkout command success"""
112
+ mock_run_git.return_value = (0, "Switched to branch 'feature-branch'", "")
113
+
114
+ result = self.fancy_git.execute_command('checkout', 'feature-branch')
115
+
116
+ assert result is True
117
+ mock_run_git.assert_called_once_with(['checkout', 'feature-branch'])
118
+
119
+ @patch('src.git_runner.GitRunner.run_git_command')
120
+ def test_merge_command_success(self, mock_run_git):
121
+ """Test git merge command success"""
122
+ mock_run_git.return_value = (0, "Merge made by the 'recursive' strategy.\n 1 file changed, 1 insertion(+)", "")
123
+
124
+ result = self.fancy_git.execute_command('merge', 'feature-branch')
125
+
126
+ assert result is True
127
+ mock_run_git.assert_called_once_with(['merge', 'feature-branch'])
128
+
129
+ @patch('src.git_runner.GitRunner.run_git_command')
130
+ def test_merge_command_conflict(self, mock_run_git):
131
+ """Test git merge command with conflicts"""
132
+ mock_run_git.return_value = (1, "", "error: Merge conflict in README.md\nAutomatic merge failed; fix conflicts and then commit the result.")
133
+
134
+ result = self.fancy_git.execute_command('merge', 'feature-branch')
135
+
136
+ assert result is False
137
+ mock_run_git.assert_called_once_with(['merge', 'feature-branch'])
138
+
139
+ @patch('src.git_runner.GitRunner.run_git_command')
140
+ def test_rebase_command_success(self, mock_run_git):
141
+ """Test git rebase command success"""
142
+ mock_run_git.return_value = (0, "Successfully rebased and updated refs/heads/main.", "")
143
+
144
+ result = self.fancy_git.execute_command('rebase', 'origin/main')
145
+
146
+ assert result is True
147
+ mock_run_git.assert_called_once_with(['rebase', 'origin/main'])
148
+
149
+ @patch('src.git_runner.GitRunner.run_git_command')
150
+ def test_reset_command_success(self, mock_run_git):
151
+ """Test git reset command success"""
152
+ mock_run_git.return_value = (0, "Unstaged changes after reset:\nM\ttest.py", "")
153
+
154
+ result = self.fancy_git.execute_command('reset', 'HEAD~1')
155
+
156
+ assert result is True
157
+ mock_run_git.assert_called_once_with(['reset', 'HEAD~1'])
158
+
159
+ @patch('src.git_runner.GitRunner.run_git_command')
160
+ def test_log_command_success(self, mock_run_git):
161
+ """Test git log command success"""
162
+ mock_run_git.return_value = (0, "commit 1234567890abcdef\nAuthor: Test User <test@example.com>\nDate: Mon Jan 1 12:00:00 2024\n\n Test commit message", "")
163
+
164
+ result = self.fancy_git.execute_command('log', '--oneline', '-5')
165
+
166
+ assert result is True
167
+ mock_run_git.assert_called_once_with(['log', '--oneline', '-5'])
168
+
169
+ @patch('src.git_runner.GitRunner.run_git_command')
170
+ def test_diff_command_success(self, mock_run_git):
171
+ """Test git diff command success"""
172
+ mock_run_git.return_value = (0, "diff --git a/test.py b/test.py\nindex 1234567..abcdefg 100644\n--- a/test.py\n+++ b/test.py\n@@ -1,3 +1,4 @@\n+new line", "")
173
+
174
+ result = self.fancy_git.execute_command('diff', 'test.py')
175
+
176
+ assert result is True
177
+ mock_run_git.assert_called_once_with(['diff', 'test.py'])
178
+
179
+ @patch('src.git_runner.GitRunner.run_git_command')
180
+ def test_stash_command_success(self, mock_run_git):
181
+ """Test git stash command success"""
182
+ mock_run_git.return_value = (0, "Saved working directory and index state WIP on main: 1234567 Test commit", "")
183
+
184
+ result = self.fancy_git.execute_command('stash', 'push', '-m', 'WIP')
185
+
186
+ assert result is True
187
+ mock_run_git.assert_called_once_with(['stash', 'push', '-m', 'WIP'])
188
+
189
+ @patch('src.git_runner.GitRunner.run_git_command')
190
+ def test_rm_command_success(self, mock_run_git):
191
+ """Test git rm command success"""
192
+ mock_run_git.return_value = (0, "rm 'test.txt'", "")
193
+
194
+ result = self.fancy_git.execute_command('rm', 'test.txt')
195
+
196
+ assert result is True
197
+ mock_run_git.assert_called_once_with(['rm', 'test.txt'])
198
+
199
+ @patch('src.git_runner.GitRunner.run_git_command')
200
+ def test_mv_command_success(self, mock_run_git):
201
+ """Test git mv command success"""
202
+ mock_run_git.return_value = (0, "Renaming 'old.txt' to 'new.txt'", "")
203
+
204
+ result = self.fancy_git.execute_command('mv', 'old.txt', 'new.txt')
205
+
206
+ assert result is True
207
+ mock_run_git.assert_called_once_with(['mv', 'old.txt', 'new.txt'])
208
+
209
+ def test_unknown_command(self):
210
+ """Test handling of unknown commands"""
211
+ result = self.fancy_git.execute_command('unknown_command')
212
+
213
+ assert result is False
214
+
215
+ @patch('src.git_runner.GitRunner.run_git_command')
216
+ def test_command_with_no_args(self, mock_run_git):
217
+ """Test command execution with no arguments"""
218
+ mock_run_git.return_value = (0, "Git help output", "")
219
+
220
+ result = self.fancy_git.execute_command('status')
221
+
222
+ assert result is True
223
+ mock_run_git.assert_called_once_with(['status'])
224
+
225
+ @patch('src.git_runner.GitRunner.run_git_command')
226
+ def test_command_with_multiple_args(self, mock_run_git):
227
+ """Test command execution with multiple arguments"""
228
+ mock_run_git.return_value = (0, "Branch 'test-branch' set up to track remote branch 'test' from 'origin'.", "")
229
+
230
+ result = self.fancy_git.execute_command('push', '-u', 'origin', 'test-branch')
231
+
232
+ assert result is True
233
+ mock_run_git.assert_called_once_with(['push', '-u', 'origin', 'test-branch'])
234
+
235
+ @patch('src.git_runner.GitRunner.run_git_command')
236
+ def test_command_with_complex_args(self, mock_run_git):
237
+ """Test command execution with complex arguments containing quotes and special characters"""
238
+ mock_run_git.return_value = (0, "Commit successful", "")
239
+
240
+ result = self.fancy_git.execute_command('commit', '-m', 'Fix bug #123: Update configuration file')
241
+
242
+ assert result is True
243
+ mock_run_git.assert_called_once_with(['commit', '-m', 'Fix bug #123: Update configuration file'])
244
+
245
+ @pytest.mark.unit
246
+ class TestFancyGitSpecialCommands:
247
+ """Test cases for FancyGit special commands"""
248
+
249
+ def setup_method(self):
250
+ """Setup method called before each test"""
251
+ with patch.object(FancyGit, '_load_commands', return_value=[
252
+ 'welcome', 'confirmation', 'ai', 'colors', 'insights', 'visualize'
253
+ ]):
254
+ with patch.object(FancyGit, '_load_confirmation_state', return_value=True):
255
+ with patch.object(FancyGit, '_load_ai_analysis_state', return_value=False):
256
+ with patch.object(FancyGit, '_load_output_coloring_state', return_value=False):
257
+ with patch.object(FancyGit, '_load_animation_type', return_value='dots'):
258
+ self.fancy_git = FancyGit()
259
+
260
+ def test_welcome_command(self):
261
+ """Test welcome command"""
262
+ result = self.fancy_git.execute_command('welcome')
263
+
264
+ assert result is True
265
+ # The welcome command should execute without errors
266
+ # We can't easily mock the welcome function due to import issues,
267
+ # but we can verify it returns True (successful execution)
268
+
269
+ def test_confirmation_command_toggle(self):
270
+ """Test confirmation command toggle"""
271
+ initial_state = self.fancy_git.confirmation_enabled
272
+
273
+ result = self.fancy_git.execute_command('confirmation')
274
+
275
+ assert result is not None # The method returns the current state (bool)
276
+ assert self.fancy_git.confirmation_enabled != initial_state
277
+
278
+ def test_confirmation_command_enable(self):
279
+ """Test confirmation command enable"""
280
+ result = self.fancy_git.execute_command('confirmation', 'on')
281
+
282
+ assert result is True
283
+ assert self.fancy_git.confirmation_enabled is True
284
+
285
+ def test_confirmation_command_disable(self):
286
+ """Test confirmation command disable"""
287
+ result = self.fancy_git.execute_command('confirmation', 'off')
288
+
289
+ assert isinstance(result, bool) # The method returns the current state
290
+ assert self.fancy_git.confirmation_enabled is False
291
+
292
+ def test_confirmation_command_status(self):
293
+ """Test confirmation command status"""
294
+ with patch('builtins.print') as mock_print:
295
+ result = self.fancy_git.execute_command('confirmation', 'status')
296
+
297
+ assert result is True
298
+ mock_print.assert_called()
299
+
300
+ @patch('src.ollama_client.OllamaClient.test_connection')
301
+ def test_ai_command_toggle(self, mock_test_connection):
302
+ """Test AI command toggle"""
303
+ mock_test_connection.return_value = True
304
+ initial_state = self.fancy_git.ai_analysis_enabled
305
+
306
+ result = self.fancy_git.execute_command('ai')
307
+
308
+ assert result is True
309
+ assert self.fancy_git.ai_analysis_enabled != initial_state
310
+
311
+ @patch('src.ollama_client.OllamaClient.test_connection')
312
+ def test_ai_command_enable(self, mock_test_connection):
313
+ """Test AI command enable"""
314
+ mock_test_connection.return_value = True
315
+
316
+ result = self.fancy_git.execute_command('ai', 'on')
317
+
318
+ assert result is True
319
+ assert self.fancy_git.ai_analysis_enabled is True
320
+
321
+ def test_ai_command_disable(self):
322
+ """Test AI command disable"""
323
+ result = self.fancy_git.execute_command('ai', 'off')
324
+
325
+ assert isinstance(result, bool) # The method returns the current state
326
+ assert self.fancy_git.ai_analysis_enabled is False
327
+
328
+ @patch('src.ollama_client.OllamaClient.get_available_models')
329
+ @patch('src.ollama_client.OllamaClient.test_connection')
330
+ def test_ai_command_status(self, mock_test_connection, mock_get_models):
331
+ """Test AI command status"""
332
+ mock_test_connection.return_value = True
333
+ mock_get_models.return_value = ['llama2', 'mistral']
334
+
335
+ with patch('builtins.print') as mock_print:
336
+ result = self.fancy_git.execute_command('ai', 'status')
337
+
338
+ assert isinstance(result, bool) # The method returns the current state
339
+ mock_print.assert_called()
340
+
341
+ def test_colors_command_toggle(self):
342
+ """Test colors command toggle"""
343
+ initial_state = self.fancy_git.output_coloring_enabled
344
+
345
+ result = self.fancy_git.execute_command('colors')
346
+
347
+ assert result is True
348
+ assert self.fancy_git.output_coloring_enabled != initial_state
349
+
350
+ def test_colors_command_enable(self):
351
+ """Test colors command enable"""
352
+ result = self.fancy_git.execute_command('colors', 'on')
353
+
354
+ assert result is True
355
+ assert self.fancy_git.output_coloring_enabled is True
356
+
357
+ def test_colors_command_disable(self):
358
+ """Test colors command disable"""
359
+ result = self.fancy_git.execute_command('colors', 'off')
360
+
361
+ assert isinstance(result, bool) # The method returns the current state
362
+ assert self.fancy_git.output_coloring_enabled is False
363
+
364
+ def test_colors_command_status(self):
365
+ """Test colors command status"""
366
+ with patch('builtins.print') as mock_print:
367
+ result = self.fancy_git.execute_command('colors', 'status')
368
+
369
+ assert isinstance(result, bool) # The method returns the current state
370
+ mock_print.assert_called()
371
+
372
+ @patch('src.git_insights.GitInsights.generate_insights_report')
373
+ def test_insights_command_success(self, mock_generate):
374
+ """Test insights command success"""
375
+ mock_generate.return_value = {
376
+ 'generated_at': '2024-01-01T12:00:00Z',
377
+ 'analysis_period_days': 30,
378
+ 'summary': {'total_commits': 10},
379
+ 'commit_frequency': {},
380
+ 'branch_analysis': {},
381
+ 'file_hotspots': {},
382
+ 'contributor_stats': {}
383
+ }
384
+
385
+ with patch('builtins.print') as mock_print:
386
+ result = self.fancy_git.execute_command('insights')
387
+
388
+ assert isinstance(result, bool) # The method returns True/False
389
+ mock_generate.assert_called_once_with(30)
390
+
391
+ @patch('src.git_insights.GitInsights.generate_insights_report')
392
+ def test_insights_command_with_days(self, mock_generate):
393
+ """Test insights command with custom days"""
394
+ mock_generate.return_value = {
395
+ 'generated_at': '2024-01-01T12:00:00Z',
396
+ 'analysis_period_days': 7,
397
+ 'summary': {'total_commits': 5},
398
+ 'commit_frequency': {},
399
+ 'branch_analysis': {},
400
+ 'file_hotspots': {},
401
+ 'contributor_stats': {}
402
+ }
403
+
404
+ with patch('builtins.print') as mock_print:
405
+ result = self.fancy_git.execute_command('insights', '--days=7')
406
+
407
+ assert isinstance(result, bool) # The method returns True/False
408
+ mock_generate.assert_called_once_with(7)
409
+
410
+ @patch('src.mermaid_export.MermaidExporter.export_all')
411
+ @patch('webbrowser.open')
412
+ def test_visualize_command_success(self, mock_browser, mock_export):
413
+ """Test visualize command success"""
414
+ mock_export.return_value = {
415
+ 'status_mmd': '.fancygit/status.mmd',
416
+ 'graph_mmd': '.fancygit/graph.mmd',
417
+ 'tree_mmd': '.fancygit/tree.mmd',
418
+ 'deps_mmd': '.fancygit/deps.mmd',
419
+ 'html': '.fancygit/repo_visualization.html'
420
+ }
421
+
422
+ with patch.object(self.fancy_git, 'get_repo_state', return_value={'branch': 'main'}):
423
+ with patch('builtins.print') as mock_print:
424
+ result = self.fancy_git.execute_command('visualize')
425
+
426
+ assert result is True
427
+ mock_export.assert_called_once()
428
+ mock_browser.assert_called_once()
429
+
430
+ @patch('src.mermaid_export.MermaidExporter.export_all')
431
+ def test_visualize_command_no_browser(self, mock_export):
432
+ """Test visualize command without opening browser"""
433
+ mock_export.return_value = {
434
+ 'status_mmd': '.fancygit/status.mmd',
435
+ 'graph_mmd': '.fancygit/graph.mmd',
436
+ 'tree_mmd': '.fancygit/tree.mmd',
437
+ 'deps_mmd': '.fancygit/deps.mmd',
438
+ 'html': '.fancygit/repo_visualization.html'
439
+ }
440
+
441
+ with patch.object(self.fancy_git, 'get_repo_state', return_value={'branch': 'main'}):
442
+ with patch('builtins.print') as mock_print:
443
+ result = self.fancy_git.execute_command('visualize', '--no-open')
444
+
445
+ assert result is True
446
+ mock_export.assert_called_once()
447
+
448
+ @pytest.mark.unit
449
+ class TestFancyGitCommandValidation:
450
+ """Test cases for FancyGit command validation and edge cases"""
451
+
452
+ def setup_method(self):
453
+ """Setup method called before each test"""
454
+ with patch.object(FancyGit, '_load_commands', return_value=['add', 'commit', 'status']):
455
+ with patch.object(FancyGit, '_load_confirmation_state', return_value=False):
456
+ with patch.object(FancyGit, '_load_ai_analysis_state', return_value=False):
457
+ with patch.object(FancyGit, '_load_output_coloring_state', return_value=False):
458
+ with patch.object(FancyGit, '_load_animation_type', return_value='dots'):
459
+ self.fancy_git = FancyGit()
460
+
461
+ def test_empty_command(self):
462
+ """Test handling of empty command"""
463
+ result = self.fancy_git.execute_command('')
464
+
465
+ assert result is False
466
+
467
+ def test_none_command(self):
468
+ """Test handling of None command"""
469
+ result = self.fancy_git.execute_command(None)
470
+
471
+ assert result is False
472
+
473
+ def test_command_not_in_list(self):
474
+ """Test handling of command not in available commands"""
475
+ result = self.fancy_git.execute_command('nonexistent_command')
476
+
477
+ assert result is False
478
+
479
+ @patch('src.git_runner.GitRunner.run_git_command')
480
+ def test_command_with_empty_args_list(self, mock_run_git):
481
+ """Test command with empty args list"""
482
+ mock_run_git.return_value = (0, "Git status output", "")
483
+
484
+ result = self.fancy_git.execute_command('status')
485
+
486
+ assert result is True
487
+ mock_run_git.assert_called_once_with(['status'])
488
+
489
+ @patch('src.git_runner.GitRunner.run_git_command')
490
+ def test_command_with_special_characters_in_args(self, mock_run_git):
491
+ """Test command with special characters in arguments"""
492
+ mock_run_git.return_value = (0, "Commit successful", "")
493
+
494
+ result = self.fancy_git.execute_command('commit', '-m', 'Fix: Update "config.json" file')
495
+
496
+ assert result is True
497
+ mock_run_git.assert_called_once_with(['commit', '-m', 'Fix: Update "config.json" file'])
498
+
499
+ @patch('src.git_runner.GitRunner.run_git_command')
500
+ def test_command_with_unicode_args(self, mock_run_git):
501
+ """Test command with unicode characters in arguments"""
502
+ mock_run_git.return_value = (0, "Commit successful", "")
503
+
504
+ result = self.fancy_git.execute_command('commit', '-m', 'Add 🚀 emoji support')
505
+
506
+ assert result is True
507
+ mock_run_git.assert_called_once_with(['commit', '-m', 'Add 🚀 emoji support'])
@@ -0,0 +1,158 @@
1
+ import pytest
2
+ from unittest.mock import patch, MagicMock
3
+ import sys
4
+ import os
5
+
6
+ # Add project root to path for imports
7
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
8
+
9
+ from fancygit import FancyGit
10
+
11
+ @pytest.mark.integration
12
+ @pytest.mark.slow
13
+ class TestFancyGitIntegration:
14
+ """Integration tests for FancyGit class workflows"""
15
+
16
+ def setup_method(self):
17
+ """Setup method called before each test"""
18
+ # Mock the config loading to avoid file dependencies
19
+ with patch.object(FancyGit, '_load_commands', return_value=['add', 'commit', 'push', 'pull']):
20
+ with patch.object(FancyGit, '_load_confirmation_state', return_value=True):
21
+ with patch.object(FancyGit, '_load_ai_analysis_state', return_value=False):
22
+ with patch.object(FancyGit, '_load_animation_type', return_value='simple'):
23
+ self.fancy_git = FancyGit()
24
+
25
+ def test_fancygit_initialization(self):
26
+ """Test FancyGit initializes with all required components"""
27
+ assert hasattr(self.fancy_git, 'runner')
28
+ assert hasattr(self.fancy_git, 'parser')
29
+ assert hasattr(self.fancy_git, 'mermaid')
30
+ assert hasattr(self.fancy_git, 'insights')
31
+ assert hasattr(self.fancy_git, 'ollama')
32
+ assert hasattr(self.fancy_git, 'available_commands')
33
+ assert hasattr(self.fancy_git, 'confirmation_enabled')
34
+
35
+ @patch('src.git_runner.GitRunner.run_git_command')
36
+ def test_clean_git_status_workflow(self, mock_run_git):
37
+ """Test workflow when git status is clean"""
38
+ mock_run_git.return_value = (0, "On branch main\nnothing to commit, working tree clean\n", "")
39
+
40
+ returncode, stdout, stderr = self.fancy_git.runner.run_git_command(['status'])
41
+ errors = self.fancy_git.parser.detect_warnings_errors(stdout, stderr)
42
+
43
+ assert returncode == 0
44
+ assert len(errors) == 0
45
+ assert "nothing to commit" in stdout
46
+
47
+ @patch('src.git_runner.GitRunner.run_git_command')
48
+ def test_error_detection_workflow(self, mock_run_git):
49
+ """Test workflow when git command produces errors"""
50
+ mock_run_git.return_value = (1, "", "error: pathspec 'nonexistent.txt' did not match any files\n")
51
+
52
+ returncode, stdout, stderr = self.fancy_git.runner.run_git_command(['add', 'nonexistent.txt'])
53
+ errors = self.fancy_git.parser.detect_warnings_errors(stdout, stderr)
54
+
55
+ assert returncode == 1
56
+ assert len(errors) == 1
57
+ assert errors[0].severity == "error"
58
+ assert "pathspec" in errors[0].message
59
+ assert errors[0].source == "stderr"
60
+
61
+ @patch('src.git_runner.GitRunner.run_git_command')
62
+ def test_warning_detection_workflow(self, mock_run_git):
63
+ """Test workflow when git command produces warnings"""
64
+ mock_run_git.return_value = (0, "warning: LF will be replaced by CRLF in README.md\n", "")
65
+
66
+ returncode, stdout, stderr = self.fancy_git.runner.run_git_command(['add', 'README.md'])
67
+ errors = self.fancy_git.parser.detect_warnings_errors(stdout, stderr)
68
+
69
+ assert returncode == 0
70
+ assert len(errors) == 2 # Both "warning:" and "WARNING:" patterns match
71
+ assert all(error.severity == "warning" for error in errors)
72
+ assert all("LF will be replaced" in error.message for error in errors)
73
+
74
+ @patch('src.git_runner.GitRunner.run_git_command')
75
+ def test_multiple_issues_detection(self, mock_run_git):
76
+ """Test workflow with multiple warnings and errors"""
77
+ mock_run_git.return_value = (
78
+ 1,
79
+ "warning: CRLF will be replaced by LF in test.py\nYour branch is ahead by 2 commits\n",
80
+ "error: merge conflict in README.md\nfatal: unable to checkout"
81
+ )
82
+
83
+ returncode, stdout, stderr = self.fancy_git.runner.run_git_command(['pull', 'origin', 'main'])
84
+ errors = self.fancy_git.parser.detect_warnings_errors(stdout, stderr)
85
+
86
+ assert returncode == 1
87
+ assert len(errors) == 8 # Multiple pattern matches
88
+
89
+ error_severities = [error.severity for error in errors]
90
+ assert error_severities.count("warning") == 3 # warning: (twice) + ahead
91
+ assert error_severities.count("error") == 5 # error: + conflict + merge conflict + fatal + unable
92
+
93
+ def test_available_commands_loading(self):
94
+ """Test that available commands are loaded correctly"""
95
+ assert isinstance(self.fancy_git.available_commands, list)
96
+ assert len(self.fancy_git.available_commands) > 0
97
+ assert 'add' in self.fancy_git.available_commands
98
+ assert 'commit' in self.fancy_git.available_commands
99
+
100
+ @patch('src.git_runner.GitRunner.run_git_command')
101
+ def test_repo_state_integration(self, mock_run_git):
102
+ """Test repository state functionality"""
103
+ # Mock git status output for a dirty repository
104
+ mock_run_git.return_value = (
105
+ 0,
106
+ "On branch main\nChanges not staged for commit:\n modified: test.py\nUntracked files:\n new_file.py\n",
107
+ ""
108
+ )
109
+
110
+ # Test the repo state method if it exists
111
+ if hasattr(self.fancy_git, 'get_repo_state'):
112
+ repo_state = self.fancy_git.get_repo_state()
113
+ assert isinstance(repo_state, dict)
114
+ assert 'branch' in repo_state
115
+ assert 'clean' in repo_state
116
+
117
+ @patch('src.git_runner.GitRunner.run_git_command')
118
+ def test_conflict_detection_integration(self, mock_run_git):
119
+ """Test merge conflict detection integration"""
120
+ # Mock git status showing conflicts
121
+ mock_run_git.return_value = (
122
+ 1,
123
+ "",
124
+ "error: Merge conflict in README.md\nerror: Merge conflict in src/main.py\n"
125
+ )
126
+
127
+ returncode, stdout, stderr = self.fancy_git.runner.run_git_command(['merge', 'feature-branch'])
128
+ errors = self.fancy_git.parser.detect_warnings_errors(stdout, stderr)
129
+
130
+ assert returncode == 1
131
+ assert len(errors) == 6 # Each conflict matches 3 patterns: "error:", "conflict", "merge conflict"
132
+
133
+ conflict_errors = [e for e in errors if 'conflict' in e.message.lower()]
134
+ assert len(conflict_errors) == 6 # All errors contain "conflict"
135
+
136
+ @patch('src.ollama_client.OllamaClient.test_connection')
137
+ def test_ai_integration_workflow(self, mock_test_connection):
138
+ """Test AI integration workflow"""
139
+ mock_test_connection.return_value = True
140
+
141
+ # Test Ollama client initialization and connection
142
+ if hasattr(self.fancy_git, 'ollama'):
143
+ connection_status = self.fancy_git.ollama.test_connection()
144
+ assert connection_status is True
145
+
146
+ def test_mermaid_export_integration(self):
147
+ """Test Mermaid export functionality integration"""
148
+ if hasattr(self.fancy_git, 'mermaid'):
149
+ # Test that mermaid exporter is properly initialized
150
+ assert self.fancy_git.mermaid is not None
151
+ assert hasattr(self.fancy_git.mermaid, 'runner')
152
+
153
+ def test_configuration_loading(self):
154
+ """Test that configuration is loaded properly"""
155
+ # Test that configuration values are set
156
+ assert isinstance(self.fancy_git.confirmation_enabled, bool)
157
+ assert isinstance(self.fancy_git.ai_analysis_enabled, bool)
158
+ assert isinstance(self.fancy_git.loading_animation_type, str)