Avoid potential negative array index access to cached text.
[LibreOffice.git] / sc / qa / unit / subsequent_export_test.cxx
blob30600191d54a0aaa60c5d133f046ee49ecadd074
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 <officecfg/Office/Common.hxx>
11 #include <config_fonts.h>
13 #include "helper/debughelper.hxx"
15 #include "helper/qahelper.hxx"
16 #include "helper/shared_test_impl.hxx"
18 #include <userdat.hxx>
19 #include <docpool.hxx>
20 #include <cellvalue.hxx>
21 #include <scitems.hxx>
22 #include <attrib.hxx>
23 #include <stlpool.hxx>
24 #include <editutil.hxx>
25 #include <scopetools.hxx>
26 #include <postit.hxx>
27 #include <validat.hxx>
29 #include <svx/svdpage.hxx>
30 #include <tabprotection.hxx>
31 #include <editeng/wghtitem.hxx>
32 #include <editeng/postitem.hxx>
33 #include <editeng/eeitem.hxx>
34 #include <editeng/section.hxx>
35 #include <editeng/crossedoutitem.hxx>
36 #include <editeng/borderline.hxx>
37 #include <editeng/escapementitem.hxx>
38 #include <editeng/fontitem.hxx>
39 #include <editeng/fhgtitem.hxx>
40 #include <editeng/udlnitem.hxx>
41 #include <editeng/colritem.hxx>
43 using namespace ::com::sun::star;
44 using namespace ::com::sun::star::uno;
46 class ScExportTest : public ScModelTestBase
48 protected:
49 void testExcelCellBorders(const OUString& sFormatType);
51 public:
52 ScExportTest()
53 : ScModelTestBase("sc/qa/unit/data")
58 CPPUNIT_TEST_FIXTURE(ScExportTest, testExport)
60 createScDoc();
62 ScDocument* pDoc = getScDoc();
64 pDoc->SetValue(0, 0, 0, 1.0);
66 saveAndReload("calc8");
68 pDoc = getScDoc();
69 double aVal = pDoc->GetValue(0, 0, 0);
70 ASSERT_DOUBLES_EQUAL(1.0, aVal);
73 CPPUNIT_TEST_FIXTURE(ScExportTest, testDefaultFontHeight)
75 createScDoc();
77 ScDocument* pDoc = getScDoc();
78 ScDocumentPool* pPool = pDoc->GetPool();
79 pPool->SetPoolDefaultItem(SvxFontHeightItem(400, 100, ATTR_FONT_HEIGHT));
80 pPool->SetPoolDefaultItem(SvxFontHeightItem(400, 100, ATTR_CJK_FONT_HEIGHT));
81 pPool->SetPoolDefaultItem(SvxFontHeightItem(400, 100, ATTR_CTL_FONT_HEIGHT));
83 saveAndReload("calc8");
85 pDoc = getScDoc();
86 pPool = pDoc->GetPool();
87 const SvxFontHeightItem& rItem = pPool->GetDefaultItem(ATTR_FONT_HEIGHT);
88 CPPUNIT_ASSERT_EQUAL(sal_uInt32(400), rItem.GetHeight());
89 const SvxFontHeightItem& rCJKItem = pPool->GetDefaultItem(ATTR_CJK_FONT_HEIGHT);
90 CPPUNIT_ASSERT_EQUAL(sal_uInt32(400), rCJKItem.GetHeight());
91 const SvxFontHeightItem& rCTLItem = pPool->GetDefaultItem(ATTR_CTL_FONT_HEIGHT);
92 CPPUNIT_ASSERT_EQUAL(sal_uInt32(400), rCTLItem.GetHeight());
95 CPPUNIT_TEST_FIXTURE(ScExportTest, testTdf139167)
97 createScDoc("xlsx/tdf139167.xlsx");
99 save("Calc Office Open XML");
100 xmlDocUniquePtr pDoc = parseExport("xl/styles.xml");
101 CPPUNIT_ASSERT(pDoc);
103 assertXPath(pDoc, "/x:styleSheet/x:cellStyles"_ostr, "count"_ostr, "6");
104 assertXPath(pDoc, "/x:styleSheet/x:dxfs/x:dxf/x:fill/x:patternFill/x:bgColor"_ostr, "rgb"_ostr,
105 "FFFFFF00");
108 CPPUNIT_TEST_FIXTURE(ScExportTest, testFontColorWithMultipleAttributesDefined)
110 // Related: TDF #113271
111 // Test font color where "rgb" and "theme" attribute is defined and
112 // is imported and exported correctly. Theme should have priority,
113 // so LO is fine to ignore "rgb" at export.
115 createScDoc("xlsx/tdf113271.xlsx");
117 save("Calc Office Open XML");
118 xmlDocUniquePtr pDoc = parseExport("xl/styles.xml");
119 CPPUNIT_ASSERT(pDoc);
121 assertXPath(pDoc, "/x:styleSheet/x:fonts"_ostr, "count"_ostr, "6");
123 // Expect "theme" attribute to be set correctly
124 assertXPath(pDoc, "/x:styleSheet/x:fonts/x:font[1]/x:color"_ostr, "theme"_ostr, "1");
125 // We don't export "rgb" attribute
126 assertXPathNoAttribute(pDoc, "/x:styleSheet/x:fonts/x:font[1]/x:color"_ostr, "rgb"_ostr);
127 // Just making sure the checked font is the correct one
128 assertXPath(pDoc, "/x:styleSheet/x:fonts/x:font[1]/x:name"_ostr, "val"_ostr, "Calibri");
131 CPPUNIT_TEST_FIXTURE(ScExportTest, testTdf139394)
133 createScDoc("xlsx/tdf139394.xlsx");
135 save("Calc Office Open XML");
136 xmlDocUniquePtr pDoc = parseExport("xl/worksheets/sheet1.xml");
137 CPPUNIT_ASSERT(pDoc);
139 assertXPathContent(
140 pDoc,
141 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[1]/"
142 "x14:cfRule/xm:f"_ostr,
143 "LEFT(A1,LEN(\"+\"))=\"+\"");
144 assertXPathContent(
145 pDoc,
146 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[2]/"
147 "x14:cfRule/xm:f"_ostr,
148 "RIGHT(A2,LEN(\"-\"))=\"-\"");
149 assertXPathContent(
150 pDoc,
151 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[3]/"
152 "x14:cfRule/xm:f"_ostr,
153 "LEFT(A3,LEN($B$3))=$B$3");
156 CPPUNIT_TEST_FIXTURE(ScExportTest, testExtCondFormatXLSX)
158 createScDoc("xlsx/tdf139021.xlsx");
160 save("Calc Office Open XML");
161 xmlDocUniquePtr pDoc = parseExport("xl/worksheets/sheet1.xml");
162 CPPUNIT_ASSERT(pDoc);
164 assertXPath(
165 pDoc,
166 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[1]/"
167 "x14:cfRule"_ostr,
168 "type"_ostr, "containsText");
169 assertXPathContent(
170 pDoc,
171 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[1]/"
172 "x14:cfRule/xm:f[1]"_ostr,
173 "NOT(ISERROR(SEARCH($B$1,A1)))");
174 assertXPathContent(
175 pDoc,
176 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[1]/"
177 "x14:cfRule/xm:f[2]"_ostr,
178 "$B$1");
179 assertXPath(
180 pDoc,
181 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[2]/"
182 "x14:cfRule"_ostr,
183 "type"_ostr, "notContainsText");
184 assertXPathContent(
185 pDoc,
186 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[2]/"
187 "x14:cfRule/xm:f[1]"_ostr,
188 "ISERROR(SEARCH($B$2,A2))");
189 assertXPathContent(
190 pDoc,
191 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[2]/"
192 "x14:cfRule/xm:f[2]"_ostr,
193 "$B$2");
196 CPPUNIT_TEST_FIXTURE(ScExportTest, testTdf90104)
198 createScDoc("xlsx/tdf90104.xlsx");
200 save("Calc Office Open XML");
202 xmlDocUniquePtr pDoc = parseExport("xl/worksheets/sheet1.xml");
203 CPPUNIT_ASSERT(pDoc);
205 assertXPathContent(pDoc,
206 "/x:worksheet/x:dataValidations/x:dataValidation/mc:AlternateContent"
207 "/mc:Choice/x12ac:list"_ostr,
208 "1,\"2,3\",4,\"5,6\"");
209 assertXPathContent(pDoc,
210 "/x:worksheet/x:dataValidations/x:dataValidation/mc:AlternateContent"
211 "/mc:Fallback/x:formula1"_ostr,
212 "\"1,2,3,4,5,6\"");
215 CPPUNIT_TEST_FIXTURE(ScExportTest, testTdf111876)
217 // Document with relative path hyperlink
219 createScDoc("xlsx/tdf111876.xlsx");
221 save("Calc Office Open XML");
222 xmlDocUniquePtr pDoc = parseExport("xl/worksheets/_rels/sheet1.xml.rels");
223 CPPUNIT_ASSERT(pDoc);
224 OUString sTarget = getXPath(pDoc, "/rels:Relationships/rels:Relationship"_ostr, "Target"_ostr);
226 // Document is saved to the temporary directory, relative path should be different than original one
227 CPPUNIT_ASSERT(sTarget != "../xls/bug-fixes.xls");
230 CPPUNIT_TEST_FIXTURE(ScExportTest, testPasswordExport)
232 std::vector<OUString> aFilterNames{ "calc8", "MS Excel 97", "Calc Office Open XML" };
234 for (size_t i = 0; i < aFilterNames.size(); ++i)
236 createScDoc();
238 ScDocument* pDoc = getScDoc();
240 pDoc->SetValue(0, 0, 0, 1.0);
242 saveAndReload(aFilterNames[i], /*pPassword*/ "test");
244 pDoc = getScDoc();
245 double aVal = pDoc->GetValue(0, 0, 0);
246 ASSERT_DOUBLES_EQUAL(1.0, aVal);
250 CPPUNIT_TEST_FIXTURE(ScExportTest, testTdf134332)
252 createScDoc("ods/tdf134332.ods");
254 ScDocument* pDoc = getScDoc();
256 ASSERT_DOUBLES_EQUAL(190.0, pDoc->GetValue(ScAddress(0, 0, 0)));
258 ASSERT_DOUBLES_EQUAL(238.0, pDoc->GetValue(ScAddress(0, 10144, 0)));
260 saveAndReload("calc8", /*pPassword*/ "test");
262 // Without the fixes in place, it would have failed here
263 pDoc = getScDoc();
264 ASSERT_DOUBLES_EQUAL(190.0, pDoc->GetValue(ScAddress(0, 0, 0)));
266 ASSERT_DOUBLES_EQUAL(238.0, pDoc->GetValue(ScAddress(0, 10144, 0)));
269 CPPUNIT_TEST_FIXTURE(ScExportTest, testConditionalFormatExportODS)
271 createScDoc("ods/new_cond_format_test_export.ods");
273 saveAndReload("calc8");
274 ScDocument* pDoc = getScDoc();
275 OUString aCSVPath = createFilePath(u"contentCSV/new_cond_format_test_export.csv");
276 testCondFile(aCSVPath, &*pDoc, 0);
279 CPPUNIT_TEST_FIXTURE(ScExportTest, testCondFormatExportCellIs)
281 createScDoc("xlsx/condFormat_cellis.xlsx");
282 saveAndReload("Calc Office Open XML");
284 ScDocument* pDoc = getScDoc();
285 CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetCondFormList(0)->size());
287 ScConditionalFormat* pFormat = pDoc->GetCondFormat(0, 0, 0);
288 CPPUNIT_ASSERT(pFormat);
290 const ScFormatEntry* pEntry = pFormat->GetEntry(0);
291 CPPUNIT_ASSERT(pEntry);
292 CPPUNIT_ASSERT_EQUAL(ScFormatEntry::Type::ExtCondition, pEntry->GetType());
294 const ScCondFormatEntry* pCondition = static_cast<const ScCondFormatEntry*>(pEntry);
295 CPPUNIT_ASSERT_EQUAL(ScConditionMode::Equal, pCondition->GetOperation());
297 OUString aStr = pCondition->GetExpression(ScAddress(0, 0, 0), 0);
298 CPPUNIT_ASSERT_EQUAL(OUString("$Sheet2.$A$2"), aStr);
300 pEntry = pFormat->GetEntry(1);
301 CPPUNIT_ASSERT(pEntry);
302 CPPUNIT_ASSERT_EQUAL(ScFormatEntry::Type::ExtCondition, pEntry->GetType());
304 pCondition = static_cast<const ScCondFormatEntry*>(pEntry);
305 CPPUNIT_ASSERT_EQUAL(ScConditionMode::Equal, pCondition->GetOperation());
307 aStr = pCondition->GetExpression(ScAddress(0, 0, 0), 0);
308 CPPUNIT_ASSERT_EQUAL(OUString("$Sheet2.$A$1"), aStr);
311 CPPUNIT_TEST_FIXTURE(ScExportTest, testConditionalFormatExportXLSX)
313 createScDoc("xlsx/new_cond_format_test_export.xlsx");
315 saveAndReload("Calc Office Open XML");
316 ScDocument* pDoc = getScDoc();
318 OUString aCSVPath = createFilePath(u"contentCSV/new_cond_format_test_export.csv");
319 testCondFile(aCSVPath, &*pDoc, 0);
322 OUString aCSVPath = createFilePath(u"contentCSV/new_cond_format_test_sheet2.csv");
323 testCondFile(aCSVPath, &*pDoc, 1);
327 CPPUNIT_TEST_FIXTURE(ScExportTest, testTdf99856_dataValidationTest)
329 createScDoc("ods/tdf99856_dataValidationTest.ods");
331 saveAndReload("Calc Office Open XML");
333 ScDocument* pDoc = getScDoc();
334 const ScValidationData* pData = pDoc->GetValidationEntry(2);
335 CPPUNIT_ASSERT(pData);
337 // Excel can't open corrupt file if the list is longer than 255 characters
338 std::vector<ScTypedStrData> aList;
339 pData->FillSelectionList(aList, ScAddress(0, 1, 1));
340 CPPUNIT_ASSERT_EQUAL(size_t(18), aList.size());
341 CPPUNIT_ASSERT_EQUAL(OUString("18 Missis"), aList[17].GetString());
344 CPPUNIT_TEST_FIXTURE(ScExportTest, testProtectionKeyODS_UTF16LErtlSHA1)
346 OUString constexpr password(u"1012345678901234567890123456789012345678901234567890"_ustr);
348 createScDoc("fods/protection-key1.fods");
350 ScDocument* pDoc = getScDoc();
351 ScDocProtection* const pDocProt(pDoc->GetDocProtection());
352 CPPUNIT_ASSERT(pDocProt->verifyPassword(password));
353 const ScTableProtection* const pTabProt(pDoc->GetTabProtection(0));
354 CPPUNIT_ASSERT(pTabProt->verifyPassword(password));
356 // we can't assume that the user entered the password; check that we
357 // round-trip the password as-is
358 save("calc8");
359 xmlDocUniquePtr pXmlDoc = parseExport("content.xml");
360 assertXPath(
361 pXmlDoc,
362 "//office:spreadsheet[@table:structure-protected='true' and "
363 "@table:protection-key='vbnhxyBKtPHCA1wB21zG1Oha8ZA=' and "
364 "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr);
365 assertXPath(
366 pXmlDoc,
367 "//table:table[@table:protected='true' and "
368 "@table:protection-key='vbnhxyBKtPHCA1wB21zG1Oha8ZA=' and "
369 "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr);
372 CPPUNIT_TEST_FIXTURE(ScExportTest, testProtectionKeyODS_UTF8SHA1)
374 OUString constexpr password(u"1012345678901234567890123456789012345678901234567890"_ustr);
376 createScDoc("fods/protection-key2.fods");
378 ScDocument* pDoc = getScDoc();
379 ScDocProtection* const pDocProt(pDoc->GetDocProtection());
380 CPPUNIT_ASSERT(pDocProt->verifyPassword(password));
381 const ScTableProtection* const pTabProt(pDoc->GetTabProtection(0));
382 CPPUNIT_ASSERT(pTabProt->verifyPassword(password));
384 // we can't assume that the user entered the password; check that we
385 // round-trip the password as-is
386 save("calc8");
387 xmlDocUniquePtr pXmlDoc = parseExport("content.xml");
388 assertXPath(
389 pXmlDoc,
390 "//office:spreadsheet[@table:structure-protected='true' and "
391 "@table:protection-key='nLHas0RIwepGDaH4c2hpyIUvIS8=' and "
392 "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr);
393 assertXPath(
394 pXmlDoc,
395 "//table:table[@table:protected='true' and "
396 "@table:protection-key='nLHas0RIwepGDaH4c2hpyIUvIS8=' and "
397 "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr);
400 CPPUNIT_TEST_FIXTURE(ScExportTest, testProtectionKeyODS_UTF8SHA256ODF12)
402 OUString constexpr password(u"1012345678901234567890123456789012345678901234567890"_ustr);
404 createScDoc("fods/protection-key3.fods");
406 ScDocument* pDoc = getScDoc();
407 ScDocProtection* const pDocProt(pDoc->GetDocProtection());
408 CPPUNIT_ASSERT(pDocProt->verifyPassword(password));
409 const ScTableProtection* const pTabProt(pDoc->GetTabProtection(0));
410 CPPUNIT_ASSERT(pTabProt->verifyPassword(password));
412 // we can't assume that the user entered the password; check that we
413 // round-trip the password as-is
414 save("calc8");
415 xmlDocUniquePtr pXmlDoc = parseExport("content.xml");
416 assertXPath(
417 pXmlDoc,
418 "//office:spreadsheet[@table:structure-protected='true' and "
419 "@table:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=' and "
420 "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256']"_ostr);
421 assertXPath(
422 pXmlDoc,
423 "//table:table[@table:protected='true' and "
424 "@table:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=' and "
425 "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256']"_ostr);
428 CPPUNIT_TEST_FIXTURE(ScExportTest, testProtectionKeyODS_UTF8SHA256W3C)
430 OUString constexpr password(u"1012345678901234567890123456789012345678901234567890"_ustr);
432 createScDoc("fods/protection-key4.fods");
434 ScDocument* pDoc = getScDoc();
435 ScDocProtection* const pDocProt(pDoc->GetDocProtection());
436 CPPUNIT_ASSERT(pDocProt->verifyPassword(password));
437 const ScTableProtection* const pTabProt(pDoc->GetTabProtection(0));
438 CPPUNIT_ASSERT(pTabProt->verifyPassword(password));
440 // we can't assume that the user entered the password; check that we
441 // round-trip the password as-is
442 save("calc8");
443 xmlDocUniquePtr pXmlDoc = parseExport("content.xml");
444 assertXPath(
445 pXmlDoc,
446 "//office:spreadsheet[@table:structure-protected='true' and "
447 "@table:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=' and "
448 "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256']"_ostr);
449 assertXPath(
450 pXmlDoc,
451 "//table:table[@table:protected='true' and "
452 "@table:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=' and "
453 "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256']"_ostr);
456 CPPUNIT_TEST_FIXTURE(ScExportTest, testProtectionKeyODS_XL_SHA1)
458 OUString constexpr password(u"1012345678901234567890123456789012345678901234567890"_ustr);
460 createScDoc("fods/protection-key5.fods");
462 ScDocument* pDoc = getScDoc();
463 ScDocProtection* const pDocProt(pDoc->GetDocProtection());
464 CPPUNIT_ASSERT(pDocProt->verifyPassword(password));
465 const ScTableProtection* const pTabProt(pDoc->GetTabProtection(0));
466 CPPUNIT_ASSERT(pTabProt->verifyPassword(password));
468 // we can't assume that the user entered the password; check that we
469 // round-trip the password as-is
470 save("calc8");
471 xmlDocUniquePtr pXmlDoc = parseExport("content.xml");
472 assertXPath(
473 pXmlDoc,
474 "//office:spreadsheet[@table:structure-protected='true' and "
475 "@table:protection-key='OX3WkEe79fv1PE+FUmfOLdwVoqI=' and "
476 "@table:protection-key-digest-algorithm='http://docs.oasis-open.org/office/ns/table/"
477 "legacy-hash-excel' and "
478 "@loext:protection-key-digest-algorithm-2='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr);
479 assertXPath(
480 pXmlDoc,
481 "//table:table[@table:protected='true' and "
482 "@table:protection-key='OX3WkEe79fv1PE+FUmfOLdwVoqI=' and "
483 "@table:protection-key-digest-algorithm='http://docs.oasis-open.org/office/ns/table/"
484 "legacy-hash-excel' and "
485 "@loext:protection-key-digest-algorithm-2='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr);
488 CPPUNIT_TEST_FIXTURE(ScExportTest, testColorScaleExportODS)
490 createScDoc("ods/colorscale.ods");
492 saveAndReload("calc8");
494 ScDocument* pDoc = getScDoc();
496 testColorScale2Entry_Impl(*pDoc);
497 testColorScale3Entry_Impl(*pDoc);
500 CPPUNIT_TEST_FIXTURE(ScExportTest, testColorScaleExportXLSX)
502 createScDoc("xlsx/colorscale.xlsx");
504 saveAndReload("Calc Office Open XML");
506 ScDocument* pDoc = getScDoc();
508 testColorScale2Entry_Impl(*pDoc);
509 testColorScale3Entry_Impl(*pDoc);
512 CPPUNIT_TEST_FIXTURE(ScExportTest, testDataBarExportODS)
514 createScDoc("ods/databar.ods");
516 saveAndReload("calc8");
518 ScDocument* pDoc = getScDoc();
520 testDataBar_Impl(*pDoc);
523 CPPUNIT_TEST_FIXTURE(ScExportTest, testFormatExportODS)
525 createScDoc("ods/formats.ods");
527 saveAndReload("calc8");
529 ScDocument* pDoc = getScDoc();
531 testFormats(pDoc, u"calc8");
534 CPPUNIT_TEST_FIXTURE(ScExportTest, testCommentExportXLSX)
536 //tdf#104729 FILESAVE OpenOffice do not save author of the comment during export to .xlsx
537 createScDoc("ods/comment.ods");
539 save("Calc Office Open XML");
540 xmlDocUniquePtr pComments = parseExport("xl/comments1.xml");
541 CPPUNIT_ASSERT(pComments);
543 assertXPathContent(pComments, "/x:comments/x:authors/x:author[1]"_ostr, "BAKO");
544 assertXPath(pComments, "/x:comments/x:authors/x:author"_ostr, 1);
546 assertXPathContent(pComments, "/x:comments/x:commentList/x:comment/x:text/x:r/x:t"_ostr,
547 "Komentarz");
549 xmlDocUniquePtr pVmlDrawing = parseExport("xl/drawings/vmlDrawing1.vml");
550 CPPUNIT_ASSERT(pVmlDrawing);
552 //assertXPath(pVmlDrawing, "/xml/v:shapetype", "coordsize", "21600,21600");
553 assertXPath(pVmlDrawing, "/xml/v:shapetype"_ostr, "spt"_ostr, "202");
554 assertXPath(pVmlDrawing, "/xml/v:shapetype/v:stroke"_ostr, "joinstyle"_ostr, "miter");
555 const OUString sShapeTypeId = "#" + getXPath(pVmlDrawing, "/xml/v:shapetype"_ostr, "id"_ostr);
557 assertXPath(pVmlDrawing, "/xml/v:shape"_ostr, "type"_ostr, sShapeTypeId);
558 assertXPath(pVmlDrawing, "/xml/v:shape/v:shadow"_ostr, "color"_ostr, "black");
559 assertXPath(pVmlDrawing, "/xml/v:shape/v:shadow"_ostr, "obscured"_ostr, "t");
561 //tdf#117274 fix MSO interoperability with the secret VML shape type id
562 assertXPath(pVmlDrawing, "/xml/v:shapetype"_ostr, "id"_ostr, "_x0000_t202");
563 assertXPath(pVmlDrawing, "/xml/v:shape"_ostr, "type"_ostr, "#_x0000_t202");
566 CPPUNIT_TEST_FIXTURE(ScExportTest, testCommentExportXLSX_2_XLSX)
568 //tdf#117287 FILESAVE XLSX: Comments always disappear after opening the exported XLSX file with Excel
569 createScDoc("xlsx/tdf117287_comment.xlsx");
571 ScDocument* pDoc = getScDoc();
572 ScAddress aPosC9(2, 8, 0);
573 ScPostIt* pNote = pDoc->GetNote(aPosC9);
575 CPPUNIT_ASSERT(pNote);
576 CPPUNIT_ASSERT(!pNote->IsCaptionShown());
578 pNote->ShowCaption(aPosC9, true);
580 save("Calc Office Open XML");
581 xmlDocUniquePtr pComments = parseExport("xl/comments1.xml");
582 CPPUNIT_ASSERT(pComments);
584 assertXPathContent(pComments, "/x:comments/x:commentList/x:comment/x:text/x:r/x:t"_ostr,
585 "visible comment");
587 xmlDocUniquePtr pVmlDrawing = parseExport("xl/drawings/vmlDrawing1.vml");
588 CPPUNIT_ASSERT(pVmlDrawing);
590 assertXPath(pVmlDrawing, "/xml/v:shape/x:ClientData/x:Visible"_ostr, 0);
593 #if HAVE_MORE_FONTS
594 CPPUNIT_TEST_FIXTURE(ScExportTest, testCustomColumnWidthExportXLSX)
596 //tdf#100946 FILESAVE Excel on macOS ignored column widths in XLSX last saved by LO
597 createScDoc("ods/custom_column_width.ods");
599 save("Calc Office Open XML");
600 xmlDocUniquePtr pSheet = parseExport("xl/worksheets/sheet1.xml");
601 CPPUNIT_ASSERT(pSheet);
603 // tdf#124741: check that we export default width, otherwise the skipped columns would have
604 // wrong width. Previously defaultColWidth attribute was missing
605 double nDefWidth
606 = getXPath(pSheet, "/x:worksheet/x:sheetFormatPr"_ostr, "defaultColWidth"_ostr).toDouble();
607 CPPUNIT_ASSERT_DOUBLES_EQUAL(11.53515625, nDefWidth, 0.01);
609 // First column, has everything default (width in Calc: 1280), skipped
611 // Second column, has custom width (width in Calc: 1225)
612 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "hidden"_ostr, "false");
613 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "outlineLevel"_ostr, "0");
614 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "customWidth"_ostr, "true");
615 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "collapsed"_ostr, "false");
616 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "min"_ostr, "2");
617 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "max"_ostr, "2");
619 // Third column, has everything default (width in Calc: 1280), skipped
621 // Fourth column has custom width. Columns from 4 to 7 are hidden
622 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "hidden"_ostr, "true");
623 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "outlineLevel"_ostr, "0");
624 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "customWidth"_ostr, "true");
625 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "collapsed"_ostr, "false");
626 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "min"_ostr, "4");
627 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "max"_ostr, "4");
629 // 5th column has custom width. Columns from 4 to 7 are hidden
630 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "hidden"_ostr, "true");
631 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "outlineLevel"_ostr, "0");
632 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "customWidth"_ostr, "true");
633 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "collapsed"_ostr, "false");
634 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "min"_ostr, "5");
635 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "max"_ostr, "5");
637 // 6th and 7th columns have default width and they are hidden
638 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "hidden"_ostr, "true");
639 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "outlineLevel"_ostr, "0");
640 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "customWidth"_ostr, "false");
641 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "collapsed"_ostr, "false");
642 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "min"_ostr, "6");
643 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "max"_ostr, "7");
645 // 8th column has everything default - skipped
647 // 9th column has custom width
648 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "hidden"_ostr, "false");
649 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "outlineLevel"_ostr, "0");
650 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "customWidth"_ostr, "true");
651 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "collapsed"_ostr, "false");
652 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "min"_ostr, "9");
653 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "max"_ostr, "9");
655 // We expected that exactly 5 unique Nodes will be produced
656 assertXPath(pSheet, "/x:worksheet/x:cols/x:col"_ostr, 5);
658 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "hidden"_ostr, "false");
659 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "outlineLevel"_ostr, "0");
660 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "collapsed"_ostr, "false");
661 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "customFormat"_ostr, "false");
662 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "customHeight"_ostr, "false");
664 #endif
666 CPPUNIT_TEST_FIXTURE(ScExportTest, testXfDefaultValuesXLSX)
668 //tdf#70565 FORMATTING: User Defined Custom Formatting is not applied during importing XLSX documents
669 createScDoc("xlsx/xf_default_values.xlsx");
671 save("Calc Office Open XML");
672 xmlDocUniquePtr pSheet = parseExport("xl/styles.xml");
673 CPPUNIT_ASSERT(pSheet);
675 // cellStyleXfs don't need xfId, so we need to make sure it is not saved
676 assertXPathNoAttribute(pSheet, "/x:styleSheet/x:cellStyleXfs/x:xf[1]"_ostr, "xfId"_ostr);
678 // Because numFmtId fontId fillId borderId xfId are not existing during import
679 // it should be created during export, with values set to "0"
680 assertXPath(pSheet, "/x:styleSheet/x:cellXfs/x:xf[1]"_ostr, "xfId"_ostr, "0");
681 assertXPath(pSheet, "/x:styleSheet/x:cellXfs/x:xf[2]"_ostr, "xfId"_ostr, "0");
682 assertXPath(pSheet, "/x:styleSheet/x:cellXfs/x:xf[3]"_ostr, "xfId"_ostr, "0");
683 assertXPath(pSheet, "/x:styleSheet/x:cellXfs/x:xf[4]"_ostr, "xfId"_ostr, "0");
685 // We expected that exactly 15 cellXfs:xf Nodes will be produced
686 assertXPath(pSheet, "/x:styleSheet/x:cellXfs/x:xf"_ostr, 14);
689 static auto verifySpreadsheet13(char const* const pTestName, ScDocument& rDoc) -> void
691 // OFFICE-2173 table:tab-color
692 CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName, Color(0xff3838), rDoc.GetTabBgColor(0));
693 // OFFICE-3857 table:scale-to-X/table:scale-to-Y
694 OUString styleName = rDoc.GetPageStyle(0);
695 ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
696 SfxStyleSheetBase* pStyleSheet = pStylePool->Find(styleName, SfxStyleFamily::Page);
697 CPPUNIT_ASSERT_MESSAGE(pTestName, pStyleSheet);
699 SfxItemSet const& rSet = pStyleSheet->GetItemSet();
700 ScPageScaleToItem const& rItem(rSet.Get(ATTR_PAGE_SCALETO));
701 CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName, sal_uInt16(2), rItem.GetWidth());
702 CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName, sal_uInt16(3), rItem.GetHeight());
705 CPPUNIT_TEST_FIXTURE(ScExportTest, testODF13)
707 // import
708 createScDoc("ods/spreadsheet13e.ods");
709 ScDocument* pDoc = getScDoc();
711 // check model
712 verifySpreadsheet13("import", *pDoc);
714 Resetter _([]() {
715 std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
716 comphelper::ConfigurationChanges::create());
717 officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch);
718 return pBatch->commit();
722 // export ODF 1.3
723 std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
724 comphelper::ConfigurationChanges::create());
725 officecfg::Office::Common::Save::ODF::DefaultVersion::set(10, pBatch);
726 pBatch->commit();
728 // FIXME: Error: unexpected attribute "loext:scale-to-X"
729 skipValidation();
731 saveAndReload("calc8");
732 pDoc = getScDoc();
734 // check XML
735 xmlDocUniquePtr pContentXml = parseExport("content.xml");
736 assertXPath(pContentXml, "/office:document-content/office:automatic-styles/style:style/"
737 "style:table-properties[@table:tab-color='#ff3838']"_ostr);
738 xmlDocUniquePtr pStylesXml = parseExport("styles.xml");
739 assertXPath(pStylesXml, "/office:document-styles/office:automatic-styles/style:page-layout/"
740 "style:page-layout-properties[@style:scale-to-X='2']"_ostr);
741 assertXPath(pStylesXml, "/office:document-styles/office:automatic-styles/style:page-layout/"
742 "style:page-layout-properties[@style:scale-to-Y='3']"_ostr);
744 // check model
745 verifySpreadsheet13("1.3 reload", *pDoc);
748 // export ODF 1.2 Extended
749 std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
750 comphelper::ConfigurationChanges::create());
751 officecfg::Office::Common::Save::ODF::DefaultVersion::set(9, pBatch);
752 pBatch->commit();
754 saveAndReload("calc8");
755 pDoc = getScDoc();
757 // check XML
758 xmlDocUniquePtr pContentXml = parseExport("content.xml");
759 assertXPath(pContentXml, "/office:document-content/office:automatic-styles/style:style/"
760 "style:table-properties[@tableooo:tab-color='#ff3838']"_ostr);
761 xmlDocUniquePtr pStylesXml = parseExport("styles.xml");
762 assertXPath(pStylesXml, "/office:document-styles/office:automatic-styles/style:page-layout/"
763 "style:page-layout-properties[@loext:scale-to-X='2']"_ostr);
764 assertXPath(pStylesXml, "/office:document-styles/office:automatic-styles/style:page-layout/"
765 "style:page-layout-properties[@loext:scale-to-Y='3']"_ostr);
767 // check model
768 verifySpreadsheet13("1.2 Extended reload", *pDoc);
771 // export ODF 1.2
772 std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
773 comphelper::ConfigurationChanges::create());
774 officecfg::Office::Common::Save::ODF::DefaultVersion::set(4, pBatch);
775 pBatch->commit();
777 save("calc8");
779 // check XML
780 xmlDocUniquePtr pContentXml = parseExport("content.xml");
781 assertXPathNoAttribute(
782 pContentXml,
783 "/office:document-content/office:automatic-styles/style:style/style:table-properties"_ostr,
784 "tab-color"_ostr);
785 xmlDocUniquePtr pStylesXml = parseExport("styles.xml");
786 assertXPathNoAttribute(pStylesXml,
787 "/office:document-styles/office:automatic-styles/"
788 "style:page-layout[1]/style:page-layout-properties"_ostr,
789 "scale-to-X"_ostr);
790 assertXPathNoAttribute(pStylesXml,
791 "/office:document-styles/office:automatic-styles/"
792 "style:page-layout[1]/style:page-layout-properties"_ostr,
793 "scale-to-Y"_ostr);
795 // don't reload - no point
799 CPPUNIT_TEST_FIXTURE(ScExportTest, testColumnWidthResaveXLSX)
801 // tdf#91475 FILESAVE: Column width is not preserved in XLSX / after round trip.
802 // Test if after resave .xlsx file, columns width is identical with previous one
803 createScDoc("xlsx/different-column-width-excel2010.xlsx");
805 save("Calc Office Open XML");
806 xmlDocUniquePtr pSheet = parseExport("xl/worksheets/sheet1.xml");
807 CPPUNIT_ASSERT(pSheet);
809 // In original Excel document the width is "24"
810 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "width"_ostr, "24");
811 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "customWidth"_ostr, "true");
813 // In original Excel document the width is "12"
814 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "width"_ostr, "12");
815 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "customWidth"_ostr, "true");
817 // In original Excel document the width is "6"
818 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "width"_ostr, "6");
819 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "customWidth"_ostr, "true");
821 // In original Excel document the width is "1"
822 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "width"_ostr, "1");
823 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "customWidth"_ostr, "true");
825 // In original Excel document the width is "250"
826 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "width"_ostr, "250");
827 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "customWidth"_ostr, "true");
829 assertXPath(pSheet, "/x:worksheet/x:cols/x:col"_ostr, 5);
832 #if HAVE_MORE_FONTS
833 CPPUNIT_TEST_FIXTURE(ScExportTest, testColumnWidthExportFromODStoXLSX)
835 // tdf#91475 FILESAVE: Column width is not preserved in XLSX / after round trip.
836 // Test if after export .ods to .xlsx format, displayed columns width
837 // is identical with previous (.ods) one
839 createScDoc("ods/different-column-width.ods");
841 ScDocument* pDoc = getScDoc();
843 // Col 1, Tab 0 (Column width 2.00 in)
844 sal_uInt16 nExpectedColumn0Width
845 = pDoc->GetColWidth(static_cast<SCCOL>(0), static_cast<SCTAB>(0), false);
846 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(2880), nExpectedColumn0Width);
848 // Col 2, Tab 0 (Column width 1.00 in)
849 sal_uInt16 nExpectedColumn1Width
850 = pDoc->GetColWidth(static_cast<SCCOL>(1), static_cast<SCTAB>(0), false);
851 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1440), nExpectedColumn1Width);
853 // Col 3, Tab 0 (Column width 0.50 in)
854 sal_uInt16 nExpectedColumn2Width
855 = pDoc->GetColWidth(static_cast<SCCOL>(2), static_cast<SCTAB>(0), false);
856 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(720), nExpectedColumn2Width);
858 // Col 4, Tab 0 (Column width 0.25 in)
859 sal_uInt16 nExpectedColumn3Width
860 = pDoc->GetColWidth(static_cast<SCCOL>(3), static_cast<SCTAB>(0), false);
861 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(360), nExpectedColumn3Width);
863 // Col 5, Tab 0 (Column width 13.57 in)
864 sal_uInt16 nExpectedColumn4Width
865 = pDoc->GetColWidth(static_cast<SCCOL>(4), static_cast<SCTAB>(0), false);
866 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(19539), nExpectedColumn4Width);
868 // Export to .xlsx and compare column width with the .ods
869 // We expect that column width from .ods will be exactly the same as imported from .xlsx
871 saveAndReload("Calc Office Open XML");
873 pDoc = getScDoc();
875 // Col 1, Tab 0
876 sal_uInt16 nCalcWidth;
877 nCalcWidth = pDoc->GetColWidth(static_cast<SCCOL>(0), static_cast<SCTAB>(0), false);
878 CPPUNIT_ASSERT_EQUAL(nExpectedColumn0Width, nCalcWidth);
880 // Col 2, Tab 0
881 nCalcWidth = pDoc->GetColWidth(static_cast<SCCOL>(1), static_cast<SCTAB>(0), false);
882 CPPUNIT_ASSERT_EQUAL(nExpectedColumn1Width, nCalcWidth);
884 // Col 3, Tab 0
885 nCalcWidth = pDoc->GetColWidth(static_cast<SCCOL>(2), static_cast<SCTAB>(0), false);
886 CPPUNIT_ASSERT_EQUAL(nExpectedColumn2Width, nCalcWidth);
888 // Col 4, Tab 0
889 nCalcWidth = pDoc->GetColWidth(static_cast<SCCOL>(3), static_cast<SCTAB>(0), false);
890 CPPUNIT_ASSERT_EQUAL(nExpectedColumn3Width, nCalcWidth);
892 // Col 5, Tab 0
893 nCalcWidth = pDoc->GetColWidth(static_cast<SCCOL>(4), static_cast<SCTAB>(0), false);
894 CPPUNIT_ASSERT_EQUAL(nExpectedColumn4Width, nCalcWidth);
896 #endif
898 CPPUNIT_TEST_FIXTURE(ScExportTest, testOutlineExportXLSX)
900 //tdf#100347 FILESAVE FILEOPEN after exporting to .xlsx format grouping are lost
901 //tdf#51524 FILESAVE .xlsx and.xls looses width information for hidden/collapsed grouped columns
902 createScDoc("ods/outline.ods");
904 save("Calc Office Open XML");
905 xmlDocUniquePtr pSheet = parseExport("xl/worksheets/sheet1.xml");
906 CPPUNIT_ASSERT(pSheet);
908 // Maximum Outline Row is 4 for this document
909 assertXPath(pSheet, "/x:worksheet/x:sheetFormatPr"_ostr, "outlineLevelRow"_ostr, "4");
910 // Maximum Outline Column is 4 for this document
911 assertXPath(pSheet, "/x:worksheet/x:sheetFormatPr"_ostr, "outlineLevelCol"_ostr, "4");
913 // First XML node, creates two columns (from min=1 to max=2)
914 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "hidden"_ostr, "false");
915 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "outlineLevel"_ostr, "1");
916 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "collapsed"_ostr, "false");
917 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "min"_ostr, "1");
918 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[1]"_ostr, "max"_ostr, "2");
920 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "hidden"_ostr, "true");
921 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "outlineLevel"_ostr, "2");
922 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "collapsed"_ostr, "false");
923 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "min"_ostr, "3");
924 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[2]"_ostr, "max"_ostr, "3");
926 // Column 4 has custom width and it is hidden. We need to make sure that it is created
927 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "hidden"_ostr, "true");
928 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "outlineLevel"_ostr, "2");
929 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "collapsed"_ostr, "false");
930 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "min"_ostr, "4");
931 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[3]"_ostr, "max"_ostr, "4");
933 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "hidden"_ostr, "true");
934 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "outlineLevel"_ostr, "3");
935 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "collapsed"_ostr, "false");
936 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "min"_ostr, "5");
937 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[4]"_ostr, "max"_ostr, "6");
939 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "hidden"_ostr, "true");
940 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "outlineLevel"_ostr, "4");
941 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "collapsed"_ostr, "false");
942 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "min"_ostr, "7");
943 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[5]"_ostr, "max"_ostr, "7");
945 // Column 8 has custom width and it is hidden. We need to make sure that it is created
946 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[6]"_ostr, "hidden"_ostr, "true");
947 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[6]"_ostr, "outlineLevel"_ostr, "4");
948 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[6]"_ostr, "collapsed"_ostr, "false");
949 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[6]"_ostr, "min"_ostr, "8");
950 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[6]"_ostr, "max"_ostr, "8");
952 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[7]"_ostr, "hidden"_ostr, "true");
953 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[7]"_ostr, "outlineLevel"_ostr, "4");
954 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[7]"_ostr, "collapsed"_ostr, "false");
955 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[7]"_ostr, "min"_ostr, "9");
956 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[7]"_ostr, "max"_ostr, "19");
958 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[8]"_ostr, "hidden"_ostr, "true");
959 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[8]"_ostr, "outlineLevel"_ostr, "3");
960 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[8]"_ostr, "collapsed"_ostr, "true");
961 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[8]"_ostr, "min"_ostr, "20");
962 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[8]"_ostr, "max"_ostr, "20");
964 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[9]"_ostr, "hidden"_ostr, "true");
965 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[9]"_ostr, "outlineLevel"_ostr, "3");
966 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[9]"_ostr, "collapsed"_ostr, "false");
967 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[9]"_ostr, "min"_ostr, "21");
968 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[9]"_ostr, "max"_ostr, "21");
970 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[10]"_ostr, "hidden"_ostr, "true");
971 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[10]"_ostr, "outlineLevel"_ostr, "2");
972 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[10]"_ostr, "collapsed"_ostr, "false");
973 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[10]"_ostr, "min"_ostr, "22");
974 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[10]"_ostr, "max"_ostr, "23");
976 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[11]"_ostr, "hidden"_ostr, "false");
977 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[11]"_ostr, "outlineLevel"_ostr, "1");
978 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[11]"_ostr, "collapsed"_ostr, "true");
979 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[11]"_ostr, "min"_ostr, "24");
980 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[11]"_ostr, "max"_ostr, "24");
982 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[12]"_ostr, "hidden"_ostr, "false");
983 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[12]"_ostr, "outlineLevel"_ostr, "1");
984 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[12]"_ostr, "collapsed"_ostr, "false");
985 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[12]"_ostr, "min"_ostr, "25");
986 assertXPath(pSheet, "/x:worksheet/x:cols/x:col[12]"_ostr, "max"_ostr, "26");
988 // We expected that exactly 12 unique Nodes will be produced
989 assertXPath(pSheet, "/x:worksheet/x:cols/x:col"_ostr, 12);
991 // First row is empty and default so it is not written into XML file
992 // so we need to save 29 rows, as it provides information about outLineLevel
993 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "r"_ostr, "2");
994 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "hidden"_ostr, "false");
995 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "outlineLevel"_ostr, "1");
996 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "collapsed"_ostr, "false");
997 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[2]"_ostr, "r"_ostr, "3");
998 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[2]"_ostr, "hidden"_ostr, "false");
999 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[2]"_ostr, "outlineLevel"_ostr, "2");
1000 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[2]"_ostr, "collapsed"_ostr, "false");
1001 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[3]"_ostr, "r"_ostr, "4");
1002 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[3]"_ostr, "hidden"_ostr, "false");
1003 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[3]"_ostr, "outlineLevel"_ostr, "2");
1004 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[3]"_ostr, "collapsed"_ostr, "false");
1005 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[4]"_ostr, "r"_ostr, "5");
1006 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[4]"_ostr, "hidden"_ostr, "false");
1007 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[4]"_ostr, "outlineLevel"_ostr, "3");
1008 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[4]"_ostr, "collapsed"_ostr, "false");
1009 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[5]"_ostr, "r"_ostr, "6");
1010 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[5]"_ostr, "hidden"_ostr, "false");
1011 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[5]"_ostr, "outlineLevel"_ostr, "3");
1012 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[5]"_ostr, "collapsed"_ostr, "false");
1013 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[6]"_ostr, "r"_ostr, "7");
1014 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[6]"_ostr, "hidden"_ostr, "true");
1015 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[6]"_ostr, "outlineLevel"_ostr, "4");
1016 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[6]"_ostr, "collapsed"_ostr, "false");
1017 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[7]"_ostr, "r"_ostr, "8");
1018 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[7]"_ostr, "hidden"_ostr, "true");
1019 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[7]"_ostr, "outlineLevel"_ostr, "4");
1020 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[7]"_ostr, "collapsed"_ostr, "false");
1021 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[8]"_ostr, "r"_ostr, "9");
1022 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[8]"_ostr, "hidden"_ostr, "true");
1023 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[8]"_ostr, "outlineLevel"_ostr, "4");
1024 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[8]"_ostr, "collapsed"_ostr, "false");
1025 // Next rows are the same as the previous one but it needs to be preserved,
1026 // as they contain information about outlineLevel
1027 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[20]"_ostr, "r"_ostr, "21");
1028 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[20]"_ostr, "hidden"_ostr, "true");
1029 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[20]"_ostr, "outlineLevel"_ostr, "4");
1030 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[20]"_ostr, "collapsed"_ostr, "false");
1031 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[21]"_ostr, "r"_ostr, "22");
1032 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[21]"_ostr, "hidden"_ostr, "false");
1033 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[21]"_ostr, "outlineLevel"_ostr, "3");
1034 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[21]"_ostr, "collapsed"_ostr, "true");
1035 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[22]"_ostr, "r"_ostr, "23");
1036 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[22]"_ostr, "hidden"_ostr, "false");
1037 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[22]"_ostr, "outlineLevel"_ostr, "3");
1038 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[22]"_ostr, "collapsed"_ostr, "false");
1040 // We expected that exactly 29 Row Nodes will be produced
1041 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row"_ostr, 29);
1044 CPPUNIT_TEST_FIXTURE(ScExportTest, testAllRowsHiddenXLSX)
1046 createScDoc("xlsx/tdf105840_allRowsHidden.xlsx");
1048 save("Calc Office Open XML");
1049 xmlDocUniquePtr pSheet = parseExport("xl/worksheets/sheet1.xml");
1050 CPPUNIT_ASSERT(pSheet);
1051 assertXPath(pSheet, "/x:worksheet/x:sheetFormatPr"_ostr, "zeroHeight"_ostr, "true");
1052 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row"_ostr, 0);
1055 CPPUNIT_TEST_FIXTURE(ScExportTest, testHiddenEmptyRowsXLSX)
1057 //tdf#98106 FILESAVE: Hidden and empty rows became visible when export to .XLSX
1058 createScDoc("ods/hidden-empty-rows.ods");
1060 save("Calc Office Open XML");
1061 xmlDocUniquePtr pSheet = parseExport("xl/worksheets/sheet1.xml");
1062 CPPUNIT_ASSERT(pSheet);
1064 assertXPath(pSheet, "/x:worksheet/x:sheetFormatPr"_ostr, "zeroHeight"_ostr, "false");
1065 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[1]"_ostr, "hidden"_ostr, "true");
1066 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[2]"_ostr, "hidden"_ostr, "true");
1067 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[3]"_ostr, "hidden"_ostr, "true");
1068 assertXPath(pSheet, "/x:worksheet/x:sheetData/x:row[4]"_ostr, "hidden"_ostr, "false");
1071 CPPUNIT_TEST_FIXTURE(ScExportTest, testHiddenEmptyColsODS)
1073 //tdf#98106 FILESAVE: Hidden and empty rows became visible when export to .XLSX
1074 createScDoc("ods/tdf128895_emptyHiddenCols.ods");
1076 save("calc8");
1077 xmlDocUniquePtr pSheet = parseExport("content.xml");
1078 CPPUNIT_ASSERT(pSheet);
1079 assertXPath(pSheet, "//table:table/table:table-column[2]"_ostr);
1080 assertXPath(pSheet, "//table:table/table:table-column[2]"_ostr, "number-columns-repeated"_ostr,
1081 "1017");
1084 CPPUNIT_TEST_FIXTURE(ScExportTest, testLandscapeOrientationXLSX)
1086 //tdf#48767 - Landscape page orientation is not loaded from .xlsx format with MS Excel, after export with Libre Office
1087 createScDoc("ods/hidden-empty-rows.ods");
1089 save("Calc Office Open XML");
1090 xmlDocUniquePtr pSheet = parseExport("xl/worksheets/sheet1.xml");
1091 CPPUNIT_ASSERT(pSheet);
1093 // the usePrinterDefaults cannot be saved to allow opening sheets in Landscape mode via MS Excel
1094 assertXPathNoAttribute(pSheet, "/x:worksheet/x:pageSetup"_ostr, "usePrinterDefaults"_ostr);
1095 assertXPath(pSheet, "/x:worksheet/x:pageSetup"_ostr, "orientation"_ostr, "landscape");
1098 CPPUNIT_TEST_FIXTURE(ScExportTest, testDataBarExportXLSX)
1100 createScDoc("xlsx/databar.xlsx");
1102 saveAndReload("Calc Office Open XML");
1104 ScDocument* pDoc = getScDoc();
1106 testDataBar_Impl(*pDoc);
1109 CPPUNIT_TEST_FIXTURE(ScExportTest, testMiscRowHeightExport)
1111 static const TestParam::RowData DfltRowData[] = {
1112 { 0, 4, 0, 529, 0, false },
1113 { 5, 10, 0, 1058, 0, false },
1114 { 17, 20, 0, 1746, 0, false },
1115 // check last couple of row in document to ensure
1116 // they are 5.29mm ( effective default row xlsx height )
1117 { 1048573, 1048575, 0, 529, 0, false },
1120 static const TestParam::RowData EmptyRepeatRowData[] = {
1121 // rows 0-4, 5-10, 17-20 are all set at various
1122 // heights, there is no content in the rows, there
1123 // was a bug where only the first row ( of repeated rows )
1124 // was set after export
1125 { 0, 4, 0, 529, 0, false },
1126 { 5, 10, 0, 1058, 0, false },
1127 { 17, 20, 0, 1767, 0, false },
1130 TestParam aTestValues[] = {
1131 // Checks that some distributed ( non-empty ) heights remain set after export (roundtrip)
1132 // additionally there is effectively a default row height ( 5.29 mm ). So we test the
1133 // unset rows at the end of the document to ensure the effective xlsx default height
1134 // is set there too.
1135 { u"xlsx/miscrowheights.xlsx", "Calc Office Open XML", SAL_N_ELEMENTS(DfltRowData),
1136 DfltRowData },
1137 // Checks that some distributed ( non-empty ) heights remain set after export (to xls)
1138 { u"xlsx/miscrowheights.xlsx", "MS Excel 97", SAL_N_ELEMENTS(DfltRowData), DfltRowData },
1139 // Checks that repreated rows ( of various heights ) remain set after export ( to xlsx )
1140 { u"ods/miscemptyrepeatedrowheights.ods", "Calc Office Open XML",
1141 SAL_N_ELEMENTS(EmptyRepeatRowData), EmptyRepeatRowData },
1142 // Checks that repreated rows ( of various heights ) remain set after export ( to xls )
1143 { u"ods/miscemptyrepeatedrowheights.ods", "MS Excel 97", SAL_N_ELEMENTS(EmptyRepeatRowData),
1144 EmptyRepeatRowData },
1146 miscRowHeightsTest(aTestValues, SAL_N_ELEMENTS(aTestValues));
1149 namespace
1151 void setAttribute(ScFieldEditEngine& rEE, sal_Int32 nPara, sal_Int32 nStart, sal_Int32 nEnd,
1152 sal_uInt16 nType, Color nColor = COL_BLACK)
1154 ESelection aSel;
1155 aSel.nStartPara = aSel.nEndPara = nPara;
1156 aSel.nStartPos = nStart;
1157 aSel.nEndPos = nEnd;
1159 SfxItemSet aItemSet = rEE.GetEmptyItemSet();
1160 switch (nType)
1162 case EE_CHAR_WEIGHT:
1164 SvxWeightItem aWeight(WEIGHT_BOLD, nType);
1165 aItemSet.Put(aWeight);
1166 rEE.QuickSetAttribs(aItemSet, aSel);
1168 break;
1169 case EE_CHAR_ITALIC:
1171 SvxPostureItem aItalic(ITALIC_NORMAL, nType);
1172 aItemSet.Put(aItalic);
1173 rEE.QuickSetAttribs(aItemSet, aSel);
1175 break;
1176 case EE_CHAR_STRIKEOUT:
1178 SvxCrossedOutItem aCrossOut(STRIKEOUT_SINGLE, nType);
1179 aItemSet.Put(aCrossOut);
1180 rEE.QuickSetAttribs(aItemSet, aSel);
1182 break;
1183 case EE_CHAR_OVERLINE:
1185 SvxOverlineItem aItem(LINESTYLE_DOUBLE, nType);
1186 aItemSet.Put(aItem);
1187 rEE.QuickSetAttribs(aItemSet, aSel);
1189 break;
1190 case EE_CHAR_UNDERLINE:
1192 SvxUnderlineItem aItem(LINESTYLE_DOUBLE, nType);
1193 aItemSet.Put(aItem);
1194 rEE.QuickSetAttribs(aItemSet, aSel);
1196 break;
1197 case EE_CHAR_COLOR:
1199 SvxColorItem aItem(nColor, nType);
1200 aItemSet.Put(aItem);
1201 rEE.QuickSetAttribs(aItemSet, aSel);
1203 break;
1204 default:;
1208 void setFont(ScFieldEditEngine& rEE, sal_Int32 nPara, sal_Int32 nStart, sal_Int32 nEnd,
1209 const OUString& rFontName)
1211 ESelection aSel;
1212 aSel.nStartPara = aSel.nEndPara = nPara;
1213 aSel.nStartPos = nStart;
1214 aSel.nEndPos = nEnd;
1216 SfxItemSet aItemSet = rEE.GetEmptyItemSet();
1217 SvxFontItem aItem(FAMILY_MODERN, rFontName, "", PITCH_VARIABLE, RTL_TEXTENCODING_UTF8,
1218 EE_CHAR_FONTINFO);
1219 aItemSet.Put(aItem);
1220 rEE.QuickSetAttribs(aItemSet, aSel);
1223 void setEscapement(ScFieldEditEngine& rEE, sal_Int32 nPara, sal_Int32 nStart, sal_Int32 nEnd,
1224 short nEsc, sal_uInt8 nRelSize)
1226 ESelection aSel;
1227 aSel.nStartPara = aSel.nEndPara = nPara;
1228 aSel.nStartPos = nStart;
1229 aSel.nEndPos = nEnd;
1231 SfxItemSet aItemSet = rEE.GetEmptyItemSet();
1232 SvxEscapementItem aItem(nEsc, nRelSize, EE_CHAR_ESCAPEMENT);
1233 aItemSet.Put(aItem);
1234 rEE.QuickSetAttribs(aItemSet, aSel);
1238 CPPUNIT_TEST_FIXTURE(ScExportTest, testNamedRangeBugfdo62729)
1240 #if !defined(MACOSX) // FIXME: infinite loop on jenkins' mac
1241 createScDoc("ods/fdo62729.ods");
1242 ScDocument* pDoc = getScDoc();
1244 ScRangeName* pNames = pDoc->GetRangeName();
1245 //should be just a single named range
1246 CPPUNIT_ASSERT_EQUAL(size_t(1), pNames->size());
1247 pDoc->DeleteTab(0);
1248 //should be still a single named range
1249 CPPUNIT_ASSERT_EQUAL(size_t(1), pNames->size());
1250 saveAndReload("calc8");
1252 pDoc = getScDoc();
1254 pNames = pDoc->GetRangeName();
1255 //after reload should still have a named range
1256 CPPUNIT_ASSERT_EQUAL(size_t(1), pNames->size());
1257 #endif
1260 CPPUNIT_TEST_FIXTURE(ScExportTest, testBuiltinRangesXLSX)
1262 createScDoc("xlsx/built-in_ranges.xlsx");
1264 save("Calc Office Open XML");
1265 xmlDocUniquePtr pDoc = parseExport("xl/workbook.xml");
1266 CPPUNIT_ASSERT(pDoc);
1268 //assert the existing OOXML built-in names are still there
1269 assertXPathContent(pDoc,
1270 "/x:workbook/x:definedNames/"
1271 "x:definedName[@name='_xlnm._FilterDatabase'][@localSheetId='0']"_ostr,
1272 "'Sheet1 Test'!$A$1:$A$5");
1273 assertXPathContent(pDoc,
1274 "/x:workbook/x:definedNames/"
1275 "x:definedName[@name='_xlnm._FilterDatabase'][@localSheetId='1']"_ostr,
1276 "'Sheet2 Test'!$K$10:$K$14");
1277 assertXPathContent(
1278 pDoc,
1279 "/x:workbook/x:definedNames/x:definedName[@name='_xlnm.Print_Area'][@localSheetId='0']"_ostr,
1280 "'Sheet1 Test'!$A$1:$A$5");
1281 assertXPathContent(
1282 pDoc,
1283 "/x:workbook/x:definedNames/x:definedName[@name='_xlnm.Print_Area'][@localSheetId='1']"_ostr,
1284 "'Sheet2 Test'!$K$10:$M$18");
1286 //...and that no extra ones are added (see tdf#112571)
1287 assertXPath(pDoc,
1288 "/x:workbook/x:definedNames/"
1289 "x:definedName[@name='_xlnm._FilterDatabase_0'][@localSheetId='0']"_ostr,
1291 assertXPath(pDoc,
1292 "/x:workbook/x:definedNames/"
1293 "x:definedName[@name='_xlnm._FilterDatabase_0'][@localSheetId='1']"_ostr,
1295 assertXPath(
1296 pDoc,
1297 "/x:workbook/x:definedNames/x:definedName[@name='_xlnm.Print_Area_0'][@localSheetId='0']"_ostr,
1299 assertXPath(
1300 pDoc,
1301 "/x:workbook/x:definedNames/x:definedName[@name='_xlnm.Print_Area_0'][@localSheetId='1']"_ostr,
1305 CPPUNIT_TEST_FIXTURE(ScExportTest, testRichTextExportODS)
1307 struct
1309 static bool isBold(const editeng::Section& rAttr)
1311 return std::any_of(
1312 rAttr.maAttributes.begin(), rAttr.maAttributes.end(), [](const SfxPoolItem* p) {
1313 return p->Which() == EE_CHAR_WEIGHT
1314 && static_cast<const SvxWeightItem*>(p)->GetWeight() == WEIGHT_BOLD;
1318 static bool isItalic(const editeng::Section& rAttr)
1320 return std::any_of(
1321 rAttr.maAttributes.begin(), rAttr.maAttributes.end(), [](const SfxPoolItem* p) {
1322 return p->Which() == EE_CHAR_ITALIC
1323 && static_cast<const SvxPostureItem*>(p)->GetPosture() == ITALIC_NORMAL;
1327 static bool isStrikeOut(const editeng::Section& rAttr)
1329 return std::any_of(
1330 rAttr.maAttributes.begin(), rAttr.maAttributes.end(), [](const SfxPoolItem* p) {
1331 return p->Which() == EE_CHAR_STRIKEOUT
1332 && static_cast<const SvxCrossedOutItem*>(p)->GetStrikeout()
1333 == STRIKEOUT_SINGLE;
1337 static bool isOverline(const editeng::Section& rAttr, FontLineStyle eStyle)
1339 return std::any_of(rAttr.maAttributes.begin(), rAttr.maAttributes.end(),
1340 [&eStyle](const SfxPoolItem* p) {
1341 return p->Which() == EE_CHAR_OVERLINE
1342 && static_cast<const SvxOverlineItem*>(p)->GetLineStyle()
1343 == eStyle;
1347 static bool isUnderline(const editeng::Section& rAttr, FontLineStyle eStyle)
1349 return std::any_of(rAttr.maAttributes.begin(), rAttr.maAttributes.end(),
1350 [&eStyle](const SfxPoolItem* p) {
1351 return p->Which() == EE_CHAR_UNDERLINE
1352 && static_cast<const SvxUnderlineItem*>(p)->GetLineStyle()
1353 == eStyle;
1357 static bool isFont(const editeng::Section& rAttr, const OUString& rFontName)
1359 return std::any_of(rAttr.maAttributes.begin(), rAttr.maAttributes.end(),
1360 [&rFontName](const SfxPoolItem* p) {
1361 return p->Which() == EE_CHAR_FONTINFO
1362 && static_cast<const SvxFontItem*>(p)->GetFamilyName()
1363 == rFontName;
1367 static bool isEscapement(const editeng::Section& rAttr, short nEsc, sal_uInt8 nRelSize)
1369 return std::any_of(rAttr.maAttributes.begin(), rAttr.maAttributes.end(),
1370 [&nEsc, &nRelSize](const SfxPoolItem* p) {
1371 if (p->Which() != EE_CHAR_ESCAPEMENT)
1372 return false;
1373 const SvxEscapementItem* pItem
1374 = static_cast<const SvxEscapementItem*>(p);
1375 return ((pItem->GetEsc() == nEsc)
1376 && (pItem->GetProportionalHeight() == nRelSize));
1380 static bool isColor(const editeng::Section& rAttr, Color nColor)
1382 return std::any_of(rAttr.maAttributes.begin(), rAttr.maAttributes.end(),
1383 [&nColor](const SfxPoolItem* p) {
1384 return p->Which() == EE_CHAR_COLOR
1385 && static_cast<const SvxColorItem*>(p)->GetValue()
1386 == nColor;
1390 bool checkB2(const EditTextObject* pText) const
1392 if (!pText)
1393 return false;
1395 if (pText->GetParagraphCount() != 1)
1396 return false;
1398 if (pText->GetText(0) != "Bold and Italic")
1399 return false;
1401 std::vector<editeng::Section> aSecAttrs;
1402 pText->GetAllSections(aSecAttrs);
1403 if (aSecAttrs.size() != 3)
1404 return false;
1406 // Check the first bold section.
1407 const editeng::Section* pAttr = aSecAttrs.data();
1408 if (pAttr->mnParagraph != 0 || pAttr->mnStart != 0 || pAttr->mnEnd != 4)
1409 return false;
1411 if (pAttr->maAttributes.size() != 1 || !isBold(*pAttr))
1412 return false;
1414 // The middle section should be unformatted.
1415 pAttr = &aSecAttrs[1];
1416 if (pAttr->mnParagraph != 0 || pAttr->mnStart != 4 || pAttr->mnEnd != 9)
1417 return false;
1419 if (!pAttr->maAttributes.empty())
1420 return false;
1422 // The last section should be italic.
1423 pAttr = &aSecAttrs[2];
1424 if (pAttr->mnParagraph != 0 || pAttr->mnStart != 9 || pAttr->mnEnd != 15)
1425 return false;
1427 if (pAttr->maAttributes.size() != 1 || !isItalic(*pAttr))
1428 return false;
1430 return true;
1433 bool checkB4(const EditTextObject* pText) const
1435 if (!pText)
1436 return false;
1438 if (pText->GetParagraphCount() != 3)
1439 return false;
1441 if (pText->GetText(0) != "One")
1442 return false;
1444 if (pText->GetText(1) != "Two")
1445 return false;
1447 if (pText->GetText(2) != "Three")
1448 return false;
1450 return true;
1453 bool checkB5(const EditTextObject* pText) const
1455 if (!pText)
1456 return false;
1458 if (pText->GetParagraphCount() != 6)
1459 return false;
1461 if (!pText->GetText(0).isEmpty())
1462 return false;
1464 if (pText->GetText(1) != "Two")
1465 return false;
1467 if (pText->GetText(2) != "Three")
1468 return false;
1470 if (!pText->GetText(3).isEmpty())
1471 return false;
1473 if (pText->GetText(4) != "Five")
1474 return false;
1476 if (!pText->GetText(5).isEmpty())
1477 return false;
1479 return true;
1482 bool checkB6(const EditTextObject* pText) const
1484 if (!pText)
1485 return false;
1487 if (pText->GetParagraphCount() != 1)
1488 return false;
1490 if (pText->GetText(0) != "Strike Me")
1491 return false;
1493 std::vector<editeng::Section> aSecAttrs;
1494 pText->GetAllSections(aSecAttrs);
1495 if (aSecAttrs.size() != 2)
1496 return false;
1498 // Check the first strike-out section.
1499 const editeng::Section* pAttr = aSecAttrs.data();
1500 if (pAttr->mnParagraph != 0 || pAttr->mnStart != 0 || pAttr->mnEnd != 6)
1501 return false;
1503 if (pAttr->maAttributes.size() != 1 || !isStrikeOut(*pAttr))
1504 return false;
1506 // The last section should be unformatted.
1507 pAttr = &aSecAttrs[1];
1508 return pAttr->mnParagraph == 0 && pAttr->mnStart == 6 && pAttr->mnEnd == 9;
1511 bool checkB7(const EditTextObject* pText) const
1513 if (!pText)
1514 return false;
1516 if (pText->GetParagraphCount() != 1)
1517 return false;
1519 if (pText->GetText(0) != "Font1 and Font2")
1520 return false;
1522 std::vector<editeng::Section> aSecAttrs;
1523 pText->GetAllSections(aSecAttrs);
1524 if (aSecAttrs.size() != 3)
1525 return false;
1527 // First section should have "Courier" font applied.
1528 const editeng::Section* pAttr = aSecAttrs.data();
1529 if (pAttr->mnParagraph != 0 || pAttr->mnStart != 0 || pAttr->mnEnd != 5)
1530 return false;
1532 if (pAttr->maAttributes.size() != 1 || !isFont(*pAttr, "Courier"))
1533 return false;
1535 // Last section should have "Luxi Mono" applied.
1536 pAttr = &aSecAttrs[2];
1537 if (pAttr->mnParagraph != 0 || pAttr->mnStart != 10 || pAttr->mnEnd != 15)
1538 return false;
1540 if (pAttr->maAttributes.size() != 1 || !isFont(*pAttr, "Luxi Mono"))
1541 return false;
1543 return true;
1546 bool checkB8(const EditTextObject* pText) const
1548 if (!pText)
1549 return false;
1551 if (pText->GetParagraphCount() != 1)
1552 return false;
1554 if (pText->GetText(0) != "Over and Under")
1555 return false;
1557 std::vector<editeng::Section> aSecAttrs;
1558 pText->GetAllSections(aSecAttrs);
1559 if (aSecAttrs.size() != 3)
1560 return false;
1562 // First section should have overline applied.
1563 const editeng::Section* pAttr = aSecAttrs.data();
1564 if (pAttr->mnParagraph != 0 || pAttr->mnStart != 0 || pAttr->mnEnd != 4)
1565 return false;
1567 if (pAttr->maAttributes.size() != 1 || !isOverline(*pAttr, LINESTYLE_DOUBLE))
1568 return false;
1570 // Last section should have underline applied.
1571 pAttr = &aSecAttrs[2];
1572 if (pAttr->mnParagraph != 0 || pAttr->mnStart != 9 || pAttr->mnEnd != 14)
1573 return false;
1575 if (pAttr->maAttributes.size() != 1 || !isUnderline(*pAttr, LINESTYLE_DOUBLE))
1576 return false;
1578 return true;
1581 bool checkB9(const EditTextObject* pText) const
1583 if (!pText)
1584 return false;
1586 if (pText->GetParagraphCount() != 1)
1587 return false;
1589 if (pText->GetText(0) != "Sub and Super")
1590 return false;
1592 std::vector<editeng::Section> aSecAttrs;
1593 pText->GetAllSections(aSecAttrs);
1594 if (aSecAttrs.size() != 3)
1595 return false;
1597 // superscript
1598 const editeng::Section* pAttr = aSecAttrs.data();
1599 if (pAttr->mnParagraph != 0 || pAttr->mnStart != 0 || pAttr->mnEnd != 3)
1600 return false;
1602 if (pAttr->maAttributes.size() != 1 || !isEscapement(*pAttr, 32, 64))
1603 return false;
1605 // subscript
1606 pAttr = &aSecAttrs[2];
1607 if (pAttr->mnParagraph != 0 || pAttr->mnStart != 8 || pAttr->mnEnd != 13)
1608 return false;
1610 if (pAttr->maAttributes.size() != 1 || !isEscapement(*pAttr, -32, 66))
1611 return false;
1613 return true;
1616 bool checkB10(const EditTextObject* pText) const
1618 if (!pText)
1619 return false;
1621 if (pText->GetParagraphCount() != 1)
1622 return false;
1624 if (pText->GetText(0) != "BLUE AUTO")
1625 return false;
1627 std::vector<editeng::Section> aSecAttrs;
1628 pText->GetAllSections(aSecAttrs);
1629 if (aSecAttrs.size() != 2)
1630 return false;
1632 // auto color
1633 const editeng::Section* pAttr = &aSecAttrs[1];
1634 if (pAttr->mnParagraph != 0 || pAttr->mnStart != 5 || pAttr->mnEnd != 9)
1635 return false;
1637 if (pAttr->maAttributes.size() != 1 || !isColor(*pAttr, COL_AUTO))
1638 return false;
1640 return true;
1643 } aCheckFunc;
1645 // Start with an empty document, put one edit text cell, and make sure it
1646 // survives the save and reload.
1647 createScDoc();
1648 const EditTextObject* pEditText;
1650 ScDocument* pDoc = getScDoc();
1651 CPPUNIT_ASSERT_MESSAGE("This document should at least have one sheet.",
1652 pDoc->GetTableCount() > 0);
1654 // Insert an edit text cell.
1655 ScFieldEditEngine* pEE = &pDoc->GetEditEngine();
1656 pEE->SetTextCurrentDefaults("Bold and Italic");
1657 // Set the 'Bold' part bold.
1658 setAttribute(*pEE, 0, 0, 4, EE_CHAR_WEIGHT);
1659 // Set the 'Italic' part italic.
1660 setAttribute(*pEE, 0, 9, 15, EE_CHAR_ITALIC);
1661 ESelection aSel;
1662 aSel.nStartPara = aSel.nEndPara = 0;
1664 // Set this edit text to cell B2.
1665 pDoc->SetEditText(ScAddress(1, 1, 0), pEE->CreateTextObject());
1666 pEditText = pDoc->GetEditText(ScAddress(1, 1, 0));
1667 CPPUNIT_ASSERT_MESSAGE("Incorrect B2 value.", aCheckFunc.checkB2(pEditText));
1670 // Now, save and reload this document.
1671 saveAndReload("calc8");
1673 ScDocument* pDoc = getScDoc();
1674 CPPUNIT_ASSERT_MESSAGE("Reloaded document should at least have one sheet.",
1675 pDoc->GetTableCount() > 0);
1676 ScFieldEditEngine* pEE = &pDoc->GetEditEngine();
1677 pEditText = pDoc->GetEditText(ScAddress(1, 1, 0));
1679 // Make sure the content of B2 is still intact.
1680 CPPUNIT_ASSERT_MESSAGE("Incorrect B2 value.", aCheckFunc.checkB2(pEditText));
1682 // Insert a multi-line content to B4.
1683 pEE->Clear();
1684 pEE->SetTextCurrentDefaults("One\nTwo\nThree");
1685 pDoc->SetEditText(ScAddress(1, 3, 0), pEE->CreateTextObject());
1686 pEditText = pDoc->GetEditText(ScAddress(1, 3, 0));
1687 CPPUNIT_ASSERT_MESSAGE("Incorrect B4 value.", aCheckFunc.checkB4(pEditText));
1690 // Reload the doc again, and check the content of B2 and B4.
1691 saveAndReload("calc8");
1693 ScDocument* pDoc = getScDoc();
1694 ScFieldEditEngine* pEE = &pDoc->GetEditEngine();
1696 pEditText = pDoc->GetEditText(ScAddress(1, 1, 0));
1697 CPPUNIT_ASSERT_MESSAGE("B2 should be an edit text.", pEditText);
1698 pEditText = pDoc->GetEditText(ScAddress(1, 3, 0));
1699 CPPUNIT_ASSERT_MESSAGE("Incorrect B4 value.", aCheckFunc.checkB4(pEditText));
1701 // Insert a multi-line content to B5, but this time, set some empty paragraphs.
1702 pEE->Clear();
1703 pEE->SetTextCurrentDefaults("\nTwo\nThree\n\nFive\n");
1704 pDoc->SetEditText(ScAddress(1, 4, 0), pEE->CreateTextObject());
1705 pEditText = pDoc->GetEditText(ScAddress(1, 4, 0));
1706 CPPUNIT_ASSERT_MESSAGE("Incorrect B5 value.", aCheckFunc.checkB5(pEditText));
1708 // Insert a text with strikethrough in B6.
1709 pEE->Clear();
1710 pEE->SetTextCurrentDefaults("Strike Me");
1711 // Set the 'Strike' part strikethrough.
1712 setAttribute(*pEE, 0, 0, 6, EE_CHAR_STRIKEOUT);
1713 pDoc->SetEditText(ScAddress(1, 5, 0), pEE->CreateTextObject());
1714 pEditText = pDoc->GetEditText(ScAddress(1, 5, 0));
1715 CPPUNIT_ASSERT_MESSAGE("Incorrect B6 value.", aCheckFunc.checkB6(pEditText));
1717 // Insert a text with different font segments in B7.
1718 pEE->Clear();
1719 pEE->SetTextCurrentDefaults("Font1 and Font2");
1720 setFont(*pEE, 0, 0, 5, "Courier");
1721 setFont(*pEE, 0, 10, 15, "Luxi Mono");
1722 pDoc->SetEditText(ScAddress(1, 6, 0), pEE->CreateTextObject());
1723 pEditText = pDoc->GetEditText(ScAddress(1, 6, 0));
1724 CPPUNIT_ASSERT_MESSAGE("Incorrect B7 value.", aCheckFunc.checkB7(pEditText));
1726 // Insert a text with overline and underline in B8.
1727 pEE->Clear();
1728 pEE->SetTextCurrentDefaults("Over and Under");
1729 setAttribute(*pEE, 0, 0, 4, EE_CHAR_OVERLINE);
1730 setAttribute(*pEE, 0, 9, 14, EE_CHAR_UNDERLINE);
1731 pDoc->SetEditText(ScAddress(1, 7, 0), pEE->CreateTextObject());
1732 pEditText = pDoc->GetEditText(ScAddress(1, 7, 0));
1733 CPPUNIT_ASSERT_MESSAGE("Incorrect B8 value.", aCheckFunc.checkB8(pEditText));
1735 pEE->Clear();
1736 pEE->SetTextCurrentDefaults("Sub and Super");
1737 setEscapement(*pEE, 0, 0, 3, 32, 64);
1738 setEscapement(*pEE, 0, 8, 13, -32, 66);
1739 pDoc->SetEditText(ScAddress(1, 8, 0), pEE->CreateTextObject());
1740 pEditText = pDoc->GetEditText(ScAddress(1, 8, 0));
1741 CPPUNIT_ASSERT_MESSAGE("Incorrect B9 value.", aCheckFunc.checkB9(pEditText));
1743 ScPatternAttr aCellFontColor(pDoc->GetPool());
1744 aCellFontColor.GetItemSet().Put(SvxColorItem(COL_BLUE, ATTR_FONT_COLOR));
1745 // Set font color of B10 to blue.
1746 pDoc->ApplyPattern(1, 9, 0, aCellFontColor);
1747 pEE->Clear();
1748 pEE->SetTextCurrentDefaults("BLUE AUTO");
1749 // Set the color of the string "AUTO" to automatic color.
1750 setAttribute(*pEE, 0, 5, 9, EE_CHAR_COLOR, COL_AUTO);
1751 pDoc->SetEditText(ScAddress(1, 9, 0), pEE->CreateTextObject());
1752 pEditText = pDoc->GetEditText(ScAddress(1, 9, 0));
1753 CPPUNIT_ASSERT_MESSAGE("Incorrect B10 value.", aCheckFunc.checkB10(pEditText));
1756 // Reload the doc again, and check the content of B2, B4, B6 and B7.
1757 saveAndReload("calc8");
1758 ScDocument* pDoc = getScDoc();
1760 pEditText = pDoc->GetEditText(ScAddress(1, 1, 0));
1761 CPPUNIT_ASSERT_MESSAGE("Incorrect B2 value after save and reload.",
1762 aCheckFunc.checkB2(pEditText));
1763 pEditText = pDoc->GetEditText(ScAddress(1, 3, 0));
1764 CPPUNIT_ASSERT_MESSAGE("Incorrect B4 value after save and reload.",
1765 aCheckFunc.checkB4(pEditText));
1766 pEditText = pDoc->GetEditText(ScAddress(1, 4, 0));
1767 CPPUNIT_ASSERT_MESSAGE("Incorrect B5 value after save and reload.",
1768 aCheckFunc.checkB5(pEditText));
1769 pEditText = pDoc->GetEditText(ScAddress(1, 5, 0));
1770 CPPUNIT_ASSERT_MESSAGE("Incorrect B6 value after save and reload.",
1771 aCheckFunc.checkB6(pEditText));
1772 pEditText = pDoc->GetEditText(ScAddress(1, 6, 0));
1773 CPPUNIT_ASSERT_MESSAGE("Incorrect B7 value after save and reload.",
1774 aCheckFunc.checkB7(pEditText));
1775 pEditText = pDoc->GetEditText(ScAddress(1, 7, 0));
1776 CPPUNIT_ASSERT_MESSAGE("Incorrect B8 value after save and reload.",
1777 aCheckFunc.checkB8(pEditText));
1778 pEditText = pDoc->GetEditText(ScAddress(1, 9, 0));
1779 CPPUNIT_ASSERT_MESSAGE("Incorrect B10 value after save and reload.",
1780 aCheckFunc.checkB10(pEditText));
1783 CPPUNIT_TEST_FIXTURE(ScExportTest, testRichTextCellFormatXLSX)
1785 createScDoc("xls/cellformat.xls");
1787 save("Calc Office Open XML");
1788 xmlDocUniquePtr pSheet = parseExport("xl/worksheets/sheet1.xml");
1789 CPPUNIT_ASSERT(pSheet);
1791 // make sure the only cell in this doc is assigned some formatting record
1792 OUString aCellFormat = getXPath(pSheet, "/x:worksheet/x:sheetData/x:row/x:c"_ostr, "s"_ostr);
1793 CPPUNIT_ASSERT_MESSAGE("Cell format is missing", !aCellFormat.isEmpty());
1795 xmlDocUniquePtr pStyles = parseExport("xl/styles.xml");
1796 CPPUNIT_ASSERT(pStyles);
1798 OString nFormatIdx = OString::number(aCellFormat.toInt32() + 1);
1799 const OString aXPath1("/x:styleSheet/x:cellXfs/x:xf[" + nFormatIdx + "]/x:alignment");
1800 // formatting record is set to wrap text
1801 assertXPath(pStyles, aXPath1, "wrapText"_ostr, "true");
1803 // see what font it references
1804 const OString aXPath2("/x:styleSheet/x:cellXfs/x:xf[" + nFormatIdx + "]");
1805 OUString aFontId = getXPath(pStyles, aXPath2, "fontId"_ostr);
1806 OString nFontIdx = OString::number(aFontId.toInt32() + 1);
1808 // that font should be bold
1809 const OString aXPath3("/x:styleSheet/x:fonts/x:font[" + nFontIdx + "]/x:b");
1810 assertXPath(pStyles, aXPath3, "val"_ostr, "true");
1813 CPPUNIT_TEST_FIXTURE(ScExportTest, testWrapText)
1815 createScDoc("xlsx/wrap-text.xlsx");
1817 save("Calc Office Open XML");
1819 xmlDocUniquePtr pStyles = parseExport("xl/styles.xml");
1820 CPPUNIT_ASSERT(pStyles);
1822 assertXPath(pStyles, "/x:styleSheet/x:cellXfs"_ostr, "count"_ostr, "7");
1824 assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[1]/x:alignment"_ostr, "wrapText"_ostr,
1825 "false");
1826 assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[2]/x:alignment"_ostr, "wrapText"_ostr,
1827 "false");
1828 assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[3]/x:alignment"_ostr, "wrapText"_ostr,
1829 "false");
1830 assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[4]/x:alignment"_ostr, "wrapText"_ostr,
1831 "false");
1832 assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[5]/x:alignment"_ostr, "wrapText"_ostr,
1833 "true");
1834 assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[6]/x:alignment"_ostr, "wrapText"_ostr,
1835 "true");
1836 assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[7]/x:alignment"_ostr, "wrapText"_ostr,
1837 "true");
1840 CPPUNIT_TEST_FIXTURE(ScExportTest, testFormulaRefSheetNameODS)
1842 createScDoc("ods/formula-quote-in-sheet-name.ods");
1844 ScDocument* pDoc = getScDoc();
1846 sc::AutoCalcSwitch aACSwitch(*pDoc, true); // turn on auto calc.
1847 pDoc->SetString(ScAddress(1, 1, 0), "='90''s Data'.B2");
1848 CPPUNIT_ASSERT_EQUAL(1.1, pDoc->GetValue(ScAddress(1, 1, 0)));
1849 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("='90''s Data'.B2"),
1850 pDoc->GetFormula(1, 1, 0));
1852 // Now, save and reload this document.
1853 saveAndReload("calc8");
1855 ScDocument* pDoc = getScDoc();
1856 pDoc->CalcAll();
1857 CPPUNIT_ASSERT_EQUAL(1.1, pDoc->GetValue(ScAddress(1, 1, 0)));
1858 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("='90''s Data'.B2"),
1859 pDoc->GetFormula(1, 1, 0));
1862 CPPUNIT_TEST_FIXTURE(ScExportTest, testCellValuesExportODS)
1864 // Start with an empty document
1865 createScDoc();
1867 ScDocument* pDoc = getScDoc();
1868 CPPUNIT_ASSERT_MESSAGE("This document should at least have one sheet.",
1869 pDoc->GetTableCount() > 0);
1871 // set a value double
1872 pDoc->SetValue(ScAddress(0, 0, 0), 2.0); // A1
1874 // set a formula
1875 pDoc->SetValue(ScAddress(2, 0, 0), 3.0); // C1
1876 pDoc->SetValue(ScAddress(3, 0, 0), 3); // D1
1877 pDoc->SetString(ScAddress(4, 0, 0), "=10*C1/4"); // E1
1878 pDoc->SetValue(ScAddress(5, 0, 0), 3.0); // F1
1879 pDoc->SetString(ScAddress(7, 0, 0), "=SUM(C1:F1)"); //H1
1881 // set a string
1882 pDoc->SetString(ScAddress(0, 2, 0), "a simple line"); //A3
1884 // set a digit string
1885 pDoc->SetString(ScAddress(0, 4, 0), "'12"); //A5
1886 // set a contiguous value
1887 pDoc->SetValue(ScAddress(0, 5, 0), 12.0); //A6
1888 // set a contiguous string
1889 pDoc->SetString(ScAddress(0, 6, 0), "a string"); //A7
1890 // set a contiguous formula
1891 pDoc->SetString(ScAddress(0, 7, 0), "=$A$6"); //A8
1893 // save and reload
1894 saveAndReload("calc8");
1895 ScDocument* pDoc = getScDoc();
1896 CPPUNIT_ASSERT_MESSAGE("Reloaded document should at least have one sheet.",
1897 pDoc->GetTableCount() > 0);
1899 // check value
1900 CPPUNIT_ASSERT_EQUAL(2.0, pDoc->GetValue(0, 0, 0));
1901 CPPUNIT_ASSERT_EQUAL(3.0, pDoc->GetValue(2, 0, 0));
1902 CPPUNIT_ASSERT_EQUAL(3.0, pDoc->GetValue(3, 0, 0));
1903 CPPUNIT_ASSERT_EQUAL(7.5, pDoc->GetValue(4, 0, 0));
1904 CPPUNIT_ASSERT_EQUAL(3.0, pDoc->GetValue(5, 0, 0));
1906 // check formula
1907 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula =10*C1/4", OUString("=10*C1/4"),
1908 pDoc->GetFormula(4, 0, 0));
1909 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula =SUM(C1:F1)", OUString("=SUM(C1:F1)"),
1910 pDoc->GetFormula(7, 0, 0));
1911 CPPUNIT_ASSERT_EQUAL(16.5, pDoc->GetValue(7, 0, 0));
1913 // check string
1914 ScRefCellValue aCell;
1915 aCell.assign(*pDoc, ScAddress(0, 2, 0));
1916 CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, aCell.getType());
1918 // check for an empty cell
1919 aCell.assign(*pDoc, ScAddress(0, 3, 0));
1920 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, aCell.getType());
1922 // check a digit string
1923 aCell.assign(*pDoc, ScAddress(0, 4, 0));
1924 CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, aCell.getType());
1926 //check contiguous values
1927 CPPUNIT_ASSERT_EQUAL(12.0, pDoc->GetValue(0, 5, 0));
1928 CPPUNIT_ASSERT_EQUAL(OUString("a string"), pDoc->GetString(0, 6, 0));
1929 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula =$A$6", OUString("=$A$6"),
1930 pDoc->GetFormula(0, 7, 0));
1931 CPPUNIT_ASSERT_EQUAL(pDoc->GetValue(0, 5, 0), pDoc->GetValue(0, 7, 0));
1934 CPPUNIT_TEST_FIXTURE(ScExportTest, testCellNoteExportODS)
1936 createScDoc("ods/single-note.ods");
1937 ScAddress aPos(0, 0, 0); // Start with A1.
1939 ScDocument* pDoc = getScDoc();
1941 CPPUNIT_ASSERT_MESSAGE("There should be a note at A1.", pDoc->HasNote(aPos));
1943 aPos.IncRow(); // Move to A2.
1944 ScPostIt* pNote = pDoc->GetOrCreateNote(aPos);
1945 pNote->SetText(aPos, "Note One");
1946 pNote->SetAuthor("Author One");
1947 CPPUNIT_ASSERT_MESSAGE("There should be a note at A2.", pDoc->HasNote(aPos));
1949 // save and reload
1950 saveAndReload("calc8");
1951 ScDocument* pDoc = getScDoc();
1953 aPos.SetRow(0); // Move back to A1.
1954 CPPUNIT_ASSERT_MESSAGE("There should be a note at A1.", pDoc->HasNote(aPos));
1955 aPos.IncRow(); // Move to A2.
1956 CPPUNIT_ASSERT_MESSAGE("There should be a note at A2.", pDoc->HasNote(aPos));
1959 CPPUNIT_TEST_FIXTURE(ScExportTest, testCellNoteExportXLS)
1961 // Start with an empty document.s
1962 createScDoc("ods/notes-on-3-sheets.ods");
1964 ScDocument* pDoc = getScDoc();
1965 CPPUNIT_ASSERT_EQUAL_MESSAGE("This document should have 3 sheets.", SCTAB(3),
1966 pDoc->GetTableCount());
1968 // Check note's presence.
1969 CPPUNIT_ASSERT(pDoc->HasNote(ScAddress(0, 0, 0)));
1970 CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 1, 0)));
1971 CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 2, 0)));
1973 CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 0, 1)));
1974 CPPUNIT_ASSERT(pDoc->HasNote(ScAddress(0, 1, 1)));
1975 CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 2, 1)));
1977 CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 0, 2)));
1978 CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 1, 2)));
1979 CPPUNIT_ASSERT(pDoc->HasNote(ScAddress(0, 2, 2)));
1981 // save and reload as XLS.
1982 saveAndReload("MS Excel 97");
1984 ScDocument* pDoc = getScDoc();
1985 CPPUNIT_ASSERT_EQUAL_MESSAGE("This document should have 3 sheets.", SCTAB(3),
1986 pDoc->GetTableCount());
1988 // Check note's presence again.
1989 CPPUNIT_ASSERT(pDoc->HasNote(ScAddress(0, 0, 0)));
1990 CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 1, 0)));
1991 CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 2, 0)));
1993 CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 0, 1)));
1994 CPPUNIT_ASSERT(pDoc->HasNote(ScAddress(0, 1, 1)));
1995 CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 2, 1)));
1997 CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 0, 2)));
1998 CPPUNIT_ASSERT(!pDoc->HasNote(ScAddress(0, 1, 2)));
1999 CPPUNIT_ASSERT(pDoc->HasNote(ScAddress(0, 2, 2)));
2003 namespace
2005 void checkMatrixRange(ScDocument& rDoc, const ScRange& rRange)
2007 ScRange aMatRange;
2008 ScAddress aMatOrigin;
2009 for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
2011 for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
2013 ScAddress aPos(nCol, nRow, rRange.aStart.Tab());
2014 bool bIsMatrix = rDoc.GetMatrixFormulaRange(aPos, aMatRange);
2015 CPPUNIT_ASSERT_MESSAGE("Matrix expected, but not found.", bIsMatrix);
2016 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong matrix range.", rRange, aMatRange);
2017 const ScFormulaCell* pCell = rDoc.GetFormulaCell(aPos);
2018 CPPUNIT_ASSERT_MESSAGE("This must be a formula cell.", pCell);
2020 bIsMatrix = pCell->GetMatrixOrigin(rDoc, aMatOrigin);
2021 CPPUNIT_ASSERT_MESSAGE("Not a part of matrix formula.", bIsMatrix);
2022 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong matrix origin.", aMatRange.aStart, aMatOrigin);
2028 CPPUNIT_TEST_FIXTURE(ScExportTest, testInlineArrayXLS)
2030 createScDoc("xls/inline-array.xls");
2032 saveAndReload("MS Excel 97");
2034 ScDocument* pDoc = getScDoc();
2036 // B2:C3 contains a matrix.
2037 checkMatrixRange(*pDoc, ScRange(1, 1, 0, 2, 2, 0));
2039 // B5:D6 contains a matrix.
2040 checkMatrixRange(*pDoc, ScRange(1, 4, 0, 3, 5, 0));
2042 // B8:C10 as well.
2043 checkMatrixRange(*pDoc, ScRange(1, 7, 0, 2, 9, 0));
2046 CPPUNIT_TEST_FIXTURE(ScExportTest, testEmbeddedChartODS)
2048 createScDoc("xls/embedded-chart.xls");
2050 save("calc8");
2052 xmlDocUniquePtr pDoc = parseExport("content.xml");
2053 CPPUNIT_ASSERT(pDoc);
2054 assertXPath(pDoc,
2055 "/office:document-content/office:body/office:spreadsheet/table:table[2]/"
2056 "table:table-row[7]/table:table-cell[2]/draw:frame/draw:object"_ostr,
2057 "notify-on-update-of-ranges"_ostr,
2058 "Chart1.B3:Chart1.B5 Chart1.C2:Chart1.C2 Chart1.C3:Chart1.C5");
2061 CPPUNIT_TEST_FIXTURE(ScExportTest, testEmbeddedChartXLS)
2063 createScDoc("xls/embedded-chart.xls");
2065 saveAndReload("MS Excel 97");
2067 ScDocument* pDoc = getScDoc();
2069 // Make sure the 2nd sheet is named 'Chart1'.
2070 OUString aName;
2071 pDoc->GetName(1, aName);
2072 CPPUNIT_ASSERT_EQUAL(OUString("Chart1"), aName);
2074 const SdrOle2Obj* pOleObj = getSingleChartObject(*pDoc, 1);
2075 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve a chart object from the 2nd sheet.", pOleObj);
2077 ScRangeList aRanges = getChartRanges(*pDoc, *pOleObj);
2078 CPPUNIT_ASSERT_MESSAGE("Label range (B3:B5) not found.",
2079 aRanges.Contains(ScRange(1, 2, 1, 1, 4, 1)));
2080 CPPUNIT_ASSERT_MESSAGE("Data label (C2) not found.", aRanges.Contains(ScAddress(2, 1, 1)));
2081 CPPUNIT_ASSERT_MESSAGE("Data range (C3:C5) not found.",
2082 aRanges.Contains(ScRange(2, 2, 1, 2, 4, 1)));
2085 CPPUNIT_TEST_FIXTURE(ScExportTest, testCellAnchoredGroupXLS)
2087 createScDoc("xls/cell-anchored-group.xls");
2089 saveAndReload("calc8");
2091 // the document contains a group anchored on the first cell, make sure it's there in the right place
2092 ScDocument* pDoc = getScDoc();
2093 CPPUNIT_ASSERT_MESSAGE("There should be at least one sheet.", pDoc->GetTableCount() > 0);
2094 ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
2095 SdrPage* pPage = pDrawLayer->GetPage(0);
2096 CPPUNIT_ASSERT_MESSAGE("draw page for sheet 1 should exist.", pPage);
2097 const size_t nCount = pPage->GetObjCount();
2098 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be 1 objects.", static_cast<size_t>(1), nCount);
2100 SdrObject* pObj = pPage->GetObj(0);
2101 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj);
2102 ScDrawObjData* pData = ScDrawLayer::GetObjData(pObj);
2103 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData);
2104 CPPUNIT_ASSERT_MESSAGE("Upper left of bounding rectangle should be nonnegative.",
2105 pData->getShapeRect().Left() >= 0 || pData->getShapeRect().Top() >= 0);
2108 CPPUNIT_TEST_FIXTURE(ScExportTest, testFormulaReferenceXLS)
2110 createScDoc("xls/formula-reference.xls");
2112 saveAndReload("MS Excel 97");
2114 ScDocument* pDoc = getScDoc();
2116 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D2", OUString("=$A$2+$B$2+$C$2"),
2117 pDoc->GetFormula(3, 1, 0));
2118 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D3", OUString("=A3+B3+C3"),
2119 pDoc->GetFormula(3, 2, 0));
2120 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D6", OUString("=SUM($A$6:$C$6)"),
2121 pDoc->GetFormula(3, 5, 0));
2122 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D7", OUString("=SUM(A7:C7)"),
2123 pDoc->GetFormula(3, 6, 0));
2124 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D10", OUString("=$Two.$A$2+$Two.$B$2+$Two.$C$2"),
2125 pDoc->GetFormula(3, 9, 0));
2126 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D11", OUString("=$Two.A3+$Two.B3+$Two.C3"),
2127 pDoc->GetFormula(3, 10, 0));
2128 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D14", OUString("=MIN($Two.$A$2:$C$2)"),
2129 pDoc->GetFormula(3, 13, 0));
2130 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D15", OUString("=MAX($Two.A3:C3)"),
2131 pDoc->GetFormula(3, 14, 0));
2134 CPPUNIT_TEST_FIXTURE(ScExportTest, testSheetProtectionXLSX)
2136 createScDoc("xlsx/ProtecteSheet1234Pass.xlsx");
2138 saveAndReload("Calc Office Open XML");
2140 ScDocument* pDoc = getScDoc();
2141 const ScTableProtection* pTabProtect = pDoc->GetTabProtection(0);
2142 CPPUNIT_ASSERT(pTabProtect);
2143 Sequence<sal_Int8> aHash = pTabProtect->getPasswordHash(PASSHASH_XL);
2144 // check has
2145 if (aHash.getLength() >= 2)
2147 CPPUNIT_ASSERT_EQUAL(sal_uInt8(204), static_cast<sal_uInt8>(aHash[0]));
2148 CPPUNIT_ASSERT_EQUAL(sal_uInt8(61), static_cast<sal_uInt8>(aHash[1]));
2150 // we could flesh out this check I guess
2151 CPPUNIT_ASSERT(!pTabProtect->isOptionEnabled(ScTableProtection::OBJECTS));
2152 CPPUNIT_ASSERT(!pTabProtect->isOptionEnabled(ScTableProtection::SCENARIOS));
2155 CPPUNIT_TEST_FIXTURE(ScExportTest, testSheetProtectionXLSB)
2157 createScDoc("xlsb/tdf108017_calcProtection.xlsb");
2159 saveAndReload("Calc Office Open XML");
2161 ScDocument* pDoc = getScDoc();
2162 const ScTableProtection* pTabProtect = pDoc->GetTabProtection(0);
2163 CPPUNIT_ASSERT(pTabProtect);
2164 CPPUNIT_ASSERT(pTabProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS));
2165 CPPUNIT_ASSERT(!pTabProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS));
2168 CPPUNIT_TEST_FIXTURE(ScExportTest, testConditionalFormatNumberInTextRule)
2170 createScDoc();
2172 ScDocument* pDocument = getScDoc();
2173 ScAddress aAddress(0, 0, 0);
2175 auto pFormat = std::make_unique<ScConditionalFormat>(0, pDocument);
2176 ScRange aCondFormatRange(aAddress);
2177 ScRangeList aRangeList(aCondFormatRange);
2178 pFormat->SetRange(aRangeList);
2179 ScCondFormatEntry* pEntry
2180 = new ScCondFormatEntry(ScConditionMode::BeginsWith, "15", "", *pDocument, aAddress, "");
2181 pFormat->AddEntry(pEntry);
2182 pDocument->AddCondFormat(std::move(pFormat), 0);
2184 saveAndReload("Calc Office Open XML");
2185 pDocument = getScDoc();
2187 ScConditionalFormat* pCondFormat = pDocument->GetCondFormat(0, 0, 0);
2188 CPPUNIT_ASSERT(pCondFormat);
2189 CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormat->size());
2190 const ScFormatEntry* pCondFormatEntry = pCondFormat->GetEntry(0);
2191 CPPUNIT_ASSERT(pCondFormatEntry);
2192 CPPUNIT_ASSERT_EQUAL(ScFormatEntry::Type::Condition, pCondFormatEntry->GetType());
2193 const ScConditionEntry* pConditionEntry
2194 = static_cast<const ScConditionEntry*>(pCondFormatEntry);
2195 CPPUNIT_ASSERT_EQUAL(ScConditionMode::BeginsWith, pConditionEntry->GetOperation());
2196 CPPUNIT_ASSERT_EQUAL(OUString("\"15\""), pConditionEntry->GetExpression(aAddress, 0));
2199 namespace
2201 const char* toBorderName(SvxBorderLineStyle eStyle)
2203 switch (eStyle)
2205 case SvxBorderLineStyle::SOLID:
2206 return "SOLID";
2207 case SvxBorderLineStyle::DOTTED:
2208 return "DOTTED";
2209 case SvxBorderLineStyle::DASHED:
2210 return "DASHED";
2211 case SvxBorderLineStyle::DASH_DOT:
2212 return "DASH_DOT";
2213 case SvxBorderLineStyle::DASH_DOT_DOT:
2214 return "DASH_DOT_DOT";
2215 case SvxBorderLineStyle::DOUBLE_THIN:
2216 return "DOUBLE_THIN";
2217 case SvxBorderLineStyle::FINE_DASHED:
2218 return "FINE_DASHED";
2219 default:;
2222 return "";
2226 void ScExportTest::testExcelCellBorders(const OUString& sFormatType)
2228 static const struct
2230 SCROW mnRow;
2231 SvxBorderLineStyle mnStyle;
2232 tools::Long mnWidth;
2233 } aChecks[] = {
2234 { 1, SvxBorderLineStyle::SOLID, 1 }, // hair
2235 { 3, SvxBorderLineStyle::DOTTED, 15 }, // dotted
2236 { 5, SvxBorderLineStyle::DASH_DOT_DOT, 15 }, // dash dot dot
2237 { 7, SvxBorderLineStyle::DASH_DOT, 15 }, // dash dot
2238 { 9, SvxBorderLineStyle::FINE_DASHED, 15 }, // dashed
2239 { 11, SvxBorderLineStyle::SOLID, 15 }, // thin
2240 { 13, SvxBorderLineStyle::DASH_DOT_DOT, 35 }, // medium dash dot dot
2241 { 17, SvxBorderLineStyle::DASH_DOT, 35 }, // medium dash dot
2242 { 19, SvxBorderLineStyle::DASHED, 35 }, // medium dashed
2243 { 21, SvxBorderLineStyle::SOLID, 35 }, // medium
2244 { 23, SvxBorderLineStyle::SOLID, 50 }, // thick
2245 { 25, SvxBorderLineStyle::DOUBLE_THIN, -1 }, // double (don't check width)
2249 ScDocument* pDoc = getScDoc();
2251 for (auto const[nRow, eStyle, nWidth] : aChecks)
2253 const editeng::SvxBorderLine* pLine = nullptr;
2254 pDoc->GetBorderLines(2, nRow, 0, nullptr, &pLine, nullptr, nullptr);
2255 CPPUNIT_ASSERT(pLine);
2256 CPPUNIT_ASSERT_EQUAL(toBorderName(eStyle), toBorderName(pLine->GetBorderLineStyle()));
2257 if (nWidth >= 0)
2258 CPPUNIT_ASSERT_EQUAL(nWidth, pLine->GetWidth());
2262 saveAndReload(sFormatType);
2263 ScDocument* pDoc = getScDoc();
2264 for (auto const[nRow, eStyle, nWidth] : aChecks)
2266 const editeng::SvxBorderLine* pLine = nullptr;
2267 pDoc->GetBorderLines(2, nRow, 0, nullptr, &pLine, nullptr, nullptr);
2268 CPPUNIT_ASSERT(pLine);
2269 CPPUNIT_ASSERT_EQUAL(toBorderName(eStyle), toBorderName(pLine->GetBorderLineStyle()));
2270 if (nWidth >= 0)
2271 CPPUNIT_ASSERT_EQUAL(nWidth, pLine->GetWidth());
2275 CPPUNIT_TEST_FIXTURE(ScExportTest, testCellBordersXLS)
2277 createScDoc("xls/cell-borders.xls");
2278 testExcelCellBorders("MS Excel 97");
2281 CPPUNIT_TEST_FIXTURE(ScExportTest, testCellBordersXLSX)
2283 createScDoc("xlsx/cell-borders.xlsx");
2284 testExcelCellBorders("Calc Office Open XML");
2287 CPPUNIT_TEST_FIXTURE(ScExportTest, testTdf155368)
2289 createScDoc("ods/tdf155368.ods");
2291 dispatchCommand(mxComponent, ".uno:SelectAll", {});
2293 dispatchCommand(mxComponent, ".uno:WrapText", {});
2295 save("Calc Office Open XML");
2297 xmlDocUniquePtr pStyles = parseExport("xl/styles.xml");
2298 CPPUNIT_ASSERT(pStyles);
2300 assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[1]/x:alignment"_ostr, "wrapText"_ostr,
2301 "false");
2303 // Without the fix in place, this test would have failed with
2304 // - Expected: false
2305 // - Actual : true
2306 assertXPath(pStyles, "/x:styleSheet/x:cellXfs/x:xf[2]/x:alignment"_ostr, "wrapText"_ostr,
2307 "false");
2310 CPPUNIT_PLUGIN_IMPLEMENT();
2312 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */