Libcdbxx test

/* test.cc

 * This file is part of cdbxx library

 * Copyright (c) 2004 by Stanislav Ievlev

 *

 * This file is covered by the GNU Library General Public License,

 * which should be included with libcdbxx as the file COPYING.

 */

#include <iostream>

#include <stdexcept>

#include <cstdio>

#include <algorithm>

#include <unistd.h>

#include <fcntl.h>

#include "cdbxx/db.hh"

#include "cdbxx/map.hh"

struct test_struct

{

    test_struct():a_(3),b_('3') {}

    int a_;

    char b_;

};

const std::string test_str("some value");

const int max = 50;

void show(const cdbxx::data_pair& field)

{

    static int i = 0;

    if ((i < max) && (i != field.first.as<const int>()))

        throw std::runtime_error("wrong key");

    ++i;

    if (i > max) return;

    if (cdbxx::string(field.second) != test_str)

        throw std::runtime_error("wrong string value");

   

    cdbxx::vector<char> content(field.second);

    content.get().push_back('\000');//append zero symbol to compare as a strings

    if (&content.get()[0] != test_str) throw std::runtime_error("wrong vector value");

}

void no_here(const cdbxx::data_pair&)

{

    throw std::runtime_error("this was an empty database");

}

int

main()

{

    int ret = EXIT_SUCCESS;

    const char db_name1[]="./test1.cdb";

    const char db_name2[]="./test2.cdb";

    const char db_name3[]="./test3.cdb";

    const char empty_db[]="./empty.cdb";

    const char map_name[]="./map.cdb";

    //simple filling of the database

    std::cout << " 1";

    try

    {

        cdbxx::out_db new_database(db_name1);

        std::vector<int> key(1);

        std::vector<char> value(test_str.begin(), test_str.end());

        for (int i = 0;i < max;++i)

        {

            key[0] = i;

            new_database.insert(key, value);

        }

        //test insert with key as a string

        new_database.insert("some key", value);

        //test insert with key as a struct

        test_struct    struct_value;

        new_database.insert("struct key",&struct_value);

    }

    catch (std::runtime_error e)

    {

        std::cerr << "catch:" << e.what() << std::endl;

        ret = EXIT_FAILURE;

    }

    catch (...)

    {

        std::cerr << "unknown exception\n";

        ret = EXIT_FAILURE;

    }

    //catch if value exist

    std::cout << " 2";

    try

    {

        cdbxx::out_db new_database(db_name2);

        std::vector<int> key(1);

        std::vector<char> value(test_str.begin(), test_str.end());

        for (int i = 1;i < 3;++i)

        {

            key[0] = 55;

            new_database.insert(key, value); //must catch exception on second loop

        }

        ret = EXIT_FAILURE;

        std::cerr << "we must catch insertion of duplicate here\n";

    }

    catch (std::runtime_error)

    {

        //catch here

    }

    catch (...)

    {

        std::cerr << "unknown exception\n";

        ret = EXIT_FAILURE;

    }

    //read database

    std::cout << " 3";

    try

    {

        cdbxx::in_db    old_database(db_name1);

        std::for_each(old_database.begin(), old_database.end(), show);

    }

    catch (std::runtime_error e)

    {

        std::cerr << "catch:" << e.what() << std::endl;

        ret = EXIT_FAILURE;

    }

    catch (...)

    {

        std::cerr << "unknown exception\n";

        ret = EXIT_FAILURE;

    }

    //search in database

    std::cout << " 4";

    try

    {

        cdbxx::in_db    old_database(db_name1);

        cdbxx::iterator it = old_database.find("some key");

        if (it == old_database.end() || (cdbxx::string(it->second) != test_str))

            throw std::runtime_error("problems with find: search for existing value (key as string)");

        std::vector<int> key(1);

        key[0] = 1;

        cdbxx::iterator it2 = old_database.find(key);

        if (it2 == old_database.end() || (cdbxx::string(it2->second) != test_str))

            throw std::runtime_error("problems with find: search for existing value (key as vector)");

        cdbxx::iterator it3 = old_database.find("unknown key");

        if (it3 != old_database.end())

            throw std::runtime_error("problems with find: search for noexisting value");

        //search for a struct

        cdbxx::iterator it4 = old_database.find("struct key");

        if (it4 == old_database.end())

            throw std::runtime_error("problems with find: search for struct value");

        else

        {

            const test_struct *st_value = it4->second.as_ptr<const test_struct>();

            if ((st_value->a_ != 3) || (st_value->b_ != '3'))

            throw std::runtime_error("wrong struct was returned");

        }

    }

    catch (std::runtime_error e)

    {

        std::cerr << "catch:" << e.what() << std::endl;

        ret = EXIT_FAILURE;

    }

    catch (...)

    {

        std::cerr << "unknown exception\n";

        ret = EXIT_FAILURE;

    }

    //open non existing database

    std::cout << " 5";

    try

    {

        cdbxx::in_db    old_database("./non-existend-databse.cdb");

        ret = EXIT_FAILURE;//we must catch exception

        std::cerr<<"non existent database: cannot catch exception\n";

    }

    catch (cdbxx::open_error)

    {

        //ok if here

    }

    catch (std::runtime_error e)

    {

        std::cerr << "catch:" << e.what() << std::endl;

        ret = EXIT_FAILURE;

    }

    catch (...)

    {

        std::cerr << "unknown exception\n";

        ret = EXIT_FAILURE;

    }

   

    //open on wrong descriptors

    std::cout<< " 6";

    try

    {

        const int test_value = 36;

        int fd = open(db_name3,O_RDWR|O_CREAT,0644);

        //first: fill with values

        {

            std::vector<int> value(1);

            value[0] = test_value;

            cdbxx::out_db    out(fd);

            out.insert("key",value);

        }

       

        //then try to read

        {

            cdbxx::in_db    in(fd);

            cdbxx::iterator it = in.find("key");

            if (it == in.end())

            throw std::runtime_error("unable to find existing key");

            if (it->second.as<const int>() != test_value)

            throw std::runtime_error("reading wrong value");

        }

        close(fd);

    }

    catch (std::runtime_error e)

    {

        std::cerr << "catch:" << e.what() << std::endl;

        ret = EXIT_FAILURE;

    }

    catch (...)

    {

        std::cerr << "unknown exception\n";

        ret = EXIT_FAILURE;

    }

   

    //working with empty database

    std::cout << " 7";

    try

    {

        {

        cdbxx::out_db new_database(empty_db);

        }

        {

        cdbxx::in_db old_database(empty_db);

        std::for_each(old_database.begin(),old_database.end(),no_here);

        }

       

    }

    catch (std::runtime_error& e)

    {

        //catch here

        std::cerr << "catch:" << e.what() << std::endl;

        ret = EXIT_FAILURE;

    }

    catch (...)

    {

        std::cerr << "unknown exception\n";

        ret = EXIT_FAILURE;

    }

    //std::map like interface

    std::cout << " 8";

    try

    {

        {

        cdbxx::out_map<int,std::string>    m(map_name);

        m.set(1,"aaa");

        }

        {

        cdbxx::in_map<int,std::string>    m(map_name);

        if (m.get(1) != "aaa")

            throw std::runtime_error("getting strange value");

        }

       

    }

    catch (std::runtime_error& e)

    {

        //catch here

        std::cerr << "catch:" << e.what() << std::endl;

        ret = EXIT_FAILURE;

    }

    catch (...)

    {

        std::cerr << "unknown exception\n";

        ret = EXIT_FAILURE;

    }

   

   

   

    std::remove(db_name1);

    std::remove(db_name2);

    std::remove(db_name3);

    std::remove(empty_db);

    std::remove(map_name);

    std::cout << "- "<<((EXIT_SUCCESS == ret)?"ok":"failed")<<std::endl;

    return ret;

}