Commits

Caleb Smith  committed ec8ecdf

Added more tests to check_entries command.

  • Participants
  • Parent commits 02ca0cc

Comments (0)

Files changed (3)

File timepiece/management/commands/check_entries.py

                     user = entry_a.user
             if entry_a.is_overlapping():
                 user_total_overlaps += 1
-                self.show_overlap(entry_a)
-                
+                if verbosity >= 1:
+                    self.show_overlap(entry_a)                
 #Removed until check_overlap is fixed
 #            for index_b in range(index_a, len(entries)):
 #                entry_b = entries[index_b]
-#                if entry_a.is_overlapping():
-#                if entry_a.check_overlap(entry_b):
-#                    user_total_overlaps += 1            
+#                if entry_a.check_overlap_pause(entry_b):
+#                    user_total_overlaps += 1
 #                    self.show_overlap(entry_a, entry_b)
                     
         if user_total_overlaps and user and verbosity >= 1:

File timepiece/models.py

     objects = EntryManager()
     worked = EntryWorkedManager()
 
-    def check_overlap(self, entry_b):
+    def check_overlap(self, entry_b, **kwargs):
         """
         Given two entries, return True if they overlap, otherwise return False
         """
+        pause = kwargs.get('pause', False)
         entry_a = self
         #if entries are open, consider them to be closed right now
         if not entry_a.end_time:
         if not entry_b.end_time:
             entry_b.end_time = datetime.datetime.now()
         #Check the two entries against each other        
-        start_is_inside = entry_a.start_time > entry_b.start_time \
+        start_inside = entry_a.start_time > entry_b.start_time \
             and entry_a.start_time < entry_b.end_time 
-        end_is_inside = entry_a.end_time > entry_b.start_time \
+        end_inside = entry_a.end_time > entry_b.start_time \
+            and entry_a.end_time < entry_b.end_time
+        a_is_inside = entry_a.start_time > entry_b.start_time \
             and entry_a.end_time < entry_b.end_time        
         b_is_inside = entry_a.start_time < entry_b.start_time \
             and entry_a.end_time > entry_b.end_time
-        overlap = start_is_inside or end_is_inside or b_is_inside
-        return overlap
+        overlap = start_inside or end_inside or a_is_inside or b_is_inside
+        if not pause:
+            return overlap
+        else:
+            if overlap:
+                max_end = max(entry_a.end_time, entry_b.end_time)
+                min_start = min(entry_a.start_time, entry_b.start_time)
+                diff = max_end - min_start
+                diff = diff.seconds + diff.days * 86400
+                total = entry_a.get_seconds() + entry_b.get_seconds()
+    #            paused = entry_a.seconds_paused + entry_b.seconds_paused
+    #            if total > diff or paused < diff - total:
+                if total > diff:
+                    return True
+            return False
 
     def is_overlapping(self):
         if self.start_time and self.end_time:

File timepiece/tests/management.py

 import datetime
-import re
 from StringIO import StringIO
 from dateutil.relativedelta import relativedelta
 
 from django.core.urlresolvers import reverse
 from django.contrib.auth.models import User, Permission
 from django.core.exceptions import ValidationError
-from django.core.management import call_command
 
 from timepiece.tests.base import TimepieceDataTestCase
 
         self.user2.first_name = 'first2'
         self.user2.last_name = 'last2'
         self.user2.save()
+        self.all_users = [self.user, self.user2, self.superuser]
+        #Create a valid entry for all users on every day since 60 days ago
+        self.make_entry_bulk(self.all_users, 60)
 
-        #Create a list of valid entries.
-        #Test cases may create overlapping entries later
-        for user in [self.user, self.user2]:
-            self.default_data.update({
-                'user': user,
-            })
-            #Range uses 1 so that good_start/good_end use today as valid times.
-            for day in range(1, 80):
-                self.default_data.update({
-                    'start_time': datetime.datetime.now() - datetime.timedelta(days=day, hours=8),
-                    'end_time': datetime.datetime.now() - datetime.timedelta(days=day,),
-                })
-                self.create_entry(self.default_data)        
-#        print timepiece.Entry.objects.all()
+    #helper functions           
+    def make_entry(self, **kwargs):
+        """
+        Make a valid or invalid entry
 
-    #helper functions
-    buffer_dict = {}
-    def check(self, *args, **kwargs):
-        output = err = StringIO()
-        call_command('check_entries', *args, stdout=output, stderr=err, **kwargs)
-        output.seek(0)
-        err.seek(0)
-        out = output.read()
-        overlap = re.findall('Entry.*', out)
-        out_list = out.split('\n')
-        err_list = err.read().split('\n')
-        self.buffer_dict = {
-            'out': out_list,
-            'err': err_list,
-            'overlap': overlap,
-        }
-        return self.buffer_dict
-
-    def get_output(self, dict_in=buffer_dict):
-        return dict_in.get('out', [])
-    
-    def get_err(self, dict_in=buffer_dict):
-        return dict_in.get('err', [])
-
-    def show_output(self, dict_in=buffer_dict):
-        for string in self.get_output(dict_in):
-            print string
-
-    def show_err(self, dict_in=buffer_dict):
-        for string in self.get_err(dict_in):
-            print string
-
-    def make_entry(self, **kwargs):
+        make_entry(**kwargs) 
+        **kwargs can include: start_time, end_time, valid    
+        Without any kwargs, make_entry makes a valid entry. (first time called)
+        With valid=False, makes an invalid entry
+        start_time and end_time can be specified.
+        If start_time is used without end_time, end_time is 10 mintues later
+        """
         valid = kwargs.get('valid', True)
         if valid:
             default_start = self.good_start
             default_end = self.bad_end
         user = kwargs.get('user', self.user)
         start = kwargs.get('start_time', default_start)
-        end = kwargs.get('end_time', default_end)
+        if 'end_time' in kwargs:
+            end = kwargs.get('end_time', default_end)
+        else:
+            if 'start_time' in kwargs:
+                end = start + relativedelta(minutes=10)
+            else:
+                end = default_end
         data = self.default_data
         data.update({
             'user': user,
         })
         self.create_entry(data)
 
+    def make_entry_bulk(self, users, days, *args, **kwargs):
+        """
+        Create entries for users listed, from n days ago (but not today)
+        
+        make_entry_bulk(users_list, num_days)
+        """
+        #Test cases may create overlapping entries later
+        for user in users:
+            self.default_data.update({'user': user})
+            #Range uses 1 so that good_start/good_end use today as valid times.
+            for day in range(1, days + 1):
+                self.default_data.update({
+                    'start_time': datetime.datetime.now() - \
+                        datetime.timedelta(days=day, minutes=1),
+                    'end_time': datetime.datetime.now() - \
+                        datetime.timedelta(days=day,)
+                })
+                self.create_entry(self.default_data)
+
     #tests
     def testFindStart(self):
+        """
+        With various kwargs, find_start should return the correct date
+        """
         #Establish some datetimes
         now = datetime.datetime.now()
         today = now - relativedelta(
         self.assertEqual(start_of_year, thisyear)
 
     def testFindPeople(self):
+        """
+        With args, find_people should search and return those user objects
+        Without args, find_people should return all user objects
+        """
         #Find one person by icontains first or last name, return all if no args
         people1 = check_entries.Command().find_people('firsT1')
         people2 = check_entries.Command().find_people('LasT2')
         self.assertEqual(all_3, self.superuser)
 
     def testFindEntries(self):
+        """
+        Given a list of users and a starting point, entries should generate a
+        list of all entries for each user from that time until now.
+        """
         start = check_entries.Command().find_start()
         all_people = check_entries.Command().find_people()
         entries = check_entries.Command().find_entries(all_people, start)
-        self.make_entry(valid=False)
-        all_overlaps = 0
+        #Determine the number of days checked
+        today = datetime.datetime.now() - \
+            relativedelta(hour=0, minute=0, second=0, microsecond=0)
+        diff = today - start
+        days_checked = diff.days
+        total_entries = 0
         while True:
             try:
                 person_entries = entries.next()
+                for entry in person_entries:
+                    total_entries += 1
             except StopIteration:
-                print all_overlaps
+                #Verify that every entry from the start point was returned
+                self.assertEqual(total_entries, days_checked * len(self.all_users))
                 return
-            else:
-                user_total_overlaps = check_entries.Command().check_entry(
-                    person_entries, verbosity=2)
-                all_overlaps += user_total_overlaps
+
+    def testCheckEntry(self):
+        """
+        Given lists of entries from users, check_entry should return all 
+        overlapping entries.
+        """
+        start = check_entries.Command().find_start()
+        all_people = check_entries.Command().find_people()
+        entries = check_entries.Command().find_entries(all_people, start)
+        total_overlaps = 0
+        #make some bad entries
+        num_days = 5
+        self.make_entry_bulk(self.all_users, num_days)
+        while True:
+            try:
+                person_entries = entries.next()
+                user_overlaps = check_entries.Command().check_entry(
+                    person_entries, verbosity=0)
+                total_overlaps += user_overlaps
+            except StopIteration:
+                self.assertEqual(
+                    total_overlaps, num_days * len(self.all_users) * 2)
+                return
 
     def testCheckOverlap(self):
+        """
+        With every possbile type of overlap, check_overlap should return True
+        With valid entries, check_overlap should return False
+        """
         #define start and end times relative to a valid entry
-        a_start_before = self.good_start - datetime.timedelta(minutes=5)
-        a_start_inside = self.good_start + datetime.timedelta(minutes=5)
-        a_end_inside = self.good_start + datetime.timedelta(minutes=5)
-        a_end_after = self.good_end + datetime.timedelta(minutes=5)
+        a_start_before = self.good_start - datetime.timedelta(minutes=2)
+        a_start_inside = self.good_end - datetime.timedelta(minutes=2)
+        a_end_inside = self.good_start + datetime.timedelta(minutes=2)
+        a_end_after = self.good_end + datetime.timedelta(minutes=2)
         #Create a valid entry for today
         self.make_entry(valid=True)
 
         #Create a bad entry starting inside the valid one
         self.make_entry(start_time=a_start_inside, end_time=a_end_after)
         #Create a bad entry ending inside the valid one
+        self.make_entry(start_time=a_start_before, end_time=a_end_inside)
+        #Create a bad entry that starts and ends inside a valid one
+        self.make_entry(start_time=a_start_inside, end_time=a_end_inside)
+        #Bump the day back one so this entry only conflicts with a valid entry
+        a_start_before -= relativedelta(days=1)
+        a_end_after -= relativedelta(days=1)
+        #Create a bad entry that starts and ends outside a valid one
         self.make_entry(start_time=a_start_before, end_time=a_end_after)
-        #Create a bad entry that starts and ends outside a valid one
-        self.make_entry(start_time=a_start_inside, end_time=a_end_inside)
-        #Create a bad entry that starts and ends inside a valid one
-        self.make_entry(start_time=a_start_before, end_time=a_end_after)
-
         entries = timepiece.Entry.objects.filter(user=self.user)
         user_total_overlaps = 0
         for index_a, entry_a in enumerate(entries):
             for index_b in range(index_a, len(entries)):
                 entry_b = entries[index_b]
-                if entry_a.check_overlap(entry_b):                    
+                if entry_a.check_overlap(entry_b):
                     user_total_overlaps += 1
-#                    print 'Conflict with %s and %s' % (entry_a, entry_b)
-
-#                    check_entries.Command().show_overlap(entry_a, entry_b)
-#                    self.show_overlap(entry_a, entry_b)
-
-        
-#    def testAllEntries(self):
-#        self.default_data.update({
-#            'start_time': datetime.datetime.now() - datetime.timedelta(days=0, hours=8),
-#            'end_time': datetime.datetime.now() - datetime.timedelta(days=0,),
-#        })
-#        self.create_entry(self.default_data)
-#        bars = check_1_2 = self.check('first1', 'first2', verbosity=2)
-#        self.show_output(bars)
-#        print bars['overlap']
+        self.assertEqual(user_total_overlaps, 4)