#93: reorganise Rerun, Diffusion, Schedule module #95
@ -165,7 +165,7 @@ class Diffusion(Rerun):
 | 
			
		||||
 | 
			
		||||
    def save_rerun(self):
 | 
			
		||||
        self.episode = self.initial.episode
 | 
			
		||||
        self.program = self.episode.program
 | 
			
		||||
        super().save_rerun()
 | 
			
		||||
 | 
			
		||||
    def save_initial(self):
 | 
			
		||||
        self.program = self.episode.program
 | 
			
		||||
 | 
			
		||||
@ -64,24 +64,6 @@ class Rerun(models.Model):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        abstract = True
 | 
			
		||||
 | 
			
		||||
    def save(self, *args, **kwargs):
 | 
			
		||||
        if self.initial is not None:
 | 
			
		||||
            self.initial = self.initial.get_initial()
 | 
			
		||||
        if self.initial == self:
 | 
			
		||||
            self.initial = None
 | 
			
		||||
 | 
			
		||||
        if self.is_rerun:
 | 
			
		||||
            self.save_rerun()
 | 
			
		||||
        else:
 | 
			
		||||
            self.save_initial()
 | 
			
		||||
        super().save(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def save_rerun(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def save_initial(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def is_initial(self):
 | 
			
		||||
        return self.initial is None
 | 
			
		||||
@ -96,7 +78,29 @@ class Rerun(models.Model):
 | 
			
		||||
 | 
			
		||||
    def clean(self):
 | 
			
		||||
        super().clean()
 | 
			
		||||
        if self.initial is not None and self.initial.start >= self.start:
 | 
			
		||||
        if (
 | 
			
		||||
            hasattr(self, "start")
 | 
			
		||||
            and self.initial is not None
 | 
			
		||||
            and self.initial.start >= self.start
 | 
			
		||||
        ):
 | 
			
		||||
            raise ValidationError(
 | 
			
		||||
                {"initial": _("rerun must happen after original")}
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
    def save_rerun(self):
 | 
			
		||||
        self.program = self.initial.program
 | 
			
		||||
 | 
			
		||||
    def save_initial(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def save(self, *args, **kwargs):
 | 
			
		||||
        if self.initial is not None:
 | 
			
		||||
            self.initial = self.initial.get_initial()
 | 
			
		||||
        if self.initial == self:
 | 
			
		||||
            self.initial = None
 | 
			
		||||
 | 
			
		||||
        if self.is_rerun:
 | 
			
		||||
            self.save_rerun()
 | 
			
		||||
        else:
 | 
			
		||||
            self.save_initial()
 | 
			
		||||
        super().save(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
@ -75,8 +75,8 @@ class Schedule(Rerun):
 | 
			
		||||
            self.time.strftime("%H:%M"),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def save_rerun(self, *args, **kwargs):
 | 
			
		||||
        self.program = self.initial.program
 | 
			
		||||
    def save_rerun(self):
 | 
			
		||||
        super().save_rerun()
 | 
			
		||||
        self.duration = self.initial.duration
 | 
			
		||||
        self.frequency = self.initial.frequency
 | 
			
		||||
 | 
			
		||||
@ -107,23 +107,6 @@ class Schedule(Rerun):
 | 
			
		||||
            .capitalize()
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    # initial cached data
 | 
			
		||||
    __initial = None
 | 
			
		||||
 | 
			
		||||
    def changed(self, fields=["date", "duration", "frequency", "timezone"]):
 | 
			
		||||
        initial = self._Schedule__initial
 | 
			
		||||
 | 
			
		||||
        if not initial:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        this = self.__dict__
 | 
			
		||||
 | 
			
		||||
        for field in fields:
 | 
			
		||||
            if initial.get(field) != this.get(field):
 | 
			
		||||
                return True
 | 
			
		||||
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def normalize(self, date):
 | 
			
		||||
        """Return a datetime set to schedule's time for the provided date,
 | 
			
		||||
        handling timezone (based on schedule's timezone)."""
 | 
			
		||||
@ -245,10 +228,3 @@ class Schedule(Rerun):
 | 
			
		||||
                end=date + duration,
 | 
			
		||||
            )
 | 
			
		||||
        return episodes.values(), diffusions.values()
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
        # TODO/FIXME: use validators?
 | 
			
		||||
        if self.initial is not None and self.date > self.date:
 | 
			
		||||
            raise ValueError("initial must be later")
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										63
									
								
								aircox/tests/conftest.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								aircox/tests/conftest.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,63 @@
 | 
			
		||||
from datetime import time, timedelta
 | 
			
		||||
import itertools
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
from model_bakery import baker
 | 
			
		||||
 | 
			
		||||
from aircox.models import Diffusion
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def stations():
 | 
			
		||||
    return baker.make("aircox.station", quantity=2)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def programs(stations):
 | 
			
		||||
    return list(
 | 
			
		||||
        itertools.chain(
 | 
			
		||||
            *(
 | 
			
		||||
                baker.make("aircox.program", quantity=3, station=station)
 | 
			
		||||
                for station in stations
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def sched_initials(programs):
 | 
			
		||||
    # use concrete class
 | 
			
		||||
    return [
 | 
			
		||||
        baker.make("aircox.schedule", program=program, time=time(16, 00))
 | 
			
		||||
        for program in programs
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def sched_reruns(initials):
 | 
			
		||||
    # use concrete class
 | 
			
		||||
    return [
 | 
			
		||||
        baker.make(
 | 
			
		||||
            "aircox.schedule",
 | 
			
		||||
            initial=initial,
 | 
			
		||||
            date=initial.date,
 | 
			
		||||
            time=(initial.start + timedelta(hours=1)).time(),
 | 
			
		||||
        )
 | 
			
		||||
        for initial in initials
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def schedules(sched_initials, sched_reruns):
 | 
			
		||||
    return sched_initials + sched_reruns
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def episodes(programs):
 | 
			
		||||
    items = []
 | 
			
		||||
    for program in programs:
 | 
			
		||||
        items += [
 | 
			
		||||
            baker.make("aircox.episode", parent=program, type=type)
 | 
			
		||||
            for type, _ in Diffusion.TYPE_CHOICES
 | 
			
		||||
        ]
 | 
			
		||||
    return items
 | 
			
		||||
							
								
								
									
										19
									
								
								aircox/tests/models/test_diffusion.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								aircox/tests/models/test_diffusion.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestDiffusionQuerySet:
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_episode_by_obj(self, episodes):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_episode_by_id(self, episodes):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_on_air(self, episodes):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_now(self, episodes):
 | 
			
		||||
        pass
 | 
			
		||||
							
								
								
									
										117
									
								
								aircox/tests/models/test_rerun.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								aircox/tests/models/test_rerun.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,117 @@
 | 
			
		||||
from datetime import timedelta
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
from django.core.exceptions import ValidationError
 | 
			
		||||
 | 
			
		||||
# we use Schedule as concrete class (Rerun is abstract)
 | 
			
		||||
from aircox.models import Schedule
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestRerunQuerySet:
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_station_by_obj(self, stations):
 | 
			
		||||
        for station in stations:
 | 
			
		||||
            queryset = (
 | 
			
		||||
                Schedule.objects.station(station)
 | 
			
		||||
                .distinct()
 | 
			
		||||
                .value_list("station", flat=True)
 | 
			
		||||
            )
 | 
			
		||||
            assert queryset.count() == 1
 | 
			
		||||
            assert queryset.first() == station
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_station_by_id(self, stations):
 | 
			
		||||
        for station in stations:
 | 
			
		||||
            queryset = (
 | 
			
		||||
                Schedule.objects.station(id=station.pk)
 | 
			
		||||
                .distinct()
 | 
			
		||||
                .value_list("station", flat=True)
 | 
			
		||||
            )
 | 
			
		||||
            assert queryset.count() == 1
 | 
			
		||||
            assert queryset.first() == station
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_program_by_obj(self, programs):
 | 
			
		||||
        for program in programs:
 | 
			
		||||
            queryset = (
 | 
			
		||||
                Schedule.objects.program(program)
 | 
			
		||||
                .distinct()
 | 
			
		||||
                .value_list("program", flat=True)
 | 
			
		||||
            )
 | 
			
		||||
            assert queryset.count() == 1
 | 
			
		||||
            assert queryset.first() == program
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_program_by_id(self, programs):
 | 
			
		||||
        for program in programs:
 | 
			
		||||
            queryset = (
 | 
			
		||||
                Schedule.objects.program(id=program.pk)
 | 
			
		||||
                .distinct()
 | 
			
		||||
                .value_list("program", flat=True)
 | 
			
		||||
            )
 | 
			
		||||
            assert queryset.count() == 1
 | 
			
		||||
            assert queryset.first() == program
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_rerun(self, sched_reruns):
 | 
			
		||||
        queryset = Schedule.objects.rerun().value_list("initial", flat=True)
 | 
			
		||||
        assert None not in queryset
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_initial(self, sched_initials):
 | 
			
		||||
        queryset = (
 | 
			
		||||
            Schedule.objects.rerun()
 | 
			
		||||
            .distinct()
 | 
			
		||||
            .value_list("initial", flat=True)
 | 
			
		||||
        )
 | 
			
		||||
        assert queryset.count() == 1
 | 
			
		||||
        assert queryset.first() is None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestRerun:
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_is_initial_true(self, sched_initials):
 | 
			
		||||
        assert all(r.is_initial for r in sched_initials)
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_is_initial_false(self, sched_reruns):
 | 
			
		||||
        assert all(not r.is_initial for r in sched_reruns)
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_is_rerun_true(self, sched_reruns):
 | 
			
		||||
        assert all(r.is_rerun for r in sched_reruns)
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_is_rerun_false(self, sched_initials):
 | 
			
		||||
        assert all(not r.is_rerun for r in sched_initials)
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_get_initial_of_initials(self, sched_initials):
 | 
			
		||||
        assert all(r.get_initial() is r for r in sched_initials)
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_get_initial_of_reruns(self, sched_reruns):
 | 
			
		||||
        assert all(r.get_initial() is r.initial for r in sched_reruns)
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_clean_success(self, sched_reruns):
 | 
			
		||||
        for rerun in sched_reruns:
 | 
			
		||||
            rerun.clean()
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_clean_fails(self, sched_reruns):
 | 
			
		||||
        for rerun in sched_reruns:
 | 
			
		||||
            rerun.time = (rerun.initial.start - timedelta(hours=2)).time()
 | 
			
		||||
            with pytest.raises(ValidationError):
 | 
			
		||||
                rerun.clean()
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_save_rerun(self, sched_reruns):
 | 
			
		||||
        for rerun in sched_reruns:
 | 
			
		||||
            rerun.program = None
 | 
			
		||||
            rerun.save_rerun()
 | 
			
		||||
            assert rerun.program == rerun.initial.program
 | 
			
		||||
 | 
			
		||||
    # TODO: save()
 | 
			
		||||
    # save_initial is empty, thus not tested
 | 
			
		||||
							
								
								
									
										74
									
								
								aircox/tests/models/test_schedule.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								aircox/tests/models/test_schedule.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
from aircox import utils
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestSchedule:
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_save_rerun(self, sched_reruns):
 | 
			
		||||
        for schedule in sched_reruns:
 | 
			
		||||
            schedule.duration = None
 | 
			
		||||
            schedule.frequency = None
 | 
			
		||||
            schedule.save_rerun()
 | 
			
		||||
            assert schedule.program == schedule.initial.program
 | 
			
		||||
            assert schedule.duration == schedule.initial.duration
 | 
			
		||||
            assert schedule.frequency == schedule.initial.frequency
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_tz(self, schedules):
 | 
			
		||||
        for schedule in schedules:
 | 
			
		||||
            assert schedule.timezone == schedule.tz.zone
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_start(self, schedules):
 | 
			
		||||
        for schedule in schedules:
 | 
			
		||||
            assert schedule.start.date() == schedule.date
 | 
			
		||||
            assert schedule.start.time() == schedule.time
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_end(self, schedules):
 | 
			
		||||
        for schedule in schedules:
 | 
			
		||||
            delta = utils.to_timedelta(schedule.duration)
 | 
			
		||||
            assert schedule.end - schedule.start == delta
 | 
			
		||||
 | 
			
		||||
    # def test_get_frequency_verbose(self):
 | 
			
		||||
    #    pass
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_normalize(self, schedules):
 | 
			
		||||
        for schedule in schedules:
 | 
			
		||||
            dt = datetime.combine(schedule.date, schedule.time)
 | 
			
		||||
            assert schedule.normalize(dt).tzinfo.zone == schedule.timezone.zone
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_dates_of_month_ponctual(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_dates_of_month_n_day_of_month(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_dates_of_month_first_and_third(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_dates_of_month_second_and_fourth(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_dates_of_month_every(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_dates_of_month_one_on_two(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test__exclude_existing_date(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.django_db
 | 
			
		||||
    def test_diffusions_of_month(self):
 | 
			
		||||
        pass
 | 
			
		||||
@ -1,2 +1,3 @@
 | 
			
		||||
pytest~=7.2
 | 
			
		||||
pytest-django~=4.5
 | 
			
		||||
model_bakery~=1.10
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user