1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <test/xmltesttools.hxx>
14 #include <vcl/mtfxmldump.hxx>
15 #include <sal/log.hxx>
19 OUString
convert(xmlChar
const * string
) {
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
)));
32 OString
oconvert(xmlChar
const * string
)
34 return reinterpret_cast<char const *>(string
);
39 XmlTestTools::XmlTestTools()
42 XmlTestTools::~XmlTestTools()
45 xmlDocUniquePtr
XmlTestTools::parseXml(utl::TempFile
const & aTempFile
)
47 SvFileStream
aFileStream(aTempFile
.GetURL(), StreamMode::READ
);
48 return parseXmlStream(&aFileStream
);
51 xmlDocUniquePtr
XmlTestTools::parseXmlStream(SvStream
* pStream
)
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
);
57 auto pCharBuffer
= reinterpret_cast<xmlChar
*>(pBuffer
.get());
58 SAL_INFO("test", "XmlTestTools::parseXmlStream: pBuffer is '" << pCharBuffer
<< "'");
59 return xmlDocUniquePtr(xmlParseDoc(pCharBuffer
));
62 xmlDocUniquePtr
XmlTestTools::dumpAndParse(MetafileXmlDump
& rDumper
, const GDIMetaFile
& rGDIMetaFile
)
64 SvMemoryStream aStream
;
65 rDumper
.dump(rGDIMetaFile
, aStream
);
66 aStream
.Seek(STREAM_SEEK_TO_BEGIN
);
67 return XmlTestTools::parseXmlStream(&aStream
);
70 xmlXPathObjectPtr
XmlTestTools::getXPathNode(const xmlDocUniquePtr
& pXmlDoc
, const OString
& rXPath
)
72 xmlXPathContextPtr pXmlXpathCtx
= xmlXPathNewContext(pXmlDoc
.get());
73 registerNamespaces(pXmlXpathCtx
);
74 xmlXPathObjectPtr pXmlXpathObj
= xmlXPathEvalExpression(BAD_CAST(rXPath
.getStr()), pXmlXpathCtx
);
75 xmlXPathFreeContext(pXmlXpathCtx
);
79 void XmlTestTools::registerNamespaces(xmlXPathContextPtr
& /*pXmlXpathCtx*/)
83 OUString
XmlTestTools::getXPath(const xmlDocUniquePtr
& pXmlDoc
, const OString
& rXPath
, const OString
& rAttribute
)
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())
92 xmlXPathFreeObject(pXmlObj
);
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
));
102 xmlXPathFreeObject(pXmlObj
);
106 OUString
XmlTestTools::getXPathContent(const xmlDocUniquePtr
& pXmlDoc
, const OString
& rXPath
)
108 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, rXPath
);
109 switch (pXmlObj
->type
)
111 case XPATH_UNDEFINED
:
112 CPPUNIT_FAIL("Undefined XPath type");
115 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
117 CPPUNIT_ASSERT_MESSAGE(
118 OString(OStringLiteral("In <") + pXmlDoc
->name
+ ">, XPath '" + rXPath
+ "' not found")
120 xmlXPathNodeSetGetLength(pXmlNodes
) > 0);
122 xmlNodePtr pXmlNode
= pXmlNodes
->nodeTab
[0];
123 xmlNodePtr pXmlChild
= pXmlNode
->children
;
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
);
134 auto boolVal
= pXmlObj
->boolval
;
135 xmlXPathFreeObject(pXmlObj
);
136 return boolVal
? OUString("true") : OUString("false");
140 auto floatVal
= pXmlObj
->floatval
;
141 xmlXPathFreeObject(pXmlObj
);
142 return OUString::number(floatVal
);
146 auto convertedVal
= convert(pXmlObj
->stringval
);
147 xmlXPathFreeObject(pXmlObj
);
152 case XPATH_LOCATIONSET
:
154 case XPATH_XSLT_TREE
:
155 xmlXPathFreeObject(pXmlObj
);
156 CPPUNIT_FAIL("Unsupported XPath type");
159 CPPUNIT_FAIL("Invalid XPath type");
162 void XmlTestTools::assertXPath(const xmlDocUniquePtr
& pXmlDoc
, const OString
& rXPath
)
164 getXPath(pXmlDoc
, rXPath
, ""); // it asserts that rXPath exists, and returns exactly one node
167 void XmlTestTools::assertXPath(const xmlDocUniquePtr
& pXmlDoc
, const OString
& rXPath
, const OString
& rAttribute
, const OUString
& rExpectedValue
)
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
);
174 void XmlTestTools::assertXPathAttrs(const xmlDocUniquePtr
& pXmlDoc
, const OString
& rXPath
,
175 const std::vector
<std::pair
<OString
, OUString
>>& aPairVector
)
177 for (auto& rPair
: aPairVector
)
179 assertXPath(pXmlDoc
, rXPath
, rPair
.first
, rPair
.second
);
183 void XmlTestTools::assertXPath(const xmlDocUniquePtr
& pXmlDoc
, const OString
& rXPath
, int nNumberOfNodes
)
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
);
192 void XmlTestTools::assertXPathContent(const xmlDocUniquePtr
& pXmlDoc
, const OString
& rXPath
, const OUString
& rContent
)
194 CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc
->name
+ ">, XPath contents of child does not match").getStr(), rContent
, getXPathContent(pXmlDoc
, rXPath
));
197 void XmlTestTools::assertXPathNSDef(const xmlDocUniquePtr
& pXmlDoc
, const OString
& rXPath
,
198 const OUString
& rNSPrefix
, const OUString
& rNSHref
)
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);
206 xmlNodePtr pXmlNode
= pXmlNodes
->nodeTab
[0];
208 for (xmlNsPtr pNamespace
= pXmlNode
->nsDef
; pNamespace
; pNamespace
= pNamespace
->next
)
210 if (!pNamespace
->prefix
)
213 CPPUNIT_ASSERT(pNamespace
->href
);
214 if (rNSPrefix
== convert(pNamespace
->prefix
) && rNSHref
== convert(pNamespace
->href
))
220 xmlXPathFreeObject(pXmlObj
);
221 CPPUNIT_ASSERT(bFound
);
224 void XmlTestTools::assertXPathChildren(const xmlDocUniquePtr
& pXmlDoc
, const OString
& rXPath
, int nNumberOfChildNodes
)
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
);
238 (void)nNumberOfChildNodes
;
242 void XmlTestTools::assertXPathNoAttribute(const xmlDocUniquePtr
& pXmlDoc
, const OString
& rXPath
, const OString
& rAttribute
)
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
);
254 int XmlTestTools::getXPathPosition(const xmlDocUniquePtr
& pXmlDoc
, const OString
& rXPath
, const OString
& rChildName
)
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(),
260 xmlXPathNodeSetGetLength(pXmlNodes
));
261 xmlNodePtr pXmlNode
= pXmlNodes
->nodeTab
[0];
264 for (xmlNodePtr pChild
= pXmlNode
->children
; pChild
; pChild
= pChild
->next
)
266 if (oconvert(pChild
->name
) == rChildName
)
273 xmlXPathFreeObject(pXmlObj
);
274 CPPUNIT_ASSERT_MESSAGE(OString(OStringLiteral("In <") + pXmlDoc
->name
+ ">, XPath '" + rXPath
275 + "' child '" + rChildName
+ "' not found")
281 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */