CIDict, our case-insensitive dictionary, inherits from dict but did not reimplement the full dict interface. Calling the missing methods silently invoked case-sensitive behavior. Our code seems to avoid that, but it's a bit of a minefield for new development.

Patch 119 adds the missing dict methods (except view{items,keys,values}(), which now raise errors), and adds tests.


Patches 117-118 modernize the testsuite a bit (these have been sitting in my queue for a while, I think now is a good time to submit them): The first one moves some old tests from the main code tree to tests/. (The adtrust_install test wasn't run before, this move makes nose notice it).
The second converts CIDict's unittest-based suite to nose.

--
Petr³
From 7ea2a0abd92f6337e70c96599fb9a0118672921b Mon Sep 17 00:00:00 2001
From: Petr Viktorin <[email protected]>
Date: Fri, 20 Apr 2012 07:03:16 -0400
Subject: [PATCH] Move tests to test directories

Nose doesn't pick up directories that don't begin with 'test'.
Rename tests/test_ipaserver/install to test_install so that it's run.

Also, merge test_ipautil.py from ipapython/test into tests/test_ipapython,
so the whole test suite is in one place.
---
 .../test => tests/test_ipapython}/test_ipautil.py  |   64 ++++++++++++++++----
 .../test_ipapython}/test_ipavalidate.py            |    0
 .../test_adtrustinstance.py                        |    0
 3 files changed, 52 insertions(+), 12 deletions(-)
 rename {ipapython/test => tests/test_ipapython}/test_ipautil.py (87%)
 rename {ipapython/test => tests/test_ipapython}/test_ipavalidate.py (100%)
 rename tests/test_ipaserver/{install => test_install}/test_adtrustinstance.py (100%)

diff --git a/ipapython/test/test_ipautil.py b/tests/test_ipapython/test_ipautil.py
similarity index 87%
rename from ipapython/test/test_ipautil.py
rename to tests/test_ipapython/test_ipautil.py
index ff9f282340c7900e51ecbf2abec912beb3f1f340..6783bd974ffe72a8ed191774aca6d2b2452036c7 100644
--- a/ipapython/test/test_ipautil.py
+++ b/tests/test_ipapython/test_ipautil.py
@@ -1,30 +1,74 @@
-#! /usr/bin/python -E
+# Authors:
+#   Jan Cholasta <[email protected]>
 #
-# Copyright (C) 2007    Red Hat
+# Copyright (C) 2011  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
+# 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/>.
-#
-
-import sys
-sys.path.insert(0, ".")
+"""
+Test the `ipapython/ipautil.py` module.
+"""
 
+import nose
 import unittest
-import datetime
 
 from ipapython import ipautil
 
+class CheckIPAddress:
+    def __init__(self, addr):
+        self.description = "Test IP address parsing and verification (%s)" % addr
+
+    def __call__(self, addr, words=None, prefixlen=None):
+        try:
+            ip = ipautil.CheckedIPAddress(addr, match_local=False)
+            assert ip.words == words and ip.prefixlen == prefixlen
+        except:
+            assert words is None and prefixlen is None
+
+def test_ip_address():
+    addrs = [
+        ('10.11.12.13',     (10, 11, 12, 13),   8),
+        ('10.11.12.13/14',  (10, 11, 12, 13),   14),
+        ('10.11.12.13%zoneid',),
+        ('10.11.12.13%zoneid/14',),
+        ('10.11.12.1337',),
+        ('10.11.12.13/33',),
+        ('127.0.0.1',),
+        ('241.1.2.3',),
+        ('169.254.1.2',),
+        ('10.11.12.0/24',),
+        ('224.5.6.7',),
+        ('10.11.12.255/24',),
+
+        ('2001::1',         (0x2001, 0, 0, 0, 0, 0, 0, 1), 64),
+        ('2001::1/72',      (0x2001, 0, 0, 0, 0, 0, 0, 1), 72),
+        ('2001::1%zoneid',  (0x2001, 0, 0, 0, 0, 0, 0, 1), 64),
+        ('2001::1%zoneid/72',),
+        ('2001::1beef',),
+        ('2001::1/129',),
+        ('::1',),
+        ('6789::1',),
+        ('fe89::1',),
+        ('2001::/64',),
+        ('ff01::1',),
+
+        ('junk',)
+    ]
+
+    for addr in addrs:
+        yield (CheckIPAddress(addr[0]),) + addr
+
 
 class TestCIDict(unittest.TestCase):
     def setUp(self):
@@ -303,7 +347,3 @@ class TestTimeParser(unittest.TestCase):
         self.assertEqual(-30, time.tzinfo.minoffset)
         offset = time.tzinfo.utcoffset(time.tzinfo.dst())
         self.assertEqual(((24 - 9) * 60 * 60) - (30 * 60), offset.seconds)
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/ipapython/test/test_ipavalidate.py b/tests/test_ipapython/test_ipavalidate.py
similarity index 100%
rename from ipapython/test/test_ipavalidate.py
rename to tests/test_ipapython/test_ipavalidate.py
diff --git a/tests/test_ipaserver/install/test_adtrustinstance.py b/tests/test_ipaserver/test_install/test_adtrustinstance.py
similarity index 100%
rename from tests/test_ipaserver/install/test_adtrustinstance.py
rename to tests/test_ipaserver/test_install/test_adtrustinstance.py
-- 
1.7.7.6

From 070196ba607b2a88cbd3736f7cba4682fe916459 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <[email protected]>
Date: Fri, 15 Jun 2012 05:17:49 -0400
Subject: [PATCH] Convert test_ipautil from unittest to nose

---
 tests/test_ipapython/test_ipautil.py |  312 ++++++++++++++++------------------
 1 files changed, 148 insertions(+), 164 deletions(-)

diff --git a/tests/test_ipapython/test_ipautil.py b/tests/test_ipapython/test_ipautil.py
index 6783bd974ffe72a8ed191774aca6d2b2452036c7..95933581f2f83f61008493079ba11fcda59487ef 100644
--- a/tests/test_ipapython/test_ipautil.py
+++ b/tests/test_ipapython/test_ipautil.py
@@ -21,7 +21,6 @@ Test the `ipapython/ipautil.py` module.
 """
 
 import nose
-import unittest
 
 from ipapython import ipautil
 
@@ -70,280 +69,265 @@ def test_ip_address():
         yield (CheckIPAddress(addr[0]),) + addr
 
 
-class TestCIDict(unittest.TestCase):
-    def setUp(self):
+class TestCIDict(object):
+    def setup(self):
         self.cidict = ipautil.CIDict()
         self.cidict["Key1"] = "val1"
         self.cidict["key2"] = "val2"
         self.cidict["KEY3"] = "VAL3"
 
-    def tearDown(self):
-        pass
+    def test_len(self):
+        nose.tools.assert_equal(3, len(self.cidict))
 
-    def testLen(self):
-        self.assertEqual(3, len(self.cidict))
-
-    def test__GetItem(self):
-        self.assertEqual("val1", self.cidict["Key1"])
-        self.assertEqual("val1", self.cidict["key1"])
-        self.assertEqual("val2", self.cidict["KEY2"])
-        self.assertEqual("VAL3", self.cidict["key3"])
-        self.assertEqual("VAL3", self.cidict["KEY3"])
-        try:
+    def test_getitem(self):
+        nose.tools.assert_equal("val1", self.cidict["Key1"])
+        nose.tools.assert_equal("val1", self.cidict["key1"])
+        nose.tools.assert_equal("val2", self.cidict["KEY2"])
+        nose.tools.assert_equal("VAL3", self.cidict["key3"])
+        nose.tools.assert_equal("VAL3", self.cidict["KEY3"])
+        with nose.tools.assert_raises(KeyError):
             self.cidict["key4"]
-            fail("should have raised KeyError")
-        except KeyError:
-            pass
 
-    def testGet(self):
-        self.assertEqual("val1", self.cidict.get("Key1"))
-        self.assertEqual("val1", self.cidict.get("key1"))
-        self.assertEqual("val2", self.cidict.get("KEY2"))
-        self.assertEqual("VAL3", self.cidict.get("key3"))
-        self.assertEqual("VAL3", self.cidict.get("KEY3"))
-        self.assertEqual("default", self.cidict.get("key4", "default"))
+    def test_get(self):
+        nose.tools.assert_equal("val1", self.cidict.get("Key1"))
+        nose.tools.assert_equal("val1", self.cidict.get("key1"))
+        nose.tools.assert_equal("val2", self.cidict.get("KEY2"))
+        nose.tools.assert_equal("VAL3", self.cidict.get("key3"))
+        nose.tools.assert_equal("VAL3", self.cidict.get("KEY3"))
+        nose.tools.assert_equal("default", self.cidict.get("key4", "default"))
 
-    def test__SetItem(self):
+    def test_setitem(self):
         self.cidict["key4"] = "val4"
-        self.assertEqual("val4", self.cidict["key4"])
+        nose.tools.assert_equal("val4", self.cidict["key4"])
         self.cidict["KEY4"] = "newval4"
-        self.assertEqual("newval4", self.cidict["key4"])
+        nose.tools.assert_equal("newval4", self.cidict["key4"])
 
-    def testDel(self):
-        self.assert_(self.cidict.has_key("Key1"))
+    def test_del(self):
+        assert self.cidict.has_key("Key1")
         del(self.cidict["Key1"])
-        self.failIf(self.cidict.has_key("Key1"))
+        assert not self.cidict.has_key("Key1")
 
-        self.assert_(self.cidict.has_key("key2"))
+        assert self.cidict.has_key("key2")
         del(self.cidict["KEY2"])
-        self.failIf(self.cidict.has_key("key2"))
+        assert not self.cidict.has_key("key2")
 
-    def testClear(self):
-        self.assertEqual(3, len(self.cidict))
+    def test_clear(self):
+        nose.tools.assert_equal(3, len(self.cidict))
         self.cidict.clear()
-        self.assertEqual(0, len(self.cidict))
+        nose.tools.assert_equal(0, len(self.cidict))
 
-    def testCopy(self):
+    def test_copy(self):
         """A copy is no longer a CIDict, but should preserve the case of
            the keys as they were inserted."""
         copy = self.cidict.copy()
-        self.assertEqual(3, len(copy))
-        self.assert_(copy.has_key("Key1"))
-        self.assertEqual("val1", copy["Key1"])
-        self.failIf(copy.has_key("key1"))
+        nose.tools.assert_equal(3, len(copy))
+        assert copy.has_key("Key1")
+        nose.tools.assert_equal("val1", copy["Key1"])
+        assert not copy.has_key("key1")
 
-    def testHasKey(self):
-        self.assert_(self.cidict.has_key("KEY1"))
-        self.assert_(self.cidict.has_key("key2"))
-        self.assert_(self.cidict.has_key("key3"))
+    def test_haskey(self):
+        assert self.cidict.has_key("KEY1")
+        assert self.cidict.has_key("key2")
+        assert self.cidict.has_key("key3")
 
-    def testItems(self):
+    def test_items(self):
         items = self.cidict.items()
-        self.assertEqual(3, len(items))
+        nose.tools.assert_equal(3, len(items))
         items_set = set(items)
-        self.assert_(("Key1", "val1") in items_set)
-        self.assert_(("key2", "val2") in items_set)
-        self.assert_(("KEY3", "VAL3") in items_set)
+        assert ("Key1", "val1") in items_set
+        assert ("key2", "val2") in items_set
+        assert ("KEY3", "VAL3") in items_set
 
-    def testIterItems(self):
+    def test_iteritems(self):
         items = []
         for (k,v) in self.cidict.iteritems():
             items.append((k,v))
-        self.assertEqual(3, len(items))
+        nose.tools.assert_equal(3, len(items))
         items_set = set(items)
-        self.assert_(("Key1", "val1") in items_set)
-        self.assert_(("key2", "val2") in items_set)
-        self.assert_(("KEY3", "VAL3") in items_set)
+        assert ("Key1", "val1") in items_set
+        assert ("key2", "val2") in items_set
+        assert ("KEY3", "VAL3") in items_set
 
-    def testIterKeys(self):
+    def test_iterkeys(self):
         keys = []
         for k in self.cidict.iterkeys():
             keys.append(k)
-        self.assertEqual(3, len(keys))
+        nose.tools.assert_equal(3, len(keys))
         keys_set = set(keys)
-        self.assert_("Key1" in keys_set)
-        self.assert_("key2" in keys_set)
-        self.assert_("KEY3" in keys_set)
+        assert "Key1" in keys_set
+        assert "key2" in keys_set
+        assert "KEY3" in keys_set
 
-    def testIterValues(self):
+    def test_itervalues(self):
         values = []
         for k in self.cidict.itervalues():
             values.append(k)
-        self.assertEqual(3, len(values))
+        nose.tools.assert_equal(3, len(values))
         values_set = set(values)
-        self.assert_("val1" in values_set)
-        self.assert_("val2" in values_set)
-        self.assert_("VAL3" in values_set)
+        assert "val1" in values_set
+        assert "val2" in values_set
+        assert "VAL3" in values_set
 
-    def testKeys(self):
+    def test_keys(self):
         keys = self.cidict.keys()
-        self.assertEqual(3, len(keys))
+        nose.tools.assert_equal(3, len(keys))
         keys_set = set(keys)
-        self.assert_("Key1" in keys_set)
-        self.assert_("key2" in keys_set)
-        self.assert_("KEY3" in keys_set)
+        assert "Key1" in keys_set
+        assert "key2" in keys_set
+        assert "KEY3" in keys_set
 
-    def testValues(self):
+    def test_values(self):
         values = self.cidict.values()
-        self.assertEqual(3, len(values))
+        nose.tools.assert_equal(3, len(values))
         values_set = set(values)
-        self.assert_("val1" in values_set)
-        self.assert_("val2" in values_set)
-        self.assert_("VAL3" in values_set)
+        assert "val1" in values_set
+        assert "val2" in values_set
+        assert "VAL3" in values_set
 
-    def testUpdate(self):
+    def test_update(self):
         newdict = { "KEY2": "newval2",
                     "key4": "val4" }
         self.cidict.update(newdict)
-        self.assertEqual(4, len(self.cidict))
+        nose.tools.assert_equal(4, len(self.cidict))
 
         items = self.cidict.items()
-        self.assertEqual(4, len(items))
+        nose.tools.assert_equal(4, len(items))
         items_set = set(items)
-        self.assert_(("Key1", "val1") in items_set)
+        assert ("Key1", "val1") in items_set
         # note the update "overwrites" the case of the key2
-        self.assert_(("KEY2", "newval2") in items_set)
-        self.assert_(("KEY3", "VAL3") in items_set)
-        self.assert_(("key4", "val4") in items_set)
+        assert ("KEY2", "newval2") in items_set
+        assert ("KEY3", "VAL3") in items_set
+        assert ("key4", "val4") in items_set
 
-    def testSetDefault(self):
-        self.assertEqual("val1", self.cidict.setdefault("KEY1", "default"))
+    def test_setdefault(self):
+        nose.tools.assert_equal("val1", self.cidict.setdefault("KEY1", "default"))
 
-        self.failIf(self.cidict.has_key("KEY4"))
-        self.assertEqual("default", self.cidict.setdefault("KEY4", "default"))
-        self.assert_(self.cidict.has_key("KEY4"))
-        self.assertEqual("default", self.cidict["key4"])
+        assert not self.cidict.has_key("KEY4")
+        nose.tools.assert_equal("default", self.cidict.setdefault("KEY4", "default"))
+        assert self.cidict.has_key("KEY4")
+        nose.tools.assert_equal("default", self.cidict["key4"])
 
-        self.failIf(self.cidict.has_key("KEY5"))
-        self.assertEqual(None, self.cidict.setdefault("KEY5"))
-        self.assert_(self.cidict.has_key("KEY5"))
-        self.assertEqual(None, self.cidict["key5"])
+        assert not self.cidict.has_key("KEY5")
+        nose.tools.assert_equal(None, self.cidict.setdefault("KEY5"))
+        assert self.cidict.has_key("KEY5")
+        nose.tools.assert_equal(None, self.cidict["key5"])
 
-    def testPop(self):
-        self.assertEqual("val1", self.cidict.pop("KEY1", "default"))
-        self.failIf(self.cidict.has_key("key1"))
+    def test_pop(self):
+        nose.tools.assert_equal("val1", self.cidict.pop("KEY1", "default"))
+        assert not self.cidict.has_key("key1")
 
-        self.assertEqual("val2", self.cidict.pop("KEY2"))
-        self.failIf(self.cidict.has_key("key2"))
+        nose.tools.assert_equal("val2", self.cidict.pop("KEY2"))
+        assert not self.cidict.has_key("key2")
 
-        self.assertEqual("default", self.cidict.pop("key4", "default"))
-        try:
+        nose.tools.assert_equal("default", self.cidict.pop("key4", "default"))
+        with nose.tools.assert_raises(KeyError):
             self.cidict.pop("key4")
-            fail("should have raised KeyError")
-        except KeyError:
-            pass
 
-    def testPopItem(self):
+    def test_popitem(self):
         items = set(self.cidict.items())
-        self.assertEqual(3, len(self.cidict))
+        nose.tools.assert_equal(3, len(self.cidict))
 
         item = self.cidict.popitem()
-        self.assertEqual(2, len(self.cidict))
-        self.assert_(item in items)
+        nose.tools.assert_equal(2, len(self.cidict))
+        assert item in items
         items.discard(item)
 
         item = self.cidict.popitem()
-        self.assertEqual(1, len(self.cidict))
-        self.assert_(item in items)
+        nose.tools.assert_equal(1, len(self.cidict))
+        assert item in items
         items.discard(item)
 
         item = self.cidict.popitem()
-        self.assertEqual(0, len(self.cidict))
-        self.assert_(item in items)
+        nose.tools.assert_equal(0, len(self.cidict))
+        assert item in items
         items.discard(item)
 
-class TestTimeParser(unittest.TestCase):
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def testSimple(self):
+class TestTimeParser(object):
+    def test_simple(self):
         timestr = "20070803"
 
         time = ipautil.parse_generalized_time(timestr)
-        self.assertEqual(2007, time.year)
-        self.assertEqual(8, time.month)
-        self.assertEqual(3, time.day)
-        self.assertEqual(0, time.hour)
-        self.assertEqual(0, time.minute)
-        self.assertEqual(0, time.second)
+        nose.tools.assert_equal(2007, time.year)
+        nose.tools.assert_equal(8, time.month)
+        nose.tools.assert_equal(3, time.day)
+        nose.tools.assert_equal(0, time.hour)
+        nose.tools.assert_equal(0, time.minute)
+        nose.tools.assert_equal(0, time.second)
 
-    def testHourMinSec(self):
+    def test_hour_min_sec(self):
         timestr = "20051213141205"
 
         time = ipautil.parse_generalized_time(timestr)
-        self.assertEqual(2005, time.year)
-        self.assertEqual(12, time.month)
-        self.assertEqual(13, time.day)
-        self.assertEqual(14, time.hour)
-        self.assertEqual(12, time.minute)
-        self.assertEqual(5, time.second)
+        nose.tools.assert_equal(2005, time.year)
+        nose.tools.assert_equal(12, time.month)
+        nose.tools.assert_equal(13, time.day)
+        nose.tools.assert_equal(14, time.hour)
+        nose.tools.assert_equal(12, time.minute)
+        nose.tools.assert_equal(5, time.second)
 
-    def testFractions(self):
+    def test_fractions(self):
         timestr = "2003092208.5"
 
         time = ipautil.parse_generalized_time(timestr)
-        self.assertEqual(2003, time.year)
-        self.assertEqual(9, time.month)
-        self.assertEqual(22, time.day)
-        self.assertEqual(8, time.hour)
-        self.assertEqual(30, time.minute)
-        self.assertEqual(0, time.second)
+        nose.tools.assert_equal(2003, time.year)
+        nose.tools.assert_equal(9, time.month)
+        nose.tools.assert_equal(22, time.day)
+        nose.tools.assert_equal(8, time.hour)
+        nose.tools.assert_equal(30, time.minute)
+        nose.tools.assert_equal(0, time.second)
 
         timestr = "199203301544,25"
 
         time = ipautil.parse_generalized_time(timestr)
-        self.assertEqual(1992, time.year)
-        self.assertEqual(3, time.month)
-        self.assertEqual(30, time.day)
-        self.assertEqual(15, time.hour)
-        self.assertEqual(44, time.minute)
-        self.assertEqual(15, time.second)
+        nose.tools.assert_equal(1992, time.year)
+        nose.tools.assert_equal(3, time.month)
+        nose.tools.assert_equal(30, time.day)
+        nose.tools.assert_equal(15, time.hour)
+        nose.tools.assert_equal(44, time.minute)
+        nose.tools.assert_equal(15, time.second)
 
         timestr = "20060401185912,8"
 
         time = ipautil.parse_generalized_time(timestr)
-        self.assertEqual(2006, time.year)
-        self.assertEqual(4, time.month)
-        self.assertEqual(1, time.day)
-        self.assertEqual(18, time.hour)
-        self.assertEqual(59, time.minute)
-        self.assertEqual(12, time.second)
-        self.assertEqual(800000, time.microsecond)
+        nose.tools.assert_equal(2006, time.year)
+        nose.tools.assert_equal(4, time.month)
+        nose.tools.assert_equal(1, time.day)
+        nose.tools.assert_equal(18, time.hour)
+        nose.tools.assert_equal(59, time.minute)
+        nose.tools.assert_equal(12, time.second)
+        nose.tools.assert_equal(800000, time.microsecond)
 
-    def testTimeZones(self):
+    def test_time_zones(self):
         timestr = "20051213141205Z"
 
         time = ipautil.parse_generalized_time(timestr)
-        self.assertEqual(0, time.tzinfo.houroffset)
-        self.assertEqual(0, time.tzinfo.minoffset)
+        nose.tools.assert_equal(0, time.tzinfo.houroffset)
+        nose.tools.assert_equal(0, time.tzinfo.minoffset)
         offset = time.tzinfo.utcoffset(time.tzinfo.dst())
-        self.assertEqual(0, offset.seconds)
+        nose.tools.assert_equal(0, offset.seconds)
 
         timestr = "20051213141205+0500"
 
         time = ipautil.parse_generalized_time(timestr)
-        self.assertEqual(5, time.tzinfo.houroffset)
-        self.assertEqual(0, time.tzinfo.minoffset)
+        nose.tools.assert_equal(5, time.tzinfo.houroffset)
+        nose.tools.assert_equal(0, time.tzinfo.minoffset)
         offset = time.tzinfo.utcoffset(time.tzinfo.dst())
-        self.assertEqual(5 * 60 * 60, offset.seconds)
+        nose.tools.assert_equal(5 * 60 * 60, offset.seconds)
 
         timestr = "20051213141205-0500"
 
         time = ipautil.parse_generalized_time(timestr)
-        self.assertEqual(-5, time.tzinfo.houroffset)
-        self.assertEqual(0, time.tzinfo.minoffset)
+        nose.tools.assert_equal(-5, time.tzinfo.houroffset)
+        nose.tools.assert_equal(0, time.tzinfo.minoffset)
         # NOTE - the offset is always positive - it's minutes
         #        _east_ of UTC
         offset = time.tzinfo.utcoffset(time.tzinfo.dst())
-        self.assertEqual((24 - 5) * 60 * 60, offset.seconds)
+        nose.tools.assert_equal((24 - 5) * 60 * 60, offset.seconds)
 
         timestr = "20051213141205-0930"
 
         time = ipautil.parse_generalized_time(timestr)
-        self.assertEqual(-9, time.tzinfo.houroffset)
-        self.assertEqual(-30, time.tzinfo.minoffset)
+        nose.tools.assert_equal(-9, time.tzinfo.houroffset)
+        nose.tools.assert_equal(-30, time.tzinfo.minoffset)
         offset = time.tzinfo.utcoffset(time.tzinfo.dst())
-        self.assertEqual(((24 - 9) * 60 * 60) - (30 * 60), offset.seconds)
+        nose.tools.assert_equal(((24 - 9) * 60 * 60) - (30 * 60), offset.seconds)
-- 
1.7.7.6

From 3237ab534cc78376f786147e63efb4524db827b3 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <[email protected]>
Date: Tue, 5 Feb 2013 10:24:46 -0500
Subject: [PATCH] Add missing dict methods to CIDict

Add __contains__, __iter__, clear.
Also add values() and itervalues(). Previously the dict versions were
used; the new ones guarantee that the order matches keys().
Mark view* methods as not implemented.

Document that CIDict.copy() returns a plain dict.
Test the above additions, and fromkeys() which worked but wasn't tested.
---
 ipapython/ipautil.py                 |   45 +++++++++++++++++++++++++---------
 tests/test_ipapython/test_ipautil.py |   35 ++++++++++++++++++++++++++
 2 files changed, 68 insertions(+), 12 deletions(-)

diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index c0ac3a1f76397e79672f1b99c2d46463d8e0af3e..a9708102c58b5c5660a6ddc189c6c1650f3983dd 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -441,7 +441,7 @@ class CIDict(dict):
 
     def __init__(self, default=None):
         super(CIDict, self).__init__()
-        self._keys = {}
+        self._keys = {}  # mapping of lowercased keys to proper case
         self.update(default or {})
 
     def __getitem__(self, key):
@@ -455,41 +455,49 @@ class CIDict(dict):
     def __delitem__(self, key):
         lower_key = key.lower()
         del self._keys[lower_key]
-        return super(CIDict, self).__delitem__(key.lower())
+        return super(CIDict, self).__delitem__(lower_key)
 
     def update(self, dict):
         for key in dict.keys():
             self[key] = dict[key]
 
+    def __contains__(self, key):
+        return super(CIDict, self).__contains__(key.lower())
+
     def has_key(self, key):
         return super(CIDict, self).has_key(key.lower())
 
     def get(self, key, failobj=None):
         try:
             return self[key]
         except KeyError:
             return failobj
 
+    def __iter__(self):
+        return self._keys.itervalues()
+
     def keys(self):
-        return self._keys.values()
+        return list(self.iterkeys())
 
     def items(self):
-        result = []
-        for k in self._keys.values():
-            result.append((k, self[k]))
-        return result
+        return list(self.iteritems())
+
+    def values(self):
+        return list(self.itervalues())
 
     def copy(self):
+        """Returns a copy of this CIDict as an ordinary dict"""
         copy = {}
-        for k in self._keys.values():
-            copy[k] = self[k]
-        return copy
+        return dict(self.items())
 
     def iteritems(self):
-        return self.copy().iteritems()
+        return ((k, self[k]) for k in self._keys.itervalues())
 
     def iterkeys(self):
-        return self.copy().iterkeys()
+        return self._keys.itervalues()
+
+    def itervalues(self):
+        return (v for k, v in self.iteritems())
 
     def setdefault(self, key, value=None):
         try:
@@ -515,6 +523,19 @@ class CIDict(dict):
 
         return (key, value)
 
+    def clear(self):
+        self._keys.clear()
+        return super(CIDict, self).clear()
+
+    def viewitems(self):
+        raise NotImplementedError('CIDict.viewitems is not implemented')
+
+    def viewkeys(self):
+        raise NotImplementedError('CIDict.viewkeys is not implemented')
+
+    def viewvvalues(self):
+        raise NotImplementedError('CIDict.viewvvalues is not implemented')
+
 
 class GeneralizedTimeZone(datetime.tzinfo):
     """This class is a basic timezone wrapper for the offset specified
diff --git a/tests/test_ipapython/test_ipautil.py b/tests/test_ipapython/test_ipautil.py
index 95933581f2f83f61008493079ba11fcda59487ef..bd2d0bdcb2a1794bd5358156ef4e5076ce102c8d 100644
--- a/tests/test_ipapython/test_ipautil.py
+++ b/tests/test_ipapython/test_ipautil.py
@@ -130,14 +130,31 @@ class TestCIDict(object):
         assert self.cidict.has_key("key2")
         assert self.cidict.has_key("key3")
 
+        assert not self.cidict.has_key("Key4")
+
+    def test_contains(self):
+        assert "KEY1" in self.cidict
+        assert "key2" in self.cidict
+        assert "key3" in self.cidict
+
+        assert "Key4" not in self.cidict
+
     def test_items(self):
         items = self.cidict.items()
         nose.tools.assert_equal(3, len(items))
         items_set = set(items)
         assert ("Key1", "val1") in items_set
         assert ("key2", "val2") in items_set
         assert ("KEY3", "VAL3") in items_set
 
+        assert self.cidict.items() == list(self.cidict.iteritems()) == zip(
+            self.cidict.iterkeys(), self.cidict.itervalues())
+
+    def test_iter(self):
+        items = []
+        assert list(self.cidict) == list(self.cidict.keys())
+        assert sorted(self.cidict) == sorted(['Key1', 'key2', 'KEY3'])
+
     def test_iteritems(self):
         items = []
         for (k,v) in self.cidict.iteritems():
@@ -176,14 +193,18 @@ class TestCIDict(object):
         assert "key2" in keys_set
         assert "KEY3" in keys_set
 
+        assert self.cidict.keys() == list(self.cidict.iterkeys())
+
     def test_values(self):
         values = self.cidict.values()
         nose.tools.assert_equal(3, len(values))
         values_set = set(values)
         assert "val1" in values_set
         assert "val2" in values_set
         assert "VAL3" in values_set
 
+        assert self.cidict.values() == list(self.cidict.itervalues())
+
     def test_update(self):
         newdict = { "KEY2": "newval2",
                     "key4": "val4" }
@@ -242,6 +263,20 @@ class TestCIDict(object):
         assert item in items
         items.discard(item)
 
+    def test_fromkeys(self):
+        dct = ipautil.CIDict.fromkeys(('A', 'b', 'C'))
+        assert sorted(dct.keys()) == sorted(['A', 'b', 'C'])
+        assert sorted(dct.values()) == [None] * 3
+
+    def test_clear(self):
+        self.cidict.clear()
+        assert self.cidict == {}
+        assert self.cidict.keys() == []
+        assert self.cidict.values() == []
+        assert self.cidict.items() == []
+        assert self.cidict._keys == {}
+
+
 class TestTimeParser(object):
     def test_simple(self):
         timestr = "20070803"
-- 
1.7.7.6

_______________________________________________
Freeipa-devel mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to