c++options: Serialize and deserialize to strings instead of streams.

And use serialize to create values for gnc:generate-restore-forms and both
of them for the meat of the stream functions.

This fixes in particular QofInstance serialization where passing the
option value directly to scheme format resulted in a notation about
a swig pointer instead of the desired GUID string or commodity namespace
and mnemonic strings.
This commit is contained in:
John Ralls 2021-12-02 15:04:49 -08:00
parent c3b8b6cc49
commit 6f93a68bad
8 changed files with 502 additions and 67 deletions

View File

@ -26,6 +26,7 @@
#include <gnc-datetime.hpp>
#include <guid.hpp>
#include <cassert>
#include <charconv>
extern "C"
{
@ -389,8 +390,28 @@ qof_instance_from_string(const std::string& str, GncOptionUIType type)
std::string
qof_instance_to_string(const QofInstance* inst)
{
gnc::GUID guid{*qof_instance_get_guid(inst)};
return guid.to_string();
std::string retval;
if (GNC_IS_COMMODITY(inst))
{
auto commodity{GNC_COMMODITY(inst)};
if (!gnc_commodity_is_currency(commodity))
{
auto name_space{gnc_commodity_get_namespace(GNC_COMMODITY(inst))};
if (name_space && *name_space != '\0')
{
retval = name_space;
retval += ":";
}
}
retval += gnc_commodity_get_mnemonic(GNC_COMMODITY(inst));
return retval;
}
else
{
gnc::GUID guid{*qof_instance_get_guid(inst)};
retval = guid.to_string();
}
return retval;
}
template <typename ValueType> void
@ -411,6 +432,41 @@ GncOptionValue<ValueType>::reset_default_value()
m_value = m_default_value;
}
template <typename ValueType> std::string
GncOptionValue<ValueType>::serialize() const noexcept
{
if constexpr(std::is_same_v<ValueType, const QofInstance*>)
return qof_instance_to_string(m_value);
else if constexpr(is_same_decayed_v<ValueType, std::string>)
return m_value;
else if constexpr(is_same_decayed_v<ValueType, bool>)
return m_value ? "True" : "False";
else if constexpr(std::is_arithmetic_v<ValueType>)
return std::to_string(m_value);
else
return "";
}
template <typename ValueType> bool
GncOptionValue<ValueType>::deserialize(const std::string& str) noexcept
{
if constexpr(std::is_same_v<ValueType, const QofInstance*>)
set_value(qof_instance_from_string(str, get_ui_type()));
else if constexpr(is_same_decayed_v<ValueType, std::string>)
set_value(str);
else if constexpr(is_same_decayed_v<ValueType, bool>)
set_value(str == "True");
else if constexpr(is_same_decayed_v<ValueType, int>)
set_value(stoi(str));
else if constexpr(is_same_decayed_v<ValueType, int64_t>)
set_value(stoll(str));
else if constexpr(is_same_decayed_v<ValueType, double>)
set_value(stod(str));
else
return false;
return true;
}
template <> void
GncOptionValue<SCM>::set_value(SCM new_value)
{
@ -441,6 +497,201 @@ GncOptionValue<SCM>::reset_default_value()
scm_gc_protect_object(m_value);
}
template <typename ValueType> std::string
GncOptionValidatedValue<ValueType>::serialize() const noexcept
{
if constexpr(std::is_same_v<ValueType, const QofInstance*>)
return qof_instance_to_string(m_value);
else if constexpr(is_same_decayed_v<ValueType, std::string>)
return m_value;
else if constexpr(is_same_decayed_v<ValueType, bool>)
return m_value ? "True" : "False";
else if constexpr(std::is_arithmetic_v<ValueType>)
return std::to_string(m_value);
else
return "Invalid Value Type";
}
template <typename ValueType> bool
GncOptionValidatedValue<ValueType>::deserialize(const std::string& str) noexcept
{
if constexpr(std::is_same_v<ValueType, const QofInstance*>)
set_value(qof_instance_from_string(str, get_ui_type()));
else if constexpr(is_same_decayed_v<ValueType, std::string>)
set_value(str);
else if constexpr(is_same_decayed_v<ValueType, bool>)
set_value(str == "True");
else if constexpr(is_same_decayed_v<ValueType, int>)
set_value(stoi(str));
else if constexpr(is_same_decayed_v<ValueType, int64_t>)
set_value(stoll(str));
else if constexpr(is_same_decayed_v<ValueType, double>)
set_value(stod(str));
else
return false;
return true;
}
std::string
GncOptionAccountListValue::serialize() const noexcept
{
std::string retval;
bool first = true;
for (auto val : m_value)
{
if (!first)
retval += " ";
first = false;
retval += qof_instance_to_string(QOF_INSTANCE(val));
}
return retval;
}
bool
GncOptionAccountListValue::deserialize(const std::string& str) noexcept
{
if (str.empty() || str.size() < GUID_ENCODING_LENGTH)
return false;
m_value.clear();
m_value.reserve(str.size() / GUID_ENCODING_LENGTH);
bool first = true;
size_t pos{};
while (pos + GUID_ENCODING_LENGTH < str.size())
{
if (!first)
++pos;
first = false;
auto ptr = qof_instance_from_string(str.substr(pos, pos + GUID_ENCODING_LENGTH), get_ui_type());
m_value.push_back(reinterpret_cast<Account*>(ptr));
pos += GUID_ENCODING_LENGTH;
}
return true;
}
std::string
GncOptionAccountSelValue::serialize() const noexcept
{
return qof_instance_to_string(QOF_INSTANCE(m_value));
}
bool
GncOptionAccountSelValue::deserialize(const std::string& str) noexcept
{
set_value(reinterpret_cast<Account*>(qof_instance_from_string(str, get_ui_type())));
return true;
}
std::string
GncOptionMultichoiceValue::serialize() const noexcept
{
std::string retval;
bool first = true;
for (auto index : m_value)
{
if (!first)
retval += " ";
first = false;
retval += std::get<0>(m_choices[index]);
}
return retval;
}
bool
GncOptionMultichoiceValue::deserialize(const std::string& str) noexcept
{
static const auto size_t_max = std::numeric_limits<std::size_t>::max();
if (str.empty())
return false;
size_t pos{};
while (pos < str.size())
{
auto endpos{str.find(' ', pos)};
if (endpos == std::string::npos)
endpos = str.size();
//need a null-terminated char* to pass to permissible_value_index
auto index{permissible_value_index(str.substr(pos, endpos).c_str())};
if (index == size_t_max)
return false;
m_value.push_back(index);
pos = endpos + 1;
}
return true;
}
template <typename ValueType> std::string
GncOptionRangeValue<ValueType>::serialize() const noexcept
{
if constexpr (std::is_arithmetic_v<ValueType>)
return std::to_string(m_value);
return "";
}
template <typename ValueType> bool
GncOptionRangeValue<ValueType>::deserialize(const std::string& str) noexcept
{
if constexpr(is_same_decayed_v<ValueType, int>)
set_value(stoi(str));
else if constexpr(is_same_decayed_v<ValueType, double>)
set_value(stod(str));
return true;
}
std::string
GncOptionDateValue::serialize() const noexcept
{
std::string retval{"("};
if (m_period == RelativeDatePeriod::ABSOLUTE)
{
retval += date_type_str[0];
retval += " . ";
retval += std::to_string(m_date);
}
else
{
retval += date_type_str[1];
retval += " . ";
retval += gnc_relative_date_storage_string(m_period);
}
retval += ")";
return retval;
}
bool
GncOptionDateValue::deserialize(const std::string& str) noexcept
{
//The length of both "absolute" and "relative".
static constexpr size_t date_type_len{9};
// date_type_len plus the length of " . ".
static constexpr size_t date_value_pos{12};
auto type_str{str.substr(0, date_type_len)};
auto period_str{str.substr(date_value_pos)};
if (type_str == "absolute")
{
set_value(std::stoll(period_str));
return true;
}
else if (type_str == "relative ")
{
auto period = gnc_relative_date_from_storage_string(period_str.c_str());
if (period == RelativeDatePeriod::ABSOLUTE)
{
PWARN("Unknown period string in date option: '%s'",
period_str.c_str());
return false;
}
set_value(period);
return true;
}
else
{
PWARN("Unknown date type string in date option: '%s'",
type_str.c_str());
return false;
}
}
template GncOptionValue<bool>::GncOptionValue(const GncOptionValue<bool>&);
template GncOptionValue<int>::GncOptionValue(const GncOptionValue<int>&);
template GncOptionValue<int64_t>::GncOptionValue(const GncOptionValue<int64_t>&);
@ -498,3 +749,49 @@ template void GncOptionValue<RelativeDatePeriod>::reset_default_value();
template void GncOptionValue<size_t>::reset_default_value();
template void GncOptionValue<GncOptionAccountList>::reset_default_value();
template void GncOptionValue<GncMultichoiceOptionIndexVec>::reset_default_value();
template std::string GncOptionValue<bool>::serialize() const noexcept;
template std::string GncOptionValue<int>::serialize() const noexcept;
template std::string GncOptionValue<int64_t>::serialize() const noexcept;
template std::string GncOptionValue<double>::serialize() const noexcept;
template std::string GncOptionValue<char*>::serialize() const noexcept;
template std::string GncOptionValue<const char*>::serialize() const noexcept;
template std::string GncOptionValue<std::string>::serialize() const noexcept;
template std::string GncOptionValue<const QofInstance*>::serialize() const noexcept;
template std::string GncOptionValue<const QofQuery*>::serialize() const noexcept;
template std::string GncOptionValue<const GncOwner*>::serialize() const noexcept;
template std::string GncOptionValue<SCM>::serialize() const noexcept;
template std::string GncOptionValidatedValue<bool>::serialize() const noexcept;
template std::string GncOptionValidatedValue<int>::serialize() const noexcept;
template std::string GncOptionValidatedValue<int64_t>::serialize() const noexcept;
template std::string GncOptionValidatedValue<double>::serialize() const noexcept;
template std::string GncOptionValidatedValue<char*>::serialize() const noexcept;
template std::string GncOptionValidatedValue<const char*>::serialize() const noexcept;
template std::string GncOptionValidatedValue<std::string>::serialize() const noexcept;
template std::string GncOptionValidatedValue<const QofInstance*>::serialize() const noexcept;
template std::string GncOptionValidatedValue<const QofQuery*>::serialize() const noexcept;
template std::string GncOptionValidatedValue<const GncOwner*>::serialize() const noexcept;
template std::string GncOptionRangeValue<int>::serialize() const noexcept;
template std::string GncOptionRangeValue<double>::serialize() const noexcept;
template bool GncOptionValue<bool>::deserialize(const std::string&) noexcept;
template bool GncOptionValue<int>::deserialize(const std::string&) noexcept;
template bool GncOptionValue<int64_t>::deserialize(const std::string&) noexcept;
template bool GncOptionValue<double>::deserialize(const std::string&) noexcept;
template bool GncOptionValue<char*>::deserialize(const std::string&) noexcept;
template bool GncOptionValue<const char*>::deserialize(const std::string&) noexcept;
template bool GncOptionValue<std::string>::deserialize(const std::string&) noexcept;
template bool GncOptionValue<const QofInstance*>::deserialize(const std::string&) noexcept;
template bool GncOptionValue<const QofQuery*>::deserialize(const std::string&) noexcept;
template bool GncOptionValue<const GncOwner*>::deserialize(const std::string&) noexcept;
template bool GncOptionValue<SCM>::deserialize(const std::string&) noexcept;
template bool GncOptionValidatedValue<bool>::deserialize(const std::string&) noexcept;
template bool GncOptionValidatedValue<int>::deserialize(const std::string&) noexcept;
template bool GncOptionValidatedValue<int64_t>::deserialize(const std::string&) noexcept;
template bool GncOptionValidatedValue<double>::deserialize(const std::string&) noexcept;
template bool GncOptionValidatedValue<char*>::deserialize(const std::string&) noexcept;
template bool GncOptionValidatedValue<const char*>::deserialize(const std::string&) noexcept;
template bool GncOptionValidatedValue<std::string>::deserialize(const std::string&) noexcept;
template bool GncOptionValidatedValue<const QofInstance*>::deserialize(const std::string&) noexcept;
template bool GncOptionValidatedValue<const QofQuery*>::deserialize(const std::string&) noexcept;
template bool GncOptionValidatedValue<const GncOwner*>::deserialize(const std::string&) noexcept;
template bool GncOptionRangeValue<int>::deserialize(const std::string&) noexcept;
template bool GncOptionRangeValue<double>::deserialize(const std::string&) noexcept;

View File

@ -134,6 +134,8 @@ public:
bool is_changed() const noexcept { return m_value != m_default_value; }
GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
std::string serialize() const noexcept;
bool deserialize(const std::string& str) noexcept;
private:
GncOptionUIType m_ui_type;
ValueType m_value;
@ -201,6 +203,8 @@ public:
bool is_changed() const noexcept { return m_value != m_default_value; }
GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
std::string serialize() const noexcept;
bool deserialize(const std::string& str) noexcept;
private:
GncOptionUIType m_ui_type;
ValueType m_value;
@ -299,19 +303,24 @@ std::istream&
operator>> (std::istream& iss, OptType& opt)
{
std::string instr;
if (auto type = opt.get_ui_type(); type == GncOptionUIType::COMMODITY ||
type == GncOptionUIType::CURRENCY)
auto type = opt.get_ui_type();
if (type == GncOptionUIType::COMMODITY || type == GncOptionUIType::CURRENCY)
{
std::string name_space, mnemonic;
if (type = opt.get_ui_type(); type == GncOptionUIType::COMMODITY)
{
if (type == GncOptionUIType::COMMODITY)
iss >> name_space;
}
else
name_space = GNC_COMMODITY_NS_CURRENCY;
iss >> mnemonic;
instr = name_space + ":";
instr += mnemonic;
if (name_space.find(":") == std::string::npos)
{
iss >> mnemonic;
instr = name_space + ":";
instr += mnemonic;
}
else
{
instr = name_space;
}
}
else
{
@ -385,6 +394,8 @@ public:
if (m_ui_type == GncOptionUIType::PLOT_SIZE)
m_alternate = value;
}
std::string serialize() const noexcept;
bool deserialize(const std::string& str) noexcept;
private:
GncOptionUIType m_ui_type = GncOptionUIType::NUMBER_RANGE;
ValueType m_value;
@ -644,6 +655,8 @@ public:
GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
GncOptionMultichoiceKeyType get_keytype(unsigned i) const { return std::get<2>(m_choices.at(i)); }
std::string serialize() const noexcept;
bool deserialize(const std::string& str) noexcept;
private:
std::size_t find_key (const std::string& key) const noexcept
{
@ -794,6 +807,8 @@ public:
GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
bool is_multiselect() const noexcept { return m_multiselect; }
std::string serialize() const noexcept;
bool deserialize(const std::string& str) noexcept;
private:
GncOptionUIType m_ui_type;
GncOptionAccountList m_value;
@ -895,6 +910,8 @@ public:
bool is_changed() const noexcept { return m_value != m_default_value; }
GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
std::string serialize() const noexcept;
bool deserialize(const std::string& str) noexcept;
private:
GncOptionUIType m_ui_type;
Account* m_value;
@ -1042,6 +1059,8 @@ public:
GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
const RelativeDatePeriodVec& get_period_set() const { return m_period_set; }
std::string serialize() const noexcept;
bool deserialize(const std::string& str) noexcept;
private:
GncOptionUIType m_ui_type;
time64 m_date;

View File

@ -406,12 +406,21 @@ GncOption::set_alternate(bool alt) noexcept
}, *m_option);
}
std::ostream&
GncOption::out_stream(std::ostream& oss) const
std::string
GncOption::serialize() const
{
return std::visit([&oss](auto& option) -> std::ostream& {
oss << option;
return oss;
if (m_option->valueless_by_exception())
return "Valueless Option";
return std::visit([&](auto& option) -> std::string {
return option.serialize();
}, *m_option);
}
bool
GncOption::deserialize(const std::string& str)
{
return std::visit([&str](auto& option) -> bool {
return option.deserialize(str);
}, *m_option);
}

View File

@ -180,9 +180,20 @@ public:
GList* account_type_list() const noexcept;
bool is_alternate() const noexcept;
void set_alternate(bool) noexcept;
std::ostream& out_stream(std::ostream& oss) const;
/** Get a string suitable for storage representing the option's value.
* @return a std::string
*/
std::string serialize() const;
/** Set the option's value from a character sequence.
* @param str: The character sequence representing the value
* @return true if the value was set, false otherwise.
*/
bool deserialize(const std::string& str);
/** Set the option's value from an input stream
* @param iss: An input stream reference.
* @return the stream reference for chaining.
*/
std::istream& in_stream(std::istream& iss);
friend GncOptionVariant& swig_get_option(GncOption*);
private:
@ -200,7 +211,8 @@ operator<(const GncOption& right, const GncOption& left)
inline std::ostream&
operator<<(std::ostream& oss, const GncOption& opt)
{
return opt.out_stream(oss);
oss << opt.serialize();
return oss;
}
inline std::istream&

View File

@ -590,6 +590,7 @@ wrap_unique_ptr(GncOptionDBPtr, GncOptionDB);
#include <array>
#include <string>
#include "gnc-option.hpp"
#include "gnc-option-impl.hpp"
#include "gnc-option-ui.hpp"
GncOptionVariant& swig_get_option(GncOption* option)
@ -1009,7 +1010,9 @@ inline SCM return_scm_value(ValueType value)
const SCM ticked_format_str{scm_from_utf8_string("'~a")};
//scm_simple_format needs a scheme list of arguments to match the format
//placeholders.
auto value{scm_list_1(GncOption_get_scm_value($self))};
auto serial{$self->serialize()};
SCM value = serial.empty() ? SCM_BOOL_F :
scm_list_1(scm_from_utf8_string(serial.c_str()));
auto uitype{$self->get_ui_type()};
if (uitype == GncOptionUIType::STRING ||
uitype == GncOptionUIType::TEXT ||
@ -1030,11 +1033,48 @@ inline SCM return_scm_value(ValueType value)
return scm_simple_format(SCM_BOOL_F, plain_format_str, value);
else
return scm_simple_format(SCM_BOOL_F, plain_format_str,
SCM_BOOL_F);
scm_list_1(SCM_BOOL_F));
}
else if (uitype == GncOptionUIType::CURRENCY)
{
const SCM quoted_format_str{scm_from_utf8_string("\"~a\"")};
return scm_simple_format(SCM_BOOL_F, quoted_format_str, value);
}
else if (uitype == GncOptionUIType::COMMODITY)
{
const SCM commodity_fmt{scm_from_utf8_string("\"~a\" \"~a\"")};
auto sep{serial.find(':')};
if (sep == std::string::npos)
sep = serial.find(' ');
if (sep == std::string::npos)
{
const SCM quoted_format_str{scm_from_utf8_string("\"~a\"")};
return scm_simple_format(SCM_BOOL_F, quoted_format_str, value);
}
auto name_space{serial.substr(0, sep)};
auto symbol{serial.substr(sep + 1, std::string::npos)};
auto commodity_val{scm_list_2(scm_from_utf8_string(name_space.c_str()),
scm_from_utf8_string(symbol.c_str()))};
return scm_simple_format(SCM_BOOL_F, commodity_fmt, commodity_val);
}
else if (uitype == GncOptionUIType::DATE_ABSOLUTE ||
uitype == GncOptionUIType::DATE_RELATIVE ||
uitype == GncOptionUIType::DATE_BOTH)
{
const SCM date_fmt{scm_from_utf8_string("'~a")};
return scm_simple_format(SCM_BOOL_F, date_fmt, value);
}
else
{
return scm_simple_format(SCM_BOOL_F, ticked_format_str, value);
if (value && scm_is_true(value))
{
return scm_simple_format(SCM_BOOL_F, ticked_format_str, value);
}
else
{
return scm_simple_format(SCM_BOOL_F, plain_format_str,
scm_list_1(SCM_BOOL_F));
}
}
}
@ -1085,6 +1125,24 @@ inline SCM return_scm_value(ValueType value)
}
return;
}
if constexpr (is_same_decayed_v<decltype(option),
GncOptionAccountSelValue>)
{
if (scm_is_string(new_value))
{
auto strval{scm_to_utf8_string(new_value)};
GncGUID guid;
string_to_guid(strval, &guid);
auto book{gnc_get_current_book()};
option.set_value(xaccAccountLookup(&guid, book));
}
else
{
auto val{scm_to_value<const QofInstance*>(new_value)};
option.set_value(GNC_ACCOUNT(val));
}
return;
}
auto value{scm_to_value<std::decay_t<decltype(option.get_value())>>(new_value)}; //Can't inline, set_value takes arg by reference.
option.set_value(static_cast<decltype(option.get_value())>(value));
}, swig_get_option($self));
@ -1143,6 +1201,24 @@ inline SCM return_scm_value(ValueType value)
}
return;
}
if constexpr (is_same_decayed_v<decltype(option),
GncOptionAccountSelValue>)
{
if (scm_is_string(new_value))
{
auto strval{scm_to_utf8_string(new_value)};
GncGUID guid;
string_to_guid(strval, &guid);
auto book{gnc_get_current_book()};
option.set_default_value(xaccAccountLookup(&guid, book));
}
else
{
auto val{scm_to_value<Account*>(new_value)};
option.set_default_value(val);
}
return;
}
auto value{scm_to_value<std::decay_t<decltype(option.get_value())>>(new_value)}; //Can't inline, set_value takes arg by reference.
option.set_default_value(value);
}, swig_get_option($self));
@ -1392,7 +1468,8 @@ inline SCM return_scm_value(ValueType value)
gnc_commodity *value)
{
return new GncOption{GncOptionValue<const QofInstance*>{
section, name, key, doc_string, (const QofInstance*)value}};
section, name, key, doc_string, (const QofInstance*)value,
GncOptionUIType::COMMODITY}};
}
static GncOption*

View File

@ -87,14 +87,13 @@
;; Used only by test-stress-options.scm
(define-public (gnc:option-data option)
(let ((num-values (GncOption-num-permissible-values option))
(retval '()))
(do ((i 0 (1+ i))) ((>= i num-values))
(let ((value (GncOption-permissible-value option i))
(name (GncOption-permissible-value-name option i)))
(set! retval (cons retval (vector value name)))))
retval))
; (define num-values (GncOption-num-permissible-values option))
; (let loop ((i 0) (retval '()))
; (if (>= i num-values) (reverse retval)
; (let ((value (GncOption-permissible-value option i))
; (name (GncOption-permissible-value-name option i)))
; (loop (1+ i) (cons (vector value name) retval))))))
(list (vector 1 2)))
;; Create the database and return a dispatch function.
(define-public (gnc:new-options)
(let ((optiondb (new-gnc-optiondb)))

View File

@ -121,11 +121,11 @@ TEST(GncOption, test_bool_stream_out)
GncOption option("foo", "bar", "baz", "Phony Option", false);
std::ostringstream oss;
oss << option;
EXPECT_STREQ(oss.str().c_str(), "#f");
EXPECT_STREQ(oss.str().c_str(), "False");
oss.str("");
option.set_value(true);
oss << option;
EXPECT_STREQ(oss.str().c_str(), "#t");
EXPECT_STREQ(oss.str().c_str(), "True");
}
TEST(GncOption, test_bool_stream_in)
@ -301,7 +301,7 @@ static inline std::string make_currency_str(gnc_commodity* cur)
static inline std::string make_commodity_str(gnc_commodity* com)
{
std::string com_str{gnc_commodity_get_namespace(com)};
com_str += " ";
com_str += ":";
com_str += gnc_commodity_get_mnemonic(com);
return com_str;
}
@ -511,7 +511,7 @@ TEST_F(GncRangeOption, test_range_out)
{
std::ostringstream oss;
oss << "Integer " << m_intoption << " Double " << m_doubleoption << ".";
EXPECT_STREQ("Integer 15 Double 1.5.", oss.str().c_str());
EXPECT_STREQ("Integer 15 Double 1.500000.", oss.str().c_str());
}
TEST_F(GncRangeOption, test_range_in)
@ -1120,8 +1120,8 @@ TEST_F(GncDateOption, test_stream_out)
m_option.set_value(time1);
std::ostringstream oss;
oss << time1;
std::string timestr{"absolute . "};
timestr += oss.str();
std::string timestr{"(absolute . "};
timestr += oss.str() + ")";
oss.str("");
oss << m_option;
EXPECT_EQ(oss.str(), timestr);
@ -1129,77 +1129,77 @@ TEST_F(GncDateOption, test_stream_out)
m_option.set_value(RelativeDatePeriod::TODAY);
oss.str("");
oss << m_option;
EXPECT_STREQ(oss.str().c_str(), "relative . today");
EXPECT_STREQ(oss.str().c_str(), "(relative . today)");
m_option.set_value(RelativeDatePeriod::START_THIS_MONTH);
oss.str("");
oss << m_option;
EXPECT_STREQ(oss.str().c_str(), "relative . start-this-month");
EXPECT_STREQ(oss.str().c_str(), "(relative . start-this-month)");
m_option.set_value(RelativeDatePeriod::END_THIS_MONTH);
oss.str("");
oss << m_option;
EXPECT_STREQ(oss.str().c_str(), "relative . end-this-month");
EXPECT_STREQ(oss.str().c_str(), "(relative . end-this-month)");
m_option.set_value(RelativeDatePeriod::START_PREV_MONTH);
oss.str("");
oss << m_option;
EXPECT_STREQ(oss.str().c_str(), "relative . start-prev-month");
EXPECT_STREQ(oss.str().c_str(), "(relative . start-prev-month)");
m_option.set_value(RelativeDatePeriod::END_PREV_MONTH);
oss.str("");
oss << m_option;
EXPECT_STREQ(oss.str().c_str(), "relative . end-prev-month");
EXPECT_STREQ(oss.str().c_str(), "(relative . end-prev-month)");
m_option.set_value(RelativeDatePeriod::START_CURRENT_QUARTER);
oss.str("");
oss << m_option;
EXPECT_STREQ(oss.str().c_str(), "relative . start-current-quarter");
EXPECT_STREQ(oss.str().c_str(), "(relative . start-current-quarter)");
m_option.set_value(RelativeDatePeriod::END_CURRENT_QUARTER);
oss.str("");
oss << m_option;
EXPECT_STREQ(oss.str().c_str(), "relative . end-current-quarter");
EXPECT_STREQ(oss.str().c_str(), "(relative . end-current-quarter)");
m_option.set_value(RelativeDatePeriod::START_PREV_QUARTER);
oss.str("");
oss << m_option;
EXPECT_STREQ(oss.str().c_str(), "relative . start-prev-quarter");
EXPECT_STREQ(oss.str().c_str(), "(relative . start-prev-quarter)");
m_option.set_value(RelativeDatePeriod::END_PREV_QUARTER);
oss.str("");
oss << m_option;
EXPECT_STREQ(oss.str().c_str(), "relative . end-prev-quarter");
EXPECT_STREQ(oss.str().c_str(), "(relative . end-prev-quarter)");
m_option.set_value(RelativeDatePeriod::START_CAL_YEAR);
oss.str("");
oss << m_option;
EXPECT_STREQ(oss.str().c_str(), "relative . start-cal-year");
EXPECT_STREQ(oss.str().c_str(), "(relative . start-cal-year)");
m_option.set_value(RelativeDatePeriod::END_CAL_YEAR);
oss.str("");
oss << m_option;
EXPECT_STREQ(oss.str().c_str(), "relative . end-cal-year");
EXPECT_STREQ(oss.str().c_str(), "(relative . end-cal-year)");
m_option.set_value(RelativeDatePeriod::START_PREV_YEAR);
oss.str("");
oss << m_option;
EXPECT_STREQ(oss.str().c_str(), "relative . start-prev-year");
EXPECT_STREQ(oss.str().c_str(), "(relative . start-prev-year)");
m_option.set_value(RelativeDatePeriod::END_PREV_YEAR);
oss.str("");
oss << m_option;
EXPECT_STREQ(oss.str().c_str(), "relative . end-prev-year");
EXPECT_STREQ(oss.str().c_str(), "(relative . end-prev-year)");
m_option.set_value(RelativeDatePeriod::START_ACCOUNTING_PERIOD);
oss.str("");
oss << m_option;
EXPECT_STREQ(oss.str().c_str(), "relative . start-prev-fin-year");
EXPECT_STREQ(oss.str().c_str(), "(relative . start-prev-fin-year)");
m_option.set_value(RelativeDatePeriod::END_ACCOUNTING_PERIOD);
oss.str("");
oss << m_option;
EXPECT_STREQ(oss.str().c_str(), "relative . end-prev-fin-year");
EXPECT_STREQ(oss.str().c_str(), "(relative . end-prev-fin-year)");
}
TEST_F(GncDateOption, test_stream_in_absolute)

View File

@ -66,10 +66,32 @@
(let ((option (gnc:lookup-option options
\"foo\"
\"bar\")))
((lambda (o) (if o (gnc:option-set-value o '~s))) option))
((lambda (o) (if o (gnc:option-set-value o '~a))) option))
" value))
(define (test-currency-output-template value)
(format #f "
; Section: foo
(let ((option (gnc:lookup-option options
\"foo\"
\"bar\")))
((lambda (o) (if o (gnc:option-set-value o \"~a\"))) option))
" value))
(define (test-commodity-output-template value)
(format #f "
; Section: foo
(let ((option (gnc:lookup-option options
\"foo\"
\"bar\")))
((lambda (o) (if o (gnc:option-set-value o \"~a\" \"~a\"))) option))
" (string-split value #\:)))
(define (test-budget-output-template value)
(format #f "
; Section: foo
@ -90,7 +112,7 @@
(test-equal test-unchanged-section-output-template
(gnc:generate-restore-forms odb "options"))
(gnc:option-set-value (gnc:lookup-option odb "foo" "bar") value)
(test-equal (test-template value)
(test-equal (test-template (GncOption-serialize (gnc:lookup-option odb "foo" "bar")))
(gnc:generate-restore-forms odb "options"))))
(define (test-gnc-string-option-to-scheme)
@ -125,7 +147,7 @@ veritatis et quasi architecto beatae vitae dicta sunt, explicabo.")
(EUR (gnc-commodity-new book "European Union Euro" "CURRENCY" "EUR" "" 100)))
(gnc-commodity-table-insert table USD)
(gnc-commodity-table-insert table EUR)
(test-option-scheme-output gnc:make-currency-option test-literal-output-template
(test-option-scheme-output gnc:make-currency-option test-currency-output-template
USD EUR)
;; Garbage collection has already eaten USD and EUR.
(test-book-clear-data book "gnc-commodity-table")
@ -163,7 +185,7 @@ veritatis et quasi architecto beatae vitae dicta sunt, explicabo.")
(let* ((book (gnc-option-test-book-new))
(AAPL (gnc-commodity-new book "Apple" "NASDAQ" "AAPL" "" 1))
(FMAGX (gnc-commodity-new book "Fidelity Magellan Fund" "FUND" "FMAGX" "" 1000)))
(test-option-scheme-output gnc:make-commodity-option test-literal-output-template
(test-option-scheme-output gnc:make-commodity-option test-currency-output-template
AAPL FMAGX))
(test-end "test-gnc-commodity-option-to-scheme"))
@ -181,19 +203,19 @@ veritatis et quasi architecto beatae vitae dicta sunt, explicabo.")
(test-begin "test-gnc-date-option-to-scheme")
(let ((odb (gnc:new-options)))
(gnc:options-make-end-date! odb "foo" "bar" "baz" "Phoney Option")
(test-equal test-unchanged-section-output-template
(test-equal "Date Unchanged" test-unchanged-section-output-template
(gnc:generate-restore-forms odb "options"))
(let* ((option (gnc:lookup-option odb "foo" "bar"))
(test-template test-literal-output-template)
(time (gnc-dmy2time64 25 12 2020))
(value `(absolute . ,time)))
(gnc:option-set-value option value)
(test-equal (test-template (GncOption-get-scm-value option))
(test-equal "Absolute Date" (test-template (GncOption-serialize option))
(gnc:generate-restore-forms odb "options"))
(set! value '(relative . end-prev-year))
(gnc:option-set-value option value)
(test-equal value (GncOption-get-scm-value option))
(test-equal (test-template (GncOption-get-scm-value option))
(test-equal "Relative Date Value" value (GncOption-get-scm-value option))
(test-equal "Relative Date" (test-template (GncOption-serialize option))
(gnc:generate-restore-forms odb "options"))))
(test-end "test-gnc-date-option-to-scheme"))
@ -248,7 +270,7 @@ veritatis et quasi architecto beatae vitae dicta sunt, explicabo.")
(test-template test-literal-output-template)
(new-acclist (gnc-account-list-from-types book (list ACCT-TYPE-BANK))))
(gnc-option-set-value option new-acclist)
(test-equal (test-template (GncOption-get-scm-value option))
(test-equal (test-template (GncOption-serialize option))
(gnc:generate-restore-forms odb "options"))
))
(test-end "test-gnc-account-list-option-to-scheme"))
@ -271,7 +293,7 @@ veritatis et quasi architecto beatae vitae dicta sunt, explicabo.")
(test-template test-literal-output-template)
(new-acclist (gnc-account-list-from-types book (list ACCT-TYPE-BANK))))
(gnc-option-set-value option new-acclist)
(test-equal (test-template (GncOption-get-scm-value option))
(test-equal (test-template (GncOption-serialize option))
(gnc:generate-restore-forms odb "options"))
))
(test-end "test-gnc-account-sel-option-to-scheme"))
@ -301,7 +323,7 @@ veritatis et quasi architecto beatae vitae dicta sunt, explicabo.")
(gnc:generate-restore-forms odb "options"))
(let ((option (gnc:lookup-option odb "foo" "bar")))
(gnc:option-set-value option value)
(test-equal (test-template (GncOption-get-scm-value option))
(test-equal (test-template (GncOption-serialize option))
(gnc:generate-restore-forms odb "options"))))
(test-end "test-gnc-multichoice-option-to-scheme"))
@ -319,7 +341,7 @@ veritatis et quasi architecto beatae vitae dicta sunt, explicabo.")
(let ((option (gnc:lookup-option odb "foo" "bar"))
(test-template test-literal-output-template))
(gnc-option-set-value option '(ugly))
(test-equal (test-template (GncOption-get-scm-value option))
(test-equal (test-template (GncOption-serialize option))
(gnc:generate-restore-forms odb "options"))
))
(test-end "test-gnc-list-option-to-scheme"))
@ -340,7 +362,7 @@ veritatis et quasi architecto beatae vitae dicta sunt, explicabo.")
(let ((option (gnc:lookup-option odb "foo" "bar"))
(test-template test-literal-output-template))
(gnc-option-set-value option 42.0)
(test-equal (test-template (GncOption-get-scm-value option))
(test-equal (test-template (GncOption-serialize option))
(gnc:generate-restore-forms odb "options"))
))
(test-end "test-gnc-number-range-option-to-scheme"))
@ -361,7 +383,7 @@ veritatis et quasi architecto beatae vitae dicta sunt, explicabo.")
(let ((option (gnc:lookup-option odb "foo" "bar"))
(test-template test-literal-output-template))
(gnc-option-set-value option 420)
(test-equal (test-template (GncOption-get-scm-value option))
(test-equal (test-template (GncOption-serialize option))
(gnc:generate-restore-forms odb "options"))
))
(test-end "test-gnc-number-plot-size-option-to-scheme"))
@ -384,7 +406,7 @@ veritatis et quasi architecto beatae vitae dicta sunt, explicabo.")
(let ((option (gnc:lookup-option odb "__reg" "query"))
(test-template test-literal-output-template))
(gnc-option-set-value option (gnc-scm2query query-scm))
(test-equal (test-template (GncOption-get-scm-value option))
(test-equal (test-template (GncOption-serialize option))
(gnc:generate-restore-forms odb "options"))
))
(test-end "test-gnc-number-plot-size-option-to-scheme"))
@ -420,7 +442,7 @@ veritatis et quasi architecto beatae vitae dicta sunt, explicabo.")
(let ((option (gnc:lookup-option odb "foo" "bar"))
(test-template test-literal-output-template))
(gnc-option-set-value option '"13b305236443451a86c5366b7f890ecb")
(test-equal (test-template (GncOption-get-scm-value option))
(test-equal (test-template (GncOption-serialize option))
(gnc:generate-restore-forms odb "options"))
))
(test-end "test-gnc-owner-option-to-scheme"))