From 9de2ef672fb840f82828a2d31f303c1d357a715c Mon Sep 17 00:00:00 2001 From: Nick Jackson Date: Mon, 24 Apr 2023 12:55:56 +0100 Subject: [PATCH 1/8] Move tests to new folder This will help us in future when we slice tests into multiple files for clarity --- judgments/{ => tests}/tests.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename judgments/{ => tests}/tests.py (100%) diff --git a/judgments/tests.py b/judgments/tests/tests.py similarity index 100% rename from judgments/tests.py rename to judgments/tests/tests.py From 74cd38d270b534d3424835bcad67901e3fc275cd Mon Sep 17 00:00:00 2001 From: Nick Jackson Date: Mon, 24 Apr 2023 13:06:45 +0100 Subject: [PATCH 2/8] Move court tests to own file --- judgments/tests/test_courts.py | 48 ++++++++++++++++++++++++++++++++++ judgments/tests/tests.py | 47 ++------------------------------- 2 files changed, 50 insertions(+), 45 deletions(-) create mode 100644 judgments/tests/test_courts.py diff --git a/judgments/tests/test_courts.py b/judgments/tests/test_courts.py new file mode 100644 index 000000000..150e1792f --- /dev/null +++ b/judgments/tests/test_courts.py @@ -0,0 +1,48 @@ +from unittest.mock import Mock, patch + +from django.test import TestCase + +from judgments.models import CourtDates +from judgments.templatetags.court_utils import get_court_date_range, get_court_name + + +def test_get_court_name(): + assert get_court_name("uksc") == "United Kingdom Supreme Court" + + +def test_get_court_name_non_existent(): + assert get_court_name("ffff") == "" + + +@patch("judgments.templatetags.court_utils.CourtDates.objects.get") +class TestCourtDatesHelper(TestCase): + def mock_court_dates(self, start_year, end_year): + mock = Mock() + mock.configure_mock(start_year=start_year, end_year=end_year) + return mock + + def test_when_court_with_param_exists_and_no_dates_in_db_and_start_end_same( + self, get + ): + get.side_effect = CourtDates.DoesNotExist + court = self.mock_court_dates(2011, 2011) + self.assertEqual(get_court_date_range(court), "2011") + + def test_when_court_with_param_exists_and_no_dates_in_db_and_start_end_different( + self, get + ): + get.side_effect = CourtDates.DoesNotExist + court = self.mock_court_dates(2011, 2012) + self.assertEqual(get_court_date_range(court), "2011 – 2012") + + def test_when_court_with_param_exists_and_dates_in_db_and_start_end_same(self, get): + get.return_value = self.mock_court_dates(2013, 2013) + court = self.mock_court_dates(2011, 2012) + self.assertEqual(get_court_date_range(court), "2013") + + def test_when_court_with_param_exists_and_dates_in_db_and_start_end_different( + self, get + ): + get.return_value = self.mock_court_dates(2013, 2015) + court = self.mock_court_dates(2011, 2012) + self.assertEqual(get_court_date_range(court), "2013 – 2015") diff --git a/judgments/tests/tests.py b/judgments/tests/tests.py index 88efc89ac..00677ba67 100644 --- a/judgments/tests/tests.py +++ b/judgments/tests/tests.py @@ -1,15 +1,14 @@ import re from os import environ from unittest import skip -from unittest.mock import Mock, patch +from unittest.mock import patch from dateutil import parser as dateparser from django.test import TestCase from lxml import etree from judgments import converters, utils -from judgments.models import CourtDates, SearchResult, SearchResults -from judgments.templatetags.court_utils import get_court_date_range, get_court_name +from judgments.models import SearchResult, SearchResults from judgments.utils import as_integer, display_back_link, paginator @@ -463,45 +462,3 @@ def test_solo_stop_word_regex(): stop_words = ["and", "of", "the", "for"] expected_output = r"(^and$)|(^of$)|(^the$)|(^for$)" assert utils.solo_stop_word_regex(stop_words) == expected_output - - -def test_get_court_name(): - assert get_court_name("uksc") == "United Kingdom Supreme Court" - - -def test_get_court_name_non_existent(): - assert get_court_name("ffff") == "" - - -@patch("judgments.templatetags.court_utils.CourtDates.objects.get") -class TestCourtDatesHelper(TestCase): - def mock_court_dates(self, start_year, end_year): - mock = Mock() - mock.configure_mock(start_year=start_year, end_year=end_year) - return mock - - def test_when_court_with_param_exists_and_no_dates_in_db_and_start_end_same( - self, get - ): - get.side_effect = CourtDates.DoesNotExist - court = self.mock_court_dates(2011, 2011) - self.assertEqual(get_court_date_range(court), "2011") - - def test_when_court_with_param_exists_and_no_dates_in_db_and_start_end_different( - self, get - ): - get.side_effect = CourtDates.DoesNotExist - court = self.mock_court_dates(2011, 2012) - self.assertEqual(get_court_date_range(court), "2011 – 2012") - - def test_when_court_with_param_exists_and_dates_in_db_and_start_end_same(self, get): - get.return_value = self.mock_court_dates(2013, 2013) - court = self.mock_court_dates(2011, 2012) - self.assertEqual(get_court_date_range(court), "2013") - - def test_when_court_with_param_exists_and_dates_in_db_and_start_end_different( - self, get - ): - get.return_value = self.mock_court_dates(2013, 2015) - court = self.mock_court_dates(2011, 2012) - self.assertEqual(get_court_date_range(court), "2013 – 2015") From efe626c58229f431b63bab5559c9c8a38a095a1d Mon Sep 17 00:00:00 2001 From: Nick Jackson Date: Mon, 24 Apr 2023 13:15:52 +0100 Subject: [PATCH 3/8] Move search tests to own file --- judgments/tests/test_search.py | 150 +++++++++++++++++++++++++++++++++ judgments/tests/tests.py | 147 +------------------------------- 2 files changed, 151 insertions(+), 146 deletions(-) create mode 100644 judgments/tests/test_search.py diff --git a/judgments/tests/test_search.py b/judgments/tests/test_search.py new file mode 100644 index 000000000..2a0eb65d8 --- /dev/null +++ b/judgments/tests/test_search.py @@ -0,0 +1,150 @@ +from unittest.mock import patch + +from dateutil import parser as dateparser +from django.test import TestCase +from lxml import etree + +from judgments.models import SearchResult, SearchResults + + +def fake_search_results(): + with open("fixtures/search_results.xml", "r") as f: + return SearchResults.create_from_string(f.read()) + + +def fake_search_result(): + return SearchResult( + uri="ewhc/ch/2022/1.xml", + neutral_citation="[2022] EWHC 1 (Ch)", + name="A SearchResult name!", + matches=[], + court="A court!", + date="2022-01-01T00:01:00", + author="", + last_modified="2022-01-01T00:01:00.123", + content_hash="A hash!", + transformation_date="2022-01-01T00:02:00", + ) + + +class TestSearchResults(TestCase): + @patch("judgments.views.results.perform_advanced_search") + @patch("judgments.models.SearchResult.create_from_node") + @patch("judgments.utils.perform_advanced_search") + def test_judgment_results(self, f3, fake_result, fake_advanced_search): + fake_advanced_search.return_value = fake_search_results() + f3.r = fake_search_results() + fake_result.return_value = fake_search_result() + response = self.client.get("/judgments/results?query=waltham+forest") + self.assertContains( + response, + 'waltham forest', + ) + + @patch("judgments.views.results.perform_advanced_search") + @patch("judgments.models.SearchResult.create_from_node") + @patch("judgments.utils.perform_advanced_search") + @patch("judgments.views.results.preprocess_query") + def test_jugdment_results_query_preproccesed( + self, fake_preprocess_query, f3, fake_result, fake_advanced_search + ): + fake_advanced_search.return_value = fake_search_results() + f3.r = fake_search_results() + fake_result.return_value = fake_search_result() + fake_preprocess_query.return_value = "normalised query" + self.client.get("/judgments/results?query=waltham+forest") + + fake_preprocess_query.assert_called() + + @patch("judgments.views.advanced_search.perform_advanced_search") + @patch("judgments.models.SearchResult.create_from_node") + def test_judgment_advanced_search(self, fake_result, fake_advanced_search): + fake_advanced_search.return_value = fake_search_results() + fake_result.return_value = fake_search_result() + response = self.client.get("/judgments/advanced_search?query=waltham+forest") + self.assertContains( + response, + 'waltham forest', + ) + + @patch("judgments.views.advanced_search.perform_advanced_search") + @patch("judgments.models.SearchResult.create_from_node") + @patch("judgments.views.advanced_search.preprocess_query") + def test_judgment_advanced_search_query_preprocessed( + self, fake_preprocess_query, fake_result, fake_advanced_search + ): + fake_advanced_search.return_value = fake_search_results() + fake_result.return_value = fake_search_result() + fake_preprocess_query.return_value = "normalised query" + self.client.get("/judgments/advanced_search?query=waltham+forest") + fake_preprocess_query.assert_called() + + +class TestSearchResult(TestCase): + @patch("judgments.models.api_client") + def test_create_from_node(self, fake_client): + client_attrs = { + "get_property.return_value": "something fake", + "get_last_modified.return_value": "01-01-2022", + } + fake_client.configure_mock(**client_attrs) + search_result_str = """ + + + + + + + UKUT-LC + [2022] UKUT 241 (LC) + + 56c551fef5be37cb1658c895c1d15c913e76b712ba3ccc88d3b6b75ea69d3e8a + + + [2022] UKUT 241 (LC) + + + + """ + search_result_xml = etree.fromstring(search_result_str) + search_result = SearchResult.create_from_node(search_result_xml) + self.assertEqual( + "London Borough of Waltham Forest v Nasim Hussain", search_result.name + ) + self.assertEqual("ukut/lc/2022/241", search_result.uri) + self.assertEqual("[2022] UKUT 241 (LC)", search_result.neutral_citation) + self.assertEqual("UKUT-LC", search_result.court.code) + self.assertEqual(dateparser.parse("2022-09-09"), search_result.date) + self.assertEqual("2022-10-10", search_result.transformation_date) + + @patch("judgments.models.api_client") + def test_create_from_node_with_missing_elements(self, fake_client): + client_attrs = { + "get_property.return_value": "something fake", + "get_last_modified.return_value": "01-01-2022", + } + fake_client.configure_mock(**client_attrs) + search_result_str = """ + + + + + + + + + + + + """ + search_result_xml = etree.fromstring(search_result_str) + search_result = SearchResult.create_from_node(search_result_xml) + self.assertEqual( + "London Borough of Waltham Forest v Nasim Hussain", search_result.name + ) + self.assertEqual("ukut/lc/2022/241", search_result.uri) + self.assertEqual(None, search_result.neutral_citation) + self.assertEqual(None, search_result.court) + self.assertEqual(None, search_result.content_hash) diff --git a/judgments/tests/tests.py b/judgments/tests/tests.py index 00677ba67..bb6786d6f 100644 --- a/judgments/tests/tests.py +++ b/judgments/tests/tests.py @@ -3,88 +3,13 @@ from unittest import skip from unittest.mock import patch -from dateutil import parser as dateparser from django.test import TestCase -from lxml import etree +from test_search import fake_search_result, fake_search_results from judgments import converters, utils -from judgments.models import SearchResult, SearchResults from judgments.utils import as_integer, display_back_link, paginator -def fake_search_results(): - with open("fixtures/search_results.xml", "r") as f: - return SearchResults.create_from_string(f.read()) - - -def fake_search_result(): - return SearchResult( - uri="ewhc/ch/2022/1.xml", - neutral_citation="[2022] EWHC 1 (Ch)", - name="A SearchResult name!", - matches=[], - court="A court!", - date="2022-01-01T00:01:00", - author="", - last_modified="2022-01-01T00:01:00.123", - content_hash="A hash!", - transformation_date="2022-01-01T00:02:00", - ) - - -class TestSearchResults(TestCase): - @patch("judgments.views.results.perform_advanced_search") - @patch("judgments.models.SearchResult.create_from_node") - @patch("judgments.utils.perform_advanced_search") - def test_judgment_results(self, f3, fake_result, fake_advanced_search): - fake_advanced_search.return_value = fake_search_results() - f3.r = fake_search_results() - fake_result.return_value = fake_search_result() - response = self.client.get("/judgments/results?query=waltham+forest") - self.assertContains( - response, - 'waltham forest', - ) - - @patch("judgments.views.results.perform_advanced_search") - @patch("judgments.models.SearchResult.create_from_node") - @patch("judgments.utils.perform_advanced_search") - @patch("judgments.views.results.preprocess_query") - def test_jugdment_results_query_preproccesed( - self, fake_preprocess_query, f3, fake_result, fake_advanced_search - ): - fake_advanced_search.return_value = fake_search_results() - f3.r = fake_search_results() - fake_result.return_value = fake_search_result() - fake_preprocess_query.return_value = "normalised query" - self.client.get("/judgments/results?query=waltham+forest") - - fake_preprocess_query.assert_called() - - @patch("judgments.views.advanced_search.perform_advanced_search") - @patch("judgments.models.SearchResult.create_from_node") - def test_judgment_advanced_search(self, fake_result, fake_advanced_search): - fake_advanced_search.return_value = fake_search_results() - fake_result.return_value = fake_search_result() - response = self.client.get("/judgments/advanced_search?query=waltham+forest") - self.assertContains( - response, - 'waltham forest', - ) - - @patch("judgments.views.advanced_search.perform_advanced_search") - @patch("judgments.models.SearchResult.create_from_node") - @patch("judgments.views.advanced_search.preprocess_query") - def test_judgment_advanced_search_query_preprocessed( - self, fake_preprocess_query, fake_result, fake_advanced_search - ): - fake_advanced_search.return_value = fake_search_results() - fake_result.return_value = fake_search_result() - fake_preprocess_query.return_value = "normalised query" - self.client.get("/judgments/advanced_search?query=waltham+forest") - fake_preprocess_query.assert_called() - - class TestAtomFeed(TestCase): @patch("judgments.feeds.perform_advanced_search") @patch("judgments.models.SearchResult.create_from_node") @@ -188,76 +113,6 @@ def test_404_response(self): self.assertEqual(response.status_code, 404) -class TestSearchResult(TestCase): - @patch("judgments.models.api_client") - def test_create_from_node(self, fake_client): - client_attrs = { - "get_property.return_value": "something fake", - "get_last_modified.return_value": "01-01-2022", - } - fake_client.configure_mock(**client_attrs) - search_result_str = """ - - - - - - - UKUT-LC - [2022] UKUT 241 (LC) - - 56c551fef5be37cb1658c895c1d15c913e76b712ba3ccc88d3b6b75ea69d3e8a - - - [2022] UKUT 241 (LC) - - - - """ - search_result_xml = etree.fromstring(search_result_str) - search_result = SearchResult.create_from_node(search_result_xml) - self.assertEqual( - "London Borough of Waltham Forest v Nasim Hussain", search_result.name - ) - self.assertEqual("ukut/lc/2022/241", search_result.uri) - self.assertEqual("[2022] UKUT 241 (LC)", search_result.neutral_citation) - self.assertEqual("UKUT-LC", search_result.court.code) - self.assertEqual(dateparser.parse("2022-09-09"), search_result.date) - self.assertEqual("2022-10-10", search_result.transformation_date) - - @patch("judgments.models.api_client") - def test_create_from_node_with_missing_elements(self, fake_client): - client_attrs = { - "get_property.return_value": "something fake", - "get_last_modified.return_value": "01-01-2022", - } - fake_client.configure_mock(**client_attrs) - search_result_str = """ - - - - - - - - - - - - """ - search_result_xml = etree.fromstring(search_result_str) - search_result = SearchResult.create_from_node(search_result_xml) - self.assertEqual( - "London Borough of Waltham Forest v Nasim Hussain", search_result.name - ) - self.assertEqual("ukut/lc/2022/241", search_result.uri) - self.assertEqual(None, search_result.neutral_citation) - self.assertEqual(None, search_result.court) - self.assertEqual(None, search_result.content_hash) - - class TestPaginator(TestCase): def test_paginator_2500(self): expected_result = { From 7196b039170c39f7d5cba6096335b8ae650c2745 Mon Sep 17 00:00:00 2001 From: Nick Jackson Date: Mon, 24 Apr 2023 14:02:49 +0100 Subject: [PATCH 4/8] Move atom feed tests to own file --- judgments/tests/test_atom_feed.py | 32 +++++++++++++++++++++++++++++++ judgments/tests/tests.py | 28 --------------------------- 2 files changed, 32 insertions(+), 28 deletions(-) create mode 100644 judgments/tests/test_atom_feed.py diff --git a/judgments/tests/test_atom_feed.py b/judgments/tests/test_atom_feed.py new file mode 100644 index 000000000..5137b4bd7 --- /dev/null +++ b/judgments/tests/test_atom_feed.py @@ -0,0 +1,32 @@ +from unittest.mock import patch + +from django.test import TestCase +from test_search import fake_search_result, fake_search_results + + +class TestAtomFeed(TestCase): + @patch("judgments.feeds.perform_advanced_search") + @patch("judgments.models.SearchResult.create_from_node") + def test_feed_exists(self, fake_result, fake_advanced_search): + fake_advanced_search.return_value = fake_search_results() + fake_result.return_value = fake_search_result() + + response = self.client.get("/atom.xml") + decoded_response = response.content.decode("utf-8") + # that there is a valid page + self.assertEqual(response.status_code, 200) + # that it has the correct site name + self.assertIn("The National Archives", decoded_response) + # that it is like an Atom XML document + self.assertIn("http://www.w3.org/2005/Atom", decoded_response) + # that it has an entry + self.assertIn("", decoded_response) + # and it contains actual content - neither neutral citation or court appear in the feed to test. + self.assertIn("A SearchResult name!", decoded_response) + + @patch("judgments.utils.perform_advanced_search") + def test_bad_page_404(self, fake_advanced_search): + # "?page=" 404s, not 500 + fake_advanced_search.return_value = fake_search_results() + response = self.client.get("/atom.xml?page=") + self.assertEqual(response.status_code, 404) diff --git a/judgments/tests/tests.py b/judgments/tests/tests.py index bb6786d6f..f103946ea 100644 --- a/judgments/tests/tests.py +++ b/judgments/tests/tests.py @@ -10,34 +10,6 @@ from judgments.utils import as_integer, display_back_link, paginator -class TestAtomFeed(TestCase): - @patch("judgments.feeds.perform_advanced_search") - @patch("judgments.models.SearchResult.create_from_node") - def test_feed_exists(self, fake_result, fake_advanced_search): - fake_advanced_search.return_value = fake_search_results() - fake_result.return_value = fake_search_result() - - response = self.client.get("/atom.xml") - decoded_response = response.content.decode("utf-8") - # that there is a valid page - self.assertEqual(response.status_code, 200) - # that it has the correct site name - self.assertIn("The National Archives", decoded_response) - # that it is like an Atom XML document - self.assertIn("http://www.w3.org/2005/Atom", decoded_response) - # that it has an entry - self.assertIn("", decoded_response) - # and it contains actual content - neither neutral citation or court appear in the feed to test. - self.assertIn("A SearchResult name!", decoded_response) - - @patch("judgments.utils.perform_advanced_search") - def test_bad_page_404(self, fake_advanced_search): - # "?page=" 404s, not 500 - fake_advanced_search.return_value = fake_search_results() - response = self.client.get("/atom.xml?page=") - self.assertEqual(response.status_code, 404) - - class TestJudgment(TestCase): @patch("judgments.views.detail.requests.head") @patch("judgments.views.detail.decoder.MultipartDecoder") From 01674895103ef1428ea072aea96c93ed0dc2caa7 Mon Sep 17 00:00:00 2001 From: Nick Jackson Date: Mon, 24 Apr 2023 14:36:57 +0100 Subject: [PATCH 5/8] fake_search_result can now accept arguments So that we can test search results under various conditions, we can now pass arguments to fake_search_result() to modify the response --- judgments/tests/test_search.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/judgments/tests/test_search.py b/judgments/tests/test_search.py index 2a0eb65d8..46650adf1 100644 --- a/judgments/tests/test_search.py +++ b/judgments/tests/test_search.py @@ -12,18 +12,29 @@ def fake_search_results(): return SearchResults.create_from_string(f.read()) -def fake_search_result(): +def fake_search_result( + uri="ewhc/ch/2022/1.xml", + neutral_citation="[2022] EWHC 1 (Ch)", + name="A SearchResult name!", + matches=[], + court="A court!", + date="2022-01-01T00:01:00", + author="", + last_modified="2022-01-01T00:01:00.123", + content_hash="A hash!", + transformation_date="2022-01-01T00:02:00", +): return SearchResult( - uri="ewhc/ch/2022/1.xml", - neutral_citation="[2022] EWHC 1 (Ch)", - name="A SearchResult name!", - matches=[], - court="A court!", - date="2022-01-01T00:01:00", - author="", - last_modified="2022-01-01T00:01:00.123", - content_hash="A hash!", - transformation_date="2022-01-01T00:02:00", + uri=uri, + neutral_citation=neutral_citation, + name=name, + matches=matches, + court=court, + date=date, + author=author, + last_modified=last_modified, + content_hash=content_hash, + transformation_date=transformation_date, ) From b30f45dfd3b0ff5248de22e1d3ded4a790d8fb17 Mon Sep 17 00:00:00 2001 From: Nick Jackson Date: Mon, 24 Apr 2023 15:32:54 +0100 Subject: [PATCH 6/8] Add failing test for existing date case --- judgments/tests/test_atom_feed.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/judgments/tests/test_atom_feed.py b/judgments/tests/test_atom_feed.py index 5137b4bd7..0a3f6b662 100644 --- a/judgments/tests/test_atom_feed.py +++ b/judgments/tests/test_atom_feed.py @@ -30,3 +30,14 @@ def test_bad_page_404(self, fake_advanced_search): fake_advanced_search.return_value = fake_search_results() response = self.client.get("/atom.xml?page=") self.assertEqual(response.status_code, 404) + + @patch("judgments.feeds.perform_advanced_search") + @patch("judgments.models.SearchResult.create_from_node") + def test_feed_with_empty_date(self, fake_result, fake_advanced_search): + fake_advanced_search.return_value = fake_search_results() + fake_result.return_value = fake_search_result(date="") + + response = self.client.get("/atom.xml") + decoded_response = response.content.decode("utf-8") + self.assertEqual(response.status_code, 200) + self.assertIn("A SearchResult name!", decoded_response) From b6934eaaa0c424341726698304e67067bc33c4e4 Mon Sep 17 00:00:00 2001 From: Nick Jackson Date: Mon, 24 Apr 2023 15:34:00 +0100 Subject: [PATCH 7/8] SearchResult returns None for unparseable date Previously this would be set to the value of `date`, which would often be an empty string (and which would trip up the RSS feed generator). This now sets the value to None. --- judgments/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/judgments/models.py b/judgments/models.py index a5b0f367b..12e899866 100644 --- a/judgments/models.py +++ b/judgments/models.py @@ -30,7 +30,7 @@ def __init__( try: self.date = dateparser.parse(date) except ParserError: - self.date = date + self.date = None try: self.court = courts.get_by_code(court) except CourtNotFoundException: From 120954252de0e81e98843eac41ac988c91e46fff Mon Sep 17 00:00:00 2001 From: Nick Jackson Date: Tue, 25 Apr 2023 11:47:36 +0100 Subject: [PATCH 8/8] Improve robustness of SearchResult date parsing This is now tested, and will log a warning if a non-empty unparseable string is detected. --- judgments/models.py | 7 ++++++- judgments/tests/test_search.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/judgments/models.py b/judgments/models.py index 12e899866..6df78509e 100644 --- a/judgments/models.py +++ b/judgments/models.py @@ -1,3 +1,4 @@ +import logging from os.path import dirname, join from caselawclient.Client import api_client @@ -29,7 +30,11 @@ def __init__( try: self.date = dateparser.parse(date) - except ParserError: + except ParserError as e: + if date != "": + logging.warning( + f'Unable to parse document date "{date}". Full error: {e}' + ) self.date = None try: self.court = courts.get_by_code(court) diff --git a/judgments/tests/test_search.py b/judgments/tests/test_search.py index 46650adf1..a6b22b8c8 100644 --- a/judgments/tests/test_search.py +++ b/judgments/tests/test_search.py @@ -1,5 +1,9 @@ +from datetime import datetime +from logging import WARNING +from typing import Any from unittest.mock import patch +import pytest from dateutil import parser as dateparser from django.test import TestCase from lxml import etree @@ -159,3 +163,33 @@ def test_create_from_node_with_missing_elements(self, fake_client): self.assertEqual(None, search_result.neutral_citation) self.assertEqual(None, search_result.court) self.assertEqual(None, search_result.content_hash) + + +class TestSearchResultInit: + @pytest.mark.parametrize( + "date_string, expected", + [ + ["", None], + ["2023-05-09", datetime(2023, 5, 9, 0, 0)], + ["2023-04-05T06:54:00", datetime(2023, 4, 5, 6, 54)], + ["ffffff", None], + ], + ) + def test_searchresult_date_parsing(self, date_string: str, expected: Any): + search_result = fake_search_result(date=date_string) + + assert search_result.date == expected + + def test_unparseable_non_empty_string_logs_warning(self, caplog): + caplog.set_level(WARNING) + + fake_search_result(date="ffffff") + + assert "Unable to parse document date" in caplog.text + + def test_unparseable_empty_string_doesnt_log_warning(self, caplog): + caplog.set_level(WARNING) + + fake_search_result(date="") + + assert "Unable to parse document date" not in caplog.text