Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/.
5 from __future__ import unicode_literals
7 import imp
8 import json
9 import os
10 import shutil
11 import sys
12 import tempfile
13 import unittest
15 import mozpack.path as mozpath
17 from mozwebidlcodegen import (
18 WebIDLCodegenManager,
19 WebIDLCodegenManagerState,
20 )
22 from mozfile import NamedTemporaryFile
24 from mozunit import (
25 MockedOpen,
26 main,
27 )
30 OUR_DIR = mozpath.abspath(mozpath.dirname(__file__))
31 TOPSRCDIR = mozpath.normpath(mozpath.join(OUR_DIR, '..', '..', '..', '..'))
34 class TestWebIDLCodegenManager(unittest.TestCase):
35 TEST_STEMS = {
36 'Child',
37 'Parent',
38 'ExampleBinding',
39 'TestEvent',
40 }
42 @property
43 def _static_input_paths(self):
44 s = {mozpath.join(OUR_DIR, p) for p in os.listdir(OUR_DIR)
45 if p.endswith('.webidl')}
47 return s
49 @property
50 def _config_path(self):
51 config = mozpath.join(TOPSRCDIR, 'dom', 'bindings', 'Bindings.conf')
52 self.assertTrue(os.path.exists(config))
54 return config
56 def _get_manager_args(self):
57 tmp = tempfile.mkdtemp()
58 self.addCleanup(shutil.rmtree, tmp)
60 cache_dir = mozpath.join(tmp, 'cache')
61 os.mkdir(cache_dir)
63 ip = self._static_input_paths
65 inputs = (
66 ip,
67 {mozpath.splitext(mozpath.basename(p))[0] for p in ip},
68 set(),
69 set(),
70 )
72 return dict(
73 config_path=self._config_path,
74 inputs=inputs,
75 exported_header_dir=mozpath.join(tmp, 'exports'),
76 codegen_dir=mozpath.join(tmp, 'codegen'),
77 state_path=mozpath.join(tmp, 'state.json'),
78 make_deps_path=mozpath.join(tmp, 'codegen.pp'),
79 make_deps_target='codegen.pp',
80 cache_dir=cache_dir,
81 )
83 def _get_manager(self):
84 return WebIDLCodegenManager(**self._get_manager_args())
86 def test_unknown_state_version(self):
87 """Loading a state file with a too new version resets state."""
88 args = self._get_manager_args()
90 p = args['state_path']
92 with open(p, 'wb') as fh:
93 json.dump({
94 'version': WebIDLCodegenManagerState.VERSION + 1,
95 'foobar': '1',
96 }, fh)
98 manager = WebIDLCodegenManager(**args)
100 self.assertEqual(manager._state['version'],
101 WebIDLCodegenManagerState.VERSION)
102 self.assertNotIn('foobar', manager._state)
104 def test_generate_build_files(self):
105 """generate_build_files() does the right thing from empty."""
106 manager = self._get_manager()
107 result = manager.generate_build_files()
108 self.assertEqual(len(result.inputs), 5)
110 output = manager.expected_build_output_files()
111 self.assertEqual(result.created, output)
112 self.assertEqual(len(result.updated), 0)
113 self.assertEqual(len(result.unchanged), 0)
115 for f in output:
116 self.assertTrue(os.path.isfile(f))
118 for f in manager.GLOBAL_DECLARE_FILES:
119 self.assertIn(mozpath.join(manager._exported_header_dir, f), output)
121 for f in manager.GLOBAL_DEFINE_FILES:
122 self.assertIn(mozpath.join(manager._codegen_dir, f), output)
124 for s in self.TEST_STEMS:
125 self.assertTrue(os.path.isfile(mozpath.join(
126 manager._exported_header_dir, '%sBinding.h' % s)))
127 self.assertTrue(os.path.isfile(mozpath.join(
128 manager._codegen_dir, '%sBinding.cpp' % s)))
130 self.assertTrue(os.path.isfile(manager._state_path))
132 with open(manager._state_path, 'rb') as fh:
133 state = json.load(fh)
134 self.assertEqual(state['version'], 1)
135 self.assertIn('webidls', state)
137 child = state['webidls']['Child.webidl']
138 self.assertEqual(len(child['inputs']), 2)
139 self.assertEqual(len(child['outputs']), 2)
140 self.assertEqual(child['sha1'], 'c41527cad3bc161fa6e7909e48fa11f9eca0468b')
142 def test_generate_build_files_load_state(self):
143 """State should be equivalent when instantiating a new instance."""
144 args = self._get_manager_args()
145 m1 = WebIDLCodegenManager(**args)
146 self.assertEqual(len(m1._state['webidls']), 0)
147 m1.generate_build_files()
149 m2 = WebIDLCodegenManager(**args)
150 self.assertGreater(len(m2._state['webidls']), 2)
151 self.assertEqual(m1._state, m2._state)
153 def test_no_change_no_writes(self):
154 """If nothing changes, no files should be updated."""
155 args = self._get_manager_args()
156 m1 = WebIDLCodegenManager(**args)
157 m1.generate_build_files()
159 m2 = WebIDLCodegenManager(**args)
160 result = m2.generate_build_files()
162 self.assertEqual(len(result.inputs), 0)
163 self.assertEqual(len(result.created), 0)
164 self.assertEqual(len(result.updated), 0)
166 def test_output_file_regenerated(self):
167 """If an output file disappears, it is regenerated."""
168 args = self._get_manager_args()
169 m1 = WebIDLCodegenManager(**args)
170 m1.generate_build_files()
172 rm_count = 0
173 for p in m1._state['webidls']['Child.webidl']['outputs']:
174 rm_count += 1
175 os.unlink(p)
177 for p in m1.GLOBAL_DECLARE_FILES:
178 rm_count += 1
179 os.unlink(mozpath.join(m1._exported_header_dir, p))
181 m2 = WebIDLCodegenManager(**args)
182 result = m2.generate_build_files()
183 self.assertEqual(len(result.created), rm_count)
185 def test_only_rebuild_self(self):
186 """If an input file changes, only rebuild that one file."""
187 args = self._get_manager_args()
188 m1 = WebIDLCodegenManager(**args)
189 m1.generate_build_files()
191 child_path = None
192 for p in m1._input_paths:
193 if p.endswith('Child.webidl'):
194 child_path = p
195 break
197 self.assertIsNotNone(child_path)
198 child_content = open(child_path, 'rb').read()
200 with MockedOpen({child_path: child_content + '\n/* */'}):
201 m2 = WebIDLCodegenManager(**args)
202 result = m2.generate_build_files()
203 self.assertEqual(result.inputs, set([child_path]))
204 self.assertEqual(len(result.updated), 0)
205 self.assertEqual(len(result.created), 0)
207 def test_rebuild_dependencies(self):
208 """Ensure an input file used by others results in others rebuilding."""
209 args = self._get_manager_args()
210 m1 = WebIDLCodegenManager(**args)
211 m1.generate_build_files()
213 parent_path = None
214 child_path = None
215 for p in m1._input_paths:
216 if p.endswith('Parent.webidl'):
217 parent_path = p
218 elif p.endswith('Child.webidl'):
219 child_path = p
221 self.assertIsNotNone(parent_path)
222 parent_content = open(parent_path, 'rb').read()
224 with MockedOpen({parent_path: parent_content + '\n/* */'}):
225 m2 = WebIDLCodegenManager(**args)
226 result = m2.generate_build_files()
227 self.assertEqual(result.inputs, {child_path, parent_path})
228 self.assertEqual(len(result.updated), 0)
229 self.assertEqual(len(result.created), 0)
231 def test_python_change_regenerate_everything(self):
232 """If a Python file changes, we should attempt to rebuild everything."""
234 # We don't want to mutate files in the source directory because we want
235 # to be able to build from a read-only filesystem. So, we install a
236 # dummy module and rewrite the metadata to say it comes from the source
237 # directory.
238 #
239 # Hacking imp to accept a MockedFile doesn't appear possible. So for
240 # the first iteration we read from a temp file. The second iteration
241 # doesn't need to import, so we are fine with a mocked file.
242 fake_path = mozpath.join(OUR_DIR, 'fakemodule.py')
243 with NamedTemporaryFile('wt') as fh:
244 fh.write('# Original content')
245 fh.flush()
246 mod = imp.load_source('mozwebidlcodegen.fakemodule', fh.name)
247 mod.__file__ = fake_path
249 args = self._get_manager_args()
250 m1 = WebIDLCodegenManager(**args)
251 with MockedOpen({fake_path: '# Original content'}):
252 old_exists = os.path.exists
253 try:
254 def exists(p):
255 if p == fake_path:
256 return True
257 return old_exists(p)
259 os.path.exists = exists
261 result = m1.generate_build_files()
262 l = len(result.inputs)
264 with open(fake_path, 'wt') as fh:
265 fh.write('# Modified content')
267 m2 = WebIDLCodegenManager(**args)
268 result = m2.generate_build_files()
269 self.assertEqual(len(result.inputs), l)
271 result = m2.generate_build_files()
272 self.assertEqual(len(result.inputs), 0)
273 finally:
274 os.path.exists = old_exists
275 del sys.modules['mozwebidlcodegen.fakemodule']
277 def test_copy_input(self):
278 """Ensure a copied .webidl file is handled properly."""
280 # This test simulates changing the type of a WebIDL from static to
281 # preprocessed. In that scenario, the original file still exists but
282 # it should no longer be consulted during codegen.
284 args = self._get_manager_args()
285 m1 = WebIDLCodegenManager(**args)
286 m1.generate_build_files()
288 old_path = None
289 for p in args['inputs'][0]:
290 if p.endswith('Parent.webidl'):
291 old_path = p
292 break
293 self.assertIsNotNone(old_path)
295 new_path = mozpath.join(args['cache_dir'], 'Parent.webidl')
296 shutil.copy2(old_path, new_path)
298 args['inputs'][0].remove(old_path)
299 args['inputs'][0].add(new_path)
301 m2 = WebIDLCodegenManager(**args)
302 result = m2.generate_build_files()
303 self.assertEqual(len(result.updated), 0)
306 if __name__ == '__main__':
307 main()