diff options
Diffstat (limited to 'src/orcus_test_ods.cpp')
-rw-r--r-- | src/orcus_test_ods.cpp | 958 |
1 files changed, 958 insertions, 0 deletions
diff --git a/src/orcus_test_ods.cpp b/src/orcus_test_ods.cpp new file mode 100644 index 0000000..377c35b --- /dev/null +++ b/src/orcus_test_ods.cpp @@ -0,0 +1,958 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "test_global.hpp" +#include <orcus/orcus_ods.hpp> +#include <orcus/format_detection.hpp> +#include <orcus/stream.hpp> +#include <orcus/parser_global.hpp> +#include <orcus/spreadsheet/factory.hpp> +#include <orcus/spreadsheet/document.hpp> +#include <orcus/spreadsheet/sheet.hpp> +#include <orcus/spreadsheet/shared_strings.hpp> +#include <orcus/spreadsheet/styles.hpp> + +#include <cstdlib> +#include <cassert> +#include <string> +#include <iostream> +#include <sstream> +#include <vector> + +#include "filesystem_env.hpp" + +#include <mdds/flat_segment_tree.hpp> + +using namespace orcus; +using namespace orcus::spreadsheet; + +namespace ss = orcus::spreadsheet; + + +typedef mdds::flat_segment_tree<std::size_t, bool> bool_segment_type; + +namespace { + +std::unique_ptr<ss::document> load_doc(const fs::path& filepath) +{ + spreadsheet::range_size_t ss{1048576, 16384}; + std::unique_ptr<ss::document> doc = std::make_unique<ss::document>(ss); + import_factory factory(*doc); + orcus_ods app(&factory); + app.read_file(filepath.string()); + + return doc; +} + +std::vector<fs::path> dirs = { + SRCDIR"/test/ods/raw-values-1/", + SRCDIR"/test/ods/formula-1/", + SRCDIR"/test/ods/formula-2/", + SRCDIR"/test/ods/named-range/", + SRCDIR"/test/ods/named-expression/", + SRCDIR"/test/ods/named-expression-sheet-local/", +}; + +void test_ods_detection() +{ + ORCUS_TEST_FUNC_SCOPE; + + for (const auto& dir : dirs) + { + fs::path filepath = dir / "input.ods"; + file_content fc(filepath.string()); + assert(!fc.empty()); + + format_t detected = detect(fc.str()); + assert(detected == format_t::ods); + } +} + +void test_ods_create_filter() +{ + ORCUS_TEST_FUNC_SCOPE; + + ss::range_size_t ssize{1048576, 16384}; + std::unique_ptr<ss::document> doc = std::make_unique<ss::document>(ssize); + ss::import_factory factory(*doc); + + auto f = create_filter(format_t::ods, &factory); + assert(f); + assert(f->get_name() == "ods"); +} + +void test_ods_import_cell_values() +{ + ORCUS_TEST_FUNC_SCOPE; + + for (const auto& dir : dirs) + { + fs::path filepath{dir}; + filepath /= "input.ods"; + std::cout << filepath << std::endl; + + auto doc = load_doc(filepath); + assert(doc); + doc->recalc_formula_cells(); + + // Dump the content of the model. + std::ostringstream os; + doc->dump_check(os); + std::string check = os.str(); + + // Check that against known control. + filepath = dir; + filepath /= "check.txt"; + file_content control{filepath.string()}; + + assert(!check.empty()); + assert(!control.empty()); + + assert(trim(check) == trim(control.str())); + } +} + +void test_ods_import_column_widths_row_heights() +{ + ORCUS_TEST_FUNC_SCOPE; + + fs::path filepath{SRCDIR"/test/ods/column-width-row-height/input.ods"}; + auto doc = load_doc(filepath); + assert(doc); + + assert(doc->get_sheet_count() > 0); + spreadsheet::sheet* sh = doc->get_sheet(0); + assert(sh); + + // Column widths are in twips. + col_width_t cw = sh->get_col_width(1, nullptr, nullptr); + assert(cw == 1440); // 1 in + cw = sh->get_col_width(2, nullptr, nullptr); + assert(cw == 2160); // 1.5 in + cw = sh->get_col_width(3, nullptr, nullptr); + assert(cw == 2592); // 1.8 in + + // Row heights are in twips too. + row_height_t rh = sh->get_row_height(3, nullptr, nullptr); + assert(rh == 720); // 0.5 in + rh = sh->get_row_height(4, nullptr, nullptr); + assert(rh == 1440); // 1 in + rh = sh->get_row_height(5, nullptr, nullptr); + assert(rh == 2160); // 1.5 in + rh = sh->get_row_height(6, nullptr, nullptr); + assert(rh == 2592); // 1.8 in +} + +void test_ods_import_formatted_text() +{ + ORCUS_TEST_FUNC_SCOPE; + + fs::path filepath{SRCDIR"/test/ods/formatted-text/bold-and-italic.ods"}; + auto doc = load_doc(filepath); + assert(doc); + + assert(doc->get_sheet_count() > 0); + spreadsheet::sheet* sh = doc->get_sheet(0); + assert(sh); + + const shared_strings& ss = doc->get_shared_strings(); + + const styles& styles = doc->get_styles(); + + // A1 is unformatted + size_t str_id = sh->get_string_identifier(0,0); + const std::string* str = ss.get_string(str_id); + assert(str && *str == "Normal Text"); + std::size_t xfid = sh->get_cell_format(0, 0); + const ss::cell_format_t* xf = styles.get_cell_format(xfid); + assert(xf); + const ss::cell_style_t* xstyle = styles.get_cell_style_by_xf(xf->style_xf); + assert(xstyle); + assert(xstyle->name == "Default"); + const format_runs_t* fmt = ss.get_format_runs(str_id); + assert(!fmt); // The string should be unformatted. + + // A2 is all bold via cell format. + str_id = sh->get_string_identifier(1,0); + str = ss.get_string(str_id); + assert(str && *str == "Bold Text"); + xfid = sh->get_cell_format(1,0); + xf = styles.get_cell_format(xfid); + assert(xf); + const font_t* font_data = styles.get_font(xf->font); + assert(font_data); + assert(font_data->bold); + assert(*font_data->bold); + assert(font_data->italic); + assert(!*font_data->italic); + fmt = ss.get_format_runs(str_id); + assert(!fmt); // This string should be unformatted. + + // A3 is all italic. + str_id = sh->get_string_identifier(2,0); + str = ss.get_string(str_id); + assert(str && *str == "Italic Text"); + xfid = sh->get_cell_format(2,0); + xf = styles.get_cell_format(xfid); + assert(xf); + font_data = styles.get_font(xf->font); + assert(font_data); + assert(font_data->bold); + assert(!*font_data->bold); + assert(font_data->italic); + assert(*font_data->italic); + fmt = ss.get_format_runs(str_id); + assert(!fmt); // This string should be unformatted. + + // A4 is all bold and italic. + str_id = sh->get_string_identifier(3,0); + str = ss.get_string(str_id); + assert(str && *str == "Bold and Italic Text"); + xfid = sh->get_cell_format(3,0); + xf = styles.get_cell_format(xfid); + assert(xf); + font_data = styles.get_font(xf->font); + assert(font_data); + assert(font_data->bold); + assert(*font_data->bold); + assert(font_data->italic); + assert(*font_data->italic); + fmt = ss.get_format_runs(str_id); + assert(!fmt); // This string should be unformatted. + + // A5 has mixed format runs. + str_id = sh->get_string_identifier(4,0); + str = ss.get_string(str_id); + assert(str && *str == "Bold and Italic mixed"); + xfid = sh->get_cell_format(4,0); + xf = styles.get_cell_format(xfid); + assert(xf); + font_data = styles.get_font(xf->font); + fmt = ss.get_format_runs(str_id); + assert(fmt); // This string should be formatted. + + { + // Check the bold format segment. + bool_segment_type bold_runs(0, str->size(), font_data->bold ? *font_data->bold : false); + + for (size_t i = 0, n = fmt->size(); i < n; ++i) + { + format_run run = fmt->at(i); + bold_runs.insert_back(run.pos, run.pos+run.size, run.bold); + } + + bold_runs.build_tree(); + bool is_bold = false; + size_t start_pos, end_pos; + + // The first four letters 'Bold' should be bold. + bool good = bold_runs.search_tree(0, is_bold, &start_pos, &end_pos).second; + assert(good); + assert(is_bold); + assert(start_pos == 0); + assert(end_pos == 4); + + // The rest should be non-bold. + good = bold_runs.search_tree(4, is_bold, &start_pos, &end_pos).second; + assert(good); + assert(!is_bold); + assert(start_pos == 4); + assert(end_pos == str->size()); + } + + { + // Check the italic format segment. + bool_segment_type italic_runs(0, str->size(), font_data->italic ? *font_data->italic : false); + + for (size_t i = 0, n = fmt->size(); i < n; ++i) + { + format_run run = fmt->at(i); + italic_runs.insert_back(run.pos, run.pos+run.size, run.italic); + } + + italic_runs.build_tree(); + bool it_italic = false; + size_t start_pos, end_pos; + + // The first 9 letters 'Bold and ' should not be italic. + bool good = italic_runs.search_tree(0, it_italic, &start_pos, &end_pos).second; + assert(good); + assert(!it_italic); + assert(start_pos == 0); + assert(end_pos == 9); + + // The next 6 letters 'Italic' should be italic. + good = italic_runs.search_tree(9, it_italic, &start_pos, &end_pos).second; + assert(good); + assert(it_italic); + assert(start_pos == 9); + assert(end_pos == 15); + + // The rest should be non-italic. + good = italic_runs.search_tree(15, it_italic, &start_pos, &end_pos).second; + assert(good); + assert(!it_italic); + assert(start_pos == 15); + assert(end_pos == str->size()); + } +} + +void test_ods_import_number_formats() +{ + ORCUS_TEST_FUNC_SCOPE; + + fs::path filepath{SRCDIR"/test/ods/number-format/basic-set.ods"}; + + auto doc = load_doc(filepath); + assert(doc); + + assert(doc->get_sheet_count() > 0); + spreadsheet::sheet* sh = doc->get_sheet(0); + assert(sh); + + const styles& styles = doc->get_styles(); + + struct check + { + row_t row; + col_t col; + std::string_view format; + }; + + const check checks[] = { + { 1, 1, "#.000000" }, // B2 + { 2, 1, "[>=0][$₹]#,##0.00;[RED]-[$₹]#,##0.00" }, // B3 + { 3, 1, "0.00%" }, // B4 + { 4, 1, "#.00E+00" }, // B5 + { 5, 1, "BOOLEAN" }, // B6 + { 6, 1, "?/11" }, // B7 + { 7, 1, "MM/DD/YY" }, // B8 + { 8, 1, "HH:MM:SS AM/PM" }, // B9 + { 9, 1, "[>=0]0.00;[RED]-0.00" }, // B9 + { 10, 1, "#,##0.00" }, // B10 + { 11, 1, "Head @ Tail" }, // B11 + }; + + for (const auto& c : checks) + { + std::size_t xfid = sh->get_cell_format(c.row, c.col); + const cell_format_t* xf = styles.get_cell_format(xfid); + if (!xf) + { + std::cerr << "No cell format entry for (row=" << c.row << "; col=" << c.col << ")" << std::endl; + assert(false); + } + + const number_format_t* numfmt = styles.get_number_format(xf->number_format); + if (!numfmt) + { + std::cerr << "No number-format entry for (row=" << c.row << "; col=" << c.col << ")" << std::endl; + assert(false); + } + + if (numfmt->format_string && *numfmt->format_string != c.format) + { + std::cerr << "Number format strings differ: (expected='" << c.format << "'; actual='" + << *numfmt->format_string << "')" << std::endl; + + assert(false); + } + } +} + +void test_ods_import_cell_properties() +{ + ORCUS_TEST_FUNC_SCOPE; + + fs::path filepath{SRCDIR"/test/ods/cell-properties/wrap-and-shrink.ods"}; + + auto doc = load_doc(filepath); + assert(doc); + + const ss::styles& styles = doc->get_styles(); + const ss::sheet* sh = doc->get_sheet(0); + assert(sh); + + std::size_t xfid = sh->get_cell_format(0, 1); // B1 + const ss::cell_format_t* xf = styles.get_cell_format(xfid); + assert(xf); + assert(!xf->wrap_text); + assert(!xf->shrink_to_fit); + + xfid = sh->get_cell_format(1, 1); // B2 + xf = styles.get_cell_format(xfid); + assert(xf); + assert(xf->wrap_text); + assert(*xf->wrap_text); + assert(!xf->shrink_to_fit); + + xfid = sh->get_cell_format(2, 1); // B3 + xf = styles.get_cell_format(xfid); + assert(xf); + assert(!xf->wrap_text); + assert(xf->shrink_to_fit); + assert(*xf->shrink_to_fit); +} + +void test_ods_import_styles_direct_format() +{ + ORCUS_TEST_FUNC_SCOPE; + + fs::path filepath{SRCDIR"/test/ods/styles/direct-format.ods"}; + + auto doc = load_doc(filepath); + assert(doc); + + const ss::styles& styles = doc->get_styles(); + const ss::sheet* sh = doc->get_sheet(0); + assert(sh); + + // B2 - horizontally center, bold and underlined + std::size_t xfid = sh->get_cell_format(1, 1); + const ss::cell_format_t* xf = styles.get_cell_format(xfid); + assert(xf); + assert(xf->hor_align == ss::hor_alignment_t::center); + + const ss::font_t* font = styles.get_font(xf->font); + assert(font); + assert(font->bold); + assert(*font->bold); + assert(font->underline_style); + assert(*font->underline_style == ss::underline_t::single_line); + + // B4 - yellow background and right-aligned + xfid = sh->get_cell_format(3, 1); + xf = styles.get_cell_format(xfid); + assert(xf); + assert(xf->hor_align == ss::hor_alignment_t::right); + + const ss::fill_t* fill = styles.get_fill(xf->fill); + assert(fill); + assert(fill->pattern_type); + assert(*fill->pattern_type == ss::fill_pattern_t::solid); + assert(fill->fg_color); + assert(*fill->fg_color == ss::color_t(0xFF, 0xFF, 0xFF, 0x00)); + + // D4 - named style "Good" applied with no direct formatting on top + xfid = sh->get_cell_format(3, 3); + xf = styles.get_cell_format(xfid); + assert(xf); + + const ss::cell_style_t* xstyle = styles.get_cell_style_by_xf(xf->style_xf); + assert(xstyle); + assert(xstyle->name == "Good"); + + // D6 - named style "Good" plus wrap-text, center and middle aligned and bold text + xfid = sh->get_cell_format(5, 3); + xf = styles.get_cell_format(xfid); + assert(xf); + assert(xf->hor_align == ss::hor_alignment_t::center); + assert(xf->ver_align == ss::ver_alignment_t::middle); + assert(xf->wrap_text); + assert(*xf->wrap_text); + + font = styles.get_font(xf->font); + assert(font); + assert(font->bold); + assert(*font->bold); + + xstyle = styles.get_cell_style_by_xf(xf->style_xf); + assert(xstyle); + assert(xstyle->name == "Good"); +} + +void test_ods_import_styles_column_styles() +{ + ORCUS_TEST_FUNC_SCOPE; + + fs::path filepath{SRCDIR"/test/ods/styles/column-styles.ods"}; + + auto doc = load_doc(filepath); + assert(doc); + + const ss::styles& styles = doc->get_styles(); + const ss::sheet* sh = doc->get_sheet(0); + assert(sh); + + // A1 should have the Default style applied. + std::size_t xfid = sh->get_cell_format(0, 0); + const ss::cell_format_t* xf = styles.get_cell_format(xfid); + assert(xf); + + const ss::cell_style_t* xstyle = styles.get_cell_style_by_xf(xf->style_xf); + assert(xstyle); + assert(xstyle->name == "Default"); + + // This Default style has some custom properties. + xf = styles.get_cell_style_format(xf->style_xf); + assert(xf); + + // Default style has a solid fill with light green color. + const ss::fill_t* fill = styles.get_fill(xf->fill); + assert(fill); + assert(fill->pattern_type); + assert(*fill->pattern_type == ss::fill_pattern_t::solid); + assert(fill->fg_color); + assert(*fill->fg_color == ss::color_t(0xFF, 0xF6, 0xF9, 0xD4)); + assert(!fill->bg_color); + + // Default style has a 14pt DejaVu Sans font with normal weight + const ss::font_t* font = styles.get_font(xf->font); + assert(font); + assert(font->name); + assert(*font->name == "DejaVu Sans"); + assert(font->size); + assert(*font->size == 14.0); + assert(font->bold); + assert(!*font->bold); + + assert(xf->hor_align == ss::hor_alignment_t::center); + + // Columns B, E, G and rest all should have the "Default" style applied. + std::size_t xfid_default = xfid; + for (ss::col_t col : {1, 4, 6, 7, 8}) + { + std::cout << "column " << col << std::endl; + xfid = sh->get_cell_format(0, col); // top cell + assert(xfid == xfid_default); + xfid = sh->get_cell_format(doc->get_sheet_size().rows-1, col); // bottom cell + assert(xfid == xfid_default); + } + + // Column C should have "Gray With Lime" style applied + xfid = sh->get_cell_format(0, 2); + xf = styles.get_cell_format(xfid); + assert(xf); + xstyle = styles.get_cell_style_by_xf(xf->style_xf); + assert(xstyle); + assert(xstyle->name == "Gray With Lime" || xstyle->display_name == "Gray With Lime"); + + // Its parent style should be "Default". + xf = styles.get_cell_style_format(xf->style_xf); + assert(xf); + xstyle = styles.get_cell_style_by_xf(xf->style_xf); + assert(xstyle); + assert(xstyle->name == "Default"); + + // solid gray background + fill = styles.get_fill(xf->fill); + assert(fill); + assert(fill->pattern_type); + assert(*fill->pattern_type == ss::fill_pattern_t::solid); + assert(fill->fg_color); + assert(fill->fg_color == ss::color_t(0xFF, 0xCC, 0xCC, 0xCC)); + assert(!fill->bg_color); + + // bold, 16pt font, name not set + font = styles.get_font(xf->font); + assert(font); + assert(!font->name); + assert(font->size); + assert(*font->size == 16.0); + assert(font->bold); + assert(*font->bold); + + // left and right borders are solid light green + const ss::border_t* border = styles.get_border(xf->border); + assert(border); + + assert(border->left.style); + assert(*border->left.style == ss::border_style_t::solid); + assert(border->left.border_width); + assert(*border->left.border_width == length_t(length_unit_t::point, 2.01)); + assert(border->left.border_color); + assert(*border->left.border_color == ss::color_t(0xFF, 0x81, 0xD4, 0x1A)); + + assert(border->right.style); + assert(*border->right.style == ss::border_style_t::solid); + assert(border->right.border_width); + assert(*border->right.border_width == length_t(length_unit_t::point, 2.01)); + assert(border->right.border_color); + assert(*border->right.border_color == ss::color_t(0xFF, 0x81, 0xD4, 0x1A)); + + // Column D should have "Emphasis" style applied + xfid = sh->get_cell_format(0, 3); + xf = styles.get_cell_format(xfid); + assert(xf); + xstyle = styles.get_cell_style_by_xf(xf->style_xf); + assert(xstyle); + assert(xstyle->name == "Emphasis" || xstyle->display_name == "Emphasis"); + + // Its parent style should be "Default". + xf = styles.get_cell_style_format(xf->style_xf); + assert(xf); + xstyle = styles.get_cell_style_by_xf(xf->style_xf); + assert(xstyle); + assert(xstyle->name == "Default"); + + // solid pink background + fill = styles.get_fill(xf->fill); + assert(fill); + assert(fill->pattern_type); + assert(*fill->pattern_type == ss::fill_pattern_t::solid); + assert(fill->fg_color); + assert(*fill->fg_color == ss::color_t(0xFF, 0xFF, 0xd7, 0xd7)); + assert(!fill->bg_color); + + // font name 'Rasa Light', 18pt, underlined (solid double), red, not bold + font = styles.get_font(xf->font); + assert(font); + assert(font->name); + assert(*font->name == "Rasa Light"); + assert(font->size); + assert(*font->size == 18.0); + assert(font->bold); + assert(!*font->bold); // in the file, it is given as a font weight of 250 + assert(font->color); + assert(*font->color == ss::color_t(0xFF, 0xFF, 0x00, 0x00)); + // double underline is stored as single-line double-type? + assert(font->underline_style); + assert(*font->underline_style == ss::underline_t::single_line); + assert(font->underline_type); + assert(*font->underline_type == ss::underline_type_t::double_type); + assert(!font->underline_color); // implies the same as font color + + // Column F has "Default" style plus solid light purple background and bold font on top + xfid = sh->get_cell_format(0, 5); + xf = styles.get_cell_format(xfid); + assert(xf); + xstyle = styles.get_cell_style_by_xf(xf->style_xf); + assert(xstyle); + assert(xstyle->name == "Default"); + + // light purple solid background + fill = styles.get_fill(xf->fill); + assert(fill); + assert(fill->pattern_type); + assert(*fill->pattern_type == ss::fill_pattern_t::solid); + assert(fill->fg_color); + assert(*fill->fg_color == ss::color_t(0xFF, 0xE0, 0xC2, 0xCD)); + + // bold font + font = styles.get_font(xf->font); + assert(font); + assert(font->bold); + assert(*font->bold); + + // Check on row 10 cell format from column A to column G + for (ss::col_t col = 0; col <= 100; ++col) + { + std::cout << "(row=9; column=" << col << ")" << std::endl; + xfid = sh->get_cell_format(9, col); + xf = styles.get_cell_format(xfid); + assert(xf); + assert(xf->ver_align == ss::ver_alignment_t::top); + + fill = styles.get_fill(xf->fill); + assert(fill); + + assert(fill->pattern_type); + assert(*fill->pattern_type == ss::fill_pattern_t::solid); + assert(fill->fg_color); + assert(*fill->fg_color == ss::color_t(0xFF, 0x00, 0xA9, 0x33)); + } + + // Move on to the next sheet... + sh = doc->get_sheet(1); + assert(sh); + + // Column A uses "Default" + xfid = sh->get_cell_format(0, 0); + xf = styles.get_cell_format(xfid); + assert(xf); + xstyle = styles.get_cell_style_by_xf(xf->style_xf); + assert(xstyle); + assert(xstyle->name == "Default"); + + // Columns B:D use "Gray With Lime" with direct background color + for (ss::col_t col : {1, 2, 3}) + { + std::cout << "column " << col << std::endl; + xfid = sh->get_cell_format(0, col); + xf = styles.get_cell_format(xfid); + assert(xf); + + xstyle = styles.get_cell_style_by_xf(xf->style_xf); + assert(xstyle); + assert(xstyle->name == "Gray With Lime" || xstyle->display_name == "Gray With Lime"); + + fill = styles.get_fill(xf->fill); + assert(fill); + assert(fill->pattern_type); + assert(*fill->pattern_type == ss::fill_pattern_t::solid); + assert(fill->fg_color); + assert(*fill->fg_color == ss::color_t(0xFF, 0xFF, 0xDE, 0x59)); + } + + // Column E and the rest all use "Default" + xfid = sh->get_cell_format(0, 4); + xf = styles.get_cell_format(xfid); + assert(xf); + xstyle = styles.get_cell_style_by_xf(xf->style_xf); + assert(xstyle); + assert(xstyle->name == "Default"); + + // Columns F:I have narrower width of 0.5 inch. + { + ss::col_t col_start = -1, col_end = -1; + // column widths are stored in twips + ss::col_width_t cw = sh->get_col_width(5, &col_start, &col_end); + assert(col_start == 5); + assert(col_end == 9); // column I has an id = 8, plus 1 for the end position + length_t v{length_unit_t::inch, 0.5}; + ss::col_width_t cw_expected = convert(0.5, length_unit_t::inch, length_unit_t::twip); + assert(cw == cw_expected); + } +} + +void test_ods_import_styles_asian_complex() +{ + ORCUS_TEST_FUNC_SCOPE; + + fs::path filepath{SRCDIR"/test/ods/styles/asian-complex.ods"}; + + auto doc = load_doc(filepath); + assert(doc); + + const ss::styles& styles = doc->get_styles(); + const ss::sheet* sh = doc->get_sheet(0); + assert(sh); + + std::size_t xfid = sh->get_cell_format(0, 0); // A1 + const ss::cell_format_t* xf = styles.get_cell_format(xfid); + assert(xf); + + const ss::font_t* font = styles.get_font(xf->font); + assert(font); + + assert(font->name); + assert(*font->name == "FreeMono"); + assert(font->size); + assert(*font->size == 12.0); + assert(!font->bold); // bold not set + assert(font->italic); + assert(*font->italic); + + xfid = sh->get_cell_format(1, 0); // A2 + xf = styles.get_cell_format(xfid); + assert(xf); + + font = styles.get_font(xf->font); + assert(font); + + assert(font->name_asian); + assert(*font->name_asian == "Noto Sans CJK SC"); + assert(font->size_asian); + assert(*font->size_asian == 16.0); + assert(font->bold_asian); + assert(*font->bold_asian); + assert(font->italic_asian); + assert(*font->italic_asian); + + xfid = sh->get_cell_format(2, 0); // A3 + xf = styles.get_cell_format(xfid); + assert(xf); + + font = styles.get_font(xf->font); + assert(font); + + assert(font->name_complex); + assert(*font->name_complex == "Gubbi"); + assert(font->size_complex); + assert(*font->size_complex == 24.0); + assert(font->bold_complex); + assert(*font->bold_complex); + assert(font->italic_complex); + assert(*font->italic_complex); +} + +void test_ods_import_styles_text_underlines() +{ + ORCUS_TEST_FUNC_SCOPE; + + fs::path filepath{SRCDIR"/test/ods/styles/text-underlines.ods"}; + + auto doc = load_doc(filepath); + assert(doc); + + const ss::styles& styles = doc->get_styles(); + const ss::sheet* sh = doc->get_sheet(0); + assert(sh); + + std::size_t xfid = sh->get_cell_format(1, 0); // A2 + const ss::cell_format_t* xf = styles.get_cell_format(xfid); + assert(xf); + + const ss::font_t* font = styles.get_font(xf->font); + assert(font); + assert(font->underline_style); + assert(*font->underline_style == ss::underline_t::single_line); // solid + assert(font->underline_width); + assert(*font->underline_width == ss::underline_width_t::automatic); + assert(!font->underline_color); // same as the font color + + xfid = sh->get_cell_format(2, 0); // A3 + xf = styles.get_cell_format(xfid); + assert(xf); + + font = styles.get_font(xf->font); + assert(font); + assert(font->underline_style); + assert(*font->underline_style == ss::underline_t::single_line); // solid + assert(font->underline_type); + assert(*font->underline_type == ss::underline_type_t::double_type); + assert(font->underline_width); + assert(*font->underline_width == ss::underline_width_t::automatic); + assert(!font->underline_color); // same as the font color + + xfid = sh->get_cell_format(3, 0); // A4 + xf = styles.get_cell_format(xfid); + assert(xf); + + font = styles.get_font(xf->font); + assert(font); + assert(font->underline_style); + assert(*font->underline_style == ss::underline_t::single_line); // solid + assert(font->underline_width); + assert(*font->underline_width == ss::underline_width_t::bold); + assert(!font->underline_color); // same as the font color + + xfid = sh->get_cell_format(4, 0); // A5 + xf = styles.get_cell_format(xfid); + assert(xf); + + font = styles.get_font(xf->font); + assert(font); + assert(font->underline_style); + assert(*font->underline_style == ss::underline_t::dotted); + assert(font->underline_width); + assert(*font->underline_width == ss::underline_width_t::automatic); + assert(!font->underline_color); // same as the font color + + xfid = sh->get_cell_format(5, 0); // A6 + xf = styles.get_cell_format(xfid); + assert(xf); + + font = styles.get_font(xf->font); + assert(font); + assert(font->underline_style); + assert(*font->underline_style == ss::underline_t::dotted); + assert(font->underline_width); + assert(*font->underline_width == ss::underline_width_t::bold); + assert(!font->underline_color); // same as the font color + + xfid = sh->get_cell_format(6, 0); // A7 + xf = styles.get_cell_format(xfid); + assert(xf); + + font = styles.get_font(xf->font); + assert(font); + assert(font->underline_style); + assert(*font->underline_style == ss::underline_t::dash); + assert(font->underline_width); + assert(*font->underline_width == ss::underline_width_t::automatic); + assert(font->underline_color); + assert(*font->underline_color == ss::color_t(0x5E, 0xB9, 0x1E)); + + xfid = sh->get_cell_format(7, 0); // A8 + xf = styles.get_cell_format(xfid); + assert(xf); + + font = styles.get_font(xf->font); + assert(font); + assert(font->underline_style); + assert(*font->underline_style == ss::underline_t::long_dash); + assert(font->underline_width); + assert(*font->underline_width == ss::underline_width_t::automatic); + assert(!font->underline_color); // same as the font color + + xfid = sh->get_cell_format(8, 0); // A9 + xf = styles.get_cell_format(xfid); + assert(xf); + + font = styles.get_font(xf->font); + assert(font); + assert(font->underline_style); + assert(*font->underline_style == ss::underline_t::dot_dash); + assert(font->underline_width); + assert(*font->underline_width == ss::underline_width_t::automatic); + assert(!font->underline_color); // same as the font color + + xfid = sh->get_cell_format(9, 0); // A10 + xf = styles.get_cell_format(xfid); + assert(xf); + + font = styles.get_font(xf->font); + assert(font); + assert(font->underline_style); + assert(*font->underline_style == ss::underline_t::dot_dot_dash); + assert(font->underline_width); + assert(*font->underline_width == ss::underline_width_t::automatic); + assert(!font->underline_color); // same as the font color + + xfid = sh->get_cell_format(10, 0); // A11 + xf = styles.get_cell_format(xfid); + assert(xf); + + font = styles.get_font(xf->font); + assert(font); + assert(font->underline_style); + assert(*font->underline_style == ss::underline_t::wave); + assert(font->underline_width); + assert(*font->underline_width == ss::underline_width_t::automatic); + assert(!font->underline_color); // same as the font color + + xfid = sh->get_cell_format(11, 0); // A12 + xf = styles.get_cell_format(xfid); + assert(xf); + + font = styles.get_font(xf->font); + assert(font); + assert(font->underline_style); + assert(*font->underline_style == ss::underline_t::wave); + assert(font->underline_width); + assert(*font->underline_width == ss::underline_width_t::automatic); + assert(font->underline_color); + assert(*font->underline_color == ss::color_t(0xFF, 0x00, 0x00)); + + xfid = sh->get_cell_format(12, 0); // A13 + xf = styles.get_cell_format(xfid); + assert(xf); + + font = styles.get_font(xf->font); + assert(font); + assert(font->underline_style); + assert(*font->underline_style == ss::underline_t::wave); + assert(font->underline_type); + assert(*font->underline_type == ss::underline_type_t::double_type); + assert(font->underline_width); + assert(*font->underline_width == ss::underline_width_t::automatic); + assert(!font->underline_color); // same as the font color + assert(font->underline_mode); + assert(*font->underline_mode == ss::underline_mode_t::skip_white_space); +} + +} // anonymous namespace + +int main() +{ + test_ods_detection(); + test_ods_create_filter(); + test_ods_import_cell_values(); + test_ods_import_column_widths_row_heights(); + test_ods_import_formatted_text(); + test_ods_import_number_formats(); + test_ods_import_cell_properties(); + test_ods_import_styles_direct_format(); + test_ods_import_styles_column_styles(); + test_ods_import_styles_asian_complex(); + test_ods_import_styles_text_underlines(); + + return EXIT_SUCCESS; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |