Merge pull request #1356 from centricular/cross-platform-unit-tests

Run unit tests on more platforms, and more
pull/1395/head
Jussi Pakkanen 8 years ago committed by GitHub
commit 0cf18eb3bc
  1. 14
      mesonbuild/backend/backends.py
  2. 14
      mesonbuild/backend/ninjabackend.py
  3. 2
      mesonbuild/backend/vs2010backend.py
  4. 92
      mesonbuild/dependencies.py
  5. 28
      mesonbuild/interpreter.py
  6. 21
      mesonbuild/mintro.py
  7. 6
      mesonbuild/modules/qt4.py
  8. 6
      mesonbuild/modules/qt5.py
  9. 9
      mesonbuild/modules/rpm.py
  10. 10
      run_tests.py
  11. 612
      run_unittests.py
  12. 21
      test cases/common/105 find program path/meson.build
  13. 9
      test cases/common/119 pathjoin/meson.build
  14. 3
      test cases/common/3 static/libfile2.c
  15. 3
      test cases/common/3 static/meson.build
  16. 1
      test cases/common/3 static/meson_options.txt
  17. 1
      test cases/common/94 default options/meson.build
  18. 8
      test cases/windows/9 find program/meson.build
  19. 3
      test cases/windows/9 find program/test-script-ext.py

@ -215,13 +215,13 @@ class Backend:
exe_data = os.path.join(self.environment.get_scratch_dir(), scratch_file)
with open(exe_data, 'wb') as f:
if isinstance(exe, dependencies.ExternalProgram):
exe_fullpath = exe.fullpath
exe_cmd = exe.get_command()
exe_needs_wrapper = False
elif isinstance(exe, (build.BuildTarget, build.CustomTarget)):
exe_fullpath = [self.get_target_filename_abs(exe)]
exe_cmd = [self.get_target_filename_abs(exe)]
exe_needs_wrapper = exe.is_cross
else:
exe_fullpath = [exe]
exe_cmd = [exe]
exe_needs_wrapper = False
is_cross = exe_needs_wrapper and \
self.environment.is_cross_build() and \
@ -235,7 +235,7 @@ class Backend:
extra_paths = self.determine_windows_extra_paths(exe)
else:
extra_paths = []
es = ExecutableSerialisation(basename, exe_fullpath, cmd_args, env,
es = ExecutableSerialisation(basename, exe_cmd, cmd_args, env,
is_cross, exe_wrapper, workdir,
extra_paths, capture)
pickle.dump(es, f)
@ -444,9 +444,9 @@ class Backend:
for t in tests:
exe = t.get_exe()
if isinstance(exe, dependencies.ExternalProgram):
fname = exe.fullpath
cmd = exe.get_command()
else:
fname = [os.path.join(self.environment.get_build_dir(), self.get_target_filename(t.get_exe()))]
cmd = [os.path.join(self.environment.get_build_dir(), self.get_target_filename(t.get_exe()))]
is_cross = self.environment.is_cross_build() and \
self.environment.cross_info.need_cross_compiler() and \
self.environment.cross_info.need_exe_wrapper()
@ -471,7 +471,7 @@ class Backend:
cmd_args.append(self.get_target_filename(a))
else:
raise MesonException('Bad object in test command.')
ts = TestSerialisation(t.get_name(), t.suite, fname, is_cross, exe_wrapper,
ts = TestSerialisation(t.get_name(), t.suite, cmd, is_cross, exe_wrapper,
t.is_parallel, cmd_args, t.env, t.should_fail,
t.timeout, t.workdir, extra_paths)
arr.append(ts)

@ -30,9 +30,11 @@ from collections import OrderedDict
if mesonlib.is_windows():
quote_char = '"'
execute_wrapper = 'cmd /c'
rmfile_prefix = 'del /f /s /q {} &&'
else:
quote_char = "'"
execute_wrapper = ''
rmfile_prefix = 'rm -f {} &&'
def ninja_quote(text):
return text.replace(' ', '$ ').replace(':', '$:')
@ -1238,10 +1240,16 @@ int dummy;
'''
else:
command_template = ' command = {executable} $LINK_ARGS {output_args} $in\n'
cmdlist = []
if isinstance(static_linker, compilers.ArLinker):
# `ar` has no options to overwrite archives. It always appends,
# which is never what we want. Delete an existing library first if
# it exists. https://github.com/mesonbuild/meson/issues/1355
cmdlist = [execute_wrapper, rmfile_prefix.format('$out')]
cmdlist += static_linker.get_exelist()
command = command_template.format(
executable=' '.join(static_linker.get_exelist()),
output_args=' '.join(static_linker.get_output_args('$out'))
)
executable=' '.join(cmdlist),
output_args=' '.join(static_linker.get_output_args('$out')))
description = ' description = Static linking library $out\n\n'
outfile.write(rule)
outfile.write(command)

@ -395,7 +395,7 @@ class Vs2010Backend(backends.Backend):
if isinstance(i, build.BuildTarget):
cmd.append(os.path.join(self.environment.get_build_dir(), self.get_target_filename(i)))
elif isinstance(i, dependencies.ExternalProgram):
cmd += i.fullpath
cmd += i.get_command()
else:
cmd.append(i)
cmd_templ = '''"%s" ''' * len(cmd)

@ -120,8 +120,8 @@ class PkgConfigDependency(Dependency):
if self.required:
raise DependencyException('Pkg-config binary missing from cross file')
else:
potential_pkgbin = ExternalProgram(environment.cross_info.config['binaries'].get('pkgconfig', 'non_existing_binary'),
silent=True)
pkgname = environment.cross_info.config['binaries']['pkgconfig']
potential_pkgbin = ExternalProgram(pkgname, silent=True)
if potential_pkgbin.found():
# FIXME, we should store all pkg-configs in ExternalPrograms.
# However that is too destabilizing a change to do just before release.
@ -402,24 +402,28 @@ class WxDependency(Dependency):
return self.is_found
class ExternalProgram:
windows_exts = ('exe', 'com', 'bat')
windows_exts = ('exe', 'msc', 'com', 'bat')
def __init__(self, name, fullpath=None, silent=False, search_dir=None):
def __init__(self, name, command=None, silent=False, search_dir=None):
self.name = name
if fullpath is not None:
if not isinstance(fullpath, list):
self.fullpath = [fullpath]
if command is not None:
if not isinstance(command, list):
self.command = [command]
else:
self.fullpath = fullpath
self.command = command
else:
self.fullpath = self._search(name, search_dir)
self.command = self._search(name, search_dir)
if not silent:
if self.found():
mlog.log('Program', mlog.bold(name), 'found:', mlog.green('YES'),
'(%s)' % ' '.join(self.fullpath))
'(%s)' % ' '.join(self.command))
else:
mlog.log('Program', mlog.bold(name), 'found:', mlog.red('NO'))
def __repr__(self):
r = '<{} {!r} -> {!r}>'
return r.format(self.__class__.__name__, self.name, self.command)
@staticmethod
def _shebang_to_cmd(script):
"""
@ -473,34 +477,63 @@ class ExternalProgram:
return self._shebang_to_cmd(trial)
def _search(self, name, search_dir):
'''
Search in the specified dir for the specified executable by name
and if not found search in PATH
'''
commands = self._search_dir(name, search_dir)
if commands:
return commands
# Do a standard search in PATH
fullpath = shutil.which(name)
if fullpath or not mesonlib.is_windows():
command = shutil.which(name)
if not mesonlib.is_windows():
# On UNIX-like platforms, the standard PATH search is enough
return [fullpath]
# On Windows, if name is an absolute path, we need the extension too
for ext in self.windows_exts:
fullpath = '{}.{}'.format(name, ext)
if os.path.exists(fullpath):
return [fullpath]
# On Windows, interpreted scripts must have an extension otherwise they
# cannot be found by a standard PATH search. So we do a custom search
# where we manually search for a script with a shebang in PATH.
search_dirs = os.environ.get('PATH', '').split(';')
for search_dir in search_dirs:
commands = self._search_dir(name, search_dir)
return [command]
# HERE BEGINS THE TERROR OF WINDOWS
if command:
# On Windows, even if the PATH search returned a full path, we can't be
# sure that it can be run directly if it's not a native executable.
# For instance, interpreted scripts sometimes need to be run explicitly
# with an interpreter if the file association is not done properly.
name_ext = os.path.splitext(command)[1]
if name_ext[1:].lower() in self.windows_exts:
# Good, it can be directly executed
return [command]
# Try to extract the interpreter from the shebang
commands = self._shebang_to_cmd(command)
if commands:
return commands
else:
# Maybe the name is an absolute path to a native Windows
# executable, but without the extension. This is technically wrong,
# but many people do it because it works in the MinGW shell.
if os.path.isabs(name):
for ext in self.windows_exts:
command = '{}.{}'.format(name, ext)
if os.path.exists(command):
return [command]
# On Windows, interpreted scripts must have an extension otherwise they
# cannot be found by a standard PATH search. So we do a custom search
# where we manually search for a script with a shebang in PATH.
search_dirs = os.environ.get('PATH', '').split(';')
for search_dir in search_dirs:
commands = self._search_dir(name, search_dir)
if commands:
return commands
return [None]
def found(self):
return self.fullpath[0] is not None
return self.command[0] is not None
def get_command(self):
return self.fullpath[:]
return self.command[:]
def get_path(self):
# Assume that the last element is the full path to the script
# If it's not a script, this will be an array of length 1
if self.found():
return self.command[-1]
return None
def get_name(self):
return self.name
@ -531,6 +564,9 @@ class ExternalLibrary(Dependency):
def found(self):
return self.is_found
def get_name(self):
return self.name
def get_link_args(self):
return self.link_args
@ -994,7 +1030,7 @@ class QtBaseDependency(Dependency):
if not self.qmake.found():
continue
# Check that the qmake is for qt5
pc, stdo = Popen_safe(self.qmake.fullpath + ['-v'])[0:2]
pc, stdo = Popen_safe(self.qmake.get_command() + ['-v'])[0:2]
if pc.returncode != 0:
continue
if not 'Qt version ' + self.qtver in stdo:
@ -1007,7 +1043,7 @@ class QtBaseDependency(Dependency):
return
self.version = re.search(self.qtver + '(\.\d+)+', stdo).group(0)
# Query library path, header path, and binary path
stdo = Popen_safe(self.qmake.fullpath + ['-query'])[1]
stdo = Popen_safe(self.qmake.get_command() + ['-query'])[1]
qvars = {}
for line in stdo.split('\n'):
line = line.strip()

@ -285,16 +285,16 @@ class ExternalProgramHolder(InterpreterObject):
return self.found()
def path_method(self, args, kwargs):
return self.get_command()
return self.held_object.get_path()
def found(self):
return self.held_object.found()
def get_command(self):
return self.held_object.fullpath
return self.held_object.get_command()
def get_name(self):
return self.held_object.name
return self.held_object.get_name()
class ExternalLibraryHolder(InterpreterObject):
def __init__(self, el):
@ -308,9 +308,6 @@ class ExternalLibraryHolder(InterpreterObject):
def found_method(self, args, kwargs):
return self.found()
def get_filename(self):
return self.held_object.fullpath
def get_name(self):
return self.held_object.name
@ -1424,7 +1421,8 @@ class Interpreter(InterpreterBase):
elif isinstance(cmd, str):
cmd = [cmd]
else:
raise InterpreterException('First argument is of incorrect type.')
raise InterpreterException('First argument should be find_program() '
'or string, not {!r}'.format(cmd))
expanded_args = []
for a in mesonlib.flatten(cargs):
if isinstance(a, str):
@ -1759,7 +1757,6 @@ class Interpreter(InterpreterBase):
break
self.coredata.base_options[optname] = oobj
@stringArgs
def func_find_program(self, node, args, kwargs):
if len(args) == 0:
raise InterpreterException('No program name specified.')
@ -1769,8 +1766,21 @@ class Interpreter(InterpreterBase):
# Search for scripts relative to current subdir.
# Do not cache found programs because find_program('foobar')
# might give different results when run from different source dirs.
search_dir = os.path.join(self.environment.get_source_dir(), self.subdir)
source_dir = os.path.join(self.environment.get_source_dir(), self.subdir)
for exename in args:
if isinstance(exename, mesonlib.File):
if exename.is_built:
search_dir = os.path.join(self.environment.get_build_dir(),
exename.subdir)
else:
search_dir = os.path.join(self.environment.get_source_dir(),
exename.subdir)
exename = exename.fname
elif isinstance(exename, str):
search_dir = source_dir
else:
raise InvalidArguments('find_program only accepts strings and '
'files, not {!r}'.format(exename))
extprog = dependencies.ExternalProgram(exename, search_dir=search_dir)
progobj = ExternalProgramHolder(extprog)
if progobj.found():

@ -23,6 +23,7 @@ import json, pickle
from . import coredata, build
import argparse
import sys, os
import pathlib
parser = argparse.ArgumentParser()
parser.add_argument('--targets', action='store_true', dest='list_targets', default=False,
@ -56,7 +57,9 @@ def determine_installed_path(target, installdata):
fname = i[0]
outdir = i[1]
outname = os.path.join(installdata.prefix, outdir, os.path.split(fname)[-1])
return outname
# Normalize the path by using os.path.sep consistently, etc.
# Does not change the effective path.
return str(pathlib.PurePath(outname))
def list_installed(installdata):
@ -111,23 +114,11 @@ def list_target_files(target_name, coredata, builddata):
print(json.dumps(sources))
def list_buildoptions(coredata, builddata):
buildtype = {'choices': ['plain', 'debug', 'debugoptimized', 'release', 'minsize'],
'type': 'combo',
'value': coredata.get_builtin_option('buildtype'),
'description': 'Build type',
'name': 'type'}
strip = {'value': coredata.get_builtin_option('strip'),
'type': 'boolean',
'description': 'Strip on install',
'name': 'strip'}
unity = {'value': coredata.get_builtin_option('unity'),
'type': 'boolean',
'description': 'Unity build',
'name': 'unity'}
optlist = [buildtype, strip, unity]
optlist = []
add_keys(optlist, coredata.user_options)
add_keys(optlist, coredata.compiler_options)
add_keys(optlist, coredata.base_options)
add_keys(optlist, coredata.builtins)
print(json.dumps(optlist))
def add_keys(optlist, options):

@ -48,7 +48,7 @@ class Qt4Module(ExtensionModule):
raise MesonException('Moc preprocessor is not for Qt 4. Output:\n%s\n%s' %
(stdout, stderr))
mlog.log(' moc:', mlog.green('YES'), '(%s, %s)' %
(' '.join(self.moc.fullpath), moc_ver.split()[-1]))
(self.moc.get_path(), moc_ver.split()[-1]))
else:
mlog.log(' moc:', mlog.red('NO'))
if self.uic.found():
@ -61,7 +61,7 @@ class Qt4Module(ExtensionModule):
raise MesonException('Uic compiler is not for Qt4. Output:\n%s\n%s' %
(stdout, stderr))
mlog.log(' uic:', mlog.green('YES'), '(%s, %s)' %
(' '.join(self.uic.fullpath), uic_ver.split()[-1]))
(self.uic.get_path(), uic_ver.split()[-1]))
else:
mlog.log(' uic:', mlog.red('NO'))
if self.rcc.found():
@ -74,7 +74,7 @@ class Qt4Module(ExtensionModule):
raise MesonException('Rcc compiler is not for Qt 4. Output:\n%s\n%s' %
(stdout, stderr))
mlog.log(' rcc:', mlog.green('YES'), '(%s, %s)'
% (' '.join(self.rcc.fullpath), rcc_ver.split()[-1]))
% (self.rcc.get_path(), rcc_ver.split()[-1]))
else:
mlog.log(' rcc:', mlog.red('NO'))
self.tools_detected = True

@ -50,7 +50,7 @@ class Qt5Module(ExtensionModule):
raise MesonException('Moc preprocessor is not for Qt 5. Output:\n%s\n%s' %
(stdout, stderr))
mlog.log(' moc:', mlog.green('YES'), '(%s, %s)' %
(' '.join(self.moc.fullpath), moc_ver.split()[-1]))
(self.moc.get_path(), moc_ver.split()[-1]))
else:
mlog.log(' moc:', mlog.red('NO'))
if self.uic.found():
@ -65,7 +65,7 @@ class Qt5Module(ExtensionModule):
raise MesonException('Uic compiler is not for Qt 5. Output:\n%s\n%s' %
(stdout, stderr))
mlog.log(' uic:', mlog.green('YES'), '(%s, %s)' %
(' '.join(self.uic.fullpath), uic_ver.split()[-1]))
(self.uic.get_path(), uic_ver.split()[-1]))
else:
mlog.log(' uic:', mlog.red('NO'))
if self.rcc.found():
@ -80,7 +80,7 @@ class Qt5Module(ExtensionModule):
raise MesonException('Rcc compiler is not for Qt 5. Output:\n%s\n%s' %
(stdout, stderr))
mlog.log(' rcc:', mlog.green('YES'), '(%s, %s)'
% (' '.join(self.rcc.fullpath), rcc_ver.split()[-1]))
% (self.rcc.get_path(), rcc_ver.split()[-1]))
else:
mlog.log(' rcc:', mlog.red('NO'))
self.tools_detected = True

@ -98,17 +98,18 @@ class RPMModule(ExtensionModule):
for dep in state.environment.coredata.deps:
fn.write('BuildRequires: pkgconfig(%s)\n' % dep[0])
for lib in state.environment.coredata.ext_libs.values():
fn.write('BuildRequires: %s # FIXME\n' % lib.fullpath)
mlog.warning('replace', mlog.bold(lib.fullpath), 'with real package.',
name = lib.get_name()
fn.write('BuildRequires: {} # FIXME\n'.format(name))
mlog.warning('replace', mlog.bold(name), 'with the real package.',
'You can use following command to find package which '
'contains this lib:',
mlog.bold('dnf provides %s' % lib.fullpath))
mlog.bold("dnf provides '*/lib{}.so".format(name))
for prog in state.environment.coredata.ext_progs.values():
if not prog.found():
fn.write('BuildRequires: %%{_bindir}/%s # FIXME\n' %
prog.get_name())
else:
fn.write('BuildRequires: %s\n' % ' '.join(prog.fullpath))
fn.write('BuildRequires: {}\n'.format(prog.get_path()))
fn.write('BuildRequires: meson\n')
fn.write('\n')
fn.write('%description\n')

@ -1,6 +1,6 @@
#!/usr/bin/env python3
# Copyright 2012-2016 The Meson development team
# Copyright 2012-2017 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -21,10 +21,12 @@ from mesonbuild import mesonlib
if __name__ == '__main__':
returncode = 0
print('Running unittests.\n')
units = ['InternalTests', 'AllPlatformTests']
if mesonlib.is_linux():
returncode += subprocess.call([sys.executable, 'run_unittests.py', '-v'])
else:
returncode += subprocess.call([sys.executable, 'run_unittests.py', '-v', 'InternalTests'])
units += ['LinuxlikeTests']
elif mesonlib.is_windows():
units += ['WindowsTests']
returncode += subprocess.call([sys.executable, 'run_unittests.py', '-v'] + units)
# Ubuntu packages do not have a binary without -6 suffix.
if shutil.which('arm-linux-gnueabihf-gcc-6') and not platform.machine().startswith('arm'):
print('Running cross compilation tests.\n')

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright 2016 The Meson development team
# Copyright 2016-2017 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -18,14 +18,20 @@ 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
from mesonbuild.dependencies import PkgConfigDependency, ExternalProgram
if is_windows():
exe_suffix = '.exe'
else:
exe_suffix = ''
def get_soname(fname):
# HACK, fix to not use shell.
@ -172,15 +178,18 @@ 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 LinuxlikeTests(unittest.TestCase):
class BasePlatformTests(unittest.TestCase):
def setUp(self):
super().setUp()
src_root = os.path.dirname(__file__)
src_root = os.path.join(os.getcwd(), src_root)
self.builddir = tempfile.mkdtemp()
self.src_root = src_root
# In case the directory is inside a symlinked directory, find the real
# path otherwise we might not find the srcdir from inside the builddir.
self.builddir = os.path.realpath(tempfile.mkdtemp())
self.logdir = os.path.join(self.builddir, 'meson-logs')
self.prefix = '/usr'
self.libdir = os.path.join(self.prefix, 'lib')
@ -194,7 +203,6 @@ class LinuxlikeTests(unittest.TestCase):
self.vala_test_dir = os.path.join(src_root, 'test cases/vala')
self.framework_test_dir = os.path.join(src_root, 'test cases/frameworks')
self.unit_test_dir = os.path.join(src_root, 'test cases/unit')
self.output = b''
self.orig_env = os.environ.copy()
def tearDown(self):
@ -203,20 +211,26 @@ class LinuxlikeTests(unittest.TestCase):
super().tearDown()
def _run(self, command):
self.output += subprocess.check_output(command, stderr=subprocess.STDOUT,
env=os.environ.copy())
output = subprocess.check_output(command, stderr=subprocess.STDOUT,
env=os.environ.copy(),
universal_newlines=True)
print(output)
return output
def init(self, srcdir, extra_args=None):
def init(self, srcdir, extra_args=None, default_args=True):
if extra_args is None:
extra_args = []
args = [srcdir, self.builddir,
'--prefix', self.prefix,
'--libdir', self.libdir]
args = [srcdir, self.builddir]
if default_args:
args += ['--prefix', self.prefix,
'--libdir', self.libdir]
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'])
@ -229,9 +243,18 @@ class LinuxlikeTests(unittest.TestCase):
self._run(self.ninja_command + ['uninstall'])
def run_target(self, target):
self.output += subprocess.check_output(self.ninja_command + [target])
output = subprocess.check_output(self.ninja_command + [target],
stderr=subprocess.STDOUT,
universal_newlines=True)
print(output)
return output
def setconf(self, arg):
def setconf(self, arg, will_build=True):
# This is needed to increase the difference between build.ninja's
# timestamp and coredata.dat's timestamp due to a Ninja bug.
# https://github.com/ninja-build/ninja/issues/371
if will_build:
time.sleep(1)
self._run(self.mconf_command + [arg, self.builddir])
def wipe(self):
@ -260,6 +283,336 @@ class LinuxlikeTests(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):
'''
Tests that should run on all platforms
'''
def test_default_options_prefix(self):
'''
Tests that setting a prefix in default_options in project() works.
Can't be an ordinary test because we pass --prefix to meson there.
https://github.com/mesonbuild/meson/issues/1349
'''
testdir = os.path.join(self.common_test_dir, '94 default options')
self.init(testdir, default_args=False)
opts = self.introspect('--buildoptions')
for opt in opts:
if opt['name'] == 'prefix':
prefix = opt['value']
self.assertEqual(prefix, '/absoluteprefix')
def test_absolute_prefix_libdir(self):
'''
Tests that setting absolute paths for --prefix and --libdir work. Can't
be an ordinary test because these are set via the command-line.
https://github.com/mesonbuild/meson/issues/1341
https://github.com/mesonbuild/meson/issues/1345
'''
testdir = os.path.join(self.common_test_dir, '94 default options')
prefix = '/someabs'
libdir = 'libdir'
extra_args = ['--prefix=' + prefix,
# This can just be a relative path, but we want to test
# that passing this as an absolute path also works
'--libdir=' + prefix + '/' + libdir]
self.init(testdir, extra_args, default_args=False)
opts = self.introspect('--buildoptions')
for opt in opts:
if opt['name'] == 'prefix':
self.assertEqual(prefix, opt['value'])
elif opt['name'] == 'libdir':
self.assertEqual(libdir, opt['value'])
def test_libdir_must_be_inside_prefix(self):
'''
Tests that libdir is forced to be inside prefix no matter how it is set.
Must be a unit test for obvious reasons.
'''
testdir = os.path.join(self.common_test_dir, '1 trivial')
# libdir being inside prefix is ok
args = ['--prefix', '/opt', '--libdir', '/opt/lib32']
self.init(testdir, args)
self.wipe()
# libdir not being inside prefix is not ok
args = ['--prefix', '/usr', '--libdir', '/opt/lib32']
self.assertRaises(subprocess.CalledProcessError, self.init, testdir, args)
self.wipe()
# libdir must be inside prefix even when set via mesonconf
self.init(testdir)
self.assertRaises(subprocess.CalledProcessError, self.setconf, '-Dlibdir=/opt', False)
def test_static_library_overwrite(self):
'''
Tests that static libraries are never appended to, always overwritten.
Has to be a unit test because this involves building a project,
reconfiguring, and building it again so that `ar` is run twice on the
same static library.
https://github.com/mesonbuild/meson/issues/1355
'''
testdir = os.path.join(self.common_test_dir, '3 static')
env = Environment(testdir, self.builddir, self.meson_command,
get_fake_options(self.prefix), [])
cc = env.detect_c_compiler(False)
static_linker = env.detect_static_linker(cc)
if not isinstance(static_linker, mesonbuild.compilers.ArLinker):
raise unittest.SkipTest('static linker is not `ar`')
# Configure
self.init(testdir)
# Get name of static library
targets = self.introspect('--targets')
self.assertEqual(len(targets), 1)
libname = targets[0]['filename']
# Build and get contents of static library
self.build()
before = self._run(['ar', 't', os.path.join(self.builddir, libname)]).split()
# Filter out non-object-file contents
before = [f for f in before if f.endswith(('.o', '.obj'))]
# Static library should contain only one object
self.assertEqual(len(before), 1, msg=before)
# Change the source to be built into the static library
self.setconf('-Dsource=libfile2.c')
self.build()
after = self._run(['ar', 't', os.path.join(self.builddir, libname)]).split()
# Filter out non-object-file contents
after = [f for f in after if f.endswith(('.o', '.obj'))]
# Static library should contain only one object
self.assertEqual(len(after), 1, msg=after)
# 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 WindowsTests(BasePlatformTests):
'''
Tests that should run on Cygwin, MinGW, and MSVC
'''
def setUp(self):
super().setUp()
self.platform_test_dir = os.path.join(self.src_root, 'test cases/windows')
def test_find_program(self):
'''
Test that Windows-specific edge-cases in find_program are functioning
correctly. Cannot be an ordinary test because it involves manipulating
PATH to point to a directory with Python scripts.
'''
testdir = os.path.join(self.platform_test_dir, '9 find program')
# Find `cmd` and `cmd.exe`
prog1 = ExternalProgram('cmd')
self.assertTrue(prog1.found(), msg='cmd not found')
prog2 = ExternalProgram('cmd.exe')
self.assertTrue(prog2.found(), msg='cmd.exe not found')
self.assertPathEqual(prog1.get_path(), prog2.get_path())
# Find cmd with an absolute path that's missing the extension
cmd_path = prog2.get_path()[:-4]
prog = ExternalProgram(cmd_path)
self.assertTrue(prog.found(), msg='{!r} not found'.format(cmd_path))
# Finding a script with no extension inside a directory works
prog = ExternalProgram(os.path.join(testdir, 'test-script'))
self.assertTrue(prog.found(), msg='test-script not found')
# Finding a script with an extension inside a directory works
prog = ExternalProgram(os.path.join(testdir, 'test-script-ext.py'))
self.assertTrue(prog.found(), msg='test-script-ext.py not found')
# Finding a script in PATH w/o extension works and adds the interpreter
os.environ['PATH'] += os.pathsep + testdir
prog = ExternalProgram('test-script-ext')
self.assertTrue(prog.found(), msg='test-script-ext not found in PATH')
self.assertPathEqual(prog.get_command()[0], sys.executable)
self.assertPathBasenameEqual(prog.get_path(), 'test-script-ext.py')
# Finding a script in PATH with extension works and adds the interpreter
prog = ExternalProgram('test-script-ext.py')
self.assertTrue(prog.found(), msg='test-script-ext.py not found in PATH')
self.assertPathEqual(prog.get_command()[0], sys.executable)
self.assertPathBasenameEqual(prog.get_path(), 'test-script-ext.py')
class LinuxlikeTests(BasePlatformTests):
'''
Tests that should run on Linux and *BSD
'''
def test_basic_soname(self):
'''
Test that the soname is set correctly for shared libraries. This can't
@ -298,10 +651,6 @@ class LinuxlikeTests(unittest.TestCase):
self.init(testdir)
compdb = self.get_compdb()
self.assertIn('-fPIC', compdb[0]['command'])
# This is needed to increase the difference between build.ninja's
# timestamp and coredata.dat's timestamp due to a Ninja bug.
# https://github.com/ninja-build/ninja/issues/371
time.sleep(1)
self.setconf('-Db_staticpic=false')
# Regenerate build
self.build()
@ -358,45 +707,6 @@ class LinuxlikeTests(unittest.TestCase):
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
@ -500,16 +810,6 @@ class LinuxlikeTests(unittest.TestCase):
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)
@ -519,79 +819,6 @@ class LinuxlikeTests(unittest.TestCase):
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
@ -644,31 +871,6 @@ class LinuxlikeTests(unittest.TestCase):
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_libdir_must_be_inside_prefix(self):
testdir = os.path.join(self.common_test_dir, '1 trivial')
# libdir being inside prefix is ok
args = ['--prefix', '/opt', '--libdir', '/opt/lib32']
self.init(testdir, args)
self.wipe()
# libdir not being inside prefix is not ok
args = ['--prefix', '/usr', '--libdir', '/opt/lib32']
self.assertRaises(subprocess.CalledProcessError, self.init, testdir, args)
self.wipe()
# libdir must be inside prefix even when set via mesonconf
self.init(testdir)
self.assertRaises(subprocess.CalledProcessError, self.setconf, '-Dlibdir=/opt')
def test_installed_modes(self):
'''
Test that files installed by these tests have the correct permissions.
@ -722,47 +924,15 @@ class LinuxlikeTests(unittest.TestCase):
# 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):
def setUp(self):
super().setUp()
src_root = os.path.dirname(__file__)
self.testroot = tempfile.mkdtemp()
self.testroot = os.path.realpath(tempfile.mkdtemp())
self.rewrite_command = [sys.executable, os.path.join(src_root, 'mesonrewriter.py')]
self.tmpdir = tempfile.mkdtemp()
self.tmpdir = os.path.realpath(tempfile.mkdtemp())
self.workdir = os.path.join(self.tmpdir, 'foo')
self.test_dir = os.path.join(src_root, 'test cases/rewrite')
@ -785,34 +955,38 @@ class RewriterTests(unittest.TestCase):
def test_basic(self):
self.prime('1 basic')
subprocess.check_output(self.rewrite_command + ['remove',
'--target=trivialprog',
'--filename=notthere.c',
'--sourcedir', self.workdir])
subprocess.check_call(self.rewrite_command + ['remove',
'--target=trivialprog',
'--filename=notthere.c',
'--sourcedir', self.workdir],
universal_newlines=True)
self.check_effectively_same('meson.build', 'removed.txt')
subprocess.check_output(self.rewrite_command + ['add',
'--target=trivialprog',
'--filename=notthere.c',
'--sourcedir', self.workdir])
subprocess.check_call(self.rewrite_command + ['add',
'--target=trivialprog',
'--filename=notthere.c',
'--sourcedir', self.workdir],
universal_newlines=True)
self.check_effectively_same('meson.build', 'added.txt')
subprocess.check_output(self.rewrite_command + ['remove',
'--target=trivialprog',
'--filename=notthere.c',
'--sourcedir', self.workdir])
subprocess.check_call(self.rewrite_command + ['remove',
'--target=trivialprog',
'--filename=notthere.c',
'--sourcedir', self.workdir],
universal_newlines=True)
self.check_effectively_same('meson.build', 'removed.txt')
def test_subdir(self):
self.prime('2 subdirs')
top = self.read_contents('meson.build')
s2 = self.read_contents('sub2/meson.build')
subprocess.check_output(self.rewrite_command + ['remove',
'--target=something',
'--filename=second.c',
'--sourcedir', self.workdir])
subprocess.check_call(self.rewrite_command + ['remove',
'--target=something',
'--filename=second.c',
'--sourcedir', self.workdir],
universal_newlines=True)
self.check_effectively_same('sub1/meson.build', 'sub1/after.txt')
self.assertEqual(top, self.read_contents('meson.build'))
self.assertEqual(s2, self.read_contents('sub2/meson.build'))
if __name__ == '__main__':
unittest.main()
unittest.main(buffer=True)

@ -1,10 +1,25 @@
project('find program', 'c')
prog = find_program('program.py')
python = find_program('python3', required : false)
if not python.found()
python = find_program('python')
endif
run_command(python, prog.path())
# Source file via string
prog = find_program('program.py')
# Source file via files()
progf = files('program.py')
# Built file
py = configure_file(input : 'program.py',
output : 'builtprogram.py',
configuration : configuration_data())
foreach f : [prog, find_program(py), find_program(progf)]
ret = run_command(python, f.path())
assert(ret.returncode() == 0, 'can\'t manually run @0@'.format(prog.path()))
assert(ret.stdout().strip() == 'Found', 'wrong output from manually-run @0@'.format(prog.path()))
ret = run_command(f)
assert(ret.returncode() == 0, 'can\'t run @0@'.format(prog.path()))
assert(ret.stdout().strip() == 'Found', 'wrong output from @0@'.format(prog.path()))
endforeach

@ -1,8 +1,17 @@
project('pathjoin', 'c')
# Test string-args form since that is the canonical way
assert(join_paths('foo') == 'foo', 'Single argument join is broken')
assert(join_paths('foo', 'bar') == 'foo/bar', 'Path joining is broken')
assert(join_paths('foo', 'bar', 'baz') == 'foo/bar/baz', 'Path joining is broken')
assert(join_paths('/foo', 'bar') == '/foo/bar', 'Path joining is broken')
assert(join_paths('foo', '/bar') == '/bar', 'Absolute path joining is broken')
assert(join_paths('/foo', '/bar') == '/bar', 'Absolute path joining is broken')
# Test array form since people are using that too
assert(join_paths(['foo']) == 'foo', 'Single argument join is broken')
assert(join_paths(['foo', 'bar']) == 'foo/bar', 'Path joining is broken')
assert(join_paths(['foo', 'bar', 'baz']) == 'foo/bar/baz', 'Path joining is broken')
assert(join_paths(['/foo', 'bar']) == '/foo/bar', 'Path joining is broken')
assert(join_paths(['foo', '/bar']) == '/bar', 'Absolute path joining is broken')
assert(join_paths(['/foo', '/bar']) == '/bar', 'Absolute path joining is broken')

@ -0,0 +1,3 @@
int libfunc2() {
return 4;
}

@ -1,3 +1,4 @@
project('static library test', 'c')
lib = static_library('mylib', 'libfile.c',
lib = static_library('mylib', get_option('source'),
link_args : '-THISMUSTNOBEUSED') # Static linker needs to ignore all link args.

@ -0,0 +1 @@
option('source', type : 'combo', choices : ['libfile.c', 'libfile2.c'], value : 'libfile.c')

@ -1,4 +1,5 @@
project('default options', 'cpp', 'c', default_options : [
'prefix=/absoluteprefix',
'buildtype=debugoptimized',
'cpp_std=c++11',
'cpp_eh=none',

@ -1,4 +1,12 @@
project('find program', 'c')
# Test that we can find native windows executables
find_program('cmd')
find_program('cmd.exe')
# Test that a script file with an extension can be found
ext = find_program('test-script-ext.py')
test('ext', ext)
# Test that a script file without an extension can be found
prog = find_program('test-script')
test('script', prog)

@ -0,0 +1,3 @@
#!/usr/bin/env python3
print('ext/noext')
Loading…
Cancel
Save