import os import tempfile import unittest from datetime import date from werkzeug.security import generate_password_hash from app import create_app from app.database import get_db, init_db class AppTestCase(unittest.TestCase): def setUp(self): self.db_fd, self.db_path = tempfile.mkstemp() self.app = create_app( { "TESTING": True, "DATABASE": self.db_path, "SECRET_KEY": "test-secret", } ) with self.app.app_context(): init_db() db = get_db() db.execute( """ INSERT INTO admins (username, password_hash) VALUES (?, ?) """, ("admin", generate_password_hash("password")), ) db.commit() self.client = self.app.test_client() def tearDown(self): os.close(self.db_fd) os.unlink(self.db_path) def seed_question(self, question_date=None): if question_date is None: question_date = date.today().isoformat() with self.app.app_context(): db = get_db() db.execute( """ INSERT INTO questions (question, option_a, option_b, date) VALUES (?, ?, ?, ?) """, ("Would you rather test A or test B?", "Test A", "Test B", question_date), ) db.commit() def login(self): return self.client.post( "/admin/login", data={"username": "admin", "password": "password"}, follow_redirects=True, ) def test_public_empty_state(self): response = self.client.get("/") self.assertEqual(response.status_code, 200) self.assertIn(b"No question is scheduled yet.", response.data) def test_voting_flow_blocks_duplicate_vote(self): self.seed_question() first = self.client.post("/vote", data={"qid": "1", "vote": "A"}) second = self.client.post("/vote", data={"qid": "1", "vote": "A"}) self.assertEqual(first.status_code, 302) self.assertEqual(second.status_code, 302) with self.app.app_context(): count = get_db().execute("SELECT COUNT(*) FROM votes").fetchone()[0] self.assertEqual(count, 1) def test_homepage_uses_todays_question_only(self): self.seed_question("2030-01-01") response = self.client.get("/") self.assertIn(b"No question is scheduled yet.", response.data) self.seed_question() response = self.client.get("/") self.assertIn(b"Would you rather test A or test B?", response.data) def test_vote_rejects_non_today_question(self): self.seed_question("2030-01-01") response = self.client.post("/vote", data={"qid": "1", "vote": "A"}) self.assertEqual(response.status_code, 302) with self.app.app_context(): count = get_db().execute("SELECT COUNT(*) FROM votes").fetchone()[0] self.assertEqual(count, 0) def test_admin_login_success_and_failure(self): failed = self.client.post( "/admin/login", data={"username": "admin", "password": "wrong"}, ) self.assertIn(b"Invalid username or password.", failed.data) success = self.login() self.assertIn(b"Questions", success.data) def test_protected_route_redirects_to_login(self): response = self.client.get("/admin/dashboard") self.assertEqual(response.status_code, 302) self.assertIn("/admin/login", response.headers["Location"]) def test_question_create_duplicate_date_failure(self): self.seed_question() self.login() response = self.client.post( "/admin/question/new", data={ "date": date.today().isoformat(), "question": "Another question?", "option_a": "A", "option_b": "B", }, ) self.assertIn(b"Date already has a question.", response.data) def test_admin_can_change_credentials(self): self.login() response = self.client.post( "/admin/account", data={ "username": "newadmin", "current_password": "password", "new_password": "new-password", "confirm_password": "new-password", }, follow_redirects=True, ) self.assertIn(b"Admin credentials updated.", response.data) self.client.get("/admin/logout") old_login = self.client.post( "/admin/login", data={"username": "admin", "password": "password"}, ) self.assertIn(b"Invalid username or password.", old_login.data) new_login = self.client.post( "/admin/login", data={"username": "newadmin", "password": "new-password"}, follow_redirects=True, ) self.assertIn(b"Questions", new_login.data) def test_admin_account_requires_current_password(self): self.login() response = self.client.post( "/admin/account", data={ "username": "newadmin", "current_password": "wrong", "new_password": "new-password", "confirm_password": "new-password", }, ) self.assertIn(b"Current password is incorrect.", response.data) if __name__ == "__main__": unittest.main()