# Copyright (c) 2002, 2003 by Intevation GmbH
# Authors:
# Bernhard Herzog <bh@intevation.de>
#
# This program is free software under the GPL (>=v2)
# Read the file COPYING coming with Thuban for details.

"""
Test the TitledObject and Modifiable
"""

__version__ = "$Revision: 1123 $"
# $Source$
# $Id: test_base.py 1123 2003-06-02 14:10:00Z bh $

import unittest

import support
support.initthuban()

from Thuban.Model.base import TitledObject, Modifiable
from Thuban.Model.messages import TITLE_CHANGED, CHANGED

SOMETHING_ELSE = "SOMETHING_ELSE"

class SomeTitledObject(TitledObject, Modifiable):

    """TitledObject for test purposes.

    TitledObject is not used directly. It's a mixin to be used together
    with Modifiable.
    """

class SomeModifiable(Modifiable):

    """Modifiable for test purposes.

    Modifiable is intended to be used as a base class for classes that
    need to inform other classes when they change and that have to keep
    track of whether they have changed. Thus we use a derived class for
    testing that provides some methods that simulate modificatios.
    """

    def do_something(self):
        """Call self.changed without parameters"""
        self.changed()

    def do_something_else(self):
        """Call self.changed with a message parameter"""
        self.changed(SOMETHING_ELSE)


class SubscriberTest(unittest.TestCase, support.SubscriberMixin):

    """Base class for test cases that use SubscriberMixin.

    Just provide the default implementations of setUp and tearDown.
    """

    def setUp(self):
        """Clear the list of received messages"""
        self.clear_messages()

    def tearDown(self):
        """Clear the list of received messages"""
        self.clear_messages()


class TestTitledObject(SubscriberTest):

    """Test cases for TitledObject"""

    def test_titled_object(self):
        """Test TitledObject"""
        titled = SomeTitledObject("Some Title")
        titled.Subscribe(TITLE_CHANGED,
                         self.subscribe_with_params, TITLE_CHANGED)

        self.assertEquals(titled.Title(), "Some Title")

        titled.SetTitle("New Title")
        self.assertEquals(titled.Title(), "New Title")

        self.check_messages([(titled, TITLE_CHANGED)])


class TestModifiable(SubscriberTest):

    """Test cases for Modifiable"""

    def setUp(self):
        """Extend the inherited method to create a Modifiable instance.

        Bind the Modifiable instance (actually an instance of
        SomeModifiable) to self.modifiable and subscribe to its CHANGED
        and SOMETHING_ELSE channels.
        """
        SubscriberTest.setUp(self)
        self.modifiable = SomeModifiable()
        self.modifiable.Subscribe(CHANGED, self.subscribe_with_params, CHANGED)
        self.modifiable.Subscribe(SOMETHING_ELSE,
                                  self.subscribe_with_params, SOMETHING_ELSE)

    def tearDown(self):
        """Extend the inherited method to explicitly destroy self.modifiable.
        """
        self.modifiable.Destroy()
        SubscriberTest.tearDown(self)

    def test_initial_state(self):
        """Test Modifiable initial state"""
        # initially a modifiable is unmodified
        self.failIf(self.modifiable.WasModified())
        # this test should not have resulted in any messages
        self.check_messages([])

    def test_silent_change(self):
        """Test Modifiable method which doesn't issue messages"""
        self.modifiable.do_something()
        # Now it should be modified and we should not have received any
        # message
        self.assert_(self.modifiable.WasModified())
        self.check_messages([])

    def test_unset_modified(self):
        """Test Modifiable.UnsetModified.

        Test whether the UnsetModified does in fact clear the modified
        flag and whether it issues a CHANGED message if it changes the
        modified flag from true to false.
        """
        # We start with an unmodified object, so when we call
        # UnsetModified now it shouldn't result in any message.
        self.modifiable.UnsetModified()
        self.check_messages([])
        self.failIf(self.modifiable.WasModified())

        # Call a method that modifies the object silently.
        self.modifiable.do_something()
        self.check_messages([])
        self.assert_(self.modifiable.WasModified())

        # when we now call UnsetModified it should result in a CHANGED
        # message
        self.modifiable.UnsetModified()
        self.check_messages([(CHANGED,)])
        self.failIf(self.modifiable.WasModified())

    def test_issuing_change(self):
        """Test Modifiable method that issues messages"""
        self.modifiable.do_something_else()
        # Now it should be modified and we should have received a
        # CHANGED message
        self.check_messages([(SOMETHING_ELSE,)])
        self.assert_(self.modifiable.WasModified())



if __name__ == "__main__":
    unittest.main()
