summaryrefslogtreecommitdiffstats
path: root/dom/bindings/mozwebidlcodegen/test/test_mozwebidlcodegen.py
diff options
context:
space:
mode:
Diffstat (limited to 'dom/bindings/mozwebidlcodegen/test/test_mozwebidlcodegen.py')
-rw-r--r--dom/bindings/mozwebidlcodegen/test/test_mozwebidlcodegen.py298
1 files changed, 298 insertions, 0 deletions
diff --git a/dom/bindings/mozwebidlcodegen/test/test_mozwebidlcodegen.py b/dom/bindings/mozwebidlcodegen/test/test_mozwebidlcodegen.py
new file mode 100644
index 000000000..ce3315e88
--- /dev/null
+++ b/dom/bindings/mozwebidlcodegen/test/test_mozwebidlcodegen.py
@@ -0,0 +1,298 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import unicode_literals
+
+import imp
+import json
+import os
+import shutil
+import sys
+import tempfile
+import unittest
+
+import mozpack.path as mozpath
+
+from mozwebidlcodegen import (
+ WebIDLCodegenManager,
+ WebIDLCodegenManagerState,
+)
+
+from mozfile import NamedTemporaryFile
+
+from mozunit import (
+ MockedOpen,
+ main,
+)
+
+
+OUR_DIR = mozpath.abspath(mozpath.dirname(__file__))
+TOPSRCDIR = mozpath.normpath(mozpath.join(OUR_DIR, '..', '..', '..', '..'))
+
+
+class TestWebIDLCodegenManager(unittest.TestCase):
+ TEST_STEMS = {
+ 'Child',
+ 'Parent',
+ 'ExampleBinding',
+ 'TestEvent',
+ }
+
+ @property
+ def _static_input_paths(self):
+ s = {mozpath.join(OUR_DIR, p) for p in os.listdir(OUR_DIR)
+ if p.endswith('.webidl')}
+
+ return s
+
+ @property
+ def _config_path(self):
+ config = mozpath.join(TOPSRCDIR, 'dom', 'bindings', 'Bindings.conf')
+ self.assertTrue(os.path.exists(config))
+
+ return config
+
+ def _get_manager_args(self):
+ tmp = tempfile.mkdtemp()
+ self.addCleanup(shutil.rmtree, tmp)
+
+ cache_dir = mozpath.join(tmp, 'cache')
+ os.mkdir(cache_dir)
+
+ ip = self._static_input_paths
+
+ inputs = (
+ ip,
+ {mozpath.splitext(mozpath.basename(p))[0] for p in ip},
+ set(),
+ set(),
+ )
+
+ return dict(
+ config_path=self._config_path,
+ inputs=inputs,
+ exported_header_dir=mozpath.join(tmp, 'exports'),
+ codegen_dir=mozpath.join(tmp, 'codegen'),
+ state_path=mozpath.join(tmp, 'state.json'),
+ make_deps_path=mozpath.join(tmp, 'codegen.pp'),
+ make_deps_target='codegen.pp',
+ cache_dir=cache_dir,
+ )
+
+ def _get_manager(self):
+ return WebIDLCodegenManager(**self._get_manager_args())
+
+ def test_unknown_state_version(self):
+ """Loading a state file with a too new version resets state."""
+ args = self._get_manager_args()
+
+ p = args['state_path']
+
+ with open(p, 'wb') as fh:
+ json.dump({
+ 'version': WebIDLCodegenManagerState.VERSION + 1,
+ 'foobar': '1',
+ }, fh)
+
+ manager = WebIDLCodegenManager(**args)
+
+ self.assertEqual(manager._state['version'],
+ WebIDLCodegenManagerState.VERSION)
+ self.assertNotIn('foobar', manager._state)
+
+ def test_generate_build_files(self):
+ """generate_build_files() does the right thing from empty."""
+ manager = self._get_manager()
+ result = manager.generate_build_files()
+ self.assertEqual(len(result.inputs), 4)
+
+ output = manager.expected_build_output_files()
+ self.assertEqual(result.created, output)
+ self.assertEqual(len(result.updated), 0)
+ self.assertEqual(len(result.unchanged), 0)
+
+ for f in output:
+ self.assertTrue(os.path.isfile(f))
+
+ for f in manager.GLOBAL_DECLARE_FILES:
+ self.assertIn(mozpath.join(manager._exported_header_dir, f), output)
+
+ for f in manager.GLOBAL_DEFINE_FILES:
+ self.assertIn(mozpath.join(manager._codegen_dir, f), output)
+
+ for s in self.TEST_STEMS:
+ self.assertTrue(os.path.isfile(mozpath.join(
+ manager._exported_header_dir, '%sBinding.h' % s)))
+ self.assertTrue(os.path.isfile(mozpath.join(
+ manager._codegen_dir, '%sBinding.cpp' % s)))
+
+ self.assertTrue(os.path.isfile(manager._state_path))
+
+ with open(manager._state_path, 'rb') as fh:
+ state = json.load(fh)
+ self.assertEqual(state['version'], 1)
+ self.assertIn('webidls', state)
+
+ child = state['webidls']['Child.webidl']
+ self.assertEqual(len(child['inputs']), 2)
+ self.assertEqual(len(child['outputs']), 2)
+ self.assertEqual(child['sha1'], 'c41527cad3bc161fa6e7909e48fa11f9eca0468b')
+
+ def test_generate_build_files_load_state(self):
+ """State should be equivalent when instantiating a new instance."""
+ args = self._get_manager_args()
+ m1 = WebIDLCodegenManager(**args)
+ self.assertEqual(len(m1._state['webidls']), 0)
+ m1.generate_build_files()
+
+ m2 = WebIDLCodegenManager(**args)
+ self.assertGreater(len(m2._state['webidls']), 2)
+ self.assertEqual(m1._state, m2._state)
+
+ def test_no_change_no_writes(self):
+ """If nothing changes, no files should be updated."""
+ args = self._get_manager_args()
+ m1 = WebIDLCodegenManager(**args)
+ m1.generate_build_files()
+
+ m2 = WebIDLCodegenManager(**args)
+ result = m2.generate_build_files()
+
+ self.assertEqual(len(result.inputs), 0)
+ self.assertEqual(len(result.created), 0)
+ self.assertEqual(len(result.updated), 0)
+
+ def test_output_file_regenerated(self):
+ """If an output file disappears, it is regenerated."""
+ args = self._get_manager_args()
+ m1 = WebIDLCodegenManager(**args)
+ m1.generate_build_files()
+
+ rm_count = 0
+ for p in m1._state['webidls']['Child.webidl']['outputs']:
+ rm_count += 1
+ os.unlink(p)
+
+ for p in m1.GLOBAL_DECLARE_FILES:
+ rm_count += 1
+ os.unlink(mozpath.join(m1._exported_header_dir, p))
+
+ m2 = WebIDLCodegenManager(**args)
+ result = m2.generate_build_files()
+ self.assertEqual(len(result.created), rm_count)
+
+ def test_only_rebuild_self(self):
+ """If an input file changes, only rebuild that one file."""
+ args = self._get_manager_args()
+ m1 = WebIDLCodegenManager(**args)
+ m1.generate_build_files()
+
+ child_path = None
+ for p in m1._input_paths:
+ if p.endswith('Child.webidl'):
+ child_path = p
+ break
+
+ self.assertIsNotNone(child_path)
+ child_content = open(child_path, 'rb').read()
+
+ with MockedOpen({child_path: child_content + '\n/* */'}):
+ m2 = WebIDLCodegenManager(**args)
+ result = m2.generate_build_files()
+ self.assertEqual(result.inputs, set([child_path]))
+ self.assertEqual(len(result.updated), 0)
+ self.assertEqual(len(result.created), 0)
+
+ def test_rebuild_dependencies(self):
+ """Ensure an input file used by others results in others rebuilding."""
+ args = self._get_manager_args()
+ m1 = WebIDLCodegenManager(**args)
+ m1.generate_build_files()
+
+ parent_path = None
+ child_path = None
+ for p in m1._input_paths:
+ if p.endswith('Parent.webidl'):
+ parent_path = p
+ elif p.endswith('Child.webidl'):
+ child_path = p
+
+ self.assertIsNotNone(parent_path)
+ parent_content = open(parent_path, 'rb').read()
+
+ with MockedOpen({parent_path: parent_content + '\n/* */'}):
+ m2 = WebIDLCodegenManager(**args)
+ result = m2.generate_build_files()
+ self.assertEqual(result.inputs, {child_path, parent_path})
+ self.assertEqual(len(result.updated), 0)
+ self.assertEqual(len(result.created), 0)
+
+ def test_python_change_regenerate_everything(self):
+ """If a Python file changes, we should attempt to rebuild everything."""
+
+ # We don't want to mutate files in the source directory because we want
+ # to be able to build from a read-only filesystem. So, we install a
+ # dummy module and rewrite the metadata to say it comes from the source
+ # directory.
+ #
+ # Hacking imp to accept a MockedFile doesn't appear possible. So for
+ # the first iteration we read from a temp file. The second iteration
+ # doesn't need to import, so we are fine with a mocked file.
+ fake_path = mozpath.join(OUR_DIR, 'fakemodule.py')
+ with NamedTemporaryFile('wt') as fh:
+ fh.write('# Original content')
+ fh.flush()
+ mod = imp.load_source('mozwebidlcodegen.fakemodule', fh.name)
+ mod.__file__ = fake_path
+
+ args = self._get_manager_args()
+ m1 = WebIDLCodegenManager(**args)
+ with MockedOpen({fake_path: '# Original content'}):
+ try:
+ result = m1.generate_build_files()
+ l = len(result.inputs)
+
+ with open(fake_path, 'wt') as fh:
+ fh.write('# Modified content')
+
+ m2 = WebIDLCodegenManager(**args)
+ result = m2.generate_build_files()
+ self.assertEqual(len(result.inputs), l)
+
+ result = m2.generate_build_files()
+ self.assertEqual(len(result.inputs), 0)
+ finally:
+ del sys.modules['mozwebidlcodegen.fakemodule']
+
+ def test_copy_input(self):
+ """Ensure a copied .webidl file is handled properly."""
+
+ # This test simulates changing the type of a WebIDL from static to
+ # preprocessed. In that scenario, the original file still exists but
+ # it should no longer be consulted during codegen.
+
+ args = self._get_manager_args()
+ m1 = WebIDLCodegenManager(**args)
+ m1.generate_build_files()
+
+ old_path = None
+ for p in args['inputs'][0]:
+ if p.endswith('Parent.webidl'):
+ old_path = p
+ break
+ self.assertIsNotNone(old_path)
+
+ new_path = mozpath.join(args['cache_dir'], 'Parent.webidl')
+ shutil.copy2(old_path, new_path)
+
+ args['inputs'][0].remove(old_path)
+ args['inputs'][0].add(new_path)
+
+ m2 = WebIDLCodegenManager(**args)
+ result = m2.generate_build_files()
+ self.assertEqual(len(result.updated), 0)
+
+
+if __name__ == '__main__':
+ main()