added automatic registration of test

git-svn-id: https://zeitsenke.de/svn/SyncEvolution/trunk@692 15ad00c4-1369-45f4-8270-35d70d36bdcd
This commit is contained in:
Patrick Ohly 2008-08-02 15:46:23 +00:00
parent 55e82b4101
commit d08d1f7e88
11 changed files with 415 additions and 272 deletions

View File

@ -26,7 +26,7 @@ TESTS = @CPPUNIT_TESTS@
DISTCLEANFILES = synccompare
MAINTAINERCLEANFILES = Makefile.in
CLEANFILES = libstdc++.a
CLEANFILES = libstdc++.a client-test $(CLIENT_LIB_TEST_FILES)
# synccompare is created by replacing its 'import Algorithm::Diff;'
# with a simplified copy of Diff.pm.
@ -92,6 +92,7 @@ dist-hook:
find $(distdir) -name .libs -o -name "*~" -o -name ".*" -o -name "*.o" -o -name "*.lo" -o -name CVS -o -name autom4te.cache | xargs rm -rf
clean-local: testclean
rm -rf testcases
[ ! -d "$(FUNAMBOL_SUBDIR)" ] || (cd $(FUNAMBOL_SUBDIR) && $(MAKE) clean)
# files created during testing
@ -107,28 +108,35 @@ distclean-local:
# executed. The workaround is to explicitly set them as undefined on the
# link line.
client_test_SOURCES = client-test-app.cpp $(CORE_SOURCES)
CLIENT_LIB_TEST_FILES = ClientTest.h ClientTest.cpp client-test-main.cpp
CLIENT_LIB_TEST_FILES = ClientTest.h ClientTest.cpp client-test-main.cpp \
testcases/vcard21.vcf \
testcases/vcard30.vcf \
testcases/ical20.ics \
testcases/itodo20.ics
nodist_client_test_SOURCES = $(CLIENT_LIB_TEST_FILES)
client_test_CPPFLAGS = -DHAVE_CONFIG_H -DENABLE_INTEGRATION_TESTS -DENABLE_UNIT_TESTS $(AM_CPPFLAGS)
client_test_CXXFLAGS = `cppunit-config --cflags` $(SYNCEVOLUTION_CXXFLAGS)
client_test_LDFLAGS = `cppunit-config --libs` `nm $(FUNAMBOL_SUBDIR)/src/.libs/libfunambol.a | grep funambolAutoRegisterRegistry | sed -e 's/.* /-u /'`
client_test_LDADD = $(SYNCEVOLUTION_LDADD) @LIBDBUS@ $(FUNAMBOL_SUBDIR)/src/libfunambol.la $(CORE_LDADD)
client_test_DEPENDENCIES = $(EXTRA_LTLIBRARIES) $(CORE_DEP) all
# These dependencies are intentionally a bit too broad:
# they ensure that all files are in place to *run* client-test,
# but in particular the "all" dependency causes a rebuild
# even if the actual input files haven't changed.
client_test_DEPENDENCIES = $(EXTRA_LTLIBRARIES) $(CORE_DEP) all $(CLIENT_LIB_TEST_FILES) synccompare
# copy test files for several reasons:
# - automake expects them here
# - wchar needs to be removed from distribution to avoid need for defines
# - a locally modified file with suffix ".modified" can take precedence over
# the upstream version
# - a file in SyncEvolution's test directory is preferred if it exists
LOCAL_TEST_FILES=$(notdir $(wildcard $(srcdir)/../test/*))
LOCAL_TEST_FILES=$(subst $(srcdir)/../test/,,$(wildcard $(srcdir)/../test/* $(srcdir)/../test/testcases/*))
# sources from SyncEvolution
$(filter $(LOCAL_TEST_FILES), $(CLIENT_LIB_TEST_FILES)) : % : $(srcdir)/../test/%
$(filter-out testcases/%, $(filter $(LOCAL_TEST_FILES), $(CLIENT_LIB_TEST_FILES))) : % : $(srcdir)/../test/%
sed -e 's/WCHAR_T/char/g' -e 's/TEXT(/(/g' -e 's/wcslen/strlen/g' -e 's/wcscmp/strcmp/g' $< >$@
# sources from compiled client library
$(filter-out $(LOCAL_TEST_FILES), $(CLIENT_LIB_TEST_FILES)) : % : $(FUNAMBOL_SUBDIR)/test/test/%
$(filter-out $(LOCAL_TEST_FILES) testcases/%, $(CLIENT_LIB_TEST_FILES)) : % : $(FUNAMBOL_SUBDIR)/test/test/%
sed -e 's/WCHAR_T/char/g' -e 's/TEXT(/(/g' -e 's/wcslen/strlen/g' -e 's/wcscmp/strcmp/g' $< >$@
$(CLIENT_LIB_TEST_FILES:%=$(FUNAMBOL_SUBDIR)/test/test/%): @FUNAMBOL_DEP@
@ -137,19 +145,14 @@ $(CLIENT_LIB_TEST_FILES:%=$(FUNAMBOL_SUBDIR)/test/test/%): @FUNAMBOL_DEP@
ClientTest.cpp : ClientTest.h
# verbatim files from SyncEvolution
$(filter $(LOCAL_TEST_FILES), testcases) : % : $(srcdir)/../test/%
rm -rf $@
cp -r $< $@
$(filter testcases/%, $(filter $(LOCAL_TEST_FILES), $(CLIENT_LIB_TEST_FILES))) : % : $(srcdir)/../test/%
mkdir -p testcases
cp $< $@
# verbatim files from client library:
# - SQLiteContactSource does not support all fields: filter those out
$(filter-out $(LOCAL_TEST_FILES), testcases) : % : $(FUNAMBOL_SUBDIR)/test/test/%
rm -rf $@
cp -r $< $@
perl -e '$$_ = join("", <>); s/^(ADR|TEL|EMAIL|PHOTO).*?(?=^\S)//msg; print;' testcases/vcard21.vcf >testcases/vcard21_sqlite.vcf
test : client-test testcases synccompare
.PHONY : test
$(filter testcases/%, $(filter-out $(LOCAL_TEST_FILES), $(CLIENT_LIB_TEST_FILES))) : % : $(FUNAMBOL_SUBDIR)/test/test/%
mkdir -p testcases
cp $< $@
# rule to satisfy automatic dependencies on header files
$(FUNAMBOL_SUBDIR)/%.h :

View File

@ -86,4 +86,27 @@ protected:
SYNCEVOLUTION_TEST_SUITE_REGISTRATION(EvolutionAddressbookTest);
#endif // ENABLE_UNIT_TESTS
#ifdef ENABLE_INTEGRATION_TESTS
static class VCard21Test : public RegisterSyncSourceTest {
public:
VCard21Test() : RegisterSyncSourceTest("addressbook_vcard21", "vcard21") {}
virtual void updateConfig(ClientTestConfig &config) const
{
config.type = "apple-contacts:text/x-vcard";
}
} vCard21Test;
static class VCard30Test : public RegisterSyncSourceTest {
public:
VCard30Test() : RegisterSyncSourceTest("addressbook_vcard30", "vcard30") {}
virtual void updateConfig(ClientTestConfig &config) const
{
config.type = "apple-contacts:text/vcard";
}
} vCard30Test;
#endif // ENABLE_INTEGRATION_TESTS
#endif // ENABLE_ADDRESSBOOK

View File

@ -294,4 +294,78 @@ protected:
SYNCEVOLUTION_TEST_SUITE_REGISTRATION(EvolutionCalendarTest);
#endif // ENABLE_UNIT_TESTS
#ifdef ENABLE_INTEGRATION_TESTS
static class iCal20Test : public RegisterSyncSourceTest {
public:
iCal20Test() : RegisterSyncSourceTest("ical20", "ical20") {}
virtual void updateConfig(ClientTestConfig &config) const
{
config.type = "evolution-calendar";
}
} iCal20Test;
static class iTodo20Test : public RegisterSyncSourceTest {
public:
iTodo20Test() : RegisterSyncSourceTest("itodo20", "itodo20") {}
virtual void updateConfig(ClientTestConfig &config) const
{
config.type = "evolution-tasks";
}
} iTodo20Test;
static class MemoTest : public RegisterSyncSourceTest {
public:
MemoTest() : RegisterSyncSourceTest("text", "") {}
virtual void updateConfig(ClientTestConfig &config) const
{
config.uri = "note"; // ScheduleWorld
config.type = "Evolution Memos"; // use an alias here to test that
config.insertItem =
"BEGIN:VCALENDAR\n"
"PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
"VERSION:2.0\n"
"METHOD:PUBLISH\n"
"BEGIN:VJOURNAL\n"
"SUMMARY:Summary\n"
"DESCRIPTION:Summary\\nBody text\n"
"END:VJOURNAL\n"
"END:VCALENDAR\n";
config.updateItem =
"BEGIN:VCALENDAR\n"
"PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
"VERSION:2.0\n"
"METHOD:PUBLISH\n"
"BEGIN:VJOURNAL\n"
"SUMMARY:Summary Modified\n"
"DESCRIPTION:Summary Modified\\nBody text\n"
"END:VJOURNAL\n"
"END:VCALENDAR\n";
/* change summary, as in updateItem, and the body in the other merge item */
config.mergeItem1 = config.updateItem;
config.mergeItem2 =
"BEGIN:VCALENDAR\n"
"PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
"VERSION:2.0\n"
"METHOD:PUBLISH\n"
"BEGIN:VJOURNAL\n"
"SUMMARY:Summary\n"
"DESCRIPTION:Summary\\nBody modified\n"
"END:VJOURNAL\n"
"END:VCALENDAR\n";
config.templateItem = config.insertItem;
config.uniqueProperties = "SUMMARY:DESCRIPTION";
config.sizeProperty = "DESCRIPTION";
config.import = ClientTest::import;
config.dump = dump;
config.testcases = "testcases/imemo20.ics";
config.type = "evolution-memos";
}
} memoTest;
#endif // ENABLE_INTEGRATION_TESTS
#endif // ENABLE_ECAL

View File

@ -133,6 +133,41 @@ private:
};
SYNCEVOLUTION_TEST_SUITE_REGISTRATION(EvolutionContactTest);
#endif // ENABLE_UNIT_TESTS
#ifdef ENABLE_INTEGRATION_TESTS
/**
* We are using the vcard30 tests because they are
* a bit more complete than the vcard21 ones.
* This also tests the vCard 3.0 <-> vCard 2.1
* conversion.
*
* The local tests become identical with the
* vCard 3.0 ones because they import/export the
* same data.
*/
static class VCard21Test : public RegisterSyncSourceTest {
public:
VCard21Test() : RegisterSyncSourceTest("vcard21", "vcard30") {}
virtual void updateConfig(ClientTestConfig &config) const
{
config.uri = "card"; // Funambol
config.type = "evolution-contacts:text/x-vcard";
config.dump = dump;
}
} vCard21Test;
static class VCard30Test : public RegisterSyncSourceTest {
public:
VCard30Test() : RegisterSyncSourceTest("vcard30", "vcard30") {}
virtual void updateConfig(ClientTestConfig &config) const
{
config.type = "evolution-contacts:text/vcard";
}
} vCard30Test;
#endif // ENABLE_INTEGRATION_TESTS
#endif // ENABLE_EBOOK

View File

@ -26,3 +26,10 @@ syncsqlite_la_SOURCES = $(SYNCSQLITE_SOURCES)
syncsqlite_la_LIBADD = @SQLITE_LIBS@
syncsqlite_la_LDFLAGS = -module -rpath '$(pkglibdir)'
syncsqlite_la_CXXFLAGS = $(SYNCEVOLUTION_CXXFLAGS)
# SQLiteContactSource does not support all fields from Funambol vCard 2.1
# test cases: filter them out before testing
../../testcases/sqlite_vcard21.vcf: $(FUNAMBOL_SUBDIR)/test/test/testcases/vcard21.vcf
mkdir -p ${@D}
perl -e '$$_ = join("", <>); s/^(ADR|TEL|EMAIL|PHOTO).*?(?=^\S)//msg; s/;X-EVOLUTION-UI-SLOT=\d+//g; print;' $< >$@
all: ../../testcases/sqlite_vcard21.vcf

View File

@ -410,6 +410,11 @@ void SQLiteContactSource::logItem(const string &uid, const string &info, bool de
void SQLiteContactSource::logItem(const SyncItem &item, const string &info, bool debug)
{
if (!item.getData()) {
logItem(string(item.getKey()), info, debug);
return;
}
if (LOG.getLevel() >= (debug ? LOG_LEVEL_DEBUG : LOG_LEVEL_INFO)) {
string data = (const char *)item.getData();

View File

@ -73,4 +73,18 @@ protected:
SYNCEVOLUTION_TEST_SUITE_REGISTRATION(EvolutionSQLiteContactsTest);
#endif // ENABLE_UNIT_TESTS
#ifdef ENABLE_INTEGRATION_TESTS
static class SQLiteVCard21Test : public RegisterSyncSourceTest {
public:
SQLiteVCard21Test() : RegisterSyncSourceTest("sqlite_vcard21", "vcard21") {}
virtual void updateConfig(ClientTestConfig &config) const
{
config.type = "sqlite-contacts:text/x-vcard";
config.testcases = "testcases/sqlite_vcard21.vcf";
}
} SQLiteVCard21Test;
#endif // ENABLE_INTEGRATION_TESTS
#endif // ENABLE_SQLITE

View File

@ -51,47 +51,67 @@ CPPUNIT_REGISTRY_ADD_TO_DEFAULT("SyncEvolution");
* a wrapper class which automatically does an open() in the constructor and a close() in the destructor
* and ensures that the sync mode is "none" = testing mode
*/
class TestEvolutionSyncSource : public SyncSource {
class TestEvolutionSyncSource : public EvolutionSyncSource {
public:
TestEvolutionSyncSource(const string &type, const EvolutionSyncSourceParams &params) :
SyncSource(params.m_name.c_str(), NULL)
TestEvolutionSyncSource(const string &type,
const EvolutionSyncSourceParams &params) :
EvolutionSyncSource(params)
{
PersistentEvolutionSyncSourceConfig config(params.m_name, params.m_nodes);
config.setSourceType(type);
m_source.reset(EvolutionSyncSource::createSource(params));
CPPUNIT_ASSERT(m_source.get());
m_source->setSyncMode(SYNC_NONE);
}
virtual int beginSync() {
virtual int beginSync() throw () {
CPPUNIT_ASSERT_NO_THROW(m_source->open());
CPPUNIT_ASSERT(!m_source->hasFailed());
return m_source->beginSync();
}
virtual int endSync() {
virtual int endSync() throw () {
int res = m_source->endSync();
CPPUNIT_ASSERT_NO_THROW(m_source->close());
CPPUNIT_ASSERT(!m_source->hasFailed());
return res;
}
virtual SyncItem* getFirstItem() { return m_source->getFirstItem(); }
virtual SyncItem* getNextItem() { return m_source->getNextItem(); }
virtual SyncItem* getFirstNewItem() { return m_source->getFirstNewItem(); }
virtual SyncItem* getNextNewItem() { return m_source->getNextNewItem(); }
virtual SyncItem* getFirstUpdatedItem() { return m_source->getFirstUpdatedItem(); }
virtual SyncItem* getNextUpdatedItem() { return m_source->getNextUpdatedItem(); }
virtual SyncItem* getFirstDeletedItem() { return m_source->getFirstDeletedItem(); }
virtual SyncItem* getNextDeletedItem() { return m_source->getNextDeletedItem(); }
virtual SyncItem* getFirstItemKey() { return m_source->getFirstItemKey(); }
virtual SyncItem* getNextItemKey() { return m_source->getNextItemKey(); }
virtual void setItemStatus(const char *key, int status) { m_source->setItemStatus(key, status); }
virtual int addItem(SyncItem& item) { return m_source->addItem(item); }
virtual int updateItem(SyncItem& item) { return m_source->updateItem(item); }
virtual int deleteItem(SyncItem& item) { return m_source->deleteItem(item); }
virtual int removeAllItems() { return m_source->removeAllItems(); }
const char *getName() { return m_source->getName(); }
virtual ArrayElement* clone() { return NULL; }
virtual SyncItem* getFirstItem() throw () { return m_source->getFirstItem(); }
virtual SyncItem* getNextItem() throw () { return m_source->getNextItem(); }
virtual SyncItem* getFirstNewItem() throw () { return m_source->getFirstNewItem(); }
virtual SyncItem* getNextNewItem() throw () { return m_source->getNextNewItem(); }
virtual SyncItem* getFirstUpdatedItem() throw () { return m_source->getFirstUpdatedItem(); }
virtual SyncItem* getNextUpdatedItem() throw () { return m_source->getNextUpdatedItem(); }
virtual SyncItem* getFirstDeletedItem() throw () { return m_source->getFirstDeletedItem(); }
virtual SyncItem* getNextDeletedItem() throw () { return m_source->getNextDeletedItem(); }
virtual SyncItem* getFirstItemKey() throw () { return m_source->getFirstItemKey(); }
virtual SyncItem* getNextItemKey() throw () { return m_source->getNextItemKey(); }
virtual void setItemStatus(const char *key, int status) throw () { m_source->setItemStatus(key, status); }
virtual int addItem(SyncItem& item) throw () { return m_source->addItem(item); }
virtual int updateItem(SyncItem& item) throw () { return m_source->updateItem(item); }
virtual int deleteItem(SyncItem& item) throw () { return m_source->deleteItem(item); }
virtual int removeAllItems() throw () { return m_source->removeAllItems(); }
const char *getName() throw () { return m_source->getName(); }
virtual Databases getDatabases() { return m_source->getDatabases(); }
virtual void open() { m_source->open(); }
virtual SyncItem *createItem(const string &uid) { return m_source->createItem(uid); }
virtual void close() { m_source->close(); }
virtual void exportData(ostream &out) { m_source->exportData(out); }
virtual string fileSuffix() const { return m_source->fileSuffix(); }
virtual const char *getMimeType() const { return m_source->getMimeType(); }
virtual const char *getMimeVersion() const { return m_source->getMimeVersion(); }
virtual const char* getSupportedTypes() const { return m_source->getSupportedTypes(); }
virtual void beginSyncThrow(bool needAll,
bool needPartial,
bool deleteLocal) { m_source->beginSyncThrow(needAll, needPartial, deleteLocal); }
virtual void endSyncThrow() { m_source->endSyncThrow(); }
virtual int addItemThrow(SyncItem& item) { return m_source->addItemThrow(item); }
virtual int updateItemThrow(SyncItem& item) { return m_source->updateItemThrow(item); }
virtual int deleteItemThrow(SyncItem& item) { return m_source->deleteItemThrow(item); }
virtual void logItem(const string &uid, const string &info, bool debug = false) { m_source->logItem(uid, info, debug); }
virtual void logItem(const SyncItem &item, const string &info, bool debug = false) { m_source->logItem(item, info, debug); }
auto_ptr<EvolutionSyncSource> m_source;
};
@ -154,11 +174,13 @@ public:
TestEvolution(const string &id) :
ClientTest(getenv("CLIENT_TEST_DELAY") ? atoi(getenv("CLIENT_TEST_DELAY")) : 0,
getenv("CLIENT_TEST_LOG") ? getenv("CLIENT_TEST_LOG") : ""),
clientID(id) {
m_clientID(id),
m_configs(EvolutionSyncSource::getTestRegistry())
{
const char *server = getenv("CLIENT_TEST_SERVER");
if (id == "1") {
clientB.reset(new TestEvolution("2"));
m_clientB.reset(new TestEvolution("2"));
}
/* check server */
@ -169,41 +191,22 @@ public:
/* override Evolution database names? */
const char *evoprefix = getenv("CLIENT_TEST_EVOLUTION_PREFIX");
evoPrefix = evoprefix ? evoprefix : "SyncEvolution_Test_";
m_evoPrefix = evoprefix ? evoprefix : "SyncEvolution_Test_";
/* check sources */
const char *sourcelist = getenv("CLIENT_TEST_SOURCES");
if (!sourcelist) {
sourcelist = "vcard21,vcard30,ical20,text,itodo20,sqlite,addressbook";
set<string> sources;
if (sourcelist) {
boost::split(sources, sourcelist, boost::is_any_of(","));
} else {
BOOST_FOREACH(const RegisterSyncSourceTest *test, m_configs) {
sources.insert(test->m_configName);
}
}
numSources = 0;
for (SourceType sourceType = (SourceType)0; sourceType < TEST_MAX_SOURCE; sourceType = (SourceType)((int)sourceType + 1) ) {
string name = getSourceName(sourceType);
#ifndef ENABLE_EBOOK
if (sourceType == TEST_CONTACT21_SOURCE || sourceType == TEST_CONTACT30_SOURCE) {
continue;
}
#endif
#ifndef ENABLE_ECAL
if (sourceType == TEST_CALENDAR_SOURCE ||
sourceType == TEST_TASK_SOURCE ||
sourceType == TEST_MEMO_SOURCE) {
continue;
}
#endif
#ifndef ENABLE_SQLITE
if (sourceType == TEST_SQLITE_CONTACT_SOURCE) {
continue;
}
#endif
#ifndef ENABLE_ADDRESSBOOK
if (sourceType == TEST_ADDRESS_BOOK_SOURCE) {
continue;
}
#endif
if (strstr(sourcelist, name.c_str())) {
enabledSources[numSources++] = sourceType;
BOOST_FOREACH(const RegisterSyncSourceTest *test, m_configs) {
if (sources.find(test->m_configName) != sources.end()) {
m_source2Config.push_back(test->m_configName);
}
}
@ -216,9 +219,9 @@ public:
config.setDefaults();
config.setDevID(id == "1" ? "sc-api-nat" : "sc-pim-ppc");
}
for (SourceType sourceType = (SourceType)0; sourceType < TEST_MAX_SOURCE; sourceType = (SourceType)((int)sourceType + 1) ) {
BOOST_FOREACH(const RegisterSyncSourceTest *test, m_configs) {
ClientTest::Config testconfig;
getSourceConfig(sourceType, testconfig);
getSourceConfig(test, testconfig);
CPPUNIT_ASSERT(testconfig.type);
boost::shared_ptr<EvolutionSyncSourceConfig> sc = config.getSyncSourceConfig(testconfig.sourceName);
@ -232,7 +235,7 @@ public:
}
// always set this property: the name might have changes since last test run
string database = getDatabaseName(sourceType);
string database = getDatabaseName(test->m_configName);
sc->setDatabaseID(database);
}
config.flush();
@ -242,116 +245,27 @@ public:
return new EvolutionLocalTests(name, *this, sourceParam, co);
}
enum SourceType {
TEST_CONTACT21_SOURCE,
TEST_CONTACT30_SOURCE,
TEST_CALENDAR_SOURCE,
TEST_TASK_SOURCE,
TEST_MEMO_SOURCE,
TEST_SQLITE_CONTACT_SOURCE,
TEST_ADDRESS_BOOK_SOURCE,
TEST_MAX_SOURCE
};
virtual int getNumSources() {
return numSources;
}
virtual void getSourceConfig(SourceType sourceType, Config &config) {
memset(&config, 0, sizeof(config));
switch (sourceType) {
case TEST_CONTACT21_SOURCE:
// we cannot use the C++ client libraries' vcard21 test
// data because Evolution only imports vCard 3.0 items,
// but we can use the vcard30 test data and synchronize
// it as vCard 2.1
getTestData("vcard30", config);
config.sourceName = "vcard21";
config.uri = "card"; // Funambol
config.type = "evolution-contacts:text/x-vcard";
break;
case TEST_CONTACT30_SOURCE:
getTestData("vcard30", config);
config.type = "Evolution Address Book:text/vcard";
break;
case TEST_CALENDAR_SOURCE:
getTestData("ical20", config);
config.type = "evolution-calendar";
break;
case TEST_TASK_SOURCE:
getTestData("itodo20", config);
config.type = "evolution-tasks";
break;
case TEST_MEMO_SOURCE:
config.sourceName = "text";
config.uri = "note"; // ScheduleWorld
config.type = "Evolution Memos"; // use an alias here to test that
config.insertItem =
"BEGIN:VCALENDAR\n"
"PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
"VERSION:2.0\n"
"METHOD:PUBLISH\n"
"BEGIN:VJOURNAL\n"
"SUMMARY:Summary\n"
"DESCRIPTION:Summary\\nBody text\n"
"END:VJOURNAL\n"
"END:VCALENDAR\n";
config.updateItem =
"BEGIN:VCALENDAR\n"
"PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
"VERSION:2.0\n"
"METHOD:PUBLISH\n"
"BEGIN:VJOURNAL\n"
"SUMMARY:Summary Modified\n"
"DESCRIPTION:Summary Modified\\nBody text\n"
"END:VJOURNAL\n"
"END:VCALENDAR\n";
/* change summary, as in updateItem, and the body in the other merge item */
config.mergeItem1 = config.updateItem;
config.mergeItem2 =
"BEGIN:VCALENDAR\n"
"PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
"VERSION:2.0\n"
"METHOD:PUBLISH\n"
"BEGIN:VJOURNAL\n"
"SUMMARY:Summary\n"
"DESCRIPTION:Summary\\nBody modified\n"
"END:VJOURNAL\n"
"END:VCALENDAR\n";
config.templateItem = config.insertItem;
config.uniqueProperties = "SUMMARY:DESCRIPTION";
config.sizeProperty = "DESCRIPTION";
config.import = ClientTest::import;
config.dump = dumpMemoSource;
config.testcases = "testcases/imemo20.ics";
break;
case TEST_SQLITE_CONTACT_SOURCE:
getTestData("vcard21", config);
config.sourceName = "sqlite";
config.type = "sqlite-contacts";
config.testcases = "testcases/vcard21_sqlite.vcf";
break;
case TEST_ADDRESS_BOOK_SOURCE:
getTestData("vcard30", config);
config.sourceName = "addressbook";
config.type = "apple-contacts";
break;
default:
CPPUNIT_ASSERT(sourceType < TEST_MAX_SOURCE);
break;
}
config.createSourceA = createSource;
config.createSourceB = createSource;
config.compare = compare;
return m_source2Config.size();
}
virtual void getSourceConfig(int source, Config &config) {
getSourceConfig(enabledSources[source], config);
getSourceConfig(m_configs[m_source2Config[source]], config);
}
static void getSourceConfig(const RegisterSyncSourceTest *test, Config &config) {
memset(&config, 0, sizeof(config));
ClientTest::getTestData(test->m_testCaseName.c_str(), config);
config.createSourceA = createSource;
config.createSourceB = createSource;
config.compare = compare;
config.sourceName = test->m_configName.c_str();
test->updateConfig(config);
}
virtual ClientTest *getClientB() {
return clientB.get();
return m_clientB.get();
}
virtual bool isB64Enabled() {
@ -368,12 +282,12 @@ public:
const char *encoding = NULL) {
set<string> activeSources;
for(int i = 0; sources[i] >= 0; i++) {
activeSources.insert(getSourceName(enabledSources[sources[i]]));
activeSources.insert(m_source2Config[sources[i]]);
}
string server = getenv("CLIENT_TEST_SERVER") ? getenv("CLIENT_TEST_SERVER") : "funambol";
server += "_";
server += clientID;
server += m_clientID;
class ClientTest : public EvolutionSyncClient {
public:
@ -426,65 +340,35 @@ public:
}
private:
string clientID;
std::auto_ptr<TestEvolution> clientB;
string addressBookConfigPath;
string m_clientID;
std::auto_ptr<TestEvolution> m_clientB;
const TestRegistry &m_configs;
/** prefix to be used for Evolution databases */
string evoPrefix;
string m_evoPrefix;
/** all sources that are active in the current test run */
SourceType enabledSources[TEST_MAX_SOURCE];
/** number of active sources */
int numSources;
/** returns the name corresponding to the type, using the same strings as the C++ client testing system */
static string getSourceName(SourceType type) {
switch (type) {
case TEST_CONTACT21_SOURCE:
return "vcard21";
break;
case TEST_CONTACT30_SOURCE:
return "vcard30";
break;
case TEST_CALENDAR_SOURCE:
return "ical20";
break;
case TEST_TASK_SOURCE:
return "itodo20";
break;
case TEST_MEMO_SOURCE:
return "text";
break;
case TEST_SQLITE_CONTACT_SOURCE:
return "sqlite";
break;
case TEST_ADDRESS_BOOK_SOURCE:
return "addressbook";
break;
default:
CPPUNIT_ASSERT(type >= 0 && type < TEST_MAX_SOURCE);
return "";
break;
}
}
/**
* The ClientTest framework identifies active configs with an integer.
* This is the mapping to the corresponding config name, created when
* constructing this instance.
*/
vector<string> m_source2Config;
/** returns the name of the Evolution database */
string getDatabaseName(SourceType type) {
return evoPrefix + getSourceName(type) + "_" + clientID;
string getDatabaseName(const string &configName) {
return m_evoPrefix + configName + "_" + m_clientID;
}
static SyncSource *createSource(ClientTest &client, int source, bool isSourceA) {
TestEvolution &evClient((TestEvolution &)client);
string changeID = "SyncEvolution Change ID #";
SourceType type = ((TestEvolution &)client).enabledSources[source];
string name = evClient.m_source2Config[source];
changeID += isSourceA ? "1" : "2";
string database = ((TestEvolution &)client).getDatabaseName(type);
SyncSource *ss = NULL;
string database = evClient.getDatabaseName(name);
EvolutionSyncConfig config("client-test-changes");
string name = ((TestEvolution &)client).getSourceName(type);
SyncSourceNodes nodes = config.getSyncSourceNodes(name,
string("_") + ((TestEvolution &)client).clientID +
string("_") + ((TestEvolution &)client).m_clientID +
"_" + (isSourceA ? "A" : "B"));
// always set this property: the name might have changes since last test run
@ -494,46 +378,13 @@ private:
nodes,
changeID);
switch (type) {
case TEST_CONTACT21_SOURCE:
case TEST_CONTACT30_SOURCE:
ss = new TestEvolutionSyncSource("evolution-contacts:text/vcard", params);
break;
case TEST_CALENDAR_SOURCE:
ss = new TestEvolutionSyncSource("evolution-calendar", params);
break;
case TEST_TASK_SOURCE:
ss = new TestEvolutionSyncSource("evolution-tasks", params);
break;
case TEST_MEMO_SOURCE:
ss = new TestEvolutionSyncSource("evolution-memos", params);
break;
case TEST_SQLITE_CONTACT_SOURCE:
ss = new TestEvolutionSyncSource("SQLite Address Book", params);
break;
case TEST_ADDRESS_BOOK_SOURCE:
ss = new TestEvolutionSyncSource("apple-contacts", params);
break;
default:
CPPUNIT_ASSERT(type >= 0 && type < TEST_MAX_SOURCE);
}
const RegisterSyncSourceTest *test = evClient.m_configs[name];
ClientTestConfig testConfig;
getSourceConfig(test, testConfig);
SyncSource *ss = new TestEvolutionSyncSource(testConfig.type, params);
return ss;
}
/**
* dump memos in iCalendar 2.0 format for synccompare: ClientTest::dump() would
* dump the plain text
*/
static int dumpMemoSource(ClientTest &client, SyncSource &source, const char *file) {
std::ofstream out(file);
((TestEvolutionSyncSource &)source).m_source->exportData(out);
out.close();
return out.bad();
}
};
static void handler(int sig)
@ -582,3 +433,13 @@ private:
TestEvolution testClient;
} testEvolution;
int RegisterSyncSourceTest::dump(ClientTest &client, SyncSource &source, const char *file)
{
std::ofstream out(file);
((EvolutionSyncSource &)source).exportData(out);
out.close();
return out.bad();
}

View File

@ -133,6 +133,19 @@ static ostream & operator << (ostream &out, const RegisterSyncSource &rhs)
EvolutionSyncSource *const RegisterSyncSource::InactiveSource = (EvolutionSyncSource *)1;
TestRegistry &EvolutionSyncSource::getTestRegistry()
{
static TestRegistry testRegistry;
return testRegistry;
}
RegisterSyncSourceTest::RegisterSyncSourceTest(const string &configName, const string &testCaseName) :
m_configName(configName),
m_testCaseName(testCaseName)
{
EvolutionSyncSource::getTestRegistry().push_back(this);
}
static class ScannedModules {
public:
ScannedModules() {

View File

@ -29,6 +29,7 @@
#include <vector>
#include <set>
#include <ostream>
#include <stdexcept>
using namespace std;
#ifdef HAVE_EDS
@ -156,8 +157,8 @@ class RegisterSyncSource
const Values &typeValues);
public:
const string m_shortDescr;
bool m_enabled;
Create_t m_create;
const bool m_enabled;
const Create_t m_create;
const string m_typeDescr;
const Values m_typeValues;
};
@ -165,6 +166,107 @@ class RegisterSyncSource
typedef list<const RegisterSyncSource *> SourceRegistry;
#ifdef ENABLE_INTEGRATION_TESTS
#include <test/ClientTest.h>
typedef ClientTest::Config ClientTestConfig;
#else
/**
* this class doesn't exist and cannot be referenced in code which is
* compiled without ENABLE_INTEGRATION_TEST, but we only need to
* declare a reference to it, so that's okay
*/
class ClientTestConfig;
class ClientTest;
#endif
/**
* In addition to registering the sync source itself by creating an
* instance of RegisterSyncSource, configurations for testing it can
* also be registered. A sync source which supports more than one data
* exchange format can register one configuration for each format, but
* not registering any configuration is also okay.
*
* This code depends on the C++ client library test framework and
* therefore CPPUnit. To avoid a hard dependency on that in the normal
* "syncevolution" binary, the actual usage of the test Config class
* is limited to the *Register.cpp files when compiling them for
* inclusion in the "client-test" binary, i.e., they are protected by
* #ifdef ENABLE_UNIT_TESTS.
*
* Sync sources have to work stand-alone without a full SyncClient
* configuration for all local tests. The minimal configuration prepared
* for the source includes:
* - a tracking node (as used f.i. by TrackingSyncSource) which
* points towards "~/.config/syncevolution/client-test-changes"
* - a unique change ID (as used f.i. by EvolutionContactSource)
* - a valid "evolutionsource" property in the config node, starting
* with the CLIENT_TEST_EVOLUTION_PREFIX env variable or (if that
* wasn't set) the "SyncEvolution_Test_" prefix
*
* No other properties are set, which implies that currently sync sources
* which require further parameters cannot be tested.
*/
class RegisterSyncSourceTest
{
public:
/**
* This call is invoked after setting up the config with default
* values for the test cases selected via the constructor's
* testCaseName parameter (one of vcard21, vcard30, ical20, itodo20;
* see ClientTest in the Funambol client library for the current
* list).
*
* This call can then override any of the values or (if there
* are no predefined test cases) add them.
*
* The "type" property must select your sync source and the
* data format for the test.
*
* @retval config change any field whose default is not suitable
*/
virtual void updateConfig(ClientTestConfig &config) const = 0;
/**
* @param configName a unique string: the predefined names known by
* ClientTest::getTestData() are already used for the initial
* set of Evolution sync sources, for new sync sources
* build a string by combining them with the sync source name
* (e.g., "sqlite_vcard30")
* @param testCaseName a string recognized by ClientTest::getTestData() or an
* empty string if there are no predefined test cases
*/
RegisterSyncSourceTest(const string &configName,
const string &testCaseName);
virtual ~RegisterSyncSourceTest() {}
/**
* Dump items in the native format, not the one currently selected
* for exchange with the SyncML server. Useful for testing sync
* sources which normally use one format internally, but also
* support another one (EvolutionContactSource).
*/
static int dump(ClientTest &client, SyncSource &source, const char *file);
const string m_configName;
const string m_testCaseName;
};
class TestRegistry : public vector<const RegisterSyncSourceTest *>
{
public:
// TODO: using const RegisterSyncSourceTest * operator [] (int);
const RegisterSyncSourceTest * operator [] (const string &configName) const {
BOOST_FOREACH(const RegisterSyncSourceTest *test, *this) {
if (test->m_configName == configName) {
return test;
}
}
throw out_of_range(string("test config registry: ") + configName);
return NULL;
}
};
/**
* SyncEvolution accesses all sources through this interface. This
* class also implements common functionality for all SyncSources:
@ -213,6 +315,12 @@ class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig
*/
static SourceRegistry &getSourceRegistry();
/**
* SyncSource tests are registered here by the constructor of
* RegisterSyncSourceTest
*/
static TestRegistry &getTestRegistry();
struct Database {
Database(const string &name, const string &uri, bool isDefault = false) :
m_name( name ), m_uri( uri ), m_isDefault(isDefault) {}
@ -405,6 +513,10 @@ class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig
virtual int updateItemThrow(SyncItem& item) = 0;
virtual int deleteItemThrow(SyncItem& item) = 0;
/** log a one-line info about an item */
virtual void logItem(const string &uid, const string &info, bool debug = false) = 0;
virtual void logItem(const SyncItem &item, const string &info, bool debug = false) = 0;
protected:
#ifdef HAVE_EDS
/**
@ -431,10 +543,6 @@ class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig
#endif
);
/** log a one-line info about an item */
virtual void logItem(const string &uid, const string &info, bool debug = false) = 0;
virtual void logItem(const SyncItem &item, const string &info, bool debug = false) = 0;
const string m_changeId;
class Items : public set<string> {

View File

@ -69,7 +69,7 @@ libsyncevolution_la_SOURCES = $(CORE_SOURCES)
libsyncevolution_la_LIBADD = @FUNAMBOL_LIBS@ @EPACKAGE_LIBS@ @GLIB_LIBS@ @LIBS@
libsyncevolution_la_CXXFLAGS = $(SYNCEVOLUTION_CXXFLAGS)
# include client library and boost in distribution
# include boost in distribution
dist-hook:
cp -r $(srcdir)/boost $(distdir)
find $(distdir) -name .libs -o -name "*~" -o -name ".*" -o -name "*.o" -o -name "*.lo" -o -name CVS -o -name autom4te.cache | xargs rm -rf