From ee8d615531db308b1c12818f85cd0b0aa2a039f1 Mon Sep 17 00:00:00 2001 From: Ghytro Date: Thu, 7 Nov 2024 20:49:19 +0300 Subject: [PATCH] tests for business logic --- bot/__pycache__/exception.cpython-310.pyc | Bin 0 -> 832 bytes bot/__pycache__/msgprocessor.cpython-310.pyc | Bin 0 -> 4795 bytes bot/msgprocessor.py | 22 ++-- bot/msgprocessor_test.py | 117 +++++++++++++++++++ 4 files changed, 131 insertions(+), 8 deletions(-) create mode 100644 bot/__pycache__/exception.cpython-310.pyc create mode 100644 bot/__pycache__/msgprocessor.cpython-310.pyc create mode 100644 bot/msgprocessor_test.py diff --git a/bot/__pycache__/exception.cpython-310.pyc b/bot/__pycache__/exception.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..08003b142a14d7c615a8ed5b7b5c8aae87e9c6ec GIT binary patch literal 832 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 literal 0 HcmV?d00001 diff --git a/bot/msgprocessor.py b/bot/msgprocessor.py index 229305d..79b10f1 100644 --- a/bot/msgprocessor.py +++ b/bot/msgprocessor.py @@ -2,15 +2,16 @@ from typing import Callable from dataclasses import dataclass from exception import UrlRemoverNotImplementedException from urllib.parse import urlparse, parse_qs, urlencode, urlunparse +import re -@dataclass(init=True) +@dataclass(init=True, eq=True) class TrackerRemovalProcessorMessage: fromUsername: str text: str -@dataclass(frozen=True, init=True) +@dataclass(frozen=True, init=True, eq=True) class TrackerRemovalResult: needsToReply: bool text: str @@ -35,7 +36,9 @@ class TrackerRemovalMsgProcessor: SCHEMES = ["http://", "https://"] return len([s for s in SCHEMES if url.startswith(s)]) != 0 - lexems = self.__msg.text.split() + SEPARATOR_CHARS = [" ", "\n"] + separator_regex = "("+"|".join(SEPARATOR_CHARS)+")" + lexems = re.split(separator_regex, self.__msg.text) for i, l in enumerate(lexems): if not is_url(l): continue @@ -47,12 +50,15 @@ class TrackerRemovalMsgProcessor: trackers_extracted = True lexems[i] = removed_trackers_url - self.__msg.text = " ".join(lexems) + self.__msg.text = "".join(lexems) return trackers_extracted @staticmethod def __remove_tracker(url: str) -> str: - parsed_url = urlparse(url) + try: + parsed_url = urlparse(url) + except Exception: + return url if parsed_url.hostname is None: return url hostname = str(parsed_url.hostname) @@ -62,7 +68,7 @@ class TrackerRemovalMsgProcessor: return url def __emplace_sender_into_msg_text(self): - self.__msg.text = f'Message from {self.__msg.fromUsername}:\n\n{self.__msg.text}' + self.__msg.text = f'Message from @{self.__msg.fromUsername}:\n\n{self.__msg.text}' class TrackerRemoverFactory: @@ -82,9 +88,9 @@ class TrackerRemoverFactory: ) ] remover_one = [ - r + r for r in removers_by_domain - if len([d for d in r.domains if d.endswith(domain)]) != 0 + if len([d for d in r.domains if domain.endswith(d)]) != 0 ] if len(remover_one) == 0: raise UrlRemoverNotImplementedException(domain) diff --git a/bot/msgprocessor_test.py b/bot/msgprocessor_test.py new file mode 100644 index 0000000..5cff4de --- /dev/null +++ b/bot/msgprocessor_test.py @@ -0,0 +1,117 @@ +import unittest +from msgprocessor import ( + TrackerRemovalMsgProcessor, + TrackerRemoverFactory, + TrackerRemovalProcessorMessage, + TrackerRemovalResult, +) + + +class TestRemoverFactory(unittest.TestCase): + factory = TrackerRemoverFactory() + + def test_remove_strategy_constructor(self): + test_case_data = [ + { + "domain": "youtube.com", + "remover": self.factory.remove_yt_trackers + }, + { + "domain": "lowerlevel.youtube.com", + "remover": self.factory.remove_yt_trackers + }, + { + "domain": "youtu.be", + "remover": self.factory.remove_yt_trackers, + }, + { + "domain": "something.youtu.be", + "remover": self.factory.remove_yt_trackers, + } + ] + for test_case in test_case_data: + self.assertIs( + self.factory.make_remover(test_case["domain"]), + self.factory.remove_yt_trackers, + ) + + def test_remove_yt_si(self): + test_case_data = [ + { + "url": "https://youtu.be/jNQXAC9IVRw?si=qLIZT1rvs99_jbgy", + "expected_url": "https://youtu.be/jNQXAC9IVRw" + }, + { + "url": "https://youtu.be/jNQXAC9IVRw?si=qLIZT1rvs99_jbgy&t=16", + "expected_url": "https://youtu.be/jNQXAC9IVRw?t=16" + }, + { + "url": "https://www.youtube.com/watch?v=jNQXAC9IVRw", + "expected_url": "https://www.youtube.com/watch?v=jNQXAC9IVRw" + }, + { + "url": "http://www.youtube.com/watch?v=jNQXAC9IVRw&si=qLIZT1rvs99_jbgy&t=16", + "expected_url": "http://www.youtube.com/watch?v=jNQXAC9IVRw&t=16" + } + ] + for test_case in test_case_data: + self.assertEqual(self.factory.remove_yt_trackers(test_case["url"]), test_case["expected_url"]) + + +class TestRemovalMsgProcessor(unittest.TestCase): + def test_remove_links(self): + test_case_data = [ + { + "msg_text": "https://youtu.be/jNQXAC9IVRw?si=qLIZT1rvs99_jbgy", + "sender_username": "Ghytro", + "bot_responded": True, + "bot_response": "Message from @Ghytro:\n\nhttps://youtu.be/jNQXAC9IVRw" + }, + { + "msg_text": "чекай https://youtu.be/jNQXAC9IVRw?si=qLIZT1rvs99_jbgy\nнаш слон хд", + "sender_username": "OllyHearn", + "bot_responded": True, + "bot_response": "Message from @OllyHearn:\n\nчекай https://youtu.be/jNQXAC9IVRw\nнаш слон хд" + }, + { + "msg_text": "а я такая нитакуся без si ссылки шлю сразу https://youtu.be/jNQXAC9IVRw и по нескольку штук\nhttp://www.youtube.com/watch?v=jNQXAC9IVRw&si=qLIZT1rvs99_jbgy&t=16 дада", + "sender_username": "OllyHearn", + "bot_responded": True, + "bot_response": "Message from @OllyHearn:\n\nа я такая нитакуся без si ссылки шлю сразу https://youtu.be/jNQXAC9IVRw и по нескольку штук\nhttp://www.youtube.com/watch?v=jNQXAC9IVRw&t=16 дада" + }, + { + "msg_text": "asdasdasdasdasdasdasd asdasd asdasd asdad sasa dadsas", + "sender_username": "Ghytro", + "bot_responded": False, + "bot_response": "" + } + ] + for test_case in test_case_data: + result = TrackerRemovalMsgProcessor( + TrackerRemovalProcessorMessage( + fromUsername=test_case["sender_username"], + text=test_case["msg_text"] + ) + ).process() + self.assertEqual( + result, + TrackerRemovalResult( + needsToReply=test_case["bot_responded"], + text=test_case["bot_response"] + ) + ) + +if __name__ == "__main__": + test_classes_to_run = [TestRemoverFactory, TestRemovalMsgProcessor] + + loader = unittest.TestLoader() + + suites_list = [] + for test_class in test_classes_to_run: + suite = loader.loadTestsFromTestCase(test_class) + suites_list.append(suite) + + big_suite = unittest.TestSuite(suites_list) + + runner = unittest.TextTestRunner() + results = runner.run(big_suite)