@@ -57,6 +57,28 @@ def test_each_dataset_is_drawn_with_its_own_resolution(self, qcore_application,
5757 expected = project .model_data_for_experiment_at_index (index , q_range = q ).y
5858 np .testing .assert_allclose (drawn , expected , rtol = 1e-12 )
5959
60+ def test_a_narrowed_q_range_keeps_the_widths_of_overlapping_measurements (self , qcore_application , tmp_path ):
61+ # Two measurements of one contrast on the same q grid with very different
62+ # widths: the merged dataset holds every q twice. Restricting the q range
63+ # must not change the curve at the points that remain.
64+ q = np .array ([0.01 , 0.03 , 0.05 , 0.08 , 0.10 , 0.15 , 0.20 , 0.25 , 0.30 ])
65+ project = Project ()
66+ project .default_model ()
67+ project .load_new_experiment (_write_file (tmp_path / 'sharp.txt' , q , 0.002 ))
68+ project .append_to_experiment_at_index (0 , _write_file (tmp_path / 'broad.txt' , q , 0.08 ))
69+ merged = project .experiments [0 ]
70+ full = np .asarray (project .model_data_for_experiment_at_index (0 ).y )
71+ project .q_min = 0.03
72+ project .q_max = 0.25
73+ plotting = Plotting1d (project_lib = project , parent = None )
74+
75+ points = plotting ._get_aligned_analysis_values (0 )
76+
77+ x = np .asarray (merged .x )
78+ mask = (x >= 0.03 ) & (x <= 0.25 )
79+ np .testing .assert_allclose ([point ['q' ] for point in points ], x [mask ])
80+ np .testing .assert_allclose ([point ['calculated' ] for point in points ], full [mask ], rtol = 1e-12 )
81+
6082 def test_the_second_dataset_is_not_drawn_with_the_models_resolution (self , qcore_application , tmp_path ):
6183 project = two_datasets_on_one_model (tmp_path )
6284 plotting = Plotting1d (project_lib = project , parent = None )
@@ -221,6 +243,84 @@ def test_a_failing_file_is_reported_and_the_others_still_load(self, qcore_applic
221243 assert len (failures ) == 1 and failures [0 ].startswith ('missing.txt:' )
222244 assert project .experiments [0 ].x .size == 2 * q .size
223245
246+ def test_files_from_the_qml_dialog_are_added (self , qcore_application , tmp_path ):
247+ # A QML FileDialog's selectedFiles reaches the slot as a list of QUrl;
248+ # names with spaces, commas and non-ASCII characters must survive.
249+ from PySide6 .QtCore import QUrl
250+
251+ project = Project ()
252+ project .default_model ()
253+ q = np .linspace (0.01 , 0.2 , 10 )
254+ project .load_new_experiment (_write_file (tmp_path / 'first.txt' , q , 0.01 ))
255+ backend = self ._backend (project )
256+ failures = []
257+ backend .loadFailed .connect (failures .append )
258+ names = ['angle 2, run 7.txt' , 'Messung ß µ.txt' ]
259+ urls = [
260+ QUrl .fromLocalFile (str (_write_file (tmp_path / name , q + 0.001 * (i + 1 ), 0.02 )))
261+ for i , name in enumerate (names )
262+ ]
263+
264+ backend .appendToCurrent (urls )
265+
266+ assert failures == []
267+ assert project .experiments [0 ].x .size == 3 * q .size
268+
269+ def test_a_file_url_string_is_added (self , qcore_application , tmp_path ):
270+ from PySide6 .QtCore import QUrl
271+
272+ project = Project ()
273+ project .default_model ()
274+ q = np .linspace (0.01 , 0.2 , 10 )
275+ project .load_new_experiment (_write_file (tmp_path / 'first.txt' , q , 0.01 ))
276+ backend = self ._backend (project )
277+ failures = []
278+ backend .loadFailed .connect (failures .append )
279+ url = QUrl .fromLocalFile (str (_write_file (tmp_path / 'with space.txt' , q + 0.001 , 0.02 ))).toString ()
280+
281+ backend .appendToCurrent ([url ])
282+
283+ assert failures == []
284+ assert project .experiments [0 ].x .size == 2 * q .size
285+
286+ def test_refusals_and_warnings_of_one_call_are_reported_together (self , qcore_application , tmp_path ):
287+ # The GUI shows one dialog: per-file emissions would leave only the last visible.
288+ project = Project ()
289+ project .default_model ()
290+ q = np .linspace (0.01 , 0.2 , 10 )
291+ project .load_new_experiment (_write_file (tmp_path / 'first.txt' , q , 0.01 ))
292+ backend = self ._backend (project )
293+ failures , cautions = [], []
294+ backend .loadFailed .connect (failures .append )
295+ backend .loadWarning .connect (cautions .append )
296+
297+ backend .appendToCurrent (
298+ [
299+ str (tmp_path / 'missing_a.txt' ),
300+ str (self ._three_column (tmp_path / 'plain.txt' , q + 0.005 )),
301+ str (tmp_path / 'missing_b.txt' ),
302+ ]
303+ )
304+
305+ assert cautions == []
306+ assert len (failures ) == 1
307+ assert 'missing_a.txt:' in failures [0 ] and 'missing_b.txt:' in failures [0 ]
308+ assert 'plain.txt:' in failures [0 ]
309+
310+ def test_the_warning_is_worded_for_the_user (self , qcore_application , tmp_path ):
311+ project = Project ()
312+ project .default_model ()
313+ q = np .linspace (0.01 , 0.2 , 10 )
314+ project .load_new_experiment (_write_file (tmp_path / 'measured.txt' , q , 0.01 ))
315+ backend = self ._backend (project )
316+ cautions = []
317+ backend .loadWarning .connect (cautions .append )
318+
319+ backend .appendToCurrent ([str (self ._three_column (tmp_path / 'plain.txt' , q + 0.005 ))])
320+
321+ assert len (cautions ) == 1
322+ assert 'PercentageFwhm' not in cautions [0 ] and cautions [0 ].count ('plain.txt' ) == 1
323+
224324 def test_appending_to_a_polarized_experiment_is_refused (self , qcore_application , tmp_path ):
225325 from easyreflectometry .data import DataSet1D
226326 from easyreflectometry .data import PolarizedDataSet
0 commit comments