Skip to content

Commit

Permalink
100% branch coverage for 'zope.interface.ro'.
Browse files Browse the repository at this point in the history
  • Loading branch information
tseaver committed Dec 8, 2014
1 parent 50496ac commit 859cddd
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 17 deletions.
29 changes: 12 additions & 17 deletions src/zope/interface/ro.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,7 @@
"""
__docformat__ = 'restructuredtext'


def ro(object):
"""Compute a "resolution order" for an object
"""
return mergeOrderings([_flatten(object)])

def mergeOrderings(orderings, seen=None):
def _mergeOrderings(orderings):
"""Merge multiple orderings so that within-ordering order is preserved
Orderings are constrained in such a way that if an object appears
Expand All @@ -30,7 +24,7 @@ def mergeOrderings(orderings, seen=None):
For example:
>>> mergeOrderings([
>>> _mergeOrderings([
... ['x', 'y', 'z'],
... ['q', 'z'],
... [1, 3, 5],
Expand All @@ -40,19 +34,14 @@ def mergeOrderings(orderings, seen=None):
"""

if seen is None:
seen = {}
seen = {}
result = []
orderings.reverse()
for ordering in orderings:
ordering = list(ordering)
ordering.reverse()
for o in ordering:
for ordering in reversed(orderings):
for o in reversed(ordering):
if o not in seen:
seen[o] = 1
result.append(o)
result.insert(0, o)

result.reverse()
return result

def _flatten(ob):
Expand All @@ -67,3 +56,9 @@ def _flatten(ob):
# by definition.
result[i:i] = ob.__bases__
return result


def ro(object):
"""Compute a "resolution order" for an object
"""
return _mergeOrderings([_flatten(object)])
115 changes: 115 additions & 0 deletions src/zope/interface/tests/test_ro.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
##############################################################################
#
# Copyright (c) 2014 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Resolution ordering utility tests"""
import unittest


class Test__mergeOrderings(unittest.TestCase):

def _callFUT(self, orderings):
from zope.interface.ro import _mergeOrderings
return _mergeOrderings(orderings)

def test_empty(self):
self.assertEqual(self._callFUT([]), [])

def test_single(self):
self.assertEqual(self._callFUT(['a', 'b', 'c']), ['a', 'b', 'c'])

def test_w_duplicates(self):
self.assertEqual(self._callFUT([['a'], ['b', 'a']]), ['b', 'a'])

def test_suffix_across_multiple_duplicats(self):
O1 = ['x', 'y', 'z']
O2 = ['q', 'z']
O3 = [1, 3, 5]
O4 = ['z']
self.assertEqual(self._callFUT([O1, O2, O3, O4]),
['x', 'y', 'q', 1, 3, 5, 'z'])


class Test__flatten(unittest.TestCase):

def _callFUT(self, ob):
from zope.interface.ro import _flatten
return _flatten(ob)

def test_w_empty_bases(self):
class Foo(object):
pass
foo = Foo()
foo.__bases__ = ()
self.assertEqual(self._callFUT(foo), [foo])

def test_w_single_base(self):
class Foo(object):
pass
self.assertEqual(self._callFUT(Foo), [Foo, object])

def test_w_bases(self):
class Foo(object):
pass
class Bar(Foo):
pass
self.assertEqual(self._callFUT(Bar), [Bar, Foo, object])

def test_w_diamond(self):
class Foo(object):
pass
class Bar(Foo):
pass
class Baz(Foo):
pass
class Qux(Bar, Baz):
pass
self.assertEqual(self._callFUT(Qux),
[Qux, Bar, Foo, object, Baz, Foo, object])


class Test_ro(unittest.TestCase):

def _callFUT(self, ob):
from zope.interface.ro import ro
return ro(ob)

def test_w_empty_bases(self):
class Foo(object):
pass
foo = Foo()
foo.__bases__ = ()
self.assertEqual(self._callFUT(foo), [foo])

def test_w_single_base(self):
class Foo(object):
pass
self.assertEqual(self._callFUT(Foo), [Foo, object])

def test_w_bases(self):
class Foo(object):
pass
class Bar(Foo):
pass
self.assertEqual(self._callFUT(Bar), [Bar, Foo, object])

def test_w_diamond(self):
class Foo(object):
pass
class Bar(Foo):
pass
class Baz(Foo):
pass
class Qux(Bar, Baz):
pass
self.assertEqual(self._callFUT(Qux),
[Qux, Bar, Baz, Foo, object])

0 comments on commit 859cddd

Please sign in to comment.