From fd956261bef0d9fac193b3961683d464acb5b53a Mon Sep 17 00:00:00 2001 From: leorud Date: Fri, 26 Jan 2024 12:12:23 +0000 Subject: [PATCH] Update re-coordination tests for new functionality --- tactool/analysis_point.py | 3 +- test/test_import_export.py | 35 ++++++++++++++ test/test_transformation.py | 91 +++++++++++++++++-------------------- 3 files changed, 79 insertions(+), 50 deletions(-) diff --git a/tactool/analysis_point.py b/tactool/analysis_point.py index aaab1de..e285f88 100644 --- a/tactool/analysis_point.py +++ b/tactool/analysis_point.py @@ -10,6 +10,7 @@ DictReader, writer, ) +from pathlib import Path from typing import Any from PyQt5.QtWidgets import ( @@ -256,7 +257,7 @@ def convert_export_point(analysis_point: AnalysisPoint, headers: list[str]) -> l return analysis_point_row -def parse_sem_csv(filepath: str) -> list[dict[str, str | int | float]]: +def parse_sem_csv(filepath: str | Path) -> list[dict[str, str | int | float]]: """ Parse an SEM CSV file into a list of dictionaries. We only retain the integer ID value and the coordinates of the points. diff --git a/test/test_import_export.py b/test/test_import_export.py index 53f9565..09110b7 100644 --- a/test/test_import_export.py +++ b/test/test_import_export.py @@ -7,6 +7,7 @@ from tactool.analysis_point import ( AnalysisPoint, export_tactool_csv, + parse_sem_csv, ) @@ -172,3 +173,37 @@ def assert_csv_data(csv_path: str, expected_headers: list[str], expected_data: l # Attributes from the expected Analysis Point are converted to a string because # the raw CSV data will all be a string type assert csv_attribute == str(item_attribute) + + +def test_parse_sem_csv_good(): + # Arrange + sem_csv = Path("test/data/SEM_co-ordinate_import_test_set.csv") + expected_point_dicts = [ + {"label": "RefMark", "x": 91.576, "y": 67.762}, + {"label": "RefMark", "x": 86.01, "y": 55.893}, + {"label": "RefMark", "x": 98.138, "y": 49.417}, + {"apid": 509, "label": "Spot", "x": 96.764747, "y": 49.303754}, + {"apid": 577, "label": "Spot", "x": 97.520798, "y": 55.785059}, + {"apid": 662, "label": "Spot", "x": 93.746436, "y": 60.03264}, + {"apid": 705, "label": "Spot", "x": 91.770031, "y": 62.312733}, + {"apid": 759, "label": "Spot", "x": 92.415936, "y": 67.080603}, + ] + + # Act + actual_point_dicts = parse_sem_csv(sem_csv) + + # Assert + assert expected_point_dicts == actual_point_dicts + + +def test_parse_sem_csv_bad(): + # Arrange + sem_csv = Path("test/data/analysis_points_complete.csv") + expected_error = "SEM CSV missing required header: Particle ID" + + # Act + with pytest.raises(KeyError) as excinfo: + parse_sem_csv(sem_csv) + + # Assert + assert expected_error in str(excinfo.value) diff --git a/test/test_transformation.py b/test/test_transformation.py index a8f66f6..f511d43 100644 --- a/test/test_transformation.py +++ b/test/test_transformation.py @@ -2,8 +2,7 @@ Tests for functions in the transformation module """ import numpy as np -from csv import DictReader -from pathlib import Path +from typing import Any import pytest @@ -65,9 +64,6 @@ def test_affine_transform_matrix(): def test_toggle_recoordinate_dialog(tactool: TACtool, monkeypatch_qmsgbox_question_yes: pytest.MonkeyPatch): - # close recoord window - # check that toggling off works, main widgets, grey rect, disable graphics scene points - # Check that the RecoordinateDialog does not exist assert tactool.window.recoordinate_dialog is None # Check that the main input widgets are enabled @@ -120,70 +116,67 @@ def test_toggle_recoordinate_dialog(tactool: TACtool, monkeypatch_qmsgbox_questi @pytest.mark.parametrize( - ["input_csv", "expected_coordinates", "recoordinate_args", "non_coord_headers"], + ["input_csv", "expected_points_data"], [ - ( - "test/data/analysis_points_complete.csv", - [(336, 472), (318, 394), (268, 469), (340, 527), (380, 362)], - {"invert_x_axis_dest": False, "x_header": "X", "y_header": "Y", - "ref_col": "Type", "ref_label": "RefMark"}, - ["Name", "Type", "diameter", "scale", "colour", "mount_name", "material", "notes"], - ), ( "test/data/SEM_co-ordinate_import_test_set.csv", - [(460, 472), (478, 394), (528, 469), (525, 458), (509, 483), (487, 466), (476, 458), (464, 477)], - {"invert_x_axis_dest": True, "x_header": "Laser Ablation Centre X", "y_header": "Laser Ablation Centre Y", - "ref_col": "Mineral Classification", "ref_label": "Fiducial"}, - ["Particle ID", "Mineral Classification", "Effective Diameter m", - "Feret Max Diameter m", "Feret Min Diameter m", "F (N)", "Cl (N)"], + [ + [1, "RefMark", 336, 472, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + [2, "RefMark", 318, 394, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + [3, "RefMark", 268, 469, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + [509, "Spot", 271, 458, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + [577, "Spot", 287, 483, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + [662, "Spot", 309, 466, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + [705, "Spot", 320, 458, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + [759, "Spot", 332, 477, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + ], ), ( "test/data/SEM_co-ordinate_import_test_set_4_refs.csv", - [(460, 472), (478, 394), (528, 469), (472, 447), (525, 458), - (509, 483), (487, 466), (476, 458), (464, 477)], - {"invert_x_axis_dest": True, "x_header": "Laser Ablation Centre X", "y_header": "Laser Ablation Centre Y", - "ref_col": "Mineral Classification", "ref_label": "Fiducial"}, - ["Particle ID", "Mineral Classification", "Effective Diameter m", - "Feret Max Diameter m", "Feret Min Diameter m", "F (N)", "Cl (N)"], + [ + [1, "RefMark", 336, 472, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + [2, "RefMark", 318, 394, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + [3, "RefMark", 268, 469, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + [4, "RefMark", 324, 447, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + [509, "Spot", 271, 458, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + [577, "Spot", 287, 483, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + [662, "Spot", 309, 466, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + [705, "Spot", 320, 458, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + [759, "Spot", 332, 477, 50, 2.0, "#222222", "sample_x83", "mount_x81", "rock", ""], + ], ), ], ) -def test_recoordinate_sem_points( - tmp_path: Path, +def test_import_and_recoordinate_sem_csv( tactool: TACtool, + public_index: int, input_csv: str, - expected_coordinates: list[tuple[int, int]], - recoordinate_args: dict[str, str], - non_coord_headers: list[str], + expected_points_data: list[list[Any]], ): # Arrange - output_csv = tmp_path / "recoordinated_output.csv" - print(output_csv) # Place 4 Analysis Points which will be used for recoordination # Only the first 3 should be used tactool.graphics_view.left_click.emit(336, 472) tactool.graphics_view.left_click.emit(318, 394) tactool.graphics_view.left_click.emit(268, 469) tactool.graphics_view.left_click.emit(87, 392) - # Toggle recoordinate dialog so that the recoordinate_dialog is callable - tactool.window.toggle_recoordinate_dialog() + # Modify the Analysis Point settings as these should be applied to the recoordinated points + tactool.window.update_point_settings( + sample_name="sample_x83", + mount_name="mount_x81", + material="rock", + label="Spot", + diameter=50, + scale=2.0, + colour="#222222", + ) # Act - tactool.recoordinate_dialog.recoordinate_sem_points(input_csv, output_csv, **recoordinate_args) + # Toggle recoordinate dialog so that the recoordinate_dialog is callable + tactool.window.toggle_recoordinate_dialog() + tactool.recoordinate_dialog.input_csv_filepath_label.setText(input_csv) + tactool.recoordinate_dialog.import_and_recoordinate_sem_csv() # Assert - with open(input_csv) as input_file, open(output_csv) as output_file: - input_reader = DictReader(input_file) - output_reader = DictReader(output_file) - - # Check that the headers remain the same - assert input_reader.fieldnames == output_reader.fieldnames - - # Iterate through CSV file lines - for input_item, output_item, (expect_x, expect_y) in zip(input_reader, output_reader, expected_coordinates): - # Check that the non coordinate fields remain the same - for header in non_coord_headers: - assert input_item[header] == output_item[header] - # Check that the coordinate fields are correct - assert int(output_item[recoordinate_args["x_header"]]) == expect_x - assert int(output_item[recoordinate_args["y_header"]]) == expect_y + for expected_point, actual_point in zip(expected_points_data, tactool.table_model.analysis_points): + assert expected_point == actual_point.aslist()[:public_index]