Bug 1270446 - Allow to combine multiple FakeCompiler definitions. r=chmanchester
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 22 Apr 2016 11:34:02 +0900
changeset 296360 471bf0db284398af3ac4c83615e56ad22a0e2fe8
parent 296359 8e38b67846f12fc5423810c67a1f25721f57cdc4
child 296361 cc14a8472950cbc481c9baefac973865e45391b2
push id76310
push usermh@glandium.org
push dateFri, 06 May 2016 12:25:15 +0000
treeherdermozilla-inbound@61bae26a46bc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerschmanchester
bugs1270446
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1270446 - Allow to combine multiple FakeCompiler definitions. r=chmanchester
python/mozbuild/mozbuild/test/configure/test_toolchain_helpers.py
--- a/python/mozbuild/mozbuild/test/configure/test_toolchain_helpers.py
+++ b/python/mozbuild/mozbuild/test/configure/test_toolchain_helpers.py
@@ -108,20 +108,20 @@ class TestCompilerPreprocessor(unittest.
             #endif
         '''))
         input.name = 'foo'
         pp.do_include(input)
 
         self.assertEquals('IFDEF_A\nIF_A\nIF_B\nIF_NOT_C\n', pp.out.getvalue())
 
 
-class FakeCompiler(object):
+class FakeCompiler(dict):
     '''Defines a fake compiler for use in toolchain tests below.
 
-    The definition given when creating an instance can have one of two
+    The definitions given when creating an instance can have one of two
     forms:
     - a dict giving preprocessor symbols and their respective value, e.g.
         { '__GNUC__': 4, '__STDC__': 1 }
     - a dict associating flags to preprocessor symbols. An entry for `None`
       is required in this case. Those are the baseline preprocessor symbols.
       Additional entries describe additional flags to set or existing flags
       to unset (with a value of `False`).
         {
@@ -134,51 +134,63 @@ class FakeCompiler(object):
       __GNUC__, __STDC__, and __STDC_VERSION__ (__STRICT_ANSI__ would be
       unset).
       It is also possible to have different symbols depending on the source
       file extension. In this case, the key is '*.ext'. e.g.
         {
           '*.c': { '__STDC__': 1 },
           '*.cpp': { '__cplusplus': '199711L' },
         }
+
+    All the given definitions are merged together.
+
+    A FakeCompiler instance itself can be used as a definition to create
+    another FakeCompiler.
+
+    For convenience, FakeCompiler instances can be added (+) to one another.
     '''
-    def __init__(self, definition):
-        if definition.get(None) is None:
-            definition = {None: definition}
-        self._definition = definition
+    def __init__(self, *definitions):
+        for definition in definitions:
+            if all(not isinstance(d, dict) for d in definition.itervalues()):
+                definition = {None: definition}
+            for key, value in definition.iteritems():
+                self.setdefault(key, {}).update(value)
 
     def __call__(self, stdin, args):
         files = [arg for arg in args if not arg.startswith('-')]
         flags = [arg for arg in args if arg.startswith('-')]
         if '-E' in flags:
             assert len(files) == 1
             file = files[0]
-            pp = CompilerPreprocessor(self._definition[None])
+            pp = CompilerPreprocessor(self[None])
 
             def apply_defn(defn):
                 for k, v in defn.iteritems():
                     if v is False:
                         if k in pp.context:
                             del pp.context[k]
                     else:
                         pp.context[k] = v
 
-            for glob, defn in self._definition.iteritems():
+            for glob, defn in self.iteritems():
                 if glob and not glob.startswith('-') and fnmatch(file, glob):
                     apply_defn(defn)
 
             for flag in flags:
-                apply_defn(self._definition.get(flag, {}))
+                apply_defn(self.get(flag, {}))
 
             pp.out = StringIO()
             pp.do_include(file)
             return 0, pp.out.getvalue(), ''
 
         return 1, '', ''
 
+    def __add__(self, other):
+        return FakeCompiler(self, other)
+
 
 class TestFakeCompiler(unittest.TestCase):
     def test_fake_compiler(self):
         with MockedOpen({
             'file': 'A B C',
             'file.c': 'A B C',
         }):
             compiler = FakeCompiler({
@@ -223,11 +235,95 @@ class TestFakeCompiler(unittest.TestCase
                               (0, '1 B bar', ''))
             self.assertEquals(compiler(None, ['-E', '-qux', '-bar', 'file']),
                               (0, '1 bar bar', ''))
             self.assertEquals(compiler(None, ['-E', 'file.c']),
                               (0, '1 42 C', ''))
             self.assertEquals(compiler(None, ['-E', '-bar', 'file.c']),
                               (0, '1 bar bar', ''))
 
+    def test_multiple_definitions(self):
+        compiler = FakeCompiler({
+            'A': 1,
+            'B': 2,
+        }, {
+            'C': 3,
+        })
+
+        self.assertEquals(compiler, {
+            None: {
+                'A': 1,
+                'B': 2,
+                'C': 3,
+            },
+        })
+        compiler = FakeCompiler({
+            'A': 1,
+            'B': 2,
+        }, {
+            'B': 4,
+            'C': 3,
+        })
+
+        self.assertEquals(compiler, {
+            None: {
+                'A': 1,
+                'B': 4,
+                'C': 3,
+            },
+        })
+        compiler = FakeCompiler({
+            'A': 1,
+            'B': 2,
+        }, {
+            None: {
+                'B': 4,
+                'C': 3,
+            },
+            '-foo': {
+                'D': 5,
+            },
+        })
+
+        self.assertEquals(compiler, {
+            None: {
+                'A': 1,
+                'B': 4,
+                'C': 3,
+            },
+            '-foo': {
+                'D': 5,
+            },
+        })
+
+        compiler = FakeCompiler({
+            None: {
+                'A': 1,
+                'B': 2,
+            },
+            '-foo': {
+                'D': 5,
+            },
+        }, {
+            '-foo': {
+                'D': 5,
+            },
+            '-bar': {
+                'E': 6,
+            },
+        })
+
+        self.assertEquals(compiler, {
+            None: {
+                'A': 1,
+                'B': 2,
+            },
+            '-foo': {
+                'D': 5,
+            },
+            '-bar': {
+                'E': 6,
+            },
+        })
+
 
 if __name__ == '__main__':
     main()