2021-07-25 06:31:45 +08:00
# Copyright 2016-2021 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.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
2021-09-01 02:06:36 +08:00
from configparser import ConfigParser
2021-11-24 06:57:08 +08:00
from mesonbuild . mesonlib . universal import OptionType
2021-09-01 02:06:36 +08:00
from pathlib import Path
from unittest import mock
2021-08-31 01:28:13 +08:00
import contextlib
2021-09-01 02:06:36 +08:00
import io
import json
import operator
import os
import pickle
2021-07-25 06:31:45 +08:00
import stat
import subprocess
import tempfile
import typing as T
2021-07-30 06:36:13 +08:00
import unittest
2021-07-25 06:31:45 +08:00
import mesonbuild . mlog
import mesonbuild . depfile
import mesonbuild . dependencies . base
import mesonbuild . dependencies . factory
import mesonbuild . compilers
import mesonbuild . envconfig
import mesonbuild . environment
import mesonbuild . modules . gnome
2021-09-15 21:52:07 +08:00
from mesonbuild import coredata
2021-07-25 06:31:45 +08:00
from mesonbuild . interpreterbase import typed_pos_args , InvalidArguments , ObjectHolder
from mesonbuild . interpreterbase import typed_pos_args , InvalidArguments , typed_kwargs , ContainerTypeInfo , KwargInfo
from mesonbuild . mesonlib import (
LibType , MachineChoice , PerMachine , Version , is_windows , is_osx ,
is_cygwin , is_openbsd , search_version , MesonException , OptionKey ,
)
2021-08-27 23:32:42 +08:00
from mesonbuild . interpreter . type_checking import in_set_validator , NoneType
2021-07-25 06:31:45 +08:00
from mesonbuild . dependencies import PkgConfigDependency
from mesonbuild . programs import ExternalProgram
import mesonbuild . modules . pkgconfig
from run_tests import (
FakeCompilerOptions , get_fake_env , get_fake_options
)
from . helpers import *
class InternalTests ( unittest . TestCase ) :
def test_version_number ( self ) :
self . assertEqual ( search_version ( ' foobar 1.2.3 ' ) , ' 1.2.3 ' )
self . assertEqual ( search_version ( ' 1.2.3 ' ) , ' 1.2.3 ' )
self . assertEqual ( search_version ( ' foobar 2016.10.28 1.2.3 ' ) , ' 1.2.3 ' )
self . assertEqual ( search_version ( ' 2016.10.28 1.2.3 ' ) , ' 1.2.3 ' )
self . assertEqual ( search_version ( ' foobar 2016.10.128 ' ) , ' 2016.10.128 ' )
self . assertEqual ( search_version ( ' 2016.10.128 ' ) , ' 2016.10.128 ' )
self . assertEqual ( search_version ( ' 2016.10 ' ) , ' 2016.10 ' )
self . assertEqual ( search_version ( ' 2016.10 1.2.3 ' ) , ' 1.2.3 ' )
self . assertEqual ( search_version ( ' oops v1.2.3 ' ) , ' 1.2.3 ' )
self . assertEqual ( search_version ( ' 2016.oops 1.2.3 ' ) , ' 1.2.3 ' )
self . assertEqual ( search_version ( ' 2016.x ' ) , ' unknown version ' )
2021-07-30 06:36:13 +08:00
self . assertEqual ( search_version ( r ' something version is \ 033[32;2m1.2.0 \ 033[0m. ' ) , ' 1.2.0 ' )
# Literal output of mvn
self . assertEqual ( search_version ( r ''' \
\033 [ 1 mApache Maven 3.8 .1 ( 05 c21c65bdfed0f71a2f2ada8b84da59348c4c5d ) \033 [ 0 m
Maven home : / nix / store / g84a9wnid2h1d3z2wfydy16dky73wh7i - apache - maven - 3.8 .1 / maven
Java version : 11.0 .10 , vendor : Oracle Corporation , runtime : / nix / store / afsnl4ahmm9svvl7s1a0cj41vw4nkmz4 - openjdk - 11.0 .10 + 9 / lib / openjdk
Default locale : en_US , platform encoding : UTF - 8
OS name : " linux " , version : " 5.12.17 " , arch : " amd64 " , family : " unix " ''' ),
' 3.8.1 ' )
2021-07-25 06:31:45 +08:00
def test_mode_symbolic_to_bits ( self ) :
modefunc = mesonbuild . mesonlib . FileMode . perms_s_to_bits
self . assertEqual ( modefunc ( ' --------- ' ) , 0 )
self . assertEqual ( modefunc ( ' r-------- ' ) , stat . S_IRUSR )
self . assertEqual ( modefunc ( ' ---r----- ' ) , stat . S_IRGRP )
self . assertEqual ( modefunc ( ' ------r-- ' ) , stat . S_IROTH )
self . assertEqual ( modefunc ( ' -w------- ' ) , stat . S_IWUSR )
self . assertEqual ( modefunc ( ' ----w---- ' ) , stat . S_IWGRP )
self . assertEqual ( modefunc ( ' -------w- ' ) , stat . S_IWOTH )
self . assertEqual ( modefunc ( ' --x------ ' ) , stat . S_IXUSR )
self . assertEqual ( modefunc ( ' -----x--- ' ) , stat . S_IXGRP )
self . assertEqual ( modefunc ( ' --------x ' ) , stat . S_IXOTH )
self . assertEqual ( modefunc ( ' --S------ ' ) , stat . S_ISUID )
self . assertEqual ( modefunc ( ' -----S--- ' ) , stat . S_ISGID )
self . assertEqual ( modefunc ( ' --------T ' ) , stat . S_ISVTX )
self . assertEqual ( modefunc ( ' --s------ ' ) , stat . S_ISUID | stat . S_IXUSR )
self . assertEqual ( modefunc ( ' -----s--- ' ) , stat . S_ISGID | stat . S_IXGRP )
self . assertEqual ( modefunc ( ' --------t ' ) , stat . S_ISVTX | stat . S_IXOTH )
self . assertEqual ( modefunc ( ' rwx------ ' ) , stat . S_IRWXU )
self . assertEqual ( modefunc ( ' ---rwx--- ' ) , stat . S_IRWXG )
self . assertEqual ( modefunc ( ' ------rwx ' ) , stat . S_IRWXO )
# We could keep listing combinations exhaustively but that seems
# tedious and pointless. Just test a few more.
self . assertEqual ( modefunc ( ' rwxr-xr-x ' ) ,
stat . S_IRWXU |
stat . S_IRGRP | stat . S_IXGRP |
stat . S_IROTH | stat . S_IXOTH )
self . assertEqual ( modefunc ( ' rw-r--r-- ' ) ,
stat . S_IRUSR | stat . S_IWUSR |
stat . S_IRGRP |
stat . S_IROTH )
self . assertEqual ( modefunc ( ' rwsr-x--- ' ) ,
stat . S_IRWXU | stat . S_ISUID |
stat . S_IRGRP | stat . S_IXGRP )
def test_compiler_args_class_none_flush ( self ) :
cc = mesonbuild . compilers . ClangCCompiler ( [ ] , ' fake ' , MachineChoice . HOST , False , mock . Mock ( ) )
a = cc . compiler_args ( [ ' -I. ' ] )
#first we are checking if the tree construction deduplicates the correct -I argument
a + = [ ' -I.. ' ]
a + = [ ' -I./tests/ ' ]
a + = [ ' -I./tests2/ ' ]
#think this here as assertion, we cannot apply it, otherwise the CompilerArgs would already flush the changes:
# assertEqual(a, ['-I.', '-I./tests2/', '-I./tests/', '-I..', '-I.'])
a + = [ ' -I. ' ]
a + = [ ' -I. ' , ' -I./tests/ ' ]
self . assertEqual ( a , [ ' -I. ' , ' -I./tests/ ' , ' -I./tests2/ ' , ' -I.. ' ] )
#then we are checking that when CompilerArgs already have a build container list, that the deduplication is taking the correct one
a + = [ ' -I. ' , ' -I./tests2/ ' ]
self . assertEqual ( a , [ ' -I. ' , ' -I./tests2/ ' , ' -I./tests/ ' , ' -I.. ' ] )
def test_compiler_args_class_d ( self ) :
d = mesonbuild . compilers . DmdDCompiler ( [ ] , ' fake ' , MachineChoice . HOST , ' info ' , ' arch ' )
# check include order is kept when deduplicating
a = d . compiler_args ( [ ' -Ifirst ' , ' -Isecond ' , ' -Ithird ' ] )
a + = [ ' -Ifirst ' ]
self . assertEqual ( a , [ ' -Ifirst ' , ' -Isecond ' , ' -Ithird ' ] )
def test_compiler_args_class_clike ( self ) :
cc = mesonbuild . compilers . ClangCCompiler ( [ ] , ' fake ' , MachineChoice . HOST , False , mock . Mock ( ) )
# Test that empty initialization works
a = cc . compiler_args ( )
self . assertEqual ( a , [ ] )
# Test that list initialization works
a = cc . compiler_args ( [ ' -I. ' , ' -I.. ' ] )
self . assertEqual ( a , [ ' -I. ' , ' -I.. ' ] )
# Test that there is no de-dup on initialization
self . assertEqual ( cc . compiler_args ( [ ' -I. ' , ' -I. ' ] ) , [ ' -I. ' , ' -I. ' ] )
## Test that appending works
a . append ( ' -I.. ' )
self . assertEqual ( a , [ ' -I.. ' , ' -I. ' ] )
a . append ( ' -O3 ' )
self . assertEqual ( a , [ ' -I.. ' , ' -I. ' , ' -O3 ' ] )
## Test that in-place addition works
a + = [ ' -O2 ' , ' -O2 ' ]
self . assertEqual ( a , [ ' -I.. ' , ' -I. ' , ' -O3 ' , ' -O2 ' , ' -O2 ' ] )
# Test that removal works
a . remove ( ' -O2 ' )
self . assertEqual ( a , [ ' -I.. ' , ' -I. ' , ' -O3 ' , ' -O2 ' ] )
# Test that de-dup happens on addition
a + = [ ' -Ifoo ' , ' -Ifoo ' ]
self . assertEqual ( a , [ ' -Ifoo ' , ' -I.. ' , ' -I. ' , ' -O3 ' , ' -O2 ' ] )
# .extend() is just +=, so we don't test it
## Test that addition works
# Test that adding a list with just one old arg works and yields the same array
a = a + [ ' -Ifoo ' ]
self . assertEqual ( a , [ ' -Ifoo ' , ' -I.. ' , ' -I. ' , ' -O3 ' , ' -O2 ' ] )
# Test that adding a list with one arg new and one old works
a = a + [ ' -Ifoo ' , ' -Ibaz ' ]
self . assertEqual ( a , [ ' -Ifoo ' , ' -Ibaz ' , ' -I.. ' , ' -I. ' , ' -O3 ' , ' -O2 ' ] )
# Test that adding args that must be prepended and appended works
a = a + [ ' -Ibar ' , ' -Wall ' ]
self . assertEqual ( a , [ ' -Ibar ' , ' -Ifoo ' , ' -Ibaz ' , ' -I.. ' , ' -I. ' , ' -O3 ' , ' -O2 ' , ' -Wall ' ] )
## Test that reflected addition works
# Test that adding to a list with just one old arg works and yields the same array
a = [ ' -Ifoo ' ] + a
self . assertEqual ( a , [ ' -Ibar ' , ' -Ifoo ' , ' -Ibaz ' , ' -I.. ' , ' -I. ' , ' -O3 ' , ' -O2 ' , ' -Wall ' ] )
# Test that adding to a list with just one new arg that is not pre-pended works
a = [ ' -Werror ' ] + a
self . assertEqual ( a , [ ' -Ibar ' , ' -Ifoo ' , ' -Ibaz ' , ' -I.. ' , ' -I. ' , ' -Werror ' , ' -O3 ' , ' -O2 ' , ' -Wall ' ] )
# Test that adding to a list with two new args preserves the order
a = [ ' -Ldir ' , ' -Lbah ' ] + a
self . assertEqual ( a , [ ' -Ibar ' , ' -Ifoo ' , ' -Ibaz ' , ' -I.. ' , ' -I. ' , ' -Ldir ' , ' -Lbah ' , ' -Werror ' , ' -O3 ' , ' -O2 ' , ' -Wall ' ] )
# Test that adding to a list with old args does nothing
a = [ ' -Ibar ' , ' -Ibaz ' , ' -Ifoo ' ] + a
self . assertEqual ( a , [ ' -Ibar ' , ' -Ifoo ' , ' -Ibaz ' , ' -I.. ' , ' -I. ' , ' -Ldir ' , ' -Lbah ' , ' -Werror ' , ' -O3 ' , ' -O2 ' , ' -Wall ' ] )
## Test that adding libraries works
l = cc . compiler_args ( [ ' -Lfoodir ' , ' -lfoo ' ] )
self . assertEqual ( l , [ ' -Lfoodir ' , ' -lfoo ' ] )
# Adding a library and a libpath appends both correctly
l + = [ ' -Lbardir ' , ' -lbar ' ]
self . assertEqual ( l , [ ' -Lbardir ' , ' -Lfoodir ' , ' -lfoo ' , ' -lbar ' ] )
# Adding the same library again does nothing
l + = [ ' -lbar ' ]
self . assertEqual ( l , [ ' -Lbardir ' , ' -Lfoodir ' , ' -lfoo ' , ' -lbar ' ] )
## Test that 'direct' append and extend works
l = cc . compiler_args ( [ ' -Lfoodir ' , ' -lfoo ' ] )
self . assertEqual ( l , [ ' -Lfoodir ' , ' -lfoo ' ] )
# Direct-adding a library and a libpath appends both correctly
l . extend_direct ( [ ' -Lbardir ' , ' -lbar ' ] )
self . assertEqual ( l , [ ' -Lfoodir ' , ' -lfoo ' , ' -Lbardir ' , ' -lbar ' ] )
# Direct-adding the same library again still adds it
l . append_direct ( ' -lbar ' )
self . assertEqual ( l , [ ' -Lfoodir ' , ' -lfoo ' , ' -Lbardir ' , ' -lbar ' , ' -lbar ' ] )
# Direct-adding with absolute path deduplicates
l . append_direct ( ' /libbaz.a ' )
self . assertEqual ( l , [ ' -Lfoodir ' , ' -lfoo ' , ' -Lbardir ' , ' -lbar ' , ' -lbar ' , ' /libbaz.a ' ] )
# Adding libbaz again does nothing
l . append_direct ( ' /libbaz.a ' )
self . assertEqual ( l , [ ' -Lfoodir ' , ' -lfoo ' , ' -Lbardir ' , ' -lbar ' , ' -lbar ' , ' /libbaz.a ' ] )
def test_compiler_args_class_gnuld ( self ) :
## Test --start/end-group
linker = mesonbuild . linkers . GnuBFDDynamicLinker ( [ ] , MachineChoice . HOST , ' -Wl, ' , [ ] )
gcc = mesonbuild . compilers . GnuCCompiler ( [ ] , ' fake ' , False , MachineChoice . HOST , mock . Mock ( ) , linker = linker )
## Ensure that the fake compiler is never called by overriding the relevant function
gcc . get_default_include_dirs = lambda : [ ' /usr/include ' , ' /usr/share/include ' , ' /usr/local/include ' ]
## Test that 'direct' append and extend works
l = gcc . compiler_args ( [ ' -Lfoodir ' , ' -lfoo ' ] )
self . assertEqual ( l . to_native ( copy = True ) , [ ' -Lfoodir ' , ' -Wl,--start-group ' , ' -lfoo ' , ' -Wl,--end-group ' ] )
# Direct-adding a library and a libpath appends both correctly
l . extend_direct ( [ ' -Lbardir ' , ' -lbar ' ] )
self . assertEqual ( l . to_native ( copy = True ) , [ ' -Lfoodir ' , ' -Wl,--start-group ' , ' -lfoo ' , ' -Lbardir ' , ' -lbar ' , ' -Wl,--end-group ' ] )
# Direct-adding the same library again still adds it
l . append_direct ( ' -lbar ' )
self . assertEqual ( l . to_native ( copy = True ) , [ ' -Lfoodir ' , ' -Wl,--start-group ' , ' -lfoo ' , ' -Lbardir ' , ' -lbar ' , ' -lbar ' , ' -Wl,--end-group ' ] )
# Direct-adding with absolute path deduplicates
l . append_direct ( ' /libbaz.a ' )
self . assertEqual ( l . to_native ( copy = True ) , [ ' -Lfoodir ' , ' -Wl,--start-group ' , ' -lfoo ' , ' -Lbardir ' , ' -lbar ' , ' -lbar ' , ' /libbaz.a ' , ' -Wl,--end-group ' ] )
# Adding libbaz again does nothing
l . append_direct ( ' /libbaz.a ' )
self . assertEqual ( l . to_native ( copy = True ) , [ ' -Lfoodir ' , ' -Wl,--start-group ' , ' -lfoo ' , ' -Lbardir ' , ' -lbar ' , ' -lbar ' , ' /libbaz.a ' , ' -Wl,--end-group ' ] )
# Adding a non-library argument doesn't include it in the group
l + = [ ' -Lfoo ' , ' -Wl,--export-dynamic ' ]
self . assertEqual ( l . to_native ( copy = True ) , [ ' -Lfoo ' , ' -Lfoodir ' , ' -Wl,--start-group ' , ' -lfoo ' , ' -Lbardir ' , ' -lbar ' , ' -lbar ' , ' /libbaz.a ' , ' -Wl,--end-group ' , ' -Wl,--export-dynamic ' ] )
# -Wl,-lfoo is detected as a library and gets added to the group
l . append ( ' -Wl,-ldl ' )
self . assertEqual ( l . to_native ( copy = True ) , [ ' -Lfoo ' , ' -Lfoodir ' , ' -Wl,--start-group ' , ' -lfoo ' , ' -Lbardir ' , ' -lbar ' , ' -lbar ' , ' /libbaz.a ' , ' -Wl,--export-dynamic ' , ' -Wl,-ldl ' , ' -Wl,--end-group ' ] )
def test_compiler_args_remove_system ( self ) :
## Test --start/end-group
linker = mesonbuild . linkers . GnuBFDDynamicLinker ( [ ] , MachineChoice . HOST , ' -Wl, ' , [ ] )
gcc = mesonbuild . compilers . GnuCCompiler ( [ ] , ' fake ' , False , MachineChoice . HOST , mock . Mock ( ) , linker = linker )
## Ensure that the fake compiler is never called by overriding the relevant function
gcc . get_default_include_dirs = lambda : [ ' /usr/include ' , ' /usr/share/include ' , ' /usr/local/include ' ]
## Test that 'direct' append and extend works
l = gcc . compiler_args ( [ ' -Lfoodir ' , ' -lfoo ' ] )
self . assertEqual ( l . to_native ( copy = True ) , [ ' -Lfoodir ' , ' -Wl,--start-group ' , ' -lfoo ' , ' -Wl,--end-group ' ] )
## Test that to_native removes all system includes
l + = [ ' -isystem/usr/include ' , ' -isystem=/usr/share/include ' , ' -DSOMETHING_IMPORTANT=1 ' , ' -isystem ' , ' /usr/local/include ' ]
self . assertEqual ( l . to_native ( copy = True ) , [ ' -Lfoodir ' , ' -Wl,--start-group ' , ' -lfoo ' , ' -Wl,--end-group ' , ' -DSOMETHING_IMPORTANT=1 ' ] )
def test_string_templates_substitution ( self ) :
dictfunc = mesonbuild . mesonlib . get_filenames_templates_dict
substfunc = mesonbuild . mesonlib . substitute_values
ME = mesonbuild . mesonlib . MesonException
# Identity
self . assertEqual ( dictfunc ( [ ] , [ ] ) , { } )
# One input, no outputs
inputs = [ ' bar/foo.c.in ' ]
outputs = [ ]
ret = dictfunc ( inputs , outputs )
d = { ' @INPUT@ ' : inputs , ' @INPUT0@ ' : inputs [ 0 ] ,
' @PLAINNAME@ ' : ' foo.c.in ' , ' @BASENAME@ ' : ' foo.c ' }
# Check dictionary
self . assertEqual ( ret , d )
# Check substitutions
cmd = [ ' some ' , ' ordinary ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) , cmd )
cmd = [ ' @INPUT@.out ' , ' ordinary ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) , [ inputs [ 0 ] + ' .out ' ] + cmd [ 1 : ] )
cmd = [ ' @INPUT0@.out ' , ' @PLAINNAME@.ok ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) ,
[ inputs [ 0 ] + ' .out ' ] + [ d [ ' @PLAINNAME@ ' ] + ' .ok ' ] + cmd [ 2 : ] )
cmd = [ ' @INPUT@ ' , ' @BASENAME@.hah ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) ,
inputs + [ d [ ' @BASENAME@ ' ] + ' .hah ' ] + cmd [ 2 : ] )
cmd = [ ' @OUTPUT@ ' ]
self . assertRaises ( ME , substfunc , cmd , d )
# One input, one output
inputs = [ ' bar/foo.c.in ' ]
outputs = [ ' out.c ' ]
ret = dictfunc ( inputs , outputs )
d = { ' @INPUT@ ' : inputs , ' @INPUT0@ ' : inputs [ 0 ] ,
' @PLAINNAME@ ' : ' foo.c.in ' , ' @BASENAME@ ' : ' foo.c ' ,
' @OUTPUT@ ' : outputs , ' @OUTPUT0@ ' : outputs [ 0 ] , ' @OUTDIR@ ' : ' . ' }
# Check dictionary
self . assertEqual ( ret , d )
# Check substitutions
cmd = [ ' some ' , ' ordinary ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) , cmd )
cmd = [ ' @INPUT@.out ' , ' @OUTPUT@ ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) ,
[ inputs [ 0 ] + ' .out ' ] + outputs + cmd [ 2 : ] )
cmd = [ ' @INPUT0@.out ' , ' @PLAINNAME@.ok ' , ' @OUTPUT0@ ' ]
self . assertEqual ( substfunc ( cmd , d ) ,
[ inputs [ 0 ] + ' .out ' , d [ ' @PLAINNAME@ ' ] + ' .ok ' ] + outputs )
cmd = [ ' @INPUT@ ' , ' @BASENAME@.hah ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) ,
inputs + [ d [ ' @BASENAME@ ' ] + ' .hah ' ] + cmd [ 2 : ] )
# One input, one output with a subdir
outputs = [ ' dir/out.c ' ]
ret = dictfunc ( inputs , outputs )
d = { ' @INPUT@ ' : inputs , ' @INPUT0@ ' : inputs [ 0 ] ,
' @PLAINNAME@ ' : ' foo.c.in ' , ' @BASENAME@ ' : ' foo.c ' ,
' @OUTPUT@ ' : outputs , ' @OUTPUT0@ ' : outputs [ 0 ] , ' @OUTDIR@ ' : ' dir ' }
# Check dictionary
self . assertEqual ( ret , d )
# Two inputs, no outputs
inputs = [ ' bar/foo.c.in ' , ' baz/foo.c.in ' ]
outputs = [ ]
ret = dictfunc ( inputs , outputs )
d = { ' @INPUT@ ' : inputs , ' @INPUT0@ ' : inputs [ 0 ] , ' @INPUT1@ ' : inputs [ 1 ] }
# Check dictionary
self . assertEqual ( ret , d )
# Check substitutions
cmd = [ ' some ' , ' ordinary ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) , cmd )
cmd = [ ' @INPUT@ ' , ' ordinary ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) , inputs + cmd [ 1 : ] )
cmd = [ ' @INPUT0@.out ' , ' ordinary ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) , [ inputs [ 0 ] + ' .out ' ] + cmd [ 1 : ] )
cmd = [ ' @INPUT0@.out ' , ' @INPUT1@.ok ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) , [ inputs [ 0 ] + ' .out ' , inputs [ 1 ] + ' .ok ' ] + cmd [ 2 : ] )
cmd = [ ' @INPUT0@ ' , ' @INPUT1@ ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) , inputs + cmd [ 2 : ] )
# Many inputs, can't use @INPUT@ like this
cmd = [ ' @INPUT@.out ' , ' ordinary ' , ' strings ' ]
self . assertRaises ( ME , substfunc , cmd , d )
# Not enough inputs
cmd = [ ' @INPUT2@.out ' , ' ordinary ' , ' strings ' ]
self . assertRaises ( ME , substfunc , cmd , d )
# Too many inputs
cmd = [ ' @PLAINNAME@ ' ]
self . assertRaises ( ME , substfunc , cmd , d )
cmd = [ ' @BASENAME@ ' ]
self . assertRaises ( ME , substfunc , cmd , d )
# No outputs
cmd = [ ' @OUTPUT@ ' ]
self . assertRaises ( ME , substfunc , cmd , d )
cmd = [ ' @OUTPUT0@ ' ]
self . assertRaises ( ME , substfunc , cmd , d )
cmd = [ ' @OUTDIR@ ' ]
self . assertRaises ( ME , substfunc , cmd , d )
# Two inputs, one output
outputs = [ ' dir/out.c ' ]
ret = dictfunc ( inputs , outputs )
d = { ' @INPUT@ ' : inputs , ' @INPUT0@ ' : inputs [ 0 ] , ' @INPUT1@ ' : inputs [ 1 ] ,
' @OUTPUT@ ' : outputs , ' @OUTPUT0@ ' : outputs [ 0 ] , ' @OUTDIR@ ' : ' dir ' }
# Check dictionary
self . assertEqual ( ret , d )
# Check substitutions
cmd = [ ' some ' , ' ordinary ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) , cmd )
cmd = [ ' @OUTPUT@ ' , ' ordinary ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) , outputs + cmd [ 1 : ] )
cmd = [ ' @OUTPUT@.out ' , ' ordinary ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) , [ outputs [ 0 ] + ' .out ' ] + cmd [ 1 : ] )
cmd = [ ' @OUTPUT0@.out ' , ' @INPUT1@.ok ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) , [ outputs [ 0 ] + ' .out ' , inputs [ 1 ] + ' .ok ' ] + cmd [ 2 : ] )
# Many inputs, can't use @INPUT@ like this
cmd = [ ' @INPUT@.out ' , ' ordinary ' , ' strings ' ]
self . assertRaises ( ME , substfunc , cmd , d )
# Not enough inputs
cmd = [ ' @INPUT2@.out ' , ' ordinary ' , ' strings ' ]
self . assertRaises ( ME , substfunc , cmd , d )
# Not enough outputs
cmd = [ ' @OUTPUT2@.out ' , ' ordinary ' , ' strings ' ]
self . assertRaises ( ME , substfunc , cmd , d )
# Two inputs, two outputs
outputs = [ ' dir/out.c ' , ' dir/out2.c ' ]
ret = dictfunc ( inputs , outputs )
d = { ' @INPUT@ ' : inputs , ' @INPUT0@ ' : inputs [ 0 ] , ' @INPUT1@ ' : inputs [ 1 ] ,
' @OUTPUT@ ' : outputs , ' @OUTPUT0@ ' : outputs [ 0 ] , ' @OUTPUT1@ ' : outputs [ 1 ] ,
' @OUTDIR@ ' : ' dir ' }
# Check dictionary
self . assertEqual ( ret , d )
# Check substitutions
cmd = [ ' some ' , ' ordinary ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) , cmd )
cmd = [ ' @OUTPUT@ ' , ' ordinary ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) , outputs + cmd [ 1 : ] )
cmd = [ ' @OUTPUT0@ ' , ' @OUTPUT1@ ' , ' strings ' ]
self . assertEqual ( substfunc ( cmd , d ) , outputs + cmd [ 2 : ] )
cmd = [ ' @OUTPUT0@.out ' , ' @INPUT1@.ok ' , ' @OUTDIR@ ' ]
self . assertEqual ( substfunc ( cmd , d ) , [ outputs [ 0 ] + ' .out ' , inputs [ 1 ] + ' .ok ' , ' dir ' ] )
# Many inputs, can't use @INPUT@ like this
cmd = [ ' @INPUT@.out ' , ' ordinary ' , ' strings ' ]
self . assertRaises ( ME , substfunc , cmd , d )
# Not enough inputs
cmd = [ ' @INPUT2@.out ' , ' ordinary ' , ' strings ' ]
self . assertRaises ( ME , substfunc , cmd , d )
# Not enough outputs
cmd = [ ' @OUTPUT2@.out ' , ' ordinary ' , ' strings ' ]
self . assertRaises ( ME , substfunc , cmd , d )
# Many outputs, can't use @OUTPUT@ like this
cmd = [ ' @OUTPUT@.out ' , ' ordinary ' , ' strings ' ]
self . assertRaises ( ME , substfunc , cmd , d )
def test_needs_exe_wrapper_override ( self ) :
config = ConfigParser ( )
config [ ' binaries ' ] = {
' c ' : ' \' /usr/bin/gcc \' ' ,
}
config [ ' host_machine ' ] = {
' system ' : ' \' linux \' ' ,
' cpu_family ' : ' \' arm \' ' ,
' cpu ' : ' \' armv7 \' ' ,
' endian ' : ' \' little \' ' ,
}
# Can not be used as context manager because we need to
# open it a second time and this is not possible on
# Windows.
configfile = tempfile . NamedTemporaryFile ( mode = ' w+ ' , delete = False )
configfilename = configfile . name
config . write ( configfile )
configfile . flush ( )
configfile . close ( )
opts = get_fake_options ( )
opts . cross_file = ( configfilename , )
env = get_fake_env ( opts = opts )
detected_value = env . need_exe_wrapper ( )
os . unlink ( configfilename )
desired_value = not detected_value
config [ ' properties ' ] = {
' needs_exe_wrapper ' : ' true ' if desired_value else ' false '
}
configfile = tempfile . NamedTemporaryFile ( mode = ' w+ ' , delete = False )
configfilename = configfile . name
config . write ( configfile )
configfile . close ( )
opts = get_fake_options ( )
opts . cross_file = ( configfilename , )
env = get_fake_env ( opts = opts )
forced_value = env . need_exe_wrapper ( )
os . unlink ( configfilename )
self . assertEqual ( forced_value , desired_value )
def test_listify ( self ) :
listify = mesonbuild . mesonlib . listify
# Test sanity
self . assertEqual ( [ 1 ] , listify ( 1 ) )
self . assertEqual ( [ ] , listify ( [ ] ) )
self . assertEqual ( [ 1 ] , listify ( [ 1 ] ) )
# Test flattening
self . assertEqual ( [ 1 , 2 , 3 ] , listify ( [ 1 , [ 2 , 3 ] ] ) )
self . assertEqual ( [ 1 , 2 , 3 ] , listify ( [ 1 , [ 2 , [ 3 ] ] ] ) )
self . assertEqual ( [ 1 , [ 2 , [ 3 ] ] ] , listify ( [ 1 , [ 2 , [ 3 ] ] ] , flatten = False ) )
# Test flattening and unholdering
class TestHeldObj ( mesonbuild . mesonlib . HoldableObject ) :
def __init__ ( self , val : int ) - > None :
self . _val = val
class MockInterpreter :
def __init__ ( self ) - > None :
self . subproject = ' '
self . environment = None
heldObj1 = TestHeldObj ( 1 )
holder1 = ObjectHolder ( heldObj1 , MockInterpreter ( ) )
self . assertEqual ( [ holder1 ] , listify ( holder1 ) )
self . assertEqual ( [ holder1 ] , listify ( [ holder1 ] ) )
self . assertEqual ( [ holder1 , 2 ] , listify ( [ holder1 , 2 ] ) )
self . assertEqual ( [ holder1 , 2 , 3 ] , listify ( [ holder1 , 2 , [ 3 ] ] ) )
def test_extract_as_list ( self ) :
extract = mesonbuild . mesonlib . extract_as_list
# Test sanity
kwargs = { ' sources ' : [ 1 , 2 , 3 ] }
self . assertEqual ( [ 1 , 2 , 3 ] , extract ( kwargs , ' sources ' ) )
self . assertEqual ( kwargs , { ' sources ' : [ 1 , 2 , 3 ] } )
self . assertEqual ( [ 1 , 2 , 3 ] , extract ( kwargs , ' sources ' , pop = True ) )
self . assertEqual ( kwargs , { } )
class TestHeldObj ( mesonbuild . mesonlib . HoldableObject ) :
pass
class MockInterpreter :
def __init__ ( self ) - > None :
self . subproject = ' '
self . environment = None
heldObj = TestHeldObj ( )
# Test unholding
holder3 = ObjectHolder ( heldObj , MockInterpreter ( ) )
kwargs = { ' sources ' : [ 1 , 2 , holder3 ] }
self . assertEqual ( kwargs , { ' sources ' : [ 1 , 2 , holder3 ] } )
# flatten nested lists
kwargs = { ' sources ' : [ 1 , [ 2 , [ 3 ] ] ] }
self . assertEqual ( [ 1 , 2 , 3 ] , extract ( kwargs , ' sources ' ) )
def _test_all_naming ( self , cc , env , patterns , platform ) :
shr = patterns [ platform ] [ ' shared ' ]
stc = patterns [ platform ] [ ' static ' ]
2021-08-15 23:08:26 +08:00
shrstc = shr + tuple ( x for x in stc if x not in shr )
stcshr = stc + tuple ( x for x in shr if x not in stc )
2021-07-25 06:31:45 +08:00
p = cc . get_library_naming ( env , LibType . SHARED )
self . assertEqual ( p , shr )
p = cc . get_library_naming ( env , LibType . STATIC )
self . assertEqual ( p , stc )
p = cc . get_library_naming ( env , LibType . PREFER_STATIC )
self . assertEqual ( p , stcshr )
p = cc . get_library_naming ( env , LibType . PREFER_SHARED )
self . assertEqual ( p , shrstc )
# Test find library by mocking up openbsd
if platform != ' openbsd ' :
return
with tempfile . TemporaryDirectory ( ) as tmpdir :
for i in [ ' libfoo.so.6.0 ' , ' libfoo.so.5.0 ' , ' libfoo.so.54.0 ' , ' libfoo.so.66a.0b ' , ' libfoo.so.70.0.so.1 ' ] :
libpath = Path ( tmpdir ) / i
libpath . write_text ( ' ' , encoding = ' utf-8 ' )
found = cc . _find_library_real ( ' foo ' , env , [ tmpdir ] , ' ' , LibType . PREFER_SHARED )
self . assertEqual ( os . path . basename ( found [ 0 ] ) , ' libfoo.so.54.0 ' )
def test_find_library_patterns ( self ) :
'''
Unit test for the library search patterns used by find_library ( )
'''
unix_static = ( ' lib {} .a ' , ' {} .a ' )
msvc_static = ( ' lib {} .a ' , ' lib {} .lib ' , ' {} .a ' , ' {} .lib ' )
# This is the priority list of pattern matching for library searching
patterns = { ' openbsd ' : { ' shared ' : ( ' lib {} .so ' , ' {} .so ' , ' lib {} .so.[0-9]*.[0-9]* ' , ' {} .so.[0-9]*.[0-9]* ' ) ,
' static ' : unix_static } ,
' linux ' : { ' shared ' : ( ' lib {} .so ' , ' {} .so ' ) ,
' static ' : unix_static } ,
' darwin ' : { ' shared ' : ( ' lib {} .dylib ' , ' lib {} .so ' , ' {} .dylib ' , ' {} .so ' ) ,
' static ' : unix_static } ,
' cygwin ' : { ' shared ' : ( ' cyg {} .dll ' , ' cyg {} .dll.a ' , ' lib {} .dll ' ,
' lib {} .dll.a ' , ' {} .dll ' , ' {} .dll.a ' ) ,
' static ' : ( ' cyg {} .a ' , ) + unix_static } ,
' windows-msvc ' : { ' shared ' : ( ' lib {} .lib ' , ' {} .lib ' ) ,
' static ' : msvc_static } ,
' windows-mingw ' : { ' shared ' : ( ' lib {} .dll.a ' , ' lib {} .lib ' , ' lib {} .dll ' ,
' {} .dll.a ' , ' {} .lib ' , ' {} .dll ' ) ,
' static ' : msvc_static } }
env = get_fake_env ( )
cc = detect_c_compiler ( env , MachineChoice . HOST )
if is_osx ( ) :
self . _test_all_naming ( cc , env , patterns , ' darwin ' )
elif is_cygwin ( ) :
self . _test_all_naming ( cc , env , patterns , ' cygwin ' )
elif is_windows ( ) :
if cc . get_argument_syntax ( ) == ' msvc ' :
self . _test_all_naming ( cc , env , patterns , ' windows-msvc ' )
else :
self . _test_all_naming ( cc , env , patterns , ' windows-mingw ' )
elif is_openbsd ( ) :
self . _test_all_naming ( cc , env , patterns , ' openbsd ' )
else :
self . _test_all_naming ( cc , env , patterns , ' linux ' )
env . machines . host . system = ' openbsd '
self . _test_all_naming ( cc , env , patterns , ' openbsd ' )
env . machines . host . system = ' darwin '
self . _test_all_naming ( cc , env , patterns , ' darwin ' )
env . machines . host . system = ' cygwin '
self . _test_all_naming ( cc , env , patterns , ' cygwin ' )
env . machines . host . system = ' windows '
self . _test_all_naming ( cc , env , patterns , ' windows-mingw ' )
@skipIfNoPkgconfig
def test_pkgconfig_parse_libs ( self ) :
'''
Unit test for parsing of pkg - config output to search for libraries
https : / / github . com / mesonbuild / meson / issues / 3951
'''
def create_static_lib ( name ) :
if not is_osx ( ) :
name . open ( ' w ' , encoding = ' utf-8 ' ) . close ( )
return
src = name . with_suffix ( ' .c ' )
out = name . with_suffix ( ' .o ' )
with src . open ( ' w ' , encoding = ' utf-8 ' ) as f :
f . write ( ' int meson_foobar (void) { return 0; } ' )
subprocess . check_call ( [ ' clang ' , ' -c ' , str ( src ) , ' -o ' , str ( out ) ] )
subprocess . check_call ( [ ' ar ' , ' csr ' , str ( name ) , str ( out ) ] )
with tempfile . TemporaryDirectory ( ) as tmpdir :
pkgbin = ExternalProgram ( ' pkg-config ' , command = [ ' pkg-config ' ] , silent = True )
env = get_fake_env ( )
compiler = detect_c_compiler ( env , MachineChoice . HOST )
env . coredata . compilers . host = { ' c ' : compiler }
env . coredata . options [ OptionKey ( ' link_args ' , lang = ' c ' ) ] = FakeCompilerOptions ( )
p1 = Path ( tmpdir ) / ' 1 '
p2 = Path ( tmpdir ) / ' 2 '
p1 . mkdir ( )
p2 . mkdir ( )
# libfoo.a is in one prefix
create_static_lib ( p1 / ' libfoo.a ' )
# libbar.a is in both prefixes
create_static_lib ( p1 / ' libbar.a ' )
create_static_lib ( p2 / ' libbar.a ' )
# Ensure that we never statically link to these
create_static_lib ( p1 / ' libpthread.a ' )
create_static_lib ( p1 / ' libm.a ' )
create_static_lib ( p1 / ' libc.a ' )
create_static_lib ( p1 / ' libdl.a ' )
create_static_lib ( p1 / ' librt.a ' )
def fake_call_pkgbin ( self , args , env = None ) :
if ' --libs ' not in args :
return 0 , ' ' , ' '
if args [ - 1 ] == ' foo ' :
return 0 , f ' -L { p2 . as_posix ( ) } -lfoo -L { p1 . as_posix ( ) } -lbar ' , ' '
if args [ - 1 ] == ' bar ' :
return 0 , f ' -L { p2 . as_posix ( ) } -lbar ' , ' '
if args [ - 1 ] == ' internal ' :
return 0 , f ' -L { p1 . as_posix ( ) } -lpthread -lm -lc -lrt -ldl ' , ' '
old_call = PkgConfigDependency . _call_pkgbin
old_check = PkgConfigDependency . check_pkgconfig
PkgConfigDependency . _call_pkgbin = fake_call_pkgbin
PkgConfigDependency . check_pkgconfig = lambda x , _ : pkgbin
# Test begins
try :
kwargs = { ' required ' : True , ' silent ' : True }
foo_dep = PkgConfigDependency ( ' foo ' , env , kwargs )
self . assertEqual ( foo_dep . get_link_args ( ) ,
[ ( p1 / ' libfoo.a ' ) . as_posix ( ) , ( p2 / ' libbar.a ' ) . as_posix ( ) ] )
bar_dep = PkgConfigDependency ( ' bar ' , env , kwargs )
self . assertEqual ( bar_dep . get_link_args ( ) , [ ( p2 / ' libbar.a ' ) . as_posix ( ) ] )
internal_dep = PkgConfigDependency ( ' internal ' , env , kwargs )
if compiler . get_argument_syntax ( ) == ' msvc ' :
self . assertEqual ( internal_dep . get_link_args ( ) , [ ] )
else :
link_args = internal_dep . get_link_args ( )
for link_arg in link_args :
for lib in ( ' pthread ' , ' m ' , ' c ' , ' dl ' , ' rt ' ) :
self . assertNotIn ( f ' lib { lib } .a ' , link_arg , msg = link_args )
finally :
# Test ends
PkgConfigDependency . _call_pkgbin = old_call
PkgConfigDependency . check_pkgconfig = old_check
# Reset dependency class to ensure that in-process configure doesn't mess up
PkgConfigDependency . pkgbin_cache = { }
PkgConfigDependency . class_pkgbin = PerMachine ( None , None )
def test_version_compare ( self ) :
comparefunc = mesonbuild . mesonlib . version_compare_many
for ( a , b , result ) in [
( ' 0.99.beta19 ' , ' >= 0.99.beta14 ' , True ) ,
] :
self . assertEqual ( comparefunc ( a , b ) [ 0 ] , result )
for ( a , b , op ) in [
# examples from https://fedoraproject.org/wiki/Archive:Tools/RPM/VersionComparison
( " 1.0010 " , " 1.9 " , operator . gt ) ,
( " 1.05 " , " 1.5 " , operator . eq ) ,
( " 1.0 " , " 1 " , operator . gt ) ,
( " 2.50 " , " 2.5 " , operator . gt ) ,
( " fc4 " , " fc.4 " , operator . eq ) ,
( " FC5 " , " fc4 " , operator . lt ) ,
( " 2a " , " 2.0 " , operator . lt ) ,
( " 1.0 " , " 1.fc4 " , operator . gt ) ,
( " 3.0.0_fc " , " 3.0.0.fc " , operator . eq ) ,
# from RPM tests
( " 1.0 " , " 1.0 " , operator . eq ) ,
( " 1.0 " , " 2.0 " , operator . lt ) ,
( " 2.0 " , " 1.0 " , operator . gt ) ,
( " 2.0.1 " , " 2.0.1 " , operator . eq ) ,
( " 2.0 " , " 2.0.1 " , operator . lt ) ,
( " 2.0.1 " , " 2.0 " , operator . gt ) ,
( " 2.0.1a " , " 2.0.1a " , operator . eq ) ,
( " 2.0.1a " , " 2.0.1 " , operator . gt ) ,
( " 2.0.1 " , " 2.0.1a " , operator . lt ) ,
( " 5.5p1 " , " 5.5p1 " , operator . eq ) ,
( " 5.5p1 " , " 5.5p2 " , operator . lt ) ,
( " 5.5p2 " , " 5.5p1 " , operator . gt ) ,
( " 5.5p10 " , " 5.5p10 " , operator . eq ) ,
( " 5.5p1 " , " 5.5p10 " , operator . lt ) ,
( " 5.5p10 " , " 5.5p1 " , operator . gt ) ,
( " 10xyz " , " 10.1xyz " , operator . lt ) ,
( " 10.1xyz " , " 10xyz " , operator . gt ) ,
( " xyz10 " , " xyz10 " , operator . eq ) ,
( " xyz10 " , " xyz10.1 " , operator . lt ) ,
( " xyz10.1 " , " xyz10 " , operator . gt ) ,
( " xyz.4 " , " xyz.4 " , operator . eq ) ,
( " xyz.4 " , " 8 " , operator . lt ) ,
( " 8 " , " xyz.4 " , operator . gt ) ,
( " xyz.4 " , " 2 " , operator . lt ) ,
( " 2 " , " xyz.4 " , operator . gt ) ,
( " 5.5p2 " , " 5.6p1 " , operator . lt ) ,
( " 5.6p1 " , " 5.5p2 " , operator . gt ) ,
( " 5.6p1 " , " 6.5p1 " , operator . lt ) ,
( " 6.5p1 " , " 5.6p1 " , operator . gt ) ,
( " 6.0.rc1 " , " 6.0 " , operator . gt ) ,
( " 6.0 " , " 6.0.rc1 " , operator . lt ) ,
( " 10b2 " , " 10a1 " , operator . gt ) ,
( " 10a2 " , " 10b2 " , operator . lt ) ,
( " 1.0aa " , " 1.0aa " , operator . eq ) ,
( " 1.0a " , " 1.0aa " , operator . lt ) ,
( " 1.0aa " , " 1.0a " , operator . gt ) ,
( " 10.0001 " , " 10.0001 " , operator . eq ) ,
( " 10.0001 " , " 10.1 " , operator . eq ) ,
( " 10.1 " , " 10.0001 " , operator . eq ) ,
( " 10.0001 " , " 10.0039 " , operator . lt ) ,
( " 10.0039 " , " 10.0001 " , operator . gt ) ,
( " 4.999.9 " , " 5.0 " , operator . lt ) ,
( " 5.0 " , " 4.999.9 " , operator . gt ) ,
( " 20101121 " , " 20101121 " , operator . eq ) ,
( " 20101121 " , " 20101122 " , operator . lt ) ,
( " 20101122 " , " 20101121 " , operator . gt ) ,
( " 2_0 " , " 2_0 " , operator . eq ) ,
( " 2.0 " , " 2_0 " , operator . eq ) ,
( " 2_0 " , " 2.0 " , operator . eq ) ,
( " a " , " a " , operator . eq ) ,
( " a+ " , " a+ " , operator . eq ) ,
( " a+ " , " a_ " , operator . eq ) ,
( " a_ " , " a+ " , operator . eq ) ,
( " +a " , " +a " , operator . eq ) ,
( " +a " , " _a " , operator . eq ) ,
( " _a " , " +a " , operator . eq ) ,
( " +_ " , " +_ " , operator . eq ) ,
( " _+ " , " +_ " , operator . eq ) ,
( " _+ " , " _+ " , operator . eq ) ,
( " + " , " _ " , operator . eq ) ,
( " _ " , " + " , operator . eq ) ,
# other tests
( ' 0.99.beta19 ' , ' 0.99.beta14 ' , operator . gt ) ,
( " 1.0.0 " , " 2.0.0 " , operator . lt ) ,
( " .0.0 " , " 2.0.0 " , operator . lt ) ,
( " alpha " , " beta " , operator . lt ) ,
( " 1.0 " , " 1.0.0 " , operator . lt ) ,
( " 2.456 " , " 2.1000 " , operator . lt ) ,
( " 2.1000 " , " 3.111 " , operator . lt ) ,
( " 2.001 " , " 2.1 " , operator . eq ) ,
( " 2.34 " , " 2.34 " , operator . eq ) ,
( " 6.1.2 " , " 6.3.8 " , operator . lt ) ,
( " 1.7.3.0 " , " 2.0.0 " , operator . lt ) ,
( " 2.24.51 " , " 2.25 " , operator . lt ) ,
( " 2.1.5+20120813+gitdcbe778 " , " 2.1.5 " , operator . gt ) ,
( " 3.4.1 " , " 3.4b1 " , operator . gt ) ,
( " 041206 " , " 200090325 " , operator . lt ) ,
( " 0.6.2+git20130413 " , " 0.6.2 " , operator . gt ) ,
( " 2.6.0+bzr6602 " , " 2.6.0 " , operator . gt ) ,
( " 2.6.0 " , " 2.6b2 " , operator . gt ) ,
( " 2.6.0+bzr6602 " , " 2.6b2x " , operator . gt ) ,
( " 0.6.7+20150214+git3a710f9 " , " 0.6.7 " , operator . gt ) ,
( " 15.8b " , " 15.8.0.1 " , operator . lt ) ,
( " 1.2rc1 " , " 1.2.0 " , operator . lt ) ,
] :
ver_a = Version ( a )
ver_b = Version ( b )
if op is operator . eq :
for o , name in [ ( op , ' eq ' ) , ( operator . ge , ' ge ' ) , ( operator . le , ' le ' ) ] :
self . assertTrue ( o ( ver_a , ver_b ) , f ' { ver_a } { name } { ver_b } ' )
if op is operator . lt :
for o , name in [ ( op , ' lt ' ) , ( operator . le , ' le ' ) , ( operator . ne , ' ne ' ) ] :
self . assertTrue ( o ( ver_a , ver_b ) , f ' { ver_a } { name } { ver_b } ' )
for o , name in [ ( operator . gt , ' gt ' ) , ( operator . ge , ' ge ' ) , ( operator . eq , ' eq ' ) ] :
self . assertFalse ( o ( ver_a , ver_b ) , f ' { ver_a } { name } { ver_b } ' )
if op is operator . gt :
for o , name in [ ( op , ' gt ' ) , ( operator . ge , ' ge ' ) , ( operator . ne , ' ne ' ) ] :
self . assertTrue ( o ( ver_a , ver_b ) , f ' { ver_a } { name } { ver_b } ' )
for o , name in [ ( operator . lt , ' lt ' ) , ( operator . le , ' le ' ) , ( operator . eq , ' eq ' ) ] :
self . assertFalse ( o ( ver_a , ver_b ) , f ' { ver_a } { name } { ver_b } ' )
def test_msvc_toolset_version ( self ) :
'''
Ensure that the toolset version returns the correct value for this MSVC
'''
env = get_fake_env ( )
cc = detect_c_compiler ( env , MachineChoice . HOST )
if cc . get_argument_syntax ( ) != ' msvc ' :
raise unittest . SkipTest ( ' Test only applies to MSVC-like compilers ' )
toolset_ver = cc . get_toolset_version ( )
self . assertIsNotNone ( toolset_ver )
# Visual Studio 2015 and older versions do not define VCToolsVersion
# TODO: ICL doesn't set this in the VSC2015 profile either
if cc . id == ' msvc ' and int ( ' ' . join ( cc . version . split ( ' . ' ) [ 0 : 2 ] ) ) < 1910 :
return
if ' VCToolsVersion ' in os . environ :
vctools_ver = os . environ [ ' VCToolsVersion ' ]
else :
self . assertIn ( ' VCINSTALLDIR ' , os . environ )
# See https://devblogs.microsoft.com/cppblog/finding-the-visual-c-compiler-tools-in-visual-studio-2017/
vctools_ver = ( Path ( os . environ [ ' VCINSTALLDIR ' ] ) / ' Auxiliary ' / ' Build ' / ' Microsoft.VCToolsVersion.default.txt ' ) . read_text ( encoding = ' utf-8 ' )
self . assertTrue ( vctools_ver . startswith ( toolset_ver ) ,
msg = f ' { vctools_ver !r} does not start with { toolset_ver !r} ' )
def test_split_args ( self ) :
split_args = mesonbuild . mesonlib . split_args
join_args = mesonbuild . mesonlib . join_args
if is_windows ( ) :
test_data = [
# examples from https://docs.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments
( r ' " a b c " d e ' , [ ' a b c ' , ' d ' , ' e ' ] , True ) ,
( r ' " ab \ " c " " \\ " d ' , [ ' ab " c ' , ' \\ ' , ' d ' ] , False ) ,
( r ' a \\ \ b d " e f " g h ' , [ r ' a \\ \ b ' , ' de fg ' , ' h ' ] , False ) ,
( r ' a \\ \ " b c d ' , [ r ' a \ " b ' , ' c ' , ' d ' ] , False ) ,
( r ' a \\ \\ " b c " d e ' , [ r ' a \\ b c ' , ' d ' , ' e ' ] , False ) ,
# other basics
( r ' " " ' , [ ' ' ] , True ) ,
( r ' a b c d " " e ' , [ ' a ' , ' b ' , ' c ' , ' d ' , ' ' , ' e ' ] , True ) ,
( r " ' a b c ' d e " , [ " ' a " , ' b ' , " c ' " , ' d ' , ' e ' ] , True ) ,
( r " ' a&b&c ' d e " , [ " ' a&b&c ' " , ' d ' , ' e ' ] , True ) ,
( r " a & b & c d e " , [ ' a ' , ' & ' , ' b ' , ' & ' , ' c ' , ' d ' , ' e ' ] , True ) ,
( r " ' a & b & c d e ' " , [ " ' a " , ' & ' , ' b ' , ' & ' , ' c ' , ' d ' , " e ' " ] , True ) ,
( ' a b \n c \r d \n \r e ' , [ ' a ' , ' b ' , ' c ' , ' d ' , ' e ' ] , False ) ,
# more illustrative tests
( r ' cl test.cpp /O1 /Fe:test.exe ' , [ ' cl ' , ' test.cpp ' , ' /O1 ' , ' /Fe:test.exe ' ] , True ) ,
( r ' cl " test.cpp /O1 /Fe:test.exe " ' , [ ' cl ' , ' test.cpp /O1 /Fe:test.exe ' ] , True ) ,
( r ' cl /DNAME= \ " Bob \ " test.cpp ' , [ ' cl ' , ' /DNAME= " Bob " ' , ' test.cpp ' ] , False ) ,
( r ' cl " /DNAME= \ " Bob \ " " test.cpp ' , [ ' cl ' , ' /DNAME= " Bob " ' , ' test.cpp ' ] , True ) ,
( r ' cl /DNAME= \ " Bob, Alice \ " test.cpp ' , [ ' cl ' , ' /DNAME= " Bob, ' , ' Alice " ' , ' test.cpp ' ] , False ) ,
( r ' cl " /DNAME= \ " Bob, Alice \ " " test.cpp ' , [ ' cl ' , ' /DNAME= " Bob, Alice " ' , ' test.cpp ' ] , True ) ,
( r ' cl C: \ path \ with \ backslashes.cpp ' , [ ' cl ' , r ' C: \ path \ with \ backslashes.cpp ' ] , True ) ,
( r ' cl C: \\ path \\ with \\ double \\ backslashes.cpp ' , [ ' cl ' , r ' C: \\ path \\ with \\ double \\ backslashes.cpp ' ] , True ) ,
( r ' cl " C: \\ path \\ with \\ double \\ backslashes.cpp " ' , [ ' cl ' , r ' C: \\ path \\ with \\ double \\ backslashes.cpp ' ] , False ) ,
( r ' cl C: \ path with spaces \ test.cpp ' , [ ' cl ' , r ' C: \ path ' , ' with ' , r ' spaces \ test.cpp ' ] , False ) ,
( r ' cl " C: \ path with spaces \ test.cpp " ' , [ ' cl ' , r ' C: \ path with spaces \ test.cpp ' ] , True ) ,
( r ' cl /DPATH= " C: \ path \ with \ backslashes test.cpp ' , [ ' cl ' , r ' /DPATH=C: \ path \ with \ backslashes test.cpp ' ] , False ) ,
( r ' cl /DPATH= \ " C: \\ ends \\ with \\ backslashes \\ \ " test.cpp ' , [ ' cl ' , r ' /DPATH= " C: \\ ends \\ with \\ backslashes \ " ' , ' test.cpp ' ] , False ) ,
( r ' cl /DPATH= " C: \\ ends \\ with \\ backslashes \\ " test.cpp ' , [ ' cl ' , ' /DPATH=C: \\ \\ ends \\ \\ with \\ \\ backslashes \\ ' , ' test.cpp ' ] , False ) ,
( r ' cl " /DNAME= \ " C: \\ ends \\ with \\ backslashes \\ \ " " test.cpp ' , [ ' cl ' , r ' /DNAME= " C: \\ ends \\ with \\ backslashes \ " ' , ' test.cpp ' ] , True ) ,
( r ' cl " /DNAME= \ " C: \\ ends \\ with \\ backslashes \\ \\ " " test.cpp ' , [ ' cl ' , r ' /DNAME= " C: \\ ends \\ with \\ backslashes \\ test.cpp ' ] , False ) ,
( r ' cl " /DNAME= \ " C: \\ ends \\ with \\ backslashes \\ \\ \ " " test.cpp ' , [ ' cl ' , r ' /DNAME= " C: \\ ends \\ with \\ backslashes \\ " ' , ' test.cpp ' ] , True ) ,
]
else :
test_data = [
( r " ' a b c ' d e " , [ ' a b c ' , ' d ' , ' e ' ] , True ) ,
( r " a/b/c d e " , [ ' a/b/c ' , ' d ' , ' e ' ] , True ) ,
( r " a \ b \ c d e " , [ r ' abc ' , ' d ' , ' e ' ] , False ) ,
( r " a \\ b \\ c d e " , [ r ' a \ b \ c ' , ' d ' , ' e ' ] , False ) ,
( r ' " a b c " d e ' , [ ' a b c ' , ' d ' , ' e ' ] , False ) ,
( r ' " a \\ b \\ c \\ " d e ' , [ ' a \\ b \\ c \\ ' , ' d ' , ' e ' ] , False ) ,
( r " ' a \ b \ c \ ' d e " , [ ' a \\ b \\ c \\ ' , ' d ' , ' e ' ] , True ) ,
( r " ' a&b&c ' d e " , [ ' a&b&c ' , ' d ' , ' e ' ] , True ) ,
( r " a & b & c d e " , [ ' a ' , ' & ' , ' b ' , ' & ' , ' c ' , ' d ' , ' e ' ] , False ) ,
( r " ' a & b & c d e ' " , [ ' a & b & c d e ' ] , True ) ,
( r " abd ' e f ' g h " , [ r ' abde fg ' , ' h ' ] , False ) ,
( ' a b \n c \r d \n \r e ' , [ ' a ' , ' b ' , ' c ' , ' d ' , ' e ' ] , False ) ,
( ' g++ -DNAME= " Bob " test.cpp ' , [ ' g++ ' , ' -DNAME=Bob ' , ' test.cpp ' ] , False ) ,
( " g++ ' -DNAME= \" Bob \" ' test.cpp " , [ ' g++ ' , ' -DNAME= " Bob " ' , ' test.cpp ' ] , True ) ,
( ' g++ -DNAME= " Bob, Alice " test.cpp ' , [ ' g++ ' , ' -DNAME=Bob, Alice ' , ' test.cpp ' ] , False ) ,
( " g++ ' -DNAME= \" Bob, Alice \" ' test.cpp " , [ ' g++ ' , ' -DNAME= " Bob, Alice " ' , ' test.cpp ' ] , True ) ,
]
for ( cmd , expected , roundtrip ) in test_data :
self . assertEqual ( split_args ( cmd ) , expected )
if roundtrip :
self . assertEqual ( join_args ( expected ) , cmd )
def test_quote_arg ( self ) :
split_args = mesonbuild . mesonlib . split_args
quote_arg = mesonbuild . mesonlib . quote_arg
if is_windows ( ) :
test_data = [
( ' ' , ' " " ' ) ,
( ' arg1 ' , ' arg1 ' ) ,
( ' /option1 ' , ' /option1 ' ) ,
( ' /Ovalue ' , ' /Ovalue ' ) ,
( ' /OBob&Alice ' , ' /OBob&Alice ' ) ,
( ' /Ovalue with spaces ' , r ' " /Ovalue with spaces " ' ) ,
( r ' /O " value with spaces " ' , r ' " /O \ " value with spaces \ " " ' ) ,
( r ' /OC: \ path with spaces \ test.exe ' , r ' " /OC: \ path with spaces \ test.exe " ' ) ,
( ' /LIBPATH:C: \\ path with spaces \\ ends \\ with \\ backslashes \\ ' , r ' " /LIBPATH:C: \ path with spaces \ ends \ with \ backslashes \\ " ' ) ,
( ' /LIBPATH: " C: \\ path with spaces \\ ends \\ with \\ backslashes \\ \\ " ' , r ' " /LIBPATH: \ " C: \ path with spaces \ ends \ with \ backslashes \\ \\ \ " " ' ) ,
( r ' /DMSG= " Alice said: \ " Let \' s go \ " " ' , r ' " /DMSG= \ " Alice said: \\ \ " Let \' s go \\ \ " \ " " ' ) ,
]
else :
test_data = [
( ' arg1 ' , ' arg1 ' ) ,
( ' --option1 ' , ' --option1 ' ) ,
( ' -O=value ' , ' -O=value ' ) ,
( ' -O=Bob&Alice ' , " ' -O=Bob&Alice ' " ) ,
( ' -O=value with spaces ' , " ' -O=value with spaces ' " ) ,
( ' -O= " value with spaces " ' , ' \' -O= \" value with spaces \" \' ' ) ,
( ' -O=/path with spaces/test ' , ' \' -O=/path with spaces/test \' ' ) ,
( ' -DMSG= " Alice said: \\ " Let \' s go \\ " " ' , " ' -DMSG= \" Alice said: \\ \" Let ' \" ' \" ' s go \\ \" \" ' " ) ,
]
for ( arg , expected ) in test_data :
self . assertEqual ( quote_arg ( arg ) , expected )
self . assertEqual ( split_args ( expected ) [ 0 ] , arg )
def test_depfile ( self ) :
for ( f , target , expdeps ) in [
# empty, unknown target
( [ ' ' ] , ' unknown ' , set ( ) ) ,
# simple target & deps
( [ ' meson/foo.o : foo.c foo.h ' ] , ' meson/foo.o ' , set ( { ' foo.c ' , ' foo.h ' } ) ) ,
( [ ' meson/foo.o: foo.c foo.h ' ] , ' foo.c ' , set ( ) ) ,
# get all deps
( [ ' meson/foo.o: foo.c foo.h ' ,
' foo.c: gen.py ' ] , ' meson/foo.o ' , set ( { ' foo.c ' , ' foo.h ' , ' gen.py ' } ) ) ,
( [ ' meson/foo.o: foo.c foo.h ' ,
' foo.c: gen.py ' ] , ' foo.c ' , set ( { ' gen.py ' } ) ) ,
# linue continuation, multiple targets
( [ ' foo.o \\ ' , ' foo.h: bar ' ] , ' foo.h ' , set ( { ' bar ' } ) ) ,
( [ ' foo.o \\ ' , ' foo.h: bar ' ] , ' foo.o ' , set ( { ' bar ' } ) ) ,
# \\ handling
( [ ' foo: Program \\ F \\ iles \\ \\ X ' ] , ' foo ' , set ( { ' Program Files \\ X ' } ) ) ,
# $ handling
( [ ' f$o.o: c/b ' ] , ' f$o.o ' , set ( { ' c/b ' } ) ) ,
( [ ' f$$o.o: c/b ' ] , ' f$o.o ' , set ( { ' c/b ' } ) ) ,
# cycles
( [ ' a: b ' , ' b: a ' ] , ' a ' , set ( { ' a ' , ' b ' } ) ) ,
( [ ' a: b ' , ' b: a ' ] , ' b ' , set ( { ' a ' , ' b ' } ) ) ,
] :
d = mesonbuild . depfile . DepFile ( f )
deps = d . get_all_dependencies ( target )
self . assertEqual ( sorted ( deps ) , sorted ( expdeps ) )
def test_log_once ( self ) :
f = io . StringIO ( )
with mock . patch ( ' mesonbuild.mlog.log_file ' , f ) , \
mock . patch ( ' mesonbuild.mlog._logged_once ' , set ( ) ) :
mesonbuild . mlog . log_once ( ' foo ' )
mesonbuild . mlog . log_once ( ' foo ' )
actual = f . getvalue ( ) . strip ( )
self . assertEqual ( actual , ' foo ' , actual )
def test_log_once_ansi ( self ) :
f = io . StringIO ( )
with mock . patch ( ' mesonbuild.mlog.log_file ' , f ) , \
mock . patch ( ' mesonbuild.mlog._logged_once ' , set ( ) ) :
mesonbuild . mlog . log_once ( mesonbuild . mlog . bold ( ' foo ' ) )
mesonbuild . mlog . log_once ( mesonbuild . mlog . bold ( ' foo ' ) )
actual = f . getvalue ( ) . strip ( )
self . assertEqual ( actual . count ( ' foo ' ) , 1 , actual )
mesonbuild . mlog . log_once ( ' foo ' )
actual = f . getvalue ( ) . strip ( )
self . assertEqual ( actual . count ( ' foo ' ) , 1 , actual )
f . truncate ( )
mesonbuild . mlog . warning ( ' bar ' , once = True )
mesonbuild . mlog . warning ( ' bar ' , once = True )
actual = f . getvalue ( ) . strip ( )
self . assertEqual ( actual . count ( ' bar ' ) , 1 , actual )
def test_sort_libpaths ( self ) :
sort_libpaths = mesonbuild . dependencies . base . sort_libpaths
self . assertEqual ( sort_libpaths (
[ ' /home/mesonuser/.local/lib ' , ' /usr/local/lib ' , ' /usr/lib ' ] ,
[ ' /home/mesonuser/.local/lib/pkgconfig ' , ' /usr/local/lib/pkgconfig ' ] ) ,
[ ' /home/mesonuser/.local/lib ' , ' /usr/local/lib ' , ' /usr/lib ' ] )
self . assertEqual ( sort_libpaths (
[ ' /usr/local/lib ' , ' /home/mesonuser/.local/lib ' , ' /usr/lib ' ] ,
[ ' /home/mesonuser/.local/lib/pkgconfig ' , ' /usr/local/lib/pkgconfig ' ] ) ,
[ ' /home/mesonuser/.local/lib ' , ' /usr/local/lib ' , ' /usr/lib ' ] )
self . assertEqual ( sort_libpaths (
[ ' /usr/lib ' , ' /usr/local/lib ' , ' /home/mesonuser/.local/lib ' ] ,
[ ' /home/mesonuser/.local/lib/pkgconfig ' , ' /usr/local/lib/pkgconfig ' ] ) ,
[ ' /home/mesonuser/.local/lib ' , ' /usr/local/lib ' , ' /usr/lib ' ] )
self . assertEqual ( sort_libpaths (
[ ' /usr/lib ' , ' /usr/local/lib ' , ' /home/mesonuser/.local/lib ' ] ,
[ ' /home/mesonuser/.local/lib/pkgconfig ' , ' /usr/local/libdata/pkgconfig ' ] ) ,
[ ' /home/mesonuser/.local/lib ' , ' /usr/local/lib ' , ' /usr/lib ' ] )
def test_dependency_factory_order ( self ) :
b = mesonbuild . dependencies . base
F = mesonbuild . dependencies . factory
with tempfile . TemporaryDirectory ( ) as tmpdir :
with chdir ( tmpdir ) :
env = get_fake_env ( )
env . scratch_dir = tmpdir
f = F . DependencyFactory (
' test_dep ' ,
methods = [ b . DependencyMethods . PKGCONFIG , b . DependencyMethods . CMAKE ]
)
actual = [ m ( ) for m in f ( env , MachineChoice . HOST , { ' required ' : False } ) ]
self . assertListEqual ( [ m . type_name for m in actual ] , [ ' pkgconfig ' , ' cmake ' ] )
f = F . DependencyFactory (
' test_dep ' ,
methods = [ b . DependencyMethods . CMAKE , b . DependencyMethods . PKGCONFIG ]
)
actual = [ m ( ) for m in f ( env , MachineChoice . HOST , { ' required ' : False } ) ]
self . assertListEqual ( [ m . type_name for m in actual ] , [ ' cmake ' , ' pkgconfig ' ] )
def test_validate_json ( self ) - > None :
""" Validate the json schema for the test cases. """
try :
from jsonschema import validate , ValidationError
except ImportError :
if is_ci ( ) :
raise
raise unittest . SkipTest ( ' Python jsonschema module not found. ' )
schema = json . loads ( Path ( ' data/test.schema.json ' ) . read_text ( encoding = ' utf-8 ' ) )
errors = [ ] # type: T.Tuple[str, Exception]
for p in Path ( ' test cases ' ) . glob ( ' **/test.json ' ) :
try :
validate ( json . loads ( p . read_text ( encoding = ' utf-8 ' ) ) , schema = schema )
except ValidationError as e :
errors . append ( ( p . resolve ( ) , e ) )
for f , e in errors :
print ( f ' Failed to validate: " { f } " ' )
print ( str ( e ) )
self . assertFalse ( errors )
def test_typed_pos_args_types ( self ) - > None :
@typed_pos_args ( ' foo ' , str , int , bool )
def _ ( obj , node , args : T . Tuple [ str , int , bool ] , kwargs ) - > None :
self . assertIsInstance ( args , tuple )
self . assertIsInstance ( args [ 0 ] , str )
self . assertIsInstance ( args [ 1 ] , int )
self . assertIsInstance ( args [ 2 ] , bool )
_ ( None , mock . Mock ( ) , [ ' string ' , 1 , False ] , None )
def test_typed_pos_args_types_invalid ( self ) - > None :
@typed_pos_args ( ' foo ' , str , int , bool )
def _ ( obj , node , args : T . Tuple [ str , int , bool ] , kwargs ) - > None :
self . assertTrue ( False ) # should not be reachable
with self . assertRaises ( InvalidArguments ) as cm :
_ ( None , mock . Mock ( ) , [ ' string ' , 1.0 , False ] , None )
self . assertEqual ( str ( cm . exception ) , ' foo argument 2 was of type " float " but should have been " int " ' )
def test_typed_pos_args_types_wrong_number ( self ) - > None :
@typed_pos_args ( ' foo ' , str , int , bool )
def _ ( obj , node , args : T . Tuple [ str , int , bool ] , kwargs ) - > None :
self . assertTrue ( False ) # should not be reachable
with self . assertRaises ( InvalidArguments ) as cm :
_ ( None , mock . Mock ( ) , [ ' string ' , 1 ] , None )
self . assertEqual ( str ( cm . exception ) , ' foo takes exactly 3 arguments, but got 2. ' )
with self . assertRaises ( InvalidArguments ) as cm :
_ ( None , mock . Mock ( ) , [ ' string ' , 1 , True , True ] , None )
self . assertEqual ( str ( cm . exception ) , ' foo takes exactly 3 arguments, but got 4. ' )
def test_typed_pos_args_varargs ( self ) - > None :
@typed_pos_args ( ' foo ' , str , varargs = str )
def _ ( obj , node , args : T . Tuple [ str , T . List [ str ] ] , kwargs ) - > None :
self . assertIsInstance ( args , tuple )
self . assertIsInstance ( args [ 0 ] , str )
self . assertIsInstance ( args [ 1 ] , list )
self . assertIsInstance ( args [ 1 ] [ 0 ] , str )
self . assertIsInstance ( args [ 1 ] [ 1 ] , str )
_ ( None , mock . Mock ( ) , [ ' string ' , ' var ' , ' args ' ] , None )
def test_typed_pos_args_varargs_not_given ( self ) - > None :
@typed_pos_args ( ' foo ' , str , varargs = str )
def _ ( obj , node , args : T . Tuple [ str , T . List [ str ] ] , kwargs ) - > None :
self . assertIsInstance ( args , tuple )
self . assertIsInstance ( args [ 0 ] , str )
self . assertIsInstance ( args [ 1 ] , list )
self . assertEqual ( args [ 1 ] , [ ] )
_ ( None , mock . Mock ( ) , [ ' string ' ] , None )
def test_typed_pos_args_varargs_invalid ( self ) - > None :
@typed_pos_args ( ' foo ' , str , varargs = str )
def _ ( obj , node , args : T . Tuple [ str , T . List [ str ] ] , kwargs ) - > None :
self . assertTrue ( False ) # should not be reachable
with self . assertRaises ( InvalidArguments ) as cm :
_ ( None , mock . Mock ( ) , [ ' string ' , ' var ' , ' args ' , 0 ] , None )
self . assertEqual ( str ( cm . exception ) , ' foo argument 4 was of type " int " but should have been " str " ' )
def test_typed_pos_args_varargs_invalid_mulitple_types ( self ) - > None :
@typed_pos_args ( ' foo ' , str , varargs = ( str , list ) )
def _ ( obj , node , args : T . Tuple [ str , T . List [ str ] ] , kwargs ) - > None :
self . assertTrue ( False ) # should not be reachable
with self . assertRaises ( InvalidArguments ) as cm :
_ ( None , mock . Mock ( ) , [ ' string ' , ' var ' , ' args ' , 0 ] , None )
self . assertEqual ( str ( cm . exception ) , ' foo argument 4 was of type " int " but should have been one of: " str " , " list " ' )
def test_typed_pos_args_max_varargs ( self ) - > None :
@typed_pos_args ( ' foo ' , str , varargs = str , max_varargs = 5 )
def _ ( obj , node , args : T . Tuple [ str , T . List [ str ] ] , kwargs ) - > None :
self . assertIsInstance ( args , tuple )
self . assertIsInstance ( args [ 0 ] , str )
self . assertIsInstance ( args [ 1 ] , list )
self . assertIsInstance ( args [ 1 ] [ 0 ] , str )
self . assertIsInstance ( args [ 1 ] [ 1 ] , str )
_ ( None , mock . Mock ( ) , [ ' string ' , ' var ' , ' args ' ] , None )
def test_typed_pos_args_max_varargs_exceeded ( self ) - > None :
@typed_pos_args ( ' foo ' , str , varargs = str , max_varargs = 1 )
def _ ( obj , node , args : T . Tuple [ str , T . Tuple [ str , . . . ] ] , kwargs ) - > None :
self . assertTrue ( False ) # should not be reachable
with self . assertRaises ( InvalidArguments ) as cm :
_ ( None , mock . Mock ( ) , [ ' string ' , ' var ' , ' args ' ] , None )
self . assertEqual ( str ( cm . exception ) , ' foo takes between 1 and 2 arguments, but got 3. ' )
def test_typed_pos_args_min_varargs ( self ) - > None :
@typed_pos_args ( ' foo ' , varargs = str , max_varargs = 2 , min_varargs = 1 )
def _ ( obj , node , args : T . Tuple [ str , T . List [ str ] ] , kwargs ) - > None :
self . assertIsInstance ( args , tuple )
self . assertIsInstance ( args [ 0 ] , list )
self . assertIsInstance ( args [ 0 ] [ 0 ] , str )
self . assertIsInstance ( args [ 0 ] [ 1 ] , str )
_ ( None , mock . Mock ( ) , [ ' string ' , ' var ' ] , None )
def test_typed_pos_args_min_varargs_not_met ( self ) - > None :
@typed_pos_args ( ' foo ' , str , varargs = str , min_varargs = 1 )
def _ ( obj , node , args : T . Tuple [ str , T . List [ str ] ] , kwargs ) - > None :
self . assertTrue ( False ) # should not be reachable
with self . assertRaises ( InvalidArguments ) as cm :
_ ( None , mock . Mock ( ) , [ ' string ' ] , None )
self . assertEqual ( str ( cm . exception ) , ' foo takes at least 2 arguments, but got 1. ' )
def test_typed_pos_args_min_and_max_varargs_exceeded ( self ) - > None :
@typed_pos_args ( ' foo ' , str , varargs = str , min_varargs = 1 , max_varargs = 2 )
def _ ( obj , node , args : T . Tuple [ str , T . Tuple [ str , . . . ] ] , kwargs ) - > None :
self . assertTrue ( False ) # should not be reachable
with self . assertRaises ( InvalidArguments ) as cm :
_ ( None , mock . Mock ( ) , [ ' string ' , ' var ' , ' args ' , ' bar ' ] , None )
self . assertEqual ( str ( cm . exception ) , ' foo takes between 2 and 3 arguments, but got 4. ' )
def test_typed_pos_args_min_and_max_varargs_not_met ( self ) - > None :
@typed_pos_args ( ' foo ' , str , varargs = str , min_varargs = 1 , max_varargs = 2 )
def _ ( obj , node , args : T . Tuple [ str , T . Tuple [ str , . . . ] ] , kwargs ) - > None :
self . assertTrue ( False ) # should not be reachable
with self . assertRaises ( InvalidArguments ) as cm :
_ ( None , mock . Mock ( ) , [ ' string ' ] , None )
self . assertEqual ( str ( cm . exception ) , ' foo takes between 2 and 3 arguments, but got 1. ' )
def test_typed_pos_args_variadic_and_optional ( self ) - > None :
@typed_pos_args ( ' foo ' , str , optargs = [ str ] , varargs = str , min_varargs = 0 )
def _ ( obj , node , args : T . Tuple [ str , T . List [ str ] ] , kwargs ) - > None :
self . assertTrue ( False ) # should not be reachable
with self . assertRaises ( AssertionError ) as cm :
_ ( None , mock . Mock ( ) , [ ' string ' ] , None )
self . assertEqual (
str ( cm . exception ) ,
' varargs and optargs not supported together as this would be ambiguous ' )
def test_typed_pos_args_min_optargs_not_met ( self ) - > None :
@typed_pos_args ( ' foo ' , str , str , optargs = [ str ] )
def _ ( obj , node , args : T . Tuple [ str , T . Optional [ str ] ] , kwargs ) - > None :
self . assertTrue ( False ) # should not be reachable
with self . assertRaises ( InvalidArguments ) as cm :
_ ( None , mock . Mock ( ) , [ ' string ' ] , None )
self . assertEqual ( str ( cm . exception ) , ' foo takes at least 2 arguments, but got 1. ' )
def test_typed_pos_args_min_optargs_max_exceeded ( self ) - > None :
@typed_pos_args ( ' foo ' , str , optargs = [ str ] )
def _ ( obj , node , args : T . Tuple [ str , T . Optional [ str ] ] , kwargs ) - > None :
self . assertTrue ( False ) # should not be reachable
with self . assertRaises ( InvalidArguments ) as cm :
_ ( None , mock . Mock ( ) , [ ' string ' , ' 1 ' , ' 2 ' ] , None )
self . assertEqual ( str ( cm . exception ) , ' foo takes at most 2 arguments, but got 3. ' )
def test_typed_pos_args_optargs_not_given ( self ) - > None :
@typed_pos_args ( ' foo ' , str , optargs = [ str ] )
def _ ( obj , node , args : T . Tuple [ str , T . Optional [ str ] ] , kwargs ) - > None :
self . assertEqual ( len ( args ) , 2 )
self . assertIsInstance ( args [ 0 ] , str )
self . assertEqual ( args [ 0 ] , ' string ' )
self . assertIsNone ( args [ 1 ] )
_ ( None , mock . Mock ( ) , [ ' string ' ] , None )
def test_typed_pos_args_optargs_some_given ( self ) - > None :
@typed_pos_args ( ' foo ' , str , optargs = [ str , int ] )
def _ ( obj , node , args : T . Tuple [ str , T . Optional [ str ] , T . Optional [ int ] ] , kwargs ) - > None :
self . assertEqual ( len ( args ) , 3 )
self . assertIsInstance ( args [ 0 ] , str )
self . assertEqual ( args [ 0 ] , ' string ' )
self . assertIsInstance ( args [ 1 ] , str )
self . assertEqual ( args [ 1 ] , ' 1 ' )
self . assertIsNone ( args [ 2 ] )
_ ( None , mock . Mock ( ) , [ ' string ' , ' 1 ' ] , None )
def test_typed_pos_args_optargs_all_given ( self ) - > None :
@typed_pos_args ( ' foo ' , str , optargs = [ str ] )
def _ ( obj , node , args : T . Tuple [ str , T . Optional [ str ] ] , kwargs ) - > None :
self . assertEqual ( len ( args ) , 2 )
self . assertIsInstance ( args [ 0 ] , str )
self . assertEqual ( args [ 0 ] , ' string ' )
self . assertIsInstance ( args [ 1 ] , str )
_ ( None , mock . Mock ( ) , [ ' string ' , ' 1 ' ] , None )
def test_typed_kwarg_basic ( self ) - > None :
@typed_kwargs (
' testfunc ' ,
2021-08-28 02:47:12 +08:00
KwargInfo ( ' input ' , str , default = ' ' )
2021-07-25 06:31:45 +08:00
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , str ] ) - > None :
self . assertIsInstance ( kwargs [ ' input ' ] , str )
self . assertEqual ( kwargs [ ' input ' ] , ' foo ' )
_ ( None , mock . Mock ( ) , [ ] , { ' input ' : ' foo ' } )
def test_typed_kwarg_missing_required ( self ) - > None :
@typed_kwargs (
' testfunc ' ,
KwargInfo ( ' input ' , str , required = True ) ,
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , str ] ) - > None :
self . assertTrue ( False ) # should be unreachable
with self . assertRaises ( InvalidArguments ) as cm :
_ ( None , mock . Mock ( ) , [ ] , { } )
self . assertEqual ( str ( cm . exception ) , ' testfunc is missing required keyword argument " input " ' )
def test_typed_kwarg_missing_optional ( self ) - > None :
@typed_kwargs (
' testfunc ' ,
2021-08-28 02:47:12 +08:00
KwargInfo ( ' input ' , ( str , type ( None ) ) ) ,
2021-07-25 06:31:45 +08:00
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , T . Optional [ str ] ] ) - > None :
self . assertIsNone ( kwargs [ ' input ' ] )
_ ( None , mock . Mock ( ) , [ ] , { } )
def test_typed_kwarg_default ( self ) - > None :
@typed_kwargs (
' testfunc ' ,
KwargInfo ( ' input ' , str , default = ' default ' ) ,
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , str ] ) - > None :
self . assertEqual ( kwargs [ ' input ' ] , ' default ' )
_ ( None , mock . Mock ( ) , [ ] , { } )
def test_typed_kwarg_container_valid ( self ) - > None :
@typed_kwargs (
' testfunc ' ,
2021-08-28 02:47:12 +08:00
KwargInfo ( ' input ' , ContainerTypeInfo ( list , str ) , default = [ ] , required = True ) ,
2021-07-25 06:31:45 +08:00
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , T . List [ str ] ] ) - > None :
self . assertEqual ( kwargs [ ' input ' ] , [ ' str ' ] )
_ ( None , mock . Mock ( ) , [ ] , { ' input ' : [ ' str ' ] } )
def test_typed_kwarg_container_invalid ( self ) - > None :
@typed_kwargs (
' testfunc ' ,
KwargInfo ( ' input ' , ContainerTypeInfo ( list , str ) , required = True ) ,
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , T . List [ str ] ] ) - > None :
self . assertTrue ( False ) # should be unreachable
with self . assertRaises ( InvalidArguments ) as cm :
_ ( None , mock . Mock ( ) , [ ] , { ' input ' : { } } )
2021-11-20 02:42:38 +08:00
self . assertEqual ( str ( cm . exception ) , " testfunc keyword argument ' input ' was of type dict[] but should have been array[str] " )
2021-07-25 06:31:45 +08:00
def test_typed_kwarg_contained_invalid ( self ) - > None :
@typed_kwargs (
' testfunc ' ,
KwargInfo ( ' input ' , ContainerTypeInfo ( dict , str ) , required = True ) ,
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , T . Dict [ str , str ] ] ) - > None :
self . assertTrue ( False ) # should be unreachable
with self . assertRaises ( InvalidArguments ) as cm :
2021-11-23 04:25:37 +08:00
_ ( None , mock . Mock ( ) , [ ] , { ' input ' : { ' key ' : 1 , ' bar ' : 2 } } )
2021-11-20 02:39:21 +08:00
self . assertEqual ( str ( cm . exception ) , " testfunc keyword argument ' input ' was of type dict[int] but should have been dict[str] " )
2021-07-25 06:31:45 +08:00
def test_typed_kwarg_container_listify ( self ) - > None :
@typed_kwargs (
' testfunc ' ,
2021-08-28 02:47:12 +08:00
KwargInfo ( ' input ' , ContainerTypeInfo ( list , str ) , default = [ ] , listify = True ) ,
2021-07-25 06:31:45 +08:00
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , T . List [ str ] ] ) - > None :
self . assertEqual ( kwargs [ ' input ' ] , [ ' str ' ] )
_ ( None , mock . Mock ( ) , [ ] , { ' input ' : ' str ' } )
def test_typed_kwarg_container_default_copy ( self ) - > None :
default : T . List [ str ] = [ ]
@typed_kwargs (
' testfunc ' ,
KwargInfo ( ' input ' , ContainerTypeInfo ( list , str ) , listify = True , default = default ) ,
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , T . List [ str ] ] ) - > None :
self . assertIsNot ( kwargs [ ' input ' ] , default )
_ ( None , mock . Mock ( ) , [ ] , { } )
def test_typed_kwarg_container_pairs ( self ) - > None :
@typed_kwargs (
' testfunc ' ,
KwargInfo ( ' input ' , ContainerTypeInfo ( list , str , pairs = True ) , listify = True ) ,
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , T . List [ str ] ] ) - > None :
self . assertEqual ( kwargs [ ' input ' ] , [ ' a ' , ' b ' ] )
_ ( None , mock . Mock ( ) , [ ] , { ' input ' : [ ' a ' , ' b ' ] } )
with self . assertRaises ( MesonException ) as cm :
_ ( None , mock . Mock ( ) , [ ] , { ' input ' : [ ' a ' ] } )
2021-11-20 02:42:38 +08:00
self . assertEqual ( str ( cm . exception ) , " testfunc keyword argument ' input ' was of type array[str] but should have been array[str] that has even size " )
2021-07-25 06:31:45 +08:00
def test_typed_kwarg_since ( self ) - > None :
@typed_kwargs (
' testfunc ' ,
2021-12-02 14:31:24 +08:00
KwargInfo ( ' input ' , str , since = ' 1.0 ' , since_message = ' Its awesome, use it ' ,
deprecated = ' 2.0 ' , deprecated_message = ' Its terrible, dont use it ' )
2021-07-25 06:31:45 +08:00
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , str ] ) - > None :
self . assertIsInstance ( kwargs [ ' input ' ] , str )
self . assertEqual ( kwargs [ ' input ' ] , ' foo ' )
2021-12-03 02:24:03 +08:00
with self . subTest ( ' use before available ' ) , \
mock . patch ( ' sys.stdout ' , io . StringIO ( ) ) as out , \
mock . patch ( ' mesonbuild.mesonlib.project_meson_versions ' , { ' ' : ' 0.1 ' } ) :
2021-07-25 06:31:45 +08:00
# With Meson 0.1 it should trigger the "introduced" warning but not the "deprecated" warning
_ ( None , mock . Mock ( subproject = ' ' ) , [ ] , { ' input ' : ' foo ' } )
2021-12-02 14:31:24 +08:00
self . assertRegex ( out . getvalue ( ) , r ' WARNING:.*introduced.*input arg in testfunc. Its awesome, use it ' )
self . assertNotRegex ( out . getvalue ( ) , r ' WARNING:.*deprecated.*input arg in testfunc. Its terrible, dont use it ' )
2021-07-25 06:31:45 +08:00
2021-12-03 02:24:03 +08:00
with self . subTest ( ' no warnings should be triggered ' ) , \
mock . patch ( ' sys.stdout ' , io . StringIO ( ) ) as out , \
mock . patch ( ' mesonbuild.mesonlib.project_meson_versions ' , { ' ' : ' 1.5 ' } ) :
2021-07-25 06:31:45 +08:00
# With Meson 1.5 it shouldn't trigger any warning
_ ( None , mock . Mock ( subproject = ' ' ) , [ ] , { ' input ' : ' foo ' } )
self . assertNotRegex ( out . getvalue ( ) , r ' WARNING:.* ' )
2021-12-03 02:24:03 +08:00
with self . subTest ( ' use after deprecated ' ) , \
mock . patch ( ' sys.stdout ' , io . StringIO ( ) ) as out , \
mock . patch ( ' mesonbuild.mesonlib.project_meson_versions ' , { ' ' : ' 2.0 ' } ) :
2021-07-25 06:31:45 +08:00
# With Meson 2.0 it should trigger the "deprecated" warning but not the "introduced" warning
_ ( None , mock . Mock ( subproject = ' ' ) , [ ] , { ' input ' : ' foo ' } )
2021-12-02 14:31:24 +08:00
self . assertRegex ( out . getvalue ( ) , r ' WARNING:.*deprecated.*input arg in testfunc. Its terrible, dont use it ' )
self . assertNotRegex ( out . getvalue ( ) , r ' WARNING:.*introduced.*input arg in testfunc. Its awesome, use it ' )
2021-07-25 06:31:45 +08:00
def test_typed_kwarg_validator ( self ) - > None :
@typed_kwargs (
' testfunc ' ,
2021-08-28 02:47:12 +08:00
KwargInfo ( ' input ' , str , default = ' ' , validator = lambda x : ' invalid! ' if x != ' foo ' else None )
2021-07-25 06:31:45 +08:00
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , str ] ) - > None :
pass
# Should be valid
_ ( None , mock . Mock ( ) , tuple ( ) , dict ( input = ' foo ' ) )
with self . assertRaises ( MesonException ) as cm :
_ ( None , mock . Mock ( ) , tuple ( ) , dict ( input = ' bar ' ) )
self . assertEqual ( str ( cm . exception ) , " testfunc keyword argument \" input \" invalid! " )
def test_typed_kwarg_convertor ( self ) - > None :
@typed_kwargs (
' testfunc ' ,
2021-08-28 02:47:12 +08:00
KwargInfo ( ' native ' , bool , default = False , convertor = lambda n : MachineChoice . BUILD if n else MachineChoice . HOST )
2021-07-25 06:31:45 +08:00
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , MachineChoice ] ) - > None :
assert isinstance ( kwargs [ ' native ' ] , MachineChoice )
_ ( None , mock . Mock ( ) , tuple ( ) , dict ( native = True ) )
2021-12-03 02:39:13 +08:00
@mock.patch ( ' mesonbuild.mesonlib.project_meson_versions ' , { ' ' : ' 1.0 ' } )
2021-07-25 06:31:45 +08:00
def test_typed_kwarg_since_values ( self ) - > None :
@typed_kwargs (
' testfunc ' ,
KwargInfo ( ' input ' , ContainerTypeInfo ( list , str ) , listify = True , default = [ ] , deprecated_values = { ' foo ' : ' 0.9 ' } , since_values = { ' bar ' : ' 1.1 ' } ) ,
2021-12-03 02:35:11 +08:00
KwargInfo ( ' output ' , ContainerTypeInfo ( dict , str ) , default = { } , deprecated_values = { ' foo ' : ' 0.9 ' , ' foo2 ' : ( ' 0.9 ' , ' dont use it ' ) } , since_values = { ' bar ' : ' 1.1 ' , ' bar2 ' : ( ' 1.1 ' , ' use this ' ) } ) ,
2021-12-02 07:45:48 +08:00
KwargInfo ( ' install_dir ' , ( bool , str , NoneType ) , deprecated_values = { False : ' 0.9 ' } ) ,
2021-07-25 06:31:45 +08:00
KwargInfo (
2021-08-28 02:47:12 +08:00
' mode ' ,
( str , type ( None ) ) ,
2021-08-24 05:07:57 +08:00
validator = in_set_validator ( { ' clean ' , ' build ' , ' rebuild ' , ' deprecated ' , ' since ' } ) ,
2021-07-25 06:31:45 +08:00
deprecated_values = { ' deprecated ' : ' 1.0 ' } ,
since_values = { ' since ' : ' 1.1 ' } ) ,
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , str ] ) - > None :
pass
2021-12-03 02:39:13 +08:00
with self . subTest ( ' deprecated array string value ' ) , mock . patch ( ' sys.stdout ' , io . StringIO ( ) ) as out :
2021-07-25 06:31:45 +08:00
_ ( None , mock . Mock ( subproject = ' ' ) , [ ] , { ' input ' : [ ' foo ' ] } )
2022-05-19 17:00:44 +08:00
self . assertRegex ( out . getvalue ( ) , r """ WARNING:.Project targets ' 1.0 ' .*deprecated since ' 0.9 ' : " testfunc " keyword argument " input " value " foo " .* """ )
2021-07-25 06:31:45 +08:00
2021-12-03 02:39:13 +08:00
with self . subTest ( ' new array string value ' ) , mock . patch ( ' sys.stdout ' , io . StringIO ( ) ) as out :
2021-07-25 06:31:45 +08:00
_ ( None , mock . Mock ( subproject = ' ' ) , [ ] , { ' input ' : [ ' bar ' ] } )
2022-05-19 17:00:44 +08:00
self . assertRegex ( out . getvalue ( ) , r """ WARNING:.Project targets ' 1.0 ' .*introduced in ' 1.1 ' : " testfunc " keyword argument " input " value " bar " .* """ )
2021-07-25 06:31:45 +08:00
2021-12-03 02:39:13 +08:00
with self . subTest ( ' deprecated dict string value ' ) , mock . patch ( ' sys.stdout ' , io . StringIO ( ) ) as out :
2021-07-25 06:31:45 +08:00
_ ( None , mock . Mock ( subproject = ' ' ) , [ ] , { ' output ' : { ' foo ' : ' a ' } } )
2022-05-19 17:00:44 +08:00
self . assertRegex ( out . getvalue ( ) , r """ WARNING:.Project targets ' 1.0 ' .*deprecated since ' 0.9 ' : " testfunc " keyword argument " output " value " foo " .* """ )
2021-07-25 06:31:45 +08:00
2021-12-03 02:35:11 +08:00
with self . subTest ( ' deprecated dict string value with msg ' ) , mock . patch ( ' sys.stdout ' , io . StringIO ( ) ) as out :
_ ( None , mock . Mock ( subproject = ' ' ) , [ ] , { ' output ' : { ' foo2 ' : ' a ' } } )
2022-05-19 17:00:44 +08:00
self . assertRegex ( out . getvalue ( ) , r """ WARNING:.Project targets ' 1.0 ' .*deprecated since ' 0.9 ' : " testfunc " keyword argument " output " value " foo2 " . dont use it.* """ )
2021-12-03 02:35:11 +08:00
2021-12-03 02:39:13 +08:00
with self . subTest ( ' new dict string value ' ) , mock . patch ( ' sys.stdout ' , io . StringIO ( ) ) as out :
2021-07-25 06:31:45 +08:00
_ ( None , mock . Mock ( subproject = ' ' ) , [ ] , { ' output ' : { ' bar ' : ' b ' } } )
2022-05-19 17:00:44 +08:00
self . assertRegex ( out . getvalue ( ) , r """ WARNING:.Project targets ' 1.0 ' .*introduced in ' 1.1 ' : " testfunc " keyword argument " output " value " bar " .* """ )
2021-07-25 06:31:45 +08:00
2021-12-03 02:35:11 +08:00
with self . subTest ( ' new dict string value with msg ' ) , mock . patch ( ' sys.stdout ' , io . StringIO ( ) ) as out :
_ ( None , mock . Mock ( subproject = ' ' ) , [ ] , { ' output ' : { ' bar2 ' : ' a ' } } )
2022-05-19 17:00:44 +08:00
self . assertRegex ( out . getvalue ( ) , r """ WARNING:.Project targets ' 1.0 ' .*introduced in ' 1.1 ' : " testfunc " keyword argument " output " value " bar2 " . use this.* """ )
2021-12-03 02:35:11 +08:00
2021-12-03 02:39:13 +08:00
with self . subTest ( ' non string union ' ) , mock . patch ( ' sys.stdout ' , io . StringIO ( ) ) as out :
_ ( None , mock . Mock ( subproject = ' ' ) , [ ] , { ' install_dir ' : False } )
2022-05-19 17:00:44 +08:00
self . assertRegex ( out . getvalue ( ) , r """ WARNING:.Project targets ' 1.0 ' .*deprecated since ' 0.9 ' : " testfunc " keyword argument " install_dir " value " False " .* """ )
2021-12-03 02:39:13 +08:00
with self . subTest ( ' deprecated string union ' ) , mock . patch ( ' sys.stdout ' , io . StringIO ( ) ) as out :
2021-07-25 06:31:45 +08:00
_ ( None , mock . Mock ( subproject = ' ' ) , [ ] , { ' mode ' : ' deprecated ' } )
2022-05-19 17:00:44 +08:00
self . assertRegex ( out . getvalue ( ) , r """ WARNING:.Project targets ' 1.0 ' .*deprecated since ' 1.0 ' : " testfunc " keyword argument " mode " value " deprecated " .* """ )
2021-07-25 06:31:45 +08:00
2021-12-03 02:39:13 +08:00
with self . subTest ( ' new string union ' ) , mock . patch ( ' sys.stdout ' , io . StringIO ( ) ) as out :
2021-07-25 06:31:45 +08:00
_ ( None , mock . Mock ( subproject = ' ' ) , [ ] , { ' mode ' : ' since ' } )
2022-05-19 17:00:44 +08:00
self . assertRegex ( out . getvalue ( ) , r """ WARNING:.Project targets ' 1.0 ' .*introduced in ' 1.1 ' : " testfunc " keyword argument " mode " value " since " .* """ )
2021-07-25 06:31:45 +08:00
def test_typed_kwarg_evolve ( self ) - > None :
k = KwargInfo ( ' foo ' , str , required = True , default = ' foo ' )
v = k . evolve ( default = ' bar ' )
self . assertEqual ( k . name , ' foo ' )
self . assertEqual ( k . name , v . name )
self . assertEqual ( k . types , str )
self . assertEqual ( k . types , v . types )
self . assertEqual ( k . required , True )
self . assertEqual ( k . required , v . required )
self . assertEqual ( k . default , ' foo ' )
self . assertEqual ( v . default , ' bar ' )
2021-08-31 01:28:13 +08:00
2021-08-27 23:32:42 +08:00
def test_typed_kwarg_default_type ( self ) - > None :
@typed_kwargs (
' testfunc ' ,
KwargInfo ( ' no_default ' , ( str , ContainerTypeInfo ( list , str ) , NoneType ) ) ,
KwargInfo ( ' str_default ' , ( str , ContainerTypeInfo ( list , str ) ) , default = ' ' ) ,
KwargInfo ( ' list_default ' , ( str , ContainerTypeInfo ( list , str ) ) , default = [ ' ' ] ) ,
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , str ] ) - > None :
self . assertEqual ( kwargs [ ' no_default ' ] , None )
self . assertEqual ( kwargs [ ' str_default ' ] , ' ' )
self . assertEqual ( kwargs [ ' list_default ' ] , [ ' ' ] )
_ ( None , mock . Mock ( ) , [ ] , { } )
def test_typed_kwarg_invalid_default_type ( self ) - > None :
@typed_kwargs (
' testfunc ' ,
KwargInfo ( ' invalid_default ' , ( str , ContainerTypeInfo ( list , str ) , NoneType ) , default = 42 ) ,
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , str ] ) - > None :
pass
self . assertRaises ( AssertionError , _ , None , mock . Mock ( ) , [ ] , { } )
def test_typed_kwarg_container_in_tuple ( self ) - > None :
@typed_kwargs (
' testfunc ' ,
KwargInfo ( ' input ' , ( str , ContainerTypeInfo ( list , str ) ) ) ,
)
def _ ( obj , node , args : T . Tuple , kwargs : T . Dict [ str , str ] ) - > None :
self . assertEqual ( kwargs [ ' input ' ] , args [ 0 ] )
_ ( None , mock . Mock ( ) , [ ' ' ] , { ' input ' : ' ' } )
_ ( None , mock . Mock ( ) , [ [ ' ' ] ] , { ' input ' : [ ' ' ] } )
self . assertRaises ( InvalidArguments , _ , None , mock . Mock ( ) , [ ] , { ' input ' : 42 } )
2021-08-31 01:28:13 +08:00
def test_detect_cpu_family ( self ) - > None :
2021-10-01 06:03:23 +08:00
""" Test the various cpu families that we detect and normalize.
2021-08-31 01:28:13 +08:00
This is particularly useful as both documentation , and to keep testing
platforms that are less common .
"""
@contextlib.contextmanager
def mock_trial ( value : str ) - > T . Iterable [ None ] :
""" Mock all of the ways we could get the trial at once. """
mocked = mock . Mock ( return_value = value )
with mock . patch ( ' mesonbuild.environment.detect_windows_arch ' , mocked ) , \
mock . patch ( ' mesonbuild.environment.platform.processor ' , mocked ) , \
mock . patch ( ' mesonbuild.environment.platform.machine ' , mocked ) :
yield
cases = [
( ' x86 ' , ' x86 ' ) ,
( ' i386 ' , ' x86 ' ) ,
( ' bepc ' , ' x86 ' ) , # Haiku
( ' earm ' , ' arm ' ) , # NetBSD
( ' arm ' , ' arm ' ) ,
( ' ppc64 ' , ' ppc64 ' ) ,
( ' powerpc64 ' , ' ppc64 ' ) ,
( ' powerpc ' , ' ppc ' ) ,
( ' ppc ' , ' ppc ' ) ,
( ' macppc ' , ' ppc ' ) ,
( ' power macintosh ' , ' ppc ' ) ,
( ' mips64el ' , ' mips64 ' ) ,
( ' mips64 ' , ' mips64 ' ) ,
( ' mips ' , ' mips ' ) ,
( ' mipsel ' , ' mips ' ) ,
( ' ip30 ' , ' mips64 ' ) ,
( ' ip35 ' , ' mips64 ' ) ,
( ' parisc64 ' , ' parisc ' ) ,
( ' sun4u ' , ' sparc64 ' ) ,
( ' sun4v ' , ' sparc64 ' ) ,
( ' amd64 ' , ' x86_64 ' ) ,
( ' x64 ' , ' x86_64 ' ) ,
( ' i86pc ' , ' x86_64 ' ) , # Solaris
2021-08-31 01:41:12 +08:00
( ' aarch64 ' , ' aarch64 ' ) ,
( ' aarch64_be ' , ' aarch64 ' ) ,
2021-08-31 01:28:13 +08:00
]
with mock . patch ( ' mesonbuild.environment.any_compiler_has_define ' , mock . Mock ( return_value = False ) ) :
for test , expected in cases :
with self . subTest ( test , has_define = False ) , mock_trial ( test ) :
actual = mesonbuild . environment . detect_cpu_family ( { } )
self . assertEqual ( actual , expected )
with mock . patch ( ' mesonbuild.environment.any_compiler_has_define ' , mock . Mock ( return_value = True ) ) :
for test , expected in [ ( ' x86_64 ' , ' x86 ' ) , ( ' aarch64 ' , ' arm ' ) , ( ' ppc ' , ' ppc64 ' ) ] :
with self . subTest ( test , has_define = True ) , mock_trial ( test ) :
actual = mesonbuild . environment . detect_cpu_family ( { } )
self . assertEqual ( actual , expected )
2021-08-31 01:37:41 +08:00
def test_detect_cpu ( self ) - > None :
@contextlib.contextmanager
def mock_trial ( value : str ) - > T . Iterable [ None ] :
""" Mock all of the ways we could get the trial at once. """
mocked = mock . Mock ( return_value = value )
with mock . patch ( ' mesonbuild.environment.detect_windows_arch ' , mocked ) , \
mock . patch ( ' mesonbuild.environment.platform.processor ' , mocked ) , \
mock . patch ( ' mesonbuild.environment.platform.machine ' , mocked ) :
yield
cases = [
( ' amd64 ' , ' x86_64 ' ) ,
( ' x64 ' , ' x86_64 ' ) ,
( ' i86pc ' , ' x86_64 ' ) ,
( ' earm ' , ' arm ' ) ,
( ' mips64el ' , ' mips64 ' ) ,
( ' mips64 ' , ' mips64 ' ) ,
( ' mips ' , ' mips ' ) ,
( ' mipsel ' , ' mips ' ) ,
2021-08-31 01:41:12 +08:00
( ' aarch64 ' , ' aarch64 ' ) ,
( ' aarch64_be ' , ' aarch64 ' ) ,
2021-08-31 01:37:41 +08:00
]
with mock . patch ( ' mesonbuild.environment.any_compiler_has_define ' , mock . Mock ( return_value = False ) ) :
for test , expected in cases :
with self . subTest ( test , has_define = False ) , mock_trial ( test ) :
actual = mesonbuild . environment . detect_cpu ( { } )
self . assertEqual ( actual , expected )
with mock . patch ( ' mesonbuild.environment.any_compiler_has_define ' , mock . Mock ( return_value = True ) ) :
2021-08-31 01:38:47 +08:00
for test , expected in [ ( ' x86_64 ' , ' i686 ' ) , ( ' aarch64 ' , ' arm ' ) , ( ' ppc ' , ' ppc64 ' ) ] :
2021-08-31 01:37:41 +08:00
with self . subTest ( test , has_define = True ) , mock_trial ( test ) :
actual = mesonbuild . environment . detect_cpu ( { } )
self . assertEqual ( actual , expected )
2021-09-01 02:06:36 +08:00
def test_interpreter_unpicklable ( self ) - > None :
build = mock . Mock ( )
build . environment = mock . Mock ( )
build . environment . get_source_dir = mock . Mock ( return_value = ' ' )
with mock . patch ( ' mesonbuild.interpreter.Interpreter._redetect_machines ' , mock . Mock ( ) ) , \
2021-09-01 02:07:46 +08:00
self . assertRaises ( mesonbuild . mesonlib . MesonBugException ) :
2021-09-01 02:06:36 +08:00
i = mesonbuild . interpreter . Interpreter ( build , mock = True )
pickle . dumps ( i )
2021-09-15 21:52:07 +08:00
def test_major_versions_differ ( self ) - > None :
# Return True when going to next major release, when going to dev cycle,
# when going to rc cycle or when going out of rc cycle.
self . assertTrue ( coredata . major_versions_differ ( ' 0.59.0 ' , ' 0.60.0 ' ) )
self . assertTrue ( coredata . major_versions_differ ( ' 0.59.0 ' , ' 0.59.99 ' ) )
self . assertTrue ( coredata . major_versions_differ ( ' 0.59.0 ' , ' 0.60.0.rc1 ' ) )
self . assertTrue ( coredata . major_versions_differ ( ' 0.59.99 ' , ' 0.60.0.rc1 ' ) )
self . assertTrue ( coredata . major_versions_differ ( ' 0.60.0.rc1 ' , ' 0.60.0 ' ) )
# Return False when going to next point release or when staying in dev/rc cycle.
self . assertFalse ( coredata . major_versions_differ ( ' 0.60.0 ' , ' 0.60.0 ' ) )
self . assertFalse ( coredata . major_versions_differ ( ' 0.60.0 ' , ' 0.60.1 ' ) )
self . assertFalse ( coredata . major_versions_differ ( ' 0.59.99 ' , ' 0.59.99 ' ) )
self . assertFalse ( coredata . major_versions_differ ( ' 0.60.0.rc1 ' , ' 0.60.0.rc2 ' ) )
2021-11-24 06:57:08 +08:00
def test_option_key_from_string ( self ) - > None :
cases = [
( ' c_args ' , OptionKey ( ' args ' , lang = ' c ' , _type = OptionType . COMPILER ) ) ,
( ' build.cpp_args ' , OptionKey ( ' args ' , machine = MachineChoice . BUILD , lang = ' cpp ' , _type = OptionType . COMPILER ) ) ,
( ' prefix ' , OptionKey ( ' prefix ' , _type = OptionType . BUILTIN ) ) ,
( ' made_up ' , OptionKey ( ' made_up ' , _type = OptionType . PROJECT ) ) ,
# TODO: the from_String method should be splitting the prefix off of
# these, as we have the type already, but it doesn't. For now have a
# test so that we don't change the behavior un-intentionally
( ' b_lto ' , OptionKey ( ' b_lto ' , _type = OptionType . BASE ) ) ,
( ' backend_startup_project ' , OptionKey ( ' backend_startup_project ' , _type = OptionType . BACKEND ) ) ,
]
for raw , expected in cases :
with self . subTest ( raw ) :
self . assertEqual ( OptionKey . from_string ( raw ) , expected )