def test_copy_paste_single_appends_to_end(self): table_model = TableModel() table_model.append_table_entry(RowEntries(sample_transmission="1")) table_model.append_table_entry(RowEntries(sample_transmission="2")) table_model.copy_rows([0]) table_model.paste_rows([]) self.assertEqual(3, table_model.get_number_of_rows()) self.assertEqual(table_model.get_row(0), table_model.get_row(2))
def test_get_number_of_rows_returns_number_of_entries(self): table_model = TableModel() table_index_model = RowEntries() table_model.replace_table_entry(0, table_index_model) table_index_model = RowEntries() table_model.replace_table_entry(1, table_index_model) number_of_rows = table_model.get_number_of_rows() self.assertEqual(number_of_rows, 2)
def test_when_table_is_cleared_is_left_with_one_empty_row(self): table_model = TableModel() table_model.append_table_entry(RowEntries()) table_model.append_table_entry(RowEntries()) self.assertEqual(2, table_model.get_number_of_rows()) table_model.clear_table_entries() self.assertEqual(table_model.get_number_of_rows(), 0) self.assertTrue(table_model.get_row(0).is_empty())
def test_when_last_row_is_removed_table_is_left_with_one_empty_row(self): table_model = TableModel() table_model.append_table_entry(RowEntries()) table_model.append_table_entry(RowEntries()) self.assertEqual(2, table_model.get_number_of_rows()) table_model.remove_table_entries([0, 1]) self.assertEqual(table_model.get_number_of_rows(), 0) self.assertTrue(table_model.get_row(0).is_empty())
def test_settings_attr_resets_state(self): observed_attrs = vars(_UserEntries()) for observed_attr in iterkeys(observed_attrs): obj = RowEntries() obj.state = RowState.PROCESSED setattr(obj, observed_attr, "") self.assertEqual( RowState.UNPROCESSED, obj.state, "Row state did not reset for attr: {0}".format(observed_attr))
def test_non_user_keys_keep_state(self): observed_attrs = ["err_msg", "state"] for attr in observed_attrs: obj = RowEntries() obj.state = RowState.ERROR setattr(obj, attr, RowState.ERROR) self.assertEqual( RowState.ERROR, obj.state ) # This will likely stack-overflow instead of failing
def test_is_multi_period(self): multi_period_keys = [ "can_direct_period", "can_scatter_period", "can_transmission_period", "sample_direct_period", "sample_scatter_period", "sample_transmission_period" ] for key in multi_period_keys: obj = RowEntries() setattr(obj, key, 1.) self.assertTrue(obj.is_multi_period())
def setUp(self): self.state_gui_model = StateGuiModel(AllStates()) self._good_row_one = RowEntries(sample_scatter='LOQ74044') self._good_row_two = RowEntries(sample_scatter='LOQ74044') self.gui_state_director_instance = mock.MagicMock() self.gui_state_director_instance.create_state.return_value = self.state_gui_model self.patcher = mock.patch( 'sans.gui_logic.models.create_state.GuiStateDirector') self.addCleanup(self.patcher.stop) self.gui_state_director = self.patcher.start() self.gui_state_director.return_value = self.gui_state_director_instance
def test_copy_paste_modify_overwrite(self): # Check we aren't doing a shallow copy, which cause a user to # see two rows get modified at once table_model = TableModel() table_model.append_table_entry(RowEntries(sample_transmission="1")) table_model.append_table_entry(RowEntries(sample_transmission="2")) table_model.copy_rows([0]) table_model.paste_rows([1]) row_1 = table_model.get_row(1) self.assertEqual(table_model.get_row(0), row_1) row_1.sample_transmission = 2 self.assertNotEqual(table_model.get_row(0), row_1)
def create_state(state_model_with_view_update, file, period, facility): table_row = RowEntries(sample_scatter=file, sample_scatter_period=period) gui_state_director = GuiStateDirector(state_model_with_view_update, facility) state = gui_state_director.create_state(table_row).all_states return state
def test_that_process_all_ignores_empty_rows(self): view = mock.MagicMock() view.get_selected_rows = mock.MagicMock(return_value=[0, 1]) self.presenter.set_view(view) table_model = TableModel() populated_row = RowEntries(sample_scatter=1) table_model.append_table_entry(populated_row) table_model.append_table_entry(RowEntries()) self.presenter._table_model = table_model self.presenter._process_rows = mock.MagicMock() self.presenter.on_process_selected_clicked() self.presenter._process_rows.assert_called_with([populated_row])
def test_that_get_non_empty_rows_returns_non_empty_rows(self): table_model = TableModel() empty_row = RowEntries() table_model.append_table_entry(empty_row) table_model.append_table_entry(RowEntries(sample_scatter=123)) table_model.append_table_entry(empty_row) table_model.append_table_entry(RowEntries(sample_direct=345)) table_model.append_table_entry(empty_row) self.assertEqual(2, len(table_model.get_non_empty_rows())) for i in table_model.get_non_empty_rows(): self.assertFalse(i.is_empty()) self.assertEqual(5, table_model.get_number_of_rows())
def _parse_csv_row(self, row, row_number): # Clean all elements of the row row = list(map(str.strip, row)) output = RowEntries() # Special attention has to go to the specification of the period in a run number. The user can # specify something like 5512p for sample scatter. This means they want run number 5512 with period 7. for key, value in zip(row[::2], row[1::2]): if key in self.IGNORED_KEYWORDS: continue try: key_enum = BatchFileKeywords(key) except ValueError: raise KeyError( "The key {0} is not part of the SANS batch csv file keywords" .format(key)) try: BatchFileKeywords(value) raise KeyError( "The value {0} is a keyword, you may have missed a comma after {1}" .format(value, key)) except ValueError: pass # User did not accidentally use a key as a value self._parse_row_entry(key_enum, value, row_entry=output) self.validate_output(output, row_number) return output
def test_that_process_selected_only_processes_selected_rows(self): # Naive test. Doesn't check that we are processing the correct processed rows, # just that we are processing the same number of rows as we have selected. # This would only really fail if on_process_selected_clicked and on_process_all_clicked # get muddled-up view = mock.MagicMock() view.get_selected_rows = mock.MagicMock(return_value=[0, 2, 3]) self.presenter.set_view(view) self.presenter._process_rows = mock.Mock() table_model = TableModel() for i in range(5): table_model.append_table_entry(RowEntries(sample_scatter='74040')) self.presenter._table_model = table_model self.presenter.on_process_selected_clicked() expected = [ table_model.get_row(0), table_model.get_row(2), table_model.get_row(3) ] self.presenter._process_rows.assert_called_with(expected)
def test_create_state_from_user_file_if_specified(self, create_gui_state_mock): create_gui_state_mock.returns = StateGuiModel({}) rows = [ RowEntries(sample_scatter="LOQ74044", user_file="MaskLOQData.txt"), RowEntries(), RowEntries() ] states, errors = create_states(self.state_gui_model, row_entries=rows, facility=SANSFacility.ISIS) self.assertEqual(len(states), 1) create_gui_state_mock.assert_called_once_with('MaskLOQData.txt', self.state_gui_model)
def test_that_can_set_the_options_column_model(self): table_index_model = RowEntries() table_index_model.options.set_user_options("WavelengthMin=1, WavelengthMax=3, NotRegister2=1") options_dict = table_index_model.options.get_options_dict() self.assertEqual(len(options_dict), 2) self.assertEqual(options_dict["WavelengthMin"], 1.) self.assertEqual(options_dict["WavelengthMax"], 3.)
def test_default_obj_correctly_tracked(self): # We need to make sure there is always 1 object in table model, but not to get it mixed with user input obj = TableModel() self.assertEqual(0, obj.get_number_of_rows()) obj.clear_table_entries() self.assertEqual(0, obj.get_number_of_rows()) obj.append_table_entry(RowEntries()) self.assertEqual(1, obj.get_number_of_rows()) obj.append_table_entry(RowEntries()) self.assertEqual(2, obj.get_number_of_rows()) obj.clear_table_entries() self.assertEqual(0, obj.get_number_of_rows()) obj.append_table_entry(RowEntries()) self.assertEqual(1, obj.get_number_of_rows())
def test_get_num_rows(self): obj = TableModel() self.assertEqual(0, obj.get_number_of_rows()) obj.append_table_entry(RowEntries()) self.assertEqual(1, obj.get_number_of_rows()) obj.remove_table_entries([0]) self.assertEqual(0, obj.get_number_of_rows())
def test_that_parse_string_returns_correctly(self): string_to_parse = 'EventSlices=1-6,5-9,4:5:89 , WavelengthMax=78 , WavelengthMin=9' entry = RowEntries() entry.options.set_user_options(string_to_parse) expected_dict = {'EventSlices': '1-6,5-9,4:5:89', 'WavelengthMax': 78.0, 'WavelengthMin': 9.0} parsed_dict = entry.options.get_options_dict() self.assertEqual(expected_dict, parsed_dict)
def test_copy_paste_modify_append(self): table_model = TableModel() table_model.append_table_entry(RowEntries(sample_transmission="1")) table_model.copy_rows([0]) table_model.paste_rows([]) row_1 = table_model.get_row(1) self.assertEqual(table_model.get_row(0), row_1) row_1.sample_transmission = 2 self.assertNotEqual(table_model.get_row(0), row_1)
def test_create_state_from_user_file_if_specified(self, thickness_mock): expected_user_file = 'MaskLOQData.txt' # Mock out row entry so it does not lookup file information mock_row_entry = mock.Mock(spec=RowEntries) mock_row_entry.is_empty.return_value = False mock_row_entry.user_file = expected_user_file rows = [mock_row_entry, RowEntries(), RowEntries()] states, errors = create_states(self.state_gui_model, row_entries=rows, facility=SANSFacility.ISIS) self.assertEqual(len(states), 1) self.gui_state_director_instance.create_state.assert_called_once_with( mock_row_entry, file_lookup=mock.ANY, row_user_file=expected_user_file) thickness_mock.assert_called()
def test_deep_copy_eq(self): obj = RowEntries() # Randomly selected subset of fields for attr in [ "sample_transmission", "can_direct_period", "user_file", "output_name", "tool_tip", "state" ]: obj2 = copy.deepcopy(obj) self.assertEqual(obj, obj2) setattr(obj2, attr, 1) self.assertNotEqual(obj, obj2)
def test_copy_paste_overwrite(self): for paste_location in [0, 1]: table_model = TableModel() for entry_i in range(3): table_model.append_table_entry( RowEntries(sample_transmission=entry_i)) table_model.copy_rows([2]) table_model.paste_rows([paste_location]) self.assertEqual(table_model.get_row(2), table_model.get_row(paste_location))
def test_inserting_row_at_pos(self): model = TableModel() expected_order = [RowEntries() for _ in range(3)] model.replace_table_entry(row_index=0, row_entry=expected_order[0]) model.replace_table_entry(row_index=1, row_entry=expected_order[2]) self.assertTrue(2, model.get_number_of_rows()) model.insert_row_at(1, expected_order[1]) self.assertTrue(3, model.get_number_of_rows()) self.assertEqual(expected_order, model.get_all_rows())
def test_that_set_row_to_error_sets_row_to_error_and_tool_tip(self): table_model = TableModel() table_index_model = RowEntries() table_model.replace_table_entry(0, table_index_model) row = 0 tool_tip = 'There was an error' table_model.set_row_to_error(row, tool_tip) row_entry = table_model.get_row(0) self.assertTrue(RowState.ERROR, row_entry.state) self.assertEqual(tool_tip, row_entry.tool_tip)
def test_is_empty(self): blank_obj = RowEntries() self.assertTrue(blank_obj.is_empty(), "Default Row Entries is not blank") for attr in iterkeys(vars(_UserEntries())): obj = RowEntries() setattr(obj, attr, 1.0) self.assertFalse(obj.is_empty())
def test_parses_row_to_csv_correctly(self): test_row = RowEntries() test_row.sample_scatter = "SANS2D00022025" test_row.sample_transmission = "SANS2D00022052" test_row.sample_direct = "SANS2D00022022" test_row.output_name = "another_file" test_row.user_file = "a_user_file.txt" test_row.sample_thickness = "1.0" test_row.sample_height = 5.0 test_row.sample_width = 5.4 expected = "sample_sans,SANS2D00022025," \ "sample_trans,SANS2D00022052,"\ "sample_direct_beam,SANS2D00022022," \ "can_sans,," \ "can_trans,," \ "can_direct_beam,,"\ "output_as,another_file," \ "user_file,a_user_file.txt," \ "sample_thickness,1.0,"\ "sample_height,5.0," \ "sample_width,5.4" mocked_handle = mock.mock_open() parser = BatchCsvParser() patchable = "builtins.open" with mock.patch(patchable, mocked_handle): parser.save_batch_file(rows=[test_row], file_path='') result = mocked_handle() args, kwargs = result.write.call_args # Strip new lines etc self.assertTrue(isinstance(args[0], str)) written = args[0].replace('\n', '').replace('\r', '') self.assertEqual(expected, written)
def test_copy_paste_append_mixed_selection(self): table_model = TableModel() for entry_i in range(4): table_model.append_table_entry( RowEntries(sample_transmission=entry_i)) copied_rows = [0, 1, 3] table_model.copy_rows(copied_rows) table_model.paste_rows([]) # 4 rows + 3 pasted self.assertEqual(7, table_model.get_number_of_rows()) for dest_row, original_row in enumerate(copied_rows): self.assertEqual(table_model.get_row(original_row), table_model.get_row(dest_row + 4))
def test_insert_row_at_multiple_beyond(self): model = TableModel() expected = [RowEntries(sample_scatter=i) for i in range(2)] model.replace_table_entry(row_index=0, row_entry=expected[0]) self.assertTrue(1, model.get_number_of_rows()) model.insert_row_at(4, expected[1]) # Remember that the number of rows is counted from 1, but we use 0 based indexing self.assertTrue(5, model.get_number_of_rows()) self.assertEqual(expected, model.get_multiple_rows([0, 4])) self.assertTrue( all(i.is_empty() for i in model.get_multiple_rows([1, 2, 3])))
def test_cut_paste_sorts_order(self): # Qt can give is the order a user selected rows in, ensure it's always in the natural order table_model = TableModel() for entry_i in range(5): table_model.append_table_entry( RowEntries(sample_transmission=entry_i)) input_rows = [4, 0, 2] expected_rows = table_model.get_multiple_rows(sorted(input_rows)) table_model.cut_rows(input_rows) table_model.paste_rows([]) for i, row in enumerate(expected_rows): # 5 original rows - 3 cut rows = 2 rows remaining self.assertEqual(row, table_model.get_row(i + 2))