From 49c4e725dcd132d3549696ad53da22b8ad08903c Mon Sep 17 00:00:00 2001 From: Crzyrndm Date: Mon, 2 Jul 2018 10:29:58 +1200 Subject: [PATCH 1/9] All unimplemented functions under cell/ --- include/xlnt/worksheet/range.hpp | 4 ++-- source/cell/cell.cpp | 26 ++++++++++++++++++++++++++ source/cell/rich_text.cpp | 5 +++++ source/worksheet/range.cpp | 2 +- 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/include/xlnt/worksheet/range.hpp b/include/xlnt/worksheet/range.hpp index 0abebbcf..02b88a13 100644 --- a/include/xlnt/worksheet/range.hpp +++ b/include/xlnt/worksheet/range.hpp @@ -290,11 +290,11 @@ public: /// bool operator!=(const range &comparand) const; -private: + private: /// /// The worksheet this range is within /// - worksheet ws_; + class worksheet ws_; /// /// The reference of this range diff --git a/source/cell/cell.cpp b/source/cell/cell.cpp index 4426a5dc..96c1a021 100644 --- a/source/cell/cell.cpp +++ b/source/cell/cell.cpp @@ -434,6 +434,18 @@ void cell::hyperlink(xlnt::cell target) value(cell_address); } +void cell::hyperlink(xlnt::range target) +{ + // TODO: should this computed value be a method on a cell? + const auto range_address = target.worksheet().title() + "!" + target.reference().to_string(); + + d_->hyperlink_ = detail::hyperlink_impl(); + d_->hyperlink_.get().relationship = xlnt::relationship("", relationship_type::hyperlink, + uri(""), uri(range_address), target_mode::internal); + d_->hyperlink_.get().display = range_address; + value(range_address); +} + void cell::formula(const std::string &formula) { if (formula.empty()) @@ -472,6 +484,15 @@ void cell::clear_formula() } } +std::string cell::error() const +{ + if (d_->type_ != type::error) + { + throw xlnt::exception("called error() when cell type is not error"); + } + return value(); +} + void cell::error(const std::string &error) { if (error.length() == 0 || error[0] != '#') @@ -743,6 +764,11 @@ calendar cell::base_date() const return workbook().base_date(); } +bool operator==(std::nullptr_t, const cell &cell) +{ + return cell.data_type() == cell::type::empty; +} + XLNT_API std::ostream &operator<<(std::ostream &stream, const xlnt::cell &cell) { return stream << cell.to_string(); diff --git a/source/cell/rich_text.cpp b/source/cell/rich_text.cpp index ad5cccbd..5c3ff4fb 100644 --- a/source/cell/rich_text.cpp +++ b/source/cell/rich_text.cpp @@ -65,6 +65,11 @@ std::vector rich_text::runs() const return runs_; } +void rich_text::runs(const std::vector &new_runs) +{ + runs_ = new_runs; +} + void rich_text::add_run(const rich_text_run &t) { runs_.push_back(t); diff --git a/source/worksheet/range.cpp b/source/worksheet/range.cpp index fa8e8eb2..1226cc0b 100644 --- a/source/worksheet/range.cpp +++ b/source/worksheet/range.cpp @@ -31,7 +31,7 @@ namespace xlnt { -range::range(worksheet ws, const range_reference &reference, major_order order, bool skip_null) +range::range(class worksheet ws, const range_reference &reference, major_order order, bool skip_null) : ws_(ws), ref_(reference), order_(order), From 95ca51e5c8c5a86b6814cde790114b2afb1fcd2c Mon Sep 17 00:00:00 2001 From: Crzyrndm Date: Mon, 2 Jul 2018 10:43:09 +1200 Subject: [PATCH 2/9] unimplemented functions under styles/ --- source/styles/color.cpp | 10 ++++++++++ source/styles/conditional_format.cpp | 15 +++++++++++++++ source/styles/protection.cpp | 20 ++++++++++++++++++++ source/styles/style.cpp | 5 +++++ 4 files changed, 50 insertions(+) diff --git a/source/styles/color.cpp b/source/styles/color.cpp index e9e1c739..3eccd394 100644 --- a/source/styles/color.cpp +++ b/source/styles/color.cpp @@ -57,6 +57,11 @@ std::size_t indexed_color::index() const return index_; } +void indexed_color::index(std::size_t index) +{ + index_ = index; +} + // theme_color implementation theme_color::theme_color(std::size_t index) : index_(index) @@ -68,6 +73,11 @@ std::size_t theme_color::index() const return index_; } +void theme_color::index(std::size_t index) +{ + index_ = index; +} + // rgb_color implementation std::string rgb_color::hex_string() const diff --git a/source/styles/conditional_format.cpp b/source/styles/conditional_format.cpp index 52736b47..9a5852d5 100644 --- a/source/styles/conditional_format.cpp +++ b/source/styles/conditional_format.cpp @@ -81,6 +81,11 @@ bool conditional_format::operator!=(const conditional_format &other) const return !(*this == other); } +bool conditional_format::has_border() const +{ + return d_->border_id.is_set(); +} + xlnt::border conditional_format::border() const { return d_->parent->borders.at(d_->border_id.get()); @@ -92,6 +97,11 @@ conditional_format conditional_format::border(const xlnt::border &new_border) return *this; } +bool conditional_format::has_fill() const +{ + return d_->fill_id.is_set(); +} + xlnt::fill conditional_format::fill() const { return d_->parent->fills.at(d_->fill_id.get()); @@ -103,6 +113,11 @@ conditional_format conditional_format::fill(const xlnt::fill &new_fill) return *this; } +bool conditional_format::has_font() const +{ + return d_->font_id.is_set(); +} + xlnt::font conditional_format::font() const { return d_->parent->fonts.at(d_->font_id.get()); diff --git a/source/styles/protection.cpp b/source/styles/protection.cpp index 96b32785..3d1fd326 100644 --- a/source/styles/protection.cpp +++ b/source/styles/protection.cpp @@ -26,6 +26,26 @@ namespace xlnt { +protection protection::unlocked_and_visible() +{ + return protection(); +} + +protection protection::locked_and_visible() +{ + return protection().locked(true); +} + +protection protection::unlocked_and_hidden() +{ + return protection().hidden(true); +} + +protection protection::locked_and_hidden() +{ + return protection().locked(true).hidden(true); +} + protection::protection() : locked_(false), hidden_(false) { diff --git a/source/styles/style.cpp b/source/styles/style.cpp index d10f6896..10f145b8 100755 --- a/source/styles/style.cpp +++ b/source/styles/style.cpp @@ -66,6 +66,11 @@ std::size_t style::builtin_id() const return d_->builtin_id.get(); } +bool style::builtin() const +{ + d_->builtin_id.is_set(); +} + std::string style::name() const { return d_->name; From 3d9e887d4ac1d71ceb5f3b388ab6259184d77649 Mon Sep 17 00:00:00 2001 From: Crzyrndm Date: Mon, 2 Jul 2018 10:49:01 +1200 Subject: [PATCH 3/9] unimplemented functions under utils/ --- include/xlnt/utils/exceptions.hpp | 2 +- source/utils/variant.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/xlnt/utils/exceptions.hpp b/include/xlnt/utils/exceptions.hpp index bf088480..0618a0fb 100644 --- a/include/xlnt/utils/exceptions.hpp +++ b/include/xlnt/utils/exceptions.hpp @@ -120,7 +120,7 @@ public: /// /// Default constructor. /// - missing_number_format(); + missing_number_format() = default; /// /// Default copy constructor. diff --git a/source/utils/variant.cpp b/source/utils/variant.cpp index 44d349be..5565fe94 100644 --- a/source/utils/variant.cpp +++ b/source/utils/variant.cpp @@ -41,7 +41,7 @@ variant::variant(const char *value) : variant(std::string(value)) { } -variant::variant(std::int32_t value) +variant::variant(int32_t value) : type_(type::i4), i4_value_(value) { From f9b2ca5929c1d6fa76e9f6508c9c2336e46e1c72 Mon Sep 17 00:00:00 2001 From: Crzyrndm Date: Mon, 2 Jul 2018 10:55:32 +1200 Subject: [PATCH 4/9] unimplemented functions under workbook/ --- include/xlnt/workbook/document_security.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xlnt/workbook/document_security.hpp b/include/xlnt/workbook/document_security.hpp index 7f9cec49..b6d5624b 100644 --- a/include/xlnt/workbook/document_security.hpp +++ b/include/xlnt/workbook/document_security.hpp @@ -67,7 +67,7 @@ public: /// /// Constructs a new document security object with default values. /// - document_security(); + document_security() = default; /// /// If true, the workbook is locked for revisions. From 650bfeb7dd6d84d9396c72a17e6a0f10f6500bc6 Mon Sep 17 00:00:00 2001 From: Crzyrndm Date: Mon, 2 Jul 2018 10:57:51 +1200 Subject: [PATCH 5/9] unimplemented functions under worksheet -- NOTE: ctor was removed because it can't have been in use, and is duplicated by the overload below it. A pair parameter is only optimal in a very limited number of use cases, and then only slightly over the begin/end overload --- include/xlnt/worksheet/range_reference.hpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/include/xlnt/worksheet/range_reference.hpp b/include/xlnt/worksheet/range_reference.hpp index f5956c75..93643f68 100644 --- a/include/xlnt/worksheet/range_reference.hpp +++ b/include/xlnt/worksheet/range_reference.hpp @@ -56,12 +56,7 @@ public: /// top_left:bottom_right. /// explicit range_reference(const char *range_string); - - /// - /// Constructs a range reference from a pair of cell references. - /// - explicit range_reference(const std::pair &reference_pair); - + /// /// Constructs a range reference from cell references indicating top /// left and bottom right coordinates of the range. From 1390d6a76e0162b87d102d04b1f82c403919df78 Mon Sep 17 00:00:00 2001 From: Crzyrndm Date: Mon, 2 Jul 2018 11:09:41 +1200 Subject: [PATCH 6/9] unimplemented functions in range and path --- source/utils/path.cpp | 16 ++++++++++++++++ source/worksheet/range.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/source/utils/path.cpp b/source/utils/path.cpp index e846a6e5..b67ab977 100644 --- a/source/utils/path.cpp +++ b/source/utils/path.cpp @@ -141,6 +141,22 @@ path::path(const std::string &path_string) { } +path::path(const std::string &path_string, char sep) + : internal_(path_string) +{ + char curr_sep = guess_separator(); + if (curr_sep != sep) + { + for (char& c : internal_) // simple find and replace + { + if (c == curr_sep) + { + c = sep; + } + } + } +} + // general attributes bool path::is_relative() const diff --git a/source/worksheet/range.cpp b/source/worksheet/range.cpp index 1226cc0b..7649edc7 100644 --- a/source/worksheet/range.cpp +++ b/source/worksheet/range.cpp @@ -69,6 +69,11 @@ cell_vector range::operator[](std::size_t index) return vector(index); } +const cell_vector range::operator[](std::size_t index) const +{ + return vector(index); +} + const worksheet &range::target_worksheet() const { return ws_; @@ -112,6 +117,22 @@ cell_vector range::vector(std::size_t vector_index) return cell_vector(ws_, cursor, ref_, order_, skip_null_, false); } +const cell_vector range::vector(std::size_t vector_index) const +{ + auto cursor = ref_.top_left(); + + if (order_ == major_order::row) + { + cursor.row(cursor.row() + static_cast(vector_index)); + } + else + { + cursor.column_index(cursor.column_index() + static_cast(vector_index)); + } + + return cell_vector(ws_, cursor, ref_, order_, skip_null_, false); +} + bool range::contains(const cell_reference &ref) { return ref_.top_left().column_index() <= ref.column_index() @@ -188,6 +209,11 @@ cell range::cell(const cell_reference &ref) return (*this)[ref.row() - 1][ref.column().index - 1]; } +const cell range::cell(const cell_reference &ref) const +{ + return (*this)[ref.row() - 1][ref.column().index - 1]; +} + cell_vector range::front() { return *begin(); From 054f509f7a57bccee07dd3db790202a413f5cd35 Mon Sep 17 00:00:00 2001 From: Crzyrndm Date: Mon, 2 Jul 2018 20:57:09 +1200 Subject: [PATCH 7/9] fix missing return statement --- source/styles/style.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/styles/style.cpp b/source/styles/style.cpp index 10f145b8..5ba4db51 100755 --- a/source/styles/style.cpp +++ b/source/styles/style.cpp @@ -68,7 +68,7 @@ std::size_t style::builtin_id() const bool style::builtin() const { - d_->builtin_id.is_set(); + return d_->builtin_id.is_set(); } std::string style::name() const From 03020cc7931d6103de69b90a465832ac7645bc3b Mon Sep 17 00:00:00 2001 From: Crzyrndm Date: Mon, 2 Jul 2018 21:06:12 +1200 Subject: [PATCH 8/9] improved hyperlink implementation - hyperlinks to cells and ranges are complete - hyperlink::display is now set as well as the cell value (in excel these can be different) -- if a cell is empty, display is equal to value text -- if a cell has a value, display can be just about anything - This version copies excel in that display is completely ignored once value is set - All hyperlink tests are now part of the cell test suite (not the worksheet test suite which the majority were previously located) --- include/xlnt/cell/cell.hpp | 11 +-- include/xlnt/cell/hyperlink.hpp | 14 +++- source/cell/cell.cpp | 68 +++++++++++-------- source/cell/hyperlink.cpp | 39 +++++++++-- .../detail/implementations/hyperlink_impl.hpp | 7 +- tests/cell/cell_test_suite.cpp | 53 ++++++++++++++- tests/workbook/serialization_test_suite.cpp | 2 +- tests/worksheet/worksheet_test_suite.cpp | 45 ------------ 8 files changed, 144 insertions(+), 95 deletions(-) diff --git a/include/xlnt/cell/cell.hpp b/include/xlnt/cell/cell.hpp index f77f6d31..8b85625b 100644 --- a/include/xlnt/cell/cell.hpp +++ b/include/xlnt/cell/cell.hpp @@ -262,26 +262,21 @@ public: /// class hyperlink hyperlink() const; - /// - /// Adds a hyperlink to this cell pointing to the URL of the given value. - /// - void hyperlink(const std::string &url); - /// /// Adds a hyperlink to this cell pointing to the URI of the given value and sets /// the text value of the cell to the given parameter. /// - void hyperlink(const std::string &url, const std::string &display); + void hyperlink(const std::string &url, const std::string &display = ""); /// /// Adds an internal hyperlink to this cell pointing to the given cell. /// - void hyperlink(xlnt::cell target); + void hyperlink(xlnt::cell target, const std::string& display = ""); /// /// Adds an internal hyperlink to this cell pointing to the given range. /// - void hyperlink(xlnt::range target); + void hyperlink(xlnt::range target, const std::string& display = ""); /// /// Returns true if this cell has a hyperlink set. diff --git a/include/xlnt/cell/hyperlink.hpp b/include/xlnt/cell/hyperlink.hpp index 8034098b..e77f8830 100644 --- a/include/xlnt/cell/hyperlink.hpp +++ b/include/xlnt/cell/hyperlink.hpp @@ -44,12 +44,22 @@ class XLNT_API hyperlink public: bool external() const; class relationship relationship() const; + // external target std::string url() const; + // internal target std::string target_range() const; + + bool has_display() const; void display(const std::string &value); - std::string display() const; + const std::string& display() const; + + bool has_tooltip() const; void tooltip(const std::string &value); - std::string tooltip() const; + const std::string& tooltip() const; + + bool has_location() const; + void location(const std::string &value); + const std::string& location() const; private: friend class cell; diff --git a/source/cell/cell.cpp b/source/cell/cell.cpp index 96c1a021..f080107b 100644 --- a/source/cell/cell.cpp +++ b/source/cell/cell.cpp @@ -372,7 +372,7 @@ hyperlink cell::hyperlink() const return xlnt::hyperlink(&d_->hyperlink_.get()); } -void cell::hyperlink(const std::string &url) +void cell::hyperlink(const std::string &url, const std::string &display) { if (url.empty() || std::find(url.begin(), url.end(), ':') == url.end()) { @@ -388,7 +388,8 @@ void cell::hyperlink(const std::string &url) auto relationships = manifest.relationships(ws.path(), relationship_type::hyperlink); auto relation = std::find_if(relationships.cbegin(), relationships.cend(), [&url](xlnt::relationship rel) { return rel.target().path().string() == url; }); - if (relation != relationships.end()) { + if (relation != relationships.end()) + { d_->hyperlink_.get().relationship = *relation; } else @@ -400,29 +401,20 @@ void cell::hyperlink(const std::string &url) target_mode::external); // TODO: make manifest::register_relationship return the created relationship instead of rel id d_->hyperlink_.get().relationship = manifest.relationship(ws.path(), rel_id); - } - - if (!has_value()) // hyperlink on an empty cell sets the value to the hyperlink string + } + // if a value is already present, the display string is ignored + if (has_value()) { - value(url); + d_->hyperlink_.get().display.set(to_string()); + } + else + { + d_->hyperlink_.get().display.set(display.empty() ? url : display); + value(hyperlink().display()); } } -void cell::hyperlink(const std::string &url, const std::string &display) -{ - if (!display.empty()) // if the display string isn't empty use that - { - value(display); - } - else // empty display string sets the value to the link text - { - value(url); - } - hyperlink(url); - d_->hyperlink_.get().display = display; -} - -void cell::hyperlink(xlnt::cell target) +void cell::hyperlink(xlnt::cell target, const std::string& display) { // TODO: should this computed value be a method on a cell? const auto cell_address = target.worksheet().title() + "!" + target.reference().to_string(); @@ -430,11 +422,19 @@ void cell::hyperlink(xlnt::cell target) d_->hyperlink_ = detail::hyperlink_impl(); d_->hyperlink_.get().relationship = xlnt::relationship("", relationship_type::hyperlink, uri(""), uri(cell_address), target_mode::internal); - d_->hyperlink_.get().display = cell_address; - value(cell_address); + // if a value is already present, the display string is ignored + if (has_value()) + { + d_->hyperlink_.get().display.set(to_string()); + } + else + { + d_->hyperlink_.get().display.set(display.empty() ? cell_address : display); + value(hyperlink().display()); + } } -void cell::hyperlink(xlnt::range target) +void cell::hyperlink(xlnt::range target, const std::string &display) { // TODO: should this computed value be a method on a cell? const auto range_address = target.worksheet().title() + "!" + target.reference().to_string(); @@ -442,8 +442,17 @@ void cell::hyperlink(xlnt::range target) d_->hyperlink_ = detail::hyperlink_impl(); d_->hyperlink_.get().relationship = xlnt::relationship("", relationship_type::hyperlink, uri(""), uri(range_address), target_mode::internal); - d_->hyperlink_.get().display = range_address; - value(range_address); + + // if a value is already present, the display string is ignored + if (has_value()) + { + d_->hyperlink_.get().display.set(to_string()); + } + else + { + d_->hyperlink_.get().display.set(display.empty() ? range_address : display); + value(hyperlink().display()); + } } void cell::formula(const std::string &formula) @@ -828,8 +837,11 @@ void cell::value(const std::string &value_string, bool infer_type) void cell::clear_format() { - format().d_->references -= format().d_->references > 0 ? 1 : 0; - d_->format_.clear(); + if (d_->format_.is_set()) + { + format().d_->references -= format().d_->references > 0 ? 1 : 0; + d_->format_.clear(); + } } void cell::clear_style() diff --git a/source/cell/hyperlink.cpp b/source/cell/hyperlink.cpp index 8d28d84e..28539107 100644 --- a/source/cell/hyperlink.cpp +++ b/source/cell/hyperlink.cpp @@ -67,24 +67,49 @@ bool hyperlink::external() const return d_->relationship.target_mode() == target_mode::external; } -void hyperlink::display(const std::string &value) +bool hyperlink::has_display() const { - d_->display = value; + return d_->display.is_set(); } -std::string hyperlink::display() const +void hyperlink::display(const std::string &value) { - return d_->display; + d_->display.set(value); +} + +const std::string& hyperlink::display() const +{ + return d_->display.get(); +} + +bool hyperlink::has_tooltip() const +{ + return d_->tooltip.is_set(); } void hyperlink::tooltip(const std::string &value) { - d_->tooltip = value; + d_->tooltip.set(value); } -std::string hyperlink::tooltip() const +const std::string& hyperlink::tooltip() const { - return d_->tooltip; + return d_->tooltip.get(); +} + +bool hyperlink::has_location() const +{ + return d_->location.is_set(); +} + +void hyperlink::location(const std::string &value) +{ + d_->location.set(value); +} + +const std::string &hyperlink::location() const +{ + return d_->location.get(); } } // namespace xlnt diff --git a/source/detail/implementations/hyperlink_impl.hpp b/source/detail/implementations/hyperlink_impl.hpp index 84172986..274997c3 100644 --- a/source/detail/implementations/hyperlink_impl.hpp +++ b/source/detail/implementations/hyperlink_impl.hpp @@ -26,15 +26,18 @@ #include #include +#include namespace xlnt { namespace detail { +// [serialised] struct hyperlink_impl { xlnt::relationship relationship; - std::string tooltip; - std::string display; + xlnt::optional location; + xlnt::optional tooltip; + xlnt::optional display; }; inline bool operator==(const hyperlink_impl &lhs, const hyperlink_impl &rhs) diff --git a/tests/cell/cell_test_suite.cpp b/tests/cell/cell_test_suite.cpp index a0753a49..8729134e 100644 --- a/tests/cell/cell_test_suite.cpp +++ b/tests/cell/cell_test_suite.cpp @@ -37,11 +37,13 @@ #include #include #include +#include #include #include #include #include + class cell_test_suite : public test_suite { public: @@ -665,13 +667,60 @@ private: { xlnt::workbook wb; auto cell = wb.active_sheet().cell("A1"); + cell.value(123); xlnt_assert(!cell.has_hyperlink()); xlnt_assert_throws(cell.hyperlink(), xlnt::invalid_attribute); xlnt_assert_throws(cell.hyperlink("notaurl"), xlnt::invalid_parameter); xlnt_assert_throws(cell.hyperlink(""), xlnt::invalid_parameter); - cell.hyperlink("http://example.com"); + // link without optional display + const std::string link1("http://example.com"); + cell.hyperlink(link1); xlnt_assert(cell.has_hyperlink()); - xlnt_assert_equals(cell.hyperlink().relationship().target().to_string(), "http://example.com"); + xlnt_assert(cell.hyperlink().external()); + xlnt_assert_equals(cell.hyperlink().url(), link1); + xlnt_assert_equals(cell.hyperlink().relationship().target().to_string(), link1); + xlnt_assert_equals(cell.hyperlink().display(), link1); + // link with display + const std::string link2("http://example2.com"); + const std::string display_txt("notaurl"); + cell.hyperlink(link2, display_txt); + xlnt_assert(cell.has_hyperlink()); + xlnt_assert(cell.hyperlink().external()); + xlnt_assert_equals(cell.hyperlink().url(), link2); + xlnt_assert_equals(cell.hyperlink().relationship().target().to_string(), link2); + xlnt_assert_equals(cell.hyperlink().display(), display_txt); + // cell overload without display + const std::string cell_target_str("A2"); + auto cell_target = wb.active_sheet().cell(cell_target_str); + std::string link3 = wb.active_sheet().title() + '!' + cell_target_str; // Sheet1!A2 + cell.hyperlink(cell_target); + xlnt_assert(cell.has_hyperlink()); + xlnt_assert(!cell.hyperlink().external()); + xlnt_assert_equals(cell.hyperlink().target_range(), link3); + xlnt_assert_equals(cell.hyperlink().display(), link3); + // cell overload with display + cell.hyperlink(cell_target, display_txt); + xlnt_assert(cell.has_hyperlink()); + xlnt_assert(!cell.hyperlink().external()); + xlnt_assert_equals(cell.hyperlink().target_range(), link3); + xlnt_assert_equals(cell.hyperlink().display(), display_txt); + // range overload without display + const std::string range_target_str("A2:A5"); + xlnt::range range_target(wb.active_sheet(), xlnt::range_reference(range_target_str)); + std::string link4 = wb.active_sheet().title() + '!' + range_target_str; // Sheet1!A2:A5 + cell.hyperlink(range_target); + xlnt_assert(cell.has_hyperlink()); + xlnt_assert(!cell.hyperlink().external()); + xlnt_assert_equals(cell.hyperlink().target_range(), link4); + xlnt_assert_equals(cell.hyperlink().display(), link4); + // range overload with display + cell.hyperlink(range_target, display_txt); + xlnt_assert(cell.has_hyperlink()); + xlnt_assert(!cell.hyperlink().external()); + xlnt_assert_equals(cell.hyperlink().target_range(), link4); + xlnt_assert_equals(cell.hyperlink().display(), display_txt); + // value not touched + xlnt_assert_equals(cell.value(), 123); } void test_comment() diff --git a/tests/workbook/serialization_test_suite.cpp b/tests/workbook/serialization_test_suite.cpp index 3533159c..744103ee 100644 --- a/tests/workbook/serialization_test_suite.cpp +++ b/tests/workbook/serialization_test_suite.cpp @@ -575,7 +575,7 @@ public: std::vector destination; source_workbook.save(destination); - source_workbook.save("temp.xlsx"); + source_workbook.save("temp" + source.filename()); #ifdef _MSC_VER std::ifstream source_stream(source.wstring(), std::ios::binary); diff --git a/tests/worksheet/worksheet_test_suite.cpp b/tests/worksheet/worksheet_test_suite.cpp index 84fa2693..b25e0d61 100644 --- a/tests/worksheet/worksheet_test_suite.cpp +++ b/tests/worksheet/worksheet_test_suite.cpp @@ -50,7 +50,6 @@ public: register_test(test_remove_named_range_bad); register_test(test_cell_alternate_coordinates); register_test(test_cell_range_name); - register_test(test_hyperlink_value); register_test(test_rows); register_test(test_no_rows); register_test(test_no_cols); @@ -225,50 +224,6 @@ public: xlnt_assert(c_range_coord[0][0] == c_cell); } - void test_hyperlink_value() - { - xlnt::workbook wb; - auto ws = wb.active_sheet(); - std::string test_link = "http://test.com"; - xlnt::cell_reference test_cell("A1"); - ws.cell(test_cell).hyperlink(test_link); - // when a hyperlink is added to an empty cell, the display text becomes == to the link - xlnt_assert_equals(ws.cell(test_cell).hyperlink().url(), test_link); - xlnt_assert_equals(ws.cell(test_cell).value(), test_link); - // if the display value changes, the hyperlink remains the same - std::string test_string = "test"; - ws.cell(test_cell).value(test_string); - xlnt_assert_equals(test_string, ws.cell(test_cell).value()); - xlnt_assert_equals(ws.cell(test_cell).hyperlink().url(), test_link); - // changing the link doesn't change the cell value - std::string test_link2 = "http://test-123.com"; - ws.cell(test_cell).hyperlink(test_link2); - xlnt_assert_equals(test_string, ws.cell(test_cell).value()); - xlnt_assert_equals(ws.cell(test_cell).hyperlink().url(), test_link2); - // and we can edit both value and hyperlink together - std::string test_string3 = "123test"; - std::string test_link3 = "http://123-test.com"; - ws.cell(test_cell).hyperlink(test_link3, test_string3); - xlnt_assert_equals(test_string3, ws.cell(test_cell).value()); - xlnt_assert_equals(ws.cell(test_cell).hyperlink().url(), test_link3); - // hyperlinks can also be applied to cells with non-string values - int numeric_test_val = 123; - std::string test_link4 = "http://test-numeric.com"; - xlnt::cell_reference numeric_test_cell("B1"); - ws.cell(numeric_test_cell).value(numeric_test_val); - ws.cell(numeric_test_cell).hyperlink(test_link4); - xlnt_assert_equals(ws.cell(numeric_test_cell).hyperlink().url(), test_link4); - xlnt_assert_equals(ws.cell(numeric_test_cell).value(), numeric_test_val); - // and there should be no issues if two cells use the same hyperlink - ws.cell(numeric_test_cell).hyperlink(test_link3); // still in use on 'A1' - // 'A1' - xlnt_assert_equals(test_string3, ws.cell(test_cell).value()); - xlnt_assert_equals(ws.cell(test_cell).hyperlink().url(), test_link3); - // 'B1' - xlnt_assert_equals(ws.cell(numeric_test_cell).hyperlink().url(), test_link3); - xlnt_assert_equals(ws.cell(numeric_test_cell).value(), numeric_test_val); - } - void test_rows() { xlnt::workbook wb; From ddab6551b02969d125fbc43e1aa0add552757721 Mon Sep 17 00:00:00 2001 From: Crzyrndm Date: Tue, 10 Jul 2018 17:19:56 +1200 Subject: [PATCH 9/9] Add tests for functionality added to implement declared functionality --- include/xlnt/cell/cell.hpp | 9 ++- include/xlnt/cell/rich_text_run.hpp | 2 +- include/xlnt/styles/color.hpp | 24 +++++- include/xlnt/utils/path.hpp | 7 +- source/cell/cell.cpp | 29 +++---- source/detail/implementations/cell_impl.hpp | 15 ++-- source/styles/color.cpp | 24 +++++- source/styles/style.cpp | 5 ++ source/utils/path.cpp | 7 +- source/utils/variant.cpp | 5 +- tests/cell/cell_test_suite.cpp | 77 +++++++++++++++++-- tests/cell/rich_text_test_suite.cpp | 15 ++++ tests/styles/color_test_suite.cpp | 40 +++++----- .../styles/conditional_format_test_suite.cpp | 64 +++++++++++++++ tests/styles/protection_test_suite.cpp | 55 +++++++++++++ tests/styles/style_test_suite.cpp | 66 ++++++++++++++++ tests/utils/path_test_suite.cpp | 1 + tests/utils/variant_tests.cpp | 69 +++++++++++++++++ tests/worksheet/range_test_suite.cpp | 30 ++++++++ 19 files changed, 479 insertions(+), 65 deletions(-) create mode 100644 tests/styles/conditional_format_test_suite.cpp create mode 100644 tests/styles/protection_test_suite.cpp create mode 100644 tests/styles/style_test_suite.cpp create mode 100644 tests/utils/variant_tests.cpp diff --git a/include/xlnt/cell/cell.hpp b/include/xlnt/cell/cell.hpp index 8b85625b..9ff5fb93 100644 --- a/include/xlnt/cell/cell.hpp +++ b/include/xlnt/cell/cell.hpp @@ -608,9 +608,9 @@ public: bool operator==(const cell &comparand) const; /// - /// Returns true if this cell is uninitialized. + /// Returns false if this cell the same cell as comparand (compared by reference). /// - bool operator==(std::nullptr_t) const; + bool operator!=(const cell &comparand) const; private: friend class style; @@ -646,6 +646,11 @@ private: /// XLNT_API bool operator==(std::nullptr_t, const cell &cell); +/// +/// Returns true if this cell is uninitialized. +/// +XLNT_API bool operator==(const cell &cell, std::nullptr_t); + /// /// Convenience function for writing cell to an ostream. /// Uses cell::to_string() internally. diff --git a/include/xlnt/cell/rich_text_run.hpp b/include/xlnt/cell/rich_text_run.hpp index 0988a7e7..dc31fe52 100644 --- a/include/xlnt/cell/rich_text_run.hpp +++ b/include/xlnt/cell/rich_text_run.hpp @@ -34,7 +34,7 @@ namespace xlnt { /// /// Typedef a rich_text_run as a pair of string and optional font. /// -struct rich_text_run +struct XLNT_API rich_text_run { std::string first; optional second; diff --git a/include/xlnt/styles/color.hpp b/include/xlnt/styles/color.hpp index 609ede8a..db35e6ef 100644 --- a/include/xlnt/styles/color.hpp +++ b/include/xlnt/styles/color.hpp @@ -252,19 +252,37 @@ public: /// Returns the internal indexed color representing this color. If this is not an RGB color, /// an invalid_attribute exception will be thrown. /// - rgb_color rgb() const; + const rgb_color& rgb() const; + + /// + /// Returns the internal indexed color representing this color. If this is not an RGB color, + /// an invalid_attribute exception will be thrown. + /// + rgb_color &rgb(); /// /// Returns the internal indexed color representing this color. If this is not an indexed color, /// an invalid_attribute exception will be thrown. /// - indexed_color indexed() const; + const indexed_color& indexed() const; + + /// + /// Returns the internal indexed color representing this color. If this is not an indexed color, + /// an invalid_attribute exception will be thrown. + /// + indexed_color &indexed(); /// /// Returns the internal indexed color representing this color. If this is not a theme color, /// an invalid_attribute exception will be thrown. /// - theme_color theme() const; + const theme_color& theme() const; + + /// + /// Returns the internal indexed color representing this color. If this is not a theme color, + /// an invalid_attribute exception will be thrown. + /// + theme_color& theme(); /// /// Returns the tint of this color. diff --git a/include/xlnt/utils/path.hpp b/include/xlnt/utils/path.hpp index beff0165..ba16526f 100644 --- a/include/xlnt/utils/path.hpp +++ b/include/xlnt/utils/path.hpp @@ -107,7 +107,7 @@ public: /// Create a string representing this path separated by the provided /// separator or the system-default separator if not provided. /// - std::string string() const; + const std::string& string() const; #ifdef _MSC_VER /// @@ -176,6 +176,11 @@ public: /// bool operator==(const path &other) const; + /// + /// Returns true if left path is equal to right path. + /// + bool operator!=(const path &other) const; + private: /// /// Returns the character that separates directories in the path. diff --git a/source/cell/cell.cpp b/source/cell/cell.cpp index f080107b..bc5f558f 100644 --- a/source/cell/cell.cpp +++ b/source/cell/cell.cpp @@ -341,32 +341,18 @@ cell_reference cell::reference() const return {d_->column_, d_->row_}; } -bool cell::operator==(std::nullptr_t) const -{ - return d_ == nullptr; -} - bool cell::operator==(const cell &comparand) const { return d_ == comparand.d_; } -cell &cell::operator=(const cell &rhs) +bool cell::operator!=(const cell &comparand) const { - d_->column_ = rhs.d_->column_; - d_->format_ = rhs.d_->format_; - d_->formula_ = rhs.d_->formula_; - d_->hyperlink_ = rhs.d_->hyperlink_; - d_->is_merged_ = rhs.d_->is_merged_; - d_->parent_ = rhs.d_->parent_; - d_->row_ = rhs.d_->row_; - d_->type_ = rhs.d_->type_; - d_->value_numeric_ = rhs.d_->value_numeric_; - d_->value_text_ = rhs.d_->value_text_; - - return *this; + return d_ != comparand.d_; } +cell &cell::operator=(const cell &rhs) = default; + hyperlink cell::hyperlink() const { return xlnt::hyperlink(&d_->hyperlink_.get()); @@ -437,7 +423,7 @@ void cell::hyperlink(xlnt::cell target, const std::string& display) void cell::hyperlink(xlnt::range target, const std::string &display) { // TODO: should this computed value be a method on a cell? - const auto range_address = target.worksheet().title() + "!" + target.reference().to_string(); + const auto range_address = target.target_worksheet().title() + "!" + target.reference().to_string(); d_->hyperlink_ = detail::hyperlink_impl(); d_->hyperlink_.get().relationship = xlnt::relationship("", relationship_type::hyperlink, @@ -778,6 +764,11 @@ bool operator==(std::nullptr_t, const cell &cell) return cell.data_type() == cell::type::empty; } +bool operator==(const cell &cell, std::nullptr_t) +{ + return nullptr == cell; +} + XLNT_API std::ostream &operator<<(std::ostream &stream, const xlnt::cell &cell) { return stream << cell.to_string(); diff --git a/source/detail/implementations/cell_impl.hpp b/source/detail/implementations/cell_impl.hpp index ed1833ed..64756770 100644 --- a/source/detail/implementations/cell_impl.hpp +++ b/source/detail/implementations/cell_impl.hpp @@ -27,22 +27,26 @@ #include #include -#include #include +#include #include #include +#include #include namespace xlnt { namespace detail { -struct format_impl; struct worksheet_impl; struct cell_impl { cell_impl(); - + cell_impl(const cell_impl &other) = default; + cell_impl(cell_impl &&other) = default; + cell_impl &operator=(const cell_impl &other) = default; + cell_impl &operator=(cell_impl &&other) = default; + cell_type type_; worksheet_impl *parent_; @@ -72,9 +76,8 @@ inline bool operator==(const cell_impl &lhs, const cell_impl &rhs) && lhs.value_numeric_ == rhs.value_numeric_ && lhs.formula_ == rhs.formula_ && lhs.hyperlink_ == rhs.hyperlink_ - // comparing pointers is unlikely to be what is wanted - /*&& lhs.format_ == rhs.format_ - && lhs.comment_ == rhs.comment_*/; + && (lhs.format_.is_set() == rhs.format_.is_set() && (!lhs.format_.is_set() || *lhs.format_.get() == *rhs.format_.get())) + && (lhs.comment_.is_set() == rhs.comment_.is_set() && (!lhs.comment_.is_set() || *lhs.comment_.get() == *rhs.comment_.get())); } } // namespace detail diff --git a/source/styles/color.cpp b/source/styles/color.cpp index 3eccd394..01561eec 100644 --- a/source/styles/color.cpp +++ b/source/styles/color.cpp @@ -233,19 +233,37 @@ void color::auto_(bool value) auto__ = value; } -indexed_color color::indexed() const +const indexed_color& color::indexed() const { assert_type(color_type::indexed); return indexed_; } -theme_color color::theme() const +indexed_color &color::indexed() +{ + assert_type(color_type::indexed); + return indexed_; +} + +const theme_color& color::theme() const { assert_type(color_type::theme); return theme_; } -rgb_color color::rgb() const +theme_color &color::theme() +{ + assert_type(color_type::theme); + return theme_; +} + +const rgb_color& color::rgb() const +{ + assert_type(color_type::rgb); + return rgb_; +} + +rgb_color &color::rgb() { assert_type(color_type::rgb); return rgb_; diff --git a/source/styles/style.cpp b/source/styles/style.cpp index 5ba4db51..4dd5418d 100755 --- a/source/styles/style.cpp +++ b/source/styles/style.cpp @@ -92,6 +92,11 @@ bool style::operator==(const style &other) const return name() == other.name(); } +bool style::operator!=(const style &other) const +{ + return !operator==(other); +} + xlnt::alignment style::alignment() const { return d_->parent->alignments.at(d_->alignment_id.get()); diff --git a/source/utils/path.cpp b/source/utils/path.cpp index b67ab977..34c36cf0 100644 --- a/source/utils/path.cpp +++ b/source/utils/path.cpp @@ -221,7 +221,7 @@ std::pair path::split_extension() const // conversion -std::string path::string() const +const std::string& path::string() const { return internal_; } @@ -347,4 +347,9 @@ bool path::operator==(const path &other) const return internal_ == other.internal_; } +bool path::operator!=(const path &other) const +{ + return !operator==(other); +} + } // namespace xlnt diff --git a/source/utils/variant.cpp b/source/utils/variant.cpp index 5565fe94..4c420eea 100644 --- a/source/utils/variant.cpp +++ b/source/utils/variant.cpp @@ -27,9 +27,8 @@ namespace xlnt { variant::variant() -{ - -} + : type_(type::null) +{} variant::variant(const std::string &value) : type_(type::lpstr), diff --git a/tests/cell/cell_test_suite.cpp b/tests/cell/cell_test_suite.cpp index 8729134e..510786b3 100644 --- a/tests/cell/cell_test_suite.cpp +++ b/tests/cell/cell_test_suite.cpp @@ -29,20 +29,20 @@ #include #include #include -#include #include #include #include #include +#include #include #include -#include -#include #include #include #include #include - +#include +#include +#include class cell_test_suite : public test_suite { @@ -81,6 +81,7 @@ public: register_test(test_anchor); register_test(test_hyperlink); register_test(test_comment); + register_test(test_copy_and_compare); } private: @@ -253,11 +254,27 @@ private: xlnt::workbook wb; auto ws = wb.active_sheet(); auto cell = ws.cell(xlnt::cell_reference(1, 1)); + // error string can't be empty + xlnt_assert_throws(cell.error(""), xlnt::exception); + // error string has to have a leading '#' + xlnt_assert_throws(cell.error("not an error"), xlnt::exception); for (auto error_code : xlnt::cell::error_codes()) { + // error type from the string format cell.value(error_code.first, true); xlnt_assert(cell.data_type() == xlnt::cell::type::error); + std::string error; + xlnt_assert_throws_nothing(error = cell.error()); + xlnt_assert_equals(error, error_code.first); + // clearing the value clears the error state + cell.clear_value(); + xlnt_assert_throws(cell.error(), xlnt::exception); + // can explicitly set the error + xlnt_assert_throws_nothing(cell.error(error_code.first)); + std::string error2; + xlnt_assert_throws_nothing(error2 = cell.error()); + xlnt_assert_equals(error2, error_code.first); } } @@ -667,7 +684,7 @@ private: { xlnt::workbook wb; auto cell = wb.active_sheet().cell("A1"); - cell.value(123); + xlnt_assert(!cell.has_hyperlink()); xlnt_assert_throws(cell.hyperlink(), xlnt::invalid_attribute); xlnt_assert_throws(cell.hyperlink("notaurl"), xlnt::invalid_parameter); @@ -680,7 +697,8 @@ private: xlnt_assert_equals(cell.hyperlink().url(), link1); xlnt_assert_equals(cell.hyperlink().relationship().target().to_string(), link1); xlnt_assert_equals(cell.hyperlink().display(), link1); - // link with display + cell.clear_value(); + // link with display const std::string link2("http://example2.com"); const std::string display_txt("notaurl"); cell.hyperlink(link2, display_txt); @@ -689,6 +707,14 @@ private: xlnt_assert_equals(cell.hyperlink().url(), link2); xlnt_assert_equals(cell.hyperlink().relationship().target().to_string(), link2); xlnt_assert_equals(cell.hyperlink().display(), display_txt); + // value + int cell_test_val = 123; + cell.value(cell_test_val); + std::string cell_value_str = std::to_string(cell_test_val); + cell.hyperlink(link2, display_txt); + xlnt_assert_equals(cell.value(), 123); + xlnt_assert_equals(cell.hyperlink().display(), cell_value_str); // display text ignored + cell.clear_value(); // cell overload without display const std::string cell_target_str("A2"); auto cell_target = wb.active_sheet().cell(cell_target_str); @@ -698,12 +724,19 @@ private: xlnt_assert(!cell.hyperlink().external()); xlnt_assert_equals(cell.hyperlink().target_range(), link3); xlnt_assert_equals(cell.hyperlink().display(), link3); + cell.clear_value(); // cell overload with display cell.hyperlink(cell_target, display_txt); xlnt_assert(cell.has_hyperlink()); xlnt_assert(!cell.hyperlink().external()); xlnt_assert_equals(cell.hyperlink().target_range(), link3); xlnt_assert_equals(cell.hyperlink().display(), display_txt); + // value + cell.value(cell_test_val); + cell.hyperlink(cell_target, display_txt); + xlnt_assert_equals(cell.value(), 123); + xlnt_assert_equals(cell.hyperlink().display(), cell_value_str); // display text ignored + cell.clear_value(); // range overload without display const std::string range_target_str("A2:A5"); xlnt::range range_target(wb.active_sheet(), xlnt::range_reference(range_target_str)); @@ -713,14 +746,19 @@ private: xlnt_assert(!cell.hyperlink().external()); xlnt_assert_equals(cell.hyperlink().target_range(), link4); xlnt_assert_equals(cell.hyperlink().display(), link4); + cell.clear_value(); // range overload with display cell.hyperlink(range_target, display_txt); xlnt_assert(cell.has_hyperlink()); xlnt_assert(!cell.hyperlink().external()); xlnt_assert_equals(cell.hyperlink().target_range(), link4); xlnt_assert_equals(cell.hyperlink().display(), display_txt); - // value not touched + // value + cell.value(cell_test_val); + cell.hyperlink(range_target, display_txt); xlnt_assert_equals(cell.value(), 123); + xlnt_assert_equals(cell.hyperlink().display(), cell_value_str); // display text ignored + cell.clear_value(); } void test_comment() @@ -737,6 +775,31 @@ private: xlnt_assert(!cell.has_comment()); xlnt_assert_throws(cell.comment(), xlnt::exception); } + + void test_copy_and_compare() + { + xlnt::workbook wb; + auto ws = wb.active_sheet(); + auto cell1 = ws.cell("A1"); + auto cell2 = ws.cell("A2"); + + xlnt_assert_equals(cell1, cell1); + xlnt_assert_equals(cell2, cell2); + xlnt_assert_differs(cell1, cell2); + xlnt_assert_differs(cell2, cell1); + // nullptr equality + xlnt_assert(nullptr == cell1); + xlnt_assert(cell1 == nullptr); + cell1.value("test"); + xlnt_assert(!(nullptr == cell1)); + xlnt_assert(!(cell1 == nullptr)); + // copy + xlnt::cell cell3(cell1); + xlnt_assert_equals(cell1, cell3); + // assign + cell3 = cell2; + xlnt_assert_equals(cell2, cell3); + } }; static cell_test_suite x{}; \ No newline at end of file diff --git a/tests/cell/rich_text_test_suite.cpp b/tests/cell/rich_text_test_suite.cpp index af44f815..3af26383 100644 --- a/tests/cell/rich_text_test_suite.cpp +++ b/tests/cell/rich_text_test_suite.cpp @@ -35,6 +35,7 @@ public: rich_text_test_suite() { register_test(test_operators); + register_test(test_runs); } void test_operators() @@ -100,5 +101,19 @@ public: text_family_differs.add_run(run_family_differs); xlnt_assert_differs(text_formatted, text_family_differs); } + + void test_runs() + { + xlnt::rich_text rt; + xlnt_assert(rt.runs().empty()); + std::vector test_runs{xlnt::rich_text_run{"1_abc_test_123"}, xlnt::rich_text_run{"2_abc_test_123"}, xlnt::rich_text_run{"3_abc_test_123"}}; + // just one + rt.add_run(test_runs[0]); + xlnt_assert_equals(1, rt.runs().size()); + xlnt_assert_equals(test_runs[0], rt.runs()[0]); + // whole set + rt.runs(test_runs); + xlnt_assert_equals(test_runs, rt.runs()); + } }; static rich_text_test_suite x{}; \ No newline at end of file diff --git a/tests/styles/color_test_suite.cpp b/tests/styles/color_test_suite.cpp index ac61291b..e65f540a 100644 --- a/tests/styles/color_test_suite.cpp +++ b/tests/styles/color_test_suite.cpp @@ -38,37 +38,39 @@ public: void test_known_colors() { - const std::vector> known_colors - { - { xlnt::color::black(), "FF000000" }, - { xlnt::color::white(), "FFFFFFFF" }, - { xlnt::color::red(), "FFFF0000" }, - { xlnt::color::darkred(), "FF8B0000" }, - { xlnt::color::blue(), "FF0000FF" }, - { xlnt::color::darkblue(), "FF00008B" }, - { xlnt::color::green(), "FF00FF00" }, - { xlnt::color::darkgreen(), "FF008B00" }, - { xlnt::color::yellow(), "FFFFFF00" }, - { xlnt::color::darkyellow(), "FFCCCC00" } - }; - + const std::vector> known_colors{ + {xlnt::color::black(), "FF000000"}, + {xlnt::color::white(), "FFFFFFFF"}, + {xlnt::color::red(), "FFFF0000"}, + {xlnt::color::darkred(), "FF8B0000"}, + {xlnt::color::blue(), "FF0000FF"}, + {xlnt::color::darkblue(), "FF00008B"}, + {xlnt::color::green(), "FF00FF00"}, + {xlnt::color::darkgreen(), "FF008B00"}, + {xlnt::color::yellow(), "FFFFFF00"}, + {xlnt::color::darkyellow(), "FFCCCC00"}}; + for (auto pair : known_colors) { xlnt_assert_equals(pair.first.rgb().hex_string(), pair.second); } } - + void test_non_rgb_colors() { - xlnt::color indexed = xlnt::indexed_color(1); - xlnt_assert(!indexed.auto_()); + xlnt::color indexed = xlnt::indexed_color(1); + xlnt_assert(!indexed.auto_()); xlnt_assert_equals(indexed.indexed().index(), 1); + indexed.indexed().index(2); + xlnt_assert_equals(indexed.indexed().index(), 2); xlnt_assert_throws(indexed.theme(), xlnt::invalid_attribute); xlnt_assert_throws(indexed.rgb(), xlnt::invalid_attribute); - xlnt::color theme = xlnt::theme_color(3); - xlnt_assert(!theme.auto_()); + xlnt::color theme = xlnt::theme_color(3); + xlnt_assert(!theme.auto_()); xlnt_assert_equals(theme.theme().index(), 3); + theme.theme().index(4); + xlnt_assert_equals(theme.theme().index(), 4); xlnt_assert_throws(theme.indexed(), xlnt::invalid_attribute); xlnt_assert_throws(theme.rgb(), xlnt::invalid_attribute); } diff --git a/tests/styles/conditional_format_test_suite.cpp b/tests/styles/conditional_format_test_suite.cpp new file mode 100644 index 00000000..1410774f --- /dev/null +++ b/tests/styles/conditional_format_test_suite.cpp @@ -0,0 +1,64 @@ +// Copyright (c) 2014-2018 Thomas Fussell +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE +// +// @license: http://www.opensource.org/licenses/mit-license.php +// @author: see AUTHORS file + +#include +#include +#include + +class conditional_format_test_suite : public test_suite +{ +public: + conditional_format_test_suite() + { + register_test(test_all); + } + + void test_all() + { + xlnt::workbook wb; + auto ws = wb.active_sheet(); + auto format = ws.conditional_format(xlnt::range_reference("A1:A10"), xlnt::condition::text_contains("test")); + xlnt_assert(!format.has_border()); + xlnt_assert(!format.has_fill()); + xlnt_assert(!format.has_font()); + // set border + auto border = xlnt::border().diagonal(xlnt::diagonal_direction::both); + format.border(border); + xlnt_assert(format.has_border()); + xlnt_assert_equals(format.border(), border); + // set fill + auto fill = xlnt::fill(xlnt::gradient_fill().type(xlnt::gradient_fill_type::path)); + format.fill(fill); + xlnt_assert(format.has_fill()); + xlnt_assert_equals(format.fill(), fill); + // set font + auto font = xlnt::font().color(xlnt::color::darkblue()); + format.font(font); + xlnt_assert(format.has_font()); + xlnt_assert_equals(format.font(), font); + // copy ctor + auto format_copy(format); + xlnt_assert_equals(format, format_copy); + } +}; +static conditional_format_test_suite x; \ No newline at end of file diff --git a/tests/styles/protection_test_suite.cpp b/tests/styles/protection_test_suite.cpp new file mode 100644 index 00000000..039d987c --- /dev/null +++ b/tests/styles/protection_test_suite.cpp @@ -0,0 +1,55 @@ +// Copyright (c) 2014-2018 Thomas Fussell +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE +// +// @license: http://www.opensource.org/licenses/mit-license.php +// @author: see AUTHORS file + +#include +#include +#include + +class protection_test_suite : public test_suite +{ +public: + protection_test_suite() + { + register_test(test_all); + } + + void test_all() + { + auto prot = xlnt::protection::unlocked_and_visible(); + xlnt_assert(!prot.hidden()); + xlnt_assert(!prot.locked()); + + prot = xlnt::protection::locked_and_visible(); + xlnt_assert(!prot.hidden()); + xlnt_assert(prot.locked()); + + prot = xlnt::protection::unlocked_and_hidden(); + xlnt_assert(prot.hidden()); + xlnt_assert(!prot.locked()); + + prot = xlnt::protection::locked_and_hidden(); + xlnt_assert(prot.hidden()); + xlnt_assert(prot.locked()); + } +}; +static protection_test_suite x; \ No newline at end of file diff --git a/tests/styles/style_test_suite.cpp b/tests/styles/style_test_suite.cpp new file mode 100644 index 00000000..3cd22a15 --- /dev/null +++ b/tests/styles/style_test_suite.cpp @@ -0,0 +1,66 @@ +// Copyright (c) 2014-2018 Thomas Fussell +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE +// +// @license: http://www.opensource.org/licenses/mit-license.php +// @author: see AUTHORS file + +#include +#include +#include + +class style_test_suite : public test_suite +{ +public: + style_test_suite() + { + register_test(test_all); + } + + void test_all() + { + xlnt::workbook wb; + auto ws = wb.active_sheet(); + auto test_style = wb.create_style("test_style"); + test_style.number_format(xlnt::number_format::date_ddmmyyyy()); + + auto copy_style(test_style); + xlnt_assert_equals(test_style, copy_style); + + // number format + xlnt_assert_equals(copy_style.name(), "test_style"); + xlnt_assert_equals(copy_style.number_format(), xlnt::number_format::date_ddmmyyyy()); + //xlnt_assert(!copy_style.number_format_applied()); // this doesn't seem to have sensible behaviour? + copy_style.number_format(xlnt::number_format::date_datetime(), true); // true applied param + xlnt_assert_equals(copy_style.number_format(), xlnt::number_format::date_datetime()); + xlnt_assert(copy_style.number_format_applied()); + copy_style.number_format(xlnt::number_format::date_dmminus(), false); // false applied param + xlnt_assert_equals(copy_style.number_format(), xlnt::number_format::date_dmminus()); + xlnt_assert(!copy_style.number_format_applied()); + + xlnt_assert(!copy_style.pivot_button()); + copy_style.pivot_button(true); + xlnt_assert(copy_style.pivot_button()); + + xlnt_assert(!copy_style.quote_prefix()); + copy_style.quote_prefix(true); + xlnt_assert(copy_style.quote_prefix()); + } +}; +static style_test_suite x; \ No newline at end of file diff --git a/tests/utils/path_test_suite.cpp b/tests/utils/path_test_suite.cpp index f8d4f24c..bfc6fdfa 100644 --- a/tests/utils/path_test_suite.cpp +++ b/tests/utils/path_test_suite.cpp @@ -26,6 +26,7 @@ #include #include #include +#include class path_test_suite : public test_suite { diff --git a/tests/utils/variant_tests.cpp b/tests/utils/variant_tests.cpp new file mode 100644 index 00000000..10de95ec --- /dev/null +++ b/tests/utils/variant_tests.cpp @@ -0,0 +1,69 @@ +// Copyright (c) 2014-2018 Thomas Fussell +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE +// +// @license: http://www.opensource.org/licenses/mit-license.php +// @author: see AUTHORS file + +#include +#include + +class variant_test_suite : public test_suite +{ +public: + variant_test_suite() + : test_suite() + { + register_test(test_null); + register_test(test_int32); + register_test(test_string); + } + + void test_null() + { + xlnt::variant var_null; + xlnt_assert_equals(var_null.value_type(), xlnt::variant::type::null); + xlnt_assert(var_null.is(xlnt::variant::type::null)); + } + + void test_int32() + { + xlnt::variant var_int(std::int32_t(10)); + xlnt_assert_equals(var_int.value_type(), xlnt::variant::type::i4); + xlnt_assert(var_int.is(xlnt::variant::type::i4)); + xlnt_assert_throws_nothing(var_int.get()); + xlnt_assert_equals(10, var_int.get()); + } + + void test_string() + { + xlnt::variant var_str1("test1"); + xlnt_assert_equals(var_str1.value_type(), xlnt::variant::type::lpstr); + xlnt_assert(var_str1.is(xlnt::variant::type::lpstr)); + xlnt_assert_throws_nothing(var_str1.get()); + xlnt_assert_equals("test1", var_str1.get()); + + xlnt::variant var_str2(std::string("test2")); + xlnt_assert_equals(var_str2.value_type(), xlnt::variant::type::lpstr); + xlnt_assert(var_str2.is(xlnt::variant::type::lpstr)); + xlnt_assert_throws_nothing(var_str2.get()); + xlnt_assert_equals("test2", var_str2.get()); + } +}; +static variant_test_suite x; \ No newline at end of file diff --git a/tests/worksheet/range_test_suite.cpp b/tests/worksheet/range_test_suite.cpp index 98012289..b8c14fb6 100644 --- a/tests/worksheet/range_test_suite.cpp +++ b/tests/worksheet/range_test_suite.cpp @@ -37,10 +37,40 @@ class range_test_suite : public test_suite public: range_test_suite() { + register_test(test_construction); register_test(test_batch_formatting); register_test(test_clear_cells); } + void test_construction() + { + xlnt::workbook wb; + auto ws = wb.active_sheet(); + + xlnt::range range_1(ws, xlnt::range_reference("A1:D10")); + xlnt_assert_equals(range_1.target_worksheet(), ws); + xlnt_assert_equals(1, range_1.front()[0].row()); // NOTE: querying row/column here desperately needs some shortcuts + xlnt_assert_equals(xlnt::column_t("D"), range_1.front().back().column()); + xlnt_assert_equals(10, range_1.back()[0].row()); + xlnt_assert_equals(xlnt::column_t("D"), range_1.back().back().column()); + // assert default parameters in ctor + xlnt::range range_2(ws, xlnt::range_reference("A1:D10"), xlnt::major_order::row, false); + xlnt_assert_equals(range_1, range_2); + // assert copy + xlnt::range range_3(range_2); + xlnt_assert_equals(range_1, range_3); + + // column order + xlnt::range range_4(ws, xlnt::range_reference("A1:D10"), xlnt::major_order::column); + xlnt_assert_equals(xlnt::column_t("A"), range_4.front()[0].column()); // NOTE: querying row/column here desperately needs some shortcuts + xlnt_assert_equals(10, range_4.front().back().row()); + xlnt_assert_equals(xlnt::column_t("D"), range_4.back()[0].column()); + xlnt_assert_equals(10, range_4.back().back().row()); + // assignment + range_3 = range_4; + xlnt_assert_equals(range_3, range_4); + } + void test_batch_formatting() { xlnt::workbook wb;