Skip to content

Commit 01cae55

Browse files
committed
Add regression tests for blame view and log view
1 parent 0ef73eb commit 01cae55

File tree

1 file changed

+299
-0
lines changed

1 file changed

+299
-0
lines changed
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
# -*- coding: utf-8 -*-
2+
import os
3+
from unittest.mock import patch
4+
5+
from qgitc.blameline import BlameLine
6+
from qgitc.gitutils import Git
7+
from qgitc.logview import LogView
8+
from qgitc.windowtype import WindowType
9+
from tests.base import TestBase
10+
11+
12+
class TestBlameViewLogViewInteraction(TestBase):
13+
"""Test BlameCommitPanel and LogView interaction"""
14+
15+
def setUp(self):
16+
super().setUp()
17+
self.window = self.app.getWindow(WindowType.BlameWindow)
18+
self.window.showMaximized()
19+
self.blameView = self.window._view
20+
self.commitPanel = self.blameView.commitPanel
21+
self.logView = self.commitPanel.logView
22+
23+
def tearDown(self):
24+
self.window.close()
25+
super().tearDown()
26+
27+
def test_switchToCommit_with_delay_parameter(self):
28+
"""Test switchToCommit respects delay parameter when fetcher is loading"""
29+
# Setup: Show logs for a file
30+
file = os.path.join(self.gitDir.name, "test.py")
31+
self.commitPanel.showLogs(self.gitDir.name, file)
32+
33+
# Wait for fetch to complete
34+
self.wait(3000, lambda: self.logView.fetcher.isLoading())
35+
36+
# Ensure data is available
37+
self.assertGreater(len(self.logView.data), 0)
38+
39+
# Get the SHA1 of the first commit in the log
40+
firstCommit = self.logView.data[0]
41+
sha1 = firstCommit.sha1
42+
43+
# Test 1: switchToCommit with delay=False
44+
# This should try to switch immediately
45+
self.assertFalse(self.logView.fetcher.isLoading())
46+
result = self.logView.switchToCommit(sha1, delay=False)
47+
self.assertTrue(
48+
result, "switchToCommit should return True when commit is found")
49+
50+
# Test 2: switchToCommit with delay parameter set to True
51+
# When delay=True AND commit is NOT found, preferSha1 should be set
52+
# Reset first
53+
self.logView.setCurrentIndex(-1)
54+
self.logView.preferSha1 = None
55+
56+
# Use a non-existent commit to trigger the delay path
57+
fake_sha1 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
58+
result = self.logView.switchToCommit(fake_sha1, delay=True)
59+
self.assertTrue(
60+
result, "switchToCommit with delay=True should return True even if commit not found")
61+
# The key behavior: when delay=True and commit not found, it sets preferSha1
62+
self.assertEqual(self.logView.preferSha1, fake_sha1,
63+
"preferSha1 should be set when delay=True and commit not found")
64+
65+
def test_switchToCommit_when_fetcher_loading(self):
66+
"""Test switchToCommit behavior when fetcher is actively loading"""
67+
file = os.path.join(self.gitDir.name, "test.py")
68+
69+
# Get a valid SHA1
70+
sha1 = Git.checkOutput(
71+
["log", "-1", "--pretty=format:%H", file]).rstrip().decode()
72+
73+
# Mock fetcher to return isLoading=True
74+
with patch.object(self.logView.fetcher, 'isLoading', return_value=True):
75+
# When fetcher is loading and commit not yet in data, should set preferSha1
76+
result = self.logView.switchToCommit(sha1, delay=True)
77+
78+
# Should set preferSha1 and return True when loading
79+
self.assertTrue(result)
80+
self.assertEqual(self.logView.preferSha1, sha1)
81+
82+
def test_showRevision_with_loading_fetcher(self):
83+
"""Test that showRevision correctly handles fetcher loading state"""
84+
file = os.path.join(self.gitDir.name, "test.py")
85+
86+
# Get commit info before loading
87+
sha1 = Git.checkOutput(
88+
["log", "-1", "--pretty=format:%H", file]).rstrip().decode()
89+
90+
# Create a BlameLine for a commit not yet in data
91+
blameLine = BlameLine()
92+
blameLine.sha1 = sha1
93+
blameLine.previous = None
94+
95+
# Mock fetcher.isLoading() to return True to test delay path
96+
with patch.object(self.logView.fetcher, 'isLoading', return_value=True):
97+
# Call showRevision while "fetcher is loading" and data is empty
98+
# This tests the fix: passing self.logView.fetcher.isLoading() to switchToCommit
99+
self.commitPanel.showRevision(blameLine)
100+
101+
# Should have set preferSha1 because isLoading() returned True and commit not found
102+
self.assertEqual(self.logView.preferSha1, sha1)
103+
104+
def test_no_endFetch_connection_in_BlameCommitPanel(self):
105+
"""Test that BlameCommitPanel doesn't connect to logView.endFetch signal"""
106+
# This test verifies that the problematic endFetch connection is removed
107+
# We can't directly check signal connections, but we can verify behavior
108+
109+
file = os.path.join(self.gitDir.name, "test.py")
110+
sha1_list = []
111+
112+
# Get multiple commits
113+
output = Git.checkOutput(
114+
["log", "--pretty=format:%H", "--all"],
115+
repoDir=self.gitDir.name
116+
).decode()
117+
sha1_list = output.strip().split('\n')
118+
119+
self.assertGreater(len(sha1_list), 0)
120+
121+
# Setup logs
122+
self.commitPanel.showLogs(self.gitDir.name, file)
123+
self.wait(3000, lambda: self.logView.fetcher.isLoading())
124+
125+
# Create blame line for first commit
126+
blameLine = BlameLine()
127+
blameLine.sha1 = sha1_list[0]
128+
blameLine.previous = None
129+
130+
# Show the revision
131+
self.commitPanel.showRevision(blameLine)
132+
self.wait(300)
133+
134+
# Trigger another log fetch
135+
self.logView.setCurrentIndex(-1)
136+
self.commitPanel.showLogs(self.gitDir.name, file, rev="HEAD~1")
137+
138+
# Wait for the new fetch to complete
139+
self.wait(3000, lambda: self.logView.fetcher.isLoading())
140+
141+
# The key test: After endFetch, the current index should NOT be automatically
142+
# changed by a now-removed _onLogFetchFinished handler
143+
# Since _selectOnFetch is False, it should remain -1
144+
finalIndex = self.logView.currentIndex()
145+
146+
# With the fix, the index should remain -1 or be controlled by our explicit calls,
147+
# not automatically set by the endFetch signal
148+
# If _selectOnFetch is False and we don't explicitly call setCurrentIndex,
149+
# it should not auto-select on fetch finish
150+
self.assertEqual(finalIndex, -1)
151+
152+
def test_race_condition_blame_finishes_before_log(self):
153+
"""
154+
Test the race condition fix: when blame fetch finishes before log fetch
155+
156+
This was the original bug: if blame fetch completed first, the active line
157+
could be incorrect because _onLogFetchFinished would update the selection.
158+
159+
With the fix:
160+
- setAllowSelectOnFetch(False) prevents automatic selection
161+
- switchToCommit uses delay when fetcher is loading
162+
- No endFetch handler interferes with the selection
163+
"""
164+
file = os.path.join(self.gitDir.name, "test.py")
165+
166+
# Get commit SHA1
167+
sha1 = Git.checkOutput(
168+
["log", "-1", "--pretty=format:%H", file]).rstrip().decode()
169+
170+
# Create a BlameLine
171+
blameLine = BlameLine()
172+
blameLine.sha1 = sha1
173+
blameLine.previous = None
174+
175+
# Mock fetcher to simulate it's still loading (race condition scenario)
176+
with patch.object(self.logView.fetcher, 'isLoading', return_value=True):
177+
# Start showing logs
178+
self.commitPanel.showLogs(self.gitDir.name, file)
179+
180+
# Show revision while "fetcher is loading" (simulating blame fetch completing first)
181+
self.commitPanel.showRevision(blameLine)
182+
183+
# Verify that preferSha1 is set (delay path taken)
184+
self.assertEqual(self.logView.preferSha1, sha1)
185+
186+
# Now complete the actual fetch
187+
self.wait(3000, lambda: self.logView.fetcher.isLoading())
188+
189+
# After fetch completes, preferSha1 should have been used to select the commit
190+
currentIndex = self.logView.currentIndex()
191+
self.assertNotEqual(currentIndex, -1)
192+
currentCommit = self.logView.getCommit(currentIndex)
193+
self.assertEqual(currentCommit.sha1, sha1)
194+
195+
def test_selectOnFetch_false_no_auto_selection_on_empty(self):
196+
"""Test that with _selectOnFetch=False, no auto-selection occurs even with data"""
197+
# This tests the specific code path in __onFetchFinished
198+
# where _selectOnFetch is checked
199+
200+
self.assertFalse(self.logView._selectOnFetch)
201+
self.assertEqual(self.logView.currentIndex(), -1)
202+
203+
file = os.path.join(self.gitDir.name, "test.py")
204+
205+
# Show logs without setting preferSha1
206+
self.logView.preferSha1 = None
207+
self.commitPanel.showLogs(self.gitDir.name, file)
208+
self.wait(3000, lambda: self.logView.fetcher.isLoading())
209+
210+
self.assertEqual(self.logView.currentIndex(), -1)
211+
self.assertGreater(len(self.logView.data), 0)
212+
213+
def test_switchToCommit_same_commit_already_selected(self):
214+
"""Test switchToCommit when the same commit is already selected"""
215+
file = os.path.join(self.gitDir.name, "test.py")
216+
217+
# Setup: fetch logs and select a commit
218+
self.commitPanel.showLogs(self.gitDir.name, file)
219+
self.wait(3000, lambda: self.logView.fetcher.isLoading())
220+
221+
# Select first commit
222+
self.logView.setCurrentIndex(0)
223+
firstCommit = self.logView.getCommit(0)
224+
sha1 = firstCommit.sha1
225+
226+
# Try to switch to the same commit
227+
result = self.logView.switchToCommit(sha1, delay=False)
228+
229+
# Should return True and stay on same index
230+
self.assertTrue(result)
231+
self.assertEqual(self.logView.currentIndex(), 0)
232+
233+
def test_switchToCommit_commit_not_found(self):
234+
"""Test switchToCommit when commit is not in the log"""
235+
file = os.path.join(self.gitDir.name, "test.py")
236+
237+
# Setup: fetch logs
238+
self.commitPanel.showLogs(self.gitDir.name, file)
239+
self.wait(3000, lambda: self.logView.fetcher.isLoading())
240+
241+
# Try to switch to a non-existent commit
242+
fake_sha1 = "0000000000000000000000000000000000000000"
243+
result = self.logView.switchToCommit(fake_sha1, delay=False)
244+
245+
# Should return False when commit not found and not loading
246+
self.assertFalse(result)
247+
248+
def test_switchToCommit_commit_not_found_while_loading(self):
249+
"""Test switchToCommit when commit not found but fetcher is loading"""
250+
# Try to switch to a commit while loading
251+
fake_sha1 = "1111111111111111111111111111111111111111"
252+
253+
# Mock fetcher to simulate loading state
254+
with patch.object(self.logView.fetcher, 'isLoading', return_value=True):
255+
# Should set preferSha1 and return True even if commit not found yet
256+
result = self.logView.switchToCommit(fake_sha1, delay=True)
257+
self.assertTrue(result)
258+
self.assertEqual(self.logView.preferSha1, fake_sha1)
259+
260+
def test_switchToCommit_with_fetcher_not_loading(self):
261+
"""Test switchToCommit with delay=True when fetcher is NOT loading"""
262+
# Setup: fetch logs first
263+
file = os.path.join(self.gitDir.name, "test.py")
264+
self.commitPanel.showLogs(self.gitDir.name, file)
265+
self.wait(3000, lambda: self.logView.fetcher.isLoading())
266+
267+
fake_sha1 = "2222222222222222222222222222222222222222"
268+
269+
# Mock fetcher to ensure it's NOT loading
270+
with patch.object(self.logView.fetcher, 'isLoading', return_value=False):
271+
# With delay=True but commit not found and not loading
272+
# it should still set preferSha1 (because delay=True)
273+
result = self.logView.switchToCommit(fake_sha1, delay=True)
274+
self.assertTrue(result)
275+
self.assertEqual(self.logView.preferSha1, fake_sha1)
276+
277+
def test_showRevision_with_fetcher_not_loading(self):
278+
"""Test showRevision when fetcher is NOT loading"""
279+
file = os.path.join(self.gitDir.name, "test.py")
280+
281+
# Setup: fetch logs first
282+
self.commitPanel.showLogs(self.gitDir.name, file)
283+
self.wait(3000, lambda: self.logView.fetcher.isLoading())
284+
285+
# Get a commit
286+
sha1 = self.logView.data[0].sha1
287+
blameLine = BlameLine()
288+
blameLine.sha1 = sha1
289+
blameLine.previous = None
290+
291+
# Mock fetcher.isLoading() to return False
292+
with patch.object(self.logView.fetcher, 'isLoading', return_value=False):
293+
self.commitPanel.showRevision(blameLine)
294+
295+
# Should have switched immediately, not set preferSha1
296+
# (because delay parameter would be False when not loading)
297+
self.assertIsNone(self.logView.preferSha1)
298+
# And current index should be set
299+
self.assertEqual(self.logView.currentIndex(), 0)

0 commit comments

Comments
 (0)