mirror of
https://github.com/searxng/searxng
synced 2024-01-01 19:24:07 +01:00
Merge branch 'searxng:master' into elasticsearch-custom-query
This commit is contained in:
commit
82d1544a6b
341 changed files with 29669 additions and 12534 deletions
|
|
@ -3,9 +3,14 @@
|
|||
|
||||
from collections import defaultdict
|
||||
import mock
|
||||
|
||||
from searx.engines import xpath
|
||||
from searx import logger
|
||||
|
||||
from tests import SearxTestCase
|
||||
|
||||
logger = logger.getChild('engines')
|
||||
|
||||
|
||||
class TestXpathEngine(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
html = """
|
||||
|
|
@ -23,6 +28,9 @@ class TestXpathEngine(SearxTestCase): # pylint: disable=missing-class-docstring
|
|||
</div>
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
xpath.logger = logger.getChild('test_xpath')
|
||||
|
||||
def test_request(self):
|
||||
xpath.search_url = 'https://url.com/{query}'
|
||||
xpath.categories = []
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
Test:
|
||||
"**********"
|
||||
xxx
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ general:
|
|||
search:
|
||||
safe_search: 0
|
||||
autocomplete: ""
|
||||
favicon_resolver: ""
|
||||
default_lang: ""
|
||||
ban_time_on_fail: 5
|
||||
max_ban_time_on_fail: 120
|
||||
|
|
|
|||
|
|
@ -2,15 +2,16 @@
|
|||
# pylint: disable=missing-module-docstring
|
||||
|
||||
from mock import Mock
|
||||
from parameterized import parameterized
|
||||
|
||||
from searx.answerers import answerers
|
||||
from tests import SearxTestCase
|
||||
|
||||
|
||||
class AnswererTest(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
def test_unicode_input(self):
|
||||
@parameterized.expand(answerers)
|
||||
def test_unicode_input(self, answerer):
|
||||
query = Mock()
|
||||
unicode_payload = 'árvíztűrő tükörfúrógép'
|
||||
for answerer in answerers:
|
||||
query.query = '{} {}'.format(answerer.keywords[0], unicode_payload)
|
||||
self.assertTrue(isinstance(answerer.answer(query), list))
|
||||
query.query = '{} {}'.format(answerer.keywords[0], unicode_payload)
|
||||
self.assertIsInstance(answerer.answer(query), list)
|
||||
|
|
|
|||
44
tests/unit/test_engine_mariadb_server.py
Normal file
44
tests/unit/test_engine_mariadb_server.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# pylint: disable=missing-module-docstring
|
||||
|
||||
from unittest.mock import MagicMock, Mock
|
||||
from searx.engines import load_engines, mariadb_server
|
||||
from tests import SearxTestCase
|
||||
|
||||
|
||||
class MariadbServerTests(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
def setUp(self):
|
||||
load_engines(
|
||||
[
|
||||
{
|
||||
'name': 'mariadb server',
|
||||
'engine': 'mariadb_server',
|
||||
'shortcut': 'mdb',
|
||||
'timeout': 9.0,
|
||||
'disabled': True,
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
load_engines([])
|
||||
|
||||
def test_init_no_query_str_raises(self):
|
||||
self.assertRaises(ValueError, lambda: mariadb_server.init({}))
|
||||
|
||||
def test_init_non_select_raises(self):
|
||||
self.assertRaises(ValueError, lambda: mariadb_server.init({'query_str': 'foobar'}))
|
||||
|
||||
def test_search_returns_results(self):
|
||||
test_string = 'FOOBAR'
|
||||
cursor_mock = MagicMock()
|
||||
with cursor_mock as setup: # pylint: disable=not-context-manager
|
||||
setup.__iter__ = Mock(return_value=iter([{test_string, 1}]))
|
||||
setup.description = [[test_string]]
|
||||
conn_mock = Mock()
|
||||
conn_mock.cursor.return_value = cursor_mock
|
||||
mariadb_server._connection = conn_mock # pylint: disable=protected-access
|
||||
results = mariadb_server.search(test_string, {'pageno': 1})
|
||||
self.assertEqual(1, len(results))
|
||||
self.assertIn(test_string, results[0])
|
||||
self.assertEqual(mariadb_server.result_template, results[0]['template'])
|
||||
94
tests/unit/test_engine_tineye.py
Normal file
94
tests/unit/test_engine_tineye.py
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# pylint: disable=missing-module-docstring
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from unittest.mock import Mock
|
||||
from requests import HTTPError
|
||||
from parameterized import parameterized
|
||||
from searx.engines import load_engines, tineye
|
||||
from tests import SearxTestCase
|
||||
|
||||
|
||||
class TinEyeTests(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
|
||||
def setUp(self):
|
||||
load_engines([{'name': 'tineye', 'engine': 'tineye', 'shortcut': 'tin', 'timeout': 9.0, 'disabled': True}])
|
||||
|
||||
def tearDown(self):
|
||||
load_engines([])
|
||||
|
||||
def test_status_code_raises(self):
|
||||
response = Mock()
|
||||
response.status_code = 401
|
||||
response.raise_for_status.side_effect = HTTPError()
|
||||
self.assertRaises(HTTPError, lambda: tineye.response(response))
|
||||
|
||||
@parameterized.expand([(400), (422)])
|
||||
def test_returns_empty_list(self, status_code):
|
||||
response = Mock()
|
||||
response.json.return_value = {}
|
||||
response.status_code = status_code
|
||||
response.raise_for_status.side_effect = HTTPError()
|
||||
results = tineye.response(response)
|
||||
self.assertEqual(0, len(results))
|
||||
|
||||
def test_logs_format_for_422(self):
|
||||
response = Mock()
|
||||
response.json.return_value = {"suggestions": {"key": "Invalid image URL"}}
|
||||
response.status_code = 422
|
||||
response.raise_for_status.side_effect = HTTPError()
|
||||
|
||||
with self.assertLogs(tineye.logger) as assert_logs_context:
|
||||
tineye.response(response)
|
||||
self.assertIn(tineye.FORMAT_NOT_SUPPORTED, ','.join(assert_logs_context.output))
|
||||
|
||||
def test_logs_signature_for_422(self):
|
||||
response = Mock()
|
||||
response.json.return_value = {"suggestions": {"key": "NO_SIGNATURE_ERROR"}}
|
||||
response.status_code = 422
|
||||
response.raise_for_status.side_effect = HTTPError()
|
||||
|
||||
with self.assertLogs(tineye.logger) as assert_logs_context:
|
||||
tineye.response(response)
|
||||
self.assertIn(tineye.NO_SIGNATURE_ERROR, ','.join(assert_logs_context.output))
|
||||
|
||||
def test_logs_download_for_422(self):
|
||||
response = Mock()
|
||||
response.json.return_value = {"suggestions": {"key": "Download Error"}}
|
||||
response.status_code = 422
|
||||
response.raise_for_status.side_effect = HTTPError()
|
||||
|
||||
with self.assertLogs(tineye.logger) as assert_logs_context:
|
||||
tineye.response(response)
|
||||
self.assertIn(tineye.DOWNLOAD_ERROR, ','.join(assert_logs_context.output))
|
||||
|
||||
def test_logs_description_for_400(self):
|
||||
description = 'There was a problem with that request. Error ID: ad5fc955-a934-43c1-8187-f9a61d301645'
|
||||
response = Mock()
|
||||
response.json.return_value = {"suggestions": {"description": [description], "title": "Oops! We're sorry!"}}
|
||||
response.status_code = 400
|
||||
response.raise_for_status.side_effect = HTTPError()
|
||||
|
||||
with self.assertLogs(tineye.logger) as assert_logs_context:
|
||||
tineye.response(response)
|
||||
self.assertIn(description, ','.join(assert_logs_context.output))
|
||||
|
||||
def test_crawl_date_parses(self):
|
||||
date_str = '2020-05-25'
|
||||
date = datetime.strptime(date_str, '%Y-%m-%d')
|
||||
response = Mock()
|
||||
response.json.return_value = {
|
||||
'matches': [
|
||||
{
|
||||
'backlinks': [
|
||||
{
|
||||
'crawl_date': date_str,
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
response.status_code = 200
|
||||
results = tineye.response(response)
|
||||
self.assertEqual(date, results[0]['publishedDate'])
|
||||
|
|
@ -10,6 +10,7 @@ class TestEnginesInit(SearxTestCase): # pylint: disable=missing-class-docstring
|
|||
def tearDownClass(cls):
|
||||
settings['outgoing']['using_tor_proxy'] = False
|
||||
settings['outgoing']['extra_proxy_timeout'] = 0
|
||||
engines.load_engines([])
|
||||
|
||||
def test_initialize_engines_default(self):
|
||||
engine_list = [
|
||||
|
|
|
|||
|
|
@ -1,42 +1,36 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# pylint: disable=missing-module-docstring
|
||||
|
||||
from parameterized import parameterized
|
||||
from tests import SearxTestCase
|
||||
import searx.exceptions
|
||||
from searx import get_setting
|
||||
|
||||
|
||||
class TestExceptions(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
def test_default_suspend_time(self):
|
||||
with self.assertRaises(searx.exceptions.SearxEngineAccessDeniedException) as e:
|
||||
raise searx.exceptions.SearxEngineAccessDeniedException()
|
||||
@parameterized.expand(
|
||||
[
|
||||
searx.exceptions.SearxEngineAccessDeniedException,
|
||||
searx.exceptions.SearxEngineCaptchaException,
|
||||
searx.exceptions.SearxEngineTooManyRequestsException,
|
||||
]
|
||||
)
|
||||
def test_default_suspend_time(self, exception):
|
||||
with self.assertRaises(exception) as e:
|
||||
raise exception()
|
||||
self.assertEqual(
|
||||
e.exception.suspended_time,
|
||||
get_setting(searx.exceptions.SearxEngineAccessDeniedException.SUSPEND_TIME_SETTING),
|
||||
get_setting(exception.SUSPEND_TIME_SETTING),
|
||||
)
|
||||
|
||||
with self.assertRaises(searx.exceptions.SearxEngineCaptchaException) as e:
|
||||
raise searx.exceptions.SearxEngineCaptchaException()
|
||||
self.assertEqual(
|
||||
e.exception.suspended_time, get_setting(searx.exceptions.SearxEngineCaptchaException.SUSPEND_TIME_SETTING)
|
||||
)
|
||||
|
||||
with self.assertRaises(searx.exceptions.SearxEngineTooManyRequestsException) as e:
|
||||
raise searx.exceptions.SearxEngineTooManyRequestsException()
|
||||
self.assertEqual(
|
||||
e.exception.suspended_time,
|
||||
get_setting(searx.exceptions.SearxEngineTooManyRequestsException.SUSPEND_TIME_SETTING),
|
||||
)
|
||||
|
||||
def test_custom_suspend_time(self):
|
||||
with self.assertRaises(searx.exceptions.SearxEngineAccessDeniedException) as e:
|
||||
raise searx.exceptions.SearxEngineAccessDeniedException(suspended_time=1337)
|
||||
@parameterized.expand(
|
||||
[
|
||||
searx.exceptions.SearxEngineAccessDeniedException,
|
||||
searx.exceptions.SearxEngineCaptchaException,
|
||||
searx.exceptions.SearxEngineTooManyRequestsException,
|
||||
]
|
||||
)
|
||||
def test_custom_suspend_time(self, exception):
|
||||
with self.assertRaises(exception) as e:
|
||||
raise exception(suspended_time=1337)
|
||||
self.assertEqual(e.exception.suspended_time, 1337)
|
||||
|
||||
with self.assertRaises(searx.exceptions.SearxEngineCaptchaException) as e:
|
||||
raise searx.exceptions.SearxEngineCaptchaException(suspended_time=1409)
|
||||
self.assertEqual(e.exception.suspended_time, 1409)
|
||||
|
||||
with self.assertRaises(searx.exceptions.SearxEngineTooManyRequestsException) as e:
|
||||
raise searx.exceptions.SearxEngineTooManyRequestsException(suspended_time=1543)
|
||||
self.assertEqual(e.exception.suspended_time, 1543)
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ class TestGetBangDefinitionAndAutocomplete(SearxTestCase): # pylint:disable=mis
|
|||
|
||||
def test_partial(self):
|
||||
bang_definition, new_autocomplete = get_bang_definition_and_autocomplete('examp', external_bangs_db=TEST_DB)
|
||||
self.assertEqual(bang_definition, None)
|
||||
self.assertIsNone(bang_definition)
|
||||
self.assertEqual(new_autocomplete, ['example'])
|
||||
|
||||
def test_partial2(self):
|
||||
|
|
@ -100,7 +100,7 @@ class TestGetBangDefinitionAndAutocomplete(SearxTestCase): # pylint:disable=mis
|
|||
|
||||
def test_error(self):
|
||||
bang_definition, new_autocomplete = get_bang_definition_and_autocomplete('error', external_bangs_db=TEST_DB)
|
||||
self.assertEqual(bang_definition, None)
|
||||
self.assertIsNone(bang_definition)
|
||||
self.assertEqual(new_autocomplete, [])
|
||||
|
||||
def test_actual_data(self):
|
||||
|
|
@ -112,7 +112,7 @@ class TestGetBangDefinitionAndAutocomplete(SearxTestCase): # pylint:disable=mis
|
|||
class TestExternalBangJson(SearxTestCase): # pylint:disable=missing-class-docstring
|
||||
def test_no_external_bang_query(self):
|
||||
result = get_bang_url(SearchQuery('test', engineref_list=[EngineRef('wikipedia', 'general')]))
|
||||
self.assertEqual(result, None)
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_get_bang_url(self):
|
||||
url = get_bang_url(SearchQuery('test', engineref_list=[], external_bang='example'), external_bangs_db=TEST_DB)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
# pylint: disable=missing-module-docstring
|
||||
"""Test some code from module :py:obj:`searx.locales`"""
|
||||
|
||||
from __future__ import annotations
|
||||
from parameterized import parameterized
|
||||
from searx import locales
|
||||
from searx.sxng_locales import sxng_locales
|
||||
from tests import SearxTestCase
|
||||
|
|
@ -13,98 +15,102 @@ class TestLocales(SearxTestCase):
|
|||
- :py:obj:`searx.locales.match_locale`
|
||||
"""
|
||||
|
||||
def test_match_locale(self):
|
||||
|
||||
locale_tag_list = [x[0] for x in sxng_locales]
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.locale_tag_list = [x[0] for x in sxng_locales]
|
||||
|
||||
@parameterized.expand(
|
||||
[
|
||||
'de',
|
||||
'fr',
|
||||
'zh',
|
||||
]
|
||||
)
|
||||
def test_locale_languages(self, locale: str):
|
||||
# Test SearXNG search languages
|
||||
self.assertEqual(locales.match_locale(locale, self.locale_tag_list), locale)
|
||||
|
||||
self.assertEqual(locales.match_locale('de', locale_tag_list), 'de')
|
||||
self.assertEqual(locales.match_locale('fr', locale_tag_list), 'fr')
|
||||
self.assertEqual(locales.match_locale('zh', locale_tag_list), 'zh')
|
||||
|
||||
@parameterized.expand(
|
||||
[
|
||||
('de-at', 'de-AT'),
|
||||
('de-de', 'de-DE'),
|
||||
('en-UK', 'en-GB'),
|
||||
('fr-be', 'fr-BE'),
|
||||
('fr-ca', 'fr-CA'),
|
||||
('fr-ch', 'fr-CH'),
|
||||
('zh-cn', 'zh-CN'),
|
||||
('zh-tw', 'zh-TW'),
|
||||
('zh-hk', 'zh-HK'),
|
||||
]
|
||||
)
|
||||
def test_match_region(self, locale: str, expected_locale: str):
|
||||
# Test SearXNG search regions
|
||||
self.assertEqual(locales.match_locale(locale, self.locale_tag_list), expected_locale)
|
||||
|
||||
self.assertEqual(locales.match_locale('ca-es', locale_tag_list), 'ca-ES')
|
||||
self.assertEqual(locales.match_locale('de-at', locale_tag_list), 'de-AT')
|
||||
self.assertEqual(locales.match_locale('de-de', locale_tag_list), 'de-DE')
|
||||
self.assertEqual(locales.match_locale('en-UK', locale_tag_list), 'en-GB')
|
||||
self.assertEqual(locales.match_locale('fr-be', locale_tag_list), 'fr-BE')
|
||||
self.assertEqual(locales.match_locale('fr-be', locale_tag_list), 'fr-BE')
|
||||
self.assertEqual(locales.match_locale('fr-ca', locale_tag_list), 'fr-CA')
|
||||
self.assertEqual(locales.match_locale('fr-ch', locale_tag_list), 'fr-CH')
|
||||
self.assertEqual(locales.match_locale('zh-cn', locale_tag_list), 'zh-CN')
|
||||
self.assertEqual(locales.match_locale('zh-tw', locale_tag_list), 'zh-TW')
|
||||
self.assertEqual(locales.match_locale('zh-hk', locale_tag_list), 'zh-HK')
|
||||
|
||||
@parameterized.expand(
|
||||
[
|
||||
('zh-hans', 'zh-CN'),
|
||||
('zh-hans-cn', 'zh-CN'),
|
||||
('zh-hant', 'zh-TW'),
|
||||
('zh-hant-tw', 'zh-TW'),
|
||||
]
|
||||
)
|
||||
def test_match_lang_script_code(self, locale: str, expected_locale: str):
|
||||
# Test language script code
|
||||
self.assertEqual(locales.match_locale(locale, self.locale_tag_list), expected_locale)
|
||||
|
||||
self.assertEqual(locales.match_locale('zh-hans', locale_tag_list), 'zh-CN')
|
||||
self.assertEqual(locales.match_locale('zh-hans-cn', locale_tag_list), 'zh-CN')
|
||||
self.assertEqual(locales.match_locale('zh-hant', locale_tag_list), 'zh-TW')
|
||||
self.assertEqual(locales.match_locale('zh-hant-tw', locale_tag_list), 'zh-TW')
|
||||
|
||||
# Test individual locale lists
|
||||
def test_locale_de(self):
|
||||
self.assertEqual(locales.match_locale('de', ['de-CH', 'de-DE']), 'de-DE')
|
||||
self.assertEqual(locales.match_locale('de', ['de-CH', 'de-DE']), 'de-DE')
|
||||
|
||||
def test_locale_es(self):
|
||||
self.assertEqual(locales.match_locale('es', [], fallback='fallback'), 'fallback')
|
||||
|
||||
self.assertEqual(locales.match_locale('de', ['de-CH', 'de-DE']), 'de-DE')
|
||||
self.assertEqual(locales.match_locale('de', ['de-CH', 'de-DE']), 'de-DE')
|
||||
self.assertEqual(locales.match_locale('es', ['ES']), 'ES')
|
||||
self.assertEqual(locales.match_locale('es', ['es-AR', 'es-ES', 'es-MX']), 'es-ES')
|
||||
self.assertEqual(locales.match_locale('es-AR', ['es-AR', 'es-ES', 'es-MX']), 'es-AR')
|
||||
self.assertEqual(locales.match_locale('es-CO', ['es-AR', 'es-ES']), 'es-ES')
|
||||
self.assertEqual(locales.match_locale('es-CO', ['es-AR']), 'es-AR')
|
||||
|
||||
# Tests from the commit message of 9ae409a05a
|
||||
@parameterized.expand(
|
||||
[
|
||||
('zh-TW', ['zh-HK'], 'zh-HK'), # A user selects region 'zh-TW' which should end in zh_HK.
|
||||
# hint: CN is 'Hans' and HK ('Hant') fits better to TW ('Hant')
|
||||
('zh', ['zh-CN'], 'zh-CN'), # A user selects only the language 'zh' which should end in CN
|
||||
('fr', ['fr-CA'], 'fr-CA'), # A user selects only the language 'fr' which should end in fr_CA
|
||||
('nl', ['nl-BE'], 'nl-BE'), # A user selects only the language 'fr' which should end in fr_CA
|
||||
# Territory tests
|
||||
('en', ['en-GB'], 'en-GB'), # A user selects only a language
|
||||
(
|
||||
'fr',
|
||||
['fr-FR', 'fr-CA'],
|
||||
'fr-FR',
|
||||
), # the engine supports fr_FR and fr_CA since no territory is given, fr_FR takes priority
|
||||
]
|
||||
)
|
||||
def test_locale_optimized_selected(self, locale: str, locale_list: list[str], expected_locale: str):
|
||||
"""
|
||||
Tests from the commit message of 9ae409a05a
|
||||
|
||||
# Assumption:
|
||||
# A. When a user selects a language the results should be optimized according to
|
||||
# the selected language.
|
||||
#
|
||||
# B. When user selects a language and a territory the results should be
|
||||
# optimized with first priority on territory and second on language.
|
||||
Assumption:
|
||||
A. When a user selects a language the results should be optimized according to
|
||||
the selected language.
|
||||
"""
|
||||
self.assertEqual(locales.match_locale(locale, locale_list), expected_locale)
|
||||
|
||||
# Assume we have an engine that supports the following locales:
|
||||
locale_tag_list = ['zh-CN', 'zh-HK', 'nl-BE', 'fr-CA']
|
||||
@parameterized.expand(
|
||||
[
|
||||
('fr-BE', ['fr-FR', 'fr-CA', 'nl-BE'], 'nl-BE'), # A user selects region 'fr-BE' which should end in nl-BE
|
||||
('fr', ['fr-BE', 'fr-CH'], 'fr-BE'), # A user selects fr with 2 locales,
|
||||
# the get_engine_locale selects the locale by looking at the "population
|
||||
# percent" and this percentage has an higher amount in BE (68.%)
|
||||
# compared to CH (21%)
|
||||
]
|
||||
)
|
||||
def test_locale_optimized_territory(self, locale: str, locale_list: list[str], expected_locale: str):
|
||||
"""
|
||||
Tests from the commit message of 9ae409a05a
|
||||
|
||||
# Examples (Assumption A.)
|
||||
# ------------------------
|
||||
|
||||
# A user selects region 'zh-TW' which should end in zh_HK.
|
||||
# hint: CN is 'Hans' and HK ('Hant') fits better to TW ('Hant')
|
||||
self.assertEqual(locales.match_locale('zh-TW', locale_tag_list), 'zh-HK')
|
||||
|
||||
# A user selects only the language 'zh' which should end in CN
|
||||
self.assertEqual(locales.match_locale('zh', locale_tag_list), 'zh-CN')
|
||||
|
||||
# A user selects only the language 'fr' which should end in fr_CA
|
||||
self.assertEqual(locales.match_locale('fr', locale_tag_list), 'fr-CA')
|
||||
|
||||
# The difference in priority on the territory is best shown with a
|
||||
# engine that supports the following locales:
|
||||
locale_tag_list = ['fr-FR', 'fr-CA', 'en-GB', 'nl-BE']
|
||||
|
||||
# A user selects only a language
|
||||
self.assertEqual(locales.match_locale('en', locale_tag_list), 'en-GB')
|
||||
|
||||
# hint: the engine supports fr_FR and fr_CA since no territory is given,
|
||||
# fr_FR takes priority ..
|
||||
self.assertEqual(locales.match_locale('fr', locale_tag_list), 'fr-FR')
|
||||
|
||||
# Examples (Assumption B.)
|
||||
# ------------------------
|
||||
|
||||
# A user selects region 'fr-BE' which should end in nl-BE
|
||||
self.assertEqual(locales.match_locale('fr-BE', locale_tag_list), 'nl-BE')
|
||||
|
||||
# If the user selects a language and there are two locales like the
|
||||
# following:
|
||||
|
||||
locale_tag_list = ['fr-BE', 'fr-CH']
|
||||
|
||||
# The get_engine_locale selects the locale by looking at the "population
|
||||
# percent" and this percentage has an higher amount in BE (68.%)
|
||||
# compared to CH (21%)
|
||||
|
||||
self.assertEqual(locales.match_locale('fr', locale_tag_list), 'fr-BE')
|
||||
B. When user selects a language and a territory the results should be
|
||||
optimized with first priority on territory and second on language.
|
||||
"""
|
||||
self.assertEqual(locales.match_locale(locale, locale_list), expected_locale)
|
||||
|
|
|
|||
103
tests/unit/test_plugin_calculator.py
Normal file
103
tests/unit/test_plugin_calculator.py
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# pylint: disable=missing-module-docstring
|
||||
|
||||
import flask
|
||||
from parameterized.parameterized import parameterized
|
||||
from searx import plugins
|
||||
from searx import preferences
|
||||
from tests import SearxTestCase
|
||||
from .test_utils import random_string
|
||||
|
||||
from .test_plugins import get_search_mock
|
||||
|
||||
|
||||
class PluginCalculator(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
|
||||
def setUp(self):
|
||||
from searx import webapp # pylint: disable=import-outside-toplevel
|
||||
|
||||
self.webapp = webapp
|
||||
self.store = plugins.PluginStore()
|
||||
plugin = plugins.load_and_initialize_plugin('searx.plugins.calculator', False, (None, {}))
|
||||
self.store.register(plugin)
|
||||
self.preferences = preferences.Preferences(["simple"], ["general"], {}, self.store)
|
||||
self.preferences.parse_dict({"locale": "en"})
|
||||
|
||||
def test_plugin_store_init(self):
|
||||
self.assertEqual(1, len(self.store.plugins))
|
||||
|
||||
def test_single_page_number_true(self):
|
||||
with self.webapp.app.test_request_context():
|
||||
flask.request.preferences = self.preferences
|
||||
search = get_search_mock(query=random_string(10), pageno=2)
|
||||
result = self.store.call(self.store.plugins, 'post_search', flask.request, search)
|
||||
|
||||
self.assertTrue(result)
|
||||
self.assertNotIn('calculate', search.result_container.answers)
|
||||
|
||||
def test_long_query_true(self):
|
||||
with self.webapp.app.test_request_context():
|
||||
flask.request.preferences = self.preferences
|
||||
search = get_search_mock(query=random_string(101), pageno=1)
|
||||
result = self.store.call(self.store.plugins, 'post_search', flask.request, search)
|
||||
|
||||
self.assertTrue(result)
|
||||
self.assertNotIn('calculate', search.result_container.answers)
|
||||
|
||||
def test_alpha_true(self):
|
||||
with self.webapp.app.test_request_context():
|
||||
flask.request.preferences = self.preferences
|
||||
search = get_search_mock(query=random_string(10), pageno=1)
|
||||
result = self.store.call(self.store.plugins, 'post_search', flask.request, search)
|
||||
|
||||
self.assertTrue(result)
|
||||
self.assertNotIn('calculate', search.result_container.answers)
|
||||
|
||||
@parameterized.expand(
|
||||
[
|
||||
("1+1", "2", "en"),
|
||||
("1-1", "0", "en"),
|
||||
("1*1", "1", "en"),
|
||||
("1/1", "1", "en"),
|
||||
("1**1", "1", "en"),
|
||||
("1^1", "1", "en"),
|
||||
("1,000.0+1,000.0", "2,000", "en"),
|
||||
("1.0+1.0", "2", "en"),
|
||||
("1.0-1.0", "0", "en"),
|
||||
("1.0*1.0", "1", "en"),
|
||||
("1.0/1.0", "1", "en"),
|
||||
("1.0**1.0", "1", "en"),
|
||||
("1.0^1.0", "1", "en"),
|
||||
("1.000,0+1.000,0", "2.000", "de"),
|
||||
("1,0+1,0", "2", "de"),
|
||||
("1,0-1,0", "0", "de"),
|
||||
("1,0*1,0", "1", "de"),
|
||||
("1,0/1,0", "1", "de"),
|
||||
("1,0**1,0", "1", "de"),
|
||||
("1,0^1,0", "1", "de"),
|
||||
]
|
||||
)
|
||||
def test_localized_query(self, operation: str, contains_result: str, lang: str):
|
||||
with self.webapp.app.test_request_context():
|
||||
self.preferences.parse_dict({"locale": lang})
|
||||
flask.request.preferences = self.preferences
|
||||
search = get_search_mock(query=operation, lang=lang, pageno=1)
|
||||
result = self.store.call(self.store.plugins, 'post_search', flask.request, search)
|
||||
|
||||
self.assertTrue(result)
|
||||
self.assertIn('calculate', search.result_container.answers)
|
||||
self.assertIn(contains_result, search.result_container.answers['calculate']['answer'])
|
||||
|
||||
@parameterized.expand(
|
||||
[
|
||||
"1/0",
|
||||
]
|
||||
)
|
||||
def test_invalid_operations(self, operation):
|
||||
with self.webapp.app.test_request_context():
|
||||
flask.request.preferences = self.preferences
|
||||
search = get_search_mock(query=operation, pageno=1)
|
||||
result = self.store.call(self.store.plugins, 'post_search', flask.request, search)
|
||||
|
||||
self.assertTrue(result)
|
||||
self.assertNotIn('calculate', search.result_container.answers)
|
||||
51
tests/unit/test_plugin_hash.py
Normal file
51
tests/unit/test_plugin_hash.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# pylint: disable=missing-module-docstring, invalid-name
|
||||
|
||||
from mock import Mock
|
||||
from parameterized.parameterized import parameterized
|
||||
from searx import plugins
|
||||
from tests import SearxTestCase
|
||||
|
||||
from .test_plugins import get_search_mock
|
||||
|
||||
|
||||
class PluginHashTest(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
def setUp(self):
|
||||
self.store = plugins.PluginStore()
|
||||
plugin = plugins.load_and_initialize_plugin('searx.plugins.hash_plugin', False, (None, {}))
|
||||
self.store.register(plugin)
|
||||
|
||||
def test_plugin_store_init(self):
|
||||
self.assertEqual(1, len(self.store.plugins))
|
||||
|
||||
@parameterized.expand(
|
||||
[
|
||||
('md5 test', 'md5 hash digest: 098f6bcd4621d373cade4e832627b4f6'),
|
||||
('sha1 test', 'sha1 hash digest: a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'),
|
||||
('sha224 test', 'sha224 hash digest: 90a3ed9e32b2aaf4c61c410eb925426119e1a9dc53d4286ade99a809'),
|
||||
('sha256 test', 'sha256 hash digest: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'),
|
||||
(
|
||||
'sha384 test',
|
||||
'sha384 hash digest: 768412320f7b0aa5812fce428dc4706b3c'
|
||||
'ae50e02a64caa16a782249bfe8efc4b7ef1ccb126255d196047dfedf1'
|
||||
'7a0a9',
|
||||
),
|
||||
(
|
||||
'sha512 test',
|
||||
'sha512 hash digest: ee26b0dd4af7e749aa1a8ee3c10ae9923f6'
|
||||
'18980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5'
|
||||
'fa9ad8e6f57f50028a8ff',
|
||||
),
|
||||
]
|
||||
)
|
||||
def test_hash_digest_new(self, query: str, hash_str: str):
|
||||
request = Mock(remote_addr='127.0.0.1')
|
||||
search = get_search_mock(query=query, pageno=1)
|
||||
self.store.call(self.store.plugins, 'post_search', request, search)
|
||||
self.assertIn(hash_str, search.result_container.answers['hash']['answer'])
|
||||
|
||||
def test_md5_bytes_no_answer(self):
|
||||
request = Mock(remote_addr='127.0.0.1')
|
||||
search = get_search_mock(query=b'md5 test', pageno=2)
|
||||
self.store.call(self.store.plugins, 'post_search', request, search)
|
||||
self.assertNotIn('hash', search.result_container.answers)
|
||||
65
tests/unit/test_plugin_self_info.py
Normal file
65
tests/unit/test_plugin_self_info.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# pylint: disable=missing-module-docstring, invalid-name
|
||||
|
||||
from mock import Mock
|
||||
from parameterized.parameterized import parameterized
|
||||
|
||||
from searx import (
|
||||
plugins,
|
||||
limiter,
|
||||
botdetection,
|
||||
)
|
||||
from tests import SearxTestCase
|
||||
from .test_plugins import get_search_mock
|
||||
|
||||
|
||||
class PluginIPSelfInfo(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
def setUp(self):
|
||||
plugin = plugins.load_and_initialize_plugin('searx.plugins.self_info', False, (None, {}))
|
||||
self.store = plugins.PluginStore()
|
||||
self.store.register(plugin)
|
||||
cfg = limiter.get_cfg()
|
||||
botdetection.init(cfg, None)
|
||||
|
||||
def test_plugin_store_init(self):
|
||||
self.assertEqual(1, len(self.store.plugins))
|
||||
|
||||
def test_ip_in_answer(self):
|
||||
request = Mock()
|
||||
request.remote_addr = '127.0.0.1'
|
||||
request.headers = {'X-Forwarded-For': '1.2.3.4, 127.0.0.1', 'X-Real-IP': '127.0.0.1'}
|
||||
search = get_search_mock(query='ip', pageno=1)
|
||||
self.store.call(self.store.plugins, 'post_search', request, search)
|
||||
self.assertIn('127.0.0.1', search.result_container.answers["ip"]["answer"])
|
||||
|
||||
def test_ip_not_in_answer(self):
|
||||
request = Mock()
|
||||
request.remote_addr = '127.0.0.1'
|
||||
request.headers = {'X-Forwarded-For': '1.2.3.4, 127.0.0.1', 'X-Real-IP': '127.0.0.1'}
|
||||
search = get_search_mock(query='ip', pageno=2)
|
||||
self.store.call(self.store.plugins, 'post_search', request, search)
|
||||
self.assertNotIn('ip', search.result_container.answers)
|
||||
|
||||
@parameterized.expand(
|
||||
[
|
||||
'user-agent',
|
||||
'What is my User-Agent?',
|
||||
]
|
||||
)
|
||||
def test_user_agent_in_answer(self, query: str):
|
||||
request = Mock(user_agent=Mock(string='Mock'))
|
||||
search = get_search_mock(query=query, pageno=1)
|
||||
self.store.call(self.store.plugins, 'post_search', request, search)
|
||||
self.assertIn('Mock', search.result_container.answers["user-agent"]["answer"])
|
||||
|
||||
@parameterized.expand(
|
||||
[
|
||||
'user-agent',
|
||||
'What is my User-Agent?',
|
||||
]
|
||||
)
|
||||
def test_user_agent_not_in_answer(self, query: str):
|
||||
request = Mock(user_agent=Mock(string='Mock'))
|
||||
search = get_search_mock(query=query, pageno=2)
|
||||
self.store.call(self.store.plugins, 'post_search', request, search)
|
||||
self.assertNotIn('user-agent', search.result_container.answers)
|
||||
|
|
@ -1,18 +1,15 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# pylint: disable=missing-module-docstring
|
||||
|
||||
import babel
|
||||
from mock import Mock
|
||||
|
||||
from searx import (
|
||||
plugins,
|
||||
limiter,
|
||||
botdetection,
|
||||
)
|
||||
|
||||
from searx import plugins
|
||||
from tests import SearxTestCase
|
||||
|
||||
|
||||
def get_search_mock(query, **kwargs):
|
||||
lang = kwargs.get("lang", "en-US")
|
||||
kwargs["locale"] = babel.Locale.parse(lang, sep="-")
|
||||
return Mock(search_query=Mock(query=query, **kwargs), result_container=Mock(answers={}))
|
||||
|
||||
|
||||
|
|
@ -23,143 +20,31 @@ class PluginMock: # pylint: disable=missing-class-docstring, too-few-public-met
|
|||
|
||||
|
||||
class PluginStoreTest(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
def test_PluginStore_init(self):
|
||||
store = plugins.PluginStore()
|
||||
self.assertTrue(isinstance(store.plugins, list) and len(store.plugins) == 0)
|
||||
def setUp(self):
|
||||
self.store = plugins.PluginStore()
|
||||
|
||||
def test_PluginStore_register(self):
|
||||
store = plugins.PluginStore()
|
||||
def test_init(self):
|
||||
self.assertEqual(0, len(self.store.plugins))
|
||||
self.assertIsInstance(self.store.plugins, list)
|
||||
|
||||
def test_register(self):
|
||||
testplugin = PluginMock()
|
||||
store.register(testplugin)
|
||||
self.store.register(testplugin)
|
||||
self.assertEqual(1, len(self.store.plugins))
|
||||
|
||||
self.assertTrue(len(store.plugins) == 1)
|
||||
def test_call_empty(self):
|
||||
testplugin = PluginMock()
|
||||
self.store.register(testplugin)
|
||||
setattr(testplugin, 'asdf', Mock())
|
||||
request = Mock()
|
||||
self.store.call([], 'asdf', request, Mock())
|
||||
self.assertFalse(getattr(testplugin, 'asdf').called) # pylint: disable=E1101
|
||||
|
||||
def test_PluginStore_call(self):
|
||||
def test_call_with_plugin(self):
|
||||
store = plugins.PluginStore()
|
||||
testplugin = PluginMock()
|
||||
store.register(testplugin)
|
||||
setattr(testplugin, 'asdf', Mock())
|
||||
request = Mock()
|
||||
store.call([], 'asdf', request, Mock())
|
||||
|
||||
self.assertFalse(testplugin.asdf.called) # pylint: disable=E1101
|
||||
|
||||
store.call([testplugin], 'asdf', request, Mock())
|
||||
self.assertTrue(testplugin.asdf.called) # pylint: disable=E1101
|
||||
|
||||
|
||||
class SelfIPTest(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
def test_PluginStore_init(self):
|
||||
plugin = plugins.load_and_initialize_plugin('searx.plugins.self_info', False, (None, {}))
|
||||
store = plugins.PluginStore()
|
||||
store.register(plugin)
|
||||
cfg = limiter.get_cfg()
|
||||
botdetection.init(cfg, None)
|
||||
|
||||
self.assertTrue(len(store.plugins) == 1)
|
||||
|
||||
# IP test
|
||||
request = Mock()
|
||||
request.remote_addr = '127.0.0.1'
|
||||
request.headers = {'X-Forwarded-For': '1.2.3.4, 127.0.0.1', 'X-Real-IP': '127.0.0.1'}
|
||||
search = get_search_mock(
|
||||
query='ip',
|
||||
pageno=1,
|
||||
)
|
||||
store.call(store.plugins, 'post_search', request, search)
|
||||
self.assertTrue('127.0.0.1' in search.result_container.answers["ip"]["answer"])
|
||||
|
||||
search = get_search_mock(query='ip', pageno=2)
|
||||
store.call(store.plugins, 'post_search', request, search)
|
||||
self.assertFalse('ip' in search.result_container.answers)
|
||||
|
||||
# User agent test
|
||||
request = Mock(user_agent='Mock')
|
||||
|
||||
search = get_search_mock(query='user-agent', pageno=1)
|
||||
store.call(store.plugins, 'post_search', request, search)
|
||||
self.assertTrue('Mock' in search.result_container.answers["user-agent"]["answer"])
|
||||
|
||||
search = get_search_mock(query='user-agent', pageno=2)
|
||||
store.call(store.plugins, 'post_search', request, search)
|
||||
self.assertFalse('user-agent' in search.result_container.answers)
|
||||
|
||||
search = get_search_mock(query='user-agent', pageno=1)
|
||||
store.call(store.plugins, 'post_search', request, search)
|
||||
self.assertTrue('Mock' in search.result_container.answers["user-agent"]["answer"])
|
||||
|
||||
search = get_search_mock(query='user-agent', pageno=2)
|
||||
store.call(store.plugins, 'post_search', request, search)
|
||||
self.assertFalse('user-agent' in search.result_container.answers)
|
||||
|
||||
search = get_search_mock(query='What is my User-Agent?', pageno=1)
|
||||
store.call(store.plugins, 'post_search', request, search)
|
||||
self.assertTrue('Mock' in search.result_container.answers["user-agent"]["answer"])
|
||||
|
||||
search = get_search_mock(query='What is my User-Agent?', pageno=2)
|
||||
store.call(store.plugins, 'post_search', request, search)
|
||||
self.assertFalse('user-agent' in search.result_container.answers)
|
||||
|
||||
|
||||
class HashPluginTest(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
def test_PluginStore_init(self):
|
||||
store = plugins.PluginStore()
|
||||
plugin = plugins.load_and_initialize_plugin('searx.plugins.hash_plugin', False, (None, {}))
|
||||
store.register(plugin)
|
||||
|
||||
self.assertTrue(len(store.plugins) == 1)
|
||||
|
||||
request = Mock(remote_addr='127.0.0.1')
|
||||
|
||||
# MD5
|
||||
search = get_search_mock(query='md5 test', pageno=1)
|
||||
store.call(store.plugins, 'post_search', request, search)
|
||||
self.assertTrue(
|
||||
'md5 hash digest: 098f6bcd4621d373cade4e832627b4f6' in search.result_container.answers['hash']['answer']
|
||||
)
|
||||
|
||||
search = get_search_mock(query=b'md5 test', pageno=2)
|
||||
store.call(store.plugins, 'post_search', request, search)
|
||||
self.assertFalse('hash' in search.result_container.answers)
|
||||
|
||||
# SHA1
|
||||
search = get_search_mock(query='sha1 test', pageno=1)
|
||||
store.call(store.plugins, 'post_search', request, search)
|
||||
self.assertTrue(
|
||||
'sha1 hash digest: a94a8fe5ccb19ba61c4c0873d391e9879'
|
||||
'82fbbd3' in search.result_container.answers['hash']['answer']
|
||||
)
|
||||
|
||||
# SHA224
|
||||
search = get_search_mock(query='sha224 test', pageno=1)
|
||||
store.call(store.plugins, 'post_search', request, search)
|
||||
self.assertTrue(
|
||||
'sha224 hash digest: 90a3ed9e32b2aaf4c61c410eb9254261'
|
||||
'19e1a9dc53d4286ade99a809' in search.result_container.answers['hash']['answer']
|
||||
)
|
||||
|
||||
# SHA256
|
||||
search = get_search_mock(query='sha256 test', pageno=1)
|
||||
store.call(store.plugins, 'post_search', request, search)
|
||||
self.assertTrue(
|
||||
'sha256 hash digest: 9f86d081884c7d659a2feaa0c55ad015a'
|
||||
'3bf4f1b2b0b822cd15d6c15b0f00a08' in search.result_container.answers['hash']['answer']
|
||||
)
|
||||
|
||||
# SHA384
|
||||
search = get_search_mock(query='sha384 test', pageno=1)
|
||||
store.call(store.plugins, 'post_search', request, search)
|
||||
self.assertTrue(
|
||||
'sha384 hash digest: 768412320f7b0aa5812fce428dc4706b3c'
|
||||
'ae50e02a64caa16a782249bfe8efc4b7ef1ccb126255d196047dfedf1'
|
||||
'7a0a9' in search.result_container.answers['hash']['answer']
|
||||
)
|
||||
|
||||
# SHA512
|
||||
search = get_search_mock(query='sha512 test', pageno=1)
|
||||
store.call(store.plugins, 'post_search', request, search)
|
||||
self.assertTrue(
|
||||
'sha512 hash digest: ee26b0dd4af7e749aa1a8ee3c10ae9923f6'
|
||||
'18980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5'
|
||||
'fa9ad8e6f57f50028a8ff' in search.result_container.answers['hash']['answer']
|
||||
)
|
||||
self.assertTrue(getattr(testplugin, 'asdf').called) # pylint: disable=E1101
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# pylint: disable=missing-module-docstring, invalid-name
|
||||
|
||||
import flask
|
||||
from mock import Mock
|
||||
from tests import SearxTestCase
|
||||
from searx import favicons
|
||||
from searx.locales import locales_initialize
|
||||
from searx.preferences import (
|
||||
Setting,
|
||||
EnumStringSetting,
|
||||
MapSetting,
|
||||
SearchLanguageSetting,
|
||||
|
|
@ -10,12 +15,14 @@ from searx.preferences import (
|
|||
PluginsSetting,
|
||||
ValidationException,
|
||||
)
|
||||
from tests import SearxTestCase
|
||||
from searx.plugins import Plugin
|
||||
from searx.preferences import Preferences
|
||||
|
||||
locales_initialize()
|
||||
favicons.init()
|
||||
|
||||
|
||||
class PluginStub: # pylint: disable=missing-class-docstring, too-few-public-methods
|
||||
class PluginStub(Plugin): # pylint: disable=missing-class-docstring, too-few-public-methods
|
||||
def __init__(self, plugin_id, default_on):
|
||||
self.id = plugin_id
|
||||
self.default_on = default_on
|
||||
|
|
@ -47,22 +54,22 @@ class TestSettings(SearxTestCase): # pylint: disable=missing-class-docstring
|
|||
|
||||
def test_enum_setting_invalid_default_value(self):
|
||||
with self.assertRaises(ValidationException):
|
||||
EnumStringSetting(3, choices=[0, 1, 2])
|
||||
EnumStringSetting('3', choices=['0', '1', '2'])
|
||||
|
||||
def test_enum_setting_invalid_choice(self):
|
||||
setting = EnumStringSetting(0, choices=[0, 1, 2])
|
||||
setting = EnumStringSetting('0', choices=['0', '1', '2'])
|
||||
with self.assertRaises(ValidationException):
|
||||
setting.parse(3)
|
||||
setting.parse('3')
|
||||
|
||||
def test_enum_setting_valid_default(self):
|
||||
setting = EnumStringSetting(3, choices=[1, 2, 3])
|
||||
self.assertEqual(setting.get_value(), 3)
|
||||
setting = EnumStringSetting('3', choices=['1', '2', '3'])
|
||||
self.assertEqual(setting.get_value(), '3')
|
||||
|
||||
def test_enum_setting_valid_choice(self):
|
||||
setting = EnumStringSetting(3, choices=[1, 2, 3])
|
||||
self.assertEqual(setting.get_value(), 3)
|
||||
setting.parse(2)
|
||||
self.assertEqual(setting.get_value(), 2)
|
||||
setting = EnumStringSetting('3', choices=['1', '2', '3'])
|
||||
self.assertEqual(setting.get_value(), '3')
|
||||
setting.parse('2')
|
||||
self.assertEqual(setting.get_value(), '2')
|
||||
|
||||
# multiple choice settings
|
||||
|
||||
|
|
@ -122,10 +129,10 @@ class TestSettings(SearxTestCase): # pylint: disable=missing-class-docstring
|
|||
|
||||
|
||||
class TestPreferences(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
def test_encode(self):
|
||||
from searx.preferences import Preferences # pylint: disable=import-outside-toplevel
|
||||
def setUp(self):
|
||||
self.preferences = Preferences(['simple'], ['general'], {}, [])
|
||||
|
||||
pref = Preferences(['simple'], ['general'], {}, [])
|
||||
def test_encode(self):
|
||||
url_params = (
|
||||
'eJx1Vk1z4zYM_TXxRZNMd7eddg8-pe21nWnvGoiEJEQkofDDtvzrC1qSRdnbQxQTBA'
|
||||
'Hw8eGRCiJ27AnDsUOHHszBgOsSdHjU-Pr7HwfDCkweHCBFVmxHgxGPB7LiU4-eL9Px'
|
||||
|
|
@ -152,8 +159,48 @@ class TestPreferences(SearxTestCase): # pylint: disable=missing-class-docstring
|
|||
'd-DZy7PtaVp2WgvPBpzCXUL_J1OGex48RVmOXzBU8_N3kqekkefRDzxNK2_Klp9mBJ'
|
||||
'wsUnXyRqq1mScHuYalUY7_AZTCR4s=&q='
|
||||
)
|
||||
pref.parse_encoded_data(url_params)
|
||||
self.preferences.parse_encoded_data(url_params)
|
||||
self.assertEqual(
|
||||
vars(pref.key_value_settings['categories']),
|
||||
vars(self.preferences.key_value_settings['categories']),
|
||||
{'value': ['general'], 'locked': False, 'choices': ['general', 'none']},
|
||||
)
|
||||
|
||||
def test_save_key_value_setting(self):
|
||||
setting_key = 'foo'
|
||||
setting_value = 'bar'
|
||||
|
||||
cookie_callback = {}
|
||||
|
||||
def set_cookie_callback(name, value, max_age): # pylint: disable=unused-argument
|
||||
cookie_callback[name] = value
|
||||
|
||||
response_mock = Mock(flask.Response)
|
||||
response_mock.set_cookie = set_cookie_callback
|
||||
self.preferences.key_value_settings = {
|
||||
setting_key: Setting(
|
||||
setting_value,
|
||||
locked=False,
|
||||
),
|
||||
}
|
||||
self.preferences.save(response_mock)
|
||||
self.assertIn(setting_key, cookie_callback)
|
||||
self.assertEqual(cookie_callback[setting_key], setting_value)
|
||||
|
||||
def test_false_key_value_setting(self):
|
||||
setting_key = 'foo'
|
||||
|
||||
cookie_callback = {}
|
||||
|
||||
def set_cookie_callback(name, value, max_age): # pylint: disable=unused-argument
|
||||
cookie_callback[name] = value
|
||||
|
||||
response_mock = Mock(flask.Response)
|
||||
response_mock.set_cookie = set_cookie_callback
|
||||
self.preferences.key_value_settings = {
|
||||
setting_key: Setting(
|
||||
'',
|
||||
locked=True,
|
||||
),
|
||||
}
|
||||
self.preferences.save(response_mock)
|
||||
self.assertNotIn(setting_key, cookie_callback)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# pylint: disable=missing-module-docstring
|
||||
|
||||
from searx import settings
|
||||
from parameterized.parameterized import parameterized
|
||||
from searx.engines import load_engines
|
||||
from searx.query import RawTextQuery
|
||||
from tests import SearxTestCase
|
||||
|
|
@ -130,49 +130,32 @@ class TestLanguageParser(SearxTestCase): # pylint:disable=missing-class-docstri
|
|||
query = RawTextQuery(query_text, [])
|
||||
self.assertEqual(query.autocomplete_list, [":en", ":en_us", ":english", ":united_kingdom"])
|
||||
|
||||
def test_autocomplete(self):
|
||||
query = RawTextQuery(':englis', [])
|
||||
self.assertEqual(query.autocomplete_list, [":english"])
|
||||
|
||||
query = RawTextQuery(':deutschla', [])
|
||||
self.assertEqual(query.autocomplete_list, [":deutschland"])
|
||||
|
||||
query = RawTextQuery(':new_zea', [])
|
||||
self.assertEqual(query.autocomplete_list, [":new_zealand"])
|
||||
|
||||
query = RawTextQuery(':hu-H', [])
|
||||
self.assertEqual(query.autocomplete_list, [":hu-hu"])
|
||||
|
||||
query = RawTextQuery(':zh-', [])
|
||||
self.assertEqual(query.autocomplete_list, [':zh-cn', ':zh-hk', ':zh-tw'])
|
||||
@parameterized.expand(
|
||||
[
|
||||
(':englis', [":english"]),
|
||||
(':deutschla', [":deutschland"]),
|
||||
(':new_zea', [":new_zealand"]),
|
||||
(':zh-', [':zh-cn', ':zh-hk', ':zh-tw']),
|
||||
]
|
||||
)
|
||||
def test_autocomplete(self, query: str, autocomplete_list: list):
|
||||
query = RawTextQuery(query, [])
|
||||
self.assertEqual(query.autocomplete_list, autocomplete_list)
|
||||
|
||||
|
||||
class TestTimeoutParser(SearxTestCase): # pylint:disable=missing-class-docstring
|
||||
def test_timeout_below100(self):
|
||||
query_text = '<3 the query'
|
||||
@parameterized.expand(
|
||||
[
|
||||
('<3 the query', 3),
|
||||
('<350 the query', 0.35),
|
||||
('<3500 the query', 3.5),
|
||||
]
|
||||
)
|
||||
def test_timeout_limit(self, query_text: str, timeout_limit: float):
|
||||
query = RawTextQuery(query_text, [])
|
||||
|
||||
self.assertEqual(query.getFullQuery(), query_text)
|
||||
self.assertEqual(len(query.query_parts), 1)
|
||||
self.assertEqual(query.timeout_limit, 3)
|
||||
self.assertFalse(query.specific)
|
||||
|
||||
def test_timeout_above100(self):
|
||||
query_text = '<350 the query'
|
||||
query = RawTextQuery(query_text, [])
|
||||
|
||||
self.assertEqual(query.getFullQuery(), query_text)
|
||||
self.assertEqual(len(query.query_parts), 1)
|
||||
self.assertEqual(query.timeout_limit, 0.35)
|
||||
self.assertFalse(query.specific)
|
||||
|
||||
def test_timeout_above1000(self):
|
||||
query_text = '<3500 the query'
|
||||
query = RawTextQuery(query_text, [])
|
||||
|
||||
self.assertEqual(query.getFullQuery(), query_text)
|
||||
self.assertEqual(len(query.query_parts), 1)
|
||||
self.assertEqual(query.timeout_limit, 3.5)
|
||||
self.assertEqual(query.timeout_limit, timeout_limit)
|
||||
self.assertFalse(query.specific)
|
||||
|
||||
def test_timeout_invalid(self):
|
||||
|
|
@ -183,7 +166,7 @@ class TestTimeoutParser(SearxTestCase): # pylint:disable=missing-class-docstrin
|
|||
self.assertEqual(query.getFullQuery(), query_text)
|
||||
self.assertEqual(len(query.query_parts), 0)
|
||||
self.assertEqual(query.getQuery(), query_text)
|
||||
self.assertEqual(query.timeout_limit, None)
|
||||
self.assertIsNone(query.timeout_limit)
|
||||
self.assertFalse(query.specific)
|
||||
|
||||
def test_timeout_autocomplete(self):
|
||||
|
|
@ -194,7 +177,7 @@ class TestTimeoutParser(SearxTestCase): # pylint:disable=missing-class-docstrin
|
|||
self.assertEqual(query.getFullQuery(), query_text)
|
||||
self.assertEqual(len(query.query_parts), 0)
|
||||
self.assertEqual(query.getQuery(), query_text)
|
||||
self.assertEqual(query.timeout_limit, None)
|
||||
self.assertIsNone(query.timeout_limit)
|
||||
self.assertFalse(query.specific)
|
||||
self.assertEqual(query.autocomplete_list, ['<3', '<850'])
|
||||
|
||||
|
|
@ -213,7 +196,7 @@ class TestExternalBangParser(SearxTestCase): # pylint:disable=missing-class-doc
|
|||
query = RawTextQuery(query_text, [])
|
||||
|
||||
self.assertEqual(query.getFullQuery(), query_text)
|
||||
self.assertEqual(query.external_bang, None)
|
||||
self.assertIsNone(query.external_bang)
|
||||
self.assertFalse(query.specific)
|
||||
|
||||
def test_external_bang_autocomplete(self):
|
||||
|
|
@ -234,33 +217,34 @@ class TestBang(SearxTestCase): # pylint:disable=missing-class-docstring
|
|||
SPECIFIC_BANGS = ['!dummy_engine', '!du', '!general']
|
||||
THE_QUERY = 'the query'
|
||||
|
||||
def test_bang(self):
|
||||
def setUp(self):
|
||||
load_engines(TEST_ENGINES)
|
||||
|
||||
for bang in TestBang.SPECIFIC_BANGS:
|
||||
with self.subTest(msg="Check bang", bang=bang):
|
||||
query_text = TestBang.THE_QUERY + ' ' + bang
|
||||
query = RawTextQuery(query_text, [])
|
||||
def tearDown(self):
|
||||
load_engines([])
|
||||
|
||||
self.assertEqual(query.getFullQuery(), bang + ' ' + TestBang.THE_QUERY)
|
||||
self.assertEqual(query.query_parts, [bang])
|
||||
self.assertEqual(query.user_query_parts, TestBang.THE_QUERY.split(' '))
|
||||
@parameterized.expand(SPECIFIC_BANGS)
|
||||
def test_bang(self, bang: str):
|
||||
with self.subTest(msg="Check bang", bang=bang):
|
||||
query_text = TestBang.THE_QUERY + ' ' + bang
|
||||
query = RawTextQuery(query_text, [])
|
||||
|
||||
def test_specific(self):
|
||||
load_engines(TEST_ENGINES)
|
||||
for bang in TestBang.SPECIFIC_BANGS:
|
||||
with self.subTest(msg="Check bang is specific", bang=bang):
|
||||
query_text = TestBang.THE_QUERY + ' ' + bang
|
||||
query = RawTextQuery(query_text, [])
|
||||
self.assertTrue(query.specific)
|
||||
self.assertEqual(query.getFullQuery(), bang + ' ' + TestBang.THE_QUERY)
|
||||
self.assertEqual(query.query_parts, [bang])
|
||||
self.assertEqual(query.user_query_parts, TestBang.THE_QUERY.split(' '))
|
||||
|
||||
@parameterized.expand(SPECIFIC_BANGS)
|
||||
def test_specific(self, bang: str):
|
||||
with self.subTest(msg="Check bang is specific", bang=bang):
|
||||
query_text = TestBang.THE_QUERY + ' ' + bang
|
||||
query = RawTextQuery(query_text, [])
|
||||
self.assertTrue(query.specific)
|
||||
|
||||
def test_bang_not_found(self):
|
||||
load_engines(TEST_ENGINES)
|
||||
query = RawTextQuery('the query !bang_not_found', [])
|
||||
self.assertEqual(query.getFullQuery(), 'the query !bang_not_found')
|
||||
|
||||
def test_bang_autocomplete(self):
|
||||
load_engines(TEST_ENGINES)
|
||||
query = RawTextQuery('the query !dum', [])
|
||||
self.assertEqual(query.autocomplete_list, ['!dummy_engine'])
|
||||
|
||||
|
|
@ -269,7 +253,6 @@ class TestBang(SearxTestCase): # pylint:disable=missing-class-docstring
|
|||
self.assertEqual(query.getQuery(), '!dum the query')
|
||||
|
||||
def test_bang_autocomplete_empty(self):
|
||||
load_engines(settings['engines'])
|
||||
query = RawTextQuery('the query !', [])
|
||||
self.assertEqual(query.autocomplete_list, ['!images', '!wikipedia', '!osm'])
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
# pylint: disable=missing-module-docstring, invalid-name
|
||||
|
||||
from copy import copy
|
||||
import logging
|
||||
|
||||
import searx.search
|
||||
from searx.search import SearchQuery, EngineRef
|
||||
|
|
@ -46,8 +47,13 @@ class SearchQueryTestCase(SearxTestCase): # pylint: disable=missing-class-docst
|
|||
class SearchTestCase(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
def setUp(self):
|
||||
|
||||
log = logging.getLogger("searx")
|
||||
log_lev = log.level
|
||||
log.setLevel(logging.ERROR)
|
||||
from searx import webapp # pylint: disable=import-outside-toplevel
|
||||
|
||||
log.setLevel(log_lev)
|
||||
|
||||
self.app = webapp.app
|
||||
|
||||
@classmethod
|
||||
|
|
@ -104,7 +110,7 @@ class SearchTestCase(SearxTestCase): # pylint: disable=missing-class-docstring
|
|||
search.search()
|
||||
self.assertEqual(search.actual_timeout, 10.0)
|
||||
|
||||
def test_external_bang(self):
|
||||
def test_external_bang_valid(self):
|
||||
search_query = SearchQuery(
|
||||
'yes yes',
|
||||
[EngineRef(PUBLIC_ENGINE_NAME, 'general')],
|
||||
|
|
@ -118,8 +124,9 @@ class SearchTestCase(SearxTestCase): # pylint: disable=missing-class-docstring
|
|||
search = searx.search.Search(search_query)
|
||||
results = search.search()
|
||||
# For checking if the user redirected with the youtube external bang
|
||||
self.assertTrue(results.redirect_url is not None)
|
||||
self.assertIsNotNone(results.redirect_url)
|
||||
|
||||
def test_external_bang_none(self):
|
||||
search_query = SearchQuery(
|
||||
'youtube never gonna give you up',
|
||||
[EngineRef(PUBLIC_ENGINE_NAME, 'general')],
|
||||
|
|
@ -134,4 +141,4 @@ class SearchTestCase(SearxTestCase): # pylint: disable=missing-class-docstring
|
|||
with self.app.test_request_context('/search'):
|
||||
results = search.search()
|
||||
# This should not redirect
|
||||
self.assertTrue(results.redirect_url is None)
|
||||
self.assertIsNone(results.redirect_url)
|
||||
|
|
|
|||
|
|
@ -1,15 +1,20 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# pylint: disable=missing-module-docstring
|
||||
|
||||
from os.path import dirname, join, abspath
|
||||
from pathlib import Path
|
||||
|
||||
import os
|
||||
from unittest.mock import patch
|
||||
|
||||
from parameterized import parameterized
|
||||
|
||||
from searx.exceptions import SearxSettingsException
|
||||
from searx import settings_loader
|
||||
from tests import SearxTestCase
|
||||
|
||||
|
||||
test_dir = abspath(dirname(__file__))
|
||||
def _settings(f_name):
|
||||
return str(Path(__file__).parent.absolute() / "settings" / f_name)
|
||||
|
||||
|
||||
class TestLoad(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
|
|
@ -18,16 +23,9 @@ class TestLoad(SearxTestCase): # pylint: disable=missing-class-docstring
|
|||
settings_loader.load_yaml('/dev/zero')
|
||||
|
||||
with self.assertRaises(SearxSettingsException):
|
||||
settings_loader.load_yaml(join(test_dir, '/settings/syntaxerror_settings.yml'))
|
||||
settings_loader.load_yaml(_settings("syntaxerror_settings.yml"))
|
||||
|
||||
with self.assertRaises(SearxSettingsException):
|
||||
settings_loader.load_yaml(join(test_dir, '/settings/empty_settings.yml'))
|
||||
|
||||
def test_existing_filename_or_none(self):
|
||||
self.assertIsNone(settings_loader.existing_filename_or_none('/dev/zero'))
|
||||
|
||||
bad_settings_path = join(test_dir, 'settings/syntaxerror_settings.yml')
|
||||
self.assertEqual(settings_loader.existing_filename_or_none(bad_settings_path), bad_settings_path)
|
||||
self.assertEqual(settings_loader.load_yaml(_settings("empty_settings.yml")), {})
|
||||
|
||||
|
||||
class TestDefaultSettings(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
|
|
@ -35,13 +33,13 @@ class TestDefaultSettings(SearxTestCase): # pylint: disable=missing-class-docst
|
|||
settings, msg = settings_loader.load_settings(load_user_settings=False)
|
||||
self.assertTrue(msg.startswith('load the default settings from'))
|
||||
self.assertFalse(settings['general']['debug'])
|
||||
self.assertTrue(isinstance(settings['general']['instance_name'], str))
|
||||
self.assertIsInstance(settings['general']['instance_name'], str)
|
||||
self.assertEqual(settings['server']['secret_key'], "ultrasecretkey")
|
||||
self.assertTrue(isinstance(settings['server']['port'], int))
|
||||
self.assertTrue(isinstance(settings['server']['bind_address'], str))
|
||||
self.assertTrue(isinstance(settings['engines'], list))
|
||||
self.assertTrue(isinstance(settings['doi_resolvers'], dict))
|
||||
self.assertTrue(isinstance(settings['default_doi_resolver'], str))
|
||||
self.assertIsInstance(settings['server']['port'], int)
|
||||
self.assertIsInstance(settings['server']['bind_address'], str)
|
||||
self.assertIsInstance(settings['engines'], list)
|
||||
self.assertIsInstance(settings['doi_resolvers'], dict)
|
||||
self.assertIsInstance(settings['default_doi_resolver'], str)
|
||||
|
||||
|
||||
class TestUserSettings(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
|
|
@ -54,25 +52,26 @@ class TestUserSettings(SearxTestCase): # pylint: disable=missing-class-docstrin
|
|||
with self.assertRaises(ValueError):
|
||||
self.assertFalse(settings_loader.is_use_default_settings({'use_default_settings': 0}))
|
||||
|
||||
def test_user_settings_not_found(self):
|
||||
with patch.dict(settings_loader.environ, {'SEARXNG_SETTINGS_PATH': '/dev/null'}):
|
||||
settings, msg = settings_loader.load_settings()
|
||||
self.assertTrue(msg.startswith('load the default settings from'))
|
||||
self.assertEqual(settings['server']['secret_key'], "ultrasecretkey")
|
||||
@parameterized.expand(
|
||||
[
|
||||
_settings("not_exists.yml"),
|
||||
"/folder/not/exists",
|
||||
]
|
||||
)
|
||||
def test_user_settings_not_found(self, path: str):
|
||||
with patch.dict(os.environ, {'SEARXNG_SETTINGS_PATH': path}):
|
||||
with self.assertRaises(EnvironmentError):
|
||||
_s, _m = settings_loader.load_settings()
|
||||
|
||||
def test_user_settings(self):
|
||||
with patch.dict(
|
||||
settings_loader.environ, {'SEARXNG_SETTINGS_PATH': join(test_dir, 'settings/user_settings_simple.yml')}
|
||||
):
|
||||
with patch.dict(os.environ, {'SEARXNG_SETTINGS_PATH': _settings("user_settings_simple.yml")}):
|
||||
settings, msg = settings_loader.load_settings()
|
||||
self.assertTrue(msg.startswith('merge the default settings'))
|
||||
self.assertEqual(settings['server']['secret_key'], "user_secret_key")
|
||||
self.assertEqual(settings['server']['default_http_headers']['Custom-Header'], "Custom-Value")
|
||||
|
||||
def test_user_settings_remove(self):
|
||||
with patch.dict(
|
||||
settings_loader.environ, {'SEARXNG_SETTINGS_PATH': join(test_dir, 'settings/user_settings_remove.yml')}
|
||||
):
|
||||
with patch.dict(os.environ, {'SEARXNG_SETTINGS_PATH': _settings("user_settings_remove.yml")}):
|
||||
settings, msg = settings_loader.load_settings()
|
||||
self.assertTrue(msg.startswith('merge the default settings'))
|
||||
self.assertEqual(settings['server']['secret_key'], "user_secret_key")
|
||||
|
|
@ -83,9 +82,7 @@ class TestUserSettings(SearxTestCase): # pylint: disable=missing-class-docstrin
|
|||
self.assertIn('wikipedia', engine_names)
|
||||
|
||||
def test_user_settings_remove2(self):
|
||||
with patch.dict(
|
||||
settings_loader.environ, {'SEARXNG_SETTINGS_PATH': join(test_dir, 'settings/user_settings_remove2.yml')}
|
||||
):
|
||||
with patch.dict(os.environ, {'SEARXNG_SETTINGS_PATH': _settings("user_settings_remove2.yml")}):
|
||||
settings, msg = settings_loader.load_settings()
|
||||
self.assertTrue(msg.startswith('merge the default settings'))
|
||||
self.assertEqual(settings['server']['secret_key'], "user_secret_key")
|
||||
|
|
@ -101,9 +98,7 @@ class TestUserSettings(SearxTestCase): # pylint: disable=missing-class-docstrin
|
|||
self.assertEqual(newengine[0]['engine'], 'dummy')
|
||||
|
||||
def test_user_settings_keep_only(self):
|
||||
with patch.dict(
|
||||
settings_loader.environ, {'SEARXNG_SETTINGS_PATH': join(test_dir, 'settings/user_settings_keep_only.yml')}
|
||||
):
|
||||
with patch.dict(os.environ, {'SEARXNG_SETTINGS_PATH': _settings("user_settings_keep_only.yml")}):
|
||||
settings, msg = settings_loader.load_settings()
|
||||
self.assertTrue(msg.startswith('merge the default settings'))
|
||||
engine_names = [engine['name'] for engine in settings['engines']]
|
||||
|
|
@ -112,9 +107,7 @@ class TestUserSettings(SearxTestCase): # pylint: disable=missing-class-docstrin
|
|||
self.assertEqual(len(settings['engines'][2]), 1)
|
||||
|
||||
def test_custom_settings(self):
|
||||
with patch.dict(
|
||||
settings_loader.environ, {'SEARXNG_SETTINGS_PATH': join(test_dir, 'settings/user_settings.yml')}
|
||||
):
|
||||
with patch.dict(os.environ, {'SEARXNG_SETTINGS_PATH': _settings("user_settings.yml")}):
|
||||
settings, msg = settings_loader.load_settings()
|
||||
self.assertTrue(msg.startswith('load the user settings from'))
|
||||
self.assertEqual(settings['server']['port'], 9000)
|
||||
|
|
|
|||
13
tests/unit/test_toml.py
Normal file
13
tests/unit/test_toml.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# pylint: disable=missing-module-docstring
|
||||
|
||||
from tests import SearxTestCase
|
||||
from searx import compat
|
||||
from searx.favicons.config import DEFAULT_CFG_TOML_PATH
|
||||
|
||||
|
||||
class CompatTest(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
|
||||
def test_toml(self):
|
||||
with DEFAULT_CFG_TOML_PATH.open("rb") as f:
|
||||
_ = compat.tomllib.load(f)
|
||||
|
|
@ -1,15 +1,21 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# pylint: disable=missing-module-docstring, invalid-name
|
||||
|
||||
import random
|
||||
import string
|
||||
import lxml.etree
|
||||
from lxml import html
|
||||
from parameterized.parameterized import parameterized
|
||||
|
||||
from searx.exceptions import SearxXPathSyntaxException, SearxEngineXPathException
|
||||
from searx import utils
|
||||
|
||||
from tests import SearxTestCase
|
||||
|
||||
|
||||
def random_string(length, choices=string.ascii_letters):
|
||||
return ''.join(random.choice(choices) for _ in range(length))
|
||||
|
||||
|
||||
class TestUtils(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
def test_gen_useragent(self):
|
||||
self.assertIsInstance(utils.gen_useragent(), str)
|
||||
|
|
@ -66,9 +72,15 @@ class TestUtils(SearxTestCase): # pylint: disable=missing-class-docstring
|
|||
self.assertEqual(utils.extract_text(dom.xpath('boolean(//span)')), 'True')
|
||||
self.assertEqual(utils.extract_text(dom.xpath('//img/@src')), 'test.jpg')
|
||||
self.assertEqual(utils.extract_text(dom.xpath('//unexistingtag')), '')
|
||||
|
||||
def test_extract_text_allow_none(self):
|
||||
self.assertEqual(utils.extract_text(None, allow_none=True), None)
|
||||
|
||||
def test_extract_text_error_none(self):
|
||||
with self.assertRaises(ValueError):
|
||||
utils.extract_text(None)
|
||||
|
||||
def test_extract_text_error_empty(self):
|
||||
with self.assertRaises(ValueError):
|
||||
utils.extract_text({})
|
||||
|
||||
|
|
@ -103,14 +115,16 @@ class TestHTMLTextExtractor(SearxTestCase): # pylint: disable=missing-class-doc
|
|||
def test__init__(self):
|
||||
self.assertEqual(self.html_text_extractor.result, [])
|
||||
|
||||
def test_handle_charref(self):
|
||||
self.html_text_extractor.handle_charref('xF')
|
||||
self.assertIn('\x0f', self.html_text_extractor.result)
|
||||
self.html_text_extractor.handle_charref('XF')
|
||||
self.assertIn('\x0f', self.html_text_extractor.result)
|
||||
|
||||
self.html_text_extractor.handle_charref('97')
|
||||
self.assertIn('a', self.html_text_extractor.result)
|
||||
@parameterized.expand(
|
||||
[
|
||||
('xF', '\x0f'),
|
||||
('XF', '\x0f'),
|
||||
('97', 'a'),
|
||||
]
|
||||
)
|
||||
def test_handle_charref(self, charref: str, expected: str):
|
||||
self.html_text_extractor.handle_charref(charref)
|
||||
self.assertIn(expected, self.html_text_extractor.result)
|
||||
|
||||
def test_handle_entityref(self):
|
||||
entity = 'test'
|
||||
|
|
@ -191,7 +205,7 @@ class TestXPathUtils(SearxTestCase): # pylint: disable=missing-class-docstring
|
|||
self.assertEqual(utils.eval_xpath_getindex(doc, '//i/text()', 1, default='something'), 'something')
|
||||
|
||||
# default is None
|
||||
self.assertEqual(utils.eval_xpath_getindex(doc, '//i/text()', 1, default=None), None)
|
||||
self.assertIsNone(utils.eval_xpath_getindex(doc, '//i/text()', 1, default=None))
|
||||
|
||||
# index not found
|
||||
with self.assertRaises(SearxEngineXPathException) as context:
|
||||
|
|
@ -225,4 +239,4 @@ class TestXPathUtils(SearxTestCase): # pylint: disable=missing-class-docstring
|
|||
self.assertIsNone(l)
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
utils.detect_language(None)
|
||||
utils.detect_language(None) # type: ignore
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# pylint: disable=missing-module-docstring
|
||||
|
||||
import logging
|
||||
import json
|
||||
from urllib.parse import ParseResult
|
||||
import babel
|
||||
from mock import Mock
|
||||
from searx.results import Timing
|
||||
|
||||
|
|
@ -20,8 +22,13 @@ class ViewsTestCase(SearxTestCase): # pylint: disable=missing-class-docstring,
|
|||
|
||||
self.setattr4test(searx.search.processors, 'initialize_processor', dummy)
|
||||
|
||||
log = logging.getLogger("searx")
|
||||
log_lev = log.level
|
||||
log.setLevel(logging.ERROR)
|
||||
from searx import webapp # pylint: disable=import-outside-toplevel
|
||||
|
||||
log.setLevel(log_lev)
|
||||
|
||||
webapp.app.config['TESTING'] = True # to get better error messages
|
||||
self.app = webapp.app.test_client()
|
||||
|
||||
|
|
@ -76,6 +83,7 @@ class ViewsTestCase(SearxTestCase): # pylint: disable=missing-class-docstring,
|
|||
redirect_url=None,
|
||||
engine_data={},
|
||||
)
|
||||
search_self.search_query.locale = babel.Locale.parse("en-US", sep='-')
|
||||
|
||||
self.setattr4test(Search, 'search', search_mock)
|
||||
|
||||
|
|
@ -172,7 +180,7 @@ class ViewsTestCase(SearxTestCase): # pylint: disable=missing-class-docstring,
|
|||
def test_search_rss(self):
|
||||
result = self.app.post('/search', data={'q': 'test', 'format': 'rss'})
|
||||
|
||||
self.assertIn(b'<description>Search results for "test" - searx</description>', result.data)
|
||||
self.assertIn(b'<description>Search results for "test" - SearXNG</description>', result.data)
|
||||
|
||||
self.assertIn(b'<opensearch:totalResults>3</opensearch:totalResults>', result.data)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,52 +2,59 @@
|
|||
# pylint: disable=missing-module-docstring
|
||||
|
||||
import mock
|
||||
from parameterized.parameterized import parameterized
|
||||
from searx import webutils
|
||||
from tests import SearxTestCase
|
||||
|
||||
|
||||
class TestWebUtils(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
def test_prettify_url(self):
|
||||
data = (
|
||||
|
||||
@parameterized.expand(
|
||||
[
|
||||
('https://searx.me/', 'https://searx.me/'),
|
||||
('https://searx.me/ű', 'https://searx.me/ű'),
|
||||
('https://searx.me/' + (100 * 'a'), 'https://searx.me/[...]aaaaaaaaaaaaaaaaa'),
|
||||
('https://searx.me/' + (100 * 'ű'), 'https://searx.me/[...]űűűűűűűűűűűűűűűűű'),
|
||||
)
|
||||
]
|
||||
)
|
||||
def test_prettify_url(self, test_url: str, expected: str):
|
||||
self.assertEqual(webutils.prettify_url(test_url, max_length=32), expected)
|
||||
|
||||
for test_url, expected in data:
|
||||
self.assertEqual(webutils.prettify_url(test_url, max_length=32), expected)
|
||||
@parameterized.expand(
|
||||
[
|
||||
(0, None, None),
|
||||
(None, None, None),
|
||||
('', None, None),
|
||||
(False, None, None),
|
||||
]
|
||||
)
|
||||
def test_highlight_content_none(self, content, query, expected):
|
||||
self.assertEqual(webutils.highlight_content(content, query), expected)
|
||||
|
||||
def test_highlight_content(self):
|
||||
self.assertEqual(webutils.highlight_content(0, None), None)
|
||||
self.assertEqual(webutils.highlight_content(None, None), None)
|
||||
self.assertEqual(webutils.highlight_content('', None), None)
|
||||
self.assertEqual(webutils.highlight_content(False, None), None)
|
||||
def test_highlight_content_same(self):
|
||||
content = '<html></html>not<'
|
||||
self.assertEqual(webutils.highlight_content(content, None), content)
|
||||
|
||||
contents = ['<html></html>not<']
|
||||
for content in contents:
|
||||
self.assertEqual(webutils.highlight_content(content, None), content)
|
||||
|
||||
content = 'a'
|
||||
query = 'test'
|
||||
self.assertEqual(webutils.highlight_content(content, query), 'a')
|
||||
query = 'a test'
|
||||
self.assertEqual(webutils.highlight_content(content, query), '<span class="highlight">a</span>')
|
||||
|
||||
# pylint: disable=line-too-long
|
||||
data = (
|
||||
@parameterized.expand(
|
||||
[
|
||||
('test', 'a', 'a'),
|
||||
('a test', 'a', '<span class="highlight">a</span>'),
|
||||
('" test "', 'a test string', 'a <span class="highlight">test</span> string'),
|
||||
('"a"', 'this is a test string', 'this is <span class="highlight">a</span> test string'),
|
||||
(
|
||||
'a test',
|
||||
'this is a test string that matches entire query',
|
||||
'this is <span class="highlight">a</span> <span class="highlight">test</span> string that matches entire query',
|
||||
'this is <span class="highlight">a</span>'
|
||||
' <span class="highlight">test</span>'
|
||||
' string that matches entire query',
|
||||
),
|
||||
(
|
||||
'this a test',
|
||||
'this is a string to test.',
|
||||
(
|
||||
'<span class="highlight">this</span> is <span class="highlight">a</span> string to <span class="highlight">test</span>.'
|
||||
'<span class="highlight">this</span>'
|
||||
' is <span class="highlight">a</span>'
|
||||
' string to <span class="highlight">test</span>.'
|
||||
),
|
||||
),
|
||||
(
|
||||
|
|
@ -65,9 +72,10 @@ class TestWebUtils(SearxTestCase): # pylint: disable=missing-class-docstring
|
|||
'a string with class.',
|
||||
'<span class="highlight">a</span> string with <span class="highlight">class</span>.',
|
||||
),
|
||||
)
|
||||
for query, content, expected in data:
|
||||
self.assertEqual(webutils.highlight_content(content, query), expected)
|
||||
]
|
||||
)
|
||||
def test_highlight_content_equal(self, query: str, content: str, expected: str):
|
||||
self.assertEqual(webutils.highlight_content(content, query), expected)
|
||||
|
||||
|
||||
class TestUnicodeWriter(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
|
|
@ -76,7 +84,7 @@ class TestUnicodeWriter(SearxTestCase): # pylint: disable=missing-class-docstri
|
|||
|
||||
def test_write_row(self):
|
||||
row = [1, 2, 3]
|
||||
self.assertEqual(self.unicode_writer.writerow(row), None)
|
||||
self.assertIsNone(self.unicode_writer.writerow(row))
|
||||
|
||||
def test_write_rows(self):
|
||||
self.unicode_writer.writerow = mock.MagicMock()
|
||||
|
|
@ -86,13 +94,18 @@ class TestUnicodeWriter(SearxTestCase): # pylint: disable=missing-class-docstri
|
|||
|
||||
|
||||
class TestNewHmac(SearxTestCase): # pylint: disable=missing-class-docstring
|
||||
def test_bytes(self):
|
||||
@parameterized.expand(
|
||||
[
|
||||
b'secret',
|
||||
1,
|
||||
]
|
||||
)
|
||||
def test_attribute_error(self, secret_key):
|
||||
data = b'http://example.com'
|
||||
with self.assertRaises(AttributeError):
|
||||
webutils.new_hmac(b'secret', data)
|
||||
|
||||
with self.assertRaises(AttributeError):
|
||||
webutils.new_hmac(1, data)
|
||||
webutils.new_hmac(secret_key, data)
|
||||
|
||||
def test_bytes(self):
|
||||
data = b'http://example.com'
|
||||
res = webutils.new_hmac('secret', data)
|
||||
self.assertEqual(res, '23e2baa2404012a5cc8e4a18b4aabf0dde4cb9b56f679ddc0fd6d7c24339d819')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue