commit
						f6db77d81e
					
				| @ -13,12 +13,9 @@ def request(query, params): | |||||||
|     if not m: |     if not m: | ||||||
|         # wrong query |         # wrong query | ||||||
|         return params |         return params | ||||||
|     try: | 
 | ||||||
|     ammount, from_currency, to_currency = m.groups() |     ammount, from_currency, to_currency = m.groups() | ||||||
|     ammount = float(ammount) |     ammount = float(ammount) | ||||||
|     except: |  | ||||||
|         # wrong params |  | ||||||
|         return params |  | ||||||
| 
 | 
 | ||||||
|     q = (from_currency + to_currency).upper() |     q = (from_currency + to_currency).upper() | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ | |||||||
| 
 | 
 | ||||||
| from urllib import urlencode | from urllib import urlencode | ||||||
| from lxml.html import fromstring | from lxml.html import fromstring | ||||||
| from searx.utils import html_to_text | from searx.engines.xpath import extract_text | ||||||
| 
 | 
 | ||||||
| # engine dependent config | # engine dependent config | ||||||
| categories = ['general'] | categories = ['general'] | ||||||
| @ -28,8 +28,8 @@ url = 'https://duckduckgo.com/html?{query}&s={offset}' | |||||||
| # specific xpath variables | # specific xpath variables | ||||||
| result_xpath = '//div[@class="results_links results_links_deep web-result"]'  # noqa | result_xpath = '//div[@class="results_links results_links_deep web-result"]'  # noqa | ||||||
| url_xpath = './/a[@class="large"]/@href' | url_xpath = './/a[@class="large"]/@href' | ||||||
| title_xpath = './/a[@class="large"]//text()' | title_xpath = './/a[@class="large"]' | ||||||
| content_xpath = './/div[@class="snippet"]//text()' | content_xpath = './/div[@class="snippet"]' | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # do search-request | # do search-request | ||||||
| @ -64,8 +64,8 @@ def response(resp): | |||||||
|         if not res_url: |         if not res_url: | ||||||
|             continue |             continue | ||||||
| 
 | 
 | ||||||
|         title = html_to_text(''.join(r.xpath(title_xpath))) |         title = extract_text(r.xpath(title_xpath)) | ||||||
|         content = html_to_text(''.join(r.xpath(content_xpath))) |         content = extract_text(r.xpath(content_xpath)) | ||||||
| 
 | 
 | ||||||
|         # append result |         # append result | ||||||
|         results.append({'title': title, |         results.append({'title': title, | ||||||
|  | |||||||
| @ -25,9 +25,10 @@ def request(query, params): | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def response(resp): | def response(resp): | ||||||
|     search_res = json.loads(resp.text) |  | ||||||
|     results = [] |     results = [] | ||||||
| 
 | 
 | ||||||
|  |     search_res = json.loads(resp.text) | ||||||
|  | 
 | ||||||
|     content = '' |     content = '' | ||||||
|     heading = search_res.get('Heading', '') |     heading = search_res.get('Heading', '') | ||||||
|     attributes = [] |     attributes = [] | ||||||
| @ -68,7 +69,7 @@ def response(resp): | |||||||
|             results.append({'title': heading, 'url': firstURL}) |             results.append({'title': heading, 'url': firstURL}) | ||||||
| 
 | 
 | ||||||
|     # related topics |     # related topics | ||||||
|     for ddg_result in search_res.get('RelatedTopics', None): |     for ddg_result in search_res.get('RelatedTopics', []): | ||||||
|         if 'FirstURL' in ddg_result: |         if 'FirstURL' in ddg_result: | ||||||
|             suggestion = result_to_text(ddg_result.get('FirstURL', None), |             suggestion = result_to_text(ddg_result.get('FirstURL', None), | ||||||
|                                         ddg_result.get('Text', None), |                                         ddg_result.get('Text', None), | ||||||
|  | |||||||
| @ -37,7 +37,7 @@ search_category = {'general': 'web', | |||||||
| 
 | 
 | ||||||
| # do search-request | # do search-request | ||||||
| def request(query, params): | def request(query, params): | ||||||
|     offset = (params['pageno']-1) * number_of_results + 1 |     offset = (params['pageno'] - 1) * number_of_results + 1 | ||||||
|     categorie = search_category.get(params['category'], 'web') |     categorie = search_category.get(params['category'], 'web') | ||||||
| 
 | 
 | ||||||
|     if params['language'] == 'all': |     if params['language'] == 'all': | ||||||
| @ -45,11 +45,11 @@ def request(query, params): | |||||||
|     else: |     else: | ||||||
|         language = params['language'].split('_')[0] |         language = params['language'].split('_')[0] | ||||||
| 
 | 
 | ||||||
|     # skip, if language is not supported |     # if language is not supported, put it in english | ||||||
|     if language != 'en' and\ |     if language != 'en' and\ | ||||||
|        language != 'de' and\ |        language != 'de' and\ | ||||||
|        language != 'zh': |        language != 'zh': | ||||||
|         return params |         language = 'en' | ||||||
| 
 | 
 | ||||||
|     params['url'] = search_url.format(offset=offset, |     params['url'] = search_url.format(offset=offset, | ||||||
|                                       number_of_results=number_of_results, |                                       number_of_results=number_of_results, | ||||||
| @ -69,12 +69,10 @@ def response(resp): | |||||||
|     # HTTP-Code 401: api-key is not valide |     # HTTP-Code 401: api-key is not valide | ||||||
|     if resp.status_code == 401: |     if resp.status_code == 401: | ||||||
|         raise Exception("API key is not valide") |         raise Exception("API key is not valide") | ||||||
|         return [] |  | ||||||
| 
 | 
 | ||||||
|     # HTTP-Code 429: rate limit exceeded |     # HTTP-Code 429: rate limit exceeded | ||||||
|     if resp.status_code == 429: |     if resp.status_code == 429: | ||||||
|         raise Exception("rate limit has been exceeded!") |         raise Exception("rate limit has been exceeded!") | ||||||
|         return [] |  | ||||||
| 
 | 
 | ||||||
|     results = [] |     results = [] | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -38,6 +38,9 @@ def response(resp): | |||||||
| 
 | 
 | ||||||
|     # parse results |     # parse results | ||||||
|     for r in json: |     for r in json: | ||||||
|  |         if 'display_name' not in r: | ||||||
|  |             continue | ||||||
|  | 
 | ||||||
|         title = r['display_name'] |         title = r['display_name'] | ||||||
|         osm_type = r.get('osm_type', r.get('type')) |         osm_type = r.get('osm_type', r.get('type')) | ||||||
|         url = result_base_url.format(osm_type=osm_type, |         url = result_base_url.format(osm_type=osm_type, | ||||||
| @ -49,10 +52,8 @@ def response(resp): | |||||||
|         geojson = r.get('geojson') |         geojson = r.get('geojson') | ||||||
| 
 | 
 | ||||||
|         # if no geojson is found and osm_type is a node, add geojson Point |         # if no geojson is found and osm_type is a node, add geojson Point | ||||||
|         if not geojson and\ |         if not geojson and osm_type == 'node': | ||||||
|            osm_type == 'node': |             geojson = {u'type': u'Point', u'coordinates': [r['lon'], r['lat']]} | ||||||
|             geojson = {u'type': u'Point', |  | ||||||
|                        u'coordinates': [r['lon'], r['lat']]} |  | ||||||
| 
 | 
 | ||||||
|         address_raw = r.get('address') |         address_raw = r.get('address') | ||||||
|         address = {} |         address = {} | ||||||
|  | |||||||
| @ -61,7 +61,7 @@ def response(resp): | |||||||
|             continue |             continue | ||||||
| 
 | 
 | ||||||
|         # get title |         # get title | ||||||
|         title = properties['name'] |         title = properties.get('name') | ||||||
| 
 | 
 | ||||||
|         # get osm-type |         # get osm-type | ||||||
|         if properties.get('osm_type') == 'N': |         if properties.get('osm_type') == 'N': | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ | |||||||
| from lxml import html | from lxml import html | ||||||
| from cgi import escape | from cgi import escape | ||||||
| import re | import re | ||||||
|  | from searx.engines.xpath import extract_text | ||||||
| 
 | 
 | ||||||
| # engine dependent config | # engine dependent config | ||||||
| categories = ['general'] | categories = ['general'] | ||||||
| @ -45,8 +46,7 @@ def request(query, params): | |||||||
| 
 | 
 | ||||||
|     # set language if specified |     # set language if specified | ||||||
|     if params['language'] != 'all': |     if params['language'] != 'all': | ||||||
|         params['data']['with_language'] = ('lang_' + |         params['data']['with_language'] = ('lang_' + params['language'].split('_')[0]) | ||||||
|                                            params['language'].split('_')[0]) |  | ||||||
| 
 | 
 | ||||||
|     return params |     return params | ||||||
| 
 | 
 | ||||||
| @ -64,18 +64,15 @@ def response(resp): | |||||||
|             continue |             continue | ||||||
|         link = links[0] |         link = links[0] | ||||||
|         url = link.attrib.get('href') |         url = link.attrib.get('href') | ||||||
|         try: |  | ||||||
|             title = escape(link.text_content()) |  | ||||||
|         except UnicodeDecodeError: |  | ||||||
|             continue |  | ||||||
| 
 | 
 | ||||||
|         # block google-ad url's |         # block google-ad url's | ||||||
|         if re.match("^http(s|)://www.google.[a-z]+/aclk.*$", url): |         if re.match("^http(s|)://www.google.[a-z]+/aclk.*$", url): | ||||||
|             continue |             continue | ||||||
| 
 | 
 | ||||||
|  |         title = escape(extract_text(link)) | ||||||
|  | 
 | ||||||
|         if result.xpath('./p[@class="desc"]'): |         if result.xpath('./p[@class="desc"]'): | ||||||
|             content = escape(result.xpath('./p[@class="desc"]')[0] |             content = escape(extract_text(result.xpath('./p[@class="desc"]'))) | ||||||
|                              .text_content()) |  | ||||||
|         else: |         else: | ||||||
|             content = '' |             content = '' | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -12,6 +12,7 @@ from cgi import escape | |||||||
| from urllib import quote_plus | from urllib import quote_plus | ||||||
| from lxml import html | from lxml import html | ||||||
| from searx.languages import language_codes | from searx.languages import language_codes | ||||||
|  | from searx.engines.xpath import extract_text | ||||||
| 
 | 
 | ||||||
| # engine dependent config | # engine dependent config | ||||||
| categories = ['videos'] | categories = ['videos'] | ||||||
| @ -20,7 +21,7 @@ language = "" | |||||||
| 
 | 
 | ||||||
| # search-url | # search-url | ||||||
| url = 'http://www.subtitleseeker.com/' | url = 'http://www.subtitleseeker.com/' | ||||||
| search_url = url+'search/TITLES/{query}&p={pageno}' | search_url = url + 'search/TITLES/{query}&p={pageno}' | ||||||
| 
 | 
 | ||||||
| # specific xpath variables | # specific xpath variables | ||||||
| results_xpath = '//div[@class="boxRows"]' | results_xpath = '//div[@class="boxRows"]' | ||||||
| @ -44,7 +45,7 @@ def response(resp): | |||||||
|     if resp.search_params['language'] != 'all': |     if resp.search_params['language'] != 'all': | ||||||
|         search_lang = [lc[1] |         search_lang = [lc[1] | ||||||
|                        for lc in language_codes |                        for lc in language_codes | ||||||
|                        if lc[0][:2] == resp.search_params['language']][0] |                        if lc[0][:2] == resp.search_params['language'].split('_')[0]][0] | ||||||
| 
 | 
 | ||||||
|     # parse results |     # parse results | ||||||
|     for result in dom.xpath(results_xpath): |     for result in dom.xpath(results_xpath): | ||||||
| @ -56,17 +57,17 @@ def response(resp): | |||||||
|         elif search_lang: |         elif search_lang: | ||||||
|             href = href + search_lang + '/' |             href = href + search_lang + '/' | ||||||
| 
 | 
 | ||||||
|         title = escape(link.xpath(".//text()")[0]) |         title = escape(extract_text(link)) | ||||||
| 
 | 
 | ||||||
|         content = result.xpath('.//div[contains(@class,"red")]//text()')[0] |         content = extract_text(result.xpath('.//div[contains(@class,"red")]')) | ||||||
|         content = content + " - " |         content = content + " - " | ||||||
|         text = result.xpath('.//div[contains(@class,"grey-web")]')[0] |         text = extract_text(result.xpath('.//div[contains(@class,"grey-web")]')[0]) | ||||||
|         content = content + html.tostring(text, method='text') |         content = content + text | ||||||
| 
 | 
 | ||||||
|         if result.xpath(".//span") != []: |         if result.xpath(".//span") != []: | ||||||
|             content = content +\ |             content = content +\ | ||||||
|                 " - (" +\ |                 " - (" +\ | ||||||
|                 result.xpath(".//span//text()")[0].strip() +\ |                 extract_text(result.xpath(".//span")) +\ | ||||||
|                 ")" |                 ")" | ||||||
| 
 | 
 | ||||||
|         # append result |         # append result | ||||||
|  | |||||||
| @ -13,8 +13,8 @@ | |||||||
| from urlparse import urljoin | from urlparse import urljoin | ||||||
| from urllib import urlencode | from urllib import urlencode | ||||||
| from lxml import html | from lxml import html | ||||||
| from cgi import escape |  | ||||||
| from datetime import datetime | from datetime import datetime | ||||||
|  | from searx.engines.xpath import extract_text | ||||||
| 
 | 
 | ||||||
| # engine dependent config | # engine dependent config | ||||||
| categories = ['social media'] | categories = ['social media'] | ||||||
| @ -22,12 +22,12 @@ language_support = True | |||||||
| 
 | 
 | ||||||
| # search-url | # search-url | ||||||
| base_url = 'https://twitter.com/' | base_url = 'https://twitter.com/' | ||||||
| search_url = base_url+'search?' | search_url = base_url + 'search?' | ||||||
| 
 | 
 | ||||||
| # specific xpath variables | # specific xpath variables | ||||||
| results_xpath = '//li[@data-item-type="tweet"]' | results_xpath = '//li[@data-item-type="tweet"]' | ||||||
| link_xpath = './/small[@class="time"]//a' | link_xpath = './/small[@class="time"]//a' | ||||||
| title_xpath = './/span[@class="username js-action-profile-name"]//text()' | title_xpath = './/span[@class="username js-action-profile-name"]' | ||||||
| content_xpath = './/p[@class="js-tweet-text tweet-text"]' | content_xpath = './/p[@class="js-tweet-text tweet-text"]' | ||||||
| timestamp_xpath = './/span[contains(@class,"_timestamp")]' | timestamp_xpath = './/span[contains(@class,"_timestamp")]' | ||||||
| 
 | 
 | ||||||
| @ -39,6 +39,8 @@ def request(query, params): | |||||||
|     # set language if specified |     # set language if specified | ||||||
|     if params['language'] != 'all': |     if params['language'] != 'all': | ||||||
|         params['cookies']['lang'] = params['language'].split('_')[0] |         params['cookies']['lang'] = params['language'].split('_')[0] | ||||||
|  |     else: | ||||||
|  |         params['cookies']['lang'] = 'en' | ||||||
| 
 | 
 | ||||||
|     return params |     return params | ||||||
| 
 | 
 | ||||||
| @ -53,8 +55,9 @@ def response(resp): | |||||||
|     for tweet in dom.xpath(results_xpath): |     for tweet in dom.xpath(results_xpath): | ||||||
|         link = tweet.xpath(link_xpath)[0] |         link = tweet.xpath(link_xpath)[0] | ||||||
|         url = urljoin(base_url, link.attrib.get('href')) |         url = urljoin(base_url, link.attrib.get('href')) | ||||||
|         title = ''.join(tweet.xpath(title_xpath)) |         title = extract_text(tweet.xpath(title_xpath)) | ||||||
|         content = escape(html.tostring(tweet.xpath(content_xpath)[0], method='text', encoding='UTF-8').decode("utf-8")) |         content = extract_text(tweet.xpath(content_xpath)[0]) | ||||||
|  | 
 | ||||||
|         pubdate = tweet.xpath(timestamp_xpath) |         pubdate = tweet.xpath(timestamp_xpath) | ||||||
|         if len(pubdate) > 0: |         if len(pubdate) > 0: | ||||||
|             timestamp = float(pubdate[0].attrib.get('data-time')) |             timestamp = float(pubdate[0].attrib.get('data-time')) | ||||||
|  | |||||||
| @ -28,7 +28,7 @@ search_url = '/yacysearch.json?{query}'\ | |||||||
|              '&startRecord={offset}'\ |              '&startRecord={offset}'\ | ||||||
|              '&maximumRecords={limit}'\ |              '&maximumRecords={limit}'\ | ||||||
|              '&contentdom={search_type}'\ |              '&contentdom={search_type}'\ | ||||||
|                              '&resource=global'             # noqa |              '&resource=global' | ||||||
| 
 | 
 | ||||||
| # yacy specific type-definitions | # yacy specific type-definitions | ||||||
| search_types = {'general': 'text', | search_types = {'general': 'text', | ||||||
| @ -41,7 +41,7 @@ search_types = {'general': 'text', | |||||||
| # do search-request | # do search-request | ||||||
| def request(query, params): | def request(query, params): | ||||||
|     offset = (params['pageno'] - 1) * number_of_results |     offset = (params['pageno'] - 1) * number_of_results | ||||||
|     search_type = search_types.get(params['category'], '0') |     search_type = search_types.get(params.get('category'), '0') | ||||||
| 
 | 
 | ||||||
|     params['url'] = base_url +\ |     params['url'] = base_url +\ | ||||||
|         search_url.format(query=urlencode({'query': query}), |         search_url.format(query=urlencode({'query': query}), | ||||||
| @ -66,9 +66,12 @@ def response(resp): | |||||||
|     if not raw_search_results: |     if not raw_search_results: | ||||||
|         return [] |         return [] | ||||||
| 
 | 
 | ||||||
|     search_results = raw_search_results.get('channels', {})[0].get('items', []) |     search_results = raw_search_results.get('channels', []) | ||||||
| 
 | 
 | ||||||
|     for result in search_results: |     if len(search_results) == 0: | ||||||
|  |         return [] | ||||||
|  | 
 | ||||||
|  |     for result in search_results[0].get('items', []): | ||||||
|         # parse image results |         # parse image results | ||||||
|         if result.get('image'): |         if result.get('image'): | ||||||
|             # append result |             # append result | ||||||
| @ -88,7 +91,7 @@ def response(resp): | |||||||
|                             'content': result['description'], |                             'content': result['description'], | ||||||
|                             'publishedDate': publishedDate}) |                             'publishedDate': publishedDate}) | ||||||
| 
 | 
 | ||||||
|         #TODO parse video, audio and file results |         # TODO parse video, audio and file results | ||||||
| 
 | 
 | ||||||
|     # return results |     # return results | ||||||
|     return results |     return results | ||||||
|  | |||||||
| @ -35,7 +35,7 @@ suggestion_xpath = '//div[@id="satat"]//a' | |||||||
| def parse_url(url_string): | def parse_url(url_string): | ||||||
|     endings = ['/RS', '/RK'] |     endings = ['/RS', '/RK'] | ||||||
|     endpositions = [] |     endpositions = [] | ||||||
|     start = url_string.find('http', url_string.find('/RU=')+1) |     start = url_string.find('http', url_string.find('/RU=') + 1) | ||||||
| 
 | 
 | ||||||
|     for ending in endings: |     for ending in endings: | ||||||
|         endpos = url_string.rfind(ending) |         endpos = url_string.rfind(ending) | ||||||
| @ -91,7 +91,7 @@ def response(resp): | |||||||
|                         'content': content}) |                         'content': content}) | ||||||
| 
 | 
 | ||||||
|     # if no suggestion found, return results |     # if no suggestion found, return results | ||||||
|     if not suggestion_xpath: |     if not dom.xpath(suggestion_xpath): | ||||||
|         return results |         return results | ||||||
| 
 | 
 | ||||||
|     # parse suggestion |     # parse suggestion | ||||||
|  | |||||||
							
								
								
									
										44
									
								
								searx/tests/engines/test_currency_convert.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								searx/tests/engines/test_currency_convert.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | |||||||
|  | from collections import defaultdict | ||||||
|  | from datetime import datetime | ||||||
|  | import mock | ||||||
|  | from searx.engines import currency_convert | ||||||
|  | from searx.testing import SearxTestCase | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestCurrencyConvertEngine(SearxTestCase): | ||||||
|  | 
 | ||||||
|  |     def test_request(self): | ||||||
|  |         query = 'test_query' | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['pageno'] = 1 | ||||||
|  |         params = currency_convert.request(query, dicto) | ||||||
|  |         self.assertNotIn('url', params) | ||||||
|  | 
 | ||||||
|  |         query = '1.1.1 EUR in USD' | ||||||
|  |         params = currency_convert.request(query, dicto) | ||||||
|  |         self.assertNotIn('url', params) | ||||||
|  | 
 | ||||||
|  |         query = '10 eur in usd' | ||||||
|  |         params = currency_convert.request(query, dicto) | ||||||
|  |         self.assertIn('url', params) | ||||||
|  |         self.assertIn('finance.yahoo.com', params['url']) | ||||||
|  |         self.assertIn('EUR', params['url']) | ||||||
|  |         self.assertIn('USD', params['url']) | ||||||
|  | 
 | ||||||
|  |     def test_response(self): | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['ammount'] = 10 | ||||||
|  |         dicto['from'] = "EUR" | ||||||
|  |         dicto['to'] = "USD" | ||||||
|  |         response = mock.Mock(text='a,b,c,d', search_params=dicto) | ||||||
|  |         self.assertEqual(currency_convert.response(response), []) | ||||||
|  | 
 | ||||||
|  |         csv = "2,0.5,1" | ||||||
|  |         response = mock.Mock(text=csv, search_params=dicto) | ||||||
|  |         results = currency_convert.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 1) | ||||||
|  |         self.assertEqual(results[0]['answer'], '10 EUR = 5.0 USD (1 EUR = 0.5 USD)') | ||||||
|  |         now_date = datetime.now().strftime('%Y%m%d') | ||||||
|  |         self.assertEqual(results[0]['url'], 'http://finance.yahoo.com/currency/converter-results/' + | ||||||
|  |                                             now_date + '/10-eur-to-usd.html') | ||||||
							
								
								
									
										90
									
								
								searx/tests/engines/test_duckduckgo.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								searx/tests/engines/test_duckduckgo.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,90 @@ | |||||||
|  | from collections import defaultdict | ||||||
|  | import mock | ||||||
|  | from searx.engines import duckduckgo | ||||||
|  | from searx.testing import SearxTestCase | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestDuckduckgoEngine(SearxTestCase): | ||||||
|  | 
 | ||||||
|  |     def test_request(self): | ||||||
|  |         query = 'test_query' | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['pageno'] = 1 | ||||||
|  |         dicto['language'] = 'fr_FR' | ||||||
|  |         params = duckduckgo.request(query, dicto) | ||||||
|  |         self.assertIn('url', params) | ||||||
|  |         self.assertIn(query, params['url']) | ||||||
|  |         self.assertIn('duckduckgo.com', params['url']) | ||||||
|  |         self.assertIn('fr-fr', params['url']) | ||||||
|  | 
 | ||||||
|  |         dicto['language'] = 'all' | ||||||
|  |         params = duckduckgo.request(query, dicto) | ||||||
|  |         self.assertIn('en-us', params['url']) | ||||||
|  | 
 | ||||||
|  |     def test_response(self): | ||||||
|  |         self.assertRaises(AttributeError, duckduckgo.response, None) | ||||||
|  |         self.assertRaises(AttributeError, duckduckgo.response, []) | ||||||
|  |         self.assertRaises(AttributeError, duckduckgo.response, '') | ||||||
|  |         self.assertRaises(AttributeError, duckduckgo.response, '[]') | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='<html></html>') | ||||||
|  |         self.assertEqual(duckduckgo.response(response), []) | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <div class="results_links results_links_deep web-result"> | ||||||
|  |             <div class="icon_fav" style="display: block;"> | ||||||
|  |                 <a rel="nofollow" href="https://www.test.com/"> | ||||||
|  |                     <img width="16" height="16" alt="" | ||||||
|  |                     src="/i/www.test.com.ico" style="visibility: visible;" name="i15" /> | ||||||
|  |                 </a> | ||||||
|  |             </div> | ||||||
|  |             <div class="links_main links_deep"> <!-- This is the visible part --> | ||||||
|  |                 <a rel="nofollow" class="large" href="http://this.should.be.the.link/"> | ||||||
|  |                     This <b>is</b> <b>the</b> title | ||||||
|  |                 </a> | ||||||
|  |                 <div class="snippet"><b>This</b> should be the content.</div> | ||||||
|  |                 <div class="url"> | ||||||
|  |                     http://this.should.be.the.link/ | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=html) | ||||||
|  |         results = duckduckgo.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 1) | ||||||
|  |         self.assertEqual(results[0]['title'], 'This is the title') | ||||||
|  |         self.assertEqual(results[0]['url'], 'http://this.should.be.the.link/') | ||||||
|  |         self.assertEqual(results[0]['content'], 'This should be the content.') | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <div class="results_links results_links_deep web-result"> | ||||||
|  |             <div class="icon_fav" style="display: block;"> | ||||||
|  |             </div> | ||||||
|  |             <div class="links_main links_deep"> <!-- This is the visible part --> | ||||||
|  |                 <div class="snippet"><b>This</b> should be the content.</div> | ||||||
|  |                 <div class="url"> | ||||||
|  |                     http://this.should.be.the.link/ | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="results_links results_links_deep web-result"> | ||||||
|  |             <div class="icon_fav" style="display: block;"> | ||||||
|  |                 <img width="16" height="16" alt="" | ||||||
|  |                 src="/i/www.test.com.ico" style="visibility: visible;" name="i15" /> | ||||||
|  |             </div> | ||||||
|  |             <div class="links_main links_deep"> <!-- This is the visible part --> | ||||||
|  |                 <a rel="nofollow" class="large" href=""> | ||||||
|  |                     This <b>is</b> <b>the</b> title | ||||||
|  |                 </a> | ||||||
|  |                 <div class="snippet"><b>This</b> should be the content.</div> | ||||||
|  |                 <div class="url"> | ||||||
|  |                     http://this.should.be.the.link/ | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=html) | ||||||
|  |         results = duckduckgo.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 0) | ||||||
							
								
								
									
										250
									
								
								searx/tests/engines/test_duckduckgo_definitions.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										250
									
								
								searx/tests/engines/test_duckduckgo_definitions.py
									
									
									
									
									
										Normal file
									
								
							| @ -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 = '<a href="url">Text in link</a>' | ||||||
|  |         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']) | ||||||
							
								
								
									
										116
									
								
								searx/tests/engines/test_faroo.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								searx/tests/engines/test_faroo.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,116 @@ | |||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | from collections import defaultdict | ||||||
|  | import mock | ||||||
|  | from searx.engines import faroo | ||||||
|  | from searx.testing import SearxTestCase | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestFarooEngine(SearxTestCase): | ||||||
|  | 
 | ||||||
|  |     def test_request(self): | ||||||
|  |         query = 'test_query' | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['pageno'] = 1 | ||||||
|  |         dicto['language'] = 'fr_FR' | ||||||
|  |         dicto['category'] = 'general' | ||||||
|  |         params = faroo.request(query, dicto) | ||||||
|  |         self.assertIn('url', params) | ||||||
|  |         self.assertIn(query, params['url']) | ||||||
|  |         self.assertIn('faroo.com', params['url']) | ||||||
|  |         self.assertIn('en', params['url']) | ||||||
|  |         self.assertIn('web', params['url']) | ||||||
|  | 
 | ||||||
|  |         dicto['language'] = 'all' | ||||||
|  |         params = faroo.request(query, dicto) | ||||||
|  |         self.assertIn('en', params['url']) | ||||||
|  | 
 | ||||||
|  |         dicto['language'] = 'de_DE' | ||||||
|  |         params = faroo.request(query, dicto) | ||||||
|  |         self.assertIn('de', params['url']) | ||||||
|  | 
 | ||||||
|  |     def test_response(self): | ||||||
|  |         self.assertRaises(AttributeError, faroo.response, None) | ||||||
|  |         self.assertRaises(AttributeError, faroo.response, []) | ||||||
|  |         self.assertRaises(AttributeError, faroo.response, '') | ||||||
|  |         self.assertRaises(AttributeError, faroo.response, '[]') | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='{}') | ||||||
|  |         self.assertEqual(faroo.response(response), []) | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='{"data": []}') | ||||||
|  |         self.assertEqual(faroo.response(response), []) | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='{"data": []}', status_code=401) | ||||||
|  |         self.assertRaises(Exception, faroo.response, response) | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='{"data": []}', status_code=429) | ||||||
|  |         self.assertRaises(Exception, faroo.response, response) | ||||||
|  | 
 | ||||||
|  |         json = """ | ||||||
|  |         { | ||||||
|  |           "results": [ | ||||||
|  |             { | ||||||
|  |               "title": "This is the title", | ||||||
|  |               "kwic": "This is the content", | ||||||
|  |               "content": "", | ||||||
|  |               "url": "http://this.is.the.url/", | ||||||
|  |               "iurl": "", | ||||||
|  |               "domain": "css3test.com", | ||||||
|  |               "author": "Jim Dalrymple", | ||||||
|  |               "news": true, | ||||||
|  |               "votes": "10", | ||||||
|  |               "date": 1360622563000, | ||||||
|  |               "related": [] | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |               "title": "This is the title2", | ||||||
|  |               "kwic": "This is the content2", | ||||||
|  |               "content": "", | ||||||
|  |               "url": "http://this.is.the.url2/", | ||||||
|  |               "iurl": "", | ||||||
|  |               "domain": "css3test.com", | ||||||
|  |               "author": "Jim Dalrymple", | ||||||
|  |               "news": false, | ||||||
|  |               "votes": "10", | ||||||
|  |               "related": [] | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |               "title": "This is the title3", | ||||||
|  |               "kwic": "This is the content3", | ||||||
|  |               "content": "", | ||||||
|  |               "url": "http://this.is.the.url3/", | ||||||
|  |               "iurl": "http://upload.wikimedia.org/optimized.jpg", | ||||||
|  |               "domain": "css3test.com", | ||||||
|  |               "author": "Jim Dalrymple", | ||||||
|  |               "news": false, | ||||||
|  |               "votes": "10", | ||||||
|  |               "related": [] | ||||||
|  |             } | ||||||
|  |           ], | ||||||
|  |           "query": "test", | ||||||
|  |           "suggestions": [], | ||||||
|  |           "count": 100, | ||||||
|  |           "start": 1, | ||||||
|  |           "length": 10, | ||||||
|  |           "time": "15" | ||||||
|  |         } | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=json) | ||||||
|  |         results = faroo.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 4) | ||||||
|  |         self.assertEqual(results[0]['title'], 'This is the title') | ||||||
|  |         self.assertEqual(results[0]['url'], 'http://this.is.the.url/') | ||||||
|  |         self.assertEqual(results[0]['content'], 'This is the content') | ||||||
|  |         self.assertEqual(results[1]['title'], 'This is the title2') | ||||||
|  |         self.assertEqual(results[1]['url'], 'http://this.is.the.url2/') | ||||||
|  |         self.assertEqual(results[1]['content'], 'This is the content2') | ||||||
|  |         self.assertEqual(results[3]['img_src'], 'http://upload.wikimedia.org/optimized.jpg') | ||||||
|  | 
 | ||||||
|  |         json = """ | ||||||
|  |         {} | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=json) | ||||||
|  |         results = faroo.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 0) | ||||||
							
								
								
									
										162
									
								
								searx/tests/engines/test_google.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								searx/tests/engines/test_google.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,162 @@ | |||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | from collections import defaultdict | ||||||
|  | import mock | ||||||
|  | import lxml | ||||||
|  | from searx.engines import google | ||||||
|  | from searx.testing import SearxTestCase | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestGoogleEngine(SearxTestCase): | ||||||
|  | 
 | ||||||
|  |     def test_request(self): | ||||||
|  |         query = 'test_query' | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['pageno'] = 1 | ||||||
|  |         dicto['language'] = 'fr_FR' | ||||||
|  |         params = google.request(query, dicto) | ||||||
|  |         self.assertIn('url', params) | ||||||
|  |         self.assertIn(query, params['url']) | ||||||
|  |         self.assertIn('google.com', params['url']) | ||||||
|  |         self.assertIn('PREF', params['cookies']) | ||||||
|  |         self.assertIn('fr', params['headers']['Accept-Language']) | ||||||
|  | 
 | ||||||
|  |         dicto['language'] = 'all' | ||||||
|  |         params = google.request(query, dicto) | ||||||
|  |         self.assertIn('en', params['headers']['Accept-Language']) | ||||||
|  | 
 | ||||||
|  |     def test_response(self): | ||||||
|  |         self.assertRaises(AttributeError, google.response, None) | ||||||
|  |         self.assertRaises(AttributeError, google.response, []) | ||||||
|  |         self.assertRaises(AttributeError, google.response, '') | ||||||
|  |         self.assertRaises(AttributeError, google.response, '[]') | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='<html></html>') | ||||||
|  |         self.assertEqual(google.response(response), []) | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <li class="g"> | ||||||
|  |             <h3 class="r"> | ||||||
|  |                 <a href="http://this.should.be.the.link/"> | ||||||
|  |                     <b>This</b> is <b>the</b> title | ||||||
|  |                 </a> | ||||||
|  |             </h3> | ||||||
|  |             <div class="s"> | ||||||
|  |                 <div class="kv" style="margin-bottom:2px"> | ||||||
|  |                     <cite> | ||||||
|  |                         <b>test</b>.psychologies.com/ | ||||||
|  |                     </cite> | ||||||
|  |                     <div class="_nBb"> | ||||||
|  |                         <div style="display:inline" onclick="google.sham(this);" aria-expanded="false" | ||||||
|  |                             aria-haspopup="true" tabindex="0" data-ved="0CBUQ7B0wAA"> | ||||||
|  |                             <span class="_O0"> | ||||||
|  |                             </span> | ||||||
|  |                         </div> | ||||||
|  |                         <div style="display:none" class="am-dropdown-menu" role="menu" tabindex="-1"> | ||||||
|  |                             <ul> | ||||||
|  |                                 <li class="_Ykb"> | ||||||
|  |                                     <a class="_Zkb" href="http://www.google.fr/url?url=http://webcache.googleusercontent | ||||||
|  |                                         .com/search%3Fcache:R1Z_4pGXjuIJ:http://test.psychologies.com/"> | ||||||
|  |                                         En cache | ||||||
|  |                                     </a> | ||||||
|  |                                 </li> | ||||||
|  |                                 <li class="_Ykb"> | ||||||
|  |                                     <a class="_Zkb" href="/search?safe=off&q=related:test.psy.com/"> | ||||||
|  |                                         Pages similaires | ||||||
|  |                                     </a> | ||||||
|  |                                 </li> | ||||||
|  |                             </ul> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |                 <span class="st"> | ||||||
|  |                     This should be the content. | ||||||
|  |                 </span> | ||||||
|  |                 <br> | ||||||
|  |                 <div class="osl"> | ||||||
|  |                     <a href="http://www.google.fr/url?url=http://test.psychologies.com/tests/"> | ||||||
|  |                         Test Personnalité | ||||||
|  |                     </a> -  | ||||||
|  |                     <a href="http://www.google.fr/url?url=http://test.psychologies.com/test/"> | ||||||
|  |                         Tests - Moi | ||||||
|  |                     </a> -  | ||||||
|  |                     <a href="http://www.google.fr/url?url=http://test.psychologies.com/test/tests-couple"> | ||||||
|  |                         Test Couple | ||||||
|  |                     </a> | ||||||
|  |                     -  | ||||||
|  |                     <a href="http://www.google.fr/url?url=http://test.psychologies.com/tests/tests-amour"> | ||||||
|  |                         Test Amour | ||||||
|  |                     </a> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </li> | ||||||
|  |         <li class="g"> | ||||||
|  |             <h3 class="r"> | ||||||
|  |                 <a href="http://www.google.com/images?q=toto"> | ||||||
|  |                     <b>This</b> | ||||||
|  |                 </a> | ||||||
|  |             </h3> | ||||||
|  |         </li> | ||||||
|  |         <li class="g"> | ||||||
|  |             <h3 class="r"> | ||||||
|  |                 <a href="http://www.google.com/search?q=toto"> | ||||||
|  |                     <b>This</b> is | ||||||
|  |                 </a> | ||||||
|  |             </h3> | ||||||
|  |         </li> | ||||||
|  |         <li class="g"> | ||||||
|  |             <h3 class="r"> | ||||||
|  |                 <a href="€"> | ||||||
|  |                     <b>This</b> is <b>the</b> | ||||||
|  |                 </a> | ||||||
|  |             </h3> | ||||||
|  |         </li> | ||||||
|  |         <li class="g"> | ||||||
|  |             <h3 class="r"> | ||||||
|  |                 <a href="/url?q=url"> | ||||||
|  |                     <b>This</b> is <b>the</b> | ||||||
|  |                 </a> | ||||||
|  |             </h3> | ||||||
|  |         </li> | ||||||
|  |         <p class="_Bmc" style="margin:3px 8px"> | ||||||
|  |             <a href="/search?num=20&safe=off&q=t&revid=1754833769&sa=X&ei=-&ved="> | ||||||
|  |                 suggestion <b>title</b> | ||||||
|  |             </a> | ||||||
|  |         </p> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=html) | ||||||
|  |         results = google.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 2) | ||||||
|  |         self.assertEqual(results[0]['title'], 'This is the title') | ||||||
|  |         self.assertEqual(results[0]['url'], 'http://this.should.be.the.link/') | ||||||
|  |         self.assertEqual(results[0]['content'], 'This should be the content.') | ||||||
|  |         self.assertEqual(results[1]['suggestion'], 'suggestion title') | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <li class="b_algo" u="0|5109|4755453613245655|UAGjXgIrPH5yh-o5oNHRx_3Zta87f_QO"> | ||||||
|  |         </li> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=html) | ||||||
|  |         results = google.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 0) | ||||||
|  | 
 | ||||||
|  |     def test_parse_images(self): | ||||||
|  |         html = """ | ||||||
|  |         <li> | ||||||
|  |             <div> | ||||||
|  |                 <a href="http://www.google.com/url?q=http://this.is.the.url/"> | ||||||
|  |                     <img style="margin:3px 0;margin-right:6px;padding:0" height="90" | ||||||
|  |                         src="https://this.is.the.image/image.jpg" width="60" align="middle" alt="" border="0"> | ||||||
|  |                 </a> | ||||||
|  |             </div> | ||||||
|  |         </li> | ||||||
|  |         """ | ||||||
|  |         dom = lxml.html.fromstring(html) | ||||||
|  |         results = google.parse_images(dom) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 1) | ||||||
|  |         self.assertEqual(results[0]['url'], 'http://this.is.the.url/') | ||||||
|  |         self.assertEqual(results[0]['title'], '') | ||||||
|  |         self.assertEqual(results[0]['content'], '') | ||||||
|  |         self.assertEqual(results[0]['img_src'], 'https://this.is.the.image/image.jpg') | ||||||
							
								
								
									
										130
									
								
								searx/tests/engines/test_mediawiki.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								searx/tests/engines/test_mediawiki.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,130 @@ | |||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | from collections import defaultdict | ||||||
|  | import mock | ||||||
|  | from searx.engines import mediawiki | ||||||
|  | from searx.testing import SearxTestCase | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestMediawikiEngine(SearxTestCase): | ||||||
|  | 
 | ||||||
|  |     def test_request(self): | ||||||
|  |         query = 'test_query' | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['pageno'] = 1 | ||||||
|  |         dicto['language'] = 'fr_FR' | ||||||
|  |         params = mediawiki.request(query, dicto) | ||||||
|  |         self.assertIn('url', params) | ||||||
|  |         self.assertIn(query, params['url']) | ||||||
|  |         self.assertIn('wikipedia.org', params['url']) | ||||||
|  |         self.assertIn('fr', params['url']) | ||||||
|  | 
 | ||||||
|  |         dicto['language'] = 'all' | ||||||
|  |         params = mediawiki.request(query, dicto) | ||||||
|  |         self.assertIn('en', params['url']) | ||||||
|  | 
 | ||||||
|  |         mediawiki.base_url = "http://test.url/" | ||||||
|  |         mediawiki.search_url = mediawiki.base_url +\ | ||||||
|  |                                  'w/api.php?action=query'\ | ||||||
|  |                                  '&list=search'\ | ||||||
|  |                                  '&{query}'\ | ||||||
|  |                                  '&srprop=timestamp'\ | ||||||
|  |                                  '&format=json'\ | ||||||
|  |                                  '&sroffset={offset}'\ | ||||||
|  |                                  '&srlimit={limit}'     # noqa | ||||||
|  |         params = mediawiki.request(query, dicto) | ||||||
|  |         self.assertIn('test.url', params['url']) | ||||||
|  | 
 | ||||||
|  |     def test_response(self): | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['language'] = 'fr' | ||||||
|  |         mediawiki.base_url = "https://{language}.wikipedia.org/" | ||||||
|  | 
 | ||||||
|  |         self.assertRaises(AttributeError, mediawiki.response, None) | ||||||
|  |         self.assertRaises(AttributeError, mediawiki.response, []) | ||||||
|  |         self.assertRaises(AttributeError, mediawiki.response, '') | ||||||
|  |         self.assertRaises(AttributeError, mediawiki.response, '[]') | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='{}', search_params=dicto) | ||||||
|  |         self.assertEqual(mediawiki.response(response), []) | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='{"data": []}', search_params=dicto) | ||||||
|  |         self.assertEqual(mediawiki.response(response), []) | ||||||
|  | 
 | ||||||
|  |         json = """ | ||||||
|  |         { | ||||||
|  |             "query-continue": { | ||||||
|  |                 "search": { | ||||||
|  |                     "sroffset": 1 | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             "query": { | ||||||
|  |                 "searchinfo": { | ||||||
|  |                     "totalhits": 29721 | ||||||
|  |                 }, | ||||||
|  |                 "search": [ | ||||||
|  |                     { | ||||||
|  |                         "ns": 0, | ||||||
|  |                         "title": "This is the title étude", | ||||||
|  |                         "timestamp": "2014-12-19T17:42:52Z" | ||||||
|  |                     } | ||||||
|  |                 ] | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=json, search_params=dicto) | ||||||
|  |         results = mediawiki.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 1) | ||||||
|  |         self.assertEqual(results[0]['title'], u'This is the title étude') | ||||||
|  |         self.assertIn('fr.wikipedia.org', results[0]['url']) | ||||||
|  |         self.assertIn('This_is_the_title', results[0]['url']) | ||||||
|  |         self.assertIn('%C3%A9tude', results[0]['url']) | ||||||
|  |         self.assertEqual(results[0]['content'], '') | ||||||
|  | 
 | ||||||
|  |         json = """ | ||||||
|  |         { | ||||||
|  |             "query-continue": { | ||||||
|  |                 "search": { | ||||||
|  |                     "sroffset": 1 | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             "query": { | ||||||
|  |                 "searchinfo": { | ||||||
|  |                     "totalhits": 29721 | ||||||
|  |                 }, | ||||||
|  |                 "search": [ | ||||||
|  |                 ] | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=json, search_params=dicto) | ||||||
|  |         results = mediawiki.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 0) | ||||||
|  | 
 | ||||||
|  |         json = """ | ||||||
|  |         { | ||||||
|  |             "query-continue": { | ||||||
|  |                 "search": { | ||||||
|  |                     "sroffset": 1 | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             "query": { | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=json, search_params=dicto) | ||||||
|  |         results = mediawiki.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 0) | ||||||
|  | 
 | ||||||
|  |         json = """ | ||||||
|  |         {"toto":[ | ||||||
|  |             {"id":200,"name":"Artist Name", | ||||||
|  |             "link":"http:\/\/www.mediawiki.com\/artist\/1217","type":"artist"} | ||||||
|  |         ]} | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=json, search_params=dicto) | ||||||
|  |         results = mediawiki.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 0) | ||||||
							
								
								
									
										199
									
								
								searx/tests/engines/test_openstreetmap.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								searx/tests/engines/test_openstreetmap.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,199 @@ | |||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | from collections import defaultdict | ||||||
|  | import mock | ||||||
|  | from searx.engines import openstreetmap | ||||||
|  | from searx.testing import SearxTestCase | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestOpenstreetmapEngine(SearxTestCase): | ||||||
|  | 
 | ||||||
|  |     def test_request(self): | ||||||
|  |         query = 'test_query' | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['pageno'] = 1 | ||||||
|  |         params = openstreetmap.request(query, dicto) | ||||||
|  |         self.assertIn('url', params) | ||||||
|  |         self.assertIn(query, params['url']) | ||||||
|  |         self.assertIn('openstreetmap.org', params['url']) | ||||||
|  | 
 | ||||||
|  |     def test_response(self): | ||||||
|  |         self.assertRaises(AttributeError, openstreetmap.response, None) | ||||||
|  |         self.assertRaises(AttributeError, openstreetmap.response, []) | ||||||
|  |         self.assertRaises(AttributeError, openstreetmap.response, '') | ||||||
|  |         self.assertRaises(AttributeError, openstreetmap.response, '[]') | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='{}') | ||||||
|  |         self.assertEqual(openstreetmap.response(response), []) | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='{"data": []}') | ||||||
|  |         self.assertEqual(openstreetmap.response(response), []) | ||||||
|  | 
 | ||||||
|  |         json = """ | ||||||
|  |         [ | ||||||
|  |           { | ||||||
|  |             "place_id": "127732055", | ||||||
|  |             "licence": "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright", | ||||||
|  |             "osm_type": "relation", | ||||||
|  |             "osm_id": "7444", | ||||||
|  |             "boundingbox": [ | ||||||
|  |               "48.8155755", | ||||||
|  |               "48.902156", | ||||||
|  |               "2.224122", | ||||||
|  |               "2.4697602" | ||||||
|  |             ], | ||||||
|  |             "lat": "48.8565056", | ||||||
|  |             "lon": "2.3521334", | ||||||
|  |             "display_name": "This is the title", | ||||||
|  |             "class": "place", | ||||||
|  |             "type": "city", | ||||||
|  |             "importance": 0.96893459932191, | ||||||
|  |             "icon": "https://nominatim.openstreetmap.org/images/mapicons/poi_place_city.p.20.png", | ||||||
|  |             "address": { | ||||||
|  |               "city": "Paris", | ||||||
|  |               "county": "Paris", | ||||||
|  |               "state": "Île-de-France", | ||||||
|  |               "country": "France", | ||||||
|  |               "country_code": "fr" | ||||||
|  |             }, | ||||||
|  |             "geojson": { | ||||||
|  |               "type": "Polygon", | ||||||
|  |               "coordinates": [ | ||||||
|  |                 [ | ||||||
|  |                   [ | ||||||
|  |                     2.224122, | ||||||
|  |                     48.854199 | ||||||
|  |                   ] | ||||||
|  |                 ] | ||||||
|  |               ] | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=json) | ||||||
|  |         results = openstreetmap.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 1) | ||||||
|  |         self.assertEqual(results[0]['title'], 'This is the title') | ||||||
|  |         self.assertEqual(results[0]['url'], 'https://openstreetmap.org/relation/7444') | ||||||
|  |         self.assertIn('coordinates', results[0]['geojson']) | ||||||
|  |         self.assertEqual(results[0]['geojson']['coordinates'][0][0][0], 2.224122) | ||||||
|  |         self.assertEqual(results[0]['geojson']['coordinates'][0][0][1], 48.854199) | ||||||
|  |         self.assertEqual(results[0]['address'], None) | ||||||
|  |         self.assertIn('48.8155755', results[0]['boundingbox']) | ||||||
|  |         self.assertIn('48.902156', results[0]['boundingbox']) | ||||||
|  |         self.assertIn('2.224122', results[0]['boundingbox']) | ||||||
|  |         self.assertIn('2.4697602', results[0]['boundingbox']) | ||||||
|  | 
 | ||||||
|  |         json = """ | ||||||
|  |         [ | ||||||
|  |           { | ||||||
|  |             "place_id": "127732055", | ||||||
|  |             "licence": "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright", | ||||||
|  |             "osm_type": "relation", | ||||||
|  |             "osm_id": "7444", | ||||||
|  |             "boundingbox": [ | ||||||
|  |               "48.8155755", | ||||||
|  |               "48.902156", | ||||||
|  |               "2.224122", | ||||||
|  |               "2.4697602" | ||||||
|  |             ], | ||||||
|  |             "lat": "48.8565056", | ||||||
|  |             "lon": "2.3521334", | ||||||
|  |             "display_name": "This is the title", | ||||||
|  |             "class": "tourism", | ||||||
|  |             "type": "city", | ||||||
|  |             "importance": 0.96893459932191, | ||||||
|  |             "icon": "https://nominatim.openstreetmap.org/images/mapicons/poi_place_city.p.20.png", | ||||||
|  |             "address": { | ||||||
|  |               "city": "Paris", | ||||||
|  |               "county": "Paris", | ||||||
|  |               "state": "Île-de-France", | ||||||
|  |               "country": "France", | ||||||
|  |               "country_code": "fr", | ||||||
|  |               "address29": "Address" | ||||||
|  |             }, | ||||||
|  |             "geojson": { | ||||||
|  |               "type": "Polygon", | ||||||
|  |               "coordinates": [ | ||||||
|  |                 [ | ||||||
|  |                   [ | ||||||
|  |                     2.224122, | ||||||
|  |                     48.854199 | ||||||
|  |                   ] | ||||||
|  |                 ] | ||||||
|  |               ] | ||||||
|  |             } | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "place_id": "127732055", | ||||||
|  |             "licence": "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright", | ||||||
|  |             "osm_type": "relation", | ||||||
|  |             "osm_id": "7444", | ||||||
|  |             "boundingbox": [ | ||||||
|  |               "48.8155755", | ||||||
|  |               "48.902156", | ||||||
|  |               "2.224122", | ||||||
|  |               "2.4697602" | ||||||
|  |             ], | ||||||
|  |             "lat": "48.8565056", | ||||||
|  |             "lon": "2.3521334", | ||||||
|  |             "display_name": "This is the title", | ||||||
|  |             "class": "tourism", | ||||||
|  |             "type": "city", | ||||||
|  |             "importance": 0.96893459932191, | ||||||
|  |             "icon": "https://nominatim.openstreetmap.org/images/mapicons/poi_place_city.p.20.png", | ||||||
|  |             "address": { | ||||||
|  |               "city": "Paris", | ||||||
|  |               "county": "Paris", | ||||||
|  |               "state": "Île-de-France", | ||||||
|  |               "country": "France", | ||||||
|  |               "postcode": 75000, | ||||||
|  |               "country_code": "fr" | ||||||
|  |             }, | ||||||
|  |             "geojson": { | ||||||
|  |               "type": "Polygon", | ||||||
|  |               "coordinates": [ | ||||||
|  |                 [ | ||||||
|  |                   [ | ||||||
|  |                     2.224122, | ||||||
|  |                     48.854199 | ||||||
|  |                   ] | ||||||
|  |                 ] | ||||||
|  |               ] | ||||||
|  |             } | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "place_id": "127732055", | ||||||
|  |             "licence": "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright", | ||||||
|  |             "osm_type": "node", | ||||||
|  |             "osm_id": "7444", | ||||||
|  |             "boundingbox": [ | ||||||
|  |               "48.8155755", | ||||||
|  |               "48.902156", | ||||||
|  |               "2.224122", | ||||||
|  |               "2.4697602" | ||||||
|  |             ], | ||||||
|  |             "lat": "48.8565056", | ||||||
|  |             "lon": "2.3521334", | ||||||
|  |             "display_name": "This is the title", | ||||||
|  |             "class": "tourism", | ||||||
|  |             "type": "city", | ||||||
|  |             "importance": 0.96893459932191, | ||||||
|  |             "icon": "https://nominatim.openstreetmap.org/images/mapicons/poi_place_city.p.20.png", | ||||||
|  |             "address": { | ||||||
|  |               "city": "Paris", | ||||||
|  |               "county": "Paris", | ||||||
|  |               "state": "Île-de-France", | ||||||
|  |               "country": "France", | ||||||
|  |               "country_code": "fr", | ||||||
|  |               "address29": "Address" | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=json) | ||||||
|  |         results = openstreetmap.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 3) | ||||||
|  |         self.assertIn('48.8565056', results[2]['geojson']['coordinates']) | ||||||
|  |         self.assertIn('2.3521334', results[2]['geojson']['coordinates']) | ||||||
							
								
								
									
										166
									
								
								searx/tests/engines/test_photon.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								searx/tests/engines/test_photon.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,166 @@ | |||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | from collections import defaultdict | ||||||
|  | import mock | ||||||
|  | from searx.engines import photon | ||||||
|  | from searx.testing import SearxTestCase | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestPhotonEngine(SearxTestCase): | ||||||
|  | 
 | ||||||
|  |     def test_request(self): | ||||||
|  |         query = 'test_query' | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['pageno'] = 1 | ||||||
|  |         dicto['language'] = 'all' | ||||||
|  |         params = photon.request(query, dicto) | ||||||
|  |         self.assertIn('url', params) | ||||||
|  |         self.assertIn(query, params['url']) | ||||||
|  |         self.assertIn('photon.komoot.de', params['url']) | ||||||
|  | 
 | ||||||
|  |         dicto['language'] = 'all' | ||||||
|  |         params = photon.request(query, dicto) | ||||||
|  |         self.assertNotIn('lang', params['url']) | ||||||
|  | 
 | ||||||
|  |         dicto['language'] = 'al' | ||||||
|  |         params = photon.request(query, dicto) | ||||||
|  |         self.assertNotIn('lang', params['url']) | ||||||
|  | 
 | ||||||
|  |         dicto['language'] = 'fr' | ||||||
|  |         params = photon.request(query, dicto) | ||||||
|  |         self.assertIn('fr', params['url']) | ||||||
|  | 
 | ||||||
|  |     def test_response(self): | ||||||
|  |         self.assertRaises(AttributeError, photon.response, None) | ||||||
|  |         self.assertRaises(AttributeError, photon.response, []) | ||||||
|  |         self.assertRaises(AttributeError, photon.response, '') | ||||||
|  |         self.assertRaises(AttributeError, photon.response, '[]') | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='{}') | ||||||
|  |         self.assertEqual(photon.response(response), []) | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='{"data": []}') | ||||||
|  |         self.assertEqual(photon.response(response), []) | ||||||
|  | 
 | ||||||
|  |         json = """ | ||||||
|  |         { | ||||||
|  |           "features": [ | ||||||
|  |             { | ||||||
|  |               "properties": { | ||||||
|  |                 "osm_key": "waterway", | ||||||
|  |                 "extent": [ | ||||||
|  |                   -1.4508446, | ||||||
|  |                   51.1614997, | ||||||
|  |                   -1.4408036, | ||||||
|  |                   51.1525635 | ||||||
|  |                 ], | ||||||
|  |                 "name": "This is the title", | ||||||
|  |                 "state": "England", | ||||||
|  |                 "osm_id": 114823817, | ||||||
|  |                 "osm_type": "W", | ||||||
|  |                 "osm_value": "river", | ||||||
|  |                 "city": "Test Valley", | ||||||
|  |                 "country": "United Kingdom" | ||||||
|  |               }, | ||||||
|  |               "type": "Feature", | ||||||
|  |               "geometry": { | ||||||
|  |                 "type": "Point", | ||||||
|  |                 "coordinates": [ | ||||||
|  |                   -1.4458571, | ||||||
|  |                   51.1576661 | ||||||
|  |                 ] | ||||||
|  |               } | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |               "properties": { | ||||||
|  |                 "osm_key": "place", | ||||||
|  |                 "street": "Rue", | ||||||
|  |                 "state": "Ile-de-France", | ||||||
|  |                 "osm_id": 129211377, | ||||||
|  |                 "osm_type": "R", | ||||||
|  |                 "housenumber": "10", | ||||||
|  |                 "postcode": "75011", | ||||||
|  |                 "osm_value": "house", | ||||||
|  |                 "city": "Paris", | ||||||
|  |                 "country": "France" | ||||||
|  |               }, | ||||||
|  |               "type": "Feature", | ||||||
|  |               "geometry": { | ||||||
|  |                 "type": "Point", | ||||||
|  |                 "coordinates": [ | ||||||
|  |                   2.3725025, | ||||||
|  |                   48.8654481 | ||||||
|  |                 ] | ||||||
|  |               } | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |               "properties": { | ||||||
|  |                 "osm_key": "amenity", | ||||||
|  |                 "street": "Allée", | ||||||
|  |                 "name": "Bibliothèque", | ||||||
|  |                 "state": "Ile-de-France", | ||||||
|  |                 "osm_id": 1028573132, | ||||||
|  |                 "osm_type": "N", | ||||||
|  |                 "postcode": "75001", | ||||||
|  |                 "osm_value": "library", | ||||||
|  |                 "city": "Paris", | ||||||
|  |                 "country": "France" | ||||||
|  |               }, | ||||||
|  |               "type": "Feature", | ||||||
|  |               "geometry": { | ||||||
|  |                 "type": "Point", | ||||||
|  |                 "coordinates": [ | ||||||
|  |                   2.3445634, | ||||||
|  |                   48.862494 | ||||||
|  |                 ] | ||||||
|  |               } | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |               "properties": { | ||||||
|  |                 "osm_key": "amenity", | ||||||
|  |                 "osm_id": 1028573132, | ||||||
|  |                 "osm_type": "Y", | ||||||
|  |                 "postcode": "75001", | ||||||
|  |                 "osm_value": "library", | ||||||
|  |                 "city": "Paris", | ||||||
|  |                 "country": "France" | ||||||
|  |               }, | ||||||
|  |               "type": "Feature", | ||||||
|  |               "geometry": { | ||||||
|  |                 "type": "Point", | ||||||
|  |                 "coordinates": [ | ||||||
|  |                   2.3445634, | ||||||
|  |                   48.862494 | ||||||
|  |                 ] | ||||||
|  |               } | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |           "type": "FeatureCollection" | ||||||
|  |         } | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=json) | ||||||
|  |         results = photon.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 3) | ||||||
|  |         self.assertEqual(results[0]['title'], 'This is the title') | ||||||
|  |         self.assertEqual(results[0]['content'], '') | ||||||
|  |         self.assertEqual(results[0]['longitude'], -1.4458571) | ||||||
|  |         self.assertEqual(results[0]['latitude'], 51.1576661) | ||||||
|  |         self.assertIn(-1.4508446, results[0]['boundingbox']) | ||||||
|  |         self.assertIn(51.1614997, results[0]['boundingbox']) | ||||||
|  |         self.assertIn(-1.4408036, results[0]['boundingbox']) | ||||||
|  |         self.assertIn(51.1525635, results[0]['boundingbox']) | ||||||
|  |         self.assertIn('type', results[0]['geojson']) | ||||||
|  |         self.assertEqual(results[0]['geojson']['type'], 'Point') | ||||||
|  |         self.assertEqual(results[0]['address'], None) | ||||||
|  |         self.assertEqual(results[0]['osm']['type'], 'way') | ||||||
|  |         self.assertEqual(results[0]['osm']['id'], 114823817) | ||||||
|  |         self.assertEqual(results[0]['url'], 'https://openstreetmap.org/way/114823817') | ||||||
|  |         self.assertEqual(results[1]['osm']['type'], 'relation') | ||||||
|  |         self.assertEqual(results[2]['address']['name'], u'Bibliothèque') | ||||||
|  |         self.assertEqual(results[2]['address']['house_number'], None) | ||||||
|  |         self.assertEqual(results[2]['address']['locality'], 'Paris') | ||||||
|  |         self.assertEqual(results[2]['address']['postcode'], '75001') | ||||||
|  |         self.assertEqual(results[2]['address']['country'], 'France') | ||||||
|  |         self.assertEqual(results[2]['osm']['type'], 'node') | ||||||
							
								
								
									
										140
									
								
								searx/tests/engines/test_startpage.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								searx/tests/engines/test_startpage.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,140 @@ | |||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | from collections import defaultdict | ||||||
|  | import mock | ||||||
|  | from searx.engines import startpage | ||||||
|  | from searx.testing import SearxTestCase | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestStartpageEngine(SearxTestCase): | ||||||
|  | 
 | ||||||
|  |     def test_request(self): | ||||||
|  |         query = 'test_query' | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['pageno'] = 1 | ||||||
|  |         dicto['language'] = 'fr_FR' | ||||||
|  |         params = startpage.request(query, dicto) | ||||||
|  |         self.assertIn('url', params) | ||||||
|  |         self.assertIn('startpage.com', params['url']) | ||||||
|  |         self.assertIn('data', params) | ||||||
|  |         self.assertIn('query', params['data']) | ||||||
|  |         self.assertIn(query, params['data']['query']) | ||||||
|  |         self.assertIn('with_language', params['data']) | ||||||
|  |         self.assertIn('lang_fr', params['data']['with_language']) | ||||||
|  | 
 | ||||||
|  |         dicto['language'] = 'all' | ||||||
|  |         params = startpage.request(query, dicto) | ||||||
|  |         self.assertNotIn('with_language', params['data']) | ||||||
|  | 
 | ||||||
|  |     def test_response(self): | ||||||
|  |         self.assertRaises(AttributeError, startpage.response, None) | ||||||
|  |         self.assertRaises(AttributeError, startpage.response, []) | ||||||
|  |         self.assertRaises(AttributeError, startpage.response, '') | ||||||
|  |         self.assertRaises(AttributeError, startpage.response, '[]') | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(content='<html></html>') | ||||||
|  |         self.assertEqual(startpage.response(response), []) | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <div class='result' style=' *width : auto; *margin-right : 10%;'> | ||||||
|  |             <h3> | ||||||
|  |                 <a href='http://this.should.be.the.link/' id='title_2' name='title_2' > | ||||||
|  |                     This should be the title | ||||||
|  |                 </a> | ||||||
|  |                 <span id='title_stars_2' name='title_stars_2'>  </span> | ||||||
|  |             </h3> | ||||||
|  |             <p class='desc'> | ||||||
|  |                 This should be the content. | ||||||
|  |             </p> | ||||||
|  |             <p> | ||||||
|  |                 <span class='url'>www.speed<b>test</b>.net/fr/ | ||||||
|  |                 </span> | ||||||
|  |                   - | ||||||
|  |                 <A class="proxy" id="proxy_link" HREF="https://ixquick-proxy.com/do/spg/proxy?ep=&edata=&ek=&ekdata=" | ||||||
|  |                     class='proxy'> | ||||||
|  |                     Navigation avec Ixquick Proxy | ||||||
|  |                 </A> | ||||||
|  |                     - | ||||||
|  |                 <A HREF="https://ixquick-proxy.com/do/spg/highlight.pl?l=francais&c=hf&cat=web&q=test&rl=NONE&rid= | ||||||
|  |                     &hlq=https://startpage.com/do/search&mtabp=-1&mtcmd=process_search&mtlanguage=francais&mtengine0= | ||||||
|  |                     &mtcat=web&u=http:%2F%2Fwww.speedtest.net%2Ffr%2F" class='proxy'> | ||||||
|  |                     Mis en surbrillance | ||||||
|  |                 </A> | ||||||
|  |             </p> | ||||||
|  |         </div> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(content=html) | ||||||
|  |         results = startpage.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 1) | ||||||
|  |         self.assertEqual(results[0]['title'], 'This should be the title') | ||||||
|  |         self.assertEqual(results[0]['url'], 'http://this.should.be.the.link/') | ||||||
|  |         self.assertEqual(results[0]['content'], 'This should be the content.') | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <div class='result' style=' *width : auto; *margin-right : 10%;'> | ||||||
|  |             <h3> | ||||||
|  |                 <a href='http://www.google.com/aclk?sa=l&ai=C' id='title_2' name='title_2' > | ||||||
|  |                     This should be the title | ||||||
|  |                 </a> | ||||||
|  |                 <span id='title_stars_2' name='title_stars_2'>  </span> | ||||||
|  |             </h3> | ||||||
|  |             <p class='desc'> | ||||||
|  |                 This should be the content. | ||||||
|  |             </p> | ||||||
|  |             <p> | ||||||
|  |                 <span class='url'>www.speed<b>test</b>.net/fr/ | ||||||
|  |                 </span> | ||||||
|  |                   - | ||||||
|  |                 <A class="proxy" id="proxy_link" HREF="https://ixquick-proxy.com/do/spg/proxy?ep=&edata=&ek=&ekdata=" | ||||||
|  |                     class='proxy'> | ||||||
|  |                     Navigation avec Ixquick Proxy | ||||||
|  |                 </A> | ||||||
|  |                     - | ||||||
|  |                 <A HREF="https://ixquick-proxy.com/do/spg/highlight.pl?l=francais&c=hf&cat=web&q=test&rl=NONE&rid= | ||||||
|  |                     &hlq=https://startpage.com/do/search&mtabp=-1&mtcmd=process_search&mtlanguage=francais&mtengine0= | ||||||
|  |                     &mtcat=web&u=http:%2F%2Fwww.speedtest.net%2Ffr%2F" class='proxy'> | ||||||
|  |                     Mis en surbrillance | ||||||
|  |                 </A> | ||||||
|  |             </p> | ||||||
|  |         </div> | ||||||
|  |         <div class='result' style=' *width : auto; *margin-right : 10%;'> | ||||||
|  |             <h3> | ||||||
|  |                 <span id='title_stars_2' name='title_stars_2'>  </span> | ||||||
|  |             </h3> | ||||||
|  |             <p class='desc'> | ||||||
|  |                 This should be the content. | ||||||
|  |             </p> | ||||||
|  |             <p> | ||||||
|  |                 <span class='url'>www.speed<b>test</b>.net/fr/ | ||||||
|  |                 </span> | ||||||
|  |             </p> | ||||||
|  |         </div> | ||||||
|  |         <div class='result' style=' *width : auto; *margin-right : 10%;'> | ||||||
|  |             <h3> | ||||||
|  |                 <a href='http://this.should.be.the.link/' id='title_2' name='title_2' > | ||||||
|  |                     This should be the title | ||||||
|  |                 </a> | ||||||
|  |                 <span id='title_stars_2' name='title_stars_2'>  </span> | ||||||
|  |             </h3> | ||||||
|  |             <p> | ||||||
|  |                 <span class='url'>www.speed<b>test</b>.net/fr/ | ||||||
|  |                 </span> | ||||||
|  |                   - | ||||||
|  |                 <A class="proxy" id="proxy_link" HREF="https://ixquick-proxy.com/do/spg/proxy?ep=&edata=&ek=&ekdata=" | ||||||
|  |                     class='proxy'> | ||||||
|  |                     Navigation avec Ixquick Proxy | ||||||
|  |                 </A> | ||||||
|  |                     - | ||||||
|  |                 <A HREF="https://ixquick-proxy.com/do/spg/highlight.pl?l=francais&c=hf&cat=web&q=test&rl=NONE&rid= | ||||||
|  |                     &hlq=https://startpage.com/do/search&mtabp=-1&mtcmd=process_search&mtlanguage=francais&mtengine0= | ||||||
|  |                     &mtcat=web&u=http:%2F%2Fwww.speedtest.net%2Ffr%2F" class='proxy'> | ||||||
|  |                     Mis en surbrillance | ||||||
|  |                 </A> | ||||||
|  |             </p> | ||||||
|  |         </div> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(content=html) | ||||||
|  |         results = startpage.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 1) | ||||||
|  |         self.assertEqual(results[0]['content'], '') | ||||||
							
								
								
									
										169
									
								
								searx/tests/engines/test_subtitleseeker.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								searx/tests/engines/test_subtitleseeker.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,169 @@ | |||||||
|  | from collections import defaultdict | ||||||
|  | import mock | ||||||
|  | from searx.engines import subtitleseeker | ||||||
|  | from searx.testing import SearxTestCase | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestSubtitleseekerEngine(SearxTestCase): | ||||||
|  | 
 | ||||||
|  |     def test_request(self): | ||||||
|  |         query = 'test_query' | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['pageno'] = 1 | ||||||
|  |         params = subtitleseeker.request(query, dicto) | ||||||
|  |         self.assertTrue('url' in params) | ||||||
|  |         self.assertTrue(query in params['url']) | ||||||
|  |         self.assertTrue('subtitleseeker.com' in params['url']) | ||||||
|  | 
 | ||||||
|  |     def test_response(self): | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['language'] = 'fr_FR' | ||||||
|  |         response = mock.Mock(search_params=dicto) | ||||||
|  | 
 | ||||||
|  |         self.assertRaises(AttributeError, subtitleseeker.response, None) | ||||||
|  |         self.assertRaises(AttributeError, subtitleseeker.response, []) | ||||||
|  |         self.assertRaises(AttributeError, subtitleseeker.response, '') | ||||||
|  |         self.assertRaises(AttributeError, subtitleseeker.response, '[]') | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='<html></html>', search_params=dicto) | ||||||
|  |         self.assertEqual(subtitleseeker.response(response), []) | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <div class="boxRows"> | ||||||
|  |             <div class="boxRowsInner" style="width:600px;"> | ||||||
|  |                 <img src="http://static.subtitleseeker.com/images/movie.gif" | ||||||
|  |                     style="width:16px; height:16px;" class="icon"> | ||||||
|  |                 <a href="http://this.is.the.url/" | ||||||
|  |                     class="blue" title="Title subtitle" > | ||||||
|  |                     This is the Title | ||||||
|  |                 </a> | ||||||
|  |                 <br><br> | ||||||
|  |                 <span class="f10b grey-dark arial" style="padding:0px 0px 5px 20px"> | ||||||
|  |                     "Alternative Title" | ||||||
|  |                 </span> | ||||||
|  |             </div> | ||||||
|  |             <div class="boxRowsInner f12b red" style="width:70px;"> | ||||||
|  |                 1998 | ||||||
|  |             </div> | ||||||
|  |             <div class="boxRowsInner grey-web f12" style="width:120px;"> | ||||||
|  |                 <img src="http://static.subtitleseeker.com/images/basket_put.png" | ||||||
|  |                     style="width:16px; height:16px;" class="icon"> | ||||||
|  |                 1039 Subs | ||||||
|  |             </div> | ||||||
|  |             <div class="boxRowsInner grey-web f10" style="width:130px;"> | ||||||
|  |                 <img src="http://static.subtitleseeker.com/images/arrow_refresh_small.png" | ||||||
|  |                     style="width:16px; height:16px;" class="icon"> | ||||||
|  |                 1 hours ago | ||||||
|  |             </div> | ||||||
|  |             <div class="clear"></div> | ||||||
|  |         </div> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=html, search_params=dicto) | ||||||
|  |         results = subtitleseeker.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 1) | ||||||
|  |         self.assertEqual(results[0]['title'], 'This is the Title') | ||||||
|  |         self.assertEqual(results[0]['url'], 'http://this.is.the.url/French/') | ||||||
|  |         self.assertIn('1998', results[0]['content']) | ||||||
|  |         self.assertIn('1039 Subs', results[0]['content']) | ||||||
|  |         self.assertIn('Alternative Title', results[0]['content']) | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <div class="boxRows"> | ||||||
|  |             <div class="boxRowsInner" style="width:600px;"> | ||||||
|  |                 <img src="http://static.subtitleseeker.com/images/movie.gif" | ||||||
|  |                     style="width:16px; height:16px;" class="icon"> | ||||||
|  |                 <a href="http://this.is.the.url/" | ||||||
|  |                     class="blue" title="Title subtitle" > | ||||||
|  |                     This is the Title | ||||||
|  |                 </a> | ||||||
|  |             </div> | ||||||
|  |             <div class="boxRowsInner f12b red" style="width:70px;"> | ||||||
|  |                 1998 | ||||||
|  |             </div> | ||||||
|  |             <div class="boxRowsInner grey-web f12" style="width:120px;"> | ||||||
|  |                 <img src="http://static.subtitleseeker.com/images/basket_put.png" | ||||||
|  |                     style="width:16px; height:16px;" class="icon"> | ||||||
|  |                 1039 Subs | ||||||
|  |             </div> | ||||||
|  |             <div class="boxRowsInner grey-web f10" style="width:130px;"> | ||||||
|  |                 <img src="http://static.subtitleseeker.com/images/arrow_refresh_small.png" | ||||||
|  |                     style="width:16px; height:16px;" class="icon"> | ||||||
|  |                 1 hours ago | ||||||
|  |             </div> | ||||||
|  |             <div class="clear"></div> | ||||||
|  |         </div> | ||||||
|  |         """ | ||||||
|  |         dicto['language'] = 'all' | ||||||
|  |         response = mock.Mock(text=html, search_params=dicto) | ||||||
|  |         results = subtitleseeker.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 1) | ||||||
|  |         self.assertEqual(results[0]['title'], 'This is the Title') | ||||||
|  |         self.assertEqual(results[0]['url'], 'http://this.is.the.url/') | ||||||
|  |         self.assertIn('1998', results[0]['content']) | ||||||
|  |         self.assertIn('1039 Subs', results[0]['content']) | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <div class="boxRows"> | ||||||
|  |             <div class="boxRowsInner" style="width:600px;"> | ||||||
|  |                 <img src="http://static.subtitleseeker.com/images/movie.gif" | ||||||
|  |                     style="width:16px; height:16px;" class="icon"> | ||||||
|  |                 <a href="http://this.is.the.url/" | ||||||
|  |                     class="blue" title="Title subtitle" > | ||||||
|  |                     This is the Title | ||||||
|  |                 </a> | ||||||
|  |             </div> | ||||||
|  |             <div class="boxRowsInner f12b red" style="width:70px;"> | ||||||
|  |                 1998 | ||||||
|  |             </div> | ||||||
|  |             <div class="boxRowsInner grey-web f12" style="width:120px;"> | ||||||
|  |                 <img src="http://static.subtitleseeker.com/images/basket_put.png" | ||||||
|  |                     style="width:16px; height:16px;" class="icon"> | ||||||
|  |                 1039 Subs | ||||||
|  |             </div> | ||||||
|  |             <div class="boxRowsInner grey-web f10" style="width:130px;"> | ||||||
|  |                 <img src="http://static.subtitleseeker.com/images/arrow_refresh_small.png" | ||||||
|  |                     style="width:16px; height:16px;" class="icon"> | ||||||
|  |                 1 hours ago | ||||||
|  |             </div> | ||||||
|  |             <div class="clear"></div> | ||||||
|  |         </div> | ||||||
|  |         """ | ||||||
|  |         subtitleseeker.language = 'English' | ||||||
|  |         response = mock.Mock(text=html, search_params=dicto) | ||||||
|  |         results = subtitleseeker.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 1) | ||||||
|  |         self.assertEqual(results[0]['title'], 'This is the Title') | ||||||
|  |         self.assertEqual(results[0]['url'], 'http://this.is.the.url/English/') | ||||||
|  |         self.assertIn('1998', results[0]['content']) | ||||||
|  |         self.assertIn('1039 Subs', results[0]['content']) | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <div class="boxRowsInner" style="width:600px;"> | ||||||
|  |             <img src="http://static.subtitleseeker.com/images/movie.gif" | ||||||
|  |                 style="width:16px; height:16px;" class="icon"> | ||||||
|  |             <a href="http://this.is.the.url/" | ||||||
|  |                 class="blue" title="Title subtitle" > | ||||||
|  |                 This is the Title | ||||||
|  |             </a> | ||||||
|  |         </div> | ||||||
|  |         <div class="boxRowsInner f12b red" style="width:70px;"> | ||||||
|  |             1998 | ||||||
|  |         </div> | ||||||
|  |         <div class="boxRowsInner grey-web f12" style="width:120px;"> | ||||||
|  |             <img src="http://static.subtitleseeker.com/images/basket_put.png" | ||||||
|  |                 style="width:16px; height:16px;" class="icon"> | ||||||
|  |             1039 Subs | ||||||
|  |         </div> | ||||||
|  |         <div class="boxRowsInner grey-web f10" style="width:130px;"> | ||||||
|  |             <img src="http://static.subtitleseeker.com/images/arrow_refresh_small.png" | ||||||
|  |                 style="width:16px; height:16px;" class="icon"> | ||||||
|  |             1 hours ago | ||||||
|  |         </div> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=html, search_params=dicto) | ||||||
|  |         results = subtitleseeker.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 0) | ||||||
							
								
								
									
										502
									
								
								searx/tests/engines/test_twitter.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										502
									
								
								searx/tests/engines/test_twitter.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,502 @@ | |||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | from collections import defaultdict | ||||||
|  | import mock | ||||||
|  | from searx.engines import twitter | ||||||
|  | from searx.testing import SearxTestCase | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestTwitterEngine(SearxTestCase): | ||||||
|  | 
 | ||||||
|  |     def test_request(self): | ||||||
|  |         query = 'test_query' | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['pageno'] = 0 | ||||||
|  |         dicto['language'] = 'fr_FR' | ||||||
|  |         params = twitter.request(query, dicto) | ||||||
|  |         self.assertIn('url', params) | ||||||
|  |         self.assertIn(query, params['url']) | ||||||
|  |         self.assertIn('twitter.com', params['url']) | ||||||
|  |         self.assertIn('cookies', params) | ||||||
|  |         self.assertIn('lang', params['cookies']) | ||||||
|  |         self.assertIn('fr', params['cookies']['lang']) | ||||||
|  | 
 | ||||||
|  |         dicto['language'] = 'all' | ||||||
|  |         params = twitter.request(query, dicto) | ||||||
|  |         self.assertIn('cookies', params) | ||||||
|  |         self.assertIn('lang', params['cookies']) | ||||||
|  |         self.assertIn('en', params['cookies']['lang']) | ||||||
|  | 
 | ||||||
|  |     def test_response(self): | ||||||
|  |         self.assertRaises(AttributeError, twitter.response, None) | ||||||
|  |         self.assertRaises(AttributeError, twitter.response, []) | ||||||
|  |         self.assertRaises(AttributeError, twitter.response, '') | ||||||
|  |         self.assertRaises(AttributeError, twitter.response, '[]') | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='<html></html>') | ||||||
|  |         self.assertEqual(twitter.response(response), []) | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <li class="js-stream-item stream-item stream-item expanding-stream-item" data-item-id="563005573290287105" | ||||||
|  |             id="stream-item-tweet-563005573290287105" data-item-type="tweet"> | ||||||
|  |             <div class="tweet original-tweet js-stream-tweet js-actionable-tweet js-profile-popup-actionable | ||||||
|  |                 js-original-tweet has-cards has-native-media" data-tweet-id="563005573290287105" data-disclosure-type="" | ||||||
|  |                 data-item-id="563005573290287105" data-screen-name="Jalopnik" data-name="Jalopnik" | ||||||
|  |                 data-user-id="3060631" data-has-native-media="true" data-has-cards="true" data-card-type="photo" | ||||||
|  |                 data-expanded-footer="<div class="js-tweet-details-fixer | ||||||
|  |                 tweet-details-fixer">


 | ||||||
|  |                 <div class="cards-media-container js-media-container"><div | ||||||
|  |                 data-card-url="//twitter.com/Jalopnik/status/563005573290287105/photo/1" data-card-type=" | ||||||
|  |                 photo" class="cards-base cards-multimedia" data-element-context="platform_photo_card | ||||||
|  |                 ">


  <a class="media media-thumbnail twitter-timeline-link is-preview | ||||||
|  |                 " data-url="https://pbs.twimg.com/media/B9Aylf5IMAAuziP.jpg:large" | ||||||
|  |                 data-resolved-url-large="https://pbs.twimg.com/media/B9Aylf5IMAAuziP.jpg:large" | ||||||
|  |                 href="//twitter.com/Jalopnik/status/563005573290287105/photo/1">
 | ||||||
|  |                 <div class="">
 <img src=" | ||||||
|  |                 https://pbs.twimg.com/media/B9Aylf5IMAAuziP.jpg" | ||||||
|  |                 alt="Embedded image permalink" width="636" height="309">
 | ||||||
|  |                 </div>

  </a>

  <div class="cards-content">
 | ||||||
|  |                 <div class="byline">
      
    </div>
    
  </div>
 | ||||||
|  |                 
</div>




</div>



  <div | ||||||
|  |                 class="js-machine-translated-tweet-container"></div>
    <div | ||||||
|  |                 class="js-tweet-stats-container tweet-stats-container ">
    </div>

 | ||||||
|  |                 <div class="client-and-actions">
  <span class="metadata">
 | ||||||
|  |                 <span>5:06 PM - 4 Feb 2015</span>

       &middot; <a | ||||||
|  |                 class="permalink-link js-permalink js-nav" href="/Jalopnik/status/563005573290287105 | ||||||
|  |                 "tabindex="-1">Details</a>
    

        
        
 | ||||||
|  |                 

  </span>
</div>


</div>
" data-you-follow="false" | ||||||
|  |                 data-you-block="false"> | ||||||
|  |                 <div class="context"> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="content"> | ||||||
|  |                     <div class="stream-item-header"> | ||||||
|  |                         <a class="account-group js-account-group js-action-profile js-user-profile-link js-nav" | ||||||
|  |                             href="/Jalopnik" data-user-id="3060631"> | ||||||
|  |                             <img class="avatar js-action-profile-avatar" | ||||||
|  |                                 src="https://pbs.twimg.com/profile_images/2976430168/5cd4a59_bigger.jpeg" alt=""> | ||||||
|  |                             <strong class="fullname js-action-profile-name show-popup-with-id" data-aria-label-part> | ||||||
|  |                                 Jalopnik | ||||||
|  |                             </strong> | ||||||
|  |                             <span>‏</span> | ||||||
|  |                             <span class="username js-action-profile-name" data-aria-label-part> | ||||||
|  |                             <s>@</s><b>TitleName</b> | ||||||
|  |                             </span> | ||||||
|  |                         </a> | ||||||
|  |                         <small class="time"> | ||||||
|  |                         <a href="/this.is.the.url" | ||||||
|  |                             class="tweet-timestamp js-permalink js-nav js-tooltip" title="5:06 PM - 4 Feb 2015" > | ||||||
|  |                             <span class="u-hiddenVisually" data-aria-label-part="last">17 minutes ago</span> | ||||||
|  |                         </a> | ||||||
|  |                         </small> | ||||||
|  |                     </div> | ||||||
|  |                     <p class="js-tweet-text tweet-text" lang="en" data-aria-label-part="0"> | ||||||
|  |                         This is the content étude à€ | ||||||
|  |                         <a href="http://t.co/nRWsqQAwBL" rel="nofollow" dir="ltr" | ||||||
|  |                             data-expanded-url="http://jalo.ps/ReMENu4" class="twitter-timeline-link" | ||||||
|  |                             target="_blank" title="http://jalo.ps/ReMENu4" > | ||||||
|  |                         <span class="tco-ellipsis"> | ||||||
|  |                         </span> | ||||||
|  |                         <span class="invisible">http://</span><span class="js-display-url">link.in.tweet</span> | ||||||
|  |                         <span class="invisible"></span> | ||||||
|  |                         <span class="tco-ellipsis"> | ||||||
|  |                             <span class="invisible"> </span> | ||||||
|  |                         </span> | ||||||
|  |                     </a> | ||||||
|  |                     <a href="http://t.co/rbFsfeE0l3" class="twitter-timeline-link u-hidden" | ||||||
|  |                         data-pre-embedded="true" dir="ltr"> | ||||||
|  |                         pic.twitter.com/rbFsfeE0l3 | ||||||
|  |                     </a> | ||||||
|  |                     </p> | ||||||
|  |                     <div class="expanded-content js-tweet-details-dropdown"> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="stream-item-footer"> | ||||||
|  |                         <a class="details with-icn js-details" href="/Jalopnik/status/563005573290287105"> | ||||||
|  |                             <span class="Icon Icon--photo"> | ||||||
|  |                             </span> | ||||||
|  |                             <b> | ||||||
|  |                                 <span class="expand-stream-item js-view-details"> | ||||||
|  |                                     View photo | ||||||
|  |                                 </span> | ||||||
|  |                                 <span class="collapse-stream-item  js-hide-details"> | ||||||
|  |                                     Hide photo | ||||||
|  |                                 </span> | ||||||
|  |                             </b> | ||||||
|  |                         </a> | ||||||
|  |                         <span class="ProfileTweet-action--reply u-hiddenVisually"> | ||||||
|  |                             <span class="ProfileTweet-actionCount" aria-hidden="true" data-tweet-stat-count="0"> | ||||||
|  |                                 <span class="ProfileTweet-actionCountForAria" >0 replies</span> | ||||||
|  |                             </span> | ||||||
|  |                         </span> | ||||||
|  |                         <span class="ProfileTweet-action--retweet u-hiddenVisually"> | ||||||
|  |                             <span class="ProfileTweet-actionCount"  data-tweet-stat-count="8"> | ||||||
|  |                                 <span class="ProfileTweet-actionCountForAria" data-aria-label-part>8 retweets</span> | ||||||
|  |                             </span> | ||||||
|  |                         </span> | ||||||
|  |                         <span class="ProfileTweet-action--favorite u-hiddenVisually"> | ||||||
|  |                             <span class="ProfileTweet-actionCount"  data-tweet-stat-count="14"> | ||||||
|  |                                 <span class="ProfileTweet-actionCountForAria" data-aria-label-part>14 favorites</span> | ||||||
|  |                             </span> | ||||||
|  |                         </span> | ||||||
|  |                         <div role="group" aria-label="Tweet actions" class="ProfileTweet-actionList u-cf js-actions"> | ||||||
|  |                             <div class="ProfileTweet-action ProfileTweet-action--reply"> | ||||||
|  |                                 <button class="ProfileTweet-actionButton u-textUserColorHover js-actionButton | ||||||
|  |                                     js-actionReply" data-modal="ProfileTweet-reply" type="button" title="Reply"> | ||||||
|  |                                     <span class="Icon Icon--reply"> | ||||||
|  |                                     </span> | ||||||
|  |                                     <span class="u-hiddenVisually">Reply</span> | ||||||
|  |                                     <span class="ProfileTweet-actionCount u-textUserColorHover | ||||||
|  |                                         ProfileTweet-actionCount--isZero"> | ||||||
|  |                                         <span class="ProfileTweet-actionCountForPresentation" aria-hidden="true"> | ||||||
|  |                                         </span> | ||||||
|  |                                     </span> | ||||||
|  |                                 </button> | ||||||
|  |                             </div> | ||||||
|  |                             <div class="ProfileTweet-action ProfileTweet-action--retweet js-toggleState js-toggleRt"> | ||||||
|  |                                 <button class="ProfileTweet-actionButton  js-actionButton js-actionRetweet js-tooltip" | ||||||
|  |                                     title="Retweet" data-modal="ProfileTweet-retweet" type="button"> | ||||||
|  |                                     <span class="Icon Icon--retweet"> | ||||||
|  |                                     </span> | ||||||
|  |                                     <span class="u-hiddenVisually">Retweet</span> | ||||||
|  |                                     <span class="ProfileTweet-actionCount"> | ||||||
|  |                                         <span class="ProfileTweet-actionCountForPresentation">8</span> | ||||||
|  |                                     </span> | ||||||
|  |                                 </button> | ||||||
|  |                                 <button class="ProfileTweet-actionButtonUndo js-actionButton js-actionRetweet" | ||||||
|  |                                     data-modal="ProfileTweet-retweet" title="Undo retweet" type="button"> | ||||||
|  |                                     <span class="Icon Icon--retweet"> | ||||||
|  |                                     </span> | ||||||
|  |                                     <span class="u-hiddenVisually">Retweeted</span> | ||||||
|  |                                     <span class="ProfileTweet-actionCount"> | ||||||
|  |                                         <span class="ProfileTweet-actionCountForPresentation">8</span> | ||||||
|  |                                     </span> | ||||||
|  |                                 </button> | ||||||
|  |                             </div> | ||||||
|  |                             <div class="ProfileTweet-action ProfileTweet-action--favorite js-toggleState"> | ||||||
|  |                                 <button class="ProfileTweet-actionButton js-actionButton js-actionFavorite js-tooltip" | ||||||
|  |                                     title="Favorite" type="button"> | ||||||
|  |                                     <span class="Icon Icon--favorite"> | ||||||
|  |                                     </span> | ||||||
|  |                                     <span class="u-hiddenVisually">Favorite</span> | ||||||
|  |                                     <span class="ProfileTweet-actionCount"> | ||||||
|  |                                         <span class="ProfileTweet-actionCountForPresentation">14</span> | ||||||
|  |                                     </span> | ||||||
|  |                                 </button> | ||||||
|  |                                 <button class="ProfileTweet-actionButtonUndo u-linkClean js-actionButton | ||||||
|  |                                     js-actionFavorite" title="Undo favorite" type="button"> | ||||||
|  |                                     <span class="Icon Icon--favorite"> | ||||||
|  |                                     </span> | ||||||
|  |                                     <span class="u-hiddenVisually">Favorited</span> | ||||||
|  |                                     <span class="ProfileTweet-actionCount"> | ||||||
|  |                                         <span class="ProfileTweet-actionCountForPresentation"> | ||||||
|  |                                             14 | ||||||
|  |                                         </span> | ||||||
|  |                                     </span> | ||||||
|  |                                 </button> | ||||||
|  |                             </div> | ||||||
|  |                             <div class="ProfileTweet-action ProfileTweet-action--more js-more-ProfileTweet-actions"> | ||||||
|  |                                 <div class="dropdown"> | ||||||
|  |                                     <button class="ProfileTweet-actionButton u-textUserColorHover dropdown-toggle | ||||||
|  |                                         js-tooltip js-dropdown-toggle" type="button" title="More"> | ||||||
|  |                                         <span class="Icon Icon--dots"> | ||||||
|  |                                         </span> | ||||||
|  |                                         <span class="u-hiddenVisually">More</span> | ||||||
|  |                                     </button> | ||||||
|  |                                     <div class="dropdown-menu"> | ||||||
|  |                                         <div class="dropdown-caret"> | ||||||
|  |                                             <div class="caret-outer"> | ||||||
|  |                                             </div> | ||||||
|  |                                             <div class="caret-inner"> | ||||||
|  |                                             </div> | ||||||
|  |                                         </div> | ||||||
|  |                                         <ul> | ||||||
|  |                                             <li class="share-via-dm js-actionShareViaDM" data-nav="share_tweet_dm"> | ||||||
|  |                                                 <button type="button" class="dropdown-link"> | ||||||
|  |                                                     Share via Direct Message | ||||||
|  |                                                 </button> | ||||||
|  |                                             </li> | ||||||
|  |                                             <li class="embed-link js-actionEmbedTweet" data-nav="embed_tweet"> | ||||||
|  |                                                 <button type="button" class="dropdown-link"> | ||||||
|  |                                                     Embed Tweet | ||||||
|  |                                                 </button> | ||||||
|  |                                             </li> | ||||||
|  |                                             <li class="mute-user-item pretty-link"> | ||||||
|  |                                                 <button type="button" class="dropdown-link"> | ||||||
|  |                                                     Mute | ||||||
|  |                                                 </button> | ||||||
|  |                                             </li> | ||||||
|  |                                             <li class="unmute-user-item pretty-link"> | ||||||
|  |                                                 <button type="button" class="dropdown-link"> | ||||||
|  |                                                     Unmute | ||||||
|  |                                                 </button> | ||||||
|  |                                             </li> | ||||||
|  |                                             <li class="block-or-report-link js-actionBlockOrReport" | ||||||
|  |                                                 data-nav="block_or_report"> | ||||||
|  |                                                 <button type="button" class="dropdown-link"> | ||||||
|  |                                                     Block or report | ||||||
|  |                                                 </button> | ||||||
|  |                                             </li> | ||||||
|  |                                         </ul> | ||||||
|  |                                     </div> | ||||||
|  |                                 </div> | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </li> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=html) | ||||||
|  |         results = twitter.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 1) | ||||||
|  |         self.assertEqual(results[0]['title'], '@TitleName') | ||||||
|  |         self.assertEqual(results[0]['url'], 'https://twitter.com/this.is.the.url') | ||||||
|  |         self.assertIn(u'This is the content', results[0]['content']) | ||||||
|  |         # self.assertIn(u'This is the content étude à€', results[0]['content']) | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <li class="js-stream-item stream-item stream-item expanding-stream-item" data-item-id="563005573290287105" | ||||||
|  |             id="stream-item-tweet-563005573290287105" data-item-type="tweet"> | ||||||
|  |             <div class="tweet original-tweet js-stream-tweet js-actionable-tweet js-profile-popup-actionable | ||||||
|  |                 js-original-tweet has-cards has-native-media" data-tweet-id="563005573290287105" data-disclosure-type="" | ||||||
|  |                 data-item-id="563005573290287105" data-screen-name="Jalopnik" data-name="Jalopnik" | ||||||
|  |                 data-user-id="3060631" data-has-native-media="true" data-has-cards="true" data-card-type="photo" | ||||||
|  |                 data-expanded-footer="<div class="js-tweet-details-fixer | ||||||
|  |                 tweet-details-fixer">


 | ||||||
|  |                 <div class="cards-media-container js-media-container"><div | ||||||
|  |                 data-card-url="//twitter.com/Jalopnik/status/563005573290287105/photo/1" data-card-type=" | ||||||
|  |                 photo" class="cards-base cards-multimedia" data-element-context="platform_photo_card | ||||||
|  |                 ">


  <a class="media media-thumbnail twitter-timeline-link is-preview | ||||||
|  |                 " data-url="https://pbs.twimg.com/media/B9Aylf5IMAAuziP.jpg:large" | ||||||
|  |                 data-resolved-url-large="https://pbs.twimg.com/media/B9Aylf5IMAAuziP.jpg:large" | ||||||
|  |                 href="//twitter.com/Jalopnik/status/563005573290287105/photo/1">
 | ||||||
|  |                 <div class="">
 <img src=" | ||||||
|  |                 https://pbs.twimg.com/media/B9Aylf5IMAAuziP.jpg" | ||||||
|  |                 alt="Embedded image permalink" width="636" height="309">
 | ||||||
|  |                 </div>

  </a>

  <div class="cards-content">
 | ||||||
|  |                 <div class="byline">
      
    </div>
    
  </div>
 | ||||||
|  |                 
</div>




</div>



  <div | ||||||
|  |                 class="js-machine-translated-tweet-container"></div>
    <div | ||||||
|  |                 class="js-tweet-stats-container tweet-stats-container ">
    </div>

 | ||||||
|  |                 <div class="client-and-actions">
  <span class="metadata">
 | ||||||
|  |                 <span>5:06 PM - 4 Feb 2015</span>

       &middot; <a | ||||||
|  |                 class="permalink-link js-permalink js-nav" href="/Jalopnik/status/563005573290287105 | ||||||
|  |                 "tabindex="-1">Details</a>
    

        
        
 | ||||||
|  |                 

  </span>
</div>


</div>
" data-you-follow="false" | ||||||
|  |                 data-you-block="false"> | ||||||
|  |                 <div class="context"> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="content"> | ||||||
|  |                     <div class="stream-item-header"> | ||||||
|  |                         <a class="account-group js-account-group js-action-profile js-user-profile-link js-nav" | ||||||
|  |                             href="/Jalopnik" data-user-id="3060631"> | ||||||
|  |                             <img class="avatar js-action-profile-avatar" | ||||||
|  |                                 src="https://pbs.twimg.com/profile_images/2976430168/5cd4a59_bigger.jpeg" alt=""> | ||||||
|  |                             <strong class="fullname js-action-profile-name show-popup-with-id" data-aria-label-part> | ||||||
|  |                                 Jalopnik | ||||||
|  |                             </strong> | ||||||
|  |                             <span>‏</span> | ||||||
|  |                             <span class="username js-action-profile-name" data-aria-label-part> | ||||||
|  |                             <s>@</s><b>TitleName</b> | ||||||
|  |                             </span> | ||||||
|  |                         </a> | ||||||
|  |                         <small class="time"> | ||||||
|  |                         <a href="/this.is.the.url" | ||||||
|  |                             class="tweet-timestamp js-permalink js-nav js-tooltip" title="5:06 PM - 4 Feb 2015" > | ||||||
|  |                             <span class="_timestamp js-short-timestamp js-relative-timestamp"  data-time="1423065963" | ||||||
|  |                                 data-time-ms="1423065963000" data-long-form="true" aria-hidden="true"> | ||||||
|  |                                 17m | ||||||
|  |                             </span> | ||||||
|  |                             <span class="u-hiddenVisually" data-aria-label-part="last">17 minutes ago</span> | ||||||
|  |                         </a> | ||||||
|  |                         </small> | ||||||
|  |                     </div> | ||||||
|  |                     <p class="js-tweet-text tweet-text" lang="en" data-aria-label-part="0"> | ||||||
|  |                         This is the content étude à€ | ||||||
|  |                         <a href="http://t.co/nRWsqQAwBL" rel="nofollow" dir="ltr" | ||||||
|  |                             data-expanded-url="http://jalo.ps/ReMENu4" class="twitter-timeline-link" | ||||||
|  |                             target="_blank" title="http://jalo.ps/ReMENu4" > | ||||||
|  |                         <span class="tco-ellipsis"> | ||||||
|  |                         </span> | ||||||
|  |                         <span class="invisible">http://</span><span class="js-display-url">link.in.tweet</span> | ||||||
|  |                         <span class="invisible"></span> | ||||||
|  |                         <span class="tco-ellipsis"> | ||||||
|  |                             <span class="invisible"> </span> | ||||||
|  |                         </span> | ||||||
|  |                     </a> | ||||||
|  |                     <a href="http://t.co/rbFsfeE0l3" class="twitter-timeline-link u-hidden" | ||||||
|  |                         data-pre-embedded="true" dir="ltr"> | ||||||
|  |                         pic.twitter.com/rbFsfeE0l3 | ||||||
|  |                     </a> | ||||||
|  |                     </p> | ||||||
|  |                     <div class="expanded-content js-tweet-details-dropdown"> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="stream-item-footer"> | ||||||
|  |                         <a class="details with-icn js-details" href="/Jalopnik/status/563005573290287105"> | ||||||
|  |                             <span class="Icon Icon--photo"> | ||||||
|  |                             </span> | ||||||
|  |                             <b> | ||||||
|  |                                 <span class="expand-stream-item js-view-details"> | ||||||
|  |                                     View photo | ||||||
|  |                                 </span> | ||||||
|  |                                 <span class="collapse-stream-item  js-hide-details"> | ||||||
|  |                                     Hide photo | ||||||
|  |                                 </span> | ||||||
|  |                             </b> | ||||||
|  |                         </a> | ||||||
|  |                         <span class="ProfileTweet-action--reply u-hiddenVisually"> | ||||||
|  |                             <span class="ProfileTweet-actionCount" aria-hidden="true" data-tweet-stat-count="0"> | ||||||
|  |                                 <span class="ProfileTweet-actionCountForAria" >0 replies</span> | ||||||
|  |                             </span> | ||||||
|  |                         </span> | ||||||
|  |                         <span class="ProfileTweet-action--retweet u-hiddenVisually"> | ||||||
|  |                             <span class="ProfileTweet-actionCount"  data-tweet-stat-count="8"> | ||||||
|  |                                 <span class="ProfileTweet-actionCountForAria" data-aria-label-part>8 retweets</span> | ||||||
|  |                             </span> | ||||||
|  |                         </span> | ||||||
|  |                         <span class="ProfileTweet-action--favorite u-hiddenVisually"> | ||||||
|  |                             <span class="ProfileTweet-actionCount"  data-tweet-stat-count="14"> | ||||||
|  |                                 <span class="ProfileTweet-actionCountForAria" data-aria-label-part>14 favorites</span> | ||||||
|  |                             </span> | ||||||
|  |                         </span> | ||||||
|  |                         <div role="group" aria-label="Tweet actions" class="ProfileTweet-actionList u-cf js-actions"> | ||||||
|  |                             <div class="ProfileTweet-action ProfileTweet-action--reply"> | ||||||
|  |                                 <button class="ProfileTweet-actionButton u-textUserColorHover js-actionButton | ||||||
|  |                                     js-actionReply" data-modal="ProfileTweet-reply" type="button" title="Reply"> | ||||||
|  |                                     <span class="Icon Icon--reply"> | ||||||
|  |                                     </span> | ||||||
|  |                                     <span class="u-hiddenVisually">Reply</span> | ||||||
|  |                                     <span class="ProfileTweet-actionCount u-textUserColorHover | ||||||
|  |                                         ProfileTweet-actionCount--isZero"> | ||||||
|  |                                         <span class="ProfileTweet-actionCountForPresentation" aria-hidden="true"> | ||||||
|  |                                         </span> | ||||||
|  |                                     </span> | ||||||
|  |                                 </button> | ||||||
|  |                             </div> | ||||||
|  |                             <div class="ProfileTweet-action ProfileTweet-action--retweet js-toggleState js-toggleRt"> | ||||||
|  |                                 <button class="ProfileTweet-actionButton  js-actionButton js-actionRetweet js-tooltip" | ||||||
|  |                                     title="Retweet" data-modal="ProfileTweet-retweet" type="button"> | ||||||
|  |                                     <span class="Icon Icon--retweet"> | ||||||
|  |                                     </span> | ||||||
|  |                                     <span class="u-hiddenVisually">Retweet</span> | ||||||
|  |                                     <span class="ProfileTweet-actionCount"> | ||||||
|  |                                         <span class="ProfileTweet-actionCountForPresentation">8</span> | ||||||
|  |                                     </span> | ||||||
|  |                                 </button> | ||||||
|  |                                 <button class="ProfileTweet-actionButtonUndo js-actionButton js-actionRetweet" | ||||||
|  |                                     data-modal="ProfileTweet-retweet" title="Undo retweet" type="button"> | ||||||
|  |                                     <span class="Icon Icon--retweet"> | ||||||
|  |                                     </span> | ||||||
|  |                                     <span class="u-hiddenVisually">Retweeted</span> | ||||||
|  |                                     <span class="ProfileTweet-actionCount"> | ||||||
|  |                                         <span class="ProfileTweet-actionCountForPresentation">8</span> | ||||||
|  |                                     </span> | ||||||
|  |                                 </button> | ||||||
|  |                             </div> | ||||||
|  |                             <div class="ProfileTweet-action ProfileTweet-action--favorite js-toggleState"> | ||||||
|  |                                 <button class="ProfileTweet-actionButton js-actionButton js-actionFavorite js-tooltip" | ||||||
|  |                                     title="Favorite" type="button"> | ||||||
|  |                                     <span class="Icon Icon--favorite"> | ||||||
|  |                                     </span> | ||||||
|  |                                     <span class="u-hiddenVisually">Favorite</span> | ||||||
|  |                                     <span class="ProfileTweet-actionCount"> | ||||||
|  |                                         <span class="ProfileTweet-actionCountForPresentation">14</span> | ||||||
|  |                                     </span> | ||||||
|  |                                 </button> | ||||||
|  |                                 <button class="ProfileTweet-actionButtonUndo u-linkClean js-actionButton | ||||||
|  |                                     js-actionFavorite" title="Undo favorite" type="button"> | ||||||
|  |                                     <span class="Icon Icon--favorite"> | ||||||
|  |                                     </span> | ||||||
|  |                                     <span class="u-hiddenVisually">Favorited</span> | ||||||
|  |                                     <span class="ProfileTweet-actionCount"> | ||||||
|  |                                         <span class="ProfileTweet-actionCountForPresentation"> | ||||||
|  |                                             14 | ||||||
|  |                                         </span> | ||||||
|  |                                     </span> | ||||||
|  |                                 </button> | ||||||
|  |                             </div> | ||||||
|  |                             <div class="ProfileTweet-action ProfileTweet-action--more js-more-ProfileTweet-actions"> | ||||||
|  |                                 <div class="dropdown"> | ||||||
|  |                                     <button class="ProfileTweet-actionButton u-textUserColorHover dropdown-toggle | ||||||
|  |                                         js-tooltip js-dropdown-toggle" type="button" title="More"> | ||||||
|  |                                         <span class="Icon Icon--dots"> | ||||||
|  |                                         </span> | ||||||
|  |                                         <span class="u-hiddenVisually">More</span> | ||||||
|  |                                     </button> | ||||||
|  |                                     <div class="dropdown-menu"> | ||||||
|  |                                         <div class="dropdown-caret"> | ||||||
|  |                                             <div class="caret-outer"> | ||||||
|  |                                             </div> | ||||||
|  |                                             <div class="caret-inner"> | ||||||
|  |                                             </div> | ||||||
|  |                                         </div> | ||||||
|  |                                         <ul> | ||||||
|  |                                             <li class="share-via-dm js-actionShareViaDM" data-nav="share_tweet_dm"> | ||||||
|  |                                                 <button type="button" class="dropdown-link"> | ||||||
|  |                                                     Share via Direct Message | ||||||
|  |                                                 </button> | ||||||
|  |                                             </li> | ||||||
|  |                                             <li class="embed-link js-actionEmbedTweet" data-nav="embed_tweet"> | ||||||
|  |                                                 <button type="button" class="dropdown-link"> | ||||||
|  |                                                     Embed Tweet | ||||||
|  |                                                 </button> | ||||||
|  |                                             </li> | ||||||
|  |                                             <li class="mute-user-item pretty-link"> | ||||||
|  |                                                 <button type="button" class="dropdown-link"> | ||||||
|  |                                                     Mute | ||||||
|  |                                                 </button> | ||||||
|  |                                             </li> | ||||||
|  |                                             <li class="unmute-user-item pretty-link"> | ||||||
|  |                                                 <button type="button" class="dropdown-link"> | ||||||
|  |                                                     Unmute | ||||||
|  |                                                 </button> | ||||||
|  |                                             </li> | ||||||
|  |                                             <li class="block-or-report-link js-actionBlockOrReport" | ||||||
|  |                                                 data-nav="block_or_report"> | ||||||
|  |                                                 <button type="button" class="dropdown-link"> | ||||||
|  |                                                     Block or report | ||||||
|  |                                                 </button> | ||||||
|  |                                             </li> | ||||||
|  |                                         </ul> | ||||||
|  |                                     </div> | ||||||
|  |                                 </div> | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </li> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=html) | ||||||
|  |         results = twitter.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 1) | ||||||
|  |         self.assertEqual(results[0]['title'], '@TitleName') | ||||||
|  |         self.assertEqual(results[0]['url'], 'https://twitter.com/this.is.the.url') | ||||||
|  |         self.assertIn(u'This is the content', results[0]['content']) | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <li class="b_algo" u="0|5109|4755453613245655|UAGjXgIrPH5yh-o5oNHRx_3Zta87f_QO"> | ||||||
|  |             <div Class="sa_mc"> | ||||||
|  |                 <div class="sb_tlst"> | ||||||
|  |                     <h2> | ||||||
|  |                         <a href="http://this.should.be.the.link/" h="ID=SERP,5124.1"> | ||||||
|  |                         <strong>This</strong> should be the title</a> | ||||||
|  |                     </h2> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="sb_meta"> | ||||||
|  |                 <cite> | ||||||
|  |                 <strong>this</strong>.meta.com</cite> | ||||||
|  |                     <span class="c_tlbxTrg"> | ||||||
|  |                         <span class="c_tlbxH" H="BASE:CACHEDPAGEDEFAULT" K="SERP,5125.1"> | ||||||
|  |                         </span> | ||||||
|  |                     </span> | ||||||
|  |                 </div> | ||||||
|  |                 <p> | ||||||
|  |                 <strong>This</strong> should be the content.</p> | ||||||
|  |             </div> | ||||||
|  |         </li> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=html) | ||||||
|  |         results = twitter.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 0) | ||||||
							
								
								
									
										96
									
								
								searx/tests/engines/test_yacy.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								searx/tests/engines/test_yacy.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,96 @@ | |||||||
|  | from collections import defaultdict | ||||||
|  | import mock | ||||||
|  | from searx.engines import yacy | ||||||
|  | from searx.testing import SearxTestCase | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestYacyEngine(SearxTestCase): | ||||||
|  | 
 | ||||||
|  |     def test_request(self): | ||||||
|  |         query = 'test_query' | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['pageno'] = 1 | ||||||
|  |         dicto['language'] = 'fr_FR' | ||||||
|  |         params = yacy.request(query, dicto) | ||||||
|  |         self.assertIn('url', params) | ||||||
|  |         self.assertIn(query, params['url']) | ||||||
|  |         self.assertIn('localhost', params['url']) | ||||||
|  |         self.assertIn('fr', params['url']) | ||||||
|  | 
 | ||||||
|  |         dicto['language'] = 'all' | ||||||
|  |         params = yacy.request(query, dicto) | ||||||
|  |         self.assertIn('url', params) | ||||||
|  |         self.assertNotIn('lr=lang_', params['url']) | ||||||
|  | 
 | ||||||
|  |     def test_response(self): | ||||||
|  |         self.assertRaises(AttributeError, yacy.response, None) | ||||||
|  |         self.assertRaises(AttributeError, yacy.response, []) | ||||||
|  |         self.assertRaises(AttributeError, yacy.response, '') | ||||||
|  |         self.assertRaises(AttributeError, yacy.response, '[]') | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='{}') | ||||||
|  |         self.assertEqual(yacy.response(response), []) | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='{"data": []}') | ||||||
|  |         self.assertEqual(yacy.response(response), []) | ||||||
|  | 
 | ||||||
|  |         json = """ | ||||||
|  |         { | ||||||
|  |           "channels": [ | ||||||
|  |             { | ||||||
|  |               "title": "YaCy P2P-Search for test", | ||||||
|  |               "description": "Search for test", | ||||||
|  |               "link": "http://search.yacy.de:7001/yacysearch.html?query=test&resource=global&contentdom=0", | ||||||
|  |               "image": { | ||||||
|  |                 "url": "http://search.yacy.de:7001/env/grafics/yacy.png", | ||||||
|  |                 "title": "Search for test", | ||||||
|  |                 "link": "http://search.yacy.de:7001/yacysearch.html?query=test&resource=global&contentdom=0" | ||||||
|  |               }, | ||||||
|  |               "totalResults": "249", | ||||||
|  |               "startIndex": "0", | ||||||
|  |               "itemsPerPage": "5", | ||||||
|  |               "searchTerms": "test", | ||||||
|  |               "items": [ | ||||||
|  |                 { | ||||||
|  |                   "title": "This is the title", | ||||||
|  |                   "link": "http://this.is.the.url", | ||||||
|  |                   "code": "", | ||||||
|  |                   "description": "This should be the content", | ||||||
|  |                   "pubDate": "Sat, 08 Jun 2013 02:00:00 +0200", | ||||||
|  |                   "size": "44213", | ||||||
|  |                   "sizename": "43 kbyte", | ||||||
|  |                   "guid": "lzh_1T_5FP-A", | ||||||
|  |                   "faviconCode": "XTS4uQ_5FP-A", | ||||||
|  |                   "host": "www.gamestar.de", | ||||||
|  |                   "path": "/spiele/city-of-heroes-freedom/47019.html", | ||||||
|  |                   "file": "47019.html", | ||||||
|  |                   "urlhash": "lzh_1T_5FP-A", | ||||||
|  |                   "ranking": "0.20106804" | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                   "title": "This is the title2", | ||||||
|  |                   "icon": "/ViewImage.png?maxwidth=96&maxheight=96&code=7EbAbW6BpPOA", | ||||||
|  |                   "image": "http://image.url/image.png", | ||||||
|  |                   "cache": "/ViewImage.png?quadratic=&url=http://golem.ivwbox.de/cgi-bin/ivw/CP/G_INET?d=14071378", | ||||||
|  |                   "url": "http://this.is.the.url", | ||||||
|  |                   "urlhash": "7EbAbW6BpPOA", | ||||||
|  |                   "host": "www.golem.de", | ||||||
|  |                   "width": "-1", | ||||||
|  |                   "height": "-1" | ||||||
|  |                 } | ||||||
|  |               ] | ||||||
|  |             } | ||||||
|  |           ] | ||||||
|  |         } | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=json) | ||||||
|  |         results = yacy.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 2) | ||||||
|  |         self.assertEqual(results[0]['title'], 'This is the title') | ||||||
|  |         self.assertEqual(results[0]['url'], 'http://this.is.the.url') | ||||||
|  |         self.assertEqual(results[0]['content'], 'This should be the content') | ||||||
|  |         self.assertEqual(results[1]['img_src'], 'http://image.url/image.png') | ||||||
|  |         self.assertEqual(results[1]['content'], '') | ||||||
|  |         self.assertEqual(results[1]['url'], 'http://this.is.the.url') | ||||||
|  |         self.assertEqual(results[1]['title'], 'This is the title2') | ||||||
							
								
								
									
										154
									
								
								searx/tests/engines/test_yahoo.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								searx/tests/engines/test_yahoo.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,154 @@ | |||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | from collections import defaultdict | ||||||
|  | import mock | ||||||
|  | from searx.engines import yahoo | ||||||
|  | from searx.testing import SearxTestCase | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestYahooEngine(SearxTestCase): | ||||||
|  | 
 | ||||||
|  |     def test_parse_url(self): | ||||||
|  |         test_url = 'http://r.search.yahoo.com/_ylt=A0LEb9JUSKcAEGRXNyoA;_ylu=X3oDMTEzZm1qazYwBHNlYwNzcgRwb3MDMQRjb' +\ | ||||||
|  |                    '2xvA2Jm2dGlkA1NNRTcwM18x/RV=2/RE=1423106085/RO=10/RU=https%3a%2f%2fthis.is.the.url%2f/RK=0/RS=' +\ | ||||||
|  |                    'dtcJsfP4mEeBOjnVfUQ-' | ||||||
|  |         url = yahoo.parse_url(test_url) | ||||||
|  |         self.assertEqual('https://this.is.the.url/', url) | ||||||
|  | 
 | ||||||
|  |         test_url = 'http://r.search.yahoo.com/_ylt=A0LElb9JUSKcAEGRXNyoA;_ylu=X3oDMTEzZm1qazYwBHNlYwNzcgRwb3MDMQRjb' +\ | ||||||
|  |                    '2xvA2Jm2dGlkA1NNRTcwM18x/RV=2/RE=1423106085/RO=10/RU=https%3a%2f%2fthis.is.the.url%2f/RS=' +\ | ||||||
|  |                    'dtcJsfP4mEeBOjnVfUQ-' | ||||||
|  |         url = yahoo.parse_url(test_url) | ||||||
|  |         self.assertEqual('https://this.is.the.url/', url) | ||||||
|  | 
 | ||||||
|  |         test_url = 'https://this.is.the.url/' | ||||||
|  |         url = yahoo.parse_url(test_url) | ||||||
|  |         self.assertEqual('https://this.is.the.url/', url) | ||||||
|  | 
 | ||||||
|  |     def test_request(self): | ||||||
|  |         query = 'test_query' | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['pageno'] = 1 | ||||||
|  |         dicto['language'] = 'fr_FR' | ||||||
|  |         params = yahoo.request(query, dicto) | ||||||
|  |         self.assertIn('url', params) | ||||||
|  |         self.assertIn(query, params['url']) | ||||||
|  |         self.assertIn('search.yahoo.com', params['url']) | ||||||
|  |         self.assertIn('fr', params['url']) | ||||||
|  |         self.assertIn('cookies', params) | ||||||
|  |         self.assertIn('sB', params['cookies']) | ||||||
|  |         self.assertIn('fr', params['cookies']['sB']) | ||||||
|  | 
 | ||||||
|  |         dicto['language'] = 'all' | ||||||
|  |         params = yahoo.request(query, dicto) | ||||||
|  |         self.assertIn('cookies', params) | ||||||
|  |         self.assertIn('sB', params['cookies']) | ||||||
|  |         self.assertIn('en', params['cookies']['sB']) | ||||||
|  |         self.assertIn('en', params['url']) | ||||||
|  | 
 | ||||||
|  |     def test_response(self): | ||||||
|  |         self.assertRaises(AttributeError, yahoo.response, None) | ||||||
|  |         self.assertRaises(AttributeError, yahoo.response, []) | ||||||
|  |         self.assertRaises(AttributeError, yahoo.response, '') | ||||||
|  |         self.assertRaises(AttributeError, yahoo.response, '[]') | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='<html></html>') | ||||||
|  |         self.assertEqual(yahoo.response(response), []) | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <div class="res"> | ||||||
|  |             <div> | ||||||
|  |                 <h3> | ||||||
|  |                 <a id="link-1" class="yschttl spt" href="http://r.search.yahoo.com/_ylt=A0LEVzClb9JUSKcAEGRXNyoA; | ||||||
|  |                     _ylu=X3oDMTEzZm1qazYwBHNlYwNzcgRwb3MDMQRjb2xvA2JmMQR2dGlkA1NNRTcwM18x/RV=2/RE=1423106085/RO=10 | ||||||
|  |                     /RU=https%3a%2f%2fthis.is.the.url%2f/RK=0/RS=dtcJsfP4mEeBOjnVfUQ-"target="_blank" data-bk="5063.1"> | ||||||
|  |                     <b>This</b> is the title | ||||||
|  |                 </a> | ||||||
|  |                 </h3> | ||||||
|  |             </div> | ||||||
|  |             <span class="url" dir="ltr">www.<b>test</b>.com</span> | ||||||
|  |             <div class="abstr"> | ||||||
|  |                 <b>This</b> is the content | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         <div id="satat"  data-bns="Yahoo" data-bk="124.1"> | ||||||
|  |             <h2>Also Try</h2> | ||||||
|  |             <table> | ||||||
|  |                 <tbody> | ||||||
|  |                     <tr> | ||||||
|  |                         <td> | ||||||
|  |                             <a id="srpnat0" class="" href="https://search.yahoo.com/search=rs-bottom" > | ||||||
|  |                                 <span> | ||||||
|  |                                     <b></b>This is <b>the suggestion</b> | ||||||
|  |                                 </span> | ||||||
|  |                             </a> | ||||||
|  |                         </td> | ||||||
|  |                     </tr> | ||||||
|  |                 </tbody> | ||||||
|  |             </table> | ||||||
|  |         </div> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=html) | ||||||
|  |         results = yahoo.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 2) | ||||||
|  |         self.assertEqual(results[0]['title'], 'This is the title') | ||||||
|  |         self.assertEqual(results[0]['url'], 'https://this.is.the.url/') | ||||||
|  |         self.assertEqual(results[0]['content'], 'This is the content') | ||||||
|  |         self.assertEqual(results[1]['suggestion'], 'This is the suggestion') | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <div class="res"> | ||||||
|  |             <div> | ||||||
|  |                 <h3> | ||||||
|  |                 <a id="link-1" class="yschttl spt" href="http://r.search.yahoo.com/_ylt=A0LEVzClb9JUSKcAEGRXNyoA; | ||||||
|  |                     _ylu=X3oDMTEzZm1qazYwBHNlYwNzcgRwb3MDMQRjb2xvA2JmMQR2dGlkA1NNRTcwM18x/RV=2/RE=1423106085/RO=10 | ||||||
|  |                     /RU=https%3a%2f%2fthis.is.the.url%2f/RK=0/RS=dtcJsfP4mEeBOjnVfUQ-"target="_blank" data-bk="5063.1"> | ||||||
|  |                     <b>This</b> is the title | ||||||
|  |                 </a> | ||||||
|  |                 </h3> | ||||||
|  |             </div> | ||||||
|  |             <span class="url" dir="ltr">www.<b>test</b>.com</span> | ||||||
|  |             <div class="abstr"> | ||||||
|  |                 <b>This</b> is the content | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="res"> | ||||||
|  |             <div> | ||||||
|  |                 <h3> | ||||||
|  |                 <a id="link-1" class="yschttl spt"> | ||||||
|  |                     <b>This</b> is the title | ||||||
|  |                 </a> | ||||||
|  |                 </h3> | ||||||
|  |             </div> | ||||||
|  |             <span class="url" dir="ltr">www.<b>test</b>.com</span> | ||||||
|  |             <div class="abstr"> | ||||||
|  |                 <b>This</b> is the content | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="res"> | ||||||
|  |             <div> | ||||||
|  |                 <h3> | ||||||
|  |                 </h3> | ||||||
|  |             </div> | ||||||
|  |             <span class="url" dir="ltr">www.<b>test</b>.com</span> | ||||||
|  |             <div class="abstr"> | ||||||
|  |                 <b>This</b> is the content | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=html) | ||||||
|  |         results = yahoo.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 1) | ||||||
|  |         self.assertEqual(results[0]['title'], 'This is the title') | ||||||
|  |         self.assertEqual(results[0]['url'], 'https://this.is.the.url/') | ||||||
|  |         self.assertEqual(results[0]['content'], 'This is the content') | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <li class="b_algo" u="0|5109|4755453613245655|UAGjXgIrPH5yh-o5oNHRx_3Zta87f_QO"> | ||||||
|  |         </li> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=html) | ||||||
|  |         results = yahoo.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 0) | ||||||
							
								
								
									
										143
									
								
								searx/tests/engines/test_yahoo_news.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								searx/tests/engines/test_yahoo_news.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,143 @@ | |||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | from collections import defaultdict | ||||||
|  | from datetime import datetime | ||||||
|  | import mock | ||||||
|  | from searx.engines import yahoo_news | ||||||
|  | from searx.testing import SearxTestCase | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestYahooNewsEngine(SearxTestCase): | ||||||
|  | 
 | ||||||
|  |     def test_request(self): | ||||||
|  |         query = 'test_query' | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['pageno'] = 1 | ||||||
|  |         dicto['language'] = 'fr_FR' | ||||||
|  |         params = yahoo_news.request(query, dicto) | ||||||
|  |         self.assertIn('url', params) | ||||||
|  |         self.assertIn(query, params['url']) | ||||||
|  |         self.assertIn('news.search.yahoo.com', params['url']) | ||||||
|  |         self.assertIn('fr', params['url']) | ||||||
|  |         self.assertIn('cookies', params) | ||||||
|  |         self.assertIn('sB', params['cookies']) | ||||||
|  |         self.assertIn('fr', params['cookies']['sB']) | ||||||
|  | 
 | ||||||
|  |         dicto['language'] = 'all' | ||||||
|  |         params = yahoo_news.request(query, dicto) | ||||||
|  |         self.assertIn('cookies', params) | ||||||
|  |         self.assertIn('sB', params['cookies']) | ||||||
|  |         self.assertIn('en', params['cookies']['sB']) | ||||||
|  |         self.assertIn('en', params['url']) | ||||||
|  | 
 | ||||||
|  |     def test_response(self): | ||||||
|  |         self.assertRaises(AttributeError, yahoo_news.response, None) | ||||||
|  |         self.assertRaises(AttributeError, yahoo_news.response, []) | ||||||
|  |         self.assertRaises(AttributeError, yahoo_news.response, '') | ||||||
|  |         self.assertRaises(AttributeError, yahoo_news.response, '[]') | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='<html></html>') | ||||||
|  |         self.assertEqual(yahoo_news.response(response), []) | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <div class="res"> | ||||||
|  |             <div> | ||||||
|  |                 <h3> | ||||||
|  |                     <a class="yschttl spt" href="http://this.is.the.url" target="_blank"> | ||||||
|  |                         This is | ||||||
|  |                         the <b>title</b>... | ||||||
|  |                     </a> | ||||||
|  |                 </h3> | ||||||
|  |             </div> | ||||||
|  |             <span class="url">Business via Yahoo! Finance</span>   <span class="timestamp">Feb 03 09:45am</span> | ||||||
|  |             <div class="abstr"> | ||||||
|  |                 This is the content | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=html) | ||||||
|  |         results = yahoo_news.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 1) | ||||||
|  |         self.assertEqual(results[0]['title'], 'This is the title...') | ||||||
|  |         self.assertEqual(results[0]['url'], 'http://this.is.the.url/') | ||||||
|  |         self.assertEqual(results[0]['content'], 'This is the content') | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <div class="res"> | ||||||
|  |             <div> | ||||||
|  |                 <h3> | ||||||
|  |                     <a class="yschttl spt" href="http://this.is.the.url" target="_blank"> | ||||||
|  |                         This is | ||||||
|  |                         the <b>title</b>... | ||||||
|  |                     </a> | ||||||
|  |                 </h3> | ||||||
|  |             </div> | ||||||
|  |             <span class="url">Business via Yahoo!</span>   <span class="timestamp">2 hours, 22 minutes ago</span> | ||||||
|  |             <div class="abstr"> | ||||||
|  |                 This is the content | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="res"> | ||||||
|  |             <div> | ||||||
|  |                 <h3> | ||||||
|  |                     <a class="yschttl spt" href="http://this.is.the.url" target="_blank"> | ||||||
|  |                         This is | ||||||
|  |                         the <b>title</b>... | ||||||
|  |                     </a> | ||||||
|  |                 </h3> | ||||||
|  |             </div> | ||||||
|  |             <span class="url">Business via Yahoo!</span>   <span class="timestamp">22 minutes ago</span> | ||||||
|  |             <div class="abstr"> | ||||||
|  |                 This is the content | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="res"> | ||||||
|  |             <div> | ||||||
|  |                 <h3> | ||||||
|  |                     <a class="yschttl spt" href="http://this.is.the.url" target="_blank"> | ||||||
|  |                         This is | ||||||
|  |                         the <b>title</b>... | ||||||
|  |                     </a> | ||||||
|  |                 </h3> | ||||||
|  |             </div> | ||||||
|  |             <span class="url">Business via Yahoo!</span>   <span class="timestamp">Feb 03 09:45am 1900</span> | ||||||
|  |             <div class="abstr"> | ||||||
|  |                 This is the content | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=html) | ||||||
|  |         results = yahoo_news.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 3) | ||||||
|  |         self.assertEqual(results[0]['title'], 'This is the title...') | ||||||
|  |         self.assertEqual(results[0]['url'], 'http://this.is.the.url/') | ||||||
|  |         self.assertEqual(results[0]['content'], 'This is the content') | ||||||
|  |         self.assertEqual(results[2]['publishedDate'].year, datetime.now().year) | ||||||
|  | 
 | ||||||
|  |         html = """ | ||||||
|  |         <li class="b_algo" u="0|5109|4755453613245655|UAGjXgIrPH5yh-o5oNHRx_3Zta87f_QO"> | ||||||
|  |             <div Class="sa_mc"> | ||||||
|  |                 <div class="sb_tlst"> | ||||||
|  |                     <h2> | ||||||
|  |                         <a href="http://this.should.be.the.link/" h="ID=SERP,5124.1"> | ||||||
|  |                         <strong>This</strong> should be the title</a> | ||||||
|  |                     </h2> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="sb_meta"> | ||||||
|  |                 <cite> | ||||||
|  |                 <strong>this</strong>.meta.com</cite> | ||||||
|  |                     <span class="c_tlbxTrg"> | ||||||
|  |                         <span class="c_tlbxH" H="BASE:CACHEDPAGEDEFAULT" K="SERP,5125.1"> | ||||||
|  |                         </span> | ||||||
|  |                     </span> | ||||||
|  |                 </div> | ||||||
|  |                 <p> | ||||||
|  |                 <strong>This</strong> should be the content.</p> | ||||||
|  |             </div> | ||||||
|  |         </li> | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=html) | ||||||
|  |         results = yahoo_news.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 0) | ||||||
| @ -3,25 +3,39 @@ from searx.tests.engines.test_bing_images import *  # noqa | |||||||
| from searx.tests.engines.test_bing_news import *  # noqa | from searx.tests.engines.test_bing_news import *  # noqa | ||||||
| from searx.tests.engines.test_blekko_images import *  # noqa | from searx.tests.engines.test_blekko_images import *  # noqa | ||||||
| from searx.tests.engines.test_btdigg import *  # noqa | from searx.tests.engines.test_btdigg import *  # noqa | ||||||
|  | from searx.tests.engines.test_currency_convert import *  # noqa | ||||||
| from searx.tests.engines.test_dailymotion import *  # noqa | from searx.tests.engines.test_dailymotion import *  # noqa | ||||||
| from searx.tests.engines.test_deezer import *  # noqa | from searx.tests.engines.test_deezer import *  # noqa | ||||||
| from searx.tests.engines.test_deviantart import *  # noqa | from searx.tests.engines.test_deviantart import *  # noqa | ||||||
| from searx.tests.engines.test_digg 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_dummy import *  # noqa | ||||||
|  | from searx.tests.engines.test_faroo import *  # noqa | ||||||
| from searx.tests.engines.test_flickr import *  # noqa | from searx.tests.engines.test_flickr import *  # noqa | ||||||
| from searx.tests.engines.test_flickr_noapi import *  # noqa | from searx.tests.engines.test_flickr_noapi import *  # noqa | ||||||
| from searx.tests.engines.test_gigablast import *  # noqa | from searx.tests.engines.test_gigablast import *  # noqa | ||||||
| from searx.tests.engines.test_github import *  # noqa | from searx.tests.engines.test_github import *  # noqa | ||||||
| from searx.tests.engines.test_www1x import *  # noqa | from searx.tests.engines.test_google import *  # noqa | ||||||
| from searx.tests.engines.test_google_images import *  # noqa | from searx.tests.engines.test_google_images import *  # noqa | ||||||
| from searx.tests.engines.test_google_news import *  # noqa | from searx.tests.engines.test_google_news import *  # noqa | ||||||
| from searx.tests.engines.test_kickass import *  # noqa | from searx.tests.engines.test_kickass import *  # noqa | ||||||
|  | from searx.tests.engines.test_mediawiki import *  # noqa | ||||||
| from searx.tests.engines.test_mixcloud import *  # noqa | from searx.tests.engines.test_mixcloud import *  # noqa | ||||||
|  | from searx.tests.engines.test_openstreetmap import *  # noqa | ||||||
|  | from searx.tests.engines.test_photon import *  # noqa | ||||||
| from searx.tests.engines.test_piratebay import *  # noqa | from searx.tests.engines.test_piratebay import *  # noqa | ||||||
| from searx.tests.engines.test_searchcode_code import *  # noqa | from searx.tests.engines.test_searchcode_code import *  # noqa | ||||||
| from searx.tests.engines.test_searchcode_doc import *  # noqa | from searx.tests.engines.test_searchcode_doc import *  # noqa | ||||||
| from searx.tests.engines.test_soundcloud import *  # noqa | from searx.tests.engines.test_soundcloud import *  # noqa | ||||||
| from searx.tests.engines.test_stackoverflow import *  # noqa | from searx.tests.engines.test_stackoverflow import *  # noqa | ||||||
|  | from searx.tests.engines.test_startpage import *  # noqa | ||||||
|  | from searx.tests.engines.test_subtitleseeker import *  # noqa | ||||||
|  | from searx.tests.engines.test_twitter import *  # noqa | ||||||
| from searx.tests.engines.test_vimeo import *  # noqa | from searx.tests.engines.test_vimeo import *  # noqa | ||||||
|  | from searx.tests.engines.test_www1x import *  # noqa | ||||||
| from searx.tests.engines.test_www500px import *  # noqa | from searx.tests.engines.test_www500px import *  # noqa | ||||||
|  | from searx.tests.engines.test_yacy import *  # noqa | ||||||
|  | from searx.tests.engines.test_yahoo import *  # noqa | ||||||
| from searx.tests.engines.test_youtube import *  # noqa | from searx.tests.engines.test_youtube import *  # noqa | ||||||
|  | from searx.tests.engines.test_yahoo_news import *  # noqa | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user