/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// autogenerated file with codegen.pl

#include <testshl/simpleheader.hxx>

#include <rtl/ref.hxx>
#include <osl/file.hxx>
#include <osl/process.h>
#include <comphelper/seqstream.hxx>
#include <comphelper/sequence.hxx>
#include <cppuhelper/compbase1.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <cppuhelper/basemutex.hxx>

#include <com/sun/star/xml/sax/FastToken.hpp>
#include <com/sun/star/xml/sax/XSAXSerializable.hpp>
#include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>

#include "../source/dom/documentbuilder.hxx"


using namespace ::DOM;
using namespace ::comphelper;
using namespace ::com::sun::star;

namespace
{

// valid xml
static const char validTestFile[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?> \
 <office:document-content \
   xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" \
   xmlns:xlink=\"http://www.w3.org/1999/xlink\" \
   office:version=\"1.0\"> \
   <office:scripts/> \
   <xlink:test/> \
   <office:automatic-styles teststyle=\"test\"/> \
   <moretest/> \
    some text öäü \
 </office:document-content> \
";

// generates a warning: unsupported xml version, unknown xml:space
// value
static const char warningTestFile[] =
"<?xml version=\"47-11.0\" encoding=\"UTF-8\"?> \
 <office:document-content \
   xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" \
   xml:space=\"blafasl\" \
   office:version=\"1.0\"> \
   <office:scripts/> \
   <office:automatic-styles/> \
 </office:document-content> \
";

// <?xml not at start of file
static const char errorTestFile[] =
" <?xml version=\"1.0\" encoding=\"UTF-8\"?> \
 <office:document-content \
   xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" \
   office:version=\"1.0\"> \
   <office:scripts/> \
   <office:automatic-styles/> \
 </office:document-content> \
";

// plain empty
static const char fatalTestFile[] = "";

struct ErrorHandler
    : public ::cppu::WeakImplHelper1< xml::sax::XErrorHandler >
{
    sal_uInt32 mnErrCount;
    sal_uInt32 mnFatalCount;
    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& ) throw (xml::sax::SAXException, uno::RuntimeException)
    {
        ++mnErrCount;
    }

    virtual void SAL_CALL fatalError( const uno::Any& ) throw (xml::sax::SAXException, uno::RuntimeException)
    {
        ++mnFatalCount;
    }

    virtual void SAL_CALL warning( const uno::Any& ) throw (xml::sax::SAXException, uno::RuntimeException)
    {
        ++mnWarnCount;
    }
};

struct DocumentHandler
    : public ::cppu::WeakImplHelper1< xml::sax::XFastDocumentHandler >
{
    // XFastContextHandler
    virtual void SAL_CALL startFastElement( ::sal_Int32 Element, const uno::Reference< xml::sax::XFastAttributeList >& Attribs ) throw (xml::sax::SAXException, uno::RuntimeException)
    {
        OSL_TRACE("Seen element: %c with namespace 0x%x",
                  Element & 0xFFFF, Element & 0xFFFF0000);
    }

    virtual void SAL_CALL startUnknownElement( const ::rtl::OUString& Namespace, const ::rtl::OUString& Name, const uno::Reference< xml::sax::XFastAttributeList >& Attribs ) throw (xml::sax::SAXException, uno::RuntimeException)
    {
    }

    virtual void SAL_CALL endFastElement( ::sal_Int32 Element ) throw (xml::sax::SAXException, uno::RuntimeException)
    {
    }

    virtual void SAL_CALL endUnknownElement( const ::rtl::OUString& Namespace, const ::rtl::OUString& Name ) throw (xml::sax::SAXException, uno::RuntimeException)
    {
    }

    virtual uno::Reference< xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 Element, const uno::Reference< xml::sax::XFastAttributeList >& Attribs ) throw (xml::sax::SAXException, uno::RuntimeException)
    {
        return this;
    }

    virtual uno::Reference< xml::sax::XFastContextHandler > SAL_CALL createUnknownChildContext( const ::rtl::OUString& Namespace, const ::rtl::OUString& Name, const uno::Reference< xml::sax::XFastAttributeList >& Attribs ) throw (xml::sax::SAXException, uno::RuntimeException)
    {
        return this;
    }

    virtual void SAL_CALL characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException)
    {
    }

    // XFastDocumentHandler
    virtual void SAL_CALL startDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException)
    {
    }

    virtual void SAL_CALL endDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException)
    {
    }

    virtual void SAL_CALL setDocumentLocator( const uno::Reference< xml::sax::XLocator >& xLocator ) throw (xml::sax::SAXException, uno::RuntimeException)
    {
    }
};

struct TokenHandler
    : public ::cppu::WeakImplHelper1< xml::sax::XFastTokenHandler >
{
    virtual ::sal_Int32 SAL_CALL getToken( const ::rtl::OUString& Identifier ) throw (uno::RuntimeException)
    {
        CPPUNIT_ASSERT_MESSAGE( "TokenHandler::getToken() unexpected call",
                                false );
        return -1;
    }

    virtual ::rtl::OUString SAL_CALL getIdentifier( ::sal_Int32 Token ) throw (uno::RuntimeException)
    {
        CPPUNIT_ASSERT_MESSAGE( "TokenHandler::getIdentifier() unexpected call",
                                false );
        return rtl::OUString();
    }

    virtual ::sal_Int32 SAL_CALL getTokenFromUTF8( const uno::Sequence< ::sal_Int8 >& Identifier ) throw (uno::RuntimeException)
    {
        OSL_TRACE("getTokenFromUTF8() %s", (const char*)Identifier.getConstArray());
        return Identifier.getLength() ? Identifier[0] : 0;
    }

    virtual uno::Sequence< ::sal_Int8 > SAL_CALL getUTF8Identifier( ::sal_Int32 Token ) throw (uno::RuntimeException)
    {
        CPPUNIT_ASSERT_MESSAGE( "TokenHandler::getUTF8Identifier() unexpected call", 
                                false );
        return uno::Sequence<sal_Int8>();
    }
};

struct BasicTest : public CppUnit::TestFixture
{
    rtl::Reference<CDocumentBuilder>    mxDomBuilder;
    rtl::Reference<ErrorHandler>        mxErrHandler;
    rtl::Reference<SequenceInputStream> mxValidInStream;
    rtl::Reference<SequenceInputStream> mxWarningInStream;
    rtl::Reference<SequenceInputStream> mxErrorInStream;
    rtl::Reference<SequenceInputStream> mxFatalInStream;

    void setUp()
    {
        // luckily, DOM builder doesn't use service fac, so we need
        // not bootstrap uno here
        mxErrHandler.set( new ErrorHandler() );
        mxDomBuilder.set( new CDocumentBuilder(Reference< XMultiServiceFactory >() ));
        mxValidInStream.set( new SequenceInputStream(ByteSequence((sal_Int8*)validTestFile,
                                                                  sizeof(validTestFile)/sizeof(*validTestFile))) );
        mxWarningInStream.set( new SequenceInputStream(ByteSequence((sal_Int8*)warningTestFile,
                                                                    sizeof(warningTestFile)/sizeof(*warningTestFile))) );
        mxErrorInStream.set( new SequenceInputStream(ByteSequence((sal_Int8*)errorTestFile,
                                                                  sizeof(errorTestFile)/sizeof(*errorTestFile))) );
        mxFatalInStream.set( new SequenceInputStream(ByteSequence((sal_Int8*)fatalTestFile,
                                                                  sizeof(fatalTestFile)/sizeof(*fatalTestFile))) );
        mxDomBuilder->setErrorHandler(mxErrHandler.get());
    }

    void validInputTest()
    {        
        CPPUNIT_ASSERT_MESSAGE( "Valid input file did not result in XDocument #1", 
                                mxDomBuilder->parse(
                                    uno::Reference<io::XInputStream>(
                                        mxValidInStream.get())).is() );
        CPPUNIT_ASSERT_MESSAGE( "Valid input file resulted in parse errors", 
                                mxErrHandler->noErrors() );
    }

    void warningInputTest()
    {
        CPPUNIT_ASSERT_MESSAGE( "Valid input file did not result in XDocument #2", 
                                mxDomBuilder->parse(
                                    uno::Reference<io::XInputStream>(
                                        mxWarningInStream.get())).is() );
        CPPUNIT_ASSERT_MESSAGE( "No parse warnings in unclean input file", 
                                mxErrHandler->mnWarnCount && !mxErrHandler->mnErrCount && !mxErrHandler->mnFatalCount );
    }

    void errorInputTest()
    {        
        CPPUNIT_ASSERT_MESSAGE( "Valid input file did not result in XDocument #3", 
                                mxDomBuilder->parse(
                                    uno::Reference<io::XInputStream>(
                                        mxErrorInStream.get())).is() );
        CPPUNIT_ASSERT_MESSAGE( "No parse errors in unclean input file", 
                                !mxErrHandler->mnWarnCount && mxErrHandler->mnErrCount && !mxErrHandler->mnFatalCount );
    }

    void fatalInputTest()
    {        
        CPPUNIT_ASSERT_MESSAGE( "Broken input file resulted in XDocument", 
                                !mxDomBuilder->parse(
                                    uno::Reference<io::XInputStream>(
                                        mxFatalInStream.get())).is() );
        CPPUNIT_ASSERT_MESSAGE( "No fatal 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(fatalInputTest);
    CPPUNIT_TEST_SUITE_END();
};

struct SerializerTest : public CppUnit::TestFixture
{
    SerializerTest() : mbUnoInitialized(false) {}

    uno::Reference<uno::XComponentContext>                   mxCtx;
    rtl::Reference<CDocumentBuilder>                         mxDomBuilder;
    rtl::Reference<ErrorHandler>                             mxErrHandler;
    rtl::Reference<SequenceInputStream>                      mxInStream;
    rtl::Reference<DocumentHandler>                          mxHandler;
    rtl::Reference<TokenHandler>                             mxTokHandler;
    uno::Sequence< beans::Pair< rtl::OUString, sal_Int32 > > maRegisteredNamespaces;
    bool                                                     mbUnoInitialized;

    void setUp()
    {
        // need working typelib, bootstrap UNO now
        if( !mbUnoInitialized )
        {
            const char* pArgs( getForwardString() );
            CPPUNIT_ASSERT_MESSAGE("Test file parameter", pArgs);

            const rtl::OUString sBaseDir=rtl::OUString::createFromAscii(pArgs);

            // bootstrap UNO
            try
            {
                ::rtl::OUString aIniUrl;
                CPPUNIT_ASSERT_MESSAGE( 
                    "Converting ini file to URL",
                    osl_getFileURLFromSystemPath( 
                        (sBaseDir+rtl::OUString::createFromAscii("unoxml_unittest_test.ini")).pData, 
                        &aIniUrl.pData ) == osl_File_E_None );

                mxCtx = ::cppu::defaultBootstrap_InitialComponentContext(aIniUrl);
                CPPUNIT_ASSERT_MESSAGE("Getting component context", mxCtx.is());
            }
            catch( uno::Exception& )
            {
                CPPUNIT_ASSERT_MESSAGE("Bootstrapping UNO", false);
            }

            mbUnoInitialized = true;
        }

        mxErrHandler.set( new ErrorHandler() );
        mxDomBuilder.set( new CDocumentBuilder(
                              uno::Reference< lang::XMultiServiceFactory >(  
                                  mxCtx->getServiceManager(), 
                                  uno::UNO_QUERY )));
        mxInStream.set( new SequenceInputStream(ByteSequence((sal_Int8*)validTestFile,
                                                             sizeof(validTestFile)/sizeof(*validTestFile))) );
        mxDomBuilder->setErrorHandler(mxErrHandler.get());

        mxHandler.set( new DocumentHandler() );
        mxTokHandler.set( new TokenHandler() );

        maRegisteredNamespaces.realloc(2);
        maRegisteredNamespaces[0] = beans::make_Pair(
            rtl::OUString( 
                RTL_CONSTASCII_USTRINGPARAM(
                    "urn:oasis:names:tc:opendocument:xmlns:office:1.0") ),
            xml::sax::FastToken::NAMESPACE);
        maRegisteredNamespaces[1] = beans::make_Pair(
            rtl::OUString( 
                RTL_CONSTASCII_USTRINGPARAM(
                    "http://www.w3.org/1999/xlink") ),
            2*xml::sax::FastToken::NAMESPACE);
    }

    void serializerTest ()
    {        
        uno::Reference< xml::dom::XDocument > xDoc=
            mxDomBuilder->parse(
                uno::Reference<io::XInputStream>(
                    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 );
    }

    // 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_NAMED_REGISTRATION(BasicTest, "BasicTest");
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(SerializerTest, "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.
NOADDITIONAL;

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
