1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <com/sun/star/frame/XStorable.hpp>
11 #include <com/sun/star/drawing/FillStyle.hpp>
12 #include <com/sun/star/awt/Gradient.hpp>
13 #include <com/sun/star/packages/zip/ZipFileAccess.hpp>
14 #include <com/sun/star/style/TabStop.hpp>
15 #include <com/sun/star/view/XViewSettingsSupplier.hpp>
16 #include <com/sun/star/text/XTextFrame.hpp>
17 #include <com/sun/star/text/XTextTable.hpp>
18 #include <com/sun/star/text/XTextFramesSupplier.hpp>
19 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
20 #include <com/sun/star/style/ParagraphAdjust.hpp>
21 #include <com/sun/star/view/XSelectionSupplier.hpp>
22 #include <com/sun/star/table/BorderLine2.hpp>
23 #include <com/sun/star/table/ShadowFormat.hpp>
24 #include <com/sun/star/text/XPageCursor.hpp>
25 #include <com/sun/star/awt/FontWeight.hpp>
26 #include <com/sun/star/awt/FontUnderline.hpp>
27 #include <com/sun/star/awt/FontSlant.hpp>
28 #include <com/sun/star/text/WrapTextMode.hpp>
30 #include <unotools/tempfile.hxx>
31 #include <unotools/ucbstreamhelper.hxx>
32 #include <rtl/strbuf.hxx>
33 #include <swmodeltestbase.hxx>
35 #include <libxml/xpathInternals.h>
36 #include <libxml/parserInternals.h>
38 class Test
: public SwModelTestBase
42 void defaultTabStopNotInStyles();
44 void testMathEscape();
46 void testMathAccents();
48 void testMathEscaping();
50 void testMathMalformedXml();
51 void testMathMatrix();
52 void testMathMso2k7();
54 void testMathOverbraceUnderbrace();
55 void testMathOverstrike();
56 void testMathPlaceholders();
58 void testMathSubscripts();
59 void testMathVerticalStacks();
60 void testTablePosition();
62 void testTableBorders();
65 void test1Table1Page();
66 void testTextFrames();
67 void testTextFrameBorders();
68 void testTextframeGradient();
70 void testTableStylerPrSz();
71 void testMathLiteral();
83 CPPUNIT_TEST_SUITE(Test
);
84 #if !defined(MACOSX) && !defined(WNT)
87 CPPUNIT_TEST_SUITE_END();
92 * Given that some problem doesn't affect the result in the importer, we
93 * test the resulting file directly, by opening the zip file, parsing an
94 * xml stream, and asserting an XPath expression. This method returns the
95 * xml stream, so that you can do the asserting.
97 xmlDocPtr
parseExport();
98 void assertXPath(xmlDocPtr pXmlDoc
, OString aXPath
, OString aAttribute
= OString(), OUString aExpectedValue
= OUString());
103 MethodEntry
<Test
> aMethods
[] = {
104 {"zoom.docx", &Test::testZoom
},
105 {"empty.odt", &Test::defaultTabStopNotInStyles
},
106 {"fdo38244.docx", &Test::testFdo38244
},
107 {"math-escape.docx", &Test::testMathEscape
},
108 {"fdo51034.odt", &Test::testFdo51034
},
109 {"math-accents.docx", &Test::testMathAccents
},
110 {"math-d.docx", &Test::testMathD
},
111 {"math-escaping.docx", &Test::testMathEscaping
},
112 {"math-lim.docx", &Test::testMathLim
},
113 {"math-malformed_xml.docx", &Test::testMathMalformedXml
},
114 {"math-matrix.docx", &Test::testMathMatrix
},
115 {"math-mso2k7.docx", &Test::testMathMso2k7
},
116 {"math-nary.docx", &Test::testMathNary
},
117 {"math-overbrace_underbrace.docx", &Test::testMathOverbraceUnderbrace
},
118 {"math-overstrike.docx", &Test::testMathOverstrike
},
119 {"math-placeholders.docx", &Test::testMathPlaceholders
},
120 {"math-rad.docx", &Test::testMathRad
},
121 {"math-subscripts.docx", &Test::testMathSubscripts
},
122 {"math-vertical_stacks.docx", &Test::testMathVerticalStacks
},
123 {"table-position.docx", &Test::testTablePosition
},
124 {"fdo47669.docx", &Test::testFdo47669
},
125 {"table-borders.docx", &Test::testTableBorders
},
126 {"fdo51550.odt", &Test::testFdo51550
},
127 {"n789482.docx", &Test::testN789482
},
128 // {"1-table-1-page.docx", &Test::test1Table1Page}, // doesn't work on openSUSE12.2 at least
129 {"textframes.odt", &Test::testTextFrames
},
130 {"textframe-borders.docx", &Test::testTextFrameBorders
},
131 {"textframe-gradient.docx", &Test::testTextframeGradient
},
132 {"cell-btlr.docx", &Test::testCellBtlr
},
133 {"table-style-rPr-sz.docx", &Test::testTableStylerPrSz
},
134 {"math-literal.docx", &Test::testMathLiteral
},
135 {"fdo48557.odt", &Test::testFdo48557
},
136 {"i120928.docx", &Test::testI120928
},
137 {"n822175.odt", &Test::testN822175
},
138 {"fdo58577.odt", &Test::testFdo58577
},
139 {"fdo60990.odt", &Test::testFdo60990
},
140 {"bnc834035.odt", &Test::testBnc834035
},
141 {"cp1000015.odt", &Test::testCp1000015
},
142 {"fdo70812.docx", &Test::testFdo70812
},
143 {"bnc837302.docx", &Test::testBnc837302
},
144 {"fdo65655.docx", &Test::testFdo65655
},
146 // Don't test the first import of these, for some reason those tests fail
147 const char* aBlacklist
[] = {
151 std::vector
<const char*> vBlacklist(aBlacklist
, aBlacklist
+ SAL_N_ELEMENTS(aBlacklist
));
153 for (unsigned int i
= 0; i
< SAL_N_ELEMENTS(aMethods
); ++i
)
155 MethodEntry
<Test
>& rEntry
= aMethods
[i
];
156 load("/sw/qa/extras/ooxmlexport/data/", rEntry
.pName
);
157 // If the testcase is stored in some other format, it's pointless to test.
158 if (OString(rEntry
.pName
).endsWith(".docx") && std::find(vBlacklist
.begin(), vBlacklist
.end(), rEntry
.pName
) == vBlacklist
.end())
159 (this->*rEntry
.pMethod
)();
160 reload("Office Open XML Text");
161 (this->*rEntry
.pMethod
)();
166 xmlDocPtr
Test::parseExport()
168 // Create the zip file.
169 utl::TempFile aTempFile
;
170 save("Office Open XML Text", aTempFile
);
172 // Read the XML stream we're interested in.
173 uno::Reference
<packages::zip::XZipFileAccess2
> xNameAccess
= packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory
), aTempFile
.GetURL());
174 uno::Reference
<io::XInputStream
> xInputStream(xNameAccess
->getByName("word/document.xml"), uno::UNO_QUERY
);
175 boost::shared_ptr
<SvStream
> pStream(utl::UcbStreamHelper::CreateStream(xInputStream
, sal_True
));
176 pStream
->Seek(STREAM_SEEK_TO_END
);
177 sal_Size nSize
= pStream
->Tell();
179 OStringBuffer
aDocument(nSize
);
181 for (sal_Size i
= 0; i
< nSize
; ++i
)
184 aDocument
.append(ch
);
188 return xmlParseMemory((const char*)aDocument
.getStr(), aDocument
.getLength());
191 void Test::assertXPath(xmlDocPtr pXmlDoc
, OString aXPath
, OString aAttribute
, OUString aExpectedValue
)
193 xmlXPathContextPtr pXmlXpathCtx
= xmlXPathNewContext(pXmlDoc
);
194 xmlXPathRegisterNs(pXmlXpathCtx
, BAD_CAST("w"), BAD_CAST("http://schemas.openxmlformats.org/wordprocessingml/2006/main"));
195 xmlXPathRegisterNs(pXmlXpathCtx
, BAD_CAST("v"), BAD_CAST("urn:schemas-microsoft-com:vml"));
196 xmlXPathObjectPtr pXmlXpathObj
= xmlXPathEvalExpression(BAD_CAST(aXPath
.getStr()), pXmlXpathCtx
);
197 xmlNodeSetPtr pXmlNodes
= pXmlXpathObj
->nodesetval
;
198 CPPUNIT_ASSERT_EQUAL(1, xmlXPathNodeSetGetLength(pXmlNodes
));
199 if (aAttribute
.isEmpty())
201 xmlNodePtr pXmlNode
= pXmlNodes
->nodeTab
[0];
202 OUString aValue
= OUString::createFromAscii((const char*)xmlGetProp(pXmlNode
, BAD_CAST(aAttribute
.getStr())));
203 CPPUNIT_ASSERT_EQUAL(aExpectedValue
, aValue
);
206 void Test::testZoom()
208 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
209 uno::Reference
<view::XViewSettingsSupplier
> xViewSettingsSupplier(xModel
->getCurrentController(), uno::UNO_QUERY
);
210 uno::Reference
<beans::XPropertySet
> xPropertySet(xViewSettingsSupplier
->getViewSettings());
211 sal_Int16 nValue
= 0;
212 xPropertySet
->getPropertyValue("ZoomValue") >>= nValue
;
213 CPPUNIT_ASSERT_EQUAL(sal_Int16(42), nValue
);
216 void Test::defaultTabStopNotInStyles()
218 // The default tab stop was mistakenly exported to a style.
219 // xray ThisComponent.StyleFamilies(1)(0).ParaTabStop
220 uno::Reference
< container::XNameAccess
> paragraphStyles
= getStyles( "ParagraphStyles" );
221 uno::Reference
< beans::XPropertySet
> properties( paragraphStyles
->getByName( "Standard" ), uno::UNO_QUERY
);
222 uno::Sequence
< style::TabStop
> stops
= getProperty
< uno::Sequence
< style::TabStop
> >(
223 paragraphStyles
->getByName( "Standard" ), "ParaTabStops" );
224 // There actually be be one tab stop, but it will be the default.
225 CPPUNIT_ASSERT_EQUAL( static_cast<sal_Int32
>(1), stops
.getLength());
226 CPPUNIT_ASSERT_EQUAL( style::TabAlign_DEFAULT
, stops
[ 0 ].Alignment
);
229 void Test::testFdo38244()
232 * Comments attached to a range was imported without the range, check for the fieldmark start/end positions.
234 * oParas = ThisComponent.Text.createEnumeration
235 * oPara = oParas.nextElement
236 * oRuns = oPara.createEnumeration
237 * oRun = oRuns.nextElement
238 * oRun = oRuns.nextElement 'TextFieldStart
239 * oRun = oRuns.nextElement
240 * oRun = oRuns.nextElement 'TextFieldEnd
241 * xray oRun.TextPortionType
243 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
244 uno::Reference
<container::XEnumerationAccess
> xParaEnumAccess(xTextDocument
->getText(), uno::UNO_QUERY
);
245 uno::Reference
<container::XEnumeration
> xParaEnum
= xParaEnumAccess
->createEnumeration();
246 uno::Reference
<container::XEnumerationAccess
> xRunEnumAccess(xParaEnum
->nextElement(), uno::UNO_QUERY
);
247 uno::Reference
<container::XEnumeration
> xRunEnum
= xRunEnumAccess
->createEnumeration();
248 xRunEnum
->nextElement();
249 uno::Reference
<beans::XPropertySet
> xPropertySet(xRunEnum
->nextElement(), uno::UNO_QUERY
);
250 CPPUNIT_ASSERT_EQUAL(OUString("TextFieldStart"), getProperty
<OUString
>(xPropertySet
, "TextPortionType"));
251 xRunEnum
->nextElement();
252 xPropertySet
.set(xRunEnum
->nextElement(), uno::UNO_QUERY
);
253 CPPUNIT_ASSERT_EQUAL(OUString("TextFieldEnd"), getProperty
<OUString
>(xPropertySet
, "TextPortionType"));
256 * Initials were not imported.
258 * oFields = ThisComponent.TextFields.createEnumeration
259 * oField = oFields.nextElement
260 * xray oField.Initials
262 uno::Reference
<text::XTextFieldsSupplier
> xTextFieldsSupplier(mxComponent
, uno::UNO_QUERY
);
263 uno::Reference
<container::XEnumerationAccess
> xFieldsAccess(xTextFieldsSupplier
->getTextFields());
264 uno::Reference
<container::XEnumeration
> xFields(xFieldsAccess
->createEnumeration());
265 xPropertySet
.set(xFields
->nextElement(), uno::UNO_QUERY
);
266 CPPUNIT_ASSERT_EQUAL(OUString("M"), getProperty
<OUString
>(xPropertySet
, "Initials"));
269 * There was a fake empty paragraph at the end of the comment text.
271 * oFields = ThisComponent.TextFields.createEnumeration
272 * oField = oFields.nextElement
273 * oParas = oField.TextRange.createEnumeration
274 * oPara = oParas.nextElement
275 * oPara = oParas.nextElement
278 xParaEnumAccess
.set(getProperty
< uno::Reference
<container::XEnumerationAccess
> >(xPropertySet
, "TextRange"), uno::UNO_QUERY
);
279 xParaEnum
= xParaEnumAccess
->createEnumeration();
280 xParaEnum
->nextElement();
281 bool bCaught
= false;
284 xParaEnum
->nextElement();
286 catch (container::NoSuchElementException
&)
290 CPPUNIT_ASSERT_EQUAL(true, bCaught
);
293 void Test::testMathEscape()
295 CPPUNIT_ASSERT_EQUAL(OUString("\\{ left [ right ] left ( right ) \\}"), getFormula(getRun(getParagraph(1), 1)));
298 void Test::testFdo51034()
300 // The problem was that the 'l' param of the HYPERLINK field was parsed with = "#", not += "#".
301 CPPUNIT_ASSERT_EQUAL(OUString("http://Www.google.com/#a"), getProperty
<OUString
>(getRun(getParagraph(1), 1), "HyperLinkURL"));
304 // Construct the expected formula from UTF8, as there may be such characters.
305 // Remove all spaces, as LO export/import may change that.
306 // Replace symbol - (i.e. U+2212) with ASCII - , LO does this change and it shouldn't matter.
307 #define CHECK_FORMULA( expected, actual ) \
308 CPPUNIT_ASSERT_EQUAL( \
309 OUString( expected, strlen( expected ), RTL_TEXTENCODING_UTF8 ) \
310 .replaceAll( " ", "" ).replaceAll( OUString( "−", strlen( "−" ), RTL_TEXTENCODING_UTF8 ), "-" ), \
311 OUString( actual ).replaceAll( " ", "" ).replaceAll( OUString( "−", strlen( "−" ), RTL_TEXTENCODING_UTF8 ), "-" ))
313 void Test::testMathAccents()
316 "acute {a} grave {a} check {a} breve {a} circle {a} widevec {a} widetilde {a}"
317 " widehat {a} dot {a} widevec {a} widevec {a} widetilde {a} underline {a}",
318 getFormula( getRun( getParagraph( 1 ), 1 )));
321 void Test::testMathD()
323 CHECK_FORMULA( "left (x mline y mline z right )", getFormula( getRun( getParagraph( 1 ), 1 )));
324 CHECK_FORMULA( "left (1 right )", getFormula( getRun( getParagraph( 1 ), 2 )));
325 CHECK_FORMULA( "left [2 right ]", getFormula( getRun( getParagraph( 1 ), 3 )));
326 CHECK_FORMULA( "left ldbracket 3 right rdbracket", getFormula( getRun( getParagraph( 1 ), 4 )));
327 CHECK_FORMULA( "left lline 4 right rline", getFormula( getRun( getParagraph( 1 ), 5 )));
328 CHECK_FORMULA( "left ldline 5 right rdline", getFormula( getRun( getParagraph( 1 ), 6 )));
329 CHECK_FORMULA( "left langle 6 right rangle", getFormula( getRun( getParagraph( 1 ), 7 )));
330 CHECK_FORMULA( "left langle a mline b right rangle", getFormula( getRun( getParagraph( 1 ), 8 )));
331 CHECK_FORMULA( "left ({x} over {y} right )", getFormula( getRun( getParagraph( 1 ), 9 )));
334 void Test::testMathEscaping()
336 CHECK_FORMULA( "− ∞ < x < ∞", getFormula( getRun( getParagraph( 1 ), 1 )));
339 void Test::testMathLim()
341 CHECK_FORMULA( "lim from {x → 1} {x}", getFormula( getRun( getParagraph( 1 ), 1 )));
344 void Test::testMathMalformedXml()
346 CPPUNIT_ASSERT_EQUAL( 0, getLength());
349 void Test::testMathMatrix()
351 CHECK_FORMULA( "left [matrix {1 # 2 ## 3 # 4} right ]", getFormula( getRun( getParagraph( 1 ), 1 )));
354 void Test::testMathMso2k7()
356 CHECK_FORMULA( "A = π {r} ^ {2}", getFormula( getRun( getParagraph( 1 ), 1 )));
357 // TODO check the stack/binom difference
358 // CHECK_FORMULA( "{left (x+a right )} ^ {n} = sum from {k=0} to {n} {left (binom {n} {k} right ) {x} ^ {k} {a} ^ {n-k}}",
359 CHECK_FORMULA( "{left (x+a right )} ^ {n} = sum from {k=0} to {n} {left (stack {n # k} right ) {x} ^ {k} {a} ^ {n-k}}",
360 getFormula( getRun( getParagraph( 2 ), 1 )));
361 CHECK_FORMULA( "{left (1+x right )} ^ {n} =1+ {nx} over {1!} + {n left (n-1 right ) {x} ^ {2}} over {2!} +…",
362 getFormula( getRun( getParagraph( 3 ), 1 )));
363 // TODO check (cos/sin miss {})
364 // CHECK_FORMULA( "f left (x right ) = {a} rsub {0} + sum from {n=1} to {∞} {left ({a} rsub {n} cos {{nπx} over {L}} + {b} rsub {n} sin {{nπx} over {L}} right )}",
365 CHECK_FORMULA( "f left (x right ) = {a} rsub {0} + sum from {n=1} to {∞} {left ({a} rsub {n} cos {nπx} over {L} + {b} rsub {n} sin {nπx} over {L} right )}",
366 getFormula( getRun( getParagraph( 4 ), 1 )));
367 CHECK_FORMULA( "{a} ^ {2} + {b} ^ {2} = {c} ^ {2}", getFormula( getRun( getParagraph( 5 ), 1 )));
368 CHECK_FORMULA( "x = {- b ± sqrt {{b} ^ {2} -4 ac}} over {2 a}",
369 getFormula( getRun( getParagraph( 6 ), 1 )));
371 "{e} ^ {x} =1+ {x} over {1!} + {{x} ^ {2}} over {2!} + {{x} ^ {3}} over {3!} +…, -∞<x<∞",
372 getFormula( getRun( getParagraph( 7 ), 1 )));
374 // "sin {α} ± sin {β} =2 sin {{1} over {2} left (α±β right )} cos {{1} over {2} left (α∓β right )}",
375 // TODO check (cos/in miss {})
376 "sin α ± sin β =2 sin {1} over {2} left (α±β right ) cos {1} over {2} left (α∓β right )",
377 getFormula( getRun( getParagraph( 8 ), 1 )));
379 // "cos {α} + cos {β} =2 cos {{1} over {2} left (α+β right )} cos {{1} over {2} left (α-β right )}",
380 // TODO check (cos/sin miss {})
381 "cos α + cos β =2 cos {1} over {2} left (α+β right ) cos {1} over {2} left (α-β right )",
382 getFormula( getRun( getParagraph( 9 ), 1 )));
385 void Test::testMathNary()
387 CHECK_FORMULA( "lllint from {1} to {2} {x + 1}", getFormula( getRun( getParagraph( 1 ), 1 )));
388 CHECK_FORMULA( "prod from {a} {b}", getFormula( getRun( getParagraph( 1 ), 2 )));
389 CHECK_FORMULA( "sum to {2} {x}", getFormula( getRun( getParagraph( 1 ), 3 )));
392 void Test::testMathOverbraceUnderbrace()
394 CHECK_FORMULA( "{abcd} overbrace {4}", getFormula( getRun( getParagraph( 1 ), 1 )));
395 CHECK_FORMULA( "{xyz} underbrace {3}", getFormula( getRun( getParagraph( 2 ), 1 )));
398 void Test::testMathOverstrike()
400 CHECK_FORMULA( "overstrike {abc}", getFormula( getRun( getParagraph( 1 ), 1 )));
403 void Test::testMathPlaceholders()
405 CHECK_FORMULA( "sum from <?> to <?> <?>", getFormula( getRun( getParagraph( 1 ), 1 )));
408 void Test::testMathRad()
410 CHECK_FORMULA( "sqrt {4}", getFormula( getRun( getParagraph( 1 ), 1 )));
411 CHECK_FORMULA( "nroot {3} {x + 1}", getFormula( getRun( getParagraph( 1 ), 2 )));
414 void Test::testMathSubscripts()
416 CHECK_FORMULA( "{x} ^ {y} + {e} ^ {x}", getFormula( getRun( getParagraph( 1 ), 1 )));
417 CHECK_FORMULA( "{x} ^ {b}", getFormula( getRun( getParagraph( 1 ), 2 )));
418 CHECK_FORMULA( "{x} rsub {b}", getFormula( getRun( getParagraph( 1 ), 3 )));
419 CHECK_FORMULA( "{a} rsub {c} rsup {b}", getFormula( getRun( getParagraph( 1 ), 4 )));
420 CHECK_FORMULA( "{x} lsub {2} lsup {1}", getFormula( getRun( getParagraph( 1 ), 5 )));
421 CHECK_FORMULA( "{{x csup {6} csub {3}} lsub {4} lsup {5}} rsub {2} rsup {1}",
422 getFormula( getRun( getParagraph( 1 ), 6 )));
425 void Test::testMathVerticalStacks()
427 CHECK_FORMULA( "{a} over {b}", getFormula( getRun( getParagraph( 1 ), 1 )));
428 CHECK_FORMULA( "{a} / {b}", getFormula( getRun( getParagraph( 2 ), 1 )));
430 // CHECK_FORMULA( "binom {a} {b}", getFormula( getRun( getParagraph( 3 ), 1 )));
431 // CHECK_FORMULA( "binom {a} {binom {b} {c}}", getFormula( getRun( getParagraph( 4 ), 1 )));
434 void Test::testTablePosition()
436 sal_Int32 xCoordsFromOffice
[] = { 2500, -1000, 0, 0 };
437 sal_Int32 cellLeftMarginFromOffice
[] = { 250, 100, 0, 0 };
439 uno::Reference
<text::XTextTablesSupplier
> xTablesSupplier(mxComponent
, uno::UNO_QUERY
);
440 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
441 uno::Reference
<container::XIndexAccess
> xTables(xTablesSupplier
->getTextTables( ), uno::UNO_QUERY
);
443 for (int i
=0; i
<4; i
++) {
444 uno::Reference
<text::XTextTable
> xTable1 (xTables
->getByIndex(i
), uno::UNO_QUERY
);
446 uno::Reference
<view::XSelectionSupplier
> xCtrl(xModel
->getCurrentController(), uno::UNO_QUERY
);
447 xCtrl
->select(uno::makeAny(xTable1
));
448 uno::Reference
<text::XTextViewCursorSupplier
> xTextViewCursorSupplier(xCtrl
, uno::UNO_QUERY
);
449 uno::Reference
<text::XTextViewCursor
> xCursor(xTextViewCursorSupplier
->getViewCursor(), uno::UNO_QUERY
);
450 awt::Point pos
= xCursor
->getPosition();
451 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Incorrect X coord computed from docx",
452 xCoordsFromOffice
[i
], pos
.X
, 1);
454 // Verify left margin of 1st cell :
455 // * Office left margins are measured relative to the right of the border
456 // * LO left spacing is measured from the center of the border
457 uno::Reference
<table::XCell
> xCell
= xTable1
->getCellByName("A1");
458 uno::Reference
< beans::XPropertySet
> xPropSet(xCell
, uno::UNO_QUERY_THROW
);
459 sal_Int32 aLeftMargin
= -1;
460 xPropSet
->getPropertyValue("LeftBorderDistance") >>= aLeftMargin
;
461 uno::Any aLeftBorder
= xPropSet
->getPropertyValue("LeftBorder");
462 table::BorderLine2 aLeftBorderLine
;
463 aLeftBorder
>>= aLeftBorderLine
;
464 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Incorrect left spacing computed from docx cell margin",
465 cellLeftMarginFromOffice
[i
], aLeftMargin
- 0.5 * aLeftBorderLine
.LineWidth
, 1);
469 void Test::testFdo47669()
472 * Problem: we created imbalance </w:hyperlink> which shouldn't be there,
473 * resulting in loading error: missing last character of hyperlink text
474 * and content after it wasn't loaded.
476 getParagraph(1, "This is a hyperlink with anchor. Also, this sentence should be seen.");
477 getRun(getParagraph(1), 2, "hyperlink with anchor");
478 CPPUNIT_ASSERT_EQUAL(OUString("http://www.google.com/#a"), getProperty
<OUString
>(getRun(getParagraph(1), 2), "HyperLinkURL"));
481 struct SingleLineBorders
{
482 sal_Int16 top
, bottom
, left
, right
;
483 SingleLineBorders(int t
=0, int b
=0, int l
=0, int r
=0)
484 : top(t
), bottom(b
), left(l
), right(r
) {}
485 sal_Int16
getBorder(int i
) const
489 case 1: return bottom
;
491 case 3: return right
;
492 default: assert(false); return 0;
496 void Test::testTableBorders() {
497 uno::Reference
<text::XTextTablesSupplier
> xTablesSupplier(mxComponent
, uno::UNO_QUERY
);
498 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
499 uno::Reference
<container::XIndexAccess
> xTables(xTablesSupplier
->getTextTables( ), uno::UNO_QUERY
);
500 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables
->getCount());
501 uno::Reference
<text::XTextTable
> xTextTable (xTables
->getByIndex(0), uno::UNO_QUERY
);
503 std::map
<OUString
, SingleLineBorders
> cellBorders
;
504 cellBorders
[OUString("A1")] = SingleLineBorders(106, 106, 106, 106);
505 cellBorders
[OUString("B1")] = SingleLineBorders(106, 0, 106, 35);
506 cellBorders
[OUString("C1")] = SingleLineBorders(106, 106, 35, 106);
507 cellBorders
[OUString("A2")] = SingleLineBorders(106, 35, 106, 0);
508 cellBorders
[OUString("B2")] = SingleLineBorders(0, 0, 0, 0);
509 cellBorders
[OUString("C2")] = SingleLineBorders(106, 106, 0, 106);
510 cellBorders
[OUString("A3")] = SingleLineBorders(35, 35, 106, 106);
511 cellBorders
[OUString("B3")] = SingleLineBorders(0, 106, 106, 106);
512 cellBorders
[OUString("C3")] = SingleLineBorders(106, 106, 106, 106);
513 cellBorders
[OUString("A4")] = SingleLineBorders(35, 106, 106, 35);
514 cellBorders
[OUString("B4")] = SingleLineBorders(106, 106, 35, 106);
515 cellBorders
[OUString("C4")] = SingleLineBorders(106, 106, 106, 106);
517 const OUString borderNames
[] = {
518 OUString("TopBorder"),
519 OUString("BottomBorder"),
520 OUString("LeftBorder"),
521 OUString("RightBorder"),
524 uno::Sequence
<OUString
> const cells
= xTextTable
->getCellNames();
525 sal_Int32 nLength
= cells
.getLength();
526 CPPUNIT_ASSERT_EQUAL((sal_Int32
)cellBorders
.size(), nLength
);
528 for (sal_Int32 i
= 0; i
< nLength
; ++i
)
530 uno::Reference
<table::XCell
> xCell
= xTextTable
->getCellByName(cells
[i
]);
531 uno::Reference
< beans::XPropertySet
> xPropSet(xCell
, uno::UNO_QUERY_THROW
);
532 const SingleLineBorders
& borders
= cellBorders
[cells
[i
]];
534 for (sal_Int32 j
= 0; j
< 4; ++j
)
536 uno::Any aBorder
= xPropSet
->getPropertyValue(borderNames
[j
]);
537 table::BorderLine aBorderLine
;
538 if (aBorder
>>= aBorderLine
)
540 std::stringstream message
;
541 message
<< cells
[i
] << "'s " << borderNames
[j
] << " is incorrect";
542 CPPUNIT_ASSERT_EQUAL_MESSAGE(message
.str(),
543 borders
.getBorder(j
), aBorderLine
.OuterLineWidth
);
549 void Test::testFdo51550()
551 // The problem was that we lacked the fallback to export the replacement graphic for OLE objects.
552 uno::Reference
<drawing::XDrawPageSupplier
> xDrawPageSupplier(mxComponent
, uno::UNO_QUERY
);
553 uno::Reference
<container::XIndexAccess
> xDraws(xDrawPageSupplier
->getDrawPage(), uno::UNO_QUERY
);
554 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xDraws
->getCount());
557 void Test::testN789482()
559 // The problem was that w:del was exported before w:hyperlink, resulting in an invalid XML.
560 uno::Reference
<text::XTextRange
> xParagraph
= getParagraph(1);
561 getRun(xParagraph
, 1, "Before. ");
563 CPPUNIT_ASSERT_EQUAL(OUString("Delete"), getProperty
<OUString
>(getRun(xParagraph
, 2), "RedlineType"));
564 CPPUNIT_ASSERT_EQUAL(sal_True
, getProperty
<sal_Bool
>(getRun(xParagraph
, 2), "IsStart"));
566 getRun(xParagraph
, 3, "www.test.com");
567 CPPUNIT_ASSERT_EQUAL(OUString("http://www.test.com/"), getProperty
<OUString
>(getRun(xParagraph
, 3), "HyperLinkURL"));
569 CPPUNIT_ASSERT_EQUAL(OUString("Delete"), getProperty
<OUString
>(getRun(xParagraph
, 4), "RedlineType"));
570 CPPUNIT_ASSERT_EQUAL(sal_False
, getProperty
<sal_Bool
>(getRun(xParagraph
, 4), "IsStart"));
572 getRun(xParagraph
, 5, " After.");
575 void Test::test1Table1Page()
577 // 2 problem for this document after export:
578 // - invalid sectPr inserted at the beginning of the page
579 // - font of empty cell is not preserved, leading to change in rows height
580 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
581 uno::Reference
<text::XTextViewCursorSupplier
> xTextViewCursorSupplier(xModel
->getCurrentController(), uno::UNO_QUERY
);
582 uno::Reference
<text::XPageCursor
> xCursor(xTextViewCursorSupplier
->getViewCursor(), uno::UNO_QUERY
);
583 xCursor
->jumpToLastPage();
584 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), xCursor
->getPage());
587 void Test::testTextFrames()
589 // The frames were simply missing, so let's check if all 3 frames were imported back.
590 uno::Reference
<text::XTextFramesSupplier
> xTextFramesSupplier(mxComponent
, uno::UNO_QUERY
);
591 uno::Reference
<container::XIndexAccess
> xIndexAccess(xTextFramesSupplier
->getTextFrames(), uno::UNO_QUERY
);
592 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xIndexAccess
->getCount());
595 void Test::testTextFrameBorders()
597 uno::Reference
<text::XTextFramesSupplier
> xTextFramesSupplier(mxComponent
, uno::UNO_QUERY
);
598 uno::Reference
<container::XIndexAccess
> xIndexAccess(xTextFramesSupplier
->getTextFrames(), uno::UNO_QUERY
);
599 uno::Reference
<beans::XPropertySet
> xFrame(xIndexAccess
->getByIndex(0), uno::UNO_QUERY
);
600 CPPUNIT_ASSERT_EQUAL(sal_Int32(0xD99594), getProperty
<sal_Int32
>(xFrame
, "BackColor"));
602 table::BorderLine2 aBorder
= getProperty
<table::BorderLine2
>(xFrame
, "TopBorder");
603 CPPUNIT_ASSERT_EQUAL(sal_Int32(0xC0504D), aBorder
.Color
);
604 CPPUNIT_ASSERT_EQUAL(sal_uInt32(35), aBorder
.LineWidth
);
606 table::ShadowFormat aShadowFormat
= getProperty
<table::ShadowFormat
>(xFrame
, "ShadowFormat");
607 CPPUNIT_ASSERT_EQUAL(table::ShadowLocation_BOTTOM_RIGHT
, aShadowFormat
.Location
);
608 CPPUNIT_ASSERT_EQUAL(sal_Int16(48), aShadowFormat
.ShadowWidth
);
609 CPPUNIT_ASSERT_EQUAL(sal_Int32(0x622423), aShadowFormat
.Color
);
612 void Test::testTextframeGradient()
614 uno::Reference
<text::XTextFramesSupplier
> xTextFramesSupplier(mxComponent
, uno::UNO_QUERY
);
615 uno::Reference
<container::XIndexAccess
> xIndexAccess(xTextFramesSupplier
->getTextFrames(), uno::UNO_QUERY
);
616 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xIndexAccess
->getCount());
618 uno::Reference
<beans::XPropertySet
> xFrame(xIndexAccess
->getByIndex(0), uno::UNO_QUERY
);
619 CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_GRADIENT
, getProperty
<drawing::FillStyle
>(xFrame
, "FillStyle"));
620 awt::Gradient aGradient
= getProperty
<awt::Gradient
>(xFrame
, "FillGradient");
621 CPPUNIT_ASSERT_EQUAL(sal_Int32(0xC0504D), aGradient
.StartColor
);
622 CPPUNIT_ASSERT_EQUAL(sal_Int32(0xD99594), aGradient
.EndColor
);
623 CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_AXIAL
, aGradient
.Style
);
625 xFrame
.set(xIndexAccess
->getByIndex(1), uno::UNO_QUERY
);
626 CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_GRADIENT
, getProperty
<drawing::FillStyle
>(xFrame
, "FillStyle"));
627 aGradient
= getProperty
<awt::Gradient
>(xFrame
, "FillGradient");
628 CPPUNIT_ASSERT_EQUAL(sal_Int32(0x000000), aGradient
.StartColor
);
629 CPPUNIT_ASSERT_EQUAL(sal_Int32(0x666666), aGradient
.EndColor
);
630 CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_AXIAL
, aGradient
.Style
);
633 void Test::testCellBtlr()
636 * The problem was that the exporter didn't mirror the workaround of the
637 * importer, regarding the btLr text direction: the <w:textDirection
638 * w:val="btLr"/> token was completely missing in the output.
640 * Given that this doesn't affect the result in the importer, we test the
641 * resulting file directly, by opening the zip file, parsing an xml stream,
642 * and asserting an XPath expression. This can be extracted to a helper
643 * method, once it's clear what is common in such tests.
646 // Create the zip file.
647 utl::TempFile aTempFile
;
648 save("Office Open XML Text", aTempFile
);
650 // Read the XML stream we're interested in.
651 uno::Sequence
<uno::Any
> aArgs(1);
652 aArgs
[0] <<= OUString(aTempFile
.GetURL());
653 uno::Reference
<container::XNameAccess
> xNameAccess(m_xSFactory
->createInstanceWithArguments("com.sun.star.packages.zip.ZipFileAccess", aArgs
), uno::UNO_QUERY
);
654 uno::Reference
<io::XInputStream
> xInputStream(xNameAccess
->getByName("word/document.xml"), uno::UNO_QUERY
);
655 boost::shared_ptr
<SvStream
> pStream(utl::UcbStreamHelper::CreateStream(xInputStream
, sal_True
));
656 pStream
->Seek(STREAM_SEEK_TO_END
);
657 sal_Size nSize
= pStream
->Tell();
659 OStringBuffer
aDocument(nSize
);
661 for (sal_Size i
= 0; i
< nSize
; ++i
)
664 aDocument
.append(ch
);
668 xmlDocPtr pXmlDoc
= xmlParseMemory((const char*)aDocument
.getStr(), aDocument
.getLength());
670 // Assert the XPath expression.
671 xmlXPathContextPtr pXmlXpathCtx
= xmlXPathNewContext(pXmlDoc
);
672 xmlXPathRegisterNs(pXmlXpathCtx
, BAD_CAST("w"), BAD_CAST("http://schemas.openxmlformats.org/wordprocessingml/2006/main"));
673 OString aXPath
= "/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:textDirection";
674 xmlXPathObjectPtr pXmlXpathObj
= xmlXPathEvalExpression(BAD_CAST(aXPath
.getStr()), pXmlXpathCtx
);
675 xmlNodeSetPtr pXmlNodes
= pXmlXpathObj
->nodesetval
;
676 CPPUNIT_ASSERT_EQUAL(1, xmlXPathNodeSetGetLength(pXmlNodes
));
677 xmlNodePtr pXmlNode
= pXmlNodes
->nodeTab
[0];
678 OString aAttribute
= "val";
679 OUString aValue
= OUString::createFromAscii((const char*)xmlGetProp(pXmlNode
, BAD_CAST(aAttribute
.getStr())));
680 CPPUNIT_ASSERT_EQUAL(OUString("btLr"), aValue
);
683 void Test::testTableStylerPrSz()
685 // Verify that font size inside the table is 20pt, despite the sz attribute in the table size.
686 // Also check that other rPr attribute are used: italic, bold, underline
687 // Office has the same behavior
688 uno::Reference
<text::XTextTablesSupplier
> xTextTablesSupplier(mxComponent
, uno::UNO_QUERY
);
689 uno::Reference
<container::XIndexAccess
> xTables(xTextTablesSupplier
->getTextTables(), uno::UNO_QUERY
);
690 uno::Reference
<text::XTextTable
> xTable(xTables
->getByIndex(0), uno::UNO_QUERY
);
691 uno::Reference
<text::XTextRange
> xCell(xTable
->getCellByName("A1"), uno::UNO_QUERY
);
692 uno::Reference
<container::XEnumerationAccess
> xParaEnumAccess(xCell
->getText(), uno::UNO_QUERY
);
693 uno::Reference
<container::XEnumeration
> xParaEnum
= xParaEnumAccess
->createEnumeration();
694 uno::Reference
<text::XTextRange
> xPara(xParaEnum
->nextElement(), uno::UNO_QUERY
);
696 CPPUNIT_ASSERT_EQUAL(20.f
, getProperty
<float>(getRun(xPara
, 1), "CharHeight"));
697 // CPPUNIT_ASSERT_EQUAL(awt::FontUnderline::SINGLE, getProperty<short>(getRun(xPara, 1), "CharUnderline"));
698 // CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty<float>(getRun(xPara, 1), "CharWeight"));
699 // CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, getProperty<awt::FontSlant>(getRun(xPara, 1), "CharPosture"));
702 void Test::testMathLiteral()
704 CHECK_FORMULA( "iiint from {V} to <?> {\"div\" \"F\"} dV= llint from {S} to <?> {\"F\" ∙ \"n \" dS}",
705 getFormula( getRun( getParagraph( 1 ), 1 )));
708 void Test::testFdo48557()
710 // Inner margins of the textframe wasn't exported.
711 uno::Reference
<text::XTextFramesSupplier
> xTextFramesSupplier(mxComponent
, uno::UNO_QUERY
);
712 uno::Reference
<container::XIndexAccess
> xIndexAccess(xTextFramesSupplier
->getTextFrames(), uno::UNO_QUERY
);
713 uno::Reference
<beans::XPropertySet
> xFrame(xIndexAccess
->getByIndex(0), uno::UNO_QUERY
);
714 CPPUNIT_ASSERT_EQUAL(sal_Int32(150), getProperty
<sal_Int32
>(xFrame
, "LeftBorderDistance"));
715 CPPUNIT_ASSERT_EQUAL(sal_Int32(150), getProperty
<sal_Int32
>(xFrame
, "RightBorderDistance"));
716 CPPUNIT_ASSERT_EQUAL(sal_Int32(150), getProperty
<sal_Int32
>(xFrame
, "TopBorderDistance"));
717 CPPUNIT_ASSERT_EQUAL(sal_Int32(150), getProperty
<sal_Int32
>(xFrame
, "BottomBorderDistance"));
720 void Test::testI120928()
722 // w:numPicBullet was ignored, leading to missing graphic bullet in numbering.
723 uno::Reference
<beans::XPropertySet
> xPropertySet(getStyles("NumberingStyles")->getByName("WWNum1"), uno::UNO_QUERY
);
724 uno::Reference
<container::XIndexAccess
> xLevels(xPropertySet
->getPropertyValue("NumberingRules"), uno::UNO_QUERY
);
725 uno::Sequence
<beans::PropertyValue
> aProps
;
726 xLevels
->getByIndex(0) >>= aProps
; // 1st level
728 bool bIsGraphic
= false;
729 for (int i
= 0; i
< aProps
.getLength(); ++i
)
731 const beans::PropertyValue
& rProp
= aProps
[i
];
733 if (rProp
.Name
== "NumberingType")
734 CPPUNIT_ASSERT_EQUAL(style::NumberingType::BITMAP
, rProp
.Value
.get
<sal_Int16
>());
735 else if (rProp
.Name
== "GraphicURL")
738 CPPUNIT_ASSERT_EQUAL(true, bIsGraphic
);
741 void Test::testN822175()
743 uno::Reference
<drawing::XDrawPageSupplier
> xDrawPageSupplier(mxComponent
, uno::UNO_QUERY
);
744 uno::Reference
<container::XIndexAccess
> xDraws(xDrawPageSupplier
->getDrawPage(), uno::UNO_QUERY
);
745 uno::Reference
<beans::XPropertySet
> xFrame(xDraws
->getByIndex(0), uno::UNO_QUERY
);
746 // Was text::WrapTextMode_THROUGH, due to missing Surround handling in the exporter.
747 CPPUNIT_ASSERT_EQUAL(text::WrapTextMode_PARALLEL
, getProperty
<text::WrapTextMode
>(xFrame
, "Surround"));
750 void Test::testFdo58577()
752 // The second frame was simply missing, so let's check if both frames were imported back.
753 uno::Reference
<text::XTextFramesSupplier
> xTextFramesSupplier(mxComponent
, uno::UNO_QUERY
);
754 uno::Reference
<container::XIndexAccess
> xIndexAccess(xTextFramesSupplier
->getTextFrames(), uno::UNO_QUERY
);
755 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xIndexAccess
->getCount());
758 void Test::testFdo60990()
760 // The shape had no background, no paragraph adjust and no font color.
761 uno::Reference
<drawing::XDrawPageSupplier
> xDrawPageSupplier(mxComponent
, uno::UNO_QUERY
);
762 uno::Reference
<container::XIndexAccess
> xDraws(xDrawPageSupplier
->getDrawPage(), uno::UNO_QUERY
);
763 uno::Reference
<beans::XPropertySet
> xShape(xDraws
->getByIndex(0), uno::UNO_QUERY
);
764 CPPUNIT_ASSERT_EQUAL(sal_Int32(0x00CFE7F5), getProperty
<sal_Int32
>(xShape
, "BackColor"));
765 uno::Reference
<text::XText
> xText
= uno::Reference
<text::XTextRange
>(xShape
, uno::UNO_QUERY
)->getText();
766 uno::Reference
<text::XTextRange
> xParagraph
= getParagraphOfText(1, xText
);
767 CPPUNIT_ASSERT_EQUAL(style::ParagraphAdjust_CENTER
, static_cast<style::ParagraphAdjust
>(getProperty
<sal_Int16
>(xParagraph
, "ParaAdjust")));
768 CPPUNIT_ASSERT_EQUAL(sal_Int32(0x00FF00), getProperty
<sal_Int32
>(getRun(xParagraph
, 1), "CharColor"));
771 void Test::testBnc834035()
773 // This is tricky, when saving manually, there are 2 hyperlinks, here only
774 // one, no idea why. That one still shows that we're not using bookmarks, though.
776 // Illustration index had wrong hyperlinks: anchor was using Writer's
777 // <seqname>!<index>|sequence syntax, not a bookmark name.
778 xmlDocPtr pXmlDoc
= parseExport();
779 // This was Figure!1|sequence.
780 assertXPath(pXmlDoc
, "/w:document/w:body/w:p/w:hyperlink", "anchor", "_Toc363553908");
783 void Test::testCp1000015()
785 // Redline and hyperlink end got exported in an incorrect order.
786 getParagraph(1, "Hello.");
787 getParagraph(2, "http://www.google.com/");
790 void Test::testFdo70812()
792 // Import just crashed.
793 getParagraph(1, "Sample pages document.");
796 void Test::testBnc837302()
798 // The problem was that text with empty author was not inserted as a redline
799 uno::Reference
<text::XTextRange
> xParagraph
= getParagraph(1);
801 // previously 'AAA' was not an own run
802 getRun(xParagraph
, 3, "AAA");
803 // interestingly the 'Insert' is set on the _previous_ run
804 CPPUNIT_ASSERT_EQUAL(OUString("Insert"), getProperty
<OUString
>(getRun(xParagraph
, 2), "RedlineType"));
806 // make sure we don't introduce a redlined delete in the 2nd paragraph
807 xParagraph
= getParagraph(2);
811 // throws when not present
812 aProperty
= getProperty
<OUString
>(getRun(xParagraph
, 1), "RedlineType");
814 catch (const beans::UnknownPropertyException
&) {}
815 CPPUNIT_ASSERT_EQUAL(OUString(), aProperty
);
818 void Test::testFdo65655()
820 // The problem was that the DOCX had a non-blank odd footer and a blank even footer
821 // The 'Different Odd & Even Pages' was turned on
822 // However - LO assumed that because the 'even' footer is blank - it should ignore the 'Different Odd & Even Pages' flag
823 // So it did not import it and did not export it
824 uno::Reference
<beans::XPropertySet
> xPropertySet(getStyles("PageStyles")->getByName(DEFAULT_STYLE
), uno::UNO_QUERY
);
825 sal_Bool bValue
= false;
826 xPropertySet
->getPropertyValue("HeaderIsShared") >>= bValue
;
827 CPPUNIT_ASSERT_EQUAL(false, bool(bValue
));
828 xPropertySet
->getPropertyValue("FooterIsShared") >>= bValue
;
829 CPPUNIT_ASSERT_EQUAL(false, bool(bValue
));
832 CPPUNIT_TEST_SUITE_REGISTRATION(Test
);
834 CPPUNIT_PLUGIN_IMPLEMENT();
836 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */