def setUp(self):
        self.view = PhaseTableView()
        self.context = setup_context()
        self.context.data_context.instrument = 'MUSR'

        self.presenter = PhaseTablePresenter(self.view, self.context)

        forward_group = MuonGroup(group_name="fwd", detector_ids=[1,3,5,7,9])
        backward_group = MuonGroup(group_name="bwd", detector_ids=[2,4,6,8,10])

        self.context.group_pair_context.add_group(forward_group)
        self.context.group_pair_context.add_group(backward_group)
        self.presenter.update_current_groups_list()

        self.view.warning_popup = mock.MagicMock()
Exemple #2
0
    def __init__(self, context, parent):
        self.phase_table_view = PhaseTableView(parent)

        self.phase_table_presenter = PhaseTablePresenter(self.phase_table_view, context)

        self.phase_table_view.set_calculate_phase_table_action(self.phase_table_presenter.handle_calulate_phase_table_clicked)

        self.phase_table_view.set_calculate_phase_quad_action(self.phase_table_presenter.handle_calculate_phase_quad_button_clicked)

        self.phase_table_view.set_cancel_action(self.phase_table_presenter.cancel)

        context.update_view_from_model_notifier.add_subscriber(self.phase_table_presenter.update_view_from_model_observer)
    def setUp(self):
        self._qapp = mock_widget.mockQapp()
        self.view = PhaseTableView()
        self.context = setup_context()
        self.context.data_context.instrument = 'MUSR'

        self.presenter = PhaseTablePresenter(self.view, self.context)

        forward_group = MuonGroup(group_name="fwd", detector_ids=[1,3,5,7,9])
        backward_group = MuonGroup(group_name="bwd", detector_ids=[2,4,6,8,10])

        self.context.group_pair_context.add_group(forward_group)
        self.context.group_pair_context.add_group(backward_group)
        self.presenter.update_current_groups_list()

        self.view.warning_popup = mock.MagicMock()
    def __init__(self, context, parent):
        self.phase_table_view = PhaseTableView(parent)
        self.phase_table_presenter = PhaseTablePresenter(
            self.phase_table_view, context)

        # Phase table actions
        self.phase_table_view.set_calculate_phase_table_action(
            self.phase_table_presenter.handle_calculate_phase_table_clicked)
        self.phase_table_view.set_cancel_calculate_phase_table_action(
            self.phase_table_presenter.cancel_current_alg)
        self.phase_table_view.set_phase_table_changed_action(
            self.phase_table_presenter.handle_phase_table_changed)

        # Phaseqaud table actions
        self.phase_table_view.set_add_phasequad_action(
            self.phase_table_presenter.handle_add_phasequad_button_clicked)
        self.phase_table_view.set_remove_phasequad_action(
            self.phase_table_presenter.handle_remove_phasequad_button_clicked)

        context.update_view_from_model_notifier.add_subscriber(
            self.phase_table_presenter.update_view_from_model_observer)
class PhaseTablePresenterTest(unittest.TestCase):
    def wait_for_thread(self, thread_model):
        if thread_model:
            thread_model._thread.wait()
            QApplication.instance().processEvents()

    def setUp(self):
        self.view = PhaseTableView()
        self.context = setup_context()
        self.context.data_context.instrument = 'MUSR'

        self.presenter = PhaseTablePresenter(self.view, self.context)

        forward_group = MuonGroup(group_name="fwd",
                                  detector_ids=[1, 3, 5, 7, 9])
        backward_group = MuonGroup(group_name="bwd",
                                   detector_ids=[2, 4, 6, 8, 10])

        self.context.group_pair_context.add_group(forward_group)
        self.context.group_pair_context.add_group(backward_group)
        self.presenter.update_current_groups_list()

        self.view.warning_popup = mock.MagicMock()

    def test_update_view_from_model_updates_view_to_have_correct_values(self):
        self.presenter.update_view_from_model()

        for key, item in self.context.phase_context.options_dict.items():
            self.assertEqual(getattr(self.view, key), item)

    def test_update_model_from_view_updates_model_to_have_correct_values_if_view_changed(
            self):
        workspace_name = 'new_workspace_name'
        self.view.set_input_combo_box([workspace_name])
        self.view.input_workspace = workspace_name

        self.presenter.update_model_from_view()

        self.assertEqual(
            self.context.phase_context.options_dict['input_workspace'],
            workspace_name)

    def test_create_parameters_for_cal_muon_phase_returns_correct_parameter_dict(
            self):
        workspace_name = 'input_workspace_name_raw_data'
        self.context.phase_context.options_dict[
            'input_workspace'] = workspace_name

        result = self.presenter.create_parameters_for_cal_muon_phase_algorithm(
        )

        self.assertEqual(
            result, {
                'BackwardSpectra': [2, 4, 6, 8, 10],
                'FirstGoodData': 0.1,
                'ForwardSpectra': [1, 3, 5, 7, 9],
                'InputWorkspace': workspace_name,
                'LastGoodData': 15,
                'DetectorTable': 'input_workspace_name; PhaseTable; fwd; bwd'
            })

    def test_correctly_retrieves_workspace_names_associsated_to_current_runs(
            self):
        self.view.set_input_combo_box = mock.MagicMock()
        self.context.getGroupedWorkspaceNames = mock.MagicMock(
            return_value=['MUSR22222', 'MUSR44444'])

        self.presenter.update_current_run_list()

        self.view.set_input_combo_box.assert_called_once_with(
            ['MUSR22222', 'MUSR44444'])

    def test_correctly_retrieves_names_of_current_groups(self):
        self.view.set_group_combo_boxes = mock.MagicMock()

        self.presenter.update_current_groups_list()

        self.view.set_group_combo_boxes.assert_called_once_with(['fwd', 'bwd'])

    @mock.patch(
        'Muon.GUI.Common.phase_table_widget.phase_table_presenter.MuonWorkspaceWrapper'
    )
    def test_that_phase_table_added_to_ADS_with_correct_name_and_group(
            self, mock_workspace_wrapper):
        workspace_wrapper = mock.MagicMock()
        mock_workspace_wrapper.return_value = workspace_wrapper
        mock_phase_table = mock.MagicMock()

        self.presenter.add_phase_table_to_ADS('MUSR22222_period_1; PhaseTable',
                                              mock_phase_table)

        mock_workspace_wrapper.assert_called_once_with(
            mock_phase_table, 'MUSR22222 MA/MUSR22222_period_1; PhaseTable')
        workspace_wrapper.show.assert_called_once_with()

    @mock.patch(
        'Muon.GUI.Common.phase_table_widget.phase_table_presenter.run_CalMuonDetectorPhases'
    )
    def test_handle_calculate_phase_table_clicked_behaves_correctly_for_succesful_calculation(
            self, run_algorith_mock):
        detector_table_mock = mock.MagicMock()
        self.view.set_input_combo_box(['MUSR22222_raw_data_period_1'])
        self.context.getGroupedWorkspaceNames = mock.MagicMock(
            return_value=['MUSR22222_raw_data_period_1'])
        self.context.phase_context.options_dict[
            'input_workspace'] = 'MUSR22222_raw_data_period_1'
        self.presenter.update_view_from_model()
        run_algorith_mock.return_value = (detector_table_mock,
                                          mock.MagicMock())
        self.presenter.add_phase_table_to_ADS = mock.MagicMock()

        self.presenter.handle_calulate_phase_table_clicked()
        self.wait_for_thread(self.presenter.calculation_thread)

        self.presenter.add_phase_table_to_ADS.assert_called_once_with(
            'MUSR22222; PhaseTable_period_1; fwd; bwd', detector_table_mock)
        self.assertTrue(self.view.isEnabled())

    @mock.patch(
        'Muon.GUI.Common.phase_table_widget.phase_table_presenter.run_CalMuonDetectorPhases'
    )
    def test_handle_calculate_phase_table_clicked_behaves_correctly_for_error_in_calculation(
            self, run_algorith_mock):
        self.context.phase_context.options_dict[
            'input_workspace'] = 'MUSR22222_raw_data_period_1'
        self.presenter.update_view_from_model()
        run_algorith_mock.side_effect = RuntimeError(
            'CalMuonDetectorPhases has failed')
        self.presenter.add_phase_table_to_ADS = mock.MagicMock()
        self.presenter.calculate_base_name_and_group = mock.MagicMock(
            return_value=('MUSR22222_raw_data_period_1',
                          'MUSR22222 PhaseTable'))

        self.presenter.handle_calulate_phase_table_clicked()
        self.wait_for_thread(self.presenter.calculation_thread)

        self.assertTrue(self.view.isEnabled())
        self.view.warning_popup.assert_called_once_with(
            'CalMuonDetectorPhases has failed')

    def test_get_parameters_for_phase_quad(self):
        self.view.set_input_combo_box(['MUSR22222_raw_data_period_1'])
        self.view.set_phase_table_combo_box(['MUSR22222_period_1_phase_table'])

        self.presenter.update_model_from_view()

        parameters = self.presenter.get_parameters_for_phase_quad()

        self.assertEqual(
            parameters, {
                'InputWorkspace': 'MUSR22222_raw_data_period_1',
                'PhaseTable': 'MUSR22222_period_1_phase_table'
            })

    def test_that_new_phase_table_calculated_if_construct_selected(self):
        self.view.set_input_combo_box(['MUSR22222_raw_data_period_1'])
        self.view.set_phase_table_combo_box(
            ['Construct', 'MUSR22222_period_1_phase_table'])
        self.presenter.calculate_phase_table = mock.MagicMock(
            return_value='created_phase_table')

        self.presenter.update_model_from_view()

        parameters = self.presenter.get_parameters_for_phase_quad()

        self.assertEqual(
            parameters, {
                'InputWorkspace': 'MUSR22222_raw_data_period_1',
                'PhaseTable': 'created_phase_table'
            })

    @mock.patch(
        'Muon.GUI.Common.phase_table_widget.phase_table_presenter.MuonWorkspaceWrapper'
    )
    def test_add_phase_quad_to_ADS_does_so_in_correct_location_with_correct_name(
            self, mock_workspace_wrapper):
        phase_quad = mock.MagicMock()

        self.presenter.add_phase_quad_to_ADS(
            'MUSR22222_PhaseQuad_phase_table_MUSR22222',
            'MUSR22222 PhaseTable', phase_quad)

        mock_workspace_wrapper.assert_called_once_with(
            phase_quad,
            'MUSR22222 MA/MUSR22222_PhaseQuad_phase_table_MUSR22222 MUSR22222 PhaseTable'
        )
        mock_workspace_wrapper.return_value.show.assert_called_once_with()

    @mock.patch(
        'Muon.GUI.Common.phase_table_widget.phase_table_presenter.run_PhaseQuad'
    )
    @mock.patch(
        'Muon.GUI.Common.phase_table_widget.phase_table_presenter.mantid')
    def test_handle_calcuate_phase_quad_behaves_correctly_for_succesful_calculation(
            self, mantid_mock, run_algorithm_mock):
        phase_quad_mock = mock.MagicMock()
        alg_mock = mock.MagicMock()
        mantid_mock.AlgorithmManager.create.return_value = alg_mock
        run_algorithm_mock.return_value = phase_quad_mock
        self.presenter.add_phase_quad_to_ADS = mock.MagicMock()
        self.presenter.calculate_base_name_and_group = mock.MagicMock(
            return_value=('MUSR22222_period_1_phase_table',
                          'MUSR22222 PhaseTable'))
        self.view.set_input_combo_box(['MUSR22222_raw_data_period_1'])
        self.view.set_phase_table_combo_box(['MUSR22222_period_1_phase_table'])
        self.presenter.update_model_from_view()

        self.presenter.handle_calculate_phase_quad_button_clicked()
        self.wait_for_thread(self.presenter.phasequad_calculation_thread)

        self.assertTrue(self.view.isEnabled())
        run_algorithm_mock.assert_called_once_with(
            {
                'PhaseTable': 'MUSR22222_period_1_phase_table',
                'InputWorkspace': 'MUSR22222_raw_data_period_1'
            }, alg_mock)
        self.presenter.add_phase_quad_to_ADS.assert_called_once_with(
            'MUSR22222_raw_data_period_1', 'MUSR22222_period_1_phase_table',
            phase_quad_mock)

    @mock.patch(
        'Muon.GUI.Common.phase_table_widget.phase_table_presenter.run_PhaseQuad'
    )
    def test_handle_phase_quad_calculation_behaves_correctly_on_error(
            self, run_algorithm_mock):
        run_algorithm_mock.side_effect = RuntimeError(
            'PhaseQuad algorithm returned error')
        self.view.set_phase_table_combo_box(['MUSR22222_period_1_phase_table'])

        self.presenter.handle_calculate_phase_quad_button_clicked()
        self.wait_for_thread(self.presenter.phasequad_calculation_thread)

        self.assertTrue(self.view.isEnabled())
        self.view.warning_popup.assert_called_once_with(
            'PhaseQuad algorithm returned error')

    def test_update_current_phase_table_list_retrieves_all_correct_tables(
            self):
        self.view.set_phase_table_combo_box = mock.MagicMock()
        workspace_wrapper = mock.MagicMock()
        workspace_wrapper.workspace_name = 'MUSR22222_phase_table'
        self.context.phase_context.add_phase_table(workspace_wrapper)

        self.presenter.update_current_phase_tables()

        self.view.set_phase_table_combo_box.assert_called_once_with(
            ['MUSR22222_phase_table', 'Construct'])

    def test_handle_calculation_started_and_handle_calculation_ended_called_correctly(
            self):
        self.presenter.handle_phase_table_calculation_started = mock.MagicMock(
        )
        self.presenter.handle_calculation_success = mock.MagicMock()
        self.presenter.handle_calculation_error = mock.MagicMock()
        self.presenter.calculate_phase_table = mock.MagicMock()

        self.presenter.handle_calulate_phase_table_clicked()
        self.wait_for_thread(self.presenter.calculation_thread)

        self.presenter.handle_phase_table_calculation_started.assert_called_once_with(
        )
        self.presenter.handle_calculation_success.assert_called_once_with()
        self.presenter.handle_calculation_error.assert_not_called()
        self.presenter.calculate_phase_table.assert_called_once_with()

    @mock.patch(
        'Muon.GUI.Common.phase_table_widget.phase_table_presenter.MuonWorkspaceWrapper'
    )
    def test_add_fitting_info_to_ADS_does_nothing_if_output_fitting_info_is_false(
            self, workspace_wrapper_mock):
        self.presenter.add_fitting_info_to_ADS_if_required(
            'MUSR22222_PhaseTable', mock.MagicMock())

        workspace_wrapper_mock.assert_not_called()

    @mock.patch(
        'Muon.GUI.Common.phase_table_widget.phase_table_presenter.MuonWorkspaceWrapper'
    )
    def test_add_fitting_info_to_ADS_adds_fitting_info_to_ADS_if_option_selected(
            self, workspace_wrapper_mock):
        self.view.output_fit_info_box.setCheckState(QtCore.Qt.Checked)
        fit_information = mock.MagicMock()

        self.presenter.add_fitting_info_to_ADS_if_required(
            'MUSR22222_PhaseTable', fit_information)

        workspace_wrapper_mock.assert_called_once_with(
            fit_information,
            'MUSR22222 MA/MUSR22222 Phase Tab MA/MUSR22222_PhaseTable; fit_information'
        )
        workspace_wrapper_mock.return_value.show.assert_called_once_with()
class PhaseTablePresenterTest(unittest.TestCase):
    def wait_for_thread(self, thread_model):
        if thread_model:
            thread_model._thread.wait()
            self._qapp.processEvents()

    def setUp(self):
        self._qapp = mock_widget.mockQapp()
        self.view = PhaseTableView()
        self.context = setup_context()
        self.context.data_context.instrument = 'MUSR'

        self.presenter = PhaseTablePresenter(self.view, self.context)

        forward_group = MuonGroup(group_name="fwd", detector_ids=[1,3,5,7,9])
        backward_group = MuonGroup(group_name="bwd", detector_ids=[2,4,6,8,10])

        self.context.group_pair_context.add_group(forward_group)
        self.context.group_pair_context.add_group(backward_group)
        self.presenter.update_current_groups_list()

        self.view.warning_popup = mock.MagicMock()

    def test_update_view_from_model_updates_view_to_have_correct_values(self):
        self.presenter.update_view_from_model()

        for key, item in self.context.phase_context.options_dict.items():
            self.assertEquals(getattr(self.view, key), item)

    def test_update_model_from_view_updates_model_to_have_correct_values_if_view_changed(self):
        workspace_name = 'new_workspace_name'
        self.view.set_input_combo_box([workspace_name])
        self.view.input_workspace = workspace_name

        self.presenter.update_model_from_view()

        self.assertEquals(self.context.phase_context.options_dict['input_workspace'], workspace_name)

    def test_create_parameters_for_cal_muon_phase_returns_correct_parameter_dict(self):
        workspace_name = 'input_workspace_name_raw_data'
        self.context.phase_context.options_dict['input_workspace'] = workspace_name

        result = self.presenter.create_parameters_for_cal_muon_phase_algorithm()

        self.assertEquals(result, {'BackwardSpectra': [2, 4, 6, 8, 10], 'FirstGoodData': 0.1, 'ForwardSpectra': [1, 3, 5, 7, 9],
                                   'InputWorkspace': workspace_name, 'LastGoodData': 15,
                                   'DetectorTable': 'input_workspace_name; PhaseTable; fwd, bwd'})

    def test_correctly_retrieves_workspace_names_associsated_to_current_runs(self):
        self.view.set_input_combo_box = mock.MagicMock()
        self.context.getGroupedWorkspaceNames = mock.MagicMock(return_value=['MUSR22222', 'MUSR44444'])

        self.presenter.update_current_run_list()

        self.view.set_input_combo_box.assert_called_once_with(['MUSR22222', 'MUSR44444'])

    def test_correctly_retrieves_names_of_current_groups(self):
        self.view.set_group_combo_boxes = mock.MagicMock()

        self.presenter.update_current_groups_list()

        self.view.set_group_combo_boxes.assert_called_once_with(['fwd', 'bwd'])

    @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.MuonWorkspaceWrapper')
    def test_that_phase_table_added_to_ADS_with_correct_name_and_group(self, mock_workspace_wrapper):
        workspace_wrapper = mock.MagicMock()
        mock_workspace_wrapper.return_value = workspace_wrapper
        mock_phase_table = mock.MagicMock()

        self.presenter.add_phase_table_to_ADS('MUSR22222_period_1; PhaseTable', mock_phase_table)

        mock_workspace_wrapper.assert_called_once_with(mock_phase_table, 'Muon Data/MUSR22222/MUSR22222 Phase Tab'
                                                                         '/MUSR22222_period_1; PhaseTable')
        workspace_wrapper.show.assert_called_once_with()

    @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.run_CalMuonDetectorPhases')
    def test_handle_calculate_phase_table_clicked_behaves_correctly_for_succesful_calculation(self, run_algorith_mock):
        detector_table_mock = mock.MagicMock()
        self.view.set_input_combo_box(['MUSR22222_raw_data_period_1'])
        self.context.phase_context.options_dict['input_workspace'] = 'MUSR22222_raw_data_period_1'
        self.presenter.update_view_from_model()
        run_algorith_mock.return_value = (detector_table_mock, mock.MagicMock())
        self.presenter.add_phase_table_to_ADS = mock.MagicMock()

        self.presenter.handle_calulate_phase_table_clicked()
        self.wait_for_thread(self.presenter.calculation_thread)

        self.presenter.add_phase_table_to_ADS.assert_called_once_with('MUSR22222; PhaseTable_period_1; fwd, bwd', detector_table_mock)
        self.assertTrue(self.view.isEnabled())

    @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.run_CalMuonDetectorPhases')
    def test_handle_calculate_phase_table_clicked_behaves_correctly_for_error_in_calculation(self, run_algorith_mock):
        self.context.phase_context.options_dict['input_workspace'] = 'MUSR22222_raw_data_period_1'
        self.presenter.update_view_from_model()
        run_algorith_mock.side_effect = RuntimeError('CalMuonDetectorPhases has failed')
        self.presenter.add_phase_table_to_ADS = mock.MagicMock()
        self.presenter.calculate_base_name_and_group = mock.MagicMock(return_value=('MUSR22222_raw_data_period_1', 'MUSR22222 PhaseTable'))

        self.presenter.handle_calulate_phase_table_clicked()
        self.wait_for_thread(self.presenter.calculation_thread)

        self.assertTrue(self.view.isEnabled())
        self.view.warning_popup.assert_called_once_with('CalMuonDetectorPhases has failed')

    def test_get_parameters_for_phase_quad(self):
        self.view.set_input_combo_box(['MUSR22222_raw_data_period_1'])
        self.view.set_phase_table_combo_box(['MUSR22222_period_1_phase_table'])

        self.presenter.update_model_from_view()

        parameters = self.presenter.get_parameters_for_phase_quad()

        self.assertEquals(parameters, {'InputWorkspace': 'MUSR22222_raw_data_period_1', 'PhaseTable': 'MUSR22222_period_1_phase_table'})

    def test_that_new_phase_table_calculated_if_construct_selected(self):
        self.view.set_input_combo_box(['MUSR22222_raw_data_period_1'])
        self.view.set_phase_table_combo_box(['Construct', 'MUSR22222_period_1_phase_table'])
        self.presenter.calculate_phase_table = mock.MagicMock(return_value='created_phase_table')

        self.presenter.update_model_from_view()

        parameters = self.presenter.get_parameters_for_phase_quad()

        self.assertEquals(parameters, {'InputWorkspace': 'MUSR22222_raw_data_period_1',
                                       'PhaseTable': 'created_phase_table'})

    @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.MuonWorkspaceWrapper')
    def test_add_phase_quad_to_ADS_does_so_in_correct_location_with_correct_name(self, mock_workspace_wrapper):
        phase_quad = mock.MagicMock()

        self.presenter.add_phase_quad_to_ADS('MUSR22222_PhaseQuad_phase_table_MUSR22222', 'MUSR22222 PhaseTable',
                                             phase_quad)

        mock_workspace_wrapper.assert_called_once_with(phase_quad, 'Muon Data/MUSR22222/MUSR22222 Phase Tab/MUSR22222_'
                                                                   'PhaseQuad_phase_table_MUSR22222 MUSR22222 PhaseTable')
        mock_workspace_wrapper.return_value.show.assert_called_once_with()

    @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.run_PhaseQuad')
    @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.mantid')
    def test_handle_calcuate_phase_quad_behaves_correctly_for_succesful_calculation(self, mantid_mock, run_algorithm_mock):
        phase_quad_mock = mock.MagicMock()
        alg_mock = mock.MagicMock()
        mantid_mock.AlgorithmManager.create.return_value = alg_mock
        run_algorithm_mock.return_value = phase_quad_mock
        self.presenter.add_phase_quad_to_ADS = mock.MagicMock()
        self.presenter.calculate_base_name_and_group = mock.MagicMock(return_value=('MUSR22222_period_1_phase_table',
                                                                                    'MUSR22222 PhaseTable'))
        self.view.set_input_combo_box(['MUSR22222_raw_data_period_1'])
        self.view.set_phase_table_combo_box(['MUSR22222_period_1_phase_table'])
        self.presenter.update_model_from_view()

        self.presenter.handle_calculate_phase_quad_button_clicked()
        self.wait_for_thread(self.presenter.phasequad_calculation_thread)

        self.assertTrue(self.view.isEnabled())
        run_algorithm_mock.assert_called_once_with({'PhaseTable': 'MUSR22222_period_1_phase_table',

                                                    'InputWorkspace': 'MUSR22222_raw_data_period_1'}, alg_mock)
        self.presenter.add_phase_quad_to_ADS.assert_called_once_with('MUSR22222_raw_data_period_1',
                                                                     'MUSR22222_period_1_phase_table', phase_quad_mock)

    @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.run_PhaseQuad')
    def test_handle_phase_quad_calculation_behaves_correctly_on_error(self, run_algorithm_mock):
        run_algorithm_mock.side_effect = RuntimeError('PhaseQuad algorithm returned error')
        self.view.set_phase_table_combo_box(['MUSR22222_period_1_phase_table'])

        self.presenter.handle_calculate_phase_quad_button_clicked()
        self.wait_for_thread(self.presenter.phasequad_calculation_thread)

        self.assertTrue(self.view.isEnabled())
        self.view.warning_popup.assert_called_once_with('PhaseQuad algorithm returned error')

    def test_update_current_phase_table_list_retrieves_all_correct_tables(self):
        self.view.set_phase_table_combo_box = mock.MagicMock()
        workspace_wrapper = mock.MagicMock()
        workspace_wrapper.workspace_name = 'MUSR22222_phase_table'
        self.context.phase_context.add_phase_table(workspace_wrapper)

        self.presenter.update_current_phase_tables()

        self.view.set_phase_table_combo_box.assert_called_once_with(['MUSR22222_phase_table', 'Construct'])

    def test_handle_calculation_started_and_handle_calculation_ended_called_correctly(self):
        self.presenter.handle_phase_table_calculation_started = mock.MagicMock()
        self.presenter.handle_calculation_success = mock.MagicMock()
        self.presenter.handle_calculation_error = mock.MagicMock()
        self.presenter.calculate_phase_table = mock.MagicMock()

        self.presenter.handle_calulate_phase_table_clicked()
        self.wait_for_thread(self.presenter.calculation_thread)

        self.presenter.handle_phase_table_calculation_started.assert_called_once_with()
        self.presenter.handle_calculation_success.assert_called_once_with()
        self.presenter.handle_calculation_error.assert_not_called()
        self.presenter.calculate_phase_table.assert_called_once_with()

    @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.MuonWorkspaceWrapper')
    def test_add_fitting_info_to_ADS_does_nothing_if_output_fitting_info_is_false(self, workspace_wrapper_mock):
        self.presenter.add_fitting_info_to_ADS_if_required('MUSR22222_PhaseTable', mock.MagicMock())

        workspace_wrapper_mock.assert_not_called()

    @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.MuonWorkspaceWrapper')
    def test_add_fitting_info_to_ADS_adds_fitting_info_to_ADS_if_option_selected(self, workspace_wrapper_mock):
        self.view.output_fit_info_box.setCheckState(QtCore.Qt.Checked)
        fit_information = mock.MagicMock()

        self.presenter.add_fitting_info_to_ADS_if_required('MUSR22222_PhaseTable',fit_information)

        workspace_wrapper_mock.assert_called_once_with(fit_information, 'Muon Data/MUSR22222/MUSR22222 Phase Tab/'
                                                                        'MUSR22222_PhaseTable; fit_information')
        workspace_wrapper_mock.return_value.show.assert_called_once_with()
class PhaseTablePresenterTest(unittest.TestCase):
    def wait_for_thread(self, thread_model):
        if thread_model:
            thread_model._thread.wait()
            QApplication.sendPostedEvents()

    def setUp(self):
        self.view = PhaseTableView()
        self.context = setup_context()
        self.context.data_context.instrument = 'MUSR'

        self.presenter = PhaseTablePresenter(self.view, self.context)

        forward_group = MuonGroup(group_name="fwd", detector_ids=[1, 3, 5, 7, 9])
        backward_group = MuonGroup(group_name="bwd", detector_ids=[2, 4, 6, 8, 10])

        self.context.group_pair_context.add_group(forward_group)
        self.context.group_pair_context.add_group(backward_group)
        self.presenter.update_current_groups_list()

        self.view.warning_popup = mock.MagicMock()
        self.view.enter_phase_table_name = mock.Mock()
        self.view.enter_phase_table_name.side_effect = phase_table_name_side_effect

    def test_update_view_from_model_updates_view_to_have_correct_values(self):
        self.presenter.update_view_from_model()

        for key, item in self.context.phase_context.options_dict.items():
            self.assertEqual(getattr(self.view, key), item)

    def test_update_model_from_view_updates_model_to_have_correct_values_if_view_changed(self):
        workspace_name = 'new_workspace_name'
        self.view.set_input_combo_box([workspace_name])
        self.view.input_workspace = workspace_name

        self.presenter.update_model_from_view()

        self.assertEqual(self.context.phase_context.options_dict['input_workspace'], workspace_name)

    def test_create_parameters_for_cal_muon_phase_returns_correct_parameter_dict(self):
        workspace_name = 'input_workspace_name_raw_data'
        self.context.phase_context.options_dict['input_workspace'] = workspace_name

        result = self.presenter.create_parameters_for_cal_muon_phase_algorithm()

        self.assertEqual(result,
                         {'BackwardSpectra': [2, 4, 6, 8, 10], 'FirstGoodData': 0.1, 'ForwardSpectra': [1, 3, 5, 7, 9],
                          'InputWorkspace': workspace_name, 'LastGoodData': 15,
                          'DetectorTable': 'input_workspace_name; PhaseTable; fwd; bwd'})

    def test_correctly_retrieves_workspace_names_associsated_to_current_runs(self):
        self.view.set_input_combo_box = mock.MagicMock()
        self.context.getGroupedWorkspaceNames = mock.MagicMock(return_value=['MUSR22222', 'MUSR44444'])

        self.presenter.update_current_run_list()

        self.view.set_input_combo_box.assert_called_once_with(['MUSR22222', 'MUSR44444'])

    def test_correctly_retrieves_names_of_current_groups(self):
        self.view.set_group_combo_boxes = mock.MagicMock()

        self.presenter.update_current_groups_list()

        self.view.set_group_combo_boxes.assert_called_once_with(['fwd', 'bwd'])

    @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.MuonWorkspaceWrapper')
    def test_that_phase_table_added_to_ADS_with_correct_name_and_group(self, mock_workspace_wrapper):
        workspace_wrapper = mock.MagicMock()
        mock_workspace_wrapper.return_value = workspace_wrapper

        self.presenter.add_phase_table_to_ADS('MUSR22222_period_1; PhaseTable')

        mock_workspace_wrapper.assert_called_once_with('MUSR22222 MA/MUSR22222_period_1; PhaseTable')
        workspace_wrapper.show.assert_called_once_with()

    @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.run_CalMuonDetectorPhases')
    def test_handle_calculate_phase_table_clicked_behaves_correctly_for_succesful_calculation(self, run_algorithm_mock):
        detector_table_mock = mock.MagicMock()
        self.view.set_input_combo_box(['MUSR22222_raw_data_period_1'])
        self.context.getGroupedWorkspaceNames = mock.MagicMock(return_value=['MUSR22222_raw_data_period_1'])
        self.context.phase_context.options_dict['input_workspace'] = 'MUSR22222_raw_data_period_1'
        self.presenter.update_view_from_model()
        run_algorithm_mock.return_value = (detector_table_mock, mock.MagicMock())
        self.presenter.add_phase_table_to_ADS = mock.MagicMock()

        self.presenter.update_current_run_list()
        self.presenter.handle_calculate_phase_table_clicked()
        self.wait_for_thread(self.presenter.calculation_thread)

        self.presenter.add_phase_table_to_ADS.assert_called_once_with(detector_table_mock)
        self.assertTrue(self.view.isEnabled())

    @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.run_CalMuonDetectorPhases')
    def test_handle_calculate_phase_table_clicked_behaves_correctly_for_error_in_calculation(self, run_algorithm_mock):
        self.context.getGroupedWorkspaceNames = mock.MagicMock(return_value=['MUSR22222_raw_data_period_1'])
        self.context.phase_context.options_dict['input_workspace'] = 'MUSR22222_raw_data_period_1'
        self.presenter.update_view_from_model()
        run_algorithm_mock.side_effect = RuntimeError('CalMuonDetectorPhases has failed')
        self.presenter.add_phase_table_to_ADS = mock.MagicMock()
        self.presenter.calculate_base_name_and_group = mock.MagicMock(
            return_value=('MUSR22222_raw_data_period_1', 'MUSR22222 PhaseTable'))

        self.presenter.update_current_run_list()
        self.presenter.handle_calculate_phase_table_clicked()
        self.wait_for_thread(self.presenter.calculation_thread)

        self.assertTrue(self.view.isEnabled())
        self.view.warning_popup.assert_called_once_with('CalMuonDetectorPhases has failed')

    def test_update_current_phase_table_list_retrieves_all_correct_tables(self):
        self.view.set_phase_table_combo_box = mock.MagicMock()
        workspace_wrapper = mock.MagicMock()
        workspace_wrapper.workspace_name = 'MUSR22222_phase_table'
        self.context.phase_context.add_phase_table(workspace_wrapper)

        self.presenter.update_current_phase_tables()

        self.view.set_phase_table_combo_box.assert_called_once_with(['MUSR22222_phase_table'])

    def test_handle_calculation_started_and_handle_calculation_ended_called_correctly(self):
        self.presenter.handle_phase_table_calculation_started = mock.MagicMock()
        self.presenter.handle_phase_table_calculation_success = mock.MagicMock()
        self.presenter.handle_phase_table_calculation_error = mock.MagicMock()
        self.presenter.calculate_phase_table = mock.MagicMock()

        self.presenter.handle_calculate_phase_table_clicked()
        self.wait_for_thread(self.presenter.calculation_thread)

        self.presenter.handle_phase_table_calculation_started.assert_called_once_with()
        self.presenter.handle_phase_table_calculation_success.assert_called_once_with()
        self.presenter.handle_phase_table_calculation_error.assert_not_called()
        self.presenter.calculate_phase_table.assert_called_once_with()

    @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.MuonWorkspaceWrapper')
    def test_add_fitting_info_to_ADS_does_nothing_if_output_fitting_info_is_false(self, workspace_wrapper_mock):
        self.presenter.add_fitting_info_to_ADS_if_required('MUSR22222_PhaseTable', mock.MagicMock())

        workspace_wrapper_mock.assert_not_called()

    @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.MuonWorkspaceWrapper')
    def test_add_fitting_info_to_ADS_adds_fitting_info_to_ADS_if_option_selected(self, workspace_wrapper_mock):
        self.view.output_fit_info_box.setCheckState(QtCore.Qt.Checked)

        self.presenter.add_fitting_info_to_ADS_if_required('MUSR22222_PhaseTable',
                                                           'MUSR22222_PhaseTable; fit_information')

        workspace_wrapper_mock.assert_called_once_with('MUSR22222_PhaseTable; fit_information')
        workspace_wrapper_mock.return_value.show.assert_called_once_with()

    def test_that_disable_observer_calls_on_view_when_triggered(self):
        self.view.setEnabled(True)
        self.view.enable_widget()

        for widget in self.view.children():
            if str(widget.objectName()) in ['cancel_calculate_phase_table_button']:
                continue
            self.assertTrue(widget.isEnabled())

        disable_notifier = GenericObservable()
        disable_notifier.add_subscriber(self.presenter.disable_tab_observer)

        disable_notifier.notify_subscribers()
        for widget in self.view.children():
            if str(widget.objectName()) in ['cancel_calculate_phase_table_button']:
                continue
            self.assertFalse(widget.isEnabled())

    def test_that_enable_observer_calls_on_view_when_triggered(self):
        self.view.setEnabled(True)
        self.view.disable_widget()

        for widget in self.view.children():
            if str(widget.objectName()) in ['cancel_calculate_phase_table_button']:
                continue
            self.assertFalse(widget.isEnabled())

        enable_notifier = GenericObservable()
        enable_notifier.add_subscriber(self.presenter.enable_tab_observer)

        enable_notifier.notify_subscribers()
        for widget in self.view.children():
            if str(widget.objectName()) in ['cancel_calculate_phase_table_button']:
                continue
            self.assertTrue(widget.isEnabled())

    def test_handle_add_phasequad_button_no_table(self):
        self.presenter.handle_add_phasequad_button_clicked()
        self.view.warning_popup.assert_called_once_with('Please generate a phase table first.')

    def test_handle_add_phasequad_button_no_name(self):
        self.view.set_phase_table_combo_box(["Table"])
        self.view.enter_phasequad_name = mock.Mock(return_value=None)
        self.presenter.create_phasequad_calculation_thread = mock.MagicMock()

        self.presenter.handle_add_phasequad_button_clicked()
        self.assertEqual(self.presenter.create_phasequad_calculation_thread.call_count, 0)

    def test_handle_add_phasequad_button(self):
        self.view.set_phase_table_combo_box(["Table"])
        self.presenter.validate_phasequad_name = mock.Mock(return_value=True)
        self.view.enter_phasequad_name = mock.Mock(return_value="test")
        self.presenter.create_phasequad_calculation_thread = mock.MagicMock()

        self.presenter.handle_add_phasequad_button_clicked()
        self.assertEqual(self.presenter.create_phasequad_calculation_thread.call_count, 1)

    def test_phasequad_success(self):
        self.context.group_pair_context.add_pair_to_selected_pairs = mock.Mock()
        self.presenter.selected_phasequad_changed_notifier = mock.Mock()
        self.presenter.calculation_finished_notifier = mock.Mock()
        self.presenter.handle_thread_calculation_success = mock.Mock()

        self.context.group_pair_context.add_pair_to_selected_pairs = mock.Mock()
        self.presenter.selected_phasequad_changed_notifier.notify_subscribers = mock.Mock()
        self.presenter._phasequad_obj = MuonPhasequad("test", "table")
        self.presenter.handle_phasequad_calculation_success()

        self.context.group_pair_context.add_pair_to_selected_pairs.assert_any_call("test_Re_")
        self.context.group_pair_context.add_pair_to_selected_pairs.assert_any_call("test_Im_")
        self.presenter.selected_phasequad_changed_notifier.notify_subscribers.assert_not_called()
        self.presenter.calculation_finished_notifier.notify_subscribers.assert_called_once_with()
        self.presenter.handle_thread_calculation_success.assert_called_once_with()

    def test_handle_first_good_data_too_small(self):
        self.view.input_workspace_combo_box.currentText = mock.Mock(return_value="MUSR62260_raw_data MA")
        self.context.data_context.instrument = 'MUSR'
        self.view.first_good_time = 0.0
        self.context.first_good_data = mock.Mock(return_value=0.102)
        self.presenter.handle_first_good_data_changed()

        self.view.warning_popup.assert_called_once_with('First Good Data cannot be smaller than 0.102')

    def test_handle_first_good_data_too_big(self):
        self.view.input_workspace_combo_box.currentText = mock.Mock(return_value="MUSR62260_raw_data MA")
        self.context.data_context.instrument = 'MUSR'
        self.view.first_good_time = 40.0
        self.view.last_good_time = 41.0
        self.context.last_good_data = mock.Mock(return_value=32.29)
        self.presenter.handle_first_good_data_changed()

        self.view.warning_popup.assert_called_once_with('First Good Data cannot be greater than 32.29')

    def test_handle_last_good_data_too_small(self):
        self.view.input_workspace_combo_box.currentText = mock.Mock(return_value="MUSR62260_raw_data MA")
        self.context.data_context.instrument = 'MUSR'
        self.view.first_good_time = -1.0
        self.view.last_good_time = 0.0
        self.context.first_good_data = mock.Mock(return_value=0.102)
        self.presenter.handle_last_good_data_changed()

        self.view.warning_popup.assert_called_once_with('Last Good Data cannot be smaller than 0.102')

    def test_handle_last_good_data_too_big(self):
        self.view.input_workspace_combo_box.currentText = mock.Mock(return_value="MUSR62260_raw_data MA")
        self.context.data_context.instrument = 'MUSR'
        self.view.last_good_time = 41.0
        self.context.last_good_data = mock.Mock(return_value=32.29)
        self.presenter.handle_last_good_data_changed()

        self.view.warning_popup.assert_called_once_with('Last Good Data cannot be greater than 32.29')

    def test_handle_first_good_greater_than_last_good(self):
        self.view.input_workspace_combo_box.currentText = mock.Mock(return_value="MUSR62260_raw_data MA")
        self.context.data_context.instrument = 'MUSR'
        self.view.first_good_time = 20.0
        self.view.last_good_time = 10.0
        self.presenter.handle_first_good_data_changed()

        self.view.warning_popup.assert_called_once_with('First Good Data cannot be greater than Last Good Data')

    def test_handle_last_good_less_than_first_good(self):
        self.view.input_workspace_combo_box.currentText = mock.Mock(return_value="MUSR62260_raw_data MA")
        self.context.data_context.instrument = 'MUSR'
        self.view.first_good_time = 20.0
        self.view.last_good_time = 10.0
        self.presenter.handle_last_good_data_changed()

        self.view.warning_popup.assert_called_once_with('First Good Data cannot be greater than Last Good Data')

    def test_handle_first_good_and_last_good_pass_validation(self):
        self.view.input_workspace_combo_box.currentText = mock.Mock(return_value="MUSR62260_raw_data MA")
        self.context.data_context.instrument = 'MUSR'
        self.context.first_good_data = mock.Mock(return_value=0.102)
        self.context.last_good_data = mock.Mock(return_value=32.29)
        self.view.first_good_time = 10.0
        self.view.last_good_time = 20.0
        self.presenter.handle_first_good_data_changed()
        self.presenter.handle_last_good_data_changed()

        self.view.warning_popup.assert_not_called()

    def test_remove_phasequad_button_last_row(self):
        phasequad = MuonPhasequad("test", "table")
        self.view.num_rows = mock.Mock(return_value=1)
        self.view.get_table_item_text = mock.Mock(return_value="test")
        self.view.get_selected_phasequad_names_and_indexes = mock.Mock(return_value=None)
        self.view.get_table_contents = mock.Mock(return_value=["test"])
        self.view.remove_last_row = mock.Mock()
        self.presenter.add_phasequad_to_analysis = mock.Mock()
        self.presenter.calculation_finished_notifier = mock.Mock()
        self.presenter.context.group_pair_context._phasequad = [phasequad]
        self.presenter.handle_remove_phasequad_button_clicked()

        self.assertEqual(0, len(self.presenter.context.group_pair_context.phasequads))
        self.presenter.add_phasequad_to_analysis.assert_called_once_with(False, False, phasequad)
        self.presenter.calculation_finished_notifier.notify_subscribers.assert_called_once_with()

    def test_remove_phasequad_button_selected_rows(self):
        phasequad_1 = MuonPhasequad("test_1", "table")
        phasequad_2 = MuonPhasequad("test_2", "table")
        phasequad_3 = MuonPhasequad("test_3", "table")
        self.view.num_rows = mock.Mock(return_value=3)
        self.view.get_table_item_text = mock.Mock(return_value="test")
        self.view.get_selected_phasequad_names_and_indexes = mock.Mock(return_value=[("test_1", 0), ("test_2", 1)])
        self.view.remove_phasequad_by_index = mock.Mock()
        self.presenter.add_phasequad_to_analysis = mock.Mock()
        self.presenter.calculation_finished_notifier = mock.Mock()
        self.presenter.context.group_pair_context._phasequad = [phasequad_1, phasequad_2, phasequad_3]
        self.presenter.handle_remove_phasequad_button_clicked()

        self.assertEqual(1, len(self.presenter.context.group_pair_context.phasequads))
        self.view.remove_phasequad_by_index.assert_any_call(0)
        self.view.remove_phasequad_by_index.assert_any_call(1)
        self.presenter.add_phasequad_to_analysis.assert_any_call(False, False, phasequad_1)
        self.presenter.add_phasequad_to_analysis.assert_any_call(False, False, phasequad_2)
        self.assertEqual(2, self.presenter.calculation_finished_notifier.notify_subscribers.call_count)

    def test_calculate_phasequad(self):
        self.presenter.phasequad_calculation_complete_notifier = mock.Mock()
        self.presenter.phasequad_calculation_complete_notifier.notify_subscribers = mock.Mock()
        self.context.group_pair_context.add_phasequad = mock.Mock()
        self.context.calculate_phasequads = mock.Mock()
        phasequad = MuonPhasequad("test", "table")
        self.presenter._phasequad_obj = phasequad

        self.presenter.calculate_phasequad()
        self.context.group_pair_context.add_phasequad.assert_called_once_with(phasequad)
        self.context.calculate_phasequads.assert_called_once_with(phasequad)
        self.presenter.phasequad_calculation_complete_notifier.notify_subscribers.assert_any_call(phasequad.Re.name)
        self.presenter.phasequad_calculation_complete_notifier.notify_subscribers.assert_any_call(phasequad.Im.name)
        self.assertEqual(self.presenter.phasequad_calculation_complete_notifier.notify_subscribers.call_count, 2)