Bug 902619 - Write mozinfo.json as part of config.status; r=ted
authorGregory Szorc <gps@mozilla.com>
Wed, 07 Aug 2013 23:48:41 -0700
changeset 154669 da018ddfa0c0f9c2d2c4475386281f63563613fe
parent 154668 07e9242d563a96d887096cc687a4d182891cc093
child 154670 814808c7bba85899e79e3ee92286c5acb0dcc3c0
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted
bugs902619
milestone26.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 902619 - Write mozinfo.json as part of config.status; r=ted There are both mechanical and logical changes in this patch. The mechanical changes involve moving some files into the mozbuild package. The logical changes include move writing of mozinfo.json into config.status (from configure.in). There were some variable assignments being performed in configure.in. These variables were read from writemozinfo.py. However, these variables don't appear to be necessary! Now that mozinfo has full access to the underlying config.status data structure, it can now access these variables directly. I verified that every variable being assigned in configure.in had a corresponding AC_SUBST earlier in the file. The only variable that's a bit weird is the TOPSRCDIR and MOZCONFIG environment variables. mozinfo continues to look in the environment for MOZCONFIG. However TOPSRCDIR is now coming from config.status. As part of moving the code, I also modernized the test file, cleaned up some style, and removed some unused imports.
build/ConfigStatus.py
config/tests/unit-writemozinfo.py
config/writemozinfo.py
configure.in
js/src/build/ConfigStatus.py
python/mozbuild/mozbuild/mozinfo.py
python/mozbuild/mozbuild/test/test_mozinfo.py
--- a/build/ConfigStatus.py
+++ b/build/ConfigStatus.py
@@ -14,18 +14,17 @@ import sys
 
 from optparse import OptionParser
 
 from mach.logging import LoggingManager
 from mozbuild.backend.configenvironment import ConfigEnvironment
 from mozbuild.backend.recursivemake import RecursiveMakeBackend
 from mozbuild.frontend.emitter import TreeMetadataEmitter
 from mozbuild.frontend.reader import BuildReader
-
-from Preprocessor import Preprocessor
+from mozbuild.mozinfo import write_mozinfo
 
 
 log_manager = LoggingManager()
 
 
 def config_status(topobjdir = '.', topsrcdir = '.',
                   defines = [], non_global_defines = [], substs = [],
                   files = [], headers = []):
@@ -82,16 +81,21 @@ def config_status(topobjdir = '.', topsr
 
     # Without -n, the current directory is meant to be the top object directory
     if not options.not_topobjdir:
         topobjdir = os.path.abspath('.')
 
     env = ConfigEnvironment(topsrcdir, topobjdir, defines=defines,
             non_global_defines=non_global_defines, substs=substs)
 
+    # mozinfo.json only needs written if configure changes and configure always
+    # passes this environment variable.
+    if 'WRITE_MOZINFO' in os.environ:
+        write_mozinfo(os.path.join(topobjdir, 'mozinfo.json'), env, os.environ)
+
     reader = BuildReader(env)
     emitter = TreeMetadataEmitter(env)
     backend = RecursiveMakeBackend(env)
     # This won't actually do anything because of the magic of generators.
     definitions = emitter.emit(reader.read_topsrcdir())
 
     if options.recheck:
         # Execute configure from the top object directory
--- a/configure.in
+++ b/configure.in
@@ -9049,17 +9049,19 @@ HAVE_SYS_MOUNT_H
 AC_CONFIG_HEADER(
 netwerk/necko-config.h
 xpcom/xpcom-config.h
 xpcom/xpcom-private.h
 )
 
 AC_SUBST(STLPORT_LIBS)
 
+export WRITE_MOZINFO=1
 AC_OUTPUT([mozilla-config.h])
+unset WRITE_MOZINFO
 
 # Hack around an Apple bug that affects the egrep that comes with OS X 10.7.
 # "env ARCHPREFERENCE=i386,x86_64 arch egrep" first tries to use the 32-bit
 # Intel part of the egrep fat binary, even on 64-bit systems, and falls back on
 # the 64-bit part if it's not a fat binary, as can happen with MacPorts. We
 # (apparently) only need this hack when egrep's "pattern" is particularly long
 # (as in the following code) and the first egrep on our $PATH is Apple's.  See
 # bug 655339.
@@ -9196,34 +9198,16 @@ dnl so that regeneration via dependencie
      $GYP_WEBRTC_OPTIONS \
      --generator-output=${_objdir}/media/mtransport/third_party/nICEr \
      ${srcdir}/media/mtransport/third_party/nICEr/nicer.gyp
    if test "$?" != 0; then
       AC_MSG_ERROR([failed to generate nICEr Makefiles])
    fi
 fi
 
-# Generate a JSON config file for unittest harnesses etc to read
-# build configuration details from in a standardized way.
-OS_TARGET=${OS_TARGET} \
-TARGET_CPU=${TARGET_CPU} \
-MOZ_DEBUG=${MOZ_DEBUG} \
-MOZ_WIDGET_TOOLKIT=${MOZ_WIDGET_TOOLKIT} \
-UNIVERSAL_BINARY=${UNIVERSAL_BINARY} \
-MOZ_CRASHREPORTER=${MOZ_CRASHREPORTER} \
-MOZ_APP_NAME=${MOZ_APP_NAME} \
-TOPSRCDIR=${_topsrcdir} \
-MOZ_ASAN=${MOZ_ASAN} \
-  $PYTHON ${_topsrcdir}/config/writemozinfo.py ./mozinfo.json.tmp
-if cmp -s ./mozinfo.json.tmp ./mozinfo.json; then
-  rm ./mozinfo.json.tmp
-else
-  mv -f ./mozinfo.json.tmp ./mozinfo.json
-fi
-
 # Run jemalloc configure script
 
 if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_MEMORY" && test -n "$MOZ_JEMALLOC3" -o -n "$MOZ_REPLACE_MALLOC"; then
   ac_configure_args="$_SUBDIR_CONFIG_ARGS --build=$build --host=$target --enable-stats --with-jemalloc-prefix=je_"
   if test -n "$MOZ_REPLACE_MALLOC"; then
     # When using replace_malloc, we always want memalign and valloc exported from jemalloc.
     ac_configure_args="$ac_configure_args ac_cv_func_memalign=yes"
     ac_configure_args="$ac_configure_args ac_cv_func_valloc=yes"
--- a/js/src/build/ConfigStatus.py
+++ b/js/src/build/ConfigStatus.py
@@ -14,18 +14,17 @@ import sys
 
 from optparse import OptionParser
 
 from mach.logging import LoggingManager
 from mozbuild.backend.configenvironment import ConfigEnvironment
 from mozbuild.backend.recursivemake import RecursiveMakeBackend
 from mozbuild.frontend.emitter import TreeMetadataEmitter
 from mozbuild.frontend.reader import BuildReader
-
-from Preprocessor import Preprocessor
+from mozbuild.mozinfo import write_mozinfo
 
 
 log_manager = LoggingManager()
 
 
 def config_status(topobjdir = '.', topsrcdir = '.',
                   defines = [], non_global_defines = [], substs = [],
                   files = [], headers = []):
@@ -82,16 +81,21 @@ def config_status(topobjdir = '.', topsr
 
     # Without -n, the current directory is meant to be the top object directory
     if not options.not_topobjdir:
         topobjdir = os.path.abspath('.')
 
     env = ConfigEnvironment(topsrcdir, topobjdir, defines=defines,
             non_global_defines=non_global_defines, substs=substs)
 
+    # mozinfo.json only needs written if configure changes and configure always
+    # passes this environment variable.
+    if 'WRITE_MOZINFO' in os.environ:
+        write_mozinfo(os.path.join(topobjdir, 'mozinfo.json'), env, os.environ)
+
     reader = BuildReader(env)
     emitter = TreeMetadataEmitter(env)
     backend = RecursiveMakeBackend(env)
     # This won't actually do anything because of the magic of generators.
     definitions = emitter.emit(reader.read_topsrcdir())
 
     if options.recheck:
         # Execute configure from the top object directory
rename from config/writemozinfo.py
rename to python/mozbuild/mozbuild/mozinfo.py
--- a/config/writemozinfo.py
+++ b/python/mozbuild/mozbuild/mozinfo.py
@@ -1,49 +1,40 @@
-#!/usr/bin/env python
 # 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/.
 
-#
-# This script is run during configure, taking variables set in configure
-# and producing a JSON file that describes some portions of the build
-# configuration, such as the target OS and CPU.
-#
-# The output file is intended to be used as input to the mozinfo package.
-from __future__ import print_function
+# This module produces a JSON file that provides basic build info and
+# configuration metadata.
+
 import os
 import re
-import sys
 import json
 
-import buildconfig
 
-def build_dict(env=None):
+def build_dict(config, env=os.environ):
     """
     Build a dict containing data about the build configuration from
     the environment.
     """
-    substs = env or buildconfig.substs
-    env = env or os.environ
+    substs = config.substs
 
     # Check that all required variables are present first.
     required = ["TARGET_CPU", "OS_TARGET", "MOZ_WIDGET_TOOLKIT"]
     missing = [r for r in required if r not in substs]
     if missing:
         raise Exception("Missing required environment variables: %s" %
                         ', '.join(missing))
 
     d = {}
-    d['topsrcdir'] = substs.get('TOPSRCDIR', buildconfig.topsrcdir)
+    d['topsrcdir'] = config.topsrcdir
 
     if 'MOZCONFIG' in env:
         mozconfig = env["MOZCONFIG"]
-        if 'TOPSRCDIR' in env:
-            mozconfig = os.path.join(env["TOPSRCDIR"], mozconfig)
+        mozconfig = os.path.join(config.topsrcdir, mozconfig)
         d['mozconfig'] = os.path.normpath(mozconfig)
 
     # os
     o = substs["OS_TARGET"]
     known_os = {"Linux": "linux",
                 "WINNT": "win",
                 "Darwin": "mac",
                 "Android": "b2g" if substs["MOZ_WIDGET_TOOLKIT"] == "gonk" else "android"}
@@ -84,29 +75,22 @@ def build_dict(env=None):
     d['debug'] = substs.get('MOZ_DEBUG') == '1'
     d['crashreporter'] = substs.get('MOZ_CRASHREPORTER') == '1'
     d['asan'] = substs.get('MOZ_ASAN') == '1'
     d['tests_enabled'] = substs.get('ENABLE_TESTS') == "1"
     d['bin_suffix'] = substs.get('BIN_SUFFIX', '')
 
     return d
 
-def write_json(file, env=None):
-    """
-    Write JSON data about the configuration specified in |env|
-    to |file|, which may be a filename or file-like object.
+
+def write_mozinfo(file, config, env=os.environ):
+    """Write JSON data about the configuration specified in config and an
+    environment variable dict to |file|, which may be a filename or file-like
+    object.
     See build_dict for information about what  environment variables are used,
     and what keys are produced.
     """
-    build_conf = build_dict(env=env)
+    build_conf = build_dict(config, env)
     if isinstance(file, basestring):
         with open(file, "w") as f:
             json.dump(build_conf, f)
     else:
         json.dump(build_conf, file)
-
-
-if __name__ == '__main__':
-    try:
-        write_json(sys.argv[1] if len(sys.argv) > 1 else sys.stdout)
-    except Exception as e:
-        print(str(e), file=sys.stderr)
-        sys.exit(1)
rename from config/tests/unit-writemozinfo.py
rename to python/mozbuild/mozbuild/test/test_mozinfo.py
--- a/config/tests/unit-writemozinfo.py
+++ b/python/mozbuild/mozbuild/test/test_mozinfo.py
@@ -1,204 +1,271 @@
 #!/usr/bin/env python
+# 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/.
+
+import json
+import os
+import tempfile
 import unittest
-import json, os, sys, time, tempfile
+
 from StringIO import StringIO
+
 import mozunit
 
-from writemozinfo import build_dict, write_json
+from mozbuild.backend.configenvironment import ConfigEnvironment
+
+from mozbuild.mozinfo import (
+    build_dict,
+    write_mozinfo,
+)
+
 
-class TestBuildDict(unittest.TestCase):
-    def testMissing(self):
+class Base(object):
+    def _config(self, substs={}):
+        d = os.path.dirname(__file__)
+        return ConfigEnvironment(d, d, substs=substs)
+
+
+class TestBuildDict(unittest.TestCase, Base):
+    def test_missing(self):
         """
         Test that missing required values raises.
         """
-        self.assertRaises(Exception, build_dict, {'OS_TARGET':'foo'})
-        self.assertRaises(Exception, build_dict, {'TARGET_CPU':'foo'})
-        self.assertRaises(Exception, build_dict, {'MOZ_WIDGET_TOOLKIT':'foo'})
+
+        with self.assertRaises(Exception):
+            build_dict(self._config(substs=dict(OS_TARGET='foo')))
+
+        with self.assertRaises(Exception):
+            build_dict(self._config(substs=dict(TARGET_CPU='foo')))
 
-    def testWin(self):
-        d = build_dict({'OS_TARGET':'WINNT',
-                        'TARGET_CPU':'i386',
-                        'MOZ_WIDGET_TOOLKIT':'windows'})
+        with self.assertRaises(Exception):
+            build_dict(self._config(substs=dict(MOZ_WIDGET_TOOLKIT='foo')))
+
+    def test_win(self):
+        d = build_dict(self._config(dict(
+            OS_TARGET='WINNT',
+            TARGET_CPU='i386',
+            MOZ_WIDGET_TOOLKIT='windows',
+        )))
         self.assertEqual('win', d['os'])
         self.assertEqual('x86', d['processor'])
         self.assertEqual('windows', d['toolkit'])
         self.assertEqual(32, d['bits'])
 
-    def testLinux(self):
-        d = build_dict({'OS_TARGET':'Linux',
-                        'TARGET_CPU':'i386',
-                        'MOZ_WIDGET_TOOLKIT':'gtk2'})
+    def test_linux(self):
+        d = build_dict(self._config(dict(
+            OS_TARGET='Linux',
+            TARGET_CPU='i386',
+            MOZ_WIDGET_TOOLKIT='gtk2',
+        )))
         self.assertEqual('linux', d['os'])
         self.assertEqual('x86', d['processor'])
         self.assertEqual('gtk2', d['toolkit'])
         self.assertEqual(32, d['bits'])
 
-        d = build_dict({'OS_TARGET':'Linux',
-                        'TARGET_CPU':'x86_64',
-                        'MOZ_WIDGET_TOOLKIT':'gtk2'})
+        d = build_dict(self._config(dict(
+            OS_TARGET='Linux',
+            TARGET_CPU='x86_64',
+            MOZ_WIDGET_TOOLKIT='gtk2',
+        )))
         self.assertEqual('linux', d['os'])
         self.assertEqual('x86_64', d['processor'])
         self.assertEqual('gtk2', d['toolkit'])
         self.assertEqual(64, d['bits'])
 
-    def testMac(self):
-        d = build_dict({'OS_TARGET':'Darwin',
-                        'TARGET_CPU':'i386',
-                        'MOZ_WIDGET_TOOLKIT':'cocoa'})
+    def test_mac(self):
+        d = build_dict(self._config(dict(
+            OS_TARGET='Darwin',
+            TARGET_CPU='i386',
+            MOZ_WIDGET_TOOLKIT='cocoa',
+        )))
         self.assertEqual('mac', d['os'])
         self.assertEqual('x86', d['processor'])
         self.assertEqual('cocoa', d['toolkit'])
         self.assertEqual(32, d['bits'])
 
-        d = build_dict({'OS_TARGET':'Darwin',
-                        'TARGET_CPU':'x86_64',
-                        'MOZ_WIDGET_TOOLKIT':'cocoa'})
+        d = build_dict(self._config(dict(
+            OS_TARGET='Darwin',
+            TARGET_CPU='x86_64',
+            MOZ_WIDGET_TOOLKIT='cocoa',
+        )))
         self.assertEqual('mac', d['os'])
         self.assertEqual('x86_64', d['processor'])
         self.assertEqual('cocoa', d['toolkit'])
         self.assertEqual(64, d['bits'])
 
-    def testMacUniversal(self):
-        d = build_dict({'OS_TARGET':'Darwin',
-                        'TARGET_CPU':'i386',
-                        'MOZ_WIDGET_TOOLKIT':'cocoa',
-                        'UNIVERSAL_BINARY': '1'})
-        self.assertEqual('mac', d['os'])
-        self.assertEqual('universal-x86-x86_64', d['processor'])
-        self.assertEqual('cocoa', d['toolkit'])
-        self.assertFalse('bits' in d)
-
-        d = build_dict({'OS_TARGET':'Darwin',
-                        'TARGET_CPU':'x86_64',
-                        'MOZ_WIDGET_TOOLKIT':'cocoa',
-                        'UNIVERSAL_BINARY': '1'})
+    def test_mac_universal(self):
+        d = build_dict(self._config(dict(
+            OS_TARGET='Darwin',
+            TARGET_CPU='i386',
+            MOZ_WIDGET_TOOLKIT='cocoa',
+            UNIVERSAL_BINARY='1',
+        )))
         self.assertEqual('mac', d['os'])
         self.assertEqual('universal-x86-x86_64', d['processor'])
         self.assertEqual('cocoa', d['toolkit'])
         self.assertFalse('bits' in d)
 
-    def testAndroid(self):
-        d = build_dict({'OS_TARGET':'Android',
-                        'TARGET_CPU':'arm',
-                        'MOZ_WIDGET_TOOLKIT':'android'})
+        d = build_dict(self._config(dict(
+            OS_TARGET='Darwin',
+            TARGET_CPU='x86_64',
+            MOZ_WIDGET_TOOLKIT='cocoa',
+            UNIVERSAL_BINARY='1',
+        )))
+        self.assertEqual('mac', d['os'])
+        self.assertEqual('universal-x86-x86_64', d['processor'])
+        self.assertEqual('cocoa', d['toolkit'])
+        self.assertFalse('bits' in d)
+
+    def test_android(self):
+        d = build_dict(self._config(dict(
+            OS_TARGET='Android',
+            TARGET_CPU='arm',
+            MOZ_WIDGET_TOOLKIT='android',
+        )))
         self.assertEqual('android', d['os'])
         self.assertEqual('arm', d['processor'])
         self.assertEqual('android', d['toolkit'])
         self.assertEqual(32, d['bits'])
 
-    def testX86(self):
+    def test_x86(self):
         """
         Test that various i?86 values => x86.
         """
-        d = build_dict({'OS_TARGET':'WINNT',
-                        'TARGET_CPU':'i486',
-                        'MOZ_WIDGET_TOOLKIT':'windows'})
+        d = build_dict(self._config(dict(
+            OS_TARGET='WINNT',
+            TARGET_CPU='i486',
+            MOZ_WIDGET_TOOLKIT='windows',
+        )))
         self.assertEqual('x86', d['processor'])
 
-        d = build_dict({'OS_TARGET':'WINNT',
-                        'TARGET_CPU':'i686',
-                        'MOZ_WIDGET_TOOLKIT':'windows'})
+        d = build_dict(self._config(dict(
+            OS_TARGET='WINNT',
+            TARGET_CPU='i686',
+            MOZ_WIDGET_TOOLKIT='windows',
+        )))
         self.assertEqual('x86', d['processor'])
 
-    def testARM(self):
+    def test_arm(self):
         """
         Test that all arm CPU architectures => arm.
         """
-        d = build_dict({'OS_TARGET':'Linux',
-                        'TARGET_CPU':'arm',
-                        'MOZ_WIDGET_TOOLKIT':'gtk2'})
+        d = build_dict(self._config(dict(
+            OS_TARGET='Linux',
+            TARGET_CPU='arm',
+            MOZ_WIDGET_TOOLKIT='gtk2',
+        )))
         self.assertEqual('arm', d['processor'])
 
-        d = build_dict({'OS_TARGET':'Linux',
-                        'TARGET_CPU':'armv7',
-                        'MOZ_WIDGET_TOOLKIT':'gtk2'})
+        d = build_dict(self._config(dict(
+            OS_TARGET='Linux',
+            TARGET_CPU='armv7',
+            MOZ_WIDGET_TOOLKIT='gtk2',
+        )))
         self.assertEqual('arm', d['processor'])
 
-    def testUnknown(self):
+    def test_unknown(self):
         """
         Test that unknown values pass through okay.
         """
-        d = build_dict({'OS_TARGET':'RandOS',
-                        'TARGET_CPU':'cptwo',
-                        'MOZ_WIDGET_TOOLKIT':'foobar'})
+        d = build_dict(self._config(dict(
+            OS_TARGET='RandOS',
+            TARGET_CPU='cptwo',
+            MOZ_WIDGET_TOOLKIT='foobar',
+        )))
         self.assertEqual("randos", d["os"])
         self.assertEqual("cptwo", d["processor"])
         self.assertEqual("foobar", d["toolkit"])
         # unknown CPUs should not get a bits value
         self.assertFalse("bits" in d)
-        
-    def testDebug(self):
+
+    def test_debug(self):
         """
         Test that debug values are properly detected.
         """
-        d = build_dict({'OS_TARGET':'Linux',
-                        'TARGET_CPU':'i386',
-                        'MOZ_WIDGET_TOOLKIT':'gtk2'})
+        d = build_dict(self._config(dict(
+            OS_TARGET='Linux',
+            TARGET_CPU='i386',
+            MOZ_WIDGET_TOOLKIT='gtk2',
+        )))
         self.assertEqual(False, d['debug'])
-        
-        d = build_dict({'OS_TARGET':'Linux',
-                        'TARGET_CPU':'i386',
-                        'MOZ_WIDGET_TOOLKIT':'gtk2',
-                        'MOZ_DEBUG':'1'})
+
+        d = build_dict(self._config(dict(
+            OS_TARGET='Linux',
+            TARGET_CPU='i386',
+            MOZ_WIDGET_TOOLKIT='gtk2',
+            MOZ_DEBUG='1',
+        )))
         self.assertEqual(True, d['debug'])
 
-    def testCrashreporter(self):
+    def test_crashreporter(self):
         """
         Test that crashreporter values are properly detected.
         """
-        d = build_dict({'OS_TARGET':'Linux',
-                        'TARGET_CPU':'i386',
-                        'MOZ_WIDGET_TOOLKIT':'gtk2'})
+        d = build_dict(self._config(dict(
+            OS_TARGET='Linux',
+            TARGET_CPU='i386',
+            MOZ_WIDGET_TOOLKIT='gtk2',
+        )))
         self.assertEqual(False, d['crashreporter'])
-        
-        d = build_dict({'OS_TARGET':'Linux',
-                        'TARGET_CPU':'i386',
-                        'MOZ_WIDGET_TOOLKIT':'gtk2',
-                        'MOZ_CRASHREPORTER':'1'})
+
+        d = build_dict(self._config(dict(
+            OS_TARGET='Linux',
+            TARGET_CPU='i386',
+            MOZ_WIDGET_TOOLKIT='gtk2',
+            MOZ_CRASHREPORTER='1',
+        )))
         self.assertEqual(True, d['crashreporter'])
 
-class TestWriteJson(unittest.TestCase):
+
+class TestWriteMozinfo(unittest.TestCase, Base):
     """
-    Test the write_json function.
+    Test the write_mozinfo function.
     """
     def setUp(self):
         fd, self.f = tempfile.mkstemp()
         os.close(fd)
 
     def tearDown(self):
         os.unlink(self.f)
 
-    def testBasic(self):
+    def test_basic(self):
         """
         Test that writing to a file produces correct output.
         """
-        write_json(self.f, env={'OS_TARGET':'WINNT',
-                                'TARGET_CPU':'i386',
-                                'TOPSRCDIR':'/tmp',
-                                'MOZCONFIG':'foo',
-                                'MOZ_WIDGET_TOOLKIT':'windows'})
+        c = self._config(dict(
+            OS_TARGET='WINNT',
+            TARGET_CPU='i386',
+            MOZ_WIDGET_TOOLKIT='windows',
+        ))
+        c.topsrcdir = '/tmp'
+        write_mozinfo(self.f, c, {'MOZCONFIG': 'foo'})
         with open(self.f) as f:
             d = json.load(f)
             self.assertEqual('win', d['os'])
             self.assertEqual('x86', d['processor'])
             self.assertEqual('windows', d['toolkit'])
             self.assertEqual('/tmp', d['topsrcdir'])
             self.assertEqual(os.path.normpath('/tmp/foo'), d['mozconfig'])
             self.assertEqual(32, d['bits'])
 
-    def testFileObj(self):
+    def test_fileobj(self):
         """
         Test that writing to a file-like object produces correct output.
         """
         s = StringIO()
-        write_json(s, env={'OS_TARGET':'WINNT',
-                           'TARGET_CPU':'i386',
-                           'MOZ_WIDGET_TOOLKIT':'windows'})
+        c = self._config(dict(
+            OS_TARGET='WINNT',
+            TARGET_CPU='i386',
+            MOZ_WIDGET_TOOLKIT='windows',
+        ))
+        write_mozinfo(s, c)
         d = json.loads(s.getvalue())
         self.assertEqual('win', d['os'])
         self.assertEqual('x86', d['processor'])
         self.assertEqual('windows', d['toolkit'])
         self.assertEqual(32, d['bits'])
 
+
 if __name__ == '__main__':
     mozunit.main()