mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
test some number formatting edge cases
This commit is contained in:
parent
8970bfaffb
commit
053508e8b7
|
@ -159,7 +159,6 @@ bool format_condition::satisfied_by(long double number) const
|
||||||
return number < value;
|
return number < value;
|
||||||
case condition_type::not_equal:
|
case condition_type::not_equal:
|
||||||
return number != value;
|
return number != value;
|
||||||
case condition_type::none:
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -198,9 +197,6 @@ void number_format_parser::parse()
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case number_format_token::token_type::bad:
|
|
||||||
throw std::runtime_error("bad format");
|
|
||||||
|
|
||||||
case number_format_token::token_type::color:
|
case number_format_token::token_type::color:
|
||||||
if (section.color != format_color::none
|
if (section.color != format_color::none
|
||||||
|| section.condition.type != format_condition::condition_type::none
|
|| section.condition.type != format_condition::condition_type::none
|
||||||
|
@ -716,6 +712,12 @@ number_format_token number_format_parser::parse_next_token()
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case '*':
|
||||||
|
token.type = number_format_token::token_type::fill;
|
||||||
|
token.string.push_back(format_string_[position_++]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case '0':
|
case '0':
|
||||||
case '#':
|
case '#':
|
||||||
case '?':
|
case '?':
|
||||||
|
@ -783,10 +785,18 @@ number_format_token number_format_parser::parse_next_token()
|
||||||
|
|
||||||
while (end != std::string::npos && format_string_[end - 1] == '\\')
|
while (end != std::string::npos && format_string_[end - 1] == '\\')
|
||||||
{
|
{
|
||||||
|
token.string.append(format_string_.substr(start, end - start - 1));
|
||||||
|
token.string.push_back('"');
|
||||||
|
position_ = end + 1;
|
||||||
|
start = position_;
|
||||||
end = format_string_.find('"', position_);
|
end = format_string_.find('"', position_);
|
||||||
}
|
}
|
||||||
|
|
||||||
token.string = format_string_.substr(start, end - start);
|
if (end != start)
|
||||||
|
{
|
||||||
|
token.string.append(format_string_.substr(start, end - start));
|
||||||
|
}
|
||||||
|
|
||||||
position_ = end + 1;
|
position_ = end + 1;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -910,9 +920,9 @@ format_placeholders number_format_parser::parse_placeholders(const std::string &
|
||||||
|
|
||||||
if (!comma_indices.empty())
|
if (!comma_indices.empty())
|
||||||
{
|
{
|
||||||
std::size_t i = placeholders_string.size();
|
std::size_t i = placeholders_string.size() - 1;
|
||||||
|
|
||||||
while (i == comma_indices.back())
|
while (!comma_indices.empty() && i == comma_indices.back())
|
||||||
{
|
{
|
||||||
++p.thousands_scale;
|
++p.thousands_scale;
|
||||||
--i;
|
--i;
|
||||||
|
@ -1140,6 +1150,11 @@ std::string number_formatter::fill_placeholders(const format_placeholders &p, lo
|
||||||
number *= 100;
|
number *= 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p.thousands_scale > 0)
|
||||||
|
{
|
||||||
|
number /= std::pow(1000, p.thousands_scale);
|
||||||
|
}
|
||||||
|
|
||||||
auto integer_part = static_cast<int>(number);
|
auto integer_part = static_cast<int>(number);
|
||||||
|
|
||||||
if (p.type == format_placeholders::placeholders_type::integer_only
|
if (p.type == format_placeholders::placeholders_type::integer_only
|
||||||
|
@ -1365,6 +1380,9 @@ std::string number_formatter::format_number(const format_code &format, long doub
|
||||||
}
|
}
|
||||||
|
|
||||||
bool improper_fraction = true;
|
bool improper_fraction = true;
|
||||||
|
std::size_t fill_index = 0;
|
||||||
|
bool fill = false;
|
||||||
|
std::string fill_character;
|
||||||
|
|
||||||
for (std::size_t i = 0; i < format.parts.size(); ++i)
|
for (std::size_t i = 0; i < format.parts.size(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -1378,6 +1396,11 @@ std::string number_formatter::format_number(const format_code &format, long doub
|
||||||
case template_part::template_type::text:
|
case template_part::template_type::text:
|
||||||
result.append(part.string);
|
result.append(part.string);
|
||||||
break;
|
break;
|
||||||
|
case template_part::template_type::fill:
|
||||||
|
fill = true;
|
||||||
|
fill_index = result.size();
|
||||||
|
fill_character = part.string;
|
||||||
|
break;
|
||||||
case template_part::template_type::general:
|
case template_part::template_type::general:
|
||||||
{
|
{
|
||||||
if (part.placeholders.type == format_placeholders::placeholders_type::fraction_integer)
|
if (part.placeholders.type == format_placeholders::placeholders_type::fraction_integer)
|
||||||
|
@ -1504,6 +1527,28 @@ std::string number_formatter::format_number(const format_code &format, long doub
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::size_t width = 11;
|
||||||
|
|
||||||
|
if (fill && result.size() < width)
|
||||||
|
{
|
||||||
|
auto remaining = width - result.size();
|
||||||
|
|
||||||
|
std::string fill_string(remaining, fill_character.front());
|
||||||
|
|
||||||
|
// A UTF-8 character could be multiple bytes
|
||||||
|
if (fill_character.size() > 1)
|
||||||
|
{
|
||||||
|
fill_string.clear();
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < remaining; ++i)
|
||||||
|
{
|
||||||
|
fill_string.append(fill_character);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result.substr(0, fill_index) + fill_string + result.substr(fill_index);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,14 @@ public:
|
||||||
nf.set_format_string("\"any\"General");
|
nf.set_format_string("\"any\"General");
|
||||||
formatted = nf.format(-3.14, xlnt::calendar::windows_1900);
|
formatted = nf.format(-3.14, xlnt::calendar::windows_1900);
|
||||||
TS_ASSERT_EQUALS(formatted, "-any3.14");
|
TS_ASSERT_EQUALS(formatted, "-any3.14");
|
||||||
|
|
||||||
|
nf.set_format_string("\"positive\"General;\"negative\"General;\"zero\"General");
|
||||||
|
formatted = nf.format(3.14, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "positive3.14");
|
||||||
|
formatted = nf.format(-3.14, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "negative3.14");
|
||||||
|
formatted = nf.format(0, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "zero0");
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_simple_date()
|
void test_simple_date()
|
||||||
|
@ -272,6 +280,14 @@ public:
|
||||||
formatted = nf.format(2, xlnt::calendar::windows_1900);
|
formatted = nf.format(2, xlnt::calendar::windows_1900);
|
||||||
TS_ASSERT_EQUALS(formatted, "third2");
|
TS_ASSERT_EQUALS(formatted, "third2");
|
||||||
|
|
||||||
|
nf.set_format_string("[>=5]\"first\"General");
|
||||||
|
formatted = nf.format(4, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "###########");
|
||||||
|
|
||||||
|
nf.set_format_string("[>=5]\"first\"General;[>=4]\"second\"General");
|
||||||
|
formatted = nf.format(3, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "###########");
|
||||||
|
|
||||||
nf.set_format_string("[<1]\"first\"General;[<5]\"second\"General;\"third\"General");
|
nf.set_format_string("[<1]\"first\"General;[<5]\"second\"General;\"third\"General");
|
||||||
formatted = nf.format(0, xlnt::calendar::windows_1900);
|
formatted = nf.format(0, xlnt::calendar::windows_1900);
|
||||||
TS_ASSERT_EQUALS(formatted, "first0");
|
TS_ASSERT_EQUALS(formatted, "first0");
|
||||||
|
@ -307,6 +323,36 @@ public:
|
||||||
TS_ASSERT_EQUALS(formatted, "third3");
|
TS_ASSERT_EQUALS(formatted, "third3");
|
||||||
formatted = nf.format(0, xlnt::calendar::windows_1900);
|
formatted = nf.format(0, xlnt::calendar::windows_1900);
|
||||||
TS_ASSERT_EQUALS(formatted, "third0");
|
TS_ASSERT_EQUALS(formatted, "third0");
|
||||||
|
|
||||||
|
nf.set_format_string("[<>1]\"first\"General;[<>2]\"second\"General");
|
||||||
|
formatted = nf.format(2, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "first2");
|
||||||
|
formatted = nf.format(1, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "second1");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_space()
|
||||||
|
{
|
||||||
|
xlnt::number_format nf;
|
||||||
|
nf.set_format_string("_(General_)");
|
||||||
|
auto formatted = nf.format(6, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, " 6 ");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_fill()
|
||||||
|
{
|
||||||
|
xlnt::number_format nf;
|
||||||
|
nf.set_format_string("*-General");
|
||||||
|
auto formatted = nf.format(6, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "----------6");
|
||||||
|
|
||||||
|
nf.set_format_string("General*-");
|
||||||
|
formatted = nf.format(6, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "6----------");
|
||||||
|
|
||||||
|
nf.set_format_string("\\a*-\\b");
|
||||||
|
formatted = nf.format(6, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "a---------b");
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_locale_currency()
|
void test_locale_currency()
|
||||||
|
@ -353,6 +399,65 @@ public:
|
||||||
TS_ASSERT_THROWS(nf.format(1.2, xlnt::calendar::windows_1900), std::runtime_error);
|
TS_ASSERT_THROWS(nf.format(1.2, xlnt::calendar::windows_1900), std::runtime_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_escaped_quote_string()
|
||||||
|
{
|
||||||
|
xlnt::number_format nf;
|
||||||
|
|
||||||
|
nf.set_format_string("\"\\\"\"General");
|
||||||
|
auto formatted = nf.format(6, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "\"6");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_thousands_scale()
|
||||||
|
{
|
||||||
|
xlnt::number_format nf;
|
||||||
|
|
||||||
|
nf.set_format_string("#,");
|
||||||
|
auto formatted = nf.format(61234, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "61");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_colors()
|
||||||
|
{
|
||||||
|
xlnt::number_format nf;
|
||||||
|
|
||||||
|
nf.set_format_string("[Black]#");
|
||||||
|
auto formatted = nf.format(6, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "6");
|
||||||
|
|
||||||
|
nf.set_format_string("[Black]#");
|
||||||
|
formatted = nf.format(6, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "6");
|
||||||
|
|
||||||
|
nf.set_format_string("[Blue]#");
|
||||||
|
formatted = nf.format(6, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "6");
|
||||||
|
|
||||||
|
nf.set_format_string("[Green]#");
|
||||||
|
formatted = nf.format(6, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "6");
|
||||||
|
|
||||||
|
nf.set_format_string("[Red]#");
|
||||||
|
formatted = nf.format(6, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "6");
|
||||||
|
|
||||||
|
nf.set_format_string("[Cyan]#");
|
||||||
|
formatted = nf.format(6, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "6");
|
||||||
|
|
||||||
|
nf.set_format_string("[Magenta]#");
|
||||||
|
formatted = nf.format(6, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "6");
|
||||||
|
|
||||||
|
nf.set_format_string("[Yellow]#");
|
||||||
|
formatted = nf.format(6, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "6");
|
||||||
|
|
||||||
|
nf.set_format_string("[Color15]#");
|
||||||
|
formatted = nf.format(6, xlnt::calendar::windows_1900);
|
||||||
|
TS_ASSERT_EQUALS(formatted, "6");
|
||||||
|
}
|
||||||
|
|
||||||
void test_bad_format()
|
void test_bad_format()
|
||||||
{
|
{
|
||||||
xlnt::number_format nf;
|
xlnt::number_format nf;
|
||||||
|
@ -362,6 +467,24 @@ public:
|
||||||
|
|
||||||
nf.set_format_string("\"first\"General;\"second\"General;\"third\"General;\"fourth\"General;\"fifth\"General");
|
nf.set_format_string("\"first\"General;\"second\"General;\"third\"General;\"fourth\"General;\"fifth\"General");
|
||||||
TS_ASSERT_THROWS(nf.format(1.2, xlnt::calendar::windows_1900), std::runtime_error);
|
TS_ASSERT_THROWS(nf.format(1.2, xlnt::calendar::windows_1900), std::runtime_error);
|
||||||
|
|
||||||
|
nf.set_format_string("[");
|
||||||
|
TS_ASSERT_THROWS(nf.format(1.2, xlnt::calendar::windows_1900), std::runtime_error);
|
||||||
|
|
||||||
|
nf.set_format_string("[]");
|
||||||
|
TS_ASSERT_THROWS(nf.format(1.2, xlnt::calendar::windows_1900), std::runtime_error);
|
||||||
|
|
||||||
|
nf.set_format_string("[Redd]");
|
||||||
|
TS_ASSERT_THROWS(nf.format(1.2, xlnt::calendar::windows_1900), std::runtime_error);
|
||||||
|
|
||||||
|
nf.set_format_string("[$1]#");
|
||||||
|
TS_ASSERT_THROWS(nf.format(1.2, xlnt::calendar::windows_1900), std::runtime_error);
|
||||||
|
|
||||||
|
nf.set_format_string("Gee");
|
||||||
|
TS_ASSERT_THROWS(nf.format(1.2, xlnt::calendar::windows_1900), std::runtime_error);
|
||||||
|
|
||||||
|
nf.set_format_string("!");
|
||||||
|
TS_ASSERT_THROWS(nf.format(1.2, xlnt::calendar::windows_1900), std::runtime_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void format_and_test(const xlnt::number_format &nf, const std::array<std::string, 4> &expect)
|
void format_and_test(const xlnt::number_format &nf, const std::array<std::string, 4> &expect)
|
||||||
|
@ -404,7 +527,7 @@ public:
|
||||||
// #,##0.00
|
// #,##0.00
|
||||||
void test_builtin_format_4()
|
void test_builtin_format_4()
|
||||||
{
|
{
|
||||||
format_and_test(xlnt::number_format::from_builtin_id(4), {{"42,503.12", "-42,503.12", "0.00", "text"}});
|
format_and_test(xlnt::number_format::number_comma_separated1(), {{"42,503.12", "-42,503.12", "0.00", "text"}});
|
||||||
}
|
}
|
||||||
|
|
||||||
// #,##0;-#,##0
|
// #,##0;-#,##0
|
||||||
|
@ -464,49 +587,49 @@ public:
|
||||||
// mm-dd-yy
|
// mm-dd-yy
|
||||||
void test_builtin_format_14()
|
void test_builtin_format_14()
|
||||||
{
|
{
|
||||||
format_and_test(xlnt::number_format::from_builtin_id(14), {{"05-13-16", "###########", "01-00-00", "text"}});
|
format_and_test(xlnt::number_format::date_xlsx14(), {{"05-13-16", "###########", "01-00-00", "text"}});
|
||||||
}
|
}
|
||||||
|
|
||||||
// d-mmm-yy
|
// d-mmm-yy
|
||||||
void test_builtin_format_15()
|
void test_builtin_format_15()
|
||||||
{
|
{
|
||||||
format_and_test(xlnt::number_format::from_builtin_id(15), {{"13-May-16", "###########", "0-Jan-00", "text"}});
|
format_and_test(xlnt::number_format::date_xlsx15(), {{"13-May-16", "###########", "0-Jan-00", "text"}});
|
||||||
}
|
}
|
||||||
|
|
||||||
// d-mmm
|
// d-mmm
|
||||||
void test_builtin_format_16()
|
void test_builtin_format_16()
|
||||||
{
|
{
|
||||||
format_and_test(xlnt::number_format::from_builtin_id(16), {{"13-May", "###########", "0-Jan", "text"}});
|
format_and_test(xlnt::number_format::date_xlsx16(), {{"13-May", "###########", "0-Jan", "text"}});
|
||||||
}
|
}
|
||||||
|
|
||||||
// mmm-yy
|
// mmm-yy
|
||||||
void test_builtin_format_17()
|
void test_builtin_format_17()
|
||||||
{
|
{
|
||||||
format_and_test(xlnt::number_format::from_builtin_id(17), {{"May-16", "###########", "Jan-00", "text"}});
|
format_and_test(xlnt::number_format::date_xlsx17(), {{"May-16", "###########", "Jan-00", "text"}});
|
||||||
}
|
}
|
||||||
|
|
||||||
// h:mm AM/PM
|
// h:mm AM/PM
|
||||||
void test_builtin_format_18()
|
void test_builtin_format_18()
|
||||||
{
|
{
|
||||||
format_and_test(xlnt::number_format::from_builtin_id(18), {{"2:57 AM", "###########", "12:00 AM", "text"}});
|
format_and_test(xlnt::number_format::date_time1(), {{"2:57 AM", "###########", "12:00 AM", "text"}});
|
||||||
}
|
}
|
||||||
|
|
||||||
// h:mm:ss AM/PM
|
// h:mm:ss AM/PM
|
||||||
void test_builtin_format_19()
|
void test_builtin_format_19()
|
||||||
{
|
{
|
||||||
format_and_test(xlnt::number_format::from_builtin_id(19), {{"2:57:42 AM", "###########", "12:00:00 AM", "text"}});
|
format_and_test(xlnt::number_format::date_time2(), {{"2:57:42 AM", "###########", "12:00:00 AM", "text"}});
|
||||||
}
|
}
|
||||||
|
|
||||||
// h:mm
|
// h:mm
|
||||||
void test_builtin_format_20()
|
void test_builtin_format_20()
|
||||||
{
|
{
|
||||||
format_and_test(xlnt::number_format::from_builtin_id(20), {{"2:57", "###########", "0:00", "text"}});
|
format_and_test(xlnt::number_format::date_time3(), {{"2:57", "###########", "0:00", "text"}});
|
||||||
}
|
}
|
||||||
|
|
||||||
// h:mm:ss
|
// h:mm:ss
|
||||||
void test_builtin_format_21()
|
void test_builtin_format_21()
|
||||||
{
|
{
|
||||||
format_and_test(xlnt::number_format::from_builtin_id(21), {{"2:57:42", "###########", "0:00:00", "text"}});
|
format_and_test(xlnt::number_format::date_time4(), {{"2:57:42", "###########", "0:00:00", "text"}});
|
||||||
}
|
}
|
||||||
|
|
||||||
// m/d/yy h:mm
|
// m/d/yy h:mm
|
||||||
|
|
Loading…
Reference in New Issue
Block a user