diff --git a/include/xlnt/utils/exceptions.hpp b/include/xlnt/utils/exceptions.hpp index 70a92ecd..bd800269 100644 --- a/include/xlnt/utils/exceptions.hpp +++ b/include/xlnt/utils/exceptions.hpp @@ -63,15 +63,6 @@ public: invalid_sheet_title(const std::string &title); }; -/// -/// Exception for incorrectly formatted named ranges. -/// -class XLNT_CLASS invalid_named_range : public exception -{ -public: - invalid_named_range(); -}; - /// /// Exception when a referenced number format is not in the stylesheet. /// diff --git a/source/detail/number_formatter.cpp b/source/detail/number_formatter.cpp index 52b9a9df..2d2a54ac 100644 --- a/source/detail/number_formatter.cpp +++ b/source/detail/number_formatter.cpp @@ -160,8 +160,6 @@ bool format_condition::satisfied_by(long double number) const return number < value; case condition_type::not_equal: return number != value; - default: - return false; } } @@ -199,24 +197,26 @@ void number_format_parser::parse() break; case number_format_token::token_type::color: - if (section.color != format_color::none - || section.condition.type != format_condition::condition_type::none - || section.locale != format_locale::none + if (section.has_color + || section.has_condition + || section.has_locale || !section.parts.empty()) { throw std::runtime_error("color should be the first part of a format"); } + section.has_color = true; section.color = color_from_string(token.string); break; case number_format_token::token_type::locale: { - if (section.locale != format_locale::none) + if (section.has_locale) { throw std::runtime_error("multiple locales"); } + section.has_locale = true; auto parsed_locale = locale_from_string(token.string); section.locale = parsed_locale.first; @@ -233,11 +233,12 @@ void number_format_parser::parse() case number_format_token::token_type::condition: { - if (section.condition.type != format_condition::condition_type::none) + if (section.has_condition) { throw std::runtime_error("multiple conditions"); } + section.has_condition = true; std::string value; if (token.string.front() == '<') @@ -439,9 +440,6 @@ void number_format_parser::parse() finalize(); return; - - default: - break; } token = parse_next_token(); @@ -524,6 +522,7 @@ void number_format_parser::finalize() fractional_seconds = true; } + //TODO this block needs improvement if (part.type == template_part::template_type::month_number || part.type == template_part::template_type::month_number_leading_zero) { @@ -552,8 +551,8 @@ void number_format_parser::finalize() if (previous.type == template_part::template_type::text && previous.string == ":" - && (before_previous.type == template_part::template_type::hour || - before_previous.type == template_part::template_type::hour_leading_zero)) + && (before_previous.type == template_part::template_type::hour_leading_zero + || before_previous.type == template_part::template_type::hour)) { fix = true; leading_zero = part.type == template_part::template_type::month_number_leading_zero; @@ -848,9 +847,9 @@ void number_format_parser::validate() if (codes_.size() > 2) { - if (codes_[0].condition.type != format_condition::condition_type::none && - codes_[1].condition.type != format_condition::condition_type::none && - codes_[2].condition.type != format_condition::condition_type::none) + if (codes_[0].has_condition + && codes_[1].has_condition + && codes_[2].has_condition) { throw std::runtime_error("format should have a maximum of two codes with conditions"); } @@ -1045,7 +1044,7 @@ number_formatter::number_formatter(const std::string &format_string, xlnt::calen std::string number_formatter::format_number(long double number) { - if (format_[0].condition.type != format_condition::condition_type::none) + if (format_[0].has_condition) { if (format_[0].condition.satisfied_by(number)) { @@ -1057,7 +1056,7 @@ std::string number_formatter::format_number(long double number) return std::string(11, '#'); } - if (format_[1].condition.type == format_condition::condition_type::none + if (!format_[1].has_condition || format_[1].condition.satisfied_by(number)) { return format_number(format_[1], number); @@ -1125,10 +1124,12 @@ std::string number_formatter::format_text(const std::string &text) std::string number_formatter::fill_placeholders(const format_placeholders &p, long double number) { + std::string result; + if (p.type == format_placeholders::placeholders_type::general || p.type == format_placeholders::placeholders_type::text) { - auto result = std::to_string(number); + result = std::to_string(number); while (result.back() == '0') { @@ -1155,13 +1156,11 @@ std::string number_formatter::fill_placeholders(const format_placeholders &p, lo auto integer_part = static_cast(number); - switch (p.type) + if (p.type == format_placeholders::placeholders_type::integer_only + || p.type == format_placeholders::placeholders_type::integer_part + || p.type == format_placeholders::placeholders_type::fraction_integer) { - case format_placeholders::placeholders_type::integer_only: - case format_placeholders::placeholders_type::integer_part: - case format_placeholders::placeholders_type::fraction_integer: - { - auto result = std::to_string(integer_part); + result = std::to_string(integer_part); while (result.size() < p.num_zeros) { @@ -1195,16 +1194,13 @@ std::string number_formatter::fill_placeholders(const format_placeholders &p, lo { result.push_back('%'); } - - return result; } - - case format_placeholders::placeholders_type::fractional_part: + else if (p.type == format_placeholders::placeholders_type::fractional_part) { auto fractional_part = number - integer_part; - auto result = fractional_part == 0 ? std::string(".") : std::to_string(fractional_part).substr(1); + result = fractional_part == 0 ? std::string(".") : std::to_string(fractional_part).substr(1); - while (result.back() == '0' || result.size() > (p.num_zeros + p.num_optionals + 1)) + while (result.back() == '0' || result.size() > (p.num_zeros + p.num_optionals + p.num_spaces + 1)) { result.pop_back(); } @@ -1214,7 +1210,7 @@ std::string number_formatter::fill_placeholders(const format_placeholders &p, lo result.push_back('0'); } - while (result.size() < p.num_zeros + p.num_spaces + 1) + while (result.size() < p.num_zeros + p.num_optionals + p.num_spaces + 1) { result.push_back(' '); } @@ -1223,13 +1219,9 @@ std::string number_formatter::fill_placeholders(const format_placeholders &p, lo { result.push_back('%'); } - - return result; } - default: - return ""; - } + return result; } std::string number_formatter::fill_scientific_placeholders(const format_placeholders &integer_part, @@ -1591,9 +1583,6 @@ std::string number_formatter::format_number(const format_code &format, long doub case template_part::template_type::day_name: result.append(day_names->at(dt.weekday() - 1)); break; - - case template_part::template_type::bad: - throw std::runtime_error("bad format"); } } diff --git a/source/detail/number_formatter.hpp b/source/detail/number_formatter.hpp index c9be063b..ff2428a8 100644 --- a/source/detail/number_formatter.hpp +++ b/source/detail/number_formatter.hpp @@ -36,7 +36,6 @@ namespace detail { enum class format_color { - none, black, blue, cyan, @@ -105,7 +104,6 @@ enum class format_color enum class format_locale { - none = 0, arabic_saudi_arabia = 0x401, bulgarian = 0x402, catalan = 0x403, @@ -218,14 +216,13 @@ struct XLNT_CLASS format_condition { enum class condition_type { - none, less_than, less_or_equal, equal, not_equal, greater_than, greater_or_equal - } type = condition_type::none; + } type = condition_type::not_equal; long double value = 0; @@ -236,7 +233,6 @@ struct format_placeholders { enum class placeholders_type { - bad, general, text, integer_only, @@ -248,7 +244,7 @@ struct format_placeholders scientific_significand, scientific_exponent_plus, scientific_exponent_minus - } type = placeholders_type::bad; + } type = placeholders_type::general; bool use_comma_separator = false; bool percentage = false; @@ -264,7 +260,6 @@ struct number_format_token { enum class token_type { - bad, color, locale, condition, @@ -275,7 +270,7 @@ struct number_format_token datetime, end_section, end - } type = token_type::bad; + } type = token_type::end; std::string string; }; @@ -284,7 +279,6 @@ struct template_part { enum class template_type { - bad, text, fill, space, @@ -313,7 +307,7 @@ struct template_part elapsed_hours, elapsed_minutes, elapsed_seconds - } type = template_type::bad; + } type = template_type::general; std::string string; format_placeholders placeholders; @@ -321,8 +315,11 @@ struct template_part struct format_code { - format_color color = format_color::none; - format_locale locale = format_locale::none; + bool has_color = false; + format_color color = format_color::black; + bool has_locale = false; + format_locale locale = format_locale::english_united_states; + bool has_condition = false; format_condition condition; bool is_datetime = false; bool is_timedelta = false; diff --git a/source/styles/tests/test_number_format.hpp b/source/styles/tests/test_number_format.hpp index df365327..d0c2d1ee 100644 --- a/source/styles/tests/test_number_format.hpp +++ b/source/styles/tests/test_number_format.hpp @@ -1,11 +1,10 @@ #pragma once #include +#include #include -#include "pugixml.hpp" #include -#include class test_number_format : public CxxTest::TestSuite { @@ -375,16 +374,6 @@ public: TS_ASSERT_EQUALS(formatted, "text"); } - void test_bad_part() - { - xlnt::detail::template_part bad_part; - xlnt::detail::format_code bad_code; - bad_code.parts.push_back(bad_part); - xlnt::detail::number_formatter formatter("", xlnt::calendar::windows_1900); - formatter.format_ = { bad_code }; - TS_ASSERT_THROWS(formatter.format_number(1), std::runtime_error); - } - void test_conditional_format() { xlnt::number_format nf; @@ -487,7 +476,53 @@ public: formatted = nf.format(6, xlnt::calendar::windows_1900); TS_ASSERT_EQUALS(formatted, "a---------b"); } - + + void test_placeholders_zero() + { + xlnt::number_format nf; + nf.set_format_string("00"); + auto formatted = nf.format(6, xlnt::calendar::windows_1900); + TS_ASSERT_EQUALS(formatted, "06"); + + nf.set_format_string("00"); + formatted = nf.format(63, xlnt::calendar::windows_1900); + TS_ASSERT_EQUALS(formatted, "63"); + } + + void test_placeholders_space() + { + xlnt::number_format nf; + nf.set_format_string("?0"); + auto formatted = nf.format(6, xlnt::calendar::windows_1900); + TS_ASSERT_EQUALS(formatted, " 6"); + + nf.set_format_string("?0"); + formatted = nf.format(63, xlnt::calendar::windows_1900); + TS_ASSERT_EQUALS(formatted, "63"); + + nf.set_format_string("?0"); + formatted = nf.format(637, xlnt::calendar::windows_1900); + TS_ASSERT_EQUALS(formatted, "637"); + + nf.set_format_string("0.?"); + formatted = nf.format(6, xlnt::calendar::windows_1900); + TS_ASSERT_EQUALS(formatted, "6. "); + + nf.set_format_string("0.0?"); + formatted = nf.format(6.3, xlnt::calendar::windows_1900); + TS_ASSERT_EQUALS(formatted, "6.3 "); + formatted = nf.format(6.34, xlnt::calendar::windows_1900); + TS_ASSERT_EQUALS(formatted, "6.34"); + } + + void test_scientific() + { + xlnt::number_format nf; + nf.set_format_string("0E-0"); + auto formatted = nf.format(6.1, xlnt::calendar::windows_1900); + TS_ASSERT_EQUALS(formatted, "6.1E0"); + } + void test_locale_currency() { xlnt::number_format nf; @@ -627,14 +662,6 @@ public: TS_ASSERT_THROWS(nf.format(1.2, xlnt::calendar::windows_1900), std::runtime_error); } - void test_none_condition() - { - xlnt::detail::format_condition f; - f.type = xlnt::detail::format_condition::condition_type::none; - f.value = 3; - TS_ASSERT(!f.satisfied_by(3)); - } - void format_and_test(const xlnt::number_format &nf, const std::array &expect) { long double positive = 42503.1234; diff --git a/source/utils/exceptions.cpp b/source/utils/exceptions.cpp index 50eea8cf..0e147de9 100644 --- a/source/utils/exceptions.cpp +++ b/source/utils/exceptions.cpp @@ -52,11 +52,6 @@ invalid_data_type::invalid_data_type() { } -invalid_named_range::invalid_named_range() - : exception("named range not found or not owned by this worksheet") -{ -} - invalid_file::invalid_file(const std::string &filename) : exception(std::string("couldn't open file: (") + filename + ")") {