#!/usr/bin/env python3.0
"""Unit tests for abc.py."""

import sys
import unittest

import abc

class ABCTestCase(unittest.TestCase):

    def test_abstract_method_machinery(self):
        class C(metaclass=abc.ABCMeta):
            @abc.abstractmethod
            def foo(self): pass
            def bar(self): pass
        self.assertRaises(TypeError, C)
        class D(C):
            def bar(self): pass
        self.assertRaises(TypeError, D)
        class E(D):
            def foo(self): pass
        E()

    def test_hashable_set_hash_matches_frozenset_hash(self):
        class C(abc.Set):
            def __new__(cls, values):
                obj = super(C, cls).__new__(cls)
                obj.__values = set(values)
                return obj
            def __len__(self):
                return len(self.__values)
            def __contains__(self, x):
                return x in self.__values
            def __iter__(self):
                return iter(self.__values)
        for l in ([], [0], [1], [0, 1],
                  list(range(-sys.maxint, sys.maxint, 100000)),
                  "The quick brown fox jumps over the lazy dog".split()):
            hc = C(l)._hash()
            hfs = hash(frozenset(l))
            self.assertEqual(hc, hfs, repr((l, hc, hfs)))


    def test_adapt_to_sequence(self):
        a = abc.AdaptToSequence(range(10))
        self.assertEqual(len(a), 10)
        self.assertEqual(a[0], 0)
        self.assertEqual(a[9], 9)
        self.assertEqual(a[-1], 9)
        self.assertEqual(list(a), list(range(10)))
        b = a[1:-1]
        self.assertEqual(b.__class__, abc.AdaptToSequence)
        self.assertEqual(list(b), list(range(1, 9)))

    def test_adapt_to_mapping(self):
        a = abc.AdaptToMapping({1: 10, 2: 20})
        self.assertEqual(len(a), 2)
        self.assertEqual(a[1], 10)
        self.assertEqual(a.get(2), 20)
        self.assertEqual(a.get(3), None)
        self.assertEqual(a.get(4, 42), 42)
        self.assertEqual(1 in a, True)
        self.assertEqual(2 in a, True)
        self.assertEqual(3 in a, False)
        self.assertEqual(set(a.keys()), {1, 2})
        self.assertEqual(set(a.items()), {(1, 10), (2, 20)})
        self.assertEqual(set(a.values()), {10, 20})
        #self.assertEqual(a.keys(), {1, 2})
        #self.assertEqual(a.items(), {(1, 10), (2, 20)})
        #self.assertEqual(a.values(), {10, 20})

    def test_adapt_to_set(self):
        a = abc.AdaptToSet({1, 2, 3})
        self.assertEqual(1 in a, True)
        self.assertEqual(2 in a, True)
        self.assertEqual(42 in a, False)
        self.assertEqual(len(a), 3)

    def test_overloading(self):
        # Basic 'flatten' example
        @abc.overloadable
        def flatten(x):
            yield x
        @flatten.overload
        def _(x: abc.Iterable):
            for a in x:
                for b in flatten(a):
                    yield b
        @flatten.overload
        def _(x: basestring):
            yield x
        self.assertEqual(list(flatten([1, 2, 3])), [1, 2, 3])
        self.assertEqual(list(flatten([1,[2],3])), [1, 2, 3])
        self.assertEqual(list(flatten([1,[2,3]])), [1, 2, 3])
        self.assertEqual(list(flatten([1,[2,3]])), [1, 2, 3])
        self.assertEqual(list(flatten([1,"abc",3])), [1, "abc", 3])

        # Add 2-arg version
        @flatten.overload
        def _(t: type, x):
            return t(flatten(x))
        self.assertEqual(flatten(tuple, [1, 2, 3]), (1, 2, 3))
        self.assertEqual(flatten(tuple, [1,[2],3]), (1, 2, 3))
        self.assertEqual(flatten(tuple, [1,"abc",3]), (1, "abc", 3))

        # Change an overload
        @flatten.overload
        def flatten(x: basestring):
            for c in x:
                yield c
        self.assertEqual(list(flatten([1, "abc", 3])), [1, "a", "b", "c", 3])


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