#include "Test.h"

#include "Owner.h"
#include "Array_of_own.h"

namespace MM
{

class Owner_test : public Test
{
public:
    Owner_test (const Text & suite_name) : Test (suite_name) { }


    void run()
    {
        test_example_1();                count_tests();
        test_example_2();                count_tests();
        test_example_3();                count_tests();
    }

    class  B;

    struct A
    {
        B                   *b_;
        void                adopt (B * adoptee) 
        {
            b_ = adoptee;
            set_ownership (*adoptee, *this);
        }
        void                erase (B&)         {delete b_; b_ = 0;}
    };

    struct A2
    {
        Array_of_own<B>     b_;
        void                adopt (B * adoptee) 
        {
            set_ownership (*adoptee, *this);
            b_.push_back (adoptee);
        }
        void                erase (B & obj)    {b_.remove (obj);      }
    };

    class B
    {
    public:
        Connections <B>     connections_;

        void                erase ()             {connections_.erase (*this);}
    };

    class B_holder
    {
    public:
        B                   *b_;

        explicit            B_holder (B &obj) : b_(&obj) {remember (obj, *this);}
        void                forget (B &) {b_ = 0;}
    };


    void test_example_1()
    {
        A  a;
        B *b = new B;
        a.adopt (b);
        B_holder holder (*b);
        
        TEST ("'a' is owner 'b'", a.b_ == b);
        TEST ("'b' in 'holder'",  holder.b_ == b);

        b->erase();

        TEST ("'b' destroyed",  a.b_ == 0);
        TEST ("forget 'b'",     holder.b_ == 0);
    }

    void test_example_2()
    {
        A2  a;
        B  *b = new B ();
        a.adopt (b);
        
        TEST ("'a' is owner 'b'", a.b_.size() == 1);

        b->erase();
        TEST ("'b' destroyed", a.b_.size() == 0);
    }


    class  C;

    struct A3
    {
        C                   *c_;

        explicit A3 (C * adoptee) : c_(adoptee) {set_ownership (*adoptee, *this);}
        void                erase (C&)         {delete c_; c_ = 0;}
    };

    class C
    {
    public:
        Connections <C>     connections_;
        void                erase ()    {connections_.erase(*this);}
    };

    void test_example_3()
    {
        C  *c = new C;
        A3  a (c);
        
        TEST ("'a' is owner 'c'", a.c_ == c);

        c->erase();
        TEST ("'c' destroyed", a.c_ == 0);
    }
};

Owner_test test_owner ("correctness");

}//MM

