1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
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>
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"
26 #include "inputopt.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>
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 */
50 : public test::FiltersTest
51 , public ScBootstrapFixture
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
;
63 * Ensure CVEs remain unbroken
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();
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.
124 xDocShRef
->DoClose();
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());
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
);
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.");
193 createCSVPath( aSheet2CSV
, aCSVPath
);
194 testFile( aCSVPath
, rDoc
, 1);
200 void testContentImpl(ScDocument
& rDoc
, sal_Int32 nFormat
) //same code for ods, xls, xlsx
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
)
231 rDoc
.ExtendMerge(4, 1, nCol
, nRow
, 0, false);
232 CPPUNIT_ASSERT_MESSAGE("merged cells are not imported", nCol
== 5 && nRow
== 2);
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
);
256 void ScFiltersTest::testContentXLS()
258 ScDocShellRef xDocSh
= loadDoc("universal-content.", XLS
);
259 xDocSh
->DoHardRecalc(true);
261 ScDocument
& rDoc
= xDocSh
->GetDocument();
262 testContentImpl(rDoc
, XLS
);
266 void ScFiltersTest::testContentXLSX()
268 ScDocShellRef xDocSh
= loadDoc("universal-content.", XLSX
);
269 xDocSh
->DoHardRecalc(true);
271 ScDocument
& rDoc
= xDocSh
->GetDocument();
272 testContentImpl(rDoc
, XLSX
);
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
);
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
);
297 void ScFiltersTest::testContentDIF()
299 ScDocShellRef xDocSh
= loadDoc("universal-content.", DIF
);
301 ScDocument
& rDoc
= xDocSh
->GetDocument();
302 CPPUNIT_ASSERT(&rDoc
);
306 void ScFiltersTest::testContentXLSB()
308 ScDocShellRef xDocSh
= loadDoc("universal-content.", XLSB
);
309 xDocSh
->DoHardRecalc(true);
311 ScDocument
& rDoc
= xDocSh
->GetDocument();
312 testContentImpl(rDoc
, XLSB
);
316 // void ScFiltersTest::testContentXLS_XML()
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();
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);
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();
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());
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);
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]);
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
);
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
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
522 impl_testLegacyCellAnchoredRotatedShape( rDoc
, aRect
, aAnchor
, 100 );
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 );
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
);
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
);
582 void ScFiltersTest::testEnhancedProtectionXLSX()
584 ScDocShellRef xDocSh
= loadDoc("enhanced-protection.", XLSX
);
585 CPPUNIT_ASSERT(xDocSh
.Is());
586 ScDocument
& rDoc
= xDocSh
->GetDocument();
588 testEnhancedProtectionImpl( rDoc
);
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));
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));
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
;
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));
636 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), pFC
->GetSharedTopRow());
637 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(15), pFC
->GetSharedLength());
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.
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
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();
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();
682 // Sort with absolute references has to work in both UpdateReferenceOnSort
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();
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);
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
;
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;
742 ScDBDocFunc
aFunc(*xDocSh
);
743 bool bSorted
= aFunc
.Sort(0, aSortData
, true, true, true);
744 CPPUNIT_ASSERT(bSorted
);
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
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
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: */