11from types import SimpleNamespace
2+ from unittest .mock import MagicMock
23
34from PySide6 .QtCore import QObject
45from PySide6 .QtCore import Signal
@@ -34,6 +35,7 @@ class StubSample(QObject):
3435 modelsIndexChanged = Signal ()
3536 assembliesTableChanged = Signal ()
3637 assembliesIndexChanged = Signal ()
38+ qRangeChanged = Signal ()
3739
3840 def __init__ (self , _project_lib ):
3941 super ().__init__ ()
@@ -46,6 +48,7 @@ def _clearCacheAndEmitLayersChanged(self):
4648class StubExperiment (QObject ):
4749 externalExperimentChanged = Signal ()
4850 experimentChanged = Signal ()
51+ qRangeUpdated = Signal ()
4952
5053 def __init__ (self , _project_lib ):
5154 super ().__init__ ()
@@ -211,3 +214,90 @@ def test_backend_refresh_plots_emits_ranges_and_multi_signal(monkeypatch, qcore_
211214 assert backend .plottingIndividualExperimentDataList == [{'name' : 'E0' , 'index' : 0 , 'color' : '#111111' , 'hasData' : True }]
212215 assert backend .plottingGetExperimentDataPoints (3 ) == [{'x' : 3.0 , 'y' : 0.0 }]
213216 assert backend .plottingGetAnalysisDataPoints (5 ) == [{'x' : 5.0 , 'measured' : 0.0 , 'calculated' : 0.0 }]
217+
218+
219+ # ===========================================================================
220+ # Delegation-contract tests.
221+ # These verify that PyBackend correctly forwards calls to Plotting1d without
222+ # requiring the full Qt infrastructure — Plotting1d is replaced by MagicMock.
223+ # ===========================================================================
224+
225+ class _DelegationStub :
226+ """Minimal replica of the PyBackend delegation methods under test."""
227+
228+ def __init__ (self , plotting_1d ):
229+ self ._plotting_1d = plotting_1d
230+
231+ def plottingGetAnalysisDataPoints (self , experiment_index : int ) -> list :
232+ return self ._plotting_1d .getAnalysisDataPoints (experiment_index )
233+
234+ def plottingGetResidualDataPoints (self , experiment_index : int ) -> list :
235+ return self ._plotting_1d .getResidualDataPoints (experiment_index )
236+
237+
238+ class TestPlottingGetResidualDataPointsDelegation :
239+ def _backend (self ):
240+ mock_plotting = MagicMock ()
241+ return _DelegationStub (mock_plotting ), mock_plotting
242+
243+ def test_delegates_to_plotting_1d (self ):
244+ backend , plotting = self ._backend ()
245+ expected = [{'x' : 0.1 , 'y' : 0.002 }, {'x' : 0.2 , 'y' : - 0.001 }]
246+ plotting .getResidualDataPoints .return_value = expected
247+
248+ result = backend .plottingGetResidualDataPoints (0 )
249+
250+ plotting .getResidualDataPoints .assert_called_once_with (0 )
251+ assert result == expected
252+
253+ def test_passes_experiment_index (self ):
254+ backend , plotting = self ._backend ()
255+ plotting .getResidualDataPoints .return_value = []
256+
257+ backend .plottingGetResidualDataPoints (3 )
258+
259+ plotting .getResidualDataPoints .assert_called_once_with (3 )
260+
261+ def test_returns_empty_list_when_plotting_returns_empty (self ):
262+ backend , plotting = self ._backend ()
263+ plotting .getResidualDataPoints .return_value = []
264+
265+ result = backend .plottingGetResidualDataPoints (0 )
266+
267+ assert result == []
268+
269+ def test_returns_result_unchanged (self ):
270+ backend , plotting = self ._backend ()
271+ payload = [{'x' : i * 0.1 , 'y' : i * 0.001 } for i in range (10 )]
272+ plotting .getResidualDataPoints .return_value = payload
273+
274+ result = backend .plottingGetResidualDataPoints (0 )
275+
276+ assert result is payload
277+
278+
279+ class TestPlottingGetAnalysisDataPointsDelegation :
280+ """Regression: existing analysis bridging is unaffected by residual additions."""
281+
282+ def _backend (self ):
283+ mock_plotting = MagicMock ()
284+ return _DelegationStub (mock_plotting ), mock_plotting
285+
286+ def test_delegates_to_plotting_1d (self ):
287+ backend , plotting = self ._backend ()
288+ expected = [{'x' : 0.1 , 'measured' : - 2.0 , 'calculated' : - 1.9 }]
289+ plotting .getAnalysisDataPoints .return_value = expected
290+
291+ result = backend .plottingGetAnalysisDataPoints (0 )
292+
293+ plotting .getAnalysisDataPoints .assert_called_once_with (0 )
294+ assert result == expected
295+
296+ def test_passes_experiment_index (self ):
297+ backend , plotting = self ._backend ()
298+ plotting .getAnalysisDataPoints .return_value = []
299+
300+ backend .plottingGetAnalysisDataPoints (5 )
301+
302+ plotting .getAnalysisDataPoints .assert_called_once_with (5 )
303+
0 commit comments