diff options
-rw-r--r-- | src/format.cc | 20 | ||||
-rw-r--r-- | src/unistring.h | 48 | ||||
-rw-r--r-- | test/unit/CMakeLists.txt | 2 | ||||
-rw-r--r-- | test/unit/t_format.cc | 122 |
4 files changed, 181 insertions, 11 deletions
diff --git a/src/format.cc b/src/format.cc index 5b9baa21..87168ea2 100644 --- a/src/format.cc +++ b/src/format.cc @@ -478,7 +478,7 @@ string format_t::truncate(const unistring& ustr, { assert(width < 4095); - const std::size_t len = ustr.length(); + const std::size_t len = ustr.width(); if (width == 0 || len <= width) return ustr.extract(); @@ -491,14 +491,14 @@ string format_t::truncate(const unistring& ustr, switch (style) { case TRUNCATE_LEADING: // This method truncates at the beginning. - buf << ".." << ustr.extract(len - (width - 2), width - 2); + buf << ".." << ustr.extract_by_width(len - (width - 2), width - 2); break; case TRUNCATE_MIDDLE: // This method truncates in the middle. - buf << ustr.extract(0, (width - 2) / 2) + buf << ustr.extract_by_width(0, (width - 2) / 2) << ".." - << ustr.extract(len - ((width - 2) / 2 + (width - 2) % 2), + << ustr.extract_by_width(len - ((width - 2) / 2 + (width - 2) % 2), (width - 2) / 2 + (width - 2) % 2); break; @@ -545,7 +545,7 @@ string format_t::truncate(const unistring& ustr, for (std::list<string>::iterator i = parts.begin(); i != parts.end(); i++) { - std::size_t l = unistring(*i).length(); + std::size_t l = unistring(*i).width(); DEBUG("format.abbrev", "Segment " << ++index << " is " << l << " chars wide"); lens.push_back(l); @@ -667,8 +667,8 @@ string format_t::truncate(const unistring& ustr, } unistring temp(*i); - if (temp.length() > *l) - result << temp.extract(0, *l) << ":"; + if (temp.width() > *l) + result << temp.extract_by_width(0, *l) << ":"; else result << *i << ":"; } @@ -677,8 +677,8 @@ string format_t::truncate(const unistring& ustr, // Even abbreviated its too big to show the last account, so // abbreviate all but the last and truncate at the beginning. unistring temp(result.str()); - assert(temp.length() > width - 2); - buf << ".." << temp.extract(temp.length() - (width - 2), width - 2); + assert(temp.width() > width - 2); + buf << ".." << temp.extract_by_width(temp.width() - (width - 2), width - 2); } else { buf << result.str(); } @@ -688,7 +688,7 @@ string format_t::truncate(const unistring& ustr, case TRUNCATE_TRAILING: // This method truncates at the end (the default). - buf << ustr.extract(0, width - 2) << ".."; + buf << ustr.extract_by_width(0, width - 2) << ".."; break; } diff --git a/src/unistring.h b/src/unistring.h index 8cc4a9cd..87b2f904 100644 --- a/src/unistring.h +++ b/src/unistring.h @@ -111,6 +111,54 @@ public: return utf8result; } + std::string extract_by_width(std::string::size_type begin, + std::size_t len) const + { + std::string utf8result; + std::size_t this_width = width(); + std::string::size_type this_len = length(); + + assert(begin <= this_width); + if (begin + len > this_width) + len = this_width - begin; + + std::size_t pos = 0; + std::size_t begin_idx = 0, end_idx = 0; + std::size_t head = 0, tail = 0; + for (std::size_t idx = 0; idx < this_len; ++idx) { + std::size_t w = mk_wcwidth(utf32chars[idx]); + + if (pos < begin) { + if (pos + w >= begin) { + head = std::min(pos + w, begin + len) - begin; + begin_idx = idx + 1; + } + } else if (pos < begin + len) { + if (pos + w > begin + len) { + tail = begin + len - pos; + end_idx = idx; + } + if (pos + w == begin + len) { + tail = 0; + end_idx = idx + 1; + } + } + pos += w; + } + + utf8result += std::string(head, '.'); + + if (begin_idx < end_idx) + utf8::unchecked::utf32to8 + (utf32chars.begin() + static_cast<std::string::difference_type>(begin_idx), + utf32chars.begin() + static_cast<std::string::difference_type>(end_idx), + std::back_inserter(utf8result)); + + utf8result += std::string(tail, '.'); + + return utf8result; + } + std::size_t find(const boost::uint32_t __s, std::size_t __pos = 0) const { std::size_t idx = 0; foreach (const boost::uint32_t& ch, utf32chars) { diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 1bd5e4b3..5570d5e1 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -8,7 +8,7 @@ endmacro(add_ledger_test _name) include_directories(${PROJECT_SOURCE_DIR}/src) if (BUILD_LIBRARY) - add_executable(UtilTests t_times.cc) + add_executable(UtilTests t_times.cc t_format.cc) if (HAVE_BOOST_PYTHON) target_link_libraries(UtilTests ${Python_LIBRARIES}) endif() diff --git a/test/unit/t_format.cc b/test/unit/t_format.cc new file mode 100644 index 00000000..142db92c --- /dev/null +++ b/test/unit/t_format.cc @@ -0,0 +1,122 @@ +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> + +#include <system.hh> + +#include "format.h" + +using namespace ledger; + +struct format_fixture { + format_fixture() { + format_t::default_style = format_t::TRUNCATE_TRAILING; + format_t::default_style_changed = false; + } + ~format_fixture() { + format_t::default_style = format_t::TRUNCATE_TRAILING; + format_t::default_style_changed = false; + } +}; + +BOOST_FIXTURE_TEST_SUITE(format, format_fixture) + +BOOST_AUTO_TEST_CASE(testTruncateTrailing) +{ + format_t::default_style = format_t::TRUNCATE_TRAILING; + unistring str("abcd:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 0, 0), "abcd:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 99, 0), "abcd:1234:ABCD"); + + BOOST_CHECK_EQUAL(format_t::truncate(str, 14, 0), "abcd:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 13, 0), "abcd:1234:A.."); + BOOST_CHECK_EQUAL(format_t::truncate(str, 12, 0), "abcd:1234:.."); + BOOST_CHECK_EQUAL(format_t::truncate(str, 11, 0), "abcd:1234.."); + BOOST_CHECK_EQUAL(format_t::truncate(str, 10, 0), "abcd:123.."); + + unistring ustr("中文:中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 14, 0), "中文:中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 13, 0), "中文:中文:..."); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 12, 0), "中文:中文:.."); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 11, 0), "中文:中文.."); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 10, 0), "中文:中..."); +} + +BOOST_AUTO_TEST_CASE(testTruncateMiddle) +{ + format_t::default_style = format_t::TRUNCATE_MIDDLE; + unistring str("abcd:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 0, 0), "abcd:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 99, 0), "abcd:1234:ABCD"); + + BOOST_CHECK_EQUAL(format_t::truncate(str, 14, 0), "abcd:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 13, 0), "abcd:..4:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 12, 0), "abcd:..:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 11, 0), "abcd..:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 10, 0), "abcd..ABCD"); + + unistring ustr("中文:中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 14, 0), "中文:中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 13, 0), "中文:...:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 12, 0), "中文:..:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 11, 0), "中文..:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 10, 0), "中文..中文"); +} + +BOOST_AUTO_TEST_CASE(testTruncateLeading) +{ + format_t::default_style = format_t::TRUNCATE_LEADING; + unistring str("abcd:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 0, 0), "abcd:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 99, 0), "abcd:1234:ABCD"); + + BOOST_CHECK_EQUAL(format_t::truncate(str, 14, 0), "abcd:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 13, 0), "..d:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 12, 0), "..:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 11, 0), "..1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 10, 0), "..234:ABCD"); + + unistring ustr("中文:中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 14, 0), "中文:中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 13, 0), "...:中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 12, 0), "..:中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 11, 0), "..中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 10, 0), "...文:中文"); +} + +BOOST_AUTO_TEST_CASE(testTruncateAbbreviate) +{ + format_t::default_style = format_t::ABBREVIATE; + unistring str("abcd:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 0, 2), "abcd:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 99, 2), "abcd:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 14, 2), "abcd:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 13, 2), "abc:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 12, 2), "ab:1234:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 11, 2), "ab:123:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 10, 2), "ab:12:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 9, 2), "..12:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 8, 2), "..2:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 7, 2), "..:ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 6, 2), "..ABCD"); + BOOST_CHECK_EQUAL(format_t::truncate(str, 5, 2), "..BCD"); + + unistring ustr("中文:中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 14, 2), "中文:中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 13, 2), "中.:中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 12, 2), "中:中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 11, 2), "中:中.:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 10, 2), "中:中:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 9, 2), "..中:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 8, 2), "...:中文"); + + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 14, 1), "中文:中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 13, 1), "中.:中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 12, 1), "中:中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 11, 1), ".:中文:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 10, 1), ".:中.:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 9, 1), ".:中:中文"); + BOOST_CHECK_EQUAL(format_t::truncate(ustr, 8, 1), ".:.:中文"); +} + +BOOST_AUTO_TEST_SUITE_END() |