[Checkins] SVN: zope.index/trunk/src/zope/index/keyword/ 100% coverage for zope.index.keyword.index module.

Tres Seaver tseaver at palladion.com
Thu Jun 11 03:47:29 EDT 2009


Log message for revision 100844:
  100% coverage for zope.index.keyword.index module.

Changed:
  U   zope.index/trunk/src/zope/index/keyword/index.py
  U   zope.index/trunk/src/zope/index/keyword/tests.py

-=-
Modified: zope.index/trunk/src/zope/index/keyword/index.py
===================================================================
--- zope.index/trunk/src/zope/index/keyword/index.py	2009-06-11 06:52:41 UTC (rev 100843)
+++ zope.index/trunk/src/zope/index/keyword/index.py	2009-06-11 07:47:28 UTC (rev 100844)
@@ -62,17 +62,17 @@
 
     def normalize(self, seq):
         """Perform normalization on sequence of keywords.
-        
+
         Return normalized sequence. This method may be
         overriden by subclasses.
-        
+
         """
         return seq
 
     def index_doc(self, docid, seq):
         if isinstance(seq, basestring):
             raise TypeError('seq argument must be a list/tuple of strings')
-    
+
         if not seq:
             return
 
@@ -93,12 +93,15 @@
 
             # removed keywords are removed from the forward index
             for word in kw_removed:
-                self._fwd_index[word].remove(docid)
-            
+                fwd = self._fwd_index[word]
+                fwd.remove(docid)
+                if len(fwd) == 0:
+                    del self._fwd_index[word]
+
             # now update reverse and forward indexes
             self._insert_forward(docid, kw_added)
             self._insert_reverse(docid, new_kw)
-        
+
     def unindex_doc(self, docid):
         idx  = self._fwd_index
 
@@ -106,14 +109,15 @@
             for word in self._rev_index[docid]:
                 idx[word].remove(docid)
                 if not idx[word]:
-                    del idx[word] 
+                    del idx[word]
         except KeyError:
+            msg = 'WAAA!  Inconsistent'
             return
-        
+
         try:
             del self._rev_index[docid]
-        except KeyError:
-            pass
+        except KeyError: #pragma NO COVERAGE
+            msg = 'WAAA!  Inconsistent'
 
         self._num_docs.change(-1)
 
@@ -157,8 +161,9 @@
                 if not rs:
                     break
         else:
-            raise TypeError('Keyword index only supports `and` and `or` operators, not `%s`.' % operator)
-        
+            raise TypeError('Keyword index only supports `and` and `or` '
+                            'operators, not `%s`.' % operator)
+
         if rs:
             return rs
         else:

Modified: zope.index/trunk/src/zope/index/keyword/tests.py
===================================================================
--- zope.index/trunk/src/zope/index/keyword/tests.py	2009-06-11 06:52:41 UTC (rev 100843)
+++ zope.index/trunk/src/zope/index/keyword/tests.py	2009-06-11 07:47:28 UTC (rev 100844)
@@ -12,167 +12,370 @@
 #
 ##############################################################################
 
-from unittest import TestCase, TestSuite, main, makeSuite
+import unittest
 
-import BTrees
+class _KeywordIndexTestsBase:
 
-from zope.index.keyword.index import CaseInsensitiveKeywordIndex
-from zope.index.interfaces import IInjection, IStatistics, IIndexSearch
-from zope.index.keyword.interfaces import IKeywordQuerying
-from zope.interface.verify import verifyClass
+    def _getTargetClass(self):
+        from zope.index.keyword.index import KeywordIndex
+        return KeywordIndex
 
-class KeywordIndexTest(TestCase):
+    def _populate(self, index):
 
-    from BTrees.IFBTree import IFSet
+        index.index_doc(1, ('zope', 'CMF', 'Zope3'))
+        index.index_doc(2, ('the', 'quick', 'brown', 'FOX'))
+        index.index_doc(3, ('Zope',))
+        index.index_doc(4, ())
+        index.index_doc(5, ('cmf',))
 
-    def setUp(self):
-        self.index = CaseInsensitiveKeywordIndex()
+    _populated_doc_count = 4
+    _populated_word_count = 9
 
-    def _populate_index(self):
+    def test_normalize(self):
+        index = self._makeOne()
+        self.assertEqual(index.normalize(['Foo']), ['Foo'])
 
-        self.index.index_doc(1, ('zope', 'CMF', 'zope3', 'Zope3'))
-        self.index.index_doc(2, ('the', 'quick', 'brown', 'FOX'))
-        self.index.index_doc(3, ('Zope', 'zope'))
-        self.index.index_doc(4, ())
-        self.index.index_doc(5, ('cmf',))
+    def test_simplesearch(self):
+        index = self._makeOne()
+        self._populate(index)
+        self._search(index, [''],      self.IFSet())
+        self._search(index, 'cmf',     self.IFSet([5]))
+        self._search(index, ['cmf'],   self.IFSet([5]))
+        self._search(index, ['Zope'],  self.IFSet([3]))
+        self._search(index, ['Zope3'], self.IFSet([1]))
+        self._search(index, ['foo'],   self.IFSet())
 
+    def test_search_and(self):
+        index = self._makeOne()
+        self._populate(index)
+        self._search_and(index, ('CMF', 'Zope3'), self.IFSet([1]))
+        self._search_and(index, ('CMF', 'zope'),  self.IFSet([1]))
+        self._search_and(index, ('cmf', 'zope4'), self.IFSet())
+        self._search_and(index, ('quick', 'FOX'), self.IFSet([2]))
 
-    def _search(self, query, expected, mode='and'):
-        results = self.index.search(query, mode)
+    def test_search_or(self):
+        index = self._makeOne()
+        self._populate(index)
+        self._search_or(index, ('cmf', 'Zope3'), self.IFSet([1, 5]))
+        self._search_or(index, ('cmf', 'zope'),  self.IFSet([1, 5]))
+        self._search_or(index, ('cmf', 'zope4'), self.IFSet([5]))
+        self._search_or(index, ('zope', 'Zope'), self.IFSet([1,3]))
 
+    def test_apply(self):
+        index = self._makeOne()
+        self._populate(index)
+        self._apply(index, ('CMF', 'Zope3'), self.IFSet([1]))
+        self._apply(index, ('CMF', 'zope'),  self.IFSet([1]))
+        self._apply(index, ('cmf', 'zope4'), self.IFSet())
+        self._apply(index, ('quick', 'FOX'), self.IFSet([2]))
+
+    def test_apply_and(self):
+        index = self._makeOne()
+        self._populate(index)
+        self._apply_and(index, ('CMF', 'Zope3'), self.IFSet([1]))
+        self._apply_and(index, ('CMF', 'zope'),  self.IFSet([1]))
+        self._apply_and(index, ('cmf', 'zope4'), self.IFSet())
+        self._apply_and(index, ('quick', 'FOX'), self.IFSet([2]))
+
+    def test_apply_or(self):
+        index = self._makeOne()
+        self._populate(index)
+        self._apply_or(index, ('cmf', 'Zope3'), self.IFSet([1, 5]))
+        self._apply_or(index, ('cmf', 'zope'),  self.IFSet([1, 5]))
+        self._apply_or(index, ('cmf', 'zope4'), self.IFSet([5]))
+        self._apply_or(index, ('zope', 'Zope'), self.IFSet([1,3]))
+
+class CaseInsensitiveKeywordIndexTestsBase:
+
+    def _getTargetClass(self):
+        from zope.index.keyword.index import CaseInsensitiveKeywordIndex
+        return CaseInsensitiveKeywordIndex
+
+    def _populate(self, index):
+
+        index.index_doc(1, ('zope', 'CMF', 'zope3', 'Zope3'))
+        index.index_doc(2, ('the', 'quick', 'brown', 'FOX'))
+        index.index_doc(3, ('Zope', 'zope'))
+        index.index_doc(4, ())
+        index.index_doc(5, ('cmf',))
+
+    _populated_doc_count = 4
+    _populated_word_count = 7
+
+    def test_normalize(self):
+        index = self._makeOne()
+        self.assertEqual(index.normalize(['Foo']), ['foo'])
+
+    def test_simplesearch(self):
+        index = self._makeOne()
+        self._populate(index)
+        self._search(index, [''],      self.IFSet())
+        self._search(index, 'cmf',     self.IFSet([1, 5]))
+        self._search(index, ['cmf'],   self.IFSet([1, 5]))
+        self._search(index, ['zope'],  self.IFSet([1, 3]))
+        self._search(index, ['zope3'], self.IFSet([1]))
+        self._search(index, ['foo'],   self.IFSet())
+
+    def test_search_and(self):
+        index = self._makeOne()
+        self._populate(index)
+        self._search_and(index, ('cmf', 'zope3'), self.IFSet([1]))
+        self._search_and(index, ('cmf', 'zope'),  self.IFSet([1]))
+        self._search_and(index, ('cmf', 'zope4'), self.IFSet())
+        self._search_and(index, ('zope', 'ZOPE'), self.IFSet([1, 3]))
+
+    def test_search_or(self):
+        index = self._makeOne()
+        self._populate(index)
+        self._search_or(index, ('cmf', 'zope3'), self.IFSet([1, 5]))
+        self._search_or(index, ('cmf', 'zope'),  self.IFSet([1, 3, 5]))
+        self._search_or(index, ('cmf', 'zope4'), self.IFSet([1, 5]))
+        self._search_or(index, ('zope', 'ZOPE'), self.IFSet([1,3]))
+
+    def test_apply(self):
+        index = self._makeOne()
+        self._populate(index)
+        self._apply(index, ('cmf', 'zope3'), self.IFSet([1]))
+        self._apply(index, ('cmf', 'zope'),  self.IFSet([1]))
+        self._apply(index, ('cmf', 'zope4'), self.IFSet())
+        self._apply(index, ('zope', 'ZOPE'), self.IFSet([1, 3]))
+
+    def test_apply_and(self):
+        index = self._makeOne()
+        self._populate(index)
+        self._apply_and(index, ('cmf', 'zope3'), self.IFSet([1]))
+        self._apply_and(index, ('cmf', 'zope'),  self.IFSet([1]))
+        self._apply_and(index, ('cmf', 'zope4'), self.IFSet())
+        self._apply_and(index, ('zope', 'ZOPE'), self.IFSet([1, 3]))
+
+    def test_apply_or(self):
+        index = self._makeOne()
+        self._populate(index)
+        self._apply_or(index, ('cmf', 'zope3'), self.IFSet([1, 5]))
+        self._apply_or(index, ('cmf', 'zope'),  self.IFSet([1, 3, 5]))
+        self._apply_or(index, ('cmf', 'zope4'), self.IFSet([1, 5]))
+        self._apply_or(index, ('zope', 'ZOPE'), self.IFSet([1,3]))
+
+class _ThirtyTwoBitBase:
+
+    def _get_family(self):
+        import BTrees
+        return BTrees.family32
+
+    def IFSet(self, *args, **kw):
+        from BTrees.IFBTree import IFSet
+        return IFSet(*args, **kw)
+
+class _SixtyFourBitBase:
+
+    def _get_family(self):
+        import BTrees
+        return BTrees.family64
+
+    def IFSet(self, *args, **kw):
+        from BTrees.LFBTree import LFSet
+        return LFSet(*args, **kw)
+
+_marker = object()
+
+class _TestCaseBase:
+
+    def _makeOne(self, family=_marker):
+        if family is _marker:
+            return self._getTargetClass()(self._get_family())
+        return self._getTargetClass()(family)
+
+    def _search(self, index, query, expected, mode='and'):
+        results = index.search(query, mode)
+
         # results and expected are IFSets() but we can not
         # compare them directly since __eq__() does not seem
         # to be implemented for BTrees
         self.assertEqual(results.keys(), expected.keys())
 
-    def _search_and(self, query, expected):
-        return self._search(query, expected, 'and')
+    def _search_and(self, index, query, expected):
+        return self._search(index, query, expected, 'and')
 
-    def _search_or(self, query, expected):
-        return self._search(query, expected, 'or')
+    def _search_or(self, index, query, expected):
+        return self._search(index, query, expected, 'or')
 
-    def _apply(self, query, expected, mode='and'):
-        results = self.index.apply(query)
+    def _apply(self, index, query, expected, mode='and'):
+        results = index.apply(query)
         self.assertEqual(results.keys(), expected.keys())
 
-    def _apply_and(self, query, expected):
-        results = self.index.apply({'operator': 'and', 'query': query})
+    def _apply_and(self, index, query, expected):
+        results = index.apply({'operator': 'and', 'query': query})
         self.assertEqual(results.keys(), expected.keys())
 
-    def _apply_or(self, query, expected):
-        results = self.index.apply({'operator': 'or', 'query': query})
+    def _apply_or(self, index, query, expected):
+        results = index.apply({'operator': 'or', 'query': query})
         self.assertEqual(results.keys(), expected.keys())
 
-    def test_interface(self):
-        verifyClass(IInjection, CaseInsensitiveKeywordIndex)
-        verifyClass(IStatistics, CaseInsensitiveKeywordIndex)
-        verifyClass(IIndexSearch, CaseInsensitiveKeywordIndex)
-        verifyClass(IKeywordQuerying, CaseInsensitiveKeywordIndex)
+    def test_class_conforms_to_IInjection(self):
+        from zope.interface.verify import verifyClass
+        from zope.index.interfaces import IInjection
+        verifyClass(IInjection, self._getTargetClass())
 
+    def test_instance_conforms_to_IInjection(self):
+        from zope.interface.verify import verifyObject
+        from zope.index.interfaces import IInjection
+        verifyObject(IInjection, self._makeOne())
+
+    def test_class_conforms_to_IIndexSearch(self):
+        from zope.interface.verify import verifyClass
+        from zope.index.interfaces import IIndexSearch
+        verifyClass(IIndexSearch, self._getTargetClass())
+
+    def test_instance_conforms_to_IIndexSearch(self):
+        from zope.interface.verify import verifyObject
+        from zope.index.interfaces import IIndexSearch
+        verifyObject(IIndexSearch, self._makeOne())
+
+    def test_class_conforms_to_IStatistics(self):
+        from zope.interface.verify import verifyClass
+        from zope.index.interfaces import IStatistics
+        verifyClass(IStatistics, self._getTargetClass())
+
+    def test_instance_conforms_to_IStatistics(self):
+        from zope.interface.verify import verifyObject
+        from zope.index.interfaces import IStatistics
+        verifyObject(IStatistics, self._makeOne())
+
+    def test_class_conforms_to_IKeywordQuerying(self):
+        from zope.interface.verify import verifyClass
+        from zope.index.keyword.interfaces import IKeywordQuerying
+        verifyClass(IKeywordQuerying, self._getTargetClass())
+
+    def test_instance_conforms_to_IKeywordQuerying(self):
+        from zope.interface.verify import verifyObject
+        from zope.index.keyword.interfaces import IKeywordQuerying
+        verifyObject(IKeywordQuerying, self._makeOne())
+
+    def test_ctor_defaults(self):
+        index = self._makeOne()
+        self.failUnless(index.family is self._get_family())
+
+    def test_ctor_explicit_family(self):
+        import BTrees
+        index = self._makeOne(family=BTrees.family64)
+        self.failUnless(index.family is BTrees.family64)
+
     def test_empty_index(self):
-        self.assertEqual(self.index.documentCount(), 0)
-        self.assertEqual(self.index.wordCount(), 0)
-        self._populate_index()
-        self.assertEqual(self.index.documentCount(), 4)
-        self.assertEqual(self.index.wordCount(), 7)
-        self.index.clear()
-        self.assertEqual(self.index.documentCount(), 0)
-        self.assertEqual(self.index.wordCount(), 0)
+        index = self._makeOne()
+        self.assertEqual(index.documentCount(), 0)
+        self.assertEqual(index.wordCount(), 0)
+        self.failIf(index.has_doc(1))
 
-    def test_unindex(self):
-        self._populate_index()
-        self.assertEqual(self.index.documentCount(), 4)
-        self.index.unindex_doc(1)
-        self.index.unindex_doc(2)
-        self.assertEqual(self.index.documentCount(), 2)
-        self.index.unindex_doc(-99999)     # no exception should be raised
-        self.assertEqual(self.index.documentCount(), 2)
+    def test_index_doc_string_value_raises(self):
+        index = self._makeOne()
+        self.assertRaises(TypeError, index.index_doc, 1, 'albatross')
 
-    def test_reindex(self):
-        self._populate_index()
-        self.assertEqual(self.index.documentCount(), 4)
-        self.index.unindex_doc(1)
-        self.index.unindex_doc(2)
-        self.index.index_doc(1,  ('foo', 'bar', 'doom'))
-        self.index.index_doc(1,  ('bar', 'blabla'))
-        self.assertEqual(self.index.documentCount(), 3)
-        self._search('quick',   self.IFSet())
-        self._search('foo',   self.IFSet())
-        self._search('bar',   self.IFSet([1]))
-        self._search(['doom'],   self.IFSet())
-        self._search(['blabla'],   self.IFSet([1]))
-        self._search_and(('bar', 'blabla'),   self.IFSet([1]))
-        self._search(['cmf'],   self.IFSet([5]))
+    def test_index_doc_single(self):
+        index = self._makeOne()
+        index.index_doc(1, ('albatross', 'cormorant'))
+        self.assertEqual(index.documentCount(), 1)
+        self.assertEqual(index.wordCount(), 2)
+        self.failUnless(index.has_doc(1))
+        self.failUnless('albatross' in index._fwd_index)
+        self.failUnless('cormorant' in index._fwd_index)
 
-    def test_hasdoc(self):
-        self._populate_index()
-        self.assertEqual(self.index.has_doc(1), 1)
-        self.assertEqual(self.index.has_doc(2), 1)
-        self.assertEqual(self.index.has_doc(3), 1)
-        self.assertEqual(self.index.has_doc(4), 0)
-        self.assertEqual(self.index.has_doc(5), 1)
-        self.assertEqual(self.index.has_doc(6), 0)
+    def test_index_doc_existing(self):
+        index = self._makeOne()
+        index.index_doc(1, ('albatross', 'cormorant'))
+        index.index_doc(1, ('buzzard', 'cormorant'))
+        self.assertEqual(index.documentCount(), 1)
+        self.assertEqual(index.wordCount(), 2)
+        self.failUnless(index.has_doc(1))
+        self.failIf('albatross' in index._fwd_index)
+        self.failUnless('buzzard' in index._fwd_index)
+        self.failUnless('cormorant' in index._fwd_index)
 
-    def test_simplesearch(self):
-        self._populate_index()
-        self._search([''],      self.IFSet())
-        self._search(['cmf'],   self.IFSet([1, 5]))
-        self._search(['zope'],  self.IFSet([1, 3]))
-        self._search(['zope3'], self.IFSet([1]))
-        self._search(['foo'],   self.IFSet())
+    def test_index_doc_many(self):
+        index = self._makeOne()
+        self._populate(index)
+        self.assertEqual(index.documentCount(), self._populated_doc_count)
+        self.assertEqual(index.wordCount(), self._populated_word_count)
+        for docid in range(1, 6):
+            if docid == 4:
+                self.failIf(index.has_doc(docid))
+            else:
+                self.failUnless(index.has_doc(docid))
 
-    def test_search_and(self):
-        self._populate_index()
-        self._search_and(('cmf', 'zope3'), self.IFSet([1]))
-        self._search_and(('cmf', 'zope'),  self.IFSet([1]))
-        self._search_and(('cmf', 'zope4'), self.IFSet())
-        self._search_and(('zope', 'ZOPE'), self.IFSet([1, 3]))
+    def test_clear(self):
+        index = self._makeOne()
+        self._populate(index)
+        index.clear()
+        self.assertEqual(index.documentCount(), 0)
+        self.assertEqual(index.wordCount(), 0)
+        for docid in range(1, 6):
+            self.failIf(index.has_doc(docid))
 
-    def test_search_or(self):
-        self._populate_index()
-        self._search_or(('cmf', 'zope3'), self.IFSet([1, 5]))
-        self._search_or(('cmf', 'zope'),  self.IFSet([1, 3, 5]))
-        self._search_or(('cmf', 'zope4'), self.IFSet([1, 5]))
-        self._search_or(('zope', 'ZOPE'), self.IFSet([1,3]))
+    def test_unindex_doc_missing(self):
+        index = self._makeOne()
+        index.unindex_doc(1) # doesn't raise
 
-    def test_apply(self):
-        self._populate_index()
-        self._apply(('cmf', 'zope3'), self.IFSet([1]))
-        self._apply(('cmf', 'zope'),  self.IFSet([1]))
-        self._apply(('cmf', 'zope4'), self.IFSet())
-        self._apply(('zope', 'ZOPE'), self.IFSet([1, 3]))
+    def test_unindex_no_residue(self):
+        index = self._makeOne()
+        index.index_doc(1, ('albatross', ))
+        index.unindex_doc(1)
+        self.assertEqual(index.documentCount(), 0)
+        self.assertEqual(index.wordCount(), 0)
+        self.failIf(index.has_doc(1))
 
-    def test_apply_and(self):
-        self._populate_index()
-        self._apply_and(('cmf', 'zope3'), self.IFSet([1]))
-        self._apply_and(('cmf', 'zope'),  self.IFSet([1]))
-        self._apply_and(('cmf', 'zope4'), self.IFSet())
-        self._apply_and(('zope', 'ZOPE'), self.IFSet([1, 3]))
+    def test_unindex_w_residue(self):
+        index = self._makeOne()
+        index.index_doc(1, ('albatross', ))
+        index.index_doc(2, ('albatross', 'cormorant'))
+        index.unindex_doc(1)
+        self.assertEqual(index.documentCount(), 1)
+        self.assertEqual(index.wordCount(), 2)
+        self.failIf(index.has_doc(1))
 
-    def test_apply_or(self):
-        self._populate_index()
-        self._apply_or(('cmf', 'zope3'), self.IFSet([1, 5]))
-        self._apply_or(('cmf', 'zope'),  self.IFSet([1, 3, 5]))
-        self._apply_or(('cmf', 'zope4'), self.IFSet([1, 5]))
-        self._apply_or(('zope', 'ZOPE'), self.IFSet([1,3]))
+    def test_hasdoc(self):
+        index = self._makeOne()
+        self._populate(index)
+        self.assertEqual(index.has_doc(1), 1)
+        self.assertEqual(index.has_doc(2), 1)
+        self.assertEqual(index.has_doc(3), 1)
+        self.assertEqual(index.has_doc(4), 0)
+        self.assertEqual(index.has_doc(5), 1)
+        self.assertEqual(index.has_doc(6), 0)
 
-    def test_index_input(self):
-        self.assertRaises(
-            TypeError, self.index.index_doc, 1, "non-sequence-string")
+    def test_search_bad_operator(self):
+        index = self._makeOne()
+        self.assertRaises(TypeError, index.search, 'whatever', 'maybe')
 
 
-class KeywordIndexTest64(KeywordIndexTest):
+class KeywordIndexTests32(_KeywordIndexTestsBase,
+                          _ThirtyTwoBitBase,
+                          _TestCaseBase,
+                          unittest.TestCase):
+    pass
 
-    from BTrees.LFBTree import LFSet as IFSet
+class CaseInsensitiveKeywordIndexTests32(CaseInsensitiveKeywordIndexTestsBase,
+                                         _ThirtyTwoBitBase,
+                                         _TestCaseBase,
+                                         unittest.TestCase):
+    pass
 
-    def setUp(self):
-        self.index = CaseInsensitiveKeywordIndex(family=BTrees.family64)
+class KeywordIndexTests64(_KeywordIndexTestsBase,
+                          _SixtyFourBitBase,
+                          _TestCaseBase,
+                          unittest.TestCase):
+    pass
 
+class CaseInsensitiveKeywordIndexTests64(CaseInsensitiveKeywordIndexTestsBase,
+                                         _SixtyFourBitBase,
+                                         _TestCaseBase,
+                                         unittest.TestCase):
+    pass
 
+
+
 def test_suite():
-    return TestSuite((makeSuite(KeywordIndexTest),
-                      makeSuite(KeywordIndexTest64),
-                      ))
-
-if __name__=='__main__':
-    main(defaultTest='test_suite')
+    return unittest.TestSuite((
+        unittest.makeSuite(KeywordIndexTests32),
+        unittest.makeSuite(KeywordIndexTests64),
+        unittest.makeSuite(CaseInsensitiveKeywordIndexTests32),
+        unittest.makeSuite(CaseInsensitiveKeywordIndexTests64),
+    ))



More information about the Checkins mailing list