From 6e5f12dff0b38a8ea0aca6c6079e4bd42db9ce79 Mon Sep 17 00:00:00 2001 From: specify Date: Thu, 24 Sep 2026 11:56:34 -0500 Subject: [PATCH 1/8] [test]: test batch image upload unit test --- .../tests/test_batch_image_upload.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 specifyweb/backend/businessrules/tests/test_batch_image_upload.py diff --git a/specifyweb/backend/businessrules/tests/test_batch_image_upload.py b/specifyweb/backend/businessrules/tests/test_batch_image_upload.py new file mode 100644 index 00000000000..66d74836c7a --- /dev/null +++ b/specifyweb/backend/businessrules/tests/test_batch_image_upload.py @@ -0,0 +1,33 @@ +from specifyweb.specify import models +from specifyweb.specify.tests.test_api import ApiTests +from specifyweb.specify.api.crud import create_obj, delete_resource, get_collection, get_resource, post_resource, update_obj + + +class BatchImageTests(ApiTests): + def setUp(self): + super().setUp() + + self.attachments = [ + models.Attachment.objects.create( + origfilename='test.txt', + tableid=1, + ) + ] + + def test_add_attachment(self): + attachment = post_resource( + self.collection, + self.agent, + 'attachment', + {'origfilename': 'new.txt', 'tableid': 1}, + ) + + self.assertIsNotNone(attachment.id) + self.assertExists( + models.Attachment.objects.filter( + id=attachment.id, + origfilename='new.txt', + ) + ) + + attachment.delete() \ No newline at end of file From 91cc4c8f34d6f1d10a4e3e68e7a51303f6c50649 Mon Sep 17 00:00:00 2001 From: specify Date: Thu, 24 Sep 2026 13:04:31 -0500 Subject: [PATCH 2/8] Batch image upload - Unit Test --- .../businessrules/tests/test_batch_image_upload.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/specifyweb/backend/businessrules/tests/test_batch_image_upload.py b/specifyweb/backend/businessrules/tests/test_batch_image_upload.py index 66d74836c7a..0ef83b642d4 100644 --- a/specifyweb/backend/businessrules/tests/test_batch_image_upload.py +++ b/specifyweb/backend/businessrules/tests/test_batch_image_upload.py @@ -13,8 +13,19 @@ def setUp(self): tableid=1, ) ] + self.datasetattachment = [ + models.Spdatasetattachment.objects.create( + collectionmemberid=0, + ordinal=0, + attachment= attachment, + spdataset=spdataset, - def test_add_attachment(self): + + + ) + ] + + def test_validate_attachment(self): attachment = post_resource( self.collection, self.agent, From 8a35deffa6a18b99c0bfa7b4cb899090d569db5b Mon Sep 17 00:00:00 2001 From: specify Date: Tue, 29 Sep 2026 10:33:55 -0500 Subject: [PATCH 3/8] [test]: match collection object/cat# --- .../tests/test_batch_image_upload.py | 50 ++++++------------- 1 file changed, 15 insertions(+), 35 deletions(-) diff --git a/specifyweb/backend/businessrules/tests/test_batch_image_upload.py b/specifyweb/backend/businessrules/tests/test_batch_image_upload.py index 0ef83b642d4..59c13d69490 100644 --- a/specifyweb/backend/businessrules/tests/test_batch_image_upload.py +++ b/specifyweb/backend/businessrules/tests/test_batch_image_upload.py @@ -1,44 +1,24 @@ from specifyweb.specify import models from specifyweb.specify.tests.test_api import ApiTests -from specifyweb.specify.api.crud import create_obj, delete_resource, get_collection, get_resource, post_resource, update_obj +from specifyweb.specify.api.crud import post_resource class BatchImageTests(ApiTests): def setUp(self): super().setUp() + + self.attachments = [ + models.Attachment.objects.create( + attachmentlocation='0123.png', + origfilename='0123.png', + title='0123.png', + mimetype='image/png', + tableid=model.Attachment.specify_model.tableId, + ) + ] - self.attachments = [ - models.Attachment.objects.create( - origfilename='test.txt', - tableid=1, - ) - ] - self.datasetattachment = [ - models.Spdatasetattachment.objects.create( - collectionmemberid=0, - ordinal=0, - attachment= attachment, - spdataset=spdataset, + def test_match_collectionobject_catnumber(self): + attachment = self.attachments[0] - - - ) - ] - - def test_validate_attachment(self): - attachment = post_resource( - self.collection, - self.agent, - 'attachment', - {'origfilename': 'new.txt', 'tableid': 1}, - ) - - self.assertIsNotNone(attachment.id) - self.assertExists( - models.Attachment.objects.filter( - id=attachment.id, - origfilename='new.txt', - ) - ) - - attachment.delete() \ No newline at end of file + + self.assertEquals() From 1e142fff3b1c386f2ce7ffe193ed6d60e36b211a Mon Sep 17 00:00:00 2001 From: specify Date: Tue, 29 Sep 2026 13:55:54 -0500 Subject: [PATCH 4/8] [test]: match collectionobject with cat # --- .../tests/test_batch_image_upload.py | 64 +++++++++++++------ 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/specifyweb/backend/businessrules/tests/test_batch_image_upload.py b/specifyweb/backend/businessrules/tests/test_batch_image_upload.py index 59c13d69490..fa493ebe3ec 100644 --- a/specifyweb/backend/businessrules/tests/test_batch_image_upload.py +++ b/specifyweb/backend/businessrules/tests/test_batch_image_upload.py @@ -1,24 +1,50 @@ +from unittest.mock import patch +import json + +from django.test import Client +from django.db import transaction + +from specifyweb.backend.stored_queries.tests.tests import SQLAlchemySetup +from specifyweb.backend.stored_queries.tests.test_views.raw_query import ( + get_simple_query, +) from specifyweb.specify import models -from specifyweb.specify.tests.test_api import ApiTests -from specifyweb.specify.api.crud import post_resource -class BatchImageTests(ApiTests): - def setUp(self): - super().setUp() - - self.attachments = [ - models.Attachment.objects.create( - attachmentlocation='0123.png', - origfilename='0123.png', - title='0123.png', - mimetype='image/png', - tableid=model.Attachment.specify_model.tableId, - ) - ] - - def test_match_collectionobject_catnumber(self): - attachment = self.attachments[0] +class TestCollectionobjectCatnumber(SQLAlchemySetup): + @patch("specifyweb.backend.stored_queries.execution.models.session_context") + def test_match_collectionobject_by_cat_number(self, session_context): + session_context.return_value = TestCollectionobjectCatnumber.test_session_context() + + with transaction.atomic(): + target = models.Collectionobject.objects.create( + catalognumber='num-add', + collection=self.collection, + collectionmemberid=1, + ) + + target = self.collectionobjects[0] + target.catalognumber = "123" + target.save() + + c = Client() + c.force_login(self.specifyuser) + response = c.post(f'/stored_query/ephemeral/', get_simple_query(self.specifyuser), content_type="application/json") - self.assertEquals() + self.assertEqual(response.status_code, 200) + self.assertEqual( + {'results': [ + [target.id, '123'], + [target.id, 'num-1'], + [target.id, 'num-2'], + [target.id, 'num-3'], + [target.id, 'num-4'], + [target.id, 'num-add'] + ] + }, + json.loads(response.content.decode()) + ) + + + From e63e65f417f1e826d61e94eb59b8ca03bc0c0307 Mon Sep 17 00:00:00 2001 From: Gabriel Kiveu <50419484+gabek96@users.noreply.github.com> Date: Wed, 30 Sep 2026 09:24:40 -0500 Subject: [PATCH 5/8] Potential fix for pull request finding 'CodeQL / Variable defined multiple times' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .../backend/businessrules/tests/test_batch_image_upload.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/backend/businessrules/tests/test_batch_image_upload.py b/specifyweb/backend/businessrules/tests/test_batch_image_upload.py index fa493ebe3ec..87b57f93b0f 100644 --- a/specifyweb/backend/businessrules/tests/test_batch_image_upload.py +++ b/specifyweb/backend/businessrules/tests/test_batch_image_upload.py @@ -17,7 +17,7 @@ def test_match_collectionobject_by_cat_number(self, session_context): session_context.return_value = TestCollectionobjectCatnumber.test_session_context() with transaction.atomic(): - target = models.Collectionobject.objects.create( + models.Collectionobject.objects.create( catalognumber='num-add', collection=self.collection, collectionmemberid=1, From 88106605540f762c6975d1982b937ef41774829a Mon Sep 17 00:00:00 2001 From: specify Date: Wed, 30 Sep 2026 09:46:01 -0500 Subject: [PATCH 6/8] fixed for match collection number by cat number --- .../tests/test_batch_image_upload.py | 39 +++++++------------ 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/specifyweb/backend/businessrules/tests/test_batch_image_upload.py b/specifyweb/backend/businessrules/tests/test_batch_image_upload.py index 87b57f93b0f..fd13989ef84 100644 --- a/specifyweb/backend/businessrules/tests/test_batch_image_upload.py +++ b/specifyweb/backend/businessrules/tests/test_batch_image_upload.py @@ -1,14 +1,12 @@ -from unittest.mock import patch import json +from unittest.mock import patch from django.test import Client -from django.db import transaction from specifyweb.backend.stored_queries.tests.tests import SQLAlchemySetup from specifyweb.backend.stored_queries.tests.test_views.raw_query import ( get_simple_query, ) -from specifyweb.specify import models class TestCollectionobjectCatnumber(SQLAlchemySetup): @@ -16,35 +14,24 @@ class TestCollectionobjectCatnumber(SQLAlchemySetup): def test_match_collectionobject_by_cat_number(self, session_context): session_context.return_value = TestCollectionobjectCatnumber.test_session_context() - with transaction.atomic(): - models.Collectionobject.objects.create( - catalognumber='num-add', - collection=self.collection, - collectionmemberid=1, - ) - target = self.collectionobjects[0] target.catalognumber = "123" target.save() - c = Client() c.force_login(self.specifyuser) - response = c.post(f'/stored_query/ephemeral/', get_simple_query(self.specifyuser), content_type="application/json") + + + query = get_simple_query(self.specifyuser) + query["fields"][0].update({ + "operstart": 10, + "startvalue": "123", + }) + + response = c.post("/stored_query/ephemeral/",query,content_type="application/json",) self.assertEqual(response.status_code, 200) self.assertEqual( - {'results': [ - [target.id, '123'], - [target.id, 'num-1'], - [target.id, 'num-2'], - [target.id, 'num-3'], - [target.id, 'num-4'], - [target.id, 'num-add'] - ] - }, - json.loads(response.content.decode()) - ) - - - + json.loads(response.content.decode()), + {"results": [[target.id, "123"]]}, + ) From cbac1d326ab6abbb005d3c7744d9627d60d198a9 Mon Sep 17 00:00:00 2001 From: specify Date: Wed, 30 Sep 2026 10:48:45 -0500 Subject: [PATCH 7/8] [test]: match collection number by alt catalog number --- .../tests/test_batch_image_upload.py | 44 ++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/specifyweb/backend/businessrules/tests/test_batch_image_upload.py b/specifyweb/backend/businessrules/tests/test_batch_image_upload.py index fd13989ef84..22a055caa33 100644 --- a/specifyweb/backend/businessrules/tests/test_batch_image_upload.py +++ b/specifyweb/backend/businessrules/tests/test_batch_image_upload.py @@ -9,14 +9,14 @@ ) -class TestCollectionobjectCatnumber(SQLAlchemySetup): +class TestCollectionobjectCatalognumber(SQLAlchemySetup): @patch("specifyweb.backend.stored_queries.execution.models.session_context") def test_match_collectionobject_by_cat_number(self, session_context): - session_context.return_value = TestCollectionobjectCatnumber.test_session_context() + session_context.return_value = TestCollectionobjectCatalognumber.test_session_context() - target = self.collectionobjects[0] - target.catalognumber = "123" - target.save() + catnum = self.collectionobjects[0] + catnum.catalognumber = "123" + catnum.save() c = Client() c.force_login(self.specifyuser) @@ -33,5 +33,37 @@ def test_match_collectionobject_by_cat_number(self, session_context): self.assertEqual(response.status_code, 200) self.assertEqual( json.loads(response.content.decode()), - {"results": [[target.id, "123"]]}, + {"results": [[catnum.id, "123"]]}, + ) + +class TestCollectionobjectAltCatalogNumber(SQLAlchemySetup): + @patch("specifyweb.backend.stored_queries.execution.models.session_context") + def test_match_collectionobject_by_previous_alt_cat_number(self, session_context): + session_context.return_value = TestCollectionobjectAltCatalogNumber.test_session_context() + + altcat = self.collectionobjects[0] + altcat.altcatalognumber = "123" + altcat.save() + + c = Client() + c.force_login(self.specifyuser) + + query = get_simple_query(self.specifyuser) + query["fields"][0].update({ + "stringid": "1.collectionobject.altCatalogNumber", + "fieldname": "altCatalogNumber", + "operstart": 10, + "startvalue": "123", + }) + + response = c.post( + "/stored_query/ephemeral/", + query, + content_type="application/json", + ) + + self.assertEqual(response.status_code, 200, response.content.decode()) + self.assertEqual( + json.loads(response.content.decode()), + {"results": [[altcat.id, "123"]]}, ) From 7c98f134357284ca6a17f7f3fe21d913193c2857 Mon Sep 17 00:00:00 2001 From: specify Date: Wed, 30 Sep 2026 11:32:50 -0500 Subject: [PATCH 8/8] [test]: match by taxon full name --- .../tests/test_batch_image_upload.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/specifyweb/backend/businessrules/tests/test_batch_image_upload.py b/specifyweb/backend/businessrules/tests/test_batch_image_upload.py index 22a055caa33..191dd69d14b 100644 --- a/specifyweb/backend/businessrules/tests/test_batch_image_upload.py +++ b/specifyweb/backend/businessrules/tests/test_batch_image_upload.py @@ -2,6 +2,7 @@ from unittest.mock import patch from django.test import Client +from specifyweb.specify import models from specifyweb.backend.stored_queries.tests.tests import SQLAlchemySetup from specifyweb.backend.stored_queries.tests.test_views.raw_query import ( @@ -67,3 +68,38 @@ def test_match_collectionobject_by_previous_alt_cat_number(self, session_context json.loads(response.content.decode()), {"results": [[altcat.id, "123"]]}, ) + +class TestTaxonFullname(SQLAlchemySetup): + @patch("specifyweb.backend.stored_queries.execution.models.session_context") + def test_match_taxon_by_full_name(self, session_context): + session_context.return_value = TestTaxonFullname.test_session_context() + + root = self.taxontreedef.treedefitems.create(name="Taxonomy Root", rankid=0) + taxon = root.treeentries.create( + name="John Doe", + fullname="John Doe", + definition=self.taxontreedef, + rankid=root.rankid, + ) + models.Determination.objects.create( + collectionobject=self.collectionobjects[0], + taxon=taxon, + iscurrent=True, + ) + + c = Client() + c.force_login(self.specifyuser) + + query = get_simple_query(self.specifyuser) + query["fields"][0].update({ + "tablelist": "1,9-determinations,4", + "stringid": "1,9-determinations,4.taxon.fullname", + "fieldname": "fullname", + "operstart": 1, + "startvalue": "John Doe", + }) + + response = c.post( "/stored_query/ephemeral/",query,content_type="application/json",) + + self.assertEqual(response.status_code, 200, response.content.decode()) + self.assertEqual(json.loads(response.content.decode()),{"results": [[self.collectionobjects[0].id, "John Doe"]]},)