diff --git a/run_unittests.py b/run_unittests.py
index e0b96f128..3facf4960 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -18,15 +18,21 @@ import shlex
 import subprocess
 import re, json
 import tempfile
-import pathlib
 import unittest, os, sys, shutil, time
 from glob import glob
+from pathlib import PurePath
 import mesonbuild.compilers
 import mesonbuild.environment
 import mesonbuild.mesonlib
+from mesonbuild.mesonlib import is_windows
 from mesonbuild.environment import detect_ninja, Environment
 from mesonbuild.dependencies import PkgConfigDependency
 
+if is_windows():
+    exe_suffix = '.exe'
+else:
+    exe_suffix = ''
+
 def get_soname(fname):
     # HACK, fix to not use shell.
     raw_out = subprocess.check_output(['readelf', '-a', fname],
@@ -172,7 +178,7 @@ class InternalTests(unittest.TestCase):
         self.assertEqual(commonpath(['blam', 'bin']), '')
         prefix = '/some/path/to/prefix'
         libdir = '/some/path/to/prefix/libdir'
-        self.assertEqual(commonpath([prefix, libdir]), str(pathlib.PurePath(prefix)))
+        self.assertEqual(commonpath([prefix, libdir]), str(PurePath(prefix)))
 
 
 class BasePlatformTests(unittest.TestCase):
@@ -220,8 +226,10 @@ class BasePlatformTests(unittest.TestCase):
         self._run(self.meson_command + args + extra_args)
         self.privatedir = os.path.join(self.builddir, 'meson-private')
 
-    def build(self):
-        self._run(self.ninja_command)
+    def build(self, extra_args=None):
+        if extra_args is None:
+            extra_args = []
+        self._run(self.ninja_command + extra_args)
 
     def run_tests(self):
         self._run(self.ninja_command + ['test'])
@@ -274,6 +282,21 @@ class BasePlatformTests(unittest.TestCase):
                                       universal_newlines=True)
         return json.loads(out)
 
+    def assertPathEqual(self, path1, path2):
+        '''
+        Handles a lot of platform-specific quirks related to paths such as
+        separator, case-sensitivity, etc.
+        '''
+        self.assertEqual(PurePath(path1), PurePath(path2))
+
+    def assertPathBasenameEqual(self, path, basename):
+        msg = '{!r} does not end with {!r}'.format(path, basename)
+        # We cannot use os.path.basename because it returns '' when the path
+        # ends with '/' for some silly reason. This is not how the UNIX utility
+        # `basename` works.
+        path_basename = PurePath(path).parts[-1]
+        self.assertEqual(PurePath(path_basename), PurePath(basename), msg)
+
 
 class AllPlatformTests(BasePlatformTests):
     '''
@@ -372,6 +395,174 @@ class AllPlatformTests(BasePlatformTests):
         # and the object must have changed
         self.assertNotEqual(before, after)
 
+    def test_static_compile_order(self):
+        '''
+        Test that the order of files in a compiler command-line while compiling
+        and linking statically is deterministic. This can't be an ordinary test
+        case because we need to inspect the compiler database.
+        https://github.com/mesonbuild/meson/pull/951
+        '''
+        testdir = os.path.join(self.common_test_dir, '5 linkstatic')
+        self.init(testdir)
+        compdb = self.get_compdb()
+        # Rules will get written out in this order
+        self.assertTrue(compdb[0]['file'].endswith("libfile.c"))
+        self.assertTrue(compdb[1]['file'].endswith("libfile2.c"))
+        self.assertTrue(compdb[2]['file'].endswith("libfile3.c"))
+        self.assertTrue(compdb[3]['file'].endswith("libfile4.c"))
+        # FIXME: We don't have access to the linker command
+
+    def test_run_target_files_path(self):
+        '''
+        Test that run_targets are run from the correct directory
+        https://github.com/mesonbuild/meson/issues/957
+        '''
+        testdir = os.path.join(self.common_test_dir, '58 run target')
+        self.init(testdir)
+        self.run_target('check_exists')
+
+    def test_install_introspection(self):
+        '''
+        Tests that the Meson introspection API exposes install filenames correctly
+        https://github.com/mesonbuild/meson/issues/829
+        '''
+        testdir = os.path.join(self.common_test_dir, '8 install')
+        self.init(testdir)
+        intro = self.introspect('--targets')
+        if intro[0]['type'] == 'executable':
+            intro = intro[::-1]
+        self.assertPathEqual(intro[0]['install_filename'], '/usr/lib/libstat.a')
+        self.assertPathEqual(intro[1]['install_filename'], '/usr/bin/prog' + exe_suffix)
+
+    def test_uninstall(self):
+        exename = os.path.join(self.installdir, 'usr/bin/prog' + exe_suffix)
+        testdir = os.path.join(self.common_test_dir, '8 install')
+        self.init(testdir)
+        self.assertFalse(os.path.exists(exename))
+        self.install()
+        self.assertTrue(os.path.exists(exename))
+        self.uninstall()
+        self.assertFalse(os.path.exists(exename))
+
+    def test_testsetups(self):
+        if not shutil.which('valgrind'):
+                raise unittest.SkipTest('Valgrind not installed.')
+        testdir = os.path.join(self.unit_test_dir, '2 testsetups')
+        self.init(testdir)
+        self.build()
+        self.run_tests()
+        with open(os.path.join(self.logdir, 'testlog.txt')) as f:
+            basic_log = f.read()
+        self.assertRaises(subprocess.CalledProcessError,
+                          self._run, self.mtest_command + ['--setup=valgrind'])
+        with open(os.path.join(self.logdir, 'testlog-valgrind.txt')) as f:
+            vg_log = f.read()
+        self.assertFalse('TEST_ENV is set' in basic_log)
+        self.assertFalse('Memcheck' in basic_log)
+        self.assertTrue('TEST_ENV is set' in vg_log)
+        self.assertTrue('Memcheck' in vg_log)
+
+    def assertFailedTestCount(self, failure_count, command):
+        try:
+            self._run(command)
+            self.assertEqual(0, failure_count, 'Expected %d tests to fail.' % failure_count)
+        except subprocess.CalledProcessError as e:
+            self.assertEqual(e.returncode, failure_count)
+
+    def test_suite_selection(self):
+        testdir = os.path.join(self.unit_test_dir, '4 suite selection')
+        self.init(testdir)
+        self.build()
+
+        self.assertFailedTestCount(3, self.mtest_command)
+
+        self.assertFailedTestCount(0, self.mtest_command + ['--suite', ':success'])
+        self.assertFailedTestCount(3, self.mtest_command + ['--suite', ':fail'])
+        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', ':success'])
+        self.assertFailedTestCount(0, self.mtest_command + ['--no-suite', ':fail'])
+
+        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'mainprj'])
+        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc'])
+        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail'])
+        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjmix'])
+        self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'mainprj'])
+        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjsucc'])
+        self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjfail'])
+        self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjmix'])
+
+        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'mainprj:fail'])
+        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'mainprj:success'])
+        self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'mainprj:fail'])
+        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'mainprj:success'])
+
+        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail:fail'])
+        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjfail:success'])
+        self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjfail:fail'])
+        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjfail:success'])
+
+        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc:fail'])
+        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc:success'])
+        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjsucc:fail'])
+        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjsucc:success'])
+
+        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjmix:fail'])
+        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjmix:success'])
+        self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjmix:fail'])
+        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjmix:success'])
+
+        self.assertFailedTestCount(2, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix:fail'])
+        self.assertFailedTestCount(3, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj'])
+        self.assertFailedTestCount(2, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj', '--no-suite', 'subprjmix:fail'])
+        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj', '--no-suite', 'subprjmix:fail', 'mainprj-failing_test'])
+
+        self.assertFailedTestCount(1, self.mtest_command + ['--no-suite', 'subprjfail:fail', '--no-suite', 'subprjmix:fail'])
+
+    def test_build_by_default(self):
+        testdir = os.path.join(self.common_test_dir, '137 build by default')
+        self.init(testdir)
+        self.build()
+        genfile = os.path.join(self.builddir, 'generated.dat')
+        exe = os.path.join(self.builddir, 'fooprog' + exe_suffix)
+        self.assertTrue(os.path.exists(genfile))
+        self.assertFalse(os.path.exists(exe))
+        self._run(self.ninja_command + ['fooprog' + exe_suffix])
+        self.assertTrue(os.path.exists(exe))
+
+    def test_internal_include_order(self):
+        testdir = os.path.join(self.common_test_dir, '138 include order')
+        self.init(testdir)
+        for cmd in self.get_compdb():
+            if cmd['file'].endswith('/main.c'):
+                cmd = cmd['command']
+                break
+        else:
+            raise Exception('Could not find main.c command')
+        if cmd.endswith('.rsp'):
+            # Pretend to build so that the rsp files are generated
+            self.build(['-d', 'keeprsp', '-n'])
+            # Extract the actual command from the rsp file
+            rsp = os.path.join(self.builddir, cmd.split('cl @')[1])
+            with open(rsp, 'r', encoding='utf-8') as f:
+                cmd = f.read()
+        incs = [a for a in shlex.split(cmd) if a.startswith("-I")]
+        self.assertEqual(len(incs), 8)
+        # target private dir
+        self.assertPathEqual(incs[0], "-Isub4/someexe@exe")
+        # target build subdir
+        self.assertPathEqual(incs[1], "-Isub4")
+        # target source subdir
+        self.assertPathBasenameEqual(incs[2], 'sub4')
+        # include paths added via per-target c_args: ['-I'...]
+        self.assertPathBasenameEqual(incs[3], 'sub3')
+        # target include_directories: build dir
+        self.assertPathEqual(incs[4], "-Isub2")
+        # target include_directories: source dir
+        self.assertPathBasenameEqual(incs[5], 'sub2')
+        # target internal dependency include_directories: build dir
+        self.assertPathEqual(incs[6], "-Isub1")
+        # target internal dependency include_directories: source dir
+        self.assertPathBasenameEqual(incs[7], 'sub1')
+
 
 class LinuxlikeTests(BasePlatformTests):
     '''
@@ -471,45 +662,6 @@ class LinuxlikeTests(BasePlatformTests):
         self.assertIn("'-Werror'", vala_command)
         self.assertIn("'-Werror'", c_command)
 
-    def test_static_compile_order(self):
-        '''
-        Test that the order of files in a compiler command-line while compiling
-        and linking statically is deterministic. This can't be an ordinary test
-        case because we need to inspect the compiler database.
-        https://github.com/mesonbuild/meson/pull/951
-        '''
-        testdir = os.path.join(self.common_test_dir, '5 linkstatic')
-        self.init(testdir)
-        compdb = self.get_compdb()
-        # Rules will get written out in this order
-        self.assertTrue(compdb[0]['file'].endswith("libfile.c"))
-        self.assertTrue(compdb[1]['file'].endswith("libfile2.c"))
-        self.assertTrue(compdb[2]['file'].endswith("libfile3.c"))
-        self.assertTrue(compdb[3]['file'].endswith("libfile4.c"))
-        # FIXME: We don't have access to the linker command
-
-    def test_install_introspection(self):
-        '''
-        Tests that the Meson introspection API exposes install filenames correctly
-        https://github.com/mesonbuild/meson/issues/829
-        '''
-        testdir = os.path.join(self.common_test_dir, '8 install')
-        self.init(testdir)
-        intro = self.introspect('--targets')
-        if intro[0]['type'] == 'executable':
-            intro = intro[::-1]
-        self.assertEqual(intro[0]['install_filename'], '/usr/lib/libstat.a')
-        self.assertEqual(intro[1]['install_filename'], '/usr/bin/prog')
-
-    def test_run_target_files_path(self):
-        '''
-        Test that run_targets are run from the correct directory
-        https://github.com/mesonbuild/meson/issues/957
-        '''
-        testdir = os.path.join(self.common_test_dir, '58 run target')
-        self.init(testdir)
-        self.run_target('check_exists')
-
     def test_qt5dependency_qmake_detection(self):
         '''
         Test that qt5 detection with qmake works. This can't be an ordinary
@@ -613,16 +765,6 @@ class LinuxlikeTests(BasePlatformTests):
             Oargs = [arg for arg in cmd if arg.startswith('-O')]
             self.assertEqual(Oargs, [Oflag, '-O0'])
 
-    def test_uninstall(self):
-        exename = os.path.join(self.installdir, 'usr/bin/prog')
-        testdir = os.path.join(self.common_test_dir, '8 install')
-        self.init(testdir)
-        self.assertFalse(os.path.exists(exename))
-        self.install()
-        self.assertTrue(os.path.exists(exename))
-        self.uninstall()
-        self.assertFalse(os.path.exists(exename))
-
     def test_custom_target_exe_data_deterministic(self):
         testdir = os.path.join(self.common_test_dir, '117 custom target capture')
         self.init(testdir)
@@ -632,79 +774,6 @@ class LinuxlikeTests(BasePlatformTests):
         meson_exe_dat2 = glob(os.path.join(self.privatedir, 'meson_exe*.dat'))
         self.assertListEqual(meson_exe_dat1, meson_exe_dat2)
 
-    def test_testsetups(self):
-        if not shutil.which('valgrind'):
-                raise unittest.SkipTest('Valgrind not installed.')
-        testdir = os.path.join(self.unit_test_dir, '2 testsetups')
-        self.init(testdir)
-        self.build()
-        self.run_tests()
-        with open(os.path.join(self.logdir, 'testlog.txt')) as f:
-            basic_log = f.read()
-        self.assertRaises(subprocess.CalledProcessError,
-                          self._run, self.mtest_command + ['--setup=valgrind'])
-        with open(os.path.join(self.logdir, 'testlog-valgrind.txt')) as f:
-            vg_log = f.read()
-        self.assertFalse('TEST_ENV is set' in basic_log)
-        self.assertFalse('Memcheck' in basic_log)
-        self.assertTrue('TEST_ENV is set' in vg_log)
-        self.assertTrue('Memcheck' in vg_log)
-
-    def assertFailedTestCount(self, failure_count, command):
-        try:
-            self._run(command)
-            self.assertEqual(0, failure_count, 'Expected %d tests to fail.' % failure_count)
-        except subprocess.CalledProcessError as e:
-            self.assertEqual(e.returncode, failure_count)
-
-    def test_suite_selection(self):
-        testdir = os.path.join(self.unit_test_dir, '4 suite selection')
-        self.init(testdir)
-        self.build()
-
-        self.assertFailedTestCount(3, self.mtest_command)
-
-        self.assertFailedTestCount(0, self.mtest_command + ['--suite', ':success'])
-        self.assertFailedTestCount(3, self.mtest_command + ['--suite', ':fail'])
-        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', ':success'])
-        self.assertFailedTestCount(0, self.mtest_command + ['--no-suite', ':fail'])
-
-        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'mainprj'])
-        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc'])
-        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail'])
-        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjmix'])
-        self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'mainprj'])
-        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjsucc'])
-        self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjfail'])
-        self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjmix'])
-
-        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'mainprj:fail'])
-        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'mainprj:success'])
-        self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'mainprj:fail'])
-        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'mainprj:success'])
-
-        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail:fail'])
-        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjfail:success'])
-        self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjfail:fail'])
-        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjfail:success'])
-
-        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc:fail'])
-        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc:success'])
-        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjsucc:fail'])
-        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjsucc:success'])
-
-        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjmix:fail'])
-        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjmix:success'])
-        self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjmix:fail'])
-        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjmix:success'])
-
-        self.assertFailedTestCount(2, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix:fail'])
-        self.assertFailedTestCount(3, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj'])
-        self.assertFailedTestCount(2, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj', '--no-suite', 'subprjmix:fail'])
-        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj', '--no-suite', 'subprjmix:fail', 'mainprj-failing_test'])
-
-        self.assertFailedTestCount(1, self.mtest_command + ['--no-suite', 'subprjfail:fail', '--no-suite', 'subprjmix:fail'])
-
     def _test_stds_impl(self, testdir, compiler, p):
         lang_std = p + '_std'
         # Check that all the listed -std=xxx options for this compiler work
@@ -757,17 +826,6 @@ class LinuxlikeTests(BasePlatformTests):
         cpp = env.detect_cpp_compiler(False)
         self._test_stds_impl(testdir, cpp, 'cpp')
 
-    def test_build_by_default(self):
-        testdir = os.path.join(self.common_test_dir, '137 build by default')
-        self.init(testdir)
-        self.build()
-        genfile = os.path.join(self.builddir, 'generated.dat')
-        exe = os.path.join(self.builddir, 'fooprog')
-        self.assertTrue(os.path.exists(genfile))
-        self.assertFalse(os.path.exists(exe))
-        self._run(self.ninja_command + ['fooprog'])
-        self.assertTrue(os.path.exists(exe))
-
     def test_installed_modes(self):
         '''
         Test that files installed by these tests have the correct permissions.
@@ -821,38 +879,6 @@ class LinuxlikeTests(BasePlatformTests):
             # The chown failed nonfatally if we're not root
             self.assertEqual(0, statf.st_uid)
 
-    def test_internal_include_order(self):
-        testdir = os.path.join(self.common_test_dir, '138 include order')
-        self.init(testdir)
-        for cmd in self.get_compdb():
-            if cmd['file'].endswith('/main.c'):
-                cmd = cmd['command']
-                break
-        else:
-            raise Exception('Could not find main.c command')
-        incs = [a for a in shlex.split(cmd) if a.startswith("-I")]
-        self.assertEqual(len(incs), 8)
-        # target private dir
-        self.assertEqual(incs[0], "-Isub4/someexe@exe")
-        # target build subdir
-        self.assertEqual(incs[1], "-Isub4")
-        # target source subdir
-        msg = "{!r} does not end with '/sub4'".format(incs[2])
-        self.assertTrue(incs[2].endswith("/sub4"), msg)
-        # include paths added via per-target c_args: ['-I'...]
-        msg = "{!r} does not end with '/sub3'".format(incs[3])
-        self.assertTrue(incs[3].endswith("/sub3"), msg)
-        # target include_directories: build dir
-        self.assertEqual(incs[4], "-Isub2")
-        # target include_directories: source dir
-        msg = "{!r} does not end with '/sub2'".format(incs[5])
-        self.assertTrue(incs[5].endswith("/sub2"), msg)
-        # target internal dependency include_directories: build dir
-        self.assertEqual(incs[6], "-Isub1")
-        # target internal dependency include_directories: source dir
-        msg = "{!r} does not end with '/sub1'".format(incs[7])
-        self.assertTrue(incs[7].endswith("/sub1"), msg)
-
 
 class RewriterTests(unittest.TestCase):