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 : #include <sal/config.h>
11 : #include <rtl/strbuf.hxx>
12 : #include <osl/file.hxx>
13 :
14 : #include <sfx2/app.hxx>
15 : #include <sfx2/docfile.hxx>
16 : #include <sfx2/frame.hxx>
17 : #include <sfx2/sfxmodelfactory.hxx>
18 : #include <svl/stritem.hxx>
19 :
20 : #include "helper/qahelper.hxx"
21 : #include "helper/xpath.hxx"
22 : #include "helper/shared_test_impl.hxx"
23 :
24 : #include "docsh.hxx"
25 : #include "patattr.hxx"
26 : #include "scitems.hxx"
27 : #include "document.hxx"
28 : #include "cellform.hxx"
29 : #include "formulacell.hxx"
30 : #include "tokenarray.hxx"
31 : #include "editutil.hxx"
32 : #include "scopetools.hxx"
33 : #include "cellvalue.hxx"
34 : #include "docfunc.hxx"
35 : #include <postit.hxx>
36 : #include <tokenstringcontext.hxx>
37 : #include <chgtrack.hxx>
38 : #include <dpcache.hxx>
39 : #include <dpobject.hxx>
40 : #include <dpsave.hxx>
41 : #include <dputil.hxx>
42 :
43 : #include <svx/svdoole2.hxx>
44 : #include "tabprotection.hxx"
45 : #include <editeng/wghtitem.hxx>
46 : #include <editeng/postitem.hxx>
47 : #include <editeng/editdata.hxx>
48 : #include <editeng/eeitem.hxx>
49 : #include <editeng/editobj.hxx>
50 : #include <editeng/section.hxx>
51 : #include <editeng/crossedoutitem.hxx>
52 : #include <editeng/borderline.hxx>
53 : #include <editeng/fontitem.hxx>
54 : #include <editeng/udlnitem.hxx>
55 : #include <formula/grammar.hxx>
56 : #include <unotools/useroptions.hxx>
57 : #include <tools/datetime.hxx>
58 :
59 : #include <test/xmltesttools.hxx>
60 :
61 : #include <com/sun/star/table/BorderLineStyle.hpp>
62 : #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
63 : #include <com/sun/star/sheet/GeneralFunction.hpp>
64 :
65 : using namespace ::com::sun::star;
66 : using namespace ::com::sun::star::uno;
67 :
68 140 : class ScExportTest : public ScBootstrapFixture, XmlTestTools
69 : {
70 : protected:
71 : virtual void registerNamespaces(xmlXPathContextPtr& pXmlXPathCtx) SAL_OVERRIDE;
72 : public:
73 : ScExportTest();
74 :
75 : virtual void setUp() SAL_OVERRIDE;
76 : virtual void tearDown() SAL_OVERRIDE;
77 :
78 : #if !defined MACOSX && !defined DRAGONFLY
79 : ScDocShellRef saveAndReloadPassword( ScDocShell*, const OUString&, const OUString&, const OUString&, sal_uLong );
80 : #endif
81 :
82 : void test();
83 : #if !defined MACOSX && !defined DRAGONFLY
84 : void testPasswordExport();
85 : #endif
86 : void testConditionalFormatExportODS();
87 : void testConditionalFormatExportXLSX();
88 : void testColorScaleExportODS();
89 : void testColorScaleExportXLSX();
90 : void testDataBarExportODS();
91 : void testDataBarExportXLSX();
92 : void testMiscRowHeightExport();
93 : void testNamedRangeBugfdo62729();
94 : void testRichTextExportODS();
95 : void testFormulaRefSheetNameODS();
96 :
97 : void testCellValuesExportODS();
98 : void testCellNoteExportODS();
99 : void testCellNoteExportXLS();
100 : void testFormatExportODS();
101 :
102 : void testInlineArrayXLS();
103 : void testEmbeddedChartXLS();
104 : void testFormulaReferenceXLS();
105 : void testSheetProtectionXLSX();
106 :
107 : void testCellBordersXLS();
108 : void testCellBordersXLSX();
109 : void testTrackChangesSimpleXLSX();
110 : void testSheetTabColorsXLSX();
111 :
112 : void testSharedFormulaExportXLS();
113 : void testSharedFormulaExportXLSX();
114 : void testSharedFormulaStringResultExportXLSX();
115 :
116 : void testFunctionsExcel2010( sal_uLong nFormatType );
117 : void testFunctionsExcel2010XLSX();
118 : void testFunctionsExcel2010XLS();
119 : void testFunctionsExcel2010ODS();
120 :
121 : void testRelativePaths();
122 : void testSheetProtection();
123 :
124 : void testPivotTableXLSX();
125 : void testPivotTableTwoDataFieldsXLSX();
126 :
127 : void testSupBookVirtualPath();
128 :
129 4 : CPPUNIT_TEST_SUITE(ScExportTest);
130 2 : CPPUNIT_TEST(test);
131 : #if !defined(MACOSX) && !defined(DRAGONFLY)
132 2 : CPPUNIT_TEST(testPasswordExport);
133 : #endif
134 2 : CPPUNIT_TEST(testConditionalFormatExportODS);
135 2 : CPPUNIT_TEST(testConditionalFormatExportXLSX);
136 2 : CPPUNIT_TEST(testColorScaleExportODS);
137 2 : CPPUNIT_TEST(testColorScaleExportXLSX);
138 2 : CPPUNIT_TEST(testDataBarExportODS);
139 2 : CPPUNIT_TEST(testDataBarExportXLSX);
140 2 : CPPUNIT_TEST(testMiscRowHeightExport);
141 2 : CPPUNIT_TEST(testNamedRangeBugfdo62729);
142 2 : CPPUNIT_TEST(testRichTextExportODS);
143 2 : CPPUNIT_TEST(testFormulaRefSheetNameODS);
144 2 : CPPUNIT_TEST(testCellValuesExportODS);
145 2 : CPPUNIT_TEST(testCellNoteExportODS);
146 2 : CPPUNIT_TEST(testCellNoteExportXLS);
147 2 : CPPUNIT_TEST(testFormatExportODS);
148 2 : CPPUNIT_TEST(testInlineArrayXLS);
149 2 : CPPUNIT_TEST(testEmbeddedChartXLS);
150 2 : CPPUNIT_TEST(testFormulaReferenceXLS);
151 2 : CPPUNIT_TEST(testSheetProtectionXLSX);
152 2 : CPPUNIT_TEST(testCellBordersXLS);
153 2 : CPPUNIT_TEST(testCellBordersXLSX);
154 2 : CPPUNIT_TEST(testTrackChangesSimpleXLSX);
155 2 : CPPUNIT_TEST(testSheetTabColorsXLSX);
156 2 : CPPUNIT_TEST(testSharedFormulaExportXLS);
157 2 : CPPUNIT_TEST(testSharedFormulaExportXLSX);
158 2 : CPPUNIT_TEST(testSharedFormulaStringResultExportXLSX);
159 2 : CPPUNIT_TEST(testFunctionsExcel2010XLSX);
160 2 : CPPUNIT_TEST(testFunctionsExcel2010XLS);
161 : #if !defined(WNT)
162 2 : CPPUNIT_TEST(testRelativePaths);
163 : #endif
164 2 : CPPUNIT_TEST(testSheetProtection);
165 2 : CPPUNIT_TEST(testPivotTableXLSX);
166 2 : CPPUNIT_TEST(testPivotTableTwoDataFieldsXLSX);
167 2 : CPPUNIT_TEST(testFunctionsExcel2010ODS);
168 : #if !defined(WNT)
169 2 : CPPUNIT_TEST(testSupBookVirtualPath);
170 : #endif
171 :
172 4 : CPPUNIT_TEST_SUITE_END();
173 :
174 : private:
175 : void testExcelCellBorders( sal_uLong nFormatType );
176 :
177 : uno::Reference<uno::XInterface> m_xCalcComponent;
178 :
179 : };
180 :
181 2 : void ScExportTest::registerNamespaces(xmlXPathContextPtr& pXmlXPathCtx)
182 : {
183 : struct { xmlChar* pPrefix; xmlChar* pURI; } aNamespaces[] =
184 : {
185 : { BAD_CAST("w"), BAD_CAST("http://schemas.openxmlformats.org/wordprocessingml/2006/main") },
186 : { BAD_CAST("v"), BAD_CAST("urn:schemas-microsoft-com:vml") },
187 : { BAD_CAST("c"), BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/chart") },
188 : { BAD_CAST("a"), BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/main") },
189 : { BAD_CAST("mc"), BAD_CAST("http://schemas.openxmlformats.org/markup-compatibility/2006") },
190 : { BAD_CAST("wps"), BAD_CAST("http://schemas.microsoft.com/office/word/2010/wordprocessingShape") },
191 : { BAD_CAST("wpg"), BAD_CAST("http://schemas.microsoft.com/office/word/2010/wordprocessingGroup") },
192 : { BAD_CAST("wp"), BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing") },
193 : { BAD_CAST("office"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:office:1.0") },
194 : { BAD_CAST("table"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:table:1.0") },
195 : { BAD_CAST("text"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:text:1.0") },
196 : { BAD_CAST("xlink"), BAD_CAST("http://www.w3c.org/1999/xlink") }
197 2 : };
198 26 : for(size_t i = 0; i < SAL_N_ELEMENTS(aNamespaces); ++i)
199 : {
200 24 : xmlXPathRegisterNs(pXmlXPathCtx, aNamespaces[i].pPrefix, aNamespaces[i].pURI );
201 : }
202 2 : }
203 :
204 : #if !defined MACOSX && !defined DRAGONFLY
205 2 : ScDocShellRef ScExportTest::saveAndReloadPassword(ScDocShell* pShell, const OUString &rFilter,
206 : const OUString &rUserData, const OUString& rTypeName, sal_uLong nFormatType)
207 : {
208 2 : utl::TempFile aTempFile;
209 2 : aTempFile.EnableKillingFile();
210 4 : SfxMedium aStoreMedium( aTempFile.GetURL(), STREAM_STD_WRITE );
211 2 : sal_uInt32 nExportFormat = 0;
212 2 : if (nFormatType == ODS_FORMAT_TYPE)
213 2 : nExportFormat = SFX_FILTER_EXPORT | SFX_FILTER_USESOPTIONS;
214 : SfxFilter* pExportFilter = new SfxFilter(
215 : rFilter,
216 : OUString(), nFormatType, nExportFormat, rTypeName, 0, OUString(),
217 2 : rUserData, OUString("private:factory/scalc*") );
218 2 : pExportFilter->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
219 2 : aStoreMedium.SetFilter(pExportFilter);
220 2 : SfxItemSet* pExportSet = aStoreMedium.GetItemSet();
221 4 : uno::Sequence< beans::NamedValue > aEncryptionData = comphelper::OStorageHelper::CreatePackageEncryptionData( OUString("test") );
222 4 : uno::Any xEncryptionData;
223 2 : xEncryptionData <<= aEncryptionData;
224 2 : pExportSet->Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA, xEncryptionData));
225 :
226 4 : uno::Reference< embed::XStorage > xMedStorage = aStoreMedium.GetStorage();
227 2 : ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( xMedStorage, aEncryptionData );
228 :
229 2 : pShell->DoSaveAs( aStoreMedium );
230 2 : pShell->DoClose();
231 :
232 : //std::cout << "File: " << aTempFile.GetURL() << std::endl;
233 :
234 2 : sal_uInt32 nFormat = 0;
235 2 : if (nFormatType == ODS_FORMAT_TYPE)
236 2 : nFormat = SFX_FILTER_IMPORT | SFX_FILTER_USESOPTIONS;
237 :
238 4 : OUString aPass("test");
239 4 : return load(aTempFile.GetURL(), rFilter, rUserData, rTypeName, nFormatType, nFormat, SOFFICE_FILEFORMAT_CURRENT, &aPass);
240 : }
241 : #endif
242 :
243 2 : void ScExportTest::test()
244 : {
245 : ScDocShell* pShell = new ScDocShell(
246 : SFXMODEL_STANDARD |
247 : SFXMODEL_DISABLE_EMBEDDED_SCRIPTS |
248 2 : SFXMODEL_DISABLE_DOCUMENT_RECOVERY);
249 2 : pShell->DoInitNew();
250 :
251 2 : ScDocument& rDoc = pShell->GetDocument();
252 :
253 2 : rDoc.SetValue(0,0,0, 1.0);
254 :
255 2 : ScDocShellRef xDocSh = saveAndReload( pShell, ODS );
256 :
257 2 : CPPUNIT_ASSERT(xDocSh.Is());
258 2 : ScDocument& rLoadedDoc = xDocSh->GetDocument();
259 2 : double aVal = rLoadedDoc.GetValue(0,0,0);
260 2 : ASSERT_DOUBLES_EQUAL(aVal, 1.0);
261 2 : xDocSh->DoClose();
262 2 : }
263 :
264 : #if !defined MACOSX && !defined DRAGONFLY
265 2 : void ScExportTest::testPasswordExport()
266 : {
267 : ScDocShell* pShell = new ScDocShell(
268 : SFXMODEL_STANDARD |
269 : SFXMODEL_DISABLE_EMBEDDED_SCRIPTS |
270 2 : SFXMODEL_DISABLE_DOCUMENT_RECOVERY);
271 2 : pShell->DoInitNew();
272 :
273 2 : ScDocument& rDoc = pShell->GetDocument();
274 :
275 2 : rDoc.SetValue(0,0,0, 1.0);
276 :
277 2 : sal_Int32 nFormat = ODS;
278 2 : OUString aFilterName(getFileFormats()[nFormat].pFilterName, strlen(getFileFormats()[nFormat].pFilterName), RTL_TEXTENCODING_UTF8) ;
279 4 : OUString aFilterType(getFileFormats()[nFormat].pTypeName, strlen(getFileFormats()[nFormat].pTypeName), RTL_TEXTENCODING_UTF8);
280 4 : ScDocShellRef xDocSh = saveAndReloadPassword(pShell, aFilterName, OUString(), aFilterType, getFileFormats()[nFormat].nFormatType);
281 :
282 2 : CPPUNIT_ASSERT(xDocSh.Is());
283 2 : ScDocument& rLoadedDoc = xDocSh->GetDocument();
284 2 : double aVal = rLoadedDoc.GetValue(0,0,0);
285 2 : ASSERT_DOUBLES_EQUAL(aVal, 1.0);
286 :
287 4 : xDocSh->DoClose();
288 2 : }
289 : #endif
290 :
291 2 : void ScExportTest::testConditionalFormatExportODS()
292 : {
293 2 : ScDocShellRef xShell = loadDoc("new_cond_format_test.", ODS);
294 2 : CPPUNIT_ASSERT(xShell.Is());
295 :
296 4 : ScDocShellRef xDocSh = saveAndReload(&(*xShell), ODS);
297 2 : CPPUNIT_ASSERT(xDocSh.Is());
298 2 : ScDocument& rDoc = xDocSh->GetDocument();
299 4 : OUString aCSVFile("new_cond_format_test.");
300 4 : OUString aCSVPath;
301 2 : createCSVPath( aCSVFile, aCSVPath );
302 2 : testCondFile(aCSVPath, &rDoc, 0);
303 :
304 4 : xDocSh->DoClose();
305 2 : }
306 :
307 2 : void ScExportTest::testConditionalFormatExportXLSX()
308 : {
309 2 : ScDocShellRef xShell = loadDoc("new_cond_format_test.", XLSX);
310 2 : CPPUNIT_ASSERT(xShell.Is());
311 :
312 4 : ScDocShellRef xDocSh = saveAndReload(&(*xShell), XLSX);
313 2 : CPPUNIT_ASSERT(xDocSh.Is());
314 2 : ScDocument& rDoc = xDocSh->GetDocument();
315 : {
316 2 : OUString aCSVFile("new_cond_format_test.");
317 4 : OUString aCSVPath;
318 2 : createCSVPath( aCSVFile, aCSVPath );
319 4 : testCondFile(aCSVPath, &rDoc, 0);
320 : }
321 : {
322 2 : OUString aCSVFile("new_cond_format_test_sheet2.");
323 4 : OUString aCSVPath;
324 2 : createCSVPath( aCSVFile, aCSVPath );
325 4 : testCondFile(aCSVPath, &rDoc, 1);
326 : }
327 :
328 4 : xDocSh->DoClose();
329 2 : }
330 :
331 2 : void ScExportTest::testColorScaleExportODS()
332 : {
333 2 : ScDocShellRef xShell = loadDoc("colorscale.", ODS);
334 2 : CPPUNIT_ASSERT(xShell.Is());
335 :
336 4 : ScDocShellRef xDocSh = saveAndReload(xShell, ODS);
337 2 : CPPUNIT_ASSERT(xDocSh.Is());
338 :
339 2 : ScDocument& rDoc = xDocSh->GetDocument();
340 :
341 2 : testColorScale2Entry_Impl(rDoc);
342 2 : testColorScale3Entry_Impl(rDoc);
343 :
344 4 : xDocSh->DoClose();
345 2 : }
346 :
347 2 : void ScExportTest::testColorScaleExportXLSX()
348 : {
349 2 : ScDocShellRef xShell = loadDoc("colorscale.", XLSX);
350 2 : CPPUNIT_ASSERT(xShell.Is());
351 :
352 4 : ScDocShellRef xDocSh = saveAndReload(xShell, XLSX);
353 2 : CPPUNIT_ASSERT(xDocSh.Is());
354 :
355 2 : ScDocument& rDoc = xDocSh->GetDocument();
356 :
357 2 : testColorScale2Entry_Impl(rDoc);
358 2 : testColorScale3Entry_Impl(rDoc);
359 :
360 4 : xDocSh->DoClose();
361 2 : }
362 :
363 2 : void ScExportTest::testDataBarExportODS()
364 : {
365 2 : ScDocShellRef xShell = loadDoc("databar.", ODS);
366 2 : CPPUNIT_ASSERT(xShell.Is());
367 :
368 4 : ScDocShellRef xDocSh = saveAndReload(xShell, ODS);
369 2 : CPPUNIT_ASSERT(xDocSh.Is());
370 :
371 2 : ScDocument& rDoc = xDocSh->GetDocument();
372 :
373 2 : testDataBar_Impl(rDoc);
374 :
375 4 : xDocSh->DoClose();
376 2 : }
377 :
378 2 : void ScExportTest::testFormatExportODS()
379 : {
380 2 : ScDocShellRef xShell = loadDoc("formats.", ODS);
381 2 : CPPUNIT_ASSERT(xShell.Is());
382 :
383 4 : ScDocShellRef xDocSh = saveAndReload(xShell, ODS);
384 2 : CPPUNIT_ASSERT(xDocSh.Is());
385 :
386 2 : ScDocument& rDoc = xDocSh->GetDocument();
387 :
388 2 : testFormats(this, &rDoc, ODS);
389 :
390 4 : xDocSh->DoClose();
391 2 : }
392 :
393 2 : void ScExportTest::testDataBarExportXLSX()
394 : {
395 2 : ScDocShellRef xShell = loadDoc("databar.", XLSX);
396 2 : CPPUNIT_ASSERT(xShell.Is());
397 :
398 4 : ScDocShellRef xDocSh = saveAndReload(xShell, XLSX);
399 2 : CPPUNIT_ASSERT(xDocSh.Is());
400 :
401 2 : ScDocument& rDoc = xDocSh->GetDocument();
402 :
403 2 : testDataBar_Impl(rDoc);
404 :
405 4 : xDocSh->DoClose();
406 2 : }
407 :
408 2 : void ScExportTest::testMiscRowHeightExport()
409 : {
410 : TestParam::RowData DfltRowData[] =
411 : {
412 : { 0, 4, 0, 529, 0, false },
413 : { 5, 10, 0, 1058, 0, false },
414 : { 17, 20, 0, 1767, 0, false },
415 : // check last couple of row in document to ensure
416 : // they are 5.29mm ( effective default row xlsx height )
417 : { 1048573, 1048575, 0, 529, 0, false },
418 2 : };
419 :
420 : TestParam::RowData EmptyRepeatRowData[] =
421 : {
422 : // rows 0-4, 5-10, 17-20 are all set at various
423 : // heights, there is no content in the rows, there
424 : // was a bug where only the first row ( of repeated rows )
425 : // was set after export
426 : { 0, 4, 0, 529, 0, false },
427 : { 5, 10, 0, 1058, 0, false },
428 : { 17, 20, 0, 1767, 0, false },
429 2 : };
430 :
431 : TestParam aTestValues[] =
432 : {
433 : // Checks that some distributed ( non-empty ) heights remain set after export (roundtrip)
434 : // additionally there is effectively a default row height ( 5.29 mm ). So we test the
435 : // unset rows at the end of the document to ensure the effective xlsx default height
436 : // is set there too.
437 : { "miscrowheights.", XLSX, XLSX, SAL_N_ELEMENTS(DfltRowData), DfltRowData },
438 : // Checks that some distributed ( non-empty ) heights remain set after export (to xls)
439 : { "miscrowheights.", XLSX, XLS, SAL_N_ELEMENTS(DfltRowData), DfltRowData },
440 : // Checks that repreated rows ( of various heights ) remain set after export ( to xlsx )
441 : { "miscemptyrepeatedrowheights.", ODS, XLSX, SAL_N_ELEMENTS(EmptyRepeatRowData), EmptyRepeatRowData },
442 : // Checks that repreated rows ( of various heights ) remain set after export ( to xls )
443 : { "miscemptyrepeatedrowheights.", ODS, XLS, SAL_N_ELEMENTS(EmptyRepeatRowData), EmptyRepeatRowData },
444 2 : };
445 2 : miscRowHeightsTest( aTestValues, SAL_N_ELEMENTS(aTestValues) );
446 2 : }
447 :
448 : namespace {
449 :
450 10 : void setAttribute( ScFieldEditEngine& rEE, sal_Int32 nPara, sal_Int32 nStart, sal_Int32 nEnd, sal_uInt16 nType )
451 : {
452 10 : ESelection aSel;
453 10 : aSel.nStartPara = aSel.nEndPara = nPara;
454 10 : aSel.nStartPos = nStart;
455 10 : aSel.nEndPos = nEnd;
456 :
457 10 : SfxItemSet aItemSet = rEE.GetEmptyItemSet();
458 10 : switch (nType)
459 : {
460 : case EE_CHAR_WEIGHT:
461 : {
462 2 : SvxWeightItem aWeight(WEIGHT_BOLD, nType);
463 2 : aItemSet.Put(aWeight);
464 2 : rEE.QuickSetAttribs(aItemSet, aSel);
465 : }
466 2 : break;
467 : case EE_CHAR_ITALIC:
468 : {
469 2 : SvxPostureItem aItalic(ITALIC_NORMAL, nType);
470 2 : aItemSet.Put(aItalic);
471 2 : rEE.QuickSetAttribs(aItemSet, aSel);
472 : }
473 2 : break;
474 : case EE_CHAR_STRIKEOUT:
475 : {
476 2 : SvxCrossedOutItem aCrossOut(STRIKEOUT_SINGLE, nType);
477 2 : aItemSet.Put(aCrossOut);
478 2 : rEE.QuickSetAttribs(aItemSet, aSel);
479 : }
480 2 : break;
481 : case EE_CHAR_OVERLINE:
482 : {
483 2 : SvxOverlineItem aItem(UNDERLINE_DOUBLE, nType);
484 2 : aItemSet.Put(aItem);
485 2 : rEE.QuickSetAttribs(aItemSet, aSel);
486 : }
487 2 : break;
488 : case EE_CHAR_UNDERLINE:
489 : {
490 2 : SvxUnderlineItem aItem(UNDERLINE_DOUBLE, nType);
491 2 : aItemSet.Put(aItem);
492 2 : rEE.QuickSetAttribs(aItemSet, aSel);
493 : }
494 2 : break;
495 : default:
496 : ;
497 10 : }
498 10 : }
499 :
500 4 : void setFont( ScFieldEditEngine& rEE, sal_Int32 nPara, sal_Int32 nStart, sal_Int32 nEnd, const OUString& rFontName )
501 : {
502 4 : ESelection aSel;
503 4 : aSel.nStartPara = aSel.nEndPara = nPara;
504 4 : aSel.nStartPos = nStart;
505 4 : aSel.nEndPos = nEnd;
506 :
507 4 : SfxItemSet aItemSet = rEE.GetEmptyItemSet();
508 8 : SvxFontItem aItem(FAMILY_MODERN, rFontName, "", PITCH_VARIABLE, RTL_TEXTENCODING_UTF8, EE_CHAR_FONTINFO);
509 4 : aItemSet.Put(aItem);
510 8 : rEE.QuickSetAttribs(aItemSet, aSel);
511 4 : }
512 :
513 : }
514 :
515 2 : void ScExportTest::testNamedRangeBugfdo62729()
516 : {
517 2 : ScDocShellRef xShell = loadDoc("fdo62729.", ODS);
518 2 : CPPUNIT_ASSERT(xShell.Is());
519 2 : ScDocument& rDoc = xShell->GetDocument();
520 :
521 2 : ScRangeName* pNames = rDoc.GetRangeName();
522 : //should be just a single named range
523 2 : CPPUNIT_ASSERT(pNames->size() == 1 );
524 2 : rDoc.DeleteTab(0);
525 : //should be still a single named range
526 2 : CPPUNIT_ASSERT(pNames->size() == 1 );
527 4 : ScDocShellRef xDocSh = saveAndReload(xShell, ODS);
528 2 : xShell->DoClose();
529 :
530 2 : CPPUNIT_ASSERT(xDocSh.Is());
531 2 : ScDocument& rDoc2 = xDocSh->GetDocument();
532 :
533 2 : pNames = rDoc2.GetRangeName();
534 : //after reload should still have a named range
535 2 : CPPUNIT_ASSERT(pNames->size() == 1 );
536 :
537 4 : xDocSh->DoClose();
538 2 : }
539 :
540 2 : void ScExportTest::testRichTextExportODS()
541 : {
542 : struct
543 : {
544 6 : static bool isBold(const editeng::Section& rAttr)
545 : {
546 6 : if (rAttr.maAttributes.empty())
547 0 : return false;
548 :
549 6 : std::vector<const SfxPoolItem*>::const_iterator it = rAttr.maAttributes.begin(), itEnd = rAttr.maAttributes.end();
550 6 : for (; it != itEnd; ++it)
551 : {
552 6 : const SfxPoolItem* p = *it;
553 6 : if (p->Which() != EE_CHAR_WEIGHT)
554 0 : continue;
555 :
556 6 : return static_cast<const SvxWeightItem*>(p)->GetWeight() == WEIGHT_BOLD;
557 : }
558 0 : return false;
559 : }
560 :
561 6 : static bool isItalic(const editeng::Section& rAttr)
562 : {
563 6 : if (rAttr.maAttributes.empty())
564 0 : return false;
565 :
566 6 : std::vector<const SfxPoolItem*>::const_iterator it = rAttr.maAttributes.begin(), itEnd = rAttr.maAttributes.end();
567 6 : for (; it != itEnd; ++it)
568 : {
569 6 : const SfxPoolItem* p = *it;
570 6 : if (p->Which() != EE_CHAR_ITALIC)
571 0 : continue;
572 :
573 6 : return static_cast<const SvxPostureItem*>(p)->GetPosture() == ITALIC_NORMAL;
574 : }
575 0 : return false;
576 : }
577 :
578 4 : static bool isStrikeOut(const editeng::Section& rAttr)
579 : {
580 4 : if (rAttr.maAttributes.empty())
581 0 : return false;
582 :
583 4 : std::vector<const SfxPoolItem*>::const_iterator it = rAttr.maAttributes.begin(), itEnd = rAttr.maAttributes.end();
584 4 : for (; it != itEnd; ++it)
585 : {
586 4 : const SfxPoolItem* p = *it;
587 4 : if (p->Which() != EE_CHAR_STRIKEOUT)
588 0 : continue;
589 :
590 4 : return static_cast<const SvxCrossedOutItem*>(p)->GetStrikeout() == STRIKEOUT_SINGLE;
591 : }
592 0 : return false;
593 : }
594 :
595 4 : static bool isOverline(const editeng::Section& rAttr, FontUnderline eStyle)
596 : {
597 4 : if (rAttr.maAttributes.empty())
598 0 : return false;
599 :
600 4 : std::vector<const SfxPoolItem*>::const_iterator it = rAttr.maAttributes.begin(), itEnd = rAttr.maAttributes.end();
601 4 : for (; it != itEnd; ++it)
602 : {
603 4 : const SfxPoolItem* p = *it;
604 4 : if (p->Which() != EE_CHAR_OVERLINE)
605 0 : continue;
606 :
607 4 : return static_cast<const SvxOverlineItem*>(p)->GetLineStyle() == eStyle;
608 : }
609 0 : return false;
610 : }
611 :
612 4 : static bool isUnderline(const editeng::Section& rAttr, FontUnderline eStyle)
613 : {
614 4 : if (rAttr.maAttributes.empty())
615 0 : return false;
616 :
617 4 : std::vector<const SfxPoolItem*>::const_iterator it = rAttr.maAttributes.begin(), itEnd = rAttr.maAttributes.end();
618 4 : for (; it != itEnd; ++it)
619 : {
620 4 : const SfxPoolItem* p = *it;
621 4 : if (p->Which() != EE_CHAR_UNDERLINE)
622 0 : continue;
623 :
624 4 : return static_cast<const SvxUnderlineItem*>(p)->GetLineStyle() == eStyle;
625 : }
626 0 : return false;
627 : }
628 :
629 8 : static bool isFont(const editeng::Section& rAttr, const OUString& rFontName)
630 : {
631 8 : if (rAttr.maAttributes.empty())
632 0 : return false;
633 :
634 8 : std::vector<const SfxPoolItem*>::const_iterator it = rAttr.maAttributes.begin(), itEnd = rAttr.maAttributes.end();
635 8 : for (; it != itEnd; ++it)
636 : {
637 8 : const SfxPoolItem* p = *it;
638 8 : if (p->Which() != EE_CHAR_FONTINFO)
639 0 : continue;
640 :
641 8 : return static_cast<const SvxFontItem*>(p)->GetFamilyName() == rFontName;
642 : }
643 0 : return false;
644 : }
645 :
646 6 : bool checkB2(const EditTextObject* pText) const
647 : {
648 6 : if (!pText)
649 0 : return false;
650 :
651 6 : if (pText->GetParagraphCount() != 1)
652 0 : return false;
653 :
654 6 : if (pText->GetText(0) != "Bold and Italic")
655 0 : return false;
656 :
657 6 : std::vector<editeng::Section> aSecAttrs;
658 6 : pText->GetAllSections(aSecAttrs);
659 6 : if (aSecAttrs.size() != 3)
660 0 : return false;
661 :
662 : // Check the first bold section.
663 6 : const editeng::Section* pAttr = &aSecAttrs[0];
664 6 : if (pAttr->mnParagraph != 0 ||pAttr->mnStart != 0 || pAttr->mnEnd != 4)
665 0 : return false;
666 :
667 6 : if (pAttr->maAttributes.size() != 1 || !isBold(*pAttr))
668 0 : return false;
669 :
670 : // The middle section should be unformatted.
671 6 : pAttr = &aSecAttrs[1];
672 6 : if (pAttr->mnParagraph != 0 ||pAttr->mnStart != 4 || pAttr->mnEnd != 9)
673 0 : return false;
674 :
675 6 : if (!pAttr->maAttributes.empty())
676 0 : return false;
677 :
678 : // The last section should be italic.
679 6 : pAttr = &aSecAttrs[2];
680 6 : if (pAttr->mnParagraph != 0 ||pAttr->mnStart != 9 || pAttr->mnEnd != 15)
681 0 : return false;
682 :
683 6 : if (pAttr->maAttributes.size() != 1 || !isItalic(*pAttr))
684 0 : return false;
685 :
686 6 : return true;
687 : }
688 :
689 6 : bool checkB4(const EditTextObject* pText) const
690 : {
691 6 : if (!pText)
692 0 : return false;
693 :
694 6 : if (pText->GetParagraphCount() != 3)
695 0 : return false;
696 :
697 6 : if (pText->GetText(0) != "One")
698 0 : return false;
699 :
700 6 : if (pText->GetText(1) != "Two")
701 0 : return false;
702 :
703 6 : if (pText->GetText(2) != "Three")
704 0 : return false;
705 :
706 6 : return true;
707 : }
708 :
709 4 : bool checkB5(const EditTextObject* pText) const
710 : {
711 4 : if (!pText)
712 0 : return false;
713 :
714 4 : if (pText->GetParagraphCount() != 6)
715 0 : return false;
716 :
717 4 : if (pText->GetText(0) != "")
718 0 : return false;
719 :
720 4 : if (pText->GetText(1) != "Two")
721 0 : return false;
722 :
723 4 : if (pText->GetText(2) != "Three")
724 0 : return false;
725 :
726 4 : if (pText->GetText(3) != "")
727 0 : return false;
728 :
729 4 : if (pText->GetText(4) != "Five")
730 0 : return false;
731 :
732 4 : if (pText->GetText(5) != "")
733 0 : return false;
734 :
735 4 : return true;
736 : }
737 :
738 4 : bool checkB6(const EditTextObject* pText) const
739 : {
740 4 : if (!pText)
741 0 : return false;
742 :
743 4 : if (pText->GetParagraphCount() != 1)
744 0 : return false;
745 :
746 4 : if (pText->GetText(0) != "Strike Me")
747 0 : return false;
748 :
749 4 : std::vector<editeng::Section> aSecAttrs;
750 4 : pText->GetAllSections(aSecAttrs);
751 4 : if (aSecAttrs.size() != 2)
752 0 : return false;
753 :
754 : // Check the first strike-out section.
755 4 : const editeng::Section* pAttr = &aSecAttrs[0];
756 4 : if (pAttr->mnParagraph != 0 ||pAttr->mnStart != 0 || pAttr->mnEnd != 6)
757 0 : return false;
758 :
759 4 : if (pAttr->maAttributes.size() != 1 || !isStrikeOut(*pAttr))
760 0 : return false;
761 :
762 : // The last section should be unformatted.
763 4 : pAttr = &aSecAttrs[1];
764 4 : if (pAttr->mnParagraph != 0 ||pAttr->mnStart != 6 || pAttr->mnEnd != 9)
765 0 : return false;
766 :
767 4 : return true;
768 : }
769 :
770 4 : bool checkB7(const EditTextObject* pText) const
771 : {
772 4 : if (!pText)
773 0 : return false;
774 :
775 4 : if (pText->GetParagraphCount() != 1)
776 0 : return false;
777 :
778 4 : if (pText->GetText(0) != "Font1 and Font2")
779 0 : return false;
780 :
781 4 : std::vector<editeng::Section> aSecAttrs;
782 4 : pText->GetAllSections(aSecAttrs);
783 4 : if (aSecAttrs.size() != 3)
784 0 : return false;
785 :
786 : // First section should have "Courier" font applied.
787 4 : const editeng::Section* pAttr = &aSecAttrs[0];
788 4 : if (pAttr->mnParagraph != 0 ||pAttr->mnStart != 0 || pAttr->mnEnd != 5)
789 0 : return false;
790 :
791 4 : if (pAttr->maAttributes.size() != 1 || !isFont(*pAttr, "Courier"))
792 0 : return false;
793 :
794 : // Last section should have "Luxi Mono" applied.
795 4 : pAttr = &aSecAttrs[2];
796 4 : if (pAttr->mnParagraph != 0 ||pAttr->mnStart != 10 || pAttr->mnEnd != 15)
797 0 : return false;
798 :
799 4 : if (pAttr->maAttributes.size() != 1 || !isFont(*pAttr, "Luxi Mono"))
800 0 : return false;
801 :
802 4 : return true;
803 : }
804 :
805 4 : bool checkB8(const EditTextObject* pText) const
806 : {
807 4 : if (!pText)
808 0 : return false;
809 :
810 4 : if (pText->GetParagraphCount() != 1)
811 0 : return false;
812 :
813 4 : if (pText->GetText(0) != "Over and Under")
814 0 : return false;
815 :
816 4 : std::vector<editeng::Section> aSecAttrs;
817 4 : pText->GetAllSections(aSecAttrs);
818 4 : if (aSecAttrs.size() != 3)
819 0 : return false;
820 :
821 : // First section shoul have overline applied.
822 4 : const editeng::Section* pAttr = &aSecAttrs[0];
823 4 : if (pAttr->mnParagraph != 0 ||pAttr->mnStart != 0 || pAttr->mnEnd != 4)
824 0 : return false;
825 :
826 4 : if (pAttr->maAttributes.size() != 1 || !isOverline(*pAttr, UNDERLINE_DOUBLE))
827 0 : return false;
828 :
829 : // Last section should have underline applied.
830 4 : pAttr = &aSecAttrs[2];
831 4 : if (pAttr->mnParagraph != 0 ||pAttr->mnStart != 9 || pAttr->mnEnd != 14)
832 0 : return false;
833 :
834 4 : if (pAttr->maAttributes.size() != 1 || !isUnderline(*pAttr, UNDERLINE_DOUBLE))
835 0 : return false;
836 :
837 4 : return true;
838 : }
839 :
840 : } aCheckFunc;
841 :
842 : // Start with an empty document, put one edit text cell, and make sure it
843 : // survives the save and reload.
844 2 : ScDocShellRef xOrigDocSh = loadDoc("empty.", ODS, true);
845 : const EditTextObject* pEditText;
846 : {
847 2 : ScDocument& rDoc = xOrigDocSh->GetDocument();
848 2 : CPPUNIT_ASSERT_MESSAGE("This document should at least have one sheet.", rDoc.GetTableCount() > 0);
849 :
850 : // Insert an edit text cell.
851 2 : ScFieldEditEngine* pEE = &rDoc.GetEditEngine();
852 2 : pEE->SetText("Bold and Italic");
853 : // Set the 'Bold' part bold.
854 2 : setAttribute(*pEE, 0, 0, 4, EE_CHAR_WEIGHT);
855 : // Set the 'Italic' part italic.
856 2 : setAttribute(*pEE, 0, 9, 15, EE_CHAR_ITALIC);
857 2 : ESelection aSel;
858 2 : aSel.nStartPara = aSel.nEndPara = 0;
859 :
860 : // Set this edit text to cell B2.
861 2 : rDoc.SetEditText(ScAddress(1,1,0), pEE->CreateTextObject());
862 2 : pEditText = rDoc.GetEditText(ScAddress(1,1,0));
863 2 : CPPUNIT_ASSERT_MESSAGE("Incorret B2 value.", aCheckFunc.checkB2(pEditText));
864 : }
865 :
866 : // Now, save and reload this document.
867 4 : ScDocShellRef xNewDocSh = saveAndReload(xOrigDocSh, ODS);
868 : {
869 2 : xOrigDocSh->DoClose();
870 2 : CPPUNIT_ASSERT(xNewDocSh.Is());
871 2 : ScDocument& rDoc2 = xNewDocSh->GetDocument();
872 2 : CPPUNIT_ASSERT_MESSAGE("Reloaded document should at least have one sheet.", rDoc2.GetTableCount() > 0);
873 2 : ScFieldEditEngine* pEE = &rDoc2.GetEditEngine();
874 :
875 : // Make sure the content of B2 is still intact.
876 2 : CPPUNIT_ASSERT_MESSAGE("Incorret B2 value.", aCheckFunc.checkB2(pEditText));
877 :
878 : // Insert a multi-line content to B4.
879 2 : pEE->Clear();
880 2 : pEE->SetText("One\nTwo\nThree");
881 2 : rDoc2.SetEditText(ScAddress(1,3,0), pEE->CreateTextObject());
882 2 : pEditText = rDoc2.GetEditText(ScAddress(1,3,0));
883 2 : CPPUNIT_ASSERT_MESSAGE("Incorrect B4 value.", aCheckFunc.checkB4(pEditText));
884 : }
885 :
886 : // Reload the doc again, and check the content of B2 and B4.
887 4 : ScDocShellRef xNewDocSh2 = saveAndReload(xNewDocSh, ODS);
888 : {
889 2 : ScDocument& rDoc3 = xNewDocSh2->GetDocument();
890 2 : ScFieldEditEngine* pEE = &rDoc3.GetEditEngine();
891 2 : xNewDocSh->DoClose();
892 :
893 2 : pEditText = rDoc3.GetEditText(ScAddress(1,1,0));
894 2 : CPPUNIT_ASSERT_MESSAGE("B2 should be an edit text.", pEditText);
895 2 : pEditText = rDoc3.GetEditText(ScAddress(1,3,0));
896 2 : CPPUNIT_ASSERT_MESSAGE("Incorrect B4 value.", aCheckFunc.checkB4(pEditText));
897 :
898 : // Insert a multi-line content to B5, but this time, set some empty paragraphs.
899 2 : pEE->Clear();
900 2 : pEE->SetText("\nTwo\nThree\n\nFive\n");
901 2 : rDoc3.SetEditText(ScAddress(1,4,0), pEE->CreateTextObject());
902 2 : pEditText = rDoc3.GetEditText(ScAddress(1,4,0));
903 2 : CPPUNIT_ASSERT_MESSAGE("Incorrect B5 value.", aCheckFunc.checkB5(pEditText));
904 :
905 : // Insert a text with strikethrough in B6.
906 2 : pEE->Clear();
907 2 : pEE->SetText("Strike Me");
908 : // Set the 'Strike' part strikethrough.
909 2 : setAttribute(*pEE, 0, 0, 6, EE_CHAR_STRIKEOUT);
910 2 : rDoc3.SetEditText(ScAddress(1,5,0), pEE->CreateTextObject());
911 2 : pEditText = rDoc3.GetEditText(ScAddress(1,5,0));
912 2 : CPPUNIT_ASSERT_MESSAGE("Incorrect B6 value.", aCheckFunc.checkB6(pEditText));
913 :
914 : // Insert a text with different font segments in B7.
915 2 : pEE->Clear();
916 2 : pEE->SetText("Font1 and Font2");
917 2 : setFont(*pEE, 0, 0, 5, "Courier");
918 2 : setFont(*pEE, 0, 10, 15, "Luxi Mono");
919 2 : rDoc3.SetEditText(ScAddress(1,6,0), pEE->CreateTextObject());
920 2 : pEditText = rDoc3.GetEditText(ScAddress(1,6,0));
921 2 : CPPUNIT_ASSERT_MESSAGE("Incorrect B7 value.", aCheckFunc.checkB7(pEditText));
922 :
923 : // Insert a text with overline and underline in B8.
924 2 : pEE->Clear();
925 2 : pEE->SetText("Over and Under");
926 2 : setAttribute(*pEE, 0, 0, 4, EE_CHAR_OVERLINE);
927 2 : setAttribute(*pEE, 0, 9, 14, EE_CHAR_UNDERLINE);
928 2 : rDoc3.SetEditText(ScAddress(1,7,0), pEE->CreateTextObject());
929 2 : pEditText = rDoc3.GetEditText(ScAddress(1,7,0));
930 2 : CPPUNIT_ASSERT_MESSAGE("Incorrect B8 value.", aCheckFunc.checkB8(pEditText));
931 : }
932 :
933 : // Reload the doc again, and check the content of B2, B4, B6 and B7.
934 4 : ScDocShellRef xNewDocSh3 = saveAndReload(xNewDocSh2, ODS);
935 2 : ScDocument& rDoc4 = xNewDocSh3->GetDocument();
936 2 : xNewDocSh2->DoClose();
937 :
938 2 : pEditText = rDoc4.GetEditText(ScAddress(1,1,0));
939 2 : CPPUNIT_ASSERT_MESSAGE("Incorrect B2 value after save and reload.", aCheckFunc.checkB2(pEditText));
940 2 : pEditText = rDoc4.GetEditText(ScAddress(1,3,0));
941 2 : CPPUNIT_ASSERT_MESSAGE("Incorrect B4 value after save and reload.", aCheckFunc.checkB4(pEditText));
942 2 : pEditText = rDoc4.GetEditText(ScAddress(1,4,0));
943 2 : CPPUNIT_ASSERT_MESSAGE("Incorrect B5 value after save and reload.", aCheckFunc.checkB5(pEditText));
944 2 : pEditText = rDoc4.GetEditText(ScAddress(1,5,0));
945 2 : CPPUNIT_ASSERT_MESSAGE("Incorrect B6 value after save and reload.", aCheckFunc.checkB6(pEditText));
946 2 : pEditText = rDoc4.GetEditText(ScAddress(1,6,0));
947 2 : CPPUNIT_ASSERT_MESSAGE("Incorrect B7 value after save and reload.", aCheckFunc.checkB7(pEditText));
948 2 : pEditText = rDoc4.GetEditText(ScAddress(1,7,0));
949 2 : CPPUNIT_ASSERT_MESSAGE("Incorrect B8 value after save and reload.", aCheckFunc.checkB8(pEditText));
950 :
951 4 : xNewDocSh3->DoClose();
952 2 : }
953 :
954 2 : void ScExportTest::testFormulaRefSheetNameODS()
955 : {
956 2 : ScDocShellRef xDocSh = loadDoc("formula-quote-in-sheet-name.", ODS, true);
957 : {
958 2 : ScDocument& rDoc = xDocSh->GetDocument();
959 :
960 2 : sc::AutoCalcSwitch aACSwitch(rDoc, true); // turn on auto calc.
961 2 : rDoc.SetString(ScAddress(1,1,0), "='90''s Data'.B2");
962 2 : CPPUNIT_ASSERT_EQUAL(1.1, rDoc.GetValue(ScAddress(1,1,0)));
963 2 : if (!checkFormula(rDoc, ScAddress(1,1,0), "'90''s Data'.B2"))
964 0 : CPPUNIT_FAIL("Wrong formula");
965 : }
966 : // Now, save and reload this document.
967 4 : ScDocShellRef xNewDocSh = saveAndReload(xDocSh, ODS);
968 2 : xDocSh->DoClose();
969 :
970 2 : ScDocument& rDoc = xNewDocSh->GetDocument();
971 2 : rDoc.CalcAll();
972 2 : CPPUNIT_ASSERT_EQUAL(1.1, rDoc.GetValue(ScAddress(1,1,0)));
973 2 : if (!checkFormula(rDoc, ScAddress(1,1,0), "'90''s Data'.B2"))
974 0 : CPPUNIT_FAIL("Wrong formula");
975 :
976 4 : xNewDocSh->DoClose();
977 2 : }
978 :
979 2 : void ScExportTest::testCellValuesExportODS()
980 : {
981 : // Start with an empty document
982 2 : ScDocShellRef xOrigDocSh = loadDoc("empty.", ODS);
983 : {
984 2 : ScDocument& rDoc = xOrigDocSh->GetDocument();
985 2 : CPPUNIT_ASSERT_MESSAGE("This document should at least have one sheet.", rDoc.GetTableCount() > 0);
986 :
987 : // set a value double
988 2 : rDoc.SetValue(ScAddress(0,0,0), 2.0); // A1
989 :
990 : // set a formula
991 2 : rDoc.SetValue(ScAddress(2,0,0), 3.0); // C1
992 2 : rDoc.SetValue(ScAddress(3,0,0), 3); // D1
993 2 : rDoc.SetString(ScAddress(4,0,0), "=10*C1/4"); // E1
994 2 : rDoc.SetValue(ScAddress(5,0,0), 3.0); // F1
995 2 : rDoc.SetString(ScAddress(7,0,0), "=SUM(C1:F1)"); //H1
996 :
997 : // set a string
998 2 : rDoc.SetString(ScAddress(0,2,0), "a simple line"); //A3
999 :
1000 : // set a digit string
1001 2 : rDoc.SetString(ScAddress(0,4,0), "'12"); //A5
1002 : // set a contiguous value
1003 2 : rDoc.SetValue(ScAddress(0,5,0), 12.0); //A6
1004 : // set acontiguous string
1005 2 : rDoc.SetString(ScAddress(0,6,0), "a string"); //A7
1006 : // set a contiguous formula
1007 2 : rDoc.SetString(ScAddress(0,7,0), "=$A$6"); //A8
1008 : }
1009 : // save and reload
1010 4 : ScDocShellRef xNewDocSh = saveAndReload(xOrigDocSh, ODS);
1011 2 : xOrigDocSh->DoClose();
1012 2 : CPPUNIT_ASSERT(xNewDocSh.Is());
1013 2 : ScDocument& rDoc = xNewDocSh->GetDocument();
1014 2 : CPPUNIT_ASSERT_MESSAGE("Reloaded document should at least have one sheet.", rDoc.GetTableCount() > 0);
1015 :
1016 : // check value
1017 2 : CPPUNIT_ASSERT_EQUAL(2.0, rDoc.GetValue(0,0,0));
1018 2 : CPPUNIT_ASSERT_EQUAL(3.0, rDoc.GetValue(2,0,0));
1019 2 : CPPUNIT_ASSERT_EQUAL(3.0, rDoc.GetValue(3,0,0));
1020 2 : CPPUNIT_ASSERT_EQUAL(7.5, rDoc.GetValue(4,0,0));
1021 2 : CPPUNIT_ASSERT_EQUAL(3.0, rDoc.GetValue(5,0,0));
1022 :
1023 : // check formula
1024 2 : if (!checkFormula(rDoc, ScAddress(4,0,0), "10*C1/4"))
1025 0 : CPPUNIT_FAIL("Wrong formula =10*C1/4");
1026 2 : if (!checkFormula(rDoc, ScAddress(7,0,0), "SUM(C1:F1)"))
1027 0 : CPPUNIT_FAIL("Wrong formula =SUM(C1:F1)");
1028 2 : CPPUNIT_ASSERT_EQUAL(16.5, rDoc.GetValue(7,0,0));
1029 :
1030 : // check string
1031 4 : ScRefCellValue aCell;
1032 2 : aCell.assign(rDoc, ScAddress(0,2,0));
1033 2 : CPPUNIT_ASSERT_EQUAL( CELLTYPE_STRING, aCell.meType );
1034 :
1035 : // check for an empty cell
1036 2 : aCell.assign(rDoc, ScAddress(0,3,0));
1037 2 : CPPUNIT_ASSERT_EQUAL( CELLTYPE_NONE, aCell.meType);
1038 :
1039 : // check a digit string
1040 2 : aCell.assign(rDoc, ScAddress(0,4,0));
1041 2 : CPPUNIT_ASSERT_EQUAL( CELLTYPE_STRING, aCell.meType);
1042 :
1043 : //check contiguous values
1044 2 : CPPUNIT_ASSERT_EQUAL( 12.0, rDoc.GetValue(0,5,0) );
1045 2 : CPPUNIT_ASSERT_EQUAL( OUString("a string"), rDoc.GetString(0,6,0) );
1046 2 : if (!checkFormula(rDoc, ScAddress(0,7,0), "$A$6"))
1047 0 : CPPUNIT_FAIL("Wrong formula =$A$6");
1048 2 : CPPUNIT_ASSERT_EQUAL( rDoc.GetValue(0,5,0), rDoc.GetValue(0,7,0) );
1049 :
1050 4 : xNewDocSh->DoClose();
1051 2 : }
1052 :
1053 2 : void ScExportTest::testCellNoteExportODS()
1054 : {
1055 2 : ScDocShellRef xOrigDocSh = loadDoc("single-note.", ODS);
1056 2 : ScAddress aPos(0,0,0); // Start with A1.
1057 : {
1058 2 : ScDocument& rDoc = xOrigDocSh->GetDocument();
1059 :
1060 2 : CPPUNIT_ASSERT_MESSAGE("There should be a note at A1.", rDoc.HasNote(aPos));
1061 :
1062 2 : aPos.IncRow(); // Move to A2.
1063 2 : ScPostIt* pNote = rDoc.GetOrCreateNote(aPos);
1064 2 : pNote->SetText(aPos, "Note One");
1065 2 : pNote->SetAuthor("Author One");
1066 2 : CPPUNIT_ASSERT_MESSAGE("There should be a note at A2.", rDoc.HasNote(aPos));
1067 : }
1068 : // save and reload
1069 4 : ScDocShellRef xNewDocSh = saveAndReload(xOrigDocSh, ODS);
1070 2 : xOrigDocSh->DoClose();
1071 2 : CPPUNIT_ASSERT(xNewDocSh.Is());
1072 2 : ScDocument& rDoc = xNewDocSh->GetDocument();
1073 :
1074 2 : aPos.SetRow(0); // Move back to A1.
1075 2 : CPPUNIT_ASSERT_MESSAGE("There should be a note at A1.", rDoc.HasNote(aPos));
1076 2 : aPos.IncRow(); // Move to A2.
1077 2 : CPPUNIT_ASSERT_MESSAGE("There should be a note at A2.", rDoc.HasNote(aPos));
1078 :
1079 4 : xNewDocSh->DoClose();
1080 2 : }
1081 :
1082 2 : void ScExportTest::testCellNoteExportXLS()
1083 : {
1084 : // Start with an empty document.s
1085 2 : ScDocShellRef xOrigDocSh = loadDoc("notes-on-3-sheets.", ODS);
1086 : {
1087 2 : ScDocument& rDoc = xOrigDocSh->GetDocument();
1088 2 : CPPUNIT_ASSERT_MESSAGE("This document should have 3 sheets.", rDoc.GetTableCount() == 3);
1089 :
1090 : // Check note's presence.
1091 2 : CPPUNIT_ASSERT( rDoc.HasNote(ScAddress(0,0,0)));
1092 2 : CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0,1,0)));
1093 2 : CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0,2,0)));
1094 :
1095 2 : CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0,0,1)));
1096 2 : CPPUNIT_ASSERT( rDoc.HasNote(ScAddress(0,1,1)));
1097 2 : CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0,2,1)));
1098 :
1099 2 : CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0,0,2)));
1100 2 : CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0,1,2)));
1101 2 : CPPUNIT_ASSERT( rDoc.HasNote(ScAddress(0,2,2)));
1102 : }
1103 : // save and reload as XLS.
1104 4 : ScDocShellRef xNewDocSh = saveAndReload(xOrigDocSh, XLS);
1105 : {
1106 2 : xOrigDocSh->DoClose();
1107 2 : CPPUNIT_ASSERT(xNewDocSh.Is());
1108 2 : ScDocument& rDoc = xNewDocSh->GetDocument();
1109 2 : CPPUNIT_ASSERT_MESSAGE("This document should have 3 sheets.", rDoc.GetTableCount() == 3);
1110 :
1111 : // Check note's presence again.
1112 2 : CPPUNIT_ASSERT( rDoc.HasNote(ScAddress(0,0,0)));
1113 2 : CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0,1,0)));
1114 2 : CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0,2,0)));
1115 :
1116 2 : CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0,0,1)));
1117 2 : CPPUNIT_ASSERT( rDoc.HasNote(ScAddress(0,1,1)));
1118 2 : CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0,2,1)));
1119 :
1120 2 : CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0,0,2)));
1121 2 : CPPUNIT_ASSERT(!rDoc.HasNote(ScAddress(0,1,2)));
1122 2 : CPPUNIT_ASSERT( rDoc.HasNote(ScAddress(0,2,2)));
1123 :
1124 2 : xNewDocSh->DoClose();
1125 2 : }
1126 2 : }
1127 :
1128 : namespace {
1129 :
1130 6 : void checkMatrixRange(ScDocument& rDoc, const ScRange& rRange)
1131 : {
1132 6 : ScRange aMatRange;
1133 6 : ScAddress aMatOrigin;
1134 20 : for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
1135 : {
1136 46 : for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
1137 : {
1138 32 : ScAddress aPos(nCol, nRow, rRange.aStart.Tab());
1139 32 : bool bIsMatrix = rDoc.GetMatrixFormulaRange(aPos, aMatRange);
1140 32 : CPPUNIT_ASSERT_MESSAGE("Matrix expected, but not found.", bIsMatrix);
1141 32 : CPPUNIT_ASSERT_MESSAGE("Wrong matrix range.", rRange == aMatRange);
1142 32 : const ScFormulaCell* pCell = rDoc.GetFormulaCell(aPos);
1143 32 : CPPUNIT_ASSERT_MESSAGE("This must be a formula cell.", pCell);
1144 :
1145 32 : bIsMatrix = pCell->GetMatrixOrigin(aMatOrigin);
1146 32 : CPPUNIT_ASSERT_MESSAGE("Not a part of matrix formula.", bIsMatrix);
1147 32 : CPPUNIT_ASSERT_MESSAGE("Wrong matrix origin.", aMatOrigin == aMatRange.aStart);
1148 : }
1149 : }
1150 6 : }
1151 :
1152 : }
1153 :
1154 2 : void ScExportTest::testInlineArrayXLS()
1155 : {
1156 2 : ScDocShellRef xShell = loadDoc("inline-array.", XLS);
1157 2 : CPPUNIT_ASSERT(xShell.Is());
1158 :
1159 4 : ScDocShellRef xDocSh = saveAndReload(xShell, XLS);
1160 2 : xShell->DoClose();
1161 2 : CPPUNIT_ASSERT(xDocSh.Is());
1162 :
1163 2 : ScDocument& rDoc = xDocSh->GetDocument();
1164 :
1165 : // B2:C3 contains a matrix.
1166 2 : checkMatrixRange(rDoc, ScRange(1,1,0,2,2,0));
1167 :
1168 : // B5:D6 contains a matrix.
1169 2 : checkMatrixRange(rDoc, ScRange(1,4,0,3,5,0));
1170 :
1171 : // B8:C10 as well.
1172 2 : checkMatrixRange(rDoc, ScRange(1,7,0,2,9,0));
1173 :
1174 4 : xDocSh->DoClose();
1175 2 : }
1176 :
1177 2 : void ScExportTest::testEmbeddedChartXLS()
1178 : {
1179 2 : ScDocShellRef xShell = loadDoc("embedded-chart.", XLS);
1180 2 : CPPUNIT_ASSERT(xShell.Is());
1181 :
1182 4 : ScDocShellRef xDocSh = saveAndReload(xShell, XLS);
1183 2 : xShell->DoClose();
1184 2 : CPPUNIT_ASSERT(xDocSh.Is());
1185 :
1186 2 : ScDocument& rDoc = xDocSh->GetDocument();
1187 :
1188 : // Make sure the 2nd sheet is named 'Chart1'.
1189 4 : OUString aName;
1190 2 : rDoc.GetName(1, aName);
1191 2 : CPPUNIT_ASSERT_EQUAL(OUString("Chart1"), aName);
1192 :
1193 2 : const SdrOle2Obj* pOleObj = getSingleChartObject(rDoc, 1);
1194 2 : CPPUNIT_ASSERT_MESSAGE("Failed to retrieve a chart object from the 2nd sheet.", pOleObj);
1195 :
1196 4 : ScRangeList aRanges = getChartRanges(rDoc, *pOleObj);
1197 2 : CPPUNIT_ASSERT_MESSAGE("Label range (B3:B5) not found.", aRanges.In(ScRange(1,2,1,1,4,1)));
1198 2 : CPPUNIT_ASSERT_MESSAGE("Data label (C2) not found.", aRanges.In(ScAddress(2,1,1)));
1199 2 : CPPUNIT_ASSERT_MESSAGE("Data range (C3:C5) not found.", aRanges.In(ScRange(2,2,1,2,4,1)));
1200 :
1201 4 : xDocSh->DoClose();
1202 2 : }
1203 :
1204 2 : void ScExportTest::testFormulaReferenceXLS()
1205 : {
1206 2 : ScDocShellRef xShell = loadDoc("formula-reference.", XLS);
1207 2 : CPPUNIT_ASSERT(xShell.Is());
1208 :
1209 4 : ScDocShellRef xDocSh = saveAndReload(xShell, XLS);
1210 2 : xShell->DoClose();
1211 2 : CPPUNIT_ASSERT(xDocSh.Is());
1212 :
1213 2 : ScDocument& rDoc = xDocSh->GetDocument();
1214 :
1215 2 : if (!checkFormula(rDoc, ScAddress(3,1,0), "$A$2+$B$2+$C$2"))
1216 0 : CPPUNIT_FAIL("Wrong formula in D2");
1217 :
1218 2 : if (!checkFormula(rDoc, ScAddress(3,2,0), "A3+B3+C3"))
1219 0 : CPPUNIT_FAIL("Wrong formula in D3");
1220 :
1221 2 : if (!checkFormula(rDoc, ScAddress(3,5,0), "SUM($A$6:$C$6)"))
1222 0 : CPPUNIT_FAIL("Wrong formula in D6");
1223 :
1224 2 : if (!checkFormula(rDoc, ScAddress(3,6,0), "SUM(A7:C7)"))
1225 0 : CPPUNIT_FAIL("Wrong formula in D7");
1226 :
1227 2 : if (!checkFormula(rDoc, ScAddress(3,9,0), "$Two.$A$2+$Two.$B$2+$Two.$C$2"))
1228 0 : CPPUNIT_FAIL("Wrong formula in D10");
1229 :
1230 2 : if (!checkFormula(rDoc, ScAddress(3,10,0), "$Two.A3+$Two.B3+$Two.C3"))
1231 0 : CPPUNIT_FAIL("Wrong formula in D11");
1232 :
1233 2 : if (!checkFormula(rDoc, ScAddress(3,13,0), "MIN($Two.$A$2:$C$2)"))
1234 0 : CPPUNIT_FAIL("Wrong formula in D14");
1235 :
1236 2 : if (!checkFormula(rDoc, ScAddress(3,14,0), "MAX($Two.A3:C3)"))
1237 0 : CPPUNIT_FAIL("Wrong formula in D15");
1238 :
1239 4 : xDocSh->DoClose();
1240 2 : }
1241 :
1242 2 : void ScExportTest::testSheetProtectionXLSX()
1243 : {
1244 2 : ScDocShellRef xShell = loadDoc("ProtecteSheet1234Pass.", XLSX);
1245 2 : CPPUNIT_ASSERT(xShell.Is());
1246 :
1247 4 : ScDocShellRef xDocSh = saveAndReload(xShell, XLSX);
1248 2 : CPPUNIT_ASSERT(xDocSh.Is());
1249 :
1250 2 : ScDocument& rDoc = xDocSh->GetDocument();
1251 2 : const ScTableProtection* pTabProtect = rDoc.GetTabProtection(0);
1252 2 : CPPUNIT_ASSERT(pTabProtect);
1253 2 : if ( pTabProtect )
1254 : {
1255 2 : Sequence<sal_Int8> aHash = pTabProtect->getPasswordHash(PASSHASH_XL);
1256 : // check has
1257 2 : if (aHash.getLength() >= 2)
1258 : {
1259 2 : CPPUNIT_ASSERT( (sal_uInt8)aHash[0] == 204 );
1260 2 : CPPUNIT_ASSERT( (sal_uInt8)aHash[1] == 61 );
1261 : }
1262 : // we could flesh out this check I guess
1263 2 : CPPUNIT_ASSERT ( !pTabProtect->isOptionEnabled( ScTableProtection::OBJECTS ) );
1264 2 : CPPUNIT_ASSERT ( !pTabProtect->isOptionEnabled( ScTableProtection::SCENARIOS ) );
1265 : }
1266 4 : xDocSh->DoClose();
1267 2 : }
1268 :
1269 : namespace {
1270 :
1271 192 : const char* toBorderName( sal_Int16 eStyle )
1272 : {
1273 192 : switch (eStyle)
1274 : {
1275 64 : case table::BorderLineStyle::SOLID: return "SOLID";
1276 16 : case table::BorderLineStyle::DOTTED: return "DOTTED";
1277 16 : case table::BorderLineStyle::DASHED: return "DASHED";
1278 32 : case table::BorderLineStyle::DASH_DOT: return "DASH_DOT";
1279 32 : case table::BorderLineStyle::DASH_DOT_DOT: return "DASH_DOT_DOT";
1280 16 : case table::BorderLineStyle::DOUBLE_THIN: return "DOUBLE_THIN";
1281 16 : case table::BorderLineStyle::FINE_DASHED: return "FINE_DASHED";
1282 : default:
1283 : ;
1284 : }
1285 :
1286 0 : return "";
1287 : }
1288 :
1289 : }
1290 :
1291 4 : void ScExportTest::testExcelCellBorders( sal_uLong nFormatType )
1292 : {
1293 : struct
1294 : {
1295 : SCROW mnRow;
1296 : sal_Int16 mnStyle;
1297 : long mnWidth;
1298 : } aChecks[] = {
1299 : { 1, table::BorderLineStyle::SOLID, 1L }, // hair
1300 : { 3, table::BorderLineStyle::DOTTED, 15L }, // dotted
1301 : { 5, table::BorderLineStyle::DASH_DOT_DOT, 15L }, // dash dot dot
1302 : { 7, table::BorderLineStyle::DASH_DOT, 15L }, // dash dot
1303 : { 9, table::BorderLineStyle::FINE_DASHED, 15L }, // dashed
1304 : { 11, table::BorderLineStyle::SOLID, 15L }, // thin
1305 : { 13, table::BorderLineStyle::DASH_DOT_DOT, 35L }, // medium dash dot dot
1306 : { 17, table::BorderLineStyle::DASH_DOT, 35L }, // medium dash dot
1307 : { 19, table::BorderLineStyle::DASHED, 35L }, // medium dashed
1308 : { 21, table::BorderLineStyle::SOLID, 35L }, // medium
1309 : { 23, table::BorderLineStyle::SOLID, 50L }, // thick
1310 : { 25, table::BorderLineStyle::DOUBLE_THIN, -1L }, // double (don't check width)
1311 4 : };
1312 :
1313 4 : ScDocShellRef xDocSh = loadDoc("cell-borders.", nFormatType);
1314 4 : CPPUNIT_ASSERT_MESSAGE("Failed to load file", xDocSh.Is());
1315 : {
1316 4 : ScDocument& rDoc = xDocSh->GetDocument();
1317 :
1318 52 : for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
1319 : {
1320 48 : const editeng::SvxBorderLine* pLine = NULL;
1321 48 : rDoc.GetBorderLines(2, aChecks[i].mnRow, 0, NULL, &pLine, NULL, NULL);
1322 48 : CPPUNIT_ASSERT(pLine);
1323 48 : CPPUNIT_ASSERT_EQUAL(toBorderName(aChecks[i].mnStyle), toBorderName(pLine->GetBorderLineStyle()));
1324 48 : if (aChecks[i].mnWidth >= 0)
1325 44 : CPPUNIT_ASSERT_EQUAL(aChecks[i].mnWidth, pLine->GetWidth());
1326 : }
1327 : }
1328 :
1329 8 : ScDocShellRef xNewDocSh = saveAndReload(xDocSh, nFormatType);
1330 4 : xDocSh->DoClose();
1331 4 : ScDocument& rDoc = xNewDocSh->GetDocument();
1332 52 : for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
1333 : {
1334 48 : const editeng::SvxBorderLine* pLine = NULL;
1335 48 : rDoc.GetBorderLines(2, aChecks[i].mnRow, 0, NULL, &pLine, NULL, NULL);
1336 48 : CPPUNIT_ASSERT(pLine);
1337 48 : CPPUNIT_ASSERT_EQUAL(toBorderName(aChecks[i].mnStyle), toBorderName(pLine->GetBorderLineStyle()));
1338 48 : if (aChecks[i].mnWidth >= 0)
1339 44 : CPPUNIT_ASSERT_EQUAL(aChecks[i].mnWidth, pLine->GetWidth());
1340 : }
1341 :
1342 8 : xNewDocSh->DoClose();
1343 4 : }
1344 :
1345 2 : void ScExportTest::testCellBordersXLS()
1346 : {
1347 2 : testExcelCellBorders(XLS);
1348 2 : }
1349 :
1350 2 : void ScExportTest::testCellBordersXLSX()
1351 : {
1352 2 : testExcelCellBorders(XLSX);
1353 2 : }
1354 :
1355 0 : OUString toString( const ScBigRange& rRange )
1356 : {
1357 0 : OUStringBuffer aBuf;
1358 0 : aBuf.appendAscii("(columns:");
1359 0 : aBuf.append(rRange.aStart.Col());
1360 0 : aBuf.append('-');
1361 0 : aBuf.append(rRange.aEnd.Col());
1362 0 : aBuf.appendAscii(";rows:");
1363 0 : aBuf.append(rRange.aStart.Row());
1364 0 : aBuf.append('-');
1365 0 : aBuf.append(rRange.aEnd.Row());
1366 0 : aBuf.appendAscii(";sheets:");
1367 0 : aBuf.append(rRange.aStart.Tab());
1368 0 : aBuf.append('-');
1369 0 : aBuf.append(rRange.aEnd.Tab());
1370 0 : aBuf.append(')');
1371 :
1372 0 : return aBuf.makeStringAndClear();
1373 : }
1374 :
1375 2 : void ScExportTest::testTrackChangesSimpleXLSX()
1376 : {
1377 : struct CheckItem
1378 : {
1379 : sal_uLong mnActionId;
1380 : ScChangeActionType meType;
1381 :
1382 : sal_Int32 mnStartCol;
1383 : sal_Int32 mnStartRow;
1384 : sal_Int32 mnStartTab;
1385 : sal_Int32 mnEndCol;
1386 : sal_Int32 mnEndRow;
1387 : sal_Int32 mnEndTab;
1388 :
1389 : bool mbRowInsertedAtBottom;
1390 : };
1391 :
1392 : struct
1393 : {
1394 104 : bool checkRange( ScChangeActionType eType, const ScBigRange& rExpected, const ScBigRange& rActual )
1395 : {
1396 104 : ScBigRange aExpected(rExpected), aActual(rActual);
1397 :
1398 104 : switch (eType)
1399 : {
1400 : case SC_CAT_INSERT_ROWS:
1401 : {
1402 : // Ignore columns.
1403 48 : aExpected.aStart.SetCol(0);
1404 48 : aExpected.aEnd.SetCol(0);
1405 48 : aActual.aStart.SetCol(0);
1406 48 : aActual.aEnd.SetCol(0);
1407 : }
1408 48 : break;
1409 : default:
1410 : ;
1411 : }
1412 :
1413 104 : return aExpected == aActual;
1414 : }
1415 :
1416 8 : bool check( ScDocument& rDoc )
1417 : {
1418 : CheckItem aChecks[] =
1419 : {
1420 : { 1, SC_CAT_CONTENT , 1, 1, 0, 1, 1, 0, false },
1421 : { 2, SC_CAT_INSERT_ROWS , 0, 2, 0, 0, 2, 0, true },
1422 : { 3, SC_CAT_CONTENT , 1, 2, 0, 1, 2, 0, false },
1423 : { 4, SC_CAT_INSERT_ROWS , 0, 3, 0, 0, 3, 0, true },
1424 : { 5, SC_CAT_CONTENT , 1, 3, 0, 1, 3, 0, false },
1425 : { 6, SC_CAT_INSERT_ROWS , 0, 4, 0, 0, 4, 0, true },
1426 : { 7, SC_CAT_CONTENT , 1, 4, 0, 1, 4, 0, false },
1427 : { 8, SC_CAT_INSERT_ROWS , 0, 5, 0, 0, 5, 0, true },
1428 : { 9, SC_CAT_CONTENT , 1, 5, 0, 1, 5, 0, false },
1429 : { 10, SC_CAT_INSERT_ROWS , 0, 6, 0, 0, 6, 0, true },
1430 : { 11, SC_CAT_CONTENT , 1, 6, 0, 1, 6, 0, false },
1431 : { 12, SC_CAT_INSERT_ROWS , 0, 7, 0, 0, 7, 0, true },
1432 : { 13, SC_CAT_CONTENT , 1, 7, 0, 1, 7, 0, false },
1433 8 : };
1434 :
1435 8 : ScChangeTrack* pCT = rDoc.GetChangeTrack();
1436 8 : if (!pCT)
1437 : {
1438 0 : cerr << "Change track instance doesn't exist." << endl;
1439 0 : return false;
1440 : }
1441 :
1442 8 : sal_uLong nActionMax = pCT->GetActionMax();
1443 8 : if (nActionMax != 13)
1444 : {
1445 0 : cerr << "Unexpected highest action ID value." << endl;
1446 0 : return false;
1447 : }
1448 :
1449 224 : for (size_t i = 0, n = SAL_N_ELEMENTS(aChecks); i < n; ++i)
1450 : {
1451 104 : sal_uInt16 nActId = aChecks[i].mnActionId;
1452 104 : const ScChangeAction* pAction = pCT->GetAction(nActId);
1453 104 : if (!pAction)
1454 : {
1455 0 : cerr << "No action for action number " << nActId << " found." << endl;
1456 0 : return false;
1457 : }
1458 :
1459 104 : if (pAction->GetType() != aChecks[i].meType)
1460 : {
1461 0 : cerr << "Unexpected action type for action number " << nActId << "." << endl;
1462 0 : return false;
1463 : }
1464 :
1465 104 : const ScBigRange& rRange = pAction->GetBigRange();
1466 : ScBigRange aCheck(aChecks[i].mnStartCol, aChecks[i].mnStartRow, aChecks[i].mnStartTab,
1467 104 : aChecks[i].mnEndCol, aChecks[i].mnEndRow, aChecks[i].mnEndTab);
1468 :
1469 104 : if (!checkRange(pAction->GetType(), aCheck, rRange))
1470 : {
1471 0 : cerr << "Unexpected range for action number " << nActId
1472 0 : << ": expected=" << toString(aCheck) << " actual=" << toString(rRange) << endl;
1473 0 : return false;
1474 : }
1475 :
1476 104 : switch (pAction->GetType())
1477 : {
1478 : case SC_CAT_INSERT_ROWS:
1479 : {
1480 48 : const ScChangeActionIns* p = static_cast<const ScChangeActionIns*>(pAction);
1481 48 : if (p->IsEndOfList() != aChecks[i].mbRowInsertedAtBottom)
1482 : {
1483 0 : cerr << "Unexpected end-of-list flag for action number " << nActId << "." << endl;
1484 0 : return false;
1485 : }
1486 : }
1487 48 : break;
1488 : default:
1489 : ;
1490 : }
1491 : }
1492 :
1493 8 : return true;
1494 : }
1495 :
1496 4 : bool checkRevisionUserAndTime( ScDocument& rDoc, const OUString& rOwnerName )
1497 : {
1498 4 : ScChangeTrack* pCT = rDoc.GetChangeTrack();
1499 4 : if (!pCT)
1500 : {
1501 0 : cerr << "Change track instance doesn't exist." << endl;
1502 0 : return false;
1503 : }
1504 :
1505 4 : ScChangeAction* pAction = pCT->GetLast();
1506 4 : if (pAction->GetUser() != "Kohei Yoshida")
1507 : {
1508 0 : cerr << "Wrong user name." << endl;
1509 0 : return false;
1510 : }
1511 :
1512 4 : DateTime aDT = pAction->GetDateTime();
1513 4 : if (aDT.GetYear() != 2014 || aDT.GetMonth() != 7 || aDT.GetDay() != 11)
1514 : {
1515 0 : cerr << "Wrong time stamp." << endl;
1516 0 : return false;
1517 : }
1518 :
1519 : // Insert a new record to make sure the user and date-time are correct.
1520 4 : rDoc.SetString(ScAddress(1,8,0), "New String");
1521 4 : ScCellValue aEmpty;
1522 4 : pCT->AppendContent(ScAddress(1,8,0), aEmpty);
1523 4 : pAction = pCT->GetLast();
1524 4 : if (!pAction)
1525 : {
1526 0 : cerr << "Failed to retrieve last revision." << endl;
1527 0 : return false;
1528 : }
1529 :
1530 4 : if (rOwnerName != pAction->GetUser())
1531 : {
1532 0 : cerr << "Wrong user name." << endl;
1533 0 : return false;
1534 : }
1535 :
1536 4 : DateTime aDTNew = pAction->GetDateTime();
1537 4 : if (aDTNew <= aDT)
1538 : {
1539 0 : cerr << "Time stamp of the new revision should be more recent than that of the last revision." << endl;
1540 0 : return false;
1541 : }
1542 :
1543 4 : return true;
1544 : }
1545 :
1546 : } aTest;
1547 :
1548 2 : SvtUserOptions& rUserOpt = SC_MOD()->GetUserOptions();
1549 2 : rUserOpt.SetToken(USER_OPT_FIRSTNAME, "Export");
1550 2 : rUserOpt.SetToken(USER_OPT_LASTNAME, "Test");
1551 :
1552 2 : OUString aOwnerName = rUserOpt.GetFirstName() + " " + rUserOpt.GetLastName();
1553 :
1554 : // First, test the xls variant.
1555 :
1556 4 : ScDocShellRef xDocSh = loadDoc("track-changes/simple-cell-changes.", XLS);
1557 2 : CPPUNIT_ASSERT(xDocSh.Is());
1558 2 : ScDocument* pDoc = &xDocSh->GetDocument();
1559 2 : bool bGood = aTest.check(*pDoc);
1560 2 : CPPUNIT_ASSERT_MESSAGE("Initial check failed (xls).", bGood);
1561 :
1562 4 : ScDocShellRef xDocSh2 = saveAndReload(xDocSh, XLS);
1563 2 : xDocSh->DoClose();
1564 2 : pDoc = &xDocSh2->GetDocument();
1565 2 : bGood = aTest.check(*pDoc);
1566 2 : CPPUNIT_ASSERT_MESSAGE("Check after reload failed (xls).", bGood);
1567 :
1568 : // fdo#81445 : Check the blank value string to make sure it's "<empty>".
1569 2 : ScChangeTrack* pCT = pDoc->GetChangeTrack();
1570 2 : CPPUNIT_ASSERT(pCT);
1571 2 : ScChangeAction* pAction = pCT->GetAction(1);
1572 2 : CPPUNIT_ASSERT(pAction);
1573 4 : OUString aDesc;
1574 2 : pAction->GetDescription(aDesc, pDoc);
1575 2 : CPPUNIT_ASSERT_EQUAL(OUString("Cell B2 changed from '<empty>' to '1'"), aDesc);
1576 :
1577 2 : bGood = aTest.checkRevisionUserAndTime(*pDoc, aOwnerName);
1578 2 : CPPUNIT_ASSERT_MESSAGE("Check revision and time failed after reload (xls).", bGood);
1579 :
1580 2 : xDocSh2->DoClose();
1581 :
1582 : // Now, test the xlsx variant the same way.
1583 :
1584 2 : xDocSh = loadDoc("track-changes/simple-cell-changes.", XLSX);
1585 2 : CPPUNIT_ASSERT(xDocSh.Is());
1586 2 : pDoc = &xDocSh->GetDocument();
1587 2 : aTest.check(*pDoc);
1588 2 : CPPUNIT_ASSERT_MESSAGE("Initial check failed (xlsx).", bGood);
1589 :
1590 2 : xDocSh2 = saveAndReload(xDocSh, XLSX);
1591 2 : xDocSh->DoClose();
1592 2 : pDoc = &xDocSh2->GetDocument();
1593 2 : bGood = aTest.check(*pDoc);
1594 2 : CPPUNIT_ASSERT_MESSAGE("Check after reload failed (xlsx).", bGood);
1595 :
1596 2 : bGood = aTest.checkRevisionUserAndTime(*pDoc, aOwnerName);
1597 2 : CPPUNIT_ASSERT_MESSAGE("Check revision and time failed after reload (xlsx).", bGood);
1598 :
1599 4 : xDocSh2->DoClose();
1600 2 : }
1601 :
1602 2 : void ScExportTest::testSheetTabColorsXLSX()
1603 : {
1604 : struct
1605 : {
1606 4 : bool checkContent( ScDocument& rDoc )
1607 : {
1608 :
1609 4 : std::vector<OUString> aTabNames = rDoc.GetAllTableNames();
1610 :
1611 : // green, red, blue, yellow (from left to right).
1612 4 : if (aTabNames.size() != 4)
1613 : {
1614 0 : cerr << "There should be exactly 4 sheets." << endl;
1615 0 : return false;
1616 : }
1617 :
1618 4 : const char* pNames[] = { "Green", "Red", "Blue", "Yellow" };
1619 20 : for (size_t i = 0, n = SAL_N_ELEMENTS(pNames); i < n; ++i)
1620 : {
1621 16 : OUString aExpected = OUString::createFromAscii(pNames[i]);
1622 16 : if (aExpected != aTabNames[i])
1623 : {
1624 0 : cerr << "incorrect sheet name: expected='" << aExpected <<"', actual='" << aTabNames[i] << "'" << endl;
1625 0 : return false;
1626 : }
1627 16 : }
1628 :
1629 : const ColorData aXclColors[] =
1630 : {
1631 : 0x0000B050, // green
1632 : 0x00FF0000, // red
1633 : 0x000070C0, // blue
1634 : 0x00FFFF00, // yellow
1635 4 : };
1636 :
1637 20 : for (size_t i = 0, n = SAL_N_ELEMENTS(aXclColors); i < n; ++i)
1638 : {
1639 16 : if (aXclColors[i] != rDoc.GetTabBgColor(i).GetColor())
1640 : {
1641 0 : cerr << "wrong sheet color for sheet " << i << endl;
1642 0 : return false;
1643 : }
1644 : }
1645 :
1646 4 : return true;
1647 : }
1648 :
1649 : } aTest;
1650 :
1651 2 : ScDocShellRef xDocSh = loadDoc("sheet-tab-color.", XLSX);
1652 : {
1653 2 : CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocSh.Is());
1654 2 : ScDocument& rDoc = xDocSh->GetDocument();
1655 2 : bool bRes = aTest.checkContent(rDoc);
1656 2 : CPPUNIT_ASSERT_MESSAGE("Failed on the initial content check.", bRes);
1657 : }
1658 :
1659 4 : ScDocShellRef xDocSh2 = saveAndReload(xDocSh, XLSX);
1660 2 : CPPUNIT_ASSERT_MESSAGE("Failed to reload file.", xDocSh2.Is());
1661 2 : xDocSh->DoClose();
1662 2 : ScDocument& rDoc = xDocSh2->GetDocument();
1663 2 : bool bRes = aTest.checkContent(rDoc);
1664 2 : CPPUNIT_ASSERT_MESSAGE("Failed on the content check after reload.", bRes);
1665 :
1666 4 : xDocSh2->DoClose();
1667 2 : }
1668 :
1669 2 : void ScExportTest::testSharedFormulaExportXLS()
1670 : {
1671 : struct
1672 : {
1673 4 : bool checkContent( ScDocument& rDoc )
1674 : {
1675 4 : formula::FormulaGrammar::Grammar eGram = formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1;
1676 4 : rDoc.SetGrammar(eGram);
1677 4 : sc::TokenStringContext aCxt(&rDoc, eGram);
1678 :
1679 : // Check the title row.
1680 :
1681 8 : OUString aActual = rDoc.GetString(0,1,0);
1682 8 : OUString aExpected = "Response";
1683 4 : if (aActual != aExpected)
1684 : {
1685 0 : cerr << "Wrong content in A2: expected='" << aExpected << "', actual='" << aActual << "'" << endl;
1686 0 : return false;
1687 : }
1688 :
1689 4 : aActual = rDoc.GetString(1,1,0);
1690 4 : aExpected = "Response";
1691 4 : if (aActual != aExpected)
1692 : {
1693 0 : cerr << "Wrong content in B2: expected='" << aExpected << "', actual='" << aActual << "'" << endl;
1694 0 : return false;
1695 : }
1696 :
1697 : // A3:A12 and B3:B12 are numbers from 1 to 10.
1698 88 : for (SCROW i = 0; i <= 9; ++i)
1699 : {
1700 40 : double fExpected = i + 1.0;
1701 40 : ScAddress aPos(0,i+2,0);
1702 40 : double fActual = rDoc.GetValue(aPos);
1703 40 : if (fExpected != fActual)
1704 : {
1705 0 : cerr << "Wrong value in A" << (i+2) << ": expected=" << fExpected << ", actual=" << fActual << endl;
1706 0 : return false;
1707 : }
1708 :
1709 40 : aPos.IncCol();
1710 40 : ScFormulaCell* pFC = rDoc.GetFormulaCell(aPos);
1711 40 : if (!pFC)
1712 : {
1713 0 : cerr << "B" << (i+2) << " should be a formula cell." << endl;
1714 0 : return false;
1715 : }
1716 :
1717 40 : OUString aFormula = pFC->GetCode()->CreateString(aCxt, aPos);
1718 40 : aExpected = "Coefficients!RC[-1]";
1719 40 : if (aFormula != aExpected)
1720 : {
1721 0 : cerr << "Wrong formula in B" << (i+2) << ": expected='" << aExpected << "', actual='" << aFormula << "'" << endl;
1722 0 : return false;
1723 : }
1724 :
1725 40 : fActual = rDoc.GetValue(aPos);
1726 40 : if (fExpected != fActual)
1727 : {
1728 0 : cerr << "Wrong value in B" << (i+2) << ": expected=" << fExpected << ", actual=" << fActual << endl;
1729 0 : return false;
1730 : }
1731 40 : }
1732 :
1733 8 : return true;
1734 : }
1735 :
1736 : } aTest;
1737 :
1738 2 : ScDocShellRef xDocSh = loadDoc("shared-formula/3d-reference.", ODS);
1739 : {
1740 2 : CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocSh.Is());
1741 2 : ScDocument& rDoc = xDocSh->GetDocument();
1742 :
1743 : // Check the content of the original.
1744 2 : bool bRes = aTest.checkContent(rDoc);
1745 2 : CPPUNIT_ASSERT_MESSAGE("Content check on the original document failed.", bRes);
1746 : }
1747 :
1748 4 : ScDocShellRef xDocSh2 = saveAndReload(xDocSh, XLS);
1749 2 : xDocSh->DoClose();
1750 2 : CPPUNIT_ASSERT_MESSAGE("Failed to reload file.", xDocSh2.Is());
1751 :
1752 2 : ScDocument& rDoc = xDocSh2->GetDocument();
1753 :
1754 : // Check the content of the reloaded. This should be identical.
1755 2 : bool bRes = aTest.checkContent(rDoc);
1756 2 : CPPUNIT_ASSERT_MESSAGE("Content check on the reloaded document failed.", bRes);
1757 :
1758 4 : xDocSh2->DoClose();
1759 2 : }
1760 :
1761 2 : void ScExportTest::testSharedFormulaExportXLSX()
1762 : {
1763 : struct
1764 : {
1765 6 : bool checkContent( ScDocument& rDoc )
1766 : {
1767 6 : SCTAB nTabCount = rDoc.GetTableCount();
1768 6 : if (nTabCount != 2)
1769 : {
1770 0 : cerr << "Document should have exactly 2 sheets. " << nTabCount << " found." << endl;
1771 0 : return false;
1772 : }
1773 :
1774 : // Make sure the sheet tab colors are not set.
1775 18 : for (SCROW i = 0; i <= 1; ++i)
1776 : {
1777 12 : Color aTabBgColor = rDoc.GetTabBgColor(i);
1778 12 : if (aTabBgColor != Color(COL_AUTO))
1779 : {
1780 0 : cerr << "The tab color of Sheet " << (i+1) << " should not be explicitly set." << endl;
1781 0 : return false;
1782 : }
1783 : }
1784 :
1785 : // B2:B7 should show 1,2,3,4,5,6.
1786 6 : double fExpected = 1.0;
1787 42 : for (SCROW i = 1; i <= 6; ++i, ++fExpected)
1788 : {
1789 36 : ScAddress aPos(1,i,0);
1790 36 : double fVal = rDoc.GetValue(aPos);
1791 36 : if (fVal != fExpected)
1792 : {
1793 0 : cerr << "Wrong value in B" << (i+1) << ": expected=" << fExpected << ", actual=" << fVal << endl;
1794 0 : return false;
1795 : }
1796 : }
1797 :
1798 : // C2:C7 should show 10,20,....,60.
1799 6 : fExpected = 10.0;
1800 42 : for (SCROW i = 1; i <= 6; ++i, fExpected+=10.0)
1801 : {
1802 36 : ScAddress aPos(2,i,0);
1803 36 : double fVal = rDoc.GetValue(aPos);
1804 36 : if (fVal != fExpected)
1805 : {
1806 0 : cerr << "Wrong value in C" << (i+1) << ": expected=" << fExpected << ", actual=" << fVal << endl;
1807 0 : return false;
1808 : }
1809 : }
1810 :
1811 : // D2:D7 should show 1,2,...,6.
1812 6 : fExpected = 1.0;
1813 42 : for (SCROW i = 1; i <= 6; ++i, ++fExpected)
1814 : {
1815 36 : ScAddress aPos(3,i,0);
1816 36 : double fVal = rDoc.GetValue(aPos);
1817 36 : if (fVal != fExpected)
1818 : {
1819 0 : cerr << "Wrong value in D" << (i+1) << ": expected=" << fExpected << ", actual=" << fVal << endl;
1820 0 : return false;
1821 : }
1822 : }
1823 :
1824 6 : return true;
1825 : }
1826 :
1827 : } aTest;
1828 :
1829 2 : ScDocShellRef xDocSh = loadDoc("shared-formula/3d-reference.", XLSX);
1830 : {
1831 2 : CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocSh.Is());
1832 2 : ScDocument& rDoc = xDocSh->GetDocument();
1833 :
1834 2 : bool bRes = aTest.checkContent(rDoc);
1835 2 : CPPUNIT_ASSERT_MESSAGE("Content check on the initial document failed.", bRes);
1836 :
1837 2 : rDoc.CalcAll(); // Recalculate to flush all cached results.
1838 2 : bRes = aTest.checkContent(rDoc);
1839 2 : CPPUNIT_ASSERT_MESSAGE("Content check on the initial recalculated document failed.", bRes);
1840 : }
1841 :
1842 : // Save and reload, and check the content again.
1843 4 : ScDocShellRef xDocSh2 = saveAndReload(xDocSh, XLSX);
1844 2 : xDocSh->DoClose();
1845 :
1846 2 : CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocSh2.Is());
1847 2 : ScDocument& rDoc = xDocSh2->GetDocument();
1848 2 : rDoc.CalcAll(); // Recalculate to flush all cached results.
1849 :
1850 2 : bool bRes = aTest.checkContent(rDoc);
1851 2 : CPPUNIT_ASSERT_MESSAGE("Content check on the reloaded document failed.", bRes);
1852 :
1853 4 : xDocSh2->DoClose();
1854 2 : }
1855 :
1856 2 : void ScExportTest::testSharedFormulaStringResultExportXLSX()
1857 : {
1858 : struct
1859 : {
1860 6 : bool checkContent( ScDocument& rDoc )
1861 : {
1862 : {
1863 : // B2:B7 should show A,B,....,F.
1864 6 : const char* expected[] = { "A", "B", "C", "D", "E", "F" };
1865 42 : for (SCROW i = 0; i <= 5; ++i)
1866 : {
1867 36 : ScAddress aPos(1,i+1,0);
1868 36 : OUString aStr = rDoc.GetString(aPos);
1869 72 : OUString aExpected = OUString::createFromAscii(expected[i]);
1870 36 : if (aStr != aExpected)
1871 : {
1872 0 : cerr << "Wrong value in B" << (i+2) << ": expected='" << aExpected << "', actual='" << aStr << "'" << endl;
1873 0 : return false;
1874 : }
1875 36 : }
1876 : }
1877 :
1878 : {
1879 : // C2:C7 should show AA,BB,....,FF.
1880 6 : const char* expected[] = { "AA", "BB", "CC", "DD", "EE", "FF" };
1881 42 : for (SCROW i = 0; i <= 5; ++i)
1882 : {
1883 36 : ScAddress aPos(2,i+1,0);
1884 36 : OUString aStr = rDoc.GetString(aPos);
1885 72 : OUString aExpected = OUString::createFromAscii(expected[i]);
1886 36 : if (aStr != aExpected)
1887 : {
1888 0 : cerr << "Wrong value in C" << (i+2) << ": expected='" << aExpected << "', actual='" << aStr << "'" << endl;
1889 0 : return false;
1890 : }
1891 36 : }
1892 : }
1893 :
1894 6 : return true;
1895 : }
1896 :
1897 : } aTest;
1898 :
1899 2 : ScDocShellRef xDocSh = loadDoc("shared-formula/text-results.", XLSX);
1900 : {
1901 2 : CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocSh.Is());
1902 2 : ScDocument& rDoc = xDocSh->GetDocument();
1903 :
1904 : // Check content without re-calculation, to test cached formula results.
1905 2 : bool bRes = aTest.checkContent(rDoc);
1906 2 : CPPUNIT_ASSERT_MESSAGE("Content check on the initial document failed.", bRes);
1907 :
1908 : // Now, re-calculate and check the results.
1909 2 : rDoc.CalcAll();
1910 2 : bRes = aTest.checkContent(rDoc);
1911 2 : CPPUNIT_ASSERT_MESSAGE("Content check on the initial recalculated document failed.", bRes);
1912 : }
1913 : // Reload and check again.
1914 4 : ScDocShellRef xDocSh2 = saveAndReload(xDocSh, XLSX);
1915 2 : xDocSh->DoClose();
1916 2 : CPPUNIT_ASSERT_MESSAGE("Failed to re-load file.", xDocSh2.Is());
1917 2 : ScDocument& rDoc = xDocSh2->GetDocument();
1918 :
1919 2 : bool bRes = aTest.checkContent(rDoc);
1920 2 : CPPUNIT_ASSERT_MESSAGE("Content check on the reloaded document failed.", bRes);
1921 :
1922 4 : xDocSh2->DoClose();
1923 2 : }
1924 :
1925 4 : void ScExportTest::testFunctionsExcel2010( sal_uLong nFormatType )
1926 : {
1927 4 : ScDocShellRef xShell = loadDoc("functions-excel-2010.", XLSX);
1928 4 : CPPUNIT_ASSERT_MESSAGE("Failed to load the document.", xShell.Is());
1929 :
1930 8 : ScDocShellRef xDocSh = saveAndReload(xShell, nFormatType);
1931 4 : ScDocument& rDoc = xDocSh->GetDocument();
1932 4 : rDoc.CalcAll(); // perform hard re-calculation.
1933 :
1934 4 : testFunctionsExcel2010_Impl(rDoc);
1935 :
1936 8 : xDocSh->DoClose();
1937 4 : }
1938 :
1939 2 : void ScExportTest::testFunctionsExcel2010XLSX()
1940 : {
1941 2 : testFunctionsExcel2010(XLSX);
1942 2 : }
1943 :
1944 2 : void ScExportTest::testFunctionsExcel2010XLS()
1945 : {
1946 2 : testFunctionsExcel2010(XLS);
1947 2 : }
1948 :
1949 2 : void ScExportTest::testRelativePaths()
1950 : {
1951 2 : ScDocShellRef xDocSh = loadDoc("fdo79305.", ODS);
1952 2 : CPPUNIT_ASSERT(xDocSh.Is());
1953 :
1954 2 : xmlDocPtr pDoc = XPathHelper::parseExport(&(*xDocSh), m_xSFactory, "content.xml", ODS);
1955 2 : CPPUNIT_ASSERT(pDoc);
1956 : OUString aURL = getXPath(pDoc,
1957 4 : "/office:document-content/office:body/office:spreadsheet/table:table/table:table-row[2]/table:table-cell[2]/text:p/text:a", "href");
1958 : // make sure that the URL is relative
1959 4 : CPPUNIT_ASSERT(aURL.startsWith(".."));
1960 2 : }
1961 :
1962 : namespace {
1963 :
1964 4 : void testSheetProtection_Impl(ScDocument& rDoc)
1965 : {
1966 4 : CPPUNIT_ASSERT(rDoc.IsTabProtected(0));
1967 4 : ScTableProtection* pTabProtection = rDoc.GetTabProtection(0);
1968 4 : CPPUNIT_ASSERT(pTabProtection);
1969 4 : CPPUNIT_ASSERT(pTabProtection->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS));
1970 4 : CPPUNIT_ASSERT(!pTabProtection->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS));
1971 4 : }
1972 :
1973 : }
1974 :
1975 2 : void ScExportTest::testSheetProtection()
1976 : {
1977 2 : ScDocShellRef xDocSh = loadDoc("sheet-protection.", ODS);
1978 2 : CPPUNIT_ASSERT(xDocSh.Is());
1979 :
1980 : {
1981 2 : ScDocument& rDoc = xDocSh->GetDocument();
1982 2 : testSheetProtection_Impl(rDoc);
1983 : }
1984 :
1985 4 : ScDocShellRef xDocSh2 = saveAndReload(xDocSh, ODS);
1986 : {
1987 2 : ScDocument& rDoc = xDocSh2->GetDocument();
1988 2 : testSheetProtection_Impl(rDoc);
1989 : }
1990 :
1991 4 : xDocSh2->DoClose();
1992 2 : }
1993 :
1994 2 : void ScExportTest::testPivotTableXLSX()
1995 : {
1996 : struct
1997 : {
1998 4 : bool check( const ScDocument& rDoc )
1999 : {
2000 4 : if (!rDoc.HasPivotTable())
2001 : {
2002 0 : cerr << "The document should have pivot table." << endl;
2003 0 : return false;
2004 : }
2005 :
2006 4 : const ScDPCollection* pDPs = rDoc.GetDPCollection();
2007 4 : if (!pDPs)
2008 : {
2009 0 : cerr << "Pivot table container should exist." << endl;
2010 0 : return false;
2011 : }
2012 :
2013 4 : ScRange aSrcRange(0,0,0,9,2,0); // A1:J3 on Sheet1.
2014 4 : const ScDPCache* pCache = pDPs->GetSheetCaches().getExistingCache(aSrcRange);
2015 4 : if (!pCache)
2016 : {
2017 0 : cerr << "The document should have a pivot cache for A1:J3 on Sheet1." << endl;
2018 0 : return false;
2019 : }
2020 :
2021 : // Cache should have fields from F1 through F10.
2022 :
2023 : const char* pNames[] = {
2024 : "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10"
2025 4 : };
2026 :
2027 4 : size_t nCount = pCache->GetFieldCount();
2028 4 : if (nCount != SAL_N_ELEMENTS(pNames))
2029 : {
2030 0 : cout << "Incorrect number of fields in pivot cache." << endl;
2031 0 : return false;
2032 : }
2033 :
2034 44 : for (size_t i = 0; i < nCount; ++i)
2035 : {
2036 40 : OUString aCacheName = pCache->GetDimensionName(i);
2037 40 : if (aCacheName != OUString::createFromAscii(pNames[i]))
2038 : {
2039 0 : cerr << "Field " << i << " has label '" << aCacheName << "' but expected '" << pNames[i] << "'" << endl;
2040 0 : return false;
2041 : }
2042 40 : }
2043 :
2044 4 : const ScDPObject* pDPObj = rDoc.GetDPAtCursor(0,10,0); // A11
2045 4 : if (!pDPObj)
2046 : {
2047 0 : cerr << "A pivot table should exist over A11." << endl;
2048 0 : return false;
2049 : }
2050 :
2051 : // Output range should be A8:D15.
2052 4 : ScRange aOutRange = pDPObj->GetOutRange();
2053 4 : if (ScRange(0,7,0,3,14,0) != aOutRange)
2054 : {
2055 0 : cerr << "Incorrect output range." << endl;
2056 0 : return false;
2057 : }
2058 :
2059 : // Row field - F1
2060 : // Column field - F4
2061 : // Page fields - F7 and F6
2062 : // Data field - F10
2063 :
2064 4 : const ScDPSaveData* pSaveData = pDPObj->GetSaveData();
2065 4 : if (!pSaveData)
2066 : {
2067 0 : cerr << "Save data should exist in each pivot table object." << endl;
2068 0 : return false;
2069 : }
2070 :
2071 4 : std::vector<const ScDPSaveDimension*> aDims;
2072 4 : pSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_ROW, aDims);
2073 4 : if (aDims.size() != 1 || aDims[0]->GetName() != "F1")
2074 : {
2075 0 : cerr << "Pivot table should have one row field labeld 'F1'" << endl;
2076 0 : return false;
2077 : }
2078 :
2079 4 : pSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_COLUMN, aDims);
2080 4 : if (aDims.size() != 1 || aDims[0]->GetName() != "F4")
2081 : {
2082 0 : cerr << "Pivot table should have one column field labeld 'F4'" << endl;
2083 0 : return false;
2084 : }
2085 :
2086 4 : pSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_PAGE, aDims);
2087 4 : if (aDims.size() != 2 || aDims[0]->GetName() != "F7" || aDims[1]->GetName() != "F6")
2088 : {
2089 0 : cerr << "Pivot table should have two page fields labeld 'F7' and 'F6' in this order." << endl;
2090 0 : return false;
2091 : }
2092 :
2093 4 : pSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_DATA, aDims);
2094 4 : if (aDims.size() != 1 || aDims[0]->GetName() != "F10")
2095 : {
2096 0 : cerr << "Pivot table should have one data field labeld 'F10'" << endl;
2097 0 : return false;
2098 : }
2099 :
2100 4 : const ScDPSaveDimension* pDim = aDims[0];
2101 4 : if (pDim->GetFunction() != sheet::GeneralFunction_SUM)
2102 : {
2103 0 : cerr << "Data field should have SUM function." << endl;
2104 0 : return false;
2105 : }
2106 :
2107 4 : return true;
2108 : }
2109 :
2110 : } aTest;
2111 :
2112 2 : ScDocShellRef xDocSh = loadDoc("pivot-table/many-fields-in-cache.", XLSX);
2113 2 : CPPUNIT_ASSERT(xDocSh.Is());
2114 2 : ScDocument* pDoc = &xDocSh->GetDocument();
2115 :
2116 : // Initial check.
2117 2 : bool bCheck = aTest.check(*pDoc);
2118 2 : CPPUNIT_ASSERT_MESSAGE("Initial check failed.", bCheck);
2119 :
2120 4 : ScDocShellRef xDocSh2 = saveAndReload(xDocSh, XLSX);
2121 2 : xDocSh->DoClose();
2122 2 : CPPUNIT_ASSERT(xDocSh2.Is());
2123 2 : pDoc = &xDocSh2->GetDocument();
2124 :
2125 : // Reload check.
2126 2 : bCheck = aTest.check(*pDoc);
2127 2 : CPPUNIT_ASSERT_MESSAGE("Reload check failed.", bCheck);
2128 :
2129 4 : xDocSh2->DoClose();
2130 2 : }
2131 :
2132 2 : void ScExportTest::testPivotTableTwoDataFieldsXLSX()
2133 : {
2134 : struct
2135 : {
2136 4 : bool check( const ScDocument& rDoc )
2137 : {
2138 4 : if (!rDoc.HasPivotTable())
2139 : {
2140 0 : cerr << "The document should have pivot table." << endl;
2141 0 : return false;
2142 : }
2143 :
2144 4 : const ScDPCollection* pDPs = rDoc.GetDPCollection();
2145 4 : if (!pDPs)
2146 : {
2147 0 : cerr << "Pivot table container should exist." << endl;
2148 0 : return false;
2149 : }
2150 :
2151 4 : ScRange aSrcRange(1,1,1,2,8,1); // B2:C9 on the 2nd sheet.
2152 4 : const ScDPCache* pCache = pDPs->GetSheetCaches().getExistingCache(aSrcRange);
2153 4 : if (!pCache)
2154 : {
2155 0 : cerr << "The document should have a pivot cache for B2:C9 on 'Src'." << endl;
2156 0 : return false;
2157 : }
2158 :
2159 4 : const char* pNames[] = { "Name", "Value" };
2160 : (void) pNames;
2161 :
2162 4 : size_t nCount = pCache->GetFieldCount();
2163 4 : if (nCount != SAL_N_ELEMENTS(pNames))
2164 : {
2165 0 : cout << "Incorrect number of fields in pivot cache." << endl;
2166 0 : return false;
2167 : }
2168 :
2169 4 : const ScDPObject* pDPObj = rDoc.GetDPAtCursor(0,2,0); // A3
2170 4 : if (!pDPObj)
2171 : {
2172 0 : cerr << "A pivot table should exist over A3." << endl;
2173 0 : return false;
2174 : }
2175 :
2176 : // Output range should be A3:C12.
2177 4 : ScRange aOutRange = pDPObj->GetOutRange();
2178 4 : if (ScRange(0,2,0,2,11,0) != aOutRange)
2179 : {
2180 0 : cerr << "Incorrect output range." << endl;
2181 0 : return false;
2182 : }
2183 :
2184 4 : const ScDPSaveData* pSaveData = pDPObj->GetSaveData();
2185 4 : if (!pSaveData)
2186 : {
2187 0 : cerr << "Save data should exist in each pivot table object." << endl;
2188 0 : return false;
2189 : }
2190 :
2191 4 : std::vector<const ScDPSaveDimension*> aDims;
2192 4 : pSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_ROW, aDims);
2193 4 : if (aDims.size() != 1 || aDims[0]->GetName() != "Name")
2194 : {
2195 0 : cerr << "Pivot table should have one row field labeld 'Name'" << endl;
2196 0 : return false;
2197 : }
2198 :
2199 4 : pSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_DATA, aDims);
2200 20 : if (aDims.size() != 2 ||
2201 28 : ScDPUtil::getSourceDimensionName(aDims[0]->GetName()) != "Value" ||
2202 12 : ScDPUtil::getSourceDimensionName(aDims[1]->GetName()) != "Value")
2203 : {
2204 0 : cerr << "Pivot table should have two duplicated data fields both of which are named 'Value'." << endl;
2205 0 : return false;
2206 : }
2207 :
2208 4 : if (aDims[0]->GetFunction() != sheet::GeneralFunction_SUM)
2209 : {
2210 0 : cerr << "First data field should be SUM." << endl;
2211 0 : return false;
2212 : }
2213 :
2214 4 : if (aDims[1]->GetFunction() != sheet::GeneralFunction_COUNT)
2215 : {
2216 0 : cerr << "First data field should be COUNT." << endl;
2217 0 : return false;
2218 : }
2219 :
2220 4 : pSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_COLUMN, aDims);
2221 4 : if (aDims.size() != 1 || !aDims[0]->IsDataLayout())
2222 : {
2223 0 : cerr << "Pivot table should have one column field which is a data layout field." << endl;
2224 0 : return false;
2225 : }
2226 :
2227 4 : return true;
2228 : }
2229 :
2230 : } aTest;
2231 :
2232 2 : ScDocShellRef xDocSh = loadDoc("pivot-table/two-data-fields.", XLSX);
2233 2 : CPPUNIT_ASSERT(xDocSh.Is());
2234 2 : ScDocument* pDoc = &xDocSh->GetDocument();
2235 :
2236 : // Initial check.
2237 2 : bool bCheck = aTest.check(*pDoc);
2238 2 : CPPUNIT_ASSERT_MESSAGE("Initial check failed.", bCheck);
2239 :
2240 4 : ScDocShellRef xDocSh2 = saveAndReload(xDocSh, XLSX);
2241 2 : xDocSh->DoClose();
2242 2 : CPPUNIT_ASSERT(xDocSh2.Is());
2243 2 : pDoc = &xDocSh2->GetDocument();
2244 :
2245 : // Reload check.
2246 2 : bCheck = aTest.check(*pDoc);
2247 2 : CPPUNIT_ASSERT_MESSAGE("Reload check failed.", bCheck);
2248 :
2249 4 : xDocSh2->DoClose();
2250 2 : }
2251 :
2252 2 : void ScExportTest::testFunctionsExcel2010ODS()
2253 : {
2254 : //testFunctionsExcel2010(ODS);
2255 2 : }
2256 :
2257 70 : ScExportTest::ScExportTest()
2258 70 : : ScBootstrapFixture("/sc/qa/unit/data")
2259 : {
2260 70 : }
2261 :
2262 70 : void ScExportTest::setUp()
2263 : {
2264 70 : test::BootstrapFixture::setUp();
2265 :
2266 : // This is a bit of a fudge, we do this to ensure that ScGlobals::ensure,
2267 : // which is a private symbol to us, gets called
2268 140 : m_xCalcComponent =
2269 210 : getMultiServiceFactory()->createInstance("com.sun.star.comp.Calc.SpreadsheetDocument");
2270 70 : CPPUNIT_ASSERT_MESSAGE("no calc component!", m_xCalcComponent.is());
2271 70 : }
2272 :
2273 70 : void ScExportTest::tearDown()
2274 : {
2275 70 : uno::Reference< lang::XComponent >( m_xCalcComponent, UNO_QUERY_THROW )->dispose();
2276 70 : test::BootstrapFixture::tearDown();
2277 70 : }
2278 :
2279 2 : void ScExportTest::testSupBookVirtualPath()
2280 : {
2281 2 : ScDocShellRef xShell = loadDoc("external-ref.", XLS);
2282 2 : CPPUNIT_ASSERT(xShell.Is());
2283 :
2284 4 : ScDocShellRef xDocSh = saveAndReload(xShell, XLS);
2285 2 : xShell->DoClose();
2286 2 : CPPUNIT_ASSERT(xDocSh.Is());
2287 :
2288 2 : ScDocument& rDoc = xDocSh->GetDocument();
2289 :
2290 2 : if (!checkFormula(rDoc, ScAddress(0,0,0), "'file:///home/timar/Documents/external.xls'#$Sheet1.A1"))
2291 0 : CPPUNIT_FAIL("Wrong SupBook VirtualPath URL");
2292 :
2293 4 : xDocSh->DoClose();
2294 2 : }
2295 :
2296 2 : CPPUNIT_TEST_SUITE_REGISTRATION(ScExportTest);
2297 :
2298 8 : CPPUNIT_PLUGIN_IMPLEMENT();
2299 :
2300 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|