LibreOffice Module test (master)  1
xmltesttools.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include <test/xmltesttools.hxx>
11 
12 #include <memory>
13 
14 #include <vcl/mtfxmldump.hxx>
15 #include <sal/log.hxx>
16 
17 namespace {
18 
19 OUString convert(xmlChar const * string) {
20  OUString s;
21  CPPUNIT_ASSERT_MESSAGE(
22  "xmlChar string is not UTF-8",
23  rtl_convertStringToUString(
24  &s.pData, reinterpret_cast<char const *>(string), xmlStrlen(string),
25  RTL_TEXTENCODING_UTF8,
26  (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
27  | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
28  | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)));
29  return s;
30 }
31 
32 OString oconvert(xmlChar const * string)
33 {
34  return reinterpret_cast<char const *>(string);
35 }
36 
37 }
38 
40 {}
41 
43 {}
44 
46 {
47  SvFileStream aFileStream(aTempFile.GetURL(), StreamMode::READ);
48  return parseXmlStream(&aFileStream);
49 }
50 
52 {
53  std::size_t nSize = pStream->remainingSize();
54  std::unique_ptr<sal_uInt8[]> pBuffer(new sal_uInt8[nSize + 1]);
55  pStream->ReadBytes(pBuffer.get(), nSize);
56  pBuffer[nSize] = 0;
57  auto pCharBuffer = reinterpret_cast<xmlChar*>(pBuffer.get());
58  SAL_INFO("test", "XmlTestTools::parseXmlStream: pBuffer is '" << pCharBuffer << "'");
59  return xmlDocUniquePtr(xmlParseDoc(pCharBuffer));
60 }
61 
63 {
64  SvMemoryStream aStream;
65  rDumper.dump(rGDIMetaFile, aStream);
66  aStream.Seek(STREAM_SEEK_TO_BEGIN);
67  return XmlTestTools::parseXmlStream(&aStream);
68 }
69 
70 xmlXPathObjectPtr XmlTestTools::getXPathNode(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath)
71 {
72  xmlXPathContextPtr pXmlXpathCtx = xmlXPathNewContext(pXmlDoc.get());
73  registerNamespaces(pXmlXpathCtx);
74  xmlXPathObjectPtr pXmlXpathObj = xmlXPathEvalExpression(BAD_CAST(rXPath.getStr()), pXmlXpathCtx);
75  xmlXPathFreeContext(pXmlXpathCtx);
76  return pXmlXpathObj;
77 }
78 
79 void XmlTestTools::registerNamespaces(xmlXPathContextPtr& /*pXmlXpathCtx*/)
80 {
81 }
82 
83 OUString XmlTestTools::getXPath(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath, const OString& rAttribute)
84 {
85  CPPUNIT_ASSERT(pXmlDoc);
86  xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, rXPath);
87  xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
88  CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' number of nodes is incorrect").getStr(),
89  1, xmlXPathNodeSetGetLength(pXmlNodes));
90  if (rAttribute.isEmpty())
91  {
92  xmlXPathFreeObject(pXmlObj);
93  return OUString();
94  }
95  xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
96  xmlChar * prop = xmlGetProp(pXmlNode, BAD_CAST(rAttribute.getStr()));
97  OString sAttAbsent = OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath
98  + "' no attribute '" + rAttribute + "' exist";
99  CPPUNIT_ASSERT_MESSAGE(sAttAbsent.getStr(), prop);
100  OUString s(convert(prop));
101  xmlFree(prop);
102  xmlXPathFreeObject(pXmlObj);
103  return s;
104 }
105 
106 OUString XmlTestTools::getXPathContent(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath)
107 {
108  xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, rXPath);
109  switch (pXmlObj->type)
110  {
111  case XPATH_UNDEFINED:
112  CPPUNIT_FAIL("Undefined XPath type");
113  case XPATH_NODESET:
114  {
115  xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
116 
117  CPPUNIT_ASSERT_MESSAGE(
118  OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' not found")
119  .getStr(),
120  xmlXPathNodeSetGetLength(pXmlNodes) > 0);
121 
122  xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
123  xmlNodePtr pXmlChild = pXmlNode->children;
124  OUString s;
125  while (pXmlChild && pXmlChild->type != XML_TEXT_NODE)
126  pXmlChild = pXmlChild->next;
127  if (pXmlChild && pXmlChild->type == XML_TEXT_NODE)
128  s = convert(pXmlChild->content);
129  xmlXPathFreeObject(pXmlObj);
130  return s;
131  }
132  case XPATH_BOOLEAN:
133  {
134  auto boolVal = pXmlObj->boolval;
135  xmlXPathFreeObject(pXmlObj);
136  return boolVal ? OUString("true") : OUString("false");
137  }
138  case XPATH_NUMBER:
139  {
140  auto floatVal = pXmlObj->floatval;
141  xmlXPathFreeObject(pXmlObj);
142  return OUString::number(floatVal);
143  }
144  case XPATH_STRING:
145  {
146  auto convertedVal = convert(pXmlObj->stringval);
147  xmlXPathFreeObject(pXmlObj);
148  return convertedVal;
149  }
150  case XPATH_POINT:
151  case XPATH_RANGE:
152  case XPATH_LOCATIONSET:
153  case XPATH_USERS:
154  case XPATH_XSLT_TREE:
155  xmlXPathFreeObject(pXmlObj);
156  CPPUNIT_FAIL("Unsupported XPath type");
157  }
158 
159  CPPUNIT_FAIL("Invalid XPath type");
160 }
161 
162 void XmlTestTools::assertXPath(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath)
163 {
164  getXPath(pXmlDoc, rXPath, ""); // it asserts that rXPath exists, and returns exactly one node
165 }
166 
167 void XmlTestTools::assertXPath(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath, const OString& rAttribute, const OUString& rExpectedValue)
168 {
169  OUString aValue = getXPath(pXmlDoc, rXPath, rAttribute);
170  CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, attribute '" + rAttribute + "' of '" + rXPath + "' incorrect value.").getStr(),
171  rExpectedValue, aValue);
172 }
173 
174 void XmlTestTools::assertXPathAttrs(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath,
175  const std::vector<std::pair<OString, OUString>>& aPairVector)
176 {
177  for (auto& rPair : aPairVector)
178  {
179  assertXPath(pXmlDoc, rXPath, rPair.first, rPair.second);
180  }
181 }
182 
183 void XmlTestTools::assertXPath(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath, int nNumberOfNodes)
184 {
185  xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, rXPath);
186  xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
187  CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' number of nodes is incorrect").getStr(),
188  nNumberOfNodes, xmlXPathNodeSetGetLength(pXmlNodes));
189  xmlXPathFreeObject(pXmlObj);
190 }
191 
192 void XmlTestTools::assertXPathContent(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath, const OUString& rContent)
193 {
194  CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath contents of child does not match").getStr(), rContent, getXPathContent(pXmlDoc, rXPath));
195 }
196 
197 void XmlTestTools::assertXPathNSDef(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath,
198  std::u16string_view rNSPrefix, std::u16string_view rNSHref)
199 {
200  xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, rXPath);
201  xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
202  CPPUNIT_ASSERT_MESSAGE(
203  OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' not found").getStr(),
204  xmlXPathNodeSetGetLength(pXmlNodes) > 0);
205 
206  xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
207  bool bFound = false;
208  for (xmlNsPtr pNamespace = pXmlNode->nsDef; pNamespace; pNamespace = pNamespace->next)
209  {
210  if (!pNamespace->prefix)
211  continue;
212 
213  CPPUNIT_ASSERT(pNamespace->href);
214  if (rNSPrefix == convert(pNamespace->prefix) && rNSHref == convert(pNamespace->href))
215  {
216  bFound = true;
217  break;
218  }
219  }
220  xmlXPathFreeObject(pXmlObj);
221  CPPUNIT_ASSERT(bFound);
222 }
223 
224 void XmlTestTools::assertXPathChildren(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath, int nNumberOfChildNodes)
225 {
226 #if LIBXML_VERSION >= 20703 /* xmlChildElementCount is only available in libxml2 >= 2.7.3 */
227  xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, rXPath);
228  xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
229  CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' number of nodes is incorrect").getStr(),
230  1, xmlXPathNodeSetGetLength(pXmlNodes));
231  xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
232  CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' number of child-nodes is incorrect").getStr(),
233  nNumberOfChildNodes, static_cast<int>(xmlChildElementCount(pXmlNode)));
234  xmlXPathFreeObject(pXmlObj);
235 #else
236  (void)pXmlDoc;
237  (void)rXPath;
238  (void)nNumberOfChildNodes;
239 #endif
240 }
241 
242 void XmlTestTools::assertXPathNoAttribute(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath, const OString& rAttribute)
243 {
244  xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, rXPath);
245  xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
246  CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' number of nodes is incorrect").getStr(),
247  1, xmlXPathNodeSetGetLength(pXmlNodes));
248  xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
249  CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' unexpected '" + rAttribute + "' attribute").getStr(),
250  static_cast<xmlChar*>(nullptr), xmlGetProp(pXmlNode, BAD_CAST(rAttribute.getStr())));
251  xmlXPathFreeObject(pXmlObj);
252 }
253 
254 int XmlTestTools::getXPathPosition(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath, std::string_view rChildName)
255 {
256  xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, rXPath);
257  xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
258  CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath + "' number of nodes is incorrect").getStr(),
259  1,
260  xmlXPathNodeSetGetLength(pXmlNodes));
261  xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
262  int nRet = 0;
263  bool bFound = false;
264  for (xmlNodePtr pChild = pXmlNode->children; pChild; pChild = pChild->next)
265  {
266  if (oconvert(pChild->name) == rChildName)
267  {
268  bFound = true;
269  break;
270  }
271  ++nRet;
272  }
273  xmlXPathFreeObject(pXmlObj);
274  CPPUNIT_ASSERT_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc->name + ">, XPath '" + rXPath
275  + "' child '" + rChildName + "' not found")
276  .getStr(),
277  bFound);
278  return nRet;
279 }
280 
281 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static xmlDocUniquePtr dumpAndParse(MetafileXmlDump &rDumper, const GDIMetaFile &rGDIMetaFile)
void dump(const GDIMetaFile &rMetaFile, SvStream &rStream)
std::unique_ptr< xmlDoc, xmlDocDeleter > xmlDocUniquePtr
Definition: xmldocptr.hxx:18
virtual ~XmlTestTools()
sal_uInt64 Seek(sal_uInt64 nPos)
void assertXPathNSDef(const xmlDocUniquePtr &pXmlDoc, const OString &rXPath, std::u16string_view rNSPrefix, std::u16string_view rNSHref)
Assert that rXPath exists and it has an rNSPrefix=rNSHref namespace definition.
static xmlDocUniquePtr parseXml(utl::TempFile const &aTempFile)
static xmlDocUniquePtr parseXmlStream(SvStream *pStream)
Return xmlDocPtr representation of the XML stream read from pStream.
sal_uInt64 remainingSize()
void assertXPathChildren(const xmlDocUniquePtr &pXmlDoc, const OString &rXPath, int nNumberOfChildNodes)
Assert that rXPath exists, and has exactly nNumberOfChildNodes child nodes.
int getXPathPosition(const xmlDocUniquePtr &pXmlDoc, const OString &rXPath, std::string_view rChildName)
Get the position of the child named rName of the parent node specified by rXPath. ...
OUString const & GetURL() const
#define STREAM_SEEK_TO_BEGIN
void assertXPathAttrs(const xmlDocUniquePtr &pXmlDoc, const OString &rXPath, const std::vector< std::pair< OString, OUString >> &aPairVector)
virtual void registerNamespaces(xmlXPathContextPtr &pXmlXpathCtx)
std::size_t ReadBytes(void *pData, std::size_t nSize)
convert
void assertXPathNoAttribute(const xmlDocUniquePtr &pXmlDoc, const OString &rXPath, const OString &rAttribute)
Assert that rXPath exists, has exactly 1 result set nodes and does not have an attribute named rAttri...
void assertXPath(const xmlDocUniquePtr &pXmlDoc, const OString &rXPath)
Assert that rXPath exists, and returns exactly one node.
void assertXPathContent(const xmlDocUniquePtr &pXmlDoc, const OString &rXPath, const OUString &rContent)
Assert that rXPath exists, and its content equals rContent.
unsigned char sal_uInt8
#define SAL_INFO(area, stream)
xmlXPathObjectPtr getXPathNode(const xmlDocUniquePtr &pXmlDoc, const OString &rXPath)
OUString getXPath(const xmlDocUniquePtr &pXmlDoc, const OString &rXPath, const OString &rAttribute)
Same as the assertXPath(), but don't assert: return the string instead.
OUString getXPathContent(const xmlDocUniquePtr &pXmlDoc, const OString &rXPath)
Same as the assertXPathContent(), but don't assert: return the string instead.
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo