From ef1c83862b8166066a860fbfac93a19ec26bb8c3 Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git@the-compiler.org>
Date: Wed, 20 Sep 2017 10:39:39 +0200
Subject: [PATCH] Use utils.is_* for platform checks everywhere

---
 misc/qutebrowser.spec                         |  5 +-
 qutebrowser/browser/commands.py               |  3 +-
 qutebrowser/browser/downloads.py              |  2 +-
 .../browser/webengine/webenginesettings.py    |  3 +-
 .../browser/webkit/network/networkmanager.py  |  2 +-
 qutebrowser/browser/webkit/webkittab.py       |  9 ++--
 qutebrowser/browser/webkit/webview.py         |  4 +-
 qutebrowser/commands/userscripts.py           |  6 +--
 qutebrowser/misc/crashsignal.py               |  4 +-
 qutebrowser/misc/ipc.py                       | 13 ++---
 qutebrowser/utils/log.py                      |  2 +
 qutebrowser/utils/standarddir.py              | 19 ++++---
 qutebrowser/utils/utils.py                    |  2 +-
 qutebrowser/utils/version.py                  |  6 +--
 scripts/dev/build_release.py                  | 51 ++++++++++---------
 scripts/dev/check_coverage.py                 |  9 ++--
 tests/conftest.py                             | 16 +++---
 tests/end2end/conftest.py                     |  4 +-
 tests/end2end/features/conftest.py            | 15 +++---
 .../browser/webkit/network/test_filescheme.py |  7 +--
 tests/unit/commands/test_userscripts.py       |  6 ++-
 tests/unit/config/test_configfiles.py         |  4 +-
 tests/unit/keyinput/test_basekeyparser.py     |  7 ++-
 tests/unit/misc/test_ipc.py                   | 11 ++--
 tests/unit/misc/test_msgbox.py                |  7 ++-
 tests/unit/misc/test_utilcmds.py              |  4 +-
 tests/unit/scripts/test_check_coverage.py     |  4 +-
 tests/unit/utils/test_error.py                |  5 +-
 tests/unit/utils/test_jinja.py                |  2 +-
 tests/unit/utils/test_qtutils.py              |  7 ++-
 tests/unit/utils/test_standarddir.py          | 16 +++---
 tests/unit/utils/test_utils.py                |  4 +-
 tests/unit/utils/test_version.py              | 13 +++--
 33 files changed, 133 insertions(+), 139 deletions(-)

diff --git a/misc/qutebrowser.spec b/misc/qutebrowser.spec
index bcbd67405..e9ccc1619 100644
--- a/misc/qutebrowser.spec
+++ b/misc/qutebrowser.spec
@@ -5,6 +5,7 @@ import os
 
 sys.path.insert(0, os.getcwd())
 from scripts import setupcommon
+from qutebrowser import utils
 
 block_cipher = None
 
@@ -30,9 +31,9 @@ def get_data_files():
 setupcommon.write_git_file()
 
 
-if os.name == 'nt':
+if utils.is_windows:
     icon = 'icons/qutebrowser.ico'
-elif sys.platform == 'darwin':
+elif utils.is_mac:
     icon = 'icons/qutebrowser.icns'
 else:
     icon = None
diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py
index 5bb07f129..f1dcc19e8 100644
--- a/qutebrowser/browser/commands.py
+++ b/qutebrowser/browser/commands.py
@@ -20,7 +20,6 @@
 """Command dispatcher for TabbedBrowser."""
 
 import os
-import sys
 import os.path
 import shlex
 import functools
@@ -430,7 +429,7 @@ class CommandDispatcher:
             tab.printing.to_printer(diag.printer(), print_callback)
 
         diag = QPrintDialog(tab)
-        if sys.platform == 'darwin':
+        if utils.is_mac:
             # For some reason we get a segfault when using open() on macOS
             ret = diag.exec_()
             if ret == QDialog.Accepted:
diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py
index 9458e39d0..07e5c7c30 100644
--- a/qutebrowser/browser/downloads.py
+++ b/qutebrowser/browser/downloads.py
@@ -174,7 +174,7 @@ def transform_path(path):
 
     Returns None if the path is invalid on the current platform.
     """
-    if sys.platform != "win32":
+    if not utils.is_windows:
         return path
     path = utils.expand_windows_drive(path)
     # Drive dependent working directories are not supported, e.g.
diff --git a/qutebrowser/browser/webengine/webenginesettings.py b/qutebrowser/browser/webengine/webenginesettings.py
index 0bac53915..7b4ece0e8 100644
--- a/qutebrowser/browser/webengine/webenginesettings.py
+++ b/qutebrowser/browser/webengine/webenginesettings.py
@@ -28,7 +28,6 @@ Module attributes:
 """
 
 import os
-import sys
 import ctypes
 import ctypes.util
 
@@ -207,7 +206,7 @@ def init(args):
 
     # WORKAROUND for
     # https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/941826
-    if sys.platform == 'linux':
+    if utils.is_linux:
         ctypes.CDLL(ctypes.util.find_library("GL"), mode=ctypes.RTLD_GLOBAL)
 
     _init_profiles()
diff --git a/qutebrowser/browser/webkit/network/networkmanager.py b/qutebrowser/browser/webkit/network/networkmanager.py
index 42de3a65d..beaa690ca 100644
--- a/qutebrowser/browser/webkit/network/networkmanager.py
+++ b/qutebrowser/browser/webkit/network/networkmanager.py
@@ -58,7 +58,7 @@ def _is_secure_cipher(cipher):
         # https://codereview.qt-project.org/#/c/75943/
         return False
     # OpenSSL should already protect against this in a better way
-    elif cipher.keyExchangeMethod() == 'DH' and os.name == 'nt':
+    elif cipher.keyExchangeMethod() == 'DH' and utils.is_windows:
         # https://weakdh.org/
         return False
     elif cipher.encryptionMethod().upper().startswith('RC4'):
diff --git a/qutebrowser/browser/webkit/webkittab.py b/qutebrowser/browser/webkit/webkittab.py
index cf2156431..9a9daad77 100644
--- a/qutebrowser/browser/webkit/webkittab.py
+++ b/qutebrowser/browser/webkit/webkittab.py
@@ -19,7 +19,6 @@
 
 """Wrapper over our (QtWebKit) WebView."""
 
-import sys
 import functools
 import xml.etree.ElementTree
 
@@ -223,11 +222,11 @@ class WebKitCaret(browsertab.AbstractCaret):
     def move_to_end_of_word(self, count=1):
         if not self.selection_enabled:
             act = [QWebPage.MoveToNextWord]
-            if sys.platform == 'win32':  # pragma: no cover
+            if utils.is_windows:  # pragma: no cover
                 act.append(QWebPage.MoveToPreviousChar)
         else:
             act = [QWebPage.SelectNextWord]
-            if sys.platform == 'win32':  # pragma: no cover
+            if utils.is_windows:  # pragma: no cover
                 act.append(QWebPage.SelectPreviousChar)
         for _ in range(count):
             for a in act:
@@ -236,11 +235,11 @@ class WebKitCaret(browsertab.AbstractCaret):
     def move_to_next_word(self, count=1):
         if not self.selection_enabled:
             act = [QWebPage.MoveToNextWord]
-            if sys.platform != 'win32':  # pragma: no branch
+            if not utils.is_windows:  # pragma: no branch
                 act.append(QWebPage.MoveToNextChar)
         else:
             act = [QWebPage.SelectNextWord]
-            if sys.platform != 'win32':  # pragma: no branch
+            if not utils.is_windows:  # pragma: no branch
                 act.append(QWebPage.SelectNextChar)
         for _ in range(count):
             for a in act:
diff --git a/qutebrowser/browser/webkit/webview.py b/qutebrowser/browser/webkit/webview.py
index 5608995a4..4f1ff10c8 100644
--- a/qutebrowser/browser/webkit/webview.py
+++ b/qutebrowser/browser/webkit/webview.py
@@ -19,8 +19,6 @@
 
 """The main browser widgets."""
 
-import sys
-
 from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QUrl
 from PyQt5.QtGui import QPalette
 from PyQt5.QtWidgets import QStyleFactory
@@ -57,7 +55,7 @@ class WebView(QWebView):
 
     def __init__(self, *, win_id, tab_id, tab, private, parent=None):
         super().__init__(parent)
-        if sys.platform == 'darwin':
+        if utils.is_mac:
             # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-42948
             # See https://github.com/qutebrowser/qutebrowser/issues/462
             self.setStyle(QStyleFactory.create('Fusion'))
diff --git a/qutebrowser/commands/userscripts.py b/qutebrowser/commands/userscripts.py
index 5449f1598..10e509ce7 100644
--- a/qutebrowser/commands/userscripts.py
+++ b/qutebrowser/commands/userscripts.py
@@ -25,7 +25,7 @@ import tempfile
 
 from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QSocketNotifier
 
-from qutebrowser.utils import message, log, objreg, standarddir
+from qutebrowser.utils import message, log, objreg, standarddir, utils
 from qutebrowser.commands import runners
 from qutebrowser.config import config
 from qutebrowser.misc import guiprocess
@@ -406,9 +406,9 @@ def run_async(tab, cmd, *args, win_id, env, verbose=False):
                                 window=win_id)
     commandrunner = runners.CommandRunner(win_id, parent=tabbed_browser)
 
-    if os.name == 'posix':
+    if utils.is_posix:
         runner = _POSIXUserscriptRunner(tabbed_browser)
-    elif os.name == 'nt':  # pragma: no cover
+    elif utils.is_windows:  # pragma: no cover
         runner = _WindowsUserscriptRunner(tabbed_browser)
     else:  # pragma: no cover
         raise UnsupportedError
diff --git a/qutebrowser/misc/crashsignal.py b/qutebrowser/misc/crashsignal.py
index 393aa26f0..9a1b88942 100644
--- a/qutebrowser/misc/crashsignal.py
+++ b/qutebrowser/misc/crashsignal.py
@@ -40,7 +40,7 @@ from PyQt5.QtWidgets import QApplication, QDialog
 
 from qutebrowser.commands import cmdutils
 from qutebrowser.misc import earlyinit, crashdialog
-from qutebrowser.utils import usertypes, standarddir, log, objreg, debug
+from qutebrowser.utils import usertypes, standarddir, log, objreg, debug, utils
 
 
 @attr.s
@@ -312,7 +312,7 @@ class SignalHandler(QObject):
         self._orig_handlers[signal.SIGTERM] = signal.signal(
             signal.SIGTERM, self.interrupt)
 
-        if os.name == 'posix' and hasattr(signal, 'set_wakeup_fd'):
+        if utils.is_posix and hasattr(signal, 'set_wakeup_fd'):
             # pylint: disable=import-error,no-member,useless-suppression
             import fcntl
             read_fd, write_fd = os.pipe()
diff --git a/qutebrowser/misc/ipc.py b/qutebrowser/misc/ipc.py
index 562cc84cc..e308ac8a0 100644
--- a/qutebrowser/misc/ipc.py
+++ b/qutebrowser/misc/ipc.py
@@ -30,7 +30,7 @@ from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, Qt
 from PyQt5.QtNetwork import QLocalSocket, QLocalServer, QAbstractSocket
 
 import qutebrowser
-from qutebrowser.utils import log, usertypes, error, objreg, standarddir
+from qutebrowser.utils import log, usertypes, error, objreg, standarddir, utils
 
 
 CONNECT_TIMEOUT = 100  # timeout for connecting/disconnecting
@@ -51,7 +51,7 @@ def _get_socketname_windows(basedir):
 
 def _get_socketname(basedir):
     """Get a socketname to use."""
-    if os.name == 'nt':  # pragma: no cover
+    if utils.is_windows:  # pragma: no cover
         return _get_socketname_windows(basedir)
 
     parts_to_hash = [getpass.getuser()]
@@ -139,8 +139,6 @@ class IPCServer(QObject):
         _server: A QLocalServer to accept new connections.
         _socket: The QLocalSocket we're currently connected to.
         _socketname: The socketname to use.
-        _socketopts_ok: Set if using setSocketOptions is working with this
-                        OS/Qt version.
         _atime_timer: Timer to update the atime of the socket regularly.
 
     Signals:
@@ -169,7 +167,7 @@ class IPCServer(QObject):
         self._timer.setInterval(READ_TIMEOUT)
         self._timer.timeout.connect(self.on_timeout)
 
-        if os.name == 'nt':  # pragma: no cover
+        if utils.is_windows:  # pragma: no cover
             self._atime_timer = None
         else:
             self._atime_timer = usertypes.Timer(self, 'ipc-atime')
@@ -182,8 +180,7 @@ class IPCServer(QObject):
 
         self._socket = None
         self._old_socket = None
-        self._socketopts_ok = os.name == 'nt'
-        if self._socketopts_ok:  # pragma: no cover
+        if utils.is_windows:  # pragma: no cover
             # If we use setSocketOptions on Unix with Qt < 5.4, we get a
             # NameError while listening...
             log.ipc.debug("Calling setSocketOptions")
@@ -210,7 +207,7 @@ class IPCServer(QObject):
                 raise AddressInUseError(self._server)
             else:
                 raise ListenError(self._server)
-        if not self._socketopts_ok:  # pragma: no cover
+        if not utils.is_windows:  # pragma: no cover
             # If we use setSocketOptions on Unix with Qt < 5.4, we get a
             # NameError while listening.
             # (see b135569d5c6e68c735ea83f42e4baf51f7972281)
diff --git a/qutebrowser/utils/log.py b/qutebrowser/utils/log.py
index 3049d5dfe..fa0208ea7 100644
--- a/qutebrowser/utils/log.py
+++ b/qutebrowser/utils/log.py
@@ -409,6 +409,8 @@ def qt_message_handler(msg_type, context, msg):
         # https://codereview.qt-project.org/176831
         "QObject::disconnect: Unexpected null parameter",
     ]
+    # not using utils.is_mac here, because we can't be sure we can successfully
+    # import the utils module here.
     if sys.platform == 'darwin':
         suppressed_msgs += [
             'libpng warning: iCCP: known incorrect sRGB profile',
diff --git a/qutebrowser/utils/standarddir.py b/qutebrowser/utils/standarddir.py
index 468fba51e..d6ad7fc39 100644
--- a/qutebrowser/utils/standarddir.py
+++ b/qutebrowser/utils/standarddir.py
@@ -20,7 +20,6 @@
 """Utilities to get and initialize data/config paths."""
 
 import os
-import sys
 import shutil
 import os.path
 import contextlib
@@ -28,7 +27,7 @@ import contextlib
 from PyQt5.QtCore import QStandardPaths
 from PyQt5.QtWidgets import QApplication
 
-from qutebrowser.utils import log, debug, usertypes, message
+from qutebrowser.utils import log, debug, usertypes, message, utils
 
 # The cached locations
 _locations = {}
@@ -69,7 +68,7 @@ def _init_config(args):
     typ = QStandardPaths.ConfigLocation
     overridden, path = _from_args(typ, args)
     if not overridden:
-        if os.name == 'nt':
+        if utils.is_windows:
             app_data_path = _writable_location(
                 QStandardPaths.AppDataLocation)
             path = os.path.join(app_data_path, 'config')
@@ -80,7 +79,7 @@ def _init_config(args):
     _locations[Location.auto_config] = path
 
     # Override the normal (non-auto) config on macOS
-    if sys.platform == 'darwin':
+    if utils.is_mac:
         overridden, path = _from_args(typ, args)
         if not overridden:  # pragma: no branch
             path = os.path.expanduser('~/.' + APPNAME)
@@ -104,7 +103,7 @@ def _init_data(args):
     typ = QStandardPaths.DataLocation
     overridden, path = _from_args(typ, args)
     if not overridden:
-        if os.name == 'nt':
+        if utils.is_windows:
             app_data_path = _writable_location(QStandardPaths.AppDataLocation)
             path = os.path.join(app_data_path, 'data')
         else:
@@ -114,7 +113,7 @@ def _init_data(args):
 
     # system_data
     _locations.pop(Location.system_data, None)  # Remove old state
-    if sys.platform.startswith('linux'):
+    if utils.is_linux:
         path = '/usr/share/' + APPNAME
         if os.path.exists(path):
             _locations[Location.system_data] = path
@@ -139,7 +138,7 @@ def _init_cache(args):
     typ = QStandardPaths.CacheLocation
     overridden, path = _from_args(typ, args)
     if not overridden:
-        if os.name == 'nt':
+        if utils.is_windows:
             # Local, not Roaming!
             data_path = _writable_location(QStandardPaths.DataLocation)
             path = os.path.join(data_path, 'cache')
@@ -172,7 +171,7 @@ def download():
 
 def _init_runtime(args):
     """Initialize location for runtime data."""
-    if sys.platform.startswith('linux'):
+    if utils.is_linux:
         typ = QStandardPaths.RuntimeLocation
     else:
         # RuntimeLocation is a weird path on macOS and Windows.
@@ -312,9 +311,9 @@ def init(args):
     _init_dirs(args)
     _init_cachedir_tag()
     if args is not None and getattr(args, 'basedir', None) is None:
-        if sys.platform == 'darwin':  # pragma: no cover
+        if utils.is_mac:  # pragma: no cover
             _move_macos()
-        elif os.name == 'nt':  # pragma: no cover
+        elif utils.is_windows:  # pragma: no cover
             _move_windows()
 
 
diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py
index 12d85f608..23c442008 100644
--- a/qutebrowser/utils/utils.py
+++ b/qutebrowser/utils/utils.py
@@ -383,7 +383,7 @@ def keyevent_to_string(e):
         A name of the key (combination) as a string or
         None if only modifiers are pressed..
     """
-    if sys.platform == 'darwin':
+    if is_mac:
         # Qt swaps Ctrl/Meta on macOS, so we switch it back here so the user
         # can use it in the config as expected. See:
         # https://github.com/qutebrowser/qutebrowser/issues/110
diff --git a/qutebrowser/utils/version.py b/qutebrowser/utils/version.py
index 673590208..0f1b2233d 100644
--- a/qutebrowser/utils/version.py
+++ b/qutebrowser/utils/version.py
@@ -248,12 +248,12 @@ def _os_info():
     """
     lines = []
     releaseinfo = None
-    if sys.platform == 'linux':
+    if utils.is_linux:
         osver = ''
         releaseinfo = _release_info()
-    elif sys.platform == 'win32':
+    elif utils.is_windows:
         osver = ', '.join(platform.win32_ver())
-    elif sys.platform == 'darwin':
+    elif utils.is_mac:
         release, versioninfo, machine = platform.mac_ver()
         if all(not e for e in versioninfo):
             versioninfo = ''
diff --git a/scripts/dev/build_release.py b/scripts/dev/build_release.py
index d5c03ad02..a51c8f2b3 100755
--- a/scripts/dev/build_release.py
+++ b/scripts/dev/build_release.py
@@ -36,7 +36,8 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir,
                                 os.pardir))
 
 import qutebrowser
-from scripts import utils
+from qutebrowser.utils import utils
+from scripts import utils as scriptutils
 # from scripts.dev import update_3rdparty
 
 
@@ -70,7 +71,7 @@ def call_tox(toxenv, *args, python=sys.executable):
 
 def run_asciidoc2html(args):
     """Common buildsteps used for all OS'."""
-    utils.print_title("Running asciidoc2html.py")
+    scriptutils.print_title("Running asciidoc2html.py")
     if args.asciidoc is not None:
         a2h_args = ['--asciidoc'] + args.asciidoc
     else:
@@ -127,7 +128,7 @@ def patch_mac_app():
 
 def build_mac():
     """Build macOS .dmg/.app."""
-    utils.print_title("Cleaning up...")
+    scriptutils.print_title("Cleaning up...")
     for f in ['wc.dmg', 'template.dmg']:
         try:
             os.remove(f)
@@ -135,20 +136,20 @@ def build_mac():
             pass
     for d in ['dist', 'build']:
         shutil.rmtree(d, ignore_errors=True)
-    utils.print_title("Updating 3rdparty content")
+    scriptutils.print_title("Updating 3rdparty content")
     # Currently disabled because QtWebEngine has no pdfjs support
     # update_3rdparty.run(ace=False, pdfjs=True, fancy_dmg=False)
-    utils.print_title("Building .app via pyinstaller")
+    scriptutils.print_title("Building .app via pyinstaller")
     call_tox('pyinstaller', '-r')
-    utils.print_title("Patching .app")
+    scriptutils.print_title("Patching .app")
     patch_mac_app()
-    utils.print_title("Building .dmg")
+    scriptutils.print_title("Building .dmg")
     subprocess.check_call(['make', '-f', 'scripts/dev/Makefile-dmg'])
 
     dmg_name = 'qutebrowser-{}.dmg'.format(qutebrowser.__version__)
     os.rename('qutebrowser.dmg', dmg_name)
 
-    utils.print_title("Running smoke test")
+    scriptutils.print_title("Running smoke test")
 
     try:
         with tempfile.TemporaryDirectory() as tmpdir:
@@ -177,11 +178,11 @@ def patch_windows(out_dir):
 
 def build_windows():
     """Build windows executables/setups."""
-    utils.print_title("Updating 3rdparty content")
+    scriptutils.print_title("Updating 3rdparty content")
     # Currently disabled because QtWebEngine has no pdfjs support
     # update_3rdparty.run(ace=False, pdfjs=True, fancy_dmg=False)
 
-    utils.print_title("Building Windows binaries")
+    scriptutils.print_title("Building Windows binaries")
     parts = str(sys.version_info.major), str(sys.version_info.minor)
     ver = ''.join(parts)
     python_x86 = r'C:\Python{}-32\python.exe'.format(ver)
@@ -194,19 +195,19 @@ def build_windows():
 
     artifacts = []
 
-    utils.print_title("Running pyinstaller 32bit")
+    scriptutils.print_title("Running pyinstaller 32bit")
     _maybe_remove(out_32)
     call_tox('pyinstaller', '-r', python=python_x86)
     shutil.move(out_pyinstaller, out_32)
     patch_windows(out_32)
 
-    utils.print_title("Running pyinstaller 64bit")
+    scriptutils.print_title("Running pyinstaller 64bit")
     _maybe_remove(out_64)
     call_tox('pyinstaller', '-r', python=python_x64)
     shutil.move(out_pyinstaller, out_64)
     patch_windows(out_64)
 
-    utils.print_title("Building installers")
+    scriptutils.print_title("Building installers")
     subprocess.check_call(['makensis.exe',
                            '/DVERSION={}'.format(qutebrowser.__version__),
                            'misc/qutebrowser.nsi'])
@@ -227,12 +228,12 @@ def build_windows():
          'Windows 64bit installer'),
     ]
 
-    utils.print_title("Running 32bit smoke test")
+    scriptutils.print_title("Running 32bit smoke test")
     smoke_test(os.path.join(out_32, 'qutebrowser.exe'))
-    utils.print_title("Running 64bit smoke test")
+    scriptutils.print_title("Running 64bit smoke test")
     smoke_test(os.path.join(out_64, 'qutebrowser.exe'))
 
-    utils.print_title("Zipping 32bit standalone...")
+    scriptutils.print_title("Zipping 32bit standalone...")
     name = 'qutebrowser-{}-windows-standalone-win32'.format(
         qutebrowser.__version__)
     shutil.make_archive(name, 'zip', 'dist', os.path.basename(out_32))
@@ -240,7 +241,7 @@ def build_windows():
                       'application/zip',
                       'Windows 32bit standalone'))
 
-    utils.print_title("Zipping 64bit standalone...")
+    scriptutils.print_title("Zipping 64bit standalone...")
     name = 'qutebrowser-{}-windows-standalone-amd64'.format(
         qutebrowser.__version__)
     shutil.make_archive(name, 'zip', 'dist', os.path.basename(out_64))
@@ -253,7 +254,7 @@ def build_windows():
 
 def build_sdist():
     """Build an sdist and list the contents."""
-    utils.print_title("Building sdist")
+    scriptutils.print_title("Building sdist")
 
     _maybe_remove('dist')
 
@@ -276,10 +277,10 @@ def build_sdist():
 
     assert '.pyc' not in by_ext
 
-    utils.print_title("sdist contents")
+    scriptutils.print_title("sdist contents")
 
     for ext, files in sorted(by_ext.items()):
-        utils.print_subtitle(ext)
+        scriptutils.print_subtitle(ext)
         print('\n'.join(files))
 
     filename = 'qutebrowser-{}.tar.gz'.format(qutebrowser.__version__)
@@ -308,7 +309,7 @@ def github_upload(artifacts, tag):
         tag: The name of the release tag
     """
     import github3
-    utils.print_title("Uploading to github...")
+    scriptutils.print_title("Uploading to github...")
 
     token = read_github_token()
     gh = github3.login(token=token)
@@ -343,7 +344,7 @@ def main():
     parser.add_argument('--upload', help="Tag to upload the release for",
                         nargs=1, required=False, metavar='TAG')
     args = parser.parse_args()
-    utils.change_cwd()
+    scriptutils.change_cwd()
 
     upload_to_pypi = False
 
@@ -353,7 +354,7 @@ def main():
         import github3  # pylint: disable=unused-variable
         read_github_token()
 
-    if os.name == 'nt':
+    if utils.is_windows:
         if sys.maxsize > 2**32:
             # WORKAROUND
             print("Due to a python/Windows bug, this script needs to be run ")
@@ -364,7 +365,7 @@ def main():
             sys.exit(1)
         run_asciidoc2html(args)
         artifacts = build_windows()
-    elif sys.platform == 'darwin':
+    elif utils.is_mac:
         run_asciidoc2html(args)
         artifacts = build_mac()
     else:
@@ -372,7 +373,7 @@ def main():
         upload_to_pypi = True
 
     if args.upload is not None:
-        utils.print_title("Press enter to release...")
+        scriptutils.print_title("Press enter to release...")
         input()
         github_upload(artifacts, args.upload[0])
         if upload_to_pypi:
diff --git a/scripts/dev/check_coverage.py b/scripts/dev/check_coverage.py
index dfd336d16..aa5072536 100644
--- a/scripts/dev/check_coverage.py
+++ b/scripts/dev/check_coverage.py
@@ -32,7 +32,8 @@ import attr
 sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir,
                                 os.pardir))
 
-from scripts import utils
+from scripts import utils as scriptutils
+from qutebrowser.utils import utils
 
 
 @attr.s
@@ -207,7 +208,7 @@ def _get_filename(filename):
 
 def check(fileobj, perfect_files):
     """Main entry point which parses/checks coverage.xml if applicable."""
-    if sys.platform != 'linux':
+    if not utils.is_linux:
         raise Skipped("on non-Linux system.")
     elif '-k' in sys.argv[1:]:
         raise Skipped("because -k is given.")
@@ -272,7 +273,7 @@ def main_check():
     if messages:
         print()
         print()
-        utils.print_title("Coverage check failed")
+        scriptutils.print_title("Coverage check failed")
         for msg in messages:
             print(msg.text)
         print()
@@ -323,7 +324,7 @@ def main_check_all():
 
 
 def main():
-    utils.change_cwd()
+    scriptutils.change_cwd()
     if '--check-all' in sys.argv:
         return main_check_all()
     else:
diff --git a/tests/conftest.py b/tests/conftest.py
index b12f85d6e..0ba48e330 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -35,7 +35,7 @@ from helpers import logfail
 from helpers.logfail import fail_on_logging
 from helpers.messagemock import message_mock
 from helpers.fixtures import *
-from qutebrowser.utils import qtutils, standarddir, usertypes
+from qutebrowser.utils import qtutils, standarddir, usertypes, utils
 from qutebrowser.misc import objects
 
 import qutebrowser.app  # To register commands
@@ -50,18 +50,18 @@ hypothesis.settings.load_profile('default')
 def _apply_platform_markers(config, item):
     """Apply a skip marker to a given item."""
     markers = [
-        ('posix', os.name != 'posix', "Requires a POSIX os"),
-        ('windows', os.name != 'nt', "Requires Windows"),
-        ('linux', not sys.platform.startswith('linux'), "Requires Linux"),
-        ('mac', sys.platform != 'darwin', "Requires macOS"),
-        ('not_mac', sys.platform == 'darwin', "Skipped on macOS"),
+        ('posix', not utils.is_posix, "Requires a POSIX os"),
+        ('windows', not utils.is_mac, "Requires Windows"),
+        ('linux', not utils.is_linux, "Requires Linux"),
+        ('mac', not utils.is_mac, "Requires macOS"),
+        ('not_mac', utils.is_mac, "Skipped on macOS"),
         ('not_frozen', getattr(sys, 'frozen', False),
             "Can't be run when frozen"),
         ('frozen', not getattr(sys, 'frozen', False),
             "Can only run when frozen"),
         ('ci', 'CI' not in os.environ, "Only runs on CI."),
         ('no_ci', 'CI' in os.environ, "Skipped on CI."),
-        ('issue2478', os.name == 'nt' and config.webengine,
+        ('issue2478', utils.is_windows and config.webengine,
          "Broken with QtWebEngine on Windows"),
     ]
 
@@ -181,7 +181,7 @@ def check_display(request):
             request.config.xvfb is not None):
         raise Exception("Xvfb is running on buildbot!")
 
-    if sys.platform == 'linux' and not os.environ.get('DISPLAY', ''):
+    if utils.is_linux and not os.environ.get('DISPLAY', ''):
         raise Exception("No display and no Xvfb available!")
 
 
diff --git a/tests/end2end/conftest.py b/tests/end2end/conftest.py
index 1fd6eb874..51a0497bf 100644
--- a/tests/end2end/conftest.py
+++ b/tests/end2end/conftest.py
@@ -38,7 +38,7 @@ from end2end.fixtures.webserver import server, server_after_test, ssl_server
 from end2end.fixtures.quteprocess import (quteproc_process, quteproc,
                                           quteproc_new)
 from end2end.fixtures.testprocess import pytest_runtest_makereport
-from qutebrowser.utils import qtutils
+from qutebrowser.utils import qtutils, utils
 
 
 def pytest_configure(config):
@@ -144,7 +144,7 @@ def pytest_collection_modifyitems(config, items):
         ('qtwebengine_flaky', 'Flaky with QtWebEngine', pytest.mark.skipif,
          config.webengine),
         ('qtwebengine_mac_xfail', 'Fails on macOS with QtWebEngine',
-         pytest.mark.xfail, config.webengine and sys.platform == 'darwin'),
+         pytest.mark.xfail, config.webengine and utils.is_mac),
     ]
 
     for item in items:
diff --git a/tests/end2end/features/conftest.py b/tests/end2end/features/conftest.py
index 52dfe616c..7f5b4e2a6 100644
--- a/tests/end2end/features/conftest.py
+++ b/tests/end2end/features/conftest.py
@@ -31,9 +31,9 @@ import textwrap
 import pytest
 import pytest_bdd as bdd
 
-from qutebrowser.utils import log
+from qutebrowser.utils import log, utils
 from qutebrowser.browser import pdfjs
-from helpers import utils
+from helpers import utils as testutils
 
 
 def _get_echo_exe_path():
@@ -42,8 +42,9 @@ def _get_echo_exe_path():
     Return:
         Path to the "echo"-utility.
     """
-    if sys.platform == "win32":
-        return os.path.join(utils.abs_datapath(), 'userscripts', 'echo.bat')
+    if utils.is_windows:
+        return os.path.join(testutils.abs_datapath(), 'userscripts',
+                            'echo.bat')
     else:
         return 'echo'
 
@@ -255,7 +256,7 @@ def run_command(quteproc, server, tmpdir, command):
         invalid = False
 
     command = command.replace('(port)', str(server.port))
-    command = command.replace('(testdata)', utils.abs_datapath())
+    command = command.replace('(testdata)', testutils.abs_datapath())
     command = command.replace('(tmpdir)', str(tmpdir))
     command = command.replace('(dirsep)', os.sep)
     command = command.replace('(echo-exe)', _get_echo_exe_path())
@@ -349,7 +350,7 @@ def hint(quteproc, args):
 
 @bdd.when(bdd.parsers.parse('I hint with args "{args}" and follow {letter}'))
 def hint_and_follow(quteproc, args, letter):
-    args = args.replace('(testdata)', utils.abs_datapath())
+    args = args.replace('(testdata)', testutils.abs_datapath())
     quteproc.send_cmd(':hint {}'.format(args))
     quteproc.wait_for(message='hints: *')
     quteproc.send_cmd(':follow-hint {}'.format(letter))
@@ -502,7 +503,7 @@ def check_header(quteproc, header, value):
         assert header not in data['headers']
     else:
         actual = data['headers'][header]
-        assert utils.pattern_match(pattern=value, value=actual)
+        assert testutils.pattern_match(pattern=value, value=actual)
 
 
 @bdd.then(bdd.parsers.parse('the page should contain the html "{text}"'))
diff --git a/tests/unit/browser/webkit/network/test_filescheme.py b/tests/unit/browser/webkit/network/test_filescheme.py
index 0cc485556..13700a103 100644
--- a/tests/unit/browser/webkit/network/test_filescheme.py
+++ b/tests/unit/browser/webkit/network/test_filescheme.py
@@ -26,7 +26,7 @@ from PyQt5.QtCore import QUrl
 from PyQt5.QtNetwork import QNetworkRequest
 
 from qutebrowser.browser.webkit.network import filescheme
-from qutebrowser.utils import urlutils
+from qutebrowser.utils import urlutils, utils
 
 
 @pytest.mark.parametrize('create_file, create_dir, filterfunc, expected', [
@@ -228,10 +228,7 @@ class TestDirbrowserHtml:
         assert parsed.folders == [bar_item]
 
     def test_root_dir(self, tmpdir, parser):
-        if os.name == 'nt':
-            root_dir = 'C:\\'
-        else:
-            root_dir = '/'
+        root_dir = 'C:\\' if utils.is_windows else '/'
         parsed = parser(root_dir)
         assert not parsed.parent
 
diff --git a/tests/unit/commands/test_userscripts.py b/tests/unit/commands/test_userscripts.py
index 7829fbca9..be514e788 100644
--- a/tests/unit/commands/test_userscripts.py
+++ b/tests/unit/commands/test_userscripts.py
@@ -27,6 +27,7 @@ import pytest
 from PyQt5.QtCore import QFileSystemWatcher
 
 from qutebrowser.commands import userscripts
+from qutebrowser.utils import utils
 
 
 @pytest.mark.posix
@@ -60,7 +61,7 @@ class TestQtFIFOReader:
     userscripts._WindowsUserscriptRunner,
 ])
 def runner(request, runtime_tmpdir):
-    if (os.name != 'posix' and
+    if (not utils.is_posix and
             request.param is userscripts._POSIXUserscriptRunner):
         pytest.skip("Requires a POSIX os")
     else:
@@ -246,7 +247,8 @@ def test_unicode_error(caplog, qtbot, py_proc, runner):
 
 
 def test_unsupported(monkeypatch, tabbed_browser_stubs):
-    monkeypatch.setattr(userscripts.os, 'name', 'toaster')
+    monkeypatch.setattr(userscripts.utils, 'is_posix', False)
+    monkeypatch.setattr(userscripts.utils, 'is_windows', False)
     with pytest.raises(userscripts.UnsupportedError, match="Userscripts are "
                        "not supported on this platform!"):
         userscripts.run_async(tab=None, cmd=None, win_id=0, env=None)
diff --git a/tests/unit/config/test_configfiles.py b/tests/unit/config/test_configfiles.py
index 1fc939373..b7dba3b18 100644
--- a/tests/unit/config/test_configfiles.py
+++ b/tests/unit/config/test_configfiles.py
@@ -19,11 +19,11 @@
 """Tests for qutebrowser.config.configfiles."""
 
 import os
-import sys
 
 import pytest
 
 from qutebrowser.config import config, configfiles, configexc
+from qutebrowser.utils import utils
 
 from PyQt5.QtCore import QSettings
 
@@ -343,7 +343,7 @@ def test_init(init_patch, config_tmpdir):
     configfiles.init()
 
     # Make sure qsettings land in a subdir
-    if sys.platform == 'linux':
+    if utils.is_linux:
         settings = QSettings()
         settings.setValue("hello", "world")
         settings.sync()
diff --git a/tests/unit/keyinput/test_basekeyparser.py b/tests/unit/keyinput/test_basekeyparser.py
index 18f04266d..e7131f92c 100644
--- a/tests/unit/keyinput/test_basekeyparser.py
+++ b/tests/unit/keyinput/test_basekeyparser.py
@@ -19,7 +19,6 @@
 
 """Tests for BaseKeyParser."""
 
-import sys
 import logging
 from unittest import mock
 
@@ -166,7 +165,7 @@ class TestSpecialKeys:
         keyparser._read_config('prompt')
 
     def test_valid_key(self, fake_keyevent_factory, keyparser):
-        if sys.platform == 'darwin':
+        if utils.is_mac:
             modifier = Qt.MetaModifier
         else:
             modifier = Qt.ControlModifier
@@ -176,7 +175,7 @@ class TestSpecialKeys:
             'message-info ctrla', keyparser.Type.special, None)
 
     def test_valid_key_count(self, fake_keyevent_factory, keyparser):
-        if sys.platform == 'darwin':
+        if utils.is_mac:
             modifier = Qt.MetaModifier
         else:
             modifier = Qt.ControlModifier
@@ -210,7 +209,7 @@ class TestKeyChain:
         keyparser._read_config('prompt')
 
     def test_valid_special_key(self, fake_keyevent_factory, keyparser):
-        if sys.platform == 'darwin':
+        if utils.is_mac:
             modifier = Qt.MetaModifier
         else:
             modifier = Qt.ControlModifier
diff --git a/tests/unit/misc/test_ipc.py b/tests/unit/misc/test_ipc.py
index 2b7c17e62..d8024b207 100644
--- a/tests/unit/misc/test_ipc.py
+++ b/tests/unit/misc/test_ipc.py
@@ -19,7 +19,6 @@
 
 """Tests for qutebrowser.misc.ipc."""
 
-import sys
 import os
 import getpass
 import logging
@@ -35,7 +34,7 @@ from PyQt5.QtTest import QSignalSpy
 
 import qutebrowser
 from qutebrowser.misc import ipc
-from qutebrowser.utils import objreg, standarddir
+from qutebrowser.utils import objreg, standarddir, utils
 from helpers import stubs
 
 
@@ -228,11 +227,11 @@ class TestSocketName:
         We probably would adjust the code first to make it work on that
         platform.
         """
-        if os.name == 'nt':
+        if utils.is_windows:
             pass
-        elif sys.platform == 'darwin':
+        elif utils.is_mac:
             pass
-        elif sys.platform.startswith('linux'):
+        elif utils.is_linux:
             pass
         else:
             raise Exception("Unexpected platform!")
@@ -431,7 +430,7 @@ class TestHandleConnection:
 
 @pytest.fixture
 def connected_socket(qtbot, qlocalsocket, ipc_server):
-    if sys.platform == 'darwin':
+    if utils.is_mac:
         pytest.skip("Skipping connected_socket test - "
                     "https://github.com/qutebrowser/qutebrowser/issues/1045")
     ipc_server.listen()
diff --git a/tests/unit/misc/test_msgbox.py b/tests/unit/misc/test_msgbox.py
index 2c1268bd8..5f0058dea 100644
--- a/tests/unit/misc/test_msgbox.py
+++ b/tests/unit/misc/test_msgbox.py
@@ -18,11 +18,10 @@
 
 """Tests for qutebrowser.misc.msgbox."""
 
-import sys
-
 import pytest
 
 from qutebrowser.misc import msgbox
+from qutebrowser.utils import utils
 
 from PyQt5.QtCore import Qt
 from PyQt5.QtWidgets import QMessageBox, QWidget
@@ -40,7 +39,7 @@ def test_attributes(qtbot):
     box = msgbox.msgbox(parent=parent, title=title, text=text, icon=icon,
                         buttons=buttons)
     qtbot.add_widget(box)
-    if sys.platform != 'darwin':
+    if not utils.is_mac:
         assert box.windowTitle() == title
     assert box.icon() == icon
     assert box.standardButtons() == buttons
@@ -82,7 +81,7 @@ def test_finished_signal(qtbot):
 def test_information(qtbot):
     box = msgbox.information(parent=None, title='foo', text='bar')
     qtbot.add_widget(box)
-    if sys.platform != 'darwin':
+    if not utils.is_mac:
         assert box.windowTitle() == 'foo'
     assert box.text() == 'bar'
     assert box.icon() == QMessageBox.Information
diff --git a/tests/unit/misc/test_utilcmds.py b/tests/unit/misc/test_utilcmds.py
index 238244617..dfb99115d 100644
--- a/tests/unit/misc/test_utilcmds.py
+++ b/tests/unit/misc/test_utilcmds.py
@@ -21,7 +21,6 @@
 
 import contextlib
 import logging
-import os
 import signal
 import time
 
@@ -29,6 +28,7 @@ import pytest
 
 from qutebrowser.misc import utilcmds
 from qutebrowser.commands import cmdexc
+from qutebrowser.utils import utils
 
 
 @contextlib.contextmanager
@@ -45,7 +45,7 @@ def test_debug_crash_exception():
         utilcmds.debug_crash(typ='exception')
 
 
-@pytest.mark.skipif(os.name == 'nt',
+@pytest.mark.skipif(utils.is_windows,
                     reason="current CPython/win can't recover from SIGSEGV")
 def test_debug_crash_segfault():
     """Verify that debug_crash crashes as intended."""
diff --git a/tests/unit/scripts/test_check_coverage.py b/tests/unit/scripts/test_check_coverage.py
index 440c743cf..f80dcba44 100644
--- a/tests/unit/scripts/test_check_coverage.py
+++ b/tests/unit/scripts/test_check_coverage.py
@@ -207,8 +207,8 @@ def test_skipped_args(covtest, args, reason):
     covtest.check_skipped(args, reason)
 
 
-def test_skipped_windows(covtest, monkeypatch):
-    monkeypatch.setattr(check_coverage.sys, 'platform', 'toaster')
+def test_skipped_non_linux(covtest, monkeypatch):
+    monkeypatch.setattr(check_coverage.utils, 'is_linux', False)
     covtest.check_skipped([], "on non-Linux system.")
 
 
diff --git a/tests/unit/utils/test_error.py b/tests/unit/utils/test_error.py
index 4f4905365..47a1c52d9 100644
--- a/tests/unit/utils/test_error.py
+++ b/tests/unit/utils/test_error.py
@@ -18,12 +18,11 @@
 
 """Tests for qutebrowser.utils.error."""
 
-import sys
 import logging
 
 import pytest
 
-from qutebrowser.utils import error
+from qutebrowser.utils import error, utils
 from qutebrowser.misc import ipc
 
 from PyQt5.QtCore import QTimer
@@ -84,7 +83,7 @@ def test_err_windows(qtbot, qapp, fake_args, pre_text, post_text, expected):
         w = qapp.activeModalWidget()
         try:
             qtbot.add_widget(w)
-            if sys.platform != 'darwin':
+            if not utils.is_mac:
                 assert w.windowTitle() == 'title'
             assert w.icon() == QMessageBox.Critical
             assert w.standardButtons() == QMessageBox.Ok
diff --git a/tests/unit/utils/test_jinja.py b/tests/unit/utils/test_jinja.py
index c2a72de1a..1278d7bc1 100644
--- a/tests/unit/utils/test_jinja.py
+++ b/tests/unit/utils/test_jinja.py
@@ -89,7 +89,7 @@ def test_resource_url():
 
     path = url.path()
 
-    if os.name == "nt":
+    if utils.is_windows:
         path = path.lstrip('/')
         path = path.replace('/', os.sep)
 
diff --git a/tests/unit/utils/test_qtutils.py b/tests/unit/utils/test_qtutils.py
index f3c1afc04..8045bb0d3 100644
--- a/tests/unit/utils/test_qtutils.py
+++ b/tests/unit/utils/test_qtutils.py
@@ -21,7 +21,6 @@
 
 import io
 import os
-import sys
 import os.path
 import unittest
 import unittest.mock
@@ -36,7 +35,7 @@ import pytest
 from PyQt5.QtCore import (QDataStream, QPoint, QUrl, QByteArray, QIODevice,
                           QTimer, QBuffer, QFile, QProcess, QFileDevice)
 
-from qutebrowser.utils import qtutils
+from qutebrowser.utils import qtutils, utils
 import overflow_test_cases
 
 
@@ -458,13 +457,13 @@ class TestSavefileOpen:
         with qtutils.savefile_open(str(filename)) as f:
             f.write('foo\nbar\nbaz')
         data = filename.read_binary()
-        if os.name == 'nt':
+        if utils.is_windows:
             assert data == b'foo\r\nbar\r\nbaz'
         else:
             assert data == b'foo\nbar\nbaz'
 
 
-if test_file is not None and sys.platform != 'darwin':
+if test_file is not None and not utils.is_mac:
     # If we were able to import Python's test_file module, we run some code
     # here which defines unittest TestCases to run the python tests over
     # PyQIODevice.
diff --git a/tests/unit/utils/test_standarddir.py b/tests/unit/utils/test_standarddir.py
index 5230c9c78..b3daec643 100644
--- a/tests/unit/utils/test_standarddir.py
+++ b/tests/unit/utils/test_standarddir.py
@@ -32,7 +32,7 @@ import attr
 from PyQt5.QtCore import QStandardPaths
 import pytest
 
-from qutebrowser.utils import standarddir
+from qutebrowser.utils import standarddir, utils
 
 
 # Use a different application name for tests to make sure we don't change real
@@ -80,7 +80,7 @@ def test_unset_organization_no_qapp(monkeypatch):
 
 def test_fake_mac_config(tmpdir, monkeypatch):
     """Test standardir.config on a fake Mac."""
-    monkeypatch.setattr(sys, 'platform', 'darwin')
+    monkeypatch.setattr(utils, 'is_mac', True)
     monkeypatch.setenv('HOME', str(tmpdir))
     expected = str(tmpdir) + '/.qute_test'  # always with /
     standarddir._init_config(args=None)
@@ -91,7 +91,7 @@ def test_fake_mac_config(tmpdir, monkeypatch):
 @pytest.mark.not_mac
 def test_fake_windows(tmpdir, monkeypatch, what):
     """Make sure the config/data/cache dirs are correct on a fake Windows."""
-    monkeypatch.setattr(os, 'name', 'nt')
+    monkeypatch.setattr(standarddir.utils, 'is_windows', True)
     monkeypatch.setattr(standarddir.QStandardPaths, 'writableLocation',
                         lambda typ: str(tmpdir / APPNAME))
 
@@ -175,7 +175,7 @@ class TestStandardDir:
 
     def test_runtimedir_empty_tempdir(self, monkeypatch, tmpdir):
         """With an empty tempdir on non-Linux, we should raise."""
-        monkeypatch.setattr(standarddir.sys, 'platform', 'nt')
+        monkeypatch.setattr(standarddir.utils, 'is_linux', False)
         monkeypatch.setattr(standarddir.QStandardPaths, 'writableLocation',
                             lambda typ: '')
         with pytest.raises(standarddir.EmptyValueError):
@@ -294,7 +294,7 @@ class TestCreatingDir:
 
         assert basedir.exists()
 
-        if os.name == 'posix':
+        if utils.is_posix:
             assert basedir.stat().mode & 0o777 == 0o700
 
     @pytest.mark.parametrize('typ', DIR_TYPES)
@@ -326,7 +326,7 @@ class TestSystemData:
 
     def test_system_datadir_exist_linux(self, monkeypatch):
         """Test that /usr/share/qute_test is used if path exists."""
-        monkeypatch.setattr('sys.platform', "linux")
+        monkeypatch.setattr(standarddir.utils, 'is_linux', True)
         monkeypatch.setattr(os.path, 'exists', lambda path: True)
         standarddir._init_dirs()
         assert standarddir.data(system=True) == "/usr/share/qute_test"
@@ -493,10 +493,10 @@ def test_init(mocker, tmpdir, args_kind):
 
     assert standarddir._locations != {}
     if args_kind == 'normal':
-        if sys.platform == 'darwin':
+        if utils.is_mac:
             assert not m_windows.called
             assert m_mac.called
-        elif os.name == 'nt':
+        elif utils.is_windows:
             assert m_windows.called
             assert not m_mac.called
         else:
diff --git a/tests/unit/utils/test_utils.py b/tests/unit/utils/test_utils.py
index 623f77cc7..e0be5fdb8 100644
--- a/tests/unit/utils/test_utils.py
+++ b/tests/unit/utils/test_utils.py
@@ -355,7 +355,7 @@ class TestKeyEventToString:
     def test_key_and_modifier(self, fake_keyevent_factory):
         """Test with key and modifier pressed."""
         evt = fake_keyevent_factory(key=Qt.Key_A, modifiers=Qt.ControlModifier)
-        expected = 'meta+a' if sys.platform == 'darwin' else 'ctrl+a'
+        expected = 'meta+a' if utils.is_mac else 'ctrl+a'
         assert utils.keyevent_to_string(evt) == expected
 
     def test_key_and_modifiers(self, fake_keyevent_factory):
@@ -367,7 +367,7 @@ class TestKeyEventToString:
 
     def test_mac(self, monkeypatch, fake_keyevent_factory):
         """Test with a simulated mac."""
-        monkeypatch.setattr(sys, 'platform', 'darwin')
+        monkeypatch.setattr(utils, 'is_mac', True)
         evt = fake_keyevent_factory(key=Qt.Key_A, modifiers=Qt.ControlModifier)
         assert utils.keyevent_to_string(evt) == 'meta+a'
 
diff --git a/tests/unit/utils/test_version.py b/tests/unit/utils/test_version.py
index c3243862b..7c60d3d1e 100644
--- a/tests/unit/utils/test_version.py
+++ b/tests/unit/utils/test_version.py
@@ -36,7 +36,7 @@ import attr
 import pytest
 
 import qutebrowser
-from qutebrowser.utils import version, usertypes
+from qutebrowser.utils import version, usertypes, utils
 from qutebrowser.browser import pdfjs
 
 
@@ -333,7 +333,7 @@ class TestGitStrSubprocess:
                 'GIT_COMMITTER_EMAIL': 'mail@qutebrowser.org',
                 'GIT_COMMITTER_DATE': 'Thu  1 Jan 01:00:00 CET 1970',
             })
-            if os.name == 'nt':
+            if utils.is_windows:
                 # If we don't call this with shell=True it might fail under
                 # some environments on Windows...
                 # http://bugs.python.org/issue24493
@@ -696,15 +696,18 @@ class TestOsInfo:
             mac_ver: The tuple to set platform.mac_ver() to.
             mac_ver_str: The expected Mac version string in version._os_info().
         """
-        monkeypatch.setattr(version.sys, 'platform', 'darwin')
+        monkeypatch.setattr(version.utils, 'is_linux', False)
+        monkeypatch.setattr(version.utils, 'is_windows', False)
+        monkeypatch.setattr(version.utils, 'is_mac', True)
         monkeypatch.setattr(version.platform, 'mac_ver', lambda: mac_ver)
         ret = version._os_info()
         expected = ['OS Version: {}'.format(mac_ver_str)]
         assert ret == expected
 
     def test_unknown_fake(self, monkeypatch):
-        """Test with a fake unknown sys.platform."""
-        monkeypatch.setattr(version.sys, 'platform', 'toaster')
+        """Test with a fake unknown platform."""
+        for name in ['is_mac', 'is_windows', 'is_linux']:
+            monkeypatch.setattr(version.utils, name, False)
         ret = version._os_info()
         expected = ['OS Version: ?']
         assert ret == expected