office-gobmx/test/source/xmltesttools.cxx
Miklos Vajna 51534ac2b9 tdf#127778 DOCX import: fix unexpected heading on non-first page ...
... when the first page has a heading

Regression from commit 17e51f427b (DOCX
import: first page header should always set default headers as well,
2014-11-21), the problem is around how to split a first + follow page
style on import, and then do the opposite on export.

This is described using a single section in OOXML, but Writer has 2 page
styles for this (unlike in case of the DOC filter). This means the
header margin has to be taken from one of these page styles. The above
commit tweaked the import, so the follow page style has the wanted
header margin, but this leads to incorrect layout.

Fix the problem by tweaking the export instead: it has random access to
the doc model, so it can take the header margin from the first page
style if needed, and then the import side can be reverted, leading to
correct layout.

Also remove some leftover debug code in test/, which was added in commit
5352d45dd4 (convert AnimationImport to
fast-parser APIs, 2020-02-18).

Change-Id: I4bbf7271f3a437e8432399bd1e32e9d24190a501
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/94013
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
2020-05-12 09:02:43 +02:00

281 lines
11 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 <test/xmltesttools.hxx>
#include <memory>
#include <vcl/mtfxmldump.hxx>
#include <sal/log.hxx>
namespace {
OUString convert(xmlChar const * string) {
OUString s;
CPPUNIT_ASSERT_MESSAGE(
"xmlChar string is not UTF-8",
rtl_convertStringToUString(
&s.pData, reinterpret_cast<char const *>(string), xmlStrlen(string),
RTL_TEXTENCODING_UTF8,
(RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
| RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
| RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)));
return s;
}
OString oconvert(xmlChar const * string)
{
return reinterpret_cast<char const *>(string);
}
}
XmlTestTools::XmlTestTools()
{}
XmlTestTools::~XmlTestTools()
{}
xmlDocUniquePtr XmlTestTools::parseXml(utl::TempFile const & aTempFile)
{
SvFileStream aFileStream(aTempFile.GetURL(), StreamMode::READ);
return parseXmlStream(&aFileStream);
}
xmlDocUniquePtr XmlTestTools::parseXmlStream(SvStream* pStream)
{
std::size_t nSize = pStream->remainingSize();
std::unique_ptr<sal_uInt8[]> pBuffer(new sal_uInt8[nSize + 1]);
pStream->ReadBytes(pBuffer.get(), nSize);
pBuffer[nSize] = 0;
auto pCharBuffer = reinterpret_cast<xmlChar*>(pBuffer.get());
SAL_INFO("test", "XmlTestTools::parseXmlStream: pBuffer is '" << pCharBuffer << "'");
return xmlDocUniquePtr(xmlParseDoc(pCharBuffer));
}
xmlDocUniquePtr XmlTestTools::dumpAndParse(MetafileXmlDump& rDumper, const GDIMetaFile& rGDIMetaFile)
{
SvMemoryStream aStream;
rDumper.dump(rGDIMetaFile, aStream);
aStream.Seek(STREAM_SEEK_TO_BEGIN);
return XmlTestTools::parseXmlStream(&aStream);
}
xmlXPathObjectPtr XmlTestTools::getXPathNode(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath)
{
xmlXPathContextPtr pXmlXpathCtx = xmlXPathNewContext(pXmlDoc.get());
registerNamespaces(pXmlXpathCtx);
xmlXPathObjectPtr pXmlXpathObj = xmlXPathEvalExpression(BAD_CAST(rXPath.getStr()), pXmlXpathCtx);
xmlXPathFreeContext(pXmlXpathCtx);
return pXmlXpathObj;
}
void XmlTestTools::registerNamespaces(xmlXPathContextPtr& /*pXmlXpathCtx*/)
{
}
OUString XmlTestTools::getXPath(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath, const OString& rAttribute)
{
CPPUNIT_ASSERT(pXmlDoc);
xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, rXPath);
xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' number of nodes is incorrect").getStr(),
1, xmlXPathNodeSetGetLength(pXmlNodes));
if (rAttribute.isEmpty())
{
xmlXPathFreeObject(pXmlObj);
return OUString();
}
xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
xmlChar * prop = xmlGetProp(pXmlNode, BAD_CAST(rAttribute.getStr()));
OString sAttAbsent = OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath
+ "' no attribute '" + rAttribute + "' exist";
CPPUNIT_ASSERT_MESSAGE(sAttAbsent.getStr(), prop);
OUString s(convert(prop));
xmlFree(prop);
xmlXPathFreeObject(pXmlObj);
return s;
}
OUString XmlTestTools::getXPathContent(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath)
{
xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, rXPath);
switch (pXmlObj->type)
{
case XPATH_UNDEFINED:
CPPUNIT_FAIL("Undefined XPath type");
case XPATH_NODESET:
{
xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
CPPUNIT_ASSERT_MESSAGE(
OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' not found")
.getStr(),
xmlXPathNodeSetGetLength(pXmlNodes) > 0);
xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
xmlNodePtr pXmlChild = pXmlNode->children;
OUString s;
while (pXmlChild && pXmlChild->type != XML_TEXT_NODE)
pXmlChild = pXmlChild->next;
if (pXmlChild && pXmlChild->type == XML_TEXT_NODE)
s = convert(pXmlChild->content);
xmlXPathFreeObject(pXmlObj);
return s;
}
case XPATH_BOOLEAN:
{
auto boolVal = pXmlObj->boolval;
xmlXPathFreeObject(pXmlObj);
return boolVal ? OUString("true") : OUString("false");
}
case XPATH_NUMBER:
{
auto floatVal = pXmlObj->floatval;
xmlXPathFreeObject(pXmlObj);
return OUString::number(floatVal);
}
case XPATH_STRING:
{
auto convertedVal = convert(pXmlObj->stringval);
xmlXPathFreeObject(pXmlObj);
return convertedVal;
}
case XPATH_POINT:
case XPATH_RANGE:
case XPATH_LOCATIONSET:
case XPATH_USERS:
case XPATH_XSLT_TREE:
xmlXPathFreeObject(pXmlObj);
CPPUNIT_FAIL("Unsupported XPath type");
}
CPPUNIT_FAIL("Invalid XPath type");
}
void XmlTestTools::assertXPath(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath)
{
getXPath(pXmlDoc, rXPath, ""); // it asserts that rXPath exists, and returns exactly one node
}
void XmlTestTools::assertXPath(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath, const OString& rAttribute, const OUString& rExpectedValue)
{
OUString aValue = getXPath(pXmlDoc, rXPath, rAttribute);
CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, attribute '" + rAttribute + "' of '" + rXPath + "' incorrect value.").getStr(),
rExpectedValue, aValue);
}
void XmlTestTools::assertXPathAttrs(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath,
const std::vector<std::pair<OString, OUString>>& aPairVector)
{
for (auto& rPair : aPairVector)
{
assertXPath(pXmlDoc, rXPath, rPair.first, rPair.second);
}
}
void XmlTestTools::assertXPath(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath, int nNumberOfNodes)
{
xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, rXPath);
xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' number of nodes is incorrect").getStr(),
nNumberOfNodes, xmlXPathNodeSetGetLength(pXmlNodes));
xmlXPathFreeObject(pXmlObj);
}
void XmlTestTools::assertXPathContent(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath, const OUString& rContent)
{
CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath contents of child does not match").getStr(), rContent, getXPathContent(pXmlDoc, rXPath));
}
void XmlTestTools::assertXPathNSDef(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath,
const OUString& rNSPrefix, const OUString& rNSHref)
{
xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, rXPath);
xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
CPPUNIT_ASSERT_MESSAGE(
OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' not found").getStr(),
xmlXPathNodeSetGetLength(pXmlNodes) > 0);
xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
bool bFound = false;
for (xmlNsPtr pNamespace = pXmlNode->nsDef; pNamespace; pNamespace = pNamespace->next)
{
if (!pNamespace->prefix)
continue;
CPPUNIT_ASSERT(pNamespace->href);
if (rNSPrefix == convert(pNamespace->prefix) && rNSHref == convert(pNamespace->href))
{
bFound = true;
break;
}
}
xmlXPathFreeObject(pXmlObj);
CPPUNIT_ASSERT(bFound);
}
void XmlTestTools::assertXPathChildren(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath, int nNumberOfChildNodes)
{
#if LIBXML_VERSION >= 20703 /* xmlChildElementCount is only available in libxml2 >= 2.7.3 */
xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, rXPath);
xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' number of nodes is incorrect").getStr(),
1, xmlXPathNodeSetGetLength(pXmlNodes));
xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' number of child-nodes is incorrect").getStr(),
nNumberOfChildNodes, static_cast<int>(xmlChildElementCount(pXmlNode)));
xmlXPathFreeObject(pXmlObj);
#else
(void)pXmlDoc;
(void)rXPath;
(void)nNumberOfChildNodes;
#endif
}
void XmlTestTools::assertXPathNoAttribute(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath, const OString& rAttribute)
{
xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, rXPath);
xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' number of nodes is incorrect").getStr(),
1, xmlXPathNodeSetGetLength(pXmlNodes));
xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' unexpected '" + rAttribute + "' attribute").getStr(),
static_cast<xmlChar*>(nullptr), xmlGetProp(pXmlNode, BAD_CAST(rAttribute.getStr())));
xmlXPathFreeObject(pXmlObj);
}
int XmlTestTools::getXPathPosition(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath, const OString& rChildName)
{
xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, rXPath);
xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' number of nodes is incorrect").getStr(),
1,
xmlXPathNodeSetGetLength(pXmlNodes));
xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
int nRet = 0;
bool bFound = false;
for (xmlNodePtr pChild = pXmlNode->children; pChild; pChild = pChild->next)
{
if (oconvert(pChild->name) == rChildName)
{
bFound = true;
break;
}
++nRet;
}
xmlXPathFreeObject(pXmlObj);
CPPUNIT_ASSERT_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath
+ "' child '" + rChildName + "' not found")
.getStr(),
bFound);
return nRet;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */