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