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/shared_test_impl.hxx"
22 :
23 : #include "docsh.hxx"
24 : #include "postit.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 <postit.hxx>
35 : #include <tokenstringcontext.hxx>
36 :
37 : #include "svx/svdoole2.hxx"
38 : #include "tabprotection.hxx"
39 : #include "editeng/wghtitem.hxx"
40 : #include "editeng/postitem.hxx"
41 : #include "editeng/editdata.hxx"
42 : #include "editeng/eeitem.hxx"
43 : #include "editeng/editobj.hxx"
44 : #include "editeng/section.hxx"
45 : #include <editeng/crossedoutitem.hxx>
46 : #include <editeng/borderline.hxx>
47 : #include <formula/grammar.hxx>
48 :
49 : #include <com/sun/star/table/BorderLineStyle.hpp>
50 :
51 : using namespace ::com::sun::star;
52 : using namespace ::com::sun::star::uno;
53 :
54 48 : class ScExportTest : public ScBootstrapFixture
55 : {
56 : public:
57 : ScExportTest();
58 :
59 : virtual void setUp() SAL_OVERRIDE;
60 : virtual void tearDown() SAL_OVERRIDE;
61 :
62 : ScDocShellRef saveAndReloadPassword( ScDocShell*, const OUString&, const OUString&, const OUString&, sal_uLong );
63 :
64 : void test();
65 : void testPasswordExport();
66 : void testConditionalFormatExportODS();
67 : void testConditionalFormatExportXLSX();
68 : void testColorScaleExportODS();
69 : void testColorScaleExportXLSX();
70 : void testDataBarExportODS();
71 : void testDataBarExportXLSX();
72 : void testMiscRowHeightExport();
73 : void testNamedRangeBugfdo62729();
74 : void testRichTextExportODS();
75 : void testFormulaRefSheetNameODS();
76 :
77 : void testCellValuesExportODS();
78 : void testCellNoteExportODS();
79 : void testCellNoteExportXLS();
80 : void testFormatExportODS();
81 :
82 : void testInlineArrayXLS();
83 : void testEmbeddedChartXLS();
84 : void testFormulaReferenceXLS();
85 : void testSheetProtectionXLSX();
86 :
87 : void testCellBordersXLS();
88 : void testCellBordersXLSX();
89 :
90 : void testSheetTabColorsXLSX();
91 :
92 : void testSharedFormulaExportXLS();
93 : void testSharedFormulaExportXLSX();
94 : void testSharedFormulaStringResultExportXLSX();
95 :
96 2 : CPPUNIT_TEST_SUITE(ScExportTest);
97 1 : CPPUNIT_TEST(test);
98 : #if !defined(MACOSX) && !defined(DRAGONFLY)
99 1 : CPPUNIT_TEST(testPasswordExport);
100 : #endif
101 1 : CPPUNIT_TEST(testConditionalFormatExportODS);
102 1 : CPPUNIT_TEST(testConditionalFormatExportXLSX);
103 1 : CPPUNIT_TEST(testColorScaleExportODS);
104 1 : CPPUNIT_TEST(testColorScaleExportXLSX);
105 1 : CPPUNIT_TEST(testMiscRowHeightExport);
106 1 : CPPUNIT_TEST(testNamedRangeBugfdo62729);
107 1 : CPPUNIT_TEST(testRichTextExportODS);
108 1 : CPPUNIT_TEST(testFormulaRefSheetNameODS);
109 1 : CPPUNIT_TEST(testCellValuesExportODS);
110 1 : CPPUNIT_TEST(testCellNoteExportODS);
111 1 : CPPUNIT_TEST(testCellNoteExportXLS);
112 1 : CPPUNIT_TEST(testFormatExportODS);
113 1 : CPPUNIT_TEST(testInlineArrayXLS);
114 1 : CPPUNIT_TEST(testEmbeddedChartXLS);
115 1 : CPPUNIT_TEST(testFormulaReferenceXLS);
116 1 : CPPUNIT_TEST(testSheetProtectionXLSX);
117 1 : CPPUNIT_TEST(testCellBordersXLS);
118 1 : CPPUNIT_TEST(testCellBordersXLSX);
119 1 : CPPUNIT_TEST(testSheetTabColorsXLSX);
120 1 : CPPUNIT_TEST(testSharedFormulaExportXLS);
121 1 : CPPUNIT_TEST(testSharedFormulaExportXLSX);
122 1 : CPPUNIT_TEST(testSharedFormulaStringResultExportXLSX);
123 :
124 2 : CPPUNIT_TEST_SUITE_END();
125 :
126 : private:
127 : void testExcelCellBorders( sal_uLong nFormatType );
128 :
129 : uno::Reference<uno::XInterface> m_xCalcComponent;
130 :
131 : };
132 :
133 1 : ScDocShellRef ScExportTest::saveAndReloadPassword(ScDocShell* pShell, const OUString &rFilter,
134 : const OUString &rUserData, const OUString& rTypeName, sal_uLong nFormatType)
135 : {
136 1 : utl::TempFile aTempFile;
137 1 : aTempFile.EnableKillingFile();
138 2 : SfxMedium aStoreMedium( aTempFile.GetURL(), STREAM_STD_WRITE );
139 1 : sal_uInt32 nExportFormat = 0;
140 1 : if (nFormatType == ODS_FORMAT_TYPE)
141 1 : nExportFormat = SFX_FILTER_EXPORT | SFX_FILTER_USESOPTIONS;
142 : SfxFilter* pExportFilter = new SfxFilter(
143 : rFilter,
144 : OUString(), nFormatType, nExportFormat, rTypeName, 0, OUString(),
145 1 : rUserData, OUString("private:factory/scalc*") );
146 1 : pExportFilter->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
147 1 : aStoreMedium.SetFilter(pExportFilter);
148 1 : SfxItemSet* pExportSet = aStoreMedium.GetItemSet();
149 2 : uno::Sequence< beans::NamedValue > aEncryptionData = comphelper::OStorageHelper::CreatePackageEncryptionData( OUString("test") );
150 2 : uno::Any xEncryptionData;
151 1 : xEncryptionData <<= aEncryptionData;
152 1 : pExportSet->Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA, xEncryptionData));
153 :
154 2 : uno::Reference< embed::XStorage > xMedStorage = aStoreMedium.GetStorage();
155 1 : ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( xMedStorage, aEncryptionData );
156 :
157 1 : pShell->DoSaveAs( aStoreMedium );
158 1 : pShell->DoClose();
159 :
160 : //std::cout << "File: " << aTempFile.GetURL() << std::endl;
161 :
162 1 : sal_uInt32 nFormat = 0;
163 1 : if (nFormatType == ODS_FORMAT_TYPE)
164 1 : nFormat = SFX_FILTER_IMPORT | SFX_FILTER_USESOPTIONS;
165 :
166 2 : OUString aPass("test");
167 2 : return load(aTempFile.GetURL(), rFilter, rUserData, rTypeName, nFormatType, nFormat, SOFFICE_FILEFORMAT_CURRENT, &aPass);
168 : }
169 :
170 1 : void ScExportTest::test()
171 : {
172 : ScDocShell* pShell = new ScDocShell(
173 : SFXMODEL_STANDARD |
174 : SFXMODEL_DISABLE_EMBEDDED_SCRIPTS |
175 1 : SFXMODEL_DISABLE_DOCUMENT_RECOVERY);
176 1 : pShell->DoInitNew();
177 :
178 1 : ScDocument* pDoc = pShell->GetDocument();
179 :
180 1 : pDoc->SetValue(0,0,0, 1.0);
181 1 : CPPUNIT_ASSERT(pDoc);
182 :
183 1 : ScDocShellRef xDocSh = saveAndReload( pShell, ODS );
184 :
185 1 : CPPUNIT_ASSERT(xDocSh.Is());
186 1 : ScDocument* pLoadedDoc = xDocSh->GetDocument();
187 1 : double aVal = pLoadedDoc->GetValue(0,0,0);
188 1 : ASSERT_DOUBLES_EQUAL(aVal, 1.0);
189 1 : }
190 :
191 1 : void ScExportTest::testPasswordExport()
192 : {
193 : ScDocShell* pShell = new ScDocShell(
194 : SFXMODEL_STANDARD |
195 : SFXMODEL_DISABLE_EMBEDDED_SCRIPTS |
196 1 : SFXMODEL_DISABLE_DOCUMENT_RECOVERY);
197 1 : pShell->DoInitNew();
198 :
199 1 : ScDocument* pDoc = pShell->GetDocument();
200 :
201 1 : pDoc->SetValue(0,0,0, 1.0);
202 1 : CPPUNIT_ASSERT(pDoc);
203 :
204 1 : sal_Int32 nFormat = ODS;
205 1 : OUString aFilterName(getFileFormats()[nFormat].pFilterName, strlen(getFileFormats()[nFormat].pFilterName), RTL_TEXTENCODING_UTF8) ;
206 2 : OUString aFilterType(getFileFormats()[nFormat].pTypeName, strlen(getFileFormats()[nFormat].pTypeName), RTL_TEXTENCODING_UTF8);
207 2 : ScDocShellRef xDocSh = saveAndReloadPassword(pShell, aFilterName, OUString(), aFilterType, getFileFormats()[nFormat].nFormatType);
208 :
209 1 : CPPUNIT_ASSERT(xDocSh.Is());
210 1 : ScDocument* pLoadedDoc = xDocSh->GetDocument();
211 1 : double aVal = pLoadedDoc->GetValue(0,0,0);
212 1 : ASSERT_DOUBLES_EQUAL(aVal, 1.0);
213 :
214 2 : xDocSh->DoClose();
215 1 : }
216 :
217 1 : void ScExportTest::testConditionalFormatExportODS()
218 : {
219 1 : ScDocShellRef xShell = loadDoc("new_cond_format_test.", ODS);
220 1 : CPPUNIT_ASSERT(xShell.Is());
221 :
222 2 : ScDocShellRef xDocSh = saveAndReload(&(*xShell), ODS);
223 1 : CPPUNIT_ASSERT(xDocSh.Is());
224 1 : ScDocument* pDoc = xDocSh->GetDocument();
225 2 : OUString aCSVFile("new_cond_format_test.");
226 2 : OUString aCSVPath;
227 1 : createCSVPath( aCSVFile, aCSVPath );
228 1 : testCondFile(aCSVPath, pDoc, 0);
229 :
230 2 : xDocSh->DoClose();
231 1 : }
232 :
233 1 : void ScExportTest::testConditionalFormatExportXLSX()
234 : {
235 1 : ScDocShellRef xShell = loadDoc("new_cond_format_test.", XLSX);
236 1 : CPPUNIT_ASSERT(xShell.Is());
237 :
238 2 : ScDocShellRef xDocSh = saveAndReload(&(*xShell), XLSX);
239 1 : CPPUNIT_ASSERT(xDocSh.Is());
240 1 : ScDocument* pDoc = xDocSh->GetDocument();
241 2 : OUString aCSVFile("new_cond_format_test.");
242 2 : OUString aCSVPath;
243 1 : createCSVPath( aCSVFile, aCSVPath );
244 1 : testCondFile(aCSVPath, pDoc, 0);
245 :
246 2 : xDocSh->DoClose();
247 1 : }
248 :
249 1 : void ScExportTest::testColorScaleExportODS()
250 : {
251 1 : ScDocShellRef xShell = loadDoc("colorscale.", ODS);
252 1 : CPPUNIT_ASSERT(xShell.Is());
253 :
254 2 : ScDocShellRef xDocSh = saveAndReload(xShell, ODS);
255 1 : CPPUNIT_ASSERT(xDocSh.Is());
256 :
257 1 : ScDocument* pDoc = xDocSh->GetDocument();
258 1 : CPPUNIT_ASSERT(pDoc);
259 :
260 1 : testColorScale2Entry_Impl(pDoc);
261 1 : testColorScale3Entry_Impl(pDoc);
262 :
263 2 : xDocSh->DoClose();
264 1 : }
265 :
266 1 : void ScExportTest::testColorScaleExportXLSX()
267 : {
268 1 : ScDocShellRef xShell = loadDoc("colorscale.", XLSX);
269 1 : CPPUNIT_ASSERT(xShell.Is());
270 :
271 2 : ScDocShellRef xDocSh = saveAndReload(xShell, XLSX);
272 1 : CPPUNIT_ASSERT(xDocSh.Is());
273 :
274 1 : ScDocument* pDoc = xDocSh->GetDocument();
275 1 : CPPUNIT_ASSERT(pDoc);
276 :
277 1 : testColorScale2Entry_Impl(pDoc);
278 1 : testColorScale3Entry_Impl(pDoc);
279 :
280 2 : xDocSh->DoClose();
281 1 : }
282 :
283 0 : void ScExportTest::testDataBarExportODS()
284 : {
285 0 : ScDocShellRef xShell = loadDoc("databar.", ODS);
286 0 : CPPUNIT_ASSERT(xShell.Is());
287 :
288 0 : ScDocShellRef xDocSh = saveAndReload(xShell, ODS);
289 0 : CPPUNIT_ASSERT(xDocSh.Is());
290 :
291 0 : ScDocument* pDoc = xDocSh->GetDocument();
292 0 : CPPUNIT_ASSERT(pDoc);
293 :
294 0 : testDataBar_Impl(pDoc);
295 :
296 0 : xDocSh->DoClose();
297 0 : }
298 :
299 1 : void ScExportTest::testFormatExportODS()
300 : {
301 1 : ScDocShellRef xShell = loadDoc("formats.", ODS);
302 1 : CPPUNIT_ASSERT(xShell.Is());
303 :
304 2 : ScDocShellRef xDocSh = saveAndReload(xShell, ODS);
305 1 : CPPUNIT_ASSERT(xDocSh.Is());
306 :
307 1 : ScDocument* pDoc = xDocSh->GetDocument();
308 :
309 1 : testFormats(this, pDoc, ODS);
310 :
311 2 : xDocSh->DoClose();
312 1 : }
313 :
314 0 : void ScExportTest::testDataBarExportXLSX()
315 : {
316 0 : ScDocShellRef xShell = loadDoc("databar.", XLSX);
317 0 : CPPUNIT_ASSERT(xShell.Is());
318 :
319 0 : ScDocShellRef xDocSh = saveAndReload(xShell, XLSX);
320 0 : CPPUNIT_ASSERT(xDocSh.Is());
321 :
322 0 : ScDocument* pDoc = xDocSh->GetDocument();
323 0 : CPPUNIT_ASSERT(pDoc);
324 :
325 0 : testDataBar_Impl(pDoc);
326 :
327 0 : xDocSh->DoClose();
328 0 : }
329 :
330 1 : void ScExportTest::testMiscRowHeightExport()
331 : {
332 : TestParam::RowData DfltRowData[] =
333 : {
334 : { 0, 4, 0, 529, 0, false },
335 : { 5, 10, 0, 1058, 0, false },
336 : { 17, 20, 0, 1767, 0, false },
337 : // check last couple of row in document to ensure
338 : // they are 5.29mm ( effective default row xlsx height )
339 : { 1048573, 1048575, 0, 529, 0, false },
340 1 : };
341 :
342 : TestParam::RowData EmptyRepeatRowData[] =
343 : {
344 : // rows 0-4, 5-10, 17-20 are all set at various
345 : // heights, there is no content in the rows, there
346 : // was a bug where only the first row ( of repeated rows )
347 : // was set after export
348 : { 0, 4, 0, 529, 0, false },
349 : { 5, 10, 0, 1058, 0, false },
350 : { 17, 20, 0, 1767, 0, false },
351 1 : };
352 :
353 : TestParam aTestValues[] =
354 : {
355 : // Checks that some distributed ( non-empty ) heights remain set after export (roundtrip)
356 : // additionally there is effectively a default row height ( 5.29 mm ). So we test the
357 : // unset rows at the end of the document to ensure the effective xlsx default height
358 : // is set there too.
359 : { "miscrowheights.", XLSX, XLSX, SAL_N_ELEMENTS(DfltRowData), DfltRowData },
360 : // Checks that some distributed ( non-empty ) heights remain set after export (to xls)
361 : { "miscrowheights.", XLSX, XLS, SAL_N_ELEMENTS(DfltRowData), DfltRowData },
362 : // Checks that repreated rows ( of various heights ) remain set after export ( to xlsx )
363 : { "miscemptyrepeatedrowheights.", ODS, XLSX, SAL_N_ELEMENTS(EmptyRepeatRowData), EmptyRepeatRowData },
364 : // Checks that repreated rows ( of various heights ) remain set after export ( to xls )
365 : { "miscemptyrepeatedrowheights.", ODS, XLS, SAL_N_ELEMENTS(EmptyRepeatRowData), EmptyRepeatRowData },
366 1 : };
367 1 : miscRowHeightsTest( aTestValues, SAL_N_ELEMENTS(aTestValues) );
368 1 : }
369 :
370 : namespace {
371 :
372 3 : void setAttribute( ScFieldEditEngine& rEE, sal_Int32 nPara, sal_Int32 nStart, sal_Int32 nEnd, sal_uInt16 nType )
373 : {
374 3 : ESelection aSel;
375 3 : aSel.nStartPara = aSel.nEndPara = nPara;
376 3 : aSel.nStartPos = nStart;
377 3 : aSel.nEndPos = nEnd;
378 :
379 3 : SfxItemSet aItemSet = rEE.GetEmptyItemSet();
380 3 : switch (nType)
381 : {
382 : case EE_CHAR_WEIGHT:
383 : {
384 1 : SvxWeightItem aWeight(WEIGHT_BOLD, nType);
385 1 : aItemSet.Put(aWeight);
386 1 : rEE.QuickSetAttribs(aItemSet, aSel);
387 : }
388 1 : break;
389 : case EE_CHAR_ITALIC:
390 : {
391 1 : SvxPostureItem aItalic(ITALIC_NORMAL, nType);
392 1 : aItemSet.Put(aItalic);
393 1 : rEE.QuickSetAttribs(aItemSet, aSel);
394 : }
395 1 : break;
396 : case EE_CHAR_STRIKEOUT:
397 : {
398 1 : SvxCrossedOutItem aCrossOut(STRIKEOUT_SINGLE, nType);
399 1 : aItemSet.Put(aCrossOut);
400 1 : rEE.QuickSetAttribs(aItemSet, aSel);
401 : }
402 1 : break;
403 : default:
404 : ;
405 3 : }
406 3 : }
407 :
408 : }
409 :
410 1 : void ScExportTest::testNamedRangeBugfdo62729()
411 : {
412 1 : ScDocShellRef xShell = loadDoc("fdo62729.", ODS);
413 1 : CPPUNIT_ASSERT(xShell.Is());
414 1 : ScDocument* pDoc = xShell->GetDocument();
415 1 : CPPUNIT_ASSERT(pDoc);
416 :
417 1 : ScRangeName* pNames = pDoc->GetRangeName();
418 : //should be just a single named range
419 1 : CPPUNIT_ASSERT(pNames->size() == 1 );
420 1 : pDoc->DeleteTab(0);
421 : //should be still a single named range
422 1 : CPPUNIT_ASSERT(pNames->size() == 1 );
423 2 : ScDocShellRef xDocSh = saveAndReload(xShell, ODS);
424 1 : xShell->DoClose();
425 :
426 1 : CPPUNIT_ASSERT(xDocSh.Is());
427 1 : pDoc = xDocSh->GetDocument();
428 1 : CPPUNIT_ASSERT(pDoc);
429 :
430 1 : pNames = pDoc->GetRangeName();
431 : //after reload should still have a named range
432 1 : CPPUNIT_ASSERT(pNames->size() == 1 );
433 :
434 2 : xDocSh->DoClose();
435 1 : }
436 :
437 1 : void ScExportTest::testRichTextExportODS()
438 : {
439 : struct
440 : {
441 3 : static bool isBold(const editeng::Section& rAttr)
442 : {
443 3 : if (rAttr.maAttributes.empty())
444 0 : return false;
445 :
446 3 : std::vector<const SfxPoolItem*>::const_iterator it = rAttr.maAttributes.begin(), itEnd = rAttr.maAttributes.end();
447 3 : for (; it != itEnd; ++it)
448 : {
449 3 : const SfxPoolItem* p = *it;
450 3 : if (p->Which() != EE_CHAR_WEIGHT)
451 0 : continue;
452 :
453 3 : return static_cast<const SvxWeightItem*>(p)->GetWeight() == WEIGHT_BOLD;
454 : }
455 0 : return false;
456 : }
457 :
458 3 : static bool isItalic(const editeng::Section& rAttr)
459 : {
460 3 : if (rAttr.maAttributes.empty())
461 0 : return false;
462 :
463 3 : std::vector<const SfxPoolItem*>::const_iterator it = rAttr.maAttributes.begin(), itEnd = rAttr.maAttributes.end();
464 3 : for (; it != itEnd; ++it)
465 : {
466 3 : const SfxPoolItem* p = *it;
467 3 : if (p->Which() != EE_CHAR_ITALIC)
468 0 : continue;
469 :
470 3 : return static_cast<const SvxPostureItem*>(p)->GetPosture() == ITALIC_NORMAL;
471 : }
472 0 : return false;
473 : }
474 :
475 2 : static bool isStrikeOut(const editeng::Section& rAttr)
476 : {
477 2 : if (rAttr.maAttributes.empty())
478 0 : return false;
479 :
480 2 : std::vector<const SfxPoolItem*>::const_iterator it = rAttr.maAttributes.begin(), itEnd = rAttr.maAttributes.end();
481 2 : for (; it != itEnd; ++it)
482 : {
483 2 : const SfxPoolItem* p = *it;
484 2 : if (p->Which() != EE_CHAR_STRIKEOUT)
485 0 : continue;
486 :
487 2 : return static_cast<const SvxCrossedOutItem*>(p)->GetStrikeout() == STRIKEOUT_SINGLE;
488 : }
489 0 : return false;
490 : }
491 :
492 3 : bool checkB2(const EditTextObject* pText) const
493 : {
494 3 : if (!pText)
495 0 : return false;
496 :
497 3 : if (pText->GetParagraphCount() != 1)
498 0 : return false;
499 :
500 3 : if (pText->GetText(0) != "Bold and Italic")
501 0 : return false;
502 :
503 3 : std::vector<editeng::Section> aSecAttrs;
504 3 : pText->GetAllSections(aSecAttrs);
505 3 : if (aSecAttrs.size() != 3)
506 0 : return false;
507 :
508 : // Check the first bold section.
509 3 : const editeng::Section* pAttr = &aSecAttrs[0];
510 3 : if (pAttr->mnParagraph != 0 ||pAttr->mnStart != 0 || pAttr->mnEnd != 4)
511 0 : return false;
512 :
513 3 : if (pAttr->maAttributes.size() != 1 || !isBold(*pAttr))
514 0 : return false;
515 :
516 : // The middle section should be unformatted.
517 3 : pAttr = &aSecAttrs[1];
518 3 : if (pAttr->mnParagraph != 0 ||pAttr->mnStart != 4 || pAttr->mnEnd != 9)
519 0 : return false;
520 :
521 3 : if (!pAttr->maAttributes.empty())
522 0 : return false;
523 :
524 : // The last section should be italic.
525 3 : pAttr = &aSecAttrs[2];
526 3 : if (pAttr->mnParagraph != 0 ||pAttr->mnStart != 9 || pAttr->mnEnd != 15)
527 0 : return false;
528 :
529 3 : if (pAttr->maAttributes.size() != 1 || !isItalic(*pAttr))
530 0 : return false;
531 :
532 3 : return true;
533 : }
534 :
535 3 : bool checkB4(const EditTextObject* pText) const
536 : {
537 3 : if (!pText)
538 0 : return false;
539 :
540 3 : if (pText->GetParagraphCount() != 3)
541 0 : return false;
542 :
543 3 : if (pText->GetText(0) != "One")
544 0 : return false;
545 :
546 3 : if (pText->GetText(1) != "Two")
547 0 : return false;
548 :
549 3 : if (pText->GetText(2) != "Three")
550 0 : return false;
551 :
552 3 : return true;
553 : }
554 :
555 2 : bool checkB5(const EditTextObject* pText) const
556 : {
557 2 : if (!pText)
558 0 : return false;
559 :
560 2 : if (pText->GetParagraphCount() != 6)
561 0 : return false;
562 :
563 2 : if (pText->GetText(0) != "")
564 0 : return false;
565 :
566 2 : if (pText->GetText(1) != "Two")
567 0 : return false;
568 :
569 2 : if (pText->GetText(2) != "Three")
570 0 : return false;
571 :
572 2 : if (pText->GetText(3) != "")
573 0 : return false;
574 :
575 2 : if (pText->GetText(4) != "Five")
576 0 : return false;
577 :
578 2 : if (pText->GetText(5) != "")
579 0 : return false;
580 :
581 2 : return true;
582 : }
583 :
584 2 : bool checkB6(const EditTextObject* pText) const
585 : {
586 2 : if (!pText)
587 0 : return false;
588 :
589 2 : if (pText->GetParagraphCount() != 1)
590 0 : return false;
591 :
592 2 : if (pText->GetText(0) != "Strike Me")
593 0 : return false;
594 :
595 2 : std::vector<editeng::Section> aSecAttrs;
596 2 : pText->GetAllSections(aSecAttrs);
597 2 : if (aSecAttrs.size() != 2)
598 0 : return false;
599 :
600 : // Check the first strike-out section.
601 2 : const editeng::Section* pAttr = &aSecAttrs[0];
602 2 : if (pAttr->mnParagraph != 0 ||pAttr->mnStart != 0 || pAttr->mnEnd != 6)
603 0 : return false;
604 :
605 2 : if (pAttr->maAttributes.size() != 1 || !isStrikeOut(*pAttr))
606 0 : return false;
607 :
608 : // The last section should be unformatted.
609 2 : pAttr = &aSecAttrs[1];
610 2 : if (pAttr->mnParagraph != 0 ||pAttr->mnStart != 6 || pAttr->mnEnd != 9)
611 0 : return false;
612 :
613 2 : return true;
614 : }
615 :
616 : } aCheckFunc;
617 :
618 : // Start with an empty document, put one edit text cell, and make sure it
619 : // survives the save and reload.
620 1 : ScDocShellRef xOrigDocSh = loadDoc("empty.", ODS);
621 1 : ScDocument* pDoc = xOrigDocSh->GetDocument();
622 1 : CPPUNIT_ASSERT(pDoc);
623 1 : CPPUNIT_ASSERT_MESSAGE("This document should at least have one sheet.", pDoc->GetTableCount() > 0);
624 :
625 : // Insert an edit text cell.
626 1 : ScFieldEditEngine& rEE = pDoc->GetEditEngine();
627 1 : rEE.SetText("Bold and Italic");
628 : // Set the 'Bold' part bold.
629 1 : setAttribute(rEE, 0, 0, 4, EE_CHAR_WEIGHT);
630 : // Set the 'Italic' part italic.
631 1 : setAttribute(rEE, 0, 9, 15, EE_CHAR_ITALIC);
632 1 : ESelection aSel;
633 1 : aSel.nStartPara = aSel.nEndPara = 0;
634 :
635 : // Set this edit text to cell B2.
636 1 : pDoc->SetEditText(ScAddress(1,1,0), rEE.CreateTextObject());
637 1 : const EditTextObject* pEditText = pDoc->GetEditText(ScAddress(1,1,0));
638 1 : CPPUNIT_ASSERT_MESSAGE("Incorret B2 value.", aCheckFunc.checkB2(pEditText));
639 :
640 : // Now, save and reload this document.
641 2 : ScDocShellRef xNewDocSh = saveAndReload(xOrigDocSh, ODS);
642 1 : xOrigDocSh->DoClose();
643 1 : CPPUNIT_ASSERT(xNewDocSh.Is());
644 1 : pDoc = xNewDocSh->GetDocument();
645 1 : CPPUNIT_ASSERT(pDoc);
646 1 : CPPUNIT_ASSERT_MESSAGE("Reloaded document should at least have one sheet.", pDoc->GetTableCount() > 0);
647 :
648 : // Make sure the content of B2 is still intact.
649 1 : CPPUNIT_ASSERT_MESSAGE("Incorret B2 value.", aCheckFunc.checkB2(pEditText));
650 :
651 : // Insert a multi-line content to B4.
652 1 : rEE.Clear();
653 1 : rEE.SetText("One\nTwo\nThree");
654 1 : pDoc->SetEditText(ScAddress(3,1,0), rEE.CreateTextObject());
655 1 : pEditText = pDoc->GetEditText(ScAddress(3,1,0));
656 1 : CPPUNIT_ASSERT_MESSAGE("Incorret B4 value.", aCheckFunc.checkB4(pEditText));
657 :
658 : // Reload the doc again, and check the content of B2 and B4.
659 2 : ScDocShellRef xNewDocSh2 = saveAndReload(xNewDocSh, ODS);
660 1 : pDoc = xNewDocSh2->GetDocument();
661 1 : xNewDocSh->DoClose();
662 :
663 1 : pEditText = pDoc->GetEditText(ScAddress(1,1,0));
664 1 : CPPUNIT_ASSERT_MESSAGE("B2 should be an edit text.", pEditText);
665 1 : pEditText = pDoc->GetEditText(ScAddress(3,1,0));
666 1 : CPPUNIT_ASSERT_MESSAGE("Incorret B4 value.", aCheckFunc.checkB4(pEditText));
667 :
668 : // Insert a multi-line content to B5, but this time, set some empty paragraphs.
669 1 : rEE.Clear();
670 1 : rEE.SetText("\nTwo\nThree\n\nFive\n");
671 1 : pDoc->SetEditText(ScAddress(4,1,0), rEE.CreateTextObject());
672 1 : pEditText = pDoc->GetEditText(ScAddress(4,1,0));
673 1 : CPPUNIT_ASSERT_MESSAGE("Incorret B5 value.", aCheckFunc.checkB5(pEditText));
674 :
675 : // Insert a text with strikethrough in B6.
676 1 : rEE.Clear();
677 1 : rEE.SetText("Strike Me");
678 : // Set the 'Strike' part strikethrough.
679 1 : setAttribute(rEE, 0, 0, 6, EE_CHAR_STRIKEOUT);
680 1 : pDoc->SetEditText(ScAddress(5,1,0), rEE.CreateTextObject());
681 1 : pEditText = pDoc->GetEditText(ScAddress(5,1,0));
682 1 : CPPUNIT_ASSERT_MESSAGE("Incorret B6 value.", aCheckFunc.checkB6(pEditText));
683 :
684 : // Reload the doc again, and check the content of B2, B4 and B6.
685 2 : ScDocShellRef xNewDocSh3 = saveAndReload(xNewDocSh2, ODS);
686 1 : pDoc = xNewDocSh3->GetDocument();
687 1 : xNewDocSh2->DoClose();
688 :
689 1 : pEditText = pDoc->GetEditText(ScAddress(1,1,0));
690 1 : CPPUNIT_ASSERT_MESSAGE("Incorret B2 value.", aCheckFunc.checkB2(pEditText));
691 1 : pEditText = pDoc->GetEditText(ScAddress(3,1,0));
692 1 : CPPUNIT_ASSERT_MESSAGE("Incorret B4 value.", aCheckFunc.checkB4(pEditText));
693 1 : pEditText = pDoc->GetEditText(ScAddress(4,1,0));
694 1 : CPPUNIT_ASSERT_MESSAGE("Incorret B5 value.", aCheckFunc.checkB5(pEditText));
695 1 : pEditText = pDoc->GetEditText(ScAddress(5,1,0));
696 1 : CPPUNIT_ASSERT_MESSAGE("Incorret B6 value.", aCheckFunc.checkB6(pEditText));
697 :
698 2 : xNewDocSh3->DoClose();
699 1 : }
700 :
701 1 : void ScExportTest::testFormulaRefSheetNameODS()
702 : {
703 1 : ScDocShellRef xDocSh = loadDoc("formula-quote-in-sheet-name.", ODS, true);
704 1 : ScDocument* pDoc = xDocSh->GetDocument();
705 :
706 2 : sc::AutoCalcSwitch aACSwitch(*pDoc, true); // turn on auto calc.
707 1 : pDoc->SetString(ScAddress(1,1,0), "='90''s Data'.B2");
708 1 : CPPUNIT_ASSERT_EQUAL(1.1, pDoc->GetValue(ScAddress(1,1,0)));
709 1 : if (!checkFormula(*pDoc, ScAddress(1,1,0), "'90''s Data'.B2"))
710 0 : CPPUNIT_FAIL("Wrong formula");
711 :
712 : // Now, save and reload this document.
713 2 : ScDocShellRef xNewDocSh = saveAndReload(xDocSh, ODS);
714 1 : xDocSh->DoClose();
715 :
716 1 : pDoc = xNewDocSh->GetDocument();
717 1 : pDoc->CalcAll();
718 1 : CPPUNIT_ASSERT_EQUAL(1.1, pDoc->GetValue(ScAddress(1,1,0)));
719 1 : if (!checkFormula(*pDoc, ScAddress(1,1,0), "'90''s Data'.B2"))
720 0 : CPPUNIT_FAIL("Wrong formula");
721 :
722 2 : xNewDocSh->DoClose();
723 1 : }
724 :
725 1 : void ScExportTest::testCellValuesExportODS()
726 : {
727 : // Start with an empty document
728 1 : ScDocShellRef xOrigDocSh = loadDoc("empty.", ODS);
729 1 : ScDocument* pDoc = xOrigDocSh->GetDocument();
730 1 : CPPUNIT_ASSERT(pDoc);
731 1 : CPPUNIT_ASSERT_MESSAGE("This document should at least have one sheet.", pDoc->GetTableCount() > 0);
732 :
733 : // set a value double
734 1 : pDoc->SetValue(ScAddress(0,0,0), 2.0); // A1
735 :
736 : // set a formula
737 1 : pDoc->SetValue(ScAddress(2,0,0), 3.0); // C1
738 1 : pDoc->SetValue(ScAddress(3,0,0), 3); // D1
739 1 : pDoc->SetString(ScAddress(4,0,0), "=10*C1/4"); // E1
740 1 : pDoc->SetValue(ScAddress(5,0,0), 3.0); // F1
741 1 : pDoc->SetString(ScAddress(7,0,0), "=SUM(C1:F1)"); //H1
742 :
743 : // set a string
744 1 : pDoc->SetString(ScAddress(0,2,0), "a simple line"); //A3
745 :
746 : // set a digit string
747 1 : pDoc->SetString(ScAddress(0,4,0), "'12"); //A5
748 : // set a contiguous value
749 1 : pDoc->SetValue(ScAddress(0,5,0), 12.0); //A6
750 : // set acontiguous string
751 1 : pDoc->SetString(ScAddress(0,6,0), "a string"); //A7
752 : // set a contiguous formula
753 1 : pDoc->SetString(ScAddress(0,7,0), "=$A$6"); //A8
754 :
755 : // save and reload
756 2 : ScDocShellRef xNewDocSh = saveAndReload(xOrigDocSh, ODS);
757 1 : xOrigDocSh->DoClose();
758 1 : CPPUNIT_ASSERT(xNewDocSh.Is());
759 1 : pDoc = xNewDocSh->GetDocument();
760 1 : CPPUNIT_ASSERT(pDoc);
761 1 : CPPUNIT_ASSERT_MESSAGE("Reloaded document should at least have one sheet.", pDoc->GetTableCount() > 0);
762 :
763 : // check value
764 1 : CPPUNIT_ASSERT_EQUAL(2.0, pDoc->GetValue(0,0,0));
765 1 : CPPUNIT_ASSERT_EQUAL(3.0, pDoc->GetValue(2,0,0));
766 1 : CPPUNIT_ASSERT_EQUAL(3.0, pDoc->GetValue(3,0,0));
767 1 : CPPUNIT_ASSERT_EQUAL(7.5, pDoc->GetValue(4,0,0));
768 1 : CPPUNIT_ASSERT_EQUAL(3.0, pDoc->GetValue(5,0,0));
769 :
770 : // check formula
771 1 : if (!checkFormula(*pDoc, ScAddress(4,0,0), "10*C1/4"))
772 0 : CPPUNIT_FAIL("Wrong formula =10*C1/4");
773 1 : if (!checkFormula(*pDoc, ScAddress(7,0,0), "SUM(C1:F1)"))
774 0 : CPPUNIT_FAIL("Wrong formula =SUM(C1:F1)");
775 1 : CPPUNIT_ASSERT_EQUAL(16.5, pDoc->GetValue(7,0,0));
776 :
777 : // check string
778 2 : ScRefCellValue aCell;
779 1 : aCell.assign(*pDoc, ScAddress(0,2,0));
780 1 : CPPUNIT_ASSERT_EQUAL( CELLTYPE_STRING, aCell.meType );
781 :
782 : // check for an empty cell
783 1 : aCell.assign(*pDoc, ScAddress(0,3,0));
784 1 : CPPUNIT_ASSERT_EQUAL( CELLTYPE_NONE, aCell.meType);
785 :
786 : // check a digit string
787 1 : aCell.assign(*pDoc, ScAddress(0,4,0));
788 1 : CPPUNIT_ASSERT_EQUAL( CELLTYPE_STRING, aCell.meType);
789 :
790 : //check contiguous values
791 1 : CPPUNIT_ASSERT_EQUAL( 12.0, pDoc->GetValue(0,5,0) );
792 1 : CPPUNIT_ASSERT_EQUAL( OUString("a string"), pDoc->GetString(0,6,0) );
793 1 : if (!checkFormula(*pDoc, ScAddress(0,7,0), "$A$6"))
794 0 : CPPUNIT_FAIL("Wrong formula =$A$6");
795 1 : CPPUNIT_ASSERT_EQUAL( pDoc->GetValue(0,5,0), pDoc->GetValue(0,7,0) );
796 :
797 2 : xNewDocSh->DoClose();
798 1 : }
799 :
800 1 : void ScExportTest::testCellNoteExportODS()
801 : {
802 1 : ScDocShellRef xOrigDocSh = loadDoc("single-note.", ODS);
803 1 : ScDocument* pDoc = xOrigDocSh->GetDocument();
804 :
805 1 : ScAddress aPos(0,0,0); // Start with A1.
806 1 : CPPUNIT_ASSERT_MESSAGE("There should be a note at A1.", pDoc->HasNote(aPos));
807 :
808 1 : aPos.IncRow(); // Move to A2.
809 1 : ScPostIt* pNote = pDoc->GetOrCreateNote(aPos);
810 1 : pNote->SetText(aPos, "Note One");
811 1 : pNote->SetAuthor("Author One");
812 1 : CPPUNIT_ASSERT_MESSAGE("There should be a note at A2.", pDoc->HasNote(aPos));
813 :
814 : // save and reload
815 2 : ScDocShellRef xNewDocSh = saveAndReload(xOrigDocSh, ODS);
816 1 : xOrigDocSh->DoClose();
817 1 : CPPUNIT_ASSERT(xNewDocSh.Is());
818 1 : pDoc = xNewDocSh->GetDocument();
819 :
820 1 : aPos.SetRow(0); // Move back to A1.
821 1 : CPPUNIT_ASSERT_MESSAGE("There should be a note at A1.", pDoc->HasNote(aPos));
822 1 : aPos.IncRow(); // Move to A2.
823 1 : CPPUNIT_ASSERT_MESSAGE("There should be a note at A2.", pDoc->HasNote(aPos));
824 :
825 2 : xNewDocSh->DoClose();
826 1 : }
827 :
828 1 : void ScExportTest::testCellNoteExportXLS()
829 : {
830 : // Start with an empty document.s
831 1 : ScDocShellRef xOrigDocSh = loadDoc("notes-on-3-sheets.", ODS);
832 1 : ScDocument* pDoc = xOrigDocSh->GetDocument();
833 1 : CPPUNIT_ASSERT_MESSAGE("This document should have 3 sheets.", pDoc->GetTableCount() == 3);
834 :
835 : // Check note's presence.
836 1 : CPPUNIT_ASSERT( pDoc->HasNote(ScAddress(0,0,0)));
837 1 : CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0,1,0)));
838 1 : CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0,2,0)));
839 :
840 1 : CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0,0,1)));
841 1 : CPPUNIT_ASSERT( pDoc->HasNote(ScAddress(0,1,1)));
842 1 : CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0,2,1)));
843 :
844 1 : CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0,0,2)));
845 1 : CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0,1,2)));
846 1 : CPPUNIT_ASSERT( pDoc->HasNote(ScAddress(0,2,2)));
847 :
848 : // save and reload as XLS.
849 2 : ScDocShellRef xNewDocSh = saveAndReload(xOrigDocSh, XLS);
850 1 : xOrigDocSh->DoClose();
851 1 : CPPUNIT_ASSERT(xNewDocSh.Is());
852 1 : pDoc = xNewDocSh->GetDocument();
853 1 : CPPUNIT_ASSERT_MESSAGE("This document should have 3 sheets.", pDoc->GetTableCount() == 3);
854 :
855 : // Check note's presence again.
856 1 : CPPUNIT_ASSERT( pDoc->HasNote(ScAddress(0,0,0)));
857 1 : CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0,1,0)));
858 1 : CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0,2,0)));
859 :
860 1 : CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0,0,1)));
861 1 : CPPUNIT_ASSERT( pDoc->HasNote(ScAddress(0,1,1)));
862 1 : CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0,2,1)));
863 :
864 1 : CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0,0,2)));
865 1 : CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0,1,2)));
866 1 : CPPUNIT_ASSERT( pDoc->HasNote(ScAddress(0,2,2)));
867 :
868 2 : xNewDocSh->DoClose();
869 1 : }
870 :
871 : namespace {
872 :
873 3 : void checkMatrixRange(ScDocument& rDoc, const ScRange& rRange)
874 : {
875 3 : ScRange aMatRange;
876 3 : ScAddress aMatOrigin;
877 10 : for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
878 : {
879 23 : for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
880 : {
881 16 : ScAddress aPos(nCol, nRow, rRange.aStart.Tab());
882 16 : bool bIsMatrix = rDoc.GetMatrixFormulaRange(aPos, aMatRange);
883 16 : CPPUNIT_ASSERT_MESSAGE("Matrix expected, but not found.", bIsMatrix);
884 16 : CPPUNIT_ASSERT_MESSAGE("Wrong matrix range.", rRange == aMatRange);
885 16 : const ScFormulaCell* pCell = rDoc.GetFormulaCell(aPos);
886 16 : CPPUNIT_ASSERT_MESSAGE("This must be a formula cell.", pCell);
887 :
888 16 : bIsMatrix = pCell->GetMatrixOrigin(aMatOrigin);
889 16 : CPPUNIT_ASSERT_MESSAGE("Not a part of matrix formula.", bIsMatrix);
890 16 : CPPUNIT_ASSERT_MESSAGE("Wrong matrix origin.", aMatOrigin == aMatRange.aStart);
891 : }
892 : }
893 3 : }
894 :
895 : }
896 :
897 1 : void ScExportTest::testInlineArrayXLS()
898 : {
899 1 : ScDocShellRef xShell = loadDoc("inline-array.", XLS);
900 1 : CPPUNIT_ASSERT(xShell.Is());
901 :
902 2 : ScDocShellRef xDocSh = saveAndReload(xShell, XLS);
903 1 : xShell->DoClose();
904 1 : CPPUNIT_ASSERT(xDocSh.Is());
905 :
906 1 : ScDocument* pDoc = xDocSh->GetDocument();
907 1 : CPPUNIT_ASSERT(pDoc);
908 :
909 : // B2:C3 contains a matrix.
910 1 : checkMatrixRange(*pDoc, ScRange(1,1,0,2,2,0));
911 :
912 : // B5:D6 contains a matrix.
913 1 : checkMatrixRange(*pDoc, ScRange(1,4,0,3,5,0));
914 :
915 : // B8:C10 as well.
916 1 : checkMatrixRange(*pDoc, ScRange(1,7,0,2,9,0));
917 :
918 2 : xDocSh->DoClose();
919 1 : }
920 :
921 1 : void ScExportTest::testEmbeddedChartXLS()
922 : {
923 1 : ScDocShellRef xShell = loadDoc("embedded-chart.", XLS);
924 1 : CPPUNIT_ASSERT(xShell.Is());
925 :
926 2 : ScDocShellRef xDocSh = saveAndReload(xShell, XLS);
927 1 : xShell->DoClose();
928 1 : CPPUNIT_ASSERT(xDocSh.Is());
929 :
930 1 : ScDocument* pDoc = xDocSh->GetDocument();
931 1 : CPPUNIT_ASSERT(pDoc);
932 :
933 : // Make sure the 2nd sheet is named 'Chart1'.
934 2 : OUString aName;
935 1 : pDoc->GetName(1, aName);
936 1 : CPPUNIT_ASSERT_EQUAL(OUString("Chart1"), aName);
937 :
938 1 : const SdrOle2Obj* pOleObj = getSingleChartObject(*pDoc, 1);
939 1 : CPPUNIT_ASSERT_MESSAGE("Failed to retrieve a chart object from the 2nd sheet.", pOleObj);
940 :
941 2 : ScRangeList aRanges = getChartRanges(*pDoc, *pOleObj);
942 1 : CPPUNIT_ASSERT_MESSAGE("Label range (B3:B5) not found.", aRanges.In(ScRange(1,2,1,1,4,1)));
943 1 : CPPUNIT_ASSERT_MESSAGE("Data label (C2) not found.", aRanges.In(ScAddress(2,1,1)));
944 1 : CPPUNIT_ASSERT_MESSAGE("Data range (C3:C5) not found.", aRanges.In(ScRange(2,2,1,2,4,1)));
945 :
946 2 : xDocSh->DoClose();
947 1 : }
948 :
949 1 : void ScExportTest::testFormulaReferenceXLS()
950 : {
951 1 : ScDocShellRef xShell = loadDoc("formula-reference.", XLS);
952 1 : CPPUNIT_ASSERT(xShell.Is());
953 :
954 2 : ScDocShellRef xDocSh = saveAndReload(xShell, XLS);
955 1 : xShell->DoClose();
956 1 : CPPUNIT_ASSERT(xDocSh.Is());
957 :
958 1 : ScDocument* pDoc = xDocSh->GetDocument();
959 1 : CPPUNIT_ASSERT(pDoc);
960 :
961 1 : if (!checkFormula(*pDoc, ScAddress(3,1,0), "$A$2+$B$2+$C$2"))
962 0 : CPPUNIT_FAIL("Wrong formula in D2");
963 :
964 1 : if (!checkFormula(*pDoc, ScAddress(3,2,0), "A3+B3+C3"))
965 0 : CPPUNIT_FAIL("Wrong formula in D3");
966 :
967 1 : if (!checkFormula(*pDoc, ScAddress(3,5,0), "SUM($A$6:$C$6)"))
968 0 : CPPUNIT_FAIL("Wrong formula in D6");
969 :
970 1 : if (!checkFormula(*pDoc, ScAddress(3,6,0), "SUM(A7:C7)"))
971 0 : CPPUNIT_FAIL("Wrong formula in D7");
972 :
973 1 : if (!checkFormula(*pDoc, ScAddress(3,9,0), "$Two.$A$2+$Two.$B$2+$Two.$C$2"))
974 0 : CPPUNIT_FAIL("Wrong formula in D10");
975 :
976 1 : if (!checkFormula(*pDoc, ScAddress(3,10,0), "$Two.A3+$Two.B3+$Two.C3"))
977 0 : CPPUNIT_FAIL("Wrong formula in D11");
978 :
979 1 : if (!checkFormula(*pDoc, ScAddress(3,13,0), "MIN($Two.$A$2:$C$2)"))
980 0 : CPPUNIT_FAIL("Wrong formula in D14");
981 :
982 1 : if (!checkFormula(*pDoc, ScAddress(3,14,0), "MAX($Two.A3:C3)"))
983 0 : CPPUNIT_FAIL("Wrong formula in D15");
984 :
985 2 : xDocSh->DoClose();
986 1 : }
987 :
988 1 : void ScExportTest::testSheetProtectionXLSX()
989 : {
990 1 : ScDocShellRef xShell = loadDoc("ProtecteSheet1234Pass.", XLSX);
991 1 : CPPUNIT_ASSERT(xShell.Is());
992 :
993 2 : ScDocShellRef xDocSh = saveAndReload(xShell, XLSX);
994 1 : CPPUNIT_ASSERT(xDocSh.Is());
995 :
996 1 : ScDocument* pDoc = xDocSh->GetDocument();
997 1 : CPPUNIT_ASSERT(pDoc);
998 1 : const ScTableProtection* pTabProtect = pDoc->GetTabProtection(0);
999 1 : CPPUNIT_ASSERT(pTabProtect);
1000 1 : if ( pTabProtect )
1001 : {
1002 1 : Sequence<sal_Int8> aHash = pTabProtect->getPasswordHash(PASSHASH_XL);
1003 : // check has
1004 1 : if (aHash.getLength() >= 2)
1005 : {
1006 1 : CPPUNIT_ASSERT( (sal_uInt8)aHash[0] == 204 );
1007 1 : CPPUNIT_ASSERT( (sal_uInt8)aHash[1] == 61 );
1008 : }
1009 : // we could flesh out this check I guess
1010 1 : CPPUNIT_ASSERT ( !pTabProtect->isOptionEnabled( ScTableProtection::OBJECTS ) );
1011 1 : CPPUNIT_ASSERT ( !pTabProtect->isOptionEnabled( ScTableProtection::SCENARIOS ) );
1012 : }
1013 2 : xDocSh->DoClose();
1014 1 : }
1015 :
1016 : namespace {
1017 :
1018 96 : const char* toBorderName( sal_Int16 eStyle )
1019 : {
1020 96 : switch (eStyle)
1021 : {
1022 32 : case table::BorderLineStyle::SOLID: return "SOLID";
1023 8 : case table::BorderLineStyle::DOTTED: return "DOTTED";
1024 8 : case table::BorderLineStyle::DASHED: return "DASHED";
1025 16 : case table::BorderLineStyle::DASH_DOT: return "DASH_DOT";
1026 16 : case table::BorderLineStyle::DASH_DOT_DOT: return "DASH_DOT_DOT";
1027 8 : case table::BorderLineStyle::DOUBLE_THIN: return "DOUBLE_THIN";
1028 8 : case table::BorderLineStyle::FINE_DASHED: return "FINE_DASHED";
1029 : default:
1030 : ;
1031 : }
1032 :
1033 0 : return "";
1034 : }
1035 :
1036 : }
1037 :
1038 2 : void ScExportTest::testExcelCellBorders( sal_uLong nFormatType )
1039 : {
1040 2 : ScDocShellRef xDocSh = loadDoc("cell-borders.", nFormatType);
1041 :
1042 2 : CPPUNIT_ASSERT_MESSAGE("Failed to load file", xDocSh.Is());
1043 2 : ScDocument* pDoc = xDocSh->GetDocument();
1044 :
1045 : struct
1046 : {
1047 : SCROW mnRow;
1048 : sal_Int16 mnStyle;
1049 : long mnWidth;
1050 : } aChecks[] = {
1051 : { 1, table::BorderLineStyle::SOLID, 1L }, // hair
1052 : { 3, table::BorderLineStyle::DOTTED, 15L }, // dotted
1053 : { 5, table::BorderLineStyle::DASH_DOT_DOT, 15L }, // dash dot dot
1054 : { 7, table::BorderLineStyle::DASH_DOT, 15L }, // dash dot
1055 : { 9, table::BorderLineStyle::FINE_DASHED, 15L }, // dashed
1056 : { 11, table::BorderLineStyle::SOLID, 15L }, // thin
1057 : { 13, table::BorderLineStyle::DASH_DOT_DOT, 35L }, // medium dash dot dot
1058 : { 17, table::BorderLineStyle::DASH_DOT, 35L }, // medium dash dot
1059 : { 19, table::BorderLineStyle::DASHED, 35L }, // medium dashed
1060 : { 21, table::BorderLineStyle::SOLID, 35L }, // medium
1061 : { 23, table::BorderLineStyle::SOLID, 50L }, // thick
1062 : { 25, table::BorderLineStyle::DOUBLE_THIN, -1L }, // double (don't check width)
1063 2 : };
1064 :
1065 26 : for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
1066 : {
1067 24 : const editeng::SvxBorderLine* pLine = NULL;
1068 24 : pDoc->GetBorderLines(2, aChecks[i].mnRow, 0, NULL, &pLine, NULL, NULL);
1069 24 : CPPUNIT_ASSERT(pLine);
1070 24 : CPPUNIT_ASSERT_EQUAL(toBorderName(aChecks[i].mnStyle), toBorderName(pLine->GetBorderLineStyle()));
1071 24 : if (aChecks[i].mnWidth >= 0)
1072 22 : CPPUNIT_ASSERT_EQUAL(aChecks[i].mnWidth, pLine->GetWidth());
1073 : }
1074 :
1075 4 : ScDocShellRef xNewDocSh = saveAndReload(xDocSh, nFormatType);
1076 2 : xDocSh->DoClose();
1077 2 : pDoc = xNewDocSh->GetDocument();
1078 26 : for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
1079 : {
1080 24 : const editeng::SvxBorderLine* pLine = NULL;
1081 24 : pDoc->GetBorderLines(2, aChecks[i].mnRow, 0, NULL, &pLine, NULL, NULL);
1082 24 : CPPUNIT_ASSERT(pLine);
1083 24 : CPPUNIT_ASSERT_EQUAL(toBorderName(aChecks[i].mnStyle), toBorderName(pLine->GetBorderLineStyle()));
1084 24 : if (aChecks[i].mnWidth >= 0)
1085 22 : CPPUNIT_ASSERT_EQUAL(aChecks[i].mnWidth, pLine->GetWidth());
1086 : }
1087 :
1088 4 : xNewDocSh->DoClose();
1089 2 : }
1090 :
1091 1 : void ScExportTest::testCellBordersXLS()
1092 : {
1093 1 : testExcelCellBorders(XLS);
1094 1 : }
1095 :
1096 1 : void ScExportTest::testCellBordersXLSX()
1097 : {
1098 1 : testExcelCellBorders(XLSX);
1099 1 : }
1100 :
1101 1 : void ScExportTest::testSheetTabColorsXLSX()
1102 : {
1103 : struct
1104 : {
1105 2 : bool checkContent( ScDocument* pDoc )
1106 : {
1107 :
1108 2 : std::vector<OUString> aTabNames = pDoc->GetAllTableNames();
1109 :
1110 : // green, red, blue, yellow (from left to right).
1111 2 : if (aTabNames.size() != 4)
1112 : {
1113 0 : cerr << "There should be exactly 4 sheets." << endl;
1114 0 : return false;
1115 : }
1116 :
1117 2 : const char* pNames[] = { "Green", "Red", "Blue", "Yellow" };
1118 10 : for (size_t i = 0, n = SAL_N_ELEMENTS(pNames); i < n; ++i)
1119 : {
1120 8 : OUString aExpected = OUString::createFromAscii(pNames[i]);
1121 8 : if (aExpected != aTabNames[i])
1122 : {
1123 0 : cerr << "incorrect sheet name: expected='" << aExpected <<"', actual='" << aTabNames[i] << "'" << endl;
1124 0 : return false;
1125 : }
1126 8 : }
1127 :
1128 : const ColorData aXclColors[] =
1129 : {
1130 : 0x0000B050, // green
1131 : 0x00FF0000, // red
1132 : 0x000070C0, // blue
1133 : 0x00FFFF00, // yellow
1134 2 : };
1135 :
1136 10 : for (size_t i = 0, n = SAL_N_ELEMENTS(aXclColors); i < n; ++i)
1137 : {
1138 8 : if (aXclColors[i] != pDoc->GetTabBgColor(i).GetColor())
1139 : {
1140 0 : cerr << "wrong sheet color for sheet " << i << endl;
1141 0 : return false;
1142 : }
1143 : }
1144 :
1145 2 : return true;
1146 : }
1147 :
1148 : } aTest;
1149 :
1150 1 : ScDocShellRef xDocSh = loadDoc("sheet-tab-color.", XLSX);
1151 1 : CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocSh.Is());
1152 1 : ScDocument* pDoc = xDocSh->GetDocument();
1153 1 : bool bRes = aTest.checkContent(pDoc);
1154 1 : CPPUNIT_ASSERT_MESSAGE("Failed on the initial content check.", bRes);
1155 :
1156 2 : ScDocShellRef xDocSh2 = saveAndReload(xDocSh, XLSX);
1157 1 : CPPUNIT_ASSERT_MESSAGE("Failed to reload file.", xDocSh2.Is());
1158 1 : xDocSh->DoClose();
1159 1 : pDoc = xDocSh2->GetDocument();
1160 1 : bRes = aTest.checkContent(pDoc);
1161 1 : CPPUNIT_ASSERT_MESSAGE("Failed on the content check after reload.", bRes);
1162 :
1163 2 : xDocSh2->DoClose();
1164 1 : }
1165 :
1166 1 : void ScExportTest::testSharedFormulaExportXLS()
1167 : {
1168 : struct
1169 : {
1170 2 : bool checkContent( ScDocument* pDoc )
1171 : {
1172 2 : formula::FormulaGrammar::Grammar eGram = formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1;
1173 2 : pDoc->SetGrammar(eGram);
1174 2 : sc::TokenStringContext aCxt(pDoc, eGram);
1175 :
1176 : // Check the title row.
1177 :
1178 4 : OUString aActual = pDoc->GetString(0,1,0);
1179 4 : OUString aExpected = "Response";
1180 2 : if (aActual != aExpected)
1181 : {
1182 0 : cerr << "Wrong content in A2: expected='" << aExpected << "', actual='" << aActual << "'" << endl;
1183 0 : return false;
1184 : }
1185 :
1186 2 : aActual = pDoc->GetString(1,1,0);
1187 2 : aExpected = "Response";
1188 2 : if (aActual != aExpected)
1189 : {
1190 0 : cerr << "Wrong content in B2: expected='" << aExpected << "', actual='" << aActual << "'" << endl;
1191 0 : return false;
1192 : }
1193 :
1194 : // A3:A12 and B3:B12 are numbers from 1 to 10.
1195 44 : for (SCROW i = 0; i <= 9; ++i)
1196 : {
1197 20 : double fExpected = i + 1.0;
1198 20 : ScAddress aPos(0,i+2,0);
1199 20 : double fActual = pDoc->GetValue(aPos);
1200 20 : if (fExpected != fActual)
1201 : {
1202 0 : cerr << "Wrong value in A" << (i+2) << ": expected=" << fExpected << ", actual=" << fActual << endl;
1203 0 : return false;
1204 : }
1205 :
1206 20 : aPos.IncCol();
1207 20 : ScFormulaCell* pFC = pDoc->GetFormulaCell(aPos);
1208 20 : if (!pFC)
1209 : {
1210 0 : cerr << "B" << (i+2) << " should be a formula cell." << endl;
1211 0 : return false;
1212 : }
1213 :
1214 20 : OUString aFormula = pFC->GetCode()->CreateString(aCxt, aPos);
1215 20 : aExpected = "Coefficients!RC[-1]";
1216 20 : if (aFormula != aExpected)
1217 : {
1218 0 : cerr << "Wrong formula in B" << (i+2) << ": expected='" << aExpected << "', actual='" << aFormula << "'" << endl;
1219 0 : return false;
1220 : }
1221 :
1222 20 : fActual = pDoc->GetValue(aPos);
1223 20 : if (fExpected != fActual)
1224 : {
1225 0 : cerr << "Wrong value in B" << (i+2) << ": expected=" << fExpected << ", actual=" << fActual << endl;
1226 0 : return false;
1227 : }
1228 20 : }
1229 :
1230 4 : return true;
1231 : }
1232 :
1233 : } aTest;
1234 :
1235 1 : ScDocShellRef xDocSh = loadDoc("shared-formula/3d-reference.", ODS);
1236 1 : CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocSh.Is());
1237 1 : ScDocument* pDoc = xDocSh->GetDocument();
1238 :
1239 : // Check the content of the original.
1240 1 : bool bRes = aTest.checkContent(pDoc);
1241 1 : CPPUNIT_ASSERT_MESSAGE("Content check on the original document failed.", bRes);
1242 :
1243 2 : ScDocShellRef xDocSh2 = saveAndReload(xDocSh, XLS);
1244 1 : xDocSh->DoClose();
1245 1 : CPPUNIT_ASSERT_MESSAGE("Failed to reload file.", xDocSh2.Is());
1246 :
1247 1 : pDoc = xDocSh2->GetDocument();
1248 :
1249 : // Check the content of the reloaded. This should be identical.
1250 1 : bRes = aTest.checkContent(pDoc);
1251 1 : CPPUNIT_ASSERT_MESSAGE("Content check on the reloaded document failed.", bRes);
1252 :
1253 2 : xDocSh2->DoClose();
1254 1 : }
1255 :
1256 1 : void ScExportTest::testSharedFormulaExportXLSX()
1257 : {
1258 : struct
1259 : {
1260 3 : bool checkContent( ScDocument* pDoc )
1261 : {
1262 : // B2:B7 should show 1,2,3,4,5,6.
1263 3 : double fExpected = 1.0;
1264 21 : for (SCROW i = 1; i <= 6; ++i, ++fExpected)
1265 : {
1266 18 : ScAddress aPos(1,i,0);
1267 18 : double fVal = pDoc->GetValue(aPos);
1268 18 : if (fVal != fExpected)
1269 : {
1270 0 : cerr << "Wrong value in B" << (i+1) << ": expected=" << fExpected << ", actual=" << fVal << endl;
1271 0 : return false;
1272 : }
1273 : }
1274 :
1275 : // C2:C7 should show 10,20,....,60.
1276 3 : fExpected = 10.0;
1277 21 : for (SCROW i = 1; i <= 6; ++i, fExpected+=10.0)
1278 : {
1279 18 : ScAddress aPos(2,i,0);
1280 18 : double fVal = pDoc->GetValue(aPos);
1281 18 : if (fVal != fExpected)
1282 : {
1283 0 : cerr << "Wrong value in C" << (i+1) << ": expected=" << fExpected << ", actual=" << fVal << endl;
1284 0 : return false;
1285 : }
1286 : }
1287 :
1288 : // D2:D7 should show 1,2,...,6.
1289 3 : fExpected = 1.0;
1290 21 : for (SCROW i = 1; i <= 6; ++i, ++fExpected)
1291 : {
1292 18 : ScAddress aPos(3,i,0);
1293 18 : double fVal = pDoc->GetValue(aPos);
1294 18 : if (fVal != fExpected)
1295 : {
1296 0 : cerr << "Wrong value in D" << (i+1) << ": expected=" << fExpected << ", actual=" << fVal << endl;
1297 0 : return false;
1298 : }
1299 : }
1300 :
1301 3 : return true;
1302 : }
1303 :
1304 : } aTest;
1305 :
1306 1 : ScDocShellRef xDocSh = loadDoc("shared-formula/3d-reference.", XLSX);
1307 1 : CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocSh.Is());
1308 1 : ScDocument* pDoc = xDocSh->GetDocument();
1309 :
1310 1 : bool bRes = aTest.checkContent(pDoc);
1311 1 : CPPUNIT_ASSERT_MESSAGE("Content check on the initial document failed.", bRes);
1312 :
1313 1 : pDoc->CalcAll(); // Recalculate to flush all cached results.
1314 1 : bRes = aTest.checkContent(pDoc);
1315 1 : CPPUNIT_ASSERT_MESSAGE("Content check on the initial recalculated document failed.", bRes);
1316 :
1317 : // Save and reload, and check the content again.
1318 2 : ScDocShellRef xDocSh2 = saveAndReload(xDocSh, XLSX);
1319 1 : xDocSh->DoClose();
1320 :
1321 1 : CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocSh2.Is());
1322 1 : pDoc = xDocSh2->GetDocument();
1323 1 : pDoc->CalcAll(); // Recalculate to flush all cached results.
1324 :
1325 1 : bRes = aTest.checkContent(pDoc);
1326 1 : CPPUNIT_ASSERT_MESSAGE("Content check on the reloaded document failed.", bRes);
1327 :
1328 2 : xDocSh2->DoClose();
1329 1 : }
1330 :
1331 1 : void ScExportTest::testSharedFormulaStringResultExportXLSX()
1332 : {
1333 : struct
1334 : {
1335 3 : bool checkContent( ScDocument* pDoc )
1336 : {
1337 : {
1338 : // B2:B7 should show A,B,....,F.
1339 3 : const char* expected[] = { "A", "B", "C", "D", "E", "F" };
1340 21 : for (SCROW i = 0; i <= 5; ++i)
1341 : {
1342 18 : ScAddress aPos(1,i+1,0);
1343 18 : OUString aStr = pDoc->GetString(aPos);
1344 36 : OUString aExpected = OUString::createFromAscii(expected[i]);
1345 18 : if (aStr != aExpected)
1346 : {
1347 0 : cerr << "Wrong value in B" << (i+2) << ": expected='" << aExpected << "', actual='" << aStr << "'" << endl;
1348 0 : return false;
1349 : }
1350 18 : }
1351 : }
1352 :
1353 : {
1354 : // C2:C7 should show AA,BB,....,FF.
1355 3 : const char* expected[] = { "AA", "BB", "CC", "DD", "EE", "FF" };
1356 21 : for (SCROW i = 0; i <= 5; ++i)
1357 : {
1358 18 : ScAddress aPos(2,i+1,0);
1359 18 : OUString aStr = pDoc->GetString(aPos);
1360 36 : OUString aExpected = OUString::createFromAscii(expected[i]);
1361 18 : if (aStr != aExpected)
1362 : {
1363 0 : cerr << "Wrong value in C" << (i+2) << ": expected='" << aExpected << "', actual='" << aStr << "'" << endl;
1364 0 : return false;
1365 : }
1366 18 : }
1367 : }
1368 :
1369 3 : return true;
1370 : }
1371 :
1372 : } aTest;
1373 :
1374 1 : ScDocShellRef xDocSh = loadDoc("shared-formula/text-results.", XLSX);
1375 1 : CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocSh.Is());
1376 1 : ScDocument* pDoc = xDocSh->GetDocument();
1377 :
1378 : // Check content without re-calculation, to test cached formula results.
1379 1 : bool bRes = aTest.checkContent(pDoc);
1380 1 : CPPUNIT_ASSERT_MESSAGE("Content check on the initial document failed.", bRes);
1381 :
1382 : // Now, re-calculate and check the results.
1383 1 : pDoc->CalcAll();
1384 1 : bRes = aTest.checkContent(pDoc);
1385 1 : CPPUNIT_ASSERT_MESSAGE("Content check on the initial recalculated document failed.", bRes);
1386 :
1387 : // Reload and check again.
1388 2 : ScDocShellRef xDocSh2 = saveAndReload(xDocSh, XLSX);
1389 1 : xDocSh->DoClose();
1390 1 : CPPUNIT_ASSERT_MESSAGE("Failed to re-load file.", xDocSh2.Is());
1391 1 : pDoc = xDocSh2->GetDocument();
1392 :
1393 1 : bRes = aTest.checkContent(pDoc);
1394 1 : CPPUNIT_ASSERT_MESSAGE("Content check on the reloaded document failed.", bRes);
1395 :
1396 2 : xDocSh2->DoClose();
1397 1 : }
1398 :
1399 24 : ScExportTest::ScExportTest()
1400 24 : : ScBootstrapFixture("/sc/qa/unit/data")
1401 : {
1402 24 : }
1403 :
1404 24 : void ScExportTest::setUp()
1405 : {
1406 24 : test::BootstrapFixture::setUp();
1407 :
1408 : // This is a bit of a fudge, we do this to ensure that ScGlobals::ensure,
1409 : // which is a private symbol to us, gets called
1410 48 : m_xCalcComponent =
1411 72 : getMultiServiceFactory()->createInstance("com.sun.star.comp.Calc.SpreadsheetDocument");
1412 24 : CPPUNIT_ASSERT_MESSAGE("no calc component!", m_xCalcComponent.is());
1413 24 : }
1414 :
1415 24 : void ScExportTest::tearDown()
1416 : {
1417 24 : uno::Reference< lang::XComponent >( m_xCalcComponent, UNO_QUERY_THROW )->dispose();
1418 24 : test::BootstrapFixture::tearDown();
1419 24 : }
1420 :
1421 1 : CPPUNIT_TEST_SUITE_REGISTRATION(ScExportTest);
1422 :
1423 4 : CPPUNIT_PLUGIN_IMPLEMENT();
1424 :
1425 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|