diff --git a/.gitignore b/.gitignore index 9799510..fb3c037 100644 --- a/.gitignore +++ b/.gitignore @@ -161,4 +161,5 @@ cython_debug/ # KKAFIO stuff traceback.log -app/config/ \ No newline at end of file +app/config/ +test/ diff --git a/test.py b/test.py new file mode 100644 index 0000000..f7559b6 --- /dev/null +++ b/test.py @@ -0,0 +1,209 @@ +import concurrent.futures +import requests +import json +import patoolib +import logging +import shutil + +from bs4 import BeautifulSoup +from pathlib import Path +from util.config import Config +from util.file_manager import FileManager +from modules.create_backup import CreateBackup +from modules.fc_kks import FilterConvertKKS +from modules.install_chara import InstallChara +from modules.remove_chara import RemoveChara + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +CWD = Path.cwd() +TEST_PATH = CWD / "test" +GAMEPATH = TEST_PATH / "Koikatsu Party" +BACKUP_PATH = TEST_PATH / "Backup" +DOWNLOAD_PATH = TEST_PATH / "Downloads" + + +if TEST_PATH.exists() and TEST_PATH.is_dir(): + shutil.rmtree(TEST_PATH) + +paths_to_check = [ + TEST_PATH, + BACKUP_PATH, + DOWNLOAD_PATH, + GAMEPATH / "UserData", + GAMEPATH / "BepInEx", + GAMEPATH / "mods", + GAMEPATH / "UserData" / "chara" / "female", + GAMEPATH / "UserData" / "coordinate", + GAMEPATH / "UserData" / "Overlays" +] + +for path in paths_to_check: + path.mkdir(parents=True, exist_ok=True) + +def create_config(): + """Creates and saves the configuration file.""" + data = { + "Core": {"GamePath": str(GAMEPATH)}, + "CreateBackup": { + "Enable": True, + "OutputPath": str(BACKUP_PATH), + "BepInEx": False, + "Filename": "koikatsu_backup", + "mods": False, + "UserData": False, + }, + "FilterConvertKKS": { + "Convert": True, + "InputPath": str(DOWNLOAD_PATH), + "Enable": True, + }, + "InstallChara": { + "Password": "Skip", + "FileConflicts": "Skip", + "Enable": True, + "InputPath": str(DOWNLOAD_PATH), + }, + "RemoveChara": { + "Enable": True, + "InputPath": str(DOWNLOAD_PATH), + }, + } + + config_path = TEST_PATH / 'config/config.json' + config_path.parent.mkdir(parents=True, exist_ok=True) + with open(config_path, "w") as f: + json.dump(data, f, indent=4) + return Config(config_path) + + +CONFIG = create_config() +FILE_MANAGER = FileManager(CONFIG) + + +def valid_link(link_button): + """Check if a link is a valid download button.""" + return link_button.text == 'Download' and link_button.get('href') + + +def get_card_urls(bepis_url: str) -> list[str]: + """Extract card download URLs from a bepis page.""" + try: + response = requests.get(bepis_url) + response.raise_for_status() + except requests.RequestException as e: + logger.error(f"Error fetching {bepis_url}: {e}") + return [] + + soup = BeautifulSoup(response.text, 'html.parser') + link_buttons = soup.find_all('a', class_='btn btn-primary btn-sm') + return ['https://db.bepis.moe' + link_button.get('href') for link_button in link_buttons if valid_link(link_button)] + + +def download_card(card_url: str) -> Path: + """Download a card from a given URL.""" + card_name = Path(card_url).name + card_path = DOWNLOAD_PATH / card_name + + try: + with requests.get(card_url, stream=True) as response: + response.raise_for_status() + with open(card_path, "wb") as out_file: + out_file.write(response.content) + logger.info(f"Downloaded {card_name}") + return card_path + except requests.RequestException as e: + logger.error(f"Error downloading {card_url}: {e}") + return None + + +def download(bepis_url: str): + """Download all cards from a given bepis URL using a thread pool.""" + download_urls = get_card_urls(bepis_url) + with concurrent.futures.ThreadPoolExecutor() as executor: + results = list(executor.map(download_card, download_urls)) + + return set(filter(None, results)) + + +def test_fckss(kk_cards, kks_cards): + """Test FilterConvertKKS functionality.""" + fckss = FilterConvertKKS(CONFIG, FILE_MANAGER) + fckss.run() + + filter_path = DOWNLOAD_PATH / '_KKS_card_' + conversion_path = DOWNLOAD_PATH / '_KKS_to_KK_' + + assert filter_path.exists(), "Filter path does not exist." + assert conversion_path.exists(), "Conversion path does not exist." + + for kk_path in kk_cards: + card_name = kk_path.name + filtered_kks_path = filter_path / card_name + converted_kks_path = conversion_path / f"KKS2KK_{card_name}" + + assert not filtered_kks_path.exists(), f"{filtered_kks_path} exists but should not." + assert not converted_kks_path.exists(), f"{converted_kks_path} exists but should not." + + for kks_path in kks_cards: + card_name = kks_path.name + filtered_kks_path = filter_path / card_name + converted_kks_path = conversion_path / f"KKS2KK_{card_name}" + assert filtered_kks_path.exists(), f"{filtered_kks_path} does not exist." + assert converted_kks_path.exists(), f"{converted_kks_path} does not exist." + kk_cards.add(converted_kks_path) + + +def test_install(kk_cards): + """Test character installation.""" + install_chara = InstallChara(CONFIG, FILE_MANAGER) + install_chara.run() + + chara_path = GAMEPATH / 'UserData' / 'chara' / 'female' + + for card in kk_cards: + assert (chara_path / card.name).exists(), f"{card.name} not found in installed cards." + + +def test_backup(kk_cards): + """Test backup functionality.""" + create_backup = CreateBackup(CONFIG, FILE_MANAGER) + create_backup.run() + + koikatsu_backup = BACKUP_PATH / 'koikatsu_backup.7z' + assert koikatsu_backup.exists(), "Backup file does not exist." + + outdir = BACKUP_PATH / 'outdir' + patoolib.extract_archive(str(koikatsu_backup), outdir=str(outdir)) + + for card in kk_cards: + assert (outdir / "UserData" / "chara" / "female" / card.name).exists(), f"{card.name} missing in backup." + + +def test_remove(): + """Test character removal.""" + remove_chara = RemoveChara(CONFIG, FILE_MANAGER) + remove_chara.run() + + chara_path = GAMEPATH / 'UserData' / 'chara' / 'female' + assert not list(chara_path.iterdir()), "Character directory not empty after removal." + + +def main(): + """Main function to run all tests.""" + kk_cards = download('https://db.bepis.moe/koikatsu?type=base') + kks_cards = download('https://db.bepis.moe/koikatsu?type=sunshine') + + if kk_cards and kks_cards: + test_fckss(kk_cards, kks_cards) + test_install(kk_cards) + test_backup(kk_cards) + test_remove() + shutil.rmtree(TEST_PATH) + else: + logger.error("No cards downloaded. Exiting.") + + +if __name__ == '__main__': + main() diff --git a/test/Backup/.gitignore b/test/Backup/.gitignore deleted file mode 100644 index 86d0cb2..0000000 --- a/test/Backup/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore \ No newline at end of file diff --git a/test/Koikatsu Party/BepInEx/.gitignore b/test/Koikatsu Party/BepInEx/.gitignore deleted file mode 100644 index 86d0cb2..0000000 --- a/test/Koikatsu Party/BepInEx/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore \ No newline at end of file diff --git a/test/Koikatsu Party/UserData/Overlays/.gitignore b/test/Koikatsu Party/UserData/Overlays/.gitignore deleted file mode 100644 index 86d0cb2..0000000 --- a/test/Koikatsu Party/UserData/Overlays/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore \ No newline at end of file diff --git a/test/Koikatsu Party/UserData/chara/female/.gitignore b/test/Koikatsu Party/UserData/chara/female/.gitignore deleted file mode 100644 index 86d0cb2..0000000 --- a/test/Koikatsu Party/UserData/chara/female/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore \ No newline at end of file diff --git a/test/Koikatsu Party/UserData/chara/male/.gitignore b/test/Koikatsu Party/UserData/chara/male/.gitignore deleted file mode 100644 index 86d0cb2..0000000 --- a/test/Koikatsu Party/UserData/chara/male/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore \ No newline at end of file diff --git a/test/Koikatsu Party/UserData/coordinate/.gitignore b/test/Koikatsu Party/UserData/coordinate/.gitignore deleted file mode 100644 index 86d0cb2..0000000 --- a/test/Koikatsu Party/UserData/coordinate/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore \ No newline at end of file diff --git a/test/Koikatsu Party/mods/.gitignore b/test/Koikatsu Party/mods/.gitignore deleted file mode 100644 index 86d0cb2..0000000 --- a/test/Koikatsu Party/mods/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore \ No newline at end of file