From 267c6f2ac71f92999e969232431ba04678e7437e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 07:54:39 +0200 Subject: Adding upstream version 4:24.2.0. Signed-off-by: Daniel Baumann --- sw/qa/extras/odfexport/odfexport2.cxx | 1133 +++++++++++++++++++++++++++++++++ 1 file changed, 1133 insertions(+) create mode 100644 sw/qa/extras/odfexport/odfexport2.cxx (limited to 'sw/qa/extras/odfexport/odfexport2.cxx') diff --git a/sw/qa/extras/odfexport/odfexport2.cxx b/sw/qa/extras/odfexport/odfexport2.cxx new file mode 100644 index 0000000000..6db396c40d --- /dev/null +++ b/sw/qa/extras/odfexport/odfexport2.cxx @@ -0,0 +1,1133 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Test : public SwModelTestBase +{ +public: + Test() : SwModelTestBase("/sw/qa/extras/odfexport/data/", "writer8") {} +}; + +CPPUNIT_TEST_FIXTURE(Test, testEmbeddedFontProps) +{ + loadAndReload("embedded-font-props.odt"); + CPPUNIT_ASSERT_EQUAL(1, getPages()); +#if !defined(MACOSX) + // Test that font style/weight of embedded fonts is exposed. + // Test file is a normal ODT, except EmbedFonts is set to true in settings.xml. + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // These failed, the attributes were missing. + assertXPath(pXmlDoc, "//style:font-face[@style:name='Liberation Serif']/svg:font-face-src/svg:font-face-uri[1]"_ostr, "font-style"_ostr, "normal"); + assertXPath(pXmlDoc, "//style:font-face[@style:name='Liberation Serif']/svg:font-face-src/svg:font-face-uri[1]"_ostr, "font-weight"_ostr, "normal"); + assertXPath(pXmlDoc, "//style:font-face[@style:name='Liberation Serif']/svg:font-face-src/svg:font-face-uri[2]"_ostr, "font-style"_ostr, "normal"); + assertXPath(pXmlDoc, "//style:font-face[@style:name='Liberation Serif']/svg:font-face-src/svg:font-face-uri[2]"_ostr, "font-weight"_ostr, "bold"); + assertXPath(pXmlDoc, "//style:font-face[@style:name='Liberation Serif']/svg:font-face-src/svg:font-face-uri[3]"_ostr, "font-style"_ostr, "italic"); + assertXPath(pXmlDoc, "//style:font-face[@style:name='Liberation Serif']/svg:font-face-src/svg:font-face-uri[3]"_ostr, "font-weight"_ostr, "normal"); + assertXPath(pXmlDoc, "//style:font-face[@style:name='Liberation Serif']/svg:font-face-src/svg:font-face-uri[4]"_ostr, "font-style"_ostr, "italic"); + assertXPath(pXmlDoc, "//style:font-face[@style:name='Liberation Serif']/svg:font-face-src/svg:font-face-uri[4]"_ostr, "font-weight"_ostr, "bold"); +#endif +} + +DECLARE_ODFEXPORT_TEST(testTdf100492, "tdf100492.odt") +{ + CPPUNIT_ASSERT_EQUAL(2, getShapes()); + CPPUNIT_ASSERT_EQUAL(1, getPages()); + uno::Reference xShape = getShape(1); + CPPUNIT_ASSERT(xShape.is()); + + // Save the first shape to a SVG + uno::Reference xGraphicExporter = drawing::GraphicExportFilter::create(comphelper::getProcessComponentContext()); + uno::Reference xSourceDoc(xShape, uno::UNO_QUERY); + xGraphicExporter->setSourceDocument(xSourceDoc); + + SvMemoryStream aStream; + uno::Reference xOutputStream(new utl::OStreamWrapper(aStream)); + uno::Sequence aDescriptor( comphelper::InitPropertySequence({ + { "OutputStream", uno::Any(xOutputStream) }, + { "FilterName", uno::Any(OUString("SVG")) } + })); + xGraphicExporter->filter(aDescriptor); + aStream.Seek(STREAM_SEEK_TO_BEGIN); + + // TODO: Disabled. Parsing of SVG gives just root node without any children. + // Reason of such behavior unclear. So XPATH assert fails. + + // Parse resulting SVG as XML file. + // xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + + // Check amount of paths required to draw an arrow. + // Since there are still some empty paths in output test can fail later. There are just two + // really used and visible paths. + //assertXPath(pXmlDoc, "/svg/path", 4); +} + +DECLARE_ODFEXPORT_TEST(testTdf77961, "tdf77961.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + uno::Reference xStyles(getStyles("PageStyles")); + uno::Reference xStyle(xStyles->getByName("Standard"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL( false , getProperty(xStyle, "GridDisplay")); + CPPUNIT_ASSERT_EQUAL( false , getProperty(xStyle, "GridPrint")); +} + +DECLARE_ODFEXPORT_TEST(testReferenceLanguage, "referencelanguage.odt") +{ + CPPUNIT_ASSERT_EQUAL(2, getPages()); + // Test loext:reference-language attribute of reference fields + // (used from LibreOffice 6.1, and proposed for next ODF) + OUString const aFieldTexts[] = { "A 2", "Az Isten", "Az 50-esek", + "A 2018-asok", "Az egyebek", "A fejezetek", + u"Az „Őseinket...”"_ustr, "a 2", + "Az v", "az 1", "Az e)", "az 1", + "Az (5)", "az 1", "A 2", "az 1" }; + uno::Reference xTextFieldsSupplier(mxComponent, uno::UNO_QUERY); + // update "A (4)" to "Az (5)" + uno::Reference(xTextFieldsSupplier->getTextFields(), uno::UNO_QUERY_THROW)->refresh(); + + uno::Reference xFieldsAccess(xTextFieldsSupplier->getTextFields()); + uno::Reference xFields(xFieldsAccess->createEnumeration()); + + uno::Any aHu(OUString("Hu")); + uno::Any ahu(OUString("hu")); + for (auto const& sFieldText : aFieldTexts) + { + uno::Any aField = xFields->nextElement(); + uno::Reference xServiceInfo(aField, uno::UNO_QUERY); + if (xServiceInfo->supportsService("com.sun.star.text.textfield.GetReference")) + { + uno::Reference xPropertySet(aField, uno::UNO_QUERY); + uno::Any aLang = xPropertySet->getPropertyValue("ReferenceFieldLanguage"); + CPPUNIT_ASSERT_EQUAL(true, aLang == aHu || aLang == ahu); + uno::Reference xField(aField, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sFieldText, xField->getAnchor()->getString()); + } + } +} + +CPPUNIT_TEST_FIXTURE(Test, testRubyPosition) +{ + loadAndReload("ruby-position.odt"); + CPPUNIT_ASSERT_EQUAL(1, getPages()); + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + + assertXPath(pXmlDoc, "//style:style[@style:family='ruby']/style:ruby-properties[@loext:ruby-position='inter-character']"_ostr, 1); + assertXPath(pXmlDoc, "//style:style[@style:family='ruby']/style:ruby-properties[@style:ruby-position='below']"_ostr, 1); +} + +DECLARE_ODFEXPORT_TEST(testAllowOverlap, "allow-overlap.odt") +{ + CPPUNIT_ASSERT_EQUAL(2, getShapes()); + CPPUNIT_ASSERT_EQUAL(1, getPages()); + uno::Reference xShape = getShape(1); + // Without the accompanying fix in place, this test would have failed with: + // - Expression: !getProperty(xShape, "AllowOverlap") + // i.e. the custom AllowOverlap=false shape property was lost on import/export. + CPPUNIT_ASSERT(!getProperty(xShape, "AllowOverlap")); + xShape = getShape(2); + CPPUNIT_ASSERT(!getProperty(xShape, "AllowOverlap")); +} + +CPPUNIT_TEST_FIXTURE(Test, testSignatureLineProperties) +{ + loadAndReload("signatureline-properties.fodt"); + uno::Reference xShape = getShape(1); + CPPUNIT_ASSERT(xShape.is()); + + CPPUNIT_ASSERT_EQUAL(true, getProperty(xShape, "IsSignatureLine")); + CPPUNIT_ASSERT_EQUAL(OUString("{3C24159B-3B98-4F60-AB52-00E7721758E9}"), + getProperty(xShape, "SignatureLineId")); + CPPUNIT_ASSERT_EQUAL(OUString("John Doe"), + getProperty(xShape, "SignatureLineSuggestedSignerName")); + CPPUNIT_ASSERT_EQUAL(OUString("Farmer"), + getProperty(xShape, "SignatureLineSuggestedSignerTitle")); + CPPUNIT_ASSERT_EQUAL(OUString("john@farmers.org"), + getProperty(xShape, "SignatureLineSuggestedSignerEmail")); + CPPUNIT_ASSERT_EQUAL(OUString("Please farm here."), + getProperty(xShape, "SignatureLineSigningInstructions")); + CPPUNIT_ASSERT_EQUAL(true, getProperty(xShape, "SignatureLineCanAddComment")); + CPPUNIT_ASSERT_EQUAL(true, getProperty(xShape, "SignatureLineShowSignDate")); + + // tdf#130917 This needs to be always set when importing a doc, ooxml export expects it. + uno::Reference xUnsignedGraphic; + uno::Reference xProps(xShape, uno::UNO_QUERY); + xProps->getPropertyValue("SignatureLineUnsignedImage") >>= xUnsignedGraphic; + CPPUNIT_ASSERT_EQUAL(true, xUnsignedGraphic.is()); +} + +DECLARE_ODFEXPORT_TEST(testQrCodeGenProperties, "qrcode-properties.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getShapes()); + CPPUNIT_ASSERT_EQUAL(1, getPages()); + uno::Reference xShape = getShape(1); + CPPUNIT_ASSERT(xShape.is()); + + css::drawing::BarCode aBarCode = getProperty(xShape, "BarCodeProperties"); + + CPPUNIT_ASSERT_EQUAL(OUString("www.libreoffice.org"), + aBarCode.Payload); + CPPUNIT_ASSERT_EQUAL(css::drawing::BarCodeErrorCorrection::LOW, + aBarCode.ErrorCorrection); + CPPUNIT_ASSERT_EQUAL(sal_Int32(5), + aBarCode.Border); +} + +DECLARE_ODFEXPORT_TEST(testChapterNumberingNewLine, "chapter-number-new-line.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + uno::Reference xNumberingSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xNumberingRules = xNumberingSupplier->getChapterNumberingRules(); + comphelper::SequenceAsHashMap hashMap(xNumberingRules->getByIndex(0)); + + //This failed Actual Value was LISTTAB instead of NEWLINE + CPPUNIT_ASSERT_EQUAL( + sal_Int16(SvxNumberFormat::NEWLINE), hashMap["LabelFollowedBy"].get()); +} + +DECLARE_ODFEXPORT_TEST(testSpellOutNumberingTypes, "spellout-numberingtypes.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + // ordinal indicator, ordinal and cardinal number numbering styles (from LibreOffice 6.1) + OUString const aFieldTexts[] = { "1st", "Erste", "Eins", "1.", "Premier", "Un", u"1ᵉʳ"_ustr, "First", "One" }; + // fallback for old platforms without std::codecvt and std::regex supports + OUString const aFieldTextFallbacks[] = { "Ordinal-number 1", "Ordinal 1", "1" }; + uno::Reference xTextFieldsSupplier(mxComponent, uno::UNO_QUERY); + // update text field content + uno::Reference(xTextFieldsSupplier->getTextFields(), uno::UNO_QUERY_THROW)->refresh(); + + uno::Reference xFieldsAccess(xTextFieldsSupplier->getTextFields()); + uno::Reference xFields(xFieldsAccess->createEnumeration()); + + for (size_t i = 0; i < SAL_N_ELEMENTS(aFieldTexts); i++) + { + uno::Any aField = xFields->nextElement(); + uno::Reference xServiceInfo(aField, uno::UNO_QUERY); + if (xServiceInfo->supportsService("com.sun.star.text.textfield.PageNumber")) + { + uno::Reference xField(aField, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(true, aFieldTexts[i].equals(xField->getAnchor()->getString()) || + aFieldTextFallbacks[i%3].equals(xField->getAnchor()->getString())); + } + } +} + +DECLARE_ODFEXPORT_TEST(tdf133507_contextualSpacingSection, "tdf133507_contextualSpacingSection.odt") +{ + // Previously this was one page (no UL spacing) or three pages (every para had spacing) + CPPUNIT_ASSERT_EQUAL(2, getPages()); +} + +// MAILMERGE Add conditional to expand / collapse bookmarks +DECLARE_ODFEXPORT_TEST(tdf101856_overlapped, "tdf101856_overlapped.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + // get bookmark interface + uno::Reference xBookmarksSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xBookmarksByIdx(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY); + uno::Reference xBookmarksByName = xBookmarksSupplier->getBookmarks(); + + // check: we have 2 bookmarks + CPPUNIT_ASSERT_EQUAL(static_cast(2), xBookmarksByIdx->getCount()); + CPPUNIT_ASSERT(xBookmarksByName->hasByName("BookmarkNonHidden")); + CPPUNIT_ASSERT(xBookmarksByName->hasByName("BookmarkHidden")); + + // + uno::Reference xBookmark1(xBookmarksByName->getByName("BookmarkNonHidden"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty(xBookmark1, UNO_NAME_BOOKMARK_CONDITION)); + CPPUNIT_ASSERT_EQUAL(false, getProperty(xBookmark1, UNO_NAME_BOOKMARK_HIDDEN)); + + // + uno::Reference xBookmark2(xBookmarksByName->getByName("BookmarkHidden"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty(xBookmark2, UNO_NAME_BOOKMARK_CONDITION)); + CPPUNIT_ASSERT_EQUAL(true, getProperty(xBookmark2, UNO_NAME_BOOKMARK_HIDDEN)); +} + +// MAILMERGE Add conditional to expand / collapse bookmarks +DECLARE_ODFEXPORT_TEST(tdf101856, "tdf101856.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + // get bookmark interface + uno::Reference xBookmarksSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xBookmarksByIdx(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY); + uno::Reference xBookmarksByName = xBookmarksSupplier->getBookmarks(); + + // check: we have 2 bookmarks + CPPUNIT_ASSERT_EQUAL(static_cast(5), xBookmarksByIdx->getCount()); + CPPUNIT_ASSERT(xBookmarksByName->hasByName("BookmarkVisible")); + CPPUNIT_ASSERT(xBookmarksByName->hasByName("BookmarkHidden")); + CPPUNIT_ASSERT(xBookmarksByName->hasByName("BookmarkVisibleWithCondition")); + CPPUNIT_ASSERT(xBookmarksByName->hasByName("BookmarkNotHiddenWithCondition")); + CPPUNIT_ASSERT(xBookmarksByName->hasByName("BookmarkHiddenWithCondition")); + + // + uno::Reference xBookmark1(xBookmarksByName->getByName("BookmarkVisible"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty(xBookmark1, UNO_NAME_BOOKMARK_CONDITION)); + CPPUNIT_ASSERT_EQUAL(false, getProperty(xBookmark1, UNO_NAME_BOOKMARK_HIDDEN)); + + // + uno::Reference xBookmark2(xBookmarksByName->getByName("BookmarkHidden"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty(xBookmark2, UNO_NAME_BOOKMARK_CONDITION)); + CPPUNIT_ASSERT_EQUAL(true, getProperty(xBookmark2, UNO_NAME_BOOKMARK_HIDDEN)); + + // + uno::Reference xBookmark3(xBookmarksByName->getByName("BookmarkVisibleWithCondition"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("0==1"), getProperty(xBookmark3, UNO_NAME_BOOKMARK_CONDITION)); + CPPUNIT_ASSERT_EQUAL(true, getProperty(xBookmark3, UNO_NAME_BOOKMARK_HIDDEN)); + + // + // + // The following test doesn't work, while during output in the case of loext:hidden="false". + // no additional parameters are written. Implementation should be reviewed. + // +// uno::Reference xBookmark4(xBookmarksByName->getByName("BookmarkNotHiddenWithCondition"), uno::UNO_QUERY); +// CPPUNIT_ASSERT_EQUAL(OUString("1==1"), getProperty(xBookmark4, UNO_NAME_BOOKMARK_CONDITION)); +// CPPUNIT_ASSERT_EQUAL(false, getProperty(xBookmark4, UNO_NAME_BOOKMARK_HIDDEN)); + + // + uno::Reference xBookmark5(xBookmarksByName->getByName("BookmarkHiddenWithCondition"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("1==1"), getProperty(xBookmark5, UNO_NAME_BOOKMARK_CONDITION)); + CPPUNIT_ASSERT_EQUAL(true, getProperty(xBookmark5, UNO_NAME_BOOKMARK_HIDDEN)); +} + +DECLARE_ODFEXPORT_TEST(tdf118502, "tdf118502.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getShapes()); + CPPUNIT_ASSERT_EQUAL(1, getPages()); + uno::Reference xShape = getShape(1); + // Make sure the replacement graphic is still there + // (was gone because the original graphic was not recognized during load) + auto xReplacementGraphic + = getProperty>(xShape, "ReplacementGraphic"); + CPPUNIT_ASSERT(xReplacementGraphic.is()); +} + +CPPUNIT_TEST_FIXTURE(Test, tdf99631) +{ + loadAndReload("tdf99631.docx"); + // check import of VisualArea settings of the embedded XLSX OLE objects + xmlDocUniquePtr pXmlDoc = parseExport("Object 1/settings.xml"); + assertXPathContent(pXmlDoc, "//config:config-item[@config:name='VisibleAreaWidth']"_ostr, "4516"); + assertXPathContent(pXmlDoc, "//config:config-item[@config:name='VisibleAreaHeight']"_ostr, "903"); + + xmlDocUniquePtr pXmlDoc2 = parseExport("Object 2/settings.xml"); + assertXPathContent(pXmlDoc2, "//config:config-item[@config:name='VisibleAreaWidth']"_ostr, "4516"); + assertXPathContent(pXmlDoc2, "//config:config-item[@config:name='VisibleAreaHeight']"_ostr, "1355"); +} + +CPPUNIT_TEST_FIXTURE(Test, tdf145871) +{ + loadAndReload("tdf145871.odt"); + uno::Reference xTablesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xTables(xTablesSupplier->getTextTables( ), uno::UNO_QUERY); + uno::Reference xTextTable(xTables->getByIndex(0), uno::UNO_QUERY); + uno::Reference xTableRows = xTextTable->getRows(); + + // Without the fix in place, this test would have failed with + // - Expected: 3150 + // - Actual : 5851 + CPPUNIT_ASSERT_EQUAL(sal_Int64(3150) , getProperty(xTableRows->getByIndex(0), "Height")); +} + +CPPUNIT_TEST_FIXTURE(Test, tdf128504) +{ + loadAndReload("tdf128504.docx"); + uno::Reference xPara = getParagraph(6); + uno::Reference xRun(getRun(xPara,1), uno::UNO_QUERY); + OUString unVisitedStyleName = getProperty(xRun, "UnvisitedCharStyleName"); + CPPUNIT_ASSERT(!unVisitedStyleName.equalsIgnoreAsciiCase("Internet Link")); + OUString visitedStyleName = getProperty(xRun, "VisitedCharStyleName"); + CPPUNIT_ASSERT(!visitedStyleName.equalsIgnoreAsciiCase("Visited Internet Link")); +} + +DECLARE_ODFEXPORT_TEST(tdf121658, "tdf121658.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + uno::Reference xParaStyles(getStyles("ParagraphStyles")); + uno::Reference xStyle1(xParaStyles->getByName( + "Standard"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(true, getProperty(xStyle1, "ParaHyphenationNoCaps")); +} + +DECLARE_ODFEXPORT_TEST(tdf149248, "tdf149248.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + CPPUNIT_ASSERT_EQUAL(false, getProperty(getParagraph(2), "ParaHyphenationNoLastWord")); + CPPUNIT_ASSERT_EQUAL(true, getProperty(getParagraph(4), "ParaHyphenationNoLastWord")); +} + +DECLARE_ODFEXPORT_TEST(testThemeCrash, "tdf156905.odt") +{ + // first it started to crash at import time, later at export time + CPPUNIT_ASSERT_EQUAL(4, getPages()); +} + +DECLARE_ODFEXPORT_TEST(testTdf150394, "tdf150394.odt") +{ + // crashes at import time + CPPUNIT_ASSERT_EQUAL(1, getPages()); +} + +DECLARE_ODFEXPORT_TEST(tdf149324, "tdf149324.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), getProperty(getParagraph(2), "ParaHyphenationMinWordLength")); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(7), getProperty(getParagraph(4), "ParaHyphenationMinWordLength")); +} + +DECLARE_ODFEXPORT_TEST(tdf149420, "tdf149420.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), getProperty(getParagraph(2), "ParaHyphenationZone")); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(567), getProperty(getParagraph(4), "ParaHyphenationZone")); +} + +DECLARE_ODFEXPORT_TEST(testArabicZeroNumbering, "arabic-zero-numbering.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + auto xNumberingRules + = getProperty>(getParagraph(1), "NumberingRules"); + comphelper::SequenceAsHashMap aMap(xNumberingRules->getByIndex(0)); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 64 + // - Actual : 4 + // i.e. numbering type was ARABIC, not ARABIC_ZERO. + CPPUNIT_ASSERT_EQUAL(o3tl::narrowing(style::NumberingType::ARABIC_ZERO), + aMap["NumberingType"].get()); +} + +DECLARE_ODFEXPORT_TEST(testArabicZero3Numbering, "arabic-zero3-numbering.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + auto xNumberingRules + = getProperty>(getParagraph(1), "NumberingRules"); + comphelper::SequenceAsHashMap aMap(xNumberingRules->getByIndex(0)); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 65 + // - Actual : 4 + // i.e. numbering type was ARABIC, not ARABIC_ZERO3. + CPPUNIT_ASSERT_EQUAL(o3tl::narrowing(style::NumberingType::ARABIC_ZERO3), + aMap["NumberingType"].get()); +} + +DECLARE_ODFEXPORT_TEST(testArabicZero4Numbering, "arabic-zero4-numbering.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + auto xNumberingRules + = getProperty>(getParagraph(1), "NumberingRules"); + comphelper::SequenceAsHashMap aMap(xNumberingRules->getByIndex(0)); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 66 + // - Actual : 4 + // i.e. numbering type was ARABIC, not ARABIC_ZERO4. + CPPUNIT_ASSERT_EQUAL(o3tl::narrowing(style::NumberingType::ARABIC_ZERO4), + aMap["NumberingType"].get()); +} + +DECLARE_ODFEXPORT_TEST(testArabicZero5Numbering, "arabic-zero5-numbering.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + auto xNumberingRules + = getProperty>(getParagraph(1), "NumberingRules"); + comphelper::SequenceAsHashMap aMap(xNumberingRules->getByIndex(0)); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 67 + // - Actual : 4 + // i.e. numbering type was ARABIC, not ARABIC_ZERO5. + CPPUNIT_ASSERT_EQUAL(o3tl::narrowing(style::NumberingType::ARABIC_ZERO5), + aMap["NumberingType"].get()); +} + +DECLARE_ODFEXPORT_TEST(testRovasNumbering, "rovas-numbering.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + auto xNumberingRules + = getProperty>(getParagraph(1), "NumberingRules"); + comphelper::SequenceAsHashMap aMap(xNumberingRules->getByIndex(0)); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 68 + // - Actual : 4 + // i.e. numbering type was ARABIC, not SZEKELY_ROVAS. + CPPUNIT_ASSERT_EQUAL(o3tl::narrowing(style::NumberingType::SZEKELY_ROVAS), + aMap["NumberingType"].get()); +} + +DECLARE_ODFEXPORT_TEST(testPageContentTop, "page-content-top.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getShapes()); + CPPUNIT_ASSERT_EQUAL(1, getPages()); + uno::Reference xShape(getShape(1), uno::UNO_QUERY); + sal_Int16 nExpected = text::RelOrientation::PAGE_PRINT_AREA_TOP; + CPPUNIT_ASSERT_EQUAL(nExpected, getProperty(xShape, "VertOrientRelation")); +} + +DECLARE_ODFEXPORT_TEST(testPageContentBottom, "page-content-bottom.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getShapes()); + CPPUNIT_ASSERT_EQUAL(1, getPages()); + uno::Reference xShape(getShape(1), uno::UNO_QUERY); + sal_Int16 nExpected = text::RelOrientation::PAGE_PRINT_AREA_BOTTOM; + CPPUNIT_ASSERT_EQUAL(nExpected, getProperty(xShape, "VertOrientRelation")); +} + +CPPUNIT_TEST_FIXTURE(Test, tdf124470) +{ + loadAndReload("tdf124470TableAndEmbeddedUsedFonts.odt"); + // Table styles were exported out of place, inside font-face-decls. + // Without the fix in place, this will fail already in ODF validation: + // "content.xml[2,2150]: Error: tag name "style:style" is not allowed. Possible tag names are: " + + CPPUNIT_ASSERT_EQUAL(1, getPages()); + + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + + assertXPath(pXmlDoc, "/office:document-content/office:font-face-decls/style:style"_ostr, 0); + assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/style:style[@style:family='table']"_ostr, 1); + assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/style:style[@style:family='table-column']"_ostr, 2); + assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/style:style[@style:family='paragraph']"_ostr, 1); +} + +CPPUNIT_TEST_FIXTURE(Test, tdf135942) +{ + loadAndReload("nestedTableInFooter.odt"); + // All table autostyles should be collected, including nested, and must not crash. + + CPPUNIT_ASSERT_EQUAL(1, getPages()); + + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + + assertXPath(pXmlDoc, "/office:document-styles/office:automatic-styles/style:style[@style:family='table']"_ostr, 2); +} + +CPPUNIT_TEST_FIXTURE(Test, tdf150927) +{ + // Similar to tdf135942 + + loadAndReload("table-in-frame-in-table-in-header-base.odt"); + // All table autostyles should be collected, including nested, and must not crash. + + CPPUNIT_ASSERT_EQUAL(1, getPages()); + + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + + assertXPath(pXmlDoc, "/office:document-styles/office:automatic-styles/style:style[@style:family='table']"_ostr, 2); +} + +CPPUNIT_TEST_FIXTURE(Test, tdf151100) +{ + // Similar to tdf135942 + + loadAndReload("tdf151100.docx"); + // All table autostyles should be collected, including nested, and must not crash. + + CPPUNIT_ASSERT_EQUAL(1, getPages()); + + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + + assertXPath(pXmlDoc, "/office:document-styles/office:automatic-styles/style:style[@style:family='table']"_ostr, 1); +} + +DECLARE_ODFEXPORT_TEST(testGutterLeft, "gutter-left.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + uno::Reference xPageStyle; + getStyles("PageStyles")->getByName("Standard") >>= xPageStyle; + sal_Int32 nGutterMargin{}; + xPageStyle->getPropertyValue("GutterMargin") >>= nGutterMargin; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1270 + // - Actual : 0 + // i.e. gutter margin was lost. + CPPUNIT_ASSERT_EQUAL(static_cast(1270), nGutterMargin); +} + +DECLARE_ODFEXPORT_TEST(testTdf52065_centerTabs, "testTdf52065_centerTabs.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + sal_Int32 nTabStop = parseDump("//body/txt[4]/SwParaPortion/SwLineLayout/child::*[3]"_ostr, "width"_ostr).toInt32(); + // Without the fix, the text was unseen, with a tabstop width of 64057. It should be 3057 + CPPUNIT_ASSERT(nTabStop < 4000); + CPPUNIT_ASSERT(3000 < nTabStop); + CPPUNIT_ASSERT_EQUAL(u"Pečiatka zamestnávateľa"_ustr, parseDump("//body/txt[4]/SwParaPortion/SwLineLayout/child::*[4]"_ostr, "portion"_ostr)); + + // tdf#149547: __XXX___invalid CharacterStyles should not be imported/exported + CPPUNIT_ASSERT(!getStyles("CharacterStyles")->hasByName("__XXX___invalid")); +} + +DECLARE_ODFEXPORT_TEST(testTdf104254_noHeaderWrapping, "tdf104254_noHeaderWrapping.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getShapes()); + CPPUNIT_ASSERT_EQUAL(1, getPages()); + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + + sal_Int32 nParaHeight = getXPath(pXmlDoc, "//header/txt[1]/infos/bounds"_ostr, "height"_ostr).toInt32(); + // The wrapping on header images is supposed to be ignored (since OOo for MS compat reasons), + // thus making the text run underneath the image. Before, height was 1104. Now it is 552. + CPPUNIT_ASSERT_MESSAGE("Paragraph should fit on a single line", nParaHeight < 600); +} + +DECLARE_ODFEXPORT_TEST(testTdf131025_noZerosInTable, "tdf131025_noZerosInTable.odt") +{ + uno::Reference xSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xTables = xSupplier->getTextTables(); + uno::Reference xTable(xTables->getByName("Table1"), uno::UNO_QUERY); + + uno::Reference xCell(xTable->getCellByName("C3"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("5 gp"), xCell->getString()); +} + +DECLARE_ODFEXPORT_TEST(testTdf153090, "Custom-Style-TOC.docx") +{ + uno::Reference xIndexSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xIndexes(xIndexSupplier->getDocumentIndexes()); + uno::Reference xTOC(xIndexes->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("_CustomImageCaption"), getProperty(xTOC, "CreateFromParagraphStyle")); + // tdf#153659 this was imported as "table of figures" instead of "Figure Index 1" + // thus custom settings were not retained after ToF update + CPPUNIT_ASSERT_EQUAL(OUString("Figure Index 1"), getProperty(getParagraph(1), "ParaStyleName")); + + xTOC->update(); + OUString const tocContent(xTOC->getAnchor()->getString()); + CPPUNIT_ASSERT(tocContent.indexOf("1. Abb. Ein Haus") != -1); + CPPUNIT_ASSERT(tocContent.indexOf("2. Abb.Ein Schiff!") != -1); + CPPUNIT_ASSERT(tocContent.indexOf(u"1. ábra Small house with Hungarian description category") != -1); +} + +DECLARE_ODFEXPORT_TEST(testTdf143793_noBodyWrapping, "tdf143793_noBodyWrapping.odt") +{ + CPPUNIT_ASSERT_EQUAL(2, getShapes()); + // Preserve old document wrapping. Compat "Use OOo 1.1 text wrapping around objects" + // Originally, the body text did not wrap around spill-over header images + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Fits on one page", 1, getPages() ); + + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + + sal_Int32 nParaHeight = getXPath(pXmlDoc, "//page[1]/header/txt[1]/infos/bounds"_ostr, "height"_ostr).toInt32(); + // The header text should wrap around the header image in OOo 1.1 and prior, + // thus taking up two lines instead of one. One line is 276. It should be 552. + CPPUNIT_ASSERT_MESSAGE("Header text should fill two lines", nParaHeight > 400); +} + +CPPUNIT_TEST_FIXTURE(Test, testTdf137199) +{ + loadAndReload("tdf137199.docx"); + CPPUNIT_ASSERT_EQUAL(OUString(">1<"), getProperty(getParagraph(1), "ListLabelString")); + + CPPUNIT_ASSERT_EQUAL(OUString("1)"), getProperty(getParagraph(2), "ListLabelString")); + + CPPUNIT_ASSERT_EQUAL(OUString("HELLO1WORLD!"), getProperty(getParagraph(3), "ListLabelString")); + + CPPUNIT_ASSERT_EQUAL(OUString("HELLO2WORLD!"), getProperty(getParagraph(4), "ListLabelString")); +} + +DECLARE_ODFEXPORT_TEST(testTdf143605, "tdf143605.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + // With numbering type "none" there should be just prefix & suffix + CPPUNIT_ASSERT_EQUAL(OUString("."), getProperty(getParagraph(1), "ListLabelString")); +} + +CPPUNIT_TEST_FIXTURE(Test, testTdf57317_autoListName) +{ + createSwDoc("tdf57317_autoListName.odt"); + // The list style (from styles.xml) overrides a duplicate named auto-style + //uno::Any aNumStyle = getStyles("NumberingStyles")->getByName("L1"); + //CPPUNIT_ASSERT(aNumStyle.hasValue()); + uno::Reference xPara(getParagraph(1), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString(">1<"), getProperty(xPara, "ListLabelString")); + CPPUNIT_ASSERT_EQUAL(OUString("L1"), getProperty(xPara, "NumberingStyleName")); + + dispatchCommand(mxComponent, ".uno:SelectAll", {}); + dispatchCommand(mxComponent, ".uno:DefaultBullet", {}); + + // This was failing with a duplicate auto numbering style name of L1 instead of a unique name, + // thus it was showing the same info as before the bullet modification. + saveAndReload("writer8"); + xPara.set(getParagraph(1), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty(xPara, "ListLabelString")); + + uno::Reference xLevels(xPara->getPropertyValue("NumberingRules"), + uno::UNO_QUERY); + uno::Sequence aProps; + xLevels->getByIndex(0) >>= aProps; + for (beans::PropertyValue const& rProp : std::as_const(aProps)) + { + if (rProp.Name == "BulletChar") + return; + } + CPPUNIT_FAIL("no BulletChar property"); +} + +CPPUNIT_TEST_FIXTURE(Test, testListFormatDocx) +{ + loadAndReload("listformat.docx"); + // Ensure in resulting ODT we also have not just prefix/suffix, but custom delimiters + CPPUNIT_ASSERT_EQUAL(OUString(">1<"), getProperty(getParagraph(1), "ListLabelString")); + CPPUNIT_ASSERT_EQUAL(OUString(">>1/1<<"), getProperty(getParagraph(2), "ListLabelString")); + CPPUNIT_ASSERT_EQUAL(OUString(">>1/1/1<<"), getProperty(getParagraph(3), "ListLabelString")); + CPPUNIT_ASSERT_EQUAL(OUString(">>1/1/2<<"), getProperty(getParagraph(4), "ListLabelString")); + + // Check also that in numbering styles we have num-list-format defined + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + assertXPath(pXmlDoc, "/office:document-styles/office:styles/text:list-style[@style:name='WWNum1']/" + "text:list-level-style-number[@text:level='1']"_ostr, "num-list-format"_ostr, ">%1%<"); + assertXPath(pXmlDoc, "/office:document-styles/office:styles/text:list-style[@style:name='WWNum1']/" + "text:list-level-style-number[@text:level='2']"_ostr, "num-list-format"_ostr, ">>%1%/%2%<<"); + assertXPath(pXmlDoc, "/office:document-styles/office:styles/text:list-style[@style:name='WWNum1']/" + "text:list-level-style-number[@text:level='3']"_ostr, "num-list-format"_ostr, ">>%1%/%2%/%3%<<"); + + // But for compatibility there are still prefix/suffix + assertXPath(pXmlDoc, "/office:document-styles/office:styles/text:list-style[@style:name='WWNum1']/" + "text:list-level-style-number[@text:level='1']"_ostr, "num-prefix"_ostr, ">"); + assertXPath(pXmlDoc, "/office:document-styles/office:styles/text:list-style[@style:name='WWNum1']/" + "text:list-level-style-number[@text:level='1']"_ostr, "num-suffix"_ostr, "<"); + assertXPath(pXmlDoc, "/office:document-styles/office:styles/text:list-style[@style:name='WWNum1']/" + "text:list-level-style-number[@text:level='2']"_ostr, "num-prefix"_ostr, ">>"); + assertXPath(pXmlDoc, "/office:document-styles/office:styles/text:list-style[@style:name='WWNum1']/" + "text:list-level-style-number[@text:level='2']"_ostr, "num-suffix"_ostr, "<<"); + assertXPath(pXmlDoc, "/office:document-styles/office:styles/text:list-style[@style:name='WWNum1']/" + "text:list-level-style-number[@text:level='3']"_ostr, "num-prefix"_ostr, ">>"); + assertXPath(pXmlDoc, "/office:document-styles/office:styles/text:list-style[@style:name='WWNum1']/" + "text:list-level-style-number[@text:level='3']"_ostr, "num-suffix"_ostr, "<<"); +} + +DECLARE_ODFEXPORT_TEST(testShapeWithHyperlink, "shape-with-hyperlink.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getShapes()); + CPPUNIT_ASSERT_EQUAL(1, getPages()); + if (isExported()) + { + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // Check how conversion from prefix/suffix to list format did work + assertXPath(pXmlDoc, "/office:document-content/office:body/office:text/text:p/draw:a"_ostr, + "href"_ostr, "http://shape.com/"); + } +} + +DECLARE_ODFEXPORT_TEST(testShapesHyperlink, "shapes-hyperlink.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + CPPUNIT_ASSERT_EQUAL(5, getShapes()); + uno::Reference const xPropSet1(getShape(1), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("http://libreoffice.org/"), getProperty(xPropSet1, "Hyperlink")); + + uno::Reference const xPropSet2(getShape(2), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("http://libreoffice2.org/"), getProperty(xPropSet2, "Hyperlink")); + + uno::Reference const xPropSet3(getShape(3), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("http://libreoffice3.org/"), getProperty(xPropSet3, "Hyperlink")); + + uno::Reference const xPropSet4(getShape(4), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("http://libreoffice4.org/"), getProperty(xPropSet4, "Hyperlink")); + + uno::Reference const xPropSet5(getShape(5), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("http://libreoffice5.org/"), getProperty(xPropSet5, "Hyperlink")); +} + +DECLARE_ODFEXPORT_TEST(testListFormatOdt, "listformat.odt") +{ + CPPUNIT_ASSERT_EQUAL(1, getPages()); + // Ensure in resulting ODT we also have not just prefix/suffix, but custom delimiters + CPPUNIT_ASSERT_EQUAL(OUString(">1<"), getProperty(getParagraph(1), "ListLabelString")); + CPPUNIT_ASSERT_EQUAL(OUString(">>1.1<<"), getProperty(getParagraph(2), "ListLabelString")); + CPPUNIT_ASSERT_EQUAL(OUString(">>1.1.1<<"), getProperty(getParagraph(3), "ListLabelString")); + CPPUNIT_ASSERT_EQUAL(OUString(">>1.1.2<<"), getProperty(getParagraph(4), "ListLabelString")); + + if (isExported()) + { + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + // Check how conversion from prefix/suffix to list format did work + assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/text:list-style[@style:name='L1']/" + "text:list-level-style-number[@text:level='1']"_ostr, "num-list-format"_ostr, ">%1%<"); + assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/text:list-style[@style:name='L1']/" + "text:list-level-style-number[@text:level='2']"_ostr, "num-list-format"_ostr, ">>%1%.%2%<<"); + assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/text:list-style[@style:name='L1']/" + "text:list-level-style-number[@text:level='3']"_ostr, "num-list-format"_ostr, ">>%1%.%2%.%3%<<"); + + // But for compatibility there are still prefix/suffix as they were before + assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/text:list-style[@style:name='L1']/" + "text:list-level-style-number[@text:level='1']"_ostr, "num-prefix"_ostr, ">"); + assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/text:list-style[@style:name='L1']/" + "text:list-level-style-number[@text:level='1']"_ostr, "num-suffix"_ostr, "<"); + assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/text:list-style[@style:name='L1']/" + "text:list-level-style-number[@text:level='2']"_ostr, "num-prefix"_ostr, ">>"); + assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/text:list-style[@style:name='L1']/" + "text:list-level-style-number[@text:level='2']"_ostr, "num-suffix"_ostr, "<<"); + assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/text:list-style[@style:name='L1']/" + "text:list-level-style-number[@text:level='3']"_ostr, "num-prefix"_ostr, ">>"); + assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/text:list-style[@style:name='L1']/" + "text:list-level-style-number[@text:level='3']"_ostr, "num-suffix"_ostr, "<<"); + } +} + +CPPUNIT_TEST_FIXTURE(Test, testStyleLink) +{ + // Given a document with a para and a char style that links each other, when loading that + // document: + createSwDoc("style-link.fodt"); + + // Then make sure the char style links the para one: + uno::Any aCharStyle = getStyles("CharacterStyles")->getByName("List Paragraph Char"); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: List Paragraph + // - Actual : + // i.e. the linked style was lost on import. + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph"), getProperty(aCharStyle, "LinkStyle")); + uno::Any aParaStyle = getStyles("ParagraphStyles")->getByName("List Paragraph"); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: List Paragraph Char + // - Actual : + // i.e. the linked style was lost on import. + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph Char"), getProperty(aParaStyle, "LinkStyle")); +} + +CPPUNIT_TEST_FIXTURE(Test, tdf120972) +{ + loadAndReload("table_number_format_3.docx"); + + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + OUString cDecimal(SvtSysLocale().GetLocaleData().getNumDecimalSep()[0]); + assertXPath( + pXmlDoc, + "//style:style[@style:name='P1']/style:paragraph-properties/style:tab-stops/style:tab-stop"_ostr, + "char"_ostr, cDecimal); + assertXPath( + pXmlDoc, + "//style:style[@style:name='P2']/style:paragraph-properties/style:tab-stops/style:tab-stop"_ostr, + "char"_ostr, cDecimal); +} + +DECLARE_ODFEXPORT_TEST(testTdf114287, "tdf114287.odt") +{ + uno::Reference const xLevels1( + getProperty>(getParagraph(2), "NumberingRules")); + uno::Reference const xNum1(xLevels1, uno::UNO_QUERY); + ::comphelper::SequenceAsHashMap props1(xLevels1->getByIndex(0)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-700), props1["FirstLineIndent"].get()); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1330), props1["IndentAt"].get()); + + // 1: automatic style applies list-style-name and margin-left + CPPUNIT_ASSERT_EQUAL(sal_Int32(-1000), getProperty(getParagraph(2), "ParaFirstLineIndent")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(5001), getProperty(getParagraph(2), "ParaLeftMargin")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(2), "ParaRightMargin")); + + // list is continued + uno::Reference const xNum2( + getProperty>(getParagraph(9), "NumberingRules")); + CPPUNIT_ASSERT_EQUAL(xNum1->getName(), xNum2->getName()); + + // 2: style applies list-style-name and margin-left, list applies list-style-name + CPPUNIT_ASSERT_EQUAL(sal_Int32(-1000), getProperty(getParagraph(9), "ParaFirstLineIndent")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(5001), getProperty(getParagraph(9), "ParaLeftMargin")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(9), "ParaRightMargin")); + + // list is continued + uno::Reference const xNum3( + getProperty>(getParagraph(16), "NumberingRules")); + CPPUNIT_ASSERT_EQUAL(xNum1->getName(), xNum3->getName()); + + // 3: style applies margin-left, automatic style applies list-style-name + CPPUNIT_ASSERT_EQUAL(sal_Int32(-1000), getProperty(getParagraph(16), "ParaFirstLineIndent")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(5001), getProperty(getParagraph(16), "ParaLeftMargin")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(16), "ParaRightMargin")); + + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/infos/prtBounds"_ostr, "left"_ostr, "2268"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/infos/prtBounds"_ostr, "right"_ostr, "11339"); + // the problem was that the list style name of the list must override the + // paragraph style even though it's the same list style + assertXPath(pXmlDoc, "/root/page[1]/body/txt[9]/infos/prtBounds"_ostr, "left"_ostr, "357"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[9]/infos/prtBounds"_ostr, "right"_ostr, "11339"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[16]/infos/prtBounds"_ostr, "left"_ostr, "357"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[16]/infos/prtBounds"_ostr, "right"_ostr, "11339"); +} + +DECLARE_ODFEXPORT_TEST(testSectionColumnSeparator, "section-columns-separator.fodt") +{ + // tdf#150235: due to wrong types used in column export, 'style:height' and 'style:style' + // attributes were exported incorrectly for 'style:column-sep' element + auto xSection = getProperty>(getParagraph(1), "TextSection"); + auto xColumns = getProperty>(xSection, "TextColumns"); + CPPUNIT_ASSERT(xColumns); + CPPUNIT_ASSERT_EQUAL(sal_Int16(2), xColumns->getColumnCount()); + + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 50 + // - Actual : 100 + CPPUNIT_ASSERT_EQUAL(static_cast(50), + getProperty(xColumns, "SeparatorLineRelativeHeight")); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 2 + // - Actual : 0 + CPPUNIT_ASSERT_EQUAL(css::text::ColumnSeparatorStyle::DOTTED, + getProperty(xColumns, "SeparatorLineStyle")); + + // Check the rest of the properties, too + CPPUNIT_ASSERT_EQUAL(true, getProperty(xColumns, "IsAutomatic")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(600), getProperty(xColumns, "AutomaticDistance")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(9), getProperty(xColumns, "SeparatorLineWidth")); + CPPUNIT_ASSERT_EQUAL(Color(0x99, 0xAA, 0xBB), + getProperty(xColumns, "SeparatorLineColor")); + CPPUNIT_ASSERT_EQUAL( + css::style::VerticalAlignment_BOTTOM, + getProperty(xColumns, "SeparatorLineVerticalAlignment")); + CPPUNIT_ASSERT_EQUAL(true, getProperty(xColumns, "SeparatorLineIsOn")); +} + +DECLARE_ODFEXPORT_TEST(testTdf78510, "WordTest_edit.odt") +{ + uno::Reference const xLevels1( + getProperty>(getParagraph(1), "NumberingRules")); + ::comphelper::SequenceAsHashMap props1(xLevels1->getByIndex(0)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-1000), props1["FirstLineIndent"].get()); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2000), props1["IndentAt"].get()); + + // 1: inherited from paragraph style and overridden by list + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(1), "ParaFirstLineIndent")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1270), getProperty(getParagraph(1), "ParaLeftMargin")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(1), "ParaRightMargin")); + // 2: as 1 + paragraph sets firstline + CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), getProperty(getParagraph(2), "ParaFirstLineIndent")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1270), getProperty(getParagraph(2), "ParaLeftMargin")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(2), "ParaRightMargin")); + // 3: as 1 + paragraph sets textleft + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(3), "ParaFirstLineIndent")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(3000), getProperty(getParagraph(3), "ParaLeftMargin")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(3), "ParaRightMargin")); + // 4: as 1 + paragraph sets firstline, textleft + CPPUNIT_ASSERT_EQUAL(sal_Int32(-2000), getProperty(getParagraph(4), "ParaFirstLineIndent")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(3000), getProperty(getParagraph(4), "ParaLeftMargin")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(4), "ParaRightMargin")); + // 5: as 1 + paragraph sets firstline + CPPUNIT_ASSERT_EQUAL(sal_Int32(-2000), getProperty(getParagraph(5), "ParaFirstLineIndent")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1270), getProperty(getParagraph(5), "ParaLeftMargin")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(5), "ParaRightMargin")); + // 6: as 1 + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(6), "ParaFirstLineIndent")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1270), getProperty(getParagraph(6), "ParaLeftMargin")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(6), "ParaRightMargin")); + + uno::Reference const xLevels8( + getProperty>(getParagraph(8), "NumberingRules")); + ::comphelper::SequenceAsHashMap props8(xLevels8->getByIndex(0)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), props8["FirstLineIndent"].get()); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), props8["IndentAt"].get()); + + // 8: inherited from paragraph style and overridden by list + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(8), "ParaFirstLineIndent")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1270), getProperty(getParagraph(8), "ParaLeftMargin")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(8), "ParaRightMargin")); + // 9: as 8 + paragraph sets firstline + CPPUNIT_ASSERT_EQUAL(sal_Int32(2000), getProperty(getParagraph(9), "ParaFirstLineIndent")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1270), getProperty(getParagraph(9), "ParaLeftMargin")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(9), "ParaRightMargin")); + // 10: as 8 + paragraph sets textleft + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(10), "ParaFirstLineIndent")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(3000), getProperty(getParagraph(10), "ParaLeftMargin")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(10), "ParaRightMargin")); + // 11: as 8 + paragraph sets firstline, textleft + CPPUNIT_ASSERT_EQUAL(sal_Int32(-2000), getProperty(getParagraph(11), "ParaFirstLineIndent")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(3000), getProperty(getParagraph(11), "ParaLeftMargin")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(11), "ParaRightMargin")); + // 12: as 8 + paragraph sets firstline + CPPUNIT_ASSERT_EQUAL(sal_Int32(-2000), getProperty(getParagraph(12), "ParaFirstLineIndent")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1270), getProperty(getParagraph(12), "ParaLeftMargin")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(12), "ParaRightMargin")); + // 13: as 8 + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(13), "ParaFirstLineIndent")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1270), getProperty(getParagraph(13), "ParaLeftMargin")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty(getParagraph(13), "ParaRightMargin")); + + // unfortunately it appears that the portions don't have a position + // so it's not possible to check the first-line-offset that's applied + // (the first-line-indent is computed on the fly in SwTextMargin when + // painting) + { + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/infos/prtBounds"_ostr, "left"_ostr, "567"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/infos/prtBounds"_ostr, "right"_ostr, "9359"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/infos/prtBounds"_ostr, "left"_ostr, "1134"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/infos/prtBounds"_ostr, "right"_ostr, "9359"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/infos/prtBounds"_ostr, "left"_ostr, "1134"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/infos/prtBounds"_ostr, "right"_ostr, "9359"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/infos/prtBounds"_ostr, "left"_ostr, "567"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/infos/prtBounds"_ostr, "right"_ostr, "9359"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[5]/infos/prtBounds"_ostr, "left"_ostr, "0"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[5]/infos/prtBounds"_ostr, "right"_ostr, "9359"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[6]/infos/prtBounds"_ostr, "left"_ostr, "567"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[6]/infos/prtBounds"_ostr, "right"_ostr, "9359"); + + assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/infos/prtBounds"_ostr, "left"_ostr, "567"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/infos/prtBounds"_ostr, "right"_ostr, "9359"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[9]/infos/prtBounds"_ostr, "left"_ostr, "567"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[9]/infos/prtBounds"_ostr, "right"_ostr, "9359"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/infos/prtBounds"_ostr, "left"_ostr, "1701"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/infos/prtBounds"_ostr, "right"_ostr, "9359"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/infos/prtBounds"_ostr, "left"_ostr, "567"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/infos/prtBounds"_ostr, "right"_ostr, "9359"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[12]/infos/prtBounds"_ostr, "left"_ostr, "-567"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[12]/infos/prtBounds"_ostr, "right"_ostr, "9359"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[13]/infos/prtBounds"_ostr, "left"_ostr, "567"); + assertXPath(pXmlDoc, "/root/page[1]/body/txt[13]/infos/prtBounds"_ostr, "right"_ostr, "9359"); + } + + // now check the positions where text is actually painted - + // wonder how fragile this is... + // FIXME some platform difference, 1st one is 2306 on Linux, 3087 on WNT ? + // some Mac has 3110 +#if !defined(_WIN32) && !defined(MACOSX) + { + SwDocShell *const pShell(dynamic_cast(*mxComponent).GetDocShell()); + std::shared_ptr pMetaFile = pShell->GetPreviewMetaFile(); + MetafileXmlDump aDumper; + xmlDocUniquePtr pXmlDoc = dumpAndParse(aDumper, *pMetaFile); + + // 1: inherited from paragraph style and overridden by list + // bullet char is extra + + assertXPath(pXmlDoc, "//textarray[1]"_ostr, "x"_ostr, "2306"); + // text is after a tab from list - haven't checked if that is correct? + assertXPath(pXmlDoc, "//textarray[2]"_ostr, "x"_ostr, "2873"); + // second line + assertXPath(pXmlDoc, "//textarray[3]"_ostr, "x"_ostr, "2873"); + // 2: as 1 + paragraph sets firstline + assertXPath(pXmlDoc, "//textarray[4]"_ostr, "x"_ostr, "3440"); + assertXPath(pXmlDoc, "//textarray[5]"_ostr, "x"_ostr, "3593"); + assertXPath(pXmlDoc, "//textarray[6]"_ostr, "x"_ostr, "2873"); + // 3: as 1 + paragraph sets textleft + assertXPath(pXmlDoc, "//textarray[7]"_ostr, "x"_ostr, "2873"); + assertXPath(pXmlDoc, "//textarray[8]"_ostr, "x"_ostr, "3440"); + assertXPath(pXmlDoc, "//textarray[9]"_ostr, "x"_ostr, "3440"); + // 4: as 1 + paragraph sets firstline, textleft + assertXPath(pXmlDoc, "//textarray[10]"_ostr, "x"_ostr, "2306"); + assertXPath(pXmlDoc, "//textarray[11]"_ostr, "x"_ostr, "3440"); + assertXPath(pXmlDoc, "//textarray[12]"_ostr, "x"_ostr, "3440"); + // 5: as 1 + paragraph sets firstline + assertXPath(pXmlDoc, "//textarray[13]"_ostr, "x"_ostr, "1739"); + assertXPath(pXmlDoc, "//textarray[14]"_ostr, "x"_ostr, "2873"); + assertXPath(pXmlDoc, "//textarray[15]"_ostr, "x"_ostr, "2873"); + // 6: as 1 + assertXPath(pXmlDoc, "//textarray[16]"_ostr, "x"_ostr, "2306"); + assertXPath(pXmlDoc, "//textarray[17]"_ostr, "x"_ostr, "2873"); + + // 8: inherited from paragraph style and overridden by list + assertXPath(pXmlDoc, "//textarray[18]"_ostr, "x"_ostr, "2873"); + assertXPath(pXmlDoc, "//textarray[19]"_ostr, "x"_ostr, "3746"); + assertXPath(pXmlDoc, "//textarray[20]"_ostr, "x"_ostr, "2306"); + // 9: as 8 + paragraph sets firstline + assertXPath(pXmlDoc, "//textarray[21]"_ostr, "x"_ostr, "3440"); + assertXPath(pXmlDoc, "//textarray[22]"_ostr, "x"_ostr, "3746"); + assertXPath(pXmlDoc, "//textarray[23]"_ostr, "x"_ostr, "2306"); + // 10: as 8 + paragraph sets textleft + assertXPath(pXmlDoc, "//textarray[24]"_ostr, "x"_ostr, "4007"); + assertXPath(pXmlDoc, "//textarray[25]"_ostr, "x"_ostr, "4880"); + assertXPath(pXmlDoc, "//textarray[26]"_ostr, "x"_ostr, "3440"); + // 11: as 8 + paragraph sets firstline, textleft + assertXPath(pXmlDoc, "//textarray[27]"_ostr, "x"_ostr, "2306"); + assertXPath(pXmlDoc, "//textarray[28]"_ostr, "x"_ostr, "3440"); + assertXPath(pXmlDoc, "//textarray[29]"_ostr, "x"_ostr, "3440"); + // 12: as 8 + paragraph sets firstline + assertXPath(pXmlDoc, "//textarray[30]"_ostr, "x"_ostr, "1172"); + assertXPath(pXmlDoc, "//textarray[31]"_ostr, "x"_ostr, "1739"); + assertXPath(pXmlDoc, "//textarray[32]"_ostr, "x"_ostr, "2306"); + // 13: as 8 + assertXPath(pXmlDoc, "//textarray[33]"_ostr, "x"_ostr, "2873"); + assertXPath(pXmlDoc, "//textarray[34]"_ostr, "x"_ostr, "3746"); + } +#endif +} + +CPPUNIT_TEST_FIXTURE(Test, testParagraphMarkerMarkupRoundtrip) +{ + loadAndReload("ParagraphMarkerMarkup.fodt"); + // Test that the markup stays at save-and-reload + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + assertXPath(pXmlDoc, "/office:document-content/office:body/office:text/text:p"_ostr, "marker-style-name"_ostr, "T2"); + assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/style:style[@style:name='T2']/style:text-properties"_ostr, "font-size"_ostr, "9pt"); + assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/style:style[@style:name='T2']/style:text-properties"_ostr, "color"_ostr, "#ff0000"); +} + +CPPUNIT_TEST_FIXTURE(Test, testCommentStyles) +{ + createSwDoc(); + + auto xFactory(mxComponent.queryThrow()); + auto xComment(xFactory->createInstance("com.sun.star.text.textfield.Annotation").queryThrow()); + auto xCommentText(getProperty>(xComment, "TextRange")); + xCommentText->setString("Hello World"); + xCommentText.queryThrow()->setPropertyValue("ParaStyleName", uno::Any(OUString("Heading"))); + + xComment->attach(getParagraph(1)->getEnd()); + + saveAndReload("writer8"); + + auto xFields(mxComponent.queryThrow()->getTextFields()->createEnumeration()); + xComment.set(xFields->nextElement().queryThrow()); + CPPUNIT_ASSERT(xComment.queryThrow()->supportsService("com.sun.star.text.textfield.Annotation")); + + xCommentText.set(getProperty>(xComment, "TextRange")); + CPPUNIT_ASSERT_EQUAL(OUString("Heading"), getProperty(xCommentText, "ParaStyleName")); + + auto xStyleFamilies(mxComponent.queryThrow()->getStyleFamilies()); + auto xParaStyles(xStyleFamilies->getByName("ParagraphStyles")); + auto xStyle(xParaStyles.queryThrow()->getByName("Heading")); + CPPUNIT_ASSERT_EQUAL(getProperty(xStyle, "CharHeight"), getProperty(xCommentText, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(beans::PropertyState_DEFAULT_VALUE, + xCommentText.queryThrow()->getPropertyState("CharHeight")); +} + +CPPUNIT_TEST_FIXTURE(Test, testTdf150408_IsLegal) +{ + loadAndReload("IsLegal.fodt"); + + // Second level's numbering should use Arabic numbers for first level reference + auto xPara = getParagraph(1); + CPPUNIT_ASSERT_EQUAL(OUString("CH I"), getProperty(xPara, "ListLabelString")); + xPara = getParagraph(2); + CPPUNIT_ASSERT_EQUAL(OUString("Sect 1.01"), getProperty(xPara, "ListLabelString")); + xPara = getParagraph(3); + CPPUNIT_ASSERT_EQUAL(OUString("CH II"), getProperty(xPara, "ListLabelString")); + xPara = getParagraph(4); + CPPUNIT_ASSERT_EQUAL(OUString("Sect 2.01"), getProperty(xPara, "ListLabelString")); + + // Test that the markup stays at save-and-reload + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + assertXPath( + pXmlDoc, + "/office:document-styles/office:styles/text:outline-style/text:outline-level-style[2]"_ostr, + "is-legal"_ostr, "true"); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3