prefpicker 2.17.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- prefpicker/__init__.py +9 -0
- prefpicker/__main__.py +10 -0
- prefpicker/main.py +113 -0
- prefpicker/prefpicker.py +265 -0
- prefpicker/py.typed +0 -0
- prefpicker/templates/browser-fuzzing.yml +1165 -0
- prefpicker/templates/schema.json +56 -0
- prefpicker/test_main.py +95 -0
- prefpicker/test_prefpicker.py +281 -0
- prefpicker/test_templates.py +44 -0
- prefpicker-2.17.0.dist-info/METADATA +121 -0
- prefpicker-2.17.0.dist-info/RECORD +16 -0
- prefpicker-2.17.0.dist-info/WHEEL +5 -0
- prefpicker-2.17.0.dist-info/entry_points.txt +2 -0
- prefpicker-2.17.0.dist-info/licenses/LICENSE +373 -0
- prefpicker-2.17.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"description": "prefpicker template schema",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"properties": {
|
|
7
|
+
"pref": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"additionalProperties": false,
|
|
10
|
+
"patternProperties": {
|
|
11
|
+
"^.+$": {
|
|
12
|
+
"additionalProperties": false,
|
|
13
|
+
"type": "object",
|
|
14
|
+
"properties": {
|
|
15
|
+
"variants": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"additionalProperties": false,
|
|
18
|
+
"patternProperties": {
|
|
19
|
+
"^.+$": {
|
|
20
|
+
"type": "array",
|
|
21
|
+
"minItems": 1,
|
|
22
|
+
"items": {
|
|
23
|
+
"type": ["boolean", "integer", "null", "string"]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"required": [
|
|
28
|
+
"default"
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"review_on_close": {
|
|
32
|
+
"type": "array",
|
|
33
|
+
"minItems": 1,
|
|
34
|
+
"items": {
|
|
35
|
+
"type": "integer"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"required": [
|
|
40
|
+
"variants"
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"variant": {
|
|
46
|
+
"type": "array",
|
|
47
|
+
"items": {
|
|
48
|
+
"type": "string"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"required": [
|
|
53
|
+
"pref",
|
|
54
|
+
"variant"
|
|
55
|
+
]
|
|
56
|
+
}
|
prefpicker/test_main.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
3
|
+
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
4
|
+
"""main.py tests"""
|
|
5
|
+
|
|
6
|
+
from pytest import raises
|
|
7
|
+
|
|
8
|
+
from .main import main
|
|
9
|
+
from .prefpicker import PrefPicker
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_main_01(tmp_path):
|
|
13
|
+
"""test main()"""
|
|
14
|
+
prefs_js = tmp_path / "prefs.js"
|
|
15
|
+
yml = tmp_path / "test.yml"
|
|
16
|
+
yml.write_text(
|
|
17
|
+
"""
|
|
18
|
+
variant: []
|
|
19
|
+
pref:
|
|
20
|
+
test.a:
|
|
21
|
+
variants:
|
|
22
|
+
default: [1]"""
|
|
23
|
+
)
|
|
24
|
+
assert main([str(yml), str(prefs_js), "--variant", "default"]) == 0
|
|
25
|
+
assert prefs_js.is_file()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_main_02(capsys):
|
|
29
|
+
"""test main() with missing input"""
|
|
30
|
+
with raises(SystemExit):
|
|
31
|
+
main(["missing.yml", "prefs.js"])
|
|
32
|
+
assert "Cannot find input file 'missing.yml'" in capsys.readouterr()[1]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_main_03(tmp_path):
|
|
36
|
+
"""test main() with built-in input"""
|
|
37
|
+
prefs_js = tmp_path / "prefs.js"
|
|
38
|
+
templates = tuple(x.name for x in PrefPicker.templates())
|
|
39
|
+
assert templates
|
|
40
|
+
assert main([templates[0], str(prefs_js)]) == 0
|
|
41
|
+
assert prefs_js.is_file()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_main_04(tmp_path):
|
|
45
|
+
"""test main() with invalid variant"""
|
|
46
|
+
prefs_js = tmp_path / "prefs.js"
|
|
47
|
+
yml = tmp_path / "test.yml"
|
|
48
|
+
yml.write_text(
|
|
49
|
+
"""
|
|
50
|
+
variant: []
|
|
51
|
+
pref:
|
|
52
|
+
test.a:
|
|
53
|
+
variants:
|
|
54
|
+
default: [1]"""
|
|
55
|
+
)
|
|
56
|
+
assert main([str(yml), str(prefs_js), "--variant", "x"]) == 1
|
|
57
|
+
assert not prefs_js.is_file()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_main_05(tmp_path):
|
|
61
|
+
"""test main() with check results"""
|
|
62
|
+
prefs_js = tmp_path / "prefs.js"
|
|
63
|
+
yml = tmp_path / "test.yml"
|
|
64
|
+
yml.write_text(
|
|
65
|
+
"""
|
|
66
|
+
variant: [extra]
|
|
67
|
+
pref:
|
|
68
|
+
test.a:
|
|
69
|
+
variants:
|
|
70
|
+
default: [1, 1]
|
|
71
|
+
extra: [1, 1]"""
|
|
72
|
+
)
|
|
73
|
+
assert main([str(yml), str(prefs_js), "--check", "--variant", "extra"]) == 0
|
|
74
|
+
assert prefs_js.is_file()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_main_06(capsys, tmp_path):
|
|
78
|
+
"""test main() with invalid output path"""
|
|
79
|
+
yml = tmp_path / "test.yml"
|
|
80
|
+
yml.touch()
|
|
81
|
+
# output is a directory
|
|
82
|
+
with raises(SystemExit):
|
|
83
|
+
main([str(yml), str(tmp_path)])
|
|
84
|
+
assert "is a directory." in capsys.readouterr()[1]
|
|
85
|
+
# output to missing directory
|
|
86
|
+
with raises(SystemExit):
|
|
87
|
+
main([str(yml), str(tmp_path / "missing" / "prefs.js")])
|
|
88
|
+
assert "directory does not exist." in capsys.readouterr()[1]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_main_07(tmp_path):
|
|
92
|
+
"""test main() with invalid input"""
|
|
93
|
+
yml = tmp_path / "test.yml"
|
|
94
|
+
yml.write_text("{test{")
|
|
95
|
+
assert main([str(yml), str(tmp_path / "prefs.js")]) == 1
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
3
|
+
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
4
|
+
"""prefpicker.py tests"""
|
|
5
|
+
|
|
6
|
+
from pytest import mark, raises
|
|
7
|
+
|
|
8
|
+
from .prefpicker import PrefPicker, SourceDataError
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_prefpicker_01(tmp_path):
|
|
12
|
+
"""test simple PrefPicker"""
|
|
13
|
+
yml = tmp_path / "test.yml"
|
|
14
|
+
yml.write_text(
|
|
15
|
+
"""
|
|
16
|
+
variant: []
|
|
17
|
+
pref:
|
|
18
|
+
test.a:
|
|
19
|
+
variants:
|
|
20
|
+
default: [1]"""
|
|
21
|
+
)
|
|
22
|
+
picker = PrefPicker.load_template(yml)
|
|
23
|
+
assert len(picker.variants) == 1
|
|
24
|
+
assert "default" in picker.variants
|
|
25
|
+
assert len(picker.prefs) == 1
|
|
26
|
+
assert "test.a" in picker.prefs
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@mark.parametrize(
|
|
30
|
+
"data, msg",
|
|
31
|
+
[
|
|
32
|
+
# invalid template
|
|
33
|
+
([], "invalid template"),
|
|
34
|
+
# variant list missing
|
|
35
|
+
({"pref": {"a.b": {"variants": {"default": [1]}}}}, "variant list is missing"),
|
|
36
|
+
# variant definition is invalid type
|
|
37
|
+
({"variant": [{"bad": 1}]}, "variant definition must be a string"),
|
|
38
|
+
# variant is invalid type
|
|
39
|
+
({"variant": ""}, "variant is not a list"),
|
|
40
|
+
# pref dict missing
|
|
41
|
+
({"variant": []}, "pref group is missing"),
|
|
42
|
+
# pref is invalid type
|
|
43
|
+
({"pref": [], "variant": []}, "pref is not a dict"),
|
|
44
|
+
# pref entry is invalid
|
|
45
|
+
(
|
|
46
|
+
{"pref": {"a.b": None}, "variant": []},
|
|
47
|
+
r"'a\.b' entry must contain a dict",
|
|
48
|
+
),
|
|
49
|
+
# pref variants is invalid
|
|
50
|
+
(
|
|
51
|
+
{"pref": {"a.b": {"variants": None}}, "variant": []},
|
|
52
|
+
r"'a\.b' is missing 'variants' dict",
|
|
53
|
+
),
|
|
54
|
+
# pref missing default variant
|
|
55
|
+
(
|
|
56
|
+
{"variant": [], "pref": {"test.a": {"variants": {}}}},
|
|
57
|
+
r"'test\.a' is missing 'default' variant",
|
|
58
|
+
),
|
|
59
|
+
# template with undefined variant
|
|
60
|
+
(
|
|
61
|
+
{"variant": [], "pref": {"a.b": {"variants": {"default": [1], "x": [2]}}}},
|
|
62
|
+
r"'x' in 'a\.b' is not a defined variant",
|
|
63
|
+
),
|
|
64
|
+
# template with unused variant
|
|
65
|
+
(
|
|
66
|
+
{"variant": ["unused"], "pref": {"a.b": {"variants": {"default": [1]}}}},
|
|
67
|
+
"Unused variants 'unused'",
|
|
68
|
+
),
|
|
69
|
+
# pref with empty variant list
|
|
70
|
+
(
|
|
71
|
+
{"variant": [], "pref": {"a.b": {"variants": {"default": []}}}},
|
|
72
|
+
r"'default' in 'a\.b' is empty",
|
|
73
|
+
),
|
|
74
|
+
# pref with invalid variant type
|
|
75
|
+
(
|
|
76
|
+
{"variant": [], "pref": {"a.b": {"variants": {"default": "x"}}}},
|
|
77
|
+
r"variant 'default' in 'a\.b' is not a list",
|
|
78
|
+
),
|
|
79
|
+
# pref variant with invalid type
|
|
80
|
+
(
|
|
81
|
+
{"variant": [], "pref": {"a.b": {"variants": {"default": [1.11]}}}},
|
|
82
|
+
r"unsupported datatype 'float' \(a\.b\)",
|
|
83
|
+
),
|
|
84
|
+
],
|
|
85
|
+
)
|
|
86
|
+
def test_prefpicker_02(data, msg):
|
|
87
|
+
"""test PrefPicker.verify_data()"""
|
|
88
|
+
with raises(SourceDataError, match=msg):
|
|
89
|
+
PrefPicker.verify_data(data)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_prefpicker_03():
|
|
93
|
+
"""test PrefPicker.check_overwrites()"""
|
|
94
|
+
raw_data = {
|
|
95
|
+
"variant": ["fail", "safe"],
|
|
96
|
+
"pref": {
|
|
97
|
+
"test.a": {"variants": {"default": [1], "fail": [1, 2], "safe": [3]}},
|
|
98
|
+
"test.b": {"variants": {"default": [9], "safe": [None]}},
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
# use verify_data just to sanity check test data
|
|
102
|
+
PrefPicker.verify_data(raw_data)
|
|
103
|
+
ppick = PrefPicker()
|
|
104
|
+
ppick.variants = set(raw_data["variant"] + ["default"])
|
|
105
|
+
ppick.prefs = raw_data["pref"]
|
|
106
|
+
results = tuple(ppick.check_overwrites())
|
|
107
|
+
assert results
|
|
108
|
+
assert results[0][0] == "test.a"
|
|
109
|
+
assert results[0][1] == "fail"
|
|
110
|
+
assert results[0][2] == 1
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_prefpicker_04():
|
|
114
|
+
"""test PrefPicker.check_duplicates()"""
|
|
115
|
+
raw_data = {
|
|
116
|
+
"variant": ["fail", "safe"],
|
|
117
|
+
"pref": {
|
|
118
|
+
"test.a": {"variants": {"default": [1], "fail": [1, 2, 3, 1], "safe": [3]}},
|
|
119
|
+
"test.b": {"variants": {"default": [9], "safe": [None]}},
|
|
120
|
+
},
|
|
121
|
+
}
|
|
122
|
+
# use verify_data just to sanity check test data
|
|
123
|
+
PrefPicker.verify_data(raw_data)
|
|
124
|
+
ppick = PrefPicker()
|
|
125
|
+
ppick.variants = set(raw_data["variant"] + ["default"])
|
|
126
|
+
ppick.prefs = raw_data["pref"]
|
|
127
|
+
results = tuple(ppick.check_duplicates())
|
|
128
|
+
assert results
|
|
129
|
+
assert results[0][0] == "test.a"
|
|
130
|
+
assert results[0][1] == "fail"
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def test_prefpicker_05():
|
|
134
|
+
"""test PrefPicker.check_combinations()"""
|
|
135
|
+
raw_data = {
|
|
136
|
+
"variant": ["v1", "v2"],
|
|
137
|
+
"pref": {
|
|
138
|
+
"test.a": {"variants": {"default": [1], "v1": [1, 2, 3, 4], "v2": [3]}},
|
|
139
|
+
"test.b": {"variants": {"default": [2], "v1": [1, 2], "v2": [3]}},
|
|
140
|
+
"test.c": {"variants": {"default": [1, 3], "v2": [None]}},
|
|
141
|
+
},
|
|
142
|
+
}
|
|
143
|
+
# use verify_data just to sanity check test data
|
|
144
|
+
PrefPicker.verify_data(raw_data)
|
|
145
|
+
ppick = PrefPicker()
|
|
146
|
+
ppick.variants = set(raw_data["variant"] + ["default"])
|
|
147
|
+
ppick.prefs = raw_data["pref"]
|
|
148
|
+
results = tuple(ppick.check_combinations())
|
|
149
|
+
assert len(results) == 2
|
|
150
|
+
assert results[0][0] == "default"
|
|
151
|
+
assert results[0][1] == 2
|
|
152
|
+
assert results[1][0] == "v1"
|
|
153
|
+
assert results[1][1] == 16
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_prefpicker_06(tmp_path):
|
|
157
|
+
"""test simple PrefPicker.create_prefsjs()"""
|
|
158
|
+
ppick = PrefPicker()
|
|
159
|
+
prefs = tmp_path / "prefs.js"
|
|
160
|
+
ppick.create_prefsjs(prefs)
|
|
161
|
+
assert prefs.is_file()
|
|
162
|
+
# check only comments were written to the document
|
|
163
|
+
with prefs.open("r") as in_fp:
|
|
164
|
+
for line in in_fp:
|
|
165
|
+
assert line.startswith("//")
|
|
166
|
+
assert in_fp.tell() > 0
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def test_prefpicker_07(tmp_path):
|
|
170
|
+
"""test PrefPicker.create_prefsjs() with variants"""
|
|
171
|
+
raw_data = {
|
|
172
|
+
"variant": ["test", "skip"],
|
|
173
|
+
"pref": {
|
|
174
|
+
"test.a": {"variants": {"default": [0], "test": [1], "skip": [2]}},
|
|
175
|
+
"test.b": {"variants": {"default": [True]}},
|
|
176
|
+
},
|
|
177
|
+
}
|
|
178
|
+
PrefPicker.verify_data(raw_data)
|
|
179
|
+
ppick = PrefPicker()
|
|
180
|
+
ppick.variants = set(raw_data["variant"] + ["default"])
|
|
181
|
+
ppick.prefs = raw_data["pref"]
|
|
182
|
+
prefs = tmp_path / "prefs.js"
|
|
183
|
+
# test with 'default' variant
|
|
184
|
+
ppick.create_prefsjs(prefs)
|
|
185
|
+
assert prefs.is_file()
|
|
186
|
+
prefs_data = prefs.read_text()
|
|
187
|
+
assert "defined by variant 'default'" not in prefs_data
|
|
188
|
+
assert 'user_pref("test.a", 0);\n' in prefs_data
|
|
189
|
+
assert 'user_pref("test.b", true);\n' in prefs_data
|
|
190
|
+
# test with 'test' variant
|
|
191
|
+
ppick.create_prefsjs(prefs, variant="test")
|
|
192
|
+
assert prefs.is_file()
|
|
193
|
+
prefs_data = prefs.read_text()
|
|
194
|
+
assert 'user_pref("test.a", 1);\n' in prefs_data
|
|
195
|
+
assert 'user_pref("test.b", true);\n' in prefs_data
|
|
196
|
+
assert "// 'test.a' defined by variant 'test'" in prefs_data
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def test_prefpicker_08(tmp_path):
|
|
200
|
+
"""test PrefPicker.create_prefsjs() with different values"""
|
|
201
|
+
raw_data = {
|
|
202
|
+
"variant": [],
|
|
203
|
+
"pref": {
|
|
204
|
+
# type int
|
|
205
|
+
"test.a": {
|
|
206
|
+
"variants": {
|
|
207
|
+
"default": [0, 1],
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
# type None (skip)
|
|
211
|
+
"test.b": {
|
|
212
|
+
"variants": {
|
|
213
|
+
"default": [None],
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
# type string
|
|
217
|
+
"test.c": {
|
|
218
|
+
"variants": {
|
|
219
|
+
"default": ["test string"],
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
# type string (with quotes)
|
|
223
|
+
"test.d": {
|
|
224
|
+
"variants": {
|
|
225
|
+
"default": ["'test' \"string\""],
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
# type bool
|
|
229
|
+
"test.e": {
|
|
230
|
+
"variants": {
|
|
231
|
+
"default": [True, False],
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
# add None twice to trigger the 'skip' code path and write out comment
|
|
235
|
+
"test.f": {
|
|
236
|
+
"variants": {
|
|
237
|
+
"default": [None, None],
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
# mixed types
|
|
241
|
+
"test.g": {
|
|
242
|
+
"variants": {
|
|
243
|
+
"default": ["foo", True, 0],
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
}
|
|
248
|
+
PrefPicker.verify_data(raw_data)
|
|
249
|
+
ppick = PrefPicker()
|
|
250
|
+
ppick.variants = set(raw_data["variant"] + ["default"])
|
|
251
|
+
ppick.prefs = raw_data["pref"]
|
|
252
|
+
prefs = tmp_path / "prefs.js"
|
|
253
|
+
ppick.create_prefsjs(prefs)
|
|
254
|
+
assert prefs.is_file()
|
|
255
|
+
prefs_data = prefs.read_text()
|
|
256
|
+
assert 'user_pref("test.b",' not in prefs_data
|
|
257
|
+
assert "user_pref(\"test.c\", 'test string');" in prefs_data
|
|
258
|
+
# test with unsupported value datatype
|
|
259
|
+
raw_data = {"variant": [], "pref": {"boom.": {"variants": {"default": [1.01]}}}}
|
|
260
|
+
ppick.variants = set(raw_data["variant"] + ["default"])
|
|
261
|
+
ppick.prefs = raw_data["pref"]
|
|
262
|
+
with raises(SourceDataError, match="Unsupported datatype"):
|
|
263
|
+
ppick.create_prefsjs(prefs)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def test_prefpicker_09(tmp_path):
|
|
267
|
+
"""test PrefPicker.load_template() with invalid YAML"""
|
|
268
|
+
yml = tmp_path / "test.yml"
|
|
269
|
+
yml.write_text("{-{-{-{-:::")
|
|
270
|
+
with raises(SourceDataError, match=r"invalid YAML"):
|
|
271
|
+
PrefPicker.load_template(yml)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def test_prefpicker_10():
|
|
275
|
+
"""test PrefPicker.lookup_template()"""
|
|
276
|
+
# unknown template
|
|
277
|
+
assert PrefPicker.lookup_template("missing") is None
|
|
278
|
+
# existing template
|
|
279
|
+
template = next(PrefPicker.templates(), None)
|
|
280
|
+
assert template is not None
|
|
281
|
+
assert PrefPicker.lookup_template(template.name)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
3
|
+
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
4
|
+
"""template.py tests"""
|
|
5
|
+
|
|
6
|
+
from difflib import unified_diff
|
|
7
|
+
|
|
8
|
+
from yaml import safe_dump, safe_load
|
|
9
|
+
|
|
10
|
+
from .main import main
|
|
11
|
+
from .prefpicker import PrefPicker
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_templates_01(tmp_path):
|
|
15
|
+
"""sanity check template YAML files"""
|
|
16
|
+
prefs_js = tmp_path / "prefs.js"
|
|
17
|
+
checked = []
|
|
18
|
+
for template in PrefPicker.templates():
|
|
19
|
+
assert main([str(template), str(prefs_js), "--check"]) == 0
|
|
20
|
+
assert prefs_js.is_file()
|
|
21
|
+
prefs_js.unlink()
|
|
22
|
+
checked.append(template.name)
|
|
23
|
+
assert "browser-fuzzing.yml" in checked
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_templates_02():
|
|
27
|
+
"""check formatting of template YAML files"""
|
|
28
|
+
for template in PrefPicker.templates():
|
|
29
|
+
with template.open() as in_fp:
|
|
30
|
+
# remove comments
|
|
31
|
+
input_yml = "".join(x for x in in_fp if not x.lstrip().startswith("#"))
|
|
32
|
+
formatted_yml = safe_dump(safe_load(input_yml), indent=2, width=100)
|
|
33
|
+
diff = tuple(
|
|
34
|
+
unified_diff(
|
|
35
|
+
input_yml.splitlines(),
|
|
36
|
+
formatted_yml.splitlines(),
|
|
37
|
+
fromfile=str(template),
|
|
38
|
+
tofile="formatting fixes",
|
|
39
|
+
lineterm="",
|
|
40
|
+
)
|
|
41
|
+
)
|
|
42
|
+
if diff:
|
|
43
|
+
formatted = "\n".join(diff)
|
|
44
|
+
raise AssertionError(f"Formatting changes required:\n{formatted}")
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: prefpicker
|
|
3
|
+
Version: 2.17.0
|
|
4
|
+
Summary: PrefPicker - Manage & generate prefs.js files
|
|
5
|
+
Home-page: https://github.com/MozillaSecurity/prefpicker
|
|
6
|
+
Author: Tyson Smith
|
|
7
|
+
Author-email: twsmith@mozilla.com
|
|
8
|
+
Maintainer: Mozilla Fuzzing Team
|
|
9
|
+
Maintainer-email: fuzzing@mozilla.com
|
|
10
|
+
License: MPL 2.0
|
|
11
|
+
Keywords: firefox fuzz fuzzing test testing
|
|
12
|
+
Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Topic :: Software Development :: Testing
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: PyYAML
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
21
|
+
Requires-Dist: tox; extra == "dev"
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
PrefPicker
|
|
25
|
+
==========
|
|
26
|
+
[](https://github.com/MozillaSecurity/prefpicker/actions/workflows/ci.yml)
|
|
27
|
+
[](https://codecov.io/gh/MozillaSecurity/prefpicker)
|
|
28
|
+
[](https://matrix.to/#/#fuzzing:mozilla.org)
|
|
29
|
+
[](https://pypi.org/project/prefpicker)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
Manage & generate prefs.js files for use when testing Firefox. This tool is intended to simplify the use and tracking of prefs used by
|
|
33
|
+
our fuzzing tools. The template files can be modified to allow the creation of custom prefs.js files without
|
|
34
|
+
the need to maintain a separate mostly duplicate version of a prefs file.
|
|
35
|
+
|
|
36
|
+
YAML Template Structure
|
|
37
|
+
-----------------------
|
|
38
|
+
|
|
39
|
+
The template document is made up of variants, prefs and values.
|
|
40
|
+
|
|
41
|
+
_**pref**_ is the name of the preference that will be added to the prefs.js file. This is an unquoted string.
|
|
42
|
+
Valid prefs can be found in [all.js](https://hg.mozilla.org/mozilla-central/file/tip/modules/libpref/init/all.js) or in [StaticPrefList.yml](https://hg.mozilla.org/mozilla-central/file/tip/modules/libpref/init/StaticPrefList.yaml).
|
|
43
|
+
|
|
44
|
+
__**review_on_close**__ is optional. It is a list of relevant Bugzilla IDs used to help avoid obsolete entries. When all bugs in the list are closed the entry will be reviewed and removed if appropriate.
|
|
45
|
+
|
|
46
|
+
_**value**_ can be a `bool`, `int`, `string` or `null`. Adding multiple potential values is possible.
|
|
47
|
+
When multiple values are present one is chosen at random when generating the output.
|
|
48
|
+
Using a value of `null` will exclude the pref from the prefs.js file (acts as browser default).
|
|
49
|
+
|
|
50
|
+
_**variant**_ is a subset of values to be used in place of the default values.
|
|
51
|
+
The default variant is used unless a variant is specified.
|
|
52
|
+
|
|
53
|
+
There are a few mechanisms in place to help keep the file in order:
|
|
54
|
+
- All prefs must have a default variant
|
|
55
|
+
- All variants must be defined in the variant list
|
|
56
|
+
- All variants in the variant list must be used
|
|
57
|
+
- All variants must be a list and contain values
|
|
58
|
+
|
|
59
|
+
```yml
|
|
60
|
+
# example.yml
|
|
61
|
+
variant: # list of extra variants, default is implied
|
|
62
|
+
- alt # name of variant
|
|
63
|
+
pref:
|
|
64
|
+
pref.name: # unquoted name of the pref used in prefs.js
|
|
65
|
+
review_on_close: # optional
|
|
66
|
+
- 123456
|
|
67
|
+
variants:
|
|
68
|
+
default: # variant definition, default is required
|
|
69
|
+
- 0 # potential value
|
|
70
|
+
alt: # extra optional variant
|
|
71
|
+
- 1 # if multiple values are defined one is chosen randomly
|
|
72
|
+
- null # null is a special case meaning exclude the pref
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Updating Templates and Adding Prefs
|
|
76
|
+
-----------------------------------
|
|
77
|
+
Prefs are found in the `.yml` files in the [template](/src/prefpicker/templates) directory.
|
|
78
|
+
Only prefs that are ready to be tested should be added.
|
|
79
|
+
When adding a pref to a template it is encouraged to add a comment that provides justification and points to a bug in Bugzilla for additional context.
|
|
80
|
+
If a pref does not already exist and is only used with non-default variants a `null` entry must be added to the default variant.
|
|
81
|
+
|
|
82
|
+
Quick Setup
|
|
83
|
+
-----------
|
|
84
|
+
|
|
85
|
+
Use pip to install prefpicker.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pip install prefpicker
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Examples
|
|
92
|
+
--------
|
|
93
|
+
|
|
94
|
+
Use a built-in [template](/src/prefpicker/templates) to generate an up-to-date `prefs.js` file.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
prefpicker browser-fuzzing.yml prefs.js
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Or generate a `prefs.js` file from a custom template using the `webrender` variant:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
user@machine:~/prefpicker$ prefpicker custom/template.yml ~/Desktop/prefs.js --variant webrender
|
|
104
|
+
Loading 'template.yml'...
|
|
105
|
+
Loaded 255 prefs and 5 variants
|
|
106
|
+
Generating 'prefs.js' using variant 'webrender'...
|
|
107
|
+
Done.
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The resulting `prefs.js` file is ready to be used with Firefox. It will look something like this:
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
// Generated with PrefPicker @ 2020-02-08 00:50:29 UTC
|
|
114
|
+
// Variant 'webrender'
|
|
115
|
+
/// ... snip
|
|
116
|
+
user_pref("fuzzing.enabled", true);
|
|
117
|
+
/// ... snip
|
|
118
|
+
// 'gfx.webrender.all' defined by variant 'webrender'
|
|
119
|
+
user_pref("gfx.webrender.all", true);
|
|
120
|
+
/// ... snip
|
|
121
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
prefpicker/__init__.py,sha256=XWsqb0fPEcXI12OFAGU0ftCAiUAnNTyyAzADC62x1-g,348
|
|
2
|
+
prefpicker/__main__.py,sha256=8-D6LzRgVF2PwY7XXs1Fs-Nzy0NPOl04DKMmk18SqsU,282
|
|
3
|
+
prefpicker/main.py,sha256=V10iJ6UiNc5aACflJSHjJl59kc6f1uJhuSfRFkrsJqw,3842
|
|
4
|
+
prefpicker/prefpicker.py,sha256=tKnwVdO0bwmOv1XjNntojAiCPwHsAGNx3X6SMxLpaJQ,9817
|
|
5
|
+
prefpicker/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
prefpicker/test_main.py,sha256=6K4eKDvXwy7ogdj-tOKIfjCJjr0CnQwfFyobjpj4hgk,2644
|
|
7
|
+
prefpicker/test_prefpicker.py,sha256=ojoYid7rC57dpWqjpnXnp7_E1F84OBa6iBKrAwl1CyU,9330
|
|
8
|
+
prefpicker/test_templates.py,sha256=jlu3QTWzn1iE_7ljQs3byBAvUaGjeFZPNuBySSvSUoM,1496
|
|
9
|
+
prefpicker/templates/browser-fuzzing.yml,sha256=wAuOaGPHoLQY6TnuvE0b67YOvRBWMVfMj6C-Hd64BXs,23756
|
|
10
|
+
prefpicker/templates/schema.json,sha256=D14picYNGMXV0WObBxeZFb7l_U_OJkZIi29Rv25M2nA,1293
|
|
11
|
+
prefpicker-2.17.0.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
|
|
12
|
+
prefpicker-2.17.0.dist-info/METADATA,sha256=LHgAJLnJzhqWKYK9bc7IVzQijRarWvx8ExS7VfMab54,4949
|
|
13
|
+
prefpicker-2.17.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
14
|
+
prefpicker-2.17.0.dist-info/entry_points.txt,sha256=og57vebqGVtgg_OZGO39WUb13H8wMzcnNBh4h-t26K0,52
|
|
15
|
+
prefpicker-2.17.0.dist-info/top_level.txt,sha256=H-QqR-VZXNwG4ya7wnqx5NA-yua6D9uQuBquP2zCRbc,11
|
|
16
|
+
prefpicker-2.17.0.dist-info/RECORD,,
|