Files
odfstudio/sc/qa/unit/subsequent_export_test3.cxx
T
Andrea Gelmini f1c58464ac Fix typos
Change-Id: I38b80f7bbf93192b7e2e00a426b72b77eb33bf1c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/210568
Tested-by: Julien Nabet <serval2412@yahoo.fr>
Reviewed-by: Julien Nabet <serval2412@yahoo.fr>
2026-09-10 21:28:54 +02:00

2192 lines
84 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <iterator>
#include "helper/qahelper.hxx"
#include <formulacell.hxx>
#include <userdat.hxx>
#include <tokenstringcontext.hxx>
#include <chgtrack.hxx>
#include <scmod.hxx>
#include <formula/errorcodes.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdograf.hxx>
#include <svx/svdomeas.hxx>
#include <svl/zformat.hxx>
#include <svl/numformat.hxx>
#include <tabprotection.hxx>
#include <editeng/borderline.hxx>
#include <unotools/tempfile.hxx>
#include <unotools/useroptions.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/linkmgr.hxx>
#include <tools/datetime.hxx>
#include <tools/UnitConversion.hxx>
#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
#include <com/sun/star/awt/XBitmap.hpp>
#include <com/sun/star/graphic/GraphicType.hpp>
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
class ScExportTest3 : public ScModelTestBase
{
public:
ScExportTest3()
: ScModelTestBase(u"sc/qa/unit/data"_ustr)
{
}
protected:
void testCeilingFloor(TestFilter eFormatType);
void testFunctionsExcel2010(TestFilter eFormatType);
void testSwappedOutImageExport(TestFilter eFormatType);
void testLinkedGraphicRT(TestFilter eFormatType);
void testImageWithSpecialID(TestFilter eFormatType);
};
CPPUNIT_TEST_FIXTURE(ScExportTest3, testBordersExchangeXLSX)
{
// Document: sc/qa/unit/data/README.cellborders
// short name for the table
const SvxBorderLineStyle None = SvxBorderLineStyle::NONE;
const SvxBorderLineStyle Solid = SvxBorderLineStyle::SOLID;
const SvxBorderLineStyle Dotted = SvxBorderLineStyle::DOTTED;
const SvxBorderLineStyle Dashed = SvxBorderLineStyle::DASHED;
const SvxBorderLineStyle FineDash = SvxBorderLineStyle::FINE_DASHED;
const SvxBorderLineStyle DashDot = SvxBorderLineStyle::DASH_DOT;
const SvxBorderLineStyle DashDoDo = SvxBorderLineStyle::DASH_DOT_DOT;
const SvxBorderLineStyle DoubThin = SvxBorderLineStyle::DOUBLE_THIN;
const size_t nMaxCol = 18;
const size_t nMaxRow = 7;
static struct
{
SvxBorderLineStyle BorderStyleTop, BorderStyleBottom;
tools::Long WidthTop, WidthBottom;
} aCheckBorderWidth[nMaxCol][nMaxRow]
= { /* Width */
/* 0,05 */ { { Solid, Solid, 1, 1 }, // SOLID
{ Dotted, Dotted, 15, 15 }, // DOTTED
{ Dotted, Dotted, 15, 15 }, // DASHED
{ FineDash, FineDash, 15, 15 }, // FINE_DASHED
{ FineDash, FineDash, 15, 15 }, // DASH_DOT
{ FineDash, FineDash, 15, 15 }, // DASH_DOT_DOT
{ None, None, 0, 0 } }, // DOUBLE_THIN
/* 0,25 */
{ { Solid, Solid, 1, 1 },
{ Dotted, Dotted, 15, 15 },
{ Dotted, Dotted, 15, 15 },
{ FineDash, FineDash, 15, 15 },
{ FineDash, FineDash, 15, 15 },
{ FineDash, FineDash, 15, 15 },
{ None, None, 0, 0 } },
/* 0,50 */
{ { Solid, Solid, 1, 1 },
{ Dotted, Dotted, 15, 15 },
{ Dotted, Dotted, 15, 15 },
{ FineDash, FineDash, 15, 15 },
{ FineDash, FineDash, 15, 15 },
{ FineDash, FineDash, 15, 15 },
{ None, None, 0, 0 } },
/* 0,75 */
{ { Solid, Solid, 15, 15 },
{ Dotted, Dotted, 15, 15 },
{ FineDash, FineDash, 15, 15 },
{ FineDash, FineDash, 15, 15 },
{ DashDot, DashDot, 15, 15 },
{ DashDoDo, DashDoDo, 15, 15 },
{ DoubThin, DoubThin, 35, 35 } },
/* 1,00 */
{ { Solid, Solid, 15, 15 },
{ Dotted, Dotted, 15, 15 },
{ FineDash, FineDash, 15, 15 },
{ FineDash, FineDash, 15, 15 },
{ DashDot, DashDot, 15, 15 },
{ DashDoDo, DashDoDo, 15, 15 },
{ DoubThin, DoubThin, 35, 35 } },
/* 1,25 */
{ { Solid, Solid, 15, 15 },
{ Dotted, Dotted, 15, 15 },
{ FineDash, FineDash, 15, 15 },
{ FineDash, FineDash, 15, 15 },
{ DashDot, DashDot, 15, 15 },
{ DashDoDo, DashDoDo, 15, 15 },
{ DoubThin, DoubThin, 35, 35 } },
/* 1,50 */
{ { Solid, Solid, 15, 15 },
{ Dotted, Dotted, 15, 15 },
{ FineDash, FineDash, 15, 15 },
{ FineDash, FineDash, 15, 15 },
{ DashDot, DashDot, 15, 15 },
{ DashDoDo, DashDoDo, 15, 15 },
{ DoubThin, DoubThin, 35, 35 } },
/* 1,75 */
{ { Solid, Solid, 35, 35 },
{ FineDash, FineDash, 35, 35 },
{ Dashed, Dashed, 35, 35 },
{ FineDash, FineDash, 35, 35 },
{ DashDot, DashDot, 35, 35 },
{ DashDoDo, DashDoDo, 35, 35 },
{ DoubThin, DoubThin, 35, 35 } },
/* 2,00 */
{ { Solid, Solid, 35, 35 },
{ FineDash, FineDash, 35, 35 },
{ Dashed, Dashed, 35, 35 },
{ FineDash, FineDash, 35, 35 },
{ DashDot, DashDot, 35, 35 },
{ DashDoDo, DashDoDo, 35, 35 },
{ DoubThin, DoubThin, 35, 35 } },
/* 2,25 */
{ { Solid, Solid, 35, 35 },
{ FineDash, FineDash, 35, 35 },
{ Dashed, Dashed, 35, 35 },
{ FineDash, FineDash, 35, 35 },
{ DashDot, DashDot, 35, 35 },
{ DashDoDo, DashDoDo, 35, 35 },
{ DoubThin, DoubThin, 35, 35 } },
/* 2,50 */
{ { Solid, Solid, 50, 50 },
{ FineDash, FineDash, 35, 35 },
{ Dashed, Dashed, 35, 35 },
{ FineDash, FineDash, 35, 35 },
{ DashDot, DashDot, 35, 35 },
{ DashDoDo, DashDoDo, 35, 35 },
{ DoubThin, DoubThin, 35, 35 } },
/* 2,75 */
{ { Solid, Solid, 50, 50 },
{ FineDash, FineDash, 35, 35 },
{ Dashed, Dashed, 35, 35 },
{ FineDash, FineDash, 35, 35 },
{ DashDot, DashDot, 35, 35 },
{ DashDoDo, DashDoDo, 35, 35 },
{ DoubThin, DoubThin, 35, 35 } },
/* 3,00 */
{ { Solid, Solid, 50, 50 },
{ FineDash, FineDash, 35, 35 },
{ Dashed, Dashed, 35, 35 },
{ FineDash, FineDash, 35, 35 },
{ DashDot, DashDot, 35, 35 },
{ DashDoDo, DashDoDo, 35, 35 },
{ DoubThin, DoubThin, 35, 35 } },
/* 3,50 */
{ { Solid, Solid, 50, 50 },
{ FineDash, FineDash, 35, 35 },
{ Dashed, Dashed, 35, 35 },
{ FineDash, FineDash, 35, 35 },
{ DashDot, DashDot, 35, 35 },
{ DashDoDo, DashDoDo, 35, 35 },
{ DoubThin, DoubThin, 35, 35 } },
/* 4,00 */
{ { Solid, Solid, 50, 50 },
{ FineDash, FineDash, 35, 35 },
{ Dashed, Dashed, 35, 35 },
{ FineDash, FineDash, 35, 35 },
{ DashDot, DashDot, 35, 35 },
{ DashDoDo, DashDoDo, 35, 35 },
{ DoubThin, DoubThin, 35, 35 } },
/* 5,00 */
{ { Solid, Solid, 50, 50 },
{ FineDash, FineDash, 35, 35 },
{ Dashed, Dashed, 35, 35 },
{ FineDash, FineDash, 35, 35 },
{ DashDot, DashDot, 35, 35 },
{ DashDoDo, DashDoDo, 35, 35 },
{ DoubThin, DoubThin, 35, 35 } },
/* 7,00 */
{ { Solid, Solid, 50, 50 },
{ FineDash, FineDash, 35, 35 },
{ Dashed, Dashed, 35, 35 },
{ FineDash, FineDash, 35, 35 },
{ DashDot, DashDot, 35, 35 },
{ DashDoDo, DashDoDo, 35, 35 },
{ DoubThin, DoubThin, 35, 35 } },
/* 9,00 */
{ { Solid, Solid, 50, 50 },
{ FineDash, FineDash, 35, 35 },
{ Dashed, Dashed, 35, 35 },
{ FineDash, FineDash, 35, 35 },
{ DashDot, DashDot, 35, 35 },
{ DashDoDo, DashDoDo, 35, 35 },
{ DoubThin, DoubThin, 35, 35 } }
};
createScDoc("ods/test_borders_export.ods");
saveAndReload(TestFilter::XLSX);
ScDocument* pDoc = getScDoc();
for (size_t nCol = 0; nCol < nMaxCol; ++nCol)
{
for (size_t nRow = 0; nRow < nMaxRow; ++nRow)
{
const editeng::SvxBorderLine* pLineTop = nullptr;
const editeng::SvxBorderLine* pLineBottom = nullptr;
pDoc->GetBorderLines(nCol + 2, (nRow * 2) + 8, 0, nullptr, &pLineTop, nullptr,
&pLineBottom);
if ((nCol < 3) && (nRow == 6))
{ // in this range there are no lines since minimum size to create a double is 0.5
CPPUNIT_ASSERT(!pLineTop);
CPPUNIT_ASSERT(!pLineBottom);
continue;
}
else
{
CPPUNIT_ASSERT(pLineTop);
CPPUNIT_ASSERT(pLineBottom);
}
CPPUNIT_ASSERT_EQUAL_MESSAGE("Top Border-Line-Style wrong",
aCheckBorderWidth[nCol][nRow].BorderStyleTop,
pLineTop->GetBorderLineStyle());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Bottom Border-Line-Style wrong",
aCheckBorderWidth[nCol][nRow].BorderStyleBottom,
pLineBottom->GetBorderLineStyle());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Top Width-Line wrong",
aCheckBorderWidth[nCol][nRow].WidthTop,
pLineTop->GetWidth());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Bottom Width-Line wrong",
aCheckBorderWidth[nCol][nRow].WidthBottom,
pLineBottom->GetWidth());
}
}
}
static OUString toString(const ScBigRange& rRange)
{
return "(columns:" + OUString::number(rRange.aStart.Col()) + "-"
+ OUString::number(rRange.aEnd.Col()) + ";rows:" + OUString::number(rRange.aStart.Row())
+ "-" + OUString::number(rRange.aEnd.Row())
+ ";sheets:" + OUString::number(rRange.aStart.Tab()) + "-"
+ OUString::number(rRange.aEnd.Tab()) + ")";
}
namespace
{
struct CheckItem
{
sal_uLong mnActionId;
ScChangeActionType meType;
sal_Int32 mnStartCol;
sal_Int32 mnStartRow;
sal_Int32 mnStartTab;
sal_Int32 mnEndCol;
sal_Int32 mnEndRow;
sal_Int32 mnEndTab;
bool mbRowInsertedAtBottom;
};
bool checkRange(ScChangeActionType eType, const ScBigRange& rExpected, const ScBigRange& rActual)
{
ScBigRange aExpected(rExpected), aActual(rActual);
switch (eType)
{
case SC_CAT_INSERT_ROWS:
{
// Ignore columns.
aExpected.aStart.SetCol(0);
aExpected.aEnd.SetCol(0);
aActual.aStart.SetCol(0);
aActual.aEnd.SetCol(0);
}
break;
default:;
}
return aExpected == aActual;
}
bool check(const ScDocument& rDoc)
{
static const CheckItem aChecks[] = {
{ 1, SC_CAT_CONTENT, 1, 1, 0, 1, 1, 0, false },
{ 2, SC_CAT_INSERT_ROWS, 0, 2, 0, 0, 2, 0, true },
{ 3, SC_CAT_CONTENT, 1, 2, 0, 1, 2, 0, false },
{ 4, SC_CAT_INSERT_ROWS, 0, 3, 0, 0, 3, 0, true },
{ 5, SC_CAT_CONTENT, 1, 3, 0, 1, 3, 0, false },
{ 6, SC_CAT_INSERT_ROWS, 0, 4, 0, 0, 4, 0, true },
{ 7, SC_CAT_CONTENT, 1, 4, 0, 1, 4, 0, false },
{ 8, SC_CAT_INSERT_ROWS, 0, 5, 0, 0, 5, 0, true },
{ 9, SC_CAT_CONTENT, 1, 5, 0, 1, 5, 0, false },
{ 10, SC_CAT_INSERT_ROWS, 0, 6, 0, 0, 6, 0, true },
{ 11, SC_CAT_CONTENT, 1, 6, 0, 1, 6, 0, false },
{ 12, SC_CAT_INSERT_ROWS, 0, 7, 0, 0, 7, 0, true },
{ 13, SC_CAT_CONTENT, 1, 7, 0, 1, 7, 0, false },
};
ScChangeTrack* pCT = rDoc.GetChangeTrack();
if (!pCT)
{
std::cerr << "Change track instance doesn't exist." << std::endl;
return false;
}
sal_uLong nActionMax = pCT->GetActionMax();
if (nActionMax != 13)
{
std::cerr << "Unexpected highest action ID value." << std::endl;
return false;
}
for (const auto& rCheck : aChecks)
{
sal_uInt16 nActId = rCheck.mnActionId;
const ScChangeAction* pAction = pCT->GetAction(nActId);
if (!pAction)
{
std::cerr << "No action for action number " << nActId << " found." << std::endl;
return false;
}
if (pAction->GetType() != rCheck.meType)
{
std::cerr << "Unexpected action type for action number " << nActId << "." << std::endl;
return false;
}
const ScBigRange& rRange = pAction->GetBigRange();
ScBigRange aCheck(rCheck.mnStartCol, rCheck.mnStartRow, rCheck.mnStartTab, rCheck.mnEndCol,
rCheck.mnEndRow, rCheck.mnEndTab);
if (!checkRange(pAction->GetType(), aCheck, rRange))
{
std::cerr << "Unexpected range for action number " << nActId
<< ": expected=" << toString(aCheck) << " actual=" << toString(rRange)
<< std::endl;
return false;
}
switch (pAction->GetType())
{
case SC_CAT_INSERT_ROWS:
{
const ScChangeActionIns* p = static_cast<const ScChangeActionIns*>(pAction);
if (p->IsEndOfList() != rCheck.mbRowInsertedAtBottom)
{
std::cerr << "Unexpected end-of-list flag for action number " << nActId << "."
<< std::endl;
return false;
}
}
break;
default:;
}
}
return true;
}
bool checkRevisionUserAndTime(ScDocument& rDoc, std::u16string_view rOwnerName)
{
ScChangeTrack* pCT = rDoc.GetChangeTrack();
if (!pCT)
{
std::cerr << "Change track instance doesn't exist." << std::endl;
return false;
}
ScChangeAction* pAction = pCT->GetLast();
if (pAction->GetUser() != "Kohei Yoshida")
{
std::cerr << "Wrong user name." << std::endl;
return false;
}
DateTime aDT = pAction->GetDateTime();
if (aDT.GetYear() != 2014 || aDT.GetMonth() != 7 || aDT.GetDay() != 11)
{
std::cerr << "Wrong time stamp." << std::endl;
return false;
}
// Insert a new record to make sure the user and date-time are correct.
rDoc.SetString(ScAddress(1, 8, 0), u"New String"_ustr);
ScCellValue aEmpty;
pCT->AppendContent(ScAddress(1, 8, 0), aEmpty);
pAction = pCT->GetLast();
if (!pAction)
{
std::cerr << "Failed to retrieve last revision." << std::endl;
return false;
}
if (rOwnerName != pAction->GetUser())
{
std::cerr << "Wrong user name." << std::endl;
return false;
}
DateTime aDTNew = pAction->GetDateTime();
if (aDTNew <= aDT)
{
std::cerr << "Time stamp of the new revision should be more recent than that of the "
"last revision."
<< std::endl;
return false;
}
return true;
}
} //namespace
CPPUNIT_TEST_FIXTURE(ScExportTest3, testTrackChangesSimpleXLS)
{
SvtUserOptions& rUserOpt = ScModule::get()->GetUserOptions();
rUserOpt.SetToken(UserOptToken::FirstName, u"Export"_ustr);
rUserOpt.SetToken(UserOptToken::LastName, u"Test"_ustr);
OUString aOwnerName = rUserOpt.GetFirstName() + " " + rUserOpt.GetLastName();
// First, test the xls variant.
createScDoc("xls/track-changes/simple-cell-changes.xls");
ScDocument* pDoc = getScDoc();
bool bGood = check(*pDoc);
CPPUNIT_ASSERT_MESSAGE("Initial check failed (xls).", bGood);
saveAndReload(TestFilter::XLS);
pDoc = getScDoc();
bGood = check(*pDoc);
CPPUNIT_ASSERT_MESSAGE("Check after reload failed (xls).", bGood);
// fdo#81445 : Check the blank value string to make sure it's "<empty>".
ScChangeTrack* pCT = pDoc->GetChangeTrack();
CPPUNIT_ASSERT(pCT);
ScChangeAction* pAction = pCT->GetAction(1);
CPPUNIT_ASSERT(pAction);
OUString aDesc = pAction->GetDescription(*pDoc);
CPPUNIT_ASSERT_EQUAL(u"Cell B2 changed from '<empty>' to '1'"_ustr, aDesc);
pDoc = getScDoc();
bGood = checkRevisionUserAndTime(*pDoc, aOwnerName);
CPPUNIT_ASSERT_MESSAGE("Check revision and time failed after reload (xls).", bGood);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testTrackChangesSimpleXLSX)
{
SvtUserOptions& rUserOpt = ScModule::get()->GetUserOptions();
rUserOpt.SetToken(UserOptToken::FirstName, u"Export"_ustr);
rUserOpt.SetToken(UserOptToken::LastName, u"Test"_ustr);
OUString aOwnerName = rUserOpt.GetFirstName() + " " + rUserOpt.GetLastName();
createScDoc("xlsx/track-changes/simple-cell-changes.xlsx");
ScDocument* pDoc = getScDoc();
bool bGood = check(*pDoc);
CPPUNIT_ASSERT_MESSAGE("Initial check failed (xlsx).", bGood);
saveAndReload(TestFilter::XLSX);
pDoc = getScDoc();
bGood = check(*pDoc);
CPPUNIT_ASSERT_MESSAGE("Check after reload failed (xlsx).", bGood);
bGood = checkRevisionUserAndTime(*pDoc, aOwnerName);
CPPUNIT_ASSERT_MESSAGE("Check revision and time failed after reload (xlsx).", bGood);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testSheetTabColorsXLSX)
{
struct
{
bool checkContent(const ScDocument& rDoc)
{
std::vector<OUString> aTabNames = rDoc.GetAllTableNames();
// green, red, blue, yellow (from left to right).
if (aTabNames.size() != 4)
{
std::cerr << "There should be exactly 4 sheets." << std::endl;
return false;
}
const char* pNames[] = { "Green", "Red", "Blue", "Yellow" };
for (size_t i = 0; i < std::size(pNames); ++i)
{
OUString aExpected = OUString::createFromAscii(pNames[i]);
if (aExpected != aTabNames[i])
{
std::cerr << "incorrect sheet name: expected='" << aExpected << "', actual='"
<< aTabNames[i] << "'" << std::endl;
return false;
}
}
static const Color aXclColors[] = {
0x0000B050, // green
0x00FF0000, // red
0x000070C0, // blue
0x00FFFF00, // yellow
};
for (size_t i = 0; i < std::size(aXclColors); ++i)
{
if (aXclColors[i] != rDoc.GetTabBgColor(i))
{
std::cerr << "wrong sheet color for sheet " << i << std::endl;
return false;
}
}
return true;
}
} aTest;
createScDoc("xlsx/sheet-tab-color.xlsx");
{
ScDocument* pDoc = getScDoc();
bool bRes = aTest.checkContent(*pDoc);
CPPUNIT_ASSERT_MESSAGE("Failed on the initial content check.", bRes);
}
saveAndReload(TestFilter::XLSX);
ScDocument* pDoc = getScDoc();
bool bRes = aTest.checkContent(*pDoc);
CPPUNIT_ASSERT_MESSAGE("Failed on the content check after reload.", bRes);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testTdf133487)
{
createScDoc("fods/shapes_foreground_background.fods");
save(TestFilter::ODS);
xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
CPPUNIT_ASSERT(pXmlDoc);
// shape in background has lowest index
assertXPath(pXmlDoc,
"/office:document-content/office:body/office:spreadsheet/table:table[1]/"
"table:table-row[1]/table:table-cell[1]/draw:custom-shape",
"z-index", u"0");
assertXPath(pXmlDoc,
"/office:document-content/office:body/office:spreadsheet/table:table[1]/"
"table:table-row[1]/table:table-cell[1]/draw:custom-shape"
"/attribute::table:table-background",
1);
assertXPath(pXmlDoc,
"/office:document-content/office:body/office:spreadsheet/table:table[1]/"
"table:table-row[1]/table:table-cell[1]/draw:custom-shape",
"table-background", u"true");
// shape in foreground, previously index 1
assertXPath(pXmlDoc,
"/office:document-content/office:body/office:spreadsheet/table:table[1]/"
"table:table-row[1]/table:table-cell[2]/draw:custom-shape",
"z-index", u"2");
// attribute is only written for value "true"
assertXPath(pXmlDoc,
"/office:document-content/office:body/office:spreadsheet/table:table[1]/"
"table:table-row[1]/table:table-cell[2]/draw:custom-shape"
"/attribute::table:table-background",
0);
// shape in foreground, previously index 0
assertXPath(pXmlDoc,
"/office:document-content/office:body/office:spreadsheet/table:table[1]/"
"table:table-row[3]/table:table-cell[1]/draw:custom-shape",
"z-index", u"1");
// attribute is only written for value "true"
assertXPath(pXmlDoc,
"/office:document-content/office:body/office:spreadsheet/table:table[1]/"
"table:table-row[3]/table:table-cell[1]/draw:custom-shape"
"/attribute::table:table-background",
0);
// shape in foreground, previously index 4
assertXPath(pXmlDoc,
"/office:document-content/office:body/office:spreadsheet/table:table[1]/"
"table:shapes/draw:custom-shape",
"z-index", u"3");
// attribute is only written for value "true"
assertXPath(pXmlDoc,
"/office:document-content/office:body/office:spreadsheet/table:table[1]/"
"table:shapes/draw:custom-shape"
"/attribute::table:table-background",
0);
// form control, previously index 3
assertXPath(pXmlDoc,
"/office:document-content/office:body/office:spreadsheet/table:table[1]/"
"table:shapes/draw:control",
"z-index", u"4");
// attribute is only written for value "true"
assertXPath(pXmlDoc,
"/office:document-content/office:body/office:spreadsheet/table:table[1]/"
"table:shapes/draw:control"
"/attribute::table:table-background",
0);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testSharedFormulaExportXLS)
{
struct
{
bool checkContent(ScDocument& rDoc)
{
formula::FormulaGrammar::Grammar eGram = formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1;
FormulaGrammarSwitch aFGSwitch(&rDoc, eGram);
sc::TokenStringContext aCxt(rDoc, eGram);
// Check the title row.
OUString aActual = rDoc.GetString(0, 1, 0);
OUString aExpected = u"Response"_ustr;
if (aActual != aExpected)
{
std::cerr << "Wrong content in A2: expected='" << aExpected << "', actual='"
<< aActual << "'" << std::endl;
return false;
}
aActual = rDoc.GetString(1, 1, 0);
aExpected = "Response";
if (aActual != aExpected)
{
std::cerr << "Wrong content in B2: expected='" << aExpected << "', actual='"
<< aActual << "'" << std::endl;
return false;
}
// A3:A12 and B3:B12 are numbers from 1 to 10.
for (SCROW i = 0; i <= 9; ++i)
{
double fExpected = i + 1.0;
ScAddress aPos(0, i + 2, 0);
double fActual = rDoc.GetValue(aPos);
if (fExpected != fActual)
{
std::cerr << "Wrong value in A" << (i + 2) << ": expected=" << fExpected
<< ", actual=" << fActual << std::endl;
return false;
}
aPos.IncCol();
ScFormulaCell* pFC = rDoc.GetFormulaCell(aPos);
if (!pFC)
{
std::cerr << "B" << (i + 2) << " should be a formula cell." << std::endl;
return false;
}
OUString aFormula = pFC->GetCode()->CreateString(aCxt, aPos);
aExpected = "Coefficients!RC[-1]";
if (aFormula != aExpected)
{
std::cerr << "Wrong formula in B" << (i + 2) << ": expected='" << aExpected
<< "', actual='" << aFormula << "'" << std::endl;
return false;
}
fActual = rDoc.GetValue(aPos);
if (fExpected != fActual)
{
std::cerr << "Wrong value in B" << (i + 2) << ": expected=" << fExpected
<< ", actual=" << fActual << std::endl;
return false;
}
}
return true;
}
} aTest;
createScDoc("ods/shared-formula/3d-reference.ods");
{
// Check the content of the original.
ScDocument* pDoc = getScDoc();
bool bRes = aTest.checkContent(*pDoc);
CPPUNIT_ASSERT_MESSAGE("Content check on the original document failed.", bRes);
}
saveAndReload(TestFilter::XLS);
// Check the content of the reloaded. This should be identical.
ScDocument* pDoc = getScDoc();
bool bRes = aTest.checkContent(*pDoc);
CPPUNIT_ASSERT_MESSAGE("Content check on the reloaded document failed.", bRes);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testSharedFormulaExportXLSX)
{
struct
{
bool checkContent(const ScDocument& rDoc)
{
SCTAB nTabCount = rDoc.GetTableCount();
if (nTabCount != 2)
{
std::cerr << "Document should have exactly 2 sheets. " << nTabCount << " found."
<< std::endl;
return false;
}
// Make sure the sheet tab colors are not set.
for (SCROW i = 0; i <= 1; ++i)
{
Color aTabBgColor = rDoc.GetTabBgColor(i);
if (aTabBgColor != COL_AUTO)
{
std::cerr << "The tab color of Sheet " << (i + 1)
<< " should not be explicitly set." << std::endl;
return false;
}
}
// B2:B7 should show 1,2,3,4,5,6.
double fExpected = 1.0;
for (SCROW i = 1; i <= 6; ++i, ++fExpected)
{
ScAddress aPos(1, i, 0);
double fVal = rDoc.GetValue(aPos);
if (fVal != fExpected)
{
std::cerr << "Wrong value in B" << (i + 1) << ": expected=" << fExpected
<< ", actual=" << fVal << std::endl;
return false;
}
}
// C2:C7 should show 10,20,...,60.
fExpected = 10.0;
for (SCROW i = 1; i <= 6; ++i, fExpected += 10.0)
{
ScAddress aPos(2, i, 0);
double fVal = rDoc.GetValue(aPos);
if (fVal != fExpected)
{
std::cerr << "Wrong value in C" << (i + 1) << ": expected=" << fExpected
<< ", actual=" << fVal << std::endl;
return false;
}
}
// D2:D7 should show 1,2,...,6.
fExpected = 1.0;
for (SCROW i = 1; i <= 6; ++i, ++fExpected)
{
ScAddress aPos(3, i, 0);
double fVal = rDoc.GetValue(aPos);
if (fVal != fExpected)
{
std::cerr << "Wrong value in D" << (i + 1) << ": expected=" << fExpected
<< ", actual=" << fVal << std::endl;
return false;
}
}
return true;
}
} aTest;
createScDoc("xlsx/shared-formula/3d-reference.xlsx");
{
ScDocument* pDoc = getScDoc();
bool bRes = aTest.checkContent(*pDoc);
CPPUNIT_ASSERT_MESSAGE("Content check on the initial document failed.", bRes);
pDoc->CalcAll(); // Recalculate to flush all cached results.
bRes = aTest.checkContent(*pDoc);
CPPUNIT_ASSERT_MESSAGE("Content check on the initial recalculated document failed.", bRes);
}
// Save and reload, and check the content again.
saveAndReload(TestFilter::XLSX);
ScDocument* pDoc = getScDoc();
pDoc->CalcAll(); // Recalculate to flush all cached results.
bool bRes = aTest.checkContent(*pDoc);
CPPUNIT_ASSERT_MESSAGE("Content check on the reloaded document failed.", bRes);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testSharedFormulaStringResultExportXLSX)
{
struct
{
bool checkContent(const ScDocument& rDoc)
{
{
// B2:B7 should show A,B,...,F.
const char* const expected[] = { "A", "B", "C", "D", "E", "F" };
for (SCROW i = 0; i <= 5; ++i)
{
ScAddress aPos(1, i + 1, 0);
OUString aStr = rDoc.GetString(aPos);
OUString aExpected = OUString::createFromAscii(expected[i]);
if (aStr != aExpected)
{
std::cerr << "Wrong value in B" << (i + 2) << ": expected='" << aExpected
<< "', actual='" << aStr << "'" << std::endl;
return false;
}
}
}
{
// C2:C7 should show AA,BB,...,FF.
const char* const expected[] = { "AA", "BB", "CC", "DD", "EE", "FF" };
for (SCROW i = 0; i <= 5; ++i)
{
ScAddress aPos(2, i + 1, 0);
OUString aStr = rDoc.GetString(aPos);
OUString aExpected = OUString::createFromAscii(expected[i]);
if (aStr != aExpected)
{
std::cerr << "Wrong value in C" << (i + 2) << ": expected='" << aExpected
<< "', actual='" << aStr << "'" << std::endl;
return false;
}
}
}
return true;
}
} aTest;
createScDoc("xlsx/shared-formula/text-results.xlsx");
{
ScDocument* pDoc = getScDoc();
// Check content without re-calculation, to test cached formula results.
bool bRes = aTest.checkContent(*pDoc);
CPPUNIT_ASSERT_MESSAGE("Content check on the initial document failed.", bRes);
// Now, re-calculate and check the results.
pDoc->CalcAll();
bRes = aTest.checkContent(*pDoc);
CPPUNIT_ASSERT_MESSAGE("Content check on the initial recalculated document failed.", bRes);
}
// Reload and check again.
saveAndReload(TestFilter::XLSX);
ScDocument* pDoc = getScDoc();
bool bRes = aTest.checkContent(*pDoc);
CPPUNIT_ASSERT_MESSAGE("Content check on the reloaded document failed.", bRes);
}
namespace
{
bool isFormulaWithoutError(ScDocument& rDoc, const ScAddress& rPos)
{
ScFormulaCell* pFC = rDoc.GetFormulaCell(rPos);
if (!pFC)
return false;
return pFC->GetErrCode() == FormulaError::NONE;
}
void testFunctionsExcel2010_Impl(ScDocument& rDoc)
{
// Original test case document is functions-excel-2010.xlsx
// Which test rows to evaluate, 1-based as in UI to ease maintenance.
static struct
{
SCROW nRow;
bool bEvaluate;
} const aTests[] = {
{ 2, false }, // name=[ AGGREGATE ], result=0, expected=1
{ 3, true }, { 4, true }, { 5, true }, { 6, true }, { 7, true }, { 8, true },
{ 9, true }, { 10, true }, { 11, true }, { 12, true }, { 13, true }, { 14, true },
{ 15, true }, { 16, true }, { 17, true }, { 18, true }, { 19, true }, { 20, true },
{ 21, true }, { 22, true }, { 23, true }, { 24, true }, { 25, true }, { 26, true },
{ 27, true }, { 28, true }, { 29, true }, { 30, true }, { 31, true }, { 32, true },
{ 33, true }, { 34, true }, { 35, true }, { 36, true }, { 37, true }, { 38, true },
{ 39, true }, { 40, true }, { 41, true }, { 42, true }, { 43, true }, { 44, true },
{ 45, false }, // name=[ NETWORKDAYS.INTL ], result=18, expected=19
{ 46, true }, { 47, true }, { 48, true }, { 49, true }, { 50, true }, { 51, true },
{ 52, true }, { 53, true }, { 54, true }, { 55, true }, { 56, true }, { 57, true },
{ 58, true }, { 59, true }, { 60, true }, { 61, true }, { 62, true }, { 63, true },
{ 64, true }, { 65, true }, { 66, true }, { 67, true }, { 68, true }, { 69, true },
{ 70, true }, { 71, true }, { 72, true }, { 73, true }, { 74, true }, { 75, true },
{ 76, true }, { 77, true }, { 78, true }, { 79, false }, // name=[ WORKDAY.INTL ], result=41755 , expected=41754
{ 80, true }
};
for (size_t i = 0; i < std::size(aTests); ++i)
{
if (aTests[i].bEvaluate)
{
// Column 0 is description, 1 is formula, 2 is Excel result, 3 is
// comparison.
SCROW nRow = aTests[i].nRow - 1; // 0-based
OString aStr
= OString::number(aTests[i].nRow) + ", function name=[ "
+ OUStringToOString(rDoc.GetString(ScAddress(0, nRow, 0)), RTL_TEXTENCODING_UTF8)
+ " ], result=" + OString::number(rDoc.GetValue(ScAddress(1, nRow, 0)))
+ ", expected=" + OString::number(rDoc.GetValue(ScAddress(2, nRow, 0)));
ScFormulaCell* pFC = rDoc.GetFormulaCell(ScAddress(1, nRow, 0));
if (pFC && pFC->GetErrCode() != FormulaError::NONE)
aStr += ", error code =" + OString::number(static_cast<int>(pFC->GetErrCode()));
CPPUNIT_ASSERT_MESSAGE(
OString("Expected a formula cell without error at row " + aStr).getStr(),
isFormulaWithoutError(rDoc, ScAddress(1, nRow, 0)));
CPPUNIT_ASSERT_MESSAGE(OString("Expected a TRUE value at row " + aStr).getStr(),
0 != rDoc.GetValue(ScAddress(3, nRow, 0)));
}
}
}
void testCeilingFloor_Impl(ScDocument& rDoc)
{
// Original test case document is ceiling-floor.xlsx
// Sheet1.K1 has =AND(K3:K81) to evaluate all results.
static constexpr OUString pORef = u"Sheet1.K1"_ustr;
ScAddress aPos;
aPos.Parse(pORef, rDoc);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", u"=AND(K3:K81)"_ustr,
rDoc.GetFormula(aPos.Col(), aPos.Row(), aPos.Tab()));
CPPUNIT_ASSERT_MESSAGE(OUString(pORef + " result is error.").toUtf8().getStr(),
isFormulaWithoutError(rDoc, aPos));
CPPUNIT_ASSERT_EQUAL(1.0, rDoc.GetValue(aPos));
}
}
void ScExportTest3::testFunctionsExcel2010(TestFilter eFormatType)
{
createScDoc("xlsx/functions-excel-2010.xlsx");
ScDocument* pDoc = getScDoc();
pDoc->CalcAll(); // perform hard re-calculation.
testFunctionsExcel2010_Impl(*pDoc);
saveAndReload(eFormatType);
pDoc = getScDoc();
pDoc->CalcAll(); // perform hard re-calculation.
testFunctionsExcel2010_Impl(*pDoc);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testFunctionsExcel2010XLSX)
{
testFunctionsExcel2010(TestFilter::XLSX);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testFunctionsExcel2010XLS)
{
testFunctionsExcel2010(TestFilter::XLS);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testFunctionsExcel2010ODS)
{
testFunctionsExcel2010(TestFilter::ODS);
}
void ScExportTest3::testCeilingFloor(TestFilter eFormatType)
{
createScDoc("xlsx/ceiling-floor.xlsx");
ScDocument* pDoc = getScDoc();
pDoc->CalcAll(); // perform hard re-calculation.
testCeilingFloor_Impl(*pDoc);
saveAndReload(eFormatType);
pDoc = getScDoc();
pDoc->CalcAll(); // perform hard re-calculation.
testCeilingFloor_Impl(*pDoc);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testCeilingFloorXLSX) { testCeilingFloor(TestFilter::XLSX); }
CPPUNIT_TEST_FIXTURE(ScExportTest3, testCeilingFloorXLS) { testCeilingFloor(TestFilter::XLS); }
CPPUNIT_TEST_FIXTURE(ScExportTest3, testCeilingFloorODS) { testCeilingFloor(TestFilter::ODS); }
CPPUNIT_TEST_FIXTURE(ScExportTest3, testCeilingFloorODSToXLSX)
{
// tdf#100011 - Cannot open sheet containing FLOOR/CEILING functions by MS Excel, after export to .xlsx
createScDoc("ods/ceiling-floor.ods");
save(TestFilter::XLSX);
xmlDocUniquePtr pSheet = parseExport(u"xl/workbook.xml"_ustr);
CPPUNIT_ASSERT(pSheet);
// there shouldn't be any defined names during export of FLOOR and CEILING functions to .xlsx
assertXPath(pSheet, "/x:workbook/x:definedNames", 0);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testCustomXml)
{
// Load document and export it to a temporary file
createScDoc("xlsx/customxml.xlsx");
saveAndReload(TestFilter::XLSX);
xmlDocUniquePtr pXmlDoc = parseExport(u"customXml/item1.xml"_ustr);
CPPUNIT_ASSERT(pXmlDoc);
xmlDocUniquePtr pRelsDoc = parseExport(u"customXml/_rels/item1.xml.rels"_ustr);
CPPUNIT_ASSERT(pRelsDoc);
// Check there is a relation to itemProps1.xml.
assertXPath(pRelsDoc, "/rels:Relationships/rels:Relationship", 1);
assertXPath(pRelsDoc, "/rels:Relationships/rels:Relationship[@Id='rId1']", "Target",
u"itemProps1.xml");
std::unique_ptr<SvStream> pStream
= parseExportStream(maTempFile.GetURL(), u"ddp/ddpfile.xen"_ustr);
CPPUNIT_ASSERT(pStream);
// tdf#161453: ensure E1's wrap text attribute was round-tripped
ScDocument* pDoc = getScDoc();
CPPUNIT_ASSERT(pDoc->GetAttr(4, 0, 0, ATTR_LINEBREAK).GetValue());
}
#ifdef _WIN32
static sal_Unicode lcl_getWindowsDrive(const OUString& aURL)
{
static const sal_Int32 nMinLen = strlen("file:///X:/");
if (aURL.getLength() <= nMinLen)
return 0;
const OUString aUrlStart = aURL.copy(0, nMinLen);
return (aUrlStart.startsWith("file:///") && aUrlStart.endsWith(":/")) ? aUrlStart[8] : 0;
}
#endif
CPPUNIT_TEST_FIXTURE(ScExportTest3, testRelativePathsODS)
{
createScDoc("ods/fdo79305.ods");
save(TestFilter::ODS);
xmlDocUniquePtr pDoc = parseExport(u"content.xml"_ustr);
CPPUNIT_ASSERT(pDoc);
OUString aURL = getXPath(pDoc,
"/office:document-content/office:body/office:spreadsheet/table:table/"
"table:table-row[2]/table:table-cell[2]/text:p/text:a",
"href");
#ifdef _WIN32
// if the exported document is not on the same drive then the linked document,
// there is no way to get a relative URL for the link, because ../X:/ is undefined.
if (!aURL.startsWith(".."))
{
sal_Unicode aDocDrive = lcl_getWindowsDrive(maTempFile.GetURL());
sal_Unicode aLinkDrive = lcl_getWindowsDrive(aURL);
CPPUNIT_ASSERT_MESSAGE("document on the same drive but no relative link!", aDocDrive != 0);
CPPUNIT_ASSERT_MESSAGE("document on the same drive but no relative link!", aLinkDrive != 0);
CPPUNIT_ASSERT_MESSAGE("document on the same drive but no relative link!",
aDocDrive != aLinkDrive);
return;
}
#endif
// make sure that the URL is relative
CPPUNIT_ASSERT(aURL.startsWith(".."));
}
namespace
{
void testSheetProtection_Impl(const ScDocument& rDoc)
{
CPPUNIT_ASSERT(rDoc.IsTabProtected(0));
const ScTableProtection* pTabProtection = rDoc.GetTabProtection(0);
CPPUNIT_ASSERT(pTabProtection);
CPPUNIT_ASSERT(pTabProtection->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS));
CPPUNIT_ASSERT(!pTabProtection->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS));
}
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testSheetProtectionODS)
{
createScDoc("ods/sheet-protection.ods");
ScDocument* pDoc = getScDoc();
testSheetProtection_Impl(*pDoc);
saveAndReload(TestFilter::ODS);
pDoc = getScDoc();
testSheetProtection_Impl(*pDoc);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testSwappedOutImageExport_ODS)
{
testSwappedOutImageExport(TestFilter::ODS);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testSwappedOutImageExport_XLS)
{
testSwappedOutImageExport(TestFilter::XLS);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testSwappedOutImageExport_XLSX)
{
testSwappedOutImageExport(TestFilter::XLSX);
}
void ScExportTest3::testSwappedOutImageExport(TestFilter eFormatType)
{
// Check whether the export code swaps in the image which was swapped out before.
createScDoc("ods/document_with_two_images.ods");
const OString sFailedMessage
= OString::Concat("Failed on filter: ") + TestFilterNames.at(eFormatType).toUtf8();
// Export the document and import again for a check
saveAndReload(eFormatType);
// Check whether graphic exported well after it was swapped out
uno::Reference<sheet::XSpreadsheetDocument> xDoc(mxComponent, UNO_QUERY_THROW);
uno::Reference<container::XIndexAccess> xIA(xDoc->getSheets(), UNO_QUERY_THROW);
uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xIA->getByIndex(0),
UNO_QUERY_THROW);
uno::Reference<container::XIndexAccess> xDraws(xDrawPageSupplier->getDrawPage(),
UNO_QUERY_THROW);
CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast<sal_Int32>(2),
xDraws->getCount());
uno::Reference<drawing::XShape> xImage(xDraws->getByIndex(0), uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> XPropSet(xImage, uno::UNO_QUERY_THROW);
// Check Graphic, Size
{
uno::Reference<graphic::XGraphic> xGraphic;
XPropSet->getPropertyValue(u"Graphic"_ustr) >>= xGraphic;
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is());
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(),
xGraphic->getType() != graphic::GraphicType::EMPTY);
uno::Reference<awt::XBitmap> xBitmap(xGraphic, uno::UNO_QUERY);
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xBitmap.is());
CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast<sal_Int32>(610),
xBitmap->getSize().Width);
CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast<sal_Int32>(381),
xBitmap->getSize().Height);
}
// Second Image
xImage.set(xDraws->getByIndex(1), uno::UNO_QUERY);
XPropSet.set(xImage, uno::UNO_QUERY_THROW);
// Check Graphic, Size
{
uno::Reference<graphic::XGraphic> xGraphic;
XPropSet->getPropertyValue(u"Graphic"_ustr) >>= xGraphic;
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is());
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(),
xGraphic->getType() != graphic::GraphicType::EMPTY);
uno::Reference<awt::XBitmap> xBitmap(xGraphic, uno::UNO_QUERY);
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xBitmap.is());
CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast<sal_Int32>(900),
xBitmap->getSize().Width);
CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast<sal_Int32>(600),
xBitmap->getSize().Height);
}
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testSupBookVirtualPathXLS)
{
createScDoc("xls/external-ref.xls");
saveAndReload(TestFilter::XLS);
ScDocument* pDoc = getScDoc();
OUString aFormula = pDoc->GetFormula(0, 0, 0);
#ifdef _WIN32
aFormula = OUString::Concat(aFormula.subView(0, 9)) + aFormula.subView(12);
// strip drive letter, e.g. 'C:/'
#endif
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong SupBook VirtualPath URL",
u"='file:///home/timar/Documents/external.xls'#$Sheet1.A1"_ustr,
aFormula);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testLinkedGraphicRT_ODS)
{
testLinkedGraphicRT(TestFilter::ODS);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testLinkedGraphicRT_XLS)
{
testLinkedGraphicRT(TestFilter::XLS);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testLinkedGraphicRT_XLSX)
{
testLinkedGraphicRT(TestFilter::XLSX);
}
void ScExportTest3::testLinkedGraphicRT(TestFilter eFormatType)
{
// Load the original file with one image
createScDoc("ods/document_with_linked_graphic.ods");
const OString sFailedMessage
= OString::Concat("Failed on filter: ") + TestFilterNames.at(eFormatType).toUtf8();
// linked graphic fetch is deferred during loading, allow link
// updates and trigger the fetch before export
getScDocShell()->getEmbeddedObjectContainer().setUserAllowsLinkUpdate(true);
getScDoc()->GetLinkManager()->UpdateAllLinks(false, u""_ustr);
// Export the document and import again for a check
saveAndReload(eFormatType);
// allow link updates on the reloaded document too (for ODS/XLS
// which keep the graphic as a link rather than embedding it)
getScDocShell()->getEmbeddedObjectContainer().setUserAllowsLinkUpdate(true);
// Check whether graphic imported well after export
ScDocument* pDoc = getScDoc();
ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pDrawLayer != nullptr);
const SdrPage* pPage = pDrawLayer->GetPage(0);
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pPage != nullptr);
SdrGrafObj* pObject = dynamic_cast<SdrGrafObj*>(pPage->GetObj(0));
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pObject != nullptr);
if (eFormatType == TestFilter::XLSX)
{
// FIXME: tdf#152036
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), !pObject->IsLinkedGraphic());
}
else
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pObject->IsLinkedGraphic());
const GraphicObject& rGraphicObj = pObject->GetGraphicObject(true);
CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), int(GraphicType::Bitmap),
int(rGraphicObj.GetGraphic().GetType()));
CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_uLong(864900),
rGraphicObj.GetGraphic().GetSizeBytes());
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testImageWithSpecialID_ODS)
{
testImageWithSpecialID(TestFilter::ODS);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testImageWithSpecialID_XLS)
{
testImageWithSpecialID(TestFilter::XLSX);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testImageWithSpecialID_XLSX)
{
testImageWithSpecialID(TestFilter::XLSX);
}
void ScExportTest3::testImageWithSpecialID(TestFilter eFormatType)
{
createScDoc("ods/images_with_special_IDs.ods");
const OString sFailedMessage
= OString::Concat("Failed on filter: ") + TestFilterNames.at(eFormatType).toUtf8();
// Export the document and import again for a check
saveAndReload(eFormatType);
// Check whether graphic was exported well
uno::Reference<sheet::XSpreadsheetDocument> xDoc(mxComponent, UNO_QUERY_THROW);
uno::Reference<container::XIndexAccess> xIA(xDoc->getSheets(), UNO_QUERY_THROW);
uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xIA->getByIndex(0),
UNO_QUERY_THROW);
uno::Reference<container::XIndexAccess> xDraws(xDrawPageSupplier->getDrawPage(),
UNO_QUERY_THROW);
CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast<sal_Int32>(2),
xDraws->getCount());
uno::Reference<drawing::XShape> xImage(xDraws->getByIndex(0), uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> XPropSet(xImage, uno::UNO_QUERY_THROW);
// Check Graphic, Size
{
uno::Reference<graphic::XGraphic> xGraphic;
XPropSet->getPropertyValue(u"Graphic"_ustr) >>= xGraphic;
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is());
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(),
xGraphic->getType() != graphic::GraphicType::EMPTY);
uno::Reference<awt::XBitmap> xBitmap(xGraphic, uno::UNO_QUERY);
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xBitmap.is());
CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast<sal_Int32>(610),
xBitmap->getSize().Width);
CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast<sal_Int32>(381),
xBitmap->getSize().Height);
}
// Second Image
xImage.set(xDraws->getByIndex(1), uno::UNO_QUERY);
XPropSet.set(xImage, uno::UNO_QUERY_THROW);
// Check Graphic, Size
{
uno::Reference<graphic::XGraphic> xGraphic;
XPropSet->getPropertyValue(u"Graphic"_ustr) >>= xGraphic;
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is());
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(),
xGraphic->getType() != graphic::GraphicType::EMPTY);
uno::Reference<awt::XBitmap> xBitmap(xGraphic, uno::UNO_QUERY);
CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xBitmap.is());
CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast<sal_Int32>(900),
xBitmap->getSize().Width);
CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), static_cast<sal_Int32>(600),
xBitmap->getSize().Height);
}
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testAbsNamedRangeHTML)
{
setImportFilterName(TestFilter::HTML_CALC_WEBQUERY);
createScDoc("html/numberformat.html");
ScDocShell* pDocSh = getScDocShell();
pDocSh->DoHardRecalc();
//reset import filter
setImportFilterName(TestFilter::ODS);
saveAndReload(TestFilter::ODS);
pDocSh = getScDocShell();
pDocSh->DoHardRecalc();
ScDocument* pDoc = getScDoc();
ScRangeData* pRangeData = pDoc->GetRangeName().findByUpperName(u"HTML_1"_ustr);
ScSingleRefData& rRef
= static_cast<ScDoubleRefToken*>(pRangeData->GetCode()->FirstToken())->GetSingleRef();
// see tdf#119141 for the reason why this isn't Sheet1.HTML_1
CPPUNIT_ASSERT_MESSAGE("HTML_1 is an absolute reference", !rRef.IsTabRel());
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testTdf80149)
{
createScDoc("csv/tdf80149.csv");
ScDocShell* pDocSh = getScDocShell();
pDocSh->DoHardRecalc();
saveAndReload(TestFilter::XLSX);
pDocSh = getScDocShell();
pDocSh->DoHardRecalc();
ScDocument* pDoc = getScDoc();
CPPUNIT_ASSERT_EQUAL(u"row 1"_ustr, pDoc->GetString(0, 0, 0));
// Without the fix in place, this test would have failed with
// - Expected: Character 0x16 is here ->><<--
// - Actual :
CPPUNIT_ASSERT_EQUAL(u"Character 0x16 is here ->><<--"_ustr, pDoc->GetString(1, 0, 0));
CPPUNIT_ASSERT_EQUAL(u"File opens in libre office, but can't be saved as xlsx"_ustr,
pDoc->GetString(2, 0, 0));
CPPUNIT_ASSERT_EQUAL(u"row 2"_ustr, pDoc->GetString(0, 1, 0));
CPPUNIT_ASSERT_EQUAL(u"Subsequent rows get truncated"_ustr, pDoc->GetString(1, 1, 0));
CPPUNIT_ASSERT_EQUAL(u"This cell goes missing"_ustr, pDoc->GetString(2, 1, 0));
CPPUNIT_ASSERT_EQUAL(u"row 3"_ustr, pDoc->GetString(0, 2, 0));
CPPUNIT_ASSERT_EQUAL(u"Subsequent rows get truncated"_ustr, pDoc->GetString(1, 2, 0));
CPPUNIT_ASSERT_EQUAL(u"This cell goes missing"_ustr, pDoc->GetString(2, 2, 0));
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testSheetLocalRangeNameXLS)
{
createScDoc("xls/named-ranges-local.xls");
ScDocShell* pDocSh = getScDocShell();
pDocSh->DoHardRecalc();
saveAndReload(TestFilter::XLS);
pDocSh = getScDocShell();
pDocSh->DoHardRecalc();
ScDocument* pDoc = getScDoc();
ScRangeName* pRangeName = pDoc->GetRangeName(0);
CPPUNIT_ASSERT(pRangeName);
CPPUNIT_ASSERT_EQUAL(size_t(2), pRangeName->size());
OUString aFormula = pDoc->GetFormula(3, 11, 0);
CPPUNIT_ASSERT_EQUAL(u"=SUM(local_name2)"_ustr, aFormula);
ASSERT_DOUBLES_EQUAL(14.0, pDoc->GetValue(3, 11, 0));
aFormula = pDoc->GetFormula(6, 4, 0);
CPPUNIT_ASSERT_EQUAL(u"=local_name1"_ustr, aFormula);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testRelativeNamedExpressionsXLS)
{
createScDoc("ods/tdf113991_relativeNamedRanges.ods");
ScDocShell* pDocSh = getScDocShell();
pDocSh->DoHardRecalc();
saveAndReload(TestFilter::XLS);
pDocSh = getScDocShell();
pDocSh->DoHardRecalc();
ScDocument* pDoc = getScDoc();
// Sheet1:G3
ScAddress aPos(6, 2, 0);
CPPUNIT_ASSERT_EQUAL(1.0, pDoc->GetValue(aPos));
CPPUNIT_ASSERT_EQUAL(u"=single_cell_A3"_ustr,
pDoc->GetFormula(aPos.Col(), aPos.Row(), aPos.Tab()));
// Sheet2:F6
aPos = ScAddress(5, 5, 1);
CPPUNIT_ASSERT_EQUAL(18.0, pDoc->GetValue(aPos));
CPPUNIT_ASSERT_EQUAL(u"=SUM(test_conflict)"_ustr,
pDoc->GetFormula(aPos.Col(), aPos.Row(), aPos.Tab()));
// Sheet2:H3
aPos = ScAddress(7, 2, 1);
CPPUNIT_ASSERT_EQUAL(10.0, pDoc->GetValue(aPos));
CPPUNIT_ASSERT_EQUAL(u"=single_global_A3"_ustr,
pDoc->GetFormula(aPos.Col(), aPos.Row(), aPos.Tab()));
// Sheet2:H6
aPos = ScAddress(7, 5, 1);
CPPUNIT_ASSERT_EQUAL(75.0, pDoc->GetValue(aPos));
CPPUNIT_ASSERT_EQUAL(u"=SUM(A6:F6)"_ustr, pDoc->GetFormula(aPos.Col(), aPos.Row(), aPos.Tab()));
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testSheetTextBoxHyperlinkXLSX)
{
createScDoc("xlsx/textbox-hyperlink.xlsx");
save(TestFilter::XLSX);
xmlDocUniquePtr pDoc = parseExport(u"xl/drawings/drawing1.xml"_ustr);
CPPUNIT_ASSERT(pDoc);
assertXPath(
pDoc,
"/xdr:wsDr[1]/xdr:twoCellAnchor[1]/xdr:sp[1]/xdr:nvSpPr[1]/xdr:cNvPr[1]/a:hlinkClick[1]",
1);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testFontSizeXLSX)
{
createScDoc("xlsx/fontSize.xlsx");
save(TestFilter::XLSX);
xmlDocUniquePtr pDoc = parseExport(u"xl/drawings/drawing1.xml"_ustr);
CPPUNIT_ASSERT(pDoc);
OUString fontSize = getXPath(
pDoc, "/xdr:wsDr/xdr:twoCellAnchor/xdr:sp[1]/xdr:txBody/a:p[1]/a:r[1]/a:rPr", "sz");
// make sure that the font size is 18
CPPUNIT_ASSERT_EQUAL(u"1800"_ustr, fontSize);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testSheetCharacterKerningSpaceXLSX)
{
createScDoc("xlsx/textbox-CharKerningSpace.xlsx");
saveAndReload(TestFilter::XLSX);
save(TestFilter::XLSX);
xmlDocUniquePtr pDoc = parseExport(u"xl/drawings/drawing1.xml"_ustr);
CPPUNIT_ASSERT(pDoc);
OUString CharKerningSpace = getXPath(
pDoc, "/xdr:wsDr[1]/xdr:twoCellAnchor[1]/xdr:sp[1]/xdr:txBody[1]/a:p[1]/a:r[1]/a:rPr[1]",
"spc");
// make sure that the CharKerning is 2001 (2000 in original document).
CPPUNIT_ASSERT_EQUAL(u"2001"_ustr, CharKerningSpace);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testSheetCondensedCharacterSpaceXLSX)
{
createScDoc("xlsx/textbox-CondensedCharacterSpace.xlsx");
save(TestFilter::XLSX);
xmlDocUniquePtr pDoc = parseExport(u"xl/drawings/drawing1.xml"_ustr);
CPPUNIT_ASSERT(pDoc);
OUString CondensedCharSpace = getXPath(
pDoc, "/xdr:wsDr[1]/xdr:twoCellAnchor[1]/xdr:sp[1]/xdr:txBody[1]/a:p[1]/a:r[1]/a:rPr[1]",
"spc");
// make sure that the CondensedCharSpace is -1001 (-1000 in original document).
CPPUNIT_ASSERT_EQUAL(u"-1001"_ustr, CondensedCharSpace);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testTextUnderlineColorXLSX)
{
createScDoc("xlsx/underlineColor.xlsx");
save(TestFilter::XLSX);
xmlDocUniquePtr pDoc = parseExport(u"xl/drawings/drawing1.xml"_ustr);
CPPUNIT_ASSERT(pDoc);
// Make sure the underline type is double line
assertXPath(pDoc, "/xdr:wsDr/xdr:twoCellAnchor[1]/xdr:sp[1]/xdr:txBody/a:p[1]/a:r[1]/a:rPr",
"u", u"dbl");
assertXPath(pDoc, "/xdr:wsDr/xdr:twoCellAnchor[1]/xdr:sp[1]/xdr:txBody/a:p[1]/a:r[1]/a:rPr",
"b", u"1");
// Make sure that the underline color is RED
assertXPathInsensitive(
pDoc,
"/xdr:wsDr/xdr:twoCellAnchor[1]/xdr:sp[1]/xdr:txBody/a:p[1]/a:r[1]/a:rPr/a:uFill/"
"a:solidFill/a:srgbClr",
"val", u"ff0000");
// Make sure the underline type is drawn with heavy line
assertXPath(pDoc, "/xdr:wsDr/xdr:twoCellAnchor[2]/xdr:sp[1]/xdr:txBody/a:p[1]/a:r[1]/a:rPr",
"u", u"heavy");
// tdf#104219 Make sure that uFill is not existing and uFillTx is set.
// It mean that color is automatic, should be the same color as the text.
assertXPath(
pDoc, "/xdr:wsDr/xdr:twoCellAnchor[2]/xdr:sp[1]/xdr:txBody/a:p[1]/a:r[1]/a:rPr/a:uFill", 0);
assertXPath(pDoc,
"/xdr:wsDr/xdr:twoCellAnchor[2]/xdr:sp[1]/xdr:txBody/a:p[1]/a:r[1]/a:rPr/a:uFillTx",
1);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testSheetRunParagraphPropertyXLSX)
{
createScDoc("xlsx/TextColor.xlsx");
save(TestFilter::XLSX);
xmlDocUniquePtr pDoc = parseExport(u"xl/sharedStrings.xml"_ustr);
CPPUNIT_ASSERT(pDoc);
OUString aColor = getXPath(pDoc, "/x:sst/x:si/x:r[1]/x:rPr[1]/x:color", "rgb");
CPPUNIT_ASSERT_EQUAL(u"FFFF0000"_ustr, aColor);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testPreserveTextWhitespaceXLSX)
{
createScDoc("xlsx/preserve-whitespace.xlsx");
save(TestFilter::XLSX);
xmlDocUniquePtr pDoc = parseExport(u"xl/sharedStrings.xml"_ustr);
CPPUNIT_ASSERT(pDoc);
assertXPath(pDoc, "/x:sst/x:si/x:t", "space", u"preserve");
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testPreserveTextWhitespace2XLSX)
{
createScDoc("xlsx/preserve_space.xlsx");
saveAndReload(TestFilter::XLSX);
xmlDocUniquePtr pDoc = parseExport(u"xl/sharedStrings.xml"_ustr);
CPPUNIT_ASSERT(pDoc);
assertXPath(pDoc, "/x:sst/x:si[1]/x:t", "space", u"preserve");
assertXPath(pDoc, "/x:sst/x:si[2]/x:t", "space", u"preserve");
// tdf#158460: ensure B1 is NOT set to wrap text, so Excel keeps displaying as single line
SCTAB nTab = 0;
SCROW nRow = 0;
CPPUNIT_ASSERT(!getScDoc()->GetAttr(1, nRow, nTab, ATTR_LINEBREAK).GetValue());
// Without the fix, this wrapped to two lines high (841). It should be 1 line high (529).
int nHeight = convertTwipToMm100(getScDoc()->GetRowHeight(nRow, nTab, false));
CPPUNIT_ASSERT_LESS(600, nHeight);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testHiddenShapeXLS)
{
createScDoc("xls/hiddenShape.xls");
ScDocument* pDoc = getScDoc();
CPPUNIT_ASSERT(pDoc->GetTableCount() > 0);
ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
SdrPage* pPage = pDrawLayer->GetPage(0);
CPPUNIT_ASSERT(pPage);
SdrObject* pObj = pPage->GetObj(0);
CPPUNIT_ASSERT(pObj);
CPPUNIT_ASSERT_MESSAGE("Drawing object should not be visible.", !pObj->IsVisible());
CPPUNIT_ASSERT_MESSAGE("Drawing object should not be printable.", !pObj->IsPrintable());
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testHiddenShapeXLSX)
{
createScDoc("xlsx/hiddenShape.xlsx");
ScDocument* pDoc = getScDoc();
CPPUNIT_ASSERT(pDoc->GetTableCount() > 0);
ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
SdrPage* pPage = pDrawLayer->GetPage(0);
CPPUNIT_ASSERT(pPage);
SdrObject* pObj = pPage->GetObj(0);
CPPUNIT_ASSERT(pObj);
CPPUNIT_ASSERT_MESSAGE("Drawing object should not be visible.", !pObj->IsVisible());
CPPUNIT_ASSERT_MESSAGE("Drawing object should not be printable.", !pObj->IsPrintable());
save(TestFilter::XLSX);
xmlDocUniquePtr pDocXml = parseExport(u"xl/drawings/drawing1.xml"_ustr);
CPPUNIT_ASSERT(pDocXml);
assertXPath(pDocXml, "/xdr:wsDr/xdr:twoCellAnchor/xdr:sp[1]/xdr:nvSpPr/xdr:cNvPr", "hidden",
u"1");
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testShapeAutofitXLSX)
{
createScDoc("xlsx/testShapeAutofit.xlsx");
save(TestFilter::XLSX);
xmlDocUniquePtr pDoc = parseExport(u"xl/drawings/drawing1.xml"_ustr);
CPPUNIT_ASSERT(pDoc);
// TextAutoGrowHeight --> "Fit height to text" / "Resize shape to fit text" --> true
assertXPath(pDoc, "/xdr:wsDr/xdr:twoCellAnchor[1]/xdr:sp/xdr:txBody/a:bodyPr/a:spAutoFit", 1);
// TextAutoGrowHeight --> "Fit height to text" / "Resize shape to fit text" --> false
assertXPath(pDoc, "/xdr:wsDr/xdr:twoCellAnchor[2]/xdr:sp/xdr:txBody/a:bodyPr/a:noAutofit", 1);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testHyperlinkXLSX)
{
createScDoc("xlsx/hyperlink.xlsx");
save(TestFilter::XLSX);
xmlDocUniquePtr pDoc = parseExport(u"xl/drawings/_rels/drawing1.xml.rels"_ustr);
CPPUNIT_ASSERT(pDoc);
assertXPath(pDoc, "/rels:Relationships/rels:Relationship", "Target", u"#Sheet2!A1");
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testMoveCellAnchoredShapesODS)
{
createScDoc("ods/move-cell-anchored-shapes.ods");
// There are two cell-anchored objects on the first sheet.
ScDocument* pDoc = getScDoc();
CPPUNIT_ASSERT_MESSAGE("There should be at least one sheet.", pDoc->GetTableCount() > 0);
ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
SdrPage* pPage = pDrawLayer->GetPage(0);
CPPUNIT_ASSERT_MESSAGE("draw page for sheet 1 should exist.", pPage);
SdrObject* pObj = pPage->GetObj(0);
CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj);
// Check cell anchor state
ScAnchorType oldType = ScDrawLayer::GetAnchorType(*pObj);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to get anchor type", SCA_CELL_RESIZE, oldType);
// Get anchor data
ScDrawObjData* pData = ScDrawLayer::GetObjData(pObj);
CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData);
CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.",
!pData->getShapeRect().IsEmpty());
ScAddress aDataStart = pData->maStart;
ScAddress aDataEnd = pData->maEnd;
// Get non rotated anchor data
ScDrawObjData* pNData = ScDrawLayer::GetNonRotatedObjData(pObj);
CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData);
CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.",
!pNData->getShapeRect().IsEmpty());
ScAddress aNDataStart = pNData->maStart;
ScAddress aNDataEnd = pNData->maEnd;
CPPUNIT_ASSERT_EQUAL(aDataStart, aNDataStart);
CPPUNIT_ASSERT_EQUAL(aDataEnd, aNDataEnd);
// Insert 2 rows.
pDoc->InsertRow(ScRange(0, aDataStart.Row() - 1, 0, pDoc->MaxCol(), aDataStart.Row(), 0));
// Get anchor data
pData = ScDrawLayer::GetObjData(pObj);
CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData);
CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.",
!pData->getShapeRect().IsEmpty());
// Get non rotated anchor data
pNData = ScDrawLayer::GetNonRotatedObjData(pObj);
CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData);
CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.",
!pNData->getShapeRect().IsEmpty());
// Check if data has moved to new rows
CPPUNIT_ASSERT_EQUAL(pData->maStart.Row(), aDataStart.Row() + 2);
CPPUNIT_ASSERT_EQUAL(pData->maEnd.Row(), aDataEnd.Row() + 2);
CPPUNIT_ASSERT_EQUAL(pNData->maStart.Row(), aNDataStart.Row() + 2);
CPPUNIT_ASSERT_EQUAL(pNData->maEnd.Row(), aNDataEnd.Row() + 2);
// Save the anchor data
aDataStart = pData->maStart;
aDataEnd = pData->maEnd;
aNDataStart = pNData->maStart;
aNDataEnd = pNData->maEnd;
// Save the document and load again to check anchor persist
saveAndReload(TestFilter::ODS);
// There are two cell-anchored objects on the first sheet.
pDoc = getScDoc();
CPPUNIT_ASSERT_MESSAGE("There should be at least one sheet.", pDoc->GetTableCount() > 0);
pDrawLayer = pDoc->GetDrawLayer();
pPage = pDrawLayer->GetPage(0);
CPPUNIT_ASSERT_MESSAGE("draw page for sheet 1 should exist.", pPage);
pObj = pPage->GetObj(0);
CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj);
// Check cell anchor state
oldType = ScDrawLayer::GetAnchorType(*pObj);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to get anchor type", SCA_CELL_RESIZE, oldType);
// Get anchor data
pData = ScDrawLayer::GetObjData(pObj);
CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData);
CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.",
!pData->getShapeRect().IsEmpty());
// Get non rotated anchor data
pNData = ScDrawLayer::GetNonRotatedObjData(pObj);
CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData);
CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.",
!pNData->getShapeRect().IsEmpty());
// Check if data after save it
CPPUNIT_ASSERT_EQUAL(pData->maStart, aDataStart);
CPPUNIT_ASSERT_EQUAL(pData->maEnd, aDataEnd);
CPPUNIT_ASSERT_EQUAL(pNData->maStart, aNDataStart);
CPPUNIT_ASSERT_EQUAL(pNData->maEnd, aNDataEnd);
// Insert a column.
pDoc->InsertCol(ScRange(aDataStart.Col(), 0, 0, aDataStart.Col(), pDoc->MaxRow(), 0));
// Get anchor data
pData = ScDrawLayer::GetObjData(pObj);
CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData);
CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.",
!pData->getShapeRect().IsEmpty());
// Get non rotated anchor data
pNData = ScDrawLayer::GetNonRotatedObjData(pObj);
CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData);
CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.",
!pNData->getShapeRect().IsEmpty());
// Check if data has moved to new rows
CPPUNIT_ASSERT_EQUAL(pData->maStart.Col(), SCCOL(aDataStart.Col() + 1));
CPPUNIT_ASSERT_EQUAL(pData->maEnd.Col(), SCCOL(aDataEnd.Col() + 1));
CPPUNIT_ASSERT_EQUAL(pNData->maStart.Col(), SCCOL(aNDataStart.Col() + 1));
CPPUNIT_ASSERT_EQUAL(pNData->maEnd.Col(), SCCOL(aNDataEnd.Col() + 1));
// Save the anchor data
aDataStart = pData->maStart;
aDataEnd = pData->maEnd;
aNDataStart = pNData->maStart;
aNDataEnd = pNData->maEnd;
// Save the document and load again to check anchor persist
saveAndReload(TestFilter::ODS);
// There are two cell-anchored objects on the first sheet.
pDoc = getScDoc();
CPPUNIT_ASSERT_MESSAGE("There should be at least one sheet.", pDoc->GetTableCount() > 0);
pDrawLayer = pDoc->GetDrawLayer();
pPage = pDrawLayer->GetPage(0);
CPPUNIT_ASSERT_MESSAGE("draw page for sheet 1 should exist.", pPage);
pObj = pPage->GetObj(0);
CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj);
// Check cell anchor state
oldType = ScDrawLayer::GetAnchorType(*pObj);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to get anchor type", SCA_CELL_RESIZE, oldType);
// Get anchor data
pData = ScDrawLayer::GetObjData(pObj);
CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData);
CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.",
!pData->getShapeRect().IsEmpty());
// Get non rotated anchor data
pNData = ScDrawLayer::GetNonRotatedObjData(pObj);
CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData);
CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.",
!pNData->getShapeRect().IsEmpty());
// Check if data after save it
CPPUNIT_ASSERT_EQUAL(pData->maStart, aDataStart);
CPPUNIT_ASSERT_EQUAL(pData->maEnd, aDataEnd);
CPPUNIT_ASSERT_EQUAL(pNData->maStart, aNDataStart);
CPPUNIT_ASSERT_EQUAL(pNData->maEnd, aNDataEnd);
}
static void impl_testLegacyCellAnchoredRotatedShape(ScDocument& rDoc, const tools::Rectangle& aRect,
const ScDrawObjData& aAnchor,
tools::Long TOLERANCE = 30 /* 30 hmm */)
{
ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
CPPUNIT_ASSERT_MESSAGE("No drawing layer.", pDrawLayer);
SdrPage* pPage = pDrawLayer->GetPage(0);
CPPUNIT_ASSERT_MESSAGE("No page instance for the 1st sheet.", pPage);
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pPage->GetObjCount());
SdrObject* pObj = pPage->GetObj(0);
const tools::Rectangle& aSnap = pObj->GetSnapRect();
CPPUNIT_ASSERT_DOUBLES_EQUAL(aRect.GetHeight(), aSnap.GetHeight(), TOLERANCE);
CPPUNIT_ASSERT_DOUBLES_EQUAL(aRect.GetWidth(), aSnap.GetWidth(), TOLERANCE);
CPPUNIT_ASSERT_DOUBLES_EQUAL(aRect.Left(), aSnap.Left(), TOLERANCE);
CPPUNIT_ASSERT_DOUBLES_EQUAL(aRect.Top(), aSnap.Top(), TOLERANCE);
ScDrawObjData* pData = ScDrawLayer::GetObjData(pObj);
CPPUNIT_ASSERT_MESSAGE("expected object meta data", pData);
CPPUNIT_ASSERT_EQUAL(aAnchor.maStart.Row(), pData->maStart.Row());
CPPUNIT_ASSERT_EQUAL(aAnchor.maStart.Col(), pData->maStart.Col());
CPPUNIT_ASSERT_EQUAL(aAnchor.maEnd.Row(), pData->maEnd.Row());
CPPUNIT_ASSERT_EQUAL(aAnchor.maEnd.Col(), pData->maEnd.Col());
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testLegacyCellAnchoredRotatedShape)
{
// This example doc contains cell anchored shape that is rotated, the
// rotated shape is in fact clipped by the sheet boundaries (and thus
// is a good edge case test to see if we import it still correctly)
createScDoc("ods/legacycellanchoredrotatedclippedshape.ods");
ScDocument* pDoc = getScDoc();
// ensure the imported legacy rotated shape is in the expected position
tools::Rectangle aRect(6000, -2000, 8000, 4000);
// ensure the imported ( and converted ) anchor ( note we internally now store the anchor in
// terms of the rotated shape ) is more or less contains the correct info
ScDrawObjData aAnchor;
aAnchor.maStart.SetRow(0);
aAnchor.maStart.SetCol(5);
aAnchor.maEnd.SetRow(3);
aAnchor.maEnd.SetCol(7);
impl_testLegacyCellAnchoredRotatedShape(*pDoc, aRect, aAnchor);
// test save and reload
// for some reason having this test in subsequent_export-test.cxx causes
// a core dump in editeng ( so moved to here )
saveAndReload(TestFilter::ODS);
pDoc = getScDoc();
impl_testLegacyCellAnchoredRotatedShape(*pDoc, aRect, aAnchor);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testLegacyCellAnchoredRotatedShape2)
{
// This example doc contains cell anchored shape that is rotated, the
// rotated shape is in fact clipped by the sheet boundaries, additionally
// the shape is completely hidden because the rows the shape occupies
// are hidden
createScDoc("ods/legacycellanchoredrotatedhiddenshape.ods");
ScDocument* pDoc = getScDoc();
// ensure the imported legacy rotated shape is in the expected position
tools::Rectangle aRect(6000, -2000, 8000, 4000);
// ensure the imported (and converted) anchor (note we internally now store the anchor in
// terms of the rotated shape) is more or less contains the correct info
ScDrawObjData aAnchor;
aAnchor.maStart.SetRow(0);
aAnchor.maStart.SetCol(5);
aAnchor.maEnd.SetRow(3);
aAnchor.maEnd.SetCol(7);
pDoc->ShowRows(0, 9, 0, true); // show relevant rows
pDoc->SetDrawPageSize(0); // trigger recalcpos
impl_testLegacyCellAnchoredRotatedShape(*pDoc, aRect, aAnchor);
// test save and reload
saveAndReload(TestFilter::ODS);
pDoc = getScDoc();
impl_testLegacyCellAnchoredRotatedShape(*pDoc, aRect, aAnchor);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testLegacyCellAnchoredRotatedShape3)
{
// This example doc contains cell anchored shape that is rotated
createScDoc("ods/legacycellanchoredrotatedshape.ods");
ScDocument* pDoc = getScDoc();
// ensure the imported legacy rotated shape is in the expected position
tools::Rectangle aRect(6000, 3000, 8000, 9000);
// ensure the imported (and converted) anchor (note we internally now store the anchor in
// terms of the rotated shape) more or less contains the correct info
ScDrawObjData aAnchor;
aAnchor.maStart.SetRow(3);
aAnchor.maStart.SetCol(6);
aAnchor.maEnd.SetRow(9);
aAnchor.maEnd.SetCol(8);
// test import
impl_testLegacyCellAnchoredRotatedShape(*pDoc, aRect, aAnchor);
// test save and reload
saveAndReload(TestFilter::ODS);
pDoc = getScDoc();
impl_testLegacyCellAnchoredRotatedShape(*pDoc, aRect, aAnchor);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testTdf113646)
{
createScDoc("ods/tdf113646.ods");
save(TestFilter::XLSX);
xmlDocUniquePtr pSheet = parseExport(u"xl/styles.xml"_ustr);
CPPUNIT_ASSERT(pSheet);
assertXPath(pSheet, "/x:styleSheet/x:dxfs/x:dxf/x:font/x:sz", "val", u"36");
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testDateStandardfilterXLSX)
{
// XLSX Roundtripping standard filter with date
createScDoc("ods/tdf142607.ods");
save(TestFilter::XLSX);
xmlDocUniquePtr pDoc = parseExport(u"xl/worksheets/sheet1.xml"_ustr);
CPPUNIT_ASSERT(pDoc);
assertXPath(pDoc, "//x:autoFilter", "ref", u"A1:B6");
assertXPath(pDoc, "//x:autoFilter/x:filterColumn/x:filters/x:dateGroupItem[1]", "day", u"03");
assertXPath(pDoc, "//x:autoFilter/x:filterColumn/x:filters/x:dateGroupItem[1]", "month", u"12");
assertXPath(pDoc, "//x:autoFilter/x:filterColumn/x:filters/x:dateGroupItem[1]", "year",
u"2011");
assertXPath(pDoc, "//x:autoFilter/x:filterColumn/x:filters/x:dateGroupItem[1]",
"dateTimeGrouping", u"day");
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testTdf137576_Measureline)
{
// The document contains a vertical measure line, anchored "To Cell (resize with cell)" with
// length 37mm. Save and reload had resulted in a line of 0mm length.
// Get document
createScDoc("ods/tdf137576_Measureline.ods");
ScDocument* pDoc = getScDoc();
// Get shape
ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
CPPUNIT_ASSERT_MESSAGE("Load: No ScDrawLayer", pDrawLayer);
SdrPage* pPage = pDrawLayer->GetPage(0);
CPPUNIT_ASSERT_MESSAGE("Load: No draw page", pPage);
SdrMeasureObj* pObj = static_cast<SdrMeasureObj*>(pPage->GetObj(0));
CPPUNIT_ASSERT_MESSAGE("Load: No measure object", pObj);
// Check start and end point of measureline
const Point aStart = pObj->GetPoint(0);
CPPUNIT_ASSERT_POINT_EQUAL_WITH_TOLERANCE(Point(4800, 1500), aStart, 1);
const Point aEnd = pObj->GetPoint(1);
CPPUNIT_ASSERT_POINT_EQUAL_WITH_TOLERANCE(Point(4800, 5200), aEnd, 1);
// Save and reload
saveAndReload(TestFilter::ODS);
pDoc = getScDoc();
// Get shape
pDrawLayer = pDoc->GetDrawLayer();
CPPUNIT_ASSERT_MESSAGE("Reload: No ScDrawLayer", pDrawLayer);
pPage = pDrawLayer->GetPage(0);
CPPUNIT_ASSERT_MESSAGE("Reload: No draw page", pPage);
pObj = static_cast<SdrMeasureObj*>(pPage->GetObj(0));
CPPUNIT_ASSERT_MESSAGE("Reload: No measure object", pObj);
// Check start and end point of measureline, should be unchanged
const Point aStart2 = pObj->GetPoint(0);
CPPUNIT_ASSERT_POINT_EQUAL_WITH_TOLERANCE(Point(4800, 1500), aStart2, 1);
const Point aEnd2 = pObj->GetPoint(1);
CPPUNIT_ASSERT_POINT_EQUAL_WITH_TOLERANCE(Point(4800, 5200), aEnd2, 1);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testTdf137044_CoverHiddenRows)
{
// The document contains a shape anchored "To Cell (resize with cell)" with start in cell A4 and
// end in cell A7. Row height is 30mm. Hiding rows 5 and 6, then saving and reload had resulted
// in a wrong end cell offset and thus a wrong height of the shape.
// Get document
createScDoc("ods/tdf137044_CoverHiddenRows.ods");
ScDocument* pDoc = getScDoc();
// Get shape
ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
CPPUNIT_ASSERT_MESSAGE("Load: No ScDrawLayer", pDrawLayer);
SdrPage* pPage = pDrawLayer->GetPage(0);
CPPUNIT_ASSERT_MESSAGE("Load: No draw page", pPage);
SdrObject* pObj = pPage->GetObj(0);
CPPUNIT_ASSERT_MESSAGE("Load: No object", pObj);
// Get original object values
tools::Rectangle aSnapRectOrig = pObj->GetSnapRect();
Point aOriginalEndOffset = ScDrawLayer::GetObjData(pObj)->maEndOffset;
CPPUNIT_ASSERT_RECTANGLE_EQUAL_WITH_TOLERANCE(
tools::Rectangle(Point(500, 3500), Size(1501, 11001)), aSnapRectOrig, 1);
CPPUNIT_ASSERT_POINT_EQUAL_WITH_TOLERANCE(Point(2000, 2499), aOriginalEndOffset, 1);
// Hide rows 5 and 6 in UI = row index 4 to 5.
pDoc->SetRowHidden(4, 5, 0, true);
// Save and reload
saveAndReload(TestFilter::ODS);
pDoc = getScDoc();
// Get shape
pDrawLayer = pDoc->GetDrawLayer();
CPPUNIT_ASSERT_MESSAGE("Reload: No ScDrawLayer", pDrawLayer);
pPage = pDrawLayer->GetPage(0);
CPPUNIT_ASSERT_MESSAGE("Reload: No draw page", pPage);
pObj = pPage->GetObj(0);
CPPUNIT_ASSERT_MESSAGE("Reload: No object", pObj);
// Get new values and compare. End offset should be the same, height should be 6000 smaller.
tools::Rectangle aSnapRectReload = pObj->GetSnapRect();
Point aReloadEndOffset = ScDrawLayer::GetObjData(pObj)->maEndOffset;
CPPUNIT_ASSERT_RECTANGLE_EQUAL_WITH_TOLERANCE(
tools::Rectangle(Point(500, 3500), Size(1501, 5001)), aSnapRectReload, 1);
CPPUNIT_ASSERT_POINT_EQUAL_WITH_TOLERANCE(Point(2000, 2499), aReloadEndOffset, 1);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testTdf137020_FlipVertical)
{
// Get document
createScDoc("ods/tdf137020_FlipVertical.ods");
ScDocument* pDoc = getScDoc();
// Get shape
ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
CPPUNIT_ASSERT_MESSAGE("Load: No ScDrawLayer", pDrawLayer);
SdrPage* pPage = pDrawLayer->GetPage(0);
CPPUNIT_ASSERT_MESSAGE("Load: No draw page", pPage);
SdrObject* pObj = pPage->GetObj(0);
CPPUNIT_ASSERT_MESSAGE("Load: No object", pObj);
const tools::Rectangle aSnapRectOrig = pObj->GetSnapRect();
// Vertical mirror on center should not change the snap rect.
pObj->Mirror(aSnapRectOrig.LeftCenter(), aSnapRectOrig.RightCenter());
const tools::Rectangle aSnapRectFlip = pObj->GetSnapRect();
CPPUNIT_ASSERT_RECTANGLE_EQUAL_WITH_TOLERANCE(aSnapRectOrig, aSnapRectFlip, 1);
// Save and reload
saveAndReload(TestFilter::ODS);
pDoc = getScDoc();
// Get shape
pDrawLayer = pDoc->GetDrawLayer();
CPPUNIT_ASSERT_MESSAGE("Reload: No ScDrawLayer", pDrawLayer);
pPage = pDrawLayer->GetPage(0);
CPPUNIT_ASSERT_MESSAGE("Reload: No draw page", pPage);
pObj = pPage->GetObj(0);
CPPUNIT_ASSERT_MESSAGE("Reload: No object", pObj);
// Check pos and size of shape again, should be unchanged
const tools::Rectangle aSnapRectReload = pObj->GetSnapRect();
CPPUNIT_ASSERT_RECTANGLE_EQUAL_WITH_TOLERANCE(aSnapRectOrig, aSnapRectReload, 1);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testTdf82254_csv_bom)
{
setImportFilterName(TestFilter::CSV);
createScDoc("csv/testTdf82254-csv-bom.csv");
saveAndReload(TestFilter::CSV);
ScDocShell* pDocSh = getScDocShell();
SvStream* pStream = pDocSh->GetMedium()->GetInStream();
pStream->Seek(0);
CPPUNIT_ASSERT_EQUAL(sal_uInt64(0), pStream->Tell());
pStream->StartReadingUnicodeText(RTL_TEXTENCODING_UTF8);
// Without the fix in place, this test would have failed with
// - Expected: 3
// - Actual : 0 (no byte order mark was read)
CPPUNIT_ASSERT_EQUAL(sal_uInt64(3), pStream->Tell());
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testTdf170249)
{
createScDoc("ods/tdf170249.ods");
save(TestFilter::XLSX);
xmlDocUniquePtr pSheet = parseExport(u"xl/worksheets/sheet1.xml"_ustr);
CPPUNIT_ASSERT(pSheet);
assertXPathContent(pSheet, "/x:worksheet/x:sheetData/x:row[1]/x:c/x:f",
u"INDEX($B2:$XFD2, 1, 2)");
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testTdf170292)
{
createScDoc("ods/tdf170292.ods");
save(TestFilter::XLSX);
xmlDocUniquePtr pSheet = parseExport(u"xl/workbook.xml"_ustr);
CPPUNIT_ASSERT(pSheet);
assertXPath(pSheet, "/x:workbook/x:definedNames/x:definedName[1]", "name", u"_cat1");
assertXPathContent(pSheet, "/x:workbook/x:definedNames/x:definedName[2]",
u"OFFSET(_cat1,0,2,,)");
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testPictureTagOrder)
{
createScDoc("xls/pictureOrder.xls");
save(TestFilter::XLSX);
xmlDocUniquePtr pSheet = parseExport(u"xl/worksheets/sheet3.xml"_ustr);
CPPUNIT_ASSERT(pSheet);
assertXPath(pSheet, "/x:worksheet/x:picture", 1);
assertXPath(pSheet, "/x:worksheet/mc:AlternateContent", 1);
assertXPath(pSheet, "/x:worksheet/x:picture/following-sibling::mc:AlternateContent", 1);
pSheet = parseExport(u"xl/worksheets/sheet4.xml"_ustr);
CPPUNIT_ASSERT(pSheet);
assertXPath(pSheet, "/x:worksheet/x:picture", 1);
assertXPath(pSheet, "/x:worksheet/mc:AlternateContent", 1);
assertXPath(pSheet, "/x:worksheet/x:picture/following-sibling::mc:AlternateContent", 1);
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testRefAfterNoName)
{
createScDoc("ods/ooo88173-1.ods");
save(TestFilter::XLSX);
xmlDocUniquePtr pSheet = parseExport(u"xl/worksheets/sheet1.xml"_ustr);
CPPUNIT_ASSERT(pSheet);
// earlier #NAME?$C7
assertXPathContent(pSheet, "/x:worksheet/x:conditionalFormatting[5]/x:cfRule/x:formula",
u"#NAME?");
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testfdo55572)
{
createScDoc("xls/fdo55572-1.xls");
save(TestFilter::XLSX);
xmlDocUniquePtr pWorkbook = parseExport(u"xl/workbook.xml"_ustr);
CPPUNIT_ASSERT(pWorkbook);
assertXPathContent(
pWorkbook, "/x:workbook/x:definedNames/x:definedName[1]",
u"'Analisi Venduto per Aliquota IV'!$L$3"); // analisi venduto per aliquota iv!r3c12
assertXPathContent(
pWorkbook, "/x:workbook/x:definedNames/x:definedName[2]",
u"'Analisi Venduto per Aliquota IV'!$O$3"); // analisi venduto per aliquota iv!r3c15
assertXPathContent(
pWorkbook, "/x:workbook/x:definedNames/x:definedName[3]",
u"'Analisi Venduto per Aliquota IV'!$L$5"); // analisi venduto per aliquota iv!r5c12
assertXPathContent(
pWorkbook, "/x:workbook/x:definedNames/x:definedName[4]",
u"'Analisi Venduto per Aliquota IV'!$O$5"); // analisi venduto per aliquota iv!r5c15
assertXPathContent(
pWorkbook, "/x:workbook/x:definedNames/x:definedName[5]",
u"'Analisi Venduto per Aliquota IV'!$A$7"); // analisi venduto per aliquota iv!r7c1
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testEmptyTwoCellAnchor)
{
createScDoc("xls/emptyAnchor.xls");
save(TestFilter::XLSX);
xmlDocUniquePtr pDrawing = parseExport(u"xl/drawings/drawing1.xml"_ustr);
CPPUNIT_ASSERT(pDrawing);
/* The anchored element on sheet 1 of the doc doesn't contain any graphic
and exporting empty anchors with no graphic produces an error in excel. Hence,
we should not export the anchor at all if it doesn't contain any graphic.
*/
assertXPathContent(pDrawing, "/xdr:wsDr", u"");
}
CPPUNIT_TEST_FIXTURE(ScExportTest3, testForumMsoEn4145327)
{
// regressed due to commit 7de38a6f32a0d77c33978195ee9dd22db154ad65
createScDoc("xlsx/forum-mso-en4-145327.xlsx");
save(TestFilter::XLSX);
xmlDocUniquePtr pWorkbook = parseExport(u"xl/workbook.xml"_ustr);
CPPUNIT_ASSERT(pWorkbook);
// regressed export -> REPLACE(CELL("filename",!$'1'.A1),1,FIND("]",CELL("filename",!$'1'.A1)),"")-1
// having invalid string "!$'1'.A1"
assertXPathContent(
pWorkbook, "/x:workbook/x:definedNames/x:definedName[1]",
u"REPLACE(CELL(\"filename\",!A1),1,FIND(\"]\",CELL(\"filename\",!A1)),\"\")-1");
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */