diff options
Diffstat (limited to 'tests/auto')
871 files changed, 14172 insertions, 2774 deletions
diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt new file mode 100644 index 000000000..8b1a124aa --- /dev/null +++ b/tests/auto/CMakeLists.txt @@ -0,0 +1,10 @@ +add_subdirectory(api) +add_subdirectory(cmdlineparser) +add_subdirectory(blackbox) + +if(WITH_UNIT_TESTS) + add_subdirectory(buildgraph) + add_subdirectory(language) + add_subdirectory(pkgconfig) + add_subdirectory(tools) +endif() diff --git a/tests/auto/api/CMakeLists.txt b/tests/auto/api/CMakeLists.txt new file mode 100644 index 000000000..c1f89972d --- /dev/null +++ b/tests/auto/api/CMakeLists.txt @@ -0,0 +1,9 @@ +add_qbs_test(api + DEFINES + "QBS_RELATIVE_LIBEXEC_PATH=\"${QBS_RELATIVE_LIBEXEC_PATH}\"" + "QBS_RELATIVE_SEARCH_PATH=\"${QBS_RELATIVE_SEARCH_PATH}\"" + "QBS_RELATIVE_PLUGINS_PATH=\"${QBS_RELATIVE_PLUGINS_PATH}\"" + SOURCES + tst_api.cpp + tst_api.h + ) diff --git a/tests/auto/api/api.pro b/tests/auto/api/api.pro deleted file mode 100644 index d9c42e7bb..000000000 --- a/tests/auto/api/api.pro +++ /dev/null @@ -1,28 +0,0 @@ -TARGET = tst_api - -HEADERS = tst_api.h -SOURCES = tst_api.cpp - -include(../../../src/library_dirname.pri) -isEmpty(QBS_RELATIVE_LIBEXEC_PATH) { - win32:QBS_RELATIVE_LIBEXEC_PATH=. - else:QBS_RELATIVE_LIBEXEC_PATH=../libexec/qbs -} -isEmpty(QBS_RELATIVE_PLUGINS_PATH):QBS_RELATIVE_PLUGINS_PATH=../$${QBS_LIBRARY_DIRNAME} -isEmpty(QBS_RELATIVE_SEARCH_PATH):QBS_RELATIVE_SEARCH_PATH=.. -DEFINES += QBS_RELATIVE_LIBEXEC_PATH=\\\"$${QBS_RELATIVE_LIBEXEC_PATH}\\\" -DEFINES += QBS_RELATIVE_PLUGINS_PATH=\\\"$${QBS_RELATIVE_PLUGINS_PATH}\\\" -DEFINES += QBS_RELATIVE_SEARCH_PATH=\\\"$${QBS_RELATIVE_SEARCH_PATH}\\\" -qbs_enable_project_file_updates:DEFINES += QBS_ENABLE_PROJECT_FILE_UPDATES - -include(../auto.pri) - -DATA_DIRS = testdata - -for(data_dir, DATA_DIRS) { - files = $$files($$PWD/$$data_dir/*, true) - win32:files ~= s|\\\\|/|g - for(file, files):!exists($$file/*):FILES += $$file -} - -OTHER_FILES += $$FILES diff --git a/tests/auto/api/api.qbs b/tests/auto/api/api.qbs index 09e0af7dc..10064c888 100644 --- a/tests/auto/api/api.qbs +++ b/tests/auto/api/api.qbs @@ -1,4 +1,3 @@ -import qbs import qbs.Utilities QbsAutotest { @@ -9,7 +8,7 @@ QbsAutotest { "QBS_RELATIVE_LIBEXEC_PATH=" + Utilities.cStringQuote(qbsbuildconfig.relativeLibexecPath), "QBS_RELATIVE_SEARCH_PATH=" + Utilities.cStringQuote(qbsbuildconfig.relativeSearchPath), "QBS_RELATIVE_PLUGINS_PATH=" + Utilities.cStringQuote(qbsbuildconfig.relativePluginsPath) - ]).concat(qbsbuildconfig.enableProjectFileUpdates ? ["QBS_ENABLE_PROJECT_FILE_UPDATES"] : []) + ]) Group { name: "testdata" diff --git a/tests/auto/api/testdata/QBS-728/QBS-728.qbs b/tests/auto/api/testdata/QBS-728/QBS-728.qbs index 5969e13cc..cdeb7c6db 100644 --- a/tests/auto/api/testdata/QBS-728/QBS-728.qbs +++ b/tests/auto/api/testdata/QBS-728/QBS-728.qbs @@ -1,5 +1,5 @@ Product { - property bool isBlubbOS: qbs.targetOS.contains("blubb-OS") + property bool isBlubbOS: qbs.targetOS.includes("blubb-OS") qbs.profiles: isBlubbOS ? ["blubb-profile"] : [project.profile] qbs.architecture: "blubb-arch" } diff --git a/tests/auto/api/testdata/app-without-sources/app-without-sources.qbs b/tests/auto/api/testdata/app-without-sources/app-without-sources.qbs index 4cc25ad66..db707f515 100644 --- a/tests/auto/api/testdata/app-without-sources/app-without-sources.qbs +++ b/tests/auto/api/testdata/app-without-sources/app-without-sources.qbs @@ -26,7 +26,7 @@ Project { // HACK: cpp.entryPoint currently not working 100% with gcc Properties { - condition: qbs.toolchain.contains("msvc") + condition: qbs.toolchain.includes("msvc") cpp.entryPoint: "main" cpp.dynamicLibraries: ["ucrt", "kernel32"] } diff --git a/tests/auto/api/testdata/build-properties-source/build-properties-source.qbs b/tests/auto/api/testdata/build-properties-source/build-properties-source.qbs index 571feced8..3237e90dc 100644 --- a/tests/auto/api/testdata/build-properties-source/build-properties-source.qbs +++ b/tests/auto/api/testdata/build-properties-source/build-properties-source.qbs @@ -6,11 +6,6 @@ Project { Depends { name: 'cpp' } - Properties { - condition: qbs.toolchain.contains("gcc") - cpp.cxxFlags: "-march=native" - } - Group { cpp.defines: ['WORLD="BANANA"'] files : [ "main.cpp" ] diff --git a/tests/auto/api/testdata/build-properties-source/main.cpp b/tests/auto/api/testdata/build-properties-source/main.cpp index f830ee1fd..89ec55463 100644 --- a/tests/auto/api/testdata/build-properties-source/main.cpp +++ b/tests/auto/api/testdata/build-properties-source/main.cpp @@ -26,7 +26,7 @@ ** ****************************************************************************/ -#include <stdio.h> +#include <cstdio> #ifndef WORLD # error WORLD is not defined @@ -34,5 +34,5 @@ int main() { - puts("Hello " WORLD "!"); + std::puts("Hello " WORLD "!"); } diff --git a/tests/auto/api/testdata/change-dependent-lib/change-dependent-lib.qbs b/tests/auto/api/testdata/change-dependent-lib/change-dependent-lib.qbs index 222dc4476..cb925eeca 100644 --- a/tests/auto/api/testdata/change-dependent-lib/change-dependent-lib.qbs +++ b/tests/auto/api/testdata/change-dependent-lib/change-dependent-lib.qbs @@ -18,7 +18,7 @@ Project { cpp.defines: ["XXXX"] Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } diff --git a/tests/auto/api/testdata/change-dependent-lib/main.cpp b/tests/auto/api/testdata/change-dependent-lib/main.cpp index 8ad414c46..9334da1ef 100644 --- a/tests/auto/api/testdata/change-dependent-lib/main.cpp +++ b/tests/auto/api/testdata/change-dependent-lib/main.cpp @@ -28,13 +28,12 @@ #include "../dllexport.h" -#include <stdio.h> +#include <cstdio> DLL_IMPORT int mylib_hello(); int main() { - puts("application says hello!"); + std::puts("application says hello!"); return mylib_hello(); } - diff --git a/tests/auto/api/testdata/change-dependent-lib/mylib.cpp b/tests/auto/api/testdata/change-dependent-lib/mylib.cpp index 28cb69f95..b8c3e9082 100644 --- a/tests/auto/api/testdata/change-dependent-lib/mylib.cpp +++ b/tests/auto/api/testdata/change-dependent-lib/mylib.cpp @@ -28,10 +28,10 @@ #include "../dllexport.h" -#include <stdio.h> +#include <cstdio> DLL_EXPORT int mylib_hello() { - puts("mylib says hello!"); + std::puts("mylib says hello!"); return 0; } diff --git a/tests/auto/api/testdata/codegen/codegen.qbs b/tests/auto/api/testdata/codegen/codegen.qbs index d8a217572..42e4c6b08 100644 --- a/tests/auto/api/testdata/codegen/codegen.qbs +++ b/tests/auto/api/testdata/codegen/codegen.qbs @@ -43,7 +43,7 @@ Project { // check whether multipart module name translation is working var actual = product.moduleProperty("Qt.core", "mocName"); - if (!actual || !actual.contains("moc")) + if (!actual || !actual.includes("moc")) throw "multipart module name translation is broken"; // check whether we can access project properties here @@ -57,7 +57,7 @@ Project { code = expandMacros(code, product.replacements); var args = ['echo ' + code + '>' + output.filePath] var cmd - if (product.moduleProperty("qbs", "hostOS").contains('windows')) { + if (product.moduleProperty("qbs", "hostOS").includes('windows')) { cmd = new Command(product.qbs.windowsShellPath, ['/C'].concat(args)); } else { args[0] = args[0].replace(/\(/g, '\\(') @@ -65,7 +65,7 @@ Project { args[0] = args[0].replace(/;/g, '\\;') cmd = new Command(product.qbs.shellPath, ['-c'].concat(args)) } - cmd.description = 'generate\t' + FileInfo.fileName(output.filePath); + cmd.description = 'generating ' + FileInfo.fileName(output.filePath); cmd.highlight = 'codegen'; return cmd; } diff --git a/tests/auto/api/testdata/dependency-on-multiplexed-type/dependency-on-multiplexed-type.qbs b/tests/auto/api/testdata/dependency-on-multiplexed-type/dependency-on-multiplexed-type.qbs index cfc2769d2..f0ffebe39 100644 --- a/tests/auto/api/testdata/dependency-on-multiplexed-type/dependency-on-multiplexed-type.qbs +++ b/tests/auto/api/testdata/dependency-on-multiplexed-type/dependency-on-multiplexed-type.qbs @@ -1,5 +1,3 @@ -import qbs - Project { Product { name: "dep"; type: "x" } Product { diff --git a/tests/auto/api/testdata/disabled-product/disabled-product.qbs b/tests/auto/api/testdata/disabled-product/disabled-product.qbs index dad8f5d4c..e7eea7380 100644 --- a/tests/auto/api/testdata/disabled-product/disabled-product.qbs +++ b/tests/auto/api/testdata/disabled-product/disabled-product.qbs @@ -2,7 +2,7 @@ CppApplication { condition: false files: "main.cpp" Group { - condition: qbs.targetOS.contains("stuff") + condition: qbs.targetOS.includes("stuff") qbs.install: false } } diff --git a/tests/auto/api/testdata/disappeared-wildcard-file/disappeared-wildcard-file.qbs b/tests/auto/api/testdata/disappeared-wildcard-file/disappeared-wildcard-file.qbs new file mode 100644 index 000000000..3c38e18a7 --- /dev/null +++ b/tests/auto/api/testdata/disappeared-wildcard-file/disappeared-wildcard-file.qbs @@ -0,0 +1,4 @@ +Product { + name: "dummy" + files: "*.txt" +} diff --git a/tests/auto/blackbox/testdata/concurrent-executor/dummy1.input b/tests/auto/api/testdata/disappeared-wildcard-file/file1.txt index e69de29bb..e69de29bb 100644 --- a/tests/auto/blackbox/testdata/concurrent-executor/dummy1.input +++ b/tests/auto/api/testdata/disappeared-wildcard-file/file1.txt diff --git a/tests/auto/blackbox/testdata/concurrent-executor/dummy2.input b/tests/auto/api/testdata/disappeared-wildcard-file/file2.txt index e69de29bb..e69de29bb 100644 --- a/tests/auto/blackbox/testdata/concurrent-executor/dummy2.input +++ b/tests/auto/api/testdata/disappeared-wildcard-file/file2.txt diff --git a/tests/auto/api/testdata/explicitly-depends-on/explicitly-depends-on.qbs b/tests/auto/api/testdata/explicitly-depends-on/explicitly-depends-on.qbs index 05886a99e..0ebb73413 100644 --- a/tests/auto/api/testdata/explicitly-depends-on/explicitly-depends-on.qbs +++ b/tests/auto/api/testdata/explicitly-depends-on/explicitly-depends-on.qbs @@ -1,4 +1,5 @@ import qbs.FileInfo +import qbs.Host import qbs.TextFile Project { @@ -11,6 +12,12 @@ Project { } } Product { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: "p" type: ["mytype"] diff --git a/tests/auto/api/testdata/export-simple/export-simple.qbs b/tests/auto/api/testdata/export-simple/export-simple.qbs index 01177049d..84ce5541d 100644 --- a/tests/auto/api/testdata/export-simple/export-simple.qbs +++ b/tests/auto/api/testdata/export-simple/export-simple.qbs @@ -43,7 +43,7 @@ Project { } Depends { name: "cpp" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } diff --git a/tests/auto/api/testdata/export-simple/lib1.cpp b/tests/auto/api/testdata/export-simple/lib1.cpp index 2b22d4993..7981edf92 100644 --- a/tests/auto/api/testdata/export-simple/lib1.cpp +++ b/tests/auto/api/testdata/export-simple/lib1.cpp @@ -27,10 +27,10 @@ ****************************************************************************/ #include "../dllexport.h" -#include <stdio.h> +#include <cstdio> DLL_EXPORT int lib1_hello() { - puts("lib1 says hello!"); + std::puts("lib1 says hello!"); return 0; } diff --git a/tests/auto/api/testdata/export-simple/main.cpp b/tests/auto/api/testdata/export-simple/main.cpp index 820e6f3bc..060037b82 100644 --- a/tests/auto/api/testdata/export-simple/main.cpp +++ b/tests/auto/api/testdata/export-simple/main.cpp @@ -27,13 +27,12 @@ ****************************************************************************/ #include "../dllexport.h" -#include <stdio.h> +#include <cstdio> DLL_IMPORT int lib1_hello(); int main() { - puts("application says hello!"); + std::puts("application says hello!"); return lib1_hello(); } - diff --git a/tests/auto/api/testdata/infinite-loop-js/infinite-loop.qbs b/tests/auto/api/testdata/infinite-loop-js/infinite-loop.qbs index bb616a9e2..224e90ca6 100644 --- a/tests/auto/api/testdata/infinite-loop-js/infinite-loop.qbs +++ b/tests/auto/api/testdata/infinite-loop-js/infinite-loop.qbs @@ -8,7 +8,7 @@ Product { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Running infinite loop"; + cmd.description = "running infinite loop"; cmd.sourceCode = function() { while (true) ; diff --git a/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs b/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs index f4ea8bf83..687955f2f 100644 --- a/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs +++ b/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs @@ -1,3 +1,5 @@ +import qbs.Host + Project { CppApplication { type: "application" @@ -6,7 +8,7 @@ Project { name: "infinite-loop" cpp.cxxLanguageVersion: "c++11" Properties { - condition: qbs.toolchain.contains("gcc") + condition: qbs.toolchain.includes("gcc") cpp.driverFlags: "-pthread" } } @@ -17,14 +19,14 @@ Project { Depends { name: "infinite-loop" } Depends { name: "cpp" // Make sure build environment is set up properly. - condition: qbs.hostOS.contains("windows") && qbs.toolchain.contains("gcc") + condition: Host.os().includes("windows") && qbs.toolchain.includes("gcc") } Rule { inputsFromDependencies: "application" outputFileTags: "mytype" prepare: { var cmd = new Command(inputs["application"][0].filePath); - cmd.description = "Calling application that runs forever"; + cmd.description = "calling application that runs forever"; return cmd; } } diff --git a/tests/auto/blackbox/testdata/innosetup/inc/qbsinc.iss b/tests/auto/api/testdata/infinite-loop-scanning-scan/file.in index e69de29bb..e69de29bb 100644 --- a/tests/auto/blackbox/testdata/innosetup/inc/qbsinc.iss +++ b/tests/auto/api/testdata/infinite-loop-scanning-scan/file.in diff --git a/tests/auto/api/testdata/infinite-loop-scanning-scan/infinite-loop.qbs b/tests/auto/api/testdata/infinite-loop-scanning-scan/infinite-loop.qbs new file mode 100644 index 000000000..5e3e33b6e --- /dev/null +++ b/tests/auto/api/testdata/infinite-loop-scanning-scan/infinite-loop.qbs @@ -0,0 +1,21 @@ +Product { + type: "t" + Depends { name: "m" } + Group { + files: "file.in" + fileTags: "i" + } + Rule { + inputs: "i" + Artifact { + filePath: "dummy" + fileTags: "t" + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.silent = true; + cmd.sourceCode = function() {}; + return cmd; + } + } +} diff --git a/tests/auto/api/testdata/infinite-loop-scanning-scan/modules/m/m.qbs b/tests/auto/api/testdata/infinite-loop-scanning-scan/modules/m/m.qbs new file mode 100644 index 000000000..9c8a18072 --- /dev/null +++ b/tests/auto/api/testdata/infinite-loop-scanning-scan/modules/m/m.qbs @@ -0,0 +1,6 @@ +Module { + Scanner { + inputs: "i" + scan: { while (true); } + } +}
\ No newline at end of file diff --git a/tests/auto/api/testdata/infinite-loop-scanning-searchpaths/file.in b/tests/auto/api/testdata/infinite-loop-scanning-searchpaths/file.in new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/api/testdata/infinite-loop-scanning-searchpaths/file.in diff --git a/tests/auto/api/testdata/infinite-loop-scanning-searchpaths/infinite-loop.qbs b/tests/auto/api/testdata/infinite-loop-scanning-searchpaths/infinite-loop.qbs new file mode 100644 index 000000000..5e3e33b6e --- /dev/null +++ b/tests/auto/api/testdata/infinite-loop-scanning-searchpaths/infinite-loop.qbs @@ -0,0 +1,21 @@ +Product { + type: "t" + Depends { name: "m" } + Group { + files: "file.in" + fileTags: "i" + } + Rule { + inputs: "i" + Artifact { + filePath: "dummy" + fileTags: "t" + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.silent = true; + cmd.sourceCode = function() {}; + return cmd; + } + } +} diff --git a/tests/auto/api/testdata/infinite-loop-scanning-searchpaths/modules/m/m.qbs b/tests/auto/api/testdata/infinite-loop-scanning-searchpaths/modules/m/m.qbs new file mode 100644 index 000000000..0476478b9 --- /dev/null +++ b/tests/auto/api/testdata/infinite-loop-scanning-searchpaths/modules/m/m.qbs @@ -0,0 +1,7 @@ +Module { + Scanner { + inputs: "i" + searchPaths: { while (true); } + scan: [] + } +} diff --git a/tests/auto/api/testdata/installed-artifact/installed-artifact.qbs b/tests/auto/api/testdata/installed-artifact/installed-artifact.qbs index d3f91662a..e4e050213 100644 --- a/tests/auto/api/testdata/installed-artifact/installed-artifact.qbs +++ b/tests/auto/api/testdata/installed-artifact/installed-artifact.qbs @@ -17,6 +17,7 @@ Project { } qbs.installPrefix: "/usr" install: true + installDebugInformation: false installDir: "bin" Group { fileTagsFilter: "obj" diff --git a/tests/auto/api/testdata/is-runnable/is-runnable.qbs b/tests/auto/api/testdata/is-runnable/is-runnable.qbs index 870279294..e93cc38aa 100644 --- a/tests/auto/api/testdata/is-runnable/is-runnable.qbs +++ b/tests/auto/api/testdata/is-runnable/is-runnable.qbs @@ -5,7 +5,7 @@ Project { DynamicLibrary { name: "lib" Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } diff --git a/tests/auto/api/testdata/lib-same-source/main.cpp b/tests/auto/api/testdata/lib-same-source/main.cpp index 47e1013f9..c9602f59f 100644 --- a/tests/auto/api/testdata/lib-same-source/main.cpp +++ b/tests/auto/api/testdata/lib-same-source/main.cpp @@ -26,9 +26,9 @@ ** ****************************************************************************/ -#include <stdio.h> +#include <cstdio> int main() { - puts("Hello WOrld!"); + std::puts("Hello WOrld!"); } diff --git a/tests/auto/api/testdata/link-dynamiclibs-staticlibs/dynamic1.cpp b/tests/auto/api/testdata/link-dynamiclibs-staticlibs/dynamic1.cpp index ed5f822fb..555c91afe 100644 --- a/tests/auto/api/testdata/link-dynamiclibs-staticlibs/dynamic1.cpp +++ b/tests/auto/api/testdata/link-dynamiclibs-staticlibs/dynamic1.cpp @@ -1,4 +1,4 @@ -#include <stdio.h> +#include <cstdio> #include "../dllexport.h" @@ -7,6 +7,6 @@ void static1_hello(); DLL_EXPORT int dynamic1_hello() { static1_hello(); - puts("dynamic1 says hello!"); + std::puts("dynamic1 says hello!"); return 0; } diff --git a/tests/auto/api/testdata/link-dynamiclibs-staticlibs/dynamic2.cpp b/tests/auto/api/testdata/link-dynamiclibs-staticlibs/dynamic2.cpp index b2db5d23e..d5fcbaab4 100644 --- a/tests/auto/api/testdata/link-dynamiclibs-staticlibs/dynamic2.cpp +++ b/tests/auto/api/testdata/link-dynamiclibs-staticlibs/dynamic2.cpp @@ -1,10 +1,10 @@ #include "../dllexport.h" #include "static2.h" -#include <stdio.h> +#include <cstdio> DLL_EXPORT void dynamic2_hello() { TestMe tm; tm.hello(); - puts("dynamic2 says hello!"); + std::puts("dynamic2 says hello!"); } diff --git a/tests/auto/api/testdata/link-dynamiclibs-staticlibs/link-dynamiclibs-staticlibs.qbs b/tests/auto/api/testdata/link-dynamiclibs-staticlibs/link-dynamiclibs-staticlibs.qbs index b2a54080c..0c86d05c6 100644 --- a/tests/auto/api/testdata/link-dynamiclibs-staticlibs/link-dynamiclibs-staticlibs.qbs +++ b/tests/auto/api/testdata/link-dynamiclibs-staticlibs/link-dynamiclibs-staticlibs.qbs @@ -12,7 +12,7 @@ Project { Depends { name: "cpp" } Depends { name: "static1" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } @@ -31,7 +31,7 @@ Project { Depends { name: "static2" } cpp.visibility: 'hidden' Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } @@ -40,6 +40,11 @@ Project { name: "static2" files: [ "static2.cpp", "static2.h" ] Depends { name: "cpp" } + Probe { + id: tcPrinter + property bool isGcc: qbs.toolchain.contains("gcc") + configure: { console.info("is gcc: " + isGcc); } + } } } diff --git a/tests/auto/api/testdata/link-dynamiclibs-staticlibs/main.cpp b/tests/auto/api/testdata/link-dynamiclibs-staticlibs/main.cpp index 73c0922d6..9b0a190b4 100644 --- a/tests/auto/api/testdata/link-dynamiclibs-staticlibs/main.cpp +++ b/tests/auto/api/testdata/link-dynamiclibs-staticlibs/main.cpp @@ -1,11 +1,11 @@ #include "../dllexport.h" -#include <stdio.h> +#include <cstdio> DLL_IMPORT int dynamic1_hello(); int main() { int result = dynamic1_hello(); - puts("application says hello!"); + std::puts("application says hello!"); return result; } diff --git a/tests/auto/api/testdata/link-dynamiclibs-staticlibs/static1.cpp b/tests/auto/api/testdata/link-dynamiclibs-staticlibs/static1.cpp index 81c53bd4e..d07910f96 100644 --- a/tests/auto/api/testdata/link-dynamiclibs-staticlibs/static1.cpp +++ b/tests/auto/api/testdata/link-dynamiclibs-staticlibs/static1.cpp @@ -1,10 +1,10 @@ #include "../dllexport.h" -#include <stdio.h> +#include <cstdio> DLL_IMPORT void dynamic2_hello(); void static1_hello() { dynamic2_hello(); - puts("static1 says hello!"); + std::puts("static1 says hello!"); } diff --git a/tests/auto/api/testdata/link-dynamiclibs-staticlibs/static2.cpp b/tests/auto/api/testdata/link-dynamiclibs-staticlibs/static2.cpp index 073b13609..99a60be0c 100644 --- a/tests/auto/api/testdata/link-dynamiclibs-staticlibs/static2.cpp +++ b/tests/auto/api/testdata/link-dynamiclibs-staticlibs/static2.cpp @@ -1,7 +1,7 @@ #include "static2.h" -#include <stdio.h> +#include <cstdio> void TestMe::hello() const { - puts("static2 says hello!"); + std::puts("static2 says hello!"); } diff --git a/tests/auto/api/testdata/link-dynamiclibs/lib1.cpp b/tests/auto/api/testdata/link-dynamiclibs/lib1.cpp index 14666cf58..e2e943b37 100644 --- a/tests/auto/api/testdata/link-dynamiclibs/lib1.cpp +++ b/tests/auto/api/testdata/link-dynamiclibs/lib1.cpp @@ -27,13 +27,13 @@ ****************************************************************************/ #include "../dllexport.h" -#include <stdio.h> +#include <cstdio> DLL_IMPORT void lib2_hello(); DLL_EXPORT int lib1_hello() { - puts("lib1 says hello!"); + std::puts("lib1 says hello!"); lib2_hello(); return 0; } diff --git a/tests/auto/api/testdata/link-dynamiclibs/lib2.cpp b/tests/auto/api/testdata/link-dynamiclibs/lib2.cpp index 01938b16b..f8bf990a3 100644 --- a/tests/auto/api/testdata/link-dynamiclibs/lib2.cpp +++ b/tests/auto/api/testdata/link-dynamiclibs/lib2.cpp @@ -27,13 +27,13 @@ ****************************************************************************/ #include "../dllexport.h" -#include <stdio.h> +#include <cstdio> DLL_IMPORT void lib3_hello(); DLL_EXPORT void lib2_hello() { - puts("lib2 says hello!"); + std::puts("lib2 says hello!"); lib3_hello(); } diff --git a/tests/auto/api/testdata/link-dynamiclibs/lib3.cpp b/tests/auto/api/testdata/link-dynamiclibs/lib3.cpp index b90a99981..ff2d351ba 100644 --- a/tests/auto/api/testdata/link-dynamiclibs/lib3.cpp +++ b/tests/auto/api/testdata/link-dynamiclibs/lib3.cpp @@ -27,11 +27,11 @@ ****************************************************************************/ #include "../dllexport.h" -#include <stdio.h> +#include <cstdio> DLL_EXPORT void lib3_hello() { - puts("lib3 says hello!"); + std::puts("lib3 says hello!"); } DLL_EXPORT char* lib3_greeting() diff --git a/tests/auto/api/testdata/link-dynamiclibs/lib4.cpp b/tests/auto/api/testdata/link-dynamiclibs/lib4.cpp index 2d66e40f6..ebb97afc9 100644 --- a/tests/auto/api/testdata/link-dynamiclibs/lib4.cpp +++ b/tests/auto/api/testdata/link-dynamiclibs/lib4.cpp @@ -34,10 +34,10 @@ TestMe::TestMe() void TestMe::hello1() const { - puts("lib4 says hello!"); + std::puts("lib4 says hello!"); } void TestMe::hello2Impl() const { - puts("lib4 says hello inline!"); + std::puts("lib4 says hello inline!"); } diff --git a/tests/auto/api/testdata/link-dynamiclibs/lib4.h b/tests/auto/api/testdata/link-dynamiclibs/lib4.h index 63258b2ea..69bde04ec 100644 --- a/tests/auto/api/testdata/link-dynamiclibs/lib4.h +++ b/tests/auto/api/testdata/link-dynamiclibs/lib4.h @@ -30,7 +30,7 @@ #define LIB4_H #include "../dllexport.h" -#include <stdio.h> +#include <cstdio> #ifdef TEST_LIB # define LIB_EXPORT DLL_EXPORT diff --git a/tests/auto/api/testdata/link-dynamiclibs/link-dynamiclibs.qbs b/tests/auto/api/testdata/link-dynamiclibs/link-dynamiclibs.qbs index cc86a4402..e0bce7264 100644 --- a/tests/auto/api/testdata/link-dynamiclibs/link-dynamiclibs.qbs +++ b/tests/auto/api/testdata/link-dynamiclibs/link-dynamiclibs.qbs @@ -17,7 +17,7 @@ Project { Depends { name: "cpp" } Depends { name: "lib2" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } @@ -31,7 +31,7 @@ Project { Depends { name: "cpp" } Depends { name: "lib3" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } @@ -44,7 +44,7 @@ Project { } Depends { name: "cpp" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } @@ -58,13 +58,13 @@ Project { } Depends { name: "cpp" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } Export { Depends { name: "cpp" } - cpp.includePaths: [product.sourceDirectory] + cpp.includePaths: [exportingProduct.sourceDirectory] } } } diff --git a/tests/auto/api/testdata/link-dynamiclibs/main.cpp b/tests/auto/api/testdata/link-dynamiclibs/main.cpp index 64f7948cb..b6165d30f 100644 --- a/tests/auto/api/testdata/link-dynamiclibs/main.cpp +++ b/tests/auto/api/testdata/link-dynamiclibs/main.cpp @@ -26,14 +26,14 @@ ** ****************************************************************************/ -#include <stdio.h> +#include <cstdio> #include <lib4.h> DLL_IMPORT int lib1_hello(); int main() { - puts("application says hello!"); + std::puts("application says hello!"); TestMe test; test.hello1(); test.hello2(); diff --git a/tests/auto/api/testdata/link-static-lib/link-static-lib.qbs b/tests/auto/api/testdata/link-static-lib/link-static-lib.qbs index 6960c7d17..829aa5f3e 100644 --- a/tests/auto/api/testdata/link-static-lib/link-static-lib.qbs +++ b/tests/auto/api/testdata/link-static-lib/link-static-lib.qbs @@ -25,7 +25,7 @@ Project { Depends { name: "helper2" } Export { Depends { name: "cpp" } - cpp.includePaths: [product.sourceDirectory + '/helper1'] + cpp.includePaths: [exportingProduct.sourceDirectory + '/helper1'] } } @@ -38,7 +38,7 @@ Project { Depends { name: "cpp" } Export { Depends { name: "cpp" } - cpp.includePaths: [product.sourceDirectory + '/helper2'] + cpp.includePaths: [exportingProduct.sourceDirectory + '/helper2'] } } } diff --git a/tests/auto/api/testdata/link-static-lib/main.cpp b/tests/auto/api/testdata/link-static-lib/main.cpp index 5f6aed0b9..2d94a4b0b 100644 --- a/tests/auto/api/testdata/link-static-lib/main.cpp +++ b/tests/auto/api/testdata/link-static-lib/main.cpp @@ -26,7 +26,7 @@ ** ****************************************************************************/ -#include <stdio.h> +#include <cstdio> int bla(); diff --git a/tests/auto/api/testdata/link-static-lib/mystaticlib.cpp b/tests/auto/api/testdata/link-static-lib/mystaticlib.cpp index 71777ef05..0b5d02fd4 100644 --- a/tests/auto/api/testdata/link-static-lib/mystaticlib.cpp +++ b/tests/auto/api/testdata/link-static-lib/mystaticlib.cpp @@ -26,12 +26,13 @@ ** ****************************************************************************/ -#include <stdio.h> #include <helper1.h> +#include <cstdio> + int bla() { int n = getSomeNumber(); - printf("Hello World! The magic number is %d.", n); + std::printf("Hello World! The magic number is %d.", n); return n; } diff --git a/tests/auto/api/testdata/link-staticlibs-dynamiclibs/dynamic1.cpp b/tests/auto/api/testdata/link-staticlibs-dynamiclibs/dynamic1.cpp index 3f8a5f8d7..b4379f8c9 100644 --- a/tests/auto/api/testdata/link-staticlibs-dynamiclibs/dynamic1.cpp +++ b/tests/auto/api/testdata/link-staticlibs-dynamiclibs/dynamic1.cpp @@ -1,11 +1,11 @@ #include "../dllexport.h" #include "static2.h" -#include <stdio.h> +#include <cstdio> DLL_EXPORT int dynamic1_hello() { TestMe tm; tm.hello(); - puts("dynamic1 says hello!"); + std::puts("dynamic1 says hello!"); return 1; } diff --git a/tests/auto/api/testdata/link-staticlibs-dynamiclibs/dynamic2.cpp b/tests/auto/api/testdata/link-staticlibs-dynamiclibs/dynamic2.cpp index 75594185e..3511b4759 100644 --- a/tests/auto/api/testdata/link-staticlibs-dynamiclibs/dynamic2.cpp +++ b/tests/auto/api/testdata/link-staticlibs-dynamiclibs/dynamic2.cpp @@ -1,7 +1,7 @@ #include "../dllexport.h" -#include <stdio.h> +#include <cstdio> DLL_EXPORT void dynamic2_hello() { - puts("dynamic2 says hello!"); + std::puts("dynamic2 says hello!"); } diff --git a/tests/auto/api/testdata/link-staticlibs-dynamiclibs/link-staticlibs-dynamiclibs.qbs b/tests/auto/api/testdata/link-staticlibs-dynamiclibs/link-staticlibs-dynamiclibs.qbs index d7ed6c862..c30cf40f9 100644 --- a/tests/auto/api/testdata/link-staticlibs-dynamiclibs/link-staticlibs-dynamiclibs.qbs +++ b/tests/auto/api/testdata/link-staticlibs-dynamiclibs/link-staticlibs-dynamiclibs.qbs @@ -14,9 +14,13 @@ Project { Probe { id: osCheck - property bool isNormalUnix: qbs.targetOS.contains("unix") - && !qbs.targetOS.contains("darwin") - configure: { console.info("is normal unix: " + (isNormalUnix ? "yes" : "no")); } + property bool isNormalUnix: qbs.targetOS.includes("unix") + && !qbs.targetOS.includes("darwin") + property bool isGcc: qbs.toolchain.contains("gcc") + configure: { + console.info("is normal unix: " + (isNormalUnix ? "yes" : "no")); + console.info("is gcc: " + isGcc); + } } } @@ -26,7 +30,7 @@ Project { Depends { name: "cpp" } Depends { name: "static2" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } @@ -44,7 +48,7 @@ Project { Depends { name: "cpp" } cpp.visibility: 'hidden' Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } diff --git a/tests/auto/api/testdata/link-staticlibs-dynamiclibs/main.cpp b/tests/auto/api/testdata/link-staticlibs-dynamiclibs/main.cpp index 4b8193341..b9e522ac4 100644 --- a/tests/auto/api/testdata/link-staticlibs-dynamiclibs/main.cpp +++ b/tests/auto/api/testdata/link-staticlibs-dynamiclibs/main.cpp @@ -1,10 +1,10 @@ -#include <stdio.h> +#include <cstdio> void static1_hello(); int main() { static1_hello(); - puts("application says hello!"); + std::puts("application says hello!"); return 0; } diff --git a/tests/auto/api/testdata/link-staticlibs-dynamiclibs/static1.cpp b/tests/auto/api/testdata/link-staticlibs-dynamiclibs/static1.cpp index a3058c63b..320344f91 100644 --- a/tests/auto/api/testdata/link-staticlibs-dynamiclibs/static1.cpp +++ b/tests/auto/api/testdata/link-staticlibs-dynamiclibs/static1.cpp @@ -1,10 +1,11 @@ #include "../dllexport.h" -#include <stdio.h> + +#include <cstdio> DLL_IMPORT int dynamic1_hello(); void static1_hello() { int n = dynamic1_hello(); - printf("static%d says hello!\n", n); + std::printf("static%d says hello!\n", n); } diff --git a/tests/auto/api/testdata/link-staticlibs-dynamiclibs/static2.cpp b/tests/auto/api/testdata/link-staticlibs-dynamiclibs/static2.cpp index 374bf7ceb..88c6d2a3f 100644 --- a/tests/auto/api/testdata/link-staticlibs-dynamiclibs/static2.cpp +++ b/tests/auto/api/testdata/link-staticlibs-dynamiclibs/static2.cpp @@ -1,11 +1,11 @@ #include "../dllexport.h" #include "static2.h" -#include <stdio.h> +#include <cstdio> DLL_IMPORT void dynamic2_hello(); void TestMe::hello() const { dynamic2_hello(); - puts("static2 says hello!"); + std::puts("static2 says hello!"); } diff --git a/tests/auto/api/testdata/lots-of-dots/m.a.i.n.cpp b/tests/auto/api/testdata/lots-of-dots/m.a.i.n.cpp index 427f9907d..e1701dc47 100644 --- a/tests/auto/api/testdata/lots-of-dots/m.a.i.n.cpp +++ b/tests/auto/api/testdata/lots-of-dots/m.a.i.n.cpp @@ -33,6 +33,6 @@ int main() { ObjectNarf obj; - puts("..."); + std::puts("..."); } diff --git a/tests/auto/api/testdata/moc-hpp-included/moc-hpp-included.qbs b/tests/auto/api/testdata/moc-hpp-included/moc-hpp-included.qbs index a484b9c22..38d3d88ca 100644 --- a/tests/auto/api/testdata/moc-hpp-included/moc-hpp-included.qbs +++ b/tests/auto/api/testdata/moc-hpp-included/moc-hpp-included.qbs @@ -11,7 +11,7 @@ Project { files: ["object.cpp", "object.h"] Group { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") files: ["object2.mm", "object2.h"] } } diff --git a/tests/auto/api/testdata/moc-hpp-included/object.cpp b/tests/auto/api/testdata/moc-hpp-included/object.cpp index 4f1502af5..dd0b237cf 100644 --- a/tests/auto/api/testdata/moc-hpp-included/object.cpp +++ b/tests/auto/api/testdata/moc-hpp-included/object.cpp @@ -38,6 +38,6 @@ Object::Object(QObject *parent) int main() { Object obj; - printf("Hello World\n"); + std::printf("Hello World\n"); } diff --git a/tests/auto/api/testdata/moc-hpp/object.cpp b/tests/auto/api/testdata/moc-hpp/object.cpp index 601893c34..4c0e59393 100644 --- a/tests/auto/api/testdata/moc-hpp/object.cpp +++ b/tests/auto/api/testdata/moc-hpp/object.cpp @@ -36,6 +36,6 @@ Object::Object(QObject *parent) int main() { Object obj; - printf("Hello World\n"); + std::printf("Hello World\n"); } diff --git a/tests/auto/api/testdata/multiplexing/multiplexing.qbs b/tests/auto/api/testdata/multiplexing/multiplexing.qbs index 243c73d46..75958ed60 100644 --- a/tests/auto/api/testdata/multiplexing/multiplexing.qbs +++ b/tests/auto/api/testdata/multiplexing/multiplexing.qbs @@ -74,6 +74,13 @@ Project { qbs.architectures: ["TRS-80", "C64"] qbs.buildVariants: ["debug", "release"] } + Product { + name: "multiplex-without-aggregator-4-depends-2" + multiplexByQbsProperties: ["architectures", "buildVariants"] + qbs.architectures: ["TRS-80", "C64"] + qbs.buildVariants: ["debug", "release"] + Depends { name: "multiplex-without-aggregator-2" } + } } Product { diff --git a/tests/auto/api/testdata/new-output-artifact-in-dependency/new-output-artifact-in-dependency.qbs b/tests/auto/api/testdata/new-output-artifact-in-dependency/new-output-artifact-in-dependency.qbs index 5c3e475b0..e87af67c7 100644 --- a/tests/auto/api/testdata/new-output-artifact-in-dependency/new-output-artifact-in-dependency.qbs +++ b/tests/auto/api/testdata/new-output-artifact-in-dependency/new-output-artifact-in-dependency.qbs @@ -4,7 +4,7 @@ Project { name: "lib" files: "lib.cpp" Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } diff --git a/tests/auto/api/testdata/objc/objc.qbs b/tests/auto/api/testdata/objc/objc.qbs index 845eb8d32..2fba48d9b 100644 --- a/tests/auto/api/testdata/objc/objc.qbs +++ b/tests/auto/api/testdata/objc/objc.qbs @@ -1,6 +1,6 @@ Project { CppApplication { - condition: qbs.targetOS.contains("macos") + condition: qbs.targetOS.includes("macos") files: "main.mm" cpp.frameworks: [ "Foundation" ] } diff --git a/tests/auto/api/testdata/precompiled-header-dynamic/precompiled-header-dynamic.qbs b/tests/auto/api/testdata/precompiled-header-dynamic/precompiled-header-dynamic.qbs index 2fd58d24e..1b0728669 100644 --- a/tests/auto/api/testdata/precompiled-header-dynamic/precompiled-header-dynamic.qbs +++ b/tests/auto/api/testdata/precompiled-header-dynamic/precompiled-header-dynamic.qbs @@ -21,7 +21,7 @@ CppApplication { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Generating " + output.fileName; + cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); } return [cmd]; } diff --git a/tests/auto/api/testdata/process-result/process-result.qbs b/tests/auto/api/testdata/process-result/process-result.qbs index 84706ace8..dc9ff2839 100644 --- a/tests/auto/api/testdata/process-result/process-result.qbs +++ b/tests/auto/api/testdata/process-result/process-result.qbs @@ -1,9 +1,18 @@ +import qbs.Host + Project { CppApplication { name: "app" + consoleApplication: true files: ["main.cpp"] } Product { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: "app-caller" type: "mytype" Depends { name: "app" } @@ -20,7 +29,7 @@ Project { cmd.stdoutFilePath = product.buildDirectory + "/stdout.txt"; if (product.redirectStderr) cmd.stderrFilePath = product.buildDirectory + "/stderr.txt"; - cmd.description = "Building app-caller"; + cmd.description = "building app-caller"; return [cmd]; } } diff --git a/tests/auto/api/testdata/project-with-properties-item/project-with-properties-item.qbs b/tests/auto/api/testdata/project-with-properties-item/project-with-properties-item.qbs index 866ec4ecb..812c6a65e 100644 --- a/tests/auto/api/testdata/project-with-properties-item/project-with-properties-item.qbs +++ b/tests/auto/api/testdata/project-with-properties-item/project-with-properties-item.qbs @@ -3,7 +3,7 @@ Project { property string libPath: "/usr/lib" Properties { - condition: qbs.targetOS.contains("macos") + condition: qbs.targetOS.includes("macos") binPath: "/Users/boo" libPath: "/Libraries/foo" } diff --git a/tests/auto/api/testdata/properties-blocks/main.cpp b/tests/auto/api/testdata/properties-blocks/main.cpp index 5473bffa7..a01a5850e 100644 --- a/tests/auto/api/testdata/properties-blocks/main.cpp +++ b/tests/auto/api/testdata/properties-blocks/main.cpp @@ -26,7 +26,7 @@ ** ****************************************************************************/ -#include <stdio.h> +#include <cstdio> #ifndef HAVE_MAIN_CPP # error missing define HAVE_MAIN_CPP @@ -38,9 +38,8 @@ int main() { #ifdef _DEBUG - puts("Hello World! (debug version)"); + std::puts("Hello World! (debug version)"); #else - puts("Hello World! (release version)"); + std::puts("Hello World! (release version)"); #endif } - diff --git a/tests/auto/api/testdata/properties-blocks/properties-blocks.qbs b/tests/auto/api/testdata/properties-blocks/properties-blocks.qbs index dda4652d2..c234a6b41 100644 --- a/tests/auto/api/testdata/properties-blocks/properties-blocks.qbs +++ b/tests/auto/api/testdata/properties-blocks/properties-blocks.qbs @@ -14,7 +14,7 @@ Product { } Properties { - condition: qbs.targetOS.contains("weird") + condition: qbs.targetOS.includes("weird") cpp.staticLibraries: "abc" } diff --git a/tests/auto/api/testdata/qt5-plugin/qt5-plugin.qbs b/tests/auto/api/testdata/qt5-plugin/qt5-plugin.qbs index 204711625..1558e3bc9 100644 --- a/tests/auto/api/testdata/qt5-plugin/qt5-plugin.qbs +++ b/tests/auto/api/testdata/qt5-plugin/qt5-plugin.qbs @@ -1,4 +1,3 @@ -import qbs.base import qbs.File import qbs.FileInfo @@ -8,7 +7,7 @@ DynamicLibrary { Depends { name: "Qt.core" } Depends { name: "cpp" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } diff --git a/tests/auto/api/testdata/remove-file-dependency/main.cpp b/tests/auto/api/testdata/remove-file-dependency/main.cpp index 5c0b03938..47cd716d7 100644 --- a/tests/auto/api/testdata/remove-file-dependency/main.cpp +++ b/tests/auto/api/testdata/remove-file-dependency/main.cpp @@ -31,7 +31,7 @@ int main() { - printf("The magic value is %d.\n", magicValue()); + std::printf("The magic value is %d.\n", magicValue()); return 0; } diff --git a/tests/auto/api/testdata/rename-product/rename.qbs b/tests/auto/api/testdata/rename-product/rename.qbs index 9d23bf804..aa59d9650 100644 --- a/tests/auto/api/testdata/rename-product/rename.qbs +++ b/tests/auto/api/testdata/rename-product/rename.qbs @@ -11,7 +11,7 @@ Project { cpp.defines: "MY_EXPORT=DLL_EXPORT" files: "lib.cpp" Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } diff --git a/tests/auto/api/testdata/rename-target-artifact/rename.qbs b/tests/auto/api/testdata/rename-target-artifact/rename.qbs index 810b0eb08..aea4b8d9e 100644 --- a/tests/auto/api/testdata/rename-target-artifact/rename.qbs +++ b/tests/auto/api/testdata/rename-target-artifact/rename.qbs @@ -14,7 +14,7 @@ Project { qbs.buildVariant: "release" files: "lib.cpp" Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } diff --git a/tests/auto/api/testdata/renamed-qbs-source-file/renamed-qbs-source-file.qbs b/tests/auto/api/testdata/renamed-qbs-source-file/renamed-qbs-source-file.qbs new file mode 100644 index 000000000..d295d43ea --- /dev/null +++ b/tests/auto/api/testdata/renamed-qbs-source-file/renamed-qbs-source-file.qbs @@ -0,0 +1,9 @@ +Project { + references: "the-product/the-prodduct.qbs" + Product { + Group { + files: "the-product/*.qbs" + fileTags: [] + } + } +} diff --git a/tests/auto/api/testdata/renamed-qbs-source-file/the-product/the-prodduct.qbs b/tests/auto/api/testdata/renamed-qbs-source-file/the-product/the-prodduct.qbs new file mode 100644 index 000000000..86718b571 --- /dev/null +++ b/tests/auto/api/testdata/renamed-qbs-source-file/the-product/the-prodduct.qbs @@ -0,0 +1 @@ +Product { } diff --git a/tests/auto/api/testdata/restored-warnings/restored-warnings.qbs b/tests/auto/api/testdata/restored-warnings/restored-warnings.qbs index bbdfbeadb..9d4abb757 100644 --- a/tests/auto/api/testdata/restored-warnings/restored-warnings.qbs +++ b/tests/auto/api/testdata/restored-warnings/restored-warnings.qbs @@ -1,14 +1,25 @@ import qbs.Process 1.5 -CppApplication { - name: "theProduct" +Project { + CppApplication { + name: "theProduct" - property bool moreFiles: false - cpp.blubb: true + cpp.blubb: true - files: ["file.cpp", "main.cpp"] - Group { - condition: moreFiles - files: ["blubb.cpp"] + files: ["file.cpp", "main.cpp"] + } + + Product { + name: "theOtherProduct" + property bool dummy: { throw "this one comes from a thread"; } + } + + Product { + name: "aThirdProduct" + property bool moreFiles: false + Group { + condition: moreFiles + files: ["blubb.txt"] + } } } diff --git a/tests/auto/api/testdata/same-base-name/same-base-name.qbs b/tests/auto/api/testdata/same-base-name/same-base-name.qbs index 8448d04fd..ba0adfaac 100644 --- a/tests/auto/api/testdata/same-base-name/same-base-name.qbs +++ b/tests/auto/api/testdata/same-base-name/same-base-name.qbs @@ -16,7 +16,7 @@ Project { ] Group { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") files: [ "lib.m", "lib.mm" @@ -25,7 +25,7 @@ Project { Export { Depends { name: "cpp" } - cpp.frameworks: qbs.targetOS.contains("darwin") ? "Foundation" : undefined + cpp.frameworks: qbs.targetOS.includes("darwin") ? "Foundation" : undefined } } } diff --git a/tests/auto/api/testdata/static-lib-deps/static-lib-deps.qbs b/tests/auto/api/testdata/static-lib-deps/static-lib-deps.qbs index b584b4d41..67800b8eb 100644 --- a/tests/auto/api/testdata/static-lib-deps/static-lib-deps.qbs +++ b/tests/auto/api/testdata/static-lib-deps/static-lib-deps.qbs @@ -44,23 +44,23 @@ Project { ] Group { - condition: qbs.targetOS.contains("macos") + condition: qbs.targetOS.includes("macos") files: ["d.mm"] } Properties { - condition: qbs.targetOS.contains("windows") + condition: qbs.targetOS.includes("windows") cpp.defines: ["WITH_SETUPAPI"] cpp.staticLibraries: ["setupapi"] } Properties { - condition: qbs.targetOS.contains("macos") + condition: qbs.targetOS.includes("macos") cpp.defines: ["WITH_LEX_YACC"] cpp.staticLibraries: ["l", "y"] cpp.frameworks: ["Foundation"] } Properties { - condition: qbs.targetOS.contains("linux") + condition: qbs.targetOS.includes("linux") cpp.defines: ["WITH_PTHREAD"] cpp.staticLibraries: ["pthread"] } @@ -84,7 +84,7 @@ Project { Depends { name: "e" } Properties { - condition: qbs.targetOS.contains("linux") + condition: qbs.targetOS.includes("linux") cpp.driverFlags: ["-static"] } diff --git a/tests/auto/api/testdata/timeout-js/timeout.qbs b/tests/auto/api/testdata/timeout-js/timeout.qbs index 26aa4ce87..72c72573b 100644 --- a/tests/auto/api/testdata/timeout-js/timeout.qbs +++ b/tests/auto/api/testdata/timeout-js/timeout.qbs @@ -8,7 +8,7 @@ Product { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Running infinite loop"; + cmd.description = "running infinite loop"; cmd.sourceCode = function() { while (true) ; diff --git a/tests/auto/api/testdata/timeout-process/timeout.qbs b/tests/auto/api/testdata/timeout-process/timeout.qbs index bb8deac9b..403506eed 100644 --- a/tests/auto/api/testdata/timeout-process/timeout.qbs +++ b/tests/auto/api/testdata/timeout-process/timeout.qbs @@ -1,3 +1,5 @@ +import qbs.Host + Project { CppApplication { type: "application" @@ -7,25 +9,31 @@ Project { cpp.cxxLanguageVersion: "c++11" cpp.minimumOsxVersion: "10.8" // For <chrono> Properties { - condition: qbs.toolchain.contains("gcc") + condition: qbs.toolchain.includes("gcc") cpp.driverFlags: "-pthread" } } Product { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } type: "product-under-test" name: "caller" Depends { name: "infinite-loop" } Depends { name: "cpp" // Make sure build environment is set up properly. - condition: qbs.hostOS.contains("windows") && qbs.toolchain.contains("gcc") + condition: Host.os().includes("windows") && qbs.toolchain.includes("gcc") } Rule { inputsFromDependencies: "application" outputFileTags: "product-under-test" prepare: { var cmd = new Command(inputs["application"][0].filePath); - cmd.description = "Calling application that runs forever"; + cmd.description = "calling application that runs forever"; cmd.timeout = 3; return cmd; } diff --git a/tests/auto/api/testdata/tool-in-module/use-outside-project/modules/thetool/thetool.qbs b/tests/auto/api/testdata/tool-in-module/use-outside-project/modules/thetool/thetool.qbs index d72ebda17..e2b1ec6df 100644 --- a/tests/auto/api/testdata/tool-in-module/use-outside-project/modules/thetool/thetool.qbs +++ b/tests/auto/api/testdata/tool-in-module/use-outside-project/modules/thetool/thetool.qbs @@ -1,11 +1,12 @@ import qbs.FileInfo +import qbs.Host Module { Depends { name: "cpp" } Group { name: "thetool binary" files: FileInfo.cleanPath(FileInfo.joinPaths(path, "..", "..", - "thetool" + (qbs.hostOS.contains("windows") ? ".exe" : ""))); + "thetool" + (Host.os().includes("windows") ? ".exe" : ""))); fileTags: ["thetool.thetool"] filesAreTargets: true } diff --git a/tests/auto/api/testdata/tool-in-module/use-within-project/use-within-project.qbs b/tests/auto/api/testdata/tool-in-module/use-within-project/use-within-project.qbs index 575f4020e..ab4e07170 100644 --- a/tests/auto/api/testdata/tool-in-module/use-within-project/use-within-project.qbs +++ b/tests/auto/api/testdata/tool-in-module/use-within-project/use-within-project.qbs @@ -1,9 +1,18 @@ +import qbs.Host + Project { CppApplication { name: "thetool" consoleApplication: true files: "main.cpp" + property bool skip: { + var result = qbs.targetPlatform !== Host.platform(); + if (result) + console.info("Skip this test"); + return result; + } + install: true installDir: "" qbs.installPrefix: "" diff --git a/tests/auto/api/testdata/transformer-data/transformer-data.qbs b/tests/auto/api/testdata/transformer-data/transformer-data.qbs index f9433ed73..d29dbdbae 100644 --- a/tests/auto/api/testdata/transformer-data/transformer-data.qbs +++ b/tests/auto/api/testdata/transformer-data/transformer-data.qbs @@ -11,7 +11,7 @@ Product { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Creating " + output.fileName; + cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); @@ -27,7 +27,7 @@ Product { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Creating " + output.fileName; + cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }; return [cmd]; } diff --git a/tests/auto/api/testdata/two-default-property-values/modules/mymodule/mymodule.qbs b/tests/auto/api/testdata/two-default-property-values/modules/mymodule/mymodule.qbs index 8ac7b75a3..67f34ed66 100644 --- a/tests/auto/api/testdata/two-default-property-values/modules/mymodule/mymodule.qbs +++ b/tests/auto/api/testdata/two-default-property-values/modules/mymodule/mymodule.qbs @@ -12,7 +12,7 @@ Module { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Creating " + output.fileName; + cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); diff --git a/tests/auto/api/tst_api.cpp b/tests/auto/api/tst_api.cpp index 235f2ac04..45463312b 100644 --- a/tests/auto/api/tst_api.cpp +++ b/tests/auto/api/tst_api.cpp @@ -144,7 +144,7 @@ static bool waitForFinished(qbs::AbstractJob *job, int timeout = 0) TestApi::TestApi() : m_logSink(new LogSink) - , m_sourceDataDir(QDir::cleanPath(SRCDIR "/testdata")) + , m_sourceDataDir(testDataSourceDir(SRCDIR "/testdata")) , m_workingDataDir(testWorkDir(QStringLiteral("api"))) { } @@ -196,7 +196,7 @@ void TestApi::addedFilePersistent() // On the initial run, linking will fail. const QString relProjectFilePath = "added-file-persistent"; ProcessResultReceiver receiver; - qbs::ErrorInfo errorInfo = doBuildProject(relProjectFilePath, 0, &receiver); + qbs::ErrorInfo errorInfo = doBuildProject(relProjectFilePath, nullptr, &receiver); QVERIFY(errorInfo.hasError()); QVERIFY2(isAboutUndefinedSymbols(receiver.output), qPrintable((receiver.output))); receiver.output.clear(); @@ -206,7 +206,7 @@ void TestApi::addedFilePersistent() const qbs::SetupProjectParameters params = defaultSetupParameters(relProjectFilePath); REPLACE_IN_FILE(params.projectFilePath(), "/* 'file.cpp' */", "'file.cpp'"); std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(params, m_logSink, - 0)); + nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); setupJob.reset(nullptr); @@ -215,14 +215,14 @@ void TestApi::addedFilePersistent() // Consequently, the linking step must fail as in the initial run. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(params.projectFilePath(), "'file.cpp'", "/* 'file.cpp' */"); - errorInfo = doBuildProject(relProjectFilePath, 0, &receiver); + errorInfo = doBuildProject(relProjectFilePath, nullptr, &receiver); QVERIFY(errorInfo.hasError()); QVERIFY2(isAboutUndefinedSymbols(receiver.output), qPrintable((receiver.output))); // Add the file again. qbs must schedule it for rule application on the next build. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(params.projectFilePath(), "/* 'file.cpp' */", "'file.cpp'"); - setupJob.reset(qbs::Project().setupProject(params, m_logSink, 0)); + setupJob.reset(qbs::Project().setupProject(params, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); setupJob.reset(nullptr); @@ -249,7 +249,7 @@ void TestApi::buildGraphInfo() setupParams.setTopLevelProfile(p.p.name()); setupParams.setOverriddenValues({std::make_pair("qbs.architecture", "arm")}); std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); const QString bgFilePath = setupParams.buildRoot() + QLatin1Char('/') @@ -295,14 +295,14 @@ void TestApi::buildGraphLocking() qbs::SetupProjectParameters setupParams = defaultSetupParameters("buildgraph-locking"); std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); const qbs::Project project = setupJob->project(); Q_UNUSED(project); // Case 1: Setting up a competing project from scratch. - setupJob.reset(qbs::Project().setupProject(setupParams, m_logSink, 0)); + setupJob.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY(setupJob->error().hasError()); QVERIFY2(setupJob->error().toString().contains("lock"), @@ -311,7 +311,7 @@ void TestApi::buildGraphLocking() // Case 2: Setting up a non-competing project and then making it competing. qbs::SetupProjectParameters setupParams2 = setupParams; setupParams2.setBuildRoot(setupParams.buildRoot() + "/2"); - setupJob.reset(qbs::Project().setupProject(setupParams2, m_logSink, 0)); + setupJob.reset(qbs::Project().setupProject(setupParams2, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); const QString buildDirName = relativeBuildDir(setupParams2.configurationName()); @@ -320,7 +320,7 @@ void TestApi::buildGraphLocking() QVERIFY2(QFileInfo(lockFile).isFile(), qPrintable(lockFile)); qbs::Project project2 = setupJob->project(); QVERIFY(project2.isValid()); - setupJob.reset(project2.setupProject(setupParams, m_logSink, 0)); + setupJob.reset(project2.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY(setupJob->error().hasError()); QVERIFY2(setupJob->error().toString().contains("lock"), @@ -330,7 +330,7 @@ void TestApi::buildGraphLocking() // Case 3: Changing the build directory of an existing project to something non-competing. qbs::SetupProjectParameters setupParams3 = setupParams2; setupParams3.setBuildRoot(setupParams.buildRoot() + "/3"); - setupJob.reset(qbs::Project().setupProject(setupParams3, m_logSink, 0)); + setupJob.reset(qbs::Project().setupProject(setupParams3, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); project2 = qbs::Project(); @@ -342,7 +342,7 @@ void TestApi::buildGraphLocking() QVERIFY(project3.isValid()); // Case 4: Changing the build directory again, but cancelling the job. - setupJob.reset(project3.setupProject(setupParams2, m_logSink, 0)); + setupJob.reset(project3.setupProject(setupParams2, m_logSink, nullptr)); QThread::sleep(1); setupJob->cancel(); waitForFinished(setupJob.get()); @@ -362,7 +362,10 @@ void TestApi::buildProject() + QLatin1String(".qbs"); qbs::SetupProjectParameters params = defaultSetupParameters(projectFilePath); removeBuildDir(params); - qbs::ErrorInfo errorInfo = doBuildProject(projectFilePath); + ProcessResultReceiver resultReceiver; + qbs::ErrorInfo errorInfo = doBuildProject(projectFilePath, nullptr, &resultReceiver); + if (resultReceiver.output.contains("mingw32_gt_pch_use_address")) + QSKIP("https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91440"); VERIFY_NO_ERROR(errorInfo); QVERIFY(regularFileExists(relativeBuildGraphFilePath())); if (!productFileName.isEmpty()) { @@ -373,7 +376,7 @@ void TestApi::buildProject() WAIT_FOR_NEW_TIMESTAMP(); qbs::BuildOptions options; options.setForceTimestampCheck(true); - errorInfo = doBuildProject(projectFilePath, 0, 0, 0, options); + errorInfo = doBuildProject(projectFilePath, nullptr, nullptr, nullptr, options); VERIFY_NO_ERROR(errorInfo); if (!productFileName.isEmpty()) QVERIFY2(regularFileExists(productFileName), qPrintable(productFileName)); @@ -457,7 +460,7 @@ void TestApi::buildProjectDryRun() removeBuildDir(params); qbs::BuildOptions options; options.setDryRun(true); - const qbs::ErrorInfo errorInfo = doBuildProject(projectFilePath, 0, 0, 0, options); + const qbs::ErrorInfo errorInfo = doBuildProject(projectFilePath, nullptr, nullptr, nullptr, options); VERIFY_NO_ERROR(errorInfo); QVERIFY2(!QFileInfo::exists(relativeBuildDir()), qPrintable(QDir(relativeBuildDir()) .entryList(QDir::NoDotAndDotDot | QDir::AllEntries | QDir::System).join(", "))); @@ -473,7 +476,7 @@ void TestApi::buildSingleFile() qbs::SetupProjectParameters setupParams = defaultSetupParameters("build-single-file"); std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); @@ -483,9 +486,14 @@ void TestApi::buildSingleFile() m_logSink->setLogLevel(qbs::LoggerMaxLevel); std::unique_ptr<qbs::BuildJob> buildJob(project.buildAllProducts(options)); BuildDescriptionReceiver receiver; + ProcessResultReceiver resultReceiver; + connect(buildJob.get(), &qbs::BuildJob::reportProcessResult, + &resultReceiver, &ProcessResultReceiver::handleProcessResult); connect(buildJob.get(), &qbs::BuildJob::reportCommandDescription, &receiver, &BuildDescriptionReceiver::handleDescription); waitForFinished(buildJob.get()); + if (resultReceiver.output.contains("mingw32_gt_pch_use_address")) + QSKIP("https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91440"); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); QCOMPARE(receiver.descriptions.count("compiling"), 2); QCOMPARE(receiver.descriptions.count("precompiling"), 1); @@ -502,6 +510,8 @@ void TestApi::canonicalToolchainList() QStringList({"xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"clang", "llvm", "gcc"})), QStringList({"clang", "llvm", "gcc"})); + QCOMPARE(qbs::canonicalToolchain(QStringList({"clang-cl", "msvc"})), + QStringList({"clang-cl", "msvc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"llvm", "gcc"})), QStringList({"llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"mingw", "gcc"})), @@ -516,6 +526,8 @@ void TestApi::canonicalToolchainList() QStringList({"xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"clang"})), QStringList({"clang", "llvm", "gcc"})); + QCOMPARE(qbs::canonicalToolchain(QStringList({"clang-cl"})), + QStringList({"clang-cl", "msvc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"llvm"})), QStringList({"llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"mingw"})), @@ -592,7 +604,7 @@ void TestApi::checkOutputs() qbs::BuildOptions options; options.setForceOutputCheck(check); removeBuildDir(params); - qbs::ErrorInfo errorInfo = doBuildProject("/check-outputs", 0, 0, 0, options); + qbs::ErrorInfo errorInfo = doBuildProject("/check-outputs", nullptr, nullptr, nullptr, options); if (check) QVERIFY(errorInfo.hasError()); else @@ -616,37 +628,29 @@ qbs::GroupData findGroup(const qbs::ProductData &product, const QString &name) return qbs::GroupData(); } -#ifdef QBS_ENABLE_PROJECT_FILE_UPDATES - static qbs::Project::ProductSelection defaultProducts() { return qbs::Project::ProductSelectionDefaultOnly; } -static void printProjectData(const qbs::ProjectData &project) -{ - const auto products = project.products(); - for (const qbs::ProductData &p : products) { - qDebug(" Product '%s' at %s", qPrintable(p.name()), qPrintable(p.location().toString())); - const auto groups = p.groups(); - for (const qbs::GroupData &g : groups) { - qDebug(" Group '%s' at %s", qPrintable(g.name()), qPrintable(g.location().toString())); - qDebug(" Files: %s", qPrintable(g.allFilePaths().join(QLatin1String(", ")))); - } - } -} - void TestApi::changeContent() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("project-editing"); - std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, - m_logSink, 0)); - waitForFinished(job.get()); - QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); - qbs::Project project = job->project(); - qbs::ProjectData projectData = project.projectData(); - QCOMPARE(projectData.allProducts().size(), 1); - qbs::ProductData product = projectData.allProducts().front(); + std::unique_ptr<qbs::SetupProjectJob> job; + qbs::Project project; + qbs::ProjectData projectData; + qbs::ProductData product; + + const auto resolve = [&] { + job.reset(project.setupProject(setupParams, m_logSink, 0)); + waitForFinished(job.get()); + QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); + project = job->project(); + projectData = project.projectData(); + QCOMPARE(projectData.allProducts().size(), 1); + product = projectData.allProducts().front(); + }; + resolve(); QVERIFY(product.groups().size() >= 8); // Error handling: Invalid product. @@ -659,12 +663,16 @@ void TestApi::changeContent() QVERIFY(errorInfo.hasError()); QVERIFY(errorInfo.toString().contains("empty")); + WAIT_FOR_NEW_TIMESTAMP(); errorInfo = project.addGroup(product, "New Group 1"); VERIFY_NO_ERROR(errorInfo); errorInfo = project.addGroup(product, "New Group 2"); VERIFY_NO_ERROR(errorInfo); + resolve(); + QVERIFY(product.groups().size() >= 10); + // Error handling: Group already inserted. errorInfo = project.addGroup(product, "New Group 1"); QVERIFY(errorInfo.hasError()); @@ -677,20 +685,14 @@ void TestApi::changeContent() QVERIFY2(errorInfo.toString().contains("more than once"), qPrintable(errorInfo.toString())); // Add files to empty array literal. - projectData = project.projectData(); - QVERIFY(projectData.products().size() == 1); - product = projectData.products().front(); - QVERIFY(product.groups().size() >= 10); + WAIT_FOR_NEW_TIMESTAMP(); qbs::GroupData group = findGroup(product, "New Group 1"); QVERIFY(group.isValid()); errorInfo = project.addFiles(product, group, QStringList() << "file.h" << "file.cpp"); VERIFY_NO_ERROR(errorInfo); // Error handling: Add the same file again. - projectData = project.projectData(); - QVERIFY(projectData.products().size() == 1); - product = projectData.products().front(); - QVERIFY(product.groups().size() >= 10); + resolve(); group = findGroup(product, "New Group 1"); QVERIFY(group.isValid()); errorInfo = project.addFiles(product, group, QStringList() << "file.cpp"); @@ -698,14 +700,12 @@ void TestApi::changeContent() QVERIFY2(errorInfo.toString().contains("already"), qPrintable(errorInfo.toString())); // Remove one of the newly added files again. + WAIT_FOR_NEW_TIMESTAMP(); errorInfo = project.removeFiles(product, group, QStringList("file.h")); VERIFY_NO_ERROR(errorInfo); // Error handling: Try to remove the same file again. - projectData = project.projectData(); - QVERIFY(projectData.products().size() == 1); - product = projectData.products().front(); - QVERIFY(product.groups().size() >= 10); + resolve(); group = findGroup(product, "New Group 1"); QVERIFY(group.isValid()); errorInfo = project.removeFiles(product, group, QStringList() << "file.h"); @@ -720,38 +720,34 @@ void TestApi::changeContent() QVERIFY2(errorInfo.toString().contains("complex"), qPrintable(errorInfo.toString())); // Remove file from product's 'files' binding. + WAIT_FOR_NEW_TIMESTAMP(); errorInfo = project.removeFiles(product, qbs::GroupData(), QStringList("main.cpp")); VERIFY_NO_ERROR(errorInfo); + resolve(); // Add file to non-empty array literal. - projectData = project.projectData(); - QVERIFY(projectData.products().size() == 1); - product = projectData.products().front(); + WAIT_FOR_NEW_TIMESTAMP(); group = findGroup(product, "Existing Group 1"); QVERIFY(group.isValid()); errorInfo = project.addFiles(product, group, QStringList() << "newfile1.txt"); VERIFY_NO_ERROR(errorInfo); + resolve(); // Add files to list represented as a single string. - projectData = project.projectData(); - QVERIFY(projectData.products().size() == 1); - product = projectData.products().front(); + WAIT_FOR_NEW_TIMESTAMP(); errorInfo = project.addFiles(product, qbs::GroupData(), QStringList() << "newfile2.txt"); VERIFY_NO_ERROR(errorInfo); + resolve(); // Add files to list represented as an identifier. - projectData = project.projectData(); - QVERIFY(projectData.products().size() == 1); - product = projectData.products().front(); + WAIT_FOR_NEW_TIMESTAMP(); group = findGroup(product, "Existing Group 2"); QVERIFY(group.isValid()); errorInfo = project.addFiles(product, group, QStringList() << "newfile3.txt"); VERIFY_NO_ERROR(errorInfo); + resolve(); // Add files to list represented as a block of code (not yet implemented). - projectData = project.projectData(); - QVERIFY(projectData.products().size() == 1); - product = projectData.products().front(); group = findGroup(product, "Existing Group 3"); QVERIFY(group.isValid()); errorInfo = project.addFiles(product, group, QStringList() << "newfile4.txt"); @@ -759,18 +755,14 @@ void TestApi::changeContent() QVERIFY2(errorInfo.toString().contains("complex"), qPrintable(errorInfo.toString())); // Add file to group with directory prefix. - projectData = project.projectData(); - QVERIFY(projectData.products().size() == 1); - product = projectData.products().front(); + WAIT_FOR_NEW_TIMESTAMP(); group = findGroup(product, "Existing Group 4"); QVERIFY(group.isValid()); errorInfo = project.addFiles(product, group, QStringList() << "file.txt"); VERIFY_NO_ERROR(errorInfo); + resolve(); // Error handling: Add file to group with non-directory prefix. - projectData = project.projectData(); - QVERIFY(projectData.products().size() == 1); - product = projectData.products().front(); group = findGroup(product, "Existing Group 5"); QVERIFY(group.isValid()); errorInfo = project.addFiles(product, group, QStringList() << "newfile1.txt"); @@ -778,16 +770,12 @@ void TestApi::changeContent() QVERIFY2(errorInfo.toString().contains("prefix"), qPrintable(errorInfo.toString())); // Remove group. - projectData = project.projectData(); - QVERIFY(projectData.products().size() == 1); - product = projectData.products().front(); + WAIT_FOR_NEW_TIMESTAMP(); group = findGroup(product, "Existing Group 5"); QVERIFY(group.isValid()); errorInfo = project.removeGroup(product, group); VERIFY_NO_ERROR(errorInfo); - projectData = project.projectData(); - QVERIFY(projectData.products().size() == 1); - QVERIFY(projectData.products().front().groups().size() >= 9); + resolve(); // Error handling: Try to remove the same group again. errorInfo = project.removeGroup(product, group); @@ -805,9 +793,7 @@ void TestApi::changeContent() newFile.close(); errorInfo = project.addFiles(product, group, QStringList() << newFile.fileName()); VERIFY_NO_ERROR(errorInfo); - projectData = project.projectData(); - QVERIFY(projectData.products().size() == 1); - product = projectData.products().front(); + resolve(); group = findGroup(product, "Group with wildcards"); QVERIFY(group.isValid()); QCOMPARE(group.sourceArtifactsFromWildcards().size(), 1); @@ -838,46 +824,13 @@ void TestApi::changeContent() QVERIFY(rcvr.descriptions.contains("compiling file.cpp")); QVERIFY(!rcvr.descriptions.contains("compiling main.cpp")); - // Now check whether the data updates were done correctly. - projectData = project.projectData(); - job.reset(project.setupProject(setupParams, m_logSink, 0)); - waitForFinished(job.get()); - QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); - project = job->project(); - qbs::ProjectData newProjectData = project.projectData(); - - // Can't use Project::operator== here, as the target artifacts will differ due to the build - // not having run yet. - bool projectDataMatches = newProjectData.products().size() == 1 - && projectData.products().size() == 1 - && newProjectData.products().front().groups() == projectData.products().front().groups(); - if (!projectDataMatches) { - qDebug("This is the assumed project:"); - printProjectData(projectData); - qDebug("This is the actual project:"); - printProjectData(newProjectData); - } - QVERIFY(projectDataMatches); // Will fail if e.g. code locations don't match. - - // Now try building again and check if the newly resolved product behaves the same way. - buildJob.reset(project.buildAllProducts(buildOptions, defaultProducts(), this)); - connect(buildJob.get(), &qbs::BuildJob::reportCommandDescription, - &rcvr, &BuildDescriptionReceiver::handleDescription); - waitForFinished(buildJob.get()); - QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); - QVERIFY(rcvr.descriptions.contains("compiling file.cpp")); - QVERIFY(!rcvr.descriptions.contains("compiling main.cpp")); - - // Now, after the build, the project data must be entirely identical. - QVERIFY(projectData == project.projectData()); - // Error handling: Try to change the project during a build. buildJob.reset(project.buildAllProducts(buildOptions, defaultProducts(), this)); - errorInfo = project.addGroup(newProjectData.products().front(), "blubb"); + errorInfo = project.addGroup(projectData.products().front(), "blubb"); QVERIFY(errorInfo.hasError()); QVERIFY2(errorInfo.toString().contains("in progress"), qPrintable(errorInfo.toString())); waitForFinished(buildJob.get()); - errorInfo = project.addGroup(newProjectData.products().front(), "blubb"); + errorInfo = project.addGroup(projectData.products().front(), "blubb"); VERIFY_NO_ERROR(errorInfo); project = qbs::Project(); @@ -888,16 +841,11 @@ void TestApi::changeContent() setupParams.setProjectFilePath(QDir::cleanPath(m_workingDataDir + "/project-editing/project-with-no-files.qbs")); - job.reset(project.setupProject(setupParams, m_logSink, 0)); - waitForFinished(job.get()); - QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); - project = job->project(); - projectData = project.projectData(); - QCOMPARE(projectData.allProducts().size(), 1); - product = projectData.allProducts().front(); + resolve(); + WAIT_FOR_NEW_TIMESTAMP(); errorInfo = project.addFiles(product, qbs::GroupData(), QStringList("main.cpp")); VERIFY_NO_ERROR(errorInfo); - projectData = project.projectData(); + resolve(); rcvr.descriptions.clear(); buildJob.reset(project.buildAllProducts(buildOptions, defaultProducts(), this)); connect(buildJob.get(), &qbs::BuildJob::reportCommandDescription, @@ -908,27 +856,13 @@ void TestApi::changeContent() job.reset(project.setupProject(setupParams, m_logSink, 0)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); - // Can't use Project::operator== here, as the target artifacts will differ due to the build - // not having run yet. - newProjectData = job->project().projectData(); - projectDataMatches = newProjectData.products().size() == 1 - && projectData.products().size() == 1 - && newProjectData.products().front().groups() == projectData.products().front().groups(); - if (!projectDataMatches) { - printProjectData(projectData); - qDebug("\n====\n"); - printProjectData(newProjectData); - } - QVERIFY(projectDataMatches); } -#endif // QBS_ENABLE_PROJECT_FILE_UPDATES - void TestApi::commandExtraction() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("/command-extraction"); std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); @@ -971,7 +905,7 @@ void TestApi::dependencyOnMultiplexedType() qbs::SetupProjectParameters setupParams = defaultSetupParameters("/dependency-on-multiplexed-type"); std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); @@ -994,16 +928,12 @@ void TestApi::dependencyOnMultiplexedType() } else { QVERIFY(p.name() == "p2"); ++p2Count; - - // FIXME: This is an odd effect of our current algorithm: We collect the products - // matching the requested type and add Depends items with their names ("p1" in - // this case). Later, the algorithm checking for compatibility regarding the - // multiplexing axes picks the aggregate. However, the aggregate does not have - // a matching type... It's not entirely clear what the real expected - // result should be here. - QCOMPARE(p.dependencies().size(), 2); + QVERIFY(p.dependencies().contains("dep")); } } + QCOMPARE(depCount, 1); + QCOMPARE(p1Count, 3); + QCOMPARE(p2Count, 1); std::unique_ptr<qbs::BuildJob> buildJob(project.buildAllProducts(qbs::BuildOptions())); waitForFinished(buildJob.get()); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); @@ -1060,7 +990,7 @@ void TestApi::errorInSetupRunEnvironment() qbs::SetupProjectParameters setupParams = defaultSetupParameters("error-in-setup-run-environment"); std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); const qbs::Project project = job->project(); @@ -1076,7 +1006,7 @@ void TestApi::errorInSetupRunEnvironment() qbs::ErrorInfo error; const QProcessEnvironment env = runEnv.runEnvironment(&error); QVERIFY(error.hasError()); - QVERIFY(error.toString().contains("trallala")); + QVERIFY2(error.toString().contains("trallala"), qPrintable(error.toString())); } catch (const qbs::ErrorInfo &) { exceptionCaught = true; } @@ -1087,7 +1017,7 @@ void TestApi::excludedInputs() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("excluded-inputs"); std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); const qbs::Project project = job->project(); @@ -1095,10 +1025,11 @@ void TestApi::excludedInputs() waitForFinished(buildJob.get()); QVERIFY2(!buildJob->error().hasError(), qPrintable(job->error().toString())); QVERIFY(project.isValid()); - QCOMPARE(project.projectData().products().size(), 2); + const qbs::ProjectData projectData = project.projectData(); + QCOMPARE(projectData.products().size(), 2); qbs::ProductData depProduct; qbs::ProductData pProduct; - for (qbs::ProductData &p : project.projectData().products()) { + for (const qbs::ProductData &p : projectData.products()) { if (p.name() == "dep") depProduct = p; else if (p.name() == "p") @@ -1129,7 +1060,7 @@ void TestApi::excludedInputs() QCOMPARE(dummyCount, 3); } -static qbs::ErrorInfo forceRuleEvaluation(const qbs::Project project) +static qbs::ErrorInfo forceRuleEvaluation(const qbs::Project &project) { qbs::BuildOptions buildOptions; buildOptions.setDryRun(true); @@ -1143,7 +1074,7 @@ void TestApi::disabledInstallGroup() qbs::SetupProjectParameters setupParams = defaultSetupParameters("disabled_install_group"); std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); const qbs::Project project = job->project(); @@ -1175,6 +1106,95 @@ void TestApi::disabledProject() VERIFY_NO_ERROR(errorInfo); } +void TestApi::disappearedWildcardFile() +{ + const qbs::SetupProjectParameters setupParams + = defaultSetupParameters("disappeared-wildcard-file/disappeared-wildcard-file.qbs"); + std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams, + m_logSink, nullptr)); + QVERIFY(waitForFinished(setupJob.get())); + VERIFY_NO_ERROR(setupJob->error()); + + qbs::Project project = setupJob->project(); + qbs::ProjectData projectData = project.projectData(); + QVERIFY(projectData.isValid()); + QList<qbs::ProductData> products = projectData.allProducts(); + QCOMPARE(products.size(), 1); + QCOMPARE(products.first().groups().size(), 1); + QCOMPARE(products.first().groups().first().allFilePaths().size(), 2); + + std::unique_ptr<qbs::BuildJob> buildJob(project.buildAllProducts({})); + QVERIFY(waitForFinished(buildJob.get())); + VERIFY_NO_ERROR(buildJob->error()); + + WAIT_FOR_NEW_TIMESTAMP(); + const QString fileToRemove = QFileInfo(setupParams.projectFilePath()).path() + "/file2.txt"; + QVERIFY(QFile::remove(fileToRemove)); + buildJob.reset(project.buildAllProducts({})); + QVERIFY(waitForFinished(buildJob.get())); + QVERIFY(buildJob->error().hasError()); + QVERIFY2(buildJob->error().toString().contains( + tr("Source file '%1' has disappeared.") + .arg(fileToRemove)), qPrintable(buildJob->error().toString())); + + setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); + QVERIFY(waitForFinished(setupJob.get())); + VERIFY_NO_ERROR(setupJob->error()); + + project = setupJob->project(); + projectData = project.projectData(); + QVERIFY(projectData.isValid()); + products = projectData.allProducts(); + QCOMPARE(products.size(), 1); + QCOMPARE(products.first().groups().size(), 1); + QCOMPARE(products.first().groups().first().allFilePaths().size(), 1); + + buildJob.reset(project.buildAllProducts({})); + QVERIFY(waitForFinished(buildJob.get())); + VERIFY_NO_ERROR(buildJob->error()); +} + +void TestApi::renamedQbsSource() +{ + const qbs::SetupProjectParameters setupParams + = defaultSetupParameters("renamed-qbs-source-file/renamed-qbs-source-file.qbs"); + std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams, + m_logSink, nullptr)); + QVERIFY(waitForFinished(setupJob.get())); + VERIFY_NO_ERROR(setupJob->error()); + qbs::Project project = setupJob->project(); + QCOMPARE(project.projectData().allProducts().size(), 2); + + std::unique_ptr<qbs::BuildJob> buildJob(project.buildAllProducts({})); + QVERIFY(waitForFinished(buildJob.get())); + VERIFY_NO_ERROR(buildJob->error()); + + WAIT_FOR_NEW_TIMESTAMP(); + const QString oldFilePath = QFileInfo(setupParams.projectFilePath()).path() + + "/the-product/the-prodduct.qbs"; + const QString newFilePath = QFileInfo(setupParams.projectFilePath()).path() + + "/the-product/the-product.qbs"; + QVERIFY(QFile::rename(oldFilePath, newFilePath)); + REPLACE_IN_FILE(setupParams.projectFilePath(), "prodduct", "product"); + buildJob.reset(project.buildAllProducts({})); + QVERIFY(waitForFinished(buildJob.get())); + QVERIFY(buildJob->error().hasError()); + QVERIFY2(buildJob->error().toString().contains( + tr("Source file '%1' has disappeared.") + .arg(oldFilePath)), qPrintable(buildJob->error().toString())); + + setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); + QVERIFY(waitForFinished(setupJob.get())); + VERIFY_NO_ERROR(setupJob->error()); + + project = setupJob->project(); + QCOMPARE(project.projectData().allProducts().size(), 2); + + buildJob.reset(project.buildAllProducts({})); + QVERIFY(waitForFinished(buildJob.get())); + VERIFY_NO_ERROR(buildJob->error()); +} + void TestApi::duplicateProductNames() { QFETCH(QString, projectFileName); @@ -1210,6 +1230,8 @@ void TestApi::explicitlyDependsOn() BuildDescriptionReceiver receiver; qbs::ErrorInfo errorInfo = doBuildProject("explicitly-depends-on", &receiver); VERIFY_NO_ERROR(errorInfo); + if (m_logSink->output.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QVERIFY2(receiver.descriptions.contains("compiling compiler.cpp"), qPrintable(receiver.descriptions)); QVERIFY2(receiver.descriptions.contains("compiling a.in"), qPrintable(receiver.descriptions)); @@ -1266,7 +1288,7 @@ void TestApi::fallbackGcc() QVERIFY(project.isValid()); QList<qbs::ProductData> products = project.allProducts(); QCOMPARE(products.size(), 2); - for (const qbs::ProductData &p : qAsConst(products)) { + for (const qbs::ProductData &p : std::as_const(products)) { if (p.profile() == "unixProfile") { qbs::PropertyMap moduleProps = p.moduleProperties(); QCOMPARE(moduleProps.getModuleProperty("qbs", "targetOS").toStringList(), @@ -1305,7 +1327,7 @@ void TestApi::fileTagsFilterOverride() qbs::SetupProjectParameters setupParams = defaultSetupParameters("filetagsfilter_override"); std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); qbs::Project project = job->project(); @@ -1326,7 +1348,7 @@ void TestApi::generatedFilesList() qbs::SetupProjectParameters setupParams = defaultSetupParameters("generated-files-list"); std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); QVERIFY(waitForFinished(setupJob.get())); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); @@ -1385,7 +1407,7 @@ void TestApi::infiniteLoopBuilding() qbs::SetupProjectParameters setupParams = defaultSetupParameters(projectDirName + "/infinite-loop.qbs"); std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); @@ -1400,13 +1422,16 @@ void TestApi::infiniteLoopBuilding_data() QTest::addColumn<QString>("projectDirName"); QTest::newRow("JS Command") << QString("infinite-loop-js"); QTest::newRow("Process Command") << QString("infinite-loop-process"); + QTest::newRow("Scanner (scan property)") << QString("infinite-loop-scanning-scan"); + QTest::newRow("Scanner (searchPaths property)") + << QString("infinite-loop-scanning-searchpaths"); } void TestApi::infiniteLoopResolving() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("infinite-loop-resolving"); std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); QTimer::singleShot(1000, setupJob.get(), &qbs::AbstractJob::cancel); QVERIFY(waitForFinished(setupJob.get(), testTimeoutInMsecs())); QVERIFY2(setupJob->error().toString().toLower().contains("cancel"), @@ -1435,7 +1460,7 @@ void TestApi::inheritQbsSearchPaths() QVariantMap overriddenValues; overriddenValues.insert("project.qbsSearchPaths", QStringList() << m_workingDataDir + "/inherit-qbs-search-paths/subdir"); - errorInfo = doBuildProject(projectFilePath, 0, 0, 0, qbs::BuildOptions(), overriddenValues); + errorInfo = doBuildProject(projectFilePath, nullptr, nullptr, nullptr, qbs::BuildOptions(), overriddenValues); VERIFY_NO_ERROR(errorInfo); } @@ -1452,7 +1477,7 @@ void TestApi::installableFiles() overriddenValues.insert(QStringLiteral("qbs.installRoot"), QStringLiteral("/tmp")); setupParams.setOverriddenValues(overriddenValues); std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); qbs::Project project = job->project(); @@ -1481,7 +1506,7 @@ void TestApi::installableFiles() setupParams = defaultSetupParameters("recursive-wildcards"); setupParams.setOverriddenValues(overriddenValues); - job.reset(project.setupProject(setupParams, m_logSink, 0)); + job.reset(project.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); project = job->project(); @@ -1502,7 +1527,7 @@ void TestApi::isRunnable() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("is-runnable"); std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); qbs::Project project = job->project(); @@ -1528,27 +1553,30 @@ void TestApi::linkDynamicAndStaticLibs() BuildDescriptionReceiver bdr; qbs::BuildOptions options; options.setEchoMode(qbs::CommandEchoModeCommandLine); + m_logSink->output.clear(); const qbs::ErrorInfo errorInfo = doBuildProject("link-dynamiclibs-staticlibs", &bdr, nullptr, nullptr, options); VERIFY_NO_ERROR(errorInfo); + const bool isGcc = m_logSink->output.contains("is gcc: true"); + const bool isNotGcc = m_logSink->output.contains("is gcc: false"); + if (isNotGcc) + QSKIP("The remainder of this test applies only to GCC"); + QVERIFY(isGcc); + // The dependent static libs should not appear in the link command for the executable. - const SettingsPtr s = settings(); - const qbs::Profile buildProfile(profileName(), s.get()); - if (buildProfile.value("qbs.toolchain").toStringList().contains("gcc")) { - static const std::regex appLinkCmdRex(" -o [^ ]*/HelloWorld" QBS_HOST_EXE_SUFFIX " "); - QString appLinkCmd; - for (const QString &line : qAsConst(bdr.descriptionLines)) { - const auto ln = line.toStdString(); - if (std::regex_search(ln, appLinkCmdRex)) { - appLinkCmd = line; - break; - } + static const std::regex appLinkCmdRex(" -o [^ ]*/HelloWorld" QBS_HOST_EXE_SUFFIX " "); + QString appLinkCmd; + for (const QString &line : std::as_const(bdr.descriptionLines)) { + const auto ln = line.toStdString(); + if (std::regex_search(ln, appLinkCmdRex)) { + appLinkCmd = line; + break; } - QVERIFY(!appLinkCmd.isEmpty()); - QVERIFY(!appLinkCmd.contains("static1")); - QVERIFY(!appLinkCmd.contains("static2")); } + QVERIFY(!appLinkCmd.isEmpty()); + QVERIFY(!appLinkCmd.contains("static1")); + QVERIFY(!appLinkCmd.contains("static2")); } void TestApi::linkStaticAndDynamicLibs() @@ -1563,31 +1591,32 @@ void TestApi::linkStaticAndDynamicLibs() const bool isNormalUnix = m_logSink->output.contains("is normal unix: yes"); const bool isNotNormalUnix = m_logSink->output.contains("is normal unix: no"); QVERIFY2(isNormalUnix != isNotNormalUnix, qPrintable(m_logSink->output)); + const bool isGcc = m_logSink->output.contains("is gcc: true"); + const bool isNotGcc = m_logSink->output.contains("is gcc: false"); + if (isNotGcc) + QSKIP("The remainder of this test applies only to GCC"); + QVERIFY(isGcc); // The dependencies libdynamic1.so and libstatic2.a must not appear in the link command for the // executable. The -rpath-link line for libdynamic1.so must be there. - const SettingsPtr s = settings(); - const qbs::Profile buildProfile(profileName(), s.get()); - if (buildProfile.value("qbs.toolchain").toStringList().contains("gcc")) { - static const std::regex appLinkCmdRex(" -o [^ ]*/HelloWorld" QBS_HOST_EXE_SUFFIX " "); - QString appLinkCmd; - for (const QString &line : qAsConst(bdr.descriptionLines)) { - const auto ln = line.toStdString(); - if (std::regex_search(ln, appLinkCmdRex)) { - appLinkCmd = line; - break; - } - } - QVERIFY(!appLinkCmd.isEmpty()); - if (isNormalUnix) { - const std::regex rpathLinkRex("-rpath-link=\\S*/" - + relativeProductBuildDir("dynamic2").toStdString()); - const auto ln = appLinkCmd.toStdString(); - QVERIFY(std::regex_search(ln, rpathLinkRex)); + static const std::regex appLinkCmdRex(" -o [^ ]*/HelloWorld" QBS_HOST_EXE_SUFFIX " "); + QString appLinkCmd; + for (const QString &line : std::as_const(bdr.descriptionLines)) { + const auto ln = line.toStdString(); + if (std::regex_search(ln, appLinkCmdRex)) { + appLinkCmd = line; + break; } - QVERIFY(!appLinkCmd.contains("libstatic2.a")); - QVERIFY(!appLinkCmd.contains("libdynamic2.so")); } + QVERIFY(!appLinkCmd.isEmpty()); + if (isNormalUnix) { + const std::regex rpathLinkRex("-rpath-link=\\S*/" + + relativeProductBuildDir("dynamic2").toStdString()); + const auto ln = appLinkCmd.toStdString(); + QVERIFY(std::regex_search(ln, rpathLinkRex)); + } + QVERIFY(!appLinkCmd.contains("libstatic2.a")); + QVERIFY(!appLinkCmd.contains("libdynamic2.so")); } void TestApi::listBuildSystemFiles() @@ -1595,15 +1624,14 @@ void TestApi::listBuildSystemFiles() qbs::SetupProjectParameters setupParams = defaultSetupParameters("subprojects/toplevelproject.qbs"); std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); - const auto buildSystemFiles = qbs::Internal::Set<QString>::fromStdSet( - job->project().buildSystemFiles()); - QVERIFY(buildSystemFiles.contains(setupParams.projectFilePath())); - QVERIFY(buildSystemFiles.contains(setupParams.buildRoot() + "/subproject2/subproject2.qbs")); - QVERIFY(buildSystemFiles.contains(setupParams.buildRoot() - + "/subproject2/subproject3/subproject3.qbs")); + const auto buildSystemFiles = job->project().buildSystemFiles(); + QVERIFY(buildSystemFiles.count(setupParams.projectFilePath())); + QVERIFY(buildSystemFiles.count(setupParams.buildRoot() + "/subproject2/subproject2.qbs")); + QVERIFY(buildSystemFiles.count(setupParams.buildRoot() + + "/subproject2/subproject3/subproject3.qbs")); } void TestApi::localProfiles() @@ -1614,7 +1642,7 @@ void TestApi::localProfiles() setupParams.setOverriddenValues( {std::make_pair(QString("project.enableProfiles"), enableProfiles)}); std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); QString taskDescriptions; const auto taskDescHandler = [&taskDescriptions](const QString &desc, int, qbs::AbstractJob *) { taskDescriptions += '\n' + desc; @@ -1636,7 +1664,7 @@ void TestApi::localProfiles() qbs::ProductData libClang; qbs::ProductData appDebug; qbs::ProductData appRelease; - for (const qbs::ProductData &p : qAsConst(products)) { + for (const qbs::ProductData &p : std::as_const(products)) { if (p.name() == "lib") { if (p.profile() == "mingwProfile") libMingw = p; @@ -1666,7 +1694,7 @@ void TestApi::localProfiles() QStringList({"mingw", "gcc"})); if (moduleProps.getModuleProperty("cpp", "present").toBool()) { QCOMPARE(moduleProps.getModuleProperty("cpp", "cxxCompilerName").toString(), - QString("g++")); + qbs::Internal::HostOsInfo::appendExecutableSuffix(QString("g++"))); } moduleProps = libClang.moduleProperties(); QCOMPARE(moduleProps.getModuleProperty("qbs", "targetOS").toStringList(), @@ -1675,7 +1703,7 @@ void TestApi::localProfiles() QStringList({"clang", "llvm", "gcc"})); if (moduleProps.getModuleProperty("cpp", "present").toBool()) { QCOMPARE(moduleProps.getModuleProperty("cpp", "cxxCompilerName").toString(), - QString("clang++")); + qbs::Internal::HostOsInfo::appendExecutableSuffix(QString("clang++"))); } moduleProps = appDebug.moduleProperties(); if (moduleProps.getModuleProperty("cpp", "present").toBool()) @@ -1685,7 +1713,7 @@ void TestApi::localProfiles() QCOMPARE(moduleProps.getModuleProperty("cpp", "optimization").toString(), QString("fast")); taskDescriptions.clear(); - job.reset(qbs::Project().setupProject(setupParams, m_logSink, 0)); + job.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); connect(job.get(), &qbs::AbstractJob::taskStarted, taskDescHandler); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); @@ -1699,20 +1727,20 @@ void TestApi::localProfiles() projectFile.resize(0); projectFile.write(content); projectFile.close(); - job.reset(qbs::Project().setupProject(setupParams, m_logSink, 0)); + job.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); project = job->project().projectData(); products = project.allProducts(); QCOMPARE(products.size(), 4); int clangProfiles = 0; - for (const qbs::ProductData &p : qAsConst(products)) { + for (const qbs::ProductData &p : std::as_const(products)) { if (p.profile() == "clangProfile") { ++clangProfiles; moduleProps = p.moduleProperties(); if (moduleProps.getModuleProperty("cpp", "present").toBool()) { QCOMPARE(moduleProps.getModuleProperty("cpp", "cxxCompilerName").toString(), - QString("g++")); + qbs::Internal::HostOsInfo::appendExecutableSuffix(QString("g++"))); } } } @@ -1733,7 +1761,7 @@ void TestApi::missingSourceFile() setupParams.setProductErrorMode(qbs::ErrorHandlingMode::Relaxed); m_logSink->setLogLevel(qbs::LoggerMinLevel); std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); qbs::ProjectData project = job->project().projectData(); @@ -1744,7 +1772,7 @@ void TestApi::missingSourceFile() QCOMPARE(group.allSourceArtifacts().size(), 2); QFile::rename("file2.txt.missing", "file2.txt"); - job.reset(qbs::Project().setupProject(setupParams, m_logSink, 0)); + job.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); project = job->project().projectData(); @@ -1797,12 +1825,13 @@ void TestApi::multiArch() overriddenValues.insert("project.targetProfile", targetProfile.name()); setupParams.setOverriddenValues(overriddenValues); std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); QCOMPARE(project.profile(), profileName()); - const QList<qbs::ProductData> &products = project.projectData().products(); + const qbs::ProjectData projectData = project.projectData(); + const QList<qbs::ProductData> &products = projectData.products(); QCOMPARE(products.size(), 3); QList<qbs::ProductData> hostProducts; QList<qbs::ProductData> targetProducts; @@ -1861,26 +1890,23 @@ void TestApi::multiArch() QFile p2ArtifactInstalled(installRoot + "/host/host-tool.output"); QVERIFY2(p2ArtifactInstalled.exists(), qPrintable(p2ArtifactInstalled.fileName())); - // Error check: Try to build for the same profile twice. + // Specifying the same profile twice should not result in an attempt to multiplex. overriddenValues.insert("project.targetProfile", hostProfile.name()); setupParams.setOverriddenValues(overriddenValues); - setupJob.reset(project.setupProject(setupParams, m_logSink, 0)); + setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); - QVERIFY(setupJob->error().hasError()); - QVERIFY2(setupJob->error().toString().contains("Duplicate entry 'host' in qbs.profiles."), - qPrintable(setupJob->error().toString())); + QVERIFY(!setupJob->error().hasError()); + QCOMPARE(int(setupJob->project().projectData().products().size()), 2); - // Error check: Try to build for the same profile twice, this time attaching - // the properties via the product name. + // The same, but this time attaching the properties via the product name. overriddenValues.remove(QStringLiteral("project.targetProfile")); overriddenValues.insert("products.p1.myProfiles", targetProfile.name() + ',' + targetProfile.name()); setupParams.setOverriddenValues(overriddenValues); - setupJob.reset(project.setupProject(setupParams, m_logSink, 0)); + setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); - QVERIFY(setupJob->error().hasError()); - QVERIFY2(setupJob->error().toString().contains("Duplicate entry 'target' in qbs.profiles."), - qPrintable(setupJob->error().toString())); + QVERIFY(!setupJob->error().hasError()); + QCOMPARE(int(setupJob->project().projectData().products().size()), 2); } struct ProductDataSelector @@ -1899,7 +1925,8 @@ struct ProductDataSelector bool qbsPropertiesMatch(const qbs::ProductData &p) const { for (auto it = qbsProperties.begin(); it != qbsProperties.end(); ++it) { - if (it.value() != p.moduleProperties().getModuleProperty("qbs", it.key())) + if (!qbs::qVariantsEqual( + it.value(), p.moduleProperties().getModuleProperty("qbs", it.key()))) return false; } return true; @@ -1926,7 +1953,7 @@ void TestApi::multiplexing() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("multiplexing"); std::unique_ptr<qbs::SetupProjectJob> setupJob( - qbs::Project().setupProject(setupParams, m_logSink, 0)); + qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); @@ -2035,6 +2062,31 @@ void TestApi::multiplexing() QVERIFY(product.dependencies().empty()); selector.clear(); + selector.name = "multiplex-without-aggregator-4-depends-2"; + selector.qbsProperties["architecture"] = "C64"; + selector.qbsProperties["buildVariant"] = "debug"; + product = takeMatchingProduct(products, selector); + QVERIFY(product.isValid()); + QVERIFY(product.isMultiplexed()); + QCOMPARE(product.dependencies().size(), 1); + selector.qbsProperties["buildVariant"] = "release"; + product = takeMatchingProduct(products, selector); + QVERIFY(product.isValid()); + QVERIFY(product.isMultiplexed()); + QCOMPARE(product.dependencies().size(), 1); + selector.qbsProperties["architecture"] = "TRS-80"; + selector.qbsProperties["buildVariant"] = "debug"; + product = takeMatchingProduct(products, selector); + QVERIFY(product.isValid()); + QVERIFY(product.isMultiplexed()); + QCOMPARE(product.dependencies().size(), 1); + selector.qbsProperties["buildVariant"] = "release"; + product = takeMatchingProduct(products, selector); + QVERIFY(product.isValid()); + QVERIFY(product.isMultiplexed()); + QCOMPARE(product.dependencies().size(), 1); + + selector.clear(); selector.name = "multiplex-with-aggregator-2"; selector.qbsProperties["architecture"] = "C64"; product = takeMatchingProduct(products, selector); @@ -2137,12 +2189,12 @@ void TestApi::newOutputArtifactInDependency() void TestApi::newPatternMatch() { TaskReceiver receiver; - qbs::ErrorInfo errorInfo = doBuildProject("new-pattern-match", 0, 0, &receiver); + qbs::ErrorInfo errorInfo = doBuildProject("new-pattern-match", nullptr, nullptr, &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY2(receiver.taskDescriptions.contains("Resolving"), qPrintable(m_logSink->output)); receiver.taskDescriptions.clear(); - errorInfo = doBuildProject("new-pattern-match", 0, 0, &receiver); + errorInfo = doBuildProject("new-pattern-match", nullptr, nullptr, &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY(!receiver.taskDescriptions.contains("Resolving")); @@ -2150,18 +2202,18 @@ void TestApi::newPatternMatch() QFile f("test.txt"); QVERIFY2(f.open(QIODevice::WriteOnly), qPrintable(f.errorString())); f.close(); - errorInfo = doBuildProject("new-pattern-match", 0, 0, &receiver); + errorInfo = doBuildProject("new-pattern-match", nullptr, nullptr, &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY(receiver.taskDescriptions.contains("Resolving")); receiver.taskDescriptions.clear(); - errorInfo = doBuildProject("new-pattern-match", 0, 0, &receiver); + errorInfo = doBuildProject("new-pattern-match", nullptr, nullptr, &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY(!receiver.taskDescriptions.contains("Resolving")); WAIT_FOR_NEW_TIMESTAMP(); f.remove(); - errorInfo = doBuildProject("new-pattern-match", 0, 0, &receiver); + errorInfo = doBuildProject("new-pattern-match", nullptr, nullptr, &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY(receiver.taskDescriptions.contains("Resolving")); } @@ -2169,9 +2221,9 @@ void TestApi::newPatternMatch() void TestApi::nonexistingProjectPropertyFromProduct() { qbs::SetupProjectParameters setupParams - = defaultSetupParameters("nonexistingprojectproperties"); + = defaultSetupParameters("nonexistingprojectproperties/invalidaccessfromproduct.qbs"); std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(job.get()); QEXPECT_FAIL("", "QBS-432", Abort); QVERIFY(job->error().hasError()); @@ -2188,7 +2240,7 @@ void TestApi::nonexistingProjectPropertyFromCommandLine() projectProperties.insert(QStringLiteral("project.blubb"), QStringLiteral("true")); setupParams.setOverriddenValues(projectProperties); std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY(job->error().hasError()); QVERIFY2(job->error().toString().contains(QLatin1String("blubb")), @@ -2206,7 +2258,7 @@ void TestApi::projectDataAfterProductInvalidation() qbs::SetupProjectParameters setupParams = defaultSetupParameters("project-data-after-" "product-invalidation/project-data-after-product-invalidation.qbs"); std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); @@ -2228,7 +2280,7 @@ void TestApi::projectDataAfterProductInvalidation() projectFile.resize(0); projectFile.write(content); projectFile.flush(); - setupJob.reset(project.setupProject(setupParams, m_logSink, 0)); + setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); QVERIFY(!project.isValid()); @@ -2260,6 +2312,8 @@ void TestApi::processResult() ProcessResultReceiver resultReceiver; const qbs::ErrorInfo errorInfo = doBuildProject("process-result", nullptr, &resultReceiver, nullptr, qbs::BuildOptions(), overridden); + if (m_logSink->output.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(expectedExitCode != 0, errorInfo.hasError()); QVERIFY(resultReceiver.results.size() > 1); const qbs::ProcessResult &result = resultReceiver.results.back(); @@ -2311,20 +2365,20 @@ void TestApi::projectInvalidation() qbs::SetupProjectParameters setupParams = defaultSetupParameters("project-invalidation"); QVERIFY(QFile::copy("project.no-error.qbs", "project-invalidation.qbs")); std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); QVERIFY(project.isValid()); WAIT_FOR_NEW_TIMESTAMP(); copyFileAndUpdateTimestamp("project.early-error.qbs", "project-invalidation.qbs"); - setupJob.reset(project.setupProject(setupParams, m_logSink, 0)); + setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY(setupJob->error().hasError()); QVERIFY(project.isValid()); // Error in Loader, old project still valid. WAIT_FOR_NEW_TIMESTAMP(); copyFileAndUpdateTimestamp("project.late-error.qbs", "project-invalidation.qbs"); - setupJob.reset(project.setupProject(setupParams, m_logSink, 0)); + setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY(setupJob->error().hasError()); QVERIFY(!project.isValid()); // Error in build data re-resolving, old project not valid anymore. @@ -2334,13 +2388,13 @@ void TestApi::projectLocking() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("project-locking"); std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); - setupJob.reset(project.setupProject(setupParams, m_logSink, 0)); + setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); std::unique_ptr<qbs::SetupProjectJob> setupJob2(project.setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(setupJob2.get()); QVERIFY(setupJob2->error().hasError()); QVERIFY2(setupJob2->error().toString() @@ -2357,14 +2411,14 @@ void TestApi::projectPropertiesByName() QVERIFY(errorInfo.hasError()); QVariantMap overridden; overridden.insert("project.theDefines", QStringList() << "SUB1" << "SUB2"); - errorInfo = doBuildProject(projectFile, 0, 0, 0, qbs::BuildOptions(), overridden); + errorInfo = doBuildProject(projectFile, nullptr, nullptr, nullptr, qbs::BuildOptions(), overridden); QVERIFY(errorInfo.hasError()); overridden.clear(); overridden.insert("projects.subproject1.theDefines", QStringList() << "SUB1"); - errorInfo = doBuildProject(projectFile, 0, 0, 0, qbs::BuildOptions(), overridden); + errorInfo = doBuildProject(projectFile, nullptr, nullptr, nullptr, qbs::BuildOptions(), overridden); QVERIFY(errorInfo.hasError()); overridden.insert("projects.subproject2.theDefines", QStringList() << "SUB2"); - errorInfo = doBuildProject(projectFile, 0, 0, 0, qbs::BuildOptions(), overridden); + errorInfo = doBuildProject(projectFile, nullptr, nullptr, nullptr, qbs::BuildOptions(), overridden); VERIFY_NO_ERROR(errorInfo); } @@ -2424,7 +2478,7 @@ void TestApi::referencedFileErrors() params.setProductErrorMode(relaxedMode ? qbs::ErrorHandlingMode::Relaxed : qbs::ErrorHandlingMode::Strict); m_logSink->setLogLevel(qbs::LoggerMinLevel); - std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(params, m_logSink, 0)); + std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(params, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(job->error().hasError() != relaxedMode, qPrintable(job->error().toString())); const qbs::Project project = job->project(); @@ -2459,7 +2513,9 @@ qbs::SetupProjectParameters TestApi::defaultSetupParameters(const QString &proje } qbs::SetupProjectParameters setupParams; - setupParams.setEnvironment(QProcessEnvironment::systemEnvironment()); + auto environment = QProcessEnvironment::systemEnvironment(); + environment.insert("QBS_AUTOTEST_CODE_SIGNING_REQUIRED", "0"); + setupParams.setEnvironment(environment); setupParams.setProjectFilePath(projectFilePath); setupParams.setPropertyCheckingMode(qbs::ErrorHandlingMode::Strict); setupParams.setOverrideBuildGraphData(true); @@ -2474,6 +2530,7 @@ qbs::SetupProjectParameters TestApi::defaultSetupParameters(const QString &proje setupParams.setLibexecPath(QDir::cleanPath(QCoreApplication::applicationDirPath() + QLatin1String("/" QBS_RELATIVE_LIBEXEC_PATH))); setupParams.setTopLevelProfile(profileName()); + setupParams.setMaxJobCount(2); setupParams.setConfigurationName(QStringLiteral("default")); setupParams.setSettingsDirectory(settings()->baseDirectory()); return setupParams; @@ -2484,21 +2541,21 @@ void TestApi::references() qbs::SetupProjectParameters setupParams = defaultSetupParameters("references/invalid1.qbs"); const QString projectDir = QDir::cleanPath(m_workingDataDir + "/references"); std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY(job->error().hasError()); QString errorString = job->error().toString(); QVERIFY2(errorString.contains("does not contain"), qPrintable(errorString)); setupParams.setProjectFilePath(projectDir + QLatin1String("/invalid2.qbs")); - job.reset(qbs::Project().setupProject(setupParams, m_logSink, 0)); + job.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY(job->error().hasError()); errorString = job->error().toString(); QVERIFY2(errorString.contains("contains more than one"), qPrintable(errorString)); setupParams.setProjectFilePath(projectDir + QLatin1String("/valid.qbs")); - job.reset(qbs::Project().setupProject(setupParams, m_logSink, 0)); + job.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); const qbs::ProjectData topLevelProject = job->project().projectData(); @@ -2514,7 +2571,7 @@ void TestApi::relaxedModeRecovery() setupParams.setProductErrorMode(qbs::ErrorHandlingMode::Relaxed); setupParams.setPropertyCheckingMode(qbs::ErrorHandlingMode::Relaxed); std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); if (m_logSink->warnings.size() != 4) { @@ -2600,7 +2657,7 @@ void TestApi::removeFileDependency() QFile::remove("someheader.h"); ProcessResultReceiver receiver; - errorInfo = doBuildProject("remove-file-dependency/removeFileDependency.qbs", 0, &receiver); + errorInfo = doBuildProject("remove-file-dependency/removeFileDependency.qbs", nullptr, &receiver); QVERIFY(errorInfo.hasError()); QVERIFY2(receiver.output.contains("someheader.h"), qPrintable(receiver.output)); } @@ -2613,7 +2670,7 @@ void TestApi::resolveProject() const qbs::SetupProjectParameters params = defaultSetupParameters(projectSubDir); removeBuildDir(params); const std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(params, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(setupJob.get()); VERIFY_NO_ERROR(setupJob->error()); QVERIFY2(!QFile::exists(productFileName), qPrintable(productFileName)); @@ -2634,7 +2691,7 @@ void TestApi::resolveProjectDryRun() params.setDryRun(true); removeBuildDir(params); const std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(params, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(setupJob.get()); VERIFY_NO_ERROR(setupJob->error()); QVERIFY2(!QFile::exists(productFileName), qPrintable(productFileName)); @@ -2654,44 +2711,51 @@ void TestApi::restoredWarnings() // Initial resolving: Errors are new. std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); job.reset(nullptr); - QCOMPARE(toSet(m_logSink->warnings).size(), 2); + QCOMPARE(toSet(m_logSink->warnings).size(), 5); const auto beforeErrors = m_logSink->warnings; for (const qbs::ErrorInfo &e : beforeErrors) { const QString msg = e.toString(); QVERIFY2(msg.contains("Superfluous version") - || msg.contains("Property 'blubb' is not declared"), + || msg.contains("Property 'blubb' is not declared") + || msg.contains("this one comes from a thread") + || msg.contains("Product 'theOtherProduct' had errors and was disabled") + || msg.contains("Product 'theProduct' had errors and was disabled"), qPrintable(msg)); } m_logSink->warnings.clear(); // Re-resolving with no changes: Errors come from the stored build graph. - job.reset(qbs::Project().setupProject(setupParams, m_logSink, 0)); + job.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); job.reset(nullptr); - QCOMPARE(toSet(m_logSink->warnings).size(), 2); + QCOMPARE(toSet(m_logSink->warnings).size(), 5); m_logSink->warnings.clear(); // Re-resolving with changes: Errors come from the re-resolving, stored ones must be suppressed. QVariantMap overridenValues; - overridenValues.insert("products.theProduct.moreFiles", true); + overridenValues.insert("products.aThirdProduct.moreFiles", true); setupParams.setOverriddenValues(overridenValues); - job.reset(qbs::Project().setupProject(setupParams, m_logSink, 0)); + job.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); job.reset(nullptr); - QCOMPARE(toSet(m_logSink->warnings).size(), 3); // One more for the additional group + QCOMPARE(toSet(m_logSink->warnings).size(), 6); // One more for the additional group const auto afterErrors = m_logSink->warnings; for (const qbs::ErrorInfo &e : afterErrors) { const QString msg = e.toString(); - QVERIFY2(msg.contains("Superfluous version") - || msg.contains("Property 'blubb' is not declared") - || msg.contains("blubb.cpp' does not exist"), - qPrintable(msg)); + QVERIFY2( + msg.contains("Superfluous version") || msg.contains("Property 'blubb' is not declared") + || msg.contains("blubb.txt' does not exist") + || msg.contains("this one comes from a thread") + || msg.contains("Product 'theOtherProduct' had errors and was disabled") + || msg.contains("Product 'theThirdProduct' had errors and was disabled") + || msg.contains("Product 'theProduct' had errors and was disabled"), + qPrintable(msg)); } m_logSink->warnings.clear(); } @@ -2710,7 +2774,7 @@ void TestApi::runEnvForDisabledProduct() const qbs::SetupProjectParameters params = defaultSetupParameters("run-disabled-product/run-disabled-product.qbs"); const std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(params, - m_logSink, 0)); + m_logSink, nullptr)); QVERIFY(waitForFinished(setupJob.get())); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); const qbs::Project project = setupJob->project(); @@ -2747,7 +2811,7 @@ void TestApi::sourceFileInBuildDir() const QString generatedFile = relativeProductBuildDir("theProduct") + "/generated.cpp"; QVERIFY2(regularFileExists(generatedFile), qPrintable(generatedFile)); std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); const qbs::ProjectData projectData = job->project().projectData(); @@ -2820,7 +2884,7 @@ void TestApi::targetArtifactStatus() = defaultSetupParameters("target-artifact-status/target-artifact-status.qbs"); params.setOverriddenValues({std::make_pair("products.p.enableTagging", enableTagging)}); const std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(params, - m_logSink, 0)); + m_logSink, nullptr)); waitForFinished(setupJob.get()); VERIFY_NO_ERROR(setupJob->error()); const qbs::Project project = setupJob->project(); @@ -2838,10 +2902,13 @@ void TestApi::targetArtifactStatus() void TestApi::timeout() { QFETCH(QString, projectDirName); + QFETCH(QString, cancelOutput); const auto setupParams = defaultSetupParameters(projectDirName + "/timeout.qbs"); std::unique_ptr<qbs::SetupProjectJob> setupJob{ qbs::Project().setupProject(setupParams, m_logSink, nullptr)}; waitForFinished(setupJob.get()); + if (m_logSink->output.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); auto project = setupJob->project(); const auto products = project.projectData().products(); @@ -2868,42 +2935,54 @@ void TestApi::timeout() const auto errorString = buildJob->error().toString(); QVERIFY2(errorString.contains("cancel"), qPrintable(errorString)); QVERIFY(errorString.contains("timeout")); + QVERIFY(errorString.contains(cancelOutput)); } void TestApi::timeout_data() { QTest::addColumn<QString>("projectDirName"); - QTest::newRow("JS Command") << QString("timeout-js"); - QTest::newRow("Process Command") << QString("timeout-process"); + QTest::addColumn<QString>("cancelOutput"); + QTest::newRow("JS Command") << QString("timeout-js") << QString("infinite loop"); + QTest::newRow("Process Command") << QString("timeout-process") << QString("infinite-loop"); } void TestApi::toolInModule() { QVariantMap overrides({std::make_pair("qbs.installRoot", m_workingDataDir + "/tool-in-module/use-outside-project")}); - const qbs::ErrorInfo error - = doBuildProject("tool-in-module/use-within-project/use-within-project.qbs", nullptr, - nullptr, nullptr, qbs::BuildOptions(), overrides); - QVERIFY2(!error.hasError(), qPrintable(error.toString())); + + qbs::SetupProjectParameters params + = defaultSetupParameters("tool-in-module/use-within-project/use-within-project.qbs"); + params.setOverriddenValues(overrides); + std::unique_ptr<qbs::SetupProjectJob> setupJob( + qbs::Project().setupProject(params, m_logSink, nullptr)); + QVERIFY(waitForFinished(setupJob.get())); + QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); + if (m_logSink->output.contains("Skip this test")) + QSKIP("Skip this test"); + + std::unique_ptr<qbs::BuildJob> buildJob(setupJob->project() + .buildAllProducts(qbs::BuildOptions())); + + QVERIFY(waitForFinished(buildJob.get())); + QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); + const QString toolOutput = relativeProductBuildDir("user-in-project") + "/tool-output.txt"; QVERIFY2(QFile::exists(toolOutput), qPrintable(toolOutput)); - const qbs::SetupProjectParameters params - = defaultSetupParameters("tool-in-module/use-outside-project/use-outside-project.qbs"); - const std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(params, - m_logSink, 0)); + params = defaultSetupParameters("tool-in-module/use-outside-project/use-outside-project.qbs"); + setupJob.reset(qbs::Project().setupProject(params, m_logSink, nullptr)); QVERIFY(waitForFinished(setupJob.get())); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); - const qbs::Project project = setupJob->project(); - const qbs::ProjectData projectData = project.projectData(); - const QList<qbs::ProductData> products = projectData.products(); + const auto project = setupJob->project(); + const auto projectData = project.projectData(); + const auto products = projectData.products(); QCOMPARE(products.size(), 1); const qbs::ProductData product = products.front(); const auto groups = product.groups(); for (const qbs::GroupData &group : groups) QVERIFY(group.name() != "thetool binary"); - const std::unique_ptr<qbs::BuildJob> buildJob(setupJob->project() - .buildAllProducts(qbs::BuildOptions())); + buildJob.reset(setupJob->project().buildAllProducts(qbs::BuildOptions())); QVERIFY(waitForFinished(buildJob.get())); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); const QString toolOutput2 = relativeProductBuildDir("user-outside-project") @@ -2917,18 +2996,18 @@ void TestApi::trackAddQObjectHeader() = defaultSetupParameters("missing-qobject-header/missingheader.qbs"); QFile qbsFile(params.projectFilePath()); QVERIFY(qbsFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); - qbsFile.write("import qbs.base 1.0\nCppApplication {\n Depends { name: 'Qt.core' }\n" + qbsFile.write("CppApplication {\n Depends { name: 'Qt.core' }\n" " files: ['main.cpp', 'myobject.cpp']\n}"); qbsFile.close(); ProcessResultReceiver receiver; qbs::ErrorInfo errorInfo - = doBuildProject("missing-qobject-header/missingheader.qbs", 0, &receiver); + = doBuildProject("missing-qobject-header/missingheader.qbs", nullptr, &receiver); QVERIFY(errorInfo.hasError()); QVERIFY2(isAboutUndefinedSymbols(receiver.output), qPrintable(receiver.output)); WAIT_FOR_NEW_TIMESTAMP(); QVERIFY(qbsFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); - qbsFile.write("import qbs.base 1.0\nCppApplication {\n Depends { name: 'Qt.core' }\n" + qbsFile.write("CppApplication {\n Depends { name: 'Qt.core' }\n" " files: ['main.cpp', 'myobject.cpp','myobject.h']\n}"); qbsFile.close(); errorInfo = doBuildProject("missing-qobject-header/missingheader.qbs"); @@ -2942,7 +3021,7 @@ void TestApi::trackRemoveQObjectHeader() removeBuildDir(params); QFile qbsFile(params.projectFilePath()); QVERIFY(qbsFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); - qbsFile.write("import qbs.base 1.0\nCppApplication {\n Depends { name: 'Qt.core' }\n" + qbsFile.write("CppApplication {\n Depends { name: 'Qt.core' }\n" " files: ['main.cpp', 'myobject.cpp','myobject.h']\n}"); qbsFile.close(); qbs::ErrorInfo errorInfo = doBuildProject("missing-qobject-header/missingheader.qbs"); @@ -2950,11 +3029,11 @@ void TestApi::trackRemoveQObjectHeader() WAIT_FOR_NEW_TIMESTAMP(); QVERIFY(qbsFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); - qbsFile.write("import qbs.base 1.0\nCppApplication {\n Depends { name: 'Qt.core' }\n" + qbsFile.write("CppApplication {\n Depends { name: 'Qt.core' }\n" " files: ['main.cpp', 'myobject.cpp']\n}"); qbsFile.close(); ProcessResultReceiver receiver; - errorInfo = doBuildProject("missing-qobject-header/missingheader.qbs", 0, &receiver); + errorInfo = doBuildProject("missing-qobject-header/missingheader.qbs", nullptr, &receiver); QVERIFY(errorInfo.hasError()); QVERIFY2(isAboutUndefinedSymbols(receiver.output), qPrintable(receiver.output)); } @@ -2964,7 +3043,7 @@ void TestApi::transformerData() const qbs::SetupProjectParameters params = defaultSetupParameters("transformer-data/transformer-data.qbs"); const std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(params, - m_logSink, 0)); + m_logSink, nullptr)); QVERIFY(waitForFinished(setupJob.get())); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); const qbs::Project project = setupJob->project(); @@ -3038,13 +3117,13 @@ void TestApi::uic() qbs::ErrorInfo TestApi::doBuildProject( const QString &projectFilePath, BuildDescriptionReceiver *buildDescriptionReceiver, ProcessResultReceiver *procResultReceiver, TaskReceiver *taskReceiver, - const qbs::BuildOptions &options, const QVariantMap overriddenValues) + const qbs::BuildOptions &options, const QVariantMap &overriddenValues) { qbs::SetupProjectParameters params = defaultSetupParameters(projectFilePath); params.setOverriddenValues(overriddenValues); params.setDryRun(options.dryRun()); const std::unique_ptr<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(params, - m_logSink, 0)); + m_logSink, nullptr)); if (taskReceiver) { connect(setupJob.get(), &qbs::AbstractJob::taskStarted, taskReceiver, &TaskReceiver::handleTaskStart); diff --git a/tests/auto/api/tst_api.h b/tests/auto/api/tst_api.h index aa00ddc99..cca6d4970 100644 --- a/tests/auto/api/tst_api.h +++ b/tests/auto/api/tst_api.h @@ -69,9 +69,7 @@ private slots: void buildProjectDryRun_data(); void buildSingleFile(); void canonicalToolchainList(); -#ifdef QBS_ENABLE_PROJECT_FILE_UPDATES void changeContent(); -#endif void changeDependentLib(); void checkOutputs(); void checkOutputs_data(); @@ -80,6 +78,7 @@ private slots: void disabledInstallGroup(); void disabledProduct(); void disabledProject(); + void disappearedWildcardFile(); void duplicateProductNames(); void duplicateProductNames_data(); void emptyFileTagList(); @@ -132,6 +131,7 @@ private slots: void removeFileDependency(); void renameProduct(); void renameTargetArtifact(); + void renamedQbsSource(); void resolveProject(); void resolveProject_data(); void resolveProjectDryRun(); @@ -161,7 +161,7 @@ private: ProcessResultReceiver *procResultReceiver = 0, TaskReceiver *taskReceiver = 0, const qbs::BuildOptions &options = qbs::BuildOptions(), - const QVariantMap overriddenValues = QVariantMap()); + const QVariantMap &overriddenValues = QVariantMap()); LogSink * const m_logSink; const QString m_sourceDataDir; diff --git a/tests/auto/auto.pri b/tests/auto/auto.pri deleted file mode 100644 index fd8afad50..000000000 --- a/tests/auto/auto.pri +++ /dev/null @@ -1,18 +0,0 @@ -TEMPLATE = app -DESTDIR = ../../../bin -DEFINES += SRCDIR=\\\"$$_PRO_FILE_PWD_\\\" -qbs_test_suite_name = $$replace(_PRO_FILE_, ^.*/([^/.]+)\\.pro$, \\1) -qbs_test_suite_name = $$upper($$replace(qbs_test_suite_name, -, _)) -DEFINES += QBS_TEST_SUITE_NAME=\\\"$${qbs_test_suite_name}\\\" -INCLUDEPATH += $$PWD/../../src $$PWD/../../src/app/shared - -QT = core testlib -CONFIG += testcase console -CONFIG -= app_bundle -CONFIG += c++14 -target.CONFIG += no_default_install - -dev_lib_frameworks=$$QMAKE_XCODE_DEVELOPER_PATH/Library/Frameworks -exists($$dev_lib_frameworks): LIBS += -F$$dev_lib_frameworks - -include(../../src/lib/corelib/use_corelib.pri) diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro deleted file mode 100644 index 1afe48176..000000000 --- a/tests/auto/auto.pro +++ /dev/null @@ -1,19 +0,0 @@ -TEMPLATE=subdirs - -qbs_enable_unit_tests { - SUBDIRS += \ - buildgraph \ - language \ - tools \ -} - -SUBDIRS += \ - cmdlineparser \ - blackbox/blackbox.pro \ - blackbox/blackbox-android.pro \ - blackbox/blackbox-apple.pro \ - blackbox/blackbox-clangdb.pro \ - blackbox/blackbox-java.pro \ - blackbox/blackbox-joblimits.pro \ - blackbox/blackbox-qt.pro \ - api diff --git a/tests/auto/auto.qbs b/tests/auto/auto.qbs index bf75d0f23..b042d180a 100644 --- a/tests/auto/auto.qbs +++ b/tests/auto/auto.qbs @@ -1,19 +1,23 @@ -import qbs - Project { name: "Autotests" references: [ "api/api.qbs", - "blackbox/blackbox.qbs", "blackbox/blackbox-android.qbs", "blackbox/blackbox-apple.qbs", + "blackbox/blackbox-baremetal.qbs", "blackbox/blackbox-clangdb.qbs", + "blackbox/blackbox-examples.qbs", "blackbox/blackbox-java.qbs", "blackbox/blackbox-joblimits.qbs", + "blackbox/blackbox-providers.qbs", "blackbox/blackbox-qt.qbs", + "blackbox/blackbox-tutorial.qbs", + "blackbox/blackbox-windows.qbs", + "blackbox/blackbox.qbs", "buildgraph/buildgraph.qbs", "cmdlineparser/cmdlineparser.qbs", "language/language.qbs", + "pkgconfig/pkgconfig.qbs", "tools/tools.qbs", ] } diff --git a/tests/auto/blackbox/CMakeLists.txt b/tests/auto/blackbox/CMakeLists.txt new file mode 100644 index 000000000..88e19acdf --- /dev/null +++ b/tests/auto/blackbox/CMakeLists.txt @@ -0,0 +1,99 @@ +add_qbs_test(blackbox + DEFINES + ${QBS_UNIT_TESTS_DEFINES} + "QBS_VERSION=\"${QBS_VERSION}\"" + SOURCES + ../shared.h + tst_blackboxbase.cpp + tst_blackboxbase.h + tst_blackbox.cpp + tst_blackbox.h + ) + +add_qbs_test(blackbox-android + SOURCES + ../shared.h + tst_blackboxbase.cpp + tst_blackboxbase.h + tst_blackboxandroid.cpp + tst_blackboxandroid.h + ) + +add_qbs_test(blackbox-apple + SOURCES + ../shared.h + tst_blackboxbase.cpp + tst_blackboxbase.h + tst_blackboxapple.cpp + tst_blackboxapple.h + ) + +add_qbs_test(blackbox-baremetal + SOURCES + ../shared.h + tst_blackboxbase.cpp + tst_blackboxbase.h + tst_blackboxbaremetal.cpp + tst_blackboxbaremetal.h + ) + +add_qbs_test(blackbox-clangdb + SOURCES + ../shared.h + tst_blackboxbase.cpp + tst_blackboxbase.h + tst_clangdb.cpp + tst_clangdb.h + ) + +add_qbs_test(blackbox-java + SOURCES + ../shared.h + tst_blackboxbase.cpp + tst_blackboxbase.h + tst_blackboxjava.cpp + tst_blackboxjava.h + ) + +add_qbs_test(blackbox-joblimits + SOURCES + ../shared.h + tst_blackboxbase.cpp + tst_blackboxbase.h + tst_blackboxjoblimits.cpp + ) + +add_qbs_test(blackbox-providers + SOURCES + ../shared.h + tst_blackboxbase.cpp + tst_blackboxbase.h + tst_blackboxproviders.cpp + ) + +add_qbs_test(blackbox-qt + SOURCES + ../shared.h + tst_blackboxbase.cpp + tst_blackboxbase.h + tst_blackboxqt.cpp + tst_blackboxqt.h + ) + +add_qbs_test(blackbox-tutorial + SOURCES + ../shared.h + tst_blackboxbase.cpp + tst_blackboxbase.h + tst_blackboxtutorial.h + tst_blackboxtutorial.cpp + ) + +add_qbs_test(blackbox-windows + SOURCES + ../shared.h + tst_blackboxbase.cpp + tst_blackboxbase.h + tst_blackboxwindows.cpp + tst_blackboxwindows.h + ) diff --git a/tests/auto/blackbox/blackbox-android.pro b/tests/auto/blackbox/blackbox-android.pro deleted file mode 100644 index 7aca99e8d..000000000 --- a/tests/auto/blackbox/blackbox-android.pro +++ /dev/null @@ -1,21 +0,0 @@ -TARGET = tst_blackbox-android - -HEADERS = tst_blackboxandroid.h tst_blackboxbase.h -SOURCES = tst_blackboxandroid.cpp tst_blackboxbase.cpp -OBJECTS_DIR = android -MOC_DIR = $${OBJECTS_DIR}-moc - -include(../auto.pri) - -DATA_DIRS = testdata-android ../find - -for(data_dir, DATA_DIRS) { - files = $$files($$PWD/$$data_dir/*, true) - win32:files ~= s|\\\\|/|g - for(file, files):!exists($$file/*):FILES += $$file -} - -OTHER_FILES += $$FILES - -DISTFILES += \ - testdata/texttemplate/expected-output-one.txt diff --git a/tests/auto/blackbox/blackbox-apple.pro b/tests/auto/blackbox/blackbox-apple.pro deleted file mode 100644 index 1a009e222..000000000 --- a/tests/auto/blackbox/blackbox-apple.pro +++ /dev/null @@ -1,20 +0,0 @@ -TARGET = tst_blackbox-apple - -HEADERS = tst_blackboxapple.h tst_blackboxbase.h -SOURCES = tst_blackboxapple.cpp tst_blackboxbase.cpp -OBJECTS_DIR = apple -MOC_DIR = $${OBJECTS_DIR}-moc - -include(../auto.pri) - -QT += xml - -DATA_DIRS = testdata-apple ../find - -for(data_dir, DATA_DIRS) { - files = $$files($$PWD/$$data_dir/*, true) - win32:files ~= s|\\\\|/|g - for(file, files):!exists($$file/*):FILES += $$file -} - -OTHER_FILES += $$FILES diff --git a/tests/auto/blackbox/blackbox-baremetal.qbs b/tests/auto/blackbox/blackbox-baremetal.qbs new file mode 100644 index 000000000..18ae588fe --- /dev/null +++ b/tests/auto/blackbox/blackbox-baremetal.qbs @@ -0,0 +1,21 @@ +import qbs.Utilities + +QbsAutotest { + testName: "blackbox-baremetal" + Depends { name: "qbs_app" } + Depends { name: "qbs-setup-toolchains" } + Group { + name: "testdata" + prefix: "testdata-baremetal/" + files: ["**/*"] + fileTags: [] + } + files: [ + "../shared.h", + "tst_blackboxbase.cpp", + "tst_blackboxbase.h", + "tst_blackboxbaremetal.cpp", + "tst_blackboxbaremetal.h", + ] + cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) +} diff --git a/tests/auto/blackbox/blackbox-clangdb.pro b/tests/auto/blackbox/blackbox-clangdb.pro deleted file mode 100644 index 6e4075175..000000000 --- a/tests/auto/blackbox/blackbox-clangdb.pro +++ /dev/null @@ -1,18 +0,0 @@ -TARGET = tst_blackbox-clangdb - -HEADERS = tst_blackboxbase.h tst_clangdb.h -SOURCES = tst_blackboxbase.cpp tst_clangdb.cpp -OBJECTS_DIR = clangdb -MOC_DIR = $${OBJECTS_DIR}-moc - -include(../auto.pri) - -DATA_DIRS = testdata-clangdb - -for(data_dir, DATA_DIRS) { - files = $$files($$PWD/$$data_dir/*, true) - win32:files ~= s|\\\\|/|g - for(file, files):!exists($$file/*):FILES += $$file -} - -OTHER_FILES += $$FILES diff --git a/tests/auto/blackbox/blackbox-examples.qbs b/tests/auto/blackbox/blackbox-examples.qbs new file mode 100644 index 000000000..77d32636c --- /dev/null +++ b/tests/auto/blackbox/blackbox-examples.qbs @@ -0,0 +1,21 @@ +import qbs.Utilities + +QbsAutotest { + testName: "blackbox-examples" + Depends { name: "qbs_app" } + Depends { name: "qbs-setup-toolchains" } + Group { + name: "testdata" + prefix: "../../../examples/" + files: ["**/*"] + fileTags: [] + } + files: [ + "../shared.h", + "tst_blackboxexamples.cpp", + "tst_blackboxexamples.h", + "tst_blackboxbase.cpp", + "tst_blackboxbase.h", + ] + cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) +} diff --git a/tests/auto/blackbox/blackbox-java.pro b/tests/auto/blackbox/blackbox-java.pro deleted file mode 100644 index d297d9e09..000000000 --- a/tests/auto/blackbox/blackbox-java.pro +++ /dev/null @@ -1,18 +0,0 @@ -TARGET = tst_blackbox-java - -HEADERS = tst_blackboxjava.h tst_blackboxbase.h -SOURCES = tst_blackboxjava.cpp tst_blackboxbase.cpp -OBJECTS_DIR = java -MOC_DIR = $${OBJECTS_DIR}-moc - -include(../auto.pri) - -DATA_DIRS = testdata-java ../find - -for(data_dir, DATA_DIRS) { - files = $$files($$PWD/$$data_dir/*, true) - win32:files ~= s|\\\\|/|g - for(file, files):!exists($$file/*):FILES += $$file -} - -OTHER_FILES += $$FILES diff --git a/tests/auto/blackbox/blackbox-joblimits.pro b/tests/auto/blackbox/blackbox-joblimits.pro deleted file mode 100644 index 85413473e..000000000 --- a/tests/auto/blackbox/blackbox-joblimits.pro +++ /dev/null @@ -1,18 +0,0 @@ -TARGET = tst_blackbox-joblimits - -HEADERS = tst_blackboxbase.h -SOURCES = tst_blackboxjoblimits.cpp tst_blackboxbase.cpp -OBJECTS_DIR = joblimits -MOC_DIR = $${OBJECTS_DIR}-moc - -include(../auto.pri) - -DATA_DIRS = testdata-joblimits ../find - -for(data_dir, DATA_DIRS) { - files = $$files($$PWD/$$data_dir/*, true) - win32:files ~= s|\\\\|/|g - for(file, files):!exists($$file/*):FILES += $$file -} - -OTHER_FILES += $$FILES diff --git a/tests/auto/blackbox/blackbox-providers.qbs b/tests/auto/blackbox/blackbox-providers.qbs new file mode 100644 index 000000000..95ebaa423 --- /dev/null +++ b/tests/auto/blackbox/blackbox-providers.qbs @@ -0,0 +1,21 @@ +import qbs.Utilities + +QbsAutotest { + testName: "blackbox-providers" + Depends { name: "qbs_app" } + Depends { name: "qbs-setup-toolchains" } + Group { + name: "testdata" + prefix: "testdata-providers/" + files: ["**/*"] + fileTags: [] + } + files: [ + "../shared.h", + "tst_blackboxbase.cpp", + "tst_blackboxbase.h", + "tst_blackboxproviders.cpp", + "tst_blackboxproviders.h", + ] + cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) +} diff --git a/tests/auto/blackbox/blackbox-qt.pro b/tests/auto/blackbox/blackbox-qt.pro deleted file mode 100644 index e17a04a7e..000000000 --- a/tests/auto/blackbox/blackbox-qt.pro +++ /dev/null @@ -1,18 +0,0 @@ -TARGET = tst_blackbox-qt - -HEADERS = tst_blackboxqt.h tst_blackboxbase.h -SOURCES = tst_blackboxqt.cpp tst_blackboxbase.cpp -OBJECTS_DIR = qt -MOC_DIR = $${OBJECTS_DIR}-moc - -include(../auto.pri) - -DATA_DIRS = testdata-qt ../find - -for(data_dir, DATA_DIRS) { - files = $$files($$PWD/$$data_dir/*, true) - win32:files ~= s|\\\\|/|g - for(file, files):!exists($$file/*):FILES += $$file -} - -OTHER_FILES += $$FILES diff --git a/tests/auto/blackbox/blackbox-tutorial.qbs b/tests/auto/blackbox/blackbox-tutorial.qbs new file mode 100644 index 000000000..174821ffa --- /dev/null +++ b/tests/auto/blackbox/blackbox-tutorial.qbs @@ -0,0 +1,21 @@ +import qbs.Utilities + +QbsAutotest { + testName: "blackbox-tutorial" + Depends { name: "qbs_app" } + Depends { name: "qbs-setup-toolchains" } + Group { + name: "testdata" + prefix: "../../../tutorial/" + files: ["**/*"] + fileTags: [] + } + files: [ + "../shared.h", + "tst_blackboxtutorial.cpp", + "tst_blackboxtutorial.h", + "tst_blackboxbase.cpp", + "tst_blackboxbase.h", + ] + cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) +} diff --git a/tests/auto/blackbox/blackbox-windows.qbs b/tests/auto/blackbox/blackbox-windows.qbs new file mode 100644 index 000000000..e32421e3b --- /dev/null +++ b/tests/auto/blackbox/blackbox-windows.qbs @@ -0,0 +1,21 @@ +import qbs.Utilities + +QbsAutotest { + testName: "blackbox-windows" + Depends { name: "qbs_app" } + Depends { name: "qbs-setup-toolchains" } + Group { + name: "testdata" + prefix: "testdata-windows/" + files: ["**/*"] + fileTags: [] + } + files: [ + "../shared.h", + "tst_blackboxbase.cpp", + "tst_blackboxbase.h", + "tst_blackboxwindows.cpp", + "tst_blackboxwindows.h", + ] + cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) +} diff --git a/tests/auto/blackbox/blackbox.pro b/tests/auto/blackbox/blackbox.pro deleted file mode 100644 index 42848d077..000000000 --- a/tests/auto/blackbox/blackbox.pro +++ /dev/null @@ -1,21 +0,0 @@ -TARGET = tst_blackbox - -HEADERS = tst_blackbox.h tst_blackboxbase.h -SOURCES = tst_blackbox.cpp tst_blackboxbase.cpp -OBJECTS_DIR = generic -MOC_DIR = $${OBJECTS_DIR}-moc -qbs_enable_unit_tests:DEFINES += QBS_ENABLE_UNIT_TESTS - -include(../auto.pri) - -QT += xml - -DATA_DIRS = testdata ../find - -for(data_dir, DATA_DIRS) { - files = $$files($$PWD/$$data_dir/*, true) - win32:files ~= s|\\\\|/|g - for(file, files):!exists($$file/*):FILES += $$file -} - -OTHER_FILES += $$FILES diff --git a/tests/auto/blackbox/blackbox.qbs b/tests/auto/blackbox/blackbox.qbs index 3f0ff959a..ac6bf750e 100644 --- a/tests/auto/blackbox/blackbox.qbs +++ b/tests/auto/blackbox/blackbox.qbs @@ -25,4 +25,5 @@ QbsAutotest { ] cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) .concat(qbsbuildconfig.enableUnitTests ? ["QBS_ENABLE_UNIT_TESTS"] : []) + .concat("QBS_VERSION=" + Utilities.cStringQuote(qbsversion.version)) } diff --git a/tests/auto/blackbox/find/find-android.qbs b/tests/auto/blackbox/find/find-android.qbs index 26dedc60f..1cde0ed84 100644 --- a/tests/auto/blackbox/find/find-android.qbs +++ b/tests/auto/blackbox/find/find-android.qbs @@ -3,12 +3,23 @@ import qbs.TextFile Product { property string packageName: "" qbs.targetPlatform: "android" + multiplexByQbsProperties: ["architectures"] + + Properties { + condition: qbs.architectures && qbs.architectures.length > 1 + aggregate: true + multiplexedType: "json_arch" + } Depends { name: "Android.sdk"; required: false } Depends { name: "Android.ndk"; required: false } type: ["json"] + Rule { multiplex: true + property stringList inputTags: "json_arch" + inputsFromDependencies: inputTags + inputs: product.aggregate ? [] : inputTags Artifact { filePath: ["android.json"] fileTags: ["json"] @@ -18,17 +29,51 @@ Product { cmd.description = output.filePath; cmd.sourceCode = function() { var tools = {}; + + for (var i in inputs["json_arch"]) { + var tf = new TextFile(inputs["json_arch"][i].filePath, TextFile.ReadOnly); + var json = JSON.parse(tf.readAll()); + tools["ndk"] = json["ndk"]; + tools["ndk-samples"] = json["ndk-samples"]; + tf.close(); + } + if (product.moduleProperty("Android.sdk", "present")) { tools["sdk"] = product.moduleProperty("Android.sdk", "sdkDir"); tools["sdk-build-tools-dx"] = product.Android.sdk.dxFilePath; + tools["sdk-build-tools-d8"] = product.Android.sdk.d8FilePath; } + if (product.java && product.java.present) + tools["jar"] = product.java.jarFilePath; + + var tf; + try { + tf = new TextFile(output.filePath, TextFile.WriteOnly); + tf.writeLine(JSON.stringify(tools, undefined, 4)); + } finally { + if (tf) + tf.close(); + } + }; + return cmd; + } + } + Rule { + multiplex: true + Artifact { + filePath: ["android_arch.json"] + fileTags: ["json_arch"] + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = output.filePath; + cmd.sourceCode = function() { + var tools = {}; if (product.moduleProperty("Android.ndk", "present")) { tools["ndk"] = product.moduleProperty("Android.ndk", "ndkDir"); tools["ndk-samples"] = product.Android.ndk.ndkSamplesDir; } - if (product.java && product.java.present) - tools["jar"] = product.java.jarFilePath; var tf; try { @@ -43,3 +88,4 @@ Product { } } } + diff --git a/tests/auto/blackbox/find/find-xcode.qbs b/tests/auto/blackbox/find/find-xcode.qbs index bb6ee9718..15c2aa17e 100644 --- a/tests/auto/blackbox/find/find-xcode.qbs +++ b/tests/auto/blackbox/find/find-xcode.qbs @@ -14,7 +14,9 @@ Product { cmd.description = output.filePath; cmd.sourceCode = function() { var tools = {}; - if (product.moduleProperty("xcode", "present")) { + var present = product.moduleProperty("xcode", "present"); + tools["present"] = !!present; + if (present) { var keys = [ "developerPath", "version" diff --git a/tests/auto/blackbox/testdata-android/aidl/AndroidManifest.xml b/tests/auto/blackbox/testdata-android/aidl/AndroidManifest.xml index e8a950847..1d27681ac 100644 --- a/tests/auto/blackbox/testdata-android/aidl/AndroidManifest.xml +++ b/tests/auto/blackbox/testdata-android/aidl/AndroidManifest.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" + android:versionName="1.0" android:versionCode="1" package="io.qbs.aidltest"> <application android:label="AidlTest"> <activity android:name="MainActivity"> diff --git a/tests/auto/blackbox/testdata-android/minimal-native/minimal-native.qbs b/tests/auto/blackbox/testdata-android/minimal-native/minimal-native.qbs index 570152707..7231f7e62 100644 --- a/tests/auto/blackbox/testdata-android/minimal-native/minimal-native.qbs +++ b/tests/auto/blackbox/testdata-android/minimal-native/minimal-native.qbs @@ -1,7 +1,7 @@ CppApplication { name: "minimalnative" qbs.buildVariant: "release" - Properties { condition: qbs.toolchain.contains("clang"); Android.ndk.appStl: "c++_shared" } + Properties { condition: qbs.toolchain.includes("clang"); Android.ndk.appStl: "c++_shared" } Android.sdk.packageName: "my.minimalnative" Android.sdk.apkBaseName: name Android.ndk.appStl: "stlport_shared" diff --git a/tests/auto/blackbox/testdata-android/minimal-native/src/main/AndroidManifest.xml b/tests/auto/blackbox/testdata-android/minimal-native/src/main/AndroidManifest.xml index 575e95e8d..f61dc9850 100644 --- a/tests/auto/blackbox/testdata-android/minimal-native/src/main/AndroidManifest.xml +++ b/tests/auto/blackbox/testdata-android/minimal-native/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" + android:versionName="1.0" android:versionCode="1" package="somedefault"> <application android:label="MinimalNative"> <activity android:name="MainActivity"> diff --git a/tests/auto/blackbox/testdata-android/minimal-native/src/main/native/native.c b/tests/auto/blackbox/testdata-android/minimal-native/src/main/native/native.c index 6b625858b..f49b4f90f 100644 --- a/tests/auto/blackbox/testdata-android/minimal-native/src/main/native/native.c +++ b/tests/auto/blackbox/testdata-android/minimal-native/src/main/native/native.c @@ -4,5 +4,6 @@ jstring Java_minimalnative_MinimalNative_stringFromNative(JNIEnv* env, jobject thiz) { + (void)thiz; return (*env)->NewStringUTF(env, "This message comes from native code."); } diff --git a/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/product1.qbs b/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/product1.qbs index c4a78a30b..c7b9b3de2 100644 --- a/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/product1.qbs +++ b/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/product1.qbs @@ -5,9 +5,12 @@ Project { name: "p1lib1" files: ["src/main/jni/lib1.cpp"] qbs.targetPlatform: "android" - Properties { condition: qbs.toolchain.contains("clang"); Android.ndk.appStl: "c++_shared" } + Properties { condition: qbs.toolchain.includes("clang"); Android.ndk.appStl: "c++_shared" } Android.ndk.appStl: "stlport_shared" - qbs.architectures: !qbs.architecture ? ["armv7a", "x86"] : undefined + Properties { + qbs.architectures: !qbs.architecture ? ["armv7a", "x86"] : undefined + overrideListProperties: true + } cpp.useRPaths: false } @@ -17,7 +20,7 @@ Project { name: "p1lib2" files: ["src/main/jni/lib2.cpp"] qbs.targetPlatform: "android" - Properties { condition: qbs.toolchain.contains("clang"); Android.ndk.appStl: "c++_shared" } + Properties { condition: qbs.toolchain.includes("clang"); Android.ndk.appStl: "c++_shared" } Android.ndk.appStl: "stlport_shared" cpp.useRPaths: false } diff --git a/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/AndroidManifest.xml b/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/AndroidManifest.xml index 289969409..272fe55de 100644 --- a/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/AndroidManifest.xml +++ b/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.qt.dummy1" android:versionCode="1" android:versionName="1.0"> - <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="19"/> + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/> <uses-feature android:glEsVersion="0x00020000"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:allowBackup="true" android:hasCode="true"> diff --git a/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/product2.qbs b/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/product2.qbs index 9be70dcda..f880a576d 100644 --- a/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/product2.qbs +++ b/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/product2.qbs @@ -13,7 +13,7 @@ Project { name: "p2lib2" files: ["src/main/jni/lib2.cpp"] qbs.targetPlatform: "android" - Properties { condition: qbs.toolchain.contains("clang"); Android.ndk.appStl: "c++_shared" } + Properties { condition: qbs.toolchain.includes("clang"); Android.ndk.appStl: "c++_shared" } Android.ndk.appStl: "stlport_shared" } diff --git a/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/AndroidManifest.xml b/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/AndroidManifest.xml index ef0fbe54f..871aadbe6 100644 --- a/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/AndroidManifest.xml +++ b/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.qt.dummy2" android:versionCode="1" android:versionName="1.0"> - <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="19"/> + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/> <uses-feature android:glEsVersion="0x00020000"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:allowBackup="true" android:hasCode="true"> diff --git a/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/multiple-libs-per-apk.qbs b/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/multiple-libs-per-apk.qbs index 8b9ded211..a5e193905 100644 --- a/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/multiple-libs-per-apk.qbs +++ b/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/multiple-libs-per-apk.qbs @@ -5,7 +5,7 @@ Project { name: "lib1" files: ["src/main/jni/lib1.cpp"] qbs.targetPlatform: "android" - Properties { condition: qbs.toolchain.contains("clang"); Android.ndk.appStl: "c++_shared" } + Properties { condition: qbs.toolchain.includes("clang"); Android.ndk.appStl: "c++_shared" } Android.ndk.appStl: "stlport_shared" cpp.useRPaths: false } @@ -16,7 +16,7 @@ Project { name: "lib2" files: ["src/main/jni/lib2.cpp"] qbs.targetPlatform: "android" - Properties { condition: qbs.toolchain.contains("clang"); Android.ndk.appStl: "c++_shared" } + Properties { condition: qbs.toolchain.includes("clang"); Android.ndk.appStl: "c++_shared" } Android.ndk.appStl: "stlport_shared" cpp.useRPaths: false } diff --git a/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/AndroidManifest.xml b/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/AndroidManifest.xml index 6694afc18..f184a8f1f 100644 --- a/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/AndroidManifest.xml +++ b/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.qt.dummy" android:versionCode="1" android:versionName="1.0"> - <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="19"/> + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/> <uses-feature android:glEsVersion="0x00020000"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:allowBackup="true" android:hasCode="true"> diff --git a/tests/auto/blackbox/testdata-android/qml-app/qml-app.qbs b/tests/auto/blackbox/testdata-android/qml-app/qml-app.qbs index e91a14902..5760fa4f0 100644 --- a/tests/auto/blackbox/testdata-android/qml-app/qml-app.qbs +++ b/tests/auto/blackbox/testdata-android/qml-app/qml-app.qbs @@ -3,12 +3,12 @@ QtApplication { Depends { name: "Qt.quick" } Depends { name: "Qt.android_support" } Properties { - condition: qbs.targetOS.contains("android") + condition: qbs.targetOS.includes("android") Qt.android_support.extraPrefixDirs: path } Android.sdk.packageName: "my.qmlapp" Android.sdk.apkBaseName: name - property stringList qmlImportPaths: path + Qt.android_support.qmlImportPaths: path files: [ "main.cpp", "qml.qrc", diff --git a/tests/auto/blackbox/testdata-android/qml-app/src/main/AndroidManifest.xml b/tests/auto/blackbox/testdata-android/qml-app/src/main/AndroidManifest.xml index 066ec0a63..c8237c639 100644 --- a/tests/auto/blackbox/testdata-android/qml-app/src/main/AndroidManifest.xml +++ b/tests/auto/blackbox/testdata-android/qml-app/src/main/AndroidManifest.xml @@ -16,7 +16,6 @@ <!-- Application arguments --> <meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/> - <meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/> <meta-data android:name="android.app.repository" android:value="default"/> <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/> <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/> @@ -31,8 +30,6 @@ <meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/> <meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/> <!-- Messages maps --> - <meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/> - <meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/> <meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/> <!-- Messages maps --> @@ -67,7 +64,7 @@ </application> - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="16"/> + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/> <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/> <!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application. diff --git a/tests/auto/blackbox/testdata-android/qt-app/MainWindow.cpp b/tests/auto/blackbox/testdata-android/qt-app/MainWindow.cpp new file mode 100644 index 000000000..b2e08c83e --- /dev/null +++ b/tests/auto/blackbox/testdata-android/qt-app/MainWindow.cpp @@ -0,0 +1,11 @@ +#include "MainWindow.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) +{ +} + +MainWindow::~MainWindow() +{ +} + diff --git a/tests/auto/blackbox/testdata-android/qt-app/MainWindow.h b/tests/auto/blackbox/testdata-android/qt-app/MainWindow.h new file mode 100644 index 000000000..ace53a4a0 --- /dev/null +++ b/tests/auto/blackbox/testdata-android/qt-app/MainWindow.h @@ -0,0 +1,15 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QMainWindow> + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); +}; + +#endif // MAINWINDOW_H diff --git a/tests/auto/blackbox/testdata-android/qt-app/Test.java b/tests/auto/blackbox/testdata-android/qt-app/Test.java new file mode 100644 index 000000000..c57486d56 --- /dev/null +++ b/tests/auto/blackbox/testdata-android/qt-app/Test.java @@ -0,0 +1,54 @@ +package org.qbs.example; + +import org.qtproject.qt5.android.bindings.QtActivity; +import android.os.*; +import android.content.*; +import android.app.*; +import android.util.Log; + +import java.lang.String; +import android.content.Intent; + +import org.qbs.example.*; + + +public class Test extends QtActivity +{ + public static native void testFunc(String test); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Log.d("qbs", "onCreate Test"); + Intent theIntent = getIntent(); + if (theIntent != null) { + String theAction = theIntent.getAction(); + if (theAction != null) { + Log.d("qbs onCreate ", theAction); + } + } + } + + @Override + public void onDestroy() { + Log.d("qbs", "onDestroy"); + System.exit(0); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + Log.d("qbs onActivityResult", "requestCode: "+requestCode); + if (resultCode == RESULT_OK) { + Log.d("qbs onActivityResult - resultCode: ", "SUCCESS"); + } else { + Log.d("qbs onActivityResult - resultCode: ", "CANCEL"); + } + } + + @Override + public void onNewIntent(Intent intent) { + Log.d("qbs", "onNewIntent"); + super.onNewIntent(intent); + setIntent(intent); + } +} diff --git a/tests/auto/blackbox/testdata-android/qt-app/TestQt6.java b/tests/auto/blackbox/testdata-android/qt-app/TestQt6.java new file mode 100644 index 000000000..239507122 --- /dev/null +++ b/tests/auto/blackbox/testdata-android/qt-app/TestQt6.java @@ -0,0 +1,54 @@ +package org.qbs.example; + +import org.qtproject.qt.android.bindings.QtActivity; +import android.os.*; +import android.content.*; +import android.app.*; +import android.util.Log; + +import java.lang.String; +import android.content.Intent; + +import org.qbs.example.*; + + +public class TestQt6 extends QtActivity +{ + public static native void testFunc(String test); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Log.d("qbs", "onCreate Test"); + Intent theIntent = getIntent(); + if (theIntent != null) { + String theAction = theIntent.getAction(); + if (theAction != null) { + Log.d("qbs onCreate ", theAction); + } + } + } + + @Override + public void onDestroy() { + Log.d("qbs", "onDestroy"); + System.exit(0); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + Log.d("qbs onActivityResult", "requestCode: "+requestCode); + if (resultCode == RESULT_OK) { + Log.d("qbs onActivityResult - resultCode: ", "SUCCESS"); + } else { + Log.d("qbs onActivityResult - resultCode: ", "CANCEL"); + } + } + + @Override + public void onNewIntent(Intent intent) { + Log.d("qbs", "onNewIntent"); + super.onNewIntent(intent); + setIntent(intent); + } +} diff --git a/tests/auto/blackbox/testdata-android/qt-app/main.cpp b/tests/auto/blackbox/testdata-android/qt-app/main.cpp new file mode 100644 index 000000000..0a0916fca --- /dev/null +++ b/tests/auto/blackbox/testdata-android/qt-app/main.cpp @@ -0,0 +1,11 @@ +#include "MainWindow.h" + +#include <QApplication> + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/tests/auto/blackbox/testdata-android/qt-app/qt-app.qbs b/tests/auto/blackbox/testdata-android/qt-app/qt-app.qbs new file mode 100644 index 000000000..04dcbf403 --- /dev/null +++ b/tests/auto/blackbox/testdata-android/qt-app/qt-app.qbs @@ -0,0 +1,27 @@ +Project { + QtGuiApplication { + Depends { name: "Lib" } + files: ["main.cpp", "MainWindow.cpp", "MainWindow.h" ] + Group { + condition: Qt.core.versionMajor == 5 + files: ["Test.java"] + } + Group { + condition: Qt.core.versionMajor == 6 + files: ["TestQt6.java"] + } + + Android.sdk.packageName: "my.qtapp" + Android.sdk.apkBaseName: name + Depends { name: "Qt"; submodules: ["core", "widgets"] } + } + + StaticLibrary { + name: "Lib" + Export { + Depends { + name: "Qt.android_support"; + } + } + } +} diff --git a/tests/auto/blackbox/testdata-android/qt-app/test.keystore b/tests/auto/blackbox/testdata-android/qt-app/test.keystore Binary files differnew file mode 100644 index 000000000..5713d10d2 --- /dev/null +++ b/tests/auto/blackbox/testdata-android/qt-app/test.keystore diff --git a/tests/auto/blackbox/testdata-android/teapot/teapot.qbs b/tests/auto/blackbox/testdata-android/teapot/teapot.qbs index 2b5cb8aba..0b1dead6e 100644 --- a/tests/auto/blackbox/testdata-android/teapot/teapot.qbs +++ b/tests/auto/blackbox/testdata-android/teapot/teapot.qbs @@ -51,7 +51,7 @@ Project { files: ["*.cpp", "*.h"].concat( !File.exists(ndkHelperProbe.dir + "/gl3stub.cpp") ? ["gl3stub.c"] : []) } - Properties { condition: qbs.toolchain.contains("clang"); Android.ndk.appStl: "c++_shared" } + Properties { condition: qbs.toolchain.includes("clang"); Android.ndk.appStl: "c++_shared" } Android.ndk.appStl: "gnustl_shared" cpp.cxxLanguageVersion: "c++11" @@ -133,10 +133,11 @@ Project { FileTagger { patterns: ["*.inl"]; fileTags: ["hpp"] } + version: "2.0" Android.sdk.apkBaseName: name Android.sdk.packageName: "com.sample.teapot" Android.sdk.sourceSetDir: teapotProbe.dir - Properties { condition: qbs.toolchain.contains("clang"); Android.ndk.appStl: "c++_shared" } + Properties { condition: qbs.toolchain.includes("clang"); Android.ndk.appStl: "c++_shared" } Android.ndk.appStl: "gnustl_shared" cpp.cxxLanguageVersion: "c++11" cpp.dynamicLibraries: ["log", "android", "EGL", "GLESv2"] diff --git a/tests/auto/blackbox/testdata-apple/aggregateDependencyLinking/aggregateDependencyLinking.qbs b/tests/auto/blackbox/testdata-apple/aggregateDependencyLinking/aggregateDependencyLinking.qbs index e7c8867bd..6f57c1e44 100644 --- a/tests/auto/blackbox/testdata-apple/aggregateDependencyLinking/aggregateDependencyLinking.qbs +++ b/tests/auto/blackbox/testdata-apple/aggregateDependencyLinking/aggregateDependencyLinking.qbs @@ -1,5 +1,3 @@ -import qbs - Project { minimumQbsVersion: "1.8" @@ -9,11 +7,27 @@ Project { Depends { name: "cpp" } Depends { name: "bundle" } + property bool hasX86Mac: true // cannot use xcode.version in qbs.architectures + property bool hasArmMac: false bundle.isBundle: false // This will generate 2 multiplex configs and an aggregate. - qbs.architectures: ["x86", "x86_64"] + qbs.architectures: { + if (qbs.targetPlatform === "macos") { + if (hasX86Mac) + return ["x86_64", "x86"]; + else if (hasArmMac) + return ["arm64", "x86_64"]; + } else if (qbs.targetPlatform === "ios") { + return ["arm64", "armv7a"]; + } + console.info("Cannot build fat binaries for this target platform (" + + qbs.targetPlatform + ")"); + return original; + } + qbs.buildVariant: "debug" + cpp.minimumMacosVersion: "10.8" } CppApplication { @@ -21,15 +35,22 @@ Project { files: ["app.c"] // This should link only against the aggregate static library, and not against - // the {debug, x86_64} variant, or worse - against both the single arch variant + // the {debug, arm64} variant, or worse - against both the single arch variant // and the lipo-ed one. Depends { name: "multi_arch_lib" } Depends { name: "bundle" } bundle.isBundle: false - qbs.architecture: "x86_64" + qbs.architecture: { + if (qbs.targetPlatform === "macos") + return "x86_64"; + else if (qbs.targetPlatform === "ios") + return "arm64"; + return original; + } qbs.buildVariant: "debug" + cpp.minimumMacosVersion: "10.8" multiplexByQbsProperties: [] } } diff --git a/tests/auto/blackbox/testdata-apple/apple-multiconfig/apple-multiconfig.qbs b/tests/auto/blackbox/testdata-apple/apple-multiconfig/apple-multiconfig.qbs index 438624f70..5615722d5 100644 --- a/tests/auto/blackbox/testdata-apple/apple-multiconfig/apple-multiconfig.qbs +++ b/tests/auto/blackbox/testdata-apple/apple-multiconfig/apple-multiconfig.qbs @@ -1,23 +1,32 @@ import qbs.Utilities +import "../multiarch-helpers.js" as Helpers + Project { minimumQbsVersion: "1.8" - property bool enableX86 + condition: xcodeVersion + property string xcodeVersion CppApplication { Depends { name: "singlelib" } Depends { name: "bundle" } + property bool isShallow: { + console.info("isShallow: " + bundle.isShallow); + return bundle.isShallow; + } name: "singleapp" targetName: "singleapp" files: ["app.c"] cpp.rpaths: [cpp.rpathOrigin + "/../../../"] cpp.minimumMacosVersion: "10.6" + cpp.minimumIosVersion: "8.0" // Turn off multiplexing aggregate: false multiplexByQbsProperties: [] install: true + installDebugInformation: false installDir: "" } @@ -29,13 +38,15 @@ Project { files: ["app.c"] cpp.rpaths: [cpp.rpathOrigin + "/../../../"] cpp.minimumMacosVersion: "10.6" + cpp.minimumIosVersion: "8.0" // Force aggregation when not needed aggregate: true - qbs.architectures: ["x86_64"] + qbs.architectures: [Helpers.getNewArch(qbs)] qbs.buildVariants: ["release"] install: true + installDebugInformation: false installDir: "" } @@ -45,7 +56,7 @@ Project { name: "singlelib" targetName: "singlelib" files: ["lib.c"] - cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined + cpp.sonamePrefix: qbs.targetOS.includes("darwin") ? "@rpath" : undefined cpp.defines: ["VARIANT=" + Utilities.cStringQuote(qbs.buildVariant)] // Turn off multiplexing @@ -53,6 +64,7 @@ Project { multiplexByQbsProperties: [] install: true + installDebugInformation: false installDir: "" } @@ -64,8 +76,10 @@ Project { files: ["app.c"] cpp.rpaths: [cpp.rpathOrigin + "/../../../"] cpp.minimumMacosVersion: "10.6" + cpp.minimumIosVersion: "8.0" install: true + installDebugInformation: false installDir: "" } @@ -77,13 +91,16 @@ Project { files: ["app.c"] cpp.rpaths: [cpp.rpathOrigin + "/../../../"] cpp.minimumMacosVersion: "10.6" - qbs.architectures: project.enableX86 ? ["x86", "x86_64"] : ["x86_64"] - qbs.architecture: "x86_64" - multiplexByQbsProperties: project.enableX86 ? ["architectures", "buildVariants"] - : ["buildVariants"] + cpp.minimumIosVersion: "8.0" + qbs.architectures: Helpers.getArchitectures(qbs, project.xcodeVersion) + qbs.architecture: Helpers.getNewArch(qbs) + multiplexByQbsProperties: Helpers.enableOldArch(qbs, project.xcodeVersion) + ? ["architectures", "buildVariants"] + : ["buildVariants"] qbs.buildVariants: "debug" install: true + installDebugInformation: false installDir: "" } @@ -95,10 +112,12 @@ Project { files: ["app.c"] cpp.rpaths: [cpp.rpathOrigin + "/../../../"] cpp.minimumMacosVersion: "10.6" - qbs.architectures: project.enableX86 ? ["x86", "x86_64"] : ["x86_64"] - qbs.buildVariants: ["debug", "profile"] + cpp.minimumIosVersion: "8.0" + qbs.architectures: Helpers.getArchitectures(qbs, project.xcodeVersion) + qbs.buildVariants: ["debug", "profiling"] install: true + installDebugInformation: false installDir: "" } @@ -108,12 +127,14 @@ Project { name: "multilib" targetName: "multilib" files: ["lib.c"] - cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined + cpp.minimumIosVersion: "8.0" + cpp.sonamePrefix: qbs.targetOS.includes("darwin") ? "@rpath" : undefined cpp.defines: ["VARIANT=" + Utilities.cStringQuote(qbs.buildVariant)] - qbs.architectures: project.enableX86 ? ["x86", "x86_64"] : ["x86_64"] - qbs.buildVariants: ["release", "debug", "profile"] + qbs.architectures: Helpers.getArchitectures(qbs, project.xcodeVersion) + qbs.buildVariants: ["release", "debug", "profiling"] install: true + installDebugInformation: false installDir: "" } @@ -123,12 +144,14 @@ Project { name: "multilib-no-release" targetName: "multilib-no-release" files: ["lib.c"] - cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined + cpp.minimumIosVersion: "8.0" + cpp.sonamePrefix: qbs.targetOS.includes("darwin") ? "@rpath" : undefined cpp.defines: ["VARIANT=" + Utilities.cStringQuote(qbs.buildVariant)] - qbs.architectures: project.enableX86 ? ["x86", "x86_64"] : ["x86_64"] - qbs.buildVariants: ["debug", "profile"] + qbs.architectures: Helpers.getArchitectures(qbs, project.xcodeVersion) + qbs.buildVariants: ["debug", "profiling"] install: true + installDebugInformation: false installDir: "" } @@ -138,11 +161,13 @@ Project { Depends { name: "multilibB" } name: "multilibA" files: ["lib.c"] + cpp.minimumIosVersion: "8.0" cpp.sonamePrefix: "@rpath" cpp.defines: ["VARIANT=" + Utilities.cStringQuote(qbs.buildVariant)] - qbs.architectures: project.enableX86 ? ["x86", "x86_64"] : ["x86_64"] - qbs.buildVariants: ["debug", "profile"] + qbs.architectures: Helpers.getArchitectures(qbs, project.xcodeVersion) + qbs.buildVariants: ["debug", "profiling"] install: true + installDebugInformation: false installDir: "" } DynamicLibrary { @@ -150,11 +175,13 @@ Project { Depends { name: "bundle" } name: "multilibB" files: ["lib.c"] + cpp.minimumIosVersion: "8.0" cpp.sonamePrefix: "@rpath" cpp.defines: ["VARIANT=" + Utilities.cStringQuote(qbs.buildVariant)] - qbs.architectures: project.enableX86 ? ["x86", "x86_64"] : ["x86_64"] - qbs.buildVariants: ["debug", "profile"] + qbs.architectures: Helpers.getArchitectures(qbs, project.xcodeVersion) + qbs.buildVariants: ["debug", "profiling"] install: true + installDebugInformation: false installDir: "" } } diff --git a/tests/auto/blackbox/testdata-apple/bundle-structure/bundle-structure.qbs b/tests/auto/blackbox/testdata-apple/bundle-structure/bundle-structure.qbs index 8cf031e33..33ac58967 100644 --- a/tests/auto/blackbox/testdata-apple/bundle-structure/bundle-structure.qbs +++ b/tests/auto/blackbox/testdata-apple/bundle-structure/bundle-structure.qbs @@ -3,12 +3,21 @@ Project { property stringList buildableProducts: ["A", "B", "C", "D", "E", "F", "G"] + Product { + Depends { name: "bundle" } + condition: { + console.info("bundle.isShallow: " + bundle.isShallow); + console.info("qbs.targetOS: " + qbs.targetOS); + return false; + } + } + Application { Depends { name: "cpp" } Depends { name: "B" } Depends { name: "C" } Depends { name: "D" } - condition: buildableProducts.contains("A") + condition: buildableProducts.includes("A") name: "A" bundle.isBundle: true bundle.publicHeaders: ["dummy.h"] @@ -24,7 +33,7 @@ Project { Depends { name: "B" } Depends { name: "C" } Depends { name: "D" } - condition: buildableProducts.contains("ABadApple") + condition: buildableProducts.includes("ABadApple") name: "ABadApple" bundle._productTypeIdentifier: "com.apple.product-type.will.never.exist.ever.guaranteed" bundle.isBundle: true @@ -41,7 +50,7 @@ Project { Depends { name: "B" } Depends { name: "C" } Depends { name: "D" } - condition: buildableProducts.contains("ABadThirdParty") + condition: buildableProducts.includes("ABadThirdParty") name: "ABadThirdParty" bundle._productTypeIdentifier: "org.special.third.party.non.existent.product.type" bundle.isBundle: true @@ -94,7 +103,7 @@ Project { ApplicationExtension { Depends { name: "cpp" } - condition: buildableProducts.contains("E") + condition: buildableProducts.includes("E") name: "E" bundle.isBundle: true bundle.publicHeaders: ["dummy.h"] @@ -107,7 +116,7 @@ Project { XPCService { Depends { name: "cpp" } - condition: buildableProducts.contains("F") + condition: buildableProducts.includes("F") name: "F" bundle.isBundle: true bundle.publicHeaders: ["dummy.h"] @@ -120,11 +129,14 @@ Project { Product { Depends { name: "bundle" } - condition: buildableProducts.contains("G") + condition: buildableProducts.includes("G") type: ["inapppurchase"] name: "G" bundle.isBundle: true bundle.resources: ["resource.txt"] + // XCode 12.5 does not support com.apple.product-type.in-app-purchase-content type anymore, + // so use older specs from Qbs + bundle._useXcodeBuildSpecs: false Group { fileTagsFilter: product.type.concat(project.bundleFileTags) qbs.install: true diff --git a/tests/auto/blackbox/testdata-apple/byteArrayInfoPlist/ByteArray-Info.plist b/tests/auto/blackbox/testdata-apple/byteArrayInfoPlist/ByteArray-Info.plist new file mode 100644 index 000000000..df0429f25 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/byteArrayInfoPlist/ByteArray-Info.plist @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>DataKey</key> + <!--The data value--> + <data>VGhlIGRhdGEgdmFsdWU=</data> + <key>StringKey</key> + <string>The string value</string> +</dict> +</plist> diff --git a/tests/auto/blackbox/testdata-apple/byteArrayInfoPlist/byteArrayInfoPlist.qbs b/tests/auto/blackbox/testdata-apple/byteArrayInfoPlist/byteArrayInfoPlist.qbs new file mode 100644 index 000000000..4df0886ff --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/byteArrayInfoPlist/byteArrayInfoPlist.qbs @@ -0,0 +1,37 @@ +import qbs.BundleTools +import qbs.TextFile + +CppApplication { + Depends { name: "bundle" } + cpp.minimumMacosVersion: "10.7" + files: ["main.c", "ByteArray-Info.plist"] + type: base.concat(["txt_output"]) + + Properties { + condition: qbs.targetOS.includes("darwin") + bundle.isBundle: true + bundle.identifierPrefix: "com.test" + } + + Rule { + inputs: ["aggregate_infoplist"] + Artifact { + filePath: input.fileName + ".out" + fileTags: ["txt_output"] + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "generating" + output.fileName + " from " + input.fileName; + cmd.highlight = "codegen"; + cmd.sourceCode = function() { + var plist = new BundleTools.infoPlistContents(input.filePath); + var content = plist["DataKey"]; + var int8view = new Uint8Array(content); + file = new TextFile(output.filePath, TextFile.WriteOnly); + file.write(String.fromCharCode.apply(null, int8view)); + file.close(); + } + return [cmd]; + } + } +} diff --git a/tests/auto/blackbox/testdata/innosetupDependencies/main.c b/tests/auto/blackbox/testdata-apple/byteArrayInfoPlist/main.c index 76e819701..76e819701 100644 --- a/tests/auto/blackbox/testdata/innosetupDependencies/main.c +++ b/tests/auto/blackbox/testdata-apple/byteArrayInfoPlist/main.c diff --git a/tests/auto/blackbox/testdata/path-probe/main.cpp b/tests/auto/blackbox/testdata-apple/codesign/app.cpp index 76e819701..76e819701 100644 --- a/tests/auto/blackbox/testdata/path-probe/main.cpp +++ b/tests/auto/blackbox/testdata-apple/codesign/app.cpp diff --git a/tests/auto/blackbox/testdata-apple/codesign/codesign.qbs b/tests/auto/blackbox/testdata-apple/codesign/codesign.qbs new file mode 100644 index 000000000..c1fc0502a --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/codesign/codesign.qbs @@ -0,0 +1,57 @@ +import "../multiarch-helpers.js" as Helpers + +Project { + name: "p" + // we do not have the access to xcode version in qbs.architectures so we need to pass it here + property string xcodeVersion + + property bool isBundle: true + property bool enableSigning: true + property bool multiArch: false + property bool multiVariant: false + + CppApplication { + name: "A" + version: "1.0.0" + bundle.isBundle: project.isBundle + files: "app.cpp" + codesign.enableCodeSigning: project.enableSigning + codesign.signingType: "ad-hoc" + install: true + installDir: "" + + qbs.architectures: + multiArch ? Helpers.getArchitectures(qbs, project.xcodeVersion) : [] + qbs.buildVariants: project.multiVariant ? ["debug", "release"] : [] + } + + DynamicLibrary { + Depends { name: "cpp" } + name: "B" + version: "1.0.0" + bundle.isBundle: project.isBundle + files: "app.cpp" + codesign.enableCodeSigning: project.enableSigning + codesign.signingType: "ad-hoc" + install: true + installDir: "" + qbs.architectures: + multiArch ? Helpers.getArchitectures(qbs, project.xcodeVersion) : [] + qbs.buildVariants: project.multiVariant ? ["debug", "release"] : [] + } + + LoadableModule { + Depends { name: "cpp" } + name: "C" + version: "1.0.0" + bundle.isBundle: project.isBundle + files: "app.cpp" + codesign.enableCodeSigning: project.enableSigning + codesign.signingType: "ad-hoc" + install: true + installDir: "" + qbs.architectures: + multiArch ? Helpers.getArchitectures(qbs, project.xcodeVersion) : [] + qbs.buildVariants: project.multiVariant ? ["debug", "release"] : [] + } +} diff --git a/tests/auto/blackbox/testdata-apple/deploymentTarget/deployment.qbs b/tests/auto/blackbox/testdata-apple/deploymentTarget/deployment.qbs index 9eff57b60..2179e9c84 100644 --- a/tests/auto/blackbox/testdata-apple/deploymentTarget/deployment.qbs +++ b/tests/auto/blackbox/testdata-apple/deploymentTarget/deployment.qbs @@ -5,7 +5,7 @@ CppApplication { // - will actually link (as of Xcode 8.1) // - exist for the given architecture(s) cpp.minimumMacosVersion: qbs.architecture === "x86_64h" ? "10.12" : "10.6" - cpp.minimumIosVersion: ["armv7s", "arm64", "x86_64"].contains(qbs.architecture) ? "7.0" : "6.0" + cpp.minimumIosVersion: ["armv7s", "arm64", "x86_64"].includes(qbs.architecture) ? "7.0" : "6.0" cpp.minimumTvosVersion: "9.0" cpp.minimumWatchosVersion: "2.0" diff --git a/tests/auto/blackbox/testdata-apple/frameworkStructure/frameworkStructure.qbs b/tests/auto/blackbox/testdata-apple/frameworkStructure/frameworkStructure.qbs index a812ae513..3c6d39332 100644 --- a/tests/auto/blackbox/testdata-apple/frameworkStructure/frameworkStructure.qbs +++ b/tests/auto/blackbox/testdata-apple/frameworkStructure/frameworkStructure.qbs @@ -2,6 +2,12 @@ Project { property bool includeHeaders: true Library { Depends { name: "cpp" } + Depends { name: "bundle" } + + property bool isShallow: { + console.info("isShallow: " + bundle.isShallow); + return bundle.isShallow; + } name: "Widget" bundle.isBundle: true diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/100.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/100.png Binary files differnew file mode 100644 index 000000000..98f8eaeb7 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/100.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/114.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/114.png Binary files differnew file mode 100644 index 000000000..a14be545e --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/114.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/120.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/120.png Binary files differnew file mode 100644 index 000000000..b910f96df --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/120.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/128.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/128.png Binary files differnew file mode 100644 index 000000000..7cf0327dc --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/128.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/144.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/144.png Binary files differnew file mode 100644 index 000000000..c7f18cda1 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/144.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/152.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/152.png Binary files differnew file mode 100644 index 000000000..af411d7e3 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/152.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/16.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/16.png Binary files differnew file mode 100644 index 000000000..be3743a22 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/16.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/167.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/167.png Binary files differnew file mode 100644 index 000000000..855952774 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/167.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/172.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/172.png Binary files differnew file mode 100644 index 000000000..a410f8bb2 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/172.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/180.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/180.png Binary files differnew file mode 100644 index 000000000..fcef493f4 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/180.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/196.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/196.png Binary files differnew file mode 100644 index 000000000..c974bf14a --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/196.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/20.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/20.png Binary files differnew file mode 100644 index 000000000..25897fc42 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/20.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/216.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/216.png Binary files differnew file mode 100644 index 000000000..ea0703112 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/216.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/256.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/256.png Binary files differnew file mode 100644 index 000000000..f1a3ef352 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/256.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/29.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/29.png Binary files differnew file mode 100644 index 000000000..1f9ef0678 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/29.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/32.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/32.png Binary files differnew file mode 100644 index 000000000..d969ed1df --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/32.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/40.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/40.png Binary files differnew file mode 100644 index 000000000..1f76c0b09 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/40.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/48.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/48.png Binary files differnew file mode 100644 index 000000000..5279cb807 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/48.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/50.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/50.png Binary files differnew file mode 100644 index 000000000..8045e514d --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/50.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/512.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/512.png Binary files differnew file mode 100644 index 000000000..c8f3cb758 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/512.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/55.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/55.png Binary files differnew file mode 100644 index 000000000..c3d8811f6 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/55.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/57.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/57.png Binary files differnew file mode 100644 index 000000000..5abf4b377 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/57.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/58.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/58.png Binary files differnew file mode 100644 index 000000000..fc8cf5df5 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/58.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/60.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/60.png Binary files differnew file mode 100644 index 000000000..ddc66846c --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/60.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/64.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/64.png Binary files differnew file mode 100644 index 000000000..ad87d2af1 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/64.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/72.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/72.png Binary files differnew file mode 100644 index 000000000..b78c47708 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/72.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/76.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/76.png Binary files differnew file mode 100644 index 000000000..50bab502d --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/76.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/80.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/80.png Binary files differnew file mode 100644 index 000000000..6a3a31fa6 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/80.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/87.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/87.png Binary files differnew file mode 100644 index 000000000..13fb01fef --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/87.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/88.png b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/88.png Binary files differnew file mode 100644 index 000000000..8eb955ca8 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/88.png diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/Contents.json b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..87ae131b9 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,299 @@ +{ + "images" : [ + { + "filename" : "40.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "60.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "filename" : "29.png", + "idiom" : "iphone", + "scale" : "1x", + "size" : "29x29" + }, + { + "filename" : "58.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "87.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "filename" : "80.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "120.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "57.png", + "idiom" : "iphone", + "scale" : "1x", + "size" : "57x57" + }, + { + "filename" : "114.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "57x57" + }, + { + "filename" : "120.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "180.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "filename" : "20.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "filename" : "40.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "29.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "filename" : "58.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "40.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "filename" : "80.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "50.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "50x50" + }, + { + "filename" : "100.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "50x50" + }, + { + "filename" : "72.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "72x72" + }, + { + "filename" : "144.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "72x72" + }, + { + "filename" : "76.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "filename" : "152.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "filename" : "167.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + }, + { + "filename" : "48.png", + "idiom" : "watch", + "role" : "notificationCenter", + "scale" : "2x", + "size" : "24x24", + "subtype" : "38mm" + }, + { + "filename" : "55.png", + "idiom" : "watch", + "role" : "notificationCenter", + "scale" : "2x", + "size" : "27.5x27.5", + "subtype" : "42mm" + }, + { + "filename" : "58.png", + "idiom" : "watch", + "role" : "companionSettings", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "87.png", + "idiom" : "watch", + "role" : "companionSettings", + "scale" : "3x", + "size" : "29x29" + }, + { + "filename" : "80.png", + "idiom" : "watch", + "role" : "appLauncher", + "scale" : "2x", + "size" : "40x40", + "subtype" : "38mm" + }, + { + "filename" : "88.png", + "idiom" : "watch", + "role" : "appLauncher", + "scale" : "2x", + "size" : "44x44", + "subtype" : "40mm" + }, + { + "filename" : "100.png", + "idiom" : "watch", + "role" : "appLauncher", + "scale" : "2x", + "size" : "50x50", + "subtype" : "44mm" + }, + { + "filename" : "172.png", + "idiom" : "watch", + "role" : "quickLook", + "scale" : "2x", + "size" : "86x86", + "subtype" : "38mm" + }, + { + "filename" : "196.png", + "idiom" : "watch", + "role" : "quickLook", + "scale" : "2x", + "size" : "98x98", + "subtype" : "42mm" + }, + { + "filename" : "216.png", + "idiom" : "watch", + "role" : "quickLook", + "scale" : "2x", + "size" : "108x108", + "subtype" : "44mm" + }, + { + "idiom" : "watch-marketing", + "scale" : "1x", + "size" : "1024x1024" + }, + { + "filename" : "16.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "filename" : "32.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "filename" : "32.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "filename" : "64.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "filename" : "128.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "filename" : "256.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "filename" : "256.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "filename" : "512.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "filename" : "512.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tests/auto/blackbox/testdata-apple/ib/appiconset/appiconset.qbs b/tests/auto/blackbox/testdata-apple/ib/appiconset/appiconset.qbs new file mode 100644 index 000000000..2015032ea --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/appiconset.qbs @@ -0,0 +1,10 @@ +CppApplication { + Depends { name: "ib" } + Depends { name: "bundle" } + property bool isShallow: { + console.info("bundle.isShallow: " + bundle.isShallow); + return bundle.isShallow; + } + files: ["main.c", "AppIconSet.xcassets"] + ib.appIconName: "AppIcon" +} diff --git a/tests/auto/blackbox/testdata/wixDependencies/main.c b/tests/auto/blackbox/testdata-apple/ib/appiconset/main.c index 76e819701..76e819701 100644 --- a/tests/auto/blackbox/testdata/wixDependencies/main.c +++ b/tests/auto/blackbox/testdata-apple/ib/appiconset/main.c diff --git a/tests/auto/blackbox/testdata-apple/ib/assetcatalog/assetcatalogempty.qbs b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/assetcatalogempty.qbs index 622fa46cb..d06e24eb3 100644 --- a/tests/auto/blackbox/testdata-apple/ib/assetcatalog/assetcatalogempty.qbs +++ b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/assetcatalogempty.qbs @@ -1,6 +1,13 @@ +import qbs.Host import qbs.Utilities Project { + condition: { + var result = qbs.targetOS.includes("macos"); + if (!result) + console.info("Skip this test"); + return result; + } property bool includeIconset CppApplication { @@ -11,7 +18,8 @@ Project { filez.push("empty.xcassets/empty.iconset"); else if (Utilities.versionCompare(xcode.version, "5") >= 0) filez.push("empty.xcassets"); - if (qbs.hostOSVersionMinor >= 10 // need macOS 10.10 to build SBs + if ((Host.osVersionMajor() >= 11 + || Host.osVersionMinor() >= 10) // need macOS 10.10 or higher to build SBs && cpp.minimumMacosVersion !== undefined && Utilities.versionCompare(cpp.minimumMacosVersion, "10.10") >= 0) filez.push("Storyboard.storyboard"); diff --git a/tests/auto/blackbox/testdata-apple/ib/iconsetapp/iconsetapp.qbs b/tests/auto/blackbox/testdata-apple/ib/iconsetapp/iconsetapp.qbs index 04e6ce0ce..dd39d1639 100644 --- a/tests/auto/blackbox/testdata-apple/ib/iconsetapp/iconsetapp.qbs +++ b/tests/auto/blackbox/testdata-apple/ib/iconsetapp/iconsetapp.qbs @@ -1,4 +1,9 @@ CppApplication { Depends { name: "ib" } + Depends { name: "bundle" } + property bool isShallow: { + console.info("isShallow: " + bundle.isShallow); + return bundle.isShallow; + } files: ["main.c", "white.iconset"] } diff --git a/tests/auto/blackbox/testdata-apple/infoPlistVariables/Info.plist b/tests/auto/blackbox/testdata-apple/infoPlistVariables/Info.plist new file mode 100644 index 000000000..cb879d70c --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/infoPlistVariables/Info.plist @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>Curly</key> + <string>${EXECUTABLE_NAME}</string> + <key>Braces</key> + <string>$(EXECUTABLE_NAME)</string> + <key>At</key> + <string>@EXECUTABLE_NAME@</string> + <key>CurlyMult</key> + <string>${EXECUTABLE_NAME}_${PRODUCT_NAME}</string> + <key>BracesMult</key> + <string>$(EXECUTABLE_NAME)_$(PRODUCT_NAME)</string> + <key>AtMult</key> + <string>@EXECUTABLE_NAME@_@PRODUCT_NAME@</string> + <key>CurlyNested</key> + <string>${${EXE}_NAME}</string> + <key>BracesNested</key> + <string>${${EXE}_NAME}</string> + <key>WithDefault</key> + <string>${NON_EXISTING:default=DEFAULT}</string> +</dict> +</plist> diff --git a/tests/auto/blackbox/testdata-apple/infoPlistVariables/infoPlistVariables.qbs b/tests/auto/blackbox/testdata-apple/infoPlistVariables/infoPlistVariables.qbs new file mode 100644 index 000000000..47ca80f07 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/infoPlistVariables/infoPlistVariables.qbs @@ -0,0 +1,16 @@ +CppApplication { + Depends { name: "bundle" } + cpp.minimumMacosVersion: "10.7" + files: ["main.c", "Info.plist"] + + Properties { + condition: qbs.targetOS.includes("darwin") + bundle.isBundle: true + bundle.identifierPrefix: "com.test" + bundle.extraEnv: { + var result = original; + result["EXE"] = "EXECUTABLE"; + return result; + } + } +} diff --git a/tests/auto/blackbox/testdata-apple/infoPlistVariables/main.c b/tests/auto/blackbox/testdata-apple/infoPlistVariables/main.c new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/infoPlistVariables/main.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/blackbox/testdata-apple/multiarch-helpers.js b/tests/auto/blackbox/testdata-apple/multiarch-helpers.js new file mode 100644 index 000000000..a8054b63c --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/multiarch-helpers.js @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +var Utilities = require("qbs.Utilities"); + +// Typically, multiple architectures are used for migration from "old" arch to a "new" one +// For example: x86 -> x86_64 on macOS, armv7 -> arm64 on iOS + +function enableOldArch(qbs, xcodeVersion) { + return qbs.targetOS.includes("macos") + && xcodeVersion + && (Utilities.versionCompare(xcodeVersion, "10") < 0 + || Utilities.versionCompare(xcodeVersion, "12.2") >= 0) + || qbs.targetOS.includes("ios") +} + +function getNewArch(qbs, xcodeVersion) { + if (qbs.targetOS.includes("macos")) + return xcodeVersion + && Utilities.versionCompare(xcodeVersion, "12.2") >= 0 ? "arm64" : "x86_64"; + else if (qbs.targetOS.includes("ios-simulator")) + return "x86_64" + else if (qbs.targetOS.includes("ios")) + return "arm64" + else if (qbs.targetOS.includes("tvos")) + return "arm64" + else if (qbs.targetOS.includes("watchos")) + return "armv7k" + throw "unsupported targetOS: " + qbs.targetOS; +} + +function getOldArch(qbs, xcodeVersion) { + if (qbs.targetOS.includes("macos")) + return xcodeVersion + && Utilities.versionCompare(xcodeVersion, "12.2") >= 0 ? "x86_64" : "x86"; + else if (qbs.targetOS.includes("ios-simulator")) + return "x86" + else if (qbs.targetOS.includes("ios")) + return "armv7a" + throw "unsupported targetOS: " + qbs.targetOS; +} + +function getArchitectures(qbs, xcodeVersion) { + return enableOldArch(qbs, xcodeVersion) + ? [getOldArch(qbs, xcodeVersion), getNewArch(qbs, xcodeVersion)] + : [getNewArch(qbs, xcodeVersion)]; +} diff --git a/tests/auto/blackbox/testdata-apple/objc-arc/objc-arc.qbs b/tests/auto/blackbox/testdata-apple/objc-arc/objc-arc.qbs index 545d5701c..ce128059f 100644 --- a/tests/auto/blackbox/testdata-apple/objc-arc/objc-arc.qbs +++ b/tests/auto/blackbox/testdata-apple/objc-arc/objc-arc.qbs @@ -2,7 +2,7 @@ Product { Depends { name: "cpp" } consoleApplication: true type: ["application"] - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") Group { cpp.automaticReferenceCounting: true diff --git a/tests/auto/blackbox/testdata-apple/overrideInfoPlist/Override-Info.plist b/tests/auto/blackbox/testdata-apple/overrideInfoPlist/Override-Info.plist new file mode 100644 index 000000000..f2621e983 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/overrideInfoPlist/Override-Info.plist @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>DefaultValue</key> + <string>The default value</string> + <key>OverriddenValue</key> + <string>The default value</string> +</dict> +</plist> diff --git a/tests/auto/blackbox/testdata-apple/overrideInfoPlist/main.c b/tests/auto/blackbox/testdata-apple/overrideInfoPlist/main.c new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/overrideInfoPlist/main.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/blackbox/testdata-apple/overrideInfoPlist/overrideInfoPlist.qbs b/tests/auto/blackbox/testdata-apple/overrideInfoPlist/overrideInfoPlist.qbs new file mode 100644 index 000000000..270a0792c --- /dev/null +++ b/tests/auto/blackbox/testdata-apple/overrideInfoPlist/overrideInfoPlist.qbs @@ -0,0 +1,16 @@ +CppApplication { + Depends { name: "bundle" } + cpp.minimumMacosVersion: "10.7" + files: ["main.c", "Override-Info.plist"] + + Properties { + condition: qbs.targetOS.includes("darwin") + bundle.isBundle: true + bundle.identifierPrefix: "com.test" + + bundle.infoPlist: ({ + "CFBundleName": "My Bundle", + "OverriddenValue": "The overridden value", + }) + } +} diff --git a/tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs b/tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs index fbab6d0b1..e7bf4739a 100644 --- a/tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs +++ b/tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs @@ -16,19 +16,19 @@ Project { console.info("Available SDK versions: " + xcode.availableSdkVersions.join(", ")); var targetOsToKey = function(targetOS) { - if (targetOS.contains("ios")) + if (targetOS.includes("ios")) return "iphoneos"; - if (targetOS.contains("ios-simulator")) + if (targetOS.includes("ios-simulator")) return "iphonesimulator"; - if (targetOS.contains("macos")) + if (targetOS.includes("macos")) return "macosx"; - if (targetOS.contains("tvos")) + if (targetOS.includes("tvos")) return "appletvos"; - if (targetOS.contains("tvos-simulator")) + if (targetOS.includes("tvos-simulator")) return "appletvsimulator"; - if (targetOS.contains("watchos")) + if (targetOS.includes("watchos")) return "watchos"; - if (targetOS.contains("watchos-simulator")) + if (targetOS.includes("watchos-simulator")) return "watchossimulator"; throw "Unsupported OS" + targetOS; } @@ -43,8 +43,11 @@ Project { } for (var i = 0; i < a.length; ++i) { - if (a[i] !== b[i]) { - throw msg; + var version1 = a[i].split('.'); + var version2 = b[i].split('.'); + for (var j = 0; j < version1.length; ++j) { + if (version1[j] !== version2[j]) + throw msg; } } } diff --git a/tests/auto/blackbox/testdata-baremetal/BareMetalApplication.qbs b/tests/auto/blackbox/testdata-baremetal/BareMetalApplication.qbs new file mode 100644 index 000000000..7a35e4e13 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/BareMetalApplication.qbs @@ -0,0 +1,29 @@ +import qbs.Host + +BareMetalProduct { + type: "application" + consoleApplication: true + + property bool dummy: { + if (qbs.targetPlatform !== Host.platform() + || qbs.architecture !== Host.architecture()) { + + function supportsCrossRun() { + // We can run 32 bit applications on 64 bit Windows. + if (Host.platform() === "windows" && Host.architecture() === "x86_64" + && qbs.targetPlatform === "windows" && qbs.architecture === "x86") { + return true; + } + } + + if (!supportsCrossRun()) + console.info("targetPlatform differs from hostPlatform") + } + } + + Group { + condition: qbs.toolchain.includes("cosmic") + files: "cosmic.lkf" + fileTags: "linkerscript" + } +} diff --git a/tests/auto/blackbox/testdata-baremetal/BareMetalProduct.qbs b/tests/auto/blackbox/testdata-baremetal/BareMetalProduct.qbs new file mode 100644 index 000000000..446cfe086 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/BareMetalProduct.qbs @@ -0,0 +1,158 @@ +Product { + Depends { name: "cpp" } + cpp.positionIndependentCode: false + Properties { + condition: qbs.toolchain.includes("iar") + && qbs.architecture === "stm8" + cpp.driverLinkerFlags: [ + "--config_def", "_CSTACK_SIZE=0x100", + "--config_def", "_HEAP_SIZE=0x100", + ] + } + Properties { + condition: qbs.toolchain.includes("iar") + && qbs.architecture === "rl78" + cpp.driverLinkerFlags: [ + "--config_def", "_NEAR_HEAP_SIZE=256", + "--config_def", "_FAR_HEAP_SIZE=4096", + "--config_def", "_HUGE_HEAP_SIZE=0", + "--config_def", "_STACK_SIZE=128", + "--config_def", "_NEAR_CONST_LOCATION_SIZE=0x6F00", + "--config_def", "_NEAR_CONST_LOCATION_START=0x3000", + "--define_symbol", "_NEAR_CONST_LOCATION=0", + "--config", cpp.toolchainInstallPath + "/../config/lnkrl78_s3.icf" + ] + } + Properties { + condition: qbs.toolchain.includes("iar") + && qbs.architecture === "rh850" + cpp.driverLinkerFlags: [ + "--config_def", "CSTACK_SIZE=0x1000", + "--config_def", "HEAP_SIZE=0x1000", + "--config", cpp.toolchainInstallPath + "/../config/lnkrh850_g3m.icf" + ] + } + Properties { + condition: qbs.toolchain.includes("iar") + && qbs.architecture === "v850" + cpp.driverLinkerFlags: [ + "-D_CSTACK_SIZE=1000", + "-D_HEAP_SIZE=1000", + "-f", cpp.toolchainInstallPath + "/../config/lnk85.xcl" + ] + } + Properties { + condition: qbs.toolchain.includes("iar") + && qbs.architecture === "78k" + cpp.commonCompilerFlags: [ + "--core", "78k0", + "--code_model", "standard" + ] + cpp.driverLinkerFlags: [ + "-D_CSTACK_SIZE=80", + "-D_HEAP_SIZE=200", + "-D_CODEBANK_START=0", + "-D_CODEBANK_END=0", + "-D_CODEBANK_BANKS=0", + "-f", cpp.toolchainInstallPath + "/../config/lnk.xcl", + cpp.toolchainInstallPath + "/../lib/clib/cl78ks1.r26" + ] + } + Properties { + condition: qbs.toolchain.includes("iar") + && qbs.architecture === "sh" + cpp.driverLinkerFlags: [ + "--config_def", "_CSTACK_SIZE=0x800", + "--config_def", "_HEAP_SIZE=0x800", + "--config_def", "_INT_TABLE=0x10", + "--config", cpp.toolchainInstallPath + "/../config/generic.icf" + ] + } + Properties { + condition: qbs.toolchain.includes("iar") + && qbs.architecture === "hcs8" + cpp.driverLinkerFlags: [ + "-D_CSTACK_SIZE=200", + "-D_HEAP_SIZE=200", + "-f", cpp.toolchainInstallPath + "/../config/lnkunspecifieds08.xcl" + ] + } + Properties { + condition: qbs.toolchain.includes("iar") + && qbs.architecture === "m32c" + cpp.driverLinkerFlags: [ + "-D_CSTACK_SIZE=100", + "-D_NEAR_HEAP_SIZE=400", + "-D_FAR_HEAP_SIZE=400", + "-D_HUGE_HEAP_SIZE=400", + "-D_ISTACK_SIZE=40", + "-f", cpp.toolchainInstallPath + "/../config/lnkm32c.xcl", + cpp.toolchainInstallPath + (qbs.debugInformation ? "/../lib/dlib/dlm32cnf.r48" : "/../lib/clib/clm32cf.r48") + ] + } + Properties { + condition: qbs.toolchain.includes("iar") + && qbs.architecture === "riscv" + cpp.driverLinkerFlags: [ + "--config_def", "CSTACK_SIZE=0x1000", + "--config_def", "HEAP_SIZE=0x1000" + ] + } + Properties { + condition: qbs.toolchain.includes("iar") + && qbs.architecture === "m68k" + cpp.cFlags: [ + "--no_div" + ] + cpp.driverLinkerFlags: [ + "-D__FLASHBEGIN=0", + "-D__FLASHEND=1FFFF", + "-D__RAMBEGIN=800000", + "-D__RAMEND=803FFF", + "-D_CSTACK_SIZE=200", + "-D_HEAP_SIZE=1000", + "-D_VBR_ADDRESS=0", + "-f", cpp.toolchainInstallPath + "/../config/lnkm51ac128.xcl", + cpp.toolchainInstallPath + "/../lib/dlcfcffdn.r68" + ] + } + Properties { + condition: qbs.toolchain.includes("keil") + && qbs.architecture.startsWith("arm") + && cpp.compilerName.startsWith("armcc") + cpp.assemblerFlags: ["--cpu", "cortex-m0"] + cpp.commonCompilerFlags: ["--cpu", "cortex-m0"] + } + Properties { + condition: qbs.toolchain.includes("keil") + && qbs.architecture.startsWith("arm") + && cpp.compilerName.startsWith("armclang") + cpp.assemblerFlags: ["--cpu", "cortex-m0"] + cpp.commonCompilerFlags: ["-mcpu=cortex-m0", "--target=arm-arm-none-eabi"] + } + Properties { + condition: qbs.toolchain.includes("gcc") + && qbs.architecture.startsWith("arm") + cpp.driverFlags: ["-specs=nosys.specs"] + } + Properties { + condition: qbs.toolchain.includes("gcc") + && qbs.architecture === "xtensa" + cpp.driverFlags: ["-nostdlib"] + } + Properties { + condition: qbs.toolchain.includes("gcc") + && qbs.architecture === "msp430" + cpp.driverFlags: ["-mmcu=msp430f5529", "-nostdlib"] + } + Properties { + condition: qbs.toolchain.includes("gcc") + && qbs.architecture === "m32r" + cpp.driverFlags: ["-nostdlib"] + } + Properties { + condition: qbs.toolchain.includes("gcc") + && qbs.architecture === "riscv" + cpp.driverFlags: ["-nostdlib"] + } +} diff --git a/tests/auto/blackbox/testdata-baremetal/BareMetalStaticLibrary.qbs b/tests/auto/blackbox/testdata-baremetal/BareMetalStaticLibrary.qbs new file mode 100644 index 000000000..7259b1446 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/BareMetalStaticLibrary.qbs @@ -0,0 +1,3 @@ +BareMetalProduct { + type: "staticlibrary" +} diff --git a/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/app.c b/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/app.c new file mode 100644 index 000000000..58fe69254 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/app.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/compiler-defines-by-language.qbs b/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/compiler-defines-by-language.qbs new file mode 100644 index 000000000..73365ada4 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/compiler-defines-by-language.qbs @@ -0,0 +1,73 @@ +import "../BareMetalApplication.qbs" as BareMetalApplication + +Project { + property bool supportsCpp: { + if (qbs.toolchain.includes("cosmic")) + return false; + if (qbs.toolchain.includes("sdcc")) + return false; + if (qbs.toolchain.includes("keil")) { + if (qbs.architecture === "mcs51" + || qbs.architecture === "mcs251" + || qbs.architecture === "c166") { + return false; + } + } + return true; + } + + BareMetalApplication { + name: "c_language" + files: ["app.c", "ctest.c"] + cpp.enableCompilerDefinesByLanguage: [] + property var foo: { + if (!cpp.compilerDefinesByLanguage) + throw "ASSERT cpp.compilerDefinesByLanguage: " + + cpp.compilerDefinesByLanguage; + if (!cpp.compilerDefinesByLanguage["c"]) + throw "ASSERT cpp.compilerDefinesByLanguage[\"c\"]: " + + cpp.compilerDefinesByLanguage["c"]; + if (cpp.compilerDefinesByLanguage["cpp"]) + throw "ASSERT !cpp.compilerDefinesByLanguage[\"cpp\"]: " + + cpp.compilerDefinesByLanguage["cpp"]; + } + } + + BareMetalApplication { + condition: supportsCpp + name: "cpp_language" + files: ["app.c", "cpptest.cpp"] + cpp.enableCompilerDefinesByLanguage: ["cpp"] + cpp.enableExceptions: false + property var foo: { + if (!cpp.compilerDefinesByLanguage) + throw "ASSERT cpp.compilerDefinesByLanguage: " + + cpp.compilerDefinesByLanguage; + if (cpp.compilerDefinesByLanguage["c"]) + throw "ASSERT !cpp.compilerDefinesByLanguage[\"c\"]: " + + cpp.compilerDefinesByLanguage["c"]; + if (!cpp.compilerDefinesByLanguage["cpp"]) + throw "ASSERT cpp.compilerDefinesByLanguage[\"cpp\"]: " + + cpp.compilerDefinesByLanguage["cpp"]; + } + } + + BareMetalApplication { + condition: supportsCpp + name: "c_and_cpp_language" + files: ["app.c", "ctest.c", "cpptest.cpp"] + cpp.enableCompilerDefinesByLanguage: ["c", "cpp"] + cpp.enableExceptions: false + property var foo: { + if (!cpp.compilerDefinesByLanguage) + throw "ASSERT cpp.compilerDefinesByLanguage: " + + cpp.compilerDefinesByLanguage; + if (!cpp.compilerDefinesByLanguage["c"]) + throw "ASSERT cpp.compilerDefinesByLanguage[\"c\"]: " + + cpp.compilerDefinesByLanguage["c"]; + if (!cpp.compilerDefinesByLanguage["cpp"]) + throw "ASSERT cpp.compilerDefinesByLanguage[\"cpp\"]: " + + cpp.compilerDefinesByLanguage["cpp"]; + } + } +} diff --git a/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/cpptest.cpp b/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/cpptest.cpp new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/cpptest.cpp diff --git a/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/ctest.c b/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/ctest.c new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/ctest.c diff --git a/tests/auto/blackbox/testdata-baremetal/compiler-include-paths/compiler-include-paths.qbs b/tests/auto/blackbox/testdata-baremetal/compiler-include-paths/compiler-include-paths.qbs new file mode 100644 index 000000000..5c73302ad --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/compiler-include-paths/compiler-include-paths.qbs @@ -0,0 +1,9 @@ +import "../BareMetalApplication.qbs" as BareMetalApplication + +BareMetalApplication { + files: ["main.c"] + property bool dummy: { + console.info("compilerIncludePaths: %%" + cpp.compilerIncludePaths + "%%"); + return true; + } +} diff --git a/tests/auto/blackbox/testdata-baremetal/compiler-include-paths/main.c b/tests/auto/blackbox/testdata-baremetal/compiler-include-paths/main.c new file mode 100644 index 000000000..58fe69254 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/compiler-include-paths/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/tests/auto/blackbox/testdata-baremetal/compiler-listing/compiler-listing.qbs b/tests/auto/blackbox/testdata-baremetal/compiler-listing/compiler-listing.qbs new file mode 100644 index 000000000..6bd51e3bd --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/compiler-listing/compiler-listing.qbs @@ -0,0 +1,14 @@ +import "../BareMetalApplication.qbs" as BareMetalApplication + +BareMetalApplication { + condition: { + if (!qbs.toolchain.includes("gcc")) { + console.info("compiler listing suffix: %%" + cpp.compilerListingSuffix + "%%"); + return true; + } + console.info("unsupported toolset: %%" + + qbs.toolchainType + "%%, %%" + qbs.architecture + "%%"); + return false; + } + files: ["main.c", "fun.c"] +} diff --git a/tests/auto/blackbox/testdata-baremetal/compiler-listing/fun.c b/tests/auto/blackbox/testdata-baremetal/compiler-listing/fun.c new file mode 100644 index 000000000..3b8c8f2f4 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/compiler-listing/fun.c @@ -0,0 +1,4 @@ +int f(void) +{ + return 0; +} diff --git a/tests/auto/blackbox/testdata-baremetal/compiler-listing/main.c b/tests/auto/blackbox/testdata-baremetal/compiler-listing/main.c new file mode 100644 index 000000000..2c3d7726c --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/compiler-listing/main.c @@ -0,0 +1,6 @@ +extern int f(void); + +int main(void) +{ + return f(); +} diff --git a/tests/auto/blackbox/testdata-baremetal/cosmic.lkf b/tests/auto/blackbox/testdata-baremetal/cosmic.lkf new file mode 100644 index 000000000..90c254d1e --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/cosmic.lkf @@ -0,0 +1 @@ +@* diff --git a/tests/auto/blackbox/testdata-baremetal/defines/defines.qbs b/tests/auto/blackbox/testdata-baremetal/defines/defines.qbs new file mode 100644 index 000000000..b257a8a4b --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/defines/defines.qbs @@ -0,0 +1,6 @@ +import "../BareMetalApplication.qbs" as BareMetalApplication + +BareMetalApplication { + cpp.defines: ["FOO", "BAR"] + files: ["main.c"] +} diff --git a/tests/auto/blackbox/testdata-baremetal/defines/main.c b/tests/auto/blackbox/testdata-baremetal/defines/main.c new file mode 100644 index 000000000..d2d4769e4 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/defines/main.c @@ -0,0 +1,11 @@ +#ifndef FOO +#error FOO missing! +#endif +#ifndef BAR +#error BAR missing! +#endif + +int main(void) +{ + return 0; +} diff --git a/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/bar/bar.h b/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/bar/bar.h new file mode 100644 index 000000000..49ffa0b12 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/bar/bar.h @@ -0,0 +1,6 @@ +#ifndef BAR_H +#define BAR_H + +#define BAR_VALUE 1 + +#endif // BAR_H diff --git a/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/distribution-include-paths.qbs b/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/distribution-include-paths.qbs new file mode 100644 index 000000000..0fded6a46 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/distribution-include-paths.qbs @@ -0,0 +1,6 @@ +import "../BareMetalApplication.qbs" as BareMetalApplication + +BareMetalApplication { + files: ["main.c"] + cpp.distributionIncludePaths: ["foo", "bar"] +} diff --git a/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/foo/foo.h b/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/foo/foo.h new file mode 100644 index 000000000..dc510379d --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/foo/foo.h @@ -0,0 +1,6 @@ +#ifndef FOO_H +#define FOO_H + +#define FOO_VALUE 1 + +#endif // FOO_H diff --git a/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/main.c b/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/main.c new file mode 100644 index 000000000..aabc97a0c --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/main.c @@ -0,0 +1,7 @@ +#include <foo.h> +#include <bar.h> + +int main(void) +{ + return FOO_VALUE - BAR_VALUE; +} diff --git a/tests/auto/blackbox/testdata-baremetal/external-static-libraries/external-static-libraries.qbs b/tests/auto/blackbox/testdata-baremetal/external-static-libraries/external-static-libraries.qbs new file mode 100644 index 000000000..7336e3970 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/external-static-libraries/external-static-libraries.qbs @@ -0,0 +1,34 @@ +import "../BareMetalApplication.qbs" as BareMetalApplication +import "../BareMetalStaticLibrary.qbs" as BareMetalStaticLibrary + +Project { + property string outputLibrariesDirectory: buildDirectory + "/libs" + BareMetalStaticLibrary { + name: "lib-a" + destinationDirectory: project.outputLibrariesDirectory + Depends { name: "cpp" } + Properties { + condition: qbs.targetOS.includes("darwin") + bundle.isBundle: false + } + files: ["lib-a.c"] + } + BareMetalStaticLibrary { + name: "lib-b" + destinationDirectory: project.outputLibrariesDirectory + Depends { name: "cpp" } + Depends { name: "lib-a" } + Properties { + condition: qbs.targetOS.includes("darwin") + bundle.isBundle: false + } + files: ["lib-b.c"] + } + BareMetalApplication { + Depends { name: "lib-a"; cpp.link: false } + Depends { name: "lib-b"; cpp.link: false } + files: ["main.c"] + cpp.libraryPaths: [project.outputLibrariesDirectory] + cpp.staticLibraries: ["lib-b", "lib-a"] + } +} diff --git a/tests/auto/blackbox/testdata-baremetal/external-static-libraries/lib-a.c b/tests/auto/blackbox/testdata-baremetal/external-static-libraries/lib-a.c new file mode 100644 index 000000000..13401861f --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/external-static-libraries/lib-a.c @@ -0,0 +1,4 @@ +int a(void) +{ + return 0; +} diff --git a/tests/auto/blackbox/testdata-baremetal/external-static-libraries/lib-b.c b/tests/auto/blackbox/testdata-baremetal/external-static-libraries/lib-b.c new file mode 100644 index 000000000..5d45b8175 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/external-static-libraries/lib-b.c @@ -0,0 +1,6 @@ +extern int a(void); + +int b(void) +{ + return a(); +} diff --git a/tests/auto/blackbox/testdata-baremetal/external-static-libraries/main.c b/tests/auto/blackbox/testdata-baremetal/external-static-libraries/main.c new file mode 100644 index 000000000..84ef5e51e --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/external-static-libraries/main.c @@ -0,0 +1,6 @@ +extern int b(); + +int main(void) +{ + return b(); +} diff --git a/tests/auto/blackbox/testdata-baremetal/linker-map/linker-map.qbs b/tests/auto/blackbox/testdata-baremetal/linker-map/linker-map.qbs new file mode 100644 index 000000000..fe93ac144 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/linker-map/linker-map.qbs @@ -0,0 +1,8 @@ +import "../BareMetalApplication.qbs" as BareMetalApplication + +BareMetalApplication { + property bool dummy: { + console.info("linker map suffix: %%" + cpp.linkerMapSuffix + "%%"); + } + files: ["main.c"] +} diff --git a/tests/auto/blackbox/testdata-baremetal/linker-map/main.c b/tests/auto/blackbox/testdata-baremetal/linker-map/main.c new file mode 100644 index 000000000..58fe69254 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/linker-map/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-application/main.c b/tests/auto/blackbox/testdata-baremetal/one-object-application/main.c new file mode 100644 index 000000000..58fe69254 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-application/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-application/one-object-application.qbs b/tests/auto/blackbox/testdata-baremetal/one-object-application/one-object-application.qbs new file mode 100644 index 000000000..482425b5f --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-application/one-object-application.qbs @@ -0,0 +1,5 @@ +import "../BareMetalApplication.qbs" as BareMetalApplication + +BareMetalApplication { + files: ["main.c"] +} diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/78k-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/78k-iar.s new file mode 100644 index 000000000..25f0e2bbd --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/78k-iar.s @@ -0,0 +1,6 @@ + PUBLIC main + RSEG CODE:CODE:NOROOT(0) +main: + MOVW AX, #0 + RET + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/arm-cosmic.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/arm-cosmic.s new file mode 100644 index 000000000..4b45cc989 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/arm-cosmic.s @@ -0,0 +1,5 @@ +_main: + movs r0, #0 + bx lr + xdef _main + end diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/arm-gcc.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/arm-gcc.s new file mode 100644 index 000000000..c7b894230 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/arm-gcc.s @@ -0,0 +1,5 @@ + .global main + .type main, %function +main: + mov r0, #0 + bx lr diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/arm-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/arm-iar.s new file mode 100644 index 000000000..0a13a5dc2 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/arm-iar.s @@ -0,0 +1,7 @@ + PUBLIC main + SECTION `.text`:CODE:NOROOT(1) + THUMB +main: + MOVS R0, #+0 + BX LR + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/arm-keil.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/arm-keil.s new file mode 100644 index 000000000..f3fcd50fe --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/arm-keil.s @@ -0,0 +1,7 @@ + THUMB + AREA ||.text||, CODE, READONLY, ALIGN = 1 +main PROC + MOVS r0, #0 + BX lr + ENDP + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/avr-gcc.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/avr-gcc.s new file mode 100644 index 000000000..4ba005a47 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/avr-gcc.s @@ -0,0 +1,6 @@ + .global main + .type main, %function +main: + ldi r24, 0 + ldi r25, 0 + ret diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/avr-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/avr-iar.s new file mode 100644 index 000000000..49e9d476e --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/avr-iar.s @@ -0,0 +1,7 @@ + PUBLIC main + RSEG CODE:CODE:NOROOT(1) +main: + LDI R16, 0 + LDI R17, 0 + RET + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/avr32-gcc.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/avr32-gcc.s new file mode 100644 index 000000000..879e54150 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/avr32-gcc.s @@ -0,0 +1,8 @@ + .global main + .type main, @function +main: + stm --sp, r7, lr + mov r7, sp + mov r8, 0 + mov r12, r8 + ldm sp++, r7, pc diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/avr32-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/avr32-iar.s new file mode 100644 index 000000000..c5e78896f --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/avr32-iar.s @@ -0,0 +1,7 @@ + PUBLIC main + RSEG CODE32:CODE:REORDER:NOROOT(2) + CODE +main: + MOV R12, 0x0 + RET R12 + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/c166-keil.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/c166-keil.s new file mode 100644 index 000000000..394bc2ae4 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/c166-keil.s @@ -0,0 +1,7 @@ +MAIN_SEG SECTION CODE WORD 'NCODE' +main PROC NEAR + MOV R4, #0 + RET +main ENDP +MAIN_SEG ENDS + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/cr16-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/cr16-iar.s new file mode 100644 index 000000000..4a14de6a1 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/cr16-iar.s @@ -0,0 +1,6 @@ + PUBLIC main + RSEG CODE:CODE:NOROOT(0) +main: + MOVW $0, R0 + JUMP (RA) + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs12-cosmic.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs12-cosmic.s new file mode 100644 index 000000000..c33c2b32d --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs12-cosmic.s @@ -0,0 +1,5 @@ +_main: + .dcall "2,0,_main" + rts + xdef _main + end diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs12-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs12-iar.s new file mode 100644 index 000000000..4344e757f --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs12-iar.s @@ -0,0 +1,7 @@ + PUBLIC main + RSEG CODE:CODE:REORDER:NOROOT(0) +main: + CLRB + CLRA + RTS + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs8-cosmic.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs8-cosmic.s new file mode 100644 index 000000000..c33c2b32d --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs8-cosmic.s @@ -0,0 +1,5 @@ +_main: + .dcall "2,0,_main" + rts + xdef _main + end diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs8-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs8-iar.s new file mode 100644 index 000000000..883dfdcad --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs8-iar.s @@ -0,0 +1,6 @@ + PUBLIC main + RSEG CODE:CODE:REORDER:NOROOT(0) +main: + LDHX #0x0000 + RTS + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs8-sdcc.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs8-sdcc.s new file mode 100644 index 000000000..f47fed1be --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs8-sdcc.s @@ -0,0 +1,6 @@ + .globl main + .area DSEG (PAG) + .area HOME (CODE) +main: + clra + tax diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m16c-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m16c-iar.s new file mode 100644 index 000000000..4153f290e --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m16c-iar.s @@ -0,0 +1,6 @@ + PUBLIC main + RSEG CODE:CODE:REORDER:NOROOT(0) +main: + MOV.W #0x0, R0 + RTS + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m32c-gcc.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m32c-gcc.s new file mode 100644 index 000000000..173c04c39 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m32c-gcc.s @@ -0,0 +1,5 @@ + .global _main + .type _main, @function +_main: + mov.w #0, r0 + rts diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m32c-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m32c-iar.s new file mode 100644 index 000000000..4153f290e --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m32c-iar.s @@ -0,0 +1,6 @@ + PUBLIC main + RSEG CODE:CODE:REORDER:NOROOT(0) +main: + MOV.W #0x0, R0 + RTS + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m32r-gcc.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m32r-gcc.s new file mode 100644 index 000000000..dfcf42ca1 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m32r-gcc.s @@ -0,0 +1,9 @@ + .global main + .type main, @function +main: + push fp + mv fp, sp + ldi r4, #0 + mv r0, r4 + pop fp + jmp lr diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m68k-cosmic.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m68k-cosmic.s new file mode 100644 index 000000000..811b1d79e --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m68k-cosmic.s @@ -0,0 +1,5 @@ +_main: + .dcall "8,0,_main" + rts + xdef _main + end diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m68k-gcc.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m68k-gcc.s new file mode 100644 index 000000000..fdde81dae --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m68k-gcc.s @@ -0,0 +1,7 @@ + .global main + .type main, @function +main: + link.w %fp, #0 + clr.l %d0 + unlk %fp + rts diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m68k-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m68k-iar.s new file mode 100644 index 000000000..9811be134 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m68k-iar.s @@ -0,0 +1,6 @@ + PUBLIC main + RSEG FCODE:CODE:NOROOT(1) +main: + CLR.L D0 + RTS + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/mcs251-keil.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/mcs251-keil.s new file mode 100644 index 000000000..312cc9680 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/mcs251-keil.s @@ -0,0 +1,8 @@ +PUBLIC main +MAIN_SEG SEGMENT CODE + RSEG MAIN_SEG +main PROC + XRL WR6,WR6 + RET + ENDP + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/mcs51-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/mcs51-iar.s new file mode 100644 index 000000000..09cc64613 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/mcs51-iar.s @@ -0,0 +1,7 @@ + PUBLIC main + RSEG NEAR_CODE:CODE:NOROOT(0) +main: + MOV R2, #0x0 + MOV R3, #0x0 + RET + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/mcs51-keil.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/mcs51-keil.s new file mode 100644 index 000000000..28174d0e2 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/mcs51-keil.s @@ -0,0 +1,8 @@ +PUBLIC main +MAIN_SEG SEGMENT CODE + RSEG MAIN_SEG +main: + MOV R6, #0x0 + MOV R7, #0x0 + RET + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/mcs51-sdcc.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/mcs51-sdcc.s new file mode 100644 index 000000000..eaa6467e3 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/mcs51-sdcc.s @@ -0,0 +1,7 @@ + .globl main + .area PSEG (PAG,XDATA) + .area XSEG (XDATA) + .area HOME (CODE) +main: + mov dptr, #0x0000 + ret diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/msp430-gcc.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/msp430-gcc.s new file mode 100644 index 000000000..8e8a24980 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/msp430-gcc.s @@ -0,0 +1,5 @@ + .global main + .type main, %function +main: + mov #0, r15 + .LIRD0: diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/msp430-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/msp430-iar.s new file mode 100644 index 000000000..fbabe3ba8 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/msp430-iar.s @@ -0,0 +1,6 @@ + PUBLIC main + RSEG `CODE`:CODE:REORDER:NOROOT(1) +main: + MOV.W #0x0, R12 + RET + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/one-object-asm-application.qbs b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/one-object-asm-application.qbs new file mode 100644 index 000000000..e8805225c --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/one-object-asm-application.qbs @@ -0,0 +1,122 @@ +import "../BareMetalApplication.qbs" as BareMetalApplication + +BareMetalApplication { + condition: { + if (qbs.toolchainType === "cosmic") { + if (qbs.architecture.startsWith("arm")) + return true; + if (qbs.architecture === "stm8") + return true; + if (qbs.architecture === "hcs8") + return true; + if (qbs.architecture === "hcs12") + return true; + if (qbs.architecture === "m68k") + return true; + } else if (qbs.toolchainType === "keil") { + if (qbs.architecture.startsWith("arm")) + return true; + if (qbs.architecture === "mcs51") + return true; + if (qbs.architecture === "mcs251") + return true; + if (qbs.architecture === "c166") + return true; + } else if (qbs.toolchainType === "iar") { + if (qbs.architecture.startsWith("arm")) + return true; + if (qbs.architecture === "mcs51") + return true; + if (qbs.architecture === "stm8") + return true; + if (qbs.architecture === "avr") + return true; + if (qbs.architecture === "avr32") + return true; + if (qbs.architecture === "msp430") + return true; + if (qbs.architecture === "rl78") + return true; + if (qbs.architecture === "rh850") + return true; + if (qbs.architecture === "v850") + return true; + if (qbs.architecture === "78k") + return true; + if (qbs.architecture === "r32c") + return true; + if (qbs.architecture === "sh") + return true; + if (qbs.architecture === "cr16") + return true; + if (qbs.architecture === "m16c") + return true; + if (qbs.architecture === "hcs8") + return true; + if (qbs.architecture === "hcs12") + return true; + if (qbs.architecture === "rx") + return true; + if (qbs.architecture === "m32c") + return true; + if (qbs.architecture === "riscv") + return true; + if (qbs.architecture === "m68k") + return true; + } else if (qbs.toolchainType === "sdcc") { + if (qbs.architecture === "mcs51") + return true; + if (qbs.architecture === "stm8") + return true; + if (qbs.architecture === "hcs8") + return true; + } else if (qbs.toolchainType === "gcc") { + if (qbs.architecture.startsWith("arm")) + return true; + if (qbs.architecture === "avr") + return true; + if (qbs.architecture === "avr32") + return true; + if (qbs.architecture === "msp430") + return true; + if (qbs.architecture === "xtensa") + return true; + if (qbs.architecture === "rl78") + return true; + if (qbs.architecture === "m32c") + return true; + if (qbs.architecture === "m32r") + return true; + if (qbs.architecture === "m68k") + return true; + if (qbs.architecture === "v850") + return true; + if (qbs.architecture === "riscv") + return true; + if (qbs.architecture === "rx") + return true; + } + console.info("unsupported toolset: %%" + + qbs.toolchainType + "%%, %%" + qbs.architecture + "%%"); + return false; + } + + Properties { + condition: qbs.toolchainType === "gcc" + && qbs.architecture === "msp430" + // We need to use this workaround to enable + // the cpp.driverFlags property. + cpp.linkerPath: cpp.compilerPathByLanguage["c"] + } + + Properties { + condition: qbs.toolchainType === "iar" + && qbs.architecture.startsWith("arm") + cpp.entryPoint: "main" + } + + cpp.linkerPath: original + + files: [(qbs.architecture.startsWith("arm") ? "arm" : qbs.architecture) + + "-" + qbs.toolchainType + ".s"] +} diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/r32c-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/r32c-iar.s new file mode 100644 index 000000000..844306811 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/r32c-iar.s @@ -0,0 +1,7 @@ + PUBLIC main + RSEG CODE24:CODE:REORDER:NOROOT(0) +main: + MOV.L:Z #0x0, R2R0 + RTS + RSEG SBREF:DATA:NOROOT(0) + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rh850-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rh850-iar.s new file mode 100644 index 000000000..8901027aa --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rh850-iar.s @@ -0,0 +1,7 @@ + PUBLIC _main + SECTION `.text`:CODE:NOROOT(2) + CODE +_main: + MOV r0, r10 + JMP [lp] + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/riscv-gcc.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/riscv-gcc.s new file mode 100644 index 000000000..d09097804 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/riscv-gcc.s @@ -0,0 +1,11 @@ + .globl main + .type main, @function +main: + add sp, sp, -16 + sd s0, 8(sp) + add s0, sp, 16 + li a5, 0 + mv a0, a5 + ld s0, 8(sp) + add sp, sp, 16 + jr ra diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/riscv-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/riscv-iar.s new file mode 100644 index 000000000..e19fdfddb --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/riscv-iar.s @@ -0,0 +1,7 @@ + PUBLIC main + SECTION `.text`:CODE:REORDER:NOROOT(2) + CODE +main: + MV A0, ZERO + RET + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rl78-gcc.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rl78-gcc.s new file mode 100644 index 000000000..59510bd01 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rl78-gcc.s @@ -0,0 +1,11 @@ +r8 = 0xffef0 +.text + .global _main + .type _main, @function +_main: + subw sp, #2 + clrw ax + movw [sp], ax + movw r8, ax + addw sp, #2 + ret diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rl78-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rl78-iar.s new file mode 100644 index 000000000..1f00996cc --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rl78-iar.s @@ -0,0 +1,7 @@ + PUBLIC _main + SECTION `.text`:CODE:NOROOT(0) + CODE +_main: + CLRW AX + RET + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rx-gcc.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rx-gcc.s new file mode 100644 index 000000000..501d4cd7e --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rx-gcc.s @@ -0,0 +1,8 @@ + .global _main + .type _main, @function +_main: + push.l r10 + mov.L r0, r10 + mov.L #0, r5 + mov.L r5, r1 + rtsd #4, r10-r10 diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rx-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rx-iar.s new file mode 100644 index 000000000..cc1573431 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rx-iar.s @@ -0,0 +1,5 @@ + PUBLIC _main + SECTION CODE:CODE:ROOT(2) +_main: + BRA _main + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/sh-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/sh-iar.s new file mode 100644 index 000000000..d86780310 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/sh-iar.s @@ -0,0 +1,7 @@ + PUBLIC _main + SECTION `.code32.text`:CODE:NOROOT(2) +_main: + CODE + MOV #0, R0 + RTS/N + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/stm8-cosmic.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/stm8-cosmic.s new file mode 100644 index 000000000..818b0d680 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/stm8-cosmic.s @@ -0,0 +1,7 @@ + scross off +_main: + .dcall "2,0,_main" + ret + .scheck _main + xdef _main + end diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/stm8-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/stm8-iar.s new file mode 100644 index 000000000..674e20de6 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/stm8-iar.s @@ -0,0 +1,7 @@ + PUBLIC main + SECTION `.near_func.text`:CODE:REORDER:NOROOT(0) + CODE +main: + CLRW X + RET + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/stm8-sdcc.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/stm8-sdcc.s new file mode 100644 index 000000000..1a552f4a4 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/stm8-sdcc.s @@ -0,0 +1,7 @@ + .globl main + .area DATA + .area SSEG + .area HOME +main: + clrw x + ret diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/v850-gcc.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/v850-gcc.s new file mode 100644 index 000000000..3599a1fb1 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/v850-gcc.s @@ -0,0 +1,11 @@ + .global _main + .type _main, @function +_main: + add -4, sp + st.w r29, 0[sp] + mov sp, r29 + mov 0, r10 + mov r29, sp + ld.w 0[sp], r29 + add 4, sp + jmp [r31] diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/v850-iar.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/v850-iar.s new file mode 100644 index 000000000..4ccfacd64 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/v850-iar.s @@ -0,0 +1,7 @@ + PUBLIC _main + RSEG `CODE`:CODE:NOROOT(2) + CODE +_main: + MOV zero, r1 + JMP [lp] + END diff --git a/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/xtensa-gcc.s b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/xtensa-gcc.s new file mode 100644 index 000000000..c21000905 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/xtensa-gcc.s @@ -0,0 +1,11 @@ + .global main + .type main, @function +main: + addi sp, sp, -16 + s32i.n a15, sp, 12 + mov.n a15, sp + movi.n a2, 0 + mov.n sp, a15 + l32i.n a15, sp, 12 + addi sp, sp, 16 + ret.n diff --git a/tests/auto/blackbox/testdata-baremetal/preinclude-headers/main.c b/tests/auto/blackbox/testdata-baremetal/preinclude-headers/main.c new file mode 100644 index 000000000..755192287 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/preinclude-headers/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return PREINCLUDE_VALUE; +} diff --git a/tests/auto/blackbox/testdata-baremetal/preinclude-headers/preinclude-headers.qbs b/tests/auto/blackbox/testdata-baremetal/preinclude-headers/preinclude-headers.qbs new file mode 100644 index 000000000..0ded6ff15 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/preinclude-headers/preinclude-headers.qbs @@ -0,0 +1,18 @@ +import "../BareMetalApplication.qbs" as BareMetalApplication + +BareMetalApplication { + condition: { + if (qbs.toolchainType === "keil") { + if (qbs.architecture === "mcs51" + || qbs.architecture === "mcs251" + || qbs.architecture === "c166") { + console.info("unsupported toolset: %%" + + qbs.toolchainType + "%%, %%" + qbs.architecture + "%%"); + return false; + } + } + return true; + } + cpp.prefixHeaders: ["preinclude.h"] + files: ["main.c"] +} diff --git a/tests/auto/blackbox/testdata-baremetal/preinclude-headers/preinclude.h b/tests/auto/blackbox/testdata-baremetal/preinclude-headers/preinclude.h new file mode 100644 index 000000000..6b68e4826 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/preinclude-headers/preinclude.h @@ -0,0 +1,6 @@ +#ifndef PREINCLUDE_H +#define PREINCLUDE_H + +#define PREINCLUDE_VALUE 0 + +#endif // PREINCLUDE_H diff --git a/tests/auto/blackbox/testdata-baremetal/shared-libraries/app.c b/tests/auto/blackbox/testdata-baremetal/shared-libraries/app.c new file mode 100644 index 000000000..f2ecb5f55 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/shared-libraries/app.c @@ -0,0 +1,12 @@ +#include "../dllexport.h" + +#include <stdio.h> + +DLL_IMPORT void foo(void); + +int main(void) +{ + printf("Hello from app\n"); + foo(); + return 0; +} diff --git a/tests/auto/blackbox/testdata-baremetal/shared-libraries/shared-libraries.qbs b/tests/auto/blackbox/testdata-baremetal/shared-libraries/shared-libraries.qbs new file mode 100644 index 000000000..fded553f6 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/shared-libraries/shared-libraries.qbs @@ -0,0 +1,32 @@ +import "../BareMetalApplication.qbs" as BareMetalApplication + +Project { + condition: { + if (qbs.targetPlatform === "windows" && qbs.architecture === "x86") { + if (qbs.toolchainType === "watcom") + return true; + if (qbs.toolchainType === "dmc") + return true; + } + + if (qbs.toolchainType === "msvc") + return true; + + console.info("unsupported toolset: %%" + + qbs.toolchainType + "%%, %%" + qbs.architecture + "%%"); + return false; + } + + DynamicLibrary { + Depends { name: "cpp" } + destinationDirectory: "bin" + name: "shared" + files: ["shared.c"] + } + BareMetalApplication { + Depends { name: "shared" } + destinationDirectory: "bin" + name: "app" + files: ["app.c"] + } +} diff --git a/tests/auto/blackbox/testdata-baremetal/shared-libraries/shared.c b/tests/auto/blackbox/testdata-baremetal/shared-libraries/shared.c new file mode 100644 index 000000000..ab0c110fb --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/shared-libraries/shared.c @@ -0,0 +1,19 @@ +#include "../dllexport.h" + +#include <stdio.h> + +#ifdef __DMC__ +#include <windows.h> +#define EXPORT_FUN _export +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) +{ + return TRUE; +} +#else +#define EXPORT_FUN +#endif // __DMC__ + +DLL_EXPORT void EXPORT_FUN foo(void) +{ + printf("Hello from lib\n"); +} diff --git a/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/a1.c b/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/a1.c new file mode 100644 index 000000000..b593e95d8 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/a1.c @@ -0,0 +1,4 @@ +int a1(void) +{ + return 0; +} diff --git a/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/a2.c b/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/a2.c new file mode 100644 index 000000000..35ab7feb3 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/a2.c @@ -0,0 +1,4 @@ +int a2(void) +{ + return 0; +} diff --git a/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/app.c b/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/app.c new file mode 100644 index 000000000..9814bfd9c --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/app.c @@ -0,0 +1,6 @@ +extern int e(void); + +int main(void) +{ + return e(); +} diff --git a/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/b.c b/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/b.c new file mode 100644 index 000000000..92df418d1 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/b.c @@ -0,0 +1,6 @@ +extern int a1(void); + +int b(void) +{ + return a1(); +} diff --git a/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/c.c b/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/c.c new file mode 100644 index 000000000..0c0e350f2 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/c.c @@ -0,0 +1,6 @@ +extern int a2(void); + +int c(void) +{ + return a2(); +} diff --git a/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/d.c b/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/d.c new file mode 100644 index 000000000..a3fc084f5 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/d.c @@ -0,0 +1,7 @@ +extern int b(void); +extern int c(void); + +int d(void) +{ + return b() + c(); +} diff --git a/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/e.c b/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/e.c new file mode 100644 index 000000000..9381e845c --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/e.c @@ -0,0 +1,7 @@ +extern int d(void); + +int e(void) +{ + return d(); +} + diff --git a/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/static-library-dependencies.qbs b/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/static-library-dependencies.qbs new file mode 100644 index 000000000..7184f47ea --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/static-library-dependencies.qbs @@ -0,0 +1,40 @@ +import "../BareMetalApplication.qbs" as BareMetalApplication +import "../BareMetalStaticLibrary.qbs" as BareMetalStaticLibrary + +Project { + BareMetalStaticLibrary { + name: "lib-a" + Depends { name: "cpp" } + files: ["a1.c", "a2.c"] + } + BareMetalStaticLibrary { + name: "lib-b" + Depends { name: "cpp" } + Depends { name: "lib-a" } + files: ["b.c"] + } + BareMetalStaticLibrary { + name: "lib-c" + Depends { name: "cpp" } + Depends { name: "lib-a" } + files: ["c.c"] + } + BareMetalStaticLibrary { + name: "lib-d" + Depends { name: "cpp" } + Depends { name: "lib-b" } + Depends { name: "lib-c" } + files: ["d.c"] + } + BareMetalStaticLibrary { + name: "lib-e" + Depends { name: "cpp" } + Depends { name: "lib-d" } + files: ["e.c"] + } + BareMetalApplication { + name: "app" + Depends { name: "lib-e" } + files: ["app.c"] + } +} diff --git a/tests/auto/blackbox/testdata-baremetal/system-include-paths/bar/bar.h b/tests/auto/blackbox/testdata-baremetal/system-include-paths/bar/bar.h new file mode 100644 index 000000000..49ffa0b12 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/system-include-paths/bar/bar.h @@ -0,0 +1,6 @@ +#ifndef BAR_H +#define BAR_H + +#define BAR_VALUE 1 + +#endif // BAR_H diff --git a/tests/auto/blackbox/testdata-baremetal/system-include-paths/foo/foo.h b/tests/auto/blackbox/testdata-baremetal/system-include-paths/foo/foo.h new file mode 100644 index 000000000..dc510379d --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/system-include-paths/foo/foo.h @@ -0,0 +1,6 @@ +#ifndef FOO_H +#define FOO_H + +#define FOO_VALUE 1 + +#endif // FOO_H diff --git a/tests/auto/blackbox/testdata-baremetal/system-include-paths/main.c b/tests/auto/blackbox/testdata-baremetal/system-include-paths/main.c new file mode 100644 index 000000000..aabc97a0c --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/system-include-paths/main.c @@ -0,0 +1,7 @@ +#include <foo.h> +#include <bar.h> + +int main(void) +{ + return FOO_VALUE - BAR_VALUE; +} diff --git a/tests/auto/blackbox/testdata-baremetal/system-include-paths/system-include-paths.qbs b/tests/auto/blackbox/testdata-baremetal/system-include-paths/system-include-paths.qbs new file mode 100644 index 000000000..1f9fd1231 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/system-include-paths/system-include-paths.qbs @@ -0,0 +1,6 @@ +import "../BareMetalApplication.qbs" as BareMetalApplication + +BareMetalApplication { + files: ["main.c"] + cpp.systemIncludePaths: ["foo", "bar"] +} diff --git a/tests/auto/blackbox/testdata-baremetal/target-platform/target-platform.qbs b/tests/auto/blackbox/testdata-baremetal/target-platform/target-platform.qbs new file mode 100644 index 000000000..d29e7e619 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/target-platform/target-platform.qbs @@ -0,0 +1,19 @@ +Product { + Depends { name: "cpp" } + condition: { + if (qbs.toolchainType === "keil" + || qbs.toolchainType === "iar" + || qbs.toolchainType === "sdcc" + || qbs.toolchainType === "cosmic") { + var hasNoPlatform = (qbs.targetPlatform === "none"); + var hasNoOS = (qbs.targetOS.length === 1 && qbs.targetOS[0] === "none"); + console.info("has no platform: " + hasNoPlatform); + console.info("has no os: " + hasNoOS); + } else { + console.info("unsupported toolset: %%" + + qbs.toolchainType + "%%, %%" + qbs.architecture + "%%"); + return false; + } + return true; + } +} diff --git a/tests/auto/blackbox/testdata-baremetal/toolchain-probe/probes/dmc.qbs b/tests/auto/blackbox/testdata-baremetal/toolchain-probe/probes/dmc.qbs new file mode 100644 index 000000000..13f751669 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/toolchain-probe/probes/dmc.qbs @@ -0,0 +1,31 @@ +import qbs.Probes + +Product { + id: product + condition: qbs.toolchainType === "dmc" + + Depends { name: "cpp" } + + Probes.DmcProbe { + id: probe + compilerFilePath: cpp.compilerPath + enableDefinesByLanguage: cpp.enableCompilerDefinesByLanguage + _targetPlatform: qbs.targetPlatform + _targetArchitecture: qbs.architecture + _targetExtender: cpp.extenderName + } + + property bool dummy: { + if (!product.condition) + return; + if (!probe.found + || !probe.compilerDefinesByLanguage + || !probe.includePaths + || (probe.includePaths.length === 0) + || (qbs.architecture !== probe.architecture) + || (qbs.targetPlatform !== probe.targetPlatform)) { + console.info("broken probe: %%" + qbs.toolchainType + "%%, %%" + + qbs.architecture + "%%"); + } + } +} diff --git a/tests/auto/blackbox/testdata-baremetal/toolchain-probe/probes/sdcc.qbs b/tests/auto/blackbox/testdata-baremetal/toolchain-probe/probes/sdcc.qbs new file mode 100644 index 000000000..fa5f519a9 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/toolchain-probe/probes/sdcc.qbs @@ -0,0 +1,29 @@ +import qbs.Probes + +Product { + id: product + condition: qbs.toolchainType === "sdcc" + + Depends { name: "cpp" } + + Probes.SdccProbe { + id: probe + compilerFilePath: cpp.compilerPath + enableDefinesByLanguage: cpp.enableCompilerDefinesByLanguage + preferredArchitecture: qbs.architecture + } + + property bool dummy: { + if (!product.condition) + return; + if (!probe.found + || !probe.endianness + || !probe.compilerDefinesByLanguage + || !probe.includePaths + || (probe.includePaths.length === 0) + || (qbs.architecture !== probe.architecture)) { + console.info("broken probe: %%" + qbs.toolchainType + "%%, %%" + + qbs.architecture + "%%"); + } + } +} diff --git a/tests/auto/blackbox/testdata-baremetal/toolchain-probe/probes/watcom.qbs b/tests/auto/blackbox/testdata-baremetal/toolchain-probe/probes/watcom.qbs new file mode 100644 index 000000000..b7c92dc21 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/toolchain-probe/probes/watcom.qbs @@ -0,0 +1,34 @@ +import qbs.Probes + +Product { + id: product + condition: qbs.toolchainType === "watcom" + + Depends { name: "cpp" } + + Probes.WatcomProbe { + id: probe + compilerFilePath: cpp.compilerPath + enableDefinesByLanguage: cpp.enableCompilerDefinesByLanguage + _pathListSeparator: qbs.pathListSeparator + _toolchainInstallPath: cpp.toolchainInstallPath + _targetPlatform: qbs.targetPlatform + _targetArchitecture: qbs.architecture + } + + property bool dummy: { + if (!product.condition) + return; + if (!probe.found + || !probe.endianness + || !probe.compilerDefinesByLanguage + || !probe.environment + || !probe.includePaths + || (probe.includePaths.length === 0) + || (qbs.architecture !== probe.architecture) + || (qbs.targetPlatform !== probe.targetPlatform)) { + console.info("broken probe: %%" + qbs.toolchainType + "%%, %%" + + qbs.architecture + "%%"); + } + } +} diff --git a/tests/auto/blackbox/testdata-baremetal/toolchain-probe/toolchain-probe.qbs b/tests/auto/blackbox/testdata-baremetal/toolchain-probe/toolchain-probe.qbs new file mode 100644 index 000000000..36725cfde --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/toolchain-probe/toolchain-probe.qbs @@ -0,0 +1,7 @@ +Project { + references: [ + "probes/dmc.qbs", + "probes/sdcc.qbs", + "probes/watcom.qbs", + ] +} diff --git a/tests/auto/blackbox/testdata-baremetal/two-object-application/fun.c b/tests/auto/blackbox/testdata-baremetal/two-object-application/fun.c new file mode 100644 index 000000000..3b8c8f2f4 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/two-object-application/fun.c @@ -0,0 +1,4 @@ +int f(void) +{ + return 0; +} diff --git a/tests/auto/blackbox/testdata-baremetal/two-object-application/main.c b/tests/auto/blackbox/testdata-baremetal/two-object-application/main.c new file mode 100644 index 000000000..2c3d7726c --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/two-object-application/main.c @@ -0,0 +1,6 @@ +extern int f(void); + +int main(void) +{ + return f(); +} diff --git a/tests/auto/blackbox/testdata-baremetal/two-object-application/two-object-application.qbs b/tests/auto/blackbox/testdata-baremetal/two-object-application/two-object-application.qbs new file mode 100644 index 000000000..2947975ca --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/two-object-application/two-object-application.qbs @@ -0,0 +1,5 @@ +import "../BareMetalApplication.qbs" as BareMetalApplication + +BareMetalApplication { + files: ["main.c", "fun.c"] +} diff --git a/tests/auto/blackbox/testdata-baremetal/user-include-paths/bar/bar.h b/tests/auto/blackbox/testdata-baremetal/user-include-paths/bar/bar.h new file mode 100644 index 000000000..49ffa0b12 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/user-include-paths/bar/bar.h @@ -0,0 +1,6 @@ +#ifndef BAR_H +#define BAR_H + +#define BAR_VALUE 1 + +#endif // BAR_H diff --git a/tests/auto/blackbox/testdata-baremetal/user-include-paths/foo/foo.h b/tests/auto/blackbox/testdata-baremetal/user-include-paths/foo/foo.h new file mode 100644 index 000000000..dc510379d --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/user-include-paths/foo/foo.h @@ -0,0 +1,6 @@ +#ifndef FOO_H +#define FOO_H + +#define FOO_VALUE 1 + +#endif // FOO_H diff --git a/tests/auto/blackbox/testdata-baremetal/user-include-paths/main.c b/tests/auto/blackbox/testdata-baremetal/user-include-paths/main.c new file mode 100644 index 000000000..e76e08cbe --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/user-include-paths/main.c @@ -0,0 +1,7 @@ +#include "foo.h" +#include "bar.h" + +int main(void) +{ + return FOO_VALUE - BAR_VALUE; +} diff --git a/tests/auto/blackbox/testdata-baremetal/user-include-paths/user-include-paths.qbs b/tests/auto/blackbox/testdata-baremetal/user-include-paths/user-include-paths.qbs new file mode 100644 index 000000000..23d5dbced --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/user-include-paths/user-include-paths.qbs @@ -0,0 +1,6 @@ +import "../BareMetalApplication.qbs" as BareMetalApplication + +BareMetalApplication { + files: ["main.c"] + cpp.includePaths: ["foo", "bar"] +} diff --git a/tests/auto/blackbox/testdata-clangdb/project1/project.qbs b/tests/auto/blackbox/testdata-clangdb/project1/project.qbs index ecfc562b0..313f33ead 100644 --- a/tests/auto/blackbox/testdata-clangdb/project1/project.qbs +++ b/tests/auto/blackbox/testdata-clangdb/project1/project.qbs @@ -7,8 +7,8 @@ Project { Application { Probe { id: dummy - property bool isMingw: qbs.toolchain.contains("mingw") - property bool isMsvc: qbs.toolchain.contains("msvc") + property bool isMingw: qbs.toolchain.includes("mingw") + property bool isMsvc: qbs.toolchain.includes("msvc") property var buildEnv: cpp.buildEnv configure: { if (!buildEnv) diff --git a/tests/auto/blackbox/testdata-java/java/vehicles.qbs b/tests/auto/blackbox/testdata-java/java/vehicles.qbs index 8153efe00..8a4bb732f 100644 --- a/tests/auto/blackbox/testdata-java/java/vehicles.qbs +++ b/tests/auto/blackbox/testdata-java/java/vehicles.qbs @@ -1,4 +1,5 @@ import qbs.FileInfo +import qbs.Host import qbs.Utilities Project { @@ -6,10 +7,17 @@ Project { Depends { name: "cpp" } Depends { name: "car_jar" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } + property bool _testPlatform: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } + name: "native" files: ["engine.c"] @@ -34,7 +42,7 @@ Project { Export { Depends { name: "java" } - java.manifestClassPath: [product.targetName + ".jar"] + java.manifestClassPath: [exportingProduct.targetName + ".jar"] } } @@ -50,7 +58,7 @@ Project { Export { Depends { name: "java" } - java.manifestClassPath: [product.targetName + ".jar"] + java.manifestClassPath: [exportingProduct.targetName + ".jar"] } } @@ -68,13 +76,13 @@ Project { cpp.systemIncludePaths: { var paths = importingProduct.java.jdkIncludePaths; if (Utilities.versionCompare(importingProduct.java.version, "1.8") >= 0) { - paths.push(product.buildDirectory); // generated JNI headers + paths.push(exportingProduct.buildDirectory); // generated JNI headers } return paths; } Depends { name: "java" } - java.manifestClassPath: [product.targetName + ".jar"] + java.manifestClassPath: [exportingProduct.targetName + ".jar"] } qbs.installPrefix: "" diff --git a/tests/auto/blackbox/testdata-joblimits/job-limits-init/job-limits-init.qbs b/tests/auto/blackbox/testdata-joblimits/job-limits-init/job-limits-init.qbs new file mode 100644 index 000000000..3a0075530 --- /dev/null +++ b/tests/auto/blackbox/testdata-joblimits/job-limits-init/job-limits-init.qbs @@ -0,0 +1,10 @@ +import qbs.Host + +Product { + property bool _testPlatform: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } +} diff --git a/tests/auto/blackbox/testdata-joblimits/job-limits/job-limits.qbs b/tests/auto/blackbox/testdata-joblimits/job-limits/job-limits.qbs index 221105a64..76f54807a 100644 --- a/tests/auto/blackbox/testdata-joblimits/job-limits/job-limits.qbs +++ b/tests/auto/blackbox/testdata-joblimits/job-limits/job-limits.qbs @@ -19,7 +19,7 @@ Project { consoleApplication: true cpp.cxxLanguageVersion: "c++14" Properties { - condition: qbs.targetOS.contains("macos") + condition: qbs.targetOS.includes("macos") cpp.minimumMacosVersion: "10.9" } files: "main.cpp" @@ -37,7 +37,7 @@ Project { var cmd = new Command(explicitlyDependsOn.tool_tag[0].filePath, [output.filePath]); cmd.workingDirectory = product.buildDirectory; - cmd.description = "Running tool"; + cmd.description = "running tool"; cmd.jobPool = "singleton"; return cmd; } diff --git a/tests/auto/blackbox/testdata-joblimits/job-limits/main.cpp b/tests/auto/blackbox/testdata-joblimits/job-limits/main.cpp index ec9acba80..5f436b0e9 100644 --- a/tests/auto/blackbox/testdata-joblimits/job-limits/main.cpp +++ b/tests/auto/blackbox/testdata-joblimits/job-limits/main.cpp @@ -63,7 +63,7 @@ int main(int argc, char *argv[]) const std::string lockFilePath = std::string(argv[0]) + ".lock"; std::FILE * const lockFile = std::fopen(lockFilePath.c_str(), "w"); if (!lockFile) { - std::cerr << "cannot open lock file: " << strerror(errno) << std::endl; + std::cerr << "cannot open lock file: " << std::strerror(errno) << std::endl; return 2; } if (!tryLock(lockFile)) { @@ -71,17 +71,17 @@ int main(int argc, char *argv[]) std::cerr << "tool is exclusive" << std::endl; return 3; } else { - std::cerr << "unexpected lock failure: " << strerror(errno) << std::endl; - fclose(lockFile); + std::cerr << "unexpected lock failure: " << std::strerror(errno) << std::endl; + std::fclose(lockFile); return 4; } } std::this_thread::sleep_for(std::chrono::milliseconds(50)); - fclose(lockFile); + std::fclose(lockFile); std::FILE * const output = std::fopen(argv[1], "w"); if (!output) { - std::cerr << "cannot create output file: " << strerror(errno) << std::endl; + std::cerr << "cannot create output file: " << std::strerror(errno) << std::endl; return 5; } - fclose(output); + std::fclose(output); } diff --git a/tests/auto/blackbox/testdata-providers/allowed-values/allowed-values.qbs b/tests/auto/blackbox/testdata-providers/allowed-values/allowed-values.qbs new file mode 100644 index 000000000..e6dbaddde --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/allowed-values/allowed-values.qbs @@ -0,0 +1,4 @@ +Product { + Depends { name: "qbsmetatestmodule" } + qbsModuleProviders: "provider" +} diff --git a/tests/auto/blackbox/testdata-providers/allowed-values/module-providers/provider.qbs b/tests/auto/blackbox/testdata-providers/allowed-values/module-providers/provider.qbs new file mode 100644 index 000000000..c0e426c96 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/allowed-values/module-providers/provider.qbs @@ -0,0 +1,14 @@ +import "../../qbs-module-providers-helpers.js" as Helpers + +ModuleProvider { + isEager: false + property stringList aProperty: "zero" + PropertyOptions { + name: "aProperty" + allowedValues: ["one", "two"] + } + relativeSearchPaths: { + Helpers.writeModule(outputBaseDir, moduleName, "from_provider"); + return ""; + } +} diff --git a/tests/auto/blackbox/testdata-providers/broken-provider/broken-provider.qbs b/tests/auto/blackbox/testdata-providers/broken-provider/broken-provider.qbs new file mode 100644 index 000000000..461c7e30e --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/broken-provider/broken-provider.qbs @@ -0,0 +1,13 @@ +Project { + qbsModuleProviders: "provider_a" + name: "project" + Project { + name: "innerProject" + Product { + name: "p1" + Depends { name: "qbsothermodule"; required: false } + Depends { name: "qbsmetatestmodule" } + } + } + +} diff --git a/tests/auto/blackbox/testdata-providers/broken-provider/module-providers/provider_a.qbs b/tests/auto/blackbox/testdata-providers/broken-provider/module-providers/provider_a.qbs new file mode 100644 index 000000000..f446d2d13 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/broken-provider/module-providers/provider_a.qbs @@ -0,0 +1,5 @@ +ModuleProvider { + relativeSearchPaths: { + throw "This provider is broken"; + } +} diff --git a/tests/auto/blackbox/testdata-providers/conan-provider/conan-module-provider.qbs b/tests/auto/blackbox/testdata-providers/conan-provider/conan-module-provider.qbs new file mode 100644 index 000000000..e8880fc96 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/conan-provider/conan-module-provider.qbs @@ -0,0 +1,11 @@ +CppApplication { + consoleApplication: true + name: "p" + files: "main.cpp" + qbsModuleProviders: "conan" + qbs.buildVariant: "release" + qbs.installPrefix: "" + install: true + Depends { name: "conanmoduleprovider.testlib" } + Depends { name: "conanmoduleprovider.testlibheader" } +} diff --git a/tests/auto/blackbox/testdata-providers/conan-provider/conanfile.txt b/tests/auto/blackbox/testdata-providers/conan-provider/conanfile.txt new file mode 100644 index 000000000..7c40ff7d6 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/conan-provider/conanfile.txt @@ -0,0 +1,3 @@ +[requires] +conanmoduleprovider.testlib/1.2.3 +conanmoduleprovider.testlibheader/0.1.0 diff --git a/tests/auto/blackbox/testdata-providers/conan-provider/main.cpp b/tests/auto/blackbox/testdata-providers/conan-provider/main.cpp new file mode 100644 index 000000000..6250927b3 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/conan-provider/main.cpp @@ -0,0 +1,8 @@ +#include <testlib.h> + +#include <header.h> + +int main() +{ + HelloWorld h(42 + hello()); +} diff --git a/tests/auto/blackbox/testdata-providers/conan-provider/testlib/CMakeLists.txt b/tests/auto/blackbox/testdata-providers/conan-provider/testlib/CMakeLists.txt new file mode 100644 index 000000000..d186d1906 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/conan-provider/testlib/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.15) +project(conanmoduleprovider.testlib) + +find_package(conanmoduleprovider.testlibdep REQUIRED) + +add_library(${PROJECT_NAME} STATIC testlib.cpp) +set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "testlib.h") +target_link_libraries(${PROJECT_NAME} conanmoduleprovider.testlibdep::conanmoduleprovider.testlibdep) +install(TARGETS ${PROJECT_NAME}) diff --git a/tests/auto/blackbox/testdata-providers/conan-provider/testlib/conanfile.py b/tests/auto/blackbox/testdata-providers/conan-provider/testlib/conanfile.py new file mode 100644 index 000000000..7cb91f9ef --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/conan-provider/testlib/conanfile.py @@ -0,0 +1,36 @@ +from conan import ConanFile +from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps +from conan.tools.files import collect_libs +import os + +class ConanModuleProviderTestlib(ConanFile): + name = "conanmoduleprovider.testlib" + license = "none" + version = "1.2.3" + + exports_sources = "*.cpp", "*.h", "CMakeLists.txt" + settings = "os", "compiler", "build_type", "arch" + + def requirements(self): + self.requires("conanmoduleprovider.testlibdep/1.2.3") + + def layout(self): + cmake_layout(self) + + def generate(self): + deps = CMakeDeps(self) + deps.generate() + tc = CMakeToolchain(self, generator="Ninja") + tc.generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def package(self): + cmake = CMake(self) + cmake.install() + + def package_info(self): + self.cpp_info.libs = collect_libs(self) diff --git a/tests/auto/blackbox/testdata-providers/conan-provider/testlib/testlib.cpp b/tests/auto/blackbox/testdata-providers/conan-provider/testlib/testlib.cpp new file mode 100644 index 000000000..7118dfda9 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/conan-provider/testlib/testlib.cpp @@ -0,0 +1,7 @@ +#include "testlib.h" + +#include <testlibdep.h> + +HelloWorld::HelloWorld(int x) + : m_x(foo(x)) +{} diff --git a/tests/auto/blackbox/testdata-providers/conan-provider/testlib/testlib.h b/tests/auto/blackbox/testdata-providers/conan-provider/testlib/testlib.h new file mode 100644 index 000000000..11a354b70 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/conan-provider/testlib/testlib.h @@ -0,0 +1,10 @@ +#pragma once + +class HelloWorld +{ +public: + explicit HelloWorld(int x); + +private: + int m_x; +}; diff --git a/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/CMakeLists.txt b/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/CMakeLists.txt new file mode 100644 index 000000000..5510a9250 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.15) +project(conanmoduleprovider.testlibdep) + +add_library(${PROJECT_NAME} STATIC testlibdep.cpp) +set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "testlibdep.h") +install(TARGETS ${PROJECT_NAME}) +install(FILES lorem_ipsum.txt DESTINATION share)
\ No newline at end of file diff --git a/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/conanfile.py b/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/conanfile.py new file mode 100644 index 000000000..f2c577c5e --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/conanfile.py @@ -0,0 +1,35 @@ +from conan import ConanFile +from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps +from conan.tools.files import collect_libs, copy +import os + +class ConanModuleProviderTestlib(ConanFile): + name = "conanmoduleprovider.testlibdep" + license = "none" + version = "1.2.3" + + exports_sources = "*.cpp", "*.h", "*.txt" + settings = "os", "compiler", "build_type", "arch" + + def layout(self): + cmake_layout(self) + + def generate(self): + deps = CMakeDeps(self) + deps.generate() + tc = CMakeToolchain(self, generator="Ninja") + tc.generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def package(self): + cmake = CMake(self) + cmake.install() + + def package_info(self): + self.cpp_info.libs = collect_libs(self) + self.cpp_info.resdirs = ['share'] + diff --git a/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/lorem_ipsum.txt b/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/lorem_ipsum.txt new file mode 100644 index 000000000..d8634396c --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/lorem_ipsum.txt @@ -0,0 +1 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit.
\ No newline at end of file diff --git a/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/testlibdep.cpp b/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/testlibdep.cpp new file mode 100644 index 000000000..893478c82 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/testlibdep.cpp @@ -0,0 +1,6 @@ +#include "testlibdep.h" + +int foo(int i) +{ + return i * i; +}
\ No newline at end of file diff --git a/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/testlibdep.h b/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/testlibdep.h new file mode 100644 index 000000000..ca7bd3cbc --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/testlibdep.h @@ -0,0 +1,3 @@ +#pragma once + +int foo(int i);
\ No newline at end of file diff --git a/tests/auto/blackbox/testdata-providers/conan-provider/testlibheader/conanfile.py b/tests/auto/blackbox/testdata-providers/conan-provider/testlibheader/conanfile.py new file mode 100644 index 000000000..6078b9750 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/conan-provider/testlibheader/conanfile.py @@ -0,0 +1,15 @@ +from conan import ConanFile +from conan.tools.files import copy + +import os + +class Recipe(ConanFile): + exports_sources = ("header.h") + version = '0.1.0' + name = 'conanmoduleprovider.testlibheader' + + def package(self): + copy(self, + "header.h", + src=self.source_folder, + dst=os.path.join(self.package_folder, "include"))
\ No newline at end of file diff --git a/tests/auto/blackbox/testdata-providers/conan-provider/testlibheader/header.h b/tests/auto/blackbox/testdata-providers/conan-provider/testlibheader/header.h new file mode 100644 index 000000000..66bd50d57 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/conan-provider/testlibheader/header.h @@ -0,0 +1,6 @@ +#pragma once + +inline int hello() +{ + return 0; +}
\ No newline at end of file diff --git a/tests/auto/blackbox/testdata/fallback-module-provider/fallback-module-provider.qbs b/tests/auto/blackbox/testdata-providers/fallback-module-provider/fallback-module-provider.qbs index a798e15b3..a798e15b3 100644 --- a/tests/auto/blackbox/testdata/fallback-module-provider/fallback-module-provider.qbs +++ b/tests/auto/blackbox/testdata-providers/fallback-module-provider/fallback-module-provider.qbs diff --git a/tests/auto/blackbox/testdata/fallback-module-provider/libdir/qbsmetatestmodule.pc b/tests/auto/blackbox/testdata-providers/fallback-module-provider/libdir/qbsmetatestmodule.pc index ae4daba89..ae4daba89 100644 --- a/tests/auto/blackbox/testdata/fallback-module-provider/libdir/qbsmetatestmodule.pc +++ b/tests/auto/blackbox/testdata-providers/fallback-module-provider/libdir/qbsmetatestmodule.pc diff --git a/tests/auto/blackbox/testdata/fallback-module-provider/main.cpp b/tests/auto/blackbox/testdata-providers/fallback-module-provider/main.cpp index 442b755bf..442b755bf 100644 --- a/tests/auto/blackbox/testdata/fallback-module-provider/main.cpp +++ b/tests/auto/blackbox/testdata-providers/fallback-module-provider/main.cpp diff --git a/tests/auto/blackbox/testdata-providers/module-providers-cache/module-providers-cache.qbs b/tests/auto/blackbox/testdata-providers/module-providers-cache/module-providers-cache.qbs new file mode 100644 index 000000000..508ed84d2 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/module-providers-cache/module-providers-cache.qbs @@ -0,0 +1,11 @@ +Project { + qbsModuleProviders: ["provider_a"] + name: "project" + property string dummyProp + + Product { + name: "p1" + Depends { name: "qbsothermodule" } + Depends { name: "qbsmetatestmodule" } + } +} diff --git a/tests/auto/blackbox/testdata-providers/module-providers-cache/module-providers/provider_a.qbs b/tests/auto/blackbox/testdata-providers/module-providers-cache/module-providers/provider_a.qbs new file mode 100644 index 000000000..782cf7d25 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/module-providers-cache/module-providers/provider_a.qbs @@ -0,0 +1,9 @@ +import "../../qbs-module-providers-helpers.js" as Helpers + +ModuleProvider { + relativeSearchPaths: { + Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", "from_provider_a"); + Helpers.writeModule(outputBaseDir, "qbsothermodule", "from_provider_a"); + return ""; + } +} diff --git a/tests/auto/blackbox/testdata/module-providers/main.cpp b/tests/auto/blackbox/testdata-providers/module-providers/main.cpp index 9cd29b1fe..85a4f551c 100644 --- a/tests/auto/blackbox/testdata/module-providers/main.cpp +++ b/tests/auto/blackbox/testdata-providers/module-providers/main.cpp @@ -3,4 +3,6 @@ int main() { std::cout << "The letters are " << LETTER1 << " and " << LETTER2 << std::endl; + std::cout << "The MY_DEFINE is " << MY_DEFINE << std::endl; + return 0; } diff --git a/tests/auto/blackbox/testdata-providers/module-providers/module-providers.qbs b/tests/auto/blackbox/testdata-providers/module-providers/module-providers.qbs new file mode 100644 index 000000000..89bd1a11d --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/module-providers/module-providers.qbs @@ -0,0 +1,36 @@ +import qbs.Host + +Project { + property bool enabled: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } + readonly property string beginning: "beginning" + CppApplication { + name: "app1" + property string chooseLettersFrom: project.beginning // This indirection tests QBS-1747. + Depends { name: "mygenerator.module1" } + Depends { name: "mygenerator.module2" } + Depends { name: "othergenerator" } + moduleProviders.mygenerator.chooseLettersFrom: chooseLettersFrom + moduleProviders.othergenerator.someDefines: name + files: "main.cpp" + } + CppApplication { + readonly property string end: "end" + name: "app2" + Depends { name: "mygenerator.module1" } + Depends { name: "mygenerator.module2" } + Depends { name: "othergenerator" } + Profile { + name: "myProfile" + baseProfile: project.profile + moduleProviders.mygenerator.chooseLettersFrom: product.end + moduleProviders.othergenerator.someDefines: "app2" + } + qbs.profile: "myProfile" + files: "main.cpp" + } +} diff --git a/tests/auto/blackbox/testdata/module-providers/module-providers/mygenerator/provider.qbs b/tests/auto/blackbox/testdata-providers/module-providers/module-providers/mygenerator/provider.qbs index dae02c03a..dae02c03a 100644 --- a/tests/auto/blackbox/testdata/module-providers/module-providers/mygenerator/provider.qbs +++ b/tests/auto/blackbox/testdata-providers/module-providers/module-providers/mygenerator/provider.qbs diff --git a/tests/auto/blackbox/testdata-providers/module-providers/module-providers/othergenerator/provider.qbs b/tests/auto/blackbox/testdata-providers/module-providers/module-providers/othergenerator/provider.qbs new file mode 100644 index 000000000..66557037c --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/module-providers/module-providers/othergenerator/provider.qbs @@ -0,0 +1,19 @@ +import qbs.File; +import qbs.FileInfo; +import qbs.TextFile; + +ModuleProvider { + property string someDefines + relativeSearchPaths: { + console.info("Running setup script for " + name); + var moduleDir = FileInfo.joinPaths(outputBaseDir, "modules", "othergenerator"); + File.makePath(moduleDir); + var module = new TextFile(FileInfo.joinPaths(moduleDir, "module.qbs"), TextFile.WriteOnly); + module.writeLine("Module {"); + module.writeLine(" Depends { name: 'cpp' }"); + module.writeLine(" cpp.defines: 'MY_DEFINE=\"" + someDefines + "\"'"); + module.writeLine("}"); + module.close(); + return ""; + } +} diff --git a/tests/auto/blackbox/testdata-providers/non-eager-provider/module-providers/provider_a.qbs b/tests/auto/blackbox/testdata-providers/non-eager-provider/module-providers/provider_a.qbs new file mode 100644 index 000000000..6cd9177db --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/non-eager-provider/module-providers/provider_a.qbs @@ -0,0 +1,11 @@ +import "../../qbs-module-providers-helpers.js" as Helpers + +ModuleProvider { + isEager: false + relativeSearchPaths: { + if (moduleName === "nonexistentmodule") + return undefined; + Helpers.writeModule(outputBaseDir, moduleName, "from_provider_a"); + return ""; + } +} diff --git a/tests/auto/blackbox/testdata-providers/non-eager-provider/non-eager-provider.qbs b/tests/auto/blackbox/testdata-providers/non-eager-provider/non-eager-provider.qbs new file mode 100644 index 000000000..bd3662de3 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/non-eager-provider/non-eager-provider.qbs @@ -0,0 +1,13 @@ +Project { + Product { + name: "p1" + Depends { name: "qbsmetatestmodule" } + Depends { name: "qbsothermodule" } + Depends { name: "nonexistentmodule"; required: false } + property bool dummy: { + console.info("p1.qbsmetatestmodule.prop: " + qbsmetatestmodule.prop); + console.info("p1.qbsothermodule.prop: " + qbsothermodule.prop); + } + qbsModuleProviders: "provider_a" + } +} diff --git a/tests/auto/blackbox/testdata-providers/probe-in-module-provider/module-providers/provider_a.qbs b/tests/auto/blackbox/testdata-providers/probe-in-module-provider/module-providers/provider_a.qbs new file mode 100644 index 000000000..476a83143 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/probe-in-module-provider/module-providers/provider_a.qbs @@ -0,0 +1,23 @@ +import "../../qbs-module-providers-helpers.js" as Helpers + +ModuleProvider { + property string sysroot: qbs.sysroot + Probe { + id: theProbe + property string theValue: "value" + property string dummy: sysroot + configure: { + console.info("Running probe with irrelevant value '" + dummy + "'"); + found = true; + } + } + isEager: false + property bool found: theProbe.found + property string theValue: theProbe.theValue + relativeSearchPaths: { + Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", theValue, undefined, found); + if (sysroot !== qbs.sysroot) + throw "this is unexpected"; + return ""; + } +} diff --git a/tests/auto/blackbox/testdata-providers/probe-in-module-provider/probe-in-module-provider.qbs b/tests/auto/blackbox/testdata-providers/probe-in-module-provider/probe-in-module-provider.qbs new file mode 100644 index 000000000..1f2b3d387 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/probe-in-module-provider/probe-in-module-provider.qbs @@ -0,0 +1,9 @@ +Product { + qbsModuleProviders: ["provider_a"] + name: "p" + Depends { name: "qbsmetatestmodule" } + property bool dummy: { + console.info("p.qbsmetatestmodule.boolProp: " + JSON.stringify(qbsmetatestmodule.boolProp)); + console.info("p.qbsmetatestmodule.prop: " + JSON.stringify(qbsmetatestmodule.prop)); + } +} diff --git a/tests/auto/blackbox/testdata-providers/providers-properties/module-providers/provider_a.qbs b/tests/auto/blackbox/testdata-providers/providers-properties/module-providers/provider_a.qbs new file mode 100644 index 000000000..ab9d475d8 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/providers-properties/module-providers/provider_a.qbs @@ -0,0 +1,9 @@ +import "../../qbs-module-providers-helpers.js" as Helpers + +ModuleProvider { + property stringList someProp: "provider_a" + relativeSearchPaths: { + Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", undefined, someProp); + return ""; + } +} diff --git a/tests/auto/blackbox/testdata-providers/providers-properties/module-providers/provider_b.qbs b/tests/auto/blackbox/testdata-providers/providers-properties/module-providers/provider_b.qbs new file mode 100644 index 000000000..1b2a79979 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/providers-properties/module-providers/provider_b.qbs @@ -0,0 +1,9 @@ +import "../../qbs-module-providers-helpers.js" as Helpers + +ModuleProvider { + property stringList someProp: "provider_b" + relativeSearchPaths: { + Helpers.writeModule(outputBaseDir, "qbsothermodule", undefined, someProp); + return ""; + } +} diff --git a/tests/auto/blackbox/testdata-providers/providers-properties/providers-properties.qbs b/tests/auto/blackbox/testdata-providers/providers-properties/providers-properties.qbs new file mode 100644 index 000000000..258a973fa --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/providers-properties/providers-properties.qbs @@ -0,0 +1,12 @@ +Product { + qbsModuleProviders: ["provider_a", "provider_b"] + name: "p" + Depends { name: "qbsmetatestmodule" } + Depends { name: "qbsothermodule" } + moduleProviders.provider_a.someProp: "someValue" + property bool dummy: { + console.info("p.qbsmetatestmodule.listProp: " + + JSON.stringify(qbsmetatestmodule.listProp)); + console.info("p.qbsothermodule.listProp: " + JSON.stringify(qbsothermodule.listProp)); + } +} diff --git a/tests/auto/blackbox/testdata-providers/qbs-module-properties-in-providers/module-providers/provider_a.qbs b/tests/auto/blackbox/testdata-providers/qbs-module-properties-in-providers/module-providers/provider_a.qbs new file mode 100644 index 000000000..95c89cd1c --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbs-module-properties-in-providers/module-providers/provider_a.qbs @@ -0,0 +1,9 @@ +import "../../qbs-module-providers-helpers.js" as Helpers + +ModuleProvider { + property string sysroot: qbs.sysroot + relativeSearchPaths: { + Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", sysroot); + return ""; + } +} diff --git a/tests/auto/blackbox/testdata-providers/qbs-module-properties-in-providers/qbs-module-properties-in-providers.qbs b/tests/auto/blackbox/testdata-providers/qbs-module-properties-in-providers/qbs-module-properties-in-providers.qbs new file mode 100644 index 000000000..c2fc58299 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbs-module-properties-in-providers/qbs-module-properties-in-providers.qbs @@ -0,0 +1,34 @@ +Project { + qbsModuleProviders: "provider_a" + name: "project" + + Profile { + name: "profile1" + qbs.sysroot: "/sysroot1" + } + + Profile { + name: "profile2" + qbs.sysroot: "/sysroot2" + } + + Product { + name: "product1" + Depends { name: "qbsmetatestmodule" } + property bool dummy: { + console.info("product1.qbsmetatestmodule.prop: " + qbsmetatestmodule.prop); + } + // multiplex over profiles, sysroot should not be cached + qbs.profiles: ["profile1", "profile2"] + } + + Product { + name: "product2" + Depends { name: "qbsmetatestmodule" } + property bool dummy: { + console.info("product2.qbsmetatestmodule.prop: " + qbsmetatestmodule.prop); + } + // multiplex over profiles, sysroot should not be cached + qbs.profiles: ["profile1", "profile2"] + } +} diff --git a/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/module-providers/provider_a.qbs b/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/module-providers/provider_a.qbs new file mode 100644 index 000000000..d34d1cac5 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/module-providers/provider_a.qbs @@ -0,0 +1,8 @@ +import "../../qbs-module-providers-helpers.js" as Helpers + +ModuleProvider { + relativeSearchPaths: { + Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", "from_provider_a"); + return ""; + } +} diff --git a/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/module-providers/provider_b.qbs b/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/module-providers/provider_b.qbs new file mode 100644 index 000000000..767e30923 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/module-providers/provider_b.qbs @@ -0,0 +1,9 @@ +import "../../qbs-module-providers-helpers.js" as Helpers + +ModuleProvider { + relativeSearchPaths: { + Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", "from_provider_b"); + Helpers.writeModule(outputBaseDir, "qbsothermodule", "from_provider_b"); + return ""; + } +} diff --git a/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/qbs-module-providers-cli-override.qbs b/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/qbs-module-providers-cli-override.qbs new file mode 100644 index 000000000..6f94ab207 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/qbs-module-providers-cli-override.qbs @@ -0,0 +1,13 @@ +Project { + name: "project" + Project { + name: "innerProject" + Product { + name: "product" + Depends { name: "qbsmetatestmodule"; required: false } + property bool dummy: { + console.info("qbsmetatestmodule.prop: " + qbsmetatestmodule.prop); + } + } + } +} diff --git a/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/module-providers/named_provider.qbs b/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/module-providers/named_provider.qbs new file mode 100644 index 000000000..07114b5ef --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/module-providers/named_provider.qbs @@ -0,0 +1,8 @@ +import "../../qbs-module-providers-helpers.js" as Helpers + +ModuleProvider { + relativeSearchPaths: { + Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", "from_named_provider"); + return ""; + } +} diff --git a/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/module-providers/qbsmetatestmodule/provider.qbs b/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/module-providers/qbsmetatestmodule/provider.qbs new file mode 100644 index 000000000..b04a52261 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/module-providers/qbsmetatestmodule/provider.qbs @@ -0,0 +1,8 @@ +import "../../../qbs-module-providers-helpers.js" as Helpers + +ModuleProvider { + relativeSearchPaths: { + Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", "from_scoped_provider"); + return ""; + } +} diff --git a/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/qbs-module-providers-compatibility.qbs b/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/qbs-module-providers-compatibility.qbs new file mode 100644 index 000000000..7885b540a --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/qbs-module-providers-compatibility.qbs @@ -0,0 +1,7 @@ +Product { + name: "p" + Depends { name: "qbsmetatestmodule" } + property bool dummy: { + console.info("qbsmetatestmodule.prop: " + qbsmetatestmodule.prop); + } +} diff --git a/tests/auto/blackbox/testdata-providers/qbs-module-providers-helpers.js b/tests/auto/blackbox/testdata-providers/qbs-module-providers-helpers.js new file mode 100644 index 000000000..8b6d9e275 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbs-module-providers-helpers.js @@ -0,0 +1,23 @@ +var File = require("qbs.File"); +var FileInfo = require("qbs.FileInfo"); +var TextFile = require("qbs.TextFile"); +var ModUtils = require("qbs.ModUtils"); + +function writeModule(outputBaseDir, name, prop, listProp, boolProp) { + console.info("Running setup script for " + name); + var moduleDir = FileInfo.joinPaths(outputBaseDir, "modules", name); + File.makePath(moduleDir); + var module = new TextFile(FileInfo.joinPaths(moduleDir, "module.qbs"), TextFile.WriteOnly); + module.writeLine("Module {"); + module.writeLine(" property string prop: " + ModUtils.toJSLiteral(prop)); + if (listProp) { + module.writeLine(" property stringList listProp: " + + ModUtils.toJSLiteral(listProp)); + } + if (boolProp) { + module.writeLine(" property bool boolProp: " + + ModUtils.toJSLiteral(boolProp)); + } + module.writeLine("}"); + module.close(); +} diff --git a/tests/auto/blackbox/testdata-providers/qbs-module-providers/module-providers/provider_a.qbs b/tests/auto/blackbox/testdata-providers/qbs-module-providers/module-providers/provider_a.qbs new file mode 100644 index 000000000..d34d1cac5 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbs-module-providers/module-providers/provider_a.qbs @@ -0,0 +1,8 @@ +import "../../qbs-module-providers-helpers.js" as Helpers + +ModuleProvider { + relativeSearchPaths: { + Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", "from_provider_a"); + return ""; + } +} diff --git a/tests/auto/blackbox/testdata-providers/qbs-module-providers/module-providers/provider_b.qbs b/tests/auto/blackbox/testdata-providers/qbs-module-providers/module-providers/provider_b.qbs new file mode 100644 index 000000000..767e30923 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbs-module-providers/module-providers/provider_b.qbs @@ -0,0 +1,9 @@ +import "../../qbs-module-providers-helpers.js" as Helpers + +ModuleProvider { + relativeSearchPaths: { + Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", "from_provider_b"); + Helpers.writeModule(outputBaseDir, "qbsothermodule", "from_provider_b"); + return ""; + } +} diff --git a/tests/auto/blackbox/testdata-providers/qbs-module-providers/qbs-module-providers.qbs b/tests/auto/blackbox/testdata-providers/qbs-module-providers/qbs-module-providers.qbs new file mode 100644 index 000000000..00776a62e --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbs-module-providers/qbs-module-providers.qbs @@ -0,0 +1,28 @@ +Project { + qbsModuleProviders: "provider_a" + property stringList wantedProviders: qbsModuleProviders + name: "project" + Project { + name: "innerProject" + qbsModuleProviders: project.wantedProviders + Product { + name: "p1" + Depends { name: "qbsmetatestmodule" } + Depends { name: "qbsothermodule"; required: false } + property bool dummy: { + console.info("p1.qbsmetatestmodule.prop: " + qbsmetatestmodule.prop); + console.info("p1.qbsothermodule.prop: " + qbsothermodule.prop); + } + } + } + + Product { + name: "p2" + Depends { name: "qbsmetatestmodule" } + Depends { name: "qbsothermodule"; required: false } + property bool dummy: { + console.info("p2.qbsmetatestmodule.prop: " + qbsmetatestmodule.prop); + console.info("p2.qbsothermodule.prop: " + qbsothermodule.prop); + } + } +} diff --git a/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/libs/libA.cpp b/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/libs/libA.cpp new file mode 100644 index 000000000..0c5274415 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/libs/libA.cpp @@ -0,0 +1,14 @@ +#include "libA.h" + +#include <iostream> + +void foo() +{ + std::cout << "hello from foo: "; +#ifdef MYLIB_FRAMEWORK + std::cout << "bundled: yes"; +#else + std::cout << "bundled: no"; +#endif + std::cout << std::endl; +} diff --git a/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/libs/libA.h b/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/libs/libA.h new file mode 100644 index 000000000..ddaaf1609 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/libs/libA.h @@ -0,0 +1,21 @@ +#pragma once + +#if defined(_WIN32) || defined(WIN32) +# define DECL_EXPORT __declspec(dllexport) +# define DECL_IMPORT __declspec(dllimport) +#else +# define DECL_EXPORT __attribute__((visibility("default"))) +# define DECL_IMPORT __attribute__((visibility("default"))) +# endif + +#if defined(LIBA_STATIC_LIBRARY) +# define LIBA_EXPORT +#else +# if defined(MYLIB_LIBRARY) +# define LIBA_EXPORT DECL_EXPORT +# else +# define LIBA_EXPORT DECL_IMPORT +# endif +#endif + +LIBA_EXPORT void foo(); diff --git a/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/libs/libs.qbs b/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/libs/libs.qbs new file mode 100644 index 000000000..b473083c6 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/libs/libs.qbs @@ -0,0 +1,42 @@ +import qbs.FileInfo + +Project { + property bool isBundle: false + + DynamicLibrary { + Depends { name: "cpp" } + Depends { name: "bundle" } + Depends { name: "Exporter.pkgconfig" } + Exporter.pkgconfig.versionEntry: "1.0" + name: "libA" + bundle.isBundle: project.isBundle + bundle.publicHeaders: ["libA.h"] + files: "libA.cpp" + cpp.defines: { + var result = []; + if (project.isBundle) + result.push("MYLIB_FRAMEWORK"); + return result; + } + qbs.installPrefix: "/usr" + install: true + installImportLib: true + installDir: "lib" + Group { + files: ["libA.h"] + qbs.install: !project.isBundle + qbs.installDir: FileInfo.joinPaths("include", product.name) + } + Group { + fileTagsFilter: ["Exporter.pkgconfig.pc"] + qbs.install: !project.isBundle + qbs.installDir: FileInfo.joinPaths("share", "pkgconfig") + } + Export { + Depends { name: "cpp" } + cpp.defines: ["THE_MAGIC_DEFINE"] + cpp.includePaths: [FileInfo.joinPaths(exportingProduct.qbs.installPrefix, "include")] + cpp.libraryPaths: [FileInfo.joinPaths(exportingProduct.qbs.installPrefix, "lib")] + } + } +} diff --git a/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/main.cpp b/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/main.cpp new file mode 100644 index 000000000..5fa0f7eed --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/main.cpp @@ -0,0 +1,11 @@ +#include <libA/libA.h> + +#ifndef THE_MAGIC_DEFINE +#error "missing the magic define" +#endif + +int main() +{ + foo(); + return 0; +} diff --git a/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/qbspkgconfig-module-provider.qbs b/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/qbspkgconfig-module-provider.qbs new file mode 100644 index 000000000..d2b3654ae --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/qbspkgconfig-module-provider.qbs @@ -0,0 +1,6 @@ +CppApplication { + name: "p" + Depends { name: "libA" } + files: "main.cpp" + qbsModuleProviders: "qbspkgconfig" +} diff --git a/tests/auto/blackbox/testdata-providers/removal-version/module-providers/provider_a.qbs b/tests/auto/blackbox/testdata-providers/removal-version/module-providers/provider_a.qbs new file mode 100644 index 000000000..7f358acbc --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/removal-version/module-providers/provider_a.qbs @@ -0,0 +1,14 @@ +import "../../qbs-module-providers-helpers.js" as Helpers + +ModuleProvider { + isEager: false + property bool deprecated: false + PropertyOptions { + name: "deprecated" + removalVersion: "2.2.0" + } + relativeSearchPaths: { + Helpers.writeModule(outputBaseDir, moduleName, "from_provider_a"); + return ""; + } +} diff --git a/tests/auto/blackbox/testdata-providers/removal-version/removal-version.qbs b/tests/auto/blackbox/testdata-providers/removal-version/removal-version.qbs new file mode 100644 index 000000000..1aa5e2ce9 --- /dev/null +++ b/tests/auto/blackbox/testdata-providers/removal-version/removal-version.qbs @@ -0,0 +1,12 @@ +Project { + qbsModuleProviders: "provider_a" + name: "project" + Project { + name: "innerProject" + Product { + name: "p1" + Depends { name: "qbsmetatestmodule" } + } + } + +} diff --git a/tests/auto/blackbox/testdata-qt/auto-qrc/auto-qrc.qbs b/tests/auto/blackbox/testdata-qt/auto-qrc/auto-qrc.qbs index e08f89032..bdbf8b2a1 100644 --- a/tests/auto/blackbox/testdata-qt/auto-qrc/auto-qrc.qbs +++ b/tests/auto/blackbox/testdata-qt/auto-qrc/auto-qrc.qbs @@ -1,5 +1,14 @@ +import qbs.Host + Project { QtApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } + name: "app" files: ["main.cpp"] diff --git a/tests/auto/blackbox/testdata-qt/dbus-adaptors/car.cpp b/tests/auto/blackbox/testdata-qt/dbus-adaptors/car.cpp index 5e4f348d2..ce1d33ed6 100644 --- a/tests/auto/blackbox/testdata-qt/dbus-adaptors/car.cpp +++ b/tests/auto/blackbox/testdata-qt/dbus-adaptors/car.cpp @@ -49,7 +49,9 @@ ****************************************************************************/ #include "car.h" -#include <QtWidgets/QtWidgets> + +#include <QtGui/QPainter> + #include <math.h> static const double Pi = 3.14159265358979323846264338327950288419717; diff --git a/tests/auto/blackbox/testdata-qt/dbus-adaptors/main.cpp b/tests/auto/blackbox/testdata-qt/dbus-adaptors/main.cpp index 0491719d7..197005215 100644 --- a/tests/auto/blackbox/testdata-qt/dbus-adaptors/main.cpp +++ b/tests/auto/blackbox/testdata-qt/dbus-adaptors/main.cpp @@ -50,9 +50,15 @@ #include "car.h" #include "car_adaptor.h" +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include <QtWidgets/QApplication> #include <QtWidgets/QGraphicsView> #include <QtWidgets/QGraphicsScene> +#else +#include <QApplication> +#include <QGraphicsView> +#include <QGraphicsScene> +#endif #include <QtDBus/QDBusConnection> int main(int argc, char *argv[]) diff --git a/tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.cpp b/tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.cpp index eaff5c775..0f7a77efa 100644 --- a/tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.cpp +++ b/tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.cpp @@ -48,7 +48,8 @@ ** ****************************************************************************/ -#include <QtWidgets> +#include <QtGlobal> +#include <QtDBus/QDBusConnection> #include "controller.h" #include "car_interface.h" diff --git a/tests/auto/blackbox/testdata-qt/dbus-interfaces/main.cpp b/tests/auto/blackbox/testdata-qt/dbus-interfaces/main.cpp index fdd9fc590..c4e6ee485 100644 --- a/tests/auto/blackbox/testdata-qt/dbus-interfaces/main.cpp +++ b/tests/auto/blackbox/testdata-qt/dbus-interfaces/main.cpp @@ -48,7 +48,12 @@ ** ****************************************************************************/ -#include <QtWidgets> +#include <QtGlobal> +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include <QtWidgets/QApplication> +#else +#include <QtGui/QApplication>> +#endif #include <QtDBus> #include "controller.h" diff --git a/tests/auto/blackbox/testdata-qt/forced-moc/forced-moc.qbs b/tests/auto/blackbox/testdata-qt/forced-moc/forced-moc.qbs index a59aaa28e..064470a79 100644 --- a/tests/auto/blackbox/testdata-qt/forced-moc/forced-moc.qbs +++ b/tests/auto/blackbox/testdata-qt/forced-moc/forced-moc.qbs @@ -1,4 +1,17 @@ +import qbs.Host +import qbs.Utilities + QtApplication { + condition: { + if (Utilities.versionCompare(Qt.core.version, "5.0") < 0) { + console.info("using qt4"); + return false; + } + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } files: "main.cpp" Group { name: "QObject service provider" diff --git a/tests/auto/blackbox/testdata-qt/included-moc-cpp/included-moc-cpp.qbs b/tests/auto/blackbox/testdata-qt/included-moc-cpp/included-moc-cpp.qbs index 1ed85ccdd..265b0c9e3 100644 --- a/tests/auto/blackbox/testdata-qt/included-moc-cpp/included-moc-cpp.qbs +++ b/tests/auto/blackbox/testdata-qt/included-moc-cpp/included-moc-cpp.qbs @@ -1,6 +1,13 @@ -import qbs +import qbs.Utilities QtApplication { + condition: { + if (Utilities.versionCompare(Qt.core.version, "5.0") < 0) { + console.info("using qt4"); + return false; + } + return true; + } files: [ "main.cpp", "myobject.cpp", diff --git a/tests/auto/blackbox/testdata-qt/linker-variant/qt-linker-variant.qbs b/tests/auto/blackbox/testdata-qt/linker-variant/qt-linker-variant.qbs index ab5889007..c1a77d696 100644 --- a/tests/auto/blackbox/testdata-qt/linker-variant/qt-linker-variant.qbs +++ b/tests/auto/blackbox/testdata-qt/linker-variant/qt-linker-variant.qbs @@ -3,7 +3,7 @@ QtApplication { id: qtConfigProbe property stringList moduleConfig: Qt.core.moduleConfig configure: { - console.info("Qt requires gold: " + moduleConfig.contains("use_gold_linker")); + console.info("Qt requires gold: " + moduleConfig.includes("use_gold_linker")); } } files: "main.cpp" diff --git a/tests/auto/blackbox/testdata-qt/metatypes/metatypes.qbs b/tests/auto/blackbox/testdata-qt/metatypes/metatypes.qbs new file mode 100644 index 000000000..bbc98c934 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/metatypes/metatypes.qbs @@ -0,0 +1,28 @@ +import qbs.Utilities + +StaticLibrary { + name: "mylib" + + Depends { name: "Qt.core" } + + qbs.installPrefix: "some-prefix" + + Probe { + id: capabilitiesChecker + property string version: Qt.core.version + configure: { + if (Utilities.versionCompare(version, "5.15") >= 0) + console.info("can generate"); + else + console.info("cannot generate"); + found = true; + } + } + + files: [ + "mocableclass1.cpp", + "mocableclass1.h", + "mocableclass2.cpp", + "unmocableclass.cpp", + ] +} diff --git a/tests/auto/blackbox/testdata-qt/metatypes/mocableclass1.cpp b/tests/auto/blackbox/testdata-qt/metatypes/mocableclass1.cpp new file mode 100644 index 000000000..06adc8ca5 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/metatypes/mocableclass1.cpp @@ -0,0 +1,3 @@ +#include "mocableclass1.h" + +MocableClass1::MocableClass1(QObject *parent) : QObject(parent) {} diff --git a/tests/auto/blackbox/testdata-qt/metatypes/mocableclass1.h b/tests/auto/blackbox/testdata-qt/metatypes/mocableclass1.h new file mode 100644 index 000000000..020c15179 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/metatypes/mocableclass1.h @@ -0,0 +1,8 @@ +#include <QObject> + +class MocableClass1 : public QObject +{ + Q_OBJECT +public: + MocableClass1(QObject *parent = nullptr); +}; diff --git a/tests/auto/blackbox/testdata-qt/metatypes/mocableclass2.cpp b/tests/auto/blackbox/testdata-qt/metatypes/mocableclass2.cpp new file mode 100644 index 000000000..bf538913a --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/metatypes/mocableclass2.cpp @@ -0,0 +1,10 @@ +#include <QObject> + +class MocableClass2 : public QObject +{ + Q_OBJECT +public: + MocableClass2(QObject *parent) : QObject(parent) {} +}; + +#include <mocableclass2.moc> diff --git a/tests/auto/blackbox/testdata-qt/metatypes/unmocableclass.cpp b/tests/auto/blackbox/testdata-qt/metatypes/unmocableclass.cpp new file mode 100644 index 000000000..34330d189 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/metatypes/unmocableclass.cpp @@ -0,0 +1,7 @@ +#include <QObject> + +class UnmocableClass : public QObject +{ +public: + UnmocableClass(QObject *parent) : QObject(parent) {} +}; diff --git a/tests/auto/blackbox/testdata-qt/mixed-build-variants/mixed-build-variants.qbs b/tests/auto/blackbox/testdata-qt/mixed-build-variants/mixed-build-variants.qbs index 7d8ab1b90..dea30eef4 100644 --- a/tests/auto/blackbox/testdata-qt/mixed-build-variants/mixed-build-variants.qbs +++ b/tests/auto/blackbox/testdata-qt/mixed-build-variants/mixed-build-variants.qbs @@ -1,6 +1,6 @@ QtApplication { Properties { - condition: qbs.toolchain.contains("msvc") + condition: qbs.toolchain.includes("msvc") Qt.core.qtBuildVariant: "release" } Qt.core.qtBuildVariant: "dummy" diff --git a/tests/auto/blackbox/testdata-qt/moc-compiler-defines/main.cpp b/tests/auto/blackbox/testdata-qt/moc-compiler-defines/main.cpp new file mode 100644 index 000000000..d3b8f310e --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/moc-compiler-defines/main.cpp @@ -0,0 +1,7 @@ +#include "object.h" + +int main() +{ + QObject o; + return 0; +} diff --git a/tests/auto/blackbox/testdata-qt/moc-compiler-defines/moc-compiler-defines.qbs b/tests/auto/blackbox/testdata-qt/moc-compiler-defines/moc-compiler-defines.qbs new file mode 100644 index 000000000..e184f554e --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/moc-compiler-defines/moc-compiler-defines.qbs @@ -0,0 +1,3 @@ +QtApplication { + files: ["main.cpp", "object.h", "object.cpp"] +} diff --git a/tests/auto/blackbox/testdata-qt/moc-compiler-defines/object.cpp b/tests/auto/blackbox/testdata-qt/moc-compiler-defines/object.cpp new file mode 100644 index 000000000..7ffcf419b --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/moc-compiler-defines/object.cpp @@ -0,0 +1,6 @@ +#include "object.h" + +Object::Object(QObject *parent) : QObject(parent) +{ + +} diff --git a/tests/auto/blackbox/testdata-qt/moc-compiler-defines/object.h b/tests/auto/blackbox/testdata-qt/moc-compiler-defines/object.h new file mode 100644 index 000000000..3221d1173 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/moc-compiler-defines/object.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef OBJECT_H +#define OBJECT_H + +#include <QtCore/QObject> + +// These were not defined during the moc run (QBS-1592). +// Do not use Q_OS_UNIX here as it is a fallback value which is defined when nothing else is. +#if defined(Q_OS_DARWIN) || defined(Q_OS_LINUX) || defined(Q_OS_WIN) + +class Object : public QObject +{ + Q_OBJECT +public: + explicit Object(QObject *parent = nullptr); +}; + +#endif + +#endif // OBJECT_H diff --git a/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/lib.cpp b/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/lib.cpp new file mode 100644 index 000000000..675960f2d --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/lib.cpp @@ -0,0 +1,8 @@ +#include <QtDebug> + +#include "lib.h" + +SymbolsTest::SymbolsTest() +{ + // qDebug() << "hallo"; +} diff --git a/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/lib.h b/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/lib.h new file mode 100644 index 000000000..0cb4a23c4 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/lib.h @@ -0,0 +1,18 @@ +#ifndef SYMBOLSTEST_H +#define SYMBOLSTEST_H + +#include <QtCore/qglobal.h> + +#if defined(SYMBOLSTEST_LIBRARY) +# define SYMBOLSTEST_EXPORT Q_DECL_EXPORT +#else +# define SYMBOLSTEST_EXPORT Q_DECL_IMPORT +#endif + +class SYMBOLSTEST_EXPORT SymbolsTest +{ + public: + SymbolsTest(); +}; + +#endif // SYMBOLSTEST_H diff --git a/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/main.cpp b/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/main.cpp new file mode 100644 index 000000000..5047a34e3 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/main.cpp @@ -0,0 +1,3 @@ +int main() +{ +} diff --git a/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/symbols-test.qbs b/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/symbols-test.qbs new file mode 100644 index 000000000..a614d96c4 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/symbols-test.qbs @@ -0,0 +1,27 @@ +Project { + CppApplication { + name: "app" + Depends { name: "lib" } + property bool dummy: { + console.info("is GCC: " + qbs.toolchain.includes("gcc")); + console.info("is MinGW: " + qbs.toolchain.includes("mingw")); + console.info("is Darwin: " + qbs.targetOS.includes("darwin")); + } + files: "main.cpp" + } + + DynamicLibrary { + name: "lib" + Depends { name: "Qt.core" } + + cpp.cxxLanguageVersion: "c++11" + cpp.defines: "SYMBOLSTEST_LIBRARY" + + files: [ + "lib.cpp", + "lib.h", + ] + + Export { Depends { name: "Qt.core" } } + } +} diff --git a/tests/auto/blackbox/testdata-qt/pkgconfig-qt/dump-libpath.qbs b/tests/auto/blackbox/testdata-qt/pkgconfig-qt/dump-libpath.qbs new file mode 100644 index 000000000..9aa1c5d17 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/pkgconfig-qt/dump-libpath.qbs @@ -0,0 +1,6 @@ +QtApplication { + files: "main.cpp" + property bool test: { + console.info("libPath="+Qt.core.libPath) + } +} diff --git a/tests/auto/blackbox/testdata-qt/pkgconfig-qt/main.cpp b/tests/auto/blackbox/testdata-qt/pkgconfig-qt/main.cpp new file mode 100644 index 000000000..237c8ce18 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/pkgconfig-qt/main.cpp @@ -0,0 +1 @@ +int main() {} diff --git a/tests/auto/blackbox/testdata-qt/pkgconfig-qt/module-providers/dummyProvider.qbs b/tests/auto/blackbox/testdata-qt/pkgconfig-qt/module-providers/dummyProvider.qbs new file mode 100644 index 000000000..6ed2ca82e --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/pkgconfig-qt/module-providers/dummyProvider.qbs @@ -0,0 +1,3 @@ +ModuleProvider { + relativeSearchPaths: "" +} diff --git a/tests/auto/blackbox/testdata-qt/pkgconfig-qt/pkgconfig-qt.qbs b/tests/auto/blackbox/testdata-qt/pkgconfig-qt/pkgconfig-qt.qbs new file mode 100644 index 000000000..a1d8d8974 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/pkgconfig-qt/pkgconfig-qt.qbs @@ -0,0 +1,6 @@ +QtApplication { + name: "p" + files: "main.cpp" + qbsSearchPaths: "." + qbsModuleProviders: "qbspkgconfig" +} diff --git a/tests/auto/blackbox/testdata-qt/pkgconfig/pkgconfig.qbs b/tests/auto/blackbox/testdata-qt/pkgconfig/pkgconfig.qbs index 04b0097ef..b2d411154 100644 --- a/tests/auto/blackbox/testdata-qt/pkgconfig/pkgconfig.qbs +++ b/tests/auto/blackbox/testdata-qt/pkgconfig/pkgconfig.qbs @@ -1,8 +1,15 @@ +import qbs.Host import qbs.Probes Project { property string name: 'pkgconfig' CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: project.name Probes.PkgConfigProbe { id: pkgConfig diff --git a/tests/auto/blackbox/testdata-qt/plugin-meta-data/plugin-meta-data.qbs b/tests/auto/blackbox/testdata-qt/plugin-meta-data/plugin-meta-data.qbs index f018b34e0..dbe64d5ea 100644 --- a/tests/auto/blackbox/testdata-qt/plugin-meta-data/plugin-meta-data.qbs +++ b/tests/auto/blackbox/testdata-qt/plugin-meta-data/plugin-meta-data.qbs @@ -1,5 +1,20 @@ +import qbs.Host +import qbs.Utilities + Project { QtApplication { + condition: { + if (Utilities.versionCompare(Qt.core.version, "5.0") < 0) { + // qt4 moc can't be used with pluginMetaData + console.info("using qt4"); + return false; + } + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } + name: "app" consoleApplication: true @@ -8,7 +23,7 @@ Project { cpp.cxxLanguageVersion: "c++11" Properties { - condition: qbs.targetOS.contains("unix") + condition: qbs.targetOS.includes("unix") cpp.rpaths: [cpp.rpathOrigin] } @@ -28,12 +43,12 @@ Project { Depends { name: "Qt.core" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } cpp.defines: [Qt.core.staticBuild ? "QT_STATICPLUGIN" : "QT_PLUGIN"] cpp.cxxLanguageVersion: "c++11" - cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined + cpp.sonamePrefix: qbs.targetOS.includes("darwin") ? "@rpath" : undefined cpp.includePaths: ["."] Qt.core.pluginMetaData: ["theKey=theValue"] diff --git a/tests/auto/blackbox/testdata-qt/plugin-support/plugin-support.qbs b/tests/auto/blackbox/testdata-qt/plugin-support/plugin-support.qbs index c554a7dc2..8e0923e94 100644 --- a/tests/auto/blackbox/testdata-qt/plugin-support/plugin-support.qbs +++ b/tests/auto/blackbox/testdata-qt/plugin-support/plugin-support.qbs @@ -1,4 +1,14 @@ +import qbs.Utilities + QtGuiApplication { + condition: { + // pluginTypes empty for Qt4 + if (Utilities.versionCompare(Qt.core.version, "5.0") < 0) { + console.info("using qt4"); + return false; + } + return true; + } Probe { id: staticProbe property bool isStaticQt: Qt.gui.isStaticLibrary diff --git a/tests/auto/blackbox/testdata-qt/qdoc/qdoc.qbs b/tests/auto/blackbox/testdata-qt/qdoc/qdoc.qbs new file mode 100644 index 000000000..4b82bc405 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/qdoc/qdoc.qbs @@ -0,0 +1,22 @@ +import qbs.Utilities + +Product { + condition: { + var ok = Utilities.versionCompare(Qt.core.version, "5.0.0") >= 0; + if (!ok) + console.info("Qt is too old"); + return ok; + } + name: "QDoc Test" + type: ["qdoc-html", "qch"] + + Depends { name: "Qt.core" } + + files: ["qdoc.qdoc"] + + Group { + name: "main qdocconf file" + files: "qdoc.qdocconf" + fileTags: "qdocconf-main" + } +} diff --git a/tests/auto/blackbox/testdata-qt/qdoc/qdoc.qdoc b/tests/auto/blackbox/testdata-qt/qdoc/qdoc.qdoc new file mode 100644 index 000000000..9e44e0948 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/qdoc/qdoc.qdoc @@ -0,0 +1,7 @@ +/*! + \page index.html + + \title QDoc Test + + QDoc Test is a test for QDoc. +*/
\ No newline at end of file diff --git a/tests/auto/blackbox/testdata-qt/qdoc/qdoc.qdocconf b/tests/auto/blackbox/testdata-qt/qdoc/qdoc.qdocconf new file mode 100644 index 000000000..8c82bb575 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/qdoc/qdoc.qdocconf @@ -0,0 +1,13 @@ +project = QDoc Test +description = QDoc Test + +headerdirs = . +sourcedirs = . +exampledirs = . + +outputdir = doc/html + +qhp.projects = QDocTest +qhp.QDocTest.file = qdoctest.qhp +qhp.QDocTest.namespace = org.qt-project.QDocTest +qhp.QDocTest.virtualFolder = doc diff --git a/tests/auto/blackbox/testdata-qt/qml-debugging/qml-debugging.qbs b/tests/auto/blackbox/testdata-qt/qml-debugging/qml-debugging.qbs index 8176a7c3e..0885e6b0b 100644 --- a/tests/auto/blackbox/testdata-qt/qml-debugging/qml-debugging.qbs +++ b/tests/auto/blackbox/testdata-qt/qml-debugging/qml-debugging.qbs @@ -4,4 +4,9 @@ QtApplication { Depends { name: "Qt.quick" } Qt.quick.qmlDebugging: true files: "main.cpp" + Probe { + id: checker + property bool isGcc: qbs.toolchain.contains("gcc") + configure: { console.info("is gcc: " + isGcc); } + } } diff --git a/tests/auto/blackbox/testdata-qt/qmltyperegistrar/example.qml b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/example.qml new file mode 100644 index 000000000..ef97df12d --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/example.qml @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// ![0] +import People 1.0 + +Person { + name: "Bob Jones" + shoeSize: 12 +} +// ![0] diff --git a/tests/auto/blackbox/testdata-qt/qmltyperegistrar/main.cpp b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/main.cpp new file mode 100644 index 000000000..6c3920f04 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/main.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QCoreApplication> +#include <QQmlEngine> +#include <QQmlComponent> +#include <QDebug> +#include "person.h" + +int main(int argc, char ** argv) +{ + QCoreApplication app(argc, argv); + + QQmlEngine engine; + QQmlComponent component(&engine, QUrl("qrc:example.qml")); + auto *person = qobject_cast<Person *>(component.create()); + if (person) { + qWarning() << "The person's name is" << person->name(); + qWarning() << "They wear a" << person->shoeSize() << "sized shoe"; + } else { + qWarning() << component.errors(); + } + + return EXIT_SUCCESS; +} diff --git a/tests/auto/blackbox/testdata-qt/qmltyperegistrar/person.cpp b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/person.cpp new file mode 100644 index 000000000..de4a33dd0 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/person.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "person.h" + +// ![0] +Person::Person(QObject *parent) +: QObject(parent), m_shoeSize(0) +{ +} + +QString Person::name() const +{ + return m_name; +} + +void Person::setName(const QString &n) +{ + m_name = n; +} + +int Person::shoeSize() const +{ + return m_shoeSize; +} + +void Person::setShoeSize(int s) +{ + m_shoeSize = s; +} + +// ![0] diff --git a/tests/auto/blackbox/testdata-qt/qmltyperegistrar/person.h b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/person.h new file mode 100644 index 000000000..530c335de --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/person.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef PERSON_H +#define PERSON_H + +#include <QObject> +#include <QtQml/qqml.h> + +//![0] +class Person : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString name READ name WRITE setName) + Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize) + QML_ELEMENT +public: + Person(QObject *parent = nullptr); + + QString name() const; + void setName(const QString &); + + int shoeSize() const; + void setShoeSize(int); + +private: + QString m_name; + int m_shoeSize; +}; +//![0] + +#endif // PERSON_H diff --git a/tests/auto/blackbox/testdata-qt/qmltyperegistrar/qmltyperegistrar.qbs b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/qmltyperegistrar.qbs new file mode 100644 index 000000000..68dc83743 --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/qmltyperegistrar.qbs @@ -0,0 +1,33 @@ +import qbs.Utilities + +CppApplication { + name: "myapp" + Depends { name: "Qt.qml" } + + Qt.qml.importVersion: "1" + cpp.includePaths: sourceDirectory + qbs.installPrefix: "" + + files: [ + "main.cpp", + "person.cpp", + "person.h", + ] + + Group { + files: "example.qml" + fileTags: "qt.core.resource_data" + } + + Probe { + id: versionProbe + property string version: Qt.core.version + configure: { + if (Utilities.versionCompare(version, "5.15") >= 0) + console.info("has registrar"); + else + console.info("does not have registrar"); + found = true; + } + } +} diff --git a/tests/auto/blackbox/testdata-qt/qrc/i.qbs b/tests/auto/blackbox/testdata-qt/qrc/i.qbs index c005490c4..45275106d 100644 --- a/tests/auto/blackbox/testdata-qt/qrc/i.qbs +++ b/tests/auto/blackbox/testdata-qt/qrc/i.qbs @@ -1,5 +1,18 @@ +import qbs.Host +import qbs.Utilities + Project { Product { + condition: { + if (Utilities.versionCompare(Qt.core.version, "5.0") < 0) { + console.info("using qt4"); + return false; + } + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } consoleApplication: true type: "application" name: "i" diff --git a/tests/auto/blackbox/testdata-qt/qtscxml/qtscxml.qbs b/tests/auto/blackbox/testdata-qt/qtscxml/qtscxml.qbs index 991e4ddcb..6fee91479 100644 --- a/tests/auto/blackbox/testdata-qt/qtscxml/qtscxml.qbs +++ b/tests/auto/blackbox/testdata-qt/qtscxml/qtscxml.qbs @@ -1,5 +1,6 @@ import qbs.Environment import qbs.FileInfo +import qbs.Host import qbs.Utilities Project { @@ -24,6 +25,12 @@ Project { } Product { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: "runner" type: ["runner"] Depends { name: "app" } @@ -33,18 +40,22 @@ Project { prepare: { var cmd = new Command(input.filePath); cmd.description = "running " + input.filePath; - var pathVar; - var pathValue; - if (product.qbs.hostOS.contains("windows")) { - pathVar = "PATH"; - pathValue = FileInfo.toWindowsSeparators(input["Qt.core"].binPath); + + var envVars = {}; + if (Host.os().includes("windows")) { + envVars["PATH"] = FileInfo.toWindowsSeparators(input["Qt.core"].binPath); + } else if (Host.os().includes("macos")) { + envVars["DYLD_LIBRARY_PATH"] = input["Qt.core"].libPath; + envVars["DYLD_FRAMEWORK_PATH"] = input["Qt.core"].libPath; } else { - pathVar = "LD_LIBRARY_PATH"; - pathValue = input["Qt.core"].libPath; + envVars["LD_LIBRARY_PATH"] = input["Qt.core"].libPath; } - var oldValue = Environment.getEnv(pathVar) || ""; - var newValue = pathValue + product.qbs.pathListSeparator + oldValue; - cmd.environment = [pathVar + '=' + newValue]; + for (var varName in envVars) { + var oldValue = Environment.getEnv(varName) || ""; + var newValue = envVars[varName] + FileInfo.pathListSeparator() + oldValue; + cmd.environment.push(varName + '=' + newValue); + } + return [cmd]; } } diff --git a/tests/auto/blackbox/testdata-qt/quick-compiler/quick-compiler.qbs b/tests/auto/blackbox/testdata-qt/quick-compiler/quick-compiler.qbs index b141c8672..793d261e9 100644 --- a/tests/auto/blackbox/testdata-qt/quick-compiler/quick-compiler.qbs +++ b/tests/auto/blackbox/testdata-qt/quick-compiler/quick-compiler.qbs @@ -1,5 +1,9 @@ CppApplication { - Depends { name: "Qt.quick" } + Depends { + name: "Qt.quick" + // Must fail when using Qt4 + versionAtLeast: "5" + } Qt.quick.useCompiler: Qt.quick.compilerAvailable cpp.cxxLanguageVersion: "c++11" diff --git a/tests/auto/blackbox/testdata-qt/static-qt-plugin-linking/lib.cpp b/tests/auto/blackbox/testdata-qt/static-qt-plugin-linking/lib.cpp new file mode 100644 index 000000000..dd79cbe6c --- /dev/null +++ b/tests/auto/blackbox/testdata-qt/static-qt-plugin-linking/lib.cpp @@ -0,0 +1 @@ +void function() {} diff --git a/tests/auto/blackbox/testdata-qt/static-qt-plugin-linking/static-qt-plugin-linking.qbs b/tests/auto/blackbox/testdata-qt/static-qt-plugin-linking/static-qt-plugin-linking.qbs index 745fe5527..e4e56bb4b 100644 --- a/tests/auto/blackbox/testdata-qt/static-qt-plugin-linking/static-qt-plugin-linking.qbs +++ b/tests/auto/blackbox/testdata-qt/static-qt-plugin-linking/static-qt-plugin-linking.qbs @@ -11,11 +11,16 @@ Product { } Group { - condition: type.contains("application") + condition: type.includes("application") files: "main.cpp" } + Group { + condition: type.includes("staticlibrary") + files: "lib.cpp" + } + Depends { name: "Qt.core" } Depends { name: "Qt.gui" } - Depends { name: "Qt.qminimal"; condition: Qt.core.staticBuild; } + Depends { name: "Qt.qminimal"; condition: Qt.core.staticBuild } } diff --git a/tests/auto/blackbox/testdata-windows/codesign/app.cpp b/tests/auto/blackbox/testdata-windows/codesign/app.cpp new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/blackbox/testdata-windows/codesign/app.cpp @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/blackbox/testdata-windows/codesign/codesign.qbs b/tests/auto/blackbox/testdata-windows/codesign/codesign.qbs new file mode 100644 index 000000000..1963f6926 --- /dev/null +++ b/tests/auto/blackbox/testdata-windows/codesign/codesign.qbs @@ -0,0 +1,43 @@ +Project { + name: "p" + + property bool enableSigning: true + property string hashAlgorithm + property string subjectName + property string signingTimestamp + + CppApplication { + name: "A" + files: "app.cpp" + condition: qbs.toolchain.includes("msvc") + codesign.enableCodeSigning: project.enableSigning + codesign.hashAlgorithm: project.hashAlgorithm + codesign.subjectName: project.subjectName + codesign.signingTimestamp: project.signingTimestamp + codesign.timestampAlgorithm: "sha256" + install: true + installDir: "" + property bool dummy: { + if (codesign.codesignPath) + console.info("signtool path: %%" + codesign.codesignPath + "%%"); + } + } + + DynamicLibrary { + Depends { name: "cpp" } + name: "B" + files: "app.cpp" + condition: qbs.toolchain.includes("msvc") + codesign.enableCodeSigning: project.enableSigning + codesign.hashAlgorithm: project.hashAlgorithm + codesign.subjectName: project.subjectName + codesign.signingTimestamp: project.signingTimestamp + codesign.timestampAlgorithm: "sha256" + install: true + installDir: "" + property bool dummy: { + if (codesign.codesignPath) + console.info("signtool path: %%" + codesign.codesignPath + "%%"); + } + } +} diff --git a/tests/auto/blackbox/testdata-windows/innosetup/inc/qbsinc.iss b/tests/auto/blackbox/testdata-windows/innosetup/inc/qbsinc.iss new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata-windows/innosetup/inc/qbsinc.iss diff --git a/tests/auto/blackbox/testdata/innosetup/innosetup.qbs b/tests/auto/blackbox/testdata-windows/innosetup/innosetup.qbs index c9f6a22e8..fd8868900 100644 --- a/tests/auto/blackbox/testdata/innosetup/innosetup.qbs +++ b/tests/auto/blackbox/testdata-windows/innosetup/innosetup.qbs @@ -2,6 +2,11 @@ import qbs.FileInfo Project { InnoSetup { + property bool _test: { + var present = qbs.targetOS.includes("windows") && innosetup.present; + console.info("has innosetup: " + present); + } + name: "QbsSetup" targetName: "qbs.setup.test" version: "1.5" @@ -12,11 +17,9 @@ Project { innosetup.includePaths: ["inc"] innosetup.defines: ["MyProgram=" + name, "MyProgramVersion=" + version] innosetup.compilerFlags: ["/V9"] - qbs.targetPlatform: "windows" } InnoSetup { name: "Example1" files: [FileInfo.joinPaths(innosetup.toolchainInstallPath, "Examples", name + ".iss")] - qbs.targetPlatform: "windows" } } diff --git a/tests/auto/blackbox/testdata/innosetup/test.iss b/tests/auto/blackbox/testdata-windows/innosetup/test.iss index f9f9195a6..f9f9195a6 100644 --- a/tests/auto/blackbox/testdata/innosetup/test.iss +++ b/tests/auto/blackbox/testdata-windows/innosetup/test.iss diff --git a/tests/auto/blackbox/testdata/innosetupDependencies/innosetupDependencies.qbs b/tests/auto/blackbox/testdata-windows/innosetupDependencies/innosetupDependencies.qbs index db65e127f..3ef8c30e7 100644 --- a/tests/auto/blackbox/testdata/innosetupDependencies/innosetupDependencies.qbs +++ b/tests/auto/blackbox/testdata-windows/innosetupDependencies/innosetupDependencies.qbs @@ -2,6 +2,10 @@ import qbs.TextFile Project { InnoSetup { + property bool _test: { + var present = qbs.targetOS.includes("windows") && innosetup.present; + console.info("has innosetup: " + present); + } Depends { name: "app" } Depends { name: "lib" } name: "QbsSetup" diff --git a/tests/auto/blackbox/testdata-windows/innosetupDependencies/main.c b/tests/auto/blackbox/testdata-windows/innosetupDependencies/main.c new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/blackbox/testdata-windows/innosetupDependencies/main.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/blackbox/testdata/innosetupDependencies/test.iss b/tests/auto/blackbox/testdata-windows/innosetupDependencies/test.iss index 430f9941b..430f9941b 100644 --- a/tests/auto/blackbox/testdata/innosetupDependencies/test.iss +++ b/tests/auto/blackbox/testdata-windows/innosetupDependencies/test.iss diff --git a/tests/auto/blackbox/testdata/wix/ExampleScript.bat b/tests/auto/blackbox/testdata-windows/wix/ExampleScript.bat index 3af583cd8..3af583cd8 100644 --- a/tests/auto/blackbox/testdata/wix/ExampleScript.bat +++ b/tests/auto/blackbox/testdata-windows/wix/ExampleScript.bat diff --git a/tests/auto/blackbox/testdata/wix/QbsBootstrapper.wxs b/tests/auto/blackbox/testdata-windows/wix/QbsBootstrapper.wxs index 272f6af5b..272f6af5b 100644 --- a/tests/auto/blackbox/testdata/wix/QbsBootstrapper.wxs +++ b/tests/auto/blackbox/testdata-windows/wix/QbsBootstrapper.wxs diff --git a/tests/auto/blackbox/testdata/wix/QbsSetup.wxs b/tests/auto/blackbox/testdata-windows/wix/QbsSetup.wxs index 8f97ff667..8f97ff667 100644 --- a/tests/auto/blackbox/testdata/wix/QbsSetup.wxs +++ b/tests/auto/blackbox/testdata-windows/wix/QbsSetup.wxs diff --git a/tests/auto/blackbox/testdata/wix/Qt.wxs b/tests/auto/blackbox/testdata-windows/wix/Qt.wxs index fbd992c43..fbd992c43 100644 --- a/tests/auto/blackbox/testdata/wix/Qt.wxs +++ b/tests/auto/blackbox/testdata-windows/wix/Qt.wxs diff --git a/tests/auto/blackbox/testdata/wix/WiXInstallers.qbs b/tests/auto/blackbox/testdata-windows/wix/WiXInstallers.qbs index 07f61ba2c..acc7cf7b3 100644 --- a/tests/auto/blackbox/testdata/wix/WiXInstallers.qbs +++ b/tests/auto/blackbox/testdata-windows/wix/WiXInstallers.qbs @@ -1,4 +1,5 @@ import qbs.FileInfo +import qbs.Host Project { WindowsInstallerPackage { @@ -12,14 +13,14 @@ Project { Export { Depends { name: "wix" } wix.defines: base.concat(["msiName=" + - FileInfo.joinPaths(product.buildDirectory, - product.targetName + wix.windowsInstallerSuffix)]) + FileInfo.joinPaths(exportingProduct.buildDirectory, + exportingProduct.targetName + wix.windowsInstallerSuffix)]) } } WindowsSetupPackage { Depends { name: "QbsSetup" } - condition: qbs.hostOS.contains("windows") // currently does not work in Wine with WiX 3.9 + condition: Host.os().includes("windows") // currently does not work in Wine with WiX 3.9 name: "QbsBootstrapper" targetName: "qbs-setup-" + qbs.architecture files: ["QbsBootstrapper.wxs"] diff --git a/tests/auto/blackbox/testdata/wix/de.wxl b/tests/auto/blackbox/testdata-windows/wix/de.wxl index 75394cfdd..75394cfdd 100644 --- a/tests/auto/blackbox/testdata/wix/de.wxl +++ b/tests/auto/blackbox/testdata-windows/wix/de.wxl diff --git a/tests/auto/blackbox/testdata/wixDependencies/QbsSetup.wxs b/tests/auto/blackbox/testdata-windows/wixDependencies/QbsSetup.wxs index ec839a269..ec839a269 100644 --- a/tests/auto/blackbox/testdata/wixDependencies/QbsSetup.wxs +++ b/tests/auto/blackbox/testdata-windows/wixDependencies/QbsSetup.wxs diff --git a/tests/auto/blackbox/testdata-windows/wixDependencies/main.c b/tests/auto/blackbox/testdata-windows/wixDependencies/main.c new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/blackbox/testdata-windows/wixDependencies/main.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/blackbox/testdata/wixDependencies/wixDependencies.qbs b/tests/auto/blackbox/testdata-windows/wixDependencies/wixDependencies.qbs index d42a18054..d42a18054 100644 --- a/tests/auto/blackbox/testdata/wixDependencies/wixDependencies.qbs +++ b/tests/auto/blackbox/testdata-windows/wixDependencies/wixDependencies.qbs diff --git a/tests/auto/blackbox/testdata/allowed-values/allowed-values.qbs b/tests/auto/blackbox/testdata/allowed-values/allowed-values.qbs new file mode 100644 index 000000000..699713770 --- /dev/null +++ b/tests/auto/blackbox/testdata/allowed-values/allowed-values.qbs @@ -0,0 +1,19 @@ +Product { + Depends { name: "a" } + // tests VariantValue + property string prop + PropertyOptions { + name: "prop" + description: "Some prop" + allowedValues: "foo" + } + // tests JSValue + property string prop2 // setter for otherProp + property string otherProp: prop2 + PropertyOptions { + name: "otherProp" + description: "Some other prop" + allowedValues: "foo" + } + name: "p" +} diff --git a/tests/auto/blackbox/testdata/allowed-values/modules/a/a.qbs b/tests/auto/blackbox/testdata/allowed-values/modules/a/a.qbs new file mode 100644 index 000000000..2bbcde525 --- /dev/null +++ b/tests/auto/blackbox/testdata/allowed-values/modules/a/a.qbs @@ -0,0 +1,18 @@ +Module { + // tests VariantValue + property stringList prop + PropertyOptions { + name: "prop" + description: "Some prop" + allowedValues: ["foo", "bar"] + } + // tests JSValue + property stringList prop2 // setter for otherProp + property stringList otherProp: prop2 + PropertyOptions { + name: "otherProp" + description: "Some other prop" + allowedValues: ["foo", "bar"] + } +} + diff --git a/tests/auto/blackbox/testdata/assembly/assembly.qbs b/tests/auto/blackbox/testdata/assembly/assembly.qbs index f7bd4ecad..9d5584af5 100644 --- a/tests/auto/blackbox/testdata/assembly/assembly.qbs +++ b/tests/auto/blackbox/testdata/assembly/assembly.qbs @@ -30,9 +30,9 @@ Project { name : "testa" files : [ "testa.s" ] Depends { name: "cpp" } - condition: qbs.toolchain.contains("gcc") + condition: qbs.toolchain.includes("gcc") Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } @@ -40,9 +40,9 @@ Project { name : "testb" files : [ "testb.S" ] Depends { name: "cpp" } - condition: qbs.toolchain.contains("gcc") + condition: qbs.toolchain.includes("gcc") Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } @@ -50,9 +50,9 @@ Project { name : "testc" files : [ "testc.sx" ] Depends { name: "cpp" } - condition: qbs.toolchain.contains("gcc") + condition: qbs.toolchain.includes("gcc") Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } @@ -63,10 +63,10 @@ Project { files: ["testd_" + qbs.architecture + ".asm"] } Depends { name: "cpp" } - condition: qbs.toolchain.contains("msvc") + condition: qbs.toolchain.includes("msvc") && (qbs.architecture === "x86" || qbs.architecture === "x86_64") Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } diff --git a/tests/auto/blackbox/testdata/autotest-timeout/autotests-timeout.qbs b/tests/auto/blackbox/testdata/autotest-timeout/autotests-timeout.qbs index 49ee35d3a..b6094ed22 100644 --- a/tests/auto/blackbox/testdata/autotest-timeout/autotests-timeout.qbs +++ b/tests/auto/blackbox/testdata/autotest-timeout/autotests-timeout.qbs @@ -1,12 +1,20 @@ +import qbs.Host + Project { CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: "testApp" type: ["application", "autotest"] Depends { name: "autotest" } cpp.cxxLanguageVersion: "c++11" cpp.minimumOsxVersion: "10.8" // For <chrono> Properties { - condition: qbs.toolchain.contains("gcc") + condition: qbs.toolchain.includes("gcc") cpp.driverFlags: "-pthread" } files: "test-main.cpp" @@ -14,7 +22,7 @@ Project { AutotestRunner { Depends { name: "cpp" // Make sure build environment is set up properly. - condition: qbs.hostOS.contains("windows") && qbs.toolchain.contains("gcc") + condition: Host.os().includes("windows") && qbs.toolchain.includes("gcc") } } } diff --git a/tests/auto/blackbox/testdata/autotest-with-dependencies/autotest-with-dependencies.qbs b/tests/auto/blackbox/testdata/autotest-with-dependencies/autotest-with-dependencies.qbs index 7ae6cef73..bea74796a 100644 --- a/tests/auto/blackbox/testdata/autotest-with-dependencies/autotest-with-dependencies.qbs +++ b/tests/auto/blackbox/testdata/autotest-with-dependencies/autotest-with-dependencies.qbs @@ -1,7 +1,14 @@ import qbs.FileInfo +import qbs.Host Project { CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: "helper-app" type: ["application", "test-helper"] consoleApplication: true @@ -23,7 +30,7 @@ Project { AutotestRunner { Depends { name: "cpp" // Make sure build environment is set up properly. - condition: qbs.hostOS.contains("windows") && qbs.toolchain.contains("gcc") + condition: Host.os().includes("windows") && qbs.toolchain.includes("gcc") } arguments: FileInfo.joinPaths(qbs.installRoot, qbs.installPrefix, "bin") auxiliaryInputs: "test-helper" diff --git a/tests/auto/blackbox/testdata/autotests/autotests.qbs b/tests/auto/blackbox/testdata/autotests/autotests.qbs index 10334156e..cfb7fc560 100644 --- a/tests/auto/blackbox/testdata/autotests/autotests.qbs +++ b/tests/auto/blackbox/testdata/autotests/autotests.qbs @@ -1,9 +1,17 @@ +import qbs.Host + Project { references: ["test1", "test2", "test3"] AutotestRunner { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } Depends { name: "cpp" // Make sure build environment is set up properly. - condition: qbs.hostOS.contains("windows") && qbs.toolchain.contains("gcc") + condition: Host.os().includes("windows") && qbs.toolchain.includes("gcc") } } } diff --git a/tests/auto/blackbox/testdata/badInterpreter/badInterpreter.qbs b/tests/auto/blackbox/testdata/badInterpreter/badInterpreter.qbs index bef82a003..3c8f64c6c 100644 --- a/tests/auto/blackbox/testdata/badInterpreter/badInterpreter.qbs +++ b/tests/auto/blackbox/testdata/badInterpreter/badInterpreter.qbs @@ -1,4 +1,13 @@ +import qbs.Host + Project { + property bool enabled: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } + qbsSearchPaths: base.concat(["qbs"]) Product { diff --git a/tests/auto/blackbox/testdata/build-variant-defaults/build-variant-defaults.qbs b/tests/auto/blackbox/testdata/build-variant-defaults/build-variant-defaults.qbs new file mode 100644 index 000000000..4015817ca --- /dev/null +++ b/tests/auto/blackbox/testdata/build-variant-defaults/build-variant-defaults.qbs @@ -0,0 +1,16 @@ +CppApplication { + property bool validate: { + var valid = true; + if (qbs.buildVariant === "release") { + valid = !qbs.enableDebugCode && !qbs.debugInformation && qbs.optimization === "fast"; + } else if (qbs.buildVariant === "debug") { + valid = qbs.enableDebugCode && qbs.debugInformation && qbs.optimization === "none"; + } else if (qbs.buildVariant === "profiling") { + valid = !qbs.enableDebugCode && qbs.debugInformation && qbs.optimization === "fast"; + } + + if (!valid) + throw "Invalid defaults"; + return valid; + } +} diff --git a/tests/auto/blackbox/testdata/build-variant-defaults/main.cpp b/tests/auto/blackbox/testdata/build-variant-defaults/main.cpp new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/blackbox/testdata/build-variant-defaults/main.cpp @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/blackbox/testdata/buildenv-change/buildenv-change.qbs b/tests/auto/blackbox/testdata/buildenv-change/buildenv-change.qbs index 6c0bcc73e..54005e76a 100644 --- a/tests/auto/blackbox/testdata/buildenv-change/buildenv-change.qbs +++ b/tests/auto/blackbox/testdata/buildenv-change/buildenv-change.qbs @@ -3,7 +3,7 @@ CppApplication { id: dummy property stringList toolchain: qbs.toolchain configure: { - if (toolchain.contains("msvc")) + if (toolchain.includes("msvc")) console.info("msvc"); } } diff --git a/tests/auto/blackbox/testdata/capnproto/bar.capnp b/tests/auto/blackbox/testdata/capnproto/bar.capnp new file mode 100644 index 000000000..a0e8a0f8c --- /dev/null +++ b/tests/auto/blackbox/testdata/capnproto/bar.capnp @@ -0,0 +1,8 @@ +@0xc967c84bcca70a1d; + +using Foo = import "foo.capnp"; + +struct Bar { + foo @0 :Foo.Foo; + # Use type "Foo" defined in foo.capnp. +} diff --git a/tests/auto/blackbox/testdata/capnproto/baz.capnp b/tests/auto/blackbox/testdata/capnproto/baz.capnp new file mode 100644 index 000000000..8b2fe4faf --- /dev/null +++ b/tests/auto/blackbox/testdata/capnproto/baz.capnp @@ -0,0 +1,8 @@ +@0xc967c84bcca70a1d; + +using Foo = import "/imports/foo.capnp"; + +struct Baz { + foo @0 :Foo.Foo; + # Use type "Foo" defined in foo.capnp. +} diff --git a/tests/auto/blackbox/testdata/capnproto/capnproto_absolute_import.cpp b/tests/auto/blackbox/testdata/capnproto/capnproto_absolute_import.cpp new file mode 100644 index 000000000..0e8979eec --- /dev/null +++ b/tests/auto/blackbox/testdata/capnproto/capnproto_absolute_import.cpp @@ -0,0 +1,14 @@ +#include "baz.capnp.h" + +#include <capnp/message.h> + +int main() +{ + ::capnp::MallocMessageBuilder message; + + auto baz = message.initRoot<Baz>(); + auto foo = baz.initFoo(); + foo.setStr("hello"); + + return 0; +} diff --git a/tests/auto/blackbox/testdata/capnproto/capnproto_absolute_import.qbs b/tests/auto/blackbox/testdata/capnproto/capnproto_absolute_import.qbs new file mode 100644 index 000000000..4674d6a6a --- /dev/null +++ b/tests/auto/blackbox/testdata/capnproto/capnproto_absolute_import.qbs @@ -0,0 +1,21 @@ +import qbs.Host + +CppApplication { + Depends { name: "capnproto.cpp"; required: false } + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + if (!capnproto.cpp.present) + console.info("capnproto is not present"); + return result && capnproto.cpp.present; + } + cpp.minimumMacosVersion: "10.8" + capnproto.cpp.importPaths: "." + files: [ + "baz.capnp", + "capnproto_absolute_import.cpp", + "imports/foo.capnp", + ] + qbs.buildVariant: "release" +} diff --git a/tests/auto/blackbox/testdata/capnproto/capnproto_cpp.cpp b/tests/auto/blackbox/testdata/capnproto/capnproto_cpp.cpp new file mode 100644 index 000000000..b9f729955 --- /dev/null +++ b/tests/auto/blackbox/testdata/capnproto/capnproto_cpp.cpp @@ -0,0 +1,13 @@ +#include "foo.capnp.h" + +#include <capnp/message.h> + +int main() +{ + ::capnp::MallocMessageBuilder message; + + auto foo = message.initRoot<Foo>(); + foo.setStr("hello"); + + return 0; +} diff --git a/tests/auto/blackbox/testdata/capnproto/capnproto_cpp.qbs b/tests/auto/blackbox/testdata/capnproto/capnproto_cpp.qbs new file mode 100644 index 000000000..9f287e906 --- /dev/null +++ b/tests/auto/blackbox/testdata/capnproto/capnproto_cpp.qbs @@ -0,0 +1,19 @@ +import qbs.Host + +CppApplication { + Depends { name: "capnproto.cpp"; required: false } + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + if (!capnproto.cpp.present) + console.info("capnproto is not present"); + return result && capnproto.cpp.present; + } + cpp.minimumMacosVersion: "10.8" + files: [ + "capnproto_cpp.cpp", + "foo.capnp" + ] + qbs.buildVariant: "release" +} diff --git a/tests/auto/blackbox/testdata/capnproto/capnproto_relative_import.cpp b/tests/auto/blackbox/testdata/capnproto/capnproto_relative_import.cpp new file mode 100644 index 000000000..5116bd3d6 --- /dev/null +++ b/tests/auto/blackbox/testdata/capnproto/capnproto_relative_import.cpp @@ -0,0 +1,14 @@ +#include "bar.capnp.h" + +#include <capnp/message.h> + +int main() +{ + ::capnp::MallocMessageBuilder message; + + auto bar = message.initRoot<Bar>(); + auto foo = bar.initFoo(); + foo.setStr("hello"); + + return 0; +} diff --git a/tests/auto/blackbox/testdata/capnproto/capnproto_relative_import.qbs b/tests/auto/blackbox/testdata/capnproto/capnproto_relative_import.qbs new file mode 100644 index 000000000..333a3cdb9 --- /dev/null +++ b/tests/auto/blackbox/testdata/capnproto/capnproto_relative_import.qbs @@ -0,0 +1,19 @@ +import qbs.Host + +CppApplication { + Depends { name: "capnproto.cpp"; required: false } + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + if (!capnproto.cpp.present) + console.info("capnproto is not present"); + return result && capnproto.cpp.present; + } + cpp.minimumMacosVersion: "10.8" + files: [ + "bar.capnp", + "capnproto_relative_import.cpp", + "foo.capnp", + ] +} diff --git a/tests/auto/blackbox/testdata/capnproto/conanfile.txt b/tests/auto/blackbox/testdata/capnproto/conanfile.txt new file mode 100644 index 000000000..7313bb82e --- /dev/null +++ b/tests/auto/blackbox/testdata/capnproto/conanfile.txt @@ -0,0 +1,6 @@ +[requires] +capnproto/1.0.2 +[tool_requires] +capnproto/1.0.2 +[generators] +QbsDeps diff --git a/tests/auto/blackbox/testdata/capnproto/foo.capnp b/tests/auto/blackbox/testdata/capnproto/foo.capnp new file mode 100644 index 000000000..146a2969f --- /dev/null +++ b/tests/auto/blackbox/testdata/capnproto/foo.capnp @@ -0,0 +1,6 @@ +@0x8a2efe67220790be; + +struct Foo { + num @0 :UInt32; + str @1 :Text; +} diff --git a/tests/auto/blackbox/testdata/capnproto/greeter-client.cpp b/tests/auto/blackbox/testdata/capnproto/greeter-client.cpp new file mode 100644 index 000000000..d3fcdb4e3 --- /dev/null +++ b/tests/auto/blackbox/testdata/capnproto/greeter-client.cpp @@ -0,0 +1,25 @@ +#include "greeter.capnp.h" + +#include <capnp/ez-rpc.h> + +#include <iostream> + +int main(int argc, char *argv[]) +{ + const char address[] = "localhost:5050"; + capnp::EzRpcClient client(address); + Greeter::Client greeter = client.getMain<Greeter>(); + + auto& waitScope = client.getWaitScope(); + + for (int i = 0; i < 2; ++i) { + auto request = greeter.sayHelloRequest(); + request.initRequest().setName("hello workd"); + auto promise = request.send(); + + auto response = promise.wait(waitScope); + std::cout << response.getResponse().getName().cStr() << std::endl; + } + + return 0; +} diff --git a/tests/auto/blackbox/testdata/capnproto/greeter-server.cpp b/tests/auto/blackbox/testdata/capnproto/greeter-server.cpp new file mode 100644 index 000000000..a7f482cc8 --- /dev/null +++ b/tests/auto/blackbox/testdata/capnproto/greeter-server.cpp @@ -0,0 +1,27 @@ +#include "greeter.capnp.h" + +#include <capnp/ez-rpc.h> +#include <capnp/message.h> + +#include <iostream> + +class GreeterImpl final: public Greeter::Server +{ +public: + ::kj::Promise<void> sayHello(SayHelloContext context) override + { + auto response = context.getResults().initResponse(); + response.setName(context.getParams().getRequest().getName()); + return kj::READY_NOW; + }; +}; + +int main(int argc, char *argv[]) +{ + const char address[] = "localhost:5050"; + capnp::EzRpcServer server(kj::heap<GreeterImpl>(), address); + + auto& waitScope = server.getWaitScope(); + // Run forever, accepting connections and handling requests. + kj::NEVER_DONE.wait(waitScope); +} diff --git a/tests/auto/blackbox/testdata/capnproto/greeter.capnp b/tests/auto/blackbox/testdata/capnproto/greeter.capnp new file mode 100644 index 000000000..b9188f634 --- /dev/null +++ b/tests/auto/blackbox/testdata/capnproto/greeter.capnp @@ -0,0 +1,13 @@ +@0x85150b117366d14b; + +struct HelloRequest { + name @0 :Text; +} + +struct HelloResponse { + name @0 :Text; +} + +interface Greeter { + sayHello @0 (request: HelloRequest) -> (response: HelloResponse); +} diff --git a/tests/auto/blackbox/testdata/capnproto/greeter_cpp.qbs b/tests/auto/blackbox/testdata/capnproto/greeter_cpp.qbs new file mode 100644 index 000000000..5fc5464b1 --- /dev/null +++ b/tests/auto/blackbox/testdata/capnproto/greeter_cpp.qbs @@ -0,0 +1,39 @@ +import qbs.Host + +Project { + CppApplication { + Depends { name: "capnproto.cpp"; required: false } + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + if (!capnproto.cpp.present) + console.info("capnproto is not present"); + return result && capnproto.cpp.present; + } + name: "server" + consoleApplication: true + cpp.minimumMacosVersion: "10.8" + // workaround for broken capnproto + cpp.staticLibraries: qbs.targetOS.contains("windows") ? "Advapi32" : [] + capnproto.cpp.useRpc: true + files: [ + "greeter.capnp", + "greeter-server.cpp" + ] + qbs.buildVariant: "release" + } + CppApplication { + Depends { name: "capnproto.cpp"; required: false } + name: "client" + consoleApplication: true + capnproto.cpp.useRpc: true + cpp.minimumMacosVersion: "10.8" + cpp.staticLibraries: qbs.targetOS.contains("windows") ? "Advapi32" : [] + files: [ + "greeter.capnp", + "greeter-client.cpp" + ] + qbs.buildVariant: "release" + } +} diff --git a/tests/auto/blackbox/testdata/capnproto/imports/foo.capnp b/tests/auto/blackbox/testdata/capnproto/imports/foo.capnp new file mode 100644 index 000000000..146a2969f --- /dev/null +++ b/tests/auto/blackbox/testdata/capnproto/imports/foo.capnp @@ -0,0 +1,6 @@ +@0x8a2efe67220790be; + +struct Foo { + num @0 :UInt32; + str @1 :Text; +} diff --git a/tests/auto/blackbox/testdata/change-in-imported-file/change-in-imported-file.qbs b/tests/auto/blackbox/testdata/change-in-imported-file/change-in-imported-file.qbs index cf5354268..011eedc91 100644 --- a/tests/auto/blackbox/testdata/change-in-imported-file/change-in-imported-file.qbs +++ b/tests/auto/blackbox/testdata/change-in-imported-file/change-in-imported-file.qbs @@ -15,7 +15,7 @@ Product { prepare: { var cmd = new JavaScriptCommand(); PrepareHelper.prepare(cmd); - cmd.description = "Creating output"; + cmd.description = "creating output"; return [cmd]; } } diff --git a/tests/auto/blackbox/testdata/change-tracking-and-multiplexing/change-tracking-and-multiplexing.qbs b/tests/auto/blackbox/testdata/change-tracking-and-multiplexing/change-tracking-and-multiplexing.qbs index d1215355c..096778cd3 100644 --- a/tests/auto/blackbox/testdata/change-tracking-and-multiplexing/change-tracking-and-multiplexing.qbs +++ b/tests/auto/blackbox/testdata/change-tracking-and-multiplexing/change-tracking-and-multiplexing.qbs @@ -1,8 +1,8 @@ StaticLibrary { name: "l" - Depends { condition: qbs.targetOS.contains("darwin"); name: "bundle" } - Properties { condition: qbs.targetOS.contains("darwin"); bundle.isBundle: false } + Depends { condition: qbs.targetOS.includes("darwin"); name: "bundle" } + Properties { condition: qbs.targetOS.includes("darwin"); bundle.isBundle: false } multiplexByQbsProperties: ["buildVariants"] qbs.buildVariants: ["debug", "release"] diff --git a/tests/auto/blackbox/testdata/choose-module-instance/other-searchpath/modules/limerick/generic.qbs b/tests/auto/blackbox/testdata/choose-module-instance/other-searchpath/modules/limerick/generic.qbs index 2ebaaac11..bd8e901c7 100644 --- a/tests/auto/blackbox/testdata/choose-module-instance/other-searchpath/modules/limerick/generic.qbs +++ b/tests/auto/blackbox/testdata/choose-module-instance/other-searchpath/modules/limerick/generic.qbs @@ -1,3 +1,3 @@ Module { - condition: !qbs.targetOS.contains("Beatles") + condition: !qbs.targetOS.includes("Beatles") } diff --git a/tests/auto/blackbox/testdata/clean/clean.qbs b/tests/auto/blackbox/testdata/clean/clean.qbs index ce3a8eb12..10eca2d41 100644 --- a/tests/auto/blackbox/testdata/clean/clean.qbs +++ b/tests/auto/blackbox/testdata/clean/clean.qbs @@ -5,7 +5,7 @@ Project { name: "dep" files: "dep.cpp" Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } diff --git a/tests/auto/blackbox/testdata/cli/dotnettest.qbs b/tests/auto/blackbox/testdata/cli/dotnettest.qbs index 9a10b8068..5685be8c4 100644 --- a/tests/auto/blackbox/testdata/cli/dotnettest.qbs +++ b/tests/auto/blackbox/testdata/cli/dotnettest.qbs @@ -1,7 +1,7 @@ Project { Application { Depends { name: "cli" } - Depends { name: "HelloWorldModule"; condition: !qbs.toolchain.contains("mono") } + Depends { name: "HelloWorldModule"; condition: !qbs.toolchain.includes("mono") } Depends { name: "NetLib" } type: "application" @@ -16,7 +16,7 @@ Project { // Mono's VB compiler doesn't support modules yet, and if we try with C#, it crashes anyways NetModule { - condition: !qbs.toolchain.contains("mono") + condition: !qbs.toolchain.includes("mono") Depends { name: "cli" } name: "HelloWorldModule" @@ -37,7 +37,7 @@ Project { // fill-in for missing NetModule Group { - condition: qbs.toolchain.contains("mono") + condition: qbs.toolchain.includes("mono") files: ["Module.cs"] } diff --git a/tests/auto/blackbox/testdata/command-file/command-file.qbs b/tests/auto/blackbox/testdata/command-file/command-file.qbs index 8e25221c5..87dd0e054 100644 --- a/tests/auto/blackbox/testdata/command-file/command-file.qbs +++ b/tests/auto/blackbox/testdata/command-file/command-file.qbs @@ -4,7 +4,7 @@ Project { destinationDirectory: project.buildDirectory Depends { name: "cpp" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } files: ["lib.cpp"] @@ -14,6 +14,6 @@ Project { cpp.libraryPaths: project.buildDirectory files: ["main.cpp"] cpp.staticLibraries: ['@' + sourceDirectory + '/' - + (qbs.toolchain.contains("msvc") ? "list.msvc" : "list.gcc")] + + (qbs.toolchain.includes("msvc") ? "list.msvc" : "list.gcc")] } } diff --git a/tests/auto/blackbox/testdata/compilerDefinesByLanguage/CppDefinesApp.qbs b/tests/auto/blackbox/testdata/compilerDefinesByLanguage/CppDefinesApp.qbs index b205ef2a7..f2da212f6 100644 --- a/tests/auto/blackbox/testdata/compilerDefinesByLanguage/CppDefinesApp.qbs +++ b/tests/auto/blackbox/testdata/compilerDefinesByLanguage/CppDefinesApp.qbs @@ -1,7 +1,7 @@ CppApplication { files: ["app.c"] - property bool enableObjectiveC: qbs.targetOS.contains("darwin") + property bool enableObjectiveC: qbs.targetOS.includes("darwin") Group { name: "C/C++" diff --git a/tests/auto/blackbox/testdata/conanfile-probe/testapp/conanfile-probe-project.qbs b/tests/auto/blackbox/testdata/conanfile-probe/testapp/conanfile-probe-project.qbs new file mode 100644 index 000000000..adcb2bd9c --- /dev/null +++ b/tests/auto/blackbox/testdata/conanfile-probe/testapp/conanfile-probe-project.qbs @@ -0,0 +1,23 @@ +import qbs.Probes +import qbs.TextFile + +Project { + readonly property bool forceFailure: false + + Probes.ConanfileProbe { + id: conan + conanfilePath: path + "/conanfile.py" + options: ({opt: "True", forceFailure: (project.forceFailure ? "True" : "False")}) + settings: ({os: "AIX"}) + } + + property var check: { + var tf = new TextFile(buildDirectory + "/results.json", TextFile.WriteOnly); + var o = { + json: conan.json.deps_env_info["ENV_VAR"], + dependencies: conan.dependencies["testlib"].libs, + generatedFilesPath: conan.generatedFilesPath + }; + tf.write(JSON.stringify(o)); + } +} diff --git a/tests/auto/blackbox/testdata/conanfile-probe/testapp/conanfile.py b/tests/auto/blackbox/testdata/conanfile-probe/testapp/conanfile.py new file mode 100644 index 000000000..59e40cc80 --- /dev/null +++ b/tests/auto/blackbox/testdata/conanfile-probe/testapp/conanfile.py @@ -0,0 +1,26 @@ +from conans import ConanFile + +class TestApp(ConanFile): + name = "testapp" + description = "Our project package, to be inspected by the Qbs ConanfileProbe" + license = "none" + version = "6.6.6" + + settings = "os" + options = {"opt": [True, False], "forceFailure": [True, False]} + default_options = {"opt": False, "forceFailure": False} + + requires = "testlib/1.2.3@qbs/testing" + + def configure(self): + assert(not self.options.forceFailure) + self.options["testlib"].opt = self.options.opt + + def source(self): + pass + + def build(self): + pass + + def package(self): + pass diff --git a/tests/auto/blackbox/testdata/conanfile-probe/testlib/conanfile.py b/tests/auto/blackbox/testdata/conanfile-probe/testlib/conanfile.py new file mode 100644 index 000000000..983c22599 --- /dev/null +++ b/tests/auto/blackbox/testdata/conanfile-probe/testlib/conanfile.py @@ -0,0 +1,25 @@ +from conans import ConanFile + +class Testlib(ConanFile): + name = "testlib" + description = "Represents an arbitrary package, for instance on bintray" + license = "none" + version = "1.2.3" + + settings = "os" + options = {"opt": [True, False]} + default_options = {"opt": False} + + def source(self): + pass + + def build(self): + pass + + def package(self): + pass + + def package_info(self): + self.cpp_info.libs = ["testlib1","testlib2"] + self.env_info.ENV_VAR = "TESTLIB_ENV_VAL" + self.user_info.user_var = "testlib_user_val" diff --git a/tests/auto/blackbox/testdata/concurrent-executor/concurrent-executor.qbs b/tests/auto/blackbox/testdata/concurrent-executor/concurrent-executor.qbs deleted file mode 100644 index 802aa1450..000000000 --- a/tests/auto/blackbox/testdata/concurrent-executor/concurrent-executor.qbs +++ /dev/null @@ -1,67 +0,0 @@ -import qbs.File -import qbs.TextFile -import "util.js" as Utils - -Product { - type: ["final1", "final2"] - Group { - files: ["dummy1.input"] - fileTags: ["input1"] - } - Group { - files: ["dummy2.input"] - fileTags: ["input2"] - } - Rule { - inputs: ["input1"] - Artifact { - filePath: project.buildDirectory + "/dummy1.final" - fileTags: ["final1"] - } - prepare: { - var cmds = []; - for (var i = 0; i < 10; ++i) { - var cmd = new JavaScriptCommand(); - cmd.silent = true; - cmd.createFile = i == 9; - cmd.sourceCode = function() { - if (createFile) { - console.info("Creating file"); - var file = new TextFile(output.filePath, TextFile.WriteOnly); - file.close(); - } - }; - cmds.push(cmd); - } - return cmds; - } - } - Rule { - inputs: ["input2"] - Artifact { - filePath: "dummy.intermediate" - fileTags: ["intermediate"] - } - prepare: { - var cmd = new JavaScriptCommand(); - cmd.silent = true; - cmd.sourceCode = function() { }; - return [cmd]; - } - } - Rule { - inputs: ["intermediate"] - outputFileTags: "final2" - prepare: { - do - Utils.sleep(6000); - while (!File.exists(project.buildDirectory + "/dummy1.final")); - var cmd = new JavaScriptCommand(); - cmd.silent = true; - cmd.sourceCode = function() { }; - return [cmd]; - } - } -} - - diff --git a/tests/auto/blackbox/testdata/concurrent-executor/util.js b/tests/auto/blackbox/testdata/concurrent-executor/util.js deleted file mode 100644 index a37a8cbb1..000000000 --- a/tests/auto/blackbox/testdata/concurrent-executor/util.js +++ /dev/null @@ -1,8 +0,0 @@ -function sleep(timeInMs) -{ - var referenceTime = new Date(); - var time = null; - do { - time = new Date(); - } while (time - referenceTime < timeInMs); -} diff --git a/tests/auto/blackbox/testdata/conditional-filetagger/conditional-filetagger.qbs b/tests/auto/blackbox/testdata/conditional-filetagger/conditional-filetagger.qbs index 5f0c93e46..f5d7ad676 100644 --- a/tests/auto/blackbox/testdata/conditional-filetagger/conditional-filetagger.qbs +++ b/tests/auto/blackbox/testdata/conditional-filetagger/conditional-filetagger.qbs @@ -1,7 +1,7 @@ CppApplication { name: "theApp" property bool enableTagger - files: ["main.custom"]; + files: ["main.custom"] FileTagger { condition: enableTagger patterns: ["*.custom"] diff --git a/tests/auto/blackbox/testdata/configure/configure.qbs b/tests/auto/blackbox/testdata/configure/configure.qbs index af5638dde..be0e65247 100644 --- a/tests/auto/blackbox/testdata/configure/configure.qbs +++ b/tests/auto/blackbox/testdata/configure/configure.qbs @@ -1,6 +1,13 @@ import qbs.FileInfo +import qbs.Host Project { + property bool enabled: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } property string name: 'configure' qbsSearchPaths: '.' Product { diff --git a/tests/auto/blackbox/testdata/configure/main.cpp b/tests/auto/blackbox/testdata/configure/main.cpp index c7213c768..a91914f73 100644 --- a/tests/auto/blackbox/testdata/configure/main.cpp +++ b/tests/auto/blackbox/testdata/configure/main.cpp @@ -30,7 +30,7 @@ int main() { - printf("%s..\n", TEXT); + std::printf("%s..\n", TEXT); return 0; } diff --git a/tests/auto/blackbox/testdata/configure/modules/definition/module.qbs b/tests/auto/blackbox/testdata/configure/modules/definition/module.qbs index 1d647faa2..6a1dbe67d 100644 --- a/tests/auto/blackbox/testdata/configure/modules/definition/module.qbs +++ b/tests/auto/blackbox/testdata/configure/modules/definition/module.qbs @@ -12,7 +12,7 @@ Module { var cmd; var args; var p = path; - if (targetOS.contains("windows")) { + if (targetOS.includes("windows")) { cmd = windowsShellPath; args = ["/c", "date", "/t"]; } else { diff --git a/tests/auto/blackbox/testdata/conflicting-property-values/conflicting-property-values.qbs b/tests/auto/blackbox/testdata/conflicting-property-values/conflicting-property-values.qbs new file mode 100644 index 000000000..23b6ee5a3 --- /dev/null +++ b/tests/auto/blackbox/testdata/conflicting-property-values/conflicting-property-values.qbs @@ -0,0 +1,41 @@ +Project { + Product { + name: "low" + Export { property string prop: "low"; property string prop2: "low" } + } + Product { + name: "higher1" + Export { Depends { name: "low" } low.prop: "higher1" } + } + Product { + name: "higher2" + Export { Depends { name: "low" } low.prop: "higher2" } + } + Product { + name: "highest1" + Export { + Depends { name: "low" } + Depends { name: "higher1" } + Depends { name: "higher2" } + low.prop: "highest1" + low.prop2: "highest" + } + } + Product { + name: "highest2" + Export { + Depends { name: "low" } + Depends { name: "higher1" } + Depends { name: "higher2" } + low.prop: "highest2" + low.prop2: "highest" + } + } + Product { + name: "toplevel" + Depends { name: "highest1" } + Depends { name: "highest2" } + low.prop: name + property bool dummy: { console.info("final prop value: " + low.prop); } + } +} diff --git a/tests/auto/blackbox/testdata/cpu-features/cpu-features.qbs b/tests/auto/blackbox/testdata/cpu-features/cpu-features.qbs index 0bfdaceba..36e805516 100644 --- a/tests/auto/blackbox/testdata/cpu-features/cpu-features.qbs +++ b/tests/auto/blackbox/testdata/cpu-features/cpu-features.qbs @@ -8,7 +8,7 @@ CppApplication { property bool dummy: { console.info("is x86: " + (qbs.architecture === "x86")); console.info("is x64: " + (qbs.architecture === "x86_64")); - console.info("is gcc: " + qbs.toolchain.contains("gcc")); - console.info("is msvc: " + qbs.toolchain.contains("msvc")); + console.info("is gcc: " + qbs.toolchain.includes("gcc")); + console.info("is msvc: " + qbs.toolchain.includes("msvc")); } } diff --git a/tests/auto/blackbox/testdata/cxx-language-version/cxx-language-version.qbs b/tests/auto/blackbox/testdata/cxx-language-version/cxx-language-version.qbs index 322ded85c..24c37951c 100644 --- a/tests/auto/blackbox/testdata/cxx-language-version/cxx-language-version.qbs +++ b/tests/auto/blackbox/testdata/cxx-language-version/cxx-language-version.qbs @@ -13,10 +13,10 @@ CppApplication { var isEvenNewerMsvc; var isOlderMsvc; var isGcc; - if (toolchain.contains("clang-cl")) { + if (toolchain.includes("clang-cl")) { isEvenNewerMsvc = true; isNewerMsvc = true; - } else if (toolchain.contains("msvc")) { + } else if (toolchain.includes("msvc")) { if (compilerVersion >= "19.12.25831") isEvenNewerMsvc = true; if (compilerVersion >= "18.00.30723") diff --git a/tests/auto/blackbox/testdata/date-property/date-property.qbs b/tests/auto/blackbox/testdata/date-property/date-property.qbs new file mode 100644 index 000000000..ffd584802 --- /dev/null +++ b/tests/auto/blackbox/testdata/date-property/date-property.qbs @@ -0,0 +1,18 @@ +Product { + type: "date" + property var theDate: new Date(1999, 11, 31); + Rule { + multiplex: true + Artifact { filePath: "dummy"; fileTags: "date" } + prepare: { + var cmd = new JavaScriptCommand; + cmd.silent = true; + cmd.sourceCode = function() { + var d = product.theDate; + console.info("The stored date was " + d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + + d.getDate()); + }; + return cmd; + } + } +} diff --git a/tests/auto/blackbox/testdata/dependenciesProperty/dependenciesProperty.qbs b/tests/auto/blackbox/testdata/dependenciesProperty/dependenciesProperty.qbs index 735bfffbc..681ffeab0 100644 --- a/tests/auto/blackbox/testdata/dependenciesProperty/dependenciesProperty.qbs +++ b/tests/auto/blackbox/testdata/dependenciesProperty/dependenciesProperty.qbs @@ -18,7 +18,7 @@ Project { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = 'generate ' + FileInfo.fileName(output.filePath); + cmd.description = 'generating ' + FileInfo.fileName(output.filePath); cmd.highlight = 'codegen'; cmd.sourceCode = function() { file = new TextFile(output.filePath, TextFile.WriteOnly); diff --git a/tests/auto/blackbox/testdata/dependency-profile-mismatch/dependency-profile-mismatch.qbs b/tests/auto/blackbox/testdata/dependency-profile-mismatch/dependency-profile-mismatch.qbs deleted file mode 100644 index 8a6f733c0..000000000 --- a/tests/auto/blackbox/testdata/dependency-profile-mismatch/dependency-profile-mismatch.qbs +++ /dev/null @@ -1,12 +0,0 @@ -Project { - property string mainProfile - property string depProfile - Product { - name: "dep" - qbs.profiles: [project.depProfile] - } - Product { - name: "main" - Depends { name: "dep"; profiles: [project.mainProfile]; } - } -} diff --git a/tests/auto/blackbox/testdata/dependency-scanning-loop/dependency-scanning-loop.qbs b/tests/auto/blackbox/testdata/dependency-scanning-loop/dependency-scanning-loop.qbs new file mode 100644 index 000000000..ac8e7258c --- /dev/null +++ b/tests/auto/blackbox/testdata/dependency-scanning-loop/dependency-scanning-loop.qbs @@ -0,0 +1,34 @@ +import qbs.FileInfo +import qbs.TextFile + +CppApplication { + name: "app" + cpp.includePaths: buildDirectory + Group { + files: "main.cpp" + fileTags: ["cpp", "custom.in"] + } + Rule { + inputs: "custom.in" + Artifact { + filePath: FileInfo.completeBaseName(input.filePath) + ".h" + fileTags: "hpp" + } + Artifact { + filePath: "custom.txt" + fileTags: "whatever" + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "generating " + outputs.hpp[0].fileName; + cmd.sourceCode = function() { + var f = new TextFile(outputs.hpp[0].filePath, TextFile.WriteOnly); + f.writeLine("int main() {}"); + f.close(); + f = new TextFile(outputs.whatever[0].filePath, TextFile.WriteOnly); + f.close(); + } + return cmd; + } + } +} diff --git a/tests/auto/blackbox/testdata/dependency-scanning-loop/main.cpp b/tests/auto/blackbox/testdata/dependency-scanning-loop/main.cpp new file mode 100644 index 000000000..5e8dda41b --- /dev/null +++ b/tests/auto/blackbox/testdata/dependency-scanning-loop/main.cpp @@ -0,0 +1 @@ +#include <main.h> diff --git a/tests/auto/blackbox/testdata/deprecated-property/deprecated-property.qbs b/tests/auto/blackbox/testdata/deprecated-property/deprecated-property.qbs index a8efb97b5..7d1550312 100644 --- a/tests/auto/blackbox/testdata/deprecated-property/deprecated-property.qbs +++ b/tests/auto/blackbox/testdata/deprecated-property/deprecated-property.qbs @@ -1,8 +1,6 @@ -import qbs - Product { Depends { name: "themodule" } themodule.newProp: true - themodule.oldProp: false + themodule.expiringProp: false themodule.veryOldProp: false } diff --git a/tests/auto/blackbox/testdata/deprecated-property/modules/themodule/m.qbs b/tests/auto/blackbox/testdata/deprecated-property/modules/themodule/m.qbs index 106ed4135..58164e918 100644 --- a/tests/auto/blackbox/testdata/deprecated-property/modules/themodule/m.qbs +++ b/tests/auto/blackbox/testdata/deprecated-property/modules/themodule/m.qbs @@ -1,8 +1,8 @@ -import qbs +import qbs.Environment Module { property bool newProp - property bool oldProp + property bool expiringProp property bool forgottenProp PropertyOptions { @@ -10,9 +10,9 @@ Module { description: "Use this, it's good!" } PropertyOptions { - name: "oldProp" + name: "expiringProp" description: "Use newProp instead." - removalVersion: "99.9" + removalVersion: Environment.getEnv("REMOVAL_VERSION") } PropertyOptions { name: "veryOldProp" diff --git a/tests/auto/blackbox/testdata/disappeared-profile/modules-dir/modules/m/m.qbs b/tests/auto/blackbox/testdata/disappeared-profile/modules-dir/modules/m/m.qbs index 3e1747ade..fd755ce86 100644 --- a/tests/auto/blackbox/testdata/disappeared-profile/modules-dir/modules/m/m.qbs +++ b/tests/auto/blackbox/testdata/disappeared-profile/modules-dir/modules/m/m.qbs @@ -10,7 +10,7 @@ Module { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Creating " + output.fileName + " with " + product.m.p1; + cmd.description = "creating " + output.fileName + " with " + product.m.p1; cmd.sourceCode = function() {}; return [cmd]; } @@ -24,7 +24,7 @@ Module { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Creating " + output.fileName + " with " + product.m.p2; + cmd.description = "creating " + output.fileName + " with " + product.m.p2; cmd.sourceCode = function() {}; return [cmd]; } diff --git a/tests/auto/blackbox/testdata/discard-unused-data/discard-unused-data.qbs b/tests/auto/blackbox/testdata/discard-unused-data/discard-unused-data.qbs index fdd3aa1f7..367bb665c 100644 --- a/tests/auto/blackbox/testdata/discard-unused-data/discard-unused-data.qbs +++ b/tests/auto/blackbox/testdata/discard-unused-data/discard-unused-data.qbs @@ -4,9 +4,9 @@ CppApplication { files: "main.cpp" - Depends { name: "bundle"; condition: qbs.targetOS.contains("darwin") } + Depends { name: "bundle"; condition: qbs.targetOS.includes("darwin") } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } @@ -17,7 +17,7 @@ CppApplication { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { - console.info("is Darwin: " + product.qbs.targetOS.contains("darwin")); + console.info("is Darwin: " + product.qbs.targetOS.includes("darwin")); console.info("---" + product.cpp.nmPath + "---"); } return [cmd]; diff --git a/tests/auto/blackbox/testdata/distribution-include-paths/distribution-include-paths.qbs b/tests/auto/blackbox/testdata/distribution-include-paths/distribution-include-paths.qbs new file mode 100644 index 000000000..3e6fb9b00 --- /dev/null +++ b/tests/auto/blackbox/testdata/distribution-include-paths/distribution-include-paths.qbs @@ -0,0 +1,4 @@ +CppApplication { + files: ["main.cpp"] + cpp.distributionIncludePaths: ["subdir"] +} diff --git a/tests/auto/blackbox/testdata/distribution-include-paths/main.cpp b/tests/auto/blackbox/testdata/distribution-include-paths/main.cpp new file mode 100644 index 000000000..10d376a31 --- /dev/null +++ b/tests/auto/blackbox/testdata/distribution-include-paths/main.cpp @@ -0,0 +1,8 @@ +#include <cstdio> +#include <gagagugu.h> + +int main() +{ + printStuff(); + return 0; +} diff --git a/tests/auto/blackbox/testdata/distribution-include-paths/subdir/gagagugu.h b/tests/auto/blackbox/testdata/distribution-include-paths/subdir/gagagugu.h new file mode 100644 index 000000000..b951d8855 --- /dev/null +++ b/tests/auto/blackbox/testdata/distribution-include-paths/subdir/gagagugu.h @@ -0,0 +1,4 @@ +void printStuff() +{ + puts("alalalalonglonglilonglonglong"); +} diff --git a/tests/auto/blackbox/testdata/dot-dot-pc-file/dot-dot-pc-file.qbs b/tests/auto/blackbox/testdata/dot-dot-pc-file/dot-dot-pc-file.qbs new file mode 100644 index 000000000..60c4ea2bc --- /dev/null +++ b/tests/auto/blackbox/testdata/dot-dot-pc-file/dot-dot-pc-file.qbs @@ -0,0 +1,7 @@ +CppApplication { + name: "p" + Depends { name: "qbs-metatest-module"; } + files: "main.cpp" + moduleProviders.qbspkgconfig.libDirs: "libdir" + qbsModuleProviders: "qbspkgconfig" +} diff --git a/tests/auto/blackbox/testdata/dot-dot-pc-file/libdir/qbs.metatest.module.pc b/tests/auto/blackbox/testdata/dot-dot-pc-file/libdir/qbs.metatest.module.pc new file mode 100644 index 000000000..c00fd26d6 --- /dev/null +++ b/tests/auto/blackbox/testdata/dot-dot-pc-file/libdir/qbs.metatest.module.pc @@ -0,0 +1,5 @@ +Name: qbs.metatest.module +Description: just a test +Version: 0.0.1 + +Cflags: -DTHE_MAGIC_DEFINE diff --git a/tests/auto/blackbox/testdata/dot-dot-pc-file/main.cpp b/tests/auto/blackbox/testdata/dot-dot-pc-file/main.cpp new file mode 100644 index 000000000..442b755bf --- /dev/null +++ b/tests/auto/blackbox/testdata/dot-dot-pc-file/main.cpp @@ -0,0 +1,5 @@ +#ifndef THE_MAGIC_DEFINE +#error "missing the magic define" +#endif + +int main() {} diff --git a/tests/auto/blackbox/testdata/driver-linker-flags/driver-linker-flags.qbs b/tests/auto/blackbox/testdata/driver-linker-flags/driver-linker-flags.qbs index 5de0fe053..57f096494 100644 --- a/tests/auto/blackbox/testdata/driver-linker-flags/driver-linker-flags.qbs +++ b/tests/auto/blackbox/testdata/driver-linker-flags/driver-linker-flags.qbs @@ -8,7 +8,7 @@ CppApplication { Probe { id: toolchainProbe - condition: qbs.toolchain.contains("gcc") + condition: qbs.toolchain.includes("gcc") configure: { console.info("toolchain is GCC-like"); found = true; diff --git a/tests/auto/blackbox/testdata/dynamic-library-in-module/Dll.qbs b/tests/auto/blackbox/testdata/dynamic-library-in-module/Dll.qbs index 1acf606dc..c95d88052 100644 --- a/tests/auto/blackbox/testdata/dynamic-library-in-module/Dll.qbs +++ b/tests/auto/blackbox/testdata/dynamic-library-in-module/Dll.qbs @@ -1,8 +1,8 @@ DynamicLibrary { Depends { name: "cpp" } - Depends { name: "bundle"; condition: qbs.targetOS.contains("darwin") } + Depends { name: "bundle"; condition: qbs.targetOS.includes("darwin") } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false cpp.minimumMacosVersion: "10.7" // For -rpath } diff --git a/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/thelib/thelib.qbs b/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/thelib/thelib.qbs index 30f87337d..3059fa5e9 100644 --- a/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/thelib/thelib.qbs +++ b/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/thelib/thelib.qbs @@ -13,7 +13,7 @@ Module { } Group { name: "thelib dll import" - condition: qbs.targetOS.contains("windows") + condition: qbs.targetOS.includes("windows") files: FileInfo.joinPaths(product.thelib.baseDir, "thelib.lib") fileTags: ["dynamiclibrary_import"] filesAreTargets: true diff --git a/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/theotherlib/theotherlib.qbs b/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/theotherlib/theotherlib.qbs index 1eb1e01a5..f387feb80 100644 --- a/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/theotherlib/theotherlib.qbs +++ b/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/theotherlib/theotherlib.qbs @@ -13,7 +13,7 @@ Module { } Group { name: "theotherlib dll import" - condition: qbs.targetOS.contains("windows") + condition: qbs.targetOS.includes("windows") files: FileInfo.joinPaths(product.theotherlib.baseDir, "theotherlib.lib") fileTags: ["dynamiclibrary_import"] filesAreTargets: true diff --git a/tests/auto/blackbox/testdata/dynamic-library-in-module/theapp.qbs b/tests/auto/blackbox/testdata/dynamic-library-in-module/theapp.qbs index b9149d091..5ea8cef23 100644 --- a/tests/auto/blackbox/testdata/dynamic-library-in-module/theapp.qbs +++ b/tests/auto/blackbox/testdata/dynamic-library-in-module/theapp.qbs @@ -1,5 +1,13 @@ +import qbs.Host + Project { CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: "theapp" cpp.minimumMacosVersion: "10.7" // For -rpath Depends { name: "theotherlib" } diff --git a/tests/auto/blackbox/testdata/dynamic-project/dynamic-project.qbs b/tests/auto/blackbox/testdata/dynamic-project/dynamic-project.qbs index 166648c80..5acdb8892 100644 --- a/tests/auto/blackbox/testdata/dynamic-project/dynamic-project.qbs +++ b/tests/auto/blackbox/testdata/dynamic-project/dynamic-project.qbs @@ -17,13 +17,12 @@ Project var srcDir = FileInfo.joinPaths(sourceDir, "src"); var projectDirs = File.directoryEntries(srcDir, File.Dirs | File.NoDotAndDotDot); var list = []; - for (it in projectDirs) { + for (var it = 0; it < projectDirs.length; ++it) { var name = projectDirs[it]; var productSrcDir = FileInfo.joinPaths(srcDir, name); var productFilePath = FileInfo.joinPaths(tempDir, name + ".qbs"); var file = new TextFile(productFilePath, TextFile.WriteOnly); try { - file.writeLine("import qbs"); file.writeLine("CppApplication"); file.writeLine("{"); file.writeLine("\tfiles: [ \"" + productSrcDir + "/*.cpp\" ]"); diff --git a/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/flexoptionsreader.js b/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/flexoptionsreader.js index bd596fbca..b925effcf 100644 --- a/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/flexoptionsreader.js +++ b/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/flexoptionsreader.js @@ -35,7 +35,7 @@ ** ****************************************************************************/ -// needs import qbs.TextFile +var TextFile = require("qbs.TextFile"); function readFlexOptions(filePath) { @@ -82,7 +82,7 @@ function readFlexOptions(filePath) } } - var tf = new TextFile(input.filePath); + var tf = new TextFile(filePath); var line; var optrex = /^%option\s+(.*$)/; var res; diff --git a/tests/auto/blackbox/testdata/empty-profile/empty-profile.qbs b/tests/auto/blackbox/testdata/empty-profile/empty-profile.qbs new file mode 100644 index 000000000..da7536315 --- /dev/null +++ b/tests/auto/blackbox/testdata/empty-profile/empty-profile.qbs @@ -0,0 +1,3 @@ +CppApplication { + files: ["main.cpp"] +} diff --git a/tests/auto/blackbox/testdata/empty-profile/main.cpp b/tests/auto/blackbox/testdata/empty-profile/main.cpp new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/blackbox/testdata/empty-profile/main.cpp @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/blackbox/testdata/enableExceptions/exceptions.qbs b/tests/auto/blackbox/testdata/enableExceptions/exceptions.qbs index 9a75043a8..e1d09f7e0 100644 --- a/tests/auto/blackbox/testdata/enableExceptions/exceptions.qbs +++ b/tests/auto/blackbox/testdata/enableExceptions/exceptions.qbs @@ -1,5 +1,5 @@ CppApplication { files: ["main.cpp"] cpp.treatWarningsAsErrors: true - cpp.defines: qbs.toolchain.contains("msvc") && !cpp.enableExceptions ? ["FORCE_FAIL_VS"] : [] + cpp.defines: qbs.toolchain.includes("msvc") && !cpp.enableExceptions ? ["FORCE_FAIL_VS"] : [] } diff --git a/tests/auto/blackbox/testdata/enableExceptions/none.qbs b/tests/auto/blackbox/testdata/enableExceptions/none.qbs index 8fb052476..439ea3037 100644 --- a/tests/auto/blackbox/testdata/enableExceptions/none.qbs +++ b/tests/auto/blackbox/testdata/enableExceptions/none.qbs @@ -2,7 +2,7 @@ CppApplication { files: ["emptymain.cpp"] Group { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") files: ["empty.m", "empty.mm"] } } diff --git a/tests/auto/blackbox/testdata/env-merging/env-merging.qbs b/tests/auto/blackbox/testdata/env-merging/env-merging.qbs index 6edeca444..eb681f36b 100644 --- a/tests/auto/blackbox/testdata/env-merging/env-merging.qbs +++ b/tests/auto/blackbox/testdata/env-merging/env-merging.qbs @@ -1,3 +1,5 @@ +import qbs.Host + Project { CppApplication { name: "tool" @@ -5,6 +7,12 @@ Project { } Product { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: "p" type: "custom" Depends { name: "tool" } diff --git a/tests/auto/blackbox/testdata/escaped-linker-flags/escaped-linker-flags.qbs b/tests/auto/blackbox/testdata/escaped-linker-flags/escaped-linker-flags.qbs index f48bf8d1f..b4fb0df4d 100644 --- a/tests/auto/blackbox/testdata/escaped-linker-flags/escaped-linker-flags.qbs +++ b/tests/auto/blackbox/testdata/escaped-linker-flags/escaped-linker-flags.qbs @@ -10,4 +10,9 @@ CppApplication { cpp.linkerFlags: ["-s"] } files: ["main.cpp"] + Probe { + id: checker + property bool isUnixGcc: qbs.toolchain.contains("gcc") && !qbs.targetOS.contains("macos") + configure: { console.info("is gcc: " + isUnixGcc); } + } } diff --git a/tests/auto/blackbox/testdata/export-rule/export-rule.qbs b/tests/auto/blackbox/testdata/export-rule/export-rule.qbs index 29899e728..455ccba0d 100644 --- a/tests/auto/blackbox/testdata/export-rule/export-rule.qbs +++ b/tests/auto/blackbox/testdata/export-rule/export-rule.qbs @@ -13,7 +13,7 @@ Project { Export { Depends { name: "cpp" } property bool enableTagger - property string description: "Creating C++ source file."; + property string description: "creating C++ source file."; FileTagger { condition: enableTagger patterns: ["*.blubb"] diff --git a/tests/auto/blackbox/testdata/exports-cmake/Foo.cpp b/tests/auto/blackbox/testdata/exports-cmake/Foo.cpp new file mode 100644 index 000000000..ea334f9af --- /dev/null +++ b/tests/auto/blackbox/testdata/exports-cmake/Foo.cpp @@ -0,0 +1,5 @@ +#include "Foo.h" +int someFooWork() +{ + return 42; +} diff --git a/tests/auto/blackbox/testdata/exports-cmake/Foo.h b/tests/auto/blackbox/testdata/exports-cmake/Foo.h new file mode 100644 index 000000000..2f279f577 --- /dev/null +++ b/tests/auto/blackbox/testdata/exports-cmake/Foo.h @@ -0,0 +1,16 @@ +#ifndef FOO_H +#define FOO_H +#include <dllexport.h> + +#ifdef FOO_LIB_STATIC +#define FOO_LIB_EXPORT +#else +#ifdef FOO_LIB +#define FOO_LIB_EXPORT DLL_EXPORT +#else +#define FOO_LIB_EXPORT DLL_IMPORT +#endif +#endif + +FOO_LIB_EXPORT int someFooWork(); +#endif // FOO_H diff --git a/tests/auto/blackbox/testdata/exports-cmake/cmake/CMakeLists.txt b/tests/auto/blackbox/testdata/exports-cmake/cmake/CMakeLists.txt new file mode 100644 index 000000000..d874e0e92 --- /dev/null +++ b/tests/auto/blackbox/testdata/exports-cmake/cmake/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.10) + +project(qbs_import) + +find_package(Bar PATHS REQUIRED) +add_executable(Consumer main.cpp) +target_link_libraries(Consumer Bar) diff --git a/tests/auto/blackbox/testdata/exports-cmake/cmake/main.cpp b/tests/auto/blackbox/testdata/exports-cmake/cmake/main.cpp new file mode 100644 index 000000000..1a1fa90ec --- /dev/null +++ b/tests/auto/blackbox/testdata/exports-cmake/cmake/main.cpp @@ -0,0 +1,6 @@ +#include <Foo.h> + +int main() +{ + return someFooWork(); +} diff --git a/tests/auto/blackbox/testdata/exports-cmake/exports-cmake.qbs b/tests/auto/blackbox/testdata/exports-cmake/exports-cmake.qbs new file mode 100644 index 000000000..6464af705 --- /dev/null +++ b/tests/auto/blackbox/testdata/exports-cmake/exports-cmake.qbs @@ -0,0 +1,70 @@ +import qbs.FileInfo + +Project { + property bool isStatic: false + property bool isBundle: false + + property string headersInstallDir: "include" + + Product { + name: "DllExport" + Depends { name: "Exporter.cmake" } + Group { + name: "API headers" + files: ["../dllexport.h"] + qbs.install: true + qbs.installDir: project.headersInstallDir + } + Group { + fileTagsFilter: ["Exporter.cmake.package"] + qbs.install: true + qbs.installDir: "/lib/cmake/DllExport" + } + Export { + Depends { name: "cpp" } + cpp.includePaths: FileInfo.joinPaths( + exportingProduct.qbs.installRoot, + exportingProduct.qbs.installPrefix, + project.headersInstallDir) + } + } + + Library { + type: project.isStatic ? "staticlibrary" : "dynamiclibrary" + Depends { name: "cpp" } + Depends { name: "DllExport" } + Depends { name: "Exporter.cmake" } + Exporter.cmake.packageName: "Bar" + name: "Foo" + files: ["Foo.cpp"] + version: "1.2.3" + cpp.includePaths: "." + cpp.defines: "FOO_LIB" + Group { + name: "API headers" + files: ["Foo.h"] + qbs.install: true + qbs.installDir: project.headersInstallDir + } + install: true + installImportLib: true + Group { + fileTagsFilter: ["Exporter.cmake.package"] + qbs.install: true + qbs.installDir: "/lib/cmake/Bar" + } + Export { + Depends { name: "cpp" } + cpp.includePaths: FileInfo.joinPaths( + exportingProduct.qbs.installRoot, + exportingProduct.qbs.installPrefix, + project.headersInstallDir) + cpp.defines: ["FOO=1"].concat(project.isStatic ? ["FOO_LIB_STATIC"] : []) + cpp.commonCompilerFlags: "-DOTHER_DEF=1" + cpp.linkerFlags: exportingProduct.qbs.toolchain.contains("gcc") ? ["-s"] : [] + } + + Depends { name: 'bundle' } + bundle.isBundle: qbs.targetOS.includes("darwin") && project.isBundle + } +} diff --git a/tests/auto/blackbox/testdata/exports-cmake/find-cmake.qbs b/tests/auto/blackbox/testdata/exports-cmake/find-cmake.qbs new file mode 100644 index 000000000..52f388966 --- /dev/null +++ b/tests/auto/blackbox/testdata/exports-cmake/find-cmake.qbs @@ -0,0 +1,46 @@ +import qbs.Probes + +Product { + Depends { name: "cpp" } + + Probes.BinaryProbe { + id: cmakeProbe + names: "cmake" + } + + Probes.BinaryProbe { + id: ninjaProbe + names: ["ninja"] + } + + property bool test: { + var data = { + cmakeFound: cmakeProbe.found, + cmakeFilePath: cmakeProbe.filePath, + crossCompiling: qbs.targetPlatform !== qbs.hostPlatform, + installPrefix: qbs.installPrefix + }; + data.buildEnv = {} + Object.assign(data.buildEnv, cpp.buildEnv); // deep copy buildEnv from a probe + if (qbs.toolchain.includes("gcc")) { + data.buildEnv["CC"] = cpp.cCompilerName; + data.buildEnv["CXX"] = cpp.cxxCompilerName; + } else { + data.buildEnv["CC"] = cpp.compilerName; + data.buildEnv["CXX"] = cpp.compilerName; + } + + if (ninjaProbe.found) { + data.generator = "Ninja"; + } else { + if (qbs.toolchain.includes("msvc")) { + data.generator = "NMake Makefiles" + } else if (qbs.toolchain.includes("mingw")) { + data.generator = "MinGW Makefiles"; + } else if (qbs.toolchain.includes("gcc")) { + data.generator = "Unix Makefiles"; + } + } + console.info("---" + JSON.stringify(data) + "---"); + } +} diff --git a/tests/auto/blackbox/testdata/exports-pkgconfig/exports-pkgconfig.qbs b/tests/auto/blackbox/testdata/exports-pkgconfig/exports-pkgconfig.qbs index 96d1cabb9..23331f93f 100644 --- a/tests/auto/blackbox/testdata/exports-pkgconfig/exports-pkgconfig.qbs +++ b/tests/auto/blackbox/testdata/exports-pkgconfig/exports-pkgconfig.qbs @@ -1,4 +1,5 @@ import qbs.FileInfo +import qbs.Host Project { Product { @@ -42,14 +43,14 @@ Project { Depends { name: "Qt.core"; required: false } Depends { name: "helper1" } Depends { name: "helper3" } - property bool someCondition: qbs.hostOS.contains("windows") // hostOS for easier testing + property bool someCondition: Host.os().includes("windows") // hostOS for easier testing property bool someOtherCondition: someCondition Properties { condition: !someOtherCondition cpp.driverFlags: ["-pthread"] } - cpp.defines: product.name - cpp.includePaths: [FileInfo.joinPaths(product.qbs.installPrefix, "include")] + cpp.defines: exportingProduct.name + cpp.includePaths: [FileInfo.joinPaths(exportingProduct.qbs.installPrefix, "include")] Qt.core.mocName: "muck" } @@ -94,7 +95,7 @@ Project { Depends { name: "cpp" } cpp.includePaths: [ "/opt/thesecondlib/include", - product.sourceDirectory, + exportingProduct.sourceDirectory, importingProduct.buildDirectory ] property string hurz: importingProduct.name diff --git a/tests/auto/blackbox/testdata/exports-qbs/consumer.qbs b/tests/auto/blackbox/testdata/exports-qbs/consumer.qbs index 02affdfe8..073504400 100644 --- a/tests/auto/blackbox/testdata/exports-qbs/consumer.qbs +++ b/tests/auto/blackbox/testdata/exports-qbs/consumer.qbs @@ -1,4 +1,12 @@ +import qbs.Host + CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: "consumer" qbsSearchPaths: "default/install-root/usr/qbs" property string outTag: "cpp" diff --git a/tests/auto/blackbox/testdata/exports-qbs/lib.qbs b/tests/auto/blackbox/testdata/exports-qbs/lib.qbs index 53a472dbb..01f89a221 100644 --- a/tests/auto/blackbox/testdata/exports-qbs/lib.qbs +++ b/tests/auto/blackbox/testdata/exports-qbs/lib.qbs @@ -16,7 +16,7 @@ DynamicLibrary { cpp.defines: ["MYLIB_BUILD"] cpp.variantSuffix: qbs.buildVariant === "debug" ? "d" : "" Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } files: ["mylib.cpp"] @@ -38,8 +38,8 @@ DynamicLibrary { Export { Depends { name: "cpp" } - property string includeDir: product.sourceDirectory - property var config: product.config + property string includeDir: exportingProduct.sourceDirectory + property var config: exportingProduct.config Properties { condition: true cpp.includePaths: [includeDir] @@ -52,7 +52,7 @@ DynamicLibrary { condition: true prefixMapping: [{ prefix: includeDir, - replacement: FileInfo.joinPaths(qbs.installPrefix, product.headersInstallDir) + replacement: FileInfo.joinPaths(exportingProduct.qbs.installPrefix, exportingProduct.headersInstallDir) }] } } diff --git a/tests/auto/blackbox/testdata/exports-qbs/tool.qbs b/tests/auto/blackbox/testdata/exports-qbs/tool.qbs index 655597cf7..d3626bead 100644 --- a/tests/auto/blackbox/testdata/exports-qbs/tool.qbs +++ b/tests/auto/blackbox/testdata/exports-qbs/tool.qbs @@ -33,7 +33,7 @@ CppApplication { } Export { - property stringList toolTags: product.toolTags + property stringList toolTags: exportingProduct.toolTags property stringList outTags: [importingProduct.outTag] property var helper2Obj: Helper2 Rule { @@ -49,7 +49,7 @@ CppApplication { prepare: { var cmd = new Command(explicitlyDependsOn["MyTool.tool"][0].filePath, [input.filePath, output.filePath]); - cmd.description = input.fileName + " -> " + output.fileName; + cmd.description = "compiling" + input.fileName + " to " + output.fileName; return [cmd]; } } diff --git a/tests/auto/blackbox/testdata/external-libs/external-libs.qbs b/tests/auto/blackbox/testdata/external-libs/external-libs.qbs index 619f40867..326bf5dae 100644 --- a/tests/auto/blackbox/testdata/external-libs/external-libs.qbs +++ b/tests/auto/blackbox/testdata/external-libs/external-libs.qbs @@ -1,13 +1,13 @@ import qbs.TextFile Project { - property string libDir: sourceDirectory + "/libs" + property string libDir: buildDirectory + "/libs" StaticLibrary { name: "lib1" destinationDirectory: project.libDir Depends { name: "cpp" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } files: ["lib1.cpp"] @@ -18,7 +18,7 @@ Project { Depends { name: "cpp" } Depends { name: "lib1" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } files: ["lib2.cpp"] diff --git a/tests/auto/blackbox/testdata/fileDependencies/awesomelib/awesome.h b/tests/auto/blackbox/testdata/fileDependencies/awesomelib/awesome.h index 4633f9746..8f1f25087 100644 --- a/tests/auto/blackbox/testdata/fileDependencies/awesomelib/awesome.h +++ b/tests/auto/blackbox/testdata/fileDependencies/awesomelib/awesome.h @@ -31,6 +31,6 @@ void doAwesomeStuff() { - printf(magnificentMessage); + std::printf(magnificentMessage); } diff --git a/tests/auto/blackbox/testdata/flatbuf/bar.fbs b/tests/auto/blackbox/testdata/flatbuf/bar.fbs new file mode 100644 index 000000000..47148f800 --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/bar.fbs @@ -0,0 +1,9 @@ +include "foo.fbs"; + +namespace QbsTest; + +table Bar { + foo:Foo; +} + +root_type Bar; diff --git a/tests/auto/blackbox/testdata/flatbuf/baz.fbs b/tests/auto/blackbox/testdata/flatbuf/baz.fbs new file mode 100644 index 000000000..312183710 --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/baz.fbs @@ -0,0 +1,9 @@ +include "imported_foo/imported_foo.fbs"; + +namespace QbsTest; + +table Baz { + foo:Foo; +} + +root_type Baz; diff --git a/tests/auto/blackbox/testdata/flatbuf/conanfile.txt b/tests/auto/blackbox/testdata/flatbuf/conanfile.txt new file mode 100644 index 000000000..188da5897 --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/conanfile.txt @@ -0,0 +1,6 @@ +[requires] +flatbuffers/24.3.25 +[tool_requires] +flatbuffers/24.3.25 +[generators] +QbsDeps diff --git a/tests/auto/blackbox/testdata/flatbuf/flat.c b/tests/auto/blackbox/testdata/flatbuf/flat.c new file mode 100644 index 000000000..55e25e556 --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/flat.c @@ -0,0 +1,36 @@ +#include "foo_builder.h" + +#include <stdio.h> + +#undef ns +#define ns(x) FLATBUFFERS_WRAP_NAMESPACE(QbsTest, x) // Specified in the schema. + +#define test_assert(x) do { if (!(x)) { assert(0); return -1; }} while (0) + +int main() +{ + void *buffer = NULL; + size_t size = 0; + + flatcc_builder_t builder; + flatcc_builder_init(&builder); + + flatbuffers_string_ref_t name = flatbuffers_string_create_str(&builder, "John Doe"); + + ns(Foo_create_as_root(&builder, name, 42)); + + buffer = flatcc_builder_finalize_aligned_buffer(&builder, &size); + + ns(Foo_table_t) foo = ns(Foo_as_root(buffer)); + + test_assert(strcmp(ns(Foo_name(foo)), "John Doe") == 0); + test_assert(ns(Foo_count(foo)) == 42); + + free(buffer); + + flatcc_builder_clear(&builder); + + printf("The FlatBuffer was successfully created and accessed!\n"); + + return 0; +} diff --git a/tests/auto/blackbox/testdata/flatbuf/flat.cpp b/tests/auto/blackbox/testdata/flatbuf/flat.cpp new file mode 100644 index 000000000..56332bacd --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/flat.cpp @@ -0,0 +1,22 @@ +#include "foo_generated.h" + +#include <iostream> + +using namespace QbsTest; + +int main() +{ + flatbuffers::FlatBufferBuilder builder; + auto name = builder.CreateString("John Doe"); + auto newFoo = QbsTest::CreateFoo(builder, name, 42); + builder.Finish(newFoo); + + auto foo = GetFoo(builder.GetBufferPointer()); + + assert(foo->name()->str() == "John Doe"); + assert(foo->count() == 42); + + std::cout << "The FlatBuffer was successfully created and accessed!" << std::endl; + + return 0; +} diff --git a/tests/auto/blackbox/testdata/flatbuf/flat_absolute_import.cpp b/tests/auto/blackbox/testdata/flatbuf/flat_absolute_import.cpp new file mode 100644 index 000000000..b7c43d8a5 --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/flat_absolute_import.cpp @@ -0,0 +1,25 @@ +#include "baz_generated.h" + +#include <iostream> + +using namespace QbsTest; + +int main() +{ + flatbuffers::FlatBufferBuilder builder; + + auto name = builder.CreateString("John Doe"); + auto newFoo = QbsTest::CreateFoo(builder, name, 42); + + auto newBaz = QbsTest::CreateBaz(builder, newFoo); + builder.Finish(newBaz); + + auto baz = GetBaz(builder.GetBufferPointer()); + + assert(baz->foo()->name()->str() == "John Doe"); + assert(baz->foo()->count() == 42); + + std::cout << "The FlatBuffer was successfully created and accessed!" << std::endl; + + return 0; +} diff --git a/tests/auto/blackbox/testdata/flatbuf/flat_absolute_import.qbs b/tests/auto/blackbox/testdata/flatbuf/flat_absolute_import.qbs new file mode 100644 index 000000000..888bfd4e3 --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/flat_absolute_import.qbs @@ -0,0 +1,24 @@ +CppApplication { + Depends { name: "flatbuf.cpp"; required: false } + + consoleApplication: true + condition: { + var result = qbs.targetPlatform === qbs.hostPlatform; + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && hasFlatbuffers; + } + property bool hasFlatbuffers: { + console.info("has flatbuffers: " + flatbuf.cpp.present); + return flatbuf.cpp.present; + } + + flatbuf.cpp.importPaths: "imports/" + + files: [ + "flat_absolute_import.cpp", + "baz.fbs", + "imports/imported_foo/imported_foo.fbs", + ] + qbsModuleProviders: "conan" +} diff --git a/tests/auto/blackbox/testdata/flatbuf/flat_c.qbs b/tests/auto/blackbox/testdata/flatbuf/flat_c.qbs new file mode 100644 index 000000000..6d365252e --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/flat_c.qbs @@ -0,0 +1,21 @@ +CppApplication { + Depends { name: "flatbuffers.c"; required: false } + + consoleApplication: true + condition: { + var result = qbs.targetPlatform === qbs.hostPlatform; + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && hasFlatbuffers; + } + property bool hasFlatbuffers: { + console.info("has flatbuffers: " + flatbuffers.c.present); + return flatbuffers.c.present; + } + + files: [ + "flat.c", + "foo.fbs", + ] + qbsModuleProviders: "conan" +} diff --git a/tests/auto/blackbox/testdata/flatbuf/flat_cpp.qbs b/tests/auto/blackbox/testdata/flatbuf/flat_cpp.qbs new file mode 100644 index 000000000..99e89a5fa --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/flat_cpp.qbs @@ -0,0 +1,21 @@ +CppApplication { + Depends { name: "flatbuf.cpp"; required: false } + + consoleApplication: true + condition: { + var result = qbs.targetPlatform === qbs.hostPlatform; + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && hasFlatbuffers; + } + property bool hasFlatbuffers: { + console.info("has flatbuffers: " + flatbuf.cpp.present); + return flatbuf.cpp.present; + } + + files: [ + "flat.cpp", + "foo.fbs", + ] + qbsModuleProviders: "conan" +} diff --git a/tests/auto/blackbox/testdata/flatbuf/flat_filename_extension.cpp b/tests/auto/blackbox/testdata/flatbuf/flat_filename_extension.cpp new file mode 100644 index 000000000..77ed64acd --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/flat_filename_extension.cpp @@ -0,0 +1,22 @@ +#include "foo_generated.hpp" + +#include <iostream> + +using namespace QbsTest; + +int main() +{ + flatbuffers::FlatBufferBuilder builder; + auto name = builder.CreateString("John Doe"); + auto newFoo = QbsTest::CreateFoo(builder, name, 42); + builder.Finish(newFoo); + + auto foo = GetFoo(builder.GetBufferPointer()); + + assert(foo->name()->str() == "John Doe"); + assert(foo->count() == 42); + + std::cout << "The FlatBuffer was successfully created and accessed!" << std::endl; + + return 0; +} diff --git a/tests/auto/blackbox/testdata/flatbuf/flat_filename_extension.qbs b/tests/auto/blackbox/testdata/flatbuf/flat_filename_extension.qbs new file mode 100644 index 000000000..31eec7629 --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/flat_filename_extension.qbs @@ -0,0 +1,23 @@ +CppApplication { + Depends { name: "flatbuf.cpp"; required: false } + + consoleApplication: true + condition: { + var result = qbs.targetPlatform === qbs.hostPlatform; + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && hasFlatbuffers; + } + property bool hasFlatbuffers: { + console.info("has flatbuffers: " + flatbuf.cpp.present); + return flatbuf.cpp.present; + } + + flatbuf.cpp.filenameExtension: "hpp" + + files: [ + "flat_filename_extension.cpp", + "foo.fbs", + ] + qbsModuleProviders: "conan" +} diff --git a/tests/auto/blackbox/testdata/flatbuf/flat_filename_suffix.cpp b/tests/auto/blackbox/testdata/flatbuf/flat_filename_suffix.cpp new file mode 100644 index 000000000..630e4aaef --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/flat_filename_suffix.cpp @@ -0,0 +1,22 @@ +#include "foo.fbs.h" + +#include <iostream> + +using namespace QbsTest; + +int main() +{ + flatbuffers::FlatBufferBuilder builder; + auto name = builder.CreateString("John Doe"); + auto newFoo = QbsTest::CreateFoo(builder, name, 42); + builder.Finish(newFoo); + + auto foo = GetFoo(builder.GetBufferPointer()); + + assert(foo->name()->str() == "John Doe"); + assert(foo->count() == 42); + + std::cout << "The FlatBuffer was successfully created and accessed!" << std::endl; + + return 0; +} diff --git a/tests/auto/blackbox/testdata/flatbuf/flat_filename_suffix.qbs b/tests/auto/blackbox/testdata/flatbuf/flat_filename_suffix.qbs new file mode 100644 index 000000000..5103b041f --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/flat_filename_suffix.qbs @@ -0,0 +1,23 @@ +CppApplication { + Depends { name: "flatbuf.cpp"; required: false } + + consoleApplication: true + condition: { + var result = qbs.targetPlatform === qbs.hostPlatform; + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && hasFlatbuffers; + } + property bool hasFlatbuffers: { + console.info("has flatbuffers: " + flatbuf.cpp.present); + return flatbuf.cpp.present; + } + + flatbuf.cpp.filenameSuffix: ".fbs" + + files: [ + "flat_filename_suffix.cpp", + "foo.fbs", + ] + qbsModuleProviders: "conan" +} diff --git a/tests/auto/blackbox/testdata/flatbuf/flat_keep_prefix.cpp b/tests/auto/blackbox/testdata/flatbuf/flat_keep_prefix.cpp new file mode 100644 index 000000000..5f4b55e96 --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/flat_keep_prefix.cpp @@ -0,0 +1,26 @@ +#include "baz_generated.h" +#include "imported_foo/imported_foo_generated.h" + +#include <iostream> + +using namespace QbsTest; + +int main() +{ + flatbuffers::FlatBufferBuilder builder; + + auto name = builder.CreateString("John Doe"); + auto newFoo = QbsTest::CreateFoo(builder, name, 42); + + auto newBaz = QbsTest::CreateBaz(builder, newFoo); + builder.Finish(newBaz); + + auto baz = GetBaz(builder.GetBufferPointer()); + + assert(baz->foo()->name()->str() == "John Doe"); + assert(baz->foo()->count() == 42); + + std::cout << "The FlatBuffer was successfully created and accessed!" << std::endl; + + return 0; +} diff --git a/tests/auto/blackbox/testdata/flatbuf/flat_keep_prefix.qbs b/tests/auto/blackbox/testdata/flatbuf/flat_keep_prefix.qbs new file mode 100644 index 000000000..0ea0d1dac --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/flat_keep_prefix.qbs @@ -0,0 +1,25 @@ +CppApplication { + Depends { name: "flatbuf.cpp"; required: false } + + consoleApplication: true + condition: { + var result = qbs.targetPlatform === qbs.hostPlatform; + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && hasFlatbuffers; + } + property bool hasFlatbuffers: { + console.info("has flatbuffers: " + flatbuf.cpp.present); + return flatbuf.cpp.present; + } + + flatbuf.cpp.importPaths: "imports/" + flatbuf.cpp.keepPrefix: true + + files: [ + "flat_keep_prefix.cpp", + "baz.fbs", + "imports/imported_foo/imported_foo.fbs", + ] + qbsModuleProviders: "conan" +} diff --git a/tests/auto/blackbox/testdata/flatbuf/flat_relative_import.cpp b/tests/auto/blackbox/testdata/flatbuf/flat_relative_import.cpp new file mode 100644 index 000000000..bec6dadfd --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/flat_relative_import.cpp @@ -0,0 +1,25 @@ +#include "bar_generated.h" + +#include <iostream> + +using namespace QbsTest; + +int main() +{ + flatbuffers::FlatBufferBuilder builder; + + auto name = builder.CreateString("John Doe"); + auto newFoo = QbsTest::CreateFoo(builder, name, 42); + + auto newBar = QbsTest::CreateBar(builder, newFoo); + builder.Finish(newBar); + + auto bar = GetBar(builder.GetBufferPointer()); + + assert(bar->foo()->name()->str() == "John Doe"); + assert(bar->foo()->count() == 42); + + std::cout << "The FlatBuffer was successfully created and accessed!" << std::endl; + + return 0; +} diff --git a/tests/auto/blackbox/testdata/flatbuf/flat_relative_import.qbs b/tests/auto/blackbox/testdata/flatbuf/flat_relative_import.qbs new file mode 100644 index 000000000..f5a2c5d0b --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/flat_relative_import.qbs @@ -0,0 +1,22 @@ +CppApplication { + Depends { name: "flatbuf.cpp"; required: false } + + consoleApplication: true + condition: { + var result = qbs.targetPlatform === qbs.hostPlatform; + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && hasFlatbuffers; + } + property bool hasFlatbuffers: { + console.info("has flatbuffers: " + flatbuf.cpp.present); + return flatbuf.cpp.present; + } + + files: [ + "flat_relative_import.cpp", + "bar.fbs", + "foo.fbs", + ] + qbsModuleProviders: "conan" +} diff --git a/tests/auto/blackbox/testdata/flatbuf/foo.fbs b/tests/auto/blackbox/testdata/flatbuf/foo.fbs new file mode 100644 index 000000000..dff3b488f --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/foo.fbs @@ -0,0 +1,8 @@ +namespace QbsTest; + +table Foo { + name:string; + count:int; +} + +root_type Foo; diff --git a/tests/auto/blackbox/testdata/flatbuf/imports/imported_foo/imported_foo.fbs b/tests/auto/blackbox/testdata/flatbuf/imports/imported_foo/imported_foo.fbs new file mode 100644 index 000000000..dff3b488f --- /dev/null +++ b/tests/auto/blackbox/testdata/flatbuf/imports/imported_foo/imported_foo.fbs @@ -0,0 +1,8 @@ +namespace QbsTest; + +table Foo { + name:string; + count:int; +} + +root_type Foo; diff --git a/tests/auto/blackbox/testdata/freedesktop/freedesktop.qbs b/tests/auto/blackbox/testdata/freedesktop/freedesktop.qbs new file mode 100644 index 000000000..1efe5c91c --- /dev/null +++ b/tests/auto/blackbox/testdata/freedesktop/freedesktop.qbs @@ -0,0 +1,23 @@ +Project { + CppApplication { + name: "main" + install: true + files: [ + "main.cpp", + "myapp.desktop", + "myapp.appdata.xml", + ] + + Depends { name: "freedesktop" } + + freedesktop.appName: "My App" + freedesktop.desktopKeys: ({ + 'Icon': "myapp.png" + }) + + Group { + files: "myapp.png" + fileTags: "freedesktop.appIcon" + } + } +} diff --git a/tests/auto/blackbox/testdata/freedesktop/main.cpp b/tests/auto/blackbox/testdata/freedesktop/main.cpp new file mode 100644 index 000000000..905869dfa --- /dev/null +++ b/tests/auto/blackbox/testdata/freedesktop/main.cpp @@ -0,0 +1,4 @@ +int main() +{ + return 0; +} diff --git a/tests/auto/blackbox/testdata/freedesktop/myapp.appdata.xml b/tests/auto/blackbox/testdata/freedesktop/myapp.appdata.xml new file mode 100644 index 000000000..3cf0a5641 --- /dev/null +++ b/tests/auto/blackbox/testdata/freedesktop/myapp.appdata.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<component type="desktop"> + <id>myapp.desktop</id> + <metadata_license>CC0</metadata_license> + <name>MyApp</name> + <summary>The coolest app ever</summary> + + <description> + <p>This is a cool application.</p> + </description> + + <url type="homepage">https://software.house/myapp</url> + <project_license>GPL-2.0+</project_license> + <developer_name>Coding Wizard</developer_name> +</component> diff --git a/tests/auto/blackbox/testdata/freedesktop/myapp.desktop b/tests/auto/blackbox/testdata/freedesktop/myapp.desktop new file mode 100644 index 000000000..dac3014c3 --- /dev/null +++ b/tests/auto/blackbox/testdata/freedesktop/myapp.desktop @@ -0,0 +1,4 @@ +[Desktop Entry] +GenericName=Image Editor +Comment=Create images and edit photographs +Icon=overridden.png diff --git a/tests/auto/blackbox/testdata/freedesktop/myapp.png b/tests/auto/blackbox/testdata/freedesktop/myapp.png new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/freedesktop/myapp.png diff --git a/tests/auto/blackbox/testdata/generate-linker-map-file/generate-linker-map-file.qbs b/tests/auto/blackbox/testdata/generate-linker-map-file/generate-linker-map-file.qbs index 815e64853..0d67fa54c 100644 --- a/tests/auto/blackbox/testdata/generate-linker-map-file/generate-linker-map-file.qbs +++ b/tests/auto/blackbox/testdata/generate-linker-map-file/generate-linker-map-file.qbs @@ -2,11 +2,14 @@ Project { CppApplication { name: "app-map" files: ["main.cpp"] + // lld-link has different flag for map files, test it by switching to "lld" linkerVariant + Properties { condition: qbs.toolchain.includes("clang-cl"); cpp.linkerVariant: "lld" } cpp.generateLinkerMapFile: true } CppApplication { name: "app-nomap" files: ["main.cpp"] + Properties { condition: qbs.toolchain.includes("clang-cl"); cpp.linkerVariant: "lld" } cpp.generateLinkerMapFile: false } CppApplication { @@ -16,8 +19,8 @@ Project { Probe { id: toolchainProbe - property bool isUsed: qbs.toolchain.contains("msvc") - || qbs.toolchain.contains("gcc") + property bool isUsed: qbs.toolchain.includes("msvc") + || qbs.toolchain.includes("gcc") configure: { console.info("use test: " + isUsed); } diff --git a/tests/auto/blackbox/testdata/generator/generator.qbs b/tests/auto/blackbox/testdata/generator/generator.qbs index d0857beb5..9f6d452e7 100644 --- a/tests/auto/blackbox/testdata/generator/generator.qbs +++ b/tests/auto/blackbox/testdata/generator/generator.qbs @@ -18,12 +18,12 @@ CppApplication { var f = new TextFile(input.filePath, TextFile.ReadOnly); var content = f.readAll(); f.close(); - if (content.contains("file1")) { + if (content.includes("file1")) { f = new TextFile(outputs.file1[0].filePath, TextFile.WriteOnly); f.writeLine("void f1() {}"); f.close(); } - if (content.contains("file2")) { + if (content.includes("file2")) { f = new TextFile(outputs.file2[0].filePath, TextFile.WriteOnly); f.writeLine("void f2() {}"); f.close(); diff --git a/tests/auto/blackbox/testdata/groups-in-modules/groups-in-modules.qbs b/tests/auto/blackbox/testdata/groups-in-modules/groups-in-modules.qbs index 7347b1211..47275821f 100644 --- a/tests/auto/blackbox/testdata/groups-in-modules/groups-in-modules.qbs +++ b/tests/auto/blackbox/testdata/groups-in-modules/groups-in-modules.qbs @@ -1,11 +1,22 @@ +import qbs.Host + Project { Product { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } Depends { name: "dep" } Depends { name: "helper" } Depends { name: "helper3" required: false } + Depends { name: "helper7" } + helper7.fileName: "helper7.c" + type: ["diamond"] files: [ diff --git a/tests/auto/blackbox/testdata/groups-in-modules/imports/Helper7Base.qbs b/tests/auto/blackbox/testdata/groups-in-modules/imports/Helper7Base.qbs new file mode 100644 index 000000000..cc55e6351 --- /dev/null +++ b/tests/auto/blackbox/testdata/groups-in-modules/imports/Helper7Base.qbs @@ -0,0 +1,8 @@ +Module { + property string directory + property string fileName + Group { + prefix: directory + "/" + files: fileName + } +} diff --git a/tests/auto/blackbox/testdata/groups-in-modules/modules/helper/helper.qbs b/tests/auto/blackbox/testdata/groups-in-modules/modules/helper/helper.qbs index cbd30a35d..9dc903411 100644 --- a/tests/auto/blackbox/testdata/groups-in-modules/modules/helper/helper.qbs +++ b/tests/auto/blackbox/testdata/groups-in-modules/modules/helper/helper.qbs @@ -39,7 +39,7 @@ Module { prepare: { var cmd = new Command(FileInfo.joinPaths(product.buildDirectory, product.targetName), [input.filePath, output.filePath]); - cmd.description = "compile " + input.fileName + " => " + output.fileName; + cmd.description = "compiling " + input.fileName + " to " + output.fileName; return [cmd]; } } diff --git a/tests/auto/blackbox/testdata/groups-in-modules/modules/helper7/helper7.c b/tests/auto/blackbox/testdata/groups-in-modules/modules/helper7/helper7.c new file mode 100644 index 000000000..a83f5476e --- /dev/null +++ b/tests/auto/blackbox/testdata/groups-in-modules/modules/helper7/helper7.c @@ -0,0 +1 @@ +void helper7(void) {} diff --git a/tests/auto/blackbox/testdata/groups-in-modules/modules/helper7/helper7.qbs b/tests/auto/blackbox/testdata/groups-in-modules/modules/helper7/helper7.qbs new file mode 100644 index 000000000..90e1f11e2 --- /dev/null +++ b/tests/auto/blackbox/testdata/groups-in-modules/modules/helper7/helper7.qbs @@ -0,0 +1,3 @@ +Helper7Base { + directory: path +} diff --git a/tests/auto/blackbox/testdata/grpc/conanfile.txt b/tests/auto/blackbox/testdata/grpc/conanfile.txt new file mode 100644 index 000000000..f88e6e8d6 --- /dev/null +++ b/tests/auto/blackbox/testdata/grpc/conanfile.txt @@ -0,0 +1,7 @@ +[requires] +grpc/1.54.3 +[tool_requires] +protobuf/3.21.12 +grpc/1.54.3 +[generators] +QbsDeps diff --git a/tests/auto/blackbox/testdata/grpc/grpc.cpp b/tests/auto/blackbox/testdata/grpc/grpc.cpp index 81995601d..5f85c5b40 100644 --- a/tests/auto/blackbox/testdata/grpc/grpc.cpp +++ b/tests/auto/blackbox/testdata/grpc/grpc.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2019 Ivan Komissarov -** Contact: abbapoh@gmail.com +** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) +** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** diff --git a/tests/auto/blackbox/testdata/grpc/grpc_cpp.qbs b/tests/auto/blackbox/testdata/grpc/grpc_cpp.qbs index 8ee3dd9c9..d1bdd5d60 100644 --- a/tests/auto/blackbox/testdata/grpc/grpc_cpp.qbs +++ b/tests/auto/blackbox/testdata/grpc/grpc_cpp.qbs @@ -1,20 +1,29 @@ -import qbs +import qbs.Host CppApplication { name: "grpc_cpp" consoleApplication: true - condition: hasDependencies + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && hasDependencies; + } Depends { name: "cpp" } - cpp.cxxLanguageVersion: "c++11" + cpp.cxxLanguageVersion: "c++17" + cpp.minimumMacosVersion: "10.15" cpp.warningLevel: "none" + qbs.buildVariant: "release" Depends { name: "protobuf.cpp"; required: false } + Depends { name: "grpc++"; id: grpcpp; required: false } protobuf.cpp.useGrpc: true property bool hasDependencies: { console.info("has grpc: " + protobuf.cpp.present); - return protobuf.cpp.present; + console.info("has modules: " + grpcpp.present); + return protobuf.cpp.present && grpcpp.present; } files: "grpc.cpp" diff --git a/tests/auto/blackbox/testdata/host-os-properties/host-os-properties.qbs b/tests/auto/blackbox/testdata/host-os-properties/host-os-properties.qbs new file mode 100644 index 000000000..9d050e166 --- /dev/null +++ b/tests/auto/blackbox/testdata/host-os-properties/host-os-properties.qbs @@ -0,0 +1,16 @@ +import qbs.Host + +CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } + consoleApplication: true + cpp.defines: [ + 'HOST_ARCHITECTURE="' + Host.architecture() + '"', + 'HOST_PLATFORM="' + Host.platform() + '"' + ] + files: "main.cpp" +} diff --git a/tests/auto/blackbox/testdata/host-os-properties/main.cpp b/tests/auto/blackbox/testdata/host-os-properties/main.cpp new file mode 100644 index 000000000..129c16379 --- /dev/null +++ b/tests/auto/blackbox/testdata/host-os-properties/main.cpp @@ -0,0 +1,7 @@ +#include <cstdio> + +int main() { + std::printf("HOST_ARCHITECTURE = %s\n", HOST_ARCHITECTURE); + std::printf("HOST_PLATFORM = %s\n", HOST_PLATFORM); + return 0; +} diff --git a/tests/auto/blackbox/testdata/importing-product/importing-product.qbs b/tests/auto/blackbox/testdata/importing-product/importing-product.qbs index dfc4cd65e..54ad727b7 100644 --- a/tests/auto/blackbox/testdata/importing-product/importing-product.qbs +++ b/tests/auto/blackbox/testdata/importing-product/importing-product.qbs @@ -16,7 +16,7 @@ Project { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Copying file"; + cmd.description = "copying file"; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); } diff --git a/tests/auto/blackbox/testdata/includeLookup/includeLookup.qbs b/tests/auto/blackbox/testdata/includeLookup/includeLookup.qbs index 182d1e232..903d170d0 100644 --- a/tests/auto/blackbox/testdata/includeLookup/includeLookup.qbs +++ b/tests/auto/blackbox/testdata/includeLookup/includeLookup.qbs @@ -1,9 +1,16 @@ import qbs.FileInfo +import qbs.Host Project { property string name: 'includeLookup' qbsSearchPaths: '.' Product { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } type: 'application' consoleApplication: true name: project.name diff --git a/tests/auto/blackbox/testdata/includeLookup/main.cpp b/tests/auto/blackbox/testdata/includeLookup/main.cpp index c7213c768..a91914f73 100644 --- a/tests/auto/blackbox/testdata/includeLookup/main.cpp +++ b/tests/auto/blackbox/testdata/includeLookup/main.cpp @@ -30,7 +30,7 @@ int main() { - printf("%s..\n", TEXT); + std::printf("%s..\n", TEXT); return 0; } diff --git a/tests/auto/blackbox/testdata/input-tags-change-tracking/input-tags-change-tracking.qbs b/tests/auto/blackbox/testdata/input-tags-change-tracking/input-tags-change-tracking.qbs index ef2c5c55b..1e4248009 100644 --- a/tests/auto/blackbox/testdata/input-tags-change-tracking/input-tags-change-tracking.qbs +++ b/tests/auto/blackbox/testdata/input-tags-change-tracking/input-tags-change-tracking.qbs @@ -43,10 +43,10 @@ Product { inputs: "txt" outputFileTags: "p_tag" outputArtifacts: { - if (input.fileTags.contains("empty")) + if (input.fileTags.includes("empty")) return []; return [{ - filePath: input.fileTags.contains("y") ? "y.out" : "x.out", + filePath: input.fileTags.includes("y") ? "y.out" : "x.out", fileTags: "p_tag" }] } diff --git a/tests/auto/blackbox/testdata/inputs-from-dependencies/inputs-from-dependencies.qbs b/tests/auto/blackbox/testdata/inputs-from-dependencies/inputs-from-dependencies.qbs index 919060c73..f9993ecf3 100644 --- a/tests/auto/blackbox/testdata/inputs-from-dependencies/inputs-from-dependencies.qbs +++ b/tests/auto/blackbox/testdata/inputs-from-dependencies/inputs-from-dependencies.qbs @@ -37,7 +37,7 @@ Project { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Gathering text files"; + cmd.description = "gathering text files"; cmd.sourceCode = function() { for (i in inputs.txt) console.info(inputs.txt[i].filePath); diff --git a/tests/auto/blackbox/testdata/install-locations/install-locations.qbs b/tests/auto/blackbox/testdata/install-locations/install-locations.qbs index 8a97f74a1..ba51c0dc1 100644 --- a/tests/auto/blackbox/testdata/install-locations/install-locations.qbs +++ b/tests/auto/blackbox/testdata/install-locations/install-locations.qbs @@ -1,16 +1,24 @@ Project { property bool dummy: { - if (qbs.targetOS.contains("windows")) + if (qbs.targetOS.includes("windows")) { console.info("is windows"); - else if (qbs.targetOS.contains("macos")) - console.info("is mac"); - else + } else if (qbs.targetOS.includes("darwin")) { + console.info("is darwin"); + if (qbs.targetOS.includes("macos")) + console.info("is mac"); + } else { console.info("is unix"); + } + + if (qbs.toolchain.includes("mingw")) + console.info("is mingw"); } CppApplication { name: "theapp" install: true + installDebugInformation: true files: "main.cpp" + cpp.separateDebugInformation: true Group { fileTagsFilter: "application" fileTags: "some-tag" @@ -20,7 +28,17 @@ Project { name: "thelib" install: true installImportLib: true + installDebugInformation: true Depends { name: "cpp" } + cpp.separateDebugInformation: true files: "thelib.cpp" } + LoadableModule { + name: "theplugin" + install: true + installDebugInformation: true + Depends { name: "cpp" } + cpp.separateDebugInformation: true + files: "theplugin.cpp" + } } diff --git a/tests/auto/blackbox/testdata/install-locations/theplugin.cpp b/tests/auto/blackbox/testdata/install-locations/theplugin.cpp new file mode 100644 index 000000000..ac1ede090 --- /dev/null +++ b/tests/auto/blackbox/testdata/install-locations/theplugin.cpp @@ -0,0 +1,3 @@ +#include "../dllexport.h" + +DLL_EXPORT void pluginFunc() {} diff --git a/tests/auto/blackbox/testdata/installable-as-auxiliary-input/installable-as-auxiliary-input.qbs b/tests/auto/blackbox/testdata/installable-as-auxiliary-input/installable-as-auxiliary-input.qbs index 2d37e85d6..a445fc35b 100644 --- a/tests/auto/blackbox/testdata/installable-as-auxiliary-input/installable-as-auxiliary-input.qbs +++ b/tests/auto/blackbox/testdata/installable-as-auxiliary-input/installable-as-auxiliary-input.qbs @@ -1,10 +1,17 @@ import qbs.File import qbs.FileInfo +import qbs.Host import qbs.TextFile Project { name: "p" CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: "app" Depends { name: "installed-header" } Rule { @@ -42,7 +49,7 @@ Project { Export { Depends { name: "cpp" } - cpp.includePaths: FileInfo.joinPaths(qbs.installRoot, product.installDir); + cpp.includePaths: FileInfo.joinPaths(qbs.installRoot, exportingProduct.installDir); } Rule { @@ -50,7 +57,7 @@ Project { Artifact { filePath: "theheader.h.in"; fileTags: "header.in" } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Creating " + output.fileName; + cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { for (var i = 0; i < 1000; ++i) { // Artificial delay. var file = new TextFile(output.filePath, TextFile.WriteOnly); @@ -69,7 +76,7 @@ Project { Artifact { filePath: "theheader.h"; fileTags: "header" } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Creating " + output.fileName; + cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }; return [cmd]; } diff --git a/tests/auto/blackbox/testdata/installable/installable.qbs b/tests/auto/blackbox/testdata/installable/installable.qbs index 56feb6ec5..de93cf61f 100644 --- a/tests/auto/blackbox/testdata/installable/installable.qbs +++ b/tests/auto/blackbox/testdata/installable/installable.qbs @@ -11,6 +11,7 @@ Project { } install: true + installDebugInformation: false installDir: "" } @@ -27,7 +28,7 @@ Project { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Creating " + output.fileName; + cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { var file = new TextFile(output.filePath, TextFile.WriteOnly); for (var i = 0; i < inputs.installable.length; ++i) diff --git a/tests/auto/blackbox/testdata/installed-transformer-output/qbs668.qbs b/tests/auto/blackbox/testdata/installed-transformer-output/qbs668.qbs index aa40b7691..6f84206be 100644 --- a/tests/auto/blackbox/testdata/installed-transformer-output/qbs668.qbs +++ b/tests/auto/blackbox/testdata/installed-transformer-output/qbs668.qbs @@ -18,7 +18,7 @@ Product { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Creating file:'" + output.fileName + "'"; + cmd.description = "creating file:'" + output.fileName + "'"; cmd.highlight = "codegen"; cmd.sourceCode = function() { var file = new TextFile(output.filePath, TextFile.WriteOnly); diff --git a/tests/auto/blackbox/testdata/installpackage/installpackage.qbs b/tests/auto/blackbox/testdata/installpackage/installpackage.qbs index a0649a578..3396b79a4 100644 --- a/tests/auto/blackbox/testdata/installpackage/installpackage.qbs +++ b/tests/auto/blackbox/testdata/installpackage/installpackage.qbs @@ -2,7 +2,7 @@ Project { CppApplication { name: "public_tool" Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } Depends { name: "mylib" } @@ -20,7 +20,7 @@ Project { } DynamicLibrary { Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } Depends { name: "cpp" } diff --git a/tests/auto/blackbox/testdata/invalid-artifact-path/invalid-artifact-path.qbs b/tests/auto/blackbox/testdata/invalid-artifact-path/invalid-artifact-path.qbs new file mode 100644 index 000000000..650233d86 --- /dev/null +++ b/tests/auto/blackbox/testdata/invalid-artifact-path/invalid-artifact-path.qbs @@ -0,0 +1,18 @@ +Project { + property string artifactDir + Product { + type: "t" + Rule { + multiplex: true + Artifact { + filePath: project.artifactDir + "/file.out" + fileTags: "t" + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.sourceCode = function() {}; + return cmd; + } + } + } +} diff --git a/tests/auto/blackbox/testdata/invalid-command-property/invalid-command-property.qbs b/tests/auto/blackbox/testdata/invalid-command-property/invalid-command-property.qbs index b08fcd4a3..a07beda57 100644 --- a/tests/auto/blackbox/testdata/invalid-command-property/invalid-command-property.qbs +++ b/tests/auto/blackbox/testdata/invalid-command-property/invalid-command-property.qbs @@ -16,7 +16,7 @@ Product { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Creating output"; + cmd.description = "creating output"; if (product.errorType === "qobject") cmd.dummy = new TextFile(input.filePath, TextFile.ReadOnly); else if (product.errorType === "input") diff --git a/tests/auto/blackbox/testdata/jsextensions-binaryfile/binaryfile.qbs b/tests/auto/blackbox/testdata/jsextensions-binaryfile/binaryfile.qbs index 1e7426744..5824fe518 100644 --- a/tests/auto/blackbox/testdata/jsextensions-binaryfile/binaryfile.qbs +++ b/tests/auto/blackbox/testdata/jsextensions-binaryfile/binaryfile.qbs @@ -36,6 +36,9 @@ Product { destination.write(source.atEof() ? [ 0xFF ] : [ 0x00 ]); source.close(); destination.close(); + source = new BinaryFile("destination.dat", BinaryFile.ReadOnly); + destination = new BinaryFile("destination2.dat", BinaryFile.WriteOnly); + destination.write(source.read(8)); }; commands.push(cmd); return commands; diff --git a/tests/auto/blackbox/testdata/jsextensions-file/file.qbs b/tests/auto/blackbox/testdata/jsextensions-file/file.qbs index 6adf714e2..7a47cf3cd 100644 --- a/tests/auto/blackbox/testdata/jsextensions-file/file.qbs +++ b/tests/auto/blackbox/testdata/jsextensions-file/file.qbs @@ -33,10 +33,10 @@ Product { if (!created || !File.exists(zePath)) throw new Error("zePath was not created."); var entries = File.directoryEntries(product.sourceDirectory, File.AllEntries | File.NoDotAndDotDot); - if (entries.length < 3 || !entries.contains("file.qbs")) + if (entries.length < 3 || !entries.includes("file.qbs")) throw new Error("Directory did not contain file.qbs"); entries = File.directoryEntries(product.sourceDirectory, File.Dirs | File.NoDotAndDotDot); - if (entries.length < 1 || !entries.contains("zePath")) + if (entries.length < 1 || !entries.includes("zePath")) throw new Error("Directory did not contain only zePath"); var moveSource = FileInfo.joinPaths(product.sourceDirectory, "tomove.txt"); var moveTarget = FileInfo.joinPaths(product.sourceDirectory, "moved.txt"); diff --git a/tests/auto/blackbox/testdata/jsextensions-fileinfo/fileinfo.qbs b/tests/auto/blackbox/testdata/jsextensions-fileinfo/fileinfo.qbs index d63ba2962..0e727d04b 100644 --- a/tests/auto/blackbox/testdata/jsextensions-fileinfo/fileinfo.qbs +++ b/tests/auto/blackbox/testdata/jsextensions-fileinfo/fileinfo.qbs @@ -39,6 +39,8 @@ Product { output.writeLine(FileInfo.relativePath("/tmp", "/blubb.tar.gz")); output.writeLine(FileInfo.toWindowsSeparators("/tmp/blubb.tar.gz")); output.writeLine(FileInfo.toWindowsSeparators("c:\\tmp\\blubb.tar.gz")); + output.writeLine(FileInfo.pathListSeparator()); + output.writeLine(FileInfo.pathSeparator()); output.close(); }; return [cmd]; diff --git a/tests/auto/blackbox/testdata/jsextensions-host/host.qbs b/tests/auto/blackbox/testdata/jsextensions-host/host.qbs new file mode 100644 index 000000000..08d13b25d --- /dev/null +++ b/tests/auto/blackbox/testdata/jsextensions-host/host.qbs @@ -0,0 +1,31 @@ +import qbs.FileInfo +import qbs.Host +import qbs.TextFile + +Product { + type: ["dummy"] + Rule { + multiplex: true + outputFileTags: "dummy" + prepare: { + var cmd = new JavaScriptCommand(); + cmd.silent = true; + cmd.sourceCode = function() { + var output = new TextFile(FileInfo.joinPaths(product.sourceDirectory, "output.txt"), + TextFile.WriteOnly); + output.writeLine("architecture: " +Host.architecture()); + output.writeLine("os: " + Host.os()); + output.writeLine("platform: " + Host.platform()); + output.writeLine("osVersion: " + Host.osVersion()); + output.writeLine("osBuildVersion: " + Host.osBuildVersion()); + output.writeLine("osVersionParts: " + Host.osVersionParts()); + output.writeLine("osVersionMajor: " + Host.osVersionMajor()); + output.writeLine("osVersionMinor: " + Host.osVersionMinor()); + output.writeLine("osVersionPatch: " + Host.osVersionPatch()); + output.writeLine("nullDevice: " + Host.nullDevice()); + output.close(); + }; + return [cmd]; + } + } +} diff --git a/tests/auto/blackbox/testdata/jsextensions-process/main.cpp b/tests/auto/blackbox/testdata/jsextensions-process/main.cpp index df769de87..3f28fe091 100644 --- a/tests/auto/blackbox/testdata/jsextensions-process/main.cpp +++ b/tests/auto/blackbox/testdata/jsextensions-process/main.cpp @@ -4,17 +4,17 @@ int main(int argc, char *argv[]) { - if (argc != 2 || strcmp(argv[1], "help") != 0) { - fprintf(stderr, "First argument to this program must be 'help'.\n"); + if (argc != 2 || std::strcmp(argv[1], "help") != 0) { + std::fprintf(stderr, "First argument to this program must be 'help'.\n"); return 1; } const char *env = std::getenv("SOME_ENV"); - if (!env || strcmp(env, "why, hello!") != 0) { - fprintf(stderr, "The SOME_ENV environment variable must be 'why, hello!'.\n"); + if (!env || std::strcmp(env, "why, hello!") != 0) { + std::fprintf(stderr, "The SOME_ENV environment variable must be 'why, hello!'.\n"); return 1; } - printf("qbs jsextensions-process test\n"); + std::printf("qbs jsextensions-process test\n"); return 0; } diff --git a/tests/auto/blackbox/testdata/jsextensions-process/process.qbs b/tests/auto/blackbox/testdata/jsextensions-process/process.qbs index eba95d005..50f22cdfc 100644 --- a/tests/auto/blackbox/testdata/jsextensions-process/process.qbs +++ b/tests/auto/blackbox/testdata/jsextensions-process/process.qbs @@ -1,10 +1,17 @@ import qbs.Environment import qbs.FileInfo +import qbs.Host import qbs.Process import qbs.TextFile Project { Product { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } Depends { name: "cpp" } type: ["dummy"] name: "dummy" @@ -48,7 +55,7 @@ Project { // closeWriteChannel test process = new Process(); - if (product.qbs.hostOS.contains("windows")) + if (Host.os().includes("windows")) process.start(product.qbs.windowsShellPath, ["/C", product.qbs.windowsSystemRoot + "\\system32\\sort.exe"]); else @@ -69,7 +76,7 @@ Project { testReadlineFile.close(); process = new Process(); - if (product.qbs.hostOS.contains("windows")) + if (Host.os().includes("windows")) process.exec(product.qbs.windowsShellPath, ["/C", "type", "123.txt"], true); diff --git a/tests/auto/blackbox/testdata/last-module-candidate-broken/last-module-candidate-broken.qbs b/tests/auto/blackbox/testdata/last-module-candidate-broken/last-module-candidate-broken.qbs new file mode 100644 index 000000000..db7dc2265 --- /dev/null +++ b/tests/auto/blackbox/testdata/last-module-candidate-broken/last-module-candidate-broken.qbs @@ -0,0 +1,5 @@ +CppApplication { + qbsSearchPaths: "qbs" + Depends { name: "Foo" } + files: "main.cpp" +} diff --git a/tests/auto/blackbox/testdata/last-module-candidate-broken/main.cpp b/tests/auto/blackbox/testdata/last-module-candidate-broken/main.cpp new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/blackbox/testdata/last-module-candidate-broken/main.cpp @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/Foo1.qbs b/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/Foo1.qbs new file mode 100644 index 000000000..ba08b862b --- /dev/null +++ b/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/Foo1.qbs @@ -0,0 +1,3 @@ +Module { + condition: false +} diff --git a/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/Foo2.qbs b/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/Foo2.qbs new file mode 100644 index 000000000..0bc383b86 --- /dev/null +++ b/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/Foo2.qbs @@ -0,0 +1,2 @@ +Group { +} diff --git a/tests/auto/blackbox/testdata/ld/ld.qbs b/tests/auto/blackbox/testdata/ld/ld.qbs index 25fede1b0..cb04d3d9a 100644 --- a/tests/auto/blackbox/testdata/ld/ld.qbs +++ b/tests/auto/blackbox/testdata/ld/ld.qbs @@ -5,7 +5,7 @@ Project { targetName: "qbs can handle any file paths, even the crazy ones! ;)" files: ["coreutils.cpp", "coreutils.h"] Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false cpp.sonamePrefix: "@rpath" } diff --git a/tests/auto/blackbox/testdata/ld/main.cpp b/tests/auto/blackbox/testdata/ld/main.cpp index fd6b72f3b..bcf293705 100644 --- a/tests/auto/blackbox/testdata/ld/main.cpp +++ b/tests/auto/blackbox/testdata/ld/main.cpp @@ -27,10 +27,11 @@ ****************************************************************************/ #include "coreutils.h" -#include <stdio.h> + +#include <cstdio> int main(int argc, char *argv[]) { - printf("%d\n", foo()); + std::printf("%d\n", foo()); return 0; } diff --git a/tests/auto/blackbox/testdata/lexyacc/modules/bisonhelper/bisonhelper.qbs b/tests/auto/blackbox/testdata/lexyacc/modules/bisonhelper/bisonhelper.qbs index 449b130e2..4cce9a1e3 100644 --- a/tests/auto/blackbox/testdata/lexyacc/modules/bisonhelper/bisonhelper.qbs +++ b/tests/auto/blackbox/testdata/lexyacc/modules/bisonhelper/bisonhelper.qbs @@ -1,4 +1,3 @@ -import qbs import qbs.Process Module { @@ -8,7 +7,7 @@ Module { property string yaccBinary: lex_yacc.yaccBinary configure: { var p = Process(); - found = p.exec(yaccBinary, ["-V"]) == 0 && p.readStdOut().contains("bison"); + found = p.exec(yaccBinary, ["-V"]) == 0 && p.readStdOut().includes("bison"); p.close(); } } diff --git a/tests/auto/blackbox/testdata/lexyacc/one-grammar/one-grammar.qbs b/tests/auto/blackbox/testdata/lexyacc/one-grammar/one-grammar.qbs index 6cd334247..faa5d1fac 100644 --- a/tests/auto/blackbox/testdata/lexyacc/one-grammar/one-grammar.qbs +++ b/tests/auto/blackbox/testdata/lexyacc/one-grammar/one-grammar.qbs @@ -1,4 +1,12 @@ +import qbs.Host + CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } qbsSearchPaths: ".." Depends { name: "bisonhelper" } Depends { name: "lex_yacc" } @@ -11,10 +19,10 @@ CppApplication { Probe { id: pathCheck property string theDir: { - if (qbs.targetOS.contains("windows")) { - if (qbs.toolchain.contains("mingw")) + if (qbs.targetOS.includes("windows")) { + if (qbs.toolchain.includes("mingw")) return cpp.toolchainInstallPath; - if (qbs.toolchain.contains("clang") && qbs.sysroot) + if (qbs.toolchain.includes("clang") && qbs.sysroot) return qbs.sysroot + "/bin"; } } diff --git a/tests/auto/blackbox/testdata/lexyacc/two-grammars/two-grammars.qbs b/tests/auto/blackbox/testdata/lexyacc/two-grammars/two-grammars.qbs index 7b0c1e515..648860d9c 100644 --- a/tests/auto/blackbox/testdata/lexyacc/two-grammars/two-grammars.qbs +++ b/tests/auto/blackbox/testdata/lexyacc/two-grammars/two-grammars.qbs @@ -1,7 +1,13 @@ +import qbs.Host + CppApplication { Depends { name: "lex_yacc" } consoleApplication: true cpp.includePaths: ".." + Properties { + condition: Host.os().includes("darwin") && qbs.toolchain.includes("clang") + cpp.cFlags: "-Wno-implicit-function-declaration" + } files: [ "g1.l", "g1.y", diff --git a/tests/auto/blackbox/testdata/linker-library-duplicates/setup-run-environment.qbs b/tests/auto/blackbox/testdata/linker-library-duplicates/setup-run-environment.qbs index 9723fd3f5..c41e8f1d7 100644 --- a/tests/auto/blackbox/testdata/linker-library-duplicates/setup-run-environment.qbs +++ b/tests/auto/blackbox/testdata/linker-library-duplicates/setup-run-environment.qbs @@ -1,5 +1,3 @@ -import qbs 1.0 - Project { DynamicLibrary { id: idLib1 @@ -8,6 +6,11 @@ Project { files: ["lib1.cpp"] Depends { name: "bundle" } bundle.isBundle: false + Probe { + id: checker + property bool isGcc: qbs.toolchain.contains("gcc") + configure: { console.info("is gcc: " + isGcc); } + } } DynamicLibrary { diff --git a/tests/auto/blackbox/testdata/linker-module-definition/linker-module-definition.qbs b/tests/auto/blackbox/testdata/linker-module-definition/linker-module-definition.qbs new file mode 100644 index 000000000..cae80e651 --- /dev/null +++ b/tests/auto/blackbox/testdata/linker-module-definition/linker-module-definition.qbs @@ -0,0 +1,20 @@ +import qbs.Host + +Project { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } + DynamicLibrary { + name: "testlib" + Depends { name: "cpp"} + files: ["testlib.cpp", "testlib.def"] + } + CppApplication { + name: "testapp" + Depends { name: "testlib"} + files: ["testapp.cpp"] + } +} diff --git a/tests/auto/blackbox/testdata/linker-module-definition/testapp.cpp b/tests/auto/blackbox/testdata/linker-module-definition/testapp.cpp new file mode 100644 index 000000000..7cb5ee901 --- /dev/null +++ b/tests/auto/blackbox/testdata/linker-module-definition/testapp.cpp @@ -0,0 +1,39 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +extern void foo(); +extern void bar(); + +int main() +{ + foo(); + bar(); + return 0; +} diff --git a/tests/auto/blackbox/testdata/linker-module-definition/testlib.cpp b/tests/auto/blackbox/testdata/linker-module-definition/testlib.cpp new file mode 100644 index 000000000..4af8dd9bb --- /dev/null +++ b/tests/auto/blackbox/testdata/linker-module-definition/testlib.cpp @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include <cstdio> + +void foo() +{ + std::printf("foo\n"); +} + +void bar() +{ + std::printf("bar\n"); +} diff --git a/tests/auto/blackbox/testdata/linker-module-definition/testlib.def b/tests/auto/blackbox/testdata/linker-module-definition/testlib.def new file mode 100644 index 000000000..36967ddd5 --- /dev/null +++ b/tests/auto/blackbox/testdata/linker-module-definition/testlib.def @@ -0,0 +1,3 @@ +EXPORTS +foo +bar diff --git a/tests/auto/blackbox/testdata/linker-variant/linker-variant.qbs b/tests/auto/blackbox/testdata/linker-variant/linker-variant.qbs index 57bd4ccba..9256bf767 100644 --- a/tests/auto/blackbox/testdata/linker-variant/linker-variant.qbs +++ b/tests/auto/blackbox/testdata/linker-variant/linker-variant.qbs @@ -3,7 +3,7 @@ CppApplication { property string linkerVariant Probe { id: gccProbe - property bool isGcc: qbs.toolchain.contains("gcc") + property bool isGcc: qbs.toolchain.includes("gcc") configure: { console.info("is GCC: " + isGcc); if (isGcc) diff --git a/tests/auto/blackbox/testdata/linkerMode/darwin.s b/tests/auto/blackbox/testdata/linkerMode/darwin.s new file mode 100644 index 000000000..fb165114b --- /dev/null +++ b/tests/auto/blackbox/testdata/linkerMode/darwin.s @@ -0,0 +1,6 @@ +.globl _main +.globl main + +_main: +main: + ret diff --git a/tests/auto/blackbox/testdata/linkerMode/linkerMode.qbs b/tests/auto/blackbox/testdata/linkerMode/linkerMode.qbs index 1be50c0aa..176730ce0 100644 --- a/tests/auto/blackbox/testdata/linkerMode/linkerMode.qbs +++ b/tests/auto/blackbox/testdata/linkerMode/linkerMode.qbs @@ -2,7 +2,7 @@ Project { CppApplication { consoleApplication: true name: "LinkedProduct-Assembly" - files: ["main.s"] + files: qbs.targetOS.includes("darwin") ? "darwin.s" : "main.s" cpp.linkerPath: cpp.compilerPathByLanguage["c"] @@ -24,7 +24,7 @@ Project { } CppApplication { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") consoleApplication: true name: "LinkedProduct-Objective-C" @@ -50,7 +50,7 @@ Project { } CppApplication { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") consoleApplication: true name: "LinkedProduct-Objective-C++" diff --git a/tests/auto/blackbox/testdata/linkerscripts/linkerscripts.qbs b/tests/auto/blackbox/testdata/linkerscripts/linkerscripts.qbs index 0b4de0ab9..6d068b6a2 100644 --- a/tests/auto/blackbox/testdata/linkerscripts/linkerscripts.qbs +++ b/tests/auto/blackbox/testdata/linkerscripts/linkerscripts.qbs @@ -55,6 +55,13 @@ DynamicLibrary { } } + Probe { + id: checker + property bool isGcc: qbs.toolchain.contains("gcc") + property bool isLinux: qbs.targetOS.contains("linux") + configure: { console.info("is Linux gcc: " + (isGcc && isLinux)) } + } + qbs.installPrefix: "" install: true installDir: "" diff --git a/tests/auto/blackbox/testdata/list-property-order/modules/lower/lower.qbs b/tests/auto/blackbox/testdata/list-property-order/modules/lower/lower.qbs index df9181641..c47a40aea 100644 --- a/tests/auto/blackbox/testdata/list-property-order/modules/lower/lower.qbs +++ b/tests/auto/blackbox/testdata/list-property-order/modules/lower/lower.qbs @@ -1,5 +1,5 @@ Module { - property stringList listProp + property stringList listProp: [ "lower" ] Rule { inputs: ["intype"] diff --git a/tests/auto/blackbox/testdata/list-property-order/product.qbs b/tests/auto/blackbox/testdata/list-property-order/product.qbs index e92494693..bec122214 100644 --- a/tests/auto/blackbox/testdata/list-property-order/product.qbs +++ b/tests/auto/blackbox/testdata/list-property-order/product.qbs @@ -4,6 +4,7 @@ Product { Depends { name: "higher1" } Depends { name: "higher2" } Depends { name: "higher3" } + lower.listProp: ["product"] Group { files: ["dummy.txt"] fileTags: ["intype"] diff --git a/tests/auto/blackbox/testdata/loadablemodule/loadablemodule.qbs b/tests/auto/blackbox/testdata/loadablemodule/loadablemodule.qbs index ec5b0b358..8023eed36 100644 --- a/tests/auto/blackbox/testdata/loadablemodule/loadablemodule.qbs +++ b/tests/auto/blackbox/testdata/loadablemodule/loadablemodule.qbs @@ -1,8 +1,10 @@ +import qbs.Host + Project { LoadableModule { Depends { name: "cpp" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } name: "CoolPlugIn" @@ -15,6 +17,12 @@ Project { } CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } Depends { name: "cpp" } Depends { name: "CoolPlugIn"; cpp.link: false } consoleApplication: true @@ -22,10 +30,10 @@ Project { files: ["main.cpp"] cpp.cxxLanguageVersion: "c++11" - cpp.dynamicLibraries: [qbs.targetOS.contains("windows") ? "kernel32" : "dl"] + cpp.dynamicLibraries: [qbs.targetOS.includes("windows") ? "kernel32" : "dl"] Properties { - condition: qbs.targetOS.contains("unix") && !qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("unix") && !qbs.targetOS.includes("darwin") cpp.rpaths: [cpp.rpathOrigin] } diff --git a/tests/auto/blackbox/testdata/localDeployment/localDeployment.qbs b/tests/auto/blackbox/testdata/localDeployment/localDeployment.qbs index 650f07104..b3fa86d32 100644 --- a/tests/auto/blackbox/testdata/localDeployment/localDeployment.qbs +++ b/tests/auto/blackbox/testdata/localDeployment/localDeployment.qbs @@ -1,5 +1,13 @@ +import qbs.Host + Project { Product { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } type: ["application"] consoleApplication: true name: "HelloWorld" diff --git a/tests/auto/blackbox/testdata/lsp/lsp.qbs b/tests/auto/blackbox/testdata/lsp/lsp.qbs new file mode 100644 index 000000000..24479e0ec --- /dev/null +++ b/tests/auto/blackbox/testdata/lsp/lsp.qbs @@ -0,0 +1,11 @@ +Project { + Product { + name: "dep" + Depends { name: "m" } + Depends { name: "Prefix"; submodules: ["m1", "m2", "m3"] } + + } + Product { + Depends { name: "dep" } + } +} diff --git a/tests/auto/blackbox/testdata/lsp/modules/Prefix/m1/m1.qbs b/tests/auto/blackbox/testdata/lsp/modules/Prefix/m1/m1.qbs new file mode 100644 index 000000000..09bac2dc2 --- /dev/null +++ b/tests/auto/blackbox/testdata/lsp/modules/Prefix/m1/m1.qbs @@ -0,0 +1,5 @@ +Module { + property bool p1 + property string p2 + property bool x +} diff --git a/tests/auto/language/testdata/erroneous/modules/prefix1/prefix1.qbs b/tests/auto/blackbox/testdata/lsp/modules/Prefix/m2/m2.qbs index 84957060c..84957060c 100644 --- a/tests/auto/language/testdata/erroneous/modules/prefix1/prefix1.qbs +++ b/tests/auto/blackbox/testdata/lsp/modules/Prefix/m2/m2.qbs diff --git a/tests/auto/blackbox/testdata/lsp/modules/Prefix/m3/m3.qbs b/tests/auto/blackbox/testdata/lsp/modules/Prefix/m3/m3.qbs new file mode 100644 index 000000000..84957060c --- /dev/null +++ b/tests/auto/blackbox/testdata/lsp/modules/Prefix/m3/m3.qbs @@ -0,0 +1,2 @@ +Module { +} diff --git a/tests/auto/blackbox/testdata/lsp/modules/m/m.qbs b/tests/auto/blackbox/testdata/lsp/modules/m/m.qbs new file mode 100644 index 000000000..84957060c --- /dev/null +++ b/tests/auto/blackbox/testdata/lsp/modules/m/m.qbs @@ -0,0 +1,2 @@ +Module { +} diff --git a/tests/auto/blackbox/testdata/makefile-generator/app.qbs b/tests/auto/blackbox/testdata/makefile-generator/app.qbs index dfd67276e..fd3fbb91b 100644 --- a/tests/auto/blackbox/testdata/makefile-generator/app.qbs +++ b/tests/auto/blackbox/testdata/makefile-generator/app.qbs @@ -1,11 +1,19 @@ +import qbs.Host + CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: "the app" consoleApplication: true cpp.cxxLanguageVersion: "c++11" cpp.separateDebugInformation: false Properties { - condition: qbs.targetOS.contains("macos") + condition: qbs.targetOS.includes("macos") bundle.embedInfoPlist: false cpp.minimumMacosVersion: "10.7" } diff --git a/tests/auto/blackbox/testdata/maximum-c-language-version/maximum-c-language-version.qbs b/tests/auto/blackbox/testdata/maximum-c-language-version/maximum-c-language-version.qbs index 320494d00..9f41570f8 100644 --- a/tests/auto/blackbox/testdata/maximum-c-language-version/maximum-c-language-version.qbs +++ b/tests/auto/blackbox/testdata/maximum-c-language-version/maximum-c-language-version.qbs @@ -4,10 +4,13 @@ CppApplication { Probe { id: osProbe - property stringList toolchain: qbs.toolchain + property string toolchainType: qbs.toolchainType + property string compilerVersion: cpp.compilerVersion configure: { - if (toolchain.contains("msvc")) - console.info("is msvc"); + console.info("is msvc: " + (toolchainType === "msvc" || toolchainType === "clang-cl")); + var isOld = (toolchainType === "msvc" && compilerVersion < "19.29.30138") + || (toolchainType === "clang-cl" && compilerVersion < "13"); + console.info("is old msvc: " + isOld); found = true; } } diff --git a/tests/auto/blackbox/testdata/maximum-cxx-language-version/modules/newestmodule/newestmodule.qbs b/tests/auto/blackbox/testdata/maximum-cxx-language-version/modules/newestmodule/newestmodule.qbs index f99932b10..305cb29f1 100644 --- a/tests/auto/blackbox/testdata/maximum-cxx-language-version/modules/newestmodule/newestmodule.qbs +++ b/tests/auto/blackbox/testdata/maximum-cxx-language-version/modules/newestmodule/newestmodule.qbs @@ -1,4 +1,4 @@ Module { Depends { name: "cpp" } - cpp.cxxLanguageVersion: "c++17" + cpp.cxxLanguageVersion: "c++23" } diff --git a/tests/auto/blackbox/testdata/minimumSystemVersion/fakewindows.qbs b/tests/auto/blackbox/testdata/minimumSystemVersion/fakewindows.qbs index 1a56e0b7e..da836e609 100644 --- a/tests/auto/blackbox/testdata/minimumSystemVersion/fakewindows.qbs +++ b/tests/auto/blackbox/testdata/minimumSystemVersion/fakewindows.qbs @@ -4,7 +4,7 @@ import qbs.Utilities // (but will still compile and link since we avoid passing a // bad value to the linker) CppApplication { - condition: qbs.targetOS.contains("windows") + condition: qbs.targetOS.includes("windows") files: ["main.cpp"] consoleApplication: true cpp.minimumWindowsVersion: "5.3" diff --git a/tests/auto/blackbox/testdata/minimumSystemVersion/macappstore.qbs b/tests/auto/blackbox/testdata/minimumSystemVersion/macappstore.qbs index 8440da779..26a94e132 100644 --- a/tests/auto/blackbox/testdata/minimumSystemVersion/macappstore.qbs +++ b/tests/auto/blackbox/testdata/minimumSystemVersion/macappstore.qbs @@ -1,8 +1,15 @@ // just to make sure three-digit minimum versions work on macOS // this only affects the value of __MAC_OS_X_VERSION_MIN_REQUIRED, // not the actual LC_VERSION_MIN_MACOSX command which is limited to two +import qbs.Host + CppApplication { - condition: qbs.targetOS.contains("macos") + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && qbs.targetOS.includes("macos"); + } files: ["main.mm"] consoleApplication: true cpp.frameworks: "Foundation" diff --git a/tests/auto/blackbox/testdata/minimumSystemVersion/specific.qbs b/tests/auto/blackbox/testdata/minimumSystemVersion/specific.qbs index f6ecab418..b2b67642a 100644 --- a/tests/auto/blackbox/testdata/minimumSystemVersion/specific.qbs +++ b/tests/auto/blackbox/testdata/minimumSystemVersion/specific.qbs @@ -3,22 +3,29 @@ import qbs.Utilities // a specific version of the operating systems is specified // when the application is run its output should confirm // that the given values took effect +import qbs.Host + CppApplication { - condition: qbs.targetOS.contains("windows") || qbs.targetOS.contains("macos") - files: [qbs.targetOS.contains("darwin") ? "main.mm" : "main.cpp"] + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && qbs.targetOS.includes("windows") || qbs.targetOS.includes("macos"); + } + files: [qbs.targetOS.includes("darwin") ? "main.mm" : "main.cpp"] consoleApplication: true Properties { - condition: qbs.targetOS.contains("windows") - cpp.minimumWindowsVersion: "6.0" + condition: qbs.targetOS.includes("windows") + cpp.minimumWindowsVersion: "6.2" cpp.defines: [ - "QBS_WINVER=0x600", + "QBS_WINVER=0x602", "TOOLCHAIN_INSTALL_PATH=" + Utilities.cStringQuote(cpp.toolchainInstallPath) ] } Properties { - condition: qbs.targetOS.contains("macos") + condition: qbs.targetOS.includes("macos") cpp.frameworks: "Foundation" cpp.minimumMacosVersion: "10.7" } diff --git a/tests/auto/blackbox/testdata/minimumSystemVersion/unspecified-forced.qbs b/tests/auto/blackbox/testdata/minimumSystemVersion/unspecified-forced.qbs index a5ea620fd..adb61a6d8 100644 --- a/tests/auto/blackbox/testdata/minimumSystemVersion/unspecified-forced.qbs +++ b/tests/auto/blackbox/testdata/minimumSystemVersion/unspecified-forced.qbs @@ -2,8 +2,16 @@ import qbs.Utilities // no minimum versions are specified, and explicitly set to undefined in // case the profile has set it +import qbs.Host + CppApplication { - files: [qbs.targetOS.contains("darwin") ? "main.mm" : "main.cpp"] + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } + files: [qbs.targetOS.includes("darwin") ? "main.mm" : "main.cpp"] consoleApplication: true cpp.minimumWindowsVersion: undefined cpp.minimumMacosVersion: undefined @@ -11,12 +19,12 @@ CppApplication { cpp.minimumAndroidVersion: undefined Properties { - condition: qbs.targetOS.contains("windows") + condition: qbs.targetOS.includes("windows") cpp.defines: ["TOOLCHAIN_INSTALL_PATH=" + Utilities.cStringQuote(cpp.toolchainInstallPath)] } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") cpp.frameworks: "Foundation" } } diff --git a/tests/auto/blackbox/testdata/minimumSystemVersion/unspecified.qbs b/tests/auto/blackbox/testdata/minimumSystemVersion/unspecified.qbs index 0eeb2d547..3c6559c39 100644 --- a/tests/auto/blackbox/testdata/minimumSystemVersion/unspecified.qbs +++ b/tests/auto/blackbox/testdata/minimumSystemVersion/unspecified.qbs @@ -1,17 +1,25 @@ import qbs.Utilities // no minimum versions are specified so the profile defaults will be used +import qbs.Host + CppApplication { - files: [qbs.targetOS.contains("darwin") ? "main.mm" : "main.cpp"] + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } + files: [qbs.targetOS.includes("darwin") ? "main.mm" : "main.cpp"] consoleApplication: true Properties { - condition: qbs.targetOS.contains("windows") + condition: qbs.targetOS.includes("windows") cpp.defines: ["TOOLCHAIN_INSTALL_PATH=" + Utilities.cStringQuote(cpp.toolchainInstallPath)] } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") cpp.frameworks: "Foundation" } } diff --git a/tests/auto/blackbox/testdata/module-conditions/module-conditions.qbs b/tests/auto/blackbox/testdata/module-conditions/module-conditions.qbs index dc3768203..207df5ded 100644 --- a/tests/auto/blackbox/testdata/module-conditions/module-conditions.qbs +++ b/tests/auto/blackbox/testdata/module-conditions/module-conditions.qbs @@ -1,5 +1,3 @@ -import qbs - Project { Product { name: "p1" diff --git a/tests/auto/blackbox/testdata/module-providers/module-providers.qbs b/tests/auto/blackbox/testdata/module-providers/module-providers.qbs deleted file mode 100644 index d1ff79269..000000000 --- a/tests/auto/blackbox/testdata/module-providers/module-providers.qbs +++ /dev/null @@ -1,20 +0,0 @@ -Project { - CppApplication { - name: "app1" - Depends { name: "mygenerator.module1" } - Depends { name: "mygenerator.module2" } - moduleProviders.mygenerator.chooseLettersFrom: "beginning" - files: "main.cpp" - } - CppApplication { - name: "app2" - Depends { name: "mygenerator.module1" } - Depends { name: "mygenerator.module2" } - Profile { - name: "myProfile" - moduleProviders.mygenerator.chooseLettersFrom: "end" - } - qbs.profile: "myProfile" - files: "main.cpp" - } -} diff --git a/tests/auto/blackbox/testdata/msvc-asm-flags/include/header.inc b/tests/auto/blackbox/testdata/msvc-asm-flags/include/header.inc new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/msvc-asm-flags/include/header.inc diff --git a/tests/auto/blackbox/testdata/msvc-asm-flags/msvc-asm-flags.asm b/tests/auto/blackbox/testdata/msvc-asm-flags/msvc-asm-flags.asm new file mode 100644 index 000000000..eddc49131 --- /dev/null +++ b/tests/auto/blackbox/testdata/msvc-asm-flags/msvc-asm-flags.asm @@ -0,0 +1,8 @@ +include header.inc + +.code +main proc + mov ecx, 16 +main endp + +end
\ No newline at end of file diff --git a/tests/auto/blackbox/testdata/msvc-asm-flags/msvc-asm-flags.qbs b/tests/auto/blackbox/testdata/msvc-asm-flags/msvc-asm-flags.qbs new file mode 100644 index 000000000..d632098c9 --- /dev/null +++ b/tests/auto/blackbox/testdata/msvc-asm-flags/msvc-asm-flags.qbs @@ -0,0 +1,6 @@ +StaticLibrary { + condition: qbs.toolchain.includes("msvc") + Depends { name: "cpp" } + files: "msvc-asm-flags.asm" + cpp.assemblerFlags: ["/I", "include"] +} diff --git a/tests/auto/blackbox/testdata/multiplexed-tool/multiplexed-tool.qbs b/tests/auto/blackbox/testdata/multiplexed-tool/multiplexed-tool.qbs index 3994bd95f..1ec51c354 100644 --- a/tests/auto/blackbox/testdata/multiplexed-tool/multiplexed-tool.qbs +++ b/tests/auto/blackbox/testdata/multiplexed-tool/multiplexed-tool.qbs @@ -1,13 +1,23 @@ +import qbs.Host + Project { CppApplication { name: "tool" consoleApplication: true + property bool _testPlatform: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } Profile { name: "debugProfile" + baseProfile: project.profile qbs.buildVariant: "debug" } Profile { name: "releaseProfile" + baseProfile: project.profile qbs.buildVariant: "release" } multiplexByQbsProperties: "profiles" diff --git a/tests/auto/blackbox/testdata/nested-properties/modules/lowerlevel/lower-level.qbs b/tests/auto/blackbox/testdata/nested-properties/modules/lowerlevel/lower-level.qbs index f8b6a7dc0..a5a6c7d4b 100644 --- a/tests/auto/blackbox/testdata/nested-properties/modules/lowerlevel/lower-level.qbs +++ b/tests/auto/blackbox/testdata/nested-properties/modules/lowerlevel/lower-level.qbs @@ -10,7 +10,7 @@ Module { var cmd = new JavaScriptCommand(); cmd.sourceCode = function() { }; var prop = product.lowerlevel.prop; - cmd.description = "lowerlevel.prop is '" + prop + "'."; + cmd.description = "lowerlevel.prop is '" + prop + "'"; return [cmd]; } } diff --git a/tests/auto/blackbox/testdata/no-exported-symbols/no-exported-symbols.qbs b/tests/auto/blackbox/testdata/no-exported-symbols/no-exported-symbols.qbs index 346a94e21..9aad3d032 100644 --- a/tests/auto/blackbox/testdata/no-exported-symbols/no-exported-symbols.qbs +++ b/tests/auto/blackbox/testdata/no-exported-symbols/no-exported-symbols.qbs @@ -12,7 +12,7 @@ Project { id: toolchainProbe property stringList toolchain: qbs.toolchain configure: { - if (toolchain.contains("msvc") && !toolchain.contains("clang-cl")) + if (toolchain.includes("msvc") && !toolchain.includes("clang-cl")) console.info("compiler is MSVC") else console.info("compiler is not MSVC") diff --git a/tests/auto/blackbox/testdata/no-such-profile/no-such-profile.qbs b/tests/auto/blackbox/testdata/no-such-profile/no-such-profile.qbs index 8e64ba478..1de3a4b10 100644 --- a/tests/auto/blackbox/testdata/no-such-profile/no-such-profile.qbs +++ b/tests/auto/blackbox/testdata/no-such-profile/no-such-profile.qbs @@ -1,5 +1,3 @@ -import qbs - Product { name: "theProduct" property int p diff --git a/tests/auto/blackbox/testdata/nodejs/hello.qbs b/tests/auto/blackbox/testdata/nodejs/hello.qbs index c19e455db..849a8789f 100644 --- a/tests/auto/blackbox/testdata/nodejs/hello.qbs +++ b/tests/auto/blackbox/testdata/nodejs/hello.qbs @@ -1,4 +1,12 @@ +import qbs.Host + NodeJSApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } nodejs.applicationFile: "hello.js" name: "hello" } diff --git a/tests/auto/blackbox/testdata/nsis/hello.qbs b/tests/auto/blackbox/testdata/nsis/hello.qbs index a161a6998..f70f27e2b 100644 --- a/tests/auto/blackbox/testdata/nsis/hello.qbs +++ b/tests/auto/blackbox/testdata/nsis/hello.qbs @@ -1,5 +1,5 @@ NSISSetup { - condition: qbs.targetOS.contains("windows") + condition: qbs.targetOS.includes("windows") name: "Qbs Hello" targetName: "qbs-hello-" + qbs.architecture files: ["hello.nsi", "hello.bat"] diff --git a/tests/auto/blackbox/testdata/nsisDependencies/nsisDependencies.qbs b/tests/auto/blackbox/testdata/nsisDependencies/nsisDependencies.qbs index d8185aabf..a4ce92067 100644 --- a/tests/auto/blackbox/testdata/nsisDependencies/nsisDependencies.qbs +++ b/tests/auto/blackbox/testdata/nsisDependencies/nsisDependencies.qbs @@ -2,7 +2,7 @@ import qbs.FileInfo import qbs.TextFile Project { - condition: qbs.targetOS.contains("windows") + condition: qbs.targetOS.includes("windows") NSISSetup { Depends { name: "app" } diff --git a/tests/auto/blackbox/testdata/output-redirection/output-redirection.qbs b/tests/auto/blackbox/testdata/output-redirection/output-redirection.qbs index 3ee443438..d2474cecf 100644 --- a/tests/auto/blackbox/testdata/output-redirection/output-redirection.qbs +++ b/tests/auto/blackbox/testdata/output-redirection/output-redirection.qbs @@ -1,4 +1,5 @@ import qbs.FileInfo +import qbs.Host Product { name: "the-product" @@ -21,7 +22,7 @@ Product { prepare: { var binary; var prefixArgs; - if (product.qbs.hostOS.contains("windows")) { + if (Host.os().includes("windows")) { binary = product.qbs.windowsShellPath; prefixArgs = ["/c", "type"]; } else { diff --git a/tests/auto/blackbox/testdata/overrideProjectProperties/helper_lib.qbs b/tests/auto/blackbox/testdata/overrideProjectProperties/helper_lib.qbs index b69dd0da8..c7eab99e2 100644 --- a/tests/auto/blackbox/testdata/overrideProjectProperties/helper_lib.qbs +++ b/tests/auto/blackbox/testdata/overrideProjectProperties/helper_lib.qbs @@ -3,7 +3,7 @@ DynamicLibrary { files: "helperlib.cpp" Depends { name: "cpp" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } diff --git a/tests/auto/blackbox/testdata/path-list-in-probe/main.cpp b/tests/auto/blackbox/testdata/path-list-in-probe/main.cpp new file mode 100644 index 000000000..5bc549337 --- /dev/null +++ b/tests/auto/blackbox/testdata/path-list-in-probe/main.cpp @@ -0,0 +1,4 @@ +int main() +{ + return 0; +}
\ No newline at end of file diff --git a/tests/auto/blackbox/testdata/path-list-in-probe/path-list-in-probe.qbs b/tests/auto/blackbox/testdata/path-list-in-probe/path-list-in-probe.qbs new file mode 100644 index 000000000..3bf36367a --- /dev/null +++ b/tests/auto/blackbox/testdata/path-list-in-probe/path-list-in-probe.qbs @@ -0,0 +1,18 @@ +Project { + CppApplication { + Probe { + id: theProbe + property pathList result + configure: { + result = ["main.cpp"] + found = true + } + } + property pathList res: theProbe.found ? theProbe.result : [] + + Group { + name: "files" + files: res + } + } +} diff --git a/tests/auto/blackbox/testdata/path-probe/BaseApp.qbs b/tests/auto/blackbox/testdata/path-probe/BaseApp.qbs index 84c00c240..62871698e 100644 --- a/tests/auto/blackbox/testdata/path-probe/BaseApp.qbs +++ b/tests/auto/blackbox/testdata/path-probe/BaseApp.qbs @@ -28,9 +28,10 @@ ** ****************************************************************************/ +import qbs.FileInfo import qbs.Probes -CppApplication { +Product { property varList inputSelectors property varList inputNames @@ -38,8 +39,10 @@ CppApplication { property pathList inputSearchPaths property var inputNameFilter property var inputCandidateFilter + property stringList inputEnvironmentPaths property stringList outputFilePaths + property var outputCandidatePaths Probes.PathProbe { id: probe @@ -49,6 +52,8 @@ CppApplication { nameFilter: inputNameFilter candidateFilter: inputCandidateFilter searchPaths: inputSearchPaths + platformSearchPaths: [] + environmentPaths: inputEnvironmentPaths } property bool validate: { @@ -56,21 +61,72 @@ CppApplication { if (lhs.length !== rhs.length) return false; for (var i = 0; i < lhs.length; ++i) { - if (lhs[i] !== rhs[i]) + if ((lhs[i] instanceof Array) && (rhs[i] instanceof Array)) { + if (!compareArrays(lhs[i], rhs[i])) + return false; + } else if (FileInfo.resolvePath(path, lhs[i]) !== FileInfo.resolvePath(path, rhs[i])) { return false; + } } return true; }; - if (!probe.found) + if (outputCandidatePaths) { + var actual = probe.allResults.map(function(file) { return file.candidatePaths; }); + if (!compareArrays(actual, outputCandidatePaths)) { + throw "Invalid canndidatePaths: actual = " + JSON.stringify(actual) + + ", expected = " + JSON.stringify(outputCandidatePaths); + } + } + + if (!probe.found) { + if (probe.filePath) { + throw "Invalid filePath: actual = " + JSON.stringify(probe.filePath) + + ", expected = 'undefined'"; + } + if (probe.fileName) { + throw "Invalid fileName: actual = " + JSON.stringify(probe.fileName) + + ", expected = 'undefined'"; + } + if (probe.path) { + throw "Invalid path: actual = " + JSON.stringify(probe.path) + + ", expected = 'undefined'"; + } + throw "Probe failed to find files"; + } if (outputFilePaths) { var actual = probe.allResults.map(function(file) { return file.filePath; }); - if (!compareArrays(actual, outputFilePaths)) - throw "Invalid filePaths: actual = " + actual + ", expected = " + outputFilePaths; + if (!compareArrays(actual, outputFilePaths)) { + throw "Invalid filePaths: actual = " + JSON.stringify(actual) + + ", expected = " + JSON.stringify(outputFilePaths); + } } - } - files: ["main.cpp"] + if (probe.allResults.length !== 1) + return; + + // check that single-file interface matches the first value in allResults + var expectedFilePath = probe.allResults[0].filePath; + if (probe.filePath !== expectedFilePath) { + throw "Invalid filePath: actual = " + probe.filePath + + ", expected = " + expectedFilePath; + } + var expectedFileName = probe.allResults[0].fileName; + if (probe.fileName !== expectedFileName) { + throw "Invalid fileName: actual = " + probe.fileName + + ", expected = " + expectedFileName; + } + var expectedPath = probe.allResults[0].path; + if (FileInfo.resolvePath(path, probe.path) !== FileInfo.resolvePath(path, expectedPath)) { + throw "Invalid path: actual = " + probe.path + + ", expected = " + expectedPath; + } + var expectedCandidatePaths = probe.allResults[0].candidatePaths; + if (!compareArrays(probe.candidatePaths, expectedCandidatePaths)) { + throw "Invalid candidatePaths: actual = " + JSON.stringify(probe.candidatePaths) + + ", expected = " + JSON.stringify(expectedCandidatePaths); + } + } } diff --git a/tests/auto/blackbox/testdata/path-probe/candidate-filter.qbs b/tests/auto/blackbox/testdata/path-probe/candidate-filter.qbs index a65256a68..5c259ae9b 100644 --- a/tests/auto/blackbox/testdata/path-probe/candidate-filter.qbs +++ b/tests/auto/blackbox/testdata/path-probe/candidate-filter.qbs @@ -3,10 +3,12 @@ import qbs.FileInfo BaseApp { inputNames: ["tool.1", "tool.2"] inputSearchPaths: "bin" - outputFilePaths: ["bin/tool.2"] inputCandidateFilter: { + var fi = FileInfo; return function(f) { - return FileInfo.fileName(f) == "tool.2"; + return fi.fileName(f) == "tool.2"; } } + outputFilePaths: ["bin/tool.2"] + outputCandidatePaths: [["bin/tool.1", "bin/tool.2"]] } diff --git a/tests/auto/blackbox/testdata/path-probe/environment-paths.qbs b/tests/auto/blackbox/testdata/path-probe/environment-paths.qbs new file mode 100644 index 000000000..fca824bfb --- /dev/null +++ b/tests/auto/blackbox/testdata/path-probe/environment-paths.qbs @@ -0,0 +1,10 @@ +import qbs.FileInfo + +BaseApp { + inputNames: "tool" + inputSearchPaths: ["bin", "usr/bin"] + // env takes precedence + inputEnvironmentPaths: "SEARCH_PATH" + outputFilePaths: ["usr/bin/tool"] + outputCandidatePaths: [["usr/bin/tool"]] +} diff --git a/tests/auto/blackbox/testdata/path-probe/mult-files-common-suffixes.qbs b/tests/auto/blackbox/testdata/path-probe/mult-files-common-suffixes.qbs new file mode 100644 index 000000000..c4d53a715 --- /dev/null +++ b/tests/auto/blackbox/testdata/path-probe/mult-files-common-suffixes.qbs @@ -0,0 +1,10 @@ +BaseApp { + inputSelectors: [ + {names : "tool"}, + {names : "super-tool"}, + ] + inputNameSuffixes: ".1" + inputSearchPaths: "bin" + outputFilePaths: ["bin/tool.1", "bin/super-tool.1"] + outputCandidatePaths: [["bin/tool.1"], ["bin/super-tool.1"]] +} diff --git a/tests/auto/blackbox/testdata/path-probe/mult-files-mult-suffixes.qbs b/tests/auto/blackbox/testdata/path-probe/mult-files-mult-suffixes.qbs index b112db44d..33656d4e6 100644 --- a/tests/auto/blackbox/testdata/path-probe/mult-files-mult-suffixes.qbs +++ b/tests/auto/blackbox/testdata/path-probe/mult-files-mult-suffixes.qbs @@ -1,8 +1,9 @@ BaseApp { inputSelectors: [ - {names : "tool", nameSuffixes: [".1", ".2"]}, + {names : "tool", nameSuffixes: [".0", ".1", ".2"]}, {names : "super-tool", nameSuffixes: [".1"]}, ] inputSearchPaths: "bin" outputFilePaths: ["bin/tool.1", "bin/super-tool.1"] + outputCandidatePaths: [["bin/tool.0", "bin/tool.1"], ["bin/super-tool.1"]] } diff --git a/tests/auto/blackbox/testdata/path-probe/mult-files-mult-variants.qbs b/tests/auto/blackbox/testdata/path-probe/mult-files-mult-variants.qbs index 60c56e6b4..dd0b58aa2 100644 --- a/tests/auto/blackbox/testdata/path-probe/mult-files-mult-variants.qbs +++ b/tests/auto/blackbox/testdata/path-probe/mult-files-mult-variants.qbs @@ -1,9 +1,10 @@ BaseApp { inputSelectors: [ "tool", - ["tool.1", "tool.2"], + ["tool.0", "tool.1", "tool.2"], {names : ["tool.3", "tool.4"]}, ] inputSearchPaths: "bin" outputFilePaths: ["bin/tool", "bin/tool.1", "bin/tool.3"] + outputCandidatePaths: [["bin/tool"], ["bin/tool.0", "bin/tool.1"], ["bin/tool.3"]] } diff --git a/tests/auto/blackbox/testdata/path-probe/mult-files-suffixes.qbs b/tests/auto/blackbox/testdata/path-probe/mult-files-suffixes.qbs index 5e4fc27ca..7ae78de24 100644 --- a/tests/auto/blackbox/testdata/path-probe/mult-files-suffixes.qbs +++ b/tests/auto/blackbox/testdata/path-probe/mult-files-suffixes.qbs @@ -5,4 +5,5 @@ BaseApp { ] inputSearchPaths: "bin" outputFilePaths: ["bin/tool.2", "bin/super-tool.1"] + outputCandidatePaths: [["bin/tool.2"], ["bin/super-tool.1"]] } diff --git a/tests/auto/blackbox/testdata/path-probe/mult-files.qbs b/tests/auto/blackbox/testdata/path-probe/mult-files.qbs index 08727ac01..aa08befc8 100644 --- a/tests/auto/blackbox/testdata/path-probe/mult-files.qbs +++ b/tests/auto/blackbox/testdata/path-probe/mult-files.qbs @@ -7,4 +7,5 @@ BaseApp { ] inputSearchPaths: "bin" outputFilePaths: ["bin/tool.1", "bin/tool.2", "bin/tool.3", "bin/tool.4"] + outputCandidatePaths: [["bin/tool.1"], ["bin/tool.2"], ["bin/tool.3"], ["bin/tool.4"]] } diff --git a/tests/auto/blackbox/testdata/path-probe/name-filter.qbs b/tests/auto/blackbox/testdata/path-probe/name-filter.qbs index 406988fed..b2840443b 100644 --- a/tests/auto/blackbox/testdata/path-probe/name-filter.qbs +++ b/tests/auto/blackbox/testdata/path-probe/name-filter.qbs @@ -7,4 +7,5 @@ BaseApp { }; } outputFilePaths: ["bin/tool.2"] + outputCandidatePaths: [["bin/tool.2"]] } diff --git a/tests/auto/blackbox/testdata/path-probe/non-existent-selector.qbs b/tests/auto/blackbox/testdata/path-probe/non-existent-selector.qbs index aaa27042c..aabb0fe7b 100644 --- a/tests/auto/blackbox/testdata/path-probe/non-existent-selector.qbs +++ b/tests/auto/blackbox/testdata/path-probe/non-existent-selector.qbs @@ -5,4 +5,5 @@ BaseApp { "tool.2", ] inputSearchPaths: "bin" + outputCandidatePaths: [["bin/tool.1"], ["bin/nonexistent"], ["bin/tool.2"]] } diff --git a/tests/auto/blackbox/testdata/path-probe/non-existent.qbs b/tests/auto/blackbox/testdata/path-probe/non-existent.qbs index f0c58fa6c..aad01c31b 100644 --- a/tests/auto/blackbox/testdata/path-probe/non-existent.qbs +++ b/tests/auto/blackbox/testdata/path-probe/non-existent.qbs @@ -1,4 +1,5 @@ BaseApp { inputNames: "nonexistent" inputSearchPaths: "bin" + outputCandidatePaths: [["bin/nonexistent"]] } diff --git a/tests/auto/blackbox/testdata/path-probe/single-file-mult-variants.qbs b/tests/auto/blackbox/testdata/path-probe/single-file-mult-variants.qbs index 992a0bea4..98f5b141a 100644 --- a/tests/auto/blackbox/testdata/path-probe/single-file-mult-variants.qbs +++ b/tests/auto/blackbox/testdata/path-probe/single-file-mult-variants.qbs @@ -2,4 +2,5 @@ BaseApp { inputNames: ["tool.1", "tool.2"] inputSearchPaths: "bin" outputFilePaths: ["bin/tool.1"] + outputCandidatePaths: [["bin/tool.1"]] } diff --git a/tests/auto/blackbox/testdata/path-probe/single-file-selector-array.qbs b/tests/auto/blackbox/testdata/path-probe/single-file-selector-array.qbs index 697665242..292df4add 100644 --- a/tests/auto/blackbox/testdata/path-probe/single-file-selector-array.qbs +++ b/tests/auto/blackbox/testdata/path-probe/single-file-selector-array.qbs @@ -2,4 +2,5 @@ BaseApp { inputSelectors: ["tool"] inputSearchPaths: "bin" outputFilePaths: ["bin/tool"] + outputCandidatePaths: [["bin/tool"]] } diff --git a/tests/auto/blackbox/testdata/path-probe/single-file-selector.qbs b/tests/auto/blackbox/testdata/path-probe/single-file-selector.qbs index d57700baf..cf7cfe436 100644 --- a/tests/auto/blackbox/testdata/path-probe/single-file-selector.qbs +++ b/tests/auto/blackbox/testdata/path-probe/single-file-selector.qbs @@ -2,4 +2,5 @@ BaseApp { inputSelectors: "tool" inputSearchPaths: "bin" outputFilePaths: ["bin/tool"] + outputCandidatePaths: [["bin/tool"]] } diff --git a/tests/auto/blackbox/testdata/path-probe/single-file-suffixes.qbs b/tests/auto/blackbox/testdata/path-probe/single-file-suffixes.qbs index 4442e719a..3436a49c3 100644 --- a/tests/auto/blackbox/testdata/path-probe/single-file-suffixes.qbs +++ b/tests/auto/blackbox/testdata/path-probe/single-file-suffixes.qbs @@ -1,6 +1,7 @@ BaseApp { inputNames: "tool" inputSearchPaths: "bin" - inputNameSuffixes: [".1", ".2"] + inputNameSuffixes: [".0", ".1", ".2"] outputFilePaths: ["bin/tool.1"] + outputCandidatePaths: [["bin/tool.0", "bin/tool.1"]] } diff --git a/tests/auto/blackbox/testdata/path-probe/single-file.qbs b/tests/auto/blackbox/testdata/path-probe/single-file.qbs index 3590e7664..e22d7ba0d 100644 --- a/tests/auto/blackbox/testdata/path-probe/single-file.qbs +++ b/tests/auto/blackbox/testdata/path-probe/single-file.qbs @@ -2,4 +2,5 @@ BaseApp { inputNames: "tool" inputSearchPaths: "bin" outputFilePaths: ["bin/tool"] + outputCandidatePaths: [["bin/tool"]] } diff --git a/tests/auto/blackbox/testdata/path-probe/usr/bin/tool b/tests/auto/blackbox/testdata/path-probe/usr/bin/tool new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/path-probe/usr/bin/tool diff --git a/tests/auto/blackbox/testdata/plugin-dependency/helper1.cpp b/tests/auto/blackbox/testdata/plugin-dependency/helper1.cpp index 72331da80..15a3e0d86 100644 --- a/tests/auto/blackbox/testdata/plugin-dependency/helper1.cpp +++ b/tests/auto/blackbox/testdata/plugin-dependency/helper1.cpp @@ -1,4 +1,4 @@ -#include <stdio.h> +#include <cstdio> #if defined(_WIN32) || defined(WIN32) # define EXPORT __declspec(dllexport) @@ -12,5 +12,5 @@ EXPORT void helper1_hello() { - puts("helper1 says hello!"); + std::puts("helper1 says hello!"); } diff --git a/tests/auto/blackbox/testdata/plugin-dependency/helper2.cpp b/tests/auto/blackbox/testdata/plugin-dependency/helper2.cpp index cdcdfc942..dccd72a04 100644 --- a/tests/auto/blackbox/testdata/plugin-dependency/helper2.cpp +++ b/tests/auto/blackbox/testdata/plugin-dependency/helper2.cpp @@ -1,7 +1,7 @@ #include "../dllexport.h" -#include <stdio.h> +#include <cstdio> DLL_EXPORT void helper2_hello() { - puts("Hello from helper2!"); + std::puts("Hello from helper2!"); } diff --git a/tests/auto/blackbox/testdata/plugin-dependency/plugin-dependency.qbs b/tests/auto/blackbox/testdata/plugin-dependency/plugin-dependency.qbs index c619b33ef..752673b78 100644 --- a/tests/auto/blackbox/testdata/plugin-dependency/plugin-dependency.qbs +++ b/tests/auto/blackbox/testdata/plugin-dependency/plugin-dependency.qbs @@ -1,16 +1,18 @@ +import qbs.Host + Project { CppApplication { name: "myapp" files: ["main.cpp"] Depends { name: "plugin1" // not to be linked - cpp.link: qbs.hostOS === undefined + cpp.link: Host.os() === undefined } Depends { name: "plugin2" } // not to be linked Depends { name: "plugin3" // supposed to be linked - //property bool theCondition: true - cpp.link: /*theCondition && */product.name === "myapp" // TODO: Make this work + property bool theCondition: true + cpp.link: theCondition && product.name === "myapp" } Depends { name: "plugin4" } // supposed to be linked Depends { name: "helper1" } // supposed to be linked diff --git a/tests/auto/blackbox/testdata/plugin-dependency/plugin1.cpp b/tests/auto/blackbox/testdata/plugin-dependency/plugin1.cpp index 2535bd85e..8cf7e3851 100644 --- a/tests/auto/blackbox/testdata/plugin-dependency/plugin1.cpp +++ b/tests/auto/blackbox/testdata/plugin-dependency/plugin1.cpp @@ -1,7 +1,7 @@ #include "../dllexport.h" -#include <stdio.h> +#include <cstdio> DLL_EXPORT void plugin1_hello() { - puts("plugin1 says hello!"); + std::puts("plugin1 says hello!"); } diff --git a/tests/auto/blackbox/testdata/plugin-dependency/plugin2.cpp b/tests/auto/blackbox/testdata/plugin-dependency/plugin2.cpp index fb2030d60..9efc83e2b 100644 --- a/tests/auto/blackbox/testdata/plugin-dependency/plugin2.cpp +++ b/tests/auto/blackbox/testdata/plugin-dependency/plugin2.cpp @@ -1,7 +1,7 @@ #include "../dllexport.h" -#include <stdio.h> +#include <cstdio> DLL_EXPORT void plugin2_hello() { - puts("plugin2 says hello!"); + std::puts("plugin2 says hello!"); } diff --git a/tests/auto/blackbox/testdata/plugin-dependency/plugin3.cpp b/tests/auto/blackbox/testdata/plugin-dependency/plugin3.cpp index 8a9f5ee76..0e08ac85a 100644 --- a/tests/auto/blackbox/testdata/plugin-dependency/plugin3.cpp +++ b/tests/auto/blackbox/testdata/plugin-dependency/plugin3.cpp @@ -1,7 +1,7 @@ #include "../dllexport.h" -#include <stdio.h> +#include <cstdio> DLL_EXPORT void plugin3_hello() { - puts("plugin3 says hello!"); + std::puts("plugin3 says hello!"); } diff --git a/tests/auto/blackbox/testdata/plugin-dependency/plugin4.cpp b/tests/auto/blackbox/testdata/plugin-dependency/plugin4.cpp index 4663247fa..cee2362ec 100644 --- a/tests/auto/blackbox/testdata/plugin-dependency/plugin4.cpp +++ b/tests/auto/blackbox/testdata/plugin-dependency/plugin4.cpp @@ -1,7 +1,7 @@ #include "../dllexport.h" -#include <stdio.h> +#include <cstdio> DLL_EXPORT void plugin4_hello() { - puts("plugin4 says hello!"); + std::puts("plugin4 says hello!"); } diff --git a/tests/auto/blackbox/testdata/precompiled-headers-and-redefine/precompiled-headers-and-redefine.qbs b/tests/auto/blackbox/testdata/precompiled-headers-and-redefine/precompiled-headers-and-redefine.qbs index 55b53a7af..3974b514e 100644 --- a/tests/auto/blackbox/testdata/precompiled-headers-and-redefine/precompiled-headers-and-redefine.qbs +++ b/tests/auto/blackbox/testdata/precompiled-headers-and-redefine/precompiled-headers-and-redefine.qbs @@ -8,7 +8,7 @@ CppApplication { Group { files: ["file.cpp"] cpp.defines: ["MYDEF=1"] - cpp.cxxFlags: base.concat(qbs.toolchain.contains("clang-cl") ? ["-Wno-clang-cl-pch"] : []) + cpp.cxxFlags: base.concat(qbs.toolchain.includes("clang-cl") ? ["-Wno-clang-cl-pch"] : []) } cpp.treatWarningsAsErrors: true diff --git a/tests/auto/blackbox/testdata/probe-in-exported-module/modules/depmodule/depmodule.qbs b/tests/auto/blackbox/testdata/probe-in-exported-module/modules/depmodule/depmodule.qbs index 41c6cfe50..45b8e157f 100644 --- a/tests/auto/blackbox/testdata/probe-in-exported-module/modules/depmodule/depmodule.qbs +++ b/tests/auto/blackbox/testdata/probe-in-exported-module/modules/depmodule/depmodule.qbs @@ -7,7 +7,7 @@ Module { outputFileTags: "dep-out" prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Creating dep-out artifact"; + cmd.description = "creating dep-out artifact"; cmd.sourceCode = function() { console.info("prop: " + product.depmodule.prop); console.info("listProp: " + product.depmodule.listProp); diff --git a/tests/auto/blackbox/testdata/probe-in-exported-module/modules/mymodule/mymodule.qbs b/tests/auto/blackbox/testdata/probe-in-exported-module/modules/mymodule/mymodule.qbs index 89d544f7e..31275aa40 100644 --- a/tests/auto/blackbox/testdata/probe-in-exported-module/modules/mymodule/mymodule.qbs +++ b/tests/auto/blackbox/testdata/probe-in-exported-module/modules/mymodule/mymodule.qbs @@ -13,7 +13,7 @@ Module { outputFileTags: "out" prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Creating out artifact"; + cmd.description = "creating out artifact"; cmd.sourceCode = function() { console.info("found: " + product.mymodule.found); }; diff --git a/tests/auto/blackbox/testdata/probeProperties/probeProperties.qbs b/tests/auto/blackbox/testdata/probeProperties/probeProperties.qbs index 9846eacef..ce89d11f4 100644 --- a/tests/auto/blackbox/testdata/probeProperties/probeProperties.qbs +++ b/tests/auto/blackbox/testdata/probeProperties/probeProperties.qbs @@ -1,29 +1,40 @@ import qbs.Probes -CppApplication { - Probes.PathProbe { - id: probe1 - names: ["bin/tool"] - platformSearchPaths: [product.sourceDirectory] - } +Project { - Probes.PathProbe { - id: probe2 - names: ["tool"] - platformSearchPaths: [product.sourceDirectory + "/bin"] - } + CppApplication { + Probes.PathProbe { + id: probe1 + names: ["bin/tool"] + platformSearchPaths: [product.sourceDirectory] + } - targetName: { - console.info("probe1.fileName=" + probe1.fileName); - console.info("probe1.path=" + probe1.path); - console.info("probe1.filePath=" + probe1.filePath); + Probes.PathProbe { + id: probe2 + names: ["tool"] + platformSearchPaths: [product.sourceDirectory + "/bin"] + } - console.info("probe2.fileName=" + probe2.fileName); - console.info("probe2.path=" + probe2.path); - console.info("probe2.filePath=" + probe2.filePath); + targetName: { + console.info("probe1.fileName=" + probe1.fileName); + console.info("probe1.path=" + probe1.path); + console.info("probe1.filePath=" + probe1.filePath); - return name; + console.info("probe2.fileName=" + probe2.fileName); + console.info("probe2.path=" + probe2.path); + console.info("probe2.filePath=" + probe2.filePath); + + console.info("probe3.fileName=" + probe3.fileName); + console.info("probe3.path=" + probe3.path); + console.info("probe3.filePath=" + probe3.filePath); + return name; + } + } + + Probes.PathProbe { + id: probe3 + names: ["tool"] + platformSearchPaths: [project.sourceDirectory + "/bin"] } - files: ["main.c"] } diff --git a/tests/auto/blackbox/testdata/probes-and-array-properties/modules/mymodule/mymodule.qbs b/tests/auto/blackbox/testdata/probes-and-array-properties/modules/mymodule/mymodule.qbs index e5c368a88..92ece5be7 100644 --- a/tests/auto/blackbox/testdata/probes-and-array-properties/modules/mymodule/mymodule.qbs +++ b/tests/auto/blackbox/testdata/probes-and-array-properties/modules/mymodule/mymodule.qbs @@ -3,8 +3,7 @@ Module { id: propProbe property stringList prop: [] configure: { - prop = []; - prop.push("probe"); + prop = ["probe"]; found = true; } } diff --git a/tests/auto/blackbox/testdata/product-dependencies-by-type/product-dependencies-by-type.qbs b/tests/auto/blackbox/testdata/product-dependencies-by-type/product-dependencies-by-type.qbs index 8fa761a2d..8e1f291f3 100644 --- a/tests/auto/blackbox/testdata/product-dependencies-by-type/product-dependencies-by-type.qbs +++ b/tests/auto/blackbox/testdata/product-dependencies-by-type/product-dependencies-by-type.qbs @@ -91,7 +91,7 @@ Project { name: "lib-product" files: "main.cpp" Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } @@ -116,7 +116,7 @@ Project { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Collecting apps"; + cmd.description = "collecting apps"; cmd.sourceCode = function() { var file = new TextFile(output.filePath, TextFile.WriteOnly); for (var i = 0; i < inputs["application"].length; ++i) diff --git a/tests/auto/blackbox/testdata/product-in-exported-module/modules/m/m.qbs b/tests/auto/blackbox/testdata/product-in-exported-module/modules/m/m.qbs new file mode 100644 index 000000000..0e79d0abe --- /dev/null +++ b/tests/auto/blackbox/testdata/product-in-exported-module/modules/m/m.qbs @@ -0,0 +1,3 @@ +Module { + Depends { name: "dummy"; condition: { console.info("product: " + product.name); return false; } } +} diff --git a/tests/auto/blackbox/testdata/product-in-exported-module/product-in-exported-module.qbs b/tests/auto/blackbox/testdata/product-in-exported-module/product-in-exported-module.qbs new file mode 100644 index 000000000..3ead0ca6c --- /dev/null +++ b/tests/auto/blackbox/testdata/product-in-exported-module/product-in-exported-module.qbs @@ -0,0 +1,10 @@ +Project { + Product { + name: "importing" + Depends { name: "dep" } + } + Product { + name: "dep" + Export { Depends { name: "m" } } + } +} diff --git a/tests/auto/blackbox/testdata/productproperties/header.qbs b/tests/auto/blackbox/testdata/productproperties/header.qbs index 42f9c88d9..13a62035f 100644 --- a/tests/auto/blackbox/testdata/productproperties/header.qbs +++ b/tests/auto/blackbox/testdata/productproperties/header.qbs @@ -29,6 +29,6 @@ Product { Export { Depends { name: "cpp" } - cpp.includePaths: product.buildDirectory + cpp.includePaths: exportingProduct.buildDirectory } } diff --git a/tests/auto/blackbox/testdata/proper quoting/main.cpp b/tests/auto/blackbox/testdata/proper quoting/main.cpp index 22cafeaa9..6e9be6df1 100644 --- a/tests/auto/blackbox/testdata/proper quoting/main.cpp +++ b/tests/auto/blackbox/testdata/proper quoting/main.cpp @@ -26,16 +26,16 @@ ** ****************************************************************************/ -#include <stdio.h> +#include <cstdio> int bla(); int main() { - printf(DEFINE"\n"); - printf(DEFINEWITHSPACE"\n"); - printf(DEFINEWITHTAB"\n"); - printf(DEFINEWITHBACKSLASH"\n"); + std::printf(DEFINE"\n"); + std::printf(DEFINEWITHSPACE"\n"); + std::printf(DEFINEWITHTAB"\n"); + std::printf(DEFINEWITHBACKSLASH"\n"); return bla(); } diff --git a/tests/auto/blackbox/testdata/proper quoting/my static lib.cpp b/tests/auto/blackbox/testdata/proper quoting/my static lib.cpp index e7490e807..7c07fd4c9 100644 --- a/tests/auto/blackbox/testdata/proper quoting/my static lib.cpp +++ b/tests/auto/blackbox/testdata/proper quoting/my static lib.cpp @@ -26,12 +26,13 @@ ** ****************************************************************************/ -#include <stdio.h> #include <some helper.h> +#include <cstdio> + int bla() { int n = getSomeNumber(); - printf("Hello World! The magic number is %d.", n); + std::printf("Hello World! The magic number is %d.", n); return n; } diff --git a/tests/auto/blackbox/testdata/proper quoting/proper quoting.qbs b/tests/auto/blackbox/testdata/proper quoting/proper quoting.qbs index 184ee13e3..1587940a2 100644 --- a/tests/auto/blackbox/testdata/proper quoting/proper quoting.qbs +++ b/tests/auto/blackbox/testdata/proper quoting/proper quoting.qbs @@ -1,7 +1,13 @@ -import qbs 1.0 +import qbs.Host Project { Product { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } type: "application" consoleApplication: true name: "Hello World" @@ -34,7 +40,7 @@ Project { Depends { name: "cpp" } Export { Depends { name: "cpp" } - cpp.includePaths: [product.sourceDirectory + '/some helper'] + cpp.includePaths: [exportingProduct.sourceDirectory + '/some helper'] } } } diff --git a/tests/auto/blackbox/testdata/property-assignment-on-non-present-module/property-assignment-on-non-present-module.qbs b/tests/auto/blackbox/testdata/property-assignment-on-non-present-module/property-assignment-on-non-present-module.qbs deleted file mode 100644 index a01d6c561..000000000 --- a/tests/auto/blackbox/testdata/property-assignment-on-non-present-module/property-assignment-on-non-present-module.qbs +++ /dev/null @@ -1,4 +0,0 @@ -Product { - Depends { name: "nein"; required: false } - nein.doch: "ohhh!" -} diff --git a/tests/auto/blackbox/testdata/property-evaluation-context/modules/base/base.qbs b/tests/auto/blackbox/testdata/property-evaluation-context/modules/base/base.qbs new file mode 100644 index 000000000..a97538751 --- /dev/null +++ b/tests/auto/blackbox/testdata/property-evaluation-context/modules/base/base.qbs @@ -0,0 +1,4 @@ +Module { + property string productInBase: product.name + property string productInTop: "" +} diff --git a/tests/auto/blackbox/testdata/property-evaluation-context/modules/top/top.qbs b/tests/auto/blackbox/testdata/property-evaluation-context/modules/top/top.qbs new file mode 100644 index 000000000..fa073ff78 --- /dev/null +++ b/tests/auto/blackbox/testdata/property-evaluation-context/modules/top/top.qbs @@ -0,0 +1,6 @@ +Module { + Depends { name: "base" } + base.productInTop: product.name + property string productInTop: product.name + property string productInExport: "" +} diff --git a/tests/auto/blackbox/testdata/property-evaluation-context/property-evaluation-context.qbs b/tests/auto/blackbox/testdata/property-evaluation-context/property-evaluation-context.qbs new file mode 100644 index 000000000..ede32cf74 --- /dev/null +++ b/tests/auto/blackbox/testdata/property-evaluation-context/property-evaluation-context.qbs @@ -0,0 +1,34 @@ +Project { + qbsSearchPaths: [ path ] + Product { + name: "mylib" + Export { + Depends { name: "top" } + top.productInExport: exportingProduct.name + } + } + + Product { + type: "rule-output" + name: "myapp" + Depends { name: "mylib" } + + Rule { + alwaysRun: true + multiplex: true + requiresInputs: false + outputFileTags: "rule-output" + prepare: { + var cmd = new JavaScriptCommand(); + cmd.silent = true; + cmd.sourceCode = function() { + console.info("base.productInBase evaluated in: " + product.base.productInBase); + console.info("base.productInTop evaluated in: " + product.base.productInTop); + console.info("top.productInExport evaluated in: " + product.top.productInExport); + console.info("top.productInTop evaluated in: " + product.top.productInTop); + } + return [cmd]; + } + } + } +} diff --git a/tests/auto/blackbox/testdata/propertyChanges/modules/TestModule/module.qbs b/tests/auto/blackbox/testdata/propertyChanges/modules/TestModule/module.qbs index b1e4a1fdc..590736f6a 100644 --- a/tests/auto/blackbox/testdata/propertyChanges/modules/TestModule/module.qbs +++ b/tests/auto/blackbox/testdata/propertyChanges/modules/TestModule/module.qbs @@ -18,7 +18,7 @@ Module { prepare: { var cmd = new JavaScriptCommand(); cmd.highlight = "codegen"; - cmd.description = "Making output from input"; + cmd.description = "making output from input"; cmd.sourceCode = function() { // console.info('Change in source code'); console.info(input.TestModule.testProperty); diff --git a/tests/auto/blackbox/testdata/propertyChanges/propertyChanges.qbs b/tests/auto/blackbox/testdata/propertyChanges/propertyChanges.qbs index f13b1986e..29365a887 100644 --- a/tests/auto/blackbox/testdata/propertyChanges/propertyChanges.qbs +++ b/tests/auto/blackbox/testdata/propertyChanges/propertyChanges.qbs @@ -27,7 +27,7 @@ Project { name: "library" files: "lib.cpp" Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } @@ -80,7 +80,7 @@ Project { prepare: { var cmd = new JavaScriptCommand(); cmd.highlight = "codegen"; - cmd.description = "Making output from other output"; + cmd.description = "making output from other output"; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); } return cmd; } diff --git a/tests/auto/blackbox/testdata/protobuf-library-install/hello.proto b/tests/auto/blackbox/testdata/protobuf-library-install/hello.proto new file mode 100644 index 000000000..946108ddc --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf-library-install/hello.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; +package protobuf.library; + +import "hello/world.proto"; + +message Hello { + hello.World world = 1; +}; diff --git a/tests/auto/blackbox/testdata/protobuf-library-install/hello/world.proto b/tests/auto/blackbox/testdata/protobuf-library-install/hello/world.proto new file mode 100644 index 000000000..f718621b6 --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf-library-install/hello/world.proto @@ -0,0 +1,6 @@ +syntax = "proto3"; +package protobuf.library.hello; + +message World { + int32 value = 1; +}; diff --git a/tests/auto/blackbox/testdata/protobuf-library-install/protobuf-library.qbs b/tests/auto/blackbox/testdata/protobuf-library-install/protobuf-library.qbs new file mode 100644 index 000000000..501675c15 --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf-library-install/protobuf-library.qbs @@ -0,0 +1,34 @@ +import qbs.Host + +StaticLibrary { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && hasProtobuf; + } + + Depends { name: "cpp" } + cpp.cxxLanguageVersion: "c++11" + cpp.minimumMacosVersion: "10.8" + + protobuf.cpp.importPaths: product.sourceDirectory + + Depends { name: "protobuf.cpp"; required: false } + property bool hasProtobuf: { + console.info("has protobuf: " + protobuf.cpp.present); + return protobuf.cpp.present; + } + + Group { + fileTagsFilter: "protobuf.hpp" + qbs.installDir: "include" + qbs.installSourceBase: protobuf.cpp.outputDir + qbs.install: true + } + + files: [ + "hello.proto", + "hello/world.proto", + ] +} diff --git a/tests/auto/blackbox/testdata/protobuf/addressbook_cpp.qbs b/tests/auto/blackbox/testdata/protobuf/addressbook_cpp.qbs index a5a4caf75..959552ea5 100644 --- a/tests/auto/blackbox/testdata/protobuf/addressbook_cpp.qbs +++ b/tests/auto/blackbox/testdata/protobuf/addressbook_cpp.qbs @@ -1,16 +1,22 @@ -import qbs +import qbs.Host CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && hasProtobuf; + } name: "addressbook_cpp" consoleApplication: true - condition: hasProtobuf Depends { name: "cpp" } - cpp.cxxLanguageVersion: "c++11" + cpp.minimumMacosVersion: "10.15" Depends { name: "protobuf.cpp"; required: false } property bool hasProtobuf: { console.info("has protobuf: " + protobuf.cpp.present); + console.info("has modules: " + protobuflib.present); return protobuf.cpp.present; } diff --git a/tests/auto/blackbox/testdata/protobuf/addressbook_nanopb.options b/tests/auto/blackbox/testdata/protobuf/addressbook_nanopb.options new file mode 100644 index 000000000..60726de93 --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/addressbook_nanopb.options @@ -0,0 +1,3 @@ +tutorial.Person.name max_size:128 +tutorial.Person.email max_size:256 +tutorial.Person.phones max_count:16 diff --git a/tests/auto/blackbox/testdata/protobuf/addressbook_nanopb.proto b/tests/auto/blackbox/testdata/protobuf/addressbook_nanopb.proto new file mode 100644 index 000000000..5db0bedbf --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/addressbook_nanopb.proto @@ -0,0 +1,38 @@ +// See README.txt for information and build instructions. +// +// Note: START and END tags are used in comments to define sections used in +// tutorials. They are not part of the syntax for Protocol Buffers. +// +// To get an in-depth walkthrough of this file and the related examples, see: +// https://developers.google.com/protocol-buffers/docs/tutorials + +// [START declaration] +syntax = "proto3"; +package tutorial; +// [END declaration] + +// [START messages] +message Person { + string name = 1; + int32 id = 2; // Unique ID number for this person. + string email = 3; + + enum PhoneType { + MOBILE = 0; + HOME = 1; + WORK = 2; + } + + message PhoneNumber { + string number = 1; + PhoneType type = 2; + } + + repeated PhoneNumber phones = 4; +} + +// Our address book file is just one of these. +message AddressBook { + repeated Person people = 1; +} +// [END messages] diff --git a/tests/auto/blackbox/testdata/protobuf/addressbook_nanopb.qbs b/tests/auto/blackbox/testdata/protobuf/addressbook_nanopb.qbs new file mode 100644 index 000000000..3dfc911e1 --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/addressbook_nanopb.qbs @@ -0,0 +1,29 @@ +import qbs.Host + +CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && hasProtobuf; + } + name: "addressbook_nanopb" + consoleApplication: true + + Depends { name: "cpp" } + cpp.minimumMacosVersion: "10.8" + + Depends { name: "protobuf.nanopb"; required: false } + property bool hasProtobuf: { + console.info("has protobuf: " + protobuf.nanopb.present); + console.info("has modules: false"); + return protobuf.nanopb.present; + } + protobuf.nanopb.importPaths: product.sourceDirectory + + files: [ + "addressbook_nanopb.proto", + "addressbook_nanopb.options", + "main_nanopb.cpp", + ] +} diff --git a/tests/auto/blackbox/testdata/protobuf/addressbook_objc.qbs b/tests/auto/blackbox/testdata/protobuf/addressbook_objc.qbs index be68abfee..7f0b999aa 100644 --- a/tests/auto/blackbox/testdata/protobuf/addressbook_objc.qbs +++ b/tests/auto/blackbox/testdata/protobuf/addressbook_objc.qbs @@ -1,14 +1,20 @@ -import qbs +import qbs.Host CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && hasProtobuf; + } name: "addressbook_objc" consoleApplication: true - condition: hasProtobuf Depends { name: "cpp" } Depends { name: "protobuf.objc"; required: false } property bool hasProtobuf: { console.info("has protobuf: " + protobuf.objc.present); + console.info("has modules: false"); return protobuf.objc.present; } diff --git a/tests/auto/blackbox/testdata/protobuf/conanfile.txt b/tests/auto/blackbox/testdata/protobuf/conanfile.txt new file mode 100644 index 000000000..e7d849b1a --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/conanfile.txt @@ -0,0 +1,6 @@ +[requires] +protobuf/3.21.12 +[tool_requires] +protobuf/3.21.12 +[generators] +QbsDeps diff --git a/tests/auto/blackbox/testdata/protobuf/create-proto-library.qbs b/tests/auto/blackbox/testdata/protobuf/create-proto-library.qbs new file mode 100644 index 000000000..005752fd8 --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/create-proto-library.qbs @@ -0,0 +1,53 @@ +import qbs.Host + +Project { + StaticLibrary { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && hasProtobuf; + } + name: "proto_lib" + + Depends { name: "cpp" } + cpp.minimumMacosVersion: "10.8" + + protobuf.cpp.importPaths: product.sourceDirectory + + Depends { name: "protobuf.cpp"; required: false } + property bool hasProtobuf: { + console.info("has protobuf: " + protobuf.cpp.present); + console.info("has modules: " + protobuflib.present); + return protobuf.cpp.present; + } + + files: [ + "import.proto", + "subdir/myenum.proto", + ] + + Export { + Depends { name: "cpp" } + Depends { name: "protobuf.cpp"; required: false } + cpp.cxxLanguageVersion: "c++11" + cpp.minimumMacosVersion: "10.8" + cpp.includePaths: exportingProduct.protobuf.cpp.outputDir + } + } + + CppApplication { + condition: proto_lib.present + name: "consumes_proto_lib" + consoleApplication: true + + files: [ + "import-main.cpp", + ] + + Depends { + name: "proto_lib" + required: false + } + } +} diff --git a/tests/auto/blackbox/testdata/protobuf/import-main.cpp b/tests/auto/blackbox/testdata/protobuf/import-main.cpp index 6d90cdf16..65048dd83 100644 --- a/tests/auto/blackbox/testdata/protobuf/import-main.cpp +++ b/tests/auto/blackbox/testdata/protobuf/import-main.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2018 Ivan Komissarov -** Contact: abbapoh@gmail.com +** Copyright (C) 2018 Ivan Komissarov (abbapoh@gmail.com) +** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** diff --git a/tests/auto/blackbox/testdata/protobuf/import.qbs b/tests/auto/blackbox/testdata/protobuf/import.qbs index 4c4de063f..56d489de8 100644 --- a/tests/auto/blackbox/testdata/protobuf/import.qbs +++ b/tests/auto/blackbox/testdata/protobuf/import.qbs @@ -1,17 +1,23 @@ -import qbs +import qbs.Host CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && hasProtobuf; + } name: "app" consoleApplication: true - condition: hasProtobuf protobuf.cpp.importPaths: [sourceDirectory] - cpp.cxxLanguageVersion: "c++11" + cpp.minimumMacosVersion: "10.8" Depends { name: "protobuf.cpp"; required: false } property bool hasProtobuf: { console.info("has protobuf: " + protobuf.cpp.present); + console.info("has modules: " + protobuflib.present); return protobuf.cpp.present; } diff --git a/tests/auto/blackbox/testdata/protobuf/main.cpp b/tests/auto/blackbox/testdata/protobuf/main.cpp index c93c46717..d4b1c431b 100644 --- a/tests/auto/blackbox/testdata/protobuf/main.cpp +++ b/tests/auto/blackbox/testdata/protobuf/main.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2018 Ivan Komissarov -** Contact: abbapoh@gmail.com +** Copyright (C) 2018 Ivan Komissarov (abbapoh@gmail.com) +** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** diff --git a/tests/auto/blackbox/testdata/protobuf/main.m b/tests/auto/blackbox/testdata/protobuf/main.m index e9d7ce66a..414d1aa2f 100644 --- a/tests/auto/blackbox/testdata/protobuf/main.m +++ b/tests/auto/blackbox/testdata/protobuf/main.m @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2018 Ivan Komissarov -** Contact: abbapoh@gmail.com +** Copyright (C) 2018 Ivan Komissarov (abbapoh@gmail.com) +** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** diff --git a/tests/auto/blackbox/testdata/protobuf/main_nanopb.cpp b/tests/auto/blackbox/testdata/protobuf/main_nanopb.cpp new file mode 100644 index 000000000..76fa03fca --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/main_nanopb.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Kai Dohmen (psykai1993@gmail.com) +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include <array> +#include <cassert> +#include <pb_encode.h> + +#include "addressbook_nanopb.pb.h" + +static_assert(std::is_array<decltype(std::declval<tutorial_Person>().name)>::value, ""); +static_assert(std::is_array<decltype(std::declval<tutorial_Person>().email)>::value, ""); +static_assert(std::is_array<decltype(std::declval<tutorial_Person>().phones)>::value, ""); + +bool writeString(pb_ostream_t *stream, const pb_field_t *field, void *const *) +{ + constexpr auto str = "0123456789"; + if (!pb_encode_tag_for_field(stream, field)) + return false; + return pb_encode_string(stream, reinterpret_cast<const uint8_t*>(str), strlen(str)); +} + +int main() +{ + std::array<uint8_t, 32> buffer = {}; + + tutorial_Person_PhoneNumber phoneNumber; + phoneNumber.number.funcs.encode = writeString; + phoneNumber.type = tutorial_Person_PhoneType_WORK; + + auto ostream = pb_ostream_from_buffer(buffer.data(), buffer.size()); + assert(pb_encode(&ostream, tutorial_Person_PhoneNumber_fields, &phoneNumber)); + + return 0; +} diff --git a/tests/auto/blackbox/testdata/protobuf/needs-import-dir-main.cpp b/tests/auto/blackbox/testdata/protobuf/needs-import-dir-main.cpp index d6faf9e84..5d62a0d06 100644 --- a/tests/auto/blackbox/testdata/protobuf/needs-import-dir-main.cpp +++ b/tests/auto/blackbox/testdata/protobuf/needs-import-dir-main.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2018 Ivan Komissarov -** Contact: abbapoh@gmail.com +** Copyright (C) 2018 Ivan Komissarov (abbapoh@gmail.com) +** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** diff --git a/tests/auto/blackbox/testdata/protobuf/needs-import-dir.qbs b/tests/auto/blackbox/testdata/protobuf/needs-import-dir.qbs index 788bbc93c..07be566cb 100644 --- a/tests/auto/blackbox/testdata/protobuf/needs-import-dir.qbs +++ b/tests/auto/blackbox/testdata/protobuf/needs-import-dir.qbs @@ -1,18 +1,24 @@ -import qbs +import qbs.Host CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result && hasProtobuf; + } name: "app" consoleApplication: true - condition: hasProtobuf property path theImportDir protobuf.cpp.importPaths: (theImportDir ? [theImportDir] : []).concat([sourceDirectory]) - cpp.cxxLanguageVersion: "c++11" + cpp.minimumMacosVersion: "10.8" Depends { name: "protobuf.cpp"; required: false } property bool hasProtobuf: { console.info("has protobuf: " + protobuf.cpp.present); + console.info("has modules: " + protobuflib.present); return protobuf.cpp.present; } diff --git a/tests/auto/blackbox/testdata/qbs-config-import-export/config.json b/tests/auto/blackbox/testdata/qbs-config-import-export/config.json new file mode 100644 index 000000000..edcaf238a --- /dev/null +++ b/tests/auto/blackbox/testdata/qbs-config-import-export/config.json @@ -0,0 +1,11 @@ +{ + "group": { + "key1": "value1", + "key2": "value2" + }, + "key": "value", + "listKey": [ + "valueOne", + "valueTwo" + ] +} diff --git a/tests/auto/blackbox/testdata/qbs-config-import-export/config.txt b/tests/auto/blackbox/testdata/qbs-config-import-export/config.txt new file mode 100644 index 000000000..2bd19c422 --- /dev/null +++ b/tests/auto/blackbox/testdata/qbs-config-import-export/config.txt @@ -0,0 +1,4 @@ +group.key1: "value1" +group.key2: "value2" +key: "value" +listKey: ["valueOne", "valueTwo"] diff --git a/tests/auto/blackbox/testdata/recursive_wildcards/recursive_wildcards.qbs b/tests/auto/blackbox/testdata/recursive_wildcards/recursive_wildcards.qbs index 4e9da01d3..4fc275877 100644 --- a/tests/auto/blackbox/testdata/recursive_wildcards/recursive_wildcards.qbs +++ b/tests/auto/blackbox/testdata/recursive_wildcards/recursive_wildcards.qbs @@ -23,7 +23,7 @@ Product { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Creating " + output.fileName; + cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { var inputList = explicitlyDependsOn["txt.in"]; var fileNameList = []; diff --git a/tests/auto/blackbox/testdata/remove-duplicate-libs/remove-duplicate-libs.qbs b/tests/auto/blackbox/testdata/remove-duplicate-libs/remove-duplicate-libs.qbs index 4ffb8d0e2..d89e47414 100644 --- a/tests/auto/blackbox/testdata/remove-duplicate-libs/remove-duplicate-libs.qbs +++ b/tests/auto/blackbox/testdata/remove-duplicate-libs/remove-duplicate-libs.qbs @@ -1,11 +1,13 @@ import "MyStaticLib.qbs" as MyStaticLib +import qbs.Host Project { property bool removeDuplicates property string libDir: buildDirectory + "/lib" property bool dummy: { + // most BSD systems (including macOS) use LLVM linker now console.info("is bfd linker: " - + (qbs.toolchain.contains("gcc") && !qbs.hostOS.contains("macos"))) + + (qbs.toolchain.includes("gcc") && !Host.os().includes("bsd"))) } qbsSearchPaths: "." diff --git a/tests/auto/blackbox/testdata/reproducible-build/reproducible-build.qbs b/tests/auto/blackbox/testdata/reproducible-build/reproducible-build.qbs index f7ed8e61a..fabdf48db 100644 --- a/tests/auto/blackbox/testdata/reproducible-build/reproducible-build.qbs +++ b/tests/auto/blackbox/testdata/reproducible-build/reproducible-build.qbs @@ -2,4 +2,9 @@ CppApplication { name: "the product" files: ["file1.cpp", "file2.cpp", "main.cpp"] cpp.cxxFlags: ["-flto"] + Probe { + id: checker + property bool isGcc: qbs.toolchain.contains("gcc") && !qbs.toolchain.contains("clang") + configure: { console.info("is gcc: " + isGcc); } + } } diff --git a/tests/auto/blackbox/testdata/require-deprecated/blubb.js b/tests/auto/blackbox/testdata/require-deprecated/blubb.js deleted file mode 100644 index 9acc13968..000000000 --- a/tests/auto/blackbox/testdata/require-deprecated/blubb.js +++ /dev/null @@ -1,13 +0,0 @@ -var TextFile = loadExtension("qbs.TextFile") -var zort = loadFile("zort.js") - -function createCommands(filePaths) { - var cmd = new JavaScriptCommand(); - cmd.description = "Write an empty file"; - cmd.filePath = filePaths[0]; - cmd.sourceCode = function() { - var f = new TextFile(filePath, TextFile.WriteOnly); - f.close(); - } - return [cmd, zort.createCommand(filePaths)]; -} diff --git a/tests/auto/blackbox/testdata/require-deprecated/require.qbs b/tests/auto/blackbox/testdata/require-deprecated/require.qbs deleted file mode 100644 index 87d8b054b..000000000 --- a/tests/auto/blackbox/testdata/require-deprecated/require.qbs +++ /dev/null @@ -1,21 +0,0 @@ -import 'blubb.js' as blubb - -Product { - type: ["text"] - Rule { - multiplex: true - Artifact { - fileTags: ["text"] - filePath: "one.txt" - } - Artifact { - fileTags: ["text"] - filePath: "two.txt" - } - prepare: { - var filePaths = outputs.text.map(function (artifact) {return artifact.filePath; }); - return blubb.createCommands(filePaths); - } - } -} - diff --git a/tests/auto/blackbox/testdata/require-deprecated/zort.js b/tests/auto/blackbox/testdata/require-deprecated/zort.js deleted file mode 100644 index 0dcffb767..000000000 --- a/tests/auto/blackbox/testdata/require-deprecated/zort.js +++ /dev/null @@ -1,11 +0,0 @@ -var File = loadExtension("qbs.File") - -function createCommand(filePaths) { - var cmd = new JavaScriptCommand(); - cmd.description = "Create another empty file"; - cmd.filePaths = filePaths; - cmd.sourceCode = function() { - File.copy(filePaths[0], filePaths[1]); - }; - return cmd; -} diff --git a/tests/auto/blackbox/testdata/response-files/response-files.qbs b/tests/auto/blackbox/testdata/response-files/response-files.qbs index fbb6f0518..c18fcac43 100644 --- a/tests/auto/blackbox/testdata/response-files/response-files.qbs +++ b/tests/auto/blackbox/testdata/response-files/response-files.qbs @@ -1,4 +1,5 @@ import qbs.FileInfo +import qbs.Host import qbs.TextFile Project { @@ -8,6 +9,12 @@ Project { cpp.enableExceptions: true } Product { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: "response-file-text" type: ["text"] Depends { name: "cpp" } @@ -38,6 +45,9 @@ Project { Product { name: "lotsofobjects" type: ["dynamiclibrary"] + // clang-cl does not use response file internally, thus linker complains that command is + // too long. This can be worked around by calling the linker directly + cpp.linkerMode: qbs.toolchain.includes("clang-cl") ? "manual" : original Depends { name: "cpp" } Rule { multiplex: true diff --git a/tests/auto/blackbox/testdata/rpathlink-deduplication/rpathlink-deduplication-lib.cpp b/tests/auto/blackbox/testdata/rpathlink-deduplication/rpathlink-deduplication-lib.cpp new file mode 100644 index 000000000..6418df94d --- /dev/null +++ b/tests/auto/blackbox/testdata/rpathlink-deduplication/rpathlink-deduplication-lib.cpp @@ -0,0 +1,3 @@ +int dynamicFunc() { + return 1; +}
\ No newline at end of file diff --git a/tests/auto/blackbox/testdata/rpathlink-deduplication/rpathlink-deduplication-main.cpp b/tests/auto/blackbox/testdata/rpathlink-deduplication/rpathlink-deduplication-main.cpp new file mode 100644 index 000000000..60f8494f6 --- /dev/null +++ b/tests/auto/blackbox/testdata/rpathlink-deduplication/rpathlink-deduplication-main.cpp @@ -0,0 +1,5 @@ +extern int dynamicFunc(); + +int main() { + return dynamicFunc(); +}
\ No newline at end of file diff --git a/tests/auto/blackbox/testdata/rpathlink-deduplication/rpathlink-deduplication.qbs b/tests/auto/blackbox/testdata/rpathlink-deduplication/rpathlink-deduplication.qbs new file mode 100644 index 000000000..adb63872a --- /dev/null +++ b/tests/auto/blackbox/testdata/rpathlink-deduplication/rpathlink-deduplication.qbs @@ -0,0 +1,47 @@ +Project { + DynamicLibrary { + Depends { name: "bundle" } + Depends { name: "cpp" } + + bundle.isBundle: false + name: "DynamicLibraryA" + files: ["rpathlink-deduplication-lib.cpp"] + } + + DynamicLibrary { + Depends { name: "bundle" } + Depends { name: "cpp" } + Depends { name: "DynamicLibraryA" } + + bundle.isBundle: false + name: "DynamicLibraryB" + files: ["rpathlink-deduplication-lib.cpp"] + } + + DynamicLibrary { + Depends { name: "bundle" } + Depends { name: "cpp" } + Depends { name: "DynamicLibraryA" } + + bundle.isBundle: false + name: "DynamicLibraryC" + files: ["rpathlink-deduplication-lib.cpp"] + } + + CppApplication { + Depends { name: "bundle" } + Depends { name: "DynamicLibraryB" } + Depends { name: "DynamicLibraryC" } + consoleApplication: true + bundle.isBundle: false + cpp.removeDuplicateLibraries: false + files: "rpathlink-deduplication-main.cpp" + property bool test: { + if (cpp.useRPathLink) + console.info("useRPathLink: true"); + else + console.info("useRPathLink: false"); + console.info("===" + cpp.rpathLinkFlag + "==="); + } + } +}
\ No newline at end of file diff --git a/tests/auto/blackbox/testdata/rule-with-non-required-inputs/rule-with-non-required-inputs.qbs b/tests/auto/blackbox/testdata/rule-with-non-required-inputs/rule-with-non-required-inputs.qbs index 1bd9beebf..9d861b674 100644 --- a/tests/auto/blackbox/testdata/rule-with-non-required-inputs/rule-with-non-required-inputs.qbs +++ b/tests/auto/blackbox/testdata/rule-with-non-required-inputs/rule-with-non-required-inputs.qbs @@ -22,7 +22,7 @@ Product { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Generating " + output.fileName; + cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.write('('); diff --git a/tests/auto/blackbox/testdata/run-multiplexed/main.cpp b/tests/auto/blackbox/testdata/run-multiplexed/main.cpp new file mode 100644 index 000000000..237c8ce18 --- /dev/null +++ b/tests/auto/blackbox/testdata/run-multiplexed/main.cpp @@ -0,0 +1 @@ +int main() {} diff --git a/tests/auto/blackbox/testdata/run-multiplexed/run-multiplexed.qbs b/tests/auto/blackbox/testdata/run-multiplexed/run-multiplexed.qbs new file mode 100644 index 000000000..11577b54a --- /dev/null +++ b/tests/auto/blackbox/testdata/run-multiplexed/run-multiplexed.qbs @@ -0,0 +1,21 @@ +import qbs.Host + +CppApplication { + aggregate: false + consoleApplication: true + name: "app" + multiplexByQbsProperties: "buildVariants" + + qbs.buildVariants: ["debug", "release"] + + files: "main.cpp" + + Probe { + id: checker + property string targetPlatform: qbs.targetPlatform + configure: { + if (targetPlatform !== Host.platform()) + console.info("targetPlatform differs from hostPlatform"); + } + } +} diff --git a/tests/auto/blackbox/testdata/sanitizer/sanitizer.cpp b/tests/auto/blackbox/testdata/sanitizer/sanitizer.cpp new file mode 100644 index 000000000..4a7c3ee32 --- /dev/null +++ b/tests/auto/blackbox/testdata/sanitizer/sanitizer.cpp @@ -0,0 +1,4 @@ +int main(int argc, char *argv[]) +{ + return 0; +} diff --git a/tests/auto/blackbox/testdata/sanitizer/sanitizer.qbs b/tests/auto/blackbox/testdata/sanitizer/sanitizer.qbs new file mode 100644 index 000000000..438f3cc39 --- /dev/null +++ b/tests/auto/blackbox/testdata/sanitizer/sanitizer.qbs @@ -0,0 +1,44 @@ +CppApplication { + Depends { name: "Sanitizers.address" } + Sanitizers.address.enabled: sanitizer === "address" + property string sanitizer + + property bool supportsSanitizer: { + if (qbs.toolchain.includes("mingw")) + return false; + if (sanitizer === "address") + return Sanitizers.address._supported; + if (qbs.toolchain.includes("clang-cl")) { + if (cpp.toolchainInstallPath.includes("Microsoft Visual Studio") + && qbs.architecture === "x86_64") { + // 32 bit sanitizer shipped with VS misses the x86_64 libraries + return false; + } + // only these are supported + return sanitizer === "address" || sanitizer === "undefined"; + } + if (!qbs.toolchain.includes("gcc")) + return false; + if (qbs.targetOS.includes("ios")) { + // thread sanitizer is not supported + return sanitizer !== "thread"; + } + return true; + } + + condition: { + if (!sanitizer) + return true; + if (!supportsSanitizer) + console.info("Compiler does not support sanitizer"); + return supportsSanitizer; + } + qbs.buildVariant: "release" + cpp.cxxLanguageVersion: "c++11" + cpp.minimumMacosVersion: "10.8" + consoleApplication: true + cpp.runtimeLibrary: "static" + cpp.driverFlags: sanitizer && sanitizer !== "address" ? ["-fsanitize=" + sanitizer] : [] + cpp.debugInformation: true + files: "sanitizer.cpp" +} diff --git a/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/app.h b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/app.h new file mode 100644 index 000000000..a82b12fbd --- /dev/null +++ b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/app.h @@ -0,0 +1 @@ +#include "lib.h" diff --git a/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/app.qbs b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/app.qbs new file mode 100644 index 000000000..e931b853c --- /dev/null +++ b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/app.qbs @@ -0,0 +1,4 @@ +CppApplication { + cpp.includePaths: project.sourceDirectory + "/lib" + files: "main.cpp" +} diff --git a/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/main.cpp b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/main.cpp new file mode 100644 index 000000000..2e7bedac8 --- /dev/null +++ b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/main.cpp @@ -0,0 +1,3 @@ +#include "app.h" + +int main() { } diff --git a/tests/auto/blackbox/testdata/scan-result-in-non-dependency/lib/lib.h b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/lib/lib.h new file mode 100644 index 000000000..af6f627b7 --- /dev/null +++ b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/lib/lib.h @@ -0,0 +1,3 @@ +#pragma once + +void lib1_foo();
\ No newline at end of file diff --git a/tests/auto/blackbox/testdata/scan-result-in-non-dependency/other/other.qbs b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/other/other.qbs new file mode 100644 index 000000000..29682da1c --- /dev/null +++ b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/other/other.qbs @@ -0,0 +1,24 @@ +import qbs.TextFile + +Product { + type: "testproduct" + files: "../lib/lib.h" + + Rule { + multiplex: true + Artifact { + fileTags: ["testproduct"] + filePath: "fubar" + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "generating text file"; + cmd.sourceCode = function() { + var tf = new TextFile(output.filePath, TextFile.WriteOnly); + tf.writeLine("blubb"); + tf.close(); + } + return cmd; + } + } +} diff --git a/tests/auto/blackbox/testdata/scan-result-in-non-dependency/p.qbs b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/p.qbs new file mode 100644 index 000000000..bcbd5ebce --- /dev/null +++ b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/p.qbs @@ -0,0 +1,6 @@ +Project { + references: [ + "app/app.qbs", + "other/other.qbs", + ] +} diff --git a/tests/auto/blackbox/testdata/scan-result-in-other-product/app/app.h b/tests/auto/blackbox/testdata/scan-result-in-other-product/app/app.h new file mode 100644 index 000000000..a82b12fbd --- /dev/null +++ b/tests/auto/blackbox/testdata/scan-result-in-other-product/app/app.h @@ -0,0 +1 @@ +#include "lib.h" diff --git a/tests/auto/blackbox/testdata/scan-result-in-other-product/app/app.qbs b/tests/auto/blackbox/testdata/scan-result-in-other-product/app/app.qbs new file mode 100644 index 000000000..984e9aca9 --- /dev/null +++ b/tests/auto/blackbox/testdata/scan-result-in-other-product/app/app.qbs @@ -0,0 +1,4 @@ +CppApplication { + Depends { name: "lib" } + files: "main.cpp" +} diff --git a/tests/auto/blackbox/testdata/scan-result-in-other-product/app/main.cpp b/tests/auto/blackbox/testdata/scan-result-in-other-product/app/main.cpp new file mode 100644 index 000000000..2e7bedac8 --- /dev/null +++ b/tests/auto/blackbox/testdata/scan-result-in-other-product/app/main.cpp @@ -0,0 +1,3 @@ +#include "app.h" + +int main() { } diff --git a/tests/auto/blackbox/testdata/scan-result-in-other-product/lib/lib.h b/tests/auto/blackbox/testdata/scan-result-in-other-product/lib/lib.h new file mode 100644 index 000000000..af6f627b7 --- /dev/null +++ b/tests/auto/blackbox/testdata/scan-result-in-other-product/lib/lib.h @@ -0,0 +1,3 @@ +#pragma once + +void lib1_foo();
\ No newline at end of file diff --git a/tests/auto/blackbox/testdata/scan-result-in-other-product/lib/lib.qbs b/tests/auto/blackbox/testdata/scan-result-in-other-product/lib/lib.qbs new file mode 100644 index 000000000..a6ed0c990 --- /dev/null +++ b/tests/auto/blackbox/testdata/scan-result-in-other-product/lib/lib.qbs @@ -0,0 +1,7 @@ +Product { + files: "lib.h" + Export { + Depends { name: "cpp" } + cpp.includePaths: exportingProduct.sourceDirectory + } +} diff --git a/tests/auto/blackbox/testdata/scan-result-in-other-product/other/other.qbs b/tests/auto/blackbox/testdata/scan-result-in-other-product/other/other.qbs new file mode 100644 index 000000000..29682da1c --- /dev/null +++ b/tests/auto/blackbox/testdata/scan-result-in-other-product/other/other.qbs @@ -0,0 +1,24 @@ +import qbs.TextFile + +Product { + type: "testproduct" + files: "../lib/lib.h" + + Rule { + multiplex: true + Artifact { + fileTags: ["testproduct"] + filePath: "fubar" + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "generating text file"; + cmd.sourceCode = function() { + var tf = new TextFile(output.filePath, TextFile.WriteOnly); + tf.writeLine("blubb"); + tf.close(); + } + return cmd; + } + } +} diff --git a/tests/auto/blackbox/testdata/scan-result-in-other-product/p.qbs b/tests/auto/blackbox/testdata/scan-result-in-other-product/p.qbs new file mode 100644 index 000000000..fedf84989 --- /dev/null +++ b/tests/auto/blackbox/testdata/scan-result-in-other-product/p.qbs @@ -0,0 +1,7 @@ +Project { + references: [ + "app/app.qbs", + "lib/lib.qbs", + "other/other.qbs", + ] +} diff --git a/tests/auto/blackbox/testdata/separate-debug-info/separate-debug-info.qbs b/tests/auto/blackbox/testdata/separate-debug-info/separate-debug-info.qbs index 0b16d1984..4198b863f 100644 --- a/tests/auto/blackbox/testdata/separate-debug-info/separate-debug-info.qbs +++ b/tests/auto/blackbox/testdata/separate-debug-info/separate-debug-info.qbs @@ -8,9 +8,13 @@ Project { Probe { id: osProbe property stringList targetOS: qbs.targetOS + property stringList toolchain: qbs.toolchain configure: { - console.info("is windows: " + (targetOS.contains("windows") ? "yes" : "no")); - console.info("is darwin: " + (targetOS.contains("darwin") ? "yes" : "no")); + console.info("is windows: " + (targetOS.includes("windows") ? "yes" : "no")); + console.info("is macos: " + (targetOS.includes("macos") ? "yes" : "no")); + console.info("is darwin: " + (targetOS.includes("darwin") ? "yes" : "no")); + console.info("is gcc: " + (toolchain.includes("gcc") ? "yes" : "no")); + console.info("is msvc: " + (toolchain.includes("msvc") ? "yes" : "no")); } } } @@ -54,7 +58,7 @@ Project { files: ["main.cpp"] cpp.separateDebugInformation: true Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") cpp.dsymutilFlags: ["--flat"] } } @@ -65,7 +69,7 @@ Project { files: ["foo.cpp"] cpp.separateDebugInformation: true Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") cpp.dsymutilFlags: ["--flat"] } } @@ -75,7 +79,7 @@ Project { files: ["foo.cpp"] cpp.separateDebugInformation: true Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") cpp.dsymutilFlags: ["--flat"] } } @@ -93,7 +97,7 @@ Project { type: ["dynamiclibrary"] files: ["foo.cpp"] Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } cpp.separateDebugInformation: true @@ -103,7 +107,7 @@ Project { name: "bar4" files: ["foo.cpp"] Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } cpp.separateDebugInformation: true @@ -114,12 +118,12 @@ Project { type: ["application"] files: ["main.cpp"] Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } cpp.separateDebugInformation: true Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") cpp.dsymutilFlags: ["--flat"] } } @@ -129,12 +133,12 @@ Project { type: ["dynamiclibrary"] files: ["foo.cpp"] Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } cpp.separateDebugInformation: true Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") cpp.dsymutilFlags: ["--flat"] } } @@ -143,12 +147,12 @@ Project { name: "bar5" files: ["foo.cpp"] Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } cpp.separateDebugInformation: true Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") cpp.dsymutilFlags: ["--flat"] } } diff --git a/tests/auto/blackbox/testdata/setup-run-environment/setup-run-environment.qbs b/tests/auto/blackbox/testdata/setup-run-environment/setup-run-environment.qbs index d2d47b767..b1310c005 100644 --- a/tests/auto/blackbox/testdata/setup-run-environment/setup-run-environment.qbs +++ b/tests/auto/blackbox/testdata/setup-run-environment/setup-run-environment.qbs @@ -1,4 +1,5 @@ import qbs.FileInfo +import qbs.Host Project { DynamicLibrary { // Product dependency, installed @@ -7,13 +8,13 @@ Project { files: ["lib1.cpp"] - install: !qbs.targetOS.contains("darwin") + install: !qbs.targetOS.includes("darwin") installImportLib: true installDir: "lib1" importLibInstallDir: installDir Group { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") fileTagsFilter: ["bundle.content"] qbs.install: true qbs.installSourceBase: destinationDirectory @@ -26,7 +27,7 @@ Project { Depends { name: "lib5" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } @@ -40,7 +41,7 @@ Project { files: ["lib3.cpp"] Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } @@ -57,14 +58,14 @@ Project { files: ["lib4.cpp"] Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } // Testing shows that clang (8.0) does not find dynamic libraries via // the -L<dir> and -l<libname> mechanism unless the name is "lib<libname>.a". Properties { - condition: qbs.hostOS.contains("windows") && qbs.toolchain.contains("clang") + condition: Host.os().includes("windows") && qbs.toolchain.includes("clang") cpp.dynamicLibraryPrefix: "lib" cpp.dynamicLibraryImportSuffix: ".a" } @@ -82,7 +83,7 @@ Project { Depends { name: "cpp" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } @@ -90,6 +91,12 @@ Project { } CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: "app" consoleApplication: true files: "main.cpp" @@ -101,7 +108,7 @@ Project { property string fullInstallPrefix: FileInfo.joinPaths(qbs.installRoot, qbs.installPrefix) property string lib3FilePath: FileInfo.joinPaths(fullInstallPrefix, "lib3", - cpp.dynamicLibraryPrefix + "lib3" + (qbs.targetOS.contains("windows") + cpp.dynamicLibraryPrefix + "lib3" + (qbs.targetOS.includes("windows") ? cpp.dynamicLibraryImportSuffix : cpp.dynamicLibrarySuffix)) cpp.dynamicLibraries: [lib3FilePath, "lib4"] @@ -110,7 +117,7 @@ Project { Probe { id: osPrinter - property bool isWindows: qbs.targetOS.contains("windows") + property bool isWindows: qbs.targetOS.includes("windows") configure: { console.info("is windows"); found = true; diff --git a/tests/auto/blackbox/testdata/smart-relinking/smart-relinking.qbs b/tests/auto/blackbox/testdata/smart-relinking/smart-relinking.qbs index aac0692a8..29e6c2e17 100644 --- a/tests/auto/blackbox/testdata/smart-relinking/smart-relinking.qbs +++ b/tests/auto/blackbox/testdata/smart-relinking/smart-relinking.qbs @@ -5,7 +5,7 @@ Project { property stringList toolchain: qbs.toolchain property stringList targetOS: qbs.targetOS configure: { - found = toolchain.contains("gcc") && targetOS.contains("unix"); + found = toolchain.includes("gcc") && targetOS.includes("unix"); if (!found) console.info("project disabled"); } diff --git a/tests/auto/blackbox/testdata/source-artifact-changes/source-artifact-changes.qbs b/tests/auto/blackbox/testdata/source-artifact-changes/source-artifact-changes.qbs index de56376df..a53819753 100644 --- a/tests/auto/blackbox/testdata/source-artifact-changes/source-artifact-changes.qbs +++ b/tests/auto/blackbox/testdata/source-artifact-changes/source-artifact-changes.qbs @@ -4,7 +4,7 @@ CppApplication { consoleApplication: true Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.embedInfoPlist: false } @@ -12,7 +12,7 @@ CppApplication { id: toolchainProbe property stringList toolchain: qbs.toolchain configure: { - console.info("is gcc: " + toolchain.contains("gcc")); + console.info("is gcc: " + toolchain.includes("gcc")); found = true; } } diff --git a/tests/auto/blackbox/testdata/static-lib-without-sources/static-lib-without-sources.qbs b/tests/auto/blackbox/testdata/static-lib-without-sources/static-lib-without-sources.qbs index 32a58c94b..54ec5e230 100644 --- a/tests/auto/blackbox/testdata/static-lib-without-sources/static-lib-without-sources.qbs +++ b/tests/auto/blackbox/testdata/static-lib-without-sources/static-lib-without-sources.qbs @@ -6,7 +6,7 @@ StaticLibrary { } Product { - type: qbs.targetOS.contains("darwin") ? undefined : ["staticlibrary"] + type: qbs.targetOS.includes("darwin") ? undefined : ["staticlibrary"] name: "b" Depends { name: "cpp" } Depends { name: "a" } diff --git a/tests/auto/blackbox/testdata/successive-changes/successive-changes.qbs b/tests/auto/blackbox/testdata/successive-changes/successive-changes.qbs index 77df81e39..c33e24d34 100644 --- a/tests/auto/blackbox/testdata/successive-changes/successive-changes.qbs +++ b/tests/auto/blackbox/testdata/successive-changes/successive-changes.qbs @@ -17,7 +17,7 @@ Project { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Creating output"; + cmd.description = "creating output"; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.write(project.version); diff --git a/tests/auto/blackbox/testdata/symbolLinkMode/lib.cpp b/tests/auto/blackbox/testdata/symbolLinkMode/lib.cpp index 8d96f5094..9dcb48738 100644 --- a/tests/auto/blackbox/testdata/symbolLinkMode/lib.cpp +++ b/tests/auto/blackbox/testdata/symbolLinkMode/lib.cpp @@ -3,9 +3,9 @@ int somefunction() return 42; } -#include <stdio.h> +#include <cstdio> static const auto func = []() { - printf("Lib was loaded!\n"); + std::printf("Lib was loaded!\n"); return 0; }(); diff --git a/tests/auto/blackbox/testdata/symbolLinkMode/main.cpp b/tests/auto/blackbox/testdata/symbolLinkMode/main.cpp index 801491634..4d847ba19 100644 --- a/tests/auto/blackbox/testdata/symbolLinkMode/main.cpp +++ b/tests/auto/blackbox/testdata/symbolLinkMode/main.cpp @@ -1,15 +1,15 @@ extern WEAK_IMPORT int somefunction(); extern void indirect(); -#include <stdio.h> +#include <cstdio> int main() { - printf("meow\n"); + std::printf("meow\n"); if (&somefunction != nullptr) - printf("somefunction existed and it returned %d\n", somefunction()); + std::printf("somefunction existed and it returned %d\n", somefunction()); else - printf("somefunction did not exist\n"); + std::printf("somefunction did not exist\n"); #if SHOULD_INSTALL_LIB indirect(); #endif diff --git a/tests/auto/blackbox/testdata/symbolLinkMode/symbolLinkMode.qbs b/tests/auto/blackbox/testdata/symbolLinkMode/symbolLinkMode.qbs index 2d3d64b00..49bcd9951 100644 --- a/tests/auto/blackbox/testdata/symbolLinkMode/symbolLinkMode.qbs +++ b/tests/auto/blackbox/testdata/symbolLinkMode/symbolLinkMode.qbs @@ -1,15 +1,22 @@ import qbs.FileInfo +import qbs.Host Project { property bool shouldInstallLibrary: true property bool lazy: false Application { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } Depends { name: "cpp" } Depends { name: "functions"; cpp.symbolLinkMode: product.symbolLinkMode - cpp.link: !(product.qbs.targetOS.contains("linux") && product.symbolLinkMode === "weak") + cpp.link: !(product.qbs.targetOS.includes("linux") && product.symbolLinkMode === "weak") } property string symbolLinkMode: project.lazy ? "lazy" : "weak" @@ -20,7 +27,7 @@ Project { property string installLib: "SHOULD_INSTALL_LIB=" + project.shouldInstallLibrary cpp.defines: { if (symbolLinkMode === "weak") { - return qbs.targetOS.contains("darwin") + return qbs.targetOS.includes("darwin") ? ["WEAK_IMPORT=__attribute__((weak_import))", installLib] : ["WEAK_IMPORT=__attribute__((weak))", installLib]; } @@ -42,7 +49,7 @@ Project { Depends { name: "indirect"; cpp.symbolLinkMode: "reexport" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } name: "functions" @@ -52,7 +59,7 @@ Project { cpp.rpaths: [cpp.rpathOrigin] Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") cpp.sonamePrefix: "@rpath" } @@ -65,7 +72,7 @@ Project { Export { // let the autotest pass on Linux where reexport is not supported - Depends { name: "indirect"; condition: !qbs.targetOS.contains("darwin") } + Depends { name: "indirect"; condition: !qbs.targetOS.includes("darwin") } // on Linux, there is no LC_WEAK_LOAD_DYLIB equivalent (the library is simply omitted // from the list of load commands entirely), so use LD_PRELOAD to emulate @@ -84,7 +91,7 @@ Project { Depends { name: "cpp" } Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } name: "indirect" @@ -93,7 +100,7 @@ Project { cpp.minimumMacosVersion: "10.7" Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") // reexport is incompatible with rpath, // "ERROR: ld: file not found: @rpath/libindirect.dylib for architecture x86_64" cpp.sonamePrefix: qbs.installRoot + "/lib" diff --git a/tests/auto/blackbox/testdata/system-include-paths/main.cpp b/tests/auto/blackbox/testdata/system-include-paths/main.cpp index e449173d3..10d376a31 100644 --- a/tests/auto/blackbox/testdata/system-include-paths/main.cpp +++ b/tests/auto/blackbox/testdata/system-include-paths/main.cpp @@ -1,4 +1,4 @@ -#include <stdio.h> +#include <cstdio> #include <gagagugu.h> int main() diff --git a/tests/auto/blackbox/testdata/system-run-paths/system-run-paths.qbs b/tests/auto/blackbox/testdata/system-run-paths/system-run-paths.qbs index 6e2137173..35dd7a00f 100644 --- a/tests/auto/blackbox/testdata/system-run-paths/system-run-paths.qbs +++ b/tests/auto/blackbox/testdata/system-run-paths/system-run-paths.qbs @@ -20,4 +20,9 @@ Project { cpp.rpaths: qbs.installRoot + "/lib" cpp.systemRunPaths: project.setRunPaths ? [qbs.installRoot + "/lib"] : [] } + Probe { + id: checker + property bool isUnix: qbs.targetOS.contains("unix") + configure: { console.info("is unix: " + isUnix); } + } } diff --git a/tests/auto/blackbox/testdata/trackAddFile/after/main.cpp b/tests/auto/blackbox/testdata/trackAddFile/after/main.cpp index 0e474b221..d108825d6 100644 --- a/tests/auto/blackbox/testdata/trackAddFile/after/main.cpp +++ b/tests/auto/blackbox/testdata/trackAddFile/after/main.cpp @@ -31,7 +31,7 @@ int main(int argc, char **argv) { - printf("Hello World!\n"); + std::printf("Hello World!\n"); Narf narf; narf.shout(); Zort zort; diff --git a/tests/auto/blackbox/testdata/trackAddFile/after/trackAddFile.qbs b/tests/auto/blackbox/testdata/trackAddFile/after/trackAddFile.qbs index f4b9ba21f..4d454d4ff 100644 --- a/tests/auto/blackbox/testdata/trackAddFile/after/trackAddFile.qbs +++ b/tests/auto/blackbox/testdata/trackAddFile/after/trackAddFile.qbs @@ -1,5 +1,13 @@ +import qbs.Host + Project { Product { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: 'someapp' type: 'application' consoleApplication: true diff --git a/tests/auto/blackbox/testdata/trackAddFile/after/zort.cpp b/tests/auto/blackbox/testdata/trackAddFile/after/zort.cpp index 1915ea869..55a9dfa6d 100644 --- a/tests/auto/blackbox/testdata/trackAddFile/after/zort.cpp +++ b/tests/auto/blackbox/testdata/trackAddFile/after/zort.cpp @@ -30,6 +30,6 @@ void Zort::shout() { - printf("ZORT!\n"); + std::printf("ZORT!\n"); } diff --git a/tests/auto/blackbox/testdata/trackAddFile/before/main.cpp b/tests/auto/blackbox/testdata/trackAddFile/before/main.cpp index f989e1d9b..e8915030e 100644 --- a/tests/auto/blackbox/testdata/trackAddFile/before/main.cpp +++ b/tests/auto/blackbox/testdata/trackAddFile/before/main.cpp @@ -30,7 +30,7 @@ int main(int argc, char **argv) { - printf("Hello World!\n"); + std::printf("Hello World!\n"); Narf narf; narf.shout(); return 0; diff --git a/tests/auto/blackbox/testdata/trackAddFile/before/narf.cpp b/tests/auto/blackbox/testdata/trackAddFile/before/narf.cpp index 280d5f3bd..c301b57df 100644 --- a/tests/auto/blackbox/testdata/trackAddFile/before/narf.cpp +++ b/tests/auto/blackbox/testdata/trackAddFile/before/narf.cpp @@ -30,6 +30,6 @@ void Narf::shout() { - printf("NARF!\n"); + std::printf("NARF!\n"); } diff --git a/tests/auto/blackbox/testdata/trackAddFile/before/trackAddFile.qbs b/tests/auto/blackbox/testdata/trackAddFile/before/trackAddFile.qbs index bb0ab7d44..fd858b247 100644 --- a/tests/auto/blackbox/testdata/trackAddFile/before/trackAddFile.qbs +++ b/tests/auto/blackbox/testdata/trackAddFile/before/trackAddFile.qbs @@ -1,5 +1,13 @@ +import qbs.Host + Project { Product { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: 'someapp' type: 'application' consoleApplication: true diff --git a/tests/auto/blackbox/testdata/trackExternalProductChanges/trackExternalProductChanges.qbs b/tests/auto/blackbox/testdata/trackExternalProductChanges/trackExternalProductChanges.qbs index 534f49ff2..0e28e5687 100644 --- a/tests/auto/blackbox/testdata/trackExternalProductChanges/trackExternalProductChanges.qbs +++ b/tests/auto/blackbox/testdata/trackExternalProductChanges/trackExternalProductChanges.qbs @@ -11,4 +11,9 @@ CppApplication { name: "file that needs help from the environment to find a header" files: "including.cpp" } + Probe { + id: checker + property bool isGcc: qbs.toolchain.contains("gcc") + configure: { console.info("is gcc: " + isGcc); } + } } diff --git a/tests/auto/blackbox/testdata/trackFileTags/after/main.cpp b/tests/auto/blackbox/testdata/trackFileTags/after/main.cpp index 1d2c8ebb7..7520b5ed7 100644 --- a/tests/auto/blackbox/testdata/trackFileTags/after/main.cpp +++ b/tests/auto/blackbox/testdata/trackFileTags/after/main.cpp @@ -31,7 +31,7 @@ int foo(); int main(int argc, char **argv) { - printf("there's %d foo here\n", foo()); + std::printf("there's %d foo here\n", foo()); return 0; } diff --git a/tests/auto/blackbox/testdata/trackFileTags/after/trackFileTags.qbs b/tests/auto/blackbox/testdata/trackFileTags/after/trackFileTags.qbs index 869ce238b..1c5b6b56f 100644 --- a/tests/auto/blackbox/testdata/trackFileTags/after/trackFileTags.qbs +++ b/tests/auto/blackbox/testdata/trackFileTags/after/trackFileTags.qbs @@ -1,7 +1,15 @@ import qbs.TextFile +import qbs.Host + Project { Product { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: 'someapp' type: 'application' consoleApplication: true diff --git a/tests/auto/blackbox/testdata/trackFileTags/before/main.cpp b/tests/auto/blackbox/testdata/trackFileTags/before/main.cpp index 3016f8bb1..b4d71f995 100644 --- a/tests/auto/blackbox/testdata/trackFileTags/before/main.cpp +++ b/tests/auto/blackbox/testdata/trackFileTags/before/main.cpp @@ -29,7 +29,7 @@ int main(int argc, char **argv) { - printf("there's no foo here\n"); + std::printf("there's no foo here\n"); return 0; } diff --git a/tests/auto/blackbox/testdata/trackFileTags/before/trackFileTags.qbs b/tests/auto/blackbox/testdata/trackFileTags/before/trackFileTags.qbs index ebe31bf26..86771ab8f 100644 --- a/tests/auto/blackbox/testdata/trackFileTags/before/trackFileTags.qbs +++ b/tests/auto/blackbox/testdata/trackFileTags/before/trackFileTags.qbs @@ -1,7 +1,15 @@ import qbs.TextFile +import qbs.Host + Project { Product { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } name: 'someapp' type: 'application' consoleApplication: true diff --git a/tests/auto/blackbox/testdata/trackProducts/after/zoo.cpp b/tests/auto/blackbox/testdata/trackProducts/after/zoo.cpp index b65fb3f9d..fc0d13e4b 100644 --- a/tests/auto/blackbox/testdata/trackProducts/after/zoo.cpp +++ b/tests/auto/blackbox/testdata/trackProducts/after/zoo.cpp @@ -30,5 +30,5 @@ int main() { - printf("zoo\n"); + std::printf("zoo\n"); } diff --git a/tests/auto/blackbox/testdata/trackProducts/before/bar.cpp b/tests/auto/blackbox/testdata/trackProducts/before/bar.cpp index 7880c8669..3664897de 100644 --- a/tests/auto/blackbox/testdata/trackProducts/before/bar.cpp +++ b/tests/auto/blackbox/testdata/trackProducts/before/bar.cpp @@ -30,5 +30,5 @@ int main() { - printf("bar\n"); + std::printf("bar\n"); } diff --git a/tests/auto/blackbox/testdata/trackProducts/before/foo.cpp b/tests/auto/blackbox/testdata/trackProducts/before/foo.cpp index 865fb1299..fb5c32769 100644 --- a/tests/auto/blackbox/testdata/trackProducts/before/foo.cpp +++ b/tests/auto/blackbox/testdata/trackProducts/before/foo.cpp @@ -30,5 +30,5 @@ int main() { - printf("foo\n"); + std::printf("foo\n"); } diff --git a/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/a/a.qbs b/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/a/a.qbs new file mode 100644 index 000000000..fd52488fb --- /dev/null +++ b/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/a/a.qbs @@ -0,0 +1,5 @@ +Module { + validate: { + throw "Module cannot be loaded"; + } +} diff --git a/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/b/b.qbs b/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/b/b.qbs new file mode 100644 index 000000000..605a2aaee --- /dev/null +++ b/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/b/b.qbs @@ -0,0 +1,3 @@ +Module { + Depends { name: "a" } +} diff --git a/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/c/c.qbs b/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/c/c.qbs new file mode 100644 index 000000000..ac7dbbec6 --- /dev/null +++ b/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/c/c.qbs @@ -0,0 +1,3 @@ +Module { + Depends { name: "a"; required: false } +} diff --git a/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/d/d.qbs b/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/d/d.qbs new file mode 100644 index 000000000..0bdd8c3b7 --- /dev/null +++ b/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/d/d.qbs @@ -0,0 +1,4 @@ +Module { + Depends { name: "b"; } + Depends { name: "c"; } +} diff --git a/tests/auto/blackbox/testdata/transitive-invalid-dependencies/transitive-invalid-dependencies.qbs b/tests/auto/blackbox/testdata/transitive-invalid-dependencies/transitive-invalid-dependencies.qbs new file mode 100644 index 000000000..209b1e47d --- /dev/null +++ b/tests/auto/blackbox/testdata/transitive-invalid-dependencies/transitive-invalid-dependencies.qbs @@ -0,0 +1,11 @@ +Product { + property bool modulePresent: { + console.info("b.present = " + b.present); + console.info("c.present = " + c.present); + console.info("d.present = " + d.present); + } + + Depends { name: "b"; required: false } + Depends { name: "c"; required: false } + Depends { name: "d"; required: false } +} diff --git a/tests/auto/blackbox/testdata/undefined-target-platform/undefined-target-platform.qbs b/tests/auto/blackbox/testdata/undefined-target-platform/undefined-target-platform.qbs new file mode 100644 index 000000000..4a738afcc --- /dev/null +++ b/tests/auto/blackbox/testdata/undefined-target-platform/undefined-target-platform.qbs @@ -0,0 +1,13 @@ +import qbs.File +import qbs.FileInfo + +Product { + name: "undefined-target-platform" + qbs.targetPlatform: undefined + + readonly property bool _validate: { + if ((qbs.targetOS instanceof Array) && qbs.targetOS.length === 0) + return true; + throw "Invalid qbs.targetOS value: " + qbs.targetOS; + } +} diff --git a/tests/auto/blackbox/testdata/variant-suffix/variant-suffix.qbs b/tests/auto/blackbox/testdata/variant-suffix/variant-suffix.qbs index b6e025e4c..1131e6a2f 100644 --- a/tests/auto/blackbox/testdata/variant-suffix/variant-suffix.qbs +++ b/tests/auto/blackbox/testdata/variant-suffix/variant-suffix.qbs @@ -1,8 +1,8 @@ StaticLibrary { name: "l" - Depends { condition: qbs.targetOS.contains("darwin"); name: "bundle" } - Properties { condition: qbs.targetOS.contains("darwin"); bundle.isBundle: false } + Depends { condition: qbs.targetOS.includes("darwin"); name: "bundle" } + Properties { condition: qbs.targetOS.includes("darwin"); bundle.isBundle: false } aggregate: false property string variantSuffix @@ -31,8 +31,8 @@ StaticLibrary { id: targetOSProbe property stringList targetOS: qbs.targetOS configure: { - console.info("is Windows: " + targetOS.contains("windows")); - console.info("is Apple: " + targetOS.contains("darwin")); + console.info("is Windows: " + targetOS.includes("windows")); + console.info("is Apple: " + targetOS.includes("darwin")); } } } diff --git a/tests/auto/blackbox/testdata/vcs/vcstest.qbs b/tests/auto/blackbox/testdata/vcs/vcstest.qbs index 5d359e2c7..4f861654b 100644 --- a/tests/auto/blackbox/testdata/vcs/vcstest.qbs +++ b/tests/auto/blackbox/testdata/vcs/vcstest.qbs @@ -1,4 +1,12 @@ +import qbs.Host + CppApplication { + condition: { + var result = qbs.targetPlatform === Host.platform(); + if (!result) + console.info("targetPlatform differs from hostPlatform"); + return result; + } Depends { name: "vcs" } vcs.headerFileName: "my-repo-state.h" files: ["main.cpp"] diff --git a/tests/auto/blackbox/testdata/versionscript/versionscript.qbs b/tests/auto/blackbox/testdata/versionscript/versionscript.qbs index cc5c7b1cc..fcb4314a2 100644 --- a/tests/auto/blackbox/testdata/versionscript/versionscript.qbs +++ b/tests/auto/blackbox/testdata/versionscript/versionscript.qbs @@ -20,6 +20,12 @@ DynamicLibrary { return [cmd]; } } + Probe { + id: checker + property bool isLinux: qbs.targetOS.includes("linux") + property bool isGcc: qbs.toolchain.contains("gcc") + configure: { console.info("is gcc for Linux: " + (isLinux && isGcc)); } + } qbs.installPrefix: "" install: true diff --git a/tests/auto/blackbox/testdata/whole-archive/whole-archive.qbs b/tests/auto/blackbox/testdata/whole-archive/whole-archive.qbs index f3bcff2cd..c138e46c0 100644 --- a/tests/auto/blackbox/testdata/whole-archive/whole-archive.qbs +++ b/tests/auto/blackbox/testdata/whole-archive/whole-archive.qbs @@ -32,7 +32,8 @@ Project { property string compilerVersion: cpp.compilerVersion property string dummy: product.linkWholeArchive // To force probe re-execution configure: { - if (!toolchain.contains("msvc") + if (!toolchain.includes("msvc") + || toolchain.includes("clang-cl") || Utilities.versionCompare(compilerVersion, "19.0.24215.1") >= 0) { console.info("can link whole archives"); } else { diff --git a/tests/auto/blackbox/testdata/wildcards-and-change-tracking/nonrecursive/subdir1/file.txt b/tests/auto/blackbox/testdata/wildcards-and-change-tracking/nonrecursive/subdir1/file.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/wildcards-and-change-tracking/nonrecursive/subdir1/file.txt diff --git a/tests/auto/blackbox/testdata/wildcards-and-change-tracking/nonrecursive/subdir2/file.txt b/tests/auto/blackbox/testdata/wildcards-and-change-tracking/nonrecursive/subdir2/file.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/wildcards-and-change-tracking/nonrecursive/subdir2/file.txt diff --git a/tests/auto/blackbox/testdata/wildcards-and-change-tracking/recursive1/recursive.txt b/tests/auto/blackbox/testdata/wildcards-and-change-tracking/recursive1/recursive.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/wildcards-and-change-tracking/recursive1/recursive.txt diff --git a/tests/auto/blackbox/testdata/wildcards-and-change-tracking/recursive2/recursive.txt b/tests/auto/blackbox/testdata/wildcards-and-change-tracking/recursive2/recursive.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/wildcards-and-change-tracking/recursive2/recursive.txt diff --git a/tests/auto/blackbox/testdata/wildcards-and-change-tracking/wildcards-and-change-tracking.qbs b/tests/auto/blackbox/testdata/wildcards-and-change-tracking/wildcards-and-change-tracking.qbs new file mode 100644 index 000000000..0a889bab3 --- /dev/null +++ b/tests/auto/blackbox/testdata/wildcards-and-change-tracking/wildcards-and-change-tracking.qbs @@ -0,0 +1,16 @@ +Product { + Group { + name: "recursive" + files: "**/file.txt" + } + Group { + name: "directories" + prefix: "nonrecursive/" + files: "subdi?/file.txt" + } + Group { + prefix: "nonrecursive/empty/" + name: "no files" + files: "*.txt" + } +} diff --git a/tests/auto/blackbox/testdata/wildcards-and-rules/wildcards-and-rules.qbs b/tests/auto/blackbox/testdata/wildcards-and-rules/wildcards-and-rules.qbs index f6662529d..fe6088943 100644 --- a/tests/auto/blackbox/testdata/wildcards-and-rules/wildcards-and-rules.qbs +++ b/tests/auto/blackbox/testdata/wildcards-and-rules/wildcards-and-rules.qbs @@ -22,7 +22,7 @@ Product { } prepare: { var cmd = new JavaScriptCommand(); - cmd.description = "Creating output artifact"; + cmd.description = "creating output artifact"; cmd.highlight = "codegen"; cmd.sourceCode = function() { var file = new TextFile(output.filePath, TextFile.WriteOnly); diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp index faada314f..dbabfb311 100644 --- a/tests/auto/blackbox/tst_blackbox.cpp +++ b/tests/auto/blackbox/tst_blackbox.cpp @@ -49,10 +49,11 @@ #include <QtCore/qjsonobject.h> #include <QtCore/qjsonvalue.h> #include <QtCore/qlocale.h> -#include <QtCore/qregexp.h> +#include <QtCore/qregularexpression.h> #include <QtCore/qsettings.h> #include <QtCore/qtemporarydir.h> #include <QtCore/qtemporaryfile.h> +#include <QtCore/qversionnumber.h> #include <algorithm> #include <functional> @@ -62,7 +63,6 @@ #define WAIT_FOR_NEW_TIMESTAMP() waitForNewTimestamp(testDataDir) using qbs::Internal::HostOsInfo; -using qbs::Profile; class MacosTarHealer { public: @@ -138,12 +138,32 @@ QString TestBlackbox::findArchiver(const QString &fileName, int *status) QString binary = findExecutable(QStringList(fileName)); if (binary.isEmpty()) { const SettingsPtr s = settings(); - Profile p(profileName(), s.get()); + qbs::Profile p(profileName(), s.get()); binary = findExecutable(p.value("archiver.command").toStringList()); } return binary; } +bool TestBlackbox::prepareAndRunConan() +{ + QString executable = findExecutable({"conan"}); + if (executable.isEmpty()) { + qInfo() << "conan is not installed or not available in PATH."; + return false; + } + const auto profilePath = QDir::homePath() + "/.conan2/profiles/qbs-test"; + if (!QFileInfo(profilePath).exists()) { + qInfo() << "conan profile is not installed, run './scripts/setup-conan-profiles.sh'"; + return false; + } + QProcess conan; + QDir::setCurrent(testDataDir + "/conan-provider/testlibdep"); + rmDirR("build"); + QStringList arguments{"install", ".", "--profile:all=qbs-test", "--output-folder=build"}; + conan.start(executable, arguments); + return waitForProcessSuccess(conan, 60000); +} + bool TestBlackbox::lexYaccExist() { return !findExecutable(QStringList("lex")).isEmpty() @@ -253,6 +273,13 @@ void TestBlackbox::systemIncludePaths() QCOMPARE(runQbs(), 0); } +void TestBlackbox::distributionIncludePaths() +{ + const QString projectDir = testDataDir + "/distribution-include-paths"; + QDir::setCurrent(projectDir); + QCOMPARE(runQbs(), 0); +} + void TestBlackbox::tar() { if (HostOsInfo::hostOs() == HostOsInfo::HostOsWindows) @@ -291,7 +318,7 @@ void TestBlackbox::textTemplate() static QStringList sortedFileList(const QByteArray &ba) { - auto list = QString::fromUtf8(ba).split(QRegExp("[\r\n]"), QString::SkipEmptyParts); + auto list = QString::fromUtf8(ba).split(QRegularExpression("[\r\n]"), Qt::SkipEmptyParts); std::sort(list.begin(), list.end()); return list; } @@ -356,6 +383,57 @@ TestBlackbox::TestBlackbox() : TestBlackboxBase (SRCDIR "/testdata", "blackbox") { } +void TestBlackbox::allowedValues() +{ + QFETCH(QString, property); + QFETCH(QString, value); + QFETCH(QString, invalidValue); + + QDir::setCurrent(testDataDir + "/allowed-values"); + rmDirR(relativeBuildDir()); + + QbsRunParameters params; + if (!property.isEmpty() && !value.isEmpty()) { + params.arguments << QStringLiteral("%1:%2").arg(property, value); + } + + params.expectFailure = !invalidValue.isEmpty(); + QCOMPARE(runQbs(params) == 0, !params.expectFailure); + if (params.expectFailure) { + const auto errorString = + QStringLiteral("Value '%1' is not allowed for property").arg(invalidValue); + QVERIFY2(m_qbsStderr.contains(errorString.toUtf8()), m_qbsStderr.constData()); + } +} + +void TestBlackbox::allowedValues_data() +{ + QTest::addColumn<QString>("property"); + QTest::addColumn<QString>("value"); + QTest::addColumn<QString>("invalidValue"); + + QTest::newRow("default") << QString() << QString() << QString(); + + QTest::newRow("allowed (product, CLI)") << "products.p.prop" << "foo" << QString(); + QTest::newRow("not allowed (product, CLI)") << "products.p.prop" << "bar" << "bar"; + QTest::newRow("allowed (product, JS)") << "products.p.prop2" << "foo" << QString(); + QTest::newRow("not allowed (product, JS)") << "products.p.prop2" << "bar" << "bar"; + + QTest::newRow("allowed single (module, CLI)") << "modules.a.prop" << "foo" << QString(); + QTest::newRow("not allowed single (module, CLI)") << "modules.a.prop" << "baz" << "baz"; + QTest::newRow("allowed mult (module, CLI)") << "modules.a.prop" << "foo,bar" << QString(); + QTest::newRow("not allowed mult (module, CLI)") << "modules.a.prop" << "foo,baz" << "baz"; + + QTest::newRow("allowed single (module, JS)") << "modules.a.prop2" << "foo" << QString(); + QTest::newRow("not allowed single (module, JS)") << "modules.a.prop2" << "baz" << "baz"; + QTest::newRow("allowed mult (module, JS)") << "modules.a.prop2" << "foo,bar" << QString(); + QTest::newRow("not allowed mult (module, JS)") << "modules.a.prop2" << "foo,baz" << "baz"; + + // undefined should always be allowed + QTest::newRow("undefined (product)") << "products.p.prop" << "undefined" << QString(); + QTest::newRow("undefined (module)") << "modules.a.prop" << "undefined" << QString(); +} + void TestBlackbox::addFileTagToGeneratedArtifact() { QDir::setCurrent(testDataDir + "/add-filetag-to-generated-artifact"); @@ -640,7 +718,7 @@ void TestBlackbox::buildDirectories() QDir::setCurrent(projectDir); QCOMPARE(runQbs(), 0); const QStringList outputLines - = QString::fromLocal8Bit(m_qbsStdout.trimmed()).split('\n', QString::SkipEmptyParts); + = QString::fromLocal8Bit(m_qbsStdout.trimmed()).split('\n', Qt::SkipEmptyParts); QVERIFY2(outputLines.contains(projectDir + '/' + relativeProductBuildDir("p1")), m_qbsStdout.constData()); QVERIFY2(outputLines.contains(projectDir + '/' + relativeProductBuildDir("p2")), @@ -649,6 +727,45 @@ void TestBlackbox::buildDirectories() QVERIFY2(outputLines.contains(projectDir), m_qbsStdout.constData()); } +void TestBlackbox::buildDirPlaceholders_data() +{ + QTest::addColumn<QString>("buildDir"); + QTest::addColumn<bool>("setProjectFile"); + QTest::addColumn<bool>("successExpected"); + + QTest::newRow("normal dir, with project file") << "somedir" << true << true; + QTest::newRow("normal dir, without project file") << "somedir" << false << true; + QTest::newRow("@project, with project file") << "somedir/@project" << true << true; + QTest::newRow("@project, without project file") << "somedir/@project" << false << false; + QTest::newRow("@path, with project file") << "somedir/@path" << true << true; + QTest::newRow("@path, without project file") << "somedir/@path" << false << false; +} + +void TestBlackbox::buildDirPlaceholders() +{ + QFETCH(QString, buildDir); + QFETCH(bool, setProjectFile); + QFETCH(bool, successExpected); + + const QString projectDir = testDataDir + "/build-dir-placeholders"; + rmDirR(projectDir); + QVERIFY(QDir().mkpath(projectDir)); + QDir::setCurrent(projectDir); + QFile projectFile("build-dir-placeholders.qbs"); + QVERIFY(projectFile.open(QIODevice::WriteOnly)); + projectFile.write("Product {\n}\n"); + projectFile.flush(); + rmDirR(relativeBuildDir()); + QbsRunParameters params; + params.buildDirectory = buildDir; + if (setProjectFile) { + params.arguments << "-f" + << "build-dir-placeholders.qbs"; + } + params.expectFailure = !successExpected; + QCOMPARE(runQbs(params) == 0, successExpected); +} + void TestBlackbox::buildEnvChange() { QDir::setCurrent(testDataDir + "/buildenv-change"); @@ -713,6 +830,69 @@ void TestBlackbox::buildGraphVersions() QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); } +void TestBlackbox::buildVariantDefaults_data() +{ + QTest::addColumn<QString>("buildVariant"); + QTest::newRow("default") << QString(); + QTest::newRow("debug") << QStringLiteral("debug"); + QTest::newRow("release") << QStringLiteral("release"); + QTest::newRow("profiling") << QStringLiteral("profiling"); +} + +void TestBlackbox::buildVariantDefaults() +{ + QFETCH(QString, buildVariant); + QDir::setCurrent(testDataDir + "/build-variant-defaults"); + QbsRunParameters params{QStringLiteral("resolve")}; + if (!buildVariant.isEmpty()) + params.arguments << ("modules.qbs.buildVariant:" + buildVariant); + QCOMPARE(runQbs(params), 0); +} + +void TestBlackbox::capnproto() +{ + QFETCH(QString, projectFile); + QFETCH(QStringList, arguments); + QDir::setCurrent(testDataDir + "/capnproto"); + rmDirR(relativeBuildDir()); + + if (QTest::currentDataTag() == QLatin1String("cpp-conan") + || QTest::currentDataTag() == QLatin1String("rpc-conan")) { + if (!prepareAndRunConan()) + QSKIP("conan is not prepared, check messages above"); + } + + QbsRunParameters params{QStringLiteral("resolve"), {QStringLiteral("-f"), projectFile}}; + params.arguments << arguments; + QCOMPARE(runQbs(params), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); + if (m_qbsStdout.contains("capnproto is not present")) + QSKIP("capnproto is not present"); + + params.command = QStringLiteral("build"); + QCOMPARE(runQbs(params), 0); +} + +void TestBlackbox::capnproto_data() +{ + QTest::addColumn<QString>("projectFile"); + QTest::addColumn<QStringList>("arguments"); + + QStringList pkgConfigArgs({"project.qbsModuleProviders:qbspkgconfig"}); + QTest::newRow("cpp-pkgconfig") << QStringLiteral("capnproto_cpp.qbs") << pkgConfigArgs; + QTest::newRow("rpc-pkgconfig") << QStringLiteral("greeter_cpp.qbs") << pkgConfigArgs; + QTest::newRow("relative import") + << QStringLiteral("capnproto_relative_import.qbs") << pkgConfigArgs; + QTest::newRow("absolute import") + << QStringLiteral("capnproto_absolute_import.qbs") << pkgConfigArgs; + + QStringList conanArgs( + {"project.qbsModuleProviders:conan", "moduleProviders.conan.installDirectory:build"}); + QTest::newRow("cpp-conan") << QStringLiteral("capnproto_cpp.qbs") << conanArgs; + QTest::newRow("rpc-conan") << QStringLiteral("greeter_cpp.qbs") << conanArgs; +} + void TestBlackbox::changedFiles_data() { QTest::addColumn<bool>("useChangedFilesForInitialBuild"); @@ -885,7 +1065,7 @@ void TestBlackbox::dependenciesProperty() QJsonArray cpp_dependencies = product2_cpp.value("dependencies").toArray(); QVERIFY(!cpp_dependencies.isEmpty()); int qbsCount = 0; - for (const auto &dep : cpp_dependencies) { + for (const auto dep : cpp_dependencies) { if (dep.toObject().value("name").toString() == "qbs") ++qbsCount; } @@ -897,7 +1077,7 @@ void TestBlackbox::dependenciesProperty() REPLACE_IN_FILE(projectFile, "// Depends { name: 'newDependency' }", "Depends { name: 'newDependency' }"); QCOMPARE(runQbs(), 0); - QVERIFY2(m_qbsStdout.contains("generate product1.deps"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("generating product1.deps"), m_qbsStdout.constData()); readDepsOutput(depsFile, jsondoc); dependencies = jsondoc.array(); QCOMPARE(dependencies.size(), 3); @@ -908,7 +1088,7 @@ void TestBlackbox::dependenciesProperty() REPLACE_IN_FILE(projectFile, "// Depends { name: 'product2' }", "Depends { name: 'product2' }"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); - QVERIFY2(!m_qbsStdout.contains("generate product1.deps"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("generating product1.deps"), m_qbsStdout.constData()); readDepsOutput(depsFile, jsondoc); dependencies = jsondoc.array(); QCOMPARE(dependencies.size(), 3); @@ -918,7 +1098,7 @@ void TestBlackbox::dependenciesProperty() 0); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("compiling product2.cpp"), m_qbsStdout.constData()); - QVERIFY2(m_qbsStdout.contains("generate product1.deps"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("generating product1.deps"), m_qbsStdout.constData()); readDepsOutput(depsFile, jsondoc); dependencies = jsondoc.array(); QCOMPARE(dependencies.size(), 3); @@ -930,7 +1110,7 @@ void TestBlackbox::dependenciesProperty() "products.product2.cpp.defines:DIGEDAG"})), 0); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling product2.cpp"), m_qbsStdout.constData()); - QVERIFY2(m_qbsStdout.contains("generate product1.deps"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("generating product1.deps"), m_qbsStdout.constData()); readDepsOutput(depsFile, jsondoc); dependencies = jsondoc.array(); QCOMPARE(dependencies.size(), 3); @@ -942,40 +1122,77 @@ void TestBlackbox::dependenciesProperty() QCOMPARE(product2_cpp_defines.first().toString(), QLatin1String("DIGEDAG")); } -void TestBlackbox::dependencyProfileMismatch() +void TestBlackbox::dependencyScanningLoop() { - QDir::setCurrent(testDataDir + "/dependency-profile-mismatch"); - const SettingsPtr s = settings(); - qbs::Internal::TemporaryProfile depProfile("qbs_autotests_profileMismatch", s.get()); - depProfile.p.setValue("qbs.architecture", "x86"); // Profiles must not be empty... - s->sync(); - QbsRunParameters params(QStringList() << ("project.mainProfile:" + profileName()) - << ("project.depProfile:" + depProfile.p.name())); - params.expectFailure = true; - QVERIFY2(runQbs(params) != 0, m_qbsStderr.constData()); - QVERIFY2(m_qbsStderr.contains(profileName().toLocal8Bit()) - && m_qbsStderr.contains("', which does not exist"), - m_qbsStderr.constData()); + QDir::setCurrent(testDataDir + "/dependency-scanning-loop"); + QCOMPARE(runQbs(), 0); + QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); } void TestBlackbox::deprecatedProperty() { + QFETCH(QString, version); + QFETCH(QString, mode); + QFETCH(bool, expiringWarning); + QFETCH(bool, expiringError); + QDir::setCurrent(testDataDir + "/deprecated-property"); QbsRunParameters params(QStringList("-q")); params.expectFailure = true; + params.environment.insert("REMOVAL_VERSION", version); + if (!mode.isEmpty()) + params.arguments << "--deprecation-warnings" << mode; QVERIFY(runQbs(params) != 0); m_qbsStderr = QDir::fromNativeSeparators(QString::fromLocal8Bit(m_qbsStderr)).toLocal8Bit(); - QVERIFY2(m_qbsStderr.contains("deprecated-property.qbs:6:24 The property 'oldProp' is " - "deprecated and will be removed in Qbs 99.9.0."), m_qbsStderr.constData()); - QVERIFY2(m_qbsStderr.contains("deprecated-property.qbs:7:28 The property 'veryOldProp' can no " - "longer be used. It was removed in Qbs 1.3.0."), m_qbsStderr.constData()); + const bool hasExpiringWarning = m_qbsStderr.contains(QByteArray( + "deprecated-property.qbs:4:29 The property 'expiringProp' is " + "deprecated and will be removed in Qbs ") + version.toLocal8Bit()); + QVERIFY2(expiringWarning == hasExpiringWarning, m_qbsStderr.constData()); + const bool hasRemovedOutput = m_qbsStderr.contains( + "deprecated-property.qbs:5:28 The property 'veryOldProp' can no " + "longer be used. It was removed in Qbs 1.3.0."); + QVERIFY2(hasRemovedOutput == !expiringError, m_qbsStderr.constData()); QVERIFY2(m_qbsStderr.contains("Property 'forgottenProp' was scheduled for removal in version " "1.8.0, but is still present."), m_qbsStderr.constData()); QVERIFY2(m_qbsStderr.contains("themodule/m.qbs:22:5 Removal version for 'forgottenProp' " "specified here."), m_qbsStderr.constData()); - QVERIFY2(m_qbsStderr.count("Use newProp instead.") == 2, m_qbsStderr.constData()); - QVERIFY2(m_qbsStderr.count("is deprecated") == 1, m_qbsStderr.constData()); - QVERIFY2(m_qbsStderr.count("was removed") == 1, m_qbsStderr.constData()); + QVERIFY2(m_qbsStderr.count("Use newProp instead.") == 1 + + int(expiringWarning && !expiringError), m_qbsStderr.constData()); + QVERIFY2(m_qbsStderr.count("is deprecated") == int(expiringWarning), m_qbsStderr.constData()); + QVERIFY2(m_qbsStderr.count("was removed") == int(!expiringError), m_qbsStderr.constData()); +} + +void TestBlackbox::deprecatedProperty_data() +{ + QTest::addColumn<QString>("version"); + QTest::addColumn<QString>("mode"); + QTest::addColumn<bool>("expiringWarning"); + QTest::addColumn<bool>("expiringError"); + + const auto current = QVersionNumber::fromString(QBS_VERSION); + const QString next = QVersionNumber(current.majorVersion(), current.minorVersion() + 1) + .toString(); + const QString nextNext = QVersionNumber(current.majorVersion(), current.minorVersion() + 2) + .toString(); + const QString nextMajor = QVersionNumber(current.majorVersion() + 1).toString(); + + QTest::newRow("default/next") << next << QString() << true << false; + QTest::newRow("default/nextnext") << nextNext << QString() << false << false; + QTest::newRow("default/nextmajor") << nextMajor << QString() << true << false; + QTest::newRow("error/next") << next << QString("error") << true << true; + QTest::newRow("error/nextnext") << nextNext << QString("error") << true << true; + QTest::newRow("error/nextmajor") << nextMajor << QString("error") << true << true; + QTest::newRow("on/next") << next << QString("on") << true << false; + QTest::newRow("on/nextnext") << nextNext << QString("on") << true << false; + QTest::newRow("on/nextmajor") << nextMajor << QString("on") << true << false; + QTest::newRow("before-removal/next") << next << QString("before-removal") << true << false; + QTest::newRow("before-removal/nextnext") << nextNext << QString("before-removal") + << false << false; + QTest::newRow("before-removal/nextmajor") << nextMajor << QString("before-removal") + << true << false; + QTest::newRow("off/next") << next << QString("off") << false << false; + QTest::newRow("off/nextnext") << nextNext << QString("off") << false << false; + QTest::newRow("off/nextmajor") << nextMajor << QString("off") << false << false; } void TestBlackbox::disappearedProfile() @@ -1008,16 +1225,16 @@ void TestBlackbox::disappearedProfile() QbsRunParameters buildParams; buildParams.profile.clear(); QCOMPARE(runQbs(buildParams), 0); - QVERIFY2(m_qbsStdout.contains("Creating dummy1.txt with p1 from profile"), + QVERIFY2(m_qbsStdout.contains("creating dummy1.txt with p1 from profile"), m_qbsStdout.constData()); - QVERIFY2(m_qbsStdout.contains("Creating dummy2.txt with p2 from profile"), + QVERIFY2(m_qbsStdout.contains("creating dummy2.txt with p2 from profile"), m_qbsStdout.constData()); // Now we do use the "resolve" command, so the new property value is taken into account. QCOMPARE(runQbs(resolveParams), 0); QCOMPARE(runQbs(buildParams), 0); - QVERIFY2(!m_qbsStdout.contains("Creating dummy1.txt"), m_qbsStdout.constData()); - QVERIFY2(m_qbsStdout.contains("Creating dummy2.txt with p2 new from profile"), + QVERIFY2(!m_qbsStdout.contains("creating dummy1.txt"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("creating dummy2.txt with p2 new from profile"), m_qbsStdout.constData()); // Now we change the profile again without a "resolve" command. However, this time we @@ -1030,8 +1247,8 @@ void TestBlackbox::disappearedProfile() "property string p1: 'p1 from module'"); QCOMPARE(runQbs(buildParams), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); - QVERIFY2(!m_qbsStdout.contains("Creating dummy1.txt"), m_qbsStdout.constData()); - QVERIFY2(!m_qbsStdout.contains("Creating dummy2.txt"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("creating dummy1.txt"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("creating dummy2.txt"), m_qbsStdout.constData()); // Now we run the "resolve" command without giving the necessary settings path to find // the profile. @@ -1055,10 +1272,12 @@ void TestBlackbox::discardUnusedData() QVERIFY2(m_qbsStdout.contains("is Darwin"), m_qbsStdout.constData()); const bool isDarwin = m_qbsStdout.contains("is Darwin: true"); const QString output = QString::fromLocal8Bit(m_qbsStdout); - QRegExp pattern(".*---(.*)---.*"); - QVERIFY2(pattern.exactMatch(output), qPrintable(output)); - QCOMPARE(pattern.captureCount(), 1); - const QString nmPath = pattern.capturedTexts().at(1); + const QRegularExpression pattern(QRegularExpression::anchoredPattern(".*---(.*)---.*"), + QRegularExpression::DotMatchesEverythingOption); + const QRegularExpressionMatch match = pattern.match(output); + QVERIFY2(match.hasMatch(), qPrintable(output)); + QCOMPARE(match.lastCapturedIndex(), 1); + const QString nmPath = match.captured(1); if (!QFile::exists(nmPath)) QSKIP("Cannot check for symbol presence: No nm found."); QProcess nm; @@ -1082,6 +1301,13 @@ void TestBlackbox::discardUnusedData_data() QTest::newRow("default") << QString() << true; } +void TestBlackbox::dotDotPcFile() +{ + QDir::setCurrent(testDataDir + "/dot-dot-pc-file"); + + QCOMPARE(runQbs(), 0); +} + void TestBlackbox::driverLinkerFlags() { QDir::setCurrent(testDataDir + QLatin1String("/driver-linker-flags")); @@ -1124,9 +1350,13 @@ void TestBlackbox::dynamicLibraryInModule() QbsRunParameters libParams(QStringList({"-f", "thelibs.qbs", installRootSpec})); libParams.buildDirectory = "libbuild"; QCOMPARE(runQbs(libParams), 0); - QbsRunParameters appParams("run", QStringList({"-f", "theapp.qbs", installRootSpec})); + QbsRunParameters appParams("build", QStringList({"-f", "theapp.qbs", installRootSpec})); appParams.buildDirectory = "appbuild"; QCOMPARE(runQbs(appParams), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); + appParams.command = "run"; + QCOMPARE(runQbs(appParams), 0); QVERIFY2(m_qbsStdout.contains("Hello from thelib"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("Hello from theotherlib"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("thirdlib"), m_qbsStdout.constData()); @@ -1232,19 +1462,6 @@ void TestBlackbox::variantSuffix_data() std::make_pair(QString("unix"), QStringList())}); } -static bool waitForProcessSuccess(QProcess &p) -{ - if (!p.waitForStarted() || !p.waitForFinished()) { - qDebug() << p.errorString(); - return false; - } - if (p.exitCode() != 0) { - qDebug() << p.readAllStandardError(); - return false; - } - return true; -} - void TestBlackbox::vcsGit() { const QString gitFilePath = findExecutable(QStringList("git")); @@ -1275,6 +1492,9 @@ void TestBlackbox::vcsGit() return m_qbsStdout.mid(startIndex + 2, endIndex - startIndex - 2); }; + QCOMPARE(runQbs({"resolve", {"-f", repoDir.path()}}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); // Run without git metadata. QbsRunParameters params("run", QStringList{"-f", repoDir.path()}); params.workingDir = repoDir.path() + "/.."; @@ -1340,6 +1560,9 @@ void TestBlackbox::vcsSubversion() if (svnFilePath.isEmpty()) QSKIP("svn not found"); + if (HostOsInfo::isWindowsHost() && qEnvironmentVariableIsSet("GITHUB_ACTIONS")) + QSKIP("Skip this test when running on GitHub"); + // Set up repo. QTemporaryDir repoDir; QVERIFY(repoDir.isValid()); @@ -1363,6 +1586,8 @@ void TestBlackbox::vcsSubversion() failParams.command = "run"; failParams.expectFailure = true; const int retval = runQbs(failParams); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); if (m_qbsStderr.contains("svn too old")) QSKIP("svn too old"); QCOMPARE(retval, 0); @@ -1431,19 +1656,21 @@ void TestBlackbox::versionCheck_data() void TestBlackbox::versionScript() { - const SettingsPtr s = settings(); - Profile buildProfile(profileName(), s.get()); - QStringList toolchain = buildProfile.value("qbs.toolchain").toStringList(); - if (!toolchain.contains("gcc") || targetOs() != HostOsInfo::HostOsLinux) - QSKIP("version script test only applies to Linux"); QDir::setCurrent(testDataDir + "/versionscript"); - QCOMPARE(runQbs(QbsRunParameters(QStringList("-q") - << ("qbs.installRoot:" + QDir::currentPath()))), 0); + QCOMPARE(runQbs(QbsRunParameters("resolve", {"qbs.installRoot:" + QDir::currentPath()})), 0); + const bool isLinuxGcc = m_qbsStdout.contains("is gcc for Linux: true"); + const bool isNotLinuxGcc = m_qbsStdout.contains("is gcc for Linux: false"); + if (isNotLinuxGcc) + QSKIP("version script test only applies to Linux"); + QVERIFY(isLinuxGcc); + QCOMPARE(runQbs(QbsRunParameters(QStringList("-q"))), 0); const QString output = QString::fromLocal8Bit(m_qbsStderr); - QRegExp pattern(".*---(.*)---.*"); - QVERIFY2(pattern.exactMatch(output), qPrintable(output)); + const QRegularExpression pattern(QRegularExpression::anchoredPattern(".*---(.*)---.*"), + QRegularExpression::DotMatchesEverythingOption); + const QRegularExpressionMatch match = pattern.match(output); + QVERIFY2(match.hasMatch(), qPrintable(output)); QCOMPARE(pattern.captureCount(), 1); - const QString nmPath = pattern.capturedTexts().at(1); + const QString nmPath = match.captured(1); if (!QFile::exists(nmPath)) QSKIP("Cannot check for symbol presence: No nm found."); QProcess nm; @@ -1554,7 +1781,7 @@ void TestBlackbox::clean() QVERIFY(!QFile(appExeFilePath).exists()); QVERIFY(!QFile(depObjectFilePath).exists()); QVERIFY(!QFile(depLibFilePath).exists()); - for (const QString &symLink : qAsConst(symlinks)) + for (const QString &symLink : std::as_const(symlinks)) QVERIFY2(!symlinkExists(symLink), qPrintable(symLink)); // Remove all, with a forced re-resolve in between. @@ -1573,7 +1800,7 @@ void TestBlackbox::clean() QVERIFY(!QFile(appExeFilePath).exists()); QVERIFY(!QFile(depObjectFilePath).exists()); QVERIFY(!QFile(depLibFilePath).exists()); - for (const QString &symLink : qAsConst(symlinks)) + for (const QString &symLink : std::as_const(symlinks)) QVERIFY2(!symlinkExists(symLink), qPrintable(symLink)); // Dry run. @@ -1585,7 +1812,7 @@ void TestBlackbox::clean() QVERIFY(regularFileExists(appExeFilePath)); QVERIFY(regularFileExists(depObjectFilePath)); QVERIFY(regularFileExists(depLibFilePath)); - for (const QString &symLink : qAsConst(symlinks)) + for (const QString &symLink : std::as_const(symlinks)) QVERIFY2(symlinkExists(symLink), qPrintable(symLink)); // Product-wise, dependency only. @@ -1599,7 +1826,7 @@ void TestBlackbox::clean() QVERIFY(regularFileExists(appExeFilePath)); QVERIFY(!QFile(depObjectFilePath).exists()); QVERIFY(!QFile(depLibFilePath).exists()); - for (const QString &symLink : qAsConst(symlinks)) + for (const QString &symLink : std::as_const(symlinks)) QVERIFY2(!symlinkExists(symLink), qPrintable(symLink)); // Product-wise, dependent product only. @@ -1613,17 +1840,10 @@ void TestBlackbox::clean() QVERIFY(!QFile(appExeFilePath).exists()); QVERIFY(regularFileExists(depObjectFilePath)); QVERIFY(regularFileExists(depLibFilePath)); - for (const QString &symLink : qAsConst(symlinks)) + for (const QString &symLink : std::as_const(symlinks)) QVERIFY2(symlinkExists(symLink), qPrintable(symLink)); } -void TestBlackbox::concurrentExecutor() -{ - QDir::setCurrent(testDataDir + "/concurrent-executor"); - QCOMPARE(runQbs(QStringList() << "-j" << "2"), 0); - QVERIFY2(!m_qbsStderr.contains("ASSERT"), m_qbsStderr.constData()); -} - void TestBlackbox::conditionalExport() { QDir::setCurrent(testDataDir + "/conditional-export"); @@ -1657,6 +1877,9 @@ void TestBlackbox::conditionalFileTagger() void TestBlackbox::configure() { QDir::setCurrent(testDataDir + "/configure"); + QCOMPARE(runQbs({"resolve"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params; params.command = "run"; QCOMPARE(runQbs(params), 0); @@ -1753,6 +1976,92 @@ void TestBlackbox::cxxLanguageVersion_data() std::make_pair(QString("msvc-new"), QString("/std:"))}); } +void TestBlackbox::conanfileProbe_data() +{ + QTest::addColumn<bool>("forceFailure"); + + QTest::newRow("success") << false; + QTest::newRow("failure") << true; +} + +void TestBlackbox::conanfileProbe() +{ + QFETCH(bool, forceFailure); + + if (qEnvironmentVariableIsSet("GITHUB_ACTIONS")) + QSKIP("Skip this test when running on GitHub"); + + QString executable = findExecutable({"conan"}); + if (executable.isEmpty()) + QSKIP("conan is not installed or not available in PATH."); + + // We first build a dummy package testlib and use that as dependency + // in the testapp package. + QDir::setCurrent(testDataDir + "/conanfile-probe/testlib"); + QStringList arguments { "create", "-o", "opt=True", "-s", "os=AIX", ".", + "testlib/1.2.3@qbs/testing" }; + QProcess conan; + conan.start(executable, arguments); + QVERIFY(waitForProcessSuccess(conan)); + + QDir::setCurrent(testDataDir + "/conanfile-probe/testapp"); + QCOMPARE(runQbs(QbsRunParameters("resolve", + {"--force-probe-execution", + QStringLiteral("projects.conanfile-probe-project.forceFailure:") + + (forceFailure ? "true" : "false")})), forceFailure ? 1 : 0); + + QFile file(relativeBuildDir() + "/results.json"); + QVERIFY(file.open(QIODevice::ReadOnly)); + QVariantMap actualResults = QJsonDocument::fromJson(file.readAll()).toVariant().toMap(); + const auto generatedFilesPath = actualResults.take("generatedFilesPath").toString(); + // We want to make sure that generatedFilesPath is under the project directory, + // but we don't care about the actual name. + QVERIFY(directoryExists(relativeBuildDir() + "/genconan/" + + QFileInfo(generatedFilesPath).baseName())); + + const QVariantMap expectedResults = { + { "json", "TESTLIB_ENV_VAL" }, + { "dependencies", QVariantList{"testlib1", "testlib2"} }, + }; + QCOMPARE(actualResults, expectedResults); +} + +void TestBlackbox::conflictingPropertyValues_data() +{ + QTest::addColumn<bool>("overrideInProduct"); + QTest::newRow("don't override in product") << false; + QTest::newRow("override in product") << true; +} + +void TestBlackbox::conflictingPropertyValues() +{ + QFETCH(bool, overrideInProduct); + + QDir::setCurrent(testDataDir + "/conflicting-property-values"); + if (overrideInProduct) + REPLACE_IN_FILE("conflicting-property-values.qbs", "// low.prop: name", "low.prop: name"); + else + REPLACE_IN_FILE("conflicting-property-values.qbs", "low.prop: name", "// low.prop: name"); + WAIT_FOR_NEW_TIMESTAMP(); + QCOMPARE(runQbs(QString("resolve")), 0); + if (overrideInProduct) { + // Binding in product itself overrides everything else, module-level conflicts + // are irrelevant. + QVERIFY2(m_qbsStdout.contains("final prop value: toplevel"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); + } else { + // Only the conflicts in the highest-level modules are reported, lower-level conflicts + // are irrelevant. + // prop2 does not cause a conflict, because the values are the same. + QVERIFY2(m_qbsStdout.contains("final prop value: highest"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStderr.contains("Conflicting scalar values for property 'prop'"), + m_qbsStderr.constData()); + QVERIFY2(m_qbsStderr.count("values.qbs") == 2, m_qbsStderr.constData()); + QVERIFY2(m_qbsStderr.contains("values.qbs:20:23"), m_qbsStderr.constData()); + QVERIFY2(m_qbsStderr.contains("values.qbs:30:23"), m_qbsStderr.constData()); + } +} + void TestBlackbox::cpuFeatures() { QDir::setCurrent(testDataDir + "/cpu-features"); @@ -1784,6 +2093,13 @@ void TestBlackbox::cpuFeatures() } } +void TestBlackbox::dateProperty() +{ + QDir::setCurrent(testDataDir + "/date-property"); + QCOMPARE(runQbs(), 0); + QVERIFY2(m_qbsStdout.contains("The stored date was 1999-12-31"), m_qbsStdout.constData()); +} + void TestBlackbox::renameDependency() { QDir::setCurrent(testDataDir + "/renameDependency"); @@ -1811,13 +2127,19 @@ void TestBlackbox::separateDebugInfo() const bool isWindows = m_qbsStdout.contains("is windows: yes"); const bool isNotWindows = m_qbsStdout.contains("is windows: no"); QVERIFY(isWindows != isNotWindows); + const bool isMacos = m_qbsStdout.contains("is macos: yes"); + const bool isNotMacos = m_qbsStdout.contains("is macos: no"); + QVERIFY(isMacos != isNotMacos); const bool isDarwin = m_qbsStdout.contains("is darwin: yes"); const bool isNotDarwin = m_qbsStdout.contains("is darwin: no"); QVERIFY(isDarwin != isNotDarwin); + const bool isGcc = m_qbsStdout.contains("is gcc: yes"); + const bool isNotGcc = m_qbsStdout.contains("is gcc: no"); + QVERIFY(isGcc != isNotGcc); + const bool isMsvc = m_qbsStdout.contains("is msvc: yes"); + const bool isNotMsvc = m_qbsStdout.contains("is msvc: no"); + QVERIFY(isMsvc != isNotMsvc); - const SettingsPtr s = settings(); - Profile buildProfile(profileName(), s.get()); - QStringList toolchain = buildProfile.value("qbs.toolchain").toStringList(); if (isDarwin) { QVERIFY(directoryExists(relativeProductBuildDir("app1") + "/app1.app.dSYM")); QVERIFY(regularFileExists(relativeProductBuildDir("app1") @@ -1829,8 +2151,13 @@ void TestBlackbox::separateDebugInfo() .entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries).size(), 1); QVERIFY(!QFile::exists(relativeProductBuildDir("app2") + "/app2.app.dSYM")); QVERIFY(!QFile::exists(relativeProductBuildDir("app3") + "/app3.app.dSYM")); - QVERIFY(regularFileExists(relativeProductBuildDir("app3") - + "/app3.app/Contents/MacOS/app3.dwarf")); + if (isMacos) { + QVERIFY(regularFileExists(relativeProductBuildDir("app3") + + "/app3.app/Contents/MacOS/app3.dwarf")); + } else { + QVERIFY(regularFileExists(relativeProductBuildDir("app3") + + "/app3.app/app3.dwarf")); + } QVERIFY(directoryExists(relativeProductBuildDir("app4") + "/app4.dSYM")); QVERIFY(regularFileExists(relativeProductBuildDir("app4") + "/app4.dSYM/Contents/Info.plist")); @@ -1850,8 +2177,13 @@ void TestBlackbox::separateDebugInfo() .entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries).size(), 1); QVERIFY(!QFile::exists(relativeProductBuildDir("foo2") + "/foo2.framework.dSYM")); QVERIFY(!QFile::exists(relativeProductBuildDir("foo3") + "/foo3.framework.dSYM")); - QVERIFY(regularFileExists(relativeProductBuildDir("foo3") - + "/foo3.framework/Versions/A/foo3.dwarf")); + if (isMacos) { + QVERIFY(regularFileExists(relativeProductBuildDir("foo3") + + "/foo3.framework/Versions/A/foo3.dwarf")); + } else { + QVERIFY(regularFileExists(relativeProductBuildDir("foo3") + + "/foo3.framework/foo3.dwarf")); + } QVERIFY(directoryExists(relativeProductBuildDir("foo4") + "/libfoo4.dylib.dSYM")); QVERIFY(regularFileExists(relativeProductBuildDir("foo4") + "/libfoo4.dylib.dSYM/Contents/Info.plist")); @@ -1871,8 +2203,13 @@ void TestBlackbox::separateDebugInfo() .entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries).size(), 1); QVERIFY(!QFile::exists(relativeProductBuildDir("bar2") + "/bar2.bundle.dSYM")); QVERIFY(!QFile::exists(relativeProductBuildDir("bar3") + "/bar3.bundle.dSYM")); - QVERIFY(regularFileExists(relativeProductBuildDir("bar3") - + "/bar3.bundle/Contents/MacOS/bar3.dwarf")); + if (isMacos) { + QVERIFY(regularFileExists(relativeProductBuildDir("bar3") + + "/bar3.bundle/Contents/MacOS/bar3.dwarf")); + } else { + QVERIFY(regularFileExists(relativeProductBuildDir("bar3") + + "/bar3.bundle/bar3.dwarf")); + } QVERIFY(directoryExists(relativeProductBuildDir("bar4") + "/bar4.bundle.dSYM")); QVERIFY(regularFileExists(relativeProductBuildDir("bar4") + "/bar4.bundle.dSYM/Contents/Info.plist")); @@ -1882,7 +2219,7 @@ void TestBlackbox::separateDebugInfo() + "/bar4.bundle.dSYM/Contents/Resources/DWARF") .entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries).size(), 1); QVERIFY(regularFileExists(relativeProductBuildDir("bar5") + "/bar5.bundle.dwarf")); - } else if (toolchain.contains("gcc")) { + } else if (isGcc) { const QString exeSuffix = isWindows ? ".exe" : ""; const QString dllPrefix = isWindows ? "" : "lib"; const QString dllSuffix = isWindows ? ".dll" : ".so"; @@ -1896,7 +2233,7 @@ void TestBlackbox::separateDebugInfo() + '/' + dllPrefix + "bar1" + dllSuffix + ".debug")); QVERIFY(!QFile::exists(relativeProductBuildDir("bar2") + '/' + dllPrefix + "bar2" + dllSuffix + ".debug")); - } else if (toolchain.contains("msvc")) { + } else if (isMsvc) { QVERIFY(QFile::exists(relativeProductBuildDir("app1") + "/app1.pdb")); QVERIFY(QFile::exists(relativeProductBuildDir("foo1") + "/foo1.pdb")); QVERIFY(QFile::exists(relativeProductBuildDir("bar1") + "/bar1.pdb")); @@ -1915,6 +2252,9 @@ void TestBlackbox::trackAddFile() QDir().mkdir("work"); ccp("before", "work"); QDir::setCurrent(testDataDir + "/trackAddFile/work"); + QCOMPARE(runQbs({"resolve"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); const QbsRunParameters runParams("run", QStringList{"-qp", "someapp"}); QCOMPARE(runQbs(runParams), 0); @@ -1950,6 +2290,9 @@ void TestBlackbox::trackExternalProductChanges() QVERIFY(!m_qbsStdout.contains("compiling jsFileChange.cpp")); QVERIFY(!m_qbsStdout.contains("compiling fileExists.cpp")); + const bool isGcc = m_qbsStdout.contains("is gcc: true"); + const bool isNotGcc = m_qbsStdout.contains("is gcc: false"); + QbsRunParameters params; params.environment.insert("QBS_TEST_PULL_IN_FILE_VIA_ENV", "1"); QCOMPARE(runQbs(params), 0); @@ -1999,13 +2342,12 @@ void TestBlackbox::trackExternalProductChanges() QVERIFY(!m_qbsStdout.contains("compiling jsFileChange.cpp")); QVERIFY(m_qbsStdout.contains("compiling fileExists.cpp")); + if (isNotGcc) + QSKIP("The remainder of this test requires a GCC-like toolchain"); + QVERIFY(isGcc); + rmDirR(relativeBuildDir()); - const SettingsPtr s = settings(); - const Profile profile(profileName(), s.get()); - const QStringList toolchainTypes = profile.value("qbs.toolchain").toStringList(); - if (!toolchainTypes.contains("gcc")) - QSKIP("Need GCC-like compiler to run this test"); - params.environment = QProcessEnvironment::systemEnvironment(); + params.environment = QbsRunParameters::defaultEnvironment(); params.environment.insert("INCLUDE_PATH_TEST", "1"); params.expectFailure = true; QVERIFY(runQbs(params) != 0); @@ -2044,6 +2386,9 @@ void TestBlackbox::trackRemoveFile() ccp("before", "work"); ccp("after", "work"); QDir::setCurrent(testDataDir + "/trackAddFile/work"); + QCOMPARE(runQbs({"resolve"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); const QbsRunParameters runParams("run", QStringList{"-qp", "someapp"}); QCOMPARE(runQbs(runParams), 0); output = m_qbsStdout.split('\n'); @@ -2088,6 +2433,9 @@ void TestBlackbox::trackAddFileTag() QDir().mkdir("work"); ccp("before", "work"); QDir::setCurrent(testDataDir + "/trackFileTags/work"); + QCOMPARE(runQbs({"resolve"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); const QbsRunParameters runParams("run", QStringList{"-qp", "someapp"}); QCOMPARE(runQbs(runParams), 0); output = m_qbsStdout.split('\n'); @@ -2112,6 +2460,9 @@ void TestBlackbox::trackRemoveFileTag() QDir().mkdir("work"); ccp("after", "work"); QDir::setCurrent(testDataDir + "/trackFileTags/work"); + QCOMPARE(runQbs({"resolve"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); const QbsRunParameters runParams("run", QStringList{"-qp", "someapp"}); QCOMPARE(runQbs(runParams), 0); @@ -2260,8 +2611,8 @@ void TestBlackbox::referenceErrorInExport() QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); - QVERIFY(m_qbsStderr.contains( - "referenceErrorInExport.qbs:15:12 ReferenceError: Can't find variable: includePaths")); + QVERIFY2(m_qbsStderr.contains("referenceErrorInExport.qbs:5:27 'includePaths' is not defined"), + m_qbsStderr.constData()); } void TestBlackbox::removeDuplicateLibraries_data() @@ -2288,20 +2639,21 @@ void TestBlackbox::removeDuplicateLibraries() void TestBlackbox::reproducibleBuild() { - const SettingsPtr s = settings(); - const Profile profile(profileName(), s.get()); - const QStringList toolchains = profile.value("qbs.toolchain").toStringList(); - if (!toolchains.contains("gcc") || toolchains.contains("clang")) - QSKIP("reproducible builds only supported for gcc"); - QFETCH(bool, reproducible); QDir::setCurrent(testDataDir + "/reproducible-build"); - QbsRunParameters params; + QbsRunParameters params("resolve"); params.arguments << QString("modules.cpp.enableReproducibleBuilds:") + (reproducible ? "true" : "false"); rmDirR(relativeBuildDir()); QCOMPARE(runQbs(params), 0); + const bool isGcc = m_qbsStdout.contains("is gcc: true"); + const bool isNotGcc = m_qbsStdout.contains("is gcc: false"); + if (isNotGcc) + QSKIP("reproducible builds only supported for gcc"); + QVERIFY(isGcc); + + QCOMPARE(runQbs(), 0); QFile object(relativeProductBuildDir("the product") + '/' + inputDirHash(".") + '/' + objectFileName("file1.cpp", profileName())); QVERIFY2(object.open(QIODevice::ReadOnly), qPrintable(object.fileName())); @@ -2309,6 +2661,7 @@ void TestBlackbox::reproducibleBuild() object.close(); QCOMPARE(runQbs(QbsRunParameters("clean")), 0); QVERIFY(!object.exists()); + params.command = "build"; QCOMPARE(runQbs(params), 0); if (reproducible) { QVERIFY(object.open(QIODevice::ReadOnly)); @@ -2329,6 +2682,9 @@ void TestBlackbox::reproducibleBuild_data() void TestBlackbox::responseFiles() { QDir::setCurrent(testDataDir + "/response-files"); + QCOMPARE(runQbs({"resolve"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params; params.command = "install"; params.arguments << "--install-root" << "installed"; @@ -2367,6 +2723,32 @@ void TestBlackbox::retaggedOutputArtifact() QVERIFY2(!QFile::exists(a3), qPrintable(a3)); } +void TestBlackbox::rpathlinkDeduplication() +{ + QDir::setCurrent(testDataDir + "/rpathlink-deduplication"); + QbsRunParameters resolveParams{"resolve"}; + QCOMPARE(runQbs(resolveParams), 0); + const bool useRPathLink = m_qbsStdout.contains("useRPathLink: true"); + const bool dontUseRPathLink = m_qbsStdout.contains("useRPathLink: false"); + QVERIFY2(useRPathLink || dontUseRPathLink, m_qbsStdout); + if (dontUseRPathLink) + QSKIP("Only applies to toolchains that support rPathLink"); + const QString output = QString::fromLocal8Bit(m_qbsStdout); + const QRegularExpression pattern(QRegularExpression::anchoredPattern(".*===(.*)===.*"), + QRegularExpression::DotMatchesEverythingOption); + const QRegularExpressionMatch match = pattern.match(output); + QVERIFY2(match.hasMatch(), qPrintable(output)); + QCOMPARE(pattern.captureCount(), 1); + const QString linkFlag = match.captured(1); + + QbsRunParameters buildParams; + buildParams.arguments = QStringList({"--command-echo-mode", "command-line"}); + QCOMPARE(runQbs(buildParams), 0); + // private DynamicLibraryA is a dependency for 2 other libs but should only appear once + const auto libDir = QFileInfo(relativeProductBuildDir("DynamicLibraryA")).absoluteFilePath(); + QCOMPARE(m_qbsStdout.count((linkFlag + libDir).toUtf8()), 1); +} + void TestBlackbox::ruleConditions() { QDir::setCurrent(testDataDir + "/ruleConditions"); @@ -2444,11 +2826,60 @@ void TestBlackbox::ruleWithNonRequiredInputs() output = outFile.readAll(); QCOMPARE(output, QByteArray("(a.inp,b.inp,c.inp,)")); QCOMPARE(runQbs(), 0); - QVERIFY2(!m_qbsStdout.contains("Generating"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("generating"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("a.inp"); QCOMPARE(runQbs(), 0); - QVERIFY2(m_qbsStdout.contains("Generating"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("generating"), m_qbsStdout.constData()); +} + +void TestBlackbox::runMultiplexed() +{ + QDir::setCurrent(testDataDir + "/run-multiplexed"); + QCOMPARE(runQbs({"resolve"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); + + QbsRunParameters params("run"); + params.expectFailure = true; + QVERIFY(runQbs(params) != 0); + params.arguments = QStringList{"-p", "app"}; + QVERIFY(runQbs(params) != 0); + params.expectFailure = false; + params.arguments.last() = "app {\"buildVariant\":\"debug\"}"; + QCOMPARE(runQbs(params), 0); + params.arguments.last() = "app {\"buildVariant\":\"release\"}"; + QCOMPARE(runQbs(params), 0); +} + +void TestBlackbox::sanitizer_data() +{ + QTest::addColumn<QString>("sanitizer"); + QTest::newRow("none") << QString(); + QTest::newRow("address") << QStringLiteral("address"); + QTest::newRow("undefined") << QStringLiteral("undefined"); + QTest::newRow("thread") << QStringLiteral("thread"); +} + +void TestBlackbox::sanitizer() +{ + QFETCH(QString, sanitizer); + QDir::setCurrent(testDataDir + "/sanitizer"); + rmDirR(relativeBuildDir()); + QbsRunParameters params("build", {"--command-echo-mode", "command-line"}); + if (!sanitizer.isEmpty()) { + params.arguments.append( + {QStringLiteral("products.sanitizer.sanitizer:\"") + sanitizer + "\""}); + } + QCOMPARE(runQbs(params), 0); + if (m_qbsStdout.contains(QByteArrayLiteral("Compiler does not support sanitizer"))) + QSKIP("Compiler does not support the specified sanitizer"); + if (!sanitizer.isEmpty()) { + QVERIFY2(m_qbsStdout.contains(QByteArrayLiteral("fsanitize=") + sanitizer.toLatin1()), + qPrintable(m_qbsStdout)); + } else { + QVERIFY2(!m_qbsStdout.contains(QByteArrayLiteral("fsanitize=")), qPrintable(m_qbsStdout)); + } } void TestBlackbox::scannerItem() @@ -2469,6 +2900,47 @@ void TestBlackbox::scannerItem() QVERIFY2(m_qbsStdout.contains("handling file2.in"), m_qbsStdout.constData()); } +void TestBlackbox::scanResultInOtherProduct() +{ + QDir::setCurrent(testDataDir + "/scan-result-in-other-product"); + QCOMPARE(runQbs(QStringList("-vv")), 0); + QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("generating text file"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStderr.contains("The file dependency might get lost during change tracking"), + m_qbsStderr.constData()); + WAIT_FOR_NEW_TIMESTAMP(); + REPLACE_IN_FILE("other/other.qbs", "blubb", "blubb2"); + QCOMPARE(runQbs(), 0); + QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("generating text file"), m_qbsStdout.constData()); + WAIT_FOR_NEW_TIMESTAMP(); + touch("lib/lib.h"); + QCOMPARE(runQbs(), 0); + QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("generating text file"), m_qbsStdout.constData()); +} + +void TestBlackbox::scanResultInNonDependency() +{ + QDir::setCurrent(testDataDir + "/scan-result-in-non-dependency"); + QCOMPARE(runQbs(QStringList("-vv")), 0); + QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("generating text file"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStderr.contains("The file dependency might get lost during change tracking"), + m_qbsStderr.constData()); + WAIT_FOR_NEW_TIMESTAMP(); + REPLACE_IN_FILE("other/other.qbs", "blubb", "blubb2"); + QCOMPARE(runQbs(), 0); + QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("generating text file"), m_qbsStdout.constData()); + WAIT_FOR_NEW_TIMESTAMP(); + touch("lib/lib.h"); + QCOMPARE(runQbs(), 0); + QEXPECT_FAIL("", "QBS-1532", Continue); + QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("generating text file"), m_qbsStdout.constData()); +} + void TestBlackbox::setupBuildEnvironment() { QDir::setCurrent(testDataDir + "/setup-build-environment"); @@ -2486,6 +2958,8 @@ void TestBlackbox::setupRunEnvironment() { QDir::setCurrent(testDataDir + "/setup-run-environment"); QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters failParams("run", QStringList({"--setup-run-env-config", "ignore-lib-dependencies"})); failParams.expectFailure = true; @@ -2760,9 +3234,11 @@ void TestBlackbox::pathProbe_data() QTest::newRow("mult-files-mult-variants") << QString("mult-files-mult-variants.qbs") << true; QTest::newRow("single-file-suffixes") << QString("single-file-suffixes.qbs") << true; QTest::newRow("mult-files-suffixes") << QString("mult-files-suffixes.qbs") << true; + QTest::newRow("mult-files-common-suffixes") << QString("mult-files-common-suffixes.qbs") << true; QTest::newRow("mult-files-mult-suffixes") << QString("mult-files-mult-suffixes.qbs") << true; QTest::newRow("name-filter") << QString("name-filter.qbs") << true; QTest::newRow("candidate-filter") << QString("candidate-filter.qbs") << true; + QTest::newRow("environment-paths") << QString("environment-paths.qbs") << true; } void TestBlackbox::pathProbe() @@ -2774,23 +3250,41 @@ void TestBlackbox::pathProbe() QbsRunParameters buildParams("build", QStringList{"-f", projectFile}); buildParams.expectFailure = !successExpected; + buildParams.environment.insert("SEARCH_PATH", "usr/bin"); QCOMPARE(runQbs(buildParams) == 0, successExpected); + if (!successExpected) + QVERIFY2(m_qbsStderr.contains("Probe failed to find files"), m_qbsStderr); +} + +void TestBlackbox::pathListInProbe() +{ + QDir::setCurrent(testDataDir + "/path-list-in-probe"); + QCOMPARE(runQbs(), 0); } void TestBlackbox::pchChangeTracking() { QDir::setCurrent(testDataDir + "/pch-change-tracking"); - QCOMPARE(runQbs(), 0); + bool success = runQbs() == 0; + if (!success && m_qbsStderr.contains("mingw32_gt_pch_use_address")) + QSKIP("https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91440"); + QVERIFY(success); QVERIFY(m_qbsStdout.contains("precompiling pch.h (cpp)")); WAIT_FOR_NEW_TIMESTAMP(); touch("header1.h"); - QCOMPARE(runQbs(), 0); + success = runQbs() == 0; + if (!success && m_qbsStderr.contains("mingw32_gt_pch_use_address")) + QSKIP("https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91440"); + QVERIFY(success); QVERIFY(m_qbsStdout.contains("precompiling pch.h (cpp)")); QVERIFY(m_qbsStdout.contains("compiling header2.cpp")); QVERIFY(m_qbsStdout.contains("compiling main.cpp")); WAIT_FOR_NEW_TIMESTAMP(); touch("header2.h"); - QCOMPARE(runQbs(), 0); + success = runQbs() == 0; + if (!success && m_qbsStderr.contains("mingw32_gt_pch_use_address")) + QSKIP("https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91440"); + QVERIFY(success); QVERIFY2(!m_qbsStdout.contains("precompiling pch.h (cpp)"), m_qbsStdout.constData()); } @@ -2920,13 +3414,19 @@ void TestBlackbox::pluginDependency() void TestBlackbox::precompiledAndPrefixHeaders() { QDir::setCurrent(testDataDir + "/precompiled-and-prefix-headers"); - QCOMPARE(runQbs(), 0); + const bool success = runQbs() == 0; + if (!success && m_qbsStderr.contains("mingw32_gt_pch_use_address")) + QSKIP("https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91440"); + QVERIFY(success); } void TestBlackbox::precompiledHeaderAndRedefine() { QDir::setCurrent(testDataDir + "/precompiled-headers-and-redefine"); - QCOMPARE(runQbs(), 0); + const bool success = runQbs() == 0; + if (!success && m_qbsStderr.contains("mingw32_gt_pch_use_address")) + QSKIP("https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91440"); + QVERIFY(success); } void TestBlackbox::preventFloatingPointValues() @@ -3031,6 +3531,9 @@ void TestBlackbox::probeProperties() QVERIFY2(m_qbsStdout.contains("probe2.fileName=tool"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("probe2.path=" + dir + "/bin"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("probe2.filePath=" + dir + "/bin/tool"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("probe3.fileName=tool"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("probe3.path=" + dir + "/bin"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("probe3.filePath=" + dir + "/bin/tool"), m_qbsStdout.constData()); } void TestBlackbox::probesAndShadowProducts() @@ -3053,7 +3556,7 @@ void TestBlackbox::probeInExportedModule() << QStringLiteral("probe-in-exported-module.qbs"))), 0); QVERIFY2(m_qbsStdout.contains("found: true"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("prop: yes"), m_qbsStdout.constData()); - QVERIFY2(m_qbsStdout.contains("listProp: my,myother"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("listProp: myother,my"), m_qbsStdout.constData()); } void TestBlackbox::probesAndArrayProperties() @@ -3075,13 +3578,6 @@ void TestBlackbox::productProperties() QVERIFY(regularFileExists(relativeExecutableFilePath("blubb_user"))); } -void TestBlackbox::propertyAssignmentOnNonPresentModule() -{ - QDir::setCurrent(testDataDir + "/property-assignment-on-non-present-module"); - QCOMPARE(runQbs(), 0); - QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); -} - void TestBlackbox::propertyAssignmentInFailedModule() { QDir::setCurrent(testDataDir + "/property-assignment-in-failed-module"); @@ -3091,7 +3587,7 @@ void TestBlackbox::propertyAssignmentInFailedModule() QVERIFY(runQbs(failParams) != 0); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("modules.m.doFail:true"))), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); - QEXPECT_FAIL(0, "circular dependency between module merging and validation", Continue); + failParams.expectFailure = false; QCOMPARE(runQbs(failParams), 0); } @@ -3109,9 +3605,9 @@ void TestBlackbox::propertyChanges() QVERIFY(m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(m_qbsStdout.contains("linking product 1.debug")); QVERIFY(m_qbsStdout.contains("generated.txt")); - QVERIFY(m_qbsStdout.contains("Making output from input")); + QVERIFY(m_qbsStdout.contains("making output from input")); QVERIFY(m_qbsStdout.contains("default value")); - QVERIFY(m_qbsStdout.contains("Making output from other output")); + QVERIFY(m_qbsStdout.contains("making output from other output")); QFile generatedFile(relativeProductBuildDir("generated text file") + "/generated.txt"); QVERIFY(generatedFile.open(QIODevice::ReadOnly)); QCOMPARE(generatedFile.readAll(), QByteArray("prefix 1contents 1suffix 1")); @@ -3125,8 +3621,8 @@ void TestBlackbox::propertyChanges() QVERIFY(!m_qbsStdout.contains("compiling lib.cpp.cpp")); QVERIFY(!m_qbsStdout.contains("linking")); QVERIFY(!m_qbsStdout.contains("generated.txt")); - QVERIFY(!m_qbsStdout.contains("Making output from input")); - QVERIFY(!m_qbsStdout.contains("Making output from other output")); + QVERIFY(!m_qbsStdout.contains("making output from input")); + QVERIFY(!m_qbsStdout.contains("making output from other output")); // Incremental build with no changes, but updated project file timestamp. WAIT_FOR_NEW_TIMESTAMP(); @@ -3138,8 +3634,8 @@ void TestBlackbox::propertyChanges() QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(!m_qbsStdout.contains("linking")); QVERIFY(!m_qbsStdout.contains("generated.txt")); - QVERIFY(!m_qbsStdout.contains("Making output from input")); - QVERIFY(!m_qbsStdout.contains("Making output from other output")); + QVERIFY(!m_qbsStdout.contains("making output from input")); + QVERIFY(!m_qbsStdout.contains("making output from other output")); // Incremental build, input property changed for first product WAIT_FOR_NEW_TIMESTAMP(); @@ -3151,8 +3647,8 @@ void TestBlackbox::propertyChanges() QVERIFY(!m_qbsStdout.contains("linking product 3")); QVERIFY(!m_qbsStdout.contains("linking library")); QVERIFY(!m_qbsStdout.contains("generated.txt")); - QVERIFY(!m_qbsStdout.contains("Making output from input")); - QVERIFY(!m_qbsStdout.contains("Making output from other output")); + QVERIFY(!m_qbsStdout.contains("making output from input")); + QVERIFY(!m_qbsStdout.contains("making output from other output")); // Incremental build, input property changed via project for second product. WAIT_FOR_NEW_TIMESTAMP(); @@ -3162,8 +3658,8 @@ void TestBlackbox::propertyChanges() QVERIFY(m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("linking product 3")); QVERIFY(!m_qbsStdout.contains("generated.txt")); - QVERIFY(!m_qbsStdout.contains("Making output from input")); - QVERIFY(!m_qbsStdout.contains("Making output from other output")); + QVERIFY(!m_qbsStdout.contains("making output from input")); + QVERIFY(!m_qbsStdout.contains("making output from other output")); // Incremental build, input property changed via command line for second product. params.command = "resolve"; @@ -3181,8 +3677,8 @@ void TestBlackbox::propertyChanges() QVERIFY(m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("linking product 3")); QVERIFY(!m_qbsStdout.contains("generated.txt")); - QVERIFY(!m_qbsStdout.contains("Making output from input")); - QVERIFY(!m_qbsStdout.contains("Making output from other output")); + QVERIFY(!m_qbsStdout.contains("making output from input")); + QVERIFY(!m_qbsStdout.contains("making output from other output")); // Incremental build, input property changed via environment for third product. params.environment.insert("QBS_BLACKBOX_DEFINE", "newvalue"); @@ -3197,8 +3693,8 @@ void TestBlackbox::propertyChanges() QVERIFY(!m_qbsStdout.contains("linking product 2")); QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("generated.txt")); - QVERIFY(!m_qbsStdout.contains("Making output from input")); - QVERIFY(!m_qbsStdout.contains("Making output from other output")); + QVERIFY(!m_qbsStdout.contains("making output from input")); + QVERIFY(!m_qbsStdout.contains("making output from other output")); params.environment.insert("QBS_BLACKBOX_DEFINE", "newvalue"); QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); @@ -3213,8 +3709,8 @@ void TestBlackbox::propertyChanges() QVERIFY(!m_qbsStdout.contains("linking product 2")); QVERIFY(m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("generated.txt")); - QVERIFY(!m_qbsStdout.contains("Making output from input")); - QVERIFY(!m_qbsStdout.contains("Making output from other output")); + QVERIFY(!m_qbsStdout.contains("making output from input")); + QVERIFY(!m_qbsStdout.contains("making output from other output")); // Incremental build, module property changed via command line. params.arguments << "qbs.enableDebugCode:false"; @@ -3234,8 +3730,8 @@ void TestBlackbox::propertyChanges() QVERIFY(m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("generated.txt")); - QVERIFY(!m_qbsStdout.contains("Making output from input")); - QVERIFY(!m_qbsStdout.contains("Making output from other output")); + QVERIFY(!m_qbsStdout.contains("making output from input")); + QVERIFY(!m_qbsStdout.contains("making output from other output")); // Incremental build, non-essential dependency removed. WAIT_FOR_NEW_TIMESTAMP(); @@ -3247,8 +3743,8 @@ void TestBlackbox::propertyChanges() QVERIFY(!m_qbsStdout.contains("linking product 3")); QVERIFY(!m_qbsStdout.contains("linking library")); QVERIFY(!m_qbsStdout.contains("generated.txt")); - QVERIFY(!m_qbsStdout.contains("Making output from input")); - QVERIFY(!m_qbsStdout.contains("Making output from other output")); + QVERIFY(!m_qbsStdout.contains("making output from input")); + QVERIFY(!m_qbsStdout.contains("making output from other output")); // Incremental build, prepare script of a transformer changed. WAIT_FOR_NEW_TIMESTAMP(); @@ -3259,8 +3755,8 @@ void TestBlackbox::propertyChanges() QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(m_qbsStdout.contains("generated.txt")); - QVERIFY(!m_qbsStdout.contains("Making output from input")); - QVERIFY(!m_qbsStdout.contains("Making output from other output")); + QVERIFY(!m_qbsStdout.contains("making output from input")); + QVERIFY(!m_qbsStdout.contains("making output from other output")); QVERIFY(generatedFile.open(QIODevice::ReadOnly)); QCOMPARE(generatedFile.readAll(), QByteArray("prefix 1contents 2suffix 1")); generatedFile.close(); @@ -3274,8 +3770,8 @@ void TestBlackbox::propertyChanges() QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(m_qbsStdout.contains("generated.txt")); - QVERIFY(!m_qbsStdout.contains("Making output from input")); - QVERIFY(!m_qbsStdout.contains("Making output from other output")); + QVERIFY(!m_qbsStdout.contains("making output from input")); + QVERIFY(!m_qbsStdout.contains("making output from other output")); QVERIFY(generatedFile.open(QIODevice::ReadOnly)); QCOMPARE(generatedFile.readAll(), QByteArray("prefix 2contents 2suffix 1")); generatedFile.close(); @@ -3289,8 +3785,8 @@ void TestBlackbox::propertyChanges() QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(m_qbsStdout.contains("generated.txt")); - QVERIFY(!m_qbsStdout.contains("Making output from input")); - QVERIFY(!m_qbsStdout.contains("Making output from other output")); + QVERIFY(!m_qbsStdout.contains("making output from input")); + QVERIFY(!m_qbsStdout.contains("making output from other output")); QVERIFY(generatedFile.open(QIODevice::ReadOnly)); QCOMPARE(generatedFile.readAll(), QByteArray("prefix 2contents 2suffix 2")); generatedFile.close(); @@ -3304,8 +3800,8 @@ void TestBlackbox::propertyChanges() QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(!m_qbsStdout.contains("generated.txt")); - QVERIFY(m_qbsStdout.contains("Making output from input")); - QVERIFY(m_qbsStdout.contains("Making output from other output")); + QVERIFY(m_qbsStdout.contains("making output from input")); + QVERIFY(m_qbsStdout.contains("making output from other output")); QVERIFY(m_qbsStdout.contains("new value")); // Incremental build, prepare script of a rule in a module changed. @@ -3318,22 +3814,31 @@ void TestBlackbox::propertyChanges() QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(!m_qbsStdout.contains("generated.txt")); - QVERIFY(m_qbsStdout.contains("Making output from input")); - QVERIFY(m_qbsStdout.contains("Making output from other output")); + QVERIFY(m_qbsStdout.contains("making output from input")); + QVERIFY(m_qbsStdout.contains("making output from other output")); +} + +void TestBlackbox::propertyEvaluationContext() +{ + const QString testDir = testDataDir + "/property-evaluation-context"; + QDir::setCurrent(testDir); + QCOMPARE(runQbs(), 0); + QCOMPARE(m_qbsStdout.count("base.productInBase evaluated in: myapp"), 1); + QCOMPARE(m_qbsStdout.count("base.productInTop evaluated in: myapp"), 1); + QCOMPARE(m_qbsStdout.count("top.productInExport evaluated in: mylib"), 1); + QCOMPARE(m_qbsStdout.count("top.productInTop evaluated in: myapp"), 1); } void TestBlackbox::qtBug51237() { - const QString profileName = "profile-qtBug51237"; - const QString propertyName = "mymodule.theProperty"; - { - const SettingsPtr s = settings(); - Profile profile(profileName, s.get()); - profile.setValue(propertyName, QStringList()); - } + const SettingsPtr s = settings(); + qbs::Internal::TemporaryProfile profile("qbs_autotests_qtBug51237", s.get()); + profile.p.setValue("mymodule.theProperty", QStringList()); + s->sync(); + QDir::setCurrent(testDataDir + "/QTBUG-51237"); QbsRunParameters params; - params.profile = profileName; + params.profile = profile.p.name(); QCOMPARE(runQbs(params), 0); } @@ -3406,6 +3911,42 @@ void TestBlackbox::dynamicRuleOutputs() QVERIFY(!QFile::exists(sourceFile2)); } +void TestBlackbox::emptyProfile() +{ + QDir::setCurrent(testDataDir + "/empty-profile"); + + const SettingsPtr s = settings(); + const qbs::Profile buildProfile(profileName(), s.get()); + bool isMsvc = false; + auto toolchainType = buildProfile.value(QStringLiteral("qbs.toolchainType")).toString(); + QbsRunParameters params; + params.profile = "none"; + + if (toolchainType.isEmpty()) { + const auto toolchain = buildProfile.value(QStringLiteral("qbs.toolchain")).toStringList(); + if (!toolchain.isEmpty()) + toolchainType = toolchain.first(); + } + if (!toolchainType.isEmpty()) { + params.arguments = QStringList{QStringLiteral("qbs.toolchainType:") + toolchainType}; + isMsvc = toolchainType == "msvc" || toolchainType == "clang-cl"; + } + + if (!isMsvc) { + const auto tcPath = + QDir::toNativeSeparators( + buildProfile.value(QStringLiteral("cpp.toolchainInstallPath")).toString()); + auto paths = params.environment.value(QStringLiteral("PATH")) + .split(HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts); + if (!tcPath.isEmpty() && !paths.contains(tcPath)) { + paths.prepend(tcPath); + params.environment.insert( + QStringLiteral("PATH"), paths.join(HostOsInfo::pathListSeparator())); + } + } + QCOMPARE(runQbs(params), 0); +} + void TestBlackbox::erroneousFiles_data() { QTest::addColumn<QString>("errorMessage"); @@ -3433,7 +3974,7 @@ void TestBlackbox::erroneousFiles() params.expectFailure = true; QVERIFY(runQbs(params) != 0); QString err = QString::fromLocal8Bit(m_qbsStderr); - if (!err.contains(QRegExp(errorMessage))) { + if (!err.contains(QRegularExpression(errorMessage))) { qDebug().noquote() << "Output: " << err; qDebug().noquote() << "Expected: " << errorMessage; QFAIL("Unexpected error message."); @@ -3496,13 +4037,16 @@ void TestBlackbox::errorInfo() void TestBlackbox::escapedLinkerFlags() { - const SettingsPtr s = settings(); - const Profile buildProfile(profileName(), s.get()); - const QStringList toolchain = buildProfile.value("qbs.toolchain").toStringList(); - if (!toolchain.contains("gcc") || targetOs() == HostOsInfo::HostOsMacos) - QSKIP("escaped linker flags test only applies with gcc and GNU ld"); QDir::setCurrent(testDataDir + "/escaped-linker-flags"); - QbsRunParameters params(QStringList("products.app.escapeLinkerFlags:false")); + QbsRunParameters params("resolve", QStringList("products.app.escapeLinkerFlags:false")); + QCOMPARE(runQbs(params), 0); + const bool isGcc = m_qbsStdout.contains("is gcc: true"); + const bool isNotGcc = m_qbsStdout.contains("is gcc: false"); + if (isNotGcc) + QSKIP("escaped linker flags test only applies on plain unix with gcc and GNU ld"); + QVERIFY(isGcc); + + params.command = "build"; QCOMPARE(runQbs(params), 0); params.command = "resolve"; params.arguments = QStringList() << "products.app.escapeLinkerFlags:true"; @@ -3559,26 +4103,24 @@ void TestBlackbox::exportedPropertyInDisabledProduct_data() void TestBlackbox::systemRunPaths() { - const SettingsPtr s = settings(); - const Profile buildProfile(profileName(), s.get()); - switch (targetOs()) { - case HostOsInfo::HostOsLinux: - case HostOsInfo::HostOsMacos: - case HostOsInfo::HostOsOtherUnix: - break; - default: - QSKIP("only applies on Unix"); - } - const QString lddFilePath = findExecutable(QStringList() << "ldd"); if (lddFilePath.isEmpty()) QSKIP("ldd not found"); + QDir::setCurrent(testDataDir + "/system-run-paths"); QFETCH(bool, setRunPaths); rmDirR(relativeBuildDir()); - QbsRunParameters params; + QbsRunParameters params("resolve"); params.arguments << QString("project.setRunPaths:") + (setRunPaths ? "true" : "false"); QCOMPARE(runQbs(params), 0); + const bool isUnix = m_qbsStdout.contains("is unix: true"); + const bool isNotUnix = m_qbsStdout.contains("is unix: false"); + if (isNotUnix) + QSKIP("only applies on Unix"); + QVERIFY(isUnix); + + params.command = "build"; + QCOMPARE(runQbs(params), 0); QProcess ldd; ldd.start(lddFilePath, QStringList() << relativeExecutableFilePath("app")); QVERIFY2(ldd.waitForStarted(), qPrintable(ldd.errorString())); @@ -3615,7 +4157,7 @@ void TestBlackbox::exportRule() params.expectFailure = false; QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); - QVERIFY2(m_qbsStdout.contains("Creating C++ source file"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("creating C++ source file"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("compiling myapp.cpp"), m_qbsStdout.constData()); } @@ -3629,12 +4171,88 @@ void TestBlackbox::exportToOutsideSearchPath() m_qbsStderr.constData()); } +void TestBlackbox::exportsCMake() +{ + QFETCH(QStringList, arguments); + + QDir::setCurrent(testDataDir + "/exports-cmake"); + rmDirR(relativeBuildDir()); + QbsRunParameters findCMakeParams("resolve", {"-f", "find-cmake.qbs"}); + QCOMPARE(runQbs(findCMakeParams), 0); + const QString output = QString::fromLocal8Bit(m_qbsStdout); + const QRegularExpression pattern( + QRegularExpression::anchoredPattern(".*---(.*)---.*"), + QRegularExpression::DotMatchesEverythingOption); + const QRegularExpressionMatch match = pattern.match(output); + QVERIFY2(match.hasMatch(), qPrintable(output)); + QCOMPARE(pattern.captureCount(), 1); + const QString jsonString = match.captured(1); + const QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString.toUtf8()); + const QJsonObject jsonData = jsonDoc.object(); + + rmDirR(relativeBuildDir()); + const QStringList exporterArgs{"-f", "exports-cmake.qbs"}; + QbsRunParameters exporterRunParams("build", exporterArgs); + exporterRunParams.arguments << arguments; + QCOMPARE(runQbs(exporterRunParams), 0); + + if (!jsonData.value(u"cmakeFound").toBool()) { + QSKIP("cmake is not installed"); + return; + } + + if (jsonData.value(u"crossCompiling").toBool()) { + QSKIP("test is not applicable with cross-compile toolchains"); + return; + } + + const auto cmakeFilePath = jsonData.value(u"cmakeFilePath").toString(); + QVERIFY(!cmakeFilePath.isEmpty()); + + const auto generator = jsonData.value(u"generator").toString(); + if (generator.isEmpty()) { + QSKIP("cannot detect cmake generator"); + return; + } + + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + const auto buildEnv = jsonData.value(u"buildEnv").toObject(); + for (auto it = buildEnv.begin(), end = buildEnv.end(); it != end; ++it) { + env.insert(it.key(), it.value().toString()); + } + + const auto installPrefix = jsonData.value(u"installPrefix").toString(); + const auto cmakePrefixPath = QFileInfo(relativeBuildDir()).absoluteFilePath() + "/install-root/" + + installPrefix + "/lib/cmake"; + const auto sourceDirectory = testDataDir + "/exports-cmake/cmake"; + QProcess configure; + configure.setProcessEnvironment(env); + configure.setWorkingDirectory(sourceDirectory); + configure.start( + cmakeFilePath, {".", "-DCMAKE_PREFIX_PATH=" + cmakePrefixPath, "-G" + generator}); + QVERIFY(waitForProcessSuccess(configure, 120000)); + + QProcess build; + build.setProcessEnvironment(env); + build.setWorkingDirectory(sourceDirectory); + build.start(cmakeFilePath, QStringList{"--build", "."}); + QVERIFY(waitForProcessSuccess(build)); +} + +void TestBlackbox::exportsCMake_data() +{ + QTest::addColumn<QStringList>("arguments"); + QTest::newRow("dynamic lib") << QStringList("project.isStatic: false"); + QTest::newRow("static lib") << QStringList("project.isStatic: true"); + QTest::newRow("framework") << QStringList("project.isBundle: true"); +} + void TestBlackbox::exportsPkgconfig() { QDir::setCurrent(testDataDir + "/exports-pkgconfig"); QCOMPARE(runQbs(), 0); - QVERIFY2(m_qbsStdout.contains("Creating TheFirstLib.pc"), m_qbsStdout.constData()); - QVERIFY2(m_qbsStdout.contains("Creating TheSecondLib.pc"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("creating TheFirstLib.pc"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("creating TheSecondLib.pc"), m_qbsStdout.constData()); QFile sourcePcFile(HostOsInfo::isWindowsHost() ? "TheFirstLib_windows.pc" : "TheFirstLib.pc"); QString generatedPcFilePath = relativeProductBuildDir("TheFirstLib") + "/TheFirstLib.pc"; QFile generatedPcFile(generatedPcFilePath); @@ -3649,14 +4267,17 @@ void TestBlackbox::exportsPkgconfig() touch("firstlib.cpp"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("linking"), m_qbsStdout.constData()); - QVERIFY2(!m_qbsStdout.contains("Creating TheFirstLib.pc"), m_qbsStdout.constData()); - QVERIFY2(!m_qbsStdout.contains("Creating TheSecondLib.pc"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("creating TheFirstLib.pc"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("creating TheSecondLib.pc"), m_qbsStdout.constData()); } void TestBlackbox::exportsQbs() { QDir::setCurrent(testDataDir + "/exports-qbs"); + QCOMPARE(runQbs({"resolve", {"-f", "exports-qbs.qbs"}}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); // First we build exportable products and use them (as products) inside // the original project. QCOMPARE(runQbs(QStringList{"-f", "exports-qbs.qbs", "--command-echo-mode", "command-line"}), @@ -3679,11 +4300,12 @@ void TestBlackbox::exportsQbs() // Trying to build with an unsupported build variant must fail. paramsExternalBuild.arguments = QStringList{"-f", "consumer.qbs", - "modules.qbs.buildVariant:unknown"}; + "modules.qbs.buildVariant:profiling"}; paramsExternalBuild.buildDirectory = QDir::currentPath() + "/external-consumer-profile"; paramsExternalBuild.expectFailure = true; QVERIFY(runQbs(paramsExternalBuild) != 0); - QVERIFY2(m_qbsStderr.contains("MyLib could not be loaded"), m_qbsStderr.constData()); + QVERIFY2(m_qbsStderr.contains("Dependency 'MyLib' not found for product 'consumer'"), + m_qbsStderr.constData()); // Removing the condition from the generated module leaves us with two conflicting // candidates. @@ -3697,19 +4319,19 @@ void TestBlackbox::exportsQbs() // Change tracking for accesses to product.exports (negative). QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList{"-f", "exports-qbs.qbs"})), 0); QCOMPARE(runQbs(), 0); - QVERIFY2(m_qbsStdout.contains("Creating MyTool.qbs"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("creating MyTool.qbs"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("exports-qbs.qbs"); QCOMPARE(runQbs(QStringList({"-p", "MyTool"})), 0); - QVERIFY2(!m_qbsStdout.contains("Creating MyTool.qbs"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("creating MyTool.qbs"), m_qbsStdout.constData()); // Rebuilding the target binary should not cause recreating the module file. WAIT_FOR_NEW_TIMESTAMP(); touch("mylib.cpp"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.count("linking") >= 2, m_qbsStdout.constData()); - QVERIFY2(!m_qbsStdout.contains("Creating MyLib"), m_qbsStdout.constData()); - QVERIFY2(!m_qbsStdout.contains("Creating MyTool.qbs"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("creating MyLib"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("creating MyTool.qbs"), m_qbsStdout.constData()); // Changing a setting that influences the name of a target artifact should cause // recreating the module file. @@ -3718,14 +4340,14 @@ void TestBlackbox::exportsQbs() QCOMPARE(runQbs(resolveParams), 0); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.count("linking") >= 2, m_qbsStdout.constData()); - QVERIFY2(m_qbsStdout.count("Creating MyLib") == 2, m_qbsStdout.constData()); - QVERIFY2(!m_qbsStdout.contains("Creating MyTool.qbs"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.count("creating MyLib") == 2, m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("creating MyTool.qbs"), m_qbsStdout.constData()); // Change tracking for accesses to product.exports (positive). WAIT_FOR_NEW_TIMESTAMP(); - REPLACE_IN_FILE("tool.qbs", "product.toolTags", "[]"); + REPLACE_IN_FILE("tool.qbs", "exportingProduct.toolTags", "[]"); QCOMPARE(runQbs(QStringList({"-p", "MyTool"})), 0); - QVERIFY2(m_qbsStdout.contains("Creating MyTool.qbs"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("creating MyTool.qbs"), m_qbsStdout.constData()); } void TestBlackbox::externalLibs() @@ -3787,6 +4409,77 @@ void TestBlackbox::fileTagsFilterMerging() QVERIFY2(QFile::exists(otherOutput), qPrintable(otherOutput)); } +void TestBlackbox::flatbuf() +{ + QFETCH(QString, projectFile); + + QDir::setCurrent(testDataDir + "/flatbuf"); + + rmDirR(relativeBuildDir()); + if (!prepareAndRunConan()) + QSKIP("conan is not prepared, check messages above"); + + QbsRunParameters resolveParams( + "resolve", QStringList{"-f", projectFile, "moduleProviders.conan.installDirectory:build"}); + QCOMPARE(runQbs(resolveParams), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); + const bool withFlatbuffers = m_qbsStdout.contains("has flatbuffers: true"); + const bool withoutFlatbuffers = m_qbsStdout.contains("has flatbuffers: false"); + QVERIFY2(withFlatbuffers || withoutFlatbuffers, m_qbsStdout.constData()); + if (withoutFlatbuffers) + QSKIP("flatbuf module not present"); + QbsRunParameters runParams("run"); + QCOMPARE(runQbs(runParams), 0); +} + +void TestBlackbox::flatbuf_data() +{ + QTest::addColumn<QString>("projectFile"); + + // QTest::newRow("c") << QString("flat_c.qbs"); + QTest::newRow("cpp") << QString("flat_cpp.qbs"); + QTest::newRow("relative import") << QString("flat_relative_import.qbs"); + QTest::newRow("absolute import") << QString("flat_absolute_import.qbs"); + QTest::newRow("filename suffix") << QString("flat_filename_suffix.qbs"); + QTest::newRow("filename extension") << QString("flat_filename_extension.qbs"); + QTest::newRow("keep prefix") << QString("flat_keep_prefix.qbs"); +} + +void TestBlackbox::freedesktop() +{ + if (!HostOsInfo::isAnyUnixHost()) + QSKIP("only applies on Unix"); + if (HostOsInfo::isMacosHost()) + QSKIP("Does not apply on macOS"); + QDir::setCurrent(testDataDir + "/freedesktop"); + QCOMPARE(runQbs(), 0); + + // Check desktop file + QString desktopFilePath = + defaultInstallRoot + "/usr/local/share/applications/myapp.desktop"; + QVERIFY(QFile::exists(desktopFilePath)); + QFile desktopFile(desktopFilePath); + QVERIFY2(desktopFile.open(QIODevice::ReadOnly), qPrintable(desktopFile.errorString())); + QByteArrayList lines = desktopFile.readAll().split('\n'); + // Automatically filled line: + QVERIFY(lines.contains("Exec=main")); + // Name specified in `freedesktop.name` property + QVERIFY(lines.contains("Name=My App")); + // Overridden line: + QVERIFY(lines.contains("Icon=myapp.png")); + // Untouched line: + QVERIFY(lines.contains("Terminal=false")); + + // Check AppStream file + QVERIFY(QFile::exists(defaultInstallRoot + + "/usr/local/share/metainfo/myapp.appdata.xml")); + + // Check icon file + QVERIFY(QFile::exists(defaultInstallRoot + + "/usr/local/share/icons/hicolor/scalable/apps/myapp.png")); +} + void TestBlackbox::installedTransformerOutput() { QDir::setCurrent(testDataDir + "/installed-transformer-output"); @@ -3800,8 +4493,16 @@ void TestBlackbox::installLocations_data() QTest::addColumn<QString>("binDir"); QTest::addColumn<QString>("dllDir"); QTest::addColumn<QString>("libDir"); - QTest::newRow("explicit values") << QString("bindir") << QString("dlldir") << QString("libdir"); - QTest::newRow("default values") << QString() << QString() << QString(); + QTest::addColumn<QString>("pluginDir"); + QTest::addColumn<QString>("dsymDir"); + QTest::newRow("explicit values") + << QString("bindir") + << QString("dlldir") + << QString("libdir") + << QString("pluginDir") + << QString("dsymDir"); + QTest::newRow("default values") + << QString() << QString() << QString() << QString() << QString(); } void TestBlackbox::installLocations() @@ -3810,6 +4511,8 @@ void TestBlackbox::installLocations() QFETCH(QString, binDir); QFETCH(QString, dllDir); QFETCH(QString, libDir); + QFETCH(QString, pluginDir); + QFETCH(QString, dsymDir); QbsRunParameters params("resolve"); if (!binDir.isEmpty()) params.arguments.push_back("products.theapp.installDir:" + binDir); @@ -3817,35 +4520,98 @@ void TestBlackbox::installLocations() params.arguments.push_back("products.thelib.installDir:" + dllDir); if (!libDir.isEmpty()) params.arguments.push_back("products.thelib.importLibInstallDir:" + libDir); + if (!pluginDir.isEmpty()) + params.arguments.push_back("products.theplugin.installDir:" + pluginDir); + if (!dsymDir.isEmpty()) { + params.arguments.push_back("products.theapp.debugInformationInstallDir:" + dsymDir); + params.arguments.push_back("products.thelib.debugInformationInstallDir:" + dsymDir); + params.arguments.push_back("products.theplugin.debugInformationInstallDir:" + dsymDir); + } QCOMPARE(runQbs(params), 0); const bool isWindows = m_qbsStdout.contains("is windows"); + const bool isDarwin = m_qbsStdout.contains("is darwin"); const bool isMac = m_qbsStdout.contains("is mac"); const bool isUnix = m_qbsStdout.contains("is unix"); - QVERIFY(isWindows || isMac || isUnix); + const bool isMingw = m_qbsStdout.contains("is mingw"); + QVERIFY(isWindows || isDarwin || isUnix); QCOMPARE(runQbs(QbsRunParameters(QStringList("--clean-install-root"))), 0); - const QString dllFileName = isWindows ? "thelib.dll" : isMac ? "thelib" : "libthelib.so"; - const QString appFileName = isWindows ? "theapp.exe" : "theapp"; - if (binDir.isEmpty()) - binDir = isMac ? "/Applications" : "/bin"; - if (dllDir.isEmpty()) - dllDir = isMac ? "/Library/Frameworks" : isWindows ? "/bin" : "/lib"; - if (libDir.isEmpty()) - libDir = "/lib"; - if (isMac) { - binDir += "/theapp.app/Contents/MacOS"; - dllDir += "/thelib.framework"; - } + + struct BinaryInfo + { + QString fileName; + QString installDir; + QString subDir; + + QString absolutePath(const QString &prefix) const + { + return QDir::cleanPath(prefix + '/' + installDir + '/' + subDir + '/' + fileName); + } + }; + + const BinaryInfo dll = { + isWindows ? "thelib.dll" : isDarwin ? "thelib" : "libthelib.so", + dllDir.isEmpty() + ? (isDarwin ? "/Library/Frameworks" : (isWindows ? "/bin" : "/lib")) + : dllDir, + isDarwin ? "thelib.framework" : "" + }; + const BinaryInfo dllDsym = { + isWindows + ? (!isMingw ? "thelib.pdb" : "thelib.dll.debug") + : isDarwin ? "thelib.framework.dSYM" : "libthelib.so.debug", + dsymDir.isEmpty() ? dll.installDir : dsymDir, + {} + }; + const BinaryInfo plugin = { + isWindows ? "theplugin.dll" : isDarwin ? "theplugin" : "libtheplugin.so", + pluginDir.isEmpty() ? dll.installDir : pluginDir, + isDarwin ? (isMac ? "theplugin.bundle/Contents/MacOS" : "theplugin.bundle") : "" + }; + const BinaryInfo pluginDsym = { + isWindows + ? (!isMingw ? "theplugin.pdb" : "theplugin.dll.debug") + : isDarwin ? "theplugin.bundle.dSYM" : "libtheplugin.so.debug", + dsymDir.isEmpty() ? plugin.installDir : dsymDir, + {} + }; + const BinaryInfo app = { + isWindows ? "theapp.exe" : "theapp", + binDir.isEmpty() ? (isDarwin ? "/Applications" : "/bin") : binDir, + isDarwin ? (isMac ? "theapp.app/Contents/MacOS" : "theapp.app") : "" + }; + const BinaryInfo appDsym = { + isWindows + ? (!isMingw ? "theapp.pdb" : "theapp.exe.debug") + : isDarwin ? "theapp.app.dSYM" : "theapp.debug", + dsymDir.isEmpty() ? app.installDir : dsymDir, + {} + }; + const QString installRoot = QDir::currentPath() + "/default/install-root"; const QString installPrefix = isWindows ? QString() : "/usr/local"; const QString fullInstallPrefix = installRoot + '/' + installPrefix + '/'; - const QString appFilePath = fullInstallPrefix + binDir + '/' + appFileName; + const QString appFilePath = app.absolutePath(fullInstallPrefix); QVERIFY2(QFile::exists(appFilePath), qPrintable(appFilePath)); - const QString dllFilePath = fullInstallPrefix + dllDir + '/' + dllFileName; + const QString dllFilePath = dll.absolutePath(fullInstallPrefix); QVERIFY2(QFile::exists(dllFilePath), qPrintable(dllFilePath)); if (isWindows) { - const QString libFilePath = fullInstallPrefix + libDir + "/thelib.lib"; + const BinaryInfo lib = { + "thelib.lib", + libDir.isEmpty() ? "/lib" : libDir, + "" + }; + const QString libFilePath = lib.absolutePath(fullInstallPrefix); QVERIFY2(QFile::exists(libFilePath), qPrintable(libFilePath)); } + const QString pluginFilePath = plugin.absolutePath(fullInstallPrefix); + QVERIFY2(QFile::exists(pluginFilePath), qPrintable(pluginFilePath)); + + const QString appDsymFilePath = appDsym.absolutePath(fullInstallPrefix); + QVERIFY2(QFileInfo(appDsymFilePath).exists(), qPrintable(appDsymFilePath)); + const QString dllDsymFilePath = dllDsym.absolutePath(fullInstallPrefix); + QVERIFY2(QFileInfo(dllDsymFilePath).exists(), qPrintable(dllDsymFilePath)); + const QString pluginDsymFilePath = pluginDsym.absolutePath(fullInstallPrefix); + QVERIFY2(QFile::exists(pluginDsymFilePath), qPrintable(pluginDsymFilePath)); } void TestBlackbox::inputsFromDependencies() @@ -3887,7 +4653,7 @@ void TestBlackbox::installPackage() cleanOutputLines.push_back(trimmedLine); } QCOMPARE(cleanOutputLines.size(), 3); - for (const QByteArray &line : qAsConst(cleanOutputLines)) { + for (const QByteArray &line : std::as_const(cleanOutputLines)) { QVERIFY2(line.contains("public_tool") || line.contains("mylib") || line.contains("lib.h"), line.constData()); } @@ -3915,6 +4681,9 @@ void TestBlackbox::installable() void TestBlackbox::installableAsAuxiliaryInput() { QDir::setCurrent(testDataDir + "/installable-as-auxiliary-input"); + QCOMPARE(runQbs({"resolve"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(QbsRunParameters("run")), 0); QVERIFY2(m_qbsStdout.contains("f-impl"), m_qbsStdout.constData()); } @@ -3931,6 +4700,33 @@ void TestBlackbox::installTree() QVERIFY(QFile::exists(installRoot + "content/subdir2/baz.txt")); } +void TestBlackbox::invalidArtifactPath_data() +{ + QTest::addColumn<QString>("baseDir"); + QTest::addColumn<bool>("isValid"); + + QTest::newRow("inside, normal case") << "subdir" << true; + QTest::newRow("inside, build dir 1") << "project.buildDirectory" << true; + QTest::newRow("inside, build dir 2") << "subdir/.." << true; + QTest::newRow("outside, absolute") << "/tmp" << false; + QTest::newRow("outside, relative 1") << "../../" << false; + QTest::newRow("outside, relative 2") << "subdir/../../.." << false; +} + +void TestBlackbox::invalidArtifactPath() +{ + QFETCH(QString, baseDir); + QFETCH(bool, isValid); + + rmDirR(relativeBuildDir()); + QDir::setCurrent(testDataDir + "/invalid-artifact-path"); + QbsRunParameters params(QStringList("project.artifactDir:" + baseDir)); + params.expectFailure = !isValid; + QCOMPARE(runQbs(params) == 0, isValid); + if (!isValid) + QVERIFY2(m_qbsStderr.contains("outside of build directory"), m_qbsStderr.constData()); +} + void TestBlackbox::invalidCommandProperty_data() { QTest::addColumn<QString>("errorType"); @@ -3961,7 +4757,7 @@ void TestBlackbox::invalidLibraryNames() QbsRunParameters params(QStringList("project.valueIndex:" + index)); params.expectFailure = !success; QCOMPARE(runQbs(params) == 0, success); - for (const QString &diag : qAsConst(diagnostics)) + for (const QString &diag : std::as_const(diagnostics)) QVERIFY2(m_qbsStderr.contains(diag.toLocal8Bit()), m_qbsStderr.constData()); } @@ -4022,8 +4818,8 @@ void TestBlackbox::cli() QCOMPARE(status, 0); const SettingsPtr s = settings(); - Profile p("qbs_autotests-cli", s.get()); - const QStringList toolchain = p.value("qbs.toolchain").toStringList(); + qbs::Profile p("qbs_autotests-cli", s.get()); + const QStringList toolchain = profileToolchain(p); if (!p.exists() || !(toolchain.contains("dotnet") || toolchain.contains("mono"))) QSKIP("No suitable Common Language Infrastructure test profile"); @@ -4114,7 +4910,7 @@ void TestBlackbox::jsExtensionsFileInfo() QVERIFY(output.exists()); QVERIFY(output.open(QIODevice::ReadOnly)); const QList<QByteArray> lines = output.readAll().trimmed().split('\n'); - QCOMPARE(lines.size(), 26); + QCOMPARE(lines.size(), 28); int i = 0; QCOMPARE(lines.at(i++).trimmed().constData(), "blubb"); QCOMPARE(lines.at(i++).trimmed().constData(), qUtf8Printable( @@ -4143,11 +4939,52 @@ void TestBlackbox::jsExtensionsFileInfo() QCOMPARE(lines.at(i++).trimmed().constData(), "../blubb.tar.gz"); QCOMPARE(lines.at(i++).trimmed().constData(), "\\tmp\\blubb.tar.gz"); QCOMPARE(lines.at(i++).trimmed().constData(), "c:\\tmp\\blubb.tar.gz"); + QCOMPARE(lines.at(i++).trimmed().constData(), qUtf8Printable(HostOsInfo::pathListSeparator())); + QCOMPARE(lines.at(i++).trimmed().constData(), qUtf8Printable(HostOsInfo::pathSeparator())); +} + +void TestBlackbox::jsExtensionsHost() +{ + QDir::setCurrent(testDataDir + "//jsextensions-host"); + QbsRunParameters params(QStringList { "-f", "host.qbs" }); + QCOMPARE(runQbs(params), 0); + QFile output("output.txt"); + QVERIFY(output.exists()); + QVERIFY(output.open(QIODevice::ReadOnly)); + const QList<QByteArray> lines = output.readAll().trimmed().split('\n'); + QCOMPARE(lines.size(), 10); + int i = 0; + QCOMPARE(lines.at(i++).trimmed().constData(), "architecture: " + + HostOsInfo::hostOSArchitecture()); + QStringList list; + for (const auto &s : HostOsInfo::canonicalOSIdentifiers(HostOsInfo::hostOSIdentifier())) + list.push_back(s); + QCOMPARE(lines.at(i++).trimmed().constData(), "os: " + list.join(',')); + QCOMPARE(lines.at(i++).trimmed().constData(), "platform: " + HostOsInfo::hostOSIdentifier()); + QCOMPARE(lines.at(i++).trimmed().constData(), "osVersion: " + + HostOsInfo::hostOsVersion().toString()); + QCOMPARE(lines.at(i++).trimmed().constData(), "osBuildVersion: " + + (HostOsInfo::hostOsBuildVersion().isNull() ? "undefined" : + HostOsInfo::hostOsBuildVersion())); + QCOMPARE(lines.at(i++).trimmed().constData(), "osVersionParts: " + + HostOsInfo::hostOsVersion().toString(',')); + QCOMPARE(lines.at(i++).trimmed().constData(), "osVersionMajor: " + QString::number( + HostOsInfo::hostOsVersion().majorVersion())); + QCOMPARE(lines.at(i++).trimmed().constData(), "osVersionMinor: " + QString::number( + HostOsInfo::hostOsVersion().minorVersion())); + QCOMPARE(lines.at(i++).trimmed().constData(), "osVersionPatch: " + QString::number( + HostOsInfo::hostOsVersion().patchLevel())); + QString nullDevice = HostOsInfo::isWindowsHost() ? QStringLiteral("NUL") : + QStringLiteral("/dev/null"); + QCOMPARE(lines.at(i++).trimmed().constData(), "nullDevice: " + nullDevice); } void TestBlackbox::jsExtensionsProcess() { QDir::setCurrent(testDataDir + "/jsextensions-process"); + QCOMPARE(runQbs({"resolve", {"-f", "process.qbs"}}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params(QStringList() << "-f" << "process.qbs"); QCOMPARE(runQbs(params), 0); QFile output("output.txt"); @@ -4249,6 +5086,20 @@ void TestBlackbox::jsExtensionsBinaryFile() QCOMPARE(data.at(5), char(0x05)); QCOMPARE(data.at(6), char(0x06)); QCOMPARE(data.at(7), char(0xFF)); + QFile destination2("destination2.dat"); + QVERIFY(destination2.exists()); + QVERIFY(destination2.open(QIODevice::ReadOnly)); + QCOMPARE(destination2.readAll(), data); +} + +void TestBlackbox::lastModuleCandidateBroken() +{ + QDir::setCurrent(testDataDir + "/last-module-candidate-broken"); + QbsRunParameters params; + params.expectFailure = true; + QVERIFY(runQbs(params) != 0); + QVERIFY2(m_qbsStderr.contains("Dependency 'Foo' not found for product " + "'last-module-candidate-broken'"), m_qbsStderr); } void TestBlackbox::ld() @@ -4264,6 +5115,9 @@ void TestBlackbox::symbolLinkMode() QDir::setCurrent(testDataDir + "/symbolLinkMode"); + QCOMPARE(runQbs({"resolve"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params; params.command = "run"; const QStringList commonArgs{"-p", "driver", "--setup-run-env-config", @@ -4351,6 +5205,7 @@ void TestBlackbox::linkerVariant_data() QTest::newRow("default") << QString(); QTest::newRow("bfd") << QString("bfd"); QTest::newRow("gold") << QString("gold"); + QTest::newRow("mold") << QString("mold"); } void TestBlackbox::linkerVariant() @@ -4378,6 +5233,9 @@ void TestBlackbox::lexyacc() if (!lexYaccExist()) QSKIP("lex or yacc not present"); QDir::setCurrent(testDataDir + "/lexyacc/one-grammar"); + QCOMPARE(runQbs({"resolve"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(), 0); const QString parserBinary = relativeExecutableFilePath("one-grammar"); QProcess p; @@ -4393,7 +5251,7 @@ void TestBlackbox::lexyacc() env.insert("PATH", dir); p.setProcessEnvironment(env); } - p.start(parserBinary); + p.start(parserBinary, QStringList()); QVERIFY2(p.waitForStarted(), qPrintable(p.errorString())); p.write("a && b || c && !d"); p.closeWriteChannel(); @@ -4481,22 +5339,20 @@ void TestBlackbox::lexyaccOutputs_data() void TestBlackbox::linkerLibraryDuplicates() { - const SettingsPtr s = settings(); - Profile buildProfile(profileName(), s.get()); - QStringList toolchain = buildProfile.value("qbs.toolchain").toStringList(); - if (!toolchain.contains("gcc")) - QSKIP("linkerLibraryDuplicates test only applies to GCC toolchain"); - QDir::setCurrent(testDataDir + "/linker-library-duplicates"); rmDirR(relativeBuildDir()); - QFETCH(QString, removeDuplicateLibraries); QStringList runParams; - if (!removeDuplicateLibraries.isEmpty()) { + if (!removeDuplicateLibraries.isEmpty()) runParams.append(removeDuplicateLibraries); - } QCOMPARE(runQbs(QbsRunParameters("resolve", runParams)), 0); + const bool isGcc = m_qbsStdout.contains("is gcc: true"); + const bool isNotGcc = m_qbsStdout.contains("is gcc: false"); + if (isNotGcc) + QSKIP("linkerLibraryDuplicates test only applies to GCC toolchain"); + QVERIFY(isGcc); + QCOMPARE(runQbs(QStringList { "--command-echo-mode", "command-line" }), 0); const QByteArrayList output = m_qbsStdout.split('\n'); QByteArray linkLine; @@ -4561,25 +5417,27 @@ void TestBlackbox::linkerLibraryDuplicates_data() void TestBlackbox::linkerScripts() { - const SettingsPtr s = settings(); - Profile buildProfile(profileName(), s.get()); - QStringList toolchain = buildProfile.value("qbs.toolchain").toStringList(); - if (!toolchain.contains("gcc") || targetOs() != HostOsInfo::HostOsLinux) - QSKIP("linker script test only applies to Linux "); - - QbsRunParameters runParams(QStringList() -// << "--log-level" << "debug" - << ("qbs.installRoot:" + QDir::currentPath())); const QString sourceDir = QDir::cleanPath(testDataDir + "/linkerscripts"); + QbsRunParameters runParams("resolve", {"qbs.installRoot:" + QDir::currentPath()}); runParams.buildDirectory = sourceDir + "/build"; runParams.workingDir = sourceDir; QCOMPARE(runQbs(runParams), 0); + const bool isGcc = m_qbsStdout.contains("is Linux gcc: true"); + const bool isNotGcc = m_qbsStdout.contains("is Linux gcc: false"); + if (isNotGcc) + QSKIP("linker script test only applies to Linux"); + QVERIFY(isGcc); + + runParams.command = "build"; + QCOMPARE(runQbs(runParams), 0); const QString output = QString::fromLocal8Bit(m_qbsStderr); - QRegExp pattern(".*---(.*)---.*"); - QVERIFY2(pattern.exactMatch(output), qPrintable(output)); + const QRegularExpression pattern(QRegularExpression::anchoredPattern(".*---(.*)---.*"), + QRegularExpression::DotMatchesEverythingOption); + const QRegularExpressionMatch match = pattern.match(output); + QVERIFY2(match.hasMatch(), qPrintable(output)); QCOMPARE(pattern.captureCount(), 1); - const QString nmPath = pattern.capturedTexts().at(1); + const QString nmPath = match.captured(1); if (!QFile::exists(nmPath)) QSKIP("Cannot check for symbol presence: No nm found."); @@ -4652,6 +5510,26 @@ void TestBlackbox::linkerScripts() "TEST_SYMBOL_FROM_RECURSIVE_MODIFIED"})); } +void TestBlackbox::linkerModuleDefinition() +{ + QDir::setCurrent(testDataDir + "/linker-module-definition"); + QCOMPARE(runQbs({"build"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); + QCOMPARE(runQbs({"run"}), 0); + const auto verifyOutput = [this](const QByteArrayList &symbols) { + for (const QByteArray &symbol : symbols) { + if (!m_qbsStdout.contains(symbol)) { + qDebug() << "Expected symbol" << symbol + << "not found in" << m_qbsStdout; + return false; + } + } + return true; + }; + QVERIFY(verifyOutput({"foo", "bar"})); +} + void TestBlackbox::listProducts() { QDir::setCurrent(testDataDir + "/list-products"); @@ -4680,7 +5558,7 @@ void TestBlackbox::listPropertyOrder() const QbsRunParameters params(QStringList() << "-q"); QCOMPARE(runQbs(params), 0); const QByteArray firstOutput = m_qbsStderr; - QVERIFY(firstOutput.contains("listProp = [\"higher1\",\"higher2\",\"higher3\"]")); + QVERIFY(firstOutput.contains("listProp = [\"product\",\"higher3\",\"higher2\",\"higher1\",\"lower\"]")); for (int i = 0; i < 25; ++i) { rmDirR(relativeBuildDir()); QCOMPARE(runQbs(params), 0); @@ -4696,16 +5574,6 @@ void TestBlackbox::require() QCOMPARE(runQbs(), 0); } -void TestBlackbox::requireDeprecated() -{ - QDir::setCurrent(testDataDir + "/require-deprecated"); - QCOMPARE(runQbs(), 0); - QVERIFY2(m_qbsStderr.contains("loadExtension() function is deprecated"), - m_qbsStderr.constData()); - QVERIFY2(m_qbsStderr.contains("loadFile() function is deprecated"), - m_qbsStderr.constData()); -} - void TestBlackbox::rescueTransformerData() { QDir::setCurrent(testDataDir + "/rescue-transformer-data"); @@ -4767,6 +5635,9 @@ void TestBlackbox::multipleConfigurations() void TestBlackbox::multiplexedTool() { QDir::setCurrent(testDataDir + "/multiplexed-tool"); + QCOMPARE(runQbs(QStringLiteral("resolve")), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(), 0); QCOMPARE(m_qbsStdout.count("creating tool.out"), 4); } @@ -4922,6 +5793,8 @@ void TestBlackbox::propertyPrecedence() // Case 1: [cmdline=0,prod=0,export=0,nonleaf=0,profile=0] QCOMPARE(runQbs(params), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); + QVERIFY2(m_qbsStdout.contains("scalar prop: leaf\n") && m_qbsStdout.contains("list prop: [\"leaf\"]\n"), m_qbsStdout.constData()); @@ -4930,6 +5803,8 @@ void TestBlackbox::propertyPrecedence() // Case 2: [cmdline=0,prod=0,export=0,nonleaf=0,profile=1] switchProfileContents(profile.p, s.get(), true); QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); + QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: profile\n") && m_qbsStdout.contains("list prop: [\"profile\"]\n"), @@ -4941,6 +5816,7 @@ void TestBlackbox::propertyPrecedence() switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, true); QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: nonleaf\n") && m_qbsStdout.contains("list prop: [\"nonleaf\",\"leaf\"]\n"), @@ -4949,6 +5825,7 @@ void TestBlackbox::propertyPrecedence() // Case 4: [cmdline=0,prod=0,export=0,nonleaf=1,profile=1] switchProfileContents(profile.p, s.get(), true); QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: nonleaf\n") && m_qbsStdout.contains("list prop: [\"nonleaf\",\"profile\"]\n"), @@ -4961,6 +5838,7 @@ void TestBlackbox::propertyPrecedence() switchFileContents(nonleafFile, false); switchFileContents(depFile, true); QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: export\n") && m_qbsStdout.contains("list prop: [\"export\",\"leaf\"]\n"), @@ -4969,16 +5847,18 @@ void TestBlackbox::propertyPrecedence() // Case 6: [cmdline=0,prod=0,export=1,nonleaf=0,profile=1] switchProfileContents(profile.p, s.get(), true); QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: export\n") && m_qbsStdout.contains("list prop: [\"export\",\"profile\"]\n"), m_qbsStdout.constData()); + // Case 7: [cmdline=0,prod=0,export=1,nonleaf=1,profile=0] switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, true); QCOMPARE(runQbs(resolveParams), 0); - QCOMPARE(runQbs(params), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: export\n") && m_qbsStdout.contains("list prop: [\"export\",\"nonleaf\",\"leaf\"]\n"), m_qbsStdout.constData()); @@ -4986,6 +5866,7 @@ void TestBlackbox::propertyPrecedence() // Case 8: [cmdline=0,prod=0,export=1,nonleaf=1,profile=1] switchProfileContents(profile.p, s.get(), true); QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: export\n") && m_qbsStdout.contains("list prop: [\"export\",\"nonleaf\",\"profile\"]\n"), @@ -4999,6 +5880,7 @@ void TestBlackbox::propertyPrecedence() switchFileContents(depFile, false); switchFileContents(productFile, true); QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: product\n") && m_qbsStdout.contains("list prop: [\"product\",\"leaf\"]\n"), @@ -5007,6 +5889,7 @@ void TestBlackbox::propertyPrecedence() // Case 10: [cmdline=0,prod=1,export=0,nonleaf=0,profile=1] switchProfileContents(profile.p, s.get(), true); QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: product\n") && m_qbsStdout.contains("list prop: [\"product\",\"profile\"]\n"), @@ -5016,6 +5899,7 @@ void TestBlackbox::propertyPrecedence() switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, true); QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: product\n") && m_qbsStdout.contains("list prop: [\"product\",\"nonleaf\",\"leaf\"]\n"), @@ -5024,6 +5908,7 @@ void TestBlackbox::propertyPrecedence() // Case 12: [cmdline=0,prod=1,export=0,nonleaf=1,profile=1] switchProfileContents(profile.p, s.get(), true); QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: product\n") && m_qbsStdout.contains("list prop: [\"product\",\"nonleaf\",\"profile\"]\n"), @@ -5034,6 +5919,7 @@ void TestBlackbox::propertyPrecedence() switchFileContents(nonleafFile, false); switchFileContents(depFile, true); QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: product\n") && m_qbsStdout.contains("list prop: [\"product\",\"export\",\"leaf\"]\n"), @@ -5042,6 +5928,7 @@ void TestBlackbox::propertyPrecedence() // Case 14: [cmdline=0,prod=1,export=1,nonleaf=0,profile=1] switchProfileContents(profile.p, s.get(), true); QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: product\n") && m_qbsStdout.contains("list prop: [\"product\",\"export\",\"profile\"]\n"), @@ -5051,6 +5938,7 @@ void TestBlackbox::propertyPrecedence() switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, true); QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: product\n") && m_qbsStdout.contains("list prop: [\"product\",\"export\",\"nonleaf\",\"leaf\"]\n"), @@ -5059,6 +5947,7 @@ void TestBlackbox::propertyPrecedence() // Case 16: [cmdline=0,prod=1,export=1,nonleaf=1,profile=1] switchProfileContents(profile.p, s.get(), true); QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: product\n") && m_qbsStdout.contains("list prop: [\"product\",\"export\",\"nonleaf\",\"profile\"]\n"), @@ -5072,6 +5961,7 @@ void TestBlackbox::propertyPrecedence() switchFileContents(productFile, false); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), @@ -5081,6 +5971,7 @@ void TestBlackbox::propertyPrecedence() switchProfileContents(profile.p, s.get(), true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), @@ -5091,6 +5982,7 @@ void TestBlackbox::propertyPrecedence() switchFileContents(nonleafFile, true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), @@ -5100,6 +5992,7 @@ void TestBlackbox::propertyPrecedence() switchProfileContents(profile.p, s.get(), true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), @@ -5111,6 +6004,7 @@ void TestBlackbox::propertyPrecedence() switchFileContents(depFile, true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), @@ -5120,6 +6014,7 @@ void TestBlackbox::propertyPrecedence() switchProfileContents(profile.p, s.get(), true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), @@ -5130,6 +6025,7 @@ void TestBlackbox::propertyPrecedence() switchFileContents(nonleafFile, true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), @@ -5139,6 +6035,7 @@ void TestBlackbox::propertyPrecedence() switchProfileContents(profile.p, s.get(), true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), @@ -5151,6 +6048,7 @@ void TestBlackbox::propertyPrecedence() switchFileContents(productFile, true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), @@ -5160,6 +6058,7 @@ void TestBlackbox::propertyPrecedence() switchProfileContents(profile.p, s.get(), true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), @@ -5170,6 +6069,7 @@ void TestBlackbox::propertyPrecedence() switchFileContents(nonleafFile, true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), @@ -5179,6 +6079,7 @@ void TestBlackbox::propertyPrecedence() switchProfileContents(profile.p, s.get(), true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), @@ -5190,6 +6091,7 @@ void TestBlackbox::propertyPrecedence() switchFileContents(depFile, true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), @@ -5199,6 +6101,7 @@ void TestBlackbox::propertyPrecedence() switchProfileContents(profile.p, s.get(), true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), @@ -5209,6 +6112,7 @@ void TestBlackbox::propertyPrecedence() switchFileContents(nonleafFile, true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), @@ -5218,6 +6122,7 @@ void TestBlackbox::propertyPrecedence() switchProfileContents(profile.p, s.get(), true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); + QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), @@ -5247,10 +6152,19 @@ void TestBlackbox::productDependenciesByType() QVERIFY(apps.empty()); } +void TestBlackbox::productInExportedModule() +{ + QDir::setCurrent(testDataDir + "/product-in-exported-module"); + QCOMPARE(runQbs(), 0); + QVERIFY2(m_qbsStdout.contains("product: importing"), m_qbsStdout.constData()); +} + void TestBlackbox::properQuoting() { QDir::setCurrent(testDataDir + "/proper quoting"); QCOMPARE(runQbs(), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params(QStringLiteral("run"), QStringList() << "-q" << "-p" << "Hello World"); params.expectFailure = true; // Because the exit code is non-zero. QCOMPARE(runQbs(params), 156); @@ -5272,15 +6186,27 @@ void TestBlackbox::protobuf_data() { QTest::addColumn<QString>("projectFile"); QTest::addColumn<QStringList>("properties"); + QTest::addColumn<bool>("hasModules"); QTest::addColumn<bool>("successExpected"); - QTest::newRow("cpp") << QString("addressbook_cpp.qbs") << QStringList() << true; - QTest::newRow("objc") << QString("addressbook_objc.qbs") << QStringList() << true; - QTest::newRow("import") << QString("import.qbs") << QStringList() << true; + QTest::newRow("cpp-pkgconfig") + << QString("addressbook_cpp.qbs") + << QStringList({"project.qbsModuleProviders:qbspkgconfig"}) << true << true; + QTest::newRow("cpp-conan") << QString("addressbook_cpp.qbs") + << QStringList( + {"project.qbsModuleProviders:conan", + "qbs.buildVariant:release", + "moduleProviders.conan.installDirectory:build"}) + << true << true; + QTest::newRow("objc") << QString("addressbook_objc.qbs") << QStringList() << false << true; + QTest::newRow("nanopb") << QString("addressbook_nanopb.qbs") << QStringList() << false << true; + QTest::newRow("import") << QString("import.qbs") << QStringList() << true << true; QTest::newRow("missing import dir") << QString("needs-import-dir.qbs") - << QStringList() << false; + << QStringList() << true << false; QTest::newRow("provided import dir") << QString("needs-import-dir.qbs") - << QStringList("products.app.theImportDir:subdir") << true; + << QStringList("products.app.theImportDir:subdir") << true << true; + QTest::newRow("create proto library") + << QString("create-proto-library.qbs") << QStringList() << true << true; } void TestBlackbox::protobuf() @@ -5288,20 +6214,55 @@ void TestBlackbox::protobuf() QDir::setCurrent(testDataDir + "/protobuf"); QFETCH(QString, projectFile); QFETCH(QStringList, properties); + QFETCH(bool, hasModules); QFETCH(bool, successExpected); rmDirR(relativeBuildDir()); + + if (QTest::currentDataTag() == QLatin1String("cpp-conan")) { + if (!prepareAndRunConan()) + QSKIP("conan is not prepared, check messages above"); + } + QbsRunParameters resolveParams("resolve", QStringList{"-f", projectFile} << properties); QCOMPARE(runQbs(resolveParams), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); const bool withProtobuf = m_qbsStdout.contains("has protobuf: true"); const bool withoutProtobuf = m_qbsStdout.contains("has protobuf: false"); QVERIFY2(withProtobuf || withoutProtobuf, m_qbsStdout.constData()); if (withoutProtobuf) QSKIP("protobuf module not present"); + const bool hasMods = m_qbsStdout.contains("has modules: true"); + const bool dontHaveMods = m_qbsStdout.contains("has modules: false"); + QVERIFY2(hasMods == !dontHaveMods, m_qbsStdout.constData()); + QCOMPARE(hasMods, hasModules); QbsRunParameters runParams("run"); runParams.expectFailure = !successExpected; QCOMPARE(runQbs(runParams) == 0, successExpected); } +void TestBlackbox::protobufLibraryInstall() +{ + QDir::setCurrent(testDataDir + "/protobuf-library-install"); + rmDirR(relativeBuildDir()); + QbsRunParameters resolveParams("resolve", QStringList{"qbs.installPrefix:/usr/local"}); + QCOMPARE(runQbs(resolveParams), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); + const bool withProtobuf = m_qbsStdout.contains("has protobuf: true"); + const bool withoutProtobuf = m_qbsStdout.contains("has protobuf: false"); + QVERIFY2(withProtobuf || withoutProtobuf, m_qbsStdout.constData()); + if (withoutProtobuf) + QSKIP("protobuf module not present"); + QbsRunParameters buildParams("build"); + buildParams.expectFailure = false; + QCOMPARE(runQbs(buildParams), 0); + + const QString installRootInclude = relativeBuildDir() + "/install-root/usr/local/include"; + QVERIFY(QFileInfo::exists(installRootInclude + "/hello.pb.h") && + QFileInfo::exists(installRootInclude + "/hello/world.pb.h")); +} + void TestBlackbox::pseudoMultiplexing() { // This is "pseudo-multiplexing" on all platforms that initialize qbs.architectures @@ -5411,7 +6372,158 @@ void TestBlackbox::qbsConfig() if (!canWriteToSystemSettings) { QVERIFY2(m_qbsStderr.contains("You do not have permission to write to that location."), m_qbsStderr.constData()); + } else { + // cleanup system settings + params.arguments = QStringList{"--system", "--unset", "key.subkey.scalar"}; + QCOMPARE(runQbs(params) == 0, canWriteToSystemSettings); + } +} + +void TestBlackbox::qbsConfigAddProfile() +{ + QbsRunParameters params("config"); + QTemporaryDir settingsDir1; + QTemporaryDir settingsDir2; + QVERIFY(settingsDir1.isValid()); + QVERIFY(settingsDir2.isValid()); + const QStringList settingsDir1Args = QStringList{"--settings-dir", settingsDir1.path()}; + const QStringList settingsDir2Args = QStringList{"--settings-dir", settingsDir2.path()}; + + QFETCH(QStringList, args); + QFETCH(QString, errorMsg); + + // Step 1: Run --add-profile. + params.arguments = settingsDir1Args; + params.arguments << "--add-profile"; + params.arguments << args; + params.expectFailure = !errorMsg.isEmpty(); + QCOMPARE(runQbs(params) == 0, !params.expectFailure); + if (params.expectFailure) { + QVERIFY(QString::fromLocal8Bit(m_qbsStderr).contains(errorMsg)); + return; } + params.expectFailure = false; + params.arguments = settingsDir1Args; + params.arguments << "--list"; + QCOMPARE(runQbs(params), 0); + const QByteArray output1 = m_qbsStdout; + + // Step 2: Set properties manually. + for (int i = 1; i < args.size(); i += 2) { + params.arguments = settingsDir2Args; + params.arguments << ("profiles." + args.first() + '.' + args.at(i)) << args.at(i + 1); + QCOMPARE(runQbs(params), 0); + } + params.arguments = settingsDir2Args; + params.arguments << "--list"; + QCOMPARE(runQbs(params), 0); + const QByteArray output2 = m_qbsStdout; + + // Step3: Compare results. + QCOMPARE(output1, output2); +} + +void TestBlackbox::qbsConfigAddProfile_data() +{ + QTest::addColumn<QStringList>("args"); + QTest::addColumn<QString>("errorMsg"); + QTest::newRow("no arguments") << QStringList() << QString("Profile name missing"); + QTest::newRow("empty name") << QStringList{"", "p", "v"} + << QString("Profile name must not be empty"); + QTest::newRow("no properties") << QStringList("p") + << QString("Profile properties must be provided"); + QTest::newRow("one property") << QStringList{"p", "p", "v"} << QString(); + QTest::newRow("two properties") << QStringList{"p", "p1", "v1", "p2", "v2"} << QString(); + QTest::newRow("missing value") << QStringList{"p", "p"} + << QString("Profile properties must be key/value pairs"); + QTest::newRow("missing values") << QStringList{"p", "p1", "v1", "p2"} + << QString("Profile properties must be key/value pairs"); +} + +void TestBlackbox::qbsConfigImport() +{ + QFETCH(QString, format); + + QDir::setCurrent(testDataDir + "/qbs-config-import-export"); + + QbsRunParameters params("config"); + QTemporaryDir settingsDir; + QVERIFY(settingsDir.isValid()); + const QStringList settingsDirArgs = QStringList{"--settings-dir", settingsDir.path()}; + params.arguments = settingsDirArgs; + params.arguments << "--import" << "config." + format; + + QCOMPARE(runQbs(params), 0); + + params.arguments = settingsDirArgs; + params.arguments << "--list"; + QCOMPARE(runQbs(params), 0); + const QByteArray output = m_qbsStdout; + const auto lines = output.split('\n'); + QCOMPARE(lines.count(), 5); + QCOMPARE(lines[0], "group.key1: \"value1\""); + QCOMPARE(lines[1], "group.key2: \"value2\""); + QCOMPARE(lines[2], "key: \"value\""); + QCOMPARE(lines[3], "listKey: [\"valueOne\", \"valueTwo\"]"); + QCOMPARE(lines[4], ""); +} + +void TestBlackbox::qbsConfigImport_data() +{ + QTest::addColumn<QString>("format"); + + QTest::newRow("text") << QStringLiteral("txt"); + QTest::newRow("json") << QStringLiteral("json"); +} + +void TestBlackbox::qbsConfigExport() +{ + QFETCH(QString, format); + + QDir::setCurrent(testDataDir + "/qbs-config-import-export"); + + QbsRunParameters params("config"); + QTemporaryDir settingsDir; + const QString fileName = "config." + format; + const QString filePath = settingsDir.path() + "/" + fileName; + QVERIFY(settingsDir.isValid()); + const QStringList commonArgs = QStringList{"--settings-dir", settingsDir.path(), "--user"}; + + std::pair<QString, QString> values[] = { + {"key", "value"}, + {"listKey", "[\"valueOne\",\"valueTwo\"]"}, + {"group.key1", "value1"}, + {"group.key2", "value2"} + }; + + for (const auto &value: values) { + params.arguments = commonArgs; + params.arguments << value.first << value.second; + QCOMPARE(runQbs(params), 0); + } + + params.arguments = commonArgs; + params.arguments << "--export" << filePath; + + QCOMPARE(runQbs(params), 0); + + QVERIFY(QFileInfo(filePath).canonicalPath() != QFileInfo(fileName).canonicalPath()); + + QFile exported(filePath); + QFile expected(fileName); + + QVERIFY(exported.open(QIODevice::ReadOnly | QIODevice::Text)); + QVERIFY(expected.open(QIODevice::ReadOnly | QIODevice::Text)); + + QCOMPARE(exported.readAll(), expected.readAll()); +} + +void TestBlackbox::qbsConfigExport_data() +{ + QTest::addColumn<QString>("format"); + + QTest::newRow("text") << QStringLiteral("txt"); + QTest::newRow("json") << QStringLiteral("json"); } static QJsonObject getNextSessionPacket(QProcess &session, QByteArray &data) @@ -5450,6 +6562,137 @@ static QJsonObject getNextSessionPacket(QProcess &session, QByteArray &data) return QJsonDocument::fromJson(QByteArray::fromBase64(msg)).object(); } +static void sendSessionPacket(QProcess &sessionProc, const QJsonObject &message) +{ + const QByteArray data = QJsonDocument(message).toJson().toBase64(); + sessionProc.write("qbsmsg:"); + sessionProc.write(QByteArray::number(data.length())); + sessionProc.write("\n"); + sessionProc.write(data); +} + +void TestBlackbox::qbsLanguageServer_data() +{ + QTest::addColumn<QString>("request"); + QTest::addColumn<QString>("location"); + QTest::addColumn<QString>("insertLocation"); + QTest::addColumn<QString>("insertString"); + QTest::addColumn<QString>("expectedReply"); + + QTest::addRow("follow to module") << "--goto-def" + << (testDataDir + "/lsp/lsp.qbs:4:9") + << QString() << QString() + << (testDataDir + "/lsp/modules/m/m.qbs:1:1"); + QTest::addRow("follow to submodules") + << "--goto-def" + << (testDataDir + "/lsp/lsp.qbs:5:35") + << QString() << QString() + << ((testDataDir + "/lsp/modules/Prefix/m1/m1.qbs:1:1\n") + + (testDataDir + "/lsp/modules/Prefix/m2/m2.qbs:1:1\n") + + (testDataDir + "/lsp/modules/Prefix/m3/m3.qbs:1:1")); + QTest::addRow("follow to product") + << "--goto-def" << (testDataDir + "/lsp/lsp.qbs:9:19") << QString() << QString() + << (testDataDir + "/lsp/lsp.qbs:2:5"); + QTest::addRow("follow to module, non-invalidating insert") + << "--goto-def" << (testDataDir + "/lsp/lsp.qbs:4:9") << "5:9" + << QString("property bool dummy\n") << (testDataDir + "/lsp/modules/m/m.qbs:1:1"); + QTest::addRow("follow to module, invalidating insert") + << "--goto-def" << (testDataDir + "/lsp/lsp.qbs:4:9") << QString() + << QString("property bool dummy\n") << QString(); + QTest::addRow("completion: LHS, module prefix") + << "--completion" << (testDataDir + "/lsp/lsp.qbs:7:1") << QString() << QString("P") + << QString("Prefix.m1\nPrefix.m2\nPrefix.m3"); + QTest::addRow("completion: LHS, module name") + << "--completion" << (testDataDir + "/lsp/lsp.qbs:7:1") << QString() << QString("Prefix.m") + << QString("m1\nm2\nm3"); + QTest::addRow("completion: LHS, module property right after dot") + << "--completion" << (testDataDir + "/lsp/lsp.qbs:7:1") << QString() + << QString("Prefix.m1.") << QString("p1 bool\np2 string\nx bool"); + QTest::addRow("completion: LHS, module property with identifier prefix") + << "--completion" << (testDataDir + "/lsp/lsp.qbs:7:1") << QString() + << QString("Prefix.m1.p") << QString("p1 bool\np2 string"); + QTest::addRow("completion: simple RHS, module property") + << "--completion" << (testDataDir + "/lsp/lsp.qbs:7:1") << QString() + << QString("property bool dummy: Prefix.m1.p") << QString("p1 bool\np2 string"); + QTest::addRow("completion: complex RHS, module property") + << "--completion" << (testDataDir + "/lsp/lsp.qbs:7:1") << QString() + << QString("property bool dummy: { return Prefix.m1.p") << QString("p1 bool\np2 string"); +} + +void TestBlackbox::qbsLanguageServer() +{ + QFETCH(QString, request); + QFETCH(QString, location); + QFETCH(QString, insertLocation); + QFETCH(QString, insertString); + QFETCH(QString, expectedReply); + + QDir::setCurrent(testDataDir + "/lsp"); + QProcess sessionProc; + sessionProc.start(qbsExecutableFilePath, QStringList("session")); + + QVERIFY(sessionProc.waitForStarted()); + + QByteArray incomingData; + + // Wait for and verify hello packet. + QJsonObject receivedMessage = getNextSessionPacket(sessionProc, incomingData); + const QString socketPath = receivedMessage.value("lsp-socket").toString(); + QVERIFY(!socketPath.isEmpty()); + + // Resolve project. + QJsonObject resolveMessage; + resolveMessage.insert("type", "resolve-project"); + resolveMessage.insert("top-level-profile", profileName()); + resolveMessage.insert("project-file-path", QDir::currentPath() + "/lsp.qbs"); + resolveMessage.insert("build-root", QDir::currentPath()); + resolveMessage.insert("settings-directory", settings()->baseDirectory()); + sendSessionPacket(sessionProc, resolveMessage); + bool receivedReply = false; + while (!receivedReply) { + receivedMessage = getNextSessionPacket(sessionProc, incomingData); + QVERIFY(!receivedMessage.isEmpty()); + const QString msgType = receivedMessage.value("type").toString(); + if (msgType == "project-resolved") { + receivedReply = true; + const QJsonObject error = receivedMessage.value("error").toObject(); + if (!error.isEmpty()) + qDebug() << error; + QVERIFY(error.isEmpty()); + } + } + QVERIFY(receivedReply); + + // Employ client app to send request. + QProcess lspClient; + const QFileInfo qbsFileInfo(qbsExecutableFilePath); + const QString clientFilePath = HostOsInfo::appendExecutableSuffix( + qbsFileInfo.absolutePath() + "/qbs_lspclient"); + QStringList args{"--socket", socketPath, request, location}; + if (!insertString.isEmpty()) + args << "--insert-code" << insertString; + if (!insertLocation.isEmpty()) + args << "--insert-location" << insertLocation; + lspClient.start(clientFilePath, args); + QVERIFY2(lspClient.waitForStarted(), qPrintable(lspClient.errorString())); + QVERIFY2(lspClient.waitForFinished(), qPrintable(lspClient.errorString())); + QString errMsg; + if (lspClient.exitStatus() != QProcess::NormalExit) + errMsg = lspClient.errorString(); + if (errMsg.isEmpty()) + errMsg = QString::fromLocal8Bit(lspClient.readAllStandardError()); + QVERIFY2(lspClient.exitCode() == 0, qPrintable(errMsg)); + QVERIFY2(errMsg.isEmpty(), qPrintable(errMsg)); + QString output = QString::fromUtf8(lspClient.readAllStandardOutput().trimmed()); + output.replace("\r\n", "\n"); + QCOMPARE(output, expectedReply); + + QJsonObject quitRequest; + quitRequest.insert("type", "quit"); + sendSessionPacket(sessionProc, quitRequest); + QVERIFY(sessionProc.waitForFinished(3000)); +} + void TestBlackbox::qbsSession() { QDir::setCurrent(testDataDir + "/qbs-session"); @@ -5466,11 +6709,7 @@ void TestBlackbox::qbsSession() QVERIFY(sessionProc.waitForStarted()); const auto sendPacket = [&sessionProc](const QJsonObject &message) { - const QByteArray data = QJsonDocument(message).toJson().toBase64(); - sessionProc.write("qbsmsg:"); - sessionProc.write(QByteArray::number(data.length())); - sessionProc.write("\n"); - sessionProc.write(data); + sendSessionPacket(sessionProc, message); }; static const auto envToJson = [](const QProcessEnvironment &env) { @@ -5494,8 +6733,8 @@ void TestBlackbox::qbsSession() // Wait for and verify hello packet. QJsonObject receivedMessage = getNextSessionPacket(sessionProc, incomingData); QCOMPARE(receivedMessage.value("type"), "hello"); - QCOMPARE(receivedMessage.value("api-level").toInt(), 1); - QCOMPARE(receivedMessage.value("api-compat-level").toInt(), 1); + QCOMPARE(receivedMessage.value("api-level").toInt(), 5); + QCOMPARE(receivedMessage.value("api-compat-level").toInt(), 2); // Resolve & verify structure QJsonObject resolveMessage; @@ -5508,8 +6747,9 @@ void TestBlackbox::qbsSession() QJsonObject overriddenValues; overriddenValues.insert("products.theLib.cpp.cxxLanguageVersion", "c++17"); resolveMessage.insert("overridden-properties", overriddenValues); - resolveMessage.insert("environment", envToJson(QProcessEnvironment::systemEnvironment())); + resolveMessage.insert("environment", envToJson(QbsRunParameters::defaultEnvironment())); resolveMessage.insert("data-mode", "only-if-changed"); + resolveMessage.insert("max-job-count", 2); resolveMessage.insert("log-time", true); resolveMessage.insert("module-properties", QJsonArray::fromStringList({"cpp.cxxLanguageVersion"})); @@ -5553,7 +6793,7 @@ void TestBlackbox::qbsSession() const QJsonObject group = v.toObject(); const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray(); - const auto findArtifact = [&sourceArtifacts](const QString fileName) { + const auto findArtifact = [&sourceArtifacts](const QString &fileName) { for (const QJsonValue &v : sourceArtifacts) { const QJsonObject artifact = v.toObject(); if (QFileInfo(artifact.value("file-path").toString()).fileName() @@ -5815,7 +7055,7 @@ void TestBlackbox::qbsSession() QCOMPARE(receivedMessage.value("type").toString(), QString("files-added")); error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) { - for (const auto &item: error[QStringLiteral("items")].toArray()) { + for (const auto item: error[QStringLiteral("items")].toArray()) { const auto description = QStringLiteral("Project file updates are not enabled"); if (item.toObject()[QStringLiteral("description")].toString().contains(description)) QSKIP("File updates are disabled"); @@ -5823,34 +7063,51 @@ void TestBlackbox::qbsSession() qDebug() << error; } QVERIFY(error.isEmpty()); - QJsonObject projectData = receivedMessage.value("project-data").toObject(); - QJsonArray products = projectData.value("products").toArray(); - bool file1 = false; - bool file2 = false; - for (const QJsonValue &v : products) { - const QJsonObject product = v.toObject(); - const QString productName = product.value("full-display-name").toString(); - const QJsonArray groups = product.value("groups").toArray(); - for (const QJsonValue &v : groups) { - const QJsonObject group = v.toObject(); - const QString groupName = group.value("name").toString(); - const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray(); - for (const QJsonValue &v : sourceArtifacts) { - const QString filePath = v.toObject().value("file-path").toString(); - if (filePath.endsWith("file1.cpp")) { - QCOMPARE(productName, QString("theLib")); - QCOMPARE(groupName, QString("sources")); - file1 = true; - } else if (filePath.endsWith("file2.cpp")) { - QCOMPARE(productName, QString("theLib")); - QCOMPARE(groupName, QString("sources")); - file2 = true; + + receivedReply = false; + sendPacket(resolveMessage); + while (!receivedReply) { + receivedMessage = getNextSessionPacket(sessionProc, incomingData); + QVERIFY(!receivedMessage.isEmpty()); + const QString msgType = receivedMessage.value("type").toString(); + if (msgType == "project-resolved") { + receivedReply = true; + const QJsonObject error = receivedMessage.value("error").toObject(); + if (!error.isEmpty()) + qDebug() << error; + QVERIFY(error.isEmpty()); + const QJsonObject projectData = receivedMessage.value("project-data").toObject(); + QJsonArray products = projectData.value("products").toArray(); + bool file1 = false; + bool file2 = false; + for (const QJsonValue v : products) { + const QJsonObject product = v.toObject(); + const QString productName = product.value("full-display-name").toString(); + const QJsonArray groups = product.value("groups").toArray(); + for (const QJsonValue &v : groups) { + const QJsonObject group = v.toObject(); + const QString groupName = group.value("name").toString(); + const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray(); + for (const QJsonValue &v : sourceArtifacts) { + const QString filePath = v.toObject().value("file-path").toString(); + if (filePath.endsWith("file1.cpp")) { + QCOMPARE(productName, QString("theLib")); + QCOMPARE(groupName, QString("sources")); + file1 = true; + } else if (filePath.endsWith("file2.cpp")) { + QCOMPARE(productName, QString("theLib")); + QCOMPARE(groupName, QString("sources")); + file2 = true; + } + } } } + QVERIFY(file1); + QVERIFY(file2); } } - QVERIFY(file1); - QVERIFY(file2); + QVERIFY(receivedReply); + receivedReply = false; receivedProcessResult = false; bool compiledFile1 = false; @@ -5909,32 +7166,48 @@ void TestBlackbox::qbsSession() if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); - projectData = receivedMessage.value("project-data").toObject(); - products = projectData.value("products").toArray(); - file1 = false; - file2 = false; - for (const QJsonValue &v : products) { - const QJsonObject product = v.toObject(); - const QString productName = product.value("full-display-name").toString(); - const QJsonArray groups = product.value("groups").toArray(); - for (const QJsonValue &v : groups) { - const QJsonObject group = v.toObject(); - const QString groupName = group.value("name").toString(); - const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray(); - for (const QJsonValue &v : sourceArtifacts) { - const QString filePath = v.toObject().value("file-path").toString(); - if (filePath.endsWith("file1.cpp")) { - file1 = true; - } else if (filePath.endsWith("file2.cpp")) { - QCOMPARE(productName, QString("theLib")); - QCOMPARE(groupName, QString("sources")); - file2 = true; + receivedReply = false; + sendPacket(resolveMessage); + while (!receivedReply) { + receivedMessage = getNextSessionPacket(sessionProc, incomingData); + QVERIFY(!receivedMessage.isEmpty()); + const QString msgType = receivedMessage.value("type").toString(); + if (msgType == "project-resolved") { + receivedReply = true; + const QJsonObject error = receivedMessage.value("error").toObject(); + if (!error.isEmpty()) + qDebug() << error; + QVERIFY(error.isEmpty()); + const QJsonObject projectData = receivedMessage.value("project-data").toObject(); + QJsonArray products = projectData.value("products").toArray(); + bool file1 = false; + bool file2 = false; + for (const QJsonValue v : products) { + const QJsonObject product = v.toObject(); + const QString productName = product.value("full-display-name").toString(); + const QJsonArray groups = product.value("groups").toArray(); + for (const QJsonValue &v : groups) { + const QJsonObject group = v.toObject(); + const QString groupName = group.value("name").toString(); + const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray(); + for (const QJsonValue &v : sourceArtifacts) { + const QString filePath = v.toObject().value("file-path").toString(); + if (filePath.endsWith("file1.cpp")) { + file1 = true; + } else if (filePath.endsWith("file2.cpp")) { + QCOMPARE(productName, QString("theLib")); + QCOMPARE(groupName, QString("sources")); + file2 = true; + } + } } } + QVERIFY(!file1); + QVERIFY(file2); } } - QVERIFY(!file1); - QVERIFY(file2); + QVERIFY(receivedReply); + receivedReply = false; receivedProcessResult = false; compiledFile1 = false; @@ -6388,6 +7661,9 @@ void TestBlackbox::assembly() void TestBlackbox::autotestWithDependencies() { QDir::setCurrent(testDataDir + "/autotest-with-dependencies"); + QCOMPARE(runQbs({"resolve"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(QStringList({"-p", "autotest-runner"})), 0); QVERIFY2(m_qbsStdout.contains("i am the test app") && m_qbsStdout.contains("i am the helper"), m_qbsStdout.constData()); @@ -6397,14 +7673,19 @@ void TestBlackbox::autotestTimeout() { QFETCH(QStringList, resolveParams); QFETCH(bool, expectFailure); + QFETCH(QString, errorDetails); QDir::setCurrent(testDataDir + "/autotest-timeout"); QbsRunParameters resolveParameters("resolve", resolveParams); QCOMPARE(runQbs(resolveParameters), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters buildParameters(QStringList({"-p", "autotest-runner"})); buildParameters.expectFailure = expectFailure; if (expectFailure) { QVERIFY(runQbs(buildParameters) != 0); - QVERIFY(m_qbsStderr.contains("cancelled") && m_qbsStderr.contains("timeout")); + QVERIFY( + m_qbsStderr.contains("cancelled") && m_qbsStderr.contains("timeout") + && m_qbsStderr.contains(errorDetails.toLocal8Bit())); } else QVERIFY(runQbs(buildParameters) == 0); @@ -6414,11 +7695,12 @@ void TestBlackbox::autotestTimeout_data() { QTest::addColumn<QStringList>("resolveParams"); QTest::addColumn<bool>("expectFailure"); - QTest::newRow("no timeout") << QStringList() << false; - QTest::newRow("timeout on test") << QStringList({"products.testApp.autotest.timeout:2"}) - << true; - QTest::newRow("timeout on runner") << QStringList({"products.autotest-runner.timeout:2"}) - << true; + QTest::addColumn<QString>("errorDetails"); + QTest::newRow("no timeout") << QStringList() << false << QString(); + QTest::newRow("timeout on test") + << QStringList({"products.testApp.autotest.timeout:2"}) << true << QString("testApp"); + QTest::newRow("timeout on runner") + << QStringList({"products.autotest-runner.timeout:2"}) << true << QString("testApp"); } void TestBlackbox::autotests_data() @@ -6444,6 +7726,8 @@ void TestBlackbox::autotests() if (!evilPropertySpec.isEmpty()) resolveParams.arguments << evilPropertySpec; QCOMPARE(runQbs(resolveParams), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters testParams(QStringList{"-p", "autotest-runner"}); if (!evilPropertySpec.isEmpty()) testParams.expectFailure = true; @@ -6452,9 +7736,9 @@ void TestBlackbox::autotests() QVERIFY2(m_qbsStderr.contains(expectedErrorMessage), m_qbsStderr.constData()); return; } - QVERIFY2(m_qbsStdout.contains("Running test test1") - && m_qbsStdout.contains("Running test test2") - && m_qbsStdout.contains("Running test test3"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running test test1") + && m_qbsStdout.contains("running test test2") + && m_qbsStdout.contains("running test test3"), m_qbsStdout.constData()); QCOMPARE(m_qbsStdout.count("PASS"), 2); QCOMPARE(m_qbsStderr.count("FAIL"), 1); } @@ -6543,9 +7827,9 @@ static bool haveMakeNsis() << QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS"); QStringList paths = QProcessEnvironment::systemEnvironment().value("PATH") - .split(HostOsInfo::pathListSeparator(), QString::SkipEmptyParts); + .split(HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts); - for (const QString &key : qAsConst(regKeys)) { + for (const QString &key : std::as_const(regKeys)) { QSettings settings(key, QSettings::NativeFormat); QString str = settings.value(QStringLiteral(".")).toString(); if (!str.isEmpty()) @@ -6553,7 +7837,7 @@ static bool haveMakeNsis() } bool haveMakeNsis = false; - for (const QString &path : qAsConst(paths)) { + for (const QString &path : std::as_const(paths)) { if (regularFileExists(QDir::fromNativeSeparators(path) + HostOsInfo::appendExecutableSuffix(QStringLiteral("/makensis")))) { haveMakeNsis = true; @@ -6678,12 +7962,16 @@ void TestBlackbox::enableRtti() void TestBlackbox::envMerging() { QDir::setCurrent(testDataDir + "/env-merging"); - QbsRunParameters params; + QbsRunParameters params("resolve"); QString pathVal = params.environment.value("PATH"); pathVal.prepend(HostOsInfo::pathListSeparator()).prepend("/opt/blackbox/bin"); const QString keyName = HostOsInfo::isWindowsHost() ? "pATh" : "PATH"; params.environment.insert(keyName, pathVal); QCOMPARE(runQbs(params), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); + params.command = "build"; + QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains(QByteArray("PATH=/opt/tool/bin") + HostOsInfo::pathListSeparator().toLatin1()) && m_qbsStdout.contains(HostOsInfo::pathListSeparator().toLatin1() @@ -6774,98 +8062,10 @@ void TestBlackbox::generator_data() QTest::newRow("no update") << QString() << QStringList(); } -static bool haveWiX(const Profile &profile) -{ - if (profile.value("wix.toolchainInstallPath").isValid() && - profile.value("wix.toolchainInstallRoot").isValid()) { - return true; - } - - QStringList regKeys; - regKeys << QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows Installer XML\\") - << QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Installer XML\\"); - - QStringList paths = QProcessEnvironment::systemEnvironment().value("PATH") - .split(HostOsInfo::pathListSeparator(), QString::SkipEmptyParts); - - for (const QString &key : qAsConst(regKeys)) { - const QStringList versions = QSettings(key, QSettings::NativeFormat).childGroups(); - for (const QString &version : versions) { - QSettings settings(key + version, QSettings::NativeFormat); - QString str = settings.value(QStringLiteral("InstallRoot")).toString(); - if (!str.isEmpty()) - paths.prepend(str); - } - } - - for (const QString &path : qAsConst(paths)) { - if (regularFileExists(QDir::fromNativeSeparators(path) + - HostOsInfo::appendExecutableSuffix(QStringLiteral("/candle"))) && - regularFileExists(QDir::fromNativeSeparators(path) + - HostOsInfo::appendExecutableSuffix(QStringLiteral("/light")))) { - return true; - } - } - - return false; -} - -void TestBlackbox::wix() -{ - const SettingsPtr s = settings(); - Profile profile(profileName(), s.get()); - - if (!haveWiX(profile)) { - QSKIP("WiX is not installed"); - return; - } - - QByteArray arch = profile.value("qbs.architecture").toString().toLatin1(); - if (arch.isEmpty()) - arch = QByteArrayLiteral("x86"); - - QDir::setCurrent(testDataDir + "/wix"); - QCOMPARE(runQbs(), 0); - QVERIFY2(m_qbsStdout.contains("compiling QbsSetup.wxs"), m_qbsStdout); - QVERIFY2(m_qbsStdout.contains("linking qbs.msi"), m_qbsStdout); - QVERIFY(regularFileExists(relativeProductBuildDir("QbsSetup") + "/qbs.msi")); - - if (HostOsInfo::isWindowsHost()) { - QVERIFY2(m_qbsStdout.contains("compiling QbsBootstrapper.wxs"), m_qbsStdout); - QVERIFY2(m_qbsStdout.contains("linking qbs-setup-" + arch + ".exe"), m_qbsStdout); - QVERIFY(regularFileExists(relativeProductBuildDir("QbsBootstrapper") - + "/qbs-setup-" + arch + ".exe")); - } -} - -void TestBlackbox::wixDependencies() -{ - const SettingsPtr s = settings(); - Profile profile(profileName(), s.get()); - - if (!haveWiX(profile)) { - QSKIP("WiX is not installed"); - return; - } - - QByteArray arch = profile.value("qbs.architecture").toString().toLatin1(); - if (arch.isEmpty()) - arch = QByteArrayLiteral("x86"); - - QDir::setCurrent(testDataDir + "/wixDependencies"); - QbsRunParameters params; - if (!HostOsInfo::isWindowsHost()) - params.arguments << "qbs.targetOS:windows"; - QCOMPARE(runQbs(params), 0); - QVERIFY2(m_qbsStdout.contains("compiling QbsSetup.wxs"), m_qbsStdout); - QVERIFY2(m_qbsStdout.contains("linking qbs.msi"), m_qbsStdout); - QVERIFY(regularFileExists(relativeBuildDir() + "/qbs.msi")); -} - void TestBlackbox::nodejs() { const SettingsPtr s = settings(); - Profile p(profileName(), s.get()); + qbs::Profile p(profileName(), s.get()); int status; findNodejs(&status); @@ -6884,6 +8084,13 @@ void TestBlackbox::nodejs() QSKIP("nodejs.packageManagerFilePath not set and automatic detection failed"); } + if (p.value("nodejs.interpreterFilePath").toString().isEmpty() + && status != 0 && m_qbsStderr.contains("interpreterPath")) { + QSKIP("nodejs.interpreterFilePath not set and automatic detection failed"); + } + + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(status, 0); QbsRunParameters params; @@ -6895,8 +8102,11 @@ void TestBlackbox::nodejs() void TestBlackbox::typescript() { + if (qEnvironmentVariableIsSet("GITHUB_ACTIONS")) + QSKIP("Skip this test when running on GitHub"); + const SettingsPtr s = settings(); - Profile p(profileName(), s.get()); + qbs::Profile p(profileName(), s.get()); int status; findTypeScript(&status); @@ -6930,6 +8140,12 @@ void TestBlackbox::typescript() QVERIFY(regularFileExists(relativeProductBuildDir("animals") + "/main.js")); } +void TestBlackbox::undefinedTargetPlatform() +{ + QDir::setCurrent(testDataDir + "/undefined-target-platform"); + QCOMPARE(runQbs(), 0); +} + void TestBlackbox::importInPropertiesCondition() { QDir::setCurrent(testDataDir + "/import-in-properties-condition"); @@ -6959,77 +8175,15 @@ void TestBlackbox::importsConflict() void TestBlackbox::includeLookup() { QDir::setCurrent(testDataDir + "/includeLookup"); + QCOMPARE(runQbs({"resolve"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params; params.command = "run"; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("definition.."), m_qbsStdout.constData()); } -static bool haveInnoSetup(const Profile &profile) -{ - if (profile.value("innosetup.toolchainInstallPath").isValid()) - return true; - - QStringList regKeys; - regKeys << QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Inno Setup 5_is1") - << QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Inno Setup 5_is1"); - - QStringList paths = QProcessEnvironment::systemEnvironment().value("PATH") - .split(HostOsInfo::pathListSeparator(), QString::SkipEmptyParts); - - for (const QString &key : qAsConst(regKeys)) { - QSettings settings(key, QSettings::NativeFormat); - QString str = settings.value(QStringLiteral("InstallLocation")).toString(); - if (!str.isEmpty()) - paths.prepend(str); - } - - for (const QString &path : qAsConst(paths)) { - if (regularFileExists(QDir::fromNativeSeparators(path) + - HostOsInfo::appendExecutableSuffix(QStringLiteral("/ISCC")))) - return true; - } - - return false; -} - -void TestBlackbox::innoSetup() -{ - const SettingsPtr s = settings(); - Profile profile(profileName(), s.get()); - - if (!haveInnoSetup(profile)) { - QSKIP("Inno Setup is not installed"); - return; - } - - QDir::setCurrent(testDataDir + "/innosetup"); - QCOMPARE(runQbs(), 0); - QVERIFY(m_qbsStdout.contains("compiling test.iss")); - QVERIFY(m_qbsStdout.contains("compiling Example1.iss")); - QVERIFY(regularFileExists(relativeProductBuildDir("QbsSetup") + "/qbs.setup.test.exe")); - QVERIFY(regularFileExists(relativeProductBuildDir("Example1") + "/Example1.exe")); -} - -void TestBlackbox::innoSetupDependencies() -{ - const SettingsPtr s = settings(); - Profile profile(profileName(), s.get()); - - if (!haveInnoSetup(profile)) { - QSKIP("Inno Setup is not installed"); - return; - } - - QDir::setCurrent(testDataDir + "/innosetupDependencies"); - QbsRunParameters params; - if (!HostOsInfo::isWindowsHost()) - params.arguments << "qbs.targetOS:windows"; - QCOMPARE(runQbs(params), 0); - QVERIFY(m_qbsStdout.contains("compiling test.iss")); - QVERIFY(regularFileExists(relativeBuildDir() + "/qbs.setup.test.exe")); -} - void TestBlackbox::inputTagsChangeTracking_data() { QTest::addColumn<QString>("generateInput"); @@ -7091,7 +8245,7 @@ void TestBlackbox::wildCardsAndRules() { QDir::setCurrent(testDataDir + "/wildcards-and-rules"); QCOMPARE(runQbs(), 0); - QVERIFY(m_qbsStdout.contains("Creating output artifact")); + QVERIFY(m_qbsStdout.contains("creating output artifact")); QFile output(relativeProductBuildDir("wildcards-and-rules") + "/test.mytype"); QVERIFY2(output.open(QIODevice::ReadOnly), qPrintable(output.errorString())); QCOMPARE(output.readAll().count('\n'), 1); @@ -7103,7 +8257,7 @@ void TestBlackbox::wildCardsAndRules() QbsRunParameters params; params.expectFailure = true; QCOMPARE(runQbs(params), 0); - QVERIFY(m_qbsStdout.contains("Creating output artifact")); + QVERIFY(m_qbsStdout.contains("creating output artifact")); QVERIFY2(output.open(QIODevice::ReadOnly), qPrintable(output.errorString())); QCOMPARE(output.readAll().count('\n'), 2); output.close(); @@ -7112,17 +8266,49 @@ void TestBlackbox::wildCardsAndRules() WAIT_FOR_NEW_TIMESTAMP(); touch("dep.dep"); QCOMPARE(runQbs(), 0); - QVERIFY(m_qbsStdout.contains("Creating output artifact")); + QVERIFY(m_qbsStdout.contains("creating output artifact")); // Add nothing. QCOMPARE(runQbs(), 0); - QVERIFY(!m_qbsStdout.contains("Creating output artifact")); + QVERIFY(!m_qbsStdout.contains("creating output artifact")); +} + +void TestBlackbox::wildCardsAndChangeTracking_data() +{ + QTest::addColumn<QString>("dirToModify"); + QTest::addColumn<bool>("expectReResolve"); + + QTest::newRow("root path") << QString(".") << false; + QTest::newRow("dir with recursive match") << QString("recursive1") << false; + QTest::newRow("non-recursive base dir") << QString("nonrecursive") << true; + QTest::newRow("empty base dir with file patterns") << QString("nonrecursive/empty") << true; +} + +void TestBlackbox::wildCardsAndChangeTracking() +{ + QFETCH(QString, dirToModify); + QFETCH(bool, expectReResolve); + + const QString srcDir = testDataDir + "/wildcards-and-change-tracking"; + QDir::setCurrent(srcDir); + rmDirR("default"); + QDir::current().mkdir("nonrecursive/empty"); + + QCOMPARE(runQbs({"resolve"}), 0); + QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + WAIT_FOR_NEW_TIMESTAMP(); + touch(dirToModify + "/blubb.txt"); + QCOMPARE(runQbs({"resolve"}), 0); + QCOMPARE(m_qbsStdout.contains("Resolving"), expectReResolve); } void TestBlackbox::loadableModule() { QDir::setCurrent(testDataDir + QLatin1String("/loadablemodule")); + QCOMPARE(runQbs({"resolve"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params; params.command = "run"; QCOMPARE(runQbs(params), 0); @@ -7136,6 +8322,10 @@ void TestBlackbox::localDeployment() QVERIFY(main.open(QIODevice::ReadOnly)); QByteArray content = main.readAll(); content.replace('\r', ""); + QCOMPARE(runQbs({"resolve"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); + QbsRunParameters params; params.command = "run"; QCOMPARE(runQbs(params), 0); @@ -7149,6 +8339,8 @@ void TestBlackbox::makefileGenerator() QCOMPARE(runQbs(params), 0); if (HostOsInfo::isWindowsHost()) return; + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QProcess make; make.setWorkingDirectory(QDir::currentPath() + '/' + relativeBuildDir()); const QString customInstallRoot = QDir::currentPath() + "/my-install-root"; @@ -7157,7 +8349,7 @@ void TestBlackbox::makefileGenerator() QVERIFY(QFile::exists(relativeExecutableFilePath("the app"))); QVERIFY(!QFile::exists(relativeBuildGraphFilePath())); QProcess app; - app.start('"' + customInstallRoot + "/usr/local/bin/the app\""); + app.start(customInstallRoot + "/usr/local/bin/the app", QStringList()); QVERIFY(waitForProcessSuccess(app)); const QByteArray appStdout = app.readAllStandardOutput(); QVERIFY2(appStdout.contains("Hello, World!"), appStdout.constData()); @@ -7171,14 +8363,18 @@ void TestBlackbox::maximumCLanguageVersion() QDir::setCurrent(testDataDir + "/maximum-c-language-version"); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("products.app.enableNewestModule:true"))), 0); - if (m_qbsStdout.contains("is msvc")) - QSKIP("MSVC has no support for setting the C language version."); + const bool isMsvc = m_qbsStdout.contains("is msvc: true"); + if (isMsvc && m_qbsStdout.contains("is old msvc: true")) + QSKIP("MSVC supports setting the C language version only from version 16.8, and Clang from version 13."); QCOMPARE(runQbs(QStringList({"--command-echo-mode", "command-line", "-n"})), 0); QVERIFY2(m_qbsStdout.contains("c11") || m_qbsStdout.contains("c1x"), m_qbsStdout.constData()); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("products.app.enableNewestModule:false"))), 0); QCOMPARE(runQbs(QStringList({"--command-echo-mode", "command-line", "-n"})), 0); - QVERIFY2(m_qbsStdout.contains("c99"), m_qbsStdout.constData()); + if (isMsvc) + QVERIFY2(!m_qbsStdout.contains("c11"), m_qbsStdout.constData()); + else + QVERIFY2(m_qbsStdout.contains("c99"), m_qbsStdout.constData()); } void TestBlackbox::maximumCxxLanguageVersion() @@ -7187,7 +8383,7 @@ void TestBlackbox::maximumCxxLanguageVersion() QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("products.app.enableNewestModule:true"))), 0); QCOMPARE(runQbs(QStringList({"--command-echo-mode", "command-line", "-n"})), 0); - QVERIFY2(m_qbsStdout.contains("c++17") || m_qbsStdout.contains("c++1z") + QVERIFY2(m_qbsStdout.contains("c++23") || m_qbsStdout.contains("c++2b") || m_qbsStdout.contains("c++latest"), m_qbsStdout.constData()); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("products.app.enableNewestModule:false"))), 0); @@ -7196,107 +8392,6 @@ void TestBlackbox::maximumCxxLanguageVersion() m_qbsStdout.constData()); } -void TestBlackbox::moduleProviders() -{ - QDir::setCurrent(testDataDir + "/module-providers"); - - // Resolving in dry-run mode must not leave any data behind. - QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); - QCOMPARE(m_qbsStdout.count("Running setup script for mygenerator"), 2); - QVERIFY(!QFile::exists(relativeBuildDir())); - - // Initial build. - QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app1"})), 0); - QVERIFY(QFile::exists(relativeBuildDir())); - QCOMPARE(m_qbsStdout.count("Running setup script for mygenerator"), 2); - QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); - QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app2"})), 0); - QVERIFY2(m_qbsStdout.contains("The letters are Z and Y"), m_qbsStdout.constData()); - - // Rebuild with overridden module provider config. The output for product 2 must change, - // but no setup script must be re-run, because both config values have already been - // handled in the first run. - const QStringList resolveArgs("moduleProviders.mygenerator.chooseLettersFrom:beginning"); - QCOMPARE(runQbs(QbsRunParameters("resolve", resolveArgs)), 0); - QVERIFY2(!m_qbsStdout.contains("Running setup script"), m_qbsStdout.constData()); - QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app1"})), 0); - QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); - QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app2"})), 0); - QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); - - // Forcing Probe execution triggers a re-run of the setup script. But only once, - // because the module provider config is the same now. - QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList(resolveArgs) - << "--force-probe-execution")), 0); - QCOMPARE(m_qbsStdout.count("Running setup script for mygenerator"), 1); - QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app1"})), 0); - QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); - QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app2"})), 0); - QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); - - // Now re-run without the module provider config override. Again, the setup script must - // run once, for the config value that was not present in the last run. - QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); - QCOMPARE(m_qbsStdout.count("Running setup script for mygenerator"), 1); - QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app1"})), 0); - QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); - QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app2"})), 0); - QVERIFY2(m_qbsStdout.contains("The letters are Z and Y"), m_qbsStdout.constData()); -} - -void TestBlackbox::fallbackModuleProvider_data() -{ - QTest::addColumn<bool>("fallbacksEnabledGlobally"); - QTest::addColumn<bool>("fallbacksEnabledInProduct"); - QTest::addColumn<QStringList>("pkgConfigLibDirs"); - QTest::addColumn<bool>("successExpected"); - QTest::newRow("without custom lib dir, fallbacks disabled globally and in product") - << false << false << QStringList() << false; - QTest::newRow("without custom lib dir, fallbacks disabled globally, enabled in product") - << false << true << QStringList() << false; - QTest::newRow("without custom lib dir, fallbacks enabled globally, disabled in product") - << true << false << QStringList() << false; - QTest::newRow("without custom lib dir, fallbacks enabled globally and in product") - << true << true << QStringList() << false; - QTest::newRow("with custom lib dir, fallbacks disabled globally and in product") - << false << false << QStringList(testDataDir + "/fallback-module-provider/libdir") - << false; - QTest::newRow("with custom lib dir, fallbacks disabled globally, enabled in product") - << false << true << QStringList(testDataDir + "/fallback-module-provider/libdir") - << false; - QTest::newRow("with custom lib dir, fallbacks enabled globally, disabled in product") - << true << false << QStringList(testDataDir + "/fallback-module-provider/libdir") - << false; - QTest::newRow("with custom lib dir, fallbacks enabled globally and in product") - << true << true << QStringList(testDataDir + "/fallback-module-provider/libdir") - << true; -} - -void TestBlackbox::fallbackModuleProvider() -{ - QFETCH(bool, fallbacksEnabledInProduct); - QFETCH(bool, fallbacksEnabledGlobally); - QFETCH(QStringList, pkgConfigLibDirs); - QFETCH(bool, successExpected); - QDir::setCurrent(testDataDir + "/fallback-module-provider"); - static const auto b2s = [](bool b) { return QString(b ? "true" : "false"); }; - QbsRunParameters resolveParams("resolve", - QStringList{"modules.pkgconfig.libDirs:" + pkgConfigLibDirs.join(','), - "products.p.fallbacksEnabled:" + b2s(fallbacksEnabledInProduct), - "--force-probe-execution"}); - if (!fallbacksEnabledGlobally) - resolveParams.arguments << "--no-fallback-module-provider"; - QCOMPARE(runQbs(resolveParams), 0); - const bool pkgConfigPresent = m_qbsStdout.contains("pkg-config present: true"); - const bool pkgConfigNotPresent = m_qbsStdout.contains("pkg-config present: false"); - QVERIFY(pkgConfigPresent != pkgConfigNotPresent); - if (pkgConfigNotPresent) - successExpected = false; - QbsRunParameters buildParams; - buildParams.expectFailure = !successExpected; - QCOMPARE(runQbs(buildParams) == 0, successExpected); -} - void TestBlackbox::minimumSystemVersion() { rmDirR(relativeBuildDir()); @@ -7304,6 +8399,10 @@ void TestBlackbox::minimumSystemVersion() QFETCH(QString, file); QFETCH(QString, output); QbsRunParameters params({ "-f", file + ".qbs" }); + params.command = "resolve"; + QCOMPARE(runQbs(params), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); params.command = "run"; QCOMPARE(runQbs(params), 0); if (m_qbsStdout.contains("Unsupported compiler")) @@ -7385,7 +8484,7 @@ void TestBlackbox::minimumSystemVersion_data() return "__MAC_OS_X_VERSION_MIN_REQUIRED=1070\nversion 10.7\n"; if (HostOsInfo::isWindowsHost()) - return "WINVER=1536\n6.00 operating system version\n6.00 subsystem version\n"; + return "WINVER=1538\n6.02 operating system version\n6.02 subsystem version\n"; return ""; }(); @@ -7413,7 +8512,7 @@ void TestBlackbox::missingBuildGraph() QbsRunParameters params; params.expectFailure = true; params.arguments << QLatin1String("config:") + actualConfigName; - for (const QString &command : qAsConst(commands)) { + for (const QString &command : std::as_const(commands)) { params.command = command; QVERIFY2(runQbs(params) != 0, qPrintable(command)); const QString expectedErrorMessage = QString("Build graph not found for " @@ -7523,6 +8622,12 @@ void TestBlackbox::movedFileDependency() QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); } +void TestBlackbox::msvcAsmLinkerFlags() +{ + QDir::setCurrent(testDataDir + "/msvc-asm-flags"); + QCOMPARE(runQbs(), 0); +} + void TestBlackbox::badInterpreter() { if (!HostOsInfo::isAnyUnixHost()) @@ -7531,16 +8636,19 @@ void TestBlackbox::badInterpreter() QDir::setCurrent(testDataDir + QLatin1String("/badInterpreter")); QCOMPARE(runQbs(), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); + QbsRunParameters params("run"); params.expectFailure = true; - const QRegExp reNoSuchFileOrDir("bad interpreter:.* No such file or directory"); - const QRegExp rePermissionDenied("bad interpreter:.* Permission denied"); + const QRegularExpression reNoSuchFileOrDir("bad interpreter:.* No such file or directory"); + const QRegularExpression rePermissionDenied("bad interpreter:.* Permission denied"); params.arguments = QStringList() << "-p" << "script-interp-missing"; QCOMPARE(runQbs(params), 1); QString strerr = QString::fromLocal8Bit(m_qbsStderr); - QVERIFY(strerr.contains(reNoSuchFileOrDir)); + QVERIFY2(strerr.contains(reNoSuchFileOrDir), m_qbsStderr); params.arguments = QStringList() << "-p" << "script-interp-noexec"; QCOMPARE(runQbs(params), 1); @@ -7609,6 +8717,16 @@ void TestBlackbox::qbsVersion() QVERIFY(runQbs(params) != 0); } +void TestBlackbox::transitiveInvalidDependencies() +{ + QDir::setCurrent(testDataDir + "/transitive-invalid-dependencies"); + QbsRunParameters params; + QCOMPARE(runQbs(params), 0); + QVERIFY2(m_qbsStdout.contains("b.present = false"), m_qbsStdout); + QVERIFY2(m_qbsStdout.contains("c.present = true"), m_qbsStdout); + QVERIFY2(m_qbsStdout.contains("d.present = false"), m_qbsStdout); +} + void TestBlackbox::transitiveOptionalDependencies() { QDir::setCurrent(testDataDir + "/transitive-optional-dependencies"); @@ -7619,19 +8737,23 @@ void TestBlackbox::transitiveOptionalDependencies() void TestBlackbox::groupsInModules() { QDir::setCurrent(testDataDir + "/groups-in-modules"); + QCOMPARE(runQbs({"resolve"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params; QCOMPARE(runQbs(params), 0); - QVERIFY(m_qbsStdout.contains("compile rock.coal => rock.diamond")); - QVERIFY(m_qbsStdout.contains("compile chunk.coal => chunk.diamond")); + QVERIFY(m_qbsStdout.contains("compiling rock.coal to rock.diamond")); + QVERIFY(m_qbsStdout.contains("compiling chunk.coal to chunk.diamond")); QVERIFY(m_qbsStdout.contains("compiling helper2.c")); QVERIFY(!m_qbsStdout.contains("compiling helper3.c")); QVERIFY(m_qbsStdout.contains("compiling helper4.c")); QVERIFY(m_qbsStdout.contains("compiling helper5.c")); QVERIFY(!m_qbsStdout.contains("compiling helper6.c")); + QVERIFY(m_qbsStdout.contains("compiling helper7.c")); QCOMPARE(runQbs(params), 0); - QVERIFY(!m_qbsStdout.contains("compile rock.coal => rock.diamond")); - QVERIFY(!m_qbsStdout.contains("compile chunk.coal => chunk.diamond")); + QVERIFY(!m_qbsStdout.contains("compiling rock.coal to rock.diamond")); + QVERIFY(!m_qbsStdout.contains("compiling chunk.coal to chunk.diamond")); WAIT_FOR_NEW_TIMESTAMP(); touch("modules/helper/diamondc.c"); @@ -7639,8 +8761,8 @@ void TestBlackbox::groupsInModules() waitForFileUnlock(); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("compiling diamondc.c")); - QVERIFY(m_qbsStdout.contains("compile rock.coal => rock.diamond")); - QVERIFY(m_qbsStdout.contains("compile chunk.coal => chunk.diamond")); + QVERIFY(m_qbsStdout.contains("compiling rock.coal to rock.diamond")); + QVERIFY(m_qbsStdout.contains("compiling chunk.coal to chunk.diamond")); QVERIFY(regularFileExists(relativeProductBuildDir("groups-in-modules") + "/rock.diamond")); QFile output(relativeProductBuildDir("groups-in-modules") + "/rock.diamond"); QVERIFY(output.open(QIODevice::ReadOnly)); @@ -7650,15 +8772,36 @@ void TestBlackbox::groupsInModules() void TestBlackbox::grpc_data() { QTest::addColumn<QString>("projectFile"); - QTest::newRow("cpp") << QString("grpc_cpp.qbs"); + QTest::addColumn<QStringList>("arguments"); + QTest::addColumn<bool>("hasModules"); + + QStringList pkgConfigArgs({"project.qbsModuleProviders:qbspkgconfig"}); + // on macOS, openSSL is hidden from pkg-config by default + if (qbs::Internal::HostOsInfo::isMacosHost()) { + pkgConfigArgs + << "moduleProviders.qbspkgconfig.extraPaths:/usr/local/opt/openssl@1.1/lib/pkgconfig"; + } + QTest::newRow("cpp-pkgconfig") << QString("grpc_cpp.qbs") << pkgConfigArgs << true; + QStringList conanArgs( + {"project.qbsModuleProviders:conan", "moduleProviders.conan.installDirectory:build"}); + QTest::newRow("cpp-conan") << QString("grpc_cpp.qbs") << conanArgs << true; } void TestBlackbox::grpc() { QDir::setCurrent(testDataDir + "/grpc"); QFETCH(QString, projectFile); + QFETCH(QStringList, arguments); + QFETCH(bool, hasModules); + rmDirR(relativeBuildDir()); + if (QTest::currentDataTag() == QLatin1String("cpp-conan")) { + if (!prepareAndRunConan()) + QSKIP("conan is not prepared, check messages above"); + } + QbsRunParameters resolveParams("resolve", QStringList{"-f", projectFile}); + resolveParams.arguments << arguments; QCOMPARE(runQbs(resolveParams), 0); const bool withGrpc = m_qbsStdout.contains("has grpc: true"); const bool withoutGrpc = m_qbsStdout.contains("has grpc: false"); @@ -7666,10 +8809,33 @@ void TestBlackbox::grpc() if (withoutGrpc) QSKIP("grpc module not present"); + const bool hasMods = m_qbsStdout.contains("has modules: true"); + const bool dontHaveMods = m_qbsStdout.contains("has modules: false"); + QVERIFY2(hasMods == !dontHaveMods, m_qbsStdout.constData()); + QCOMPARE(hasMods, hasModules); + + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); + QbsRunParameters runParams; QCOMPARE(runQbs(runParams), 0); } +void TestBlackbox::hostOsProperties() +{ + QDir::setCurrent(testDataDir + "/host-os-properties"); + QCOMPARE(runQbs(QStringLiteral("resolve")), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); + QCOMPARE(runQbs(QStringLiteral("run")), 0); + QVERIFY2(m_qbsStdout.contains( + ("HOST_ARCHITECTURE = " + HostOsInfo::hostOSArchitecture().toUtf8()).data()), + m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains( + ("HOST_PLATFORM = " + HostOsInfo::hostOSIdentifier().toUtf8()).data()), + m_qbsStdout.constData()); +} + void TestBlackbox::ico() { QDir::setCurrent(testDataDir + "/ico"); @@ -7747,8 +8913,8 @@ void TestBlackbox::ico() QCOMPARE(b.at(12), '\0'); QCOMPARE(b.at(26), '\0'); QCOMPARE(b.at(28), '\0'); - QWARN("this version of icoutil does not support setting the hotspot " - "for cursor files with multiple images"); + qWarning() << "this version of icoutil does not support setting the hotspot " + "for cursor files with multiple images"; } else { QCOMPARE(b.at(10), '\x8'); QCOMPARE(b.at(12), '\x9'); diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h index 4e2755724..3f817b481 100644 --- a/tests/auto/blackbox/tst_blackbox.h +++ b/tests/auto/blackbox/tst_blackbox.h @@ -40,6 +40,8 @@ public: TestBlackbox(); private slots: + void allowedValues(); + void allowedValues_data(); void addFileTagToGeneratedArtifact(); void alwaysRun(); void alwaysRun_data(); @@ -58,8 +60,14 @@ private slots: void bomSources(); void buildDataOfDisabledProduct(); void buildDirectories(); + void buildDirPlaceholders_data(); + void buildDirPlaceholders(); void buildEnvChange(); void buildGraphVersions(); + void buildVariantDefaults_data(); + void buildVariantDefaults(); + void capnproto(); + void capnproto_data(); void changedFiles_data(); void changedFiles(); void changedInputsFromDependencies(); @@ -76,26 +84,33 @@ private slots: void combinedSources(); void commandFile(); void compilerDefinesByLanguage(); - void concurrentExecutor(); void conditionalExport(); void conditionalFileTagger(); void configure(); void conflictingArtifacts(); void cxxLanguageVersion(); void cxxLanguageVersion_data(); + void conanfileProbe_data(); + void conanfileProbe(); + void conflictingPropertyValues_data(); + void conflictingPropertyValues(); void cpuFeatures(); + void dateProperty(); void dependenciesProperty(); - void dependencyProfileMismatch(); + void dependencyScanningLoop(); void deprecatedProperty(); + void deprecatedProperty_data(); void disappearedProfile(); void discardUnusedData(); void discardUnusedData_data(); + void dotDotPcFile(); void driverLinkerFlags(); void driverLinkerFlags_data(); void dynamicLibraryInModule(); void dynamicMultiplexRule(); void dynamicProject(); void dynamicRuleOutputs(); + void emptyProfile(); void enableExceptions(); void enableExceptions_data(); void enableRtti(); @@ -113,11 +128,16 @@ private slots: void exportedPropertyInDisabledProduct_data(); void exportRule(); void exportToOutsideSearchPath(); + void exportsCMake(); + void exportsCMake_data(); void exportsPkgconfig(); void exportsQbs(); void externalLibs(); void fileDependencies(); void fileTagsFilterMerging(); + void flatbuf(); + void flatbuf_data(); + void freedesktop(); void generatedArtifactAsInputToDynamicRule(); void generateLinkerMapFile(); void generator(); @@ -125,6 +145,7 @@ private slots: void groupsInModules(); void grpc_data(); void grpc(); + void hostOsProperties(); void ico(); void importAssignment(); void importChangeTracking(); @@ -133,8 +154,6 @@ private slots: void importingProduct(); void importsConflict(); void includeLookup(); - void innoSetup(); - void innoSetupDependencies(); void inputTagsChangeTracking_data(); void inputTagsChangeTracking(); void inputsFromDependencies(); @@ -150,6 +169,8 @@ private slots: void installPackage(); void installRootFromProjectFile(); void installTree(); + void invalidArtifactPath_data(); + void invalidArtifactPath(); void invalidCommandProperty_data(); void invalidCommandProperty(); void invalidExtensionInstantiation(); @@ -159,11 +180,13 @@ private slots: void invalidLibraryNames_data(); void jsExtensionsFile(); void jsExtensionsFileInfo(); + void jsExtensionsHost(); void jsExtensionsProcess(); void jsExtensionsPropertyList(); void jsExtensionsTemporaryDir(); void jsExtensionsTextFile(); void jsExtensionsBinaryFile(); + void lastModuleCandidateBroken(); void ld(); void linkerMode(); void linkerVariant_data(); @@ -174,6 +197,7 @@ private slots: void linkerLibraryDuplicates(); void linkerLibraryDuplicates_data(); void linkerScripts(); + void linkerModuleDefinition(); void listProducts(); void listPropertiesWithOuter(); void listPropertyOrder(); @@ -182,9 +206,6 @@ private slots: void makefileGenerator(); void maximumCLanguageVersion(); void maximumCxxLanguageVersion(); - void moduleProviders(); - void fallbackModuleProvider_data(); - void fallbackModuleProvider(); void minimumSystemVersion(); void minimumSystemVersion_data(); void missingBuildGraph(); @@ -194,6 +215,7 @@ private slots: void missingOverridePrefix(); void moduleConditions(); void movedFileDependency(); + void msvcAsmLinkerFlags(); void multipleChanges(); void multipleConfigurations(); void multiplexedTool(); @@ -216,6 +238,7 @@ private slots: void overrideProjectProperties(); void pathProbe_data(); void pathProbe(); + void pathListInProbe(); void pchChangeTracking(); void perGroupDefineInExportItem(); void pkgConfigProbe(); @@ -232,17 +255,27 @@ private slots: void probesAndArrayProperties(); void probesInNestedModules(); void productDependenciesByType(); + void productInExportedModule(); void productProperties(); - void propertyAssignmentOnNonPresentModule(); void propertyAssignmentInFailedModule(); void propertyChanges(); + void propertyEvaluationContext(); void propertyPrecedence(); void properQuoting(); void propertiesInExportItems(); void protobuf_data(); void protobuf(); + void protobufLibraryInstall(); void pseudoMultiplexing(); void qbsConfig(); + void qbsConfigAddProfile(); + void qbsConfigAddProfile_data(); + void qbsConfigImport(); + void qbsConfigImport_data(); + void qbsConfigExport(); + void qbsConfigExport_data(); + void qbsLanguageServer_data(); + void qbsLanguageServer(); void qbsSession(); void qbsVersion(); void qtBug51237(); @@ -256,16 +289,21 @@ private slots: void reproducibleBuild(); void reproducibleBuild_data(); void require(); - void requireDeprecated(); void rescueTransformerData(); void responseFiles(); void retaggedOutputArtifact(); + void rpathlinkDeduplication(); void ruleConditions(); void ruleConnectionWithExcludedInputs(); void ruleCycle(); void ruleWithNoInputs(); void ruleWithNonRequiredInputs(); + void runMultiplexed(); + void sanitizer_data(); + void sanitizer(); void scannerItem(); + void scanResultInOtherProduct(); + void scanResultInNonDependency(); void setupBuildEnvironment(); void setupRunEnvironment(); void smartRelinking(); @@ -285,6 +323,7 @@ private slots: void suspiciousCalls(); void suspiciousCalls_data(); void systemIncludePaths(); + void distributionIncludePaths(); void systemRunPaths(); void systemRunPaths_data(); void tar(); @@ -299,8 +338,10 @@ private slots: void trackRemoveFile(); void trackRemoveFileTag(); void trackRemoveProduct(); + void transitiveInvalidDependencies(); void transitiveOptionalDependencies(); void typescript(); + void undefinedTargetPlatform(); void usingsAsSoleInputsNonMultiplexed(); void variantSuffix(); void variantSuffix_data(); @@ -312,9 +353,9 @@ private slots: void wholeArchive(); void wholeArchive_data(); void wildCardsAndRules(); + void wildCardsAndChangeTracking_data(); + void wildCardsAndChangeTracking(); void wildcardRenaming(); - void wix(); - void wixDependencies(); void zip(); void zip_data(); void zipInvalid(); @@ -324,6 +365,7 @@ private: QMap<QString, QString> findNodejs(int *status); QMap<QString, QString> findTypeScript(int *status); QString findArchiver(const QString &fileName, int *status = nullptr); + bool prepareAndRunConan(); static bool lexYaccExist(); static qbs::Version bisonVersion(); }; diff --git a/tests/auto/blackbox/tst_blackboxandroid.cpp b/tests/auto/blackbox/tst_blackboxandroid.cpp index e312c4493..a74d9415d 100644 --- a/tests/auto/blackbox/tst_blackboxandroid.cpp +++ b/tests/auto/blackbox/tst_blackboxandroid.cpp @@ -58,6 +58,7 @@ QMap<QString, QString> TestBlackboxAndroid::findAndroid(int *status, const QStri return { {"sdk", QDir::fromNativeSeparators(tools["sdk"].toString())}, {"sdk-build-tools-dx", QDir::fromNativeSeparators(tools["sdk-build-tools-dx"].toString())}, + {"sdk-build-tools-d8", QDir::fromNativeSeparators(tools["sdk-build-tools-d8"].toString())}, {"ndk", QDir::fromNativeSeparators(tools["ndk"].toString())}, {"ndk-samples", QDir::fromNativeSeparators(tools["ndk-samples"].toString())}, {"jar", QDir::fromNativeSeparators(tools["jar"].toString())}, @@ -80,11 +81,19 @@ void TestBlackboxAndroid::android() QFETCH(QStringList, productNames); QFETCH(QList<QByteArrayList>, expectedFilesLists); QFETCH(QStringList, customProperties); + QFETCH(bool, enableAapt2); + QFETCH(bool, generateAab); + QFETCH(bool, isIncrementalBuild); + QFETCH(bool, enableD8); + + // skip tests on github except when run in docker - this var is not propagated into the image + if (qEnvironmentVariableIsSet("GITHUB_ACTIONS")) + QSKIP("Skip Android tests when running on GitHub"); const SettingsPtr s = settings(); - Profile p(theProfileName(projectDir == "qml-app"), s.get()); + Profile p(theProfileName(projectDir == "qml-app" || projectDir == "qt-app"), s.get()); if (!p.exists()) - p = Profile("none", s.get()); + QSKIP("Qt is not installed"); int status; const auto androidPaths = findAndroid(&status, p.name()); QCOMPARE(status, 0); @@ -103,33 +112,39 @@ void TestBlackboxAndroid::android() && ndkSamplesDirs.contains(projectDir)) QSKIP("NDK samples directory not present"); + const QString buildSubDir = enableAapt2 ? (generateAab ? "aab" : "aapt2") : "aapt"; QDir::setCurrent(testDataDir + "/" + projectDir); + if (!isIncrementalBuild) + rmDirR(relativeBuildDir(buildSubDir)); static const QStringList configNames { "debug", "release" }; for (const QString &configName : configNames) { auto currentExpectedFilesLists = expectedFilesLists; const QString configArgument = "config:" + configName; QbsRunParameters resolveParams("resolve"); + resolveParams.buildDirectory = buildSubDir; resolveParams.arguments << configArgument << customProperties; resolveParams.profile = p.name(); QCOMPARE(runQbs(resolveParams), 0); QbsRunParameters buildParams(QStringList{"--command-echo-mode", "command-line", configArgument}); + buildParams.buildDirectory = buildSubDir; buildParams.profile = p.name(); QCOMPARE(runQbs(buildParams), 0); - for (const QString &productName : qAsConst(productNames)) { + for (const QString &productName : std::as_const(productNames)) { const QByteArray tag(QTest::currentDataTag()); - const bool isIncrementalBuild = tag.startsWith("qml app") && tag != "qml app"; - QCOMPARE(m_qbsStdout.count("Generating BuildConfig.java"), + QCOMPARE(m_qbsStdout.count("generating BuildConfig.java"), isIncrementalBuild ? 0 : productNames.size()); - QVERIFY(m_qbsStdout.contains(productName.toLocal8Bit() + ".apk")); - const QString apkFilePath = relativeProductBuildDir(productName, configName) - + '/' + productName + ".apk"; - QVERIFY2(regularFileExists(apkFilePath), qPrintable(apkFilePath)); + const QString packageName = productName + (generateAab ? ".aab" : ".apk"); + QVERIFY(m_qbsStdout.contains(packageName.toLocal8Bit())); + const QString packageFilePath = buildSubDir + "/" + relativeProductBuildDir(productName, + configName) + + '/' + packageName; + QVERIFY2(regularFileExists(packageFilePath), qPrintable(packageFilePath)); const QString jarFilePath = androidPaths["jar"]; QVERIFY(!jarFilePath.isEmpty()); QProcess jar; - jar.start(jarFilePath, QStringList() << "-tf" << apkFilePath); + jar.start(jarFilePath, QStringList() << "-tf" << packageFilePath); QVERIFY2(jar.waitForStarted(), qPrintable(jar.errorString())); QVERIFY2(jar.waitForFinished(), qPrintable(jar.errorString())); QVERIFY2(jar.exitCode() == 0, qPrintable(jar.readAllStandardError().constData())); @@ -159,8 +174,8 @@ void TestBlackboxAndroid::android() return f.contains("qmltooling"); }; if (none_of(actualFiles, isFileSharedObject) - || std::all_of(actualFiles.cbegin(), actualFiles.cend(), isQmlToolingLib)) { - QWARN(msg); + || qbs::Internal::all_of(actualFiles, isQmlToolingLib)) { + qWarning() << msg; } else { QFAIL(msg); } @@ -168,11 +183,12 @@ void TestBlackboxAndroid::android() } if (projectDir == "multiple-libs-per-apk") { - const auto dxPath = androidPaths["sdk-build-tools-dx"]; - QVERIFY(!dxPath.isEmpty()); + const auto dexCompilerPath = enableD8 ? androidPaths["sdk-build-tools-d8"] + : androidPaths["sdk-build-tools-dx"]; + QVERIFY(!dexCompilerPath.isEmpty()); const auto lines = m_qbsStdout.split('\n'); const auto it = std::find_if(lines.cbegin(), lines.cend(), [&](const QByteArray &line) { - return !line.isEmpty() && line.startsWith(dxPath.toUtf8()); + return !line.isEmpty() && line.startsWith(dexCompilerPath.toUtf8()); }); QVERIFY2(it != lines.cend(), qPrintable(m_qbsStdout.constData())); const auto line = *it; @@ -204,71 +220,102 @@ void TestBlackboxAndroid::android_data() const auto cxxLibPath = [&p, &pQt](const QByteArray &oldcxxLib, bool forQt) { const bool usesClang = (forQt ? pQt : p).value(QStringLiteral("qbs.toolchainType")) .toString() == "clang"; - return QByteArray("lib/${ARCH}/") + (usesClang ? "libc++_shared.so" : oldcxxLib); + const QByteArray path = "lib/${ARCH}/"; + return path + (usesClang ? QByteArrayLiteral("libc++_shared.so") : oldcxxLib); }; - const QByteArrayList archsForQt = { pQt.value("qbs.architecture").toString().toUtf8() }; - QByteArrayList ndkArchsForQt = archsForQt; - if (ndkArchsForQt.first() == "armv7a") - ndkArchsForQt.first() = "armeabi-v7a"; - else if (ndkArchsForQt.first() == "armv5te") - ndkArchsForQt.first() = "armeabi"; - else if (ndkArchsForQt.first() == "arm64") - ndkArchsForQt.first() = "arm64-v8a"; + qbs::Version version(5, 13); + QStringList qmakeFilePaths = pQt.value(QStringLiteral("moduleProviders.Qt.qmakeFilePaths")). + toStringList(); + if (qmakeFilePaths.size() >= 1) + version = TestBlackboxBase::qmakeVersion(qmakeFilePaths[0]); + bool singleArchQt = (version < qbs::Version(5, 14)); + QByteArray qtVersionMajor((version >= qbs::Version(6, 0)) ? "6" : "5"); + QByteArrayList archsForQt; + if (singleArchQt) { + archsForQt = { pQt.value("qbs.architecture").toString().toUtf8() }; + if (archsStringList.empty()) + archsStringList << QStringLiteral("armv7a"); // must match default in common.qbs + } else { + QStringList archsForQtStringList = pQt.value(QStringLiteral("qbs.architectures")) + .toStringList(); + if (archsForQtStringList.empty()) + archsForQtStringList << pQt.value("qbs.architecture").toString(); + std::transform(archsForQtStringList.begin(), + archsForQtStringList.end(), + std::back_inserter(archsForQt), + [] (const QString &s) { + return s.toUtf8(); + }); + } + + QByteArrayList ndkArchsForQt; + std::transform(archsForQt.begin(), archsForQt.end(), std::back_inserter(ndkArchsForQt), + [] (const QString &s) { + return s.toUtf8().replace("armv7a", "armeabi-v7a") + .replace("armv5te", "armeabi") + .replace("arm64", "arm64-v8a"); + }); - auto expandArchs = [] (const QByteArrayList &archs, const QByteArrayList &lst) { + auto expandArchs = [] (const QByteArrayList &archs, const QByteArrayList &lst, bool aabPackage) { const QByteArray &archPlaceHolder = "${ARCH}"; QByteArrayList result; + QByteArray base( aabPackage ? "base/" : ""); for (const QByteArray &entry : lst) { if (entry.contains(archPlaceHolder)) { - for (const QByteArray &arch : qAsConst(archs)) - result << QByteArray(entry).replace(archPlaceHolder, arch); + for (const QByteArray &arch : std::as_const(archs)) + result << (base + QByteArray(entry).replace(archPlaceHolder, arch)); } else { - result << entry; + result << (base + entry); } } return result; }; - const QByteArrayList commonFiles = expandArchs(archs, { - "AndroidManifest.xml", "META-INF/ANDROIDD.RSA", "META-INF/ANDROIDD.SF", - "META-INF/MANIFEST.MF", "classes.dex" - }); + auto commonFiles = [](bool generateAab, bool codeSign = true, + QString keyAlias="androiddebugkey") { + QByteArrayList files; + if (generateAab) + files << "base/manifest/AndroidManifest.xml" << "base/dex/classes.dex" + << "BundleConfig.pb"; + else + files << "AndroidManifest.xml" << "classes.dex"; + if (codeSign) + files << QByteArray("META-INF/" + keyAlias.toUpper().left(8).toUtf8() + ".RSA") + << QByteArray("META-INF/" + keyAlias.toUpper().left(8).toUtf8() + ".SF") + << "META-INF/MANIFEST.MF"; + return files; + }; QTest::addColumn<QString>("projectDir"); QTest::addColumn<QStringList>("productNames"); QTest::addColumn<QList<QByteArrayList>>("expectedFilesLists"); QTest::addColumn<QStringList>("customProperties"); - QTest::newRow("teapot") - << "teapot" << QStringList("TeapotNativeActivity") - << (QList<QByteArrayList>() << commonFiles + expandArchs(archs, { - "resources.arsc", - "assets/Shaders/ShaderPlain.fsh", - "assets/Shaders/VS_ShaderPlain.vsh", - "lib/${ARCH}/libgdbserver.so", - cxxLibPath("libgnustl_shared.so", false), - "lib/${ARCH}/libTeapotNativeActivity.so", - "res/layout/widgets.xml"})) - << QStringList(); - QTest::newRow("minimal-native") - << "minimal-native" << QStringList("minimalnative") - << (QList<QByteArrayList>() << commonFiles + expandArchs({archs.first()}, { - "lib/${ARCH}/libminimalnative.so", - cxxLibPath("libstlport_shared.so", false), - "lib/${ARCH}/libdependency.so"})) - << QStringList{"products.minimalnative.multiplexByQbsProperties:[]", - "modules.qbs.architecture:" + archsStringList.first()}; - QTest::newRow("qml app") - << "qml-app" << QStringList("qmlapp") - << (QList<QByteArrayList>() << commonFiles + expandArchs(ndkArchsForQt, { - "resources.arsc", - "assets/--Added-by-androiddeployqt--/qml/QtQuick.2/plugins.qmltypes", - "assets/--Added-by-androiddeployqt--/qml/QtQuick.2/qmldir", - "assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/plugins.qmltypes", - "assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/qmldir", - "assets/--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list", - "lib/${ARCH}/libgdbserver.so", + QTest::addColumn<bool>("enableAapt2"); + QTest::addColumn<bool>("generateAab"); + QTest::addColumn<bool>("isIncrementalBuild"); + QTest::addColumn<bool>("enableD8"); + + const auto aaptVersion = [](bool enableAapt2) { + return QString("modules.Android.sdk.aaptName:") + (enableAapt2 ? "aapt2" : "aapt"); + }; + bool enableAapt2 = false; + const auto packageType = [](bool generateAab) { + return QString("modules.Android.sdk.packageType:") + (generateAab ? "aab" : "apk"); + }; + bool generateAab = false; + bool isIncrementalBuild = false; + + const auto dexCompilerVersion = [](bool enableD8) { + return QString("modules.Android.sdk.dexCompilerName:") + (enableD8 ? "d8" : "dx"); + }; + bool enableD8 = true; + auto qtAppExpectedFiles = [&](bool generateAab, bool enableAapt2, bool codeSign = true, + QString keyAlias="androiddebugkey") { + QByteArrayList expectedFile; + if (singleArchQt) { + expectedFile << commonFiles(generateAab, codeSign, keyAlias) + expandArchs(ndkArchsForQt, { cxxLibPath("libgnustl_shared.so", true), - "lib/${ARCH}/libplugins_bearer_libqandroidbearer.so", + "assets/--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list", "lib/${ARCH}/libplugins_imageformats_libqgif.so", "lib/${ARCH}/libplugins_imageformats_libqicns.so", "lib/${ARCH}/libplugins_imageformats_libqico.so", @@ -278,139 +325,791 @@ void TestBlackboxAndroid::android_data() "lib/${ARCH}/libplugins_imageformats_libqwbmp.so", "lib/${ARCH}/libplugins_imageformats_libqwebp.so", "lib/${ARCH}/libplugins_platforms_android_libqtforandroid.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_debugger.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_inspector.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_local.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_messages.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_native.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_nativedebugger.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_profiler.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_preview.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_quickprofiler.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_server.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_tcp.so", - "lib/${ARCH}/libqml_QtQuick.2_libqtquick2plugin.so", - "lib/${ARCH}/libqml_QtQuick_Window.2_libwindowplugin.so", + "lib/${ARCH}/libplugins_styles_libqandroidstyle.so", "lib/${ARCH}/libQt5Core.so", "lib/${ARCH}/libQt5Gui.so", - "lib/${ARCH}/libQt5Network.so", - "lib/${ARCH}/libQt5Qml.so", - "lib/${ARCH}/libQt5QuickParticles.so", - "lib/${ARCH}/libQt5Quick.so", - "lib/${ARCH}/libqmlapp.so", - "res/layout/splash.xml"})) - << QStringList{"modules.Android.sdk.automaticSources:false", - "modules.qbs.architecture:" + archsForQt.first()}; - QTest::newRow("qml app using Ministro") - << "qml-app" << QStringList("qmlapp") - << (QList<QByteArrayList>() << commonFiles + expandArchs(ndkArchsForQt, { - "resources.arsc", - "assets/--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list", - "lib/${ARCH}/libgdbserver.so", + "lib/${ARCH}/libQt5Widgets.so", + "lib/${ARCH}/libqt-app.so"}, generateAab); + } else { + expectedFile << commonFiles(generateAab, codeSign, keyAlias) + expandArchs(ndkArchsForQt, { cxxLibPath("libgnustl_shared.so", true), - "lib/${ARCH}/libqmlapp.so", - "res/layout/splash.xml"})) - << QStringList{"modules.Qt.android_support.useMinistro:true", - "modules.Android.sdk.automaticSources:false"}; + "lib/${ARCH}/libplugins_imageformats_qgif_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qico_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qjpeg_${ARCH}.so", + "lib/${ARCH}/libplugins_platforms_qtforandroid_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "Core_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "Gui_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "Widgets_${ARCH}.so", + "lib/${ARCH}/libqt-app_${ARCH}.so"}, generateAab); + } + if (generateAab) + expectedFile << "base/resources.pb" << "base/native.pb"; + else + expectedFile << "resources.arsc"; + if (version >= qbs::Version(5, 14)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libplugins_styles_qandroidstyle_${ARCH}.so"}, generateAab); + if (version < qbs::Version(6, 0) && version >= qbs::Version(5, 14)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libplugins_imageformats_qicns_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qtga_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qtiff_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qwbmp_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qwebp_${ARCH}.so"}, generateAab); + if (version >= qbs::Version(6, 5)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libQt6Svg_${ARCH}.so", + "lib/${ARCH}/libplugins_iconengines_qsvgicon_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qsvg_${ARCH}.so"}, generateAab); + if (!enableAapt2 && version < qbs::Version(6, 0)) + expectedFile << "res/layout/splash.xml"; + return expectedFile; + }; + auto codeSignProperties = [&](bool codeSign, QString keyStorePath, QString keystorePassword, + QString keyPassword, QString keyAlias) { + if (!codeSign) + return QStringList{"modules.codesign.enableCodeSigning:false"}; + return QStringList{ + "modules.codesign.enableCodeSigning:true", + "modules.codesign.keystorePath:" + keyStorePath, + "modules.codesign.keystorePassword:" + keystorePassword, + "modules.codesign.keyPassword:" + keyPassword, + "modules.codesign.keyAlias:" + keyAlias, + }; + }; + bool codeSign = true; + QString keyStorePath(testDataDir + "/qt-app/test.keystore"); + QString keystorePassword("qbsKeystoreTest"); + QString keyPassword("qbsKeyTest"); + QString keyAlias("qbsTest"); + QTest::newRow("qt app") + << "qt-app" << QStringList("qt-app") + << (QList<QByteArrayList>() << (QByteArrayList() << qtAppExpectedFiles(generateAab, + enableAapt2, + codeSign, + keyAlias))) + << (QStringList() << codeSignProperties(codeSign, keyStorePath, keystorePassword, + keyPassword, keyAlias) + << aaptVersion(enableAapt2) + << packageType(generateAab)) + << enableAapt2 << generateAab << isIncrementalBuild << enableD8;; + codeSign = false; + QTest::newRow("qt app no signing") + << "qt-app" << QStringList("qt-app") + << (QList<QByteArrayList>() << (QByteArrayList() << qtAppExpectedFiles(generateAab, + enableAapt2, + codeSign, + keyAlias))) + << (QStringList() << codeSignProperties(codeSign, keyStorePath, keystorePassword, + keyPassword, keyAlias) + << aaptVersion(enableAapt2) + << packageType(generateAab)) + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + enableAapt2 = true; + codeSign = true; + QTest::newRow("qt app aapt2") + << "qt-app" << QStringList("qt-app") + << (QList<QByteArrayList>() << (QByteArrayList() << qtAppExpectedFiles(generateAab, + enableAapt2, + codeSign, + keyAlias))) + << (QStringList() << codeSignProperties(codeSign, keyStorePath, keystorePassword, + keyPassword, keyAlias) + << aaptVersion(enableAapt2) + << packageType(generateAab)) + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + generateAab = true; + QTest::newRow("qt app aab") + << "qt-app" << QStringList("qt-app") + << (QList<QByteArrayList>() << (QByteArrayList() << qtAppExpectedFiles(generateAab, + enableAapt2, + codeSign, + keyAlias))) + << (QStringList() << codeSignProperties(codeSign, keyStorePath, keystorePassword, + keyPassword, keyAlias) + << aaptVersion(enableAapt2) + << packageType(generateAab)) + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + codeSign = false; + QTest::newRow("qt app aab no signing") + << "qt-app" << QStringList("qt-app") + << (QList<QByteArrayList>() << (QByteArrayList() << qtAppExpectedFiles(generateAab, + enableAapt2, + codeSign, + keyAlias))) + << (QStringList() << codeSignProperties(codeSign, keyStorePath, keystorePassword, + keyPassword, keyAlias) + << aaptVersion(enableAapt2) + << packageType(generateAab)) + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + + const QByteArrayList ndkArchsForQtSave = ndkArchsForQt; + ndkArchsForQt = {ndkArchsForQt.first()}; + QTest::newRow("qt app (single arch)") + << "qt-app" << QStringList("qt-app") + << (QList<QByteArrayList>() << (QByteArrayList() << qtAppExpectedFiles(generateAab, + enableAapt2))) + << QStringList{aaptVersion(enableAapt2), packageType(generateAab), + "modules.qbs.architectures:" + archsForQt.first()} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + ndkArchsForQt = ndkArchsForQtSave; + + auto teaPotAppExpectedFiles = [&](const QByteArrayList &archs, bool generateAab) { + QByteArrayList expectedFile; + expectedFile << commonFiles(generateAab) + expandArchs(archs, { + "assets/Shaders/ShaderPlain.fsh", + "assets/Shaders/VS_ShaderPlain.vsh", + cxxLibPath("libgnustl_shared.so", false), + "lib/${ARCH}/libTeapotNativeActivity.so", + "res/layout/widgets.xml", + "res/mipmap-hdpi-v4/ic_launcher.png", + "res/mipmap-mdpi-v4/ic_launcher.png", + "res/mipmap-xhdpi-v4/ic_launcher.png", + "res/mipmap-xxhdpi-v4/ic_launcher.png"}, generateAab); + if (generateAab) + expectedFile << "base/resources.pb" << "base/assets.pb" << "base/native.pb"; + else + expectedFile << "resources.arsc"; + return expectedFile; + }; + generateAab = false; + enableAapt2 = false; + QTest::newRow("teapot") + << "teapot" << QStringList("TeapotNativeActivity") + << (QList<QByteArrayList>() << teaPotAppExpectedFiles(archs, generateAab)) + << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + enableAapt2 = true; + QTest::newRow("teapot aapt2") + << "teapot" << QStringList("TeapotNativeActivity") + << (QList<QByteArrayList>() << teaPotAppExpectedFiles(archs, generateAab)) + << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + generateAab = true; + QTest::newRow("teapot aapt2 aab") + << "teapot" << QStringList("TeapotNativeActivity") + << (QList<QByteArrayList>() << teaPotAppExpectedFiles(archs, generateAab)) + << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + enableAapt2 = false; + generateAab = false; + QTest::newRow("minimal-native") + << "minimal-native" << QStringList("minimalnative") + << (QList<QByteArrayList>() << commonFiles(generateAab) + expandArchs({archs.first()}, { + "lib/${ARCH}/libminimalnative.so", + cxxLibPath("libstlport_shared.so", false), + "lib/${ARCH}/libdependency.so"}, generateAab)) + << QStringList{"products.minimalnative.multiplexByQbsProperties:[]", + "modules.qbs.architecture:" + archsStringList.first(), + aaptVersion(enableAapt2)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + enableAapt2 = true; + QTest::newRow("minimal-native aapt2") + << "minimal-native" << QStringList("minimalnative") + << (QList<QByteArrayList>() << commonFiles(generateAab) + + (QByteArrayList() << "resources.arsc") + expandArchs({archs.first()}, { + "lib/${ARCH}/libminimalnative.so", + cxxLibPath("libstlport_shared.so", false), + "lib/${ARCH}/libdependency.so"}, generateAab)) + << QStringList{"products.minimalnative.multiplexByQbsProperties:[]", + "modules.qbs.architecture:" + archsStringList.first(), + aaptVersion(enableAapt2), packageType(generateAab)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + generateAab = true; + QTest::newRow("minimal-native aapt2 aab") + << "minimal-native" << QStringList("minimalnative") + << (QList<QByteArrayList>() << commonFiles(generateAab) + + (QByteArrayList() << "base/resources.pb" << "base/native.pb") + + expandArchs({archs.first()}, { + "lib/${ARCH}/libminimalnative.so", + cxxLibPath("libstlport_shared.so", false), + "lib/${ARCH}/libdependency.so"}, generateAab)) + << QStringList{"products.minimalnative.multiplexByQbsProperties:[]", + "modules.qbs.architecture:" + archsStringList.first(), + aaptVersion(enableAapt2), packageType(generateAab)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + auto qmlAppExpectedFiles = [&](bool generateAab, bool enableAapt2) { + QByteArrayList expectedFile; + if (singleArchQt) { + expectedFile << commonFiles(generateAab) + expandArchs(ndkArchsForQt, { + "assets/--Added-by-androiddeployqt--/qml/QtQuick.2/plugins.qmltypes", + "assets/--Added-by-androiddeployqt--/qml/QtQuick.2/qmldir", + "assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/plugins.qmltypes", + "assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/qmldir", + "assets/--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list", + cxxLibPath("libgnustl_shared.so", true), + "lib/${ARCH}/libplugins_bearer_libqandroidbearer.so", + "lib/${ARCH}/libplugins_imageformats_libqgif.so", + "lib/${ARCH}/libplugins_imageformats_libqicns.so", + "lib/${ARCH}/libplugins_imageformats_libqico.so", + "lib/${ARCH}/libplugins_imageformats_libqjpeg.so", + "lib/${ARCH}/libplugins_imageformats_libqtga.so", + "lib/${ARCH}/libplugins_imageformats_libqtiff.so", + "lib/${ARCH}/libplugins_imageformats_libqwbmp.so", + "lib/${ARCH}/libplugins_imageformats_libqwebp.so", + "lib/${ARCH}/libplugins_platforms_android_libqtforandroid.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_debugger.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_inspector.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_local.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_messages.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_native.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_nativedebugger.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_profiler.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_preview.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_quickprofiler.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_server.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_tcp.so", + "lib/${ARCH}/libqml_QtQuick.2_libqtquick2plugin.so", + "lib/${ARCH}/libqml_QtQuick_Window.2_libwindowplugin.so", + "lib/${ARCH}/libQt5Core.so", + "lib/${ARCH}/libQt5Gui.so", + "lib/${ARCH}/libQt5Network.so", + "lib/${ARCH}/libQt5Qml.so", + "lib/${ARCH}/libQt5QuickParticles.so", + "lib/${ARCH}/libQt5Quick.so", + "lib/${ARCH}/libqmlapp.so"}, generateAab); + } else { + expectedFile << commonFiles(generateAab) + expandArchs(ndkArchsForQt, { + "assets/android_rcc_bundle.rcc", + cxxLibPath("libgnustl_shared.so", true), + "lib/${ARCH}/libplugins_imageformats_qgif_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qico_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qjpeg_${ARCH}.so", + "lib/${ARCH}/libplugins_platforms_qtforandroid_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_debugger_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_inspector_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_local_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_messages_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_native_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_nativedebugger_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_profiler_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_preview_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_quickprofiler_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_server_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_tcp_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "Core_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "Gui_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "Network_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "Qml_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "Quick_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "QmlModels_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "QmlWorkerScript_${ARCH}.so", + "lib/${ARCH}/libqmlapp_${ARCH}.so"}, generateAab); + if (version < qbs::Version(5, 15)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libQt5QuickParticles_${ARCH}.so"}, generateAab); + if (version >= qbs::Version(5, 15) && version < qbs::Version(6, 0)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libqml_QtQml_StateMachine_qtqmlstatemachine_${ARCH}.so", + "lib/${ARCH}/libqml_QtQml_WorkerScript.2_workerscriptplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQml_Models.2_modelsplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQml_qmlplugin_${ARCH}.so"}, generateAab); + if (version >= qbs::Version(5, 14) && version < qbs::Version(6, 0)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libqml_QtQuick.2_qtquick2plugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Window.2_windowplugin_${ARCH}.so"}, + generateAab); + if (version < qbs::Version(6, 0)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libplugins_bearer_qandroidbearer_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qicns_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qtga_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qtiff_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qwbmp_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qwebp_${ARCH}.so"}, generateAab); + if (version >= qbs::Version(6, 5)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libQt6Svg_${ARCH}.so", + "lib/${ARCH}/libplugins_iconengines_qsvgicon_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qsvg_${ARCH}.so"}, generateAab); + if (version >= qbs::Version(6, 0)) { + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libQt6OpenGL_${ARCH}.so", + "lib/${ARCH}/libqml_QtQml_Models_modelsplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQml_WorkerScript_workerscriptplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_qtquick2plugin_${ARCH}.so"}, generateAab); + if (version >= qbs::Version(6, 5)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libqml_QtQml_Base_qmlplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQml_qmlmetaplugin_${ARCH}.so"}, generateAab); + else + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libqml_QtQml_qmlplugin_${ARCH}.so"}, generateAab); + } + if (version >= qbs::Version(6, 2)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libplugins_networkinformation_qandroidnetworkinformation_${ARCH}.so", + "lib/${ARCH}/libplugins_tls_qcertonlybackend_${ARCH}.so", + "lib/${ARCH}/libplugins_tls_qopensslbackend_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Window_quickwindowplugin_${ARCH}.so", + }, generateAab); + + if (version >= qbs::Version(6, 0) && version < qbs::Version(6, 3)) { + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libQt6QuickControls2Impl_${ARCH}.so", + "lib/${ARCH}/libQt6QuickControls2_${ARCH}.so", + "lib/${ARCH}/libQt6QuickParticles_${ARCH}.so", + "lib/${ARCH}/libQt6QuickShapes_${ARCH}.so", + "lib/${ARCH}/libQt6QuickTemplates2_${ARCH}.so", + "lib/${ARCH}/libQt6Sql_${ARCH}.so", + "lib/${ARCH}/libplugins_sqldrivers_qsqlite_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Basic_impl_qtquickcontrols2basicstyleimplplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Basic_qtquickcontrols2basicstyleplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Fusion_impl_qtquickcontrols2fusionstyleimplplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Fusion_qtquickcontrols2fusionstyleplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Imagine_impl_qtquickcontrols2imaginestyleimplplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Imagine_qtquickcontrols2imaginestyleplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Material_impl_qtquickcontrols2materialstyleimplplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Material_qtquickcontrols2materialstyleplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Universal_impl_qtquickcontrols2universalstyleimplplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Universal_qtquickcontrols2universalstyleplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_impl_qtquickcontrols2implplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_qtquickcontrols2plugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_LocalStorage_qmllocalstorageplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_NativeStyle_qtquickcontrols2nativestyleplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Particles_particlesplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Shapes_qmlshapesplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Templates_qtquicktemplates2plugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Timeline_qtquicktimelineplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Layouts_qquicklayoutsplugin_${ARCH}.so"}, generateAab); + if (version >= qbs::Version(6, 2)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libqml_QtQuick_tooling_quicktoolingplugin_${ARCH}.so", + "lib/${ARCH}/libQt6QmlLocalStorage_${ARCH}.so", + "lib/${ARCH}/libQt6QmlXmlListModel_${ARCH}.so", + "lib/${ARCH}/libQt6QuickDialogs2QuickImpl_${ARCH}.so", + "lib/${ARCH}/libQt6QuickDialogs2Utils_${ARCH}.so", + "lib/${ARCH}/libQt6QuickDialogs2_${ARCH}.so", + "lib/${ARCH}/libQt6QuickLayouts_${ARCH}.so", + "lib/${ARCH}/libQt6QuickTimeline_${ARCH}.so", + "lib/${ARCH}/libqml_QtQml_XmlListModel_qmlxmllistmodelplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Dialogs_qtquickdialogsplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Dialogs_quickimpl_qtquickdialogs2quickimplplugin_${ARCH}.so"}, + generateAab); + else + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libqml_QtQuick_Window_quickwindow_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_tooling_quicktooling_${ARCH}.so"}, generateAab); + } + } + if (generateAab) + expectedFile << "base/resources.pb" << "base/assets.pb" << "base/native.pb"; + else + expectedFile << "resources.arsc"; + if (!enableAapt2 && version < qbs::Version(6, 0)) + expectedFile << "res/layout/splash.xml"; + return expectedFile; + }; + auto qmlAppCustomMetaDataExpectedFiles = [&](bool generateAab, bool enableAapt2) { + QByteArrayList expectedFile; + if (singleArchQt) { + expectedFile << commonFiles(generateAab) + expandArchs(ndkArchsForQt, { + "assets/--Added-by-androiddeployqt--/qml/QtQuick.2/plugins.qmltypes", + "assets/--Added-by-androiddeployqt--/qml/QtQuick.2/qmldir", + "assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/plugins.qmltypes", + "assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/qmldir", + "assets/--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list", + "assets/dummyasset.txt", + cxxLibPath("libgnustl_shared.so", true), + "lib/${ARCH}/libplugins_bearer_libqandroidbearer.so", + "lib/${ARCH}/libplugins_imageformats_libqgif.so", + "lib/${ARCH}/libplugins_imageformats_libqicns.so", + "lib/${ARCH}/libplugins_imageformats_libqico.so", + "lib/${ARCH}/libplugins_imageformats_libqjpeg.so", + "lib/${ARCH}/libplugins_imageformats_libqtga.so", + "lib/${ARCH}/libplugins_imageformats_libqtiff.so", + "lib/${ARCH}/libplugins_imageformats_libqwbmp.so", + "lib/${ARCH}/libplugins_imageformats_libqwebp.so", + "lib/${ARCH}/libplugins_platforms_android_libqtforandroid.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_debugger.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_inspector.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_local.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_messages.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_native.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_nativedebugger.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_profiler.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_preview.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_quickprofiler.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_server.so", + "lib/${ARCH}/libplugins_qmltooling_libqmldbg_tcp.so", + "lib/${ARCH}/libqml_QtQuick.2_libqtquick2plugin.so", + "lib/${ARCH}/libqml_QtQuick_Window.2_libwindowplugin.so", + "lib/${ARCH}/libQt5Core.so", + "lib/${ARCH}/libQt5Gui.so", + "lib/${ARCH}/libQt5Network.so", + "lib/${ARCH}/libQt5Qml.so", + "lib/${ARCH}/libQt5QuickParticles.so", + "lib/${ARCH}/libQt5Quick.so", + "lib/${ARCH}/libqmlapp.so"}, generateAab); + } else { + expectedFile << commonFiles(generateAab) + expandArchs(ndkArchsForQt, { + "assets/android_rcc_bundle.rcc", + "assets/dummyasset.txt", + cxxLibPath("libgnustl_shared.so", true), + "lib/${ARCH}/libplugins_imageformats_qgif_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qico_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qjpeg_${ARCH}.so", + "lib/${ARCH}/libplugins_platforms_qtforandroid_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_debugger_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_inspector_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_local_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_messages_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_native_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_nativedebugger_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_profiler_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_preview_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_quickprofiler_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_server_${ARCH}.so", + "lib/${ARCH}/libplugins_qmltooling_qmldbg_tcp_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "Core_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "Gui_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "Network_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "Qml_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "Quick_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "QmlModels_${ARCH}.so", + "lib/${ARCH}/libQt" + qtVersionMajor + "QmlWorkerScript_${ARCH}.so", + "lib/${ARCH}/libqmlapp_${ARCH}.so"}, generateAab); + if (version < qbs::Version(5, 15)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libQt5QuickParticles_${ARCH}.so"}, generateAab); + if (version >= qbs::Version(5, 15) && version < qbs::Version(6, 0)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libqml_QtQml_StateMachine_qtqmlstatemachine_${ARCH}.so", + "lib/${ARCH}/libqml_QtQml_WorkerScript.2_workerscriptplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQml_Models.2_modelsplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQml_qmlplugin_${ARCH}.so"}, generateAab); + if (version >= qbs::Version(5, 14) && version < qbs::Version(6, 0)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libqml_QtQuick.2_qtquick2plugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Window.2_windowplugin_${ARCH}.so"}, + generateAab); + if (version < qbs::Version(6, 0)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libplugins_bearer_qandroidbearer_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qicns_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qtga_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qtiff_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qwbmp_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qwebp_${ARCH}.so"}, generateAab); + if (version >= qbs::Version(6, 5)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libQt6Svg_${ARCH}.so", + "lib/${ARCH}/libplugins_iconengines_qsvgicon_${ARCH}.so", + "lib/${ARCH}/libplugins_imageformats_qsvg_${ARCH}.so"}, generateAab); + if (version >= qbs::Version(6, 0)) { + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libQt6OpenGL_${ARCH}.so", + "lib/${ARCH}/libqml_QtQml_Models_modelsplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQml_WorkerScript_workerscriptplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_qtquick2plugin_${ARCH}.so"}, generateAab); + if (version >= qbs::Version(6, 5)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libqml_QtQml_Base_qmlplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQml_qmlmetaplugin_${ARCH}.so"}, generateAab); + else + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libqml_QtQml_qmlplugin_${ARCH}.so"}, generateAab); + } + if (version >= qbs::Version(6, 2)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libplugins_networkinformation_qandroidnetworkinformation_${ARCH}.so", + "lib/${ARCH}/libplugins_tls_qcertonlybackend_${ARCH}.so", + "lib/${ARCH}/libplugins_tls_qopensslbackend_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Window_quickwindowplugin_${ARCH}.so", + }, generateAab); + if (version >= qbs::Version(6, 0) && version < qbs::Version(6, 3)) { + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libQt6QuickControls2Impl_${ARCH}.so", + "lib/${ARCH}/libQt6QuickControls2_${ARCH}.so", + "lib/${ARCH}/libQt6QuickParticles_${ARCH}.so", + "lib/${ARCH}/libQt6QuickShapes_${ARCH}.so", + "lib/${ARCH}/libQt6QuickTemplates2_${ARCH}.so", + "lib/${ARCH}/libQt6Sql_${ARCH}.so", + "lib/${ARCH}/libplugins_sqldrivers_qsqlite_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Basic_impl_qtquickcontrols2basicstyleimplplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Basic_qtquickcontrols2basicstyleplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Fusion_impl_qtquickcontrols2fusionstyleimplplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Fusion_qtquickcontrols2fusionstyleplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Imagine_impl_qtquickcontrols2imaginestyleimplplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Imagine_qtquickcontrols2imaginestyleplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Material_impl_qtquickcontrols2materialstyleimplplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Material_qtquickcontrols2materialstyleplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Universal_impl_qtquickcontrols2universalstyleimplplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_Universal_qtquickcontrols2universalstyleplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_impl_qtquickcontrols2implplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Controls_qtquickcontrols2plugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_LocalStorage_qmllocalstorageplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_NativeStyle_qtquickcontrols2nativestyleplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Particles_particlesplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Shapes_qmlshapesplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Templates_qtquicktemplates2plugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Timeline_qtquicktimelineplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Layouts_qquicklayoutsplugin_${ARCH}.so"}, generateAab); + if (version >= qbs::Version(6, 2)) + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libqml_QtQuick_tooling_quicktoolingplugin_${ARCH}.so", + "lib/${ARCH}/libQt6QmlLocalStorage_${ARCH}.so", + "lib/${ARCH}/libQt6QmlXmlListModel_${ARCH}.so", + "lib/${ARCH}/libQt6QuickDialogs2QuickImpl_${ARCH}.so", + "lib/${ARCH}/libQt6QuickDialogs2Utils_${ARCH}.so", + "lib/${ARCH}/libQt6QuickDialogs2_${ARCH}.so", + "lib/${ARCH}/libQt6QuickLayouts_${ARCH}.so", + "lib/${ARCH}/libQt6QuickTimeline_${ARCH}.so", + "lib/${ARCH}/libqml_QtQml_XmlListModel_qmlxmllistmodelplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Dialogs_qtquickdialogsplugin_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_Dialogs_quickimpl_qtquickdialogs2quickimplplugin_${ARCH}.so"}, + generateAab); + else + expectedFile << expandArchs(ndkArchsForQt, { + "lib/${ARCH}/libqml_QtQuick_Window_quickwindow_${ARCH}.so", + "lib/${ARCH}/libqml_QtQuick_tooling_quicktooling_${ARCH}.so"}, generateAab); + } + } + if (generateAab) + expectedFile << "base/resources.pb" << "base/assets.pb" << "base/native.pb"; + else + expectedFile << "resources.arsc"; + if (!enableAapt2 && version < qbs::Version(6, 0)) + expectedFile << "res/layout/splash.xml"; + return expectedFile; + }; + QStringList qmlAppCustomProperties; + if (singleArchQt) { + qmlAppCustomProperties = QStringList{"modules.Android.sdk.automaticSources:false", + "modules.qbs.architecture:" + archsForQt.first()}; + } else { + qmlAppCustomProperties = QStringList{"modules.Android.sdk.automaticSources:false"}; + } + // aapt tool for the resources works with a directory option pointing to the parent directory + // of the resources (res). + // The Qt.android_support module adds res/values/libs.xml (from Qt install dir). So the res from + // Qt install res directory is added to aapt. This results in adding res/layout/splash.xml to + // the package eventhough the file is not needed. + // On the other hand aapt2 requires giving all the resources files. + // Also when enabling aapt2 the resources.arsc is always created, eventhough no resources are + // declared. + enableAapt2 = false; + generateAab = false; + QTest::newRow("qml app") + << "qml-app" << QStringList("qmlapp") + << (QList<QByteArrayList>() << qmlAppExpectedFiles(generateAab, enableAapt2)) + << (QStringList() << qmlAppCustomProperties << aaptVersion(enableAapt2) + << packageType(generateAab)) + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + enableAapt2 = true; + QTest::newRow("qml app aapt2") + << "qml-app" << QStringList("qmlapp") + << (QList<QByteArrayList>() << qmlAppExpectedFiles(generateAab, enableAapt2)) + << (QStringList() << qmlAppCustomProperties << aaptVersion(enableAapt2) + << packageType(generateAab)) + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + generateAab = true; + QTest::newRow("qml app aab") + << "qml-app" << QStringList("qmlapp") + << (QList<QByteArrayList>() << qmlAppExpectedFiles(generateAab, enableAapt2)) + << (QStringList() << qmlAppCustomProperties << aaptVersion(enableAapt2) + << packageType(generateAab)) + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + enableAapt2 = false; + generateAab = false; QTest::newRow("qml app with custom metadata") << "qml-app" << QStringList("qmlapp") - << (QList<QByteArrayList>() << commonFiles + expandArchs(ndkArchsForQt, { - "resources.arsc", - "assets/--Added-by-androiddeployqt--/qml/QtQuick.2/plugins.qmltypes", - "assets/--Added-by-androiddeployqt--/qml/QtQuick.2/qmldir", - "assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/plugins.qmltypes", - "assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/qmldir", - "assets/--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list", - "assets/dummyasset.txt", - "lib/${ARCH}/libgdbserver.so", - cxxLibPath("libgnustl_shared.so", true), - "lib/${ARCH}/libplugins_bearer_libqandroidbearer.so", - "lib/${ARCH}/libplugins_imageformats_libqgif.so", - "lib/${ARCH}/libplugins_imageformats_libqicns.so", - "lib/${ARCH}/libplugins_imageformats_libqico.so", - "lib/${ARCH}/libplugins_imageformats_libqjpeg.so", - "lib/${ARCH}/libplugins_imageformats_libqtga.so", - "lib/${ARCH}/libplugins_imageformats_libqtiff.so", - "lib/${ARCH}/libplugins_imageformats_libqwbmp.so", - "lib/${ARCH}/libplugins_imageformats_libqwebp.so", - "lib/${ARCH}/libplugins_platforms_android_libqtforandroid.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_debugger.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_inspector.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_local.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_messages.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_native.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_nativedebugger.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_profiler.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_preview.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_quickprofiler.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_server.so", - "lib/${ARCH}/libplugins_qmltooling_libqmldbg_tcp.so", - "lib/${ARCH}/libqml_QtQuick.2_libqtquick2plugin.so", - "lib/${ARCH}/libqml_QtQuick_Window.2_libwindowplugin.so", - "lib/${ARCH}/libQt5Core.so", - "lib/${ARCH}/libQt5Gui.so", - "lib/${ARCH}/libQt5Network.so", - "lib/${ARCH}/libQt5Qml.so", - "lib/${ARCH}/libQt5QuickParticles.so", - "lib/${ARCH}/libQt5Quick.so", - "lib/${ARCH}/libqmlapp.so", - "res/layout/splash.xml"})) - << QStringList("modules.Android.sdk.automaticSources:true"); + << (QList<QByteArrayList>() << (QByteArrayList() + << qmlAppCustomMetaDataExpectedFiles(generateAab, + enableAapt2))) + << QStringList{"modules.Android.sdk.automaticSources:true", + aaptVersion(enableAapt2), packageType(generateAab)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + enableAapt2 = true; + QTest::newRow("qml app with custom metadata aapt2") + << "qml-app" << QStringList("qmlapp") + << (QList<QByteArrayList>() << (QByteArrayList() + << qmlAppCustomMetaDataExpectedFiles(generateAab, + enableAapt2))) + << QStringList{"modules.Android.sdk.automaticSources:true", aaptVersion(enableAapt2), + packageType(generateAab)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + generateAab = true; + if (!singleArchQt) { + QTest::newRow("qml app with custom metadata aab") + << "qml-app" << QStringList("qmlapp") + << (QList<QByteArrayList>() << (QByteArrayList() + << qmlAppCustomMetaDataExpectedFiles(generateAab, + enableAapt2))) + << QStringList{"modules.Android.sdk.automaticSources:true", aaptVersion(enableAapt2), + packageType(generateAab)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + } + isIncrementalBuild = false; + enableAapt2 = false; + generateAab = false; + auto noNativeExpectedFiles = [&](bool generateAab) { + QByteArrayList expectedFile; + expectedFile << commonFiles(generateAab) + expandArchs(archs, { + "res/drawable-hdpi-v4/ic_action_play_disabled.png", + "res/drawable-hdpi-v4/ic_action_play.png", + "res/drawable-hdpi-v4/ic_launcher.png", + "res/drawable-hdpi-v4/tile.9.png", + "res/drawable-mdpi-v4/ic_action_play_disabled.png", + "res/drawable-mdpi-v4/ic_action_play.png", + "res/drawable-mdpi-v4/ic_launcher.png", + "res/drawable/selector_play.xml", + "res/drawable-xhdpi-v4/ic_action_play_disabled.png", + "res/drawable-xhdpi-v4/ic_action_play.png", + "res/drawable-xhdpi-v4/ic_launcher.png", + "res/drawable-xxhdpi-v4/ic_launcher.png", + "res/layout/sample_main.xml", + "res/menu/action_menu.xml", + "res/raw/vid_bigbuckbunny.mp4"}, generateAab); + if (generateAab) + expectedFile << "base/resources.pb"; + else + expectedFile << "resources.arsc"; + return expectedFile; + }; + QTest::newRow("no native") << "no-native" << QStringList("com.example.android.basicmediadecoder") - << (QList<QByteArrayList>() << commonFiles + expandArchs(archs, { - "resources.arsc", - "res/drawable-hdpi-v4/ic_action_play_disabled.png", - "res/drawable-hdpi-v4/ic_action_play.png", - "res/drawable-hdpi-v4/ic_launcher.png", - "res/drawable-hdpi-v4/tile.9.png", - "res/drawable-mdpi-v4/ic_action_play_disabled.png", - "res/drawable-mdpi-v4/ic_action_play.png", - "res/drawable-mdpi-v4/ic_launcher.png", - "res/drawable/selector_play.xml", - "res/drawable-xhdpi-v4/ic_action_play_disabled.png", - "res/drawable-xhdpi-v4/ic_action_play.png", - "res/drawable-xhdpi-v4/ic_launcher.png", - "res/drawable-xxhdpi-v4/ic_launcher.png", - "res/layout/sample_main.xml", - "res/menu/action_menu.xml", - "res/menu-v11/action_menu.xml", - "res/raw/vid_bigbuckbunny.mp4"})) - << QStringList(); + << (QList<QByteArrayList>() << noNativeExpectedFiles(generateAab)) + << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + enableAapt2 = true; + QTest::newRow("no native aapt2") + << "no-native" + << QStringList("com.example.android.basicmediadecoder") + << (QList<QByteArrayList>() << noNativeExpectedFiles(generateAab)) + << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + generateAab = true; + QTest::newRow("no native aab") + << "no-native" + << QStringList("com.example.android.basicmediadecoder") + << (QList<QByteArrayList>() << noNativeExpectedFiles(generateAab)) + << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + enableAapt2 = false; + generateAab = false; QTest::newRow("aidl") << "aidl" << QStringList("io.qbs.aidltest") - << QList<QByteArrayList>{commonFiles} << QStringList(); + << (QList<QByteArrayList>() << (QByteArrayList() + << commonFiles(generateAab))) + << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + enableAapt2 = true; + QTest::newRow("aidl aapt2") << "aidl" << QStringList("io.qbs.aidltest") + << (QList<QByteArrayList>() << (QByteArrayList() + << commonFiles(generateAab) + << "resources.arsc")) + << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + generateAab = true; + QTest::newRow("aidl aab") << "aidl" << QStringList("io.qbs.aidltest") + << (QList<QByteArrayList>() << (QByteArrayList() + << commonFiles(generateAab) + << "base/resources.pb")) + << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + enableAapt2 = false; + generateAab = false; + enableD8 = false; QTest::newRow("multiple libs") << "multiple-libs-per-apk" << QStringList("twolibs") - << (QList<QByteArrayList>() << commonFiles + expandArchs(archs, { + << (QList<QByteArrayList>() << commonFiles(generateAab) + expandArchs(archs, { + "resources.arsc", + "lib/${ARCH}/liblib1.so", + "lib/${ARCH}/liblib2.so", + cxxLibPath("libstlport_shared.so", false)}, generateAab)) + << QStringList{aaptVersion(enableAapt2), packageType(generateAab), + dexCompilerVersion(enableD8)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + enableD8 = true; + QTest::newRow("multiple libs with d8") + << "multiple-libs-per-apk" + << QStringList("twolibs") + << (QList<QByteArrayList>() << commonFiles(generateAab) + expandArchs(archs, { + "resources.arsc", + "lib/${ARCH}/liblib1.so", + "lib/${ARCH}/liblib2.so", + cxxLibPath("libstlport_shared.so", false)}, generateAab)) + << QStringList{aaptVersion(enableAapt2), packageType(generateAab), + dexCompilerVersion(enableD8)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + enableD8 = false; + enableAapt2 = true; + QTest::newRow("multiple libs aapt2") + << "multiple-libs-per-apk" + << QStringList("twolibs") + << (QList<QByteArrayList>() << commonFiles(generateAab) + expandArchs(archs, { "resources.arsc", - "lib/${ARCH}/libgdbserver.so", "lib/${ARCH}/liblib1.so", "lib/${ARCH}/liblib2.so", - cxxLibPath("libstlport_shared.so", false)})) - << QStringList(); - QByteArrayList expectedFiles1 = (commonFiles - + expandArchs(QByteArrayList{"armeabi-v7a", "x86"}, { - "resources.arsc", - "lib/${ARCH}/libgdbserver.so", - "lib/${ARCH}/libp1lib1.so", - cxxLibPath("libstlport_shared.so", false)}) - + expandArchs(QByteArrayList{archs}, { - "resources.arsc", - "lib/${ARCH}/libgdbserver.so", - "lib/${ARCH}/libp1lib2.so", - cxxLibPath("libstlport_shared.so", false)})).toSet().toList(); - QByteArrayList expectedFiles2 = commonFiles + expandArchs(archs, { - "lib/${ARCH}/libgdbserver.so", - "lib/${ARCH}/libp2lib1.so", - "lib/${ARCH}/libp2lib2.so", - cxxLibPath("libstlport_shared.so", false)}); + cxxLibPath("libstlport_shared.so", false)}, generateAab)) + << QStringList{aaptVersion(enableAapt2), packageType(generateAab), + dexCompilerVersion(enableD8)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + generateAab = true; + QTest::newRow("multiple libs aab") + << "multiple-libs-per-apk" + << QStringList("twolibs") + << (QList<QByteArrayList>() << commonFiles(generateAab) + expandArchs(archs, { + "resources.pb", "native.pb", + "lib/${ARCH}/liblib1.so", + "lib/${ARCH}/liblib2.so", + cxxLibPath("libstlport_shared.so", false)}, generateAab)) + << QStringList{aaptVersion(enableAapt2), packageType(generateAab), + dexCompilerVersion(enableD8)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + + enableAapt2 = false; + generateAab = false; + auto expectedFiles1 = [&](bool generateAab) { + QByteArrayList expectedFile = qbs::toList(qbs::toSet(commonFiles(generateAab) + + expandArchs(QByteArrayList{"armeabi-v7a", "x86"}, { + "lib/${ARCH}/libp1lib1.so", + cxxLibPath("libstlport_shared.so", false)}, generateAab) + + expandArchs(QByteArrayList{archs}, { + "lib/${ARCH}/libp1lib2.so", + cxxLibPath("libstlport_shared.so", false)}, generateAab))); + if (generateAab) + expectedFile << "base/resources.pb" << "base/native.pb"; + else + expectedFile << "resources.arsc"; + return expectedFile; + }; + auto expectedFiles2 = [&](bool generateAab) { + QByteArrayList expectedFile = commonFiles(generateAab) + expandArchs(archs, { + "lib/${ARCH}/libp2lib1.so", + "lib/${ARCH}/libp2lib2.so", + cxxLibPath("libstlport_shared.so", false)}, generateAab); + return expectedFile; + }; QTest::newRow("multiple apks") << "multiple-apks-per-project" << (QStringList() << "twolibs1" << "twolibs2") - << QList<QByteArrayList>{expectedFiles1, expectedFiles2} - << QStringList(); + << QList<QByteArrayList>{expectedFiles1(generateAab), expectedFiles2(generateAab)} + << QStringList{aaptVersion(enableAapt2), packageType(generateAab), + dexCompilerVersion(enableD8)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + enableAapt2 = true; + QTest::newRow("multiple apks aapt2") + << "multiple-apks-per-project" + << (QStringList() << "twolibs1" << "twolibs2") + << (QList<QByteArrayList>() << expectedFiles1(generateAab) + << (QByteArrayList() << expectedFiles2(generateAab) << "resources.arsc")) + << QStringList{aaptVersion(enableAapt2), packageType(generateAab), + dexCompilerVersion(enableD8)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; + generateAab = true; + QTest::newRow("multiple apks aab") + << "multiple-apks-per-project" + << (QStringList() << "twolibs1" << "twolibs2") + << (QList<QByteArrayList>() << expectedFiles1(generateAab) + << (QByteArrayList() << expectedFiles2(generateAab) << "base/resources.pb" + << "base/native.pb")) + << QStringList{aaptVersion(enableAapt2), packageType(generateAab), + dexCompilerVersion(enableD8)} + << enableAapt2 << generateAab << isIncrementalBuild << enableD8; } QTEST_MAIN(TestBlackboxAndroid) diff --git a/tests/auto/blackbox/tst_blackboxapple.cpp b/tests/auto/blackbox/tst_blackboxapple.cpp index 96cd70b58..30e20a1c9 100644 --- a/tests/auto/blackbox/tst_blackboxapple.cpp +++ b/tests/auto/blackbox/tst_blackboxapple.cpp @@ -31,7 +31,9 @@ #include "../shared.h" #include <tools/hostosinfo.h> #include <tools/profile.h> +#include <tools/qttools.h> +#include <QtCore/qdiriterator.h> #include <QtCore/qjsondocument.h> #include <QtCore/qjsonobject.h> #include <QtXml/qdom.h> @@ -60,6 +62,117 @@ static QString getEmbeddedBinaryPlist(const QString &file) return QString::fromUtf8(p.readAllStandardOutput()).trimmed(); } +static QVariantMap readInfoPlistFile(const QString &infoPlistPath) +{ + if (!QFile::exists(infoPlistPath)) { + qWarning() << infoPlistPath << "doesn't exist"; + return {}; + } + + QProcess plutil; + plutil.start("plutil", { + QStringLiteral("-convert"), + QStringLiteral("json"), + infoPlistPath + }); + if (!plutil.waitForStarted()) { + qWarning() << plutil.errorString(); + return {}; + } + if (!plutil.waitForFinished()) { + qWarning() << plutil.errorString(); + return {}; + } + if (plutil.exitCode() != 0) { + qWarning() << plutil.readAllStandardError().constData(); + return {}; + } + + QFile infoPlist(infoPlistPath); + if (!infoPlist.open(QIODevice::ReadOnly)) { + qWarning() << infoPlist.errorString(); + return {}; + } + QJsonParseError error; + const auto json = QJsonDocument::fromJson(infoPlist.readAll(), &error); + if (error.error != QJsonParseError::NoError) { + qWarning() << error.errorString(); + return {}; + } + return json.object().toVariantMap(); +} + +static QString getInfoPlistPath(const QString &bundlePath) +{ + QFileInfo contents(bundlePath + "/Contents"); + if (contents.exists() && contents.isDir()) + return contents.filePath() + "/Info.plist"; // macOS bundle + return bundlePath + "/Info.plist"; +} + +static bool testVariantListType(const QVariant &variant, QMetaType::Type type) +{ + if (variant.userType() != QMetaType::QVariantList) + return false; + for (const auto &value : variant.toList()) { + if (value.userType() != type) + return false; + } + return true; +} + +static QString findFatLibrary(const QString &dir, const QString &libraryName) +{ + QDirIterator it(dir, {}, QDir::AllEntries, QDirIterator::Subdirectories); + while (it.hasNext()) { + it.next(); + if (it.fileInfo().fileName() == libraryName) { + QProcess lipo; + lipo.start("lipo", { QStringLiteral("-info"), it.filePath() }); + if (!lipo.waitForStarted() || !lipo.waitForFinished() || lipo.exitCode() != 0) + return {}; + auto output = lipo.readAllStandardOutput(); + if (output.contains(QByteArrayLiteral("Architectures in the fat file"))) + return QDir::cleanPath(it.filePath()); + } + } + + return {}; +} + +enum class CodeSignResult { Failed = 0, Signed, Unsigned }; +using CodeSignData = QMap<QByteArray, QByteArray>; +static std::pair<CodeSignResult, CodeSignData> parseCodeSignOutput(const QByteArray &output) +{ + CodeSignData data; + if (output.contains("code object is not signed at all")) + return {CodeSignResult::Unsigned, data}; + const auto lines = output.split('\n'); + for (const auto &line: lines) { + if (line.isEmpty() + || line.startsWith("CodeDirectory") + || line.startsWith("Sealed Resources") + || line.startsWith("Internal requirements")) { + continue; + } + const int index = line.indexOf('='); + if (index == -1) + return {CodeSignResult::Failed, {}}; + data[line.mid(0, index)] = line.mid(index + 1); + } + return {CodeSignResult::Signed, data}; +} + +static std::pair<CodeSignResult, CodeSignData> getCodeSignInfo(const QString &path) +{ + QProcess codesign; + codesign.start("codesign", { QStringLiteral("-dv"), path }); + if (!codesign.waitForStarted() || !codesign.waitForFinished()) + return {CodeSignResult::Failed, {}}; + const auto output = codesign.readAllStandardError(); + return parseCodeSignOutput(output); +} + TestBlackboxApple::TestBlackboxApple() : TestBlackboxBase (SRCDIR "/testdata-apple", "blackbox-apple") { @@ -78,106 +191,190 @@ void TestBlackboxApple::initTestCase() void TestBlackboxApple::appleMultiConfig() { const auto xcodeVersion = findXcodeVersion(); - const bool supportsX86 = xcodeVersion < qbs::Version(10); - + if (!xcodeVersion) + QSKIP("requires Xcode profile"); QDir::setCurrent(testDataDir + "/apple-multiconfig"); QCOMPARE(runQbs(QbsRunParameters(QStringList{ "qbs.installPrefix:''", - QString("project.enableX86:") + (supportsX86 ? "true" : "false")})), 0); - - QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/Contents/MacOS/singleapp").isExecutable()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/Contents/Info.plist").isRegularFile()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/Contents/PkgInfo").isRegularFile()); - - QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/Contents/MacOS/singleapp_agg").isExecutable()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/Contents/Info.plist").isRegularFile()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/Contents/PkgInfo").isRegularFile()); - - QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/singlelib").isFileSymLink()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Resources").isDirSymLink()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions").isRegularDir()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/A").isRegularDir()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/A/singlelib").isRegularFile()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/A/Resources").isRegularDir()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/A/Resources/Info.plist").isRegularFile()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/Current").isDirSymLink()); - - QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/Contents/MacOS/multiapp").isExecutable()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/Contents/Info.plist").isRegularFile()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/Contents/PkgInfo").isRegularFile()); - - QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/Contents/MacOS/fatmultiapp").isExecutable()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/Contents/Info.plist").isRegularFile()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/Contents/PkgInfo").isRegularFile()); - - QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Contents/MacOS/" - "fatmultiappmultivariant").isFileSymLink()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Contents/MacOS/" - "fatmultiappmultivariant_debug").isExecutable()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Contents/MacOS/" - "fatmultiappmultivariant_profile").isExecutable()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Contents/Info.plist") - .isRegularFile()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Contents/PkgInfo") - .isRegularFile()); - - QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/multilib").isFileSymLink()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Resources").isDirSymLink()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions").isRegularDir()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A").isRegularDir()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/multilib").isRegularFile()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/multilib_debug").isRegularFile()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/multilib_profile").isRegularFile()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/Resources").isRegularDir()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/Resources/Info.plist").isRegularFile()); - QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/Current").isDirSymLink()); - - for (const QString &variant : { "release", "debug", "profile" }) { - for (const QString &arch : { "x86_64" }) { - QProcess process; - process.setProgram("/usr/bin/arch"); - process.setArguments({ - "-arch", arch, - "-e", "DYLD_IMAGE_SUFFIX=_" + variant, - defaultInstallRoot + "/multiapp.app/Contents/MacOS/multiapp" - }); - process.start(); - process.waitForFinished(); - QCOMPARE(process.exitCode(), 0); - const auto processStdout = process.readAllStandardOutput(); - QVERIFY2(processStdout.contains("Hello from " + variant.toUtf8() + " " + arch.toUtf8()), - processStdout.constData()); + QStringLiteral("project.xcodeVersion:") + xcodeVersion->toString()})), 0); + + if (m_qbsStdout.contains("isShallow: false")) { + QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/Contents/MacOS/singleapp").isExecutable()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/Contents/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/Contents/PkgInfo").isRegularFile()); + + QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/Contents/MacOS/singleapp_agg").isExecutable()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/Contents/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/Contents/PkgInfo").isRegularFile()); + + QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/singlelib").isFileSymLink()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Resources").isDirSymLink()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/A").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/A/singlelib").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/A/Resources").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/A/Resources/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/Current").isDirSymLink()); + + QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/Contents/MacOS/multiapp").isExecutable()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/Contents/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/Contents/PkgInfo").isRegularFile()); + + QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/Contents/MacOS/fatmultiapp").isExecutable()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/Contents/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/Contents/PkgInfo").isRegularFile()); + + QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Contents/MacOS/" + "fatmultiappmultivariant").isFileSymLink()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Contents/MacOS/" + "fatmultiappmultivariant_debug").isExecutable()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Contents/MacOS/" + "fatmultiappmultivariant_profiling").isExecutable()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Contents/Info.plist") + .isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Contents/PkgInfo") + .isRegularFile()); + + QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/multilib").isFileSymLink()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Resources").isDirSymLink()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/multilib").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/multilib_debug").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/multilib_profiling").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/Resources").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/Resources/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/Current").isDirSymLink()); + + for (const QString variant : { "release", "debug", "profiling" }) { + for (const QString arch : { "x86_64" }) { + QProcess process; + process.setProgram("/usr/bin/arch"); + process.setArguments({ + "-arch", arch, + "-e", "DYLD_IMAGE_SUFFIX=_" + variant, + defaultInstallRoot + "/multiapp.app/Contents/MacOS/multiapp" + }); + process.start(); + process.waitForFinished(); + QCOMPARE(process.exitCode(), 0); + const auto processStdout = process.readAllStandardOutput(); + QVERIFY2(processStdout.contains("Hello from " + variant.toUtf8() + " " + arch.toUtf8()), + processStdout.constData()); + } } + } else if (m_qbsStdout.contains("isShallow: true")) { + QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/singleapp").isExecutable()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/PkgInfo").isRegularFile()); + + QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/singleapp_agg").isExecutable()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/PkgInfo").isRegularFile()); + + QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/singlelib").isExecutable()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Info.plist").isRegularFile()); + + QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/multiapp").isExecutable()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/PkgInfo").isRegularFile()); + + QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/fatmultiapp").isExecutable()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/PkgInfo").isRegularFile()); + + QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/" + "fatmultiappmultivariant").isFileSymLink()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/" + "fatmultiappmultivariant_debug").isExecutable()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/" + "fatmultiappmultivariant_profiling").isExecutable()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Info.plist") + .isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/PkgInfo") + .isRegularFile()); + + QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/multilib").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/multilib_debug").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/multilib_profiling").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Info.plist").isRegularFile()); + } else { + QVERIFY2(false, qPrintable(m_qbsStdout)); } } void TestBlackboxApple::aggregateDependencyLinking() { - if (HostOsInfo::hostOsVersion() > qbs::Version(10, 13, 4)) - QSKIP("32-bit arch build is no longer supported on macOS versions higher than 10.13.4."); + const auto xcodeVersion = findXcodeVersion(); + + if (!xcodeVersion) + QSKIP("requires Xcode profile"); + + // XCode 11 produces warning about deprecation of 32-bit apps, but still works + const bool hasX86Mac = xcodeVersion < qbs::Version(12); + const bool hasArmMac = xcodeVersion >= qbs::Version(12, 2); QDir::setCurrent(testDataDir + "/aggregateDependencyLinking"); - QCOMPARE(runQbs(QStringList{"-p", "multi_arch_lib"}), 0); + QbsRunParameters params{QStringList{"-p", "multi_arch_lib"}}; + params.arguments << QStringLiteral("products.multi_arch_lib.hasX86Mac:%1").arg(hasX86Mac); + params.arguments << QStringLiteral("products.multi_arch_lib.hasArmMac:%1").arg(hasArmMac); + QCOMPARE(runQbs(params), 0); + if (m_qbsStdout.contains("Cannot build fat binaries")) + QSKIP("Building fat binaries is not supported for this profile"); QCOMPARE(runQbs(QStringList{"-p", "just_app", "--command-echo-mode", "command-line"}), 0); int linkedInLibrariesCount = - QString::fromUtf8(m_qbsStdout).count(QStringLiteral("multi_arch_lib.a")); + QString::fromUtf8(m_qbsStdout).count(QStringLiteral("libmulti_arch_lib.a")); QCOMPARE(linkedInLibrariesCount, 1); + const auto fatLibPath = findFatLibrary(testDataDir, QStringLiteral("libmulti_arch_lib.a")); + QVERIFY(!fatLibPath.isEmpty()); + QVERIFY2(QString::fromUtf8(m_qbsStdout).contains(fatLibPath), m_qbsStdout); +} + +void TestBlackboxApple::appiconset() +{ + QDir::setCurrent(testDataDir + QLatin1String("/ib/appiconset")); + + QbsRunParameters params; + params.arguments = QStringList() << "-f" << "appiconset.qbs"; + QCOMPARE(runQbs(params), 0); + + const auto infoPlistPath = getInfoPlistPath( + relativeProductBuildDir("appiconset") + "/appiconset.app"); + QVERIFY(QFile::exists(infoPlistPath)); + const auto content = readInfoPlistFile(infoPlistPath); + QVERIFY(!content.isEmpty()); + + if (m_qbsStdout.contains("bundle.isShallow: false")) { + QCOMPARE(content.value(QStringLiteral("CFBundleIconFile")), QStringLiteral("AppIcon")); + QCOMPARE(content.value(QStringLiteral("CFBundleIconName")), QStringLiteral("AppIcon")); + QVERIFY(regularFileExists(relativeProductBuildDir("appiconset") + + "/appiconset.app/Contents/Resources/AppIcon.icns")); + } else if (m_qbsStdout.contains("bundle.isShallow: true")) { + const auto icons = content.value(QStringLiteral("CFBundleIcons")).toMap(); + QVERIFY2(!icons.isEmpty(), "Info.plist doesn't contain CFBundleIcons key"); + const auto primaryIcon = icons.value(QStringLiteral("CFBundlePrimaryIcon")).toMap(); + QVERIFY2(!primaryIcon.isEmpty(), "Info.plist doesn't contain CFBundlePrimaryIcon key"); + QCOMPARE(primaryIcon.value(QStringLiteral("CFBundleIconName")), QStringLiteral("AppIcon")); + } else { + QVERIFY2(false, "Cannot determine bundle type"); + } } void TestBlackboxApple::assetCatalog() { QFETCH(bool, flatten); - const auto xcodeVersion = findXcodeVersion(); QDir::setCurrent(testDataDir + QLatin1String("/ib/assetcatalog")); rmDirR(relativeBuildDir()); + if (!findXcode()) + QSKIP("requires Xcode profile"); + QbsRunParameters params; - const auto v = HostOsInfo::hostOsVersion(); const QString flattens = "modules.ib.flatten:" + QString(flatten ? "true" : "false"); - const QString macosTarget = "modules.cpp.minimumMacosVersion:'" + v.toString() + "'"; + const QString macosTarget = "modules.cpp.minimumMacosVersion:'10.15'"; // Make sure a dry run does not write anything params.arguments = QStringList() << "-f" << "assetcatalogempty.qbs" << "--dry-run" @@ -185,44 +382,20 @@ void TestBlackboxApple::assetCatalog() QCOMPARE(runQbs(params), 0); QVERIFY(!directoryExists(relativeBuildDir())); + if (m_qbsStdout.contains("Skip this test")) + QSKIP("Skip this test"); + params.arguments = QStringList() << "-f" << "assetcatalogempty.qbs" << flattens << macosTarget; QCOMPARE(runQbs(params), 0); // empty asset catalogs must still produce output - if (xcodeVersion >= qbs::Version(5)) - QVERIFY((bool)m_qbsStdout.contains("compiling empty.xcassets")); - - // should additionally produce raw assets since deployment target will be < 10.9 - // older versions of ibtool generated either raw assets OR .car files; - // newer versions always generate the .car file regardless of the deployment target - if (v < qbs::Version(10, 9)) { - QVERIFY(regularFileExists(relativeProductBuildDir("assetcatalogempty") - + "/assetcatalogempty.app/Contents/Resources/other.png")); - QVERIFY(regularFileExists(relativeProductBuildDir("assetcatalogempty") - + "/assetcatalogempty.app/Contents/Resources/other@2x.png")); - } - - rmDirR(relativeBuildDir()); - params.arguments.push_back("modules.cpp.minimumMacosVersion:'10.10'"); // force CAR generation - QCOMPARE(runQbs(params), 0); + QVERIFY((bool)m_qbsStdout.contains("compiling empty.xcassets")); // empty asset catalogs must still produce output - if (xcodeVersion >= qbs::Version(5)) { - QVERIFY((bool)m_qbsStdout.contains("compiling empty.xcassets")); - // No matter what, we need a 10.9 host to build CAR files - if (HostOsInfo::hostOsVersion() >= qbs::Version(10, 9)) { - QVERIFY(regularFileExists(relativeProductBuildDir("assetcatalogempty") - + "/assetcatalogempty.app/Contents/Resources/Assets.car")); - } else { - QVERIFY(regularFileExists(relativeProductBuildDir("assetcatalogempty") - + "/assetcatalogempty.app/Contents/Resources/empty.icns")); - QVERIFY(regularFileExists(relativeProductBuildDir("assetcatalogempty") - + "/assetcatalogempty.app/Contents/Resources/other.png")); - QVERIFY(regularFileExists(relativeProductBuildDir("assetcatalogempty") - + "/assetcatalogempty.app/Contents/Resources/other@2x.png")); - } - } + QVERIFY((bool)m_qbsStdout.contains("compiling empty.xcassets")); + QVERIFY(regularFileExists(relativeProductBuildDir("assetcatalogempty") + + "/assetcatalogempty.app/Contents/Resources/Assets.car")); // this asset catalog happens to have an embedded icon set, // but this should NOT be built since it is not in the files list @@ -301,19 +474,10 @@ void TestBlackboxApple::bundleStructure() { QFETCH(QString, productName); QFETCH(QString, productTypeIdentifier); - QFETCH(bool, isShallow); QDir::setCurrent(testDataDir + "/bundle-structure"); QbsRunParameters params(QStringList{"qbs.installPrefix:''"}); params.arguments << "project.buildableProducts:" + productName; - if (isShallow) { - // Coerce shallow bundles - don't set bundle.isShallow directly because we want to test the - // automatic detection - const auto xcode5 = findXcodeVersion() >= qbs::Version(5); - params.arguments - << "modules.qbs.targetPlatform:ios" - << (xcode5 ? "qbs.architectures:arm64" : "qbs.architectures:armv7a"); - } if (productName == "ABadApple" || productName == "ABadThirdParty") params.expectFailure = true; @@ -330,7 +494,10 @@ void TestBlackboxApple::bundleStructure() QCOMPARE(status, 0); - if (!isShallow) { + if (m_qbsStdout.contains("bundle.isShallow: false")) { + // Test shallow bundles detection - bundles are not shallow only on macOS, so also check + // the qbs.targetOS property + QVERIFY2(m_qbsStdout.contains("qbs.targetOS: macos"), m_qbsStdout); if (productName == "A") { QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app").isRegularDir()); QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents").isRegularDir()); @@ -424,7 +591,9 @@ void TestBlackboxApple::bundleStructure() QVERIFY(QFileInfo2(defaultInstallRoot + "/G/ContentInfo.plist").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/G/Contents/resource.txt").isRegularFile()); } - } else { + } else if (m_qbsStdout.contains("bundle.isShallow: true")) { + QVERIFY2(m_qbsStdout.contains("qbs.targetOS:"), m_qbsStdout); + QVERIFY2(!m_qbsStdout.contains("qbs.targetOS: macos"), m_qbsStdout); if (productName == "A") { QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app").isRegularDir()); QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/A").isRegularFile()); @@ -502,6 +671,8 @@ void TestBlackboxApple::bundleStructure() QVERIFY(QFileInfo2(defaultInstallRoot + "/G/ContentInfo.plist").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/G/Contents/resource.txt").isRegularFile()); } + } else { + QVERIFY2(false, qPrintable(m_qbsStdout)); } } @@ -511,21 +682,127 @@ void TestBlackboxApple::bundleStructure_data() QTest::addColumn<QString>("productTypeIdentifier"); QTest::addColumn<bool>("isShallow"); - const auto addRows = [](bool isShallow) { - const QString s = (isShallow ? " shallow" : ""); - QTest::newRow(("A" + s).toLatin1()) << "A" << "com.apple.product-type.application" << isShallow; - QTest::newRow(("ABadApple" + s).toLatin1()) << "ABadApple" << "com.apple.product-type.will.never.exist.ever.guaranteed" << isShallow; - QTest::newRow(("ABadThirdParty" + s).toLatin1()) << "ABadThirdParty" << "org.special.third.party.non.existent.product.type" << isShallow; - QTest::newRow(("B" + s).toLatin1()) << "B" << "com.apple.product-type.framework" << isShallow; - QTest::newRow(("C" + s).toLatin1()) << "C" << "com.apple.product-type.framework.static" << isShallow; - QTest::newRow(("D" + s).toLatin1()) << "D" << "com.apple.product-type.bundle" << isShallow; - QTest::newRow(("E" + s).toLatin1()) << "E" << "com.apple.product-type.app-extension" << isShallow; - QTest::newRow(("F" + s).toLatin1()) << "F" << "com.apple.product-type.xpc-service" << isShallow; - QTest::newRow(("G" + s).toLatin1()) << "G" << "com.apple.product-type.in-app-purchase-content" << isShallow; - }; + QTest::newRow("A") << "A" << "com.apple.product-type.application"; + QTest::newRow("ABadApple") << "ABadApple" << "com.apple.product-type.will.never.exist.ever.guaranteed"; + QTest::newRow("ABadThirdParty") << "ABadThirdParty" << "org.special.third.party.non.existent.product.type"; + QTest::newRow("B") << "B" << "com.apple.product-type.framework"; + QTest::newRow("C") << "C" << "com.apple.product-type.framework.static"; + QTest::newRow("D") << "D" << "com.apple.product-type.bundle"; + QTest::newRow("E") << "E" << "com.apple.product-type.app-extension"; + QTest::newRow("F") << "F" << "com.apple.product-type.xpc-service"; + QTest::newRow("G") << "G" << "com.apple.product-type.in-app-purchase-content"; +} + +void TestBlackboxApple::byteArrayInfoPlist() +{ + QDir::setCurrent(testDataDir + "/byteArrayInfoPlist"); + + QCOMPARE(runQbs(), 0); + + const auto infoPlistPath = getInfoPlistPath( + relativeProductBuildDir("byteArrayInfoPlist") + "/byteArrayInfoPlist.app"); + QVERIFY(QFile::exists(infoPlistPath)); + const auto outFilePath = + relativeProductBuildDir("byteArrayInfoPlist") + "/bytearrayInfoPlist-Info.plist.out"; + QFile file(outFilePath); + QVERIFY(file.exists()); + QVERIFY(file.open(QIODevice::ReadOnly)); + QCOMPARE(file.readAll(), "The data value"); +} + +void TestBlackboxApple::codesign() +{ + QFETCH(int, expectedCount); + QFETCH(bool, isBundle); + QFETCH(bool, enableSigning); + QFETCH(bool, multiArch); + QFETCH(bool, multiVariant); + + const auto xcodeVersion = findXcodeVersion(); + + if (!xcodeVersion) + QSKIP("requires Xcode profile"); + + QDir::setCurrent(testDataDir + "/codesign"); + QbsRunParameters params(QStringList{"qbs.installPrefix:''"}); + // the test can't use xcode module to determine version itself + params.arguments << QStringLiteral("project.xcodeVersion:") + xcodeVersion->toString(); + params.arguments << QStringLiteral("project.isBundle:%1").arg(isBundle ? "true" : "false"); + params.arguments << QStringLiteral("project.enableSigning:%1") + .arg(enableSigning ? "true" : "false"); + params.arguments << QStringLiteral("project.multiArch:%1").arg(multiArch ? "true" : "false"); + params.arguments << QStringLiteral("project.multiVariant:%1") + .arg(multiVariant ? "true" : "false"); + + rmDirR(relativeBuildDir()); + QCOMPARE(runQbs(params), 0); + + const int codeSignCount = + QString::fromUtf8(m_qbsStdout).count(QStringLiteral("codesign")); + QCOMPARE(codeSignCount, expectedCount); + + const auto appName = isBundle ? QStringLiteral("A.app") : QStringLiteral("A"); + const auto appPath = defaultInstallRoot + "/" + appName; + QVERIFY(QFileInfo(appPath).exists()); + auto codeSignInfo = getCodeSignInfo(appPath); + QVERIFY(codeSignInfo.first != CodeSignResult::Failed); + QCOMPARE(codeSignInfo.first == CodeSignResult::Signed, enableSigning); + QCOMPARE(codeSignInfo.second.isEmpty(), !enableSigning); + if (!codeSignInfo.second.isEmpty()) { + QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Executable"))); + QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Identifier"))); + QCOMPARE(codeSignInfo.second.value(QByteArrayLiteral("Signature")), "adhoc"); + } + + const auto libName = + isBundle ? QStringLiteral("B.framework") : QStringLiteral("libB.1.0.0.dylib"); + const auto libPath = defaultInstallRoot + "/" + libName; + QVERIFY(QFileInfo(libPath).exists()); + codeSignInfo = getCodeSignInfo(libPath); + QVERIFY(codeSignInfo.first != CodeSignResult::Failed); + QCOMPARE(codeSignInfo.first == CodeSignResult::Signed, enableSigning); + QCOMPARE(codeSignInfo.second.isEmpty(), !enableSigning); + if (!codeSignInfo.second.isEmpty()) { + QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Executable"))); + QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Identifier"))); + QCOMPARE(codeSignInfo.second.value(QByteArrayLiteral("Signature")), "adhoc"); + } + + const auto pluginPath = defaultInstallRoot + "/" + QStringLiteral("C.bundle"); + QVERIFY(QFileInfo(pluginPath).exists()); + QVERIFY(QFileInfo(pluginPath).isDir() == isBundle); + codeSignInfo = getCodeSignInfo(pluginPath); + QVERIFY(codeSignInfo.first != CodeSignResult::Failed); + QCOMPARE(codeSignInfo.first == CodeSignResult::Signed, enableSigning); + QCOMPARE(codeSignInfo.second.isEmpty(), !enableSigning); + if (!codeSignInfo.second.isEmpty()) { + QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Executable"))); + QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Identifier"))); + QCOMPARE(codeSignInfo.second.value(QByteArrayLiteral("Signature")), "adhoc"); + } +} - addRows(true); - addRows(false); +void TestBlackboxApple::codesign_data() +{ + QTest::addColumn<int>("expectedCount"); + QTest::addColumn<bool>("isBundle"); + QTest::addColumn<bool>("enableSigning"); + QTest::addColumn<bool>("multiArch"); + QTest::addColumn<bool>("multiVariant"); + + QTest::newRow("standalone, unsigned") << 0 << false << false << false << false; + QTest::newRow("bundle, unsigned") << 0 << true << false << false << false; + QTest::newRow("standalone, signed") << 3 << false << true << false << false; + QTest::newRow("bundle, signed") << 3 << true << true << false << false; + // here we only sign the resulting lipo artifact + QTest::newRow("standalone, signed, multiarch") << 3 << false << true << true << false; + QTest::newRow("bundle, signed, multiarch") << 3 << true << true << true << false; + // here we sign all artifacts + QTest::newRow("standalone, signed, multivariant") << 15 << false << true << false << true; + QTest::newRow("bundle, signed, multivariant") << 15 << true << true << false << true; + QTest::newRow("standalone, signed, multiarch, multivariant") + << 15 << false << true << true << true; + QTest::newRow("bundle, signed, multiarch, multivariant") << 15 << true << true << true << true; } void TestBlackboxApple::deploymentTarget() @@ -538,6 +815,9 @@ void TestBlackboxApple::deploymentTarget() QDir::setCurrent(testDataDir + "/deploymentTarget"); + if (!findXcode()) + QSKIP("requires Xcode profile"); + QbsRunParameters params; params.arguments = QStringList() << "--command-echo-mode" @@ -591,52 +871,54 @@ void TestBlackboxApple::deploymentTarget_data() } QTest::newRow("macos x86_64") << "macosx" << macos << "x86_64" << "-triple x86_64-apple-macosx10.6" - << "-macosx_version_min 10.6"; + << "10.6"; if (xcodeVersion >= qbs::Version(6)) QTest::newRow("macos x86_64h") << "macosx" << macos << "x86_64h" << "-triple x86_64h-apple-macosx10.12" - << "-macosx_version_min 10.12"; + << "10.12"; QTest::newRow("ios armv7a") << "iphoneos" << ios << "armv7a" << "-triple thumbv7-apple-ios6.0" - << "-iphoneos_version_min 6.0"; + << "6.0"; QTest::newRow("ios armv7s") << "iphoneos" <<ios << "armv7s" << "-triple thumbv7s-apple-ios7.0" - << "-iphoneos_version_min 7.0"; + << "7.0"; if (xcodeVersion >= qbs::Version(5)) QTest::newRow("ios arm64") << "iphoneos" <<ios << "arm64" << "-triple arm64-apple-ios7.0" - << "-iphoneos_version_min 7.0"; + << "7.0"; QTest::newRow("ios-simulator x86") << "iphonesimulator" << ios_sim << "x86" << "-triple i386-apple-ios6.0" - << "-ios_simulator_version_min 6.0"; + << "6.0"; if (xcodeVersion >= qbs::Version(5)) QTest::newRow("ios-simulator x86_64") << "iphonesimulator" << ios_sim << "x86_64" << "-triple x86_64-apple-ios7.0" - << "-ios_simulator_version_min 7.0"; + << "7.0"; if (xcodeVersion >= qbs::Version(7)) { if (xcodeVersion >= qbs::Version(7, 1)) { QTest::newRow("tvos arm64") << "appletvos" << tvos << "arm64" << "-triple arm64-apple-tvos9.0" - << "-tvos_version_min 9.0"; + << "9.0"; QTest::newRow("tvos-simulator x86_64") << "appletvsimulator" << tvos_sim << "x86_64" << "-triple x86_64-apple-tvos9.0" - << "-tvos_simulator_version_min 9.0"; + << "9.0"; } QTest::newRow("watchos armv7k") << "watchos" << watchos << "armv7k" << "-triple thumbv7k-apple-watchos2.0" - << "-watchos_version_min 2.0"; + << "2.0"; QTest::newRow("watchos-simulator x86") << "watchsimulator" << watchos_sim << "x86" << "-triple i386-apple-watchos2.0" - << "-watchos_simulator_version_min 2.0"; + << "2.0"; } } void TestBlackboxApple::dmg() { + if (qEnvironmentVariableIsSet("GITHUB_ACTIONS")) + QSKIP("Skip this test when running on GitHub"); QDir::setCurrent(testDataDir + "/apple-dmg"); QCOMPARE(runQbs(), 0); } @@ -669,16 +951,29 @@ void TestBlackboxApple::frameworkStructure() QbsRunParameters params; QCOMPARE(runQbs(params), 0); - QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Widget")); - QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Headers/Widget.h")); - QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/PrivateHeaders/WidgetPrivate.h")); - QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Resources/BaseResource")); - QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Resources/en.lproj/EnglishResource")); - QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/Current")); - QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Widget")); - QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Headers")); - QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/PrivateHeaders")); - QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Resources")); + if (m_qbsStdout.contains("isShallow: false")) { + QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Widget")); + QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Headers/Widget.h")); + QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/PrivateHeaders/WidgetPrivate.h")); + QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Resources/BaseResource")); + QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Resources/en.lproj/EnglishResource")); + QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/Current")); + QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Widget")); + QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Headers")); + QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/PrivateHeaders")); + QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Resources")); + } else if (m_qbsStdout.contains("isShallow: true")) { + QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Headers")); + QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/PrivateHeaders")); + QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Widget")); + QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Headers/Widget.h")); + QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/PrivateHeaders/WidgetPrivate.h")); + QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/BaseResource")); + QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/en.lproj/EnglishResource")); + QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Widget")); + } else { + QVERIFY2(false, qPrintable(m_qbsStdout)); + } params.command = "resolve"; params.arguments = QStringList() << "project.includeHeaders:false"; @@ -708,7 +1003,15 @@ void TestBlackboxApple::iconsetApp() params.arguments = QStringList() << "-f" << "iconsetapp.qbs"; QCOMPARE(runQbs(params), 0); - QVERIFY(regularFileExists(relativeProductBuildDir("iconsetapp") + "/iconsetapp.app/Contents/Resources/white.icns")); + if (m_qbsStdout.contains("isShallow: false")) { + QVERIFY(regularFileExists(relativeProductBuildDir("iconsetapp") + + "/iconsetapp.app/Contents/Resources/white.icns")); + } else if (m_qbsStdout.contains("isShallow: true")) { + QVERIFY(regularFileExists(relativeProductBuildDir("iconsetapp") + + "/iconsetapp.app/white.icns")); + } else { + QVERIFY2(false, qPrintable(m_qbsStdout)); + } } void TestBlackboxApple::infoPlist() @@ -719,40 +1022,74 @@ void TestBlackboxApple::infoPlist() params.arguments = QStringList() << "-f" << "infoplist.qbs"; QCOMPARE(runQbs(params), 0); - auto infoplistPath = relativeProductBuildDir("infoplist") - + "/infoplist.app/Contents/Info.plist"; - if (!QFile::exists(infoplistPath)) - infoplistPath = relativeProductBuildDir("infoplist") + "/infoplist.app/Info.plist"; - QVERIFY(QFile::exists(infoplistPath)); - QProcess plutil; - plutil.start("plutil", { - QStringLiteral("-convert"), - QStringLiteral("json"), - infoplistPath - }); - QVERIFY2(plutil.waitForStarted(), qPrintable(plutil.errorString())); - QVERIFY2(plutil.waitForFinished(), qPrintable(plutil.errorString())); - QVERIFY2(plutil.exitCode() == 0, qPrintable(plutil.readAllStandardError().constData())); + const auto infoPlistPath = getInfoPlistPath( + relativeProductBuildDir("infoplist") + "/infoplist.app"); + QVERIFY(QFile::exists(infoPlistPath)); + const auto content = readInfoPlistFile(infoPlistPath); + QVERIFY(!content.isEmpty()); - QFile infoplist(infoplistPath); - QVERIFY(infoplist.open(QIODevice::ReadOnly)); - QJsonParseError error; - const auto json = QJsonDocument::fromJson(infoplist.readAll(), &error); - QCOMPARE(error.error, QJsonParseError::NoError); - QVERIFY(json.isObject()); // common values - QCOMPARE(json.object().value(QStringLiteral("CFBundleIdentifier")), + QCOMPARE(content.value(QStringLiteral("CFBundleIdentifier")), QStringLiteral("org.example.infoplist")); - QCOMPARE(json.object().value(QStringLiteral("CFBundleName")), QStringLiteral("infoplist")); - QCOMPARE(json.object().value(QStringLiteral("CFBundleExecutable")), + QCOMPARE(content.value(QStringLiteral("CFBundleName")), QStringLiteral("infoplist")); + QCOMPARE(content.value(QStringLiteral("CFBundleExecutable")), QStringLiteral("infoplist")); - if (!json.object().contains(QStringLiteral("SDKROOT"))) { // macOS-specific values - QCOMPARE(json.object().value("LSMinimumSystemVersion"), QStringLiteral("10.7")); - QVERIFY(json.object().contains("NSPrincipalClass")); + if (!content.contains(QStringLiteral("SDKROOT"))) { // macOS-specific values + QCOMPARE(content.value("LSMinimumSystemVersion"), QStringLiteral("10.7")); + QCOMPARE(content.value("NSPrincipalClass"), QStringLiteral("NSApplication")); + QCOMPARE(content.value(QStringLiteral("NSSupportsAutomaticGraphicsSwitching")), true); + } else { + // QBS-1447: UIDeviceFamily was set to a string instead of an array + const auto family = content.value(QStringLiteral("UIDeviceFamily")); + if (family.isValid()) { + // Prior to Qt 5.15, int gets converted to a double when exporting plist as JSON + QVERIFY(testVariantListType(family, QMetaType::LongLong) + || testVariantListType(family, QMetaType::Double)); + } + const auto caps = content.value(QStringLiteral("UIRequiredDeviceCapabilities")); + if (caps.isValid()) + QVERIFY(testVariantListType(caps, QMetaType::QString)); + const auto orientations = content.value(QStringLiteral("UIRequiredDeviceCapabilities")); + if (orientations.isValid()) + QVERIFY(testVariantListType(orientations, QMetaType::QString)); } } +void TestBlackboxApple::infoPlistVariables() +{ + QDir::setCurrent(testDataDir + "/infoPlistVariables"); + + QbsRunParameters params; + params.arguments = QStringList() << "-f" << "infoPlistVariables.qbs"; + QCOMPARE(runQbs(params), 0); + + const auto infoPlistPath = getInfoPlistPath( + relativeProductBuildDir("infoPlistVariables") + "/infoPlistVariables.app"); + QVERIFY(QFile::exists(infoPlistPath)); + const auto content = readInfoPlistFile(infoPlistPath); + QVERIFY(!content.isEmpty()); + + QCOMPARE(content.value(QStringLiteral("Curly")), + QStringLiteral("infoPlistVariables")); + QCOMPARE(content.value(QStringLiteral("Braces")), + QStringLiteral("infoPlistVariables")); + QCOMPARE(content.value(QStringLiteral("At")), + QStringLiteral("infoPlistVariables")); + QCOMPARE(content.value(QStringLiteral("CurlyMult")), + QStringLiteral("infoPlistVariables_infoPlistVariables")); + QCOMPARE(content.value(QStringLiteral("BracesMult")), + QStringLiteral("infoPlistVariables_infoPlistVariables")); + QCOMPARE(content.value(QStringLiteral("AtMult")), + QStringLiteral("infoPlistVariables_infoPlistVariables")); + QCOMPARE(content.value(QStringLiteral("CurlyNested")), + QStringLiteral("infoPlistVariables")); + QCOMPARE(content.value(QStringLiteral("BracesNested")), + QStringLiteral("infoPlistVariables")); + QCOMPARE(content.value(QStringLiteral("WithDefault")), + QStringLiteral("DEFAULT")); +} + void TestBlackboxApple::objcArc() { QDir::setCurrent(testDataDir + QLatin1String("/objc-arc")); @@ -760,8 +1097,36 @@ void TestBlackboxApple::objcArc() QCOMPARE(runQbs(), 0); } +void TestBlackboxApple::overrideInfoPlist() +{ + QDir::setCurrent(testDataDir + "/overrideInfoPlist"); + + QCOMPARE(runQbs(), 0); + + const auto infoPlistPath = getInfoPlistPath( + relativeProductBuildDir("overrideInfoPlist") + "/overrideInfoPlist.app"); + QVERIFY(QFile::exists(infoPlistPath)); + const auto content = readInfoPlistFile(infoPlistPath); + QVERIFY(!content.isEmpty()); + + // test we do not override custom values by default + QCOMPARE(content.value(QStringLiteral("DefaultValue")), + QStringLiteral("The default value")); + // test we can override custom values + QCOMPARE(content.value(QStringLiteral("OverriddenValue")), + QStringLiteral("The overridden value")); + // test we do not override special values set by Qbs by default + QCOMPARE(content.value(QStringLiteral("CFBundleExecutable")), + QStringLiteral("overrideInfoPlist")); + // test we can override special values set by Qbs + QCOMPARE(content.value(QStringLiteral("CFBundleName")), QStringLiteral("My Bundle")); +} + void TestBlackboxApple::xcode() { + if (!findXcode()) + QSKIP("requires Xcode profile"); + QProcess xcodeSelect; xcodeSelect.start("xcode-select", QStringList() << "--print-path"); QVERIFY2(xcodeSelect.waitForStarted(), qPrintable(xcodeSelect.errorString())); @@ -775,8 +1140,10 @@ void TestBlackboxApple::xcode() xcodebuildShowSdks.start("xcrun", QStringList() << "xcodebuild" << "-showsdks"); QVERIFY2(xcodebuildShowSdks.waitForStarted(), qPrintable(xcodebuildShowSdks.errorString())); QVERIFY2(xcodebuildShowSdks.waitForFinished(), qPrintable(xcodebuildShowSdks.errorString())); - QVERIFY2(xcodebuildShowSdks.exitCode() == 0, qPrintable(xcodebuildShowSdks.readAllStandardError().constData())); - const auto lines = QString::fromLocal8Bit(xcodebuildShowSdks.readAllStandardOutput().trimmed()).split('\n', QString::SkipEmptyParts); + QVERIFY2(xcodebuildShowSdks.exitCode() == 0, + qPrintable(xcodebuildShowSdks.readAllStandardError().constData())); + const auto lines = QString::fromLocal8Bit(xcodebuildShowSdks.readAllStandardOutput().trimmed()) + .split('\n', Qt::SkipEmptyParts); for (const QString &line : lines) { static const std::regex regexp("^.+\\s+\\-sdk\\s+([a-z]+)([0-9]+\\.[0-9]+)$"); const auto ln = line.toStdString(); @@ -812,11 +1179,10 @@ void TestBlackboxApple::xcode() QTEST_MAIN(TestBlackboxApple) -QVariantMap TestBlackboxApple::findXcode(int *status) +std::optional<QVariantMap> TestBlackboxApple::findXcode(int *status) { QTemporaryDir temp; QbsRunParameters params = QStringList({"-f", testDataDir + "/find/find-xcode.qbs"}); - params.profile = "none"; params.buildDirectory = temp.path(); const int res = runQbs(params); if (status) @@ -825,10 +1191,16 @@ QVariantMap TestBlackboxApple::findXcode(int *status) + "/xcode.json"); if (!file.open(QIODevice::ReadOnly)) return {}; - return QJsonDocument::fromJson(file.readAll()).toVariant().toMap(); + auto result = QJsonDocument::fromJson(file.readAll()).toVariant().toMap(); + if (!result["present"].toBool()) + return {}; + return result; } -qbs::Version TestBlackboxApple::findXcodeVersion() +std::optional<qbs::Version> TestBlackboxApple::findXcodeVersion() { - return qbs::Version::fromString(findXcode().value("version").toString()); + const auto xcode = findXcode(); + if (!xcode) + return {}; + return qbs::Version::fromString(xcode->value("version").toString()); } diff --git a/tests/auto/blackbox/tst_blackboxapple.h b/tests/auto/blackbox/tst_blackboxapple.h index 76711ddf5..a51414917 100644 --- a/tests/auto/blackbox/tst_blackboxapple.h +++ b/tests/auto/blackbox/tst_blackboxapple.h @@ -31,6 +31,8 @@ #include "tst_blackboxbase.h" +#include <optional> + namespace qbs { class Version; } // namespace qbs @@ -48,12 +50,16 @@ public slots: private slots: void appleMultiConfig(); void aggregateDependencyLinking(); + void appiconset(); void assetCatalog(); void assetCatalog_data(); void assetCatalogsEmpty(); void assetCatalogsMultiple(); void bundleStructure(); void bundleStructure_data(); + void byteArrayInfoPlist(); + void codesign(); + void codesign_data(); void deploymentTarget(); void deploymentTarget_data(); void dmg(); @@ -62,12 +68,14 @@ private slots: void iconset(); void iconsetApp(); void infoPlist(); + void infoPlistVariables(); void objcArc(); + void overrideInfoPlist(); void xcode(); private: - QVariantMap findXcode(int *status = nullptr); - qbs::Version findXcodeVersion(); + std::optional<QVariantMap> findXcode(int *status = nullptr); + std::optional<qbs::Version> findXcodeVersion(); }; #endif // TST_BLACKBOXAPPLE_H diff --git a/tests/auto/blackbox/tst_blackboxbaremetal.cpp b/tests/auto/blackbox/tst_blackboxbaremetal.cpp new file mode 100644 index 000000000..ec6ffcdc6 --- /dev/null +++ b/tests/auto/blackbox/tst_blackboxbaremetal.cpp @@ -0,0 +1,311 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "tst_blackboxbaremetal.h" + +#include "../shared.h" + +#include <QtCore/qdir.h> +#include <QtCore/qregularexpression.h> + +static bool extractToolset(const QByteArray &output, + QByteArray &toolchain, QByteArray &architecture) +{ + const QRegularExpression re("%%([\\w\\-]+)%%, %%(\\w+)%%"); + QRegularExpressionMatchIterator it = re.globalMatch(output); + if (!it.hasNext()) + return false; + const QRegularExpressionMatch match = it.next(); + toolchain = match.captured(1).toLocal8Bit(); + architecture = match.captured(2).toLocal8Bit(); + return true; +} + +static bool extractCompilerIncludePaths(const QByteArray &output, QStringList &compilerIncludePaths) +{ + const QRegularExpression re("%%([^%%]+)%%"); + QRegularExpressionMatchIterator it = re.globalMatch(output); + if (!it.hasNext()) + return false; + const QRegularExpressionMatch match = it.next(); + compilerIncludePaths = match.captured(1).split(","); + return true; +} + +static bool extractQuitedValue(const QByteArray &output, QString &pattern) +{ + const QRegularExpression re("%%(.+)%%"); + const QRegularExpressionMatch match = re.match(output); + if (!match.hasMatch()) + return false; + pattern = match.captured(1); + return true; +} + +static QByteArray unsupportedToolsetMessage(const QByteArray &output) +{ + QByteArray toolchain; + QByteArray architecture; + extractToolset(output, toolchain, architecture); + return "Unsupported toolchain '" + toolchain + + "' for architecture '" + architecture + "'"; +} + +static QByteArray brokenProbeMessage(const QByteArray &output) +{ + QByteArray toolchain; + QByteArray architecture; + extractToolset(output, toolchain, architecture); + return "Broken probe for toolchain '" + toolchain + + "' for architecture '" + architecture + "'"; +} + +TestBlackboxBareMetal::TestBlackboxBareMetal() + : TestBlackboxBase (SRCDIR "/testdata-baremetal", "blackbox-baremetal") +{ +} + +void TestBlackboxBareMetal::targetPlatform() +{ + QDir::setCurrent(testDataDir + "/target-platform"); + QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); + if (m_qbsStdout.contains("unsupported toolset:")) + QSKIP(unsupportedToolsetMessage(m_qbsStdout)); + const bool hasNoPlatform = m_qbsStdout.contains("has no platform: true"); + QCOMPARE(hasNoPlatform, true); + const bool hasNoOS = m_qbsStdout.contains("has no os: true"); + QCOMPARE(hasNoOS, true); +} + +void TestBlackboxBareMetal::application_data() +{ + QTest::addColumn<QString>("testPath"); + QTest::newRow("one-object-application") << "/one-object-application"; + QTest::newRow("two-object-application") << "/two-object-application"; + QTest::newRow("one-object-asm-application") << "/one-object-asm-application"; +} + +void TestBlackboxBareMetal::application() +{ + QFETCH(QString, testPath); + QDir::setCurrent(testDataDir + testPath); + QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); + if (m_qbsStdout.contains("unsupported toolset:")) + QSKIP(unsupportedToolsetMessage(m_qbsStdout)); + QCOMPARE(runQbs(QbsRunParameters("build")), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); + QCOMPARE(runQbs(QbsRunParameters("run")), 0); +} + +void TestBlackboxBareMetal::staticLibraryDependencies() +{ + QDir::setCurrent(testDataDir + "/static-library-dependencies"); + QCOMPARE(runQbs(QStringList{"-p", "lib-a,lib-b,lib-c,lib-d,lib-e"}), 0); + QCOMPARE(runQbs(QStringList{"--command-echo-mode", "command-line"}), 0); + const QByteArray output = m_qbsStdout + '\n' + m_qbsStderr; + QVERIFY(output.contains("lib-a")); + QVERIFY(output.contains("lib-b")); + QVERIFY(output.contains("lib-c")); + QVERIFY(output.contains("lib-d")); + QVERIFY(output.contains("lib-e")); +} + +void TestBlackboxBareMetal::externalStaticLibraries() +{ + QDir::setCurrent(testDataDir + "/external-static-libraries"); + QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); + if (m_qbsStdout.contains("unsupported toolset:")) + QSKIP(unsupportedToolsetMessage(m_qbsStdout)); + QCOMPARE(runQbs(), 0); +} + +void TestBlackboxBareMetal::sharedLibraries() +{ + QDir::setCurrent(testDataDir + "/shared-libraries"); + QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); + if (m_qbsStdout.contains("unsupported toolset:")) + QSKIP(unsupportedToolsetMessage(m_qbsStdout)); + QCOMPARE(runQbs(QbsRunParameters("build")), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); + QCOMPARE(runQbs(QbsRunParameters("run")), 0); + QVERIFY2(m_qbsStdout.contains("Hello from app"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("Hello from lib"), m_qbsStdout.constData()); +} + +void TestBlackboxBareMetal::userIncludePaths() +{ + QDir::setCurrent(testDataDir + "/user-include-paths"); + QCOMPARE(runQbs(), 0); +} + +void TestBlackboxBareMetal::systemIncludePaths() +{ + QDir::setCurrent(testDataDir + "/system-include-paths"); + QCOMPARE(runQbs(), 0); +} + +void TestBlackboxBareMetal::distributionIncludePaths() +{ + QDir::setCurrent(testDataDir + "/distribution-include-paths"); + QCOMPARE(runQbs(), 0); +} + +void TestBlackboxBareMetal::compilerIncludePaths() +{ + QDir::setCurrent(testDataDir + "/compiler-include-paths"); + QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); + if (!m_qbsStdout.contains("compilerIncludePaths:")) + QFAIL("No compiler include paths exists"); + + QStringList includePaths; + QVERIFY(extractCompilerIncludePaths(m_qbsStdout, includePaths)); + QVERIFY(includePaths.count() > 0); + for (const auto &includePath : includePaths) { + const QDir dir(includePath); + QVERIFY(dir.exists()); + } +} + +void TestBlackboxBareMetal::preincludeHeaders() +{ + QDir::setCurrent(testDataDir + "/preinclude-headers"); + QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); + if (m_qbsStdout.contains("unsupported toolset:")) + QSKIP(unsupportedToolsetMessage(m_qbsStdout)); + QCOMPARE(runQbs(), 0); +} + +void TestBlackboxBareMetal::defines() +{ + QDir::setCurrent(testDataDir + "/defines"); + QCOMPARE(runQbs(), 0); +} + +void TestBlackboxBareMetal::compilerListingFiles_data() +{ + QTest::addColumn<bool>("generateListing"); + QTest::addColumn<QString>("customListingSuffix"); + QTest::newRow("do-not-generate-compiler-listing") << false << ""; + QTest::newRow("generate-default-compiler-listing") << true << ""; + QTest::newRow("generate-custom-compiler-listing") << true << ".lll"; +} + +void TestBlackboxBareMetal::compilerListingFiles() +{ + QFETCH(bool, generateListing); + QFETCH(QString, customListingSuffix); + QDir::setCurrent(testDataDir + "/compiler-listing"); + + rmDirR(relativeBuildDir()); + QStringList args = {QStringLiteral("modules.cpp.generateCompilerListingFiles:%1") + .arg(generateListing ? "true" : "false")}; + if (!customListingSuffix.isEmpty()) + args << QStringLiteral("modules.cpp.compilerListingSuffix:%1").arg(customListingSuffix); + + QCOMPARE(runQbs(QbsRunParameters("resolve", args)), 0); + if (m_qbsStdout.contains("unsupported toolset:")) + QSKIP(unsupportedToolsetMessage(m_qbsStdout)); + if (!m_qbsStdout.contains("compiler listing suffix:")) + QFAIL("No current compiler listing suffix pattern exists"); + + QString compilerListingSuffix; + if (!extractQuitedValue(m_qbsStdout, compilerListingSuffix)) + QFAIL("Unable to extract current compiler listing suffix"); + + if (!customListingSuffix.isEmpty()) + QCOMPARE(compilerListingSuffix, customListingSuffix); + + QCOMPARE(runQbs(QbsRunParameters(args)), 0); + const QString productBuildDir = relativeProductBuildDir("compiler-listing"); + const QString hash = inputDirHash("."); + const QString mainListing = productBuildDir + "/" + hash + + "/main.c" + compilerListingSuffix; + QCOMPARE(regularFileExists(mainListing), generateListing); + const QString funListing = productBuildDir + "/" + hash + + "/fun.c" + compilerListingSuffix; + QCOMPARE(regularFileExists(funListing), generateListing); +} + +void TestBlackboxBareMetal::linkerMapFile_data() +{ + QTest::addColumn<bool>("generateMap"); + QTest::addColumn<QString>("customMapSuffix"); + QTest::newRow("do-not-generate-linker-map") << false << ""; + QTest::newRow("generate-default-linker-map") << true << ""; + QTest::newRow("generate-custom-linker-map") << true << ".mmm"; +} + +void TestBlackboxBareMetal::linkerMapFile() +{ + QFETCH(bool, generateMap); + QFETCH(QString, customMapSuffix); + QDir::setCurrent(testDataDir + "/linker-map"); + + rmDirR(relativeBuildDir()); + QStringList args = {QStringLiteral("modules.cpp.generateLinkerMapFile:%1") + .arg(generateMap ? "true" : "false")}; + if (!customMapSuffix.isEmpty()) + args << QStringLiteral("modules.cpp.linkerMapSuffix:%1").arg(customMapSuffix); + + QCOMPARE(runQbs(QbsRunParameters("resolve", args)), 0); + if (!m_qbsStdout.contains("linker map suffix:")) + QFAIL("No current linker map suffix pattern exists"); + + QString linkerMapSuffix; + if (!extractQuitedValue(m_qbsStdout, linkerMapSuffix)) + QFAIL("Unable to extract current linker map suffix"); + + if (!customMapSuffix.isEmpty()) + QCOMPARE(linkerMapSuffix, customMapSuffix); + + QCOMPARE(runQbs(QbsRunParameters(args)), 0); + const QString productBuildDir = relativeProductBuildDir("linker-map"); + const QString linkerMap = productBuildDir + "/linker-map" + linkerMapSuffix; + QCOMPARE(regularFileExists(linkerMap), generateMap); +} + +void TestBlackboxBareMetal::compilerDefinesByLanguage() +{ + QDir::setCurrent(testDataDir + "/compiler-defines-by-language"); + QbsRunParameters params(QStringList{ "-f", "compiler-defines-by-language.qbs" }); + QCOMPARE(runQbs(params), 0); +} + +void TestBlackboxBareMetal::toolchainProbe() +{ + QDir::setCurrent(testDataDir + "/toolchain-probe"); + QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); + if (m_qbsStdout.contains("broken probe:")) + QFAIL(brokenProbeMessage(m_qbsStdout)); +} + +QTEST_MAIN(TestBlackboxBareMetal) diff --git a/tests/auto/blackbox/tst_blackboxbaremetal.h b/tests/auto/blackbox/tst_blackboxbaremetal.h new file mode 100644 index 000000000..9c45fa63c --- /dev/null +++ b/tests/auto/blackbox/tst_blackboxbaremetal.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef TST_BLACKBOXBAREMETAL_H +#define TST_BLACKBOXBAREMETAL_H + +#include "tst_blackboxbase.h" + +class TestBlackboxBareMetal : public TestBlackboxBase +{ + Q_OBJECT + +public: + TestBlackboxBareMetal(); + +private slots: + void targetPlatform(); + + void application_data(); + void application(); + + void staticLibraryDependencies(); + void externalStaticLibraries(); + + void sharedLibraries(); + + void userIncludePaths(); + void systemIncludePaths(); + void distributionIncludePaths(); + void compilerIncludePaths(); + + void preincludeHeaders(); + + void defines(); + + void compilerListingFiles_data(); + void compilerListingFiles(); + + void linkerMapFile_data(); + void linkerMapFile(); + + void compilerDefinesByLanguage(); + + void toolchainProbe(); + +private: + +}; + +#endif // TST_BLACKBOXBAREMETAL_H diff --git a/tests/auto/blackbox/tst_blackboxbase.cpp b/tests/auto/blackbox/tst_blackboxbase.cpp index 61b0271f6..317a6b663 100644 --- a/tests/auto/blackbox/tst_blackboxbase.cpp +++ b/tests/auto/blackbox/tst_blackboxbase.cpp @@ -64,7 +64,7 @@ static bool supportsSettingsDirOption(const QString &command) { TestBlackboxBase::TestBlackboxBase(const QString &testDataSrcDir, const QString &testName) : testDataDir(testWorkDir(testName)), - testSourceDir(QDir::cleanPath(testDataSrcDir)), + testSourceDir(testDataSourceDir(testDataSrcDir)), qbsExecutableFilePath(initQbsExecutableFilePath()), defaultInstallRoot(relativeBuildDir() + QLatin1Char('/') + InstallOptions::defaultInstallRoot()) { @@ -96,14 +96,18 @@ int TestBlackboxBase::runQbs(const QbsRunParameters ¶ms) process.setWorkingDirectory(params.workingDir); process.setProcessEnvironment(params.environment); process.start(qbsExecutableFilePath, args); + int exitCode = 0; if (!process.waitForStarted() || !process.waitForFinished(testTimeoutInMsecs()) || process.exitStatus() != QProcess::NormalExit) { - m_qbsStderr = process.readAllStandardError(); if (!params.expectCrash) { QTest::qFail("qbs did not run correctly", __FILE__, __LINE__); qDebug("%s", qPrintable(process.errorString())); } - return -1; + exitCode = -1; + } else if (m_qbsStdout.contains("Memory leak:")) { + exitCode = 27; + } else { + exitCode = process.exitCode(); } m_qbsStderr = process.readAllStandardError(); @@ -111,14 +115,14 @@ int TestBlackboxBase::runQbs(const QbsRunParameters ¶ms) sanitizeOutput(&m_qbsStderr); sanitizeOutput(&m_qbsStdout); const bool shouldLog = (process.exitStatus() != QProcess::NormalExit - || process.exitCode() != 0) && !params.expectFailure; + || exitCode != 0) && !params.expectFailure; if (!m_qbsStderr.isEmpty() && (shouldLog || qEnvironmentVariableIsSet("QBS_AUTOTEST_ALWAYS_LOG_STDERR"))) qDebug("%s", m_qbsStderr.constData()); if (!m_qbsStdout.isEmpty() && (shouldLog || qEnvironmentVariableIsSet("QBS_AUTOTEST_ALWAYS_LOG_STDOUT"))) qDebug("%s", m_qbsStdout.constData()); - return process.exitCode(); + return exitCode; } /*! @@ -194,10 +198,30 @@ void TestBlackboxBase::initTestCase() QVERIFY(copyDllExportHeader(testSourceDir, testDataDir)); } +void TestBlackboxBase::validateTestProfile() +{ + const SettingsPtr s = settings(); + if (profileName() != "none" && !s->profiles().contains(profileName())) + QFAIL(QByteArray("The build profile '" + profileName().toLocal8Bit() + + "' could not be found. Please set it up on your machine.")); + if (!m_needsQt) + return; + const QStringList qmakeFilePaths = Profile(profileName(), s.get()) + .value("moduleProviders.Qt.qmakeFilePaths").toStringList(); + if (!qmakeFilePaths.empty()) + return; + if (!findExecutable(QStringList{"qmake"}).isEmpty()) + return; + QSKIP(QByteArray("The build profile '" + profileName().toLocal8Bit() + + "' is not a valid Qt profile and Qt was not found " + "in the global search paths.")); + +} + QString TestBlackboxBase::findExecutable(const QStringList &fileNames) { const QStringList path = QString::fromLocal8Bit(qgetenv("PATH")) - .split(HostOsInfo::pathListSeparator(), QString::SkipEmptyParts); + .split(HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts); for (const QString &fileName : fileNames) { QFileInfo fi(fileName); @@ -232,3 +256,34 @@ QMap<QString, QString> TestBlackboxBase::findJdkTools(int *status) {"jar", QDir::fromNativeSeparators(tools["jar"].toString())} }; } + +qbs::Version TestBlackboxBase::qmakeVersion(const QString &qmakeFilePath) +{ + QStringList arguments; + arguments << "-query" << "QT_VERSION"; + QProcess qmakeProcess; + qmakeProcess.start(qmakeFilePath, arguments); + if (!qmakeProcess.waitForStarted() || !qmakeProcess.waitForFinished() + || qmakeProcess.exitStatus() != QProcess::NormalExit) { + qDebug() << "qmake '" << qmakeFilePath << "' could not be run."; + return qbs::Version(); + } + QByteArray result = qmakeProcess.readAll().simplified(); + qbs::Version version = qbs::Version::fromString(result); + if (!version.isValid()) + qDebug() << "qmake '" << qmakeFilePath << "' version is not valid."; + return version; +} + +bool waitForProcessSuccess(QProcess &p, int msecs) +{ + if (!p.waitForStarted(msecs) || !p.waitForFinished(msecs)) { + qDebug() << p.errorString(); + return false; + } + if (p.exitCode() != 0) { + qDebug() << p.readAllStandardError(); + return false; + } + return true; +} diff --git a/tests/auto/blackbox/tst_blackboxbase.h b/tests/auto/blackbox/tst_blackboxbase.h index 251f3752d..5733cacd7 100644 --- a/tests/auto/blackbox/tst_blackboxbase.h +++ b/tests/auto/blackbox/tst_blackboxbase.h @@ -42,14 +42,14 @@ public: init(); } - QbsRunParameters(const QString &cmd, const QStringList &args = QStringList()) - : command(cmd), arguments(args) + QbsRunParameters(QString cmd, QStringList args = QStringList()) + : command(std::move(cmd)), arguments(std::move(args)) { init(); } - QbsRunParameters(const QStringList &args) - : arguments(args) + QbsRunParameters(QStringList args) + : arguments(std::move(args)) { init(); } @@ -60,7 +60,14 @@ public: expectCrash = false; profile = profileName(); settingsDir = settings()->baseDirectory(); - environment = QProcessEnvironment::systemEnvironment(); + environment = defaultEnvironment(); + } + + static QProcessEnvironment defaultEnvironment() + { + auto result = QProcessEnvironment::systemEnvironment(); + result.insert(QStringLiteral("QBS_AUTOTEST_CODE_SIGNING_REQUIRED"), QStringLiteral("0")); + return result; } QString command; @@ -83,15 +90,19 @@ public: public slots: virtual void initTestCase(); + static QString findExecutable(const QStringList &fileNames); + protected: - virtual void validateTestProfile() { } + virtual void validateTestProfile(); + + void setNeedsQt() { m_needsQt = true; } int runQbs(const QbsRunParameters ¶ms = QbsRunParameters()); void rmDirR(const QString &dir); static QByteArray unifiedLineEndings(const QByteArray &ba); static void sanitizeOutput(QByteArray *ba); static void ccp(const QString &sourceDirPath, const QString &targetDirPath); - static QString findExecutable(const QStringList &fileNames); QMap<QString, QString> findJdkTools(int *status); + static qbs::Version qmakeVersion(const QString &qmakeFilePath); const QString testDataDir; const QString testSourceDir; @@ -100,6 +111,9 @@ protected: QByteArray m_qbsStderr; QByteArray m_qbsStdout; + int m_needsQt = false; }; +bool waitForProcessSuccess(QProcess &p, int msecs = 30000); + #endif // TST_BLACKBOXBASE_H diff --git a/tests/auto/blackbox/tst_blackboxexamples.cpp b/tests/auto/blackbox/tst_blackboxexamples.cpp new file mode 100644 index 000000000..13ccb7796 --- /dev/null +++ b/tests/auto/blackbox/tst_blackboxexamples.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "tst_blackboxexamples.h" + +#include <QtCore/qdir.h> +#include <QtCore/qdiriterator.h> + +QStringList TestBlackboxExamples::collectExamples(const QString &dirPath) +{ + QStringList result; + QDir dir(dirPath); + const auto subDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); + for (const auto &subDir : subDirs) { + const auto path = dir.filePath(subDir); + if (!QFileInfo::exists(path + "/" + subDir + ".qbs")) + continue; + result.append(QDir(testDataDir).relativeFilePath(path)); + } + return result; +} + +TestBlackboxExamples::TestBlackboxExamples() + : TestBlackboxBase(SRCDIR "/../../../examples/", "blackbox-examples") +{ + setNeedsQt(); +} + +void TestBlackboxExamples::baremetal_data() +{ + QTest::addColumn<QString>("example"); + + QDir baremetal(testDataDir + "/baremetal/"); + const auto subDirs = baremetal.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); + for (const auto &subDir : subDirs) { + const auto examples = collectExamples(baremetal.filePath(subDir)); + for (const auto &example: examples) { + const auto relativePath = baremetal.relativeFilePath(example); + QTest::newRow(relativePath.toUtf8().data()) << relativePath; + } + } +} + +void TestBlackboxExamples::baremetal() +{ + QFETCH(QString, example); + + QVERIFY(QDir::setCurrent(testDataDir + "/" + example)); + QCOMPARE(runQbs(), 0); +} + +void TestBlackboxExamples::examples_data() +{ + QTest::addColumn<QString>("example"); + + auto examples = collectExamples(testDataDir); + examples.append(collectExamples(testDataDir + "/protobuf")); + examples.append(collectExamples(testDataDir + "/flatbuffers")); + std::sort(examples.begin(), examples.end()); + + for (const auto &example: examples) { + if (example == u"baremetal") + continue; + QTest::newRow(example.toUtf8().data()) << example; + } +} + +void TestBlackboxExamples::examples() +{ + QFETCH(QString, example); + + QVERIFY(QDir::setCurrent(testDataDir + "/" + example)); + QbsRunParameters params( + {QStringLiteral("-f"), QFileInfo(example).fileName() + QStringLiteral(".qbs")}); + QCOMPARE(runQbs(params), 0); +} + +QTEST_MAIN(TestBlackboxExamples) diff --git a/tests/auto/blackbox/tst_blackboxexamples.h b/tests/auto/blackbox/tst_blackboxexamples.h new file mode 100644 index 000000000..bea8be768 --- /dev/null +++ b/tests/auto/blackbox/tst_blackboxexamples.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef TST_BLACKBOXEXAMPLES_H +#define TST_BLACKBOXEXAMPLES_H + +#include "tst_blackboxbase.h" + +class TestBlackboxExamples : public TestBlackboxBase +{ + Q_OBJECT + +private: + QStringList collectExamples(const QString &dirPath); + +public: + TestBlackboxExamples(); + +private slots: + void baremetal_data(); + void baremetal(); + void examples_data(); + void examples(); +}; + +#endif // TST_BLACKBOXEXAMPLES_H diff --git a/tests/auto/blackbox/tst_blackboxjava.cpp b/tests/auto/blackbox/tst_blackboxjava.cpp index f7feb0612..4ddd6cdda 100644 --- a/tests/auto/blackbox/tst_blackboxjava.cpp +++ b/tests/auto/blackbox/tst_blackboxjava.cpp @@ -39,7 +39,9 @@ using qbs::Internal::HostOsInfo; using qbs::Profile; -TestBlackboxJava::TestBlackboxJava() : TestBlackboxBase (SRCDIR "/testdata-java", "blackbox-java") +TestBlackboxJava::TestBlackboxJava() + : TestBlackboxBase (SRCDIR "/testdata-java", "blackbox-java"), + m_blacklistedJdks(qgetenv("QBS_AUTOTEST_JDK_BLACKLIST")) { } @@ -73,6 +75,9 @@ void TestBlackboxJava::java() QSKIP("java.jdkPath not set and automatic detection failed"); } + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Skip test in cross-compiled build"); + QCOMPARE(status, 0); const QStringList classFiles = @@ -93,7 +98,7 @@ void TestBlackboxJava::java() // Now check whether we correctly predicted the class file output paths. QCOMPARE(runQbs(QbsRunParameters("clean")), 0); - for (const QString &classFile : qAsConst(classFiles1)) { + for (const QString &classFile : std::as_const(classFiles1)) { QVERIFY2(!regularFileExists(classFile), qPrintable(classFile)); } @@ -119,7 +124,7 @@ void TestBlackboxJava::java() if (process.waitForStarted()) { QVERIFY2(process.waitForFinished(), qPrintable(process.errorString())); const QByteArray stdOut = process.readAllStandardOutput(); - QVERIFY2(stdOut.contains("Class-Path: car_jar.jar random_stuff.jar"), stdOut.constData()); + QVERIFY2(stdOut.contains("Class-Path: random_stuff.jar car_jar.jar"), stdOut.constData()); QVERIFY2(stdOut.contains("Main-Class: Vehicles"), stdOut.constData()); QVERIFY2(stdOut.contains("Some-Property: Some-Value"), stdOut.constData()); QVERIFY2(stdOut.contains("Additional-Property: Additional-Value"), stdOut.constData()); @@ -145,8 +150,11 @@ void TestBlackboxJava::javaDependencyTracking() QDir::setCurrent(testDataDir + "/java"); QbsRunParameters rp; rp.arguments.push_back("--check-outputs"); - if (!jdkPath.isEmpty()) + if (!jdkPath.isEmpty()) { + if (m_blacklistedJdks.contains(jdkPath)) + QSKIP("skipping blacklisted JDK"); rp.arguments << ("modules.java.jdkPath:" + jdkPath); + } if (!javaVersion.isEmpty()) rp.arguments << ("modules.java.languageVersion:'" + javaVersion + "'"); rmDirR(relativeBuildDir()); @@ -167,7 +175,7 @@ void TestBlackboxJava::javaDependencyTracking_data() auto getSpecificJdkVersion = [](const QString &jdkVersion) -> QString { if (HostOsInfo::isMacosHost()) { QProcess java_home; - java_home.start("/usr/libexec/java_home", QStringList() << "--version" << jdkVersion); + java_home.start("/usr/libexec/java_home", {"--version", jdkVersion, "--failfast"}); java_home.waitForFinished(); if (java_home.exitStatus() == QProcess::NormalExit && java_home.exitCode() == 0) return QString::fromLocal8Bit(java_home.readAllStandardOutput().trimmed()); @@ -184,6 +192,7 @@ void TestBlackboxJava::javaDependencyTracking_data() "/usr/lib/jvm/java-" + minorVersion + "-openjdk" + dpkgArch("-"), // Debian "/usr/lib/jvm/java-" + minorVersion + "-openjdk", // Arch "/usr/lib/jvm/jre-1." + minorVersion + ".0-openjdk", // Fedora + "/usr/lib64/jvm/java-1." + minorVersion + ".0-openjdk", // OpenSuSE }; for (const QString &searchPath : searchPaths) { if (QFile::exists(searchPath + "/bin/javac")) @@ -194,7 +203,7 @@ void TestBlackboxJava::javaDependencyTracking_data() return {}; }; - static const auto knownJdkVersions = QStringList() << "1.6" << "1.7" << "1.8" << "1.9" + static const auto knownJdkVersions = QStringList() << "1.7" << "1.8" << "1.9" << QString(); // default JDK; QStringList seenJdkVersions; for (const auto &jdkVersion : knownJdkVersions) { diff --git a/tests/auto/blackbox/tst_blackboxjava.h b/tests/auto/blackbox/tst_blackboxjava.h index 68d8a7f80..e770306df 100644 --- a/tests/auto/blackbox/tst_blackboxjava.h +++ b/tests/auto/blackbox/tst_blackboxjava.h @@ -43,6 +43,9 @@ private slots: void javaDependencyTracking(); void javaDependencyTracking_data(); void javaDependencyTrackingInnerClass(); + +private: + const QStringList m_blacklistedJdks; }; #endif // TST_BLACKBOX_H diff --git a/tests/auto/blackbox/tst_blackboxjoblimits.cpp b/tests/auto/blackbox/tst_blackboxjoblimits.cpp index 89b5f638e..acaf69a5b 100644 --- a/tests/auto/blackbox/tst_blackboxjoblimits.cpp +++ b/tests/auto/blackbox/tst_blackboxjoblimits.cpp @@ -39,6 +39,7 @@ public: TestBlackboxJobLimits(); private slots: + void initTestCase(); void jobLimits_data(); void jobLimits(); }; @@ -48,6 +49,16 @@ TestBlackboxJobLimits::TestBlackboxJobLimits() { } +void TestBlackboxJobLimits::initTestCase() +{ + TestBlackboxBase::initTestCase(); + + QDir::setCurrent(testDataDir + "/job-limits-init"); + QCOMPARE(runQbs({"resolve"}), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Skip test in cross-compiled build"); +} + void TestBlackboxJobLimits::jobLimits_data() { QTest::addColumn<int>("projectJobCount"); @@ -143,6 +154,7 @@ void TestBlackboxJobLimits::jobLimits() SettingsPtr theSettings = settings(); qbs::Internal::TemporaryProfile profile("jobLimitsProfile", theSettings.get()); profile.p.setValue("preferences.jobLimit.singleton", prefsJobCount); + profile.p.setValue("baseProfile", profileName()); theSettings->sync(); QbsRunParameters resolveParams("resolve"); resolveParams.profile = profile.p.name(); @@ -150,6 +162,7 @@ void TestBlackboxJobLimits::jobLimits() << ("project.productJobCount:" + QString::number(productJobCount)) << ("project.moduleJobCount:" + QString::number(moduleJobCount)); QCOMPARE(runQbs(resolveParams), 0); + QbsRunParameters buildParams; buildParams.expectFailure = !expectSuccess; if (cliJobCount != -1) @@ -165,7 +178,7 @@ void TestBlackboxJobLimits::jobLimits() else QVERIFY2(m_qbsStderr.contains("exclusive"), m_qbsStderr.constData()); if (exitCode == 0) - QCOMPARE(m_qbsStdout.count("Running tool"), 5); + QCOMPARE(m_qbsStdout.count("running tool"), 5); } QTEST_MAIN(TestBlackboxJobLimits) diff --git a/tests/auto/blackbox/tst_blackboxproviders.cpp b/tests/auto/blackbox/tst_blackboxproviders.cpp new file mode 100644 index 000000000..cf6594229 --- /dev/null +++ b/tests/auto/blackbox/tst_blackboxproviders.cpp @@ -0,0 +1,443 @@ +/**************************************************************************** +** +** Copyright (C) 2023 Ivan Komissarov (abbapoh@gmail.com) +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "tst_blackboxproviders.h" + +#include "../shared.h" + +// #include <tools/hostosinfo.h> +// #include <tools/profile.h> +// #include <tools/qttools.h> + +// #include <QtCore/qdir.h> +// #include <QtCore/qregularexpression.h> + +// using qbs::Internal::HostOsInfo; +// using qbs::Profile; + +#define WAIT_FOR_NEW_TIMESTAMP() waitForNewTimestamp(testDataDir) + +TestBlackboxProviders::TestBlackboxProviders() + : TestBlackboxBase(SRCDIR "/testdata-providers", "blackbox-providers") +{ +} + +void TestBlackboxProviders::allowedValues() +{ + QFETCH(QStringList, arguments); + QFETCH(bool, expectFailure); + + QDir::setCurrent(testDataDir + "/allowed-values"); + rmDirR(relativeBuildDir()); + QbsRunParameters params; + params.arguments = arguments; + params.expectFailure = expectFailure; + + QVERIFY2(runQbs(params) == int(expectFailure), m_qbsStderr); +} + +void TestBlackboxProviders::allowedValues_data() +{ + QTest::addColumn<QStringList>("arguments"); + QTest::addColumn<bool>("expectFailure"); + + QTest::newRow("invalid js value") << QStringList{} << true; + QTest::newRow("invalid variant value") + << QStringList{"moduleProviders.provider.aProperty:three"} << true; + QTest::newRow("valid variant value") + << QStringList{"moduleProviders.provider.aProperty:one"} << false; +} + +void TestBlackboxProviders::brokenProvider() +{ + QDir::setCurrent(testDataDir + "/broken-provider"); + QbsRunParameters params; + params.expectFailure = true; + QVERIFY(runQbs(params) != 0); + + QVERIFY(m_qbsStderr.contains("Error executing provider for module 'qbsothermodule'")); + QVERIFY(m_qbsStderr.contains("Error executing provider for module 'qbsmetatestmodule'")); + QCOMPARE(m_qbsStderr.count("This provider is broken"), 2); +} + +void TestBlackboxProviders::conanProvider() +{ + QFETCH(bool, generateConanFiles); + QFETCH(bool, successExpected); + + const auto executable = findExecutable({"conan"}); + if (executable.isEmpty()) + QSKIP("conan is not installed or not available in PATH."); + + const auto generator = QDir::homePath() + "/.conan2/extensions/generators/qbsdeps.py"; + if (!QFileInfo(generator).exists()) { + QSKIP( + "qbsdeps.py is not installed, call 'conan config install src/conan/ from qbs source'."); + } + + const auto profilePath = QDir::homePath() + "/.conan2/profiles/qbs-test"; + if (!QFileInfo(profilePath).exists()) + QSKIP("conan profile is not installed, run './scripts/setup-conan-profiles.sh'."); + + // install testlibdep first + QProcess conan; + QDir::setCurrent(testDataDir + "/conan-provider/testlibdep"); + conan.start(executable, {"create", ".", "--profile:all=qbs-test"}); + QVERIFY(waitForProcessSuccess(conan)); + + // install testlib second + QDir::setCurrent(testDataDir + "/conan-provider/testlib"); + conan.start(executable, {"create", ".", "--profile:all=qbs-test"}); + QVERIFY(waitForProcessSuccess(conan)); + + // install header lib third + QDir::setCurrent(testDataDir + "/conan-provider/testlibheader"); + conan.start(executable, {"create", ".", "--profile:all=qbs-test"}); + QVERIFY(waitForProcessSuccess(conan)); + + // now build an app using those libs + QDir::setCurrent(testDataDir + "/conan-provider"); + + rmDirR(relativeBuildDir()); + rmDirR("build"); + + if (generateConanFiles) { + QStringList arguments{ + "install", ".", "-g=QbsDeps", "--profile:all=qbs-test", "--output-folder=build"}; + QProcess conan; + conan.start(executable, arguments); + QVERIFY(waitForProcessSuccess(conan)); + } + + QbsRunParameters buildParams( + "build", + {"--force-probe-execution", + "moduleProviders.conan.installDirectory:" + QDir::currentPath() + "/build"}); + buildParams.expectFailure = !successExpected; + QCOMPARE(runQbs(buildParams) == 0, successExpected); +} + +void TestBlackboxProviders::conanProvider_data() +{ + QTest::addColumn<bool>("generateConanFiles"); + QTest::addColumn<bool>("successExpected"); + + QTest::addRow("no conan files generated") << false << false; + QTest::addRow("conan files generated") << true << true; +} + +void TestBlackboxProviders::moduleProviders() +{ + QDir::setCurrent(testDataDir + "/module-providers"); + + // Resolving in dry-run mode must not leave any data behind. + QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); + QCOMPARE(m_qbsStdout.count("Running setup script for mygenerator"), 2); + QVERIFY(!QFile::exists(relativeBuildDir())); + + // Initial build. + QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app1"})), 0); + QVERIFY(QFile::exists(relativeBuildDir())); + QCOMPARE(m_qbsStdout.count("Running setup script for mygenerator"), 2); + QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("The MY_DEFINE is app1"), m_qbsStdout.constData()); + QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app2"})), 0); + QVERIFY2(m_qbsStdout.contains("The letters are Z and Y"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("The MY_DEFINE is app2"), m_qbsStdout.constData()); + + // Rebuild with overridden module provider config. The output for product 2 must change, + // but no setup script must be re-run, because both config values have already been + // handled in the first run. + const QStringList resolveArgs("moduleProviders.mygenerator.chooseLettersFrom:beginning"); + QCOMPARE(runQbs(QbsRunParameters("resolve", resolveArgs)), 0); + QVERIFY2(!m_qbsStdout.contains("Running setup script"), m_qbsStdout.constData()); + QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app1"})), 0); + QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); + QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app2"})), 0); + QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); + + // Forcing Probe execution triggers a re-run of the setup script. But only once, + // because the module provider config is the same now. + QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList(resolveArgs) + << "--force-probe-execution")), 0); + QCOMPARE(m_qbsStdout.count("Running setup script for mygenerator"), 1); + QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app1"})), 0); + QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); + QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app2"})), 0); + QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); + + // Now re-run without the module provider config override. Again, the setup script must + // run once, for the config value that was not present in the last run. + QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); + QCOMPARE(m_qbsStdout.count("Running setup script for mygenerator"), 1); + QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app1"})), 0); + QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); + QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app2"})), 0); + QVERIFY2(m_qbsStdout.contains("The letters are Z and Y"), m_qbsStdout.constData()); +} + +// Checks regression - when loading 2 modules from the same provider, the second module should +// come from provider cache +void TestBlackboxProviders::moduleProvidersCache() +{ + QDir::setCurrent(testDataDir + "/module-providers-cache"); + + QbsRunParameters params("resolve", {"-v"}); + QCOMPARE(runQbs(params), 0); + const auto qbsmetatestmoduleMessage = "Re-checking for module \"qbsmetatestmodule\" with " + "newly added search paths from module provider"; + const auto qbsothermoduleMessage = "Re-checking for module \"qbsothermodule\" with " + "newly added search paths from module provider"; + QCOMPARE(m_qbsStderr.count(qbsmetatestmoduleMessage), 1); + QCOMPARE(m_qbsStderr.count(qbsothermoduleMessage), 1); + QCOMPARE(m_qbsStderr.count("Re-using provider \"provider_a\" from cache"), 1); + + // We didn't change providers, so both modules should come from cache. + params.arguments << "project.dummyProp:value"; + QCOMPARE(runQbs(params), 0); + QCOMPARE(m_qbsStderr.count(qbsmetatestmoduleMessage), 1); + QCOMPARE(m_qbsStderr.count(qbsothermoduleMessage), 1); + QCOMPARE(m_qbsStderr.count("Re-using provider \"provider_a\" from cache"), 2); +} + +void TestBlackboxProviders::nonEagerModuleProvider() +{ + QDir::setCurrent(testDataDir + "/non-eager-provider"); + + QbsRunParameters params("resolve"); + QCOMPARE(runQbs(params), 0); + QVERIFY2(m_qbsStdout.contains(("Running setup script for qbsmetatestmodule")), m_qbsStdout); + QVERIFY2(m_qbsStdout.contains(("Running setup script for qbsothermodule")), m_qbsStdout); + QVERIFY2(!m_qbsStdout.contains(("Running setup script for nonexistentmodule")), m_qbsStdout); + + QVERIFY2(m_qbsStdout.contains(("p1.qbsmetatestmodule.prop: from_provider_a")), + m_qbsStdout); + QVERIFY2(m_qbsStdout.contains(("p1.qbsothermodule.prop: from_provider_a")), + m_qbsStdout); +} + +void TestBlackboxProviders::probeInModuleProvider() +{ + QDir::setCurrent(testDataDir + "/probe-in-module-provider"); + + QbsRunParameters params; + params.command = "build"; + params.arguments << "--force-probe-execution"; + QCOMPARE(runQbs(params), 0); + QVERIFY2(m_qbsStdout.contains("Running probe"), m_qbsStdout); + QVERIFY2(m_qbsStdout.contains("p.qbsmetatestmodule.boolProp: true"), m_qbsStdout); + WAIT_FOR_NEW_TIMESTAMP(); + touch("probe-in-module-provider.qbs"); + QCOMPARE(runQbs(), 0); + QVERIFY2(m_qbsStdout.contains("p.qbsmetatestmodule.boolProp: true"), m_qbsStdout); + QVERIFY2(m_qbsStdout.contains("p.qbsmetatestmodule.prop: \"value\""), m_qbsStdout); + QVERIFY2(!m_qbsStdout.contains("Running probe"), m_qbsStdout); +} + +// Tests whether it is possible to set providers properties in a Product or from command-line +void TestBlackboxProviders::providersProperties() +{ + QDir::setCurrent(testDataDir + "/providers-properties"); + + QbsRunParameters params("build"); + params.arguments = QStringList("moduleProviders.provider_b.someProp: \"first,second\""); + QCOMPARE(runQbs(params), 0); + QVERIFY2(m_qbsStdout.contains("p.qbsmetatestmodule.listProp: [\"someValue\"]"), m_qbsStdout); + QVERIFY2(m_qbsStdout.contains( + "p.qbsothermodule.listProp: [\"first\",\"second\"]"), m_qbsStdout); +} + +// checks that we can set qbs module properties in providers and provider cache works corectly +void TestBlackboxProviders::qbsModulePropertiesInProviders() +{ + QDir::setCurrent(testDataDir + "/qbs-module-properties-in-providers"); + + QbsRunParameters params("resolve"); + + QCOMPARE(runQbs(params), 0); + + // We have 2 products in 2 configurations, but second product should use the cached value + // so we should have only 2 copies of the module, not 4. + QCOMPARE(m_qbsStdout.count("Running setup script for qbsmetatestmodule"), 2); + + // Check that products get correct values from modules + QVERIFY2(m_qbsStdout.contains(("product1.qbsmetatestmodule.prop: /sysroot1")), m_qbsStdout); + QVERIFY2(m_qbsStdout.contains(("product1.qbsmetatestmodule.prop: /sysroot2")), m_qbsStdout); + + QVERIFY2(m_qbsStdout.contains(("product2.qbsmetatestmodule.prop: /sysroot1")), m_qbsStdout); + QVERIFY2(m_qbsStdout.contains(("product2.qbsmetatestmodule.prop: /sysroot2")), m_qbsStdout); +} + +void TestBlackboxProviders::qbsModuleProviders_data() +{ + QTest::addColumn<QStringList>("arguments"); + QTest::addColumn<QString>("firstProp"); + QTest::addColumn<QString>("secondProp"); + + QTest::newRow("default") << QStringList() << "from_provider_a" << "undefined"; + QTest::newRow("override") + << QStringList("projects.project.qbsModuleProviders:provider_b") + << "from_provider_b" + << "from_provider_b"; + QTest::newRow("override list a") + << QStringList("projects.project.qbsModuleProviders:provider_a,provider_b") + << "from_provider_a" + << "from_provider_b"; + QTest::newRow("override list b") + << QStringList("projects.project.qbsModuleProviders:provider_b,provider_a") + << "from_provider_b" + << "from_provider_b"; +} + +// Tests whether it is possible to set qbsModuleProviders in Product and Project items +// and that the order of providers results in correct priority +void TestBlackboxProviders::qbsModuleProviders() +{ + QFETCH(QStringList, arguments); + QFETCH(QString, firstProp); + QFETCH(QString, secondProp); + + QDir::setCurrent(testDataDir + "/qbs-module-providers"); + + QbsRunParameters params("resolve"); + params.arguments = arguments; + QCOMPARE(runQbs(params), 0); + QVERIFY2(m_qbsStdout.contains(("p1.qbsmetatestmodule.prop: " + firstProp).toUtf8()), + m_qbsStdout); + QVERIFY2(m_qbsStdout.contains(("p1.qbsothermodule.prop: " + secondProp).toUtf8()), + m_qbsStdout); + QVERIFY2(m_qbsStdout.contains(("p2.qbsmetatestmodule.prop: " + firstProp).toUtf8()), + m_qbsStdout); + QVERIFY2(m_qbsStdout.contains(("p2.qbsothermodule.prop: " + secondProp).toUtf8()), + m_qbsStdout); +} + +void TestBlackboxProviders::qbsModuleProvidersCliOverride_data() +{ + QTest::addColumn<QStringList>("arguments"); + QTest::addColumn<QString>("propertyValue"); + + QTest::newRow("default") << QStringList() << "undefined"; + QTest::newRow("project-wide") + << QStringList("project.qbsModuleProviders:provider_a") + << "from_provider_a"; + QTest::newRow("concrete project") + << QStringList("projects.innerProject.qbsModuleProviders:provider_a") + << "from_provider_a"; + QTest::newRow("concrete product") + << QStringList("products.product.qbsModuleProviders:provider_a") + << "from_provider_a"; + QTest::newRow("concrete project override project-wide") + << QStringList({ + "project.qbsModuleProviders:provider_a", + "projects.innerProject.qbsModuleProviders:provider_b"}) + << "from_provider_b"; + QTest::newRow("concrete product override project-wide") + << QStringList({ + "project.qbsModuleProviders:provider_a", + "products.product.qbsModuleProviders:provider_b"}) + << "from_provider_b"; +} + +// Tests possible use-cases how to override providers from command-line +void TestBlackboxProviders::qbsModuleProvidersCliOverride() +{ + QFETCH(QStringList, arguments); + QFETCH(QString, propertyValue); + + QDir::setCurrent(testDataDir + "/qbs-module-providers-cli-override"); + + QbsRunParameters params("resolve"); + params.arguments = arguments; + QCOMPARE(runQbs(params), 0); + QVERIFY2(m_qbsStdout.contains(("qbsmetatestmodule.prop: " + propertyValue).toUtf8()), + m_qbsStdout); +} + +void TestBlackboxProviders::qbsModuleProvidersCompatibility_data() +{ + QTest::addColumn<QStringList>("arguments"); + QTest::addColumn<QString>("propertyValue"); + + QTest::newRow("default") << QStringList() << "from_scoped_provider"; + QTest::newRow("scoped by name") << QStringList("project.qbsModuleProviders:qbsmetatestmodule") << "from_scoped_provider"; + QTest::newRow("named") << QStringList("project.qbsModuleProviders:named_provider") << "from_named_provider"; +} + +// Tests whether scoped providers can be used as named, i.e. new provider machinery +// is compatible with the old one +void TestBlackboxProviders::qbsModuleProvidersCompatibility() +{ + QFETCH(QStringList, arguments); + QFETCH(QString, propertyValue); + + QDir::setCurrent(testDataDir + "/qbs-module-providers-compatibility"); + + QbsRunParameters params("resolve"); + params.arguments = arguments; + QCOMPARE(runQbs(params), 0); + QVERIFY2(m_qbsStdout.contains(("qbsmetatestmodule.prop: " + propertyValue).toUtf8()), + m_qbsStdout); +} + +void TestBlackboxProviders::qbspkgconfigModuleProvider() +{ + QDir::setCurrent(testDataDir + "/qbspkgconfig-module-provider/libs"); + rmDirR(relativeBuildDir()); + + const auto commonParams = QbsRunParameters(QStringLiteral("install"), { + QStringLiteral("--install-root"), + QStringLiteral("install-root") + }); + auto dynamicParams = commonParams; + dynamicParams.arguments << "config:library" << "projects.libs.isBundle:false"; + QCOMPARE(runQbs(dynamicParams), 0); + + QDir::setCurrent(testDataDir + "/qbspkgconfig-module-provider"); + rmDirR(relativeBuildDir()); + + const auto sysroot = testDataDir + "/qbspkgconfig-module-provider/libs/install-root"; + + QbsRunParameters params; + params.arguments << "moduleProviders.qbspkgconfig.sysroot:" + sysroot; + QCOMPARE(runQbs(params), 0); +} + +void TestBlackboxProviders::removalVersion() +{ + QDir::setCurrent(testDataDir + "/removal-version"); + QCOMPARE(runQbs(), 0); + QVERIFY(m_qbsStderr.contains( + "Property 'deprecated' was scheduled for removal in version 2.2.0, but is still present")); +} + +QTEST_MAIN(TestBlackboxProviders) diff --git a/tests/auto/blackbox/tst_blackboxproviders.h b/tests/auto/blackbox/tst_blackboxproviders.h new file mode 100644 index 000000000..088cea6a3 --- /dev/null +++ b/tests/auto/blackbox/tst_blackboxproviders.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2023 Ivan Komissarov (abbapoh@gmail.com) +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef TST_BLACKBOXPROVIDERS_H +#define TST_BLACKBOXPROVIDERS_H + +#include "tst_blackboxbase.h" + +class TestBlackboxProviders : public TestBlackboxBase +{ + Q_OBJECT + +public: + TestBlackboxProviders(); + +private slots: + void allowedValues(); + void allowedValues_data(); + void brokenProvider(); + void conanProvider(); + void conanProvider_data(); + void moduleProviders(); + void moduleProvidersCache(); + void nonEagerModuleProvider(); + void probeInModuleProvider(); + void providersProperties(); + void qbsModulePropertiesInProviders(); + void qbsModuleProviders_data(); + void qbsModuleProviders(); + void qbsModuleProvidersCliOverride(); + void qbsModuleProvidersCliOverride_data(); + void qbsModuleProvidersCompatibility(); + void qbsModuleProvidersCompatibility_data(); + void qbspkgconfigModuleProvider(); + void removalVersion(); +}; + +#endif // TST_BLACKBOXPROVIDERS_H diff --git a/tests/auto/blackbox/tst_blackboxqt.cpp b/tests/auto/blackbox/tst_blackboxqt.cpp index 474fb95f3..b083a97e8 100644 --- a/tests/auto/blackbox/tst_blackboxqt.cpp +++ b/tests/auto/blackbox/tst_blackboxqt.cpp @@ -38,27 +38,10 @@ #define WAIT_FOR_NEW_TIMESTAMP() waitForNewTimestamp(testDataDir) using qbs::Internal::HostOsInfo; -using qbs::Profile; TestBlackboxQt::TestBlackboxQt() : TestBlackboxBase (SRCDIR "/testdata-qt", "blackbox-qt") { -} - -void TestBlackboxQt::validateTestProfile() -{ - const SettingsPtr s = settings(); - if (profileName() != "none" && !s->profiles().contains(profileName())) - QFAIL(QByteArray("The build profile '" + profileName().toLocal8Bit() + - "' could not be found. Please set it up on your machine.")); - const QStringList qmakeFilePaths = Profile(profileName(), s.get()) - .value("moduleProviders.Qt.qmakeFilePaths").toStringList(); - if (!qmakeFilePaths.empty()) - return; - if (!findExecutable(QStringList{"qmake"}).isEmpty()) - return; - QSKIP(QByteArray("The build profile '" + profileName().toLocal8Bit() + - "' is not a valid Qt profile and Qt was not found " - "in the global search paths.")); + setNeedsQt(); } void TestBlackboxQt::addQObjectMacroToGeneratedCppFile() @@ -75,6 +58,9 @@ void TestBlackboxQt::addQObjectMacroToGeneratedCppFile() void TestBlackboxQt::autoQrc() { QDir::setCurrent(testDataDir + "/auto-qrc"); + QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app"})), 0); QVERIFY2(m_qbsStdout.simplified().contains("resource data: resource1 resource2"), m_qbsStdout.constData()); @@ -83,7 +69,9 @@ void TestBlackboxQt::autoQrc() void TestBlackboxQt::cachedQml() { QDir::setCurrent(testDataDir + "/cached-qml"); - QCOMPARE(runQbs(), 0); + if ((runQbs() != 0) && m_qbsStderr.contains("Dependency 'Qt.qml' not found for product 'app'")) + QSKIP("Qt version too old"); + QString dataDir = relativeBuildDir() + "/install-root/data"; QVERIFY2(m_qbsStdout.contains("qmlcachegen must work: true") || m_qbsStdout.contains("qmlcachegen must work: false"), @@ -118,7 +106,7 @@ void TestBlackboxQt::combinedMoc() void TestBlackboxQt::createProject() { QDir::setCurrent(testDataDir + "/create-project"); - QVERIFY(QFile::copy(SRCDIR "/../../../examples/helloworld-qt/main.cpp", + QVERIFY(QFile::copy(testSourceDir + "/../../../../examples/helloworld-qt/main.cpp", QDir::currentPath() + "/main.cpp")); QbsRunParameters createParams("create-project"); createParams.profile.clear(); @@ -145,6 +133,11 @@ void TestBlackboxQt::dbusInterfaces() void TestBlackboxQt::forcedMoc() { QDir::setCurrent(testDataDir + "/forced-moc"); + QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); + if (m_qbsStdout.contains("using qt4")) + QSKIP("Qt version too old"); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(QbsRunParameters("run")), 0); QVERIFY2(m_qbsStderr.contains("Hello from slot"), m_qbsStderr.constData()); } @@ -153,6 +146,8 @@ void TestBlackboxQt::includedMocCpp() { QDir::setCurrent(testDataDir + "/included-moc-cpp"); QCOMPARE(runQbs(), 0); + if (m_qbsStdout.contains("using qt4")) + QSKIP("Qt version too old"); QVERIFY2(!m_qbsStdout.contains("compiling moc_myobject.cpp"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("myobject.cpp", "#include <moc_myobject.cpp", "// #include <moc_myobject.cpp"); @@ -204,12 +199,48 @@ void TestBlackboxQt::lrelease() QVERIFY(!regularFileExists(relativeProductBuildDir("lrelease-test") + "/hu.qm")); } +void TestBlackboxQt::metaTypes_data() +{ + QTest::addColumn<bool>("generate"); + QTest::addColumn<QString>("installDir"); + QTest::newRow("don't generate") << false << QString(); + QTest::newRow("don't generate with install info") << false << QString("blubb"); + QTest::newRow("generate only") << true << QString(); + QTest::newRow("generate and install") << true << QString("blubb"); +} + +void TestBlackboxQt::metaTypes() +{ + QDir::setCurrent(testDataDir + "/metatypes"); + QFETCH(bool, generate); + QFETCH(QString, installDir); + const QStringList args{"modules.Qt.core.generateMetaTypesFile:" + + QString(generate ? "true" : "false"), + "modules.Qt.core.metaTypesInstallDir:" + installDir, + "-v", "--force-probe-execution"}; + QCOMPARE(runQbs(QbsRunParameters("resolve", args)), 0); + const bool canGenerate = m_qbsStdout.contains("can generate"); + const bool cannotGenerate = m_qbsStdout.contains("cannot generate"); + QVERIFY(canGenerate != cannotGenerate); + const bool expectFiles = generate && canGenerate; + const bool expectInstalledFiles = expectFiles && !installDir.isEmpty(); + QCOMPARE(runQbs(QStringList("--clean-install-root")), 0); + const QString productDir = relativeProductBuildDir("mylib"); + const QString outputDir = productDir + "/qt.headers"; + QVERIFY(!regularFileExists(outputDir + "/moc_unmocableclass.cpp.json")); + QCOMPARE(regularFileExists(outputDir + "/moc_mocableclass1.cpp.json"), expectFiles); + QCOMPARE(regularFileExists(outputDir + "/mocableclass2.moc.json"), expectFiles); + QCOMPARE(regularFileExists(productDir + "/mylib_metatypes.json"), expectFiles); + QCOMPARE(regularFileExists(relativeBuildDir() + "/install-root/some-prefix/" + installDir + + "/mylib_metatypes.json"), expectInstalledFiles); +} + void TestBlackboxQt::mixedBuildVariants() { QDir::setCurrent(testDataDir + "/mixed-build-variants"); const SettingsPtr s = settings(); - Profile profile(profileName(), s.get()); - if (profile.value("qbs.toolchain").toStringList().contains("msvc")) { + qbs::Profile profile(profileName(), s.get()); + if (profileToolchain(profile).contains("msvc")) { QbsRunParameters params; params.arguments << "qbs.buildVariant:debug"; params.expectFailure = true; @@ -240,6 +271,12 @@ void TestBlackboxQt::mocFlags() QVERIFY(runQbs(params) != 0); } +void TestBlackboxQt::mocCompilerDefines() +{ + QDir::setCurrent(testDataDir + "/moc-compiler-defines"); + QCOMPARE(runQbs(), 0); +} + void TestBlackboxQt::mocSameFileName() { QDir::setCurrent(testDataDir + "/moc-same-file-name"); @@ -247,19 +284,141 @@ void TestBlackboxQt::mocSameFileName() QCOMPARE(m_qbsStdout.count("compiling moc_someclass.cpp"), 2); } +void TestBlackboxQt::noRelinkOnQDebug() +{ + QFETCH(QString, checkMode); + QFETCH(bool, expectRelink); + + QVERIFY(QDir::setCurrent(testDataDir + "/no-relink-on-qdebug")); + rmDirR("default"); + + // Target check. + QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); + QVERIFY2(m_qbsStdout.contains("is GCC: "), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("is MinGW: "), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("is Darwin: "), m_qbsStdout.constData()); + const bool isGCCLike = m_qbsStdout.contains("is GCC: true"); + const bool isMingw = m_qbsStdout.contains("is MinGW: true"); + const bool isDarwin = m_qbsStdout.contains("is Darwin: true"); + if (!isGCCLike) + expectRelink = false; + else if (isMingw || isDarwin) + expectRelink = true; + + // Initial build. + QbsRunParameters params("resolve"); + if (isGCCLike && !checkMode.isEmpty()) + params.arguments << ("modules.cpp.exportedSymbolsCheckMode:" + checkMode); + QCOMPARE(runQbs(params), 0); + QCOMPARE(runQbs(), 0); + QCOMPARE(m_qbsStdout.count("linking"), 2); + + // Inserting the qDebug() statement will pull in weak symbols. + WAIT_FOR_NEW_TIMESTAMP(); + REPLACE_IN_FILE("lib.cpp", "// qDebug", "qDebug"); + QCOMPARE(runQbs(), 0); + QCOMPARE(m_qbsStdout.count("linking"), expectRelink ? 2 : 1); + + // Also check the opposite case. + WAIT_FOR_NEW_TIMESTAMP(); + REPLACE_IN_FILE("lib.cpp", "qDebug", "// qDebug"); + QCOMPARE(runQbs(), 0); + QCOMPARE(m_qbsStdout.count("linking"), expectRelink ? 2 : 1); +} + +void TestBlackboxQt::noRelinkOnQDebug_data() +{ + QTest::addColumn<QString>("checkMode"); + QTest::addColumn<bool>("expectRelink"); + QTest::newRow("default") << QString() << false; + QTest::newRow("relaxed") << QString("ignore-undefined") << false; + QTest::newRow("strict") << QString("strict") << true; +} + void TestBlackboxQt::pkgconfig() { QDir::setCurrent(testDataDir + "/pkgconfig"); + QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params; params.command = "run"; QCOMPARE(runQbs(params), 0); - if (m_qbsStdout.contains("Skip this test")) + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("pkgconfig or Qt not found"); } +void TestBlackboxQt::pkgconfigQt() +{ + QFETCH(QStringList, arguments); + QFETCH(bool, success); + + QDir::setCurrent(testDataDir + "/pkgconfig-qt"); + rmDirR(relativeBuildDir()); + + QbsRunParameters dumpParams("resolve", {"-f", "dump-libpath.qbs"}); + QCOMPARE(runQbs(dumpParams), 0); + auto lines = QString::fromUtf8(m_qbsStdout).split('\n'); + const QString needle = "libPath="; + qbs::Internal::removeIf( + lines, [&needle](const auto &line) { return !line.startsWith(needle); }); + QCOMPARE(lines.size(), 1); + const auto libPath = lines[0].mid(needle.size()); + auto prefix = QFileInfo(libPath).path(); + if (prefix.endsWith("/lib") && !prefix.startsWith("/lib")) + prefix = QFileInfo(prefix).path(); + const auto pkgConfigPath = libPath + "/pkgconfig/"; + if (!QFileInfo(pkgConfigPath).exists()) + QSKIP("No *.pc files found"); + + rmDirR(relativeBuildDir()); + QbsRunParameters params("build", {"-f", "pkgconfig-qt.qbs"}); + // need to override prefix for the downloaded Qt + params.environment.insert("PKG_CONFIG_QT5CORE_PREFIX", prefix); + params.environment.insert("PKG_CONFIG_QT6CORE_PREFIX", prefix); + params.arguments << "moduleProviders.qbspkgconfig.extraPaths:" + pkgConfigPath; + params.arguments << arguments; + + QCOMPARE(runQbs(params) == 0, success); + + if (!success) + QVERIFY(m_qbsStderr.contains("Dependency 'Qt.core' not found for product 'p'")); +} + +void TestBlackboxQt::pkgconfigQt_data() +{ + QTest::addColumn<QStringList>("arguments"); + QTest::addColumn<bool>("success"); + QTest::newRow("pkgconfig") << QStringList() << true; + QTest::newRow("dummy") + << QStringList({"products.p.qbsModuleProviders:dummyProvider"}) << false; + QTest::newRow("cross-compiling") + << QStringList({"moduleProviders.qbspkgconfig.sysroot:/some/fake/sysroot"}) << false; +} + +void TestBlackboxQt::pkgconfigNoQt() +{ + QDir::setCurrent(testDataDir + "/pkgconfig-qt"); + rmDirR(relativeBuildDir()); + QbsRunParameters params("build", {"-f", "pkgconfig-qt.qbs"}); + params.arguments << "moduleProviders.qbspkgconfig.libDirs:nonexistent"; + params.expectFailure = true; + + QCOMPARE(runQbs(params) == 0, false); + QVERIFY2(m_qbsStderr.contains("Dependency 'Qt.core' not found for product 'p'"), m_qbsStderr); + // QBS-1777: basic check for JS exceptions in case of missing Qt + QVERIFY2(!m_qbsStderr.contains("Error executing provider for module 'Qt.core'"), m_qbsStderr); +} + void TestBlackboxQt::pluginMetaData() { QDir::setCurrent(testDataDir + "/plugin-meta-data"); + QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); + if (m_qbsStdout.contains("using qt4")) + QSKIP("Qt version too old"); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); + QVERIFY2(runQbs(QbsRunParameters("run", QStringList{"-p", "app"})) == 0, m_qbsStderr.constData()); QVERIFY2(m_qbsStderr.contains("all ok!"), m_qbsStderr.constData()); @@ -286,7 +445,11 @@ void TestBlackboxQt::pluginSupport() resolveParams.arguments << "modules.m1.useDummy:true"; resolveParams.expectFailure = true; } - QCOMPARE(runQbs(resolveParams) == 0, !invalidPlugin); + bool resolveResult = runQbs(resolveParams) == 0; + if (m_qbsStdout.contains("using qt4")) + QSKIP("Qt version too old"); + QCOMPARE(resolveResult, !invalidPlugin); + if (invalidPlugin) { QVERIFY2(m_qbsStderr.contains("Plugin 'dummy' of type 'imageformats' was requested, " "but is not available"), m_qbsStderr.constData()); @@ -320,22 +483,36 @@ void TestBlackboxQt::pluginSupport() } } +void TestBlackboxQt::qdoc() +{ + QDir::setCurrent(testDataDir + "/qdoc"); + QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); + if (m_qbsStdout.contains("Qt is too old")) + QSKIP("Skip test since qdoc3 does not work properly"); + QCOMPARE(runQbs(), 0); + QVERIFY(QFileInfo(relativeProductBuildDir("QDoc Test") + "/qdoctest.qch").exists()); +} + void TestBlackboxQt::qmlDebugging() { QDir::setCurrent(testDataDir + "/qml-debugging"); QCOMPARE(runQbs(), 0); - const SettingsPtr s = settings(); - Profile profile(profileName(), s.get()); - if (!profile.value("qbs.toolchain").toStringList().contains("gcc")) - return; + + const bool isGcc = m_qbsStdout.contains("is gcc: true"); + const bool isNotGcc = m_qbsStdout.contains("is gcc: false"); + if (isNotGcc) + QSKIP("The remainder of this test only applies to gcc"); + QVERIFY(isGcc); + QProcess nm; nm.start("nm", QStringList(relativeExecutableFilePath("debuggable-app"))); - if (nm.waitForStarted()) { // Let's ignore hosts without nm. - QVERIFY2(nm.waitForFinished(), qPrintable(nm.errorString())); - QVERIFY2(nm.exitCode() == 0, nm.readAllStandardError().constData()); - const QByteArray output = nm.readAllStandardOutput(); - QVERIFY2(output.toLower().contains("debugginghelper"), output.constData()); - } + if (!nm.waitForStarted()) + QSKIP("The remainder of this test requires nm"); + + QVERIFY2(nm.waitForFinished(), qPrintable(nm.errorString())); + QVERIFY2(nm.exitCode() == 0, nm.readAllStandardError().constData()); + const QByteArray output = nm.readAllStandardOutput(); + QVERIFY2(output.toLower().contains("debugginghelper"), output.constData()); } void TestBlackboxQt::qobjectInObjectiveCpp() @@ -347,6 +524,42 @@ void TestBlackboxQt::qobjectInObjectiveCpp() QCOMPARE(runQbs(), 0); } +void TestBlackboxQt::qmlTypeRegistrar_data() +{ + QTest::addColumn<QString>("importName"); + QTest::addColumn<QString>("installDir"); + QTest::newRow("don't generate") << QString() << QString(); + QTest::newRow("don't generate with install info") << QString() << QString("blubb"); + QTest::newRow("generate only") << QString("People") << QString(); + QTest::newRow("generate and install") << QString("People") << QString("blubb"); +} + +void TestBlackboxQt::qmlTypeRegistrar() +{ + QDir::setCurrent(testDataDir + "/qmltyperegistrar"); + QFETCH(QString, importName); + QFETCH(QString, installDir); + rmDirR(relativeBuildDir()); + const QStringList args{"modules.Qt.qml.importName:" + importName, + "modules.Qt.qml.typesInstallDir:" + installDir}; + if ((runQbs(QbsRunParameters("resolve", args)) != 0) && + m_qbsStderr.contains("Dependency 'Qt.qml' not found for product 'myapp'")) + QSKIP("Qt version too old"); + const bool hasRegistrar = m_qbsStdout.contains("has registrar"); + const bool doesNotHaveRegistrar = m_qbsStdout.contains("does not have registrar"); + QVERIFY(hasRegistrar != doesNotHaveRegistrar); + if (doesNotHaveRegistrar) + QSKIP("Qt version too old"); + QCOMPARE(runQbs(), 0); + const bool enabled = !importName.isEmpty(); + QCOMPARE(m_qbsStdout.contains("running qmltyperegistrar"), enabled); + QCOMPARE(m_qbsStdout.contains("compiling myapp_qmltyperegistrations.cpp"), enabled); + const QString buildDir = relativeProductBuildDir("myapp"); + QCOMPARE(regularFileExists(buildDir + "/myapp.qmltypes"), enabled); + QCOMPARE(regularFileExists(relativeBuildDir() + "/install-root/" + installDir + + "/myapp.qmltypes"), enabled && !installDir.isEmpty()); +} + void TestBlackboxQt::qtKeywords() { QDir::setCurrent(testDataDir + "/qt-keywords"); @@ -364,7 +577,9 @@ void TestBlackboxQt::qtKeywords() void TestBlackboxQt::quickCompiler() { QDir::setCurrent(testDataDir + "/quick-compiler"); - QCOMPARE(runQbs(), 0); + if ((runQbs() != 0) && + m_qbsStderr.contains("'Qt.quick' has version 4.8.7, but it needs to be at least 5.0.0.")) + QSKIP("Qt version too old"); const bool hasCompiler = m_qbsStdout.contains("compiler available"); const bool doesNotHaveCompiler = m_qbsStdout.contains("compiler not available"); QVERIFY2(hasCompiler || doesNotHaveCompiler, m_qbsStdout.constData()); @@ -390,6 +605,9 @@ void TestBlackboxQt::quickCompiler() void TestBlackboxQt::qtScxml() { QDir::setCurrent(testDataDir + "/qtscxml"); + QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(), 0); if (m_qbsStdout.contains("QtScxml not present")) QSKIP("QtScxml module not present"); @@ -423,10 +641,10 @@ void TestBlackboxQt::staticQtPluginLinking() QDir::setCurrent(testDataDir + "/static-qt-plugin-linking"); QCOMPARE(runQbs(QStringList("products.p.type:application")), 0); const bool isStaticQt = m_qbsStdout.contains("Qt is static"); - QVERIFY2(m_qbsStdout.contains("Creating static import") == isStaticQt, m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("creating static import") == isStaticQt, m_qbsStdout.constData()); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("products.p.type:staticlibrary"))), 0); QCOMPARE(runQbs(), 0); - QVERIFY2(!m_qbsStdout.contains("Creating static import"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("creating static import"), m_qbsStdout.constData()); } void TestBlackboxQt::trackAddMocInclude() @@ -469,6 +687,11 @@ void TestBlackboxQt::track_qobject_change() void TestBlackboxQt::track_qrc() { QDir::setCurrent(testDataDir + "/qrc"); + QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); + if (m_qbsStdout.contains("using qt4")) + QSKIP("Qt version too old"); + if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) + QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(QbsRunParameters("run")), 0); QVERIFY2(m_qbsStdout.contains("rcc"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("compiling test.cpp"), m_qbsStdout.constData()); diff --git a/tests/auto/blackbox/tst_blackboxqt.h b/tests/auto/blackbox/tst_blackboxqt.h index 180f9e0c0..da395b7d4 100644 --- a/tests/auto/blackbox/tst_blackboxqt.h +++ b/tests/auto/blackbox/tst_blackboxqt.h @@ -38,9 +38,6 @@ class TestBlackboxQt : public TestBlackboxBase public: TestBlackboxQt(); -protected: - void validateTestProfile() override; - private slots: void addQObjectMacroToGeneratedCppFile(); void autoQrc(); @@ -53,16 +50,27 @@ private slots: void includedMocCpp(); void linkerVariant(); void lrelease(); + void metaTypes_data(); + void metaTypes(); void mixedBuildVariants(); void mocAndCppCombining(); void mocFlags(); + void mocCompilerDefines(); void mocSameFileName(); + void noRelinkOnQDebug(); + void noRelinkOnQDebug_data(); void pkgconfig(); + void pkgconfigQt(); + void pkgconfigQt_data(); + void pkgconfigNoQt(); void pluginMetaData(); void pluginSupport_data(); void pluginSupport(); + void qdoc(); void qmlDebugging(); void qobjectInObjectiveCpp(); + void qmlTypeRegistrar_data(); + void qmlTypeRegistrar(); void qtKeywords(); void quickCompiler(); void qtScxml(); diff --git a/tests/auto/blackbox/tst_blackboxtutorial.cpp b/tests/auto/blackbox/tst_blackboxtutorial.cpp new file mode 100644 index 000000000..49de448a1 --- /dev/null +++ b/tests/auto/blackbox/tst_blackboxtutorial.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com) +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "tst_blackboxtutorial.h" + +#include <QtCore/qdir.h> +#include <QtCore/qdiriterator.h> + +static QStringList collectProjects(const QString &dirPath) +{ + QStringList result; + QDir dir(dirPath); + const auto subDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); + for (const auto &subDir : subDirs) { + const auto path = dir.filePath(subDir); + if (!QFileInfo::exists(path + "/myproject.qbs")) + continue; + result.append(dir.relativeFilePath(path)); + } + return result; +} + +TestBlackboxTutorial::TestBlackboxTutorial() + : TestBlackboxBase(SRCDIR "/../../../tutorial/", "blackbox-tutorial") +{} + +void TestBlackboxTutorial::tutorial_data() +{ + QTest::addColumn<QString>("project"); + + const auto projects = collectProjects(testDataDir); + for (const auto &project : projects) { + QTest::newRow(project.toUtf8().data()) << project; + } +} + +void TestBlackboxTutorial::tutorial() +{ + QFETCH(QString, project); + + QVERIFY(QDir::setCurrent(testDataDir + "/" + project)); + QCOMPARE(runQbs(), 0); +} + +QTEST_MAIN(TestBlackboxTutorial) diff --git a/tests/auto/blackbox/tst_blackboxtutorial.h b/tests/auto/blackbox/tst_blackboxtutorial.h new file mode 100644 index 000000000..2e84d6a96 --- /dev/null +++ b/tests/auto/blackbox/tst_blackboxtutorial.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com) +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef TST_BLACKBOXTUTORIAL_H +#define TST_BLACKBOXTUTORIAL_H + +#include "tst_blackboxbase.h" + +class TestBlackboxTutorial : public TestBlackboxBase +{ + Q_OBJECT + +public: + TestBlackboxTutorial(); + +private slots: + void tutorial_data(); + void tutorial(); +}; + +#endif // TST_BLACKBOXTUTORIAL_H diff --git a/tests/auto/blackbox/tst_blackboxwindows.cpp b/tests/auto/blackbox/tst_blackboxwindows.cpp new file mode 100644 index 000000000..57bd7f947 --- /dev/null +++ b/tests/auto/blackbox/tst_blackboxwindows.cpp @@ -0,0 +1,307 @@ +/**************************************************************************** +** +** Copyright (C) 2021 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "tst_blackboxwindows.h" + +#include "../shared.h" + +#include <tools/hostosinfo.h> +#include <tools/profile.h> +#include <tools/qttools.h> + +#include <QtCore/qdir.h> +#include <QtCore/qregularexpression.h> + +using qbs::Internal::HostOsInfo; +using qbs::Profile; + +struct SigntoolInfo +{ + enum class CodeSignResult { Failed = 0, Signed, Unsigned }; + CodeSignResult result = CodeSignResult::Failed; + bool timestamped = false; + QString hashAlgorithm; + QString subjectName; +}; + +Q_DECLARE_METATYPE(SigntoolInfo::CodeSignResult) + +static SigntoolInfo extractSigntoolInfo(const QString &signtoolPath, const QString &appPath) +{ + QProcess signtool; + signtool.start(signtoolPath, { QStringLiteral("verify"), QStringLiteral("/v"), appPath }); + if (!signtool.waitForStarted() || !signtool.waitForFinished()) + return {}; + const auto output = signtool.readAllStandardError(); + SigntoolInfo signtoolInfo; + if (output.contains("No signature found")) { + signtoolInfo.result = SigntoolInfo::CodeSignResult::Unsigned; + } else { + signtoolInfo.result = SigntoolInfo::CodeSignResult::Signed; + const auto output = signtool.readAllStandardOutput(); + const auto lines = output.split('\n'); + for (const auto &line: lines) { + { + const QRegularExpression re("^Hash of file \\((.+)\\):.+$"); + const QRegularExpressionMatch match = re.match(line); + if (match.hasMatch()) { + signtoolInfo.hashAlgorithm = match.captured(1).toLocal8Bit(); + continue; + } + } + { + const QRegularExpression re("Issued to: (.+)"); + const QRegularExpressionMatch match = re.match(line); + if (match.hasMatch()) { + signtoolInfo.subjectName = match.captured(1).toLocal8Bit().trimmed(); + continue; + } + } + if (line.startsWith("The signature is timestamped:")) { + signtoolInfo.timestamped = true; + break; + } else if (line.startsWith("File is not timestamped.")) { + break; + } + } + } + return signtoolInfo; +} + +static QString extractSigntoolPath(const QByteArray &output) +{ + const QRegularExpression re("%%(.+)%%"); + QRegularExpressionMatchIterator it = re.globalMatch(output); + if (!it.hasNext()) + return {}; + const QRegularExpressionMatch match = it.next(); + return match.captured(1).toUtf8(); +} + +TestBlackboxWindows::TestBlackboxWindows() + : TestBlackboxBase (SRCDIR "/testdata-windows", "blackbox-windows") +{ +} + +void TestBlackboxWindows::initTestCase() +{ + if (!HostOsInfo::isWindowsHost()) { + QSKIP("only applies on Windows"); + return; + } + + TestBlackboxBase::initTestCase(); +} + +void TestBlackboxWindows::innoSetup() +{ + const SettingsPtr s = settings(); + Profile profile(profileName(), s.get()); + + QDir::setCurrent(testDataDir + "/innosetup"); + + QCOMPARE(runQbs({"resolve"}), 0); + const bool withInnosetup = m_qbsStdout.contains("has innosetup: true"); + const bool withoutInnosetup = m_qbsStdout.contains("has innosetup: false"); + QVERIFY2(withInnosetup || withoutInnosetup, m_qbsStdout.constData()); + if (withoutInnosetup) + QSKIP("innosetup module not present"); + + QCOMPARE(runQbs(), 0); + QVERIFY(m_qbsStdout.contains("compiling test.iss")); + QVERIFY(m_qbsStdout.contains("compiling Example1.iss")); + QVERIFY(regularFileExists(relativeProductBuildDir("QbsSetup") + "/qbs.setup.test.exe")); + QVERIFY(regularFileExists(relativeProductBuildDir("Example1") + "/Example1.exe")); +} + +void TestBlackboxWindows::innoSetupDependencies() +{ + const SettingsPtr s = settings(); + Profile profile(profileName(), s.get()); + + QDir::setCurrent(testDataDir + "/innosetupDependencies"); + + QCOMPARE(runQbs({"resolve"}), 0); + const bool withInnosetup = m_qbsStdout.contains("has innosetup: true"); + const bool withoutInnosetup = m_qbsStdout.contains("has innosetup: false"); + QVERIFY2(withInnosetup || withoutInnosetup, m_qbsStdout.constData()); + if (withoutInnosetup) + QSKIP("innosetup module not present"); + + QbsRunParameters params; + QCOMPARE(runQbs(params), 0); + QVERIFY(m_qbsStdout.contains("compiling test.iss")); + QVERIFY(regularFileExists(relativeBuildDir() + "/qbs.setup.test.exe")); +} + +void TestBlackboxWindows::standaloneCodesign() +{ + QFETCH(SigntoolInfo::CodeSignResult, result); + QFETCH(QString, hashAlgorithm); + QFETCH(QString, subjectName); + QFETCH(QString, signingTimestamp); + + QDir::setCurrent(testDataDir + "/codesign"); + QbsRunParameters params(QStringList{"qbs.installPrefix:''"}); + params.arguments << QStringLiteral("project.enableSigning:%1").arg( + (result == SigntoolInfo::CodeSignResult::Signed) ? "true" : "false") + << QStringLiteral("project.hashAlgorithm:%1").arg(hashAlgorithm) + << QStringLiteral("project.subjectName:%1").arg(subjectName) + << QStringLiteral("project.signingTimestamp:%1").arg(signingTimestamp); + + rmDirR(relativeBuildDir()); + QCOMPARE(runQbs(params), 0); + + if (!m_qbsStdout.contains("signtool path:")) + QSKIP("No current signtool path pattern exists"); + + const auto signtoolPath = extractSigntoolPath(m_qbsStdout); + QVERIFY(QFileInfo(signtoolPath).exists()); + + const QStringList outputBinaries = {"A.exe", "B.dll"}; + for (const auto &outputBinary : outputBinaries) { + const auto outputBinaryPath = defaultInstallRoot + "/" + outputBinary; + QVERIFY(QFileInfo(outputBinaryPath).exists()); + + const SigntoolInfo signtoolInfo = extractSigntoolInfo(signtoolPath, outputBinaryPath); + QVERIFY(signtoolInfo.result != SigntoolInfo::CodeSignResult::Failed); + QCOMPARE(signtoolInfo.result, result); + QCOMPARE(signtoolInfo.hashAlgorithm, hashAlgorithm); + QCOMPARE(signtoolInfo.subjectName, subjectName); + QCOMPARE(signtoolInfo.timestamped, !signingTimestamp.isEmpty()); + } +} + +void TestBlackboxWindows::standaloneCodesign_data() +{ + QTest::addColumn<SigntoolInfo::CodeSignResult>("result"); + QTest::addColumn<QString>("hashAlgorithm"); + QTest::addColumn<QString>("subjectName"); + QTest::addColumn<QString>("signingTimestamp"); + + QTest::newRow("standalone, unsigned") + << SigntoolInfo::CodeSignResult::Unsigned << "" << "" << ""; + QTest::newRow("standalone, signed, sha1, qbs@community.test, no timestamp") + << SigntoolInfo::CodeSignResult::Signed << "sha1" << "qbs@community.test" << ""; + QTest::newRow("standalone, signed, sha256, qbs@community.test, RFC3061 timestamp") + << SigntoolInfo::CodeSignResult::Signed << "sha256" << "qbs@community.test" + << "http://timestamp.digicert.com"; +} + + +static bool haveWiX(const Profile &profile) +{ + if (profile.value("wix.toolchainInstallPath").isValid() && + profile.value("wix.toolchainInstallRoot").isValid()) { + return true; + } + + QStringList regKeys; + regKeys << QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows Installer XML\\") + << QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Installer XML\\"); + + QStringList paths = QProcessEnvironment::systemEnvironment().value("PATH") + .split(HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts); + + for (const QString &key : std::as_const(regKeys)) { + const QStringList versions = QSettings(key, QSettings::NativeFormat).childGroups(); + for (const QString &version : versions) { + QSettings settings(key + version, QSettings::NativeFormat); + QString str = settings.value(QStringLiteral("InstallRoot")).toString(); + if (!str.isEmpty()) + paths.prepend(str); + } + } + + for (const QString &path : std::as_const(paths)) { + if (regularFileExists(QDir::fromNativeSeparators(path) + + HostOsInfo::appendExecutableSuffix(QStringLiteral("/candle"))) && + regularFileExists(QDir::fromNativeSeparators(path) + + HostOsInfo::appendExecutableSuffix(QStringLiteral("/light")))) { + return true; + } + } + + return false; +} + +void TestBlackboxWindows::wix() +{ + const SettingsPtr s = settings(); + Profile profile(profileName(), s.get()); + + if (!haveWiX(profile)) { + QSKIP("WiX is not installed"); + return; + } + + QByteArray arch = profile.value("qbs.architecture").toString().toLatin1(); + if (arch.isEmpty()) + arch = QByteArrayLiteral("x86"); + + QDir::setCurrent(testDataDir + "/wix"); + QCOMPARE(runQbs(), 0); + QVERIFY2(m_qbsStdout.contains("compiling QbsSetup.wxs"), m_qbsStdout); + QVERIFY2(m_qbsStdout.contains("linking qbs.msi"), m_qbsStdout); + QVERIFY(regularFileExists(relativeProductBuildDir("QbsSetup") + "/qbs.msi")); + + if (HostOsInfo::isWindowsHost()) { + QVERIFY2(m_qbsStdout.contains("compiling QbsBootstrapper.wxs"), m_qbsStdout); + QVERIFY2(m_qbsStdout.contains("linking qbs-setup-" + arch + ".exe"), m_qbsStdout); + QVERIFY(regularFileExists(relativeProductBuildDir("QbsBootstrapper") + + "/qbs-setup-" + arch + ".exe")); + } +} + +void TestBlackboxWindows::wixDependencies() +{ + const SettingsPtr s = settings(); + Profile profile(profileName(), s.get()); + + if (!haveWiX(profile)) { + QSKIP("WiX is not installed"); + return; + } + + QByteArray arch = profile.value("qbs.architecture").toString().toLatin1(); + if (arch.isEmpty()) + arch = QByteArrayLiteral("x86"); + + QDir::setCurrent(testDataDir + "/wixDependencies"); + QbsRunParameters params; + if (!HostOsInfo::isWindowsHost()) + params.arguments << "qbs.targetOS:windows"; + QCOMPARE(runQbs(params), 0); + QVERIFY2(m_qbsStdout.contains("compiling QbsSetup.wxs"), m_qbsStdout); + QVERIFY2(m_qbsStdout.contains("linking qbs.msi"), m_qbsStdout); + QVERIFY(regularFileExists(relativeBuildDir() + "/qbs.msi")); +} + +QTEST_MAIN(TestBlackboxWindows) diff --git a/tests/auto/blackbox/tst_blackboxwindows.h b/tests/auto/blackbox/tst_blackboxwindows.h new file mode 100644 index 000000000..ad8d60ca3 --- /dev/null +++ b/tests/auto/blackbox/tst_blackboxwindows.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2021 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef TST_BLACKBOXWINDOWS_H +#define TST_BLACKBOXWINDOWS_H + +#include "tst_blackboxbase.h" + +class TestBlackboxWindows : public TestBlackboxBase +{ + Q_OBJECT + +public: + TestBlackboxWindows(); + +public slots: + void initTestCase() override; + +private slots: + void innoSetup(); + void innoSetupDependencies(); + void standaloneCodesign(); + void standaloneCodesign_data(); + void wix(); + void wixDependencies(); +}; + +#endif // TST_BLACKBOXWINDOWS_H diff --git a/tests/auto/blackbox/tst_clangdb.cpp b/tests/auto/blackbox/tst_clangdb.cpp index 3a6dd2d92..c4216ac13 100644 --- a/tests/auto/blackbox/tst_clangdb.cpp +++ b/tests/auto/blackbox/tst_clangdb.cpp @@ -36,7 +36,7 @@ #include <QtCore/qdir.h> #include <QtCore/qfile.h> -#include <QtCore/qregexp.h> +#include <QtCore/qregularexpression.h> #include <QtCore/qjsonarray.h> #include <QtCore/qjsondocument.h> @@ -202,17 +202,19 @@ void TestClangDb::checkClangDetectsSourceCodeProblems() // clang-check.exe does not understand MSVC command-line syntax const SettingsPtr s = settings(); qbs::Profile profile(profileName(), s.get()); - if (profile.value("qbs.toolchain").toStringList().contains("msvc")) { + if (profileToolchain(profile).contains("msvc")) { arguments << "-extra-arg-before=--driver-mode=cl"; - } else if (profile.value("qbs.toolchain").toStringList().contains("mingw")) { + } else if (profileToolchain(profile).contains("mingw")) { arguments << "-extra-arg-before=--driver-mode=g++"; } arguments << "-analyze" << "-p" << relativeBuildDir() << sourceFilePath; QVERIFY(runProcess(executable, arguments, stdErr, stdOut) == 0); const QString output = QString::fromLocal8Bit(stdErr); - QVERIFY(output.contains(QRegExp(QStringLiteral("warning.*undefined"), Qt::CaseInsensitive))); - QVERIFY(output.contains(QRegExp(QStringLiteral("warning.*never read"), Qt::CaseInsensitive))); + QVERIFY(output.contains(QRegularExpression(QStringLiteral("warning.*undefined"), + QRegularExpression::CaseInsensitiveOption))); + QVERIFY(output.contains(QRegularExpression(QStringLiteral("warning.*never read"), + QRegularExpression::CaseInsensitiveOption))); } QTEST_MAIN(TestClangDb) diff --git a/tests/auto/buildgraph/CMakeLists.txt b/tests/auto/buildgraph/CMakeLists.txt new file mode 100644 index 000000000..d8a9a4bbe --- /dev/null +++ b/tests/auto/buildgraph/CMakeLists.txt @@ -0,0 +1,7 @@ +add_qbs_test(buildgraph + SOURCES + tst_buildgraph.cpp + tst_buildgraph.h + DEPENDS + qbsquickjsheaders + ) diff --git a/tests/auto/buildgraph/buildgraph.pro b/tests/auto/buildgraph/buildgraph.pro deleted file mode 100644 index 9230bb748..000000000 --- a/tests/auto/buildgraph/buildgraph.pro +++ /dev/null @@ -1,13 +0,0 @@ -TARGET = tst_buildgraph - -SOURCES = tst_buildgraph.cpp -HEADERS = tst_buildgraph.h - -include(../auto.pri) -include(../../../src/app/shared/logging/logging.pri) -include(../../../src/lib/bundledlibs.pri) - -qbs_use_bundled_qtscript { - CONFIG += qbs_do_not_link_bundled_qtscript - include(../../../src/lib/scriptengine/use_scriptengine.pri) -} diff --git a/tests/auto/buildgraph/buildgraph.qbs b/tests/auto/buildgraph/buildgraph.qbs index aa3cdc3f0..694d59578 100644 --- a/tests/auto/buildgraph/buildgraph.qbs +++ b/tests/auto/buildgraph/buildgraph.qbs @@ -1,6 +1,5 @@ -import qbs - -QbsAutotest { +QbsUnittest { + Depends { name: "qbsconsolelogger" } testName: "buildgraph" condition: qbsbuildconfig.enableUnitTests files: [ diff --git a/tests/auto/buildgraph/tst_buildgraph.cpp b/tests/auto/buildgraph/tst_buildgraph.cpp index 20f2cc6a5..84a52c19b 100644 --- a/tests/auto/buildgraph/tst_buildgraph.cpp +++ b/tests/auto/buildgraph/tst_buildgraph.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "tst_buildgraph.h" +#include <app/shared/logging/consolelogger.h> #include <buildgraph/artifact.h> #include <buildgraph/buildgraph.h> #include <buildgraph/cycledetector.h> @@ -47,8 +48,6 @@ #include <logging/logger.h> #include <tools/error.h> -#include "../shared/logging/consolelogger.h" - #include <QtTest/qtest.h> #include <memory> diff --git a/tests/auto/cmdlineparser/CMakeLists.txt b/tests/auto/cmdlineparser/CMakeLists.txt new file mode 100644 index 000000000..bf072e24d --- /dev/null +++ b/tests/auto/cmdlineparser/CMakeLists.txt @@ -0,0 +1,23 @@ +set(PARSER_SOURCES + commandlineoption.cpp + commandlineoption.h + commandlineoptionpool.cpp + commandlineoptionpool.h + commandlineparser.cpp + commandlineparser.h + commandpool.cpp + commandpool.h + commandtype.h + parsercommand.cpp + parsercommand.h + ) +list_transform_prepend(PARSER_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/../../../src/app/qbs/parser/") + +add_qbs_test(cmdlineparser + DEFINES + "QBS_VERSION=\"${QBS_VERSION}\"" + INCLUDES + "${CMAKE_CURRENT_SOURCE_DIR}/../../../src" + SOURCES + tst_cmdlineparser.cpp ../../../src/app/qbs/qbstool.cpp ${PARSER_SOURCES} + ) diff --git a/tests/auto/cmdlineparser/cmdlineparser.pro b/tests/auto/cmdlineparser/cmdlineparser.pro deleted file mode 100644 index a95676be5..000000000 --- a/tests/auto/cmdlineparser/cmdlineparser.pro +++ /dev/null @@ -1,7 +0,0 @@ -TARGET = tst_cmdlineparser - -SOURCES = tst_cmdlineparser.cpp ../../../src/app/qbs/qbstool.cpp - -include(../auto.pri) -include(../../../src/app/qbs/parser/parser.pri) -include(../../../src/app/shared/logging/logging.pri) diff --git a/tests/auto/cmdlineparser/cmdlineparser.qbs b/tests/auto/cmdlineparser/cmdlineparser.qbs index a45e61f5d..340a0c42e 100644 --- a/tests/auto/cmdlineparser/cmdlineparser.qbs +++ b/tests/auto/cmdlineparser/cmdlineparser.qbs @@ -1,8 +1,8 @@ -import qbs import qbs.Utilities QbsAutotest { Depends { name: "qbsversion" } + Depends { name: "qbsconsolelogger" } testName: "cmdlineparser" files: ["tst_cmdlineparser.cpp", "../../../src/app/qbs/qbstool.cpp"] cpp.defines: base.concat([ diff --git a/tests/auto/cmdlineparser/tst_cmdlineparser.cpp b/tests/auto/cmdlineparser/tst_cmdlineparser.cpp index 15b9ec382..6a8b44f89 100644 --- a/tests/auto/cmdlineparser/tst_cmdlineparser.cpp +++ b/tests/auto/cmdlineparser/tst_cmdlineparser.cpp @@ -26,6 +26,8 @@ ** ****************************************************************************/ +#include "../shared.h" + #include <app/qbs/parser/commandlineparser.h> #include <app/shared/logging/consolelogger.h> #include <tools/buildoptions.h> @@ -33,7 +35,6 @@ #include <tools/hostosinfo.h> #include <QtCore/qdir.h> -#include <QtCore/qregexp.h> #include <QtCore/qtemporaryfile.h> #include <QtTest/qtest.h> @@ -56,6 +57,25 @@ private slots: m_fileArgs = QStringList() << "-f" << m_projectFile.fileName(); } + void testResolve_data() + { + QTest::addColumn<QStringList>("args"); + QTest::addColumn<int>("expectedJobCount"); + + QTest::newRow("default job count") << QStringList() << BuildOptions::defaultMaxJobCount(); + QTest::newRow("explicit job count") << QStringList("-j5") << 5; + } + void testResolve() + { + QFETCH(QStringList, args); + QFETCH(int, expectedJobCount); + + CommandLineParser parser; + QVERIFY(parser.parseCommandLine(QStringList("resolve") << args << m_fileArgs)); + QCOMPARE(parser.command(), ResolveCommandType); + QCOMPARE(parser.jobCount(profileName()), expectedJobCount); + } + void testValidCommandLine() { QStringList args; diff --git a/tests/auto/language/CMakeLists.txt b/tests/auto/language/CMakeLists.txt new file mode 100644 index 000000000..9c04b6c8d --- /dev/null +++ b/tests/auto/language/CMakeLists.txt @@ -0,0 +1,10 @@ +add_qbs_test(language + DEFINES + "QBS_VERSION=\"${QBS_VERSION}\"" + DEPENDS + qbsquickjsheaders + Qt6Core5Compat + SOURCES + tst_language.cpp + tst_language.h + ) diff --git a/tests/auto/language/language.pro b/tests/auto/language/language.pro deleted file mode 100644 index 86248d926..000000000 --- a/tests/auto/language/language.pro +++ /dev/null @@ -1,25 +0,0 @@ -TARGET = tst_language - -SOURCES = tst_language.cpp -HEADERS = tst_language.h - -include(../auto.pri) -include(../../../src/app/shared/logging/logging.pri) -include(../../../src/lib/bundledlibs.pri) - -!qbs_use_bundled_qtscript: QT += script - -DATA_DIRS = testdata - -for(data_dir, DATA_DIRS) { - files = $$files($$PWD/$$data_dir/*, true) - win32:files ~= s|\\\\|/|g - for(file, files):!exists($$file/*):FILES += $$file -} - -OTHER_FILES += $$FILES - -qbs_use_bundled_qtscript { - CONFIG += qbs_do_not_link_bundled_qtscript - include(../../../src/lib/scriptengine/use_scriptengine.pri) -} diff --git a/tests/auto/language/language.qbs b/tests/auto/language/language.qbs index f43ca0e44..3767477db 100644 --- a/tests/auto/language/language.qbs +++ b/tests/auto/language/language.qbs @@ -1,13 +1,8 @@ -import qbs import qbs.Utilities -QbsAutotest { +QbsUnittest { Depends { name: "qbsversion" } - Depends { - name: "Qt.script" - condition: !qbsbuildconfig.useBundledQtScript - required: false - } + Depends { name: "qbsconsolelogger" } testName: "language" condition: qbsbuildconfig.enableUnitTests diff --git a/tests/auto/language/testdata/ParentWithExport.qbs b/tests/auto/language/testdata/ParentWithExport.qbs index 16f9a2cd1..b16097e69 100644 --- a/tests/auto/language/testdata/ParentWithExport.qbs +++ b/tests/auto/language/testdata/ParentWithExport.qbs @@ -1,6 +1,6 @@ Product { Export { Depends { name: "dummy" } - dummy.defines: [product.name.toUpperCase()] + dummy.defines: [exportingProduct.name.toUpperCase()] } } diff --git a/tests/auto/language/testdata/additional-product-types.qbs b/tests/auto/language/testdata/additional-product-types.qbs index 686650f42..f84397da3 100644 --- a/tests/auto/language/testdata/additional-product-types.qbs +++ b/tests/auto/language/testdata/additional-product-types.qbs @@ -5,8 +5,8 @@ Product { Depends { name: "dummy" } Depends { name: "dummy2" } - property bool hasTag1: type.contains("tag1") - property bool hasTag2: type.contains("tag2") - property bool hasTag3: type.contains("tag3") - property bool hasTag4: type.contains("tag4") + property bool hasTag1: type.includes("tag1") + property bool hasTag2: type.includes("tag2") + property bool hasTag3: type.includes("tag3") + property bool hasTag4: type.includes("tag4") } diff --git a/tests/auto/language/testdata/chained-probes/modules/m/m.qbs b/tests/auto/language/testdata/chained-probes/modules/m/m.qbs index 3c6bcd1c9..bf68e56b6 100644 --- a/tests/auto/language/testdata/chained-probes/modules/m/m.qbs +++ b/tests/auto/language/testdata/chained-probes/modules/m/m.qbs @@ -2,13 +2,13 @@ Module { Probe { id: probe1 property string probe1Prop - configure: { probe1Prop = "probe1Val"; found = true; } + configure: { probe1Prop = "probe1Val"; found = true } } Probe { id: probe2 property string inputProp: prop1 property string probe2Prop - configure: { probe2Prop = inputProp + "probe2Val"; found = true; } + configure: { probe2Prop = inputProp + "probe2Val"; found = true } } property string prop1: probe1.probe1Prop property string prop2: probe2.probe2Prop diff --git a/tests/auto/language/testdata/conditionaldepends.qbs b/tests/auto/language/testdata/conditionaldepends.qbs index 9a499da92..e4f9fae7d 100644 --- a/tests/auto/language/testdata/conditionaldepends.qbs +++ b/tests/auto/language/testdata/conditionaldepends.qbs @@ -14,25 +14,25 @@ Project { Product { name: "product_props_true" property bool someTrueProp: true - Depends { condition: someTrueProp; name: "dummy"} + Depends { condition: someTrueProp; name: "dummy" } } Product { name: "product_props_false" property bool someFalseProp: false - Depends { condition: someFalseProp; name: "dummy"} + Depends { condition: someFalseProp; name: "dummy" } } property bool someTruePrjProp: true Product { name: "project_props_true" - Depends { condition: project.someTruePrjProp; name: "dummy"} + Depends { condition: project.someTruePrjProp; name: "dummy" } } property bool someFalsePrjProp: false Product { name: "project_props_false" - Depends { condition: project.someFalsePrjProp; name: "dummy"} + Depends { condition: project.someFalsePrjProp; name: "dummy" } } Product { diff --git a/tests/auto/language/testdata/conditionaldepends_base.qbs b/tests/auto/language/testdata/conditionaldepends_base.qbs index 5ab5b973a..74eb958d4 100644 --- a/tests/auto/language/testdata/conditionaldepends_base.qbs +++ b/tests/auto/language/testdata/conditionaldepends_base.qbs @@ -1,4 +1,4 @@ -Application { +Product { name: 'conditionaldepends_base' property bool someProp: false Depends { diff --git a/tests/auto/language/testdata/dotted-names/dotted-names.qbs b/tests/auto/language/testdata/dotted-names/dotted-names.qbs index cf5658384..714988f0b 100644 --- a/tests/auto/language/testdata/dotted-names/dotted-names.qbs +++ b/tests/auto/language/testdata/dotted-names/dotted-names.qbs @@ -1,5 +1,3 @@ -import qbs - Project { name: "theProject" property bool includeDottedProduct diff --git a/tests/auto/language/testdata/dotted-names/modules/x/y/xy.qbs b/tests/auto/language/testdata/dotted-names/modules/x/y/xy.qbs index 71cfac9cb..eee46458d 100644 --- a/tests/auto/language/testdata/dotted-names/modules/x/y/xy.qbs +++ b/tests/auto/language/testdata/dotted-names/modules/x/y/xy.qbs @@ -1,5 +1,3 @@ -import qbs - Module { property string z: "default" } diff --git a/tests/auto/language/testdata/erroneous/duplicate-multiplex-value.qbs b/tests/auto/language/testdata/duplicate-multiplex-value.qbs index 56da41af1..24b246604 100644 --- a/tests/auto/language/testdata/erroneous/duplicate-multiplex-value.qbs +++ b/tests/auto/language/testdata/duplicate-multiplex-value.qbs @@ -1,5 +1,3 @@ -import qbs - Product { name: "p" multiplexByQbsProperties: "architectures" diff --git a/tests/auto/language/testdata/erroneous/duplicate-multiplex-value2.qbs b/tests/auto/language/testdata/duplicate-multiplex-value2.qbs index e412e5210..d6c057a9e 100644 --- a/tests/auto/language/testdata/erroneous/duplicate-multiplex-value2.qbs +++ b/tests/auto/language/testdata/duplicate-multiplex-value2.qbs @@ -1,5 +1,3 @@ -import qbs - Product { name: "p" multiplexByQbsProperties: ["architectures", "buildVariants", "architectures"] diff --git a/tests/auto/language/testdata/erroneous/ambiguous-multiplex-dependency.qbs b/tests/auto/language/testdata/erroneous/ambiguous-multiplex-dependency.qbs new file mode 100644 index 000000000..6f60b1faf --- /dev/null +++ b/tests/auto/language/testdata/erroneous/ambiguous-multiplex-dependency.qbs @@ -0,0 +1,14 @@ +Project { + Product { + name: "a" + multiplexByQbsProperties: ["architectures", "buildVariants"] + qbs.architectures: ["x86", "arm"] + qbs.buildVariants: ["debug", "release"] + } + Product { + name: "b" + Depends { name: "a" } + multiplexByQbsProperties: ["architectures"] + qbs.architectures: ["x86", "arm"] + } +} diff --git a/tests/auto/language/testdata/erroneous/conflicting_fileTagsFilter.qbs b/tests/auto/language/testdata/erroneous/conflicting_fileTagsFilter.qbs index 97e11bb9b..3738e0cca 100644 --- a/tests/auto/language/testdata/erroneous/conflicting_fileTagsFilter.qbs +++ b/tests/auto/language/testdata/erroneous/conflicting_fileTagsFilter.qbs @@ -1,10 +1,11 @@ -Application { +Product { + type: "app" Group { - fileTagsFilter: "application" + fileTagsFilter: "app" qbs.install: true } Group { - fileTagsFilter: "application" + fileTagsFilter: "app" qbs.install: false } } diff --git a/tests/auto/language/testdata/erroneous/dependency-profile-mismatch-2.qbs b/tests/auto/language/testdata/erroneous/dependency-profile-mismatch-2.qbs new file mode 100644 index 000000000..d76907a35 --- /dev/null +++ b/tests/auto/language/testdata/erroneous/dependency-profile-mismatch-2.qbs @@ -0,0 +1,17 @@ +Project { + Profile { + name: "profile1" + } + Profile { + name: "profile2" + } + + Product { + name: "dep" + qbs.profiles: ["profile1", "profile2"] + } + Product { + name: "main" + Depends { name: "dep"; profiles: ["profile47"]; } + } +} diff --git a/tests/auto/language/testdata/erroneous/dependency-profile-mismatch.qbs b/tests/auto/language/testdata/erroneous/dependency-profile-mismatch.qbs new file mode 100644 index 000000000..e014fa9b1 --- /dev/null +++ b/tests/auto/language/testdata/erroneous/dependency-profile-mismatch.qbs @@ -0,0 +1,14 @@ +Project { + Profile { + name: "profile1" + } + + Product { + name: "dep" + qbs.profiles: ["profile1"] + } + Product { + name: "main" + Depends { name: "dep"; profiles: ["profile47"]; } + } +} diff --git a/tests/auto/language/testdata/erroneous/dependency_cycle.qbs b/tests/auto/language/testdata/erroneous/dependency_cycle.qbs index 83a6e35f6..80c678f89 100644 --- a/tests/auto/language/testdata/erroneous/dependency_cycle.qbs +++ b/tests/auto/language/testdata/erroneous/dependency_cycle.qbs @@ -1,15 +1,15 @@ Project { - CppApplication { + Product { name: "A" Depends { name: "B" } files: ["main.cpp"] } - CppApplication { + Product { name: "B" Depends { name: "C" } files: ["main.cpp"] } - CppApplication { + Product { name: "C" Depends { name: "A" } files: ["main.cpp"] diff --git a/tests/auto/language/testdata/erroneous/dependency_cycle2.qbs b/tests/auto/language/testdata/erroneous/dependency_cycle2.qbs index 335355480..4aff0b75c 100644 --- a/tests/auto/language/testdata/erroneous/dependency_cycle2.qbs +++ b/tests/auto/language/testdata/erroneous/dependency_cycle2.qbs @@ -1,20 +1,20 @@ Project { - CppApplication { + Product { name: "A" Depends { name: "B" } files: ["main.cpp"] } - CppApplication { + Product { name: "B" Depends { name: "C" } files: ["main.cpp"] } - CppApplication { + Product { name: "C" Depends { name: "A" } files: ["main.cpp"] } - CppApplication { + Product { name: "D" files: ["main.cpp"] } diff --git a/tests/auto/language/testdata/erroneous/dependency_cycle3a.qbs b/tests/auto/language/testdata/erroneous/dependency_cycle3a.qbs new file mode 100644 index 000000000..a0660c074 --- /dev/null +++ b/tests/auto/language/testdata/erroneous/dependency_cycle3a.qbs @@ -0,0 +1,11 @@ +Project { + Product { + name: "B" + Depends { productTypes: ["a"] } + } + Product { + type: ["a"] + name: "A" + Depends { name: "B" } + } +} diff --git a/tests/auto/language/testdata/erroneous/frozen-object-list.qbs b/tests/auto/language/testdata/erroneous/frozen-object-list.qbs new file mode 100644 index 000000000..8bbd2b413 --- /dev/null +++ b/tests/auto/language/testdata/erroneous/frozen-object-list.qbs @@ -0,0 +1,17 @@ + +Product { + Probe { + id: probe + property varList output + configure: { + output = [{"key": "value"}]; + found = true; + } + } + + property var test: { + var result = probe.output; + result.push({}); + return result; + } +} diff --git a/tests/auto/language/testdata/erroneous/frozen-object.qbs b/tests/auto/language/testdata/erroneous/frozen-object.qbs new file mode 100644 index 000000000..0f891d04b --- /dev/null +++ b/tests/auto/language/testdata/erroneous/frozen-object.qbs @@ -0,0 +1,18 @@ + +Product { + Probe { + id: probe + property var output + configure: { + output = {"key": "value"} + found = true + } + } + + property var test: { + "use strict" + var result = probe.output; + result.key = "newValue"; + return result; + } +} diff --git a/tests/auto/language/testdata/erroneous/invalid_file.qbs b/tests/auto/language/testdata/erroneous/invalid_file.qbs index c461b87ef..54ec27410 100644 --- a/tests/auto/language/testdata/erroneous/invalid_file.qbs +++ b/tests/auto/language/testdata/erroneous/invalid_file.qbs @@ -1,3 +1,3 @@ -Application { +Product { files: ["main.cpp", "other.h"] } diff --git a/tests/auto/language/testdata/erroneous/missing-colon.qbs b/tests/auto/language/testdata/erroneous/missing-colon.qbs index e62eb7cfd..6e136bb56 100644 --- a/tests/auto/language/testdata/erroneous/missing-colon.qbs +++ b/tests/auto/language/testdata/erroneous/missing-colon.qbs @@ -1,3 +1,5 @@ -CppApplication { - cpp.dynamicLibraries { } +Product { + Depends { name: "dummy" } + qbsSearchPaths: ".." + dummy.cxxFlags { } } diff --git a/tests/auto/language/testdata/erroneous/missing-js-file.qbs b/tests/auto/language/testdata/erroneous/missing-js-file.qbs new file mode 100644 index 000000000..a3274a35b --- /dev/null +++ b/tests/auto/language/testdata/erroneous/missing-js-file.qbs @@ -0,0 +1,3 @@ +Product { + Depends { name: "missing-js-file-module" } +} diff --git a/tests/auto/language/testdata/erroneous/module-property-binding-in-project.qbs b/tests/auto/language/testdata/erroneous/module-property-binding-in-project.qbs new file mode 100644 index 000000000..667088c17 --- /dev/null +++ b/tests/auto/language/testdata/erroneous/module-property-binding-in-project.qbs @@ -0,0 +1,3 @@ +Project { + qbs.sysroot: "/" +} diff --git a/tests/auto/language/testdata/erroneous/module-with-id.qbs b/tests/auto/language/testdata/erroneous/module-with-id.qbs new file mode 100644 index 000000000..5b980100f --- /dev/null +++ b/tests/auto/language/testdata/erroneous/module-with-id.qbs @@ -0,0 +1,4 @@ +Product { + name: "p" + Depends { name: "module-with-id" } +} diff --git a/tests/auto/language/testdata/erroneous/modules/missing-js-file-module/missing-js-file-module.qbs b/tests/auto/language/testdata/erroneous/modules/missing-js-file-module/missing-js-file-module.qbs new file mode 100644 index 000000000..31302b5c2 --- /dev/null +++ b/tests/auto/language/testdata/erroneous/modules/missing-js-file-module/missing-js-file-module.qbs @@ -0,0 +1,3 @@ +import "missing-js-file.js" as MissingJsFile + +Module { } diff --git a/tests/auto/language/testdata/erroneous/modules/missing-js-file-module/missing-js-file.js b/tests/auto/language/testdata/erroneous/modules/missing-js-file-module/missing-js-file.js new file mode 100644 index 000000000..b66048a8f --- /dev/null +++ b/tests/auto/language/testdata/erroneous/modules/missing-js-file-module/missing-js-file.js @@ -0,0 +1 @@ +var userfile = require("javascriptfile.js") diff --git a/tests/auto/language/testdata/erroneous/modules/module-with-id/ModuleWithId.qbs b/tests/auto/language/testdata/erroneous/modules/module-with-id/ModuleWithId.qbs new file mode 100644 index 000000000..d20b96784 --- /dev/null +++ b/tests/auto/language/testdata/erroneous/modules/module-with-id/ModuleWithId.qbs @@ -0,0 +1 @@ +ModuleWithIdParent { id: foo } diff --git a/tests/auto/language/testdata/erroneous/modules/module-with-id/ModuleWithIdParent.qbs b/tests/auto/language/testdata/erroneous/modules/module-with-id/ModuleWithIdParent.qbs new file mode 100644 index 000000000..5e45122de --- /dev/null +++ b/tests/auto/language/testdata/erroneous/modules/module-with-id/ModuleWithIdParent.qbs @@ -0,0 +1 @@ +Module {} diff --git a/tests/auto/language/testdata/erroneous/original-in-export-item.qbs b/tests/auto/language/testdata/erroneous/original-in-export-item.qbs index 51fedb9a2..c83601cfb 100644 --- a/tests/auto/language/testdata/erroneous/original-in-export-item.qbs +++ b/tests/auto/language/testdata/erroneous/original-in-export-item.qbs @@ -1,5 +1,3 @@ -import qbs - Project { Product { name: "a" diff --git a/tests/auto/language/testdata/erroneous/original-in-export-item2.qbs b/tests/auto/language/testdata/erroneous/original-in-export-item2.qbs index d932d4aee..1c9f3de4b 100644 --- a/tests/auto/language/testdata/erroneous/original-in-export-item2.qbs +++ b/tests/auto/language/testdata/erroneous/original-in-export-item2.qbs @@ -1,5 +1,3 @@ -import qbs - Project { Product { name: "a" diff --git a/tests/auto/language/testdata/erroneous/original-in-export-item3.qbs b/tests/auto/language/testdata/erroneous/original-in-export-item3.qbs index d7bcb322e..d23ad0a08 100644 --- a/tests/auto/language/testdata/erroneous/original-in-export-item3.qbs +++ b/tests/auto/language/testdata/erroneous/original-in-export-item3.qbs @@ -1,5 +1,3 @@ -import qbs - Project { Product { name: "a" diff --git a/tests/auto/language/testdata/erroneous/original-in-module-prototype.qbs b/tests/auto/language/testdata/erroneous/original-in-module-prototype.qbs index e7128092a..00661fb66 100644 --- a/tests/auto/language/testdata/erroneous/original-in-module-prototype.qbs +++ b/tests/auto/language/testdata/erroneous/original-in-module-prototype.qbs @@ -1,5 +1,3 @@ -import qbs - Product { Depends { name: "module-with-invalid-original" } } diff --git a/tests/auto/language/testdata/erroneous/properties-item-with-invalid-condition.qbs b/tests/auto/language/testdata/erroneous/properties-item-with-invalid-condition.qbs index 5b1a41f1b..0b48731ae 100644 --- a/tests/auto/language/testdata/erroneous/properties-item-with-invalid-condition.qbs +++ b/tests/auto/language/testdata/erroneous/properties-item-with-invalid-condition.qbs @@ -1,7 +1,7 @@ Product { Depends { name: "cpp" } Properties { - condition: cpp.nonexistingproperty.contains("somevalue") + condition: cpp.nonexistingproperty.includes("somevalue") cpp.defines: ["ABC"] } } diff --git a/tests/auto/language/testdata/eval-error-in-non-present-module.qbs b/tests/auto/language/testdata/eval-error-in-non-present-module.qbs index c112bc6d4..6882a2216 100644 --- a/tests/auto/language/testdata/eval-error-in-non-present-module.qbs +++ b/tests/auto/language/testdata/eval-error-in-non-present-module.qbs @@ -1,5 +1,3 @@ -import qbs - Product { name: "p" property bool moduleRequired diff --git a/tests/auto/language/testdata/exports.qbs b/tests/auto/language/testdata/exports.qbs index cc86b1e4a..0071aadce 100644 --- a/tests/auto/language/testdata/exports.qbs +++ b/tests/auto/language/testdata/exports.qbs @@ -1,7 +1,8 @@ import "exports_product.qbs" as ProductWithInheritedExportItem Project { - Application { + Product { + type: "app" name: "myapp" Depends { name: "mylib" } Depends { name: "dummy" } @@ -15,30 +16,35 @@ Project { "subdir2/exports-mylib2.qbs" ] - Application { + Product { + type: "app" name: "A" Depends { name: "qbs" } Depends { name: "B" } } - StaticLibrary { + Product { + type: "lib" name: "B" Export { Depends { name: "C" } Depends { name: "qbs" } } } - StaticLibrary { + Product { + type: "lib" name: "C" Export { Depends { name: "D" } Depends { name: "qbs" } } } - StaticLibrary { + Product { + type: "lib" name: "D" } - Application { + Product { + type: "app" name: "myapp2" Depends { name: "productWithInheritedExportItem" } Depends { name: "qbs" } @@ -46,7 +52,7 @@ Project { ProductWithInheritedExportItem { name: "productWithInheritedExportItem" Export { - dummy.cFlags: base.concat("PRODUCT_" + product.name.toUpperCase()) + dummy.cFlags: base.concat("PRODUCT_" + exportingProduct.name.toUpperCase()) dummy.cxxFlags: ["-bar"] Properties { condition: true @@ -54,7 +60,8 @@ Project { } } } - Application { + Product { + type: "app" name: "myapp3" Depends { name: "productWithInheritedExportItem"; versionAtLeast: "2.0" } } @@ -125,7 +132,7 @@ Project { Export { property bool depend: false - property var config: product.config + property var config: exportingProduct.config Depends { condition: depend; name: "cpp" } Properties { condition: depend; cpp.includePaths: ["."] } } @@ -142,8 +149,9 @@ Project { name: "broken_cycle1" Export { property bool depend: true - Depends { name: "broken_cycle3"; condition: depend } } + Depends { name: "broken_cycle3"; condition: depend } } + } Product { name: "broken_cycle2" Export { diff --git a/tests/auto/language/testdata/exports_product.qbs b/tests/auto/language/testdata/exports_product.qbs index dc4c9f462..394d388d9 100644 --- a/tests/auto/language/testdata/exports_product.qbs +++ b/tests/auto/language/testdata/exports_product.qbs @@ -2,7 +2,7 @@ Product { Export { version: "2.0" Depends { name: "dummy" } - dummy.cFlags: ["BASE_" + product.name.toUpperCase()] + dummy.cFlags: ["BASE_" + exportingProduct.name.toUpperCase()] dummy.cxxFlags: ["-foo"] dummy.defines: ["ABC"] } diff --git a/tests/auto/language/testdata/getNativeSetting.qbs b/tests/auto/language/testdata/getNativeSetting.qbs index 975aefebc..73af01316 100644 --- a/tests/auto/language/testdata/getNativeSetting.qbs +++ b/tests/auto/language/testdata/getNativeSetting.qbs @@ -1,15 +1,17 @@ import qbs.FileInfo import qbs.Utilities +import qbs.Host + Project { Product { name: "p1" targetName: { - if (qbs.hostOS.contains("macos")) { + if (Host.os().includes("macos")) { return Utilities.getNativeSetting("/System/Library/CoreServices/SystemVersion.plist", "ProductName"); - } else if (qbs.hostOS.contains("windows")) { + } else if (Host.os().includes("windows")) { var productName = Utilities.getNativeSetting("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion", "ProductName"); - if (productName.contains("Windows")) { + if (productName.includes("Windows")) { return "Windows"; } return undefined; diff --git a/tests/auto/language/testdata/groupconditions.qbs b/tests/auto/language/testdata/groupconditions.qbs index b7f383d45..4f55db9cd 100644 --- a/tests/auto/language/testdata/groupconditions.qbs +++ b/tests/auto/language/testdata/groupconditions.qbs @@ -43,7 +43,7 @@ Project { Product { name: "condition_accessing_module_property" Group { - condition: qbs.targetOS.contains("narf") + condition: qbs.targetOS.includes("narf") files: ["main.cpp"] qbs.install: false } diff --git a/tests/auto/language/testdata/inherited-properties-items/imports/DebugName.qbs b/tests/auto/language/testdata/inherited-properties-items/imports/DebugName.qbs index 5ac15658c..d129dc9db 100644 --- a/tests/auto/language/testdata/inherited-properties-items/imports/DebugName.qbs +++ b/tests/auto/language/testdata/inherited-properties-items/imports/DebugName.qbs @@ -1,5 +1,3 @@ -import qbs - Properties { condition: qbs.buildVariant === "debug" name: "product_debug" diff --git a/tests/auto/language/testdata/inherited-properties-items/imports/ReleaseName.qbs b/tests/auto/language/testdata/inherited-properties-items/imports/ReleaseName.qbs index e33c5652b..57ab96a7e 100644 --- a/tests/auto/language/testdata/inherited-properties-items/imports/ReleaseName.qbs +++ b/tests/auto/language/testdata/inherited-properties-items/imports/ReleaseName.qbs @@ -1,5 +1,3 @@ -import qbs - Properties { condition: qbs.buildVariant === "release" name: "product_release" diff --git a/tests/auto/language/testdata/inherited-properties-items/inherited-properties-items-product.qbs b/tests/auto/language/testdata/inherited-properties-items/inherited-properties-items-product.qbs index c20f045c8..6d148ba53 100644 --- a/tests/auto/language/testdata/inherited-properties-items/inherited-properties-items-product.qbs +++ b/tests/auto/language/testdata/inherited-properties-items/inherited-properties-items-product.qbs @@ -1,5 +1,3 @@ -import qbs - Product { name: "product_default" DebugName {} diff --git a/tests/auto/language/testdata/inherited-properties-items/inherited-properties-items.qbs b/tests/auto/language/testdata/inherited-properties-items/inherited-properties-items.qbs index 40d41c2fb..52f7ffc00 100644 --- a/tests/auto/language/testdata/inherited-properties-items/inherited-properties-items.qbs +++ b/tests/auto/language/testdata/inherited-properties-items/inherited-properties-items.qbs @@ -1,5 +1,3 @@ -import qbs - Project { qbsSearchPaths: sourceDirectory references: "inherited-properties-items-product.qbs" diff --git a/tests/auto/language/testdata/invalid-prop-on-non-required-module/invalid-prop-on-non-required-module.qbs b/tests/auto/language/testdata/invalid-prop-on-non-required-module/invalid-prop-on-non-required-module.qbs new file mode 100644 index 000000000..80ae6ad93 --- /dev/null +++ b/tests/auto/language/testdata/invalid-prop-on-non-required-module/invalid-prop-on-non-required-module.qbs @@ -0,0 +1,19 @@ +Project { + property bool useExistingModule + + Product { + name: "a" + condition: project.useExistingModule + Depends { name: "deploader" } + Depends { name: "dep" } + dep.nosuchprop: true + } + + Product { + name: "b" + condition: !project.useExistingModule + Depends { name: "deploader" } + Depends { name: "random"; required: false } + random.nosuchprop: true + } +} diff --git a/tests/auto/language/testdata/invalid-prop-on-non-required-module/modules/dep/dep.qbs b/tests/auto/language/testdata/invalid-prop-on-non-required-module/modules/dep/dep.qbs new file mode 100644 index 000000000..5e45122de --- /dev/null +++ b/tests/auto/language/testdata/invalid-prop-on-non-required-module/modules/dep/dep.qbs @@ -0,0 +1 @@ +Module {} diff --git a/tests/auto/language/testdata/invalid-prop-on-non-required-module/modules/deploader/deploader.qbs b/tests/auto/language/testdata/invalid-prop-on-non-required-module/modules/deploader/deploader.qbs new file mode 100644 index 000000000..15a1b5309 --- /dev/null +++ b/tests/auto/language/testdata/invalid-prop-on-non-required-module/modules/deploader/deploader.qbs @@ -0,0 +1,7 @@ +Module { + // This indirection exists to properly model QBS-1776. + // "deploader" corresponds to "bundle", and "dep" corresponds to "codesign" + Depends { condition: project.useExistingModule; name: "dep"; required: false } + + Depends { condition: !project.useExistingModule; name: "random"; required: false } +} diff --git a/tests/auto/language/testdata/jsextensions.js b/tests/auto/language/testdata/jsextensions.js index df74a263b..5c5821e86 100644 --- a/tests/auto/language/testdata/jsextensions.js +++ b/tests/auto/language/testdata/jsextensions.js @@ -57,9 +57,9 @@ var a = ["one", "two", "three"]; initTestContext("Array.prototype.contains"); for (var k in a) verify(k !== "contains"); -verify(a.contains("one")); -verify(a.contains("two")); -verify(a.contains("three")); -verify(!a.contains("four")); +verify(a.includes("one")); +verify(a.includes("two")); +verify(a.includes("three")); +verify(!a.includes("four")); })() // END function wrapper diff --git a/tests/auto/language/testdata/local-profile-as-top-level-profile.qbs b/tests/auto/language/testdata/local-profile-as-top-level-profile.qbs new file mode 100644 index 000000000..9bca3c599 --- /dev/null +++ b/tests/auto/language/testdata/local-profile-as-top-level-profile.qbs @@ -0,0 +1,7 @@ +Product { + Profile { + name: "test-profile" + qbs.architecture: "arm" + qbs.targetPlatform: "macos" + } +} diff --git a/tests/auto/language/testdata/erroneous/module-depends-on-product.qbs b/tests/auto/language/testdata/module-depends-on-product.qbs index a7db9e036..a7db9e036 100644 --- a/tests/auto/language/testdata/erroneous/module-depends-on-product.qbs +++ b/tests/auto/language/testdata/module-depends-on-product.qbs diff --git a/tests/auto/language/testdata/module-name-collisions/complex-collision.qbs b/tests/auto/language/testdata/module-name-collisions/complex-collision.qbs new file mode 100644 index 000000000..cd55aa946 --- /dev/null +++ b/tests/auto/language/testdata/module-name-collisions/complex-collision.qbs @@ -0,0 +1,4 @@ +Product { + Depends { name: "prefix1.middle1" } + Depends { name: "prefix1.middle1.suffix1" } +} diff --git a/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/middle1.qbs b/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/middle1.qbs new file mode 100644 index 000000000..5e45122de --- /dev/null +++ b/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/middle1.qbs @@ -0,0 +1 @@ +Module {} diff --git a/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/suffix1/suffix1.qbs b/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/suffix1/suffix1.qbs new file mode 100644 index 000000000..5e45122de --- /dev/null +++ b/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/suffix1/suffix1.qbs @@ -0,0 +1 @@ +Module {} diff --git a/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/suffix2/suffix2.qbs b/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/suffix2/suffix2.qbs new file mode 100644 index 000000000..5e45122de --- /dev/null +++ b/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/suffix2/suffix2.qbs @@ -0,0 +1 @@ +Module {} diff --git a/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle2/suffix/suffix.qbs b/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle2/suffix/suffix.qbs new file mode 100644 index 000000000..5e45122de --- /dev/null +++ b/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle2/suffix/suffix.qbs @@ -0,0 +1 @@ +Module {} diff --git a/tests/auto/language/testdata/module-name-collisions/modules/prefix1/prefix1.qbs b/tests/auto/language/testdata/module-name-collisions/modules/prefix1/prefix1.qbs new file mode 100644 index 000000000..84957060c --- /dev/null +++ b/tests/auto/language/testdata/module-name-collisions/modules/prefix1/prefix1.qbs @@ -0,0 +1,2 @@ +Module { +} diff --git a/tests/auto/language/testdata/erroneous/modules/prefix1/suffix/suffix.qbs b/tests/auto/language/testdata/module-name-collisions/modules/prefix1/suffix/suffix.qbs index 218a4feb7..218a4feb7 100644 --- a/tests/auto/language/testdata/erroneous/modules/prefix1/suffix/suffix.qbs +++ b/tests/auto/language/testdata/module-name-collisions/modules/prefix1/suffix/suffix.qbs diff --git a/tests/auto/language/testdata/module-name-collisions/modules/prefix2/prefix2.qbs b/tests/auto/language/testdata/module-name-collisions/modules/prefix2/prefix2.qbs new file mode 100644 index 000000000..a5aaa6f8b --- /dev/null +++ b/tests/auto/language/testdata/module-name-collisions/modules/prefix2/prefix2.qbs @@ -0,0 +1,3 @@ +Module { + Depends { name: "prefix2.suffix" } +} diff --git a/tests/auto/language/testdata/module-name-collisions/modules/prefix2/suffix/suffix.qbs b/tests/auto/language/testdata/module-name-collisions/modules/prefix2/suffix/suffix.qbs new file mode 100644 index 000000000..84957060c --- /dev/null +++ b/tests/auto/language/testdata/module-name-collisions/modules/prefix2/suffix/suffix.qbs @@ -0,0 +1,2 @@ +Module { +} diff --git a/tests/auto/language/testdata/module-name-collisions/no-collision1.qbs b/tests/auto/language/testdata/module-name-collisions/no-collision1.qbs new file mode 100644 index 000000000..e5a94ad66 --- /dev/null +++ b/tests/auto/language/testdata/module-name-collisions/no-collision1.qbs @@ -0,0 +1,4 @@ +Product { + Depends { name: "prefix1.middle1.suffix1" } + Depends { name: "prefix1.middle1.suffix2" } +} diff --git a/tests/auto/language/testdata/module-name-collisions/no-collision2.qbs b/tests/auto/language/testdata/module-name-collisions/no-collision2.qbs new file mode 100644 index 000000000..664ec1729 --- /dev/null +++ b/tests/auto/language/testdata/module-name-collisions/no-collision2.qbs @@ -0,0 +1,4 @@ +Product { + Depends { name: "prefix1.middle1" } + Depends { name: "prefix1.middle2.suffix" } +} diff --git a/tests/auto/language/testdata/erroneous/same-module-prefix1.qbs b/tests/auto/language/testdata/module-name-collisions/simple-collision1.qbs index 8aba31c2a..8aba31c2a 100644 --- a/tests/auto/language/testdata/erroneous/same-module-prefix1.qbs +++ b/tests/auto/language/testdata/module-name-collisions/simple-collision1.qbs diff --git a/tests/auto/language/testdata/erroneous/same-module-prefix2.qbs b/tests/auto/language/testdata/module-name-collisions/simple-collision2.qbs index 6679091c2..6679091c2 100644 --- a/tests/auto/language/testdata/erroneous/same-module-prefix2.qbs +++ b/tests/auto/language/testdata/module-name-collisions/simple-collision2.qbs diff --git a/tests/auto/language/testdata/module-parameters/module-parameters.qbs b/tests/auto/language/testdata/module-parameters/module-parameters.qbs new file mode 100644 index 000000000..48169d601 --- /dev/null +++ b/tests/auto/language/testdata/module-parameters/module-parameters.qbs @@ -0,0 +1,35 @@ +Project { + property bool overrideFromModule + property bool overrideFromExport + property bool overrideFromProduct + + Product { + name: "dep" + Export { + Depends { + name: "higher"; + condition: project.overrideFromExport + lower.param: "fromExportDepends" + } + Parameters { lower.param: "fromParameters" } + } + } + Product { + name: "main" + + Depends { + name: "dep" + condition: project.overrideFromProduct + lower.param: "fromProductDepends" + } + Depends { + name: "higher" + condition: project.overrideFromProduct + lower.param: "fromProductDepends" + } + Depends { name: "dep"; condition: !project.overrideFromProduct } + Depends { name: "higher"; condition: !project.overrideFromProduct } + Depends { name: "highest" } + Depends { name: "broken"; required: false } + } +} diff --git a/tests/auto/language/testdata/module-parameters/modules/broken/broken.qbs b/tests/auto/language/testdata/module-parameters/modules/broken/broken.qbs new file mode 100644 index 000000000..ae7b4c4ef --- /dev/null +++ b/tests/auto/language/testdata/module-parameters/modules/broken/broken.qbs @@ -0,0 +1,4 @@ +Module { + Depends { name: "higher"; lower.param: "shouldNeverAppear" } + validate: { throw "As the name indicates, this module is broken."; } +} diff --git a/tests/auto/language/testdata/module-parameters/modules/higher/higher.qbs b/tests/auto/language/testdata/module-parameters/modules/higher/higher.qbs new file mode 100644 index 000000000..006e05a93 --- /dev/null +++ b/tests/auto/language/testdata/module-parameters/modules/higher/higher.qbs @@ -0,0 +1,4 @@ +Module { + Depends { name: "lower" } + Parameters { lower.param: "fromParameters" } +} diff --git a/tests/auto/language/testdata/module-parameters/modules/highest/highest.qbs b/tests/auto/language/testdata/module-parameters/modules/highest/highest.qbs new file mode 100644 index 000000000..83b0a0a03 --- /dev/null +++ b/tests/auto/language/testdata/module-parameters/modules/highest/highest.qbs @@ -0,0 +1,7 @@ +Module { + Depends { + name: "higher" + condition: project.overrideFromModule + lower.param: "fromModuleDepends" + } +} diff --git a/tests/auto/language/testdata/module-parameters/modules/lower/lower.qbs b/tests/auto/language/testdata/module-parameters/modules/lower/lower.qbs new file mode 100644 index 000000000..11436ecd8 --- /dev/null +++ b/tests/auto/language/testdata/module-parameters/modules/lower/lower.qbs @@ -0,0 +1,3 @@ +Module { + Parameter { property string param: "origin" } +} diff --git a/tests/auto/language/testdata/modulepropertiesingroups.qbs b/tests/auto/language/testdata/modulepropertiesingroups.qbs index e3857bdf4..49f24c0ca 100644 --- a/tests/auto/language/testdata/modulepropertiesingroups.qbs +++ b/tests/auto/language/testdata/modulepropertiesingroups.qbs @@ -80,4 +80,13 @@ Project { } } } + + Product { + name: "module-property-in-group-condition" + Depends { name: "cpp" } + Group { + condition: qbs.architecture === "x86_64" + cpp.includePaths: "." + } + } } diff --git a/tests/auto/language/testdata/modules/broken/broken.qbs b/tests/auto/language/testdata/modules/broken/broken.qbs index b960117cf..a80547340 100644 --- a/tests/auto/language/testdata/modules/broken/broken.qbs +++ b/tests/auto/language/testdata/modules/broken/broken.qbs @@ -1,5 +1,3 @@ -import qbs - Module { Probe { id: theProbe diff --git a/tests/auto/language/testdata/modules/dummy/dummy.qbs b/tests/auto/language/testdata/modules/dummy/dummy.qbs index b1791ac96..623abc413 100644 --- a/tests/auto/language/testdata/modules/dummy/dummy.qbs +++ b/tests/auto/language/testdata/modules/dummy/dummy.qbs @@ -16,7 +16,7 @@ DummyBase { property string zort: "zort in dummy" property pathList includePaths property path somePath - property stringList listProp: product.type.contains("blubb") ? ["123"] : ["456"] + property stringList listProp: product.type.includes("blubb") ? ["123"] : ["456"] property bool controllingProp: false property stringList listProp2: controllingProp diff --git a/tests/auto/language/testdata/modules/dummyqt/core/dummycore.qbs b/tests/auto/language/testdata/modules/dummyqt/core/dummycore.qbs index 746c7e37b..2764af9c2 100644 --- a/tests/auto/language/testdata/modules/dummyqt/core/dummycore.qbs +++ b/tests/auto/language/testdata/modules/dummyqt/core/dummycore.qbs @@ -1,11 +1,10 @@ Module { - id: qtcore property int versionMajor: 5 property int versionMinor: 0 property int versionPatch: 0 property string version: versionMajor.toString() + "." + versionMinor.toString() + "." + versionPatch.toString() property string coreProperty: "coreProperty" - property string coreVersion: qtcore.version + property string coreVersion: version property string zort: "zort in dummyqt.core" Depends { name: "dummy" } diff --git a/tests/auto/language/testdata/erroneous/modules/module-with-product-dependency/module-with-product-dependency.qbs b/tests/auto/language/testdata/modules/module-with-product-dependency/module-with-product-dependency.qbs index 5781bd6de..5781bd6de 100644 --- a/tests/auto/language/testdata/erroneous/modules/module-with-product-dependency/module-with-product-dependency.qbs +++ b/tests/auto/language/testdata/modules/module-with-product-dependency/module-with-product-dependency.qbs diff --git a/tests/auto/language/testdata/modules/multiple_backends/backend1.qbs b/tests/auto/language/testdata/modules/multiple_backends/backend1.qbs index 794c67827..4f78a89ae 100644 --- a/tests/auto/language/testdata/modules/multiple_backends/backend1.qbs +++ b/tests/auto/language/testdata/modules/multiple_backends/backend1.qbs @@ -1,4 +1,4 @@ Module { - condition: qbs.targetOS.contains("os1") + condition: qbs.targetOS.includes("os1") property string prop: "backend 1" } diff --git a/tests/auto/language/testdata/modules/multiple_backends/backend2.qbs b/tests/auto/language/testdata/modules/multiple_backends/backend2.qbs index 2073c4d0b..e7a44d4c7 100644 --- a/tests/auto/language/testdata/modules/multiple_backends/backend2.qbs +++ b/tests/auto/language/testdata/modules/multiple_backends/backend2.qbs @@ -1,5 +1,5 @@ Module { - condition: qbs.targetOS.contains("os2") + condition: qbs.targetOS.includes("os2") property string prop: "backend 2" property string backend2Prop } diff --git a/tests/auto/language/testdata/modules/multiple_backends/backend3.qbs b/tests/auto/language/testdata/modules/multiple_backends/backend3.qbs index 16228108b..762c12f20 100644 --- a/tests/auto/language/testdata/modules/multiple_backends/backend3.qbs +++ b/tests/auto/language/testdata/modules/multiple_backends/backend3.qbs @@ -1,5 +1,5 @@ Module { - condition: qbs.targetOS.contains("os2") && qbs.toolchain.contains("tc") + condition: qbs.targetOS.includes("os2") && qbs.toolchain.includes("tc") priority: 1 property string backend3Prop } diff --git a/tests/auto/language/testdata/multiplexed-exports.qbs b/tests/auto/language/testdata/multiplexed-exports.qbs index f98ceff95..3252145f1 100644 --- a/tests/auto/language/testdata/multiplexed-exports.qbs +++ b/tests/auto/language/testdata/multiplexed-exports.qbs @@ -6,7 +6,7 @@ Project { property string includeDir: qbs.buildVariant === "debug" ? "/d" : "/r" Export { Depends { name: "cpp" } - cpp.includePaths: product.includeDir + cpp.includePaths: exportingProduct.includeDir } } Product { diff --git a/tests/auto/language/testdata/probes-and-multiplexing.qbs b/tests/auto/language/testdata/probes-and-multiplexing.qbs new file mode 100644 index 000000000..38de08aee --- /dev/null +++ b/tests/auto/language/testdata/probes-and-multiplexing.qbs @@ -0,0 +1,15 @@ +Product { + multiplexByQbsProperties: "architectures" + qbs.architectures: ["x86", "x86_64", "arm"] + property string archFromProbe: theProbe.archOut + Probe { + id: theProbe + property string archIn: qbs.architecture + property string archOut + configure: { archOut = archIn; } + } + Group { + name: "theGroup" + qbs.sysroot: "/" + theProbe.archOut + } +} diff --git a/tests/auto/language/testdata/profilevaluesandoverriddenvalues.qbs b/tests/auto/language/testdata/profilevaluesandoverriddenvalues.qbs index 3aaa0cfa9..a0f189403 100644 --- a/tests/auto/language/testdata/profilevaluesandoverriddenvalues.qbs +++ b/tests/auto/language/testdata/profilevaluesandoverriddenvalues.qbs @@ -1,5 +1,5 @@ Project { - Application { + Product { name: "product1" property bool dummyProp: { if (!(dummy.cFlags instanceof Array)) diff --git a/tests/auto/language/testdata/qbs-properties-in-project-condition.qbs b/tests/auto/language/testdata/qbs-properties-in-project-condition.qbs index 31f648233..9d27df254 100644 --- a/tests/auto/language/testdata/qbs-properties-in-project-condition.qbs +++ b/tests/auto/language/testdata/qbs-properties-in-project-condition.qbs @@ -1,5 +1,5 @@ Project { - condition: qbs.targetOS.contains("whatever") + condition: qbs.targetOS.includes("whatever") Product { name: "never reached" diff --git a/tests/auto/language/testdata/rfc1034identifier.qbs b/tests/auto/language/testdata/rfc1034identifier.qbs index 4d320f899..e52dcc6b2 100644 --- a/tests/auto/language/testdata/rfc1034identifier.qbs +++ b/tests/auto/language/testdata/rfc1034identifier.qbs @@ -3,7 +3,7 @@ import qbs.Utilities CppApplication { name: Utilities.rfc1034Identifier("this!has@special#characters$uh-oh,Undersc0r3s_Are.Bad") Properties { - condition: qbs.targetOS.contains("darwin") + condition: qbs.targetOS.includes("darwin") bundle.infoPlist: { return {"CFBundleIdentifier": "$(PRODUCT_NAME:rfc1034identifier)"}; } } } diff --git a/tests/auto/language/testdata/subdir/exports-mylib.qbs b/tests/auto/language/testdata/subdir/exports-mylib.qbs index 92f39483a..68ea30384 100644 --- a/tests/auto/language/testdata/subdir/exports-mylib.qbs +++ b/tests/auto/language/testdata/subdir/exports-mylib.qbs @@ -8,8 +8,8 @@ StaticLibrary { Export { Depends { name: "dummy" } Depends { name: "mylib2" } - dummy.defines: [product.definePrefix + product.name.toUpperCase()] + dummy.defines: [exportingProduct.definePrefix + exportingProduct.name.toUpperCase()] dummy.includePaths: ["./lib"] - dummy.somePath: product.aPath + dummy.somePath: exportingProduct.aPath } } diff --git a/tests/auto/language/testdata/subdir2/exports-mylib2.qbs b/tests/auto/language/testdata/subdir2/exports-mylib2.qbs index ac8b9ebe4..b16b47821 100644 --- a/tests/auto/language/testdata/subdir2/exports-mylib2.qbs +++ b/tests/auto/language/testdata/subdir2/exports-mylib2.qbs @@ -5,7 +5,7 @@ StaticLibrary { property string definePrefix: "USE_" Export { Depends { name: "dummy" } - dummy.defines: [product.definePrefix + product.name.toUpperCase()] + dummy.defines: [exportingProduct.definePrefix + exportingProduct.name.toUpperCase()] dummy.includePaths: ["./lib"] } } diff --git a/tests/auto/language/testdata/suppressed-and-non-suppressed-errors.qbs b/tests/auto/language/testdata/suppressed-and-non-suppressed-errors.qbs index 4d5219157..684cc67b3 100644 --- a/tests/auto/language/testdata/suppressed-and-non-suppressed-errors.qbs +++ b/tests/auto/language/testdata/suppressed-and-non-suppressed-errors.qbs @@ -1,5 +1,5 @@ Project { - CppApplication { + Product { name: "mysterious creature" files: ["easter bunny"] } diff --git a/tests/auto/language/testdata/throw.qbs b/tests/auto/language/testdata/throw.qbs new file mode 100644 index 000000000..e9a97efb5 --- /dev/null +++ b/tests/auto/language/testdata/throw.qbs @@ -0,0 +1,16 @@ +Project { + property string throwType + property bool dummy: { + if (throwType === "bool") + throw true; + if (throwType === "int") + throw 43; + if (throwType === "string") + throw "an error"; + if (throwType === "list") + throw ["an", "error"]; + if (throwType === "object") + throw { result: "crash", reason: "overheating" }; + throw "type missing"; + } +} diff --git a/tests/auto/language/testdata/use-internal-profile.qbs b/tests/auto/language/testdata/use-internal-profile.qbs new file mode 100644 index 000000000..c2e20ff19 --- /dev/null +++ b/tests/auto/language/testdata/use-internal-profile.qbs @@ -0,0 +1,13 @@ +Project { + name: "theproject" + + Profile { + name: "theprofile" + dummy.defines: name + } + + Product { + name: "theproduct" + Depends { name: "dummy" } + } +}
\ No newline at end of file diff --git a/tests/auto/language/tst_language.cpp b/tests/auto/language/tst_language.cpp index 31aebfa3a..6a3344842 100644 --- a/tests/auto/language/tst_language.cpp +++ b/tests/auto/language/tst_language.cpp @@ -43,6 +43,7 @@ #include "../shared.h" +#include <app/shared/logging/consolelogger.h> #include <language/evaluator.h> #include <language/filecontext.h> #include <language/identifiersearch.h> @@ -52,6 +53,7 @@ #include <language/propertymapinternal.h> #include <language/scriptengine.h> #include <language/value.h> +#include <loader/projectresolver.h> #include <parser/qmljslexer_p.h> #include <parser/qmljsparser_p.h> #include <tools/scripttools.h> @@ -64,8 +66,7 @@ #include <tools/settings.h> #include <tools/stlutils.h> -#include "../shared/logging/consolelogger.h" - +#include <QtCore/qjsonobject.h> #include <QtCore/qprocess.h> #include <algorithm> @@ -79,28 +80,43 @@ using namespace qbs; using namespace qbs::Internal; static QString testDataDir() { - return FileInfo::resolvePath(QStringLiteral(SRCDIR), - QStringLiteral("../../../tests/auto/language/testdata")); + return testDataSourceDir(SRCDIR "/testdata"); } static QString testProject(const char *fileName) { return testDataDir() + QLatin1Char('/') + QLatin1String(fileName); } +class JSSourceValueCreator +{ + FileContextPtr m_fileContext; + std::vector<std::unique_ptr<QString>> m_strings; +public: + JSSourceValueCreator(const FileContextPtr &fileContext) + : m_fileContext(fileContext) + { + } + + JSSourceValuePtr create(const QString &sourceCode) + { + JSSourceValuePtr value = JSSourceValue::create(); + value->setFile(m_fileContext); + auto str = std::make_unique<QString>(sourceCode); + value->setSourceCode(*str.get()); + m_strings.push_back(std::move(str)); + return value; + } +}; + TestLanguage::TestLanguage(ILogSink *logSink, Settings *settings) : m_logSink(logSink) , m_settings(settings) , m_wildcardsTestDirPath(QDir::tempPath() + QLatin1String("/_wildcards_test_dir_")) { - qsrand(QTime::currentTime().msec()); + m_rand.seed(QTime::currentTime().msec()); qRegisterMetaType<QList<bool> >("QList<bool>"); - defaultParameters.setBuildRoot(m_tempDir.path() + "/buildroot"); - defaultParameters.setPropertyCheckingMode(ErrorHandlingMode::Strict); - defaultParameters.setSettingsDirectory(m_settings->baseDirectory()); } -TestLanguage::~TestLanguage() -{ -} +TestLanguage::~TestLanguage() = default; QHash<QString, ResolvedProductPtr> TestLanguage::productsFromProject(ResolvedProjectPtr project) { @@ -144,8 +160,7 @@ void TestLanguage::handleInitCleanupDataTags(const char *projectFileName, bool * *handled = true; bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject(projectFileName)); - project = loader->loadProject(defaultParameters); + resolveProject(projectFileName); QVERIFY(!!project); } catch (const ErrorInfo &e) { exceptionCaught = true; @@ -160,9 +175,31 @@ void TestLanguage::handleInitCleanupDataTags(const char *projectFileName, bool * } } +TopLevelProjectPtr TestLanguage::resolveProject(const char *relProjectFilePath) +{ + if (relProjectFilePath) + defaultParameters.setProjectFilePath(testProject(relProjectFilePath)); + defaultParameters.expandBuildConfiguration(); + ProjectResolver resolver(defaultParameters, m_engine.get(), m_logger); + return project = resolver.resolve(); +} + void TestLanguage::init() { + // clear caches, otherwise StoredVariantValues may end up being at the same address + // as the destroyed value + m_engine->reset(); m_logSink->setLogLevel(LoggerInfo); + defaultParameters = {}; + defaultParameters.setBuildRoot(m_tempDir.path() + "/buildroot"); + defaultParameters.setPropertyCheckingMode(ErrorHandlingMode::Strict); + defaultParameters.setSettingsDirectory(m_settings->baseDirectory()); + defaultParameters.setTopLevelProfile(profileName()); + defaultParameters.setMaxJobCount(1); + defaultParameters.setConfigurationName("default"); + defaultParameters.setEnvironment(QProcessEnvironment::systemEnvironment()); + defaultParameters.setSearchPaths({SRCDIR "/../../../share/qbs"}); + QVERIFY(m_tempDir.isValid()); } @@ -177,28 +214,16 @@ void TestLanguage::init() void TestLanguage::initTestCase() { m_logger = Logger(m_logSink); - m_engine = ScriptEngine::create(m_logger, EvalContext::PropertyEvaluation, this); - loader = new Loader(m_engine, m_logger); - loader->setSearchPaths(QStringList() - << QStringLiteral(SRCDIR "/../../../share/qbs")); - defaultParameters.setTopLevelProfile(profileName()); - defaultParameters.setConfigurationName("default"); - defaultParameters.expandBuildConfiguration(); - defaultParameters.setEnvironment(QProcessEnvironment::systemEnvironment()); - QVERIFY(QFileInfo(m_wildcardsTestDirPath).isAbsolute()); -} + m_engine = ScriptEngine::create(m_logger, EvalContext::PropertyEvaluation); -void TestLanguage::cleanupTestCase() -{ - delete loader; + QVERIFY(QFileInfo(m_wildcardsTestDirPath).isAbsolute()); } void TestLanguage::additionalProductTypes() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("additional-product-types.qbs")); - project = loader->loadProject(defaultParameters); + resolveProject("additional-product-types.qbs"); QVERIFY(!!project); const QHash<QString, ResolvedProductPtr> products = productsFromProject(project); const ResolvedProductConstPtr product = products.value("p"); @@ -219,8 +244,7 @@ void TestLanguage::baseProperty() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("baseproperty.qbs")); - project = loader->loadProject(defaultParameters); + resolveProject("baseproperty.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); ResolvedProductPtr product = products.value("product1"); @@ -237,10 +261,8 @@ void TestLanguage::baseProperty() void TestLanguage::baseValidation() { - qbs::SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("base-validate/base-validate.qbs")); try { - project = loader->loadProject(params); + resolveProject("base-validate/base-validate.qbs"); QVERIFY2(false, "exception expected"); } catch (const qbs::ErrorInfo &e) { QVERIFY2(e.toString().contains("Parent succeeded, child failed."), @@ -250,11 +272,9 @@ void TestLanguage::baseValidation() void TestLanguage::brokenDependencyCycle() { - qbs::SetupProjectParameters params = defaultParameters; QFETCH(QString, projectFileName); - params.setProjectFilePath(testProject(qPrintable(projectFileName))); try { - project = loader->loadProject(params); + resolveProject(qPrintable(projectFileName)); } catch (const qbs::ErrorInfo &e) { QVERIFY2(false, qPrintable(e.toString())); } @@ -271,12 +291,10 @@ void TestLanguage::buildConfigStringListSyntax() { bool exceptionCaught = false; try { - SetupProjectParameters parameters = defaultParameters; QVariantMap overriddenValues; overriddenValues.insert("project.someStrings", "foo,bar,baz"); - parameters.setOverriddenValues(overriddenValues); - parameters.setProjectFilePath(testProject("buildconfigstringlistsyntax.qbs")); - project = loader->loadProject(parameters); + defaultParameters.setOverriddenValues(overriddenValues); + resolveProject("buildconfigstringlistsyntax.qbs"); QVERIFY(!!project); QCOMPARE(project->projectProperties().value("someStrings").toStringList(), QStringList() << "foo" << "bar" << "baz"); @@ -291,9 +309,7 @@ void TestLanguage::builtinFunctionInSearchPathsProperty() { bool exceptionCaught = false; try { - SetupProjectParameters parameters = defaultParameters; - parameters.setProjectFilePath(testProject("builtinFunctionInSearchPathsProperty.qbs")); - QVERIFY(!!loader->loadProject(parameters)); + QVERIFY(resolveProject("builtinFunctionInSearchPathsProperty.qbs")); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); @@ -305,11 +321,12 @@ void TestLanguage::chainedProbes() { bool exceptionCaught = false; try { - SetupProjectParameters parameters = defaultParameters; - parameters.setProjectFilePath(testProject("chained-probes/chained-probes.qbs")); - const TopLevelProjectConstPtr project = loader->loadProject(parameters); + resolveProject("chained-probes/chained-probes.qbs"); QVERIFY(!!project); QCOMPARE(project->products.size(), size_t(1)); + const QString prop1Val = project->products.front()->moduleProperties + ->moduleProperty("m", "prop1").toString(); + QCOMPARE(prop1Val, QLatin1String("probe1Val")); const QString prop2Val = project->products.front()->moduleProperties ->moduleProperty("m", "prop2").toString(); QCOMPARE(prop2Val, QLatin1String("probe1Valprobe2Val")); @@ -325,9 +342,7 @@ void TestLanguage::versionCompare() { bool exceptionCaught = false; try { - SetupProjectParameters parameters = defaultParameters; - parameters.setProjectFilePath(testProject("versionCompare.qbs")); - QVERIFY(!!loader->loadProject(parameters)); + QVERIFY(resolveProject("versionCompare.qbs")); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); @@ -339,8 +354,7 @@ void TestLanguage::canonicalArchitecture() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("canonicalArchitecture.qbs")); - project = loader->loadProject(defaultParameters); + resolveProject("canonicalArchitecture.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); ResolvedProductPtr product = products.value(QStringLiteral("x86")); @@ -356,8 +370,7 @@ void TestLanguage::rfc1034Identifier() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("rfc1034identifier.qbs")); - project = loader->loadProject(defaultParameters); + resolveProject("rfc1034identifier.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); ResolvedProductPtr product = products.value(QStringLiteral("this-has-special-characters-" @@ -370,17 +383,47 @@ void TestLanguage::rfc1034Identifier() QCOMPARE(exceptionCaught, false); } +void TestLanguage::throwThings_data() +{ + QTest::addColumn<QString>("type"); + QTest::addColumn<QString>("result"); + QTest::addRow("bool") << "bool" << "true"; + QTest::addRow("int") << "int" << "43"; + QTest::addRow("string") << "string" << "an error"; + QTest::addRow("list") << "list" << R"([ + "an", + "error" +])"; + QTest::addRow("object") << "object" << R"({ + "reason": "overheating", + "result": "crash" +})"; +} + +void TestLanguage::throwThings() +{ + QFETCH(QString, type); + QFETCH(QString, result); + bool exceptionCaught = false; + try { + defaultParameters.setOverriddenValues({{"project.throwType", type}}); + resolveProject("throw.qbs"); + } catch (const ErrorInfo &e) { + exceptionCaught = true; + QVERIFY2(e.toString().contains(result), qPrintable(e.toString())); + } + QVERIFY(exceptionCaught); +} + void TestLanguage::conditionalDepends() { bool exceptionCaught = false; ResolvedProductPtr product; ResolvedModuleConstPtr dependency; try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("conditionaldepends.qbs")); - params.setOverriddenValues({std::make_pair(QString("products." + defaultParameters.setOverriddenValues({std::make_pair(QString("products." "multilevel_module_props_overridden.dummy3.loadDummy"), true)}); - project = loader->loadProject(params); + resolveProject("conditionaldepends.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); @@ -479,17 +522,38 @@ void TestLanguage::conditionalDepends() QCOMPARE(exceptionCaught, false); } +void TestLanguage::convertStringList() +{ + FileContextPtr fileContext = FileContext::create(); + fileContext->setFilePath("/dev/null"); + JSSourceValueCreator sourceValueCreator(fileContext); + ItemPool pool; + Item *scope = Item::create(&pool, ItemType::Scope); + scope->setProperty("x", sourceValueCreator.create("[\"a\", \"b\"]")); + + Evaluator evaluator(m_engine.get()); + auto variantValue = evaluator.variantValue(scope, "x"); + // despite we have a stringList prop, we evaluate it as a QVariantList + QCOMPARE(variantValue.userType(), QMetaType::Type::QVariantList); + // and we have to convert it explicitly +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + variantValue.convert(QMetaType(QMetaType::QStringList)); +#else + variantValue.convert(QMetaType::QStringList); +#endif + QCOMPARE(variantValue.userType(), QMetaType::Type::QStringList); + QCOMPARE(variantValue, QStringList({"a", "b"})); +} + void TestLanguage::delayedError() { QFETCH(bool, productEnabled); try { QFETCH(QString, projectFileName); - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject(projectFileName.toLatin1())); QVariantMap overriddenValues; overriddenValues.insert("project.enableProduct", productEnabled); - params.setOverriddenValues(overriddenValues); - project = loader->loadProject(params); + defaultParameters.setOverriddenValues(overriddenValues); + resolveProject(projectFileName.toLatin1()); QCOMPARE(productEnabled, false); QVERIFY(!!project); QCOMPARE(project->products.size(), size_t(1)); @@ -521,8 +585,6 @@ void TestLanguage::dependencyOnAllProfiles() { bool exceptionCaught = false; try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("dependencyOnAllProfiles.qbs")); TemporaryProfile p1("p1", m_settings); p1.p.setValue("qbs.architecture", "arch1"); TemporaryProfile p2("p2", m_settings); @@ -530,14 +592,14 @@ void TestLanguage::dependencyOnAllProfiles() QVariantMap overriddenValues; overriddenValues.insert("project.profile1", "p1"); overriddenValues.insert("project.profile2", "p2"); - params.setOverriddenValues(overriddenValues); - project = loader->loadProject(params); + defaultParameters.setOverriddenValues(overriddenValues); + resolveProject("dependencyOnAllProfiles.qbs"); QVERIFY(!!project); QCOMPARE(project->products.size(), size_t(3)); const ResolvedProductConstPtr mainProduct = productsFromProject(project).value("main"); QVERIFY(!!mainProduct); QCOMPARE(mainProduct->dependencies.size(), size_t { 2 }); - for (const ResolvedProductConstPtr &p : mainProduct->dependencies) { + for (const ResolvedProductPtr &p : mainProduct->dependencies) { QCOMPARE(p->name, QLatin1String("dep")); QVERIFY(p->profile() == "p1" || p->profile() == "p2"); } @@ -552,9 +614,7 @@ void TestLanguage::derivedSubProject() { bool exceptionCaught = false; try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("derived-sub-project/project.qbs")); - const TopLevelProjectPtr project = loader->loadProject(params); + resolveProject("derived-sub-project/project.qbs"); QVERIFY(!!project); const QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 1); @@ -569,9 +629,7 @@ void TestLanguage::disabledSubProject() { bool exceptionCaught = false; try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("disabled-subproject.qbs")); - const TopLevelProjectPtr project = loader->loadProject(params); + resolveProject("disabled-subproject.qbs"); QVERIFY(!!project); const QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 0); @@ -600,16 +658,14 @@ void TestLanguage::dottedNames() { QFETCH(bool, expectSuccess); try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("dotted-names/dotted-names.qbs")); QFETCH(bool, useProduct); QFETCH(bool, useModule); const QVariantMap overridden{ std::make_pair("projects.theProject.includeDottedProduct", useProduct), std::make_pair("projects.theProject.includeDottedModule", useModule) }; - params.setOverriddenValues(overridden); - TopLevelProjectPtr project = loader->loadProject(params); + defaultParameters.setOverriddenValues(overridden); + resolveProject("dotted-names/dotted-names.qbs"); QVERIFY(expectSuccess); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); @@ -626,13 +682,44 @@ void TestLanguage::dottedNames() } } +void TestLanguage::duplicateMultiplexValues_data() +{ + QTest::addColumn<bool>("dummy"); + QTest::newRow("duplicate-multiplex-value") << true; + QTest::newRow("duplicate-multiplex-value2") << true; +} + +void TestLanguage::duplicateMultiplexValues() +{ + bool exceptionCaught = false; + try { + resolveProject(qPrintable(QString::fromLocal8Bit(QTest::currentDataTag()) + + QLatin1String(".qbs"))); + QVERIFY(project); + const std::vector<ResolvedProductPtr> products = project->allProducts(); + QCOMPARE(products.size(), 2); + bool x86 = false; + bool arm = false; + for (const ResolvedProductPtr &p : products) { + if (p->moduleProperties->moduleProperty("qbs", "architecture").toString() == "x86") + x86 = true; + else if (p->moduleProperties->moduleProperty("qbs", "architecture").toString() == "arm") + arm = true; + } + QVERIFY(x86); + QVERIFY(arm); + } catch (const ErrorInfo &e) { + exceptionCaught = true; + qDebug() << e.toString(); + } + QVERIFY(!exceptionCaught); +} + void TestLanguage::emptyJsFile() { bool exceptionCaught = false; try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("empty-js-file.qbs")); - const TopLevelProjectPtr project = loader->loadProject(params); + resolveProject("empty-js-file.qbs"); QVERIFY(!!project); const QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 1); @@ -647,14 +734,12 @@ void TestLanguage::enumerateProjectProperties() { bool exceptionCaught = false; try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("enum-project-props.qbs")); - auto project = loader->loadProject(params); + resolveProject("enum-project-props.qbs"); QVERIFY(!!project); auto products = productsFromProject(project); QCOMPARE(products.size(), 1); auto product = products.values().front(); - auto files = product->groups.front()->allFiles(); + auto files = product->groups.front()->files; QCOMPARE(product->groups.size(), size_t(1)); QCOMPARE(files.size(), size_t(1)); auto fileName = FileInfo::fileName(files.front()->absoluteFilePath); @@ -672,7 +757,7 @@ void TestLanguage::evalErrorInNonPresentModule_data() QTest::addColumn<QString>("errorMessage"); QTest::newRow("module required") - << true << "broken.qbs:4:5 Element at index 0 of list property 'broken' " + << true << "broken.qbs:2:5 Element at index 0 of list property 'broken' " "does not have string type"; QTest::newRow("module not required") << false << QString(); } @@ -682,19 +767,16 @@ void TestLanguage::evalErrorInNonPresentModule() QFETCH(bool, moduleRequired); QFETCH(QString, errorMessage); try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("eval-error-in-non-present-module.qbs")); QVariantMap overridden{std::make_pair("products.p.moduleRequired", moduleRequired)}; - params.setOverriddenValues(overridden); - TopLevelProjectPtr project = loader->loadProject(params); + defaultParameters.setOverriddenValues(overridden); + resolveProject("eval-error-in-non-present-module.qbs"); QVERIFY(errorMessage.isEmpty()); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 1); const ResolvedProductPtr product = products.value("p"); QVERIFY(!!product); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { QVERIFY(!errorMessage.isEmpty()); QVERIFY2(e.toString().contains(errorMessage), qPrintable(e.toString())); } @@ -704,14 +786,12 @@ void TestLanguage::defaultValue() { bool exceptionCaught = false; try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("defaultvalue/egon.qbs")); QFETCH(QString, prop1Value); QVariantMap overridden; if (!prop1Value.isEmpty()) overridden.insert("modules.lower.prop1", prop1Value); - params.setOverriddenValues(overridden); - TopLevelProjectPtr project = loader->loadProject(params); + defaultParameters.setOverriddenValues(overridden); + resolveProject("defaultvalue/egon.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 2); @@ -725,8 +805,7 @@ void TestLanguage::defaultValue() propertyValue = product->moduleProperties->property(propertyName); QFETCH(QVariant, expectedListPropValue); QCOMPARE(propertyValue.toStringList(), expectedListPropValue.toStringList()); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } @@ -754,17 +833,14 @@ void TestLanguage::environmentVariable() try { // Create new environment: const QString varName = QStringLiteral("PRODUCT_NAME"); - const QString productName = QLatin1String("MyApp") + QString::number(qrand()); + const QString productName = QLatin1String("MyApp") + QString::number(m_rand.generate()); QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert(varName, productName); QProcessEnvironment origEnv = defaultParameters.environment(); // store orig environment defaultParameters.setEnvironment(env); - defaultParameters.setProjectFilePath(testProject("environmentvariable.qbs")); - project = loader->loadProject(defaultParameters); - - defaultParameters.setEnvironment(origEnv); // reset environment + resolveProject("environmentvariable.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); @@ -781,9 +857,7 @@ void TestLanguage::errorInDisabledProduct() { bool exceptionCaught = false; try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("error-in-disabled-product.qbs")); - auto project = loader->loadProject(params); + resolveProject("error-in-disabled-product.qbs"); QVERIFY(!!project); auto products = productsFromProject(project); QCOMPARE(products.size(), 5); @@ -807,11 +881,11 @@ void TestLanguage::erroneousFiles_data() QTest::newRow("importloop1") << "Loop detected when importing"; QTest::newRow("nonexistentouter") - << "Can't find variable: outer"; + << "'outer' is not defined"; QTest::newRow("invalid_file") << "does not exist"; QTest::newRow("invalid-parameter-rhs") - << "ReferenceError: Can't find variable: access"; + << "'access' is not defined"; QTest::newRow("invalid-parameter-type") << "Value assigned to property 'stringParameter' does not have type 'string'."; QTest::newRow("invalid_property_type") @@ -828,6 +902,8 @@ void TestLanguage::erroneousFiles_data() << "Cyclic dependencies detected."; QTest::newRow("dependency_cycle3") << "Cyclic dependencies detected."; + QTest::newRow("dependency_cycle3a") + << "Cyclic dependencies detected."; QTest::newRow("dependency_cycle4") << "Cyclic dependencies detected."; QTest::newRow("references_cycle") @@ -876,30 +952,24 @@ void TestLanguage::erroneousFiles_data() QTest::newRow("wrongQbsVersionFormat") << "The value '.*' of Project.minimumQbsVersion is not a valid version string."; QTest::newRow("properties-item-with-invalid-condition") - << "properties-item-with-invalid-condition.qbs:4:19.*TypeError: Result of expression " - "'cpp.nonexistingproperty'"; + << "properties-item-with-invalid-condition.qbs:4:19.*" + "cannot read property 'includes' of undefined"; QTest::newRow("misused-inherited-property") << "Binding to non-item property"; QTest::newRow("undeclared_property_in_Properties_item") << "Item 'blubb' is not declared"; - QTest::newRow("same-module-prefix1") << "The name of module 'prefix1' is equal to the first " - "component of the name of module 'prefix1.suffix'"; - QTest::newRow("same-module-prefix2") << "The name of module 'prefix2' is equal to the first " - "component of the name of module 'prefix2.suffix'"; QTest::newRow("conflicting-properties-in-export-items") << "Export item in inherited item redeclares property 'theProp' with different type."; QTest::newRow("invalid-property-option") << "PropertyOptions item refers to non-existing property 's0meProp'"; QTest::newRow("missing-colon") - << "Invalid item 'cpp.dynamicLibraries'. Did you mean to set a module property?"; + << "Invalid item 'dummy.cxxFlags'. Did you mean to set a module property?"; QTest::newRow("syntax-error-in-probe") - << "syntax-error-in-probe.qbs:4:20.*ReferenceError"; + << "syntax-error-in-probe.qbs:4:20.*'fngkgsdjfgklkf' is not defined"; QTest::newRow("wrong-toplevel-item") << "wrong-toplevel-item.qbs:1:1.*The top-level item must be of type 'Project' or " "'Product', but it is of type 'Artifact'."; QTest::newRow("conflicting-module-instances") << "There is more than one equally prioritized candidate for module " "'conflicting-instances'."; - QTest::newRow("module-depends-on-product") - << "module-with-product-dependency.qbs:2:5.*Modules cannot depend on products."; QTest::newRow("overwrite-inherited-readonly-property") << "overwrite-inherited-readonly-property.qbs" ":2:21.*Cannot set read-only property 'readOnlyString'."; @@ -916,25 +986,38 @@ void TestLanguage::erroneousFiles_data() << "module-with-invalid-original.qbs:2:24.*The special value 'original' cannot be used " "on the right-hand side of a property declaration."; QTest::newRow("original-in-export-item") - << "original-in-export-item.qbs:7:32.*The special value 'original' cannot be used " + << "original-in-export-item.qbs:5:32.*The special value 'original' cannot be used " "on the right-hand side of a property declaration."; QTest::newRow("original-in-export-item2") - << "original-in-export-item2.qbs:6:9.*Item 'x.y' is not declared. Did you forget " + << "original-in-export-item2.qbs:4:9.*Item 'x.y' is not declared. Did you forget " "to add a Depends item"; QTest::newRow("original-in-export-item3") << "original-in-export-item3.qbs:6:9.*Item 'x.y' is not declared. Did you forget " "to add a Depends item"; QTest::newRow("mismatching-multiplex-dependency") - << "mismatching-multiplex-dependency.qbs:7:5.*Dependency from product " - "'b \\{\"architecture\":\"mips\"\\}' to product 'a \\{\"architecture\":\"mips\"\\}'" - " not fulfilled."; - QTest::newRow("duplicate-multiplex-value") - << "duplicate-multiplex-value.qbs:3:1.*Duplicate entry 'x86' in qbs.architectures."; - QTest::newRow("duplicate-multiplex-value2") - << "duplicate-multiplex-value2.qbs:3:1.*Duplicate entry 'architecture' in " - "Product.multiplexByQbsProperties."; + << "mismatching-multiplex-dependency.qbs:9:9.*Dependency from product " + "'b \\{\"architecture\":\"mips\"\\}' to product 'a'" + " not fulfilled. There are no eligible multiplex candidates."; + QTest::newRow("ambiguous-multiplex-dependency") + << "ambiguous-multiplex-dependency.qbs:10:9.*Dependency from product 'b " + "\\{\"architecture\":\"x86\"\\}' to product 'a' is ambiguous. Eligible multiplex " + "candidates: a \\{\"architecture\":\"x86\",\"buildVariant\":\"debug\"\\}, " + "a \\{\"architecture\":\"x86\",\"buildVariant\":\"release\"\\}."; + QTest::newRow("dependency-profile-mismatch") + << "dependency-profile-mismatch.qbs:10:5.*Product 'main' depends on 'dep', " + "which does not exist for the requested profile 'profile47'."; + QTest::newRow("dependency-profile-mismatch-2") + << "dependency-profile-mismatch-2.qbs:15:9 Dependency from product 'main' to " + "product 'dep' not fulfilled. There are no eligible multiplex candidates."; QTest::newRow("invalid-references") << "invalid-references.qbs:2:17.*Cannot open '.*nosuchproject.qbs'"; + QTest::newRow("missing-js-file") + << "missing-js-file-module.qbs.*Cannot open '.*javascriptfile.js'"; + QTest::newRow("frozen-object") << "'key' is read-only"; + QTest::newRow("frozen-object-list") << "object is not extensible"; + QTest::newRow("module-property-binding-in-project") + << "Module properties cannot be set in Project items"; + QTest::newRow("module-with-id") << "Module items cannot have an id property"; } void TestLanguage::erroneousFiles() @@ -942,10 +1025,10 @@ void TestLanguage::erroneousFiles() QFETCH(QString, errorMessage); QString fileName = QString::fromLocal8Bit(QTest::currentDataTag()) + QLatin1String(".qbs"); try { - defaultParameters.setProjectFilePath(testProject("/erroneous/") + fileName); - loader->loadProject(defaultParameters); + resolveProject(qPrintable("/erroneous/" + fileName)); } catch (const ErrorInfo &e) { - if (!e.toString().contains(QRegExp(errorMessage))) { + const QRegularExpression reg(errorMessage, QRegularExpression::DotMatchesEverythingOption); + if (!e.toString().contains(reg)) { qDebug() << "Message: " << e.toString(); qDebug() << "Expected: " << errorMessage; QFAIL("Unexpected error message."); @@ -961,8 +1044,7 @@ void TestLanguage::exports() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("exports.qbs")); - TopLevelProjectPtr project = loader->loadProject(defaultParameters); + resolveProject("exports.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 22); @@ -1007,6 +1089,7 @@ void TestLanguage::exports() product = products.value("B"); QVERIFY(!!product); QVERIFY(product->dependencies.empty()); + QCOMPARE(product->exportedModule.productDependencies, std::vector<QString>{"C"}); product = products.value("C"); QVERIFY(!!product); QVERIFY(product->dependencies.empty()); @@ -1051,7 +1134,7 @@ void TestLanguage::exports() propertyName = QStringList() << "dummy" << "defines"; propertyValue = product->moduleProperties->property(propertyName); QCOMPARE(propertyValue.toStringList(), - QStringList() << "LIBA" << "LIBB" << "LIBC" << "LIBD"); + QStringList() << "LIBD" << "LIBC" << "LIBA" << "LIBB"); propertyName = QStringList() << "dummy" << "productName"; propertyValue = product->moduleProperties->property(propertyName); QCOMPARE(propertyValue.toString(), QString("libE")); @@ -1059,7 +1142,7 @@ void TestLanguage::exports() product = products.value("depender"); QVERIFY(!!product); QCOMPARE(product->modules.size(), size_t(2)); - for (const ResolvedModuleConstPtr &m : product->modules) { + for (const ResolvedModulePtr &m : product->modules) { QVERIFY2(m->name == QString("qbs") || m->name == QString("dependency"), qPrintable(m->name)); } @@ -1070,13 +1153,12 @@ void TestLanguage::exports() product = products.value("broken_cycle3"); QVERIFY(!!product); QCOMPARE(product->modules.size(), size_t(3)); - for (const ResolvedModuleConstPtr &m : product->modules) { + for (const ResolvedModulePtr &m : product->modules) { QVERIFY2(m->name == QString("qbs") || m->name == QString("broken_cycle1") || m->name == QString("broken_cycle2"), qPrintable(m->name)); } - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } @@ -1087,8 +1169,7 @@ void TestLanguage::fileContextProperties() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("filecontextproperties.qbs")); - project = loader->loadProject(defaultParameters); + resolveProject("filecontextproperties.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); ResolvedProductPtr product = products.value("product1"); @@ -1134,14 +1215,12 @@ void TestLanguage::fileInProductAndModule() QFETCH(bool, addFileToProduct); QFETCH(bool, successExpected); try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("file-in-product-and-module.qbs")); - params.setOverriddenValues(QVariantMap{ + defaultParameters.setOverriddenValues(QVariantMap{ std::make_pair("modules.module_with_file.file1IsTarget", file1IsTarget), std::make_pair("modules.module_with_file.file2IsTarget", file2IsTarget), std::make_pair("products.p.addFileToProduct", addFileToProduct), }); - project = loader->loadProject(params); + resolveProject("file-in-product-and-module.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 1); @@ -1156,16 +1235,19 @@ void TestLanguage::getNativeSetting() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("getNativeSetting.qbs")); - project = loader->loadProject(defaultParameters); + resolveProject("getNativeSetting.qbs"); QString expectedTargetName; - if (HostOsInfo::isMacosHost()) - expectedTargetName = QStringLiteral("Mac OS X"); - else if (HostOsInfo::isWindowsHost()) + if (HostOsInfo::isMacosHost()) { + if (HostOsInfo::hostOsVersion() >= qbs::Version(11)) + expectedTargetName = QStringLiteral("macOS"); + else + expectedTargetName = QStringLiteral("Mac OS X"); + } else if (HostOsInfo::isWindowsHost()) { expectedTargetName = QStringLiteral("Windows"); - else + } else { expectedTargetName = QStringLiteral("Unix"); + } QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products; @@ -1228,8 +1310,7 @@ void TestLanguage::groupName() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("groupname.qbs")); - TopLevelProjectPtr project = loader->loadProject(defaultParameters); + resolveProject("groupname.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 2); @@ -1256,8 +1337,7 @@ void TestLanguage::groupName() group = product->groups.at(2); QVERIFY(!!group); QCOMPARE(group->name, QString("Group 2")); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } @@ -1267,8 +1347,7 @@ void TestLanguage::groupName() void TestLanguage::homeDirectory() { try { - defaultParameters.setProjectFilePath(testProject("homeDirectory.qbs")); - ResolvedProjectPtr project = loader->loadProject(defaultParameters); + resolveProject("homeDirectory.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 1); @@ -1293,8 +1372,7 @@ void TestLanguage::homeDirectory() FileInfo::resolvePath(product->sourceDirectory, QStringLiteral("a/~/bb"))); QCOMPARE(product->productProperties.value("user").toString(), FileInfo::resolvePath(product->sourceDirectory, QStringLiteral("~foo/bar"))); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { qDebug() << e.toString(); } } @@ -1373,8 +1451,7 @@ void TestLanguage::idUsage() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("idusage.qbs")); - TopLevelProjectPtr project = loader->loadProject(defaultParameters); + resolveProject("idusage.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 5); @@ -1398,8 +1475,7 @@ void TestLanguage::idUsage() QVERIFY(!!product5); QCOMPARE(product5->moduleProperties->moduleProperty("deepdummy.deep.moat", "zort") .toString(), QString("zort in dummy")); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } @@ -1410,10 +1486,8 @@ void TestLanguage::idUniqueness() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("id-uniqueness.qbs")); - loader->loadProject(defaultParameters); - } - catch (const ErrorInfo &e) { + resolveProject("id-uniqueness.qbs"); + } catch (const ErrorInfo &e) { exceptionCaught = true; const QList<ErrorItem> items = e.items(); QCOMPARE(items.size(), 3); @@ -1428,15 +1502,13 @@ void TestLanguage::importCollection() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("import-collection/project.qbs")); - const TopLevelProjectPtr project = loader->loadProject(defaultParameters); + resolveProject("import-collection/project.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); const ResolvedProductConstPtr product = products.value("da product"); QCOMPARE(product->productProperties.value("targetName").toString(), QLatin1String("C1f1C1f2C2f1C2f2")); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } @@ -1455,19 +1527,15 @@ void TestLanguage::inheritedPropertiesItems() { bool exceptionCaught = false; try { - SetupProjectParameters params = defaultParameters; QFETCH(QString, buildVariant); QFETCH(QString, productName); - params.setProjectFilePath - (testProject("inherited-properties-items/inherited-properties-items.qbs")); - params.setOverriddenValues(QVariantMap{std::make_pair("qbs.buildVariant", buildVariant)}); - TopLevelProjectPtr project = loader->loadProject(params); + defaultParameters.setOverriddenValues(QVariantMap{std::make_pair("qbs.buildVariant", buildVariant)}); + resolveProject("inherited-properties-items/inherited-properties-items.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 1); QVERIFY(!!products.value(productName)); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } @@ -1478,13 +1546,11 @@ void TestLanguage::invalidBindingInDisabledItem() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("invalidBindingInDisabledItem.qbs")); - TopLevelProjectPtr project = loader->loadProject(defaultParameters); + resolveProject("invalidBindingInDisabledItem.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 2); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } @@ -1498,13 +1564,10 @@ void TestLanguage::invalidOverrides() const bool successExpected = expectedErrorMessage.isEmpty(); bool exceptionCaught = false; try { - qbs::SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("invalid-overrides.qbs")); - params.setOverriddenValues(QVariantMap{std::make_pair(key, true)}); - const TopLevelProjectPtr project = loader->loadProject(params); + defaultParameters.setOverriddenValues(QVariantMap{std::make_pair(key, true)}); + resolveProject("invalid-overrides.qbs"); QVERIFY(!!project); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; if (successExpected) qDebug() << e.toString(); @@ -1548,31 +1611,32 @@ void TestLanguage::invalidOverrides_data() << "products.MyOtherProduct.cpp.useRPaths" << QString(); } -class JSSourceValueCreator +void TestLanguage::invalidPropOnNonRequiredModule_data() { - FileContextPtr m_fileContext; - QList<QString *> m_strings; -public: - JSSourceValueCreator(const FileContextPtr &fileContext) - : m_fileContext(fileContext) - { - } + QTest::addColumn<bool>("useExistingModule"); + QTest::addColumn<bool>("errorExpected"); - ~JSSourceValueCreator() - { - qDeleteAll(m_strings); - } + QTest::newRow("existing module") << true << true; + QTest::newRow("non-existing module") << false << false; +} - JSSourceValuePtr create(const QString &sourceCode) - { - JSSourceValuePtr value = JSSourceValue::create(); - value->setFile(m_fileContext); - const auto str = new QString(sourceCode); - m_strings.push_back(str); - value->setSourceCode(QStringRef(str)); - return value; +void TestLanguage::invalidPropOnNonRequiredModule() +{ + QFETCH(bool, useExistingModule); + QFETCH(bool, errorExpected); + + try { + defaultParameters.setOverriddenValues( + {std::make_pair("project.useExistingModule", useExistingModule)}); + resolveProject("invalid-prop-on-non-required-module"); + QVERIFY(!errorExpected); + } catch (const ErrorInfo &e) { + const QString errorString = e.toString(); + QVERIFY2(errorExpected, qPrintable(errorString)); + QVERIFY2(errorString.contains("Property 'nosuchprop' is not declared"), + qPrintable(errorString)); } -}; +} void TestLanguage::itemPrototype() { @@ -1588,13 +1652,14 @@ void TestLanguage::itemPrototype() item->setProperty("y", sourceValueCreator.create("x + 1")); item->setProperty("z", sourceValueCreator.create("2")); - Evaluator evaluator(m_engine); - QCOMPARE(evaluator.property(proto, "x").toVariant().toInt(), 1); - QCOMPARE(evaluator.property(proto, "y").toVariant().toInt(), 1); - QVERIFY(!evaluator.property(proto, "z").isValid()); - QCOMPARE(evaluator.property(item, "x").toVariant().toInt(), 1); - QCOMPARE(evaluator.property(item, "y").toVariant().toInt(), 2); - QCOMPARE(evaluator.property(item, "z").toVariant().toInt(), 2); + Evaluator evaluator(m_engine.get()); + JSContext * const ctx = m_engine->context(); + QCOMPARE(getJsVariant(ctx, evaluator.property(proto, "x")).toInt(), 1); + QCOMPARE(getJsVariant(ctx, evaluator.property(proto, "y")).toInt(), 1); + QVERIFY(JS_IsUndefined(evaluator.property(proto, "z"))); + QCOMPARE(getJsVariant(ctx, evaluator.property(item, "x")).toInt(), 1); + QCOMPARE(getJsVariant(ctx, evaluator.property(item, "y")).toInt(), 2); + QCOMPARE(getJsVariant(ctx, evaluator.property(item, "z")).toInt(), 2); } void TestLanguage::itemScope() @@ -1612,11 +1677,12 @@ void TestLanguage::itemScope() item->setScope(scope2); item->setProperty("z", sourceValueCreator.create("x + y")); - Evaluator evaluator(m_engine); - QCOMPARE(evaluator.property(scope1, "x").toVariant().toInt(), 1); - QCOMPARE(evaluator.property(scope2, "y").toVariant().toInt(), 2); - QVERIFY(!evaluator.property(scope2, "x").isValid()); - QCOMPARE(evaluator.property(item, "z").toVariant().toInt(), 3); + Evaluator evaluator(m_engine.get()); + JSContext * const ctx = m_engine->context(); + QCOMPARE(getJsVariant(ctx, evaluator.property(scope1, "x")).toInt(), 1); + QCOMPARE(getJsVariant(ctx, evaluator.property(scope2, "y")).toInt(), 2); + QVERIFY(JS_IsUndefined(evaluator.property(scope2, "x"))); + QCOMPARE(getJsVariant(ctx, evaluator.property(item, "z")).toInt(), 3); } void TestLanguage::jsExtensions() @@ -1626,10 +1692,10 @@ void TestLanguage::jsExtensions() QTextStream ts(&file); QString code = ts.readAll(); QVERIFY(!code.isEmpty()); - QScriptValue evaluated = m_engine->evaluate(code, file.fileName(), 1); - if (m_engine->hasErrorOrException(evaluated)) { - qDebug() << m_engine->uncaughtExceptionBacktrace(); - QFAIL(qPrintable(m_engine->lastErrorString(evaluated))); + m_engine->evaluate(JsValueOwner::Caller, code, file.fileName(), 1); + if (JsException ex = m_engine->checkAndClearException({})) { + qDebug() << ex.stackTrace(); + QFAIL(qPrintable(ex.message())); } } @@ -1648,35 +1714,45 @@ void TestLanguage::jsImportUsedInMultipleScopes() bool exceptionCaught = false; try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("jsimportsinmultiplescopes.qbs")); - params.setOverriddenValues({std::make_pair(QStringLiteral("qbs.buildVariant"), - buildVariant)}); - params.expandBuildConfiguration(); - TopLevelProjectPtr project = loader->loadProject(params); + defaultParameters.setOverriddenValues({std::make_pair(QStringLiteral("qbs.buildVariant"), + buildVariant)}); + resolveProject("jsimportsinmultiplescopes.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 1); ResolvedProductPtr product = products.values().front(); QVERIFY(!!product); QCOMPARE(product->name, expectedProductName); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QVERIFY(!exceptionCaught); } +void TestLanguage::localProfileAsTopLevelProfile() +{ + bool exceptionCaught = false; + try { + defaultParameters.setTopLevelProfile("test-profile"); + resolveProject("local-profile-as-top-level-profile.qbs"); + QVERIFY(!!project); + QCOMPARE(int(project->products.size()), 1); + const PropertyMapConstPtr &props = project->products.front()->moduleProperties; + QCOMPARE(props->qbsPropertyValue("architecture"), "arm"); + QCOMPARE(props->qbsPropertyValue("targetPlatform"), "macos"); + } catch (const ErrorInfo &e) { + exceptionCaught = true; + qDebug() << e.toString(); + } + QCOMPARE(exceptionCaught, false); +} + void TestLanguage::moduleMergingVariantValues() { bool exceptionCaught = false; try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath - (testProject("module-merging-variant-values/module-merging-variant-values.qbs")); - params.expandBuildConfiguration(); - const TopLevelProjectPtr project = loader->loadProject(params); + resolveProject("module-merging-variant-values/module-merging-variant-values.qbs"); QVERIFY(!!project); QCOMPARE(int(project->products.size()), 2); } catch (const ErrorInfo &e) { @@ -1686,6 +1762,185 @@ void TestLanguage::moduleMergingVariantValues() QCOMPARE(exceptionCaught, false); } +void TestLanguage::moduleNameCollisions_data() +{ + QTest::addColumn<QString>("projectFile"); + QTest::addColumn<bool>("collisionExpected"); + + QTest::newRow("simple collision (one order)") << "simple-collision1.qbs" << true; + QTest::newRow("simple collision (other order)") << "simple-collision2.qbs" << true; + QTest::newRow("collision with more components") << "complex-collision.qbs" << true; + QTest::newRow("no collision (same length)") << "no-collision1.qbs" << false; + QTest::newRow("no collision (different length)") << "no-collision2.qbs" << false; +} + +void TestLanguage::moduleNameCollisions() +{ + QFETCH(QString, projectFile); + QFETCH(bool, collisionExpected); + + try { + const QString compositeProjectFilePath = QString("module-name-collisions/") + projectFile; + QVERIFY(resolveProject(qPrintable(compositeProjectFilePath))); + QVERIFY(!collisionExpected); + } catch (const ErrorInfo &e) { + const QString errorString = e.toString(); + QVERIFY2(collisionExpected, qPrintable(errorString)); + QVERIFY2(errorString.contains("not allowed"), qPrintable(errorString)); + } +} + +void TestLanguage::moduleParameters_data() +{ + QTest::addColumn<QVariantMap>("inputProperties"); + QTest::addColumn<QVariantMap>("expectedModuleParameters"); + QTest::addColumn<bool>("errorExpected"); + + QTest::newRow("no overrides") + << QVariantMap{ + std::make_pair("project.overrideFromModule", "false"), + std::make_pair("project.overrideFromExport", "false"), + std::make_pair("project.overrideFromProduct", "false")} + << QVariantMap{ + std::make_pair("higher", + QVariantMap{std::make_pair("lower", + QVariantMap{std::make_pair("param", "fromParameters")})}), + std::make_pair("dep", + QVariantMap{std::make_pair("lower", + QVariantMap{std::make_pair("param", "fromParameters")})})} + << false; + QTest::newRow("override from product") + << QVariantMap{ + std::make_pair("project.overrideFromModule", "false"), + std::make_pair("project.overrideFromExport", "false"), + std::make_pair("project.overrideFromProduct", "true")} + << QVariantMap{ + std::make_pair("higher", + QVariantMap{std::make_pair("lower", + QVariantMap{std::make_pair("param", "fromProductDepends")})}), + std::make_pair("dep", + QVariantMap{std::make_pair("lower", + QVariantMap{std::make_pair("param", "fromProductDepends")})})} + << false; + QTest::newRow("override from export") + << QVariantMap{ + std::make_pair("project.overrideFromModule", "false"), + std::make_pair("project.overrideFromExport", "true"), + std::make_pair("project.overrideFromProduct", "false")} + << QVariantMap{ + std::make_pair("higher", + QVariantMap{std::make_pair("lower", + QVariantMap{std::make_pair("param", "fromExportDepends")})}), + std::make_pair("dep", + QVariantMap{std::make_pair("lower", + QVariantMap{std::make_pair("param", "fromParameters")})})} + << false; + QTest::newRow("override from export and product") + << QVariantMap{ + std::make_pair("project.overrideFromModule", "false"), + std::make_pair("project.overrideFromExport", "true"), + std::make_pair("project.overrideFromProduct", "true")} + << QVariantMap{ + std::make_pair("higher", + QVariantMap{std::make_pair("lower", + QVariantMap{std::make_pair("param", "fromProductDepends")})}), + std::make_pair("dep", + QVariantMap{std::make_pair("lower", + QVariantMap{std::make_pair("param", "fromProductDepends")})})} + << false; + QTest::newRow("override from module") + << QVariantMap{ + std::make_pair("project.overrideFromModule", "true"), + std::make_pair("project.overrideFromExport", "false"), + std::make_pair("project.overrideFromProduct", "false")} + << QVariantMap{ + std::make_pair("higher", + QVariantMap{std::make_pair("lower", + QVariantMap{std::make_pair("param", "fromModuleDepends")})}), + std::make_pair("dep", + QVariantMap{std::make_pair("lower", + QVariantMap{std::make_pair("param", "fromParameters")})})} + << false; + QTest::newRow("override from module and product") + << QVariantMap{ + std::make_pair("project.overrideFromModule", "true"), + std::make_pair("project.overrideFromExport", "false"), + std::make_pair("project.overrideFromProduct", "true")} + << QVariantMap{ + std::make_pair("higher", + QVariantMap{std::make_pair("lower", + QVariantMap{std::make_pair("param", "fromProductDepends")})}), + std::make_pair("dep", + QVariantMap{std::make_pair("lower", + QVariantMap{std::make_pair("param", "fromProductDepends")})})} + << false; + QTest::newRow("override from module and export") + << QVariantMap{ + std::make_pair("project.overrideFromModule", "true"), + std::make_pair("project.overrideFromExport", "true"), + std::make_pair("project.overrideFromProduct", "false")} + << QVariantMap{ + std::make_pair("higher", + QVariantMap{std::make_pair("lower", + QVariantMap{std::make_pair("param", "fromExportDepends")})}), + std::make_pair("dep", + QVariantMap{std::make_pair("lower", + QVariantMap{std::make_pair("param", "fromParameters")})})} + << true; + QTest::newRow("override from module, export and product") + << QVariantMap{ + std::make_pair("project.overrideFromModule", "true"), + std::make_pair("project.overrideFromExport", "true"), + std::make_pair("project.overrideFromProduct", "true")} + << QVariantMap{ + std::make_pair("higher", + QVariantMap{std::make_pair("lower", + QVariantMap{std::make_pair("param", "fromProductDepends")})}), + std::make_pair("dep", + QVariantMap{std::make_pair("lower", + QVariantMap{std::make_pair("param", "fromProductDepends")})})} + << false; +} + +void TestLanguage::moduleParameters() +{ + QFETCH(QVariantMap, inputProperties); + QFETCH(QVariantMap, expectedModuleParameters); + QFETCH(bool, errorExpected); + + try { + defaultParameters.setOverriddenValues(inputProperties); + resolveProject("module-parameters/module-parameters.qbs"); + QVERIFY(!errorExpected); + QVERIFY(project); + QCOMPARE(int(project->products.size()), 2); + const ResolvedProductPtr mainProduct = productsFromProject(project).value("main"); + QVERIFY(mainProduct); + QCOMPARE(int(mainProduct->moduleParameters.size()), 2); + for (auto it = expectedModuleParameters.cbegin(); it != expectedModuleParameters.cend(); + ++it) { + const auto findInProduct = [&](const QString &moduleName) { + for (auto it = mainProduct->moduleParameters.cbegin(); + it != mainProduct->moduleParameters.cend(); ++it) { + if (it.key()->name == moduleName) + return it.value(); + } + return QVariantMap(); + }; + const QVariantMap actual = findInProduct(it.key()); + const QVariantMap expected = it.value().toMap(); + const bool same = qVariantMapsEqual(actual, expected); + if (!same) { + qDebug().noquote() << "---" << expected; + qDebug().noquote() << "+++" << actual; + } + QVERIFY(same); + } + } catch (const ErrorInfo &e) { + QVERIFY2(errorExpected, qPrintable(e.toString())); + } +} + void TestLanguage::modulePrioritizationBySearchPath_data() { QTest::addColumn<QStringList>("searchPaths"); @@ -1701,12 +1956,10 @@ void TestLanguage::modulePrioritizationBySearchPath() bool exceptionCaught = false; try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("module-prioritization-by-search-path/project.qbs")); - params.setOverriddenValues({std::make_pair(QStringLiteral("project.qbsSearchPaths"), - searchPaths)}); - params.expandBuildConfiguration(); - TopLevelProjectPtr project = loader->loadProject(params); + defaultParameters.setOverriddenValues( + {std::make_pair(QStringLiteral("project.qbsSearchPaths"), + searchPaths)}); + resolveProject("module-prioritization-by-search-path/project.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 1); @@ -1715,8 +1968,7 @@ void TestLanguage::modulePrioritizationBySearchPath() const QString actualVariant = product->moduleProperties->moduleProperty ("conflicting-instances", "moduleVariant").toString(); QCOMPARE(actualVariant, expectedVariant); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } @@ -1730,10 +1982,10 @@ void TestLanguage::moduleProperties_data() QTest::newRow("init") << QString() << QVariant(); QTest::newRow("merge_lists") << "defines" - << QVariant(QStringList() << "THE_PRODUCT" << "QT_CORE" << "QT_GUI" << "QT_NETWORK"); + << QVariant(QStringList() << "THE_PRODUCT" << "QT_NETWORK" << "QT_GUI" << "QT_CORE"); QTest::newRow("merge_lists_and_values") << "defines" - << QVariant(QStringList() << "THE_PRODUCT" << "QT_CORE" << "QT_GUI" << "QT_NETWORK"); + << QVariant(QStringList() << "THE_PRODUCT" << "QT_NETWORK" << "QT_GUI" << "QT_CORE"); QTest::newRow("merge_lists_with_duplicates") << "cxxFlags" << QVariant(QStringList() << "-foo" << "BAR" << "-foo" << "BAZ"); @@ -1782,7 +2034,7 @@ void TestLanguage::modulePropertiesInGroups() defaultParameters.setProjectFilePath(testProject("modulepropertiesingroups.qbs")); bool exceptionCaught = false; try { - TopLevelProjectPtr project = loader->loadProject(defaultParameters); + resolveProject(); QVERIFY(!!project); const QHash<QString, ResolvedProductPtr> products = productsFromProject(project); ResolvedProductPtr product = products.value("grouptest"); @@ -1793,7 +2045,7 @@ void TestLanguage::modulePropertiesInGroups() GroupConstPtr g2; GroupConstPtr g21; GroupConstPtr g211; - for (const GroupConstPtr &g : product->groups) { + for (const GroupPtr &g : product->groups) { if (g->name == "g1") g1= g; else if (g->name == "g2") @@ -1910,7 +2162,7 @@ void TestLanguage::modulePropertiesInGroups() QCOMPARE(g2Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2"); const auto &g2Gmod1List2 = moduleProperty(g2Props, "gmod.gmod1", "gmod1_list2") .toStringList(); - QCOMPARE(g2Gmod1List2, QStringList() << "grouptest" << "g2" << "gmod1_list2_proto"); + QCOMPARE(g2Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto" << "gmod1_list2_proto"); const int g2P0 = moduleProperty(g2Props, "gmod.gmod1", "p0").toInt(); QCOMPARE(g2P0, 6); const int g2DepProp = moduleProperty(g2Props, "gmod.gmod1", "depProp").toInt(); @@ -1928,7 +2180,7 @@ void TestLanguage::modulePropertiesInGroups() QCOMPARE(g21Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2"); const auto &g21Gmod1List2 = moduleProperty(g21Props, "gmod.gmod1", "gmod1_list2") .toStringList(); - QEXPECT_FAIL(0, "no re-eval when no module props set", Continue); + QEXPECT_FAIL(nullptr, "no re-eval when no module props set", Continue); QCOMPARE(g21Gmod1List2, QStringList() << "grouptest" << "g2.1" << "gmod1_list2_proto"); const int g21P0 = moduleProperty(g21Props, "gmod.gmod1", "p0").toInt(); QCOMPARE(g21P0, 6); @@ -1938,7 +2190,7 @@ void TestLanguage::modulePropertiesInGroups() QCOMPARE(g21Gmod2String, QString("g2")); const auto &g21Gmod2List = moduleProperty(g21Props, "gmod2", "gmod2_list") .toStringList(); - QEXPECT_FAIL(0, "no re-eval when no module props set", Continue); + QEXPECT_FAIL(nullptr, "no re-eval when no module props set", Continue); QCOMPARE(g21Gmod2List, QStringList() << "g2" << "commonName_in_gmod1" << "g2.1_gmod4_g2.1_gmod3" << "g2.1_gmod3" << "gmod2_list_proto"); @@ -1955,11 +2207,11 @@ void TestLanguage::modulePropertiesInGroups() QCOMPARE(g211DepProp, 2); const auto &g211Gmod2String = moduleProperty(g211Props, "gmod2", "gmod2_string").toString(); - QEXPECT_FAIL(0, "re-eval not triggered", Continue); + QEXPECT_FAIL(nullptr, "re-eval not triggered", Continue); QCOMPARE(g211Gmod2String, QString("g2.1.1")); const auto &g211Gmod2List = moduleProperty(g211Props, "gmod2", "gmod2_list") .toStringList(); - QEXPECT_FAIL(0, "re-eval not triggered", Continue); + QEXPECT_FAIL(nullptr, "re-eval not triggered", Continue); QCOMPARE(g211Gmod2List, QStringList() << "g2.1.1" << "commonName_in_gmod1" << "g2.1.1_gmod4_g2.1.1_gmod3" << "g2.1.1_gmod3" << "gmod2_list_proto"); @@ -1967,7 +2219,7 @@ void TestLanguage::modulePropertiesInGroups() QVERIFY(!!product); g1.reset(); g11.reset(); - for (const GroupConstPtr &g : product->groups) { + for (const GroupPtr &g : product->groups) { if (g->name == "g1") g1= g; else if (g->name == "g1.1") @@ -1994,17 +2246,14 @@ void TestLanguage::modulePropertyOverridesPerProduct() { bool exceptionCaught = false; try { - SetupProjectParameters params = defaultParameters; - params.setOverriddenValues({ + defaultParameters.setOverriddenValues({ std::make_pair("modules.dummy.rpaths", QStringList({"/usr/lib"})), std::make_pair("modules.dummy.someString", "m"), std::make_pair("products.b.dummy.someString", "b"), std::make_pair("products.c.dummy.someString", "c"), std::make_pair("products.c.dummy.rpaths", QStringList({"/home", "/tmp"})) }); - params.setProjectFilePath( - testProject("module-property-overrides-per-product.qbs")); - const TopLevelProjectPtr project = loader->loadProject(params); + resolveProject("module-property-overrides-per-product.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 3); @@ -2037,8 +2286,7 @@ void TestLanguage::modulePropertyOverridesPerProduct() QCOMPARE(listPropertyValue(a), productPropertyValue(a)); QCOMPARE(listPropertyValue(b), productPropertyValue(b)); QCOMPARE(listPropertyValue(c), productPropertyValue(c)); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } @@ -2050,7 +2298,7 @@ void TestLanguage::moduleScope() bool exceptionCaught = false; try { defaultParameters.setProjectFilePath(testProject("modulescope.qbs")); - TopLevelProjectPtr project = loader->loadProject(defaultParameters); + resolveProject(); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 1); @@ -2070,13 +2318,30 @@ void TestLanguage::moduleScope() QCOMPARE(intModuleValue("f"), 2); // overridden QCOMPARE(intModuleValue("g"), 156); // overridden, dependent on product properties QCOMPARE(intModuleValue("h"), 158); // overridden, base dependent on product properties - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); +} +void TestLanguage::moduleWithProductDependency() +{ + bool exceptionCaught = false; + try { + defaultParameters.setProjectFilePath(testProject("module-depends-on-product.qbs")); + resolveProject(); + QVERIFY(project); + QHash<QString, ResolvedProductPtr> products = productsFromProject(project); + QCOMPARE(products.size(), 2); + ResolvedProductPtr product = products.value("p1"); + QVERIFY(product); + QCOMPARE(int(product->dependencies.size()), 1); + } catch (const ErrorInfo &e) { + exceptionCaught = true; + qDebug() << e.toString(); + } + QCOMPARE(exceptionCaught, false); } void TestLanguage::modules_data() @@ -2135,9 +2400,7 @@ void TestLanguage::multiplexedExports() { bool exceptionCaught = false; try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("multiplexed-exports.qbs")); - const TopLevelProjectPtr project = loader->loadProject(params); + resolveProject("multiplexed-exports.qbs"); QVERIFY(!!project); const auto products = project->allProducts(); QCOMPARE(products.size(), size_t(4)); @@ -2171,11 +2434,9 @@ void TestLanguage::multiplexingByProfile() { QFETCH(QString, projectFileName); QFETCH(bool, successExpected); - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testDataDir() + "/multiplexing-by-profile/" + projectFileName); try { - params.setDryRun(true); - const TopLevelProjectPtr project = loader->loadProject(params); + defaultParameters.setDryRun(true); + resolveProject(qPrintable("/multiplexing-by-profile/" + projectFileName)); QVERIFY(successExpected); QVERIFY(!!project); } catch (const ErrorInfo &e) { @@ -2199,11 +2460,9 @@ void TestLanguage::nonApplicableModulePropertyInProfile() QFETCH(QString, toolchain); QFETCH(bool, successExpected); try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("non-applicable-module-property-in-profile.qbs")); - params.setOverriddenValues(QVariantMap{std::make_pair("project.targetOS", targetOS), + defaultParameters.setOverriddenValues({std::make_pair("project.targetOS", targetOS), std::make_pair("project.toolchain", toolchain)}); - const TopLevelProjectPtr project = loader->loadProject(params); + resolveProject("non-applicable-module-property-in-profile.qbs"); QVERIFY(!!project); QVERIFY(successExpected); } catch (const ErrorInfo &e) { @@ -2233,8 +2492,6 @@ void TestLanguage::nonRequiredProducts() { bool exceptionCaught = false; try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("non-required-products.qbs")); QFETCH(bool, subProjectEnabled); QFETCH(bool, dependeeEnabled); QVariantMap overriddenValues; @@ -2242,8 +2499,8 @@ void TestLanguage::nonRequiredProducts() overriddenValues.insert("projects.subproject.condition", false); else if (!dependeeEnabled) overriddenValues.insert("products.dependee.condition", false); - params.setOverriddenValues(overriddenValues); - const TopLevelProjectPtr project = loader->loadProject(params); + defaultParameters.setOverriddenValues(overriddenValues); + resolveProject("non-required-products.qbs"); QVERIFY(!!project); const auto products = productsFromProject(project); QCOMPARE(products.size(), 4 + !!subProjectEnabled); @@ -2262,8 +2519,7 @@ void TestLanguage::nonRequiredProducts() QVERIFY2(product, name); QVERIFY2(!product->enabled, name); } - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } @@ -2284,7 +2540,7 @@ void TestLanguage::outerInGroup() bool exceptionCaught = false; try { defaultParameters.setProjectFilePath(testProject("outerInGroup.qbs")); - TopLevelProjectPtr project = loader->loadProject(defaultParameters); + resolveProject(); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 1); @@ -2305,8 +2561,7 @@ void TestLanguage::outerInGroup() artifact = group->files.front(); installDir = artifact->properties->qbsPropertyValue("installDir"); QCOMPARE(installDir.toString(), QString("/somewhere/else")); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } @@ -2319,16 +2574,14 @@ void TestLanguage::overriddenPropertiesAndPrototypes() try { QFETCH(QString, osName); QFETCH(QString, backendName); - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("overridden-properties-and-prototypes.qbs")); - params.setOverriddenValues({std::make_pair("modules.qbs.targetPlatform", osName)}); - TopLevelProjectConstPtr project = loader->loadProject(params); + defaultParameters.setOverriddenValues({std::make_pair("modules.qbs.targetPlatform", + osName)}); + resolveProject("overridden-properties-and-prototypes.qbs"); QVERIFY(!!project); QCOMPARE(project->products.size(), size_t(1)); QCOMPARE(project->products.front()->moduleProperties->moduleProperty( "multiple_backends", "prop").toString(), backendName); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } @@ -2347,11 +2600,9 @@ void TestLanguage::overriddenVariantProperty() { bool exceptionCaught = false; try { - SetupProjectParameters params = defaultParameters; const QVariantMap objectValue{std::make_pair("x", 1), std::make_pair("y", 2)}; - params.setOverriddenValues({std::make_pair("products.p.myObject", objectValue)}); - params.setProjectFilePath(testProject("overridden-variant-property.qbs")); - TopLevelProjectConstPtr project = loader->loadProject(params); + defaultParameters.setOverriddenValues({std::make_pair("products.p.myObject", objectValue)}); + resolveProject("overridden-variant-property.qbs"); QVERIFY(!!project); QCOMPARE(project->products.size(), size_t(1)); QCOMPARE(project->products.front()->productProperties.value("myObject").toMap(), @@ -2368,9 +2619,8 @@ void TestLanguage::parameterTypes() bool exceptionCaught = false; try { defaultParameters.setProjectFilePath(testProject("parameter-types.qbs")); - loader->loadProject(defaultParameters); - } - catch (const ErrorInfo &e) { + resolveProject(); + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } @@ -2381,8 +2631,7 @@ void TestLanguage::pathProperties() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("pathproperties.qbs")); - project = loader->loadProject(defaultParameters); + resolveProject("pathproperties.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); ResolvedProductPtr product = products.value("product1"); @@ -2408,6 +2657,35 @@ void TestLanguage::pathProperties() QCOMPARE(exceptionCaught, false); } +void TestLanguage::probesAndMultiplexing() +{ + bool exceptionCaught = false; + try { + resolveProject("probes-and-multiplexing.qbs"); + QVERIFY(project); + QCOMPARE(int(project->products.size()), 3); + QStringList architectures{"x86", "x86_64", "arm"}; + for (const ResolvedProductPtr &product : project->products) { + const QString arch = product->moduleProperties->moduleProperty("qbs", "architecture") + .toString(); + QVERIFY2(architectures.removeOne(arch), qPrintable(arch)); + QCOMPARE(product->productProperties.value("archFromProbe").toString(), arch); + bool foundGroup = false; + for (const GroupPtr &group : product->groups) { + if (group->name == "theGroup") { + foundGroup = true; + QCOMPARE(group->properties->moduleProperty("qbs", "sysroot"), "/" + arch); + } + } + QVERIFY(foundGroup); + } + } catch (const ErrorInfo &e) { + exceptionCaught = true; + qDebug() << e.toString(); + } + QCOMPARE(exceptionCaught, false); +} + void TestLanguage::profileValuesAndOverriddenValues() { bool exceptionCaught = false; @@ -2418,14 +2696,11 @@ void TestLanguage::profileValuesAndOverriddenValues() profile.setValue("dummy.cFlags", "IN_PROFILE"); profile.setValue("dummy.cxxFlags", "IN_PROFILE"); profile.setValue("qbs.architecture", "x86"); - SetupProjectParameters parameters = defaultParameters; - parameters.setTopLevelProfile(profile.name()); + defaultParameters.setTopLevelProfile(profile.name()); QVariantMap overriddenValues; overriddenValues.insert("modules.dummy.cFlags", "OVERRIDDEN"); - parameters.setOverriddenValues(overriddenValues); - parameters.setProjectFilePath(testProject("profilevaluesandoverriddenvalues.qbs")); - parameters.expandBuildConfiguration(); - project = loader->loadProject(parameters); + defaultParameters.setOverriddenValues(overriddenValues); + resolveProject("profilevaluesandoverriddenvalues.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); ResolvedProductPtr product = products.value("product1"); @@ -2455,7 +2730,7 @@ void TestLanguage::projectFileLookup() try { SetupProjectParameters params; params.setProjectFilePath(projectFileInput); - Loader::setupProjectFilePath(params); + params.finalizeProjectFilePath(); QVERIFY(!failureExpected); QCOMPARE(params.projectFilePath(), projectFileOutput); } catch (const ErrorInfo &) { @@ -2469,7 +2744,7 @@ void TestLanguage::projectFileLookup_data() QTest::addColumn<QString>("projectFileOutput"); QTest::addColumn<bool>("failureExpected"); - const QString baseDir = QLatin1String(SRCDIR) + "/testdata"; + const QString baseDir = testDataDir(); const QString multiProjectsDir = baseDir + "/dirwithmultipleprojects"; const QString noProjectsDir = baseDir + "/dirwithnoprojects"; const QString oneProjectDir = baseDir + "/dirwithoneproject"; @@ -2486,8 +2761,7 @@ void TestLanguage::productConditions() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("productconditions.qbs")); - TopLevelProjectPtr project = loader->loadProject(defaultParameters); + resolveProject("productconditions.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 6); @@ -2515,8 +2789,7 @@ void TestLanguage::productConditions() product = products.value("product_probe_condition_true"); QVERIFY(!!product); QVERIFY(product->enabled); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } @@ -2527,8 +2800,7 @@ void TestLanguage::productDirectories() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("productdirectories.qbs")); - ResolvedProjectPtr project = loader->loadProject(defaultParameters); + resolveProject("productdirectories.qbs"); QVERIFY(!!project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 1); @@ -2539,8 +2811,7 @@ void TestLanguage::productDirectories() QCOMPARE(config.value(QStringLiteral("buildDirectory")).toString(), product->buildDirectory()); QCOMPARE(config.value(QStringLiteral("sourceDirectory")).toString(), testDataDir()); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } @@ -2686,8 +2957,7 @@ void TestLanguage::propertiesBlockInGroup() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("properties-block-in-group.qbs")); - const TopLevelProjectPtr project = loader->loadProject(defaultParameters); + resolveProject("properties-block-in-group.qbs"); QVERIFY(!!project); QCOMPARE(project->allProducts().size(), size_t(1)); const ResolvedProductConstPtr product = project->allProducts().front(); @@ -2711,13 +2981,11 @@ void TestLanguage::propertiesItemInModule() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath( - testProject("properties-item-in-module.qbs")); - const TopLevelProjectPtr project = loader->loadProject(defaultParameters); + resolveProject("properties-item-in-module.qbs"); QVERIFY(!!project); const QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 2); - for (const ResolvedProductConstPtr &p : products) { + for (const ResolvedProductPtr &p : products) { QCOMPARE(p->moduleProperties->moduleProperty("dummy", "productName").toString(), p->name); } @@ -2732,16 +3000,14 @@ void TestLanguage::propertyAssignmentInExportedGroup() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath( - testProject("property-assignment-in-exported-group.qbs")); - const TopLevelProjectPtr project = loader->loadProject(defaultParameters); + resolveProject("property-assignment-in-exported-group.qbs"); QVERIFY(!!project); const QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 2); - for (const ResolvedProductConstPtr &p : products) { + for (const ResolvedProductPtr &p : products) { QCOMPARE(p->moduleProperties->moduleProperty("dummy", "someString").toString(), QString()); - for (const GroupConstPtr &g : p->groups) { + for (const GroupPtr &g : p->groups) { const QString propValue = g->properties->moduleProperty("dummy", "someString").toString(); if (g->name == "exported_group") @@ -2761,8 +3027,7 @@ void TestLanguage::qbs1275() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath(testProject("qbs1275.qbs")); - const TopLevelProjectPtr project = loader->loadProject(defaultParameters); + resolveProject("qbs1275.qbs"); QVERIFY(!!project); const QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.count(), 5); @@ -2777,10 +3042,9 @@ void TestLanguage::qbsPropertiesInProjectCondition() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath( - testProject("qbs-properties-in-project-condition.qbs")); - const TopLevelProjectPtr project = loader->loadProject(defaultParameters); + resolveProject("qbs-properties-in-project-condition.qbs"); QVERIFY(!!project); + QVERIFY(!project->enabled); const QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 0); } catch (const ErrorInfo &e) { @@ -2794,16 +3058,14 @@ void TestLanguage::qbsPropertyConvenienceOverride() { bool exceptionCaught = false; try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("qbs-property-convenience-override.qbs")); - params.setOverriddenValues({std::make_pair("qbs.installPrefix", "/opt")}); - TopLevelProjectConstPtr project = loader->loadProject(params); + defaultParameters.setOverriddenValues({std::make_pair("qbs.installPrefix", "/opt")}); + resolveProject("qbs-property-convenience-override.qbs"); QVERIFY(!!project); QCOMPARE(project->products.size(), size_t(1)); QCOMPARE(project->products.front()->moduleProperties->qbsPropertyValue("installPrefix") .toString(), QString("/opt")); - } - catch (const ErrorInfo &e) { + } catch (const ErrorInfo &e) { + exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); @@ -2814,11 +3076,9 @@ void TestLanguage::relaxedErrorMode() m_logSink->setLogLevel(LoggerMinLevel); QFETCH(bool, strictMode); try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("relaxed-error-mode/relaxed-error-mode.qbs")); - params.setProductErrorMode(strictMode ? ErrorHandlingMode::Strict - : ErrorHandlingMode::Relaxed); - const TopLevelProjectPtr project = loader->loadProject(params); + defaultParameters.setProductErrorMode(strictMode ? ErrorHandlingMode::Strict + : ErrorHandlingMode::Relaxed); + resolveProject("relaxed-error-mode/relaxed-error-mode.qbs"); QVERIFY(!strictMode); const auto productMap = productsFromProject(project); const ResolvedProductConstPtr brokenProduct = productMap.value("broken"); @@ -2841,7 +3101,7 @@ void TestLanguage::relaxedErrorMode() QVERIFY(missingFile->enabled); QCOMPARE(missingFile->groups.size(), size_t(1)); QVERIFY(missingFile->groups.front()->enabled); - QCOMPARE(missingFile->groups.front()->allFiles().size(), size_t(2)); + QCOMPARE(missingFile->groups.front()->files.size(), size_t(2)); const ResolvedProductConstPtr fine = productMap.value("fine"); QVERIFY(fine->enabled); QCOMPARE(fine->allFiles().size(), size_t(1)); @@ -2863,10 +3123,7 @@ void TestLanguage::requiredAndNonRequiredDependencies() QFETCH(QString, projectFile); QFETCH(bool, exceptionExpected); try { - SetupProjectParameters params = defaultParameters; - const QString projectFilePath = "required-and-nonrequired-dependencies/" + projectFile; - params.setProjectFilePath(testProject(projectFilePath.toLocal8Bit())); - const TopLevelProjectConstPtr project = loader->loadProject(params); + resolveProject(qPrintable("required-and-nonrequired-dependencies/" + projectFile)); QVERIFY(!!project); QVERIFY(!exceptionExpected); } catch (const ErrorInfo &e) { @@ -2893,10 +3150,7 @@ void TestLanguage::requiredAndNonRequiredDependencies_data() void TestLanguage::suppressedAndNonSuppressedErrors() { try { - SetupProjectParameters params = defaultParameters; - const QString projectFilePath = "suppressed-and-non-suppressed-errors.qbs"; - params.setProjectFilePath(testProject(projectFilePath.toLocal8Bit())); - const TopLevelProjectConstPtr project = loader->loadProject(params); + resolveProject("suppressed-and-non-suppressed-errors.qbs"); QFAIL("failure expected"); } catch (const ErrorInfo &e) { QVERIFY2(e.toString().contains("easter bunny"), qPrintable(e.toString())); @@ -2908,12 +3162,10 @@ void TestLanguage::throwingProbe() { QFETCH(bool, enableProbe); try { - SetupProjectParameters params = defaultParameters; - params.setProjectFilePath(testProject("throwing-probe.qbs")); QVariantMap properties; properties.insert(QStringLiteral("products.theProduct.enableProbe"), enableProbe); - params.setOverriddenValues(properties); - const TopLevelProjectPtr project = loader->loadProject(params); + defaultParameters.setOverriddenValues(properties); + resolveProject("throwing-probe.qbs"); QVERIFY(!!project); QVERIFY(!enableProbe); } catch (const ErrorInfo &e) { @@ -2955,9 +3207,7 @@ void TestLanguage::recursiveProductDependencies() { bool exceptionCaught = false; try { - defaultParameters.setProjectFilePath( - testProject("recursive-dependencies/recursive-dependencies.qbs")); - const TopLevelProjectPtr project = loader->loadProject(defaultParameters); + resolveProject("recursive-dependencies/recursive-dependencies.qbs"); QVERIFY(!!project); const QHash<QString, ResolvedProductPtr> products = productsFromProject(project); QCOMPARE(products.size(), 4); @@ -3014,6 +3264,19 @@ void TestLanguage::fileTags() QCOMPARE(fileTags, expectedFileTags); } +void TestLanguage::useInternalProfile() +{ + const QString profile(QStringLiteral("theprofile")); + defaultParameters.setTopLevelProfile(profile); + resolveProject("use-internal-profile.qbs"); + QVERIFY(!!project); + QCOMPARE(project->profile(), profile); + QCOMPARE(project->products.size(), size_t(1)); + const ResolvedProductConstPtr product = project->products[0]; + QCOMPARE(product->profile(), profile); + QCOMPARE(product->moduleProperties->moduleProperty("dummy", "defines").toString(), profile); +} + void TestLanguage::wildcards_data() { QTest::addColumn<bool>("useGroup"); @@ -3182,8 +3445,8 @@ void TestLanguage::wildcards() QFile projectFile(projectFilePath); QVERIFY(projectFile.open(QIODevice::WriteOnly)); QTextStream s(&projectFile); - s << "import qbs.base 1.0" << endl << endl - << "Application {" << endl + using Qt::endl; + s << "Application {" << endl << " name: \"MyProduct\"" << endl; if (useGroup) { s << " Group {" << endl @@ -3201,7 +3464,7 @@ void TestLanguage::wildcards() } // create files - for (QString filePath : qAsConst(filesToCreate)) { + for (QString filePath : std::as_const(filesToCreate)) { filePath.prepend(m_wildcardsTestDirPath + '/'); QFileInfo fi(filePath); if (!QDir(fi.path()).exists()) @@ -3215,7 +3478,7 @@ void TestLanguage::wildcards() ResolvedProductPtr product; try { defaultParameters.setProjectFilePath(projectFilePath); - project = loader->loadProject(defaultParameters); + resolveProject(); QVERIFY(!!project); const QHash<QString, ResolvedProductPtr> products = productsFromProject(project); product = products.value("MyProduct"); @@ -3234,10 +3497,10 @@ void TestLanguage::wildcards() group = product->groups.front(); } QVERIFY(!!group); - QCOMPARE(group->files.size(), size_t(0)); + QCOMPARE(group->files.size(), expected.size()); // we assume all files are wildcards QVERIFY(!!group->wildcards); QStringList actualFilePaths; - for (const SourceArtifactConstPtr &artifact : group->wildcards->files) { + for (const SourceArtifactPtr &artifact : group->files) { QString str = artifact->absoluteFilePath; int idx = str.indexOf(m_wildcardsTestDirPath); if (idx != -1) @@ -3261,4 +3524,3 @@ int main(int argc, char *argv[]) TestLanguage tl(ConsoleLogger::instance().logSink(), s.get()); return QTest::qExec(&tl, argc, argv); } - diff --git a/tests/auto/language/tst_language.h b/tests/auto/language/tst_language.h index 3fe6d8f2a..870b7d1f8 100644 --- a/tests/auto/language/tst_language.h +++ b/tests/auto/language/tst_language.h @@ -41,10 +41,12 @@ #define TST_LANGUAGE_H #include <language/forward_decls.h> -#include <language/loader.h> +#include <language/scriptengine.h> #include <logging/ilogsink.h> +#include <logging/logger.h> #include <tools/setupprojectparameters.h> +#include <QtCore/qrandom.h> #include <QtCore/qtemporarydir.h> #include <QtTest/qtest.h> @@ -55,27 +57,9 @@ public: TestLanguage(qbs::ILogSink *logSink, qbs::Settings *settings); ~TestLanguage(); -private: - qbs::ILogSink *m_logSink; - qbs::Settings * const m_settings; - qbs::Internal::Logger m_logger; - qbs::Internal::ScriptEngine *m_engine; - qbs::Internal::Loader *loader; - qbs::Internal::TopLevelProjectPtr project; - qbs::SetupProjectParameters defaultParameters; - const QString m_wildcardsTestDirPath; - - QHash<QString, qbs::Internal::ResolvedProductPtr> productsFromProject( - qbs::Internal::ResolvedProjectPtr project); - qbs::Internal::ResolvedModuleConstPtr findModuleByName( - qbs::Internal::ResolvedProductPtr product, const QString &name); - QVariant productPropertyValue(qbs::Internal::ResolvedProductPtr product, QString propertyName); - void handleInitCleanupDataTags(const char *projectFileName, bool *handled); - private slots: void init(); void initTestCase(); - void cleanupTestCase(); void additionalProductTypes(); void baseProperty(); @@ -87,6 +71,7 @@ private slots: void chainedProbes(); void canonicalArchitecture(); void conditionalDepends(); + void convertStringList(); void delayedError(); void delayedError_data(); void dependencyOnAllProfiles(); @@ -94,6 +79,8 @@ private slots: void disabledSubProject(); void dottedNames_data(); void dottedNames(); + void duplicateMultiplexValues_data(); + void duplicateMultiplexValues(); void emptyJsFile(); void enumerateProjectProperties(); void evalErrorInNonPresentModule_data(); @@ -123,12 +110,19 @@ private slots: void invalidBindingInDisabledItem(); void invalidOverrides(); void invalidOverrides_data(); + void invalidPropOnNonRequiredModule_data(); + void invalidPropOnNonRequiredModule(); void itemPrototype(); void itemScope(); void jsExtensions(); void jsImportUsedInMultipleScopes_data(); void jsImportUsedInMultipleScopes(); + void localProfileAsTopLevelProfile(); void moduleMergingVariantValues(); + void moduleNameCollisions_data(); + void moduleNameCollisions(); + void moduleParameters_data(); + void moduleParameters(); void modulePrioritizationBySearchPath_data(); void modulePrioritizationBySearchPath(); void moduleProperties_data(); @@ -136,6 +130,7 @@ private slots: void modulePropertiesInGroups(); void modulePropertyOverridesPerProduct(); void moduleScope(); + void moduleWithProductDependency(); void modules_data(); void modules(); void multiplexedExports(); @@ -151,6 +146,7 @@ private slots: void overriddenVariantProperty(); void parameterTypes(); void pathProperties(); + void probesAndMultiplexing(); void productConditions(); void productDirectories(); void profileValuesAndOverriddenValues(); @@ -176,12 +172,31 @@ private slots: void qualifiedId(); void recursiveProductDependencies(); void rfc1034Identifier(); + void throwThings_data(); + void throwThings(); + void useInternalProfile(); void versionCompare(); void wildcards_data(); void wildcards(); private: + QHash<QString, qbs::Internal::ResolvedProductPtr> productsFromProject( + qbs::Internal::ResolvedProjectPtr project); + qbs::Internal::ResolvedModuleConstPtr findModuleByName( + qbs::Internal::ResolvedProductPtr product, const QString &name); + QVariant productPropertyValue(qbs::Internal::ResolvedProductPtr product, QString propertyName); + void handleInitCleanupDataTags(const char *projectFileName, bool *handled); + qbs::Internal::TopLevelProjectPtr resolveProject(const char *relProjectFilePath = nullptr); + + qbs::ILogSink * const m_logSink; + qbs::Settings * const m_settings; + qbs::Internal::Logger m_logger; + std::unique_ptr<qbs::Internal::ScriptEngine> m_engine; + qbs::Internal::TopLevelProjectPtr project; + qbs::SetupProjectParameters defaultParameters; + const QString m_wildcardsTestDirPath; QTemporaryDir m_tempDir; + QRandomGenerator m_rand; }; #endif // TST_LANGUAGE_H diff --git a/tests/auto/pkgconfig/CMakeLists.txt b/tests/auto/pkgconfig/CMakeLists.txt new file mode 100644 index 000000000..74a13a8ab --- /dev/null +++ b/tests/auto/pkgconfig/CMakeLists.txt @@ -0,0 +1,8 @@ +add_qbs_test(pkgconfig + SOURCES + tst_pkgconfig.cpp + tst_pkgconfig.h + DEPENDS + qbspkgconfig + qbsquickjsheaders + ) diff --git a/tests/auto/pkgconfig/pkgconfig.qbs b/tests/auto/pkgconfig/pkgconfig.qbs new file mode 100644 index 000000000..d42a5233b --- /dev/null +++ b/tests/auto/pkgconfig/pkgconfig.qbs @@ -0,0 +1,19 @@ +import qbs +import qbs.Utilities + +QbsUnittest { + Depends { name: "qbspkgconfig" } + condition: qbsbuildconfig.enableUnitTests + testName: "pkgconfig" + files: ["../shared.h", "tst_pkgconfig.h", "tst_pkgconfig.cpp"] + cpp.defines: base.concat([ + "SRCDIR=" + Utilities.cStringQuote(path), + ]) + + Group { + name: "testdata" + prefix: "testdata/" + files: ["**/*"] + fileTags: [] + } +} diff --git a/tests/auto/pkgconfig/testdata/base.name.json b/tests/auto/pkgconfig/testdata/base.name.json new file mode 100644 index 000000000..a10e905ac --- /dev/null +++ b/tests/auto/pkgconfig/testdata/base.name.json @@ -0,0 +1,20 @@ +{ + "Name": "Base Name test", + "Description": "Checks correct baseName detection", + "Version": "1.0.0", + "Vars": { + "prefix": "/usr", + "exec_prefix": "/usr", + "libdir": "/usr/lib", + "includedir": "/usr/include" + }, + "Libs": [ + {"Type": "LibraryName", "Value": "simple"} + ], + "LibsPrivate": [ + {"Type": "LibraryName", "Value": "m"} + ], + "Cflags": [ + {"Type": "IncludePath", "Value": "/usr/include"} + ] +} diff --git a/tests/auto/pkgconfig/testdata/base.name.pc b/tests/auto/pkgconfig/testdata/base.name.pc new file mode 100644 index 000000000..2bb3e275e --- /dev/null +++ b/tests/auto/pkgconfig/testdata/base.name.pc @@ -0,0 +1,12 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: Base Name test +Description: Checks correct baseName detection +Version: 1.0.0 +Requires: +Libs: -lsimple +Libs.private: -lm +Cflags: -I${includedir} diff --git a/tests/auto/pkgconfig/testdata/empty-variable.json b/tests/auto/pkgconfig/testdata/empty-variable.json new file mode 100644 index 000000000..b96689979 --- /dev/null +++ b/tests/auto/pkgconfig/testdata/empty-variable.json @@ -0,0 +1,21 @@ +{ + "Name": "Empty Variable test", + "Description": "Checks that empty variables are handled correcty", + "Version": "1.0.0", + "Vars": { + "rootprefix": "", + "prefix": "/usr", + "exec_prefix": "//usr", + "libdir": "//usr/lib", + "includedir": "//usr/include" + }, + "Libs": [ + {"Type": "LibraryName", "Value": "simple"} + ], + "LibsPrivate": [ + {"Type": "LibraryName", "Value": "m"} + ], + "Cflags": [ + {"Type": "IncludePath", "Value": "//usr/include"} + ] +} diff --git a/tests/auto/pkgconfig/testdata/empty-variable.pc b/tests/auto/pkgconfig/testdata/empty-variable.pc new file mode 100644 index 000000000..581382b7e --- /dev/null +++ b/tests/auto/pkgconfig/testdata/empty-variable.pc @@ -0,0 +1,13 @@ +rootprefix= +prefix=/usr +exec_prefix=${rootprefix}/${prefix} +libdir=${exec_prefix}/lib +includedir=${rootprefix}/${prefix}/include + +Name: Empty Variable test +Description: Checks that empty variables are handled correcty +Version: 1.0.0 +Requires: +Libs: -lsimple +Libs.private: -lm +Cflags: -I${includedir} diff --git a/tests/auto/pkgconfig/testdata/lib/pkgconfig/prefix.pc b/tests/auto/pkgconfig/testdata/lib/pkgconfig/prefix.pc new file mode 100644 index 000000000..64b980803 --- /dev/null +++ b/tests/auto/pkgconfig/testdata/lib/pkgconfig/prefix.pc @@ -0,0 +1,13 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=/usr/include +usrdir=/usrdir + +Name: Prefix test +Description: This tests prefix auto detection +Version: 1.0.0 +Requires: +Libs: -lprefix +Libs.private: -lm +Cflags: -I${includedir} diff --git a/tests/auto/pkgconfig/testdata/non-l-required.json b/tests/auto/pkgconfig/testdata/non-l-required.json new file mode 100644 index 000000000..d2dd90f06 --- /dev/null +++ b/tests/auto/pkgconfig/testdata/non-l-required.json @@ -0,0 +1,12 @@ +{ + "Name": "Non-l flags required test package", + "Description": "Test package for checking order of non-L Libs & Cflags", + "Version": "1.0.0", + "Libs": [ + {"Type": "StaticLibraryName", "Value": "/non-l-required.a"}, + {"Type": "LinkerFlag", "Value": "-pthread"} + ], + "Cflags": [ + {"Type": "IncludePath", "Value": "/non-l-required/include"} + ] +} diff --git a/tests/auto/pkgconfig/testdata/non-l-required.pc b/tests/auto/pkgconfig/testdata/non-l-required.pc new file mode 100644 index 000000000..7e398e2e1 --- /dev/null +++ b/tests/auto/pkgconfig/testdata/non-l-required.pc @@ -0,0 +1,5 @@ +Name: Non-l flags required test package +Description: Test package for checking order of non-L Libs & Cflags +Version: 1.0.0 +Libs: /non-l-required.a -pthread +Cflags: -I/non-l-required/include diff --git a/tests/auto/pkgconfig/testdata/private-dep.pc b/tests/auto/pkgconfig/testdata/private-dep.pc new file mode 100644 index 000000000..cb401391d --- /dev/null +++ b/tests/auto/pkgconfig/testdata/private-dep.pc @@ -0,0 +1,6 @@ +Name: Requires test package +Description: Dummy pkgconfig test package for testing Requires/Requires.private +Version: 1.0.0 +Libs: -L/private-dep/lib -lprivate-dep +Cflags: -I/private-dep/include + diff --git a/tests/auto/pkgconfig/testdata/public-dep.pc b/tests/auto/pkgconfig/testdata/public-dep.pc new file mode 100644 index 000000000..e450e46f1 --- /dev/null +++ b/tests/auto/pkgconfig/testdata/public-dep.pc @@ -0,0 +1,6 @@ +Name: Requires test package +Description: Dummy pkgconfig test package for testing Requires/Requires.private +Version: 1.0.0 +Requires.private: +Libs: -L/public-dep/lib -lpublic-dep +Cflags: -I/public-dep/include diff --git a/tests/auto/pkgconfig/testdata/requires-test.json b/tests/auto/pkgconfig/testdata/requires-test.json new file mode 100644 index 000000000..32acf4b91 --- /dev/null +++ b/tests/auto/pkgconfig/testdata/requires-test.json @@ -0,0 +1,18 @@ +{ + "Name": "Requires test package", + "Description": "Dummy pkgconfig test package for testing Requires/Requires.private", + "Version": "1.0.0", + "Libs": [ + {"Type": "LibraryPath", "Value": "/requires-test/lib"}, + {"Type": "LibraryName", "Value": "requires-test"} + ], + "Cflags": [ + {"Type": "IncludePath", "Value": "/requires-test/include"} + ], + "Requires": [ + {"Comparison": "GreaterThanEqual", "Name": "public-dep", "Version": "1"} + ], + "RequiresPrivate": [ + {"Comparison": "GreaterThanEqual", "Name": "private-dep", "Version": "1"} + ] +} diff --git a/tests/auto/pkgconfig/testdata/requires-test.pc b/tests/auto/pkgconfig/testdata/requires-test.pc new file mode 100644 index 000000000..e483db2db --- /dev/null +++ b/tests/auto/pkgconfig/testdata/requires-test.pc @@ -0,0 +1,8 @@ +Name: Requires test package +Description: Dummy pkgconfig test package for testing Requires/Requires.private +Version: 1.0.0 +Requires: public-dep >= 1 +Requires.private: private-dep >= 1 +Libs: -L/requires-test/lib -lrequires-test +Cflags: -I/requires-test/include + diff --git a/tests/auto/pkgconfig/testdata/simple.json b/tests/auto/pkgconfig/testdata/simple.json new file mode 100644 index 000000000..d58556e74 --- /dev/null +++ b/tests/auto/pkgconfig/testdata/simple.json @@ -0,0 +1,20 @@ +{ + "Name": "Simple test", + "Description": "Dummy pkgconfig test package for testing pkgconfig", + "Version": "1.0.0", + "Vars": { + "prefix": "/usr", + "exec_prefix": "/usr", + "libdir": "/usr/lib", + "includedir": "/usr/include" + }, + "Libs": [ + {"Type": "LibraryName", "Value": "simple"} + ], + "LibsPrivate": [ + {"Type": "LibraryName", "Value": "m"} + ], + "Cflags": [ + {"Type": "IncludePath", "Value": "/usr/include"} + ] +} diff --git a/tests/auto/pkgconfig/testdata/simple.pc b/tests/auto/pkgconfig/testdata/simple.pc new file mode 100644 index 000000000..2daa0350f --- /dev/null +++ b/tests/auto/pkgconfig/testdata/simple.pc @@ -0,0 +1,12 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: Simple test +Description: Dummy pkgconfig test package for testing pkgconfig +Version: 1.0.0 +Requires: +Libs: -lsimple +Libs.private: -lm +Cflags: -I${includedir} diff --git a/tests/auto/pkgconfig/testdata/special-flags.json b/tests/auto/pkgconfig/testdata/special-flags.json new file mode 100644 index 000000000..1949820a6 --- /dev/null +++ b/tests/auto/pkgconfig/testdata/special-flags.json @@ -0,0 +1,30 @@ +{ + "Name": "Special flags test", + "Description": "Dummy pkgconfig test package for testing pkgconfig", + "Version": "1.0.0", + "Vars": { + "prefix": "/usr", + "exec_prefix": "/usr", + "libdir": "/usr/lib", + "includedir": "/usr/include" + }, + "Libs": [ + {"Type": "LibraryPath", "Value": "/foo"}, + {"Type": "Framework", "Value": "Foo"}, + {"Type": "LibraryName", "Value": "simple"}, + {"Type": "LibraryPath", "Value": "/bar"}, + {"Type": "Framework", "Value": "Bar"}, + {"Type": "LinkerFlag", "Value": "-Wl,-framework"}, + {"Type": "LinkerFlag", "Value": "-Wl,Baz"} + ], + "Cflags": [ + {"Type": "IncludePath", "Value": "/foo"}, + {"Type": "CompilerFlag", "Value": "-g"}, + {"Type": "SystemIncludePath", "Value": "/system1"}, + {"Type": "DirAfterIncludePath", "Value": "/after1"}, + {"Type": "CompilerFlag", "Value": "-ffoo"}, + {"Type": "IncludePath", "Value": "/bar"}, + {"Type": "DirAfterIncludePath", "Value": "/after2"}, + {"Type": "SystemIncludePath", "Value": "/system2"} + ] +} diff --git a/tests/auto/pkgconfig/testdata/special-flags.pc b/tests/auto/pkgconfig/testdata/special-flags.pc new file mode 100644 index 000000000..0bdaeb1b0 --- /dev/null +++ b/tests/auto/pkgconfig/testdata/special-flags.pc @@ -0,0 +1,11 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: Special flags test +Description: Dummy pkgconfig test package for testing pkgconfig +Version: 1.0.0 +Requires: +Libs: -L/foo -framework Foo -lsimple -L/bar -framework Bar -Wl,-framework -Wl,Baz +Cflags: -I/foo -g -isystem /system1 -idirafter /after1 -ffoo -I/bar -idirafter /after2 -isystem /system2 diff --git a/tests/auto/pkgconfig/testdata/sysroot.json b/tests/auto/pkgconfig/testdata/sysroot.json new file mode 100644 index 000000000..7e8b3f6bb --- /dev/null +++ b/tests/auto/pkgconfig/testdata/sysroot.json @@ -0,0 +1,21 @@ +{ + "Name": "Test for sysroot", + "Description": "Test package for testing sysroot", + "Version": "1.0.0", + "Vars": { + "prefix": "/opt", + "exec_prefix": "/opt", + "libdir": "/opt/lib", + "includedir": "/opt/include", + "sysroot": "/newroot" + }, + "Libs": [ + {"Type": "LibraryPath", "Value": "/newroot/opt/lib"}, + {"Type": "LibraryName", "Value": "system"} + ], + "Cflags": [ + {"Type": "IncludePath", "Value": "/newroot/opt/include"}, + {"Type": "DirAfterIncludePath", "Value": "/newroot/opt/include/after"}, + {"Type": "SystemIncludePath", "Value": "/newroot/opt/include/system"} + ] +} diff --git a/tests/auto/pkgconfig/testdata/sysroot.pc b/tests/auto/pkgconfig/testdata/sysroot.pc new file mode 100644 index 000000000..d2f78987f --- /dev/null +++ b/tests/auto/pkgconfig/testdata/sysroot.pc @@ -0,0 +1,12 @@ +prefix=/opt +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include +sysroot=${pc_sysrootdir} + +Name: Test for sysroot +Description: Test package for testing sysroot +Version: 1.0.0 +Requires: +Libs: -L${libdir} -lsystem +Cflags: -I${includedir} -idirafter ${includedir}/after -isystem ${includedir}/system diff --git a/tests/auto/pkgconfig/testdata/system.json b/tests/auto/pkgconfig/testdata/system.json new file mode 100644 index 000000000..89007e7ec --- /dev/null +++ b/tests/auto/pkgconfig/testdata/system.json @@ -0,0 +1,17 @@ +{ + "Name": "System library", + "Description": "Test package", + "Version": "1.0.0", + "Vars": { + "prefix": "/usr", + "exec_prefix": "/usr", + "libdir": "/usr/lib", + "includedir": "/usr/include" + }, + "Libs": [ + {"Type": "LibraryName", "Value": "system"} + ], + "Cflags": [ + {"Type": "IncludePath", "Value": "/usr/include"} + ] +} diff --git a/tests/auto/pkgconfig/testdata/system.pc b/tests/auto/pkgconfig/testdata/system.pc new file mode 100644 index 000000000..2cef2ed9b --- /dev/null +++ b/tests/auto/pkgconfig/testdata/system.pc @@ -0,0 +1,10 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: System library +Description: Test package +Version: 1.0.0 +Libs: -L${libdir} -lsystem +Cflags: -I${includedir} diff --git a/tests/auto/pkgconfig/testdata/tilde.json b/tests/auto/pkgconfig/testdata/tilde.json new file mode 100644 index 000000000..01ea5d050 --- /dev/null +++ b/tests/auto/pkgconfig/testdata/tilde.json @@ -0,0 +1,11 @@ +{ + "Name": "tilde", + "Description": "tilde test module", + "Version": "1.0", + "Libs": [ + {"Type": "LibraryPath", "Value": "~"} + ], + "Cflags": [ + {"Type": "IncludePath", "Value": "~"} + ] +} diff --git a/tests/auto/pkgconfig/testdata/tilde.pc b/tests/auto/pkgconfig/testdata/tilde.pc new file mode 100644 index 000000000..c3babc120 --- /dev/null +++ b/tests/auto/pkgconfig/testdata/tilde.pc @@ -0,0 +1,5 @@ +Name: tilde +Description: tilde test module +Version: 1.0 +Libs: -L~ +Cflags: -I~ diff --git a/tests/auto/pkgconfig/testdata/variables.json b/tests/auto/pkgconfig/testdata/variables.json new file mode 100644 index 000000000..7565b6804 --- /dev/null +++ b/tests/auto/pkgconfig/testdata/variables.json @@ -0,0 +1,17 @@ +{ + "Name": "Complex variables", + "Description": "Test complex variable output", + "Version": "1.0", + "Vars": { + "prefix": "/local", + "exec_prefix": "/local", + "libdir": "/local/lib", + "includedir": "\"/local/include\"", + "cppflags": "-I\"/local/include\"/foo -DFOO=\\\"/bar\\\"" + }, + "Cflags": [ + {"Type": "IncludePath", "Value": "/local/include"}, + {"Type": "IncludePath", "Value": "/local/include/foo"}, + {"Type": "Define", "Value": "FOO=\"/bar\""} + ] +} diff --git a/tests/auto/pkgconfig/testdata/variables.pc b/tests/auto/pkgconfig/testdata/variables.pc new file mode 100644 index 000000000..b27ab78e1 --- /dev/null +++ b/tests/auto/pkgconfig/testdata/variables.pc @@ -0,0 +1,11 @@ +prefix=/local +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir="${prefix}/include" +cppflags=-I${includedir}/foo \ + -DFOO=\"/bar\" + +Name: Complex variables +Description: Test complex variable output +Version: 1.0 +Cflags: -I${includedir} ${cppflags} diff --git a/tests/auto/pkgconfig/testdata/whitespace.json b/tests/auto/pkgconfig/testdata/whitespace.json new file mode 100644 index 000000000..dcfa3ece3 --- /dev/null +++ b/tests/auto/pkgconfig/testdata/whitespace.json @@ -0,0 +1,24 @@ +{ + "Name": "Whitespace test", + "Description": "Dummy pkgconfig test package for testing pkgconfig", + "Version": "1.0.0", + "Vars": { + "prefix": "/usr", + "exec_prefix": "/usr", + "libdir": "\"/usr/white space/lib\"", + "includedir": "\"/usr/white space/include\"" + }, + "Libs": [ + {"Type": "LibraryPath", "Value": "/usr/white space/lib"}, + {"Type": "LibraryName", "Value": "foo bar"}, + {"Type": "LibraryName", "Value": "bar baz"}, + {"Type": "LinkerFlag", "Value": "-r:foo"} + ], + "Cflags": [ + {"Type": "IncludePath", "Value": "/usr/white space/include"}, + {"Type": "IncludePath", "Value": "$(top_builddir)"}, + {"Type": "IncludePath", "Value": "include dir"}, + {"Type": "IncludePath", "Value": "other include dir"}, + {"Type": "Define", "Value": "lala=misc"} + ] +} diff --git a/tests/auto/pkgconfig/testdata/whitespace.pc b/tests/auto/pkgconfig/testdata/whitespace.pc new file mode 100644 index 000000000..693bbc4d0 --- /dev/null +++ b/tests/auto/pkgconfig/testdata/whitespace.pc @@ -0,0 +1,11 @@ +prefix=/usr +exec_prefix=${prefix} +libdir="${exec_prefix}/white space/lib" +includedir="${prefix}/white space/include" + +Name: Whitespace test +Description: Dummy pkgconfig test package for testing pkgconfig +Version: 1.0.0 +Requires: +Libs: -L${libdir} -lfoo\ bar "-lbar baz" -r:foo +Cflags: -I${includedir} -I$(top_builddir) -Iinclude\ dir "-Iother include dir" -Dlala=misc diff --git a/tests/auto/pkgconfig/tst_pkgconfig.cpp b/tests/auto/pkgconfig/tst_pkgconfig.cpp new file mode 100644 index 000000000..86d954259 --- /dev/null +++ b/tests/auto/pkgconfig/tst_pkgconfig.cpp @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tst_pkgconfig.h" + +#include "../shared.h" + +#include <tools/fileinfo.h> +#include <tools/hostosinfo.h> +#include <pkgconfig.h> +#include <pcparser.h> +#include <jsextensions/pkgconfigjs.h> + +#include <QJsonArray> +#include <QJsonDocument> + +using HostOsInfo = qbs::Internal::HostOsInfo; +using PcPackage = qbs::PcPackage; +using PkgConfig = qbs::PkgConfig; +using Options = qbs::PkgConfig::Options; + +TestPkgConfig::TestPkgConfig() + : m_sourceDataDir(testDataSourceDir(SRCDIR "/testdata")) + , m_workingDataDir(testWorkDir(QStringLiteral("pkgconfig"))) +{ +} + +void TestPkgConfig::initTestCase() +{ + QString errorMessage; + qbs::Internal::removeDirectoryWithContents(m_workingDataDir, &errorMessage); + QVERIFY2(qbs::Internal::copyFileRecursion(m_sourceDataDir, + m_workingDataDir, false, true, &errorMessage), + qPrintable(errorMessage)); +} + +void TestPkgConfig::fileName() +{ + QCOMPARE(qbs::Internal::fileName(""), ""); + QCOMPARE(qbs::Internal::fileName("file.txt"), "file.txt"); + QCOMPARE(qbs::Internal::fileName("/home/user/file.txt"), "file.txt"); + QCOMPARE(qbs::Internal::fileName("/"), ""); +#if defined(Q_OS_WIN) + QCOMPARE(qbs::Internal::fileName("c:file.txt"), "file.txt"); + QCOMPARE(qbs::Internal::fileName("c:"), ""); +#endif +} + +void TestPkgConfig::completeBaseName() +{ + QCOMPARE(qbs::Internal::completeBaseName(""), ""); + QCOMPARE(qbs::Internal::completeBaseName("file.txt"), "file"); + QCOMPARE(qbs::Internal::completeBaseName("archive.tar.gz"), "archive.tar"); + QCOMPARE(qbs::Internal::completeBaseName("/home/user/file.txt"), "file"); +#if defined(Q_OS_WIN) + QCOMPARE(qbs::Internal::completeBaseName("c:file.txt"), "file"); + QCOMPARE(qbs::Internal::completeBaseName("c:archive.tar.gz"), "archive.tar"); + QCOMPARE(qbs::Internal::completeBaseName("c:"), ""); +#endif +} + +void TestPkgConfig::parentPath() +{ + QCOMPARE(qbs::Internal::parentPath(""), ""); + QCOMPARE(qbs::Internal::parentPath("file.txt"), "."); + QCOMPARE(qbs::Internal::parentPath("/home/user/file.txt"), "/home/user"); + QCOMPARE(qbs::Internal::parentPath("/home/user/"), "/home/user"); + QCOMPARE(qbs::Internal::parentPath("/home"), "/"); + QCOMPARE(qbs::Internal::parentPath("/"), "/"); +#if defined(Q_OS_WIN) + QCOMPARE(qbs::Internal::parentPath("c:/folder/file.txt"), "c:/folder"); + QCOMPARE(qbs::Internal::parentPath("c:/folder/"), "c:/folder"); + QCOMPARE(qbs::Internal::parentPath("c:/folder"), "c:/"); + QCOMPARE(qbs::Internal::parentPath("c:/"), "c:/"); + QCOMPARE(qbs::Internal::parentPath("c:"), "c:"); +#endif +} + +void TestPkgConfig::pkgConfig() +{ + QFETCH(QString, pcFileName); + QFETCH(QString, jsonFileName); + QFETCH(QVariantMap, optionsMap); + + if (jsonFileName.isEmpty()) + jsonFileName = pcFileName; + + Options options = qbs::Internal::PkgConfigJs::convertOptions( + QProcessEnvironment::systemEnvironment(), optionsMap); + options.libDirs.push_back(m_workingDataDir.toStdString()); + + PkgConfig pkgConfig(std::move(options)); + + QFile jsonFile(m_workingDataDir + "/" + jsonFileName + ".json"); + QVERIFY(jsonFile.open(QIODevice::ReadOnly)); + QJsonParseError error{}; + const auto json = QJsonDocument::fromJson(jsonFile.readAll(), &error).toVariant().toMap(); + QCOMPARE(error.error, QJsonParseError::NoError); + + const auto &packageOr = pkgConfig.getPackage(pcFileName.toStdString()); + QVERIFY(packageOr.isValid()); + const auto &package = packageOr.asPackage(); + QCOMPARE(QString::fromStdString(package.baseFileName), pcFileName); + QCOMPARE(QString::fromStdString(package.name), json.value("Name").toString()); + QCOMPARE(QString::fromStdString(package.description), json.value("Description").toString()); + QCOMPARE(QString::fromStdString(package.version), json.value("Version").toString()); + + auto variables = json["Vars"].toMap(); + variables["pcfiledir"] = QFileInfo(m_workingDataDir).absoluteFilePath(); + + QCOMPARE(size_t(variables.size()), package.variables.size()); + for (const auto &[key, value]: package.variables) { + QCOMPARE(QString::fromStdString(value), + variables.value(QString::fromStdString(key)).toString()); + } + + const auto jsonLibs = json.value("Libs").toJsonArray().toVariantList(); + QCOMPARE(package.libs.size(), size_t(jsonLibs.size())); + for (size_t i = 0; i < package.libs.size(); ++i) { + const auto &item = package.libs[i]; + const auto jsonItem = jsonLibs.at(i).toMap(); + + QCOMPARE(item.type, + *PcPackage::Flag::typeFromString(jsonItem.value("Type").toString().toStdString())); + QCOMPARE(QString::fromStdString(item.value), jsonItem.value("Value").toString()); + } + + const auto jsonLibsPrivate = json.value("LibsPrivate").toJsonArray().toVariantList(); + QCOMPARE(package.libsPrivate.size(), size_t(jsonLibsPrivate.size())); + for (size_t i = 0; i < package.libsPrivate.size(); ++i) { + const auto &item = package.libsPrivate[i]; + const auto jsonItem = jsonLibsPrivate.at(i).toMap(); + + QCOMPARE(item.type, + *PcPackage::Flag::typeFromString(jsonItem.value("Type").toString().toStdString())); + QCOMPARE(QString::fromStdString(item.value), jsonItem.value("Value").toString()); + } + + const auto jsonCFlags = json.value("Cflags").toJsonArray().toVariantList(); + QCOMPARE(package.cflags.size(), size_t(jsonCFlags.size())); + for (size_t i = 0; i < package.cflags.size(); ++i) { + const auto &item = package.cflags[i]; + const auto jsonItem = jsonCFlags.at(i).toMap(); + + QCOMPARE(item.type, + *PcPackage::Flag::typeFromString(jsonItem.value("Type").toString().toStdString())); + QCOMPARE(QString::fromStdString(item.value), jsonItem.value("Value").toString()); + } + + for (const auto &item: package.requiresPublic) + qInfo() << "requires" << item.name.c_str() << item.version.c_str(); + + const auto jsonRequires = json.value("Requires").toJsonArray().toVariantList(); + QCOMPARE(package.requiresPublic.size(), size_t(jsonRequires.size())); + for (size_t i = 0; i < package.requiresPublic.size(); ++i) { + const auto &item = package.requiresPublic[i]; + const auto jsonItem = jsonRequires.at(i).toMap(); + + QCOMPARE(item.comparison, + *PcPackage::RequiredVersion::comparisonFromString( + jsonItem.value("Comparison").toString().toStdString())); + QCOMPARE(QString::fromStdString(item.name), jsonItem.value("Name").toString()); + QCOMPARE(QString::fromStdString(item.version), jsonItem.value("Version").toString()); + } + + const auto jsonRequiresPrivate = json.value("RequiresPrivate").toJsonArray().toVariantList(); + QCOMPARE(package.requiresPrivate.size(), size_t(jsonRequiresPrivate.size())); + for (size_t i = 0; i < package.requiresPrivate.size(); ++i) { + const auto &item = package.requiresPrivate[i]; + const auto jsonItem = jsonRequiresPrivate.at(i).toMap(); + + QCOMPARE(item.comparison, + *PcPackage::RequiredVersion::comparisonFromString( + jsonItem.value("Comparison").toString().toStdString())); + QCOMPARE(QString::fromStdString(item.name), jsonItem.value("Name").toString()); + QCOMPARE(QString::fromStdString(item.version), jsonItem.value("Version").toString()); + } +} + +void TestPkgConfig::pkgConfig_data() +{ + QTest::addColumn<QString>("pcFileName"); + QTest::addColumn<QString>("jsonFileName"); + QTest::addColumn<QVariantMap>("optionsMap"); + + QTest::newRow("empty-variable") + << QStringLiteral("empty-variable") << QString() << QVariantMap(); + QTest::newRow("non-l-required") + << QStringLiteral("non-l-required") << QString() << QVariantMap(); + QTest::newRow("simple") + << QStringLiteral("simple") << QString() << QVariantMap(); + QTest::newRow("requires-test") + << QStringLiteral("requires-test") << QString() << QVariantMap(); + QTest::newRow("special-flags") + << QStringLiteral("special-flags") << QString() << QVariantMap(); + QTest::newRow("system") + << QStringLiteral("system") << QString() << QVariantMap(); + QTest::newRow("sysroot") + << QStringLiteral("sysroot") << QString() << QVariantMap({{"sysroot", "/newroot"}}); + QTest::newRow("tilde") + << QStringLiteral("tilde") << QString() << QVariantMap(); + QTest::newRow("variables") + << QStringLiteral("variables") << QString() << QVariantMap(); + QTest::newRow("whitespace") + << QStringLiteral("whitespace") << QString() << QVariantMap(); + QTest::newRow("base.name") + << QStringLiteral("base.name") << QString() << QVariantMap(); +} + +void TestPkgConfig::benchSystem() +{ + if (HostOsInfo::hostOs() == HostOsInfo::HostOsWindows) + QSKIP("Not available on Windows"); + QBENCHMARK { + PkgConfig pkgConfig; + QVERIFY(!pkgConfig.packages().empty()); + } +} + +void TestPkgConfig::prefix() +{ + const auto prefixDir = m_workingDataDir; + const auto libDir = m_workingDataDir + "/lib"; + const auto includeDir = m_workingDataDir + "/include"; + const auto pkgconfigDir = libDir + "/pkgconfig"; + Options options = qbs::Internal::PkgConfigJs::convertOptions( + QProcessEnvironment::systemEnvironment(), {}); + options.definePrefix = true; + options.libDirs.push_back(pkgconfigDir.toStdString()); + PkgConfig pkgConfig(std::move(options)); + const auto &packageOr = pkgConfig.getPackage("prefix"); + QVERIFY(packageOr.isValid()); + const auto &package = packageOr.asPackage(); + QCOMPARE(package.variables.at("prefix"), prefixDir.toStdString()); + QCOMPARE(package.variables.at("exec_prefix"), prefixDir.toStdString()); + QCOMPARE(package.variables.at("libdir"), libDir.toStdString()); + QCOMPARE(package.variables.at("includedir"), includeDir.toStdString()); + QCOMPARE(package.variables.at("usrdir"), "/usrdir"); +} + +QTEST_MAIN(TestPkgConfig) diff --git a/tests/auto/pkgconfig/tst_pkgconfig.h b/tests/auto/pkgconfig/tst_pkgconfig.h new file mode 100644 index 000000000..47654e1ec --- /dev/null +++ b/tests/auto/pkgconfig/tst_pkgconfig.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBS_TST_API_H +#define QBS_TST_API_H + +#include <QtCore/qobject.h> +#include <QtCore/qvariant.h> + +class TestPkgConfig : public QObject +{ + Q_OBJECT + +public: + TestPkgConfig(); + +private slots: + void initTestCase(); + void fileName(); + void completeBaseName(); + void parentPath(); + void pkgConfig(); + void pkgConfig_data(); + void benchSystem(); + void prefix(); + +private: + const QString m_sourceDataDir; + const QString m_workingDataDir; +}; + +#endif // Include guard. diff --git a/tests/auto/shared.h b/tests/auto/shared.h index e251d506c..408594be0 100644 --- a/tests/auto/shared.h +++ b/tests/auto/shared.h @@ -31,6 +31,7 @@ #include <tools/hostosinfo.h> #include <tools/profile.h> #include <tools/settings.h> +#include <tools/toolchains.h> #include <QtCore/qbytearray.h> #include <QtCore/qcryptographichash.h> @@ -46,6 +47,8 @@ #include <memory> + + #define REPLACE_IN_FILE(filePath, oldContent, newContent) \ do { \ QFile f((filePath)); \ @@ -155,8 +158,11 @@ inline QByteArray diffText(const QByteArray &actual, const QByteArray &expected) n++; } auto addLines = [&result, &n] (const QList<QByteArray> &lines) { - for (const QByteArray &line : qAsConst(lines)) { - result += QStringLiteral("%1: %2\n").arg(n).arg(QString::fromUtf8(line)); + for (const QByteArray &line : std::as_const(lines)) { + result += QStringLiteral("%1: %2\n") + .arg(n) + .arg(QString::fromUtf8(line)) + .toUtf8(); n++; } }; @@ -268,14 +274,22 @@ inline void copyFileAndUpdateTimestamp(const QString &source, const QString &tar touch(target); } +inline QStringList profileToolchain(const qbs::Profile &profile) +{ + const auto toolchainType = profile.value(QStringLiteral("qbs.toolchainType")).toString(); + if (!toolchainType.isEmpty()) + return qbs::canonicalToolchain(toolchainType); + return profile.value(QStringLiteral("qbs.toolchain")).toStringList(); +} + inline QString objectFileName(const QString &baseName, const QString &profileName) { const SettingsPtr s = settings(); qbs::Profile profile(profileName, s.get()); - const auto tc = profile.value("qbs.toolchainType").toString(); - const auto tcList = profile.value("qbs.toolchain").toStringList(); - const bool isMsvc = tc == "msvc" || tcList.contains("msvc") - || (tc.isEmpty() && tcList.isEmpty() && qbs::Internal::HostOsInfo::isWindowsHost()); + + const auto tcList = profileToolchain(profile); + const bool isMsvc = tcList.contains("msvc") + || (tcList.isEmpty() && qbs::Internal::HostOsInfo::isWindowsHost()); const QString suffix = isMsvc ? "obj" : "o"; return baseName + '.' + suffix; } @@ -285,6 +299,30 @@ inline QString inputDirHash(const QString &dir) return QCryptographicHash::hash(dir.toLatin1(), QCryptographicHash::Sha1).toHex().left(16); } +inline QString testDataSourceDir(const QString &dir) +{ + QDir result; + QString testSourceRootDirFromEnv = QDir::fromNativeSeparators(qEnvironmentVariable("QBS_TEST_SOURCE_ROOT")); + if (testSourceRootDirFromEnv.isEmpty()) { + result.setPath(dir); + } else { + QDir testSourceRootDir(dir); + while (testSourceRootDir.dirName() != "tests") + testSourceRootDir = QFileInfo(testSourceRootDir, "").dir(); + + QString relativeDataPath = testSourceRootDir.relativeFilePath(dir); + QString absoluteDataPath = QDir(testSourceRootDirFromEnv).absoluteFilePath(relativeDataPath); + result.setPath(absoluteDataPath); + } + + if (!result.exists()) + qFatal("Expected data folder '%s' to be present, but it does not exist. You may set " + "QBS_TEST_SOURCE_ROOT to the 'tests' folder in your qbs repository to configure " + "a custom location.", qPrintable(result.absolutePath())); + + return result.absolutePath(); +} + inline QString testWorkDir(const QString &testName) { QString dir = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv("QBS_TEST_WORK_ROOT"))); @@ -294,12 +332,14 @@ inline QString testWorkDir(const QString &testName) if (!dir.endsWith(QLatin1Char('/'))) dir += QLatin1Char('/'); } - return dir + testName + "/testWorkDir"; + return QDir::cleanPath(dir + testName + "/testWorkDir"); } inline bool copyDllExportHeader(const QString &srcDataDir, const QString &targetDataDir) { QFile sourceFile(srcDataDir + "/../../dllexport.h"); + if (!sourceFile.exists()) + return true; const QString targetPath = targetDataDir + "/dllexport.h"; QFile::remove(targetPath); return sourceFile.copy(targetPath); @@ -311,8 +351,7 @@ inline qbs::Internal::HostOsInfo::HostOs targetOs() const qbs::Profile buildProfile(profileName(), s.get()); const QString targetPlatform = buildProfile.value("qbs.targetPlatform").toString(); if (!targetPlatform.isEmpty()) { - const std::vector<std::string> targetOS = qbs::Internal::HostOsInfo::canonicalOSIdentifiers( - targetPlatform.toStdString()); + const auto targetOS = qbs::Internal::HostOsInfo::canonicalOSIdentifiers(targetPlatform); if (qbs::Internal::contains(targetOS, "windows")) return qbs::Internal::HostOsInfo::HostOsWindows; if (qbs::Internal::contains(targetOS, "linux")) diff --git a/tests/auto/tools/CMakeLists.txt b/tests/auto/tools/CMakeLists.txt new file mode 100644 index 000000000..a75d998a3 --- /dev/null +++ b/tests/auto/tools/CMakeLists.txt @@ -0,0 +1,7 @@ +add_qbs_test(tools + DEFINES + "QBS_VERSION=\"${QBS_VERSION}\"" + SOURCES + tst_tools.cpp + tst_tools.h + ) diff --git a/tests/auto/tools/tools.pro b/tests/auto/tools/tools.pro deleted file mode 100644 index ba293f417..000000000 --- a/tests/auto/tools/tools.pro +++ /dev/null @@ -1,6 +0,0 @@ -TARGET = tst_tools - -SOURCES = tst_tools.cpp ../../../src/app/qbs/qbstool.cpp -HEADERS = tst_tools.h - -include(../auto.pri) diff --git a/tests/auto/tools/tools.qbs b/tests/auto/tools/tools.qbs index 64cced80e..781d6edae 100644 --- a/tests/auto/tools/tools.qbs +++ b/tests/auto/tools/tools.qbs @@ -1,7 +1,6 @@ -import qbs import qbs.Utilities -QbsAutotest { +QbsUnittest { Depends { name: "qbsversion" } testName: "tools" diff --git a/tests/auto/tools/tst_tools.cpp b/tests/auto/tools/tst_tools.cpp index edf5a1308..a872bdd0d 100644 --- a/tests/auto/tools/tst_tools.cpp +++ b/tests/auto/tools/tst_tools.cpp @@ -68,6 +68,16 @@ using namespace qbs; using namespace qbs::Internal; +namespace std { +template<typename T> struct hash<std::vector<T>> +{ + std::size_t operator()(const std::vector<T> &v) const noexcept + { + return hashRange(v); + } +}; +} // namespace std + TestTools::TestTools(Settings *settings) : m_settings(settings), testDataDir(testWorkDir("tools")) { @@ -298,10 +308,10 @@ void TestTools::testSettingsMigration() QFETCH(bool, hasOldSettings); Settings settings(baseDir); if (hasOldSettings) { - QVERIFY(QFileInfo(settings.baseDirectory() + "/qbs/" QBS_VERSION "/profiles/right.txt") + // checks that we do not copy old "profiles/" dir anymore + QVERIFY(!QFileInfo(settings.baseDirectory() + "/qbs/" QBS_VERSION "/profiles/right.txt") .exists()); - QCOMPARE(settings.value("key", Settings::UserScope).toString(), - settings.baseDirectory() + "/qbs/" QBS_VERSION "/profilesright"); + QVERIFY(!settings.value("key", Settings::UserScope).toString().isEmpty()); } else { QVERIFY(!QFileInfo(settings.baseDirectory() + "/qbs/" QBS_VERSION "/profiles").exists()); QVERIFY(settings.allKeys(Settings::UserScope).empty()); @@ -673,6 +683,30 @@ void TestTools::set_containsSet() QVERIFY(set3.contains(set4)); } +void TestTools::set_find() +{ + Set<QString> set1; + + for (int i = 0; i < 500; ++i) { + QVERIFY(set1.find(QString::number(i)) == set1.end()); + set1.insert(QString::number(i)); + const auto it = set1.find(QString::number(i)); + QVERIFY(it != set1.end()); + QVERIFY(*it == QString::number(i)); + } + + QCOMPARE(set1.size(), size_t { 500 }); + + for (int j = 0; j < 500; ++j) { + int i = (j * 17) % 500; + const auto it = set1.find(QString::number(i)); + QVERIFY(it != set1.end()); + QVERIFY(*it == QString::number(i)); + set1.remove(QString::number(i)); + QVERIFY(set1.find(QString::number(i)) == set1.end()); + } +} + void TestTools::set_begin() { Set<int> set1; @@ -1275,6 +1309,40 @@ void TestTools::stringutils_trimmed() QCOMPARE(trimmed(std::move(a)), std::string("a")); } +void TestTools::hash_tuple() +{ + using Key = std::tuple<int, int>; + + Key key0{0, 5}; + Key key1{10, 20}; + Key key2{30, 40}; + + std::unordered_map<Key, int> map; + map.insert({key1, 1}); + map.insert({key2, 2}); + + QCOMPARE(map[key0], 0); + QCOMPARE(map[key1], 1); + QCOMPARE(map[key2], 2); +} + +void TestTools::hash_range() +{ + using Key = std::vector<int>; + + Key key0; + Key key1{1}; + Key key2{1, 2}; + + std::unordered_map<Key, int> map; + map.insert({key1, 1}); + map.insert({key2, 2}); + + QCOMPARE(map[key0], 0); + QCOMPARE(map[key1], 1); + QCOMPARE(map[key2], 2); +} + int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); diff --git a/tests/auto/tools/tst_tools.h b/tests/auto/tools/tst_tools.h index bd8538be2..619174976 100644 --- a/tests/auto/tools/tst_tools.h +++ b/tests/auto/tools/tst_tools.h @@ -79,6 +79,7 @@ private slots: void set_remove(); void set_contains(); void set_containsSet(); + void set_find(); void set_begin(); void set_end(); void set_insert(); @@ -99,6 +100,9 @@ private slots: void stringutils_endsWith(); void stringutils_trimmed(); + void hash_tuple(); + void hash_range(); + private: QString setupSettingsDir1(); QString setupSettingsDir2(); |