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 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <rtl/ref.hxx> 21 #include <sal/log.hxx> 22 #include <sax/fastattribs.hxx> 23 #include <comphelper/seqstream.hxx> 24 #include <cppuhelper/implbase.hxx> 25 #include <cppunit/extensions/HelperMacros.h> 26 #include <cppunit/plugin/TestPlugIn.h> 27 #include <test/bootstrapfixture.hxx> 28 29 #include <com/sun/star/xml/dom/DocumentBuilder.hpp> 30 #include <com/sun/star/xml/sax/FastToken.hpp> 31 #include <com/sun/star/xml/sax/XSAXSerializable.hpp> 32 #include <com/sun/star/xml/sax/XFastSAXSerializable.hpp> 33 #include <com/sun/star/xml/sax/SAXParseException.hpp> 34 35 using namespace ::comphelper; 36 using namespace ::com::sun::star; 37 using namespace ::com::sun::star::uno; 38 using css::xml::dom::XDocumentBuilder; 39 40 namespace 41 { 42 // valid xml 43 const char validTestFile[] = 44 "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \ 45 <office:document-content \ 46 xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" \ 47 xmlns:xlink=\"http://www.w3.org/1999/xlink\" \ 48 office:version=\"1.0\"> \ 49 <office:scripts/> \ 50 <xlink:test/> \ 51 <office:automatic-styles teststyle=\"test\"/> \ 52 <moretest/> \ 53 some text \303\266\303\244\303\274 \ 54 </office:document-content> \ 55 "; 56 57 // generates a warning: unknown xml:space 58 // value 59 const char warningTestFile[] = 60 "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \ 61 <office:document-content \ 62 xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" \ 63 xml:space=\"blah\" \ 64 xmlns:xlink=\"http://www.w3.org/1999/xlink\" \ 65 office:version=\"1.0\"> \ 66 <office:scripts/> \ 67 <xlink:test/> \ 68 <office:automatic-styles teststyle=\"test\"/> \ 69 <moretest/> \ 70 some text \303\266\303\244\303\274 \ 71 </office:document-content> \ 72 "; 73 74 // <?xml not at start of file 75 const char errorTestFile[] = 76 " <?xml version=\"1.0\" encoding=\"UTF-8\"?> \ 77 <office:document-content \ 78 xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" \ 79 office:version=\"1.0\"> \ 80 <office:scripts/> \ 81 <office:automatic-styles/> \ 82 </office:document-content> \ 83 "; 84 85 struct ErrorHandler 86 : public ::cppu::WeakImplHelper< xml::sax::XErrorHandler > 87 { 88 sal_uInt32 mnErrCount; 89 // sal_uInt32 mnFatalCount; // No fatal error counter, as lib2xml doesn't distinguish between error and fatal error 90 // (see See xmlFatalErrMsg from lib2xml/parse.c and __xmlRaiseError from lib2xml/error.c) 91 sal_uInt32 mnWarnCount; 92 noErrors__anond624b4700111::ErrorHandler93 bool noErrors() const { return !mnErrCount /*&& !mnFatalCount*/ && !mnWarnCount; } 94 ErrorHandler__anond624b4700111::ErrorHandler95 ErrorHandler() : mnErrCount(0), /*mnFatalCount(0),*/ mnWarnCount(0) 96 {} 97 error__anond624b4700111::ErrorHandler98 virtual void SAL_CALL error( const uno::Any& ) override 99 { 100 ++mnErrCount; 101 } 102 103 // Just implement FatalError function as it is in XErrorHandler 104 // This function is never used, as lib2xml doesn't distinguish between error and fatalerror and calls error functions in both cases fatalError__anond624b4700111::ErrorHandler105 virtual void SAL_CALL fatalError( const uno::Any& ) override 106 { 107 //++mnFatalCount; 108 } 109 warning__anond624b4700111::ErrorHandler110 virtual void SAL_CALL warning( const uno::Any& ) override 111 { 112 ++mnWarnCount; 113 } 114 }; 115 116 struct DocumentHandler 117 : public ::cppu::WeakImplHelper< xml::sax::XFastDocumentHandler > 118 { 119 // XFastContextHandler startFastElement__anond624b4700111::DocumentHandler120 virtual void SAL_CALL startFastElement( ::sal_Int32 Element, const uno::Reference< xml::sax::XFastAttributeList >& ) override 121 { 122 SAL_INFO( 123 "unoxml", 124 "Seen element: " << (Element & 0xFFFF) << " with namespace " 125 << (Element & 0xFFFF0000)); 126 } 127 startUnknownElement__anond624b4700111::DocumentHandler128 virtual void SAL_CALL startUnknownElement( const OUString& , const OUString& , const uno::Reference< xml::sax::XFastAttributeList >& ) override 129 { 130 } 131 endFastElement__anond624b4700111::DocumentHandler132 virtual void SAL_CALL endFastElement( ::sal_Int32 ) override 133 { 134 } 135 endUnknownElement__anond624b4700111::DocumentHandler136 virtual void SAL_CALL endUnknownElement( const OUString&, const OUString& ) override 137 { 138 } 139 createFastChildContext__anond624b4700111::DocumentHandler140 virtual uno::Reference< xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 , const uno::Reference< xml::sax::XFastAttributeList >& ) override 141 { 142 return this; 143 } 144 createUnknownChildContext__anond624b4700111::DocumentHandler145 virtual uno::Reference< xml::sax::XFastContextHandler > SAL_CALL createUnknownChildContext( const OUString& , const OUString& , const uno::Reference< xml::sax::XFastAttributeList >& ) override 146 { 147 return this; 148 } 149 characters__anond624b4700111::DocumentHandler150 virtual void SAL_CALL characters( const OUString& ) override 151 { 152 } 153 154 // XFastDocumentHandler startDocument__anond624b4700111::DocumentHandler155 virtual void SAL_CALL startDocument( ) override 156 { 157 } 158 endDocument__anond624b4700111::DocumentHandler159 virtual void SAL_CALL endDocument( ) override 160 { 161 } 162 processingInstruction__anond624b4700111::DocumentHandler163 virtual void SAL_CALL processingInstruction( const OUString& /*rTarget*/, const OUString& /*rData*/ ) override 164 { 165 } 166 setDocumentLocator__anond624b4700111::DocumentHandler167 virtual void SAL_CALL setDocumentLocator( const uno::Reference< xml::sax::XLocator >& ) override 168 { 169 } 170 }; 171 172 struct TokenHandler : public sax_fastparser::FastTokenHandlerBase 173 { getTokenFromUTF8__anond624b4700111::TokenHandler174 virtual ::sal_Int32 SAL_CALL getTokenFromUTF8( const uno::Sequence< ::sal_Int8 >& Identifier ) override 175 { 176 return Identifier.hasElements() ? Identifier[0] : 0; 177 } 178 getUTF8Identifier__anond624b4700111::TokenHandler179 virtual uno::Sequence< ::sal_Int8 > SAL_CALL getUTF8Identifier( ::sal_Int32 ) override 180 { 181 CPPUNIT_ASSERT_MESSAGE( "TokenHandler::getUTF8Identifier() unexpected call", 182 false ); 183 return uno::Sequence<sal_Int8>(); 184 } 185 getTokenDirect__anond624b4700111::TokenHandler186 virtual sal_Int32 getTokenDirect( const char * /* pToken */, sal_Int32 /* nLength */ ) const override 187 { 188 return -1; 189 } 190 }; 191 192 struct BasicTest : public test::BootstrapFixture 193 { 194 uno::Reference<XDocumentBuilder> mxDomBuilder; 195 rtl::Reference<ErrorHandler> mxErrHandler; 196 rtl::Reference<SequenceInputStream> mxValidInStream; 197 rtl::Reference<SequenceInputStream> mxWarningInStream; 198 rtl::Reference<SequenceInputStream> mxErrorInStream; 199 setUp__anond624b4700111::BasicTest200 virtual void setUp() override 201 { 202 test::BootstrapFixture::setUp(); 203 204 mxErrHandler.set( new ErrorHandler() ); 205 uno::Reference<XDocumentBuilder> xDB( getMultiServiceFactory()->createInstance("com.sun.star.xml.dom.DocumentBuilder"), uno::UNO_QUERY_THROW ); 206 mxDomBuilder.set( xDB ); 207 mxValidInStream.set( new SequenceInputStream(css::uno::Sequence<sal_Int8>(reinterpret_cast<sal_Int8 const *>(validTestFile), SAL_N_ELEMENTS(validTestFile))) ); 208 mxWarningInStream.set( new SequenceInputStream(css::uno::Sequence<sal_Int8>(reinterpret_cast<sal_Int8 const *>(warningTestFile), SAL_N_ELEMENTS(warningTestFile))) ); 209 mxErrorInStream.set( new SequenceInputStream(css::uno::Sequence<sal_Int8>(reinterpret_cast<sal_Int8 const *>(errorTestFile), SAL_N_ELEMENTS(errorTestFile))) ); 210 mxDomBuilder->setErrorHandler(mxErrHandler); 211 } 212 validInputTest__anond624b4700111::BasicTest213 void validInputTest() 214 { 215 try 216 { 217 CPPUNIT_ASSERT_MESSAGE("Valid input file did not result in XDocument #1", 218 mxDomBuilder->parse(mxValidInStream).is()); 219 CPPUNIT_ASSERT_MESSAGE("Valid input file resulted in parse errors", 220 mxErrHandler->noErrors()); 221 } 222 catch (const css::xml::sax::SAXParseException&) 223 { 224 CPPUNIT_ASSERT_MESSAGE("Valid input file did not result in XDocument (exception thrown)", false); 225 } 226 } 227 warningInputTest__anond624b4700111::BasicTest228 void warningInputTest() 229 { 230 try 231 { 232 // We DON'T expect exception here, as mxWarningInStream is valid XML Doc 233 CPPUNIT_ASSERT_MESSAGE("Valid input file did not result in XDocument #2", 234 mxDomBuilder->parse(mxWarningInStream).is()); 235 } 236 catch (const css::xml::sax::SAXParseException& ) 237 { 238 CPPUNIT_ASSERT_MESSAGE("Valid input file did not result in XDocument #2 (exception thrown)", false); 239 } 240 CPPUNIT_ASSERT_MESSAGE("No parse warnings in unclean input file", 241 mxErrHandler->mnWarnCount); 242 CPPUNIT_ASSERT_MESSAGE("No parse warnings in unclean input file", 243 !mxErrHandler->mnErrCount /*&& !mxErrHandler->mnFatalCount*/); 244 } 245 errorInputTest__anond624b4700111::BasicTest246 void errorInputTest() 247 { 248 try 249 { 250 // We expect exception here, as mxErrorInStream is invalid XML Doc 251 CPPUNIT_ASSERT_MESSAGE("Invalid input file result in XDocument #2!", 252 !mxDomBuilder->parse(mxErrorInStream).is()); 253 CPPUNIT_ASSERT_MESSAGE("No exception is thrown in unclean input file", false); 254 } 255 catch (const css::xml::sax::SAXParseException&) 256 { 257 // It's OK to catch an exception here as we parse incorrect XML file 258 } 259 CPPUNIT_ASSERT_MESSAGE("No parse errors in unclean input file", 260 !mxErrHandler->mnWarnCount); 261 CPPUNIT_ASSERT_MESSAGE("No parse errors in unclean input file", 262 mxErrHandler->mnErrCount /*&& !mxErrHandler->mnFatalCount*/); 263 } 264 265 // Change the following lines only, if you add, remove or rename 266 // member functions of the current class, 267 // because these macros are need by auto register mechanism. 268 CPPUNIT_TEST_SUITE(BasicTest); 269 CPPUNIT_TEST(validInputTest); 270 CPPUNIT_TEST(warningInputTest); 271 CPPUNIT_TEST(errorInputTest); 272 CPPUNIT_TEST_SUITE_END(); 273 }; 274 275 struct SerializerTest : public test::BootstrapFixture 276 { 277 uno::Reference<XDocumentBuilder> mxDomBuilder; 278 rtl::Reference<ErrorHandler> mxErrHandler; 279 rtl::Reference<SequenceInputStream> mxInStream; 280 rtl::Reference<DocumentHandler> mxHandler; 281 rtl::Reference<TokenHandler> mxTokHandler; 282 uno::Sequence< beans::Pair< OUString, sal_Int32 > > maRegisteredNamespaces; 283 setUp__anond624b4700111::SerializerTest284 void setUp() override 285 { 286 test::BootstrapFixture::setUp(); 287 288 mxErrHandler.set( new ErrorHandler() ); 289 uno::Reference<XDocumentBuilder> xDB( getMultiServiceFactory()->createInstance("com.sun.star.xml.dom.DocumentBuilder"), uno::UNO_QUERY_THROW ); 290 mxDomBuilder.set( xDB ); 291 mxInStream.set( new SequenceInputStream(css::uno::Sequence<sal_Int8>(reinterpret_cast<sal_Int8 const *>(validTestFile), SAL_N_ELEMENTS(validTestFile))) ); 292 mxDomBuilder->setErrorHandler(mxErrHandler); 293 mxHandler.set( new DocumentHandler ); 294 mxTokHandler.set( new TokenHandler ); 295 296 maRegisteredNamespaces.realloc(2); 297 maRegisteredNamespaces[0] = beans::make_Pair( 298 OUString( "urn:oasis:names:tc:opendocument:xmlns:office:1.0" ), 299 xml::sax::FastToken::NAMESPACE); 300 maRegisteredNamespaces[1] = beans::make_Pair( 301 OUString( "http://www.w3.org/1999/xlink" ), 302 2*xml::sax::FastToken::NAMESPACE); 303 } 304 serializerTest__anond624b4700111::SerializerTest305 void serializerTest () 306 { 307 try 308 { 309 uno::Reference< xml::dom::XDocument > xDoc = 310 mxDomBuilder->parse(mxInStream); 311 CPPUNIT_ASSERT_MESSAGE("Valid input file did not result in XDocument", 312 xDoc.is()); 313 CPPUNIT_ASSERT_MESSAGE("Valid input file resulted in parse errors", 314 mxErrHandler->noErrors()); 315 316 uno::Reference< xml::sax::XSAXSerializable > xSaxSerializer( 317 xDoc, uno::UNO_QUERY); 318 CPPUNIT_ASSERT_MESSAGE("XSAXSerializable not supported", 319 xSaxSerializer.is()); 320 321 uno::Reference< xml::sax::XFastSAXSerializable > xFastSaxSerializer( 322 xDoc, uno::UNO_QUERY); 323 CPPUNIT_ASSERT_MESSAGE("XFastSAXSerializable not supported", 324 xSaxSerializer.is()); 325 326 xFastSaxSerializer->fastSerialize(mxHandler, 327 mxTokHandler, 328 uno::Sequence< beans::StringPair >(), 329 maRegisteredNamespaces); 330 } 331 catch (const css::xml::sax::SAXParseException&) 332 { 333 CPPUNIT_ASSERT_MESSAGE("Valid input file did not result in XDocument (exception thrown)", false); 334 } 335 } 336 337 // Change the following lines only, if you add, remove or rename 338 // member functions of the current class, 339 // because these macros are need by auto register mechanism. 340 341 CPPUNIT_TEST_SUITE(SerializerTest); 342 CPPUNIT_TEST(serializerTest); 343 CPPUNIT_TEST_SUITE_END(); 344 }; 345 346 CPPUNIT_TEST_SUITE_REGISTRATION(BasicTest); 347 CPPUNIT_TEST_SUITE_REGISTRATION(SerializerTest); 348 } 349 350 // this macro creates an empty function, which will called by the RegisterAllFunctions() 351 // to let the user the possibility to also register some functions by hand. 352 CPPUNIT_PLUGIN_IMPLEMENT(); 353 354 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 355