Line data Source code
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 : #ifndef INCLUDED_SW_QA_EXTRAS_INC_SWMODELTESTBASE_HXX
11 : #define INCLUDED_SW_QA_EXTRAS_INC_SWMODELTESTBASE_HXX
12 :
13 : #include <com/sun/star/container/XContentEnumerationAccess.hpp>
14 : #include <com/sun/star/frame/Desktop.hpp>
15 : #include <com/sun/star/packages/zip/ZipFileAccess.hpp>
16 : #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
17 : #include <com/sun/star/style/XAutoStylesSupplier.hpp>
18 : #include <com/sun/star/style/XAutoStyleFamily.hpp>
19 : #include <com/sun/star/text/XPageCursor.hpp>
20 : #include <com/sun/star/text/XTextDocument.hpp>
21 : #include <com/sun/star/text/XTextRange.hpp>
22 : #include <com/sun/star/text/XTextTable.hpp>
23 : #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
24 : #include <com/sun/star/table/XCell.hpp>
25 : #include <com/sun/star/table/BorderLine2.hpp>
26 : #include <com/sun/star/task/XJob.hpp>
27 : #include <com/sun/star/sdb/CommandType.hpp>
28 : #include <com/sun/star/sdb/DatabaseContext.hpp>
29 : #include <com/sun/star/sdb/XDocumentDataSource.hpp>
30 :
31 : #include <test/bootstrapfixture.hxx>
32 : #include <test/xmltesttools.hxx>
33 : #include <unotest/macros_test.hxx>
34 : #include <unotools/ucbstreamhelper.hxx>
35 : #include <rtl/strbuf.hxx>
36 : #include <rtl/ustrbuf.hxx>
37 : #include <rtl/byteseq.hxx>
38 : #include <comphelper/processfactory.hxx>
39 : #include <unotools/tempfile.hxx>
40 : #include <unotools/localfilehelper.hxx>
41 : #include <unotools/mediadescriptor.hxx>
42 : #include <dbmgr.hxx>
43 : #include <unoprnms.hxx>
44 :
45 : #include <unotxdoc.hxx>
46 : #include <docsh.hxx>
47 : #include <doc.hxx>
48 : #include <IDocumentLayoutAccess.hxx>
49 : #include <rootfrm.hxx>
50 :
51 : using namespace css;
52 :
53 : #define DEFAULT_STYLE "Default Style"
54 :
55 : /**
56 : * Macro to declare a new test (with full round-trip. To test
57 : * import only use the DECLARE_SW_IMPORT_TEST macro instead).
58 : * In order to add a new test, one only needs to use this macro
59 : * and then specify the test content, like this:
60 : *
61 : * DECLARE_SW_ROUNDTRIP_TEST(MyTest, "myfilename.docx", Test)
62 : * {
63 : * CPPUNIT_ASSERT_EQUAL(blabla);
64 : * }
65 : *
66 : */
67 : #define DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, BaseClass) \
68 : class TestName : public BaseClass { \
69 : protected:\
70 : virtual OUString getTestName() SAL_OVERRIDE { return OUString(#TestName); } \
71 : public:\
72 : CPPUNIT_TEST_SUITE(TestName); \
73 : CPPUNIT_TEST(Import); \
74 : CPPUNIT_TEST(Import_Export_Import); \
75 : CPPUNIT_TEST_SUITE_END(); \
76 : \
77 : void Import() { \
78 : executeImportTest(filename);\
79 : }\
80 : void Import_Export_Import() {\
81 : executeImportExportImportTest(filename);\
82 : }\
83 : void verify() SAL_OVERRIDE;\
84 : }; \
85 : CPPUNIT_TEST_SUITE_REGISTRATION(TestName); \
86 : void TestName::verify()
87 :
88 : #define DECLARE_OOXMLIMPORT_TEST(TestName, filename) DECLARE_SW_IMPORT_TEST(TestName, filename, Test)
89 : #define DECLARE_OOXMLEXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, Test)
90 : #define DECLARE_RTFIMPORT_TEST(TestName, filename) DECLARE_SW_IMPORT_TEST(TestName, filename, Test)
91 : #define DECLARE_RTFEXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, Test)
92 : #define DECLARE_ODFIMPORT_TEST(TestName, filename) DECLARE_SW_IMPORT_TEST(TestName, filename, Test)
93 : #define DECLARE_ODFEXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, Test)
94 : #define DECLARE_WW8EXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, Test)
95 :
96 : #define DECLARE_SW_IMPORT_TEST(TestName, filename, BaseClass) \
97 : class TestName : public BaseClass { \
98 : protected:\
99 : virtual OUString getTestName() SAL_OVERRIDE { return OUString(#TestName); } \
100 : public:\
101 : CPPUNIT_TEST_SUITE(TestName); \
102 : CPPUNIT_TEST(Import); \
103 : CPPUNIT_TEST_SUITE_END(); \
104 : \
105 : void Import() { \
106 : executeImportTest(filename);\
107 : }\
108 : void verify() SAL_OVERRIDE;\
109 : }; \
110 : CPPUNIT_TEST_SUITE_REGISTRATION(TestName); \
111 : void TestName::verify()
112 :
113 : #define DECLARE_SW_EXPORT_TEST(TestName, filename, BaseClass) \
114 : class TestName : public BaseClass { \
115 : protected:\
116 : virtual OUString getTestName() SAL_OVERRIDE { return OUString(#TestName); } \
117 : public:\
118 : CPPUNIT_TEST_SUITE(TestName); \
119 : CPPUNIT_TEST(Import_Export); \
120 : CPPUNIT_TEST_SUITE_END(); \
121 : \
122 : void Import_Export() {\
123 : executeImportExport(filename);\
124 : }\
125 : void verify() SAL_OVERRIDE;\
126 : }; \
127 : CPPUNIT_TEST_SUITE_REGISTRATION(TestName); \
128 : void TestName::verify()
129 :
130 : /// Base class for filter tests loading or roundtriping a document, then asserting the document model.
131 : class SwModelTestBase : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools
132 : {
133 : private:
134 : OUString maFilterOptions;
135 :
136 : protected:
137 : uno::Reference< lang::XComponent > mxComponent;
138 :
139 : xmlBufferPtr mpXmlBuffer;
140 : const char* mpTestDocumentPath;
141 : const char* mpFilter;
142 :
143 : sal_uInt32 mnStartTime;
144 : utl::TempFile maTempFile;
145 : bool mbExported; ///< Does maTempFile already contain something useful?
146 :
147 : protected:
148 0 : virtual OUString getTestName() { return OUString(); }
149 :
150 : public:
151 : OUString& getFilterOptions()
152 : {
153 : return maFilterOptions;
154 : }
155 15 : void setFilterOptions(const OUString &rFilterOptions)
156 : {
157 15 : maFilterOptions = rFilterOptions;
158 15 : }
159 :
160 1645 : SwModelTestBase(const char* pTestDocumentPath = "", const char* pFilter = "")
161 : : mpXmlBuffer(0)
162 : , mpTestDocumentPath(pTestDocumentPath)
163 : , mpFilter(pFilter)
164 : , mnStartTime(0)
165 1645 : , mbExported(false)
166 : {
167 1645 : maTempFile.EnableKillingFile();
168 1645 : }
169 :
170 1645 : virtual ~SwModelTestBase()
171 1645 : {}
172 :
173 1645 : virtual void setUp() SAL_OVERRIDE
174 : {
175 1645 : test::BootstrapFixture::setUp();
176 :
177 1645 : mxDesktop.set(css::frame::Desktop::create(comphelper::getComponentContext(getMultiServiceFactory())));
178 1645 : }
179 :
180 1645 : virtual void tearDown() SAL_OVERRIDE
181 : {
182 1645 : if (mxComponent.is())
183 1561 : mxComponent->dispose();
184 :
185 1645 : test::BootstrapFixture::tearDown();
186 1645 : }
187 :
188 : protected:
189 : /**
190 : * Helper func used by each unit test to test the 'import' code.
191 : * (Loads the requested file and then calls 'verify' method)
192 : */
193 1001 : void executeImportTest(const char* filename)
194 : {
195 : // If the testcase is stored in some other format, it's pointless to test.
196 1001 : if (mustTestImportOf(filename))
197 : {
198 920 : maTempFile.EnableKillingFile(false);
199 920 : header();
200 920 : preTest(filename);
201 920 : load(mpTestDocumentPath, filename);
202 920 : postTest(filename);
203 920 : verify();
204 920 : finish();
205 920 : maTempFile.EnableKillingFile();
206 : }
207 1001 : }
208 :
209 : /**
210 : * Helper func used by each unit test to test the 'export' code.
211 : * (Loads the requested file, save it to temp file, load the
212 : * temp file and then calls 'verify' method)
213 : */
214 567 : void executeImportExportImportTest(const char* filename)
215 : {
216 567 : maTempFile.EnableKillingFile(false);
217 567 : header();
218 567 : preTest(filename);
219 567 : load(mpTestDocumentPath, filename);
220 567 : postLoad(filename);
221 567 : reload(mpFilter, filename);
222 567 : postTest(filename);
223 567 : verify();
224 567 : finish();
225 567 : maTempFile.EnableKillingFile();
226 567 : }
227 :
228 : /**
229 : * Helper func used by each unit test to test the 'export' code.
230 : * (Loads the requested file for document base (this represents
231 : * the initial document condition), exports with the desired
232 : * export filter and then calls 'verify' method)
233 : */
234 10 : void executeImportExport(const char* filename)
235 : {
236 10 : maTempFile.EnableKillingFile(false);
237 10 : header();
238 10 : preTest(filename);
239 10 : load(mpTestDocumentPath, filename);
240 10 : save(OUString::createFromAscii(mpFilter), maTempFile);
241 10 : maTempFile.EnableKillingFile(false);
242 10 : postTest(filename);
243 10 : verify();
244 10 : finish();
245 10 : maTempFile.EnableKillingFile();
246 10 : }
247 :
248 : /**
249 : * Function overridden by unit test. See DECLARE_SW_*_TEST macros
250 : */
251 0 : virtual void verify()
252 : {
253 0 : CPPUNIT_FAIL( "verify method must be overridden" );
254 0 : }
255 :
256 : /**
257 : * Override this function if interested in skipping import test for this file
258 : */
259 434 : virtual bool mustTestImportOf(const char* /* filename */) const
260 : {
261 434 : return true;
262 : }
263 : /**
264 : * Override this function if some special filename-specific setup is needed
265 : */
266 1083 : virtual void preTest(const char* /*filename*/)
267 : {
268 1083 : }
269 :
270 : /// Override this function if some special file-specific setup is needed during export test: after load, but before save.
271 484 : virtual void postLoad(const char* /*pFilename*/)
272 : {
273 484 : }
274 :
275 : /**
276 : * Override this function if some special filename-specific teardown is needed
277 : */
278 1083 : virtual void postTest(const char* /*filename*/)
279 : {
280 1083 : }
281 :
282 : /**
283 : * Override this function if calcing layout is not needed
284 : */
285 2127 : virtual bool mustCalcLayoutOf(const char* /*filename*/)
286 : {
287 2127 : return true;
288 : }
289 :
290 : /**
291 : * Override this function if validation is wanted
292 : */
293 425 : virtual bool mustValidate(const char* /*filename*/) const
294 : {
295 425 : return false;
296 : }
297 :
298 : private:
299 52 : void dumpLayout()
300 : {
301 : // create the xml writer
302 52 : mpXmlBuffer = xmlBufferCreate();
303 52 : xmlTextWriterPtr pXmlWriter = xmlNewTextWriterMemory(mpXmlBuffer, 0);
304 52 : xmlTextWriterStartDocument(pXmlWriter, NULL, NULL, NULL);
305 :
306 : // create the dump
307 52 : SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument *>(mxComponent.get());
308 52 : CPPUNIT_ASSERT(pTextDoc);
309 52 : SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
310 52 : SwRootFrm* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
311 52 : pLayout->dumpAsXml(pXmlWriter);
312 :
313 : // delete xml writer
314 52 : xmlTextWriterEndDocument(pXmlWriter);
315 52 : xmlFreeTextWriter(pXmlWriter);
316 52 : }
317 :
318 : protected:
319 3652 : void discardDumpedLayout()
320 : {
321 3652 : if (mpXmlBuffer)
322 : {
323 50 : xmlBufferFree(mpXmlBuffer);
324 50 : mpXmlBuffer = 0;
325 : }
326 3652 : }
327 :
328 2144 : void calcLayout()
329 : {
330 2144 : SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument *>(mxComponent.get());
331 2144 : CPPUNIT_ASSERT(pTextDoc);
332 2144 : SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
333 2144 : pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
334 2144 : }
335 :
336 : /// Get the length of the whole document.
337 9 : int getLength()
338 : {
339 9 : uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
340 18 : uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(), uno::UNO_QUERY);
341 18 : uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
342 18 : OUStringBuffer aBuf;
343 28 : while (xParaEnum->hasMoreElements())
344 : {
345 10 : uno::Reference<container::XEnumerationAccess> xRangeEnumAccess(xParaEnum->nextElement(), uno::UNO_QUERY);
346 20 : uno::Reference<container::XEnumeration> xRangeEnum = xRangeEnumAccess->createEnumeration();
347 34 : while (xRangeEnum->hasMoreElements())
348 : {
349 14 : uno::Reference<text::XTextRange> xRange(xRangeEnum->nextElement(), uno::UNO_QUERY);
350 14 : aBuf.append(xRange->getString());
351 14 : }
352 10 : }
353 18 : return aBuf.getLength();
354 : }
355 :
356 : /// Get a family of styles, see com.sun.star.style.StyleFamilies for possible values.
357 130 : uno::Reference<container::XNameAccess> getStyles(const OUString& aFamily)
358 : {
359 130 : uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(mxComponent, uno::UNO_QUERY);
360 260 : uno::Reference<container::XNameAccess> xStyleFamilies(xStyleFamiliesSupplier->getStyleFamilies(), uno::UNO_QUERY);
361 130 : uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName(aFamily), uno::UNO_QUERY);
362 260 : return xStyleFamily;
363 : }
364 :
365 : /// Get a family of auto styles, see com.sun.star.style.StyleFamilies for possible values.
366 2 : uno::Reference<style::XAutoStyleFamily> getAutoStyles(const OUString& aFamily)
367 : {
368 2 : uno::Reference< style::XAutoStylesSupplier > xAutoStylesSupplier(mxComponent, uno::UNO_QUERY);
369 4 : uno::Reference< style::XAutoStyles > xAutoStyles(xAutoStylesSupplier->getAutoStyles());
370 2 : uno::Reference< style::XAutoStyleFamily > xAutoStyleFamily(xAutoStyles->getByName(aFamily), uno::UNO_QUERY);
371 4 : return xAutoStyleFamily;
372 : }
373 :
374 : /// Similar to parseExport(), but this gives the xmlDocPtr of the layout dump.
375 190 : xmlDocPtr parseLayoutDump()
376 : {
377 190 : if (!mpXmlBuffer)
378 52 : dumpLayout();
379 :
380 190 : return xmlParseMemory(reinterpret_cast<const char*>(xmlBufferContent(mpXmlBuffer)), xmlBufferLength(mpXmlBuffer));;
381 : }
382 :
383 : /**
384 : * Extract a value from the layout dump using an XPath expression and an attribute name.
385 : *
386 : * If the attribute is omitted, the text of the node is returned.
387 : */
388 188 : OUString parseDump(const OString& aXPath, const OString& aAttribute = OString())
389 : {
390 188 : xmlDocPtr pXmlDoc = parseLayoutDump();
391 :
392 188 : xmlXPathContextPtr pXmlXpathCtx = xmlXPathNewContext(pXmlDoc);
393 188 : xmlXPathObjectPtr pXmlXpathObj = xmlXPathEvalExpression(BAD_CAST(aXPath.getStr()), pXmlXpathCtx);
394 188 : xmlNodeSetPtr pXmlNodes = pXmlXpathObj->nodesetval;
395 188 : CPPUNIT_ASSERT_EQUAL_MESSAGE("parsing dump failed", 1, xmlXPathNodeSetGetLength(pXmlNodes));
396 188 : xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
397 188 : OUString aRet;
398 188 : if (aAttribute.getLength())
399 60 : aRet = OUString::createFromAscii(reinterpret_cast<char*>(xmlGetProp(pXmlNode, BAD_CAST(aAttribute.getStr()))));
400 : else
401 128 : aRet = OUString::createFromAscii(reinterpret_cast<char*>(xmlNodeGetContent(pXmlNode)));
402 :
403 188 : xmlFreeDoc(pXmlDoc);
404 :
405 188 : return aRet;
406 : }
407 :
408 : template< typename T >
409 113 : T getProperty( const uno::Any& obj, const OUString& name ) const
410 : {
411 113 : uno::Reference< beans::XPropertySet > properties( obj, uno::UNO_QUERY_THROW );
412 113 : T data = T();
413 113 : if (!(properties->getPropertyValue(name) >>= data))
414 : {
415 0 : CPPUNIT_FAIL("the property is of unexpected type or void");
416 : }
417 113 : return data;
418 : }
419 :
420 : template< typename T >
421 2098 : T getProperty( const uno::Reference< uno::XInterface >& obj, const OUString& name ) const
422 : {
423 2098 : uno::Reference< beans::XPropertySet > properties( obj, uno::UNO_QUERY_THROW );
424 2098 : T data = T();
425 2098 : if (!(properties->getPropertyValue(name) >>= data))
426 : {
427 0 : CPPUNIT_FAIL("the property is of unexpected type or void");
428 : }
429 2098 : return data;
430 : }
431 :
432 18 : bool hasProperty(const uno::Reference<uno::XInterface>& obj, const OUString& name) const
433 : {
434 18 : uno::Reference<beans::XPropertySet> properties(obj, uno::UNO_QUERY_THROW);
435 18 : return properties->getPropertySetInfo()->hasPropertyByName(name);
436 : }
437 :
438 : /// Get number of paragraphs of the document.
439 5 : int getParagraphs()
440 : {
441 5 : uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
442 10 : uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(), uno::UNO_QUERY);
443 10 : uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
444 5 : int nRet = 0;
445 23 : while (xParaEnum->hasMoreElements())
446 : {
447 13 : xParaEnum->nextElement();
448 13 : nRet++;
449 : }
450 10 : return nRet;
451 : }
452 :
453 744 : uno::Reference<text::XTextContent> getParagraphOrTable(int number, uno::Reference<text::XText> xText = uno::Reference<text::XText>()) const
454 : {
455 744 : uno::Reference<container::XEnumerationAccess> paraEnumAccess;
456 744 : if (xText.is())
457 86 : paraEnumAccess.set(xText, uno::UNO_QUERY);
458 : else
459 : {
460 658 : uno::Reference<text::XTextDocument> textDocument(mxComponent, uno::UNO_QUERY);
461 658 : paraEnumAccess.set(textDocument->getText(), uno::UNO_QUERY);
462 : }
463 1488 : uno::Reference<container::XEnumeration> paraEnum = paraEnumAccess->createEnumeration();
464 1685 : for( int i = 1;
465 : i < number;
466 : ++i )
467 941 : paraEnum->nextElement();
468 744 : uno::Reference< text::XTextContent> const xElem(paraEnum->nextElement(),
469 744 : uno::UNO_QUERY_THROW);
470 1487 : return xElem;
471 : }
472 :
473 : // Get paragraph (counted from 1), optionally check it contains the given text.
474 646 : uno::Reference< text::XTextRange > getParagraph( int number, const OUString& content = OUString() ) const
475 : {
476 : uno::Reference<text::XTextRange> const xParagraph(
477 646 : getParagraphOrTable(number), uno::UNO_QUERY_THROW);
478 645 : if( !content.isEmpty())
479 55 : CPPUNIT_ASSERT_EQUAL_MESSAGE( "paragraph does not have expected content", content, xParagraph->getString());
480 645 : return xParagraph;
481 : }
482 :
483 77 : uno::Reference<text::XTextRange> getParagraphOfText(int number, uno::Reference<text::XText> xText, const OUString& content = OUString()) const
484 : {
485 77 : uno::Reference<text::XTextRange> const xParagraph(getParagraphOrTable(number, xText), uno::UNO_QUERY_THROW);
486 77 : if (!content.isEmpty())
487 10 : CPPUNIT_ASSERT_EQUAL_MESSAGE( "paragraph does not contain expected content", content, xParagraph->getString());
488 77 : return xParagraph;
489 : }
490 :
491 : /// Get run (counted from 1) of a paragraph, optionally check it contains the given text.
492 787 : uno::Reference<text::XTextRange> getRun(uno::Reference<text::XTextRange> xParagraph, int number, const OUString& content = OUString()) const
493 : {
494 787 : uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParagraph, uno::UNO_QUERY);
495 1574 : uno::Reference<container::XEnumeration> xRunEnum = xRunEnumAccess->createEnumeration();
496 3373 : for (int i = 1; i < number; ++i)
497 2586 : xRunEnum->nextElement();
498 787 : uno::Reference<text::XTextRange> xRun(xRunEnum->nextElement(), uno::UNO_QUERY);
499 787 : if( !content.isEmpty())
500 55 : CPPUNIT_ASSERT_EQUAL_MESSAGE( "run does not contain expected content", content, xRun->getString());
501 1574 : return xRun;
502 : }
503 :
504 : /// Get math formula string of a run.
505 115 : OUString getFormula(uno::Reference<text::XTextRange> xRun) const
506 : {
507 115 : uno::Reference<container::XContentEnumerationAccess> xContentEnumAccess(xRun, uno::UNO_QUERY);
508 230 : uno::Reference<container::XEnumeration> xContentEnum(xContentEnumAccess->createContentEnumeration(""), uno::UNO_QUERY);
509 230 : uno::Reference<beans::XPropertySet> xFormula(xContentEnum->nextElement(), uno::UNO_QUERY);
510 230 : return getProperty<OUString>(getProperty< uno::Reference<beans::XPropertySet> >(xFormula, "Model"), "Formula");
511 : }
512 :
513 : /// get cell of a table; table can be retrieved with getParagraphOrTable
514 7 : uno::Reference<table::XCell> getCell(
515 : uno::Reference<uno::XInterface> const& xTableIfc,
516 : OUString const& rCell, OUString const& rContent = OUString())
517 : {
518 : uno::Reference<text::XTextTable> const xTable(xTableIfc,
519 7 : uno::UNO_QUERY_THROW);
520 : uno::Reference<table::XCell> const xCell(
521 7 : xTable->getCellByName(rCell), uno::UNO_SET_THROW);
522 7 : if (!rContent.isEmpty())
523 : {
524 : uno::Reference<text::XText> const xCellText(xCell,
525 3 : uno::UNO_QUERY_THROW);
526 3 : CPPUNIT_ASSERT_EQUAL_MESSAGE("cell does not contain expected content", rContent, xCellText->getString());
527 : }
528 7 : return xCell;
529 : }
530 :
531 : /// Get shape (counted from 1)
532 399 : uno::Reference<drawing::XShape> getShape(int number)
533 : {
534 399 : uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
535 798 : uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
536 399 : uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(number - 1), uno::UNO_QUERY);
537 795 : return xShape;
538 : }
539 :
540 : /// Get shape by name
541 6 : uno::Reference<drawing::XShape> getShapeByName(const OUString& aName)
542 : {
543 6 : uno::Reference<drawing::XShape> xRet;
544 :
545 12 : uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
546 12 : uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
547 12 : for (sal_Int32 i = 0; i < xDrawPage->getCount(); ++i)
548 : {
549 12 : uno::Reference<container::XNamed> xShape(xDrawPage->getByIndex(i), uno::UNO_QUERY);
550 12 : if (xShape->getName() == aName)
551 : {
552 6 : xRet.set(xShape, uno::UNO_QUERY);
553 6 : break;
554 : }
555 6 : }
556 :
557 12 : return xRet;
558 : }
559 : /// Get TextFrame by name
560 6 : uno::Reference<drawing::XShape> getTextFrameByName(const OUString& aName)
561 : {
562 6 : uno::Reference<text::XTextFramesSupplier> xTextFramesSupplier(mxComponent, uno::UNO_QUERY);
563 12 : uno::Reference<container::XNameAccess> xNameAccess(xTextFramesSupplier->getTextFrames(), uno::UNO_QUERY);
564 6 : uno::Reference<drawing::XShape> xShape(xNameAccess->getByName(aName), uno::UNO_QUERY);
565 12 : return xShape;
566 : }
567 :
568 1506 : void header()
569 : {
570 1506 : std::cout << "File tested,Execution Time (ms)" << std::endl;
571 1506 : }
572 :
573 1554 : void load(const char* pDir, const char* pName)
574 : {
575 1554 : if (mxComponent.is())
576 0 : mxComponent->dispose();
577 : // Output name early, so in the case of a hang, the name of the hanging input file is visible.
578 1554 : std::cout << pName << ",";
579 1554 : mnStartTime = osl_getGlobalTimer();
580 1554 : mxComponent = loadFromDesktop(getURLFromSrc(pDir) + OUString::createFromAscii(pName), "com.sun.star.text.TextDocument");
581 1554 : discardDumpedLayout();
582 1554 : if (mustCalcLayoutOf(pName))
583 1553 : calcLayout();
584 1554 : }
585 :
586 569 : void reload(const char* pFilter, const char* filename)
587 : {
588 569 : uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
589 1138 : OUString aFilterName = OUString::createFromAscii(pFilter);
590 1138 : utl::MediaDescriptor aMediaDescriptor;
591 569 : aMediaDescriptor["FilterName"] <<= aFilterName;
592 569 : if (!maFilterOptions.isEmpty())
593 0 : aMediaDescriptor["FilterOptions"] <<= maFilterOptions;
594 569 : xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
595 1138 : uno::Reference<lang::XComponent> xComponent(xStorable, uno::UNO_QUERY);
596 569 : xComponent->dispose();
597 569 : mbExported = true;
598 569 : mxComponent = loadFromDesktop(maTempFile.GetURL(), "com.sun.star.text.TextDocument");
599 569 : if (mustValidate(filename))
600 : {
601 18 : if(aFilterName == "Office Open XML Text")
602 : {
603 : // too many validation errors right now
604 6 : validate(maTempFile.GetFileName(), test::OOXML);
605 : }
606 12 : else if(aFilterName == "writer8")
607 : {
608 : // still a few validation errors
609 12 : validate(maTempFile.GetFileName(), test::ODF);
610 : }
611 : }
612 569 : discardDumpedLayout();
613 569 : if (mustCalcLayoutOf(filename))
614 1137 : calcLayout();
615 569 : }
616 :
617 : /// Save the loaded document to a tempfile. Can be used to check the resulting docx/odt directly as a ZIP file.
618 11 : void save(const OUString& aFilterName, utl::TempFile& rTempFile)
619 : {
620 11 : rTempFile.EnableKillingFile();
621 11 : uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
622 22 : utl::MediaDescriptor aMediaDescriptor;
623 11 : aMediaDescriptor["FilterName"] <<= aFilterName;
624 11 : if (!maFilterOptions.isEmpty())
625 3 : aMediaDescriptor["FilterOptions"] <<= maFilterOptions;
626 22 : xStorable->storeToURL(rTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
627 11 : }
628 :
629 1506 : void finish()
630 : {
631 1506 : sal_uInt32 nEndTime = osl_getGlobalTimer();
632 1506 : std::cout << (nEndTime - mnStartTime) << std::endl;
633 1506 : discardDumpedLayout();
634 1506 : }
635 :
636 : /// Get page count.
637 36 : int getPages()
638 : {
639 36 : uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
640 72 : uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(xModel->getCurrentController(), uno::UNO_QUERY);
641 72 : uno::Reference<text::XPageCursor> xCursor(xTextViewCursorSupplier->getViewCursor(), uno::UNO_QUERY);
642 36 : xCursor->jumpToLastPage();
643 72 : return xCursor->getPage();
644 : }
645 :
646 : /**
647 : * Given that some problem doesn't affect the result in the importer, we
648 : * test the resulting file directly, by opening the zip file, parsing an
649 : * xml stream, and asserting an XPath expression. This method returns the
650 : * xml stream, so that you can do the asserting.
651 : */
652 571 : xmlDocPtr parseExport(const OUString& rStreamName = OUString("word/document.xml"))
653 : {
654 571 : if (!mbExported)
655 265 : return 0;
656 :
657 306 : return parseExportInternal( maTempFile.GetURL(), rStreamName );
658 : }
659 :
660 307 : xmlDocPtr parseExportInternal( const OUString& url, const OUString& rStreamName )
661 : {
662 : // Read the XML stream we're interested in.
663 307 : uno::Reference<packages::zip::XZipFileAccess2> xNameAccess = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory), url);
664 614 : uno::Reference<io::XInputStream> xInputStream(xNameAccess->getByName(rStreamName), uno::UNO_QUERY);
665 614 : boost::shared_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
666 :
667 307 : xmlDocPtr pXmlDoc = parseXmlStream(pStream.get());
668 307 : pXmlDoc->name = reinterpret_cast<char *>(xmlStrdup(reinterpret_cast<xmlChar const *>(OUStringToOString(maTempFile.GetURL(), RTL_TEXTENCODING_UTF8).getStr())));
669 614 : return pXmlDoc;
670 : }
671 :
672 : /**
673 : * Helper method to return nodes represented by rXPath.
674 : */
675 1162 : virtual void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) SAL_OVERRIDE
676 : {
677 : // docx
678 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("w"), BAD_CAST("http://schemas.openxmlformats.org/wordprocessingml/2006/main"));
679 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("v"), BAD_CAST("urn:schemas-microsoft-com:vml"));
680 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("mc"), BAD_CAST("http://schemas.openxmlformats.org/markup-compatibility/2006"));
681 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("wps"), BAD_CAST("http://schemas.microsoft.com/office/word/2010/wordprocessingShape"));
682 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("wpg"), BAD_CAST("http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"));
683 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("wp"), BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"));
684 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("wp14"), BAD_CAST("http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing"));
685 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("a"), BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/main"));
686 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("pic"), BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/picture"));
687 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("rels"), BAD_CAST("http://schemas.openxmlformats.org/package/2006/relationships"));
688 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("w14"), BAD_CAST("http://schemas.microsoft.com/office/word/2010/wordml"));
689 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("m"), BAD_CAST("http://schemas.openxmlformats.org/officeDocument/2006/math"));
690 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("ContentType"), BAD_CAST("http://schemas.openxmlformats.org/package/2006/content-types"));
691 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("lc"), BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas"));
692 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("extended-properties"), BAD_CAST("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"));
693 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("a14"), BAD_CAST("http://schemas.microsoft.com/office/drawing/2010/main"));
694 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("o"), BAD_CAST("urn:schemas-microsoft-com:office:office"));
695 : // odt
696 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("office"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:office:1.0"));
697 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("style"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:style:1.0"));
698 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("text"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:text:1.0"));
699 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("table"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:table:1.0"));
700 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("draw"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"));
701 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("fo"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"));
702 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xlink"), BAD_CAST("http://www.w3.org/1999/xlink"));
703 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("dc"), BAD_CAST("http://purl.org/dc/elements/1.1/"));
704 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("meta"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:meta:1.0"));
705 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("number"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"));
706 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("svg"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"));
707 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("chart"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:chart:1.0"));
708 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("dr3d"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"));
709 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("math"), BAD_CAST("http://www.w3.org/1998/Math/MathML"));
710 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("form"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:form:1.0"));
711 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("script"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:script:1.0"));
712 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("ooo"), BAD_CAST("http://openoffice.org/2004/office"));
713 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("ooow"), BAD_CAST("http://openoffice.org/2004/writer"));
714 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("oooc"), BAD_CAST("http://openoffice.org/2004/calc"));
715 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("dom"), BAD_CAST("http://www.w3.org/2001/xml-events"));
716 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xforms"), BAD_CAST("http://www.w3.org/2002/xforms"));
717 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xsd"), BAD_CAST("http://www.w3.org/2001/XMLSchema"));
718 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xsi"), BAD_CAST("http://www.w3.org/2001/XMLSchema-instance"));
719 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("rpt"), BAD_CAST("http://openoffice.org/2005/report"));
720 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("of"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:of:1.2"));
721 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xhtml"), BAD_CAST("http://www.w3.org/1999/xhtml"));
722 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("grddl"), BAD_CAST("http://www.w3.org/2003/g/data-view#"));
723 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("officeooo"), BAD_CAST("http://openoffice.org/2009/office"));
724 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("tableooo"), BAD_CAST("http://openoffice.org/2009/table"));
725 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("drawooo"), BAD_CAST("http://openoffice.org/2010/draw"));
726 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("calcext"), BAD_CAST("urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"));
727 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("loext"), BAD_CAST("urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"));
728 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("field"), BAD_CAST("urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0"));
729 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("formx"), BAD_CAST("urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0"));
730 1162 : xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("css3t"), BAD_CAST("http://www.w3.org/TR/css3-text/"));
731 1162 : }
732 : };
733 :
734 : /**
735 : * Test whether the expected and actual borderline parameters are equal
736 : * and assert if not.
737 : *
738 : * @param[in] rExpected expected borderline object
739 : * @param[in] rActual actual borderline object
740 : * @param[in] rSourceLine line from where the assertion is called
741 : * Note: This method is the implementatition of CPPUNIT_ASSERT_BORDER_EQUAL, so
742 : * use that macro instead.
743 : **/
744 126 : inline void assertBorderEqual(
745 : const table::BorderLine2& rExpected, const table::BorderLine2& rActual,
746 : const CppUnit::SourceLine& rSourceLine )
747 : {
748 126 : CPPUNIT_NS::assertEquals<util::Color>( rExpected.Color, rActual.Color, rSourceLine, "different Color" );
749 126 : CPPUNIT_NS::assertEquals<sal_Int16>( rExpected.InnerLineWidth, rActual.InnerLineWidth, rSourceLine, "different InnerLineWidth" );
750 126 : CPPUNIT_NS::assertEquals<sal_Int16>( rExpected.OuterLineWidth, rActual.OuterLineWidth, rSourceLine, "different OuterLineWidth" );
751 126 : CPPUNIT_NS::assertEquals<sal_Int16>( rExpected.LineDistance, rActual.LineDistance, rSourceLine, "different LineDistance" );
752 126 : CPPUNIT_NS::assertEquals<sal_Int16>( rExpected.LineStyle, rActual.LineStyle, rSourceLine, "different LineStyle" );
753 126 : CPPUNIT_NS::assertEquals<sal_Int32>( rExpected.LineWidth, rActual.LineWidth, rSourceLine, "different LineWidth" );
754 126 : }
755 :
756 : #define CPPUNIT_ASSERT_BORDER_EQUAL(aExpected, aActual) \
757 : assertBorderEqual( aExpected, aActual, CPPUNIT_SOURCELINE() ) \
758 :
759 : #endif // INCLUDED_SW_QA_EXTRAS_INC_SWMODELTESTBASE_HXX
760 :
761 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|