blob: 17ea5551b173b3f3ab8ed2bb539075ef47313812 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_extensions.hxx"
//#include <tools/presys.h>
#include <vector>
//#include <tools/postsys.h>
#include <smart/com/sun/star/test/XSimpleTest.hxx>
#include <smart/com/sun/star/lang/XMultiServiceFactory.hxx> // for the multiservice-factories
#include <stdio.h>
#include <smart/com/sun/star/io/XActiveDataSource.hxx>
#include <smart/com/sun/star/io/XOutputStream.hxx>
#include <smart/com/sun/star/xml/sax/SAXParseException.hxx>
#include <smart/com/sun/star/xml/sax/XParser.hxx>
#include <smart/com/sun/star/xml/sax/XExtendedDocumentHandler.hxx>
#include <rtl/wstring.hxx>
#include <osl/time.h>
#include <usr/weak.hxx>
#include <tools/string.hxx>
#include <usr/factoryhlp.hxx>
#include <usr/reflserv.hxx> // for EXTERN_SERVICE_CALLTYPE
using namespace std;
using namespace rtl;
using namespace vos;
using namespace usr;
#define BUILD_ERROR(expr, Message)\
{\
m_seqErrors.realloc( m_seqErrors.getLen() + 1 ); \
m_seqExceptions.realloc( m_seqExceptions.getLen() + 1 ); \
String str; \
str += __FILE__;\
str += " "; \
str += "(" ; \
str += __LINE__ ;\
str += ")\n";\
str += "[ " ; \
str += #expr; \
str += " ] : " ; \
str += Message; \
m_seqErrors.getArray()[ m_seqErrors.getLen()-1] = StringToUString( str , CHARSET_SYSTEM ); \
}\
((void)0)
#define WARNING_ASSERT(expr, Message) \
if( ! (expr) ) { \
m_seqWarnings.realloc( m_seqErrors.getLen() +1 ); \
String str;\
str += __FILE__;\
str += " "; \
str += "(" ; \
str += __LINE__ ;\
str += ")\n";\
str += "[ " ; \
str += #expr; \
str += " ] : " ; \
str += Message; \
m_seqWarnings.getArray()[ m_seqWarnings.getLen()-1] = StringToUString( str , CHARSET_SYSTEM ); \
return; \
}\
((void)0)
#define ERROR_ASSERT(expr, Message) \
if( ! (expr) ) { \
BUILD_ERROR(expr, Message );\
return; \
}\
((void)0)
#define ERROR_EXCEPTION_ASSERT(expr, Message, Exception) \
if( !(expr)) { \
BUILD_ERROR(expr,Message);\
m_seqExceptions.getArray()[ m_seqExceptions.getLen()-1] = UsrAny( Exception );\
return; \
} \
((void)0)
/****
* test szenarios :
*
*
*
****/
class OFileWriter :
public XOutputStream,
public OWeakObject
{
public:
OFileWriter( char *pcFile ) { strcpy( m_pcFile , pcFile ); m_f = 0; }
public: // refcounting
BOOL queryInterface( Uik aUik, XInterfaceRef & rOut )
{
if( XOutputStream::getSmartUik() == aUik ) {
rOut = (XOutputStream *) this;
}
else return OWeakObject::queryInterface( aUik , rOut );
return TRUE;
}
void acquire() { OWeakObject::acquire(); }
void release() { OWeakObject::release(); }
void* getImplementation(Reflection *p) { return OWeakObject::getImplementation(p); }
public:
virtual void writeBytes(const Sequence< BYTE >& aData)
THROWS( (NotConnectedException, BufferSizeExceededException, UsrSystemException) );
virtual void flush(void)
THROWS( (NotConnectedException, BufferSizeExceededException, UsrSystemException) );
virtual void closeOutput(void)
THROWS( (NotConnectedException, BufferSizeExceededException, UsrSystemException) );
private:
char m_pcFile[256];
FILE *m_f;
};
void OFileWriter::writeBytes(const Sequence< BYTE >& aData)
THROWS( (NotConnectedException, BufferSizeExceededException, UsrSystemException) )
{
if( ! m_f ) {
m_f = fopen( m_pcFile , "w" );
}
fwrite( aData.getConstArray() , 1 , aData.getLen() , m_f );
}
void OFileWriter::flush(void)
THROWS( (NotConnectedException, BufferSizeExceededException, UsrSystemException) )
{
fflush( m_f );
}
void OFileWriter::closeOutput(void)
THROWS( (NotConnectedException, BufferSizeExceededException, UsrSystemException) )
{
fclose( m_f );
m_f = 0;
}
class OSaxWriterTest :
public XSimpleTest,
public OWeakObject
{
public:
OSaxWriterTest( const XMultiServiceFactoryRef & rFactory ) : m_rFactory( rFactory )
{
}
~OSaxWriterTest() {}
public: // refcounting
BOOL queryInterface( Uik aUik, XInterfaceRef & rOut );
void acquire() { OWeakObject::acquire(); }
void release() { OWeakObject::release(); }
void* getImplementation(Reflection *p) { return OWeakObject::getImplementation(p); }
public:
virtual void testInvariant(const UString& TestName, const XInterfaceRef& TestObject)
THROWS( ( IllegalArgumentException,
UsrSystemException) );
virtual INT32 test( const UString& TestName,
const XInterfaceRef& TestObject,
INT32 hTestHandle) THROWS( ( IllegalArgumentException,
UsrSystemException) );
virtual BOOL testPassed(void) THROWS( ( UsrSystemException) );
virtual Sequence< UString > getErrors(void) THROWS( (UsrSystemException) );
virtual Sequence< UsrAny > getErrorExceptions(void) THROWS( (UsrSystemException) );
virtual Sequence< UString > getWarnings(void) THROWS( (UsrSystemException) );
private:
void testSimple( const XExtendedDocumentHandlerRef &r );
void testExceptions( const XExtendedDocumentHandlerRef &r );
void testDTD( const XExtendedDocumentHandlerRef &r );
void testPerformance( const XExtendedDocumentHandlerRef &r );
void writeParagraph( const XExtendedDocumentHandlerRef &r , const UString & s);
private:
Sequence<UsrAny> m_seqExceptions;
Sequence<UString> m_seqErrors;
Sequence<UString> m_seqWarnings;
XMultiServiceFactoryRef m_rFactory;
};
/*----------------------------------------
*
* Attributlist implementation
*
*----------------------------------------*/
struct AttributeListImpl_impl;
class AttributeListImpl :
public XAttributeList,
public OWeakObject
{
public:
AttributeListImpl();
AttributeListImpl( const AttributeListImpl & );
~AttributeListImpl();
public:
BOOL queryInterface( Uik aUik, XInterfaceRef & rOut );
void acquire() { OWeakObject::acquire(); }
void release() { OWeakObject::release(); }
void* getImplementation(Reflection *p) { return OWeakObject::getImplementation(p); }
public:
virtual INT16 getLength(void) THROWS( (UsrSystemException) );
virtual UString getNameByIndex(INT16 i) THROWS( (UsrSystemException) );
virtual UString getTypeByIndex(INT16 i) THROWS( (UsrSystemException) );
virtual UString getTypeByName(const UString& aName) THROWS( (UsrSystemException) );
virtual UString getValueByIndex(INT16 i) THROWS( (UsrSystemException) );
virtual UString getValueByName(const UString& aName) THROWS( (UsrSystemException) );
public:
void addAttribute( const UString &sName , const UString &sType , const UString &sValue );
void clear();
private:
struct AttributeListImpl_impl *m_pImpl;
};
struct TagAttribute
{
TagAttribute(){}
TagAttribute( const UString &sName, const UString &sType , const UString &sValue )
{
this->sName = sName;
this->sType = sType;
this->sValue = sValue;
}
UString sName;
UString sType;
UString sValue;
};
struct AttributeListImpl_impl
{
AttributeListImpl_impl()
{
// performance improvement during adding
vecAttribute.reserve(20);
}
vector<struct TagAttribute> vecAttribute;
};
INT16 AttributeListImpl::getLength(void) THROWS( (UsrSystemException) )
{
return m_pImpl->vecAttribute.size();
}
AttributeListImpl::AttributeListImpl( const AttributeListImpl &r )
{
m_pImpl = new AttributeListImpl_impl;
*m_pImpl = *(r.m_pImpl);
}
UString AttributeListImpl::getNameByIndex(INT16 i) THROWS( (UsrSystemException) )
{
if( i < m_pImpl->vecAttribute.size() ) {
return m_pImpl->vecAttribute[i].sName;
}
return UString();
}
UString AttributeListImpl::getTypeByIndex(INT16 i) THROWS( (UsrSystemException) )
{
if( i < m_pImpl->vecAttribute.size() ) {
return m_pImpl->vecAttribute[i].sType;
}
return UString();
}
UString AttributeListImpl::getValueByIndex(INT16 i) THROWS( (UsrSystemException) )
{
if( i < m_pImpl->vecAttribute.size() ) {
return m_pImpl->vecAttribute[i].sValue;
}
return UString();
}
UString AttributeListImpl::getTypeByName( const UString& sName ) THROWS( (UsrSystemException) )
{
vector<struct TagAttribute>::iterator ii = m_pImpl->vecAttribute.begin();
for( ; ii != m_pImpl->vecAttribute.end() ; ii ++ ) {
if( (*ii).sName == sName ) {
return (*ii).sType;
}
}
return UString();
}
UString AttributeListImpl::getValueByName(const UString& sName) THROWS( (UsrSystemException) )
{
vector<struct TagAttribute>::iterator ii = m_pImpl->vecAttribute.begin();
for( ; ii != m_pImpl->vecAttribute.end() ; ii ++ ) {
if( (*ii).sName == sName ) {
return (*ii).sValue;
}
}
return UString();
}
BOOL AttributeListImpl::queryInterface( Uik aUik, XInterfaceRef & rOut )
{
if( aUik == XAttributeList::getSmartUik() ) {
rOut = (XAttributeList * )this;
}
else {
return OWeakObject::queryInterface( aUik , rOut );
}
return TRUE;
}
AttributeListImpl::AttributeListImpl()
{
m_pImpl = new AttributeListImpl_impl;
}
AttributeListImpl::~AttributeListImpl()
{
delete m_pImpl;
}
void AttributeListImpl::addAttribute( const UString &sName ,
const UString &sType ,
const UString &sValue )
{
m_pImpl->vecAttribute.push_back( TagAttribute( sName , sType , sValue ) );
}
void AttributeListImpl::clear()
{
vector<struct TagAttribute> dummy;
m_pImpl->vecAttribute.swap( dummy );
OSL_ASSERT( ! getLength() );
}
/**
* for external binding
*
*
**/
XInterfaceRef OSaxWriterTest_CreateInstance( const XMultiServiceFactoryRef & rSMgr ) THROWS((Exception))
{
OSaxWriterTest *p = new OSaxWriterTest( rSMgr );
XInterfaceRef xService = *p;
return xService;
}
UString OSaxWriterTest_getServiceName( ) THROWS( () )
{
return L"test.com.sun.star.xml.sax.Writer";
}
UString OSaxWriterTest_getImplementationName( ) THROWS( () )
{
return L"test.extensions.xml.sax.Writer";
}
Sequence<UString> OSaxWriterTest_getSupportedServiceNames( ) THROWS( () )
{
Sequence<UString> aRet(1);
aRet.getArray()[0] = OSaxWriterTest_getImplementationName( );
return aRet;
}
BOOL OSaxWriterTest::queryInterface( Uik uik , XInterfaceRef &rOut )
{
if( XSimpleTest::getSmartUik() == uik ) {
rOut = (XSimpleTest *) this;
}
else {
return OWeakObject::queryInterface( uik , rOut );
}
return TRUE;
}
void OSaxWriterTest::testInvariant( const UString& TestName, const XInterfaceRef& TestObject )
THROWS( ( IllegalArgumentException,
UsrSystemException) )
{
if( L"com.sun.star.xml.sax.Writer" == TestName ) {
XDocumentHandlerRef doc( TestObject , USR_QUERY );
XExtendedDocumentHandlerRef ext( TestObject , USR_QUERY );
XActiveDataSourceRef source( TestObject , USR_QUERY );
ERROR_ASSERT( doc.is() , "XDocumentHandler cannot be queried" );
ERROR_ASSERT( ext.is() , "XExtendedDocumentHandler cannot be queried" );
ERROR_ASSERT( source.is() , "XActiveDataSource cannot be queried" );
}
else {
BUILD_ERROR( 0 , "wrong test" );
}
}
INT32 OSaxWriterTest::test( const UString& TestName,
const XInterfaceRef& TestObject,
INT32 hTestHandle) THROWS( ( IllegalArgumentException,
UsrSystemException) )
{
if( L"com.sun.star.xml.sax.Writer" == TestName ) {
try {
if( 0 == hTestHandle ) {
testInvariant( TestName , TestObject );
}
else {
XExtendedDocumentHandlerRef writer( TestObject , USR_QUERY );
if( 1 == hTestHandle ) {
testSimple( writer );
}
else if( 2 == hTestHandle ) {
testExceptions( writer );
}
else if( 3 == hTestHandle ) {
testDTD( writer );
}
else if( 4 == hTestHandle ) {
testPerformance( writer );
}
}
}
catch( Exception& e ) {
BUILD_ERROR( 0 , UStringToString( e.getName() , CHARSET_SYSTEM ).GetCharStr() );
}
catch(...) {
BUILD_ERROR( 0 , "unknown exception (Exception is not base class)" );
}
hTestHandle ++;
if( hTestHandle >= 5) {
// all tests finished.
hTestHandle = -1;
}
}
else {
BUILD_ERROR( 0 , "service not supported by test." );
}
return hTestHandle;
}
BOOL OSaxWriterTest::testPassed(void) THROWS( (UsrSystemException) )
{
return m_seqErrors.getLen() == 0;
}
Sequence< UString > OSaxWriterTest::getErrors(void) THROWS( (UsrSystemException) )
{
return m_seqErrors;
}
Sequence< UsrAny > OSaxWriterTest::getErrorExceptions(void) THROWS( (UsrSystemException) )
{
return m_seqExceptions;
}
Sequence< UString > OSaxWriterTest::getWarnings(void) THROWS( (UsrSystemException) )
{
return m_seqWarnings;
}
void OSaxWriterTest::writeParagraph( const XExtendedDocumentHandlerRef &r , const UString & s)
{
int nMax = s.len();
int nStart = 0;
Sequence<UINT16> seq( s.len() );
memcpy( seq.getArray() , s.getStr() , s.len() * sizeof( UINT16 ) );
for( int n = 1 ; n < nMax ; n++ ){
if( 32 == seq.getArray()[n] ) {
r->allowLineBreak();
r->characters( s.copy( nStart , n - nStart ) );
nStart = n;
}
}
r->allowLineBreak();
r->characters( s.copy( nStart , n - nStart ) );
}
void OSaxWriterTest::testSimple( const XExtendedDocumentHandlerRef &r )
{
UString testParagraph = L"Dies ist ein bloeder Test um zu uberpruefen, ob der SAXWriter "
L"wohl Zeilenumbrueche halbwegs richtig macht oder ob er die Zeile "
L"bis zum bitteren Ende schreibt.";
OFileWriter *pw = new OFileWriter("output.xml");
AttributeListImpl *pList = new AttributeListImpl;
XAttributeListRef rList( (XAttributeList *) pList , USR_QUERY );
XOutputStreamRef ref( ( XOutputStream * ) pw , USR_QUERY );
XActiveDataSourceRef source( r , USR_QUERY );
ERROR_ASSERT( ref.is() , "no output stream" );
ERROR_ASSERT( source.is() , "no active data source" );
source->setOutputStream( ref );
r->startDocument();
pList->addAttribute( L"Arg1" , L"CDATA" , L"bla\n u" );
pList->addAttribute( L"Arg2" , L"CDATA" , L"blub" );
r->startElement( L"tag1" , rList );
r->ignorableWhitespace( L"" );
r->characters( L"huhu" );
r->ignorableWhitespace( L"" );
r->startElement( L"hi" , rList );
r->ignorableWhitespace( L"" );
// the enpassant must be converted & -> &amp;
r->characters( L"&#252;" );
// Test added for mib. Tests if errors during conversions occurs
r->ignorableWhitespace( UString() );
sal_Char array[256];
for( sal_Int32 n = 32 ; n < 254 ; n ++ ) {
array[n-32] = n;
}
array[254-32] = 0;
r->characters(
StringToUString( array , RTL_TEXTENCODING_SYMBOL )
);
r->ignorableWhitespace( UString() );
// '>' must not be converted
r->startCDATA();
r->characters( L">fsfsdf<" );
r->endCDATA();
r->ignorableWhitespace( UString() );
writeParagraph( r , testParagraph );
r->ignorableWhitespace( UString() );
r->comment( L"Dies ist ein Kommentar !" );
r->ignorableWhitespace( UString() );
r->startElement( L"emptytagtest" , rList );
r->endElement( L"emptytagtest" );
r->endElement( L"hi" );
r->ignorableWhitespace( L"" );
r->endElement( L"tag1" );
r->endDocument();
}
void OSaxWriterTest::testExceptions( const XExtendedDocumentHandlerRef & r )
{
OFileWriter *pw = new OFileWriter("output2.xml");
AttributeListImpl *pList = new AttributeListImpl;
XAttributeListRef rList( (XAttributeList *) pList , USR_QUERY );
XOutputStreamRef ref( ( XOutputStream * ) pw , USR_QUERY );
XActiveDataSourceRef source( r , USR_QUERY );
ERROR_ASSERT( ref.is() , "no output stream" );
ERROR_ASSERT( source.is() , "no active data source" );
source->setOutputStream( ref );
{ // startDocument must be called before start element
BOOL bException = TRUE;
try {
r->startElement( L"huhu" , rList );
bException = FALSE;
}
catch( SAXException& e ) {
}
ERROR_ASSERT( bException , "expected exception not thrown !" );
}
r->startDocument();
r->startElement( L"huhu" , rList );
r->startCDATA();
{
BOOL bException = TRUE;
try {
r->startElement( L"huhu" , rList );
bException = FALSE;
}
catch( SAXException& e ) {
}
ERROR_ASSERT( bException , "expected exception not thrown !" );
}
r->endCDATA();
r->endElement( L"hi" );
r->endDocument();
}
void OSaxWriterTest::testDTD(const XExtendedDocumentHandlerRef &r )
{
OFileWriter *pw = new OFileWriter("outputDTD.xml");
AttributeListImpl *pList = new AttributeListImpl;
XAttributeListRef rList( (XAttributeList *) pList , USR_QUERY );
XOutputStreamRef ref( ( XOutputStream * ) pw , USR_QUERY );
XActiveDataSourceRef source( r , USR_QUERY );
ERROR_ASSERT( ref.is() , "no output stream" );
ERROR_ASSERT( source.is() , "no active data source" );
source->setOutputStream( ref );
r->startDocument();
r->unknown( L"<!DOCTYPE iCalendar >\n" );
r->startElement( L"huhu" , rList );
r->endElement( L"huhu" );
r->endDocument();
}
void OSaxWriterTest::testPerformance(const XExtendedDocumentHandlerRef &r )
{
OFileWriter *pw = new OFileWriter("testPerformance.xml");
AttributeListImpl *pList = new AttributeListImpl;
UString testParagraph = L"Dies ist ein bloeder Test um zu uberpruefen, ob der SAXWriter "
L"wohl > Zeilenumbrueche halbwegs richtig macht oder ob er die Zeile "
L"bis zum bitteren Ende schreibt.";
XAttributeListRef rList( (XAttributeList *) pList , USR_QUERY );
XOutputStreamRef ref( ( XOutputStream * ) pw , USR_QUERY );
XActiveDataSourceRef source( r , USR_QUERY );
ERROR_ASSERT( ref.is() , "no output stream" );
ERROR_ASSERT( source.is() , "no active data source" );
source->setOutputStream( ref );
TimeValue aStartTime, aEndTime;
osl_getSystemTime( &aStartTime );
r->startDocument();
// just write a bunch of xml tags !
// for performance testing
sal_Int32 i2;
for( i2 = 0 ; i2 < 15 ; i2 ++ )
{
r->startElement( UString( L"tag" ) + UString::valueOf( i2 ), rList );
for( sal_Int32 i = 0 ; i < 450 ; i ++ )
{
r->ignorableWhitespace( L"");
r->startElement( L"huhu" , rList );
r->characters( testParagraph );
// writeParagraph( r , testParagraph );
r->ignorableWhitespace( L"");
r->endElement( L"huhu" );
}
}
for( i2 = 14 ; i2 >= 0 ; i2-- )
{
r->ignorableWhitespace( L"");
r->endElement( UString( L"tag" ) + UString::valueOf( i2 ) );
}
r->endDocument();
osl_getSystemTime( &aEndTime );
double fStart = (double)aStartTime.Seconds + ((double)aStartTime.Nanosec / 1000000000.0);
double fEnd = (double)aEndTime.Seconds + ((double)aEndTime.Nanosec / 1000000000.0);
printf( "Performance writing : %g s\n" , fEnd - fStart );
}