<commit_before>/* This file is part of Zanshin

   Copyright 2014 Kevin Ottens <ervin@kde.org>

   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) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

   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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include <QtTest>

#include "utils/dependencymanager.h"

using namespace Utils;

class Interface0
{
public:
    typedef QSharedPointer<Interface0> Ptr;

    Interface0() {}
    virtual ~Interface0() {}
    virtual void doSomething() = 0;
};

class FirstImplementation0 : public Interface0
{
public:
    virtual void doSomething() { qDebug() << "FirstImplementation"; }
};

class SecondImplementation0 : public Interface0
{
public:
    virtual void doSomething() { qDebug() << "SecondImplementation"; }
};

#define DECLARE_IMPLEMENTED_INTERFACE(N) \
class Interface##N \
{ \
public: \
    typedef QSharedPointer<Interface##N> Ptr; \
 \
    Interface##N() {} \
    virtual ~Interface##N() {} \
    virtual void doSomething() = 0; \
}; \
 \
class Implementation##N : public Interface##N \
{ \
public: \
    virtual void doSomething() { qDebug() << "Implementation##N"; } \
};

DECLARE_IMPLEMENTED_INTERFACE(1)
DECLARE_IMPLEMENTED_INTERFACE(2)
DECLARE_IMPLEMENTED_INTERFACE(3)
DECLARE_IMPLEMENTED_INTERFACE(4)
DECLARE_IMPLEMENTED_INTERFACE(5)
DECLARE_IMPLEMENTED_INTERFACE(6)
DECLARE_IMPLEMENTED_INTERFACE(7)
DECLARE_IMPLEMENTED_INTERFACE(8)
DECLARE_IMPLEMENTED_INTERFACE(9)
DECLARE_IMPLEMENTED_INTERFACE(10)
DECLARE_IMPLEMENTED_INTERFACE(11)
DECLARE_IMPLEMENTED_INTERFACE(12)
DECLARE_IMPLEMENTED_INTERFACE(13)
DECLARE_IMPLEMENTED_INTERFACE(14)

class AnotherInterface
{
public:
    AnotherInterface() {}
    virtual ~AnotherInterface() {}
    virtual void doSomethingDelegated() = 0;
};

class AnotherFirstImplementation : public AnotherInterface
{
public:
    AnotherFirstImplementation(const Interface0::Ptr &iface)
        : m_iface(iface) {}

    void doSomethingDelegated() Q_DECL_OVERRIDE { m_iface->doSomething(); }

    Interface0::Ptr iface() const { return m_iface; }

private:
    Interface0::Ptr m_iface;
};

class AnotherSecondImplementation : public AnotherInterface
{
public:
    AnotherSecondImplementation(Interface0::Ptr iface0,
                                Interface1::Ptr iface1,
                                Interface2::Ptr iface2,
                                Interface3::Ptr iface3,
                                Interface4::Ptr iface4,
                                Interface5::Ptr iface5,
                                Interface6::Ptr iface6,
                                Interface7::Ptr iface7,
                                Interface8::Ptr iface8,
                                Interface9::Ptr iface9,
                                Interface10::Ptr iface10,
                                Interface11::Ptr iface11,
                                Interface12::Ptr iface12,
                                Interface13::Ptr iface13,
                                Interface14::Ptr iface14)
        : m_iface0(iface0),
          m_iface1(iface1),
          m_iface2(iface2),
          m_iface3(iface3),
          m_iface4(iface4),
          m_iface5(iface5),
          m_iface6(iface6),
          m_iface7(iface7),
          m_iface8(iface8),
          m_iface9(iface9),
          m_iface10(iface10),
          m_iface11(iface11),
          m_iface12(iface12),
          m_iface13(iface13),
          m_iface14(iface14)
    {
    }

    void doSomethingDelegated() Q_DECL_OVERRIDE { m_iface1->doSomething(); }

    Interface0::Ptr iface0() const { return m_iface0; }
    Interface1::Ptr iface1() const { return m_iface1; }
    Interface2::Ptr iface2() const { return m_iface2; }
    Interface3::Ptr iface3() const { return m_iface3; }
    Interface4::Ptr iface4() const { return m_iface4; }
    Interface5::Ptr iface5() const { return m_iface5; }
    Interface6::Ptr iface6() const { return m_iface6; }
    Interface7::Ptr iface7() const { return m_iface7; }
    Interface8::Ptr iface8() const { return m_iface8; }
    Interface9::Ptr iface9() const { return m_iface9; }
    Interface10::Ptr iface10() const { return m_iface10; }
    Interface11::Ptr iface11() const { return m_iface11; }
    Interface12::Ptr iface12() const { return m_iface12; }
    Interface13::Ptr iface13() const { return m_iface13; }
    Interface14::Ptr iface14() const { return m_iface14; }

private:
    Interface0::Ptr m_iface0;
    Interface1::Ptr m_iface1;
    Interface2::Ptr m_iface2;
    Interface3::Ptr m_iface3;
    Interface4::Ptr m_iface4;
    Interface5::Ptr m_iface5;
    Interface6::Ptr m_iface6;
    Interface7::Ptr m_iface7;
    Interface8::Ptr m_iface8;
    Interface9::Ptr m_iface9;
    Interface10::Ptr m_iface10;
    Interface11::Ptr m_iface11;
    Interface12::Ptr m_iface12;
    Interface13::Ptr m_iface13;
    Interface14::Ptr m_iface14;
};

class DependencyManagerTest : public QObject
{
    Q_OBJECT
private:
    static bool s_firstImplFactoryCalled;
    static DependencyManager *s_manager;

    static Interface0 *firstImplFactory(DependencyManager *manager)
    {
        s_firstImplFactoryCalled = true;
        s_manager = manager;
        return new FirstImplementation0;
    }

private slots:
    void shouldMemorizeDependency()
    {
        DependencyManager deps;
        deps.add<Interface0, FirstImplementation0>();
        auto object1 = deps.create<Interface0>();
        QVERIFY(object1.dynamicCast<FirstImplementation0>());
        auto object2 = deps.create<Interface0>();
        QVERIFY(object2.dynamicCast<FirstImplementation0>());
        QVERIFY(object1 != object2);
    }

    void shouldAllowOurOwnFactory()
    {
        s_firstImplFactoryCalled = false;
        s_manager = nullptr;
        DependencyManager deps;
        deps.add<Interface0>(&DependencyManagerTest::firstImplFactory);
        auto object = deps.create<Interface0>();
        QVERIFY(object.dynamicCast<FirstImplementation0>());
        QVERIFY(s_firstImplFactoryCalled);
        QVERIFY(s_manager == &deps);
    }

    void shouldAllowUniqueInstances()
    {
        DependencyManager deps;
        deps.add<Interface0, FirstImplementation0, DependencyManager::UniqueInstance>();
        auto object1 = deps.create<Interface0>();
        QVERIFY(object1.dynamicCast<FirstImplementation0>());
        auto object2 = deps.create<Interface0>();
        QVERIFY(object2.dynamicCast<FirstImplementation0>());
        QVERIFY(object1 == object2);
    }

    void shouldAllowUniqueInstancesWithOurOwnFactory()
    {
        s_firstImplFactoryCalled = false;
        s_manager = nullptr;
        DependencyManager deps;
        deps.add<Interface0, DependencyManager::UniqueInstance>(&DependencyManagerTest::firstImplFactory);
        auto object1 = deps.create<Interface0>();
        QVERIFY(object1.dynamicCast<FirstImplementation0>());
        auto object2 = deps.create<Interface0>();
        QVERIFY(object2.dynamicCast<FirstImplementation0>());
        QVERIFY(s_firstImplFactoryCalled);
        QVERIFY(s_manager == &deps);
        QVERIFY(object1 == object2);
    }

    void shouldAllowOurOwnFactoryAsLambda()
    {
#ifdef Q_COMPILER_LAMBDA
        bool ownFactoryCalled = false;
        DependencyManager *managerCalled = nullptr;

        DependencyManager deps;
        deps.add<Interface0>([&](DependencyManager *manager) -> Interface0* {
            ownFactoryCalled = true;
            managerCalled = manager;
            return new FirstImplementation0;
        });
        auto object = deps.create<Interface0>();
        QVERIFY(object.dynamicCast<FirstImplementation0>());
        QVERIFY(ownFactoryCalled);
        QVERIFY(managerCalled == &deps);
#endif
    }

    void shouldMakeManagerSpecificDependencies()
    {
        DependencyManager deps1;
        deps1.add<Interface0, FirstImplementation0>();
        DependencyManager deps2;
        deps2.add<Interface0, SecondImplementation0>();

        auto object1 = deps1.create<Interface0>();
        auto object2 = deps2.create<Interface0>();

        QVERIFY(object1.dynamicCast<FirstImplementation0>());
        QVERIFY(object2.dynamicCast<SecondImplementation0>());
    }

    void shouldCleanupProviders()
    {
        QCOMPARE(Internal::Supplier<Interface0>::providersCount(), 0);

        {
            DependencyManager deps1;
            deps1.add<Interface0, FirstImplementation0>();
            QCOMPARE(Internal::Supplier<Interface0>::providersCount(), 1);

            {
                DependencyManager deps2;
                deps2.add<Interface0, SecondImplementation0>();
                QCOMPARE(Internal::Supplier<Interface0>::providersCount(), 2);
            }

            QCOMPARE(Internal::Supplier<Interface0>::providersCount(), 1);
        }

        QCOMPARE(Internal::Supplier<Interface0>::providersCount(), 0);
    }

    void shouldInjectDependencyInConstructor()
    {
        DependencyManager deps;
        deps.add<Interface0, FirstImplementation0>();
        deps.add<AnotherInterface, AnotherFirstImplementation(Interface0*)>();

        auto object = deps.create<AnotherInterface>();
        auto impl = object.dynamicCast<AnotherFirstImplementation>();
        QVERIFY(impl != Q_NULLPTR);
        QVERIFY(impl->iface().dynamicCast<FirstImplementation0>());
    }

    void shouldInjectDependenciesInConstructor()
    {
        DependencyManager deps;
        deps.add<Interface0, FirstImplementation0>();
        deps.add<Interface1, Implementation1>();
        deps.add<Interface2, Implementation2>();
        deps.add<Interface3, Implementation3>();
        deps.add<Interface4, Implementation4>();
        deps.add<Interface5, Implementation5>();
        deps.add<Interface6, Implementation6>();
        deps.add<Interface7, Implementation7>();
        deps.add<Interface8, Implementation8>();
        deps.add<Interface9, Implementation9>();
        deps.add<Interface10, Implementation10>();
        deps.add<Interface11, Implementation11>();
        deps.add<Interface12, Implementation12>();
        deps.add<Interface13, Implementation13>();
        deps.add<Interface14, Implementation14>();
        deps.add<AnotherInterface, AnotherSecondImplementation(Interface0*,
                                                               Interface1*,
                                                               Interface2*,
                                                               Interface3*,
                                                               Interface4*,
                                                               Interface5*,
                                                               Interface6*,
                                                               Interface7*,
                                                               Interface8*,
                                                               Interface9*,
                                                               Interface10*,
                                                               Interface11*,
                                                               Interface12*,
                                                               Interface13*,
                                                               Interface14*)>();
        auto object = deps.create<AnotherInterface>();
        auto impl = object.dynamicCast<AnotherSecondImplementation>();
        QVERIFY(impl != Q_NULLPTR);
        QVERIFY(impl->iface0().dynamicCast<FirstImplementation0>());
        QVERIFY(impl->iface1().dynamicCast<Implementation1>());
        QVERIFY(impl->iface2().dynamicCast<Implementation2>());
        QVERIFY(impl->iface3().dynamicCast<Implementation3>());
        QVERIFY(impl->iface4().dynamicCast<Implementation4>());
        QVERIFY(impl->iface5().dynamicCast<Implementation5>());
        QVERIFY(impl->iface6().dynamicCast<Implementation6>());
        QVERIFY(impl->iface7().dynamicCast<Implementation7>());
        QVERIFY(impl->iface8().dynamicCast<Implementation8>());
        QVERIFY(impl->iface9().dynamicCast<Implementation9>());
        QVERIFY(impl->iface10().dynamicCast<Implementation10>());
        QVERIFY(impl->iface11().dynamicCast<Implementation11>());
        QVERIFY(impl->iface12().dynamicCast<Implementation12>());
        QVERIFY(impl->iface13().dynamicCast<Implementation13>());
        QVERIFY(impl->iface14().dynamicCast<Implementation14>());
    }
};

bool DependencyManagerTest::s_firstImplFactoryCalled = false;
DependencyManager *DependencyManagerTest::s_manager = nullptr;

QTEST_MAIN(DependencyManagerTest)

#include "dependencymanagertest.moc"
<commit_msg>Use Q_NULLPTR instead of nullptr<commit_after>/* This file is part of Zanshin

   Copyright 2014 Kevin Ottens <ervin@kde.org>

   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) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

   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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include <QtTest>

#include "utils/dependencymanager.h"

using namespace Utils;

class Interface0
{
public:
    typedef QSharedPointer<Interface0> Ptr;

    Interface0() {}
    virtual ~Interface0() {}
    virtual void doSomething() = 0;
};

class FirstImplementation0 : public Interface0
{
public:
    virtual void doSomething() { qDebug() << "FirstImplementation"; }
};

class SecondImplementation0 : public Interface0
{
public:
    virtual void doSomething() { qDebug() << "SecondImplementation"; }
};

#define DECLARE_IMPLEMENTED_INTERFACE(N) \
class Interface##N \
{ \
public: \
    typedef QSharedPointer<Interface##N> Ptr; \
 \
    Interface##N() {} \
    virtual ~Interface##N() {} \
    virtual void doSomething() = 0; \
}; \
 \
class Implementation##N : public Interface##N \
{ \
public: \
    virtual void doSomething() { qDebug() << "Implementation##N"; } \
};

DECLARE_IMPLEMENTED_INTERFACE(1)
DECLARE_IMPLEMENTED_INTERFACE(2)
DECLARE_IMPLEMENTED_INTERFACE(3)
DECLARE_IMPLEMENTED_INTERFACE(4)
DECLARE_IMPLEMENTED_INTERFACE(5)
DECLARE_IMPLEMENTED_INTERFACE(6)
DECLARE_IMPLEMENTED_INTERFACE(7)
DECLARE_IMPLEMENTED_INTERFACE(8)
DECLARE_IMPLEMENTED_INTERFACE(9)
DECLARE_IMPLEMENTED_INTERFACE(10)
DECLARE_IMPLEMENTED_INTERFACE(11)
DECLARE_IMPLEMENTED_INTERFACE(12)
DECLARE_IMPLEMENTED_INTERFACE(13)
DECLARE_IMPLEMENTED_INTERFACE(14)

class AnotherInterface
{
public:
    AnotherInterface() {}
    virtual ~AnotherInterface() {}
    virtual void doSomethingDelegated() = 0;
};

class AnotherFirstImplementation : public AnotherInterface
{
public:
    AnotherFirstImplementation(const Interface0::Ptr &iface)
        : m_iface(iface) {}

    void doSomethingDelegated() Q_DECL_OVERRIDE { m_iface->doSomething(); }

    Interface0::Ptr iface() const { return m_iface; }

private:
    Interface0::Ptr m_iface;
};

class AnotherSecondImplementation : public AnotherInterface
{
public:
    AnotherSecondImplementation(Interface0::Ptr iface0,
                                Interface1::Ptr iface1,
                                Interface2::Ptr iface2,
                                Interface3::Ptr iface3,
                                Interface4::Ptr iface4,
                                Interface5::Ptr iface5,
                                Interface6::Ptr iface6,
                                Interface7::Ptr iface7,
                                Interface8::Ptr iface8,
                                Interface9::Ptr iface9,
                                Interface10::Ptr iface10,
                                Interface11::Ptr iface11,
                                Interface12::Ptr iface12,
                                Interface13::Ptr iface13,
                                Interface14::Ptr iface14)
        : m_iface0(iface0),
          m_iface1(iface1),
          m_iface2(iface2),
          m_iface3(iface3),
          m_iface4(iface4),
          m_iface5(iface5),
          m_iface6(iface6),
          m_iface7(iface7),
          m_iface8(iface8),
          m_iface9(iface9),
          m_iface10(iface10),
          m_iface11(iface11),
          m_iface12(iface12),
          m_iface13(iface13),
          m_iface14(iface14)
    {
    }

    void doSomethingDelegated() Q_DECL_OVERRIDE { m_iface1->doSomething(); }

    Interface0::Ptr iface0() const { return m_iface0; }
    Interface1::Ptr iface1() const { return m_iface1; }
    Interface2::Ptr iface2() const { return m_iface2; }
    Interface3::Ptr iface3() const { return m_iface3; }
    Interface4::Ptr iface4() const { return m_iface4; }
    Interface5::Ptr iface5() const { return m_iface5; }
    Interface6::Ptr iface6() const { return m_iface6; }
    Interface7::Ptr iface7() const { return m_iface7; }
    Interface8::Ptr iface8() const { return m_iface8; }
    Interface9::Ptr iface9() const { return m_iface9; }
    Interface10::Ptr iface10() const { return m_iface10; }
    Interface11::Ptr iface11() const { return m_iface11; }
    Interface12::Ptr iface12() const { return m_iface12; }
    Interface13::Ptr iface13() const { return m_iface13; }
    Interface14::Ptr iface14() const { return m_iface14; }

private:
    Interface0::Ptr m_iface0;
    Interface1::Ptr m_iface1;
    Interface2::Ptr m_iface2;
    Interface3::Ptr m_iface3;
    Interface4::Ptr m_iface4;
    Interface5::Ptr m_iface5;
    Interface6::Ptr m_iface6;
    Interface7::Ptr m_iface7;
    Interface8::Ptr m_iface8;
    Interface9::Ptr m_iface9;
    Interface10::Ptr m_iface10;
    Interface11::Ptr m_iface11;
    Interface12::Ptr m_iface12;
    Interface13::Ptr m_iface13;
    Interface14::Ptr m_iface14;
};

class DependencyManagerTest : public QObject
{
    Q_OBJECT
private:
    static bool s_firstImplFactoryCalled;
    static DependencyManager *s_manager;

    static Interface0 *firstImplFactory(DependencyManager *manager)
    {
        s_firstImplFactoryCalled = true;
        s_manager = manager;
        return new FirstImplementation0;
    }

private slots:
    void shouldMemorizeDependency()
    {
        DependencyManager deps;
        deps.add<Interface0, FirstImplementation0>();
        auto object1 = deps.create<Interface0>();
        QVERIFY(object1.dynamicCast<FirstImplementation0>());
        auto object2 = deps.create<Interface0>();
        QVERIFY(object2.dynamicCast<FirstImplementation0>());
        QVERIFY(object1 != object2);
    }

    void shouldAllowOurOwnFactory()
    {
        s_firstImplFactoryCalled = false;
        s_manager = Q_NULLPTR;
        DependencyManager deps;
        deps.add<Interface0>(&DependencyManagerTest::firstImplFactory);
        auto object = deps.create<Interface0>();
        QVERIFY(object.dynamicCast<FirstImplementation0>());
        QVERIFY(s_firstImplFactoryCalled);
        QVERIFY(s_manager == &deps);
    }

    void shouldAllowUniqueInstances()
    {
        DependencyManager deps;
        deps.add<Interface0, FirstImplementation0, DependencyManager::UniqueInstance>();
        auto object1 = deps.create<Interface0>();
        QVERIFY(object1.dynamicCast<FirstImplementation0>());
        auto object2 = deps.create<Interface0>();
        QVERIFY(object2.dynamicCast<FirstImplementation0>());
        QVERIFY(object1 == object2);
    }

    void shouldAllowUniqueInstancesWithOurOwnFactory()
    {
        s_firstImplFactoryCalled = false;
        s_manager = Q_NULLPTR;
        DependencyManager deps;
        deps.add<Interface0, DependencyManager::UniqueInstance>(&DependencyManagerTest::firstImplFactory);
        auto object1 = deps.create<Interface0>();
        QVERIFY(object1.dynamicCast<FirstImplementation0>());
        auto object2 = deps.create<Interface0>();
        QVERIFY(object2.dynamicCast<FirstImplementation0>());
        QVERIFY(s_firstImplFactoryCalled);
        QVERIFY(s_manager == &deps);
        QVERIFY(object1 == object2);
    }

    void shouldAllowOurOwnFactoryAsLambda()
    {
#ifdef Q_COMPILER_LAMBDA
        bool ownFactoryCalled = false;
        DependencyManager *managerCalled = Q_NULLPTR;

        DependencyManager deps;
        deps.add<Interface0>([&](DependencyManager *manager) -> Interface0* {
            ownFactoryCalled = true;
            managerCalled = manager;
            return new FirstImplementation0;
        });
        auto object = deps.create<Interface0>();
        QVERIFY(object.dynamicCast<FirstImplementation0>());
        QVERIFY(ownFactoryCalled);
        QVERIFY(managerCalled == &deps);
#endif
    }

    void shouldMakeManagerSpecificDependencies()
    {
        DependencyManager deps1;
        deps1.add<Interface0, FirstImplementation0>();
        DependencyManager deps2;
        deps2.add<Interface0, SecondImplementation0>();

        auto object1 = deps1.create<Interface0>();
        auto object2 = deps2.create<Interface0>();

        QVERIFY(object1.dynamicCast<FirstImplementation0>());
        QVERIFY(object2.dynamicCast<SecondImplementation0>());
    }

    void shouldCleanupProviders()
    {
        QCOMPARE(Internal::Supplier<Interface0>::providersCount(), 0);

        {
            DependencyManager deps1;
            deps1.add<Interface0, FirstImplementation0>();
            QCOMPARE(Internal::Supplier<Interface0>::providersCount(), 1);

            {
                DependencyManager deps2;
                deps2.add<Interface0, SecondImplementation0>();
                QCOMPARE(Internal::Supplier<Interface0>::providersCount(), 2);
            }

            QCOMPARE(Internal::Supplier<Interface0>::providersCount(), 1);
        }

        QCOMPARE(Internal::Supplier<Interface0>::providersCount(), 0);
    }

    void shouldInjectDependencyInConstructor()
    {
        DependencyManager deps;
        deps.add<Interface0, FirstImplementation0>();
        deps.add<AnotherInterface, AnotherFirstImplementation(Interface0*)>();

        auto object = deps.create<AnotherInterface>();
        auto impl = object.dynamicCast<AnotherFirstImplementation>();
        QVERIFY(impl != Q_NULLPTR);
        QVERIFY(impl->iface().dynamicCast<FirstImplementation0>());
    }

    void shouldInjectDependenciesInConstructor()
    {
        DependencyManager deps;
        deps.add<Interface0, FirstImplementation0>();
        deps.add<Interface1, Implementation1>();
        deps.add<Interface2, Implementation2>();
        deps.add<Interface3, Implementation3>();
        deps.add<Interface4, Implementation4>();
        deps.add<Interface5, Implementation5>();
        deps.add<Interface6, Implementation6>();
        deps.add<Interface7, Implementation7>();
        deps.add<Interface8, Implementation8>();
        deps.add<Interface9, Implementation9>();
        deps.add<Interface10, Implementation10>();
        deps.add<Interface11, Implementation11>();
        deps.add<Interface12, Implementation12>();
        deps.add<Interface13, Implementation13>();
        deps.add<Interface14, Implementation14>();
        deps.add<AnotherInterface, AnotherSecondImplementation(Interface0*,
                                                               Interface1*,
                                                               Interface2*,
                                                               Interface3*,
                                                               Interface4*,
                                                               Interface5*,
                                                               Interface6*,
                                                               Interface7*,
                                                               Interface8*,
                                                               Interface9*,
                                                               Interface10*,
                                                               Interface11*,
                                                               Interface12*,
                                                               Interface13*,
                                                               Interface14*)>();
        auto object = deps.create<AnotherInterface>();
        auto impl = object.dynamicCast<AnotherSecondImplementation>();
        QVERIFY(impl != Q_NULLPTR);
        QVERIFY(impl->iface0().dynamicCast<FirstImplementation0>());
        QVERIFY(impl->iface1().dynamicCast<Implementation1>());
        QVERIFY(impl->iface2().dynamicCast<Implementation2>());
        QVERIFY(impl->iface3().dynamicCast<Implementation3>());
        QVERIFY(impl->iface4().dynamicCast<Implementation4>());
        QVERIFY(impl->iface5().dynamicCast<Implementation5>());
        QVERIFY(impl->iface6().dynamicCast<Implementation6>());
        QVERIFY(impl->iface7().dynamicCast<Implementation7>());
        QVERIFY(impl->iface8().dynamicCast<Implementation8>());
        QVERIFY(impl->iface9().dynamicCast<Implementation9>());
        QVERIFY(impl->iface10().dynamicCast<Implementation10>());
        QVERIFY(impl->iface11().dynamicCast<Implementation11>());
        QVERIFY(impl->iface12().dynamicCast<Implementation12>());
        QVERIFY(impl->iface13().dynamicCast<Implementation13>());
        QVERIFY(impl->iface14().dynamicCast<Implementation14>());
    }
};

bool DependencyManagerTest::s_firstImplFactoryCalled = false;
DependencyManager *DependencyManagerTest::s_manager = Q_NULLPTR;

QTEST_MAIN(DependencyManagerTest)

#include "dependencymanagertest.moc"
<|endoftext|>


<commit_before>#ifndef OBSERVERS_HPP_
#define OBSERVERS_HPP_

#include <fstream>
#include <iostream>
#include <cstdio>
#include "model.hpp"
#include "Photon.hpp"

// pictures
class Pictures
{
    public:
        Pictures(uint32_t nx, uint32_t ny)
            : nx_{ nx }
            , ny_{ ny }
        {
            f_ = new double[ nx*ny ]();
            q_ = new double[ nx*ny ]();
            u_ = new double[ nx*ny ]();
        }

        ~Pictures()
        {
            delete[] f_;
            delete[] q_;
            delete[] u_;
        }

        Pictures (Pictures const& other) = delete;
        Pictures& operator=(Pictures const& other) = delete;

        Pictures (Pictures&& other) = default;
        Pictures& operator=(Pictures&& other) = default;

        // place photon on the images
        void bin(Photon const& ph, int64_t const xl, int64_t const yl, int64_t const id)
        {
            // place weighted photon into image location
            if((id == -1 || static_cast<size_t>(id) == ph.nscat()) && (xl>=0) && (yl >= 0) && ((uint32_t)xl < nx_) && ((uint32_t)yl < ny_) )
            {
                f_[xl+yl*nx_] += ph.weight()*ph.fi();
                q_[xl+yl*nx_] += ph.weight()*ph.fq();
                u_[xl+yl*nx_] += ph.weight()*ph.fu();
            }
        }

        void normalize(size_t const numPhotons)
        {
            for (size_t i=0; i!=nx_*ny_; ++i)
            {
               f_[i] /= numPhotons;
               q_[i] /= numPhotons;
               u_[i] /= numPhotons;
            }
        }

        void write(double const phi, double const theta, int const key) const
        {
            int const FILENAME_LENGTH{ 30 };
            char fname[FILENAME_LENGTH];
            int const iPhi = int(phi*180/3.1415926+0.5);
            int const iTheta = int(theta*180/3.1415926+0.5);

            snprintf(fname, FILENAME_LENGTH, "fimage%2.2i_%2.2i_%2.2i.dat", iPhi, iTheta, key);
            std::ofstream f(fname);
            for (size_t y=0; y != ny_; ++y)
            {
                for (size_t x=0; x!=nx_; ++x)
                    f << f_[x+y*nx_] << "\t";
                f << "\n";
            }
            f.close();

            snprintf(fname, FILENAME_LENGTH, "qimage%2.2i_%2.2i_%2.2i.dat", iPhi, iTheta, key);
            std::ofstream q(fname);
            for (size_t y=0; y != ny_; ++y)
            {
                for (size_t x=0; x!=nx_; ++x)
                    q << q_[x+y*nx_] << "\t";
                q << "\n";
            }
            q.close();

            snprintf(fname, FILENAME_LENGTH, "uimage%2.2i_%2.2i_%2.2i.dat", iPhi, iTheta, key);
            std::ofstream u(fname);
            for (size_t y=0; y != ny_; ++y)
            {
                for (size_t x=0; x!=nx_; ++x)
                    u << u_[x+y*nx_] << "\t";
                u << "\n";
            }
            u.close();
        }

        void sum(std::ofstream& file)
        {
            double fsum=0, qsum=0, usum=0;
            for (size_t x=0; x!=nx_; ++x)
            {
                for (size_t y=0; y != ny_; ++y)
                {
                    fsum += f_[y + x * ny_];
                    qsum += q_[y + x * ny_];
                    usum += u_[y + x * ny_];
                }
            }
            file << "\tF= " << fsum << "\tQ= " << qsum << "\tU= " << usum
                    << "\tp= " << std::sqrt(qsum*qsum + usum*usum)/fsum
                    << "\tphi= " << 90 * std::atan2(usum, qsum)/3.1415926 << "\n" ;
        }

    private:
        uint32_t nx_, ny_;
        double *f_;
        double *q_;
        double *u_;
};

class Observer
{
public:
    Observer(double const phi, double const theta, double const rimage, uint32_t const Nx=200, uint32_t const Ny=200)
            : result_(Nx, Ny)
            , result0_(Nx, Ny)
            , result1_(Nx, Ny)
            , result2_(Nx, Ny)
            , direction_{phi, theta}
            , nx_(Nx)
            , ny_(Ny)
    {
        rimage_ = rimage;
        theta_ = theta;

        cosp_ = std::cos(phi);
        sinp_ = std::sin(phi);
    }

    void normalize(size_t const numPhotons)
    {
        result_.normalize(numPhotons);
        result0_.normalize(numPhotons);
        result1_.normalize(numPhotons);
        result2_.normalize(numPhotons);
    }

    void writeToMapFiles(bool const fWriteSingleAndDoubleScatterings)
    {
        result_.write(direction_.phi(), theta_, 0);

        if (fWriteSingleAndDoubleScatterings)
        {
            result1_.write(direction_.phi(), theta_, 1);
            result2_.write(direction_.phi(), theta_, 2);
        }
    }

    void write(std::ofstream& file)
    {
        file << "phi = " << (direction_.phi()*180/3.1415926) << "\ttheta = " << (theta_*180/3.1415926);
        result_.sum(file);
        result0_.sum(file);
    }

    void bin(Photon const& photon)
    {
        double const yimage = rimage_ + photon.pos().z() * direction_.sinTheta() -
            direction_.cosTheta() * (photon.pos().y()*sinp_ + photon.pos().x()*cosp_);

        double const ximage = rimage_ + photon.pos().y()*cosp_ - photon.pos().x()*sinp_;

        auto const xl = static_cast<int64_t>(nx_ * ximage / (2.0 * rimage_));
        auto const yl = static_cast<int64_t>(ny_ * yimage / (2.0 * rimage_));
        result_.bin(photon, xl, yl, -1);
        result0_.bin(photon, xl, yl, 0);
        result1_.bin(photon, xl, yl, 1);
        result2_.bin(photon, xl, yl, 2);
    }

    double phi() const
    {	return direction_.phi();	}
    double theta() const
    {	return theta_;	}
    const Direction3d& direction() const
    {	return direction_;}

    Observer(Observer const& other) = delete;
    Observer& operator=(Observer const& other) = delete;

    Observer(Observer&& other) = default;
    Observer& operator=(Observer&& other) = default;

private:
    Pictures result_, result0_, result1_, result2_;
    Direction3d direction_;
    uint32_t nx_, ny_;
    double rimage_;
    double theta_;
    double cosp_, sinp_;
};

#endif
<commit_msg>Fix Pictures move constructor<commit_after>#ifndef OBSERVERS_HPP_
#define OBSERVERS_HPP_

#include <fstream>
#include <iostream>
#include <cstdio>
#include "model.hpp"
#include "Photon.hpp"

// pictures
class Pictures
{
    public:
        Pictures(uint32_t nx, uint32_t ny)
            : nx_{ nx }
            , ny_{ ny }
        {
            f_ = new double[ nx*ny ]();
            q_ = new double[ nx*ny ]();
            u_ = new double[ nx*ny ]();
        }

        ~Pictures()
        {
            delete[] f_;
            delete[] q_;
            delete[] u_;
        }

        Pictures (Pictures const& other) = delete;
        Pictures& operator=(Pictures const& other) = delete;

        Pictures(Pictures&& other) noexcept
            : nx_{ other.nx_ }
            , ny_{ other.ny_ }
            , f_{ other.f_ }
            , q_{ other.q_ }
            , u_{ other.u_ }
        {
            other.f_ = nullptr;
            other.q_ = nullptr;
            other.u_ = nullptr;
        }

        Pictures& operator=(Pictures&& other) noexcept
        {
            std::swap(f_, other.f_);
            std::swap(q_, other.q_);
            std::swap(u_, other.u_);
            nx_ = other.nx_;
            ny_ = other.ny_;
            return *this;
        }

        // place photon on the images
        void bin(Photon const& ph, int64_t const xl, int64_t const yl, int64_t const id)
        {
            // place weighted photon into image location
            if((id == -1 || static_cast<size_t>(id) == ph.nscat()) && (xl>=0) && (yl >= 0) && ((uint32_t)xl < nx_) && ((uint32_t)yl < ny_) )
            {
                f_[xl+yl*nx_] += ph.weight()*ph.fi();
                q_[xl+yl*nx_] += ph.weight()*ph.fq();
                u_[xl+yl*nx_] += ph.weight()*ph.fu();
            }
        }

        void normalize(size_t const numPhotons)
        {
            for (size_t i=0; i!=nx_*ny_; ++i)
            {
               f_[i] /= numPhotons;
               q_[i] /= numPhotons;
               u_[i] /= numPhotons;
            }
        }

        void write(double const phi, double const theta, int const key) const
        {
            int const FILENAME_LENGTH{ 30 };
            char fname[FILENAME_LENGTH];
            int const iPhi = int(phi*180/3.1415926+0.5);
            int const iTheta = int(theta*180/3.1415926+0.5);

            snprintf(fname, FILENAME_LENGTH, "fimage%2.2i_%2.2i_%2.2i.dat", iPhi, iTheta, key);
            std::ofstream f(fname);
            for (size_t y=0; y != ny_; ++y)
            {
                for (size_t x=0; x!=nx_; ++x)
                    f << f_[x+y*nx_] << "\t";
                f << "\n";
            }
            f.close();

            snprintf(fname, FILENAME_LENGTH, "qimage%2.2i_%2.2i_%2.2i.dat", iPhi, iTheta, key);
            std::ofstream q(fname);
            for (size_t y=0; y != ny_; ++y)
            {
                for (size_t x=0; x!=nx_; ++x)
                    q << q_[x+y*nx_] << "\t";
                q << "\n";
            }
            q.close();

            snprintf(fname, FILENAME_LENGTH, "uimage%2.2i_%2.2i_%2.2i.dat", iPhi, iTheta, key);
            std::ofstream u(fname);
            for (size_t y=0; y != ny_; ++y)
            {
                for (size_t x=0; x!=nx_; ++x)
                    u << u_[x+y*nx_] << "\t";
                u << "\n";
            }
            u.close();
        }

        void sum(std::ofstream& file)
        {
            double fsum=0, qsum=0, usum=0;
            for (size_t x=0; x!=nx_; ++x)
            {
                for (size_t y=0; y != ny_; ++y)
                {
                    fsum += f_[y + x * ny_];
                    qsum += q_[y + x * ny_];
                    usum += u_[y + x * ny_];
                }
            }
            file << "\tF= " << fsum << "\tQ= " << qsum << "\tU= " << usum
                    << "\tp= " << std::sqrt(qsum*qsum + usum*usum)/fsum
                    << "\tphi= " << 90 * std::atan2(usum, qsum)/3.1415926 << "\n" ;
        }

    private:
        uint32_t nx_, ny_;
        double *f_;
        double *q_;
        double *u_;
};

class Observer
{
public:
    Observer(double const phi, double const theta, double const rimage, uint32_t const Nx=200, uint32_t const Ny=200)
            : result_(Nx, Ny)
            , result0_(Nx, Ny)
            , result1_(Nx, Ny)
            , result2_(Nx, Ny)
            , direction_{phi, theta}
            , nx_(Nx)
            , ny_(Ny)
    {
        rimage_ = rimage;
        theta_ = theta;

        cosp_ = std::cos(phi);
        sinp_ = std::sin(phi);
    }

    void normalize(size_t const numPhotons)
    {
        result_.normalize(numPhotons);
        result0_.normalize(numPhotons);
        result1_.normalize(numPhotons);
        result2_.normalize(numPhotons);
    }

    void writeToMapFiles(bool const fWriteSingleAndDoubleScatterings)
    {
        result_.write(direction_.phi(), theta_, 0);

        if (fWriteSingleAndDoubleScatterings)
        {
            result1_.write(direction_.phi(), theta_, 1);
            result2_.write(direction_.phi(), theta_, 2);
        }
    }

    void write(std::ofstream& file)
    {
        file << "phi = " << (direction_.phi()*180/3.1415926) << "\ttheta = " << (theta_*180/3.1415926);
        result_.sum(file);
        result0_.sum(file);
    }

    void bin(Photon const& photon)
    {
        double const yimage = rimage_ + photon.pos().z() * direction_.sinTheta() -
            direction_.cosTheta() * (photon.pos().y()*sinp_ + photon.pos().x()*cosp_);

        double const ximage = rimage_ + photon.pos().y()*cosp_ - photon.pos().x()*sinp_;

        auto const xl = static_cast<int64_t>(nx_ * ximage / (2.0 * rimage_));
        auto const yl = static_cast<int64_t>(ny_ * yimage / (2.0 * rimage_));
        result_.bin(photon, xl, yl, -1);
        result0_.bin(photon, xl, yl, 0);
        result1_.bin(photon, xl, yl, 1);
        result2_.bin(photon, xl, yl, 2);
    }

    double phi() const
    {	return direction_.phi();	}
    double theta() const
    {	return theta_;	}
    const Direction3d& direction() const
    {	return direction_;}

    Observer(Observer const& other) = delete;
    Observer& operator=(Observer const& other) = delete;

    Observer(Observer&& other) = default;
    Observer& operator=(Observer&& other) = default;

private:
    Pictures result_, result0_, result1_, result2_;
    Direction3d direction_;
    uint32_t nx_, ny_;
    double rimage_;
    double theta_;
    double cosp_, sinp_;
};

#endif
<|endoftext|>


<commit_before>/*!
 * \page CRSTestSuite_cpp Command-Line Test to Demonstrate How To Test the SimCRS Project
 * \code
 */
// //////////////////////////////////////////////////////////////////////
// Import section
// //////////////////////////////////////////////////////////////////////
// STL
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <cmath>
// Boost Unit Test Framework (UTF)
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
#define BOOST_TEST_MODULE CRSTestSuite
#include <boost/test/unit_test.hpp>
// StdAir
#include <stdair/basic/BasLogParams.hpp>
#include <stdair/basic/BasDBParams.hpp>
#include <stdair/basic/BasFileMgr.hpp>
#include <stdair/bom/TravelSolutionStruct.hpp>
#include <stdair/bom/BookingRequestStruct.hpp>
#include <stdair/service/Logger.hpp>
// SimCRS
#include <simcrs/SIMCRS_Service.hpp>
#include <simcrs/config/simcrs-paths.hpp>

namespace boost_utf = boost::unit_test;

/**
 * Configuration for the Boost Unit Test Framework (UTF)
 */
struct UnitTestConfig {
  /** Constructor. */
  UnitTestConfig() : _test_log ("CRSTestSuite_utfresults.xml")  {
    boost_utf::unit_test_log.set_stream (_test_log);
    boost_utf::unit_test_log.set_format (boost_utf::XML);
    boost_utf::unit_test_log.set_threshold_level (boost_utf::log_test_units);
  }
  /** Destructor. */
  ~UnitTestConfig() {
    boost_utf::unit_test_log.set_stream (std::cout);
  }
  /** Log file */
  std::ofstream _test_log;
};

// /////////////// Main: Unit Test Suite //////////////

// Set the UTF configuration (re-direct the output to a specific file)
BOOST_GLOBAL_FIXTURE (UnitTestConfig);

// Start the test suite
BOOST_AUTO_TEST_SUITE (master_test_suite)

/**
 * Test a simple simulation
 */
BOOST_AUTO_TEST_CASE (simcrs_simple_simulation_test) {

  // CRS code
  const std::string lCRSCode ("1P");

  // Schedule input filename
  const std::string lScheduleInputFilename (STDAIR_SAMPLE_DIR
                                            "/schedule01.csv");

  // O&D input filename
  const std::string lODInputFilename (STDAIR_SAMPLE_DIR "/ond01.csv");

  // Fare input filename
  const std::string lFareInputFilename (STDAIR_SAMPLE_DIR "/fare01.csv");

  // Check that the file path given as input corresponds to an actual file
  bool doesExistAndIsReadable =
    stdair::BasFileMgr::doesExistAndIsReadable (lScheduleInputFilename);
  BOOST_CHECK_MESSAGE (doesExistAndIsReadable == true,
                       "The '" << lScheduleInputFilename
                       << "' input file can not be open and read");

  // Check that the file path given as input corresponds to an actual file
  doesExistAndIsReadable =
    stdair::BasFileMgr::doesExistAndIsReadable (lODInputFilename);
  BOOST_CHECK_MESSAGE (doesExistAndIsReadable == true,
                       "The '" << lODInputFilename
                       << "' input file can not be open and read");

  // Check that the file path given as input corresponds to an actual file
  doesExistAndIsReadable =
    stdair::BasFileMgr::doesExistAndIsReadable (lFareInputFilename);
  BOOST_CHECK_MESSAGE (doesExistAndIsReadable == true,
                       "The '" << lFareInputFilename
                       << "' input file can not be open and read");

  // Output log File
  const std::string lLogFilename ("CRSTestSuite.log");

  // Set the log parameters
  std::ofstream logOutputFile;
  // Open and clean the log outputfile
  logOutputFile.open (lLogFilename.c_str());
  logOutputFile.clear();

  // Initialise the list of classes/buckets
  const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
  SIMCRS::SIMCRS_Service simcrsService (lLogParams, lCRSCode,
                                        lScheduleInputFilename,
                                        lODInputFilename, lFareInputFilename);

  // Create an empty booking request structure
  // TODO: fill the booking request structure from the input parameters
  const stdair::AirportCode_T lOrigin ("SIN");
  const stdair::AirportCode_T lDestination ("BKK");
  const stdair::AirportCode_T lPOS ("SIN");
  const stdair::Date_T lPreferredDepartureDate(2010, boost::gregorian::Jan, 30);
  const stdair::Date_T lRequestDate (2010, boost::gregorian::Jan, 22);
  const stdair::Duration_T lRequestTime (boost::posix_time::hours(10));
  const stdair::DateTime_T lRequestDateTime (lRequestDate, lRequestTime);
  const stdair::CabinCode_T lPreferredCabin ("Eco");
  const stdair::NbOfSeats_T lPartySize (1);
  const stdair::ChannelLabel_T lChannel ("IN");
  const stdair::TripType_T lTripType ("RI");
  const stdair::DayDuration_T lStayDuration (7);
  const stdair::FrequentFlyer_T lFrequentFlyerType ("M");
  const stdair::Duration_T lPreferredDepartureTime (boost::posix_time::hours(10));
  const stdair::WTP_T lWTP (1000.0);
  const stdair::PriceValue_T lValueOfTime (100.0);
  const stdair::BookingRequestStruct lBookingRequest (lOrigin, lDestination,
                                                      lPOS,
                                                      lPreferredDepartureDate,
                                                      lRequestDateTime,
                                                      lPreferredCabin,
                                                      lPartySize, lChannel,
                                                      lTripType, lStayDuration,
                                                      lFrequentFlyerType,
                                                      lPreferredDepartureTime,
                                                      lWTP, lValueOfTime);
  const stdair::SegmentPathList_T lSegmentPath =
    simcrsService.calculateSegmentPathList(lBookingRequest);

  // Price the travel solution
  stdair::TravelSolutionList_T lTravelSolutionList =
    simcrsService.fareQuote (lBookingRequest, lSegmentPath);

  //
  const unsigned int lNbOfTravelSolutions = lTravelSolutionList.size();

  // TODO: change the expected number of travel solutions to the actual number
  const unsigned int lExpectedNbOfTravelSolutions = 2;

  // DEBUG
  STDAIR_LOG_DEBUG ("Number of travel solutions for the booking request '"
                    << lBookingRequest.describe() << "': "
                    << lNbOfTravelSolutions << ". It is expected to be "
                    << lExpectedNbOfTravelSolutions);

  BOOST_CHECK_EQUAL (lNbOfTravelSolutions, lExpectedNbOfTravelSolutions);

  BOOST_CHECK_MESSAGE(lNbOfTravelSolutions == lExpectedNbOfTravelSolutions,
                      "The number of travel solutions for the booking request '"
                      << lBookingRequest.describe() << "' is equal to "
                      << lNbOfTravelSolutions << ", but it should be equal to "
                      << lExpectedNbOfTravelSolutions);

  /* TODO: uncomment as soon as travel solutions are found for that
     booking request
  //
  const stdair::TravelSolutionStruct& lTravelSolution =
    lTravelSolutionList.front();

  //
  const unsigned int lExpectedPrice = 1000;

  // DEBUG
  STDAIR_LOG_DEBUG ("The price given by the fare quoter for '"
                    << lTravelSolution.describe() << "' is: "
                    << lTravelSolution.getFare() << " Euros, and should be "
                    << lExpectedPrice);

  BOOST_CHECK_EQUAL (std::floor (lTravelSolution.getFare() + 0.5),
                     lExpectedPrice);

  BOOST_CHECK_MESSAGE (std::floor (lTravelSolution.getFare() + 0.5)
                       == lExpectedPrice,
                       "The price given by the fare quoter for '"
                       << lTravelSolution.describe() << "' is: "
                       << lTravelSolution.getFare() << " Euros, and should be "
                       << lExpectedPrice);
  */

  // Make a booking
  // const std::string lAirlineCode ("SV");
  // const stdair::PartySize_T lPartySize = 5;
  // BOOST_CHECK_NO_THROW (simcrsService.sell (lAirlineCode, lPartySize));

  // Close the log file
  logOutputFile.close();
}

// End the test suite
BOOST_AUTO_TEST_SUITE_END()

/*!
 * \endcode
 */

<commit_msg>[Test] The </TestLog> tag is now added at the end of the XML test report.<commit_after>/*!
 * \page CRSTestSuite_cpp Command-Line Test to Demonstrate How To Test the SimCRS Project
 * \code
 */
// //////////////////////////////////////////////////////////////////////
// Import section
// //////////////////////////////////////////////////////////////////////
// STL
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <cmath>
// Boost Unit Test Framework (UTF)
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
#define BOOST_TEST_MODULE CRSTestSuite
#include <boost/test/unit_test.hpp>
// StdAir
#include <stdair/basic/BasLogParams.hpp>
#include <stdair/basic/BasDBParams.hpp>
#include <stdair/basic/BasFileMgr.hpp>
#include <stdair/bom/TravelSolutionStruct.hpp>
#include <stdair/bom/BookingRequestStruct.hpp>
#include <stdair/service/Logger.hpp>
// SimCRS
#include <simcrs/SIMCRS_Service.hpp>
#include <simcrs/config/simcrs-paths.hpp>

namespace boost_utf = boost::unit_test;

/**
 * Configuration for the Boost Unit Test Framework (UTF)
 */
struct UnitTestConfig {
  /** Constructor. */
  UnitTestConfig() {
    static std::ofstream _test_log ("CRSTestSuite_utfresults.xml");
    boost_utf::unit_test_log.set_stream (_test_log);
    boost_utf::unit_test_log.set_format (boost_utf::XML);
    boost_utf::unit_test_log.set_threshold_level (boost_utf::log_test_units);
    //boost_utf::unit_test_log.set_threshold_level (boost_utf::log_successful_tests);
  }

  /** Destructor. */
  ~UnitTestConfig() {
  }
};

// /////////////// Main: Unit Test Suite //////////////

// Set the UTF configuration (re-direct the output to a specific file)
BOOST_GLOBAL_FIXTURE (UnitTestConfig);

// Start the test suite
BOOST_AUTO_TEST_SUITE (master_test_suite)

/**
 * Test a simple simulation
 */
BOOST_AUTO_TEST_CASE (simcrs_simple_simulation_test) {

  // CRS code
  const SIMCRS::CRSCode_T lCRSCode ("1P");

  // Schedule input filename
  const stdair::Filename_T lScheduleInputFilename (STDAIR_SAMPLE_DIR
                                                   "/schedule01.csv");

  // O&D input filename
  const stdair::Filename_T lODInputFilename (STDAIR_SAMPLE_DIR "/ond01.csv");

  // Fare input filename
  const stdair::Filename_T lFareInputFilename (STDAIR_SAMPLE_DIR "/fare01.csv");

  // Check that the file path given as input corresponds to an actual file
  bool doesExistAndIsReadable =
    stdair::BasFileMgr::doesExistAndIsReadable (lScheduleInputFilename);
  BOOST_CHECK_MESSAGE (doesExistAndIsReadable == true,
                       "The '" << lScheduleInputFilename
                       << "' input file can not be open and read");

  // Check that the file path given as input corresponds to an actual file
  doesExistAndIsReadable =
    stdair::BasFileMgr::doesExistAndIsReadable (lODInputFilename);
  BOOST_CHECK_MESSAGE (doesExistAndIsReadable == true,
                       "The '" << lODInputFilename
                       << "' input file can not be open and read");

  // Check that the file path given as input corresponds to an actual file
  doesExistAndIsReadable =
    stdair::BasFileMgr::doesExistAndIsReadable (lFareInputFilename);
  BOOST_CHECK_MESSAGE (doesExistAndIsReadable == true,
                       "The '" << lFareInputFilename
                       << "' input file can not be open and read");

  // Output log File
  const stdair::Filename_T lLogFilename ("CRSTestSuite.log");

  // Set the log parameters
  std::ofstream logOutputFile;
  // Open and clean the log outputfile
  logOutputFile.open (lLogFilename.c_str());
  logOutputFile.clear();

  // Initialise the list of classes/buckets
  const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
  SIMCRS::SIMCRS_Service simcrsService (lLogParams, lCRSCode,
                                        lScheduleInputFilename,
                                        lODInputFilename, lFareInputFilename);

  // Create an empty booking request structure
  // TODO: fill the booking request structure from the input parameters
  const stdair::AirportCode_T lOrigin ("SIN");
  const stdair::AirportCode_T lDestination ("BKK");
  const stdair::AirportCode_T lPOS ("SIN");
  const stdair::Date_T lPreferredDepartureDate(2010, boost::gregorian::Jan, 30);
  const stdair::Date_T lRequestDate (2010, boost::gregorian::Jan, 22);
  const stdair::Duration_T lRequestTime (boost::posix_time::hours(10));
  const stdair::DateTime_T lRequestDateTime (lRequestDate, lRequestTime);
  const stdair::CabinCode_T lPreferredCabin ("Eco");
  const stdair::NbOfSeats_T lPartySize (1);
  const stdair::ChannelLabel_T lChannel ("IN");
  const stdair::TripType_T lTripType ("RI");
  const stdair::DayDuration_T lStayDuration (7);
  const stdair::FrequentFlyer_T lFrequentFlyerType ("M");
  const stdair::Duration_T lPreferredDepartureTime (boost::posix_time::hours(10));
  const stdair::WTP_T lWTP (1000.0);
  const stdair::PriceValue_T lValueOfTime (100.0);
  const stdair::BookingRequestStruct lBookingRequest (lOrigin, lDestination,
                                                      lPOS,
                                                      lPreferredDepartureDate,
                                                      lRequestDateTime,
                                                      lPreferredCabin,
                                                      lPartySize, lChannel,
                                                      lTripType, lStayDuration,
                                                      lFrequentFlyerType,
                                                      lPreferredDepartureTime,
                                                      lWTP, lValueOfTime);
  const stdair::SegmentPathList_T lSegmentPath =
    simcrsService.calculateSegmentPathList(lBookingRequest);

  // Price the travel solution
  stdair::TravelSolutionList_T lTravelSolutionList =
    simcrsService.fareQuote (lBookingRequest, lSegmentPath);

  //
  const unsigned int lNbOfTravelSolutions = lTravelSolutionList.size();

  // TODO: change the expected number of travel solutions to the actual number
  const unsigned int lExpectedNbOfTravelSolutions = 2;

  // DEBUG
  STDAIR_LOG_DEBUG ("Number of travel solutions for the booking request '"
                    << lBookingRequest.describe() << "': "
                    << lNbOfTravelSolutions << ". It is expected to be "
                    << lExpectedNbOfTravelSolutions);

  BOOST_CHECK_EQUAL (lNbOfTravelSolutions, lExpectedNbOfTravelSolutions);

  BOOST_CHECK_MESSAGE(lNbOfTravelSolutions == lExpectedNbOfTravelSolutions,
                      "The number of travel solutions for the booking request '"
                      << lBookingRequest.describe() << "' is equal to "
                      << lNbOfTravelSolutions << ", but it should be equal to "
                      << lExpectedNbOfTravelSolutions);

  /* TODO: uncomment as soon as travel solutions are found for that
     booking request
  //
  const stdair::TravelSolutionStruct& lTravelSolution =
    lTravelSolutionList.front();

  //
  const unsigned int lExpectedPrice = 1000;

  // DEBUG
  STDAIR_LOG_DEBUG ("The price given by the fare quoter for '"
                    << lTravelSolution.describe() << "' is: "
                    << lTravelSolution.getFare() << " Euros, and should be "
                    << lExpectedPrice);

  BOOST_CHECK_EQUAL (std::floor (lTravelSolution.getFare() + 0.5),
                     lExpectedPrice);

  BOOST_CHECK_MESSAGE (std::floor (lTravelSolution.getFare() + 0.5)
                       == lExpectedPrice,
                       "The price given by the fare quoter for '"
                       << lTravelSolution.describe() << "' is: "
                       << lTravelSolution.getFare() << " Euros, and should be "
                       << lExpectedPrice);
  */

  // Make a booking
  // const std::string lAirlineCode ("SV");
  // const stdair::PartySize_T lPartySize = 5;
  // BOOST_CHECK_NO_THROW (simcrsService.sell (lAirlineCode, lPartySize));

  // Close the log file
  logOutputFile.close();
}

// End the test suite
BOOST_AUTO_TEST_SUITE_END()

/*!
 * \endcode
 */

<|endoftext|>


<commit_before>/*
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2010 Aldebaran Robotics
*/

#include <gtest/gtest.h>
#include <map>
#include <alcommon-ng/functor/functor.hpp>
#include <alcommon-ng/functor/makefunctor.hpp>
#include <alcommon-ng/serialization/call_definition.hpp>
#include <alcommon-ng/serialization/result_definition.hpp>

#define BIND_METHOD( x )  do { completeAndCheck(&x, fMethodDesc); bindMethod(createFunctor(this, &x)); } while (0);
#define BIND_METHOD_ASYNCHRONOUS( x )  do { completeAndCheck(&x, fMethodDesc); bindMethodAsynchronous(createFunctor(this, &x)); } while (0);

using AL::Messaging::CallDefinition;
using AL::Messaging::ResultDefinition;

class NameLookup {
public:
  void bind(const std::string &name, AL::Functor *functor) {
    _map[name] = functor;
  }

  AL::Functor *get(const std::string &name)
  {
    return _map[name];
  }

protected:
  std::map<std::string, AL::Functor *> _map;
};

int toto(int bim)
{
  std::cout << "poutre:" << bim << std::endl;
  return bim + 1;
}

struct Chiche {
  void tartine() { std::cout << "poutre la tartine" << std::endl; }
  void lover(const int &poteau) { std::cout << "poutre du poteau" << poteau << std::endl; }
};

TEST(TestBind, Simple) {
  Chiche     chiche;
  NameLookup nl;

  nl.bind("tartine", AL::makeFunctor(&chiche, &Chiche::tartine));
  nl.bind("lover",   AL::makeFunctor(&chiche, &Chiche::lover));

  ResultDefinition res;
  CallDefinition   cd;
  AL::makeFunctor(&chiche, &Chiche::tartine)->call(CallDefinition(), res);

  cd.push(40);
  AL::makeFunctor(&chiche, &Chiche::lover)->call(cd, res);

  nl.get("lover")->call(cd, res);
  //AL::createFunctor(&chiche, &Chiche::tartine)->as<void>();
  //nl.call("toto", 42);
}

<commit_msg>test_bind: add perf test<commit_after>/*
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2010 Aldebaran Robotics
*/

#include <gtest/gtest.h>
#include <map>
#include <alcommon-ng/functor/functor.hpp>
#include <alcommon-ng/functor/makefunctor.hpp>
#include <alcommon-ng/tools/dataperftimer.hpp>

static const int gLoopCount   = 1000000;

using AL::Messaging::CallDefinition;
using AL::Messaging::ResultDefinition;

class NameLookup {
public:
  void bind(const std::string &name, AL::Functor *functor) {
    _map[name] = functor;
  }

  AL::Functor *get(const std::string &name)
  {
    return _map[name];
  }

protected:
  std::map<std::string, AL::Functor *> _map;
};

int toto(int bim)
{
  std::cout << "poutre:" << bim << std::endl;
  return bim + 1;
}

struct Chiche {
  void voidCall() { return; }
  int intStringCall(const std::string &plouf) { return plouf.size(); }
  void tartine() { std::cout << "poutre la tartine" << std::endl; }
  void lover(const int &poteau) { std::cout << "poutre du poteau" << poteau << std::endl; }
};

TEST(TestBind, Simple) {
  Chiche     chiche;
  NameLookup nl;

  nl.bind("tartine", AL::makeFunctor(&chiche, &Chiche::tartine));
  nl.bind("lover",   AL::makeFunctor(&chiche, &Chiche::lover));

  ResultDefinition res;
  CallDefinition   cd;
  AL::makeFunctor(&chiche, &Chiche::tartine)->call(CallDefinition(), res);

  cd.push(40);
  AL::makeFunctor(&chiche, &Chiche::lover)->call(cd, res);

  nl.get("lover")->call(cd, res);
}

TEST(TestBind, VoidCallPerf) {
  Chiche           chiche;
  Chiche          *p = &chiche;
  NameLookup       nl;
  ResultDefinition res;
  CallDefinition   cd;

  AL::Test::DataPerfTimer dp;
  AL::Functor    *functor = AL::makeFunctor(&chiche, &Chiche::voidCall);
  std::cout << "AL::Functor call" << std::endl;
  dp.start(gLoopCount);
  for (int i = 0; i < gLoopCount; ++i)
  {
    functor->call(cd, res);
  }
  dp.stop();

  std::cout << "pointer call" << std::endl;
  dp.start(gLoopCount);
  for (int i = 0; i < gLoopCount; ++i)
  {
    p->voidCall();
  }
  dp.stop();
}

TEST(TestBind, IntStringCallPerf) {
  Chiche           chiche;
  Chiche          *p = &chiche;
  NameLookup       nl;
  ResultDefinition res;

  AL::Test::DataPerfTimer dp;

  std::cout << "AL::Functor call (string with a growing size)" << std::endl;

  for (int i = 0; i < 12; ++i)
  {
    unsigned int    numBytes = (unsigned int)pow(2.0f,(int)i);
    std::string     request = std::string(numBytes, 'B');
    CallDefinition  cd;
    AL::Functor    *functor = AL::makeFunctor(&chiche, &Chiche::intStringCall);

    cd.push(request);
    dp.start(gLoopCount, numBytes);
    for (int j = 0; j < gLoopCount; ++j) {
      functor->call(cd, res);
    }
    dp.stop();
  }

  std::cout << "pointer call (string with a growing size)" << std::endl;
  for (int i = 0; i < 12; ++i)
  {
    unsigned int    numBytes = (unsigned int)pow(2.0f,(int)i);
    std::string     request = std::string(numBytes, 'B');

    dp.start(gLoopCount, numBytes);
    for (int j = 0; j < gLoopCount; ++j) {
      p->intStringCall(request);
    }
    dp.stop();
  }

}
<|endoftext|>


<commit_before>/******************************************************************************
* Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#include <boost/test/unit_test.hpp>
#include <boost/cstdint.hpp>

#include <libpc/Header.hpp>
#include <libpc/PointBuffer.hpp>
#include <libpc/SchemaLayout.hpp>
#include <libpc/drivers/faux/Reader.hpp>
#include <libpc/drivers/faux/Iterator.hpp>

using namespace libpc;

BOOST_AUTO_TEST_SUITE(FauxReaderTest)

BOOST_AUTO_TEST_CASE(test_constant_mode_sequential_iter)
{
    Bounds<double> bounds(1.0, 2.0, 3.0, 101.0, 102.0, 103.0);
    libpc::drivers::faux::Reader reader(bounds, 1000, libpc::drivers::faux::Reader::Constant);

    BOOST_CHECK_EQUAL(reader.getName(), "Faux Reader");

    const Schema& schema = reader.getHeader().getSchema();
    SchemaLayout layout(schema);

    PointBuffer data(layout, 750);

    SequentialIterator* iter = reader.createSequentialIterator();
    boost::uint32_t numRead = iter->read(data);

    BOOST_CHECK_EQUAL(numRead, 750);

    int offsetX = schema.getDimensionIndex(Dimension::Field_X);
    int offsetY = schema.getDimensionIndex(Dimension::Field_Y);
    int offsetZ = schema.getDimensionIndex(Dimension::Field_Z);
    int offsetT = schema.getDimensionIndex(Dimension::Field_Time);

    for (boost::uint32_t i=0; i<numRead; i++)
    {
        double x = data.getField<double>(i, offsetX);
        double y = data.getField<double>(i, offsetY);
        double z = data.getField<double>(i, offsetZ);
        boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

        BOOST_CHECK_CLOSE(x, 1.0, (std::numeric_limits<double>::min)());
        BOOST_CHECK_CLOSE(y, 2.0, (std::numeric_limits<double>::min)());
        BOOST_CHECK_CLOSE(z, 3.0, (std::numeric_limits<double>::min)());
        BOOST_CHECK_EQUAL(t, i);
    }

    delete iter;

    return;
}

BOOST_AUTO_TEST_CASE(test_constant_mode_random_iter)
{
    Bounds<double> bounds(1.0, 2.0, 3.0, 101.0, 102.0, 103.0);
    libpc::drivers::faux::Reader reader(bounds, 1000, libpc::drivers::faux::Reader::Constant);

    BOOST_CHECK_EQUAL(reader.getName(), "Faux Reader");

    const Schema& schema = reader.getHeader().getSchema();
    SchemaLayout layout(schema);

    PointBuffer data(layout, 10);

    int offsetX = schema.getDimensionIndex(Dimension::Field_X);
    int offsetY = schema.getDimensionIndex(Dimension::Field_Y);
    int offsetZ = schema.getDimensionIndex(Dimension::Field_Z);
    int offsetT = schema.getDimensionIndex(Dimension::Field_Time);

    RandomIterator* iter = reader.createRandomIterator();

    boost::uint32_t numRead = iter->read(data);
    BOOST_CHECK_EQUAL(numRead, 10);

    {
        for (boost::uint32_t i=0; i<numRead; i++)
        {
            double x = data.getField<double>(i, offsetX);
            double y = data.getField<double>(i, offsetY);
            double z = data.getField<double>(i, offsetZ);
            boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

            BOOST_CHECK_CLOSE(x, 1.0, (std::numeric_limits<double>::min)());
            BOOST_CHECK_CLOSE(y, 2.0, (std::numeric_limits<double>::min)());
            BOOST_CHECK_CLOSE(z, 3.0, (std::numeric_limits<double>::min)());
            BOOST_CHECK_EQUAL(t, i);
        }
    }

    numRead = iter->read(data);
    BOOST_CHECK_EQUAL(numRead, 10);

    {
        for (boost::uint32_t i=0; i<numRead; i++)
        {
            double x = data.getField<double>(i, offsetX);
            double y = data.getField<double>(i, offsetY);
            double z = data.getField<double>(i, offsetZ);
            boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

            BOOST_CHECK_CLOSE(x, 1.0, (std::numeric_limits<double>::min)());
            BOOST_CHECK_CLOSE(y, 2.0, (std::numeric_limits<double>::min)());
            BOOST_CHECK_CLOSE(z, 3.0, (std::numeric_limits<double>::min)());
            BOOST_CHECK_EQUAL(t, i+10);
        }
    }

    boost::uint64_t newPos = iter->seek(99);
    BOOST_CHECK_EQUAL(newPos, 99);
    numRead = iter->read(data);
    BOOST_CHECK_EQUAL(numRead, 10);

    {
        for (boost::uint32_t i=0; i<numRead; i++)
        {
            double x = data.getField<double>(i, offsetX);
            double y = data.getField<double>(i, offsetY);
            double z = data.getField<double>(i, offsetZ);
            boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

            BOOST_CHECK_CLOSE(x, 1.0, (std::numeric_limits<double>::min)());
            BOOST_CHECK_CLOSE(y, 2.0, (std::numeric_limits<double>::min)());
            BOOST_CHECK_CLOSE(z, 3.0, (std::numeric_limits<double>::min)());
            BOOST_CHECK_EQUAL(t, i+99);

        }
    }

    newPos = iter->seek(7);
    BOOST_CHECK_EQUAL(newPos, 7);
    numRead = iter->read(data);
    BOOST_CHECK_EQUAL(numRead, 10);

    {
        for (boost::uint32_t i=0; i<numRead; i++)
        {
            double x = data.getField<double>(i, offsetX);
            double y = data.getField<double>(i, offsetY);
            double z = data.getField<double>(i, offsetZ);
            boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

            BOOST_CHECK_CLOSE(x, 1.0, (std::numeric_limits<double>::min)());
            BOOST_CHECK_CLOSE(y, 2.0, (std::numeric_limits<double>::min)());
            BOOST_CHECK_CLOSE(z, 3.0, (std::numeric_limits<double>::min)());
            BOOST_CHECK_EQUAL(t, i+7);

        }
    }

    delete iter;

    return;
}

BOOST_AUTO_TEST_CASE(test_random_mode)
{
    Bounds<double> bounds(1.0, 2.0, 3.0, 101.0, 102.0, 103.0);
    libpc::drivers::faux::Reader reader(bounds, 1000, libpc::drivers::faux::Reader::Random);

    const Schema& schema = reader.getHeader().getSchema();
    SchemaLayout layout(schema);

    PointBuffer data(layout, 750);

    SequentialIterator* iter = reader.createSequentialIterator();
    boost::uint32_t numRead = iter->read(data);

    BOOST_CHECK_EQUAL(numRead, 750);

    int offsetX = schema.getDimensionIndex(Dimension::Field_X);
    int offsetY = schema.getDimensionIndex(Dimension::Field_Y);
    int offsetZ = schema.getDimensionIndex(Dimension::Field_Z);
    int offsetT = schema.getDimensionIndex(Dimension::Field_Time);

    for (boost::uint32_t i=0; i<numRead; i++)
    {
        double x = data.getField<double>(i, offsetX);
        double y = data.getField<double>(i, offsetY);
        double z = data.getField<double>(i, offsetZ);
        boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

        BOOST_CHECK_GE(x, 1.0);
        BOOST_CHECK_LE(x, 101.0);

        BOOST_CHECK_GE(y, 2.0);
        BOOST_CHECK_LE(y, 102.0);

        BOOST_CHECK_GE(z, 3.0);
        BOOST_CHECK_LE(z, 103.0);

        BOOST_CHECK_EQUAL(t, i);
        // BOOST_CHECK(x >= 1.0 && x <= 101.0);
        // BOOST_CHECK(y >= 2.0 && y <= 102.0);
        // BOOST_CHECK(z >= 3.0 && z <= 103.0);
        // BOOST_CHECK(t == i);
    }

    delete iter;

    return;
}

BOOST_AUTO_TEST_CASE(test_ramp_mode_1)
{
    Bounds<double> bounds(0,0,0,4,4,4);
    libpc::drivers::faux::Reader reader(bounds, 2, libpc::drivers::faux::Reader::Ramp);

    const Schema& schema = reader.getHeader().getSchema();
    SchemaLayout layout(schema);

    PointBuffer data(layout, 2);

    SequentialIterator* iter = reader.createSequentialIterator();
    boost::uint32_t numRead = iter->read(data);

    BOOST_CHECK_EQUAL(numRead, 2);

    const int offsetX = schema.getDimensionIndex(Dimension::Field_X);
    const int offsetY = schema.getDimensionIndex(Dimension::Field_Y);
    const int offsetZ = schema.getDimensionIndex(Dimension::Field_Z);
    const int offsetT = schema.getDimensionIndex(Dimension::Field_Time);

    const double x0 = data.getField<double>(0, offsetX);
    const double y0 = data.getField<double>(0, offsetY);
    const double z0 = data.getField<double>(0, offsetZ);
    const boost::uint64_t t0 = data.getField<boost::uint64_t>(0, offsetT);

    const double x1 = data.getField<double>(1, offsetX);
    const double y1 = data.getField<double>(1, offsetY);
    const double z1 = data.getField<double>(1, offsetZ);
    const boost::uint64_t t1 = data.getField<boost::uint64_t>(1, offsetT);

    BOOST_CHECK_CLOSE(x0, 0.0, (std::numeric_limits<double>::min)());
    BOOST_CHECK_CLOSE(y0, 0.0, (std::numeric_limits<double>::min)());
    BOOST_CHECK_CLOSE(z0, 0.0, (std::numeric_limits<double>::min)());
    BOOST_CHECK_EQUAL(t0, 0);

    BOOST_CHECK_CLOSE(x1, 4.0, (std::numeric_limits<double>::min)());
    BOOST_CHECK_CLOSE(y1, 4.0, (std::numeric_limits<double>::min)());
    BOOST_CHECK_CLOSE(z1, 4.0, (std::numeric_limits<double>::min)());
    BOOST_CHECK_EQUAL(t1, 1);

    delete iter;

    return;
}

BOOST_AUTO_TEST_CASE(test_ramp_mode_2)
{
    Bounds<double> bounds(1.0, 2.0, 3.0, 101.0, 152.0, 203.0);
    libpc::drivers::faux::Reader reader(bounds, 750, libpc::drivers::faux::Reader::Ramp);

    const Schema& schema = reader.getHeader().getSchema();
    SchemaLayout layout(schema);

    PointBuffer data(layout, 750);

    SequentialIterator* iter = reader.createSequentialIterator();
    boost::uint32_t numRead = iter->read(data);

    BOOST_CHECK_EQUAL(numRead,750);

    int offsetX = schema.getDimensionIndex(Dimension::Field_X);
    int offsetY = schema.getDimensionIndex(Dimension::Field_Y);
    int offsetZ = schema.getDimensionIndex(Dimension::Field_Z);
    int offsetT = schema.getDimensionIndex(Dimension::Field_Time);

    double delX = (101.0 - 1.0) / (750.0 - 1.0);
    double delY = (152.0 - 2.0) / (750.0 - 1.0);
    double delZ = (203.0 - 3.0) / (750.0 - 1.0);

    for (boost::uint32_t i=0; i<numRead; i++)
    {
        double x = data.getField<double>(i, offsetX);
        double y = data.getField<double>(i, offsetY);
        double z = data.getField<double>(i, offsetZ);
        boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

        BOOST_CHECK_CLOSE(x, 1.0 + delX*i, (std::numeric_limits<double>::min)());
        BOOST_CHECK_CLOSE(y, 2.0 + delY*i, (std::numeric_limits<double>::min)());
        BOOST_CHECK_CLOSE(z, 3.0 + delZ*i, (std::numeric_limits<double>::min)());
        BOOST_CHECK_EQUAL(t, i);

    }

    delete iter;

    return;
}

BOOST_AUTO_TEST_CASE(test_custom_fields)
{
    Bounds<double> bounds(1.0, 2.0, 3.0, 101.0, 102.0, 103.0);

    Dimension dimY(Dimension::Field_Y, Dimension::Uint8);
    Dimension dimX(Dimension::Field_X, Dimension::Uint8);
    std::vector<Dimension> dims;
    dims.push_back(dimY);
    dims.push_back(dimX);

    libpc::drivers::faux::Reader reader(bounds, 1000, libpc::drivers::faux::Reader::Random, dims);

    const Schema& schema = reader.getHeader().getSchema();
    BOOST_CHECK_EQUAL(schema.getDimensions().size(), 2);
    BOOST_CHECK_EQUAL(schema.getDimension(0).getField(), Dimension::Field_Y);
    BOOST_CHECK_EQUAL(schema.getDimension(1).getField(), Dimension::Field_X);

    return;
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>use perc, not eps, for FP compares<commit_after>/******************************************************************************
* Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#include <boost/test/unit_test.hpp>
#include <boost/cstdint.hpp>

#include <libpc/Header.hpp>
#include <libpc/PointBuffer.hpp>
#include <libpc/SchemaLayout.hpp>
#include <libpc/drivers/faux/Reader.hpp>
#include <libpc/drivers/faux/Iterator.hpp>

using namespace libpc;

BOOST_AUTO_TEST_SUITE(FauxReaderTest)

BOOST_AUTO_TEST_CASE(test_constant_mode_sequential_iter)
{
    Bounds<double> bounds(1.0, 2.0, 3.0, 101.0, 102.0, 103.0);
    libpc::drivers::faux::Reader reader(bounds, 1000, libpc::drivers::faux::Reader::Constant);

    BOOST_CHECK_EQUAL(reader.getName(), "Faux Reader");

    const Schema& schema = reader.getHeader().getSchema();
    SchemaLayout layout(schema);

    PointBuffer data(layout, 750);

    SequentialIterator* iter = reader.createSequentialIterator();
    boost::uint32_t numRead = iter->read(data);

    BOOST_CHECK_EQUAL(numRead, 750);

    int offsetX = schema.getDimensionIndex(Dimension::Field_X);
    int offsetY = schema.getDimensionIndex(Dimension::Field_Y);
    int offsetZ = schema.getDimensionIndex(Dimension::Field_Z);
    int offsetT = schema.getDimensionIndex(Dimension::Field_Time);

    for (boost::uint32_t i=0; i<numRead; i++)
    {
        double x = data.getField<double>(i, offsetX);
        double y = data.getField<double>(i, offsetY);
        double z = data.getField<double>(i, offsetZ);
        boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

        BOOST_CHECK_CLOSE(x, 1.0, 0.00001);
        BOOST_CHECK_CLOSE(y, 2.0, 0.00001);
        BOOST_CHECK_CLOSE(z, 3.0, 0.00001);
        BOOST_CHECK_EQUAL(t, i);
    }

    delete iter;

    return;
}

BOOST_AUTO_TEST_CASE(test_constant_mode_random_iter)
{
    Bounds<double> bounds(1.0, 2.0, 3.0, 101.0, 102.0, 103.0);
    libpc::drivers::faux::Reader reader(bounds, 1000, libpc::drivers::faux::Reader::Constant);

    BOOST_CHECK_EQUAL(reader.getName(), "Faux Reader");

    const Schema& schema = reader.getHeader().getSchema();
    SchemaLayout layout(schema);

    PointBuffer data(layout, 10);

    int offsetX = schema.getDimensionIndex(Dimension::Field_X);
    int offsetY = schema.getDimensionIndex(Dimension::Field_Y);
    int offsetZ = schema.getDimensionIndex(Dimension::Field_Z);
    int offsetT = schema.getDimensionIndex(Dimension::Field_Time);

    RandomIterator* iter = reader.createRandomIterator();

    boost::uint32_t numRead = iter->read(data);
    BOOST_CHECK_EQUAL(numRead, 10);

    {
        for (boost::uint32_t i=0; i<numRead; i++)
        {
            double x = data.getField<double>(i, offsetX);
            double y = data.getField<double>(i, offsetY);
            double z = data.getField<double>(i, offsetZ);
            boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

            BOOST_CHECK_CLOSE(x, 1.0, 0.00001);
            BOOST_CHECK_CLOSE(y, 2.0, 0.00001);
            BOOST_CHECK_CLOSE(z, 3.0, 0.00001);
            BOOST_CHECK_EQUAL(t, i);
        }
    }

    numRead = iter->read(data);
    BOOST_CHECK_EQUAL(numRead, 10);

    {
        for (boost::uint32_t i=0; i<numRead; i++)
        {
            double x = data.getField<double>(i, offsetX);
            double y = data.getField<double>(i, offsetY);
            double z = data.getField<double>(i, offsetZ);
            boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

            BOOST_CHECK_CLOSE(x, 1.0, 0.00001);
            BOOST_CHECK_CLOSE(y, 2.0, 0.00001);
            BOOST_CHECK_CLOSE(z, 3.0, 0.00001);
            BOOST_CHECK_EQUAL(t, i+10);
        }
    }

    boost::uint64_t newPos = iter->seek(99);
    BOOST_CHECK_EQUAL(newPos, 99);
    numRead = iter->read(data);
    BOOST_CHECK_EQUAL(numRead, 10);

    {
        for (boost::uint32_t i=0; i<numRead; i++)
        {
            double x = data.getField<double>(i, offsetX);
            double y = data.getField<double>(i, offsetY);
            double z = data.getField<double>(i, offsetZ);
            boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

            BOOST_CHECK_CLOSE(x, 1.0, 0.00001);
            BOOST_CHECK_CLOSE(y, 2.0, 0.00001);
            BOOST_CHECK_CLOSE(z, 3.0, 0.00001);
            BOOST_CHECK_EQUAL(t, i+99);

        }
    }

    newPos = iter->seek(7);
    BOOST_CHECK_EQUAL(newPos, 7);
    numRead = iter->read(data);
    BOOST_CHECK_EQUAL(numRead, 10);

    {
        for (boost::uint32_t i=0; i<numRead; i++)
        {
            double x = data.getField<double>(i, offsetX);
            double y = data.getField<double>(i, offsetY);
            double z = data.getField<double>(i, offsetZ);
            boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

            BOOST_CHECK_CLOSE(x, 1.0, 0.00001);
            BOOST_CHECK_CLOSE(y, 2.0, 0.00001);
            BOOST_CHECK_CLOSE(z, 3.0, 0.00001);
            BOOST_CHECK_EQUAL(t, i+7);

        }
    }

    delete iter;

    return;
}

BOOST_AUTO_TEST_CASE(test_random_mode)
{
    Bounds<double> bounds(1.0, 2.0, 3.0, 101.0, 102.0, 103.0);
    libpc::drivers::faux::Reader reader(bounds, 1000, libpc::drivers::faux::Reader::Random);

    const Schema& schema = reader.getHeader().getSchema();
    SchemaLayout layout(schema);

    PointBuffer data(layout, 750);

    SequentialIterator* iter = reader.createSequentialIterator();
    boost::uint32_t numRead = iter->read(data);

    BOOST_CHECK_EQUAL(numRead, 750);

    int offsetX = schema.getDimensionIndex(Dimension::Field_X);
    int offsetY = schema.getDimensionIndex(Dimension::Field_Y);
    int offsetZ = schema.getDimensionIndex(Dimension::Field_Z);
    int offsetT = schema.getDimensionIndex(Dimension::Field_Time);

    for (boost::uint32_t i=0; i<numRead; i++)
    {
        double x = data.getField<double>(i, offsetX);
        double y = data.getField<double>(i, offsetY);
        double z = data.getField<double>(i, offsetZ);
        boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

        BOOST_CHECK_GE(x, 1.0);
        BOOST_CHECK_LE(x, 101.0);

        BOOST_CHECK_GE(y, 2.0);
        BOOST_CHECK_LE(y, 102.0);

        BOOST_CHECK_GE(z, 3.0);
        BOOST_CHECK_LE(z, 103.0);

        BOOST_CHECK_EQUAL(t, i);
        // BOOST_CHECK(x >= 1.0 && x <= 101.0);
        // BOOST_CHECK(y >= 2.0 && y <= 102.0);
        // BOOST_CHECK(z >= 3.0 && z <= 103.0);
        // BOOST_CHECK(t == i);
    }

    delete iter;

    return;
}

BOOST_AUTO_TEST_CASE(test_ramp_mode_1)
{
    Bounds<double> bounds(0,0,0,4,4,4);
    libpc::drivers::faux::Reader reader(bounds, 2, libpc::drivers::faux::Reader::Ramp);

    const Schema& schema = reader.getHeader().getSchema();
    SchemaLayout layout(schema);

    PointBuffer data(layout, 2);

    SequentialIterator* iter = reader.createSequentialIterator();
    boost::uint32_t numRead = iter->read(data);

    BOOST_CHECK_EQUAL(numRead, 2);

    const int offsetX = schema.getDimensionIndex(Dimension::Field_X);
    const int offsetY = schema.getDimensionIndex(Dimension::Field_Y);
    const int offsetZ = schema.getDimensionIndex(Dimension::Field_Z);
    const int offsetT = schema.getDimensionIndex(Dimension::Field_Time);

    const double x0 = data.getField<double>(0, offsetX);
    const double y0 = data.getField<double>(0, offsetY);
    const double z0 = data.getField<double>(0, offsetZ);
    const boost::uint64_t t0 = data.getField<boost::uint64_t>(0, offsetT);

    const double x1 = data.getField<double>(1, offsetX);
    const double y1 = data.getField<double>(1, offsetY);
    const double z1 = data.getField<double>(1, offsetZ);
    const boost::uint64_t t1 = data.getField<boost::uint64_t>(1, offsetT);

    BOOST_CHECK_CLOSE(x0, 0.0, 0.00001);
    BOOST_CHECK_CLOSE(y0, 0.0, 0.00001);
    BOOST_CHECK_CLOSE(z0, 0.0, 0.00001);
    BOOST_CHECK_EQUAL(t0, 0);

    BOOST_CHECK_CLOSE(x1, 4.0, 0.00001);
    BOOST_CHECK_CLOSE(y1, 4.0, 0.00001);
    BOOST_CHECK_CLOSE(z1, 4.0, 0.00001);
    BOOST_CHECK_EQUAL(t1, 1);

    delete iter;

    return;
}

BOOST_AUTO_TEST_CASE(test_ramp_mode_2)
{
    Bounds<double> bounds(1.0, 2.0, 3.0, 101.0, 152.0, 203.0);
    libpc::drivers::faux::Reader reader(bounds, 750, libpc::drivers::faux::Reader::Ramp);

    const Schema& schema = reader.getHeader().getSchema();
    SchemaLayout layout(schema);

    PointBuffer data(layout, 750);

    SequentialIterator* iter = reader.createSequentialIterator();
    boost::uint32_t numRead = iter->read(data);

    BOOST_CHECK_EQUAL(numRead,750);

    int offsetX = schema.getDimensionIndex(Dimension::Field_X);
    int offsetY = schema.getDimensionIndex(Dimension::Field_Y);
    int offsetZ = schema.getDimensionIndex(Dimension::Field_Z);
    int offsetT = schema.getDimensionIndex(Dimension::Field_Time);

    double delX = (101.0 - 1.0) / (750.0 - 1.0);
    double delY = (152.0 - 2.0) / (750.0 - 1.0);
    double delZ = (203.0 - 3.0) / (750.0 - 1.0);

    for (boost::uint32_t i=0; i<numRead; i++)
    {
        double x = data.getField<double>(i, offsetX);
        double y = data.getField<double>(i, offsetY);
        double z = data.getField<double>(i, offsetZ);
        boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

        BOOST_CHECK_CLOSE(x, 1.0 + delX*i, 0.00001);
        BOOST_CHECK_CLOSE(y, 2.0 + delY*i, 0.00001);
        BOOST_CHECK_CLOSE(z, 3.0 + delZ*i, 0.00001);
        BOOST_CHECK_EQUAL(t, i);

    }

    delete iter;

    return;
}

BOOST_AUTO_TEST_CASE(test_custom_fields)
{
    Bounds<double> bounds(1.0, 2.0, 3.0, 101.0, 102.0, 103.0);

    Dimension dimY(Dimension::Field_Y, Dimension::Uint8);
    Dimension dimX(Dimension::Field_X, Dimension::Uint8);
    std::vector<Dimension> dims;
    dims.push_back(dimY);
    dims.push_back(dimX);

    libpc::drivers::faux::Reader reader(bounds, 1000, libpc::drivers::faux::Reader::Random, dims);

    const Schema& schema = reader.getHeader().getSchema();
    BOOST_CHECK_EQUAL(schema.getDimensions().size(), 2);
    BOOST_CHECK_EQUAL(schema.getDimension(0).getField(), Dimension::Field_Y);
    BOOST_CHECK_EQUAL(schema.getDimension(1).getField(), Dimension::Field_X);

    return;
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include <gtest/gtest.h>

#include <unistd.h>

#include <cstdio>
#include <string>

#include "../../cvmfs/duplex_sqlite3.h"
#include "../../cvmfs/libcvmfs.h"
#include "../../cvmfs/util.h"

using namespace std;  // NOLINT

static void cvmfs_log_ignore(const char *msg) {
  // Remove comment to debug test failures
  // fprintf(stderr, "%s\n", msg);
}

class T_Libcvmfs : public ::testing::Test {
 protected:
  virtual void SetUp() {
    if (first_test) {
      sqlite3_shutdown();
      first_test = false;
    }

    cvmfs_set_log_fn(cvmfs_log_ignore);
    tmp_path_ = CreateTempDir("./cvmfs_ut_libcvmfs");
    ASSERT_NE("", tmp_path_);
    opt_cache_ = "quota_limit=0,quota_threshold=0,rebuild_cachedb,"
                 "cache_directory=" + tmp_path_;
    alien_path_ = tmp_path_ + "/alien";

    fdevnull_ = fopen("/dev/null", "w");
    ASSERT_FALSE(fdevnull_ == NULL);
  }

  virtual void TearDown() {
    fclose(fdevnull_);
    if (tmp_path_ != "")
      RemoveTree(tmp_path_);
    cvmfs_set_log_fn(NULL);
  }

  // Other tests might have initialized sqlite3.  This cannot happen in real
  // use because sqlite3 is statically linked with the library.  This static
  // variable is used to de-initialize sqlite once, so that proper shutdown
  // within the library can still be tested in the tests following the first
  // one.
  static bool first_test;

  string tmp_path_;
  string alien_path_;
  string opt_cache_;
  FILE *fdevnull_;
};

bool T_Libcvmfs::first_test = true;

TEST_F(T_Libcvmfs, Init) {
  int retval;
  string opt_cache = "cache_directory=" + tmp_path_;
  retval = cvmfs_init(opt_cache_.c_str());
  ASSERT_EQ(LIBCVMFS_FAIL_OK, retval);
  EXPECT_DEATH(cvmfs_init(opt_cache_.c_str()), ".*");
  cvmfs_fini();
}

TEST_F(T_Libcvmfs, InitFailures) {
  int retval;
  FILE *save_stderr = stderr;
  stderr = fdevnull_;
  retval = cvmfs_init("bad option");
  stderr = save_stderr;
  ASSERT_EQ(LIBCVMFS_FAIL_BADOPT, retval);

  retval = cvmfs_init((opt_cache_ + ",max_open_files=100000000").c_str());
  ASSERT_EQ(LIBCVMFS_FAIL_NOFILES, retval);

  retval = cvmfs_init("");
  ASSERT_EQ(LIBCVMFS_FAIL_MKCACHE, retval);

  sqlite3_shutdown();
}

TEST_F(T_Libcvmfs, InitConcurrent) {
  // Align with Parrot use
  string default_opts =
    "max_open_files=500,change_to_cache_directory,log_prefix=libcvmfs";

  string opt_var1_p1 = default_opts +
    ",cache_directory=" + tmp_path_ + "/p1,alien_cachedir=" + alien_path_;
  string opt_var1_p2 = default_opts +
    ",cache_directory=" + tmp_path_ + "/p2,alien_cachedir=" + alien_path_;
  string opt_var2_p1 = default_opts +
    ",alien_cache,cache_directory=" + alien_path_ +
    ",lock_directory=" + tmp_path_ + "/p1";
  string opt_var2_p2 = default_opts +
    ",alien_cache,cache_directory=" + alien_path_ +
    ",lock_directory=" + tmp_path_ + "/p2";

  int pipe_c2p[2];
  int pipe_p2c[2];
  MakePipe(pipe_c2p);
  MakePipe(pipe_p2c);
  int retval;
  pid_t child_pid = fork();
  switch (child_pid) {
    case 0:
      retval = cvmfs_init(opt_var1_p1.c_str());
      WritePipe(pipe_c2p[1], &retval, sizeof(retval));
      ReadPipe(pipe_p2c[0], &retval, sizeof(retval));
      cvmfs_fini();

      retval = cvmfs_init(opt_var2_p1.c_str());
      WritePipe(pipe_c2p[1], &retval, sizeof(retval));
      ReadPipe(pipe_p2c[0], &retval, sizeof(retval));
      exit(0);
    default:
      // Parent
      ASSERT_GT(child_pid, 0);

      ReadPipe(pipe_c2p[0], &retval, sizeof(retval));
      EXPECT_EQ(LIBCVMFS_FAIL_OK, retval);
      retval = cvmfs_init(opt_var1_p2.c_str());
      EXPECT_EQ(LIBCVMFS_FAIL_OK, retval);
      WritePipe(pipe_p2c[1], &retval, sizeof(retval));
      cvmfs_fini();

      ReadPipe(pipe_c2p[0], &retval, sizeof(retval));
      EXPECT_EQ(LIBCVMFS_FAIL_OK, retval);
      retval = cvmfs_init(opt_var2_p2.c_str());
      EXPECT_EQ(LIBCVMFS_FAIL_OK, retval);
      WritePipe(pipe_p2c[1], &retval, sizeof(retval));
      cvmfs_fini();

      int status;
      waitpid(child_pid, &status, 0);
      EXPECT_TRUE(WIFEXITED(status));
      EXPECT_EQ(0, WEXITSTATUS(status));
  }
  ClosePipe(pipe_p2c);
  ClosePipe(pipe_c2p);
}

TEST_F(T_Libcvmfs, OptionAliases) {
  int retval;
  FILE *save_stderr = stderr;

  retval = cvmfs_init((opt_cache_ +
    ",nofiles=100000000,max_open_files=100000000").c_str());
  ASSERT_EQ(LIBCVMFS_FAIL_NOFILES, retval);

  retval = cvmfs_init((opt_cache_ + ",nofiles=100000000").c_str());
  ASSERT_EQ(LIBCVMFS_FAIL_NOFILES, retval);

  retval = cvmfs_init((opt_cache_ + ",max_open_files=100000000").c_str());
  ASSERT_EQ(LIBCVMFS_FAIL_NOFILES, retval);

  stderr = fdevnull_;
  retval = cvmfs_init((opt_cache_ + ",nofiles=999,max_open_files=888").c_str());
  stderr = save_stderr;
  ASSERT_EQ(LIBCVMFS_FAIL_BADOPT, retval);

  stderr = fdevnull_;
  retval =
    cvmfs_init((opt_cache_ + ",syslog_level=0,log_syslog_level=1").c_str());
  stderr = save_stderr;
  ASSERT_EQ(LIBCVMFS_FAIL_BADOPT, retval);

  stderr = fdevnull_;
  retval =
    cvmfs_init((opt_cache_ + ",log_file=abc,logfile=efg").c_str());
  stderr = save_stderr;
  ASSERT_EQ(LIBCVMFS_FAIL_BADOPT, retval);

  stderr = fdevnull_;
  retval =
    cvmfs_init((opt_cache_ + ",cachedir=/abc").c_str());
  stderr = save_stderr;
  ASSERT_EQ(LIBCVMFS_FAIL_BADOPT, retval);

  retval =
    cvmfs_init((opt_cache_ + ",cachedir=" + tmp_path_).c_str());
  stderr = save_stderr;
  EXPECT_EQ(LIBCVMFS_FAIL_OK, retval);
  cvmfs_fini();
}
<commit_msg>FIX: T_Libcvmfs poisons working directory for other tests<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include <gtest/gtest.h>

#include <unistd.h>

#include <cstdio>
#include <string>

#include "../../cvmfs/duplex_sqlite3.h"
#include "../../cvmfs/libcvmfs.h"
#include "../../cvmfs/util.h"

using namespace std;  // NOLINT

static void cvmfs_log_ignore(const char *msg) {
  // Remove comment to debug test failures
  // fprintf(stderr, "%s\n", msg);
}

class T_Libcvmfs : public ::testing::Test {
 protected:
  virtual void SetUp() {
    if (first_test) {
      sqlite3_shutdown();
      first_test = false;
    }

    previous_working_directory_ = GetCurrentWorkingDirectory();

    cvmfs_set_log_fn(cvmfs_log_ignore);
    tmp_path_ = CreateTempDir("./cvmfs_ut_libcvmfs");
    ASSERT_NE("", tmp_path_);
    opt_cache_ = "quota_limit=0,quota_threshold=0,rebuild_cachedb,"
                 "cache_directory=" + tmp_path_;
    alien_path_ = tmp_path_ + "/alien";

    fdevnull_ = fopen("/dev/null", "w");
    ASSERT_FALSE(fdevnull_ == NULL);
  }

  virtual void TearDown() {
    fclose(fdevnull_);
    if (tmp_path_ != "")
      RemoveTree(tmp_path_);
    cvmfs_set_log_fn(NULL);

    EXPECT_EQ(0, chdir(previous_working_directory_.c_str()));
  }

  // Other tests might have initialized sqlite3.  This cannot happen in real
  // use because sqlite3 is statically linked with the library.  This static
  // variable is used to de-initialize sqlite once, so that proper shutdown
  // within the library can still be tested in the tests following the first
  // one.
  static bool first_test;

  // Libcvmfs chdir()s internally. This must be reverted since the unit tests
  // depend on the binary's working directory for sandboxing temporary files.
  // We note the working directory before executing any test code and chdir()
  // back to it in the test's TearDown().
  string previous_working_directory_;

  string tmp_path_;
  string alien_path_;
  string opt_cache_;
  FILE *fdevnull_;
};

bool T_Libcvmfs::first_test = true;

TEST_F(T_Libcvmfs, Init) {
  int retval;
  string opt_cache = "cache_directory=" + tmp_path_;
  retval = cvmfs_init(opt_cache_.c_str());
  ASSERT_EQ(LIBCVMFS_FAIL_OK, retval);
  EXPECT_DEATH(cvmfs_init(opt_cache_.c_str()), ".*");
  cvmfs_fini();
}

TEST_F(T_Libcvmfs, InitFailures) {
  int retval;
  FILE *save_stderr = stderr;
  stderr = fdevnull_;
  retval = cvmfs_init("bad option");
  stderr = save_stderr;
  ASSERT_EQ(LIBCVMFS_FAIL_BADOPT, retval);

  retval = cvmfs_init((opt_cache_ + ",max_open_files=100000000").c_str());
  ASSERT_EQ(LIBCVMFS_FAIL_NOFILES, retval);

  retval = cvmfs_init("");
  ASSERT_EQ(LIBCVMFS_FAIL_MKCACHE, retval);

  sqlite3_shutdown();
}

TEST_F(T_Libcvmfs, InitConcurrent) {
  // Align with Parrot use
  string default_opts =
    "max_open_files=500,change_to_cache_directory,log_prefix=libcvmfs";

  string opt_var1_p1 = default_opts +
    ",cache_directory=" + tmp_path_ + "/p1,alien_cachedir=" + alien_path_;
  string opt_var1_p2 = default_opts +
    ",cache_directory=" + tmp_path_ + "/p2,alien_cachedir=" + alien_path_;
  string opt_var2_p1 = default_opts +
    ",alien_cache,cache_directory=" + alien_path_ +
    ",lock_directory=" + tmp_path_ + "/p1";
  string opt_var2_p2 = default_opts +
    ",alien_cache,cache_directory=" + alien_path_ +
    ",lock_directory=" + tmp_path_ + "/p2";

  int pipe_c2p[2];
  int pipe_p2c[2];
  MakePipe(pipe_c2p);
  MakePipe(pipe_p2c);
  int retval;
  pid_t child_pid = fork();
  switch (child_pid) {
    case 0:
      retval = cvmfs_init(opt_var1_p1.c_str());
      WritePipe(pipe_c2p[1], &retval, sizeof(retval));
      ReadPipe(pipe_p2c[0], &retval, sizeof(retval));
      cvmfs_fini();

      retval = cvmfs_init(opt_var2_p1.c_str());
      WritePipe(pipe_c2p[1], &retval, sizeof(retval));
      ReadPipe(pipe_p2c[0], &retval, sizeof(retval));
      exit(0);
    default:
      // Parent
      ASSERT_GT(child_pid, 0);

      ReadPipe(pipe_c2p[0], &retval, sizeof(retval));
      EXPECT_EQ(LIBCVMFS_FAIL_OK, retval);
      retval = cvmfs_init(opt_var1_p2.c_str());
      EXPECT_EQ(LIBCVMFS_FAIL_OK, retval);
      WritePipe(pipe_p2c[1], &retval, sizeof(retval));
      cvmfs_fini();

      ReadPipe(pipe_c2p[0], &retval, sizeof(retval));
      EXPECT_EQ(LIBCVMFS_FAIL_OK, retval);
      retval = cvmfs_init(opt_var2_p2.c_str());
      EXPECT_EQ(LIBCVMFS_FAIL_OK, retval);
      WritePipe(pipe_p2c[1], &retval, sizeof(retval));
      cvmfs_fini();

      int status;
      waitpid(child_pid, &status, 0);
      EXPECT_TRUE(WIFEXITED(status));
      EXPECT_EQ(0, WEXITSTATUS(status));
  }
  ClosePipe(pipe_p2c);
  ClosePipe(pipe_c2p);
}

TEST_F(T_Libcvmfs, OptionAliases) {
  int retval;
  FILE *save_stderr = stderr;

  retval = cvmfs_init((opt_cache_ +
    ",nofiles=100000000,max_open_files=100000000").c_str());
  ASSERT_EQ(LIBCVMFS_FAIL_NOFILES, retval);

  retval = cvmfs_init((opt_cache_ + ",nofiles=100000000").c_str());
  ASSERT_EQ(LIBCVMFS_FAIL_NOFILES, retval);

  retval = cvmfs_init((opt_cache_ + ",max_open_files=100000000").c_str());
  ASSERT_EQ(LIBCVMFS_FAIL_NOFILES, retval);

  stderr = fdevnull_;
  retval = cvmfs_init((opt_cache_ + ",nofiles=999,max_open_files=888").c_str());
  stderr = save_stderr;
  ASSERT_EQ(LIBCVMFS_FAIL_BADOPT, retval);

  stderr = fdevnull_;
  retval =
    cvmfs_init((opt_cache_ + ",syslog_level=0,log_syslog_level=1").c_str());
  stderr = save_stderr;
  ASSERT_EQ(LIBCVMFS_FAIL_BADOPT, retval);

  stderr = fdevnull_;
  retval =
    cvmfs_init((opt_cache_ + ",log_file=abc,logfile=efg").c_str());
  stderr = save_stderr;
  ASSERT_EQ(LIBCVMFS_FAIL_BADOPT, retval);

  stderr = fdevnull_;
  retval =
    cvmfs_init((opt_cache_ + ",cachedir=/abc").c_str());
  stderr = save_stderr;
  ASSERT_EQ(LIBCVMFS_FAIL_BADOPT, retval);

  retval =
    cvmfs_init((opt_cache_ + ",cachedir=" + tmp_path_).c_str());
  stderr = save_stderr;
  EXPECT_EQ(LIBCVMFS_FAIL_OK, retval);
  cvmfs_fini();
}
<|endoftext|>