summaryrefslogtreecommitdiffstats
path: root/sc/qa/unit/subsequent_export_test.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/qa/unit/subsequent_export_test.cxx')
-rw-r--r--sc/qa/unit/subsequent_export_test.cxx2312
1 files changed, 2312 insertions, 0 deletions
diff --git a/sc/qa/unit/subsequent_export_test.cxx b/sc/qa/unit/subsequent_export_test.cxx
new file mode 100644
index 0000000000..30600191d5
--- /dev/null
+++ b/sc/qa/unit/subsequent_export_test.cxx
@@ -0,0 +1,2312 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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 <officecfg/Office/Common.hxx>
+#include <config_fonts.h>
+
+#include "helper/debughelper.hxx"
+
+#include "helper/qahelper.hxx"
+#include "helper/shared_test_impl.hxx"
+
+#include <userdat.hxx>
+#include <docpool.hxx>
+#include <cellvalue.hxx>
+#include <scitems.hxx>
+#include <attrib.hxx>
+#include <stlpool.hxx>
+#include <editutil.hxx>
+#include <scopetools.hxx>
+#include <postit.hxx>
+#include <validat.hxx>
+
+#include <svx/svdpage.hxx>
+#include <tabprotection.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/section.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/borderline.hxx>
+#include <editeng/escapementitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/colritem.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+class ScExportTest : public ScModelTestBase
+{
+protected:
+ void testExcelCellBorders(const OUString& sFormatType);
+
+public:
+ ScExportTest()
+ : ScModelTestBase("sc/qa/unit/data")
+ {
+ }
+};
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testExport)
+{
+ createScDoc();
+
+ ScDocument* pDoc = getScDoc();
+
+ pDoc->SetValue(0, 0, 0, 1.0);
+
+ saveAndReload("calc8");
+
+ pDoc = getScDoc();
+ double aVal = pDoc->GetValue(0, 0, 0);
+ ASSERT_DOUBLES_EQUAL(1.0, aVal);
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testDefaultFontHeight)
+{
+ createScDoc();
+
+ ScDocument* pDoc = getScDoc();
+ ScDocumentPool* pPool = pDoc->GetPool();
+ pPool->SetPoolDefaultItem(SvxFontHeightItem(400, 100, ATTR_FONT_HEIGHT));
+ pPool->SetPoolDefaultItem(SvxFontHeightItem(400, 100, ATTR_CJK_FONT_HEIGHT));
+ pPool->SetPoolDefaultItem(SvxFontHeightItem(400, 100, ATTR_CTL_FONT_HEIGHT));
+
+ saveAndReload("calc8");
+
+ pDoc = getScDoc();
+ pPool = pDoc->GetPool();
+ const SvxFontHeightItem& rItem = pPool->GetDefaultItem(ATTR_FONT_HEIGHT);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(400), rItem.GetHeight());
+ const SvxFontHeightItem& rCJKItem = pPool->GetDefaultItem(ATTR_CJK_FONT_HEIGHT);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(400), rCJKItem.GetHeight());
+ const SvxFontHeightItem& rCTLItem = pPool->GetDefaultItem(ATTR_CTL_FONT_HEIGHT);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(400), rCTLItem.GetHeight());
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testTdf139167)
+{
+ createScDoc("xlsx/tdf139167.xlsx");
+
+ save("Calc Office Open XML");
+ xmlDocUniquePtr pDoc = parseExport("xl/styles.xml");
+ CPPUNIT_ASSERT(pDoc);
+
+ assertXPath(pDoc, "/x:styleSheet/x:cellStyles"_ostr, "count"_ostr, "6");
+ assertXPath(pDoc, "/x:styleSheet/x:dxfs/x:dxf/x:fill/x:patternFill/x:bgColor"_ostr, "rgb"_ostr,
+ "FFFFFF00");
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testFontColorWithMultipleAttributesDefined)
+{
+ // Related: TDF #113271
+ // Test font color where "rgb" and "theme" attribute is defined and
+ // is imported and exported correctly. Theme should have priority,
+ // so LO is fine to ignore "rgb" at export.
+
+ createScDoc("xlsx/tdf113271.xlsx");
+
+ save("Calc Office Open XML");
+ xmlDocUniquePtr pDoc = parseExport("xl/styles.xml");
+ CPPUNIT_ASSERT(pDoc);
+
+ assertXPath(pDoc, "/x:styleSheet/x:fonts"_ostr, "count"_ostr, "6");
+
+ // Expect "theme" attribute to be set correctly
+ assertXPath(pDoc, "/x:styleSheet/x:fonts/x:font[1]/x:color"_ostr, "theme"_ostr, "1");
+ // We don't export "rgb" attribute
+ assertXPathNoAttribute(pDoc, "/x:styleSheet/x:fonts/x:font[1]/x:color"_ostr, "rgb"_ostr);
+ // Just making sure the checked font is the correct one
+ assertXPath(pDoc, "/x:styleSheet/x:fonts/x:font[1]/x:name"_ostr, "val"_ostr, "Calibri");
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testTdf139394)
+{
+ createScDoc("xlsx/tdf139394.xlsx");
+
+ save("Calc Office Open XML");
+ xmlDocUniquePtr pDoc = parseExport("xl/worksheets/sheet1.xml");
+ CPPUNIT_ASSERT(pDoc);
+
+ assertXPathContent(
+ pDoc,
+ "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[1]/"
+ "x14:cfRule/xm:f"_ostr,
+ "LEFT(A1,LEN(\"+\"))=\"+\"");
+ assertXPathContent(
+ pDoc,
+ "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[2]/"
+ "x14:cfRule/xm:f"_ostr,
+ "RIGHT(A2,LEN(\"-\"))=\"-\"");
+ assertXPathContent(
+ pDoc,
+ "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[3]/"
+ "x14:cfRule/xm:f"_ostr,
+ "LEFT(A3,LEN($B$3))=$B$3");
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testExtCondFormatXLSX)
+{
+ createScDoc("xlsx/tdf139021.xlsx");
+
+ save("Calc Office Open XML");
+ xmlDocUniquePtr pDoc = parseExport("xl/worksheets/sheet1.xml");
+ CPPUNIT_ASSERT(pDoc);
+
+ assertXPath(
+ pDoc,
+ "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[1]/"
+ "x14:cfRule"_ostr,
+ "type"_ostr, "containsText");
+ assertXPathContent(
+ pDoc,
+ "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[1]/"
+ "x14:cfRule/xm:f[1]"_ostr,
+ "NOT(ISERROR(SEARCH($B$1,A1)))");
+ assertXPathContent(
+ pDoc,
+ "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[1]/"
+ "x14:cfRule/xm:f[2]"_ostr,
+ "$B$1");
+ assertXPath(
+ pDoc,
+ "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[2]/"
+ "x14:cfRule"_ostr,
+ "type"_ostr, "notContainsText");
+ assertXPathContent(
+ pDoc,
+ "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[2]/"
+ "x14:cfRule/xm:f[1]"_ostr,
+ "ISERROR(SEARCH($B$2,A2))");
+ assertXPathContent(
+ pDoc,
+ "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[2]/"
+ "x14:cfRule/xm:f[2]"_ostr,
+ "$B$2");
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testTdf90104)
+{
+ createScDoc("xlsx/tdf90104.xlsx");
+
+ save("Calc Office Open XML");
+
+ xmlDocUniquePtr pDoc = parseExport("xl/worksheets/sheet1.xml");
+ CPPUNIT_ASSERT(pDoc);
+
+ assertXPathContent(pDoc,
+ "/x:worksheet/x:dataValidations/x:dataValidation/mc:AlternateContent"
+ "/mc:Choice/x12ac:list"_ostr,
+ "1,\"2,3\",4,\"5,6\"");
+ assertXPathContent(pDoc,
+ "/x:worksheet/x:dataValidations/x:dataValidation/mc:AlternateContent"
+ "/mc:Fallback/x:formula1"_ostr,
+ "\"1,2,3,4,5,6\"");
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testTdf111876)
+{
+ // Document with relative path hyperlink
+
+ createScDoc("xlsx/tdf111876.xlsx");
+
+ save("Calc Office Open XML");
+ xmlDocUniquePtr pDoc = parseExport("xl/worksheets/_rels/sheet1.xml.rels");
+ CPPUNIT_ASSERT(pDoc);
+ OUString sTarget = getXPath(pDoc, "/rels:Relationships/rels:Relationship"_ostr, "Target"_ostr);
+
+ // Document is saved to the temporary directory, relative path should be different than original one
+ CPPUNIT_ASSERT(sTarget != "../xls/bug-fixes.xls");
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testPasswordExport)
+{
+ std::vector<OUString> aFilterNames{ "calc8", "MS Excel 97", "Calc Office Open XML" };
+
+ for (size_t i = 0; i < aFilterNames.size(); ++i)
+ {
+ createScDoc();
+
+ ScDocument* pDoc = getScDoc();
+
+ pDoc->SetValue(0, 0, 0, 1.0);
+
+ saveAndReload(aFilterNames[i], /*pPassword*/ "test");
+
+ pDoc = getScDoc();
+ double aVal = pDoc->GetValue(0, 0, 0);
+ ASSERT_DOUBLES_EQUAL(1.0, aVal);
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testTdf134332)
+{
+ createScDoc("ods/tdf134332.ods");
+
+ ScDocument* pDoc = getScDoc();
+
+ ASSERT_DOUBLES_EQUAL(190.0, pDoc->GetValue(ScAddress(0, 0, 0)));
+
+ ASSERT_DOUBLES_EQUAL(238.0, pDoc->GetValue(ScAddress(0, 10144, 0)));
+
+ saveAndReload("calc8", /*pPassword*/ "test");
+
+ // Without the fixes in place, it would have failed here
+ pDoc = getScDoc();
+ ASSERT_DOUBLES_EQUAL(190.0, pDoc->GetValue(ScAddress(0, 0, 0)));
+
+ ASSERT_DOUBLES_EQUAL(238.0, pDoc->GetValue(ScAddress(0, 10144, 0)));
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testConditionalFormatExportODS)
+{
+ createScDoc("ods/new_cond_format_test_export.ods");
+
+ saveAndReload("calc8");
+ ScDocument* pDoc = getScDoc();
+ OUString aCSVPath = createFilePath(u"contentCSV/new_cond_format_test_export.csv");
+ testCondFile(aCSVPath, &*pDoc, 0);
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testCondFormatExportCellIs)
+{
+ createScDoc("xlsx/condFormat_cellis.xlsx");
+ saveAndReload("Calc Office Open XML");
+
+ ScDocument* pDoc = getScDoc();
+ CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetCondFormList(0)->size());
+
+ ScConditionalFormat* pFormat = pDoc->GetCondFormat(0, 0, 0);
+ CPPUNIT_ASSERT(pFormat);
+
+ const ScFormatEntry* pEntry = pFormat->GetEntry(0);
+ CPPUNIT_ASSERT(pEntry);
+ CPPUNIT_ASSERT_EQUAL(ScFormatEntry::Type::ExtCondition, pEntry->GetType());
+
+ const ScCondFormatEntry* pCondition = static_cast<const ScCondFormatEntry*>(pEntry);
+ CPPUNIT_ASSERT_EQUAL(ScConditionMode::Equal, pCondition->GetOperation());
+
+ OUString aStr = pCondition->GetExpression(ScAddress(0, 0, 0), 0);
+ CPPUNIT_ASSERT_EQUAL(OUString("$Sheet2.$A$2"), aStr);
+
+ pEntry = pFormat->GetEntry(1);
+ CPPUNIT_ASSERT(pEntry);
+ CPPUNIT_ASSERT_EQUAL(ScFormatEntry::Type::ExtCondition, pEntry->GetType());
+
+ pCondition = static_cast<const ScCondFormatEntry*>(pEntry);
+ CPPUNIT_ASSERT_EQUAL(ScConditionMode::Equal, pCondition->GetOperation());
+
+ aStr = pCondition->GetExpression(ScAddress(0, 0, 0), 0);
+ CPPUNIT_ASSERT_EQUAL(OUString("$Sheet2.$A$1"), aStr);
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testConditionalFormatExportXLSX)
+{
+ createScDoc("xlsx/new_cond_format_test_export.xlsx");
+
+ saveAndReload("Calc Office Open XML");
+ ScDocument* pDoc = getScDoc();
+ {
+ OUString aCSVPath = createFilePath(u"contentCSV/new_cond_format_test_export.csv");
+ testCondFile(aCSVPath, &*pDoc, 0);
+ }
+ {
+ OUString aCSVPath = createFilePath(u"contentCSV/new_cond_format_test_sheet2.csv");
+ testCondFile(aCSVPath, &*pDoc, 1);
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testTdf99856_dataValidationTest)
+{
+ createScDoc("ods/tdf99856_dataValidationTest.ods");
+
+ saveAndReload("Calc Office Open XML");
+
+ ScDocument* pDoc = getScDoc();
+ const ScValidationData* pData = pDoc->GetValidationEntry(2);
+ CPPUNIT_ASSERT(pData);
+
+ // Excel can't open corrupt file if the list is longer than 255 characters
+ std::vector<ScTypedStrData> aList;
+ pData->FillSelectionList(aList, ScAddress(0, 1, 1));
+ CPPUNIT_ASSERT_EQUAL(size_t(18), aList.size());
+ CPPUNIT_ASSERT_EQUAL(OUString("18 Missis"), aList[17].GetString());
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testProtectionKeyODS_UTF16LErtlSHA1)
+{
+ OUString constexpr password(u"1012345678901234567890123456789012345678901234567890"_ustr);
+
+ createScDoc("fods/protection-key1.fods");
+
+ ScDocument* pDoc = getScDoc();
+ ScDocProtection* const pDocProt(pDoc->GetDocProtection());
+ CPPUNIT_ASSERT(pDocProt->verifyPassword(password));
+ const ScTableProtection* const pTabProt(pDoc->GetTabProtection(0));
+ CPPUNIT_ASSERT(pTabProt->verifyPassword(password));
+
+ // we can't assume that the user entered the password; check that we
+ // round-trip the password as-is
+ save("calc8");
+ xmlDocUniquePtr pXmlDoc = parseExport("content.xml");
+ assertXPath(
+ pXmlDoc,
+ "//office:spreadsheet[@table:structure-protected='true' and "
+ "@table:protection-key='vbnhxyBKtPHCA1wB21zG1Oha8ZA=' and "
+ "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr);
+ assertXPath(
+ pXmlDoc,
+ "//table:table[@table:protected='true' and "
+ "@table:protection-key='vbnhxyBKtPHCA1wB21zG1Oha8ZA=' and "
+ "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr);
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testProtectionKeyODS_UTF8SHA1)
+{
+ OUString constexpr password(u"1012345678901234567890123456789012345678901234567890"_ustr);
+
+ createScDoc("fods/protection-key2.fods");
+
+ ScDocument* pDoc = getScDoc();
+ ScDocProtection* const pDocProt(pDoc->GetDocProtection());
+ CPPUNIT_ASSERT(pDocProt->verifyPassword(password));
+ const ScTableProtection* const pTabProt(pDoc->GetTabProtection(0));
+ CPPUNIT_ASSERT(pTabProt->verifyPassword(password));
+
+ // we can't assume that the user entered the password; check that we
+ // round-trip the password as-is
+ save("calc8");
+ xmlDocUniquePtr pXmlDoc = parseExport("content.xml");
+ assertXPath(
+ pXmlDoc,
+ "//office:spreadsheet[@table:structure-protected='true' and "
+ "@table:protection-key='nLHas0RIwepGDaH4c2hpyIUvIS8=' and "
+ "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr);
+ assertXPath(
+ pXmlDoc,
+ "//table:table[@table:protected='true' and "
+ "@table:protection-key='nLHas0RIwepGDaH4c2hpyIUvIS8=' and "
+ "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr);
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testProtectionKeyODS_UTF8SHA256ODF12)
+{
+ OUString constexpr password(u"1012345678901234567890123456789012345678901234567890"_ustr);
+
+ createScDoc("fods/protection-key3.fods");
+
+ ScDocument* pDoc = getScDoc();
+ ScDocProtection* const pDocProt(pDoc->GetDocProtection());
+ CPPUNIT_ASSERT(pDocProt->verifyPassword(password));
+ const ScTableProtection* const pTabProt(pDoc->GetTabProtection(0));
+ CPPUNIT_ASSERT(pTabProt->verifyPassword(password));
+
+ // we can't assume that the user entered the password; check that we
+ // round-trip the password as-is
+ save("calc8");
+ xmlDocUniquePtr pXmlDoc = parseExport("content.xml");
+ assertXPath(
+ pXmlDoc,
+ "//office:spreadsheet[@table:structure-protected='true' and "
+ "@table:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=' and "
+ "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256']"_ostr);
+ assertXPath(
+ pXmlDoc,
+ "//table:table[@table:protected='true' and "
+ "@table:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=' and "
+ "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256']"_ostr);
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testProtectionKeyODS_UTF8SHA256W3C)
+{
+ OUString constexpr password(u"1012345678901234567890123456789012345678901234567890"_ustr);
+
+ createScDoc("fods/protection-key4.fods");
+
+ ScDocument* pDoc = getScDoc();
+ ScDocProtection* const pDocProt(pDoc->GetDocProtection());
+ CPPUNIT_ASSERT(pDocProt->verifyPassword(password));
+ const ScTableProtection* const pTabProt(pDoc->GetTabProtection(0));
+ CPPUNIT_ASSERT(pTabProt->verifyPassword(password));
+
+ // we can't assume that the user entered the password; check that we
+ // round-trip the password as-is
+ save("calc8");
+ xmlDocUniquePtr pXmlDoc = parseExport("content.xml");
+ assertXPath(
+ pXmlDoc,
+ "//office:spreadsheet[@table:structure-protected='true' and "
+ "@table:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=' and "
+ "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256']"_ostr);
+ assertXPath(
+ pXmlDoc,
+ "//table:table[@table:protected='true' and "
+ "@table:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=' and "
+ "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256']"_ostr);
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testProtectionKeyODS_XL_SHA1)
+{
+ OUString constexpr password(u"1012345678901234567890123456789012345678901234567890"_ustr);
+
+ createScDoc("fods/protection-key5.fods");
+
+ ScDocument* pDoc = getScDoc();
+ ScDocProtection* const pDocProt(pDoc->GetDocProtection());
+ CPPUNIT_ASSERT(pDocProt->verifyPassword(password));
+ const ScTableProtection* const pTabProt(pDoc->GetTabProtection(0));
+ CPPUNIT_ASSERT(pTabProt->verifyPassword(password));
+
+ // we can't assume that the user entered the password; check that we
+ // round-trip the password as-is
+ save("calc8");
+ xmlDocUniquePtr pXmlDoc = parseExport("content.xml");
+ assertXPath(
+ pXmlDoc,
+ "//office:spreadsheet[@table:structure-protected='true' and "
+ "@table:protection-key='OX3WkEe79fv1PE+FUmfOLdwVoqI=' and "
+ "@table:protection-key-digest-algorithm='http://docs.oasis-open.org/office/ns/table/"
+ "legacy-hash-excel' and "
+ "@loext:protection-key-digest-algorithm-2='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr);
+ assertXPath(
+ pXmlDoc,
+ "//table:table[@table:protected='true' and "
+ "@table:protection-key='OX3WkEe79fv1PE+FUmfOLdwVoqI=' and "
+ "@table:protection-key-digest-algorithm='http://docs.oasis-open.org/office/ns/table/"
+ "legacy-hash-excel' and "
+ "@loext:protection-key-digest-algorithm-2='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr);
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testColorScaleExportODS)
+{
+ createScDoc("ods/colorscale.ods");
+
+ saveAndReload("calc8");
+
+ ScDocument* pDoc = getScDoc();
+
+ testColorScale2Entry_Impl(*pDoc);
+ testColorScale3Entry_Impl(*pDoc);
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testColorScaleExportXLSX)
+{
+ createScDoc("xlsx/colorscale.xlsx");
+
+ saveAndReload("Calc Office Open XML");
+
+ ScDocument* pDoc = getScDoc();
+
+ testColorScale2Entry_Impl(*pDoc);
+ testColorScale3Entry_Impl(*pDoc);
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testDataBarExportODS)
+{
+ createScDoc("ods/databar.ods");
+
+ saveAndReload("calc8");
+
+ ScDocument* pDoc = getScDoc();
+
+ testDataBar_Impl(*pDoc);
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testFormatExportODS)
+{
+ createScDoc("ods/formats.ods");
+
+ saveAndReload("calc8");
+
+ ScDocument* pDoc = getScDoc();
+
+ testFormats(pDoc, u"calc8");
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testCommentExportXLSX)
+{
+ //tdf#104729 FILESAVE OpenOffice do not save author of the comment during export to .xlsx
+ createScDoc("ods/comment.ods");
+
+ save("Calc Office Open XML");
+ xmlDocUniquePtr pComments = parseExport("xl/comments1.xml");
+ CPPUNIT_ASSERT(pComments);
+
+ assertXPathContent(pComments, "/x:comments/x:authors/x:author[1]"_ostr, "BAKO");
+ assertXPath(pComments, "/x:comments/x:authors/x:author"_ostr, 1);
+
+ assertXPathContent(pComments, "/x:comments/x:commentList/x:comment/x:text/x:r/x:t"_ostr,
+ "Komentarz");
+
+ xmlDocUniquePtr pVmlDrawing = parseExport("xl/drawings/vmlDrawing1.vml");
+ CPPUNIT_ASSERT(pVmlDrawing);
+
+ //assertXPath(pVmlDrawing, "/xml/v:shapetype", "coordsize", "21600,21600");
+ assertXPath(pVmlDrawing, "/xml/v:shapetype"_ostr, "spt"_ostr, "202");
+ assertXPath(pVmlDrawing, "/xml/v:shapetype/v:stroke"_ostr, "joinstyle"_ostr, "miter");
+ const OUString sShapeTypeId = "#" + getXPath(pVmlDrawing, "/xml/v:shapetype"_ostr, "id"_ostr);
+
+ assertXPath(pVmlDrawing, "/xml/v:shape"_ostr, "type"_ostr, sShapeTypeId);
+ assertXPath(pVmlDrawing, "/xml/v:shape/v:shadow"_ostr, "color"_ostr, "black");
+ assertXPath(pVmlDrawing, "/xml/v:shape/v:shadow"_ostr, "obscured"_ostr, "t");
+
+ //tdf#117274 fix MSO interoperability with the secret VML shape type id
+ assertXPath(pVmlDrawing, "/xml/v:shapetype"_ostr, "id"_ostr, "_x0000_t202");
+ assertXPath(pVmlDrawing, "/xml/v:shape"_ostr, "type"_ostr, "#_x0000_t202");
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testCommentExportXLSX_2_XLSX)
+{
+ //tdf#117287 FILESAVE XLSX: Comments always disappear after opening the exported XLSX file with Excel
+ createScDoc("xlsx/tdf117287_comment.xlsx");
+
+ ScDocument* pDoc = getScDoc();
+ ScAddress aPosC9(2, 8, 0);
+ ScPostIt* pNote = pDoc->GetNote(aPosC9);
+
+ CPPUNIT_ASSERT(pNote);
+ CPPUNIT_ASSERT(!pNote->IsCaptionShown());
+
+ pNote->ShowCaption(aPosC9, true);
+
+ save("Calc Office Open XML");
+ xmlDocUniquePtr pComments = parseExport("xl/comments1.xml");
+ CPPUNIT_ASSERT(pComments);
+
+ assertXPathContent(pComments, "/x:comments/x:commentList/x:comment/x:text/x:r/x:t"_ostr,
+ "visible comment");
+
+ xmlDocUniquePtr pVmlDrawing = parseExport("xl/drawings/vmlDrawing1.vml");
+ CPPUNIT_ASSERT(pVmlDrawing);
+
+ assertXPath(pVmlDrawing, "/xml/v:shape/x:ClientData/x:Visible"_ostr, 0);
+}
+
+#if HAVE_MORE_FONTS
+CPPUNIT_TEST_FIXTURE(ScExportTest, testCustomColumnWidthExportXLSX)
+{
+ //tdf#100946 FILESAVE Excel on macOS ignored column widths in XLSX last saved by LO
+ createScDoc("ods/custom_column_width.ods");
+
+ save("Calc Office Open XML");
+ xmlDocUniquePtr pSheet = parseExport("xl/worksheets/sheet1.xml");
+ CPPUNIT_ASSERT(pSheet);
+
+ // tdf#124741: check that we export default width, otherwise the skipped columns would have
+ // wrong width. Previously defaultColWidth attribute was missing
+ double nDefWidth
+ = getXPath(pSheet, "/x:worksheet/x:sheetFormatPr"_ostr, "defaultColWidth"_ostr).toDouble();
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(11.53515625, nDefWidth, 0.01);
+
+ // First column, has everything default (width in Calc: 1280), skipped
+
+ // Second column, has custom width (width in Calc: 1225)
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "hidden"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "outlineLevel"_ostr, "0");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "customWidth"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "min"_ostr, "2");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "max"_ostr, "2");
+
+ // Third column, has everything default (width in Calc: 1280), skipped
+
+ // Fourth column has custom width. Columns from 4 to 7 are hidden
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "outlineLevel"_ostr, "0");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "customWidth"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "min"_ostr, "4");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "max"_ostr, "4");
+
+ // 5th column has custom width. Columns from 4 to 7 are hidden
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "outlineLevel"_ostr, "0");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "customWidth"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "min"_ostr, "5");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "max"_ostr, "5");
+
+ // 6th and 7th columns have default width and they are hidden
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "outlineLevel"_ostr, "0");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "customWidth"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "min"_ostr, "6");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "max"_ostr, "7");
+
+ // 8th column has everything default - skipped
+
+ // 9th column has custom width
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "hidden"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "outlineLevel"_ostr, "0");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "customWidth"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "min"_ostr, "9");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "max"_ostr, "9");
+
+ // We expected that exactly 5 unique Nodes will be produced
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col"_ostr, 5);
+
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "hidden"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "outlineLevel"_ostr, "0");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "customFormat"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "customHeight"_ostr, "false");
+}
+#endif
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testXfDefaultValuesXLSX)
+{
+ //tdf#70565 FORMATTING: User Defined Custom Formatting is not applied during importing XLSX documents
+ createScDoc("xlsx/xf_default_values.xlsx");
+
+ save("Calc Office Open XML");
+ xmlDocUniquePtr pSheet = parseExport("xl/styles.xml");
+ CPPUNIT_ASSERT(pSheet);
+
+ // cellStyleXfs don't need xfId, so we need to make sure it is not saved
+ assertXPathNoAttribute(pSheet, "/x:styleSheet/x:cellStyleXfs/x:xf[1]"_ostr, "xfId"_ostr);
+
+ // Because numFmtId fontId fillId borderId xfId are not existing during import
+ // it should be created during export, with values set to "0"
+ assertXPath(pSheet, "/x:styleSheet/x:cellXfs/x:xf[1]"_ostr, "xfId"_ostr, "0");
+ assertXPath(pSheet, "/x:styleSheet/x:cellXfs/x:xf[2]"_ostr, "xfId"_ostr, "0");
+ assertXPath(pSheet, "/x:styleSheet/x:cellXfs/x:xf[3]"_ostr, "xfId"_ostr, "0");
+ assertXPath(pSheet, "/x:styleSheet/x:cellXfs/x:xf[4]"_ostr, "xfId"_ostr, "0");
+
+ // We expected that exactly 15 cellXfs:xf Nodes will be produced
+ assertXPath(pSheet, "/x:styleSheet/x:cellXfs/x:xf"_ostr, 14);
+}
+
+static auto verifySpreadsheet13(char const* const pTestName, ScDocument& rDoc) -> void
+{
+ // OFFICE-2173 table:tab-color
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName, Color(0xff3838), rDoc.GetTabBgColor(0));
+ // OFFICE-3857 table:scale-to-X/table:scale-to-Y
+ OUString styleName = rDoc.GetPageStyle(0);
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find(styleName, SfxStyleFamily::Page);
+ CPPUNIT_ASSERT_MESSAGE(pTestName, pStyleSheet);
+
+ SfxItemSet const& rSet = pStyleSheet->GetItemSet();
+ ScPageScaleToItem const& rItem(rSet.Get(ATTR_PAGE_SCALETO));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName, sal_uInt16(2), rItem.GetWidth());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName, sal_uInt16(3), rItem.GetHeight());
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testODF13)
+{
+ // import
+ createScDoc("ods/spreadsheet13e.ods");
+ ScDocument* pDoc = getScDoc();
+
+ // check model
+ verifySpreadsheet13("import", *pDoc);
+
+ Resetter _([]() {
+ std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch);
+ return pBatch->commit();
+ });
+
+ {
+ // export ODF 1.3
+ std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Save::ODF::DefaultVersion::set(10, pBatch);
+ pBatch->commit();
+
+ // FIXME: Error: unexpected attribute "loext:scale-to-X"
+ skipValidation();
+
+ saveAndReload("calc8");
+ pDoc = getScDoc();
+
+ // check XML
+ xmlDocUniquePtr pContentXml = parseExport("content.xml");
+ assertXPath(pContentXml, "/office:document-content/office:automatic-styles/style:style/"
+ "style:table-properties[@table:tab-color='#ff3838']"_ostr);
+ xmlDocUniquePtr pStylesXml = parseExport("styles.xml");
+ assertXPath(pStylesXml, "/office:document-styles/office:automatic-styles/style:page-layout/"
+ "style:page-layout-properties[@style:scale-to-X='2']"_ostr);
+ assertXPath(pStylesXml, "/office:document-styles/office:automatic-styles/style:page-layout/"
+ "style:page-layout-properties[@style:scale-to-Y='3']"_ostr);
+
+ // check model
+ verifySpreadsheet13("1.3 reload", *pDoc);
+ }
+ {
+ // export ODF 1.2 Extended
+ std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Save::ODF::DefaultVersion::set(9, pBatch);
+ pBatch->commit();
+
+ saveAndReload("calc8");
+ pDoc = getScDoc();
+
+ // check XML
+ xmlDocUniquePtr pContentXml = parseExport("content.xml");
+ assertXPath(pContentXml, "/office:document-content/office:automatic-styles/style:style/"
+ "style:table-properties[@tableooo:tab-color='#ff3838']"_ostr);
+ xmlDocUniquePtr pStylesXml = parseExport("styles.xml");
+ assertXPath(pStylesXml, "/office:document-styles/office:automatic-styles/style:page-layout/"
+ "style:page-layout-properties[@loext:scale-to-X='2']"_ostr);
+ assertXPath(pStylesXml, "/office:document-styles/office:automatic-styles/style:page-layout/"
+ "style:page-layout-properties[@loext:scale-to-Y='3']"_ostr);
+
+ // check model
+ verifySpreadsheet13("1.2 Extended reload", *pDoc);
+ }
+ {
+ // export ODF 1.2
+ std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Save::ODF::DefaultVersion::set(4, pBatch);
+ pBatch->commit();
+
+ save("calc8");
+
+ // check XML
+ xmlDocUniquePtr pContentXml = parseExport("content.xml");
+ assertXPathNoAttribute(
+ pContentXml,
+ "/office:document-content/office:automatic-styles/style:style/style:table-properties"_ostr,
+ "tab-color"_ostr);
+ xmlDocUniquePtr pStylesXml = parseExport("styles.xml");
+ assertXPathNoAttribute(pStylesXml,
+ "/office:document-styles/office:automatic-styles/"
+ "style:page-layout[1]/style:page-layout-properties"_ostr,
+ "scale-to-X"_ostr);
+ assertXPathNoAttribute(pStylesXml,
+ "/office:document-styles/office:automatic-styles/"
+ "style:page-layout[1]/style:page-layout-properties"_ostr,
+ "scale-to-Y"_ostr);
+
+ // don't reload - no point
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testColumnWidthResaveXLSX)
+{
+ // tdf#91475 FILESAVE: Column width is not preserved in XLSX / after round trip.
+ // Test if after resave .xlsx file, columns width is identical with previous one
+ createScDoc("xlsx/different-column-width-excel2010.xlsx");
+
+ save("Calc Office Open XML");
+ xmlDocUniquePtr pSheet = parseExport("xl/worksheets/sheet1.xml");
+ CPPUNIT_ASSERT(pSheet);
+
+ // In original Excel document the width is "24"
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "width"_ostr, "24");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "customWidth"_ostr, "true");
+
+ // In original Excel document the width is "12"
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "width"_ostr, "12");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "customWidth"_ostr, "true");
+
+ // In original Excel document the width is "6"
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "width"_ostr, "6");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "customWidth"_ostr, "true");
+
+ // In original Excel document the width is "1"
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "width"_ostr, "1");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "customWidth"_ostr, "true");
+
+ // In original Excel document the width is "250"
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "width"_ostr, "250");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "customWidth"_ostr, "true");
+
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col"_ostr, 5);
+}
+
+#if HAVE_MORE_FONTS
+CPPUNIT_TEST_FIXTURE(ScExportTest, testColumnWidthExportFromODStoXLSX)
+{
+ // tdf#91475 FILESAVE: Column width is not preserved in XLSX / after round trip.
+ // Test if after export .ods to .xlsx format, displayed columns width
+ // is identical with previous (.ods) one
+
+ createScDoc("ods/different-column-width.ods");
+
+ ScDocument* pDoc = getScDoc();
+
+ // Col 1, Tab 0 (Column width 2.00 in)
+ sal_uInt16 nExpectedColumn0Width
+ = pDoc->GetColWidth(static_cast<SCCOL>(0), static_cast<SCTAB>(0), false);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(2880), nExpectedColumn0Width);
+
+ // Col 2, Tab 0 (Column width 1.00 in)
+ sal_uInt16 nExpectedColumn1Width
+ = pDoc->GetColWidth(static_cast<SCCOL>(1), static_cast<SCTAB>(0), false);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1440), nExpectedColumn1Width);
+
+ // Col 3, Tab 0 (Column width 0.50 in)
+ sal_uInt16 nExpectedColumn2Width
+ = pDoc->GetColWidth(static_cast<SCCOL>(2), static_cast<SCTAB>(0), false);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(720), nExpectedColumn2Width);
+
+ // Col 4, Tab 0 (Column width 0.25 in)
+ sal_uInt16 nExpectedColumn3Width
+ = pDoc->GetColWidth(static_cast<SCCOL>(3), static_cast<SCTAB>(0), false);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(360), nExpectedColumn3Width);
+
+ // Col 5, Tab 0 (Column width 13.57 in)
+ sal_uInt16 nExpectedColumn4Width
+ = pDoc->GetColWidth(static_cast<SCCOL>(4), static_cast<SCTAB>(0), false);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(19539), nExpectedColumn4Width);
+
+ // Export to .xlsx and compare column width with the .ods
+ // We expect that column width from .ods will be exactly the same as imported from .xlsx
+
+ saveAndReload("Calc Office Open XML");
+
+ pDoc = getScDoc();
+
+ // Col 1, Tab 0
+ sal_uInt16 nCalcWidth;
+ nCalcWidth = pDoc->GetColWidth(static_cast<SCCOL>(0), static_cast<SCTAB>(0), false);
+ CPPUNIT_ASSERT_EQUAL(nExpectedColumn0Width, nCalcWidth);
+
+ // Col 2, Tab 0
+ nCalcWidth = pDoc->GetColWidth(static_cast<SCCOL>(1), static_cast<SCTAB>(0), false);
+ CPPUNIT_ASSERT_EQUAL(nExpectedColumn1Width, nCalcWidth);
+
+ // Col 3, Tab 0
+ nCalcWidth = pDoc->GetColWidth(static_cast<SCCOL>(2), static_cast<SCTAB>(0), false);
+ CPPUNIT_ASSERT_EQUAL(nExpectedColumn2Width, nCalcWidth);
+
+ // Col 4, Tab 0
+ nCalcWidth = pDoc->GetColWidth(static_cast<SCCOL>(3), static_cast<SCTAB>(0), false);
+ CPPUNIT_ASSERT_EQUAL(nExpectedColumn3Width, nCalcWidth);
+
+ // Col 5, Tab 0
+ nCalcWidth = pDoc->GetColWidth(static_cast<SCCOL>(4), static_cast<SCTAB>(0), false);
+ CPPUNIT_ASSERT_EQUAL(nExpectedColumn4Width, nCalcWidth);
+}
+#endif
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testOutlineExportXLSX)
+{
+ //tdf#100347 FILESAVE FILEOPEN after exporting to .xlsx format grouping are lost
+ //tdf#51524 FILESAVE .xlsx and.xls looses width information for hidden/collapsed grouped columns
+ createScDoc("ods/outline.ods");
+
+ save("Calc Office Open XML");
+ xmlDocUniquePtr pSheet = parseExport("xl/worksheets/sheet1.xml");
+ CPPUNIT_ASSERT(pSheet);
+
+ // Maximum Outline Row is 4 for this document
+ assertXPath(pSheet, "/x:worksheet/x:sheetFormatPr"_ostr, "outlineLevelRow"_ostr, "4");
+ // Maximum Outline Column is 4 for this document
+ assertXPath(pSheet, "/x:worksheet/x:sheetFormatPr"_ostr, "outlineLevelCol"_ostr, "4");
+
+ // First XML node, creates two columns (from min=1 to max=2)
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "hidden"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "outlineLevel"_ostr, "1");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "min"_ostr, "1");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "max"_ostr, "2");
+
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "outlineLevel"_ostr, "2");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "min"_ostr, "3");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "max"_ostr, "3");
+
+ // Column 4 has custom width and it is hidden. We need to make sure that it is created
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "outlineLevel"_ostr, "2");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "min"_ostr, "4");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "max"_ostr, "4");
+
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "outlineLevel"_ostr, "3");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "min"_ostr, "5");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "max"_ostr, "6");
+
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "outlineLevel"_ostr, "4");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "min"_ostr, "7");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "max"_ostr, "7");
+
+ // Column 8 has custom width and it is hidden. We need to make sure that it is created
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[6]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[6]"_ostr, "outlineLevel"_ostr, "4");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[6]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[6]"_ostr, "min"_ostr, "8");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[6]"_ostr, "max"_ostr, "8");
+
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[7]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[7]"_ostr, "outlineLevel"_ostr, "4");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[7]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[7]"_ostr, "min"_ostr, "9");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[7]"_ostr, "max"_ostr, "19");
+
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[8]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[8]"_ostr, "outlineLevel"_ostr, "3");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[8]"_ostr, "collapsed"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[8]"_ostr, "min"_ostr, "20");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[8]"_ostr, "max"_ostr, "20");
+
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[9]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[9]"_ostr, "outlineLevel"_ostr, "3");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[9]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[9]"_ostr, "min"_ostr, "21");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[9]"_ostr, "max"_ostr, "21");
+
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[10]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[10]"_ostr, "outlineLevel"_ostr, "2");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[10]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[10]"_ostr, "min"_ostr, "22");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[10]"_ostr, "max"_ostr, "23");
+
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[11]"_ostr, "hidden"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[11]"_ostr, "outlineLevel"_ostr, "1");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[11]"_ostr, "collapsed"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[11]"_ostr, "min"_ostr, "24");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[11]"_ostr, "max"_ostr, "24");
+
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[12]"_ostr, "hidden"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[12]"_ostr, "outlineLevel"_ostr, "1");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[12]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[12]"_ostr, "min"_ostr, "25");
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col[12]"_ostr, "max"_ostr, "26");
+
+ // We expected that exactly 12 unique Nodes will be produced
+ assertXPath(pSheet, "/x:worksheet/x:cols/x:col"_ostr, 12);
+
+ // First row is empty and default so it is not written into XML file
+ // so we need to save 29 rows, as it provides information about outLineLevel
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "r"_ostr, "2");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "hidden"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "outlineLevel"_ostr, "1");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[2]"_ostr, "r"_ostr, "3");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[2]"_ostr, "hidden"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[2]"_ostr, "outlineLevel"_ostr, "2");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[2]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[3]"_ostr, "r"_ostr, "4");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[3]"_ostr, "hidden"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[3]"_ostr, "outlineLevel"_ostr, "2");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[3]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[4]"_ostr, "r"_ostr, "5");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[4]"_ostr, "hidden"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[4]"_ostr, "outlineLevel"_ostr, "3");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[4]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[5]"_ostr, "r"_ostr, "6");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[5]"_ostr, "hidden"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[5]"_ostr, "outlineLevel"_ostr, "3");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[5]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[6]"_ostr, "r"_ostr, "7");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[6]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[6]"_ostr, "outlineLevel"_ostr, "4");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[6]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[7]"_ostr, "r"_ostr, "8");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[7]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[7]"_ostr, "outlineLevel"_ostr, "4");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[7]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[8]"_ostr, "r"_ostr, "9");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[8]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[8]"_ostr, "outlineLevel"_ostr, "4");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[8]"_ostr, "collapsed"_ostr, "false");
+ // Next rows are the same as the previous one but it needs to be preserved,
+ // as they contain information about outlineLevel
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[20]"_ostr, "r"_ostr, "21");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[20]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[20]"_ostr, "outlineLevel"_ostr, "4");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[20]"_ostr, "collapsed"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[21]"_ostr, "r"_ostr, "22");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[21]"_ostr, "hidden"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[21]"_ostr, "outlineLevel"_ostr, "3");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[21]"_ostr, "collapsed"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[22]"_ostr, "r"_ostr, "23");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[22]"_ostr, "hidden"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[22]"_ostr, "outlineLevel"_ostr, "3");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[22]"_ostr, "collapsed"_ostr, "false");
+
+ // We expected that exactly 29 Row Nodes will be produced
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row"_ostr, 29);
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testAllRowsHiddenXLSX)
+{
+ createScDoc("xlsx/tdf105840_allRowsHidden.xlsx");
+
+ save("Calc Office Open XML");
+ xmlDocUniquePtr pSheet = parseExport("xl/worksheets/sheet1.xml");
+ CPPUNIT_ASSERT(pSheet);
+ assertXPath(pSheet, "/x:worksheet/x:sheetFormatPr"_ostr, "zeroHeight"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row"_ostr, 0);
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testHiddenEmptyRowsXLSX)
+{
+ //tdf#98106 FILESAVE: Hidden and empty rows became visible when export to .XLSX
+ createScDoc("ods/hidden-empty-rows.ods");
+
+ save("Calc Office Open XML");
+ xmlDocUniquePtr pSheet = parseExport("xl/worksheets/sheet1.xml");
+ CPPUNIT_ASSERT(pSheet);
+
+ assertXPath(pSheet, "/x:worksheet/x:sheetFormatPr"_ostr, "zeroHeight"_ostr, "false");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[2]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[3]"_ostr, "hidden"_ostr, "true");
+ assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[4]"_ostr, "hidden"_ostr, "false");
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testHiddenEmptyColsODS)
+{
+ //tdf#98106 FILESAVE: Hidden and empty rows became visible when export to .XLSX
+ createScDoc("ods/tdf128895_emptyHiddenCols.ods");
+
+ save("calc8");
+ xmlDocUniquePtr pSheet = parseExport("content.xml");
+ CPPUNIT_ASSERT(pSheet);
+ assertXPath(pSheet, "//table:table/table:table-column[2]"_ostr);
+ assertXPath(pSheet, "//table:table/table:table-column[2]"_ostr, "number-columns-repeated"_ostr,
+ "1017");
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testLandscapeOrientationXLSX)
+{
+ //tdf#48767 - Landscape page orientation is not loaded from .xlsx format with MS Excel, after export with Libre Office
+ createScDoc("ods/hidden-empty-rows.ods");
+
+ save("Calc Office Open XML");
+ xmlDocUniquePtr pSheet = parseExport("xl/worksheets/sheet1.xml");
+ CPPUNIT_ASSERT(pSheet);
+
+ // the usePrinterDefaults cannot be saved to allow opening sheets in Landscape mode via MS Excel
+ assertXPathNoAttribute(pSheet, "/x:worksheet/x:pageSetup"_ostr, "usePrinterDefaults"_ostr);
+ assertXPath(pSheet, "/x:worksheet/x:pageSetup"_ostr, "orientation"_ostr, "landscape");
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testDataBarExportXLSX)
+{
+ createScDoc("xlsx/databar.xlsx");
+
+ saveAndReload("Calc Office Open XML");
+
+ ScDocument* pDoc = getScDoc();
+
+ testDataBar_Impl(*pDoc);
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testMiscRowHeightExport)
+{
+ static const TestParam::RowData DfltRowData[] = {
+ { 0, 4, 0, 529, 0, false },
+ { 5, 10, 0, 1058, 0, false },
+ { 17, 20, 0, 1746, 0, false },
+ // check last couple of row in document to ensure
+ // they are 5.29mm ( effective default row xlsx height )
+ { 1048573, 1048575, 0, 529, 0, false },
+ };
+
+ static const TestParam::RowData EmptyRepeatRowData[] = {
+ // rows 0-4, 5-10, 17-20 are all set at various
+ // heights, there is no content in the rows, there
+ // was a bug where only the first row ( of repeated rows )
+ // was set after export
+ { 0, 4, 0, 529, 0, false },
+ { 5, 10, 0, 1058, 0, false },
+ { 17, 20, 0, 1767, 0, false },
+ };
+
+ TestParam aTestValues[] = {
+ // Checks that some distributed ( non-empty ) heights remain set after export (roundtrip)
+ // additionally there is effectively a default row height ( 5.29 mm ). So we test the
+ // unset rows at the end of the document to ensure the effective xlsx default height
+ // is set there too.
+ { u"xlsx/miscrowheights.xlsx", "Calc Office Open XML", SAL_N_ELEMENTS(DfltRowData),
+ DfltRowData },
+ // Checks that some distributed ( non-empty ) heights remain set after export (to xls)
+ { u"xlsx/miscrowheights.xlsx", "MS Excel 97", SAL_N_ELEMENTS(DfltRowData), DfltRowData },
+ // Checks that repreated rows ( of various heights ) remain set after export ( to xlsx )
+ { u"ods/miscemptyrepeatedrowheights.ods", "Calc Office Open XML",
+ SAL_N_ELEMENTS(EmptyRepeatRowData), EmptyRepeatRowData },
+ // Checks that repreated rows ( of various heights ) remain set after export ( to xls )
+ { u"ods/miscemptyrepeatedrowheights.ods", "MS Excel 97", SAL_N_ELEMENTS(EmptyRepeatRowData),
+ EmptyRepeatRowData },
+ };
+ miscRowHeightsTest(aTestValues, SAL_N_ELEMENTS(aTestValues));
+}
+
+namespace
+{
+void setAttribute(ScFieldEditEngine& rEE, sal_Int32 nPara, sal_Int32 nStart, sal_Int32 nEnd,
+ sal_uInt16 nType, Color nColor = COL_BLACK)
+{
+ ESelection aSel;
+ aSel.nStartPara = aSel.nEndPara = nPara;
+ aSel.nStartPos = nStart;
+ aSel.nEndPos = nEnd;
+
+ SfxItemSet aItemSet = rEE.GetEmptyItemSet();
+ switch (nType)
+ {
+ case EE_CHAR_WEIGHT:
+ {
+ SvxWeightItem aWeight(WEIGHT_BOLD, nType);
+ aItemSet.Put(aWeight);
+ rEE.QuickSetAttribs(aItemSet, aSel);
+ }
+ break;
+ case EE_CHAR_ITALIC:
+ {
+ SvxPostureItem aItalic(ITALIC_NORMAL, nType);
+ aItemSet.Put(aItalic);
+ rEE.QuickSetAttribs(aItemSet, aSel);
+ }
+ break;
+ case EE_CHAR_STRIKEOUT:
+ {
+ SvxCrossedOutItem aCrossOut(STRIKEOUT_SINGLE, nType);
+ aItemSet.Put(aCrossOut);
+ rEE.QuickSetAttribs(aItemSet, aSel);
+ }
+ break;
+ case EE_CHAR_OVERLINE:
+ {
+ SvxOverlineItem aItem(LINESTYLE_DOUBLE, nType);
+ aItemSet.Put(aItem);
+ rEE.QuickSetAttribs(aItemSet, aSel);
+ }
+ break;
+ case EE_CHAR_UNDERLINE:
+ {
+ SvxUnderlineItem aItem(LINESTYLE_DOUBLE, nType);
+ aItemSet.Put(aItem);
+ rEE.QuickSetAttribs(aItemSet, aSel);
+ }
+ break;
+ case EE_CHAR_COLOR:
+ {
+ SvxColorItem aItem(nColor, nType);
+ aItemSet.Put(aItem);
+ rEE.QuickSetAttribs(aItemSet, aSel);
+ }
+ break;
+ default:;
+ }
+}
+
+void setFont(ScFieldEditEngine& rEE, sal_Int32 nPara, sal_Int32 nStart, sal_Int32 nEnd,
+ const OUString& rFontName)
+{
+ ESelection aSel;
+ aSel.nStartPara = aSel.nEndPara = nPara;
+ aSel.nStartPos = nStart;
+ aSel.nEndPos = nEnd;
+
+ SfxItemSet aItemSet = rEE.GetEmptyItemSet();
+ SvxFontItem aItem(FAMILY_MODERN, rFontName, "", PITCH_VARIABLE, RTL_TEXTENCODING_UTF8,
+ EE_CHAR_FONTINFO);
+ aItemSet.Put(aItem);
+ rEE.QuickSetAttribs(aItemSet, aSel);
+}
+
+void setEscapement(ScFieldEditEngine& rEE, sal_Int32 nPara, sal_Int32 nStart, sal_Int32 nEnd,
+ short nEsc, sal_uInt8 nRelSize)
+{
+ ESelection aSel;
+ aSel.nStartPara = aSel.nEndPara = nPara;
+ aSel.nStartPos = nStart;
+ aSel.nEndPos = nEnd;
+
+ SfxItemSet aItemSet = rEE.GetEmptyItemSet();
+ SvxEscapementItem aItem(nEsc, nRelSize, EE_CHAR_ESCAPEMENT);
+ aItemSet.Put(aItem);
+ rEE.QuickSetAttribs(aItemSet, aSel);
+}
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testNamedRangeBugfdo62729)
+{
+#if !defined(MACOSX) // FIXME: infinite loop on jenkins' mac
+ createScDoc("ods/fdo62729.ods");
+ ScDocument* pDoc = getScDoc();
+
+ ScRangeName* pNames = pDoc->GetRangeName();
+ //should be just a single named range
+ CPPUNIT_ASSERT_EQUAL(size_t(1), pNames->size());
+ pDoc->DeleteTab(0);
+ //should be still a single named range
+ CPPUNIT_ASSERT_EQUAL(size_t(1), pNames->size());
+ saveAndReload("calc8");
+
+ pDoc = getScDoc();
+
+ pNames = pDoc->GetRangeName();
+ //after reload should still have a named range
+ CPPUNIT_ASSERT_EQUAL(size_t(1), pNames->size());
+#endif
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testBuiltinRangesXLSX)
+{
+ createScDoc("xlsx/built-in_ranges.xlsx");
+
+ save("Calc Office Open XML");
+ xmlDocUniquePtr pDoc = parseExport("xl/workbook.xml");
+ CPPUNIT_ASSERT(pDoc);
+
+ //assert the existing OOXML built-in names are still there
+ assertXPathContent(pDoc,
+ "/x:workbook/x:definedNames/"
+ "x:definedName[@name='_xlnm._FilterDatabase'][@localSheetId='0']"_ostr,
+ "'Sheet1 Test'!$A$1:$A$5");
+ assertXPathContent(pDoc,
+ "/x:workbook/x:definedNames/"
+ "x:definedName[@name='_xlnm._FilterDatabase'][@localSheetId='1']"_ostr,
+ "'Sheet2 Test'!$K$10:$K$14");
+ assertXPathContent(
+ pDoc,
+ "/x:workbook/x:definedNames/x:definedName[@name='_xlnm.Print_Area'][@localSheetId='0']"_ostr,
+ "'Sheet1 Test'!$A$1:$A$5");
+ assertXPathContent(
+ pDoc,
+ "/x:workbook/x:definedNames/x:definedName[@name='_xlnm.Print_Area'][@localSheetId='1']"_ostr,
+ "'Sheet2 Test'!$K$10:$M$18");
+
+ //...and that no extra ones are added (see tdf#112571)
+ assertXPath(pDoc,
+ "/x:workbook/x:definedNames/"
+ "x:definedName[@name='_xlnm._FilterDatabase_0'][@localSheetId='0']"_ostr,
+ 0);
+ assertXPath(pDoc,
+ "/x:workbook/x:definedNames/"
+ "x:definedName[@name='_xlnm._FilterDatabase_0'][@localSheetId='1']"_ostr,
+ 0);
+ assertXPath(
+ pDoc,
+ "/x:workbook/x:definedNames/x:definedName[@name='_xlnm.Print_Area_0'][@localSheetId='0']"_ostr,
+ 0);
+ assertXPath(
+ pDoc,
+ "/x:workbook/x:definedNames/x:definedName[@name='_xlnm.Print_Area_0'][@localSheetId='1']"_ostr,
+ 0);
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testRichTextExportODS)
+{
+ struct
+ {
+ static bool isBold(const editeng::Section& rAttr)
+ {
+ return std::any_of(
+ rAttr.maAttributes.begin(), rAttr.maAttributes.end(), [](const SfxPoolItem* p) {
+ return p->Which() == EE_CHAR_WEIGHT
+ && static_cast<const SvxWeightItem*>(p)->GetWeight() == WEIGHT_BOLD;
+ });
+ }
+
+ static bool isItalic(const editeng::Section& rAttr)
+ {
+ return std::any_of(
+ rAttr.maAttributes.begin(), rAttr.maAttributes.end(), [](const SfxPoolItem* p) {
+ return p->Which() == EE_CHAR_ITALIC
+ && static_cast<const SvxPostureItem*>(p)->GetPosture() == ITALIC_NORMAL;
+ });
+ }
+
+ static bool isStrikeOut(const editeng::Section& rAttr)
+ {
+ return std::any_of(
+ rAttr.maAttributes.begin(), rAttr.maAttributes.end(), [](const SfxPoolItem* p) {
+ return p->Which() == EE_CHAR_STRIKEOUT
+ && static_cast<const SvxCrossedOutItem*>(p)->GetStrikeout()
+ == STRIKEOUT_SINGLE;
+ });
+ }
+
+ static bool isOverline(const editeng::Section& rAttr, FontLineStyle eStyle)
+ {
+ return std::any_of(rAttr.maAttributes.begin(), rAttr.maAttributes.end(),
+ [&eStyle](const SfxPoolItem* p) {
+ return p->Which() == EE_CHAR_OVERLINE
+ && static_cast<const SvxOverlineItem*>(p)->GetLineStyle()
+ == eStyle;
+ });
+ }
+
+ static bool isUnderline(const editeng::Section& rAttr, FontLineStyle eStyle)
+ {
+ return std::any_of(rAttr.maAttributes.begin(), rAttr.maAttributes.end(),
+ [&eStyle](const SfxPoolItem* p) {
+ return p->Which() == EE_CHAR_UNDERLINE
+ && static_cast<const SvxUnderlineItem*>(p)->GetLineStyle()
+ == eStyle;
+ });
+ }
+
+ static bool isFont(const editeng::Section& rAttr, const OUString& rFontName)
+ {
+ return std::any_of(rAttr.maAttributes.begin(), rAttr.maAttributes.end(),
+ [&rFontName](const SfxPoolItem* p) {
+ return p->Which() == EE_CHAR_FONTINFO
+ && static_cast<const SvxFontItem*>(p)->GetFamilyName()
+ == rFontName;
+ });
+ }
+
+ static bool isEscapement(const editeng::Section& rAttr, short nEsc, sal_uInt8 nRelSize)
+ {
+ return std::any_of(rAttr.maAttributes.begin(), rAttr.maAttributes.end(),
+ [&nEsc, &nRelSize](const SfxPoolItem* p) {
+ if (p->Which() != EE_CHAR_ESCAPEMENT)
+ return false;
+ const SvxEscapementItem* pItem
+ = static_cast<const SvxEscapementItem*>(p);
+ return ((pItem->GetEsc() == nEsc)
+ && (pItem->GetProportionalHeight() == nRelSize));
+ });
+ }
+
+ static bool isColor(const editeng::Section& rAttr, Color nColor)
+ {
+ return std::any_of(rAttr.maAttributes.begin(), rAttr.maAttributes.end(),
+ [&nColor](const SfxPoolItem* p) {
+ return p->Which() == EE_CHAR_COLOR
+ && static_cast<const SvxColorItem*>(p)->GetValue()
+ == nColor;
+ });
+ }
+
+ bool checkB2(const EditTextObject* pText) const
+ {
+ if (!pText)
+ return false;
+
+ if (pText->GetParagraphCount() != 1)
+ return false;
+
+ if (pText->GetText(0) != "Bold and Italic")
+ return false;
+
+ std::vector<editeng::Section> aSecAttrs;
+ pText->GetAllSections(aSecAttrs);
+ if (aSecAttrs.size() != 3)
+ return false;
+
+ // Check the first bold section.
+ const editeng::Section* pAttr = aSecAttrs.data();
+ if (pAttr->mnParagraph != 0 || pAttr->mnStart != 0 || pAttr->mnEnd != 4)
+ return false;
+
+ if (pAttr->maAttributes.size() != 1 || !isBold(*pAttr))
+ return false;
+
+ // The middle section should be unformatted.
+ pAttr = &aSecAttrs[1];
+ if (pAttr->mnParagraph != 0 || pAttr->mnStart != 4 || pAttr->mnEnd != 9)
+ return false;
+
+ if (!pAttr->maAttributes.empty())
+ return false;
+
+ // The last section should be italic.
+ pAttr = &aSecAttrs[2];
+ if (pAttr->mnParagraph != 0 || pAttr->mnStart != 9 || pAttr->mnEnd != 15)
+ return false;
+
+ if (pAttr->maAttributes.size() != 1 || !isItalic(*pAttr))
+ return false;
+
+ return true;
+ }
+
+ bool checkB4(const EditTextObject* pText) const
+ {
+ if (!pText)
+ return false;
+
+ if (pText->GetParagraphCount() != 3)
+ return false;
+
+ if (pText->GetText(0) != "One")
+ return false;
+
+ if (pText->GetText(1) != "Two")
+ return false;
+
+ if (pText->GetText(2) != "Three")
+ return false;
+
+ return true;
+ }
+
+ bool checkB5(const EditTextObject* pText) const
+ {
+ if (!pText)
+ return false;
+
+ if (pText->GetParagraphCount() != 6)
+ return false;
+
+ if (!pText->GetText(0).isEmpty())
+ return false;
+
+ if (pText->GetText(1) != "Two")
+ return false;
+
+ if (pText->GetText(2) != "Three")
+ return false;
+
+ if (!pText->GetText(3).isEmpty())
+ return false;
+
+ if (pText->GetText(4) != "Five")
+ return false;
+
+ if (!pText->GetText(5).isEmpty())
+ return false;
+
+ return true;
+ }
+
+ bool checkB6(const EditTextObject* pText) const
+ {
+ if (!pText)
+ return false;
+
+ if (pText->GetParagraphCount() != 1)
+ return false;
+
+ if (pText->GetText(0) != "Strike Me")
+ return false;
+
+ std::vector<editeng::Section> aSecAttrs;
+ pText->GetAllSections(aSecAttrs);
+ if (aSecAttrs.size() != 2)
+ return false;
+
+ // Check the first strike-out section.
+ const editeng::Section* pAttr = aSecAttrs.data();
+ if (pAttr->mnParagraph != 0 || pAttr->mnStart != 0 || pAttr->mnEnd != 6)
+ return false;
+
+ if (pAttr->maAttributes.size() != 1 || !isStrikeOut(*pAttr))
+ return false;
+
+ // The last section should be unformatted.
+ pAttr = &aSecAttrs[1];
+ return pAttr->mnParagraph == 0 && pAttr->mnStart == 6 && pAttr->mnEnd == 9;
+ }
+
+ bool checkB7(const EditTextObject* pText) const
+ {
+ if (!pText)
+ return false;
+
+ if (pText->GetParagraphCount() != 1)
+ return false;
+
+ if (pText->GetText(0) != "Font1 and Font2")
+ return false;
+
+ std::vector<editeng::Section> aSecAttrs;
+ pText->GetAllSections(aSecAttrs);
+ if (aSecAttrs.size() != 3)
+ return false;
+
+ // First section should have "Courier" font applied.
+ const editeng::Section* pAttr = aSecAttrs.data();
+ if (pAttr->mnParagraph != 0 || pAttr->mnStart != 0 || pAttr->mnEnd != 5)
+ return false;
+
+ if (pAttr->maAttributes.size() != 1 || !isFont(*pAttr, "Courier"))
+ return false;
+
+ // Last section should have "Luxi Mono" applied.
+ pAttr = &aSecAttrs[2];
+ if (pAttr->mnParagraph != 0 || pAttr->mnStart != 10 || pAttr->mnEnd != 15)
+ return false;
+
+ if (pAttr->maAttributes.size() != 1 || !isFont(*pAttr, "Luxi Mono"))
+ return false;
+
+ return true;
+ }
+
+ bool checkB8(const EditTextObject* pText) const
+ {
+ if (!pText)
+ return false;
+
+ if (pText->GetParagraphCount() != 1)
+ return false;
+
+ if (pText->GetText(0) != "Over and Under")
+ return false;
+
+ std::vector<editeng::Section> aSecAttrs;
+ pText->GetAllSections(aSecAttrs);
+ if (aSecAttrs.size() != 3)
+ return false;
+
+ // First section should have overline applied.
+ const editeng::Section* pAttr = aSecAttrs.data();
+ if (pAttr->mnParagraph != 0 || pAttr->mnStart != 0 || pAttr->mnEnd != 4)
+ return false;
+
+ if (pAttr->maAttributes.size() != 1 || !isOverline(*pAttr, LINESTYLE_DOUBLE))
+ return false;
+
+ // Last section should have underline applied.
+ pAttr = &aSecAttrs[2];
+ if (pAttr->mnParagraph != 0 || pAttr->mnStart != 9 || pAttr->mnEnd != 14)
+ return false;
+
+ if (pAttr->maAttributes.size() != 1 || !isUnderline(*pAttr, LINESTYLE_DOUBLE))
+ return false;
+
+ return true;
+ }
+
+ bool checkB9(const EditTextObject* pText) const
+ {
+ if (!pText)
+ return false;
+
+ if (pText->GetParagraphCount() != 1)
+ return false;
+
+ if (pText->GetText(0) != "Sub and Super")
+ return false;
+
+ std::vector<editeng::Section> aSecAttrs;
+ pText->GetAllSections(aSecAttrs);
+ if (aSecAttrs.size() != 3)
+ return false;
+
+ // superscript
+ const editeng::Section* pAttr = aSecAttrs.data();
+ if (pAttr->mnParagraph != 0 || pAttr->mnStart != 0 || pAttr->mnEnd != 3)
+ return false;
+
+ if (pAttr->maAttributes.size() != 1 || !isEscapement(*pAttr, 32, 64))
+ return false;
+
+ // subscript
+ pAttr = &aSecAttrs[2];
+ if (pAttr->mnParagraph != 0 || pAttr->mnStart != 8 || pAttr->mnEnd != 13)
+ return false;
+
+ if (pAttr->maAttributes.size() != 1 || !isEscapement(*pAttr, -32, 66))
+ return false;
+
+ return true;
+ }
+
+ bool checkB10(const EditTextObject* pText) const
+ {
+ if (!pText)
+ return false;
+
+ if (pText->GetParagraphCount() != 1)
+ return false;
+
+ if (pText->GetText(0) != "BLUE AUTO")
+ return false;
+
+ std::vector<editeng::Section> aSecAttrs;
+ pText->GetAllSections(aSecAttrs);
+ if (aSecAttrs.size() != 2)
+ return false;
+
+ // auto color
+ const editeng::Section* pAttr = &aSecAttrs[1];
+ if (pAttr->mnParagraph != 0 || pAttr->mnStart != 5 || pAttr->mnEnd != 9)
+ return false;
+
+ if (pAttr->maAttributes.size() != 1 || !isColor(*pAttr, COL_AUTO))
+ return false;
+
+ return true;
+ }
+
+ } aCheckFunc;
+
+ // Start with an empty document, put one edit text cell, and make sure it
+ // survives the save and reload.
+ createScDoc();
+ const EditTextObject* pEditText;
+ {
+ ScDocument* pDoc = getScDoc();
+ CPPUNIT_ASSERT_MESSAGE("This document should at least have one sheet.",
+ pDoc->GetTableCount() > 0);
+
+ // Insert an edit text cell.
+ ScFieldEditEngine* pEE = &pDoc->GetEditEngine();
+ pEE->SetTextCurrentDefaults("Bold and Italic");
+ // Set the 'Bold' part bold.
+ setAttribute(*pEE, 0, 0, 4, EE_CHAR_WEIGHT);
+ // Set the 'Italic' part italic.
+ setAttribute(*pEE, 0, 9, 15, EE_CHAR_ITALIC);
+ ESelection aSel;
+ aSel.nStartPara = aSel.nEndPara = 0;
+
+ // Set this edit text to cell B2.
+ pDoc->SetEditText(ScAddress(1, 1, 0), pEE->CreateTextObject());
+ pEditText = pDoc->GetEditText(ScAddress(1, 1, 0));
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B2 value.", aCheckFunc.checkB2(pEditText));
+ }
+
+ // Now, save and reload this document.
+ saveAndReload("calc8");
+ {
+ ScDocument* pDoc = getScDoc();
+ CPPUNIT_ASSERT_MESSAGE("Reloaded document should at least have one sheet.",
+ pDoc->GetTableCount() > 0);
+ ScFieldEditEngine* pEE = &pDoc->GetEditEngine();
+ pEditText = pDoc->GetEditText(ScAddress(1, 1, 0));
+
+ // Make sure the content of B2 is still intact.
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B2 value.", aCheckFunc.checkB2(pEditText));
+
+ // Insert a multi-line content to B4.
+ pEE->Clear();
+ pEE->SetTextCurrentDefaults("One\nTwo\nThree");
+ pDoc->SetEditText(ScAddress(1, 3, 0), pEE->CreateTextObject());
+ pEditText = pDoc->GetEditText(ScAddress(1, 3, 0));
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B4 value.", aCheckFunc.checkB4(pEditText));
+ }
+
+ // Reload the doc again, and check the content of B2 and B4.
+ saveAndReload("calc8");
+ {
+ ScDocument* pDoc = getScDoc();
+ ScFieldEditEngine* pEE = &pDoc->GetEditEngine();
+
+ pEditText = pDoc->GetEditText(ScAddress(1, 1, 0));
+ CPPUNIT_ASSERT_MESSAGE("B2 should be an edit text.", pEditText);
+ pEditText = pDoc->GetEditText(ScAddress(1, 3, 0));
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B4 value.", aCheckFunc.checkB4(pEditText));
+
+ // Insert a multi-line content to B5, but this time, set some empty paragraphs.
+ pEE->Clear();
+ pEE->SetTextCurrentDefaults("\nTwo\nThree\n\nFive\n");
+ pDoc->SetEditText(ScAddress(1, 4, 0), pEE->CreateTextObject());
+ pEditText = pDoc->GetEditText(ScAddress(1, 4, 0));
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B5 value.", aCheckFunc.checkB5(pEditText));
+
+ // Insert a text with strikethrough in B6.
+ pEE->Clear();
+ pEE->SetTextCurrentDefaults("Strike Me");
+ // Set the 'Strike' part strikethrough.
+ setAttribute(*pEE, 0, 0, 6, EE_CHAR_STRIKEOUT);
+ pDoc->SetEditText(ScAddress(1, 5, 0), pEE->CreateTextObject());
+ pEditText = pDoc->GetEditText(ScAddress(1, 5, 0));
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B6 value.", aCheckFunc.checkB6(pEditText));
+
+ // Insert a text with different font segments in B7.
+ pEE->Clear();
+ pEE->SetTextCurrentDefaults("Font1 and Font2");
+ setFont(*pEE, 0, 0, 5, "Courier");
+ setFont(*pEE, 0, 10, 15, "Luxi Mono");
+ pDoc->SetEditText(ScAddress(1, 6, 0), pEE->CreateTextObject());
+ pEditText = pDoc->GetEditText(ScAddress(1, 6, 0));
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B7 value.", aCheckFunc.checkB7(pEditText));
+
+ // Insert a text with overline and underline in B8.
+ pEE->Clear();
+ pEE->SetTextCurrentDefaults("Over and Under");
+ setAttribute(*pEE, 0, 0, 4, EE_CHAR_OVERLINE);
+ setAttribute(*pEE, 0, 9, 14, EE_CHAR_UNDERLINE);
+ pDoc->SetEditText(ScAddress(1, 7, 0), pEE->CreateTextObject());
+ pEditText = pDoc->GetEditText(ScAddress(1, 7, 0));
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B8 value.", aCheckFunc.checkB8(pEditText));
+
+ pEE->Clear();
+ pEE->SetTextCurrentDefaults("Sub and Super");
+ setEscapement(*pEE, 0, 0, 3, 32, 64);
+ setEscapement(*pEE, 0, 8, 13, -32, 66);
+ pDoc->SetEditText(ScAddress(1, 8, 0), pEE->CreateTextObject());
+ pEditText = pDoc->GetEditText(ScAddress(1, 8, 0));
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B9 value.", aCheckFunc.checkB9(pEditText));
+
+ ScPatternAttr aCellFontColor(pDoc->GetPool());
+ aCellFontColor.GetItemSet().Put(SvxColorItem(COL_BLUE, ATTR_FONT_COLOR));
+ // Set font color of B10 to blue.
+ pDoc->ApplyPattern(1, 9, 0, aCellFontColor);
+ pEE->Clear();
+ pEE->SetTextCurrentDefaults("BLUE AUTO");
+ // Set the color of the string "AUTO" to automatic color.
+ setAttribute(*pEE, 0, 5, 9, EE_CHAR_COLOR, COL_AUTO);
+ pDoc->SetEditText(ScAddress(1, 9, 0), pEE->CreateTextObject());
+ pEditText = pDoc->GetEditText(ScAddress(1, 9, 0));
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B10 value.", aCheckFunc.checkB10(pEditText));
+ }
+
+ // Reload the doc again, and check the content of B2, B4, B6 and B7.
+ saveAndReload("calc8");
+ ScDocument* pDoc = getScDoc();
+
+ pEditText = pDoc->GetEditText(ScAddress(1, 1, 0));
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B2 value after save and reload.",
+ aCheckFunc.checkB2(pEditText));
+ pEditText = pDoc->GetEditText(ScAddress(1, 3, 0));
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B4 value after save and reload.",
+ aCheckFunc.checkB4(pEditText));
+ pEditText = pDoc->GetEditText(ScAddress(1, 4, 0));
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B5 value after save and reload.",
+ aCheckFunc.checkB5(pEditText));
+ pEditText = pDoc->GetEditText(ScAddress(1, 5, 0));
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B6 value after save and reload.",
+ aCheckFunc.checkB6(pEditText));
+ pEditText = pDoc->GetEditText(ScAddress(1, 6, 0));
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B7 value after save and reload.",
+ aCheckFunc.checkB7(pEditText));
+ pEditText = pDoc->GetEditText(ScAddress(1, 7, 0));
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B8 value after save and reload.",
+ aCheckFunc.checkB8(pEditText));
+ pEditText = pDoc->GetEditText(ScAddress(1, 9, 0));
+ CPPUNIT_ASSERT_MESSAGE("Incorrect B10 value after save and reload.",
+ aCheckFunc.checkB10(pEditText));
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testRichTextCellFormatXLSX)
+{
+ createScDoc("xls/cellformat.xls");
+
+ save("Calc Office Open XML");
+ xmlDocUniquePtr pSheet = parseExport("xl/worksheets/sheet1.xml");
+ CPPUNIT_ASSERT(pSheet);
+
+ // make sure the only cell in this doc is assigned some formatting record
+ OUString aCellFormat = getXPath(pSheet, "/x:worksheet/x:sheetData/x:row/x:c"_ostr, "s"_ostr);
+ CPPUNIT_ASSERT_MESSAGE("Cell format is missing", !aCellFormat.isEmpty());
+
+ xmlDocUniquePtr pStyles = parseExport("xl/styles.xml");
+ CPPUNIT_ASSERT(pStyles);
+
+ OString nFormatIdx = OString::number(aCellFormat.toInt32() + 1);
+ const OString aXPath1("/x:styleSheet/x:cellXfs/x:xf[" + nFormatIdx + "]/x:alignment");
+ // formatting record is set to wrap text
+ assertXPath(pStyles, aXPath1, "wrapText"_ostr, "true");
+
+ // see what font it references
+ const OString aXPath2("/x:styleSheet/x:cellXfs/x:xf[" + nFormatIdx + "]");
+ OUString aFontId = getXPath(pStyles, aXPath2, "fontId"_ostr);
+ OString nFontIdx = OString::number(aFontId.toInt32() + 1);
+
+ // that font should be bold
+ const OString aXPath3("/x:styleSheet/x:fonts/x:font[" + nFontIdx + "]/x:b");
+ assertXPath(pStyles, aXPath3, "val"_ostr, "true");
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testWrapText)
+{
+ createScDoc("xlsx/wrap-text.xlsx");
+
+ save("Calc Office Open XML");
+
+ xmlDocUniquePtr pStyles = parseExport("xl/styles.xml");
+ CPPUNIT_ASSERT(pStyles);
+
+ assertXPath(pStyles, "/x:styleSheet/x:cellXfs"_ostr, "count"_ostr, "7");
+
+ assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[1]/x:alignment"_ostr, "wrapText"_ostr,
+ "false");
+ assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[2]/x:alignment"_ostr, "wrapText"_ostr,
+ "false");
+ assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[3]/x:alignment"_ostr, "wrapText"_ostr,
+ "false");
+ assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[4]/x:alignment"_ostr, "wrapText"_ostr,
+ "false");
+ assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[5]/x:alignment"_ostr, "wrapText"_ostr,
+ "true");
+ assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[6]/x:alignment"_ostr, "wrapText"_ostr,
+ "true");
+ assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[7]/x:alignment"_ostr, "wrapText"_ostr,
+ "true");
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testFormulaRefSheetNameODS)
+{
+ createScDoc("ods/formula-quote-in-sheet-name.ods");
+ {
+ ScDocument* pDoc = getScDoc();
+
+ sc::AutoCalcSwitch aACSwitch(*pDoc, true); // turn on auto calc.
+ pDoc->SetString(ScAddress(1, 1, 0), "='90''s Data'.B2");
+ CPPUNIT_ASSERT_EQUAL(1.1, pDoc->GetValue(ScAddress(1, 1, 0)));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("='90''s Data'.B2"),
+ pDoc->GetFormula(1, 1, 0));
+ }
+ // Now, save and reload this document.
+ saveAndReload("calc8");
+
+ ScDocument* pDoc = getScDoc();
+ pDoc->CalcAll();
+ CPPUNIT_ASSERT_EQUAL(1.1, pDoc->GetValue(ScAddress(1, 1, 0)));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("='90''s Data'.B2"),
+ pDoc->GetFormula(1, 1, 0));
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testCellValuesExportODS)
+{
+ // Start with an empty document
+ createScDoc();
+ {
+ ScDocument* pDoc = getScDoc();
+ CPPUNIT_ASSERT_MESSAGE("This document should at least have one sheet.",
+ pDoc->GetTableCount() > 0);
+
+ // set a value double
+ pDoc->SetValue(ScAddress(0, 0, 0), 2.0); // A1
+
+ // set a formula
+ pDoc->SetValue(ScAddress(2, 0, 0), 3.0); // C1
+ pDoc->SetValue(ScAddress(3, 0, 0), 3); // D1
+ pDoc->SetString(ScAddress(4, 0, 0), "=10*C1/4"); // E1
+ pDoc->SetValue(ScAddress(5, 0, 0), 3.0); // F1
+ pDoc->SetString(ScAddress(7, 0, 0), "=SUM(C1:F1)"); //H1
+
+ // set a string
+ pDoc->SetString(ScAddress(0, 2, 0), "a simple line"); //A3
+
+ // set a digit string
+ pDoc->SetString(ScAddress(0, 4, 0), "'12"); //A5
+ // set a contiguous value
+ pDoc->SetValue(ScAddress(0, 5, 0), 12.0); //A6
+ // set a contiguous string
+ pDoc->SetString(ScAddress(0, 6, 0), "a string"); //A7
+ // set a contiguous formula
+ pDoc->SetString(ScAddress(0, 7, 0), "=$A$6"); //A8
+ }
+ // save and reload
+ saveAndReload("calc8");
+ ScDocument* pDoc = getScDoc();
+ CPPUNIT_ASSERT_MESSAGE("Reloaded document should at least have one sheet.",
+ pDoc->GetTableCount() > 0);
+
+ // check value
+ CPPUNIT_ASSERT_EQUAL(2.0, pDoc->GetValue(0, 0, 0));
+ CPPUNIT_ASSERT_EQUAL(3.0, pDoc->GetValue(2, 0, 0));
+ CPPUNIT_ASSERT_EQUAL(3.0, pDoc->GetValue(3, 0, 0));
+ CPPUNIT_ASSERT_EQUAL(7.5, pDoc->GetValue(4, 0, 0));
+ CPPUNIT_ASSERT_EQUAL(3.0, pDoc->GetValue(5, 0, 0));
+
+ // check formula
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula =10*C1/4", OUString("=10*C1/4"),
+ pDoc->GetFormula(4, 0, 0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula =SUM(C1:F1)", OUString("=SUM(C1:F1)"),
+ pDoc->GetFormula(7, 0, 0));
+ CPPUNIT_ASSERT_EQUAL(16.5, pDoc->GetValue(7, 0, 0));
+
+ // check string
+ ScRefCellValue aCell;
+ aCell.assign(*pDoc, ScAddress(0, 2, 0));
+ CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, aCell.getType());
+
+ // check for an empty cell
+ aCell.assign(*pDoc, ScAddress(0, 3, 0));
+ CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, aCell.getType());
+
+ // check a digit string
+ aCell.assign(*pDoc, ScAddress(0, 4, 0));
+ CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, aCell.getType());
+
+ //check contiguous values
+ CPPUNIT_ASSERT_EQUAL(12.0, pDoc->GetValue(0, 5, 0));
+ CPPUNIT_ASSERT_EQUAL(OUString("a string"), pDoc->GetString(0, 6, 0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula =$A$6", OUString("=$A$6"),
+ pDoc->GetFormula(0, 7, 0));
+ CPPUNIT_ASSERT_EQUAL(pDoc->GetValue(0, 5, 0), pDoc->GetValue(0, 7, 0));
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testCellNoteExportODS)
+{
+ createScDoc("ods/single-note.ods");
+ ScAddress aPos(0, 0, 0); // Start with A1.
+ {
+ ScDocument* pDoc = getScDoc();
+
+ CPPUNIT_ASSERT_MESSAGE("There should be a note at A1.", pDoc->HasNote(aPos));
+
+ aPos.IncRow(); // Move to A2.
+ ScPostIt* pNote = pDoc->GetOrCreateNote(aPos);
+ pNote->SetText(aPos, "Note One");
+ pNote->SetAuthor("Author One");
+ CPPUNIT_ASSERT_MESSAGE("There should be a note at A2.", pDoc->HasNote(aPos));
+ }
+ // save and reload
+ saveAndReload("calc8");
+ ScDocument* pDoc = getScDoc();
+
+ aPos.SetRow(0); // Move back to A1.
+ CPPUNIT_ASSERT_MESSAGE("There should be a note at A1.", pDoc->HasNote(aPos));
+ aPos.IncRow(); // Move to A2.
+ CPPUNIT_ASSERT_MESSAGE("There should be a note at A2.", pDoc->HasNote(aPos));
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testCellNoteExportXLS)
+{
+ // Start with an empty document.s
+ createScDoc("ods/notes-on-3-sheets.ods");
+ {
+ ScDocument* pDoc = getScDoc();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("This document should have 3 sheets.", SCTAB(3),
+ pDoc->GetTableCount());
+
+ // Check note's presence.
+ CPPUNIT_ASSERT(pDoc->HasNote(ScAddress(0, 0, 0)));
+ CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 1, 0)));
+ CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 2, 0)));
+
+ CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 0, 1)));
+ CPPUNIT_ASSERT(pDoc->HasNote(ScAddress(0, 1, 1)));
+ CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 2, 1)));
+
+ CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 0, 2)));
+ CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 1, 2)));
+ CPPUNIT_ASSERT(pDoc->HasNote(ScAddress(0, 2, 2)));
+ }
+ // save and reload as XLS.
+ saveAndReload("MS Excel 97");
+ {
+ ScDocument* pDoc = getScDoc();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("This document should have 3 sheets.", SCTAB(3),
+ pDoc->GetTableCount());
+
+ // Check note's presence again.
+ CPPUNIT_ASSERT(pDoc->HasNote(ScAddress(0, 0, 0)));
+ CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 1, 0)));
+ CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 2, 0)));
+
+ CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 0, 1)));
+ CPPUNIT_ASSERT(pDoc->HasNote(ScAddress(0, 1, 1)));
+ CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 2, 1)));
+
+ CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 0, 2)));
+ CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 1, 2)));
+ CPPUNIT_ASSERT(pDoc->HasNote(ScAddress(0, 2, 2)));
+ }
+}
+
+namespace
+{
+void checkMatrixRange(ScDocument& rDoc, const ScRange& rRange)
+{
+ ScRange aMatRange;
+ ScAddress aMatOrigin;
+ for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
+ {
+ for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
+ {
+ ScAddress aPos(nCol, nRow, rRange.aStart.Tab());
+ bool bIsMatrix = rDoc.GetMatrixFormulaRange(aPos, aMatRange);
+ CPPUNIT_ASSERT_MESSAGE("Matrix expected, but not found.", bIsMatrix);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong matrix range.", rRange, aMatRange);
+ const ScFormulaCell* pCell = rDoc.GetFormulaCell(aPos);
+ CPPUNIT_ASSERT_MESSAGE("This must be a formula cell.", pCell);
+
+ bIsMatrix = pCell->GetMatrixOrigin(rDoc, aMatOrigin);
+ CPPUNIT_ASSERT_MESSAGE("Not a part of matrix formula.", bIsMatrix);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong matrix origin.", aMatRange.aStart, aMatOrigin);
+ }
+ }
+}
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testInlineArrayXLS)
+{
+ createScDoc("xls/inline-array.xls");
+
+ saveAndReload("MS Excel 97");
+
+ ScDocument* pDoc = getScDoc();
+
+ // B2:C3 contains a matrix.
+ checkMatrixRange(*pDoc, ScRange(1, 1, 0, 2, 2, 0));
+
+ // B5:D6 contains a matrix.
+ checkMatrixRange(*pDoc, ScRange(1, 4, 0, 3, 5, 0));
+
+ // B8:C10 as well.
+ checkMatrixRange(*pDoc, ScRange(1, 7, 0, 2, 9, 0));
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testEmbeddedChartODS)
+{
+ createScDoc("xls/embedded-chart.xls");
+
+ save("calc8");
+
+ xmlDocUniquePtr pDoc = parseExport("content.xml");
+ CPPUNIT_ASSERT(pDoc);
+ assertXPath(pDoc,
+ "/office:document-content/office:body/office:spreadsheet/table:table[2]/"
+ "table:table-row[7]/table:table-cell[2]/draw:frame/draw:object"_ostr,
+ "notify-on-update-of-ranges"_ostr,
+ "Chart1.B3:Chart1.B5 Chart1.C2:Chart1.C2 Chart1.C3:Chart1.C5");
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testEmbeddedChartXLS)
+{
+ createScDoc("xls/embedded-chart.xls");
+
+ saveAndReload("MS Excel 97");
+
+ ScDocument* pDoc = getScDoc();
+
+ // Make sure the 2nd sheet is named 'Chart1'.
+ OUString aName;
+ pDoc->GetName(1, aName);
+ CPPUNIT_ASSERT_EQUAL(OUString("Chart1"), aName);
+
+ const SdrOle2Obj* pOleObj = getSingleChartObject(*pDoc, 1);
+ CPPUNIT_ASSERT_MESSAGE("Failed to retrieve a chart object from the 2nd sheet.", pOleObj);
+
+ ScRangeList aRanges = getChartRanges(*pDoc, *pOleObj);
+ CPPUNIT_ASSERT_MESSAGE("Label range (B3:B5) not found.",
+ aRanges.Contains(ScRange(1, 2, 1, 1, 4, 1)));
+ CPPUNIT_ASSERT_MESSAGE("Data label (C2) not found.", aRanges.Contains(ScAddress(2, 1, 1)));
+ CPPUNIT_ASSERT_MESSAGE("Data range (C3:C5) not found.",
+ aRanges.Contains(ScRange(2, 2, 1, 2, 4, 1)));
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testCellAnchoredGroupXLS)
+{
+ createScDoc("xls/cell-anchored-group.xls");
+
+ saveAndReload("calc8");
+
+ // the document contains a group anchored on the first cell, make sure it's there in the right place
+ ScDocument* pDoc = getScDoc();
+ CPPUNIT_ASSERT_MESSAGE("There should be at least one sheet.", pDoc->GetTableCount() > 0);
+ ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
+ SdrPage* pPage = pDrawLayer->GetPage(0);
+ CPPUNIT_ASSERT_MESSAGE("draw page for sheet 1 should exist.", pPage);
+ const size_t nCount = pPage->GetObjCount();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be 1 objects.", static_cast<size_t>(1), nCount);
+
+ SdrObject* pObj = pPage->GetObj(0);
+ CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj);
+ ScDrawObjData* pData = ScDrawLayer::GetObjData(pObj);
+ CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData);
+ CPPUNIT_ASSERT_MESSAGE("Upper left of bounding rectangle should be nonnegative.",
+ pData->getShapeRect().Left() >= 0 || pData->getShapeRect().Top() >= 0);
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testFormulaReferenceXLS)
+{
+ createScDoc("xls/formula-reference.xls");
+
+ saveAndReload("MS Excel 97");
+
+ ScDocument* pDoc = getScDoc();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D2", OUString("=$A$2+$B$2+$C$2"),
+ pDoc->GetFormula(3, 1, 0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D3", OUString("=A3+B3+C3"),
+ pDoc->GetFormula(3, 2, 0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D6", OUString("=SUM($A$6:$C$6)"),
+ pDoc->GetFormula(3, 5, 0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D7", OUString("=SUM(A7:C7)"),
+ pDoc->GetFormula(3, 6, 0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D10", OUString("=$Two.$A$2+$Two.$B$2+$Two.$C$2"),
+ pDoc->GetFormula(3, 9, 0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D11", OUString("=$Two.A3+$Two.B3+$Two.C3"),
+ pDoc->GetFormula(3, 10, 0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D14", OUString("=MIN($Two.$A$2:$C$2)"),
+ pDoc->GetFormula(3, 13, 0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D15", OUString("=MAX($Two.A3:C3)"),
+ pDoc->GetFormula(3, 14, 0));
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testSheetProtectionXLSX)
+{
+ createScDoc("xlsx/ProtecteSheet1234Pass.xlsx");
+
+ saveAndReload("Calc Office Open XML");
+
+ ScDocument* pDoc = getScDoc();
+ const ScTableProtection* pTabProtect = pDoc->GetTabProtection(0);
+ CPPUNIT_ASSERT(pTabProtect);
+ Sequence<sal_Int8> aHash = pTabProtect->getPasswordHash(PASSHASH_XL);
+ // check has
+ if (aHash.getLength() >= 2)
+ {
+ CPPUNIT_ASSERT_EQUAL(sal_uInt8(204), static_cast<sal_uInt8>(aHash[0]));
+ CPPUNIT_ASSERT_EQUAL(sal_uInt8(61), static_cast<sal_uInt8>(aHash[1]));
+ }
+ // we could flesh out this check I guess
+ CPPUNIT_ASSERT(!pTabProtect->isOptionEnabled(ScTableProtection::OBJECTS));
+ CPPUNIT_ASSERT(!pTabProtect->isOptionEnabled(ScTableProtection::SCENARIOS));
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testSheetProtectionXLSB)
+{
+ createScDoc("xlsb/tdf108017_calcProtection.xlsb");
+
+ saveAndReload("Calc Office Open XML");
+
+ ScDocument* pDoc = getScDoc();
+ const ScTableProtection* pTabProtect = pDoc->GetTabProtection(0);
+ CPPUNIT_ASSERT(pTabProtect);
+ CPPUNIT_ASSERT(pTabProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS));
+ CPPUNIT_ASSERT(!pTabProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS));
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testConditionalFormatNumberInTextRule)
+{
+ createScDoc();
+
+ ScDocument* pDocument = getScDoc();
+ ScAddress aAddress(0, 0, 0);
+
+ auto pFormat = std::make_unique<ScConditionalFormat>(0, pDocument);
+ ScRange aCondFormatRange(aAddress);
+ ScRangeList aRangeList(aCondFormatRange);
+ pFormat->SetRange(aRangeList);
+ ScCondFormatEntry* pEntry
+ = new ScCondFormatEntry(ScConditionMode::BeginsWith, "15", "", *pDocument, aAddress, "");
+ pFormat->AddEntry(pEntry);
+ pDocument->AddCondFormat(std::move(pFormat), 0);
+
+ saveAndReload("Calc Office Open XML");
+ pDocument = getScDoc();
+
+ ScConditionalFormat* pCondFormat = pDocument->GetCondFormat(0, 0, 0);
+ CPPUNIT_ASSERT(pCondFormat);
+ CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormat->size());
+ const ScFormatEntry* pCondFormatEntry = pCondFormat->GetEntry(0);
+ CPPUNIT_ASSERT(pCondFormatEntry);
+ CPPUNIT_ASSERT_EQUAL(ScFormatEntry::Type::Condition, pCondFormatEntry->GetType());
+ const ScConditionEntry* pConditionEntry
+ = static_cast<const ScConditionEntry*>(pCondFormatEntry);
+ CPPUNIT_ASSERT_EQUAL(ScConditionMode::BeginsWith, pConditionEntry->GetOperation());
+ CPPUNIT_ASSERT_EQUAL(OUString("\"15\""), pConditionEntry->GetExpression(aAddress, 0));
+}
+
+namespace
+{
+const char* toBorderName(SvxBorderLineStyle eStyle)
+{
+ switch (eStyle)
+ {
+ case SvxBorderLineStyle::SOLID:
+ return "SOLID";
+ case SvxBorderLineStyle::DOTTED:
+ return "DOTTED";
+ case SvxBorderLineStyle::DASHED:
+ return "DASHED";
+ case SvxBorderLineStyle::DASH_DOT:
+ return "DASH_DOT";
+ case SvxBorderLineStyle::DASH_DOT_DOT:
+ return "DASH_DOT_DOT";
+ case SvxBorderLineStyle::DOUBLE_THIN:
+ return "DOUBLE_THIN";
+ case SvxBorderLineStyle::FINE_DASHED:
+ return "FINE_DASHED";
+ default:;
+ }
+
+ return "";
+}
+}
+
+void ScExportTest::testExcelCellBorders(const OUString& sFormatType)
+{
+ static const struct
+ {
+ SCROW mnRow;
+ SvxBorderLineStyle mnStyle;
+ tools::Long mnWidth;
+ } aChecks[] = {
+ { 1, SvxBorderLineStyle::SOLID, 1 }, // hair
+ { 3, SvxBorderLineStyle::DOTTED, 15 }, // dotted
+ { 5, SvxBorderLineStyle::DASH_DOT_DOT, 15 }, // dash dot dot
+ { 7, SvxBorderLineStyle::DASH_DOT, 15 }, // dash dot
+ { 9, SvxBorderLineStyle::FINE_DASHED, 15 }, // dashed
+ { 11, SvxBorderLineStyle::SOLID, 15 }, // thin
+ { 13, SvxBorderLineStyle::DASH_DOT_DOT, 35 }, // medium dash dot dot
+ { 17, SvxBorderLineStyle::DASH_DOT, 35 }, // medium dash dot
+ { 19, SvxBorderLineStyle::DASHED, 35 }, // medium dashed
+ { 21, SvxBorderLineStyle::SOLID, 35 }, // medium
+ { 23, SvxBorderLineStyle::SOLID, 50 }, // thick
+ { 25, SvxBorderLineStyle::DOUBLE_THIN, -1 }, // double (don't check width)
+ };
+
+ {
+ ScDocument* pDoc = getScDoc();
+
+ for (auto const[nRow, eStyle, nWidth] : aChecks)
+ {
+ const editeng::SvxBorderLine* pLine = nullptr;
+ pDoc->GetBorderLines(2, nRow, 0, nullptr, &pLine, nullptr, nullptr);
+ CPPUNIT_ASSERT(pLine);
+ CPPUNIT_ASSERT_EQUAL(toBorderName(eStyle), toBorderName(pLine->GetBorderLineStyle()));
+ if (nWidth >= 0)
+ CPPUNIT_ASSERT_EQUAL(nWidth, pLine->GetWidth());
+ }
+ }
+
+ saveAndReload(sFormatType);
+ ScDocument* pDoc = getScDoc();
+ for (auto const[nRow, eStyle, nWidth] : aChecks)
+ {
+ const editeng::SvxBorderLine* pLine = nullptr;
+ pDoc->GetBorderLines(2, nRow, 0, nullptr, &pLine, nullptr, nullptr);
+ CPPUNIT_ASSERT(pLine);
+ CPPUNIT_ASSERT_EQUAL(toBorderName(eStyle), toBorderName(pLine->GetBorderLineStyle()));
+ if (nWidth >= 0)
+ CPPUNIT_ASSERT_EQUAL(nWidth, pLine->GetWidth());
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testCellBordersXLS)
+{
+ createScDoc("xls/cell-borders.xls");
+ testExcelCellBorders("MS Excel 97");
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testCellBordersXLSX)
+{
+ createScDoc("xlsx/cell-borders.xlsx");
+ testExcelCellBorders("Calc Office Open XML");
+}
+
+CPPUNIT_TEST_FIXTURE(ScExportTest, testTdf155368)
+{
+ createScDoc("ods/tdf155368.ods");
+
+ dispatchCommand(mxComponent, ".uno:SelectAll", {});
+
+ dispatchCommand(mxComponent, ".uno:WrapText", {});
+
+ save("Calc Office Open XML");
+
+ xmlDocUniquePtr pStyles = parseExport("xl/styles.xml");
+ CPPUNIT_ASSERT(pStyles);
+
+ assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[1]/x:alignment"_ostr, "wrapText"_ostr,
+ "false");
+
+ // Without the fix in place, this test would have failed with
+ // - Expected: false
+ // - Actual : true
+ assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[2]/x:alignment"_ostr, "wrapText"_ostr,
+ "false");
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */