Patch for Issue #47, provided by gps@google.com




git-svn-id: http://pymox.googlecode.com/svn/trunk@75 b1010a0a-674b-0410-b734-77272b80c875
diff --git a/mox.py b/mox.py
index f250187..48f6391 100755
--- a/mox.py
+++ b/mox.py
@@ -61,6 +61,10 @@
   my_mox.VerifyAll()
 """
 
+try:
+  import abc
+except ImportError:
+  abc = None  # Python 2.5 and earlier
 from collections import deque
 import difflib
 import inspect
@@ -260,6 +264,8 @@
 
   # A list of types that may be stubbed out with a MockObjectFactory.
   _USE_MOCK_FACTORY = [types.ClassType, types.ObjectType, types.TypeType]
+  if abc:
+    _USE_MOCK_FACTORY.append(abc.ABCMeta)
 
   def __init__(self):
     """Initialize a new Mox."""
diff --git a/mox_test.py b/mox_test.py
index 89efd48..3e2d9b6 100755
--- a/mox_test.py
+++ b/mox_test.py
@@ -19,6 +19,7 @@
 import cStringIO
 import unittest
 import re
+import sys
 
 import mox
 
@@ -1898,6 +1899,39 @@
     self.assertEquals('mock', actual_one)
     self.assertEquals('called mock', actual_two)
 
+  try:
+    import abc
+    # I'd use the unittest skipping decorators for this but I want to support
+    # older versions of Python that don't have them.
+    def testStubOutClass_ABCMeta(self):
+      self.mox.StubOutClassWithMocks(mox_test_helper,
+                                     'CallableSubclassOfMyDictABC')
+      mock_foo = mox_test_helper.CallableSubclassOfMyDictABC(foo='!mock bar')
+      mock_foo['foo'].AndReturn('mock bar')
+      mock_spam = mox_test_helper.CallableSubclassOfMyDictABC(spam='!mock eggs')
+      mock_spam('beans').AndReturn('called mock')
+
+      self.mox.ReplayAll()
+
+      foo = mox_test_helper.CallableSubclassOfMyDictABC(foo='!mock bar')
+      actual_foo_bar = foo['foo']
+
+      spam = mox_test_helper.CallableSubclassOfMyDictABC(spam='!mock eggs')
+      actual_spam = spam('beans')
+
+      self.mox.VerifyAll()
+      self.mox.UnsetStubs()
+
+      # Verify the correct mocks were returned
+      self.assertEquals(mock_foo, foo)
+      self.assertEquals(mock_spam, spam)
+
+      # Verify
+      self.assertEquals('mock bar', actual_foo_bar)
+      self.assertEquals('called mock', actual_spam)
+  except ImportError:
+    print >>sys.stderr, "testStubOutClass_ABCMeta. ... Skipped - no abc module"
+
   def testStubOutClass_NotAClass(self):
     self.assertRaises(TypeError, self.mox.StubOutClassWithMocks,
                       mox_test_helper, 'MyTestFunction')
diff --git a/mox_test_helper.py b/mox_test_helper.py
index 5ac989f..58c099e 100755
--- a/mox_test_helper.py
+++ b/mox_test_helper.py
@@ -118,6 +118,25 @@
     return 'Not mock'
 
 
+try:
+  import abc
+
+  class MyDictABC(object):
+    __metaclass__ = abc.ABCMeta
+
+  MyDictABC.register(dict)
+
+  class CallableSubclassOfMyDictABC(MyDictABC):
+
+    def __call__(self, one):
+      return 'Not mock'
+
+    def __getitem__(self, key, default=None):
+      return 'Not mock'
+except ImportError:
+  pass  # Python 2.5 or earlier
+
+
 def MyTestFunction(one, two, nine=None):
   pass