Merge pull request #2863 from jon-turney/exit-status-on-exception

Verify that failing tests are failing with an error, not a python exception
This commit is contained in:
Jussi Pakkanen 2018-02-18 13:54:50 +02:00 committed by GitHub
commit 55a7c265c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 75 additions and 9 deletions

View File

@ -146,3 +146,9 @@ Meson has a standard command line help feature. It can be accessed
with the following command. with the following command.
meson --help meson --help
Exit status
==
Meson exits with status 0 if successful, 1 for problems with the command line or
meson.build file, and 2 for internal errors.

View File

@ -202,6 +202,19 @@ show available versions of the specified project
\fBstatus\fR \fBstatus\fR
show installed and available versions of currently used subprojects show installed and available versions of currently used subprojects
.SH EXIT STATUS
.TP
.B 0
Successful.
.TP
.B 1
Usage error, or an error parsing or executing meson.build.
.TP
.B 2
Internal error.
.TP
.SH SEE ALSO .SH SEE ALSO
http://mesonbuild.com/ http://mesonbuild.com/

View File

@ -695,10 +695,11 @@ class Environment:
for compiler in compilers: for compiler in compilers:
if isinstance(compiler, str): if isinstance(compiler, str):
compiler = [compiler] compiler = [compiler]
arg = ['--version']
try: try:
p, out = Popen_safe(compiler + ['--version'])[0:2] p, out = Popen_safe(compiler + arg)[0:2]
except OSError as e: except OSError as e:
popen_exceptions[compiler] = e popen_exceptions[' '.join(compiler + arg)] = e
continue continue
version = search_version(out) version = search_version(out)

View File

@ -1504,6 +1504,8 @@ class Interpreter(InterpreterBase):
'test': self.func_test, 'test': self.func_test,
'vcs_tag': self.func_vcs_tag, 'vcs_tag': self.func_vcs_tag,
}) })
if 'MESON_UNIT_TEST' in os.environ:
self.funcs.update({'exception': self.func_exception})
def holderify(self, item): def holderify(self, item):
if isinstance(item, list): if isinstance(item, list):
@ -1984,6 +1986,11 @@ to directly access options of other subprojects.''')
self.validate_arguments(args, 1, [str]) self.validate_arguments(args, 1, [str])
raise InterpreterException('Problem encountered: ' + args[0]) raise InterpreterException('Problem encountered: ' + args[0])
@noKwargs
def func_exception(self, node, args, kwargs):
self.validate_arguments(args, 0, [])
raise Exception()
def detect_compilers(self, lang, need_cross_compiler): def detect_compilers(self, lang, need_cross_compiler):
cross_comp = None cross_comp = None
if lang == 'c': if lang == 'c':

View File

@ -267,9 +267,8 @@ class InterpreterBase:
def validate_comparison_types(self, val1, val2): def validate_comparison_types(self, val1, val2):
if type(val1) != type(val2): if type(val1) != type(val2):
mlog.warning('''Trying to compare values of different types ({}, {}). return False
The result of this is undefined and will become a hard error return True
in a future Meson release.'''.format(type(val1).__name__, type(val2).__name__))
def evaluate_comparison(self, node): def evaluate_comparison(self, node):
val1 = self.evaluate_statement(node.left) val1 = self.evaluate_statement(node.left)
@ -278,11 +277,23 @@ in a future Meson release.'''.format(type(val1).__name__, type(val2).__name__))
val2 = self.evaluate_statement(node.right) val2 = self.evaluate_statement(node.right)
if is_disabler(val2): if is_disabler(val2):
return val2 return val2
self.validate_comparison_types(val1, val2) valid = self.validate_comparison_types(val1, val2)
# Ordering comparisons of different types isn't allowed since PR #1810
# (0.41.0). Since PR #2884 we also warn about equality comparisons of
# different types, which will one day become an error.
if not valid and (node.ctype == '==' or node.ctype == '!='):
mlog.warning('''Trying to compare values of different types ({}, {}) using {}.
The result of this is undefined and will become a hard error in a future Meson release.'''
.format(type(val1).__name__, type(val2).__name__, node.ctype), location=node)
if node.ctype == '==': if node.ctype == '==':
return val1 == val2 return val1 == val2
elif node.ctype == '!=': elif node.ctype == '!=':
return val1 != val2 return val1 != val2
elif not valid:
raise InterpreterException(
'Values of different types ({}, {}) cannot be compared using {}.'.format(type(val1).__name__,
type(val2).__name__,
node.ctype))
elif not self.is_elementary_type(val1): elif not self.is_elementary_type(val1):
raise InterpreterException('{} can only be compared for equality.'.format(node.left.value)) raise InterpreterException('{} can only be compared for equality.'.format(node.left.value))
elif not self.is_elementary_type(val2): elif not self.is_elementary_type(val2):

View File

@ -376,11 +376,12 @@ def run(original_args, mainfile=None):
mlog.log("\nA full log can be found at", mlog.bold(logfile)) mlog.log("\nA full log can be found at", mlog.bold(logfile))
if os.environ.get('MESON_FORCE_BACKTRACE'): if os.environ.get('MESON_FORCE_BACKTRACE'):
raise raise
return 1
else: else:
if os.environ.get('MESON_FORCE_BACKTRACE'): if os.environ.get('MESON_FORCE_BACKTRACE'):
raise raise
traceback.print_exc() traceback.print_exc()
return 1 return 2
finally: finally:
mlog.shutdown() mlog.shutdown()

View File

@ -321,9 +321,12 @@ def _run_test(testdir, test_build_dir, install_dir, extra_args, compiler, backen
mesonlog = no_meson_log_msg mesonlog = no_meson_log_msg
gen_time = time.time() - gen_start gen_time = time.time() - gen_start
if should_fail == 'meson': if should_fail == 'meson':
if returncode != 0: if returncode == 1:
return TestResult('', BuildStep.configure, stdo, stde, mesonlog, gen_time) return TestResult('', BuildStep.configure, stdo, stde, mesonlog, gen_time)
return TestResult('Test that should have failed succeeded', BuildStep.configure, stdo, stde, mesonlog, gen_time) elif returncode != 0:
return TestResult('Test exited with unexpected status {}'.format(returncode), BuildStep.configure, stdo, stde, mesonlog, gen_time)
else:
return TestResult('Test that should have failed succeeded', BuildStep.configure, stdo, stde, mesonlog, gen_time)
if returncode != 0: if returncode != 0:
return TestResult('Generating the build system failed.', BuildStep.configure, stdo, stde, mesonlog, gen_time) return TestResult('Generating the build system failed.', BuildStep.configure, stdo, stde, mesonlog, gen_time)
# Touch the meson.build file to force a regenerate so we can test that # Touch the meson.build file to force a regenerate so we can test that

View File

@ -1933,6 +1933,17 @@ class FailureTests(BasePlatformTests):
self.assertRegex(out, r'Also couldn\'t find a fallback subproject in ' self.assertRegex(out, r'Also couldn\'t find a fallback subproject in '
'.*subprojects.*failingsubproj.*for the dependency.*somedep') '.*subprojects.*failingsubproj.*for the dependency.*somedep')
def test_exception_exit_status(self):
'''
Test exit status on python exception
'''
tdir = os.path.join(self.unit_test_dir, '21 exit status')
os.environ['MESON_UNIT_TEST'] = '1'
with self.assertRaises(subprocess.CalledProcessError) as cm:
self.init(tdir, inprocess=False)
self.assertEqual(cm.exception.returncode, 2)
self.wipe()
class WindowsTests(BasePlatformTests): class WindowsTests(BasePlatformTests):
''' '''

View File

@ -126,3 +126,14 @@ test('equalfalse', exe13)
test('equaltrue', exe14) test('equaltrue', exe14)
test('nequaltrue', exe15) test('nequaltrue', exe15)
test('nequalfalse', exe16) test('nequalfalse', exe16)
# Equality comparisons of different elementary types
# (these all cause warnings currently, will become an error in future)
assert([] != 'st', 'not equal')
assert([] != 1, 'not equal')
assert(2 != 'st', 'not equal')
assert(not ([] == 'st'), 'not equal')
assert(not ([] == 1), 'not equal')
assert(not (2 == 'st'), 'not equal')

View File

@ -0,0 +1,2 @@
project('exit status')
exception()