Skip to content

Commit df1d463

Browse files
committed
Add coverage for folder functionality
Extend app-page tests for folder create/assign/rename/delete, ordering, collapse behavior, scope-specific persistence, and menu entries. Add VM manager test for folder scope feature events. Adjust tests to avoid mock qubesd feature-set calls by using local feature dict/mocks where needed.
1 parent 435519c commit df1d463

2 files changed

Lines changed: 178 additions & 1 deletion

File tree

qubes_menu/tests/test_app_page.py

Lines changed: 151 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
# You should have received a copy of the GNU Lesser General Public License along
1919
# with this program; if not, see <http://www.gnu.org/licenses/>.
2020
from unittest import mock
21+
import json
2122

2223
from ..desktop_file_manager import DesktopFileManager
2324
from ..vm_manager import VMManager
24-
from ..custom_widgets import VMRow
25+
from ..custom_widgets import VMRow, FolderRow
26+
from .. import constants
2527
from qubesadmin.tests.mock_app import MockDispatcher, MockQube
2628
from ..application_page import AppPage
2729
from ..settings_page import SettingsPage
@@ -172,3 +174,151 @@ def test_settings_app_page(test_desktop_file_path, test_qapp, test_builder):
172174

173175
for row in settings_page.app_list.get_children():
174176
assert not row.app_info.vm
177+
178+
179+
def test_folder_create_assign_rename_delete(
180+
test_desktop_file_path, test_qapp, test_builder
181+
):
182+
dispatcher = MockDispatcher(test_qapp)
183+
vm_manager = VMManager(test_qapp, dispatcher)
184+
185+
with mock.patch.object(
186+
DesktopFileManager, "desktop_dirs", [test_desktop_file_path]
187+
):
188+
desktop_file_manager = DesktopFileManager(test_qapp)
189+
190+
app_page = AppPage(vm_manager, test_builder, desktop_file_manager)
191+
app_page.toggle_buttons.apps_toggle.set_active(True)
192+
app_page._save_folder_state = mock.Mock()
193+
app_page._save_collapsed_state = mock.Mock()
194+
195+
vm_entry = vm_manager.load_vm_from_name("test-red")
196+
assert vm_entry
197+
vm_entry.vm.features = {}
198+
199+
app_page._create_folder("Work")
200+
assert "Work" in app_page.folder_order
201+
202+
app_page._assign_folder(vm_entry, "Work")
203+
assert app_page._vm_folder(vm_entry) == "Work"
204+
assert vm_entry.vm.features[constants.FOLDER_FEATURE_APPS] == "Work"
205+
206+
app_page._rename_folder("Work", "Projects")
207+
assert "Work" not in app_page.folder_order
208+
assert "Projects" in app_page.folder_order
209+
assert app_page._vm_folder(vm_entry) == "Projects"
210+
assert vm_entry.vm.features[constants.FOLDER_FEATURE_APPS] == "Projects"
211+
212+
app_page._delete_folder("Projects")
213+
assert "Projects" not in app_page.folder_order
214+
assert app_page._vm_folder(vm_entry) == ""
215+
assert constants.FOLDER_FEATURE_APPS not in vm_entry.vm.features
216+
217+
218+
def test_folder_move_and_collapsed_state_saved(
219+
test_desktop_file_path, test_qapp, test_builder
220+
):
221+
dispatcher = MockDispatcher(test_qapp)
222+
vm_manager = VMManager(test_qapp, dispatcher)
223+
224+
with mock.patch.object(
225+
DesktopFileManager, "desktop_dirs", [test_desktop_file_path]
226+
):
227+
desktop_file_manager = DesktopFileManager(test_qapp)
228+
229+
app_page = AppPage(vm_manager, test_builder, desktop_file_manager)
230+
app_page.toggle_buttons.apps_toggle.set_active(True)
231+
app_page._save_folder_state = mock.Mock()
232+
app_page._save_collapsed_state = mock.Mock()
233+
234+
app_page._create_folder("A")
235+
app_page._create_folder("B")
236+
app_page._create_folder("C")
237+
assert app_page.folder_order == [app_page.UNGROUPED, "A", "B", "C"]
238+
239+
app_page._move_folder(None, "B", -1)
240+
assert app_page.folder_order == [app_page.UNGROUPED, "B", "A", "C"]
241+
242+
app_page._move_folder(None, "B", 1)
243+
assert app_page.folder_order == [app_page.UNGROUPED, "A", "B", "C"]
244+
245+
folder_b = app_page.folder_rows["B"]
246+
assert isinstance(folder_b, FolderRow)
247+
assert "B" not in app_page.collapsed_folders
248+
249+
app_page._toggle_folder(folder_b)
250+
assert "B" in app_page.collapsed_folders
251+
app_page._save_collapsed_state.assert_called()
252+
253+
app_page._set_all_folders_collapsed(None, True)
254+
assert set(app_page.folder_order) == app_page.collapsed_folders
255+
256+
app_page._set_all_folders_collapsed(None, False)
257+
assert app_page.collapsed_folders == set()
258+
259+
260+
def test_folder_state_is_scope_specific(test_desktop_file_path, test_qapp, test_builder):
261+
test_qapp._qubes["dom0"].features[constants.FOLDERS_FEATURE_APPS] = json.dumps(
262+
["Ungrouped", "AppsOnly"]
263+
)
264+
test_qapp._qubes["dom0"].features[
265+
constants.FOLDERS_COLLAPSED_FEATURE_APPS
266+
] = json.dumps(["AppsOnly"])
267+
test_qapp._qubes["dom0"].features[constants.FOLDERS_FEATURE_TEMPLATES] = (
268+
json.dumps(["Ungrouped", "TplOnly"])
269+
)
270+
test_qapp._qubes["dom0"].features[constants.FOLDERS_FEATURE_SERVICE] = (
271+
json.dumps(["Ungrouped", "SvcOnly"])
272+
)
273+
test_qapp.update_vm_calls()
274+
275+
dispatcher = MockDispatcher(test_qapp)
276+
vm_manager = VMManager(test_qapp, dispatcher)
277+
278+
with mock.patch.object(
279+
DesktopFileManager, "desktop_dirs", [test_desktop_file_path]
280+
):
281+
desktop_file_manager = DesktopFileManager(test_qapp)
282+
283+
app_page = AppPage(vm_manager, test_builder, desktop_file_manager)
284+
285+
app_page.toggle_buttons.apps_toggle.set_active(True)
286+
assert app_page.folder_order == ["Ungrouped", "AppsOnly"]
287+
assert app_page.collapsed_folders == {"AppsOnly"}
288+
289+
app_page.toggle_buttons.templates_toggle.set_active(True)
290+
assert app_page.folder_order == ["Ungrouped", "TplOnly"]
291+
292+
app_page.toggle_buttons.system_toggle.set_active(True)
293+
assert app_page.folder_order == ["Ungrouped", "SvcOnly"]
294+
295+
296+
def test_folder_selection_menu_entries(test_desktop_file_path, test_qapp, test_builder):
297+
dispatcher = MockDispatcher(test_qapp)
298+
vm_manager = VMManager(test_qapp, dispatcher)
299+
300+
with mock.patch.object(
301+
DesktopFileManager, "desktop_dirs", [test_desktop_file_path]
302+
):
303+
desktop_file_manager = DesktopFileManager(test_qapp)
304+
305+
app_page = AppPage(vm_manager, test_builder, desktop_file_manager)
306+
app_page.toggle_buttons.apps_toggle.set_active(True)
307+
app_page._save_folder_state = mock.Mock()
308+
app_page._save_collapsed_state = mock.Mock()
309+
310+
vm_entry = vm_manager.load_vm_from_name("test-red")
311+
assert vm_entry
312+
vm_entry.vm.features = {}
313+
314+
app_page._create_folder("Work")
315+
app_page._create_folder("Personal")
316+
app_page._assign_folder(vm_entry, "Work")
317+
318+
submenu = app_page._folder_selection_menu(vm_entry, include_remove=True)
319+
labels = [item.get_label() for item in submenu.get_children()]
320+
321+
assert "Work" not in labels
322+
assert "Personal" in labels
323+
assert "Create new folder…" in labels
324+
assert "Remove from folder" in labels

qubes_menu/tests/test_vmmanager.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import qubesadmin
2222
import qubesadmin.events
23+
from unittest import mock
2324
from ..vm_manager import VMManager
2425
from ..application_page import VMTypeToggle
2526
from .. import constants
@@ -163,3 +164,29 @@ def test_filter(test_qapp):
163164
assert VMTypeToggle._filter_appvms(entry_dvm_template)
164165
assert VMTypeToggle._filter_templatevms(entry_dvm_template)
165166
assert not VMTypeToggle._filter_service(entry_dvm_template)
167+
168+
169+
def test_folder_scope_feature_events_refresh_entries(test_qapp):
170+
dispatcher = qubesadmin.events.EventsDispatcher(test_qapp)
171+
vm_manager = VMManager(test_qapp, dispatcher)
172+
173+
vm_name = "test-vm"
174+
entry_test = vm_manager.load_vm_from_name(vm_name)
175+
assert entry_test
176+
177+
with mock.patch.object(entry_test, "update_entries") as update_entries:
178+
vm_manager._update_domain_feature(
179+
vm_name,
180+
f"feature-set:{constants.FOLDER_FEATURE_APPS}",
181+
feature=constants.FOLDER_FEATURE_APPS,
182+
value="Work",
183+
)
184+
update_entries.assert_called_once_with(update_type=True)
185+
186+
with mock.patch.object(entry_test, "update_entries") as update_entries:
187+
vm_manager._update_domain_feature(
188+
vm_name,
189+
f"feature-delete:{constants.FOLDER_FEATURE_TEMPLATES}",
190+
feature=constants.FOLDER_FEATURE_TEMPLATES,
191+
)
192+
update_entries.assert_called_once_with(update_type=True)

0 commit comments

Comments
 (0)