Skip to content

Commit 7933a0f

Browse files
committed
Add tests for src/flavors module
1 parent 1bac212 commit 7933a0f

File tree

4 files changed

+421
-0
lines changed

4 files changed

+421
-0
lines changed

tests/flavors/__init__.py

Whitespace-only changes.

tests/flavors/test_init.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import types
2+
import importlib
3+
4+
from gardenlinux import flavors
5+
6+
7+
def test_parser_exposed_at_top_level():
8+
"""Parser should be importable directly from the package."""
9+
from gardenlinux.flavors import parser
10+
11+
assert flavors.Parser is parser.Parser
12+
13+
14+
def test___all___is_correct():
15+
"""__all__ should only contain Parser."""
16+
assert flavors.__all__ == ["Parser"]
17+
18+
19+
def test_star_import(monkeypatch):
20+
"""from flavors import * should bring Parser into locals()."""
21+
# Arrange
22+
namespace = {}
23+
24+
# Act
25+
module = importlib.import_module("gardenlinux.flavors")
26+
for name in getattr(module, "__all__", []):
27+
namespace[name] = getattr(module, name)
28+
29+
# Assert
30+
assert "Parser" in namespace
31+
assert namespace["Parser"] is flavors.Parser
32+
33+
34+
def test_import_module():
35+
"""Importing the package should not raise exceptions."""
36+
importlib.reload(flavors) # Should succeed without errors

tests/flavors/test_main.py

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
import json
2+
import sys
3+
import pytest
4+
5+
import gardenlinux.flavors.__main__ as fm
6+
7+
8+
def test_generate_markdown_table():
9+
# Arrange
10+
combos = [("amd64", "linux-amd64")]
11+
12+
# Act
13+
table = fm.generate_markdown_table(combos, no_arch=False)
14+
15+
# Assert
16+
assert table.startswith("| Platform | Architecture | Flavor")
17+
assert "`linux-amd64`" in table
18+
assert "| linux"
19+
20+
21+
def test_parse_args(monkeypatch):
22+
"""simulate CLI invocation and make sure parse_args reads them correctly"""
23+
# Arrange
24+
argv = [
25+
"prog",
26+
"--no-arch",
27+
"--include-only",
28+
"a*",
29+
"--exclude",
30+
"b*",
31+
"--build",
32+
"--publish",
33+
"--test",
34+
"--test-platform",
35+
"--category",
36+
"cat1",
37+
"--exclude-category",
38+
"cat2",
39+
"--json-by-arch",
40+
]
41+
monkeypatch.setattr(sys, "argv", argv)
42+
43+
# Act
44+
args = fm.parse_args()
45+
46+
# Assert
47+
assert args.no_arch is True
48+
assert args.include_only == ["a*"]
49+
assert args.exclude == ["b*"]
50+
assert args.build is True
51+
assert args.publish is True
52+
assert args.test is True
53+
assert args.test_platform is True
54+
assert args.category == ["cat1"]
55+
assert args.exclude_category == ["cat2"]
56+
assert args.json_by_arch is True
57+
58+
59+
def _make_parser_class(filter_result, group_result=None, remove_result=None):
60+
"""
61+
Factory to create a fake Parser class
62+
Instances ignore the favors_data passed to __init__.
63+
"""
64+
65+
class DummyParser:
66+
def __init__(self, flavors_data):
67+
self._data = flavors_data
68+
69+
def filter(self, **kwargs):
70+
# return the prepared combinations list
71+
return filter_result
72+
73+
@staticmethod
74+
def group_by_arch(combinations):
75+
# Return a prepared mapping or derive a simple mapping if None
76+
if group_result is not None:
77+
return group_result
78+
# naive default behaviour: group combinations by arch
79+
d = {}
80+
for arch, comb in combinations:
81+
d.setdefault(arch, []).append(comb)
82+
return d
83+
84+
@staticmethod
85+
def remove_arch(combinations):
86+
if remove_result is not None:
87+
return remove_result
88+
# naive default: remote '-{arch}' suffix if present
89+
out = []
90+
for arch, comb in combinations:
91+
suffix = f"-{arch}"
92+
if comb.endswith(suffix):
93+
out.append(comb[: -len(suffix)])
94+
else:
95+
out.append(comb)
96+
return out
97+
98+
return DummyParser
99+
100+
101+
def test_main_exits_when_flavors_missing(tmp_path, monkeypatch):
102+
# Arrange
103+
# make Git().root point to a tmp dir that does NOT contain flavors.yaml
104+
class DummyGit:
105+
def __init__(self):
106+
self.root = str(tmp_path)
107+
108+
monkeypatch.setattr(fm, "Git", DummyGit)
109+
110+
# ensure no flavors.yaml
111+
monkeypatch.setattr(sys, "argv", ["prog"])
112+
113+
# Act / Assert
114+
with pytest.raises(SystemExit) as excinfo:
115+
fm.main()
116+
assert "does not exist" in str(excinfo.value)
117+
118+
119+
def test_main_json_by_arch_prints_json(tmp_path, monkeypatch, capsys):
120+
# Arrange
121+
# prepare flavors.yaml at tmp path
122+
flavors_file = tmp_path / "flavors.yaml"
123+
flavors_file.write_text("dummy: content")
124+
125+
class DummyGit:
126+
def __init__(self):
127+
self.root = str(tmp_path)
128+
129+
# define combinations and expected grouped mapping
130+
combinations = [("x86", "linux-x86"), ("arm", "android-arm")]
131+
grouped = {"x86": ["linux-x86"], "arm": ["android-arm"]}
132+
133+
DummyParser = _make_parser_class(filter_result=combinations, group_result=grouped)
134+
monkeypatch.setattr(fm, "Git", DummyGit)
135+
monkeypatch.setattr(fm, "Parser", DummyParser)
136+
monkeypatch.setattr(sys, "argv", ["prog", "--json-by-arch"])
137+
138+
# Act
139+
fm.main()
140+
out = capsys.readouterr().out
141+
142+
# Assert
143+
parsed = json.loads(out)
144+
assert parsed == grouped
145+
146+
147+
def test_main_json_by_arch_with_no_arch_strips_arch_suffix(
148+
tmp_path, monkeypatch, capsys
149+
):
150+
# Arrange
151+
flavors_file = tmp_path / "flavors.yaml"
152+
flavors_file.write_text("dummy: content")
153+
154+
class DummyGit:
155+
def __init__(self):
156+
self.root = str(tmp_path)
157+
158+
combinations = [("x86", "linux-x86"), ("arm", "android-arm")]
159+
# group_by_arch returns items that include architecture suffixes
160+
grouped = {"x86": ["linux-x86"], "arm": ["android-arm"]}
161+
DummyParser = _make_parser_class(filter_result=combinations, group_result=grouped)
162+
163+
monkeypatch.setattr(fm, "Git", DummyGit)
164+
monkeypatch.setattr(fm, "Parser", DummyParser)
165+
monkeypatch.setattr(sys, "argv", ["prog", "--json-by-arch", "--no-arch"])
166+
167+
# Act
168+
fm.main()
169+
out = capsys.readouterr().out
170+
171+
# Assert
172+
parsed = json.loads(out)
173+
# with --no-arch, main removes '-<arch>' from each flavor string
174+
assert parsed == {"x86": ["linux"], "arm": ["android"]}
175+
176+
177+
def test_main_markdown_table_branch(tmp_path, monkeypatch, capsys):
178+
# Arrange
179+
flavors_file = tmp_path / "flavors.yaml"
180+
flavors_file.write_text("dummy: content")
181+
182+
class DummyGit:
183+
def __init__(self):
184+
self.root = str(tmp_path)
185+
186+
combinations = [("x86_64", "linux-x86_64"), ("armv7", "android-armv7")]
187+
DummyParser = _make_parser_class(filter_result=combinations)
188+
189+
monkeypatch.setattr(fm, "Git", DummyGit)
190+
monkeypatch.setattr(fm, "Parser", DummyParser)
191+
monkeypatch.setattr(sys, "argv", ["prog", "--markdown-table-by-platform"])
192+
193+
# Act
194+
fm.main()
195+
out = capsys.readouterr().out
196+
197+
# Assert
198+
assert "`linux-x86_64`" in out
199+
assert "`android-armv7`" in out
200+
assert "| Platform" in out
201+
202+
203+
def test_main_default_prints_flavors_list(tmp_path, monkeypatch, capsys):
204+
# Arrange
205+
flavors_file = tmp_path / "flavors.yaml"
206+
flavors_file.write_text("dummy: content")
207+
208+
class DummyGit:
209+
def __init__(self):
210+
self.root = str(tmp_path)
211+
212+
# filter returns tuples; main's default branch prints comb[1] values, sorted unique
213+
combinations = [("x86", "linux-x86"), ("arm", "android-arm")]
214+
DummyParser = _make_parser_class(filter_result=combinations)
215+
216+
monkeypatch.setattr(fm, "Git", DummyGit)
217+
monkeypatch.setattr(fm, "Parser", DummyParser)
218+
monkeypatch.setattr(sys, "argv", ["prog"])
219+
220+
# Act
221+
fm.main()
222+
out = capsys.readouterr().out
223+
lines = out.strip().splitlines()
224+
225+
# Assert
226+
assert sorted(lines) == sorted(["linux-x86", "android-arm"])

0 commit comments

Comments
 (0)