mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
[price-quotes] Implement error codes for currency and quote failures.
This commit is contained in:
parent
6db7800ca5
commit
4c47e91180
@ -96,6 +96,8 @@ public:
|
|||||||
const std::string& version() noexcept { return m_version.empty() ? not_found : m_version; }
|
const std::string& version() noexcept { return m_version.empty() ? not_found : m_version; }
|
||||||
const QuoteSources& sources() noexcept { return m_sources; }
|
const QuoteSources& sources() noexcept { return m_sources; }
|
||||||
GList* sources_as_glist ();
|
GList* sources_as_glist ();
|
||||||
|
const QFVec& failures() noexcept;
|
||||||
|
std::string report_failures() noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string query_fq (const CommVec&);
|
std::string query_fq (const CommVec&);
|
||||||
@ -106,6 +108,7 @@ private:
|
|||||||
std::unique_ptr<GncQuoteSource> m_quotesource;
|
std::unique_ptr<GncQuoteSource> m_quotesource;
|
||||||
std::string m_version;
|
std::string m_version;
|
||||||
QuoteSources m_sources;
|
QuoteSources m_sources;
|
||||||
|
QFVec m_failures;
|
||||||
QofBook *m_book;
|
QofBook *m_book;
|
||||||
gnc_commodity *m_dflt_curr;
|
gnc_commodity *m_dflt_curr;
|
||||||
};
|
};
|
||||||
@ -129,6 +132,8 @@ private:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const std::string empty_string{};
|
||||||
|
|
||||||
GncFQQuoteSource::GncFQQuoteSource() :
|
GncFQQuoteSource::GncFQQuoteSource() :
|
||||||
c_cmd{bp::search_path("perl")},
|
c_cmd{bp::search_path("perl")},
|
||||||
c_fq_wrapper{std::string(gnc_path_get_bindir()) + "/finance-quote-wrapper"},
|
c_fq_wrapper{std::string(gnc_path_get_bindir()) + "/finance-quote-wrapper"},
|
||||||
@ -227,8 +232,9 @@ GncFQQuoteSource::run_cmd (const StrVec& args, const std::string& json_string) c
|
|||||||
|
|
||||||
/* GncQuotes implementation */
|
/* GncQuotes implementation */
|
||||||
GncQuotesImpl::GncQuotesImpl() : m_quotesource{new GncFQQuoteSource},
|
GncQuotesImpl::GncQuotesImpl() : m_quotesource{new GncFQQuoteSource},
|
||||||
m_version{}, m_sources{}, m_book{qof_session_get_book(gnc_get_current_session())},
|
m_version{}, m_sources{}, m_failures{},
|
||||||
m_dflt_curr{gnc_default_currency()}
|
m_book{qof_session_get_book(gnc_get_current_session())},
|
||||||
|
m_dflt_curr{gnc_default_currency()}
|
||||||
{
|
{
|
||||||
if (!m_quotesource->usable())
|
if (!m_quotesource->usable())
|
||||||
return;
|
return;
|
||||||
@ -283,6 +289,7 @@ GncQuotesImpl::fetch (gnc_commodity *comm)
|
|||||||
void
|
void
|
||||||
GncQuotesImpl::fetch (CommVec& commodities)
|
GncQuotesImpl::fetch (CommVec& commodities)
|
||||||
{
|
{
|
||||||
|
m_failures.clear();
|
||||||
if (commodities.empty())
|
if (commodities.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -290,6 +297,66 @@ GncQuotesImpl::fetch (CommVec& commodities)
|
|||||||
parse_quotes (quote_str, commodities);
|
parse_quotes (quote_str, commodities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QFVec&
|
||||||
|
GncQuotesImpl::failures() noexcept
|
||||||
|
{
|
||||||
|
return m_failures;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
explain(GncQuoteError err, const std::string& errmsg)
|
||||||
|
{
|
||||||
|
std::string retval;
|
||||||
|
switch (err)
|
||||||
|
{
|
||||||
|
case GncQuoteError::NO_RESULT:
|
||||||
|
if (errmsg.empty())
|
||||||
|
retval += _("Finance::Quote returned no data and set no error.");
|
||||||
|
else
|
||||||
|
retval += _("Finance::Quote returned an error: ") + errmsg;
|
||||||
|
break;
|
||||||
|
case GncQuoteError::QUOTE_FAILED:
|
||||||
|
if (errmsg.empty())
|
||||||
|
retval += _("Finance::Quote reported failure set no error.");
|
||||||
|
else
|
||||||
|
retval += _("Finance::Quote reported failure with error: ") + errmsg;
|
||||||
|
break;
|
||||||
|
case GncQuoteError::NO_CURRENCY:
|
||||||
|
retval += _("Finance::Quote returned a quote with no currency.");
|
||||||
|
break;
|
||||||
|
case GncQuoteError::UNKNOWN_CURRENCY:
|
||||||
|
retval += _("Finance::Quote returned a quote with a currency GnuCash doesn't know about.");
|
||||||
|
break;
|
||||||
|
case GncQuoteError::NO_PRICE:
|
||||||
|
retval += _("Finance::Quote returned a quote with no price element.");
|
||||||
|
break;
|
||||||
|
case GncQuoteError::PRICE_PARSE_FAILURE:
|
||||||
|
retval += _("Finance::Quote returned a quote with a price that GnuCash was unable to covert to a number.");
|
||||||
|
break;
|
||||||
|
case GncQuoteError::SUCCESS:
|
||||||
|
default:
|
||||||
|
retval += _("The quote has no error set.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
GncQuotesImpl::report_failures() noexcept
|
||||||
|
{
|
||||||
|
std::string retval{_("Quotes for the following commodities were unavailable or unusable:\n")};
|
||||||
|
std::for_each(m_failures.begin(), m_failures.end(),
|
||||||
|
[&retval](auto failure)
|
||||||
|
{
|
||||||
|
auto [ns, sym, reason, err] = failure;
|
||||||
|
retval += "* " + ns + ":" + sym + " " +
|
||||||
|
explain(reason, err) + "\n";
|
||||||
|
});
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* **** Private function implementations ****/
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
GncQuotesImpl::comm_vec_to_json_string (const CommVec& comm_vec) const
|
GncQuotesImpl::comm_vec_to_json_string (const CommVec& comm_vec) const
|
||||||
{
|
{
|
||||||
@ -368,11 +435,13 @@ get_price_and_type(PriceParams& p, const bpt::ptree& comm_pt)
|
|||||||
{
|
{
|
||||||
p.type = "last";
|
p.type = "last";
|
||||||
p.price = comm_pt.get_optional<std::string> (p.type);
|
p.price = comm_pt.get_optional<std::string> (p.type);
|
||||||
|
|
||||||
if (!p.price)
|
if (!p.price)
|
||||||
{
|
{
|
||||||
p.type = "nav";
|
p.type = "nav";
|
||||||
p.price = comm_pt.get_optional<std::string> (p.type);
|
p.price = comm_pt.get_optional<std::string> (p.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!p.price)
|
if (!p.price)
|
||||||
{
|
{
|
||||||
p.type = "price";
|
p.type = "price";
|
||||||
@ -472,11 +541,13 @@ get_price(const PriceParams& p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gnc_commodity*
|
static gnc_commodity*
|
||||||
get_currency(const PriceParams& p, QofBook* book)
|
get_currency(const PriceParams& p, QofBook* book, QFVec& failures)
|
||||||
{
|
{
|
||||||
if (!p.currency)
|
if (!p.currency)
|
||||||
{
|
{
|
||||||
PWARN("Skipped %s:%s - Finance::Quote didn't return a currency",
|
failures.emplace_back(p.ns, p.mnemonic, GncQuoteError::NO_CURRENCY,
|
||||||
|
empty_string);
|
||||||
|
PWARN("Skipped %s:%s - Finance::Quote returned a quote with no currency",
|
||||||
p.ns, p.mnemonic);
|
p.ns, p.mnemonic);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -487,6 +558,8 @@ get_currency(const PriceParams& p, QofBook* book)
|
|||||||
|
|
||||||
if (!currency)
|
if (!currency)
|
||||||
{
|
{
|
||||||
|
failures.emplace_back(p.ns, p.mnemonic,
|
||||||
|
GncQuoteError::UNKNOWN_CURRENCY, empty_string);
|
||||||
PWARN("Skipped %s:%s - failed to parse returned currency '%s'",
|
PWARN("Skipped %s:%s - failed to parse returned currency '%s'",
|
||||||
p.ns, p.mnemonic, p.currency->c_str());
|
p.ns, p.mnemonic, p.currency->c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -507,6 +580,8 @@ GncQuotesImpl::parse_one_quote(const bpt::ptree& pt, gnc_commodity* comm)
|
|||||||
auto comm_pt_ai{pt.find(p.mnemonic)};
|
auto comm_pt_ai{pt.find(p.mnemonic)};
|
||||||
if (comm_pt_ai == pt.not_found())
|
if (comm_pt_ai == pt.not_found())
|
||||||
{
|
{
|
||||||
|
m_failures.emplace_back(p.ns, p.mnemonic, GncQuoteError::NO_RESULT,
|
||||||
|
empty_string);
|
||||||
PINFO("Skipped %s:%s - Finance::Quote didn't return any data.",
|
PINFO("Skipped %s:%s - Finance::Quote didn't return any data.",
|
||||||
p.ns, p.mnemonic);
|
p.ns, p.mnemonic);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -517,6 +592,8 @@ GncQuotesImpl::parse_one_quote(const bpt::ptree& pt, gnc_commodity* comm)
|
|||||||
|
|
||||||
if (!p.success)
|
if (!p.success)
|
||||||
{
|
{
|
||||||
|
m_failures.emplace_back(p.ns, p.mnemonic, GncQuoteError::QUOTE_FAILED,
|
||||||
|
p.errormsg ? *p.errormsg : empty_string);
|
||||||
PWARN("Skipped %s:%s - Finance::Quote returned fetch failure.\nReason %s",
|
PWARN("Skipped %s:%s - Finance::Quote returned fetch failure.\nReason %s",
|
||||||
p.ns, p.mnemonic,
|
p.ns, p.mnemonic,
|
||||||
(p.errormsg ? p.errormsg->c_str() : "unknown"));
|
(p.errormsg ? p.errormsg->c_str() : "unknown"));
|
||||||
@ -525,6 +602,8 @@ GncQuotesImpl::parse_one_quote(const bpt::ptree& pt, gnc_commodity* comm)
|
|||||||
|
|
||||||
if (!p.price)
|
if (!p.price)
|
||||||
{
|
{
|
||||||
|
m_failures.emplace_back(p.ns, p.mnemonic,
|
||||||
|
GncQuoteError::NO_PRICE, empty_string);
|
||||||
PWARN("Skipped %s:%s - Finance::Quote didn't return a valid price",
|
PWARN("Skipped %s:%s - Finance::Quote didn't return a valid price",
|
||||||
p.ns, p.mnemonic);
|
p.ns, p.mnemonic);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -532,11 +611,16 @@ GncQuotesImpl::parse_one_quote(const bpt::ptree& pt, gnc_commodity* comm)
|
|||||||
|
|
||||||
auto price{get_price(p)};
|
auto price{get_price(p)};
|
||||||
if (!price)
|
if (!price)
|
||||||
|
{
|
||||||
|
m_failures.emplace_back(p.ns, p.mnemonic,
|
||||||
|
GncQuoteError::PRICE_PARSE_FAILURE,
|
||||||
|
empty_string);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
auto currency{get_currency(p, m_book)};
|
auto currency{get_currency(p, m_book, m_failures)};
|
||||||
if (!currency)
|
if (!currency)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto quotedt{calc_price_time(p)};
|
auto quotedt{calc_price_time(p)};
|
||||||
auto gnc_price = gnc_price_create (m_book);
|
auto gnc_price = gnc_price_create (m_book);
|
||||||
@ -737,3 +821,14 @@ GList* GncQuotes::sources_as_glist ()
|
|||||||
|
|
||||||
GncQuotes::~GncQuotes() = default;
|
GncQuotes::~GncQuotes() = default;
|
||||||
|
|
||||||
|
const QFVec&
|
||||||
|
GncQuotes::failures() noexcept
|
||||||
|
{
|
||||||
|
return m_impl->failures();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string
|
||||||
|
GncQuotes::report_failures() noexcept
|
||||||
|
{
|
||||||
|
return m_impl->report_failures();
|
||||||
|
}
|
||||||
|
@ -33,9 +33,27 @@ extern "C" {
|
|||||||
#include <qofbook.h>
|
#include <qofbook.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
using StrVec = std::vector <std::string>;
|
using StrVec = std::vector<std::string>;
|
||||||
using QuoteSources = StrVec;
|
using QuoteSources = StrVec;
|
||||||
using CmdOutput = std::pair <StrVec, StrVec>;
|
|
||||||
|
enum class GncQuoteError
|
||||||
|
{
|
||||||
|
SUCCESS,
|
||||||
|
NO_RESULT,
|
||||||
|
QUOTE_FAILED,
|
||||||
|
NO_CURRENCY,
|
||||||
|
UNKNOWN_CURRENCY,
|
||||||
|
NO_PRICE,
|
||||||
|
UNKNOWN_PRICE_TYPE,
|
||||||
|
PRICE_PARSE_FAILURE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** QuoteFailure elements are namespace, mnemonic, error code, and
|
||||||
|
* F::Q errormsg if there is one.
|
||||||
|
*/
|
||||||
|
using QuoteFailure = std::tuple<std::string, std::string,
|
||||||
|
GncQuoteError, std::string>;
|
||||||
|
using QFVec = std::vector<QuoteFailure>;
|
||||||
|
|
||||||
struct GncQuoteException : public std::runtime_error
|
struct GncQuoteException : public std::runtime_error
|
||||||
{
|
{
|
||||||
@ -93,6 +111,23 @@ public:
|
|||||||
*/
|
*/
|
||||||
GList* sources_as_glist () ;
|
GList* sources_as_glist () ;
|
||||||
|
|
||||||
|
/** Report the commodities for which quotes were requested but not successfully retrieved.
|
||||||
|
*
|
||||||
|
* This does not include requested commodities that didn't have a quote source.
|
||||||
|
*
|
||||||
|
* @return a reference to a vector of QuoteFailure tuples.
|
||||||
|
* @note The vector and its contents belong to the GncQuotes object and will be destroyed with it.
|
||||||
|
*/
|
||||||
|
const QFVec& failures() noexcept;
|
||||||
|
|
||||||
|
/* Report the commodities for which quotes were requested but not successfully retrieved.
|
||||||
|
*
|
||||||
|
* This does not include requested commodities that didn't have a quote source.
|
||||||
|
*
|
||||||
|
* @return A localized std::string with an intro and a list of the quote failures with a cause. The string is owned by the caller.
|
||||||
|
*/
|
||||||
|
const std::string report_failures() noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<GncQuotesImpl> m_impl;
|
std::unique_ptr<GncQuotesImpl> m_impl;
|
||||||
};
|
};
|
||||||
|
@ -141,7 +141,11 @@ TEST_F(GncQuotesTest, online_wiggle)
|
|||||||
GncQuotes quotes;
|
GncQuotes quotes;
|
||||||
quotes.fetch(m_book);
|
quotes.fetch(m_book);
|
||||||
auto pricedb{gnc_pricedb_get_db(m_book)};
|
auto pricedb{gnc_pricedb_get_db(m_book)};
|
||||||
EXPECT_EQ(3u, gnc_pricedb_get_num_prices(pricedb));
|
auto failures{quotes.failures()};
|
||||||
|
ASSERT_EQ(2u, failures.size());
|
||||||
|
EXPECT_EQ(GncQuoteError::QUOTE_FAILED, std::get<2>(failures[0]));
|
||||||
|
EXPECT_EQ(GncQuoteError::QUOTE_FAILED, std::get<2>(failures[1]));
|
||||||
|
EXPECT_EQ(2u, gnc_pricedb_get_num_prices(pricedb));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -153,6 +157,9 @@ TEST_F(GncQuotesTest, offline_wiggle)
|
|||||||
StrVec err_vec;
|
StrVec err_vec;
|
||||||
GncQuotesImpl quotes(m_book, std::make_unique<GncMockQuoteSource>(std::move(quote_vec), std::move(err_vec)));
|
GncQuotesImpl quotes(m_book, std::make_unique<GncMockQuoteSource>(std::move(quote_vec), std::move(err_vec)));
|
||||||
quotes.fetch(m_book);
|
quotes.fetch(m_book);
|
||||||
|
auto failures{quotes.failures()};
|
||||||
|
ASSERT_EQ(1u, failures.size());
|
||||||
|
EXPECT_EQ(GncQuoteError::QUOTE_FAILED, std::get<2>(failures[0]));
|
||||||
auto pricedb{gnc_pricedb_get_db(m_book)};
|
auto pricedb{gnc_pricedb_get_db(m_book)};
|
||||||
EXPECT_EQ(3u, gnc_pricedb_get_num_prices(pricedb));
|
EXPECT_EQ(3u, gnc_pricedb_get_num_prices(pricedb));
|
||||||
}
|
}
|
||||||
@ -169,7 +176,9 @@ TEST_F(GncQuotesTest, comvec_fetch)
|
|||||||
CommVec comms{hpe, aapl};
|
CommVec comms{hpe, aapl};
|
||||||
GncQuotesImpl quotes(m_book, std::make_unique<GncMockQuoteSource>(std::move(quote_vec), std::move(err_vec)));
|
GncQuotesImpl quotes(m_book, std::make_unique<GncMockQuoteSource>(std::move(quote_vec), std::move(err_vec)));
|
||||||
quotes.fetch(comms);
|
quotes.fetch(comms);
|
||||||
auto pricedb{gnc_pricedb_get_db(m_book)};
|
auto failures{quotes.failures()};
|
||||||
|
EXPECT_TRUE(failures.empty());
|
||||||
|
auto pricedb{gnc_pricedb_get_db(m_book)};
|
||||||
EXPECT_EQ(2u, gnc_pricedb_get_num_prices(pricedb));
|
EXPECT_EQ(2u, gnc_pricedb_get_num_prices(pricedb));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,6 +193,8 @@ TEST_F(GncQuotesTest, fetch_one_commodity)
|
|||||||
auto usd{gnc_commodity_table_lookup(commtable, "ISO4217", "USD")};
|
auto usd{gnc_commodity_table_lookup(commtable, "ISO4217", "USD")};
|
||||||
GncQuotesImpl quotes(m_book, std::make_unique<GncMockQuoteSource>(std::move(quote_vec), std::move(err_vec)));
|
GncQuotesImpl quotes(m_book, std::make_unique<GncMockQuoteSource>(std::move(quote_vec), std::move(err_vec)));
|
||||||
quotes.fetch(hpe);
|
quotes.fetch(hpe);
|
||||||
|
auto failures{quotes.failures()};
|
||||||
|
EXPECT_TRUE(failures.empty());
|
||||||
auto pricedb{gnc_pricedb_get_db(m_book)};
|
auto pricedb{gnc_pricedb_get_db(m_book)};
|
||||||
auto price{gnc_pricedb_lookup_latest(pricedb, hpe, usd)};
|
auto price{gnc_pricedb_lookup_latest(pricedb, hpe, usd)};
|
||||||
auto datetime{static_cast<time64>(GncDateTime("20220901160000"))};
|
auto datetime{static_cast<time64>(GncDateTime("20220901160000"))};
|
||||||
@ -208,8 +219,11 @@ TEST_F(GncQuotesTest, fetch_one_currency)
|
|||||||
auto usd{gnc_commodity_table_lookup(commtable, "ISO4217", "USD")};
|
auto usd{gnc_commodity_table_lookup(commtable, "ISO4217", "USD")};
|
||||||
GncQuotesImpl quotes(m_book, std::make_unique<GncMockQuoteSource>(std::move(quote_vec), std::move(err_vec)));
|
GncQuotesImpl quotes(m_book, std::make_unique<GncMockQuoteSource>(std::move(quote_vec), std::move(err_vec)));
|
||||||
quotes.fetch(eur);
|
quotes.fetch(eur);
|
||||||
|
auto failures{quotes.failures()};
|
||||||
|
EXPECT_TRUE(failures.empty());
|
||||||
auto pricedb{gnc_pricedb_get_db(m_book)};
|
auto pricedb{gnc_pricedb_get_db(m_book)};
|
||||||
auto price{gnc_pricedb_lookup_latest(pricedb, eur, usd)};
|
auto price{gnc_pricedb_lookup_latest(pricedb, eur, usd)};
|
||||||
|
EXPECT_EQ(1u, gnc_pricedb_get_num_prices(pricedb));
|
||||||
auto datetime{static_cast<time64>(GncDateTime())};
|
auto datetime{static_cast<time64>(GncDateTime())};
|
||||||
|
|
||||||
EXPECT_EQ(usd, gnc_price_get_currency(price));
|
EXPECT_EQ(usd, gnc_price_get_currency(price));
|
||||||
@ -222,3 +236,65 @@ TEST_F(GncQuotesTest, fetch_one_currency)
|
|||||||
EXPECT_STREQ("last", gnc_price_get_typestr(price));
|
EXPECT_STREQ("last", gnc_price_get_typestr(price));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(GncQuotesTest, no_currency)
|
||||||
|
{
|
||||||
|
StrVec quote_vec{
|
||||||
|
"{\"HPE\":{\"date\":\"09/01/2022\",\"last\":13.37,\"success\":1}}"
|
||||||
|
};
|
||||||
|
StrVec err_vec;
|
||||||
|
auto commtable{gnc_commodity_table_get_table(m_book)};
|
||||||
|
auto hpe{gnc_commodity_table_lookup(commtable, "NYSE", "HPE")};
|
||||||
|
auto usd{gnc_commodity_table_lookup(commtable, "ISO4217", "USD")};
|
||||||
|
GncQuotesImpl quotes(m_book, std::make_unique<GncMockQuoteSource>(std::move(quote_vec), std::move(err_vec)));
|
||||||
|
quotes.fetch(hpe);
|
||||||
|
auto failures{quotes.failures()};
|
||||||
|
ASSERT_EQ(1u, failures.size());
|
||||||
|
EXPECT_EQ(GncQuoteError::NO_CURRENCY, std::get<2>(failures[0]));
|
||||||
|
auto pricedb{gnc_pricedb_get_db(m_book)};
|
||||||
|
EXPECT_EQ(0u, gnc_pricedb_get_num_prices(pricedb));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(GncQuotesTest, bad_currency)
|
||||||
|
{
|
||||||
|
StrVec quote_vec{
|
||||||
|
"{\"HPE\":{\"date\":\"09/01/2022\",\"last\":13.37,\"currency\":\"BTC\",\"success\":1}}"
|
||||||
|
};
|
||||||
|
StrVec err_vec;
|
||||||
|
auto commtable{gnc_commodity_table_get_table(m_book)};
|
||||||
|
auto hpe{gnc_commodity_table_lookup(commtable, "NYSE", "HPE")};
|
||||||
|
auto usd{gnc_commodity_table_lookup(commtable, "ISO4217", "USD")};
|
||||||
|
GncQuotesImpl quotes(m_book, std::make_unique<GncMockQuoteSource>(std::move(quote_vec), std::move(err_vec)));
|
||||||
|
quotes.fetch(hpe);
|
||||||
|
auto failures{quotes.failures()};
|
||||||
|
ASSERT_EQ(1u, failures.size());
|
||||||
|
EXPECT_EQ(GncQuoteError::UNKNOWN_CURRENCY, std::get<2>(failures[0]));
|
||||||
|
auto pricedb{gnc_pricedb_get_db(m_book)};
|
||||||
|
EXPECT_EQ(0u, gnc_pricedb_get_num_prices(pricedb));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(GncQuotesTest, no_date)
|
||||||
|
{
|
||||||
|
StrVec quote_vec{
|
||||||
|
"{\"HPE\":{\"last\":13.37,\"currency\":\"USD\",\"success\":1}}"
|
||||||
|
};
|
||||||
|
StrVec err_vec;
|
||||||
|
auto commtable{gnc_commodity_table_get_table(m_book)};
|
||||||
|
auto hpe{gnc_commodity_table_lookup(commtable, "NYSE", "HPE")};
|
||||||
|
auto usd{gnc_commodity_table_lookup(commtable, "ISO4217", "USD")};
|
||||||
|
GncQuotesImpl quotes(m_book, std::make_unique<GncMockQuoteSource>(std::move(quote_vec), std::move(err_vec)));
|
||||||
|
quotes.fetch(hpe);
|
||||||
|
auto failures{quotes.failures()};
|
||||||
|
EXPECT_TRUE(failures.empty());
|
||||||
|
auto pricedb{gnc_pricedb_get_db(m_book)};
|
||||||
|
auto price{gnc_pricedb_lookup_latest(pricedb, hpe, usd)};
|
||||||
|
auto datetime{static_cast<time64>(GncDateTime())};
|
||||||
|
|
||||||
|
EXPECT_EQ(usd, gnc_price_get_currency(price));
|
||||||
|
EXPECT_EQ(datetime, gnc_price_get_time64(price));
|
||||||
|
EXPECT_EQ(PRICE_SOURCE_FQ, gnc_price_get_source(price));
|
||||||
|
EXPECT_TRUE(gnc_numeric_equal(GncNumeric{1337, 100},
|
||||||
|
gnc_price_get_value(price)));
|
||||||
|
EXPECT_STREQ("Finance::Quote", gnc_price_get_source_string(price));
|
||||||
|
EXPECT_STREQ("last", gnc_price_get_typestr(price));
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user