diff --git a/searx/engines/duckduckgo_definitions.py b/searx/engines/duckduckgo_definitions.py index b66d6c0f2..793e97d22 100644 --- a/searx/engines/duckduckgo_definitions.py +++ b/searx/engines/duckduckgo_definitions.py @@ -25,9 +25,10 @@ def request(query, params): def response(resp): - search_res = json.loads(resp.text) results = [] + search_res = json.loads(resp.text) + content = '' heading = search_res.get('Heading', '') attributes = [] @@ -68,7 +69,7 @@ def response(resp): results.append({'title': heading, 'url': firstURL}) # related topics - for ddg_result in search_res.get('RelatedTopics', None): + for ddg_result in search_res.get('RelatedTopics', []): if 'FirstURL' in ddg_result: suggestion = result_to_text(ddg_result.get('FirstURL', None), ddg_result.get('Text', None), diff --git a/searx/tests/engines/test_duckduckgo_definitions.py b/searx/tests/engines/test_duckduckgo_definitions.py new file mode 100644 index 000000000..71c84235c --- /dev/null +++ b/searx/tests/engines/test_duckduckgo_definitions.py @@ -0,0 +1,250 @@ +from collections import defaultdict +import mock +from searx.engines import duckduckgo_definitions +from searx.testing import SearxTestCase + + +class TestDDGDefinitionsEngine(SearxTestCase): + + def test_result_to_text(self): + url = '' + text = 'Text' + html_result = 'Html' + result = duckduckgo_definitions.result_to_text(url, text, html_result) + self.assertEqual(result, text) + + html_result = 'Text in link' + result = duckduckgo_definitions.result_to_text(url, text, html_result) + self.assertEqual(result, 'Text in link') + + def test_request(self): + query = 'test_query' + dicto = defaultdict(dict) + dicto['pageno'] = 1 + params = duckduckgo_definitions.request(query, dicto) + self.assertIn('url', params) + self.assertIn(query, params['url']) + self.assertIn('duckduckgo.com', params['url']) + + def test_response(self): + self.assertRaises(AttributeError, duckduckgo_definitions.response, None) + self.assertRaises(AttributeError, duckduckgo_definitions.response, []) + self.assertRaises(AttributeError, duckduckgo_definitions.response, '') + self.assertRaises(AttributeError, duckduckgo_definitions.response, '[]') + + response = mock.Mock(text='{}') + self.assertEqual(duckduckgo_definitions.response(response), []) + + response = mock.Mock(text='{"data": []}') + self.assertEqual(duckduckgo_definitions.response(response), []) + + json = """ + { + "DefinitionSource": "definition source", + "Heading": "heading", + "ImageWidth": 0, + "RelatedTopics": [ + { + "Result": "Top-level domains", + "Icon": { + "URL": "", + "Height": "", + "Width": "" + }, + "FirstURL": "https://first.url", + "Text": "text" + }, + { + "Topics": [ + { + "Result": "result topic", + "Icon": { + "URL": "", + "Height": "", + "Width": "" + }, + "FirstURL": "https://duckduckgo.com/?q=2%2F2", + "Text": "result topic text" + } + ], + "Name": "name" + } + ], + "Entity": "Entity", + "Type": "A", + "Redirect": "", + "DefinitionURL": "http://definition.url", + "AbstractURL": "https://abstract.url", + "Definition": "this is the definition", + "AbstractSource": "abstract source", + "Infobox": { + "content": [ + { + "data_type": "string", + "value": "1999", + "label": "Introduced", + "wiki_order": 0 + } + ], + "meta": [ + { + "data_type": "string", + "value": ".test", + "label": "article_title" + } + ] + }, + "Image": "image.png", + "ImageIsLogo": 0, + "Abstract": "abstract", + "AbstractText": "abstract text", + "AnswerType": "", + "ImageHeight": 0, + "Results": [{ + "Result" : "result title", + "Icon" : { + "URL" : "result url", + "Height" : 16, + "Width" : 16 + }, + "FirstURL" : "result first url", + "Text" : "result text" + } + ], + "Answer": "answer" + } + """ + response = mock.Mock(text=json) + results = duckduckgo_definitions.response(response) + self.assertEqual(type(results), list) + self.assertEqual(len(results), 4) + self.assertEqual(results[0]['answer'], 'answer') + self.assertEqual(results[1]['title'], 'heading') + self.assertEqual(results[1]['url'], 'result first url') + self.assertEqual(results[2]['suggestion'], 'text') + self.assertEqual(results[3]['infobox'], 'heading') + self.assertEqual(results[3]['id'], 'http://definition.url') + self.assertEqual(results[3]['entity'], 'Entity') + self.assertIn('abstract', results[3]['content']) + self.assertIn('this is the definition', results[3]['content']) + self.assertEqual(results[3]['img_src'], 'image.png') + self.assertIn('Introduced', results[3]['attributes'][0]['label']) + self.assertIn('1999', results[3]['attributes'][0]['value']) + self.assertIn({'url': 'https://abstract.url', 'title': 'abstract source'}, results[3]['urls']) + self.assertIn({'url': 'http://definition.url', 'title': 'definition source'}, results[3]['urls']) + self.assertIn({'name': 'name', 'suggestions': ['result topic text']}, results[3]['relatedTopics']) + + json = """ + { + "DefinitionSource": "definition source", + "Heading": "heading", + "ImageWidth": 0, + "RelatedTopics": [], + "Entity": "Entity", + "Type": "A", + "Redirect": "", + "DefinitionURL": "", + "AbstractURL": "https://abstract.url", + "Definition": "", + "AbstractSource": "abstract source", + "Image": "", + "ImageIsLogo": 0, + "Abstract": "", + "AbstractText": "abstract text", + "AnswerType": "", + "ImageHeight": 0, + "Results": [], + "Answer": "" + } + """ + response = mock.Mock(text=json) + results = duckduckgo_definitions.response(response) + self.assertEqual(type(results), list) + self.assertEqual(len(results), 1) + self.assertEqual(results[0]['url'], 'https://abstract.url') + self.assertEqual(results[0]['title'], 'heading') + self.assertEqual(results[0]['content'], '') + + json = """ + { + "DefinitionSource": "definition source", + "Heading": "heading", + "ImageWidth": 0, + "RelatedTopics": [ + { + "Result": "Top-level domains", + "Icon": { + "URL": "", + "Height": "", + "Width": "" + }, + "FirstURL": "https://first.url", + "Text": "heading" + }, + { + "Name": "name" + }, + { + "Topics": [ + { + "Result": "result topic", + "Icon": { + "URL": "", + "Height": "", + "Width": "" + }, + "FirstURL": "https://duckduckgo.com/?q=2%2F2", + "Text": "heading" + } + ], + "Name": "name" + } + ], + "Entity": "Entity", + "Type": "A", + "Redirect": "", + "DefinitionURL": "http://definition.url", + "AbstractURL": "https://abstract.url", + "Definition": "this is the definition", + "AbstractSource": "abstract source", + "Infobox": { + "meta": [ + { + "data_type": "string", + "value": ".test", + "label": "article_title" + } + ] + }, + "Image": "image.png", + "ImageIsLogo": 0, + "Abstract": "abstract", + "AbstractText": "abstract text", + "AnswerType": "", + "ImageHeight": 0, + "Results": [{ + "Result" : "result title", + "Icon" : { + "URL" : "result url", + "Height" : 16, + "Width" : 16 + }, + "Text" : "result text" + } + ], + "Answer": "" + } + """ + response = mock.Mock(text=json) + results = duckduckgo_definitions.response(response) + self.assertEqual(type(results), list) + self.assertEqual(len(results), 1) + self.assertEqual(results[0]['infobox'], 'heading') + self.assertEqual(results[0]['id'], 'http://definition.url') + self.assertEqual(results[0]['entity'], 'Entity') + self.assertIn('abstract', results[0]['content']) + self.assertIn('this is the definition', results[0]['content']) + self.assertEqual(results[0]['img_src'], 'image.png') + self.assertIn({'url': 'https://abstract.url', 'title': 'abstract source'}, results[0]['urls']) + self.assertIn({'url': 'http://definition.url', 'title': 'definition source'}, results[0]['urls']) + self.assertIn({'name': 'name', 'suggestions': []}, results[0]['relatedTopics']) diff --git a/searx/tests/test_engines.py b/searx/tests/test_engines.py index 4a27f5adb..0570a5296 100644 --- a/searx/tests/test_engines.py +++ b/searx/tests/test_engines.py @@ -8,6 +8,7 @@ from searx.tests.engines.test_deezer import * # noqa from searx.tests.engines.test_deviantart import * # noqa from searx.tests.engines.test_digg import * # noqa from searx.tests.engines.test_duckduckgo import * # noqa +from searx.tests.engines.test_duckduckgo_definitions import * # noqa from searx.tests.engines.test_dummy import * # noqa from searx.tests.engines.test_faroo import * # noqa from searx.tests.engines.test_flickr import * # noqa