mirror of
https://github.com/aclist/dztui.git
synced 2026-10-25 20:22:37 +01:00
113 lines
3.2 KiB
Python
113 lines
3.2 KiB
Python
import pytest
|
|
|
|
from hypothesis import given, strategies as st
|
|
from datetime import datetime, timedelta
|
|
|
|
from dzgui.views.dialogs.calc import (
|
|
LocalClock,
|
|
ServerClock,
|
|
Time,
|
|
TimePicker,
|
|
DAY_START_TIME,
|
|
DAY_END_TIME,
|
|
)
|
|
|
|
|
|
class DummyEmitter:
|
|
def __init__(self) -> None:
|
|
pass
|
|
|
|
def connect(self, _, __) -> None:
|
|
pass
|
|
|
|
|
|
@pytest.fixture(params=[("05:00", 10.0), ("15:30", 5.0)])
|
|
def accel_server_clock(request) -> None:
|
|
clock_time, expect = request.param
|
|
cur_time = Time(clock_time, 5.0, 2.0)
|
|
emitter = DummyEmitter()
|
|
local_clock = LocalClock(emitter)
|
|
server_clock = ServerClock(cur_time, emitter, local_clock)
|
|
return expect, server_clock
|
|
|
|
|
|
def test_accel_factor(accel_server_clock) -> None:
|
|
"""Static test checking times at known boundaries"""
|
|
expect, clock = accel_server_clock
|
|
assert clock.get_accel_factor(clock.cur_time) == expect
|
|
|
|
|
|
def reference_calc(start, end, day_factor, night_factor):
|
|
"""
|
|
Reference implementation to test validity of UI-side calculator
|
|
Aggregates total seconds and applies accel factors after
|
|
"""
|
|
day_start = datetime.combine(start.date(), DAY_START_TIME)
|
|
day_end = datetime.combine(start.date(), DAY_END_TIME)
|
|
night_factor = day_factor * night_factor
|
|
|
|
if end < start:
|
|
end += timedelta(days=1)
|
|
|
|
day_max = max(start, day_start)
|
|
day_min = min(end, day_end)
|
|
|
|
next_day_start = datetime.combine(end.date(), DAY_START_TIME)
|
|
next_day_end = datetime.combine(end.date(), DAY_END_TIME)
|
|
|
|
range1 = (day_end - day_max).total_seconds()
|
|
range2 = (min(end, next_day_end) - next_day_start).total_seconds()
|
|
|
|
if end.date() > start.date():
|
|
day_seconds = max(0, range1) + max(0, range2)
|
|
else:
|
|
day_seconds = max(0, (day_min - day_max).total_seconds())
|
|
|
|
total_seconds = (end - start).total_seconds()
|
|
night_seconds = (total_seconds - day_seconds) / night_factor
|
|
day_seconds = day_seconds / day_factor
|
|
total = night_seconds + day_seconds
|
|
|
|
return timedelta(seconds=total)
|
|
|
|
|
|
day_accel = st.floats(
|
|
min_value=1.0, max_value=24.0, allow_nan=False, allow_infinity=False
|
|
)
|
|
night_accel = st.floats(
|
|
min_value=1.0, max_value=64.0, allow_nan=False, allow_infinity=False
|
|
)
|
|
|
|
|
|
@st.composite
|
|
def time_ranges(draw):
|
|
start_time = draw(st.times())
|
|
deltas = st.timedeltas(min_value=timedelta(0), max_value=timedelta(days=1))
|
|
duration = draw(deltas)
|
|
|
|
start = datetime.combine(datetime.now(), start_time)
|
|
end = start + duration
|
|
return start, end
|
|
|
|
|
|
@given(span=time_ranges(), day_factor=day_accel, night_factor=night_accel)
|
|
def test_time_aggregation(span, day_factor, night_factor) -> None:
|
|
start, end = span
|
|
|
|
strtime = start.strftime("%H:%M")
|
|
t = Time(strtime, day_factor, night_factor)
|
|
emitter = DummyEmitter()
|
|
local_clock = LocalClock(emitter)
|
|
server_clock = ServerClock(t, emitter, local_clock)
|
|
h = end.time().hour
|
|
m = end.time().minute
|
|
picker = TimePicker(h, m)
|
|
|
|
# NOTE: truncates microseconds to mimic widget HH:MM selection behavior
|
|
start = server_clock.get_datetime()
|
|
end = picker.get_time()
|
|
actual = server_clock.calc_delta(end)
|
|
expect = reference_calc(start, end, day_factor, night_factor)
|
|
|
|
assert actual == expect
|