import pytest from django.test import Client from django.urls import reverse import io from unittest.mock import patch from django.core.files.uploadedfile import SimpleUploadedFile @pytest.fixture def client(): return Client() def test_upload_get(client): resp = client.get(reverse('identify_upload')) assert resp.status_code == 200 def test_confirm_redirects_without_session(client): resp = client.get(reverse('identify_confirm')) assert resp.status_code == 302 assert reverse('identify_upload') in resp['Location'] def test_fields_redirects_without_session(client): resp = client.get(reverse('identify_fields')) assert resp.status_code == 302 assert reverse('identify_upload') in resp['Location'] def _fake_image(name='test.jpg'): return SimpleUploadedFile(name, b'fake-image-bytes', content_type='image/jpeg') def test_upload_post_no_images(client): resp = client.post(reverse('identify_upload'), {}) assert resp.status_code == 200 assert b'select at least one' in resp.content.lower() or b'Please' in resp.content @pytest.mark.django_db def test_upload_post_calls_plantnet_and_redirects(client, settings): settings.PLANTNET_API_KEY = 'test-key' fake_matches = [ {'scientific_name': 'Liatris spicata', 'common_names': ['Blazing star'], 'score': 0.94, 'gbif_id': '123', 'family': 'Asteraceae', 'genus': 'Liatris'}, ] with patch('plants.views.identify.plantnet.identify', return_value=fake_matches): with patch('plants.views.identify.default_storage') as mock_storage: mock_storage.save.return_value = 'plants/temp_identify/abc_0.jpg' mock_storage.path.return_value = '/tmp/abc_0.jpg' resp = client.post(reverse('identify_upload'), { 'images': [_fake_image()], 'organs': ['flower'], }) assert resp.status_code == 302 assert reverse('identify_confirm') in resp['Location'] assert client.session['identify_matches'] == fake_matches def test_upload_post_plantnet_error_rerenders(client, settings): settings.PLANTNET_API_KEY = 'test-key' from plants.services.plantnet import PlantNetError with patch('plants.views.identify.plantnet.identify', side_effect=PlantNetError('No match found')): with patch('plants.views.identify.default_storage') as mock_storage: mock_storage.save.return_value = 'plants/temp_identify/abc_0.jpg' mock_storage.path.return_value = '/tmp/abc_0.jpg' mock_storage.exists.return_value = True resp = client.post(reverse('identify_upload'), { 'images': [_fake_image()], 'organs': ['flower'], }) assert resp.status_code == 200 assert b'No match found' in resp.content def _set_matches(client): session = client.session session['identify_matches'] = [ {'scientific_name': 'Liatris spicata', 'common_names': ['Blazing star'], 'score': 0.94, 'gbif_id': '123', 'family': 'Asteraceae', 'genus': 'Liatris'}, {'scientific_name': 'Liatris pycnostachya', 'common_names': ['Prairie blazing star'], 'score': 0.04, 'gbif_id': '456', 'family': 'Asteraceae', 'genus': 'Liatris'}, ] session['identify_image_paths'] = [{'path': 'plants/temp_identify/x_0.jpg', 'organ': 'flower'}] session.save() @pytest.mark.django_db def test_confirm_get_with_session(client): _set_matches(client) resp = client.get(reverse('identify_confirm')) assert resp.status_code == 200 assert b'Liatris spicata' in resp.content @pytest.mark.django_db def test_confirm_post_stores_selection_and_redirects(client): _set_matches(client) with patch('plants.views.identify.vpc_search', return_value=[ {'slug': 'liatris-spicata', 'common_name': 'Liatris spicata', 'scientific_name': 'Liatris spicata', 'thumbnail_url': '', 'source': 'vpc'}, ]): resp = client.post(reverse('identify_confirm'), {'match_idx': '0'}) assert resp.status_code == 302 assert reverse('identify_fields') in resp['Location'] assert client.session['identify_selected']['scientific_name'] == 'Liatris spicata' assert len(client.session['identify_vpc_results']) == 1 @pytest.mark.django_db def test_confirm_post_handles_vpc_failure(client): _set_matches(client) from plants.services.vpc import VPCError with patch('plants.views.identify.vpc_search', side_effect=VPCError('down')): resp = client.post(reverse('identify_confirm'), {'match_idx': '0'}) assert resp.status_code == 302 assert client.session['identify_vpc_results'] == []