diff --git a/akonadi/attributefactory.h b/akonadi/attributefactory.h index 1b9229799..479d5dbf8 100644 --- a/akonadi/attributefactory.h +++ b/akonadi/attributefactory.h @@ -1,85 +1,87 @@ /* Copyright (c) 2007 - 2008 Volker Krause 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. */ #ifndef AKONADI_ATTRIBUTEFACTORY_H #define AKONADI_ATTRIBUTEFACTORY_H #include namespace Akonadi { /** * @short Provides the functionality of registering and creating arbitrary * entity attributes. * * This class provides the functionality of registering and creating arbitrary Attributes for Entity * and its subclasses (e.g. Item and Collection). * * @code * * // register the type first * Akonadi::AttributeFactory::registerAttribute(); * * ... * * // use it anywhere else in the application * SecrecyAttribute *attr = Akonadi::AttributeFactory::createAttribute( "secrecy" ); * * @endcode * * @author Volker Krause */ class AKONADI_EXPORT AttributeFactory { public: //@cond PRIVATE ~AttributeFactory(); //@endcond /** - * Register a custom attribute of type T. + * Registers a custom attribute of type T. + * The same attribute cannot be registered more than once. */ template inline static void registerAttribute() { AttributeFactory::self()->registerAttribute( new T ); } /** * Creates an entity attribute object of the given type. + * If the type has not been registered, creates a DefaultAttribute. * * @param type The attribute type. */ static Attribute* createAttribute( const QByteArray &type ); protected: //@cond PRIVATE AttributeFactory(); private: static AttributeFactory* self(); void registerAttribute( Attribute *attribute ); class Private; Private* const d; //@endcond }; } #endif diff --git a/akonadi/entity.h b/akonadi/entity.h index 6a9514623..d333bbd07 100644 --- a/akonadi/entity.h +++ b/akonadi/entity.h @@ -1,221 +1,234 @@ /* Copyright (c) 2008 Tobias Koenig 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. */ #ifndef AKONADI_ENTITY_H #define AKONADI_ENTITY_H #include "akonadi_export.h" namespace Akonadi { class Entity; } AKONADI_EXPORT uint qHash( const Akonadi::Entity& ); #include +#include + #include #include #define AKONADI_DECLARE_PRIVATE( Class ) \ Class##Private* d_func(); \ const Class##Private* d_func() const; \ friend class Class##Private; namespace Akonadi { class EntityPrivate; /** * @short The base class for Item and Collection. * * Entity is the common base class for Item and Collection that provides * unique IDs and attributes handling. * * This class is not meant to be used directly, use Item or Collection instead. * * @author Tobias Koenig */ class AKONADI_EXPORT Entity { public: /** * Describes the unique id type. */ typedef qint64 Id; /** * Destroys the entity. */ ~Entity(); /** * Sets the unique @p identifier of the entity. */ void setId( Id identifier ); /** * Returns the unique identifier of the entity. */ Id id() const; /** * Sets the remote @p id of the entity. */ void setRemoteId( const QString& id ); /** * Returns the remote id of the entity. */ QString remoteId() const; /** * Returns whether the entity is valid. */ bool isValid() const; /** * Returns whether the entity's id equals the * id of the @p other entity. */ bool operator==( const Entity &other ) const; /** * Returns whether the entity's id does not equal the id * of the @p other entity. */ bool operator!=( const Entity &other ) const; /** * Assigns the @p other to this entity and returns a reference to this entity. */ Entity& operator=( const Entity &other ); /** * Adds an attribute to the entity. * * If an attribute of the same type name already exists, it is deleted and * replaced with the new one. * * @param attribute The new attribute. * * @note The entity takes the ownership of the attribute. */ void addAttribute( Attribute *attribute ); /** * Removes and deletes the attribute of the given type @p name. */ void removeAttribute( const QByteArray &name ); /** * Returns @c true if the entity has an attribute of the given type @p name, * false otherwise. */ bool hasAttribute( const QByteArray &name ) const; /** * Returns a list of all attributes of the entity. */ Attribute::List attributes() const; /** * Removes and deletes all attributes of the entity. */ void clearAttributes(); /** * Returns the attribute of the given type @p name if available, 0 otherwise. */ Attribute* attribute( const QByteArray &name ) const; /** * Describes the options that can be passed to access attributes. */ enum CreateOption { AddIfMissing ///< Creates the attribute if it is missing }; /** * Returns the attribute of the requested type. * If the entity has no attribute of that type yet, a new one * is created and added to the entity. * * @param option The create options. */ template inline T* attribute( CreateOption option ) { Q_UNUSED( option ); const T dummy; - if ( hasAttribute( dummy.type() ) ) - return static_cast( attribute( dummy.type() ) ); + if ( hasAttribute( dummy.type() ) ) { + T* attr = dynamic_cast( attribute( dummy.type() ) ); + if ( attr ) + return attr; + kWarning( 5250 ) << "Found attribute of unknown type" << dummy.type() + << ". Did you forget to call AttributeFactory::registerAttribute()?"; + } T* attr = new T(); addAttribute( attr ); return attr; } /** * Returns the attribute of the requested type or 0 if it is not available. */ template inline T* attribute() const { const T dummy; - if ( hasAttribute( dummy.type() ) ) - return static_cast( attribute( dummy.type() ) ); + if ( hasAttribute( dummy.type() ) ) { + T* attr = dynamic_cast( attribute( dummy.type() ) ); + if ( attr ) + return attr; + kWarning( 5250 ) << "Found attribute of unknown type" << dummy.type() + << ". Did you forget to call AttributeFactory::registerAttribute()?"; + } + return 0; } /** * Removes and deletes the attribute of the requested type. */ template inline void removeAttribute() { const T dummy; removeAttribute( dummy.type() ); } /** * Returns whether the entity has an attribute of the requested type. */ template inline bool hasAttribute() const { const T dummy; return hasAttribute( dummy.type() ); } protected: /** * Creates an entity from an @p other entity. */ Entity( const Entity &other ); //@cond PRIVATE Entity( EntityPrivate *dd ); QSharedDataPointer d_ptr; //@endcond AKONADI_DECLARE_PRIVATE( Entity ) }; } #endif diff --git a/akonadi/tests/CMakeLists.txt b/akonadi/tests/CMakeLists.txt index ef91d474a..35d4c6343 100644 --- a/akonadi/tests/CMakeLists.txt +++ b/akonadi/tests/CMakeLists.txt @@ -1,116 +1,117 @@ if(${EXECUTABLE_OUTPUT_PATH}) set( PREVIOUS_EXEC_OUTPUT_PATH ${EXECUTABLE_OUTPUT_PATH} ) else(${EXECUTABLE_OUTPUT_PATH}) set( PREVIOUS_EXEC_OUTPUT_PATH . ) endif(${EXECUTABLE_OUTPUT_PATH}) set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" ) include_directories( ${CMAKE_SOURCE_DIR}/akonadi ${CMAKE_CURRENT_SOURCE_DIR}/../ ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/../ ${Boost_INCLUDE_DIR} ${AKONADI_INCLUDE_DIR} ) # add testrunner (application for managing a self-contained test # environment) add_subdirectory(testrunner) # add benchmarker add_subdirectory(benchmarker) # convenience macro to add akonadi demo application macro(add_akonadi_demo _source) set(_test ${_source}) get_filename_component(_name ${_source} NAME_WE) kde4_add_executable(${_name} TEST ${_test}) target_link_libraries(${_name} akonadi-kde akonadi-kmime ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${KDE4_KDECORE_LIBS} ${KDE4_KDEUI_LIBS}) endmacro(add_akonadi_demo) # convenience macro to add akonadi qtestlib unit-tests macro(add_akonadi_test _source) set(_test ${_source}) get_filename_component(_name ${_source} NAME_WE) kde4_add_unit_test(${_name} TESTNAME akonadi-${_name} ${_test}) target_link_libraries(${_name} akonadi-kde akonadi-kmime ${QT_QTTEST_LIBRARY} ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${KDE4_KDECORE_LIBS} ${AKONADI_COMMON_LIBRARIES}) endmacro(add_akonadi_test) # convenience macro to add akonadi testrunner unit-tests macro(add_akonadi_isolated_test _source) set(_test ${_source}) get_filename_component(_name ${_source} NAME_WE) kde4_add_executable(${_name} TEST ${_test}) target_link_libraries(${_name} akonadi-kde akonadi-kmime ${QT_QTTEST_LIBRARY} ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${KDE4_KDECORE_LIBS} ${AKONADI_COMMON_LIBRARIES}) # based on kde4_add_unit_test if (WIN32) get_target_property( _loc ${_name} LOCATION ) set(_executable ${_loc}.bat) set(_testrunner ${PREVIOUS_EXEC_OUTPUT_PATH}/akonaditest.bat) else (WIN32) set(_executable ${EXECUTABLE_OUTPUT_PATH}/${_name}) set(_testrunner ${PREVIOUS_EXEC_OUTPUT_PATH}/akonaditest) endif (WIN32) if (UNIX) set(_executable ${_executable}.shell) set(_testrunner ${_testrunner}.shell) endif (UNIX) add_test( akonadi-db-${_name} ${_testrunner} -c ${CMAKE_CURRENT_SOURCE_DIR}/unittestenv/config-db.xml ${_executable} ) add_test( akonadi-fs-${_name} ${_testrunner} -c ${CMAKE_CURRENT_SOURCE_DIR}/unittestenv/config-fs.xml ${_executable} ) #add_test( akonadi-sqlite-${_name} ${_testrunner} -c ${CMAKE_CURRENT_SOURCE_DIR}/unittestenv/config-sqlite.xml ${_executable} ) endmacro(add_akonadi_isolated_test) # demo applications add_akonadi_demo(itemdumper.cpp) add_akonadi_demo(subscriber.cpp) add_akonadi_demo(headfetcher.cpp) add_akonadi_demo(agentinstancewidgettest.cpp) add_akonadi_demo(agenttypewidgettest.cpp) add_akonadi_demo(pluginloadertest.cpp) add_akonadi_demo(selftester.cpp) kde4_add_executable( akonadi-firstrun TEST ../firstrun.cpp firstrunner.cpp ) target_link_libraries( akonadi-firstrun akonadi-kde ${KDE4_KDEUI_LIBS} ) # qtestlib unit tests add_akonadi_test(imapparsertest.cpp) add_akonadi_test(imapsettest.cpp) add_akonadi_test(itemhydratest.cpp) add_akonadi_test(itemtest.cpp) add_akonadi_test(itemserializertest.cpp) add_akonadi_test(mimetypecheckertest.cpp) add_akonadi_test(protocolhelpertest.cpp) # testrunner tests add_akonadi_isolated_test(testenvironmenttest.cpp) add_akonadi_isolated_test(autoincrementtest.cpp) +add_akonadi_isolated_test(attributefactorytest.cpp) add_akonadi_isolated_test(collectionjobtest.cpp) add_akonadi_isolated_test(collectionpathresolvertest.cpp) add_akonadi_isolated_test(collectionattributetest.cpp) add_akonadi_isolated_test(itemfetchtest.cpp) add_akonadi_isolated_test(itemappendtest.cpp) add_akonadi_isolated_test(itemstoretest.cpp) add_akonadi_isolated_test(itemdeletetest.cpp) add_akonadi_isolated_test(monitortest.cpp) add_akonadi_isolated_test(searchjobtest.cpp) add_akonadi_isolated_test(changerecordertest.cpp) add_akonadi_isolated_test(resourcetest.cpp) add_akonadi_isolated_test(subscriptiontest.cpp) add_akonadi_isolated_test(transactiontest.cpp) add_akonadi_isolated_test(itemcopytest.cpp) add_akonadi_isolated_test(itemmovetest.cpp) add_akonadi_isolated_test(collectioncopytest.cpp) add_akonadi_isolated_test(collectionmovetest.cpp) add_akonadi_isolated_test(itemsynctest.cpp) add_akonadi_isolated_test(linktest.cpp) add_akonadi_isolated_test(cachetest.cpp) add_akonadi_isolated_test(servermanagertest.cpp) add_akonadi_isolated_test(collectioncreator.cpp) add_akonadi_isolated_test(itembenchmark.cpp) diff --git a/akonadi/tests/attributefactorytest.cpp b/akonadi/tests/attributefactorytest.cpp new file mode 100644 index 000000000..2a2ad7633 --- /dev/null +++ b/akonadi/tests/attributefactorytest.cpp @@ -0,0 +1,98 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 "attributefactorytest.h" +#include "collectionpathresolver_p.h" +#include "testattribute.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace Akonadi; + +QTEST_AKONADIMAIN( AttributeFactoryTest, NoGUI ) + +static Collection res1; + +void AttributeFactoryTest::initTestCase() +{ + CollectionPathResolver *resolver = new CollectionPathResolver( "res1", this ); + QVERIFY( resolver->exec() ); + res1 = Collection( resolver->collection() ); +} + +void AttributeFactoryTest::testUnknownAttribute() +{ + // The attribute is currently not registered. + Item item; + item.setMimeType( "text/directory" ); + item.setPayload( "payload" ); + TestAttribute *ta = new TestAttribute; + QVERIFY( AttributeFactory::createAttribute( ta->type() ) ); // DefaultAttribute + ta->data = "lalala"; + item.addAttribute( ta ); + ItemCreateJob *cjob = new ItemCreateJob( item, res1 ); + AKVERIFYEXEC( cjob ); + int id = cjob->item().id(); + item = Item( id ); + ItemFetchJob *fjob = new ItemFetchJob( item ); + fjob->fetchScope().fetchFullPayload(); + fjob->fetchScope().fetchAllAttributes(); + AKVERIFYEXEC( fjob ); + QCOMPARE( fjob->items().count(), 1 ); + item = fjob->items().first(); + QVERIFY( item.hasAttribute() ); // has DefaultAttribute + ta = item.attribute(); + QVERIFY( !ta ); // but can't cast it to TestAttribute +} + +void AttributeFactoryTest::testRegisteredAttribute() +{ + AttributeFactory::registerAttribute(); + + Item item; + item.setMimeType( "text/directory" ); + item.setPayload( "payload" ); + TestAttribute *ta = new TestAttribute; + QVERIFY( AttributeFactory::createAttribute( ta->type() ) != 0 ); + ta->data = "lalala"; + item.addAttribute( ta ); + ItemCreateJob *cjob = new ItemCreateJob( item, res1 ); + AKVERIFYEXEC( cjob ); + int id = cjob->item().id(); + item = Item( id ); + ItemFetchJob *fjob = new ItemFetchJob( item ); + fjob->fetchScope().fetchFullPayload(); + fjob->fetchScope().fetchAllAttributes(); + AKVERIFYEXEC( fjob ); + QCOMPARE( fjob->items().count(), 1 ); + item = fjob->items().first(); + QVERIFY( item.hasAttribute() ); + ta = item.attribute(); + QVERIFY( ta ); + QCOMPARE( ta->data, QByteArray( "lalala" ) ); +} + + +#include "attributefactorytest.moc" diff --git a/akonadi/tests/attributefactorytest.h b/akonadi/tests/attributefactorytest.h new file mode 100644 index 000000000..db391d052 --- /dev/null +++ b/akonadi/tests/attributefactorytest.h @@ -0,0 +1,37 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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. +*/ + +#ifndef ATTRIBUTEFACTORYTEST_H +#define ATTRIBUTEFACTORYTEST_H + +#include + + +class AttributeFactoryTest : public QObject +{ + Q_OBJECT + private slots: + void initTestCase(); + void testUnknownAttribute(); + void testRegisteredAttribute(); + +}; + + +#endif