Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
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 | |
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
4 | |
5 | |
6 import pytest | |
7 | |
8 import json | |
9 | |
10 from zipfile import ZipFile | |
11 | |
12 from xml.etree import ElementTree | |
13 from itertools import product | |
14 | |
15 from buildtools import packagerGecko | |
16 from buildtools import localeTools | |
17 | |
18 from buildtools.packager import readMetadata, getBuildVersion, Files | |
19 from functools import reduce | |
20 | |
21 TR_FA = [True, False] | |
22 | |
23 MESSAGES = '\n'.join(( | |
24 'name=Name {0}', | |
25 'description=Awesome description {0}', | |
26 )) | |
27 | |
28 | |
29 @pytest.fixture | |
30 def scripts(tmp_dir): | |
31 """Examplary scripts for testing addMissingFiles""" | |
Vasily Kuznetsov
2017/08/03 16:52:32
AFAIK "examplary" nowadays is usually spelled "exe
tlucas
2017/08/03 21:26:02
Your are right - but i like the "outstanding" part
tlucas
2017/08/04 14:52:00
Done.
| |
32 lib_dir = tmp_dir.mkdir('lib') | |
33 lib_dir.join('ext.js').write('require("hooks");') | |
34 | |
35 content_dir = tmp_dir.mkdir('chrome').mkdir('content') | |
36 content_dir.join('common.js').write('require("hooks");') | |
37 | |
38 | |
39 @pytest.fixture | |
40 def prefs_json(tmp_dir): | |
41 """Minimal .json file for testing processJSONFiles""" | |
42 lib_dir = tmp_dir.mkdir('lib') | |
43 lib_dir.join('prefs.json').write(json.dumps( | |
44 {'foo': 'bar'} | |
45 )) | |
46 | |
47 | |
48 @pytest.fixture | |
49 def locales(tmp_dir): | |
50 """Minimal locales for testing locale-processing""" | |
51 chrome_dir = tmp_dir.mkdir('chrome') | |
52 locale_dir = chrome_dir.mkdir('locale') | |
53 | |
54 data = { | |
55 'name': {'message': 'Name translated'}, | |
56 'description': {'message': 'Description translated'} | |
Vasily Kuznetsov
2017/08/03 16:52:32
When you use multiline layout for lists, sets and
tlucas
2017/08/03 21:26:03
As you can see in other collection-defintions, i n
tlucas
2017/08/04 14:51:59
Done.
| |
57 } | |
58 | |
59 for locale in ['en-US', 'de', 'kn']: | |
60 new_dir = locale_dir.mkdir(locale) | |
61 new_dir.join('meta.properties').write(MESSAGES.format(locale)) | |
62 new_dir.join('test.json').write(json.dumps(data)) | |
63 if locale == 'kn': | |
64 new_dir.join('.incomplete').write('') | |
65 | |
66 | |
67 @pytest.fixture | |
68 def subscriptions(tmp_dir): | |
69 """Examplary sbuscription-configuration""" | |
70 tmp_dir.join('subs.xml').write('\n'.join(( | |
Vasily Kuznetsov
2017/08/03 16:52:32
Wouldn't it be easier to just use a string literal
tlucas
2017/08/03 21:26:03
Acknowledged.
tlucas
2017/08/04 14:52:00
Done.
| |
71 '<subscriptions>', | |
72 '<subscription title="EasyList"', | |
73 'specialization="English"', | |
74 'url="https://easylist-downloads.adblockplus.org/easylist.txt"', | |
75 'homepage="https://easylist.adblockplus.org/"', | |
76 'prefixes="en"', | |
77 'author="fanboy, MonztA, Famlam, Khrin"', | |
78 'type="ads"/>', | |
79 '</subscriptions>', | |
80 ))) | |
81 | |
82 | |
83 def test_package_files(tmpdir): | |
84 tmpdir.join('foo.xml').write('') | |
85 tmpdir.join('foo.txt').write('') | |
86 tmpdir.join('foo.js').write('') | |
87 | |
88 params = { | |
89 'baseDir': str(tmpdir) | |
90 } | |
91 | |
92 files = packagerGecko.getPackageFiles(params) | |
93 assert 'foo.xml' in files | |
94 assert 'foo.js' in files | |
95 assert 'foo.txt' not in files | |
96 | |
97 | |
98 @pytest.mark.usefixtures('locales') | |
99 def test_get_locales(tmp_dir): | |
100 for incomplete in [True, False]: | |
Vasily Kuznetsov
2017/08/03 16:52:32
This could also be done via parametrize perhaps.
tlucas
2017/08/03 21:26:02
Acknowledged.
tlucas
2017/08/04 14:52:00
Done.
| |
101 locales = packagerGecko.getLocales(str(tmp_dir), incomplete) | |
102 | |
103 assert 'de' in locales | |
104 assert 'en-US' in locales | |
105 assert ('kn' in locales) == incomplete | |
106 | |
107 | |
108 @pytest.mark.parametrize('metadata_files', ['metadata.gecko'], indirect=True) | |
109 @pytest.mark.usefixtures('locales', 'metadata_files', 'subscriptions') | |
110 def test_create_manifest(tmp_dir): | |
Vasily Kuznetsov
2017/08/03 16:52:32
All this code is pretty cool and clever, but it ma
tlucas
2017/08/03 21:26:02
The cool- and cleverness could be a result of foll
tlucas
2017/08/04 14:51:59
Done.
Vasily Kuznetsov
2017/08/10 19:48:27
Acknowledged.
| |
111 def first(elem): | |
112 return elem[0] | |
113 | |
114 def text(elem): | |
115 return elem.text | |
116 | |
117 def iteritems(func=None): | |
118 def wrapper(elements): | |
119 for elem in elements: | |
120 if func: | |
121 yield func(elem) | |
122 else: | |
123 yield elem | |
124 return wrapper | |
125 | |
126 metadata = readMetadata(str(tmp_dir), 'gecko') | |
127 locales = packagerGecko.getLocales(str(tmp_dir)) | |
128 contributors = packagerGecko.getContributors(metadata) | |
129 | |
130 namespaces = { | |
131 'em': 'http://www.mozilla.org/2004/em-rdf#', | |
132 'ns': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', | |
133 } | |
134 | |
135 base = [ | |
136 ('.//*', [len], 54), | |
137 ('./ns:Description/em:id', [first, text], | |
138 '{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}'), | |
139 ('./ns:Description/em:optionsURL', [first, text], | |
140 'chrome://adblockplus/content/ui/settings.xul'), | |
141 ('./ns:Description/em:optionsType', [first, text], '2'), | |
142 ('./ns:Description/em:bootstrap', [first, text], 'true'), | |
143 ('./ns:Description/em:multiprocessCompatible', [first, text], 'true'), | |
144 ('./ns:Description/em:homepageURL', [first, text], | |
145 'http://adblockplus.org/'), | |
146 ('./ns:Description/em:creator', [first, text], 'Wladimir Palant'), | |
147 ('./ns:Description/em:contributor', [iteritems(text)], | |
148 ['Pety Pete', 'Neil Armstrong', 'Famlam', 'fanboy', 'Khrin', | |
149 'MonztA']), | |
150 ] | |
151 | |
152 base += [ | |
153 ('./ns:Description/em:localized/ns:Description[em:locale="{}"]/em:{}' | |
154 .format(locale, tag), | |
155 [first, text], | |
156 value.format(locale)) | |
157 for locale in locales | |
158 for tag, value in [ | |
159 ('name', 'Name {}'), | |
160 ('description', 'Awesome description {}') | |
161 ] | |
162 ] | |
163 | |
164 tags = ['minVersion', 'maxVersion'] | |
165 apps = metadata.items('compat') | |
166 comp = [ | |
167 ( | |
168 packagerGecko.KNOWN_APPS.get(app[0]), | |
169 tags[i], | |
170 app[1].split('/')[i] | |
171 ) for app in apps for i in range(2) | |
172 ] | |
173 | |
174 base += [ | |
175 (''.join(( | |
176 './ns:Description/em:targetApplication/', | |
177 'ns:Description[em:id="{}"]/em:{}' | |
178 )) | |
179 .format(mapped_id, tag), | |
180 [first, text], | |
181 value) | |
182 for mapped_id, tag, value in comp | |
183 ] | |
184 | |
185 for release, multicompartment in product(TR_FA, TR_FA): | |
Vasily Kuznetsov
2017/08/03 16:52:32
Maybe better do this with parametrization?
tlucas
2017/08/03 21:26:02
Acknowledged.
tlucas
2017/08/04 14:52:00
Done.
| |
186 version = getBuildVersion(str(tmp_dir), metadata, release, None) | |
187 expected = base + [ | |
188 ('./ns:Description/em:version', [first, text], version), | |
189 ] | |
190 params = { | |
191 'baseDir': str(tmp_dir), | |
192 'locales': locales, | |
193 'metadata': metadata, | |
194 'version': version.encode('utf-8'), | |
195 'multicompartment': multicompartment, | |
196 'contributors': contributors | |
197 } | |
198 manifest = packagerGecko.createManifest(params) | |
199 | |
200 tree = ElementTree.fromstring(manifest) | |
201 | |
202 with open('/tmp/test.xml', 'w') as fp: | |
Vasily Kuznetsov
2017/08/03 16:52:32
Why use '/tmp' instead of tmpdir fixture? Also kee
tlucas
2017/08/03 21:26:02
Acknowledged.
tlucas
2017/08/04 14:52:00
Done (removed).
| |
203 fp.write(manifest) | |
204 | |
205 for expression, modifiers, value in expected: | |
206 res = reduce( | |
207 lambda val, func: func(val), | |
208 modifiers, | |
209 tree.findall(expression, namespaces=namespaces)) | |
210 | |
211 from collections import Iterable | |
212 | |
213 if isinstance(res, Iterable) and not isinstance(res, str): | |
214 res = list(res) | |
215 for x in res: | |
Vasily Kuznetsov
2017/08/03 16:52:32
Seems like you just want to compare `res` to `valu
tlucas
2017/08/03 21:26:02
I agree with the assert set() == set() part, but o
tlucas
2017/08/04 14:52:00
I totally missed something. Done.
| |
216 assert x in value | |
217 for x in value: | |
218 assert x in res | |
219 assert res == value | |
220 | |
221 | |
222 @pytest.mark.parametrize('metadata_files', ['metadata.gecko'], indirect=True) | |
223 @pytest.mark.usefixtures('locales', 'metadata_files') | |
224 def test_fixup_import_locales(files, tmp_dir): | |
225 locale_dir = tmp_dir.dirpath(tmp_dir.basename, 'chrome', 'locale') | |
226 locale_dir.mkdir('fr').join('meta.properties')\ | |
227 .write(MESSAGES.format('fr')) | |
228 | |
229 metadata = readMetadata(str(tmp_dir), 'gecko') | |
230 locales = packagerGecko.getLocales(str(tmp_dir), False) | |
231 | |
232 params = { | |
233 'metadata': metadata, | |
234 'locales': locales, | |
235 'baseDir': str(tmp_dir) | |
236 } | |
237 | |
238 # Should add missing fr/test.properties to files | |
239 packagerGecko.fixupLocales(params, files) | |
240 | |
241 packagerGecko.importLocales(params, files) | |
242 for locale in locales: | |
243 properties = files['chrome/locale/{}/test.properties'.format(locale)] | |
244 translation_data = list( | |
245 localeTools.parsePropertiesString(properties, '')) | |
246 | |
247 for trans in [ | |
248 ('name', None, 'Name translated'), | |
249 ('description', None, 'Description translated')]: | |
250 assert trans in translation_data | |
251 | |
252 | |
253 def test_process_json_files(tmp_dir, prefs_json): | |
254 params = { | |
255 'baseDir': str(tmp_dir), | |
256 'jsonRequires': {}, | |
257 } | |
258 | |
259 files = Files(packagerGecko.getPackageFiles(params), set()) | |
260 files.read(str(tmp_dir)) | |
261 | |
262 packagerGecko.processJSONFiles(params, files) | |
263 | |
264 assert params['jsonRequires'] == {'prefs.json': {'foo': 'bar'}} | |
265 | |
266 | |
267 @pytest.mark.parametrize('metadata_files', ['metadata.gecko'], indirect=True) | |
268 @pytest.mark.usefixtures('scripts', 'metadata_files') | |
269 def test_add_missing_files(tmp_dir): | |
270 metadata = readMetadata(str(tmp_dir), 'gecko') | |
271 | |
272 params = { | |
273 'baseDir': str(tmp_dir), | |
274 'metadata': metadata, | |
275 'jsonRequires': {}, | |
276 'multicompartment': True, | |
277 'hasWebExtension': False, | |
278 } | |
279 | |
280 files = Files(packagerGecko.getPackageFiles(params), set()) | |
281 files.read(str(tmp_dir)) | |
282 | |
283 packagerGecko.addMissingFiles(params, files) | |
284 | |
285 assert 'let shutdownHandlers = [];' in files['bootstrap.js'] | |
286 assert 'Services.obs.addObserver(' in files['bootstrap.js'] | |
287 for filename in ['bootstrap.js', 'chrome/content/common.js', | |
288 'lib/ext.js', 'lib/hooks.js']: | |
289 assert filename in files | |
290 | |
291 | |
292 @pytest.mark.parametrize('metadata_files', ['metadata.gecko'], indirect=True) | |
293 @pytest.mark.usefixtures('metadata_files', 'locales', 'subscriptions') | |
294 def test_create_build(tmp_dir, capsys): | |
295 base_files = [ | |
296 'bootstrap.js', | |
297 'chrome/locale/de/test.json', | |
298 'chrome/locale/de/test.properties', | |
299 'chrome/locale/en-US/test.json', | |
300 'chrome/locale/en-US/test.properties', | |
301 'install.rdf', | |
302 'subs.xml' | |
303 ] | |
304 | |
305 for all_locales, release, multicompartment in product( | |
Vasily Kuznetsov
2017/08/03 16:52:32
Also maybe parametrization?
tlucas
2017/08/03 21:26:03
Acknowledged.
tlucas
2017/08/04 14:51:59
Done.
| |
306 ['all', None], TR_FA, TR_FA): | |
307 | |
308 if all_locales is None: | |
309 expected = base_files | |
310 else: | |
311 expected = base_files + [ | |
312 'chrome/locale/kn/test.json', | |
313 'chrome/locale/kn/test.properties' | |
314 ] | |
315 | |
316 out_file = tmp_dir.join('{}_{}_{}.zip'.format( | |
317 all_locales, release, multicompartment)) | |
318 | |
319 out_file = str(out_file) | |
320 | |
321 packagerGecko.createBuild( | |
322 str(tmp_dir), | |
323 locales=all_locales, | |
324 outFile=out_file, | |
325 releaseBuild=release, | |
326 multicompartment=multicompartment) | |
327 | |
328 out, err = capsys.readouterr() | |
329 | |
330 assert err ==\ | |
331 "Warning: Mapped file adblockplusui/firstRun.html doesn't exist\n" | |
332 | |
333 with ZipFile(out_file, 'r') as zipfp: | |
334 zipfp.testzip() | |
335 | |
336 filenames = [zipinfo.filename for zipinfo in zipfp.infolist()] | |
337 | |
338 for name in expected: | |
339 assert name in filenames | |
OLD | NEW |