diff --git a/test/helpers/test_helpers.cpp b/test/helpers/test_helpers.cpp index d9e5c552c73..aa0ac316a8a 100644 --- a/test/helpers/test_helpers.cpp +++ b/test/helpers/test_helpers.cpp @@ -9,6 +9,7 @@ #include "duckdb/parser/parsed_data/copy_info.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/execution/operator/csv_scanner/scanner/string_value_scanner.hpp" +#include "duckdb/common/case_insensitive_map.hpp" #include "pid.hpp" #include "duckdb/function/table/read_csv.hpp" @@ -23,6 +24,7 @@ namespace duckdb { static string custom_test_directory; static int debug_initialize_value = -1; static bool single_threaded = false; +static case_insensitive_set_t required_requires; bool NO_FAIL(QueryResult &result) { if (result.HasError()) { @@ -89,6 +91,14 @@ void SetSingleThreaded() { single_threaded = true; } +void AddRequire(string require) { + required_requires.insert(require); +} + +bool IsRequired(string require) { + return required_requires.count(require); +} + string GetTestDirectory() { if (custom_test_directory.empty()) { return TESTING_DIRECTORY_NAME; diff --git a/test/include/test_helpers.hpp b/test/include/test_helpers.hpp index 26e12a08356..01346b362f6 100644 --- a/test/include/test_helpers.hpp +++ b/test/include/test_helpers.hpp @@ -45,6 +45,8 @@ bool TestIsInternalError(unordered_set &internal_error_messages, const s void SetTestDirectory(string path); void SetDebugInitialize(int value); void SetSingleThreaded(); +void AddRequire(string require); +bool IsRequired(string require); string GetTestDirectory(); string GetCSVPath(); void WriteCSV(string path, const char *csv); diff --git a/test/sqlite/sqllogic_test_runner.cpp b/test/sqlite/sqllogic_test_runner.cpp index 2dc791c5e83..76f44e32aed 100644 --- a/test/sqlite/sqllogic_test_runner.cpp +++ b/test/sqlite/sqllogic_test_runner.cpp @@ -206,6 +206,168 @@ bool SQLLogicTestRunner::ForEachTokenReplace(const string ¶meter, vector ¶ms) { + if (params.size() < 1) { + parser.Fail("require requires a single parameter"); + } + // require command + string param = StringUtil::Lower(params[0]); + // os specific stuff + if (param == "notmingw") { +#ifdef __MINGW32__ + return RequireResult::MISSING; +#else + return RequireResult::PRESENT; +#endif + } + + if (param == "mingw") { +#ifndef __MINGW32__ + return RequireResult::MISSING; +#else + return RequireResult::PRESENT; +#endif + } + + if (param == "notwindows") { +#ifdef _WIN32 + return RequireResult::MISSING; +#else + return RequireResult::PRESENT; +#endif + } + + if (param == "windows") { +#ifndef _WIN32 + return RequireResult::MISSING; +#else + return RequireResult::PRESENT; +#endif + } + + if (param == "longdouble") { +#if LDBL_MANT_DIG < 54 + return RequireResult::MISSING; +#else + return RequireResult::PRESENT; +#endif + } + + if (param == "64bit") { + if (sizeof(void *) != 8) { + return RequireResult::MISSING; + } + return RequireResult::PRESENT; + } + + if (param == "noforcestorage") { + if (TestForceStorage()) { + return RequireResult::MISSING; + } + return RequireResult::PRESENT; + } + + if (param == "nothreadsan") { +#ifdef DUCKDB_THREAD_SANITIZER + return RequireResult::MISSING; +#else + return RequireResult::PRESENT; +#endif + } + + if (param == "strinline") { +#ifdef DUCKDB_DEBUG_NO_INLINE + return RequireResult::MISSING; +#else + return RequireResult::PRESENT; +#endif + } + + if (param == "vector_size") { + if (params.size() != 2) { + parser.Fail("require vector_size requires a parameter"); + } + // require a specific vector size + auto required_vector_size = std::stoi(params[1]); + if (STANDARD_VECTOR_SIZE < required_vector_size) { + // vector size is too low for this test: skip it + return RequireResult::MISSING; + } + return RequireResult::PRESENT; + } + + if (param == "exact_vector_size") { + if (params.size() != 2) { + parser.Fail("require exact_vector_size requires a parameter"); + } + // require an exact vector size + auto required_vector_size = std::stoi(params[1]); + if (STANDARD_VECTOR_SIZE != required_vector_size) { + // vector size does not match the required vector size: skip it + return RequireResult::MISSING; + } + return RequireResult::PRESENT; + } + + if (param == "block_size") { + if (params.size() != 2) { + parser.Fail("require block_size requires a parameter"); + } + // require a specific block size + auto required_block_size = std::stoi(params[1]); + if (Storage::BLOCK_ALLOC_SIZE != required_block_size) { + // block size does not match the required block size: skip it + return RequireResult::MISSING; + } + return RequireResult::PRESENT; + } + + if (param == "skip_reload") { + skip_reload = true; + return RequireResult::PRESENT; + } + + if (param == "noalternativeverify") { +#ifdef DUCKDB_ALTERNATIVE_VERIFY + return RequireResult::MISSING; +#else + return RequireResult::PRESENT; +#endif + } + + if (param == "no_extension_autoloading") { + if (config->options.autoload_known_extensions) { + // If autoloading is on, we skip this test + return RequireResult::MISSING; + } + return RequireResult::PRESENT; + } + + bool excluded_from_autoloading = true; + for (const auto &ext : AUTOLOADABLE_EXTENSIONS) { + if (ext == param) { + excluded_from_autoloading = false; + break; + } + } + + if (!config->options.autoload_known_extensions) { + auto result = ExtensionHelper::LoadExtension(*db, param); + if (result == ExtensionLoadResult::LOADED_EXTENSION) { + // add the extension to the list of loaded extensions + extensions.insert(param); + } else if (result == ExtensionLoadResult::EXTENSION_UNKNOWN) { + parser.Fail("unknown extension type: %s", params[0]); + } else if (result == ExtensionLoadResult::NOT_LOADED) { + // extension known but not build: skip this test + return RequireResult::MISSING; + } + } else if (excluded_from_autoloading) { + return RequireResult::MISSING; + } + return RequireResult::PRESENT; +} + void SQLLogicTestRunner::ExecuteFile(string script) { SQLLogicParser parser; idx_t skip_level = 0; @@ -473,111 +635,14 @@ void SQLLogicTestRunner::ExecuteFile(string script) { } else if (token.type == SQLLogicTokenType::SQLLOGIC_ENDLOOP) { EndLoop(); } else if (token.type == SQLLogicTokenType::SQLLOGIC_REQUIRE) { - if (token.parameters.size() < 1) { - parser.Fail("require requires a single parameter"); - } - // require command - string param = StringUtil::Lower(token.parameters[0]); - // os specific stuff - if (param == "notmingw") { -#ifdef __MINGW32__ - return; -#endif - } else if (param == "mingw") { -#ifndef __MINGW32__ - return; -#endif - } else if (param == "notwindows") { -#ifdef _WIN32 - return; -#endif - } else if (param == "windows") { -#ifndef _WIN32 - return; -#endif - } else if (param == "longdouble") { -#if LDBL_MANT_DIG < 54 - return; -#endif - } else if (param == "64bit") { - if (sizeof(void *) != 8) { - return; + auto require_result = CheckRequire(parser, token.parameters); + if (require_result == RequireResult::MISSING) { + auto ¶m = token.parameters[0]; + if (IsRequired(param)) { + // This extension / setting was explicitly required + parser.Fail(StringUtil::Format("require %s: FAILED", param)); } - } else if (param == "noforcestorage") { - if (TestForceStorage()) { - return; - } - } else if (param == "nothreadsan") { -#ifdef DUCKDB_THREAD_SANITIZER return; -#endif - } else if (param == "strinline") { -#ifdef DUCKDB_DEBUG_NO_INLINE - return; -#endif - } else if (param == "vector_size") { - if (token.parameters.size() != 2) { - parser.Fail("require vector_size requires a parameter"); - } - // require a specific vector size - auto required_vector_size = std::stoi(token.parameters[1]); - if (STANDARD_VECTOR_SIZE < required_vector_size) { - // vector size is too low for this test: skip it - return; - } - } else if (param == "exact_vector_size") { - if (token.parameters.size() != 2) { - parser.Fail("require exact_vector_size requires a parameter"); - } - // require an exact vector size - auto required_vector_size = std::stoi(token.parameters[1]); - if (STANDARD_VECTOR_SIZE != required_vector_size) { - // vector size does not match the required vector size: skip it - return; - } - } else if (param == "block_size") { - if (token.parameters.size() != 2) { - parser.Fail("require block_size requires a parameter"); - } - // require a specific block size - auto required_block_size = std::stoi(token.parameters[1]); - if (Storage::BLOCK_ALLOC_SIZE != required_block_size) { - // block size does not match the required block size: skip it - return; - } - } else if (param == "skip_reload") { - skip_reload = true; - } else if (param == "noalternativeverify") { -#ifdef DUCKDB_ALTERNATIVE_VERIFY - return; -#endif - } else if (param == "no_extension_autoloading") { - if (config->options.autoload_known_extensions) { - return; - } - } else { - bool excluded_from_autoloading = true; - for (const auto &ext : AUTOLOADABLE_EXTENSIONS) { - if (ext == param) { - excluded_from_autoloading = false; - break; - } - } - - if (!config->options.autoload_known_extensions) { - auto result = ExtensionHelper::LoadExtension(*db, param); - if (result == ExtensionLoadResult::LOADED_EXTENSION) { - // add the extension to the list of loaded extensions - extensions.insert(param); - } else if (result == ExtensionLoadResult::EXTENSION_UNKNOWN) { - parser.Fail("unknown extension type: %s", token.parameters[0]); - } else if (result == ExtensionLoadResult::NOT_LOADED) { - // extension known but not build: skip this test - return; - } - } else if (excluded_from_autoloading) { - return; - } } } else if (token.type == SQLLogicTokenType::SQLLOGIC_REQUIRE_ENV) { if (InLoop()) { diff --git a/test/sqlite/sqllogic_test_runner.hpp b/test/sqlite/sqllogic_test_runner.hpp index cde5a4bbd8b..dfeb1cc2578 100644 --- a/test/sqlite/sqllogic_test_runner.hpp +++ b/test/sqlite/sqllogic_test_runner.hpp @@ -16,6 +16,9 @@ namespace duckdb { class Command; class LoopCommand; +class SQLLogicParser; + +enum class RequireResult { PRESENT, MISSING }; class SQLLogicTestRunner { public: @@ -68,6 +71,9 @@ class SQLLogicTestRunner { static string ReplaceLoopIterator(string text, string loop_iterator_name, string replacement); static string LoopReplacement(string text, const vector &loops); static bool ForEachTokenReplace(const string ¶meter, vector &result); + +private: + RequireResult CheckRequire(SQLLogicParser &parser, const vector ¶ms); }; } // namespace duckdb diff --git a/test/unittest.cpp b/test/unittest.cpp index 7cf8d208969..2350e7baf8e 100644 --- a/test/unittest.cpp +++ b/test/unittest.cpp @@ -52,6 +52,8 @@ int main(int argc, char *argv[]) { return 1; } SetTestDirectory(test_dir); + } else if (string(argv[i]) == "--require") { + AddRequire(string(argv[++i])); } else if (string(argv[i]) == "--zero-initialize") { SetDebugInitialize(0); } else if (string(argv[i]) == "--one-initialize") {