Skip to content

Commit 21b82ab

Browse files
Copilotlachlangrose
andcommitted
Add unit tests for fault dip display fix
Co-authored-by: lachlangrose <7371904+lachlangrose@users.noreply.github.com>
1 parent 2783f32 commit 21b82ab

File tree

1 file changed

+164
-0
lines changed

1 file changed

+164
-0
lines changed
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
#! python3
2+
3+
"""Test fault dip display in the Geological Features panel.
4+
5+
Usage from the repo root folder:
6+
7+
.. code-block:: bash
8+
# for whole tests
9+
python -m unittest tests.unit.test_fault_dip_display
10+
# for specific test
11+
python -m unittest tests.unit.test_fault_dip_display.TestFaultDipDisplay.test_dip_from_stored_data
12+
"""
13+
14+
import unittest
15+
from unittest.mock import MagicMock, Mock
16+
import pandas as pd
17+
import numpy as np
18+
19+
20+
class TestFaultDipDisplay(unittest.TestCase):
21+
"""Test fault dip retrieval and display."""
22+
23+
def setUp(self):
24+
"""Set up mock objects for testing."""
25+
# Mock the fault object
26+
self.mock_fault = Mock()
27+
self.mock_fault.name = "TestFault"
28+
self.mock_fault.displacement = 100
29+
self.mock_fault.fault_major_axis = 500
30+
self.mock_fault.fault_minor_axis = 300
31+
self.mock_fault.fault_intermediate_axis = 400
32+
33+
# Mock fault_normal_vector that would give a dip of 90 (vertical fault)
34+
self.mock_fault.fault_normal_vector = np.array([1.0, 0.0, 0.0])
35+
36+
# Mock the model manager
37+
self.mock_model_manager = Mock()
38+
self.mock_model_manager.faults = {}
39+
40+
def test_dip_from_stored_data(self):
41+
"""Test that dip is retrieved from stored fault data when available."""
42+
# Create fault data with a dip of 45 degrees
43+
fault_data = pd.DataFrame({
44+
'X': [0, 1, 2],
45+
'Y': [0, 1, 2],
46+
'Z': [0, 0, 0],
47+
'dip': [45, 45, 45]
48+
})
49+
50+
self.mock_model_manager.faults['TestFault'] = {'data': fault_data}
51+
52+
# Import here to avoid issues if PyQt5 is not available
53+
try:
54+
from loopstructural.gui.modelling.geological_model_tab.feature_details_panel import (
55+
FaultFeatureDetailsPanel
56+
)
57+
58+
# Create the panel - this should retrieve dip from stored data
59+
panel = FaultFeatureDetailsPanel(
60+
parent=None,
61+
fault=self.mock_fault,
62+
model_manager=self.mock_model_manager,
63+
data_manager=None
64+
)
65+
66+
# Check that the dip was retrieved from stored data (45 degrees)
67+
# not from the normal vector calculation (which would be 90 degrees)
68+
self.assertEqual(panel.fault_parameters['dip'], 45)
69+
70+
except ImportError as e:
71+
self.skipTest(f"Cannot import GUI components: {e}")
72+
73+
def test_dip_fallback_to_normal_vector(self):
74+
"""Test that dip falls back to normal vector calculation when not in stored data."""
75+
# No stored dip data
76+
fault_data = pd.DataFrame({
77+
'X': [0, 1, 2],
78+
'Y': [0, 1, 2],
79+
'Z': [0, 0, 0]
80+
})
81+
82+
self.mock_model_manager.faults['TestFault'] = {'data': fault_data}
83+
84+
try:
85+
from loopstructural.gui.modelling.geological_model_tab.feature_details_panel import (
86+
FaultFeatureDetailsPanel
87+
)
88+
from LoopStructural.utils import normal_vector_to_strike_and_dip
89+
90+
# Calculate expected dip from normal vector
91+
expected_dip = normal_vector_to_strike_and_dip(self.mock_fault.fault_normal_vector)[0, 1]
92+
93+
panel = FaultFeatureDetailsPanel(
94+
parent=None,
95+
fault=self.mock_fault,
96+
model_manager=self.mock_model_manager,
97+
data_manager=None
98+
)
99+
100+
# Should fall back to calculating from normal vector
101+
self.assertEqual(panel.fault_parameters['dip'], expected_dip)
102+
103+
except ImportError as e:
104+
self.skipTest(f"Cannot import GUI components: {e}")
105+
106+
def test_dip_default_when_no_data(self):
107+
"""Test that dip defaults to 90 when no fault data exists."""
108+
# No fault data at all
109+
self.mock_model_manager.faults = {}
110+
111+
try:
112+
from loopstructural.gui.modelling.geological_model_tab.feature_details_panel import (
113+
FaultFeatureDetailsPanel
114+
)
115+
116+
panel = FaultFeatureDetailsPanel(
117+
parent=None,
118+
fault=self.mock_fault,
119+
model_manager=self.mock_model_manager,
120+
data_manager=None
121+
)
122+
123+
# Should use a reasonable default or calculate from normal vector
124+
self.assertIsInstance(panel.fault_parameters['dip'], (int, float))
125+
self.assertGreaterEqual(panel.fault_parameters['dip'], 0)
126+
self.assertLessEqual(panel.fault_parameters['dip'], 90)
127+
128+
except ImportError as e:
129+
self.skipTest(f"Cannot import GUI components: {e}")
130+
131+
def test_pitch_from_stored_data(self):
132+
"""Test that pitch is also retrieved from stored fault data when available."""
133+
# Create fault data with pitch
134+
fault_data = pd.DataFrame({
135+
'X': [0, 1, 2],
136+
'Y': [0, 1, 2],
137+
'Z': [0, 0, 0],
138+
'dip': [45, 45, 45],
139+
'pitch': [30, 30, 30]
140+
})
141+
142+
self.mock_model_manager.faults['TestFault'] = {'data': fault_data}
143+
144+
try:
145+
from loopstructural.gui.modelling.geological_model_tab.feature_details_panel import (
146+
FaultFeatureDetailsPanel
147+
)
148+
149+
panel = FaultFeatureDetailsPanel(
150+
parent=None,
151+
fault=self.mock_fault,
152+
model_manager=self.mock_model_manager,
153+
data_manager=None
154+
)
155+
156+
# Check that pitch was retrieved from stored data
157+
self.assertEqual(panel.fault_parameters['pitch'], 30)
158+
159+
except ImportError as e:
160+
self.skipTest(f"Cannot import GUI components: {e}")
161+
162+
163+
if __name__ == "__main__":
164+
unittest.main()

0 commit comments

Comments
 (0)