Improve test coverage

This commit is contained in:
Keith Edmunds 2024-04-01 21:20:00 +01:00
parent aaf2257117
commit dbe71c3be4
15 changed files with 304 additions and 123 deletions

1
.gitignore vendored
View File

@ -11,3 +11,4 @@ StudioPlaylist.png
*.howto
.direnv
tmp/
.coverage

View File

@ -1,5 +1,5 @@
from dataclasses import dataclass
from datetime import datetime, timedelta
import datetime as dt
from typing import Optional
from PyQt6.QtCore import pyqtSignal, QObject, QThread
@ -108,7 +108,7 @@ class PlaylistTrack:
self.artist: Optional[str] = None
self.duration: Optional[int] = None
self.end_time: Optional[datetime] = None
self.end_time: Optional[dt.datetime] = None
self.fade_at: Optional[int] = None
self.fade_graph: Optional[FadeCurve] = None
self.fade_length: Optional[int] = None
@ -119,7 +119,7 @@ class PlaylistTrack:
self.resume_marker: Optional[float] = None
self.silence_at: Optional[int] = None
self.start_gap: Optional[int] = None
self.start_time: Optional[datetime] = None
self.start_time: Optional[dt.datetime] = None
self.title: Optional[str] = None
self.track_id: Optional[int] = None
@ -177,9 +177,9 @@ class PlaylistTrack:
Called when track starts playing
"""
self.start_time = datetime.now()
self.start_time = dt.datetime.now()
if self.duration:
self.end_time = self.start_time + timedelta(milliseconds=self.duration)
self.end_time = self.start_time + dt.timedelta(milliseconds=self.duration)
class AddFadeCurve(QObject):

View File

@ -1,4 +1,4 @@
import datetime
import datetime as dt
import logging
import os
from typing import List, Optional
@ -38,7 +38,7 @@ class Config(object):
DEBUG_MODULES: List[Optional[str]] = ["dbconfig"]
DEFAULT_COLUMN_WIDTH = 200
DISPLAY_SQL = False
EPOCH = datetime.datetime(1970, 1, 1)
EPOCH = dt.datetime(1970, 1, 1)
ERRORS_FROM = ["noreply@midnighthax.com"]
ERRORS_TO = ["kae@midnighthax.com"]
FADE_CURVE_BACKGROUND = "lightyellow"

View File

@ -1,4 +1,4 @@
from datetime import datetime
import datetime as dt
from email.message import EmailMessage
from typing import Any, Dict, Optional
import functools
@ -99,7 +99,7 @@ def get_audio_segment(path: str) -> Optional[AudioSegment]:
return None
def get_embedded_time(text: str) -> Optional[datetime]:
def get_embedded_time(text: str) -> Optional[dt.datetime]:
"""Return datetime specified as @hh:mm in text"""
try:
@ -110,7 +110,7 @@ def get_embedded_time(text: str) -> Optional[datetime]:
return None
try:
return datetime.strptime(match.group(0)[1:], Config.NOTE_TIME_FORMAT)
return dt.datetime.strptime(match.group(0)[1:], Config.NOTE_TIME_FORMAT)
except ValueError:
return None
@ -143,7 +143,7 @@ def get_file_metadata(filepath: str) -> dict:
def get_relative_date(
past_date: Optional[datetime], reference_date: Optional[datetime] = None
past_date: Optional[dt.datetime], reference_date: Optional[dt.datetime] = None
) -> str:
"""
Return how long before reference_date past_date is as string.
@ -158,7 +158,7 @@ def get_relative_date(
if not past_date or past_date == Config.EPOCH:
return "Never"
if not reference_date:
reference_date = datetime.now()
reference_date = dt.datetime.now()
# Check parameters
if past_date > reference_date:

View File

@ -1,6 +1,6 @@
import urllib.parse
from datetime import datetime
import datetime as dt
from slugify import slugify # type: ignore
from typing import Dict
from PyQt6.QtCore import QUrl # type: ignore
@ -24,14 +24,14 @@ class InfoTabs(QTabWidget):
self.signals.search_songfacts_signal.connect(self.open_in_songfacts)
self.signals.search_wikipedia_signal.connect(self.open_in_wikipedia)
# re-use the oldest one later)
self.last_update: Dict[QWebEngineView, datetime] = {}
self.last_update: Dict[QWebEngineView, dt.datetime] = {}
self.tabtitles: Dict[int, str] = {}
# Create one tab which (for some reason) creates flickering if
# done later
widget = QWebEngineView()
widget.setZoomFactor(Config.WEB_ZOOM_FACTOR)
self.last_update[widget] = datetime.now()
self.last_update[widget] = dt.datetime.now()
_ = self.addTab(widget, "")
def open_in_songfacts(self, title):
@ -80,7 +80,7 @@ class InfoTabs(QTabWidget):
self.setTabText(tab_index, short_title)
widget.setUrl(QUrl(url))
self.last_update[widget] = datetime.now()
self.last_update[widget] = dt.datetime.now()
self.tabtitles[tab_index] = url
# Show newly updated tab

View File

@ -5,8 +5,7 @@ import re
from config import Config
from dbconfig import scoped_session
from datetime import datetime
from pprint import pprint
import datetime as dt
from typing import List, Optional, Sequence
from sqlalchemy.ext.associationproxy import association_proxy
@ -162,7 +161,7 @@ class Playdates(Base):
__tablename__ = "playdates"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
lastplayed: Mapped[datetime] = mapped_column(index=True)
lastplayed: Mapped[dt.datetime] = mapped_column(index=True)
track_id: Mapped[int] = mapped_column(ForeignKey("tracks.id"))
track: Mapped["Tracks"] = relationship("Tracks", back_populates="playdates")
@ -175,13 +174,13 @@ class Playdates(Base):
def __init__(self, session: scoped_session, track_id: int) -> None:
"""Record that track was played"""
self.lastplayed = datetime.now()
self.lastplayed = dt.datetime.now()
self.track_id = track_id
session.add(self)
session.commit()
@staticmethod
def last_played(session: scoped_session, track_id: int) -> datetime:
def last_played(session: scoped_session, track_id: int) -> dt.datetime:
"""Return datetime track last played or None"""
last_played = session.execute(
@ -194,10 +193,12 @@ class Playdates(Base):
if last_played:
return last_played[0]
else:
return Config.EPOCH
# Should never be reached as we create record with a
# last_played value
return Config.EPOCH # pragma: no cover
@staticmethod
def played_after(session: scoped_session, since: datetime) -> Sequence["Playdates"]:
def played_after(session: scoped_session, since: dt.datetime) -> Sequence["Playdates"]:
"""Return a list of Playdates objects since passed time"""
return session.scalars(
@ -216,7 +217,7 @@ class Playlists(Base):
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
name: Mapped[str] = mapped_column(String(32), unique=True)
last_used: Mapped[Optional[datetime]] = mapped_column(DateTime, default=None)
last_used: Mapped[Optional[dt.datetime]] = mapped_column(DateTime, default=None)
tab: Mapped[Optional[int]] = mapped_column(default=None)
open: Mapped[bool] = mapped_column(default=False)
is_template: Mapped[bool] = mapped_column(default=False)
@ -328,7 +329,7 @@ class Playlists(Base):
"""Mark playlist as loaded and used now"""
self.open = True
self.last_used = datetime.now()
self.last_used = dt.datetime.now()
@staticmethod
def name_is_available(session: scoped_session, name: str) -> bool:
@ -586,8 +587,6 @@ class PlaylistRows(Base):
cls,
session: scoped_session,
playlist_id: int,
from_row: Optional[int] = None,
to_row: Optional[int] = None,
) -> Sequence["PlaylistRows"]:
"""
For passed playlist, return a list of rows that
@ -597,11 +596,6 @@ class PlaylistRows(Base):
query = select(cls).where(
cls.playlist_id == playlist_id, cls.track_id.is_not(None)
)
if from_row is not None:
query = query.where(cls.plr_rownum >= from_row)
if to_row is not None:
query = query.where(cls.plr_rownum <= to_row)
plrs = session.scalars((query).order_by(cls.plr_rownum)).all()
return plrs
@ -682,7 +676,7 @@ class Settings(Base):
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
name: Mapped[str] = mapped_column(String(64), unique=True)
f_datetime: Mapped[Optional[datetime]] = mapped_column(default=None)
f_datetime: Mapped[Optional[dt.datetime]] = mapped_column(default=None)
f_int: Mapped[Optional[int]] = mapped_column(default=None)
f_string: Mapped[Optional[str]] = mapped_column(String(128), default=None)

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3
from datetime import datetime, timedelta
import datetime as dt
from time import sleep
from typing import (
cast,
@ -208,14 +208,12 @@ class Window(QMainWindow, Ui_MainWindow):
self.music: music.Music = music.Music()
self.playing: bool = False
self.selected_plrs: Optional[List[PlaylistRows]] = None
self.set_main_window_size()
self.lblSumPlaytime = QLabel("")
self.statusbar.addPermanentWidget(self.lblSumPlaytime)
self.txtSearch = QLineEdit()
self.statusbar.addWidget(self.txtSearch)
self.txtSearch.setHidden(True)
self.statusbar.addWidget(self.txtSearch)
self.hide_played_tracks = False
mixer.init()
self.widgetFadeVolume.hideAxis("bottom")
@ -755,7 +753,7 @@ class Window(QMainWindow, Ui_MainWindow):
if track_sequence.now.track_id is None or track_sequence.now.start_time is None:
return 0
now = datetime.now()
now = dt.datetime.now()
track_start = track_sequence.now.start_time
elapsed_seconds = (now - track_start).total_seconds()
return int(elapsed_seconds * 1000)
@ -902,7 +900,7 @@ class Window(QMainWindow, Ui_MainWindow):
if playlist:
_ = self.create_playlist_tab(playlist)
playlist_ids.append(playlist.id)
log.info(f"load_last_playlists() loaded {playlist=}")
log.debug(f"load_last_playlists() loaded {playlist=}")
# Set active tab
record = Settings.get_int_settings(session, "active_tab")
if record.f_int is not None and record.f_int >= 0:
@ -1236,7 +1234,7 @@ class Window(QMainWindow, Ui_MainWindow):
and track_sequence.now.resume_marker
):
elapsed_ms = track_sequence.now.duration * track_sequence.now.resume_marker
track_sequence.now.start_time -= timedelta(milliseconds=elapsed_ms)
track_sequence.now.start_time -= dt.timedelta(milliseconds=elapsed_ms)
def save_as_template(self) -> None:
"""Save current playlist as template"""
@ -1497,7 +1495,7 @@ class Window(QMainWindow, Ui_MainWindow):
and track_sequence.now.start_time
):
play_time = (
datetime.now() - track_sequence.now.start_time
dt.datetime.now() - track_sequence.now.start_time
).total_seconds() * 1000
track_sequence.now.fade_graph.tick(play_time)
@ -1506,7 +1504,7 @@ class Window(QMainWindow, Ui_MainWindow):
Called every 500ms
"""
self.lblTOD.setText(datetime.now().strftime(Config.TOD_TIME_FORMAT))
self.lblTOD.setText(dt.datetime.now().strftime(Config.TOD_TIME_FORMAT))
# Update carts
# self.cart_tick()
@ -1534,8 +1532,8 @@ class Window(QMainWindow, Ui_MainWindow):
and track_sequence.now.start_time
and (
self.music.player.is_playing()
or (datetime.now() - track_sequence.now.start_time)
< timedelta(microseconds=Config.PLAY_SETTLE)
or (dt.datetime.now() - track_sequence.now.start_time)
< dt.timedelta(microseconds=Config.PLAY_SETTLE)
)
):
playtime = self.get_playtime()

View File

@ -2,11 +2,9 @@
from __future__ import annotations
import obsws_python as obs # type: ignore
import re
from dataclasses import dataclass
from datetime import datetime, timedelta
import datetime as dt
from enum import auto, Enum
from operator import attrgetter
from pprint import pprint
from random import shuffle
from typing import List, Optional
@ -64,13 +62,13 @@ class PlaylistRowData:
self.artist: str = ""
self.bitrate = 0
self.duration: int = 0
self.lastplayed: datetime = Config.EPOCH
self.lastplayed: dt.datetime = Config.EPOCH
self.path = ""
self.played = False
self.start_gap: Optional[int] = None
self.title: str = ""
self.start_time: Optional[datetime] = None
self.end_time: Optional[datetime] = None
self.start_time: Optional[dt.datetime] = None
self.end_time: Optional[dt.datetime] = None
self.plrid: int = plr.id
self.plr_rownum: int = plr.plr_rownum
@ -685,7 +683,7 @@ class PlaylistModel(QAbstractTableModel):
< prd.plr_rownum
)
):
section_end_time = track_sequence.now.end_time + timedelta(
section_end_time = track_sequence.now.end_time + dt.timedelta(
milliseconds=duration
)
end_time_str = (
@ -1341,7 +1339,7 @@ class PlaylistModel(QAbstractTableModel):
log.info("update_track_times()")
next_start_time: Optional[datetime] = None
next_start_time: Optional[dt.datetime] = None
update_rows: List[int] = []
for row_number in range(len(self.playlist_rows)):
@ -1362,7 +1360,7 @@ class PlaylistModel(QAbstractTableModel):
and track_sequence.now.end_time
):
prd.start_time = track_sequence.now.end_time
prd.end_time = prd.start_time + timedelta(milliseconds=prd.duration)
prd.end_time = prd.start_time + dt.timedelta(milliseconds=prd.duration)
next_start_time = prd.end_time
update_rows.append(row_number)
continue
@ -1407,7 +1405,7 @@ class PlaylistModel(QAbstractTableModel):
update_rows.append(row_number)
# Calculate next start time
next_start_time += timedelta(milliseconds=prd.duration)
next_start_time += dt.timedelta(milliseconds=prd.duration)
# Update end time of this row if it's incorrect
if prd.end_time != next_start_time:
@ -1483,9 +1481,9 @@ class PlaylistProxyModel(QSortFilterProxyModel):
== self.source_model.playlist_id
):
if track_sequence.now.start_time:
if datetime.now() > (
if dt.datetime.now() > (
track_sequence.now.start_time
+ timedelta(
+ dt.timedelta(
milliseconds=Config.HIDE_AFTER_PLAYING_OFFSET
)
):

View File

@ -1,11 +1,11 @@
#!/usr/bin/python3
from datetime import datetime, timedelta
import datetime as dt
from threading import Timer
from pydub import AudioSegment
from time import sleep
from timeloop import Timeloop
import vlc
from timeloop import Timeloop # type: ignore
import vlc # type: ignore
class RepeatedTimer(object):
@ -124,7 +124,7 @@ def update_progress(player, talk_at, silent_at):
remaining_time = total_time - elapsed_time
talk_time = remaining_time - (total_time - talk_at)
silent_time = remaining_time - (total_time - silent_at)
end_time = (datetime.now() + timedelta(
end_time = (dt.datetime.now() + timedelta(
milliseconds=remaining_time)).strftime("%H:%M:%S")
print(
f"\t{ms_to_mmss(elapsed_time)}/"

89
poetry.lock generated
View File

@ -292,6 +292,74 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""}
[package.extras]
development = ["black", "flake8", "mypy", "pytest", "types-colorama"]
[[package]]
name = "coverage"
version = "7.4.4"
description = "Code coverage measurement for Python"
category = "dev"
optional = false
python-versions = ">=3.8"
files = [
{file = "coverage-7.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2"},
{file = "coverage-7.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf"},
{file = "coverage-7.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8"},
{file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562"},
{file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2"},
{file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7"},
{file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87"},
{file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c"},
{file = "coverage-7.4.4-cp310-cp310-win32.whl", hash = "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d"},
{file = "coverage-7.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f"},
{file = "coverage-7.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf"},
{file = "coverage-7.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083"},
{file = "coverage-7.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63"},
{file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f"},
{file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227"},
{file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd"},
{file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384"},
{file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b"},
{file = "coverage-7.4.4-cp311-cp311-win32.whl", hash = "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286"},
{file = "coverage-7.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec"},
{file = "coverage-7.4.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76"},
{file = "coverage-7.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818"},
{file = "coverage-7.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978"},
{file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70"},
{file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51"},
{file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c"},
{file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48"},
{file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9"},
{file = "coverage-7.4.4-cp312-cp312-win32.whl", hash = "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0"},
{file = "coverage-7.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e"},
{file = "coverage-7.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384"},
{file = "coverage-7.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1"},
{file = "coverage-7.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a"},
{file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409"},
{file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e"},
{file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd"},
{file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7"},
{file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c"},
{file = "coverage-7.4.4-cp38-cp38-win32.whl", hash = "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e"},
{file = "coverage-7.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8"},
{file = "coverage-7.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d"},
{file = "coverage-7.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357"},
{file = "coverage-7.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e"},
{file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e"},
{file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4"},
{file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec"},
{file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd"},
{file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade"},
{file = "coverage-7.4.4-cp39-cp39-win32.whl", hash = "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57"},
{file = "coverage-7.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c"},
{file = "coverage-7.4.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677"},
{file = "coverage-7.4.4.tar.gz", hash = "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49"},
]
[package.dependencies]
tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""}
[package.extras]
toml = ["tomli"]
[[package]]
name = "decorator"
version = "5.1.1"
@ -1524,6 +1592,25 @@ tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
[package.extras]
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
[[package]]
name = "pytest-cov"
version = "5.0.0"
description = "Pytest plugin for measuring coverage."
category = "dev"
optional = false
python-versions = ">=3.8"
files = [
{file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"},
{file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"},
]
[package.dependencies]
coverage = {version = ">=5.2.1", extras = ["toml"]}
pytest = ">=4.6"
[package.extras]
testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"]
[[package]]
name = "pytest-qt"
version = "4.4.0"
@ -2186,4 +2273,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
[metadata]
lock-version = "2.0"
python-versions = "^3.9"
content-hash = "9fc13f4695a3be773cbbdcc175495650e638f31d786f6e35724b57f70bcb5f78"
content-hash = "500cefc31e30cba9ae917cc51b7407961d69825d1fcae53515ed1fa12f4ab171"

View File

@ -44,6 +44,7 @@ black = "^24.2.0"
flakehell = "^0.9.0"
mypy = "^1.7.0"
pdbp = "^1.5.0"
pytest-cov = "^5.0.0"
[build-system]
requires = ["poetry-core>=1.0.0"]

View File

@ -1,4 +1,4 @@
from datetime import datetime, timedelta
import datetime as dt
from helpers import (
fade_point,
get_audio_segment,
@ -43,12 +43,12 @@ def test_get_tags():
def test_get_relative_date():
assert get_relative_date(None) == "Never"
today_at_10 = datetime.now().replace(hour=10, minute=0)
today_at_11 = datetime.now().replace(hour=11, minute=0)
today_at_10 = dt.datetime.now().replace(hour=10, minute=0)
today_at_11 = dt.datetime.now().replace(hour=11, minute=0)
assert get_relative_date(today_at_10, today_at_11) == "Today 10:00"
eight_days_ago = today_at_10 - timedelta(days=8)
eight_days_ago = today_at_10 - dt.timedelta(days=8)
assert get_relative_date(eight_days_ago, today_at_11) == "1 week, 1 day ago"
sixteen_days_ago = today_at_10 - timedelta(days=16)
sixteen_days_ago = today_at_10 - dt.timedelta(days=16)
assert get_relative_date(sixteen_days_ago, today_at_11) == "2 weeks, 2 days ago"

25
tests/test_misc.py Normal file
View File

@ -0,0 +1,25 @@
import pytest
from models import NoteColours, Settings
def test_log_exception():
"""Test deliberate exception"""
with pytest.raises(Exception):
1 / 0
def test_create_settings(session):
SETTING_NAME = "wombat"
NO_SUCH_SETTING = "abc"
VALUE = 3
setting = Settings(session, SETTING_NAME)
setting.update(session, dict(f_int=VALUE))
print(setting)
_ = Settings.all_as_dict(session)
test = Settings.get_int_settings(session, SETTING_NAME)
assert test.name == SETTING_NAME
assert test.f_int == VALUE
test_new = Settings.get_int_settings(session, NO_SUCH_SETTING)
assert test_new.name == NO_SUCH_SETTING

View File

@ -1,11 +1,11 @@
import os.path
import helpers
import datetime as dt
from app.models import (
Carts,
NoteColours,
Playdates,
Playlists,
PlaylistRows,
Tracks,
)
@ -60,68 +60,44 @@ def test_playdates_add_playdate(session, track1):
playdate = Playdates(session, track1.id)
assert playdate
print(playdate)
last_played = Playdates.last_played(session, track1.id)
assert abs((playdate.lastplayed - last_played).total_seconds()) < 2
def test_playdates_played_after(session, track1):
playdate = Playdates(session, track1.id)
yesterday = dt.datetime.now() - dt.timedelta(days=1)
played = Playdates.played_after(session, yesterday)
assert len(played) == 1
assert played[0] == playdate
def test_playlist_create(session):
TEMPLATE_NAME = "my template"
playlist = Playlists(session, "my playlist")
assert playlist
print(playlist)
# test clear tabs
Playlists.clear_tabs(session, [playlist.id])
# def test_playlist_add_track(session, track):
# # We need a playlist
# playlist = Playlists(session, "my playlist")
# create template
Playlists.save_as_template(session, playlist.id, TEMPLATE_NAME)
# row = 17
# test create template
_ = Playlists.create_playlist_from_template(session, playlist, "my new name")
# playlist.add_track(session, track.id, row)
# assert len(playlist.tracks) == 1
# playlist_track = playlist.tracks[row]
# assert playlist_track.path == track_path
# def test_playlist_tracks(session):
# # We need a playlist
# playlist = Playlists(session, "my playlist")
# # We need two tracks
# track1_path = "/a/b/c"
# track1_row = 17
# track1 = Tracks(session, track1_path)
# track2_path = "/x/y/z"
# track2_row = 29
# track2 = Tracks(session, track2_path)
# playlist.add_track(session, track1.id, track1_row)
# playlist.add_track(session, track2.id, track2_row)
# tracks = playlist.tracks
# assert tracks[track1_row] == track1
# assert tracks[track2_row] == track2
# def test_playlist_notes(session):
# # We need a playlist
# playlist = Playlists(session, "my playlist")
# # We need two notes
# note1_text = "note1 text"
# note1_row = 11
# _ = Notes(session, playlist.id, note1_row, note1_text)
# note2_text = "note2 text"
# note2_row = 19
# _ = Notes(session, playlist.id, note2_row, note2_text)
# notes = playlist.notes
# assert note1_text in [n.note for n in notes]
# assert note1_row in [n.row for n in notes]
# assert note2_text in [n.note for n in notes]
# assert note2_row in [n.row for n in notes]
# get all templates
all_templates = Playlists.get_all_templates(session)
assert len(all_templates) == 1
# Save as template creates new playlist
assert all_templates[0] != playlist
# test delete playlist
playlist.delete(session)
def test_playlist_open_and_close(session):
@ -184,3 +160,91 @@ def test_tracks_search_titles(session, track1):
track1_title = "I'm So Afraid"
assert len(Tracks.search_titles(session, track1_title)) == 1
def test_repr(session):
"""Just check for error retrieving reprs"""
nc = NoteColours(session, substring="x", colour="x")
print(nc)
def test_get_colour(session):
"""Test for errors in execution"""
GOOD_STRING = "cantelope"
BAD_STRING = "ericTheBee"
SUBSTR = "ant"
COLOUR = "blue"
nc1 = NoteColours(session, substring=SUBSTR, colour=COLOUR, is_casesensitive=True)
_ = nc1.get_colour(session, "")
colour = nc1.get_colour(session, GOOD_STRING)
assert colour == COLOUR
colour = nc1.get_colour(session, BAD_STRING)
assert colour is None
nc2 = NoteColours(session, substring=".*" + SUBSTR, colour=COLOUR, is_regex=True)
colour = nc2.get_colour(session, GOOD_STRING)
assert colour == COLOUR
colour = nc2.get_colour(session, BAD_STRING)
assert colour is None
nc3 = NoteColours(
session, substring=".*" + SUBSTR, colour=COLOUR, is_regex=True, is_casesensitive=True
)
colour = nc3.get_colour(session, GOOD_STRING)
assert colour == COLOUR
colour = nc3.get_colour(session, BAD_STRING)
assert colour is None
def test_create_cart(session):
cart = Carts(session, 1, "name")
assert cart
print(cart)
def test_name_available(session):
PLAYLIST_NAME = "a name"
RENAME = "new name"
if Playlists.name_is_available(session, PLAYLIST_NAME):
playlist = Playlists(session, PLAYLIST_NAME)
assert playlist
assert Playlists.name_is_available(session, PLAYLIST_NAME) is False
playlist.rename(session, RENAME)
def test_create_playlist_row(session):
PLAYLIST_NAME = "a name"
if Playlists.name_is_available(session, PLAYLIST_NAME):
playlist = Playlists(session, PLAYLIST_NAME)
plr = PlaylistRows(session, playlist.id, 1)
assert plr
print(plr)
plr.append_note("a note")
plr.append_note("another note")
def test_delete_plr(session):
PLAYLIST_NAME = "a name"
if Playlists.name_is_available(session, PLAYLIST_NAME):
playlist = Playlists(session, PLAYLIST_NAME)
plr = PlaylistRows(session, playlist.id, 1)
assert plr
PlaylistRows.delete_higher_rows(session, plr.playlist_id, 10)
assert PlaylistRows.get_track_plr(session, 12, plr.playlist_id) is None

View File

@ -1,4 +1,3 @@
from pprint import pprint
from typing import Optional
from app.models import (
@ -228,6 +227,20 @@ def test_insert_header_row_middle(monkeypatch, session):
)
def test_add_track_to_header(monkeypatch, session):
monkeypatch.setattr(playlistmodel, "Session", session)
note_text = "test text"
initial_row_count = 11
insert_row = 6
model = create_model_with_playlist_rows(session, initial_row_count)
model.insert_row(proposed_row_number=insert_row, note=note_text)
assert model.rowCount() == initial_row_count + 1
prd = model.playlist_rows[1]
model.add_track_to_header(insert_row, prd.track_id)
def test_create_model_with_tracks(monkeypatch, session):
monkeypatch.setattr(playlistmodel, "Session", session)
model = create_model_with_tracks(session)
@ -303,7 +316,7 @@ def test_move_one_row_between_playlists_to_end(monkeypatch, session):
model_src = create_model_with_playlist_rows(session, create_rowcount, name="source")
model_dst = create_model_with_playlist_rows(session, create_rowcount, name="destination")
model_src.move_rows_between_playlists(from_rows, to_row, model_dst)
model_src.move_rows_between_playlists(from_rows, to_row, model_dst.playlist_id)
model_dst.refresh_data(session)
assert len(model_src.playlist_rows) == create_rowcount - len(from_rows)
@ -323,7 +336,7 @@ def test_move_one_row_between_playlists_to_middle(monkeypatch, session):
model_src = create_model_with_playlist_rows(session, create_rowcount, name="source")
model_dst = create_model_with_playlist_rows(session, create_rowcount, name="destination")
model_src.move_rows_between_playlists(from_rows, to_row, model_dst)
model_src.move_rows_between_playlists(from_rows, to_row, model_dst.playlist_id)
model_dst.refresh_data(session)
# Check the rows of the destination model
@ -347,7 +360,7 @@ def test_move_multiple_rows_between_playlists_to_end(monkeypatch, session):
model_src = create_model_with_playlist_rows(session, create_rowcount, name="source")
model_dst = create_model_with_playlist_rows(session, create_rowcount, name="destination")
model_src.move_rows_between_playlists(from_rows, to_row, model_dst)
model_src.move_rows_between_playlists(from_rows, to_row, model_dst.playlist_id)
model_dst.refresh_data(session)
# Check the rows of the destination model