From d29fe67a9406fbcda5f36de9281d4bef9e785600 Mon Sep 17 00:00:00 2001 From: Abangma Jessika <127256410+InongoMag@users.noreply.github.com> Date: Tue, 28 Jan 2025 18:55:07 +0100 Subject: [PATCH 1/8] added gui tests for the main and modified the way the GUI files where imported in the files committed above --- news/gui-tests.rst | 23 +++++++++++++++++++++++ src/GUI/code/CA_GUI.py | 7 ++++--- src/GUI/code/CV_GUI.py | 7 ++++--- src/GUI/code/GUI_CA_exp_creator.py | 4 +++- src/GUI/code/GUI_CV_exp_creator.py | 3 ++- src/GUI/code/GUI_LSV_exp_creator.py | 3 ++- src/GUI/code/GUI_file_operation.py | 13 +++++++------ src/GUI/code/GUI_operator.py | 5 +++-- src/GUI/code/GUI_plotter.py | 7 ++++--- src/GUI/code/GUI_routines.py | 3 ++- src/GUI/code/GUI_run_exp.py | 14 +++++++------- src/GUI/code/LSV_GUI.py | 7 ++++--- src/GUI/designer_files/buffer.py | 26 ++++++++------------------ 13 files changed, 73 insertions(+), 49 deletions(-) create mode 100644 news/gui-tests.rst diff --git a/news/gui-tests.rst b/news/gui-tests.rst new file mode 100644 index 0000000..f1b5476 --- /dev/null +++ b/news/gui-tests.rst @@ -0,0 +1,23 @@ +**Added:** + +* added pytest for gui files + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* diff --git a/src/GUI/code/CA_GUI.py b/src/GUI/code/CA_GUI.py index f749522..c626093 100644 --- a/src/GUI/code/CA_GUI.py +++ b/src/GUI/code/CA_GUI.py @@ -1,10 +1,11 @@ ## Standard library -from Adv_params_GUI import Ui_Adv_Params +from PySide6 import QtCore, QtGui, QtWidgets + +from src.GUI.code.Adv_params_GUI import Ui_Adv_Params ## Local library # GUI_function -from GUI_load_config import Ui_Load -from PySide6 import QtCore, QtGui, QtWidgets +from src.GUI.code.GUI_load_config import Ui_Load class Ui_CA(object): diff --git a/src/GUI/code/CV_GUI.py b/src/GUI/code/CV_GUI.py index 1c34663..111b90c 100644 --- a/src/GUI/code/CV_GUI.py +++ b/src/GUI/code/CV_GUI.py @@ -1,10 +1,11 @@ ## Standard library -from Adv_params_GUI import Ui_Adv_Params +from PySide6 import QtCore, QtGui, QtWidgets + +from src.GUI.code.Adv_params_GUI import Ui_Adv_Params ## Local library # GUI_function -from GUI_load_config import Ui_Load -from PySide6 import QtCore, QtGui, QtWidgets +from src.GUI.code.GUI_load_config import Ui_Load class Ui_CV(object): diff --git a/src/GUI/code/GUI_CA_exp_creator.py b/src/GUI/code/GUI_CA_exp_creator.py index 3b7749d..19399bc 100644 --- a/src/GUI/code/GUI_CA_exp_creator.py +++ b/src/GUI/code/GUI_CA_exp_creator.py @@ -8,7 +8,8 @@ from matplotlib.figure import Figure from PySide6.QtGui import QIcon from PySide6.QtWidgets import QGridLayout, QListWidgetItem -from warning_GUI import warning + +from .warning_GUI import warning ## PartI: load output filepath @@ -203,6 +204,7 @@ def config_writer_CA( Parameters ------ + stp_num exp_type: string, experiment type rt: int, rest time diff --git a/src/GUI/code/GUI_CV_exp_creator.py b/src/GUI/code/GUI_CV_exp_creator.py index ca0e6dd..edf0a6d 100644 --- a/src/GUI/code/GUI_CV_exp_creator.py +++ b/src/GUI/code/GUI_CV_exp_creator.py @@ -8,7 +8,8 @@ from matplotlib.figure import Figure from PySide6.QtGui import QIcon from PySide6.QtWidgets import QGridLayout, QListWidgetItem -from warning_GUI import warning + +from src.GUI.code.warning_GUI import warning ## PartI: load output filepath diff --git a/src/GUI/code/GUI_LSV_exp_creator.py b/src/GUI/code/GUI_LSV_exp_creator.py index 6a531d9..be9c767 100644 --- a/src/GUI/code/GUI_LSV_exp_creator.py +++ b/src/GUI/code/GUI_LSV_exp_creator.py @@ -8,7 +8,8 @@ from matplotlib.figure import Figure from PySide6.QtGui import QIcon from PySide6.QtWidgets import QGridLayout, QListWidgetItem -from warning_GUI import warning + +from src.GUI.code.warning_GUI import warning ## PartI: load output filepath diff --git a/src/GUI/code/GUI_file_operation.py b/src/GUI/code/GUI_file_operation.py index 4f6b50c..66fdae3 100644 --- a/src/GUI/code/GUI_file_operation.py +++ b/src/GUI/code/GUI_file_operation.py @@ -1,17 +1,18 @@ ## Standard libraries from functools import partial -# GUI_function -from GUI_CA_exp_creator import CA_main, CA_window_writer -from GUI_config_reader import parse_config_file -from GUI_CV_exp_creator import CV_main, CV_window_writer -from GUI_LSV_exp_creator import LSV_main, LSV_window_writer from PySide6.QtGui import QIcon from PySide6.QtWidgets import QListWidgetItem +# GUI_function +from src.GUI.code.GUI_CA_exp_creator import CA_main, CA_window_writer +from src.GUI.code.GUI_config_reader import parse_config_file +from src.GUI.code.GUI_CV_exp_creator import CV_main, CV_window_writer +from src.GUI.code.GUI_LSV_exp_creator import LSV_main, LSV_window_writer + ## Local libraries # GUI window -from warning_GUI import warning +from src.GUI.code.warning_GUI import warning def add_exp(ui): diff --git a/src/GUI/code/GUI_operator.py b/src/GUI/code/GUI_operator.py index 4d577cb..0a656c1 100644 --- a/src/GUI/code/GUI_operator.py +++ b/src/GUI/code/GUI_operator.py @@ -2,10 +2,11 @@ import datetime import time +import numpy as np + ## Local library # GUI_function -import GUI_config_reader as cr -import numpy as np +import src.GUI.code.GUI_config_reader as cr def start_exp(d9, normalized_start, data): diff --git a/src/GUI/code/GUI_plotter.py b/src/GUI/code/GUI_plotter.py index 0d0b7f9..e33efbd 100644 --- a/src/GUI/code/GUI_plotter.py +++ b/src/GUI/code/GUI_plotter.py @@ -1,9 +1,6 @@ ## Standard libraries import sys -##Local library -# GUI_function -import GUI_config_reader as cr from matplotlib.backends.backend_qt5agg import ( FigureCanvasQTAgg as FigureCanvas, ) @@ -13,6 +10,10 @@ from matplotlib.figure import Figure from PySide6.QtWidgets import QApplication, QWidget +##Local library +# GUI_function +import src.GUI.code.GUI_config_reader as cr + class Ui_Plot(QWidget): def __init__(self): diff --git a/src/GUI/code/GUI_routines.py b/src/GUI/code/GUI_routines.py index cab6277..b1ffb59 100644 --- a/src/GUI/code/GUI_routines.py +++ b/src/GUI/code/GUI_routines.py @@ -3,7 +3,8 @@ import serial.tools.list_ports from pyfirmata import Arduino, util from PySide6.QtGui import QIcon -from warning_GUI import warning + +from src.GUI.code.warning_GUI import warning _BAUD_RATE = 115200 diff --git a/src/GUI/code/GUI_run_exp.py b/src/GUI/code/GUI_run_exp.py index b5cc60c..7573c7b 100644 --- a/src/GUI/code/GUI_run_exp.py +++ b/src/GUI/code/GUI_run_exp.py @@ -2,16 +2,16 @@ import csv import os -from GUI_config_reader import parse_config_file -from GUI_operator import experiment - -# GUI function -from GUI_plotter import Ui_Plot - ## Local libraries # GUI window from PySide6.QtGui import QIcon -from warning_GUI import warning + +from src.GUI.code.GUI_config_reader import parse_config_file +from src.GUI.code.GUI_operator import experiment + +# GUI function +from src.GUI.code.GUI_plotter import Ui_Plot +from src.GUI.code.warning_GUI import warning def calculate_time(filename): diff --git a/src/GUI/code/LSV_GUI.py b/src/GUI/code/LSV_GUI.py index 4652146..bd8f5d2 100644 --- a/src/GUI/code/LSV_GUI.py +++ b/src/GUI/code/LSV_GUI.py @@ -1,10 +1,11 @@ ## Standard library -from Adv_params_GUI import Ui_Adv_Params +from PySide6 import QtCore, QtGui, QtWidgets + +from src.GUI.code.Adv_params_GUI import Ui_Adv_Params ## Local library # GUI_function -from GUI_load_config import Ui_Load -from PySide6 import QtCore, QtGui, QtWidgets +from src.GUI.code.GUI_load_config import Ui_Load class Ui_LSV(object): diff --git a/src/GUI/designer_files/buffer.py b/src/GUI/designer_files/buffer.py index f998936..3edbe89 100644 --- a/src/GUI/designer_files/buffer.py +++ b/src/GUI/designer_files/buffer.py @@ -1,6 +1,12 @@ ## CA -from Adv_params_GUI import Ui_Adv_Params -from Load_config_GUI import Ui_Load +from PyQt6 import QtWidgets + +from src.GUI.code.Adv_params_GUI import Ui_Adv_Params +from src.GUI.code.CA_GUI import Ui_CA +from src.GUI.code.CV_GUI import Ui_CV +from src.GUI.code.Exp_type_GUI import Ui_Experiment +from src.GUI.code.GUI_load_config import Ui_Load +from src.GUI.code.LSV_GUI import Ui_LSV class Ui_CA(object): @@ -31,12 +37,6 @@ def AP_window(self): return self.AP, self.window -from Adv_params_GUI import Ui_Adv_Params - -## CV -from Load_config_GUI import Ui_Load # more - - class Ui_CV(object): """Initializes the 'Load config file' window. @@ -94,16 +94,6 @@ def AP_window(self): return self.AP, self.window -from CA_GUI import Ui_CA -from CV_GUI import Ui_CV -from Exp_type_GUI import Ui_Experiment -from Load_config_GUI import Ui_Load - -## main -## main -from LSV_GUI import Ui_LSV - - class Ui_MainWindow(object): def show_exp(self): """Initializes the 'Experiment Type' window. From b68c3b2fb1e2bd8d484f49c1819ab841e345e809 Mon Sep 17 00:00:00 2001 From: Abangma Jessika <127256410+InongoMag@users.noreply.github.com> Date: Tue, 28 Jan 2025 18:56:35 +0100 Subject: [PATCH 2/8] added gui tests for the main and modified the way the GUI files where imported in the files committed above --- src/GUI/code/main.py | 20 ++++++-- src/GUI/code/mainwindow_GUI.py | 11 +++-- tests/test_main.py | 87 ++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 10 deletions(-) create mode 100644 tests/test_main.py diff --git a/src/GUI/code/main.py b/src/GUI/code/main.py index ea68ad5..5ec4a69 100644 --- a/src/GUI/code/main.py +++ b/src/GUI/code/main.py @@ -2,16 +2,26 @@ import sys from functools import partial -from GUI_file_operation import add_exp, edit_file, load_file, remove_file +from PySide6.QtWidgets import QApplication, QGridLayout, QMainWindow + +from src.GUI.code.GUI_file_operation import ( + add_exp, + edit_file, + load_file, + remove_file, +) # GUI function -from GUI_routines import _load_arduino, disconnect_port_main, find_port_main -from GUI_run_exp import run_exp_main +from src.GUI.code.GUI_routines import ( + _load_arduino, + disconnect_port_main, + find_port_main, +) +from src.GUI.code.GUI_run_exp import run_exp_main ## Local libraries # GUI window -from mainwindow_GUI import Ui_MainWindow -from PySide6.QtWidgets import QApplication, QGridLayout, QMainWindow +from src.GUI.code.mainwindow_GUI import Ui_MainWindow # load the main window app = QApplication(sys.argv) diff --git a/src/GUI/code/mainwindow_GUI.py b/src/GUI/code/mainwindow_GUI.py index 446d339..d9e09e9 100644 --- a/src/GUI/code/mainwindow_GUI.py +++ b/src/GUI/code/mainwindow_GUI.py @@ -1,10 +1,11 @@ -from CA_GUI import Ui_CA -from CV_GUI import Ui_CV -from Exp_type_GUI import Ui_Experiment -from GUI_load_config import Ui_Load -from LSV_GUI import Ui_LSV from PySide6 import QtCore, QtGui, QtWidgets +from src.GUI.code.CA_GUI import Ui_CA +from src.GUI.code.CV_GUI import Ui_CV +from src.GUI.code.Exp_type_GUI import Ui_Experiment +from src.GUI.code.GUI_load_config import Ui_Load +from src.GUI.code.LSV_GUI import Ui_LSV + class Ui_MainWindow(object): def show_exp(self): diff --git a/tests/test_main.py b/tests/test_main.py new file mode 100644 index 0000000..aee77ef --- /dev/null +++ b/tests/test_main.py @@ -0,0 +1,87 @@ +import os +import sys +from unittest.mock import MagicMock, patch + +import pytest +from PySide6.QtWidgets import QApplication + +# Assuming the main.py is structured as a module +from src.GUI.code.main import disconnect_port, find_port, start_exp + +sys.path.insert( + 0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../src")) +) + + +@pytest.fixture +def app(qtbot): + """Create a QApplication instance for testing.""" + app = QApplication(sys.argv) + yield app + app.quit() + + +@pytest.fixture +def mock_ui(): + """Mock the UI components.""" + ui = MagicMock() + return ui + + +def test_find_port(app, mock_ui): + """Test the find_port function.""" + with patch( + "src.GUI.code.GUI_routines.find_port_main", + return_value=(True, (MagicMock(), None, None, None)), + ): + find_port() + assert mock_ui.find_potentiostat_button.clicked.call_count == 1 + + +def test_disconnect_port(app, mock_ui): + """Test the disconnect_port function.""" + with patch( + "src.GUI.code.GUI_routines.disconnect_port_main" + ) as mock_disconnect: + disconnect_port() + mock_disconnect.assert_called_once_with(mock_ui, None, None) + + +def test_add_experiment(app, mock_ui): + """Test the add experiment button functionality.""" + with patch("src.GUI.code.GUI_file_operation.add_exp") as mock_add_exp: + mock_ui.add_experiment_button.clicked.emit() + mock_add_exp.assert_called_once_with(mock_ui) + + +def test_load_experiment(app, mock_ui): + """Test the load experiment button functionality.""" + with patch("src.GUI.code.GUI_file_operation.load_file") as mock_load_file: + mock_ui.load_experiment_button.clicked.emit() + mock_load_file.assert_called_once_with(mock_ui) + + +def test_edit_experiment(app, mock_ui): + """Test the edit experiment button functionality.""" + with patch("src.GUI.code.GUI_file_operation.edit_file") as mock_edit_file: + mock_ui.edit_experiment_button.clicked.emit() + mock_edit_file.assert_called_once_with(mock_ui) + + +def test_remove_experiment(app, mock_ui): + """Test the remove experiment button functionality.""" + with patch( + "src.GUI.code.GUI_file_operation.remove_file" + ) as mock_remove_file: + mock_ui.remove_experiment_button.clicked.emit() + mock_remove_file.assert_called_once_with(mock_ui) + + +def test_start_exp(app, mock_ui): + """Test the start experiment functionality.""" + grid = MagicMock() + with patch("src.GUI.code.GUI_run_exp.run_exp_main") as mock_run_exp: + start_exp(grid) + mock_run_exp.assert_called_once_with( + mock_ui, None, (None, None, None, None), grid + ) From 3202fa1067de2ffe046f2ded7eed016d64c4fb44 Mon Sep 17 00:00:00 2001 From: Abangma Jessika <127256410+InongoMag@users.noreply.github.com> Date: Tue, 28 Jan 2025 18:59:21 +0100 Subject: [PATCH 3/8] added gui tests for the main and modified the way the GUI files where imported in the files committed above --- src/pytentiostat/main.py | 165 +++++++++++++++++++++++---------------- 1 file changed, 99 insertions(+), 66 deletions(-) diff --git a/src/pytentiostat/main.py b/src/pytentiostat/main.py index 60badf8..6099d9b 100644 --- a/src/pytentiostat/main.py +++ b/src/pytentiostat/main.py @@ -1,4 +1,5 @@ # Pytentiostat function files +import argparse import sys import matplotlib.pyplot as plt @@ -7,6 +8,24 @@ from pytentiostat.operator import experiment from pytentiostat.reporter import save_data_to_file from pytentiostat.routines import closing_routine, startup_routine +from pytentiostat.version import __version__ + + +def parser(): + parser = argparse.ArgumentParser( + description="Pytentiostat Command Line Interface. To use, first plug " + "in the potentiostat, then run the software by typing" + "pytentiostat at the command line and follow the prompts." + "For more information, see the documentation at " + "juami.github.io/pytentiostat" + ) + parser.add_argument( + "--version", + action="store_true", + help="Show the version of pytentiostat and exit", + ) + args = parser.parse_args() + return args class BoardCom: @@ -16,77 +35,91 @@ def __init__(self): ) -try: - # Initialize Experiment - board_instance = BoardCom() - # com, board, a0, a2, d9 = startup_routine() -except KeyboardInterrupt: - sys.exit( - "Connection interrupted by user. Make sure the potentiostat " - "is plugged in then restart the software.\n" - "Exiting..." - ) +def main(): + args = parser() + if args.version: + print(f"{__version__}") + sys.exit(0) -board_objects = ( - board_instance.pin_a0, - board_instance.pin_a2, - board_instance.pin_d9, -) -parse = input("Press enter to load the config file.") -config_data = parse_config_file() -while True: - while True: - # Run the experiment and get the config_data - start = input("Press enter to start the experiment.") - times, voltages, currents, interrupt = experiment( - config_data, *board_objects + try: + # Initialize Experiment + board_instance = BoardCom() + # com, board, a0, a2, d9 = startup_routine() + except KeyboardInterrupt: + sys.exit( + "Connection interrupted by user. Make sure the potentiostat " + "is plugged in then restart the software.\n" + "Exiting..." ) - if interrupt: - save = input( - "Experiment interrupted. Would you " - "like to save the data? [y/n]: " - ) - if save.lower() == "y": - temp_data = zip(times, voltages, currents) - save_data_to_file(config_data, temp_data) - print("Saved.") - reconfig = input( - "\nIf you want to do a different experiment, edit and " - "save the config file then type" - ' "new" and press enter.\n' - 'If you need to reconnect the potentiostat, type "reconnect" ' - "then press enter.\n" - "To close, just press enter. \n" + + board_objects = ( + board_instance.pin_a0, + board_instance.pin_a2, + board_instance.pin_d9, + ) + input("Press enter to load the config file.") + config_data = parse_config_file() + while True: + while True: + # Run the experiment and get the config_data + input("Press enter to start the experiment.") + times, voltages, currents, interrupt = experiment( + config_data, *board_objects ) - if reconfig.lower() == "new": - plt.close() - config_data = parse_config_file() - elif reconfig.lower() == "reconnect": - plt.close() - closing_routine(board_instance.board, board_instance.pin_d9) - board_instance.__init__() - board_objects = ( - board_instance.pin_a0, - board_instance.pin_a2, - board_instance.pin_d9, + if interrupt: + save = input( + "Experiment interrupted. Would you " + "like to save the data? [y/n]: " ) + if save.lower() == "y": + temp_data = zip(times, voltages, currents) + save_data_to_file(config_data, temp_data) + print("Saved.") + reconfig = input( + "\nIf you want to do a different experiment, edit and " + "save the config file then type" + ' "new" and press enter.\n' + "If you need to reconnect the potentiostat, type " + '"reconnect" then press enter.\n' + "To close, just press enter. \n" + ) + if reconfig.lower() == "new": + plt.close() + config_data = parse_config_file() + elif reconfig.lower() == "reconnect": + plt.close() + closing_routine( + board_instance.board, board_instance.pin_d9 + ) + board_instance.__init__() + board_objects = ( + board_instance.pin_a0, + board_instance.pin_a2, + board_instance.pin_d9, + ) + else: + closing_routine( + board_instance.board, board_instance.pin_d9 + ) + sys.exit(0) else: - closing_routine(board_instance.board, board_instance.pin_d9) - sys.exit(0) - else: + break + + # Generate a config_data report + if not interrupt: + collected_data = zip(times, voltages, currents) + save_data_to_file(config_data, collected_data) + print("Saved.") + stop = input("\nWould you like to repeat the last experiment? [y/n]: ") + if stop.lower() != "y": break + else: + interrupt = False + plt.close() + + # Wrap things up + closing_routine(board_instance.board, board_instance.pin_d9) - # Generate a config_data report - if not interrupt: - collected_data = zip(times, voltages, currents) - save_data_to_file(config_data, collected_data) - print("Saved.") - stop = input("\nWould you like to repeat the last experiment? [y/n]: ") - if stop.lower() != "y": - break - else: - interrupt = False - plt.close() -# Wrap things up -closing_routine(board_instance.board, board_instance.pin_d9) +if __name__ == "__main__": + main() From 765d1c62692bfd66500e7612f227117c1c0d0d91 Mon Sep 17 00:00:00 2001 From: Abangma Jessika <127256410+InongoMag@users.noreply.github.com> Date: Tue, 28 Jan 2025 19:11:08 +0100 Subject: [PATCH 4/8] added gui tests for the main and modified the way the GUI files where imported in the files committed above --- tests/test_adv_params_gui.py | 116 +++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 tests/test_adv_params_gui.py diff --git a/tests/test_adv_params_gui.py b/tests/test_adv_params_gui.py new file mode 100644 index 0000000..7f28e65 --- /dev/null +++ b/tests/test_adv_params_gui.py @@ -0,0 +1,116 @@ +import sys +from unittest.mock import MagicMock + +import pytest +from PySide6.QtWidgets import QApplication + +from src.GUI.code.Adv_params_GUI import Ui_Adv_Params + + +@pytest.fixture +def app(qtbot): + """Create a QApplication instance for testing.""" + app = QApplication(sys.argv) + yield app + app.quit() + + +@pytest.fixture +def ui(app): + """Create an instance of the UI for testing.""" + main_window = MagicMock() + ui = Ui_Adv_Params() + ui.setupUi(main_window) + return ui, main_window + + +def test_ui_initialization(ui): + """Test the initialization of the UI components.""" + ui, main_window = ui + + # Check if the main window is set up correctly + assert main_window.objectName() == "Adv_Params" + assert main_window.windowTitle() == "Adv Params" + + +def test_labels(ui): + """Test the labels in the UI.""" + ui, main_window = ui + + # Check the text of the labels + assert ui.experiment_conversion_factor_label.text() == "Conversion Factor" + assert ui.experiment_averag_number_label.text() == "Average Number" + assert ui.experiment_shunt_resistor_label.text() == "Shunt Resistor /mohm" + assert ui.advanced_parameters_label.text() == "Advanced Parameters" + assert ui.experiment_time_step_label.text() == "Time Step /s" + assert ui.experiment_setpoint_gain_label.text() == "Setpoint Gain" + assert ui.experiment_setpoint_offset_label.text() == "Setpoint Offset" + + +def test_line_edit_initialization(ui): + """Test the initialization of line edit fields.""" + ui, main_window = ui + + # Check if the line edits are initialized correctly + assert ( + ui.experiment_conversion_factor.objectName() + == "experiment_conversion_factor" + ) + assert ( + ui.experiment_setpoint_gain.objectName() == "experiment_setpoint_gain" + ) + assert ( + ui.experiment_setpoint_offset.objectName() + == "experiment_setpoint_offset" + ) + assert ( + ui.experiment_shunt_resistor.objectName() + == "experiment_shunt_resistor" + ) + assert ui.experiment_time_step.objectName() == "experiment_time_step" + assert ( + ui.experiment_averag_number.objectName() == "experiment_average_number" + ) + + +def test_button_initialization(ui): + """Test the initialization of buttons.""" + ui, main_window = ui + + # Check if the save button is initialized correctly + assert ( + ui.save_experiment_file_button.objectName() + == "save_experiment_file_button" + ) + assert ui.save_experiment_file_button.text() == "Save " + + +def test_line_edit_properties(ui): + """Test the properties of line edit fields.""" + ui, main_window = ui + + assert ui.experiment_conversion_factor.isAcceptDrops() is False + assert ui.experiment_conversion_factor.alignment() == 0x0004 # AlignCenter + assert ui.experiment_setpoint_gain.isAcceptDrops() is False + assert ui.experiment_setpoint_offset.isAcceptDrops() is False + assert ui.experiment_shunt_resistor.isAcceptDrops() is False + assert ui.experiment_time_step.isAcceptDrops() is False + assert ui.experiment_averag_number.isAcceptDrops() is False + + +def test_label_font_properties(ui): + """Test the font properties of labels.""" + ui, main_window = ui + + # Check if the labels have the correct font properties + assert ui.experiment_conversion_factor_label.font().bold() is True + assert ui.experiment_averag_number_label.font().bold() is True + assert ui.experiment_shunt_resistor_label.font().bold() is True + assert ui.advanced_parameters_label.font().bold() is True + assert ui.experiment_time_step_label.font().bold() is True + assert ui.experiment_setpoint_gain_label.font().bold() is True + assert ui.experiment_setpoint_offset_label.font().bold() is True + + +if __name__ == "__main__": + pytest.main() From 89b6dd1857b47f9d745b7d3f9a125fdfce9dcb4e Mon Sep 17 00:00:00 2001 From: Abangma Jessika <127256410+InongoMag@users.noreply.github.com> Date: Wed, 29 Jan 2025 03:43:41 +0100 Subject: [PATCH 5/8] added gui tests for the GUI_config_reader and provided absolute path to the config.yaml file --- src/GUI/code/GUI_config_reader.py | 2 +- tests/test_gui_config_reader.py | 154 ++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 tests/test_gui_config_reader.py diff --git a/src/GUI/code/GUI_config_reader.py b/src/GUI/code/GUI_config_reader.py index 0447aa9..5b7fc6e 100644 --- a/src/GUI/code/GUI_config_reader.py +++ b/src/GUI/code/GUI_config_reader.py @@ -138,6 +138,6 @@ def check_config_inputs(arg): if __name__ == "__main__": # used for debugging. Does the function load the configs? - data = parse_config_file("pytentiostat/tests/static") + data = parse_config_file("C:/Users/user/PycharmProjects/pytentiostat/tests/static/config.yml") data_out_name = data["general_parameters"]["data_output_filename"] print(data_out_name) diff --git a/tests/test_gui_config_reader.py b/tests/test_gui_config_reader.py new file mode 100644 index 0000000..503af04 --- /dev/null +++ b/tests/test_gui_config_reader.py @@ -0,0 +1,154 @@ +import os + +import pytest +import yaml + +from src.GUI.code.GUI_config_reader import ( + check_config_inputs, + get_adv_params, + get_ca_params, + get_cv_params, + get_exp_time, + get_exp_type, + get_lsv_params, + get_output_params, + get_rest, + get_steps, + parse_config_file, +) + +# Sample configuration data for testing +sample_config = { + "general_parameters": { + "data_output_filename": "test_output", + "data_output_path": "desktop", + "experiment_type": "cyclic_voltammetry", + "rest_time": 10, + "step_number": 5, + }, + "linear_sweep_voltammetry": { + "start_voltage": 0.0, + "end_voltage": 1.0, + "sweep_rate": 0.1, + }, + "chronoamperometry": { + "voltage": 0.5, + "time": 60, + }, + "cyclic_voltammetry": { + "start_voltage": -0.5, + "first_turnover_voltage": 0.0, + "second_turnover_voltage": 0.5, + "sweep_rate": 0.1, + "number_of_cycles": 3, + }, + "advanced_parameters": { + "conversion_factor": 1.0, + "setpoint_gain": 2.0, + "setpoint_offset": 0.1, + "shunt_resistor": 1000, + "time_step": 0.01, + "average_number": 10, + }, +} + + +# Create a temporary YAML file for testing +@pytest.fixture +def temp_config_file(tmp_path): + config_file = tmp_path / "config.yml" + with open(config_file, "w") as file: + yaml.dump(sample_config, file) + return config_file + + +def test_parse_config_file(temp_config_file): + config_data = parse_config_file(temp_config_file) + assert config_data == sample_config + + +def test_get_output_params(temp_config_file): + config_data = parse_config_file(temp_config_file) + out_name_ts, out_path = get_output_params(config_data) + assert out_name_ts.startswith("test_output_") + assert out_path == os.path.join(os.path.expanduser("~"), "Desktop") + + +def test_get_lsv_params(temp_config_file): + config_data = parse_config_file(temp_config_file) + start_voltage, end_voltage, sweep_rate = get_lsv_params(config_data) + assert start_voltage == 0.0 + assert end_voltage == 1.0 + assert sweep_rate == 0.1 + + +def test_get_ca_params(temp_config_file): + config_data = parse_config_file(temp_config_file) + voltage, time = get_ca_params(config_data) + assert voltage == 0.5 + assert time == 60 + + +def test_get_cv_params(temp_config_file): + config_data = parse_config_file(temp_config_file) + ( + start_voltage, + first_turnover, + second_turnover, + sweep_rate, + cycle_number, + ) = get_cv_params(config_data) + assert start_voltage == -0.5 + assert first_turnover == 0.0 + assert second_turnover == 0.5 + assert sweep_rate == 0.1 + assert cycle_number == 3 + + +def test_get_exp_type(temp_config_file): + config_data = parse_config_file(temp_config_file) + exp_type = get_exp_type(config_data) + assert exp_type == "cyclic_voltammetry" + + +def test_get_exp_time(temp_config_file): + config_data = parse_config_file(temp_config_file) + exp_time = get_exp_time(config_data) + assert exp_time == 60 + + +def test_get_rest(temp_config_file): + config_data = parse_config_file(temp_config_file) + rest_time = get_rest(config_data) + assert rest_time == 10 + + +def test_get_steps(temp_config_file): + config_data = parse_config_file(temp_config_file) + step_number = get_steps(config_data) + assert step_number == 5 + + +def test_get_adv_params(temp_config_file): + config_data = parse_config_file(temp_config_file) + ( + conversion_factor, + set_gain, + set_offset, + shunt_resistor, + time_step, + average_number, + ) = get_adv_params(config_data) + assert conversion_factor == 1.0 + assert set_gain == 2.0 + assert set_offset == 0.1 + assert shunt_resistor == 1000 + assert time_step == 0.01 + assert average_number == 10 + + +def test_check_config_inputs(): + assert check_config_inputs(10) is True + assert check_config_inputs("10") is True + assert check_config_inputs("abc") is False + assert check_config_inputs(None) is False From bb90bdf683421bff76a88c8c1bb4ce9172444e88 Mon Sep 17 00:00:00 2001 From: Abangma Jessika <127256410+InongoMag@users.noreply.github.com> Date: Wed, 29 Jan 2025 03:59:36 +0100 Subject: [PATCH 6/8] added gui tests for the GUI_CA_exp_creator --- src/GUI/code/GUI_CA_exp_creator.py | 2 +- tests/test_gui_ca_exp_creator.py | 263 +++++++++++++++++++++++++++++ 2 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 tests/test_gui_ca_exp_creator.py diff --git a/src/GUI/code/GUI_CA_exp_creator.py b/src/GUI/code/GUI_CA_exp_creator.py index 19399bc..89796bc 100644 --- a/src/GUI/code/GUI_CA_exp_creator.py +++ b/src/GUI/code/GUI_CA_exp_creator.py @@ -9,7 +9,7 @@ from PySide6.QtGui import QIcon from PySide6.QtWidgets import QGridLayout, QListWidgetItem -from .warning_GUI import warning +from src.GUI.code.warning_GUI import warning ## PartI: load output filepath diff --git a/tests/test_gui_ca_exp_creator.py b/tests/test_gui_ca_exp_creator.py new file mode 100644 index 0000000..a5b25cb --- /dev/null +++ b/tests/test_gui_ca_exp_creator.py @@ -0,0 +1,263 @@ +import os +import tempfile +from unittest.mock import MagicMock + +import pytest + +from src.GUI.code.GUI_CA_exp_creator import ( + CA_main, + CA_window_writer, + check, + config_writer_CA, + get_AP_parameters, + get_parameters, + load_APwindow, + load_folder, + plot, + preview_CA, + save_file, + time_converter, + write_to_file_CA, +) + +# Sample data for testing +sample_AP_params = [4.798, 1.03, 0, 0.202, 0.003, 9] +sample_exp_params = { + "experiment_file_name": "test_output", + "experiment_file_path": tempfile.gettempdir(), + "experiment_rest_time": "10", + "experiment_step_number": "5", + "experiment_voltage": "0.5", + "experiment_time": "60", +} + + +# Mocking the UI class +class MockUiCA: + def __init__(self): + self.experiment_file_path = MagicMock() + self.load_folder_name = MagicMock(return_value=tempfile.gettempdir()) + self.AP_window = MagicMock(return_value=(MagicMock(), MagicMock())) + self.experiment_queue = MagicMock() + self.plot_area = MagicMock() + self.save_experiment_file_button = MagicMock() + + +class MockUiExperiment: + def __init__(self): + self.experiment_file_name = MagicMock() + self.experiment_file_path = MagicMock() + self.experiment_rest_time = MagicMock() + self.experiment_step_number = MagicMock() + self.experiment_voltage = MagicMock() + self.experiment_time = MagicMock() + self.experiment_duration = MagicMock() + self.experiment_averag_number = MagicMock() + self.experiment_conversion_factor = MagicMock() + self.experiment_setpoint_gain = MagicMock() + self.experiment_setpoint_offset = MagicMock() + self.experiment_shunt_resistor = MagicMock() + self.experiment_time_step = MagicMock() + + +# Test for load_folder function +def test_load_folder(): + CA = MockUiCA() + load_folder(CA) + assert CA.experiment_file_path.setText.called + + +# Test for get_AP_parameters function +def test_get_AP_parameters(): + exp = MockUiExperiment() + exp.experiment_conversion_factor.text.return_value = "1.0" + exp.experiment_setpoint_gain.text.return_value = "2.0" + exp.experiment_setpoint_offset.text.return_value = "0.1" + exp.experiment_shunt_resistor.text.return_value = "0.202" + exp.experiment_time_step.text.return_value = "0.003" + exp.experiment_averag_number.text.return_value = "9" + + AP_parameters = get_AP_parameters(exp) + assert AP_parameters == [1.0, 2.0, 0.1, 0.202, 0.003, 9] + + +# Test for load_APwindow function +def test_load_APwindow(): + CA = MockUiCA() + AP_params = sample_AP_params + AP_window_mock, _ = CA.AP_window() + + load_APwindow(CA, AP_params) + + assert AP_window_mock.experiment_conversion_factor.setText.called + assert AP_window_mock.experiment_setpoint_gain.setText.called + assert AP_window_mock.experiment_setpoint_offset.setText.called + assert AP_window_mock.experiment_shunt_resistor.setText.called + assert AP_window_mock.experiment_time_step.setText.called + assert AP_window_mock.experiment_averag_number.setText.called + + # Check if the correct values were set + assert AP_window_mock.experiment_conversion_factor.setText.call_args[0][ + 0 + ] == str(AP_params[0]) + assert AP_window_mock.experiment_setpoint_gain.setText.call_args[0][ + 0 + ] == str(AP_params[1]) + assert AP_window_mock.experiment_setpoint_offset.setText.call_args[0][ + 0 + ] == str(AP_params[2]) + assert AP_window_mock.experiment_shunt_resistor.setText.call_args[0][ + 0 + ] == str(AP_params[3]) + assert AP_window_mock.experiment_time_step.setText.call_args[0][0] == str( + AP_params[4] + ) + assert AP_window_mock.experiment_averag_number.setText.call_args[0][ + 0 + ] == str(AP_params[5]) + + +# Test for time_converter function +def test_time_converter(): + assert time_converter(3661) == "1:01:01" + assert time_converter(-1) == "0:00:00" + + +# Test for plot function +def test_plot(): + x = [0, 1, 2] + y = [0, 1, 0] + canvas = plot(x, y) + assert canvas is not None + + +# Test for preview_CA function +def test_preview_CA(): + exp = MockUiExperiment() + grid = MagicMock() + exp.experiment_step_number.text.return_value = "5" + exp.experiment_voltage.text.return_value = "0.5" + exp.experiment_time.text.return_value = "60" + + preview_CA(exp, grid) + assert exp.experiment_duration.setText.called + + +# Test for save_file function +def test_save_file(): + config_data = {"test_key": "test_value"} + with tempfile.NamedTemporaryFile(delete=False) as temp_file: + config_path_name = temp_file.name + save_file(config_path_name, config_data, 0) + + with open(config_path_name, "r") as file: + contents = file.read() + assert "#General parameters to edit for an experiment" in contents + os.remove(config_path_name) + + +# Test for config_writer_CA function +def test_config_writer_CA(): + exp_type = "CA" + rt = 10 + stp_num = 5 + data_out_name = "test_output" + data_out_path = tempfile.gettempdir() + conv_fact = 1.0 + set_gain = 2.0 + set_offset = 0.1 + sr = 0.202 + ts = 0.003 + avg_num = 9 + ca_v = 0.5 + ca_time = 60 + + config_writer_CA( + exp_type, + rt, + stp_num, + data_out_name, + data_out_path, + conv_fact, + set_gain, + set_offset, + sr, + ts, + avg_num, + ca_v, + ca_time, + ) + config_file_path = os.path.join( + data_out_path, f"{data_out_name}_{exp_type}_config.yml" + ) + assert os.path.exists(config_file_path) + os.remove(config_file_path) + + +# Test for check function +def test_check(): + assert check("123") is True + assert check("-123") is True + assert check("12.3") is True + assert check("abc") is False + assert check("") is False + + +# Test for get_parameters function +def test_get_parameters(): + exp = MockUiExperiment() + exp.experiment_file_name.text.return_value = "test_output" + exp.experiment_file_path.text.return_value = tempfile.gettempdir() + exp.experiment_rest_time.text.return_value = "10" + exp.experiment_step_number.text.return_value = "5" + exp.experiment_voltage.text.return_value = "0.5" + exp.experiment_time.text.return_value = "60" + + AP_parameters = sample_AP_params + config_params = get_parameters(exp, "CA", AP_parameters) + assert config_params[0] == "CA" + assert config_params[3] == "test_output" + + +# Test for write_to_file_CA function +def test_write_to_file_CA(): + ui = MagicMock() + CA = MockUiCA() + CA_window = MagicMock() + AP_params = sample_AP_params + + write_to_file_CA(ui, CA, CA_window, AP_params) + assert CA_window.close.called + + +# Test for CA_window_writer function +def test_CA_window_writer(): + exp = MockUiExperiment() + config_data = { + "general_parameters": { + "data_output_filename": "test_output", + "data_output_path": tempfile.gettempdir(), + "rest_time": 10, + "step_number": 5, + }, + "chronoamperometry": { + "voltage": 0.5, + "time": 60, + }, + } + + CA_window_writer(exp, config_data) + assert exp.experiment_file_name.setText.called + assert exp.experiment_file_path.setText.called + + +# Test for CA_main function +def test_CA_main(): + ui = MagicMock() + config_data = None + CA = CA_main(ui, config_data) + assert CA is not None + + +if __name__ == "__main__": + pytest.main() From 66e804e8f317314df97bed874e2f856ae5215e5a Mon Sep 17 00:00:00 2001 From: Abangma Jessika <127256410+InongoMag@users.noreply.github.com> Date: Wed, 29 Jan 2025 04:52:01 +0100 Subject: [PATCH 7/8] added gui tests for the GUI_CV_exp_creator --- tests/test_gui_cv_exp_creator.py | 335 +++++++++++++++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 tests/test_gui_cv_exp_creator.py diff --git a/tests/test_gui_cv_exp_creator.py b/tests/test_gui_cv_exp_creator.py new file mode 100644 index 0000000..9caeb53 --- /dev/null +++ b/tests/test_gui_cv_exp_creator.py @@ -0,0 +1,335 @@ +import os +import tempfile +from unittest.mock import MagicMock + +import numpy as np +import pytest + +from src.GUI.code.GUI_CV_exp_creator import ( + CV_data, + CV_main, + CV_window_writer, + check, + config_writer_CV, + get_AP_parameters, + get_parameters, + load_APwindow, + load_folder, + plot, + preview_CV, + save_file, + time_converter, + write_to_file_CV, +) + +# Sample data for testing +sample_AP_params = [4.798, 1.03, 0, 0.202, 0.003, 9] +sample_exp_params = { + "experiment_file_name": "test_output", + "experiment_file_path": tempfile.gettempdir(), + "experiment_rest_time": "10", + "experiment_step_number": "5", + "experiment_start_voltage": "0.5", + "experiment_first_vertex_voltage": "1.0", + "experiment_second_vertex_voltage": "0.0", + "experiment_sweep_rate": "0.1", + "experiment_cycle_number": "3", +} + + +# Mocking the UI class +class MockUiCV: + def __init__(self): + self.experiment_file_path = MagicMock() + self.load_folder_name = MagicMock(return_value=tempfile.gettempdir()) + self.AP_window = MagicMock(return_value=(MagicMock(), MagicMock())) + self.plot_area = MagicMock() + self.save_experiment_file_button = MagicMock() + self.experiment_queue = MagicMock() + + +class MockUiExperiment: + def __init__(self): + self.experiment_file_name = MagicMock() + self.experiment_file_path = MagicMock() + self.experiment_rest_time = MagicMock() + self.experiment_step_number = MagicMock() + self.experiment_start_voltage = MagicMock() + self.experiment_first_vertex_voltage = MagicMock() + self.experiment_second_vertex_voltage = MagicMock() + self.experiment_sweep_rate = MagicMock() + self.experiment_cycle_number = MagicMock() + self.experiment_duration = MagicMock() + self.experiment_averag_number = MagicMock() + self.experiment_conversion_factor = MagicMock() + self.experiment_setpoint_gain = MagicMock() + self.experiment_setpoint_offset = MagicMock() + self.experiment_shunt_resistor = MagicMock() + self.experiment_time_step = MagicMock() + + +# Test for load_folder function +def test_load_folder(): + CV = MockUiCV() + load_folder(CV) + assert CV.experiment_file_path.setText.called + + +# Test for get_AP_parameters function +def test_get_AP_parameters(): + exp = MockUiExperiment() + exp.experiment_conversion_factor.text.return_value = "1.0" + exp.experiment_setpoint_gain.text.return_value = "2.0" + exp.experiment_setpoint_offset.text.return_value = "0.1" + exp.experiment_shunt_resistor.text.return_value = "0.202" + exp.experiment_time_step.text.return_value = "0.003" + exp.experiment_averag_number.text.return_value = "9" + + AP_parameters = get_AP_parameters(exp) + assert AP_parameters == [1.0, 2.0, 0.1, 0.202, 0.003, 9] + + +# Test for load_APwindow function +def test_load_APwindow(): + CV = MockUiCV() + AP_params = sample_AP_params + AP_window_mock, _ = CV.AP_window() + + load_APwindow(CV, AP_params) + + assert AP_window_mock.experiment_conversion_factor.setText.called + assert AP_window_mock.experiment_setpoint_gain.setText.called + assert AP_window_mock.experiment_setpoint_offset.setText.called + assert AP_window_mock.experiment_shunt_resistor.setText.called + assert AP_window_mock.experiment_time_step.setText.called + assert AP_window_mock.experiment_averag_number.setText.called + + # Check if the correct values were set + assert AP_window_mock.experiment_conversion_factor.setText.call_args[0][ + 0 + ] == str(AP_params[0]) + assert AP_window_mock.experiment_setpoint_gain.setText.call_args[0][ + 0 + ] == str(AP_params[1]) + assert AP_window_mock.experiment_setpoint_offset.setText.call_args[0][ + 0 + ] == str(AP_params[2]) + assert AP_window_mock.experiment_shunt_resistor.setText.call_args[0][ + 0 + ] == str(AP_params[3]) + assert AP_window_mock.experiment_time_step.setText.call_args[0][0] == str( + AP_params[4] + ) + assert AP_window_mock.experiment_averag_number.setText.call_args[0][ + 0 + ] == str(AP_params[5]) + + +# Test for time_converter function +def test_time_converter(): + assert time_converter(3661) == "1:01:01" + assert time_converter(-1) == "0:00:00" + + +# Test for CV_data function +def test_CV_data(): + # Test case 1: Normal case + stp_num = 6 + cv_sv = 0.0 + cv_ftv = 1.0 + cv_stv = 0.0 + cv_sr = 100.0 + + times_step_list, steps_list = CV_data( + stp_num, cv_sv, cv_ftv, cv_stv, cv_sr + ) + + expected_length = stp_num + assert ( + len(times_step_list) - 1 == expected_length + ), f"Expected {expected_length} times steps, got {len(times_step_list)}" + assert ( + len(steps_list) - 1 == expected_length + ), f"Expected {expected_length} steps, got {len(steps_list)}" + + # Test case 2: Negative voltages + stp_num = 6 + cv_sv = -1.0 + cv_ftv = 0.0 + cv_stv = -0.5 + cv_sr = 100.0 + + times_step_list, steps_list = CV_data( + stp_num, cv_sv, cv_ftv, cv_stv, cv_sr + ) + + # Check if the function handles negative voltages correctly + assert ( + len(times_step_list) - 1 == expected_length + ), f"Expected {expected_length} times steps, got {len(times_step_list)}" + assert ( + len(steps_list) - 1 == expected_length + ), f"Expected {expected_length} steps, got {len(steps_list)}" + + # Additional checks on the values in the lists + assert np.all( + steps_list >= min(cv_sv, cv_ftv, cv_stv) + ), "Steps should not be less than the minimum voltage" + assert np.all( + steps_list <= max(cv_sv, cv_ftv, cv_stv) + ), "Steps should not be greater than the maximum voltage" + + +# Test for preview_CV function +def test_preview_CV(): + exp = MockUiExperiment() + grid = MagicMock() + exp.experiment_step_number.text.return_value = "5" + exp.experiment_start_voltage.text.return_value = "0.0" + exp.experiment_first_vertex_voltage.text.return_value = "1.0" + exp.experiment_second_vertex_voltage.text.return_value = "0.0" + exp.experiment_sweep_rate.text.return_value = "0.1" + exp.experiment_cycle_number.text.return_value = "3" + + preview_CV(exp, grid) + assert exp.experiment_duration.setText.called + + +# Test for save_file function +def test_save_file(): + config_data = {"test_key": "test_value"} + with tempfile.NamedTemporaryFile(delete=False) as temp_file: + config_path_name = temp_file.name + save_file(config_path_name, config_data, 0) + + with open(config_path_name, "r") as file: + contents = file.read() + assert "#General parameters to edit for an experiment" in contents + os.remove(config_path_name) + + +# Test for config_writer_CV function +def test_config_writer_CV(): + exp_type = "CV" + rt = 10 + stp_num = 6 + data_out_name = "test_output" + data_out_path = tempfile.gettempdir() + conv_fact = 1.0 + set_gain = 2.0 + set_offset = 0.1 + sr = 0.202 + ts = 0.003 + avg_num = 9 + cv_sv = 0.0 + cv_ftv = 1.0 + cv_stv = 0.0 + cv_sr = 0.1 + cyc_num = 3 + + config_writer_CV( + exp_type, + rt, + stp_num, + data_out_name, + data_out_path, + conv_fact, + set_gain, + set_offset, + sr, + ts, + avg_num, + cv_sv, + cv_ftv, + cv_stv, + cv_sr, + cyc_num, + ) + config_file_path = os.path.join( + data_out_path, f"{data_out_name}_{exp_type}_config.yml" + ) + assert os.path.exists(config_file_path) + os.remove(config_file_path) + + +# Test for check function +def test_check(): + assert check("123") is True + assert check("-123") is True + assert check("12.3") is True + assert check("abc") is False + assert check("") is False + + +# Test for get_parameters function +def test_get_parameters(): + exp = MockUiExperiment() + exp.experiment_file_name.text.return_value = "test_output" + exp.experiment_file_path.text.return_value = tempfile.gettempdir() + exp.experiment_rest_time.text.return_value = "10" + exp.experiment_step_number.text.return_value = "5" + exp.experiment_start_voltage.text.return_value = "0.0" + exp.experiment_first_vertex_voltage.text.return_value = "1.0" + exp.experiment_second_vertex_voltage.text.return_value = "0.0" + exp.experiment_sweep_rate.text.return_value = "0.1" + exp.experiment_cycle_number.text.return_value = "3" + + AP_parameters = sample_AP_params + config_params = get_parameters(exp, "CV", AP_parameters) + assert config_params[0] == "CV" + assert config_params[3] == "test_output" + + +# Test for write_to_file_CV function +def test_write_to_file_CV(): + ui = MagicMock() + CV = MockUiCV() + CV_window = MagicMock() + AP_params = sample_AP_params + + write_to_file_CV(ui, CV, CV_window, AP_params) + assert CV_window.close.called + + +# Test for CV_window_writer function +def test_CV_window_writer(): + exp = MockUiExperiment() + config_data = { + "general_parameters": { + "data_output_filename": "test_output", + "data_output_path": tempfile.gettempdir(), + "rest_time": 10, + "step_number": 5, + }, + "cyclic_voltammetry": { + "start_voltage": 0.0, + "first_turnover_voltage": 1.0, + "second_turnover_voltage": 0.0, + "sweep_rate": 0.1, + "number_of_cycles": 3, + }, + } + + CV_window_writer(exp, config_data) + assert exp.experiment_file_name.setText.called + assert exp.experiment_file_path.setText.called + + +# Test for CV_main function +def test_CV_main(): + ui = MagicMock() + config_data = None # or provide a sample config_data if needed + CV = CV_main(ui, config_data) + assert CV is not None + + +# Test for plot function +def test_plot(): + x = [0, 1, 2] + y = [0, 1, 0] + canvas = plot(x, y) + assert canvas is not None + + +if __name__ == "__main__": + pytest.main() From f7d0210dc2defa1981ffbbe1ec85bbe25ecca610 Mon Sep 17 00:00:00 2001 From: Abangma Jessika <127256410+InongoMag@users.noreply.github.com> Date: Wed, 29 Jan 2025 05:27:50 +0100 Subject: [PATCH 8/8] reverted back to the original way the import statement was for the files --- src/GUI/code/CA_GUI.py | 7 +++---- src/GUI/code/CV_GUI.py | 7 +++---- src/GUI/code/GUI_CA_exp_creator.py | 3 +-- src/GUI/code/GUI_CV_exp_creator.py | 3 +-- src/GUI/code/GUI_LSV_exp_creator.py | 3 +-- src/GUI/code/GUI_file_operation.py | 13 ++++++------- src/GUI/code/GUI_operator.py | 5 ++--- src/GUI/code/GUI_plotter.py | 7 +++---- src/GUI/code/GUI_routines.py | 3 +-- src/GUI/code/GUI_run_exp.py | 14 +++++++------- src/GUI/code/LSV_GUI.py | 7 +++---- src/GUI/code/main.py | 20 +++++--------------- src/GUI/code/mainwindow_GUI.py | 11 +++++------ tests/test_gui_ca_exp_creator.py | 16 ++++++++-------- 14 files changed, 49 insertions(+), 70 deletions(-) diff --git a/src/GUI/code/CA_GUI.py b/src/GUI/code/CA_GUI.py index c626093..f749522 100644 --- a/src/GUI/code/CA_GUI.py +++ b/src/GUI/code/CA_GUI.py @@ -1,11 +1,10 @@ ## Standard library -from PySide6 import QtCore, QtGui, QtWidgets - -from src.GUI.code.Adv_params_GUI import Ui_Adv_Params +from Adv_params_GUI import Ui_Adv_Params ## Local library # GUI_function -from src.GUI.code.GUI_load_config import Ui_Load +from GUI_load_config import Ui_Load +from PySide6 import QtCore, QtGui, QtWidgets class Ui_CA(object): diff --git a/src/GUI/code/CV_GUI.py b/src/GUI/code/CV_GUI.py index 111b90c..1c34663 100644 --- a/src/GUI/code/CV_GUI.py +++ b/src/GUI/code/CV_GUI.py @@ -1,11 +1,10 @@ ## Standard library -from PySide6 import QtCore, QtGui, QtWidgets - -from src.GUI.code.Adv_params_GUI import Ui_Adv_Params +from Adv_params_GUI import Ui_Adv_Params ## Local library # GUI_function -from src.GUI.code.GUI_load_config import Ui_Load +from GUI_load_config import Ui_Load +from PySide6 import QtCore, QtGui, QtWidgets class Ui_CV(object): diff --git a/src/GUI/code/GUI_CA_exp_creator.py b/src/GUI/code/GUI_CA_exp_creator.py index 89796bc..970a548 100644 --- a/src/GUI/code/GUI_CA_exp_creator.py +++ b/src/GUI/code/GUI_CA_exp_creator.py @@ -8,8 +8,7 @@ from matplotlib.figure import Figure from PySide6.QtGui import QIcon from PySide6.QtWidgets import QGridLayout, QListWidgetItem - -from src.GUI.code.warning_GUI import warning +from warning_GUI import warning ## PartI: load output filepath diff --git a/src/GUI/code/GUI_CV_exp_creator.py b/src/GUI/code/GUI_CV_exp_creator.py index edf0a6d..ca0e6dd 100644 --- a/src/GUI/code/GUI_CV_exp_creator.py +++ b/src/GUI/code/GUI_CV_exp_creator.py @@ -8,8 +8,7 @@ from matplotlib.figure import Figure from PySide6.QtGui import QIcon from PySide6.QtWidgets import QGridLayout, QListWidgetItem - -from src.GUI.code.warning_GUI import warning +from warning_GUI import warning ## PartI: load output filepath diff --git a/src/GUI/code/GUI_LSV_exp_creator.py b/src/GUI/code/GUI_LSV_exp_creator.py index be9c767..6a531d9 100644 --- a/src/GUI/code/GUI_LSV_exp_creator.py +++ b/src/GUI/code/GUI_LSV_exp_creator.py @@ -8,8 +8,7 @@ from matplotlib.figure import Figure from PySide6.QtGui import QIcon from PySide6.QtWidgets import QGridLayout, QListWidgetItem - -from src.GUI.code.warning_GUI import warning +from warning_GUI import warning ## PartI: load output filepath diff --git a/src/GUI/code/GUI_file_operation.py b/src/GUI/code/GUI_file_operation.py index 66fdae3..4f6b50c 100644 --- a/src/GUI/code/GUI_file_operation.py +++ b/src/GUI/code/GUI_file_operation.py @@ -1,18 +1,17 @@ ## Standard libraries from functools import partial +# GUI_function +from GUI_CA_exp_creator import CA_main, CA_window_writer +from GUI_config_reader import parse_config_file +from GUI_CV_exp_creator import CV_main, CV_window_writer +from GUI_LSV_exp_creator import LSV_main, LSV_window_writer from PySide6.QtGui import QIcon from PySide6.QtWidgets import QListWidgetItem -# GUI_function -from src.GUI.code.GUI_CA_exp_creator import CA_main, CA_window_writer -from src.GUI.code.GUI_config_reader import parse_config_file -from src.GUI.code.GUI_CV_exp_creator import CV_main, CV_window_writer -from src.GUI.code.GUI_LSV_exp_creator import LSV_main, LSV_window_writer - ## Local libraries # GUI window -from src.GUI.code.warning_GUI import warning +from warning_GUI import warning def add_exp(ui): diff --git a/src/GUI/code/GUI_operator.py b/src/GUI/code/GUI_operator.py index 0a656c1..4d577cb 100644 --- a/src/GUI/code/GUI_operator.py +++ b/src/GUI/code/GUI_operator.py @@ -2,11 +2,10 @@ import datetime import time -import numpy as np - ## Local library # GUI_function -import src.GUI.code.GUI_config_reader as cr +import GUI_config_reader as cr +import numpy as np def start_exp(d9, normalized_start, data): diff --git a/src/GUI/code/GUI_plotter.py b/src/GUI/code/GUI_plotter.py index e33efbd..0d0b7f9 100644 --- a/src/GUI/code/GUI_plotter.py +++ b/src/GUI/code/GUI_plotter.py @@ -1,6 +1,9 @@ ## Standard libraries import sys +##Local library +# GUI_function +import GUI_config_reader as cr from matplotlib.backends.backend_qt5agg import ( FigureCanvasQTAgg as FigureCanvas, ) @@ -10,10 +13,6 @@ from matplotlib.figure import Figure from PySide6.QtWidgets import QApplication, QWidget -##Local library -# GUI_function -import src.GUI.code.GUI_config_reader as cr - class Ui_Plot(QWidget): def __init__(self): diff --git a/src/GUI/code/GUI_routines.py b/src/GUI/code/GUI_routines.py index b1ffb59..cab6277 100644 --- a/src/GUI/code/GUI_routines.py +++ b/src/GUI/code/GUI_routines.py @@ -3,8 +3,7 @@ import serial.tools.list_ports from pyfirmata import Arduino, util from PySide6.QtGui import QIcon - -from src.GUI.code.warning_GUI import warning +from warning_GUI import warning _BAUD_RATE = 115200 diff --git a/src/GUI/code/GUI_run_exp.py b/src/GUI/code/GUI_run_exp.py index 7573c7b..b5cc60c 100644 --- a/src/GUI/code/GUI_run_exp.py +++ b/src/GUI/code/GUI_run_exp.py @@ -2,16 +2,16 @@ import csv import os +from GUI_config_reader import parse_config_file +from GUI_operator import experiment + +# GUI function +from GUI_plotter import Ui_Plot + ## Local libraries # GUI window from PySide6.QtGui import QIcon - -from src.GUI.code.GUI_config_reader import parse_config_file -from src.GUI.code.GUI_operator import experiment - -# GUI function -from src.GUI.code.GUI_plotter import Ui_Plot -from src.GUI.code.warning_GUI import warning +from warning_GUI import warning def calculate_time(filename): diff --git a/src/GUI/code/LSV_GUI.py b/src/GUI/code/LSV_GUI.py index bd8f5d2..4652146 100644 --- a/src/GUI/code/LSV_GUI.py +++ b/src/GUI/code/LSV_GUI.py @@ -1,11 +1,10 @@ ## Standard library -from PySide6 import QtCore, QtGui, QtWidgets - -from src.GUI.code.Adv_params_GUI import Ui_Adv_Params +from Adv_params_GUI import Ui_Adv_Params ## Local library # GUI_function -from src.GUI.code.GUI_load_config import Ui_Load +from GUI_load_config import Ui_Load +from PySide6 import QtCore, QtGui, QtWidgets class Ui_LSV(object): diff --git a/src/GUI/code/main.py b/src/GUI/code/main.py index 5ec4a69..ea68ad5 100644 --- a/src/GUI/code/main.py +++ b/src/GUI/code/main.py @@ -2,26 +2,16 @@ import sys from functools import partial -from PySide6.QtWidgets import QApplication, QGridLayout, QMainWindow - -from src.GUI.code.GUI_file_operation import ( - add_exp, - edit_file, - load_file, - remove_file, -) +from GUI_file_operation import add_exp, edit_file, load_file, remove_file # GUI function -from src.GUI.code.GUI_routines import ( - _load_arduino, - disconnect_port_main, - find_port_main, -) -from src.GUI.code.GUI_run_exp import run_exp_main +from GUI_routines import _load_arduino, disconnect_port_main, find_port_main +from GUI_run_exp import run_exp_main ## Local libraries # GUI window -from src.GUI.code.mainwindow_GUI import Ui_MainWindow +from mainwindow_GUI import Ui_MainWindow +from PySide6.QtWidgets import QApplication, QGridLayout, QMainWindow # load the main window app = QApplication(sys.argv) diff --git a/src/GUI/code/mainwindow_GUI.py b/src/GUI/code/mainwindow_GUI.py index d9e09e9..446d339 100644 --- a/src/GUI/code/mainwindow_GUI.py +++ b/src/GUI/code/mainwindow_GUI.py @@ -1,11 +1,10 @@ +from CA_GUI import Ui_CA +from CV_GUI import Ui_CV +from Exp_type_GUI import Ui_Experiment +from GUI_load_config import Ui_Load +from LSV_GUI import Ui_LSV from PySide6 import QtCore, QtGui, QtWidgets -from src.GUI.code.CA_GUI import Ui_CA -from src.GUI.code.CV_GUI import Ui_CV -from src.GUI.code.Exp_type_GUI import Ui_Experiment -from src.GUI.code.GUI_load_config import Ui_Load -from src.GUI.code.LSV_GUI import Ui_LSV - class Ui_MainWindow(object): def show_exp(self): diff --git a/tests/test_gui_ca_exp_creator.py b/tests/test_gui_ca_exp_creator.py index a5b25cb..cb82873 100644 --- a/tests/test_gui_ca_exp_creator.py +++ b/tests/test_gui_ca_exp_creator.py @@ -123,14 +123,6 @@ def test_time_converter(): assert time_converter(-1) == "0:00:00" -# Test for plot function -def test_plot(): - x = [0, 1, 2] - y = [0, 1, 0] - canvas = plot(x, y) - assert canvas is not None - - # Test for preview_CA function def test_preview_CA(): exp = MockUiExperiment() @@ -259,5 +251,13 @@ def test_CA_main(): assert CA is not None +# Test for plot function +def test_plot(): + x = [0, 1, 2] + y = [0, 1, 0] + canvas = plot(x, y) + assert canvas is not None + + if __name__ == "__main__": pytest.main()