Skip to content

Commit

Permalink
feat(tests): enhance test suite with new GUI tests and coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
chenmozhijin committed Dec 13, 2024
1 parent a206fd5 commit e961f57
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
- name: Run tests
run: |
pytest --cov=lddc --cov-report=xml --cov-report=html --disable-warnings
pytest --cov=LDDC --cov-report=xml --cov-report=html --cov-report=term --disable-warnings
- name: Save test artifacts
if: always()
Expand Down
46 changes: 41 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,63 @@
# SPDX-FileCopyrightText: Copyright (C) 2024 沉默の金 <[email protected]>
# SPDX-License-Identifier: GPL-3.0-only

import os
import shutil
import sys
import threading
from collections.abc import Callable
from collections.abc import Callable, Generator
from functools import partial
from typing import Any

import pytest
from PySide6.QtCore import QRunnable, QThread
from PySide6.QtCore import QCoreApplication, QRunnable, QThread

from LDDC.res import resource_rc
from LDDC.utils.cache import cache
from LDDC.utils.logger import logger
from LDDC.utils.thread import threadpool

from .helper import screenshot_path, test_artifacts_path, tmp_dir_root, tmp_dirs


@pytest.fixture(scope="session", autouse=True)
def init() -> None:
cache.clear()
def init(request: pytest.FixtureRequest) -> Generator[None, Any, None]:
# 预处理
if request.config.getoption("clear_cache"):
cache.clear()

if os.path.exists(test_artifacts_path):
shutil.rmtree(test_artifacts_path)
os.makedirs(test_artifacts_path)
os.makedirs(screenshot_path)
os.makedirs(tmp_dir_root)

resource_rc.qInitResources()

yield

# 后处理
app = QCoreApplication.instance()
if app:
app.quit()

for tmp_dir in tmp_dirs:
tmp_dir.cleanup()


def pytest_addoption(parser: pytest.Parser) -> None:
group = parser.getgroup("LDDC tester")
group.addoption(
"--not-clear-cache",
action="store_false",
dest="clear_cache",
default=True,
help="Do not clear cache before and after testing",
)


@pytest.fixture(autouse=True)
def cover_qthreadpool(monkeypatch: pytest.MonkeyPatch) -> None:
def apply_coverage_for_qthread(monkeypatch: pytest.MonkeyPatch) -> None:

def run_with_trace(self: QRunnable | QThread) -> None:
if "coverage" in sys.modules:
Expand Down
15 changes: 15 additions & 0 deletions tests/helper.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# SPDX-FileCopyrightText: Copyright (C) 2024 沉默の金 <[email protected]>
# SPDX-License-Identifier: GPL-3.0-only
import os
from tempfile import TemporaryDirectory

from mutagen import File, FileType # type: ignore[reportPrivateImportUsage] mutagen中的File被误定义为私有 quodlibet/mutagen#647
from mutagen.easyid3 import EasyID3
Expand All @@ -11,6 +12,17 @@
from LDDC.backend.fetcher import get_lyrics
from LDDC.utils.enum import Source

tmp_dirs: list[TemporaryDirectory] = []
test_artifacts_path = os.path.join(os.path.dirname(__file__), "artifacts")
screenshot_path = os.path.join(test_artifacts_path, "screenshots")
tmp_dir_root = os.path.join(test_artifacts_path, "tmp")


def get_tmp_dir() -> str:
directory = TemporaryDirectory(dir=tmp_dir_root)
tmp_dirs.append(directory)
return directory.name


def verify_lyrics(lyrics_text: str) -> None:
lyrics = get_lyrics(Source.Local, use_cache=False, data=lyrics_text.encode("utf-8"))[0]
Expand All @@ -28,6 +40,8 @@ def close_msg_boxs(widget: QWidget) -> None:
def select_file(widget: QWidget, path: str | list[str]) -> None:
for child in widget.children():
if isinstance(child, QFileDialog):
if child.property("opened"):
continue
match child.fileMode():
case QFileDialog.FileMode.ExistingFile | QFileDialog.FileMode.Directory | QFileDialog.FileMode.AnyFile:
if isinstance(path, list):
Expand All @@ -40,6 +54,7 @@ def select_file(widget: QWidget, path: str | list[str]) -> None:

child.accept()
child.deleteLater()
child.setProperty("opened", True)
break
else:
msg = "No QFileDialog found"
Expand Down
180 changes: 180 additions & 0 deletions tests/test_gui_local_match.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
# SPDX-FileCopyrightText: Copyright (C) 2024 沉默の金 <[email protected]>
# SPDX-License-Identifier: GPL-3.0-only

# ruff: noqa: S101
import os
import shutil
from itertools import product

import pytest
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QFileDialog
from pytestqt.qtbot import QtBot

from LDDC.utils.enum import LocalMatchFileNameMode, LocalMatchSave2TagMode, LocalMatchSaveMode

from .helper import close_msg_boxs, create_audio_file, get_tmp_dir, grab, screenshot_path, select_file, test_artifacts_path, verify_audio_lyrics, verify_lyrics

SONGS_INFO = [
{
"title": "Little Busters!",
"artist": "Rita",
"album": "リトルバスターズ! Original SoundTrack Disc1",
"duration": 287,
"track": "01",
"path": ["key", "Little Busters!"],
},
{
"title": "Saya's Song",
"artist": "Lia",
"album": "Little Busters! Ecstasy Tracks",
"date": "2008-08-15",
"duration": 303,
"track": "14",
"path": ["key", "Little Busters!"],
},
{
"title": "Little Busters! -Ecstacy Ver.-",
"artist": "Rita",
"album": "Little Busters! Ecstasy Tracks",
"date": "2008-08-15",
"duration": 286,
"track": "15",
"path": ["key", "Little Busters!"],
},
{
"title": "時を刻む唄",
"artist": "Lia",
"album": "時を刻む唄 / TORCH",
"date": "2008-11-14",
"duration": 291,
"track": "01",
"path": ["key", "clannad"],
},
{
"title": "My Soul, Your Beats!",
"artist": "Lia",
"album": "My Soul, Your Beats!/Brave Song",
"date": "2010-05-26",
"duration": 275,
"track": "01",
"path": ["key", "angel beat"],
},
{
"title": "Brave Song",
"artist": "多田葵",
"album": "My Soul, Your Beats!/Brave Song",
"date": "2010-05-26",
"duration": 325,
"track": "02",
"path": ["key", "angel beat"],
},
{
"title": "Philosophyz",
"artist": "水谷瑠奈 (NanosizeMir)",
"album": "Rewrite Original SoundTrack",
"date": "2011-08-12",
"duration": 291,
"track": "01",
"path": ["key", "rewrite"],
},
{
"title": "星の舟",
"artist": "Lia",
"album": "アニメ「planetarian ~星の人~ 」メインテーマ「星の舟」 CW「Gentle Jena」",
"duration": 364,
"path": ["key", "planetarian"],
},
{
"title": "アルカテイル",
"artist": "鈴木このみ",
"album": "PCゲーム『Summer Pockets』オープニングテーマ「アルカテイル」",
"duration": 289,
"date": "2018.03.28",
"path": ["key", "summer pockets"],
},
{
"title": "アスタロア",
"artist": "鈴木このみ",
"album": "アスタロア/青き此方/夏の砂時計",
"date": "2020",
"duration": 278,
"track": "01",
"path": ["key", "summer pockets"],
},
]


def get_song_dir() -> str:
song_dir = get_tmp_dir()
for song_ in SONGS_INFO:
song = song_.copy()
duration, path = song["duration"], song["path"]
del song["duration"], song["path"]
create_audio_file(
os.path.join(song_dir, *path, f"{song["artist"]} - {song["title"]}.flac"),
"flac",
duration,
song,
)
return song_dir


def test_gui_local_match(qtbot: QtBot, monkeypatch: pytest.MonkeyPatch) -> None:
from LDDC.view.main_window import main_window

main_window.show()
main_window.set_current_widget(1)
qtbot.wait(300) # 等待窗口加载完成

monkeypatch.setattr(QFileDialog, "open", lambda *args, **kwargs: None) # noqa: ARG005
orig_song_dir = get_song_dir()
for file_name_mode_index, save2tagmode_index, save_mode_index in product(
range(main_window.local_match_widget.filename_mode_comboBox.count()),
range(main_window.local_match_widget.save2tag_mode_comboBox.count()),
range(main_window.local_match_widget.save_mode_comboBox.count()),
):
main_window.local_match_widget.songs_table.setRowCount(0)

file_name_mode = LocalMatchFileNameMode(file_name_mode_index)
save2tagmode = LocalMatchSave2TagMode(save2tagmode_index)
save_mode = LocalMatchSaveMode(save_mode_index)

song_dir = os.path.join(test_artifacts_path, "audio", "local_match", f"{file_name_mode.name}_{save2tagmode.name}_{save_mode.name}")
shutil.copytree(orig_song_dir, song_dir)
main_window.local_match_widget.select_dirs_button.click()
select_file(main_window.local_match_widget, song_dir)

save_path = os.path.join(test_artifacts_path, "lyrics", "local_match", f"{file_name_mode.name}_{save2tagmode.name}_{save_mode.name}")
main_window.local_match_widget.save_path_button.click()
select_file(main_window.local_match_widget, save_path)

main_window.local_match_widget.filename_mode_comboBox.setCurrentIndex(file_name_mode_index)
main_window.local_match_widget.save2tag_mode_comboBox.setCurrentIndex(save2tagmode_index)
main_window.local_match_widget.save_mode_comboBox.setCurrentIndex(save_mode_index)

def check_finished() -> bool:
return not main_window.local_match_widget.workers and not main_window.local_match_widget.status_label.text()

qtbot.waitUntil(check_finished, timeout=10000)
assert main_window.local_match_widget.songs_table.rowCount() == len(SONGS_INFO)
qtbot.wait(20)
grab(main_window, os.path.join(screenshot_path, f"local_match_prepare_{file_name_mode.name}_{save2tagmode.name}_{save_mode.name}.png"))
main_window.local_match_widget.start_cancel()
qtbot.waitUntil(check_finished, timeout=100000)
close_msg_boxs(main_window.local_match_widget)
qtbot.wait(150)
grab(main_window, os.path.join(screenshot_path, f"local_match_finish_{file_name_mode.name}_{save2tagmode.name}_{save_mode.name}.png"))

for row in range(main_window.local_match_widget.songs_table.rowCount()):
status_item = main_window.local_match_widget.songs_table.item(row, 6)
assert status_item
assert status_item.data(Qt.ItemDataRole.UserRole)["status"] == "成功"
if save2tagmode != LocalMatchSave2TagMode.ONLY_TAG:
with open(status_item.data(Qt.ItemDataRole.UserRole)["save_path"], encoding="utf-8") as f:
verify_lyrics(f.read())
if save2tagmode != LocalMatchSave2TagMode.ONLY_FILE:
for root, _dirs, files in os.walk(song_dir):
for file in files:
if file.endswith(".flac"):
verify_audio_lyrics(os.path.join(root, file))
12 changes: 1 addition & 11 deletions tests/test_gui_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

# ruff: noqa: S101
import os
import shutil
from itertools import combinations

import pytest
Expand All @@ -12,18 +11,9 @@
from PySide6.QtWidgets import QFileDialog
from pytestqt.qtbot import QtBot

from LDDC.res import resource_rc
from LDDC.utils.enum import LyricsFormat, SearchType, Source

from .helper import close_msg_boxs, create_audio_file, grab, select_file, verify_audio_lyrics, verify_lyrics

resource_rc.qInitResources()
test_artifacts_path = os.path.join(os.path.dirname(__file__), "artifacts")
screenshot_path = os.path.join(test_artifacts_path, "screenshots")
if os.path.exists(test_artifacts_path):
shutil.rmtree(test_artifacts_path)
os.makedirs(test_artifacts_path)
os.makedirs(screenshot_path)
from .helper import close_msg_boxs, create_audio_file, grab, screenshot_path, select_file, test_artifacts_path, verify_audio_lyrics, verify_lyrics


def search(qtbot: QtBot, search_type: SearchType, keyword: str) -> None:
Expand Down

0 comments on commit e961f57

Please sign in to comment.