📄 clienttest.cpp
字号:
/*
* Copyright (C) 2003-2007 Funambol, Inc
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY, TITLE, NONINFRINGEMENT 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>
/** 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;
}
int countItemsOfType(SyncSource *source, itemType type)
{
int res = 0;
switch(type) {
case NEW_ITEMS:
res = countNewItems(source);
break;
case UPDATED_ITEMS:
res = countUpdatedItems(source);
break;
case DELETED_ITEMS:
res = countDeletedItems(source);
break;
case TOTAL_ITEMS:
res = countItems(source);
break;
default:
CPPUNIT_ASSERT(false);
break;
}
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);
}
}
/** adds the supported tests to the instance itself */
void LocalTests::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 LocalTests::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 LocalTests::update(CreateSource createSource, const char *data, bool check) {
CPPUNIT_ASSERT(createSource.createSource);
CPPUNIT_ASSERT(data);
// create source
std::auto_ptr<SyncSource> source(createSource());
CPPUNIT_ASSERT(source.get() != 0);
SOURCE_ASSERT(source.get(), source->beginSync() == 0);
// get existing item, then update it
SOURCE_ASSERT(source.get(), source->beginSync() == 0 );
std::auto_ptr<SyncItem> item;
SOURCE_ASSERT_NO_FAILURE(source.get(), item.reset(source->getFirstItem()) );
CPPUNIT_ASSERT(item.get());
item->setData(data, (long)strlen(data) + 1);
item->setDataType(TEXT(""));
SOURCE_ASSERT_EQUAL(source.get(), (int)STC_OK, source->updateItem(*item));
SOURCE_ASSERT(source.get(), source->endSync() == 0);
CPPUNIT_ASSERT_NO_THROW(source.reset());
if (!check) {
return;
}
// check that the right changes are reported when reopening the source
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(createSource()));
SOURCE_ASSERT(source.get(), source->beginSync() == 0 );
CPPUNIT_ASSERT_EQUAL(1, countItems(source.get()));
CPPUNIT_ASSERT_EQUAL(0, countNewItems(source.get()));
CPPUNIT_ASSERT_EQUAL(0, countUpdatedItems(source.get()));
CPPUNIT_ASSERT_EQUAL(0, countDeletedItems(source.get()));
std::auto_ptr<SyncItem> modifiedItem;
SOURCE_ASSERT_NO_FAILURE(source.get(), modifiedItem.reset(source->getFirstItem()) );
CPPUNIT_ASSERT(modifiedItem.get());
CPPUNIT_ASSERT( wcslen( item->getKey() ) );
CPPUNIT_ASSERT( !wcscmp( item->getKey(), modifiedItem->getKey() ) );
}
/** deletes all items locally via sync source */
void LocalTests::deleteAll(CreateSource createSource) {
CPPUNIT_ASSERT(createSource.createSource);
// create source
std::auto_ptr<SyncSource> source(createSource());
CPPUNIT_ASSERT(source.get() != 0);
SOURCE_ASSERT(source.get(), source->beginSync() == 0);
// delete all items
std::auto_ptr<SyncItem> item;
SOURCE_ASSERT_NO_FAILURE(source.get(), item.reset(source->getFirstItem()));
while (item.get()) {
SOURCE_ASSERT_EQUAL(source.get(), (int)STC_OK, source->deleteItem(*item));
SOURCE_ASSERT_NO_FAILURE(source.get(), item.reset(source->getNextItem()));
}
SOURCE_ASSERT(source.get(), source->endSync() == 0);
CPPUNIT_ASSERT_NO_THROW(source.reset());
// check that all items are gone
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(createSource()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_MESSAGE(
"should be empty now",
source.get(),
countItems(source.get()) == 0);
CPPUNIT_ASSERT_EQUAL( 0, countNewItems(source.get()) );
CPPUNIT_ASSERT_EQUAL( 0, countUpdatedItems(source.get()) );
CPPUNIT_ASSERT_EQUAL( 0, countDeletedItems(source.get()) );
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
}
/**
* takes two databases, exports them,
* then compares them using synccompare
*
* @param refFile existing file with source reference items, NULL uses a dump of sync source A instead
* @param copy a sync source which contains the copied items, begin/endSync will be called
* @param raiseAssert raise assertion if comparison yields differences (defaults to true)
*/
void LocalTests::compareDatabases(const char *refFile, SyncSource ©, bool raiseAssert) {
CPPUNIT_ASSERT(config.dump);
std::string sourceFile, copyFile;
if (refFile) {
sourceFile = refFile;
} else {
sourceFile = getCurrentTest() + ".source.test.dat";
simplifyFilename(sourceFile);
std::auto_ptr<SyncSource> source;
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(createSourceA()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 0, config.dump(client, *source.get(), sourceFile.c_str()));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -