1# This Source Code Form is subject to the terms of the Mozilla Public 2# License, v. 2.0. If a copy of the MPL was not distributed with this 3# file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 5from __future__ import absolute_import, print_function, unicode_literals 6 7import os 8import six 9import unittest 10 11from mozunit import main 12 13from mozbuild.frontend.context import ObjDirPath, Path 14from mozbuild.frontend.data import ( 15 ComputedFlags, 16 ConfigFileSubstitution, 17 Defines, 18 DirectoryTraversal, 19 Exports, 20 FinalTargetPreprocessedFiles, 21 GeneratedFile, 22 GeneratedSources, 23 HostProgram, 24 HostRustLibrary, 25 HostRustProgram, 26 HostSources, 27 IPDLCollection, 28 JARManifest, 29 LocalInclude, 30 LocalizedFiles, 31 LocalizedPreprocessedFiles, 32 Program, 33 RustLibrary, 34 RustProgram, 35 SharedLibrary, 36 SimpleProgram, 37 Sources, 38 StaticLibrary, 39 TestHarnessFiles, 40 TestManifest, 41 UnifiedSources, 42 VariablePassthru, 43 WasmSources, 44) 45from mozbuild.frontend.emitter import TreeMetadataEmitter 46from mozbuild.frontend.reader import ( 47 BuildReader, 48 BuildReaderError, 49 SandboxValidationError, 50) 51 52from mozbuild.test.common import MockConfig 53 54import mozpack.path as mozpath 55 56 57data_path = mozpath.abspath(mozpath.dirname(__file__)) 58data_path = mozpath.join(data_path, "data") 59 60 61class TestEmitterBasic(unittest.TestCase): 62 def setUp(self): 63 self._old_env = dict(os.environ) 64 os.environ.pop("MOZ_OBJDIR", None) 65 66 def tearDown(self): 67 os.environ.clear() 68 os.environ.update(self._old_env) 69 70 def reader(self, name, enable_tests=False, extra_substs=None): 71 substs = dict( 72 ENABLE_TESTS="1" if enable_tests else "", 73 BIN_SUFFIX=".prog", 74 HOST_BIN_SUFFIX=".hostprog", 75 OS_TARGET="WINNT", 76 COMPILE_ENVIRONMENT="1", 77 STL_FLAGS=["-I/path/to/topobjdir/dist/stl_wrappers"], 78 VISIBILITY_FLAGS=["-include", "$(topsrcdir)/config/gcc_hidden.h"], 79 OBJ_SUFFIX="obj", 80 WASM_OBJ_SUFFIX="wasm", 81 WASM_CFLAGS=["-foo"], 82 ) 83 if extra_substs: 84 substs.update(extra_substs) 85 config = MockConfig(mozpath.join(data_path, name), extra_substs=substs) 86 87 return BuildReader(config) 88 89 def read_topsrcdir(self, reader, filter_common=True): 90 emitter = TreeMetadataEmitter(reader.config) 91 objs = list(emitter.emit(reader.read_topsrcdir())) 92 self.assertGreater(len(objs), 0) 93 94 filtered = [] 95 for obj in objs: 96 if filter_common and isinstance(obj, DirectoryTraversal): 97 continue 98 99 filtered.append(obj) 100 101 return filtered 102 103 def test_dirs_traversal_simple(self): 104 reader = self.reader("traversal-simple") 105 objs = self.read_topsrcdir(reader, filter_common=False) 106 self.assertEqual(len(objs), 4) 107 108 for o in objs: 109 self.assertIsInstance(o, DirectoryTraversal) 110 self.assertTrue(os.path.isabs(o.context_main_path)) 111 self.assertEqual(len(o.context_all_paths), 1) 112 113 reldirs = [o.relsrcdir for o in objs] 114 self.assertEqual(reldirs, ["", "foo", "foo/biz", "bar"]) 115 116 dirs = [[d.full_path for d in o.dirs] for o in objs] 117 self.assertEqual( 118 dirs, 119 [ 120 [ 121 mozpath.join(reader.config.topsrcdir, "foo"), 122 mozpath.join(reader.config.topsrcdir, "bar"), 123 ], 124 [mozpath.join(reader.config.topsrcdir, "foo", "biz")], 125 [], 126 [], 127 ], 128 ) 129 130 def test_traversal_all_vars(self): 131 reader = self.reader("traversal-all-vars") 132 objs = self.read_topsrcdir(reader, filter_common=False) 133 self.assertEqual(len(objs), 2) 134 135 for o in objs: 136 self.assertIsInstance(o, DirectoryTraversal) 137 138 reldirs = set([o.relsrcdir for o in objs]) 139 self.assertEqual(reldirs, set(["", "regular"])) 140 141 for o in objs: 142 reldir = o.relsrcdir 143 144 if reldir == "": 145 self.assertEqual( 146 [d.full_path for d in o.dirs], 147 [mozpath.join(reader.config.topsrcdir, "regular")], 148 ) 149 150 def test_traversal_all_vars_enable_tests(self): 151 reader = self.reader("traversal-all-vars", enable_tests=True) 152 objs = self.read_topsrcdir(reader, filter_common=False) 153 self.assertEqual(len(objs), 3) 154 155 for o in objs: 156 self.assertIsInstance(o, DirectoryTraversal) 157 158 reldirs = set([o.relsrcdir for o in objs]) 159 self.assertEqual(reldirs, set(["", "regular", "test"])) 160 161 for o in objs: 162 reldir = o.relsrcdir 163 164 if reldir == "": 165 self.assertEqual( 166 [d.full_path for d in o.dirs], 167 [ 168 mozpath.join(reader.config.topsrcdir, "regular"), 169 mozpath.join(reader.config.topsrcdir, "test"), 170 ], 171 ) 172 173 def test_config_file_substitution(self): 174 reader = self.reader("config-file-substitution") 175 objs = self.read_topsrcdir(reader) 176 self.assertEqual(len(objs), 2) 177 178 self.assertIsInstance(objs[0], ConfigFileSubstitution) 179 self.assertIsInstance(objs[1], ConfigFileSubstitution) 180 181 topobjdir = mozpath.abspath(reader.config.topobjdir) 182 self.assertEqual(objs[0].relpath, "foo") 183 self.assertEqual( 184 mozpath.normpath(objs[0].output_path), 185 mozpath.normpath(mozpath.join(topobjdir, "foo")), 186 ) 187 self.assertEqual( 188 mozpath.normpath(objs[1].output_path), 189 mozpath.normpath(mozpath.join(topobjdir, "bar")), 190 ) 191 192 def test_variable_passthru(self): 193 reader = self.reader("variable-passthru") 194 objs = self.read_topsrcdir(reader) 195 196 self.assertEqual(len(objs), 1) 197 self.assertIsInstance(objs[0], VariablePassthru) 198 199 wanted = { 200 "NO_DIST_INSTALL": True, 201 "RCFILE": "foo.rc", 202 "RCINCLUDE": "bar.rc", 203 "WIN32_EXE_LDFLAGS": ["-subsystem:console"], 204 } 205 206 variables = objs[0].variables 207 maxDiff = self.maxDiff 208 self.maxDiff = None 209 self.assertEqual(wanted, variables) 210 self.maxDiff = maxDiff 211 212 def test_compile_flags(self): 213 reader = self.reader( 214 "compile-flags", extra_substs={"WARNINGS_AS_ERRORS": "-Werror"} 215 ) 216 sources, ldflags, lib, flags = self.read_topsrcdir(reader) 217 self.assertIsInstance(flags, ComputedFlags) 218 self.assertEqual(flags.flags["STL"], reader.config.substs["STL_FLAGS"]) 219 self.assertEqual( 220 flags.flags["VISIBILITY"], reader.config.substs["VISIBILITY_FLAGS"] 221 ) 222 self.assertEqual(flags.flags["WARNINGS_AS_ERRORS"], ["-Werror"]) 223 self.assertEqual(flags.flags["MOZBUILD_CFLAGS"], ["-Wall", "-funroll-loops"]) 224 self.assertEqual(flags.flags["MOZBUILD_CXXFLAGS"], ["-funroll-loops", "-Wall"]) 225 226 def test_asflags(self): 227 reader = self.reader("asflags", extra_substs={"ASFLAGS": ["-safeseh"]}) 228 as_sources, sources, ldflags, lib, flags, asflags = self.read_topsrcdir(reader) 229 self.assertIsInstance(asflags, ComputedFlags) 230 self.assertEqual(asflags.flags["OS"], reader.config.substs["ASFLAGS"]) 231 self.assertEqual(asflags.flags["MOZBUILD"], ["-no-integrated-as"]) 232 233 def test_debug_flags(self): 234 reader = self.reader( 235 "compile-flags", 236 extra_substs={"MOZ_DEBUG_FLAGS": "-g", "MOZ_DEBUG_SYMBOLS": "1"}, 237 ) 238 sources, ldflags, lib, flags = self.read_topsrcdir(reader) 239 self.assertIsInstance(flags, ComputedFlags) 240 self.assertEqual(flags.flags["DEBUG"], ["-g"]) 241 242 def test_disable_debug_flags(self): 243 reader = self.reader( 244 "compile-flags", 245 extra_substs={"MOZ_DEBUG_FLAGS": "-g", "MOZ_DEBUG_SYMBOLS": ""}, 246 ) 247 sources, ldflags, lib, flags = self.read_topsrcdir(reader) 248 self.assertIsInstance(flags, ComputedFlags) 249 self.assertEqual(flags.flags["DEBUG"], []) 250 251 def test_link_flags(self): 252 reader = self.reader( 253 "link-flags", 254 extra_substs={ 255 "OS_LDFLAGS": ["-Wl,rpath-link=/usr/lib"], 256 "MOZ_OPTIMIZE": "", 257 "MOZ_OPTIMIZE_LDFLAGS": ["-Wl,-dead_strip"], 258 "MOZ_DEBUG_LDFLAGS": ["-framework ExceptionHandling"], 259 }, 260 ) 261 sources, ldflags, lib, compile_flags = self.read_topsrcdir(reader) 262 self.assertIsInstance(ldflags, ComputedFlags) 263 self.assertEqual(ldflags.flags["OS"], reader.config.substs["OS_LDFLAGS"]) 264 self.assertEqual( 265 ldflags.flags["MOZBUILD"], ["-Wl,-U_foo", "-framework Foo", "-x"] 266 ) 267 self.assertEqual(ldflags.flags["OPTIMIZE"], []) 268 269 def test_debug_ldflags(self): 270 reader = self.reader( 271 "link-flags", 272 extra_substs={ 273 "MOZ_DEBUG_SYMBOLS": "1", 274 "MOZ_DEBUG_LDFLAGS": ["-framework ExceptionHandling"], 275 }, 276 ) 277 sources, ldflags, lib, compile_flags = self.read_topsrcdir(reader) 278 self.assertIsInstance(ldflags, ComputedFlags) 279 self.assertEqual(ldflags.flags["OS"], reader.config.substs["MOZ_DEBUG_LDFLAGS"]) 280 281 def test_windows_opt_link_flags(self): 282 reader = self.reader( 283 "link-flags", 284 extra_substs={ 285 "OS_ARCH": "WINNT", 286 "GNU_CC": "", 287 "MOZ_OPTIMIZE": "1", 288 "MOZ_DEBUG_LDFLAGS": ["-DEBUG"], 289 "MOZ_DEBUG_SYMBOLS": "1", 290 "MOZ_OPTIMIZE_FLAGS": [], 291 "MOZ_OPTIMIZE_LDFLAGS": [], 292 }, 293 ) 294 sources, ldflags, lib, compile_flags = self.read_topsrcdir(reader) 295 self.assertIsInstance(ldflags, ComputedFlags) 296 self.assertIn("-DEBUG", ldflags.flags["OS"]) 297 self.assertIn("-OPT:REF,ICF", ldflags.flags["OS"]) 298 299 def test_windows_dmd_link_flags(self): 300 reader = self.reader( 301 "link-flags", 302 extra_substs={ 303 "OS_ARCH": "WINNT", 304 "GNU_CC": "", 305 "MOZ_DMD": "1", 306 "MOZ_DEBUG_LDFLAGS": ["-DEBUG"], 307 "MOZ_DEBUG_SYMBOLS": "1", 308 "MOZ_OPTIMIZE": "1", 309 "MOZ_OPTIMIZE_FLAGS": [], 310 }, 311 ) 312 sources, ldflags, lib, compile_flags = self.read_topsrcdir(reader) 313 self.assertIsInstance(ldflags, ComputedFlags) 314 self.assertEqual(ldflags.flags["OS"], ["-DEBUG", "-OPT:REF,ICF"]) 315 316 def test_host_compile_flags(self): 317 reader = self.reader( 318 "host-compile-flags", 319 extra_substs={ 320 "HOST_CXXFLAGS": ["-Wall", "-Werror"], 321 "HOST_CFLAGS": ["-Werror", "-Wall"], 322 }, 323 ) 324 sources, ldflags, flags, lib, target_flags = self.read_topsrcdir(reader) 325 self.assertIsInstance(flags, ComputedFlags) 326 self.assertEqual( 327 flags.flags["HOST_CXXFLAGS"], reader.config.substs["HOST_CXXFLAGS"] 328 ) 329 self.assertEqual( 330 flags.flags["HOST_CFLAGS"], reader.config.substs["HOST_CFLAGS"] 331 ) 332 self.assertEqual( 333 set(flags.flags["HOST_DEFINES"]), 334 set(["-DFOO", '-DBAZ="abcd"', "-UQUX", "-DBAR=7", "-DVALUE=xyz"]), 335 ) 336 self.assertEqual( 337 flags.flags["MOZBUILD_HOST_CFLAGS"], ["-funroll-loops", "-host-arg"] 338 ) 339 self.assertEqual(flags.flags["MOZBUILD_HOST_CXXFLAGS"], []) 340 341 def test_host_no_optimize_flags(self): 342 reader = self.reader( 343 "host-compile-flags", 344 extra_substs={"MOZ_OPTIMIZE": "", "MOZ_OPTIMIZE_FLAGS": ["-O2"]}, 345 ) 346 sources, ldflags, flags, lib, target_flags = self.read_topsrcdir(reader) 347 self.assertIsInstance(flags, ComputedFlags) 348 self.assertEqual(flags.flags["HOST_OPTIMIZE"], []) 349 350 def test_host_optimize_flags(self): 351 reader = self.reader( 352 "host-compile-flags", 353 extra_substs={"MOZ_OPTIMIZE": "1", "MOZ_OPTIMIZE_FLAGS": ["-O2"]}, 354 ) 355 sources, ldflags, flags, lib, target_flags = self.read_topsrcdir(reader) 356 self.assertIsInstance(flags, ComputedFlags) 357 self.assertEqual(flags.flags["HOST_OPTIMIZE"], ["-O2"]) 358 359 def test_cross_optimize_flags(self): 360 reader = self.reader( 361 "host-compile-flags", 362 extra_substs={ 363 "MOZ_OPTIMIZE": "1", 364 "MOZ_OPTIMIZE_FLAGS": ["-O2"], 365 "HOST_OPTIMIZE_FLAGS": ["-O3"], 366 "CROSS_COMPILE": "1", 367 }, 368 ) 369 sources, ldflags, flags, lib, target_flags = self.read_topsrcdir(reader) 370 self.assertIsInstance(flags, ComputedFlags) 371 self.assertEqual(flags.flags["HOST_OPTIMIZE"], ["-O3"]) 372 373 def test_host_rtl_flag(self): 374 reader = self.reader( 375 "host-compile-flags", extra_substs={"OS_ARCH": "WINNT", "MOZ_DEBUG": "1"} 376 ) 377 sources, ldflags, flags, lib, target_flags = self.read_topsrcdir(reader) 378 self.assertIsInstance(flags, ComputedFlags) 379 self.assertEqual(flags.flags["RTL"], ["-MDd"]) 380 381 def test_compile_flags_validation(self): 382 reader = self.reader("compile-flags-field-validation") 383 384 with six.assertRaisesRegex(self, BuildReaderError, "Invalid value."): 385 self.read_topsrcdir(reader) 386 387 reader = self.reader("compile-flags-type-validation") 388 with six.assertRaisesRegex( 389 self, BuildReaderError, "A list of strings must be provided" 390 ): 391 self.read_topsrcdir(reader) 392 393 def test_compile_flags_templates(self): 394 reader = self.reader( 395 "compile-flags-templates", 396 extra_substs={ 397 "NSPR_CFLAGS": ["-I/nspr/path"], 398 "NSS_CFLAGS": ["-I/nss/path"], 399 "MOZ_JPEG_CFLAGS": ["-I/jpeg/path"], 400 "MOZ_PNG_CFLAGS": ["-I/png/path"], 401 "MOZ_ZLIB_CFLAGS": ["-I/zlib/path"], 402 "MOZ_PIXMAN_CFLAGS": ["-I/pixman/path"], 403 }, 404 ) 405 sources, ldflags, lib, flags = self.read_topsrcdir(reader) 406 self.assertIsInstance(flags, ComputedFlags) 407 self.assertEqual(flags.flags["STL"], []) 408 self.assertEqual(flags.flags["VISIBILITY"], []) 409 self.assertEqual( 410 flags.flags["OS_INCLUDES"], 411 [ 412 "-I/nspr/path", 413 "-I/nss/path", 414 "-I/jpeg/path", 415 "-I/png/path", 416 "-I/zlib/path", 417 "-I/pixman/path", 418 ], 419 ) 420 421 def test_disable_stl_wrapping(self): 422 reader = self.reader("disable-stl-wrapping") 423 sources, ldflags, lib, flags = self.read_topsrcdir(reader) 424 self.assertIsInstance(flags, ComputedFlags) 425 self.assertEqual(flags.flags["STL"], []) 426 427 def test_visibility_flags(self): 428 reader = self.reader("visibility-flags") 429 sources, ldflags, lib, flags = self.read_topsrcdir(reader) 430 self.assertIsInstance(flags, ComputedFlags) 431 self.assertEqual(flags.flags["VISIBILITY"], []) 432 433 def test_defines_in_flags(self): 434 reader = self.reader("compile-defines") 435 defines, sources, ldflags, lib, flags = self.read_topsrcdir(reader) 436 self.assertIsInstance(flags, ComputedFlags) 437 self.assertEqual( 438 flags.flags["LIBRARY_DEFINES"], ["-DMOZ_LIBRARY_DEFINE=MOZ_TEST"] 439 ) 440 self.assertEqual(flags.flags["DEFINES"], ["-DMOZ_TEST_DEFINE"]) 441 442 def test_resolved_flags_error(self): 443 reader = self.reader("resolved-flags-error") 444 with six.assertRaisesRegex( 445 self, 446 BuildReaderError, 447 "`DEFINES` may not be set in COMPILE_FLAGS from moz.build", 448 ): 449 self.read_topsrcdir(reader) 450 451 def test_includes_in_flags(self): 452 reader = self.reader("compile-includes") 453 defines, sources, ldflags, lib, flags = self.read_topsrcdir(reader) 454 self.assertIsInstance(flags, ComputedFlags) 455 self.assertEqual( 456 flags.flags["BASE_INCLUDES"], 457 ["-I%s" % reader.config.topsrcdir, "-I%s" % reader.config.topobjdir], 458 ) 459 self.assertEqual( 460 flags.flags["EXTRA_INCLUDES"], 461 ["-I%s/dist/include" % reader.config.topobjdir], 462 ) 463 self.assertEqual( 464 flags.flags["LOCAL_INCLUDES"], ["-I%s/subdir" % reader.config.topsrcdir] 465 ) 466 467 def test_allow_compiler_warnings(self): 468 reader = self.reader( 469 "allow-compiler-warnings", extra_substs={"WARNINGS_AS_ERRORS": "-Werror"} 470 ) 471 sources, ldflags, lib, flags = self.read_topsrcdir(reader) 472 self.assertEqual(flags.flags["WARNINGS_AS_ERRORS"], []) 473 474 def test_disable_compiler_warnings(self): 475 reader = self.reader( 476 "disable-compiler-warnings", extra_substs={"WARNINGS_CFLAGS": "-Wall"} 477 ) 478 sources, ldflags, lib, flags = self.read_topsrcdir(reader) 479 self.assertEqual(flags.flags["WARNINGS_CFLAGS"], []) 480 481 def test_use_nasm(self): 482 # When nasm is not available, this should raise. 483 reader = self.reader("use-nasm") 484 with six.assertRaisesRegex( 485 self, SandboxValidationError, "nasm is not available" 486 ): 487 self.read_topsrcdir(reader) 488 489 # When nasm is available, this should work. 490 reader = self.reader( 491 "use-nasm", extra_substs=dict(NASM="nasm", NASM_ASFLAGS="-foo") 492 ) 493 494 sources, passthru, ldflags, lib, flags, asflags = self.read_topsrcdir(reader) 495 496 self.assertIsInstance(passthru, VariablePassthru) 497 self.assertIsInstance(ldflags, ComputedFlags) 498 self.assertIsInstance(flags, ComputedFlags) 499 self.assertIsInstance(asflags, ComputedFlags) 500 501 self.assertEqual(asflags.flags["OS"], reader.config.substs["NASM_ASFLAGS"]) 502 503 maxDiff = self.maxDiff 504 self.maxDiff = None 505 self.assertEqual( 506 passthru.variables, 507 {"AS": "nasm", "AS_DASH_C_FLAG": "", "ASOUTOPTION": "-o "}, 508 ) 509 self.maxDiff = maxDiff 510 511 def test_generated_files(self): 512 reader = self.reader("generated-files") 513 objs = self.read_topsrcdir(reader) 514 515 self.assertEqual(len(objs), 3) 516 for o in objs: 517 self.assertIsInstance(o, GeneratedFile) 518 self.assertFalse(o.localized) 519 self.assertFalse(o.force) 520 521 expected = ["bar.c", "foo.c", ("xpidllex.py", "xpidlyacc.py")] 522 for o, f in zip(objs, expected): 523 expected_filename = f if isinstance(f, tuple) else (f,) 524 self.assertEqual(o.outputs, expected_filename) 525 self.assertEqual(o.script, None) 526 self.assertEqual(o.method, None) 527 self.assertEqual(o.inputs, []) 528 529 def test_generated_files_force(self): 530 reader = self.reader("generated-files-force") 531 objs = self.read_topsrcdir(reader) 532 533 self.assertEqual(len(objs), 3) 534 for o in objs: 535 self.assertIsInstance(o, GeneratedFile) 536 self.assertEqual(o.force, "bar.c" in o.outputs) 537 538 def test_localized_generated_files(self): 539 reader = self.reader("localized-generated-files") 540 objs = self.read_topsrcdir(reader) 541 542 self.assertEqual(len(objs), 2) 543 for o in objs: 544 self.assertIsInstance(o, GeneratedFile) 545 self.assertTrue(o.localized) 546 547 expected = ["abc.ini", ("bar", "baz")] 548 for o, f in zip(objs, expected): 549 expected_filename = f if isinstance(f, tuple) else (f,) 550 self.assertEqual(o.outputs, expected_filename) 551 self.assertEqual(o.script, None) 552 self.assertEqual(o.method, None) 553 self.assertEqual(o.inputs, []) 554 555 def test_localized_generated_files_force(self): 556 reader = self.reader("localized-generated-files-force") 557 objs = self.read_topsrcdir(reader) 558 559 self.assertEqual(len(objs), 2) 560 for o in objs: 561 self.assertIsInstance(o, GeneratedFile) 562 self.assertTrue(o.localized) 563 self.assertEqual(o.force, "abc.ini" in o.outputs) 564 565 def test_localized_files_from_generated(self): 566 """Test that using LOCALIZED_GENERATED_FILES and then putting the output in 567 LOCALIZED_FILES as an objdir path works. 568 """ 569 reader = self.reader("localized-files-from-generated") 570 objs = self.read_topsrcdir(reader) 571 572 self.assertEqual(len(objs), 2) 573 self.assertIsInstance(objs[0], GeneratedFile) 574 self.assertIsInstance(objs[1], LocalizedFiles) 575 576 def test_localized_files_not_localized_generated(self): 577 """Test that using GENERATED_FILES and then putting the output in 578 LOCALIZED_FILES as an objdir path produces an error. 579 """ 580 reader = self.reader("localized-files-not-localized-generated") 581 with six.assertRaisesRegex( 582 self, 583 SandboxValidationError, 584 "Objdir file listed in LOCALIZED_FILES not in LOCALIZED_GENERATED_FILES:", 585 ): 586 self.read_topsrcdir(reader) 587 588 def test_localized_generated_files_final_target_files(self): 589 """Test that using LOCALIZED_GENERATED_FILES and then putting the output in 590 FINAL_TARGET_FILES as an objdir path produces an error. 591 """ 592 reader = self.reader("localized-generated-files-final-target-files") 593 with six.assertRaisesRegex( 594 self, 595 SandboxValidationError, 596 "Outputs of LOCALIZED_GENERATED_FILES cannot be used in FINAL_TARGET_FILES:", 597 ): 598 self.read_topsrcdir(reader) 599 600 def test_generated_files_method_names(self): 601 reader = self.reader("generated-files-method-names") 602 objs = self.read_topsrcdir(reader) 603 604 self.assertEqual(len(objs), 2) 605 for o in objs: 606 self.assertIsInstance(o, GeneratedFile) 607 608 expected = ["bar.c", "foo.c"] 609 expected_method_names = ["make_bar", "main"] 610 for o, expected_filename, expected_method in zip( 611 objs, expected, expected_method_names 612 ): 613 self.assertEqual(o.outputs, (expected_filename,)) 614 self.assertEqual(o.method, expected_method) 615 self.assertEqual(o.inputs, []) 616 617 def test_generated_files_absolute_script(self): 618 reader = self.reader("generated-files-absolute-script") 619 objs = self.read_topsrcdir(reader) 620 621 self.assertEqual(len(objs), 1) 622 623 o = objs[0] 624 self.assertIsInstance(o, GeneratedFile) 625 self.assertEqual(o.outputs, ("bar.c",)) 626 self.assertRegexpMatches(o.script, "script.py$") 627 self.assertEqual(o.method, "make_bar") 628 self.assertEqual(o.inputs, []) 629 630 def test_generated_files_no_script(self): 631 reader = self.reader("generated-files-no-script") 632 with six.assertRaisesRegex( 633 self, SandboxValidationError, "Script for generating bar.c does not exist" 634 ): 635 self.read_topsrcdir(reader) 636 637 def test_generated_files_no_inputs(self): 638 reader = self.reader("generated-files-no-inputs") 639 with six.assertRaisesRegex( 640 self, SandboxValidationError, "Input for generating foo.c does not exist" 641 ): 642 self.read_topsrcdir(reader) 643 644 def test_generated_files_no_python_script(self): 645 reader = self.reader("generated-files-no-python-script") 646 with six.assertRaisesRegex( 647 self, 648 SandboxValidationError, 649 "Script for generating bar.c does not end in .py", 650 ): 651 self.read_topsrcdir(reader) 652 653 def test_exports(self): 654 reader = self.reader("exports") 655 objs = self.read_topsrcdir(reader) 656 657 self.assertEqual(len(objs), 1) 658 self.assertIsInstance(objs[0], Exports) 659 660 expected = [ 661 ("", ["foo.h", "bar.h", "baz.h"]), 662 ("mozilla", ["mozilla1.h", "mozilla2.h"]), 663 ("mozilla/dom", ["dom1.h", "dom2.h", "dom3.h"]), 664 ("mozilla/gfx", ["gfx.h"]), 665 ("nspr/private", ["pprio.h", "pprthred.h"]), 666 ("vpx", ["mem.h", "mem2.h"]), 667 ] 668 for (expect_path, expect_headers), (actual_path, actual_headers) in zip( 669 expected, [(path, list(seq)) for path, seq in objs[0].files.walk()] 670 ): 671 self.assertEqual(expect_path, actual_path) 672 self.assertEqual(expect_headers, actual_headers) 673 674 def test_exports_missing(self): 675 """ 676 Missing files in EXPORTS is an error. 677 """ 678 reader = self.reader("exports-missing") 679 with six.assertRaisesRegex( 680 self, SandboxValidationError, "File listed in EXPORTS does not exist:" 681 ): 682 self.read_topsrcdir(reader) 683 684 def test_exports_missing_generated(self): 685 """ 686 An objdir file in EXPORTS that is not in GENERATED_FILES is an error. 687 """ 688 reader = self.reader("exports-missing-generated") 689 with six.assertRaisesRegex( 690 self, 691 SandboxValidationError, 692 "Objdir file listed in EXPORTS not in GENERATED_FILES:", 693 ): 694 self.read_topsrcdir(reader) 695 696 def test_exports_generated(self): 697 reader = self.reader("exports-generated") 698 objs = self.read_topsrcdir(reader) 699 700 self.assertEqual(len(objs), 2) 701 self.assertIsInstance(objs[0], GeneratedFile) 702 self.assertIsInstance(objs[1], Exports) 703 exports = [(path, list(seq)) for path, seq in objs[1].files.walk()] 704 self.assertEqual( 705 exports, [("", ["foo.h"]), ("mozilla", ["mozilla1.h", "!mozilla2.h"])] 706 ) 707 path, files = exports[1] 708 self.assertIsInstance(files[1], ObjDirPath) 709 710 def test_test_harness_files(self): 711 reader = self.reader("test-harness-files") 712 objs = self.read_topsrcdir(reader) 713 714 self.assertEqual(len(objs), 1) 715 self.assertIsInstance(objs[0], TestHarnessFiles) 716 717 expected = { 718 "mochitest": ["runtests.py", "utils.py"], 719 "testing/mochitest": ["mochitest.py", "mochitest.ini"], 720 } 721 722 for path, strings in objs[0].files.walk(): 723 self.assertTrue(path in expected) 724 basenames = sorted(mozpath.basename(s) for s in strings) 725 self.assertEqual(sorted(expected[path]), basenames) 726 727 def test_test_harness_files_root(self): 728 reader = self.reader("test-harness-files-root") 729 with six.assertRaisesRegex( 730 self, 731 SandboxValidationError, 732 "Cannot install files to the root of TEST_HARNESS_FILES", 733 ): 734 self.read_topsrcdir(reader) 735 736 def test_program(self): 737 reader = self.reader("program") 738 objs = self.read_topsrcdir(reader) 739 740 self.assertEqual(len(objs), 6) 741 self.assertIsInstance(objs[0], Sources) 742 self.assertIsInstance(objs[1], ComputedFlags) 743 self.assertIsInstance(objs[2], ComputedFlags) 744 self.assertIsInstance(objs[3], Program) 745 self.assertIsInstance(objs[4], SimpleProgram) 746 self.assertIsInstance(objs[5], SimpleProgram) 747 748 self.assertEqual(objs[3].program, "test_program.prog") 749 self.assertEqual(objs[4].program, "test_program1.prog") 750 self.assertEqual(objs[5].program, "test_program2.prog") 751 752 self.assertEqual(objs[3].name, "test_program.prog") 753 self.assertEqual(objs[4].name, "test_program1.prog") 754 self.assertEqual(objs[5].name, "test_program2.prog") 755 756 self.assertEqual( 757 objs[4].objs, 758 [ 759 mozpath.join( 760 reader.config.topobjdir, 761 "test_program1.%s" % reader.config.substs["OBJ_SUFFIX"], 762 ) 763 ], 764 ) 765 self.assertEqual( 766 objs[5].objs, 767 [ 768 mozpath.join( 769 reader.config.topobjdir, 770 "test_program2.%s" % reader.config.substs["OBJ_SUFFIX"], 771 ) 772 ], 773 ) 774 775 def test_program_paths(self): 776 """Various moz.build settings that change the destination of PROGRAM should be 777 accurately reflected in Program.output_path.""" 778 reader = self.reader("program-paths") 779 objs = self.read_topsrcdir(reader) 780 prog_paths = [o.output_path for o in objs if isinstance(o, Program)] 781 self.assertEqual( 782 prog_paths, 783 [ 784 "!/dist/bin/dist-bin.prog", 785 "!/dist/bin/foo/dist-subdir.prog", 786 "!/final/target/final-target.prog", 787 "!not-installed.prog", 788 ], 789 ) 790 791 def test_host_program_paths(self): 792 """The destination of a HOST_PROGRAM (almost always dist/host/bin) 793 should be accurately reflected in Program.output_path.""" 794 reader = self.reader("host-program-paths") 795 objs = self.read_topsrcdir(reader) 796 prog_paths = [o.output_path for o in objs if isinstance(o, HostProgram)] 797 self.assertEqual( 798 prog_paths, 799 [ 800 "!/dist/host/bin/final-target.hostprog", 801 "!/dist/host/bin/dist-host-bin.hostprog", 802 "!not-installed.hostprog", 803 ], 804 ) 805 806 def test_test_manifest_missing_manifest(self): 807 """A missing manifest file should result in an error.""" 808 reader = self.reader("test-manifest-missing-manifest") 809 810 with six.assertRaisesRegex(self, BuildReaderError, "Missing files"): 811 self.read_topsrcdir(reader) 812 813 def test_empty_test_manifest_rejected(self): 814 """A test manifest without any entries is rejected.""" 815 reader = self.reader("test-manifest-empty") 816 817 with six.assertRaisesRegex(self, SandboxValidationError, "Empty test manifest"): 818 self.read_topsrcdir(reader) 819 820 def test_test_manifest_just_support_files(self): 821 """A test manifest with no tests but support-files is not supported.""" 822 reader = self.reader("test-manifest-just-support") 823 824 with six.assertRaisesRegex(self, SandboxValidationError, "Empty test manifest"): 825 self.read_topsrcdir(reader) 826 827 def test_test_manifest_dupe_support_files(self): 828 """A test manifest with dupe support-files in a single test is not 829 supported. 830 """ 831 reader = self.reader("test-manifest-dupes") 832 833 with six.assertRaisesRegex( 834 self, 835 SandboxValidationError, 836 "bar.js appears multiple times " 837 "in a test manifest under a support-files field, please omit the duplicate entry.", 838 ): 839 self.read_topsrcdir(reader) 840 841 def test_test_manifest_absolute_support_files(self): 842 """Support files starting with '/' are placed relative to the install root""" 843 reader = self.reader("test-manifest-absolute-support") 844 845 objs = self.read_topsrcdir(reader) 846 self.assertEqual(len(objs), 1) 847 o = objs[0] 848 self.assertEqual(len(o.installs), 3) 849 expected = [ 850 mozpath.normpath(mozpath.join(o.install_prefix, "../.well-known/foo.txt")), 851 mozpath.join(o.install_prefix, "absolute-support.ini"), 852 mozpath.join(o.install_prefix, "test_file.js"), 853 ] 854 paths = sorted([v[0] for v in o.installs.values()]) 855 self.assertEqual(paths, expected) 856 857 @unittest.skip("Bug 1304316 - Items in the second set but not the first") 858 def test_test_manifest_shared_support_files(self): 859 """Support files starting with '!' are given separate treatment, so their 860 installation can be resolved when running tests. 861 """ 862 reader = self.reader("test-manifest-shared-support") 863 supported, child = self.read_topsrcdir(reader) 864 865 expected_deferred_installs = { 866 "!/child/test_sub.js", 867 "!/child/another-file.sjs", 868 "!/child/data/**", 869 } 870 871 self.assertEqual(len(supported.installs), 3) 872 self.assertEqual(set(supported.deferred_installs), expected_deferred_installs) 873 self.assertEqual(len(child.installs), 3) 874 self.assertEqual(len(child.pattern_installs), 1) 875 876 def test_test_manifest_deffered_install_missing(self): 877 """A non-existent shared support file reference produces an error.""" 878 reader = self.reader("test-manifest-shared-missing") 879 880 with six.assertRaisesRegex( 881 self, 882 SandboxValidationError, 883 "entry in support-files not present in the srcdir", 884 ): 885 self.read_topsrcdir(reader) 886 887 def test_test_manifest_install_includes(self): 888 """Ensure that any [include:foo.ini] are copied to the objdir.""" 889 reader = self.reader("test-manifest-install-includes") 890 891 objs = self.read_topsrcdir(reader) 892 self.assertEqual(len(objs), 1) 893 o = objs[0] 894 self.assertEqual(len(o.installs), 3) 895 self.assertEqual(o.manifest_relpath, "mochitest.ini") 896 self.assertEqual(o.manifest_obj_relpath, "mochitest.ini") 897 expected = [ 898 mozpath.normpath(mozpath.join(o.install_prefix, "common.ini")), 899 mozpath.normpath(mozpath.join(o.install_prefix, "mochitest.ini")), 900 mozpath.normpath(mozpath.join(o.install_prefix, "test_foo.html")), 901 ] 902 paths = sorted([v[0] for v in o.installs.values()]) 903 self.assertEqual(paths, expected) 904 905 def test_test_manifest_includes(self): 906 """Ensure that manifest objects from the emitter list a correct manifest.""" 907 reader = self.reader("test-manifest-emitted-includes") 908 [obj] = self.read_topsrcdir(reader) 909 910 # Expected manifest leafs for our tests. 911 expected_manifests = { 912 "reftest1.html": "reftest.list", 913 "reftest1-ref.html": "reftest.list", 914 "reftest2.html": "included-reftest.list", 915 "reftest2-ref.html": "included-reftest.list", 916 } 917 918 for t in obj.tests: 919 self.assertTrue(t["manifest"].endswith(expected_manifests[t["name"]])) 920 921 def test_test_manifest_keys_extracted(self): 922 """Ensure all metadata from test manifests is extracted.""" 923 reader = self.reader("test-manifest-keys-extracted") 924 925 objs = [o for o in self.read_topsrcdir(reader) if isinstance(o, TestManifest)] 926 927 self.assertEqual(len(objs), 8) 928 929 metadata = { 930 "a11y.ini": { 931 "flavor": "a11y", 932 "installs": {"a11y.ini": False, "test_a11y.js": True}, 933 "pattern-installs": 1, 934 }, 935 "browser.ini": { 936 "flavor": "browser-chrome", 937 "installs": { 938 "browser.ini": False, 939 "test_browser.js": True, 940 "support1": False, 941 "support2": False, 942 }, 943 }, 944 "mochitest.ini": { 945 "flavor": "mochitest", 946 "installs": {"mochitest.ini": False, "test_mochitest.js": True}, 947 "external": {"external1", "external2"}, 948 }, 949 "chrome.ini": { 950 "flavor": "chrome", 951 "installs": {"chrome.ini": False, "test_chrome.js": True}, 952 }, 953 "xpcshell.ini": { 954 "flavor": "xpcshell", 955 "dupe": True, 956 "installs": { 957 "xpcshell.ini": False, 958 "test_xpcshell.js": True, 959 "head1": False, 960 "head2": False, 961 }, 962 }, 963 "reftest.list": {"flavor": "reftest", "installs": {}}, 964 "crashtest.list": {"flavor": "crashtest", "installs": {}}, 965 "python.ini": {"flavor": "python", "installs": {"python.ini": False}}, 966 } 967 968 for o in objs: 969 m = metadata[mozpath.basename(o.manifest_relpath)] 970 971 self.assertTrue(o.path.startswith(o.directory)) 972 self.assertEqual(o.flavor, m["flavor"]) 973 self.assertEqual(o.dupe_manifest, m.get("dupe", False)) 974 975 external_normalized = set(mozpath.basename(p) for p in o.external_installs) 976 self.assertEqual(external_normalized, m.get("external", set())) 977 978 self.assertEqual(len(o.installs), len(m["installs"])) 979 for path in o.installs.keys(): 980 self.assertTrue(path.startswith(o.directory)) 981 relpath = path[len(o.directory) + 1 :] 982 983 self.assertIn(relpath, m["installs"]) 984 self.assertEqual(o.installs[path][1], m["installs"][relpath]) 985 986 if "pattern-installs" in m: 987 self.assertEqual(len(o.pattern_installs), m["pattern-installs"]) 988 989 def test_test_manifest_unmatched_generated(self): 990 reader = self.reader("test-manifest-unmatched-generated") 991 992 with six.assertRaisesRegex( 993 self, 994 SandboxValidationError, 995 "entry in generated-files not present elsewhere", 996 ): 997 self.read_topsrcdir(reader), 998 999 def test_test_manifest_parent_support_files_dir(self): 1000 """support-files referencing a file in a parent directory works.""" 1001 reader = self.reader("test-manifest-parent-support-files-dir") 1002 1003 objs = [o for o in self.read_topsrcdir(reader) if isinstance(o, TestManifest)] 1004 1005 self.assertEqual(len(objs), 1) 1006 1007 o = objs[0] 1008 1009 expected = mozpath.join(o.srcdir, "support-file.txt") 1010 self.assertIn(expected, o.installs) 1011 self.assertEqual( 1012 o.installs[expected], 1013 ("testing/mochitest/tests/child/support-file.txt", False), 1014 ) 1015 1016 def test_test_manifest_missing_test_error(self): 1017 """Missing test files should result in error.""" 1018 reader = self.reader("test-manifest-missing-test-file") 1019 1020 with six.assertRaisesRegex( 1021 self, 1022 SandboxValidationError, 1023 "lists test that does not exist: test_missing.html", 1024 ): 1025 self.read_topsrcdir(reader) 1026 1027 def test_test_manifest_missing_test_error_unfiltered(self): 1028 """Missing test files should result in error, even when the test list is not filtered.""" 1029 reader = self.reader("test-manifest-missing-test-file-unfiltered") 1030 1031 with six.assertRaisesRegex( 1032 self, SandboxValidationError, "lists test that does not exist: missing.js" 1033 ): 1034 self.read_topsrcdir(reader) 1035 1036 def test_ipdl_sources(self): 1037 reader = self.reader( 1038 "ipdl_sources", 1039 extra_substs={"IPDL_ROOT": mozpath.abspath("/path/to/topobjdir")}, 1040 ) 1041 objs = self.read_topsrcdir(reader) 1042 ipdl_collection = objs[0] 1043 self.assertIsInstance(ipdl_collection, IPDLCollection) 1044 1045 ipdls = set( 1046 mozpath.relpath(p, ipdl_collection.topsrcdir) 1047 for p in ipdl_collection.all_regular_sources() 1048 ) 1049 expected = set( 1050 ["bar/bar.ipdl", "bar/bar2.ipdlh", "foo/foo.ipdl", "foo/foo2.ipdlh"] 1051 ) 1052 1053 self.assertEqual(ipdls, expected) 1054 1055 pp_ipdls = set( 1056 mozpath.relpath(p, ipdl_collection.topsrcdir) 1057 for p in ipdl_collection.all_preprocessed_sources() 1058 ) 1059 expected = set(["bar/bar1.ipdl", "foo/foo1.ipdl"]) 1060 self.assertEqual(pp_ipdls, expected) 1061 1062 generated_sources = set(ipdl_collection.all_generated_sources()) 1063 expected = set( 1064 [ 1065 "bar.cpp", 1066 "barChild.cpp", 1067 "barParent.cpp", 1068 "bar1.cpp", 1069 "bar1Child.cpp", 1070 "bar1Parent.cpp", 1071 "bar2.cpp", 1072 "foo.cpp", 1073 "fooChild.cpp", 1074 "fooParent.cpp", 1075 "foo1.cpp", 1076 "foo1Child.cpp", 1077 "foo1Parent.cpp", 1078 "foo2.cpp", 1079 ] 1080 ) 1081 self.assertEqual(generated_sources, expected) 1082 1083 def test_local_includes(self): 1084 """Test that LOCAL_INCLUDES is emitted correctly.""" 1085 reader = self.reader("local_includes") 1086 objs = self.read_topsrcdir(reader) 1087 1088 local_includes = [o.path for o in objs if isinstance(o, LocalInclude)] 1089 expected = ["/bar/baz", "foo"] 1090 1091 self.assertEqual(local_includes, expected) 1092 1093 local_includes = [o.path.full_path for o in objs if isinstance(o, LocalInclude)] 1094 expected = [ 1095 mozpath.join(reader.config.topsrcdir, "bar/baz"), 1096 mozpath.join(reader.config.topsrcdir, "foo"), 1097 ] 1098 1099 self.assertEqual(local_includes, expected) 1100 1101 def test_local_includes_invalid(self): 1102 """Test that invalid LOCAL_INCLUDES are properly detected.""" 1103 reader = self.reader("local_includes-invalid/srcdir") 1104 1105 with six.assertRaisesRegex( 1106 self, 1107 SandboxValidationError, 1108 "Path specified in LOCAL_INCLUDES.*resolves to the " 1109 "topsrcdir or topobjdir", 1110 ): 1111 self.read_topsrcdir(reader) 1112 1113 reader = self.reader("local_includes-invalid/objdir") 1114 1115 with six.assertRaisesRegex( 1116 self, 1117 SandboxValidationError, 1118 "Path specified in LOCAL_INCLUDES.*resolves to the " 1119 "topsrcdir or topobjdir", 1120 ): 1121 self.read_topsrcdir(reader) 1122 1123 def test_local_includes_file(self): 1124 """Test that a filename can't be used in LOCAL_INCLUDES.""" 1125 reader = self.reader("local_includes-filename") 1126 1127 with six.assertRaisesRegex( 1128 self, 1129 SandboxValidationError, 1130 "Path specified in LOCAL_INCLUDES is a filename", 1131 ): 1132 self.read_topsrcdir(reader) 1133 1134 def test_generated_includes(self): 1135 """Test that GENERATED_INCLUDES is emitted correctly.""" 1136 reader = self.reader("generated_includes") 1137 objs = self.read_topsrcdir(reader) 1138 1139 generated_includes = [o.path for o in objs if isinstance(o, LocalInclude)] 1140 expected = ["!/bar/baz", "!foo"] 1141 1142 self.assertEqual(generated_includes, expected) 1143 1144 generated_includes = [ 1145 o.path.full_path for o in objs if isinstance(o, LocalInclude) 1146 ] 1147 expected = [ 1148 mozpath.join(reader.config.topobjdir, "bar/baz"), 1149 mozpath.join(reader.config.topobjdir, "foo"), 1150 ] 1151 1152 self.assertEqual(generated_includes, expected) 1153 1154 def test_defines(self): 1155 reader = self.reader("defines") 1156 objs = self.read_topsrcdir(reader) 1157 1158 defines = {} 1159 for o in objs: 1160 if isinstance(o, Defines): 1161 defines = o.defines 1162 1163 expected = { 1164 "BAR": 7, 1165 "BAZ": '"abcd"', 1166 "FOO": True, 1167 "VALUE": "xyz", 1168 "QUX": False, 1169 } 1170 1171 self.assertEqual(defines, expected) 1172 1173 def test_jar_manifests(self): 1174 reader = self.reader("jar-manifests") 1175 objs = self.read_topsrcdir(reader) 1176 1177 self.assertEqual(len(objs), 1) 1178 for obj in objs: 1179 self.assertIsInstance(obj, JARManifest) 1180 self.assertIsInstance(obj.path, Path) 1181 1182 def test_jar_manifests_multiple_files(self): 1183 with six.assertRaisesRegex( 1184 self, SandboxValidationError, "limited to one value" 1185 ): 1186 reader = self.reader("jar-manifests-multiple-files") 1187 self.read_topsrcdir(reader) 1188 1189 def test_xpidl_module_no_sources(self): 1190 """XPIDL_MODULE without XPIDL_SOURCES should be rejected.""" 1191 with six.assertRaisesRegex( 1192 self, SandboxValidationError, "XPIDL_MODULE " "cannot be defined" 1193 ): 1194 reader = self.reader("xpidl-module-no-sources") 1195 self.read_topsrcdir(reader) 1196 1197 def test_xpidl_module_missing_sources(self): 1198 """Missing XPIDL_SOURCES should be rejected.""" 1199 with six.assertRaisesRegex( 1200 self, SandboxValidationError, "File .* " "from XPIDL_SOURCES does not exist" 1201 ): 1202 reader = self.reader("missing-xpidl") 1203 self.read_topsrcdir(reader) 1204 1205 def test_missing_local_includes(self): 1206 """LOCAL_INCLUDES containing non-existent directories should be rejected.""" 1207 with six.assertRaisesRegex( 1208 self, 1209 SandboxValidationError, 1210 "Path specified in " "LOCAL_INCLUDES does not exist", 1211 ): 1212 reader = self.reader("missing-local-includes") 1213 self.read_topsrcdir(reader) 1214 1215 def test_library_defines(self): 1216 """Test that LIBRARY_DEFINES is propagated properly.""" 1217 reader = self.reader("library-defines") 1218 objs = self.read_topsrcdir(reader) 1219 1220 libraries = [o for o in objs if isinstance(o, StaticLibrary)] 1221 library_flags = [ 1222 o 1223 for o in objs 1224 if isinstance(o, ComputedFlags) and "LIBRARY_DEFINES" in o.flags 1225 ] 1226 expected = { 1227 "liba": "-DIN_LIBA", 1228 "libb": "-DIN_LIBB -DIN_LIBA", 1229 "libc": "-DIN_LIBA -DIN_LIBB", 1230 "libd": "", 1231 } 1232 defines = {} 1233 for lib in libraries: 1234 defines[lib.basename] = " ".join(lib.lib_defines.get_defines()) 1235 self.assertEqual(expected, defines) 1236 defines_in_flags = {} 1237 for flags in library_flags: 1238 defines_in_flags[flags.relobjdir] = " ".join( 1239 flags.flags["LIBRARY_DEFINES"] or [] 1240 ) 1241 self.assertEqual(expected, defines_in_flags) 1242 1243 def test_sources(self): 1244 """Test that SOURCES works properly.""" 1245 reader = self.reader("sources") 1246 objs = self.read_topsrcdir(reader) 1247 1248 as_flags = objs.pop() 1249 self.assertIsInstance(as_flags, ComputedFlags) 1250 computed_flags = objs.pop() 1251 self.assertIsInstance(computed_flags, ComputedFlags) 1252 # The third to last object is a Linkable. 1253 linkable = objs.pop() 1254 self.assertTrue(linkable.cxx_link) 1255 ld_flags = objs.pop() 1256 self.assertIsInstance(ld_flags, ComputedFlags) 1257 self.assertEqual(len(objs), 6) 1258 for o in objs: 1259 self.assertIsInstance(o, Sources) 1260 1261 suffix_map = {obj.canonical_suffix: obj for obj in objs} 1262 self.assertEqual(len(suffix_map), 6) 1263 1264 expected = { 1265 ".cpp": ["a.cpp", "b.cc", "c.cxx"], 1266 ".c": ["d.c"], 1267 ".m": ["e.m"], 1268 ".mm": ["f.mm"], 1269 ".S": ["g.S"], 1270 ".s": ["h.s", "i.asm"], 1271 } 1272 for suffix, files in expected.items(): 1273 sources = suffix_map[suffix] 1274 self.assertEqual( 1275 sources.files, [mozpath.join(reader.config.topsrcdir, f) for f in files] 1276 ) 1277 1278 for f in files: 1279 self.assertIn( 1280 mozpath.join( 1281 reader.config.topobjdir, 1282 "%s.%s" 1283 % (mozpath.splitext(f)[0], reader.config.substs["OBJ_SUFFIX"]), 1284 ), 1285 linkable.objs, 1286 ) 1287 1288 def test_sources_just_c(self): 1289 """Test that a linkable with no C++ sources doesn't have cxx_link set.""" 1290 reader = self.reader("sources-just-c") 1291 objs = self.read_topsrcdir(reader) 1292 1293 as_flags = objs.pop() 1294 self.assertIsInstance(as_flags, ComputedFlags) 1295 flags = objs.pop() 1296 self.assertIsInstance(flags, ComputedFlags) 1297 # The third to last object is a Linkable. 1298 linkable = objs.pop() 1299 self.assertFalse(linkable.cxx_link) 1300 1301 def test_linkables_cxx_link(self): 1302 """Test that linkables transitively set cxx_link properly.""" 1303 reader = self.reader("test-linkables-cxx-link") 1304 got_results = 0 1305 for obj in self.read_topsrcdir(reader): 1306 if isinstance(obj, SharedLibrary): 1307 if obj.basename == "cxx_shared": 1308 self.assertEquals( 1309 obj.name, 1310 "%scxx_shared%s" 1311 % (reader.config.dll_prefix, reader.config.dll_suffix), 1312 ) 1313 self.assertTrue(obj.cxx_link) 1314 got_results += 1 1315 elif obj.basename == "just_c_shared": 1316 self.assertEquals( 1317 obj.name, 1318 "%sjust_c_shared%s" 1319 % (reader.config.dll_prefix, reader.config.dll_suffix), 1320 ) 1321 self.assertFalse(obj.cxx_link) 1322 got_results += 1 1323 self.assertEqual(got_results, 2) 1324 1325 def test_generated_sources(self): 1326 """Test that GENERATED_SOURCES works properly.""" 1327 reader = self.reader("generated-sources") 1328 objs = self.read_topsrcdir(reader) 1329 1330 as_flags = objs.pop() 1331 self.assertIsInstance(as_flags, ComputedFlags) 1332 flags = objs.pop() 1333 self.assertIsInstance(flags, ComputedFlags) 1334 # The third to last object is a Linkable. 1335 linkable = objs.pop() 1336 self.assertTrue(linkable.cxx_link) 1337 flags = objs.pop() 1338 self.assertIsInstance(flags, ComputedFlags) 1339 self.assertEqual(len(objs), 6) 1340 1341 generated_sources = [o for o in objs if isinstance(o, GeneratedSources)] 1342 self.assertEqual(len(generated_sources), 6) 1343 1344 suffix_map = {obj.canonical_suffix: obj for obj in generated_sources} 1345 self.assertEqual(len(suffix_map), 6) 1346 1347 expected = { 1348 ".cpp": ["a.cpp", "b.cc", "c.cxx"], 1349 ".c": ["d.c"], 1350 ".m": ["e.m"], 1351 ".mm": ["f.mm"], 1352 ".S": ["g.S"], 1353 ".s": ["h.s", "i.asm"], 1354 } 1355 for suffix, files in expected.items(): 1356 sources = suffix_map[suffix] 1357 self.assertEqual( 1358 sources.files, [mozpath.join(reader.config.topobjdir, f) for f in files] 1359 ) 1360 1361 for f in files: 1362 self.assertIn( 1363 mozpath.join( 1364 reader.config.topobjdir, 1365 "%s.%s" 1366 % (mozpath.splitext(f)[0], reader.config.substs["OBJ_SUFFIX"]), 1367 ), 1368 linkable.objs, 1369 ) 1370 1371 def test_host_sources(self): 1372 """Test that HOST_SOURCES works properly.""" 1373 reader = self.reader("host-sources") 1374 objs = self.read_topsrcdir(reader) 1375 1376 # This objdir will generate target flags. 1377 flags = objs.pop() 1378 self.assertIsInstance(flags, ComputedFlags) 1379 # The second to last object is a Linkable 1380 linkable = objs.pop() 1381 self.assertTrue(linkable.cxx_link) 1382 # This objdir will also generate host flags. 1383 host_flags = objs.pop() 1384 self.assertIsInstance(host_flags, ComputedFlags) 1385 # ...and ldflags. 1386 ldflags = objs.pop() 1387 self.assertIsInstance(ldflags, ComputedFlags) 1388 self.assertEqual(len(objs), 3) 1389 for o in objs: 1390 self.assertIsInstance(o, HostSources) 1391 1392 suffix_map = {obj.canonical_suffix: obj for obj in objs} 1393 self.assertEqual(len(suffix_map), 3) 1394 1395 expected = { 1396 ".cpp": ["a.cpp", "b.cc", "c.cxx"], 1397 ".c": ["d.c"], 1398 ".mm": ["e.mm", "f.mm"], 1399 } 1400 for suffix, files in expected.items(): 1401 sources = suffix_map[suffix] 1402 self.assertEqual( 1403 sources.files, [mozpath.join(reader.config.topsrcdir, f) for f in files] 1404 ) 1405 1406 for f in files: 1407 self.assertIn( 1408 mozpath.join( 1409 reader.config.topobjdir, 1410 "host_%s.%s" 1411 % (mozpath.splitext(f)[0], reader.config.substs["OBJ_SUFFIX"]), 1412 ), 1413 linkable.objs, 1414 ) 1415 1416 def test_wasm_sources(self): 1417 """Test that WASM_SOURCES works properly.""" 1418 reader = self.reader("wasm-sources", extra_substs={"OS_TARGET": "Linux"}) 1419 objs = list(self.read_topsrcdir(reader)) 1420 1421 # The second to last object is a linkable. 1422 linkable = objs[-2] 1423 # Other than that, we only care about the WasmSources objects. 1424 objs = objs[:2] 1425 for o in objs: 1426 self.assertIsInstance(o, WasmSources) 1427 1428 suffix_map = {obj.canonical_suffix: obj for obj in objs} 1429 self.assertEqual(len(suffix_map), 2) 1430 1431 expected = {".cpp": ["a.cpp", "b.cc", "c.cxx"], ".c": ["d.c"]} 1432 for suffix, files in expected.items(): 1433 sources = suffix_map[suffix] 1434 self.assertEqual( 1435 sources.files, [mozpath.join(reader.config.topsrcdir, f) for f in files] 1436 ) 1437 for f in files: 1438 self.assertIn( 1439 mozpath.join( 1440 reader.config.topobjdir, 1441 "%s.%s" 1442 % ( 1443 mozpath.splitext(f)[0], 1444 reader.config.substs["WASM_OBJ_SUFFIX"], 1445 ), 1446 ), 1447 linkable.objs, 1448 ) 1449 1450 def test_unified_sources(self): 1451 """Test that UNIFIED_SOURCES works properly.""" 1452 reader = self.reader("unified-sources") 1453 objs = self.read_topsrcdir(reader) 1454 1455 # The last object is a ComputedFlags, the second to last a Linkable, 1456 # followed by ldflags, ignore them. 1457 linkable = objs[-2] 1458 objs = objs[:-3] 1459 self.assertEqual(len(objs), 3) 1460 for o in objs: 1461 self.assertIsInstance(o, UnifiedSources) 1462 1463 suffix_map = {obj.canonical_suffix: obj for obj in objs} 1464 self.assertEqual(len(suffix_map), 3) 1465 1466 expected = { 1467 ".cpp": ["bar.cxx", "foo.cpp", "quux.cc"], 1468 ".mm": ["objc1.mm", "objc2.mm"], 1469 ".c": ["c1.c", "c2.c"], 1470 } 1471 for suffix, files in expected.items(): 1472 sources = suffix_map[suffix] 1473 self.assertEqual( 1474 sources.files, [mozpath.join(reader.config.topsrcdir, f) for f in files] 1475 ) 1476 self.assertTrue(sources.have_unified_mapping) 1477 1478 for f in dict(sources.unified_source_mapping).keys(): 1479 self.assertIn( 1480 mozpath.join( 1481 reader.config.topobjdir, 1482 "%s.%s" 1483 % (mozpath.splitext(f)[0], reader.config.substs["OBJ_SUFFIX"]), 1484 ), 1485 linkable.objs, 1486 ) 1487 1488 def test_unified_sources_non_unified(self): 1489 """Test that UNIFIED_SOURCES with FILES_PER_UNIFIED_FILE=1 works properly.""" 1490 reader = self.reader("unified-sources-non-unified") 1491 objs = self.read_topsrcdir(reader) 1492 1493 # The last object is a Linkable, the second to last ComputedFlags, 1494 # followed by ldflags, ignore them. 1495 objs = objs[:-3] 1496 self.assertEqual(len(objs), 3) 1497 for o in objs: 1498 self.assertIsInstance(o, UnifiedSources) 1499 1500 suffix_map = {obj.canonical_suffix: obj for obj in objs} 1501 self.assertEqual(len(suffix_map), 3) 1502 1503 expected = { 1504 ".cpp": ["bar.cxx", "foo.cpp", "quux.cc"], 1505 ".mm": ["objc1.mm", "objc2.mm"], 1506 ".c": ["c1.c", "c2.c"], 1507 } 1508 for suffix, files in expected.items(): 1509 sources = suffix_map[suffix] 1510 self.assertEqual( 1511 sources.files, [mozpath.join(reader.config.topsrcdir, f) for f in files] 1512 ) 1513 self.assertFalse(sources.have_unified_mapping) 1514 1515 def test_final_target_pp_files(self): 1516 """Test that FINAL_TARGET_PP_FILES works properly.""" 1517 reader = self.reader("dist-files") 1518 objs = self.read_topsrcdir(reader) 1519 1520 self.assertEqual(len(objs), 1) 1521 self.assertIsInstance(objs[0], FinalTargetPreprocessedFiles) 1522 1523 # Ideally we'd test hierarchies, but that would just be testing 1524 # the HierarchicalStringList class, which we test separately. 1525 for path, files in objs[0].files.walk(): 1526 self.assertEqual(path, "") 1527 self.assertEqual(len(files), 2) 1528 1529 expected = {"install.rdf", "main.js"} 1530 for f in files: 1531 self.assertTrue(six.text_type(f) in expected) 1532 1533 def test_missing_final_target_pp_files(self): 1534 """Test that FINAL_TARGET_PP_FILES with missing files throws errors.""" 1535 with six.assertRaisesRegex( 1536 self, 1537 SandboxValidationError, 1538 "File listed in " "FINAL_TARGET_PP_FILES does not exist", 1539 ): 1540 reader = self.reader("dist-files-missing") 1541 self.read_topsrcdir(reader) 1542 1543 def test_final_target_pp_files_non_srcdir(self): 1544 """Test that non-srcdir paths in FINAL_TARGET_PP_FILES throws errors.""" 1545 reader = self.reader("final-target-pp-files-non-srcdir") 1546 with six.assertRaisesRegex( 1547 self, 1548 SandboxValidationError, 1549 "Only source directory paths allowed in FINAL_TARGET_PP_FILES:", 1550 ): 1551 self.read_topsrcdir(reader) 1552 1553 def test_localized_files(self): 1554 """Test that LOCALIZED_FILES works properly.""" 1555 reader = self.reader("localized-files") 1556 objs = self.read_topsrcdir(reader) 1557 1558 self.assertEqual(len(objs), 1) 1559 self.assertIsInstance(objs[0], LocalizedFiles) 1560 1561 for path, files in objs[0].files.walk(): 1562 self.assertEqual(path, "foo") 1563 self.assertEqual(len(files), 3) 1564 1565 expected = {"en-US/bar.ini", "en-US/code/*.js", "en-US/foo.js"} 1566 for f in files: 1567 self.assertTrue(six.text_type(f) in expected) 1568 1569 def test_localized_files_no_en_us(self): 1570 """Test that LOCALIZED_FILES errors if a path does not start with 1571 `en-US/` or contain `locales/en-US/`.""" 1572 reader = self.reader("localized-files-no-en-us") 1573 with six.assertRaisesRegex( 1574 self, 1575 SandboxValidationError, 1576 "LOCALIZED_FILES paths must start with `en-US/` or contain `locales/en-US/`: " 1577 "foo.js", 1578 ): 1579 self.read_topsrcdir(reader) 1580 1581 def test_localized_pp_files(self): 1582 """Test that LOCALIZED_PP_FILES works properly.""" 1583 reader = self.reader("localized-pp-files") 1584 objs = self.read_topsrcdir(reader) 1585 1586 self.assertEqual(len(objs), 1) 1587 self.assertIsInstance(objs[0], LocalizedPreprocessedFiles) 1588 1589 for path, files in objs[0].files.walk(): 1590 self.assertEqual(path, "foo") 1591 self.assertEqual(len(files), 2) 1592 1593 expected = {"en-US/bar.ini", "en-US/foo.js"} 1594 for f in files: 1595 self.assertTrue(six.text_type(f) in expected) 1596 1597 def test_rust_library_no_cargo_toml(self): 1598 """Test that defining a RustLibrary without a Cargo.toml fails.""" 1599 reader = self.reader("rust-library-no-cargo-toml") 1600 with six.assertRaisesRegex( 1601 self, SandboxValidationError, "No Cargo.toml file found" 1602 ): 1603 self.read_topsrcdir(reader) 1604 1605 def test_rust_library_name_mismatch(self): 1606 """Test that defining a RustLibrary that doesn't match Cargo.toml fails.""" 1607 reader = self.reader("rust-library-name-mismatch") 1608 with six.assertRaisesRegex( 1609 self, 1610 SandboxValidationError, 1611 "library.*does not match Cargo.toml-defined package", 1612 ): 1613 self.read_topsrcdir(reader) 1614 1615 def test_rust_library_no_lib_section(self): 1616 """Test that a RustLibrary Cargo.toml with no [lib] section fails.""" 1617 reader = self.reader("rust-library-no-lib-section") 1618 with six.assertRaisesRegex( 1619 self, SandboxValidationError, "Cargo.toml for.* has no \\[lib\\] section" 1620 ): 1621 self.read_topsrcdir(reader) 1622 1623 def test_rust_library_invalid_crate_type(self): 1624 """Test that a RustLibrary Cargo.toml has a permitted crate-type.""" 1625 reader = self.reader("rust-library-invalid-crate-type") 1626 with six.assertRaisesRegex( 1627 self, SandboxValidationError, "crate-type.* is not permitted" 1628 ): 1629 self.read_topsrcdir(reader) 1630 1631 def test_rust_library_dash_folding(self): 1632 """Test that on-disk names of RustLibrary objects convert dashes to underscores.""" 1633 reader = self.reader( 1634 "rust-library-dash-folding", 1635 extra_substs=dict(RUST_TARGET="i686-pc-windows-msvc"), 1636 ) 1637 objs = self.read_topsrcdir(reader) 1638 1639 self.assertEqual(len(objs), 3) 1640 ldflags, lib, cflags = objs 1641 self.assertIsInstance(ldflags, ComputedFlags) 1642 self.assertIsInstance(cflags, ComputedFlags) 1643 self.assertIsInstance(lib, RustLibrary) 1644 self.assertRegexpMatches(lib.lib_name, "random_crate") 1645 self.assertRegexpMatches(lib.import_name, "random_crate") 1646 self.assertRegexpMatches(lib.basename, "random-crate") 1647 1648 def test_multiple_rust_libraries(self): 1649 """Test that linking multiple Rust libraries throws an error""" 1650 reader = self.reader( 1651 "multiple-rust-libraries", 1652 extra_substs=dict(RUST_TARGET="i686-pc-windows-msvc"), 1653 ) 1654 with six.assertRaisesRegex( 1655 self, SandboxValidationError, "Cannot link the following Rust libraries" 1656 ): 1657 self.read_topsrcdir(reader) 1658 1659 def test_rust_library_features(self): 1660 """Test that RustLibrary features are correctly emitted.""" 1661 reader = self.reader( 1662 "rust-library-features", 1663 extra_substs=dict(RUST_TARGET="i686-pc-windows-msvc"), 1664 ) 1665 objs = self.read_topsrcdir(reader) 1666 1667 self.assertEqual(len(objs), 3) 1668 ldflags, lib, cflags = objs 1669 self.assertIsInstance(ldflags, ComputedFlags) 1670 self.assertIsInstance(cflags, ComputedFlags) 1671 self.assertIsInstance(lib, RustLibrary) 1672 self.assertEqual(lib.features, ["musthave", "cantlivewithout"]) 1673 1674 def test_rust_library_duplicate_features(self): 1675 """Test that duplicate RustLibrary features are rejected.""" 1676 reader = self.reader("rust-library-duplicate-features") 1677 with six.assertRaisesRegex( 1678 self, 1679 SandboxValidationError, 1680 "features for .* should not contain duplicates", 1681 ): 1682 self.read_topsrcdir(reader) 1683 1684 def test_rust_program_no_cargo_toml(self): 1685 """Test that specifying RUST_PROGRAMS without a Cargo.toml fails.""" 1686 reader = self.reader("rust-program-no-cargo-toml") 1687 with six.assertRaisesRegex( 1688 self, SandboxValidationError, "No Cargo.toml file found" 1689 ): 1690 self.read_topsrcdir(reader) 1691 1692 def test_host_rust_program_no_cargo_toml(self): 1693 """Test that specifying HOST_RUST_PROGRAMS without a Cargo.toml fails.""" 1694 reader = self.reader("host-rust-program-no-cargo-toml") 1695 with six.assertRaisesRegex( 1696 self, SandboxValidationError, "No Cargo.toml file found" 1697 ): 1698 self.read_topsrcdir(reader) 1699 1700 def test_rust_program_nonexistent_name(self): 1701 """Test that specifying RUST_PROGRAMS that don't exist in Cargo.toml 1702 correctly throws an error.""" 1703 reader = self.reader("rust-program-nonexistent-name") 1704 with six.assertRaisesRegex( 1705 self, SandboxValidationError, "Cannot find Cargo.toml definition for" 1706 ): 1707 self.read_topsrcdir(reader) 1708 1709 def test_host_rust_program_nonexistent_name(self): 1710 """Test that specifying HOST_RUST_PROGRAMS that don't exist in 1711 Cargo.toml correctly throws an error.""" 1712 reader = self.reader("host-rust-program-nonexistent-name") 1713 with six.assertRaisesRegex( 1714 self, SandboxValidationError, "Cannot find Cargo.toml definition for" 1715 ): 1716 self.read_topsrcdir(reader) 1717 1718 def test_rust_programs(self): 1719 """Test RUST_PROGRAMS emission.""" 1720 reader = self.reader( 1721 "rust-programs", 1722 extra_substs=dict(RUST_TARGET="i686-pc-windows-msvc", BIN_SUFFIX=".exe"), 1723 ) 1724 objs = self.read_topsrcdir(reader) 1725 1726 self.assertEqual(len(objs), 3) 1727 ldflags, cflags, prog = objs 1728 self.assertIsInstance(ldflags, ComputedFlags) 1729 self.assertIsInstance(cflags, ComputedFlags) 1730 self.assertIsInstance(prog, RustProgram) 1731 self.assertEqual(prog.name, "some") 1732 1733 def test_host_rust_programs(self): 1734 """Test HOST_RUST_PROGRAMS emission.""" 1735 reader = self.reader( 1736 "host-rust-programs", 1737 extra_substs=dict( 1738 RUST_HOST_TARGET="i686-pc-windows-msvc", HOST_BIN_SUFFIX=".exe" 1739 ), 1740 ) 1741 objs = self.read_topsrcdir(reader) 1742 1743 self.assertEqual(len(objs), 4) 1744 print(objs) 1745 ldflags, cflags, hostflags, prog = objs 1746 self.assertIsInstance(ldflags, ComputedFlags) 1747 self.assertIsInstance(cflags, ComputedFlags) 1748 self.assertIsInstance(hostflags, ComputedFlags) 1749 self.assertIsInstance(prog, HostRustProgram) 1750 self.assertEqual(prog.name, "some") 1751 1752 def test_host_rust_libraries(self): 1753 """Test HOST_RUST_LIBRARIES emission.""" 1754 reader = self.reader( 1755 "host-rust-libraries", 1756 extra_substs=dict( 1757 RUST_HOST_TARGET="i686-pc-windows-msvc", HOST_BIN_SUFFIX=".exe" 1758 ), 1759 ) 1760 objs = self.read_topsrcdir(reader) 1761 1762 self.assertEqual(len(objs), 3) 1763 ldflags, lib, cflags = objs 1764 self.assertIsInstance(ldflags, ComputedFlags) 1765 self.assertIsInstance(cflags, ComputedFlags) 1766 self.assertIsInstance(lib, HostRustLibrary) 1767 self.assertRegexpMatches(lib.lib_name, "host_lib") 1768 self.assertRegexpMatches(lib.import_name, "host_lib") 1769 1770 def test_crate_dependency_path_resolution(self): 1771 """Test recursive dependencies resolve with the correct paths.""" 1772 reader = self.reader( 1773 "crate-dependency-path-resolution", 1774 extra_substs=dict(RUST_TARGET="i686-pc-windows-msvc"), 1775 ) 1776 objs = self.read_topsrcdir(reader) 1777 1778 self.assertEqual(len(objs), 3) 1779 ldflags, lib, cflags = objs 1780 self.assertIsInstance(ldflags, ComputedFlags) 1781 self.assertIsInstance(cflags, ComputedFlags) 1782 self.assertIsInstance(lib, RustLibrary) 1783 1784 def test_install_shared_lib(self): 1785 """Test that we can install a shared library with TEST_HARNESS_FILES""" 1786 reader = self.reader("test-install-shared-lib") 1787 objs = self.read_topsrcdir(reader) 1788 self.assertIsInstance(objs[0], TestHarnessFiles) 1789 self.assertIsInstance(objs[1], VariablePassthru) 1790 self.assertIsInstance(objs[2], ComputedFlags) 1791 self.assertIsInstance(objs[3], SharedLibrary) 1792 self.assertIsInstance(objs[4], ComputedFlags) 1793 for path, files in objs[0].files.walk(): 1794 for f in files: 1795 self.assertEqual(str(f), "!libfoo.so") 1796 self.assertEqual(path, "foo/bar") 1797 1798 def test_symbols_file(self): 1799 """Test that SYMBOLS_FILE works""" 1800 reader = self.reader("test-symbols-file") 1801 genfile, ldflags, shlib, flags = self.read_topsrcdir(reader) 1802 self.assertIsInstance(genfile, GeneratedFile) 1803 self.assertIsInstance(flags, ComputedFlags) 1804 self.assertIsInstance(ldflags, ComputedFlags) 1805 self.assertIsInstance(shlib, SharedLibrary) 1806 # This looks weird but MockConfig sets DLL_{PREFIX,SUFFIX} and 1807 # the reader method in this class sets OS_TARGET=WINNT. 1808 self.assertEqual(shlib.symbols_file, "libfoo.so.def") 1809 1810 def test_symbols_file_objdir(self): 1811 """Test that a SYMBOLS_FILE in the objdir works""" 1812 reader = self.reader("test-symbols-file-objdir") 1813 genfile, ldflags, shlib, flags = self.read_topsrcdir(reader) 1814 self.assertIsInstance(genfile, GeneratedFile) 1815 self.assertEqual( 1816 genfile.script, mozpath.join(reader.config.topsrcdir, "foo.py") 1817 ) 1818 self.assertIsInstance(flags, ComputedFlags) 1819 self.assertIsInstance(ldflags, ComputedFlags) 1820 self.assertIsInstance(shlib, SharedLibrary) 1821 self.assertEqual(shlib.symbols_file, "foo.symbols") 1822 1823 def test_symbols_file_objdir_missing_generated(self): 1824 """Test that a SYMBOLS_FILE in the objdir that's missing 1825 from GENERATED_FILES is an error. 1826 """ 1827 reader = self.reader("test-symbols-file-objdir-missing-generated") 1828 with six.assertRaisesRegex( 1829 self, 1830 SandboxValidationError, 1831 "Objdir file specified in SYMBOLS_FILE not in GENERATED_FILES:", 1832 ): 1833 self.read_topsrcdir(reader) 1834 1835 def test_wasm_compile_flags(self): 1836 reader = self.reader("wasm-compile-flags", extra_substs={"OS_TARGET": "Linux"}) 1837 flags = list(self.read_topsrcdir(reader))[2] 1838 self.assertIsInstance(flags, ComputedFlags) 1839 self.assertEqual( 1840 flags.flags["WASM_CFLAGS"], reader.config.substs["WASM_CFLAGS"] 1841 ) 1842 self.assertEqual( 1843 flags.flags["MOZBUILD_WASM_CFLAGS"], ["-funroll-loops", "-wasm-arg"] 1844 ) 1845 self.assertEqual( 1846 set(flags.flags["WASM_DEFINES"]), 1847 set(["-DFOO", '-DBAZ="abcd"', "-UQUX", "-DBAR=7", "-DVALUE=xyz"]), 1848 ) 1849 1850 1851if __name__ == "__main__": 1852 main() 1853