"""Testing file 'cli/cmd_plot/execution.py'."""
import io
import sys
import unittest
from contextlib import redirect_stderr
from pathlib import Path
from unittest.mock import MagicMock, Mock, call, patch
try:
from cli.cmd_plot.data_handling.data_source_types import DataSourceTypes
from cli.cmd_plot.execution import Executor
from cli.helpers.config import read_config
except ModuleNotFoundError:
sys.path.insert(0, str(Path(__file__).parents[3]))
from cli.cmd_plot.data_handling.data_source_types import DataSourceTypes
from cli.cmd_plot.execution import Executor
from cli.helpers.config import read_config
PATH_DATA = Path(__file__).parent / "test_data"
PATH_EXECUTION = Path(__file__).parent / "test_execution"
class TestInit(unittest.TestCase):
"""Class to test the init method of the Executor class"""
def setUp(self) -> None:
self.config = {
"input_data": [PATH_DATA],
"data_config": PATH_EXECUTION / "test_data_source_config.yaml",
"plot_config": PATH_EXECUTION / "test_plot_config.yaml",
"data_source_type": "CSV",
"output": None,
}
def test_init_valid_config(self) -> None:
"""Tests the init with valid config"""
Executor(**self.config)
def test_data_source_type_none(self) -> None:
"""Test the get_data_source_type method with data_source_type as None"""
self.config["data_source_type"] = None
buf = io.StringIO()
with redirect_stderr(buf), self.assertRaises(SystemExit) as cm:
Executor(**self.config)
self.assertEqual(cm.exception.code, 1)
self.assertTrue(
"Data source type is required when a directory" in buf.getvalue()
)
def test_data_source_type_not_valid(self) -> None:
"""Test the get_data_source_type method with invalid data_source_type"""
self.config["data_source_type"] = "TEST"
buf = io.StringIO()
with redirect_stderr(buf), self.assertRaises(SystemExit) as cm:
Executor(**self.config)
self.assertEqual(cm.exception.code, 1)
self.assertTrue("is not valid for input" in buf.getvalue())
def test_data_source_type_with_single_file(self) -> None:
"""Test the get_data_source_type method with single file"""
self.config["data_source_type"] = None
self.config["input_data"] = [PATH_DATA / "input_data.csv"]
exe = Executor(**self.config)
self.assertEqual(exe.data_source_type, DataSourceTypes["CSV"])
@patch("pathlib.Path.mkdir")
@patch("cli.cmd_plot.drawer.graph_drawer_factory.GraphDrawerFactory.get_object")
@patch("cli.cmd_plot.data_handling.data_handler_factory.DataHandlerFactory.get_object")
class TestCreatePlots(unittest.TestCase):
"""Class to test the create_plots method of the Executor class"""
def setUp(self) -> None:
self.config = {
"input_data": [PATH_DATA],
"data_config": PATH_EXECUTION / "test_data_source_config.yaml",
"plot_config": PATH_EXECUTION / "test_plot_config.yaml",
"data_source_type": "CSV",
"output": None,
}
self.executor = Executor(**self.config)
def test_create_plots(
self, mock_data_get: Mock, mock_drawer_get: Mock, mock_mkdir: Mock
) -> None:
"""Tests the create_plots method with valid executor object"""
self.executor.create_plots()
mock_data_get.assert_called_once_with(
self.executor.data_source_type, self.executor.data_config
)
mock_mkdir.assert_called_once()
data_files = self.executor._get_data_files()
for file in data_files:
plot_dir = Path(self.executor.output) / Path(file).stem
for graph_config in read_config(self.executor.plot_config):
mock_drawer_get.assert_has_calls([call(graph_config)])
mock_drawer_get().draw.assert_has_calls(
[call(data=mock_data_get().get_data())]
)
mock_drawer_get().save.assert_has_calls([call(plot_dir)])
mock_drawer_get().show.assert_called_with()
def test_plot_config_not_a_list(self, *_: list[Mock]) -> None:
"""Test the create_plots method with a plot configuration not containing a list"""
buf = io.StringIO()
with redirect_stderr(buf), self.assertRaises(SystemExit) as cm:
self.executor.plot_config = 12
self.executor.create_plots()
self.assertEqual(cm.exception.code, 1)
self.assertIn("Plot creation failed:", buf.getvalue())
def test_read_config_invalid_yaml(self, *_: list[Mock]) -> None:
"""Tests the read_config method with a valid yaml"""
self.config["plot_config"] = PATH_EXECUTION / "test_yaml_error.yaml"
buf = io.StringIO()
with redirect_stderr(buf), self.assertRaises(SystemExit) as cm:
Executor(**self.config).create_plots()
self.assertEqual(cm.exception.code, 1)
self.assertTrue("Plot creation failed" in buf.getvalue())
class TestGetDataFiles(unittest.TestCase):
"""Class to test the get_data_files method of the Executor class"""
def setUp(self) -> None:
self.config = {
"input_data": [PATH_DATA],
"data_config": PATH_EXECUTION / "test_data_source_config.yaml",
"plot_config": PATH_EXECUTION / "test_plot_config.yaml",
"data_source_type": "CSV",
"output": None,
}
def test_input_as_dir(self) -> None:
"""Test the get_data_files method with a directory as input"""
files = Executor(**self.config)._get_data_files()
self.assertEqual(files[0], PATH_DATA / "input_data.csv")
def test_input_as_file(self) -> None:
"""Test the get_data_files method with file as input"""
self.config["input_data"] = [PATH_DATA / "input_data.csv"]
files = Executor(**self.config)._get_data_files()
self.assertEqual(files[0], PATH_DATA / "input_data.csv")
def test_input_no_file_or_dir(self) -> None:
"""Test the get_data_files method with file as input"""
self.config["input_data"] = [PATH_DATA / "data.csv"]
buf = io.StringIO()
with redirect_stderr(buf), self.assertRaises(SystemExit) as cm:
Executor(**self.config)._get_data_files()
self.assertEqual(cm.exception.code, 1)
self.assertIn(
"Input data has to contain files or directories only.", buf.getvalue()
)
class TestHandlePyplotWarnings(unittest.TestCase):
"""Class to test the handle_pyplot_warnings method of the Executor class"""
def test_empty_warning_handle(self) -> None:
"""Tests the handle_pyplot_warnings method in case the warning_handle
parameter is empty
"""
buf = io.StringIO()
graph_drawer = Mock()
with redirect_stderr(buf):
Executor._handle_pyplot_warnings([], graph_drawer)
self.assertIn("", buf.getvalue())
def test_known_warning(self) -> None:
"""Tests the handle_pyplot_warnings method with known warning"""
buf = io.StringIO()
warning_handle = MagicMock()
place_holder_mock = Mock()
place_holder_mock.message = "test"
warning_mock = Mock()
warning_mock.message = "Tight layout not applied"
warning_handle.__iter__.return_value = [
place_holder_mock,
warning_mock,
place_holder_mock,
]
graph_drawer = Mock()
graph_drawer.name = "test name"
with redirect_stderr(buf):
Executor._handle_pyplot_warnings(warning_handle, graph_drawer)
self.assertIn("Plot layout of test name seems too", buf.getvalue())
def test_unkown_warning(self) -> None:
"""Tests the handle_pyplot_warnings method with unknown warning"""
buf = io.StringIO()
warning_handle = MagicMock()
place_holder_mock = Mock()
place_holder_mock.message = "test"
warning_handle.__iter__.return_value = [place_holder_mock, place_holder_mock]
graph_drawer = Mock()
graph_drawer.name = "test name"
with redirect_stderr(buf):
Executor._handle_pyplot_warnings(warning_handle, graph_drawer)
self.assertIn("", buf.getvalue())
if __name__ == "__main__":
unittest.main()