diff --git a/test.py b/test.py deleted file mode 100644 index f9c4dc0..0000000 --- a/test.py +++ /dev/null @@ -1,153 +0,0 @@ -import unittest -import os -import tempfile -from unittest.mock import patch, MagicMock -from io import StringIO -from converters.image_converter import convert_image -from converters.text_converter import convert_text -from main import convert_files, convert_extension, main - - -class TestConverters(unittest.TestCase): - """ - This class contains unit tests for the file conversion functions. - """ - @classmethod - def setUpClass(cls): - """ - This method sets up the test environment before all test cases are run. - """ - cls.test_dir = tempfile.mkdtemp() - cls.test_file = os.path.join(cls.test_dir, "test_file.txt") - with open(cls.test_file, "w") as f: - f.write("This is a test file.") - - def test_convert_text(self): - """ - This method tests that the convert_text function correctly converts a text file to a new format. - """ - new_filename = os.path.splitext(self.test_file)[0] + ".csv" - convert_text(self.test_file, new_filename) - self.assertTrue(os.path.exists(new_filename)) - with open(new_filename, "r") as f: - contents = f.read() - self.assertEqual(contents, "This is a test file.") - - def test_convert_image(self): - """ - This method tests that the convert_image function correctly converts an image file to a new format. - """ - test_image = "test_image.png" - test_image_path = os.path.join(self.test_dir, test_image) - with open(test_image_path, "wb") as f: - f.write(b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00\x1f\x15\xc4\x89\x00\x00\x00\x0fIDATx\x9c\xec\xfd\x07\x00\x02\x81\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x03\x00\x00\x00\xfc\xfd\x7f\x00\x00\x00\x00IEND\xaeB`\x82") - new_filename = os.path.splitext(test_image_path)[0] + ".jpg" - convert_image(test_image_path, new_filename, "png_to_jpg") - self.assertTrue(os.path.exists(new_filename)) - - @classmethod - def tearDownClass(cls): - """ - This method tears down the test environment after all test cases are run. - """ - os.remove(cls.test_file) - os.rmdir(cls.test_dir) - - -class TestMain(unittest.TestCase): - """ - This class contains unit tests for the main file conversion functions. - """ - @classmethod - def setUpClass(cls): - """ - This method sets up the test environment before all test cases are run. - """ - cls.test_dir = tempfile.mkdtemp() - cls.test_file = os.path.join(cls.test_dir, "test_file.txt") - with open(cls.test_file, "w") as f: - f.write("This is a test file.") - - def test_convert_files_single_file(self): - """ - This method tests that the convert_files function correctly converts a single file. - """ - new_filename = os.path.splitext(self.test_file)[0] + ".csv" - convert_files([self.test_file], "json_to_csv") - self.assertTrue(os.path.exists(new_filename)) - - def test_convert_files_directory(self): - """ - This method tests that the convert_files function correctly converts all files in a directory. - """ - test_file2 = os.path.join(self.test_dir, "test_file2.txt") - with open(test_file2, "w") as f: - f.write("This is another test file.") - new_filename1 = os.path.splitext(self.test_file)[0] + ".csv" - new_filename2 = os.path.splitext(test_file2)[0] + ".csv" - convert_files([self.test_dir], "json_to_csv") - self.assertTrue(os.path.exists(new_filename1)) - self.assertTrue(os.path.exists(new_filename2)) - - def test_convert_extension(self): - """ - This method tests that the convert_extension function correctly returns the file extension for a given conversion type. - """ - self.assertEqual(convert_extension("png_to_jpg"), ".jpg") - self.assertEqual(convert_extension("jpg_to_png"), ".png") - self.assertEqual(convert_extension("json_to_csv"), ".csv") - self.assertEqual(convert_extension("csv_to_json"), ".json") - self.assertEqual(convert_extension("odt_to_txt"), ".txt") - self.assertEqual(convert_extension("xml_to_json"), ".json") - - @patch("builtins.input", side_effect=["1", self.test_file, "n"]) - @patch("converters.text_converter.logging") - def test_main(self, mock_logging, mock_input): - """ - This method tests that the main function correctly converts a single file. - """ - with patch("sys.stdout", new=StringIO()) as fake_output: - main() - self.assertIn("Conversion of", fake_output.getvalue()) - mock_logging.info.assert_called_once_with("Conversion of %s to %s successful.", self.test_file, os.path.splitext(self.test_file)[0] + ".csv") - - @patch("builtins.input", side_effect=["1", self.test_file, "n"]) - @patch("converters.text_converter.logging") - @patch("main.convert_files") - def test_main_mocked(self, mock_convert_files, mock_logging, mock_input): - """ - This method tests that the main function correctly calls the convert_files function. - """ - main() - mock_convert_files.assert_called_once_with([self.test_file], "json_to_csv") - - @patch("builtins.input", side_effect=["1", self.test_file, "n"]) - @patch("converters.text_converter.logging") - @patch("main.convert_files") - def test_main_mocked_exception(self, mock_convert_files, mock_logging, mock_input): - """ - This method tests that the main function correctly handles an exception raised by the convert_files function. - """ - mock_convert_files.side_effect = Exception("Test exception") - with patch("sys.stdout", new=StringIO()) as fake_output: - main() - self.assertIn("Error:", fake_output.getvalue()) - - def tearDown(self): - """ - This method tears down the test environment after each test case is run. - """ - os.remove(self.test_file) - test_file2 = os.path.join(self.test_dir, "test_file2.txt") - os.remove(test_file2) - - @classmethod - def tearDownClass(cls): - """ - This method tears down the test environment after all test cases are run. - """ - os.rmdir(cls.test_dir) - - -if __name__ == "__main__": - unittest.main() \ No newline at end of file diff --git a/tests.py b/tests.py new file mode 100644 index 0000000..48b5fd8 --- /dev/null +++ b/tests.py @@ -0,0 +1,51 @@ +import unittest +import logging +from pathlib import Path + +# Relative imports of test modules +from .tests.test_image_converter import ImageConverterTests +from .tests.test_text_converter import TextConverterTests +from .tests.test_main import MainModuleTests + +def setup_logging(): + """ + Sets up logging for the test results. + """ + log_file_path = Path(__file__).parent / 'test_results.log' + logging.basicConfig(filename=log_file_path, + level=logging.INFO, + format='%(asctime)s:%(levelname)s:%(message)s') + +def create_test_suite(): + """ + Creates a unified test suite combining all tests from the three modules. + """ + test_suite = unittest.TestSuite() + test_suite.addTest(unittest.makeSuite(ImageConverterTests)) + test_suite.addTest(unittest.makeSuite(TextConverterTests)) + test_suite.addTest(unittest.makeSuite(MainModuleTests)) + + return test_suite + +def configure_test_runner(): + """ + Configures a test runner that executes the test suite. + """ + return unittest.TextTestRunner(verbosity=2) + +def main(): + """ + Main function to run the test suite. + """ + setup_logging() + suite = create_test_suite() + runner = configure_test_runner() + test_result = runner.run(suite) + + if not test_result.wasSuccessful(): + logging.error(f"Number of failed tests: {len(test_result.failures)}") + for test, traceback in test_result.failures: + logging.error(f"{test.id()}: {traceback}") + +if __name__ == '__main__': + main() diff --git a/tests/test_image_converter.py b/tests/test_image_converter.py new file mode 100644 index 0000000..aa709d7 --- /dev/null +++ b/tests/test_image_converter.py @@ -0,0 +1,85 @@ +import pytest +import os +from PIL import Image +from ..src.image_converter import ImageConverter, convert_image + +# Test data setup +@pytest.fixture +def setup_images(tmp_path): + """ + Setup fixture to create dummy images in different formats. + """ + bmp_path = tmp_path / "test.bmp" + jpg_path = tmp_path / "test.jpg" + png_path = tmp_path / "test.png" + + # Create a simple image in BMP, JPG, PNG formats + img = Image.new("RGB", (100, 100), color="red") + img.save(bmp_path, "BMP") + img.save(jpg_path, "JPEG") + img.save(png_path, "PNG") + + return bmp_path, jpg_path, png_path + +# Test Cases for Successful Conversions +def test_convert_bmp_to_jpg(setup_images, tmp_path): + bmp_path, _, _ = setup_images + output_path = tmp_path / "output.jpg" + convert_image(str(bmp_path), str(output_path)) + assert os.path.exists(output_path) + +def test_convert_bmp_to_png(setup_images, tmp_path): + bmp_path, _, _ = setup_images + output_path = tmp_path / "output.png" + convert_image(str(bmp_path), str(output_path)) + assert os.path.exists(output_path) + +def test_copy_jpg(setup_images, tmp_path): + _, jpg_path, _ = setup_images + output_path = tmp_path / "copy.jpg" + convert_image(str(jpg_path), str(output_path)) + assert os.path.exists(output_path) + +def test_copy_png(setup_images, tmp_path): + _, _, png_path = setup_images + output_path = tmp_path / "copy.png" + convert_image(str(png_path), str(output_path)) + assert os.path.exists(output_path) + +# Test Cases for Failure Cases +def test_unsupported_input_format(setup_images, tmp_path): + _, _, _ = setup_images + output_path = tmp_path / "output.unknown" + with pytest.raises(ValueError): + convert_image("unsupported.format", str(output_path)) + +def test_unsupported_output_format(setup_images, tmp_path): + bmp_path, _, _ = setup_images + output_path = tmp_path / "output.unknown" + with pytest.raises(ValueError): + convert_image(str(bmp_path), str(output_path)) + +def test_same_input_output_path(setup_images): + bmp_path, _, _ = setup_images + with pytest.raises(ValueError): + convert_image(str(bmp_path), str(bmp_path)) + +# Test Cases for Edge Cases +def test_nonexistent_input_file(tmp_path): + nonexistent_path = tmp_path / "nonexistent.bmp" + output_path = tmp_path / "output.jpg" + with pytest.raises(FileNotFoundError): + convert_image(str(nonexistent_path), str(output_path)) + +def test_invalid_file_path(): + invalid_path = "/invalid/path/to/file.bmp" + with pytest.raises(ValueError): + convert_image(invalid_path, "output.jpg") + +# Utility Function Tests +def test_supported_conversions(): + expected_output = "Supported file formats and conversions:\n" \ + "JPEG: can be converted to JPEG (no conversion needed)\n" \ + "PNG: can be converted to PNG (no conversion needed)\n" \ + "BMP: can be converted to JPEG or PNG" + assert ImageConverter.supported_conversions() == expected_output diff --git a/tests/test_main.py b/tests/test_main.py new file mode 100644 index 0000000..c91a215 --- /dev/null +++ b/tests/test_main.py @@ -0,0 +1,54 @@ +import pytest +from unittest.mock import patch, MagicMock +from ..main import * +import os + +# Test Menu Display +def test_print_menu(capsys): + main.print_menu() + captured = capsys.readouterr() + assert "File Converter" in captured.out + +# File Conversion Tests +@patch('main.input', side_effect=['1', '/path/to/pngfile.png', 'n']) +@patch('main.convert_files') +def test_convert_single_file(mock_convert_files, mock_input): + with patch('os.path.exists', return_value=True), \ + patch('os.path.isfile', return_value=True): + main.main() + mock_convert_files.assert_called_once() + +@patch('main.input', side_effect=['1', '/path/to/directory', 'n']) +@patch('main.convert_files') +def test_convert_batch_files(mock_convert_files, mock_input): + with patch('os.listdir', return_value=['file1.png', 'file2.png']), \ + patch('os.path.exists', return_value=True), \ + patch('os.path.isdir', return_value=True): + main.main() + assert mock_convert_files.call_count == 1 + +# User Input Handling +@patch('main.input', side_effect=['7', 'q']) +def test_invalid_choice(mock_input, capsys): + main.main() + captured = capsys.readouterr() + assert "Invalid choice!" in captured.out + +@patch('main.input', side_effect=['1', '/invalid/path.png', 'n']) +def test_invalid_file_path(mock_input, capsys): + with patch('os.path.exists', return_value=False): + main.main() + captured = capsys.readouterr() + assert "Invalid path!" in captured.out + +# Error Handling Tests +def test_unsupported_conversion_type(): + with pytest.raises(ValueError): + main.convert_extension("unsupported_type") + +@patch('main.input', side_effect=['1', '/nonexistent/path.png', 'n']) +def test_nonexistent_path_handling(mock_input, capsys): + with patch('os.path.exists', return_value=False): + main.main() + captured = capsys.readouterr() + assert "Invalid path!" in captured.out diff --git a/tests/test_text_converter.py b/tests/test_text_converter.py new file mode 100644 index 0000000..daad6ec --- /dev/null +++ b/tests/test_text_converter.py @@ -0,0 +1,109 @@ +import pytest +import os +import json +import csv +import xml.etree.ElementTree as ET +from odf.opendocument import load as load_odt +from ..src.text_converter import TextConverter, convert_text +from io import StringIO + +# Helper Functions for Test Data Creation +def create_json_file(path, data): + with open(path, 'w') as file: + json.dump(data, file) + +def create_csv_file(path, data): + with open(path, 'w', newline='') as file: + writer = csv.writer(file) + writer.writerow(data[0].keys()) + for row in data: + writer.writerow(row.values()) + +def create_xml_file(path, data): + root = ET.Element("root") + for item in data: + child = ET.SubElement(root, "child", attrib=item) + tree = ET.ElementTree(root) + tree.write(path) + +def create_odt_file(path, text): + doc = opendocument.Text() + para = P(text) + doc.text.addElement(para) + doc.save(path) + +# Test Cases for Successful Conversions +@pytest.fixture +def setup_files(tmp_path): + # Create dummy files for each format + json_path = tmp_path / "test.json" + csv_path = tmp_path / "test.csv" + xml_path = tmp_path / "test.xml" + odt_path = tmp_path / "test.odt" + + # Dummy data + data = [{"name": "John", "age": 30}, {"name": "Jane", "age": 25}] + create_json_file(json_path, data) + create_csv_file(csv_path, data) + create_xml_file(xml_path, [{"name": "John"}, {"name": "Jane"}]) + create_odt_file(odt_path, "Sample text") + + return json_path, csv_path, xml_path, odt_path + +def test_convert_json_to_csv(setup_files, tmp_path): + json_path, _, _, _ = setup_files + output_path = tmp_path / "output.csv" + convert_text(str(json_path), str(output_path)) + assert os.path.exists(output_path) + +def test_convert_csv_to_json(setup_files, tmp_path): + _, csv_path, _, _ = setup_files + output_path = tmp_path / "output.json" + convert_text(str(csv_path), str(output_path)) + assert os.path.exists(output_path) + +def test_convert_odt_to_txt(setup_files, tmp_path): + _, _, _, odt_path = setup_files + output_path = tmp_path / "output.txt" + convert_text(str(odt_path), str(output_path)) + assert os.path.exists(output_path) + +def test_convert_xml_to_json(setup_files, tmp_path): + _, _, xml_path, _ = setup_files + output_path = tmp_path / "output.json" + convert_text(str(xml_path), str(output_path)) + assert os.path.exists(output_path) + +# Test Cases for Failure Cases +def test_unsupported_input_format(tmp_path): + unsupported_path = tmp_path / "unsupported.format" + output_path = tmp_path / "output.csv" + with pytest.raises(ValueError): + convert_text(str(unsupported_path), str(output_path)) + +def test_unsupported_output_format(setup_files, tmp_path): + json_path, _, _, _ = setup_files + output_path = tmp_path / "unsupported.format" + with pytest.raises(ValueError): + convert_text(str(json_path), str(output_path)) + +# Test Cases for Edge Cases +def test_nonexistent_input_file(tmp_path): + nonexistent_path = tmp_path / "nonexistent.json" + output_path = tmp_path / "output.csv" + with pytest.raises(FileNotFoundError): + convert_text(str(nonexistent_path), str(output_path)) + +def test_invalid_file_path(): + invalid_path = "/invalid/path/to/file.json" + with pytest.raises(ValueError): + convert_text(invalid_path, "output.csv") + +# Utility Function Tests +def test_supported_conversions(): + expected_output = "Supported file formats and conversions:\n" \ + "JSON: can be converted to CSV or JSON\n" \ + "CSV: can be converted to JSON or CSV (no conversion needed)\n" \ + "ODT: can be converted to plain text\n" \ + "XML: can be converted to JSON" + assert TextConverter.supported_conversions() == expected_output