1/*
2 Copyright (c) 2009 Volker Krause <vkrause@kde.org>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#ifndef XMLOPERATIONS_H
21#define XMLOPERATIONS_H
22
23#include <akonadi/collection.h>
24#include <akonadi/item.h>
25#include <akonadi/xml/xmldocument.h>
26
27#include <QtCore/QMetaEnum>
28#include <QtCore/QObject>
29#include <QtCore/QTextStream>
30
31#include <boost/bind.hpp>
32#include <algorithm>
33
34
35/**
36 Compares a Akonadi collection sub-tree with reference data supplied in an XML file.
37*/
38class XmlOperations : public QObject
39{
40 Q_OBJECT
41 Q_ENUMS( CollectionField ItemField )
42
43 public:
44 explicit XmlOperations( QObject *parent = 0 );
45 ~XmlOperations();
46
47 enum CollectionField {
48 None = 0,
49 RemoteId = 1,
50 Name = 2,
51 ContentMimeType = 4,
52 Attributes = 8
53 };
54
55 enum ItemField {
56 ItemNone = 0,
57 ItemRemoteId = 1,
58 ItemMimeType = 2,
59 ItemFlags = 4,
60 ItemPayload = 8
61 };
62
63 Q_DECLARE_FLAGS( CollectionFields, CollectionField )
64 Q_DECLARE_FLAGS( ItemFields, ItemField )
65
66 void setCollectionKey( CollectionField field );
67 void ignoreCollectionField( CollectionField field );
68 void setItemKey( ItemField field );
69 void ignoreItemField( ItemField field );
70
71 public slots:
72 void setRootCollections( const QString &resourceId );
73 void setRootCollections( const Akonadi::Collection::List &roots );
74 void setXmlFile( const QString &fileName );
75
76 Akonadi::Item getItemByRemoteId(const QString& rid);
77 Akonadi::Collection getCollectionByRemoteId(const QString& rid);
78
79 void setCollectionKey( const QString &fieldName );
80 void ignoreCollectionField( const QString &fieldName );
81 void setItemKey( const QString &fieldName );
82 void ignoreItemField( const QString &fieldName );
83
84 void setNormalizeRemoteIds( bool enable );
85
86 bool compare();
87 void assertEqual();
88
89 QString lastError() const;
90
91 bool compareCollections( const Akonadi::Collection::List &cols, const Akonadi::Collection::List &refCols );
92 bool compareCollection( const Akonadi::Collection &col, const Akonadi::Collection &refCol );
93 bool compareItems( const Akonadi::Item::List &items, const Akonadi::Item::List &refItems );
94 bool compareItem( const Akonadi::Item &item, const Akonadi::Item &refItem );
95 bool compareAttributes( const Akonadi::Entity &entity, const Akonadi::Entity &refEntity );
96 bool hasItem(const Akonadi::Item& _item, const Akonadi::Collection& _col);
97 bool hasItem(const Akonadi::Item& _item, const QString& rid);
98
99 private:
100 template <typename T, typename P>
101 bool compareValue( const Akonadi::Collection &col, const Akonadi::Collection &refCol,
102 T (P::*property)() const, CollectionField propertyType );
103 template <typename T, typename P>
104 bool compareValue( const Akonadi::Item& item, const Akonadi::Item& refItem,
105 T (P::*property)() const, ItemField propertyType );
106 template <typename T> bool compareValue( const T& value, const T& refValue );
107
108 template <typename T, typename E, typename P>
109 void sortEntityList( QList<E> &list, T ( P::*property)() const ) const;
110
111
112 Akonadi::Collection normalizeCollection( const Akonadi::Collection &in ) const;
113 Akonadi::Item normalizeItem( const Akonadi::Item &in ) const;
114
115 private:
116 Akonadi::Collection::List mRoots;
117 Akonadi::XmlDocument mDocument;
118 QString mFileName;
119 QString mErrorMsg;
120 CollectionFields mCollectionFields;
121 CollectionField mCollectionKey;
122 ItemFields mItemFields;
123 ItemField mItemKey;
124 bool mNormalizeRemoteIds;
125};
126
127
128template <typename T, typename P>
129bool XmlOperations::compareValue( const Akonadi::Collection& col, const Akonadi::Collection& refCol,
130 T (P::*property)() const,
131 CollectionField propertyType )
132{
133 if ( mCollectionFields & propertyType ) {
134 const bool result = compareValue<T>( ((col).*(property))(), ((refCol).*(property))() );
135 if ( !result ) {
136 const QMetaEnum me = metaObject()->enumerator( metaObject()->indexOfEnumerator( "CollectionField" ) );
137 mErrorMsg.prepend( QString::fromLatin1( "Collection with remote id '%1' differs in property '%2':\n" )
138 .arg( col.remoteId() ).arg( me.valueToKey( propertyType ) ) );
139 }
140 return result;
141 }
142 return true;
143}
144
145template <typename T, typename P>
146bool XmlOperations::compareValue( const Akonadi::Item& item, const Akonadi::Item& refItem,
147 T (P::*property)() const,
148 ItemField propertyType )
149{
150 if ( mItemFields & propertyType ) {
151 const bool result = compareValue<T>( ((item).*(property))(), ((refItem).*(property))() );
152 if ( !result ) {
153 const QMetaEnum me = metaObject()->enumerator( metaObject()->indexOfEnumerator( "ItemField" ) );
154 mErrorMsg.prepend( QString::fromLatin1( "Item with remote id '%1' differs in property '%2':\n" )
155 .arg( item.remoteId() ).arg( me.valueToKey( propertyType ) ) );
156 }
157 return result;
158 }
159 return true;
160}
161
162template <typename T>
163bool XmlOperations::compareValue(const T& value, const T& refValue )
164{
165 if ( value == refValue )
166 return true;
167 QTextStream ts( &mErrorMsg );
168 ts << " Actual: " << value << endl << " Expected: " << refValue;
169 return false;
170}
171
172template <typename T, typename E, typename P>
173void XmlOperations::sortEntityList( QList<E> &list, T ( P::*property)() const ) const
174{
175 std::sort( list.begin(), list.end(), boost::bind( property, _1 ) < boost::bind( property, _2 ) );
176}
177
178
179#endif
180