diff --git a/autotest/cpp/test_gdal_algorithm.cpp b/autotest/cpp/test_gdal_algorithm.cpp index 31acac4b3c89..3ce37e480dc8 100644 --- a/autotest/cpp/test_gdal_algorithm.cpp +++ b/autotest/cpp/test_gdal_algorithm.cpp @@ -101,6 +101,170 @@ TEST_F(test_gdal_algorithm, GDALAlgorithmArgDecl_SetMaxCount) 2); } +class MyAlgorithmWithDummyRun : public GDALAlgorithm +{ + public: + MyAlgorithmWithDummyRun(const std::string &name = "test", + const std::string &description = "", + const std::string &url = "https://example.com") + : GDALAlgorithm(name, description, url) + { + } + + bool RunImpl(GDALProgressFunc, void *) override + { + return true; + } +}; + +TEST_F(test_gdal_algorithm, GDALAlgorithmArg_SetDefault) +{ + + class MyAlgorithm : public MyAlgorithmWithDummyRun + { + public: + MyAlgorithm() + { + { + bool v; + auto &arg = AddArg("", 0, "", &v); + arg.SetDefault(true); + EXPECT_TRUE(arg.GetDefault()); + + CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler); + CPLErrorReset(); + arg.SetDefault("invalid"); + EXPECT_EQ(CPLGetLastErrorType(), CE_Failure); + } + + { + int v; + auto &arg = AddArg("", 0, "", &v); + arg.SetDefault(5); + EXPECT_EQ(arg.GetDefault(), 5); + + CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler); + CPLErrorReset(); + arg.SetDefault("invalid"); + EXPECT_EQ(CPLGetLastErrorType(), CE_Failure); + } + + { + double v; + auto &arg = AddArg("", 0, "", &v); + arg.SetDefault(4.5); + EXPECT_EQ(arg.GetDefault(), 4.5); + + arg.SetDefault(5); + EXPECT_EQ(arg.GetDefault(), 5); + + arg.SetDefault(2.5f); + EXPECT_EQ(arg.GetDefault(), 2.5); + + CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler); + CPLErrorReset(); + arg.SetDefault("invalid"); + EXPECT_EQ(CPLGetLastErrorType(), CE_Failure); + } + + { + std::string v; + auto &arg = AddArg("", 0, "", &v); + + arg.SetDefault("ab"); + EXPECT_STREQ(arg.GetDefault().c_str(), "ab"); + + arg.SetDefault(std::string("cd")); + EXPECT_STREQ(arg.GetDefault().c_str(), "cd"); + + CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler); + CPLErrorReset(); + arg.SetDefault(0); + EXPECT_EQ(CPLGetLastErrorType(), CE_Failure); + } + + { + std::vector v; + auto &arg = AddArg("", 0, "", &v); + arg.SetDefault(5); + std::vector expected{5}; + EXPECT_EQ(arg.GetDefault>(), expected); + + CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler); + CPLErrorReset(); + arg.SetDefault("invalid"); + EXPECT_EQ(CPLGetLastErrorType(), CE_Failure); + } + + { + std::vector v; + auto &arg = AddArg("", 0, "", &v); + arg.SetDefault(4.5); + { + std::vector expected{4.5}; + EXPECT_EQ(arg.GetDefault>(), expected); + } + + arg.SetDefault(5); + { + std::vector expected{5}; + EXPECT_EQ(arg.GetDefault>(), expected); + } + + arg.SetDefault(2.5f); + { + std::vector expected{2.5}; + EXPECT_EQ(arg.GetDefault>(), expected); + } + + CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler); + CPLErrorReset(); + arg.SetDefault("invalid"); + EXPECT_EQ(CPLGetLastErrorType(), CE_Failure); + } + + { + std::vector v; + auto &arg = AddArg("", 0, "", &v); + + arg.SetDefault("ab"); + { + std::vector expected{"ab"}; + EXPECT_EQ(arg.GetDefault>(), + expected); + } + + CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler); + CPLErrorReset(); + arg.SetDefault(0); + EXPECT_EQ(CPLGetLastErrorType(), CE_Failure); + } + + { + GDALArgDatasetValue v; + auto &arg = AddArg("", 0, "", &v); + + CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler); + CPLErrorReset(); + arg.SetDefault(0); + EXPECT_EQ(CPLGetLastErrorType(), CE_Failure); + } + + { + std::vector v; + auto &arg = AddArg("", 0, "", &v); + + CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler); + CPLErrorReset(); + arg.SetDefault(0); + EXPECT_EQ(CPLGetLastErrorType(), CE_Failure); + } + } + }; + + MyAlgorithm alg; +} + TEST_F(test_gdal_algorithm, GDALAlgorithmArg_Set) { { @@ -783,22 +947,6 @@ TEST_F(test_gdal_algorithm, SetIsCRSArg_wrong_type) } } -class MyAlgorithmWithDummyRun : public GDALAlgorithm -{ - public: - MyAlgorithmWithDummyRun(const std::string &name = "test", - const std::string &description = "", - const std::string &url = "https://example.com") - : GDALAlgorithm(name, description, url) - { - } - - bool RunImpl(GDALProgressFunc, void *) override - { - return true; - } -}; - TEST_F(test_gdal_algorithm, wrong_long_name_dash) { class MyAlgorithm : public MyAlgorithmWithDummyRun diff --git a/gcore/gdalalgorithm.h b/gcore/gdalalgorithm.h index 3190cc5f4d1b..0e5afec90090 100644 --- a/gcore/gdalalgorithm.h +++ b/gcore/gdalalgorithm.h @@ -618,54 +618,104 @@ class CPL_DLL GDALAlgorithmArgDecl final template GDALAlgorithmArgDecl &SetDefault(const T &value) { m_hasDefaultValue = true; - if constexpr (std::is_same_v) - { - if (m_type == GAAT_STRING_LIST) - { - m_defaultValue = std::vector{value}; - return *this; - } - } - else if constexpr (std::is_same_v) - { - if (m_type == GAAT_REAL) - { - m_defaultValue = static_cast(value); - return *this; - } - else if (m_type == GAAT_INTEGER_LIST) - { - m_defaultValue = std::vector{value}; - return *this; - } - else if (m_type == GAAT_REAL_LIST) - { - m_defaultValue = - std::vector{static_cast(value)}; - return *this; - } - } - else if constexpr (std::is_same_v) + try { - if (m_type == GAAT_REAL_LIST) + switch (m_type) { - m_defaultValue = std::vector{value}; - return *this; + case GAAT_BOOLEAN: + { + if constexpr (std::is_same_v) + { + m_defaultValue = value; + return *this; + } + break; + } + + case GAAT_STRING: + { + if constexpr (std::is_same_v) + { + m_defaultValue = value; + return *this; + } + break; + } + + case GAAT_INTEGER: + { + if constexpr (std::is_same_v) + { + m_defaultValue = value; + return *this; + } + break; + } + + case GAAT_REAL: + { + if constexpr (std::is_assignable_v) + { + m_defaultValue = static_cast(value); + return *this; + } + break; + } + + case GAAT_STRING_LIST: + { + if constexpr (std::is_same_v) + { + m_defaultValue = std::vector{value}; + return *this; + } + break; + } + + case GAAT_INTEGER_LIST: + { + if constexpr (std::is_same_v) + { + m_defaultValue = std::vector{value}; + return *this; + } + break; + } + + case GAAT_REAL_LIST: + { + if constexpr (std::is_assignable_v) + { + m_defaultValue = + std::vector{static_cast(value)}; + return *this; + } + break; + } + + case GAAT_DATASET: + case GAAT_DATASET_LIST: + break; } } - try - { - m_defaultValue = value; - } catch (const std::bad_variant_access &) { - CPLError(CE_Failure, CPLE_AppDefined, - "Argument %s: SetDefault(): unexpected type for value", - GetName().c_str()); + // should not happen + // fallthrough } + CPLError(CE_Failure, CPLE_AppDefined, + "Argument %s: SetDefault(): unexpected type for value", + GetName().c_str()); return *this; } + /** Declare a default value for the argument. + */ + GDALAlgorithmArgDecl &SetDefault(const char *value) + { + return SetDefault(std::string(value)); + } + /** Declare the minimum number of values for the argument. Defaults to 0. * Only applies to list type of arguments. * Setting it to non-zero does *not* make the argument required. It just @@ -1835,36 +1885,47 @@ class CPL_DLL GDALInConstructionAlgorithmArg final : public GDALAlgorithmArg if constexpr (!std::is_same_v && !std::is_same_v>) { - switch (m_decl.GetType()) + try { - case GAAT_BOOLEAN: - *std::get(m_value) = m_decl.GetDefault(); - break; - case GAAT_STRING: - *std::get(m_value) = - m_decl.GetDefault(); - break; - case GAAT_INTEGER: - *std::get(m_value) = m_decl.GetDefault(); - break; - case GAAT_REAL: - *std::get(m_value) = m_decl.GetDefault(); - break; - case GAAT_STRING_LIST: - *std::get *>(m_value) = - m_decl.GetDefault>(); - break; - case GAAT_INTEGER_LIST: - *std::get *>(m_value) = - m_decl.GetDefault>(); - break; - case GAAT_REAL_LIST: - *std::get *>(m_value) = - m_decl.GetDefault>(); - break; - case GAAT_DATASET: - case GAAT_DATASET_LIST: - break; + switch (m_decl.GetType()) + { + case GAAT_BOOLEAN: + *std::get(m_value) = m_decl.GetDefault(); + break; + case GAAT_STRING: + *std::get(m_value) = + m_decl.GetDefault(); + break; + case GAAT_INTEGER: + *std::get(m_value) = m_decl.GetDefault(); + break; + case GAAT_REAL: + *std::get(m_value) = + m_decl.GetDefault(); + break; + case GAAT_STRING_LIST: + *std::get *>(m_value) = + m_decl.GetDefault>(); + break; + case GAAT_INTEGER_LIST: + *std::get *>(m_value) = + m_decl.GetDefault>(); + break; + case GAAT_REAL_LIST: + *std::get *>(m_value) = + m_decl.GetDefault>(); + break; + case GAAT_DATASET: + case GAAT_DATASET_LIST: + break; + } + } + catch (const std::bad_variant_access &) + { + // I don't think that can happen, but Coverity Scan thinks so + CPLError(CE_Failure, CPLE_AppDefined, + "Argument %s: SetDefault(): unexpected type for value", + GetName().c_str()); } } return *this;