/* -*- 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/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::comphelper; using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using css::xml::dom::XDocumentBuilder; using css::xml::dom::DocumentBuilder; namespace { // valid xml static const char validTestFile[] = " \ \ \ \ \ \ some text \303\266\303\244\303\274 \ \ "; // generates a warning: unknown xml:space // value static const char warningTestFile[] = " \ \ \ \ \ \ some text \303\266\303\244\303\274 \ \ "; // \ \ \ \ \ "; struct ErrorHandler : public ::cppu::WeakImplHelper< xml::sax::XErrorHandler > { sal_uInt32 mnErrCount; // sal_uInt32 mnFatalCount; // No fatal error counter, as lib2xml doesn't distinguish between error and fatal error // (see See xmlFatalErrMsg from lib2xml/parse.c and __xmlRaiseError from lib2xml/error.c) sal_uInt32 mnWarnCount; bool noErrors() const { return !mnErrCount /*&& !mnFatalCount*/ && !mnWarnCount; } ErrorHandler() : mnErrCount(0), /*mnFatalCount(0),*/ mnWarnCount(0) {} virtual void SAL_CALL error( const uno::Any& ) override { ++mnErrCount; } // Just implement FatalError function as it is in XErrorHandler // This function is never used, as lib2xml doesn't distinguish between error and fatalerror and calls error functions in both cases virtual void SAL_CALL fatalError( const uno::Any& ) override { //++mnFatalCount; } virtual void SAL_CALL warning( const uno::Any& ) override { ++mnWarnCount; } }; struct DocumentHandler : public ::cppu::WeakImplHelper< xml::sax::XFastDocumentHandler > { // XFastContextHandler virtual void SAL_CALL startFastElement( ::sal_Int32 Element, const uno::Reference< xml::sax::XFastAttributeList >& ) override { SAL_INFO( "unoxml", "Seen element: " << (Element & 0xFFFF) << " with namespace " << (Element & 0xFFFF0000)); } virtual void SAL_CALL startUnknownElement( const OUString& , const OUString& , const uno::Reference< xml::sax::XFastAttributeList >& ) override { } virtual void SAL_CALL endFastElement( ::sal_Int32 ) override { } virtual void SAL_CALL endUnknownElement( const OUString&, const OUString& ) override { } virtual uno::Reference< xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 , const uno::Reference< xml::sax::XFastAttributeList >& ) override { return this; } virtual uno::Reference< xml::sax::XFastContextHandler > SAL_CALL createUnknownChildContext( const OUString& , const OUString& , const uno::Reference< xml::sax::XFastAttributeList >& ) override { return this; } virtual void SAL_CALL characters( const OUString& ) override { } // XFastDocumentHandler virtual void SAL_CALL startDocument( ) override { } virtual void SAL_CALL endDocument( ) override { } virtual void SAL_CALL processingInstruction( const OUString& /*rTarget*/, const OUString& /*rData*/ ) override { } virtual void SAL_CALL setDocumentLocator( const uno::Reference< xml::sax::XLocator >& ) override { } }; struct TokenHandler : public ::cppu::WeakImplHelper< xml::sax::XFastTokenHandler > { virtual ::sal_Int32 SAL_CALL getTokenFromUTF8( const uno::Sequence< ::sal_Int8 >& Identifier ) override { return Identifier.getLength() ? Identifier[0] : 0; } virtual uno::Sequence< ::sal_Int8 > SAL_CALL getUTF8Identifier( ::sal_Int32 ) override { CPPUNIT_ASSERT_MESSAGE( "TokenHandler::getUTF8Identifier() unexpected call", false ); return uno::Sequence(); } }; struct BasicTest : public test::BootstrapFixture { uno::Reference mxDomBuilder; rtl::Reference mxErrHandler; rtl::Reference mxValidInStream; rtl::Reference mxWarningInStream; rtl::Reference mxErrorInStream; virtual void setUp() override { test::BootstrapFixture::setUp(); mxErrHandler.set( new ErrorHandler() ); uno::Reference xDB( getMultiServiceFactory()->createInstance("com.sun.star.xml.dom.DocumentBuilder"), uno::UNO_QUERY_THROW ); mxDomBuilder.set( xDB ); mxValidInStream.set( new SequenceInputStream(css::uno::Sequence(reinterpret_cast(validTestFile), SAL_N_ELEMENTS(validTestFile))) ); mxWarningInStream.set( new SequenceInputStream(css::uno::Sequence(reinterpret_cast(warningTestFile), SAL_N_ELEMENTS(warningTestFile))) ); mxErrorInStream.set( new SequenceInputStream(css::uno::Sequence(reinterpret_cast(errorTestFile), SAL_N_ELEMENTS(errorTestFile))) ); mxDomBuilder->setErrorHandler(mxErrHandler.get()); } void validInputTest() { try { CPPUNIT_ASSERT_MESSAGE("Valid input file did not result in XDocument #1", mxDomBuilder->parse( uno::Reference( mxValidInStream.get())).is()); CPPUNIT_ASSERT_MESSAGE("Valid input file resulted in parse errors", mxErrHandler->noErrors()); } catch (const css::xml::sax::SAXParseException&) { CPPUNIT_ASSERT_MESSAGE("Valid input file did not result in XDocument (exception thrown)", false); } } void warningInputTest() { try { // We DONT expect exception here, as mxWarningInStream is valid XML Doc CPPUNIT_ASSERT_MESSAGE("Valid input file did not result in XDocument #2", mxDomBuilder->parse( uno::Reference( mxWarningInStream.get())).is()); } catch (const css::xml::sax::SAXParseException& ) { CPPUNIT_ASSERT_MESSAGE("Valid input file did not result in XDocument #2 (exception thrown)", false); } CPPUNIT_ASSERT_MESSAGE("No parse warnings in unclean input file", mxErrHandler->mnWarnCount && !mxErrHandler->mnErrCount /*&& !mxErrHandler->mnFatalCount*/); } void errorInputTest() { try { // We expect exception here, as mxErrorInStream is invalid XML Doc CPPUNIT_ASSERT_MESSAGE("Invalid input file result in XDocument #2!", !mxDomBuilder->parse( uno::Reference( mxErrorInStream.get())).is()); CPPUNIT_ASSERT_MESSAGE("No exception is thrown in unclean input file", false); } catch (const css::xml::sax::SAXParseException&) { // It's OK to catch an exception here as we parse incorrect XML file } CPPUNIT_ASSERT_MESSAGE("No parse errors in unclean input file", !mxErrHandler->mnWarnCount && mxErrHandler->mnErrCount /*&& !mxErrHandler->mnFatalCount*/); } // Change the following lines only, if you add, remove or rename // member functions of the current class, // because these macros are need by auto register mechanism. CPPUNIT_TEST_SUITE(BasicTest); CPPUNIT_TEST(validInputTest); CPPUNIT_TEST(warningInputTest); CPPUNIT_TEST(errorInputTest); CPPUNIT_TEST_SUITE_END(); }; struct SerializerTest : public test::BootstrapFixture { uno::Reference mxDomBuilder; rtl::Reference mxErrHandler; rtl::Reference mxInStream; rtl::Reference mxHandler; rtl::Reference mxTokHandler; uno::Sequence< beans::Pair< OUString, sal_Int32 > > maRegisteredNamespaces; void setUp() override { test::BootstrapFixture::setUp(); mxErrHandler.set( new ErrorHandler() ); uno::Reference xDB( getMultiServiceFactory()->createInstance("com.sun.star.xml.dom.DocumentBuilder"), uno::UNO_QUERY_THROW ); mxDomBuilder.set( xDB ); mxInStream.set( new SequenceInputStream(css::uno::Sequence(reinterpret_cast(validTestFile), SAL_N_ELEMENTS(validTestFile))) ); mxDomBuilder->setErrorHandler(mxErrHandler.get()); mxHandler.set( new DocumentHandler ); mxTokHandler.set( new TokenHandler ); maRegisteredNamespaces.realloc(2); maRegisteredNamespaces[0] = beans::make_Pair( OUString( "urn:oasis:names:tc:opendocument:xmlns:office:1.0" ), xml::sax::FastToken::NAMESPACE); maRegisteredNamespaces[1] = beans::make_Pair( OUString( "http://www.w3.org/1999/xlink" ), 2*xml::sax::FastToken::NAMESPACE); } void serializerTest () { try { uno::Reference< xml::dom::XDocument > xDoc = mxDomBuilder->parse( uno::Reference( mxInStream.get())); CPPUNIT_ASSERT_MESSAGE("Valid input file did not result in XDocument", xDoc.is()); CPPUNIT_ASSERT_MESSAGE("Valid input file resulted in parse errors", mxErrHandler->noErrors()); uno::Reference< xml::sax::XSAXSerializable > xSaxSerializer( xDoc, uno::UNO_QUERY); CPPUNIT_ASSERT_MESSAGE("XSAXSerializable not supported", xSaxSerializer.is()); uno::Reference< xml::sax::XFastSAXSerializable > xFastSaxSerializer( xDoc, uno::UNO_QUERY); CPPUNIT_ASSERT_MESSAGE("XFastSAXSerializable not supported", xSaxSerializer.is()); xFastSaxSerializer->fastSerialize(mxHandler.get(), mxTokHandler.get(), uno::Sequence< beans::StringPair >(), maRegisteredNamespaces); } catch (const css::xml::sax::SAXParseException&) { CPPUNIT_ASSERT_MESSAGE("Valid input file did not result in XDocument (exception thrown)", false); } } // Change the following lines only, if you add, remove or rename // member functions of the current class, // because these macros are need by auto register mechanism. CPPUNIT_TEST_SUITE(SerializerTest); CPPUNIT_TEST(serializerTest); CPPUNIT_TEST_SUITE_END(); }; CPPUNIT_TEST_SUITE_REGISTRATION(BasicTest); CPPUNIT_TEST_SUITE_REGISTRATION(SerializerTest); } // this macro creates an empty function, which will called by the RegisterAllFunctions() // to let the user the possibility to also register some functions by hand. CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */