Coverage for test/test_utils.py: 100%
119 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-15 20:42 -0400
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-15 20:42 -0400
1from unittest.mock import patch, mock_open, MagicMock
2from datetime import datetime
3import json
4import os
5import tempfile
6from pathlib import Path
8import pytest
9import pandas as pd
11# Assuming the run_log function is defined in a module named 'log_module'
12from peakipy.utils import (
13 run_log,
14 update_args_with_values_from_config_file,
15 update_peak_positions_from_ppm_to_points,
16 update_linewidths_from_hz_to_points,
17 save_data,
18)
21@patch("peakipy.utils.open", new_callable=mock_open)
22@patch("peakipy.utils.datetime")
23@patch("peakipy.utils.sys")
24def test_run_log(mock_sys, mock_datetime, mock_open_file):
25 # Mocking sys.argv
26 mock_sys.argv = ["test_script.py", "arg1", "arg2"]
28 # Mocking datetime to return a fixed timestamp
29 fixed_timestamp = datetime(2024, 5, 20, 15, 45)
30 mock_datetime.now.return_value = fixed_timestamp
32 # Expected timestamp string
33 expected_time_stamp = fixed_timestamp.strftime("%A %d %B %Y at %H:%M")
35 # Run the function
36 run_log("mock_run_log.txt")
38 # Prepare the expected log content
39 expected_log_content = (
40 f"# Script run on {expected_time_stamp}:\ntest_script.py arg1 arg2\n"
41 )
43 # Assert that the file was opened correctly
44 mock_open_file.assert_called_once_with("mock_run_log.txt", "a")
46 # Assert that the correct content was written to the file
47 mock_open_file().write.assert_called_once_with(expected_log_content)
49 # Assert that the script name is correctly set to the basename
50 assert mock_sys.argv[0] == "test_script.py"
53# Mock configuration loader function (you need to replace 'config_module.load_config' with the actual path if different)
54@patch("peakipy.utils.load_config")
55@patch("peakipy.utils.Path.exists")
56def test_update_args_with_config(mock_path_exists, mock_load_config):
57 # Test setup
58 mock_path_exists.return_value = True # Pretend the config file exists
59 mock_load_config.return_value = {
60 "dims": [1, 2, 3],
61 "noise": "0.05",
62 "colors": ["#ff0000", "#00ff00"],
63 }
65 args = {"dims": (0, 1, 2), "noise": False, "colors": ["#5e3c99", "#e66101"]}
67 # Run the function
68 updated_args, config = update_args_with_values_from_config_file(args)
70 # Check the updates to args
71 assert updated_args["dims"] == [1, 2, 3]
72 assert updated_args["noise"] == 0.05
73 assert updated_args["colors"] == ["#ff0000", "#00ff00"]
75 # Check the returned config
76 assert config == {
77 "dims": [1, 2, 3],
78 "noise": "0.05",
79 "colors": ["#ff0000", "#00ff00"],
80 }
83@patch("peakipy.utils.Path.exists")
84def test_update_args_with_no_config_file(mock_path_exists):
85 # Test setup
86 mock_path_exists.return_value = False # Pretend the config file does not exist
88 args = {"dims": (0, 1, 2), "noise": False, "colors": ["#5e3c99", "#e66101"]}
90 # Run the function
91 updated_args, config = update_args_with_values_from_config_file(args)
93 # Check the updates to args
94 assert updated_args["dims"] == (0, 1, 2)
95 assert updated_args["noise"] == False
96 assert updated_args["colors"] == ["#5e3c99", "#e66101"]
98 # Check the returned config (should be empty)
99 assert config == {}
102@patch("peakipy.utils.load_config")
103@patch("peakipy.utils.Path.exists")
104def test_update_args_with_corrupt_config_file(mock_path_exists, mock_load_config):
105 # Test setup
106 mock_path_exists.return_value = True # Pretend the config file exists
107 mock_load_config.side_effect = json.decoder.JSONDecodeError(
108 "Expecting value", "", 0
109 ) # Simulate corrupt JSON
111 args = {"dims": (0, 1, 2), "noise": False, "colors": ["#5e3c99", "#e66101"]}
113 # Run the function
114 updated_args, config = update_args_with_values_from_config_file(args)
116 # Check the updates to args
117 assert updated_args["dims"] == (0, 1, 2)
118 assert updated_args["noise"] == False
119 assert updated_args["colors"] == ["#5e3c99", "#e66101"]
121 # Check the returned config (should be empty due to error)
122 assert config == {}
124 # Mock class to simulate the peakipy_data object
127class MockPeakipyData:
128 def __init__(self, df, pt_per_hz_f2, pt_per_hz_f1, uc_f2, uc_f1):
129 self.df = df
130 self.pt_per_hz_f2 = pt_per_hz_f2
131 self.pt_per_hz_f1 = pt_per_hz_f1
132 self.uc_f2 = uc_f2
133 self.uc_f1 = uc_f1
136# Test data
137@pytest.fixture
138def mock_peakipy_data():
139 df = pd.DataFrame(
140 {
141 "XW_HZ": [10, 20, 30],
142 "YW_HZ": [5, 15, 25],
143 "X_PPM": [1.0, 2.0, 3.0],
144 "Y_PPM": [0.5, 1.5, 2.5],
145 }
146 )
148 pt_per_hz_f2 = 2.0
149 pt_per_hz_f1 = 3.0
151 uc_f2 = MagicMock()
152 uc_f1 = MagicMock()
153 uc_f2.side_effect = lambda x, unit: x * 100.0 if unit == "PPM" else x
154 uc_f1.side_effect = lambda x, unit: x * 200.0 if unit == "PPM" else x
155 uc_f2.f = MagicMock(side_effect=lambda x, unit: x * 1000.0 if unit == "PPM" else x)
156 uc_f1.f = MagicMock(side_effect=lambda x, unit: x * 2000.0 if unit == "PPM" else x)
158 return MockPeakipyData(df, pt_per_hz_f2, pt_per_hz_f1, uc_f2, uc_f1)
161def test_update_linewidths_from_hz_to_points(mock_peakipy_data):
162 peakipy_data = update_linewidths_from_hz_to_points(mock_peakipy_data)
164 expected_XW = [20.0, 40.0, 60.0]
165 expected_YW = [15.0, 45.0, 75.0]
167 pd.testing.assert_series_equal(
168 peakipy_data.df["XW"], pd.Series(expected_XW, name="XW")
169 )
170 pd.testing.assert_series_equal(
171 peakipy_data.df["YW"], pd.Series(expected_YW, name="YW")
172 )
175def test_update_peak_positions_from_ppm_to_points(mock_peakipy_data):
176 peakipy_data = update_peak_positions_from_ppm_to_points(mock_peakipy_data)
178 expected_X_AXIS = [100.0, 200.0, 300.0]
179 expected_Y_AXIS = [100.0, 300.0, 500.0]
180 expected_X_AXISf = [1000.0, 2000.0, 3000.0]
181 expected_Y_AXISf = [1000.0, 3000.0, 5000.0]
183 pd.testing.assert_series_equal(
184 peakipy_data.df["X_AXIS"], pd.Series(expected_X_AXIS, name="X_AXIS")
185 )
186 pd.testing.assert_series_equal(
187 peakipy_data.df["Y_AXIS"], pd.Series(expected_Y_AXIS, name="Y_AXIS")
188 )
189 pd.testing.assert_series_equal(
190 peakipy_data.df["X_AXISf"], pd.Series(expected_X_AXISf, name="X_AXISf")
191 )
192 pd.testing.assert_series_equal(
193 peakipy_data.df["Y_AXISf"], pd.Series(expected_Y_AXISf, name="Y_AXISf")
194 )
197@pytest.fixture
198def sample_dataframe():
199 data = {"A": [1, 2, 3], "B": [4.5678, 5.6789, 6.7890]}
200 return pd.DataFrame(data)
203def test_save_data_csv(sample_dataframe):
204 with tempfile.NamedTemporaryFile(suffix=".csv", delete=False) as tmpfile:
205 output_name = Path(tmpfile.name)
207 try:
208 save_data(sample_dataframe, output_name)
210 assert output_name.exists()
212 # Load the CSV and compare with the original dataframe
213 loaded_df = pd.read_csv(output_name)
214 pd.testing.assert_frame_equal(
215 loaded_df, sample_dataframe, check_exact=False, rtol=1e-4
216 )
217 finally:
218 os.remove(output_name)
221def test_save_data_tab(sample_dataframe):
222 with tempfile.NamedTemporaryFile(suffix=".tab", delete=False) as tmpfile:
223 output_name = Path(tmpfile.name)
225 try:
226 save_data(sample_dataframe, output_name)
228 assert output_name.exists()
230 # Load the tab-separated file and compare with the original dataframe
231 loaded_df = pd.read_csv(output_name, sep="\t")
232 pd.testing.assert_frame_equal(
233 loaded_df, sample_dataframe, check_exact=False, rtol=1e-4
234 )
235 finally:
236 os.remove(output_name)
239def test_save_data_pickle(sample_dataframe):
240 with tempfile.NamedTemporaryFile(suffix=".pkl", delete=False) as tmpfile:
241 output_name = Path(tmpfile.name)
243 try:
244 save_data(sample_dataframe, output_name)
246 assert output_name.exists()
248 # Load the pickle file and compare with the original dataframe
249 loaded_df = pd.read_pickle(output_name)
250 pd.testing.assert_frame_equal(loaded_df, sample_dataframe)
251 finally:
252 os.remove(output_name)