microsoft/hve-core

Public

mirrored from https://github.com/microsoft/hve-coreAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
docs/transparency-note

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

.github/skills/experimental/powerpoint/tests/fuzz_harness.py

287lines · modecode

1# Copyright (c) Microsoft Corporation.
2# SPDX-License-Identifier: MIT
3"""Polyglot fuzz harness for PowerPoint skill priority modules.
4
5Runs as a pytest test when Atheris is not installed (CI default).
6Runs as an Atheris coverage-guided fuzz target when executed directly.
7"""
8
9from __future__ import annotations
10
11import sys
12from contextlib import suppress
13
14try:
15 import atheris
16
17 FUZZING = True
18except ImportError:
19 FUZZING = False
20
21from extract_content import _has_formatting_variation
22from pptx_colors import hex_brightness, resolve_color
23from validate_deck import max_severity
24
25# ---------------------------------------------------------------------------
26# Fuzz targets — pure functions exercised by both modes
27# ---------------------------------------------------------------------------
28
29
30def fuzz_resolve_color(data):
31 """Fuzz resolve_color with str and dict inputs."""
32 fdp = atheris.FuzzedDataProvider(data)
33 hex_str = "#" + fdp.ConsumeUnicodeNoSurrogates(6)
34 with suppress(ValueError, IndexError):
35 resolve_color(hex_str)
36 theme_ref = "@" + fdp.ConsumeUnicodeNoSurrogates(20)
37 with suppress(ValueError, IndexError):
38 resolve_color(theme_ref)
39 theme_dict = {
40 "theme": fdp.ConsumeUnicodeNoSurrogates(15),
41 "brightness": fdp.ConsumeFloatInRange(-1.0, 1.0),
42 }
43 with suppress(ValueError, IndexError):
44 resolve_color(theme_dict)
45 nested_dict = {"color": "#" + fdp.ConsumeUnicodeNoSurrogates(6)}
46 with suppress(ValueError, IndexError):
47 resolve_color(nested_dict)
48
49
50def fuzz_hex_brightness(data):
51 """Fuzz hex_brightness with arbitrary strings."""
52 fdp = atheris.FuzzedDataProvider(data)
53 hex_str = fdp.ConsumeUnicodeNoSurrogates(10)
54 with suppress(ValueError, IndexError):
55 hex_brightness(hex_str)
56
57
58def fuzz_max_severity(data):
59 """Fuzz max_severity with structured dict inputs."""
60 fdp = atheris.FuzzedDataProvider(data)
61 severities = ["error", "warning", "info", fdp.ConsumeUnicodeNoSurrogates(8)]
62 num_slides = fdp.ConsumeIntInRange(0, 5)
63 slides = []
64 for _ in range(num_slides):
65 num_issues = fdp.ConsumeIntInRange(0, 4)
66 issues = [
67 {"severity": severities[fdp.ConsumeIntInRange(0, len(severities) - 1)]}
68 for _ in range(num_issues)
69 ]
70 slides.append({"issues": issues})
71 num_deck_issues = fdp.ConsumeIntInRange(0, 3)
72 deck_issues = [
73 {"severity": severities[fdp.ConsumeIntInRange(0, len(severities) - 1)]}
74 for _ in range(num_deck_issues)
75 ]
76 results = {}
77 if fdp.ConsumeBool():
78 results["slides"] = slides
79 if fdp.ConsumeBool():
80 results["deck_issues"] = deck_issues
81 with suppress(KeyError):
82 max_severity(results)
83
84
85def fuzz_has_formatting_variation(data):
86 """Fuzz _has_formatting_variation with lists of run dicts."""
87 fdp = atheris.FuzzedDataProvider(data)
88 num_runs = fdp.ConsumeIntInRange(0, 6)
89 runs = []
90 for _ in range(num_runs):
91 run = {}
92 if fdp.ConsumeBool():
93 run["font"] = fdp.ConsumeUnicodeNoSurrogates(10)
94 if fdp.ConsumeBool():
95 run["size"] = fdp.ConsumeIntInRange(6, 72)
96 if fdp.ConsumeBool():
97 run["color"] = "#" + fdp.ConsumeUnicodeNoSurrogates(6)
98 if fdp.ConsumeBool():
99 run["bold"] = fdp.ConsumeBool()
100 if fdp.ConsumeBool():
101 run["italic"] = fdp.ConsumeBool()
102 if fdp.ConsumeBool():
103 run["underline"] = fdp.ConsumeBool()
104 runs.append(run)
105 _has_formatting_variation(runs)
106
107
108FUZZ_TARGETS = [
109 fuzz_resolve_color,
110 fuzz_hex_brightness,
111 fuzz_max_severity,
112 fuzz_has_formatting_variation,
113]
114
115
116def fuzz_dispatch(data):
117 """Route Atheris input to one of the registered fuzz targets."""
118 if len(data) < 2:
119 return
120 idx = data[0] % len(FUZZ_TARGETS)
121 FUZZ_TARGETS[idx](data[1:])
122
123
124# ---------------------------------------------------------------------------
125# pytest mode — property-based tests for the same targets
126# ---------------------------------------------------------------------------
127
128import pytest # noqa: E402
129
130
131class TestFuzzResolveColor:
132 """Property tests for resolve_color edge cases."""
133
134 @pytest.mark.parametrize(
135 "value",
136 [
137 "#000000",
138 "#FFFFFF",
139 "#abcdef",
140 "@accent1",
141 "@nonexistent_theme",
142 "",
143 {"theme": "accent1", "brightness": 0.5},
144 {"theme": "accent1"},
145 {"color": "#FF0000"},
146 {"color": "#FF0000", "theme": ""},
147 ],
148 )
149 def test_resolve_color_returns_dict(self, value):
150 result = resolve_color(value)
151 assert isinstance(result, dict)
152
153 def test_resolve_color_depth_limit(self):
154 deep = {"color": {"color": {"color": "#000000"}}}
155 with pytest.raises(ValueError, match="depth"):
156 resolve_color(deep, max_depth=2)
157
158 def test_resolve_color_short_hex(self):
159 result = resolve_color("#AB")
160 assert "rgb" in result
161 assert str(result["rgb"]) == "000000"
162
163
164class TestFuzzHexBrightness:
165 """Property tests for hex_brightness."""
166
167 @pytest.mark.parametrize(
168 "hex_color,expected",
169 [
170 ("#000000", 0),
171 ("#FFFFFF", 255),
172 ("#FF0000", 76),
173 ],
174 )
175 def test_known_values(self, hex_color, expected):
176 assert hex_brightness(hex_color) == expected
177
178 def test_short_hex_returns_zero(self):
179 assert hex_brightness("#AB") == 0
180
181
182class TestFuzzMaxSeverity:
183 """Property tests for max_severity."""
184
185 def test_empty_slides(self):
186 assert max_severity({"slides": [], "deck_issues": []}) == "none"
187
188 def test_error_dominates(self):
189 results = {
190 "slides": [{"issues": [{"severity": "info"}, {"severity": "error"}]}],
191 "deck_issues": [{"severity": "warning"}],
192 }
193 assert max_severity(results) == "error"
194
195 def test_warning_over_info(self):
196 results = {
197 "slides": [{"issues": [{"severity": "info"}]}],
198 "deck_issues": [{"severity": "warning"}],
199 }
200 assert max_severity(results) == "warning"
201
202 def test_missing_slides_key(self):
203 with pytest.raises(KeyError):
204 max_severity({"deck_issues": []})
205
206 def test_missing_deck_issues_key(self):
207 assert max_severity({"slides": []}) == "none"
208
209
210# ---------------------------------------------------------------------------
211# Dict-style run helpers — exercise the dict branch of _has_formatting_variation
212# ---------------------------------------------------------------------------
213
214
215class _Color:
216 """Minimal stand-in for python-pptx RGBColor used by _make_dict_run."""
217
218 def __init__(self, rgb):
219 self.rgb = rgb
220
221 def __eq__(self, other):
222 return isinstance(other, _Color) and self.rgb == other.rgb
223
224 def __hash__(self):
225 return hash(self.rgb)
226
227
228def _make_dict_run(
229 font="Arial", bold=False, italic=False, underline=False, size=None, color_rgb=None
230):
231 """Create a plain dict matching the dict-style branch in get_props."""
232 return {
233 "font": font,
234 "bold": bold,
235 "italic": italic,
236 "underline": underline,
237 "size": size,
238 "color": _Color(color_rgb),
239 }
240
241
242class TestFuzzHasFormattingVariation:
243 """Tests for _has_formatting_variation covering all 6 formatting properties."""
244
245 def test_single_run(self):
246 assert _has_formatting_variation([_make_dict_run()]) is False
247
248 def test_identical_runs(self):
249 runs = [_make_dict_run(), _make_dict_run()]
250 assert _has_formatting_variation(runs) is False
251
252 def test_different_fonts(self):
253 runs = [_make_dict_run(font="Arial"), _make_dict_run(font="Calibri")]
254 assert _has_formatting_variation(runs) is True
255
256 def test_bold_variation(self):
257 runs = [_make_dict_run(bold=True), _make_dict_run(bold=False)]
258 assert _has_formatting_variation(runs) is True
259
260 def test_italic_variation(self):
261 runs = [_make_dict_run(italic=True), _make_dict_run(italic=False)]
262 assert _has_formatting_variation(runs) is True
263
264 def test_underline_variation(self):
265 runs = [_make_dict_run(underline=True), _make_dict_run(underline=False)]
266 assert _has_formatting_variation(runs) is True
267
268 def test_size_variation(self):
269 runs = [_make_dict_run(size=100_000), _make_dict_run(size=200_000)]
270 assert _has_formatting_variation(runs) is True
271
272 def test_color_rgb_variation(self):
273 runs = [_make_dict_run(color_rgb=0xFF0000), _make_dict_run(color_rgb=0x00FF00)]
274 assert _has_formatting_variation(runs) is True
275
276 def test_empty_list(self):
277 assert _has_formatting_variation([]) is False
278
279
280# ---------------------------------------------------------------------------
281# Atheris entry point — only runs when executed directly with Atheris installed
282# ---------------------------------------------------------------------------
283
284if __name__ == "__main__" and FUZZING:
285 atheris.instrument_all()
286 atheris.Setup(sys.argv, fuzz_dispatch)
287 atheris.Fuzz()
288