Skip to content

Commit f65feaf

Browse files
committed
Split up tests into related files
1 parent 9202977 commit f65feaf

File tree

10 files changed

+1294
-1218
lines changed

10 files changed

+1294
-1218
lines changed

tests/test_base.py

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
"""test_base.py
2+
3+
Base test class for docklib tests. Contains common setup/teardown and basic tests.
4+
"""
5+
6+
import os
7+
import pwd
8+
import types
9+
import unittest
10+
from unittest.mock import patch, MagicMock
11+
12+
import docklib
13+
14+
15+
class BaseDocklibTest(unittest.TestCase):
16+
"""Base test class with common setup and teardown for all docklib tests."""
17+
18+
def setUp(self):
19+
# Mock the LaunchAgentManager for the new implementation
20+
self.mock_launch_agent_patcher = patch("docklib.docklib.LaunchAgentManager")
21+
self.mock_launch_agent_class = self.mock_launch_agent_patcher.start()
22+
self.mock_launch_agent = MagicMock()
23+
self.mock_launch_agent.bootstrap.return_value = True
24+
self.mock_launch_agent.bootout.return_value = True
25+
self.mock_launch_agent_class.return_value = self.mock_launch_agent
26+
27+
# Mock subprocess.run for LaunchAgentManager internal calls
28+
self.mock_subprocess_run_patcher = patch("docklib.docklib.subprocess.run")
29+
self.mock_subprocess_run = self.mock_subprocess_run_patcher.start()
30+
31+
# Create a mock result for subprocess.run
32+
mock_result = MagicMock()
33+
mock_result.returncode = 0
34+
mock_result.stderr = ""
35+
mock_result.stdout = ""
36+
self.mock_subprocess_run.return_value = mock_result
37+
38+
# Mock pwd for LaunchAgentManager initialization
39+
self.mock_pwd_patcher = patch("docklib.docklib.pwd")
40+
self.mock_pwd = self.mock_pwd_patcher.start()
41+
mock_user = MagicMock()
42+
mock_user.pw_uid = 501
43+
self.mock_pwd.getpwuid.return_value = mock_user
44+
45+
self.mock_cfpref_sync_patcher = patch(
46+
"docklib.docklib.CFPreferencesAppSynchronize"
47+
)
48+
self.mock_cfpref_sync = self.mock_cfpref_sync_patcher.start()
49+
self.mock_cfpref_sync.return_value = True
50+
51+
self.mock_cfpref_set_patcher = patch("docklib.docklib.CFPreferencesSetAppValue")
52+
self.mock_cfpref_set = self.mock_cfpref_set_patcher.start()
53+
54+
self.mock_cfpref_copy_patcher = patch(
55+
"docklib.docklib.CFPreferencesCopyAppValue"
56+
)
57+
self.mock_cfpref_copy = self.mock_cfpref_copy_patcher.start()
58+
59+
# Create mock objects that have mutableCopy method
60+
class MockNSArray:
61+
def __init__(self, data):
62+
self.data = data
63+
64+
def mutableCopy(self):
65+
return list(self.data)
66+
67+
# Mock the copy function to return our sample data
68+
def mock_copy_app_value(key, domain): # pylint: disable=unused-argument
69+
if key == "persistent-apps":
70+
return MockNSArray(
71+
[
72+
{
73+
"tile-type": "file-tile",
74+
"GUID": 12345,
75+
"tile-data": {
76+
"file-label": "Chess",
77+
"bundle-identifier": "com.apple.Chess",
78+
"file-data": {
79+
"_CFURLString": "file:///System/Applications/Chess.app/"
80+
},
81+
},
82+
}
83+
]
84+
)
85+
elif key == "persistent-others":
86+
return MockNSArray(
87+
[
88+
{
89+
"tile-type": "directory-tile",
90+
"GUID": 12346,
91+
"tile-data": {
92+
"file-label": "Application Support",
93+
"file-data": {
94+
"_CFURLString": "file:///Users/test/Library/Application%20Support/"
95+
},
96+
},
97+
}
98+
]
99+
)
100+
else:
101+
return None
102+
103+
self.mock_cfpref_copy.side_effect = mock_copy_app_value
104+
105+
# Create a dock instance
106+
self.dock = docklib.Dock()
107+
108+
# Store original data for resetting between tests
109+
self.original_persistent_apps = [
110+
{
111+
"tile-type": "file-tile",
112+
"GUID": 12345,
113+
"tile-data": {
114+
"file-label": "Chess",
115+
"bundle-identifier": "com.apple.Chess",
116+
"file-data": {
117+
"_CFURLString": "file:///System/Applications/Chess.app/"
118+
},
119+
},
120+
}
121+
]
122+
123+
self.original_persistent_others = [
124+
{
125+
"tile-type": "directory-tile",
126+
"GUID": 12346,
127+
"tile-data": {
128+
"file-label": "Application Support",
129+
"file-data": {
130+
"_CFURLString": "file:///Users/test/Library/Application%20Support/"
131+
},
132+
},
133+
}
134+
]
135+
136+
# Ensure the dock has proper mock data (reset to original state)
137+
self.dock.items["persistent-apps"] = self.original_persistent_apps.copy()
138+
self.dock.items["persistent-others"] = self.original_persistent_others.copy()
139+
140+
def tearDown(self):
141+
# Stop all patchers
142+
self.mock_launch_agent_patcher.stop()
143+
self.mock_subprocess_run_patcher.stop()
144+
self.mock_pwd_patcher.stop()
145+
self.mock_cfpref_sync_patcher.stop()
146+
self.mock_cfpref_set_patcher.stop()
147+
self.mock_cfpref_copy_patcher.stop()
148+
149+
150+
class TestDockBasics(BaseDocklibTest):
151+
"""Basic Dock initialization and import tests."""
152+
153+
def test_import(self):
154+
"""Tests that the docklib module can be imported."""
155+
import docklib # pylint: disable=import-outside-toplevel
156+
157+
self.assertTrue(docklib)
158+
159+
def test_init(self):
160+
"""Tests that a Dock object can be initialized."""
161+
dock = docklib.Dock()
162+
self.assertIsInstance(dock, docklib.Dock)
163+
164+
def test_sections(self):
165+
"""Test that the expected sections are returned in the items dict."""
166+
dock = docklib.Dock()
167+
self.assertIn("persistent-apps", dock.items)
168+
self.assertIn("persistent-others", dock.items)
169+
170+
def test_item_keys(self):
171+
"""Test that the expected keys are present in dock items."""
172+
expected_keys = ["tile-type", "tile-data"]
173+
for item in self.dock.items["persistent-apps"]:
174+
for key in expected_keys:
175+
self.assertIn(key, item)
176+
for item in self.dock.items["persistent-others"]:
177+
for key in expected_keys:
178+
self.assertIn(key, item)
179+
180+
def test_tile_data_keys(self):
181+
"""Test that expected tile-data keys are present."""
182+
expected_app_keys = [
183+
"file-label",
184+
"file-data",
185+
]
186+
for item in self.dock.items["persistent-apps"]:
187+
for key in expected_app_keys:
188+
self.assertIn(key, item["tile-data"])
189+
190+
expected_other_keys = [
191+
"file-label",
192+
"file-data",
193+
]
194+
for item in self.dock.items["persistent-others"]:
195+
for key in expected_other_keys:
196+
self.assertIn(key, item["tile-data"])
197+
198+
def test_tile_types(self):
199+
"""Test that expected tile-types are correct."""
200+
for item in self.dock.items["persistent-apps"]:
201+
self.assertEqual(item["tile-type"], "file-tile")
202+
for item in self.dock.items["persistent-others"]:
203+
self.assertIn(item["tile-type"], ["file-tile", "directory-tile"])

tests/test_dock_apps.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
"""test_dock_apps.py
2+
3+
Tests for Dock application operations (add/remove apps).
4+
"""
5+
6+
from unittest.mock import patch
7+
8+
from tests.test_base import BaseDocklibTest
9+
10+
11+
class TestDockApps(BaseDocklibTest):
12+
"""Tests for Dock application operations."""
13+
14+
def test_add_app(self):
15+
"""Ensure docklib can add apps to the dock."""
16+
# Mock the make entry method to return a predictable entry
17+
mock_entry = {
18+
"tile-type": "file-tile",
19+
"GUID": 12347,
20+
"tile-data": {
21+
"file-label": "Calculator",
22+
"bundle-identifier": "com.apple.calculator",
23+
"file-data": {
24+
"_CFURLString": "file:///System/Applications/Calculator.app/"
25+
},
26+
},
27+
}
28+
29+
# Mock makeDockAppEntry to return our mock entry
30+
with patch.object(self.dock, "makeDockAppEntry", return_value=mock_entry):
31+
item = self.dock.makeDockAppEntry("/System/Applications/Calculator.app")
32+
old_len = len(self.dock.items["persistent-apps"])
33+
self.dock.items["persistent-apps"].append(item)
34+
35+
# Test that the item was added in memory
36+
new_len = len(self.dock.items["persistent-apps"])
37+
self.assertEqual(new_len, old_len + 1)
38+
39+
# Verify the correct item was added
40+
added_item = self.dock.items["persistent-apps"][-1]
41+
self.assertEqual(added_item["tile-data"]["file-label"], "Calculator")
42+
43+
# Test that save() can be called without errors
44+
try:
45+
self.dock.save()
46+
save_succeeded = True
47+
except (AttributeError, TypeError, OSError) as e:
48+
# These are the expected exception types from dock operations
49+
save_succeeded = False
50+
print(f"Save failed with: {e}")
51+
52+
self.assertTrue(
53+
save_succeeded, "dock.save() should complete without errors"
54+
)
55+
56+
def test_remove_app(self):
57+
"""Ensure docklib can remove apps from the dock."""
58+
# Ensure Chess app is in the dock for this test
59+
initial_len = len(self.dock.items["persistent-apps"])
60+
61+
# Mock removeDockEntry to simulate removal
62+
with patch.object(self.dock, "removeDockEntry") as mock_remove:
63+
64+
def simulate_removal(label):
65+
if label == "Chess":
66+
# Find and remove Chess app from the list
67+
self.dock.items["persistent-apps"] = [
68+
item
69+
for item in self.dock.items["persistent-apps"]
70+
if item["tile-data"].get("file-label") != "Chess"
71+
]
72+
return True
73+
return False
74+
75+
mock_remove.side_effect = simulate_removal
76+
self.dock.removeDockEntry("Chess")
77+
self.dock.save()
78+
79+
new_len = len(self.dock.items["persistent-apps"])
80+
self.assertEqual(new_len, initial_len - 1)
81+
mock_remove.assert_called_with("Chess")
82+
# Verify LaunchAgentManager methods were called
83+
self.mock_launch_agent.bootout.assert_called_with("com.apple.Dock.agent")
84+
self.mock_launch_agent.bootstrap.assert_called_with(
85+
"/System/Library/LaunchAgents/com.apple.Dock.plist"
86+
)

0 commit comments

Comments
 (0)