Bump version to 5.0-14
[LibreOffice.git] / sc / qa / unit / filters-test.cxx
blobbfb2a8acf34cdfc9ccabe19c46efa40922654d6b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <sal/config.h>
11 #include <unotest/filters-test.hxx>
12 #include <test/bootstrapfixture.hxx>
13 #include <rtl/strbuf.hxx>
14 #include <osl/file.hxx>
16 #include "scdll.hxx"
17 #include <sfx2/app.hxx>
18 #include <sfx2/docfilt.hxx>
19 #include <sfx2/docfile.hxx>
20 #include <sfx2/sfxmodelfactory.hxx>
21 #include <svl/stritem.hxx>
23 #include "helper/qahelper.hxx"
25 #include "docsh.hxx"
26 #include "inputopt.hxx"
27 #include "postit.hxx"
28 #include "patattr.hxx"
29 #include "scitems.hxx"
30 #include "document.hxx"
31 #include "cellform.hxx"
32 #include "drwlayer.hxx"
33 #include "userdat.hxx"
34 #include "formulacell.hxx"
35 #include "tabprotection.hxx"
36 #include <dbdocfun.hxx>
37 #include <globalnames.hxx>
38 #include <dbdata.hxx>
39 #include <sortparam.hxx>
40 #include "scopetools.hxx"
42 #include <svx/svdpage.hxx>
44 using namespace ::com::sun::star;
45 using namespace ::com::sun::star::uno;
47 /* Implementation of Filters test */
49 class ScFiltersTest
50 : public test::FiltersTest
51 , public ScBootstrapFixture
53 public:
54 ScFiltersTest();
56 virtual void setUp() SAL_OVERRIDE;
57 virtual void tearDown() SAL_OVERRIDE;
59 virtual bool load( const OUString &rFilter, const OUString &rURL,
60 const OUString &rUserData, SfxFilterFlags nFilterFlags,
61 SotClipboardFormatId nClipboardID, unsigned int nFilterVersion) SAL_OVERRIDE;
62 /**
63 * Ensure CVEs remain unbroken
65 void testCVEs();
67 //ods, xls, xlsx filter tests
68 void testRangeNameODS(); // only test ods here, xls and xlsx in subsequent_filters-test
69 void testContentODS();
70 void testContentXLS();
71 void testContentXLSX();
72 void testContentXLSXStrict(); // strict OOXML
73 void testContentLotus123();
74 void testContentDIF();
75 void testContentXLSB();
76 //void testContentXLS_XML();
77 void testSharedFormulaXLS();
78 void testSharedFormulaXLSX();
79 void testSheetNamesXLSX();
80 void testLegacyCellAnchoredRotatedShape();
81 void testEnhancedProtectionXLS();
82 void testEnhancedProtectionXLSX();
83 void testSortWithSharedFormulasODS();
84 void testSortWithSheetExternalReferencesODS();
85 void testSortWithSheetExternalReferencesODS_Impl( ScDocShellRef xDocShRef, SCROW nRow1, SCROW nRow2,
86 bool bCheckRelativeInSheet );
88 CPPUNIT_TEST_SUITE(ScFiltersTest);
89 CPPUNIT_TEST(testCVEs);
90 CPPUNIT_TEST(testRangeNameODS);
91 CPPUNIT_TEST(testContentODS);
92 CPPUNIT_TEST(testContentXLS);
93 CPPUNIT_TEST(testContentXLSX);
94 CPPUNIT_TEST(testContentXLSXStrict);
95 CPPUNIT_TEST(testContentLotus123);
96 CPPUNIT_TEST(testContentDIF);
97 CPPUNIT_TEST(testContentXLSB);
98 //CPPUNIT_TEST(testContentXLS_XML);
99 CPPUNIT_TEST(testSharedFormulaXLS);
100 CPPUNIT_TEST(testSharedFormulaXLSX);
101 CPPUNIT_TEST(testSheetNamesXLSX);
102 CPPUNIT_TEST(testLegacyCellAnchoredRotatedShape);
103 CPPUNIT_TEST(testEnhancedProtectionXLS);
104 CPPUNIT_TEST(testEnhancedProtectionXLSX);
105 CPPUNIT_TEST(testSortWithSharedFormulasODS);
106 CPPUNIT_TEST(testSortWithSheetExternalReferencesODS);
108 CPPUNIT_TEST_SUITE_END();
110 private:
111 uno::Reference<uno::XInterface> m_xCalcComponent;
112 bool mbUpdateReferenceOnSort; ///< Remember the configuration option so that we can set it back.
115 bool ScFiltersTest::load(const OUString &rFilter, const OUString &rURL,
116 const OUString &rUserData, SfxFilterFlags nFilterFlags,
117 SotClipboardFormatId nClipboardID, unsigned int nFilterVersion)
119 ScDocShellRef xDocShRef = ScBootstrapFixture::load(rURL, rFilter, rUserData,
120 OUString(), nFilterFlags, nClipboardID, nFilterVersion );
121 bool bLoaded = xDocShRef.Is();
122 //reference counting of ScDocShellRef is very confused.
123 if (bLoaded)
124 xDocShRef->DoClose();
125 return bLoaded;
128 void ScFiltersTest::testCVEs()
130 #ifndef DISABLE_CVE_TESTS
131 testDir(OUString("Quattro Pro 6.0"),
132 getURLFromSrc("/sc/qa/unit/data/qpro/"), OUString());
134 //warning, the current "sylk filter" in sc (docsh.cxx) automatically
135 //chains on failure on trying as csv, rtf, etc. so "success" may
136 //not indicate that it imported as .slk.
137 testDir(OUString("SYLK"),
138 getURLFromSrc("/sc/qa/unit/data/slk/"), OUString());
140 testDir(OUString("MS Excel 97"),
141 getURLFromSrc("/sc/qa/unit/data/xls/"), OUString());
143 testDir(OUString("dBase"),
144 getURLFromSrc("/sc/qa/unit/data/dbf/"), OUString());
146 testDir(OUString("Lotus"),
147 getURLFromSrc("/sc/qa/unit/data/wks/"), OUString());
149 #endif
152 namespace {
154 void testRangeNameImpl(ScDocument& rDoc)
156 //check one range data per sheet and one global more detailed
157 //add some more checks here
158 ScRangeData* pRangeData = rDoc.GetRangeName()->findByUpperName(OUString("GLOBAL1"));
159 CPPUNIT_ASSERT_MESSAGE("range name Global1 not found", pRangeData);
160 double aValue;
161 rDoc.GetValue(1,0,0,aValue);
162 CPPUNIT_ASSERT_MESSAGE("range name Global1 should reference Sheet1.A1", aValue == 1);
163 pRangeData = rDoc.GetRangeName(0)->findByUpperName(OUString("LOCAL1"));
164 CPPUNIT_ASSERT_MESSAGE("range name Sheet1.Local1 not found", pRangeData);
165 rDoc.GetValue(1,2,0,aValue);
166 CPPUNIT_ASSERT_MESSAGE("range name Sheet1.Local1 should reference Sheet1.A3", aValue == 3);
167 pRangeData = rDoc.GetRangeName(1)->findByUpperName(OUString("LOCAL2"));
168 CPPUNIT_ASSERT_MESSAGE("range name Sheet2.Local2 not found", pRangeData);
169 //check for correct results for the remaining formulas
170 rDoc.GetValue(1,1,0, aValue);
171 CPPUNIT_ASSERT_MESSAGE("=global2 should be 2", aValue == 2);
172 rDoc.GetValue(1,3,0, aValue);
173 CPPUNIT_ASSERT_MESSAGE("=local2 should be 4", aValue == 4);
174 rDoc.GetValue(2,0,0, aValue);
175 CPPUNIT_ASSERT_MESSAGE("=SUM(global3) should be 10", aValue == 10);
180 void ScFiltersTest::testRangeNameODS()
182 ScDocShellRef xDocSh = loadDoc("named-ranges-global.", ODS);
184 CPPUNIT_ASSERT_MESSAGE("Failed to load named-ranges-globals.*", xDocSh.Is());
186 xDocSh->DoHardRecalc(true);
188 ScDocument& rDoc = xDocSh->GetDocument();
189 testRangeNameImpl(rDoc);
191 OUString aSheet2CSV("rangeExp_Sheet2.");
192 OUString aCSVPath;
193 createCSVPath( aSheet2CSV, aCSVPath );
194 testFile( aCSVPath, rDoc, 1);
195 xDocSh->DoClose();
198 namespace {
200 void testContentImpl(ScDocument& rDoc, sal_Int32 nFormat ) //same code for ods, xls, xlsx
202 double fValue;
203 //check value import
204 rDoc.GetValue(0,0,0,fValue);
205 CPPUNIT_ASSERT_MESSAGE("value not imported correctly", fValue == 1);
206 rDoc.GetValue(0,1,0,fValue);
207 CPPUNIT_ASSERT_MESSAGE("value not imported correctly", fValue == 2);
208 OUString aString = rDoc.GetString(1, 0, 0);
210 //check string import
211 CPPUNIT_ASSERT_MESSAGE("string imported not correctly", aString == "String1");
212 aString = rDoc.GetString(1, 1, 0);
213 CPPUNIT_ASSERT_MESSAGE("string not imported correctly", aString == "String2");
215 //check basic formula import
216 // in case of DIF it just contains values
217 rDoc.GetValue(2,0,0,fValue);
218 CPPUNIT_ASSERT_MESSAGE("=2*3", fValue == 6);
219 rDoc.GetValue(2,1,0,fValue);
220 CPPUNIT_ASSERT_MESSAGE("=2+3", fValue == 5);
221 rDoc.GetValue(2,2,0,fValue);
222 CPPUNIT_ASSERT_MESSAGE("=2-3", fValue == -1);
223 rDoc.GetValue(2,3,0,fValue);
224 CPPUNIT_ASSERT_MESSAGE("=C1+C2", fValue == 11);
226 //check merged cells import
227 if(nFormat != LOTUS123 && nFormat != DIF)
229 SCCOL nCol = 4;
230 SCROW nRow = 1;
231 rDoc.ExtendMerge(4, 1, nCol, nRow, 0, false);
232 CPPUNIT_ASSERT_MESSAGE("merged cells are not imported", nCol == 5 && nRow == 2);
234 //check notes import
235 ScAddress aAddress(7, 2, 0);
236 ScPostIt* pNote = rDoc.GetNote(aAddress);
237 CPPUNIT_ASSERT_MESSAGE("note not imported", pNote);
238 CPPUNIT_ASSERT_EQUAL_MESSAGE("note text not imported correctly", pNote->GetText(), OUString("Test"));
241 //add additional checks here
246 void ScFiltersTest::testContentODS()
248 ScDocShellRef xDocSh = loadDoc("universal-content.", ODS);
249 xDocSh->DoHardRecalc(true);
251 ScDocument& rDoc = xDocSh->GetDocument();
252 testContentImpl(rDoc, ODS);
253 xDocSh->DoClose();
256 void ScFiltersTest::testContentXLS()
258 ScDocShellRef xDocSh = loadDoc("universal-content.", XLS);
259 xDocSh->DoHardRecalc(true);
261 ScDocument& rDoc = xDocSh->GetDocument();
262 testContentImpl(rDoc, XLS);
263 xDocSh->DoClose();
266 void ScFiltersTest::testContentXLSX()
268 ScDocShellRef xDocSh = loadDoc("universal-content.", XLSX);
269 xDocSh->DoHardRecalc(true);
271 ScDocument& rDoc = xDocSh->GetDocument();
272 testContentImpl(rDoc, XLSX);
273 xDocSh->DoClose();
276 void ScFiltersTest::testContentXLSXStrict()
278 ScDocShellRef xDocSh = loadDoc("universal-content-strict.", XLSX);
279 xDocSh->DoHardRecalc(true);
281 ScDocument& rDoc = xDocSh->GetDocument();
282 testContentImpl(rDoc, XLSX);
283 xDocSh->DoClose();
286 void ScFiltersTest::testContentLotus123()
288 ScDocShellRef xDocSh = loadDoc("universal-content.", LOTUS123);
289 xDocSh->DoHardRecalc(true);
291 ScDocument& rDoc = xDocSh->GetDocument();
292 CPPUNIT_ASSERT(&rDoc);
293 testContentImpl(rDoc, LOTUS123);
294 xDocSh->DoClose();
297 void ScFiltersTest::testContentDIF()
299 ScDocShellRef xDocSh = loadDoc("universal-content.", DIF);
301 ScDocument& rDoc = xDocSh->GetDocument();
302 CPPUNIT_ASSERT(&rDoc);
303 xDocSh->DoClose();
306 void ScFiltersTest::testContentXLSB()
308 ScDocShellRef xDocSh = loadDoc("universal-content.", XLSB);
309 xDocSh->DoHardRecalc(true);
311 ScDocument& rDoc = xDocSh->GetDocument();
312 testContentImpl(rDoc, XLSB);
313 xDocSh->DoClose();
316 // void ScFiltersTest::testContentXLS_XML()
317 // {
318 // ScDocShellRef xDocSh = loadDoc("universal-content.", XLS_XML);
319 // CPPUNIT_ASSERT(xDocSh);
321 // ScDocument& rDoc = xDocSh->GetDocument();
322 // CPPUNIT_ASSERT(&rDoc);
323 // testContentImpl(pDoc, XLS_XML);
324 // xDocSh->DoClose();
325 // }
327 void ScFiltersTest::testSharedFormulaXLS()
329 ScDocShellRef xDocSh = loadDoc("shared-formula/basic.", XLS);
330 CPPUNIT_ASSERT(xDocSh.Is());
331 ScDocument& rDoc = xDocSh->GetDocument();
332 xDocSh->DoHardRecalc(true);
333 // Check the results of formula cells in the shared formula range.
334 for (SCROW i = 1; i <= 18; ++i)
336 double fVal = rDoc.GetValue(ScAddress(1,i,0));
337 double fCheck = i*10.0;
338 CPPUNIT_ASSERT_EQUAL(fCheck, fVal);
341 ScFormulaCell* pCell = rDoc.GetFormulaCell(ScAddress(1,18,0));
342 CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pCell);
343 ScFormulaCellGroupRef xGroup = pCell->GetCellGroup();
344 CPPUNIT_ASSERT_MESSAGE("This cell should be a part of a cell group.", xGroup);
345 CPPUNIT_ASSERT_MESSAGE("Incorrect group geometry.", xGroup->mpTopCell->aPos.Row() == 1 && xGroup->mnLength == 18);
347 xDocSh->DoClose();
349 // The following file contains shared formula whose range is inaccurate.
350 // Excel can easily mess up shared formula ranges, so we need to be able
351 // to handle these wrong ranges that Excel stores.
353 xDocSh = loadDoc("shared-formula/gap.", XLS);
354 CPPUNIT_ASSERT(xDocSh.Is());
355 ScDocument& rDoc2 = xDocSh->GetDocument();
356 rDoc2.CalcAll();
358 if (!checkFormula(rDoc2, ScAddress(1,0,0), "A1*20"))
359 CPPUNIT_FAIL("Wrong formula.");
361 if (!checkFormula(rDoc2, ScAddress(1,1,0), "A2*20"))
362 CPPUNIT_FAIL("Wrong formula.");
364 if (!checkFormula(rDoc2, ScAddress(1,2,0), "A3*20"))
365 CPPUNIT_FAIL("Wrong formula.");
367 // There is an intentional gap at row 4.
369 if (!checkFormula(rDoc2, ScAddress(1,4,0), "A5*20"))
370 CPPUNIT_FAIL("Wrong formula.");
372 if (!checkFormula(rDoc2, ScAddress(1,5,0), "A6*20"))
373 CPPUNIT_FAIL("Wrong formula.");
375 if (!checkFormula(rDoc2, ScAddress(1,6,0), "A7*20"))
376 CPPUNIT_FAIL("Wrong formula.");
378 if (!checkFormula(rDoc2, ScAddress(1,7,0), "A8*20"))
379 CPPUNIT_FAIL("Wrong formula.");
381 // We re-group formula cells on load. Let's check that as well.
383 ScFormulaCell* pFC = rDoc2.GetFormulaCell(ScAddress(1,0,0));
384 CPPUNIT_ASSERT_MESSAGE("Failed to fetch formula cell.", pFC);
385 CPPUNIT_ASSERT_MESSAGE("This should be the top cell in formula group.", pFC->IsSharedTop());
386 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
388 pFC = rDoc2.GetFormulaCell(ScAddress(1,4,0));
389 CPPUNIT_ASSERT_MESSAGE("Failed to fetch formula cell.", pFC);
390 CPPUNIT_ASSERT_MESSAGE("This should be the top cell in formula group.", pFC->IsSharedTop());
391 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
393 xDocSh->DoClose();
396 void ScFiltersTest::testSharedFormulaXLSX()
398 ScDocShellRef xDocSh = loadDoc("shared-formula/basic.", XLSX);
399 ScDocument& rDoc = xDocSh->GetDocument();
400 CPPUNIT_ASSERT(&rDoc);
401 xDocSh->DoHardRecalc(true);
402 // Check the results of formula cells in the shared formula range.
403 for (SCROW i = 1; i <= 18; ++i)
405 double fVal = rDoc.GetValue(ScAddress(1,i,0));
406 double fCheck = i*10.0;
407 CPPUNIT_ASSERT_EQUAL(fCheck, fVal);
410 ScFormulaCell* pCell = rDoc.GetFormulaCell(ScAddress(1,18,0));
411 CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pCell);
412 ScFormulaCellGroupRef xGroup = pCell->GetCellGroup();
413 CPPUNIT_ASSERT_MESSAGE("This cell should be a part of a cell group.", xGroup);
414 CPPUNIT_ASSERT_MESSAGE("Incorrect group geometry.", xGroup->mpTopCell->aPos.Row() == 1 && xGroup->mnLength == 18);
416 xDocSh->DoClose();
419 void ScFiltersTest::testSheetNamesXLSX()
421 ScDocShellRef xDocSh = loadDoc("sheet-names.", XLSX);
422 ScDocument& rDoc = xDocSh->GetDocument();
424 std::vector<OUString> aTabNames = rDoc.GetAllTableNames();
425 CPPUNIT_ASSERT_MESSAGE("The document should have 5 sheets in total.", aTabNames.size() == 5);
426 CPPUNIT_ASSERT_EQUAL(OUString("S&P"), aTabNames[0]);
427 CPPUNIT_ASSERT_EQUAL(OUString("Sam's Club"), aTabNames[1]);
428 CPPUNIT_ASSERT_EQUAL(OUString("\"The Sheet\""), aTabNames[2]);
429 CPPUNIT_ASSERT_EQUAL(OUString("A<B"), aTabNames[3]);
430 CPPUNIT_ASSERT_EQUAL(OUString("C>D"), aTabNames[4]);
432 xDocSh->DoClose();
435 void impl_testLegacyCellAnchoredRotatedShape( ScDocument& rDoc, Rectangle& aRect, ScDrawObjData& aAnchor, long TOLERANCE = 30 /* 30 hmm */ )
437 ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
438 CPPUNIT_ASSERT_MESSAGE("No drawing layer.", pDrawLayer);
439 SdrPage* pPage = pDrawLayer->GetPage(0);
440 CPPUNIT_ASSERT_MESSAGE("No page instance for the 1st sheet.", pPage);
441 CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(1), pPage->GetObjCount() );
443 SdrObject* pObj = pPage->GetObj(0);
444 const Rectangle& aSnap = pObj->GetSnapRect();
445 printf("expected height %ld actual %ld\n", aRect.GetHeight(), aSnap.GetHeight() );
446 CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRect.GetHeight(), aSnap.GetHeight(), TOLERANCE ) );
447 printf("expected width %ld actual %ld\n", aRect.GetWidth(), aSnap.GetWidth() );
448 CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRect.GetWidth(), aSnap.GetWidth(), TOLERANCE ) );
449 printf("expected left %ld actual %ld\n", aRect.Left(), aSnap.Left() );
450 CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRect.Left(), aSnap.Left(), TOLERANCE ) );
451 printf("expected right %ld actual %ld\n", aRect.Top(), aSnap.Top() );
452 CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRect.Top(), aSnap.Top(), TOLERANCE ) );
454 ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
455 CPPUNIT_ASSERT_MESSAGE("expected object meta data", pData);
456 printf("expected startrow %" SAL_PRIdINT32 " actual %" SAL_PRIdINT32 "\n", aAnchor.maStart.Row(), pData->maStart.Row() );
457 CPPUNIT_ASSERT_EQUAL( aAnchor.maStart.Row(), pData->maStart.Row() );
458 printf("expected startcol %d actual %d\n", aAnchor.maStart.Col(), pData->maStart.Col() );
459 CPPUNIT_ASSERT_EQUAL( aAnchor.maStart.Col(), pData->maStart.Col() );
460 printf("expected endrow %" SAL_PRIdINT32 " actual %" SAL_PRIdINT32 "\n", aAnchor.maEnd.Row(), pData->maEnd.Row() );
461 CPPUNIT_ASSERT_EQUAL( aAnchor.maEnd.Row(), pData->maEnd.Row() );
462 printf("expected endcol %d actual %d\n", aAnchor.maEnd.Col(), pData->maEnd.Col() );
463 CPPUNIT_ASSERT_EQUAL( aAnchor.maEnd.Col(), pData->maEnd.Col() );
466 void ScFiltersTest::testLegacyCellAnchoredRotatedShape()
469 // This example doc contains cell anchored shape that is rotated, the
470 // rotated shape is in fact cliped by the sheet boundries ( and thus
471 // is a good edge case test to see if we import it still correctly )
472 ScDocShellRef xDocSh = loadDoc("legacycellanchoredrotatedclippedshape.", ODS);
474 ScDocument& rDoc = xDocSh->GetDocument();
475 CPPUNIT_ASSERT(&rDoc);
476 // ensure the imported legacy rotated shape is in the expected position
477 Rectangle aRect( 6000, -2000, 8000, 4000 );
478 // ensure the imported ( and converted ) anchor ( note we internally now store the anchor in
479 // terms of the rotated shape ) is more or less contains the correct info
480 ScDrawObjData aAnchor;
481 aAnchor.maStart.SetRow( 0 );
482 aAnchor.maStart.SetCol( 5 );
483 aAnchor.maEnd.SetRow( 3 );
484 aAnchor.maEnd.SetCol( 7 );
485 impl_testLegacyCellAnchoredRotatedShape( rDoc, aRect, aAnchor );
486 // test save and reload
487 // for some reason having this test in subsequent_export-test.cxx causes
488 // a core dump in editeng ( so moved to here )
489 xDocSh = saveAndReload( &(*xDocSh), ODS);
490 ScDocument& rDoc2 = xDocSh->GetDocument();
491 CPPUNIT_ASSERT(&rDoc2);
492 impl_testLegacyCellAnchoredRotatedShape( rDoc2, aRect, aAnchor );
494 xDocSh->DoClose();
497 // This example doc contains cell anchored shape that is rotated, the
498 // rotated shape is in fact clipped by the sheet boundries, additionally
499 // the shape is completely hidden because the rows the shape occupies
500 // are hidden
501 ScDocShellRef xDocSh = loadDoc("legacycellanchoredrotatedhiddenshape.", ODS, true);
502 ScDocument& rDoc = xDocSh->GetDocument();
503 CPPUNIT_ASSERT(&rDoc);
504 // ensure the imported legacy rotated shape is in the expected position
505 // when a shape is fully hidden reloading seems to result is in some errors, usually
506 // ( same but different error happens pre-patch ) - we should do better here, I regard it
507 // as a pre-existing bug though (#FIXME)
508 //Rectangle aRect( 6000, -2000, 8000, 4000 ); // proper dimensions
509 Rectangle aRect( 6000, -2000, 7430, 4000 );
510 // ensure the imported (and converted) anchor (note we internally now store the anchor in
511 // terms of the rotated shape) is more or less contains the correct info
512 ScDrawObjData aAnchor;
513 aAnchor.maStart.SetRow( 0 );
514 aAnchor.maStart.SetCol( 5 );
515 aAnchor.maEnd.SetRow( 3 );
516 aAnchor.maEnd.SetCol( 7 );
517 rDoc.ShowRows(0, 9, 0, true); // show relavent rows
518 rDoc.SetDrawPageSize(0); // trigger recalcpos
520 // apply hefty (1 mm) tolerance here, as some opensuse tinderbox
521 // failing
522 impl_testLegacyCellAnchoredRotatedShape( rDoc, aRect, aAnchor, 100 );
524 xDocSh->DoClose();
527 // This example doc contains cell anchored shape that is rotated
528 ScDocShellRef xDocSh = loadDoc("legacycellanchoredrotatedshape.", ODS);
530 ScDocument& rDoc = xDocSh->GetDocument();
531 CPPUNIT_ASSERT(&rDoc);
532 // ensure the imported legacy rotated shape is in the expected position
533 Rectangle aRect( 6000, 3000, 8000, 9000 );
534 // ensure the imported (and converted) anchor (note we internally now store the anchor in
535 // terms of the rotated shape) more or less contains the correct info
537 ScDrawObjData aAnchor;
538 aAnchor.maStart.SetRow( 3 );
539 aAnchor.maStart.SetCol( 6 );
540 aAnchor.maEnd.SetRow( 9 );
541 aAnchor.maEnd.SetCol( 7 );
542 // test import
543 impl_testLegacyCellAnchoredRotatedShape( rDoc, aRect, aAnchor );
544 // test save and reload
545 xDocSh = saveAndReload( &(*xDocSh), ODS);
546 ScDocument& rDoc2 = xDocSh->GetDocument();
547 CPPUNIT_ASSERT(&rDoc2);
548 impl_testLegacyCellAnchoredRotatedShape( rDoc2, aRect, aAnchor );
550 xDocSh->DoClose();
554 void testEnhancedProtectionImpl( ScDocument& rDoc )
556 const ScTableProtection* pProt = rDoc.GetTabProtection(0);
558 CPPUNIT_ASSERT( pProt);
560 CPPUNIT_ASSERT( !pProt->isBlockEditable( ScRange( 0, 0, 0, 0, 0, 0))); // locked
561 CPPUNIT_ASSERT( pProt->isBlockEditable( ScRange( 0, 1, 0, 0, 1, 0))); // editable without password
562 CPPUNIT_ASSERT( pProt->isBlockEditable( ScRange( 0, 2, 0, 0, 2, 0))); // editable without password
563 CPPUNIT_ASSERT( !pProt->isBlockEditable( ScRange( 0, 3, 0, 0, 3, 0))); // editable with password "foo"
564 CPPUNIT_ASSERT( !pProt->isBlockEditable( ScRange( 0, 4, 0, 0, 4, 0))); // editable with descriptor
565 CPPUNIT_ASSERT( !pProt->isBlockEditable( ScRange( 0, 5, 0, 0, 5, 0))); // editable with descriptor and password "foo"
566 CPPUNIT_ASSERT( pProt->isBlockEditable( ScRange( 0, 1, 0, 0, 2, 0))); // union of two different editables
567 CPPUNIT_ASSERT( !pProt->isBlockEditable( ScRange( 0, 0, 0, 0, 1, 0))); // union of locked and editable
568 CPPUNIT_ASSERT( !pProt->isBlockEditable( ScRange( 0, 2, 0, 0, 3, 0))); // union of editable and password editable
571 void ScFiltersTest::testEnhancedProtectionXLS()
573 ScDocShellRef xDocSh = loadDoc("enhanced-protection.", XLS);
574 CPPUNIT_ASSERT(xDocSh.Is());
575 ScDocument& rDoc = xDocSh->GetDocument();
577 testEnhancedProtectionImpl( rDoc);
579 xDocSh->DoClose();
582 void ScFiltersTest::testEnhancedProtectionXLSX()
584 ScDocShellRef xDocSh = loadDoc("enhanced-protection.", XLSX);
585 CPPUNIT_ASSERT(xDocSh.Is());
586 ScDocument& rDoc = xDocSh->GetDocument();
588 testEnhancedProtectionImpl( rDoc);
590 xDocSh->DoClose();
593 void ScFiltersTest::testSortWithSharedFormulasODS()
595 ScDocShellRef xDocSh = loadDoc("shared-formula/sort-crash.", ODS, true);
596 CPPUNIT_ASSERT(xDocSh.Is());
597 ScDocument& rDoc = xDocSh->GetDocument();
599 // E2:E10 should be shared.
600 const ScFormulaCell* pFC = rDoc.GetFormulaCell(ScAddress(4,1,0));
601 CPPUNIT_ASSERT(pFC);
602 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
603 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(9), pFC->GetSharedLength());
605 // E12:E17 should be shared.
606 pFC = rDoc.GetFormulaCell(ScAddress(4,11,0));
607 CPPUNIT_ASSERT(pFC);
608 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(11), pFC->GetSharedTopRow());
609 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), pFC->GetSharedLength());
611 // Set A1:E17 as an anonymous database range to sheet, or else Calc would
612 // refuse to sort the range.
613 ScDBData* pDBData = new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 4, 16, true, true);
614 rDoc.SetAnonymousDBData(0, pDBData);
616 // Sort ascending by Column E.
618 ScSortParam aSortData;
619 aSortData.nCol1 = 0;
620 aSortData.nCol2 = 4;
621 aSortData.nRow1 = 0;
622 aSortData.nRow2 = 16;
623 aSortData.bHasHeader = true;
624 aSortData.maKeyState[0].bDoSort = true;
625 aSortData.maKeyState[0].nField = 4;
626 aSortData.maKeyState[0].bAscending = true;
628 // Do the sorting. This should not crash.
629 ScDBDocFunc aFunc(*xDocSh);
630 bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
631 CPPUNIT_ASSERT(bSorted);
633 // After the sort, E2:E16 should be shared.
634 pFC = rDoc.GetFormulaCell(ScAddress(4,1,0));
635 CPPUNIT_ASSERT(pFC);
636 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
637 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(15), pFC->GetSharedLength());
639 xDocSh->DoClose();
642 // https://bugs.freedesktop.org/attachment.cgi?id=100089 from fdo#77018
643 // mentioned also in fdo#79441
644 // Document contains cached external references.
645 void ScFiltersTest::testSortWithSheetExternalReferencesODS()
647 ScDocShellRef xDocSh = loadDoc("sort-with-sheet-external-references.", ODS, true);
648 CPPUNIT_ASSERT(xDocSh.Is());
649 ScDocument& rDoc = xDocSh->GetDocument();
650 sc::AutoCalcSwitch aACSwitch(rDoc, true); // turn auto calc on.
651 rDoc.CalcAll();
653 // We reset the SortRefUpdate value back to the original in tearDown().
654 ScInputOptions aInputOption = SC_MOD()->GetInputOptions();
656 // The complete relative test only works with UpdateReferenceOnSort==true,
657 // but the internal and external sheet references have to work in both
658 // modes.
660 aInputOption.SetSortRefUpdate(true);
661 SC_MOD()->SetInputOptions(aInputOption);
663 // Sort A15:D20 with relative row references. UpdateReferenceOnSort==true
664 // With in-sheet relative references.
665 testSortWithSheetExternalReferencesODS_Impl( xDocSh, 14, 19, true);
667 // Undo sort with relative references to perform same sort.
668 rDoc.GetUndoManager()->Undo();
669 rDoc.CalcAll();
671 aInputOption.SetSortRefUpdate(false);
672 SC_MOD()->SetInputOptions(aInputOption);
674 // Sort A15:D20 with relative row references. UpdateReferenceOnSort==false
675 // Without in-sheet relative references.
676 testSortWithSheetExternalReferencesODS_Impl( xDocSh, 14, 19, false);
678 // Undo sort with relative references to perform new sort.
679 rDoc.GetUndoManager()->Undo();
680 rDoc.CalcAll();
682 // Sort with absolute references has to work in both UpdateReferenceOnSort
683 // modes.
685 aInputOption.SetSortRefUpdate(true);
686 SC_MOD()->SetInputOptions(aInputOption);
688 // Sort A23:D28 with absolute row references. UpdateReferenceOnSort==true
689 // With in-sheet relative references.
690 testSortWithSheetExternalReferencesODS_Impl( xDocSh, 22, 27, true);
692 // Undo sort with absolute references to perform same sort.
693 rDoc.GetUndoManager()->Undo();
694 rDoc.CalcAll();
696 aInputOption.SetSortRefUpdate(false);
697 SC_MOD()->SetInputOptions(aInputOption);
699 // Sort A23:D28 with absolute row references. UpdateReferenceOnSort==false
700 // With in-sheet relative references.
701 testSortWithSheetExternalReferencesODS_Impl( xDocSh, 22, 27, true);
703 xDocSh->DoClose();
706 void ScFiltersTest::testSortWithSheetExternalReferencesODS_Impl( ScDocShellRef xDocSh, SCROW nRow1, SCROW nRow2,
707 bool bCheckRelativeInSheet )
709 ScDocument& rDoc = xDocSh->GetDocument();
711 // Check the original data is there.
712 for (SCROW nRow=nRow1+1; nRow <= nRow2; ++nRow)
714 double aCheck[] = { 1, 2, 3, 4, 5 };
715 CPPUNIT_ASSERT_EQUAL( aCheck[nRow-nRow1-1], rDoc.GetValue( ScAddress(0,nRow,0)));
717 for (SCROW nRow=nRow1+1; nRow <= nRow2; ++nRow)
719 for (SCCOL nCol=1; nCol <= 3; ++nCol)
721 double aCheck[] = { 1, 12, 123, 1234, 12345 };
722 CPPUNIT_ASSERT_EQUAL( aCheck[nRow-nRow1-1], rDoc.GetValue( ScAddress(nCol,nRow,0)));
726 // Set as an anonymous database range to sort.
727 ScDBData* pDBData = new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, nRow1, 3, nRow2, true, true);
728 rDoc.SetAnonymousDBData(0, pDBData);
730 // Sort descending by Column A.
731 ScSortParam aSortData;
732 aSortData.nCol1 = 0;
733 aSortData.nCol2 = 3;
734 aSortData.nRow1 = nRow1;
735 aSortData.nRow2 = nRow2;
736 aSortData.bHasHeader = true;
737 aSortData.maKeyState[0].bDoSort = true;
738 aSortData.maKeyState[0].nField = 0;
739 aSortData.maKeyState[0].bAscending = false;
741 // Do the sorting.
742 ScDBDocFunc aFunc(*xDocSh);
743 bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
744 CPPUNIT_ASSERT(bSorted);
745 rDoc.CalcAll();
747 // Check the sort and that all sheet references and external references are
748 // adjusted to point to the original location.
749 for (SCROW nRow=nRow1+1; nRow <= nRow2; ++nRow)
751 double aCheck[] = { 5, 4, 3, 2, 1 };
752 CPPUNIT_ASSERT_EQUAL( aCheck[nRow-nRow1-1], rDoc.GetValue( ScAddress(0,nRow,0)));
754 // The last column (D) are in-sheet relative references.
755 SCCOL nEndCol = (bCheckRelativeInSheet ? 3 : 2);
756 for (SCROW nRow=nRow1+1; nRow <= nRow2; ++nRow)
758 for (SCCOL nCol=1; nCol <= nEndCol; ++nCol)
760 double aCheck[] = { 12345, 1234, 123, 12, 1 };
761 CPPUNIT_ASSERT_EQUAL( aCheck[nRow-nRow1-1], rDoc.GetValue( ScAddress(nCol,nRow,0)));
766 ScFiltersTest::ScFiltersTest()
767 : ScBootstrapFixture( "/sc/qa/unit/data" )
768 , mbUpdateReferenceOnSort(false)
772 void ScFiltersTest::setUp()
774 test::BootstrapFixture::setUp();
776 // This is a bit of a fudge, we do this to ensure that ScGlobals::ensure,
777 // which is a private symbol to us, gets called
778 m_xCalcComponent =
779 getMultiServiceFactory()->createInstance("com.sun.star.comp.Calc.SpreadsheetDocument");
780 CPPUNIT_ASSERT_MESSAGE("no calc component!", m_xCalcComponent.is());
782 // one test sets this configuration option; make sure we remember the
783 // original value
784 ScInputOptions aInputOption = SC_MOD()->GetInputOptions();
785 mbUpdateReferenceOnSort = aInputOption.GetSortRefUpdate();
788 void ScFiltersTest::tearDown()
790 uno::Reference< lang::XComponent >( m_xCalcComponent, UNO_QUERY_THROW )->dispose();
791 test::BootstrapFixture::tearDown();
793 // one test sets this configuration option; make sure we return it back
794 ScInputOptions aInputOption = SC_MOD()->GetInputOptions();
795 if (mbUpdateReferenceOnSort != aInputOption.GetSortRefUpdate())
797 aInputOption.SetSortRefUpdate(mbUpdateReferenceOnSort);
798 SC_MOD()->SetInputOptions(aInputOption);
802 CPPUNIT_TEST_SUITE_REGISTRATION(ScFiltersTest);
804 CPPUNIT_PLUGIN_IMPLEMENT();
806 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */