mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
More operator <</>> Fixups.
This commit is contained in:
parent
98ca190700
commit
1ea3822665
@ -176,31 +176,8 @@ private:
|
||||
GncOptionUIType m_ui_type;
|
||||
};
|
||||
|
||||
/* These will work when m_value is a built-in class; GnuCash class and container
|
||||
* values will need specialization unless they happen to define operators << and
|
||||
* >>.
|
||||
* Note that SWIG 3.0.12 chokes on the typename = std::enable_if_t<> form so we
|
||||
* have to use the non-type parameter form.
|
||||
*/
|
||||
template<class OptionValueClass, typename std::enable_if_t<std::is_base_of_v<OptionClassifier, std::decay_t<OptionValueClass>>, int> = 0>
|
||||
std::ostream& operator<<(std::ostream& oss, const OptionValueClass& opt)
|
||||
{
|
||||
oss << opt.get_value();
|
||||
return oss;
|
||||
}
|
||||
|
||||
template<class OptionValueClass, typename std::enable_if_t<std::is_base_of_v<OptionClassifier, std::decay_t<OptionValueClass>>, int> = 0>
|
||||
std::istream& operator>>(std::istream& iss, OptionValueClass& opt)
|
||||
{
|
||||
std::decay_t<decltype(opt.get_value())> value;
|
||||
iss >> value;
|
||||
opt.set_value(value);
|
||||
return iss;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
class GncOptionValue :
|
||||
public OptionClassifier, public OptionUIItem
|
||||
class GncOptionValue : public OptionClassifier, public OptionUIItem
|
||||
{
|
||||
public:
|
||||
GncOptionValue<ValueType>(const char* section, const char* name,
|
||||
@ -223,49 +200,8 @@ private:
|
||||
ValueType m_default_value;
|
||||
};
|
||||
|
||||
QofInstance* qof_instance_from_string(const std::string& str,
|
||||
GncOptionUIType type);
|
||||
std::string qof_instance_to_string(const QofInstance* inst);
|
||||
|
||||
template<> inline std::ostream&
|
||||
operator<< <GncOptionValue<bool>>(std::ostream& oss,
|
||||
const GncOptionValue<bool>& opt)
|
||||
{
|
||||
oss << (opt.get_value() ? "#t" : "#f");
|
||||
return oss;
|
||||
}
|
||||
|
||||
template<> inline std::ostream&
|
||||
operator<< <GncOptionValue<QofInstance*>>(std::ostream& oss,
|
||||
const GncOptionValue<QofInstance*>& opt)
|
||||
{
|
||||
oss << qof_instance_to_string(opt.get_value());
|
||||
return oss;
|
||||
}
|
||||
|
||||
template<> inline std::istream&
|
||||
operator>> <GncOptionValue<bool>>(std::istream& iss,
|
||||
GncOptionValue<bool>& opt)
|
||||
{
|
||||
std::string instr;
|
||||
iss >> instr;
|
||||
opt.set_value(instr == "#t" ? true : false);
|
||||
return iss;
|
||||
}
|
||||
|
||||
template<> inline std::istream&
|
||||
operator>> <GncOptionValue<QofInstance*>>(std::istream& iss,
|
||||
GncOptionValue<QofInstance*>& opt)
|
||||
{
|
||||
std::string instr;
|
||||
iss >> instr;
|
||||
opt.set_value(qof_instance_from_string(instr, opt.get_ui_type()));
|
||||
return iss;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
class GncOptionValidatedValue :
|
||||
public OptionClassifier, public OptionUIItem
|
||||
class GncOptionValidatedValue : public OptionClassifier, public OptionUIItem
|
||||
{
|
||||
public:
|
||||
GncOptionValidatedValue<ValueType>(const char* section, const char* name,
|
||||
@ -314,25 +250,177 @@ private:
|
||||
ValueType m_validation_data;
|
||||
};
|
||||
|
||||
template<> inline std::ostream&
|
||||
operator<< <GncOptionValidatedValue<QofInstance*>>(std::ostream& oss,
|
||||
const GncOptionValidatedValue<QofInstance*>& opt)
|
||||
QofInstance* qof_instance_from_string(const std::string& str,
|
||||
GncOptionUIType type);
|
||||
std::string qof_instance_to_string(const QofInstance* inst);
|
||||
|
||||
/* These will work when m_value is a built-in class; GnuCash class and container
|
||||
* values will need specialization unless they happen to define operators << and
|
||||
* >>.
|
||||
* Note that SWIG 3.0.12 chokes on elaborate enable_if so just hide the
|
||||
* following templates from SWIG. (Ignoring doesn't work because SWIG still has
|
||||
* to parse the templates to figure out the symbols.
|
||||
*/
|
||||
#ifndef SWIG
|
||||
template<class OptionValueClass,
|
||||
typename std::enable_if_t<std::is_base_of_v<OptionClassifier,
|
||||
std::decay_t<OptionValueClass>> &&
|
||||
!(std::is_same_v<std::decay_t<OptionValueClass>,
|
||||
GncOptionValue<QofInstance*>> ||
|
||||
std::is_same_v<std::decay_t<OptionValueClass>,
|
||||
GncOptionValidatedValue<QofInstance*>>), int> = 0>
|
||||
std::ostream& operator<<(std::ostream& oss, const OptionValueClass& opt)
|
||||
{
|
||||
oss << qof_instance_to_string(opt.get_value());
|
||||
std::cerr << qof_instance_to_string(opt.get_value());
|
||||
oss << opt.get_value();
|
||||
return oss;
|
||||
}
|
||||
|
||||
template<> inline std::ostream&
|
||||
operator<< <GncOptionValue<bool>>(std::ostream& oss,
|
||||
const GncOptionValue<bool>& opt)
|
||||
{
|
||||
oss << (opt.get_value() ? "#t" : "#f");
|
||||
return oss;
|
||||
}
|
||||
|
||||
template<> inline std::istream&
|
||||
operator>> <GncOptionValidatedValue<QofInstance*>>(std::istream& iss,
|
||||
GncOptionValidatedValue<QofInstance*>& opt)
|
||||
template<class OptType, typename std::enable_if_t<std::is_same_v<std::decay_t<OptType>, GncOptionValidatedValue<QofInstance*>> || std::is_same_v<std::decay_t<OptType>, GncOptionValue<QofInstance*> >, int> = 0>
|
||||
inline std::ostream&
|
||||
operator<< (std::ostream& oss, const OptType& opt)
|
||||
{
|
||||
auto value = opt.get_value();
|
||||
if (auto type = opt.get_ui_type(); type == GncOptionUIType::COMMODITY ||
|
||||
type == GncOptionUIType::CURRENCY)
|
||||
{
|
||||
if (auto type = opt.get_ui_type(); type == GncOptionUIType::COMMODITY)
|
||||
{
|
||||
oss << gnc_commodity_get_namespace(GNC_COMMODITY(value)) << " ";
|
||||
}
|
||||
oss << gnc_commodity_get_mnemonic(GNC_COMMODITY(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
oss << qof_instance_to_string(value);
|
||||
}
|
||||
return oss;
|
||||
}
|
||||
|
||||
template<class OptionValueClass,
|
||||
typename std::enable_if_t<std::is_base_of_v<OptionClassifier, std::decay_t<OptionValueClass>> &&
|
||||
!(std::is_same_v<std::decay_t<OptionValueClass>,
|
||||
GncOptionValue<QofInstance*>> ||
|
||||
std::is_same_v<std::decay_t<OptionValueClass>,
|
||||
GncOptionValidatedValue<QofInstance*>>), int> = 0>
|
||||
std::istream& operator>>(std::istream& iss, OptionValueClass& opt)
|
||||
{
|
||||
std::decay_t<decltype(opt.get_value())> value;
|
||||
iss >> value;
|
||||
opt.set_value(value);
|
||||
return iss;
|
||||
}
|
||||
|
||||
template<class OptType, typename std::enable_if_t<std::is_same_v<std::decay_t<OptType>, GncOptionValidatedValue<QofInstance*>> || std::is_same_v<std::decay_t<OptType>, GncOptionValue<QofInstance*> >, int> = 0>
|
||||
std::istream&
|
||||
operator>> (std::istream& iss, OptType& opt)
|
||||
{
|
||||
std::string instr;
|
||||
iss >> instr;
|
||||
if (auto type = opt.get_ui_type(); type == GncOptionUIType::COMMODITY ||
|
||||
type == GncOptionUIType::CURRENCY)
|
||||
{
|
||||
std::string name_space, mnemonic;
|
||||
if (type = opt.get_ui_type(); type == GncOptionUIType::COMMODITY)
|
||||
{
|
||||
iss >> name_space;
|
||||
}
|
||||
else
|
||||
name_space = GNC_COMMODITY_NS_CURRENCY;
|
||||
iss >> mnemonic;
|
||||
instr = name_space + ":";
|
||||
instr += mnemonic;
|
||||
}
|
||||
else
|
||||
{
|
||||
iss >> instr;
|
||||
}
|
||||
opt.set_value(qof_instance_from_string(instr, opt.get_ui_type()));
|
||||
return iss;
|
||||
}
|
||||
|
||||
template<> inline std::istream&
|
||||
operator>> <GncOptionValue<bool>>(std::istream& iss,
|
||||
GncOptionValue<bool>& opt)
|
||||
{
|
||||
std::string instr;
|
||||
iss >> instr;
|
||||
opt.set_value(instr == "#t" ? true : false);
|
||||
return iss;
|
||||
}
|
||||
template<class OptType, typename std::enable_if_t<std::is_same_v<std::decay_t<OptType>, GncOptionValidatedValue<QofInstance*>> || std::is_same_v<std::decay_t<OptType>, GncOptionValue<QofInstance*>>, int> = 0>
|
||||
inline std::ostream&
|
||||
gnc_option_to_scheme (std::ostream& oss, const OptType& opt)
|
||||
{
|
||||
auto value = opt.get_value();
|
||||
auto type = opt.get_ui_type();
|
||||
if (type == GncOptionUIType::COMMODITY || type == GncOptionUIType::CURRENCY)
|
||||
{
|
||||
if (type == GncOptionUIType::COMMODITY)
|
||||
{
|
||||
oss << commodity_scm_intro;
|
||||
oss << "\"" <<
|
||||
gnc_commodity_get_namespace(GNC_COMMODITY(value)) << "\" ";
|
||||
}
|
||||
|
||||
oss << "\"" << gnc_commodity_get_mnemonic(GNC_COMMODITY(value)) << "\"";
|
||||
|
||||
if (type == GncOptionUIType::COMMODITY)
|
||||
{
|
||||
oss << ")";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
oss << "\"" << qof_instance_to_string(value) << "\"";
|
||||
}
|
||||
return oss;
|
||||
}
|
||||
|
||||
template<class OptType, typename std::enable_if_t<std::is_same_v<std::decay_t<OptType>, GncOptionValidatedValue<QofInstance*>> || std::is_same_v<std::decay_t<OptType>, GncOptionValue<QofInstance*>>, int> = 0>
|
||||
inline std::istream&
|
||||
gnc_option_from_scheme (std::istream& iss, OptType& opt)
|
||||
{
|
||||
std::string instr;
|
||||
auto type = opt.get_ui_type();
|
||||
if (type == GncOptionUIType::COMMODITY || type == GncOptionUIType::CURRENCY)
|
||||
{
|
||||
std::string name_space, mnemonic;
|
||||
if (type == GncOptionUIType::COMMODITY)
|
||||
{
|
||||
iss.ignore(strlen(commodity_scm_intro) + 1, '"');
|
||||
std::getline(iss, name_space, '"');
|
||||
iss.ignore(1, '"');
|
||||
}
|
||||
else
|
||||
name_space = GNC_COMMODITY_NS_CURRENCY;
|
||||
iss.ignore(1, '"');
|
||||
std::getline(iss, mnemonic, '"');
|
||||
|
||||
if (type == GncOptionUIType::COMMODITY)
|
||||
iss.ignore(2, ')');
|
||||
else
|
||||
iss.ignore(1, '"');
|
||||
|
||||
instr = name_space + ":";
|
||||
instr += mnemonic;
|
||||
}
|
||||
else
|
||||
{
|
||||
iss.ignore(1, '"');
|
||||
std::getline(iss, instr, '"');
|
||||
}
|
||||
opt.set_value(qof_instance_from_string(instr, opt.get_ui_type()));
|
||||
return iss;
|
||||
}
|
||||
#endif // SWIG
|
||||
|
||||
/**
|
||||
* Used for numeric ranges and plot sizes.
|
||||
*/
|
||||
@ -559,8 +647,15 @@ operator<< <GncOptionAccountValue>(std::ostream& oss,
|
||||
const GncOptionAccountValue& opt)
|
||||
{
|
||||
auto values{opt.get_value()};
|
||||
bool first = true;
|
||||
for (auto value : values)
|
||||
oss << qof_instance_to_string(QOF_INSTANCE(value)) << " ";
|
||||
{
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
oss << " ";
|
||||
oss << qof_instance_to_string(QOF_INSTANCE(value));
|
||||
}
|
||||
return oss;
|
||||
}
|
||||
|
||||
|
@ -152,6 +152,28 @@ TEST_F(GncOptionTest, test_budget_ctor)
|
||||
gnc_budget_destroy(budget);
|
||||
}
|
||||
|
||||
TEST_F(GncOptionTest, test_budget_out)
|
||||
{
|
||||
auto budget = gnc_budget_new(m_book);
|
||||
GncOption option{"foo", "bar", "baz", "Phony Option", QOF_INSTANCE(budget)};
|
||||
|
||||
auto budget_guid{gnc::GUID{*qof_instance_get_guid(QOF_INSTANCE(budget))}.to_string()};
|
||||
std::ostringstream oss;
|
||||
oss << option;
|
||||
EXPECT_EQ(budget_guid, oss.str());
|
||||
gnc_budget_destroy(budget);
|
||||
}
|
||||
|
||||
TEST_F(GncOptionTest, test_budget_in)
|
||||
{
|
||||
auto budget = gnc_budget_new(m_book);
|
||||
auto budget_guid{gnc::GUID{*qof_instance_get_guid(QOF_INSTANCE(budget))}.to_string()};
|
||||
std::istringstream iss{budget_guid};
|
||||
GncOption option{GncOptionValue<QofInstance*>{"foo", "bar", "baz", "Phony Option", nullptr, GncOptionUIType::BUDGET}};
|
||||
iss >> option;
|
||||
EXPECT_EQ(QOF_INSTANCE(budget), option.get_value<QofInstance*>());
|
||||
gnc_budget_destroy(budget);
|
||||
}
|
||||
TEST_F(GncOptionTest, test_commodity_ctor)
|
||||
{
|
||||
auto hpe = gnc_commodity_new(m_book, "Hewlett Packard Enterprise, Inc.",
|
||||
@ -589,23 +611,23 @@ TEST_F(GncOptionAccountTest, test_option_value_limited_constructor)
|
||||
TEST_F(GncOptionAccountTest, test_account_list_out)
|
||||
{
|
||||
GncOptionAccountList acclist{list_of_types({ACCT_TYPE_BANK})};
|
||||
GncOptionAccountValue option{"foo", "bar", "baz", "Bogus Option",
|
||||
GncOptionUIType::ACCOUNT_LIST, acclist};
|
||||
GncOption option{GncOptionAccountValue{"foo", "bar", "baz", "Bogus Option",
|
||||
GncOptionUIType::ACCOUNT_LIST,
|
||||
acclist}};
|
||||
std::ostringstream oss;
|
||||
std::string acc_guids{gnc::GUID{*qof_instance_get_guid(acclist[0])}.to_string()};
|
||||
acc_guids += " ";
|
||||
acc_guids += gnc::GUID{*qof_instance_get_guid(acclist[1])}.to_string();
|
||||
acc_guids += " ";
|
||||
|
||||
oss << option;
|
||||
EXPECT_EQ(acc_guids, oss.str());
|
||||
|
||||
GncOptionAccountList accsel{acclist[0]};
|
||||
GncOptionAccountValue sel_option("foo", "bar", "baz", "Bogus Option",
|
||||
GncOption sel_option{GncOptionAccountValue{"foo", "bar", "baz",
|
||||
"Bogus Option",
|
||||
GncOptionUIType::ACCOUNT_LIST,
|
||||
accsel, {ACCT_TYPE_BANK});
|
||||
accsel, {ACCT_TYPE_BANK}}};
|
||||
acc_guids = gnc::GUID{*qof_instance_get_guid(accsel[0])}.to_string();
|
||||
acc_guids += " ";
|
||||
|
||||
oss.str("");
|
||||
oss << sel_option;
|
||||
@ -615,35 +637,39 @@ TEST_F(GncOptionAccountTest, test_account_list_out)
|
||||
TEST_F(GncOptionAccountTest, test_account_list_in)
|
||||
{
|
||||
GncOptionAccountList acclist{list_of_types({ACCT_TYPE_BANK})};
|
||||
GncOptionAccountValue option{"foo", "bar", "baz", "Bogus Option",
|
||||
GncOptionUIType::ACCOUNT_LIST, acclist};
|
||||
GncOption option{GncOptionAccountValue{"foo", "bar", "baz", "Bogus Option",
|
||||
GncOptionUIType::ACCOUNT_LIST,
|
||||
acclist}};
|
||||
std::string acc_guids{gnc::GUID{*qof_instance_get_guid(acclist[0])}.to_string()};
|
||||
acc_guids += " ";
|
||||
acc_guids += gnc::GUID{*qof_instance_get_guid(acclist[1])}.to_string();
|
||||
acc_guids += " ";
|
||||
|
||||
std::istringstream iss{acc_guids};
|
||||
iss >> option;
|
||||
EXPECT_EQ(acclist, option.get_value());
|
||||
EXPECT_EQ(acclist, option.get_value<GncOptionAccountList>());
|
||||
|
||||
GncOptionAccountList accsel{acclist[0]};
|
||||
GncOptionAccountValue sel_option("foo", "bar", "baz", "Bogus Option",
|
||||
GncOption sel_option{GncOptionAccountValue{"foo", "bar", "baz",
|
||||
"Bogus Option",
|
||||
GncOptionUIType::ACCOUNT_LIST,
|
||||
accsel, {ACCT_TYPE_BANK});
|
||||
accsel, {ACCT_TYPE_BANK}}};
|
||||
GncOptionAccountList acclistbad{list_of_types({ACCT_TYPE_STOCK})};
|
||||
acc_guids = gnc::GUID{*qof_instance_get_guid(acclistbad[1])}.to_string();
|
||||
acc_guids += " ";
|
||||
|
||||
iss.str(acc_guids);
|
||||
iss >> sel_option;
|
||||
EXPECT_EQ(accsel, sel_option.get_value());
|
||||
EXPECT_EQ(accsel, sel_option.get_value<GncOptionAccountList>());
|
||||
|
||||
iss.clear(); //Reset the failedbit from the invalid selection type.
|
||||
acc_guids = gnc::GUID{*qof_instance_get_guid(acclist[1])}.to_string();
|
||||
EXPECT_NO_THROW({
|
||||
iss.str(acc_guids);
|
||||
iss >> sel_option;
|
||||
});
|
||||
EXPECT_EQ(acclist[1], sel_option.get_value()[0]);
|
||||
EXPECT_EQ(acclist[1], sel_option.get_value<GncOptionAccountList>()[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class GncOptionMultichoiceTest : public ::testing::Test
|
||||
@ -710,6 +736,24 @@ TEST_F(GncMultichoiceOption, test_permissible_value_stuff)
|
||||
m_option.permissible_value_index("xyzzy"));
|
||||
}
|
||||
|
||||
TEST_F(GncMultichoiceOption, test_multichoice_out)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << m_option;
|
||||
EXPECT_EQ(oss.str(), m_option.get_value<std::string>());
|
||||
}
|
||||
|
||||
TEST_F(GncMultichoiceOption, test_multichoice_in)
|
||||
{
|
||||
std::istringstream iss{"grault"};
|
||||
EXPECT_THROW({
|
||||
iss >> m_option;
|
||||
}, std::invalid_argument);
|
||||
iss.clear(); //reset failedbit
|
||||
iss.str("pork");
|
||||
iss >> m_option;
|
||||
EXPECT_EQ(iss.str(), m_option.get_value<std::string>());
|
||||
}
|
||||
class GncOptionDateOptionTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
|
Loading…
Reference in New Issue
Block a user