Skip to content

Commit e3e7c84

Browse files
committed
Added test for hook files
1 parent 1b25b1d commit e3e7c84

4 files changed

Lines changed: 232 additions & 1 deletion

File tree

ChangeLog

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
* 2.0.1
2+
- Added unit tests for custom_config.py hook script.
3+
- Added unit tests for cleanup_config.py hook script.
4+
- Verified project tests pass by isolating from client_libs collection errors.
5+
- Fixed linting errors in new test files.
6+
17
* 2.0.0
28
- Hierachical context file for conversions troubleshooting.
39
- Added Conversion Troubleshooting & Diagnostics functionality (api_examples/collect_conversions_troubleshooting_data.py).
@@ -18,7 +24,6 @@
1824
- Changed name of setup files to install and provided an uninstall procedure.
1925
- Added additional rules for GAQL edge cases to GEMINI.md.
2026
- Added command conversions_support_data.
21-
>>>>>>> v1.6.0
2227

2328
* 1.5.0
2429
- Added rigorous GAQL validation rules to GEMINI.md

tests/test_cleanup_config.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import sys
2+
import os
3+
import unittest
4+
from unittest.mock import patch
5+
6+
# Add the project root to sys.path
7+
script_dir = os.path.dirname(os.path.abspath(__file__))
8+
project_root = os.path.abspath(os.path.join(script_dir, ".."))
9+
hooks_dir = os.path.join(project_root, ".gemini/hooks")
10+
sys.path.append(hooks_dir)
11+
12+
import cleanup_config # noqa: E402
13+
14+
class TestCleanupConfig(unittest.TestCase):
15+
16+
@patch("os.path.exists")
17+
@patch("os.listdir")
18+
@patch("os.path.isfile")
19+
@patch("os.path.isdir")
20+
@patch("os.unlink")
21+
@patch("shutil.rmtree")
22+
def test_cleanup_success(self, mock_rmtree, mock_unlink, mock_isdir, mock_isfile, mock_listdir, mock_exists):
23+
# Setup mocks
24+
mock_exists.return_value = True
25+
mock_listdir.return_value = ["file1.txt", "dir1", ".gitkeep"]
26+
27+
# Define side effects for isfile and isdir
28+
def is_file_side_effect(path):
29+
return "file1.txt" in path
30+
def is_dir_side_effect(path):
31+
return "dir1" in path
32+
33+
mock_isfile.side_effect = is_file_side_effect
34+
mock_isdir.side_effect = is_dir_side_effect
35+
36+
cleanup_config.cleanup()
37+
38+
# Verify calls
39+
mock_unlink.assert_called_once()
40+
self.assertIn("file1.txt", mock_unlink.call_args[0][0])
41+
42+
mock_rmtree.assert_called_once()
43+
self.assertIn("dir1", mock_rmtree.call_args[0][0])
44+
45+
# Verify .gitkeep was NOT touched
46+
for call in mock_unlink.call_args_list:
47+
self.assertNotIn(".gitkeep", call[0][0])
48+
49+
@patch("os.path.exists")
50+
def test_cleanup_no_config_dir(self, mock_exists):
51+
mock_exists.return_value = False
52+
with patch("sys.stderr") as mock_stderr:
53+
cleanup_config.cleanup()
54+
mock_stderr.write.assert_called()
55+
# Should not call listdir if it doesn't exist
56+
with patch("os.listdir") as mock_listdir:
57+
cleanup_config.cleanup()
58+
mock_listdir.assert_not_called()
59+
60+
if __name__ == "__main__":
61+
unittest.main()

tests/test_custom_config.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import sys
2+
import os
3+
import unittest
4+
from unittest.mock import patch, MagicMock, mock_open
5+
6+
# Add the project root to sys.path so we can import the hook scripts
7+
script_dir = os.path.dirname(os.path.abspath(__file__))
8+
project_root = os.path.abspath(os.path.join(script_dir, ".."))
9+
hooks_dir = os.path.join(project_root, ".gemini/hooks")
10+
sys.path.append(hooks_dir)
11+
12+
import custom_config # noqa: E402
13+
14+
class TestCustomConfig(unittest.TestCase):
15+
16+
def test_get_version_success(self):
17+
with patch("subprocess.run") as mocked_run:
18+
mocked_run.return_value = MagicMock(stdout="2.1.0\n", check=True)
19+
version = custom_config.get_version("dummy_script.py")
20+
self.assertEqual(version, "2.1.0")
21+
mocked_run.assert_called_once()
22+
23+
def test_get_version_failure(self):
24+
with patch("subprocess.run") as mocked_run:
25+
mocked_run.side_effect = Exception("failed")
26+
version = custom_config.get_version("dummy_script.py")
27+
self.assertEqual(version, "2.0.0") # Fallback
28+
29+
def test_parse_ruby_config(self):
30+
content = """
31+
c.developer_token = 'token123'
32+
c.client_id = "id456"
33+
c.client_secret = 'secret789'
34+
"""
35+
with patch("builtins.open", mock_open(read_data=content)):
36+
data = custom_config.parse_ruby_config("dummy.rb")
37+
self.assertEqual(data["developer_token"], "token123")
38+
self.assertEqual(data["client_id"], "id456")
39+
self.assertEqual(data["client_secret"], "secret789")
40+
41+
def test_parse_ini_config(self):
42+
content = "[DEFAULT]\ndeveloper_token = token123\nclient_id = 'id456'\n"
43+
with patch("builtins.open", mock_open(read_data=content)):
44+
data = custom_config.parse_ini_config("dummy.ini")
45+
self.assertEqual(data["developer_token"], "token123")
46+
self.assertEqual(data["client_id"], "id456")
47+
48+
def test_parse_properties_config(self):
49+
content = "api.googleads.developerToken=token123\napi.googleads.clientId=id456\n"
50+
with patch("builtins.open", mock_open(read_data=content)):
51+
data = custom_config.parse_properties_config("dummy.properties")
52+
self.assertEqual(data["developer_token"], "token123")
53+
self.assertEqual(data["client_id"], "id456")
54+
55+
def test_write_yaml_config_oauth2(self):
56+
data = {
57+
"developer_token": "token123",
58+
"client_id": "id456",
59+
"client_secret": "secret789",
60+
"refresh_token": "refresh000"
61+
}
62+
with patch("builtins.open", mock_open()) as mocked_file:
63+
success = custom_config.write_yaml_config(data, "dummy.yaml", "2.1.0")
64+
self.assertTrue(success)
65+
handle = mocked_file()
66+
handle.write.assert_any_call("developer_token: token123\n")
67+
handle.write.assert_any_call("client_id: id456\n")
68+
handle.write.assert_any_call("gaada: \"2.1.0\"\n")
69+
70+
def test_write_yaml_config_service_account(self):
71+
data = {
72+
"developer_token": "token123",
73+
"json_key_file_path": "/path/to/key.json",
74+
"impersonated_email": "user@example.com"
75+
}
76+
with patch("builtins.open", mock_open()) as mocked_file:
77+
success = custom_config.write_yaml_config(data, "dummy.yaml", "2.1.0")
78+
self.assertTrue(success)
79+
handle = mocked_file()
80+
handle.write.assert_any_call("json_key_file_path: /path/to/key.json\n")
81+
handle.write.assert_any_call("impersonated_email: user@example.com\n")
82+
# Verify client_id is NOT written
83+
for call in handle.write.call_args_list:
84+
self.assertNotIn("client_id:", call[0][0])
85+
86+
def test_configure_language(self):
87+
with patch("os.path.exists", return_value=True), \
88+
patch("shutil.copy2") as mocked_copy, \
89+
patch("builtins.open", mock_open()) as mocked_file:
90+
success = custom_config.configure_language("Python", "home.yaml", "target.yaml", "2.1.0", is_python=True)
91+
self.assertTrue(success)
92+
mocked_copy.assert_called_once_with("home.yaml", "target.yaml")
93+
handle = mocked_file()
94+
handle.write.assert_called_with('\ngaada: "2.1.0"\n')
95+
96+
if __name__ == "__main__":
97+
unittest.main()
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import sys
2+
import os
3+
import unittest
4+
from unittest.mock import patch, MagicMock
5+
6+
# Add .gemini/hooks to sys.path
7+
script_dir = os.path.dirname(os.path.abspath(__file__))
8+
hooks_dir = os.path.join(script_dir, "../.gemini/hooks")
9+
sys.path.append(hooks_dir)
10+
11+
import custom_config
12+
13+
class TestCustomConfig(unittest.TestCase):
14+
15+
def test_parse_ruby_config_service_account(self):
16+
content = """
17+
GoogleAds::Config.new do |c|
18+
c.developer_token = 'TEST_TOKEN'
19+
c.json_key_file_path = '/path/to/key.json'
20+
c.impersonated_email = 'user@example.com'
21+
end
22+
"""
23+
with patch("builtins.open", unittest.mock.mock_open(read_data=content)):
24+
data = custom_config.parse_ruby_config("dummy.rb")
25+
self.assertEqual(data["json_key_file_path"], "/path/to/key.json")
26+
self.assertEqual(data["impersonated_email"], "user@example.com")
27+
28+
def test_parse_ini_config_service_account(self):
29+
content = """
30+
[GOOGLE_ADS]
31+
developer_token = "TEST_TOKEN"
32+
json_key_file_path = "/path/to/key.json"
33+
impersonated_email = "user@example.com"
34+
"""
35+
with patch("builtins.open", unittest.mock.mock_open(read_data=content)):
36+
data = custom_config.parse_ini_config("dummy.ini")
37+
self.assertEqual(data["json_key_file_path"], "/path/to/key.json")
38+
self.assertEqual(data["impersonated_email"], "user@example.com")
39+
40+
def test_parse_properties_config_service_account(self):
41+
content = """
42+
api.googleads.developerToken=TEST_TOKEN
43+
api.googleads.oAuth2SecretsJsonPath=/path/to/key.json
44+
api.googleads.oAuth2PrnEmail=user@example.com
45+
"""
46+
with patch("builtins.open", unittest.mock.mock_open(read_data=content)):
47+
data = custom_config.parse_properties_config("dummy.properties")
48+
self.assertEqual(data["json_key_file_path"], "/path/to/key.json")
49+
self.assertEqual(data["impersonated_email"], "user@example.com")
50+
51+
def test_write_yaml_config_service_account(self):
52+
data = {
53+
"developer_token": "TEST_TOKEN",
54+
"json_key_file_path": "/path/to/key.json",
55+
"impersonated_email": "user@example.com"
56+
}
57+
with patch("builtins.open", unittest.mock.mock_open()) as mocked_file:
58+
custom_config.write_yaml_config(data, "dummy.yaml", "2.0.0")
59+
mocked_file.assert_called_once_with("dummy.yaml", "w")
60+
handle = mocked_file()
61+
# Verify json_key_file_path is written
62+
handle.write.assert_any_call("json_key_file_path: /path/to/key.json\n")
63+
# Verify client_id is NOT written
64+
for call in handle.write.call_args_list:
65+
self.assertNotIn("client_id:", call[0][0])
66+
67+
if __name__ == "__main__":
68+
unittest.main()

0 commit comments

Comments
 (0)