from datetime import date from django.contrib.auth import get_user_model from django.test import TestCase from tasks.models import Task User = get_user_model() class CustomRecurrenceTests(TestCase): """Tests for Task.calculate_next_due_date() with custom RRULE patterns.""" def setUp(self): self.user = User.objects.create_user( username='testuser', email='testuser@example.com', password='testpass123', ) def make_task(self, **kwargs): defaults = { 'user': self.user, 'title': 'Test task', 'recurrence': 'custom', } defaults.update(kwargs) return Task.objects.create(**defaults) def test_every_wednesday(self): # 2026-01-07 is a Wednesday task = self.make_task(due_date=date(2026, 1, 7), recurrence_rule='FREQ=WEEKLY;BYDAY=WE') self.assertEqual(task.calculate_next_due_date(), date(2026, 1, 14)) def test_every_other_wednesday(self): task = self.make_task(due_date=date(2026, 1, 7), recurrence_rule='FREQ=WEEKLY;INTERVAL=2;BYDAY=WE') self.assertEqual(task.calculate_next_due_date(), date(2026, 1, 21)) def test_every_second_tuesday(self): # 2026-01-13 is the second Tuesday of January 2026 task = self.make_task(due_date=date(2026, 1, 13), recurrence_rule='FREQ=MONTHLY;BYDAY=2TU') self.assertEqual(task.calculate_next_due_date(), date(2026, 2, 10)) def test_every_15th(self): task = self.make_task(due_date=date(2026, 1, 15), recurrence_rule='FREQ=MONTHLY;BYMONTHDAY=15') self.assertEqual(task.calculate_next_due_date(), date(2026, 2, 15)) def test_respects_recurrence_end_date(self): task = self.make_task( due_date=date(2026, 1, 7), recurrence_rule='FREQ=WEEKLY;BYDAY=WE', recurrence_end_date=date(2026, 1, 10), ) self.assertIsNone(task.calculate_next_due_date()) def test_malformed_rule_returns_none(self): task = self.make_task(due_date=date(2026, 1, 7), recurrence_rule='not a valid rrule') self.assertIsNone(task.calculate_next_due_date()) def test_create_next_recurrence(self): task = self.make_task(due_date=date(2026, 1, 15), recurrence_rule='FREQ=MONTHLY;BYMONTHDAY=15') new_task = task.create_next_recurrence() self.assertIsNotNone(new_task) self.assertEqual(new_task.due_date, date(2026, 2, 15)) self.assertEqual(new_task.recurrence_rule, 'FREQ=MONTHLY;BYMONTHDAY=15') self.assertEqual(new_task.status, 'pending') def test_parsed_custom_recurrence_weekly(self): task = self.make_task(recurrence_rule='FREQ=WEEKLY;INTERVAL=2;BYDAY=WE') parsed = task.parsed_custom_recurrence self.assertEqual(parsed['freq'], 'weekly') self.assertEqual(parsed['interval'], 2) self.assertEqual(parsed['byweekday'], ['WE']) def test_parsed_custom_recurrence_monthly_nth(self): task = self.make_task(recurrence_rule='FREQ=MONTHLY;BYDAY=2TU') parsed = task.parsed_custom_recurrence self.assertEqual(parsed['freq'], 'monthly') self.assertEqual(parsed['monthly_mode'], 'nth') self.assertEqual(parsed['nth_ordinal'], 2) self.assertEqual(parsed['nth_weekday'], 'TU') def test_parsed_custom_recurrence_blank(self): task = self.make_task(recurrence_rule='') parsed = task.parsed_custom_recurrence self.assertIsNone(parsed['freq']) self.assertEqual(parsed['byweekday'], [])