/*
 * vdr-podcatcher - A plugin for the Linux Video Disk Recorder
 * Copyright (c) 2006 Tobias Grimm <vdr@e-tobi.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * $Id: refptr_test.cc 3226 2006-04-16 23:08:51Z svntobi $
 *
 */

#include <cxxtest/TestSuite.h>
#include "refptr.h"
#include "stringmessagemock.h"

using namespace std;

class Foo: public StringMessageMock
{
    public:
        Foo() {}

        Foo(StringMessageMock& parent, string messagePrefix = "")
        :StringMessageMock(parent, messagePrefix)
        {
        }

        ~Foo()
        {
            AddMethod("dtor");
        }

        int Bar(int arg)
        {
            return arg;
        }
};

class ref_ptrTest: public CxxTest::TestSuite
{
    public:
        void TestEmptyPtr()
        {
            ref_ptr<Foo> ptr;
        }

        void TestSingleReference()
        {
            StringMessageMock mock;
            Foo* foo = new Foo(mock);

            mock.ExpectMethod("dtor");

            ref_ptr<Foo>* ref = new ref_ptr<Foo>(foo);
            delete ref;

            mock.Verify();
        }

        void TestGet()
        {
            Foo* foo = new Foo();
            ref_ptr<Foo> ref(foo);
            TS_ASSERT_EQUALS(foo, ref.get());
        }

        void TestPointerOperator()
        {
            Foo* foo = new Foo();
            ref_ptr<Foo> ref(foo);
            TS_ASSERT_EQUALS(10, ref->Bar(10));
        }

        void TestAstersikOperator()
        {
            Foo* foo = new Foo();
            ref_ptr<Foo> ref(foo);
            TS_ASSERT_EQUALS(10, (*ref).Bar(10));
        }

        void TestMultipleReferences()
        {
            StringMessageMock mock;
            Foo* foo = new Foo(mock);

            ref_ptr<Foo>* ref1 = new ref_ptr<Foo>(foo);
            ref_ptr<Foo>* ref2 = new ref_ptr<Foo>(*ref1);
            ref_ptr<Foo>* ref3 = new ref_ptr<Foo>(*ref2);

            delete ref1;
            mock.Verify();

            delete ref3;
            mock.Verify();

            mock.ExpectMethod("dtor");
            delete ref2;
            mock.Verify();
        }

        void TestAssignmentOperator()
        {
            StringMessageMock mock;
            Foo* foo1 = new Foo(mock, "foo1");
            Foo* foo2 = new Foo(mock, "foo2");

            ref_ptr<Foo>* ref1 = new ref_ptr<Foo>(foo1);
            ref_ptr<Foo>* ref2 = new ref_ptr<Foo>(foo2);

            mock.ExpectMethod("foo2:dtor");

            *ref2 = *ref1;

            mock.Verify();
            TS_ASSERT_EQUALS(foo1, ref2->get());

            mock.ResetMock();
            mock.ExpectMethod("foo1:dtor");

            delete ref1;
            delete ref2;

            mock.Verify();
        }

        void TestConstAssignment()
        {
            StringMessageMock mock;
            Foo* foo1 = new Foo(mock, "foo1");
            Foo* foo2 = new Foo(mock, "foo2");

            const ref_ptr<Foo>* ref1 = new ref_ptr<Foo>(foo1);
            ref_ptr<Foo>* ref2 = new ref_ptr<Foo>(foo2);

            mock.ExpectMethod("foo2:dtor");

            *ref2 = *ref1;

            mock.Verify();
            TS_ASSERT_EQUALS(foo1, ref2->get());

            mock.ResetMock();
            mock.ExpectMethod("foo1:dtor");

            delete ref1;
            delete ref2;

            mock.Verify();
        }

        void TestSelfAssignment()
        {
            StringMessageMock mock;

            ref_ptr<Foo> ref1(new Foo(mock));

            ref1 = ref1;

            mock.Verify();
        }

        void TestPointerAssignment()
        {
            StringMessageMock mock;


            Foo* foo1 = new Foo(mock, "foo1");
            ref_ptr<Foo> ref(foo1);

            mock.ExpectMethod("foo1:dtor");

            Foo* foo2 = new Foo(mock, "foo2");
            ref = foo2;

            mock.Verify();
            TS_ASSERT_EQUALS(foo2, ref.get());
        }

        void TestPointerselfAssignment()
        {
            StringMessageMock mock;
            Foo* foo = new Foo(mock);

            ref_ptr<Foo> ref(foo);

            ref = foo;

            mock.Verify();
        }
};
