summaryrefslogtreecommitdiffstats
path: root/python/mozbuild/mozbuild/test/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'python/mozbuild/mozbuild/test/frontend')
-rw-r--r--python/mozbuild/mozbuild/test/frontend/__init__.py0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/allow-compiler-warnings/moz.build20
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/allow-compiler-warnings/test1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/asflags/moz.build15
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/asflags/test1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/asflags/test2.S0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/branding-files/bar.ico0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/branding-files/baz.png0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/branding-files/foo.xpm0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/branding-files/moz.build12
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/branding-files/quux.icns0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/compile-defines/moz.build16
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/compile-defines/test1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/compile-flags-field-validation/moz.build15
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/compile-flags-field-validation/test1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/compile-flags-templates/moz.build27
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/compile-flags-templates/test1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/compile-flags-type-validation/moz.build15
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/compile-flags-type-validation/test1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/compile-flags/moz.build22
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/compile-flags/test1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/compile-includes/moz.build15
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/compile-includes/subdir/header.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/compile-includes/test1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/config-file-substitution/moz.build6
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/crate-dependency-path-resolution/Cargo.toml18
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/crate-dependency-path-resolution/moz.build19
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/crate-dependency-path-resolution/shallow/Cargo.toml6
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/crate-dependency-path-resolution/the/depths/Cargo.toml9
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/defines/moz.build9
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/disable-compiler-warnings/moz.build20
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/disable-compiler-warnings/test1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/disable-stl-wrapping/moz.build21
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/disable-stl-wrapping/test1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/dist-files-missing/install.rdf0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/dist-files-missing/moz.build8
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/dist-files/install.rdf0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/dist-files/main.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/dist-files/moz.build8
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports-generated/foo.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports-generated/moz.build8
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports-generated/mozilla1.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports-missing-generated/foo.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports-missing-generated/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports-missing/foo.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports-missing/moz.build6
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports-missing/mozilla1.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports/bar.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports/baz.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports/dom1.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports/dom2.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports/dom3.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports/foo.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports/gfx.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports/mem.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports/mem2.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports/moz.build13
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports/mozilla1.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports/mozilla2.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports/pprio.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/exports/pprthred.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/bad-assignment/moz.build2
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/different-matchers/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/final/moz.build3
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/final/subcomponent/moz.build2
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/moz.build2
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/simple/moz.build2
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/static/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/files-info/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/final-target-pp-files-non-srcdir/moz.build7
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-files-absolute-script/moz.build9
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-files-absolute-script/script.py0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-files-force/moz.build11
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-files-method-names/moz.build13
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-files-method-names/script.py0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-files-no-inputs/moz.build9
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-files-no-inputs/script.py0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-files-no-python-script/moz.build8
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-files-no-python-script/script.rb0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-files-no-script/moz.build8
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-files/moz.build9
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-sources/a.cpp0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-sources/b.cc0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-sources/c.cxx0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-sources/d.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-sources/e.m0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-sources/f.mm0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-sources/g.S0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-sources/h.s0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-sources/i.asm0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated-sources/moz.build39
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/generated_includes/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-compile-flags/moz.build22
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-compile-flags/test1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-program-paths/final-target/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-program-paths/installed/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-program-paths/moz.build14
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-program-paths/not-installed/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-rust-libraries/Cargo.toml15
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-rust-libraries/moz.build22
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-rust-program-no-cargo-toml/moz.build1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-rust-program-nonexistent-name/Cargo.toml7
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-rust-program-nonexistent-name/moz.build1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-rust-programs/Cargo.toml7
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-rust-programs/moz.build1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-sources/a.cpp0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-sources/b.cc0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-sources/c.cxx0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-sources/d.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-sources/e.mm0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-sources/f.mm0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/host-sources/moz.build27
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/include-basic/included.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/include-basic/moz.build7
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/include-file-stack/included-1.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/include-file-stack/included-2.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/include-file-stack/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/include-missing/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/include-outside-topsrcdir/relative.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/include-relative-from-child/child/child.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/include-relative-from-child/child/child2.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/include-relative-from-child/child/grandchild/grandchild.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/include-relative-from-child/parent.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/include-topsrcdir-relative/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/include-topsrcdir-relative/sibling.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/bar/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/foo/baz/moz.build7
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/foo/moz.build7
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/moz.build10
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/ipdl_sources/bar/moz.build14
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/ipdl_sources/foo/moz.build14
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/ipdl_sources/moz.build10
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/jar-manifests-multiple-files/moz.build7
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/jar-manifests/moz.build7
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/library-defines/liba/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/library-defines/libb/moz.build7
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/library-defines/libc/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/library-defines/libd/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/library-defines/moz.build11
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/link-flags/moz.build16
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/link-flags/test1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/local_includes-filename/foo.h0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/local_includes-filename/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/local_includes-invalid/objdir/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/local_includes-invalid/srcdir/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/local_includes/bar/baz/dummy_file_for_nonempty_directory0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/local_includes/foo/dummy_file_for_nonempty_directory0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/local_includes/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/localized-files-from-generated/moz.build6
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/localized-files-no-en-us/en-US/bar.ini0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/localized-files-no-en-us/foo.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/localized-files-no-en-us/inner/locales/en-US/bar.ini0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/localized-files-no-en-us/moz.build9
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/localized-files-not-localized-generated/moz.build6
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/localized-files/en-US/bar.ini0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/localized-files/en-US/foo.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/localized-files/moz.build9
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/localized-generated-files-final-target-files/moz.build6
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/localized-generated-files-force/moz.build6
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/localized-generated-files/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/localized-pp-files/en-US/bar.ini0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/localized-pp-files/en-US/foo.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/localized-pp-files/moz.build8
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/missing-local-includes/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/missing-xpidl/moz.build6
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/moz.build29
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/rust1/Cargo.toml15
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/rust1/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/rust2/Cargo.toml15
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/rust2/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/object-conflicts/1/Test.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/object-conflicts/1/Test.cpp0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/object-conflicts/1/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/object-conflicts/2/Test.cpp0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/object-conflicts/2/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/object-conflicts/2/subdir/Test.cpp0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/object-conflicts/3/Test.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/object-conflicts/3/Test.cpp0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/object-conflicts/3/moz.build7
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/object-conflicts/4/Test.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/object-conflicts/4/Test.cpp0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/object-conflicts/4/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/program-paths/dist-bin/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/program-paths/dist-subdir/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/program-paths/final-target/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/program-paths/moz.build15
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/program-paths/not-installed/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/program/moz.build18
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/program/test_program1.cpp0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/program/test_program2.cpp0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-error-bad-dir/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-error-basic/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-error-empty-list/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-error-error-func/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-error-included-from/child.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-error-included-from/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-error-missing-include/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-error-outside-topsrcdir/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-error-read-unknown-global/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-error-repeated-dir/moz.build7
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-error-script-error/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-error-syntax/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-error-write-bad-value/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-error-write-unknown-global/moz.build7
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/a/file0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/a/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/b/file0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/b/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/file10
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/file20
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/no-intermediate-moz-build/child/file0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/no-intermediate-moz-build/child/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/parent-is-far/dir1/dir2/dir3/file0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/parent-is-far/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/dir1/file0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/dir1/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/dir2/file0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/dir2/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/file0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/resolved-flags-error/moz.build17
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/resolved-flags-error/test1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-library-dash-folding/Cargo.toml15
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-library-dash-folding/moz.build19
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-library-duplicate-features/Cargo.toml15
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-library-duplicate-features/moz.build20
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-library-features/Cargo.toml15
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-library-features/moz.build20
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-library-invalid-crate-type/Cargo.toml15
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-library-invalid-crate-type/moz.build19
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-library-name-mismatch/Cargo.toml12
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-library-name-mismatch/moz.build19
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-library-no-cargo-toml/moz.build19
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-library-no-lib-section/Cargo.toml12
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-library-no-lib-section/moz.build19
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-program-no-cargo-toml/moz.build1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-program-nonexistent-name/Cargo.toml7
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-program-nonexistent-name/moz.build1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-programs/Cargo.toml7
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/rust-programs/moz.build1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/schedules/moz.build19
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/schedules/subd/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/sources-just-c/d.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/sources-just-c/e.m0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/sources-just-c/g.S0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/sources-just-c/h.s0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/sources-just-c/i.asm0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/sources-just-c/moz.build29
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/sources/a.cpp0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/sources/b.cc0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/sources/c.cxx0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/sources/d.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/sources/e.m0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/sources/f.mm0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/sources/g.S0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/sources/h.s0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/sources/i.asm0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/sources/moz.build39
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/templates/templates.mozbuild21
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-harness-files-root/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-harness-files/mochitest.ini1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-harness-files/mochitest.py1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-harness-files/moz.build7
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-harness-files/runtests.py1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-harness-files/utils.py1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-install-shared-lib/moz.build16
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/moz.build14
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/one/foo.cpp0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/one/moz.build11
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/three/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/two/foo.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/two/moz.build11
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-absolute-support/absolute-support.ini4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-absolute-support/foo.txt1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-absolute-support/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-absolute-support/test_file.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/bar.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/foo.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/mochitest.ini7
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/test_baz.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-emitted-includes/included-reftest.list1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-emitted-includes/moz.build1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-emitted-includes/reftest.list2
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-empty/empty.ini2
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-empty/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-inactive-ignored/test_inactive.html0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-install-includes/common.ini1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-install-includes/mochitest.ini3
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-install-includes/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-install-includes/test_foo.html1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-just-support/foo.txt1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-just-support/just-support.ini2
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-just-support/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/a11y-support/dir1/bar0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/a11y-support/foo0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/a11y.ini4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/browser.ini4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/chrome.ini3
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/crashtest.list1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/metro.ini3
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/mochitest.ini5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/moz.build12
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/python.ini1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/reftest.list1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_a11y.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_browser.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_chrome.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_foo.py0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_metro.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_mochitest.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_xpcshell.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/xpcshell.ini5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-manifest/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-test-file-unfiltered/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-test-file-unfiltered/xpcshell.ini4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-test-file/mochitest.ini1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-test-file/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-parent-support-files-dir/child/mochitest.ini4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-parent-support-files-dir/child/test_foo.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-parent-support-files-dir/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-parent-support-files-dir/support-file.txt0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/another-file.sjs0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/browser.ini6
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/data/one.txt0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/data/two.txt0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/test_sub.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/mochitest.ini9
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/support-file.txt0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/test_foo.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/another-file.sjs0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/browser.ini6
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/data/one.txt0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/data/two.txt0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/test_sub.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/mochitest.ini8
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/support-file.txt0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/test_foo.js0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-unmatched-generated/moz.build4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-unmatched-generated/test.ini4
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-manifest-unmatched-generated/test_foo0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-symbols-file-objdir-missing-generated/moz.build12
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-symbols-file-objdir/foo.py0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-symbols-file-objdir/moz.build15
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-symbols-file/foo.symbols1
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/test-symbols-file/moz.build12
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/traversal-all-vars/moz.build6
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/traversal-all-vars/parallel/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/traversal-all-vars/regular/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/traversal-all-vars/test/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/traversal-outside-topsrcdir/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/traversal-relative-dirs/bar/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/traversal-relative-dirs/foo/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/traversal-relative-dirs/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/traversal-repeated-dirs/bar/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/traversal-repeated-dirs/foo/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/traversal-repeated-dirs/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/traversal-simple/bar/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/traversal-simple/foo/biz/moz.build0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/traversal-simple/foo/moz.build2
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/traversal-simple/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/bar.cxx0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/c1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/c2.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/foo.cpp0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/moz.build30
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/objc1.mm0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/objc2.mm0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/quux.cc0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/unified-sources/bar.cxx0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/unified-sources/c1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/unified-sources/c2.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/unified-sources/foo.cpp0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/unified-sources/moz.build30
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/unified-sources/objc1.mm0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/unified-sources/objc2.mm0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/unified-sources/quux.cc0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/use-nasm/moz.build15
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/use-nasm/test1.S0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/variable-passthru/bans.S0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/variable-passthru/baz.def0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build13
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test1.cpp0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test1.mm0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test2.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test2.cpp0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test2.mm0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/visibility-flags/moz.build21
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/visibility-flags/test1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/wasm-compile-flags/moz.build14
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/wasm-compile-flags/test1.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/wasm-sources/a.cpp0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/wasm-sources/b.cc0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/wasm-sources/c.cxx0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/wasm-sources/d.c0
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/wasm-sources/moz.build15
-rw-r--r--python/mozbuild/mozbuild/test/frontend/data/xpidl-module-no-sources/moz.build5
-rw-r--r--python/mozbuild/mozbuild/test/frontend/test_context.py736
-rw-r--r--python/mozbuild/mozbuild/test/frontend/test_emitter.py1877
-rw-r--r--python/mozbuild/mozbuild/test/frontend/test_namespaces.py225
-rw-r--r--python/mozbuild/mozbuild/test/frontend/test_reader.py531
-rw-r--r--python/mozbuild/mozbuild/test/frontend/test_sandbox.py536
408 files changed, 5793 insertions, 0 deletions
diff --git a/python/mozbuild/mozbuild/test/frontend/__init__.py b/python/mozbuild/mozbuild/test/frontend/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/__init__.py
diff --git a/python/mozbuild/mozbuild/test/frontend/data/allow-compiler-warnings/moz.build b/python/mozbuild/mozbuild/test/frontend/data/allow-compiler-warnings/moz.build
new file mode 100644
index 0000000000..0bf5b55ecb
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/allow-compiler-warnings/moz.build
@@ -0,0 +1,20 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def AllowCompilerWarnings():
+ COMPILE_FLAGS["WARNINGS_AS_ERRORS"] = []
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+UNIFIED_SOURCES += ["test1.c"]
+
+AllowCompilerWarnings()
diff --git a/python/mozbuild/mozbuild/test/frontend/data/allow-compiler-warnings/test1.c b/python/mozbuild/mozbuild/test/frontend/data/allow-compiler-warnings/test1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/allow-compiler-warnings/test1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/asflags/moz.build b/python/mozbuild/mozbuild/test/frontend/data/asflags/moz.build
new file mode 100644
index 0000000000..80f48a7d81
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/asflags/moz.build
@@ -0,0 +1,15 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+SOURCES += ["test1.c", "test2.S"]
+
+ASFLAGS += ["-no-integrated-as"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/asflags/test1.c b/python/mozbuild/mozbuild/test/frontend/data/asflags/test1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/asflags/test1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/asflags/test2.S b/python/mozbuild/mozbuild/test/frontend/data/asflags/test2.S
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/asflags/test2.S
diff --git a/python/mozbuild/mozbuild/test/frontend/data/branding-files/bar.ico b/python/mozbuild/mozbuild/test/frontend/data/branding-files/bar.ico
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/branding-files/bar.ico
diff --git a/python/mozbuild/mozbuild/test/frontend/data/branding-files/baz.png b/python/mozbuild/mozbuild/test/frontend/data/branding-files/baz.png
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/branding-files/baz.png
diff --git a/python/mozbuild/mozbuild/test/frontend/data/branding-files/foo.xpm b/python/mozbuild/mozbuild/test/frontend/data/branding-files/foo.xpm
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/branding-files/foo.xpm
diff --git a/python/mozbuild/mozbuild/test/frontend/data/branding-files/moz.build b/python/mozbuild/mozbuild/test/frontend/data/branding-files/moz.build
new file mode 100644
index 0000000000..65f22d578b
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/branding-files/moz.build
@@ -0,0 +1,12 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+BRANDING_FILES += [
+ "bar.ico",
+ "baz.png",
+ "foo.xpm",
+]
+
+BRANDING_FILES.icons += [
+ "quux.icns",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/branding-files/quux.icns b/python/mozbuild/mozbuild/test/frontend/data/branding-files/quux.icns
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/branding-files/quux.icns
diff --git a/python/mozbuild/mozbuild/test/frontend/data/compile-defines/moz.build b/python/mozbuild/mozbuild/test/frontend/data/compile-defines/moz.build
new file mode 100644
index 0000000000..65d71dae2b
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/compile-defines/moz.build
@@ -0,0 +1,16 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+UNIFIED_SOURCES += ["test1.c"]
+
+DEFINES["MOZ_TEST_DEFINE"] = True
+LIBRARY_DEFINES["MOZ_LIBRARY_DEFINE"] = "MOZ_TEST"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/compile-defines/test1.c b/python/mozbuild/mozbuild/test/frontend/data/compile-defines/test1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/compile-defines/test1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/compile-flags-field-validation/moz.build b/python/mozbuild/mozbuild/test/frontend/data/compile-flags-field-validation/moz.build
new file mode 100644
index 0000000000..70622bc4e1
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/compile-flags-field-validation/moz.build
@@ -0,0 +1,15 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+COMPILE_FLAGS["STL_FLAGS"] = []
+
+UNIFIED_SOURCES += ["test1.c"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/compile-flags-field-validation/test1.c b/python/mozbuild/mozbuild/test/frontend/data/compile-flags-field-validation/test1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/compile-flags-field-validation/test1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/compile-flags-templates/moz.build b/python/mozbuild/mozbuild/test/frontend/data/compile-flags-templates/moz.build
new file mode 100644
index 0000000000..6e611fc598
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/compile-flags-templates/moz.build
@@ -0,0 +1,27 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+
+@template
+def DisableStlWrapping():
+ COMPILE_FLAGS["STL"] = []
+
+
+@template
+def NoVisibilityFlags():
+ COMPILE_FLAGS["VISIBILITY"] = []
+
+
+UNIFIED_SOURCES += ["test1.c"]
+
+DisableStlWrapping()
+NoVisibilityFlags()
diff --git a/python/mozbuild/mozbuild/test/frontend/data/compile-flags-templates/test1.c b/python/mozbuild/mozbuild/test/frontend/data/compile-flags-templates/test1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/compile-flags-templates/test1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/compile-flags-type-validation/moz.build b/python/mozbuild/mozbuild/test/frontend/data/compile-flags-type-validation/moz.build
new file mode 100644
index 0000000000..31094736a7
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/compile-flags-type-validation/moz.build
@@ -0,0 +1,15 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+COMPILE_FLAGS["STL"] = [None, 123]
+
+UNIFIED_SOURCES += ["test1.c"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/compile-flags-type-validation/test1.c b/python/mozbuild/mozbuild/test/frontend/data/compile-flags-type-validation/test1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/compile-flags-type-validation/test1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/compile-flags/moz.build b/python/mozbuild/mozbuild/test/frontend/data/compile-flags/moz.build
new file mode 100644
index 0000000000..0e6f75cfa1
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/compile-flags/moz.build
@@ -0,0 +1,22 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+
+@template
+def DisableStlWrapping():
+ COMPILE_FLAGS["STL"] = []
+
+
+UNIFIED_SOURCES += ["test1.c"]
+
+CXXFLAGS += ["-funroll-loops", "-Wall"]
+CFLAGS += ["-Wall", "-funroll-loops"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/compile-flags/test1.c b/python/mozbuild/mozbuild/test/frontend/data/compile-flags/test1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/compile-flags/test1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/compile-includes/moz.build b/python/mozbuild/mozbuild/test/frontend/data/compile-includes/moz.build
new file mode 100644
index 0000000000..10c28e2833
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/compile-includes/moz.build
@@ -0,0 +1,15 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+UNIFIED_SOURCES += ["test1.c"]
+
+LOCAL_INCLUDES += ["subdir"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/compile-includes/subdir/header.h b/python/mozbuild/mozbuild/test/frontend/data/compile-includes/subdir/header.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/compile-includes/subdir/header.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/compile-includes/test1.c b/python/mozbuild/mozbuild/test/frontend/data/compile-includes/test1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/compile-includes/test1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/config-file-substitution/moz.build b/python/mozbuild/mozbuild/test/frontend/data/config-file-substitution/moz.build
new file mode 100644
index 0000000000..f42dc0a517
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/config-file-substitution/moz.build
@@ -0,0 +1,6 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+CONFIGURE_SUBST_FILES += ["foo"]
+CONFIGURE_SUBST_FILES += ["bar"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/crate-dependency-path-resolution/Cargo.toml b/python/mozbuild/mozbuild/test/frontend/data/crate-dependency-path-resolution/Cargo.toml
new file mode 100644
index 0000000000..b080d53b5a
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/crate-dependency-path-resolution/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "random-crate"
+version = "0.1.0"
+authors = [
+ "The Mozilla Project Developers",
+]
+
+[lib]
+crate-type = ["staticlib"]
+
+[dependencies]
+deep-crate = { version = "0.1.0", path = "the/depths" }
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/crate-dependency-path-resolution/moz.build b/python/mozbuild/mozbuild/test/frontend/data/crate-dependency-path-resolution/moz.build
new file mode 100644
index 0000000000..de1967c519
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/crate-dependency-path-resolution/moz.build
@@ -0,0 +1,19 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+@template
+def RustLibrary(name):
+ """Template for Rust libraries."""
+ Library(name)
+
+ IS_RUST_LIBRARY = True
+
+
+RustLibrary("random-crate")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/crate-dependency-path-resolution/shallow/Cargo.toml b/python/mozbuild/mozbuild/test/frontend/data/crate-dependency-path-resolution/shallow/Cargo.toml
new file mode 100644
index 0000000000..e918f9228d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/crate-dependency-path-resolution/shallow/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "shallow-crate"
+version = "0.1.0"
+authors = [
+ "The Mozilla Project Developers",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/crate-dependency-path-resolution/the/depths/Cargo.toml b/python/mozbuild/mozbuild/test/frontend/data/crate-dependency-path-resolution/the/depths/Cargo.toml
new file mode 100644
index 0000000000..cebcb38ab7
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/crate-dependency-path-resolution/the/depths/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "deep-crate"
+version = "0.1.0"
+authors = [
+ "The Mozilla Project Developers",
+]
+
+[dependencies]
+shallow-crate = { path = "../../shallow" }
diff --git a/python/mozbuild/mozbuild/test/frontend/data/defines/moz.build b/python/mozbuild/mozbuild/test/frontend/data/defines/moz.build
new file mode 100644
index 0000000000..6085619c58
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/defines/moz.build
@@ -0,0 +1,9 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+value = "xyz"
+DEFINES["FOO"] = True
+DEFINES["BAZ"] = '"abcd"'
+DEFINES["BAR"] = 7
+DEFINES["VALUE"] = value
+DEFINES["QUX"] = False
diff --git a/python/mozbuild/mozbuild/test/frontend/data/disable-compiler-warnings/moz.build b/python/mozbuild/mozbuild/test/frontend/data/disable-compiler-warnings/moz.build
new file mode 100644
index 0000000000..064fa09893
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/disable-compiler-warnings/moz.build
@@ -0,0 +1,20 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def DisableCompilerWarnings():
+ COMPILE_FLAGS["WARNINGS_CFLAGS"] = []
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+UNIFIED_SOURCES += ["test1.c"]
+
+DisableCompilerWarnings()
diff --git a/python/mozbuild/mozbuild/test/frontend/data/disable-compiler-warnings/test1.c b/python/mozbuild/mozbuild/test/frontend/data/disable-compiler-warnings/test1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/disable-compiler-warnings/test1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/disable-stl-wrapping/moz.build b/python/mozbuild/mozbuild/test/frontend/data/disable-stl-wrapping/moz.build
new file mode 100644
index 0000000000..40cb3e7781
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/disable-stl-wrapping/moz.build
@@ -0,0 +1,21 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+
+@template
+def DisableStlWrapping():
+ COMPILE_FLAGS["STL"] = []
+
+
+UNIFIED_SOURCES += ["test1.c"]
+
+DisableStlWrapping()
diff --git a/python/mozbuild/mozbuild/test/frontend/data/disable-stl-wrapping/test1.c b/python/mozbuild/mozbuild/test/frontend/data/disable-stl-wrapping/test1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/disable-stl-wrapping/test1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/dist-files-missing/install.rdf b/python/mozbuild/mozbuild/test/frontend/data/dist-files-missing/install.rdf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/dist-files-missing/install.rdf
diff --git a/python/mozbuild/mozbuild/test/frontend/data/dist-files-missing/moz.build b/python/mozbuild/mozbuild/test/frontend/data/dist-files-missing/moz.build
new file mode 100644
index 0000000000..25961f149f
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/dist-files-missing/moz.build
@@ -0,0 +1,8 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+FINAL_TARGET_PP_FILES += [
+ "install.rdf",
+ "main.js",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/dist-files/install.rdf b/python/mozbuild/mozbuild/test/frontend/data/dist-files/install.rdf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/dist-files/install.rdf
diff --git a/python/mozbuild/mozbuild/test/frontend/data/dist-files/main.js b/python/mozbuild/mozbuild/test/frontend/data/dist-files/main.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/dist-files/main.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/dist-files/moz.build b/python/mozbuild/mozbuild/test/frontend/data/dist-files/moz.build
new file mode 100644
index 0000000000..25961f149f
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/dist-files/moz.build
@@ -0,0 +1,8 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+FINAL_TARGET_PP_FILES += [
+ "install.rdf",
+ "main.js",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports-generated/foo.h b/python/mozbuild/mozbuild/test/frontend/data/exports-generated/foo.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports-generated/foo.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports-generated/moz.build b/python/mozbuild/mozbuild/test/frontend/data/exports-generated/moz.build
new file mode 100644
index 0000000000..bd3507c97b
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports-generated/moz.build
@@ -0,0 +1,8 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+EXPORTS += ["foo.h"]
+EXPORTS.mozilla += ["mozilla1.h"]
+EXPORTS.mozilla += ["!mozilla2.h"]
+
+GENERATED_FILES += ["mozilla2.h"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports-generated/mozilla1.h b/python/mozbuild/mozbuild/test/frontend/data/exports-generated/mozilla1.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports-generated/mozilla1.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports-missing-generated/foo.h b/python/mozbuild/mozbuild/test/frontend/data/exports-missing-generated/foo.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports-missing-generated/foo.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports-missing-generated/moz.build b/python/mozbuild/mozbuild/test/frontend/data/exports-missing-generated/moz.build
new file mode 100644
index 0000000000..d81109d37d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports-missing-generated/moz.build
@@ -0,0 +1,5 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+EXPORTS += ["foo.h"]
+EXPORTS += ["!bar.h"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports-missing/foo.h b/python/mozbuild/mozbuild/test/frontend/data/exports-missing/foo.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports-missing/foo.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports-missing/moz.build b/python/mozbuild/mozbuild/test/frontend/data/exports-missing/moz.build
new file mode 100644
index 0000000000..3f94fbdccd
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports-missing/moz.build
@@ -0,0 +1,6 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+EXPORTS += ["foo.h"]
+EXPORTS.mozilla += ["mozilla1.h"]
+EXPORTS.mozilla += ["mozilla2.h"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports-missing/mozilla1.h b/python/mozbuild/mozbuild/test/frontend/data/exports-missing/mozilla1.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports-missing/mozilla1.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports/bar.h b/python/mozbuild/mozbuild/test/frontend/data/exports/bar.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports/bar.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports/baz.h b/python/mozbuild/mozbuild/test/frontend/data/exports/baz.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports/baz.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports/dom1.h b/python/mozbuild/mozbuild/test/frontend/data/exports/dom1.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports/dom1.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports/dom2.h b/python/mozbuild/mozbuild/test/frontend/data/exports/dom2.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports/dom2.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports/dom3.h b/python/mozbuild/mozbuild/test/frontend/data/exports/dom3.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports/dom3.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports/foo.h b/python/mozbuild/mozbuild/test/frontend/data/exports/foo.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports/foo.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports/gfx.h b/python/mozbuild/mozbuild/test/frontend/data/exports/gfx.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports/gfx.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports/mem.h b/python/mozbuild/mozbuild/test/frontend/data/exports/mem.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports/mem.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports/mem2.h b/python/mozbuild/mozbuild/test/frontend/data/exports/mem2.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports/mem2.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports/moz.build b/python/mozbuild/mozbuild/test/frontend/data/exports/moz.build
new file mode 100644
index 0000000000..64253b1cf0
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports/moz.build
@@ -0,0 +1,13 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+EXPORTS += ["foo.h"]
+EXPORTS += ["bar.h", "baz.h"]
+EXPORTS.mozilla += ["mozilla1.h"]
+EXPORTS.mozilla += ["mozilla2.h"]
+EXPORTS.mozilla.dom += ["dom1.h"]
+EXPORTS.mozilla.dom += ["dom2.h", "dom3.h"]
+EXPORTS.mozilla.gfx += ["gfx.h"]
+EXPORTS.vpx = ["mem.h"]
+EXPORTS.vpx += ["mem2.h"]
+EXPORTS.nspr.private = ["pprio.h", "pprthred.h"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports/mozilla1.h b/python/mozbuild/mozbuild/test/frontend/data/exports/mozilla1.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports/mozilla1.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports/mozilla2.h b/python/mozbuild/mozbuild/test/frontend/data/exports/mozilla2.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports/mozilla2.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports/pprio.h b/python/mozbuild/mozbuild/test/frontend/data/exports/pprio.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports/pprio.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/exports/pprthred.h b/python/mozbuild/mozbuild/test/frontend/data/exports/pprthred.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/exports/pprthred.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/bad-assignment/moz.build b/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/bad-assignment/moz.build
new file mode 100644
index 0000000000..693b6cc962
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/bad-assignment/moz.build
@@ -0,0 +1,2 @@
+with Files("*"):
+ BUG_COMPONENT = "bad value"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/different-matchers/moz.build b/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/different-matchers/moz.build
new file mode 100644
index 0000000000..ca5c74fd6a
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/different-matchers/moz.build
@@ -0,0 +1,4 @@
+with Files("*.jsm"):
+ BUG_COMPONENT = ("Firefox", "JS")
+with Files("*.cpp"):
+ BUG_COMPONENT = ("Firefox", "C++")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/final/moz.build b/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/final/moz.build
new file mode 100644
index 0000000000..9b1d05a9b0
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/final/moz.build
@@ -0,0 +1,3 @@
+with Files("**/Makefile.in"):
+ BUG_COMPONENT = ("Firefox Build System", "General")
+ FINAL = True
diff --git a/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/final/subcomponent/moz.build b/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/final/subcomponent/moz.build
new file mode 100644
index 0000000000..9b21529812
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/final/subcomponent/moz.build
@@ -0,0 +1,2 @@
+with Files("**"):
+ BUG_COMPONENT = ("Another", "Component")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/moz.build b/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/moz.build
new file mode 100644
index 0000000000..4bbca3dc09
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/moz.build
@@ -0,0 +1,2 @@
+with Files("**"):
+ BUG_COMPONENT = ("default_product", "default_component")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/simple/moz.build b/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/simple/moz.build
new file mode 100644
index 0000000000..e8b99df68d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/simple/moz.build
@@ -0,0 +1,2 @@
+with Files("*"):
+ BUG_COMPONENT = ("Firefox Build System", "General")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/static/moz.build b/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/static/moz.build
new file mode 100644
index 0000000000..49acf29196
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/files-info/bug_component/static/moz.build
@@ -0,0 +1,5 @@
+with Files("foo"):
+ BUG_COMPONENT = ("FooProduct", "FooComponent")
+
+with Files("bar"):
+ BUG_COMPONENT = ("BarProduct", "BarComponent")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/files-info/moz.build b/python/mozbuild/mozbuild/test/frontend/data/files-info/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/files-info/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/final-target-pp-files-non-srcdir/moz.build b/python/mozbuild/mozbuild/test/frontend/data/final-target-pp-files-non-srcdir/moz.build
new file mode 100644
index 0000000000..67e5fb5dce
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/final-target-pp-files-non-srcdir/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+FINAL_TARGET_PP_FILES += [
+ "!foo.js",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-files-absolute-script/moz.build b/python/mozbuild/mozbuild/test/frontend/data/generated-files-absolute-script/moz.build
new file mode 100644
index 0000000000..860f025eac
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-files-absolute-script/moz.build
@@ -0,0 +1,9 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+GENERATED_FILES += ["bar.c"]
+
+bar = GENERATED_FILES["bar.c"]
+bar.script = "/script.py:make_bar"
+bar.inputs = []
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-files-absolute-script/script.py b/python/mozbuild/mozbuild/test/frontend/data/generated-files-absolute-script/script.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-files-absolute-script/script.py
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-files-force/moz.build b/python/mozbuild/mozbuild/test/frontend/data/generated-files-force/moz.build
new file mode 100644
index 0000000000..33f54a17e8
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-files-force/moz.build
@@ -0,0 +1,11 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+GENERATED_FILES += [
+ "bar.c",
+ "foo.c",
+ ("xpidllex.py", "xpidlyacc.py"),
+]
+GENERATED_FILES["bar.c"].force = True
+GENERATED_FILES["foo.c"].force = False
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-files-method-names/moz.build b/python/mozbuild/mozbuild/test/frontend/data/generated-files-method-names/moz.build
new file mode 100644
index 0000000000..298513383b
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-files-method-names/moz.build
@@ -0,0 +1,13 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+GENERATED_FILES += ["bar.c", "foo.c"]
+
+bar = GENERATED_FILES["bar.c"]
+bar.script = "script.py:make_bar"
+bar.inputs = []
+
+foo = GENERATED_FILES["foo.c"]
+foo.script = "script.py"
+foo.inputs = []
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-files-method-names/script.py b/python/mozbuild/mozbuild/test/frontend/data/generated-files-method-names/script.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-files-method-names/script.py
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-files-no-inputs/moz.build b/python/mozbuild/mozbuild/test/frontend/data/generated-files-no-inputs/moz.build
new file mode 100644
index 0000000000..50f703c696
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-files-no-inputs/moz.build
@@ -0,0 +1,9 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+GENERATED_FILES += ["bar.c", "foo.c"]
+
+foo = GENERATED_FILES["foo.c"]
+foo.script = "script.py"
+foo.inputs = ["datafile"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-files-no-inputs/script.py b/python/mozbuild/mozbuild/test/frontend/data/generated-files-no-inputs/script.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-files-no-inputs/script.py
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-files-no-python-script/moz.build b/python/mozbuild/mozbuild/test/frontend/data/generated-files-no-python-script/moz.build
new file mode 100644
index 0000000000..ebdb7bfaf5
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-files-no-python-script/moz.build
@@ -0,0 +1,8 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+GENERATED_FILES += ["bar.c", "foo.c"]
+
+bar = GENERATED_FILES["bar.c"]
+bar.script = "script.rb"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-files-no-python-script/script.rb b/python/mozbuild/mozbuild/test/frontend/data/generated-files-no-python-script/script.rb
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-files-no-python-script/script.rb
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-files-no-script/moz.build b/python/mozbuild/mozbuild/test/frontend/data/generated-files-no-script/moz.build
new file mode 100644
index 0000000000..258a0f2325
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-files-no-script/moz.build
@@ -0,0 +1,8 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+GENERATED_FILES += ["bar.c", "foo.c"]
+
+bar = GENERATED_FILES["bar.c"]
+bar.script = "nonexistent-script.py"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-files/moz.build b/python/mozbuild/mozbuild/test/frontend/data/generated-files/moz.build
new file mode 100644
index 0000000000..97267c5d26
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-files/moz.build
@@ -0,0 +1,9 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+GENERATED_FILES += [
+ "bar.c",
+ "foo.c",
+ ("xpidllex.py", "xpidlyacc.py"),
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-sources/a.cpp b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/a.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/a.cpp
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-sources/b.cc b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/b.cc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/b.cc
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-sources/c.cxx b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/c.cxx
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/c.cxx
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-sources/d.c b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/d.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/d.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-sources/e.m b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/e.m
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/e.m
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-sources/f.mm b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/f.mm
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/f.mm
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-sources/g.S b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/g.S
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/g.S
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-sources/h.s b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/h.s
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/h.s
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-sources/i.asm b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/i.asm
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/i.asm
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated-sources/moz.build b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/moz.build
new file mode 100644
index 0000000000..e305d9d32f
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated-sources/moz.build
@@ -0,0 +1,39 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+SOURCES += [
+ "!a.cpp",
+ "!b.cc",
+ "!c.cxx",
+]
+
+SOURCES += [
+ "!d.c",
+]
+
+SOURCES += [
+ "!e.m",
+]
+
+SOURCES += [
+ "!f.mm",
+]
+
+SOURCES += [
+ "!g.S",
+]
+
+SOURCES += [
+ "!h.s",
+ "!i.asm",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated_includes/moz.build b/python/mozbuild/mozbuild/test/frontend/data/generated_includes/moz.build
new file mode 100644
index 0000000000..31f9042c0a
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/generated_includes/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+LOCAL_INCLUDES += ["!/bar/baz", "!foo"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-compile-flags/moz.build b/python/mozbuild/mozbuild/test/frontend/data/host-compile-flags/moz.build
new file mode 100644
index 0000000000..4225234c65
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-compile-flags/moz.build
@@ -0,0 +1,22 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def HostLibrary(name):
+ """Template for libraries."""
+ HOST_LIBRARY_NAME = name
+
+
+HostLibrary("dummy")
+
+HOST_SOURCES += ["test1.c"]
+
+value = "xyz"
+HOST_DEFINES["FOO"] = True
+HOST_DEFINES["BAZ"] = '"abcd"'
+HOST_DEFINES["BAR"] = 7
+HOST_DEFINES["VALUE"] = value
+HOST_DEFINES["QUX"] = False
+
+HOST_CFLAGS += ["-funroll-loops", "-host-arg"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-compile-flags/test1.c b/python/mozbuild/mozbuild/test/frontend/data/host-compile-flags/test1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-compile-flags/test1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-program-paths/final-target/moz.build b/python/mozbuild/mozbuild/test/frontend/data/host-program-paths/final-target/moz.build
new file mode 100644
index 0000000000..a2136749dc
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-program-paths/final-target/moz.build
@@ -0,0 +1,5 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+FINAL_TARGET = "final/target"
+HostProgram("final-target")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-program-paths/installed/moz.build b/python/mozbuild/mozbuild/test/frontend/data/host-program-paths/installed/moz.build
new file mode 100644
index 0000000000..0d10d35508
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-program-paths/installed/moz.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+HostProgram("dist-host-bin")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-program-paths/moz.build b/python/mozbuild/mozbuild/test/frontend/data/host-program-paths/moz.build
new file mode 100644
index 0000000000..ef9175fa54
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-program-paths/moz.build
@@ -0,0 +1,14 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def HostProgram(name):
+ HOST_PROGRAM = name
+
+
+DIRS += [
+ "final-target",
+ "installed",
+ "not-installed",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-program-paths/not-installed/moz.build b/python/mozbuild/mozbuild/test/frontend/data/host-program-paths/not-installed/moz.build
new file mode 100644
index 0000000000..4a8451bc8f
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-program-paths/not-installed/moz.build
@@ -0,0 +1,5 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIST_INSTALL = False
+HostProgram("not-installed")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-rust-libraries/Cargo.toml b/python/mozbuild/mozbuild/test/frontend/data/host-rust-libraries/Cargo.toml
new file mode 100644
index 0000000000..aefcab3ddb
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-rust-libraries/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "host-lib"
+version = "0.1.0"
+authors = [
+ "The Mozilla Project Developers",
+]
+
+[lib]
+crate-type = ["staticlib"]
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-rust-libraries/moz.build b/python/mozbuild/mozbuild/test/frontend/data/host-rust-libraries/moz.build
new file mode 100644
index 0000000000..37b6728ae3
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-rust-libraries/moz.build
@@ -0,0 +1,22 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def HostLibrary(name):
+ """Template for libraries."""
+ HOST_LIBRARY_NAME = name
+
+
+@template
+def HostRustLibrary(name, features=None):
+ """Template for Rust libraries."""
+ HostLibrary(name)
+
+ IS_RUST_LIBRARY = True
+
+ if features:
+ RUST_LIBRARY_FEATURES = features
+
+
+HostRustLibrary("host-lib")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-rust-program-no-cargo-toml/moz.build b/python/mozbuild/mozbuild/test/frontend/data/host-rust-program-no-cargo-toml/moz.build
new file mode 100644
index 0000000000..c60e731d99
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-rust-program-no-cargo-toml/moz.build
@@ -0,0 +1 @@
+HOST_RUST_PROGRAMS += ["none"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-rust-program-nonexistent-name/Cargo.toml b/python/mozbuild/mozbuild/test/frontend/data/host-rust-program-nonexistent-name/Cargo.toml
new file mode 100644
index 0000000000..dee335937f
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-rust-program-nonexistent-name/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+authors = ["The Mozilla Project Developers"]
+name = "testing"
+version = "0.0.1"
+
+[[bin]]
+name = "some"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-rust-program-nonexistent-name/moz.build b/python/mozbuild/mozbuild/test/frontend/data/host-rust-program-nonexistent-name/moz.build
new file mode 100644
index 0000000000..c60e731d99
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-rust-program-nonexistent-name/moz.build
@@ -0,0 +1 @@
+HOST_RUST_PROGRAMS += ["none"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-rust-programs/Cargo.toml b/python/mozbuild/mozbuild/test/frontend/data/host-rust-programs/Cargo.toml
new file mode 100644
index 0000000000..dee335937f
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-rust-programs/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+authors = ["The Mozilla Project Developers"]
+name = "testing"
+version = "0.0.1"
+
+[[bin]]
+name = "some"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-rust-programs/moz.build b/python/mozbuild/mozbuild/test/frontend/data/host-rust-programs/moz.build
new file mode 100644
index 0000000000..2d75958b07
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-rust-programs/moz.build
@@ -0,0 +1 @@
+HOST_RUST_PROGRAMS += ["some"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-sources/a.cpp b/python/mozbuild/mozbuild/test/frontend/data/host-sources/a.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-sources/a.cpp
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-sources/b.cc b/python/mozbuild/mozbuild/test/frontend/data/host-sources/b.cc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-sources/b.cc
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-sources/c.cxx b/python/mozbuild/mozbuild/test/frontend/data/host-sources/c.cxx
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-sources/c.cxx
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-sources/d.c b/python/mozbuild/mozbuild/test/frontend/data/host-sources/d.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-sources/d.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-sources/e.mm b/python/mozbuild/mozbuild/test/frontend/data/host-sources/e.mm
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-sources/e.mm
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-sources/f.mm b/python/mozbuild/mozbuild/test/frontend/data/host-sources/f.mm
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-sources/f.mm
diff --git a/python/mozbuild/mozbuild/test/frontend/data/host-sources/moz.build b/python/mozbuild/mozbuild/test/frontend/data/host-sources/moz.build
new file mode 100644
index 0000000000..b1f5b98039
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-sources/moz.build
@@ -0,0 +1,27 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def HostLibrary(name):
+ """Template for libraries."""
+ HOST_LIBRARY_NAME = name
+
+
+HostLibrary("dummy")
+
+HOST_SOURCES += [
+ "a.cpp",
+ "b.cc",
+ "c.cxx",
+]
+
+HOST_SOURCES += [
+ "d.c",
+]
+
+HOST_SOURCES += [
+ "e.mm",
+ "f.mm",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/include-basic/included.build b/python/mozbuild/mozbuild/test/frontend/data/include-basic/included.build
new file mode 100644
index 0000000000..3532347e27
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/include-basic/included.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS += ["bar"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/include-basic/moz.build b/python/mozbuild/mozbuild/test/frontend/data/include-basic/moz.build
new file mode 100644
index 0000000000..b8e37c69ea
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/include-basic/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS = ["foo"]
+
+include("included.build")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/include-file-stack/included-1.build b/python/mozbuild/mozbuild/test/frontend/data/include-file-stack/included-1.build
new file mode 100644
index 0000000000..b5dc2728c6
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/include-file-stack/included-1.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+include("included-2.build")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/include-file-stack/included-2.build b/python/mozbuild/mozbuild/test/frontend/data/include-file-stack/included-2.build
new file mode 100644
index 0000000000..9bfc65481d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/include-file-stack/included-2.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+ILLEGAL = True
diff --git a/python/mozbuild/mozbuild/test/frontend/data/include-file-stack/moz.build b/python/mozbuild/mozbuild/test/frontend/data/include-file-stack/moz.build
new file mode 100644
index 0000000000..def43513c7
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/include-file-stack/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+include("included-1.build")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/include-missing/moz.build b/python/mozbuild/mozbuild/test/frontend/data/include-missing/moz.build
new file mode 100644
index 0000000000..34129f7c93
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/include-missing/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+include("missing.build")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/include-outside-topsrcdir/relative.build b/python/mozbuild/mozbuild/test/frontend/data/include-outside-topsrcdir/relative.build
new file mode 100644
index 0000000000..714a044436
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/include-outside-topsrcdir/relative.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+include("../moz.build")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/include-relative-from-child/child/child.build b/python/mozbuild/mozbuild/test/frontend/data/include-relative-from-child/child/child.build
new file mode 100644
index 0000000000..ecae03ca7d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/include-relative-from-child/child/child.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+include("../parent.build")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/include-relative-from-child/child/child2.build b/python/mozbuild/mozbuild/test/frontend/data/include-relative-from-child/child/child2.build
new file mode 100644
index 0000000000..36210ba96b
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/include-relative-from-child/child/child2.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+include("grandchild/grandchild.build")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/include-relative-from-child/child/grandchild/grandchild.build b/python/mozbuild/mozbuild/test/frontend/data/include-relative-from-child/child/grandchild/grandchild.build
new file mode 100644
index 0000000000..76dcdb899f
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/include-relative-from-child/child/grandchild/grandchild.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+include("../../parent.build")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/include-relative-from-child/parent.build b/python/mozbuild/mozbuild/test/frontend/data/include-relative-from-child/parent.build
new file mode 100644
index 0000000000..eb1477d0df
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/include-relative-from-child/parent.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS = ["foo"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/include-topsrcdir-relative/moz.build b/python/mozbuild/mozbuild/test/frontend/data/include-topsrcdir-relative/moz.build
new file mode 100644
index 0000000000..879b832ed8
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/include-topsrcdir-relative/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+include("/sibling.build")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/include-topsrcdir-relative/sibling.build b/python/mozbuild/mozbuild/test/frontend/data/include-topsrcdir-relative/sibling.build
new file mode 100644
index 0000000000..eb1477d0df
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/include-topsrcdir-relative/sibling.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS = ["foo"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/bar/moz.build b/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/bar/moz.build
new file mode 100644
index 0000000000..568f361a54
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/bar/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/foo/baz/moz.build b/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/foo/baz/moz.build
new file mode 100644
index 0000000000..9c392681c7
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/foo/baz/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+XPIDL_MODULE = "baz"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/foo/moz.build b/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/foo/moz.build
new file mode 100644
index 0000000000..f3368867ad
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/foo/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DIRS += ["baz"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/moz.build b/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/moz.build
new file mode 100644
index 0000000000..169e9d1554
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/moz.build
@@ -0,0 +1,10 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+XPIDL_MODULE = "foobar"
+export("XPIDL_MODULE")
+
+DIRS += ["foo", "bar"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/ipdl_sources/bar/moz.build b/python/mozbuild/mozbuild/test/frontend/data/ipdl_sources/bar/moz.build
new file mode 100644
index 0000000000..b49ec1216b
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/ipdl_sources/bar/moz.build
@@ -0,0 +1,14 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+PREPROCESSED_IPDL_SOURCES += [
+ "bar1.ipdl",
+]
+
+IPDL_SOURCES += [
+ "bar.ipdl",
+ "bar2.ipdlh",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/ipdl_sources/foo/moz.build b/python/mozbuild/mozbuild/test/frontend/data/ipdl_sources/foo/moz.build
new file mode 100644
index 0000000000..c2e891572b
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/ipdl_sources/foo/moz.build
@@ -0,0 +1,14 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+PREPROCESSED_IPDL_SOURCES += [
+ "foo1.ipdl",
+]
+
+IPDL_SOURCES += [
+ "foo.ipdl",
+ "foo2.ipdlh",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/ipdl_sources/moz.build b/python/mozbuild/mozbuild/test/frontend/data/ipdl_sources/moz.build
new file mode 100644
index 0000000000..9fe7699519
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/ipdl_sources/moz.build
@@ -0,0 +1,10 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DIRS += [
+ "bar",
+ "foo",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/jar-manifests-multiple-files/moz.build b/python/mozbuild/mozbuild/test/frontend/data/jar-manifests-multiple-files/moz.build
new file mode 100644
index 0000000000..fa61c94006
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/jar-manifests-multiple-files/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+JAR_MANIFESTS += ["jar.mn", "other.jar"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/jar-manifests/moz.build b/python/mozbuild/mozbuild/test/frontend/data/jar-manifests/moz.build
new file mode 100644
index 0000000000..d988c0ff9b
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/jar-manifests/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+JAR_MANIFESTS += ["jar.mn"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/library-defines/liba/moz.build b/python/mozbuild/mozbuild/test/frontend/data/library-defines/liba/moz.build
new file mode 100644
index 0000000000..65fcc6d08e
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/library-defines/liba/moz.build
@@ -0,0 +1,5 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+Library("liba")
+LIBRARY_DEFINES["IN_LIBA"] = True
diff --git a/python/mozbuild/mozbuild/test/frontend/data/library-defines/libb/moz.build b/python/mozbuild/mozbuild/test/frontend/data/library-defines/libb/moz.build
new file mode 100644
index 0000000000..f4cf7b31a0
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/library-defines/libb/moz.build
@@ -0,0 +1,7 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+Library("libb")
+FINAL_LIBRARY = "liba"
+LIBRARY_DEFINES["IN_LIBB"] = True
+USE_LIBS += ["libd"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/library-defines/libc/moz.build b/python/mozbuild/mozbuild/test/frontend/data/library-defines/libc/moz.build
new file mode 100644
index 0000000000..022a67559d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/library-defines/libc/moz.build
@@ -0,0 +1,5 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+Library("libc")
+FINAL_LIBRARY = "libb"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/library-defines/libd/moz.build b/python/mozbuild/mozbuild/test/frontend/data/library-defines/libd/moz.build
new file mode 100644
index 0000000000..0bd94be069
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/library-defines/libd/moz.build
@@ -0,0 +1,5 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+Library("libd")
+FORCE_STATIC_LIB = True
diff --git a/python/mozbuild/mozbuild/test/frontend/data/library-defines/moz.build b/python/mozbuild/mozbuild/test/frontend/data/library-defines/moz.build
new file mode 100644
index 0000000000..dcc955cf28
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/library-defines/moz.build
@@ -0,0 +1,11 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+DIRS = ["liba", "libb", "libc", "libd"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/link-flags/moz.build b/python/mozbuild/mozbuild/test/frontend/data/link-flags/moz.build
new file mode 100644
index 0000000000..9e25efdcbf
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/link-flags/moz.build
@@ -0,0 +1,16 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+UNIFIED_SOURCES += ["test1.c"]
+
+LDFLAGS += ["-Wl,-U_foo"]
+LDFLAGS += ["-framework Foo", "-x"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/link-flags/test1.c b/python/mozbuild/mozbuild/test/frontend/data/link-flags/test1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/link-flags/test1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/local_includes-filename/foo.h b/python/mozbuild/mozbuild/test/frontend/data/local_includes-filename/foo.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/local_includes-filename/foo.h
diff --git a/python/mozbuild/mozbuild/test/frontend/data/local_includes-filename/moz.build b/python/mozbuild/mozbuild/test/frontend/data/local_includes-filename/moz.build
new file mode 100644
index 0000000000..70259db75b
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/local_includes-filename/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+LOCAL_INCLUDES += ["foo.h"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/local_includes-invalid/objdir/moz.build b/python/mozbuild/mozbuild/test/frontend/data/local_includes-invalid/objdir/moz.build
new file mode 100644
index 0000000000..6dcbab537d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/local_includes-invalid/objdir/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+LOCAL_INCLUDES += ["!/"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/local_includes-invalid/srcdir/moz.build b/python/mozbuild/mozbuild/test/frontend/data/local_includes-invalid/srcdir/moz.build
new file mode 100644
index 0000000000..6d8f6cd2af
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/local_includes-invalid/srcdir/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+LOCAL_INCLUDES += ["/"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/local_includes/bar/baz/dummy_file_for_nonempty_directory b/python/mozbuild/mozbuild/test/frontend/data/local_includes/bar/baz/dummy_file_for_nonempty_directory
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/local_includes/bar/baz/dummy_file_for_nonempty_directory
diff --git a/python/mozbuild/mozbuild/test/frontend/data/local_includes/foo/dummy_file_for_nonempty_directory b/python/mozbuild/mozbuild/test/frontend/data/local_includes/foo/dummy_file_for_nonempty_directory
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/local_includes/foo/dummy_file_for_nonempty_directory
diff --git a/python/mozbuild/mozbuild/test/frontend/data/local_includes/moz.build b/python/mozbuild/mozbuild/test/frontend/data/local_includes/moz.build
new file mode 100644
index 0000000000..1c29ac2ea2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/local_includes/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+LOCAL_INCLUDES += ["/bar/baz", "foo"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/localized-files-from-generated/moz.build b/python/mozbuild/mozbuild/test/frontend/data/localized-files-from-generated/moz.build
new file mode 100644
index 0000000000..491a026419
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-files-from-generated/moz.build
@@ -0,0 +1,6 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+LOCALIZED_GENERATED_FILES += ["abc.ini"]
+LOCALIZED_FILES += ["!abc.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/localized-files-no-en-us/en-US/bar.ini b/python/mozbuild/mozbuild/test/frontend/data/localized-files-no-en-us/en-US/bar.ini
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-files-no-en-us/en-US/bar.ini
diff --git a/python/mozbuild/mozbuild/test/frontend/data/localized-files-no-en-us/foo.js b/python/mozbuild/mozbuild/test/frontend/data/localized-files-no-en-us/foo.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-files-no-en-us/foo.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/localized-files-no-en-us/inner/locales/en-US/bar.ini b/python/mozbuild/mozbuild/test/frontend/data/localized-files-no-en-us/inner/locales/en-US/bar.ini
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-files-no-en-us/inner/locales/en-US/bar.ini
diff --git a/python/mozbuild/mozbuild/test/frontend/data/localized-files-no-en-us/moz.build b/python/mozbuild/mozbuild/test/frontend/data/localized-files-no-en-us/moz.build
new file mode 100644
index 0000000000..5c3efc8117
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-files-no-en-us/moz.build
@@ -0,0 +1,9 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+LOCALIZED_FILES.foo += [
+ "en-US/bar.ini",
+ "foo.js",
+ "inner/locales/en-US/bar.ini",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/localized-files-not-localized-generated/moz.build b/python/mozbuild/mozbuild/test/frontend/data/localized-files-not-localized-generated/moz.build
new file mode 100644
index 0000000000..678f503174
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-files-not-localized-generated/moz.build
@@ -0,0 +1,6 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+GENERATED_FILES += ["abc.ini"]
+LOCALIZED_FILES += ["!abc.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/localized-files/en-US/bar.ini b/python/mozbuild/mozbuild/test/frontend/data/localized-files/en-US/bar.ini
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-files/en-US/bar.ini
diff --git a/python/mozbuild/mozbuild/test/frontend/data/localized-files/en-US/foo.js b/python/mozbuild/mozbuild/test/frontend/data/localized-files/en-US/foo.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-files/en-US/foo.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/localized-files/moz.build b/python/mozbuild/mozbuild/test/frontend/data/localized-files/moz.build
new file mode 100644
index 0000000000..25a9030881
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-files/moz.build
@@ -0,0 +1,9 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+LOCALIZED_FILES.foo += [
+ "en-US/bar.ini",
+ "en-US/code/*.js",
+ "en-US/foo.js",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/localized-generated-files-final-target-files/moz.build b/python/mozbuild/mozbuild/test/frontend/data/localized-generated-files-final-target-files/moz.build
new file mode 100644
index 0000000000..48acff1447
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-generated-files-final-target-files/moz.build
@@ -0,0 +1,6 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+LOCALIZED_GENERATED_FILES += ["abc.ini"]
+FINAL_TARGET_FILES += ["!abc.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/localized-generated-files-force/moz.build b/python/mozbuild/mozbuild/test/frontend/data/localized-generated-files-force/moz.build
new file mode 100644
index 0000000000..73685545de
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-generated-files-force/moz.build
@@ -0,0 +1,6 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+LOCALIZED_GENERATED_FILES += ["abc.ini", ("bar", "baz")]
+LOCALIZED_GENERATED_FILES["abc.ini"].force = True
diff --git a/python/mozbuild/mozbuild/test/frontend/data/localized-generated-files/moz.build b/python/mozbuild/mozbuild/test/frontend/data/localized-generated-files/moz.build
new file mode 100644
index 0000000000..cc306d5991
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-generated-files/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+LOCALIZED_GENERATED_FILES += ["abc.ini", ("bar", "baz")]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/localized-pp-files/en-US/bar.ini b/python/mozbuild/mozbuild/test/frontend/data/localized-pp-files/en-US/bar.ini
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-pp-files/en-US/bar.ini
diff --git a/python/mozbuild/mozbuild/test/frontend/data/localized-pp-files/en-US/foo.js b/python/mozbuild/mozbuild/test/frontend/data/localized-pp-files/en-US/foo.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-pp-files/en-US/foo.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/localized-pp-files/moz.build b/python/mozbuild/mozbuild/test/frontend/data/localized-pp-files/moz.build
new file mode 100644
index 0000000000..b2916a1226
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/localized-pp-files/moz.build
@@ -0,0 +1,8 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+LOCALIZED_PP_FILES.foo += [
+ "en-US/bar.ini",
+ "en-US/foo.js",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/missing-local-includes/moz.build b/python/mozbuild/mozbuild/test/frontend/data/missing-local-includes/moz.build
new file mode 100644
index 0000000000..1c29ac2ea2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/missing-local-includes/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+LOCAL_INCLUDES += ["/bar/baz", "foo"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/missing-xpidl/moz.build b/python/mozbuild/mozbuild/test/frontend/data/missing-xpidl/moz.build
new file mode 100644
index 0000000000..e3a2a69d07
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/missing-xpidl/moz.build
@@ -0,0 +1,6 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+XPIDL_MODULE = "my_module"
+XPIDL_SOURCES = ["nonexistant.idl"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/moz.build b/python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/moz.build
new file mode 100644
index 0000000000..7956580d14
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/moz.build
@@ -0,0 +1,29 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+@template
+def RustLibrary(name):
+ """Template for Rust libraries."""
+ Library(name)
+
+ IS_RUST_LIBRARY = True
+
+
+Library("test")
+
+DIRS += [
+ "rust1",
+ "rust2",
+]
+
+USE_LIBS += [
+ "rust1",
+ "rust2",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/rust1/Cargo.toml b/python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/rust1/Cargo.toml
new file mode 100644
index 0000000000..56273d5cf7
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/rust1/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "rust1"
+version = "0.1.0"
+authors = [
+ "The Mozilla Project Developers",
+]
+
+[lib]
+crate-type = ["staticlib"]
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/rust1/moz.build b/python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/rust1/moz.build
new file mode 100644
index 0000000000..0cc01e1e24
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/rust1/moz.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+RustLibrary("rust1")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/rust2/Cargo.toml b/python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/rust2/Cargo.toml
new file mode 100644
index 0000000000..9c557f6c08
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/rust2/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "rust2"
+version = "0.1.0"
+authors = [
+ "The Mozilla Project Developers",
+]
+
+[lib]
+crate-type = ["staticlib"]
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/rust2/moz.build b/python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/rust2/moz.build
new file mode 100644
index 0000000000..4ec4ea9c79
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/multiple-rust-libraries/rust2/moz.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+RustLibrary("rust2")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/1/Test.c b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/1/Test.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/1/Test.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/1/Test.cpp b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/1/Test.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/1/Test.cpp
diff --git a/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/1/moz.build b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/1/moz.build
new file mode 100644
index 0000000000..44610a781c
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/1/moz.build
@@ -0,0 +1,4 @@
+SOURCES += [
+ "Test.c",
+ "Test.cpp",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/2/Test.cpp b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/2/Test.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/2/Test.cpp
diff --git a/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/2/moz.build b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/2/moz.build
new file mode 100644
index 0000000000..b1064ae0c0
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/2/moz.build
@@ -0,0 +1,4 @@
+SOURCES += [
+ "subdir/Test.cpp",
+ "Test.cpp",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/2/subdir/Test.cpp b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/2/subdir/Test.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/2/subdir/Test.cpp
diff --git a/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/3/Test.c b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/3/Test.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/3/Test.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/3/Test.cpp b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/3/Test.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/3/Test.cpp
diff --git a/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/3/moz.build b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/3/moz.build
new file mode 100644
index 0000000000..a225907cae
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/3/moz.build
@@ -0,0 +1,7 @@
+SOURCES += [
+ "Test.c",
+]
+
+UNIFIED_SOURCES += [
+ "Test.cpp",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/4/Test.c b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/4/Test.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/4/Test.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/4/Test.cpp b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/4/Test.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/4/Test.cpp
diff --git a/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/4/moz.build b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/4/moz.build
new file mode 100644
index 0000000000..ea5da28d88
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/object-conflicts/4/moz.build
@@ -0,0 +1,4 @@
+UNIFIED_SOURCES += [
+ "Test.c",
+ "Test.cpp",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/program-paths/dist-bin/moz.build b/python/mozbuild/mozbuild/test/frontend/data/program-paths/dist-bin/moz.build
new file mode 100644
index 0000000000..d8b952c014
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/program-paths/dist-bin/moz.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+Program("dist-bin")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/program-paths/dist-subdir/moz.build b/python/mozbuild/mozbuild/test/frontend/data/program-paths/dist-subdir/moz.build
new file mode 100644
index 0000000000..fc2f664c01
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/program-paths/dist-subdir/moz.build
@@ -0,0 +1,5 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIST_SUBDIR = "foo"
+Program("dist-subdir")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/program-paths/final-target/moz.build b/python/mozbuild/mozbuild/test/frontend/data/program-paths/final-target/moz.build
new file mode 100644
index 0000000000..a0d5805262
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/program-paths/final-target/moz.build
@@ -0,0 +1,5 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+FINAL_TARGET = "final/target"
+Program("final-target")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/program-paths/moz.build b/python/mozbuild/mozbuild/test/frontend/data/program-paths/moz.build
new file mode 100644
index 0000000000..d1d087fd45
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/program-paths/moz.build
@@ -0,0 +1,15 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Program(name):
+ PROGRAM = name
+
+
+DIRS += [
+ "dist-bin",
+ "dist-subdir",
+ "final-target",
+ "not-installed",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/program-paths/not-installed/moz.build b/python/mozbuild/mozbuild/test/frontend/data/program-paths/not-installed/moz.build
new file mode 100644
index 0000000000..c725ab7326
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/program-paths/not-installed/moz.build
@@ -0,0 +1,5 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIST_INSTALL = False
+Program("not-installed")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/program/moz.build b/python/mozbuild/mozbuild/test/frontend/data/program/moz.build
new file mode 100644
index 0000000000..b3f7062732
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/program/moz.build
@@ -0,0 +1,18 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Program(name):
+ PROGRAM = name
+
+
+@template
+def SimplePrograms(names, ext=".cpp"):
+ SIMPLE_PROGRAMS += names
+ SOURCES += ["%s%s" % (name, ext) for name in names]
+
+
+Program("test_program")
+
+SimplePrograms(["test_program1", "test_program2"])
diff --git a/python/mozbuild/mozbuild/test/frontend/data/program/test_program1.cpp b/python/mozbuild/mozbuild/test/frontend/data/program/test_program1.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/program/test_program1.cpp
diff --git a/python/mozbuild/mozbuild/test/frontend/data/program/test_program2.cpp b/python/mozbuild/mozbuild/test/frontend/data/program/test_program2.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/program/test_program2.cpp
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-error-bad-dir/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-error-bad-dir/moz.build
new file mode 100644
index 0000000000..68581574b1
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-error-bad-dir/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS = ["foo"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-error-basic/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-error-basic/moz.build
new file mode 100644
index 0000000000..0a91c4692b
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-error-basic/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+ILLEGAL = True
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-error-empty-list/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-error-empty-list/moz.build
new file mode 100644
index 0000000000..4dfba1c60f
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-error-empty-list/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS = []
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-error-error-func/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-error-error-func/moz.build
new file mode 100644
index 0000000000..d0f35c4c1d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-error-error-func/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+error("Some error.")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-error-included-from/child.build b/python/mozbuild/mozbuild/test/frontend/data/reader-error-included-from/child.build
new file mode 100644
index 0000000000..9bfc65481d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-error-included-from/child.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+ILLEGAL = True
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-error-included-from/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-error-included-from/moz.build
new file mode 100644
index 0000000000..603f3a7204
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-error-included-from/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+include("child.build")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-error-missing-include/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-error-missing-include/moz.build
new file mode 100644
index 0000000000..34129f7c93
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-error-missing-include/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+include("missing.build")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-error-outside-topsrcdir/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-error-outside-topsrcdir/moz.build
new file mode 100644
index 0000000000..040c1f5df1
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-error-outside-topsrcdir/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+include("../include-basic/moz.build")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-error-read-unknown-global/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-error-read-unknown-global/moz.build
new file mode 100644
index 0000000000..6fc10f766a
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-error-read-unknown-global/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+l = FOO
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-error-repeated-dir/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-error-repeated-dir/moz.build
new file mode 100644
index 0000000000..91845b337f
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-error-repeated-dir/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS = ["foo"]
+
+DIRS += ["foo"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-error-script-error/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-error-script-error/moz.build
new file mode 100644
index 0000000000..a91d38b415
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-error-script-error/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+foo = True + None
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-error-syntax/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-error-syntax/moz.build
new file mode 100644
index 0000000000..70a0d2c066
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-error-syntax/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+foo =
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-error-write-bad-value/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-error-write-bad-value/moz.build
new file mode 100644
index 0000000000..2e8194b223
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-error-write-bad-value/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS = "dir"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-error-write-unknown-global/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-error-write-unknown-global/moz.build
new file mode 100644
index 0000000000..5675031753
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-error-write-unknown-global/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS = ["dir1", "dir2"]
+
+FOO = "bar"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/a/file b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/a/file
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/a/file
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/a/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/a/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/a/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/b/file b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/b/file
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/b/file
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/b/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/b/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/b/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/every-level/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/file1 b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/file1
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/file1
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/file2 b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/file2
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/file2
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/no-intermediate-moz-build/child/file b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/no-intermediate-moz-build/child/file
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/no-intermediate-moz-build/child/file
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/no-intermediate-moz-build/child/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/no-intermediate-moz-build/child/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/no-intermediate-moz-build/child/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/parent-is-far/dir1/dir2/dir3/file b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/parent-is-far/dir1/dir2/dir3/file
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/parent-is-far/dir1/dir2/dir3/file
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/parent-is-far/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/parent-is-far/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d1/parent-is-far/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/dir1/file b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/dir1/file
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/dir1/file
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/dir1/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/dir1/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/dir1/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/dir2/file b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/dir2/file
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/dir2/file
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/dir2/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/dir2/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/dir2/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/d2/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/file b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/file
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/file
diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/reader-relevant-mozbuild/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/resolved-flags-error/moz.build b/python/mozbuild/mozbuild/test/frontend/data/resolved-flags-error/moz.build
new file mode 100644
index 0000000000..d4b9a3075d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/resolved-flags-error/moz.build
@@ -0,0 +1,17 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+UNIFIED_SOURCES += ["test1.c"]
+
+DEFINES["MOZ_TEST_DEFINE"] = True
+LIBRARY_DEFINES["MOZ_LIBRARY_DEFINE"] = "MOZ_TEST"
+COMPILE_FLAGS["DEFINES"] = ["-DFOO"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/resolved-flags-error/test1.c b/python/mozbuild/mozbuild/test/frontend/data/resolved-flags-error/test1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/resolved-flags-error/test1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-library-dash-folding/Cargo.toml b/python/mozbuild/mozbuild/test/frontend/data/rust-library-dash-folding/Cargo.toml
new file mode 100644
index 0000000000..fbb4ae087d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-library-dash-folding/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "random-crate"
+version = "0.1.0"
+authors = [
+ "The Mozilla Project Developers",
+]
+
+[lib]
+crate-type = ["staticlib"]
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-library-dash-folding/moz.build b/python/mozbuild/mozbuild/test/frontend/data/rust-library-dash-folding/moz.build
new file mode 100644
index 0000000000..de1967c519
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-library-dash-folding/moz.build
@@ -0,0 +1,19 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+@template
+def RustLibrary(name):
+ """Template for Rust libraries."""
+ Library(name)
+
+ IS_RUST_LIBRARY = True
+
+
+RustLibrary("random-crate")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-library-duplicate-features/Cargo.toml b/python/mozbuild/mozbuild/test/frontend/data/rust-library-duplicate-features/Cargo.toml
new file mode 100644
index 0000000000..fbb4ae087d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-library-duplicate-features/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "random-crate"
+version = "0.1.0"
+authors = [
+ "The Mozilla Project Developers",
+]
+
+[lib]
+crate-type = ["staticlib"]
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-library-duplicate-features/moz.build b/python/mozbuild/mozbuild/test/frontend/data/rust-library-duplicate-features/moz.build
new file mode 100644
index 0000000000..ccd8ede3c0
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-library-duplicate-features/moz.build
@@ -0,0 +1,20 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+@template
+def RustLibrary(name, features):
+ """Template for Rust libraries."""
+ Library(name)
+
+ IS_RUST_LIBRARY = True
+ RUST_LIBRARY_FEATURES = features
+
+
+RustLibrary("random-crate", ["musthave", "cantlivewithout", "musthave"])
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-library-features/Cargo.toml b/python/mozbuild/mozbuild/test/frontend/data/rust-library-features/Cargo.toml
new file mode 100644
index 0000000000..fbb4ae087d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-library-features/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "random-crate"
+version = "0.1.0"
+authors = [
+ "The Mozilla Project Developers",
+]
+
+[lib]
+crate-type = ["staticlib"]
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-library-features/moz.build b/python/mozbuild/mozbuild/test/frontend/data/rust-library-features/moz.build
new file mode 100644
index 0000000000..9d88bdea08
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-library-features/moz.build
@@ -0,0 +1,20 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+@template
+def RustLibrary(name, features):
+ """Template for Rust libraries."""
+ Library(name)
+
+ IS_RUST_LIBRARY = True
+ RUST_LIBRARY_FEATURES = features
+
+
+RustLibrary("random-crate", ["musthave", "cantlivewithout"])
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-library-invalid-crate-type/Cargo.toml b/python/mozbuild/mozbuild/test/frontend/data/rust-library-invalid-crate-type/Cargo.toml
new file mode 100644
index 0000000000..3572550b76
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-library-invalid-crate-type/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "random-crate"
+version = "0.1.0"
+authors = [
+ "The Mozilla Project Developers",
+]
+
+[lib]
+crate-type = ["dylib"]
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-library-invalid-crate-type/moz.build b/python/mozbuild/mozbuild/test/frontend/data/rust-library-invalid-crate-type/moz.build
new file mode 100644
index 0000000000..de1967c519
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-library-invalid-crate-type/moz.build
@@ -0,0 +1,19 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+@template
+def RustLibrary(name):
+ """Template for Rust libraries."""
+ Library(name)
+
+ IS_RUST_LIBRARY = True
+
+
+RustLibrary("random-crate")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-library-name-mismatch/Cargo.toml b/python/mozbuild/mozbuild/test/frontend/data/rust-library-name-mismatch/Cargo.toml
new file mode 100644
index 0000000000..9e05fe5cb1
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-library-name-mismatch/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "deterministic-crate"
+version = "0.1.0"
+authors = [
+ "The Mozilla Project Developers",
+]
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-library-name-mismatch/moz.build b/python/mozbuild/mozbuild/test/frontend/data/rust-library-name-mismatch/moz.build
new file mode 100644
index 0000000000..de1967c519
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-library-name-mismatch/moz.build
@@ -0,0 +1,19 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+@template
+def RustLibrary(name):
+ """Template for Rust libraries."""
+ Library(name)
+
+ IS_RUST_LIBRARY = True
+
+
+RustLibrary("random-crate")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-library-no-cargo-toml/moz.build b/python/mozbuild/mozbuild/test/frontend/data/rust-library-no-cargo-toml/moz.build
new file mode 100644
index 0000000000..de1967c519
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-library-no-cargo-toml/moz.build
@@ -0,0 +1,19 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+@template
+def RustLibrary(name):
+ """Template for Rust libraries."""
+ Library(name)
+
+ IS_RUST_LIBRARY = True
+
+
+RustLibrary("random-crate")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-library-no-lib-section/Cargo.toml b/python/mozbuild/mozbuild/test/frontend/data/rust-library-no-lib-section/Cargo.toml
new file mode 100644
index 0000000000..0934afcc4f
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-library-no-lib-section/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "random-crate"
+version = "0.1.0"
+authors = [
+ "The Mozilla Project Developers",
+]
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-library-no-lib-section/moz.build b/python/mozbuild/mozbuild/test/frontend/data/rust-library-no-lib-section/moz.build
new file mode 100644
index 0000000000..de1967c519
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-library-no-lib-section/moz.build
@@ -0,0 +1,19 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+@template
+def RustLibrary(name):
+ """Template for Rust libraries."""
+ Library(name)
+
+ IS_RUST_LIBRARY = True
+
+
+RustLibrary("random-crate")
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-program-no-cargo-toml/moz.build b/python/mozbuild/mozbuild/test/frontend/data/rust-program-no-cargo-toml/moz.build
new file mode 100644
index 0000000000..56601854f9
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-program-no-cargo-toml/moz.build
@@ -0,0 +1 @@
+RUST_PROGRAMS += ["none"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-program-nonexistent-name/Cargo.toml b/python/mozbuild/mozbuild/test/frontend/data/rust-program-nonexistent-name/Cargo.toml
new file mode 100644
index 0000000000..dee335937f
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-program-nonexistent-name/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+authors = ["The Mozilla Project Developers"]
+name = "testing"
+version = "0.0.1"
+
+[[bin]]
+name = "some"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-program-nonexistent-name/moz.build b/python/mozbuild/mozbuild/test/frontend/data/rust-program-nonexistent-name/moz.build
new file mode 100644
index 0000000000..56601854f9
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-program-nonexistent-name/moz.build
@@ -0,0 +1 @@
+RUST_PROGRAMS += ["none"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-programs/Cargo.toml b/python/mozbuild/mozbuild/test/frontend/data/rust-programs/Cargo.toml
new file mode 100644
index 0000000000..dee335937f
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-programs/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+authors = ["The Mozilla Project Developers"]
+name = "testing"
+version = "0.0.1"
+
+[[bin]]
+name = "some"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/rust-programs/moz.build b/python/mozbuild/mozbuild/test/frontend/data/rust-programs/moz.build
new file mode 100644
index 0000000000..80dc15120a
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-programs/moz.build
@@ -0,0 +1 @@
+RUST_PROGRAMS += ["some"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/schedules/moz.build b/python/mozbuild/mozbuild/test/frontend/data/schedules/moz.build
new file mode 100644
index 0000000000..3f4f450d37
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/schedules/moz.build
@@ -0,0 +1,19 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+with Files("*.win"):
+ SCHEDULES.exclusive = ["windows"]
+
+with Files("*.osx"):
+ SCHEDULES.exclusive = ["macosx"]
+
+with Files("win.and.osx"):
+ # this conflicts with the previous clause and will cause an error
+ # when read
+ SCHEDULES.exclusive = ["macosx", "windows"]
+
+with Files("subd/**.py"):
+ SCHEDULES.inclusive += ["py-lint"]
+
+with Files("**/*.js"):
+ SCHEDULES.inclusive += ["js-lint"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/schedules/subd/moz.build b/python/mozbuild/mozbuild/test/frontend/data/schedules/subd/moz.build
new file mode 100644
index 0000000000..b9c3bf6c74
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/schedules/subd/moz.build
@@ -0,0 +1,5 @@
+with Files("yaml.py"):
+ SCHEDULES.inclusive += ["yaml-lint"]
+
+with Files("win.js"):
+ SCHEDULES.exclusive = ["windows"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/d.c b/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/d.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/d.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/e.m b/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/e.m
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/e.m
diff --git a/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/g.S b/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/g.S
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/g.S
diff --git a/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/h.s b/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/h.s
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/h.s
diff --git a/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/i.asm b/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/i.asm
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/i.asm
diff --git a/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/moz.build b/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/moz.build
new file mode 100644
index 0000000000..29abd6de5d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/sources-just-c/moz.build
@@ -0,0 +1,29 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+SOURCES += [
+ "d.c",
+]
+
+SOURCES += [
+ "e.m",
+]
+
+SOURCES += [
+ "g.S",
+]
+
+SOURCES += [
+ "h.s",
+ "i.asm",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/sources/a.cpp b/python/mozbuild/mozbuild/test/frontend/data/sources/a.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/sources/a.cpp
diff --git a/python/mozbuild/mozbuild/test/frontend/data/sources/b.cc b/python/mozbuild/mozbuild/test/frontend/data/sources/b.cc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/sources/b.cc
diff --git a/python/mozbuild/mozbuild/test/frontend/data/sources/c.cxx b/python/mozbuild/mozbuild/test/frontend/data/sources/c.cxx
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/sources/c.cxx
diff --git a/python/mozbuild/mozbuild/test/frontend/data/sources/d.c b/python/mozbuild/mozbuild/test/frontend/data/sources/d.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/sources/d.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/sources/e.m b/python/mozbuild/mozbuild/test/frontend/data/sources/e.m
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/sources/e.m
diff --git a/python/mozbuild/mozbuild/test/frontend/data/sources/f.mm b/python/mozbuild/mozbuild/test/frontend/data/sources/f.mm
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/sources/f.mm
diff --git a/python/mozbuild/mozbuild/test/frontend/data/sources/g.S b/python/mozbuild/mozbuild/test/frontend/data/sources/g.S
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/sources/g.S
diff --git a/python/mozbuild/mozbuild/test/frontend/data/sources/h.s b/python/mozbuild/mozbuild/test/frontend/data/sources/h.s
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/sources/h.s
diff --git a/python/mozbuild/mozbuild/test/frontend/data/sources/i.asm b/python/mozbuild/mozbuild/test/frontend/data/sources/i.asm
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/sources/i.asm
diff --git a/python/mozbuild/mozbuild/test/frontend/data/sources/moz.build b/python/mozbuild/mozbuild/test/frontend/data/sources/moz.build
new file mode 100644
index 0000000000..e25f865f72
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/sources/moz.build
@@ -0,0 +1,39 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+SOURCES += [
+ "a.cpp",
+ "b.cc",
+ "c.cxx",
+]
+
+SOURCES += [
+ "d.c",
+]
+
+SOURCES += [
+ "e.m",
+]
+
+SOURCES += [
+ "f.mm",
+]
+
+SOURCES += [
+ "g.S",
+]
+
+SOURCES += [
+ "h.s",
+ "i.asm",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/templates/templates.mozbuild b/python/mozbuild/mozbuild/test/frontend/data/templates/templates.mozbuild
new file mode 100644
index 0000000000..290104bc72
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/templates/templates.mozbuild
@@ -0,0 +1,21 @@
+@template
+def Template(foo, bar=[]):
+ SOURCES += foo
+ DIRS += bar
+
+@template
+def TemplateError(foo):
+ ILLEGAL = foo
+
+@template
+def TemplateGlobalVariable():
+ SOURCES += illegal
+
+@template
+def TemplateGlobalUPPERVariable():
+ SOURCES += DIRS
+
+@template
+def TemplateInherit(foo):
+ USE_LIBS += ['foo']
+ Template(foo)
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-harness-files-root/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-harness-files-root/moz.build
new file mode 100644
index 0000000000..d7f6377d0d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-harness-files-root/moz.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+TEST_HARNESS_FILES += ["foo.py"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-harness-files/mochitest.ini b/python/mozbuild/mozbuild/test/frontend/data/test-harness-files/mochitest.ini
new file mode 100644
index 0000000000..d87114ac7d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-harness-files/mochitest.ini
@@ -0,0 +1 @@
+# dummy file so the existence checks for TEST_HARNESS_FILES succeed
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-harness-files/mochitest.py b/python/mozbuild/mozbuild/test/frontend/data/test-harness-files/mochitest.py
new file mode 100644
index 0000000000..d87114ac7d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-harness-files/mochitest.py
@@ -0,0 +1 @@
+# dummy file so the existence checks for TEST_HARNESS_FILES succeed
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-harness-files/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-harness-files/moz.build
new file mode 100644
index 0000000000..ff3fed0ee0
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-harness-files/moz.build
@@ -0,0 +1,7 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+TEST_HARNESS_FILES.mochitest += ["runtests.py"]
+TEST_HARNESS_FILES.mochitest += ["utils.py"]
+TEST_HARNESS_FILES.testing.mochitest += ["mochitest.py"]
+TEST_HARNESS_FILES.testing.mochitest += ["mochitest.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-harness-files/runtests.py b/python/mozbuild/mozbuild/test/frontend/data/test-harness-files/runtests.py
new file mode 100644
index 0000000000..d87114ac7d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-harness-files/runtests.py
@@ -0,0 +1 @@
+# dummy file so the existence checks for TEST_HARNESS_FILES succeed
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-harness-files/utils.py b/python/mozbuild/mozbuild/test/frontend/data/test-harness-files/utils.py
new file mode 100644
index 0000000000..d87114ac7d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-harness-files/utils.py
@@ -0,0 +1 @@
+# dummy file so the existence checks for TEST_HARNESS_FILES succeed
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-install-shared-lib/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-install-shared-lib/moz.build
new file mode 100644
index 0000000000..fa592c72a3
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-install-shared-lib/moz.build
@@ -0,0 +1,16 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def SharedLibrary(name):
+ LIBRARY_NAME = name
+ FORCE_SHARED_LIB = True
+
+
+DIST_INSTALL = False
+SharedLibrary("foo")
+
+TEST_HARNESS_FILES.foo.bar += [
+ "!%sfoo%s" % (CONFIG["DLL_PREFIX"], CONFIG["DLL_SUFFIX"])
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/moz.build
new file mode 100644
index 0000000000..0f84eb5554
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/moz.build
@@ -0,0 +1,14 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS = ["one", "two", "three"]
+
+
+@template
+def SharedLibrary(name):
+ LIBRARY_NAME = name
+ FORCE_SHARED_LIB = True
+
+
+SharedLibrary("cxx_shared")
+USE_LIBS += ["cxx_static"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/one/foo.cpp b/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/one/foo.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/one/foo.cpp
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/one/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/one/moz.build
new file mode 100644
index 0000000000..f03a34c33f
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/one/moz.build
@@ -0,0 +1,11 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ LIBRARY_NAME = name
+
+
+Library("cxx_static")
+SOURCES += ["foo.cpp"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/three/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/three/moz.build
new file mode 100644
index 0000000000..08e26c4eb3
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/three/moz.build
@@ -0,0 +1,5 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+SharedLibrary("just_c_shared")
+USE_LIBS += ["just_c_static"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/two/foo.c b/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/two/foo.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/two/foo.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/two/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/two/moz.build
new file mode 100644
index 0000000000..d3bb738ba4
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-linkables-cxx-link/two/moz.build
@@ -0,0 +1,11 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ LIBRARY_NAME = name
+
+
+Library("just_c_static")
+SOURCES += ["foo.c"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-absolute-support/absolute-support.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-absolute-support/absolute-support.ini
new file mode 100644
index 0000000000..900f421584
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-absolute-support/absolute-support.ini
@@ -0,0 +1,4 @@
+[DEFAULT]
+support-files = /.well-known/foo.txt
+
+[test_file.js]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-absolute-support/foo.txt b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-absolute-support/foo.txt
new file mode 100644
index 0000000000..ce01362503
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-absolute-support/foo.txt
@@ -0,0 +1 @@
+hello
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-absolute-support/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-absolute-support/moz.build
new file mode 100644
index 0000000000..5ccb97c1bb
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-absolute-support/moz.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+MOCHITEST_MANIFESTS += ["absolute-support.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-absolute-support/test_file.js b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-absolute-support/test_file.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-absolute-support/test_file.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/bar.js b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/bar.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/bar.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/foo.js b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/foo.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/foo.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/mochitest.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/mochitest.ini
new file mode 100644
index 0000000000..2f1fc406a0
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/mochitest.ini
@@ -0,0 +1,7 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+[DEFAULT]
+support-files = bar.js foo.js bar.js
+
+[test_baz.js]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/moz.build
new file mode 100644
index 0000000000..4cc0c3d4cf
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/moz.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+MOCHITEST_MANIFESTS += ["mochitest.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/test_baz.js b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/test_baz.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-dupes/test_baz.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-emitted-includes/included-reftest.list b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-emitted-includes/included-reftest.list
new file mode 100644
index 0000000000..1caf9cc391
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-emitted-includes/included-reftest.list
@@ -0,0 +1 @@
+!= reftest2.html reftest2-ref.html \ No newline at end of file
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-emitted-includes/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-emitted-includes/moz.build
new file mode 100644
index 0000000000..8f321387af
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-emitted-includes/moz.build
@@ -0,0 +1 @@
+REFTEST_MANIFESTS += ["reftest.list"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-emitted-includes/reftest.list b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-emitted-includes/reftest.list
new file mode 100644
index 0000000000..80caf8ffa4
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-emitted-includes/reftest.list
@@ -0,0 +1,2 @@
+== reftest1.html reftest1-ref.html
+include included-reftest.list
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-empty/empty.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-empty/empty.ini
new file mode 100644
index 0000000000..83a0cec0c6
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-empty/empty.ini
@@ -0,0 +1,2 @@
+[DEFAULT]
+foo = bar
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-empty/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-empty/moz.build
new file mode 100644
index 0000000000..486e879241
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-empty/moz.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+MOCHITEST_MANIFESTS += ["empty.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-inactive-ignored/test_inactive.html b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-inactive-ignored/test_inactive.html
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-inactive-ignored/test_inactive.html
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-install-includes/common.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-install-includes/common.ini
new file mode 100644
index 0000000000..753cd0ec0d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-install-includes/common.ini
@@ -0,0 +1 @@
+[test_foo.html]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-install-includes/mochitest.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-install-includes/mochitest.ini
new file mode 100644
index 0000000000..fe0af1cd86
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-install-includes/mochitest.ini
@@ -0,0 +1,3 @@
+[DEFAULT]
+
+[include:common.ini]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-install-includes/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-install-includes/moz.build
new file mode 100644
index 0000000000..4cc0c3d4cf
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-install-includes/moz.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+MOCHITEST_MANIFESTS += ["mochitest.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-install-includes/test_foo.html b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-install-includes/test_foo.html
new file mode 100644
index 0000000000..18ecdcb795
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-install-includes/test_foo.html
@@ -0,0 +1 @@
+<html></html>
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-just-support/foo.txt b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-just-support/foo.txt
new file mode 100644
index 0000000000..ce01362503
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-just-support/foo.txt
@@ -0,0 +1 @@
+hello
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-just-support/just-support.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-just-support/just-support.ini
new file mode 100644
index 0000000000..efa2d4bc05
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-just-support/just-support.ini
@@ -0,0 +1,2 @@
+[DEFAULT]
+support-files = foo.txt
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-just-support/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-just-support/moz.build
new file mode 100644
index 0000000000..adf2a0d91c
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-just-support/moz.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+MOCHITEST_MANIFESTS += ["just-support.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/a11y-support/dir1/bar b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/a11y-support/dir1/bar
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/a11y-support/dir1/bar
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/a11y-support/foo b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/a11y-support/foo
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/a11y-support/foo
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/a11y.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/a11y.ini
new file mode 100644
index 0000000000..9cf7989185
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/a11y.ini
@@ -0,0 +1,4 @@
+[DEFAULT]
+support-files = a11y-support/**
+
+[test_a11y.js]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/browser.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/browser.ini
new file mode 100644
index 0000000000..a81ee3acbb
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/browser.ini
@@ -0,0 +1,4 @@
+[DEFAULT]
+support-files = support1 support2
+
+[test_browser.js]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/chrome.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/chrome.ini
new file mode 100644
index 0000000000..1db07cfac9
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/chrome.ini
@@ -0,0 +1,3 @@
+[DEFAULT]
+
+[test_chrome.js]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/crashtest.list b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/crashtest.list
new file mode 100644
index 0000000000..b9d7f2685a
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/crashtest.list
@@ -0,0 +1 @@
+== crashtest1.html crashtest1-ref.html
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/metro.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/metro.ini
new file mode 100644
index 0000000000..a7eb6def41
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/metro.ini
@@ -0,0 +1,3 @@
+[DEFAULT]
+
+[test_metro.js]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/mochitest.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/mochitest.ini
new file mode 100644
index 0000000000..69fd71de0b
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/mochitest.ini
@@ -0,0 +1,5 @@
+[DEFAULT]
+support-files = external1 external2
+generated-files = external1 external2
+
+[test_mochitest.js]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/moz.build
new file mode 100644
index 0000000000..9de10add3c
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/moz.build
@@ -0,0 +1,12 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+A11Y_MANIFESTS += ["a11y.ini"]
+BROWSER_CHROME_MANIFESTS += ["browser.ini"]
+METRO_CHROME_MANIFESTS += ["metro.ini"]
+MOCHITEST_MANIFESTS += ["mochitest.ini"]
+MOCHITEST_CHROME_MANIFESTS += ["chrome.ini"]
+XPCSHELL_TESTS_MANIFESTS += ["xpcshell.ini"]
+REFTEST_MANIFESTS += ["reftest.list"]
+CRASHTEST_MANIFESTS += ["crashtest.list"]
+PYTHON_UNITTEST_MANIFESTS += ["python.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/python.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/python.ini
new file mode 100644
index 0000000000..97a9db6920
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/python.ini
@@ -0,0 +1 @@
+[test_foo.py]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/reftest.list b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/reftest.list
new file mode 100644
index 0000000000..3fc25b2966
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/reftest.list
@@ -0,0 +1 @@
+== reftest1.html reftest1-ref.html
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_a11y.js b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_a11y.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_a11y.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_browser.js b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_browser.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_chrome.js b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_chrome.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_chrome.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_foo.py b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_foo.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_foo.py
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_metro.js b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_metro.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_metro.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_mochitest.js b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_mochitest.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_mochitest.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_xpcshell.js b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_xpcshell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/test_xpcshell.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/xpcshell.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/xpcshell.ini
new file mode 100644
index 0000000000..c228c24ac1
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-keys-extracted/xpcshell.ini
@@ -0,0 +1,5 @@
+[DEFAULT]
+head = head1 head2
+dupe-manifest =
+
+[test_xpcshell.js]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-manifest/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-manifest/moz.build
new file mode 100644
index 0000000000..ec33a37d3d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-manifest/moz.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+XPCSHELL_TESTS_MANIFESTS += ["does_not_exist.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-test-file-unfiltered/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-test-file-unfiltered/moz.build
new file mode 100644
index 0000000000..d3878746bd
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-test-file-unfiltered/moz.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+XPCSHELL_TESTS_MANIFESTS += ["xpcshell.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-test-file-unfiltered/xpcshell.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-test-file-unfiltered/xpcshell.ini
new file mode 100644
index 0000000000..9ab85c0cef
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-test-file-unfiltered/xpcshell.ini
@@ -0,0 +1,4 @@
+[DEFAULT]
+support-files = support/**
+
+[missing.js]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-test-file/mochitest.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-test-file/mochitest.ini
new file mode 100644
index 0000000000..e3ef6216b7
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-test-file/mochitest.ini
@@ -0,0 +1 @@
+[test_missing.html]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-test-file/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-test-file/moz.build
new file mode 100644
index 0000000000..4cc0c3d4cf
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-missing-test-file/moz.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+MOCHITEST_MANIFESTS += ["mochitest.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-parent-support-files-dir/child/mochitest.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-parent-support-files-dir/child/mochitest.ini
new file mode 100644
index 0000000000..c788224291
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-parent-support-files-dir/child/mochitest.ini
@@ -0,0 +1,4 @@
+[DEFAULT]
+support-files = ../support-file.txt
+
+[test_foo.js]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-parent-support-files-dir/child/test_foo.js b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-parent-support-files-dir/child/test_foo.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-parent-support-files-dir/child/test_foo.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-parent-support-files-dir/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-parent-support-files-dir/moz.build
new file mode 100644
index 0000000000..275a810a5e
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-parent-support-files-dir/moz.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+MOCHITEST_MANIFESTS += ["child/mochitest.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-parent-support-files-dir/support-file.txt b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-parent-support-files-dir/support-file.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-parent-support-files-dir/support-file.txt
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/another-file.sjs b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/another-file.sjs
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/another-file.sjs
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/browser.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/browser.ini
new file mode 100644
index 0000000000..4f1335d6b1
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/browser.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+support-files =
+ another-file.sjs
+ data/**
+
+[test_sub.js] \ No newline at end of file
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/data/one.txt b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/data/one.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/data/one.txt
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/data/two.txt b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/data/two.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/data/two.txt
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/test_sub.js b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/test_sub.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/child/test_sub.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/mochitest.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/mochitest.ini
new file mode 100644
index 0000000000..ada59d387d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/mochitest.ini
@@ -0,0 +1,9 @@
+[DEFAULT]
+support-files =
+ support-file.txt
+ !/child/test_sub.js
+ !/child/another-file.sjs
+ !/child/data/**
+ !/does/not/exist.sjs
+
+[test_foo.js]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/moz.build
new file mode 100644
index 0000000000..9df54dbc99
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/moz.build
@@ -0,0 +1,5 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+MOCHITEST_MANIFESTS += ["mochitest.ini"]
+BROWSER_CHROME_MANIFESTS += ["child/browser.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/support-file.txt b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/support-file.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/support-file.txt
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/test_foo.js b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/test_foo.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-missing/test_foo.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/another-file.sjs b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/another-file.sjs
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/another-file.sjs
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/browser.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/browser.ini
new file mode 100644
index 0000000000..4f1335d6b1
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/browser.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+support-files =
+ another-file.sjs
+ data/**
+
+[test_sub.js] \ No newline at end of file
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/data/one.txt b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/data/one.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/data/one.txt
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/data/two.txt b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/data/two.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/data/two.txt
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/test_sub.js b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/test_sub.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/child/test_sub.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/mochitest.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/mochitest.ini
new file mode 100644
index 0000000000..a9860f3de8
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/mochitest.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+support-files =
+ support-file.txt
+ !/child/test_sub.js
+ !/child/another-file.sjs
+ !/child/data/**
+
+[test_foo.js]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/moz.build
new file mode 100644
index 0000000000..9df54dbc99
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/moz.build
@@ -0,0 +1,5 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+MOCHITEST_MANIFESTS += ["mochitest.ini"]
+BROWSER_CHROME_MANIFESTS += ["child/browser.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/support-file.txt b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/support-file.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/support-file.txt
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/test_foo.js b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/test_foo.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-shared-support/test_foo.js
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-unmatched-generated/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-unmatched-generated/moz.build
new file mode 100644
index 0000000000..9d098e0eab
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-unmatched-generated/moz.build
@@ -0,0 +1,4 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+MOCHITEST_MANIFESTS += ["test.ini"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-unmatched-generated/test.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-unmatched-generated/test.ini
new file mode 100644
index 0000000000..caf3911864
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-unmatched-generated/test.ini
@@ -0,0 +1,4 @@
+[DEFAULT]
+generated-files = does_not_exist
+
+[test_foo]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-unmatched-generated/test_foo b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-unmatched-generated/test_foo
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-unmatched-generated/test_foo
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-symbols-file-objdir-missing-generated/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-symbols-file-objdir-missing-generated/moz.build
new file mode 100644
index 0000000000..450af01d9a
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-symbols-file-objdir-missing-generated/moz.build
@@ -0,0 +1,12 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def SharedLibrary(name):
+ LIBRARY_NAME = name
+ FORCE_SHARED_LIB = True
+
+
+SharedLibrary("foo")
+SYMBOLS_FILE = "!foo.symbols"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-symbols-file-objdir/foo.py b/python/mozbuild/mozbuild/test/frontend/data/test-symbols-file-objdir/foo.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-symbols-file-objdir/foo.py
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-symbols-file-objdir/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-symbols-file-objdir/moz.build
new file mode 100644
index 0000000000..7ea07b4ee9
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-symbols-file-objdir/moz.build
@@ -0,0 +1,15 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def SharedLibrary(name):
+ LIBRARY_NAME = name
+ FORCE_SHARED_LIB = True
+
+
+SharedLibrary("foo")
+SYMBOLS_FILE = "!foo.symbols"
+
+GENERATED_FILES += ["foo.symbols"]
+GENERATED_FILES["foo.symbols"].script = "foo.py"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-symbols-file/foo.symbols b/python/mozbuild/mozbuild/test/frontend/data/test-symbols-file/foo.symbols
new file mode 100644
index 0000000000..257cc5642c
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-symbols-file/foo.symbols
@@ -0,0 +1 @@
+foo
diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-symbols-file/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-symbols-file/moz.build
new file mode 100644
index 0000000000..47e435dbf5
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/test-symbols-file/moz.build
@@ -0,0 +1,12 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def SharedLibrary(name):
+ LIBRARY_NAME = name
+ FORCE_SHARED_LIB = True
+
+
+SharedLibrary("foo")
+SYMBOLS_FILE = "foo.symbols"
diff --git a/python/mozbuild/mozbuild/test/frontend/data/traversal-all-vars/moz.build b/python/mozbuild/mozbuild/test/frontend/data/traversal-all-vars/moz.build
new file mode 100644
index 0000000000..480808eb8a
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/traversal-all-vars/moz.build
@@ -0,0 +1,6 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS += ["regular"]
+TEST_DIRS += ["test"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/traversal-all-vars/parallel/moz.build b/python/mozbuild/mozbuild/test/frontend/data/traversal-all-vars/parallel/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/traversal-all-vars/parallel/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/traversal-all-vars/regular/moz.build b/python/mozbuild/mozbuild/test/frontend/data/traversal-all-vars/regular/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/traversal-all-vars/regular/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/traversal-all-vars/test/moz.build b/python/mozbuild/mozbuild/test/frontend/data/traversal-all-vars/test/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/traversal-all-vars/test/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/traversal-outside-topsrcdir/moz.build b/python/mozbuild/mozbuild/test/frontend/data/traversal-outside-topsrcdir/moz.build
new file mode 100644
index 0000000000..dbdc694a6a
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/traversal-outside-topsrcdir/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS = ["../../foo"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/traversal-relative-dirs/bar/moz.build b/python/mozbuild/mozbuild/test/frontend/data/traversal-relative-dirs/bar/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/traversal-relative-dirs/bar/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/traversal-relative-dirs/foo/moz.build b/python/mozbuild/mozbuild/test/frontend/data/traversal-relative-dirs/foo/moz.build
new file mode 100644
index 0000000000..4b42bbc5ab
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/traversal-relative-dirs/foo/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS = ["../bar"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/traversal-relative-dirs/moz.build b/python/mozbuild/mozbuild/test/frontend/data/traversal-relative-dirs/moz.build
new file mode 100644
index 0000000000..68581574b1
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/traversal-relative-dirs/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS = ["foo"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/traversal-repeated-dirs/bar/moz.build b/python/mozbuild/mozbuild/test/frontend/data/traversal-repeated-dirs/bar/moz.build
new file mode 100644
index 0000000000..f204e245b4
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/traversal-repeated-dirs/bar/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS = ["../foo"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/traversal-repeated-dirs/foo/moz.build b/python/mozbuild/mozbuild/test/frontend/data/traversal-repeated-dirs/foo/moz.build
new file mode 100644
index 0000000000..4b42bbc5ab
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/traversal-repeated-dirs/foo/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS = ["../bar"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/traversal-repeated-dirs/moz.build b/python/mozbuild/mozbuild/test/frontend/data/traversal-repeated-dirs/moz.build
new file mode 100644
index 0000000000..5a9445a6e6
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/traversal-repeated-dirs/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS = ["foo", "bar"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/traversal-simple/bar/moz.build b/python/mozbuild/mozbuild/test/frontend/data/traversal-simple/bar/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/traversal-simple/bar/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/traversal-simple/foo/biz/moz.build b/python/mozbuild/mozbuild/test/frontend/data/traversal-simple/foo/biz/moz.build
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/traversal-simple/foo/biz/moz.build
diff --git a/python/mozbuild/mozbuild/test/frontend/data/traversal-simple/foo/moz.build b/python/mozbuild/mozbuild/test/frontend/data/traversal-simple/foo/moz.build
new file mode 100644
index 0000000000..3ad8a1501d
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/traversal-simple/foo/moz.build
@@ -0,0 +1,2 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+DIRS = ["biz"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/traversal-simple/moz.build b/python/mozbuild/mozbuild/test/frontend/data/traversal-simple/moz.build
new file mode 100644
index 0000000000..5a9445a6e6
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/traversal-simple/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIRS = ["foo", "bar"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/bar.cxx b/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/bar.cxx
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/bar.cxx
diff --git a/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/c1.c b/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/c1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/c1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/c2.c b/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/c2.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/c2.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/foo.cpp b/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/foo.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/foo.cpp
diff --git a/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/moz.build b/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/moz.build
new file mode 100644
index 0000000000..217e43831f
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/moz.build
@@ -0,0 +1,30 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+UNIFIED_SOURCES += [
+ "bar.cxx",
+ "foo.cpp",
+ "quux.cc",
+]
+
+UNIFIED_SOURCES += [
+ "objc1.mm",
+ "objc2.mm",
+]
+
+UNIFIED_SOURCES += [
+ "c1.c",
+ "c2.c",
+]
+
+FILES_PER_UNIFIED_FILE = 1
diff --git a/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/objc1.mm b/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/objc1.mm
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/objc1.mm
diff --git a/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/objc2.mm b/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/objc2.mm
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/objc2.mm
diff --git a/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/quux.cc b/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/quux.cc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/unified-sources-non-unified/quux.cc
diff --git a/python/mozbuild/mozbuild/test/frontend/data/unified-sources/bar.cxx b/python/mozbuild/mozbuild/test/frontend/data/unified-sources/bar.cxx
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/unified-sources/bar.cxx
diff --git a/python/mozbuild/mozbuild/test/frontend/data/unified-sources/c1.c b/python/mozbuild/mozbuild/test/frontend/data/unified-sources/c1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/unified-sources/c1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/unified-sources/c2.c b/python/mozbuild/mozbuild/test/frontend/data/unified-sources/c2.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/unified-sources/c2.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/unified-sources/foo.cpp b/python/mozbuild/mozbuild/test/frontend/data/unified-sources/foo.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/unified-sources/foo.cpp
diff --git a/python/mozbuild/mozbuild/test/frontend/data/unified-sources/moz.build b/python/mozbuild/mozbuild/test/frontend/data/unified-sources/moz.build
new file mode 100644
index 0000000000..8a86e055da
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/unified-sources/moz.build
@@ -0,0 +1,30 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+UNIFIED_SOURCES += [
+ "bar.cxx",
+ "foo.cpp",
+ "quux.cc",
+]
+
+UNIFIED_SOURCES += [
+ "objc1.mm",
+ "objc2.mm",
+]
+
+UNIFIED_SOURCES += [
+ "c1.c",
+ "c2.c",
+]
+
+FILES_PER_UNIFIED_FILE = 32
diff --git a/python/mozbuild/mozbuild/test/frontend/data/unified-sources/objc1.mm b/python/mozbuild/mozbuild/test/frontend/data/unified-sources/objc1.mm
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/unified-sources/objc1.mm
diff --git a/python/mozbuild/mozbuild/test/frontend/data/unified-sources/objc2.mm b/python/mozbuild/mozbuild/test/frontend/data/unified-sources/objc2.mm
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/unified-sources/objc2.mm
diff --git a/python/mozbuild/mozbuild/test/frontend/data/unified-sources/quux.cc b/python/mozbuild/mozbuild/test/frontend/data/unified-sources/quux.cc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/unified-sources/quux.cc
diff --git a/python/mozbuild/mozbuild/test/frontend/data/use-nasm/moz.build b/python/mozbuild/mozbuild/test/frontend/data/use-nasm/moz.build
new file mode 100644
index 0000000000..63ac5283f6
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/use-nasm/moz.build
@@ -0,0 +1,15 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+USE_NASM = True
+
+SOURCES += ["test1.S"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/use-nasm/test1.S b/python/mozbuild/mozbuild/test/frontend/data/use-nasm/test1.S
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/use-nasm/test1.S
diff --git a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/bans.S b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/bans.S
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/bans.S
diff --git a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/baz.def b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/baz.def
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/baz.def
diff --git a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build
new file mode 100644
index 0000000000..d080b00c92
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build
@@ -0,0 +1,13 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+DIST_INSTALL = False
+
+DELAYLOAD_DLLS = ["foo.dll", "bar.dll"]
+
+RCFILE = "foo.rc"
+RCINCLUDE = "bar.rc"
+DEFFILE = "baz.def"
+
+WIN32_EXE_LDFLAGS += ["-subsystem:console"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test1.c b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test1.cpp b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test1.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test1.cpp
diff --git a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test1.mm b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test1.mm
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test1.mm
diff --git a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test2.c b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test2.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test2.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test2.cpp b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test2.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test2.cpp
diff --git a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test2.mm b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test2.mm
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/test2.mm
diff --git a/python/mozbuild/mozbuild/test/frontend/data/visibility-flags/moz.build b/python/mozbuild/mozbuild/test/frontend/data/visibility-flags/moz.build
new file mode 100644
index 0000000000..630a3afd80
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/visibility-flags/moz.build
@@ -0,0 +1,21 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+
+@template
+def Library(name):
+ """Template for libraries."""
+ LIBRARY_NAME = name
+
+
+Library("dummy")
+
+
+@template
+def NoVisibilityFlags():
+ COMPILE_FLAGS["VISIBILITY"] = []
+
+
+UNIFIED_SOURCES += ["test1.c"]
+
+NoVisibilityFlags()
diff --git a/python/mozbuild/mozbuild/test/frontend/data/visibility-flags/test1.c b/python/mozbuild/mozbuild/test/frontend/data/visibility-flags/test1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/visibility-flags/test1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/wasm-compile-flags/moz.build b/python/mozbuild/mozbuild/test/frontend/data/wasm-compile-flags/moz.build
new file mode 100644
index 0000000000..e7cf13088f
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/wasm-compile-flags/moz.build
@@ -0,0 +1,14 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+SANDBOXED_WASM_LIBRARY_NAME = "dummy"
+
+WASM_SOURCES += ["test1.c"]
+
+value = "xyz"
+WASM_DEFINES["FOO"] = True
+WASM_DEFINES["BAZ"] = '"abcd"'
+WASM_DEFINES["BAR"] = 7
+WASM_DEFINES["VALUE"] = value
+WASM_DEFINES["QUX"] = False
+WASM_CFLAGS += ["-funroll-loops", "-wasm-arg"]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/wasm-compile-flags/test1.c b/python/mozbuild/mozbuild/test/frontend/data/wasm-compile-flags/test1.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/wasm-compile-flags/test1.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/wasm-sources/a.cpp b/python/mozbuild/mozbuild/test/frontend/data/wasm-sources/a.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/wasm-sources/a.cpp
diff --git a/python/mozbuild/mozbuild/test/frontend/data/wasm-sources/b.cc b/python/mozbuild/mozbuild/test/frontend/data/wasm-sources/b.cc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/wasm-sources/b.cc
diff --git a/python/mozbuild/mozbuild/test/frontend/data/wasm-sources/c.cxx b/python/mozbuild/mozbuild/test/frontend/data/wasm-sources/c.cxx
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/wasm-sources/c.cxx
diff --git a/python/mozbuild/mozbuild/test/frontend/data/wasm-sources/d.c b/python/mozbuild/mozbuild/test/frontend/data/wasm-sources/d.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/wasm-sources/d.c
diff --git a/python/mozbuild/mozbuild/test/frontend/data/wasm-sources/moz.build b/python/mozbuild/mozbuild/test/frontend/data/wasm-sources/moz.build
new file mode 100644
index 0000000000..e266bcb0dd
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/wasm-sources/moz.build
@@ -0,0 +1,15 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+SANDBOXED_WASM_LIBRARY_NAME = "wasmSources"
+
+WASM_SOURCES += [
+ "a.cpp",
+ "b.cc",
+ "c.cxx",
+]
+
+WASM_SOURCES += [
+ "d.c",
+]
diff --git a/python/mozbuild/mozbuild/test/frontend/data/xpidl-module-no-sources/moz.build b/python/mozbuild/mozbuild/test/frontend/data/xpidl-module-no-sources/moz.build
new file mode 100644
index 0000000000..f0abd45382
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/xpidl-module-no-sources/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+XPIDL_MODULE = "xpidl_module"
diff --git a/python/mozbuild/mozbuild/test/frontend/test_context.py b/python/mozbuild/mozbuild/test/frontend/test_context.py
new file mode 100644
index 0000000000..fbf35e1c8c
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/test_context.py
@@ -0,0 +1,736 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+import unittest
+
+import six
+from mozpack import path as mozpath
+from mozunit import main
+
+from mozbuild.frontend.context import (
+ FUNCTIONS,
+ SPECIAL_VARIABLES,
+ SUBCONTEXTS,
+ VARIABLES,
+ AbsolutePath,
+ Context,
+ ContextDerivedTypedHierarchicalStringList,
+ ContextDerivedTypedList,
+ ContextDerivedTypedListWithItems,
+ ContextDerivedTypedRecord,
+ Files,
+ ObjDirPath,
+ Path,
+ SourcePath,
+)
+from mozbuild.util import StrictOrderingOnAppendListWithFlagsFactory
+
+
+class TestContext(unittest.TestCase):
+ def test_defaults(self):
+ test = Context(
+ {
+ "foo": (int, int, ""),
+ "bar": (bool, bool, ""),
+ "baz": (dict, dict, ""),
+ }
+ )
+
+ self.assertEqual(list(test), [])
+
+ self.assertEqual(test["foo"], 0)
+
+ self.assertEqual(set(test.keys()), {"foo"})
+
+ self.assertEqual(test["bar"], False)
+
+ self.assertEqual(set(test.keys()), {"foo", "bar"})
+
+ self.assertEqual(test["baz"], {})
+
+ self.assertEqual(set(test.keys()), {"foo", "bar", "baz"})
+
+ with self.assertRaises(KeyError):
+ test["qux"]
+
+ self.assertEqual(set(test.keys()), {"foo", "bar", "baz"})
+
+ def test_type_check(self):
+ test = Context(
+ {
+ "foo": (int, int, ""),
+ "baz": (dict, list, ""),
+ }
+ )
+
+ test["foo"] = 5
+
+ self.assertEqual(test["foo"], 5)
+
+ with self.assertRaises(ValueError):
+ test["foo"] = {}
+
+ self.assertEqual(test["foo"], 5)
+
+ with self.assertRaises(KeyError):
+ test["bar"] = True
+
+ test["baz"] = [("a", 1), ("b", 2)]
+
+ self.assertEqual(test["baz"], {"a": 1, "b": 2})
+
+ def test_update(self):
+ test = Context(
+ {
+ "foo": (int, int, ""),
+ "bar": (bool, bool, ""),
+ "baz": (dict, list, ""),
+ }
+ )
+
+ self.assertEqual(list(test), [])
+
+ with self.assertRaises(ValueError):
+ test.update(bar=True, foo={})
+
+ self.assertEqual(list(test), [])
+
+ test.update(bar=True, foo=1)
+
+ self.assertEqual(set(test.keys()), {"foo", "bar"})
+ self.assertEqual(test["foo"], 1)
+ self.assertEqual(test["bar"], True)
+
+ test.update([("bar", False), ("foo", 2)])
+ self.assertEqual(test["foo"], 2)
+ self.assertEqual(test["bar"], False)
+
+ test.update([("foo", 0), ("baz", {"a": 1, "b": 2})])
+ self.assertEqual(test["foo"], 0)
+ self.assertEqual(test["baz"], {"a": 1, "b": 2})
+
+ test.update([("foo", 42), ("baz", [("c", 3), ("d", 4)])])
+ self.assertEqual(test["foo"], 42)
+ self.assertEqual(test["baz"], {"c": 3, "d": 4})
+
+ def test_context_paths(self):
+ test = Context()
+
+ # Newly created context has no paths.
+ self.assertIsNone(test.main_path)
+ self.assertIsNone(test.current_path)
+ self.assertEqual(test.all_paths, set())
+ self.assertEqual(test.source_stack, [])
+
+ foo = os.path.abspath("foo")
+ test.add_source(foo)
+
+ # Adding the first source makes it the main and current path.
+ self.assertEqual(test.main_path, foo)
+ self.assertEqual(test.current_path, foo)
+ self.assertEqual(test.all_paths, set([foo]))
+ self.assertEqual(test.source_stack, [foo])
+
+ bar = os.path.abspath("bar")
+ test.add_source(bar)
+
+ # Adding the second source makes leaves main and current paths alone.
+ self.assertEqual(test.main_path, foo)
+ self.assertEqual(test.current_path, foo)
+ self.assertEqual(test.all_paths, set([bar, foo]))
+ self.assertEqual(test.source_stack, [foo])
+
+ qux = os.path.abspath("qux")
+ test.push_source(qux)
+
+ # Pushing a source makes it the current path
+ self.assertEqual(test.main_path, foo)
+ self.assertEqual(test.current_path, qux)
+ self.assertEqual(test.all_paths, set([bar, foo, qux]))
+ self.assertEqual(test.source_stack, [foo, qux])
+
+ hoge = os.path.abspath("hoge")
+ test.push_source(hoge)
+ self.assertEqual(test.main_path, foo)
+ self.assertEqual(test.current_path, hoge)
+ self.assertEqual(test.all_paths, set([bar, foo, hoge, qux]))
+ self.assertEqual(test.source_stack, [foo, qux, hoge])
+
+ fuga = os.path.abspath("fuga")
+
+ # Adding a source after pushing doesn't change the source stack
+ test.add_source(fuga)
+ self.assertEqual(test.main_path, foo)
+ self.assertEqual(test.current_path, hoge)
+ self.assertEqual(test.all_paths, set([bar, foo, fuga, hoge, qux]))
+ self.assertEqual(test.source_stack, [foo, qux, hoge])
+
+ # Adding a source twice doesn't change anything
+ test.add_source(qux)
+ self.assertEqual(test.main_path, foo)
+ self.assertEqual(test.current_path, hoge)
+ self.assertEqual(test.all_paths, set([bar, foo, fuga, hoge, qux]))
+ self.assertEqual(test.source_stack, [foo, qux, hoge])
+
+ last = test.pop_source()
+
+ # Popping a source returns the last pushed one, not the last added one.
+ self.assertEqual(last, hoge)
+ self.assertEqual(test.main_path, foo)
+ self.assertEqual(test.current_path, qux)
+ self.assertEqual(test.all_paths, set([bar, foo, fuga, hoge, qux]))
+ self.assertEqual(test.source_stack, [foo, qux])
+
+ last = test.pop_source()
+ self.assertEqual(last, qux)
+ self.assertEqual(test.main_path, foo)
+ self.assertEqual(test.current_path, foo)
+ self.assertEqual(test.all_paths, set([bar, foo, fuga, hoge, qux]))
+ self.assertEqual(test.source_stack, [foo])
+
+ # Popping the main path is allowed.
+ last = test.pop_source()
+ self.assertEqual(last, foo)
+ self.assertEqual(test.main_path, foo)
+ self.assertIsNone(test.current_path)
+ self.assertEqual(test.all_paths, set([bar, foo, fuga, hoge, qux]))
+ self.assertEqual(test.source_stack, [])
+
+ # Popping past the main path asserts.
+ with self.assertRaises(AssertionError):
+ test.pop_source()
+
+ # Pushing after the main path was popped asserts.
+ with self.assertRaises(AssertionError):
+ test.push_source(foo)
+
+ test = Context()
+ test.push_source(foo)
+ test.push_source(bar)
+
+ # Pushing the same file twice is allowed.
+ test.push_source(bar)
+ test.push_source(foo)
+ self.assertEqual(last, foo)
+ self.assertEqual(test.main_path, foo)
+ self.assertEqual(test.current_path, foo)
+ self.assertEqual(test.all_paths, set([bar, foo]))
+ self.assertEqual(test.source_stack, [foo, bar, bar, foo])
+
+ def test_context_dirs(self):
+ class Config(object):
+ pass
+
+ config = Config()
+ config.topsrcdir = mozpath.abspath(os.curdir)
+ config.topobjdir = mozpath.abspath("obj")
+ test = Context(config=config)
+ foo = mozpath.abspath("foo")
+ test.push_source(foo)
+
+ self.assertEqual(test.srcdir, config.topsrcdir)
+ self.assertEqual(test.relsrcdir, "")
+ self.assertEqual(test.objdir, config.topobjdir)
+ self.assertEqual(test.relobjdir, "")
+
+ foobar = os.path.abspath("foo/bar")
+ test.push_source(foobar)
+ self.assertEqual(test.srcdir, mozpath.join(config.topsrcdir, "foo"))
+ self.assertEqual(test.relsrcdir, "foo")
+ self.assertEqual(test.objdir, config.topobjdir)
+ self.assertEqual(test.relobjdir, "")
+
+
+class TestSymbols(unittest.TestCase):
+ def _verify_doc(self, doc):
+ # Documentation should be of the format:
+ # """SUMMARY LINE
+ #
+ # EXTRA PARAGRAPHS
+ # """
+
+ self.assertNotIn("\r", doc)
+
+ lines = doc.split("\n")
+
+ # No trailing whitespace.
+ for line in lines[0:-1]:
+ self.assertEqual(line, line.rstrip())
+
+ self.assertGreater(len(lines), 0)
+ self.assertGreater(len(lines[0].strip()), 0)
+
+ # Last line should be empty.
+ self.assertEqual(lines[-1].strip(), "")
+
+ def test_documentation_formatting(self):
+ for typ, inp, doc in VARIABLES.values():
+ self._verify_doc(doc)
+
+ for attr, args, doc in FUNCTIONS.values():
+ self._verify_doc(doc)
+
+ for func, typ, doc in SPECIAL_VARIABLES.values():
+ self._verify_doc(doc)
+
+ for name, cls in SUBCONTEXTS.items():
+ self._verify_doc(cls.__doc__)
+
+ for name, v in cls.VARIABLES.items():
+ self._verify_doc(v[2])
+
+
+class TestPaths(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ class Config(object):
+ pass
+
+ cls.config = config = Config()
+ config.topsrcdir = mozpath.abspath(os.curdir)
+ config.topobjdir = mozpath.abspath("obj")
+
+ def test_path(self):
+ config = self.config
+ ctxt1 = Context(config=config)
+ ctxt1.push_source(mozpath.join(config.topsrcdir, "foo", "moz.build"))
+ ctxt2 = Context(config=config)
+ ctxt2.push_source(mozpath.join(config.topsrcdir, "bar", "moz.build"))
+
+ path1 = Path(ctxt1, "qux")
+ self.assertIsInstance(path1, SourcePath)
+ self.assertEqual(path1, "qux")
+ self.assertEqual(path1.full_path, mozpath.join(config.topsrcdir, "foo", "qux"))
+
+ path2 = Path(ctxt2, "../foo/qux")
+ self.assertIsInstance(path2, SourcePath)
+ self.assertEqual(path2, "../foo/qux")
+ self.assertEqual(path2.full_path, mozpath.join(config.topsrcdir, "foo", "qux"))
+
+ self.assertEqual(path1, path2)
+
+ self.assertEqual(
+ path1.join("../../bar/qux").full_path,
+ mozpath.join(config.topsrcdir, "bar", "qux"),
+ )
+
+ path1 = Path(ctxt1, "/qux/qux")
+ self.assertIsInstance(path1, SourcePath)
+ self.assertEqual(path1, "/qux/qux")
+ self.assertEqual(path1.full_path, mozpath.join(config.topsrcdir, "qux", "qux"))
+
+ path2 = Path(ctxt2, "/qux/qux")
+ self.assertIsInstance(path2, SourcePath)
+ self.assertEqual(path2, "/qux/qux")
+ self.assertEqual(path2.full_path, mozpath.join(config.topsrcdir, "qux", "qux"))
+
+ self.assertEqual(path1, path2)
+
+ path1 = Path(ctxt1, "!qux")
+ self.assertIsInstance(path1, ObjDirPath)
+ self.assertEqual(path1, "!qux")
+ self.assertEqual(path1.full_path, mozpath.join(config.topobjdir, "foo", "qux"))
+
+ path2 = Path(ctxt2, "!../foo/qux")
+ self.assertIsInstance(path2, ObjDirPath)
+ self.assertEqual(path2, "!../foo/qux")
+ self.assertEqual(path2.full_path, mozpath.join(config.topobjdir, "foo", "qux"))
+
+ self.assertEqual(path1, path2)
+
+ path1 = Path(ctxt1, "!/qux/qux")
+ self.assertIsInstance(path1, ObjDirPath)
+ self.assertEqual(path1, "!/qux/qux")
+ self.assertEqual(path1.full_path, mozpath.join(config.topobjdir, "qux", "qux"))
+
+ path2 = Path(ctxt2, "!/qux/qux")
+ self.assertIsInstance(path2, ObjDirPath)
+ self.assertEqual(path2, "!/qux/qux")
+ self.assertEqual(path2.full_path, mozpath.join(config.topobjdir, "qux", "qux"))
+
+ self.assertEqual(path1, path2)
+
+ path1 = Path(ctxt1, path1)
+ self.assertIsInstance(path1, ObjDirPath)
+ self.assertEqual(path1, "!/qux/qux")
+ self.assertEqual(path1.full_path, mozpath.join(config.topobjdir, "qux", "qux"))
+
+ path2 = Path(ctxt2, path2)
+ self.assertIsInstance(path2, ObjDirPath)
+ self.assertEqual(path2, "!/qux/qux")
+ self.assertEqual(path2.full_path, mozpath.join(config.topobjdir, "qux", "qux"))
+
+ self.assertEqual(path1, path2)
+
+ path1 = Path(path1)
+ self.assertIsInstance(path1, ObjDirPath)
+ self.assertEqual(path1, "!/qux/qux")
+ self.assertEqual(path1.full_path, mozpath.join(config.topobjdir, "qux", "qux"))
+
+ self.assertEqual(path1, path2)
+
+ path2 = Path(path2)
+ self.assertIsInstance(path2, ObjDirPath)
+ self.assertEqual(path2, "!/qux/qux")
+ self.assertEqual(path2.full_path, mozpath.join(config.topobjdir, "qux", "qux"))
+
+ self.assertEqual(path1, path2)
+
+ def test_source_path(self):
+ config = self.config
+ ctxt = Context(config=config)
+ ctxt.push_source(mozpath.join(config.topsrcdir, "foo", "moz.build"))
+
+ path = SourcePath(ctxt, "qux")
+ self.assertEqual(path, "qux")
+ self.assertEqual(path.full_path, mozpath.join(config.topsrcdir, "foo", "qux"))
+ self.assertEqual(path.translated, mozpath.join(config.topobjdir, "foo", "qux"))
+
+ path = SourcePath(ctxt, "../bar/qux")
+ self.assertEqual(path, "../bar/qux")
+ self.assertEqual(path.full_path, mozpath.join(config.topsrcdir, "bar", "qux"))
+ self.assertEqual(path.translated, mozpath.join(config.topobjdir, "bar", "qux"))
+
+ path = SourcePath(ctxt, "/qux/qux")
+ self.assertEqual(path, "/qux/qux")
+ self.assertEqual(path.full_path, mozpath.join(config.topsrcdir, "qux", "qux"))
+ self.assertEqual(path.translated, mozpath.join(config.topobjdir, "qux", "qux"))
+
+ with self.assertRaises(ValueError):
+ SourcePath(ctxt, "!../bar/qux")
+
+ with self.assertRaises(ValueError):
+ SourcePath(ctxt, "!/qux/qux")
+
+ path = SourcePath(path)
+ self.assertIsInstance(path, SourcePath)
+ self.assertEqual(path, "/qux/qux")
+ self.assertEqual(path.full_path, mozpath.join(config.topsrcdir, "qux", "qux"))
+ self.assertEqual(path.translated, mozpath.join(config.topobjdir, "qux", "qux"))
+
+ path = Path(path)
+ self.assertIsInstance(path, SourcePath)
+
+ def test_objdir_path(self):
+ config = self.config
+ ctxt = Context(config=config)
+ ctxt.push_source(mozpath.join(config.topsrcdir, "foo", "moz.build"))
+
+ path = ObjDirPath(ctxt, "!qux")
+ self.assertEqual(path, "!qux")
+ self.assertEqual(path.full_path, mozpath.join(config.topobjdir, "foo", "qux"))
+
+ path = ObjDirPath(ctxt, "!../bar/qux")
+ self.assertEqual(path, "!../bar/qux")
+ self.assertEqual(path.full_path, mozpath.join(config.topobjdir, "bar", "qux"))
+
+ path = ObjDirPath(ctxt, "!/qux/qux")
+ self.assertEqual(path, "!/qux/qux")
+ self.assertEqual(path.full_path, mozpath.join(config.topobjdir, "qux", "qux"))
+
+ with self.assertRaises(ValueError):
+ path = ObjDirPath(ctxt, "../bar/qux")
+
+ with self.assertRaises(ValueError):
+ path = ObjDirPath(ctxt, "/qux/qux")
+
+ path = ObjDirPath(path)
+ self.assertIsInstance(path, ObjDirPath)
+ self.assertEqual(path, "!/qux/qux")
+ self.assertEqual(path.full_path, mozpath.join(config.topobjdir, "qux", "qux"))
+
+ path = Path(path)
+ self.assertIsInstance(path, ObjDirPath)
+
+ def test_absolute_path(self):
+ config = self.config
+ ctxt = Context(config=config)
+ ctxt.push_source(mozpath.join(config.topsrcdir, "foo", "moz.build"))
+
+ path = AbsolutePath(ctxt, "%/qux")
+ self.assertEqual(path, "%/qux")
+ self.assertEqual(path.full_path, "/qux")
+
+ with self.assertRaises(ValueError):
+ path = AbsolutePath(ctxt, "%qux")
+
+ def test_path_with_mixed_contexts(self):
+ config = self.config
+ ctxt1 = Context(config=config)
+ ctxt1.push_source(mozpath.join(config.topsrcdir, "foo", "moz.build"))
+ ctxt2 = Context(config=config)
+ ctxt2.push_source(mozpath.join(config.topsrcdir, "bar", "moz.build"))
+
+ path1 = Path(ctxt1, "qux")
+ path2 = Path(ctxt2, path1)
+ self.assertEqual(path2, path1)
+ self.assertEqual(path2, "qux")
+ self.assertEqual(path2.context, ctxt1)
+ self.assertEqual(path2.full_path, mozpath.join(config.topsrcdir, "foo", "qux"))
+
+ path1 = Path(ctxt1, "../bar/qux")
+ path2 = Path(ctxt2, path1)
+ self.assertEqual(path2, path1)
+ self.assertEqual(path2, "../bar/qux")
+ self.assertEqual(path2.context, ctxt1)
+ self.assertEqual(path2.full_path, mozpath.join(config.topsrcdir, "bar", "qux"))
+
+ path1 = Path(ctxt1, "/qux/qux")
+ path2 = Path(ctxt2, path1)
+ self.assertEqual(path2, path1)
+ self.assertEqual(path2, "/qux/qux")
+ self.assertEqual(path2.context, ctxt1)
+ self.assertEqual(path2.full_path, mozpath.join(config.topsrcdir, "qux", "qux"))
+
+ path1 = Path(ctxt1, "!qux")
+ path2 = Path(ctxt2, path1)
+ self.assertEqual(path2, path1)
+ self.assertEqual(path2, "!qux")
+ self.assertEqual(path2.context, ctxt1)
+ self.assertEqual(path2.full_path, mozpath.join(config.topobjdir, "foo", "qux"))
+
+ path1 = Path(ctxt1, "!../bar/qux")
+ path2 = Path(ctxt2, path1)
+ self.assertEqual(path2, path1)
+ self.assertEqual(path2, "!../bar/qux")
+ self.assertEqual(path2.context, ctxt1)
+ self.assertEqual(path2.full_path, mozpath.join(config.topobjdir, "bar", "qux"))
+
+ path1 = Path(ctxt1, "!/qux/qux")
+ path2 = Path(ctxt2, path1)
+ self.assertEqual(path2, path1)
+ self.assertEqual(path2, "!/qux/qux")
+ self.assertEqual(path2.context, ctxt1)
+ self.assertEqual(path2.full_path, mozpath.join(config.topobjdir, "qux", "qux"))
+
+ def test_path_typed_list(self):
+ config = self.config
+ ctxt1 = Context(config=config)
+ ctxt1.push_source(mozpath.join(config.topsrcdir, "foo", "moz.build"))
+ ctxt2 = Context(config=config)
+ ctxt2.push_source(mozpath.join(config.topsrcdir, "bar", "moz.build"))
+
+ paths = [
+ "!../bar/qux",
+ "!/qux/qux",
+ "!qux",
+ "../bar/qux",
+ "/qux/qux",
+ "qux",
+ ]
+
+ MyList = ContextDerivedTypedList(Path)
+ l = MyList(ctxt1)
+ l += paths
+
+ for p_str, p_path in zip(paths, l):
+ self.assertEqual(p_str, p_path)
+ self.assertEqual(p_path, Path(ctxt1, p_str))
+ self.assertEqual(
+ p_path.join("foo"), Path(ctxt1, mozpath.join(p_str, "foo"))
+ )
+
+ l2 = MyList(ctxt2)
+ l2 += paths
+
+ for p_str, p_path in zip(paths, l2):
+ self.assertEqual(p_str, p_path)
+ self.assertEqual(p_path, Path(ctxt2, p_str))
+
+ # Assigning with Paths from another context doesn't rebase them
+ l2 = MyList(ctxt2)
+ l2 += l
+
+ for p_str, p_path in zip(paths, l2):
+ self.assertEqual(p_str, p_path)
+ self.assertEqual(p_path, Path(ctxt1, p_str))
+
+ MyListWithFlags = ContextDerivedTypedListWithItems(
+ Path,
+ StrictOrderingOnAppendListWithFlagsFactory(
+ {
+ "foo": bool,
+ }
+ ),
+ )
+ l = MyListWithFlags(ctxt1)
+ l += paths
+
+ for p in paths:
+ l[p].foo = True
+
+ for p_str, p_path in zip(paths, l):
+ self.assertEqual(p_str, p_path)
+ self.assertEqual(p_path, Path(ctxt1, p_str))
+ self.assertEqual(l[p_str].foo, True)
+ self.assertEqual(l[p_path].foo, True)
+
+ def test_path_typed_hierarchy_list(self):
+ config = self.config
+ ctxt1 = Context(config=config)
+ ctxt1.push_source(mozpath.join(config.topsrcdir, "foo", "moz.build"))
+ ctxt2 = Context(config=config)
+ ctxt2.push_source(mozpath.join(config.topsrcdir, "bar", "moz.build"))
+
+ paths = [
+ "!../bar/qux",
+ "!/qux/qux",
+ "!qux",
+ "../bar/qux",
+ "/qux/qux",
+ "qux",
+ ]
+
+ MyList = ContextDerivedTypedHierarchicalStringList(Path)
+ l = MyList(ctxt1)
+ l += paths
+ l.subdir += paths
+
+ for _, files in l.walk():
+ for p_str, p_path in zip(paths, files):
+ self.assertEqual(p_str, p_path)
+ self.assertEqual(p_path, Path(ctxt1, p_str))
+ self.assertEqual(
+ p_path.join("foo"), Path(ctxt1, mozpath.join(p_str, "foo"))
+ )
+
+ l2 = MyList(ctxt2)
+ l2 += paths
+ l2.subdir += paths
+
+ for _, files in l2.walk():
+ for p_str, p_path in zip(paths, files):
+ self.assertEqual(p_str, p_path)
+ self.assertEqual(p_path, Path(ctxt2, p_str))
+
+ # Assigning with Paths from another context doesn't rebase them
+ l2 = MyList(ctxt2)
+ l2 += l
+
+ for _, files in l2.walk():
+ for p_str, p_path in zip(paths, files):
+ self.assertEqual(p_str, p_path)
+ self.assertEqual(p_path, Path(ctxt1, p_str))
+
+
+class TestTypedRecord(unittest.TestCase):
+ def test_fields(self):
+ T = ContextDerivedTypedRecord(("field1", six.text_type), ("field2", list))
+ inst = T(None)
+ self.assertEqual(inst.field1, "")
+ self.assertEqual(inst.field2, [])
+
+ inst.field1 = "foo"
+ inst.field2 += ["bar"]
+
+ self.assertEqual(inst.field1, "foo")
+ self.assertEqual(inst.field2, ["bar"])
+
+ with self.assertRaises(AttributeError):
+ inst.field3 = []
+
+ def test_coercion(self):
+ T = ContextDerivedTypedRecord(("field1", six.text_type), ("field2", list))
+ inst = T(None)
+ inst.field1 = 3
+ inst.field2 += ("bar",)
+ self.assertEqual(inst.field1, "3")
+ self.assertEqual(inst.field2, ["bar"])
+
+ with self.assertRaises(TypeError):
+ inst.field2 = object()
+
+
+class TestFiles(unittest.TestCase):
+ def test_aggregate_empty(self):
+ c = Context({})
+
+ files = {"moz.build": Files(c, "**")}
+
+ self.assertEqual(
+ Files.aggregate(files),
+ {
+ "bug_component_counts": [],
+ "recommended_bug_component": None,
+ },
+ )
+
+ def test_single_bug_component(self):
+ c = Context({})
+ f = Files(c, "**")
+ f["BUG_COMPONENT"] = ("Product1", "Component1")
+
+ files = {"moz.build": f}
+ self.assertEqual(
+ Files.aggregate(files),
+ {
+ "bug_component_counts": [(("Product1", "Component1"), 1)],
+ "recommended_bug_component": ("Product1", "Component1"),
+ },
+ )
+
+ def test_multiple_bug_components(self):
+ c = Context({})
+ f1 = Files(c, "**")
+ f1["BUG_COMPONENT"] = ("Product1", "Component1")
+
+ f2 = Files(c, "**")
+ f2["BUG_COMPONENT"] = ("Product2", "Component2")
+
+ files = {"a": f1, "b": f2, "c": f1}
+ self.assertEqual(
+ Files.aggregate(files),
+ {
+ "bug_component_counts": [
+ (("Product1", "Component1"), 2),
+ (("Product2", "Component2"), 1),
+ ],
+ "recommended_bug_component": ("Product1", "Component1"),
+ },
+ )
+
+ def test_no_recommended_bug_component(self):
+ """If there is no clear count winner, we don't recommend a bug component."""
+ c = Context({})
+ f1 = Files(c, "**")
+ f1["BUG_COMPONENT"] = ("Product1", "Component1")
+
+ f2 = Files(c, "**")
+ f2["BUG_COMPONENT"] = ("Product2", "Component2")
+
+ files = {"a": f1, "b": f2}
+ self.assertEqual(
+ Files.aggregate(files),
+ {
+ "bug_component_counts": [
+ (("Product1", "Component1"), 1),
+ (("Product2", "Component2"), 1),
+ ],
+ "recommended_bug_component": None,
+ },
+ )
+
+ def test_multiple_patterns(self):
+ c = Context({})
+ f1 = Files(c, "a/**")
+ f1["BUG_COMPONENT"] = ("Product1", "Component1")
+ f2 = Files(c, "b/**", "a/bar")
+ f2["BUG_COMPONENT"] = ("Product2", "Component2")
+
+ files = {"a/foo": f1, "a/bar": f2, "b/foo": f2}
+ self.assertEqual(
+ Files.aggregate(files),
+ {
+ "bug_component_counts": [
+ (("Product2", "Component2"), 2),
+ (("Product1", "Component1"), 1),
+ ],
+ "recommended_bug_component": ("Product2", "Component2"),
+ },
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/python/mozbuild/mozbuild/test/frontend/test_emitter.py b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
new file mode 100644
index 0000000000..4bbab3942a
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
@@ -0,0 +1,1877 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+import unittest
+
+import mozpack.path as mozpath
+import six
+from mozunit import main
+
+from mozbuild.frontend.context import ObjDirPath, Path
+from mozbuild.frontend.data import (
+ ComputedFlags,
+ ConfigFileSubstitution,
+ Defines,
+ DirectoryTraversal,
+ Exports,
+ FinalTargetPreprocessedFiles,
+ GeneratedFile,
+ HostProgram,
+ HostRustLibrary,
+ HostRustProgram,
+ HostSources,
+ IPDLCollection,
+ JARManifest,
+ LocalInclude,
+ LocalizedFiles,
+ LocalizedPreprocessedFiles,
+ Program,
+ RustLibrary,
+ RustProgram,
+ SharedLibrary,
+ SimpleProgram,
+ Sources,
+ StaticLibrary,
+ TestHarnessFiles,
+ TestManifest,
+ UnifiedSources,
+ VariablePassthru,
+ WasmSources,
+)
+from mozbuild.frontend.emitter import TreeMetadataEmitter
+from mozbuild.frontend.reader import (
+ BuildReader,
+ BuildReaderError,
+ SandboxValidationError,
+)
+from mozbuild.test.common import MockConfig
+
+data_path = mozpath.abspath(mozpath.dirname(__file__))
+data_path = mozpath.join(data_path, "data")
+
+
+class TestEmitterBasic(unittest.TestCase):
+ def setUp(self):
+ self._old_env = dict(os.environ)
+ os.environ.pop("MOZ_OBJDIR", None)
+
+ def tearDown(self):
+ os.environ.clear()
+ os.environ.update(self._old_env)
+
+ def reader(self, name, enable_tests=False, extra_substs=None):
+ substs = dict(
+ ENABLE_TESTS="1" if enable_tests else "",
+ BIN_SUFFIX=".prog",
+ HOST_BIN_SUFFIX=".hostprog",
+ OS_TARGET="WINNT",
+ COMPILE_ENVIRONMENT="1",
+ STL_FLAGS=["-I/path/to/topobjdir/dist/stl_wrappers"],
+ VISIBILITY_FLAGS=["-include", "$(topsrcdir)/config/gcc_hidden.h"],
+ OBJ_SUFFIX="obj",
+ WASM_OBJ_SUFFIX="wasm",
+ WASM_CFLAGS=["-foo"],
+ )
+ if extra_substs:
+ substs.update(extra_substs)
+ config = MockConfig(mozpath.join(data_path, name), extra_substs=substs)
+
+ return BuildReader(config)
+
+ def read_topsrcdir(self, reader, filter_common=True):
+ emitter = TreeMetadataEmitter(reader.config)
+ objs = list(emitter.emit(reader.read_topsrcdir()))
+ self.assertGreater(len(objs), 0)
+
+ filtered = []
+ for obj in objs:
+ if filter_common and isinstance(obj, DirectoryTraversal):
+ continue
+
+ filtered.append(obj)
+
+ return filtered
+
+ def test_dirs_traversal_simple(self):
+ reader = self.reader("traversal-simple")
+ objs = self.read_topsrcdir(reader, filter_common=False)
+ self.assertEqual(len(objs), 4)
+
+ for o in objs:
+ self.assertIsInstance(o, DirectoryTraversal)
+ self.assertTrue(os.path.isabs(o.context_main_path))
+ self.assertEqual(len(o.context_all_paths), 1)
+
+ reldirs = [o.relsrcdir for o in objs]
+ self.assertEqual(reldirs, ["", "foo", "foo/biz", "bar"])
+
+ dirs = [[d.full_path for d in o.dirs] for o in objs]
+ self.assertEqual(
+ dirs,
+ [
+ [
+ mozpath.join(reader.config.topsrcdir, "foo"),
+ mozpath.join(reader.config.topsrcdir, "bar"),
+ ],
+ [mozpath.join(reader.config.topsrcdir, "foo", "biz")],
+ [],
+ [],
+ ],
+ )
+
+ def test_traversal_all_vars(self):
+ reader = self.reader("traversal-all-vars")
+ objs = self.read_topsrcdir(reader, filter_common=False)
+ self.assertEqual(len(objs), 2)
+
+ for o in objs:
+ self.assertIsInstance(o, DirectoryTraversal)
+
+ reldirs = set([o.relsrcdir for o in objs])
+ self.assertEqual(reldirs, set(["", "regular"]))
+
+ for o in objs:
+ reldir = o.relsrcdir
+
+ if reldir == "":
+ self.assertEqual(
+ [d.full_path for d in o.dirs],
+ [mozpath.join(reader.config.topsrcdir, "regular")],
+ )
+
+ def test_traversal_all_vars_enable_tests(self):
+ reader = self.reader("traversal-all-vars", enable_tests=True)
+ objs = self.read_topsrcdir(reader, filter_common=False)
+ self.assertEqual(len(objs), 3)
+
+ for o in objs:
+ self.assertIsInstance(o, DirectoryTraversal)
+
+ reldirs = set([o.relsrcdir for o in objs])
+ self.assertEqual(reldirs, set(["", "regular", "test"]))
+
+ for o in objs:
+ reldir = o.relsrcdir
+
+ if reldir == "":
+ self.assertEqual(
+ [d.full_path for d in o.dirs],
+ [
+ mozpath.join(reader.config.topsrcdir, "regular"),
+ mozpath.join(reader.config.topsrcdir, "test"),
+ ],
+ )
+
+ def test_config_file_substitution(self):
+ reader = self.reader("config-file-substitution")
+ objs = self.read_topsrcdir(reader)
+ self.assertEqual(len(objs), 2)
+
+ self.assertIsInstance(objs[0], ConfigFileSubstitution)
+ self.assertIsInstance(objs[1], ConfigFileSubstitution)
+
+ topobjdir = mozpath.abspath(reader.config.topobjdir)
+ self.assertEqual(objs[0].relpath, "foo")
+ self.assertEqual(
+ mozpath.normpath(objs[0].output_path),
+ mozpath.normpath(mozpath.join(topobjdir, "foo")),
+ )
+ self.assertEqual(
+ mozpath.normpath(objs[1].output_path),
+ mozpath.normpath(mozpath.join(topobjdir, "bar")),
+ )
+
+ def test_variable_passthru(self):
+ reader = self.reader("variable-passthru")
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 1)
+ self.assertIsInstance(objs[0], VariablePassthru)
+
+ wanted = {
+ "NO_DIST_INSTALL": True,
+ "RCFILE": "foo.rc",
+ "RCINCLUDE": "bar.rc",
+ "WIN32_EXE_LDFLAGS": ["-subsystem:console"],
+ }
+
+ variables = objs[0].variables
+ maxDiff = self.maxDiff
+ self.maxDiff = None
+ self.assertEqual(wanted, variables)
+ self.maxDiff = maxDiff
+
+ def test_compile_flags(self):
+ reader = self.reader(
+ "compile-flags", extra_substs={"WARNINGS_AS_ERRORS": "-Werror"}
+ )
+ sources, ldflags, lib, flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertEqual(flags.flags["STL"], reader.config.substs["STL_FLAGS"])
+ self.assertEqual(
+ flags.flags["VISIBILITY"], reader.config.substs["VISIBILITY_FLAGS"]
+ )
+ self.assertEqual(flags.flags["WARNINGS_AS_ERRORS"], ["-Werror"])
+ self.assertEqual(flags.flags["MOZBUILD_CFLAGS"], ["-Wall", "-funroll-loops"])
+ self.assertEqual(flags.flags["MOZBUILD_CXXFLAGS"], ["-funroll-loops", "-Wall"])
+
+ def test_asflags(self):
+ reader = self.reader("asflags", extra_substs={"ASFLAGS": ["-safeseh"]})
+ as_sources, sources, ldflags, lib, flags, asflags = self.read_topsrcdir(reader)
+ self.assertIsInstance(asflags, ComputedFlags)
+ self.assertEqual(asflags.flags["OS"], reader.config.substs["ASFLAGS"])
+ self.assertEqual(asflags.flags["MOZBUILD"], ["-no-integrated-as"])
+
+ def test_debug_flags(self):
+ reader = self.reader(
+ "compile-flags",
+ extra_substs={"MOZ_DEBUG_FLAGS": "-g", "MOZ_DEBUG_SYMBOLS": "1"},
+ )
+ sources, ldflags, lib, flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertEqual(flags.flags["DEBUG"], ["-g"])
+
+ def test_disable_debug_flags(self):
+ reader = self.reader(
+ "compile-flags",
+ extra_substs={"MOZ_DEBUG_FLAGS": "-g", "MOZ_DEBUG_SYMBOLS": ""},
+ )
+ sources, ldflags, lib, flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertEqual(flags.flags["DEBUG"], [])
+
+ def test_link_flags(self):
+ reader = self.reader(
+ "link-flags",
+ extra_substs={
+ "OS_LDFLAGS": ["-Wl,rpath-link=/usr/lib"],
+ "MOZ_OPTIMIZE": "",
+ "MOZ_OPTIMIZE_LDFLAGS": ["-Wl,-dead_strip"],
+ "MOZ_DEBUG_LDFLAGS": ["-framework ExceptionHandling"],
+ },
+ )
+ sources, ldflags, lib, compile_flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(ldflags, ComputedFlags)
+ self.assertEqual(ldflags.flags["OS"], reader.config.substs["OS_LDFLAGS"])
+ self.assertEqual(
+ ldflags.flags["MOZBUILD"], ["-Wl,-U_foo", "-framework Foo", "-x"]
+ )
+ self.assertEqual(ldflags.flags["OPTIMIZE"], [])
+
+ def test_debug_ldflags(self):
+ reader = self.reader(
+ "link-flags",
+ extra_substs={
+ "MOZ_DEBUG_SYMBOLS": "1",
+ "MOZ_DEBUG_LDFLAGS": ["-framework ExceptionHandling"],
+ },
+ )
+ sources, ldflags, lib, compile_flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(ldflags, ComputedFlags)
+ self.assertEqual(ldflags.flags["OS"], reader.config.substs["MOZ_DEBUG_LDFLAGS"])
+
+ def test_windows_opt_link_flags(self):
+ reader = self.reader(
+ "link-flags",
+ extra_substs={
+ "OS_ARCH": "WINNT",
+ "GNU_CC": "",
+ "MOZ_OPTIMIZE": "1",
+ "MOZ_DEBUG_LDFLAGS": ["-DEBUG"],
+ "MOZ_DEBUG_SYMBOLS": "1",
+ "MOZ_OPTIMIZE_FLAGS": [],
+ "MOZ_OPTIMIZE_LDFLAGS": [],
+ },
+ )
+ sources, ldflags, lib, compile_flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(ldflags, ComputedFlags)
+ self.assertIn("-DEBUG", ldflags.flags["OS"])
+ self.assertIn("-OPT:REF,ICF", ldflags.flags["OS"])
+
+ def test_windows_dmd_link_flags(self):
+ reader = self.reader(
+ "link-flags",
+ extra_substs={
+ "OS_ARCH": "WINNT",
+ "GNU_CC": "",
+ "MOZ_DMD": "1",
+ "MOZ_DEBUG_LDFLAGS": ["-DEBUG"],
+ "MOZ_DEBUG_SYMBOLS": "1",
+ "MOZ_OPTIMIZE": "1",
+ "MOZ_OPTIMIZE_FLAGS": [],
+ },
+ )
+ sources, ldflags, lib, compile_flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(ldflags, ComputedFlags)
+ self.assertEqual(ldflags.flags["OS"], ["-DEBUG", "-OPT:REF,ICF"])
+
+ def test_host_compile_flags(self):
+ reader = self.reader(
+ "host-compile-flags",
+ extra_substs={
+ "HOST_CXXFLAGS": ["-Wall", "-Werror"],
+ "HOST_CFLAGS": ["-Werror", "-Wall"],
+ },
+ )
+ sources, ldflags, flags, lib, target_flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertEqual(
+ flags.flags["HOST_CXXFLAGS"], reader.config.substs["HOST_CXXFLAGS"]
+ )
+ self.assertEqual(
+ flags.flags["HOST_CFLAGS"], reader.config.substs["HOST_CFLAGS"]
+ )
+ self.assertEqual(
+ set(flags.flags["HOST_DEFINES"]),
+ set(["-DFOO", '-DBAZ="abcd"', "-UQUX", "-DBAR=7", "-DVALUE=xyz"]),
+ )
+ self.assertEqual(
+ flags.flags["MOZBUILD_HOST_CFLAGS"], ["-funroll-loops", "-host-arg"]
+ )
+ self.assertEqual(flags.flags["MOZBUILD_HOST_CXXFLAGS"], [])
+
+ def test_host_no_optimize_flags(self):
+ reader = self.reader(
+ "host-compile-flags",
+ extra_substs={"MOZ_OPTIMIZE": "", "MOZ_OPTIMIZE_FLAGS": ["-O2"]},
+ )
+ sources, ldflags, flags, lib, target_flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertEqual(flags.flags["HOST_OPTIMIZE"], [])
+
+ def test_host_optimize_flags(self):
+ reader = self.reader(
+ "host-compile-flags",
+ extra_substs={"MOZ_OPTIMIZE": "1", "MOZ_OPTIMIZE_FLAGS": ["-O2"]},
+ )
+ sources, ldflags, flags, lib, target_flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertEqual(flags.flags["HOST_OPTIMIZE"], ["-O2"])
+
+ def test_cross_optimize_flags(self):
+ reader = self.reader(
+ "host-compile-flags",
+ extra_substs={
+ "MOZ_OPTIMIZE": "1",
+ "MOZ_OPTIMIZE_FLAGS": ["-O2"],
+ "HOST_OPTIMIZE_FLAGS": ["-O3"],
+ "CROSS_COMPILE": "1",
+ },
+ )
+ sources, ldflags, flags, lib, target_flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertEqual(flags.flags["HOST_OPTIMIZE"], ["-O3"])
+
+ def test_host_rtl_flag(self):
+ reader = self.reader(
+ "host-compile-flags", extra_substs={"OS_ARCH": "WINNT", "MOZ_DEBUG": "1"}
+ )
+ sources, ldflags, flags, lib, target_flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertEqual(flags.flags["RTL"], ["-MDd"])
+
+ def test_compile_flags_validation(self):
+ reader = self.reader("compile-flags-field-validation")
+
+ with six.assertRaisesRegex(self, BuildReaderError, "Invalid value."):
+ self.read_topsrcdir(reader)
+
+ reader = self.reader("compile-flags-type-validation")
+ with six.assertRaisesRegex(
+ self, BuildReaderError, "A list of strings must be provided"
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_compile_flags_templates(self):
+ reader = self.reader(
+ "compile-flags-templates",
+ extra_substs={
+ "NSPR_CFLAGS": ["-I/nspr/path"],
+ "NSS_CFLAGS": ["-I/nss/path"],
+ "MOZ_JPEG_CFLAGS": ["-I/jpeg/path"],
+ "MOZ_PNG_CFLAGS": ["-I/png/path"],
+ "MOZ_ZLIB_CFLAGS": ["-I/zlib/path"],
+ "MOZ_PIXMAN_CFLAGS": ["-I/pixman/path"],
+ },
+ )
+ sources, ldflags, lib, flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertEqual(flags.flags["STL"], [])
+ self.assertEqual(flags.flags["VISIBILITY"], [])
+ self.assertEqual(
+ flags.flags["OS_INCLUDES"],
+ [
+ "-I/nspr/path",
+ "-I/nss/path",
+ "-I/jpeg/path",
+ "-I/png/path",
+ "-I/zlib/path",
+ "-I/pixman/path",
+ ],
+ )
+
+ def test_disable_stl_wrapping(self):
+ reader = self.reader("disable-stl-wrapping")
+ sources, ldflags, lib, flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertEqual(flags.flags["STL"], [])
+
+ def test_visibility_flags(self):
+ reader = self.reader("visibility-flags")
+ sources, ldflags, lib, flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertEqual(flags.flags["VISIBILITY"], [])
+
+ def test_defines_in_flags(self):
+ reader = self.reader("compile-defines")
+ defines, sources, ldflags, lib, flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertEqual(
+ flags.flags["LIBRARY_DEFINES"], ["-DMOZ_LIBRARY_DEFINE=MOZ_TEST"]
+ )
+ self.assertEqual(flags.flags["DEFINES"], ["-DMOZ_TEST_DEFINE"])
+
+ def test_resolved_flags_error(self):
+ reader = self.reader("resolved-flags-error")
+ with six.assertRaisesRegex(
+ self,
+ BuildReaderError,
+ "`DEFINES` may not be set in COMPILE_FLAGS from moz.build",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_includes_in_flags(self):
+ reader = self.reader("compile-includes")
+ defines, sources, ldflags, lib, flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertEqual(
+ flags.flags["BASE_INCLUDES"],
+ ["-I%s" % reader.config.topsrcdir, "-I%s" % reader.config.topobjdir],
+ )
+ self.assertEqual(
+ flags.flags["EXTRA_INCLUDES"],
+ ["-I%s/dist/include" % reader.config.topobjdir],
+ )
+ self.assertEqual(
+ flags.flags["LOCAL_INCLUDES"], ["-I%s/subdir" % reader.config.topsrcdir]
+ )
+
+ def test_allow_compiler_warnings(self):
+ reader = self.reader(
+ "allow-compiler-warnings", extra_substs={"WARNINGS_AS_ERRORS": "-Werror"}
+ )
+ sources, ldflags, lib, flags = self.read_topsrcdir(reader)
+ self.assertEqual(flags.flags["WARNINGS_AS_ERRORS"], [])
+
+ def test_disable_compiler_warnings(self):
+ reader = self.reader(
+ "disable-compiler-warnings", extra_substs={"WARNINGS_CFLAGS": "-Wall"}
+ )
+ sources, ldflags, lib, flags = self.read_topsrcdir(reader)
+ self.assertEqual(flags.flags["WARNINGS_CFLAGS"], [])
+
+ def test_use_nasm(self):
+ # When nasm is not available, this should raise.
+ reader = self.reader("use-nasm")
+ with six.assertRaisesRegex(
+ self, SandboxValidationError, "nasm is not available"
+ ):
+ self.read_topsrcdir(reader)
+
+ # When nasm is available, this should work.
+ reader = self.reader(
+ "use-nasm", extra_substs=dict(NASM="nasm", NASM_ASFLAGS="-foo")
+ )
+
+ sources, passthru, ldflags, lib, flags, asflags = self.read_topsrcdir(reader)
+
+ self.assertIsInstance(passthru, VariablePassthru)
+ self.assertIsInstance(ldflags, ComputedFlags)
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertIsInstance(asflags, ComputedFlags)
+
+ self.assertEqual(asflags.flags["OS"], reader.config.substs["NASM_ASFLAGS"])
+
+ maxDiff = self.maxDiff
+ self.maxDiff = None
+ self.assertEqual(
+ passthru.variables,
+ {"AS": "nasm", "AS_DASH_C_FLAG": "", "ASOUTOPTION": "-o "},
+ )
+ self.maxDiff = maxDiff
+
+ def test_generated_files(self):
+ reader = self.reader("generated-files")
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 3)
+ for o in objs:
+ self.assertIsInstance(o, GeneratedFile)
+ self.assertFalse(o.localized)
+ self.assertFalse(o.force)
+
+ expected = ["bar.c", "foo.c", ("xpidllex.py", "xpidlyacc.py")]
+ for o, f in zip(objs, expected):
+ expected_filename = f if isinstance(f, tuple) else (f,)
+ self.assertEqual(o.outputs, expected_filename)
+ self.assertEqual(o.script, None)
+ self.assertEqual(o.method, None)
+ self.assertEqual(o.inputs, [])
+
+ def test_generated_files_force(self):
+ reader = self.reader("generated-files-force")
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 3)
+ for o in objs:
+ self.assertIsInstance(o, GeneratedFile)
+ self.assertEqual(o.force, "bar.c" in o.outputs)
+
+ def test_localized_generated_files(self):
+ reader = self.reader("localized-generated-files")
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 2)
+ for o in objs:
+ self.assertIsInstance(o, GeneratedFile)
+ self.assertTrue(o.localized)
+
+ expected = ["abc.ini", ("bar", "baz")]
+ for o, f in zip(objs, expected):
+ expected_filename = f if isinstance(f, tuple) else (f,)
+ self.assertEqual(o.outputs, expected_filename)
+ self.assertEqual(o.script, None)
+ self.assertEqual(o.method, None)
+ self.assertEqual(o.inputs, [])
+
+ def test_localized_generated_files_force(self):
+ reader = self.reader("localized-generated-files-force")
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 2)
+ for o in objs:
+ self.assertIsInstance(o, GeneratedFile)
+ self.assertTrue(o.localized)
+ self.assertEqual(o.force, "abc.ini" in o.outputs)
+
+ def test_localized_files_from_generated(self):
+ """Test that using LOCALIZED_GENERATED_FILES and then putting the output in
+ LOCALIZED_FILES as an objdir path works.
+ """
+ reader = self.reader("localized-files-from-generated")
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 2)
+ self.assertIsInstance(objs[0], GeneratedFile)
+ self.assertIsInstance(objs[1], LocalizedFiles)
+
+ def test_localized_files_not_localized_generated(self):
+ """Test that using GENERATED_FILES and then putting the output in
+ LOCALIZED_FILES as an objdir path produces an error.
+ """
+ reader = self.reader("localized-files-not-localized-generated")
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "Objdir file listed in LOCALIZED_FILES not in LOCALIZED_GENERATED_FILES:",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_localized_generated_files_final_target_files(self):
+ """Test that using LOCALIZED_GENERATED_FILES and then putting the output in
+ FINAL_TARGET_FILES as an objdir path produces an error.
+ """
+ reader = self.reader("localized-generated-files-final-target-files")
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "Outputs of LOCALIZED_GENERATED_FILES cannot be used in FINAL_TARGET_FILES:",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_generated_files_method_names(self):
+ reader = self.reader("generated-files-method-names")
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 2)
+ for o in objs:
+ self.assertIsInstance(o, GeneratedFile)
+
+ expected = ["bar.c", "foo.c"]
+ expected_method_names = ["make_bar", "main"]
+ for o, expected_filename, expected_method in zip(
+ objs, expected, expected_method_names
+ ):
+ self.assertEqual(o.outputs, (expected_filename,))
+ self.assertEqual(o.method, expected_method)
+ self.assertEqual(o.inputs, [])
+
+ def test_generated_files_absolute_script(self):
+ reader = self.reader("generated-files-absolute-script")
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 1)
+
+ o = objs[0]
+ self.assertIsInstance(o, GeneratedFile)
+ self.assertEqual(o.outputs, ("bar.c",))
+ self.assertRegex(o.script, "script.py$")
+ self.assertEqual(o.method, "make_bar")
+ self.assertEqual(o.inputs, [])
+
+ def test_generated_files_no_script(self):
+ reader = self.reader("generated-files-no-script")
+ with six.assertRaisesRegex(
+ self, SandboxValidationError, "Script for generating bar.c does not exist"
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_generated_files_no_inputs(self):
+ reader = self.reader("generated-files-no-inputs")
+ with six.assertRaisesRegex(
+ self, SandboxValidationError, "Input for generating foo.c does not exist"
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_generated_files_no_python_script(self):
+ reader = self.reader("generated-files-no-python-script")
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "Script for generating bar.c does not end in .py",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_exports(self):
+ reader = self.reader("exports")
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 1)
+ self.assertIsInstance(objs[0], Exports)
+
+ expected = [
+ ("", ["foo.h", "bar.h", "baz.h"]),
+ ("mozilla", ["mozilla1.h", "mozilla2.h"]),
+ ("mozilla/dom", ["dom1.h", "dom2.h", "dom3.h"]),
+ ("mozilla/gfx", ["gfx.h"]),
+ ("nspr/private", ["pprio.h", "pprthred.h"]),
+ ("vpx", ["mem.h", "mem2.h"]),
+ ]
+ for (expect_path, expect_headers), (actual_path, actual_headers) in zip(
+ expected, [(path, list(seq)) for path, seq in objs[0].files.walk()]
+ ):
+ self.assertEqual(expect_path, actual_path)
+ self.assertEqual(expect_headers, actual_headers)
+
+ def test_exports_missing(self):
+ """
+ Missing files in EXPORTS is an error.
+ """
+ reader = self.reader("exports-missing")
+ with six.assertRaisesRegex(
+ self, SandboxValidationError, "File listed in EXPORTS does not exist:"
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_exports_missing_generated(self):
+ """
+ An objdir file in EXPORTS that is not in GENERATED_FILES is an error.
+ """
+ reader = self.reader("exports-missing-generated")
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "Objdir file listed in EXPORTS not in GENERATED_FILES:",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_exports_generated(self):
+ reader = self.reader("exports-generated")
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 2)
+ self.assertIsInstance(objs[0], GeneratedFile)
+ self.assertIsInstance(objs[1], Exports)
+ exports = [(path, list(seq)) for path, seq in objs[1].files.walk()]
+ self.assertEqual(
+ exports, [("", ["foo.h"]), ("mozilla", ["mozilla1.h", "!mozilla2.h"])]
+ )
+ path, files = exports[1]
+ self.assertIsInstance(files[1], ObjDirPath)
+
+ def test_test_harness_files(self):
+ reader = self.reader("test-harness-files")
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 1)
+ self.assertIsInstance(objs[0], TestHarnessFiles)
+
+ expected = {
+ "mochitest": ["runtests.py", "utils.py"],
+ "testing/mochitest": ["mochitest.py", "mochitest.ini"],
+ }
+
+ for path, strings in objs[0].files.walk():
+ self.assertTrue(path in expected)
+ basenames = sorted(mozpath.basename(s) for s in strings)
+ self.assertEqual(sorted(expected[path]), basenames)
+
+ def test_test_harness_files_root(self):
+ reader = self.reader("test-harness-files-root")
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "Cannot install files to the root of TEST_HARNESS_FILES",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_program(self):
+ reader = self.reader("program")
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 6)
+ self.assertIsInstance(objs[0], Sources)
+ self.assertIsInstance(objs[1], ComputedFlags)
+ self.assertIsInstance(objs[2], ComputedFlags)
+ self.assertIsInstance(objs[3], Program)
+ self.assertIsInstance(objs[4], SimpleProgram)
+ self.assertIsInstance(objs[5], SimpleProgram)
+
+ self.assertEqual(objs[3].program, "test_program.prog")
+ self.assertEqual(objs[4].program, "test_program1.prog")
+ self.assertEqual(objs[5].program, "test_program2.prog")
+
+ self.assertEqual(objs[3].name, "test_program.prog")
+ self.assertEqual(objs[4].name, "test_program1.prog")
+ self.assertEqual(objs[5].name, "test_program2.prog")
+
+ self.assertEqual(
+ objs[4].objs,
+ [
+ mozpath.join(
+ reader.config.topobjdir,
+ "test_program1.%s" % reader.config.substs["OBJ_SUFFIX"],
+ )
+ ],
+ )
+ self.assertEqual(
+ objs[5].objs,
+ [
+ mozpath.join(
+ reader.config.topobjdir,
+ "test_program2.%s" % reader.config.substs["OBJ_SUFFIX"],
+ )
+ ],
+ )
+
+ def test_program_paths(self):
+ """Various moz.build settings that change the destination of PROGRAM should be
+ accurately reflected in Program.output_path."""
+ reader = self.reader("program-paths")
+ objs = self.read_topsrcdir(reader)
+ prog_paths = [o.output_path for o in objs if isinstance(o, Program)]
+ self.assertEqual(
+ prog_paths,
+ [
+ "!/dist/bin/dist-bin.prog",
+ "!/dist/bin/foo/dist-subdir.prog",
+ "!/final/target/final-target.prog",
+ "!not-installed.prog",
+ ],
+ )
+
+ def test_host_program_paths(self):
+ """The destination of a HOST_PROGRAM (almost always dist/host/bin)
+ should be accurately reflected in Program.output_path."""
+ reader = self.reader("host-program-paths")
+ objs = self.read_topsrcdir(reader)
+ prog_paths = [o.output_path for o in objs if isinstance(o, HostProgram)]
+ self.assertEqual(
+ prog_paths,
+ [
+ "!/dist/host/bin/final-target.hostprog",
+ "!/dist/host/bin/dist-host-bin.hostprog",
+ "!not-installed.hostprog",
+ ],
+ )
+
+ def test_test_manifest_missing_manifest(self):
+ """A missing manifest file should result in an error."""
+ reader = self.reader("test-manifest-missing-manifest")
+
+ with six.assertRaisesRegex(self, BuildReaderError, "Missing files"):
+ self.read_topsrcdir(reader)
+
+ def test_empty_test_manifest_rejected(self):
+ """A test manifest without any entries is rejected."""
+ reader = self.reader("test-manifest-empty")
+
+ with six.assertRaisesRegex(self, SandboxValidationError, "Empty test manifest"):
+ self.read_topsrcdir(reader)
+
+ def test_test_manifest_just_support_files(self):
+ """A test manifest with no tests but support-files is not supported."""
+ reader = self.reader("test-manifest-just-support")
+
+ with six.assertRaisesRegex(self, SandboxValidationError, "Empty test manifest"):
+ self.read_topsrcdir(reader)
+
+ def test_test_manifest_dupe_support_files(self):
+ """A test manifest with dupe support-files in a single test is not
+ supported.
+ """
+ reader = self.reader("test-manifest-dupes")
+
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "bar.js appears multiple times "
+ "in a test manifest under a support-files field, please omit the duplicate entry.",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_test_manifest_absolute_support_files(self):
+ """Support files starting with '/' are placed relative to the install root"""
+ reader = self.reader("test-manifest-absolute-support")
+
+ objs = self.read_topsrcdir(reader)
+ self.assertEqual(len(objs), 1)
+ o = objs[0]
+ self.assertEqual(len(o.installs), 3)
+ expected = [
+ mozpath.normpath(mozpath.join(o.install_prefix, "../.well-known/foo.txt")),
+ mozpath.join(o.install_prefix, "absolute-support.ini"),
+ mozpath.join(o.install_prefix, "test_file.js"),
+ ]
+ paths = sorted([v[0] for v in o.installs.values()])
+ self.assertEqual(paths, expected)
+
+ @unittest.skip("Bug 1304316 - Items in the second set but not the first")
+ def test_test_manifest_shared_support_files(self):
+ """Support files starting with '!' are given separate treatment, so their
+ installation can be resolved when running tests.
+ """
+ reader = self.reader("test-manifest-shared-support")
+ supported, child = self.read_topsrcdir(reader)
+
+ expected_deferred_installs = {
+ "!/child/test_sub.js",
+ "!/child/another-file.sjs",
+ "!/child/data/**",
+ }
+
+ self.assertEqual(len(supported.installs), 3)
+ self.assertEqual(set(supported.deferred_installs), expected_deferred_installs)
+ self.assertEqual(len(child.installs), 3)
+ self.assertEqual(len(child.pattern_installs), 1)
+
+ def test_test_manifest_deffered_install_missing(self):
+ """A non-existent shared support file reference produces an error."""
+ reader = self.reader("test-manifest-shared-missing")
+
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "entry in support-files not present in the srcdir",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_test_manifest_install_includes(self):
+ """Ensure that any [include:foo.ini] are copied to the objdir."""
+ reader = self.reader("test-manifest-install-includes")
+
+ objs = self.read_topsrcdir(reader)
+ self.assertEqual(len(objs), 1)
+ o = objs[0]
+ self.assertEqual(len(o.installs), 3)
+ self.assertEqual(o.manifest_relpath, "mochitest.ini")
+ self.assertEqual(o.manifest_obj_relpath, "mochitest.ini")
+ expected = [
+ mozpath.normpath(mozpath.join(o.install_prefix, "common.ini")),
+ mozpath.normpath(mozpath.join(o.install_prefix, "mochitest.ini")),
+ mozpath.normpath(mozpath.join(o.install_prefix, "test_foo.html")),
+ ]
+ paths = sorted([v[0] for v in o.installs.values()])
+ self.assertEqual(paths, expected)
+
+ def test_test_manifest_includes(self):
+ """Ensure that manifest objects from the emitter list a correct manifest."""
+ reader = self.reader("test-manifest-emitted-includes")
+ [obj] = self.read_topsrcdir(reader)
+
+ # Expected manifest leafs for our tests.
+ expected_manifests = {
+ "reftest1.html": "reftest.list",
+ "reftest1-ref.html": "reftest.list",
+ "reftest2.html": "included-reftest.list",
+ "reftest2-ref.html": "included-reftest.list",
+ }
+
+ for t in obj.tests:
+ self.assertTrue(t["manifest"].endswith(expected_manifests[t["name"]]))
+
+ def test_test_manifest_keys_extracted(self):
+ """Ensure all metadata from test manifests is extracted."""
+ reader = self.reader("test-manifest-keys-extracted")
+
+ objs = [o for o in self.read_topsrcdir(reader) if isinstance(o, TestManifest)]
+
+ self.assertEqual(len(objs), 8)
+
+ metadata = {
+ "a11y.ini": {
+ "flavor": "a11y",
+ "installs": {"a11y.ini": False, "test_a11y.js": True},
+ "pattern-installs": 1,
+ },
+ "browser.ini": {
+ "flavor": "browser-chrome",
+ "installs": {
+ "browser.ini": False,
+ "test_browser.js": True,
+ "support1": False,
+ "support2": False,
+ },
+ },
+ "mochitest.ini": {
+ "flavor": "mochitest",
+ "installs": {"mochitest.ini": False, "test_mochitest.js": True},
+ "external": {"external1", "external2"},
+ },
+ "chrome.ini": {
+ "flavor": "chrome",
+ "installs": {"chrome.ini": False, "test_chrome.js": True},
+ },
+ "xpcshell.ini": {
+ "flavor": "xpcshell",
+ "dupe": True,
+ "installs": {
+ "xpcshell.ini": False,
+ "test_xpcshell.js": True,
+ "head1": False,
+ "head2": False,
+ },
+ },
+ "reftest.list": {"flavor": "reftest", "installs": {}},
+ "crashtest.list": {"flavor": "crashtest", "installs": {}},
+ "python.ini": {"flavor": "python", "installs": {"python.ini": False}},
+ }
+
+ for o in objs:
+ m = metadata[mozpath.basename(o.manifest_relpath)]
+
+ self.assertTrue(o.path.startswith(o.directory))
+ self.assertEqual(o.flavor, m["flavor"])
+ self.assertEqual(o.dupe_manifest, m.get("dupe", False))
+
+ external_normalized = set(mozpath.basename(p) for p in o.external_installs)
+ self.assertEqual(external_normalized, m.get("external", set()))
+
+ self.assertEqual(len(o.installs), len(m["installs"]))
+ for path in o.installs.keys():
+ self.assertTrue(path.startswith(o.directory))
+ relpath = path[len(o.directory) + 1 :]
+
+ self.assertIn(relpath, m["installs"])
+ self.assertEqual(o.installs[path][1], m["installs"][relpath])
+
+ if "pattern-installs" in m:
+ self.assertEqual(len(o.pattern_installs), m["pattern-installs"])
+
+ def test_test_manifest_unmatched_generated(self):
+ reader = self.reader("test-manifest-unmatched-generated")
+
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "entry in generated-files not present elsewhere",
+ ):
+ self.read_topsrcdir(reader),
+
+ def test_test_manifest_parent_support_files_dir(self):
+ """support-files referencing a file in a parent directory works."""
+ reader = self.reader("test-manifest-parent-support-files-dir")
+
+ objs = [o for o in self.read_topsrcdir(reader) if isinstance(o, TestManifest)]
+
+ self.assertEqual(len(objs), 1)
+
+ o = objs[0]
+
+ expected = mozpath.join(o.srcdir, "support-file.txt")
+ self.assertIn(expected, o.installs)
+ self.assertEqual(
+ o.installs[expected],
+ ("testing/mochitest/tests/child/support-file.txt", False),
+ )
+
+ def test_test_manifest_missing_test_error(self):
+ """Missing test files should result in error."""
+ reader = self.reader("test-manifest-missing-test-file")
+
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "lists test that does not exist: test_missing.html",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_test_manifest_missing_test_error_unfiltered(self):
+ """Missing test files should result in error, even when the test list is not filtered."""
+ reader = self.reader("test-manifest-missing-test-file-unfiltered")
+
+ with six.assertRaisesRegex(
+ self, SandboxValidationError, "lists test that does not exist: missing.js"
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_ipdl_sources(self):
+ reader = self.reader(
+ "ipdl_sources",
+ extra_substs={"IPDL_ROOT": mozpath.abspath("/path/to/topobjdir")},
+ )
+ objs = self.read_topsrcdir(reader)
+ ipdl_collection = objs[0]
+ self.assertIsInstance(ipdl_collection, IPDLCollection)
+
+ ipdls = set(
+ mozpath.relpath(p, ipdl_collection.topsrcdir)
+ for p in ipdl_collection.all_regular_sources()
+ )
+ expected = set(
+ ["bar/bar.ipdl", "bar/bar2.ipdlh", "foo/foo.ipdl", "foo/foo2.ipdlh"]
+ )
+
+ self.assertEqual(ipdls, expected)
+
+ pp_ipdls = set(
+ mozpath.relpath(p, ipdl_collection.topsrcdir)
+ for p in ipdl_collection.all_preprocessed_sources()
+ )
+ expected = set(["bar/bar1.ipdl", "foo/foo1.ipdl"])
+ self.assertEqual(pp_ipdls, expected)
+
+ def test_local_includes(self):
+ """Test that LOCAL_INCLUDES is emitted correctly."""
+ reader = self.reader("local_includes")
+ objs = self.read_topsrcdir(reader)
+
+ local_includes = [o.path for o in objs if isinstance(o, LocalInclude)]
+ expected = ["/bar/baz", "foo"]
+
+ self.assertEqual(local_includes, expected)
+
+ local_includes = [o.path.full_path for o in objs if isinstance(o, LocalInclude)]
+ expected = [
+ mozpath.join(reader.config.topsrcdir, "bar/baz"),
+ mozpath.join(reader.config.topsrcdir, "foo"),
+ ]
+
+ self.assertEqual(local_includes, expected)
+
+ def test_local_includes_invalid(self):
+ """Test that invalid LOCAL_INCLUDES are properly detected."""
+ reader = self.reader("local_includes-invalid/srcdir")
+
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "Path specified in LOCAL_INCLUDES.*resolves to the "
+ "topsrcdir or topobjdir",
+ ):
+ self.read_topsrcdir(reader)
+
+ reader = self.reader("local_includes-invalid/objdir")
+
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "Path specified in LOCAL_INCLUDES.*resolves to the "
+ "topsrcdir or topobjdir",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_local_includes_file(self):
+ """Test that a filename can't be used in LOCAL_INCLUDES."""
+ reader = self.reader("local_includes-filename")
+
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "Path specified in LOCAL_INCLUDES is a filename",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_generated_includes(self):
+ """Test that GENERATED_INCLUDES is emitted correctly."""
+ reader = self.reader("generated_includes")
+ objs = self.read_topsrcdir(reader)
+
+ generated_includes = [o.path for o in objs if isinstance(o, LocalInclude)]
+ expected = ["!/bar/baz", "!foo"]
+
+ self.assertEqual(generated_includes, expected)
+
+ generated_includes = [
+ o.path.full_path for o in objs if isinstance(o, LocalInclude)
+ ]
+ expected = [
+ mozpath.join(reader.config.topobjdir, "bar/baz"),
+ mozpath.join(reader.config.topobjdir, "foo"),
+ ]
+
+ self.assertEqual(generated_includes, expected)
+
+ def test_defines(self):
+ reader = self.reader("defines")
+ objs = self.read_topsrcdir(reader)
+
+ defines = {}
+ for o in objs:
+ if isinstance(o, Defines):
+ defines = o.defines
+
+ expected = {
+ "BAR": 7,
+ "BAZ": '"abcd"',
+ "FOO": True,
+ "VALUE": "xyz",
+ "QUX": False,
+ }
+
+ self.assertEqual(defines, expected)
+
+ def test_jar_manifests(self):
+ reader = self.reader("jar-manifests")
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 1)
+ for obj in objs:
+ self.assertIsInstance(obj, JARManifest)
+ self.assertIsInstance(obj.path, Path)
+
+ def test_jar_manifests_multiple_files(self):
+ with six.assertRaisesRegex(
+ self, SandboxValidationError, "limited to one value"
+ ):
+ reader = self.reader("jar-manifests-multiple-files")
+ self.read_topsrcdir(reader)
+
+ def test_xpidl_module_no_sources(self):
+ """XPIDL_MODULE without XPIDL_SOURCES should be rejected."""
+ with six.assertRaisesRegex(
+ self, SandboxValidationError, "XPIDL_MODULE " "cannot be defined"
+ ):
+ reader = self.reader("xpidl-module-no-sources")
+ self.read_topsrcdir(reader)
+
+ def test_xpidl_module_missing_sources(self):
+ """Missing XPIDL_SOURCES should be rejected."""
+ with six.assertRaisesRegex(
+ self, SandboxValidationError, "File .* " "from XPIDL_SOURCES does not exist"
+ ):
+ reader = self.reader("missing-xpidl")
+ self.read_topsrcdir(reader)
+
+ def test_missing_local_includes(self):
+ """LOCAL_INCLUDES containing non-existent directories should be rejected."""
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "Path specified in " "LOCAL_INCLUDES does not exist",
+ ):
+ reader = self.reader("missing-local-includes")
+ self.read_topsrcdir(reader)
+
+ def test_library_defines(self):
+ """Test that LIBRARY_DEFINES is propagated properly."""
+ reader = self.reader("library-defines")
+ objs = self.read_topsrcdir(reader)
+
+ libraries = [o for o in objs if isinstance(o, StaticLibrary)]
+ library_flags = [
+ o
+ for o in objs
+ if isinstance(o, ComputedFlags) and "LIBRARY_DEFINES" in o.flags
+ ]
+ expected = {
+ "liba": "-DIN_LIBA",
+ "libb": "-DIN_LIBB -DIN_LIBA",
+ "libc": "-DIN_LIBA -DIN_LIBB",
+ "libd": "",
+ }
+ defines = {}
+ for lib in libraries:
+ defines[lib.basename] = " ".join(lib.lib_defines.get_defines())
+ self.assertEqual(expected, defines)
+ defines_in_flags = {}
+ for flags in library_flags:
+ defines_in_flags[flags.relobjdir] = " ".join(
+ flags.flags["LIBRARY_DEFINES"] or []
+ )
+ self.assertEqual(expected, defines_in_flags)
+
+ def test_sources(self):
+ """Test that SOURCES works properly."""
+ reader = self.reader("sources")
+ objs = self.read_topsrcdir(reader)
+
+ as_flags = objs.pop()
+ self.assertIsInstance(as_flags, ComputedFlags)
+ computed_flags = objs.pop()
+ self.assertIsInstance(computed_flags, ComputedFlags)
+ # The third to last object is a Linkable.
+ linkable = objs.pop()
+ self.assertTrue(linkable.cxx_link)
+ ld_flags = objs.pop()
+ self.assertIsInstance(ld_flags, ComputedFlags)
+ self.assertEqual(len(objs), 6)
+ for o in objs:
+ self.assertIsInstance(o, Sources)
+
+ suffix_map = {obj.canonical_suffix: obj for obj in objs}
+ self.assertEqual(len(suffix_map), 6)
+
+ expected = {
+ ".cpp": ["a.cpp", "b.cc", "c.cxx"],
+ ".c": ["d.c"],
+ ".m": ["e.m"],
+ ".mm": ["f.mm"],
+ ".S": ["g.S"],
+ ".s": ["h.s", "i.asm"],
+ }
+ for suffix, files in expected.items():
+ sources = suffix_map[suffix]
+ self.assertEqual(
+ sources.files, [mozpath.join(reader.config.topsrcdir, f) for f in files]
+ )
+
+ for f in files:
+ self.assertIn(
+ mozpath.join(
+ reader.config.topobjdir,
+ "%s.%s"
+ % (mozpath.splitext(f)[0], reader.config.substs["OBJ_SUFFIX"]),
+ ),
+ linkable.objs,
+ )
+
+ def test_sources_just_c(self):
+ """Test that a linkable with no C++ sources doesn't have cxx_link set."""
+ reader = self.reader("sources-just-c")
+ objs = self.read_topsrcdir(reader)
+
+ as_flags = objs.pop()
+ self.assertIsInstance(as_flags, ComputedFlags)
+ flags = objs.pop()
+ self.assertIsInstance(flags, ComputedFlags)
+ # The third to last object is a Linkable.
+ linkable = objs.pop()
+ self.assertFalse(linkable.cxx_link)
+
+ def test_linkables_cxx_link(self):
+ """Test that linkables transitively set cxx_link properly."""
+ reader = self.reader("test-linkables-cxx-link")
+ got_results = 0
+ for obj in self.read_topsrcdir(reader):
+ if isinstance(obj, SharedLibrary):
+ if obj.basename == "cxx_shared":
+ self.assertEqual(
+ obj.name,
+ "%scxx_shared%s"
+ % (reader.config.dll_prefix, reader.config.dll_suffix),
+ )
+ self.assertTrue(obj.cxx_link)
+ got_results += 1
+ elif obj.basename == "just_c_shared":
+ self.assertEqual(
+ obj.name,
+ "%sjust_c_shared%s"
+ % (reader.config.dll_prefix, reader.config.dll_suffix),
+ )
+ self.assertFalse(obj.cxx_link)
+ got_results += 1
+ self.assertEqual(got_results, 2)
+
+ def test_generated_sources(self):
+ """Test that GENERATED_SOURCES works properly."""
+ reader = self.reader("generated-sources")
+ objs = self.read_topsrcdir(reader)
+
+ as_flags = objs.pop()
+ self.assertIsInstance(as_flags, ComputedFlags)
+ flags = objs.pop()
+ self.assertIsInstance(flags, ComputedFlags)
+ # The third to last object is a Linkable.
+ linkable = objs.pop()
+ self.assertTrue(linkable.cxx_link)
+ flags = objs.pop()
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertEqual(len(objs), 6)
+
+ generated_sources = [
+ o for o in objs if isinstance(o, Sources) and o.generated_files
+ ]
+ self.assertEqual(len(generated_sources), 6)
+
+ suffix_map = {obj.canonical_suffix: obj for obj in generated_sources}
+ self.assertEqual(len(suffix_map), 6)
+
+ expected = {
+ ".cpp": ["a.cpp", "b.cc", "c.cxx"],
+ ".c": ["d.c"],
+ ".m": ["e.m"],
+ ".mm": ["f.mm"],
+ ".S": ["g.S"],
+ ".s": ["h.s", "i.asm"],
+ }
+ for suffix, files in expected.items():
+ sources = suffix_map[suffix]
+ self.assertEqual(
+ sources.generated_files,
+ [mozpath.join(reader.config.topobjdir, f) for f in files],
+ )
+
+ for f in files:
+ self.assertIn(
+ mozpath.join(
+ reader.config.topobjdir,
+ "%s.%s"
+ % (mozpath.splitext(f)[0], reader.config.substs["OBJ_SUFFIX"]),
+ ),
+ linkable.objs,
+ )
+
+ def test_host_sources(self):
+ """Test that HOST_SOURCES works properly."""
+ reader = self.reader("host-sources")
+ objs = self.read_topsrcdir(reader)
+
+ # This objdir will generate target flags.
+ flags = objs.pop()
+ self.assertIsInstance(flags, ComputedFlags)
+ # The second to last object is a Linkable
+ linkable = objs.pop()
+ self.assertTrue(linkable.cxx_link)
+ # This objdir will also generate host flags.
+ host_flags = objs.pop()
+ self.assertIsInstance(host_flags, ComputedFlags)
+ # ...and ldflags.
+ ldflags = objs.pop()
+ self.assertIsInstance(ldflags, ComputedFlags)
+ self.assertEqual(len(objs), 3)
+ for o in objs:
+ self.assertIsInstance(o, HostSources)
+
+ suffix_map = {obj.canonical_suffix: obj for obj in objs}
+ self.assertEqual(len(suffix_map), 3)
+
+ expected = {
+ ".cpp": ["a.cpp", "b.cc", "c.cxx"],
+ ".c": ["d.c"],
+ ".mm": ["e.mm", "f.mm"],
+ }
+ for suffix, files in expected.items():
+ sources = suffix_map[suffix]
+ self.assertEqual(
+ sources.files, [mozpath.join(reader.config.topsrcdir, f) for f in files]
+ )
+
+ for f in files:
+ self.assertIn(
+ mozpath.join(
+ reader.config.topobjdir,
+ "host_%s.%s"
+ % (mozpath.splitext(f)[0], reader.config.substs["OBJ_SUFFIX"]),
+ ),
+ linkable.objs,
+ )
+
+ def test_wasm_sources(self):
+ """Test that WASM_SOURCES works properly."""
+ reader = self.reader(
+ "wasm-sources", extra_substs={"WASM_CC": "clang", "WASM_CXX": "clang++"}
+ )
+ objs = list(self.read_topsrcdir(reader))
+
+ # The second to last object is a linkable.
+ linkable = objs[-2]
+ # Other than that, we only care about the WasmSources objects.
+ objs = objs[:2]
+ for o in objs:
+ self.assertIsInstance(o, WasmSources)
+
+ suffix_map = {obj.canonical_suffix: obj for obj in objs}
+ self.assertEqual(len(suffix_map), 2)
+
+ expected = {".cpp": ["a.cpp", "b.cc", "c.cxx"], ".c": ["d.c"]}
+ for suffix, files in expected.items():
+ sources = suffix_map[suffix]
+ self.assertEqual(
+ sources.files, [mozpath.join(reader.config.topsrcdir, f) for f in files]
+ )
+ for f in files:
+ self.assertIn(
+ mozpath.join(
+ reader.config.topobjdir,
+ "%s.%s"
+ % (
+ mozpath.splitext(f)[0],
+ reader.config.substs["WASM_OBJ_SUFFIX"],
+ ),
+ ),
+ linkable.objs,
+ )
+
+ def test_unified_sources(self):
+ """Test that UNIFIED_SOURCES works properly."""
+ reader = self.reader("unified-sources")
+ objs = self.read_topsrcdir(reader)
+
+ # The last object is a ComputedFlags, the second to last a Linkable,
+ # followed by ldflags, ignore them.
+ linkable = objs[-2]
+ objs = objs[:-3]
+ self.assertEqual(len(objs), 3)
+ for o in objs:
+ self.assertIsInstance(o, UnifiedSources)
+
+ suffix_map = {obj.canonical_suffix: obj for obj in objs}
+ self.assertEqual(len(suffix_map), 3)
+
+ expected = {
+ ".cpp": ["bar.cxx", "foo.cpp", "quux.cc"],
+ ".mm": ["objc1.mm", "objc2.mm"],
+ ".c": ["c1.c", "c2.c"],
+ }
+ for suffix, files in expected.items():
+ sources = suffix_map[suffix]
+ self.assertEqual(
+ sources.files, [mozpath.join(reader.config.topsrcdir, f) for f in files]
+ )
+
+ # Unified sources are not required
+ if sources.have_unified_mapping:
+
+ for f in dict(sources.unified_source_mapping).keys():
+ self.assertIn(
+ mozpath.join(
+ reader.config.topobjdir,
+ "%s.%s"
+ % (
+ mozpath.splitext(f)[0],
+ reader.config.substs["OBJ_SUFFIX"],
+ ),
+ ),
+ linkable.objs,
+ )
+
+ def test_unified_sources_non_unified(self):
+ """Test that UNIFIED_SOURCES with FILES_PER_UNIFIED_FILE=1 works properly."""
+ reader = self.reader("unified-sources-non-unified")
+ objs = self.read_topsrcdir(reader)
+
+ # The last object is a Linkable, the second to last ComputedFlags,
+ # followed by ldflags, ignore them.
+ objs = objs[:-3]
+ self.assertEqual(len(objs), 3)
+ for o in objs:
+ self.assertIsInstance(o, UnifiedSources)
+
+ suffix_map = {obj.canonical_suffix: obj for obj in objs}
+ self.assertEqual(len(suffix_map), 3)
+
+ expected = {
+ ".cpp": ["bar.cxx", "foo.cpp", "quux.cc"],
+ ".mm": ["objc1.mm", "objc2.mm"],
+ ".c": ["c1.c", "c2.c"],
+ }
+ for suffix, files in expected.items():
+ sources = suffix_map[suffix]
+ self.assertEqual(
+ sources.files, [mozpath.join(reader.config.topsrcdir, f) for f in files]
+ )
+ self.assertFalse(sources.have_unified_mapping)
+
+ def test_object_conflicts(self):
+ """Test that object name conflicts are detected."""
+ reader = self.reader("object-conflicts/1")
+ with self.assertRaisesRegex(
+ SandboxValidationError,
+ "Test.cpp from SOURCES would have the same object name as"
+ " Test.c from SOURCES\.",
+ ):
+ self.read_topsrcdir(reader)
+
+ reader = self.reader("object-conflicts/2")
+ with self.assertRaisesRegex(
+ SandboxValidationError,
+ "Test.cpp from SOURCES would have the same object name as"
+ " subdir/Test.cpp from SOURCES\.",
+ ):
+ self.read_topsrcdir(reader)
+
+ reader = self.reader("object-conflicts/3")
+ with self.assertRaisesRegex(
+ SandboxValidationError,
+ "Test.cpp from UNIFIED_SOURCES would have the same object name as"
+ " Test.c from SOURCES in non-unified builds\.",
+ ):
+ self.read_topsrcdir(reader)
+
+ reader = self.reader("object-conflicts/4")
+ with self.assertRaisesRegex(
+ SandboxValidationError,
+ "Test.cpp from UNIFIED_SOURCES would have the same object name as"
+ " Test.c from UNIFIED_SOURCES in non-unified builds\.",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_final_target_pp_files(self):
+ """Test that FINAL_TARGET_PP_FILES works properly."""
+ reader = self.reader("dist-files")
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 1)
+ self.assertIsInstance(objs[0], FinalTargetPreprocessedFiles)
+
+ # Ideally we'd test hierarchies, but that would just be testing
+ # the HierarchicalStringList class, which we test separately.
+ for path, files in objs[0].files.walk():
+ self.assertEqual(path, "")
+ self.assertEqual(len(files), 2)
+
+ expected = {"install.rdf", "main.js"}
+ for f in files:
+ self.assertTrue(six.text_type(f) in expected)
+
+ def test_missing_final_target_pp_files(self):
+ """Test that FINAL_TARGET_PP_FILES with missing files throws errors."""
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "File listed in " "FINAL_TARGET_PP_FILES does not exist",
+ ):
+ reader = self.reader("dist-files-missing")
+ self.read_topsrcdir(reader)
+
+ def test_final_target_pp_files_non_srcdir(self):
+ """Test that non-srcdir paths in FINAL_TARGET_PP_FILES throws errors."""
+ reader = self.reader("final-target-pp-files-non-srcdir")
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "Only source directory paths allowed in FINAL_TARGET_PP_FILES:",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_localized_files(self):
+ """Test that LOCALIZED_FILES works properly."""
+ reader = self.reader("localized-files")
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 1)
+ self.assertIsInstance(objs[0], LocalizedFiles)
+
+ for path, files in objs[0].files.walk():
+ self.assertEqual(path, "foo")
+ self.assertEqual(len(files), 3)
+
+ expected = {"en-US/bar.ini", "en-US/code/*.js", "en-US/foo.js"}
+ for f in files:
+ self.assertTrue(six.text_type(f) in expected)
+
+ def test_localized_files_no_en_us(self):
+ """Test that LOCALIZED_FILES errors if a path does not start with
+ `en-US/` or contain `locales/en-US/`."""
+ reader = self.reader("localized-files-no-en-us")
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "LOCALIZED_FILES paths must start with `en-US/` or contain `locales/en-US/`: "
+ "foo.js",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_localized_pp_files(self):
+ """Test that LOCALIZED_PP_FILES works properly."""
+ reader = self.reader("localized-pp-files")
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 1)
+ self.assertIsInstance(objs[0], LocalizedPreprocessedFiles)
+
+ for path, files in objs[0].files.walk():
+ self.assertEqual(path, "foo")
+ self.assertEqual(len(files), 2)
+
+ expected = {"en-US/bar.ini", "en-US/foo.js"}
+ for f in files:
+ self.assertTrue(six.text_type(f) in expected)
+
+ def test_rust_library_no_cargo_toml(self):
+ """Test that defining a RustLibrary without a Cargo.toml fails."""
+ reader = self.reader("rust-library-no-cargo-toml")
+ with six.assertRaisesRegex(
+ self, SandboxValidationError, "No Cargo.toml file found"
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_rust_library_name_mismatch(self):
+ """Test that defining a RustLibrary that doesn't match Cargo.toml fails."""
+ reader = self.reader("rust-library-name-mismatch")
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "library.*does not match Cargo.toml-defined package",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_rust_library_no_lib_section(self):
+ """Test that a RustLibrary Cargo.toml with no [lib] section fails."""
+ reader = self.reader("rust-library-no-lib-section")
+ with six.assertRaisesRegex(
+ self, SandboxValidationError, "Cargo.toml for.* has no \\[lib\\] section"
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_rust_library_invalid_crate_type(self):
+ """Test that a RustLibrary Cargo.toml has a permitted crate-type."""
+ reader = self.reader("rust-library-invalid-crate-type")
+ with six.assertRaisesRegex(
+ self, SandboxValidationError, "crate-type.* is not permitted"
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_rust_library_dash_folding(self):
+ """Test that on-disk names of RustLibrary objects convert dashes to underscores."""
+ reader = self.reader(
+ "rust-library-dash-folding",
+ extra_substs=dict(RUST_TARGET="i686-pc-windows-msvc"),
+ )
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 4)
+ ldflags, host_cflags, lib, cflags = objs
+ self.assertIsInstance(ldflags, ComputedFlags)
+ self.assertIsInstance(cflags, ComputedFlags)
+ self.assertIsInstance(host_cflags, ComputedFlags)
+ self.assertIsInstance(lib, RustLibrary)
+ self.assertRegex(lib.lib_name, "random_crate")
+ self.assertRegex(lib.import_name, "random_crate")
+ self.assertRegex(lib.basename, "random-crate")
+
+ def test_multiple_rust_libraries(self):
+ """Test that linking multiple Rust libraries throws an error"""
+ reader = self.reader(
+ "multiple-rust-libraries",
+ extra_substs=dict(RUST_TARGET="i686-pc-windows-msvc"),
+ )
+ with six.assertRaisesRegex(
+ self, SandboxValidationError, "Cannot link the following Rust libraries"
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_rust_library_features(self):
+ """Test that RustLibrary features are correctly emitted."""
+ reader = self.reader(
+ "rust-library-features",
+ extra_substs=dict(RUST_TARGET="i686-pc-windows-msvc"),
+ )
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 4)
+ ldflags, host_cflags, lib, cflags = objs
+ self.assertIsInstance(ldflags, ComputedFlags)
+ self.assertIsInstance(cflags, ComputedFlags)
+ self.assertIsInstance(host_cflags, ComputedFlags)
+ self.assertIsInstance(lib, RustLibrary)
+ self.assertEqual(lib.features, ["musthave", "cantlivewithout"])
+
+ def test_rust_library_duplicate_features(self):
+ """Test that duplicate RustLibrary features are rejected."""
+ reader = self.reader("rust-library-duplicate-features")
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "features for .* should not contain duplicates",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_rust_program_no_cargo_toml(self):
+ """Test that specifying RUST_PROGRAMS without a Cargo.toml fails."""
+ reader = self.reader("rust-program-no-cargo-toml")
+ with six.assertRaisesRegex(
+ self, SandboxValidationError, "No Cargo.toml file found"
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_host_rust_program_no_cargo_toml(self):
+ """Test that specifying HOST_RUST_PROGRAMS without a Cargo.toml fails."""
+ reader = self.reader("host-rust-program-no-cargo-toml")
+ with six.assertRaisesRegex(
+ self, SandboxValidationError, "No Cargo.toml file found"
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_rust_program_nonexistent_name(self):
+ """Test that specifying RUST_PROGRAMS that don't exist in Cargo.toml
+ correctly throws an error."""
+ reader = self.reader("rust-program-nonexistent-name")
+ with six.assertRaisesRegex(
+ self, SandboxValidationError, "Cannot find Cargo.toml definition for"
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_host_rust_program_nonexistent_name(self):
+ """Test that specifying HOST_RUST_PROGRAMS that don't exist in
+ Cargo.toml correctly throws an error."""
+ reader = self.reader("host-rust-program-nonexistent-name")
+ with six.assertRaisesRegex(
+ self, SandboxValidationError, "Cannot find Cargo.toml definition for"
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_rust_programs(self):
+ """Test RUST_PROGRAMS emission."""
+ reader = self.reader(
+ "rust-programs",
+ extra_substs=dict(RUST_TARGET="i686-pc-windows-msvc", BIN_SUFFIX=".exe"),
+ )
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 4)
+ ldflags, host_cflags, cflags, prog = objs
+ self.assertIsInstance(ldflags, ComputedFlags)
+ self.assertIsInstance(cflags, ComputedFlags)
+ self.assertIsInstance(host_cflags, ComputedFlags)
+ self.assertIsInstance(prog, RustProgram)
+ self.assertEqual(prog.name, "some")
+
+ def test_host_rust_programs(self):
+ """Test HOST_RUST_PROGRAMS emission."""
+ reader = self.reader(
+ "host-rust-programs",
+ extra_substs=dict(
+ RUST_HOST_TARGET="i686-pc-windows-msvc", HOST_BIN_SUFFIX=".exe"
+ ),
+ )
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 4)
+ print(objs)
+ ldflags, cflags, hostflags, prog = objs
+ self.assertIsInstance(ldflags, ComputedFlags)
+ self.assertIsInstance(cflags, ComputedFlags)
+ self.assertIsInstance(hostflags, ComputedFlags)
+ self.assertIsInstance(prog, HostRustProgram)
+ self.assertEqual(prog.name, "some")
+
+ def test_host_rust_libraries(self):
+ """Test HOST_RUST_LIBRARIES emission."""
+ reader = self.reader(
+ "host-rust-libraries",
+ extra_substs=dict(
+ RUST_HOST_TARGET="i686-pc-windows-msvc", HOST_BIN_SUFFIX=".exe"
+ ),
+ )
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 4)
+ ldflags, host_cflags, lib, cflags = objs
+ self.assertIsInstance(ldflags, ComputedFlags)
+ self.assertIsInstance(cflags, ComputedFlags)
+ self.assertIsInstance(host_cflags, ComputedFlags)
+ self.assertIsInstance(lib, HostRustLibrary)
+ self.assertRegex(lib.lib_name, "host_lib")
+ self.assertRegex(lib.import_name, "host_lib")
+
+ def test_crate_dependency_path_resolution(self):
+ """Test recursive dependencies resolve with the correct paths."""
+ reader = self.reader(
+ "crate-dependency-path-resolution",
+ extra_substs=dict(RUST_TARGET="i686-pc-windows-msvc"),
+ )
+ objs = self.read_topsrcdir(reader)
+
+ self.assertEqual(len(objs), 4)
+ ldflags, host_cflags, lib, cflags = objs
+ self.assertIsInstance(ldflags, ComputedFlags)
+ self.assertIsInstance(cflags, ComputedFlags)
+ self.assertIsInstance(host_cflags, ComputedFlags)
+ self.assertIsInstance(lib, RustLibrary)
+
+ def test_install_shared_lib(self):
+ """Test that we can install a shared library with TEST_HARNESS_FILES"""
+ reader = self.reader("test-install-shared-lib")
+ objs = self.read_topsrcdir(reader)
+ self.assertIsInstance(objs[0], TestHarnessFiles)
+ self.assertIsInstance(objs[1], VariablePassthru)
+ self.assertIsInstance(objs[2], ComputedFlags)
+ self.assertIsInstance(objs[3], SharedLibrary)
+ self.assertIsInstance(objs[4], ComputedFlags)
+ for path, files in objs[0].files.walk():
+ for f in files:
+ self.assertEqual(str(f), "!libfoo.so")
+ self.assertEqual(path, "foo/bar")
+
+ def test_symbols_file(self):
+ """Test that SYMBOLS_FILE works"""
+ reader = self.reader("test-symbols-file")
+ genfile, ldflags, shlib, flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(genfile, GeneratedFile)
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertIsInstance(ldflags, ComputedFlags)
+ self.assertIsInstance(shlib, SharedLibrary)
+ # This looks weird but MockConfig sets DLL_{PREFIX,SUFFIX} and
+ # the reader method in this class sets OS_TARGET=WINNT.
+ self.assertEqual(shlib.symbols_file, "libfoo.so.def")
+
+ def test_symbols_file_objdir(self):
+ """Test that a SYMBOLS_FILE in the objdir works"""
+ reader = self.reader("test-symbols-file-objdir")
+ genfile, ldflags, shlib, flags = self.read_topsrcdir(reader)
+ self.assertIsInstance(genfile, GeneratedFile)
+ self.assertEqual(
+ genfile.script, mozpath.join(reader.config.topsrcdir, "foo.py")
+ )
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertIsInstance(ldflags, ComputedFlags)
+ self.assertIsInstance(shlib, SharedLibrary)
+ self.assertEqual(shlib.symbols_file, "foo.symbols")
+
+ def test_symbols_file_objdir_missing_generated(self):
+ """Test that a SYMBOLS_FILE in the objdir that's missing
+ from GENERATED_FILES is an error.
+ """
+ reader = self.reader("test-symbols-file-objdir-missing-generated")
+ with six.assertRaisesRegex(
+ self,
+ SandboxValidationError,
+ "Objdir file specified in SYMBOLS_FILE not in GENERATED_FILES:",
+ ):
+ self.read_topsrcdir(reader)
+
+ def test_wasm_compile_flags(self):
+ reader = self.reader(
+ "wasm-compile-flags",
+ extra_substs={"WASM_CC": "clang", "WASM_CXX": "clang++"},
+ )
+ flags = list(self.read_topsrcdir(reader))[2]
+ self.assertIsInstance(flags, ComputedFlags)
+ self.assertEqual(
+ flags.flags["WASM_CFLAGS"], reader.config.substs["WASM_CFLAGS"]
+ )
+ self.assertEqual(
+ flags.flags["MOZBUILD_WASM_CFLAGS"], ["-funroll-loops", "-wasm-arg"]
+ )
+ self.assertEqual(
+ set(flags.flags["WASM_DEFINES"]),
+ set(["-DFOO", '-DBAZ="abcd"', "-UQUX", "-DBAR=7", "-DVALUE=xyz"]),
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/python/mozbuild/mozbuild/test/frontend/test_namespaces.py b/python/mozbuild/mozbuild/test/frontend/test_namespaces.py
new file mode 100644
index 0000000000..e8c1a3eb00
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/test_namespaces.py
@@ -0,0 +1,225 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import unittest
+
+import six
+from mozunit import main
+
+from mozbuild.frontend.context import (
+ Context,
+ ContextDerivedTypedList,
+ ContextDerivedTypedListWithItems,
+ ContextDerivedValue,
+)
+from mozbuild.util import (
+ StrictOrderingOnAppendList,
+ StrictOrderingOnAppendListWithFlagsFactory,
+ UnsortedError,
+)
+
+
+class Fuga(object):
+ def __init__(self, value):
+ self.value = value
+
+
+class Piyo(ContextDerivedValue):
+ def __init__(self, context, value):
+ if not isinstance(value, six.text_type):
+ raise ValueError
+ self.context = context
+ self.value = value
+
+ def lower(self):
+ return self.value.lower()
+
+ def __str__(self):
+ return self.value
+
+ def __eq__(self, other):
+ return self.value == six.text_type(other)
+
+ def __lt__(self, other):
+ return self.value < six.text_type(other)
+
+ def __le__(self, other):
+ return self.value <= six.text_type(other)
+
+ def __gt__(self, other):
+ return self.value > six.text_type(other)
+
+ def __ge__(self, other):
+ return self.value >= six.text_type(other)
+
+ def __hash__(self):
+ return hash(self.value)
+
+
+VARIABLES = {
+ "HOGE": (six.text_type, six.text_type, None),
+ "FUGA": (Fuga, six.text_type, None),
+ "PIYO": (Piyo, six.text_type, None),
+ "HOGERA": (ContextDerivedTypedList(Piyo, StrictOrderingOnAppendList), list, None),
+ "HOGEHOGE": (
+ ContextDerivedTypedListWithItems(
+ Piyo,
+ StrictOrderingOnAppendListWithFlagsFactory(
+ {
+ "foo": bool,
+ }
+ ),
+ ),
+ list,
+ None,
+ ),
+}
+
+
+class TestContext(unittest.TestCase):
+ def test_key_rejection(self):
+ # Lowercase keys should be rejected during normal operation.
+ ns = Context(allowed_variables=VARIABLES)
+
+ with self.assertRaises(KeyError) as ke:
+ ns["foo"] = True
+
+ e = ke.exception.args
+ self.assertEqual(e[0], "global_ns")
+ self.assertEqual(e[1], "set_unknown")
+ self.assertEqual(e[2], "foo")
+ self.assertTrue(e[3])
+
+ # Unknown uppercase keys should be rejected.
+ with self.assertRaises(KeyError) as ke:
+ ns["FOO"] = True
+
+ e = ke.exception.args
+ self.assertEqual(e[0], "global_ns")
+ self.assertEqual(e[1], "set_unknown")
+ self.assertEqual(e[2], "FOO")
+ self.assertTrue(e[3])
+
+ def test_allowed_set(self):
+ self.assertIn("HOGE", VARIABLES)
+
+ ns = Context(allowed_variables=VARIABLES)
+
+ ns["HOGE"] = "foo"
+ self.assertEqual(ns["HOGE"], "foo")
+
+ def test_value_checking(self):
+ ns = Context(allowed_variables=VARIABLES)
+
+ # Setting to a non-allowed type should not work.
+ with self.assertRaises(ValueError) as ve:
+ ns["HOGE"] = True
+
+ e = ve.exception.args
+ self.assertEqual(e[0], "global_ns")
+ self.assertEqual(e[1], "set_type")
+ self.assertEqual(e[2], "HOGE")
+ self.assertEqual(e[3], True)
+ self.assertEqual(e[4], six.text_type)
+
+ def test_key_checking(self):
+ # Checking for existence of a key should not populate the key if it
+ # doesn't exist.
+ g = Context(allowed_variables=VARIABLES)
+
+ self.assertFalse("HOGE" in g)
+ self.assertFalse("HOGE" in g)
+
+ def test_coercion(self):
+ ns = Context(allowed_variables=VARIABLES)
+
+ # Setting to a type different from the allowed input type should not
+ # work.
+ with self.assertRaises(ValueError) as ve:
+ ns["FUGA"] = False
+
+ e = ve.exception.args
+ self.assertEqual(e[0], "global_ns")
+ self.assertEqual(e[1], "set_type")
+ self.assertEqual(e[2], "FUGA")
+ self.assertEqual(e[3], False)
+ self.assertEqual(e[4], six.text_type)
+
+ ns["FUGA"] = "fuga"
+ self.assertIsInstance(ns["FUGA"], Fuga)
+ self.assertEqual(ns["FUGA"].value, "fuga")
+
+ ns["FUGA"] = Fuga("hoge")
+ self.assertIsInstance(ns["FUGA"], Fuga)
+ self.assertEqual(ns["FUGA"].value, "hoge")
+
+ def test_context_derived_coercion(self):
+ ns = Context(allowed_variables=VARIABLES)
+
+ # Setting to a type different from the allowed input type should not
+ # work.
+ with self.assertRaises(ValueError) as ve:
+ ns["PIYO"] = False
+
+ e = ve.exception.args
+ self.assertEqual(e[0], "global_ns")
+ self.assertEqual(e[1], "set_type")
+ self.assertEqual(e[2], "PIYO")
+ self.assertEqual(e[3], False)
+ self.assertEqual(e[4], six.text_type)
+
+ ns["PIYO"] = "piyo"
+ self.assertIsInstance(ns["PIYO"], Piyo)
+ self.assertEqual(ns["PIYO"].value, "piyo")
+ self.assertEqual(ns["PIYO"].context, ns)
+
+ ns["PIYO"] = Piyo(ns, "fuga")
+ self.assertIsInstance(ns["PIYO"], Piyo)
+ self.assertEqual(ns["PIYO"].value, "fuga")
+ self.assertEqual(ns["PIYO"].context, ns)
+
+ def test_context_derived_typed_list(self):
+ ns = Context(allowed_variables=VARIABLES)
+
+ # Setting to a type that's rejected by coercion should not work.
+ with self.assertRaises(ValueError):
+ ns["HOGERA"] = [False]
+
+ ns["HOGERA"] += ["a", "b", "c"]
+
+ self.assertIsInstance(ns["HOGERA"], VARIABLES["HOGERA"][0])
+ for n in range(0, 3):
+ self.assertIsInstance(ns["HOGERA"][n], Piyo)
+ self.assertEqual(ns["HOGERA"][n].value, ["a", "b", "c"][n])
+ self.assertEqual(ns["HOGERA"][n].context, ns)
+
+ with self.assertRaises(UnsortedError):
+ ns["HOGERA"] += ["f", "e", "d"]
+
+ def test_context_derived_typed_list_with_items(self):
+ ns = Context(allowed_variables=VARIABLES)
+
+ # Setting to a type that's rejected by coercion should not work.
+ with self.assertRaises(ValueError):
+ ns["HOGEHOGE"] = [False]
+
+ values = ["a", "b", "c"]
+ ns["HOGEHOGE"] += values
+
+ self.assertIsInstance(ns["HOGEHOGE"], VARIABLES["HOGEHOGE"][0])
+ for v in values:
+ ns["HOGEHOGE"][v].foo = True
+
+ for v, item in zip(values, ns["HOGEHOGE"]):
+ self.assertIsInstance(item, Piyo)
+ self.assertEqual(v, item)
+ self.assertEqual(ns["HOGEHOGE"][v].foo, True)
+ self.assertEqual(ns["HOGEHOGE"][item].foo, True)
+
+ with self.assertRaises(UnsortedError):
+ ns["HOGEHOGE"] += ["f", "e", "d"]
+
+
+if __name__ == "__main__":
+ main()
diff --git a/python/mozbuild/mozbuild/test/frontend/test_reader.py b/python/mozbuild/mozbuild/test/frontend/test_reader.py
new file mode 100644
index 0000000000..a15bb15d7e
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/test_reader.py
@@ -0,0 +1,531 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+import sys
+import unittest
+
+import mozpack.path as mozpath
+from mozunit import main
+
+from mozbuild import schedules
+from mozbuild.frontend.context import BugzillaComponent
+from mozbuild.frontend.reader import BuildReader, BuildReaderError
+from mozbuild.test.common import MockConfig
+
+if sys.version_info.major == 2:
+ text_type = "unicode"
+else:
+ text_type = "str"
+
+data_path = mozpath.abspath(mozpath.dirname(__file__))
+data_path = mozpath.join(data_path, "data")
+
+
+class TestBuildReader(unittest.TestCase):
+ def setUp(self):
+ self._old_env = dict(os.environ)
+ os.environ.pop("MOZ_OBJDIR", None)
+
+ def tearDown(self):
+ os.environ.clear()
+ os.environ.update(self._old_env)
+
+ def config(self, name, **kwargs):
+ path = mozpath.join(data_path, name)
+
+ return MockConfig(path, **kwargs)
+
+ def reader(self, name, enable_tests=False, error_is_fatal=True, **kwargs):
+ extra = {}
+ if enable_tests:
+ extra["ENABLE_TESTS"] = "1"
+ config = self.config(name, extra_substs=extra, error_is_fatal=error_is_fatal)
+
+ return BuildReader(config, **kwargs)
+
+ def file_path(self, name, *args):
+ return mozpath.join(data_path, name, *args)
+
+ def test_dirs_traversal_simple(self):
+ reader = self.reader("traversal-simple")
+
+ contexts = list(reader.read_topsrcdir())
+
+ self.assertEqual(len(contexts), 4)
+
+ def test_dirs_traversal_no_descend(self):
+ reader = self.reader("traversal-simple")
+
+ path = mozpath.join(reader.config.topsrcdir, "moz.build")
+ self.assertTrue(os.path.exists(path))
+
+ contexts = list(reader.read_mozbuild(path, reader.config, descend=False))
+
+ self.assertEqual(len(contexts), 1)
+
+ def test_dirs_traversal_all_variables(self):
+ reader = self.reader("traversal-all-vars")
+
+ contexts = list(reader.read_topsrcdir())
+ self.assertEqual(len(contexts), 2)
+
+ reader = self.reader("traversal-all-vars", enable_tests=True)
+
+ contexts = list(reader.read_topsrcdir())
+ self.assertEqual(len(contexts), 3)
+
+ def test_relative_dirs(self):
+ # Ensure relative directories are traversed.
+ reader = self.reader("traversal-relative-dirs")
+
+ contexts = list(reader.read_topsrcdir())
+ self.assertEqual(len(contexts), 3)
+
+ def test_repeated_dirs_ignored(self):
+ # Ensure repeated directories are ignored.
+ reader = self.reader("traversal-repeated-dirs")
+
+ contexts = list(reader.read_topsrcdir())
+ self.assertEqual(len(contexts), 3)
+
+ def test_outside_topsrcdir(self):
+ # References to directories outside the topsrcdir should fail.
+ reader = self.reader("traversal-outside-topsrcdir")
+
+ with self.assertRaises(Exception):
+ list(reader.read_topsrcdir())
+
+ def test_error_basic(self):
+ reader = self.reader("reader-error-basic")
+
+ with self.assertRaises(BuildReaderError) as bre:
+ list(reader.read_topsrcdir())
+
+ e = bre.exception
+ self.assertEqual(
+ e.actual_file, self.file_path("reader-error-basic", "moz.build")
+ )
+
+ self.assertIn("The error occurred while processing the", str(e))
+
+ def test_error_included_from(self):
+ reader = self.reader("reader-error-included-from")
+
+ with self.assertRaises(BuildReaderError) as bre:
+ list(reader.read_topsrcdir())
+
+ e = bre.exception
+ self.assertEqual(
+ e.actual_file, self.file_path("reader-error-included-from", "child.build")
+ )
+ self.assertEqual(
+ e.main_file, self.file_path("reader-error-included-from", "moz.build")
+ )
+
+ self.assertIn("This file was included as part of processing", str(e))
+
+ def test_error_syntax_error(self):
+ reader = self.reader("reader-error-syntax")
+
+ with self.assertRaises(BuildReaderError) as bre:
+ list(reader.read_topsrcdir())
+
+ e = bre.exception
+ self.assertIn("Python syntax error on line 5", str(e))
+ self.assertIn(" foo =", str(e))
+ self.assertIn(" ^", str(e))
+
+ def test_error_read_unknown_global(self):
+ reader = self.reader("reader-error-read-unknown-global")
+
+ with self.assertRaises(BuildReaderError) as bre:
+ list(reader.read_topsrcdir())
+
+ e = bre.exception
+ self.assertIn("The error was triggered on line 5", str(e))
+ self.assertIn("The underlying problem is an attempt to read", str(e))
+ self.assertIn(" FOO", str(e))
+
+ def test_error_write_unknown_global(self):
+ reader = self.reader("reader-error-write-unknown-global")
+
+ with self.assertRaises(BuildReaderError) as bre:
+ list(reader.read_topsrcdir())
+
+ e = bre.exception
+ self.assertIn("The error was triggered on line 7", str(e))
+ self.assertIn("The underlying problem is an attempt to write", str(e))
+ self.assertIn(" FOO", str(e))
+
+ def test_error_write_bad_value(self):
+ reader = self.reader("reader-error-write-bad-value")
+
+ with self.assertRaises(BuildReaderError) as bre:
+ list(reader.read_topsrcdir())
+
+ e = bre.exception
+ self.assertIn("The error was triggered on line 5", str(e))
+ self.assertIn("is an attempt to write an illegal value to a special", str(e))
+
+ self.assertIn("variable whose value was rejected is:\n\n DIRS", str(e))
+
+ self.assertIn(
+ "written to it was of the following type:\n\n %s" % text_type, str(e)
+ )
+
+ self.assertIn("expects the following type(s):\n\n list", str(e))
+
+ def test_error_illegal_path(self):
+ reader = self.reader("reader-error-outside-topsrcdir")
+
+ with self.assertRaises(BuildReaderError) as bre:
+ list(reader.read_topsrcdir())
+
+ e = bre.exception
+ self.assertIn("The underlying problem is an illegal file access", str(e))
+
+ def test_error_missing_include_path(self):
+ reader = self.reader("reader-error-missing-include")
+
+ with self.assertRaises(BuildReaderError) as bre:
+ list(reader.read_topsrcdir())
+
+ e = bre.exception
+ self.assertIn("we referenced a path that does not exist", str(e))
+
+ def test_error_script_error(self):
+ reader = self.reader("reader-error-script-error")
+
+ with self.assertRaises(BuildReaderError) as bre:
+ list(reader.read_topsrcdir())
+
+ e = bre.exception
+ self.assertIn("The error appears to be the fault of the script", str(e))
+ self.assertIn(' ["TypeError: unsupported operand', str(e))
+
+ def test_error_bad_dir(self):
+ reader = self.reader("reader-error-bad-dir")
+
+ with self.assertRaises(BuildReaderError) as bre:
+ list(reader.read_topsrcdir())
+
+ e = bre.exception
+ self.assertIn("we referenced a path that does not exist", str(e))
+
+ def test_error_repeated_dir(self):
+ reader = self.reader("reader-error-repeated-dir")
+
+ with self.assertRaises(BuildReaderError) as bre:
+ list(reader.read_topsrcdir())
+
+ e = bre.exception
+ self.assertIn("Directory (foo) registered multiple times", str(e))
+
+ def test_error_error_func(self):
+ reader = self.reader("reader-error-error-func")
+
+ with self.assertRaises(BuildReaderError) as bre:
+ list(reader.read_topsrcdir())
+
+ e = bre.exception
+ self.assertIn("A moz.build file called the error() function.", str(e))
+ self.assertIn(" Some error.", str(e))
+
+ def test_error_error_func_ok(self):
+ reader = self.reader("reader-error-error-func", error_is_fatal=False)
+
+ list(reader.read_topsrcdir())
+
+ def test_error_empty_list(self):
+ reader = self.reader("reader-error-empty-list")
+
+ with self.assertRaises(BuildReaderError) as bre:
+ list(reader.read_topsrcdir())
+
+ e = bre.exception
+ self.assertIn("Variable DIRS assigned an empty value.", str(e))
+
+ def test_inheriting_variables(self):
+ reader = self.reader("inheriting-variables")
+
+ contexts = list(reader.read_topsrcdir())
+
+ self.assertEqual(len(contexts), 4)
+ self.assertEqual(
+ [context.relsrcdir for context in contexts], ["", "foo", "foo/baz", "bar"]
+ )
+ self.assertEqual(
+ [context["XPIDL_MODULE"] for context in contexts],
+ ["foobar", "foobar", "baz", "foobar"],
+ )
+
+ def test_find_relevant_mozbuilds(self):
+ reader = self.reader("reader-relevant-mozbuild")
+
+ # Absolute paths outside topsrcdir are rejected.
+ with self.assertRaises(Exception):
+ reader._find_relevant_mozbuilds(["/foo"])
+
+ # File in root directory.
+ paths = reader._find_relevant_mozbuilds(["file"])
+ self.assertEqual(paths, {"file": ["moz.build"]})
+
+ # File in child directory.
+ paths = reader._find_relevant_mozbuilds(["d1/file1"])
+ self.assertEqual(paths, {"d1/file1": ["moz.build", "d1/moz.build"]})
+
+ # Multiple files in same directory.
+ paths = reader._find_relevant_mozbuilds(["d1/file1", "d1/file2"])
+ self.assertEqual(
+ paths,
+ {
+ "d1/file1": ["moz.build", "d1/moz.build"],
+ "d1/file2": ["moz.build", "d1/moz.build"],
+ },
+ )
+
+ # Missing moz.build from missing intermediate directory.
+ paths = reader._find_relevant_mozbuilds(
+ ["d1/no-intermediate-moz-build/child/file"]
+ )
+ self.assertEqual(
+ paths,
+ {
+ "d1/no-intermediate-moz-build/child/file": [
+ "moz.build",
+ "d1/moz.build",
+ "d1/no-intermediate-moz-build/child/moz.build",
+ ]
+ },
+ )
+
+ # Lots of empty directories.
+ paths = reader._find_relevant_mozbuilds(
+ ["d1/parent-is-far/dir1/dir2/dir3/file"]
+ )
+ self.assertEqual(
+ paths,
+ {
+ "d1/parent-is-far/dir1/dir2/dir3/file": [
+ "moz.build",
+ "d1/moz.build",
+ "d1/parent-is-far/moz.build",
+ ]
+ },
+ )
+
+ # Lots of levels.
+ paths = reader._find_relevant_mozbuilds(
+ ["d1/every-level/a/file", "d1/every-level/b/file"]
+ )
+ self.assertEqual(
+ paths,
+ {
+ "d1/every-level/a/file": [
+ "moz.build",
+ "d1/moz.build",
+ "d1/every-level/moz.build",
+ "d1/every-level/a/moz.build",
+ ],
+ "d1/every-level/b/file": [
+ "moz.build",
+ "d1/moz.build",
+ "d1/every-level/moz.build",
+ "d1/every-level/b/moz.build",
+ ],
+ },
+ )
+
+ # Different root directories.
+ paths = reader._find_relevant_mozbuilds(["d1/file", "d2/file", "file"])
+ self.assertEqual(
+ paths,
+ {
+ "file": ["moz.build"],
+ "d1/file": ["moz.build", "d1/moz.build"],
+ "d2/file": ["moz.build", "d2/moz.build"],
+ },
+ )
+
+ def test_read_relevant_mozbuilds(self):
+ reader = self.reader("reader-relevant-mozbuild")
+
+ paths, contexts = reader.read_relevant_mozbuilds(
+ ["d1/every-level/a/file", "d1/every-level/b/file", "d2/file"]
+ )
+ self.assertEqual(len(paths), 3)
+ self.assertEqual(len(contexts), 6)
+
+ self.assertEqual(
+ [ctx.relsrcdir for ctx in paths["d1/every-level/a/file"]],
+ ["", "d1", "d1/every-level", "d1/every-level/a"],
+ )
+ self.assertEqual(
+ [ctx.relsrcdir for ctx in paths["d1/every-level/b/file"]],
+ ["", "d1", "d1/every-level", "d1/every-level/b"],
+ )
+ self.assertEqual([ctx.relsrcdir for ctx in paths["d2/file"]], ["", "d2"])
+
+ def test_all_mozbuild_paths(self):
+ reader = self.reader("reader-relevant-mozbuild")
+
+ paths = list(reader.all_mozbuild_paths())
+ # Ensure no duplicate paths.
+ self.assertEqual(sorted(paths), sorted(set(paths)))
+ self.assertEqual(len(paths), 10)
+
+ def test_files_bad_bug_component(self):
+ reader = self.reader("files-info")
+
+ with self.assertRaises(BuildReaderError):
+ reader.files_info(["bug_component/bad-assignment/moz.build"])
+
+ def test_files_bug_component_static(self):
+ reader = self.reader("files-info")
+
+ v = reader.files_info(
+ [
+ "bug_component/static/foo",
+ "bug_component/static/bar",
+ "bug_component/static/foo/baz",
+ ]
+ )
+ self.assertEqual(len(v), 3)
+ self.assertEqual(
+ v["bug_component/static/foo"]["BUG_COMPONENT"],
+ BugzillaComponent("FooProduct", "FooComponent"),
+ )
+ self.assertEqual(
+ v["bug_component/static/bar"]["BUG_COMPONENT"],
+ BugzillaComponent("BarProduct", "BarComponent"),
+ )
+ self.assertEqual(
+ v["bug_component/static/foo/baz"]["BUG_COMPONENT"],
+ BugzillaComponent("default_product", "default_component"),
+ )
+
+ def test_files_bug_component_simple(self):
+ reader = self.reader("files-info")
+
+ v = reader.files_info(["bug_component/simple/moz.build"])
+ self.assertEqual(len(v), 1)
+ flags = v["bug_component/simple/moz.build"]
+ self.assertEqual(flags["BUG_COMPONENT"].product, "Firefox Build System")
+ self.assertEqual(flags["BUG_COMPONENT"].component, "General")
+
+ def test_files_bug_component_different_matchers(self):
+ reader = self.reader("files-info")
+
+ v = reader.files_info(
+ [
+ "bug_component/different-matchers/foo.jsm",
+ "bug_component/different-matchers/bar.cpp",
+ "bug_component/different-matchers/baz.misc",
+ ]
+ )
+ self.assertEqual(len(v), 3)
+
+ js_flags = v["bug_component/different-matchers/foo.jsm"]
+ cpp_flags = v["bug_component/different-matchers/bar.cpp"]
+ misc_flags = v["bug_component/different-matchers/baz.misc"]
+
+ self.assertEqual(js_flags["BUG_COMPONENT"], BugzillaComponent("Firefox", "JS"))
+ self.assertEqual(
+ cpp_flags["BUG_COMPONENT"], BugzillaComponent("Firefox", "C++")
+ )
+ self.assertEqual(
+ misc_flags["BUG_COMPONENT"],
+ BugzillaComponent("default_product", "default_component"),
+ )
+
+ def test_files_bug_component_final(self):
+ reader = self.reader("files-info")
+
+ v = reader.files_info(
+ [
+ "bug_component/final/foo",
+ "bug_component/final/Makefile.in",
+ "bug_component/final/subcomponent/Makefile.in",
+ "bug_component/final/subcomponent/bar",
+ ]
+ )
+
+ self.assertEqual(
+ v["bug_component/final/foo"]["BUG_COMPONENT"],
+ BugzillaComponent("default_product", "default_component"),
+ )
+ self.assertEqual(
+ v["bug_component/final/Makefile.in"]["BUG_COMPONENT"],
+ BugzillaComponent("Firefox Build System", "General"),
+ )
+ self.assertEqual(
+ v["bug_component/final/subcomponent/Makefile.in"]["BUG_COMPONENT"],
+ BugzillaComponent("Firefox Build System", "General"),
+ )
+ self.assertEqual(
+ v["bug_component/final/subcomponent/bar"]["BUG_COMPONENT"],
+ BugzillaComponent("Another", "Component"),
+ )
+
+ def test_invalid_flavor(self):
+ reader = self.reader("invalid-files-flavor")
+
+ with self.assertRaises(BuildReaderError):
+ reader.files_info(["foo.js"])
+
+ def test_schedules(self):
+ reader = self.reader("schedules")
+ info = reader.files_info(
+ [
+ "win.and.osx",
+ "somefile",
+ "foo.win",
+ "foo.osx",
+ "subd/aa.py",
+ "subd/yaml.py",
+ "subd/win.js",
+ ]
+ )
+ # default: all exclusive, no inclusive
+ self.assertEqual(info["somefile"]["SCHEDULES"].inclusive, [])
+ self.assertEqual(
+ info["somefile"]["SCHEDULES"].exclusive, schedules.EXCLUSIVE_COMPONENTS
+ )
+ # windows-only
+ self.assertEqual(info["foo.win"]["SCHEDULES"].inclusive, [])
+ self.assertEqual(info["foo.win"]["SCHEDULES"].exclusive, ["windows"])
+ # osx-only
+ self.assertEqual(info["foo.osx"]["SCHEDULES"].inclusive, [])
+ self.assertEqual(info["foo.osx"]["SCHEDULES"].exclusive, ["macosx"])
+ # top-level moz.build specifies subd/**.py with an inclusive option
+ self.assertEqual(info["subd/aa.py"]["SCHEDULES"].inclusive, ["py-lint"])
+ self.assertEqual(
+ info["subd/aa.py"]["SCHEDULES"].exclusive, schedules.EXCLUSIVE_COMPONENTS
+ )
+ # Files('yaml.py') in subd/moz.build combines with Files('subdir/**.py')
+ self.assertEqual(
+ info["subd/yaml.py"]["SCHEDULES"].inclusive, ["py-lint", "yaml-lint"]
+ )
+ self.assertEqual(
+ info["subd/yaml.py"]["SCHEDULES"].exclusive, schedules.EXCLUSIVE_COMPONENTS
+ )
+ # .. but exlusive does not override inclusive
+ self.assertEqual(info["subd/win.js"]["SCHEDULES"].inclusive, ["js-lint"])
+ self.assertEqual(info["subd/win.js"]["SCHEDULES"].exclusive, ["windows"])
+
+ self.assertEqual(
+ set(info["subd/yaml.py"]["SCHEDULES"].components),
+ set(schedules.EXCLUSIVE_COMPONENTS + ["py-lint", "yaml-lint"]),
+ )
+
+ # win.and.osx is defined explicitly, and matches *.osx, and the two have
+ # conflicting SCHEDULES.exclusive settings, so the later one is used
+ self.assertEqual(
+ set(info["win.and.osx"]["SCHEDULES"].exclusive), set(["macosx", "windows"])
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/python/mozbuild/mozbuild/test/frontend/test_sandbox.py b/python/mozbuild/mozbuild/test/frontend/test_sandbox.py
new file mode 100644
index 0000000000..017de1ce9c
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/test_sandbox.py
@@ -0,0 +1,536 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import unittest
+
+import mozpack.path as mozpath
+from mozunit import main
+
+from mozbuild.frontend.context import (
+ FUNCTIONS,
+ SPECIAL_VARIABLES,
+ VARIABLES,
+ Context,
+ SourcePath,
+)
+from mozbuild.frontend.reader import MozbuildSandbox, SandboxCalledError
+from mozbuild.frontend.sandbox import Sandbox, SandboxExecutionError, SandboxLoadError
+from mozbuild.test.common import MockConfig
+
+test_data_path = mozpath.abspath(mozpath.dirname(__file__))
+test_data_path = mozpath.join(test_data_path, "data")
+
+
+class TestSandbox(unittest.TestCase):
+ def sandbox(self):
+ return Sandbox(
+ Context(
+ {
+ "DIRS": (list, list, None),
+ }
+ )
+ )
+
+ def test_exec_source_success(self):
+ sandbox = self.sandbox()
+ context = sandbox._context
+
+ sandbox.exec_source("foo = True", mozpath.abspath("foo.py"))
+
+ self.assertNotIn("foo", context)
+ self.assertEqual(context.main_path, mozpath.abspath("foo.py"))
+ self.assertEqual(context.all_paths, set([mozpath.abspath("foo.py")]))
+
+ def test_exec_compile_error(self):
+ sandbox = self.sandbox()
+
+ with self.assertRaises(SandboxExecutionError) as se:
+ sandbox.exec_source("2f23;k;asfj", mozpath.abspath("foo.py"))
+
+ self.assertEqual(se.exception.file_stack, [mozpath.abspath("foo.py")])
+ self.assertIsInstance(se.exception.exc_value, SyntaxError)
+ self.assertEqual(sandbox._context.main_path, mozpath.abspath("foo.py"))
+
+ def test_exec_import_denied(self):
+ sandbox = self.sandbox()
+
+ with self.assertRaises(SandboxExecutionError) as se:
+ sandbox.exec_source("import sys")
+
+ self.assertIsInstance(se.exception, SandboxExecutionError)
+ self.assertEqual(se.exception.exc_type, ImportError)
+
+ def test_exec_source_multiple(self):
+ sandbox = self.sandbox()
+
+ sandbox.exec_source('DIRS = ["foo"]')
+ sandbox.exec_source('DIRS += ["bar"]')
+
+ self.assertEqual(sandbox["DIRS"], ["foo", "bar"])
+
+ def test_exec_source_illegal_key_set(self):
+ sandbox = self.sandbox()
+
+ with self.assertRaises(SandboxExecutionError) as se:
+ sandbox.exec_source("ILLEGAL = True")
+
+ e = se.exception
+ self.assertIsInstance(e.exc_value, KeyError)
+
+ e = se.exception.exc_value
+ self.assertEqual(e.args[0], "global_ns")
+ self.assertEqual(e.args[1], "set_unknown")
+
+ def test_exec_source_reassign(self):
+ sandbox = self.sandbox()
+
+ sandbox.exec_source('DIRS = ["foo"]')
+ with self.assertRaises(SandboxExecutionError) as se:
+ sandbox.exec_source('DIRS = ["bar"]')
+
+ self.assertEqual(sandbox["DIRS"], ["foo"])
+ e = se.exception
+ self.assertIsInstance(e.exc_value, KeyError)
+
+ e = se.exception.exc_value
+ self.assertEqual(e.args[0], "global_ns")
+ self.assertEqual(e.args[1], "reassign")
+ self.assertEqual(e.args[2], "DIRS")
+
+ def test_exec_source_reassign_builtin(self):
+ sandbox = self.sandbox()
+
+ with self.assertRaises(SandboxExecutionError) as se:
+ sandbox.exec_source("sorted = 1")
+
+ e = se.exception
+ self.assertIsInstance(e.exc_value, KeyError)
+
+ e = se.exception.exc_value
+ self.assertEqual(e.args[0], "Cannot reassign builtins")
+
+
+class TestedSandbox(MozbuildSandbox):
+ """Version of MozbuildSandbox with a little more convenience for testing.
+
+ It automatically normalizes paths given to exec_file and exec_source. This
+ helps simplify the test code.
+ """
+
+ def normalize_path(self, path):
+ return mozpath.normpath(mozpath.join(self._context.config.topsrcdir, path))
+
+ def source_path(self, path):
+ return SourcePath(self._context, path)
+
+ def exec_file(self, path):
+ super(TestedSandbox, self).exec_file(self.normalize_path(path))
+
+ def exec_source(self, source, path=""):
+ super(TestedSandbox, self).exec_source(
+ source, self.normalize_path(path) if path else ""
+ )
+
+
+class TestMozbuildSandbox(unittest.TestCase):
+ def sandbox(self, data_path=None, metadata={}):
+ config = None
+
+ if data_path is not None:
+ config = MockConfig(mozpath.join(test_data_path, data_path))
+ else:
+ config = MockConfig()
+
+ return TestedSandbox(Context(VARIABLES, config), metadata)
+
+ def test_default_state(self):
+ sandbox = self.sandbox()
+ sandbox._context.add_source(sandbox.normalize_path("moz.build"))
+ config = sandbox._context.config
+
+ self.assertEqual(sandbox["TOPSRCDIR"], config.topsrcdir)
+ self.assertEqual(sandbox["TOPOBJDIR"], config.topobjdir)
+ self.assertEqual(sandbox["RELATIVEDIR"], "")
+ self.assertEqual(sandbox["SRCDIR"], config.topsrcdir)
+ self.assertEqual(sandbox["OBJDIR"], config.topobjdir)
+
+ def test_symbol_presence(self):
+ # Ensure no discrepancies between the master symbol table and what's in
+ # the sandbox.
+ sandbox = self.sandbox()
+ sandbox._context.add_source(sandbox.normalize_path("moz.build"))
+
+ all_symbols = set()
+ all_symbols |= set(FUNCTIONS.keys())
+ all_symbols |= set(SPECIAL_VARIABLES.keys())
+
+ for symbol in all_symbols:
+ self.assertIsNotNone(sandbox[symbol])
+
+ def test_path_calculation(self):
+ sandbox = self.sandbox()
+ sandbox._context.add_source(sandbox.normalize_path("foo/bar/moz.build"))
+ config = sandbox._context.config
+
+ self.assertEqual(sandbox["TOPSRCDIR"], config.topsrcdir)
+ self.assertEqual(sandbox["TOPOBJDIR"], config.topobjdir)
+ self.assertEqual(sandbox["RELATIVEDIR"], "foo/bar")
+ self.assertEqual(sandbox["SRCDIR"], mozpath.join(config.topsrcdir, "foo/bar"))
+ self.assertEqual(sandbox["OBJDIR"], mozpath.join(config.topobjdir, "foo/bar"))
+
+ def test_config_access(self):
+ sandbox = self.sandbox()
+ config = sandbox._context.config
+
+ self.assertEqual(sandbox["CONFIG"]["MOZ_TRUE"], "1")
+ self.assertEqual(sandbox["CONFIG"]["MOZ_FOO"], config.substs["MOZ_FOO"])
+
+ # Access to an undefined substitution should return None.
+ self.assertNotIn("MISSING", sandbox["CONFIG"])
+ self.assertIsNone(sandbox["CONFIG"]["MISSING"])
+
+ # Should shouldn't be allowed to assign to the config.
+ with self.assertRaises(Exception):
+ sandbox["CONFIG"]["FOO"] = ""
+
+ def test_special_variables(self):
+ sandbox = self.sandbox()
+ sandbox._context.add_source(sandbox.normalize_path("moz.build"))
+
+ for k in SPECIAL_VARIABLES:
+ with self.assertRaises(KeyError):
+ sandbox[k] = 0
+
+ def test_exec_source_reassign_exported(self):
+ template_sandbox = self.sandbox(data_path="templates")
+
+ # Templates need to be defined in actual files because of
+ # inspect.getsourcelines.
+ template_sandbox.exec_file("templates.mozbuild")
+
+ config = MockConfig()
+
+ exports = {"DIST_SUBDIR": "browser"}
+
+ sandbox = TestedSandbox(
+ Context(VARIABLES, config),
+ metadata={
+ "exports": exports,
+ "templates": template_sandbox.templates,
+ },
+ )
+
+ self.assertEqual(sandbox["DIST_SUBDIR"], "browser")
+
+ # Templates should not interfere
+ sandbox.exec_source("Template([])", "foo.mozbuild")
+
+ sandbox.exec_source('DIST_SUBDIR = "foo"')
+ with self.assertRaises(SandboxExecutionError) as se:
+ sandbox.exec_source('DIST_SUBDIR = "bar"')
+
+ self.assertEqual(sandbox["DIST_SUBDIR"], "foo")
+ e = se.exception
+ self.assertIsInstance(e.exc_value, KeyError)
+
+ e = se.exception.exc_value
+ self.assertEqual(e.args[0], "global_ns")
+ self.assertEqual(e.args[1], "reassign")
+ self.assertEqual(e.args[2], "DIST_SUBDIR")
+
+ def test_include_basic(self):
+ sandbox = self.sandbox(data_path="include-basic")
+
+ sandbox.exec_file("moz.build")
+
+ self.assertEqual(
+ sandbox["DIRS"],
+ [
+ sandbox.source_path("foo"),
+ sandbox.source_path("bar"),
+ ],
+ )
+ self.assertEqual(
+ sandbox._context.main_path, sandbox.normalize_path("moz.build")
+ )
+ self.assertEqual(len(sandbox._context.all_paths), 2)
+
+ def test_include_outside_topsrcdir(self):
+ sandbox = self.sandbox(data_path="include-outside-topsrcdir")
+
+ with self.assertRaises(SandboxLoadError) as se:
+ sandbox.exec_file("relative.build")
+
+ self.assertEqual(
+ se.exception.illegal_path, sandbox.normalize_path("../moz.build")
+ )
+
+ def test_include_error_stack(self):
+ # Ensure the path stack is reported properly in exceptions.
+ sandbox = self.sandbox(data_path="include-file-stack")
+
+ with self.assertRaises(SandboxExecutionError) as se:
+ sandbox.exec_file("moz.build")
+
+ e = se.exception
+ self.assertIsInstance(e.exc_value, KeyError)
+
+ args = e.exc_value.args
+ self.assertEqual(args[0], "global_ns")
+ self.assertEqual(args[1], "set_unknown")
+ self.assertEqual(args[2], "ILLEGAL")
+
+ expected_stack = [
+ mozpath.join(sandbox._context.config.topsrcdir, p)
+ for p in ["moz.build", "included-1.build", "included-2.build"]
+ ]
+
+ self.assertEqual(e.file_stack, expected_stack)
+
+ def test_include_missing(self):
+ sandbox = self.sandbox(data_path="include-missing")
+
+ with self.assertRaises(SandboxLoadError) as sle:
+ sandbox.exec_file("moz.build")
+
+ self.assertIsNotNone(sle.exception.read_error)
+
+ def test_include_relative_from_child_dir(self):
+ # A relative path from a subdirectory should be relative from that
+ # child directory.
+ sandbox = self.sandbox(data_path="include-relative-from-child")
+ sandbox.exec_file("child/child.build")
+ self.assertEqual(sandbox["DIRS"], [sandbox.source_path("../foo")])
+
+ sandbox = self.sandbox(data_path="include-relative-from-child")
+ sandbox.exec_file("child/child2.build")
+ self.assertEqual(sandbox["DIRS"], [sandbox.source_path("../foo")])
+
+ def test_include_topsrcdir_relative(self):
+ # An absolute path for include() is relative to topsrcdir.
+
+ sandbox = self.sandbox(data_path="include-topsrcdir-relative")
+ sandbox.exec_file("moz.build")
+
+ self.assertEqual(sandbox["DIRS"], [sandbox.source_path("foo")])
+
+ def test_error(self):
+ sandbox = self.sandbox()
+
+ with self.assertRaises(SandboxCalledError) as sce:
+ sandbox.exec_source('error("This is an error.")')
+
+ e = sce.exception.message
+ self.assertIn("This is an error.", str(e))
+
+ def test_substitute_config_files(self):
+ sandbox = self.sandbox()
+ sandbox._context.add_source(sandbox.normalize_path("moz.build"))
+
+ sandbox.exec_source('CONFIGURE_SUBST_FILES += ["bar", "foo"]')
+ self.assertEqual(sandbox["CONFIGURE_SUBST_FILES"], ["bar", "foo"])
+ for item in sandbox["CONFIGURE_SUBST_FILES"]:
+ self.assertIsInstance(item, SourcePath)
+
+ def test_invalid_exports_set_base(self):
+ sandbox = self.sandbox()
+
+ with self.assertRaises(SandboxExecutionError) as se:
+ sandbox.exec_source('EXPORTS = "foo.h"')
+
+ self.assertEqual(se.exception.exc_type, ValueError)
+
+ def test_templates(self):
+ sandbox = self.sandbox(data_path="templates")
+
+ # Templates need to be defined in actual files because of
+ # inspect.getsourcelines.
+ sandbox.exec_file("templates.mozbuild")
+
+ sandbox2 = self.sandbox(metadata={"templates": sandbox.templates})
+ source = """
+Template([
+ 'foo.cpp',
+])
+"""
+ sandbox2.exec_source(source, "foo.mozbuild")
+
+ self.assertEqual(
+ sandbox2._context,
+ {
+ "SOURCES": ["foo.cpp"],
+ "DIRS": [],
+ },
+ )
+
+ sandbox2 = self.sandbox(metadata={"templates": sandbox.templates})
+ source = """
+SOURCES += ['qux.cpp']
+Template([
+ 'bar.cpp',
+ 'foo.cpp',
+],[
+ 'foo',
+])
+SOURCES += ['hoge.cpp']
+"""
+ sandbox2.exec_source(source, "foo.mozbuild")
+
+ self.assertEqual(
+ sandbox2._context,
+ {
+ "SOURCES": ["qux.cpp", "bar.cpp", "foo.cpp", "hoge.cpp"],
+ "DIRS": [sandbox2.source_path("foo")],
+ },
+ )
+
+ sandbox2 = self.sandbox(metadata={"templates": sandbox.templates})
+ source = """
+TemplateError([
+ 'foo.cpp',
+])
+"""
+ with self.assertRaises(SandboxExecutionError) as se:
+ sandbox2.exec_source(source, "foo.mozbuild")
+
+ e = se.exception
+ self.assertIsInstance(e.exc_value, KeyError)
+
+ e = se.exception.exc_value
+ self.assertEqual(e.args[0], "global_ns")
+ self.assertEqual(e.args[1], "set_unknown")
+
+ # TemplateGlobalVariable tries to access 'illegal' but that is expected
+ # to throw.
+ sandbox2 = self.sandbox(metadata={"templates": sandbox.templates})
+ source = """
+illegal = True
+TemplateGlobalVariable()
+"""
+ with self.assertRaises(SandboxExecutionError) as se:
+ sandbox2.exec_source(source, "foo.mozbuild")
+
+ e = se.exception
+ self.assertIsInstance(e.exc_value, NameError)
+
+ # TemplateGlobalUPPERVariable sets SOURCES with DIRS, but the context
+ # used when running the template is not expected to access variables
+ # from the global context.
+ sandbox2 = self.sandbox(metadata={"templates": sandbox.templates})
+ source = """
+DIRS += ['foo']
+TemplateGlobalUPPERVariable()
+"""
+ sandbox2.exec_source(source, "foo.mozbuild")
+ self.assertEqual(
+ sandbox2._context,
+ {
+ "SOURCES": [],
+ "DIRS": [sandbox2.source_path("foo")],
+ },
+ )
+
+ # However, the result of the template is mixed with the global
+ # context.
+ sandbox2 = self.sandbox(metadata={"templates": sandbox.templates})
+ source = """
+SOURCES += ['qux.cpp']
+TemplateInherit([
+ 'bar.cpp',
+ 'foo.cpp',
+])
+SOURCES += ['hoge.cpp']
+"""
+ sandbox2.exec_source(source, "foo.mozbuild")
+
+ self.assertEqual(
+ sandbox2._context,
+ {
+ "SOURCES": ["qux.cpp", "bar.cpp", "foo.cpp", "hoge.cpp"],
+ "USE_LIBS": ["foo"],
+ "DIRS": [],
+ },
+ )
+
+ # Template names must be CamelCase. Here, we can define the template
+ # inline because the error happens before inspect.getsourcelines.
+ sandbox2 = self.sandbox(metadata={"templates": sandbox.templates})
+ source = """
+@template
+def foo():
+ pass
+"""
+
+ with self.assertRaises(SandboxExecutionError) as se:
+ sandbox2.exec_source(source, "foo.mozbuild")
+
+ e = se.exception
+ self.assertIsInstance(e.exc_value, NameError)
+
+ e = se.exception.exc_value
+ self.assertIn("Template function names must be CamelCase.", str(e))
+
+ # Template names must not already be registered.
+ sandbox2 = self.sandbox(metadata={"templates": sandbox.templates})
+ source = """
+@template
+def Template():
+ pass
+"""
+ with self.assertRaises(SandboxExecutionError) as se:
+ sandbox2.exec_source(source, "foo.mozbuild")
+
+ e = se.exception
+ self.assertIsInstance(e.exc_value, KeyError)
+
+ e = se.exception.exc_value
+ self.assertIn(
+ 'A template named "Template" was already declared in %s.'
+ % sandbox.normalize_path("templates.mozbuild"),
+ str(e),
+ )
+
+ def test_function_args(self):
+ class Foo(int):
+ pass
+
+ def foo(a, b):
+ return type(a), type(b)
+
+ FUNCTIONS.update(
+ {
+ "foo": (lambda self: foo, (Foo, int), ""),
+ }
+ )
+
+ try:
+ sandbox = self.sandbox()
+ source = 'foo("a", "b")'
+
+ with self.assertRaises(SandboxExecutionError) as se:
+ sandbox.exec_source(source, "foo.mozbuild")
+
+ e = se.exception
+ self.assertIsInstance(e.exc_value, ValueError)
+
+ sandbox = self.sandbox()
+ source = 'foo(1, "b")'
+
+ with self.assertRaises(SandboxExecutionError) as se:
+ sandbox.exec_source(source, "foo.mozbuild")
+
+ e = se.exception
+ self.assertIsInstance(e.exc_value, ValueError)
+
+ sandbox = self.sandbox()
+ source = "a = foo(1, 2)"
+ sandbox.exec_source(source, "foo.mozbuild")
+
+ self.assertEqual(sandbox["a"], (Foo, int))
+ finally:
+ del FUNCTIONS["foo"]
+
+
+if __name__ == "__main__":
+ main()