1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include <swmodeltestbase.hxx>
11 
12 #include <com/sun/star/beans/XPropertySet.hpp>
13 #include <com/sun/star/style/BreakType.hpp>
14 #include <com/sun/star/style/ParagraphAdjust.hpp>
15 #include <com/sun/star/table/BorderLine.hpp>
16 #include <com/sun/star/text/WritingMode2.hpp>
17 #include <com/sun/star/text/XDependentTextField.hpp>
18 #include <com/sun/star/text/XFootnotesSupplier.hpp>
19 #include <com/sun/star/text/RubyAdjust.hpp>
20 #include <com/sun/star/text/RubyPosition.hpp>
21 #include <com/sun/star/text/XDocumentIndex.hpp>
22 #include <com/sun/star/drawing/FillStyle.hpp>
23 
24 class Test : public SwModelTestBase
25 {
26 public:
Test()27     Test() : SwModelTestBase("/sw/qa/extras/ooxmlexport/data/", "Office Open XML Text") {}
28 
29 protected:
30     /**
31      * Blacklist handling
32      */
mustTestImportOf(const char * filename) const33     bool mustTestImportOf(const char* filename) const override {
34         // If the testcase is stored in some other format, it's pointless to test.
35         return OString(filename).endsWith(".docx");
36     }
37 };
38 
39 DECLARE_OOXMLEXPORT_TEST(testTdf57589_hashColor, "tdf57589_hashColor.docx")
40 {
41     CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_SOLID, getProperty<drawing::FillStyle>(getParagraph(1), "FillStyle"));
42     CPPUNIT_ASSERT_EQUAL(COL_LIGHTMAGENTA, Color(getProperty<sal_uInt32>(getParagraph(1), "ParaBackColor")));
43     CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_NONE, getProperty<drawing::FillStyle>(getParagraph(2), "FillStyle"));
44     CPPUNIT_ASSERT_EQUAL(COL_AUTO, Color(getProperty<sal_uInt32>(getParagraph(2), "ParaBackColor")));
45 }
46 
47 DECLARE_OOXMLEXPORT_TEST(testTdf90906_colAuto, "tdf90906_colAuto.docx")
48 {
49     uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
50     uno::Reference<container::XIndexAccess> xTables(xTextTablesSupplier->getTextTables(), uno::UNO_QUERY);
51     uno::Reference<text::XTextTable> xTable(xTables->getByIndex(0), uno::UNO_QUERY);
52     uno::Reference<text::XTextRange> xCell(xTable->getCellByName("A1"), uno::UNO_QUERY);
53     uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xCell->getText(), uno::UNO_QUERY);
54     uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
55     uno::Reference<text::XTextRange> xPara(xParaEnum->nextElement(), uno::UNO_QUERY);
56     CPPUNIT_ASSERT_EQUAL(COL_AUTO, Color(getProperty<sal_uInt32>(getRun(xPara, 1, "Nazwa"), "CharBackColor")));
57 }
58 
59 DECLARE_OOXMLEXPORT_TEST(testTdf90906_colAutoB, "tdf90906_colAutoB.docx")
60 {
61     uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
62     uno::Reference<container::XIndexAccess> xTables(xTextTablesSupplier->getTextTables(), uno::UNO_QUERY);
63     uno::Reference<text::XTextTable> xTable(xTables->getByIndex(0), uno::UNO_QUERY);
64 
65     uno::Reference<table::XCell> xCell = xTable->getCellByName("A1");
66     CPPUNIT_ASSERT_EQUAL(COL_LIGHTGREEN, Color(getProperty<sal_uInt32>(xCell, "BackColor")));
67     xCell.set(xTable->getCellByName("A2"));
68     CPPUNIT_ASSERT_EQUAL(COL_AUTO, Color(getProperty<sal_uInt32>(xCell, "BackColor")));
69     xCell.set(xTable->getCellByName("B1"));
70     CPPUNIT_ASSERT_EQUAL(COL_AUTO, Color(getProperty<sal_uInt32>(xCell, "BackColor")));
71     xCell.set(xTable->getCellByName("B2"));
72     CPPUNIT_ASSERT_EQUAL(COL_LIGHTBLUE, Color(getProperty<sal_uInt32>(xCell, "BackColor")));
73 
74     uno::Reference<text::XTextRange> xText(getParagraph(2, "Paragraphs too"));
75     CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_NONE, getProperty<drawing::FillStyle>(xText, "FillStyle"));
76     CPPUNIT_ASSERT_EQUAL(COL_AUTO, Color(getProperty<sal_uInt32>(xText, "ParaBackColor")));
77 }
78 
79 DECLARE_OOXMLEXPORT_TEST(testTdf92524_autoColor, "tdf92524_autoColor.doc")
80 {
81     CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_NONE, getProperty<drawing::FillStyle>(getParagraph(1), "FillStyle"));
82     CPPUNIT_ASSERT_EQUAL(COL_AUTO, Color(getProperty<sal_uInt32>(getParagraph(1), "ParaBackColor")));
83 }
84 
85 DECLARE_OOXMLEXPORT_TEST(testTdf116436_rowFill, "tdf116436_rowFill.odt")
86 {
87     uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
88     uno::Reference<container::XIndexAccess> xTables(xTextTablesSupplier->getTextTables(), uno::UNO_QUERY);
89     uno::Reference<text::XTextTable> xTable(xTables->getByIndex(0), uno::UNO_QUERY);
90     uno::Reference<table::XCell> xCell = xTable->getCellByName("A1");
91     CPPUNIT_ASSERT_EQUAL(sal_Int32(0xF8DF7C), getProperty<sal_Int32>(xCell, "BackColor"));
92 }
93 
94 DECLARE_OOXMLEXPORT_TEST(testTdf121665_back2backColumnBreaks, "tdf121665_back2backColumnBreaks.docx")
95 {
96     CPPUNIT_ASSERT_EQUAL_MESSAGE("Column break type",
97         style::BreakType_COLUMN_BEFORE, getProperty<style::BreakType>(getParagraph(2), "BreakType"));
98 }
99 
100 DECLARE_OOXMLEXPORT_TEST(testTdf46938_clearTabStop, "tdf46938_clearTabStop.docx")
101 {
102     // Number of tabstops should be zero, overriding the one in the style
103     CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty< uno::Sequence<style::TabStop> >(getParagraph(1), "ParaTabStops").getLength());
104 }
105 
106 DECLARE_OOXMLEXPORT_TEST(testTdf63561_clearTabs, "tdf63561_clearTabs.docx")
107 {
108     CPPUNIT_ASSERT_EQUAL(sal_Int32(5), getProperty< uno::Sequence<style::TabStop> >(getParagraph(1), "ParaTabStops").getLength());
109     CPPUNIT_ASSERT_EQUAL(sal_Int32(7), getProperty< uno::Sequence<style::TabStop> >(getParagraph(3), "ParaTabStops").getLength());
110     CPPUNIT_ASSERT_EQUAL(sal_Int32(4), getProperty< uno::Sequence<style::TabStop> >(getParagraph(4), "ParaTabStops").getLength());
111 }
112 
113 DECLARE_OOXMLEXPORT_TEST(testTdf63561_clearTabs2, "tdf63561_clearTabs2.docx")
114 {
115     CPPUNIT_ASSERT_EQUAL(sal_Int32(1), getProperty< uno::Sequence<style::TabStop> >(getParagraph(1), "ParaTabStops").getLength());
116     CPPUNIT_ASSERT_EQUAL(sal_Int32(3), getProperty< uno::Sequence<style::TabStop> >(getParagraph(3), "ParaTabStops").getLength());
117     CPPUNIT_ASSERT_EQUAL(sal_Int32(4), getProperty< uno::Sequence<style::TabStop> >(getParagraph(4), "ParaTabStops").getLength());
118 }
119 
120 DECLARE_OOXMLEXPORT_TEST(testTdf124384, "tdf124384.docx")
121 {
122     // There should be no crash during loading of the document
123     // so, let's check just how much pages we have
124     CPPUNIT_ASSERT_EQUAL(1, getPages());
125 }
126 
127 DECLARE_OOXMLEXPORT_TEST(testTdf121456_tabsOffset, "tdf121456_tabsOffset.odt")
128 {
129     for (int i=2; i<8; i++)
130     {
131         uno::Sequence< style::TabStop > stops = getProperty< uno::Sequence<style::TabStop> >(getParagraph( i ), "ParaTabStops");
132         CPPUNIT_ASSERT_EQUAL( sal_Int32(1), stops.getLength());
133         CPPUNIT_ASSERT_EQUAL( css::style::TabAlign_RIGHT, stops[ 0 ].Alignment );
134         CPPUNIT_ASSERT_EQUAL( sal_Int32(17000), stops[ 0 ].Position );
135     }
136 }
137 
138 // tdf#121561: make sure w:sdt/w:sdtContent around TOC is written during ODT->DOCX conversion
139 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf121561_tocTitle, "tdf121456_tabsOffset.odt")
140 {
141     xmlDocPtr pXmlDoc = parseExport();
142     assertXPathContent(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtContent/w:p/w:r/w:t", "Inhaltsverzeichnis");
143     assertXPathContent(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtContent/w:p/w:r/w:instrText", " TOC \\f \\o \"1-9\" \\h");
144     assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:docPartObj/w:docPartGallery", "val", "Table of Contents");
145     assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:docPartObj/w:docPartUnique", 1);
146 }
147 
148 // Related issue tdf#121561: w:sdt/w:sdtContent around TOC
149 DECLARE_OOXMLEXPORT_TEST(testTdf124106, "tdf121456.docx")
150 {
151     uno::Reference<text::XTextDocument> textDocument(mxComponent, uno::UNO_QUERY);
152     uno::Reference<text::XText> text = textDocument->getText();
153     // -1 if the 'Y' character does not occur
154     CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), text->getString().indexOf('Y'));
155     CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), text->getString().indexOf('y'));
156 }
157 
158 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf121561_tocTitleDocx, "tdf121456_tabsOffset.odt")
159 {
160     xmlDocPtr pXmlDoc = parseExport();
161 
162     // get TOC node
163     uno::Reference<text::XDocumentIndexesSupplier> xIndexSupplier(mxComponent, uno::UNO_QUERY);
164     uno::Reference<container::XIndexAccess> xIndexes = xIndexSupplier->getDocumentIndexes( );
165     uno::Reference<text::XDocumentIndex> xTOCIndex(xIndexes->getByIndex(0), uno::UNO_QUERY);
166 
167     // ensure TOC title was set in TOC properties
168     CPPUNIT_ASSERT_EQUAL(OUString("Inhaltsverzeichnis"), getProperty<OUString>(xTOCIndex, "Title"));
169 
170     // ensure TOC end-field mark is placed inside TOC section
171     assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtContent/w:p[16]/w:r/w:fldChar", "fldCharType", "end");
172 }
173 
174 DECLARE_OOXMLEXPORT_TEST(testTdf106174_rtlParaAlign, "tdf106174_rtlParaAlign.docx")
175 {
176     CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_CENTER), getProperty<sal_Int16>(getParagraph(1), "ParaAdjust"));
177     CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_CENTER), getProperty<sal_Int16>(getParagraph(2), "ParaAdjust"));
178     uno::Reference<beans::XPropertySet> xPropertySet(getStyles("ParagraphStyles")->getByName("Another paragraph aligned to right"), uno::UNO_QUERY);
179     CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_RIGHT), getProperty<sal_Int16>(xPropertySet, "ParaAdjust"));
180     CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_RIGHT), getProperty<sal_Int16>(getParagraph(3), "ParaAdjust"));
181     CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_RIGHT), getProperty<sal_Int16>(getParagraph(4), "ParaAdjust"));
182     CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_RIGHT), getProperty<sal_Int16>(getParagraph(5), "ParaAdjust"));
183     CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_LEFT),  getProperty<sal_Int16>(getParagraph(6), "ParaAdjust"));
184     CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_RIGHT), getProperty<sal_Int16>(getParagraph(7), "ParaAdjust"));
185     CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_RIGHT), getProperty<sal_Int16>(getParagraph(8), "ParaAdjust"));
186     CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_LEFT),  getProperty<sal_Int16>(getParagraph(9), "ParaAdjust"));
187     CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_LEFT),  getProperty<sal_Int16>(getParagraph(10), "ParaAdjust"));
188     CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_RIGHT), getProperty<sal_Int16>(getParagraph(11), "ParaAdjust"));
189     CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_LEFT),  getProperty<sal_Int16>(getParagraph(12), "ParaAdjust"));
190     CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_LEFT),  getProperty<sal_Int16>(getParagraph(13), "ParaAdjust"));
191     CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_RIGHT), getProperty<sal_Int16>(getParagraph(14), "ParaAdjust"));
192 }
193 
194 DECLARE_OOXMLEXPORT_TEST(testTdf82065_Ind_start_strict, "tdf82065_Ind_start_strict.docx")
195 {
196     uno::Reference<beans::XPropertySet> xPropertySet(getStyles("NumberingStyles")->getByName("WWNum1"), uno::UNO_QUERY);
197     uno::Reference<container::XIndexAccess> xLevels(xPropertySet->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
198     uno::Sequence<beans::PropertyValue> aProps;
199     xLevels->getByIndex(0) >>= aProps; // 1st level
200     bool bFoundIndentAt = false;
201     for (int i = 0; i < aProps.getLength(); ++i)
202     {
203         const beans::PropertyValue& rProp = aProps[i];
204 
205         if (rProp.Name == "IndentAt")
206         {
207             CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("IndentAt", double(6001), rProp.Value.get<double>(), 10 );
208             bFoundIndentAt = true;
209         }
210     }
211     CPPUNIT_ASSERT_EQUAL_MESSAGE("IndentAt defined", true, bFoundIndentAt);
212 }
213 
214 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf76683_negativeTwipsMeasure, "tdf76683_negativeTwipsMeasure.docx")
215 {
216     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
217     assertXPath(pXmlDoc, "/w:document/w:body/w:sectPr/w:cols/w:col", 2);
218     sal_uInt32 nColumn1 = getXPath(pXmlDoc, "/w:document/w:body/w:sectPr/w:cols/w:col[1]", "w").toUInt32();
219     sal_uInt32 nColumn2 = getXPath(pXmlDoc, "/w:document/w:body/w:sectPr/w:cols/w:col[2]", "w").toUInt32();
220     CPPUNIT_ASSERT( nColumn1 > nColumn2 );
221 }
222 
223 DECLARE_OOXMLEXPORT_TEST(testTdf112694, "tdf112694.docx")
224 {
225     uno::Any aPageStyle = getStyles("PageStyles")->getByName("Standard");
226     // Header was on when header for file was for explicit first pages only
227     // (marked via <w:titlePg>).
228     CPPUNIT_ASSERT(!getProperty<bool>(aPageStyle, "HeaderIsOn"));
229 }
230 
231 DECLARE_OOXMLEXPORT_TEST(testTdf113849_evenAndOddHeaders, "tdf113849_evenAndOddHeaders.odt")
232 {
233     CPPUNIT_ASSERT_EQUAL_MESSAGE("Header2 text", OUString("L. J. Kendall"), parseDump("/root/page[2]/header/txt"));
234     CPPUNIT_ASSERT_EQUAL_MESSAGE("Footer2 text", OUString("*"), parseDump("/root/page[2]/footer/txt"));
235 
236     CPPUNIT_ASSERT_EQUAL_MESSAGE("Header3 text", OUString("Shadow Hunt"), parseDump("/root/page[3]/header/txt"));
237     CPPUNIT_ASSERT_EQUAL_MESSAGE("Footer3 text", OUString("*"), parseDump("/root/page[3]/footer/txt"));
238 
239     CPPUNIT_ASSERT_EQUAL_MESSAGE("Header4 text", OUString("L. J. Kendall"), parseDump("/root/page[4]/header/txt"));
240     CPPUNIT_ASSERT_EQUAL_MESSAGE("Footer4 text", OUString("*"), parseDump("/root/page[4]/footer/txt"));
241 
242     CPPUNIT_ASSERT_EQUAL_MESSAGE("Footer5 text", OUString(""), parseDump("/root/page[5]/footer/txt"));
243     CPPUNIT_ASSERT_EQUAL_MESSAGE("Footer6 text", OUString(""), parseDump("/root/page[6]/footer/txt"));
244 
245     CPPUNIT_ASSERT_EQUAL_MESSAGE("Number of pages", 6, getPages() );
246 }
247 
248 DECLARE_OOXMLEXPORT_TEST(testTdf118361_RTLfootnoteSeparator, "tdf118361_RTLfootnoteSeparator.docx")
249 {
250     uno::Any aPageStyle = getStyles("PageStyles")->getByName("Standard");
251     CPPUNIT_ASSERT_EQUAL_MESSAGE("Footnote separator RTL", sal_Int16(2), getProperty<sal_Int16>(aPageStyle, "FootnoteLineAdjust"));
252 }
253 
254 DECLARE_OOXMLEXPORT_TEST(testTdf115861, "tdf115861.docx")
255 {
256     // Second item in the paragraph enumeration was a table, 2nd paragraph was
257     // lost.
258     CPPUNIT_ASSERT_EQUAL(OUString("(k)"), getParagraph(2)->getString());
259 }
260 
261 DECLARE_OOXMLEXPORT_TEST(testTdf67207_MERGEFIELD, "mailmerge.docx")
262 {
263     uno::Reference<beans::XPropertySet> xTextField = getProperty< uno::Reference<beans::XPropertySet> >(getRun(getParagraph(1), 2), "TextField");
264     CPPUNIT_ASSERT(xTextField.is());
265     uno::Reference<lang::XServiceInfo> xServiceInfo(xTextField, uno::UNO_QUERY_THROW);
266     uno::Reference<text::XDependentTextField> xDependent(xTextField, uno::UNO_QUERY_THROW);
267 
268     CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.Database"));
269     OUString sValue;
270     xTextField->getPropertyValue("Content") >>= sValue;
271     CPPUNIT_ASSERT_EQUAL(OUString::fromUtf8(u8"«Name»"), sValue);
272 
273     uno::Reference<beans::XPropertySet> xFiledMaster = xDependent->getTextFieldMaster();
274     uno::Reference<lang::XServiceInfo> xFiledMasterServiceInfo(xFiledMaster, uno::UNO_QUERY_THROW);
275 
276     CPPUNIT_ASSERT(xFiledMasterServiceInfo->supportsService("com.sun.star.text.fieldmaster.Database"));
277 
278     // Defined properties: DataBaseName, Name, DataTableName, DataColumnName, DependentTextFields, DataCommandType, InstanceName, DataBaseURL
279     CPPUNIT_ASSERT(xFiledMaster->getPropertyValue("Name") >>= sValue);
280     CPPUNIT_ASSERT_EQUAL(OUString("Name"), sValue);
281     CPPUNIT_ASSERT(xFiledMaster->getPropertyValue("DataColumnName") >>= sValue);
282     CPPUNIT_ASSERT_EQUAL(OUString("Name"), sValue);
283     CPPUNIT_ASSERT(xFiledMaster->getPropertyValue("InstanceName") >>= sValue);
284     CPPUNIT_ASSERT_EQUAL(OUString("com.sun.star.text.fieldmaster.DataBase.Name"), sValue);
285 }
286 
287 DECLARE_OOXMLEXPORT_TEST(testTdf115719, "tdf115719.docx")
288 {
289     // This was a single page, instead of pushing the textboxes to the second
290     // page.
291     CPPUNIT_ASSERT_EQUAL(2, getPages());
292 }
293 
294 DECLARE_OOXMLIMPORT_TEST(testTdf115719b, "tdf115719b.docx")
295 {
296     // This is similar to testTdf115719, but here the left textbox is not aligned "from left, by
297     // 0cm" but simply aligned to left, which is a different codepath.
298 
299     // Without the accompanying fix in place, this test would have failed with:
300     // - Expected: 2
301     // - Actual  : 1
302     // i.e. the the textboxes did not appear on the 2nd page, but everything was on a single page.
303     CPPUNIT_ASSERT_EQUAL(2, getPages());
304 }
305 
306 DECLARE_OOXMLEXPORT_TEST(testTdf123243, "tdf123243.docx")
307 {
308     // Without the accompanying fix in place, this test would have failed with 'Expected: 1; Actual:
309     // 2'; i.e. unexpected paragraph margin created 2 pages.
310     CPPUNIT_ASSERT_EQUAL(1, getPages());
311 }
312 
313 DECLARE_OOXMLEXPORT_TEST(testTdf116410, "tdf116410.docx")
314 {
315     // Opposite of the above, was 2 pages, should be 1 page.
316     CPPUNIT_ASSERT_EQUAL(1, getPages());
317 }
318 
319 DECLARE_OOXMLEXPORT_TEST(testDefaultStyle, "defaultStyle.docx")
320 {
321     CPPUNIT_ASSERT_EQUAL_MESSAGE( "Default Style", OUString("Title"), getProperty<OUString>(getParagraph(1), "ParaStyleName") );
322     CPPUNIT_ASSERT_EQUAL(2, getPages());
323 }
324 
325 DECLARE_OOXMLEXPORT_TEST(testTdf117988, "tdf117988.docx")
326 {
327     CPPUNIT_ASSERT_EQUAL(1, getPages());
328 }
329 
330 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testParagraphSplitOnSectionBorder, "parasplit-on-section-border.odt")
331 {
332     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
333 
334     // Test document has only two paragraphs. After splitting, it should contain
335     // three of them.
336     assertXPath(pXmlDoc, "//w:sectPr", 2);
337     assertXPath(pXmlDoc, "//w:p", 3);
338 }
339 
340 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf44832_testSectionWithDifferentHeader, "tdf44832_section_new_header.odt")
341 {
342     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
343     assertXPath(pXmlDoc, "/w:document/w:body/w:sectPr/w:headerReference", 1);
344 }
345 
346 DECLARE_OOXMLEXPORT_TEST(testSignatureLineShape, "signature-line-all-props-set.docx")
347 {
348     uno::Reference<drawing::XShape> xSignatureLineShape = getShape(1);
349     uno::Reference<beans::XPropertySet> xPropSet(xSignatureLineShape, uno::UNO_QUERY);
350 
351     bool bIsSignatureLine;
352     xPropSet->getPropertyValue("IsSignatureLine") >>= bIsSignatureLine;
353     CPPUNIT_ASSERT_EQUAL(true, bIsSignatureLine);
354 
355     bool bShowSignDate;
356     xPropSet->getPropertyValue("SignatureLineShowSignDate") >>= bShowSignDate;
357     CPPUNIT_ASSERT_EQUAL(true, bShowSignDate);
358 
359     bool bCanAddComment;
360     xPropSet->getPropertyValue("SignatureLineCanAddComment") >>= bCanAddComment;
361     CPPUNIT_ASSERT_EQUAL(true, bCanAddComment);
362 
363     OUString aSignatureLineId;
364     xPropSet->getPropertyValue("SignatureLineId") >>= aSignatureLineId;
365     CPPUNIT_ASSERT_EQUAL(OUString("{0EBE47D5-A1BD-4C9E-A52E-6256E5C345E9}"), aSignatureLineId);
366 
367     OUString aSuggestedSignerName;
368     xPropSet->getPropertyValue("SignatureLineSuggestedSignerName") >>= aSuggestedSignerName;
369     CPPUNIT_ASSERT_EQUAL(OUString("John Doe"), aSuggestedSignerName);
370 
371     OUString aSuggestedSignerTitle;
372     xPropSet->getPropertyValue("SignatureLineSuggestedSignerTitle") >>= aSuggestedSignerTitle;
373     CPPUNIT_ASSERT_EQUAL(OUString("Farmer"), aSuggestedSignerTitle);
374 
375     OUString aSuggestedSignerEmail;
376     xPropSet->getPropertyValue("SignatureLineSuggestedSignerEmail") >>= aSuggestedSignerEmail;
377     CPPUNIT_ASSERT_EQUAL(OUString("john@thefarmers.com"), aSuggestedSignerEmail);
378 
379     OUString aSigningInstructions;
380     xPropSet->getPropertyValue("SignatureLineSigningInstructions") >>= aSigningInstructions;
381     CPPUNIT_ASSERT_EQUAL(OUString("Check the machines!"), aSigningInstructions);
382 }
383 
384 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf117805, "tdf117805.odt")
385 {
386     uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
387         = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory),
388                                                       maTempFile.GetURL());
389     // This failed, the header was lost. It's still referenced at an incorrect
390     // location in document.xml, though.
391     CPPUNIT_ASSERT(xNameAccess->hasByName("word/header1.xml"));
392 
393     uno::Reference<text::XText> textbox(getShape(1), uno::UNO_QUERY);
394     CPPUNIT_ASSERT_EQUAL(8, getParagraphs(textbox));
395 }
396 
397 DECLARE_OOXMLEXPORT_TEST(testTdf113183, "tdf113183.docx")
398 {
399     // The horizontal positioning of the star shape affected the positioning of
400     // the triangle one, so the triangle was outside the page frame.
401     xmlDocPtr pXmlDoc = parseLayoutDump();
402     sal_Int32 nPageLeft = getXPath(pXmlDoc, "/root/page[1]/infos/bounds", "left").toInt32();
403     sal_Int32 nPageWidth = getXPath(pXmlDoc, "/root/page[1]/infos/bounds", "width").toInt32();
404     sal_Int32 nShapeLeft
405         = getXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[2]/bounds", "left")
406               .toInt32();
407     sal_Int32 nShapeWidth
408         = getXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[2]/bounds", "width")
409               .toInt32();
410     // Make sure the second triangle shape is within the page bounds (with ~1px tolerance).
411     CPPUNIT_ASSERT_GREATEREQUAL(nShapeLeft + nShapeWidth, nPageLeft + nPageWidth + 21);
412 }
413 
414 DECLARE_OOXMLEXPORT_TEST(testGraphicObjectFliph, "graphic-object-fliph.docx")
415 {
416     CPPUNIT_ASSERT(getProperty<bool>(getShape(1), "HoriMirroredOnEvenPages"));
417     CPPUNIT_ASSERT(getProperty<bool>(getShape(1), "HoriMirroredOnOddPages"));
418 }
419 
420 DECLARE_OOXMLEXPORT_TEST(testTdf113547, "tdf113547.docx")
421 {
422     uno::Reference<beans::XPropertySet> xPropertySet(
423         getStyles("NumberingStyles")->getByName("WWNum1"), uno::UNO_QUERY);
424     uno::Reference<container::XIndexAccess> xLevels(
425         xPropertySet->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
426     comphelper::SequenceAsHashMap aProps(xLevels->getByIndex(0)); // 1st level
427     // This was 0, first-line left margin of the numbering was lost.
428     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-635), aProps["FirstLineIndent"].get<sal_Int32>());
429 }
430 
431 DECLARE_OOXMLEXPORT_TEST(testTdf113399, "tdf113399.doc")
432 {
433     // 0 padding was not preserved
434     // In LO 0 is the default, but in OOXML format the default is 254 / 127
435     uno::Reference<beans::XPropertySet> xPropSet(getShape(1), uno::UNO_QUERY);
436     sal_Int32 nPaddingValue;
437     xPropSet->getPropertyValue("TextLeftDistance") >>= nPaddingValue;
438     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), nPaddingValue);
439     xPropSet->getPropertyValue("TextRightDistance") >>= nPaddingValue;
440     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), nPaddingValue);
441     xPropSet->getPropertyValue("TextUpperDistance") >>= nPaddingValue;
442     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), nPaddingValue);
443     xPropSet->getPropertyValue("TextLowerDistance") >>= nPaddingValue;
444     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), nPaddingValue);
445 }
446 
447 DECLARE_OOXMLEXPORT_TEST(testTdf114882, "tdf114882.docx")
448 {
449     // fastserializer must not fail assertion because of mismatching elements
450 }
451 
452 DECLARE_OOXMLEXPORT_TEST(testTdf49073, "tdf49073.docx")
453 {
454     // test case for Asian phontic guide (ruby text.)
455     sal_Unicode aRuby[3] = {0x304D,0x3082,0x3093};
456     OUString sRuby(aRuby, SAL_N_ELEMENTS(aRuby));
457     CPPUNIT_ASSERT_EQUAL(sRuby,getProperty<OUString>(getParagraph(1)->getStart(), "RubyText"));
458     OUString sStyle = getProperty<OUString>( getParagraph(1)->getStart(), "RubyCharStyleName");
459     uno::Reference<beans::XPropertySet> xPropertySet(getStyles("CharacterStyles")->getByName(sStyle), uno::UNO_QUERY );
460     CPPUNIT_ASSERT_EQUAL(5.f, getProperty<float>(xPropertySet, "CharHeight"));
461     CPPUNIT_ASSERT_EQUAL(sal_Int16(text::RubyAdjust_CENTER) ,getProperty<sal_Int16>(getParagraph(2)->getStart(),"RubyAdjust"));
462     CPPUNIT_ASSERT_EQUAL(sal_Int16(text::RubyAdjust_BLOCK)  ,getProperty<sal_Int16>(getParagraph(3)->getStart(),"RubyAdjust"));
463     CPPUNIT_ASSERT_EQUAL(sal_Int16(text::RubyAdjust_INDENT_BLOCK),getProperty<sal_Int16>(getParagraph(4)->getStart(),"RubyAdjust"));
464     CPPUNIT_ASSERT_EQUAL(sal_Int16(text::RubyAdjust_LEFT)   ,getProperty<sal_Int16>(getParagraph(5)->getStart(),"RubyAdjust"));
465     CPPUNIT_ASSERT_EQUAL(sal_Int16(text::RubyAdjust_RIGHT)  ,getProperty<sal_Int16>(getParagraph(6)->getStart(),"RubyAdjust"));
466     CPPUNIT_ASSERT_EQUAL(sal_Int16(text::RubyPosition::INTER_CHARACTER)  ,getProperty<sal_Int16>(getParagraph(7)->getStart(),"RubyPosition"));
467 }
468 
469 DECLARE_OOXMLEXPORT_TEST(testTdf114703, "tdf114703.docx")
470 {
471     uno::Reference<container::XIndexAccess> xRules
472         = getProperty<uno::Reference<container::XIndexAccess>>(
473             getStyles("NumberingStyles")->getByName("WWNum1"), "NumberingRules");
474     // This was 0, level override "default" replaced the non-default value from
475     // the abstract level.
476     CPPUNIT_ASSERT_EQUAL(
477         static_cast<sal_Int32>(-1000),
478         comphelper::SequenceAsHashMap(xRules->getByIndex(0))["FirstLineIndent"].get<sal_Int32>());
479 }
480 
481 DECLARE_OOXMLEXPORT_TEST(testTdf113258, "tdf113258.docx")
482 {
483     uno::Reference<text::XTextRange> xShape(getShape(1), uno::UNO_QUERY);
484     // This was 494, i.e. automatic spacing resulted in non-zero paragraph top
485     // margin for the first paragraph in a shape.
486     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0),
487                          getProperty<sal_Int32>(xShape->getStart(), "ParaTopMargin"));
488 }
489 
490 DECLARE_OOXMLEXPORT_TEST(testTdf113258_noBeforeAutospacing, "tdf113258_noBeforeAutospacing.docx")
491 {
492     uno::Reference<text::XTextRange> xShape(getShape(1), uno::UNO_QUERY);
493     // This was 0, i.e. disabled automatic spacing still resulted in zero paragraph
494     // top margin for the first paragraph in a shape.
495     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1764),
496                          getProperty<sal_Int32>(xShape->getStart(), "ParaTopMargin"));
497 }
498 
499 DECLARE_OOXMLEXPORT_TEST(testTdf120511_eatenSection, "tdf120511_eatenSection.docx")
500 {
501     xmlDocPtr pXmlDoc = parseLayoutDump();
502     sal_Int32 nHeight = getXPath(pXmlDoc, "/root/page[1]/infos/prtBounds", "height").toInt32();
503     sal_Int32 nWidth  = getXPath(pXmlDoc, "/root/page[1]/infos/prtBounds", "width").toInt32();
504     CPPUNIT_ASSERT_MESSAGE( "Page1 is portrait", nWidth < nHeight );
505     nHeight = getXPath(pXmlDoc, "/root/page[2]/infos/prtBounds", "height").toInt32();
506     nWidth  = getXPath(pXmlDoc, "/root/page[2]/infos/prtBounds", "width").toInt32();
507     CPPUNIT_ASSERT_MESSAGE( "Page2 is landscape", nWidth > nHeight );
508 }
509 
510 DECLARE_OOXMLEXPORT_TEST(testTdf104354, "tdf104354.docx")
511 {
512     uno::Reference<text::XTextRange> xShape(getShape(1), uno::UNO_QUERY);
513     // This was 494, i.e. automatic spacing resulted in non-zero paragraph top
514     // margin for the first paragraph in a text frame.
515     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0),
516                          getProperty<sal_Int32>(xShape->getStart(), "ParaTopMargin"));
517     // still 494 in the second paragraph
518     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(494),
519                          getProperty<sal_Int32>(xShape->getEnd(), "ParaTopMargin"));
520 }
521 
522 DECLARE_OOXMLEXPORT_TEST(testTdf104354_firstParaInSection, "tdf104354_firstParaInSection.docx")
523 {
524     uno::Reference<text::XFootnotesSupplier> xFootnotesSupplier(mxComponent, uno::UNO_QUERY);
525     uno::Reference<container::XIndexAccess> xFootnotes = xFootnotesSupplier->getFootnotes();
526     uno::Reference<text::XText> xText(xFootnotes->getByIndex(0), uno::UNO_QUERY);
527     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(494),
528                          getProperty<sal_Int32>(getParagraphOfText(1, xText), "ParaTopMargin"));
529     CPPUNIT_ASSERT_EQUAL(1, getPages());
530 }
531 
532 DECLARE_OOXMLEXPORT_TEST(testPageBreak_after, "pageBreak_after.odt")
533 {
534     // The problem was that the page breakAfter put the empty page BEFORE the table
535     xmlDocPtr pDump = parseLayoutDump();
536     assertXPath(pDump, "/root/page[1]/body/tab", 1);
537     // There should be two pages actually - a blank page after a page break.
538     CPPUNIT_ASSERT_EQUAL_MESSAGE("Did you fix?? Table should be on page one of two", 1, getPages());
539 }
540 
541 DECLARE_OOXMLEXPORT_TEST(testTdf107035, "tdf107035.docx")
542 {
543     // Select the second run containing the page number field
544     auto xPgNumRun = getRun(getParagraph(1), 2, "1");
545 
546     // Check that the page number field colour is set to "automatic".
547     sal_Int32 nPgNumColour = getProperty<sal_Int32>(xPgNumRun, "CharColor");
548     CPPUNIT_ASSERT_EQUAL(sal_Int32(COL_AUTO), nPgNumColour);
549 }
550 
551 DECLARE_OOXMLEXPORT_TEST(testTdf112118_DOCX, "tdf112118.docx")
552 {
553     // The resulting left margin width (2081) differs from its DOC counterpart from ww8export2.cxx,
554     // because DOCX import does two conversions between mm/100 and twips on the route, losing one
555     // twip on the road and arriving with a value that is 2 mm/100 less. I don't see an obvious way
556     // to avoid that.
557     static const struct {
558         const char* styleName;
559         struct {
560             const char* sideName;
561             sal_Int32 nMargin;
562             sal_Int32 nBorderDistance;
563             sal_Int32 nBorderWidth;
564         } sideParams[4];
565     } styleParams[] = {                      // Margin (MS-style), border distance, border width
566         {
567             "Standard",
568             {
569                 { "Top", 496, 847, 159 },    //  851 twip, 24 pt (from text), 4.5 pt
570                 { "Left", 2081, 706, 212 },  // 1701 twip, 20 pt (from text), 6.0 pt
571                 { "Bottom", 1401, 564, 35 }, // 1134 twip, 16 pt (from text), 1.0 pt
572                 { "Right", 3471, 423, 106 }  // 2268 twip, 12 pt (from text), 3.0 pt
573             }
574         },
575         {
576             "Converted1",
577             {
578                 { "Top", 847, 496, 159 },    //  851 twip, 24 pt (from edge), 4.5 pt
579                 { "Left", 706, 2081, 212 },  // 1701 twip, 20 pt (from edge), 6.0 pt
580                 { "Bottom", 564, 1401, 35 }, // 1134 twip, 16 pt (from edge), 1.0 pt
581                 { "Right", 423, 3471, 106 }  // 2268 twip, 12 pt (from edge), 3.0 pt
582             }
583         }
584     };
585     auto xStyles = getStyles("PageStyles");
586 
587     for (const auto& style : styleParams)
588     {
589         const OUString sName = OUString::createFromAscii(style.styleName);
590         uno::Reference<beans::XPropertySet> xStyle(xStyles->getByName(sName), uno::UNO_QUERY_THROW);
591         for (const auto& side : style.sideParams)
592         {
593             const OUString sSide = OUString::createFromAscii(side.sideName);
594             const OString sStage = style.styleName + OStringLiteral(" ") + side.sideName;
595 
596             sal_Int32 nMargin = getProperty<sal_Int32>(xStyle, sSide + "Margin");
597             CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(sStage + " margin width").getStr(),
598                 side.nMargin, nMargin);
599 
600             sal_Int32 nBorderDistance = getProperty<sal_Int32>(xStyle, sSide + "BorderDistance");
601             CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(sStage + " border distance").getStr(),
602                 side.nBorderDistance, nBorderDistance);
603 
604             table::BorderLine aBorder = getProperty<table::BorderLine>(xStyle, sSide + "Border");
605             CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(sStage + " border width").getStr(),
606                 side.nBorderWidth,
607                 sal_Int32(aBorder.OuterLineWidth + aBorder.InnerLineWidth + aBorder.LineDistance));
608 
609             // tdf#116472: check that AUTO border color is imported as black
610             CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(sStage + " border color").getStr(),
611                 sal_Int32(COL_BLACK), aBorder.Color);
612         }
613     }
614 }
615 
616 DECLARE_OOXMLEXPORT_TEST(testTdf82177_outsideCellBorders, "tdf82177_outsideCellBorders.docx")
617 {
618     uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
619     uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(), uno::UNO_QUERY);
620     uno::Reference< text::XTextTable > xTable( xTables->getByIndex(0), uno::UNO_QUERY );
621     uno::Reference< table::XCell > xCell = xTable->getCellByName( "E4" );
622     CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0), getProperty<table::BorderLine2>(xCell, "TopBorder").LineWidth);
623     CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0), getProperty<table::BorderLine2>(xCell, "LeftBorder").LineWidth);
624 }
625 
626 DECLARE_OOXMLEXPORT_TEST(testTdf82177_insideCellBorders, "tdf82177_insideCellBorders.docx")
627 {
628     uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
629     uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(), uno::UNO_QUERY);
630     uno::Reference< text::XTextTable > xTable( xTables->getByIndex(0), uno::UNO_QUERY );
631     uno::Reference< table::XCell > xCell = xTable->getCellByName( "E4" );
632     CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0), getProperty<table::BorderLine2>(xCell, "TopBorder").LineWidth);
633     CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0), getProperty<table::BorderLine2>(xCell, "LeftBorder").LineWidth);
634 }
635 
636 DECLARE_OOXMLEXPORT_TEST(testTdf82177_tblBorders, "tdf82177_tblBorders.docx")
637 {
638     uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
639     uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(), uno::UNO_QUERY);
640     uno::Reference< text::XTextTable > xTable( xTables->getByIndex(0), uno::UNO_QUERY );
641     uno::Reference< table::XCell > xCell = xTable->getCellByName( "A5" );
642     CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0), getProperty<table::BorderLine2>(xCell, "BottomBorder").LineWidth);
643     CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0), getProperty<table::BorderLine2>(xCell, "LeftBorder").LineWidth);
644     xCell.set(xTable->getCellByName( "E5" ));
645     CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0), getProperty<table::BorderLine2>(xCell, "TopBorder").LineWidth);
646     CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0), getProperty<table::BorderLine2>(xCell, "LeftBorder").LineWidth);
647 }
648 
649 DECLARE_OOXMLEXPORT_TEST(testTdf119760_positionCellBorder, "tdf119760_positionCellBorder.docx")
650 {
651     //inconsistent in Word even. 2016 positions on last row, 2003 positions on first cell.
652     sal_Int32 nRowLeft = parseDump("/root/page/body/tab[4]/row[1]/infos/bounds", "left").toInt32();
653     sal_Int32 nTextLeft  = parseDump("/root/page/body/tab[4]/row[1]/cell[1]/txt/infos/bounds", "left").toInt32();
654     CPPUNIT_ASSERT( nRowLeft < nTextLeft );
655 }
656 
657 DECLARE_OOXMLEXPORT_TEST(testTdf98620_environmentBiDi, "tdf98620_environmentBiDi.odt")
658 {
659     CPPUNIT_ASSERT_EQUAL(text::WritingMode2::RL_TB, getProperty<sal_Int16>( getParagraph(1), "WritingMode" ));
660     CPPUNIT_ASSERT_EQUAL(sal_Int32(style::ParagraphAdjust_RIGHT), getProperty<sal_Int32>( getParagraph(1), "ParaAdjust" ));
661 
662     CPPUNIT_ASSERT_EQUAL(text::WritingMode2::LR_TB, getProperty<sal_Int16>( getParagraph(2), "WritingMode" ));
663     CPPUNIT_ASSERT_EQUAL(sal_Int32(style::ParagraphAdjust_RIGHT), getProperty<sal_Int32>( getParagraph(2), "ParaAdjust" ));
664 }
665 
666 DECLARE_OOXMLEXPORT_TEST(testTdf116976, "tdf116976.docx")
667 {
668     // This was 0, relative size of shape after bitmap was ignored.
669     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(40),
670                          getProperty<sal_Int16>(getShape(1), "RelativeWidth"));
671 }
672 
673 DECLARE_OOXMLEXPORT_TEST(testTdf116985, "tdf116985.docx")
674 {
675     // Body frame width is 10800, 40% is the requested relative width, with 144
676     // spacing to text on the left/right side.  So ideal width would be 4032,
677     // was 3431. Allow one pixel tolerance, though.
678     sal_Int32 nWidth
679         = parseDump("/root/page[1]/body/txt[1]/anchored/fly/infos/bounds", "width").toInt32();
680     CPPUNIT_ASSERT(nWidth > 4000);
681 }
682 
683 DECLARE_OOXMLEXPORT_TEST(testTdf116801, "tdf116801.docx")
684 {
685     uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
686     uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
687                                                     uno::UNO_QUERY);
688     // This raised a lang::IndexOutOfBoundsException, table was missing from
689     // the import result.
690     uno::Reference<text::XTextTable> xTable(xTables->getByIndex(0), uno::UNO_QUERY);
691     uno::Reference<text::XTextRange> xCell(xTable->getCellByName("D1"), uno::UNO_QUERY);
692     CPPUNIT_ASSERT_EQUAL(OUString("D1"), xCell->getString());
693 }
694 
695 DECLARE_OOXMLEXPORT_TEST(testTdf107969, "tdf107969.docx")
696 {
697     // A VML object in a footnote's tracked changes caused write past end of document.xml at export to docx.
698     // After that, importing after export failed with
699     // SAXParseException: '[word/document.xml line 2]: Extra content at the end of the document', Stream 'word/document.xml'.
700 }
701 
702 DECLARE_OOXMLEXPORT_TEST(testOpenDocumentAsReadOnly, "open-as-read-only.docx")
703 {
704     SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument *>(mxComponent.get());
705     CPPUNIT_ASSERT(pTextDoc);
706     CPPUNIT_ASSERT(pTextDoc->GetDocShell()->IsSecurityOptOpenReadOnly());
707 }
708 
709 DECLARE_OOXMLEXPORT_TEST(testNoDefault, "noDefault.docx")
710 {
711     uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
712     uno::Reference<container::XIndexAccess> xTables(xTextTablesSupplier->getTextTables(), uno::UNO_QUERY);
713     uno::Reference<text::XTextTable> xTable(xTables->getByIndex(0), uno::UNO_QUERY);
714     uno::Reference<text::XTextRange> xCell(xTable->getCellByName("A1"), uno::UNO_QUERY);
715     uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xCell->getText(), uno::UNO_QUERY);
716     uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
717     uno::Reference<text::XTextRange> xPara(xParaEnum->nextElement(), uno::UNO_QUERY);
718 
719     // Row 1: color directly applied to the paragraph, overrides table and style colors
720     CPPUNIT_ASSERT_EQUAL(sal_Int32(0x2E74B5), getProperty<sal_Int32>(getRun(xPara,1), "CharColor"));
721 
722     // Row2: (still part of firstRow table-style) ought to use the Normal style color, not the table-style color(5B9BD5)
723     //xCell.set(xTable->getCellByName("A2"), uno::UNO_QUERY);
724     //xParaEnumAccess.set(xCell->getText(), uno::UNO_QUERY);
725     //xParaEnum = xParaEnumAccess->createEnumeration();
726     //xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
727     //CPPUNIT_ASSERT_EQUAL(sal_Int32(COL_LIGHTMAGENTA), getProperty<sal_Int32>(getRun(xPara,1), "CharColor"));
728 
729     // Row 3+: Normal style still applied, even if nothing is specified with w:default="1"
730     xCell.set(xTable->getCellByName("A3"), uno::UNO_QUERY);
731     xParaEnumAccess.set(xCell->getText(), uno::UNO_QUERY);
732     xParaEnum = xParaEnumAccess->createEnumeration();
733     xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
734     CPPUNIT_ASSERT_EQUAL(sal_Int32(COL_LIGHTMAGENTA), getProperty<sal_Int32>(getRun(xPara,1), "CharColor"));
735 }
736 
737 DECLARE_OOXMLEXPORT_TEST(testMarginsFromStyle, "margins_from_style.docx")
738 {
739     // tdf#118521 paragraphs with direct formatting of top or bottom margins have
740     // lost the other margin comes from paragraph style, getting a bad
741     // margin from the default style
742 
743     // from direct formatting
744     CPPUNIT_ASSERT_EQUAL(sal_Int32(35), getProperty<sal_Int32>(getParagraph(1), "ParaTopMargin"));
745     // from paragraph style
746     CPPUNIT_ASSERT_EQUAL(sal_Int32(106), getProperty<sal_Int32>(getParagraph(1), "ParaBottomMargin"));
747 
748     // from paragraph style
749     CPPUNIT_ASSERT_EQUAL(sal_Int32(388), getProperty<sal_Int32>(getParagraph(3), "ParaTopMargin"));
750     // from direct formatting
751     CPPUNIT_ASSERT_EQUAL(sal_Int32(600), getProperty<sal_Int32>(getParagraph(3), "ParaBottomMargin"));
752 }
753 
754 DECLARE_OOXMLEXPORT_TEST(testTdf104348_contextMargin, "tdf104348_contextMargin.docx")
755 {
756     // tdf#104348 shows that ContextMargin belongs with Top/Bottom handling
757 
758     uno::Reference<beans::XPropertySet> xMyStyle(getStyles("ParagraphStyles")->getByName("MyStyle"), uno::UNO_QUERY);
759     // from paragraph style - this is what direct formatting should equal
760     sal_Int32 nMargin = getProperty<sal_Int32>(xMyStyle, "ParaBottomMargin");
761     CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nMargin);
762     // from direct formatting
763     CPPUNIT_ASSERT_EQUAL(nMargin, getProperty<sal_Int32>(getParagraph(2), "ParaBottomMargin"));
764 }
765 
766 DECLARE_OOXMLEXPORT_TEST(testTdf118521_marginsLR, "tdf118521_marginsLR.docx")
767 {
768     // tdf#118521 paragraphs with direct formatting of only some of left, right, or first margins have
769     // lost the other unset margins coming from paragraph style, getting a bad margin from the default style instead
770 
771     uno::Reference<beans::XPropertySet> xMyStyle(getStyles("ParagraphStyles")->getByName("MyStyle"), uno::UNO_QUERY);
772     // from paragraph style - this is what direct formatting should equal
773     sal_Int32 nMargin = getProperty<sal_Int32>(xMyStyle, "ParaLeftMargin");
774     CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nMargin);
775     // from direct formatting
776     CPPUNIT_ASSERT_EQUAL(nMargin, getProperty<sal_Int32>(getParagraph(1), "ParaLeftMargin"));
777 
778     nMargin = getProperty<sal_Int32>(xMyStyle, "ParaRightMargin");
779     CPPUNIT_ASSERT_EQUAL(sal_Int32(1900), nMargin);
780     CPPUNIT_ASSERT_EQUAL(nMargin, getProperty<sal_Int32>(getParagraph(2), "ParaRightMargin"));
781     CPPUNIT_ASSERT_EQUAL(sal_Int32(882), getProperty<sal_Int32>(getParagraph(2), "ParaFirstLineIndent"));
782 }
783 
784 DECLARE_OOXMLIMPORT_TEST(testTdf104797, "tdf104797.docx")
785 {
786     // check moveFrom and moveTo
787     CPPUNIT_ASSERT_EQUAL( OUString( "Will this sentence be duplicated?" ), getParagraph( 1 )->getString());
788     CPPUNIT_ASSERT_EQUAL( OUString( "" ), getRun( getParagraph( 1 ), 1 )->getString());
789     CPPUNIT_ASSERT(hasProperty(getRun(getParagraph(1), 2), "RedlineType"));
790     CPPUNIT_ASSERT_EQUAL(OUString("Delete"),getProperty<OUString>(getRun(getParagraph(1), 2), "RedlineType"));
791     CPPUNIT_ASSERT_EQUAL(true,getProperty<bool>(getRun(getParagraph(1), 2), "IsStart"));
792     CPPUNIT_ASSERT_EQUAL( OUString( "This is a filler sentence. Will this sentence be duplicated ADDED STUFF?" ),
793             getParagraph( 2 )->getString());
794     CPPUNIT_ASSERT_EQUAL( OUString( "" ), getRun( getParagraph( 2 ), 1 )->getString());
795     CPPUNIT_ASSERT_EQUAL( OUString( "This is a filler sentence." ), getRun( getParagraph( 2 ), 2 )->getString());
796     CPPUNIT_ASSERT_EQUAL( OUString( "" ), getRun( getParagraph( 2 ), 3 )->getString());
797     CPPUNIT_ASSERT(hasProperty(getRun(getParagraph(2), 3), "RedlineType"));
798     CPPUNIT_ASSERT_EQUAL(OUString("Insert"),getProperty<OUString>(getRun(getParagraph(2), 3), "RedlineType"));
799     CPPUNIT_ASSERT_EQUAL(true,getProperty<bool>(getRun(getParagraph(2), 3), "IsStart"));
800     CPPUNIT_ASSERT_EQUAL( OUString( " Will this sentence be duplicated ADDED STUFF?" ), getRun( getParagraph( 2 ), 4 )->getString());
801 }
802 
803 DECLARE_OOXMLEXPORT_TEST(testTdf113608_runAwayNumbering, "tdf113608_runAwayNumbering.docx")
804 {
805     // check that an incorrect numbering style is not applied
806     // after removing a w:r-less paragraph
807     CPPUNIT_ASSERT_EQUAL(OUString(), getProperty<OUString>(getParagraph(2), "NumberingStyleName"));
808 }
809 
810 DECLARE_OOXMLEXPORT_TEST(testTdf119188_list_margin_in_cell, "tdf119188_list_margin_in_cell.docx")
811 {
812     uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
813     uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(), uno::UNO_QUERY);
814     uno::Reference<text::XTextTable> xTable(xTables->getByIndex(0), uno::UNO_QUERY);
815     uno::Reference<text::XTextRange> xCell(xTable->getCellByName("A1"), uno::UNO_QUERY);
816 
817     // lists with auto margins in cells: top margin of the first paragraph is zero,
818     // but not the bottom margin of the last paragraph, also other list items have got
819     // zero margins.
820 
821     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), getProperty<sal_Int32>(getParagraphOfText(1, xCell->getText()), "ParaTopMargin"));
822     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), getProperty<sal_Int32>(getParagraphOfText(1, xCell->getText()), "ParaBottomMargin"));
823     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), getProperty<sal_Int32>(getParagraphOfText(2, xCell->getText()), "ParaTopMargin"));
824     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), getProperty<sal_Int32>(getParagraphOfText(2, xCell->getText()), "ParaBottomMargin"));
825     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), getProperty<sal_Int32>(getParagraphOfText(3, xCell->getText()), "ParaTopMargin"));
826     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(494), getProperty<sal_Int32>(getParagraphOfText(3, xCell->getText()), "ParaBottomMargin"));
827 }
828 
829 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testChart_BorderLine_Style, "Chart_BorderLine_Style.docx")
830 {
831     /* DOCX containing Chart with BorderLine Style as Dash Type should get preserved
832      * inside an XML tag <a:prstDash> with value "dash", "sysDot, "lgDot", etc.
833      */
834     xmlDocPtr pXmlDoc = parseExport("word/charts/chart1.xml");
835     assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:plotArea/c:barChart/c:ser[1]/c:spPr/a:ln/a:prstDash", "val", "sysDot");
836     assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:plotArea/c:barChart/c:ser[2]/c:spPr/a:ln/a:prstDash", "val", "sysDash");
837     assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:plotArea/c:barChart/c:ser[3]/c:spPr/a:ln/a:prstDash", "val", "dash");
838 }
839 
840 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testChart_Plot_BorderLine_Style, "Chart_Plot_BorderLine_Style.docx")
841 {
842     /* DOCX containing Chart wall (plot area) and Chart Page with BorderLine Style as Dash Type
843      * should get preserved inside an XML tag <a:prstDash> with value "dash", "sysDot, "lgDot", etc.
844      */
845     xmlDocPtr pXmlDoc = parseExport("word/charts/chart1.xml");
846     assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:plotArea/c:spPr/a:ln/a:prstDash", "val", "lgDashDot");
847     assertXPath(pXmlDoc, "/c:chartSpace/c:spPr/a:ln/a:prstDash", "val", "sysDash");
848 
849 }
850 
851 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTrackChangesDeletedEmptyParagraph, "testTrackChangesDeletedEmptyParagraph.docx")
852 {
853     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
854     assertXPath(pXmlDoc, "/w:document/w:body/w:p[3]/w:pPr/w:rPr/w:del");
855 }
856 
857 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTrackChangesEmptyParagraphsInADeletion, "testTrackChangesEmptyParagraphsInADeletion.docx")
858 {
859     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
860     for (int i = 1; i < 12; ++i)
861         assertXPath(pXmlDoc, "/w:document/w:body/w:p[" + OString::number(i) + "]/w:pPr/w:rPr/w:del");
862 }
863 
864 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf70234, "tdf70234.docx")
865 {
866     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
867     // import field with tracked deletion
868     assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:del/w:r[1]/w:fldChar");
869 
870     // export multiple runs of a field with tracked deletion
871     assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:del/w:r", 6);
872 
873     // export w:delInstrText
874     assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:del/w:r/w:delInstrText");
875 }
876 
877 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf115212, "tdf115212.docx")
878 {
879     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
880     // export field with tracked deletion
881     assertXPath(pXmlDoc, "//w:p[2]/w:del[1]/w:r[1]/w:fldChar");
882 }
883 
884 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf126243, "tdf120338.docx")
885 {
886     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
887     // export change tracking rejection data for tracked paragraph style change
888     assertXPath(pXmlDoc, "/w:document/w:body/w:p[11]/w:pPr/w:pPrChange/w:pPr/w:pStyle", "val", "Heading3");
889 }
890 
891 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf126245, "tdf126245.docx")
892 {
893     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
894     // export change tracking rejection data for tracked numbering change
895     assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:pPr/w:pPrChange/w:pPr/w:numPr/w:numId", "val", "1");
896 }
897 
898 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf124491, "tdf124491.docx")
899 {
900     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
901     // import format change of empty lines, FIXME: change w:r with w:pPr in export
902     assertXPath(pXmlDoc, "/w:document/w:body/w:p[2]/*/w:rPr/w:rPrChange");
903     // empty line without format change
904     assertXPath(pXmlDoc, "/w:document/w:body/w:p[4]/*/w:rPrChange", 0);
905     assertXPath(pXmlDoc, "/w:document/w:body/w:p[4]/*/*/w:rPrChange", 0);
906 }
907 
908 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf105485, "tdf105485.docx")
909 {
910     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
911     // import change tracking of deleted comments
912     assertXPath(pXmlDoc, "//w:del/w:r/w:commentReference");
913 }
914 
915 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf125894, "tdf125894.docx")
916 {
917     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
918     // import change tracking in frames
919     assertXPath(pXmlDoc, "//w:del", 2);
920     assertXPath(pXmlDoc, "//w:ins");
921 }
922 
923 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf128156, "tdf128156.docx")
924 {
925     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
926     // import change tracking in frames
927     assertXPath(pXmlDoc, "//w:ins");
928 }
929 
930 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf125546, "tdf125546.docx")
931 {
932     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
933     // compress redlines (it was 15)
934     assertXPath(pXmlDoc, "//w:rPrChange", 2);
935 }
936 
937 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testLabelWidthAndPosition_Left_FirstLineIndent, "Hau_min_list2.fodt")
938 {
939     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
940     // list is LABEL_WIDTH_AND_POSITION with SvxAdjust::Left
941     // I) LTR
942     // a) all LTR cases with no number text look good in Word
943     // 1) negative first line indent on paragraph:
944     // no list width/indent: this one was 0 previously; this looks good
945     assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:pPr/w:ind", "start", "0");
946     assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:pPr/w:ind", "hanging", "399");
947     assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:pPr/w:ind", "end", "0");
948     // list width:
949     assertXPath(pXmlDoc, "/w:document/w:body/w:p[2]/w:pPr/w:ind", "start", "567");
950     assertXPath(pXmlDoc, "/w:document/w:body/w:p[2]/w:pPr/w:ind", "hanging", "966");
951     assertXPath(pXmlDoc, "/w:document/w:body/w:p[2]/w:pPr/w:ind", "end", "0");
952     // list indent:
953     assertXPath(pXmlDoc, "/w:document/w:body/w:p[3]/w:pPr/w:ind", "start", "567");
954     assertXPath(pXmlDoc, "/w:document/w:body/w:p[3]/w:pPr/w:ind", "hanging", "399");
955     assertXPath(pXmlDoc, "/w:document/w:body/w:p[3]/w:pPr/w:ind", "end", "0");
956     // list width + list indent:
957     assertXPath(pXmlDoc, "/w:document/w:body/w:p[4]/w:pPr/w:ind", "start", "1134");
958     assertXPath(pXmlDoc, "/w:document/w:body/w:p[4]/w:pPr/w:ind", "hanging", "966");
959     assertXPath(pXmlDoc, "/w:document/w:body/w:p[4]/w:pPr/w:ind", "end", "0");
960     // 2) positive first line indent on paragraph:
961     // no list width/indent:
962     assertXPath(pXmlDoc, "/w:document/w:body/w:p[5]/w:pPr/w:ind", "start", "0");
963     assertXPath(pXmlDoc, "/w:document/w:body/w:p[5]/w:pPr/w:ind", "firstLine", "420");
964     assertXPath(pXmlDoc, "/w:document/w:body/w:p[5]/w:pPr/w:ind", "end", "0");
965     // list width:
966     assertXPath(pXmlDoc, "/w:document/w:body/w:p[6]/w:pPr/w:ind", "start", "567");
967     assertXPath(pXmlDoc, "/w:document/w:body/w:p[6]/w:pPr/w:ind", "hanging", "147");
968     assertXPath(pXmlDoc, "/w:document/w:body/w:p[6]/w:pPr/w:ind", "end", "0");
969     // list indent:
970     assertXPath(pXmlDoc, "/w:document/w:body/w:p[7]/w:pPr/w:ind", "start", "567");
971     assertXPath(pXmlDoc, "/w:document/w:body/w:p[7]/w:pPr/w:ind", "firstLine", "420");
972     assertXPath(pXmlDoc, "/w:document/w:body/w:p[7]/w:pPr/w:ind", "end", "0");
973     // list width + list indent:
974     assertXPath(pXmlDoc, "/w:document/w:body/w:p[8]/w:pPr/w:ind", "start", "1134");
975     assertXPath(pXmlDoc, "/w:document/w:body/w:p[8]/w:pPr/w:ind", "hanging", "147");
976     assertXPath(pXmlDoc, "/w:document/w:body/w:p[8]/w:pPr/w:ind", "end", "0");
977     // b) all LTR cases with number text: the indent looks good but some tabs are wrong
978     // 1) negative first line indent on paragraph:
979     // no list width/indent: this one was 0 previously; this looks good
980     assertXPath(pXmlDoc, "/w:document/w:body/w:p[9]/w:pPr/w:ind", "start", "0");
981     assertXPath(pXmlDoc, "/w:document/w:body/w:p[9]/w:pPr/w:ind", "hanging", "399");
982     assertXPath(pXmlDoc, "/w:document/w:body/w:p[9]/w:pPr/w:ind", "end", "0");
983     // list width:
984     assertXPath(pXmlDoc, "/w:document/w:body/w:p[10]/w:pPr/w:ind", "start", "567");
985     assertXPath(pXmlDoc, "/w:document/w:body/w:p[10]/w:pPr/w:ind", "hanging", "966");
986     assertXPath(pXmlDoc, "/w:document/w:body/w:p[10]/w:pPr/w:ind", "end", "0");
987     // list indent:
988     assertXPath(pXmlDoc, "/w:document/w:body/w:p[11]/w:pPr/w:ind", "start", "567");
989     assertXPath(pXmlDoc, "/w:document/w:body/w:p[11]/w:pPr/w:ind", "hanging", "399");
990     assertXPath(pXmlDoc, "/w:document/w:body/w:p[11]/w:pPr/w:ind", "end", "0");
991     // list width + list indent:
992     assertXPath(pXmlDoc, "/w:document/w:body/w:p[12]/w:pPr/w:ind", "start", "1134");
993     assertXPath(pXmlDoc, "/w:document/w:body/w:p[12]/w:pPr/w:ind", "hanging", "966");
994     assertXPath(pXmlDoc, "/w:document/w:body/w:p[12]/w:pPr/w:ind", "end", "0");
995     // 2) positive first line indent on paragraph:
996     // no list width/indent:
997     assertXPath(pXmlDoc, "/w:document/w:body/w:p[13]/w:pPr/w:ind", "start", "0");
998     assertXPath(pXmlDoc, "/w:document/w:body/w:p[13]/w:pPr/w:ind", "firstLine", "420");
999     assertXPath(pXmlDoc, "/w:document/w:body/w:p[13]/w:pPr/w:ind", "end", "0");
1000     // list width:
1001     assertXPath(pXmlDoc, "/w:document/w:body/w:p[14]/w:pPr/w:ind", "start", "567");
1002     assertXPath(pXmlDoc, "/w:document/w:body/w:p[14]/w:pPr/w:ind", "hanging", "147");
1003     assertXPath(pXmlDoc, "/w:document/w:body/w:p[14]/w:pPr/w:ind", "end", "0");
1004     // list indent:
1005     assertXPath(pXmlDoc, "/w:document/w:body/w:p[15]/w:pPr/w:ind", "start", "567");
1006     assertXPath(pXmlDoc, "/w:document/w:body/w:p[15]/w:pPr/w:ind", "firstLine", "420");
1007     assertXPath(pXmlDoc, "/w:document/w:body/w:p[15]/w:pPr/w:ind", "end", "0");
1008     // list width + list indent:
1009     assertXPath(pXmlDoc, "/w:document/w:body/w:p[16]/w:pPr/w:ind", "start", "1134");
1010     assertXPath(pXmlDoc, "/w:document/w:body/w:p[16]/w:pPr/w:ind", "hanging", "147");
1011     assertXPath(pXmlDoc, "/w:document/w:body/w:p[16]/w:pPr/w:ind", "end", "0");
1012     // (w:p[17] is empty)
1013     // I) RTL
1014     // a) only RTL cases with no number text and no width/indent look good in Word
1015     // 1) negative first line indent on paragraph:
1016     // no list width/indent
1017     assertXPath(pXmlDoc, "/w:document/w:body/w:p[18]/w:pPr/w:ind", "start", "0");
1018     assertXPath(pXmlDoc, "/w:document/w:body/w:p[18]/w:pPr/w:ind", "hanging", "399");
1019     assertXPath(pXmlDoc, "/w:document/w:body/w:p[18]/w:pPr/w:ind", "end", "0");
1020     // 2) positive first line indent on paragraph:
1021     // no list width/indent:
1022     assertXPath(pXmlDoc, "/w:document/w:body/w:p[22]/w:pPr/w:ind", "start", "0");
1023     assertXPath(pXmlDoc, "/w:document/w:body/w:p[22]/w:pPr/w:ind", "firstLine", "420");
1024     assertXPath(pXmlDoc, "/w:document/w:body/w:p[22]/w:pPr/w:ind", "end", "0");
1025     // b) RTL cases with number text: the indent looks good but some tabs are wrong
1026     // 1) negative first line indent on paragraph:
1027     // no list width/indent
1028     assertXPath(pXmlDoc, "/w:document/w:body/w:p[26]/w:pPr/w:ind", "start", "0");
1029     assertXPath(pXmlDoc, "/w:document/w:body/w:p[26]/w:pPr/w:ind", "hanging", "399");
1030     assertXPath(pXmlDoc, "/w:document/w:body/w:p[26]/w:pPr/w:ind", "end", "0");
1031     // 2) positive first line indent on paragraph:
1032     // no list width/indent:
1033     assertXPath(pXmlDoc, "/w:document/w:body/w:p[30]/w:pPr/w:ind", "start", "0");
1034     assertXPath(pXmlDoc, "/w:document/w:body/w:p[30]/w:pPr/w:ind", "firstLine", "420");
1035     assertXPath(pXmlDoc, "/w:document/w:body/w:p[30]/w:pPr/w:ind", "end", "0");
1036     // TODO: other cases
1037 }
1038 
1039 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf124604, "tdf124604.docx")
1040 {
1041     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
1042     // If the numbering comes from a base style, indentation of the base style has also priority.
1043     assertXPath(pXmlDoc, "/w:document/w:body/w:p[7]/w:pPr/w:ind", "start", "0");
1044 }
1045 
1046 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf95374, "tdf95374.docx")
1047 {
1048     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
1049     // Numbering disabled by non-existent numId=0, disabling also inheritance of indentation of parent styles
1050     assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:pPr/w:ind", "hanging", "0");
1051     assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:pPr/w:ind", "start", "1136");
1052 }
1053 
1054 DECLARE_OOXMLEXPORT_TEST(testTdf118691, "tdf118691.docx")
1055 {
1056     uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
1057     uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
1058                                                     uno::UNO_QUERY);
1059     // Text "Before" stays in the first cell, not removed before the table because of
1060     // bad handling of <w:cr>
1061     uno::Reference<text::XTextTable> xTable(xTables->getByIndex(0), uno::UNO_QUERY);
1062     uno::Reference<text::XTextRange> xCell(xTable->getCellByName("A1"), uno::UNO_QUERY);
1063     CPPUNIT_ASSERT_EQUAL(OUString("Before\nAfter"), xCell->getString());
1064 }
1065 
1066 DECLARE_OOXMLEXPORT_TEST(testTdf64264, "tdf64264.docx")
1067 {
1068     // DOCX table rows with tblHeader setting mustn't modify the count of the
1069     // repeated table header rows, when there is rows before them without tblHeader settings.
1070     xmlDocPtr pDump = parseLayoutDump();
1071     CPPUNIT_ASSERT_EQUAL(2, getPages());
1072 
1073     // table starts on page 1 and finished on page 2
1074     // and it has got only a single repeating header line
1075     assertXPath(pDump, "/root/page[2]/body/tab", 1);
1076     assertXPath(pDump, "/root/page[2]/body/tab/row", 47);
1077     CPPUNIT_ASSERT_EQUAL(OUString("Repeating Table Header"),
1078                          parseDump("/root/page[2]/body/tab/row[1]/cell[1]/txt/text()"));
1079     CPPUNIT_ASSERT_EQUAL(OUString("Text"),
1080                          parseDump("/root/page[2]/body/tab/row[2]/cell[1]/txt/text()"));
1081 }
1082 
1083 DECLARE_OOXMLEXPORT_TEST(testTdf58944RepeatingTableHeader, "tdf58944-repeating-table-header.docx")
1084 {
1085     // DOCX tables with more than 10 repeating header lines imported without repeating header lines
1086     // as a workaround for MSO's limitation of header line repetition
1087     xmlDocPtr pDump = parseLayoutDump();
1088     CPPUNIT_ASSERT_EQUAL(2, getPages());
1089 
1090     // table starts on page 1 and finished on page 2
1091     // instead of showing only a part of it on page 2
1092     assertXPath(pDump, "/root/page[1]/body/tab", 1);
1093     assertXPath(pDump, "/root/page[1]/body/tab/row", 11);
1094     CPPUNIT_ASSERT_EQUAL(OUString("Test1"),
1095                          parseDump("/root/page[2]/body/tab/row[1]/cell[1]/txt/text()"));
1096     CPPUNIT_ASSERT_EQUAL(OUString("Test2"),
1097                          parseDump("/root/page[2]/body/tab/row[2]/cell[1]/txt/text()"));
1098 }
1099 
1100 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf81100, "tdf81100.docx")
1101 {
1102     xmlDocPtr pXmlDoc = parseExport("word/styles.xml");
1103     CPPUNIT_ASSERT(pXmlDoc);
1104     // keep "repeat table header" setting of table styles
1105     assertXPath(pXmlDoc, "/w:styles/w:style/w:tblStylePr/w:trPr/w:tblHeader", 4);
1106 
1107     xmlDocPtr pDump = parseLayoutDump();
1108     CPPUNIT_ASSERT_EQUAL(3, getPages());
1109 
1110     // table starts on page 1 and finished on page 2
1111     // and it has got only a single repeating header line
1112     assertXPath(pDump, "/root/page[2]/body/tab[1]", 1);
1113     assertXPath(pDump, "/root/page[2]/body/tab[1]/row", 2);
1114     assertXPath(pDump, "/root/page[3]/body/tab", 1);
1115     if (!mbExported) // TODO export tblHeader=false
1116         assertXPath(pDump, "/root/page[3]/body/tab/row", 1);
1117 }
1118 
1119 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf121597TrackedDeletionOfMultipleParagraphs, "tdf121597.odt")
1120 {
1121     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
1122 
1123     // check paragraphs with removed paragraph mark
1124     assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:pPr/w:rPr/w:del");
1125     assertXPath(pXmlDoc, "/w:document/w:body/w:p[2]/w:pPr/w:rPr/w:del");
1126     assertXPath(pXmlDoc, "/w:document/w:body/w:p[4]/w:pPr/w:rPr/w:del");
1127     assertXPath(pXmlDoc, "/w:document/w:body/w:p[5]/w:pPr/w:rPr/w:del");
1128     assertXPath(pXmlDoc, "/w:document/w:body/w:p[7]/w:pPr/w:rPr/w:del");
1129     assertXPath(pXmlDoc, "/w:document/w:body/w:p[10]/w:pPr/w:rPr/w:del");
1130 }
1131 
1132 DECLARE_OOXMLEXPORT_TEST(testTdf123189_tableBackground, "table-black_fill.docx")
1133 {
1134     uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
1135     uno::Reference<container::XIndexAccess> xTables(xTextTablesSupplier->getTextTables(), uno::UNO_QUERY);
1136     uno::Reference<text::XTextTable> xTable(xTables->getByIndex(0), uno::UNO_QUERY);
1137 
1138     uno::Reference<table::XCell> xCell = xTable->getCellByName("A1");
1139     CPPUNIT_ASSERT_EQUAL(COL_TRANSPARENT, Color(getProperty<sal_uInt32>(xCell, "BackColor")));
1140 }
1141 
1142 DECLARE_OOXMLIMPORT_TEST(testTdf116084, "tdf116084.docx")
1143 {
1144     // tracked line is not a single text portion: w:del is recognized within w:ins
1145     CPPUNIT_ASSERT_EQUAL( OUString( "" ), getRun( getParagraph( 1 ), 1 )->getString());
1146     CPPUNIT_ASSERT(hasProperty(getRun(getParagraph(1), 1), "RedlineType"));
1147     CPPUNIT_ASSERT_EQUAL( OUString( "There should be a better start to this. " ), getRun( getParagraph( 1 ), 2 )->getString());
1148 }
1149 
1150 DECLARE_OOXMLIMPORT_TEST(testTdf121176, "tdf121176.docx")
1151 {
1152     // w:del is imported correctly when it is in a same size w:ins
1153     CPPUNIT_ASSERT_EQUAL( OUString( "" ), getRun( getParagraph( 1 ), 1 )->getString());
1154     CPPUNIT_ASSERT(hasProperty(getRun(getParagraph(1), 1), "RedlineType"));
1155     CPPUNIT_ASSERT_EQUAL( OUString( "must" ), getRun( getParagraph( 1 ), 2 )->getString());
1156 }
1157 
1158 DECLARE_OOXMLIMPORT_TEST(testTdf123054, "tdf123054.docx")
1159 {
1160     CPPUNIT_ASSERT_EQUAL(OUString("No Spacing"),
1161                          getProperty<OUString>(getParagraph(20), "ParaStyleName"));
1162 }
1163 
1164 DECLARE_OOXMLEXPORT_TEST(testTdf67207_MERGEFIELD_DATABASE, "tdf67207.docx")
1165 {
1166     // database fields use the database "database" and its table "Sheet1"
1167     uno::Reference<beans::XPropertySet> xTextField = getProperty< uno::Reference<beans::XPropertySet> >(getRun(getParagraph(2), 2), "TextField");
1168     CPPUNIT_ASSERT(xTextField.is());
1169     uno::Reference<lang::XServiceInfo> xServiceInfo(xTextField, uno::UNO_QUERY_THROW);
1170     uno::Reference<text::XDependentTextField> xDependent(xTextField, uno::UNO_QUERY_THROW);
1171 
1172     CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.Database"));
1173     OUString sValue;
1174     xTextField->getPropertyValue("Content") >>= sValue;
1175     CPPUNIT_ASSERT_EQUAL(OUString::fromUtf8("<c1>"), sValue);
1176 
1177     uno::Reference<beans::XPropertySet> xFiledMaster = xDependent->getTextFieldMaster();
1178     uno::Reference<lang::XServiceInfo> xFiledMasterServiceInfo(xFiledMaster, uno::UNO_QUERY_THROW);
1179 
1180     CPPUNIT_ASSERT(xFiledMasterServiceInfo->supportsService("com.sun.star.text.fieldmaster.Database"));
1181 
1182     // Defined properties: DataBaseName, Name, DataTableName, DataColumnName, DependentTextFields, DataCommandType, InstanceName, DataBaseURL
1183     CPPUNIT_ASSERT(xFiledMaster->getPropertyValue("DataBaseName") >>= sValue);
1184     CPPUNIT_ASSERT_EQUAL(OUString("database"), sValue);
1185     sal_Int32 nCommandType;
1186     CPPUNIT_ASSERT(xFiledMaster->getPropertyValue("DataCommandType") >>= nCommandType);
1187     CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nCommandType); // css::sdb::CommandType::TABLE
1188     CPPUNIT_ASSERT(xFiledMaster->getPropertyValue("DataTableName") >>= sValue);
1189     CPPUNIT_ASSERT_EQUAL(OUString("Sheet1"), sValue);
1190     CPPUNIT_ASSERT(xFiledMaster->getPropertyValue("DataColumnName") >>= sValue);
1191     CPPUNIT_ASSERT_EQUAL(OUString("c1"), sValue);
1192     CPPUNIT_ASSERT(xFiledMaster->getPropertyValue("InstanceName") >>= sValue);
1193     CPPUNIT_ASSERT_EQUAL(OUString("com.sun.star.text.fieldmaster.DataBase.database.Sheet1.c1"), sValue);
1194 }
1195 
1196 CPPUNIT_PLUGIN_IMPLEMENT();
1197 
1198 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1199