Skip to content

Commit 45e858b

Browse files
committed
Generate unit tests
1 parent 48daf63 commit 45e858b

20 files changed

+2113
-0
lines changed

.coveragerc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[run]
2+
include = pre_commit_hooks/*

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
# Unittest
88
__pycache__/
99
.coverage
10+
coverage.xml
1011
htmlcov/
1112

1213
# Virtual environment

RELEASING.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
1. Update the versions in __README.md__ and __setup.py__.
44

5+
1. Check unit tests:
6+
7+
venv/bin/python -m coverage run -m unittest discover -vs tests
8+
59
1. Update the change log.
610

711
1. Merge development branch to main.
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
"""test_check_autopkg_recipe_list.py
2+
3+
Unit tests for the functions in check_autopkg_recipe_list.py."""
4+
5+
import io
6+
import os
7+
import plistlib
8+
import sys
9+
import tempfile
10+
import unittest
11+
12+
import pre_commit_hooks.check_autopkg_recipe_list as target
13+
14+
15+
class TestCheckAutopkgRecipeList(unittest.TestCase):
16+
def run_main_with_files(self, files):
17+
# Helper to run main() with given files and capture stdout
18+
sys_stdout = sys.stdout
19+
out = io.StringIO()
20+
sys.stdout = out
21+
try:
22+
retval = target.main(files)
23+
finally:
24+
sys.stdout = sys_stdout
25+
return retval, out.getvalue()
26+
27+
def test_build_argument_parser_returns_parser(self):
28+
parser = target.build_argument_parser()
29+
args = parser.parse_args(["foo.txt", "bar.plist"])
30+
self.assertEqual(args.filenames, ["foo.txt", "bar.plist"])
31+
32+
def test_txt_valid_recipe_list(self):
33+
with tempfile.TemporaryDirectory() as tmpdir:
34+
txt = os.path.join(tmpdir, "recipes.txt")
35+
with open(txt, "w", encoding="utf-8") as f:
36+
f.write("com.example.recipe1\ncom.example.recipe2\n")
37+
retval, output = self.run_main_with_files([txt])
38+
self.assertEqual(retval, 0)
39+
self.assertEqual(output, "")
40+
41+
def test_txt_invalid_recipe_list(self):
42+
with tempfile.TemporaryDirectory() as tmpdir:
43+
txt = os.path.join(tmpdir, "recipes.txt")
44+
with open(txt, "w", encoding="utf-8") as f:
45+
f.write("# comment only\n\n")
46+
retval, output = self.run_main_with_files([txt])
47+
self.assertEqual(retval, 1)
48+
self.assertIn("invalid recipe list", output)
49+
50+
def test_plist_valid_recipe_list(self):
51+
with tempfile.TemporaryDirectory() as tmpdir:
52+
plist = os.path.join(tmpdir, "recipes.plist")
53+
data = {"recipes": ["com.example.recipe1", "com.example.recipe2"]}
54+
with open(plist, "wb") as f:
55+
plistlib.dump(data, f)
56+
retval, output = self.run_main_with_files([plist])
57+
self.assertEqual(retval, 0)
58+
self.assertEqual(output, "")
59+
60+
def test_plist_invalid_recipe_list(self):
61+
with tempfile.TemporaryDirectory() as tmpdir:
62+
plist = os.path.join(tmpdir, "recipes.plist")
63+
with open(plist, "wb") as f:
64+
f.write(b"not a plist")
65+
retval, output = self.run_main_with_files([plist])
66+
self.assertEqual(retval, 1)
67+
self.assertTrue(
68+
"plist parsing error" in output or "invalid recipe list" in output
69+
)
70+
71+
def test_yaml_valid_recipe_list(self):
72+
with tempfile.TemporaryDirectory() as tmpdir:
73+
yaml_file = os.path.join(tmpdir, "recipes.yaml")
74+
with open(yaml_file, "w", encoding="utf-8") as f:
75+
f.write("- com.example.recipe1\n- com.example.recipe2\n")
76+
retval, output = self.run_main_with_files([yaml_file])
77+
self.assertEqual(retval, 0)
78+
self.assertEqual(output, "")
79+
80+
def test_yaml_invalid_recipe_list(self):
81+
with tempfile.TemporaryDirectory() as tmpdir:
82+
yaml_file = os.path.join(tmpdir, "recipes.yaml")
83+
with open(yaml_file, "w", encoding="utf-8") as f:
84+
f.write("not: a list")
85+
retval, output = self.run_main_with_files([yaml_file])
86+
self.assertEqual(retval, 1)
87+
self.assertIn("invalid recipe list", output)
88+
89+
def test_json_valid_recipe_list(self):
90+
with tempfile.TemporaryDirectory() as tmpdir:
91+
json_file = os.path.join(tmpdir, "recipes.json")
92+
with open(json_file, "w", encoding="utf-8") as f:
93+
f.write('["com.example.recipe1", "com.example.recipe2"]')
94+
retval, output = self.run_main_with_files([json_file])
95+
self.assertEqual(retval, 0)
96+
self.assertEqual(output, "")
97+
98+
def test_json_invalid_recipe_list(self):
99+
with tempfile.TemporaryDirectory() as tmpdir:
100+
json_file = os.path.join(tmpdir, "recipes.json")
101+
with open(json_file, "w", encoding="utf-8") as f:
102+
f.write('{"not": "a list"}')
103+
retval, output = self.run_main_with_files([json_file])
104+
self.assertEqual(retval, 1)
105+
self.assertIn("invalid recipe list", output)
106+
107+
def test_makecatalogs_should_be_last(self):
108+
with tempfile.TemporaryDirectory() as tmpdir:
109+
txt = os.path.join(tmpdir, "recipes.txt")
110+
with open(txt, "w", encoding="utf-8") as f:
111+
f.write("com.example.recipe.munki\nSomeOtherRecipe\nMakeCatalogs\n")
112+
retval, output = self.run_main_with_files([txt])
113+
self.assertEqual(retval, 0)
114+
self.assertEqual(output, "")
115+
116+
txt2 = os.path.join(tmpdir, "recipes2.txt")
117+
with open(txt2, "w", encoding="utf-8") as f:
118+
f.write("com.example.recipe.munki\nMakeCatalogs\nSomeOtherRecipe\n")
119+
retval, output = self.run_main_with_files([txt2])
120+
self.assertEqual(retval, 1)
121+
self.assertIn("MakeCatalogs should be the last item", output)
122+
123+
def test_nonexistent_file(self):
124+
with self.assertRaises(FileNotFoundError):
125+
self.run_main_with_files(["nonexistent/file.txt"])
126+
127+
def test_multiple_files_mixed_valid_and_invalid(self):
128+
with tempfile.TemporaryDirectory() as tmpdir:
129+
# Valid txt
130+
txt = os.path.join(tmpdir, "recipes.txt")
131+
with open(txt, "w", encoding="utf-8") as f:
132+
f.write("com.example.recipe1\ncom.example.recipe2\n")
133+
# Invalid yaml (not a list)
134+
yaml_file = os.path.join(tmpdir, "recipes.yaml")
135+
with open(yaml_file, "w", encoding="utf-8") as f:
136+
f.write("not: a list")
137+
# Valid json
138+
json_file = os.path.join(tmpdir, "recipes.json")
139+
with open(json_file, "w", encoding="utf-8") as f:
140+
f.write('["com.example.recipe1", "com.example.recipe2"]')
141+
retval, output = self.run_main_with_files([txt, yaml_file, json_file])
142+
self.assertEqual(retval, 1)
143+
self.assertIn("invalid recipe list", output)
144+
self.assertNotIn("plist parsing error", output)
145+
146+
def test_empty_txt_file(self):
147+
with tempfile.TemporaryDirectory() as tmpdir:
148+
txt = os.path.join(tmpdir, "empty.txt")
149+
with open(txt, "w", encoding="utf-8") as f:
150+
f.write("")
151+
retval, output = self.run_main_with_files([txt])
152+
self.assertEqual(retval, 1)
153+
self.assertIn("invalid recipe list", output)
154+
155+
def test_txt_file_with_comments_and_blank_lines(self):
156+
with tempfile.TemporaryDirectory() as tmpdir:
157+
txt = os.path.join(tmpdir, "comments.txt")
158+
with open(txt, "w", encoding="utf-8") as f:
159+
f.write("# comment\n\n# another\ncom.example.recipe\n\n")
160+
retval, output = self.run_main_with_files([txt])
161+
self.assertEqual(retval, 0)
162+
self.assertEqual(output, "")
163+
164+
def test_yaml_parsing_error(self):
165+
with tempfile.TemporaryDirectory() as tmpdir:
166+
yaml_file = os.path.join(tmpdir, "bad.yaml")
167+
with open(yaml_file, "w", encoding="utf-8") as f:
168+
f.write(":\n-")
169+
retval, output = self.run_main_with_files([yaml_file])
170+
self.assertEqual(retval, 1)
171+
self.assertIn("yaml parsing error", output)
172+
173+
def test_json_parsing_error(self):
174+
with tempfile.TemporaryDirectory() as tmpdir:
175+
json_file = os.path.join(tmpdir, "bad.json")
176+
with open(json_file, "w", encoding="utf-8") as f:
177+
f.write("{not a valid json")
178+
retval, output = self.run_main_with_files([json_file])
179+
self.assertEqual(retval, 1)
180+
self.assertIn("json parsing error", output)
181+
182+
def test_plist_missing_recipes_key(self):
183+
with tempfile.TemporaryDirectory() as tmpdir:
184+
plist = os.path.join(tmpdir, "missing_recipes.plist")
185+
data = {"notrecipes": ["foo", "bar"]}
186+
with open(plist, "wb") as f:
187+
plistlib.dump(data, f)
188+
retval, output = self.run_main_with_files([plist])
189+
self.assertEqual(retval, 1)
190+
self.assertIn("invalid recipe list", output)
191+
192+
def test_makecatalogs_missing_when_munki_present(self):
193+
with tempfile.TemporaryDirectory() as tmpdir:
194+
txt = os.path.join(tmpdir, "recipes.txt")
195+
with open(txt, "w", encoding="utf-8") as f:
196+
f.write("com.example.recipe.munki\nSomeOtherRecipe\n")
197+
retval, output = self.run_main_with_files([txt])
198+
self.assertEqual(retval, 1)
199+
self.assertIn("MakeCatalogs should be the last item", output)
200+
201+
202+
if __name__ == "__main__":
203+
unittest.main()

0 commit comments

Comments
 (0)