parental-control/tests/test_app.py
2024-11-19 20:29:33 +01:00

390 lines
14 KiB
Python

from datetime import datetime
from unittest.mock import patch
import pytest
from parental_control import DATETIME_FORMAT, app
from parental_control.span import DateTimeSpan, MinuteSpan
@pytest.mark.parametrize(
"point_in_time, schedules, overrides, expected_result",
[
# Point in time within override
(
"2023-08-24 14:00",
{day: [] for day in range(7)},
[{"start": "2023-08-24 12:00", "end": "2023-08-24 18:00", "action": True}],
True,
),
# Point in time within schedule
(
"2023-08-24 14:00",
{3: [{"start": "10:00", "end": "16:00"}]},
[],
True,
),
# Point in time outside schedule and override
(
"2023-08-24 08:00",
{3: [{"start": "10:00", "end": "16:00"}]},
[{"start": "2023-08-24 12:00", "end": "2023-08-24 18:00", "action": True}],
False,
),
],
)
def test_get_action_at(point_in_time, schedules, overrides, expected_result):
point_in_time = datetime.strptime(point_in_time, DATETIME_FORMAT)
schedules = {
day: [MinuteSpan.from_args(**span) for span in schedule]
for day, schedule in schedules.items()
}
overrides = [DateTimeSpan.from_args(**o) for o in overrides]
result = app.get_action_at(point_in_time, schedules, overrides)
assert result == expected_result
@pytest.mark.parametrize(
"point_in_time, action, schedules, overrides, expected_result",
[
# No schedule, no overrides, next change will never occur
(
"2023-08-24 08:00",
False,
{day: [] for day in range(7)},
[],
None,
),
# Schedule 24/7, no overrides, next change will never occur
(
"2023-08-24 08:00",
True,
{day: [{"start": "00:00", "end": "24:00"}] for day in range(7)},
[],
None,
),
# No schedule, next change occurs after allow override starts
(
"2023-08-24 08:00",
False,
{day: [] for day in range(7)},
[{"start": "2023-08-26 10:00", "end": "2023-08-26 14:00", "action": True}],
"2023-08-26 10:00",
),
# Schedule 24/7, next change occurs after deny override starts
(
"2023-08-24 08:00",
True,
{day: [{"start": "00:00", "end": "24:00"}] for day in range(7)},
[{"start": "2023-08-26 10:00", "end": "2023-08-26 14:00", "action": False}],
"2023-08-26 10:00",
),
# No schedule, expired overrides, next change will never occur
(
"2023-08-24 08:00",
False,
{day: [] for day in range(7)},
[{"start": "2023-08-23 10:00", "end": "2023-08-23 14:00", "action": True}],
None,
),
# No schedule, next change occurs after allow override expires
(
"2023-08-24 08:00",
True,
{day: [] for day in range(7)},
[{"start": "2023-08-24 08:00", "end": "2023-08-26 14:00", "action": True}],
"2023-08-26 14:00",
),
# Next change occurs after allow override expires
(
"2023-08-24 08:00",
True,
{day: [{"start": "14:00", "end": "16:00"}] for day in range(7)},
[{"start": "2023-08-24 08:00", "end": "2023-08-24 10:00", "action": True}],
"2023-08-24 10:00",
),
# Next change occurs after schedule span ends
(
"2023-08-24 14:00",
True,
{
day: [{"start": "08:00", "end": "10:00"}, {"start": "14:00", "end": "16:00"}]
for day in range(7)
},
[{"start": "2023-08-24 08:00", "end": "2023-08-24 10:00", "action": True}],
"2023-08-24 16:00",
),
# Next change occurs after schedule span starts
(
"2023-08-24 13:00",
False,
{
day: [{"start": "08:00", "end": "10:00"}, {"start": "14:00", "end": "16:00"}]
for day in range(7)
},
[{"start": "2023-08-24 08:00", "end": "2023-08-24 10:00", "action": True}],
"2023-08-24 14:00",
),
# Next change occurs after deny override starts
(
"2023-08-24 11:00",
True,
{day: [{"start": "10:00", "end": "16:00"}] for day in range(7)},
[{"start": "2023-08-24 12:00", "end": "2023-08-24 14:00", "action": False}],
"2023-08-24 12:00",
),
# Next change occurs after allow override starts
(
"2023-08-24 10:00",
False,
{day: [{"start": "16:00", "end": "18:00"}] for day in range(7)},
[{"start": "2023-08-24 12:00", "end": "2023-08-24 14:00", "action": True}],
"2023-08-24 12:00",
),
# Next change occurs after schedule span ends after 7 days
(
"2023-08-21 13:00",
True,
{
0: [{"start": "00:00", "end": "04:00"}, {"start": "10:00", "end": "24:00"}],
1: [{"start": "00:00", "end": "24:00"}],
2: [{"start": "00:00", "end": "24:00"}],
3: [{"start": "00:00", "end": "24:00"}],
4: [{"start": "00:00", "end": "24:00"}],
5: [{"start": "00:00", "end": "24:00"}],
6: [{"start": "00:00", "end": "24:00"}],
},
[{"start": "2023-08-24 12:00", "end": "2023-08-24 14:00", "action": True}],
"2023-08-28 04:00",
),
# Next change occurs after schedule span starts after 7 days
(
"2023-08-21 13:00",
False,
{
0: [{"start": "00:00", "end": "04:00"}],
1: [],
2: [],
3: [],
4: [],
5: [],
6: [],
},
[{"start": "2023-08-31 12:00", "end": "2023-08-31 14:00", "action": True}],
"2023-08-28 00:00",
),
],
)
def test_get_next_action_change(point_in_time, action, schedules, overrides, expected_result):
point_in_time = datetime.strptime(point_in_time, DATETIME_FORMAT)
schedules = {
day: [MinuteSpan.from_args(**span) for span in schedule]
for day, schedule in schedules.items()
}
overrides = [DateTimeSpan.from_args(**o) for o in overrides]
result = app.get_next_action_change(point_in_time, action, schedules, overrides)
if expected_result:
expected_result = datetime.strptime(expected_result, DATETIME_FORMAT)
assert result == expected_result
@pytest.mark.parametrize(
"schedules, overrides, expected_result",
[
(
{day: [] for day in range(7)},
[],
{"action": False, "until": "", "then_until": ""},
),
(
{day: [{"start": "14:00", "end": "16:00"}] for day in range(7)},
[{"start": "2023-08-24 08:00", "end": "2023-08-24 10:00", "action": True}],
{"action": False, "until": "2023-08-24 14:00", "then_until": "2023-08-24 16:00"},
),
(
{day: [] for day in range(7)},
[{"start": "2023-08-24 08:00", "end": "2023-08-24 12:00", "action": True}],
{"action": True, "until": "2023-08-24 12:00", "then_until": ""},
),
],
)
@patch("parental_control.app.datetime", wraps=datetime)
def test_calculate_status(mock_datetime, schedules, overrides, expected_result):
mock_datetime.now.return_value = datetime(2023, 8, 24, 11)
schedules = {
day: [MinuteSpan.from_args(**span) for span in schedule]
for day, schedule in schedules.items()
}
overrides = [DateTimeSpan.from_args(**o) for o in overrides]
result = app.calculate_status(schedules, overrides)
assert result == expected_result
@pytest.mark.parametrize(
"schedule, span, action, expected_result",
[
# Allow span in empty schedule
(
[],
{"start": "09:00", "end": "11:00"},
True,
[{"start": "9:00", "end": "11:00"}],
),
# Allow span same as already existing span
(
[{"start": "9:00", "end": "11:00"}],
{"start": "09:00", "end": "11:00"},
True,
[{"start": "9:00", "end": "11:00"}],
),
# Allow span (starting at 0:00) prepening it before existing span
(
[{"start": "9:00", "end": "11:00"}],
{"start": "00:00", "end": "05:00"},
True,
[{"start": "0:00", "end": "5:00"}, {"start": "9:00", "end": "11:00"}],
),
# Allow span (ending at 24:00) appending it after existing span
(
[{"start": "9:00", "end": "11:00"}],
{"start": "19:00", "end": "0:00"},
True,
[{"start": "9:00", "end": "11:00"}, {"start": "19:00", "end": "24:00"}],
),
# Allow span merging existing spans together
(
[{"start": "9:00", "end": "11:00"}, {"start": "14:00", "end": "16:00"}],
{"start": "11:00", "end": "14:00"},
True,
[{"start": "9:00", "end": "16:00"}],
),
# Deny span from empty schedule
(
[],
{"start": "12:00", "end": "14:00"},
False,
[],
),
# Deny span which is already denied
(
[{"start": "9:00", "end": "11:00"}, {"start": "16:00", "end": "18:00"}],
{"start": "12:00", "end": "14:00"},
False,
[{"start": "9:00", "end": "11:00"}, {"start": "16:00", "end": "18:00"}],
),
# Deny span removing existing allow spans
(
[{"start": "9:00", "end": "11:00"}, {"start": "16:00", "end": "18:00"}],
{"start": "0:00", "end": "0:00"},
False,
[],
),
# Deny span within allow span, splitting the allow span
(
[{"start": "9:00", "end": "16:00"}],
{"start": "11:00", "end": "14:00"},
False,
[{"start": "9:00", "end": "11:00"}, {"start": "14:00", "end": "16:00"}],
),
# Deny span moving end and start of existing allow spans
(
[{"start": "9:00", "end": "11:00"}, {"start": "16:00", "end": "18:00"}],
{"start": "10:00", "end": "17:00"},
False,
[{"start": "9:00", "end": "10:00"}, {"start": "17:00", "end": "18:00"}],
),
],
)
def test_update_schedule(schedule, span, action, expected_result):
schedule = [MinuteSpan.from_args(**s) for s in schedule]
span = MinuteSpan.from_args(**span)
app.update_schedule(schedule, span, action)
expected_result = [MinuteSpan.from_args(**s) for s in expected_result]
assert schedule == expected_result
@pytest.mark.parametrize(
"overrides, start, end, action, expected_result",
[
# Add override into empty list of overrides
(
[],
{"start": "2023-08-24 08:00", "end": "2023-08-24 10:00", "action": True},
[{"start": "2023-08-24 08:00", "end": "2023-08-24 10:00", "action": True}],
),
# Add override into list of overrides
(
[
{"start": "2023-08-24 00:00", "end": "2023-08-24 06:00", "action": True},
{"start": "2023-08-24 15:00", "end": "2023-08-24 20:00", "action": True},
],
{"start": "2023-08-24 08:00", "end": "2023-08-24 10:00", "action": True},
[
{"start": "2023-08-24 00:00", "end": "2023-08-24 06:00", "action": True},
{"start": "2023-08-24 08:00", "end": "2023-08-24 10:00", "action": True},
{"start": "2023-08-24 15:00", "end": "2023-08-24 20:00", "action": True},
],
),
# Add override removing another override spanning over smaller period
(
[
{"start": "2023-08-24 00:00", "end": "2023-08-24 06:00", "action": True},
{"start": "2023-08-24 15:00", "end": "2023-08-24 20:00", "action": True},
],
{"start": "2023-08-24 15:00", "end": "2023-08-24 22:00", "action": False},
[
{"start": "2023-08-24 00:00", "end": "2023-08-24 06:00", "action": True},
{"start": "2023-08-24 15:00", "end": "2023-08-24 22:00", "action": False},
],
),
# Add override within existing override span, splitting it
(
[{"start": "2023-08-24 08:00", "end": "2023-08-24 20:00", "action": False}],
{"start": "2023-08-24 16:00", "end": "2023-08-24 18:00", "action": True},
[
{"start": "2023-08-24 08:00", "end": "2023-08-24 16:00", "action": False},
{"start": "2023-08-24 16:00", "end": "2023-08-24 18:00", "action": True},
{"start": "2023-08-24 18:00", "end": "2023-08-24 20:00", "action": False},
],
),
# Add override moving end and start of existing overrides
(
[
{"start": "2023-08-24 00:00", "end": "2023-08-24 06:00", "action": True},
{"start": "2023-08-24 15:00", "end": "2023-08-24 20:00", "action": True},
],
{"start": "2023-08-24 04:00", "end": "2023-08-24 18:00", "action": False},
[
{"start": "2023-08-24 00:00", "end": "2023-08-24 04:00", "action": True},
{"start": "2023-08-24 04:00", "end": "2023-08-24 18:00", "action": False},
{"start": "2023-08-24 18:00", "end": "2023-08-24 20:00", "action": True},
],
),
# Add override merging existing overrides
(
[
{"start": "2023-08-24 00:00", "end": "2023-08-24 06:00", "action": True},
{"start": "2023-08-24 15:00", "end": "2023-08-24 20:00", "action": True},
],
{"start": "2023-08-24 04:00", "end": "2023-08-24 18:00", "action": True},
[{"start": "2023-08-24 00:00", "end": "2023-08-24 20:00", "action": True}],
),
],
)
def test_update_overrides(overrides, span, expected_result):
overrides = [DateTimeSpan.from_args(**o) for o in overrides]
span = DateTimeSpan.from_args(**span)
app.update_overrides(overrides, span)
expected_result = [DateTimeSpan.from_args(**o) for o in expected_result]
assert overrides == expected_result