sc: test that a cross-doc table-name clash leaves paste unresolved

Pasting a fully-copied named table into a different document that
already owns an unrelated table of the same name must not bind the
pasted structured-reference formula to that destination table. The
name is document-global and the copied table cannot be recreated
under it, so the reference stays unresolved (#REF!) instead of
silently computing the unrelated table's data.

The engine already behaves this way. This test guards against a
regression that would bind the pasted reference to the destination's
table and produce a silent wrong result.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I7304951c03ea090703f8e4232f92b1d14179b537
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5093
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Balázs Varga <balazs.varga@collabora.com>
(cherry picked from commit cd8c7ad4578b5a7c5225e82b212f45b20cbb7d96)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207942
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
Tomaž Vajngerl
2026-07-10 14:48:11 +02:00
committed by Xisco Fauli
parent 21221fe1f0
commit a84060c9ec
+76
View File
@@ -21,6 +21,7 @@
#include <editeng/borderline.hxx>
#include <editeng/brushitem.hxx>
#include <editutil.hxx>
#include <formula/errorcodes.hxx>
#include <formulacell.hxx>
#include <impex.hxx>
#include <iostream>
@@ -10114,6 +10115,81 @@ CPPUNIT_TEST_FIXTURE(TestCopyPaste, testCopyFromClipPartialTableNoPhantom)
m_pDoc->DeleteTab(0);
}
CPPUNIT_TEST_FIXTURE(TestCopyPaste, testCopyFromClipCrossDocSameNameNoBind)
{
// A full table copy pasted into a different document that already owns an
// unrelated table of the same name must not bind the pasted structured
// reference to that destination table. The name is document-global and
// cannot be recreated, so the reference is left unresolved (#REF!) instead
// of silently computing the wrong table's data.
m_pDoc->InsertTab(0, u"Src"_ustr);
// Source MyTable A1:C4; a structured-ref formula in C2 reads its H1
// column.
auto pTable = std::make_unique<ScDBData>(u"MyTable"_ustr, 0, 0, 0, 2, 3, true, true);
pTable->SetTableColumnNames(std::vector<OUString>{ u"H1"_ustr, u"H2"_ustr, u"H3"_ustr });
CPPUNIT_ASSERT(m_pDoc->GetDBCollection()->getNamedDBs().insert(std::move(pTable)));
m_pDoc->SetValue(0, 1, 0, 1.0); // A2
m_pDoc->SetValue(0, 2, 0, 4.0); // A3
m_pDoc->SetValue(0, 3, 0, 16.0); // A4
m_pDoc->SetString(2, 1, 0, u"=SUM(MyTable[H1])"_ustr); // C2
m_pDoc->CalcAll();
CPPUNIT_ASSERT_EQUAL(21.0, m_pDoc->GetValue(2, 1, 0));
// Copy the whole table A1:C4.
ScRange aClipRange(0, 0, 0, 2, 3, 0);
ScClipParam aClipParam(aClipRange, false);
ScMarkData aMark(m_pDoc->GetSheetLimits());
aMark.SelectOneTable(0);
aMark.SetMarkArea(aClipRange);
ScDocument aClipDoc(SCDOCMODE_CLIP);
m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark, false, false);
// Destination document with its OWN unrelated MyTable at F11:H14
// carrying distinct H1 data.
ScDocShellRef xDestDocSh = new ScDocShell;
xDestDocSh->DoLoad(new SfxMedium(u"file:///crossdocnameclash.fake"_ustr, StreamMode::STD_READWRITE));
ScDocument& rDestDoc = xDestDocSh->GetDocument();
rDestDoc.InsertTab(0, u"Dest"_ustr);
auto pDestTable = std::make_unique<ScDBData>(u"MyTable"_ustr, 0, 5, 10, 7, 13, true, true);
pDestTable->SetTableColumnNames(std::vector<OUString>{ u"H1"_ustr, u"H2"_ustr, u"H3"_ustr });
CPPUNIT_ASSERT(rDestDoc.GetDBCollection()->getNamedDBs().insert(std::move(pDestTable)));
rDestDoc.SetValue(5, 11, 0, 100.0); // F12
rDestDoc.SetValue(5, 12, 0, 200.0); // F13
rDestDoc.SetValue(5, 13, 0, 400.0); // F14
// Paste the copied table at A1, clear of the destination's own table.
ScRange aDestRange(0, 0, 0, 2, 3, 0);
ScMarkData aDestMark(rDestDoc.GetSheetLimits());
aDestMark.SelectOneTable(0);
rDestDoc.CopyFromClip(aDestRange, aDestMark, InsertDeleteFlags::ALL, nullptr, &aClipDoc);
rDestDoc.CalcAll();
// The pasted formula resolves to FormulaError::NoRef.
CPPUNIT_ASSERT_EQUAL(int(FormulaError::NoRef),
int(rDestDoc.GetErrCode(ScAddress(2, 1, 0))));
// The source's H1 data landed in the destination at A2:A4.
CPPUNIT_ASSERT_EQUAL(1.0, rDestDoc.GetValue(0, 1, 0));
CPPUNIT_ASSERT_EQUAL(4.0, rDestDoc.GetValue(0, 2, 0));
CPPUNIT_ASSERT_EQUAL(16.0, rDestDoc.GetValue(0, 3, 0));
// The destination's own table stays at its original area with its data
// untouched by the paste.
const ScDBData* pDestOwn
= rDestDoc.GetDBCollection()->getNamedDBs().findByUpperName(u"MYTABLE"_ustr);
CPPUNIT_ASSERT(pDestOwn);
ScRange aDestOwnArea;
pDestOwn->GetArea(aDestOwnArea);
CPPUNIT_ASSERT_EQUAL(ScRange(5, 10, 0, 7, 13, 0), aDestOwnArea);
CPPUNIT_ASSERT_EQUAL(100.0, rDestDoc.GetValue(5, 11, 0));
CPPUNIT_ASSERT_EQUAL(200.0, rDestDoc.GetValue(5, 12, 0));
CPPUNIT_ASSERT_EQUAL(400.0, rDestDoc.GetValue(5, 13, 0));
xDestDocSh->DoClose();
m_pDoc->DeleteTab(0);
}
CPPUNIT_TEST_FIXTURE(TestCopyPaste, testCopyPasteFormulasExternalDoc)
{
SfxMedium* pMedium = new SfxMedium(u"file:///source.fake"_ustr, StreamMode::STD_READWRITE);