| 
 # Authors:  
#   Jason Gerard DeRose <jderose@redhat.com>  
#  
# Copyright (C) 2008  Red Hat  
# see file 'COPYING' for use and warranty information  
#  
# 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 3 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, see <http://www.gnu.org/licenses/>.  
  
"""  
Test the `ipalib.base` module.  
"""  
  
from tests.util import ClassChecker, raises  
from ipalib.constants import NAME_REGEX, NAME_ERROR  
from ipalib.constants import TYPE_ERROR, SET_ERROR, DEL_ERROR, OVERRIDE_ERROR  
from ipalib import base  
  
  
class test_ReadOnly(ClassChecker):  
    """  
    Test the `ipalib.base.ReadOnly` class  
    """  
    _cls = base.ReadOnly  
  
    def test_lock(self):  
        """  
        Test the `ipalib.base.ReadOnly.__lock__` method.  
        """  
        o = self.cls()  
        assert o._ReadOnly__locked is False  
        o.__lock__()  
        assert o._ReadOnly__locked is True  
        e = raises(AssertionError, o.__lock__) # Can only be locked once  
        assert str(e) == '__lock__() can only be called once'  
        assert o._ReadOnly__locked is True # This should still be True  
  
    def test_islocked(self):  
        """  
        Test the `ipalib.base.ReadOnly.__islocked__` method.  
        """  
        o = self.cls()  
        assert o.__islocked__() is False  
        o.__lock__()  
        assert o.__islocked__() is True  
  
    def test_setattr(self):  
        """  
        Test the `ipalib.base.ReadOnly.__setattr__` method.  
        """  
        o = self.cls()  
        o.attr1 = 'Hello, world!'  
        assert o.attr1 == 'Hello, world!'  
        o.__lock__()  
        for name in ('attr1', 'attr2'):  
            e = raises(AttributeError, setattr, o, name, 'whatever')  
            assert str(e) == SET_ERROR % ('ReadOnly', name, 'whatever')  
        assert o.attr1 == 'Hello, world!'  
  
    def test_delattr(self):  
        """  
        Test the `ipalib.base.ReadOnly.__delattr__` method.  
        """  
        o = self.cls()  
        o.attr1 = 'Hello, world!'  
        o.attr2 = 'How are you?'  
        assert o.attr1 == 'Hello, world!'  
        assert o.attr2 == 'How are you?'  
        del o.attr1  
        assert not hasattr(o, 'attr1')  
        o.__lock__()  
        e = raises(AttributeError, delattr, o, 'attr2')  
        assert str(e) == DEL_ERROR % ('ReadOnly', 'attr2')  
        assert o.attr2 == 'How are you?'  
  
  
def test_lock():  
    """  
    Test the `ipalib.base.lock` function  
    """  
    f = base.lock  
  
    # Test with ReadOnly instance:  
    o = base.ReadOnly()  
    assert o.__islocked__() is False  
    assert f(o) is o  
    assert o.__islocked__() is True  
    e = raises(AssertionError, f, o)  
    assert str(e) == 'already locked: %r' % o  
  
    # Test with another class implemented locking protocol:  
    class Lockable(object):  
        __locked = False  
        def __lock__(self):  
            self.__locked = True  
        def __islocked__(self):  
            return self.__locked  
    o = Lockable()  
    assert o.__islocked__() is False  
    assert f(o) is o  
    assert o.__islocked__() is True  
    e = raises(AssertionError, f, o)  
    assert str(e) == 'already locked: %r' % o  
  
    # Test with a class incorrectly implementing the locking protocol:  
    class Broken(object):  
        def __lock__(self):  
            pass  
        def __islocked__(self):  
            return False  
    o = Broken()  
    e = raises(AssertionError, f, o)  
    assert str(e) == 'failed to lock: %r' % o  
  
  
def test_islocked():  
    """  
    Test the `ipalib.base.islocked` function.  
    """  
    f = base.islocked  
  
    # Test with ReadOnly instance:  
    o = base.ReadOnly()  
    assert f(o) is False  
    o.__lock__()  
    assert f(o) is True  
  
    # Test with another class implemented locking protocol:  
    class Lockable(object):  
        __locked = False  
        def __lock__(self):  
            self.__locked = True  
        def __islocked__(self):  
            return self.__locked  
    o = Lockable()  
    assert f(o) is False  
    o.__lock__()  
    assert f(o) is True  
  
    # Test with a class incorrectly implementing the locking protocol:  
    class Broken(object):  
        __lock__ = False  
        def __islocked__(self):  
            return False  
    o = Broken()  
    e = raises(AssertionError, f, o)  
    assert str(e) == 'no __lock__() method: %r' % o  
  
  
def test_check_name():  
    """  
    Test the `ipalib.base.check_name` function.  
    """  
    f = base.check_name  
    okay = [  
        'user_add',  
        'stuff2junk',  
        'sixty9',  
    ]  
    nope = [  
        '_user_add',  
        '__user_add',  
        'user_add_',  
        'user_add__',  
        '_user_add_',  
        '__user_add__',  
        '60nine',  
    ]  
    for name in okay:  
        assert name is f(name)  
        e = raises(TypeError, f, unicode(name))  
        assert str(e) == TYPE_ERROR % ('name', str, unicode(name), unicode)  
    for name in nope:  
        e = raises(ValueError, f, name)  
        assert str(e) == NAME_ERROR % (NAME_REGEX, name)  
    for name in okay:  
        e = raises(ValueError, f, name.upper())  
        assert str(e) == NAME_ERROR % (NAME_REGEX, name.upper())  
  
  
def membername(i):  
    return 'member%03d' % i  
  
  
class DummyMember(object):  
    def __init__(self, i):  
        self.i = i  
        self.name = membername(i)  
  
  
def gen_members(*indexes):  
    return tuple(DummyMember(i) for i in indexes)  
  
  
class test_NameSpace(ClassChecker):  
    """  
    Test the `ipalib.base.NameSpace` class.  
    """  
    _cls = base.NameSpace  
  
    def new(self, count, sort=True):  
        members = tuple(DummyMember(i) for i in xrange(count, 0, -1))  
        assert len(members) == count  
        o = self.cls(members, sort=sort)  
        return (o, members)  
  
    def test_init(self):  
        """  
        Test the `ipalib.base.NameSpace.__init__` method.  
        """  
        o = self.cls([])  
        assert len(o) == 0  
        assert list(o) == []  
        assert list(o()) == []  
  
        # Test members as attribute and item:  
        for cnt in (3, 42):  
            for sort in (True, False):  
                (o, members) = self.new(cnt, sort=sort)  
                assert len(members) == cnt  
                for m in members:  
                    assert getattr(o, m.name) is m  
                    assert o[m.name] is m  
  
        # Test that TypeError is raised if sort is not a bool:  
        e = raises(TypeError, self.cls, [], sort=None)  
        assert str(e) == TYPE_ERROR % ('sort', bool, None, type(None))  
  
        # Test that AttributeError is raised with duplicate member name:  
        members = gen_members(0, 1, 2, 1, 3)  
        e = raises(AttributeError, self.cls, members)  
        assert str(e) == OVERRIDE_ERROR % (  
            'NameSpace', membername(1), members[1], members[3]  
        )  
  
    def test_len(self):  
        """  
        Test the `ipalib.base.NameSpace.__len__` method.  
        """  
        for count in (5, 18, 127):  
            (o, members) = self.new(count)  
            assert len(o) == count  
            (o, members) = self.new(count, sort=False)  
            assert len(o) == count  
  
    def test_iter(self):  
        """  
        Test the `ipalib.base.NameSpace.__iter__` method.  
        """  
        (o, members) = self.new(25)  
        assert list(o) == sorted(m.name for m in members)  
        (o, members) = self.new(25, sort=False)  
        assert list(o) == list(m.name for m in members)  
  
    def test_call(self):  
        """  
        Test the `ipalib.base.NameSpace.__call__` method.  
        """  
        (o, members) = self.new(25)  
        assert list(o()) == sorted(members, key=lambda m: m.name)  
        (o, members) = self.new(25, sort=False)  
        assert tuple(o()) == members  
  
    def test_contains(self):  
        """  
        Test the `ipalib.base.NameSpace.__contains__` method.  
        """  
        yes = (99, 3, 777)  
        no = (9, 333, 77)  
        for sort in (True, False):  
            members = gen_members(*yes)  
            o = self.cls(members, sort=sort)  
            for i in yes:  
                assert membername(i) in o  
                assert membername(i).upper() not in o  
            for i in no:  
                assert membername(i) not in o  
  
    def test_getitem(self):  
        """  
        Test the `ipalib.base.NameSpace.__getitem__` method.  
        """  
        cnt = 17  
        for sort in (True, False):  
            (o, members) = self.new(cnt, sort=sort)  
            assert len(members) == cnt  
            if sort is True:  
                members = tuple(sorted(members, key=lambda m: m.name))  
  
            # Test str keys:  
            for m in members:  
                assert o[m.name] is m  
            e = raises(KeyError, o.__getitem__, 'nope')  
  
            # Test int indexes:  
            for i in xrange(cnt):  
                assert o[i] is members[i]  
            e = raises(IndexError, o.__getitem__, cnt)  
  
            # Test negative int indexes:  
            for i in xrange(1, cnt + 1):  
                assert o[-i] is members[-i]  
            e = raises(IndexError, o.__getitem__, -(cnt + 1))  
  
            # Test slicing:  
            assert o[3:] == members[3:]  
            assert o[:10] == members[:10]  
            assert o[3:10] == members[3:10]  
            assert o[-9:] == members[-9:]  
            assert o[:-4] == members[:-4]  
            assert o[-9:-4] == members[-9:-4]  
  
            # Test that TypeError is raised with wrong type  
            e = raises(TypeError, o.__getitem__, 3.0)  
            assert str(e) == TYPE_ERROR % ('key', (str, int, slice), 3.0, float)  
  
    def test_repr(self):  
        """  
        Test the `ipalib.base.NameSpace.__repr__` method.  
        """  
        for cnt in (0, 1, 2):  
            for sort in (True, False):  
                (o, members) = self.new(cnt, sort=sort)  
                if cnt == 1:  
                    assert repr(o) == \  
                        'NameSpace(<%d member>, sort=%r)' % (cnt, sort)  
                else:  
                    assert repr(o) == \  
                        'NameSpace(<%d members>, sort=%r)' % (cnt, sort)  
  
    def test_todict(self):  
        """  
        Test the `ipalib.base.NameSpace.__todict__` method.  
        """  
        for cnt in (3, 101):  
            for sort in (True, False):  
                (o, members) = self.new(cnt, sort=sort)  
                d = o.__todict__()  
                assert d == dict((m.name, m) for m in members)  
  
                # Test that a copy is returned:  
                assert o.__todict__() is not d  
                
             |