#!/usr/bin/env python3 """ Тесты для app.py — изолированные, без внешних зависимостей. Запуск: python3 -m unittest test_app -v """ import sys import os sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import unittest from app import ( extract_hash_from_result, generate_clean_magnet, parse_size_to_bytes, parse_size, extract_resolution, extract_quality, generate_search_variants, score_torrent, normalize_search_term, is_movie_torrent, ) class TestExtractHash(unittest.TestCase): def test_direct_hash_field(self): result = {"Hash": "08ada5a7a6183aae1e09d831df6748d566095a10"} self.assertEqual(extract_hash_from_result(result), "08ADA5A7A6183AAE1E09D831DF6748D566095A10") def test_hash_from_magnet(self): result = { "Hash": "", "Magnet": "magnet:?xt=urn:btih:08ada5a7a6183aae1e09d831df6748d566095a10&dn=test" } self.assertEqual(extract_hash_from_result(result), "08ADA5A7A6183AAE1E09D831DF6748D566095A10") def test_hash_from_info_hash(self): result = {"InfoHash": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0"} self.assertEqual( extract_hash_from_result(result), "A1B2C3D4E5F6A7B8C9D0E1F2A3B4C5D6E7F8A9B0" ) def test_empty_result(self): self.assertEqual(extract_hash_from_result({}), "") self.assertEqual(extract_hash_from_result({"Hash": ""}), "") def test_hash_from_torrent_url_no_btih(self): result = {"Torrent": "https://rutracker.org/forum/dl.php?t=123456"} self.assertEqual(extract_hash_from_result(result), "") def test_case_insensitive_hash(self): result = {"Hash": "08ada5a7a6183aae1e09d831df6748d566095a10"} self.assertEqual(extract_hash_from_result(result), "08ADA5A7A6183AAE1E09D831DF6748D566095A10") def test_id_field_as_hash(self): result = {"Id": "08ada5a7a6183aae1e09d831df6748d566095a10"} self.assertEqual(extract_hash_from_result(result), "08ADA5A7A6183AAE1E09D831DF6748D566095A10") def test_non_hash_id_field(self): result = {"Id": "12345", "Hash": ""} self.assertEqual(extract_hash_from_result(result), "") def test_hash_from_lowercase_field(self): result = {"hash": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0"} self.assertEqual( extract_hash_from_result(result), "A1B2C3D4E5F6A7B8C9D0E1F2A3B4C5D6E7F8A9B0" ) class TestGenerateCleanMagnet(unittest.TestCase): def test_basic_magnet(self): magnet = generate_clean_magnet("08ada5a7a6183aae1e09d831df6748d566095a10", "Test Movie") self.assertTrue(magnet.startswith("magnet:?xt=urn:btih:08ada5a7a6183aae1e09d831df6748d566095a10")) self.assertIn("&dn=Test%20Movie", magnet) self.assertIn("&tr=udp://tracker.opentrackr.org:1337/announce", magnet) self.assertIn("&tr=udp://tracker.openbittorrent.com:6969/announce", magnet) def test_empty_hash(self): self.assertEqual(generate_clean_magnet(""), "") self.assertEqual(generate_clean_magnet(None), "") def test_no_title(self): magnet = generate_clean_magnet("08ada5a7a6183aae1e09d831df6748d566095a10") self.assertTrue(magnet.startswith("magnet:?xt=urn:btih:")) self.assertNotIn("&dn=", magnet) def test_cyrillic_title(self): magnet = generate_clean_magnet("a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0", "Терминатор 2") self.assertIn("&dn=%D0%A2%D0%B5%D1%80%D0%BC%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%202", magnet) def test_has_trackers(self): magnet = generate_clean_magnet("a" * 40) expected_trackers = [ "tracker.opentrackr.org", "open.stealth.si", "tracker.openbittorrent.com", "tracker.tamersunion.org", "exodus.desync.com", "tracker.moeking.me", ] for tracker in expected_trackers: self.assertIn(tracker, magnet, f"Missing tracker: {tracker}") def test_no_dead_trackers(self): magnet = generate_clean_magnet("a" * 40) self.assertNotIn("coppersurfer.tk", magnet) self.assertNotIn("leechers-paradise.org", magnet) class TestParseSize(unittest.TestCase): def test_gb(self): bytes_size, readable = parse_size("25.3 GB") self.assertEqual(bytes_size, int(25.3 * 1024**3)) self.assertEqual(readable, "25.3 GB") def test_mb(self): bytes_size, readable = parse_size("6.2 MB") self.assertEqual(bytes_size, int(6.2 * 1024**2)) def test_kb(self): bytes_size, readable = parse_size("512 KB") self.assertEqual(bytes_size, 512 * 1024) def test_empty(self): bytes_size, readable = parse_size("") self.assertEqual(bytes_size, 0) self.assertEqual(readable, "Неизвестно") def test_none(self): bytes_size, readable = parse_size(None) self.assertEqual(bytes_size, 0) self.assertEqual(readable, "Неизвестно") class TestParseSizeToBytes(unittest.TestCase): def test_gb(self): result = parse_size_to_bytes("25.3 GB") self.assertAlmostEqual(result, 25.3 * 1024**3, delta=1) def test_mb(self): result = parse_size_to_bytes("500 MB") self.assertEqual(result, 500 * 1024**2) def test_empty(self): self.assertEqual(parse_size_to_bytes(""), 0) class TestExtractResolution(unittest.TestCase): def test_2160p(self): self.assertEqual(extract_resolution("Movie 2024 UHD 2160p BluRay"), "2160p") def test_4k(self): self.assertEqual(extract_resolution("Movie 2024 4K HDR"), "2160p") def test_1080p(self): self.assertEqual(extract_resolution("Movie 2024 1080p WEB-DL"), "1080p") def test_720p(self): self.assertEqual(extract_resolution("Movie 2024 720p HDTV"), "720p") def test_unknown(self): self.assertEqual(extract_resolution("Movie Unknown Quality"), "Неизвестно") class TestExtractQuality(unittest.TestCase): def test_bluray(self): self.assertEqual(extract_quality("Movie 2024 Bluray 1080p"), "BluRay") def test_bdrip(self): self.assertEqual(extract_quality("Movie 2024 BDRip 720p"), "BluRay") def test_webdl(self): self.assertEqual(extract_quality("Movie 2024 WEB-DL 1080p"), "WEB-DL") def test_webrip(self): self.assertEqual(extract_quality("Movie 2024 WEBRip 720p"), "WEBRip") def test_hdtv(self): self.assertEqual(extract_quality("Movie 2024 HDTV 720p"), "HDTV") def test_unknown(self): self.assertEqual(extract_quality("Movie 2024 Some Quality"), "Unknown") class TestNormalizeSearchTerm(unittest.TestCase): def test_basic(self): self.assertEqual(normalize_search_term("The Terminator"), "Terminator") def test_with_articles(self): self.assertEqual(normalize_search_term("The Matrix Revolutions"), "Matrix.Revolutions") def test_empty(self): self.assertEqual(normalize_search_term(""), "") self.assertEqual(normalize_search_term(None), "") def test_spaces_to_dots(self): self.assertEqual(normalize_search_term("Harry Potter"), "Harry.Potter") class TestGenerateSearchVariants(unittest.TestCase): def test_basic(self): variants = generate_search_variants("Terminator", "The Terminator", "1984") self.assertIn("Terminator", variants) self.assertIn("The Terminator", variants) self.assertIn("Terminator 1984", variants) def test_terminator_special(self): variants = generate_search_variants("Терминатор 2", "Terminator 2", "1991") self.assertIn("T2", variants) self.assertIn("T2.Judgment.Day", variants) def test_no_duplicates(self): variants = generate_search_variants("Terminator", "Terminator", "1984") self.assertEqual(len(variants), len(set(variants))) class TestScoreTorrent(unittest.TestCase): def test_high_score_exact_match(self): torrent = { "title": "The Terminator 1984 1080p BluRay", "quality": "BluRay", "resolution": "1080p", "seeds": 150, } score = score_torrent(torrent, "Terminator", "The Terminator", "1984") self.assertGreater(score, 0.8) def test_low_score_no_match(self): torrent = { "title": "Some Other Movie 2023 720p WEB-DL", "quality": "WEB-DL", "resolution": "720p", "seeds": 5, } score = score_torrent(torrent, "Terminator", "The Terminator", "1984") self.assertAlmostEqual(score, 0.3) def test_score_capped_at_one(self): torrent = { "title": "The Terminator 1984 2160p BluRay", "quality": "BluRay", "resolution": "2160p", "seeds": 200, } score = score_torrent(torrent, "The Terminator", "The Terminator", "1984") self.assertLessEqual(score, 1.0) class TestIsMovieTorrent(unittest.TestCase): def test_is_movie(self): self.assertTrue(is_movie_torrent("The Terminator 1984 BluRay", "Terminator", "The Terminator")) def test_not_movie_excluded_keyword(self): self.assertFalse(is_movie_torrent("The Game 1997 1080p BluRay", "The Game", "")) def test_not_movie_unknown_title(self): self.assertFalse(is_movie_torrent("Some Other Movie 2023 720p", "Terminator", "The Terminator")) if __name__ == "__main__": unittest.main()