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>
2192 lines
84 KiB
C++
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: */
|