import pathlib import tempfile from typing import cast from .test_main import CmmTestCase from chatmastermind.message import source_code, Message, MessageError, Question, Answer from chatmastermind.tags import Tag, TagLine class SourceCodeTestCase(CmmTestCase): def test_source_code_with_include_delims(self) -> None: text = """ Some text before the code block ```python print("Hello, World!") ``` Some text after the code block ```python x = 10 y = 20 print(x + y) ``` """ expected_result = [ " ```python\n print(\"Hello, World!\")\n ```\n", " ```python\n x = 10\n y = 20\n print(x + y)\n ```\n" ] result = source_code(text, include_delims=True) self.assertEqual(result, expected_result) def test_source_code_without_include_delims(self) -> None: text = """ Some text before the code block ```python print("Hello, World!") ``` Some text after the code block ```python x = 10 y = 20 print(x + y) ``` """ expected_result = [ " print(\"Hello, World!\")\n", " x = 10\n y = 20\n print(x + y)\n" ] result = source_code(text, include_delims=False) self.assertEqual(result, expected_result) def test_source_code_with_single_code_block(self) -> None: text = "```python\nprint(\"Hello, World!\")\n```" expected_result = ["```python\nprint(\"Hello, World!\")\n```\n"] result = source_code(text, include_delims=True) self.assertEqual(result, expected_result) def test_source_code_with_no_code_blocks(self) -> None: text = "Some text without any code blocks" expected_result: list[str] = [] result = source_code(text, include_delims=True) self.assertEqual(result, expected_result) class QuestionTestCase(CmmTestCase): def test_question_with_prefix(self) -> None: with self.assertRaises(MessageError): Question("=== QUESTION === What is your name?") def test_question_without_prefix(self) -> None: question = Question("What is your favorite color?") self.assertIsInstance(question, Question) self.assertEqual(question, "What is your favorite color?") class AnswerTestCase(CmmTestCase): def test_answer_with_prefix(self) -> None: with self.assertRaises(MessageError): Answer("=== ANSWER === Yes") def test_answer_without_prefix(self) -> None: answer = Answer("No") self.assertIsInstance(answer, Answer) self.assertEqual(answer, "No") class MessageToFileTxtTestCase(CmmTestCase): def setUp(self) -> None: self.file = tempfile.NamedTemporaryFile(delete=False, suffix='.txt') self.file_path = pathlib.Path(self.file.name) self.message = Message(Question('This is a question.'), Answer('This is an answer.'), {Tag('tag1'), Tag('tag2')}, self.file_path) def tearDown(self) -> None: self.file.close() self.file_path.unlink() def test_to_file_txt(self) -> None: self.message.to_file(self.file_path) with open(self.file_path, "r") as fd: content = fd.read() expected_content = f"""{TagLine.prefix} tag1 tag2 {Question.txt_header} This is a question. {Answer.txt_header} This is an answer. """ self.assertEqual(content, expected_content) def test_to_file_unsupported_file_type(self) -> None: unsupported_file_path = pathlib.Path("example.doc") with self.assertRaises(MessageError) as cm: self.message.to_file(unsupported_file_path) self.assertEqual(str(cm.exception), "File type '.doc' is not supported") def test_to_file_no_file_path(self) -> None: """ Provoke an exception using an empty path. """ with self.assertRaises(MessageError) as cm: # clear the internal file_path self.message.file_path = None self.message.to_file(None) self.assertEqual(str(cm.exception), "Got no valid path to write message") # reset the internal file_path self.message.file_path = self.file_path class MessageToFileYamlTestCase(CmmTestCase): def setUp(self) -> None: self.file = tempfile.NamedTemporaryFile(delete=False, suffix='.yaml') self.file_path = pathlib.Path(self.file.name) self.message = Message(Question('This is a question.'), Answer('This is an answer.'), {Tag('tag1'), Tag('tag2')}, self.file_path) self.message_multiline = Message(Question('This is a\nmultiline question.'), Answer('This is a\nmultiline answer.'), {Tag('tag1'), Tag('tag2')}, self.file_path) def tearDown(self) -> None: self.file.close() self.file_path.unlink() def test_to_file_yaml(self) -> None: self.message.to_file(self.file_path) with open(self.file_path, "r") as fd: content = fd.read() expected_content = "answer: This is an answer.\nquestion: This is a question.\ntags:\n- tag1\n- tag2\n" self.assertEqual(content, expected_content) def test_to_file_yaml_multiline(self) -> None: self.message_multiline.to_file(self.file_path) with open(self.file_path, "r") as fd: content = fd.read() expected_content = f"""{Answer.yaml_key}: |- This is a multiline answer. {Question.yaml_key}: |- This is a multiline question. {Message.tags_yaml_key}: - tag1 - tag2 """ self.assertEqual(content, expected_content) class MessageFromFileTxtTestCase(CmmTestCase): def setUp(self) -> None: self.file = tempfile.NamedTemporaryFile(delete=False, suffix='.txt') self.file_path = pathlib.Path(self.file.name) with open(self.file_path, "w") as fd: fd.write(f"""{TagLine.prefix} tag1 tag2 {Question.txt_header} This is a question. {Answer.txt_header} This is an answer. """) self.file_no_tags = tempfile.NamedTemporaryFile(delete=False, suffix='.txt') self.file_path_no_tags = pathlib.Path(self.file_no_tags.name) with open(self.file_path_no_tags, "w") as fd: fd.write(f"""{Question.txt_header} This is a question. {Answer.txt_header} This is an answer. """) def tearDown(self) -> None: self.file.close() self.file_no_tags.close() self.file_path.unlink() self.file_path_no_tags.unlink() def test_from_file_txt(self) -> None: message = Message.from_file(self.file_path) self.assertIsNotNone(message) self.assertIsInstance(message, Message) if message: self.assertEqual(message.question, 'This is a question.') self.assertEqual(message.answer, 'This is an answer.') self.assertSetEqual(cast(set[Tag], message.tags), {Tag('tag1'), Tag('tag2')}) self.assertEqual(message.file_path, self.file_path) def test_from_file_txt_no_tags(self) -> None: message = Message.from_file(self.file_path_no_tags) self.assertIsNotNone(message) self.assertIsInstance(message, Message) if message: self.assertEqual(message.question, 'This is a question.') self.assertEqual(message.answer, 'This is an answer.') self.assertSetEqual(cast(set[Tag], message.tags), set()) self.assertEqual(message.file_path, self.file_path_no_tags) def test_from_file_txt_tags_match(self) -> None: message = Message.from_file(self.file_path, tags_or={Tag('tag1')}) self.assertIsNotNone(message) self.assertIsInstance(message, Message) if message: self.assertEqual(message.question, 'This is a question.') self.assertEqual(message.answer, 'This is an answer.') self.assertSetEqual(cast(set[Tag], message.tags), {Tag('tag1'), Tag('tag2')}) self.assertEqual(message.file_path, self.file_path) def test_from_file_txt_tags_dont_match(self) -> None: message = Message.from_file(self.file_path, tags_or={Tag('tag3')}) self.assertIsNone(message) def test_from_file_txt_no_tags_dont_match(self) -> None: message = Message.from_file(self.file_path_no_tags, tags_or={Tag('tag1')}) self.assertIsNone(message) def test_from_file_txt_no_tags_match_tags_not(self) -> None: message = Message.from_file(self.file_path_no_tags, tags_not={Tag('tag1')}) self.assertIsNotNone(message) self.assertIsInstance(message, Message) if message: self.assertEqual(message.question, 'This is a question.') self.assertEqual(message.answer, 'This is an answer.') self.assertSetEqual(cast(set[Tag], message.tags), set()) self.assertEqual(message.file_path, self.file_path_no_tags) def test_from_file_not_exists(self) -> None: file_not_exists = pathlib.Path("example.txt") with self.assertRaises(MessageError) as cm: Message.from_file(file_not_exists) self.assertEqual(str(cm.exception), f"Message file '{file_not_exists}' does not exist") class MessageFromFileYamlTestCase(CmmTestCase): def setUp(self) -> None: self.file = tempfile.NamedTemporaryFile(delete=False, suffix='.yaml') self.file_path = pathlib.Path(self.file.name) with open(self.file_path, "w") as fd: fd.write(f""" {Question.yaml_key}: |- This is a question. {Answer.yaml_key}: |- This is an answer. {Message.tags_yaml_key}: - tag1 - tag2 """) self.file_no_tags = tempfile.NamedTemporaryFile(delete=False, suffix='.yaml') self.file_path_no_tags = pathlib.Path(self.file_no_tags.name) with open(self.file_path_no_tags, "w") as fd: fd.write(f""" {Question.yaml_key}: |- This is a question. {Answer.yaml_key}: |- This is an answer. """) def tearDown(self) -> None: self.file.close() self.file_path.unlink() def test_from_file_yaml(self) -> None: message = Message.from_file(self.file_path) self.assertIsInstance(message, Message) self.assertIsNotNone(message) if message: self.assertEqual(message.question, 'This is a question.') self.assertEqual(message.answer, 'This is an answer.') self.assertSetEqual(cast(set[Tag], message.tags), {Tag('tag1'), Tag('tag2')}) self.assertEqual(message.file_path, self.file_path) def test_from_file_yaml_no_tags(self) -> None: message = Message.from_file(self.file_path_no_tags) self.assertIsInstance(message, Message) self.assertIsNotNone(message) if message: self.assertEqual(message.question, 'This is a question.') self.assertEqual(message.answer, 'This is an answer.') self.assertSetEqual(cast(set[Tag], message.tags), set()) self.assertEqual(message.file_path, self.file_path_no_tags) def test_from_file_not_exists(self) -> None: file_not_exists = pathlib.Path("example.yaml") with self.assertRaises(MessageError) as cm: Message.from_file(file_not_exists) self.assertEqual(str(cm.exception), f"Message file '{file_not_exists}' does not exist") def test_from_file_yaml_tags_match(self) -> None: message = Message.from_file(self.file_path, tags_or={Tag('tag1')}) self.assertIsNotNone(message) self.assertIsInstance(message, Message) if message: self.assertEqual(message.question, 'This is a question.') self.assertEqual(message.answer, 'This is an answer.') self.assertSetEqual(cast(set[Tag], message.tags), {Tag('tag1'), Tag('tag2')}) self.assertEqual(message.file_path, self.file_path) def test_from_file_yaml_tags_dont_match(self) -> None: message = Message.from_file(self.file_path, tags_or={Tag('tag3')}) self.assertIsNone(message) def test_from_file_yaml_no_tags_dont_match(self) -> None: message = Message.from_file(self.file_path_no_tags, tags_or={Tag('tag1')}) self.assertIsNone(message) def test_from_file_yaml_no_tags_match_tags_not(self) -> None: message = Message.from_file(self.file_path_no_tags, tags_not={Tag('tag1')}) self.assertIsNotNone(message) self.assertIsInstance(message, Message) if message: self.assertEqual(message.question, 'This is a question.') self.assertEqual(message.answer, 'This is an answer.') self.assertSetEqual(cast(set[Tag], message.tags), set()) self.assertEqual(message.file_path, self.file_path_no_tags)