test: basically finish clap test.
- basically finish clap test (except variable part) - fix some clap issue (still have some bugs)
This commit is contained in:
@ -41,7 +41,7 @@ PRIVATE
|
||||
yycc/carton/binstore/types.cpp
|
||||
yycc/carton/binstore/setting.cpp
|
||||
yycc/carton/binstore/configuration.cpp
|
||||
yycc/carton/binstore/storage.cpp
|
||||
#yycc/carton/binstore/storage.cpp
|
||||
)
|
||||
target_sources(YYCCommonplace
|
||||
PUBLIC
|
||||
@ -110,7 +110,7 @@ FILES
|
||||
yycc/carton/binstore/serializer.hpp
|
||||
yycc/carton/binstore/setting.hpp
|
||||
yycc/carton/binstore/configuration.hpp
|
||||
yycc/carton/binstore/storage.hpp
|
||||
#yycc/carton/binstore/storage.hpp
|
||||
yycc/carton/fft.hpp
|
||||
)
|
||||
# Setup header infomations
|
||||
|
||||
@ -84,8 +84,9 @@ namespace yycc::carton::binstore::serializer {
|
||||
struct FloatingPointSerDes {
|
||||
YYCC_DEFAULT_COPY_MOVE(FloatingPointSerDes)
|
||||
|
||||
static_assert(std::isfinite(TMin));
|
||||
static_assert(std::isfinite(TMax));
|
||||
// TODO: Use static_assert once 3 common STL make this become constexpr.
|
||||
//static_assert(std::isfinite(TMin));
|
||||
//static_assert(std::isfinite(TMax));
|
||||
static_assert(TMin <= TMax);
|
||||
static_assert(TDefault >= TMin && TDefault <= TMax);
|
||||
|
||||
|
||||
@ -11,15 +11,37 @@
|
||||
#include <ostream>
|
||||
|
||||
#define NS_YYCC_BINSTORE_TYPES ::yycc::carton::binstore::types
|
||||
#define NS_YYCC_BINSTORE_SERIALIZER ::yycc::carton::binstore::serializer
|
||||
#define NS_YYCC_BINSTORE_CFG ::yycc::carton::binstore::configuration
|
||||
#define NS_YYCC_BINSTORE_SERDES ::yycc::carton::binstore::serializer
|
||||
|
||||
namespace yycc::carton::binstore::storage {
|
||||
|
||||
/// @brief The strategy when loading from storage.
|
||||
enum class LoadStrategy {
|
||||
OnlyCurrent, ///< Only the file with exactly matched version identifier can be loaded. Any other version will cause load error.
|
||||
LegacyAndCurrent, ///< Accept all old version and current version. Any other version will cause load error.
|
||||
AcceptAll, ///< Accept all versions.
|
||||
/**
|
||||
* @brief Only accept matched version.
|
||||
* @details
|
||||
* Any loading of other versions will explicitly cause error return.
|
||||
* This is convenient for developer who want control migration by themselves.
|
||||
* They can specify this strategy and try to load data with different version configurations
|
||||
* from older to newer one by one.
|
||||
*/
|
||||
OnlyCurrent,
|
||||
/**
|
||||
* @brief Try to migrate old version.
|
||||
* @details
|
||||
* Accept mateched and any older versions.
|
||||
* Any newer versions will explicitly cause error return.
|
||||
* This strategy is good for developer who are lazy to treat this manually.
|
||||
*/
|
||||
MigrateOld,
|
||||
/**
|
||||
* @brief Accept all version.
|
||||
* @details
|
||||
* This strategy is not suggested.
|
||||
* This strategy only suit for quick demo.
|
||||
*/
|
||||
AcceptAll,
|
||||
};
|
||||
|
||||
/// @brief The operation result state when getting setting's value.
|
||||
@ -38,11 +60,12 @@ namespace yycc::carton::binstore::storage {
|
||||
class Storage {
|
||||
private:
|
||||
/**
|
||||
* @brief All stored settings in raw format.
|
||||
* @brief All stored values of setting in raw format.
|
||||
* @details Key is the token to already registered settings.
|
||||
* Valus is its stored value in raw data format.
|
||||
*/
|
||||
std::map<NS_YYCC_BINSTORE_TYPES::Token, NS_YYCC_BINSTORE_TYPES::ByteArray> raws;
|
||||
NS_YYCC_BINSTORE_CFG::Configuration configuration; ///< The configuration associated with this storage.
|
||||
|
||||
public:
|
||||
Storage();
|
||||
@ -50,38 +73,78 @@ namespace yycc::carton::binstore::storage {
|
||||
|
||||
public:
|
||||
NS_YYCC_BINSTORE_TYPES::BinstoreResult<void> load_from_file(const std::filesystem::path& fpath, LoadStrategy strategy);
|
||||
NS_YYCC_BINSTORE_TYPES::BinstoreResult<void> load_from_io(const std::istream& s, LoadStrategy strategy);
|
||||
NS_YYCC_BINSTORE_TYPES::BinstoreResult<void> load_from_io(std::istream& s, LoadStrategy strategy);
|
||||
NS_YYCC_BINSTORE_TYPES::BinstoreResult<void> save_into_file(const std::filesystem::path& fpath);
|
||||
NS_YYCC_BINSTORE_TYPES::BinstoreResult<void> save_into_io(const std::ostream& s);
|
||||
NS_YYCC_BINSTORE_TYPES::BinstoreResult<void> save_into_io(std::ostream& s);
|
||||
/**
|
||||
* @brief Reset all values of setting to their default value.
|
||||
* @details Please note that all stored value will be wiped before assign them with default value.65
|
||||
*/
|
||||
void reset();
|
||||
|
||||
private:
|
||||
bool has_value(NS_YYCC_BINSTORE_TYPES::Token token) const;
|
||||
std::optional<NS_YYCC_BINSTORE_TYPES::ByteArray> get_raw_value(NS_YYCC_BINSTORE_TYPES::Token token) const;
|
||||
const NS_YYCC_BINSTORE_TYPES::ByteArray& get_raw_value(NS_YYCC_BINSTORE_TYPES::Token token) const;
|
||||
void set_raw_value(NS_YYCC_BINSTORE_TYPES::Token token, NS_YYCC_BINSTORE_TYPES::ByteArray&& ba);
|
||||
|
||||
public:
|
||||
template<NS_YYCC_BINSTORE_SERIALIZER::SerDes T>
|
||||
NS_YYCC_BINSTORE_TYPES::BinstoreResult<std::pair<GetValueState, NS_YYCC_BINSTORE_SERIALIZER::SerDesValueType<T>>> get_value(
|
||||
template<NS_YYCC_BINSTORE_SERDES::SerDes T>
|
||||
NS_YYCC_BINSTORE_TYPES::BinstoreResult<std::pair<GetValueState, NS_YYCC_BINSTORE_SERDES::SerDesValueType<T>>> get_value(
|
||||
NS_YYCC_BINSTORE_TYPES::Token token, const T& serdes = T()) {
|
||||
// Fetch from raw value.
|
||||
auto rv_raw_value = this->get_raw_value(token);
|
||||
if (!rv_raw_value.has_value()) return std::unexpected(rv_raw_value.error());
|
||||
auto& [state, raw_value] = rv_raw_value.value();
|
||||
// If we have value, we fetch it first
|
||||
if (this->has_value(token)) {
|
||||
// Get raw value.
|
||||
const auto& ba = this->get_raw_value(token);
|
||||
// Try to deserialize it.
|
||||
auto value = serdes.deserialize(raw_value);
|
||||
// If the result is okey, return it.
|
||||
if (value.has_value()) {
|
||||
return std::make_pair(GetValueState::Ok, std::move(value.value()));
|
||||
}
|
||||
// Otherwise we need reset it into default value.
|
||||
}
|
||||
|
||||
// Pass into deserializer.
|
||||
auto rv_des = serdes.deserialize(raw_value);
|
||||
if (rv_des.has_value()) return rv_des.value();
|
||||
|
||||
// If we can not set it, we force reset it and try again.
|
||||
this->set_raw_value()
|
||||
// If we do not have this setting,
|
||||
// or we need reset it into default value,
|
||||
// we need execute following code.
|
||||
// First decide the return state.
|
||||
GetValueState state = this->has_value(token) ? GetValueState::Reset : GetValueState::Default;
|
||||
{
|
||||
// Fetch the default raw data.
|
||||
auto ba = serdes.reset();
|
||||
// Set it for this setting.
|
||||
this->set_raw_value(token, std::move(ba));
|
||||
}
|
||||
// The get it and deserialize it.
|
||||
const auto& ba = this->get_raw_value(token);
|
||||
auto value = serdes.deserialize(ba);
|
||||
// Default must can be deserialized.
|
||||
// If not, throw exception.
|
||||
if (value.has_value()) {
|
||||
return std::make_pair(state, std::move(value));
|
||||
} else {
|
||||
throw std::logic_error("default value can not be deserialized");
|
||||
}
|
||||
}
|
||||
template<NS_YYCC_BINSTORE_SERIALIZER::SerDes T>
|
||||
template<NS_YYCC_BINSTORE_SERDES::SerDes T>
|
||||
NS_YYCC_BINSTORE_TYPES::BinstoreResult<SetValueState> set_value(NS_YYCC_BINSTORE_TYPES::Token token,
|
||||
const NS_YYCC_BINSTORE_SERIALIZER::SerDesValueType<T>& value,
|
||||
const NS_YYCC_BINSTORE_SERDES::SerDesValueType<T>& value,
|
||||
const T& serdes = T()) {
|
||||
|
||||
// First we try assign it.
|
||||
{
|
||||
// Convert it into raw format.
|
||||
auto ba = serdes.serialize(value);
|
||||
// If we can not serialize it, we need reset it into default value.
|
||||
// Otherwise assign it and return.
|
||||
if (ba.has_value()) {
|
||||
this->set_raw_value(token, )
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace yycc::carton::binstore::storage
|
||||
|
||||
#undef NS_YYCC_BINSTORE_SERDES
|
||||
#undef NS_YYCC_BINSTORE_CFG
|
||||
#undef NS_YYCC_BINSTORE_TYPES
|
||||
|
||||
@ -45,8 +45,8 @@ namespace yycc::carton::clap::parser {
|
||||
bool has_option(NS_YYCC_CLAP_TYPES::Token token) const;
|
||||
NS_YYCC_CLAP_TYPES::ClapResult<bool> get_flag_option(NS_YYCC_CLAP_TYPES::Token token) const;
|
||||
template<NS_YYCC_CLAP_VALIDATOR::Validator T>
|
||||
NS_YYCC_CLAP_TYPES::ClapResult<NS_YYCC_CLAP_VALIDATOR::ValidatorReturnType<T>> get_value_option(
|
||||
NS_YYCC_CLAP_TYPES::Token token, const T& validator = T()) const {
|
||||
NS_YYCC_CLAP_TYPES::ClapResult<NS_YYCC_CLAP_VALIDATOR::ValidatorReturnType<T>> get_value_option(NS_YYCC_CLAP_TYPES::Token token,
|
||||
const T& validator = T()) const {
|
||||
auto raw_value = this->get_raw_value_option(token);
|
||||
if (raw_value.has_value()) {
|
||||
auto value = validator.validate(raw_value.value());
|
||||
|
||||
@ -47,7 +47,7 @@ namespace yycc::carton::clap::validator {
|
||||
static_assert(TMin <= TMax);
|
||||
|
||||
using ReturnType = T;
|
||||
std::optional<ReturnType> validate(const std::u8string_view& sv) {
|
||||
std::optional<ReturnType> validate(const std::u8string_view& sv) const {
|
||||
auto rv = NS_YYCC_NUM_PARSE::parse<ReturnType>(sv);
|
||||
if (rv) {
|
||||
auto value = rv.value();
|
||||
@ -61,12 +61,13 @@ namespace yycc::carton::clap::validator {
|
||||
struct FloatingPointValidator {
|
||||
YYCC_DEFAULT_COPY_MOVE(FloatingPointValidator)
|
||||
|
||||
static_assert(std::isfinite(TMin));
|
||||
static_assert(std::isfinite(TMax));
|
||||
// TODO: Use static_assert once 3 common STL make this become constexpr.
|
||||
//static_assert(std::isfinite<T>(TMin));
|
||||
//static_assert(std::isfinite<T>(TMax));
|
||||
static_assert(TMin <= TMax);
|
||||
|
||||
using ReturnType = T;
|
||||
std::optional<ReturnType> validate(const std::u8string_view& sv) {
|
||||
std::optional<ReturnType> validate(const std::u8string_view& sv) const {
|
||||
auto rv = NS_YYCC_NUM_PARSE::parse<ReturnType>(sv);
|
||||
if (rv) {
|
||||
auto value = rv.value();
|
||||
@ -80,7 +81,7 @@ namespace yycc::carton::clap::validator {
|
||||
YYCC_DEFAULT_COPY_MOVE(BoolValidator)
|
||||
|
||||
using ReturnType = bool;
|
||||
std::optional<ReturnType> validate(const std::u8string_view& sv) {
|
||||
std::optional<ReturnType> validate(const std::u8string_view& sv) const {
|
||||
auto rv = NS_YYCC_NUM_PARSE::parse<ReturnType>(sv);
|
||||
if (rv) return rv.value();
|
||||
else return std::nullopt;
|
||||
@ -91,7 +92,7 @@ namespace yycc::carton::clap::validator {
|
||||
YYCC_DEFAULT_COPY_MOVE(StringValidator)
|
||||
|
||||
using ReturnType = std::u8string;
|
||||
std::optional<ReturnType> validate(const std::u8string_view& sv) { return std::u8string(sv); }
|
||||
std::optional<ReturnType> validate(const std::u8string_view& sv) const { return std::u8string(sv); }
|
||||
};
|
||||
|
||||
} // namespace yycc::carton::clap::validator
|
||||
|
||||
@ -41,6 +41,7 @@ PRIVATE
|
||||
yycc/carton/wcwidth.cpp
|
||||
yycc/carton/tabulate.cpp
|
||||
yycc/carton/clap.cpp
|
||||
yycc/carton/binstore.cpp
|
||||
yycc/carton/fft.cpp
|
||||
)
|
||||
target_sources(YYCCTest
|
||||
|
||||
0
test/yycc/carton/binstore.cpp
Normal file
0
test/yycc/carton/binstore.cpp
Normal file
@ -0,0 +1,271 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <yycc.hpp>
|
||||
#include <yycc/carton/clap.hpp>
|
||||
#include <yycc/prelude.hpp>
|
||||
|
||||
#define CLAP ::yycc::carton::clap
|
||||
|
||||
namespace yycctest::carton::clap {
|
||||
|
||||
using Token = CLAP::types::Token;
|
||||
namespace validator = CLAP::validator;
|
||||
|
||||
TEST(CartonClap, BadOption) {
|
||||
// No short name and long name.
|
||||
EXPECT_ANY_THROW(auto opt = CLAP::option::Option(std::nullopt, std::nullopt, std::nullopt, u8""));
|
||||
// Empty short name or long name.
|
||||
EXPECT_ANY_THROW(auto opt = CLAP::option::Option(u8"", std::nullopt, std::nullopt, u8""));
|
||||
EXPECT_ANY_THROW(auto opt = CLAP::option::Option(std::nullopt, u8"", std::nullopt, u8""));
|
||||
// Bad short name
|
||||
EXPECT_ANY_THROW(auto opt = CLAP::option::Option(u8"fuck", std::nullopt, std::nullopt, u8""));
|
||||
EXPECT_ANY_THROW(auto opt = CLAP::option::Option(u8"-", std::nullopt, std::nullopt, u8""));
|
||||
}
|
||||
|
||||
TEST(CartonClap, BadOptions) {
|
||||
// Duplicated.
|
||||
{
|
||||
auto options = CLAP::option::OptionCollection();
|
||||
options.add_option(CLAP::option::Option(u8"a", std::nullopt, std::nullopt, u8""));
|
||||
EXPECT_ANY_THROW(options.add_option(CLAP::option::Option(u8"a", std::nullopt, std::nullopt, u8"")));
|
||||
}
|
||||
// Duplicate between long name and short name.
|
||||
{
|
||||
auto options = CLAP::option::OptionCollection();
|
||||
options.add_option(CLAP::option::Option(u8"a", std::nullopt, std::nullopt, u8""));
|
||||
EXPECT_ANY_THROW(options.add_option(CLAP::option::Option(std::nullopt, u8"a", std::nullopt, u8"")));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CartonClap, BadVariable) {
|
||||
// Empty name
|
||||
EXPECT_ANY_THROW(auto var = CLAP::variable::Variable(u8"", u8"", true));
|
||||
}
|
||||
|
||||
TEST(CartonClap, BadVariables) {
|
||||
// Duplicated.
|
||||
{
|
||||
auto variables = CLAP::variable::VariableCollection();
|
||||
variables.add_variable(CLAP::variable::Variable(u8"a", u8"", true));
|
||||
EXPECT_ANY_THROW(variables.add_variable(CLAP::variable::Variable(u8"a", u8"", true)));
|
||||
}
|
||||
}
|
||||
|
||||
class CartonClap : public ::testing::Test {
|
||||
protected:
|
||||
CartonClap() :
|
||||
// YYC MARK:
|
||||
// The fucking C++ must order I initialize this class which do not have default ctor in there.
|
||||
// So I forcely initialize it with dummy data and reset it in ctor body.
|
||||
// The reason why I do not use static function to intialize this is that I also need specify some class members when creating this.
|
||||
app(CLAP::summary::Summary(u8"", u8"", u8"", u8""), CLAP::option::OptionCollection(), CLAP::variable::VariableCollection()) {
|
||||
// Setup basic infos
|
||||
auto summary = CLAP::summary::Summary(u8"TestClap", u8"yyc12345", u8"1.0.0", u8"This is the test of clap.");
|
||||
|
||||
// Add options
|
||||
auto options = CLAP::option::OptionCollection();
|
||||
int_option = options.add_option(CLAP::option::Option(u8"i", u8"int", u8"<integer>", u8"integral argument"));
|
||||
float_option = options.add_option(CLAP::option::Option(u8"f", std::nullopt, u8"<float>", u8""));
|
||||
string_option = options.add_option(CLAP::option::Option(std::nullopt, u8"string", u8"<string>", u8""));
|
||||
clamped_float_option = options.add_option(CLAP::option::Option(std::nullopt, u8"clamped-float", u8"<float>", u8""));
|
||||
novalue_option = options.add_option(CLAP::option::Option(u8"b", std::nullopt, std::nullopt, u8""));
|
||||
|
||||
// Add variables
|
||||
auto variables = CLAP::variable::VariableCollection();
|
||||
int_variable = variables.add_variable(CLAP::variable::Variable(u8"int", u8"", true));
|
||||
clamped_int_variable = variables.add_variable(CLAP::variable::Variable(u8"clamped-int", u8"", true));
|
||||
novalue_variable = variables.add_variable(CLAP::variable::Variable(u8"b", u8"", false));
|
||||
|
||||
// Create final application
|
||||
app = CLAP::application::Application(std::move(summary), std::move(options), std::move(variables));
|
||||
}
|
||||
~CartonClap() override = default;
|
||||
|
||||
// Options
|
||||
Token int_option;
|
||||
using IntOptionValidator = validator::IntegralValidator<i32>;
|
||||
Token float_option;
|
||||
using FloatOptionValidator = validator::FloatingPointValidator<float>;
|
||||
Token string_option;
|
||||
using StringOptionValidator = validator::StringValidator;
|
||||
Token clamped_float_option;
|
||||
using ClampedFloatOptionValidator = validator::FloatingPointValidator<float, -1.0f, 1.0f>;
|
||||
Token novalue_option;
|
||||
// Variables
|
||||
Token int_variable;
|
||||
using IntVariableValidator = validator::IntegralValidator<i32>;
|
||||
Token clamped_int_variable;
|
||||
using ClampedFloatVariableValidator = validator::FloatingPointValidator<float, -1.0f, 1.0f>;
|
||||
Token novalue_variable;
|
||||
|
||||
// Application
|
||||
CLAP::application::Application app;
|
||||
};
|
||||
|
||||
TEST_F(CartonClap, Manual) {
|
||||
std::stringstream ss;
|
||||
auto manual = CLAP::manual::Manual(app);
|
||||
|
||||
// TODO: It may be more precious check for this.
|
||||
// But I don't want to write it anymore.
|
||||
|
||||
// Two manual output should not be empty.
|
||||
ss.str("");
|
||||
manual.print_version(ss);
|
||||
EXPECT_FALSE(ss.view().empty());
|
||||
|
||||
ss.str("");
|
||||
manual.print_help(ss);
|
||||
EXPECT_FALSE(ss.view().empty());
|
||||
}
|
||||
|
||||
TEST_F(CartonClap, ParserNormal) {
|
||||
const std::vector<std::u8string_view> args = {u8"exec", u8"-i", u8"114514"};
|
||||
auto result = CLAP::parser::Parser::from_user(app, args);
|
||||
ASSERT_TRUE(result.has_value());
|
||||
auto parser = std::move(result.value());
|
||||
|
||||
// Check that int argument was captured with correct value
|
||||
{
|
||||
auto value = parser.get_value_option<IntOptionValidator>(int_option);
|
||||
ASSERT_TRUE(value.has_value());
|
||||
EXPECT_EQ(value.value(), 114514);
|
||||
}
|
||||
// Check that other arguments were not captured
|
||||
{
|
||||
auto value = parser.get_value_option<FloatOptionValidator>(float_option);
|
||||
EXPECT_FALSE(value.has_value());
|
||||
}
|
||||
{
|
||||
auto value = parser.get_value_option<StringOptionValidator>(string_option);
|
||||
EXPECT_FALSE(value.has_value());
|
||||
}
|
||||
{
|
||||
auto value = parser.get_value_option<ClampedFloatOptionValidator>(clamped_float_option);
|
||||
EXPECT_FALSE(value.has_value());
|
||||
}
|
||||
{
|
||||
auto value = parser.get_flag_option(novalue_option);
|
||||
ASSERT_TRUE(value.has_value());
|
||||
EXPECT_EQ(value.value(), false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CartonClap, ParserNothing) {
|
||||
const std::vector<std::u8string_view> args = {u8"exec"};
|
||||
auto result = CLAP::parser::Parser::from_user(app, args);
|
||||
ASSERT_TRUE(result.has_value());
|
||||
auto parser = std::move(result.value());
|
||||
|
||||
// Check that all arguments were not captured
|
||||
{
|
||||
auto value = parser.get_value_option<IntOptionValidator>(int_option);
|
||||
EXPECT_FALSE(value.has_value());
|
||||
}
|
||||
{
|
||||
auto value = parser.get_value_option<FloatOptionValidator>(float_option);
|
||||
EXPECT_FALSE(value.has_value());
|
||||
}
|
||||
{
|
||||
auto value = parser.get_value_option<StringOptionValidator>(string_option);
|
||||
EXPECT_FALSE(value.has_value());
|
||||
}
|
||||
{
|
||||
auto value = parser.get_value_option<ClampedFloatOptionValidator>(clamped_float_option);
|
||||
EXPECT_FALSE(value.has_value());
|
||||
}
|
||||
{
|
||||
auto value = parser.get_flag_option(novalue_option);
|
||||
ASSERT_TRUE(value.has_value());
|
||||
EXPECT_EQ(value.value(), false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CartonClap, ParserInvalidName) {
|
||||
const std::vector<std::u8string_view> args = {u8"exec", u8"-?", u8"114514"};
|
||||
auto result = CLAP::parser::Parser::from_user(app, args);
|
||||
ASSERT_FALSE(result.has_value());
|
||||
}
|
||||
|
||||
TEST_F(CartonClap, ParserDuplicatedAssign) {
|
||||
const std::vector<std::u8string_view> args = {u8"exec", u8"-i", u8"114514", u8"--int", u8"114514"};
|
||||
auto result = CLAP::parser::Parser::from_user(app, args);
|
||||
ASSERT_FALSE(result.has_value());
|
||||
}
|
||||
|
||||
TEST_F(CartonClap, ParserUnexpectedValue) {
|
||||
const std::vector<std::u8string_view> args = {u8"exec", u8"-i", u8"114514", u8"1919810"};
|
||||
auto result = CLAP::parser::Parser::from_user(app, args);
|
||||
ASSERT_FALSE(result.has_value());
|
||||
}
|
||||
|
||||
TEST_F(CartonClap, ParserLostValue) {
|
||||
const std::vector<std::u8string_view> args = {u8"exec", u8"-i"};
|
||||
auto result = CLAP::parser::Parser::from_user(app, args);
|
||||
ASSERT_FALSE(result.has_value());
|
||||
}
|
||||
|
||||
TEST_F(CartonClap, ParserBadCast) {
|
||||
const std::vector<std::u8string_view> args = {u8"exec", u8"-i", u8"114514", u8"--clamped-float", u8"114.0"};
|
||||
auto result = CLAP::parser::Parser::from_user(app, args);
|
||||
ASSERT_TRUE(result.has_value());
|
||||
auto parser = std::move(result.value());
|
||||
|
||||
// Check okey cast
|
||||
{
|
||||
auto value = parser.get_value_option<IntOptionValidator>(int_option);
|
||||
ASSERT_TRUE(value.has_value());
|
||||
EXPECT_EQ(value.value(), 114514);
|
||||
}
|
||||
// Check bad cast
|
||||
{
|
||||
auto value = parser.get_value_option<ClampedFloatOptionValidator>(clamped_float_option);
|
||||
EXPECT_FALSE(value.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CartonClap, ParserFull) {
|
||||
const std::vector<std::u8string_view> args = {
|
||||
u8"exec", // Program self.
|
||||
u8"-i", // Int option
|
||||
u8"114514",
|
||||
u8"-f", // Float option
|
||||
u8"2.0",
|
||||
u8"--string", // String option
|
||||
u8"fuck",
|
||||
u8"--clamped-float", // Clamped flpat option
|
||||
u8"0.5",
|
||||
u8"-b", // No value option
|
||||
};
|
||||
auto result = CLAP::parser::Parser::from_user(app, args);
|
||||
ASSERT_TRUE(result.has_value());
|
||||
auto parser = std::move(result.value());
|
||||
|
||||
// Check that all options were not captured
|
||||
{
|
||||
auto value = parser.get_value_option<IntOptionValidator>(int_option);
|
||||
ASSERT_TRUE(value.has_value());
|
||||
EXPECT_EQ(value.value(), 114514);
|
||||
}
|
||||
{
|
||||
auto value = parser.get_value_option<FloatOptionValidator>(float_option);
|
||||
ASSERT_TRUE(value.has_value());
|
||||
EXPECT_EQ(value.value(), 2.0f);
|
||||
}
|
||||
{
|
||||
auto value = parser.get_value_option<StringOptionValidator>(string_option);
|
||||
ASSERT_TRUE(value.has_value());
|
||||
EXPECT_EQ(value.value(), u8"fuck");
|
||||
}
|
||||
{
|
||||
auto value = parser.get_value_option<ClampedFloatOptionValidator>(clamped_float_option);
|
||||
ASSERT_TRUE(value.has_value());
|
||||
EXPECT_EQ(value.value(), 0.5f);
|
||||
}
|
||||
{
|
||||
auto value = parser.get_flag_option(novalue_option);
|
||||
ASSERT_TRUE(value.has_value());
|
||||
EXPECT_EQ(value.value(), true);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace yycctest::carton::clap
|
||||
Reference in New Issue
Block a user