"""Tests for simple search controller, :mod:`search.controllers.simple`."""

from http import HTTPStatus
from unittest import TestCase, mock

from werkzeug.datastructures import MultiDict
from werkzeug.exceptions import InternalServerError, NotFound, BadRequest

from search.domain import SimpleQuery
from search.controllers import simple
from search.controllers.simple.forms import SimpleSearchForm
from search.services.index import (
    IndexConnectionError,
    QueryError,
    DocumentNotFound,
)


class TestRetrieveDocument(TestCase):
    """Tests for :func:`.simple.retrieve_document`."""

    @mock.patch("search.controllers.simple.SearchSession")
    def test_encounters_queryerror(self, mock_index):
        """There is a bug in the index or query."""

        def _raiseQueryError(*args, **kwargs):
            raise QueryError("What now")

        mock_index.get_document.side_effect = _raiseQueryError

        with self.assertRaises(InternalServerError):
            try:
                response_data, code, headers = simple.retrieve_document(1)
            except QueryError as ex:
                self.fail("QueryError should be handled (caught %s)" % ex)

        self.assertEqual(
            mock_index.get_document.call_count,
            1,
            "A search should be attempted",
        )

    @mock.patch("search.controllers.simple.SearchSession")
    def test_index_raises_connection_exception(self, mock_index):
        """Index service raises a IndexConnectionError."""
        mock_index.get_document.side_effect = IndexConnectionError

        with self.assertRaises(InternalServerError):
            response_data, code, headers = simple.retrieve_document("124.5678")
        self.assertEqual(
            mock_index.get_document.call_count,
            1,
            "A search should be attempted",
        )
        call_args, call_kwargs = mock_index.get_document.call_args
        self.assertIsInstance(call_args[0], str, "arXiv ID is passed")

        # self.assertEqual(code, status.HTTP_500_INTERNAL_SERVER_ERROR)

    @mock.patch("search.controllers.simple.SearchSession")
    def test_document_not_found(self, mock_index):
        """The document is not found."""

        def _raiseDocumentNotFound(*args, **kwargs):
            raise DocumentNotFound("What now")

        mock_index.get_document.side_effect = _raiseDocumentNotFound

        with self.assertRaises(NotFound):
            try:
                response_data, code, headers = simple.retrieve_document(1)
            except DocumentNotFound as ex:
                self.fail(
                    "DocumentNotFound should be handled (caught %s)" % ex
                )

        self.assertEqual(
            mock_index.get_document.call_count,
            1,
            "A search should be attempted",
        )


class TestSearchController(TestCase):
    """Tests for :func:`.simple.search`."""

    @mock.patch(
        "search.controllers.simple.url_for",
        lambda *a, **k: f'https://arxiv.org/{k["paper_id"]}',
    )
    @mock.patch("search.controllers.simple.SearchSession")
    def test_arxiv_id(self, mock_index):
        """Query parameter contains an arXiv ID."""
        request_data = MultiDict({"query": "1702.00123"})
        response_data, code, headers = simple.search(request_data)
        self.assertEqual(
            code,
            HTTPStatus.MOVED_PERMANENTLY,
            "Response should be a 301 redirect.",
        )
        self.assertIn("Location", headers, "Location header should be set")

        self.assertEqual(
            mock_index.search.call_count, 0, "No search should be attempted"
        )

    @mock.patch("search.controllers.simple.SearchSession")
    def test_no_form_data(self, mock_index):
        """No form data has been submitted."""
        request_data = MultiDict()
        response_data, code, headers = simple.search(request_data)
        self.assertEqual(code, HTTPStatus.OK, "Response should be OK.")

        self.assertIn("form", response_data, "Response should include form.")

        self.assertEqual(
            mock_index.search.call_count, 0, "No search should be attempted"
        )

    @mock.patch("search.controllers.simple.SearchSession")
    def test_single_field_term(self, mock_index):
        """Form data are present."""
        mock_index.search.return_value = {"metadata": {}, "results": []}
        request_data = MultiDict({"searchtype": "title", "query": "foo title"})
        response_data, code, headers = simple.search(request_data)
        self.assertEqual(
            mock_index.search.call_count, 1, "A search should be attempted"
        )
        call_args, call_kwargs = mock_index.search.call_args
        self.assertIsInstance(
            call_args[0],
            SimpleQuery,
            "An SimpleQuery is passed to the search index",
        )
        self.assertEqual(code, HTTPStatus.OK, "Response should be OK.")

    @mock.patch("search.controllers.simple.SearchSession")
    def test_invalid_data(self, mock_index):
        """Form data are invalid."""
        request_data = MultiDict({"searchtype": "title"})
        response_data, code, headers = simple.search(request_data)
        self.assertEqual(code, HTTPStatus.OK, "Response should be OK.")

        self.assertIn("form", response_data, "Response should include form.")

        self.assertEqual(
            mock_index.search.call_count, 0, "No search should be attempted"
        )

    @mock.patch("search.controllers.simple.SearchSession")
    def test_index_raises_connection_exception(self, mock_index):
        """Index service raises a IndexConnectionError."""

        def _raiseIndexConnectionError(*args, **kwargs):
            raise IndexConnectionError("What now")

        mock_index.search.side_effect = _raiseIndexConnectionError

        request_data = MultiDict({"searchtype": "title", "query": "foo title"})
        with self.assertRaises(InternalServerError):
            _, _, _ = simple.search(request_data)

        self.assertEqual(
            mock_index.search.call_count, 1, "A search should be attempted"
        )
        call_args, call_kwargs = mock_index.search.call_args
        self.assertIsInstance(
            call_args[0],
            SimpleQuery,
            "An SimpleQuery is passed to the search index",
        )

    @mock.patch("search.controllers.simple.SearchSession")
    def test_index_raises_query_error(self, mock_index):
        """Index service raises a QueryError."""

        def _raiseQueryError(*args, **kwargs):
            raise QueryError("What now")

        mock_index.search.side_effect = _raiseQueryError

        request_data = MultiDict({"searchtype": "title", "query": "foo title"})
        with self.assertRaises(InternalServerError):
            try:
                response_data, code, headers = simple.search(request_data)
            except QueryError as ex:
                self.fail("QueryError should be handled (caught %s)" % ex)

        self.assertEqual(
            mock_index.search.call_count, 1, "A search should be attempted"
        )


class TestSimpleSearchForm(TestCase):
    """Tests for :class:`.SimpleSearchForm`."""

    def test_searchtype_only(self):
        """User has entered only a searchtype (field)."""
        data = MultiDict({"searchtype": "title"})
        form = SimpleSearchForm(data)
        self.assertFalse(form.validate(), "Form should be invalid")

    def test_query_only(self):
        """User has entered only a query (value); this should never happen."""
        data = MultiDict({"query": "someone monkeyed with the request"})
        form = SimpleSearchForm(data)
        self.assertFalse(form.validate(), "Form should be invalid")

    def test_query_and_searchtype(self):
        """User has entered a searchtype (field) and query (value)."""
        data = MultiDict({"searchtype": "title", "query": "foo title"})
        form = SimpleSearchForm(data)
        self.assertTrue(form.validate(), "Form should be valid")


class TestQueryFromForm(TestCase):
    """Tests for :func:`.simple._query_from_form`."""

    def test_multiple_simple(self):
        """Form data has three simple."""
        data = MultiDict({"searchtype": "title", "query": "foo title"})
        form = SimpleSearchForm(data)
        query = simple._query_from_form(form)
        self.assertIsInstance(
            query, SimpleQuery, "Should return an instance of SimpleQuery"
        )

    def test_form_data_has_order(self):
        """Form data includes sort order."""
        data = MultiDict(
            {
                "searchtype": "title",
                "query": "foo title",
                "order": "submitted_date",
            }
        )
        form = SimpleSearchForm(data)
        query = simple._query_from_form(form)
        self.assertIsInstance(
            query, SimpleQuery, "Should return an instance of SimpleQuery"
        )
        self.assertEqual(query.order, "submitted_date")

    def test_form_data_has_no_order(self):
        """Form data includes sort order parameter, but it is 'None'."""
        data = MultiDict(
            {"searchtype": "title", "query": "foo title", "order": "None"}  #
        )
        form = SimpleSearchForm(data)
        query = simple._query_from_form(form)
        self.assertIsInstance(
            query, SimpleQuery, "Should return an instance of SimpleQuery"
        )
        self.assertIsNone(query.order, "Order should be None")

    def test_querystring_has_wildcard_at_start(self):
        """Querystring starts with a wildcard."""
        data = MultiDict({"searchtype": "title", "query": "*foo title"})
        form = SimpleSearchForm(data)
        self.assertFalse(form.validate(), "Form should be invalid")

    def test_input_whitespace_is_stripped(self):
        """If query has padding whitespace, it should be removed."""
        data = MultiDict({"searchtype": "title", "query": " foo title "})
        form = SimpleSearchForm(data)
        self.assertTrue(form.validate(), "Form should be valid.")
        self.assertEqual(form.query.data, "foo title")

    def test_querystring_has_unbalanced_quotes(self):
        """Querystring has an odd number of quote characters."""
        data = MultiDict({"searchtype": "title", "query": '"rhubarb'})
        form = SimpleSearchForm(data)
        self.assertFalse(form.validate(), "Form should be invalid")

        data["query"] = '"rhubarb"'
        form = SimpleSearchForm(data)
        self.assertTrue(form.validate(), "Form should be valid")

        data["query"] = '"rhubarb" "pie'
        form = SimpleSearchForm(data)
        self.assertFalse(form.validate(), "Form should be invalid")

        data["query"] = '"rhubarb" "pie"'
        form = SimpleSearchForm(data)
        self.assertTrue(form.validate(), "Form should be valid")


class TestPaginationParametersAreFunky(TestCase):
    """
    The user may have monkeyed with the order or sort parameters.

    Since these are limited to specific values, there is no other reason for
    them to be invalid. Given that they are passed around among
    views (to persist users' selection), it's important to break the chain.
    To do this, we return a 400 Bad Request, with a clean link back to the
    search form.
    """

    @mock.patch("search.controllers.simple.url_for")
    def test_order_is_invalid(self, mock_url_for):
        """The order parameter on the request is invalid."""
        request_data = MultiDict(
            {
                "searchtype": "title",
                "query": "foo title",
                "size": 50,  # Valid.
                "order": "foo",  # Invalid
            }
        )
        with self.assertRaises(BadRequest):
            simple.search(request_data)

    @mock.patch("search.controllers.simple.url_for")
    def test_size_is_invalid(self, mock_url_for):
        """The order parameter on the request is invalid."""
        request_data = MultiDict(
            {
                "searchtype": "title",
                "query": "foo title",
                "size": 51,  # Invalid
                "order": "",  # Valid
            }
        )
        with self.assertRaises(BadRequest):
            simple.search(request_data)


class TestClassicAuthorSyntaxIsIntercepted(TestCase):
    """
    The user may have entered an author query using `surname_f` syntax.

    This is an artefact of the classic search system, and not intended to be
    supported. Nevertheless, users have become accustomed to this syntax. We
    therefore rewrite the query using a comma, and show the user a warning
    about the syntax change.
    """

    @mock.patch("search.controllers.simple.SearchSession")
    def test_all_fields_search_contains_classic_syntax(self, mock_index):
        """User has entered a `surname_f` query in an all-fields search."""
        request_data = MultiDict(
            {
                "searchtype": "all",
                "query": "franklin_r",
                "size": 50,
                "order": "",
            }
        )
        mock_index.search.return_value = {"metadata": {}, "results": []}

        data, code, headers = simple.search(request_data)
        self.assertEqual(
            data["query"].value,
            "franklin, r",
            "The query should be rewritten.",
        )
        self.assertTrue(
            data["has_classic_format"],
            "A flag denoting the syntax interception should be set"
            " in the response context, so that a message may be"
            " rendered in the template.",
        )

    @mock.patch("search.controllers.simple.SearchSession")
    def test_author_search_contains_classic_syntax(self, mock_index):
        """User has entered a `surname_f` query in an author search."""
        request_data = MultiDict(
            {
                "searchtype": "author",
                "query": "franklin_r",
                "size": 50,
                "order": "",
            }
        )
        mock_index.search.return_value = {"metadata": {}, "results": []}

        data, code, headers = simple.search(request_data)
        self.assertEqual(
            data["query"].value,
            "franklin, r",
            "The query should be rewritten.",
        )
        self.assertTrue(
            data["has_classic_format"],
            "A flag denoting the syntax interception should be set"
            " in the response context, so that a message may be"
            " rendered in the template.",
        )

    @mock.patch("search.controllers.simple.SearchSession")
    def test_all_fields_search_multiple_classic_syntax(self, mock_index):
        """User has entered a classic query with multiple authors."""
        request_data = MultiDict(
            {
                "searchtype": "all",
                "query": "j franklin_r hawking_s",
                "size": 50,
                "order": "",
            }
        )
        mock_index.search.return_value = {"metadata": {}, "results": []}

        data, code, headers = simple.search(request_data)
        self.assertEqual(
            data["query"].value,
            "j franklin, r; hawking, s",
            "The query should be rewritten.",
        )
        self.assertTrue(
            data["has_classic_format"],
            "A flag denoting the syntax interception should be set"
            " in the response context, so that a message may be"
            " rendered in the template.",
        )

    @mock.patch("search.controllers.simple.SearchSession")
    def test_title_search_contains_classic_syntax(self, mock_index):
        """User has entered a `surname_f` query in a title search."""
        request_data = MultiDict(
            {
                "searchtype": "title",
                "query": "franklin_r",
                "size": 50,
                "order": "",
            }
        )
        mock_index.search.return_value = {"metadata": {}, "results": []}

        data, code, headers = simple.search(request_data)
        self.assertEqual(
            data["query"].value,
            "franklin_r",
            "The query should not be rewritten.",
        )
        self.assertFalse(
            data["has_classic_format"],
            "Flag should not be set, as no rewrite has occurred.",
        )

[((22, 5, 22, 58), 'unittest.mock.patch', 'mock.patch', ({(22, 16, 22, 57): '"""search.controllers.simple.SearchSession"""'}, {}), "('search.controllers.simple.SearchSession')", False, 'from unittest import TestCase, mock\n'), ((43, 5, 43, 58), 'unittest.mock.patch', 'mock.patch', ({(43, 16, 43, 57): '"""search.controllers.simple.SearchSession"""'}, {}), "('search.controllers.simple.SearchSession')", False, 'from unittest import TestCase, mock\n'), ((60, 5, 60, 58), 'unittest.mock.patch', 'mock.patch', ({(60, 16, 60, 57): '"""search.controllers.simple.SearchSession"""'}, {}), "('search.controllers.simple.SearchSession')", False, 'from unittest import TestCase, mock\n'), ((87, 5, 90, 5), 'unittest.mock.patch', 'mock.patch', ({(88, 8, 88, 43): '"""search.controllers.simple.url_for"""', (89, 8, 89, 60): '(lambda *a, **k: f"https://arxiv.org/{k[\'paper_id\']}")'}, {}), '(\'search.controllers.simple.url_for\', lambda *a, **k:\n    f"https://arxiv.org/{k[\'paper_id\']}")', False, 'from unittest import TestCase, mock\n'), ((91, 5, 91, 58), 'unittest.mock.patch', 'mock.patch', ({(91, 16, 91, 57): '"""search.controllers.simple.SearchSession"""'}, {}), "('search.controllers.simple.SearchSession')", False, 'from unittest import TestCase, mock\n'), ((107, 5, 107, 58), 'unittest.mock.patch', 'mock.patch', ({(107, 16, 107, 57): '"""search.controllers.simple.SearchSession"""'}, {}), "('search.controllers.simple.SearchSession')", False, 'from unittest import TestCase, mock\n'), ((120, 5, 120, 58), 'unittest.mock.patch', 'mock.patch', ({(120, 16, 120, 57): '"""search.controllers.simple.SearchSession"""'}, {}), "('search.controllers.simple.SearchSession')", False, 'from unittest import TestCase, mock\n'), ((137, 5, 137, 58), 'unittest.mock.patch', 'mock.patch', ({(137, 16, 137, 57): '"""search.controllers.simple.SearchSession"""'}, {}), "('search.controllers.simple.SearchSession')", False, 'from unittest import TestCase, mock\n'), ((150, 5, 150, 58), 'unittest.mock.patch', 'mock.patch', ({(150, 16, 150, 57): '"""search.controllers.simple.SearchSession"""'}, {}), "('search.controllers.simple.SearchSession')", False, 'from unittest import TestCase, mock\n'), ((173, 5, 173, 58), 'unittest.mock.patch', 'mock.patch', ({(173, 16, 173, 57): '"""search.controllers.simple.SearchSession"""'}, {}), "('search.controllers.simple.SearchSession')", False, 'from unittest import TestCase, mock\n'), ((299, 5, 299, 52), 'unittest.mock.patch', 'mock.patch', ({(299, 16, 299, 51): '"""search.controllers.simple.url_for"""'}, {}), "('search.controllers.simple.url_for')", False, 'from unittest import TestCase, mock\n'), ((313, 5, 313, 52), 'unittest.mock.patch', 'mock.patch', ({(313, 16, 313, 51): '"""search.controllers.simple.url_for"""'}, {}), "('search.controllers.simple.url_for')", False, 'from unittest import TestCase, mock\n'), ((338, 5, 338, 58), 'unittest.mock.patch', 'mock.patch', ({(338, 16, 338, 57): '"""search.controllers.simple.SearchSession"""'}, {}), "('search.controllers.simple.SearchSession')", False, 'from unittest import TestCase, mock\n'), ((364, 5, 364, 58), 'unittest.mock.patch', 'mock.patch', ({(364, 16, 364, 57): '"""search.controllers.simple.SearchSession"""'}, {}), "('search.controllers.simple.SearchSession')", False, 'from unittest import TestCase, mock\n'), ((390, 5, 390, 58), 'unittest.mock.patch', 'mock.patch', ({(390, 16, 390, 57): '"""search.controllers.simple.SearchSession"""'}, {}), "('search.controllers.simple.SearchSession')", False, 'from unittest import TestCase, mock\n'), ((416, 5, 416, 58), 'unittest.mock.patch', 'mock.patch', ({(416, 16, 416, 57): '"""search.controllers.simple.SearchSession"""'}, {}), "('search.controllers.simple.SearchSession')", False, 'from unittest import TestCase, mock\n'), ((94, 23, 94, 57), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(94, 33, 94, 56): "{'query': '1702.00123'}"}, {}), "({'query': '1702.00123'})", False, 'from werkzeug.datastructures import MultiDict\n'), ((95, 39, 95, 66), 'search.controllers.simple.search', 'simple.search', ({(95, 53, 95, 65): 'request_data'}, {}), '(request_data)', False, 'from search.controllers import simple\n'), ((110, 23, 110, 34), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({}, {}), '()', False, 'from werkzeug.datastructures import MultiDict\n'), ((111, 39, 111, 66), 'search.controllers.simple.search', 'simple.search', ({(111, 53, 111, 65): 'request_data'}, {}), '(request_data)', False, 'from search.controllers import simple\n'), ((124, 23, 124, 79), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(124, 33, 124, 78): "{'searchtype': 'title', 'query': 'foo title'}"}, {}), "({'searchtype': 'title', 'query': 'foo title'})", False, 'from werkzeug.datastructures import MultiDict\n'), ((125, 39, 125, 66), 'search.controllers.simple.search', 'simple.search', ({(125, 53, 125, 65): 'request_data'}, {}), '(request_data)', False, 'from search.controllers import simple\n'), ((140, 23, 140, 57), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(140, 33, 140, 56): "{'searchtype': 'title'}"}, {}), "({'searchtype': 'title'})", False, 'from werkzeug.datastructures import MultiDict\n'), ((141, 39, 141, 66), 'search.controllers.simple.search', 'simple.search', ({(141, 53, 141, 65): 'request_data'}, {}), '(request_data)', False, 'from search.controllers import simple\n'), ((159, 23, 159, 79), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(159, 33, 159, 78): "{'searchtype': 'title', 'query': 'foo title'}"}, {}), "({'searchtype': 'title', 'query': 'foo title'})", False, 'from werkzeug.datastructures import MultiDict\n'), ((182, 23, 182, 79), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(182, 33, 182, 78): "{'searchtype': 'title', 'query': 'foo title'}"}, {}), "({'searchtype': 'title', 'query': 'foo title'})", False, 'from werkzeug.datastructures import MultiDict\n'), ((199, 15, 199, 49), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(199, 25, 199, 48): "{'searchtype': 'title'}"}, {}), "({'searchtype': 'title'})", False, 'from werkzeug.datastructures import MultiDict\n'), ((200, 15, 200, 37), 'search.controllers.simple.forms.SimpleSearchForm', 'SimpleSearchForm', ({(200, 32, 200, 36): 'data'}, {}), '(data)', False, 'from search.controllers.simple.forms import SimpleSearchForm\n'), ((205, 15, 205, 72), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(205, 25, 205, 71): "{'query': 'someone monkeyed with the request'}"}, {}), "({'query': 'someone monkeyed with the request'})", False, 'from werkzeug.datastructures import MultiDict\n'), ((206, 15, 206, 37), 'search.controllers.simple.forms.SimpleSearchForm', 'SimpleSearchForm', ({(206, 32, 206, 36): 'data'}, {}), '(data)', False, 'from search.controllers.simple.forms import SimpleSearchForm\n'), ((211, 15, 211, 71), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(211, 25, 211, 70): "{'searchtype': 'title', 'query': 'foo title'}"}, {}), "({'searchtype': 'title', 'query': 'foo title'})", False, 'from werkzeug.datastructures import MultiDict\n'), ((212, 15, 212, 37), 'search.controllers.simple.forms.SimpleSearchForm', 'SimpleSearchForm', ({(212, 32, 212, 36): 'data'}, {}), '(data)', False, 'from search.controllers.simple.forms import SimpleSearchForm\n'), ((221, 15, 221, 71), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(221, 25, 221, 70): "{'searchtype': 'title', 'query': 'foo title'}"}, {}), "({'searchtype': 'title', 'query': 'foo title'})", False, 'from werkzeug.datastructures import MultiDict\n'), ((222, 15, 222, 37), 'search.controllers.simple.forms.SimpleSearchForm', 'SimpleSearchForm', ({(222, 32, 222, 36): 'data'}, {}), '(data)', False, 'from search.controllers.simple.forms import SimpleSearchForm\n'), ((223, 16, 223, 45), 'search.controllers.simple._query_from_form', 'simple._query_from_form', ({(223, 40, 223, 44): 'form'}, {}), '(form)', False, 'from search.controllers import simple\n'), ((230, 15, 236, 9), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(231, 12, 235, 13): "{'searchtype': 'title', 'query': 'foo title', 'order': 'submitted_date'}"}, {}), "({'searchtype': 'title', 'query': 'foo title', 'order':\n    'submitted_date'})", False, 'from werkzeug.datastructures import MultiDict\n'), ((237, 15, 237, 37), 'search.controllers.simple.forms.SimpleSearchForm', 'SimpleSearchForm', ({(237, 32, 237, 36): 'data'}, {}), '(data)', False, 'from search.controllers.simple.forms import SimpleSearchForm\n'), ((238, 16, 238, 45), 'search.controllers.simple._query_from_form', 'simple._query_from_form', ({(238, 40, 238, 44): 'form'}, {}), '(form)', False, 'from search.controllers import simple\n'), ((246, 15, 248, 9), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(247, 12, 247, 74): "{'searchtype': 'title', 'query': 'foo title', 'order': 'None'}"}, {}), "({'searchtype': 'title', 'query': 'foo title', 'order': 'None'})", False, 'from werkzeug.datastructures import MultiDict\n'), ((249, 15, 249, 37), 'search.controllers.simple.forms.SimpleSearchForm', 'SimpleSearchForm', ({(249, 32, 249, 36): 'data'}, {}), '(data)', False, 'from search.controllers.simple.forms import SimpleSearchForm\n'), ((250, 16, 250, 45), 'search.controllers.simple._query_from_form', 'simple._query_from_form', ({(250, 40, 250, 44): 'form'}, {}), '(form)', False, 'from search.controllers import simple\n'), ((258, 15, 258, 72), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(258, 25, 258, 71): "{'searchtype': 'title', 'query': '*foo title'}"}, {}), "({'searchtype': 'title', 'query': '*foo title'})", False, 'from werkzeug.datastructures import MultiDict\n'), ((259, 15, 259, 37), 'search.controllers.simple.forms.SimpleSearchForm', 'SimpleSearchForm', ({(259, 32, 259, 36): 'data'}, {}), '(data)', False, 'from search.controllers.simple.forms import SimpleSearchForm\n'), ((264, 15, 264, 73), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(264, 25, 264, 72): "{'searchtype': 'title', 'query': ' foo title '}"}, {}), "({'searchtype': 'title', 'query': ' foo title '})", False, 'from werkzeug.datastructures import MultiDict\n'), ((265, 15, 265, 37), 'search.controllers.simple.forms.SimpleSearchForm', 'SimpleSearchForm', ({(265, 32, 265, 36): 'data'}, {}), '(data)', False, 'from search.controllers.simple.forms import SimpleSearchForm\n'), ((271, 15, 271, 70), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(271, 25, 271, 69): '{\'searchtype\': \'title\', \'query\': \'"rhubarb\'}'}, {}), '({\'searchtype\': \'title\', \'query\': \'"rhubarb\'})', False, 'from werkzeug.datastructures import MultiDict\n'), ((272, 15, 272, 37), 'search.controllers.simple.forms.SimpleSearchForm', 'SimpleSearchForm', ({(272, 32, 272, 36): 'data'}, {}), '(data)', False, 'from search.controllers.simple.forms import SimpleSearchForm\n'), ((276, 15, 276, 37), 'search.controllers.simple.forms.SimpleSearchForm', 'SimpleSearchForm', ({(276, 32, 276, 36): 'data'}, {}), '(data)', False, 'from search.controllers.simple.forms import SimpleSearchForm\n'), ((280, 15, 280, 37), 'search.controllers.simple.forms.SimpleSearchForm', 'SimpleSearchForm', ({(280, 32, 280, 36): 'data'}, {}), '(data)', False, 'from search.controllers.simple.forms import SimpleSearchForm\n'), ((284, 15, 284, 37), 'search.controllers.simple.forms.SimpleSearchForm', 'SimpleSearchForm', ({(284, 32, 284, 36): 'data'}, {}), '(data)', False, 'from search.controllers.simple.forms import SimpleSearchForm\n'), ((302, 23, 309, 9), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(303, 12, 308, 13): "{'searchtype': 'title', 'query': 'foo title', 'size': 50, 'order': 'foo'}"}, {}), "({'searchtype': 'title', 'query': 'foo title', 'size': 50, 'order':\n    'foo'})", False, 'from werkzeug.datastructures import MultiDict\n'), ((316, 23, 323, 9), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(317, 12, 322, 13): "{'searchtype': 'title', 'query': 'foo title', 'size': 51, 'order': ''}"}, {}), "({'searchtype': 'title', 'query': 'foo title', 'size': 51, 'order':\n    ''})", False, 'from werkzeug.datastructures import MultiDict\n'), ((341, 23, 348, 9), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(342, 12, 347, 13): "{'searchtype': 'all', 'query': 'franklin_r', 'size': 50, 'order': ''}"}, {}), "({'searchtype': 'all', 'query': 'franklin_r', 'size': 50, 'order': ''}\n    )", False, 'from werkzeug.datastructures import MultiDict\n'), ((351, 30, 351, 57), 'search.controllers.simple.search', 'simple.search', ({(351, 44, 351, 56): 'request_data'}, {}), '(request_data)', False, 'from search.controllers import simple\n'), ((367, 23, 374, 9), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(368, 12, 373, 13): "{'searchtype': 'author', 'query': 'franklin_r', 'size': 50, 'order': ''}"}, {}), "({'searchtype': 'author', 'query': 'franklin_r', 'size': 50,\n    'order': ''})", False, 'from werkzeug.datastructures import MultiDict\n'), ((377, 30, 377, 57), 'search.controllers.simple.search', 'simple.search', ({(377, 44, 377, 56): 'request_data'}, {}), '(request_data)', False, 'from search.controllers import simple\n'), ((393, 23, 400, 9), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(394, 12, 399, 13): "{'searchtype': 'all', 'query': 'j franklin_r hawking_s', 'size': 50,\n    'order': ''}"}, {}), "({'searchtype': 'all', 'query': 'j franklin_r hawking_s', 'size': \n    50, 'order': ''})", False, 'from werkzeug.datastructures import MultiDict\n'), ((403, 30, 403, 57), 'search.controllers.simple.search', 'simple.search', ({(403, 44, 403, 56): 'request_data'}, {}), '(request_data)', False, 'from search.controllers import simple\n'), ((419, 23, 426, 9), 'werkzeug.datastructures.MultiDict', 'MultiDict', ({(420, 12, 425, 13): "{'searchtype': 'title', 'query': 'franklin_r', 'size': 50, 'order': ''}"}, {}), "({'searchtype': 'title', 'query': 'franklin_r', 'size': 50,\n    'order': ''})", False, 'from werkzeug.datastructures import MultiDict\n'), ((429, 30, 429, 57), 'search.controllers.simple.search', 'simple.search', ({(429, 44, 429, 56): 'request_data'}, {}), '(request_data)', False, 'from search.controllers import simple\n'), ((27, 18, 27, 40), 'search.services.index.QueryError', 'QueryError', ({(27, 29, 27, 39): '"""What now"""'}, {}), "('What now')", False, 'from search.services.index import IndexConnectionError, QueryError, DocumentNotFound\n'), ((49, 43, 49, 79), 'search.controllers.simple.retrieve_document', 'simple.retrieve_document', ({(49, 68, 49, 78): '"""124.5678"""'}, {}), "('124.5678')", False, 'from search.controllers import simple\n'), ((65, 18, 65, 46), 'search.services.index.DocumentNotFound', 'DocumentNotFound', ({(65, 35, 65, 45): '"""What now"""'}, {}), "('What now')", False, 'from search.services.index import IndexConnectionError, QueryError, DocumentNotFound\n'), ((155, 18, 155, 50), 'search.services.index.IndexConnectionError', 'IndexConnectionError', ({(155, 39, 155, 49): '"""What now"""'}, {}), "('What now')", False, 'from search.services.index import IndexConnectionError, QueryError, DocumentNotFound\n'), ((161, 22, 161, 49), 'search.controllers.simple.search', 'simple.search', ({(161, 36, 161, 48): 'request_data'}, {}), '(request_data)', False, 'from search.controllers import simple\n'), ((178, 18, 178, 40), 'search.services.index.QueryError', 'QueryError', ({(178, 29, 178, 39): '"""What now"""'}, {}), "('What now')", False, 'from search.services.index import IndexConnectionError, QueryError, DocumentNotFound\n'), ((311, 12, 311, 39), 'search.controllers.simple.search', 'simple.search', ({(311, 26, 311, 38): 'request_data'}, {}), '(request_data)', False, 'from search.controllers import simple\n'), ((325, 12, 325, 39), 'search.controllers.simple.search', 'simple.search', ({(325, 26, 325, 38): 'request_data'}, {}), '(request_data)', False, 'from search.controllers import simple\n'), ((33, 47, 33, 74), 'search.controllers.simple.retrieve_document', 'simple.retrieve_document', ({(33, 72, 33, 73): '1'}, {}), '(1)', False, 'from search.controllers import simple\n'), ((71, 47, 71, 74), 'search.controllers.simple.retrieve_document', 'simple.retrieve_document', ({(71, 72, 71, 73): '1'}, {}), '(1)', False, 'from search.controllers import simple\n'), ((185, 47, 185, 74), 'search.controllers.simple.search', 'simple.search', ({(185, 61, 185, 73): 'request_data'}, {}), '(request_data)', False, 'from search.controllers import simple\n')]