📄 clienttest.cpp
字号:
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 1, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countNewItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countUpdatedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countDeletedItems(source.get()));
std::auto_ptr<SyncItem> item;
SOURCE_ASSERT_NO_FAILURE(source.get(), item.reset(source->getFirstItem()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
// delete item again via sync source A
deleteAll(createSourceA);
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(createSourceB()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 0, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countNewItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countUpdatedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 1, countDeletedItems(source.get()));
std::auto_ptr<SyncItem> deletedItem;
SOURCE_ASSERT_NO_FAILURE(source.get(), deletedItem.reset(source->getFirstDeletedItem()));
CPPUNIT_ASSERT( wcslen( item->getKey() ) );
CPPUNIT_ASSERT( wcslen( deletedItem->getKey() ) );
CPPUNIT_ASSERT( !wcscmp( item->getKey(), deletedItem->getKey() ) );
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
// insert another item via sync source A
testSimpleInsert();
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(createSourceB()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 1, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 1, countNewItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countUpdatedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countDeletedItems(source.get()));
SOURCE_ASSERT_NO_FAILURE(source.get(), item.reset(source->getFirstItem()));
std::auto_ptr<SyncItem> newItem;
SOURCE_ASSERT_NO_FAILURE(source.get(), newItem.reset(source->getFirstNewItem()));
CPPUNIT_ASSERT( wcslen( item->getKey() ) );
CPPUNIT_ASSERT( wcslen( newItem->getKey() ) );
CPPUNIT_ASSERT( !wcscmp( item->getKey(), newItem->getKey() ) );
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
// update item via sync source A
update(createSourceA, config.updateItem);
SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(createSourceB()));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->beginSync());
SOURCE_ASSERT_EQUAL(source.get(), 1, countItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countNewItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 1, countUpdatedItems(source.get()));
SOURCE_ASSERT_EQUAL(source.get(), 0, countDeletedItems(source.get()));
std::auto_ptr<SyncItem> updatedItem;
SOURCE_ASSERT_NO_FAILURE(source.get(), updatedItem.reset(source->getFirstUpdatedItem()));
CPPUNIT_ASSERT( wcslen( item->getKey() ) );
CPPUNIT_ASSERT( wcslen( updatedItem->getKey() ) );
CPPUNIT_ASSERT( !wcscmp( item->getKey(), updatedItem->getKey() ) );
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
}
// clean database, import file, then export again and compare
void testImport() {
// check additional requirements
CPPUNIT_ASSERT(config.import);
CPPUNIT_ASSERT(config.dump);
CPPUNIT_ASSERT(config.compare);
CPPUNIT_ASSERT(config.testcases);
testLocalDeleteAll();
// import via sync source A
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.import(client, *source.get(), config.testcases));
SOURCE_ASSERT_EQUAL(source.get(), 0, source->endSync());
CPPUNIT_ASSERT_NO_THROW(source.reset());
// export again and compare against original file
std::auto_ptr<SyncSource> copy;
SOURCE_ASSERT_NO_FAILURE(copy.get(), copy.reset(createSourceA()));
compareDatabases(config.testcases, *copy.get());
CPPUNIT_ASSERT_NO_THROW(source.reset());
}
// same as testImport() with immediate delete
void testImportDelete() {
testImport();
// delete again, because it was observed that this did not
// work right with calendars in SyncEvolution
testLocalDeleteAll();
}
// test change tracking with large number of items
void testManyChanges() {
// check additional requirements
CPPUNIT_ASSERT(config.templateItem);
CPPUNIT_ASSERT(config.uniqueProperties);
deleteAll(createSourceA);
// check that everything is empty, also resets change counter of sync source B
std::auto_ptr<SyncSource> copy;
SOURCE_ASSERT_NO_FAILURE(copy.get(), copy.reset(createSourceB()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, copy->beginSync());
SOURCE_ASSERT_EQUAL(copy.get(), 0, countItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, copy->endSync());
CPPUNIT_ASSERT_NO_THROW(copy.reset());
// now insert plenty of items
int numItems = insertManyItems(createSourceA);
// check that exactly this number of items is listed as new
SOURCE_ASSERT_NO_FAILURE(copy.get(), copy.reset(createSourceB()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, copy->beginSync());
SOURCE_ASSERT_EQUAL(copy.get(), numItems, countItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), numItems, countNewItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, countUpdatedItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, countDeletedItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, copy->endSync());
CPPUNIT_ASSERT_NO_THROW(copy.reset());
// delete all items
deleteAll(createSourceA);
// verify again
SOURCE_ASSERT_NO_FAILURE(copy.get(), copy.reset(createSourceB()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, countItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, countNewItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, countUpdatedItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), numItems, countDeletedItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, copy->endSync());
CPPUNIT_ASSERT_NO_THROW(copy.reset());
}
};
/**
* Tests synchronization with one or more sync sources enabled.
* When testing multiple sources at once only the first config
* is checked to see which tests can be executed.
*/
class SyncTests : public CppUnit::TestSuite, public CppUnit::TestFixture {
public:
/** the client we are testing */
ClientTest &client;
SyncTests(const std::string &name, ClientTest &cl, std::vector<int> sourceIndices, bool isClientA = true) :
CppUnit::TestSuite(name),
client(cl) {
sourceArray = new int[sourceIndices.size() + 1];
for (std::vector<int>::iterator it = sourceIndices.begin();
it != sourceIndices.end();
++it) {
ClientTest::Config config;
client.getSourceConfig(*it, config);
if (config.sourceName) {
sourceArray[sources.size()] = *it;
sources.push_back(std::pair<int,LocalTests *>(*it, new LocalTests(config.sourceName, cl, *it, config)));
}
}
sourceArray[sources.size()] = -1;
// check whether we have a second client
ClientTest *clientB = cl.getClientB();
if (clientB) {
accessClientB = new SyncTests(name, *clientB, sourceIndices, false);
} else {
accessClientB = 0;
}
}
~SyncTests() {
for (source_it it = sources.begin();
it != sources.end();
++it) {
delete it->second;
}
delete [] sourceArray;
if (accessClientB) {
delete accessClientB;
}
}
/** adds the supported tests to the instance itself */
void addTests() {
if (sources.size()) {
const ClientTest::Config &config(sources[0].second->config);
// run this test first, even if it is more complex:
// if it works, all the following tests will run with
// the server in a deterministic state
if (config.createSourceA) {
if (config.insertItem) {
ADD_TEST(SyncTests, testDeleteAllRefresh);
}
}
ADD_TEST(SyncTests, testTwoWaySync);
ADD_TEST(SyncTests, testSlowSync);
ADD_TEST(SyncTests, testRefreshFromServerSync);
ADD_TEST(SyncTests, testRefreshFromClientSync);
if (config.createSourceA) {
if (config.insertItem) {
ADD_TEST(SyncTests, testRefreshSemantic);
ADD_TEST(SyncTests, testRefreshStatus);
if (accessClientB &&
config.dump &&
config.compare) {
ADD_TEST(SyncTests, testCopy);
ADD_TEST(SyncTests, testDelete);
ADD_TEST(SyncTests, testAddUpdate);
ADD_TEST(SyncTests, testManyItems);
if (config.updateItem) {
ADD_TEST(SyncTests, testUpdate);
}
if (config.complexUpdateItem) {
ADD_TEST(SyncTests, testComplexUpdate);
}
if (config.mergeItem1 && config.mergeItem2) {
ADD_TEST(SyncTests, testMerge);
}
if (config.import) {
ADD_TEST(SyncTests, testTwinning);
ADD_TEST(SyncTests, testItems);
}
if (config.templateItem) {
ADD_TEST(SyncTests, testMaxMsg);
ADD_TEST(SyncTests, testLargeObject);
ADD_TEST(SyncTests, testLargeObjectBin);
if (client.isB64Enabled()) {
ADD_TEST(SyncTests, testLargeObjectEncoded);
}
ADD_TEST(SyncTests, testOneWayFromServer);
ADD_TEST(SyncTests, testOneWayFromClient);
}
}
}
}
}
}
private:
/** list with all local test classes for manipulating the sources and their index in the client */
std::vector< std::pair<int, LocalTests *> > sources;
typedef std::vector< std::pair<int, LocalTests *> >::iterator source_it;
/** the indices from sources, terminated by -1 (for sync()) */
int *sourceArray;
/** utility functions for second client */
SyncTests *accessClientB;
enum DeleteAllMode {
DELETE_ALL_SYNC, /**< make sure client and server are in sync,
delete locally,
sync again */
DELETE_ALL_REFRESH /**< delete locally, refresh server */
};
/** compare databases of first and second client */
void compareDatabases() {
source_it it1;
source_it it2;
CPPUNIT_ASSERT(accessClientB);
for (it1 = sources.begin(), it2 = accessClientB->sources.begin();
it1 != sources.end() && it2 != accessClientB->sources.end();
++it1, ++it2) {
std::auto_ptr<SyncSource> copy;
SOURCE_ASSERT_NO_FAILURE(copy.get(), copy.reset(it2->second->createSourceB()));
it1->second->compareDatabases(NULL, *copy.get());
CPPUNIT_ASSERT_NO_THROW(copy.reset());
}
CPPUNIT_ASSERT(it1 == sources.end());
CPPUNIT_ASSERT(it2 == accessClientB->sources.end());
}
/** deletes all items locally and on server */
void deleteAll(DeleteAllMode mode = DELETE_ALL_SYNC) {
source_it it;
switch(mode) {
case DELETE_ALL_SYNC:
// a refresh from server would slightly reduce the amount of data exchanged, but not all servers support it
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->deleteAll(it->second->createSourceA);
}
sync(SYNC_SLOW, ".deleteall.init");
// now that client and server are in sync, delete locally and sync again
for (it = sources.begin(); it != sources.end(); ++it) {
it->second->deleteAll(it->second->createSourceA);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -