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,8 +159,7 @@ bool format_condition::satisfied_by(long double number) const
|
|||
return number < value;
|
||||
case condition_type::not_equal:
|
||||
return number != value;
|
||||
case condition_type::none:
|
||||
default:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -198,9 +197,6 @@ void number_format_parser::parse()
|
|||
|
||||
break;
|
||||
|
||||
case number_format_token::token_type::bad:
|
||||
throw std::runtime_error("bad format");
|
||||
|
||||
case number_format_token::token_type::color:
|
||||
if (section.color != format_color::none
|
||||
|| section.condition.type != format_condition::condition_type::none
|
||||
|
@ -715,7 +711,13 @@ number_format_token number_format_parser::parse_next_token()
|
|||
token.string.push_back(format_string_[position_++]);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case '*':
|
||||
token.type = number_format_token::token_type::fill;
|
||||
token.string.push_back(format_string_[position_++]);
|
||||
|
||||
break;
|
||||
|
||||
case '0':
|
||||
case '#':
|
||||
case '?':
|
||||
|
@ -783,10 +785,18 @@ number_format_token number_format_parser::parse_next_token()
|
|||
|
||||
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_);
|
||||
}
|
||||
|
||||
token.string = format_string_.substr(start, end - start);
|
||||
if (end != start)
|
||||
{
|
||||
token.string.append(format_string_.substr(start, end - start));
|
||||
}
|
||||
|
||||
position_ = end + 1;
|
||||
|
||||
break;
|
||||
|
@ -910,9 +920,9 @@ format_placeholders number_format_parser::parse_placeholders(const std::string &
|
|||
|
||||
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;
|
||||
--i;
|
||||
|
@ -1140,6 +1150,11 @@ std::string number_formatter::fill_placeholders(const format_placeholders &p, lo
|
|||
number *= 100;
|
||||
}
|
||||
|
||||
if (p.thousands_scale > 0)
|
||||
{
|
||||
number /= std::pow(1000, p.thousands_scale);
|
||||
}
|
||||
|
||||
auto integer_part = static_cast<int>(number);
|
||||
|
||||
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;
|
||||
std::size_t fill_index = 0;
|
||||
bool fill = false;
|
||||
std::string fill_character;
|
||||
|
||||
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:
|
||||
result.append(part.string);
|
||||
break;
|
||||
case template_part::template_type::fill:
|
||||
fill = true;
|
||||
fill_index = result.size();
|
||||
fill_character = part.string;
|
||||
break;
|
||||
case template_part::template_type::general:
|
||||
{
|
||||
if (part.placeholders.type == format_placeholders::placeholders_type::fraction_integer)
|
||||
|
@ -1503,6 +1526,28 @@ std::string number_formatter::format_number(const format_code &format, long doub
|
|||
throw "unhandled";
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,14 @@ public:
|
|||
nf.set_format_string("\"any\"General");
|
||||
formatted = nf.format(-3.14, xlnt::calendar::windows_1900);
|
||||
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()
|
||||
|
@ -272,6 +280,14 @@ public:
|
|||
formatted = nf.format(2, xlnt::calendar::windows_1900);
|
||||
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");
|
||||
formatted = nf.format(0, xlnt::calendar::windows_1900);
|
||||
TS_ASSERT_EQUALS(formatted, "first0");
|
||||
|
@ -307,6 +323,36 @@ public:
|
|||
TS_ASSERT_EQUALS(formatted, "third3");
|
||||
formatted = nf.format(0, xlnt::calendar::windows_1900);
|
||||
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()
|
||||
|
@ -352,6 +398,65 @@ public:
|
|||
nf.set_format_string("[>3][>4]#,##0.00");
|
||||
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()
|
||||
{
|
||||
|
@ -362,6 +467,24 @@ public:
|
|||
|
||||
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);
|
||||
|
||||
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)
|
||||
|
@ -404,7 +527,7 @@ public:
|
|||
// #,##0.00
|
||||
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
|
||||
|
@ -464,49 +587,49 @@ public:
|
|||
// mm-dd-yy
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue
Block a user