diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
commit | 8362bf63dea22bbf6736609b0f49c152f975eb63 (patch) | |
tree | 0eea3928e39e50fae91d4e68b21b1e6cbae25604 /lib/kofficecore/tests | |
download | koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip |
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'lib/kofficecore/tests')
-rw-r--r-- | lib/kofficecore/tests/Makefile.am | 40 | ||||
-rw-r--r-- | lib/kofficecore/tests/filter_graph.cpp | 115 | ||||
-rw-r--r-- | lib/kofficecore/tests/filterchain_test.cpp | 107 | ||||
-rw-r--r-- | lib/kofficecore/tests/kodomtest.cpp | 129 | ||||
-rw-r--r-- | lib/kofficecore/tests/kogenstylestest.cpp | 270 | ||||
-rw-r--r-- | lib/kofficecore/tests/kooasissettingstest.cpp | 106 | ||||
-rw-r--r-- | lib/kofficecore/tests/kooasisstoretest.cpp | 58 | ||||
-rw-r--r-- | lib/kofficecore/tests/kopointtest.cpp | 89 | ||||
-rw-r--r-- | lib/kofficecore/tests/korecttest.cpp | 53 | ||||
-rw-r--r-- | lib/kofficecore/tests/koxmlreadertest.cpp | 2074 | ||||
-rw-r--r-- | lib/kofficecore/tests/priorityqueue_test.cpp | 87 |
11 files changed, 3128 insertions, 0 deletions
diff --git a/lib/kofficecore/tests/Makefile.am b/lib/kofficecore/tests/Makefile.am new file mode 100644 index 00000000..3cc6827a --- /dev/null +++ b/lib/kofficecore/tests/Makefile.am @@ -0,0 +1,40 @@ +####### General stuff + +INCLUDES= -I$(srcdir)/.. $(KSTORE_INCLUDES) $(all_includes) + +####### Files + +check_PROGRAMS = priorityqueue_test filterchain_test filter_graph kogenstylestest \ + kodomtest kooasissettingstest kooasisstoretest kopointtest korecttest + +TESTS = kogenstylestest kodomtest kooasissettingstest kooasisstoretest kopointtest korecttest + +priorityqueue_test_SOURCES = priorityqueue_test.cpp +priorityqueue_test_LDADD = ../libkofficecore.la + +filterchain_test_SOURCES = filterchain_test.cpp +filterchain_test_LDADD = ../libkofficecore.la + +filter_graph_SOURCES = filter_graph.cpp +filter_graph_LDADD = ../libkofficecore.la + +kogenstylestest_SOURCES = kogenstylestest.cpp +kogenstylestest_LDADD = ../libkofficecore.la + +kodomtest_SOURCES = kodomtest.cpp +kodomtest_LDADD = ../libkofficecore.la + +kooasissettingstest_SOURCES = kooasissettingstest.cpp +kooasissettingstest_LDADD = ../libkofficecore.la + +kooasisstoretest_SOURCES = kooasisstoretest.cpp +kooasisstoretest_LDADD = ../libkofficecore.la + +kopointtest_SOURCES = kopointtest.cpp +kopointtest_LDADD = ../libkofficecore.la + +korecttest_SOURCES = korecttest.cpp +korecttest_LDADD = ../libkofficecore.la + +dot: + dot -Tpng -o graph.png graph.dot diff --git a/lib/kofficecore/tests/filter_graph.cpp b/lib/kofficecore/tests/filter_graph.cpp new file mode 100644 index 00000000..22323355 --- /dev/null +++ b/lib/kofficecore/tests/filter_graph.cpp @@ -0,0 +1,115 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Werner Trobin <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qfile.h> +#include <KoQueryTrader.h> +#include <KoFilterManager.h> +#include <kinstance.h> +#include <kdebug.h> + +int main( int /*argc*/, char ** /*argv*/ ) +{ + KInstance instance( "filter_graph" ); // we need an instance when using the trader + + QCString output = "digraph filters {\n"; + + // The following code is shamelessly copied over from KOffice::Graph::buildGraph + // It wasn't feasible to do some serious changes in the lib for that tiny bit + // of duplicated code in a test file. + + QValueList<QString> vertices; // to keep track of already inserted values, not performance critical + + // Make sure that all available parts are added to the graph + QValueList<KoDocumentEntry> parts( KoDocumentEntry::query() ); + QValueList<KoDocumentEntry>::ConstIterator partIt( parts.begin() ); + QValueList<KoDocumentEntry>::ConstIterator partEnd( parts.end() ); + + while ( partIt != partEnd ) { + //kdDebug() << ( *partIt ).service()->desktopEntryName() << endl; + QStringList nativeMimeTypes = ( *partIt ).service()->property( "X-KDE-ExtraNativeMimeTypes" ).toStringList(); + nativeMimeTypes += ( *partIt ).service()->property( "X-KDE-NativeMimeType" ).toString(); + QStringList::ConstIterator it = nativeMimeTypes.begin(); + QStringList::ConstIterator end = nativeMimeTypes.end(); + for ( ; it != end; ++it ) { + QString key = *it; + //kdDebug() << " " << key << endl; + if ( !key.isEmpty() ) { + output += " \""; + output += key.latin1(); + output += "\" [shape=box, style=filled, fillcolor=lightblue];\n"; + if ( vertices.find( key ) == vertices.end() ) + vertices.append( key ); + } + } + ++partIt; + } + + QValueList<KoFilterEntry::Ptr> filters( KoFilterEntry::query() ); // no constraint here - we want *all* :) + QValueList<KoFilterEntry::Ptr>::ConstIterator it = filters.begin(); + QValueList<KoFilterEntry::Ptr>::ConstIterator end = filters.end(); + + for ( ; it != end; ++it ) { + kdDebug() << "import " << ( *it )->import << " export " << ( *it )->export_ << endl; + // First add the "starting points" + QStringList::ConstIterator importIt = ( *it )->import.begin(); + QStringList::ConstIterator importEnd = ( *it )->import.end(); + for ( ; importIt != importEnd; ++importIt ) { + // already there? + if ( vertices.find( *importIt ) == vertices.end() ) { + vertices.append( *importIt ); + output += " \""; + output += ( *importIt ).latin1(); + output += "\";\n"; + } + } + + QStringList::ConstIterator exportIt = ( *it )->export_.begin(); + QStringList::ConstIterator exportEnd = ( *it )->export_.end(); + + for ( ; exportIt != exportEnd; ++exportIt ) { + // First make sure the export vertex is in place + if ( vertices.find( *exportIt ) == vertices.end() ) { + output += " \""; + output += ( *exportIt ).latin1(); + output += "\";\n"; + vertices.append( *exportIt ); + } + // Then create the appropriate edges + importIt = ( *it )->import.begin(); + for ( ; importIt != importEnd; ++importIt ) { + output += " \""; + output += ( *importIt ).latin1(); + output += "\" -> \""; + output += ( *exportIt ).latin1(); + if ( KoFilterManager::filterAvailable( *it ) ) + output += "\";\n"; + else + output += "\" [style=dotted];\n"; + } + } + } + + output += "}\n"; + + QFile f( "graph.dot" ); + if ( f.open( IO_WriteOnly ) ) + f.writeBlock( output.data(), output.size() - 1 ); + f.close(); + return 0; +} diff --git a/lib/kofficecore/tests/filterchain_test.cpp b/lib/kofficecore/tests/filterchain_test.cpp new file mode 100644 index 00000000..23f620a1 --- /dev/null +++ b/lib/kofficecore/tests/filterchain_test.cpp @@ -0,0 +1,107 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Werner Trobin <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <KoFilterChain.h> +#include <KoFilterManager.h> +#include <kinstance.h> +#include <kdebug.h> + +int main( int /*argc*/, char ** /*argv*/ ) +{ + KInstance instance( "filterchain_test" ); // we need an instance when using the trader + KOffice::Graph g( "application/x-kspread" ); + g.dump(); + g.setSourceMimeType( "application/x-kword" ); + g.dump(); + + KoFilterManager *manager = new KoFilterManager( 0 ); + kdDebug() << "Trying to build some filter chains..." << endl; + QCString mimeType( "foo/bar" ); + KoFilterChain::Ptr chain = g.chain( manager, mimeType ); + if ( !chain ) + kdDebug() << "Chain for 'foo/bar' is not available, OK" << endl; + else { + kdError() << "Chain for 'foo/bar' is available!" << endl; + chain->dump(); + } + + mimeType = "application/x-krita"; + chain = g.chain( manager, mimeType ); + if ( !chain ) + kdDebug() << "Chain for 'application/x-krita' is not available, OK" << endl; + else { + kdError() << "Chain 'application/x-krita' is available!" << endl; + chain->dump(); + } + + mimeType = "text/x-csv"; + chain = g.chain( manager, mimeType ); + if ( !chain ) + kdError() << "Chain for 'text/x-csv' is not available!" << endl; + else { + kdDebug() << "Chain for 'text/x-csv' is available, OK" << endl; + chain->dump(); + } + + // Try to find the closest KOffice part + mimeType = ""; + chain = g.chain( manager, mimeType ); + if ( !chain ) + kdDebug() << "It was already a KOffice part, OK" << endl; + else + kdError() << "We really got a chain? ugh :}" << endl; + + g.setSourceMimeType( "text/x-csv" ); + mimeType = ""; + chain = g.chain( manager, mimeType ); + if ( !chain ) + kdError() << "Hmm... why didn't we find a chain?" << endl; + else { + kdDebug() << "Chain for 'text/x-csv' -> closest part is available (" + << mimeType << "), OK" << endl; + chain->dump(); + } + + kdDebug() << "Checking mimeFilter() for Import:" << endl; + QStringList list = KoFilterManager::mimeFilter( "application/x-kword", KoFilterManager::Import ); + QStringList::ConstIterator it = list.begin(); + QStringList::ConstIterator end = list.end(); + for ( ; it != end; ++it ) + kdDebug() << " " << *it << endl; + kdDebug() << " " << list.count() << " entries." << endl; + + kdDebug() << "Checking mimeFilter() for Export:" << endl; + list = KoFilterManager::mimeFilter( "application/x-kword", KoFilterManager::Export ); + it = list.begin(); + end = list.end(); + for ( ; it != end; ++it ) + kdDebug() << " " << *it << endl; + kdDebug() << " " << list.count() << " entries." << endl; + + kdDebug() << "Checking KoShell's mimeFilter():" << endl; + list = KoFilterManager::mimeFilter(); + it = list.begin(); + end = list.end(); + for ( ; it != end; ++it ) + kdDebug() << " " << *it << endl; + kdDebug() << " " << list.count() << " entries." << endl; + + delete manager; + return 0; +} diff --git a/lib/kofficecore/tests/kodomtest.cpp b/lib/kofficecore/tests/kodomtest.cpp new file mode 100644 index 00000000..c8e3c539 --- /dev/null +++ b/lib/kofficecore/tests/kodomtest.cpp @@ -0,0 +1,129 @@ +/* This file is part of the KDE project + Copyright (C) 2004 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "KoDom.h" +#include "KoXmlNS.h" + +#include <qapplication.h> +#include <assert.h> + +//static void debugElemNS( const QDomElement& elem ) +//{ +// qDebug( "nodeName=%s tagName=%s localName=%s prefix=%s namespaceURI=%s", elem.nodeName().latin1(), elem.tagName().latin1(), elem.localName().latin1(), elem.prefix().latin1(), elem.namespaceURI().latin1() ); +//} + +void testQDom( const QDomDocument& doc ) +{ + QDomElement docElem = doc.documentElement(); + //debugElemNS( docElem ); + assert( docElem.nodeName() == "o:document-content" ); + assert( docElem.tagName() == "document-content" ); + assert( docElem.localName() == "document-content" ); + assert( docElem.prefix() == "o" ); + assert( docElem.namespaceURI() == KoXmlNS::office ); + + // WARNING, elementsByTagNameNS is recursive!!! + QDomNodeList docElemChildren = docElem.elementsByTagNameNS( KoXmlNS::office, "body" ); + assert( docElemChildren.length() == 1 ); + + QDomElement elem = docElemChildren.item( 0 ).toElement(); + //debugElemNS( elem ); + assert( elem.tagName() == "body" ); + assert( elem.localName() == "body" ); + assert( elem.prefix() == "o" ); + assert( elem.namespaceURI() == KoXmlNS::office ); + + QDomNode n = elem.firstChild(); + for ( ; !n.isNull() ; n = n.nextSibling() ) { + if ( !n.isElement() ) + continue; + QDomElement e = n.toElement(); + //debugElemNS( e ); + assert( e.tagName() == "p" ); + assert( e.localName() == "p" ); + assert( e.prefix().isEmpty() ); + assert( e.namespaceURI() == KoXmlNS::text ); + } + + qDebug("testQDom... ok"); +} + +void testKoDom( const QDomDocument& doc ) +{ + QDomElement docElem = KoDom::namedItemNS( doc, KoXmlNS::office, "document-content" ); + assert( !docElem.isNull() ); + assert( docElem.localName() == "document-content" ); + assert( docElem.namespaceURI() == KoXmlNS::office ); + + QDomElement body = KoDom::namedItemNS( docElem, KoXmlNS::office, "body" ); + assert( !body.isNull() ); + assert( body.localName() == "body" ); + assert( body.namespaceURI() == KoXmlNS::office ); + + QDomElement p = KoDom::namedItemNS( body, KoXmlNS::text, "p" ); + assert( !p.isNull() ); + assert( p.localName() == "p" ); + assert( p.namespaceURI() == KoXmlNS::text ); + + const QDomElement officeStyle = KoDom::namedItemNS( docElem, KoXmlNS::office, "styles" ); + assert( !officeStyle.isNull() ); + + // Look for a non-existing element + QDomElement notexist = KoDom::namedItemNS( body, KoXmlNS::text, "notexist" ); + assert( notexist.isNull() ); + + int count = 0; + QDomElement elem; + forEachElement( elem, body ) { + assert( elem.localName() == "p" ); + assert( elem.namespaceURI() == KoXmlNS::text ); + ++count; + } + assert( count == 2 ); + + // Attributes + // ### Qt bug: it doesn't work if using style-name instead of text:style-name in the XML + const QString styleName = p.attributeNS( KoXmlNS::text, "style-name", QString::null ); + qDebug( "%s", styleName.latin1() ); + assert( styleName == "L1" ); + + qDebug("testKoDom... ok"); +} + +int main( int argc, char** argv ) { + QApplication app( argc, argv, QApplication::Tty ); + + const QCString xml = QCString( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<o:document-content xmlns:o=\"" ) + + KoXmlNS::office + + "\" xmlns=\"" + KoXmlNS::text + + "\" xmlns:text=\"" + KoXmlNS::text + + "\">\n" + "<o:body><p text:style-name=\"L1\">foobar</p><p>2nd</p></o:body><o:styles></o:styles>\n" + "</o:document-content>\n"; + QDomDocument doc; + //QXmlSimpleReader reader; + //reader.setFeature( "http://xml.org/sax/features/namespaces", TRUE ); + //reader.setFeature( "http://xml.org/sax/features/namespace-prefixes", FALSE ); + bool ok = doc.setContent( xml, true /* namespace processing */ ); + assert( ok ); + + testQDom(doc); + testKoDom(doc); +} diff --git a/lib/kofficecore/tests/kogenstylestest.cpp b/lib/kofficecore/tests/kogenstylestest.cpp new file mode 100644 index 00000000..ddfac1f6 --- /dev/null +++ b/lib/kofficecore/tests/kogenstylestest.cpp @@ -0,0 +1,270 @@ +/* This file is part of the KDE project + Copyright (C) 2004-2006 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <KoGenStyles.h> +#include <KoXmlWriter.h> +#include "../../store/tests/xmlwritertest.h" +#include <kdebug.h> +#include <assert.h> + +int testLookup() +{ + kdDebug() << k_funcinfo << endl; + KoGenStyles coll; + + QMap<QString, QString> map1; + map1.insert( "map1key", "map1value" ); + QMap<QString, QString> map2; + map2.insert( "map2key1", "map2value1" ); + map2.insert( "map2key2", "map2value2" ); + + KoGenStyle first( KoGenStyle::STYLE_AUTO, "paragraph" ); + first.addAttribute( "style:master-page-name", "Standard" ); + first.addProperty( "style:page-number", "0" ); + first.addProperty( "style:foobar", "2", KoGenStyle::TextType ); + first.addStyleMap( map1 ); + first.addStyleMap( map2 ); + + QString firstName = coll.lookup( first ); + kdDebug() << "The first style got assigned the name " << firstName << endl; + assert( firstName == "A1" ); // it's fine if it's something else, but the koxmlwriter tests require a known name + assert( first.type() == KoGenStyle::STYLE_AUTO ); + + KoGenStyle second( KoGenStyle::STYLE_AUTO, "paragraph" ); + second.addAttribute( "style:master-page-name", "Standard" ); + second.addProperty( "style:page-number", "0" ); + second.addProperty( "style:foobar", "2", KoGenStyle::TextType ); + second.addStyleMap( map1 ); + second.addStyleMap( map2 ); + + QString secondName = coll.lookup( second ); + kdDebug() << "The second style got assigned the name " << secondName << endl; + + assert( firstName == secondName ); // check that sharing works + assert( first == second ); // check that operator== works :) + + const KoGenStyle* s = coll.style( firstName ); // check lookup of existing style + assert( s ); + assert( *s == first ); + s = coll.style( "foobarblah" ); // check lookup of non-existing style + assert( !s ); + + KoGenStyle third( KoGenStyle::STYLE_AUTO, "paragraph", secondName ); // inherited style + third.addProperty( "style:margin-left", "1.249cm" ); + third.addProperty( "style:page-number", "0" ); // same as parent + third.addProperty( "style:foobar", "3", KoGenStyle::TextType ); // different from parent + assert( third.parentName() == secondName ); + + QString thirdName = coll.lookup( third, "P" ); + kdDebug() << "The third style got assigned the name " << thirdName << endl; + assert( thirdName == "P1" ); + + KoGenStyle user( KoGenStyle::STYLE_USER, "paragraph" ); // differs from third since it doesn't inherit second, and has a different type + user.addProperty( "style:margin-left", "1.249cm" ); + + QString userStyleName = coll.lookup( user, "User", KoGenStyles::DontForceNumbering ); + kdDebug() << "The user style got assigned the name " << userStyleName << endl; + assert( userStyleName == "User" ); + + KoGenStyle sameAsParent( KoGenStyle::STYLE_AUTO, "paragraph", secondName ); // inherited style + sameAsParent.addAttribute( "style:master-page-name", "Standard" ); + sameAsParent.addProperty( "style:page-number", "0" ); + sameAsParent.addProperty( "style:foobar", "2", KoGenStyle::TextType ); + sameAsParent.addStyleMap( map1 ); + sameAsParent.addStyleMap( map2 ); + QString sapName = coll.lookup( sameAsParent, "foobar" ); + kdDebug() << "The 'same as parent' style got assigned the name " << sapName << endl; + + assert( sapName == secondName ); + assert( coll.styles().count() == 3 ); + + // OK, now add a style marked as for styles.xml; it looks like the above style, but + // since it's marked for styles.xml it shouldn't be shared with it. + KoGenStyle headerStyle( KoGenStyle::STYLE_AUTO, "paragraph" ); + headerStyle.addAttribute( "style:master-page-name", "Standard" ); + headerStyle.addProperty( "style:page-number", "0" ); + headerStyle.addProperty( "style:foobar", "2", KoGenStyle::TextType ); + headerStyle.addStyleMap( map1 ); + headerStyle.addStyleMap( map2 ); + headerStyle.setAutoStyleInStylesDotXml( true ); + QString headerStyleName = coll.lookup( headerStyle, "foobar" ); + + assert( coll.styles().count() == 4 ); + assert( coll.styles( KoGenStyle::STYLE_AUTO ).count() == 2 ); + assert( coll.styles( KoGenStyle::STYLE_USER ).count() == 1 ); + + QValueList<KoGenStyles::NamedStyle> stylesXmlStyles = coll.styles( KoGenStyle::STYLE_AUTO, true ); + assert( stylesXmlStyles.count() == 1 ); + KoGenStyles::NamedStyle firstStyle = stylesXmlStyles.first(); + assert( firstStyle.name == headerStyleName ); + + TEST_BEGIN( 0, 0 ); + first.writeStyle( &writer, coll, "style:style", firstName, "style:paragraph-properties" ); + TEST_END( "XML for first/second style", "<r>\n <style:style style:name=\"A1\" style:family=\"paragraph\" style:master-page-name=\"Standard\">\n <style:paragraph-properties style:page-number=\"0\"/>\n <style:text-properties style:foobar=\"2\"/>\n <style:map map1key=\"map1value\"/>\n <style:map map2key1=\"map2value1\" map2key2=\"map2value2\"/>\n </style:style>\n</r>\n" ); + + TEST_BEGIN( 0, 0 ); + third.writeStyle( &writer, coll, "style:style", thirdName, "style:paragraph-properties" ); + TEST_END( "XML for third style", "<r>\n <style:style style:name=\"P1\" style:parent-style-name=\"A1\" style:family=\"paragraph\">\n <style:paragraph-properties style:margin-left=\"1.249cm\"/>\n <style:text-properties style:foobar=\"3\"/>\n </style:style>\n</r>\n" ); + + coll.markStyleForStylesXml( firstName ); + { + QValueList<KoGenStyles::NamedStyle> stylesXmlStyles = coll.styles( KoGenStyle::STYLE_AUTO, true ); + assert( stylesXmlStyles.count() == 2 ); + QValueList<KoGenStyles::NamedStyle> contentXmlStyles = coll.styles( KoGenStyle::STYLE_AUTO, false ); + assert( contentXmlStyles.count() == 1 ); + } + + return 0; +} + +int testDefaultStyle() +{ + kdDebug() << k_funcinfo << endl; + /* Create a default style, + * and then an auto style with exactly the same attributes + * -> the lookup gives the default style. + * + * Also checks how the default style gets written out to XML. + */ + KoGenStyles coll; + + KoGenStyle defaultStyle( KoGenStyle::STYLE_AUTO, "paragraph" ); + defaultStyle.addAttribute( "style:master-page-name", "Standard" ); + defaultStyle.addProperty( "myfont", "isBold" ); + defaultStyle.setDefaultStyle( true ); + QString defaultStyleName = coll.lookup( defaultStyle ); + assert( !defaultStyleName.isEmpty() ); // whatever, but not empty + assert( defaultStyle.type() == KoGenStyle::STYLE_AUTO ); + assert( defaultStyle.isDefaultStyle() ); + + KoGenStyle anotherStyle( KoGenStyle::STYLE_AUTO, "paragraph" ); + anotherStyle.addAttribute( "style:master-page-name", "Standard" ); + anotherStyle.addProperty( "myfont", "isBold" ); + QString anotherStyleName = coll.lookup( anotherStyle ); + assert( anotherStyleName == defaultStyleName ); + + assert( coll.styles().count() == 1 ); + + TEST_BEGIN( 0, 0 ); + defaultStyle.writeStyle( &writer, coll, "style:default-style", defaultStyleName, "style:paragraph-properties" ); + TEST_END( "XML for default style", "<r>\n <style:default-style style:family=\"paragraph\" style:master-page-name=\"Standard\">\n <style:paragraph-properties myfont=\"isBold\"/>\n </style:default-style>\n</r>\n" ); + + // The kspread case: not writing out all properties, only if they differ + // from the default style. + // KoGenStyles doesn't fetch info from the parent style when testing + // for equality, so KSpread uses isEmpty() to check for equality-to-parent. + KoGenStyle dataStyle( KoGenStyle::STYLE_AUTO, "paragraph", defaultStyleName ); + assert( dataStyle.isEmpty() ); + // and then it doesn't look up the auto style, but rather uses the parent style directly. + + return 0; +} + +int testUserStyles() +{ + kdDebug() << k_funcinfo << endl; + /* Two user styles with exactly the same attributes+properties will not get merged, since + * they don't have exactly the same attributes after all: the display-name obviously differs :) + */ + KoGenStyles coll; + + KoGenStyle user1( KoGenStyle::STYLE_USER, "paragraph" ); + user1.addAttribute( "style:display-name", "User 1" ); + user1.addProperty( "myfont", "isBold" ); + + QString user1StyleName = coll.lookup( user1, "User1", KoGenStyles::DontForceNumbering ); + kdDebug() << "The user style got assigned the name " << user1StyleName << endl; + assert( user1StyleName == "User1" ); + + KoGenStyle user2( KoGenStyle::STYLE_USER, "paragraph" ); + user2.addAttribute( "style:display-name", "User 2" ); + user2.addProperty( "myfont", "isBold" ); + + QString user2StyleName = coll.lookup( user2, "User2", KoGenStyles::DontForceNumbering ); + kdDebug() << "The user style got assigned the name " << user2StyleName << endl; + assert( user2StyleName == "User2" ); + + // And now, what if the data uses that style? + // This is like sameAsParent in the other test, but this time the + // parent is a STYLE_USER... + KoGenStyle dataStyle( KoGenStyle::STYLE_AUTO, "paragraph", user2StyleName ); + dataStyle.addProperty( "myfont", "isBold" ); + + QString dataStyleName = coll.lookup( dataStyle, "DataStyle" ); + kdDebug() << "The auto style got assigned the name " << dataStyleName << endl; + assert( dataStyleName == "User2" ); // it found the parent as equal + + // Let's do the opposite test, just to make sure + KoGenStyle dataStyle2( KoGenStyle::STYLE_AUTO, "paragraph", user2StyleName ); + dataStyle2.addProperty( "myfont", "isNotBold" ); + + QString dataStyle2Name = coll.lookup( dataStyle2, "DataStyle" ); + kdDebug() << "The different auto style got assigned the name " << dataStyle2Name << endl; + assert( dataStyle2Name == "DataStyle1" ); + + assert( coll.styles().count() == 3 ); + + TEST_BEGIN( 0, 0 ); + user1.writeStyle( &writer, coll, "style:style", user1StyleName, "style:paragraph-properties" ); + TEST_END( "XML for user style 1", "<r>\n <style:style style:name=\"User1\" style:display-name=\"User 1\" style:family=\"paragraph\">\n <style:paragraph-properties myfont=\"isBold\"/>\n </style:style>\n</r>\n" ); + + TEST_BEGIN( 0, 0 ); + user2.writeStyle( &writer, coll, "style:style", user2StyleName, "style:paragraph-properties" ); + TEST_END( "XML for user style 2", "<r>\n <style:style style:name=\"User2\" style:display-name=\"User 2\" style:family=\"paragraph\">\n <style:paragraph-properties myfont=\"isBold\"/>\n </style:style>\n</r>\n" ); + + return 0; +} + +int testStylesDotXml() +{ + kdDebug() << k_funcinfo << endl; + KoGenStyles coll; + + // Check that an autostyle-in-style.xml and an autostyle-in-content.xml + // don't get the same name. It confuses KoGenStyle's named-based maps. + KoGenStyle headerStyle( KoGenStyle::STYLE_AUTO, "paragraph" ); + headerStyle.addAttribute( "style:master-page-name", "Standard" ); + headerStyle.addProperty( "style:page-number", "0" ); + headerStyle.setAutoStyleInStylesDotXml( true ); + QString headerStyleName = coll.lookup( headerStyle, "P" ); + assert( headerStyleName == "P1" ); + + //coll.dump(); + + KoGenStyle first( KoGenStyle::STYLE_AUTO, "paragraph" ); + first.addAttribute( "style:master-page-name", "Standard" ); + QString firstName = coll.lookup( first, "P" ); + kdDebug() << "The auto style got assigned the name " << firstName << endl; + assert( firstName == "P2" ); // anything but not P1. + return 0; +} + +int main( int, char** ) { + fprintf( stderr, "OK\n" ); + + if ( testLookup() ) + return 1; + if ( testDefaultStyle() ) + return 1; + if ( testUserStyles() ) + return 1; + if ( testStylesDotXml() ) + return 1; + + return 0; +} diff --git a/lib/kofficecore/tests/kooasissettingstest.cpp b/lib/kofficecore/tests/kooasissettingstest.cpp new file mode 100644 index 00000000..ef29536d --- /dev/null +++ b/lib/kofficecore/tests/kooasissettingstest.cpp @@ -0,0 +1,106 @@ +/* This file is part of the KDE project + Copyright (C) 2004 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <KoOasisSettings.h> +#include <KoDom.h> +#include <kdebug.h> +#include <assert.h> + +void testSelectItemSet( KoOasisSettings& settings ) +{ + KoOasisSettings::Items items = settings.itemSet( "notexist" ); + assert( items.isNull() ); + items = settings.itemSet( "view-settings" ); + assert( !items.isNull() ); + kdDebug() << "testSelectItemSet OK" << endl; +} + +void testParseConfigItemString( KoOasisSettings& settings ) +{ + KoOasisSettings::Items viewSettings = settings.itemSet( "view-settings" ); + const QString unit = viewSettings.parseConfigItemString( "unit" ); + qDebug( "%s", unit.latin1() ); + assert( unit == "mm" ); + kdDebug() << "testParseConfigItemString OK" << endl; +} + +void testIndexedMap( KoOasisSettings& settings ) +{ + KoOasisSettings::Items viewSettings = settings.itemSet( "view-settings" ); + assert( !viewSettings.isNull() ); + KoOasisSettings::IndexedMap viewMap = viewSettings.indexedMap( "Views" ); + assert( !viewMap.isNull() ); + KoOasisSettings::Items firstView = viewMap.entry( 0 ); + assert( !firstView.isNull() ); + const short zoomFactor = firstView.parseConfigItemShort( "ZoomFactor" ); + assert( zoomFactor == 100 ); + KoOasisSettings::Items secondView = viewMap.entry( 1 ); + assert( secondView.isNull() ); + kdDebug() << "testIndexedMap OK" << endl; +} + +void testNamedMap( KoOasisSettings& settings ) +{ + KoOasisSettings::Items viewSettings = settings.itemSet( "view-settings" ); + assert( !viewSettings.isNull() ); + KoOasisSettings::NamedMap viewMap = viewSettings.namedMap( "NamedMap" ); + assert( !viewMap.isNull() ); + KoOasisSettings::Items foo = viewMap.entry( "foo" ); + assert( !foo.isNull() ); + const int zoomFactor = foo.parseConfigItemShort( "ZoomFactor" ); + assert( zoomFactor == 100 ); + KoOasisSettings::Items secondView = viewMap.entry( "foobar" ); + assert( secondView.isNull() ); + kdDebug() << "testNamedMap OK" << endl; +} + +int main( int, char** ) { + + const QCString xml = "\ +<?xml version=\"1.0\" encoding=\"UTF-8\"?> \ +<office:document-settings xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\"> \ + <office:settings> \ + <config:config-item-set config:name=\"view-settings\"> \ + <config:config-item config:name=\"unit\" config:type=\"string\">mm</config:config-item> \ + <config:config-item-map-indexed config:name=\"Views\"> \ + <config:config-item-map-entry> \ + <config:config-item config:name=\"ZoomFactor\" config:type=\"short\">100</config:config-item> \ + </config:config-item-map-entry> \ + </config:config-item-map-indexed> \ + <config:config-item-map-named config:name=\"NamedMap\"> \ + <config:config-item-map-entry config:name=\"foo\"> \ + <config:config-item config:name=\"ZoomFactor\" config:type=\"int\">100</config:config-item> \ + </config:config-item-map-entry> \ + </config:config-item-map-named> \ + </config:config-item-set> \ + </office:settings> \ +</office:document-settings> \ +"; + + QDomDocument doc; + bool ok = doc.setContent( xml, true /* namespace processing */ ); + assert( ok ); + + KoOasisSettings settings( doc ); + + testSelectItemSet( settings ); + testParseConfigItemString( settings ); + testIndexedMap( settings ); + testNamedMap( settings ); + return 0; +} diff --git a/lib/kofficecore/tests/kooasisstoretest.cpp b/lib/kofficecore/tests/kooasisstoretest.cpp new file mode 100644 index 00000000..6750904b --- /dev/null +++ b/lib/kofficecore/tests/kooasisstoretest.cpp @@ -0,0 +1,58 @@ +/* This file is part of the KDE project + Copyright (C) 2005 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <KoOasisStore.h> +#include <KoDom.h> +#include <kdebug.h> +#include <assert.h> + +void testMimeForPath( QDomDocument& doc ) +{ + QString mime = KoOasisStore::mimeForPath( doc, "Object 1" ); + kdDebug() << k_funcinfo << mime << endl; + assert( !mime.isNull() ); + assert( !mime.isEmpty() ); + assert( mime == "application/vnd.oasis.opendocument.text" ); + kdDebug() << "testMimeForPath OK" << endl; +} + +int main( int, char** ) { + + const QCString xml = "\ +<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\ +<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">\n\ + <manifest:file-entry manifest:media-type=\"application/vnd.oasis.opendocument.text\" manifest:full-path=\"/\"/>\n\ + <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/>\n\ + <manifest:file-entry manifest:media-type=\"application/vnd.oasis.opendocument.text\" manifest:full-path=\"Object 1\"/>\n\ +</manifest:manifest> \ +"; + + QDomDocument doc; + QString errorMsg; + int errorLine, errorColumn; + bool ok = doc.setContent( xml, true /* namespace processing */, &errorMsg, &errorLine, &errorColumn ); + if ( !ok ) { + kdError() << "Parsing error! Aborting!" << endl + << " In line: " << errorLine << ", column: " << errorColumn << endl + << " Error message: " << errorMsg << endl; + return 1; + } + + testMimeForPath( doc ); + return 0; +} diff --git a/lib/kofficecore/tests/kopointtest.cpp b/lib/kofficecore/tests/kopointtest.cpp new file mode 100644 index 00000000..25286a5d --- /dev/null +++ b/lib/kofficecore/tests/kopointtest.cpp @@ -0,0 +1,89 @@ +#include <KoPoint.h> +#include <kdebug.h> +#include <kglobal.h> +#include <stdlib.h> +#include <math.h> + +bool check( QString txt, bool res, bool expected ) +{ + if ( res == expected ) { + kdDebug() << txt << " : checking '" << res << "' against expected value '" << expected << "'... " << "ok" << endl; + } else { + kdDebug() << txt << " : checking '" << res << "' against expected value '" << expected << "'... " << "KO !" << endl; + exit( 1 ); + } + return true; +} + +bool check( QString txt, double res, double expected ) +{ + if ( kAbs(res - expected) < 0.000001 ) { + kdDebug() << txt << " : checking '" << res << "' against expected value '" << expected << "'... " << "ok" << endl; + } else { + kdDebug() << txt << " : checking '" << res << "' against expected value '" << expected << "'... " << "KO !" << endl; + exit( 1 ); + } + return true; +} + +int main() +{ + KoPoint p0; + check( "KoPoint() is null", p0.isNull(), true ); + KoPoint p1( 10.1, 20.2 ); + check( "KoPoint(...) is not null", p1.isNull(), false ); + check( "KoPoint::x()", p1.x(), 10.1 ); + check( "KoPoint::y()", p1.y(), 20.2 ); + p1.setX( 2.1 ); + p1.setY( 3.2 ); + check( "KoPoint::setX()", p1.x(), 2.1 ); + check( "KoPoint::setY()", p1.y(), 3.2 ); + + KoPoint p2( QPoint( -30, -40 ) ); + check( "KoPoint(const QPoint&)", p2.x(), -30.0 ); + check( "KoPoint(const QPoint&)", p2.y(), -40.0 ); + p2.rx() = 1.5; + p2.ry() = 2.5; + check( "KoPoint::rx()", p2.x(), 1.5 ); + check( "KoPoint::ry()", p2.y(), 2.5 ); + p2.setCoords( -1.6, -1.7 ); + check( "KoPoint::setCoords(double, double)", p2.x(), -1.6 ); + check( "KoPoint::setCoords(double, double)", p2.y(), -1.7 ); + + check( "KoPoint::operator==(const KoPoint&)", p1 == p1, true ); + check( "KoPoint::operator!=(const KoPoint&)", p1 != p2, true ); + + KoPoint p4( 10.2, 20.2 ); + KoPoint p5( 30.4, 40.4 ); + p4 += p5; + check( "KoPoint::operator+=(const KoPoint&)", p4.x(), 40.6 ); + check( "KoPoint::operator+=(const KoPoint&)", p4.y(), 60.6 ); + p4 -= p5; + check( "KoPoint::operator-=(const KoPoint&)", p4.x(), 10.2 ); + check( "KoPoint::operator-=(const KoPoint&)", p4.y(), 20.2 ); + p4 *= 2.0; + check( "KoPoint::operator*=(double)", p4.x(), 20.4 ); + check( "KoPoint::operator*=(double)", p4.y(), 40.4 ); + p4 = p5; + check( "KoPoint::operator=(const KoPoint&)", p4.x(), 30.4 ); + check( "KoPoint::operator=(const KoPoint&)", p4.y(), 40.4 ); + + // ### global operator+, operator- and operator* + // ### transform + + KoPoint p6( 1.0, 2.0 ); + check( "KoPoint::isNear()", p6.isNear( p6, 0 ), true ); + check( "KoPoint::isNear()", p6.isNear( KoPoint( 2, 10 ), 1 ), false ); + check( "KoPoint::isNear()", p6.isNear( KoPoint( 2, 1 ), 1 ), true ); + + KoPoint p7( 10, 10 ); + check( "KoPoint::getAngle()", + fmod( KoPoint::getAngle( p7, p7 * -1 ) + 10*360.0, 360.0 ), 45.0 ); + // ### ??? check( "KoPoint::getAngle()", + // fmod( KoPoint::getAngle( -1 * p7, p7 ) + 10*360.0, 360.0 ), 45.0 ); + // can we define a behaviour ? + // ### check( "KoPoint::getAngle()", KoPoint::getAngle( p7, p7 ), ??? ); + + kdDebug() << endl << "Test OK !" << endl; +} + diff --git a/lib/kofficecore/tests/korecttest.cpp b/lib/kofficecore/tests/korecttest.cpp new file mode 100644 index 00000000..9c2cb8b0 --- /dev/null +++ b/lib/kofficecore/tests/korecttest.cpp @@ -0,0 +1,53 @@ +#include <KoRect.h> +#include <stdio.h> +#include <kapplication.h> +#include <stdlib.h> +#include <kdebug.h> +#include <kglobal.h> + +bool check(QString txt, bool res, bool expected) +{ + if (res == expected) { + kdDebug() << txt << " : checking '" << res << "' against expected value '" << expected << "'... " << "ok" << endl; + } + else { + kdDebug() << txt << " : checking '" << res << "' against expected value '" << expected << "'... " << "KO !" << endl; + exit(1); + } + return true; +} + +bool check(QString txt, QString a, QString b) +{ + if (a.isEmpty()) + a = QString::null; + if (b.isEmpty()) + b = QString::null; + if (a == b) { + kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "ok" << endl; + } + else { + kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "KO !" << endl; + exit(1); + } + return true; +} + +int main(int argc, char *argv[]) +{ + KApplication app(argc,argv,"korecttest",false,false); + + KoRect emptyRect; + check( "KoRect() is null", emptyRect.isNull(), true ); + check( "KoRect() is empty", emptyRect.isEmpty(), true ); + KoRect rect( 1, 15, 250, 156.14 ); + check( "KoRect(...) is not null", rect.isNull(), false ); + check( "KoRect(...) is not empty", rect.isEmpty(), false ); + KoRect unionRect = rect | emptyRect; + check( "Union is not null", unionRect.isNull(), false ); + check( "Union is not empty", unionRect.isEmpty(), false ); + kdDebug() << unionRect << endl; + + printf("\nTest OK !\n"); +} + diff --git a/lib/kofficecore/tests/koxmlreadertest.cpp b/lib/kofficecore/tests/koxmlreadertest.cpp new file mode 100644 index 00000000..213fe0db --- /dev/null +++ b/lib/kofficecore/tests/koxmlreadertest.cpp @@ -0,0 +1,2074 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Ariya Hidayat <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +*/ + +// xmlreadertest.cpp - test KoXml classes +// Ariya Hidayat, November 2005 + +#include <qstring.h> +#include <qcstring.h> +#include <qbuffer.h> +#include <qtextstream.h> +#include <qdatetime.h> +#include <qfile.h> + +#include "KoXmlReader.h" +#include <qxml.h> + +#define CHECK(x,y) check(__FILE__,__LINE__,#x,x,y) + +static int testCount = 0; +static int testFailed = 0; + +template<typename T> +void check( const char *file, int line, const char* msg, +const T& result, const T& expected ) +{ + testCount++; + if( result != expected ) + { + testFailed++; + QString message; + QTextStream ts( &message, IO_WriteOnly ); + ts << msg; + ts << " Result:"; + ts << result; + ts << ", "; + ts << "Expected:"; + ts << expected; + printf( "%s [%d]: %s\n", file, line, message.latin1() ); + } +} + +void check( const char *file, int line, const char* msg, bool result, +bool expected ) +{ + testCount++; + if( result != expected ) + { + testFailed++; + QString message; + QTextStream ts( &message, IO_WriteOnly ); + ts << msg; + ts << " Result: "; + if( result ) ts << "True"; else ts << "False"; + ts << ", "; + ts << "Expected: "; + if( expected ) ts << "True"; else ts << "False"; + printf( "%s [%d]: %s\n", file, line, message.latin1() ); + } +} + +void testNode() +{ + QString errorMsg; + int errorLine = 0; + int errorColumn = 0; + + QByteArray xmlbuf; + QBuffer xmldevice( xmlbuf ); + QTextStream xmlstream( xmlbuf, IO_WriteOnly ); + xmlstream << "<earth>"; + xmlstream << "<continents>"; + xmlstream << "<asia/>"; + xmlstream << "<africa/>"; + xmlstream << "<europe/>"; + xmlstream << "<america/>"; + xmlstream << "<australia/>"; + xmlstream << "<antartic/>"; + xmlstream << "</continents>"; + xmlstream << "<oceans>"; + xmlstream << "<pacific/>"; + xmlstream << "<atlantic/>"; + xmlstream << "</oceans>"; + xmlstream << "</earth>"; + + KoXmlDocument doc; + CHECK( doc.setContent( &xmldevice, &errorMsg, &errorLine, &errorColumn ), true ); + CHECK( errorMsg.isEmpty(), true ); + CHECK( errorLine, 0 ); + CHECK( errorColumn, 0 ); + + // null node + KoXmlNode node1; + CHECK( node1.nodeName(), QString::null ); + CHECK( node1.isNull(), true ); + CHECK( node1.isElement(), false ); + CHECK( node1.isElement(), false ); + CHECK( node1.isDocument(), false ); + CHECK( node1.ownerDocument().isNull(), false ); + CHECK( node1.parentNode().isNull(), true ); + CHECK( node1.hasChildNodes(), false ); + CHECK( node1.firstChild().isNull(), true ); + CHECK( node1.lastChild().isNull(), true ); + CHECK( node1.previousSibling().isNull(), true ); + CHECK( node1.nextSibling().isNull(), true ); + + // compare with another null node + KoXmlNode node2; + CHECK( node2.isNull(), true ); + CHECK( node1==node2, true ); + CHECK( node1!=node2, false ); + + // a node which is a document + KoXmlNode node3 = doc; + CHECK( node3.nodeName(), QString("#document") ); + CHECK( node3.isNull(), false ); + CHECK( node3.isElement(), false ); + CHECK( node3.isText(), false ); + CHECK( node3.isDocument(), true ); + CHECK( node3.ownerDocument().isNull(), false ); + CHECK( node3.ownerDocument()==doc, true ); + CHECK( node3.toDocument()==doc, true ); + + // convert to document and the compare + KoXmlDocument doc2 = node3.toDocument(); + CHECK( doc2.nodeName(), QString("#document") ); + CHECK( doc2.isNull(), false ); + CHECK( doc2.isDocument(), true ); + CHECK( node3==doc2, true ); + + // a document is of course can't be converted to element + KoXmlElement invalidElement = node3.toElement(); + CHECK( invalidElement.nodeName(), QString::null ); + CHECK( invalidElement.isNull(), true ); + CHECK( invalidElement.isElement(), true ); + CHECK( invalidElement.isText(), false ); + CHECK( invalidElement.isDocument(), false ); + + // clear() makes it a null node again + node3.clear(); + CHECK( node3.isNull(), true ); + CHECK( node3.nodeName(), QString::null ); + CHECK( node3.isElement(), false ); + CHECK( node3.isText(), false ); + CHECK( node3.isDocument(), false ); + CHECK( node3.ownerDocument().isNull(), false ); + CHECK( node1==node3, true ); + CHECK( node1!=node3, false ); + + // a node which is an element for <earth> + KoXmlNode node4 = doc.firstChild(); + CHECK( node4.isNull(), false ); + CHECK( node4.isElement(), true ); + CHECK( node4.isText(), false ); + CHECK( node4.isDocument(), false ); + CHECK( node4.hasChildNodes(), true ); + CHECK( node4.ownerDocument()==doc, true ); + CHECK( node4.toElement()==doc.firstChild().toElement(), true ); + + // clear() makes it a null node again + node4.clear(); + CHECK( node4.isNull(), true ); + CHECK( node4.isElement(), false ); + CHECK( node4.isText(), false ); + CHECK( node4.isDocument(), false ); + CHECK( node4==node1, true ); + CHECK( node4!=node1, false ); + + // a node which is an element for <continents> + KoXmlNode node5 = doc.firstChild().firstChild(); + CHECK( node5.nodeName(), QString("continents") ); + CHECK( node5.isNull(), false ); + CHECK( node5.isElement(), true ); + CHECK( node5.isText(), false ); + CHECK( node5.isDocument(), false ); + CHECK( node5.hasChildNodes(), true ); + CHECK( node5.ownerDocument()==doc, true ); + + // convert to element and the compare + KoXmlElement continentsElement = node5.toElement(); + CHECK( node5==continentsElement, true ); + CHECK( continentsElement.isNull(), false ); + CHECK( continentsElement.isElement(), true ); + CHECK( continentsElement.isText(), false ); + CHECK( continentsElement.hasChildNodes(), true ); + CHECK( continentsElement.ownerDocument()==doc, true ); + + // and it doesn't make sense to convert that node to document + // (instead a brand new document is created, i.e. not a null node) + KoXmlDocument invalidDoc = node5.toDocument(); + CHECK( invalidDoc.isNull(), false ); + CHECK( invalidDoc.isElement(), false ); + CHECK( invalidDoc.isText(), false ); + CHECK( invalidDoc.isDocument(), true ); + + // node for <europe> using namedItem() function + KoXmlNode europeNode = continentsElement.namedItem( QString("europe") ); + CHECK( europeNode.nodeName(), QString("europe") ); + CHECK( europeNode.isNull(), false ); + CHECK( europeNode.isElement(), true ); + CHECK( europeNode.isText(), false ); + CHECK( europeNode.hasChildNodes(), false ); + CHECK( europeNode.ownerDocument()==doc, true ); + + // search non-existing node + KoXmlNode fooNode = continentsElement.namedItem( QString("foobar") ); + CHECK( fooNode.isNull(), true ); + CHECK( fooNode.isElement(), false ); + CHECK( fooNode.isText(), false ); + CHECK( fooNode.isCDATASection(), false ); +} + +void testElement() +{ + QString errorMsg; + int errorLine = 0; + int errorColumn = 0; + + QByteArray xmlbuf; + QBuffer xmldevice( xmlbuf ); + + QTextStream xmlstream( xmlbuf, IO_WriteOnly ); + xmlstream << "<html>"; + xmlstream << "<body bgcolor=\"#000\">"; + xmlstream << "<p>"; + xmlstream << "Hello, world!"; + xmlstream << "</p>"; + xmlstream << "</body>"; + xmlstream << "</html>"; + + KoXmlDocument doc; + CHECK( doc.setContent( &xmldevice, &errorMsg, &errorLine, &errorColumn ), true ); + CHECK( errorMsg.isEmpty(), true ); + CHECK( errorLine, 0 ); + CHECK( errorColumn, 0 ); + + // element for <html> + KoXmlElement rootElement; + rootElement = doc.documentElement(); + CHECK( rootElement.nodeName(), QString("html") ); + CHECK( rootElement.isNull(), false ); + CHECK( rootElement.isElement(), true ); + CHECK( rootElement.isDocument(), false ); + CHECK( rootElement.ownerDocument().isNull(), false ); + CHECK( rootElement.ownerDocument()==doc, true ); + CHECK( rootElement.parentNode().isNull(), false ); + CHECK( rootElement.parentNode().toDocument()==doc, true ); + CHECK( rootElement.hasChildNodes(), true ); + CHECK( rootElement.tagName(), QString("html") ); + CHECK( rootElement.prefix().isNull(), true ); + + // element for <body> + KoXmlElement bodyElement; + bodyElement = rootElement.firstChild().toElement(); + CHECK( bodyElement.nodeName(), QString("body") ); + CHECK( bodyElement.isNull(), false ); + CHECK( bodyElement.isElement(), true ); + CHECK( bodyElement.isDocument(), false ); + CHECK( bodyElement.ownerDocument().isNull(), false ); + CHECK( bodyElement.ownerDocument()==doc, true ); + CHECK( bodyElement.parentNode().isNull(), false ); + CHECK( bodyElement.parentNode()==rootElement, true ); + CHECK( bodyElement.hasChildNodes(), true ); + CHECK( bodyElement.tagName(), QString("body") ); + CHECK( bodyElement.prefix().isNull(), true ); + CHECK( bodyElement.hasAttribute("bgcolor"), true ); + CHECK( bodyElement.attribute("bgcolor"), QString("#000") ); + + // a shared copy of <body>, will still have access to attribute bgcolor + KoXmlElement body2Element; + body2Element = bodyElement; + CHECK( body2Element.nodeName(), QString("body") ); + CHECK( body2Element.isNull(), false ); + CHECK( body2Element.isElement(), true ); + CHECK( body2Element.isDocument(), false ); + CHECK( body2Element.ownerDocument().isNull(), false ); + CHECK( body2Element.ownerDocument()==doc, true ); + CHECK( body2Element==bodyElement, true ); + CHECK( body2Element!=bodyElement, false ); + CHECK( body2Element.hasChildNodes(), true ); + CHECK( body2Element.tagName(), QString("body") ); + CHECK( body2Element.prefix().isNull(), true ); + CHECK( body2Element.hasAttribute("bgcolor"), true ); + CHECK( body2Element.attribute("bgcolor"), QString("#000") ); + + // empty element, by default constructor + KoXmlElement testElement; + CHECK( testElement.nodeName(), QString::null ); + CHECK( testElement.isNull(), true ); + CHECK( testElement.isElement(), true ); + CHECK( testElement.isDocument(), false ); + CHECK( testElement.ownerDocument().isNull(), false ); + CHECK( testElement.ownerDocument()!=doc, true ); + CHECK( testElement==rootElement, false ); + CHECK( testElement!=rootElement, true ); + CHECK( testElement.parentNode().isNull(), true ); + CHECK( testElement.hasChildNodes(), false ); + + // check assignment operator + testElement = rootElement; + CHECK( testElement.nodeName(), QString("html") ); + CHECK( testElement.isNull(), false ); + CHECK( testElement.isElement(), true ); + CHECK( testElement.isDocument(), false ); + CHECK( testElement==rootElement, true ); + CHECK( testElement!=rootElement, false ); + CHECK( testElement.parentNode().isNull(), false ); + CHECK( testElement.parentNode().toDocument()==doc, true ); + CHECK( testElement.tagName(), QString("html") ); + CHECK( testElement.prefix().isNull(), true ); + + // assigned from another empty element + testElement = KoXmlElement(); + CHECK( testElement.isNull(), true ); + CHECK( testElement!=rootElement, true ); + + // assigned from <body> + testElement = bodyElement; + CHECK( testElement.isNull(), false ); + CHECK( testElement.isElement(), true ); + CHECK( testElement.isDocument(), false ); + CHECK( testElement.ownerDocument().isNull(), false ); + CHECK( testElement.ownerDocument()==doc, true ); + CHECK( testElement==bodyElement, true ); + CHECK( testElement.parentNode().isNull(), false ); + CHECK( testElement.tagName(), QString("body") ); + CHECK( testElement.prefix().isNull(), true ); + CHECK( testElement.hasChildNodes(), true ); + + // copy constructor + KoXmlElement dummyElement( rootElement ); + CHECK( dummyElement.isNull(), false ); + CHECK( dummyElement.isElement(), true ); + CHECK( dummyElement.isDocument(), false ); + CHECK( dummyElement.ownerDocument().isNull(), false ); + CHECK( dummyElement.ownerDocument()==doc, true ); + CHECK( dummyElement==rootElement, true ); + CHECK( dummyElement.parentNode().isNull(), false ); + CHECK( dummyElement.hasChildNodes(), true ); + CHECK( dummyElement.tagName(), QString("html") ); + CHECK( dummyElement.prefix().isNull(), true ); + + // clear() turns element to null node + dummyElement.clear(); + CHECK( dummyElement.isNull(), true ); + CHECK( dummyElement.isElement(), true ); + CHECK( dummyElement.isDocument(), false ); + CHECK( dummyElement.ownerDocument().isNull(), false ); + CHECK( dummyElement.ownerDocument()==doc, false ); + CHECK( dummyElement.hasChildNodes(), false ); + CHECK( dummyElement==rootElement, false ); + CHECK( dummyElement!=rootElement, true ); + + // check for plain null node converted to element + KoXmlNode dummyNode; + dummyElement = dummyNode.toElement(); + CHECK( dummyElement.isNull(), true ); + CHECK( dummyElement.isElement(), true ); + CHECK( dummyElement.isDocument(), false ); + CHECK( dummyElement.ownerDocument().isNull(), false ); + CHECK( dummyElement.hasChildNodes(), false ); + CHECK( dummyElement.ownerDocument()==doc, false ); +} + +void testAttributes() +{ + QString errorMsg; + int errorLine = 0; + int errorColumn = 0; + + QByteArray xmlbuf; + QBuffer xmldevice( xmlbuf ); + + QTextStream xmlstream( xmlbuf, IO_WriteOnly ); + xmlstream << "<p>"; + xmlstream << "<img src=\"foo.png\" width=\"300\" height=\"150\"/>"; + xmlstream << "</p>"; + + KoXmlDocument doc; + CHECK( doc.setContent( &xmldevice, &errorMsg, &errorLine, &errorColumn ), true ); + CHECK( errorMsg.isEmpty(), true ); + CHECK( errorLine, 0 ); + CHECK( errorColumn, 0 ); + + KoXmlElement rootElement; + rootElement = doc.documentElement(); + CHECK( rootElement.isNull(), false ); + CHECK( rootElement.isElement(), true ); + CHECK( rootElement.parentNode().isNull(), false ); + CHECK( rootElement.parentNode().toDocument()==doc, true ); + CHECK( rootElement.tagName(), QString("p") ); + CHECK( rootElement.prefix().isNull(), true ); + + KoXmlElement imgElement; + imgElement = rootElement.firstChild().toElement(); + CHECK( imgElement.isNull(), false ); + CHECK( imgElement.isElement(), true ); + CHECK( imgElement.tagName(), QString("img") ); + CHECK( imgElement.prefix().isNull(), true ); + CHECK( imgElement.hasAttribute("src"), true ); + CHECK( imgElement.hasAttribute("width"), true ); + CHECK( imgElement.hasAttribute("height"), true ); + CHECK( imgElement.hasAttribute("non-exist"), false ); + CHECK( imgElement.hasAttribute("SRC"), false ); + CHECK( imgElement.attribute("src"), QString("foo.png") ); + CHECK( imgElement.attribute("width"), QString("300") ); + CHECK( imgElement.attribute("width").toInt(), 300 ); + CHECK( imgElement.attribute("height"), QString("150") ); + CHECK( imgElement.attribute("height").toInt(), 150 ); + CHECK( imgElement.attribute("border").isEmpty(), true ); + CHECK( imgElement.attribute("border","0").toInt(), 0 ); + CHECK( imgElement.attribute("border","-1").toInt(), -1 ); +} + +void testText() +{ + QString errorMsg; + int errorLine = 0; + int errorColumn = 0; + + QByteArray xmlbuf; + QBuffer xmldevice( xmlbuf ); + + QTextStream xmlstream( xmlbuf, IO_WriteOnly ); + xmlstream << "<p>"; + xmlstream << "Hello "; + xmlstream << "<b>world</b>"; + xmlstream << "</p>"; + + KoXmlDocument doc; + CHECK( doc.setContent( &xmldevice, &errorMsg, &errorLine, &errorColumn ), true ); + CHECK( errorMsg.isEmpty(), true ); + CHECK( errorLine, 0 ); + CHECK( errorColumn, 0 ); + + // element for <p> + KoXmlElement parElement; + parElement = doc.documentElement(); + CHECK( parElement.isNull(), false ); + CHECK( parElement.isElement(), true ); + CHECK( parElement.isText(), false ); + CHECK( parElement.isDocument(), false ); + CHECK( parElement.ownerDocument().isNull(), false ); + CHECK( parElement.ownerDocument()==doc, true ); + CHECK( parElement.parentNode().isNull(), false ); + CHECK( parElement.parentNode().toDocument()==doc, true ); + CHECK( parElement.hasChildNodes(), true ); + CHECK( parElement.tagName(), QString("p") ); + CHECK( parElement.prefix().isNull(), true ); + CHECK( parElement.text(), QString("Hello world") ); + + // node for "Hello" + KoXmlNode helloNode; + helloNode = parElement.firstChild(); + CHECK( helloNode.nodeName(), QString("#text") ); + CHECK( helloNode.isNull(), false ); + CHECK( helloNode.isElement(), false ); + CHECK( helloNode.isText(), true ); + CHECK( helloNode.isDocument(), false ); + + // "Hello" text + KoXmlText helloText; + helloText = helloNode.toText(); + CHECK( helloText.nodeName(), QString("#text") ); + CHECK( helloText.isNull(), false ); + CHECK( helloText.isElement(), false ); + CHECK( helloText.isText(), true ); + CHECK( helloText.isDocument(), false ); + CHECK( helloText.data(), QString("Hello ") ); + + // shared copy of the text + KoXmlText hello2Text; + hello2Text = helloText; + CHECK( hello2Text.isNull(), false ); + CHECK( hello2Text.isElement(), false ); + CHECK( hello2Text.isText(), true ); + CHECK( hello2Text.isDocument(), false ); + CHECK( hello2Text.data(), QString("Hello ") ); + + // element for <b> + KoXmlElement boldElement; + boldElement = helloNode.nextSibling().toElement(); + CHECK( boldElement.isNull(), false ); + CHECK( boldElement.isElement(), true ); + CHECK( boldElement.isText(), false ); + CHECK( boldElement.isDocument(), false ); + CHECK( boldElement.ownerDocument().isNull(), false ); + CHECK( boldElement.ownerDocument()==doc, true ); + CHECK( boldElement.parentNode().isNull(), false ); + CHECK( boldElement.hasChildNodes(), true ); + CHECK( boldElement.tagName(), QString("b") ); + CHECK( boldElement.prefix().isNull(), true ); + + // "world" text + KoXmlText worldText; + worldText = boldElement.firstChild().toText(); + CHECK( worldText.isNull(), false ); + CHECK( worldText.isElement(), false ); + CHECK( worldText.isText(), true ); + CHECK( worldText.isDocument(), false ); + CHECK( worldText.data(), QString("world") ); +} + +void testCDATA() +{ + QString errorMsg; + int errorLine = 0; + int errorColumn = 0; + + QByteArray xmlbuf; + QBuffer xmldevice( xmlbuf ); + + QTextStream xmlstream( xmlbuf, IO_WriteOnly ); + xmlstream << "<p>"; + xmlstream << "Hello "; + xmlstream << "<![CDATA[world]]>"; + xmlstream << "</p>"; + + KoXmlDocument doc; + CHECK( doc.setContent( &xmldevice, &errorMsg, &errorLine, &errorColumn ), true ); + CHECK( errorMsg.isEmpty(), true ); + CHECK( errorLine, 0 ); + CHECK( errorColumn, 0 ); + + // element for <p> + KoXmlElement parElement; + parElement = doc.documentElement(); + CHECK( parElement.isNull(), false ); + CHECK( parElement.isElement(), true ); + CHECK( parElement.isText(), false ); + CHECK( parElement.isDocument(), false ); + CHECK( parElement.ownerDocument().isNull(), false ); + CHECK( parElement.ownerDocument()==doc, true ); + CHECK( parElement.parentNode().isNull(), false ); + CHECK( parElement.parentNode().toDocument()==doc, true ); + CHECK( parElement.hasChildNodes(), true ); + CHECK( parElement.tagName(), QString("p") ); + CHECK( parElement.prefix().isNull(), true ); + CHECK( parElement.text(), QString("Hello world") ); + + // node for "Hello" + KoXmlNode helloNode; + helloNode = parElement.firstChild(); + CHECK( helloNode.isNull(), false ); + CHECK( helloNode.isElement(), false ); + CHECK( helloNode.isText(), true ); + CHECK( helloNode.isDocument(), false ); + + // "Hello" text + KoXmlText helloText; + helloText = helloNode.toText(); + CHECK( helloText.isNull(), false ); + CHECK( helloText.isElement(), false ); + CHECK( helloText.isText(), true ); + CHECK( helloText.isDocument(), false ); + CHECK( helloText.data(), QString("Hello ") ); + + // node for CDATA "world!" + // Note: isText() is also true for CDATA + KoXmlNode worldNode; + worldNode = helloNode.nextSibling(); + CHECK( worldNode.nodeName(), QString("#cdata-section") ); + CHECK( worldNode.isNull(), false ); + CHECK( worldNode.isElement(), false ); + CHECK( worldNode.isText(), true ); + CHECK( worldNode.isCDATASection(), true ); + CHECK( worldNode.isDocument(), false ); + + // CDATA section for "world!" + // Note: isText() is also true for CDATA + KoXmlCDATASection worldCDATA; + worldCDATA = worldNode.toCDATASection(); + CHECK( worldCDATA.nodeName(), QString("#cdata-section") ); + CHECK( worldCDATA.isNull(), false ); + CHECK( worldCDATA.isElement(), false ); + CHECK( worldCDATA.isText(), true ); + CHECK( worldCDATA.isCDATASection(), true ); + CHECK( worldCDATA.isDocument(), false ); + CHECK( worldCDATA.data(), QString("world") ); +} + +void testDocument() +{ + QString errorMsg; + int errorLine = 0; + int errorColumn = 0; + + QByteArray xmlbuf; + QBuffer xmldevice( xmlbuf ); + + QTextStream xmlstream( xmlbuf, IO_WriteOnly ); + xmlstream << "<koffice>"; + xmlstream << " <kword/>\n"; + xmlstream << " <kpresenter/>\n"; + xmlstream << " <krita/>\n"; + xmlstream << "</koffice>"; + + KoXmlDocument doc; + + // empty document + CHECK( doc.nodeName(), QString("#document") ); + CHECK( doc.isNull(), false ); + CHECK( doc.isElement(), false ); + CHECK( doc.isDocument(), true ); + CHECK( doc.parentNode().isNull(), true ); + CHECK( doc.firstChild().isNull(), true ); + CHECK( doc.lastChild().isNull(), true ); + CHECK( doc.previousSibling().isNull(), true ); + CHECK( doc.nextSibling().isNull(), true ); + + // now give something as the content + CHECK( doc.setContent(&xmldevice,&errorMsg,&errorLine,&errorColumn ), true ); + CHECK( errorMsg.isEmpty(), true ); + CHECK( errorLine, 0 ); + CHECK( errorColumn, 0 ); + + // this document has something already + CHECK( doc.nodeName(), QString("#document") ); + CHECK( doc.isNull(), false ); + CHECK( doc.isElement(), false ); + CHECK( doc.isDocument(), true ); + CHECK( doc.parentNode().isNull(), true ); + CHECK( doc.firstChild().isNull(), false ); + CHECK( doc.lastChild().isNull(), false ); + CHECK( doc.previousSibling().isNull(), true ); + CHECK( doc.nextSibling().isNull(), true ); + + // make sure its children are fine + KoXmlElement rootElement; + rootElement = doc.firstChild().toElement(); + CHECK( rootElement.isNull(), false ); + CHECK( rootElement.isElement(), true ); + CHECK( rootElement.isDocument(), false ); + CHECK( rootElement.parentNode().isNull(), false ); + CHECK( rootElement.parentNode().toDocument()==doc, true ); + rootElement = doc.lastChild().toElement(); + CHECK( rootElement.isNull(), false ); + CHECK( rootElement.isElement(), true ); + CHECK( rootElement.isDocument(), false ); + CHECK( rootElement.parentNode().isNull(), false ); + CHECK( rootElement.parentNode().toDocument()==doc, true ); + + // clear() converts it into null node + doc.clear(); + CHECK( doc.nodeName(), QString::null ); + CHECK( doc.isNull(), true ); + CHECK( doc.isElement(), false ); + CHECK( doc.isDocument(), true ); + CHECK( doc.parentNode().isNull(), true ); + CHECK( doc.firstChild().isNull(), true ); + CHECK( doc.lastChild().isNull(), true ); + CHECK( doc.previousSibling().isNull(), true ); + CHECK( doc.nextSibling().isNull(), true ); + + // assigned from another empty document + doc = KoXmlDocument(); + CHECK( doc.nodeName(), QString("#document") ); + CHECK( doc.isNull(), false ); + CHECK( doc.isElement(), false ); + CHECK( doc.isDocument(), true ); + CHECK( doc.parentNode().isNull(), true ); +} + +void testNamespace() +{ + QString errorMsg; + int errorLine = 0; + int errorColumn = 0; + + QByteArray xmlbuf; + QBuffer xmldevice( xmlbuf ); + QTextStream xmlstream( xmlbuf, IO_WriteOnly ); + + // taken from example in Qt documentation (xml.html) + xmlstream << "<document xmlns:book = \"http://trolltech.com/fnord/book/\""; + xmlstream << " xmlns = \"http://trolltech.com/fnord/\" >"; + xmlstream << "<book>"; + xmlstream << " <book:title>Practical XML</book:title>"; + xmlstream << " <book:author xmlns:fnord = \"http://trolltech.com/fnord/\""; + xmlstream << " title=\"Ms\""; + xmlstream << " fnord:title=\"Goddess\""; + xmlstream << " name=\"Eris Kallisti\"/>"; + xmlstream << " <chapter>"; + xmlstream << " <title>A Namespace Called fnord</title>"; + xmlstream << " </chapter>"; + xmlstream << "</book>"; + xmlstream << "</document>"; + + KoXmlDocument doc; + KoXmlElement rootElement; + KoXmlElement bookElement; + KoXmlElement bookTitleElement; + KoXmlElement bookAuthorElement; + + // ------------- first without any namespace processing ----------- + CHECK( doc.setContent( &xmldevice, &errorMsg, &errorLine, &errorColumn ), true ); + CHECK( errorMsg.isEmpty(), true ); + CHECK( errorLine, 0 ); + CHECK( errorColumn, 0 ); + + rootElement = doc.documentElement(); + CHECK( rootElement.isNull(), false ); + CHECK( rootElement.isElement(), true ); + CHECK( rootElement.tagName(), QString("document") ); + CHECK( rootElement.prefix().isNull(), true ); + + bookElement = rootElement.firstChild().toElement(); + CHECK( bookElement.isNull(), false ); + CHECK( bookElement.isElement(), true ); + CHECK( bookElement.tagName(), QString("book") ); + CHECK( bookElement.prefix().isNull(), true ); + CHECK( bookElement.localName(), QString::null ); + + bookTitleElement = bookElement.firstChild().toElement(); + CHECK( bookTitleElement.isNull(), false ); + CHECK( bookTitleElement.isElement(), true ); + CHECK( bookTitleElement.tagName(), QString("book:title") ); + CHECK( bookTitleElement.prefix().isNull(), true ); + CHECK( bookTitleElement.localName(), QString::null ); + + bookAuthorElement = bookTitleElement.nextSibling().toElement(); + CHECK( bookAuthorElement.isNull(), false ); + CHECK( bookAuthorElement.isElement(), true ); + CHECK( bookAuthorElement.tagName(), QString("book:author") ); + CHECK( bookAuthorElement.prefix().isNull(), true ); + CHECK( bookAuthorElement.attribute("title"), QString("Ms") ); + CHECK( bookAuthorElement.attribute("fnord:title"), QString("Goddess") ); + CHECK( bookAuthorElement.attribute("name"), QString("Eris Kallisti") ); + + // ------------- now with namespace processing ----------- + xmldevice.at(0); // just to rewind + + CHECK( doc.setContent( &xmldevice, true, &errorMsg, &errorLine, &errorColumn ), true ); + CHECK( errorMsg.isEmpty(), true ); + CHECK( errorLine, 0 ); + CHECK( errorColumn, 0 ); + + char* defaultNS = "http://trolltech.com/fnord/"; + char* bookNS = "http://trolltech.com/fnord/book/"; + char* fnordNS = "http://trolltech.com/fnord/"; + + // <document> + rootElement = doc.documentElement(); + CHECK( rootElement.isNull(), false ); + CHECK( rootElement.isElement(), true ); + CHECK( rootElement.tagName(), QString("document") ); + CHECK( rootElement.prefix().isEmpty(), true ); + CHECK( rootElement.namespaceURI(), QString( defaultNS ) ); + CHECK( rootElement.localName(), QString("document") ); + + // <book> + bookElement = rootElement.firstChild().toElement(); + CHECK( bookElement.isNull(), false ); + CHECK( bookElement.isElement(), true ); + CHECK( bookElement.tagName(), QString("book") ); + CHECK( bookElement.prefix().isEmpty(), true ); + CHECK( bookElement.namespaceURI(), QString( defaultNS ) ); + CHECK( bookElement.localName(), QString("book") ); + + // <book:title> + bookTitleElement = bookElement.firstChild().toElement(); + CHECK( bookTitleElement.isNull(), false ); + CHECK( bookTitleElement.isElement(), true ); + CHECK( bookTitleElement.tagName(), QString("title") ); + CHECK( bookTitleElement.prefix(), QString("book") ); + CHECK( bookTitleElement.namespaceURI(), QString(bookNS) ); + CHECK( bookTitleElement.localName(), QString("title") ); + + // another way, find it using namedItemNS() + KoXmlElement book2TitleElement; + book2TitleElement = KoXml::namedItemNS( rootElement.firstChild(), bookNS, "title" ); + //book2TitleElement = bookElement.namedItemNS( bookNS, "title" ).toElement(); + CHECK( book2TitleElement==bookTitleElement, true ); + CHECK( book2TitleElement.isNull(), false ); + CHECK( book2TitleElement.isElement(), true ); + CHECK( book2TitleElement.tagName(), QString("title") ); + + // <book:author> + bookAuthorElement = bookTitleElement.nextSibling().toElement(); + CHECK( bookAuthorElement.isNull(), false ); + CHECK( bookAuthorElement.isElement(), true ); + CHECK( bookAuthorElement.tagName(), QString("author") ); + CHECK( bookAuthorElement.prefix(), QString("book") ); + CHECK( bookAuthorElement.namespaceURI(), QString(bookNS) ); + CHECK( bookAuthorElement.localName(), QString("author") ); + + // another way, find it using namedItemNS() + KoXmlElement book2AuthorElement; + book2AuthorElement = KoXml::namedItemNS( bookElement, bookNS, "author" ); + //book2AuthorElement = bookElement.namedItemNS( bookNS, "author" ).toElement(); + CHECK( book2AuthorElement==bookAuthorElement, true ); + CHECK( book2AuthorElement.isNull(), false ); + CHECK( book2AuthorElement.isElement(), true ); + CHECK( book2AuthorElement.tagName(), QString("author") ); + + // attributes in <book:author> + // Note: with namespace processing, attribute's prefix is taken out and + // hence "fnord:title" will simply override "title" + // and searching attribute with prefix will give no result + CHECK( bookAuthorElement.hasAttribute("title"), true ); + CHECK( bookAuthorElement.hasAttribute("fnord:title"), false ); + CHECK( bookAuthorElement.hasAttribute("name"), true ); + CHECK( bookAuthorElement.attribute("title"), QString("Goddess") ); + CHECK( bookAuthorElement.attribute("fnord:title").isEmpty(), true ); + CHECK( bookAuthorElement.attribute("name"), QString("Eris Kallisti") ); + + // attributes in <book:author>, with NS family of functions + // those without prefix are not accessible at all, because they do not belong + // to any namespace at all. + // Note: default namespace does not apply to attribute names! + CHECK( bookAuthorElement.hasAttributeNS(defaultNS,"title"), true ); + CHECK( bookAuthorElement.hasAttributeNS(bookNS,"title"), false ); + CHECK( bookAuthorElement.hasAttributeNS(fnordNS,"title"), true ); + + CHECK( bookAuthorElement.attributeNS(defaultNS,"title",""), QString("Goddess") ); + CHECK( bookAuthorElement.attributeNS(bookNS,"title",""), QString("") ); + CHECK( bookAuthorElement.attributeNS(fnordNS,"title",""), QString("Goddess") ); + + CHECK( bookAuthorElement.hasAttributeNS(defaultNS,"fnord:title"), false ); + CHECK( bookAuthorElement.hasAttributeNS(bookNS,"fnord:title"), false ); + CHECK( bookAuthorElement.hasAttributeNS(fnordNS,"fnord:title"), false ); + + CHECK( bookAuthorElement.hasAttributeNS(defaultNS,"name"), false ); + CHECK( bookAuthorElement.hasAttributeNS(bookNS,"name"), false ); + CHECK( bookAuthorElement.hasAttributeNS(fnordNS,"name"), false ); + + CHECK( bookAuthorElement.attributeNS(defaultNS,"name",QString::null).isEmpty(), true ); + CHECK( bookAuthorElement.attributeNS(bookNS,"name",QString::null).isEmpty(), true ); + CHECK( bookAuthorElement.attributeNS(fnordNS,"name",QString::null).isEmpty(), true ); +} + +void testUnload() +{ + QString errorMsg; + int errorLine = 0; + int errorColumn = 0; + + QByteArray xmlbuf; + QBuffer xmldevice( xmlbuf ); + QTextStream xmlstream( xmlbuf, IO_WriteOnly ); + xmlstream << "<earth>"; + xmlstream << "<continents>"; + xmlstream << "<asia/>"; + xmlstream << "<africa/>"; + xmlstream << "<europe/>"; + xmlstream << "<america/>"; + xmlstream << "<australia/>"; + xmlstream << "<antartic/>"; + xmlstream << "</continents>"; + xmlstream << "<oceans>"; + xmlstream << "<pacific/>"; + xmlstream << "<atlantic/>"; + xmlstream << "</oceans>"; + xmlstream << "</earth>"; + + KoXmlDocument doc; + CHECK( doc.setContent( &xmldevice, &errorMsg, &errorLine, &errorColumn ), true ); + CHECK( errorMsg.isEmpty(), true ); + CHECK( errorLine, 0 ); + CHECK( errorColumn, 0 ); + + KoXmlElement earthElement; + earthElement = doc.documentElement().toElement(); + CHECK( earthElement.isNull(), false ); + CHECK( earthElement.isElement(), true ); + CHECK( earthElement.parentNode().isNull(), false ); + CHECK( earthElement.hasChildNodes(), true ); + CHECK( earthElement.tagName(), QString("earth") ); + CHECK( earthElement.prefix().isNull(), true ); + + // this ensures that all child nodes of <earth> are loaded + earthElement.firstChild(); + + // explicitly unload all child nodes of <earth> + KoXml::unload( earthElement ); + + // we should get the correct first child + KoXmlElement continentsElement = earthElement.firstChild().toElement(); + CHECK( continentsElement.nodeName(), QString("continents") ); + CHECK( continentsElement.isNull(), false ); + CHECK( continentsElement.isElement(), true ); + CHECK( continentsElement.isText(), false ); + CHECK( continentsElement.isDocument(), false ); + CHECK( continentsElement.hasChildNodes(), true ); + + // let us unload everything again + KoXml::unload( earthElement ); + + // we should get the correct last child + KoXmlElement oceansElement = earthElement.lastChild().toElement(); + CHECK( oceansElement.nodeName(), QString("oceans") ); + CHECK( oceansElement.isNull(), false ); + CHECK( oceansElement.isElement(), true ); + CHECK( oceansElement.isText(), false ); + CHECK( oceansElement.isDocument(), false ); + CHECK( oceansElement.hasChildNodes(), true ); +} + +void testSimpleXML() +{ + QString errorMsg; + int errorLine = 0; + int errorColumn = 0; + + QByteArray xmlbuf; + QBuffer xmldevice( xmlbuf ); + + QTextStream xmlstream( xmlbuf, IO_WriteOnly ); + xmlstream << "<solarsystem>"; + xmlstream << " <mercurius/>\n"; + xmlstream << " <venus/>\n"; + xmlstream << " <earth>\n"; + xmlstream << " <moon/>\n"; + xmlstream << " </earth>\n"; + xmlstream << " <mars/>\n"; + xmlstream << " <jupiter/>\n"; + xmlstream << "</solarsystem>"; + + KoXmlDocument doc; + CHECK( doc.setContent(&xmldevice,&errorMsg,&errorLine,&errorColumn ), true ); + CHECK( errorMsg.isEmpty(), true ); + CHECK( errorLine, 0 ); + CHECK( errorColumn, 0 ); + + // <solarsystem> + KoXmlElement rootElement; + rootElement = doc.documentElement(); + CHECK( rootElement.isNull(), false ); + CHECK( rootElement.isElement(), true ); + CHECK( rootElement.parentNode().isNull(), false ); + CHECK( rootElement.hasChildNodes(), true ); + CHECK( rootElement.tagName(), QString("solarsystem") ); + CHECK( rootElement.prefix().isNull(), true ); + + // node <mercurius> + KoXmlNode firstPlanetNode; + firstPlanetNode = rootElement.firstChild(); + CHECK( firstPlanetNode.isNull(), false ); + CHECK( firstPlanetNode.isElement(), true ); + CHECK( firstPlanetNode.nextSibling().isNull(), false ); + CHECK( firstPlanetNode.previousSibling().isNull(), true ); + CHECK( firstPlanetNode.parentNode().isNull(), false ); + CHECK( firstPlanetNode.parentNode()==rootElement, true ); + CHECK( firstPlanetNode.parentNode()!=rootElement, false ); + CHECK( firstPlanetNode.hasChildNodes(), false ); + CHECK( firstPlanetNode.firstChild().isNull(), true ); + CHECK( firstPlanetNode.lastChild().isNull(), true ); + + // element <mercurius> + KoXmlElement firstPlanetElement; + firstPlanetElement = firstPlanetNode.toElement(); + CHECK( firstPlanetElement.isNull(), false ); + CHECK( firstPlanetElement.isElement(), true ); + CHECK( firstPlanetElement.parentNode().isNull(), false ); + CHECK( firstPlanetElement.parentNode()==rootElement, true ); + CHECK( firstPlanetElement.hasChildNodes(), false ); + CHECK( firstPlanetElement.firstChild().isNull(), true ); + CHECK( firstPlanetElement.lastChild().isNull(), true ); + CHECK( firstPlanetElement.tagName(), QString("mercurius") ); + CHECK( firstPlanetElement.prefix().isNull(), true ); + + // node <venus> + KoXmlNode secondPlanetNode; + secondPlanetNode = firstPlanetNode.nextSibling(); + CHECK( secondPlanetNode.isNull(), false ); + CHECK( secondPlanetNode.isElement(), true ); + CHECK( secondPlanetNode.nextSibling().isNull(), false ); + CHECK( secondPlanetNode.previousSibling().isNull(), false ); + CHECK( secondPlanetNode.previousSibling()==firstPlanetNode, true ); + CHECK( secondPlanetNode.previousSibling()==firstPlanetElement, true ); + CHECK( secondPlanetNode.parentNode().isNull(), false ); + CHECK( secondPlanetNode.parentNode()==rootElement, true ); + CHECK( secondPlanetNode.parentNode()!=rootElement, false ); + CHECK( secondPlanetNode.hasChildNodes(), false ); + CHECK( secondPlanetNode.firstChild().isNull(), true ); + CHECK( secondPlanetNode.lastChild().isNull(), true ); + + // element <venus> + KoXmlElement secondPlanetElement; + secondPlanetElement = secondPlanetNode.toElement(); + CHECK( secondPlanetElement.isNull(), false ); + CHECK( secondPlanetElement.isElement(), true ); + CHECK( secondPlanetElement.nextSibling().isNull(), false ); + CHECK( secondPlanetElement.previousSibling().isNull(), false ); + CHECK( secondPlanetElement.previousSibling()==firstPlanetNode, true ); + CHECK( secondPlanetElement.previousSibling()==firstPlanetElement, true ); + CHECK( secondPlanetElement.parentNode().isNull(), false ); + CHECK( secondPlanetElement.parentNode()==rootElement, true ); + CHECK( secondPlanetElement.parentNode()!=rootElement, false ); + CHECK( secondPlanetElement.hasChildNodes(), false ); + CHECK( secondPlanetElement.firstChild().isNull(), true ); + CHECK( secondPlanetElement.lastChild().isNull(), true ); + CHECK( secondPlanetElement.tagName(), QString("venus") ); + CHECK( secondPlanetElement.prefix().isNull(), true ); +} + +void testRootError() +{ + QString errorMsg; + int errorLine = 0; + int errorColumn = 0; + + // multiple root nodes are not valid ! + QByteArray xmlbuf; + QBuffer xmldevice( xmlbuf ); + QTextStream xmlstream( xmlbuf, IO_WriteOnly ); + xmlstream << "<earth></earth><moon></moon>"; + + KoXmlDocument doc; + CHECK( doc.setContent( &xmldevice, &errorMsg, &errorLine, &errorColumn ), false ); + CHECK( errorMsg.isEmpty(), false ); + CHECK( errorMsg, QString("unexpected character") ); + CHECK( errorLine, 1 ); + CHECK( errorColumn, 17 ); +} + +void testMismatchedTag() +{ + QString errorMsg; + int errorLine = 0; + int errorColumn = 0; + + QByteArray xmlbuf; + QBuffer xmldevice( xmlbuf ); + QTextStream xmlstream( xmlbuf, IO_WriteOnly ); + xmlstream << "<earth></e>"; + + KoXmlDocument doc; + CHECK( doc.setContent( &xmldevice, &errorMsg, &errorLine, &errorColumn ), false ); + CHECK( errorMsg.isEmpty(), false ); + CHECK( errorMsg, QString("tag mismatch") ); + CHECK( errorLine, 1 ); + CHECK( errorColumn, 11 ); +} + +void testSimpleOpenDocumentText() +{ + QString errorMsg; + int errorLine = 0; + int errorColumn = 0; + + QByteArray xmlbuf; + QBuffer xmldevice( xmlbuf ); + QTextStream xmlstream( xmlbuf, IO_WriteOnly ); + + // content.xml from a simple OpenDocument text + // it has only paragraph "Hello, world!" + // automatic styles, declarations and unnecessary namespaces are omitted. + xmlstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; + xmlstream << "<office:document-content "; + xmlstream << " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\""; + xmlstream << " xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\""; + xmlstream << " xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" "; + xmlstream << " office:version=\"1.0\">"; + xmlstream << " <office:automatic-styles/>"; + xmlstream << " <office:body>"; + xmlstream << " <office:text>"; + xmlstream << " <text:p text:style-name=\"Standard\">Hello, world!</text:p>"; + xmlstream << " </office:text>"; + xmlstream << " </office:body>"; + xmlstream << "</office:document-content>"; + + KoXmlDocument doc; + CHECK( doc.setContent( &xmldevice, true, &errorMsg, &errorLine, &errorColumn ), true ); + CHECK( errorMsg.isEmpty(), true ); + CHECK( errorLine, 0 ); + CHECK( errorColumn, 0 ); + + char* officeNS = "urn:oasis:names:tc:opendocument:xmlns:office:1.0"; + char* textNS = "urn:oasis:names:tc:opendocument:xmlns:text:1.0"; + + // <office:document-content> + KoXmlElement contentElement; + contentElement = doc.documentElement(); + CHECK( contentElement.isNull(), false ); + CHECK( contentElement.isElement(), true ); + CHECK( contentElement.parentNode().isNull(), false ); + CHECK( contentElement.parentNode().toDocument()==doc, true ); + CHECK( contentElement.firstChild().isNull(), false ); + CHECK( contentElement.lastChild().isNull(), false ); + CHECK( contentElement.previousSibling().isNull(), false ); + CHECK( contentElement.nextSibling().isNull(), true ); + CHECK( contentElement.localName(), QString("document-content") ); + CHECK( contentElement.hasAttributeNS(officeNS,"version"), true ); + CHECK( contentElement.attributeNS(officeNS,"version",""), QString("1.0") ); + + // <office:automatic-styles> + KoXmlElement stylesElement; + stylesElement = KoXml::namedItemNS( contentElement, officeNS, "automatic-styles" ); + CHECK( stylesElement.isNull(), false ); + CHECK( stylesElement.isElement(), true ); + CHECK( stylesElement.parentNode().isNull(), false ); + CHECK( stylesElement.parentNode()==contentElement, true ); + CHECK( stylesElement.firstChild().isNull(), true ); + CHECK( stylesElement.lastChild().isNull(), true ); + CHECK( stylesElement.previousSibling().isNull(), true ); + CHECK( stylesElement.nextSibling().isNull(), false ); + CHECK( stylesElement.localName(), QString("automatic-styles") ); + + // also same <office:automatic-styles>, but without namedItemNS + KoXmlNode styles2Element; + styles2Element = contentElement.firstChild().toElement(); + CHECK( styles2Element.isNull(), false ); + CHECK( styles2Element.isElement(), true ); + CHECK( styles2Element.parentNode().isNull(), false ); + CHECK( styles2Element.parentNode()==contentElement, true ); + CHECK( styles2Element.firstChild().isNull(), true ); + CHECK( styles2Element.lastChild().isNull(), true ); + CHECK( styles2Element.previousSibling().isNull(), true ); + CHECK( styles2Element.nextSibling().isNull(), false ); + CHECK( styles2Element.localName(), QString("automatic-styles") ); + + // <office:body> + KoXmlElement bodyElement; + bodyElement = KoXml::namedItemNS( contentElement, officeNS, "body" ); + CHECK( bodyElement.isNull(), false ); + CHECK( bodyElement.isElement(), true ); + CHECK( bodyElement.parentNode().isNull(), false ); + CHECK( bodyElement.parentNode()==contentElement, true ); + CHECK( bodyElement.firstChild().isNull(), false ); + CHECK( bodyElement.lastChild().isNull(), false ); + CHECK( bodyElement.previousSibling().isNull(), false ); + CHECK( bodyElement.nextSibling().isNull(), true ); + CHECK( bodyElement.localName(), QString("body") ); + + // also same <office:body>, but without namedItemNS + KoXmlElement body2Element; + body2Element = stylesElement.nextSibling().toElement(); + CHECK( body2Element.isNull(), false ); + CHECK( body2Element.isElement(), true ); + CHECK( body2Element.parentNode().isNull(), false ); + CHECK( body2Element.parentNode()==contentElement, true ); + CHECK( body2Element.firstChild().isNull(), false ); + CHECK( body2Element.lastChild().isNull(), false ); + CHECK( body2Element.previousSibling().isNull(), false ); + CHECK( body2Element.nextSibling().isNull(), true ); + CHECK( body2Element.localName(), QString("body") ); + + // <office:text> + KoXmlElement textElement; + textElement = KoXml::namedItemNS( bodyElement, officeNS, "text" ); + CHECK( textElement.isNull(), false ); + CHECK( textElement.isElement(), true ); + CHECK( textElement.parentNode().isNull(), false ); + CHECK( textElement.parentNode()==bodyElement, true ); + CHECK( textElement.firstChild().isNull(), false ); + CHECK( textElement.lastChild().isNull(), false ); + CHECK( textElement.previousSibling().isNull(), true ); + CHECK( textElement.nextSibling().isNull(), true ); + CHECK( textElement.localName(), QString("text") ); + + // the same <office:text>, but without namedItemNS + KoXmlElement text2Element; + text2Element = bodyElement.firstChild().toElement(); + CHECK( text2Element.isNull(), false ); + CHECK( text2Element.isElement(), true ); + CHECK( text2Element.parentNode().isNull(), false ); + CHECK( text2Element.parentNode()==bodyElement, true ); + CHECK( text2Element.firstChild().isNull(), false ); + CHECK( text2Element.lastChild().isNull(), false ); + CHECK( text2Element.previousSibling().isNull(), true ); + CHECK( text2Element.nextSibling().isNull(), true ); + CHECK( text2Element.localName(), QString("text") ); + + // <text:p> + KoXmlElement parElement; + parElement = textElement.firstChild().toElement(); + CHECK( parElement.isNull(), false ); + CHECK( parElement.isElement(), true ); + CHECK( parElement.parentNode().isNull(), false ); + CHECK( parElement.parentNode()==textElement, true ); + CHECK( parElement.firstChild().isNull(), false ); + CHECK( parElement.lastChild().isNull(), false ); + CHECK( parElement.previousSibling().isNull(), true ); + CHECK( parElement.nextSibling().isNull(), true ); + CHECK( parElement.tagName(), QString("p") ); + CHECK( parElement.text(), QString("Hello, world!") ); + CHECK( parElement.attributeNS( QString(textNS),"style-name",""), QString("Standard") ); +} + +void testSimpleOpenDocumentSpreadsheet() +{ + QString errorMsg; + int errorLine = 0; + int errorColumn = 0; + + QByteArray xmlbuf; + QBuffer xmldevice( xmlbuf ); + QTextStream xmlstream( xmlbuf, IO_WriteOnly ); + + // content.xml from a simple OpenDocument spreadsheet + // the document has three worksheets, the last two are empty. + // on the first sheet, cell A1 contains the text "Hello, world". + // automatic styles, font declarations and unnecessary namespaces are omitted. + + xmlstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; + xmlstream << "<office:document-content "; + xmlstream << "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\""; + xmlstream << "xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" "; + xmlstream << "xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\">"; + xmlstream << "<office:body>"; + xmlstream << "<office:spreadsheet>"; + xmlstream << "<table:table table:name=\"Sheet1\" table:style-name=\"ta1\" table:print=\"false\">"; + xmlstream << "<table:table-column table:style-name=\"co1\" table:default-cell-style-name=\"Default\"/>"; + xmlstream << "<table:table-row table:style-name=\"ro1\">"; + xmlstream << "<table:table-cell office:value-type=\"string\">"; + xmlstream << "<text:p>Hello, world</text:p>"; + xmlstream << "</table:table-cell>"; + xmlstream << "</table:table-row>"; + xmlstream << "</table:table>"; + xmlstream << "<table:table table:name=\"Sheet2\" table:style-name=\"ta1\" table:print=\"false\">"; + xmlstream << "<table:table-column table:style-name=\"co1\" table:default-cell-style-name=\"Default\"/>"; + xmlstream << "<table:table-row table:style-name=\"ro1\">"; + xmlstream << "<table:table-cell/>"; + xmlstream << "</table:table-row>"; + xmlstream << "</table:table>"; + xmlstream << "<table:table table:name=\"Sheet3\" table:style-name=\"ta1\" table:print=\"false\">"; + xmlstream << "<table:table-column table:style-name=\"co1\" table:default-cell-style-name=\"Default\"/>"; + xmlstream << "<table:table-row table:style-name=\"ro1\">"; + xmlstream << "<table:table-cell/>"; + xmlstream << "</table:table-row>"; + xmlstream << "</table:table>"; + xmlstream << "</office:spreadsheet>"; + xmlstream << "</office:body>"; + xmlstream << "</office:document-content>"; + + KoXmlDocument doc; + CHECK( doc.setContent( &xmldevice, true, &errorMsg, &errorLine, &errorColumn ), true ); + CHECK( errorMsg.isEmpty(), true ); + CHECK( errorLine, 0 ); + CHECK( errorColumn, 0 ); + + QString officeNS = "urn:oasis:names:tc:opendocument:xmlns:office:1.0"; + QString tableNS = "urn:oasis:names:tc:opendocument:xmlns:table:1.0"; + QString textNS = "urn:oasis:names:tc:opendocument:xmlns:text:1.0"; + + // <office:document-content> + KoXmlElement contentElement; + contentElement = doc.documentElement(); + CHECK( contentElement.isNull(), false ); + CHECK( contentElement.isElement(), true ); + CHECK( contentElement.parentNode().isNull(), false ); + CHECK( contentElement.parentNode().toDocument()==doc, true ); + CHECK( contentElement.firstChild().isNull(), false ); + CHECK( contentElement.lastChild().isNull(), false ); + CHECK( contentElement.previousSibling().isNull(), false ); + CHECK( contentElement.nextSibling().isNull(), true ); + CHECK( contentElement.localName(), QString("document-content") ); + + // <office:body> + KoXmlElement bodyElement; + bodyElement = contentElement.firstChild().toElement(); + CHECK( bodyElement.isNull(), false ); + CHECK( bodyElement.isElement(), true ); + CHECK( bodyElement.parentNode().isNull(), false ); + CHECK( bodyElement.parentNode()==contentElement, true ); + CHECK( bodyElement.firstChild().isNull(), false ); + CHECK( bodyElement.lastChild().isNull(), false ); + CHECK( bodyElement.previousSibling().isNull(), true ); + CHECK( bodyElement.nextSibling().isNull(), true ); + CHECK( bodyElement.localName(), QString("body") ); + + // <office:spreadsheet> + KoXmlElement spreadsheetElement; + spreadsheetElement = bodyElement.firstChild().toElement(); + CHECK( spreadsheetElement.isNull(), false ); + CHECK( spreadsheetElement.isElement(), true ); + CHECK( spreadsheetElement.parentNode().isNull(), false ); + CHECK( spreadsheetElement.parentNode()==bodyElement, true ); + CHECK( spreadsheetElement.firstChild().isNull(), false ); + CHECK( spreadsheetElement.lastChild().isNull(), false ); + CHECK( spreadsheetElement.previousSibling().isNull(), true ); + CHECK( spreadsheetElement.nextSibling().isNull(), true ); + CHECK( spreadsheetElement.localName(), QString("spreadsheet") ); + + // <table:table> for Sheet1 + KoXmlElement sheet1Element; + sheet1Element = spreadsheetElement.firstChild().toElement(); + CHECK( sheet1Element.isNull(), false ); + CHECK( sheet1Element.isElement(), true ); + CHECK( sheet1Element.parentNode().isNull(), false ); + CHECK( sheet1Element.parentNode()==spreadsheetElement, true ); + CHECK( sheet1Element.firstChild().isNull(), false ); + CHECK( sheet1Element.lastChild().isNull(), false ); + CHECK( sheet1Element.previousSibling().isNull(), true ); + CHECK( sheet1Element.nextSibling().isNull(), false ); + CHECK( sheet1Element.tagName(), QString("table") ); + CHECK( sheet1Element.hasAttributeNS(tableNS,"name"), true ); + CHECK( sheet1Element.attributeNS(tableNS,"name",""), QString("Sheet1") ); + CHECK( sheet1Element.attributeNS(tableNS,"style-name",""), QString("ta1") ); + CHECK( sheet1Element.attributeNS(tableNS,"print",""), QString("false") ); + + KoXml::load( sheet1Element, 100 ); + + // <table:table-column> + KoXmlElement columnElement; + columnElement = sheet1Element.firstChild().toElement(); + CHECK( columnElement.isNull(), false ); + CHECK( columnElement.isElement(), true ); + CHECK( columnElement.parentNode().isNull(), false ); + CHECK( columnElement.parentNode()==sheet1Element, true ); + CHECK( columnElement.firstChild().isNull(), true ); + CHECK( columnElement.lastChild().isNull(), true ); + CHECK( columnElement.previousSibling().isNull(), true ); + CHECK( columnElement.nextSibling().isNull(), false ); + CHECK( columnElement.tagName(), QString("table-column") ); + CHECK( columnElement.attributeNS(tableNS,"style-name",""), QString("co1") ); + CHECK( columnElement.attributeNS(tableNS,"default-cell-style-name",""), QString("Default") ); + + // <table:table-row> + KoXmlElement rowElement; + rowElement = columnElement.nextSibling().toElement(); + CHECK( rowElement.isNull(), false ); + CHECK( rowElement.isElement(), true ); + CHECK( rowElement.parentNode().isNull(), false ); + CHECK( rowElement.parentNode()==sheet1Element, true ); + CHECK( rowElement.firstChild().isNull(), false ); + CHECK( rowElement.lastChild().isNull(), false ); + CHECK( rowElement.previousSibling().isNull(), false ); + CHECK( rowElement.nextSibling().isNull(), true ); + CHECK( rowElement.tagName(), QString("table-row") ); + CHECK( rowElement.attributeNS(tableNS,"style-name",""), QString("ro1") ); + + // <table:table-cell> + KoXmlElement cellElement; + cellElement = rowElement.firstChild().toElement(); + CHECK( cellElement.isNull(), false ); + CHECK( cellElement.isElement(), true ); + CHECK( cellElement.parentNode().isNull(), false ); + CHECK( cellElement.parentNode()==rowElement, true ); + CHECK( cellElement.firstChild().isNull(), false ); + CHECK( cellElement.lastChild().isNull(), false ); + CHECK( cellElement.previousSibling().isNull(), true ); + CHECK( cellElement.nextSibling().isNull(), true ); + CHECK( cellElement.tagName(), QString("table-cell") ); + CHECK( cellElement.attributeNS(officeNS,"value-type",""), QString("string") ); + + // <text:p> + KoXmlElement parElement; + parElement = cellElement.firstChild().toElement(); + CHECK( parElement.isNull(), false ); + CHECK( parElement.isElement(), true ); + CHECK( parElement.parentNode().isNull(), false ); + CHECK( parElement.parentNode()==cellElement, true ); + CHECK( parElement.firstChild().isNull(), false ); + CHECK( parElement.lastChild().isNull(), false ); + CHECK( parElement.previousSibling().isNull(), true ); + CHECK( parElement.nextSibling().isNull(), true ); + CHECK( parElement.tagName(), QString("p") ); + CHECK( parElement.text(), QString("Hello, world") ); + + // <table:table> for Sheet2 + KoXmlElement sheet2Element; + sheet2Element = sheet1Element.nextSibling().toElement(); + CHECK( sheet2Element.isNull(), false ); + CHECK( sheet2Element.isElement(), true ); + CHECK( sheet2Element.parentNode().isNull(), false ); + CHECK( sheet2Element.parentNode()==spreadsheetElement, true ); + CHECK( sheet2Element.firstChild().isNull(), false ); + CHECK( sheet2Element.lastChild().isNull(), false ); + CHECK( sheet2Element.previousSibling().isNull(), false ); + CHECK( sheet2Element.nextSibling().isNull(), false ); + CHECK( sheet2Element.tagName(), QString("table") ); + + // </table:table> for Sheet3 + KoXmlElement sheet3Element; + sheet3Element = sheet2Element.nextSibling().toElement(); + CHECK( sheet3Element.isNull(), false ); + CHECK( sheet3Element.isElement(), true ); + CHECK( sheet3Element.parentNode().isNull(), false ); + CHECK( sheet3Element.parentNode()==spreadsheetElement, true ); + CHECK( sheet3Element.firstChild().isNull(), false ); + CHECK( sheet3Element.lastChild().isNull(), false ); + CHECK( sheet3Element.previousSibling().isNull(), false ); + CHECK( sheet3Element.nextSibling().isNull(), true ); + CHECK( sheet3Element.tagName(), QString("table") ); +} + +void testSimpleOpenDocumentPresentation() +{ + QString errorMsg; + int errorLine = 0; + int errorColumn = 0; + + QByteArray xmlbuf; + QBuffer xmldevice( xmlbuf ); + QTextStream xmlstream( xmlbuf, IO_WriteOnly ); + + // content.xml from a simple OpenDocument presentation + // styles, declarations and unnecessary namespaces are omitted + // the first page is "Title" and has two text boxes + // the second page is + + xmlstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; + xmlstream << "<office:document-content "; + xmlstream << " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "; + xmlstream << " xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" "; + xmlstream << " xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\" "; + xmlstream << " xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\" "; + xmlstream << " xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\" "; + xmlstream << " office:version=\"1.0\">"; + xmlstream << " <office:scripts/>"; + xmlstream << " <office:automatic-styles/>"; + xmlstream << " <office:body>"; + xmlstream << " <office:presentation>"; + xmlstream << " <draw:page draw:name=\"Title\" draw:style-name=\"dp1\" "; + xmlstream << " draw:master-page-name=\"lyt-cool\" "; + xmlstream << " presentation:presentation-page-layout-name=\"AL1T0\">"; + xmlstream << " <draw:frame presentation:style-name=\"pr1\" "; + xmlstream << " draw:text-style-name=\"P2\" draw:layer=\"layout\" "; + xmlstream << " svg:width=\"23.912cm\" svg:height=\"3.508cm\" "; + xmlstream << " svg:x=\"2.058cm\" svg:y=\"1.543cm\" "; + xmlstream << " presentation:class=\"title\" "; + xmlstream << " presentation:user-transformed=\"true\">"; + xmlstream << " <draw:text-box>"; + xmlstream << " <text:p text:style-name=\"P1\">Foobar</text:p>"; + xmlstream << " </draw:text-box>"; + xmlstream << " </draw:frame>"; + xmlstream << " <draw:frame presentation:style-name=\"pr2\" "; + xmlstream << " draw:text-style-name=\"P3\" draw:layer=\"layout\""; + xmlstream << " svg:width=\"23.912cm\" svg:height=\"13.231cm\""; + xmlstream << " svg:x=\"2.058cm\" svg:y=\"5.838cm\" "; + xmlstream << " presentation:class=\"subtitle\">"; + xmlstream << " <draw:text-box>"; + xmlstream << " <text:p text:style-name=\"P3\">Foo</text:p>"; + xmlstream << " </draw:text-box>"; + xmlstream << " </draw:frame>"; + xmlstream << " <presentation:notes draw:style-name=\"dp2\">"; + xmlstream << " <draw:page-thumbnail draw:style-name=\"gr1\" draw:layer=\"layout\" svg:width=\"13.706cm\" svg:height=\"10.28cm\" svg:x=\"3.647cm\" svg:y=\"2.853cm\" draw:page-number=\"1\" presentation:class=\"page\"/>"; + xmlstream << " <draw:frame presentation:style-name=\"pr3\" draw:text-style-name=\"P1\" draw:layer=\"layout\" svg:width=\"14.518cm\" svg:height=\"11.411cm\" svg:x=\"3.249cm\" svg:y=\"14.13cm\" presentation:class=\"notes\" presentation:placeholder=\"true\">"; + xmlstream << " <draw:text-box/>"; + xmlstream << " </draw:frame>"; + xmlstream << " </presentation:notes>"; + xmlstream << " </draw:page>"; + xmlstream << " <presentation:settings presentation:stay-on-top=\"true\"/>"; + xmlstream << " </office:presentation>"; + xmlstream << " </office:body>"; + xmlstream << "</office:document-content>"; + + KoXmlDocument doc; + CHECK( doc.setContent( &xmldevice, true, &errorMsg, &errorLine, &errorColumn ), true ); + CHECK( errorMsg.isEmpty(), true ); + CHECK( errorLine, 0 ); + CHECK( errorColumn, 0 ); + + char* officeNS = "urn:oasis:names:tc:opendocument:xmlns:office:1.0"; + char* drawNS = "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"; + char* textNS = "urn:oasis:names:tc:opendocument:xmlns:text:1.0"; + char* presentationNS = "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"; + char* svgNS = "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"; + + // <office:document-content> + KoXmlElement contentElement; + contentElement = doc.documentElement(); + CHECK( contentElement.isNull(), false ); + + CHECK( contentElement.isElement(), true ); + CHECK( contentElement.parentNode().isNull(), false ); + CHECK( contentElement.parentNode().toDocument()==doc, true ); + CHECK( contentElement.firstChild().isNull(), false ); + CHECK( contentElement.lastChild().isNull(), false ); + CHECK( contentElement.previousSibling().isNull(), false ); + + CHECK( contentElement.nextSibling().isNull(), true ); + CHECK( contentElement.localName(), QString("document-content") ); + CHECK( contentElement.hasAttributeNS(officeNS,"version"), true ); + CHECK( contentElement.attributeNS(officeNS,"version",""), QString("1.0") ); + + // <office:scripts> + KoXmlElement scriptsElement; + scriptsElement = KoXml::namedItemNS( contentElement, officeNS, "scripts" ); + CHECK( scriptsElement.isNull(), false ); + CHECK( scriptsElement.isElement(), true ); + CHECK( scriptsElement.parentNode().isNull(), false ); + CHECK( scriptsElement.parentNode()==contentElement, true ); + CHECK( scriptsElement.firstChild().isNull(), true ); + CHECK( scriptsElement.lastChild().isNull(), true ); + CHECK( scriptsElement.previousSibling().isNull(), true ); + CHECK( scriptsElement.nextSibling().isNull(), false ); + CHECK( scriptsElement.localName(), QString("scripts") ); + + // <office:automatic-styles> + KoXmlElement stylesElement; + stylesElement = KoXml::namedItemNS( contentElement, officeNS, "automatic-styles" ); + CHECK( stylesElement.isNull(), false ); + CHECK( stylesElement.isElement(), true ); + CHECK( stylesElement.parentNode().isNull(), false ); + CHECK( stylesElement.parentNode()==contentElement, true ); + CHECK( stylesElement.firstChild().isNull(), true ); + CHECK( stylesElement.lastChild().isNull(), true ); + CHECK( stylesElement.previousSibling().isNull(), false ); + CHECK( stylesElement.nextSibling().isNull(), false ); + CHECK( stylesElement.localName(), QString("automatic-styles") ); + + // also same <office:automatic-styles>, but without namedItemNS + KoXmlNode styles2Element; + styles2Element = scriptsElement.nextSibling().toElement(); + CHECK( styles2Element.isNull(), false ); + CHECK( styles2Element.isElement(), true ); + CHECK( styles2Element.parentNode().isNull(), false ); + CHECK( styles2Element.parentNode()==contentElement, true ); + CHECK( styles2Element.firstChild().isNull(), true ); + CHECK( styles2Element.lastChild().isNull(), true ); + CHECK( styles2Element.previousSibling().isNull(), false ); + CHECK( styles2Element.nextSibling().isNull(), false ); + CHECK( styles2Element.localName(), QString("automatic-styles") ); + + // <office:body> + KoXmlElement bodyElement; + bodyElement = KoXml::namedItemNS( contentElement, officeNS, "body" ); + CHECK( bodyElement.isNull(), false ); + CHECK( bodyElement.isElement(), true ); + CHECK( bodyElement.parentNode().isNull(), false ); + CHECK( bodyElement.parentNode()==contentElement, true ); + CHECK( bodyElement.firstChild().isNull(), false ); + CHECK( bodyElement.lastChild().isNull(), false ); + CHECK( bodyElement.previousSibling().isNull(), false ); + CHECK( bodyElement.nextSibling().isNull(), true ); + CHECK( bodyElement.localName(), QString("body") ); + + // also same <office:body>, but without namedItemNS + KoXmlElement body2Element; + body2Element = stylesElement.nextSibling().toElement(); + CHECK( body2Element.isNull(), false ); + CHECK( body2Element.isElement(), true ); + CHECK( body2Element.parentNode().isNull(), false ); + CHECK( body2Element.parentNode()==contentElement, true ); + CHECK( body2Element.firstChild().isNull(), false ); + CHECK( body2Element.lastChild().isNull(), false ); + CHECK( body2Element.previousSibling().isNull(), false ); + CHECK( body2Element.nextSibling().isNull(), true ); + CHECK( body2Element.localName(), QString("body") ); + + // <office:presentation> + KoXmlElement presentationElement; + presentationElement = KoXml::namedItemNS( bodyElement, officeNS, "presentation" ); + CHECK( presentationElement.isNull(), false ); + CHECK( presentationElement.isElement(), true ); + CHECK( presentationElement.parentNode().isNull(), false ); + CHECK( presentationElement.parentNode()==bodyElement, true ); + CHECK( presentationElement.firstChild().isNull(), false ); + CHECK( presentationElement.lastChild().isNull(), false ); + CHECK( presentationElement.previousSibling().isNull(), true ); + CHECK( presentationElement.nextSibling().isNull(), true ); + CHECK( presentationElement.localName(), QString("presentation") ); + + // the same <office:presentation>, but without namedItemNS + KoXmlElement presentation2Element; + presentation2Element = bodyElement.firstChild().toElement(); + CHECK( presentation2Element.isNull(), false ); + CHECK( presentation2Element.isElement(), true ); + CHECK( presentation2Element.parentNode().isNull(), false ); + CHECK( presentation2Element.parentNode()==bodyElement, true ); + CHECK( presentation2Element.firstChild().isNull(), false ); + CHECK( presentation2Element.lastChild().isNull(), false ); + CHECK( presentation2Element.previousSibling().isNull(), true ); + CHECK( presentation2Element.nextSibling().isNull(), true ); + CHECK( presentation2Element.localName(), QString("presentation") ); + + // <draw:page> for "Title" + KoXmlElement titlePageElement; + titlePageElement = presentationElement.firstChild().toElement(); + CHECK( titlePageElement.isNull(), false ); + CHECK( titlePageElement.isElement(), true ); + CHECK( titlePageElement.parentNode().isNull(), false ); + CHECK( titlePageElement.parentNode()==presentationElement, true ); + CHECK( titlePageElement.firstChild().isNull(), false ); + CHECK( titlePageElement.lastChild().isNull(), false ); + CHECK( titlePageElement.previousSibling().isNull(), true ); + CHECK( titlePageElement.nextSibling().isNull(), false ); + CHECK( titlePageElement.localName(), QString("page") ); + CHECK( titlePageElement.attributeNS(drawNS,"name",""), QString("Title") ); + CHECK( titlePageElement.attributeNS(drawNS,"style-name",""), QString("dp1") ); + CHECK( titlePageElement.attributeNS(drawNS,"master-page-name",""), QString("lyt-cool") ); + CHECK( titlePageElement.attributeNS(presentationNS, + "presentation-page-layout-name",""), QString("AL1T0") ); + + // <draw:frame> for the title frame + KoXmlElement titleFrameElement; + titleFrameElement = titlePageElement.firstChild().toElement(); + CHECK( titleFrameElement.isNull(), false ); + CHECK( titleFrameElement.isElement(), true ); + CHECK( titleFrameElement.parentNode().isNull(), false ); + CHECK( titleFrameElement.parentNode()==titlePageElement, true ); + CHECK( titleFrameElement.firstChild().isNull(), false ); + CHECK( titleFrameElement.lastChild().isNull(), false ); + CHECK( titleFrameElement.previousSibling().isNull(), true ); + CHECK( titleFrameElement.nextSibling().isNull(), false ); + CHECK( titleFrameElement.localName(), QString("frame") ); + CHECK( titleFrameElement.attributeNS(presentationNS,"style-name",""), QString("pr1") ); + CHECK( titleFrameElement.attributeNS(presentationNS,"class",""), QString("title") ); + CHECK( titleFrameElement.attributeNS(presentationNS,"user-transformed",""), QString("true") ); + CHECK( titleFrameElement.attributeNS(drawNS,"text-style-name",""), QString("P2") ); + CHECK( titleFrameElement.attributeNS(drawNS,"layer",""), QString("layout") ); + CHECK( titleFrameElement.attributeNS(svgNS,"width",""), QString("23.912cm") ); + CHECK( titleFrameElement.attributeNS(svgNS,"height",""), QString("3.508cm") ); + CHECK( titleFrameElement.attributeNS(svgNS,"x",""), QString("2.058cm") ); + CHECK( titleFrameElement.attributeNS(svgNS,"y",""), QString("1.543cm") ); + + // <draw:text-box> of the title frame + KoXmlElement titleBoxElement; + titleBoxElement = titleFrameElement.firstChild().toElement(); + CHECK( titleBoxElement.isNull(), false ); + CHECK( titleBoxElement.isElement(), true ); + CHECK( titleBoxElement.parentNode().isNull(), false ); + CHECK( titleBoxElement.parentNode()==titleFrameElement, true ); + CHECK( titleBoxElement.firstChild().isNull(), false ); + CHECK( titleBoxElement.lastChild().isNull(), false ); + CHECK( titleBoxElement.previousSibling().isNull(), true ); + CHECK( titleBoxElement.nextSibling().isNull(), true ); + CHECK( titleBoxElement.localName(), QString("text-box") ); + + // <text:p> for the title text-box + KoXmlElement titleParElement; + titleParElement = titleBoxElement.firstChild().toElement(); + CHECK( titleParElement.isNull(), false ); + CHECK( titleParElement.isElement(), true ); + CHECK( titleParElement.parentNode().isNull(), false ); + CHECK( titleParElement.parentNode()==titleBoxElement, true ); + CHECK( titleParElement.firstChild().isNull(), false ); + CHECK( titleParElement.lastChild().isNull(), false ); + CHECK( titleParElement.previousSibling().isNull(), true ); + CHECK( titleParElement.nextSibling().isNull(), true ); + CHECK( titleParElement.localName(), QString("p") ); + CHECK( titleParElement.attributeNS(textNS,"style-name",""), QString("P1") ); + CHECK( titleParElement.text(), QString("Foobar") ); + + // <draw:frame> for the subtitle frame + KoXmlElement subtitleFrameElement; + subtitleFrameElement = titleFrameElement.nextSibling().toElement(); + CHECK( subtitleFrameElement.isNull(), false ); + CHECK( subtitleFrameElement.isElement(), true ); + CHECK( subtitleFrameElement.parentNode().isNull(), false ); + CHECK( subtitleFrameElement.parentNode()==titlePageElement, true ); + CHECK( subtitleFrameElement.firstChild().isNull(), false ); + CHECK( subtitleFrameElement.lastChild().isNull(), false ); + CHECK( subtitleFrameElement.previousSibling().isNull(), false ); + CHECK( subtitleFrameElement.nextSibling().isNull(), false ); + CHECK( subtitleFrameElement.localName(), QString("frame") ); + CHECK( subtitleFrameElement.attributeNS(presentationNS,"style-name",""), QString("pr2") ); + CHECK( subtitleFrameElement.attributeNS(presentationNS,"class",""), QString("subtitle") ); + CHECK( subtitleFrameElement.hasAttributeNS(presentationNS,"user-transformed"), false ); + CHECK( subtitleFrameElement.attributeNS(drawNS,"text-style-name",""), QString("P3") ); + CHECK( subtitleFrameElement.attributeNS(drawNS,"layer",""), QString("layout") ); + CHECK( subtitleFrameElement.attributeNS(svgNS,"width",""), QString("23.912cm") ); + CHECK( subtitleFrameElement.attributeNS(svgNS,"height",""), QString("13.231cm") ); + CHECK( subtitleFrameElement.attributeNS(svgNS,"x",""), QString("2.058cm") ); + CHECK( subtitleFrameElement.attributeNS(svgNS,"y",""), QString("5.838cm") ); + + // <draw:text-box> of the subtitle frame + KoXmlElement subtitleBoxElement; + subtitleBoxElement = subtitleFrameElement.firstChild().toElement(); + CHECK( subtitleBoxElement.isNull(), false ); + CHECK( subtitleBoxElement.isElement(), true ); + CHECK( subtitleBoxElement.parentNode().isNull(), false ); + CHECK( subtitleBoxElement.parentNode()==subtitleFrameElement, true ); + CHECK( subtitleBoxElement.firstChild().isNull(), false ); + CHECK( subtitleBoxElement.lastChild().isNull(), false ); + CHECK( subtitleBoxElement.previousSibling().isNull(), true ); + CHECK( subtitleBoxElement.nextSibling().isNull(), true ); + CHECK( subtitleBoxElement.localName(), QString("text-box") ); + + // <text:p> for the subtitle text-box + KoXmlElement subtitleParElement; + subtitleParElement = subtitleBoxElement.firstChild().toElement(); + CHECK( subtitleParElement.isNull(), false ); + CHECK( subtitleParElement.isElement(), true ); + CHECK( subtitleParElement.parentNode().isNull(), false ); + CHECK( subtitleParElement.parentNode()==subtitleBoxElement, true ); + CHECK( subtitleParElement.firstChild().isNull(), false ); + CHECK( subtitleParElement.lastChild().isNull(), false ); + CHECK( subtitleParElement.previousSibling().isNull(), true ); + CHECK( subtitleParElement.nextSibling().isNull(), true ); + CHECK( subtitleParElement.localName(), QString("p") ); + CHECK( subtitleParElement.attributeNS(textNS,"style-name",""), QString("P3") ); + CHECK( subtitleParElement.text(), QString("Foo") ); +} + +void testSimpleOpenDocumentFormula() +{ + QString errorMsg; + int errorLine = 0; + int errorColumn = 0; + + QByteArray xmlbuf; + QBuffer xmldevice( xmlbuf ); + QTextStream xmlstream( xmlbuf, IO_WriteOnly ); + + // content.xml from a simple OpenDocument formula + // this is essentially MathML + xmlstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; + xmlstream << "<!DOCTYPE math:math PUBLIC \"-//OpenOffice.org//DTD Modified W3C MathML 1.01//EN\" \"math.dtd\">"; + xmlstream << "<math:math xmlns:math=\"http://www.w3.org/1998/Math/MathML\">"; + xmlstream << " <math:semantics>"; + xmlstream << " <math:mrow>"; + xmlstream << " <math:mi>E</math:mi>"; + xmlstream << " <math:mo math:stretchy=\"false\">=</math:mo>"; + xmlstream << " <math:msup>"; + xmlstream << " <math:mi math:fontstyle=\"italic\">mc</math:mi>"; + xmlstream << " <math:mn>2</math:mn>"; + xmlstream << " </math:msup>"; + xmlstream << " </math:mrow>"; + xmlstream << " <math:annotation math:encoding=\"StarMath 5.0\">E = mc^2 </math:annotation>"; + xmlstream << " </math:semantics>"; + xmlstream << "</math:math>"; + + KoXmlDocument doc; + CHECK( doc.setContent( &xmldevice, true, &errorMsg, &errorLine, &errorColumn ), true ); + CHECK( errorMsg.isEmpty(), true ); + CHECK( errorLine, 0 ); + CHECK( errorColumn, 0 ); + + char* mathNS = "http://www.w3.org/1998/Math/MathML"; + + // <math:math> + KoXmlElement mathElement; + mathElement = doc.documentElement(); + CHECK( mathElement.isNull(), false ); + CHECK( mathElement.isElement(), true ); + CHECK( mathElement.parentNode().isNull(), false ); + CHECK( mathElement.parentNode().toDocument()==doc, true ); + CHECK( mathElement.firstChild().isNull(), false ); + CHECK( mathElement.lastChild().isNull(), false ); + CHECK( mathElement.previousSibling().isNull(), false ); + CHECK( mathElement.nextSibling().isNull(), true ); + CHECK( mathElement.localName(), QString("math") ); + + // <math:semantics> + KoXmlElement semanticsElement; + semanticsElement = KoXml::namedItemNS( mathElement, mathNS, "semantics" ); + CHECK( semanticsElement.isNull(), false ); + CHECK( semanticsElement.isElement(), true ); + CHECK( semanticsElement.parentNode().isNull(), false ); + CHECK( semanticsElement.parentNode().toElement()==mathElement, true ); + CHECK( semanticsElement.firstChild().isNull(), false ); + CHECK( semanticsElement.lastChild().isNull(), false ); + CHECK( semanticsElement.previousSibling().isNull(), true ); + CHECK( semanticsElement.nextSibling().isNull(), true ); + CHECK( semanticsElement.localName(), QString("semantics") ); + + // the same <math:semantics> but without namedItemNS + KoXmlElement semantics2Element; + semantics2Element = mathElement.firstChild().toElement(); + CHECK( semantics2Element.isNull(), false ); + CHECK( semantics2Element.isElement(), true ); + CHECK( semantics2Element.parentNode().isNull(), false ); + CHECK( semantics2Element.parentNode().toElement()==mathElement, true ); + CHECK( semantics2Element.firstChild().isNull(), false ); + CHECK( semantics2Element.lastChild().isNull(), false ); + CHECK( semantics2Element.previousSibling().isNull(), true ); + CHECK( semantics2Element.nextSibling().isNull(), true ); + CHECK( semantics2Element.localName(), QString("semantics") ); + + // <math:mrow> + KoXmlElement mrowElement; + mrowElement = semanticsElement.firstChild().toElement(); + CHECK( mrowElement.isNull(), false ); + CHECK( mrowElement.isElement(), true ); + CHECK( mrowElement.parentNode().isNull(), false ); + CHECK( mrowElement.parentNode().toElement()==semanticsElement, true ); + CHECK( mrowElement.firstChild().isNull(), false ); + CHECK( mrowElement.lastChild().isNull(), false ); + CHECK( mrowElement.previousSibling().isNull(), true ); + CHECK( mrowElement.nextSibling().isNull(), false ); + CHECK( mrowElement.localName(), QString("mrow") ); + + // <math:mi> for "E" + KoXmlElement miElement; + miElement = mrowElement.firstChild().toElement(); + CHECK( miElement.isNull(), false ); + CHECK( miElement.isElement(), true ); + CHECK( miElement.parentNode().isNull(), false ); + CHECK( miElement.parentNode().toElement()==mrowElement, true ); + CHECK( miElement.firstChild().isNull(), false ); + CHECK( miElement.lastChild().isNull(), false ); + CHECK( miElement.previousSibling().isNull(), true ); + CHECK( miElement.nextSibling().isNull(), false ); + CHECK( miElement.localName(), QString("mi") ); + + // <math:mo> for "=" + KoXmlElement moElement; + moElement = miElement.nextSibling().toElement(); + CHECK( moElement.isNull(), false ); + CHECK( moElement.isElement(), true ); + CHECK( moElement.parentNode().isNull(), false ); + CHECK( moElement.parentNode().toElement()==mrowElement, true ); + CHECK( moElement.firstChild().isNull(), false ); + CHECK( moElement.lastChild().isNull(), false ); + CHECK( moElement.previousSibling().isNull(), false ); + CHECK( moElement.nextSibling().isNull(), false ); + CHECK( moElement.localName(), QString("mo") ); + CHECK( moElement.attributeNS(mathNS,"stretchy",""), QString("false") ); + + // <math:msup> for "mc" and superscripted "2" + KoXmlElement msupElement; + msupElement = moElement.nextSibling().toElement(); + CHECK( msupElement.isNull(), false ); + CHECK( msupElement.isElement(), true ); + CHECK( msupElement.parentNode().isNull(), false ); + CHECK( msupElement.parentNode().toElement()==mrowElement, true ); + CHECK( msupElement.firstChild().isNull(), false ); + CHECK( msupElement.lastChild().isNull(), false ); + CHECK( msupElement.previousSibling().isNull(), false ); + CHECK( msupElement.nextSibling().isNull(), true ); + CHECK( msupElement.localName(), QString("msup") ); + + // <math:mi> inside the <math:msup> for "mc" + KoXmlElement mcElement; + mcElement = msupElement.firstChild().toElement(); + CHECK( mcElement.isNull(), false ); + CHECK( mcElement.isElement(), true ); + CHECK( mcElement.parentNode().isNull(), false ); + CHECK( mcElement.parentNode().toElement()==msupElement, true ); + CHECK( mcElement.firstChild().isNull(), false ); + CHECK( mcElement.lastChild().isNull(), false ); + CHECK( mcElement.previousSibling().isNull(), true ); + CHECK( mcElement.nextSibling().isNull(), false ); + CHECK( mcElement.localName(), QString("mi") ); + CHECK( mcElement.text(), QString("mc") ); + CHECK( mcElement.attributeNS(mathNS,"fontstyle",""), QString("italic") ); + + // <math:mn> inside the <math:msup> for "2" (superscript) + KoXmlElement mnElement; + mnElement = mcElement.nextSibling().toElement(); + CHECK( mnElement.isNull(), false ); + CHECK( mnElement.isElement(), true ); + CHECK( mnElement.parentNode().isNull(), false ); + CHECK( mnElement.parentNode().toElement()==msupElement, true ); + CHECK( mnElement.firstChild().isNull(), false ); + CHECK( mnElement.lastChild().isNull(), false ); + CHECK( mnElement.previousSibling().isNull(), false ); + CHECK( mnElement.nextSibling().isNull(), true ); + CHECK( mnElement.localName(), QString("mn") ); + CHECK( mnElement.text(), QString("2") ); + + // <math:annotation> + KoXmlElement annotationElement; + annotationElement = semanticsElement.lastChild().toElement(); + CHECK( annotationElement.isNull(), false ); + CHECK( annotationElement.isElement(), true ); + CHECK( annotationElement.parentNode().isNull(), false ); + CHECK( annotationElement.parentNode().toElement()==semanticsElement, true ); + CHECK( annotationElement.firstChild().isNull(), false ); + CHECK( annotationElement.lastChild().isNull(), false ); + CHECK( annotationElement.previousSibling().isNull(), false ); + CHECK( annotationElement.nextSibling().isNull(), true ); + CHECK( annotationElement.localName(), QString("annotation") ); + CHECK( annotationElement.text(), QString("E = mc^2 ") ); + CHECK( annotationElement.attributeNS(mathNS,"encoding",""), QString("StarMath 5.0") ); +} + +void testLargeOpenDocumentSpreadsheet() +{ + QString errorMsg; + int errorLine = 0; + int errorColumn = 0; + + int sheetCount = 4; + int rowCount = 200; + int colCount = 200*2; + + QByteArray xmlbuf; + QBuffer xmldevice( xmlbuf ); + QTextStream xmlstream( xmlbuf, IO_WriteOnly ); + + // content.xml + xmlstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; + xmlstream << "<office:document-content "; + xmlstream << "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "; + xmlstream << "xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" "; + xmlstream << "xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" >"; + xmlstream << "<office:body>"; + xmlstream << "<office:spreadsheet>"; + for( int i = 0; i < sheetCount; i++ ) + { + QString sheetName = QString("Sheet%1").arg(i+1); + xmlstream << "<table:table table:name=\"" << sheetName; + xmlstream << "\" table:print=\"false\">"; + for( int j = 0; j < rowCount; j++ ) + { + xmlstream << "<table:table-row>"; + for( int k = 0; k < colCount; k++ ) + { + xmlstream << "<table:table-cell office:value-type=\"string\">"; + xmlstream << "<text:p>Hello, world</text:p>"; + xmlstream << "</table:table-cell>"; + } + xmlstream << "</table:table-row>"; + } + xmlstream << "</table:table>"; + } + xmlstream << "</office:spreadsheet>"; + xmlstream << "</office:body>"; + xmlstream << "</office:document-content>"; + + printf("Raw XML size: %d KB\n", xmlbuf.size()/1024 ); + + QTime timer; + timer.start(); + +#if 1 + // just to test parsing speed with plain dumb handler + QXmlSimpleReader* reader = new QXmlSimpleReader; + reader->setFeature( "http://xml.org/sax/features/namespaces", true ); + QXmlDefaultHandler handler; + reader->setContentHandler( &handler ); + reader->setErrorHandler( &handler ); + reader->setLexicalHandler( &handler ); + reader->setDeclHandler( &handler ); + reader->setDTDHandler( &handler ); + QXmlInputSource xmlSource; + xmlSource.setData( QString::fromUtf8( xmlbuf.data(), xmlbuf.size() ) ); + timer.start(); + reader->parse( &xmlSource ); + printf("Large spreadsheet: QXmlDefaultHandler parsing time is %d ms\n", timer.elapsed() ); + delete reader; +#endif + + timer.start(); + KoXmlDocument doc; + + // uncomment to see the performance if on-demand/lazy loading is not used + // will definitely eat more memory +#ifndef KOXML_USE_QDOM + doc.setFastLoading( true ); +#endif + + CHECK( doc.setContent( &xmldevice, true, &errorMsg, &errorLine, &errorColumn ), true ); + CHECK( errorMsg.isEmpty(), true ); + CHECK( errorLine, 0 ); + CHECK( errorColumn, 0 ); + + printf("Large spreadsheet: parsing time is %d ms\n", timer.elapsed() ); + + // release memory taken by the XML document content + xmlbuf.resize( 0 ); + + // namespaces that will be used + QString officeNS = "urn:oasis:names:tc:opendocument:xmlns:office:1.0"; + QString tableNS = "urn:oasis:names:tc:opendocument:xmlns:table:1.0"; + QString textNS = "urn:oasis:names:tc:opendocument:xmlns:text:1.0"; + + // <office:document-content> + KoXmlElement contentElement; + contentElement = doc.documentElement(); + CHECK( contentElement.isNull(), false ); + CHECK( contentElement.isElement(), true ); + CHECK( contentElement.localName(), QString("document-content") ); + + // <office:body> + KoXmlElement bodyElement; + bodyElement = contentElement.firstChild().toElement(); + CHECK( bodyElement.isNull(), false ); + CHECK( bodyElement.isElement(), true ); + CHECK( bodyElement.localName(), QString("body") ); + + // <office:spreadsheet> + KoXmlElement spreadsheetElement; + spreadsheetElement = bodyElement.firstChild().toElement(); + CHECK( spreadsheetElement.isNull(), false ); + CHECK( spreadsheetElement.isElement(), true ); + CHECK( spreadsheetElement.localName(), QString("spreadsheet") ); + + // now we visit every sheet, every row, every cell + timer.start(); + KoXmlElement tableElement; + tableElement = spreadsheetElement.firstChild().toElement(); + for( int table=0; table < sheetCount; table++ ) + { + QString tableName = QString("Sheet%1").arg(table+1); + CHECK( tableElement.isNull(), false ); + CHECK( tableElement.isElement(), true ); + CHECK( tableElement.localName(), QString("table") ); + CHECK( tableElement.hasAttributeNS(tableNS,"name"), true ); + CHECK( tableElement.attributeNS(tableNS,"name",""), tableName ); + CHECK( tableElement.attributeNS(tableNS,"print",""), QString("false") ); + + // load everything for this table + KoXml::load( tableElement, 99 ); + + CHECK( tableElement.parentNode().isNull(), false ); + CHECK( tableElement.parentNode()==spreadsheetElement, true ); + CHECK( tableElement.firstChild().isNull(), false ); + CHECK( tableElement.lastChild().isNull(), false ); + + KoXmlElement rowElement; + rowElement = tableElement.firstChild().toElement(); + for( int row=0; row < rowCount; row++ ) + { + CHECK( rowElement.isNull(), false ); + CHECK( rowElement.isElement(), true ); + CHECK( rowElement.localName(), QString("table-row") ); + CHECK( rowElement.parentNode().isNull(), false ); + CHECK( rowElement.parentNode()==tableElement, true ); + CHECK( rowElement.firstChild().isNull(), false ); + CHECK( rowElement.lastChild().isNull(), false ); + + KoXmlElement cellElement; + cellElement = rowElement.firstChild().toElement(); + for( int col=0; col < colCount; col++ ) + { + CHECK( cellElement.isNull(), false ); + CHECK( cellElement.isElement(), true ); + CHECK( cellElement.localName(), QString("table-cell") ); + CHECK( cellElement.text(), QString("Hello, world") ); + CHECK( cellElement.hasAttributeNS(officeNS,"value-type"), true ); + CHECK( cellElement.attributeNS(officeNS,"value-type",""), QString("string" ) ); + CHECK( cellElement.parentNode().isNull(), false ); + CHECK( cellElement.parentNode()==rowElement, true ); + CHECK( cellElement.firstChild().isNull(), false ); + CHECK( cellElement.lastChild().isNull(), false ); + cellElement = cellElement.nextSibling().toElement(); + } + + //KoXml::unload( rowElement ); + rowElement = rowElement.nextSibling().toElement(); + } + + KoXml::unload( tableElement ); + tableElement = tableElement.nextSibling().toElement(); + } + + printf("Large spreadsheet: iterating time is %d ms\n", timer.elapsed() ); +} + +int main( int argc, char** argv ) +{ + Q_UNUSED( argc ); + Q_UNUSED( argv ); + + testNode(); + testElement(); + testAttributes(); + testText(); + testCDATA(); + testDocument(); + testNamespace(); + + testUnload(); + + testSimpleXML(); + testRootError(); + testMismatchedTag(); + + testSimpleOpenDocumentText(); + testSimpleOpenDocumentSpreadsheet(); + testSimpleOpenDocumentPresentation(); + testSimpleOpenDocumentFormula(); + +// testLargeOpenDocumentSpreadsheet(); + +#ifdef KOXML_USE_QDOM + printf("Using QDom: "); +#else + printf("Using KoXml: "); +#endif + printf("%d tests, %d failed\n", testCount, testFailed ); + + return testFailed; +} diff --git a/lib/kofficecore/tests/priorityqueue_test.cpp b/lib/kofficecore/tests/priorityqueue_test.cpp new file mode 100644 index 00000000..d2c7eafd --- /dev/null +++ b/lib/kofficecore/tests/priorityqueue_test.cpp @@ -0,0 +1,87 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Werner Trobin <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <priorityqueue.h> +#include <kdebug.h> +#include <qptrlist.h> +#include <qasciidict.h> +#include <stdlib.h> +#include <time.h> + +struct Node { + Node( unsigned int key ) : m_key( key ), m_index( 0 ) {} + + unsigned int key() const { return m_key; } + void setKey( unsigned int key ) { m_key = key; } + + int index() const { return m_index; } + void setIndex( int i ) { m_index = i; } +private: + unsigned int m_key; + int m_index; +}; + +static const char* const keys[] = { "one", "two", "three", "four", "five", + "six", "seven", "eight", "nine", "ten", + "eleven", "twelve", 0 }; + +int main( int /*argc*/, char **/*argv*/ ) +{ + QPtrList<Node> list; + list.setAutoDelete( true ); + QAsciiDict<Node> dict; + + KOffice::PriorityQueue<Node> queue; + + srand( time( 0 ) ); + for ( int i = 0; i < 12; ++i ) { + Node *n = new Node( rand() % 20 ); + list.append( n ); + queue.insert( n ); + // Check whether the AsciiDict CTOR is okay + Node *n2 = new Node( *n ); + dict.insert( keys[ i ], n2 ); + } + + kdDebug() << "##### Queue 1: " << endl; + queue.dump(); + + kdDebug() << "##### Queue 2: " << endl; + KOffice::PriorityQueue<Node> queue2( dict ); + queue2.dump(); + + Node *n = list.at( 6 ); + kdDebug() << "##### Decreasing node: " << n->key() << " at " << n->index() << endl; + n->setKey( 2 ); + queue.keyDecreased( n ); + queue.dump(); + + n = list.at( 2 ); + kdDebug() << "##### Decreasing node: " << n->key() << " at " << n->index() << endl; + n->setKey( 0 ); + queue.keyDecreased( n ); + queue.dump(); + + n = queue.extractMinimum(); + while ( n ) { + queue.dump(); + n = queue.extractMinimum(); + } + return 0; +} |