diff --git a/bot/exts/info/codeblock/_instructions.py b/bot/exts/info/codeblock/_instructions.py index 57c4b7ad95..7204dbeae4 100644 --- a/bot/exts/info/codeblock/_instructions.py +++ b/bot/exts/info/codeblock/_instructions.py @@ -148,23 +148,7 @@ def get_instructions(content: str) -> str | None: instructions = _get_no_ticks_message(content) else: log.trace("Searching results for a code block with invalid ticks.") - bad_ticks = [block for block in blocks if block.tick != _parsing.BACKTICK] - block = None - if bad_ticks: - block = next( - ( - bad_tick - for bad_tick in bad_ticks - if any( - block - for block in blocks - if block != bad_tick - and bad_tick.content != block.content - and bad_tick.content not in block.content - ) - ), - None, - ) + block = next((block for block in blocks if block.tick != _parsing.BACKTICK), None) if block: log.trace("A code block exists but has invalid ticks.") diff --git a/bot/exts/info/codeblock/_parsing.py b/bot/exts/info/codeblock/_parsing.py index 22cbe4344e..021f2f4a26 100644 --- a/bot/exts/info/codeblock/_parsing.py +++ b/bot/exts/info/codeblock/_parsing.py @@ -6,8 +6,6 @@ from collections.abc import Sequence from typing import NamedTuple -import regex - from bot import constants from bot.log import get_logger from bot.utils import has_lines @@ -47,8 +45,6 @@ """, re.DOTALL | re.VERBOSE ) -# copy of _RE_CODE_BLOCK. Done like this for highlighting reasons (regex.compile doesn't properly highlight) -_REGEX_CODE_BLOCK = regex.compile(_RE_CODE_BLOCK.pattern, regex.DOTALL | regex.VERBOSE) _RE_LANGUAGE = re.compile( fr""" @@ -91,7 +87,7 @@ def find_faulty_code_blocks(message: str) -> Sequence[CodeBlock] | None: log.trace("Finding all code blocks in a message.") code_blocks = [] - for match in _REGEX_CODE_BLOCK.finditer(message, overlapped=True): + for match in _RE_CODE_BLOCK.finditer(message): # Used to ensure non-matched groups have an empty string as the default value. groups = match.groupdict("") language = groups["lang"].strip() # Strip the whitespace cause it's included in the group. diff --git a/tests/bot/exts/info/codeblock/test_instructions.py b/tests/bot/exts/info/codeblock/test_instructions.py new file mode 100644 index 0000000000..04b265d519 --- /dev/null +++ b/tests/bot/exts/info/codeblock/test_instructions.py @@ -0,0 +1,93 @@ +import unittest +from textwrap import dedent + +from bot.exts.info.codeblock import _instructions as instructions, _parsing as parsing + + +class ProvideBadTicksInstructionsTest(unittest.TestCase): + def __assert_is_instructions_for_message_bad_ticks_one(self, message: str) -> None: + code_blocks = parsing.find_faulty_code_blocks(message) + self.assertIsNotNone(code_blocks) + + # Type narrowing + if code_blocks is None: + return + + code_block = next((block for block in code_blocks if block.tick != parsing.BACKTICK), None) + self.assertIsNotNone(code_block) + + # Type narrowing + if code_block is None: + return + + expected_instructions_text = instructions._get_bad_ticks_message(code_block) + self.assertIsInstance(expected_instructions_text, str) + + # Type narrowing + if not isinstance(expected_instructions_text, str): + return + + instructions_text = instructions.get_instructions(message) + self.assertIsInstance(instructions_text, str) + + # Type narrowing + if not isinstance(instructions_text, str): + return + + self.assertEqual(instructions_text, expected_instructions_text) + + def test_should_provide_when_no_lang_spec_and_bad_ticks_are_used(self) -> None: + message = dedent(""" + ''' + \"\"\"Docstring\"\"\" + numbs = [1, 2, 3] + + for numb in numbs: + print(numb) + ''' + """).strip() + self.__assert_is_instructions_for_message_bad_ticks_one(message) + + def test_should_provide_when_correct_lang_spec_and_bad_ticks_are_used(self) -> None: + message = dedent(""" + '''py + \"\"\"Docstring\"\"\" + numbs = [1, 2, 3] + + for numb in numbs: + print(numb) + ''' + """).strip() + self.__assert_is_instructions_for_message_bad_ticks_one(message) + + def test_should_provide_when_wrong_lang_spec_and_bad_ticks_are_used(self) -> None: + message = dedent(""" + '''c + \"\"\"Docstring\"\"\" + numbs = [1, 2, 3] + + for numb in numbs: + print(numb) + ''' + """).strip() + self.__assert_is_instructions_for_message_bad_ticks_one(message) + + def test_should_provide_bad_ticks_are_used_in_two_identical_codeblocks(self) -> None: + message = dedent(""" + ''' + \"\"\"Docstring\"\"\" + numbs = [1, 2, 3] + + for numb in numbs: + print(numb) + ''' + + ''' + \"\"\"Docstring\"\"\" + numbs = [1, 2, 3] + + for numb in numbs: + print(numb) + ''' + """).strip() + self.__assert_is_instructions_for_message_bad_ticks_one(message) diff --git a/tests/bot/exts/info/codeblock/test_parsing.py b/tests/bot/exts/info/codeblock/test_parsing.py index 4507fcaa54..47892e8e57 100644 --- a/tests/bot/exts/info/codeblock/test_parsing.py +++ b/tests/bot/exts/info/codeblock/test_parsing.py @@ -30,6 +30,7 @@ def test_should_recognize_contained_codeblock(self): faulty_code_blocks = parsing.find_faulty_code_blocks(message) self.assertIsNone(faulty_code_blocks) + @unittest.expectedFailure def test_should_recognize_contained_codeblock_even_if_that_breaks_formatting(self): message = """``` ```py @@ -67,7 +68,6 @@ def test_should_not_recognize_quoting_single_quotes(self): self.assertIsNotNone(faulty_code_blocks) self.assertEqual(len(faulty_code_blocks), 0) - def test_should_not_recognize_normal_double_quotes(self): """normal double quotes refer to double quotes that appear normally in text to quote something""" message = """ "I am doing a long quote.