1#!/usr/bin/python 2 3# Copyright 2008, 2012 Jurko Gospodnetic 4# Distributed under the Boost Software License, Version 1.0. 5# (See accompanying file LICENSE_1_0.txt or copy at 6# http://www.boost.org/LICENSE_1_0.txt) 7 8# Test Boost Build configuration file handling. 9 10import BoostBuild 11import TestCmd 12 13import os 14import os.path 15import re 16 17 18############################################################################### 19# 20# test_user_configuration() 21# ------------------------- 22# 23############################################################################### 24 25def test_user_configuration(): 26 """ 27 Test Boost Build user configuration handling. Both relative and absolute 28 path handling is tested. 29 30 """ 31 32 implicitConfigLoadMessage = \ 33 "notice: Loading user-config configuration file: *" 34 explicitConfigLoadMessage = \ 35 "notice: Loading explicitly specified user configuration file:" 36 disabledConfigLoadMessage = \ 37 "notice: User configuration file loading explicitly disabled." 38 testMessage = "_!_!_!_!_!_!_!_!_ %s _!_!_!_!_!_!_!_!_" 39 toolsetName = "__myDummyToolset__" 40 subdirName = "ASubDirectory" 41 configFileNames = ["ups_lala_1.jam", "ups_lala_2.jam", 42 os.path.join(subdirName, "ups_lala_3.jam")] 43 44 t = BoostBuild.Tester(["toolset=%s" % toolsetName, 45 "--debug-configuration"], pass_toolset=False, use_test_config=False) 46 47 for configFileName in configFileNames: 48 message = "ECHO \"%s\" ;" % testMessage % configFileName 49 # We need to double any backslashes in the message or Jam will 50 # interpret them as escape characters. 51 t.write(configFileName, message.replace("\\", "\\\\")) 52 53 # Prepare a dummy toolset so we do not get errors in case the default one 54 # is not found. 55 t.write(toolsetName + ".jam", """\ 56import feature ; 57feature.extend toolset : %s ; 58rule init ( ) { } 59""" % toolsetName) 60 61 # Python version of the same dummy toolset. 62 t.write(toolsetName + ".py", """\ 63from b2.build import feature 64feature.extend('toolset', ['%s']) 65def init(): pass 66""" % toolsetName) 67 68 t.write("jamroot.jam", """\ 69local test-index = [ MATCH ---test-id---=(.*) : [ modules.peek : ARGV ] ] ; 70ECHO test-index: $(test-index:E=(unknown)) ; 71""") 72 73 class LocalTester: 74 def __init__(self, tester): 75 self.__tester = tester 76 self.__test_ids = [] 77 78 def __assertionFailure(self, message): 79 BoostBuild.annotation("failure", "Internal test assertion failure " 80 "- %s" % message) 81 self.__tester.fail_test(1) 82 83 def __call__(self, test_id, env, extra_args=None, *args, **kwargs): 84 if env == "" and not canSetEmptyEnvironmentVariable: 85 self.__assertionFailure("Can not set empty environment " 86 "variables on this platform.") 87 self.__registerTestId(str(test_id)) 88 if extra_args is None: 89 extra_args = [] 90 extra_args.append("---test-id---=%s" % test_id) 91 env_name = "BOOST_BUILD_USER_CONFIG" 92 previous_env = os.environ.get(env_name) 93 _env_set(env_name, env) 94 try: 95 self.__tester.run_build_system(extra_args, *args, **kwargs) 96 finally: 97 _env_set(env_name, previous_env) 98 99 def __registerTestId(self, test_id): 100 if test_id in self.__test_ids: 101 self.__assertionFailure("Multiple test cases encountered " 102 "using the same test id '%s'." % test_id) 103 self.__test_ids.append(test_id) 104 105 test = LocalTester(t) 106 107 test(1, None) 108 t.expect_output_lines(explicitConfigLoadMessage, False) 109 t.expect_output_lines(disabledConfigLoadMessage, False) 110 t.expect_output_lines(testMessage % configFileNames[0], False) 111 t.expect_output_lines(testMessage % configFileNames[1], False) 112 t.expect_output_lines(testMessage % configFileNames[2], False) 113 114 test(2, None, ["--user-config="]) 115 t.expect_output_lines(implicitConfigLoadMessage, False) 116 t.expect_output_lines(explicitConfigLoadMessage, False) 117 t.expect_output_lines(disabledConfigLoadMessage) 118 t.expect_output_lines(testMessage % configFileNames[0], False) 119 t.expect_output_lines(testMessage % configFileNames[1], False) 120 t.expect_output_lines(testMessage % configFileNames[2], False) 121 122 test(3, None, ['--user-config=""']) 123 t.expect_output_lines(implicitConfigLoadMessage, False) 124 t.expect_output_lines(explicitConfigLoadMessage, False) 125 t.expect_output_lines(disabledConfigLoadMessage) 126 t.expect_output_lines(testMessage % configFileNames[0], False) 127 t.expect_output_lines(testMessage % configFileNames[1], False) 128 t.expect_output_lines(testMessage % configFileNames[2], False) 129 130 test(4, None, ['--user-config="%s"' % configFileNames[0]]) 131 t.expect_output_lines(implicitConfigLoadMessage, False) 132 t.expect_output_lines(explicitConfigLoadMessage) 133 t.expect_output_lines(disabledConfigLoadMessage, False) 134 t.expect_output_lines(testMessage % configFileNames[0]) 135 t.expect_output_lines(testMessage % configFileNames[1], False) 136 t.expect_output_lines(testMessage % configFileNames[2], False) 137 138 test(5, None, ['--user-config="%s"' % configFileNames[2]]) 139 t.expect_output_lines(implicitConfigLoadMessage, False) 140 t.expect_output_lines(explicitConfigLoadMessage) 141 t.expect_output_lines(disabledConfigLoadMessage, False) 142 t.expect_output_lines(testMessage % configFileNames[0], False) 143 t.expect_output_lines(testMessage % configFileNames[1], False) 144 t.expect_output_lines(testMessage % configFileNames[2]) 145 146 test(6, None, ['--user-config="%s"' % os.path.abspath(configFileNames[1])]) 147 t.expect_output_lines(implicitConfigLoadMessage, False) 148 t.expect_output_lines(explicitConfigLoadMessage) 149 t.expect_output_lines(disabledConfigLoadMessage, False) 150 t.expect_output_lines(testMessage % configFileNames[0], False) 151 t.expect_output_lines(testMessage % configFileNames[1]) 152 t.expect_output_lines(testMessage % configFileNames[2], False) 153 154 test(7, None, ['--user-config="%s"' % os.path.abspath(configFileNames[2])]) 155 t.expect_output_lines(implicitConfigLoadMessage, False) 156 t.expect_output_lines(explicitConfigLoadMessage) 157 t.expect_output_lines(disabledConfigLoadMessage, False) 158 t.expect_output_lines(testMessage % configFileNames[0], False) 159 t.expect_output_lines(testMessage % configFileNames[1], False) 160 t.expect_output_lines(testMessage % configFileNames[2]) 161 162 if canSetEmptyEnvironmentVariable: 163 test(8, "") 164 t.expect_output_lines(implicitConfigLoadMessage, False) 165 t.expect_output_lines(explicitConfigLoadMessage, False) 166 t.expect_output_lines(disabledConfigLoadMessage, True) 167 t.expect_output_lines(testMessage % configFileNames[0], False) 168 t.expect_output_lines(testMessage % configFileNames[1], False) 169 t.expect_output_lines(testMessage % configFileNames[2], False) 170 171 test(9, '""') 172 t.expect_output_lines(implicitConfigLoadMessage, False) 173 t.expect_output_lines(explicitConfigLoadMessage, False) 174 t.expect_output_lines(disabledConfigLoadMessage) 175 t.expect_output_lines(testMessage % configFileNames[0], False) 176 t.expect_output_lines(testMessage % configFileNames[1], False) 177 t.expect_output_lines(testMessage % configFileNames[2], False) 178 179 test(10, configFileNames[1]) 180 t.expect_output_lines(implicitConfigLoadMessage, False) 181 t.expect_output_lines(explicitConfigLoadMessage) 182 t.expect_output_lines(disabledConfigLoadMessage, False) 183 t.expect_output_lines(testMessage % configFileNames[0], False) 184 t.expect_output_lines(testMessage % configFileNames[1]) 185 t.expect_output_lines(testMessage % configFileNames[2], False) 186 187 test(11, configFileNames[1], ['--user-config=""']) 188 t.expect_output_lines(implicitConfigLoadMessage, False) 189 t.expect_output_lines(explicitConfigLoadMessage, False) 190 t.expect_output_lines(disabledConfigLoadMessage) 191 t.expect_output_lines(testMessage % configFileNames[0], False) 192 t.expect_output_lines(testMessage % configFileNames[1], False) 193 t.expect_output_lines(testMessage % configFileNames[2], False) 194 195 test(12, configFileNames[1], ['--user-config="%s"' % configFileNames[0]]) 196 t.expect_output_lines(implicitConfigLoadMessage, False) 197 t.expect_output_lines(explicitConfigLoadMessage) 198 t.expect_output_lines(disabledConfigLoadMessage, False) 199 t.expect_output_lines(testMessage % configFileNames[0]) 200 t.expect_output_lines(testMessage % configFileNames[1], False) 201 t.expect_output_lines(testMessage % configFileNames[2], False) 202 203 if canSetEmptyEnvironmentVariable: 204 test(13, "", ['--user-config="%s"' % configFileNames[0]]) 205 t.expect_output_lines(implicitConfigLoadMessage, False) 206 t.expect_output_lines(explicitConfigLoadMessage) 207 t.expect_output_lines(disabledConfigLoadMessage, False) 208 t.expect_output_lines(testMessage % configFileNames[0]) 209 t.expect_output_lines(testMessage % configFileNames[1], False) 210 t.expect_output_lines(testMessage % configFileNames[2], False) 211 212 test(14, '""', ['--user-config="%s"' % configFileNames[0]]) 213 t.expect_output_lines(implicitConfigLoadMessage, False) 214 t.expect_output_lines(explicitConfigLoadMessage) 215 t.expect_output_lines(disabledConfigLoadMessage, False) 216 t.expect_output_lines(testMessage % configFileNames[0]) 217 t.expect_output_lines(testMessage % configFileNames[1], False) 218 t.expect_output_lines(testMessage % configFileNames[2], False) 219 220 test(15, "invalid", ['--user-config="%s"' % configFileNames[0]]) 221 t.expect_output_lines(implicitConfigLoadMessage, False) 222 t.expect_output_lines(explicitConfigLoadMessage) 223 t.expect_output_lines(disabledConfigLoadMessage, False) 224 t.expect_output_lines(testMessage % configFileNames[0]) 225 t.expect_output_lines(testMessage % configFileNames[1], False) 226 t.expect_output_lines(testMessage % configFileNames[2], False) 227 228 t.cleanup() 229 230 231############################################################################### 232# 233# Private interface. 234# 235############################################################################### 236 237def _canSetEmptyEnvironmentVariable(): 238 """ 239 Unfortunately different OSs (and possibly Python implementations as well) 240 have different interpretations of what it means to set an environment 241 variable to an empty string. Some (e.g. Windows) interpret it as unsetting 242 the variable and some (e.g. AIX or Darwin) actually set it to an empty 243 string. 244 245 """ 246 dummyName = "UGNABUNGA_FOO_BAR_BAZ_FEE_FAE_FOU_FAM" 247 original = os.environ.get(dummyName) 248 _env_set(dummyName, "") 249 result = _getExternalEnv(dummyName) == "" 250 _env_set(dummyName, original) 251 return result 252 253 254def _env_del(name): 255 """ 256 Unsets the given environment variable if it is currently set. 257 258 Note that we can not use os.environ.pop() or os.environ.clear() here 259 since prior to Python 2.6 these functions did not remove the actual 260 environment variable by calling os.unsetenv(). 261 262 """ 263 try: 264 del os.environ[name] 265 except KeyError: 266 pass 267 268 269def _env_set(name, value): 270 """ 271 Sets the given environment variable value or unsets it, if the value is 272 None. 273 274 """ 275 if value is None: 276 _env_del(name) 277 else: 278 os.environ[name] = value 279 280 281def _getExternalEnv(name): 282 toolsetName = "__myDummyToolset__" 283 284 t = BoostBuild.Tester(["toolset=%s" % toolsetName], pass_toolset=False, 285 use_test_config=False) 286 try: 287 # Prepare a dummy toolset so we do not get errors in case the default 288 # one is not found. 289 t.write(toolsetName + ".jam", """\ 290import feature ; 291feature.extend toolset : %s ; 292rule init ( ) { } 293""" % toolsetName) 294 295 # Python version of the same dummy toolset. 296 t.write(toolsetName + ".py", """\ 297from b2.build import feature 298feature.extend('toolset', ['%s']) 299def init(): pass 300""" % toolsetName) 301 302 t.write("jamroot.jam", """\ 303import os ; 304local names = [ MATCH ^---var-name---=(.*) : [ modules.peek : ARGV ] ] ; 305for x in $(names) 306{ 307 value = [ os.environ $(x) ] ; 308 ECHO "###" $(x): '$(value)' "###" ; 309} 310""") 311 312 t.run_build_system(["---var-name---=%s" % name]) 313 m = re.search("^### %s: '(.*)' ###$" % name, t.stdout(), re.MULTILINE) 314 if m: 315 return m.group(1) 316 finally: 317 t.cleanup() 318 319 320def test_site_config(): 321 # Ignore user-config, just in case it depends on the user's site-config.jam 322 t = BoostBuild.Tester(["--user-config="], use_test_config=False, 323 pass_toolset=0) 324 # We can immediately exit after we finish loading the config files 325 t.write("Jamroot", "EXIT Done : 0 ;") 326 t.write("my-site-config.jam", "ECHO Loaded my-site-config ;") 327 328 t.run_build_system(["--site-config=my-site-config.jam"], 329 stdout="Loaded my-site-config\nDone\n") 330 331 t.run_build_system(["--ignore-site-config", "--debug-configuration"]) 332 t.expect_output_lines("""\ 333notice: Site configuration files will be ignored due to the 334notice: --ignore-site-config command-line option.""") 335 336 t.run_build_system(["--site-config=", "--debug-configuration"]) 337 t.expect_output_lines("""\ 338notice: Site configuration file loading explicitly disabled.""") 339 340 t.cleanup() 341 342def test_global_config(): 343 t = BoostBuild.Tester(use_test_config=False, pass_toolset=0) 344 t.write("my-config.jam", "ECHO Loading my-config ;") 345 t.write("Jamroot", "EXIT Done : 0 ;") 346 t.write("project-config.jam", "ECHO bad ;") 347 t.run_build_system(["--config=my-config.jam", "--debug-configuration"], 348 match=TestCmd.match_re, stdout= 349r"""notice: found boost-build\.jam at .* 350notice: loading B2 from .* 351notice: Searching '.*' for all-config configuration file 'my-config\.jam'\. 352notice: Loading all-config configuration file 'my-config\.jam' from '.*'\. 353Loading my-config 354notice: Regular configuration files will be ignored due 355notice: to the global configuration being loaded\. 356Done 357""") 358 t.run_build_system(["--config=", "--debug-configuration"], 359 match=TestCmd.match_re, stdout= 360r"""notice: found boost-build\.jam at .* 361notice: loading B2 from .* 362notice: Configuration file loading explicitly disabled. 363Done 364""") 365 t.cleanup() 366 367def test_project_config(): 368 t = BoostBuild.Tester(["--user-config=", "--site-config="], 369 use_test_config=False, pass_toolset=False) 370 t.write("Jamroot", "EXIT Done : 0 ;") 371 t.write("project-config.jam", "ECHO Loading Root ;") 372 t.write("my-project-config.jam", "ECHO Loading explicit ;") 373 t.write("sub/project-config.jam", "ECHO Loading subdir ;") 374 t.write("sub/Jamfile", "") 375 376 t.run_build_system(stdout="Loading Root\nDone\n") 377 t.run_build_system(subdir="sub", stdout="Loading subdir\nDone\n") 378 t.rm("sub/project-config.jam") 379 t.run_build_system(subdir="sub", stdout="Loading Root\nDone\n") 380 t.run_build_system(["--project-config=my-project-config.jam"], 381 stdout="Loading explicit\nDone\n") 382 383 t.cleanup() 384 385############################################################################### 386# 387# main() 388# ------ 389# 390############################################################################### 391 392canSetEmptyEnvironmentVariable = _canSetEmptyEnvironmentVariable() 393 394test_user_configuration() 395test_site_config() 396test_global_config() 397test_project_config() 398