📄 clienttest.cpp
字号:
/*
* Copyright (C) 2003-2006 Funambol
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @cond API */
/** @addtogroup ClientTest */
/** @{ */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef ENABLE_INTEGRATION_TESTS
#include "ClientTest.h"
#include "base/test.h"
#include "base/util/StringBuffer.h"
#include <memory>
#include <vector>
#include <utility>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <iostream>
#include <algorithm>
/** execute _x and then check the status of the _source pointer */
#define SOURCE_ASSERT_NO_FAILURE(_source, _x) \
{ \
CPPUNIT_ASSERT_NO_THROW(_x); \
CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \
}
/** check _x for true and then the status of the _source pointer */
#define SOURCE_ASSERT(_source, _x) \
{ \
CPPUNIT_ASSERT(_x); \
CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \
}
/** check that _x evaluates to a specific value and then the status of the _source pointer */
#define SOURCE_ASSERT_EQUAL(_source, _value, _x) \
{ \
CPPUNIT_ASSERT_EQUAL(_value, _x); \
CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \
}
/** same as SOURCE_ASSERT() with a specific failure message */
#define SOURCE_ASSERT_MESSAGE(_message, _source, _x) \
{ \
CPPUNIT_ASSERT_MESSAGE((_message), (_x)); \
CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \
}
/** utility function to iterate over different kinds of items in a sync source */
static int countAnyItems(
SyncSource *source,
SyncItem * (SyncSource::*first)(),
SyncItem * (SyncSource::*next)() )
{
SyncItem *item;
int count = 0;
CPPUNIT_ASSERT(source);
CPPUNIT_ASSERT(!source->getReport() || source->getReport()->getState() != SOURCE_ERROR);
SOURCE_ASSERT_NO_FAILURE(source, item = (source->*first)());
while ( item ) {
count++;
delete item;
SOURCE_ASSERT_NO_FAILURE(source, item = (source->*next)());
}
return count;
}
static int countNewItems( SyncSource *source )
{
int res = countAnyItems(
source,
&SyncSource::getFirstNewItem,
&SyncSource::getNextNewItem );
return res;
}
static int countUpdatedItems( SyncSource *source )
{
int res = countAnyItems(
source,
&SyncSource::getFirstUpdatedItem,
&SyncSource::getNextUpdatedItem );
return res;
}
static int countDeletedItems( SyncSource *source )
{
int res = countAnyItems(
source,
&SyncSource::getFirstDeletedItem,
&SyncSource::getNextDeletedItem );
return res;
}
static int countItems( SyncSource *source )
{
int res = countAnyItems(
source,
&SyncSource::getFirstItem,
&SyncSource::getNextItem );
return res;
}
static void importItem(SyncSource *source, std::string &data)
{
CPPUNIT_ASSERT(source);
if (data.size()) {
SyncItem item;
item.setData( data.c_str(), (long)data.size() );
item.setDataType( TEXT("raw") );
int status;
SOURCE_ASSERT_NO_FAILURE(source, status = source->addItem(item));
CPPUNIT_ASSERT(status == STC_OK || status == STC_ITEM_ADDED);
CPPUNIT_ASSERT(item.getKey() != 0);
CPPUNIT_ASSERT(wcslen(item.getKey()) > 0);
}
}
/**
* helper class to encapsulate ClientTest::Config::createsource_t
* pointer and the corresponding parameters
*/
class CreateSource {
public:
CreateSource(ClientTest::Config::createsource_t createSourceParam, ClientTest &clientParam, int sourceParam, bool isSourceAParam) :
createSource(createSourceParam),
client(clientParam),
source(sourceParam),
isSourceA(isSourceAParam) {}
SyncSource *operator() () {
CPPUNIT_ASSERT(createSource);
return createSource(client, source, isSourceA);
}
const ClientTest::Config::createsource_t createSource;
ClientTest &client;
const int source;
const bool isSourceA;
};
/**
* convenience macro for adding a test name like a function,
* to be used inside an instance of that class
*
* @param _class class which contains the function
* @param _function a function without parameters in that class
*/
#define ADD_TEST(_class, _function) \
addTest(new CppUnit::TestCaller<_class>(getName() + "::" #_function, &_class::_function, *this))
/**
* local test of one sync source and utility functions also used by
* sync tests
*/
class LocalTests : public CppUnit::TestSuite, public CppUnit::TestFixture {
public:
/** the client we are testing */
ClientTest &client;
/** number of the source we are testing in that client */
const int source;
/** configuration that corresponds to source */
const ClientTest::Config config;
/** helper funclets to create sources */
CreateSource createSourceA, createSourceB;
LocalTests(const std::string &name, ClientTest &cl, int sourceParam, ClientTest::Config &co) :
CppUnit::TestSuite(name),
client(cl),
source(sourceParam),
config(co),
createSourceA(co.createSourceA, cl, sourceParam, true),
createSourceB(co.createSourceB, cl, sourceParam, false)
{}
/** adds the supported tests to the instance itself */
void addTests() {
if (config.createSourceA) {
ADD_TEST(LocalTests, testOpen);
ADD_TEST(LocalTests, testIterateTwice);
if (config.insertItem) {
ADD_TEST(LocalTests, testSimpleInsert);
ADD_TEST(LocalTests, testLocalDeleteAll);
ADD_TEST(LocalTests, testComplexInsert);
if (config.updateItem) {
ADD_TEST(LocalTests, testLocalUpdate);
if (config.createSourceB) {
ADD_TEST(LocalTests, testChanges);
}
}
if (config.import &&
config.dump &&
config.compare &&
config.testcases) {
ADD_TEST(LocalTests, testImport);
ADD_TEST(LocalTests, testImportDelete);
}
if (config.templateItem &&
config.uniqueProperties) {
ADD_TEST(LocalTests, testManyChanges);
}
}
}
}
/**
* opens source and inserts the given item; can be called
* regardless whether the data source already contains items or not
*
* The type of the item is unset; it is assumed that the source
* can handle that.
*/
void insert(CreateSource createSource, const char *data) {
// create source
std::auto_ptr<SyncSource> source(createSource());
CPPUNIT_ASSERT(source.get() != 0);
// count number of already existing items
SOURCE_ASSERT(source.get(), source->beginSync() == 0);
int numItems;
CPPUNIT_ASSERT_NO_THROW(numItems = countItems(source.get()));
SyncItem item;
item.setData(data, (long)strlen(data));
int status;
SOURCE_ASSERT_NO_FAILURE(source.get(), status = source->addItem(item));
CPPUNIT_ASSERT(item.getKey() != 0);
CPPUNIT_ASSERT(wcslen(item.getKey()) > 0);
SOURCE_ASSERT(source.get(), source->endSync() == 0);
// delete source again
CPPUNIT_ASSERT_NO_THROW(source.reset());
// two possible results:
// - a new item was added
// - the item was matched against an existing one
CPPUNIT_ASSERT_NO_THROW(source.reset(createSource()));
CPPUNIT_ASSERT(source.get() != 0);
SOURCE_ASSERT(source.get(), source->beginSync() == 0);
CPPUNIT_ASSERT(status == STC_OK || status == STC_ITEM_ADDED || status == STC_CONFLICT_RESOLVED_WITH_MERGE);
CPPUNIT_ASSERT_EQUAL(numItems + (status == STC_CONFLICT_RESOLVED_WITH_MERGE ? 0 : 1),
countItems(source.get()));
CPPUNIT_ASSERT(countNewItems(source.get()) == 0);
CPPUNIT_ASSERT(countUpdatedItems(source.get()) == 0);
CPPUNIT_ASSERT(countDeletedItems(source.get()) == 0);
SOURCE_ASSERT(source.get(), source->endSync() == 0 );
CPPUNIT_ASSERT_NO_THROW(source.reset());
#if 0
/* source.createItem() is a SyncEvolution extension which cannot be used here */
SyncItem *sameItem;
SOURCE_ASSERT_NO_FAILURE(
source,
sameItem = source.createItem(item.getKey(), item.getState()));
CPPUNIT_ASSERT(sameItem != 0);
CPPUNIT_ASSERT(!strcmp( sameItem->getKey(), item.getKey()));
delete sameItem;
#endif
}
/**
* assumes that exactly one element is currently inserted and updates it with the given item
*
* The type of the item is cleared, as in insert() above.
*/
void update(CreateSource createSource, const char *data) {
CPPUNIT_ASSERT(createSource.createSource);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -