⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clienttest.cpp

📁 This SDK allows to integrate a syncml stack in a C++ application on a variety of platforms. Current
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/*
 * 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 + -