/* -*- 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 #include #include "helper/debughelper.hxx" #include #include "helper/qahelper.hxx" #include "helper/xpath.hxx" #include "helper/shared_test_impl.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; using namespace ::com::sun::star::uno; class ScExportTest : public ScBootstrapFixture, public XmlTestTools { protected: virtual void registerNamespaces(xmlXPathContextPtr& pXmlXPathCtx) override; public: ScExportTest(); virtual void setUp() override; virtual void tearDown() override; void test(); void testDefaultFontHeight(); void testTdf139167(); void testTdf113271(); void testTdf139394(); void testExtCondFormatXLSX(); void testTdf90104(); void testTdf111876(); void testPasswordExportODS(); void testTdf134332(); void testConditionalFormatExportODS(); void testConditionalFormatExportXLSX(); void testCondFormatExportCellIs(); void testTdf99856_dataValidationTest(); void testProtectionKeyODS_UTF16LErtlSHA1(); void testProtectionKeyODS_UTF8SHA1(); void testProtectionKeyODS_UTF8SHA256ODF12(); void testProtectionKeyODS_UTF8SHA256W3C(); void testProtectionKeyODS_XL_SHA1(); void testColorScaleExportODS(); void testColorScaleExportXLSX(); void testDataBarExportODS(); void testDataBarExportXLSX(); void testConditionalFormatRangeListXLSX(); void testConditionalFormatContainsTextXLSX(); void testConditionalFormatPriorityCheckXLSX(); void testConditionalFormatOriginXLSX(); void testMiscRowHeightExport(); void testNamedRangeBugfdo62729(); void testBuiltinRangesXLSX(); void testRichTextExportODS(); void testRichTextCellFormatXLSX(); void testFormulaRefSheetNameODS(); void testCellValuesExportODS(); void testCellNoteExportODS(); void testCellNoteExportXLS(); void testFormatExportODS(); void testCommentExportXLSX(); void testCommentExportXLSX_2_XLSX(); #if HAVE_MORE_FONTS void testCustomColumnWidthExportXLSX(); #endif void testXfDefaultValuesXLSX(); void testODF13(); void testColumnWidthResaveXLSX(); #if HAVE_MORE_FONTS void testColumnWidthExportFromODStoXLSX(); #endif void testOutlineExportXLSX(); void testHiddenEmptyRowsXLSX(); void testHiddenEmptyColsODS(); void testAllRowsHiddenXLSX(); void testLandscapeOrientationXLSX(); void testInlineArrayXLS(); void testEmbeddedChartODS(); void testEmbeddedChartXLS(); void testCellAnchoredGroupXLS(); void testFormulaReferenceXLS(); void testSheetProtectionXLSX(); void testSheetProtectionXLSB(); void testCellBordersXLS(); void testCellBordersXLSX(); void testBordersExchangeXLSX(); void testTrackChangesSimpleXLSX(); void testSheetTabColorsXLSX(); void testTdf133487(); void testSharedFormulaExportXLS(); void testSharedFormulaExportXLSX(); void testSharedFormulaStringResultExportXLSX(); void testFunctionsExcel2010(sal_uLong nFormatType); void testFunctionsExcel2010XLSX(); void testFunctionsExcel2010XLS(); void testFunctionsExcel2010ODS(); void testCeilingFloor(sal_uLong nFormatType); void testCeilingFloorXLSX(); void testCeilingFloorODSToXLSX(); void testCeilingFloorXLS(); void testCeilingFloorODS(); void testCustomXml(); void testRelativePathsODS(); void testSheetProtectionODS(); void testSwappedOutImageExport(); void testLinkedGraphicRT(); void testImageWithSpecialID(); void testSupBookVirtualPathXLS(); void testAbsNamedRangeHTML(); void testTdf80149(); void testSheetLocalRangeNameXLS(); void testRelativeNamedExpressionsXLS(); void testSheetTextBoxHyperlinkXLSX(); void testFontSizeXLSX(); void testSheetCharacterKerningSpaceXLSX(); void testSheetCondensedCharacterSpaceXLSX(); void testTextUnderlineColorXLSX(); void testSheetRunParagraphPropertyXLSX(); void testHiddenShapeXLS(); void testHiddenShapeXLSX(); void testShapeAutofitXLSX(); void testHyperlinkXLSX(); void testMoveCellAnchoredShapesODS(); void testPreserveTextWhitespaceXLSX(); void testPreserveTextWhitespace2XLSX(); void testTdf113646(); void testDateStandardfilterXLSX(); CPPUNIT_TEST_SUITE(ScExportTest); CPPUNIT_TEST(test); CPPUNIT_TEST(testDefaultFontHeight); CPPUNIT_TEST(testTdf139167); CPPUNIT_TEST(testTdf113271); CPPUNIT_TEST(testTdf139394); CPPUNIT_TEST(testExtCondFormatXLSX); CPPUNIT_TEST(testTdf90104); CPPUNIT_TEST(testTdf111876); CPPUNIT_TEST(testPasswordExportODS); CPPUNIT_TEST(testTdf134332); CPPUNIT_TEST(testConditionalFormatExportODS); CPPUNIT_TEST(testCondFormatExportCellIs); CPPUNIT_TEST(testConditionalFormatExportXLSX); CPPUNIT_TEST(testTdf99856_dataValidationTest); CPPUNIT_TEST(testProtectionKeyODS_UTF16LErtlSHA1); CPPUNIT_TEST(testProtectionKeyODS_UTF8SHA1); CPPUNIT_TEST(testProtectionKeyODS_UTF8SHA256ODF12); CPPUNIT_TEST(testProtectionKeyODS_UTF8SHA256W3C); CPPUNIT_TEST(testProtectionKeyODS_XL_SHA1); CPPUNIT_TEST(testColorScaleExportODS); CPPUNIT_TEST(testColorScaleExportXLSX); CPPUNIT_TEST(testDataBarExportODS); CPPUNIT_TEST(testDataBarExportXLSX); CPPUNIT_TEST(testConditionalFormatRangeListXLSX); CPPUNIT_TEST(testConditionalFormatContainsTextXLSX); CPPUNIT_TEST(testConditionalFormatPriorityCheckXLSX); CPPUNIT_TEST(testConditionalFormatOriginXLSX); CPPUNIT_TEST(testMiscRowHeightExport); CPPUNIT_TEST(testNamedRangeBugfdo62729); CPPUNIT_TEST(testBuiltinRangesXLSX); CPPUNIT_TEST(testRichTextExportODS); CPPUNIT_TEST(testRichTextCellFormatXLSX); CPPUNIT_TEST(testFormulaRefSheetNameODS); CPPUNIT_TEST(testCellValuesExportODS); CPPUNIT_TEST(testCellNoteExportODS); CPPUNIT_TEST(testCellNoteExportXLS); CPPUNIT_TEST(testFormatExportODS); CPPUNIT_TEST(testCommentExportXLSX); CPPUNIT_TEST(testCommentExportXLSX_2_XLSX); #if HAVE_MORE_FONTS CPPUNIT_TEST(testCustomColumnWidthExportXLSX); #endif CPPUNIT_TEST(testXfDefaultValuesXLSX); CPPUNIT_TEST(testODF13); CPPUNIT_TEST(testColumnWidthResaveXLSX); #if HAVE_MORE_FONTS CPPUNIT_TEST(testColumnWidthExportFromODStoXLSX); #endif CPPUNIT_TEST(testOutlineExportXLSX); CPPUNIT_TEST(testHiddenEmptyRowsXLSX); CPPUNIT_TEST(testHiddenEmptyColsODS); CPPUNIT_TEST(testAllRowsHiddenXLSX); CPPUNIT_TEST(testLandscapeOrientationXLSX); CPPUNIT_TEST(testInlineArrayXLS); CPPUNIT_TEST(testEmbeddedChartODS); CPPUNIT_TEST(testEmbeddedChartXLS); CPPUNIT_TEST(testCellAnchoredGroupXLS); CPPUNIT_TEST(testFormulaReferenceXLS); CPPUNIT_TEST(testSheetProtectionXLSX); CPPUNIT_TEST(testSheetProtectionXLSB); CPPUNIT_TEST(testCellBordersXLS); CPPUNIT_TEST(testCellBordersXLSX); CPPUNIT_TEST(testBordersExchangeXLSX); CPPUNIT_TEST(testTrackChangesSimpleXLSX); CPPUNIT_TEST(testSheetTabColorsXLSX); CPPUNIT_TEST(testTdf133487); CPPUNIT_TEST(testSharedFormulaExportXLS); CPPUNIT_TEST(testSharedFormulaExportXLSX); CPPUNIT_TEST(testSharedFormulaStringResultExportXLSX); CPPUNIT_TEST(testFunctionsExcel2010XLSX); CPPUNIT_TEST(testFunctionsExcel2010XLS); CPPUNIT_TEST(testFunctionsExcel2010ODS); CPPUNIT_TEST(testCeilingFloorXLSX); CPPUNIT_TEST(testCeilingFloorODSToXLSX); CPPUNIT_TEST(testCeilingFloorXLS); CPPUNIT_TEST(testCeilingFloorODS); CPPUNIT_TEST(testCustomXml); CPPUNIT_TEST(testRelativePathsODS); CPPUNIT_TEST(testSheetProtectionODS); CPPUNIT_TEST(testSupBookVirtualPathXLS); CPPUNIT_TEST(testSwappedOutImageExport); CPPUNIT_TEST(testLinkedGraphicRT); CPPUNIT_TEST(testImageWithSpecialID); CPPUNIT_TEST(testPreserveTextWhitespaceXLSX); CPPUNIT_TEST(testPreserveTextWhitespace2XLSX); CPPUNIT_TEST(testAbsNamedRangeHTML); CPPUNIT_TEST(testTdf80149); CPPUNIT_TEST(testSheetLocalRangeNameXLS); CPPUNIT_TEST(testRelativeNamedExpressionsXLS); CPPUNIT_TEST(testSheetTextBoxHyperlinkXLSX); CPPUNIT_TEST(testFontSizeXLSX); CPPUNIT_TEST(testSheetCharacterKerningSpaceXLSX); CPPUNIT_TEST(testSheetCondensedCharacterSpaceXLSX); CPPUNIT_TEST(testTextUnderlineColorXLSX); CPPUNIT_TEST(testSheetRunParagraphPropertyXLSX); CPPUNIT_TEST(testHiddenShapeXLS); CPPUNIT_TEST(testHiddenShapeXLSX); CPPUNIT_TEST(testShapeAutofitXLSX); CPPUNIT_TEST(testHyperlinkXLSX); CPPUNIT_TEST(testMoveCellAnchoredShapesODS); CPPUNIT_TEST(testTdf113646); CPPUNIT_TEST(testDateStandardfilterXLSX); CPPUNIT_TEST_SUITE_END(); private: void testExcelCellBorders(sal_uLong nFormatType); uno::Reference m_xCalcComponent; }; void ScExportTest::registerNamespaces(xmlXPathContextPtr& pXmlXPathCtx) { XmlTestTools::registerOOXMLNamespaces(pXmlXPathCtx); XmlTestTools::registerODFNamespaces(pXmlXPathCtx); } void ScExportTest::test() { ScDocShell* pShell = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT | SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS | SfxModelFlags::DISABLE_DOCUMENT_RECOVERY); pShell->DoInitNew(); ScDocument& rDoc = pShell->GetDocument(); rDoc.SetValue(0, 0, 0, 1.0); ScDocShellRef xDocSh = saveAndReload(*pShell, FORMAT_ODS); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rLoadedDoc = xDocSh->GetDocument(); double aVal = rLoadedDoc.GetValue(0, 0, 0); ASSERT_DOUBLES_EQUAL(aVal, 1.0); xDocSh->DoClose(); } void ScExportTest::testDefaultFontHeight() { ScDocShellRef xDocSh = new ScDocShell; xDocSh->DoInitNew(); ScDocumentPool* pPool = xDocSh->GetDocument().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)); xDocSh = saveAndReload(*xDocSh, FORMAT_ODS); pPool = xDocSh->GetDocument().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()); xDocSh->DoClose(); } void ScExportTest::testTdf139167() { ScDocShellRef xShell = loadDoc(u"tdf139167.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xDocSh, FORMAT_XLSX); xmlDocUniquePtr pDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/styles.xml"); CPPUNIT_ASSERT(pDoc); assertXPath(pDoc, "/x:styleSheet/x:cellStyles", "count", "6"); assertXPath(pDoc, "/x:styleSheet/x:dxfs/x:dxf/x:fill/x:patternFill/x:bgColor", "rgb", "FFFFFF00"); xDocSh->DoClose(); } void ScExportTest::testTdf113271() { ScDocShellRef xShell = loadDoc(u"tdf113271.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xDocSh, FORMAT_XLSX); xmlDocUniquePtr pDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/styles.xml"); CPPUNIT_ASSERT(pDoc); assertXPath(pDoc, "/x:styleSheet/x:fonts", "count", "6"); // Without the fix in place, this test would have failed with // - Expected: FF000000 // - Actual : FFFFFFFF assertXPath(pDoc, "/x:styleSheet/x:fonts/x:font[1]/x:color", "rgb", "FF000000"); assertXPath(pDoc, "/x:styleSheet/x:fonts/x:font[1]/x:name", "val", "Calibri"); xDocSh->DoClose(); } void ScExportTest::testTdf139394() { ScDocShellRef xShell = loadDoc(u"tdf139394.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xDocSh, FORMAT_XLSX); xmlDocUniquePtr pDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/worksheets/sheet1.xml"); CPPUNIT_ASSERT(pDoc); assertXPathContent( pDoc, "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[1]/" "x14:cfRule/xm:f", "LEFT(A1,LEN(\"+\"))=\"+\""); assertXPathContent( pDoc, "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[2]/" "x14:cfRule/xm:f", "RIGHT(A2,LEN(\"-\"))=\"-\""); assertXPathContent( pDoc, "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[3]/" "x14:cfRule/xm:f", "LEFT(A3,LEN($B$3))=$B$3"); xDocSh->DoClose(); } void ScExportTest::testExtCondFormatXLSX() { ScDocShellRef xShell = loadDoc(u"tdf139021.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xDocSh, FORMAT_XLSX); xmlDocUniquePtr pDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/worksheets/sheet1.xml"); CPPUNIT_ASSERT(pDoc); assertXPath( pDoc, "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[1]/" "x14:cfRule", "type", "containsText"); assertXPathContent( pDoc, "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[1]/" "x14:cfRule/xm:f[1]", "NOT(ISERROR(SEARCH($B$1,A1)))"); assertXPathContent( pDoc, "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[1]/" "x14:cfRule/xm:f[2]", "$B$1"); assertXPath( pDoc, "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[2]/" "x14:cfRule", "type", "notContainsText"); assertXPathContent( pDoc, "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[2]/" "x14:cfRule/xm:f[1]", "ISERROR(SEARCH($B$2,A2))"); assertXPathContent( pDoc, "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[2]/" "x14:cfRule/xm:f[2]", "$B$2"); xDocSh->DoClose(); } void ScExportTest::testTdf90104() { ScDocShellRef xShell = loadDoc(u"tdf90104.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xDocSh, FORMAT_XLSX); xmlDocUniquePtr pDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/worksheets/sheet1.xml"); CPPUNIT_ASSERT(pDoc); assertXPathContent(pDoc, "/x:worksheet/x:dataValidations/x:dataValidation/mc:AlternateContent" "/mc:Choice/x12ac:list", "1,\"2,3\",4,\"5,6\""); assertXPathContent(pDoc, "/x:worksheet/x:dataValidations/x:dataValidation/mc:AlternateContent" "/mc:Fallback/x:formula1", "\"1,2,3,4,5,6\""); } void ScExportTest::testTdf111876() { // Document with relative path hyperlink ScDocShellRef xShell = loadDoc(u"tdf111876.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); xmlDocUniquePtr pDoc = XPathHelper::parseExport2( *this, *xDocSh, m_xSFactory, "xl/worksheets/_rels/sheet1.xml.rels", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); OUString sTarget = getXPath(pDoc, "/rels:Relationships/rels:Relationship", "Target"); // Document is saved to the temporary directory, relative path should be different than original one CPPUNIT_ASSERT(sTarget != "../xls/bug-fixes.xls"); xDocSh->DoClose(); } void ScExportTest::testPasswordExportODS() { ScDocShell* pShell = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT | SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS | SfxModelFlags::DISABLE_DOCUMENT_RECOVERY); pShell->DoInitNew(); ScDocument& rDoc = pShell->GetDocument(); rDoc.SetValue(0, 0, 0, 1.0); ScDocShellRef xDocSh = saveAndReloadPassword(*pShell, FORMAT_ODS); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rLoadedDoc = xDocSh->GetDocument(); double aVal = rLoadedDoc.GetValue(0, 0, 0); ASSERT_DOUBLES_EQUAL(aVal, 1.0); xDocSh->DoClose(); } void ScExportTest::testTdf134332() { ScDocShellRef xShell = loadDoc(u"tdf134332.", FORMAT_ODS); ScDocument& rDoc = xShell->GetDocument(); ASSERT_DOUBLES_EQUAL(190.0, rDoc.GetValue(ScAddress(0, 0, 0))); ASSERT_DOUBLES_EQUAL(238.0, rDoc.GetValue(ScAddress(0, 10144, 0))); ScDocShellRef xDocSh = saveAndReloadPassword(*xShell, FORMAT_ODS); // Without the fixes in place, it would have failed here CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rLoadedDoc = xDocSh->GetDocument(); ASSERT_DOUBLES_EQUAL(190.0, rLoadedDoc.GetValue(ScAddress(0, 0, 0))); ASSERT_DOUBLES_EQUAL(238.0, rLoadedDoc.GetValue(ScAddress(0, 10144, 0))); xDocSh->DoClose(); } void ScExportTest::testConditionalFormatExportODS() { ScDocShellRef xShell = loadDoc(u"new_cond_format_test_export.", FORMAT_ODS); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_ODS); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rDoc = xDocSh->GetDocument(); OUString aCSVPath; createCSVPath("new_cond_format_test_export.", aCSVPath); testCondFile(aCSVPath, &rDoc, 0); xDocSh->DoClose(); } void ScExportTest::testCondFormatExportCellIs() { ScDocShellRef xShell = loadDoc(u"condFormat_cellis.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rDoc = xDocSh->GetDocument(); CPPUNIT_ASSERT_EQUAL(size_t(1), rDoc.GetCondFormList(0)->size()); ScConditionalFormat* pFormat = rDoc.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(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(pEntry); CPPUNIT_ASSERT_EQUAL(ScConditionMode::Equal, pCondition->GetOperation()); aStr = pCondition->GetExpression(ScAddress(0, 0, 0), 0); CPPUNIT_ASSERT_EQUAL(OUString("$Sheet2.$A$1"), aStr); xDocSh->DoClose(); } void ScExportTest::testConditionalFormatExportXLSX() { ScDocShellRef xShell = loadDoc(u"new_cond_format_test_export.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rDoc = xDocSh->GetDocument(); { OUString aCSVPath; createCSVPath("new_cond_format_test_export.", aCSVPath); testCondFile(aCSVPath, &rDoc, 0); } { OUString aCSVPath; createCSVPath("new_cond_format_test_sheet2.", aCSVPath); testCondFile(aCSVPath, &rDoc, 1); } xDocSh->DoClose(); } void ScExportTest::testTdf99856_dataValidationTest() { ScDocShellRef xShell = loadDoc(u"tdf99856_dataValidationTest.", FORMAT_ODS); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT_MESSAGE("Failed to reload doc", xDocSh.is()); ScDocument& rDoc = xDocSh->GetDocument(); const ScValidationData* pData = rDoc.GetValidationEntry(2); CPPUNIT_ASSERT(pData); // Excel can't open corrupt file if the list is longer than 255 characters std::vector 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()); xDocSh->DoClose(); } void ScExportTest::testProtectionKeyODS_UTF16LErtlSHA1() { OUString const password("1012345678901234567890123456789012345678901234567890"); ScDocShellRef xShell = loadDoc(u"protection-key1.", FORMAT_FODS); ScDocument& rDoc = xShell->GetDocument(); ScDocProtection* const pDocProt(rDoc.GetDocProtection()); CPPUNIT_ASSERT(pDocProt->verifyPassword(password)); const ScTableProtection* const pTabProt(rDoc.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 std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_ODS); xmlDocUniquePtr pXmlDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, "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']"); 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']"); xShell->DoClose(); } void ScExportTest::testProtectionKeyODS_UTF8SHA1() { OUString const password("1012345678901234567890123456789012345678901234567890"); ScDocShellRef xShell = loadDoc(u"protection-key2.", FORMAT_FODS); ScDocument& rDoc = xShell->GetDocument(); ScDocProtection* const pDocProt(rDoc.GetDocProtection()); CPPUNIT_ASSERT(pDocProt->verifyPassword(password)); const ScTableProtection* const pTabProt(rDoc.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 std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_ODS); xmlDocUniquePtr pXmlDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, "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']"); 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']"); xShell->DoClose(); } void ScExportTest::testProtectionKeyODS_UTF8SHA256ODF12() { OUString const password("1012345678901234567890123456789012345678901234567890"); ScDocShellRef xShell = loadDoc(u"protection-key3.", FORMAT_FODS); ScDocument& rDoc = xShell->GetDocument(); ScDocProtection* const pDocProt(rDoc.GetDocProtection()); CPPUNIT_ASSERT(pDocProt->verifyPassword(password)); const ScTableProtection* const pTabProt(rDoc.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 std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_ODS); xmlDocUniquePtr pXmlDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, "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']"); 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']"); xShell->DoClose(); } void ScExportTest::testProtectionKeyODS_UTF8SHA256W3C() { OUString const password("1012345678901234567890123456789012345678901234567890"); ScDocShellRef xShell = loadDoc(u"protection-key4.", FORMAT_FODS); ScDocument& rDoc = xShell->GetDocument(); ScDocProtection* const pDocProt(rDoc.GetDocProtection()); CPPUNIT_ASSERT(pDocProt->verifyPassword(password)); const ScTableProtection* const pTabProt(rDoc.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 std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_ODS); xmlDocUniquePtr pXmlDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, "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']"); 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']"); xShell->DoClose(); } void ScExportTest::testProtectionKeyODS_XL_SHA1() { OUString const password("1012345678901234567890123456789012345678901234567890"); ScDocShellRef xShell = loadDoc(u"protection-key5.", FORMAT_FODS); ScDocument& rDoc = xShell->GetDocument(); ScDocProtection* const pDocProt(rDoc.GetDocProtection()); CPPUNIT_ASSERT(pDocProt->verifyPassword(password)); const ScTableProtection* const pTabProt(rDoc.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 std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_ODS); xmlDocUniquePtr pXmlDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, "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']"); 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']"); xShell->DoClose(); } void ScExportTest::testColorScaleExportODS() { ScDocShellRef xShell = loadDoc(u"colorscale.", FORMAT_ODS); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_ODS); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rDoc = xDocSh->GetDocument(); testColorScale2Entry_Impl(rDoc); testColorScale3Entry_Impl(rDoc); xDocSh->DoClose(); } void ScExportTest::testColorScaleExportXLSX() { ScDocShellRef xShell = loadDoc(u"colorscale.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rDoc = xDocSh->GetDocument(); testColorScale2Entry_Impl(rDoc); testColorScale3Entry_Impl(rDoc); xDocSh->DoClose(); } void ScExportTest::testDataBarExportODS() { ScDocShellRef xShell = loadDoc(u"databar.", FORMAT_ODS); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_ODS); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rDoc = xDocSh->GetDocument(); testDataBar_Impl(rDoc); xDocSh->DoClose(); } void ScExportTest::testFormatExportODS() { ScDocShellRef xShell = loadDoc(u"formats.", FORMAT_ODS); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_ODS); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rDoc = xDocSh->GetDocument(); testFormats(this, &rDoc, FORMAT_ODS); xDocSh->DoClose(); } void ScExportTest::testCommentExportXLSX() { //tdf#104729 FILESAVE OpenOffice do not save author of the comment during export to .xlsx ScDocShellRef xShell = loadDoc(u"comment.", FORMAT_ODS); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_XLSX); xmlDocUniquePtr pComments = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/comments1.xml"); CPPUNIT_ASSERT(pComments); assertXPathContent(pComments, "/x:comments/x:authors/x:author[1]", "BAKO"); assertXPath(pComments, "/x:comments/x:authors/x:author", 1); assertXPathContent(pComments, "/x:comments/x:commentList/x:comment/x:text/x:r/x:t", "Komentarz"); xmlDocUniquePtr pVmlDrawing = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/drawings/vmlDrawing1.vml"); CPPUNIT_ASSERT(pVmlDrawing); //assertXPath(pVmlDrawing, "/xml/v:shapetype", "coordsize", "21600,21600"); assertXPath(pVmlDrawing, "/xml/v:shapetype", "spt", "202"); assertXPath(pVmlDrawing, "/xml/v:shapetype/v:stroke", "joinstyle", "miter"); const OUString sShapeTypeId = "#" + getXPath(pVmlDrawing, "/xml/v:shapetype", "id"); assertXPath(pVmlDrawing, "/xml/v:shape", "type", sShapeTypeId); assertXPath(pVmlDrawing, "/xml/v:shape/v:shadow", "color", "black"); assertXPath(pVmlDrawing, "/xml/v:shape/v:shadow", "obscured", "t"); //tdf#117274 fix MSO interoperability with the secret VML shape type id assertXPath(pVmlDrawing, "/xml/v:shapetype", "id", "_x0000_t202"); assertXPath(pVmlDrawing, "/xml/v:shape", "type", "#_x0000_t202"); xShell->DoClose(); } void ScExportTest::testCommentExportXLSX_2_XLSX() { //tdf#117287 FILESAVE XLSX: Comments always disappear after opening the exported XLSX file with Excel ScDocShellRef xShell = loadDoc(u"tdf117287_comment.", FORMAT_XLSX); ScDocument& rDoc = xShell->GetDocument(); ScAddress aPosC9(2, 8, 0); ScPostIt* pNote = rDoc.GetNote(aPosC9); CPPUNIT_ASSERT(pNote); CPPUNIT_ASSERT(!pNote->IsCaptionShown()); pNote->ShowCaption(aPosC9, true); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_XLSX); xmlDocUniquePtr pComments = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/comments1.xml"); CPPUNIT_ASSERT(pComments); assertXPathContent(pComments, "/x:comments/x:commentList/x:comment/x:text/x:r/x:t", "visible comment"); xmlDocUniquePtr pVmlDrawing = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/drawings/vmlDrawing1.vml"); CPPUNIT_ASSERT(pVmlDrawing); assertXPath(pVmlDrawing, "/xml/v:shape/x:ClientData/x:Visible", 0); xShell->DoClose(); } #if HAVE_MORE_FONTS void ScExportTest::testCustomColumnWidthExportXLSX() { //tdf#100946 FILESAVE Excel on macOS ignored column widths in XLSX last saved by LO ScDocShellRef xShell = loadDoc(u"custom_column_width.", FORMAT_ODS); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_XLSX); xmlDocUniquePtr pSheet = XPathHelper::parseExport(pXPathFile, m_xSFactory, "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", "defaultColWidth").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]", "hidden", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]", "outlineLevel", "0"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]", "customWidth", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]", "min", "2"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]", "max", "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]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]", "outlineLevel", "0"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]", "customWidth", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]", "min", "4"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]", "max", "4"); // 5th column has custom width. Columns from 4 to 7 are hidden assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]", "outlineLevel", "0"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]", "customWidth", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]", "min", "5"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]", "max", "5"); // 6th and 7th columns have default width and they are hidden assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]", "outlineLevel", "0"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]", "customWidth", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]", "min", "6"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]", "max", "7"); // 8th column has everything default - skipped // 9th column has custom width assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]", "hidden", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]", "outlineLevel", "0"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]", "customWidth", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]", "min", "9"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]", "max", "9"); // We expected that exactly 5 unique Nodes will be produced assertXPath(pSheet, "/x:worksheet/x:cols/x:col", 5); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]", "hidden", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]", "outlineLevel", "0"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]", "customFormat", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]", "customHeight", "false"); xShell->DoClose(); } #endif void ScExportTest::testXfDefaultValuesXLSX() { //tdf#70565 FORMATTING: User Defined Custom Formatting is not applied during importing XLSX documents ScDocShellRef xShell = loadDoc(u"xf_default_values.", FORMAT_XLSX); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_XLSX); xmlDocUniquePtr pSheet = XPathHelper::parseExport(pXPathFile, m_xSFactory, "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]", "xfId"); // 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]", "xfId", "0"); assertXPath(pSheet, "/x:styleSheet/x:cellXfs/x:xf[2]", "xfId", "0"); assertXPath(pSheet, "/x:styleSheet/x:cellXfs/x:xf[3]", "xfId", "0"); assertXPath(pSheet, "/x:styleSheet/x:cellXfs/x:xf[4]", "xfId", "0"); // We expected that exactly 15 cellXfs:xf Nodes will be produced assertXPath(pSheet, "/x:styleSheet/x:cellXfs/x:xf", 14); xShell->DoClose(); } namespace { // TODO where to put this? class Resetter { private: std::function m_Func; public: Resetter(std::function const& rFunc) : m_Func(rFunc) { } ~Resetter() { try { m_Func(); } catch (...) // has to be reliable { fprintf(stderr, "resetter failed with exception\n"); abort(); } } }; } // namespace static auto verifySpreadsheet13(char const* const pTestName, ScDocShellRef& pShell) -> void { ScDocument const& rDoc(pShell->GetDocument()); // 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()); } void ScExportTest::testODF13() { // import ScDocShellRef pShell = loadDoc(u"spreadsheet13e.", FORMAT_ODS); // check model verifySpreadsheet13("import", pShell); Resetter _([]() { std::shared_ptr pBatch( comphelper::ConfigurationChanges::create()); officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch); return pBatch->commit(); }); { // export ODF 1.3 std::shared_ptr pBatch( comphelper::ConfigurationChanges::create()); officecfg::Office::Common::Save::ODF::DefaultVersion::set(10, pBatch); pBatch->commit(); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*pShell, FORMAT_ODS); // check XML xmlDocUniquePtr pContentXml = XPathHelper::parseExport(pXPathFile, m_xSFactory, "content.xml"); assertXPath(pContentXml, "/office:document-content/office:automatic-styles/style:style/" "style:table-properties[@table:tab-color='#ff3838']"); xmlDocUniquePtr pStylesXml = XPathHelper::parseExport(pXPathFile, m_xSFactory, "styles.xml"); assertXPath(pStylesXml, "/office:document-styles/office:automatic-styles/style:page-layout/" "style:page-layout-properties[@style:scale-to-X='2']"); assertXPath(pStylesXml, "/office:document-styles/office:automatic-styles/style:page-layout/" "style:page-layout-properties[@style:scale-to-Y='3']"); // reload pShell = load(pXPathFile->GetURL(), "calc8", OUString(), OUString(), ODS_FORMAT_TYPE, SotClipboardFormatId::STARCALC_8); // check model verifySpreadsheet13("1.3 reload", pShell); } { // export ODF 1.2 Extended std::shared_ptr pBatch( comphelper::ConfigurationChanges::create()); officecfg::Office::Common::Save::ODF::DefaultVersion::set(9, pBatch); pBatch->commit(); std::shared_ptr pXPathFile = exportTo(*pShell, FORMAT_ODS, /*bValidate*/ false); pShell->DoClose(); // check XML xmlDocUniquePtr pContentXml = XPathHelper::parseExport(pXPathFile, m_xSFactory, "content.xml"); assertXPath(pContentXml, "/office:document-content/office:automatic-styles/style:style/" "style:table-properties[@tableooo:tab-color='#ff3838']"); xmlDocUniquePtr pStylesXml = XPathHelper::parseExport(pXPathFile, m_xSFactory, "styles.xml"); assertXPath(pStylesXml, "/office:document-styles/office:automatic-styles/style:page-layout/" "style:page-layout-properties[@loext:scale-to-X='2']"); assertXPath(pStylesXml, "/office:document-styles/office:automatic-styles/style:page-layout/" "style:page-layout-properties[@loext:scale-to-Y='3']"); // reload pShell = load(pXPathFile->GetURL(), "calc8", OUString(), OUString(), ODS_FORMAT_TYPE, SotClipboardFormatId::STARCALC_8); // check model verifySpreadsheet13("1.2 Extended reload", pShell); } { // export ODF 1.2 std::shared_ptr pBatch( comphelper::ConfigurationChanges::create()); officecfg::Office::Common::Save::ODF::DefaultVersion::set(4, pBatch); pBatch->commit(); std::shared_ptr pXPathFile = exportTo(*pShell, FORMAT_ODS); pShell->DoClose(); // check XML xmlDocUniquePtr pContentXml = XPathHelper::parseExport(pXPathFile, m_xSFactory, "content.xml"); assertXPathNoAttribute( pContentXml, "/office:document-content/office:automatic-styles/style:style/style:table-properties", "tab-color"); xmlDocUniquePtr pStylesXml = XPathHelper::parseExport(pXPathFile, m_xSFactory, "styles.xml"); assertXPathNoAttribute(pStylesXml, "/office:document-styles/office:automatic-styles/" "style:page-layout[1]/style:page-layout-properties", "scale-to-X"); assertXPathNoAttribute(pStylesXml, "/office:document-styles/office:automatic-styles/" "style:page-layout[1]/style:page-layout-properties", "scale-to-Y"); // don't reload - no point } } void 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 ScDocShellRef xShell = loadDoc(u"different-column-width-excel2010.", FORMAT_XLSX); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_XLSX); xmlDocUniquePtr pSheet = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/worksheets/sheet1.xml"); CPPUNIT_ASSERT(pSheet); // In original Excel document the width is "24" assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]", "width", "24"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]", "customWidth", "true"); // In original Excel document the width is "12" assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]", "width", "12"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]", "customWidth", "true"); // In original Excel document the width is "6" assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]", "width", "6"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]", "customWidth", "true"); // In original Excel document the width is "1" assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]", "width", "1"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]", "customWidth", "true"); // In original Excel document the width is "250" assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]", "width", "250"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]", "customWidth", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col", 5); xShell->DoClose(); } #if HAVE_MORE_FONTS void 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 ScDocShellRef xShell = loadDoc(u"different-column-width.", FORMAT_ODS); ScDocument& rOdsDoc = xShell->GetDocument(); // Col 1, Tab 0 (Column width 2.00 in) sal_uInt16 nExpectedColumn0Width = rOdsDoc.GetColWidth(static_cast(0), static_cast(0), false); CPPUNIT_ASSERT_EQUAL(static_cast(2880), nExpectedColumn0Width); // Col 2, Tab 0 (Column width 1.00 in) sal_uInt16 nExpectedColumn1Width = rOdsDoc.GetColWidth(static_cast(1), static_cast(0), false); CPPUNIT_ASSERT_EQUAL(static_cast(1440), nExpectedColumn1Width); // Col 3, Tab 0 (Column width 0.50 in) sal_uInt16 nExpectedColumn2Width = rOdsDoc.GetColWidth(static_cast(2), static_cast(0), false); CPPUNIT_ASSERT_EQUAL(static_cast(720), nExpectedColumn2Width); // Col 4, Tab 0 (Column width 0.25 in) sal_uInt16 nExpectedColumn3Width = rOdsDoc.GetColWidth(static_cast(3), static_cast(0), false); CPPUNIT_ASSERT_EQUAL(static_cast(360), nExpectedColumn3Width); // Col 5, Tab 0 (Column width 13.57 in) sal_uInt16 nExpectedColumn4Width = rOdsDoc.GetColWidth(static_cast(4), static_cast(0), false); CPPUNIT_ASSERT_EQUAL(static_cast(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 ScDocShellRef xXlsxDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xXlsxDocSh.is()); ScDocument& rDoc = xXlsxDocSh->GetDocument(); // Col 1, Tab 0 sal_uInt16 nCalcWidth; nCalcWidth = rDoc.GetColWidth(static_cast(0), static_cast(0), false); CPPUNIT_ASSERT_EQUAL(nExpectedColumn0Width, nCalcWidth); // Col 2, Tab 0 nCalcWidth = rDoc.GetColWidth(static_cast(1), static_cast(0), false); CPPUNIT_ASSERT_EQUAL(nExpectedColumn1Width, nCalcWidth); // Col 3, Tab 0 nCalcWidth = rDoc.GetColWidth(static_cast(2), static_cast(0), false); CPPUNIT_ASSERT_EQUAL(nExpectedColumn2Width, nCalcWidth); // Col 4, Tab 0 nCalcWidth = rDoc.GetColWidth(static_cast(3), static_cast(0), false); CPPUNIT_ASSERT_EQUAL(nExpectedColumn3Width, nCalcWidth); // Col 5, Tab 0 nCalcWidth = rDoc.GetColWidth(static_cast(4), static_cast(0), false); CPPUNIT_ASSERT_EQUAL(nExpectedColumn4Width, nCalcWidth); xXlsxDocSh->DoClose(); } #endif void 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 ScDocShellRef xShell = loadDoc(u"outline.", FORMAT_ODS); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_XLSX); xmlDocUniquePtr pSheet = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/worksheets/sheet1.xml"); CPPUNIT_ASSERT(pSheet); // Maximum Outline Row is 4 for this document assertXPath(pSheet, "/x:worksheet/x:sheetFormatPr", "outlineLevelRow", "4"); // Maximum Outline Column is 4 for this document assertXPath(pSheet, "/x:worksheet/x:sheetFormatPr", "outlineLevelCol", "4"); // First XML node, creates two columns (from min=1 to max=2) assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]", "hidden", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]", "outlineLevel", "1"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]", "min", "1"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]", "max", "2"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]", "outlineLevel", "2"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]", "min", "3"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]", "max", "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]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]", "outlineLevel", "2"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]", "min", "4"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]", "max", "4"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]", "outlineLevel", "3"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]", "min", "5"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]", "max", "6"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]", "outlineLevel", "4"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]", "min", "7"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]", "max", "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]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[6]", "outlineLevel", "4"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[6]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[6]", "min", "8"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[6]", "max", "8"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[7]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[7]", "outlineLevel", "4"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[7]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[7]", "min", "9"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[7]", "max", "19"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[8]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[8]", "outlineLevel", "3"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[8]", "collapsed", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[8]", "min", "20"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[8]", "max", "20"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[9]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[9]", "outlineLevel", "3"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[9]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[9]", "min", "21"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[9]", "max", "21"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[10]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[10]", "outlineLevel", "2"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[10]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[10]", "min", "22"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[10]", "max", "23"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[11]", "hidden", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[11]", "outlineLevel", "1"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[11]", "collapsed", "true"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[11]", "min", "24"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[11]", "max", "24"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[12]", "hidden", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[12]", "outlineLevel", "1"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[12]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[12]", "min", "25"); assertXPath(pSheet, "/x:worksheet/x:cols/x:col[12]", "max", "26"); // We expected that exactly 12 unique Nodes will be produced assertXPath(pSheet, "/x:worksheet/x:cols/x:col", 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]", "r", "2"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]", "hidden", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]", "outlineLevel", "1"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[2]", "r", "3"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[2]", "hidden", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[2]", "outlineLevel", "2"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[2]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[3]", "r", "4"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[3]", "hidden", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[3]", "outlineLevel", "2"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[3]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[4]", "r", "5"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[4]", "hidden", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[4]", "outlineLevel", "3"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[4]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[5]", "r", "6"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[5]", "hidden", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[5]", "outlineLevel", "3"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[5]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[6]", "r", "7"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[6]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[6]", "outlineLevel", "4"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[6]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[7]", "r", "8"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[7]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[7]", "outlineLevel", "4"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[7]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[8]", "r", "9"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[8]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[8]", "outlineLevel", "4"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[8]", "collapsed", "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]", "r", "21"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[20]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[20]", "outlineLevel", "4"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[20]", "collapsed", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[21]", "r", "22"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[21]", "hidden", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[21]", "outlineLevel", "3"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[21]", "collapsed", "true"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[22]", "r", "23"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[22]", "hidden", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[22]", "outlineLevel", "3"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[22]", "collapsed", "false"); // We expected that exactly 29 Row Nodes will be produced assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row", 29); xShell->DoClose(); } void ScExportTest::testAllRowsHiddenXLSX() { ScDocShellRef xOrigDocSh = loadDoc(u"tdf105840_allRowsHidden.", FORMAT_XLSX); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xOrigDocSh, FORMAT_XLSX); xmlDocUniquePtr pSheet = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/worksheets/sheet1.xml"); CPPUNIT_ASSERT(pSheet); assertXPath(pSheet, "/x:worksheet/x:sheetFormatPr", "zeroHeight", "true"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row", 0); xOrigDocSh->DoClose(); } void ScExportTest::testHiddenEmptyRowsXLSX() { //tdf#98106 FILESAVE: Hidden and empty rows became visible when export to .XLSX ScDocShellRef xShell = loadDoc(u"hidden-empty-rows.", FORMAT_ODS); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_XLSX); xmlDocUniquePtr pSheet = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/worksheets/sheet1.xml"); CPPUNIT_ASSERT(pSheet); assertXPath(pSheet, "/x:worksheet/x:sheetFormatPr", "zeroHeight", "false"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[2]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[3]", "hidden", "true"); assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[4]", "hidden", "false"); xShell->DoClose(); } void ScExportTest::testHiddenEmptyColsODS() { //tdf#98106 FILESAVE: Hidden and empty rows became visible when export to .XLSX ScDocShellRef xShell = loadDoc(u"tdf128895_emptyHiddenCols.", FORMAT_ODS); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_ODS); xmlDocUniquePtr pSheet = XPathHelper::parseExport(pXPathFile, m_xSFactory, "content.xml"); CPPUNIT_ASSERT(pSheet); assertXPath(pSheet, "//table:table/table:table-column[2]"); assertXPath(pSheet, "//table:table/table:table-column[2]", "number-columns-repeated", "1017"); xShell->DoClose(); } void ScExportTest::testLandscapeOrientationXLSX() { //tdf#48767 - Landscape page orientation is not loaded from .xlsx format with MS Excel, after export with Libre Office ScDocShellRef xShell = loadDoc(u"hidden-empty-rows.", FORMAT_ODS); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_XLSX); xmlDocUniquePtr pSheet = XPathHelper::parseExport(pXPathFile, m_xSFactory, "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", "usePrinterDefaults"); assertXPath(pSheet, "/x:worksheet/x:pageSetup", "orientation", "landscape"); xShell->DoClose(); } void ScExportTest::testDataBarExportXLSX() { ScDocShellRef xShell = loadDoc(u"databar.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rDoc = xDocSh->GetDocument(); testDataBar_Impl(rDoc); xDocSh->DoClose(); } void 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. { "miscrowheights.", FORMAT_XLSX, FORMAT_XLSX, SAL_N_ELEMENTS(DfltRowData), DfltRowData }, // Checks that some distributed ( non-empty ) heights remain set after export (to xls) { "miscrowheights.", FORMAT_XLSX, FORMAT_XLS, SAL_N_ELEMENTS(DfltRowData), DfltRowData }, // Checks that repreated rows ( of various heights ) remain set after export ( to xlsx ) { "miscemptyrepeatedrowheights.", FORMAT_ODS, FORMAT_XLSX, SAL_N_ELEMENTS(EmptyRepeatRowData), EmptyRepeatRowData }, // Checks that repreated rows ( of various heights ) remain set after export ( to xls ) { "miscemptyrepeatedrowheights.", FORMAT_ODS, FORMAT_XLS, 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); } } void ScExportTest::testNamedRangeBugfdo62729() { ScDocShellRef xShell = loadDoc(u"fdo62729.", FORMAT_ODS); ScDocument& rDoc = xShell->GetDocument(); ScRangeName* pNames = rDoc.GetRangeName(); //should be just a single named range CPPUNIT_ASSERT_EQUAL(size_t(1), pNames->size()); rDoc.DeleteTab(0); //should be still a single named range CPPUNIT_ASSERT_EQUAL(size_t(1), pNames->size()); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_ODS); xShell->DoClose(); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rDoc2 = xDocSh->GetDocument(); pNames = rDoc2.GetRangeName(); //after reload should still have a named range CPPUNIT_ASSERT_EQUAL(size_t(1), pNames->size()); xDocSh->DoClose(); } void ScExportTest::testBuiltinRangesXLSX() { ScDocShellRef xShell = loadDoc(u"built-in_ranges.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); xShell->DoClose(); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/workbook.xml", FORMAT_XLSX); 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']", "'Sheet1 Test'!$A$1:$A$5"); assertXPathContent(pDoc, "/x:workbook/x:definedNames/" "x:definedName[@name='_xlnm._FilterDatabase'][@localSheetId='1']", "'Sheet2 Test'!$K$10:$K$14"); assertXPathContent( pDoc, "/x:workbook/x:definedNames/x:definedName[@name='_xlnm.Print_Area'][@localSheetId='0']", "'Sheet1 Test'!$A$1:$A$5"); assertXPathContent( pDoc, "/x:workbook/x:definedNames/x:definedName[@name='_xlnm.Print_Area'][@localSheetId='1']", "'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']", 0); assertXPath(pDoc, "/x:workbook/x:definedNames/" "x:definedName[@name='_xlnm._FilterDatabase_0'][@localSheetId='1']", 0); assertXPath( pDoc, "/x:workbook/x:definedNames/x:definedName[@name='_xlnm.Print_Area_0'][@localSheetId='0']", 0); assertXPath( pDoc, "/x:workbook/x:definedNames/x:definedName[@name='_xlnm.Print_Area_0'][@localSheetId='1']", 0); xDocSh->DoClose(); } void 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(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(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(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(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(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(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(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(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 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 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 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 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 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 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. ScDocShellRef xOrigDocSh = loadEmptyDocument(); CPPUNIT_ASSERT(xOrigDocSh); const EditTextObject* pEditText; { ScDocument& rDoc = xOrigDocSh->GetDocument(); CPPUNIT_ASSERT_MESSAGE("This document should at least have one sheet.", rDoc.GetTableCount() > 0); // Insert an edit text cell. ScFieldEditEngine* pEE = &rDoc.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. rDoc.SetEditText(ScAddress(1, 1, 0), pEE->CreateTextObject()); pEditText = rDoc.GetEditText(ScAddress(1, 1, 0)); CPPUNIT_ASSERT_MESSAGE("Incorrect B2 value.", aCheckFunc.checkB2(pEditText)); } // Now, save and reload this document. ScDocShellRef xNewDocSh = saveAndReload(*xOrigDocSh, FORMAT_ODS); { xOrigDocSh->DoClose(); CPPUNIT_ASSERT(xNewDocSh.is()); ScDocument& rDoc2 = xNewDocSh->GetDocument(); CPPUNIT_ASSERT_MESSAGE("Reloaded document should at least have one sheet.", rDoc2.GetTableCount() > 0); ScFieldEditEngine* pEE = &rDoc2.GetEditEngine(); // 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"); rDoc2.SetEditText(ScAddress(1, 3, 0), pEE->CreateTextObject()); pEditText = rDoc2.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. ScDocShellRef xNewDocSh2 = saveAndReload(*xNewDocSh, FORMAT_ODS); { ScDocument& rDoc3 = xNewDocSh2->GetDocument(); ScFieldEditEngine* pEE = &rDoc3.GetEditEngine(); xNewDocSh->DoClose(); pEditText = rDoc3.GetEditText(ScAddress(1, 1, 0)); CPPUNIT_ASSERT_MESSAGE("B2 should be an edit text.", pEditText); pEditText = rDoc3.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"); rDoc3.SetEditText(ScAddress(1, 4, 0), pEE->CreateTextObject()); pEditText = rDoc3.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); rDoc3.SetEditText(ScAddress(1, 5, 0), pEE->CreateTextObject()); pEditText = rDoc3.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"); rDoc3.SetEditText(ScAddress(1, 6, 0), pEE->CreateTextObject()); pEditText = rDoc3.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); rDoc3.SetEditText(ScAddress(1, 7, 0), pEE->CreateTextObject()); pEditText = rDoc3.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); rDoc3.SetEditText(ScAddress(1, 8, 0), pEE->CreateTextObject()); pEditText = rDoc3.GetEditText(ScAddress(1, 8, 0)); CPPUNIT_ASSERT_MESSAGE("Incorrect B9 value.", aCheckFunc.checkB9(pEditText)); ScPatternAttr aCellFontColor(rDoc3.GetPool()); aCellFontColor.GetItemSet().Put(SvxColorItem(COL_BLUE, ATTR_FONT_COLOR)); // Set font color of B10 to blue. rDoc3.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); rDoc3.SetEditText(ScAddress(1, 9, 0), pEE->CreateTextObject()); pEditText = rDoc3.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. ScDocShellRef xNewDocSh3 = saveAndReload(*xNewDocSh2, FORMAT_ODS); ScDocument& rDoc4 = xNewDocSh3->GetDocument(); xNewDocSh2->DoClose(); pEditText = rDoc4.GetEditText(ScAddress(1, 1, 0)); CPPUNIT_ASSERT_MESSAGE("Incorrect B2 value after save and reload.", aCheckFunc.checkB2(pEditText)); pEditText = rDoc4.GetEditText(ScAddress(1, 3, 0)); CPPUNIT_ASSERT_MESSAGE("Incorrect B4 value after save and reload.", aCheckFunc.checkB4(pEditText)); pEditText = rDoc4.GetEditText(ScAddress(1, 4, 0)); CPPUNIT_ASSERT_MESSAGE("Incorrect B5 value after save and reload.", aCheckFunc.checkB5(pEditText)); pEditText = rDoc4.GetEditText(ScAddress(1, 5, 0)); CPPUNIT_ASSERT_MESSAGE("Incorrect B6 value after save and reload.", aCheckFunc.checkB6(pEditText)); pEditText = rDoc4.GetEditText(ScAddress(1, 6, 0)); CPPUNIT_ASSERT_MESSAGE("Incorrect B7 value after save and reload.", aCheckFunc.checkB7(pEditText)); pEditText = rDoc4.GetEditText(ScAddress(1, 7, 0)); CPPUNIT_ASSERT_MESSAGE("Incorrect B8 value after save and reload.", aCheckFunc.checkB8(pEditText)); pEditText = rDoc4.GetEditText(ScAddress(1, 9, 0)); CPPUNIT_ASSERT_MESSAGE("Incorrect B10 value after save and reload.", aCheckFunc.checkB10(pEditText)); xNewDocSh3->DoClose(); } void ScExportTest::testRichTextCellFormatXLSX() { ScDocShellRef xDocSh = loadDoc(u"cellformat.", FORMAT_XLS); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xDocSh, FORMAT_XLSX); xmlDocUniquePtr pSheet = XPathHelper::parseExport(pXPathFile, m_xSFactory, "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", "s"); CPPUNIT_ASSERT_MESSAGE("Cell format is missing", !aCellFormat.isEmpty()); xmlDocUniquePtr pStyles = XPathHelper::parseExport(pXPathFile, m_xSFactory, "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", "true"); // see what font it references const OString aXPath2("/x:styleSheet/x:cellXfs/x:xf[" + nFormatIdx + "]"); OUString aFontId = getXPath(pStyles, aXPath2, "fontId"); 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", "true"); xDocSh->DoClose(); } void ScExportTest::testFormulaRefSheetNameODS() { ScDocShellRef xDocSh = loadDoc(u"formula-quote-in-sheet-name.", FORMAT_ODS, true); { ScDocument& rDoc = xDocSh->GetDocument(); sc::AutoCalcSwitch aACSwitch(rDoc, true); // turn on auto calc. rDoc.SetString(ScAddress(1, 1, 0), "='90''s Data'.B2"); CPPUNIT_ASSERT_EQUAL(1.1, rDoc.GetValue(ScAddress(1, 1, 0))); ASSERT_FORMULA_EQUAL(rDoc, ScAddress(1, 1, 0), "'90''s Data'.B2", "Wrong formula"); } // Now, save and reload this document. ScDocShellRef xNewDocSh = saveAndReload(*xDocSh, FORMAT_ODS); xDocSh->DoClose(); ScDocument& rDoc = xNewDocSh->GetDocument(); rDoc.CalcAll(); CPPUNIT_ASSERT_EQUAL(1.1, rDoc.GetValue(ScAddress(1, 1, 0))); ASSERT_FORMULA_EQUAL(rDoc, ScAddress(1, 1, 0), "'90''s Data'.B2", "Wrong formula"); xNewDocSh->DoClose(); } void ScExportTest::testCellValuesExportODS() { // Start with an empty document ScDocShellRef xOrigDocSh = loadEmptyDocument(); CPPUNIT_ASSERT(xOrigDocSh); { ScDocument& rDoc = xOrigDocSh->GetDocument(); CPPUNIT_ASSERT_MESSAGE("This document should at least have one sheet.", rDoc.GetTableCount() > 0); // set a value double rDoc.SetValue(ScAddress(0, 0, 0), 2.0); // A1 // set a formula rDoc.SetValue(ScAddress(2, 0, 0), 3.0); // C1 rDoc.SetValue(ScAddress(3, 0, 0), 3); // D1 rDoc.SetString(ScAddress(4, 0, 0), "=10*C1/4"); // E1 rDoc.SetValue(ScAddress(5, 0, 0), 3.0); // F1 rDoc.SetString(ScAddress(7, 0, 0), "=SUM(C1:F1)"); //H1 // set a string rDoc.SetString(ScAddress(0, 2, 0), "a simple line"); //A3 // set a digit string rDoc.SetString(ScAddress(0, 4, 0), "'12"); //A5 // set a contiguous value rDoc.SetValue(ScAddress(0, 5, 0), 12.0); //A6 // set a contiguous string rDoc.SetString(ScAddress(0, 6, 0), "a string"); //A7 // set a contiguous formula rDoc.SetString(ScAddress(0, 7, 0), "=$A$6"); //A8 } // save and reload ScDocShellRef xNewDocSh = saveAndReload(*xOrigDocSh, FORMAT_ODS); xOrigDocSh->DoClose(); CPPUNIT_ASSERT(xNewDocSh.is()); ScDocument& rDoc = xNewDocSh->GetDocument(); CPPUNIT_ASSERT_MESSAGE("Reloaded document should at least have one sheet.", rDoc.GetTableCount() > 0); // check value CPPUNIT_ASSERT_EQUAL(2.0, rDoc.GetValue(0, 0, 0)); CPPUNIT_ASSERT_EQUAL(3.0, rDoc.GetValue(2, 0, 0)); CPPUNIT_ASSERT_EQUAL(3.0, rDoc.GetValue(3, 0, 0)); CPPUNIT_ASSERT_EQUAL(7.5, rDoc.GetValue(4, 0, 0)); CPPUNIT_ASSERT_EQUAL(3.0, rDoc.GetValue(5, 0, 0)); // check formula ASSERT_FORMULA_EQUAL(rDoc, ScAddress(4, 0, 0), "10*C1/4", "Wrong formula =10*C1/4"); ASSERT_FORMULA_EQUAL(rDoc, ScAddress(7, 0, 0), "SUM(C1:F1)", "Wrong formula =SUM(C1:F1)"); CPPUNIT_ASSERT_EQUAL(16.5, rDoc.GetValue(7, 0, 0)); // check string ScRefCellValue aCell; aCell.assign(rDoc, ScAddress(0, 2, 0)); CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, aCell.meType); // check for an empty cell aCell.assign(rDoc, ScAddress(0, 3, 0)); CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, aCell.meType); // check a digit string aCell.assign(rDoc, ScAddress(0, 4, 0)); CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, aCell.meType); //check contiguous values CPPUNIT_ASSERT_EQUAL(12.0, rDoc.GetValue(0, 5, 0)); CPPUNIT_ASSERT_EQUAL(OUString("a string"), rDoc.GetString(0, 6, 0)); ASSERT_FORMULA_EQUAL(rDoc, ScAddress(0, 7, 0), "$A$6", "Wrong formula =$A$6"); CPPUNIT_ASSERT_EQUAL(rDoc.GetValue(0, 5, 0), rDoc.GetValue(0, 7, 0)); xNewDocSh->DoClose(); } void ScExportTest::testCellNoteExportODS() { ScDocShellRef xOrigDocSh = loadDoc(u"single-note.", FORMAT_ODS); ScAddress aPos(0, 0, 0); // Start with A1. { ScDocument& rDoc = xOrigDocSh->GetDocument(); CPPUNIT_ASSERT_MESSAGE("There should be a note at A1.", rDoc.HasNote(aPos)); aPos.IncRow(); // Move to A2. ScPostIt* pNote = rDoc.GetOrCreateNote(aPos); pNote->SetText(aPos, "Note One"); pNote->SetAuthor("Author One"); CPPUNIT_ASSERT_MESSAGE("There should be a note at A2.", rDoc.HasNote(aPos)); } // save and reload ScDocShellRef xNewDocSh = saveAndReload(*xOrigDocSh, FORMAT_ODS); xOrigDocSh->DoClose(); CPPUNIT_ASSERT(xNewDocSh.is()); ScDocument& rDoc = xNewDocSh->GetDocument(); aPos.SetRow(0); // Move back to A1. CPPUNIT_ASSERT_MESSAGE("There should be a note at A1.", rDoc.HasNote(aPos)); aPos.IncRow(); // Move to A2. CPPUNIT_ASSERT_MESSAGE("There should be a note at A2.", rDoc.HasNote(aPos)); xNewDocSh->DoClose(); } void ScExportTest::testCellNoteExportXLS() { // Start with an empty document.s ScDocShellRef xOrigDocSh = loadDoc(u"notes-on-3-sheets.", FORMAT_ODS); { ScDocument& rDoc = xOrigDocSh->GetDocument(); CPPUNIT_ASSERT_EQUAL_MESSAGE("This document should have 3 sheets.", SCTAB(3), rDoc.GetTableCount()); // Check note's presence. CPPUNIT_ASSERT(rDoc.HasNote(ScAddress(0, 0, 0))); CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0, 1, 0))); CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0, 2, 0))); CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0, 0, 1))); CPPUNIT_ASSERT(rDoc.HasNote(ScAddress(0, 1, 1))); CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0, 2, 1))); CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0, 0, 2))); CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0, 1, 2))); CPPUNIT_ASSERT(rDoc.HasNote(ScAddress(0, 2, 2))); } // save and reload as XLS. ScDocShellRef xNewDocSh = saveAndReload(*xOrigDocSh, FORMAT_XLS); { xOrigDocSh->DoClose(); CPPUNIT_ASSERT(xNewDocSh.is()); ScDocument& rDoc = xNewDocSh->GetDocument(); CPPUNIT_ASSERT_EQUAL_MESSAGE("This document should have 3 sheets.", SCTAB(3), rDoc.GetTableCount()); // Check note's presence again. CPPUNIT_ASSERT(rDoc.HasNote(ScAddress(0, 0, 0))); CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0, 1, 0))); CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0, 2, 0))); CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0, 0, 1))); CPPUNIT_ASSERT(rDoc.HasNote(ScAddress(0, 1, 1))); CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0, 2, 1))); CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0, 0, 2))); CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0, 1, 2))); CPPUNIT_ASSERT(rDoc.HasNote(ScAddress(0, 2, 2))); xNewDocSh->DoClose(); } } 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); } } } } void ScExportTest::testInlineArrayXLS() { ScDocShellRef xShell = loadDoc(u"inline-array.", FORMAT_XLS); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLS); xShell->DoClose(); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rDoc = xDocSh->GetDocument(); // B2:C3 contains a matrix. checkMatrixRange(rDoc, ScRange(1, 1, 0, 2, 2, 0)); // B5:D6 contains a matrix. checkMatrixRange(rDoc, ScRange(1, 4, 0, 3, 5, 0)); // B8:C10 as well. checkMatrixRange(rDoc, ScRange(1, 7, 0, 2, 9, 0)); xDocSh->DoClose(); } void ScExportTest::testEmbeddedChartODS() { ScDocShellRef xShell = loadDoc(u"embedded-chart.", FORMAT_XLS); std::shared_ptr pTempFile(ScBootstrapFixture::exportTo(*xShell, FORMAT_ODS)); xmlDocUniquePtr pDoc = XPathHelper::parseExport(pTempFile, m_xSFactory, "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", "notify-on-update-of-ranges", "Chart1.B3:Chart1.B5 Chart1.C2:Chart1.C2 Chart1.C3:Chart1.C5"); xShell->DoClose(); } void ScExportTest::testEmbeddedChartXLS() { ScDocShellRef xShell = loadDoc(u"embedded-chart.", FORMAT_XLS); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLS); xShell->DoClose(); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rDoc = xDocSh->GetDocument(); // Make sure the 2nd sheet is named 'Chart1'. OUString aName; rDoc.GetName(1, aName); CPPUNIT_ASSERT_EQUAL(OUString("Chart1"), aName); const SdrOle2Obj* pOleObj = getSingleChartObject(rDoc, 1); CPPUNIT_ASSERT_MESSAGE("Failed to retrieve a chart object from the 2nd sheet.", pOleObj); ScRangeList aRanges = getChartRanges(rDoc, *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))); xDocSh->DoClose(); } void ScExportTest::testCellAnchoredGroupXLS() { ScDocShellRef xDocSh_in = loadDoc(u"cell-anchored-group.", FORMAT_XLS); ScDocShellRef xDocSh = saveAndReload(*xDocSh_in, FORMAT_ODS); CPPUNIT_ASSERT_MESSAGE("Failed to save and reload cell-anchored-group.ods", xDocSh.is()); // the document contains a group anchored on the first cell, make sure it's there in the right place ScDocument& rDoc = xDocSh->GetDocument(); CPPUNIT_ASSERT_MESSAGE("There should be at least one sheet.", rDoc.GetTableCount() > 0); ScDrawLayer* pDrawLayer = rDoc.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(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); xDocSh->DoClose(); } void ScExportTest::testFormulaReferenceXLS() { ScDocShellRef xShell = loadDoc(u"formula-reference.", FORMAT_XLS); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLS); xShell->DoClose(); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rDoc = xDocSh->GetDocument(); ASSERT_FORMULA_EQUAL(rDoc, ScAddress(3, 1, 0), "$A$2+$B$2+$C$2", "Wrong formula in D2"); ASSERT_FORMULA_EQUAL(rDoc, ScAddress(3, 2, 0), "A3+B3+C3", "Wrong formula in D3"); ASSERT_FORMULA_EQUAL(rDoc, ScAddress(3, 5, 0), "SUM($A$6:$C$6)", "Wrong formula in D6"); ASSERT_FORMULA_EQUAL(rDoc, ScAddress(3, 6, 0), "SUM(A7:C7)", "Wrong formula in D7"); ASSERT_FORMULA_EQUAL(rDoc, ScAddress(3, 9, 0), "$Two.$A$2+$Two.$B$2+$Two.$C$2", "Wrong formula in D10"); ASSERT_FORMULA_EQUAL(rDoc, ScAddress(3, 10, 0), "$Two.A3+$Two.B3+$Two.C3", "Wrong formula in D11"); ASSERT_FORMULA_EQUAL(rDoc, ScAddress(3, 13, 0), "MIN($Two.$A$2:$C$2)", "Wrong formula in D14"); ASSERT_FORMULA_EQUAL(rDoc, ScAddress(3, 14, 0), "MAX($Two.A3:C3)", "Wrong formula in D15"); xDocSh->DoClose(); } void ScExportTest::testSheetProtectionXLSX() { ScDocShellRef xShell = loadDoc(u"ProtecteSheet1234Pass.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rDoc = xDocSh->GetDocument(); const ScTableProtection* pTabProtect = rDoc.GetTabProtection(0); CPPUNIT_ASSERT(pTabProtect); Sequence aHash = pTabProtect->getPasswordHash(PASSHASH_XL); // check has if (aHash.getLength() >= 2) { CPPUNIT_ASSERT_EQUAL(sal_uInt8(204), static_cast(aHash[0])); CPPUNIT_ASSERT_EQUAL(sal_uInt8(61), static_cast(aHash[1])); } // we could flesh out this check I guess CPPUNIT_ASSERT(!pTabProtect->isOptionEnabled(ScTableProtection::OBJECTS)); CPPUNIT_ASSERT(!pTabProtect->isOptionEnabled(ScTableProtection::SCENARIOS)); xDocSh->DoClose(); } void ScExportTest::testSheetProtectionXLSB() { ScDocShellRef xShell = loadDoc(u"tdf108017_calcProtection.", FORMAT_XLSB); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rDoc = xDocSh->GetDocument(); const ScTableProtection* pTabProtect = rDoc.GetTabProtection(0); CPPUNIT_ASSERT(pTabProtect); CPPUNIT_ASSERT(pTabProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS)); CPPUNIT_ASSERT(!pTabProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS)); xDocSh->DoClose(); } 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(sal_uLong nFormatType) { 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) }; ScDocShellRef xDocSh = loadDoc(u"cell-borders.", nFormatType); { ScDocument& rDoc = xDocSh->GetDocument(); for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i) { const editeng::SvxBorderLine* pLine = nullptr; rDoc.GetBorderLines(2, aChecks[i].mnRow, 0, nullptr, &pLine, nullptr, nullptr); CPPUNIT_ASSERT(pLine); CPPUNIT_ASSERT_EQUAL(toBorderName(aChecks[i].mnStyle), toBorderName(pLine->GetBorderLineStyle())); if (aChecks[i].mnWidth >= 0) CPPUNIT_ASSERT_EQUAL(aChecks[i].mnWidth, pLine->GetWidth()); } } ScDocShellRef xNewDocSh = saveAndReload(*xDocSh, nFormatType); xDocSh->DoClose(); ScDocument& rDoc = xNewDocSh->GetDocument(); for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i) { const editeng::SvxBorderLine* pLine = nullptr; rDoc.GetBorderLines(2, aChecks[i].mnRow, 0, nullptr, &pLine, nullptr, nullptr); CPPUNIT_ASSERT(pLine); CPPUNIT_ASSERT_EQUAL(toBorderName(aChecks[i].mnStyle), toBorderName(pLine->GetBorderLineStyle())); if (aChecks[i].mnWidth >= 0) CPPUNIT_ASSERT_EQUAL(aChecks[i].mnWidth, pLine->GetWidth()); } xNewDocSh->DoClose(); } void ScExportTest::testCellBordersXLS() { testExcelCellBorders(FORMAT_XLS); } void ScExportTest::testCellBordersXLSX() { testExcelCellBorders(FORMAT_XLSX); } void ScExportTest::testBordersExchangeXLSX() { // Document: sc/qa/unit/data/README.cellborders // short name for the table const SvxBorderLineStyle None = SvxBorderLineStyle::NONE; const SvxBorderLineStyle Solid = SvxBorderLineStyle::SOLID; const SvxBorderLineStyle Dotted = SvxBorderLineStyle::DOTTED; const SvxBorderLineStyle Dashed = SvxBorderLineStyle::DASHED; const SvxBorderLineStyle FineDash = SvxBorderLineStyle::FINE_DASHED; const SvxBorderLineStyle DashDot = SvxBorderLineStyle::DASH_DOT; const SvxBorderLineStyle DashDoDo = SvxBorderLineStyle::DASH_DOT_DOT; const SvxBorderLineStyle DoubThin = SvxBorderLineStyle::DOUBLE_THIN; const size_t nMaxCol = 18; const size_t nMaxRow = 7; static struct { SvxBorderLineStyle BorderStyleTop, BorderStyleBottom; tools::Long WidthTop, WidthBottom; } aCheckBorderWidth[nMaxCol][nMaxRow] = { /* Width */ /* 0,05 */ { { Solid, Solid, 1, 1 }, // SOLID { Dotted, Dotted, 15, 15 }, // DOTTED { Dotted, Dotted, 15, 15 }, // DASHED { FineDash, FineDash, 15, 15 }, // FINE_DASHED { FineDash, FineDash, 15, 15 }, // DASH_DOT { FineDash, FineDash, 15, 15 }, // DASH_DOT_DOT { None, None, 0, 0 } }, // DOUBLE_THIN /* 0,25 */ { { Solid, Solid, 1, 1 }, { Dotted, Dotted, 15, 15 }, { Dotted, Dotted, 15, 15 }, { FineDash, FineDash, 15, 15 }, { FineDash, FineDash, 15, 15 }, { FineDash, FineDash, 15, 15 }, { None, None, 0, 0 } }, /* 0,50 */ { { Solid, Solid, 1, 1 }, { Dotted, Dotted, 15, 15 }, { Dotted, Dotted, 15, 15 }, { FineDash, FineDash, 15, 15 }, { FineDash, FineDash, 15, 15 }, { FineDash, FineDash, 15, 15 }, { None, None, 0, 0 } }, /* 0,75 */ { { Solid, Solid, 15, 15 }, { Dotted, Dotted, 15, 15 }, { FineDash, FineDash, 15, 15 }, { FineDash, FineDash, 15, 15 }, { DashDot, DashDot, 15, 15 }, { DashDoDo, DashDoDo, 15, 15 }, { DoubThin, DoubThin, 35, 35 } }, /* 1,00 */ { { Solid, Solid, 15, 15 }, { Dotted, Dotted, 15, 15 }, { FineDash, FineDash, 15, 15 }, { FineDash, FineDash, 15, 15 }, { DashDot, DashDot, 15, 15 }, { DashDoDo, DashDoDo, 15, 15 }, { DoubThin, DoubThin, 35, 35 } }, /* 1,25 */ { { Solid, Solid, 15, 15 }, { Dotted, Dotted, 15, 15 }, { FineDash, FineDash, 15, 15 }, { FineDash, FineDash, 15, 15 }, { DashDot, DashDot, 15, 15 }, { DashDoDo, DashDoDo, 15, 15 }, { DoubThin, DoubThin, 35, 35 } }, /* 1,50 */ { { Solid, Solid, 15, 15 }, { Dotted, Dotted, 15, 15 }, { FineDash, FineDash, 15, 15 }, { FineDash, FineDash, 15, 15 }, { DashDot, DashDot, 15, 15 }, { DashDoDo, DashDoDo, 15, 15 }, { DoubThin, DoubThin, 35, 35 } }, /* 1,75 */ { { Solid, Solid, 35, 35 }, { FineDash, FineDash, 35, 35 }, { Dashed, Dashed, 35, 35 }, { FineDash, FineDash, 35, 35 }, { DashDot, DashDot, 35, 35 }, { DashDoDo, DashDoDo, 35, 35 }, { DoubThin, DoubThin, 35, 35 } }, /* 2,00 */ { { Solid, Solid, 35, 35 }, { FineDash, FineDash, 35, 35 }, { Dashed, Dashed, 35, 35 }, { FineDash, FineDash, 35, 35 }, { DashDot, DashDot, 35, 35 }, { DashDoDo, DashDoDo, 35, 35 }, { DoubThin, DoubThin, 35, 35 } }, /* 2,25 */ { { Solid, Solid, 35, 35 }, { FineDash, FineDash, 35, 35 }, { Dashed, Dashed, 35, 35 }, { FineDash, FineDash, 35, 35 }, { DashDot, DashDot, 35, 35 }, { DashDoDo, DashDoDo, 35, 35 }, { DoubThin, DoubThin, 35, 35 } }, /* 2,50 */ { { Solid, Solid, 50, 50 }, { FineDash, FineDash, 35, 35 }, { Dashed, Dashed, 35, 35 }, { FineDash, FineDash, 35, 35 }, { DashDot, DashDot, 35, 35 }, { DashDoDo, DashDoDo, 35, 35 }, { DoubThin, DoubThin, 35, 35 } }, /* 2,75 */ { { Solid, Solid, 50, 50 }, { FineDash, FineDash, 35, 35 }, { Dashed, Dashed, 35, 35 }, { FineDash, FineDash, 35, 35 }, { DashDot, DashDot, 35, 35 }, { DashDoDo, DashDoDo, 35, 35 }, { DoubThin, DoubThin, 35, 35 } }, /* 3,00 */ { { Solid, Solid, 50, 50 }, { FineDash, FineDash, 35, 35 }, { Dashed, Dashed, 35, 35 }, { FineDash, FineDash, 35, 35 }, { DashDot, DashDot, 35, 35 }, { DashDoDo, DashDoDo, 35, 35 }, { DoubThin, DoubThin, 35, 35 } }, /* 3,50 */ { { Solid, Solid, 50, 50 }, { FineDash, FineDash, 35, 35 }, { Dashed, Dashed, 35, 35 }, { FineDash, FineDash, 35, 35 }, { DashDot, DashDot, 35, 35 }, { DashDoDo, DashDoDo, 35, 35 }, { DoubThin, DoubThin, 35, 35 } }, /* 4,00 */ { { Solid, Solid, 50, 50 }, { FineDash, FineDash, 35, 35 }, { Dashed, Dashed, 35, 35 }, { FineDash, FineDash, 35, 35 }, { DashDot, DashDot, 35, 35 }, { DashDoDo, DashDoDo, 35, 35 }, { DoubThin, DoubThin, 35, 35 } }, /* 5,00 */ { { Solid, Solid, 50, 50 }, { FineDash, FineDash, 35, 35 }, { Dashed, Dashed, 35, 35 }, { FineDash, FineDash, 35, 35 }, { DashDot, DashDot, 35, 35 }, { DashDoDo, DashDoDo, 35, 35 }, { DoubThin, DoubThin, 35, 35 } }, /* 7,00 */ { { Solid, Solid, 50, 50 }, { FineDash, FineDash, 35, 35 }, { Dashed, Dashed, 35, 35 }, { FineDash, FineDash, 35, 35 }, { DashDot, DashDot, 35, 35 }, { DashDoDo, DashDoDo, 35, 35 }, { DoubThin, DoubThin, 35, 35 } }, /* 9,00 */ { { Solid, Solid, 50, 50 }, { FineDash, FineDash, 35, 35 }, { Dashed, Dashed, 35, 35 }, { FineDash, FineDash, 35, 35 }, { DashDot, DashDot, 35, 35 }, { DashDoDo, DashDoDo, 35, 35 }, { DoubThin, DoubThin, 35, 35 } } }; ScDocShellRef xShell = loadDoc(u"test_borders_export.", FORMAT_ODS); // load the ods with our Borders ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); // save the ods to xlsx and load xlsx CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rDoc = xDocSh->GetDocument(); for (size_t nCol = 0; nCol < nMaxCol; ++nCol) { for (size_t nRow = 0; nRow < nMaxRow; ++nRow) { const editeng::SvxBorderLine* pLineTop = nullptr; const editeng::SvxBorderLine* pLineBottom = nullptr; rDoc.GetBorderLines(nCol + 2, (nRow * 2) + 8, 0, nullptr, &pLineTop, nullptr, &pLineBottom); if ((nCol < 3) && (nRow == 6)) { // in this range no lines since minimum size to create a double is 0.5 CPPUNIT_ASSERT(!pLineTop); CPPUNIT_ASSERT(!pLineBottom); continue; } else { CPPUNIT_ASSERT(pLineTop); CPPUNIT_ASSERT(pLineBottom); } CPPUNIT_ASSERT_EQUAL_MESSAGE("Top Border-Line-Style wrong", aCheckBorderWidth[nCol][nRow].BorderStyleTop, pLineTop->GetBorderLineStyle()); CPPUNIT_ASSERT_EQUAL_MESSAGE("Bottom Border-Line-Style wrong", aCheckBorderWidth[nCol][nRow].BorderStyleBottom, pLineBottom->GetBorderLineStyle()); CPPUNIT_ASSERT_EQUAL_MESSAGE("Top Width-Line wrong", aCheckBorderWidth[nCol][nRow].WidthTop, pLineTop->GetWidth()); CPPUNIT_ASSERT_EQUAL_MESSAGE("Bottom Width-Line wrong", aCheckBorderWidth[nCol][nRow].WidthBottom, pLineBottom->GetWidth()); } } xDocSh->DoClose(); } static OUString toString(const ScBigRange& rRange) { OUStringBuffer aBuf; aBuf.append("(columns:"); aBuf.append(rRange.aStart.Col()); aBuf.append('-'); aBuf.append(rRange.aEnd.Col()); aBuf.append(";rows:"); aBuf.append(rRange.aStart.Row()); aBuf.append('-'); aBuf.append(rRange.aEnd.Row()); aBuf.append(";sheets:"); aBuf.append(rRange.aStart.Tab()); aBuf.append('-'); aBuf.append(rRange.aEnd.Tab()); aBuf.append(')'); return aBuf.makeStringAndClear(); } void ScExportTest::testTrackChangesSimpleXLSX() { struct CheckItem { sal_uLong mnActionId; ScChangeActionType meType; sal_Int32 mnStartCol; sal_Int32 mnStartRow; sal_Int32 mnStartTab; sal_Int32 mnEndCol; sal_Int32 mnEndRow; sal_Int32 mnEndTab; bool mbRowInsertedAtBottom; }; struct { bool checkRange(ScChangeActionType eType, const ScBigRange& rExpected, const ScBigRange& rActual) { ScBigRange aExpected(rExpected), aActual(rActual); switch (eType) { case SC_CAT_INSERT_ROWS: { // Ignore columns. aExpected.aStart.SetCol(0); aExpected.aEnd.SetCol(0); aActual.aStart.SetCol(0); aActual.aEnd.SetCol(0); } break; default:; } return aExpected == aActual; } bool check(const ScDocument& rDoc) { static const CheckItem aChecks[] = { { 1, SC_CAT_CONTENT, 1, 1, 0, 1, 1, 0, false }, { 2, SC_CAT_INSERT_ROWS, 0, 2, 0, 0, 2, 0, true }, { 3, SC_CAT_CONTENT, 1, 2, 0, 1, 2, 0, false }, { 4, SC_CAT_INSERT_ROWS, 0, 3, 0, 0, 3, 0, true }, { 5, SC_CAT_CONTENT, 1, 3, 0, 1, 3, 0, false }, { 6, SC_CAT_INSERT_ROWS, 0, 4, 0, 0, 4, 0, true }, { 7, SC_CAT_CONTENT, 1, 4, 0, 1, 4, 0, false }, { 8, SC_CAT_INSERT_ROWS, 0, 5, 0, 0, 5, 0, true }, { 9, SC_CAT_CONTENT, 1, 5, 0, 1, 5, 0, false }, { 10, SC_CAT_INSERT_ROWS, 0, 6, 0, 0, 6, 0, true }, { 11, SC_CAT_CONTENT, 1, 6, 0, 1, 6, 0, false }, { 12, SC_CAT_INSERT_ROWS, 0, 7, 0, 0, 7, 0, true }, { 13, SC_CAT_CONTENT, 1, 7, 0, 1, 7, 0, false }, }; ScChangeTrack* pCT = rDoc.GetChangeTrack(); if (!pCT) { cerr << "Change track instance doesn't exist." << endl; return false; } sal_uLong nActionMax = pCT->GetActionMax(); if (nActionMax != 13) { cerr << "Unexpected highest action ID value." << endl; return false; } for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i) { sal_uInt16 nActId = aChecks[i].mnActionId; const ScChangeAction* pAction = pCT->GetAction(nActId); if (!pAction) { cerr << "No action for action number " << nActId << " found." << endl; return false; } if (pAction->GetType() != aChecks[i].meType) { cerr << "Unexpected action type for action number " << nActId << "." << endl; return false; } const ScBigRange& rRange = pAction->GetBigRange(); ScBigRange aCheck(aChecks[i].mnStartCol, aChecks[i].mnStartRow, aChecks[i].mnStartTab, aChecks[i].mnEndCol, aChecks[i].mnEndRow, aChecks[i].mnEndTab); if (!checkRange(pAction->GetType(), aCheck, rRange)) { cerr << "Unexpected range for action number " << nActId << ": expected=" << toString(aCheck) << " actual=" << toString(rRange) << endl; return false; } switch (pAction->GetType()) { case SC_CAT_INSERT_ROWS: { const ScChangeActionIns* p = static_cast(pAction); if (p->IsEndOfList() != aChecks[i].mbRowInsertedAtBottom) { cerr << "Unexpected end-of-list flag for action number " << nActId << "." << endl; return false; } } break; default:; } } return true; } bool checkRevisionUserAndTime(ScDocument& rDoc, std::u16string_view rOwnerName) { ScChangeTrack* pCT = rDoc.GetChangeTrack(); if (!pCT) { cerr << "Change track instance doesn't exist." << endl; return false; } ScChangeAction* pAction = pCT->GetLast(); if (pAction->GetUser() != "Kohei Yoshida") { cerr << "Wrong user name." << endl; return false; } DateTime aDT = pAction->GetDateTime(); if (aDT.GetYear() != 2014 || aDT.GetMonth() != 7 || aDT.GetDay() != 11) { cerr << "Wrong time stamp." << endl; return false; } // Insert a new record to make sure the user and date-time are correct. rDoc.SetString(ScAddress(1, 8, 0), "New String"); ScCellValue aEmpty; pCT->AppendContent(ScAddress(1, 8, 0), aEmpty); pAction = pCT->GetLast(); if (!pAction) { cerr << "Failed to retrieve last revision." << endl; return false; } if (rOwnerName != pAction->GetUser()) { cerr << "Wrong user name." << endl; return false; } DateTime aDTNew = pAction->GetDateTime(); if (aDTNew <= aDT) { cerr << "Time stamp of the new revision should be more recent than that of the " "last revision." << endl; return false; } return true; } } aTest; SvtUserOptions& rUserOpt = SC_MOD()->GetUserOptions(); rUserOpt.SetToken(UserOptToken::FirstName, "Export"); rUserOpt.SetToken(UserOptToken::LastName, "Test"); OUString aOwnerName = rUserOpt.GetFirstName() + " " + rUserOpt.GetLastName(); // First, test the xls variant. ScDocShellRef xDocSh = loadDoc(u"track-changes/simple-cell-changes.", FORMAT_XLS); ScDocument* pDoc = &xDocSh->GetDocument(); bool bGood = aTest.check(*pDoc); CPPUNIT_ASSERT_MESSAGE("Initial check failed (xls).", bGood); ScDocShellRef xDocSh2 = saveAndReload(*xDocSh, FORMAT_XLS); xDocSh->DoClose(); pDoc = &xDocSh2->GetDocument(); bGood = aTest.check(*pDoc); CPPUNIT_ASSERT_MESSAGE("Check after reload failed (xls).", bGood); // fdo#81445 : Check the blank value string to make sure it's "". ScChangeTrack* pCT = pDoc->GetChangeTrack(); CPPUNIT_ASSERT(pCT); ScChangeAction* pAction = pCT->GetAction(1); CPPUNIT_ASSERT(pAction); OUString aDesc = pAction->GetDescription(*pDoc); CPPUNIT_ASSERT_EQUAL(OUString("Cell B2 changed from '' to '1'"), aDesc); bGood = aTest.checkRevisionUserAndTime(*pDoc, aOwnerName); CPPUNIT_ASSERT_MESSAGE("Check revision and time failed after reload (xls).", bGood); xDocSh2->DoClose(); // Now, test the xlsx variant the same way. xDocSh = loadDoc(u"track-changes/simple-cell-changes.", FORMAT_XLSX); pDoc = &xDocSh->GetDocument(); aTest.check(*pDoc); CPPUNIT_ASSERT_MESSAGE("Initial check failed (xlsx).", bGood); xDocSh2 = saveAndReload(*xDocSh, FORMAT_XLSX); xDocSh->DoClose(); pDoc = &xDocSh2->GetDocument(); bGood = aTest.check(*pDoc); CPPUNIT_ASSERT_MESSAGE("Check after reload failed (xlsx).", bGood); bGood = aTest.checkRevisionUserAndTime(*pDoc, aOwnerName); CPPUNIT_ASSERT_MESSAGE("Check revision and time failed after reload (xlsx).", bGood); xDocSh2->DoClose(); } void ScExportTest::testSheetTabColorsXLSX() { struct { bool checkContent(const ScDocument& rDoc) { std::vector aTabNames = rDoc.GetAllTableNames(); // green, red, blue, yellow (from left to right). if (aTabNames.size() != 4) { cerr << "There should be exactly 4 sheets." << endl; return false; } const char* pNames[] = { "Green", "Red", "Blue", "Yellow" }; for (size_t i = 0; i < SAL_N_ELEMENTS(pNames); ++i) { OUString aExpected = OUString::createFromAscii(pNames[i]); if (aExpected != aTabNames[i]) { cerr << "incorrect sheet name: expected='" << aExpected << "', actual='" << aTabNames[i] << "'" << endl; return false; } } static const Color aXclColors[] = { 0x0000B050, // green 0x00FF0000, // red 0x000070C0, // blue 0x00FFFF00, // yellow }; for (size_t i = 0; i < SAL_N_ELEMENTS(aXclColors); ++i) { if (aXclColors[i] != rDoc.GetTabBgColor(i)) { cerr << "wrong sheet color for sheet " << i << endl; return false; } } return true; } } aTest; ScDocShellRef xDocSh = loadDoc(u"sheet-tab-color.", FORMAT_XLSX); { ScDocument& rDoc = xDocSh->GetDocument(); bool bRes = aTest.checkContent(rDoc); CPPUNIT_ASSERT_MESSAGE("Failed on the initial content check.", bRes); } ScDocShellRef xDocSh2 = saveAndReload(*xDocSh, FORMAT_XLSX); CPPUNIT_ASSERT_MESSAGE("Failed to reload file.", xDocSh2.is()); xDocSh->DoClose(); ScDocument& rDoc = xDocSh2->GetDocument(); bool bRes = aTest.checkContent(rDoc); CPPUNIT_ASSERT_MESSAGE("Failed on the content check after reload.", bRes); xDocSh2->DoClose(); } void ScExportTest::testTdf133487() { ScDocShellRef xShell = loadDoc(u"shapes_foreground_background.", FORMAT_FODS); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_ODS); xmlDocUniquePtr pXmlDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, "content.xml"); CPPUNIT_ASSERT(pXmlDoc); // shape in background has lowest index assertXPath(pXmlDoc, "/office:document-content/office:body/office:spreadsheet/table:table[1]/" "table:table-row[1]/table:table-cell[1]/draw:custom-shape", "z-index", "0"); assertXPath(pXmlDoc, "/office:document-content/office:body/office:spreadsheet/table:table[1]/" "table:table-row[1]/table:table-cell[1]/draw:custom-shape" "/attribute::table:table-background", 1); assertXPath(pXmlDoc, "/office:document-content/office:body/office:spreadsheet/table:table[1]/" "table:table-row[1]/table:table-cell[1]/draw:custom-shape", "table-background", "true"); // shape in foreground, previously index 1 assertXPath(pXmlDoc, "/office:document-content/office:body/office:spreadsheet/table:table[1]/" "table:table-row[1]/table:table-cell[2]/draw:custom-shape", "z-index", "2"); // attribute is only written for value "true" assertXPath(pXmlDoc, "/office:document-content/office:body/office:spreadsheet/table:table[1]/" "table:table-row[1]/table:table-cell[2]/draw:custom-shape" "/attribute::table:table-background", 0); // shape in foreground, previously index 0 assertXPath(pXmlDoc, "/office:document-content/office:body/office:spreadsheet/table:table[1]/" "table:table-row[3]/table:table-cell[1]/draw:custom-shape", "z-index", "1"); // attribute is only written for value "true" assertXPath(pXmlDoc, "/office:document-content/office:body/office:spreadsheet/table:table[1]/" "table:table-row[3]/table:table-cell[1]/draw:custom-shape" "/attribute::table:table-background", 0); // shape in foreground, previously index 4 assertXPath(pXmlDoc, "/office:document-content/office:body/office:spreadsheet/table:table[1]/" "table:shapes/draw:custom-shape", "z-index", "3"); // attribute is only written for value "true" assertXPath(pXmlDoc, "/office:document-content/office:body/office:spreadsheet/table:table[1]/" "table:shapes/draw:custom-shape" "/attribute::table:table-background", 0); // form control, previously index 3 assertXPath(pXmlDoc, "/office:document-content/office:body/office:spreadsheet/table:table[1]/" "table:shapes/draw:control", "z-index", "4"); // attribute is only written for value "true" assertXPath(pXmlDoc, "/office:document-content/office:body/office:spreadsheet/table:table[1]/" "table:shapes/draw:control" "/attribute::table:table-background", 0); xShell->DoClose(); } void ScExportTest::testSharedFormulaExportXLS() { struct { bool checkContent(ScDocument& rDoc) { formula::FormulaGrammar::Grammar eGram = formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1; rDoc.SetGrammar(eGram); sc::TokenStringContext aCxt(rDoc, eGram); // Check the title row. OUString aActual = rDoc.GetString(0, 1, 0); OUString aExpected = "Response"; if (aActual != aExpected) { cerr << "Wrong content in A2: expected='" << aExpected << "', actual='" << aActual << "'" << endl; return false; } aActual = rDoc.GetString(1, 1, 0); aExpected = "Response"; if (aActual != aExpected) { cerr << "Wrong content in B2: expected='" << aExpected << "', actual='" << aActual << "'" << endl; return false; } // A3:A12 and B3:B12 are numbers from 1 to 10. for (SCROW i = 0; i <= 9; ++i) { double fExpected = i + 1.0; ScAddress aPos(0, i + 2, 0); double fActual = rDoc.GetValue(aPos); if (fExpected != fActual) { cerr << "Wrong value in A" << (i + 2) << ": expected=" << fExpected << ", actual=" << fActual << endl; return false; } aPos.IncCol(); ScFormulaCell* pFC = rDoc.GetFormulaCell(aPos); if (!pFC) { cerr << "B" << (i + 2) << " should be a formula cell." << endl; return false; } OUString aFormula = pFC->GetCode()->CreateString(aCxt, aPos); aExpected = "Coefficients!RC[-1]"; if (aFormula != aExpected) { cerr << "Wrong formula in B" << (i + 2) << ": expected='" << aExpected << "', actual='" << aFormula << "'" << endl; return false; } fActual = rDoc.GetValue(aPos); if (fExpected != fActual) { cerr << "Wrong value in B" << (i + 2) << ": expected=" << fExpected << ", actual=" << fActual << endl; return false; } } return true; } } aTest; ScDocShellRef xDocSh = loadDoc(u"shared-formula/3d-reference.", FORMAT_ODS); { ScDocument& rDoc = xDocSh->GetDocument(); // Check the content of the original. bool bRes = aTest.checkContent(rDoc); CPPUNIT_ASSERT_MESSAGE("Content check on the original document failed.", bRes); } ScDocShellRef xDocSh2 = saveAndReload(*xDocSh, FORMAT_XLS); xDocSh->DoClose(); CPPUNIT_ASSERT_MESSAGE("Failed to reload file.", xDocSh2.is()); ScDocument& rDoc = xDocSh2->GetDocument(); // Check the content of the reloaded. This should be identical. bool bRes = aTest.checkContent(rDoc); CPPUNIT_ASSERT_MESSAGE("Content check on the reloaded document failed.", bRes); xDocSh2->DoClose(); } void ScExportTest::testSharedFormulaExportXLSX() { struct { bool checkContent(const ScDocument& rDoc) { SCTAB nTabCount = rDoc.GetTableCount(); if (nTabCount != 2) { cerr << "Document should have exactly 2 sheets. " << nTabCount << " found." << endl; return false; } // Make sure the sheet tab colors are not set. for (SCROW i = 0; i <= 1; ++i) { Color aTabBgColor = rDoc.GetTabBgColor(i); if (aTabBgColor != COL_AUTO) { cerr << "The tab color of Sheet " << (i + 1) << " should not be explicitly set." << endl; return false; } } // B2:B7 should show 1,2,3,4,5,6. double fExpected = 1.0; for (SCROW i = 1; i <= 6; ++i, ++fExpected) { ScAddress aPos(1, i, 0); double fVal = rDoc.GetValue(aPos); if (fVal != fExpected) { cerr << "Wrong value in B" << (i + 1) << ": expected=" << fExpected << ", actual=" << fVal << endl; return false; } } // C2:C7 should show 10,20,...,60. fExpected = 10.0; for (SCROW i = 1; i <= 6; ++i, fExpected += 10.0) { ScAddress aPos(2, i, 0); double fVal = rDoc.GetValue(aPos); if (fVal != fExpected) { cerr << "Wrong value in C" << (i + 1) << ": expected=" << fExpected << ", actual=" << fVal << endl; return false; } } // D2:D7 should show 1,2,...,6. fExpected = 1.0; for (SCROW i = 1; i <= 6; ++i, ++fExpected) { ScAddress aPos(3, i, 0); double fVal = rDoc.GetValue(aPos); if (fVal != fExpected) { cerr << "Wrong value in D" << (i + 1) << ": expected=" << fExpected << ", actual=" << fVal << endl; return false; } } return true; } } aTest; ScDocShellRef xDocSh = loadDoc(u"shared-formula/3d-reference.", FORMAT_XLSX); { ScDocument& rDoc = xDocSh->GetDocument(); bool bRes = aTest.checkContent(rDoc); CPPUNIT_ASSERT_MESSAGE("Content check on the initial document failed.", bRes); rDoc.CalcAll(); // Recalculate to flush all cached results. bRes = aTest.checkContent(rDoc); CPPUNIT_ASSERT_MESSAGE("Content check on the initial recalculated document failed.", bRes); } // Save and reload, and check the content again. ScDocShellRef xDocSh2 = saveAndReload(*xDocSh, FORMAT_XLSX); xDocSh->DoClose(); CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocSh2.is()); ScDocument& rDoc = xDocSh2->GetDocument(); rDoc.CalcAll(); // Recalculate to flush all cached results. bool bRes = aTest.checkContent(rDoc); CPPUNIT_ASSERT_MESSAGE("Content check on the reloaded document failed.", bRes); xDocSh2->DoClose(); } void ScExportTest::testSharedFormulaStringResultExportXLSX() { struct { bool checkContent(const ScDocument& rDoc) { { // B2:B7 should show A,B,...,F. const char* const expected[] = { "A", "B", "C", "D", "E", "F" }; for (SCROW i = 0; i <= 5; ++i) { ScAddress aPos(1, i + 1, 0); OUString aStr = rDoc.GetString(aPos); OUString aExpected = OUString::createFromAscii(expected[i]); if (aStr != aExpected) { cerr << "Wrong value in B" << (i + 2) << ": expected='" << aExpected << "', actual='" << aStr << "'" << endl; return false; } } } { // C2:C7 should show AA,BB,...,FF. const char* const expected[] = { "AA", "BB", "CC", "DD", "EE", "FF" }; for (SCROW i = 0; i <= 5; ++i) { ScAddress aPos(2, i + 1, 0); OUString aStr = rDoc.GetString(aPos); OUString aExpected = OUString::createFromAscii(expected[i]); if (aStr != aExpected) { cerr << "Wrong value in C" << (i + 2) << ": expected='" << aExpected << "', actual='" << aStr << "'" << endl; return false; } } } return true; } } aTest; ScDocShellRef xDocSh = loadDoc(u"shared-formula/text-results.", FORMAT_XLSX); { ScDocument& rDoc = xDocSh->GetDocument(); // Check content without re-calculation, to test cached formula results. bool bRes = aTest.checkContent(rDoc); CPPUNIT_ASSERT_MESSAGE("Content check on the initial document failed.", bRes); // Now, re-calculate and check the results. rDoc.CalcAll(); bRes = aTest.checkContent(rDoc); CPPUNIT_ASSERT_MESSAGE("Content check on the initial recalculated document failed.", bRes); } // Reload and check again. ScDocShellRef xDocSh2 = saveAndReload(*xDocSh, FORMAT_XLSX); xDocSh->DoClose(); CPPUNIT_ASSERT_MESSAGE("Failed to re-load file.", xDocSh2.is()); ScDocument& rDoc = xDocSh2->GetDocument(); bool bRes = aTest.checkContent(rDoc); CPPUNIT_ASSERT_MESSAGE("Content check on the reloaded document failed.", bRes); xDocSh2->DoClose(); } void ScExportTest::testFunctionsExcel2010(sal_uLong nFormatType) { ScDocShellRef xShell = loadDoc(u"functions-excel-2010.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, nFormatType); ScDocument& rDoc = xDocSh->GetDocument(); rDoc.CalcAll(); // perform hard re-calculation. testFunctionsExcel2010_Impl(rDoc); xDocSh->DoClose(); } void ScExportTest::testFunctionsExcel2010XLSX() { testFunctionsExcel2010(FORMAT_XLSX); } void ScExportTest::testFunctionsExcel2010XLS() { testFunctionsExcel2010(FORMAT_XLS); } void ScExportTest::testCeilingFloor(sal_uLong nFormatType) { ScDocShellRef xShell = loadDoc(u"ceiling-floor.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, nFormatType); ScDocument& rDoc = xDocSh->GetDocument(); rDoc.CalcAll(); // perform hard re-calculation. testCeilingFloor_Impl(rDoc); xDocSh->DoClose(); } void ScExportTest::testCeilingFloorXLSX() { testCeilingFloor(FORMAT_XLSX); } void ScExportTest::testCeilingFloorODSToXLSX() { // tdf#100011 - Cannot open sheet containing FLOOR/CEILING functions by MS Excel, after export to .xlsx ScDocShellRef xShell = loadDoc(u"ceiling-floor.", FORMAT_ODS); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_XLSX); xmlDocUniquePtr pSheet = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/workbook.xml"); CPPUNIT_ASSERT(pSheet); // there shouldn't be any defined names during export of FLOOR and CEILING functions to .xlsx assertXPath(pSheet, "/x:workbook/x:definedNames", 0); xShell->DoClose(); } void ScExportTest::testCeilingFloorXLS() { testCeilingFloor(FORMAT_XLS); } void ScExportTest::testCeilingFloorODS() { testCeilingFloor(FORMAT_ODS); } void ScExportTest::testCustomXml() { // Load document and export it to a temporary file ScDocShellRef xShell = loadDoc(u"customxml.", FORMAT_XLSX); std::shared_ptr pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_XLSX); xmlDocUniquePtr pXmlDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, "customXml/item1.xml"); CPPUNIT_ASSERT(pXmlDoc); xmlDocUniquePtr pRelsDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, "customXml/_rels/item1.xml.rels"); CPPUNIT_ASSERT(pRelsDoc); // Check there is a relation to itemProps1.xml. assertXPath(pRelsDoc, "/rels:Relationships/rels:Relationship", 1); assertXPath(pRelsDoc, "/rels:Relationships/rels:Relationship[@Id='rId1']", "Target", "itemProps1.xml"); std::unique_ptr pStream = XPathHelper::parseExportStream(pXPathFile, m_xSFactory, "ddp/ddpfile.xen"); CPPUNIT_ASSERT(pStream); xShell->DoClose(); } #ifdef _WIN32 static sal_Unicode lcl_getWindowsDrive(const OUString& aURL) { static const sal_Int32 nMinLen = strlen("file:///X:/"); if (aURL.getLength() <= nMinLen) return 0; const OUString aUrlStart = aURL.copy(0, nMinLen); return (aUrlStart.startsWith("file:///") && aUrlStart.endsWith(":/")) ? aUrlStart[8] : 0; } #endif void ScExportTest::testRelativePathsODS() { ScDocShellRef xDocSh = loadDoc(u"fdo79305.", FORMAT_ODS); std::shared_ptr pTempFile = exportTo(*xDocSh, FORMAT_ODS); xmlDocUniquePtr pDoc = XPathHelper::parseExport(pTempFile, m_xSFactory, "content.xml"); CPPUNIT_ASSERT(pDoc); OUString aURL = getXPath(pDoc, "/office:document-content/office:body/office:spreadsheet/table:table/" "table:table-row[2]/table:table-cell[2]/text:p/text:a", "href"); #ifdef _WIN32 // if the exported document is not on the same drive then the linked document, // there is no way to get a relative URL for the link, because ../X:/ is undefined. if (!aURL.startsWith("..")) { sal_Unicode aDocDrive = lcl_getWindowsDrive(pTempFile->GetURL()); sal_Unicode aLinkDrive = lcl_getWindowsDrive(aURL); CPPUNIT_ASSERT_MESSAGE("document on the same drive but no relative link!", aDocDrive != 0); CPPUNIT_ASSERT_MESSAGE("document on the same drive but no relative link!", aLinkDrive != 0); CPPUNIT_ASSERT_MESSAGE("document on the same drive but no relative link!", aDocDrive != aLinkDrive); return; } #endif // make sure that the URL is relative CPPUNIT_ASSERT(aURL.startsWith("..")); xDocSh->DoClose(); } namespace { void testSheetProtection_Impl(const ScDocument& rDoc) { CPPUNIT_ASSERT(rDoc.IsTabProtected(0)); const ScTableProtection* pTabProtection = rDoc.GetTabProtection(0); CPPUNIT_ASSERT(pTabProtection); CPPUNIT_ASSERT(pTabProtection->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS)); CPPUNIT_ASSERT(!pTabProtection->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS)); } } void ScExportTest::testSheetProtectionODS() { ScDocShellRef xDocSh = loadDoc(u"sheet-protection.", FORMAT_ODS); { ScDocument& rDoc = xDocSh->GetDocument(); testSheetProtection_Impl(rDoc); } ScDocShellRef xDocSh2 = saveAndReload(*xDocSh, FORMAT_ODS); { ScDocument& rDoc = xDocSh2->GetDocument(); testSheetProtection_Impl(rDoc); } xDocSh2->DoClose(); } void ScExportTest::testFunctionsExcel2010ODS() { //testFunctionsExcel2010(FORMAT_ODS); } void ScExportTest::testSwappedOutImageExport() { const char* aFilterNames[] = { "calc8", "MS Excel 97", "Calc Office Open XML", "generic_HTML", }; // Set cache size to a very small value to make sure one of the images is swapped out std::shared_ptr xBatch( comphelper::ConfigurationChanges::create()); officecfg::Office::Common::Cache::GraphicManager::TotalCacheSize::set(sal_Int32(1), xBatch); xBatch->commit(); for (size_t nFilter = 0; nFilter < SAL_N_ELEMENTS(aFilterNames); ++nFilter) { // Check whether the export code swaps in the image which was swapped out before. ScDocShellRef xDocSh = loadDoc(u"document_with_two_images.", FORMAT_ODS); const OString sFailedMessage = OString::Concat("Failed on filter: ") + aFilterNames[nFilter]; // Export the document and import again for a check ScDocShellRef xDocSh2 = saveAndReload(*xDocSh, nFilter); xDocSh->DoClose(); // Check whether graphic exported well after it was swapped out uno::Reference xModel = xDocSh2->GetModel(); uno::Reference xDoc(xModel, UNO_QUERY_THROW); uno::Reference xIA(xDoc->getSheets(), UNO_QUERY_THROW); uno::Reference xDrawPageSupplier(xIA->getByIndex(0), UNO_QUERY_THROW); uno::Reference xDraws(xDrawPageSupplier->getDrawPage(), UNO_QUERY_THROW); CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(2), xDraws->getCount()); uno::Reference xImage(xDraws->getByIndex(0), uno::UNO_QUERY); uno::Reference XPropSet(xImage, uno::UNO_QUERY_THROW); // Check Graphic, Size { uno::Reference xGraphic; XPropSet->getPropertyValue("Graphic") >>= xGraphic; CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is()); CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic->getType() != graphic::GraphicType::EMPTY); uno::Reference xBitmap(xGraphic, uno::UNO_QUERY); CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xBitmap.is()); CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(610), xBitmap->getSize().Width); CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(381), xBitmap->getSize().Height); } // Second Image xImage.set(xDraws->getByIndex(1), uno::UNO_QUERY); XPropSet.set(xImage, uno::UNO_QUERY_THROW); // Check Graphic, Size { uno::Reference xGraphic; XPropSet->getPropertyValue("Graphic") >>= xGraphic; CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is()); CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic->getType() != graphic::GraphicType::EMPTY); uno::Reference xBitmap(xGraphic, uno::UNO_QUERY); CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xBitmap.is()); CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(900), xBitmap->getSize().Width); CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(600), xBitmap->getSize().Height); } xDocSh2->DoClose(); } } ScExportTest::ScExportTest() : ScBootstrapFixture("sc/qa/unit/data") { } void ScExportTest::setUp() { test::BootstrapFixture::setUp(); // This is a bit of a fudge, we do this to ensure that ScGlobals::ensure, // which is a private symbol to us, gets called m_xCalcComponent = getMultiServiceFactory()->createInstance("com.sun.star.comp.Calc.SpreadsheetDocument"); CPPUNIT_ASSERT_MESSAGE("no calc component!", m_xCalcComponent.is()); } void ScExportTest::tearDown() { uno::Reference(m_xCalcComponent, UNO_QUERY_THROW)->dispose(); test::BootstrapFixture::tearDown(); } void ScExportTest::testSupBookVirtualPathXLS() { ScDocShellRef xShell = loadDoc(u"external-ref.", FORMAT_XLS); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLS); xShell->DoClose(); CPPUNIT_ASSERT(xDocSh.is()); ScDocument& rDoc = xDocSh->GetDocument(); ScAddress aPos(0, 0, 0); ScTokenArray* pCode = getTokens(rDoc, aPos); if (!pCode) CppUnit::Asserter::fail("empty token array", CPPUNIT_SOURCELINE()); OUString aFormula = toString(rDoc, aPos, *pCode, rDoc.GetGrammar()); #ifdef _WIN32 aFormula = OUString::Concat(aFormula.subView(0, 9)) + aFormula.subView(12); // strip drive letter, e.g. 'C:/' #endif OUString aExpectedFormula = "'file:///home/timar/Documents/external.xls'#$Sheet1.A1"; if (aFormula != aExpectedFormula) { CppUnit::Asserter::failNotEqual( to_std_string(aExpectedFormula), to_std_string(aFormula), CPPUNIT_SOURCELINE(), CppUnit::AdditionalMessage("Wrong SupBook VirtualPath URL")); } xDocSh->DoClose(); } void ScExportTest::testLinkedGraphicRT() { // Problem was with linked images const char* aFilterNames[] = { "calc8", "MS Excel 97", "Calc Office Open XML", "generic_HTML", }; for (size_t nFilter = 0; nFilter < SAL_N_ELEMENTS(aFilterNames); ++nFilter) { // Load the original file with one image ScDocShellRef xDocSh = loadDoc(u"document_with_linked_graphic.", FORMAT_ODS); const OString sFailedMessage = OString::Concat("Failed on filter: ") + aFilterNames[nFilter]; // Export the document and import again for a check ScDocShellRef xDocSh2 = saveAndReload(*xDocSh, nFilter); xDocSh->DoClose(); // Check whether graphic imported well after export ScDocument& rDoc = xDocSh->GetDocument(); ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer(); CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pDrawLayer != nullptr); const SdrPage* pPage = pDrawLayer->GetPage(0); CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pPage != nullptr); SdrGrafObj* pObject = dynamic_cast(pPage->GetObj(0)); CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pObject != nullptr); CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pObject->IsLinkedGraphic()); const GraphicObject& rGraphicObj = pObject->GetGraphicObject(true); CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), int(GraphicType::Bitmap), int(rGraphicObj.GetGraphic().GetType())); CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_uLong(864900), rGraphicObj.GetGraphic().GetSizeBytes()); xDocSh2->DoClose(); } } void ScExportTest::testImageWithSpecialID() { const char* aFilterNames[] = { "calc8", "MS Excel 97", "Calc Office Open XML", "generic_HTML", }; // Trigger swap out mechanism to test swapped state factor too. std::shared_ptr batch( comphelper::ConfigurationChanges::create()); officecfg::Office::Common::Cache::GraphicManager::TotalCacheSize::set(sal_Int32(1), batch); batch->commit(); for (size_t nFilter = 0; nFilter < SAL_N_ELEMENTS(aFilterNames); ++nFilter) { ScDocShellRef xDocSh = loadDoc(u"images_with_special_IDs.", FORMAT_ODS); const OString sFailedMessage = OString::Concat("Failed on filter: ") + aFilterNames[nFilter]; // Export the document and import again for a check ScDocShellRef xDocSh2 = saveAndReload(*xDocSh, nFilter); xDocSh->DoClose(); // Check whether graphic was exported well uno::Reference xModel = xDocSh2->GetModel(); uno::Reference xDoc(xModel, UNO_QUERY_THROW); uno::Reference xIA(xDoc->getSheets(), UNO_QUERY_THROW); uno::Reference xDrawPageSupplier(xIA->getByIndex(0), UNO_QUERY_THROW); uno::Reference xDraws(xDrawPageSupplier->getDrawPage(), UNO_QUERY_THROW); CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(2), xDraws->getCount()); uno::Reference xImage(xDraws->getByIndex(0), uno::UNO_QUERY); uno::Reference XPropSet(xImage, uno::UNO_QUERY_THROW); // Check Graphic, Size { uno::Reference xGraphic; XPropSet->getPropertyValue("Graphic") >>= xGraphic; CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is()); CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic->getType() != graphic::GraphicType::EMPTY); uno::Reference xBitmap(xGraphic, uno::UNO_QUERY); CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xBitmap.is()); CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(610), xBitmap->getSize().Width); CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(381), xBitmap->getSize().Height); } // Second Image xImage.set(xDraws->getByIndex(1), uno::UNO_QUERY); XPropSet.set(xImage, uno::UNO_QUERY_THROW); // Check Graphic, Size { uno::Reference xGraphic; XPropSet->getPropertyValue("Graphic") >>= xGraphic; CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is()); CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic->getType() != graphic::GraphicType::EMPTY); uno::Reference xBitmap(xGraphic, uno::UNO_QUERY); CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xBitmap.is()); CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(900), xBitmap->getSize().Width); CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast(600), xBitmap->getSize().Height); } xDocSh2->DoClose(); } } void ScExportTest::testAbsNamedRangeHTML() { ScDocShellRef xDocSh = loadDoc(u"numberformat.", FORMAT_HTML); xDocSh->DoHardRecalc(); ScDocShellRef xDocSh2 = saveAndReload(*xDocSh, FORMAT_ODS); xDocSh->DoClose(); xDocSh2->DoHardRecalc(); ScDocument& rDoc = xDocSh2->GetDocument(); ScRangeData* pRangeData = rDoc.GetRangeName()->findByUpperName(OUString("HTML_1")); ScSingleRefData* pRef = pRangeData->GetCode()->FirstToken()->GetSingleRef(); // see tdf#119141 for the reason why this isn't Sheet1.HTML_1 CPPUNIT_ASSERT_MESSAGE("HTML_1 is an absolute reference", !pRef->IsTabRel()); xDocSh2->DoClose(); } void ScExportTest::testTdf80149() { ScDocShellRef xDocSh = loadDoc(u"tdf80149.", FORMAT_CSV); xDocSh->DoHardRecalc(); ScDocShellRef xDocSh2 = saveAndReload(*xDocSh, FORMAT_XLSX); xDocSh->DoClose(); xDocSh2->DoHardRecalc(); ScDocument& rDoc = xDocSh2->GetDocument(); CPPUNIT_ASSERT_EQUAL(OUString("row 1"), rDoc.GetString(0, 0, 0)); // Without the fix in place, this test would have failed with // - Expected: Character 0x16 is here ->><<-- // - Actual : CPPUNIT_ASSERT_EQUAL(OUString("Character 0x16 is here ->><<--"), rDoc.GetString(1, 0, 0)); CPPUNIT_ASSERT_EQUAL(OUString("File opens in libre office, but can't be saved as xlsx"), rDoc.GetString(2, 0, 0)); CPPUNIT_ASSERT_EQUAL(OUString("row 2"), rDoc.GetString(0, 1, 0)); CPPUNIT_ASSERT_EQUAL(OUString("Subsequent rows get truncated"), rDoc.GetString(1, 1, 0)); CPPUNIT_ASSERT_EQUAL(OUString("This cell goes missing"), rDoc.GetString(2, 1, 0)); CPPUNIT_ASSERT_EQUAL(OUString("row 3"), rDoc.GetString(0, 2, 0)); CPPUNIT_ASSERT_EQUAL(OUString("Subsequent rows get truncated"), rDoc.GetString(1, 2, 0)); CPPUNIT_ASSERT_EQUAL(OUString("This cell goes missing"), rDoc.GetString(2, 2, 0)); xDocSh2->DoClose(); } void ScExportTest::testSheetLocalRangeNameXLS() { ScDocShellRef xDocSh = loadDoc(u"named-ranges-local.", FORMAT_XLS); xDocSh->DoHardRecalc(); ScDocShellRef xDocSh2 = saveAndReload(*xDocSh, FORMAT_XLS); xDocSh->DoClose(); xDocSh2->DoHardRecalc(); ScDocument& rDoc = xDocSh2->GetDocument(); ScRangeName* pRangeName = rDoc.GetRangeName(0); CPPUNIT_ASSERT(pRangeName); CPPUNIT_ASSERT_EQUAL(size_t(2), pRangeName->size()); OUString aFormula = rDoc.GetFormula(3, 11, 0); CPPUNIT_ASSERT_EQUAL(OUString("=SUM(local_name2)"), aFormula); ASSERT_DOUBLES_EQUAL(14.0, rDoc.GetValue(3, 11, 0)); aFormula = rDoc.GetFormula(6, 4, 0); CPPUNIT_ASSERT_EQUAL(OUString("=local_name1"), aFormula); xDocSh2->DoClose(); } void ScExportTest::testRelativeNamedExpressionsXLS() { ScDocShellRef xDocSh = loadDoc(u"tdf113991_relativeNamedRanges.", FORMAT_ODS); xDocSh->DoHardRecalc(); ScDocShellRef xDocSh2 = saveAndReload(*xDocSh, FORMAT_XLS); xDocSh->DoClose(); xDocSh2->DoHardRecalc(); ScDocument& rDoc = xDocSh2->GetDocument(); // Sheet1:G3 ScAddress aPos(6, 2, 0); CPPUNIT_ASSERT_EQUAL(1.0, rDoc.GetValue(aPos)); ASSERT_FORMULA_EQUAL(rDoc, aPos, "single_cell_A3", nullptr); // Sheet2:F6 aPos = ScAddress(5, 5, 1); CPPUNIT_ASSERT_EQUAL(18.0, rDoc.GetValue(aPos)); ASSERT_FORMULA_EQUAL(rDoc, aPos, "SUM(test_conflict)", nullptr); // Sheet2:H3 aPos = ScAddress(7, 2, 1); CPPUNIT_ASSERT_EQUAL(10.0, rDoc.GetValue(aPos)); ASSERT_FORMULA_EQUAL(rDoc, aPos, "single_global_A3", nullptr); // Sheet2:H6 aPos = ScAddress(7, 5, 1); CPPUNIT_ASSERT_EQUAL(75.0, rDoc.GetValue(aPos)); ASSERT_FORMULA_EQUAL(rDoc, aPos, "SUM(A6:F6)", nullptr); xDocSh2->DoClose(); } void ScExportTest::testSheetTextBoxHyperlinkXLSX() { ScDocShellRef xShell = loadDoc(u"textbox-hyperlink.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/drawings/drawing1.xml", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); assertXPath( pDoc, "/xdr:wsDr[1]/xdr:twoCellAnchor[1]/xdr:sp[1]/xdr:nvSpPr[1]/xdr:cNvPr[1]/a:hlinkClick[1]", 1); xDocSh->DoClose(); } void ScExportTest::testFontSizeXLSX() { ScDocShellRef xDocSh = loadDoc(u"fontSize.", FORMAT_XLSX); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/drawings/drawing1.xml", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); OUString fontSize = getXPath( pDoc, "/xdr:wsDr/xdr:twoCellAnchor/xdr:sp[1]/xdr:txBody/a:p[1]/a:r[1]/a:rPr", "sz"); // make sure that the font size is 18 CPPUNIT_ASSERT_EQUAL(OUString("1800"), fontSize); xDocSh->DoClose(); } void ScExportTest::testSheetCharacterKerningSpaceXLSX() { ScDocShellRef xShell = loadDoc(u"textbox-CharKerningSpace.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/drawings/drawing1.xml", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); OUString CharKerningSpace = getXPath( pDoc, "/xdr:wsDr[1]/xdr:twoCellAnchor[1]/xdr:sp[1]/xdr:txBody[1]/a:p[1]/a:r[1]/a:rPr[1]", "spc"); // make sure that the CharKerning is 1997. CPPUNIT_ASSERT_EQUAL(OUString("1997"), CharKerningSpace); xDocSh->DoClose(); } void ScExportTest::testSheetCondensedCharacterSpaceXLSX() { ScDocShellRef xShell = loadDoc(u"textbox-CondensedCharacterSpace.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/drawings/drawing1.xml", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); OUString CondensedCharSpace = getXPath( pDoc, "/xdr:wsDr[1]/xdr:twoCellAnchor[1]/xdr:sp[1]/xdr:txBody[1]/a:p[1]/a:r[1]/a:rPr[1]", "spc"); // make sure that the CondensedCharSpace is -1002. CPPUNIT_ASSERT_EQUAL(OUString("-1002"), CondensedCharSpace); xDocSh->DoClose(); } void ScExportTest::testTextUnderlineColorXLSX() { ScDocShellRef xDocSh = loadDoc(u"underlineColor.", FORMAT_XLSX); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/drawings/drawing1.xml", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); // Make sure the underline type is double line assertXPath(pDoc, "/xdr:wsDr/xdr:twoCellAnchor[1]/xdr:sp[1]/xdr:txBody/a:p[1]/a:r[1]/a:rPr", "u", "dbl"); assertXPath(pDoc, "/xdr:wsDr/xdr:twoCellAnchor[1]/xdr:sp[1]/xdr:txBody/a:p[1]/a:r[1]/a:rPr", "b", "1"); // Make sure that the underline color is RED assertXPath(pDoc, "/xdr:wsDr/xdr:twoCellAnchor[1]/xdr:sp[1]/xdr:txBody/a:p[1]/a:r[1]/a:rPr/a:uFill/" "a:solidFill/a:srgbClr", "val", "ff0000"); // Make sure the underline type is drawn with heavy line assertXPath(pDoc, "/xdr:wsDr/xdr:twoCellAnchor[2]/xdr:sp[1]/xdr:txBody/a:p[1]/a:r[1]/a:rPr", "u", "heavy"); // tdf#104219 Make sure that uFill is not existing and uFillTx is set. // It mean that color is automatic, should be the same color as the text. assertXPath( pDoc, "/xdr:wsDr/xdr:twoCellAnchor[2]/xdr:sp[1]/xdr:txBody/a:p[1]/a:r[1]/a:rPr/a:uFill", 0); assertXPath(pDoc, "/xdr:wsDr/xdr:twoCellAnchor[2]/xdr:sp[1]/xdr:txBody/a:p[1]/a:r[1]/a:rPr/a:uFillTx", 1); xDocSh->DoClose(); } void ScExportTest::testSheetRunParagraphPropertyXLSX() { ScDocShellRef xShell = loadDoc(u"TextColor.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/sharedStrings.xml", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); OUString aColor = getXPath(pDoc, "/x:sst/x:si/x:r[1]/x:rPr[1]/x:color", "rgb"); CPPUNIT_ASSERT_EQUAL(OUString("FFFF0000"), aColor); xDocSh->DoClose(); } void ScExportTest::testPreserveTextWhitespaceXLSX() { ScDocShellRef xShell = loadDoc(u"preserve-whitespace.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/sharedStrings.xml", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); assertXPath(pDoc, "/x:sst/x:si/x:t", "space", "preserve"); xDocSh->DoClose(); } void ScExportTest::testPreserveTextWhitespace2XLSX() { ScDocShellRef xShell = loadDoc(u"preserve_space.", FORMAT_XLSX); ScDocShellRef xDocSh = saveAndReload(*xShell, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh.is()); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/sharedStrings.xml", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); assertXPath(pDoc, "/x:sst/x:si[1]/x:t", "space", "preserve"); assertXPath(pDoc, "/x:sst/x:si[2]/x:r[1]/x:t", "space", "preserve"); assertXPath(pDoc, "/x:sst/x:si[2]/x:r[2]/x:t", "space", "preserve"); xDocSh->DoClose(); } void ScExportTest::testHiddenShapeXLS() { ScDocShellRef xDocSh = loadDoc(u"hiddenShape.", FORMAT_XLS); ScDocument& rDoc = xDocSh->GetDocument(); CPPUNIT_ASSERT(rDoc.GetTableCount() > 0); ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer(); SdrPage* pPage = pDrawLayer->GetPage(0); CPPUNIT_ASSERT(pPage); SdrObject* pObj = pPage->GetObj(0); CPPUNIT_ASSERT(pObj); CPPUNIT_ASSERT_MESSAGE("Drawing object should not be visible.", !pObj->IsVisible()); CPPUNIT_ASSERT_MESSAGE("Drawing object should not be printable.", !pObj->IsPrintable()); xDocSh->DoClose(); } void ScExportTest::testHiddenShapeXLSX() { ScDocShellRef xDocSh = loadDoc(u"hiddenShape.", FORMAT_XLSX); ScDocument& rDoc = xDocSh->GetDocument(); CPPUNIT_ASSERT(rDoc.GetTableCount() > 0); ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer(); SdrPage* pPage = pDrawLayer->GetPage(0); CPPUNIT_ASSERT(pPage); SdrObject* pObj = pPage->GetObj(0); CPPUNIT_ASSERT(pObj); CPPUNIT_ASSERT_MESSAGE("Drawing object should not be visible.", !pObj->IsVisible()); CPPUNIT_ASSERT_MESSAGE("Drawing object should not be printable.", !pObj->IsPrintable()); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/drawings/drawing1.xml", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); assertXPath(pDoc, "/xdr:wsDr/xdr:twoCellAnchor/xdr:sp[1]/xdr:nvSpPr/xdr:cNvPr", "hidden", "1"); xDocSh->DoClose(); } void ScExportTest::testShapeAutofitXLSX() { ScDocShellRef xDocSh = loadDoc(u"testShapeAutofit.", FORMAT_XLSX); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/drawings/drawing1.xml", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); // TextAutoGrowHeight --> "Fit height to text" / "Resize shape to fit text" --> true assertXPath(pDoc, "/xdr:wsDr/xdr:twoCellAnchor[1]/xdr:sp/xdr:txBody/a:bodyPr/a:spAutoFit", 1); // TextAutoGrowHeight --> "Fit height to text" / "Resize shape to fit text" --> false assertXPath(pDoc, "/xdr:wsDr/xdr:twoCellAnchor[2]/xdr:sp/xdr:txBody/a:bodyPr/a:noAutofit", 1); xDocSh->DoClose(); } void ScExportTest::testHyperlinkXLSX() { ScDocShellRef xDocSh = loadDoc(u"hyperlink.", FORMAT_XLSX); xmlDocUniquePtr pDoc = XPathHelper::parseExport2( *this, *xDocSh, m_xSFactory, "xl/drawings/_rels/drawing1.xml.rels", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); assertXPath(pDoc, "/rels:Relationships/rels:Relationship", "Target", "#Sheet2!A1"); xDocSh->DoClose(); } void ScExportTest::testMoveCellAnchoredShapesODS() { ScDocShellRef xDocSh = loadDoc(u"move-cell-anchored-shapes.", FORMAT_ODS); // There are two cell-anchored objects on the first sheet. ScDocument& rDoc = xDocSh->GetDocument(); CPPUNIT_ASSERT_MESSAGE("There should be at least one sheet.", rDoc.GetTableCount() > 0); ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer(); SdrPage* pPage = pDrawLayer->GetPage(0); CPPUNIT_ASSERT_MESSAGE("draw page for sheet 1 should exist.", pPage); SdrObject* pObj = pPage->GetObj(0); CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj); // Check cell anchor state ScAnchorType oldType = ScDrawLayer::GetAnchorType(*pObj); CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to get anchor type", SCA_CELL_RESIZE, oldType); // Get anchor data ScDrawObjData* pData = ScDrawLayer::GetObjData(pObj); CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData); CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pData->getShapeRect().IsEmpty()); ScAddress aDataStart = pData->maStart; ScAddress aDataEnd = pData->maEnd; // Get non rotated anchor data ScDrawObjData* pNData = ScDrawLayer::GetNonRotatedObjData(pObj); CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData); CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pNData->getShapeRect().IsEmpty()); ScAddress aNDataStart = pNData->maStart; ScAddress aNDataEnd = pNData->maEnd; CPPUNIT_ASSERT_EQUAL(aDataStart, aNDataStart); CPPUNIT_ASSERT_EQUAL(aDataEnd, aNDataEnd); // Insert 2 rows. rDoc.InsertRow(ScRange(0, aDataStart.Row() - 1, 0, rDoc.MaxCol(), aDataStart.Row(), 0)); // Get anchor data pData = ScDrawLayer::GetObjData(pObj); CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData); CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pData->getShapeRect().IsEmpty()); // Get non rotated anchor data pNData = ScDrawLayer::GetNonRotatedObjData(pObj); CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData); CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pNData->getShapeRect().IsEmpty()); // Check if data has moved to new rows CPPUNIT_ASSERT_EQUAL(pData->maStart.Row(), aDataStart.Row() + 2); CPPUNIT_ASSERT_EQUAL(pData->maEnd.Row(), aDataEnd.Row() + 2); CPPUNIT_ASSERT_EQUAL(pNData->maStart.Row(), aNDataStart.Row() + 2); CPPUNIT_ASSERT_EQUAL(pNData->maEnd.Row(), aNDataEnd.Row() + 2); // Save the anchor data aDataStart = pData->maStart; aDataEnd = pData->maEnd; aNDataStart = pNData->maStart; aNDataEnd = pNData->maEnd; // Save the document and load again to check anchor persist ScDocShellRef xDocSh1 = saveAndReload(*xDocSh, FORMAT_ODS); // There are two cell-anchored objects on the first sheet. ScDocument& rDoc1 = xDocSh1->GetDocument(); CPPUNIT_ASSERT_MESSAGE("There should be at least one sheet.", rDoc1.GetTableCount() > 0); pDrawLayer = rDoc1.GetDrawLayer(); pPage = pDrawLayer->GetPage(0); CPPUNIT_ASSERT_MESSAGE("draw page for sheet 1 should exist.", pPage); pObj = pPage->GetObj(0); CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj); // Check cell anchor state oldType = ScDrawLayer::GetAnchorType(*pObj); CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to get anchor type", SCA_CELL_RESIZE, oldType); // Get anchor data pData = ScDrawLayer::GetObjData(pObj); CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData); CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pData->getShapeRect().IsEmpty()); // Get non rotated anchor data pNData = ScDrawLayer::GetNonRotatedObjData(pObj); CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData); CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pNData->getShapeRect().IsEmpty()); // Check if data after save it CPPUNIT_ASSERT_EQUAL(pData->maStart, aDataStart); CPPUNIT_ASSERT_EQUAL(pData->maEnd, aDataEnd); CPPUNIT_ASSERT_EQUAL(pNData->maStart, aNDataStart); CPPUNIT_ASSERT_EQUAL(pNData->maEnd, aNDataEnd); // Insert a column. rDoc1.InsertCol(ScRange(aDataStart.Col(), 0, 0, aDataStart.Col(), rDoc1.MaxRow(), 0)); // Get anchor data pData = ScDrawLayer::GetObjData(pObj); CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData); CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pData->getShapeRect().IsEmpty()); // Get non rotated anchor data pNData = ScDrawLayer::GetNonRotatedObjData(pObj); CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData); CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pNData->getShapeRect().IsEmpty()); // Check if data has moved to new rows CPPUNIT_ASSERT_EQUAL(pData->maStart.Col(), SCCOL(aDataStart.Col() + 1)); CPPUNIT_ASSERT_EQUAL(pData->maEnd.Col(), SCCOL(aDataEnd.Col() + 1)); CPPUNIT_ASSERT_EQUAL(pNData->maStart.Col(), SCCOL(aNDataStart.Col() + 1)); CPPUNIT_ASSERT_EQUAL(pNData->maEnd.Col(), SCCOL(aNDataEnd.Col() + 1)); // Save the anchor data aDataStart = pData->maStart; aDataEnd = pData->maEnd; aNDataStart = pNData->maStart; aNDataEnd = pNData->maEnd; // Save the document and load again to check anchor persist ScDocShellRef xDocSh2 = saveAndReload(*xDocSh1, FORMAT_ODS); // There are two cell-anchored objects on the first sheet. ScDocument& rDoc2 = xDocSh2->GetDocument(); CPPUNIT_ASSERT_MESSAGE("There should be at least one sheet.", rDoc2.GetTableCount() > 0); pDrawLayer = rDoc2.GetDrawLayer(); pPage = pDrawLayer->GetPage(0); CPPUNIT_ASSERT_MESSAGE("draw page for sheet 1 should exist.", pPage); pObj = pPage->GetObj(0); CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj); // Check cell anchor state oldType = ScDrawLayer::GetAnchorType(*pObj); CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to get anchor type", SCA_CELL_RESIZE, oldType); // Get anchor data pData = ScDrawLayer::GetObjData(pObj); CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData); CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pData->getShapeRect().IsEmpty()); // Get non rotated anchor data pNData = ScDrawLayer::GetNonRotatedObjData(pObj); CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData); CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pNData->getShapeRect().IsEmpty()); // Check if data after save it CPPUNIT_ASSERT_EQUAL(pData->maStart, aDataStart); CPPUNIT_ASSERT_EQUAL(pData->maEnd, aDataEnd); CPPUNIT_ASSERT_EQUAL(pNData->maStart, aNDataStart); CPPUNIT_ASSERT_EQUAL(pNData->maEnd, aNDataEnd); xDocSh2->DoClose(); } void ScExportTest::testConditionalFormatRangeListXLSX() { ScDocShellRef xDocSh = loadDoc(u"conditionalformat_rangelist.", FORMAT_ODS); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/worksheets/sheet1.xml", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); assertXPath(pDoc, "//x:conditionalFormatting", "sqref", "F4 F10"); xDocSh->DoClose(); } void ScExportTest::testConditionalFormatContainsTextXLSX() { ScDocShellRef xDocSh = loadDoc(u"conditionalformat_containstext.", FORMAT_ODS); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/worksheets/sheet1.xml", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); assertXPathContent(pDoc, "//x:conditionalFormatting/x:cfRule/x:formula", "NOT(ISERROR(SEARCH(\"test\",A1)))"); xDocSh->DoClose(); } void ScExportTest::testConditionalFormatPriorityCheckXLSX() { ScDocShellRef xDocSh = loadDoc(u"conditional_fmt_checkpriority.", FORMAT_XLSX); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/worksheets/sheet1.xml", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); constexpr bool bHighPriorityExtensionA1 = true; // Should A1's extension cfRule has higher priority than normal cfRule ? constexpr bool bHighPriorityExtensionA3 = false; // Should A3's extension cfRule has higher priority than normal cfRule ? size_t nA1NormalPriority = 0; size_t nA1ExtPriority = 0; size_t nA3NormalPriority = 0; size_t nA3ExtPriority = 0; for (size_t nIdx = 1; nIdx <= 2; ++nIdx) { OString aIdx = OString::number(nIdx); OUString aCellAddr = getXPath(pDoc, "//x:conditionalFormatting[" + aIdx + "]", "sqref"); OUString aPriority = getXPath(pDoc, "//x:conditionalFormatting[" + aIdx + "]/x:cfRule", "priority"); CPPUNIT_ASSERT_MESSAGE("conditionalFormatting sqref must be either A1 or A3", aCellAddr == "A1" || aCellAddr == "A3"); if (aCellAddr == "A1") nA1NormalPriority = aPriority.toUInt32(); else nA3NormalPriority = aPriority.toUInt32(); aCellAddr = getXPathContent( pDoc, "//x:extLst/x:ext[1]/x14:conditionalFormattings/x14:conditionalFormatting[" + aIdx + "]/xm:sqref"); aPriority = getXPath(pDoc, "//x:extLst/x:ext[1]/x14:conditionalFormattings/x14:conditionalFormatting[" + aIdx + "]/x14:cfRule", "priority"); CPPUNIT_ASSERT_MESSAGE("x14:conditionalFormatting sqref must be either A1 or A3", aCellAddr == "A1" || aCellAddr == "A3"); if (aCellAddr == "A1") nA1ExtPriority = aPriority.toUInt32(); else nA3ExtPriority = aPriority.toUInt32(); } CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong priorities for A1", bHighPriorityExtensionA1, nA1ExtPriority < nA1NormalPriority); CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong priorities for A3", bHighPriorityExtensionA3, nA3ExtPriority < nA3NormalPriority); xDocSh->DoClose(); } void ScExportTest::testConditionalFormatOriginXLSX() { ScDocShellRef xDocSh = loadDoc(u"conditional_fmt_origin.", FORMAT_XLSX); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/worksheets/sheet1.xml", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); // tdf#124953 : The range-list is B3:C6 F1:G2, origin address in the formula should be B1, not B3. OUString aFormula = getXPathContent(pDoc, "//x:conditionalFormatting/x:cfRule/x:formula"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong origin address in formula", OUString("NOT(ISERROR(SEARCH(\"BAC\",B1)))"), aFormula); xDocSh->DoClose(); } void ScExportTest::testTdf113646() { ScDocShellRef xShell = loadDoc(u"tdf113646.", FORMAT_ODS); auto pXPathFile = ScBootstrapFixture::exportTo(*xShell, FORMAT_XLSX); xmlDocUniquePtr pSheet = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/styles.xml"); CPPUNIT_ASSERT(pSheet); assertXPath(pSheet, "/x:styleSheet/x:dxfs/x:dxf/x:font/x:sz", "val", "36"); xShell->DoClose(); } void ScExportTest::testDateStandardfilterXLSX() { // XLSX Roundtripping standard filter with date ScDocShellRef xDocSh = loadDoc(u"tdf142607.", FORMAT_ODS); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/worksheets/sheet1.xml", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); assertXPath(pDoc, "//x:autoFilter", "ref", "A1:B6"); assertXPath(pDoc, "//x:autoFilter/x:filterColumn/x:filters/x:dateGroupItem[1]", "day", "03"); assertXPath(pDoc, "//x:autoFilter/x:filterColumn/x:filters/x:dateGroupItem[1]", "month", "12"); assertXPath(pDoc, "//x:autoFilter/x:filterColumn/x:filters/x:dateGroupItem[1]", "year", "2011"); assertXPath(pDoc, "//x:autoFilter/x:filterColumn/x:filters/x:dateGroupItem[1]", "dateTimeGrouping", "day"); xDocSh->DoClose(); } CPPUNIT_TEST_SUITE_REGISTRATION(ScExportTest); CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */