2121# * *
2222# ***************************************************************************
2323
24+ """ Test the Change Branch GUI code"""
25+
26+ # pylint: disable=wrong-import-position, deprecated-module, too-many-return-statements
27+
2428import sys
2529import unittest
2630from unittest .mock import patch , Mock , MagicMock
2731
2832# So that when run standalone, the Addon Manager classes imported below are available
2933sys .path .append ("../.." )
3034
31- from AddonManagerTest .gui .gui_mocks import DialogWatcher , DialogInteractor , AsynchronousMonitor
35+ from AddonManagerTest .gui .gui_mocks import DialogWatcher , AsynchronousMonitor
3236
3337from change_branch import ChangeBranchDialog
3438
4549
4650
4751class MockFilter (QtCore .QSortFilterProxyModel ):
52+ """Replaces a filter with a non-filter that simply always returns whatever it's given"""
53+
4854 def mapToSource (self , something ):
4955 return something
5056
5157
5258class MockChangeBranchDialogModel (QtCore .QAbstractTableModel ):
59+ """Replace a data-connected model with a static one for testing"""
5360
5461 branches = [
5562 {"ref_name" : "ref1" , "upstream" : "us1" },
@@ -64,40 +71,45 @@ def __init__(self, _: str, parent=None) -> None:
6471 super ().__init__ (parent )
6572
6673 def rowCount (self , parent : QtCore .QModelIndex = QtCore .QModelIndex ()) -> int :
74+ """Number of rows: should always return 3"""
6775 if parent .isValid ():
6876 return 0
6977 return len (self .branches )
7078
7179 def columnCount (self , parent : QtCore .QModelIndex = QtCore .QModelIndex ()) -> int :
80+ """Number of columns (identical to non-mocked version)"""
7281 if parent .isValid ():
7382 return 0
7483 return 3 # Local name, remote name, date
7584
7685 def data (self , index : QtCore .QModelIndex , role : int = QtCore .Qt .DisplayRole ):
86+ """Mock returns static untranslated strings for DisplayRole, no tooltips at all, and
87+ otherwise matches the non-mock version"""
7788 if not index .isValid ():
7889 return None
7990 row = index .row ()
8091 column = index .column ()
8192 if role == QtCore .Qt .DisplayRole :
8293 if column == 2 :
8394 return "date"
84- elif column == 0 :
95+ if column == 0 :
8596 return "ref_name"
86- elif column == 1 :
97+ if column == 1 :
8798 return "upstream"
88- else :
89- return None
90- elif role == MockChangeBranchDialogModel .DataSortRole :
9199 return None
92- elif role == MockChangeBranchDialogModel .RefAccessRole :
100+ if role == MockChangeBranchDialogModel .DataSortRole :
101+ return None
102+ if role == MockChangeBranchDialogModel .RefAccessRole :
93103 return self .branches [row ]
104+ return None
94105
95106 def headerData (
96107 self ,
97108 section : int ,
98109 orientation : QtCore .Qt .Orientation ,
99110 role : int = QtCore .Qt .DisplayRole ,
100111 ):
112+ """Mock returns untranslated strings for DisplayRole, and no tooltips at all"""
101113 if orientation == QtCore .Qt .Vertical :
102114 return None
103115 if role != QtCore .Qt .DisplayRole :
@@ -106,16 +118,18 @@ def headerData(
106118 return "Local"
107119 if section == 1 :
108120 return "Remote tracking"
109- elif section == 2 :
121+ if section == 2 :
110122 return "Last Updated"
111- else :
112- return None
123+ return None
113124
114125 def currentBranch (self ) -> str :
126+ """Mock returns a static string stored in the class: that string could be modified to
127+ return something else by tests that require it."""
115128 return self .current_branch
116129
117130
118131class TestChangeBranchGui (unittest .TestCase ):
132+ """Tests for the ChangeBranch GUI code"""
119133
120134 MODULE = "test_change_branch" # file name without extension
121135
@@ -128,6 +142,7 @@ def tearDown(self):
128142 @patch ("change_branch.ChangeBranchDialogModel" , new = MockChangeBranchDialogModel )
129143 @patch ("change_branch.initialize_git" , new = Mock (return_value = None ))
130144 def test_no_git (self ):
145+ """If git is not present, a dialog saying so is presented"""
131146 # Arrange
132147 gui = ChangeBranchDialog ("/some/path" )
133148 ref = {"ref_name" : "foo/bar" , "upstream" : "us1" }
@@ -137,14 +152,15 @@ def test_no_git(self):
137152 )
138153
139154 # Act
140- gui ._change_branch ("/foo/bar/baz" , ref )
155+ gui .change_branch ("/foo/bar/baz" , ref )
141156
142157 # Assert
143158 self .assertTrue (dialog_watcher .dialog_found , "Failed to find the expected dialog box" )
144159
145160 @patch ("change_branch.ChangeBranchDialogModel" , new = MockChangeBranchDialogModel )
146161 @patch ("change_branch.initialize_git" )
147162 def test_git_failed (self , init_git : MagicMock ):
163+ """If git fails when attempting to change branches, a dialog saying so is presented"""
148164 # Arrange
149165 git_manager = MagicMock ()
150166 git_manager .checkout = MagicMock ()
@@ -158,24 +174,24 @@ def test_git_failed(self, init_git: MagicMock):
158174 )
159175
160176 # Act
161- gui ._change_branch ("/foo/bar/baz" , ref )
177+ gui .change_branch ("/foo/bar/baz" , ref )
162178
163179 # Assert
164180 self .assertTrue (dialog_watcher .dialog_found , "Failed to find the expected dialog box" )
165181
166182 @patch ("change_branch.ChangeBranchDialogModel" , new = MockChangeBranchDialogModel )
167183 @patch ("change_branch.initialize_git" , new = MagicMock )
168184 def test_branch_change_succeeded (self ):
169- # If nothing gets thrown, then the process is assumed to have worked, and the appropriate
170- # signal is emitted.
185+ """ If nothing gets thrown, then the process is assumed to have worked, and the appropriate
186+ signal is emitted."""
171187
172188 # Arrange
173189 gui = ChangeBranchDialog ("/some/path" )
174190 ref = {"ref_name" : "foo/bar" , "upstream" : "us1" }
175191 monitor = AsynchronousMonitor (gui .branch_changed )
176192
177193 # Act
178- gui ._change_branch ("/foo/bar/baz" , ref )
194+ gui .change_branch ("/foo/bar/baz" , ref )
179195
180196 # Assert
181197 monitor .wait_for_at_most (10 ) # Should be effectively instantaneous
@@ -185,6 +201,8 @@ def test_branch_change_succeeded(self):
185201 @patch ("change_branch.ChangeBranchDialogModel" , new = MockChangeBranchDialogModel )
186202 @patch ("change_branch.initialize_git" , new = MagicMock )
187203 def test_warning_is_shown_when_dialog_is_accepted (self ):
204+ """If the dialog is accepted (e.g. a branch change is requested) then a warning dialog is
205+ displayed, and gives the opportunity to cancel. If cancelled, no signal is emitted."""
188206 # Arrange
189207 gui = ChangeBranchDialog ("/some/path" )
190208 gui .ui .exec = MagicMock ()
@@ -197,12 +215,14 @@ def test_warning_is_shown_when_dialog_is_accepted(self):
197215 translate ("AddonsInstaller" , "DANGER: Developer feature" ),
198216 QtWidgets .QDialogButtonBox .Cancel ,
199217 )
218+ monitor = AsynchronousMonitor (gui .branch_changed )
200219
201220 # Act
202221 gui .exec ()
203222
204223 # Assert
205224 self .assertTrue (dialog_watcher .dialog_found , "Failed to find the expected dialog box" )
225+ self .assertFalse (monitor .good ()) # The watcher cancelled the op, so no signal is emitted
206226
207227
208228if __name__ == "__main__" :
0 commit comments