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 #pragma once
11 
12 #include <memory>
13 #include <string_view>
14 
15 #include <test/bootstrapfixture.hxx>
16 #include <test/xmldiff.hxx>
17 #include <test/xmltesttools.hxx>
18 
19 #include <unotest/filters-test.hxx>
20 #include <unotest/macros_test.hxx>
21 
22 #include <drawdoc.hxx>
23 #include <DrawDocShell.hxx>
24 #include <GraphicDocShell.hxx>
25 #include <unotools/tempfile.hxx>
26 #include <unotools/ucbstreamhelper.hxx>
27 #include <tools/color.hxx>
28 #include <comphelper/fileformat.h>
29 #include <comphelper/processfactory.hxx>
30 #include <o3tl/safeint.hxx>
31 #include <rtl/strbuf.hxx>
32 #include <sfx2/docfile.hxx>
33 #include <sfx2/docfilt.hxx>
34 #include <svl/itemset.hxx>
35 
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
38 #include <com/sun/star/packages/zip/ZipFileAccess.hpp>
39 #include <drawinglayer/XShapeDumper.hxx>
40 #include <com/sun/star/text/XTextField.hpp>
41 
42 using namespace ::com::sun::star;
43 
44 struct FileFormat
45 {
46     const char* pName;
47     const char* pFilterName;
48     const char* pTypeName;
49     const char* pUserData;
50     SfxFilterFlags nFormatType;
51 };
52 
53 // These values are taken from "Flags" in filter/source/config/fragments/filters/*
54 // You need to turn value of oor:name="Flags" to SfxFilterFlags::*, see
55 // include/comphelper/documentconstants.hxx for the possible values.
56 // Note: 3RDPARTYFILTER == SfxFilterFlags::STARONEFILTER
57 #define ODP_FORMAT_TYPE  ( SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT | SfxFilterFlags::TEMPLATE | SfxFilterFlags::OWN | SfxFilterFlags::DEFAULT | SfxFilterFlags::ENCRYPTION | SfxFilterFlags::PREFERED )
58 #define PPT_FORMAT_TYPE  ( SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT | SfxFilterFlags::ALIEN )
59 #define PPTX_FORMAT_TYPE ( SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT | SfxFilterFlags::ALIEN | SfxFilterFlags::STARONEFILTER | SfxFilterFlags::PREFERED )
60 #define HTML_FORMAT_TYPE ( SfxFilterFlags::EXPORT | SfxFilterFlags::ALIEN )
61 #define PDF_FORMAT_TYPE  ( SfxFilterFlags::STARONEFILTER | SfxFilterFlags::ALIEN | SfxFilterFlags::IMPORT | SfxFilterFlags::PREFERED )
62 #define FODG_FORMAT_TYPE  (SfxFilterFlags::STARONEFILTER | SfxFilterFlags::OWN | SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT)
63 #define FODP_FORMAT_TYPE  (SfxFilterFlags::STARONEFILTER | SfxFilterFlags::OWN | SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT)
64 #define SXI_FORMAT_TYPE  (SfxFilterFlags::IMPORT | SfxFilterFlags::TEMPLATE | SfxFilterFlags::OWN | SfxFilterFlags::ALIEN | SfxFilterFlags::PREFERED | SfxFilterFlags::ENCRYPTION)
65 #define ODG_FORMAT_TYPE  ( SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT | SfxFilterFlags::TEMPLATE | SfxFilterFlags::OWN | SfxFilterFlags::DEFAULT | SfxFilterFlags::ENCRYPTION | SfxFilterFlags::PREFERED )
66 #define PPTM_FORMAT_TYPE ( SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT | SfxFilterFlags::ALIEN | SfxFilterFlags::STARONEFILTER | SfxFilterFlags::PREFERED )
67 #define POTX_FORMAT_TYPE ( SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT | SfxFilterFlags::ALIEN | SfxFilterFlags::TEMPLATE | SfxFilterFlags::STARONEFILTER | SfxFilterFlags::PREFERED )
68 
69 /** List of file formats we support in Impress unit tests.
70 
71 Taken from filter/source/config/fragments/filters/ too:
72 pName: The file extension.
73 pFilterName: <node oor:Name="...">
74 pTypeName: <prop oor:Name="Type">...</prop>
75 nFormatType: <prop oor:name="Flags">...</prop>
76 */
77 static FileFormat aFileFormats[] =
78 {
79     { "odp",  "impress8", "impress8", "", ODP_FORMAT_TYPE },
80     { "ppt",  "MS PowerPoint 97", "impress_MS_PowerPoint_97", "sdfilt", PPT_FORMAT_TYPE },
81     { "pptx", "Impress Office Open XML", "Office Open XML Presentation", "", PPTX_FORMAT_TYPE },
82     { "html", "graphic_HTML", "graphic_HTML", "", HTML_FORMAT_TYPE },
83     { "pdf",  "draw_pdf_import", "pdf_Portable_Document_Format", "", PDF_FORMAT_TYPE },
84     { "fodg", "OpenDocument Drawing Flat XML", "draw_ODG_FlatXML", "", FODG_FORMAT_TYPE },
85     { "fodp", "OpenDocument Presentation Flat XML", "impress_ODP_FlatXML", "", FODP_FORMAT_TYPE },
86     { "sxi",  "StarOffice XML (Impress)", "impress_StarOffice_XML_Impress", "", SXI_FORMAT_TYPE },
87     { "odg",  "draw8", "draw8", "", ODG_FORMAT_TYPE },
88     { "pptm", "Impress MS PowerPoint 2007 XML VBA", "MS PowerPoint 2007 XML VBA", "", PPTM_FORMAT_TYPE },
89     { "potx", "Impress Office Open XML Template", "Office Open XML Presentation Template", "", POTX_FORMAT_TYPE },
90     { nullptr, nullptr, nullptr, nullptr, SfxFilterFlags::NONE }
91 };
92 
93 #define ODP  0
94 #define PPT  1
95 #define PPTX 2
96 #define HTML 3
97 #define PDF  4
98 #define FODG 5
99 #define FODP 6
100 #define SXI  7
101 #define ODG  8
102 #define PPTM 9
103 #define POTX 10
104 
105 /// Base class for filter tests loading or roundtripping a document, and asserting the document model.
106 class SdModelTestBase : public test::BootstrapFixture, public unotest::MacrosTest
107 {
108 private:
109     uno::Reference<uno::XInterface> mxDrawComponent;
110     uno::Reference<uno::XInterface> mxImpressComponent;
111 
112 public:
SdModelTestBase()113     SdModelTestBase()
114     {}
115 
setUp()116     virtual void setUp() override
117     {
118         test::BootstrapFixture::setUp();
119 
120         // This is a bit of a fudge, we do this to ensure that ScGlobals::ensure,
121         // which is a private symbol to us, gets called
122         mxImpressComponent = getMultiServiceFactory()->createInstance("com.sun.star.comp.Draw.PresentationDocument");
123         CPPUNIT_ASSERT_MESSAGE("no impress component!", mxImpressComponent.is());
124         mxDrawComponent = getMultiServiceFactory()->createInstance("com.sun.star.comp.Draw.DrawingDocument");
125         CPPUNIT_ASSERT_MESSAGE("no draw component!", mxDrawComponent.is());
126     }
127 
tearDown()128     virtual void tearDown() override
129     {
130         uno::Reference<lang::XComponent>(mxImpressComponent, uno::UNO_QUERY_THROW)->dispose();
131         uno::Reference<lang::XComponent>(mxDrawComponent, uno::UNO_QUERY_THROW)->dispose();
132         test::BootstrapFixture::tearDown();
133     }
134 
135 protected:
136     /// Load the document.
loadURL(const OUString & rURL,sal_Int32 nFormat,std::shared_ptr<SfxAllItemSet> pParams=nullptr)137     sd::DrawDocShellRef loadURL( const OUString &rURL, sal_Int32 nFormat, std::shared_ptr<SfxAllItemSet> pParams = nullptr )
138     {
139         FileFormat *pFmt = getFormat(nFormat);
140         CPPUNIT_ASSERT_MESSAGE( "missing filter info", pFmt->pName != nullptr );
141         if ( std::strcmp(pFmt->pName, "odg") == 0)
142         { // Draw
143             SotClipboardFormatId nOptions = SotClipboardFormatId::NONE;
144             if (pFmt->nFormatType != SfxFilterFlags::NONE)
145                 nOptions = SotClipboardFormatId::STARDRAW_8;
146             auto pFilter = std::make_shared<SfxFilter>(
147                 OUString::createFromAscii( pFmt->pFilterName ),
148                 OUString(), pFmt->nFormatType, nOptions,
149                 OUString::createFromAscii( pFmt->pTypeName ),
150                 OUString(),
151                 OUString::createFromAscii( pFmt->pUserData ),
152                 "private:factory/sdraw*" );
153             pFilter->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
154 
155             ::sd::DrawDocShellRef xDocShRef = new ::sd::GraphicDocShell(SfxObjectCreateMode::EMBEDDED);
156             SfxMedium* pSrcMed = new SfxMedium(rURL, StreamMode::STD_READ, pFilter, std::move(pParams));
157             if ( !xDocShRef->DoLoad(pSrcMed) || !xDocShRef.is() )
158             {
159                 if (xDocShRef.is())
160                     xDocShRef->DoClose();
161                 CPPUNIT_ASSERT_MESSAGE( OString("failed to load Draw doc" + OUStringToOString( rURL, RTL_TEXTENCODING_UTF8 )).getStr(), false );
162             }
163             CPPUNIT_ASSERT_MESSAGE( "not in destruction", !xDocShRef->IsInDestruction() );
164             return xDocShRef;
165         }
166         else // Impress
167         {
168             SotClipboardFormatId nOptions = SotClipboardFormatId::NONE;
169             if (pFmt->nFormatType != SfxFilterFlags::NONE)
170                 nOptions = SotClipboardFormatId::STARIMPRESS_8;
171             auto pFilter = std::make_shared<SfxFilter>(
172                 OUString::createFromAscii( pFmt->pFilterName ),
173                 OUString(), pFmt->nFormatType, nOptions,
174                 OUString::createFromAscii( pFmt->pTypeName ),
175                 OUString(),
176                 OUString::createFromAscii( pFmt->pUserData ),
177                 "private:factory/simpress*" );
178             pFilter->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
179 
180             ::sd::DrawDocShellRef xDocShRef = new ::sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED, false, DocumentType::Impress);
181             SfxMedium* pSrcMed = new SfxMedium(rURL, StreamMode::STD_READ, pFilter, std::move(pParams));
182             if ( !xDocShRef->DoLoad(pSrcMed) || !xDocShRef.is() )
183             {
184                 if (xDocShRef.is())
185                     xDocShRef->DoClose();
186                 CPPUNIT_ASSERT_MESSAGE( OString("failed to load " + OUStringToOString( rURL, RTL_TEXTENCODING_UTF8 )).getStr(), false );
187             }
188             CPPUNIT_ASSERT_MESSAGE( "not in destruction", !xDocShRef->IsInDestruction() );
189             return xDocShRef;
190         }
191     }
192 
getFormat(sal_Int32 nExportType)193     FileFormat* getFormat(sal_Int32 nExportType)
194     {
195         FileFormat* pFormat = &aFileFormats[0];
196         if (o3tl::make_unsigned(nExportType) < SAL_N_ELEMENTS(aFileFormats))
197             pFormat = &aFileFormats[nExportType];
198         return pFormat;
199     }
200 
exportTo(sd::DrawDocShell * pShell,FileFormat const * pFormat,utl::TempFile const & rTempFile)201     void exportTo(sd::DrawDocShell* pShell, FileFormat const * pFormat, utl::TempFile const & rTempFile)
202     {
203         SfxMedium aStoreMedium(rTempFile.GetURL(), StreamMode::STD_WRITE);
204         if ( std::strcmp(pFormat->pName, "odg") == 0)
205         { // Draw
206             SotClipboardFormatId nExportFormat = SotClipboardFormatId::NONE;
207             if (pFormat->nFormatType == ODG_FORMAT_TYPE)
208                 nExportFormat = SotClipboardFormatId::STARDRAW_8;
209             auto pExportFilter = std::make_shared<SfxFilter>(
210                                             OUString::createFromAscii(pFormat->pFilterName),
211                                             OUString(), pFormat->nFormatType, nExportFormat,
212                                             OUString::createFromAscii(pFormat->pTypeName),
213                                             OUString(),
214                                             OUString::createFromAscii(pFormat->pUserData),
215                                             "private:factory/sdraw*" );
216 
217             pExportFilter->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
218             aStoreMedium.SetFilter(pExportFilter);
219         }
220         else // Impress
221         {
222             SotClipboardFormatId nExportFormat = SotClipboardFormatId::NONE;
223             if (pFormat->nFormatType == ODP_FORMAT_TYPE)
224                 nExportFormat = SotClipboardFormatId::STARIMPRESS_8;
225             auto pExportFilter = std::make_shared<SfxFilter>(
226                                             OUString::createFromAscii(pFormat->pFilterName),
227                                             OUString(), pFormat->nFormatType, nExportFormat,
228                                             OUString::createFromAscii(pFormat->pTypeName),
229                                             OUString(),
230                                             OUString::createFromAscii(pFormat->pUserData),
231                                             "private:factory/simpress*" );
232 
233             pExportFilter->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
234             aStoreMedium.SetFilter(pExportFilter);
235         }
236         pShell->ConvertTo(aStoreMedium);
237         pShell->DoClose();
238 
239     }
240 
save(sd::DrawDocShell * pShell,FileFormat const * pFormat,utl::TempFile const & rTempFile)241     void save(sd::DrawDocShell* pShell, FileFormat const * pFormat, utl::TempFile const & rTempFile)
242     {
243         SfxMedium aStoreMedium(rTempFile.GetURL(), StreamMode::STD_WRITE);
244         if ( std::strcmp(pFormat->pName, "odg") == 0 )
245         { // Draw
246             SotClipboardFormatId nExportFormat = SotClipboardFormatId::NONE;
247             if (pFormat->nFormatType == ODG_FORMAT_TYPE)
248                 nExportFormat = SotClipboardFormatId::STARDRAW_8;
249             auto pExportFilter = std::make_shared<SfxFilter>(
250                                             OUString::createFromAscii(pFormat->pFilterName),
251                                             OUString(), pFormat->nFormatType, nExportFormat,
252                                             OUString::createFromAscii(pFormat->pTypeName),
253                                             OUString(),
254                                             OUString::createFromAscii(pFormat->pUserData),
255                                             "private:factory/sdraw*" );
256             pExportFilter->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
257             aStoreMedium.SetFilter(pExportFilter);
258         }
259         else // Impress
260         {
261             SotClipboardFormatId nExportFormat = SotClipboardFormatId::NONE;
262             if (pFormat->nFormatType == ODP_FORMAT_TYPE)
263                 nExportFormat = SotClipboardFormatId::STARCHART_8;
264             auto pExportFilter = std::make_shared<SfxFilter>(
265                                             OUString::createFromAscii(pFormat->pFilterName),
266                                             OUString(), pFormat->nFormatType, nExportFormat,
267                                             OUString::createFromAscii(pFormat->pTypeName),
268                                             OUString(),
269                                             OUString::createFromAscii(pFormat->pUserData),
270                                             "private:factory/simpress*" );
271             pExportFilter->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
272             aStoreMedium.SetFilter(pExportFilter);
273         }
274         pShell->DoSaveAs(aStoreMedium);
275         pShell->DoClose();
276     }
277 
saveAndReload(sd::DrawDocShell * pShell,sal_Int32 nExportType,utl::TempFile * pTempFile=nullptr)278     sd::DrawDocShellRef saveAndReload(sd::DrawDocShell *pShell, sal_Int32 nExportType,
279             utl::TempFile * pTempFile = nullptr)
280     {
281         FileFormat* pFormat = getFormat(nExportType);
282         std::unique_ptr<utl::TempFile> pNewTempFile;
283         if (!pTempFile)
284         {
285             pNewTempFile.reset(new utl::TempFile);
286             pTempFile = pNewTempFile.get();
287         }
288         save(pShell, pFormat, *pTempFile);
289         if (nExportType == ODP || nExportType == ODG)
290         {
291             BootstrapFixture::validate(pTempFile->GetFileName(), test::ODF);
292         }
293         else if(nExportType == PPTX)
294         {
295             BootstrapFixture::validate(pTempFile->GetFileName(), test::OOXML);
296         }
297         else if(nExportType == PPT)
298         {
299             BootstrapFixture::validate(pTempFile->GetFileName(), test::MSBINARY);
300         }
301         pTempFile->EnableKillingFile();
302         return loadURL(pTempFile->GetURL(), nExportType);
303     }
304 
305     /** Dump shapes in xDocShRef, and compare the dump against content of pShapesDumpFileNameBase<number>.xml.
306 
307         @param bCreate Instead of comparing to the reference file(s), create it/them.
308     */
compareWithShapesDump(::sd::DrawDocShellRef xDocShRef,std::u16string_view rShapesDumpFileNameBase,bool bCreate)309     void compareWithShapesDump( ::sd::DrawDocShellRef xDocShRef, std::u16string_view rShapesDumpFileNameBase, bool bCreate )
310     {
311         CPPUNIT_ASSERT_MESSAGE( "failed to load", xDocShRef.is() );
312         CPPUNIT_ASSERT_MESSAGE( "not in destruction", !xDocShRef->IsInDestruction() );
313 
314         uno::Reference<frame::XModel> xTempModel(xDocShRef->GetDoc()->getUnoModel(), uno::UNO_QUERY_THROW);
315         uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier (xTempModel, uno::UNO_QUERY_THROW);
316         uno::Reference< drawing::XDrawPages > xDrawPages = xDrawPagesSupplier->getDrawPages();
317         CPPUNIT_ASSERT(xDrawPages.is());
318 
319         sal_Int32 nLength = xDrawPages->getCount();
320         for (sal_Int32 i = 0; i < nLength; ++i)
321         {
322             uno::Reference<drawing::XDrawPage> xDrawPage;
323             uno::Any aAny = xDrawPages->getByIndex(i);
324             aAny >>= xDrawPage;
325             uno::Reference< drawing::XShapes > xShapes(xDrawPage, uno::UNO_QUERY_THROW);
326             OUString aString = XShapeDumper::dump(xShapes);
327 
328             OString aFileName = OUStringToOString( rShapesDumpFileNameBase, RTL_TEXTENCODING_UTF8 ) +
329                 OString::number(i) + ".xml";
330 
331             if ( bCreate )
332             {
333                 std::ofstream aStream( aFileName.getStr(), std::ofstream::out | std::ofstream::binary );
334                 aStream << aString;
335                 aStream.close();
336             }
337             else
338             {
339                 doXMLDiff(aFileName.getStr(),
340                         OUStringToOString(aString, RTL_TEXTENCODING_UTF8).getStr(),
341                         static_cast<int>(aString.getLength()),
342                         OUStringToOString(
343                             m_directories.getPathFromSrc(u"/sd/qa/unit/data/tolerance.xml"),
344                             RTL_TEXTENCODING_UTF8).getStr());
345             }
346         }
347         xDocShRef->DoClose();
348     }
349 
getDoc(sd::DrawDocShellRef xDocShRef)350     uno::Reference< drawing::XDrawPagesSupplier > getDoc( sd::DrawDocShellRef xDocShRef )
351     {
352         uno::Reference< drawing::XDrawPagesSupplier > xDoc (
353             xDocShRef->GetDoc()->getUnoModel(), uno::UNO_QUERY_THROW );
354         return xDoc;
355     }
356 
getPage(int nPage,sd::DrawDocShellRef xDocShRef)357     uno::Reference< drawing::XDrawPage > getPage( int nPage,  sd::DrawDocShellRef xDocShRef )
358     {
359         uno::Reference< drawing::XDrawPagesSupplier > xDoc( getDoc( xDocShRef ) );
360         uno::Reference< drawing::XDrawPage > xPage( xDoc->getDrawPages()->getByIndex( nPage ), uno::UNO_QUERY_THROW );
361         return xPage;
362     }
363 
364     // very confusing ... UNO index-based access to pages is 0-based. This one is 1-based
GetPage(int nPage,sd::DrawDocShellRef xDocShRef)365     const SdrPage* GetPage( int nPage, sd::DrawDocShellRef xDocShRef )
366     {
367         SdDrawDocument* pDoc =  xDocShRef->GetDoc() ;
368         CPPUNIT_ASSERT_MESSAGE( "no document", pDoc != nullptr );
369 
370         const SdrPage* pPage = pDoc->GetPage( nPage );
371         CPPUNIT_ASSERT_MESSAGE( "no page", pPage != nullptr );
372         return pPage;
373     }
374 
getShape(int nShape,uno::Reference<drawing::XDrawPage> const & xPage)375     uno::Reference< beans::XPropertySet > getShape( int nShape, uno::Reference< drawing::XDrawPage > const & xPage )
376     {
377         uno::Reference< beans::XPropertySet > xShape( xPage->getByIndex( nShape ), uno::UNO_QUERY );
378         CPPUNIT_ASSERT_MESSAGE( "Failed to load shape", xShape.is() );
379         return xShape;
380     }
381 
382     // Nth shape on Mth page
getShapeFromPage(int nShape,int nPage,sd::DrawDocShellRef xDocShRef)383     uno::Reference< beans::XPropertySet > getShapeFromPage( int nShape, int nPage, sd::DrawDocShellRef xDocShRef )
384     {
385         uno::Reference< drawing::XDrawPage > xPage ( getPage( nPage, xDocShRef ) );
386         uno::Reference< beans::XPropertySet > xShape( getShape( nShape, xPage ) );
387         CPPUNIT_ASSERT_MESSAGE( "Failed to load shape", xShape.is() );
388 
389         return xShape;
390     }
391 
392     // Nth paragraph of text in given text shape
getParagraphFromShape(int nPara,uno::Reference<beans::XPropertySet> const & xShape)393     uno::Reference< text::XTextRange > getParagraphFromShape( int nPara, uno::Reference< beans::XPropertySet > const & xShape )
394     {
395         uno::Reference< text::XText > xText = uno::Reference< text::XTextRange>( xShape, uno::UNO_QUERY_THROW )->getText();
396         CPPUNIT_ASSERT_MESSAGE( "Not a text shape", xText.is() );
397 
398         uno::Reference< container::XEnumerationAccess > paraEnumAccess( xText, uno::UNO_QUERY );
399         uno::Reference< container::XEnumeration > paraEnum( paraEnumAccess->createEnumeration() );
400 
401         for ( int i = 0; i < nPara; ++i )
402             paraEnum->nextElement();
403 
404         uno::Reference< text::XTextRange > xParagraph( paraEnum->nextElement(), uno::UNO_QUERY_THROW );
405 
406         return xParagraph;
407     }
408 
getRunFromParagraph(int nRun,uno::Reference<text::XTextRange> const & xParagraph)409     uno::Reference< text::XTextRange > getRunFromParagraph( int nRun, uno::Reference< text::XTextRange > const & xParagraph )
410     {
411         uno::Reference< container::XEnumerationAccess > runEnumAccess(xParagraph, uno::UNO_QUERY);
412         uno::Reference< container::XEnumeration > runEnum = runEnumAccess->createEnumeration();
413 
414         for ( int i = 0; i < nRun; ++i )
415             runEnum->nextElement();
416 
417         uno::Reference< text::XTextRange > xRun( runEnum->nextElement(), uno::UNO_QUERY);
418 
419         return xRun;
420     }
421 
getTextFieldFromPage(int nRun,int nPara,int nShape,int nPage,sd::DrawDocShellRef xDocShRef)422     uno::Reference<text::XTextField> getTextFieldFromPage(int nRun, int nPara, int nShape, int nPage, sd::DrawDocShellRef xDocShRef)
423     {
424         // get TextShape 1 from the first page
425         uno::Reference< beans::XPropertySet > xShape( getShapeFromPage( nShape, nPage, xDocShRef ) );
426 
427         // Get first paragraph
428         uno::Reference<text::XTextRange> xParagraph( getParagraphFromShape( nPara, xShape ) );
429 
430         // first chunk of text
431         uno::Reference<text::XTextRange> xRun( getRunFromParagraph( nRun, xParagraph ) );
432 
433         uno::Reference< beans::XPropertySet > xPropSet( xRun, uno::UNO_QUERY_THROW );
434 
435         uno::Reference<text::XTextField> xField;
436         xPropSet->getPropertyValue("TextField") >>= xField;
437         return xField;
438     }
439 
440 };
441 
442 class SdModelTestBaseXML
443     : public SdModelTestBase, public XmlTestTools
444 {
445 
446 public:
parseExportStream(utl::TempFile const & rTempFile,const OUString & rStreamName)447     std::unique_ptr<SvStream> parseExportStream(utl::TempFile const & rTempFile, const OUString& rStreamName)
448     {
449         // Read the stream we're interested in.
450         OUString const url(rTempFile.GetURL());
451         uno::Reference<packages::zip::XZipFileAccess2> const xZipNames(packages::zip::ZipFileAccess::createWithURL(
452                                                                         comphelper::getComponentContext(m_xSFactory), url));
453         uno::Reference<io::XInputStream> const xInputStream(xZipNames->getByName(rStreamName), uno::UNO_QUERY);
454         std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
455         return pStream;
456     }
457 
parseExport(utl::TempFile const & rTempFile,OUString const & rStreamName)458     xmlDocUniquePtr parseExport(utl::TempFile const & rTempFile, OUString const& rStreamName)
459     {
460         std::unique_ptr<SvStream> const pStream(parseExportStream(rTempFile, rStreamName));
461         xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
462         OUString const url(rTempFile.GetURL());
463         pXmlDoc->name = reinterpret_cast<char *>(xmlStrdup(
464             reinterpret_cast<xmlChar const *>(OUStringToOString(url, RTL_TEXTENCODING_UTF8).getStr())));
465         return pXmlDoc;
466     }
467 
468 };
469 
470 CPPUNIT_NS_BEGIN
471 
472 template<> struct assertion_traits<Color>
473 {
equalassertion_traits474     static bool equal( const Color& c1, const Color& c2 )
475     {
476         return c1 == c2;
477     }
478 
toStringassertion_traits479     static std::string toString( const Color& c )
480     {
481         OStringStream ost;
482         ost << "Color: R:" << static_cast<int>(c.GetRed())
483               << " G:" << static_cast<int>(c.GetGreen())
484               << " B:" << static_cast<int>(c.GetBlue())
485               << " A:" << static_cast<int>(255 - c.GetAlpha());
486         return ost.str();
487     }
488 };
489 
490 template<> struct assertion_traits<tools::Rectangle>
491 {
equalassertion_traits492     static bool equal( const tools::Rectangle& r1, const tools::Rectangle& r2 )
493     {
494         return r1 == r2;
495     }
496 
toStringassertion_traits497     static std::string toString( const tools::Rectangle& r)
498     {
499         OStringStream ost;
500         ost << "Rect P: [" << r.Top() << ", " << r.Left() << "] "
501             "S: [" << r.GetWidth() << ", " << r.GetHeight() << "]";
502         return ost.str();
503     }
504 };
505 
506 CPPUNIT_NS_END
507 
508 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
509