From 6b3781d03b3f199e0a15a0f9c60df3cc8c55896f Mon Sep 17 00:00:00 2001 From: Thomas Fussell Date: Wed, 14 Oct 2015 00:03:48 -0400 Subject: [PATCH] begin refactoring writing code --- include/xlnt/common/exceptions.hpp | 10 +- include/xlnt/workbook/named_range.hpp | 18 ++ include/xlnt/workbook/workbook.hpp | 19 ++ include/xlnt/worksheet/page_setup.hpp | 15 +- include/xlnt/worksheet/worksheet.hpp | 79 +----- include/xlnt/writer/manifest_writer.hpp | 11 + include/xlnt/writer/relationship_writer.hpp | 12 + include/xlnt/writer/theme_writer.hpp | 8 +- include/xlnt/writer/workbook_writer.hpp | 33 ++- include/xlnt/writer/worksheet_writer.hpp | 31 --- include/xlnt/writer/writer.hpp | 15 +- include/xlnt/xlnt.hpp | 1 + source/cell_reference.cpp | 16 +- source/manifest_writer.cpp | 10 + source/named_range.cpp | 73 +++++ source/relationship_writer.cpp | 45 ++++ source/workbook.cpp | 40 ++- source/workbook_writer.cpp | 285 ++++++++++++++++++++ source/worksheet.cpp | 5 + source/writer.cpp | 184 +------------ tests/helpers/helper.hpp | 5 + tests/helpers/path_helper.hpp | 11 + tests/test_named_range.hpp | 28 +- tests/test_number_format.hpp | 165 ------------ tests/test_props.hpp | 5 +- tests/test_write.hpp | 6 +- tests/test_write_workbook.hpp | 175 ++++++++++++ 27 files changed, 818 insertions(+), 487 deletions(-) create mode 100644 include/xlnt/workbook/named_range.hpp create mode 100644 include/xlnt/writer/manifest_writer.hpp create mode 100644 include/xlnt/writer/relationship_writer.hpp create mode 100644 source/manifest_writer.cpp create mode 100644 source/named_range.cpp create mode 100644 source/relationship_writer.cpp create mode 100644 source/workbook_writer.cpp delete mode 100644 tests/test_number_format.hpp create mode 100644 tests/test_write_workbook.hpp diff --git a/include/xlnt/common/exceptions.hpp b/include/xlnt/common/exceptions.hpp index c0ec17ed..f8bb984b 100644 --- a/include/xlnt/common/exceptions.hpp +++ b/include/xlnt/common/exceptions.hpp @@ -118,5 +118,13 @@ class attribute_error : public std::runtime_error public: attribute_error(); }; - + +class value_error : public std::runtime_error +{ +public: + value_error() : std::runtime_error("") + { + } +}; + } // namespace xlnt diff --git a/include/xlnt/workbook/named_range.hpp b/include/xlnt/workbook/named_range.hpp new file mode 100644 index 00000000..0b19bd64 --- /dev/null +++ b/include/xlnt/workbook/named_range.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +namespace xlnt { + +class worksheet; + +std::vector> split_named_range(const std::string &named_range_string); + +class named_range +{ +public: + named_range(const std::string &name, const std::vector> &targets); +}; + +} \ No newline at end of file diff --git a/include/xlnt/workbook/workbook.hpp b/include/xlnt/workbook/workbook.hpp index f284080a..12a50a5c 100644 --- a/include/xlnt/workbook/workbook.hpp +++ b/include/xlnt/workbook/workbook.hpp @@ -46,6 +46,7 @@ class pattern_fill; class font; class protection; class color; +class named_range; enum class encoding; @@ -174,7 +175,18 @@ public: bool load(const std::istream &stream); bool operator==(const workbook &rhs) const; + + bool operator!=(const workbook &rhs) const + { + return !(*this == rhs); + } + bool operator==(std::nullptr_t) const; + + bool operator!=(std::nullptr_t) const + { + return !(*this == std::nullptr_t{}); + } std::vector get_content_types() const; @@ -190,6 +202,13 @@ public: void add_color(color c); void add_number_format(const std::string &format); + void set_code_name(const std::string &code_name); + + void add_named_range(const named_range &n); + + bool has_loaded_theme(); + std::string get_loaded_theme(); + private: static std::size_t index_from_ws_filename(const std::string &ws_filename); diff --git a/include/xlnt/worksheet/page_setup.hpp b/include/xlnt/worksheet/page_setup.hpp index 7a014e85..48a0bd7f 100644 --- a/include/xlnt/worksheet/page_setup.hpp +++ b/include/xlnt/worksheet/page_setup.hpp @@ -24,7 +24,7 @@ #pragma once namespace xlnt { - + struct page_setup { enum class page_break @@ -64,12 +64,12 @@ struct page_setup public: page_setup() : default_(true), break_(page_break::none), sheet_state_(sheet_state::visible), paper_size_(paper_size::letter), - orientation_(orientation::portrait), fit_to_page_(false), fit_to_height_(false), fit_to_width_(false) {} + orientation_(orientation::portrait), fit_to_page_(false), fit_to_height_(false), fit_to_width_(false), horizontal_centered_(false), vertical_centered_(false), scale_(1) {} bool is_default() const { return default_; } page_break get_break() const { return break_; } void set_break(page_break b) { default_ = false; break_ = b; } sheet_state get_sheet_state() const { return sheet_state_; } - void set_sheet_state(sheet_state sheet_state) { default_ = false; sheet_state_ = sheet_state; } + void set_sheet_state(sheet_state sheet_state) { sheet_state_ = sheet_state; } paper_size get_paper_size() const { return paper_size_; } void set_paper_size(paper_size paper_size) { default_ = false; paper_size_ = paper_size; } orientation get_orientation() const { return orientation_; } @@ -80,6 +80,12 @@ public: void set_fit_to_height(bool fit_to_height) { default_ = false; fit_to_height_ = fit_to_height; } bool fit_to_width() const { return fit_to_width_; } void set_fit_to_width(bool fit_to_width) { default_ = false; fit_to_width_ = fit_to_width; } + void set_horizontal_centered(bool horizontal_centered) { default_ = false; horizontal_centered_ = horizontal_centered; } + bool get_horizontal_centered() const { return horizontal_centered_; } + void set_vertical_centered(bool vertical_centered) { default_ = false; vertical_centered_ = vertical_centered; } + bool get_vertical_centered() const { return vertical_centered_; } + void set_scale(double scale) { default_ = false; scale_ = scale; } + double get_scale() const { return scale_; } private: bool default_; @@ -90,6 +96,9 @@ private: bool fit_to_page_; bool fit_to_height_; bool fit_to_width_; + bool horizontal_centered_; + bool vertical_centered_; + double scale_; }; } // namespace xlnt diff --git a/include/xlnt/worksheet/worksheet.hpp b/include/xlnt/worksheet/worksheet.hpp index 1ca9ba86..882636b5 100644 --- a/include/xlnt/worksheet/worksheet.hpp +++ b/include/xlnt/worksheet/worksheet.hpp @@ -29,6 +29,7 @@ #include #include +#include "page_setup.hpp" #include "../common/types.hpp" #include "../common/relationship.hpp" @@ -116,82 +117,6 @@ private: footer left_footer_, right_footer_, center_footer_; }; -struct page_setup -{ - enum class page_break - { - none = 0, - row = 1, - column = 2 - }; - - enum class sheet_state - { - visible, - hidden, - very_hidden - }; - - enum class paper_size - { - letter = 1, - letter_small = 2, - tabloid = 3, - ledger = 4, - legal = 5, - statement = 6, - executive = 7, - a3 = 8, - a4 = 9, - a4_small = 10, - a5 = 11 - }; - - enum class orientation - { - portrait, - landscape - }; - -public: - page_setup() : default_(true), break_(page_break::none), sheet_state_(sheet_state::visible), paper_size_(paper_size::letter), - orientation_(orientation::portrait), fit_to_page_(false), fit_to_height_(false), fit_to_width_(false), horizontal_centered_(false), vertical_centered_(false), scale_(1) {} - bool is_default() const { return default_; } - page_break get_break() const { return break_; } - void set_break(page_break b) { default_ = false; break_ = b; } - sheet_state get_sheet_state() const { return sheet_state_; } - void set_sheet_state(sheet_state sheet_state) { sheet_state_ = sheet_state; } - paper_size get_paper_size() const { return paper_size_; } - void set_paper_size(paper_size paper_size) { default_ = false; paper_size_ = paper_size; } - orientation get_orientation() const { return orientation_; } - void set_orientation(orientation orientation) { default_ = false; orientation_ = orientation; } - bool fit_to_page() const { return fit_to_page_; } - void set_fit_to_page(bool fit_to_page) { default_ = false; fit_to_page_ = fit_to_page; } - bool fit_to_height() const { return fit_to_height_; } - void set_fit_to_height(bool fit_to_height) { default_ = false; fit_to_height_ = fit_to_height; } - bool fit_to_width() const { return fit_to_width_; } - void set_fit_to_width(bool fit_to_width) { default_ = false; fit_to_width_ = fit_to_width; } - void set_horizontal_centered(bool horizontal_centered) { default_ = false; horizontal_centered_ = horizontal_centered; } - bool get_horizontal_centered() const { return horizontal_centered_; } - void set_vertical_centered(bool vertical_centered) { default_ = false; vertical_centered_ = vertical_centered; } - bool get_vertical_centered() const { return vertical_centered_; } - void set_scale(double scale) { default_ = false; scale_ = scale; } - double get_scale() const { return scale_; } - -private: - bool default_; - page_break break_; - sheet_state sheet_state_; - paper_size paper_size_; - orientation orientation_; - bool fit_to_page_; - bool fit_to_height_; - bool fit_to_width_; - bool horizontal_centered_; - bool vertical_centered_; - double scale_; -}; - struct margins { public: @@ -348,6 +273,8 @@ public: std::vector get_formula_attributes() const; + void set_sheet_state(page_setup::sheet_state state); + private: friend class workbook; friend class cell; diff --git a/include/xlnt/writer/manifest_writer.hpp b/include/xlnt/writer/manifest_writer.hpp new file mode 100644 index 00000000..183fa98a --- /dev/null +++ b/include/xlnt/writer/manifest_writer.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace xlnt { + +class workbook; + +std::string write_content_types(const workbook &wb, bool as_template); + +}; diff --git a/include/xlnt/writer/relationship_writer.hpp b/include/xlnt/writer/relationship_writer.hpp new file mode 100644 index 00000000..568ad400 --- /dev/null +++ b/include/xlnt/writer/relationship_writer.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +namespace xlnt { + +class relationship; + +std::string write_relationships(const std::vector &relationships, const std::string &dir); + +} // namespace xlnt diff --git a/include/xlnt/writer/theme_writer.hpp b/include/xlnt/writer/theme_writer.hpp index 685a6864..0f607771 100644 --- a/include/xlnt/writer/theme_writer.hpp +++ b/include/xlnt/writer/theme_writer.hpp @@ -23,11 +23,11 @@ // @author: see AUTHORS file #pragma once +#include + namespace xlnt { -class theme_writer -{ - -}; +std::string write_theme(); +//void write_theme(const theme &t); } // namespace xlnt diff --git a/include/xlnt/writer/workbook_writer.hpp b/include/xlnt/writer/workbook_writer.hpp index 6d54413e..e73444dc 100644 --- a/include/xlnt/writer/workbook_writer.hpp +++ b/include/xlnt/writer/workbook_writer.hpp @@ -23,11 +23,40 @@ // @author: see AUTHORS file #pragma once +#include +#include + +#include + namespace xlnt { -class workbook_writer -{ +class workbook; +class zip_file; +class excel_writer +{ +public: + excel_writer(workbook &wb); + + void save(const std::string &filename, bool as_template); + void write_data(zip_file &archive, bool as_template); + void write_string_table(zip_file &archive); + void write_images(zip_file &archive); + void write_charts(zip_file &archive); + void write_chartsheets(zip_file &archive); + void write_worksheets(zip_file &archive); + void write_external_links(zip_file &archive); + +private: + workbook wb_; + style_writer style_writer_; }; +std::string write_properties_app(const workbook &wb); +std::string write_root_rels(const workbook &wb); +std::string write_workbook(const workbook &wb); +std::string write_workbook_rels(const workbook &wb); +bool save_workbook(workbook &wb, const std::string &filename, bool as_template = false); +std::vector save_virtual_workbook(xlnt::workbook &wb, bool as_template = false); + } // namespace xlnt diff --git a/include/xlnt/writer/worksheet_writer.hpp b/include/xlnt/writer/worksheet_writer.hpp index f881e06a..3f59c932 100644 --- a/include/xlnt/writer/worksheet_writer.hpp +++ b/include/xlnt/writer/worksheet_writer.hpp @@ -1,33 +1,2 @@ -// Copyright (c) 2015 Thomas Fussell -// Copyright (c) 2010-2015 openpyxl -// -// 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 #pragma once -namespace xlnt { - -class worksheet_writer -{ - -}; - -} // namespace xlnt diff --git a/include/xlnt/writer/writer.hpp b/include/xlnt/writer/writer.hpp index c4692d72..0858a996 100644 --- a/include/xlnt/writer/writer.hpp +++ b/include/xlnt/writer/writer.hpp @@ -38,13 +38,9 @@ class document_properties; class writer { public: - static std::string write_content_types(const workbook &wb); + static std::string write_content_types(const workbook &wb); - static std::string write_properties_core(const document_properties &prop); - - static std::string write_properties_app(const workbook &wb); - - static std::string write_workbook(const workbook &wb); + static std::string write_properties_core(const document_properties &prop); static std::string write_theme(); @@ -54,14 +50,7 @@ public: const std::vector &string_table = {}, const std::unordered_map &style_table = {}); - static std::string write_root_rels(); - - static std::string write_workbook_rels(const workbook &wb); - static std::string write_worksheet_rels(worksheet ws); - -private: - static std::string write_relationships(const std::vector &relationships, const std::string &dir = ""); }; } // namespace xlnt diff --git a/include/xlnt/xlnt.hpp b/include/xlnt/xlnt.hpp index cd325777..c1386be8 100644 --- a/include/xlnt/xlnt.hpp +++ b/include/xlnt/xlnt.hpp @@ -50,3 +50,4 @@ const std::string download_url = "https://github.com/tfussell/xlnt/archive/maste #include "workbook/document_properties.hpp" #include "cell/comment.hpp" #include "common/encoding.hpp" +#include "workbook/named_range.hpp" diff --git a/source/cell_reference.cpp b/source/cell_reference.cpp index 5f9651a0..db129e56 100644 --- a/source/cell_reference.cpp +++ b/source/cell_reference.cpp @@ -102,13 +102,27 @@ std::pair cell_reference::split_reference(const std::string throw cell_coordinates_exception(reference_string); } } + else if(character == '$') + { + if(column_part) + { + if(column_string.empty()) + { + column_string.append(1, upper); + } + else + { + column_part = false; + } + } + } else { if(column_part) { column_part = false; } - else if(!(std::isdigit(character, std::locale::classic()) || character == '$')) + else if(!std::isdigit(character, std::locale::classic())) { throw cell_coordinates_exception(reference_string); } diff --git a/source/manifest_writer.cpp b/source/manifest_writer.cpp new file mode 100644 index 00000000..a3f7d970 --- /dev/null +++ b/source/manifest_writer.cpp @@ -0,0 +1,10 @@ +#include + +namespace xlnt { + +std::string write_content_types(const workbook &wb, bool as_template) +{ + return ""; +} + +} // namespace xlnt \ No newline at end of file diff --git a/source/named_range.cpp b/source/named_range.cpp new file mode 100644 index 00000000..3a1781de --- /dev/null +++ b/source/named_range.cpp @@ -0,0 +1,73 @@ + +#include +#include +#include +#include + +namespace { + +/// +/// Return a vector containing string split at each delim. +/// +/// +/// This should maybe be in a utility header so it can be used elsewhere. +/// +std::vector split_string(const std::string &string, char delim) +{ + std::vector split; + std::string::size_type previous_index = 0; + auto separator_index = string.find(delim); + + while(separator_index != std::string::npos) + { + auto part = string.substr(previous_index, separator_index - previous_index); + split.push_back(part); + + previous_index = separator_index + 1; + separator_index = string.find(delim, previous_index); + } + + split.push_back(string.substr(previous_index)); + + return split; +} + +} // namespace + +namespace xlnt { + +std::vector> split_named_range(const std::string &named_range_string) +{ + std::vector> final; + + for(auto part : split_string(named_range_string, ',')) + { + auto split = split_string(part, '!'); + + if(split[0].front() == '\'' && split[0].back() == '\'') + { + split[0] = split[0].substr(1, split[0].length() - 2); + } + + // Try to parse it. Use empty string if it's not a valid range. + try + { + xlnt::range_reference ref(split[1]); + } + catch(xlnt::cell_coordinates_exception) + { + split[1] = ""; + } + + final.push_back({split[0], split[1]}); + } + + return final; +} + +named_range::named_range(const std::string &name, const std::vector> &targets) +{ + +} + +} // namespace xlnt \ No newline at end of file diff --git a/source/relationship_writer.cpp b/source/relationship_writer.cpp new file mode 100644 index 00000000..7ea3ce48 --- /dev/null +++ b/source/relationship_writer.cpp @@ -0,0 +1,45 @@ +#include + +#include +#include + +#include "constants.hpp" +#include "detail/include_pugixml.hpp" + +namespace xlnt { + +std::string write_relationships(const std::vector &relationships, const std::string &dir) +{ + pugi::xml_document doc; + + auto root_node = doc.append_child("Relationships"); + root_node.append_attribute("xmlns").set_value(constants::Namespaces.at("relationships").c_str()); + + for(auto relationship : relationships) + { + auto target = relationship.get_target_uri(); + + if (dir != "" && target.substr(0, dir.size()) == dir) + { + target = target.substr(dir.size()); + } + + auto app_props_node = root_node.append_child("Relationship"); + + app_props_node.append_attribute("Id").set_value(relationship.get_id().c_str()); + app_props_node.append_attribute("Target").set_value(target.c_str()); + app_props_node.append_attribute("Type").set_value(relationship.get_type_string().c_str()); + + if(relationship.get_target_mode() == target_mode::external) + { + app_props_node.append_attribute("TargetMode").set_value("External"); + } + } + + std::stringstream ss; + doc.save(ss); + + return ss.str(); +} + +} \ No newline at end of file diff --git a/source/workbook.cpp b/source/workbook.cpp index 02d7459a..5895e184 100644 --- a/source/workbook.cpp +++ b/source/workbook.cpp @@ -8,17 +8,18 @@ #include #endif -#include #include -#include -#include -#include #include -#include -#include #include +#include +#include #include +#include +#include +#include #include +#include +#include #include "detail/cell_impl.hpp" #include "detail/include_pugixml.hpp" @@ -564,7 +565,7 @@ bool workbook::save(const std::string &filename) f.writestr("[Content_Types].xml", writer::write_content_types(*this)); - f.writestr("docProps/app.xml", writer::write_properties_app(*this)); + f.writestr("docProps/app.xml", write_properties_app(*this)); f.writestr("docProps/core.xml", writer::write_properties_core(get_properties())); std::set shared_strings_set; @@ -589,10 +590,10 @@ bool workbook::save(const std::string &filename) f.writestr("xl/theme/theme1.xml", writer::write_theme()); f.writestr("xl/styles.xml", style_writer(*this).write_table()); - f.writestr("_rels/.rels", writer::write_root_rels()); - f.writestr("xl/_rels/workbook.xml.rels", writer::write_workbook_rels(*this)); + f.writestr("_rels/.rels", write_root_rels(*this)); + f.writestr("xl/_rels/workbook.xml.rels", write_workbook_rels(*this)); - f.writestr("xl/workbook.xml", writer::write_workbook(*this)); + f.writestr("xl/workbook.xml", write_workbook(*this)); for(auto relationship : d_->relationships_) { @@ -741,6 +742,25 @@ std::size_t workbook::index_from_ws_filename(const std::string &ws_filename) void workbook::add_font(xlnt::font f) { + } + + void workbook::set_code_name(const std::string &code_name) + { + } + void workbook::add_named_range(const xlnt::named_range &n) + { + + } + + bool workbook::has_loaded_theme() + { + return false; + } + + std::string workbook::get_loaded_theme() + { + return ""; + } } diff --git a/source/workbook_writer.cpp b/source/workbook_writer.cpp new file mode 100644 index 00000000..5026afb2 --- /dev/null +++ b/source/workbook_writer.cpp @@ -0,0 +1,285 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "constants.hpp" +#include "detail/include_pugixml.hpp" + +namespace { + +std::string to_xml(xlnt::document_properties &props) +{ + return ""; +} + +} // namespace + +namespace xlnt { + +excel_writer::excel_writer(workbook &wb) : wb_(wb), style_writer_(wb_) +{ +} + +void excel_writer::save(const std::string &filename, bool as_template) +{ + zip_file archive; + write_data(archive, as_template); + archive.save(filename); +} + +void excel_writer::write_data(zip_file &archive, bool as_template) +{ + archive.writestr(constants::ArcRootRels, write_root_rels(wb_)); + archive.writestr(constants::ArcWorkbookRels, write_workbook_rels(wb_)); + archive.writestr(constants::ArcApp, write_properties_app(wb_)); + archive.writestr(constants::ArcCore, to_xml(wb_.get_properties())); + + if(wb_.has_loaded_theme()) + { + archive.writestr(constants::ArcTheme, wb_.get_loaded_theme()); + } + else + { + archive.writestr(constants::ArcTheme, write_theme()); + } + + archive.writestr(constants::ArcWorkbook, write_workbook(wb_)); + + /* + if(wb_.has_vba_archive()) + { + auto &vba_archive = wb_.get_vba_archive(); + + for(auto name : vba_archive.namelist()) + { + for(auto s : constants::ArcVba) + { + if(match(s, name)) + { + archive.writestr(name, vba_archive.read(name)); + break; + } + } + } + } + */ + + write_charts(archive); + write_images(archive); + write_worksheets(archive); + write_chartsheets(archive); + write_string_table(archive); + write_external_links(archive); + archive.writestr(constants::ArcStyles, style_writer_.write_table()); + auto manifest = write_content_types(wb_, as_template); + archive.writestr(constants::ArcContentTypes, manifest); +} + +void excel_writer::write_string_table(zip_file &archive) +{ + +} + +void excel_writer::write_images(zip_file &archive) +{ + +} + +void excel_writer::write_charts(zip_file &archive) +{ + +} + +void excel_writer::write_chartsheets(zip_file &archive) +{ + +} + +void excel_writer::write_worksheets(zip_file &archive) +{ + +} + +void excel_writer::write_external_links(zip_file &archive) +{ + +} + +std::string write_properties_app(const workbook &wb) +{ + pugi::xml_document doc; + auto root_node = doc.append_child("Properties"); + root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"); + root_node.append_attribute("xmlns:vt").set_value("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"); + + root_node.append_child("Application").text().set("Microsoft Excel"); + root_node.append_child("DocSecurity").text().set("0"); + root_node.append_child("ScaleCrop").text().set("false"); + root_node.append_child("Company"); + root_node.append_child("LinksUpToDate").text().set("false"); + root_node.append_child("SharedDoc").text().set("false"); + root_node.append_child("HyperlinksChanged").text().set("false"); + root_node.append_child("AppVersion").text().set("12.0000"); + + auto heading_pairs_node = root_node.append_child("HeadingPairs"); + auto heading_pairs_vector_node = heading_pairs_node.append_child("vt:vector"); + heading_pairs_vector_node.append_attribute("baseType").set_value("variant"); + heading_pairs_vector_node.append_attribute("size").set_value("2"); + heading_pairs_vector_node.append_child("vt:variant").append_child("vt:lpstr").text().set("Worksheets"); + heading_pairs_vector_node.append_child("vt:variant").append_child("vt:i4").text().set(std::to_string(wb.get_sheet_names().size()).c_str()); + + auto titles_of_parts_node = root_node.append_child("TitlesOfParts"); + auto titles_of_parts_vector_node = titles_of_parts_node.append_child("vt:vector"); + titles_of_parts_vector_node.append_attribute("baseType").set_value("lpstr"); + titles_of_parts_vector_node.append_attribute("size").set_value(std::to_string(wb.get_sheet_names().size()).c_str()); + + for(auto ws : wb) + { + titles_of_parts_vector_node.append_child("vt:lpstr").text().set(ws.get_title().c_str()); + } + + std::stringstream ss; + doc.save(ss); + + return ss.str(); +} + +std::string write_root_rels(const workbook &) +{ + std::vector relationships; + + relationships.push_back(relationship(relationship::type::extended_properties, "rId3", "docProps/app.xml")); + relationships.push_back(relationship(relationship::type::core_properties, "rId2", "docProps/core.xml")); + relationships.push_back(relationship(relationship::type::office_document, "rId1", "xl/workbook.xml")); + + return write_relationships(relationships, ""); +} + +std::string write_workbook(const workbook &wb) +{ + std::size_t num_visible = 0; + + for(auto ws : wb) + { + if(ws.get_page_setup().get_sheet_state() == xlnt::page_setup::sheet_state::visible) + { + num_visible++; + } + } + + if(num_visible == 0) + { + throw value_error(); + } + + pugi::xml_document doc; + auto root_node = doc.append_child("workbook"); + root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main"); + root_node.append_attribute("xmlns:r").set_value("http://schemas.openxmlformats.org/officeDocument/2006/relationships"); + + auto file_version_node = root_node.append_child("fileVersion"); + file_version_node.append_attribute("appName").set_value("xl"); + file_version_node.append_attribute("lastEdited").set_value("4"); + file_version_node.append_attribute("lowestEdited").set_value("4"); + file_version_node.append_attribute("rupBuild").set_value("4505"); + + auto workbook_pr_node = root_node.append_child("workbookPr"); + workbook_pr_node.append_attribute("codeName").set_value("ThisWorkbook"); + workbook_pr_node.append_attribute("defaultThemeVersion").set_value("124226"); + + auto book_views_node = root_node.append_child("bookViews"); + auto workbook_view_node = book_views_node.append_child("workbookView"); + workbook_view_node.append_attribute("activeTab").set_value("0"); + workbook_view_node.append_attribute("autoFilterDateGrouping").set_value("1"); + workbook_view_node.append_attribute("firstSheet").set_value("0"); + workbook_view_node.append_attribute("minimized").set_value("0"); + workbook_view_node.append_attribute("showHorizontalScroll").set_value("1"); + workbook_view_node.append_attribute("showSheetTabs").set_value("1"); + workbook_view_node.append_attribute("showVerticalScroll").set_value("1"); + workbook_view_node.append_attribute("tabRatio").set_value("600"); + workbook_view_node.append_attribute("visibility").set_value("visible"); + + auto sheets_node = root_node.append_child("sheets"); + auto defined_names_node = root_node.append_child("definedNames"); + + for(auto relationship : wb.get_relationships()) + { + if(relationship.get_type() == relationship::type::worksheet) + { + std::string sheet_index_string = relationship.get_target_uri(); + sheet_index_string = sheet_index_string.substr(0, sheet_index_string.find('.')); + sheet_index_string = sheet_index_string.substr(sheet_index_string.find_last_of('/')); + auto iter = sheet_index_string.end(); + iter--; + while (isdigit(*iter)) iter--; + auto first_digit = iter - sheet_index_string.begin(); + sheet_index_string = sheet_index_string.substr(first_digit + 1); + std::size_t sheet_index = std::stoi(sheet_index_string) - 1; + + auto ws = wb.get_sheet_by_index(sheet_index); + + auto sheet_node = sheets_node.append_child("sheet"); + sheet_node.append_attribute("name").set_value(ws.get_title().c_str()); + sheet_node.append_attribute("r:id").set_value(relationship.get_id().c_str()); + sheet_node.append_attribute("sheetId").set_value(std::to_string(sheet_index + 1).c_str()); + + if(ws.has_auto_filter()) + { + auto defined_name_node = defined_names_node.append_child("definedName"); + defined_name_node.append_attribute("name").set_value("_xlnm._FilterDatabase"); + defined_name_node.append_attribute("hidden").set_value(1); + defined_name_node.append_attribute("localSheetId").set_value(0); + std::string name = "'" + ws.get_title() + "'!" + range_reference::make_absolute(ws.get_auto_filter()).to_string(); + defined_name_node.text().set(name.c_str()); + } + } + } + + auto calc_pr_node = root_node.append_child("calcPr"); + calc_pr_node.append_attribute("calcId").set_value("124519"); + calc_pr_node.append_attribute("calcMode").set_value("auto"); + calc_pr_node.append_attribute("fullCalcOnLoad").set_value("1"); + + std::stringstream ss; + doc.save(ss); + + return ss.str(); +} + +std::string write_workbook_rels(const workbook &wb) +{ + return write_relationships(wb.get_relationships(), "xl/"); +} + +std::string write_theme() +{ + return ""; +} + +bool save_workbook(workbook &wb, const std::string &filename, bool as_template) +{ + excel_writer writer(wb); + writer.save(filename, as_template); + return true; +} + +std::vector save_virtual_workbook(xlnt::workbook &wb, bool as_template) +{ + excel_writer writer(wb); + std::vector buffer; + zip_file archive(buffer); + writer.write_data(archive, as_template); + return buffer; +} + +} // namespace xlnt diff --git a/source/worksheet.cpp b/source/worksheet.cpp index b77af9ae..9e9c1980 100644 --- a/source/worksheet.cpp +++ b/source/worksheet.cpp @@ -699,5 +699,10 @@ cell_reference worksheet::get_point_pos(const std::pair &point) const { return get_point_pos(point.first, point.second); } + +void worksheet::set_sheet_state(page_setup::sheet_state state) +{ + get_page_setup().set_sheet_state(state); +} } // namespace xlnt diff --git a/source/writer.cpp b/source/writer.cpp index 4e38d6f4..22050b87 100644 --- a/source/writer.cpp +++ b/source/writer.cpp @@ -5,25 +5,25 @@ #include #include -#include - -#include #include +#include +#include +#include #include #include #include -#include -#include -#include +#include +#include #include "constants.hpp" +#include "detail/include_pugixml.hpp" namespace { bool is_integral(long double d) - { - return d == static_cast(d); - } +{ + return d == static_cast(d); +} } // namespace @@ -90,129 +90,9 @@ std::string writer::write_properties_core(const document_properties &prop) return ss.str(); } -std::string writer::write_properties_app(const workbook &wb) -{ - pugi::xml_document doc; - auto root_node = doc.append_child("Properties"); - root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"); - root_node.append_attribute("xmlns:vt").set_value("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"); - - root_node.append_child("Application").text().set("Microsoft Excel"); - root_node.append_child("DocSecurity").text().set("0"); - root_node.append_child("ScaleCrop").text().set("false"); - root_node.append_child("Company"); - root_node.append_child("LinksUpToDate").text().set("false"); - root_node.append_child("SharedDoc").text().set("false"); - root_node.append_child("HyperlinksChanged").text().set("false"); - root_node.append_child("AppVersion").text().set("12.0000"); - - auto heading_pairs_node = root_node.append_child("HeadingPairs"); - auto heading_pairs_vector_node = heading_pairs_node.append_child("vt:vector"); - heading_pairs_vector_node.append_attribute("baseType").set_value("variant"); - heading_pairs_vector_node.append_attribute("size").set_value("2"); - heading_pairs_vector_node.append_child("vt:variant").append_child("vt:lpstr").text().set("Worksheets"); - heading_pairs_vector_node.append_child("vt:variant").append_child("vt:i4").text().set(std::to_string(wb.get_sheet_names().size()).c_str()); - - auto titles_of_parts_node = root_node.append_child("TitlesOfParts"); - auto titles_of_parts_vector_node = titles_of_parts_node.append_child("vt:vector"); - titles_of_parts_vector_node.append_attribute("baseType").set_value("lpstr"); - titles_of_parts_vector_node.append_attribute("size").set_value(std::to_string(wb.get_sheet_names().size()).c_str()); - - for(auto ws : wb) - { - titles_of_parts_vector_node.append_child("vt:lpstr").text().set(ws.get_title().c_str()); - } - - std::stringstream ss; - doc.save(ss); - - return ss.str(); -} - -std::string writer::write_workbook_rels(const workbook &wb) -{ - return write_relationships(wb.get_relationships(), "xl/"); -} - std::string writer::write_worksheet_rels(worksheet ws) { - return write_relationships(ws.get_relationships()); -} - -std::string writer::write_workbook(const workbook &wb) -{ - pugi::xml_document doc; - auto root_node = doc.append_child("workbook"); - root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main"); - root_node.append_attribute("xmlns:r").set_value("http://schemas.openxmlformats.org/officeDocument/2006/relationships"); - - auto file_version_node = root_node.append_child("fileVersion"); - file_version_node.append_attribute("appName").set_value("xl"); - file_version_node.append_attribute("lastEdited").set_value("4"); - file_version_node.append_attribute("lowestEdited").set_value("4"); - file_version_node.append_attribute("rupBuild").set_value("4505"); - - auto workbook_pr_node = root_node.append_child("workbookPr"); - workbook_pr_node.append_attribute("codeName").set_value("ThisWorkbook"); - workbook_pr_node.append_attribute("defaultThemeVersion").set_value("124226"); - - auto book_views_node = root_node.append_child("bookViews"); - auto workbook_view_node = book_views_node.append_child("workbookView"); - workbook_view_node.append_attribute("activeTab").set_value("0"); - workbook_view_node.append_attribute("autoFilterDateGrouping").set_value("1"); - workbook_view_node.append_attribute("firstSheet").set_value("0"); - workbook_view_node.append_attribute("minimized").set_value("0"); - workbook_view_node.append_attribute("showHorizontalScroll").set_value("1"); - workbook_view_node.append_attribute("showSheetTabs").set_value("1"); - workbook_view_node.append_attribute("showVerticalScroll").set_value("1"); - workbook_view_node.append_attribute("tabRatio").set_value("600"); - workbook_view_node.append_attribute("visibility").set_value("visible"); - - auto sheets_node = root_node.append_child("sheets"); - auto defined_names_node = root_node.append_child("definedNames"); - - for(auto relationship : wb.get_relationships()) - { - if(relationship.get_type() == relationship::type::worksheet) - { - std::string sheet_index_string = relationship.get_target_uri(); - sheet_index_string = sheet_index_string.substr(0, sheet_index_string.find('.')); - sheet_index_string = sheet_index_string.substr(sheet_index_string.find_last_of('/')); - auto iter = sheet_index_string.end(); - iter--; - while (isdigit(*iter)) iter--; - auto first_digit = iter - sheet_index_string.begin(); - sheet_index_string = sheet_index_string.substr(first_digit + 1); - std::size_t sheet_index = std::stoi(sheet_index_string) - 1; - - auto ws = wb.get_sheet_by_index(sheet_index); - - auto sheet_node = sheets_node.append_child("sheet"); - sheet_node.append_attribute("name").set_value(ws.get_title().c_str()); - sheet_node.append_attribute("r:id").set_value(relationship.get_id().c_str()); - sheet_node.append_attribute("sheetId").set_value(std::to_string(sheet_index + 1).c_str()); - - if(ws.has_auto_filter()) - { - auto defined_name_node = defined_names_node.append_child("definedName"); - defined_name_node.append_attribute("name").set_value("_xlnm._FilterDatabase"); - defined_name_node.append_attribute("hidden").set_value(1); - defined_name_node.append_attribute("localSheetId").set_value(0); - std::string name = "'" + ws.get_title() + "'!" + range_reference::make_absolute(ws.get_auto_filter()).to_string(); - defined_name_node.text().set(name.c_str()); - } - } - } - - auto calc_pr_node = root_node.append_child("calcPr"); - calc_pr_node.append_attribute("calcId").set_value("124519"); - calc_pr_node.append_attribute("calcMode").set_value("auto"); - calc_pr_node.append_attribute("fullCalcOnLoad").set_value("1"); - - std::stringstream ss; - doc.save(ss); - - return ss.str(); + return write_relationships(ws.get_relationships(), ""); } std::string writer::write_worksheet(worksheet ws, const std::vector &string_table, const std::unordered_map &style_id_by_hash) @@ -571,50 +451,6 @@ std::string writer::write_content_types(const workbook &wb) return ss.str(); } -std::string xlnt::writer::write_root_rels() -{ - std::vector relationships; - - relationships.push_back(relationship(relationship::type::extended_properties, "rId3", "docProps/app.xml")); - relationships.push_back(relationship(relationship::type::core_properties, "rId2", "docProps/core.xml")); - relationships.push_back(relationship(relationship::type::office_document, "rId1", "xl/workbook.xml")); - - return write_relationships(relationships); -} - -std::string writer::write_relationships(const std::vector &relationships, const std::string &dir) -{ - pugi::xml_document doc; - - auto root_node = doc.append_child("Relationships"); - root_node.append_attribute("xmlns").set_value(constants::Namespaces.at("relationships").c_str()); - - for(auto relationship : relationships) - { - auto target = relationship.get_target_uri(); - - if (dir != "" && target.substr(0, dir.size()) == dir) - { - target = target.substr(dir.size()); - } - - auto app_props_node = root_node.append_child("Relationship"); - - app_props_node.append_attribute("Id").set_value(relationship.get_id().c_str()); - app_props_node.append_attribute("Target").set_value(target.c_str()); - app_props_node.append_attribute("Type").set_value(relationship.get_type_string().c_str()); - - if(relationship.get_target_mode() == target_mode::external) - { - app_props_node.append_attribute("TargetMode").set_value("External"); - } - } - - std::stringstream ss; - doc.save(ss); - return ss.str(); -} - std::string writer::write_theme() { pugi::xml_document doc; diff --git a/tests/helpers/helper.hpp b/tests/helpers/helper.hpp index 74c55076..48dcda7b 100644 --- a/tests/helpers/helper.hpp +++ b/tests/helpers/helper.hpp @@ -28,6 +28,11 @@ public: operator bool() const { return difference == difference_type::equivalent; } }; + static comparison_result compare_xml(const std::string &left_contents, const std::string &right_contents) + { + return {difference_type::names_differ,"",""}; + } + static comparison_result compare_xml(const pugi::xml_node &left, const pugi::xml_node &right) { std::string left_temp = left.name(); diff --git a/tests/helpers/path_helper.hpp b/tests/helpers/path_helper.hpp index 3625c18e..bde1177d 100644 --- a/tests/helpers/path_helper.hpp +++ b/tests/helpers/path_helper.hpp @@ -2,6 +2,8 @@ #include #include +#include +#include #ifdef __APPLE__ #include @@ -20,6 +22,15 @@ class PathHelper { public: + static std::string read_file(const std::string &filename) + { + std::ifstream f(filename); + std::ostringstream ss; + ss << f.rdbuf(); + + return ss.str(); + } + static std::string WindowsToUniversalPath(const std::string &windows_path) { std::string fixed; diff --git a/tests/test_named_range.hpp b/tests/test_named_range.hpp index 6a217c78..0c17a8b2 100644 --- a/tests/test_named_range.hpp +++ b/tests/test_named_range.hpp @@ -3,14 +3,38 @@ #include #include -#include +#include class test_named_range : public CxxTest::TestSuite { public: void test_split() { - /*TS_ASSERT_EQUALS([("My Sheet", "$D$8"), ], split_named_range(""My Sheet"!$D$8"))*/ + using string_pair = std::pair; + using string_pair_vector = std::vector; + using expected_pair = std::pair; + + std::vector expected_pairs = + { + { "'My Sheet'!$D$8", {{ "My Sheet", "$D$8" }} }, + { "Sheet1!$A$1", {{ "Sheet1", "$A$1" }} }, + { "[1]Sheet1!$A$1", {{ "[1]Sheet1", "$A$1" }} }, + { "[1]!B2range", {{ "[1]", "" }} }, + { "Sheet1!$C$5:$C$7,Sheet1!$C$9:$C$11,Sheet1!$E$5:$E$7,Sheet1!$E$9:$E$11,Sheet1!$D$8", + { + { "Sheet1", "$C$5:$C$7" }, + { "Sheet1", "$C$9:$C$11" }, + { "Sheet1", "$E$5:$E$7" }, + { "Sheet1", "$E$9:$E$11" }, + { "Sheet1", "$D$8" } + } + } + }; + + for(auto pair : expected_pairs) + { + TS_ASSERT_EQUALS(xlnt::split_named_range(pair.first), pair.second); + } } void test_split_no_quotes() diff --git a/tests/test_number_format.hpp b/tests/test_number_format.hpp deleted file mode 100644 index 45426a56..00000000 --- a/tests/test_number_format.hpp +++ /dev/null @@ -1,165 +0,0 @@ -#pragma once - -#include -#include - -#include - -class test_number_format : public CxxTest::TestSuite -{ -public: - test_number_format() - { - - } - - void setup_class(int cls) - { - //cls.workbook = Workbook() - // cls.worksheet = Worksheet(cls.workbook, "Test") - // cls.sd = SharedDate() - } - - void test_convert_date_to_julian() - { - //TS_ASSERT_EQUALS(40167, sd.to_julian(2009, 12, 20)) - } - - void test_convert_date_from_julian() - { - } - - void test_date_equal(int julian, int datetime) - { - //TS_ASSERT_EQUALS(sd.from_julian(julian), datetime); - - //date_pairs = ( - // (40167, datetime(2009, 12, 20)), - // (21980, datetime(1960, 3, 5)), - // ); - - //for count, dt in date_pairs - //{ - // yield test_date_equal, count, dt; - //} - } - - void test_convert_datetime_to_julian() - { - //TS_ASSERT_EQUALS(40167, sd.datetime_to_julian(datetime(2009, 12, 20))) - // TS_ASSERT_EQUALS(40196.5939815, sd.datetime_to_julian(datetime(2010, 1, 18, 14, 15, 20, 1600))) - } - - void test_insert_float() - { - //worksheet.cell("A1").value = 3.14 - // TS_ASSERT_EQUALS(Cell.TYPE_NUMERIC, worksheet.cell("A1")._data_type) - } - - void test_insert_percentage() - { - //worksheet.cell("A1").value = "3.14%" - // TS_ASSERT_EQUALS(Cell.TYPE_NUMERIC, worksheet.cell("A1")._data_type) - // assert_almost_equal(0.0314, worksheet.cell("A1").value) - } - - void test_insert_datetime() - { - //worksheet.cell("A1").value = date.today() - // TS_ASSERT_EQUALS(Cell.TYPE_NUMERIC, worksheet.cell("A1")._data_type) - } - - void test_insert_date() - { - //worksheet.cell("A1").value = datetime.now() - // TS_ASSERT_EQUALS(Cell.TYPE_NUMERIC, worksheet.cell("A1")._data_type) - } - - void test_internal_date() - { - //dt = datetime(2010, 7, 13, 6, 37, 41) - // worksheet.cell("A3").value = dt - // TS_ASSERT_EQUALS(40372.27616898148, worksheet.cell("A3")._value) - } - - void test_datetime_interpretation() - { - //dt = datetime(2010, 7, 13, 6, 37, 41) - // worksheet.cell("A3").value = dt - // TS_ASSERT_EQUALS(dt, worksheet.cell("A3").value) - } - - void test_date_interpretation() - { - //dt = date(2010, 7, 13) - // worksheet.cell("A3").value = dt - // TS_ASSERT_EQUALS(datetime(2010, 7, 13, 0, 0), worksheet.cell("A3").value) - } - - void test_number_format_style() - { - //worksheet.cell("A1").value = "12.6%" - // TS_ASSERT_EQUALS(NumberFormat.FORMAT_PERCENTAGE, \ - // worksheet.cell("A1").style.number_format.format_code) - } - - void test_date_format_on_non_date() - { - //cell = worksheet.cell("A1"); - } - - void check_date_pair(int count, const std::string &date_string) - { - //cell.value = strptime(date_string, "%Y-%m-%d"); - //TS_ASSERT_EQUALS(count, cell._value); - - //date_pairs = ( - // (15, "1900-01-15"), - // (59, "1900-02-28"), - // (61, "1900-03-01"), - // (367, "1901-01-01"), - // (2958465, "9999-12-31"), ); - //for count, date_string in date_pairs - //{ - // yield check_date_pair, count, date_string; - //} - } - - void test_1900_leap_year() - { - //assert_raises(ValueError, sd.from_julian, 60) - // assert_raises(ValueError, sd.to_julian, 1900, 2, 29) - } - - void test_bad_date() - { - //void check_bad_date(year, month, day) - //{ - // assert_raises(ValueError, sd.to_julian, year, month, day) - //} - - //bad_dates = ((1776, 7, 4), (1899, 12, 31), ) - // for year, month, day in bad_dates - // { - // yield check_bad_date, year, month, day - // } - } - - void test_bad_julian_date() - { - //assert_raises(ValueError, sd.from_julian, -1) - } - - void test_mac_date() - { - // sd.excel_base_date = CALENDAR_MAC_1904 - - // datetuple = (2011, 10, 31) - - // dt = date(datetuple[0], datetuple[1], datetuple[2]) - // julian = sd.to_julian(datetuple[0], datetuple[1], datetuple[2]) - // reverse = sd.from_julian(julian).date() - // TS_ASSERT_EQUALS(dt, reverse) - // sd.excel_base_date = CALENDAR_WINDOWS_1900 - } -}; diff --git a/tests/test_props.hpp b/tests/test_props.hpp index 17e5ff69..3625d929 100644 --- a/tests/test_props.hpp +++ b/tests/test_props.hpp @@ -3,7 +3,8 @@ #include #include -#include +#include + #include "helpers/path_helper.hpp" #include "helpers/helper.hpp" @@ -69,7 +70,7 @@ public: xlnt::workbook wb; wb.create_sheet(); wb.create_sheet(); - auto content = xlnt::writer::write_properties_app(wb); + auto content = xlnt::write_properties_app(wb); TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/app.xml", content)); } }; diff --git a/tests/test_write.hpp b/tests/test_write.hpp index 1d89def4..2a12ff75 100644 --- a/tests/test_write.hpp +++ b/tests/test_write.hpp @@ -41,7 +41,7 @@ public: void test_write_workbook_rels() { xlnt::workbook wb; - auto content = xlnt::writer::write_workbook_rels(wb); + auto content = xlnt::write_workbook_rels(wb); TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/workbook.xml.rels", content)); } @@ -49,7 +49,7 @@ public: void test_write_workbook() { xlnt::workbook wb; - auto content = xlnt::writer::write_workbook(wb); + auto content = xlnt::write_workbook(wb); TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/workbook.xml", content)); } @@ -163,7 +163,7 @@ public: auto content = xlnt::writer::write_worksheet(ws, {"hello"}, {}); TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_auto_filter.xml", content)); - content = xlnt::writer::write_workbook(wb); + content = xlnt::write_workbook(wb); TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/workbook_auto_filter.xml", content)); } diff --git a/tests/test_write_workbook.hpp b/tests/test_write_workbook.hpp new file mode 100644 index 00000000..316be0e5 --- /dev/null +++ b/tests/test_write_workbook.hpp @@ -0,0 +1,175 @@ +#pragma once + +#include +#include + +#include +#include + +#include "helpers/path_helper.hpp" + +namespace xlnt { + +xlnt::workbook load_workbook(const std::vector &bytes) +{ + return xlnt::workbook(); +} + +std::string write_workbook_rels(xlnt::workbook &wb) +{ + return ""; +} + +std::string write_root_rels(xlnt::workbook &wb) +{ + return ""; +} + +std::string write_defined_names(xlnt::workbook &wb) +{ + return ""; +} + +} + +class test_write_workbook : public CxxTest::TestSuite +{ +public: + void test_write_auto_filter() + { + xlnt::workbook wb; + auto ws = wb.create_sheet(); + ws.get_cell("F42").set_value("hello"); + ws.get_auto_filter() = "A1:F1"; + + auto content = xlnt::write_workbook(wb); + auto diff = Helper::compare_xml(PathHelper::read_file("workbook_auto_filter.xml"), content); + TS_ASSERT(!diff); + } + + void test_write_hidden_worksheet() + { + xlnt::workbook wb; + auto ws = wb.create_sheet(); + ws.set_sheet_state(xlnt::page_setup::sheet_state::hidden); + wb.create_sheet(); + auto xml = xlnt::write_workbook(wb); + std::string expected = + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + auto diff = Helper::compare_xml(xml, expected); + TS_ASSERT(!diff); + } + + void test_write_hidden_single_worksheet() + { + xlnt::workbook wb; + auto ws = wb.get_active_sheet(); + ws.set_sheet_state(xlnt::page_setup::sheet_state::hidden); + TS_ASSERT_THROWS(xlnt::write_workbook(wb), xlnt::value_error); + } + + void test_write_empty_workbook() + { + xlnt::workbook wb; + std::string dest_filename = "empty_book.xlsx"; + xlnt::save_workbook(wb, dest_filename); + TS_ASSERT(PathHelper::FileExists(dest_filename)); + } + + void test_write_virtual_workbook() + { + xlnt::workbook old_wb; + auto saved_wb = xlnt::save_virtual_workbook(old_wb); + auto new_wb = xlnt::load_workbook(saved_wb); + TS_ASSERT(new_wb != nullptr); + } + + void test_write_workbook_rels() + { + xlnt::workbook wb; + auto content = xlnt::write_workbook_rels(wb); + auto filename = "workbook.xml.rels"; + auto diff = Helper::compare_xml(PathHelper::read_file(filename), content); + TS_ASSERT(!diff); + } + + void test_write_workbook_() + { + xlnt::workbook wb; + auto content = xlnt::write_workbook(wb); + auto filename = "workbook.xml"; + auto diff = Helper::compare_xml(PathHelper::read_file(filename), content); + TS_ASSERT(!diff); + } + + void test_write_named_range() + { + xlnt::workbook wb; + auto ws = wb.create_sheet(); + xlnt::named_range xlrange("test_range", {{ws, "A1:B5"}}); + wb.add_named_range(xlrange); + auto xml = xlnt::write_defined_names(wb); + std::string expected = + "" + "'Sheet'!$A$1:$B$5" + ""; + auto diff = Helper::compare_xml(xml, expected); + TS_ASSERT(!diff); + } + + void test_read_workbook_code_name() + { +// with open(tmpl, "rb") as expected: +// TS_ASSERT(read_workbook_code_name(expected.read()) == code_name + } + + void test_write_workbook_code_name() + { + xlnt::workbook wb; + wb.set_code_name("MyWB"); + + auto content = xlnt::write_workbook(wb); + std::string expected = + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + auto diff = Helper::compare_xml(content, expected); + TS_ASSERT(!diff); + } + + void test_write_root_rels() + { + xlnt::workbook wb; + auto xml = xlnt::write_root_rels(wb); + std::string expected = + "" + " " + " " + " " + ""; + auto diff = Helper::compare_xml(xml, expected); + TS_ASSERT(!diff); + } + +private: + xlnt::workbook wb_; +};