from __future__ import annotations import importlib import os import tempfile import unittest from pathlib import Path class LibraryDatabaseTest(unittest.TestCase): def setUp(self) -> None: self.temp = tempfile.TemporaryDirectory() os.environ["LIBRARY_DATA_DIR"] = self.temp.name os.environ.pop("BOOTSTRAP_ADMIN_USERNAME", None) os.environ.pop("BOOTSTRAP_ADMIN_PASSWORD_FILE", None) import library_db self.db = importlib.reload(library_db) self.db.initialize_database() def tearDown(self) -> None: self.temp.cleanup() def test_password_hash_is_salted_and_verifiable(self) -> None: first = self.db.hash_password("safe-password-123") second = self.db.hash_password("safe-password-123") self.assertNotEqual(first, second) self.assertTrue(self.db.verify_password("safe-password-123", first)) self.assertFalse(self.db.verify_password("wrong-password", first)) def test_session_round_trip(self) -> None: with self.db.connect() as connection: cursor = connection.execute( """ INSERT INTO users (username, display_name, password_hash, created_at) VALUES ('tester', '테스터', ?, ?) """, (self.db.hash_password("safe-password-123"), self.db.utc_now()), ) user_id = cursor.lastrowid token, csrf = self.db.create_session(user_id) user = self.db.get_user_for_session(token) self.assertIsNotNone(user) self.assertEqual(user["username"], "tester") self.assertEqual(user["csrf_token"], csrf) self.db.delete_session(token) self.assertIsNone(self.db.get_user_for_session(token)) def test_database_directory_is_private_project_data(self) -> None: self.assertTrue(Path(self.temp.name, "library.sqlite3").is_file()) self.assertTrue(Path(self.temp.name, "midi").is_dir()) def test_graded_samples_are_two_hand_piano_solos(self) -> None: for sample in self.db.SAMPLES: self.assertEqual(sample["arrangement"], "piano_solo") self.assertIn("양손", sample["tags"]) self.assertNotIn("오른손", sample["tags"]) self.assertNotIn("쉬운 반주", sample["tags"]) def test_withdrawn_practice_collection_is_not_seeded(self) -> None: names = {f"practice-burgmuller-{number:02}.mid" for number in range(1, 19)} names.update(f"practice-schumann-{number:02}.mid" for number in range(1, 13)) with self.db.connect() as connection: rows = connection.execute( "SELECT seed_key, visibility, min_tier, owner_id FROM midi_items WHERE seed_key IS NOT NULL" ).fetchall() matching = {row["seed_key"]: row for row in rows if row["seed_key"] in names} self.assertFalse(matching) self.assertFalse(any(Path(self.temp.name, "midi", name).exists() for name in names)) self.assertFalse(any(row["seed_key"] in self.db.LEGACY_SAMPLE_KEYS for row in rows)) if __name__ == "__main__": unittest.main()