Back to index

plone3  3.1.7
test_DateC.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
00004 #
00005 # This software is subject to the provisions of the Zope Public License,
00006 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
00007 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00008 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00009 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00010 # FOR A PARTICULAR PURPOSE.
00011 #
00012 ##############################################################################
00013 """ Unit tests for DateCriteria module.
00014 
00015 $Id: test_DateC.py 75625 2007-05-08 15:56:26Z tseaver $
00016 """
00017 
00018 import unittest
00019 from Testing import ZopeTestCase
00020 
00021 from DateTime.DateTime import DateTime
00022 from zope.app.component.hooks import setSite
00023 
00024 from Products.CMFCore.tests.base.dummy import DummyContent
00025 from Products.CMFDefault.testing import FunctionalLayer
00026 from Products.CMFTopic.Topic import Topic
00027 
00028 from common import CriterionTestCase
00029 
00030 def _replace_DC__as_of(new_callable):
00031     from Products.CMFTopic import DateCriteria
00032     old_value = DateCriteria._as_of
00033     DateCriteria._as_of = new_callable
00034     return old_value
00035 
00036 
00037 class FriendlyDateCriterionTests(CriterionTestCase):
00038 
00039     lessThanFiveDaysOld = { 'value': 5
00040                           , 'operation': 'max'
00041                           , 'daterange': 'old'
00042                           }
00043 
00044     lessThanOneMonthAhead = { 'value': 31
00045                             , 'operation': 'max'
00046                             , 'daterange': 'ahead'
00047                             }
00048     today = { 'value': 0
00049             , 'operation': 'within_day'
00050             , 'daterange': 'ahead'
00051             }
00052 
00053     def setUp(self):
00054         self._now = DateTime()
00055         self._old_as_of = _replace_DC__as_of(lambda: self._now)
00056 
00057     def tearDown(self):
00058         _replace_DC__as_of(self._old_as_of)
00059 
00060     def _getTargetClass(self):
00061         from Products.CMFTopic.DateCriteria import FriendlyDateCriterion
00062 
00063         return FriendlyDateCriterion
00064 
00065     def test_Empty( self ):
00066         friendly = self._makeOne('foo', 'foofield')
00067 
00068         self.assertEqual( friendly.getId(), 'foo' )
00069         self.assertEqual( friendly.field, 'foofield' )
00070         self.assertEqual( friendly.value, None )
00071         self.assertEqual( friendly.operation, 'min' )
00072         self.assertEqual( friendly.daterange, 'old' )
00073         self.assertEqual( len( friendly.getCriteriaItems() ), 0 )
00074 
00075     def test_ListOfDefaultDates( self ):
00076         friendly = self._makeOne('foo', 'foofield')
00077 
00078         d = friendly.defaultDateOptions()
00079         self.assertEqual( d[0][0], 0 )
00080         self.assertEqual( d[1][0], 1 )
00081         self.assertEqual( d[2][0], 2 )
00082 
00083     def test_Clear( self ):
00084         friendly = self._makeOne('foo', 'foofield')
00085 
00086         friendly.edit( value=None )
00087         self.assertEqual( friendly.value, None )
00088         self.assertEqual( friendly.operation, 'min' )
00089         self.assertEqual( friendly.daterange, 'old' )
00090 
00091     def test_Basic( self ):
00092         friendly = self._makeOne('foo', 'foofield')
00093 
00094         friendly.apply( self.lessThanFiveDaysOld )
00095         self.assertEqual( friendly.value, 5 )
00096         self.assertEqual( friendly.operation, 'max' )
00097         self.assertEqual( friendly.daterange, 'old' )
00098 
00099     def test_BadInput( self ):
00100         friendly = self._makeOne('foo', 'foofield')
00101 
00102         # Bogus value
00103         self.assertRaises( ValueError, friendly.edit, 'blah' )
00104 
00105         # Bogus operation
00106         self.assertRaises( ValueError, friendly.edit, 4, 'min:max', 'old' )
00107 
00108         # Bogus daterange
00109         self.assertRaises( ValueError, friendly.edit, 4, 'max', 'new' )
00110 
00111     def test_StringAsValue( self ):
00112         friendly = self._makeOne('foo', 'foofield')
00113 
00114         friendly.edit( '4' )
00115         self.assertEqual( friendly.value, 4 )
00116 
00117         friendly.edit( '-4' )
00118         self.assertEqual( friendly.value, -4 )
00119 
00120         friendly.edit( '' )
00121         self.assertEqual( friendly.value, None )
00122 
00123     def test_Today( self ):
00124         friendly = self._makeOne('foo', 'foofield')
00125 
00126         friendly.apply( self.today )
00127         self.assertEqual( friendly.daterange, 'ahead' )
00128 
00129         now = DateTime()
00130 
00131         result = friendly.getCriteriaItems()
00132         self.assertEqual( len(result), 1 )
00133         self.assertEqual( result[0][0], 'foofield' )
00134         self.assertEqual( result[0][1]['query'],
00135                           ( now.earliestTime(), now.latestTime() ) )
00136         self.assertEqual( result[0][1]['range'], 'min:max' )
00137 
00138     def test_FiveDaysOld( self ):
00139         # This should create a query
00140         friendly = self._makeOne('foo', 'foofield')
00141 
00142         friendly.apply( self.lessThanFiveDaysOld )
00143         self.assertEqual( friendly.daterange, 'old' )
00144 
00145         result = friendly.getCriteriaItems()
00146         self.assertEqual( len(result), 1 )
00147         self.assertEqual( result[0][0], 'foofield' )
00148         expect_earliest, expect_now = result[0][1]['query']
00149         self.assertEqual( expect_earliest.Date(),
00150                           ( DateTime() - 5 ).Date() )
00151         self.assertEqual( result[0][1]['range'], 'min:max' )
00152 
00153     def test_OneMonthAhead( self ):
00154         friendly = self._makeOne('foo', 'foofield')
00155 
00156         friendly.apply( self.lessThanOneMonthAhead )
00157         self.assertEqual( friendly.daterange, 'ahead' )
00158 
00159         result = friendly.getCriteriaItems()
00160         expect_now, expect_latest = result[0][1]['query']
00161         self.assertEqual( expect_latest.Date(), ( DateTime() + 31 ).Date() )
00162         self.assertEqual( expect_now.Date(), DateTime().Date() )
00163         self.assertEqual( result[0][1]['range'], 'min:max' )
00164 
00165 
00166 class FriendlyDateCriterionFunctionalTests(ZopeTestCase.FunctionalTestCase):
00167 
00168     layer = FunctionalLayer
00169 
00170     # Test the date criterion using a "real CMF" with catalog etc.
00171     selectable_diffs = [0, 1, 2, 5, 7, 14, 31, 93, 186, 365, 730]
00172     nonzero_diffs = [1, 2, 5, 7, 14, 31, 93, 186, 365, 730]
00173     day_diffs = [-730, -365, -186, -93, -31, -14, -7, -5, -2, -1]
00174     day_diffs.extend(selectable_diffs)
00175 
00176     def afterSetUp(self):
00177         setSite(self.app.site)
00178         self.site = self.app.site
00179         self.site._setObject( 'topic', Topic('topic') )
00180         self.topic = self.site.topic
00181         self.topic.addCriterion('modified', 'Friendly Date Criterion')
00182         self.topic.addCriterion('portal_type', 'String Criterion')
00183         type_crit = self.topic.getCriterion('portal_type')
00184         type_crit.edit(value='Dummy Content')
00185         self.criterion = self.topic.getCriterion('modified')
00186         self.now = DateTime()
00187         self._old_as_of = _replace_DC__as_of(lambda: self.now)
00188 
00189         for i in self.day_diffs:
00190             dummy_id = 'dummy%i' % i
00191             self.site._setObject( dummy_id, DummyContent( id=dummy_id
00192                                                         , catalog=1
00193                                                         ) )
00194             dummy_ob = getattr(self.site, dummy_id)
00195             dummy_ob.modified_date = self.now + i
00196             dummy_ob.reindexObject()
00197 
00198     def beforeTearDown(self):
00199         _replace_DC__as_of(self._old_as_of)
00200 
00201     def test_Harness(self):
00202         # Make sure the test harness is set up OK
00203         ob_values = self.site.objectValues(['Dummy'])
00204         self.assertEqual(len(ob_values), len(self.day_diffs))
00205 
00206         catalog_results = self.site.portal_catalog(portal_type='Dummy Content')
00207         self.assertEqual(len(catalog_results), len(self.day_diffs))
00208 
00209     def test_WithinDayAgo(self):
00210         # What items were modified "On the day X days ago"
00211         for diff in self.selectable_diffs:
00212             self.criterion.edit( value=abs(diff)
00213                                , operation='within_day'
00214                                , daterange='old'
00215                                )
00216             results = self.topic.queryCatalog()
00217 
00218             # There is only one item with an modified date for this day
00219             self.assertEquals(len(results), 1)
00220             self.assertEquals( results[0].modified.Date()
00221                              , (self.now-diff).Date()
00222                              )
00223 
00224     def test_WithinDayAhead(self):
00225         # What items were modified "On the day X days ahead"
00226         for diff in self.selectable_diffs:
00227             self.criterion.edit( value=abs(diff)
00228                                , operation='within_day'
00229                                , daterange='ahead'
00230                                )
00231             results = self.topic.queryCatalog()
00232 
00233             # There is only one item with an modified date for this day
00234             self.assertEquals(len(results), 1)
00235             self.assertEquals( results[0].modified.Date()
00236                              , (self.now+diff).Date()
00237                              )
00238 
00239     def test_MoreThanDaysAgo(self):
00240         # What items are modified "More than X days ago"
00241         resultset_size = len(self.nonzero_diffs)
00242 
00243         for diff in self.nonzero_diffs:
00244             self.criterion.edit( value=diff
00245                                , operation='min'
00246                                , daterange='old'
00247                                )
00248             results = self.topic.queryCatalog()
00249 
00250             # As we move up in our date difference range, we must find as
00251             # many items as we have "modified" values <= the current value
00252             # in our sequence of user-selectable time differences. As we
00253             # increase the "value", we actually move backwards in time, so
00254             # the expected count of results *decreases*
00255             self.assertEquals(len(results), resultset_size)
00256             for brain in results:
00257                 self.failUnless(brain.modified <= self.now-diff)
00258 
00259             resultset_size -= 1
00260 
00261     def test_MoreThanZeroDaysAgo(self):
00262         # What items are modified "More than 0 days ago"?
00263         # This represents a special case. The "special munging"
00264         # that corrects the query terms to what a human would expect
00265         # are not applied and the search is a simple
00266         # "everything in the future" search.
00267         resultset_size = len(self.selectable_diffs)
00268         self.criterion.edit( value=0
00269                            , operation='min'
00270                            , daterange='old'
00271                            )
00272         results = self.topic.queryCatalog()
00273         self.assertEquals(len(results), resultset_size)
00274         for brain in results:
00275             self.failUnless(brain.modified >= self.now)
00276 
00277     def test_MoreThanDaysAhead(self):
00278         # What items are modified "More than X days ahead"
00279         resultset_size = len(self.nonzero_diffs)
00280 
00281         for diff in self.nonzero_diffs:
00282             self.criterion.edit( value=diff
00283                                , operation='min'
00284                                , daterange='ahead'
00285                                )
00286             results = self.topic.queryCatalog()
00287 
00288             # As we move up in our date difference range, we must find as
00289             # many items as we have "modified" values >= the current value
00290             # in our sequence of user-selectable time differences. As we
00291             # increase the "value", we actually move formward in time, so
00292             # the expected count of results *decreases*
00293             self.assertEquals(len(results), resultset_size)
00294             for brain in results:
00295                 self.failUnless(brain.modified >= self.now+diff)
00296 
00297             resultset_size -= 1
00298 
00299     def test_MoreThanZeroDaysAhead(self):
00300         # What items are modified "More than 0 days ahead"?
00301         # This represents a special case. The "special munging"
00302         # that corrects the query terms to what a human would expect
00303         # are not applied and the search is a simple
00304         # "everything in the future" search.
00305         resultset_size = len(self.selectable_diffs)
00306         self.criterion.edit( value=0
00307                            , operation='min'
00308                            , daterange='ahead'
00309                            )
00310         results = self.topic.queryCatalog()
00311         self.assertEquals(len(results), resultset_size)
00312         for brain in results:
00313             self.failUnless(brain.modified >= self.now)
00314 
00315     def test_LessThanDaysAgo(self):
00316         # What items are modified "Less than X days ago"
00317         resultset_size = 2
00318 
00319         for diff in self.nonzero_diffs:
00320             self.criterion.edit( value=diff
00321                                , operation='max'
00322                                , daterange='old'
00323                                )
00324             results = self.topic.queryCatalog()
00325 
00326             # With this query we are looking for items modified "less than
00327             # X days ago", meaning between the given time and now. As we move
00328             # through the selectable day values we increase the range to
00329             # search through and thus increase the resultset size.
00330             self.assertEquals(len(results), resultset_size)
00331             for brain in results:
00332                 self.failUnless(self.now-diff <= brain.modified <= self.now)
00333 
00334             resultset_size += 1
00335 
00336     def test_LessThanZeroDaysAgo(self):
00337         # What items are modified "Less than 0 days ago"?
00338         # This represents a special case. The "special munging"
00339         # that corrects the query terms to what a human would expect
00340         # are not applied and the search is a simple
00341         # "everything in the past" search.
00342         resultset_size = len(self.selectable_diffs)
00343         self.criterion.edit( value=0
00344                            , operation='max'
00345                            , daterange='old'
00346                            )
00347         results = self.topic.queryCatalog()
00348         self.assertEquals(len(results), resultset_size)
00349         for brain in results:
00350             self.failUnless(brain.modified <= self.now)
00351 
00352     def test_LessThanDaysAhead(self):
00353         # What items are modified "Less than X days ahead"
00354         resultset_size = 2
00355 
00356         for diff in self.nonzero_diffs:
00357             self.criterion.edit( value=diff
00358                                , operation='max'
00359                                , daterange='ahead'
00360                                )
00361             results = self.topic.queryCatalog()
00362 
00363             # With this query we are looking for items modified "less than
00364             # X days ahead", meaning between now and the given time. As we move
00365             # through the selectable day values we increase the range to
00366             # search through and thus increase the resultset size.
00367             self.assertEquals(len(results), resultset_size)
00368             for brain in results:
00369                 self.failUnless(self.now+diff >= brain.modified >= self.now)
00370 
00371             resultset_size += 1
00372 
00373     def test_LessThanZeroDaysAhead(self):
00374         # What items are modified "Less than 0 days ahead"?
00375         # This represents a special case. The "special munging"
00376         # that corrects the query terms to what a human would expect
00377         # are not applied and the search is a simple
00378         # "everything in the past" search.
00379         resultset_size = len(self.selectable_diffs)
00380         self.criterion.edit( value=0
00381                            , operation='max'
00382                            , daterange='ahead'
00383                            )
00384         results = self.topic.queryCatalog()
00385         self.assertEquals(len(results), resultset_size)
00386         for brain in results:
00387             self.failUnless(brain.modified <= self.now)
00388 
00389 
00390 def test_suite():
00391     return unittest.TestSuite((
00392         unittest.makeSuite(FriendlyDateCriterionTests),
00393         unittest.makeSuite(FriendlyDateCriterionFunctionalTests),
00394         ))
00395 
00396 if __name__ == '__main__':
00397     from Products.CMFCore.testing import run
00398     run(test_suite())