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

1from unittest.mock import patch, mock_open, MagicMock 

2from datetime import datetime 

3import json 

4import os 

5import tempfile 

6from pathlib import Path 

7 

8import pytest 

9import pandas as pd 

10 

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) 

19 

20 

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"] 

27 

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 

31 

32 # Expected timestamp string 

33 expected_time_stamp = fixed_timestamp.strftime("%A %d %B %Y at %H:%M") 

34 

35 # Run the function 

36 run_log("mock_run_log.txt") 

37 

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 ) 

42 

43 # Assert that the file was opened correctly 

44 mock_open_file.assert_called_once_with("mock_run_log.txt", "a") 

45 

46 # Assert that the correct content was written to the file 

47 mock_open_file().write.assert_called_once_with(expected_log_content) 

48 

49 # Assert that the script name is correctly set to the basename 

50 assert mock_sys.argv[0] == "test_script.py" 

51 

52 

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 } 

64 

65 args = {"dims": (0, 1, 2), "noise": False, "colors": ["#5e3c99", "#e66101"]} 

66 

67 # Run the function 

68 updated_args, config = update_args_with_values_from_config_file(args) 

69 

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"] 

74 

75 # Check the returned config 

76 assert config == { 

77 "dims": [1, 2, 3], 

78 "noise": "0.05", 

79 "colors": ["#ff0000", "#00ff00"], 

80 } 

81 

82 

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 

87 

88 args = {"dims": (0, 1, 2), "noise": False, "colors": ["#5e3c99", "#e66101"]} 

89 

90 # Run the function 

91 updated_args, config = update_args_with_values_from_config_file(args) 

92 

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"] 

97 

98 # Check the returned config (should be empty) 

99 assert config == {} 

100 

101 

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 

110 

111 args = {"dims": (0, 1, 2), "noise": False, "colors": ["#5e3c99", "#e66101"]} 

112 

113 # Run the function 

114 updated_args, config = update_args_with_values_from_config_file(args) 

115 

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"] 

120 

121 # Check the returned config (should be empty due to error) 

122 assert config == {} 

123 

124 # Mock class to simulate the peakipy_data object 

125 

126 

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 

134 

135 

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 ) 

147 

148 pt_per_hz_f2 = 2.0 

149 pt_per_hz_f1 = 3.0 

150 

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) 

157 

158 return MockPeakipyData(df, pt_per_hz_f2, pt_per_hz_f1, uc_f2, uc_f1) 

159 

160 

161def test_update_linewidths_from_hz_to_points(mock_peakipy_data): 

162 peakipy_data = update_linewidths_from_hz_to_points(mock_peakipy_data) 

163 

164 expected_XW = [20.0, 40.0, 60.0] 

165 expected_YW = [15.0, 45.0, 75.0] 

166 

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 ) 

173 

174 

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) 

177 

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] 

182 

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 ) 

195 

196 

197@pytest.fixture 

198def sample_dataframe(): 

199 data = {"A": [1, 2, 3], "B": [4.5678, 5.6789, 6.7890]} 

200 return pd.DataFrame(data) 

201 

202 

203def test_save_data_csv(sample_dataframe): 

204 with tempfile.NamedTemporaryFile(suffix=".csv", delete=False) as tmpfile: 

205 output_name = Path(tmpfile.name) 

206 

207 try: 

208 save_data(sample_dataframe, output_name) 

209 

210 assert output_name.exists() 

211 

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) 

219 

220 

221def test_save_data_tab(sample_dataframe): 

222 with tempfile.NamedTemporaryFile(suffix=".tab", delete=False) as tmpfile: 

223 output_name = Path(tmpfile.name) 

224 

225 try: 

226 save_data(sample_dataframe, output_name) 

227 

228 assert output_name.exists() 

229 

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) 

237 

238 

239def test_save_data_pickle(sample_dataframe): 

240 with tempfile.NamedTemporaryFile(suffix=".pkl", delete=False) as tmpfile: 

241 output_name = Path(tmpfile.name) 

242 

243 try: 

244 save_data(sample_dataframe, output_name) 

245 

246 assert output_name.exists() 

247 

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)