Spaces:
Sleeping
Sleeping
rmm
commited on
Commit
·
4f4541e
1
Parent(s):
838bba4
test: reorganised to be more modular
Browse files- the sidebar validation also works on the true src/main.py, although
the whole app takes a long time to load (thus tests v slow)
- so the idea of modularising the tests here is that the steps should
be reusable when we go from unit - component - e2e tests.
- tests/test_demo_input_sidebar.py +62 -47
tests/test_demo_input_sidebar.py
CHANGED
|
@@ -77,6 +77,65 @@ def verify_initial_session_state(at:AppTest):
|
|
| 77 |
assert "container_file_uploader" in at.session_state
|
| 78 |
assert "container_metadata_inputs" in at.session_state
|
| 79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
def test_no_input_no_interaction():
|
| 81 |
|
| 82 |
# zero test: no inputs
|
|
@@ -154,37 +213,7 @@ def test_two_input_files_realdata(mock_file_rv: MagicMock, mock_uploadedFile_Lis
|
|
| 154 |
print(f"[I] session state: {at.session_state}")
|
| 155 |
print(f"full tree: {at._tree}")
|
| 156 |
|
| 157 |
-
|
| 158 |
-
# changes in the elements in the session_state (x=same)
|
| 159 |
-
# x container_file_uploader exists
|
| 160 |
-
# x container_metadata_inputs exists
|
| 161 |
-
# - observations 2 elements, keys -> some hashes. values: InputObservation objects
|
| 162 |
-
# - image_hashes 2 elements, hashes (str) |
|
| 163 |
-
# - images {} 2 elements, keys -> hashes, values -> np.ndarray.
|
| 164 |
-
# - files [] a list of 2 MockUploadedFile objects
|
| 165 |
-
# x public_observations {}
|
| 166 |
-
# I think just verify the sizes and types, we could do a data integrity
|
| 167 |
-
# check on the hashes matching everywhere, but that is far from visual.
|
| 168 |
-
|
| 169 |
-
assert len(at.session_state.observations) == num_files
|
| 170 |
-
for obs in at.session_state.observations.values():
|
| 171 |
-
assert isinstance(obs, InputObservation)
|
| 172 |
-
assert len(at.session_state.image_hashes) == num_files
|
| 173 |
-
for hash in at.session_state.image_hashes:
|
| 174 |
-
assert isinstance(hash, str)
|
| 175 |
-
assert len(at.session_state.images) == num_files
|
| 176 |
-
for img in at.session_state.images.values():
|
| 177 |
-
assert isinstance(img, np.ndarray)
|
| 178 |
-
assert len(at.session_state.image_hashes) == num_files
|
| 179 |
-
for hash in at.session_state.image_hashes:
|
| 180 |
-
assert isinstance(hash, str)
|
| 181 |
-
assert len(at.session_state.files) == num_files
|
| 182 |
-
for file in at.session_state.files:
|
| 183 |
-
assert isinstance(file, MockUploadedFile)
|
| 184 |
-
assert isinstance(file, BytesIO) # cool it looks like the FileUploader.
|
| 185 |
-
#assert isinstance(file, UploadedFile) no... it isn't but bytesIO is the parent class
|
| 186 |
-
|
| 187 |
-
assert at.session_state.public_observations == {}
|
| 188 |
|
| 189 |
# and then there are plenty of visual elements, based on the image hashes.
|
| 190 |
for hash in at.session_state.image_hashes:
|
|
@@ -198,19 +227,5 @@ def test_two_input_files_realdata(mock_file_rv: MagicMock, mock_uploadedFile_Lis
|
|
| 198 |
#print(f"found element: {elem}")
|
| 199 |
#assert f"input_latitude_{hash}" in at.text_input.values()
|
| 200 |
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
assert len(at.text_area) == num_files
|
| 204 |
-
# expecting
|
| 205 |
-
exp0 = "index: 0, name: cakes.jpg, datetime: 2024:10:24 15:59:45, lat: 46.51860277777778, lon:6.562075"
|
| 206 |
-
exp1 = "index: 1, name: cakes_no_exif_datetime.jpg, datetime: None, lat: 46.51860277777778, lon:6.562075"
|
| 207 |
-
exp2 = "index: 2, name: cakes_no_exif_gps.jpg, datetime: 2024:10:24 15:59:45, lat: None, lon:None"
|
| 208 |
-
|
| 209 |
-
assert at.text_area[0].value == exp0
|
| 210 |
-
assert at.text_area[1].value == exp1
|
| 211 |
-
if num_files >= 1:
|
| 212 |
-
assert at.text_area(key='metadata_0').value == exp0
|
| 213 |
-
if num_files >= 2:
|
| 214 |
-
assert at.text_area(key='metadata_1').value == exp1
|
| 215 |
-
if num_files >= 3:
|
| 216 |
-
assert at.text_area(key='metadata_2').value == exp2
|
|
|
|
| 77 |
assert "container_file_uploader" in at.session_state
|
| 78 |
assert "container_metadata_inputs" in at.session_state
|
| 79 |
|
| 80 |
+
def verify_session_state_after_processing_files(at:AppTest, num_files:int):
|
| 81 |
+
# this is after buffering & metadata extraction, but *BEFORE* the ML is run.
|
| 82 |
+
|
| 83 |
+
# now we've processed the files and got metadata, we expect some
|
| 84 |
+
# changes in the elements in the session_state (x=same)
|
| 85 |
+
# x container_file_uploader exists
|
| 86 |
+
# x container_metadata_inputs exists
|
| 87 |
+
# - observations 2 elements, keys -> some hashes. values: InputObservation objects
|
| 88 |
+
# - image_hashes 2 elements, hashes (str) |
|
| 89 |
+
# - images {} 2 elements, keys -> hashes, values -> np.ndarray.
|
| 90 |
+
# - files [] a list of 2 MockUploadedFile objects
|
| 91 |
+
# x public_observations {}
|
| 92 |
+
# I think just verify the sizes and types, we could do a data integrity
|
| 93 |
+
# check on the hashes matching everywhere, but that is far from visual.
|
| 94 |
+
|
| 95 |
+
assert len(at.session_state.observations) == num_files
|
| 96 |
+
for obs in at.session_state.observations.values():
|
| 97 |
+
assert isinstance(obs, InputObservation)
|
| 98 |
+
assert len(at.session_state.image_hashes) == num_files
|
| 99 |
+
for hash in at.session_state.image_hashes:
|
| 100 |
+
assert isinstance(hash, str)
|
| 101 |
+
assert len(at.session_state.images) == num_files
|
| 102 |
+
for img in at.session_state.images.values():
|
| 103 |
+
assert isinstance(img, np.ndarray)
|
| 104 |
+
assert len(at.session_state.image_hashes) == num_files
|
| 105 |
+
for hash in at.session_state.image_hashes:
|
| 106 |
+
assert isinstance(hash, str)
|
| 107 |
+
assert len(at.session_state.files) == num_files
|
| 108 |
+
for file in at.session_state.files:
|
| 109 |
+
assert isinstance(file, MockUploadedFile)
|
| 110 |
+
assert isinstance(file, BytesIO) # cool it looks like the FileUploader.
|
| 111 |
+
#assert isinstance(file, UploadedFile) no... it isn't but bytesIO is the parent class
|
| 112 |
+
|
| 113 |
+
assert at.session_state.public_observations == {}
|
| 114 |
+
|
| 115 |
+
def verify_metadata_in_demo_display(at:AppTest, num_files:int):
|
| 116 |
+
# we can check the metadata display in the main area
|
| 117 |
+
# - this presentation is not part of the normal app, but is a test-only feature
|
| 118 |
+
|
| 119 |
+
if 'src/main.py' in SCRIPT_UNDER_TEST:
|
| 120 |
+
raise ValueError("This test is not valid for the main app, only for unit/component test snippets")
|
| 121 |
+
|
| 122 |
+
# finally we can check the main area, where the metadata is displayed
|
| 123 |
+
# since we uplaoded num_files files, hopefully we get num_files text areas
|
| 124 |
+
assert len(at.text_area) == num_files
|
| 125 |
+
# expecting
|
| 126 |
+
exp0 = "index: 0, name: cakes.jpg, datetime: 2024:10:24 15:59:45, lat: 46.51860277777778, lon:6.562075"
|
| 127 |
+
exp1 = "index: 1, name: cakes_no_exif_datetime.jpg, datetime: None, lat: 46.51860277777778, lon:6.562075"
|
| 128 |
+
exp2 = "index: 2, name: cakes_no_exif_gps.jpg, datetime: 2024:10:24 15:59:45, lat: None, lon:None"
|
| 129 |
+
|
| 130 |
+
assert at.text_area[0].value == exp0
|
| 131 |
+
assert at.text_area[1].value == exp1
|
| 132 |
+
if num_files >= 1:
|
| 133 |
+
assert at.text_area(key='metadata_0').value == exp0
|
| 134 |
+
if num_files >= 2:
|
| 135 |
+
assert at.text_area(key='metadata_1').value == exp1
|
| 136 |
+
if num_files >= 3:
|
| 137 |
+
assert at.text_area(key='metadata_2').value == exp2
|
| 138 |
+
|
| 139 |
def test_no_input_no_interaction():
|
| 140 |
|
| 141 |
# zero test: no inputs
|
|
|
|
| 213 |
print(f"[I] session state: {at.session_state}")
|
| 214 |
print(f"full tree: {at._tree}")
|
| 215 |
|
| 216 |
+
verify_session_state_after_processing_files(at, num_files)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 217 |
|
| 218 |
# and then there are plenty of visual elements, based on the image hashes.
|
| 219 |
for hash in at.session_state.image_hashes:
|
|
|
|
| 227 |
#print(f"found element: {elem}")
|
| 228 |
#assert f"input_latitude_{hash}" in at.text_input.values()
|
| 229 |
|
| 230 |
+
if 'demo_input_sidebar' in SCRIPT_UNDER_TEST:
|
| 231 |
+
verify_metadata_in_demo_display(at, num_files)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|