Browse Source

Merge branch 'Cqoicebordel-unit-tests'

Adam Tauber 10 years ago
parent
commit
0e6f8393ab
45 changed files with 3692 additions and 71 deletions
  1. 1
    0
      .gitignore
  2. 5
    4
      searx/engines/bing.py
  3. 4
    1
      searx/engines/bing_images.py
  4. 12
    19
      searx/engines/bing_news.py
  5. 3
    8
      searx/engines/btdigg.py
  6. 4
    3
      searx/engines/deviantart.py
  7. 1
    1
      searx/engines/digg.py
  8. 1
    1
      searx/engines/flickr_noapi.py
  9. 3
    3
      searx/engines/google_images.py
  10. 4
    2
      searx/engines/google_news.py
  11. 4
    4
      searx/engines/kickass.py
  12. 8
    4
      searx/engines/piratebay.py
  13. 1
    1
      searx/engines/searchcode_code.py
  14. 1
    1
      searx/engines/searchcode_doc.py
  15. 4
    4
      searx/engines/stackoverflow.py
  16. 1
    2
      searx/engines/vimeo.py
  17. 6
    5
      searx/engines/www500px.py
  18. 2
    2
      searx/engines/xpath.py
  19. 2
    2
      searx/engines/youtube.py
  20. 3
    3
      searx/settings.yml
  21. 90
    0
      searx/tests/engines/test_bing.py
  22. 268
    0
      searx/tests/engines/test_bing_images.py
  23. 236
    0
      searx/tests/engines/test_bing_news.py
  24. 384
    0
      searx/tests/engines/test_btdigg.py
  25. 74
    0
      searx/tests/engines/test_dailymotion.py
  26. 57
    0
      searx/tests/engines/test_deezer.py
  27. 118
    0
      searx/tests/engines/test_deviantart.py
  28. 101
    0
      searx/tests/engines/test_digg.py
  29. 142
    0
      searx/tests/engines/test_flickr.py
  30. 442
    0
      searx/tests/engines/test_flickr_noapi.py
  31. 108
    0
      searx/tests/engines/test_google_images.py
  32. 136
    0
      searx/tests/engines/test_google_news.py
  33. 398
    0
      searx/tests/engines/test_kickass.py
  34. 67
    0
      searx/tests/engines/test_mixcloud.py
  35. 137
    0
      searx/tests/engines/test_piratebay.py
  36. 75
    0
      searx/tests/engines/test_searchcode_code.py
  37. 73
    0
      searx/tests/engines/test_searchcode_doc.py
  38. 192
    0
      searx/tests/engines/test_soundcloud.py
  39. 106
    0
      searx/tests/engines/test_stackoverflow.py
  40. 84
    0
      searx/tests/engines/test_vimeo.py
  41. 83
    0
      searx/tests/engines/test_www500px.py
  42. 204
    0
      searx/tests/engines/test_youtube.py
  43. 22
    0
      searx/tests/test_engines.py
  44. 22
    0
      searx/tests/test_utils.py
  45. 3
    1
      searx/utils.py

+ 1
- 0
.gitignore View File

@@ -23,3 +23,4 @@ local/
23 23
 parts/
24 24
 searx.egg-info/
25 25
 var/
26
+node_modules/

+ 5
- 4
searx/engines/bing.py View File

@@ -14,6 +14,7 @@
14 14
 from urllib import urlencode
15 15
 from cgi import escape
16 16
 from lxml import html
17
+from searx.engines.xpath import extract_text
17 18
 
18 19
 # engine dependent config
19 20
 categories = ['general']
@@ -55,8 +56,8 @@ def response(resp):
55 56
     for result in dom.xpath('//div[@class="sa_cc"]'):
56 57
         link = result.xpath('.//h3/a')[0]
57 58
         url = link.attrib.get('href')
58
-        title = ' '.join(link.xpath('.//text()'))
59
-        content = escape(' '.join(result.xpath('.//p//text()')))
59
+        title = extract_text(link)
60
+        content = escape(extract_text(result.xpath('.//p')))
60 61
 
61 62
         # append result
62 63
         results.append({'url': url,
@@ -71,8 +72,8 @@ def response(resp):
71 72
     for result in dom.xpath('//li[@class="b_algo"]'):
72 73
         link = result.xpath('.//h2/a')[0]
73 74
         url = link.attrib.get('href')
74
-        title = ' '.join(link.xpath('.//text()'))
75
-        content = escape(' '.join(result.xpath('.//p//text()')))
75
+        title = extract_text(link)
76
+        content = escape(extract_text(result.xpath('.//p')))
76 77
 
77 78
         # append result
78 79
         results.append({'url': url,

+ 4
- 1
searx/engines/bing_images.py View File

@@ -33,7 +33,10 @@ def request(query, params):
33 33
     offset = (params['pageno'] - 1) * 10 + 1
34 34
 
35 35
     # required for cookie
36
-    language = 'en-US'
36
+    if params['language'] == 'all':
37
+        language = 'en-US'
38
+    else:
39
+        language = params['language'].replace('_', '-')
37 40
 
38 41
     search_path = search_string.format(
39 42
         query=urlencode({'q': query}),

+ 12
- 19
searx/engines/bing_news.py View File

@@ -15,6 +15,7 @@ from lxml import html
15 15
 from datetime import datetime, timedelta
16 16
 from dateutil import parser
17 17
 import re
18
+from searx.engines.xpath import extract_text
18 19
 
19 20
 # engine dependent config
20 21
 categories = ['news']
@@ -42,6 +43,7 @@ def request(query, params):
42 43
     params['cookies']['_FP'] = "ui=en-US"
43 44
 
44 45
     params['url'] = base_url + search_path
46
+
45 47
     return params
46 48
 
47 49
 
@@ -55,44 +57,35 @@ def response(resp):
55 57
     for result in dom.xpath('//div[@class="sn_r"]'):
56 58
         link = result.xpath('.//div[@class="newstitle"]/a')[0]
57 59
         url = link.attrib.get('href')
58
-        title = ' '.join(link.xpath('.//text()'))
59
-        contentXPath = result.xpath('.//div[@class="sn_txt"]/div'
60
-                                    '//span[@class="sn_snip"]//text()')
61
-        if contentXPath is not None:
62
-            content = escape(' '.join(contentXPath))
60
+        title = extract_text(link)
61
+        contentXPath = result.xpath('.//div[@class="sn_txt"]/div//span[@class="sn_snip"]')
62
+        content = escape(extract_text(contentXPath))
63 63
 
64 64
         # parse publishedDate
65 65
         publishedDateXPath = result.xpath('.//div[@class="sn_txt"]/div'
66 66
                                           '//span[contains(@class,"sn_ST")]'
67
-                                          '//span[contains(@class,"sn_tm")]'
68
-                                          '//text()')
69
-        if publishedDateXPath is not None:
70
-            publishedDate = escape(' '.join(publishedDateXPath))
67
+                                          '//span[contains(@class,"sn_tm")]')
68
+
69
+        publishedDate = escape(extract_text(publishedDateXPath))
71 70
 
72 71
         if re.match("^[0-9]+ minute(s|) ago$", publishedDate):
73 72
             timeNumbers = re.findall(r'\d+', publishedDate)
74
-            publishedDate = datetime.now()\
75
-                - timedelta(minutes=int(timeNumbers[0]))
73
+            publishedDate = datetime.now() - timedelta(minutes=int(timeNumbers[0]))
76 74
         elif re.match("^[0-9]+ hour(s|) ago$", publishedDate):
77 75
             timeNumbers = re.findall(r'\d+', publishedDate)
78
-            publishedDate = datetime.now()\
79
-                - timedelta(hours=int(timeNumbers[0]))
80
-        elif re.match("^[0-9]+ hour(s|),"
81
-                      " [0-9]+ minute(s|) ago$", publishedDate):
76
+            publishedDate = datetime.now() - timedelta(hours=int(timeNumbers[0]))
77
+        elif re.match("^[0-9]+ hour(s|), [0-9]+ minute(s|) ago$", publishedDate):
82 78
             timeNumbers = re.findall(r'\d+', publishedDate)
83 79
             publishedDate = datetime.now()\
84 80
                 - timedelta(hours=int(timeNumbers[0]))\
85 81
                 - timedelta(minutes=int(timeNumbers[1]))
86 82
         elif re.match("^[0-9]+ day(s|) ago$", publishedDate):
87 83
             timeNumbers = re.findall(r'\d+', publishedDate)
88
-            publishedDate = datetime.now()\
89
-                - timedelta(days=int(timeNumbers[0]))
84
+            publishedDate = datetime.now() - timedelta(days=int(timeNumbers[0]))
90 85
         else:
91 86
             try:
92
-                # FIXME use params['language'] to parse either mm/dd or dd/mm
93 87
                 publishedDate = parser.parse(publishedDate, dayfirst=False)
94 88
             except TypeError:
95
-                # FIXME
96 89
                 publishedDate = datetime.now()
97 90
 
98 91
         # append result

+ 3
- 8
searx/engines/btdigg.py View File

@@ -23,11 +23,6 @@ paging = True
23 23
 url = 'https://btdigg.org'
24 24
 search_url = url + '/search?q={search_term}&p={pageno}'
25 25
 
26
-# specific xpath variables
27
-magnet_xpath = './/a[@title="Torrent magnet link"]'
28
-torrent_xpath = './/a[@title="Download torrent file"]'
29
-content_xpath = './/span[@class="font11px lightgrey block"]'
30
-
31 26
 
32 27
 # do search-request
33 28
 def request(query, params):
@@ -52,8 +47,8 @@ def response(resp):
52 47
     # parse results
53 48
     for result in search_res:
54 49
         link = result.xpath('.//td[@class="torrent_name"]//a')[0]
55
-        href = urljoin(url, link.attrib['href'])
56
-        title = escape(extract_text(link.xpath('.//text()')))
50
+        href = urljoin(url, link.attrib.get('href'))
51
+        title = escape(extract_text(link))
57 52
         content = escape(extract_text(result.xpath('.//pre[@class="snippet"]')[0]))
58 53
         content = "<br />".join(content.split("\n"))
59 54
 
@@ -81,7 +76,7 @@ def response(resp):
81 76
                 filesize = int(filesize * 1024 * 1024 * 1024)
82 77
             elif filesize_multiplier == 'MB':
83 78
                 filesize = int(filesize * 1024 * 1024)
84
-            elif filesize_multiplier == 'kb':
79
+            elif filesize_multiplier == 'KB':
85 80
                 filesize = int(filesize * 1024)
86 81
         except:
87 82
             filesize = None

+ 4
- 3
searx/engines/deviantart.py View File

@@ -14,6 +14,7 @@ from urllib import urlencode
14 14
 from urlparse import urljoin
15 15
 from lxml import html
16 16
 import re
17
+from searx.engines.xpath import extract_text
17 18
 
18 19
 # engine dependent config
19 20
 categories = ['images']
@@ -50,9 +51,9 @@ def response(resp):
50 51
     for result in dom.xpath('//div[contains(@class, "tt-a tt-fh")]'):
51 52
         link = result.xpath('.//a[contains(@class, "thumb")]')[0]
52 53
         url = urljoin(base_url, link.attrib.get('href'))
53
-        title_links = result.xpath('.//span[@class="details"]//a[contains(@class, "t")]')  # noqa
54
-        title = ''.join(title_links[0].xpath('.//text()'))
55
-        thumbnail_src = link.xpath('.//img')[0].attrib['src']
54
+        title_links = result.xpath('.//span[@class="details"]//a[contains(@class, "t")]')
55
+        title = extract_text(title_links[0])
56
+        thumbnail_src = link.xpath('.//img')[0].attrib.get('src')
56 57
         img_src = regex.sub('/', thumbnail_src)
57 58
 
58 59
         # append result

+ 1
- 1
searx/engines/digg.py View File

@@ -44,7 +44,7 @@ def response(resp):
44 44
 
45 45
     search_result = loads(resp.text)
46 46
 
47
-    if search_result['html'] == '':
47
+    if 'html' not in search_result or search_result['html'] == '':
48 48
         return results
49 49
 
50 50
     dom = html.fromstring(search_result['html'])

+ 1
- 1
searx/engines/flickr_noapi.py View File

@@ -21,7 +21,7 @@ logger = logger.getChild('flickr-noapi')
21 21
 categories = ['images']
22 22
 
23 23
 url = 'https://secure.flickr.com/'
24
-search_url = url+'search/?{query}&page={page}'
24
+search_url = url + 'search/?{query}&page={page}'
25 25
 photo_url = 'https://www.flickr.com/photos/{userid}/{photoid}'
26 26
 regex = re.compile(r"\"search-photos-models\",\"photos\":(.*}),\"totalItems\":", re.DOTALL)
27 27
 image_sizes = ('o', 'k', 'h', 'b', 'c', 'z', 'n', 'm', 't', 'q', 's')

+ 3
- 3
searx/engines/google_images.py View File

@@ -18,7 +18,7 @@ paging = True
18 18
 
19 19
 # search-url
20 20
 url = 'https://ajax.googleapis.com/'
21
-search_url = url + 'ajax/services/search/images?v=1.0&start={offset}&rsz=large&safe=off&filter=off&{query}'  # noqa
21
+search_url = url + 'ajax/services/search/images?v=1.0&start={offset}&rsz=large&safe=off&filter=off&{query}'
22 22
 
23 23
 
24 24
 # do search-request
@@ -45,14 +45,14 @@ def response(resp):
45 45
     for result in search_res['responseData']['results']:
46 46
         href = result['originalContextUrl']
47 47
         title = result['title']
48
-        if not result['url']:
48
+        if 'url' not in result:
49 49
             continue
50 50
         thumbnail_src = result['tbUrl']
51 51
 
52 52
         # append result
53 53
         results.append({'url': href,
54 54
                         'title': title,
55
-                        'content': '',
55
+                        'content': result['content'],
56 56
                         'thumbnail_src': thumbnail_src,
57 57
                         'img_src': unquote(result['url']),
58 58
                         'template': 'images.html'})

+ 4
- 2
searx/engines/google_news.py View File

@@ -20,7 +20,7 @@ language_support = True
20 20
 
21 21
 # engine dependent config
22 22
 url = 'https://ajax.googleapis.com/'
23
-search_url = url + 'ajax/services/search/news?v=2.0&start={offset}&rsz=large&safe=off&filter=off&{query}&hl={language}'  # noqa
23
+search_url = url + 'ajax/services/search/news?v=2.0&start={offset}&rsz=large&safe=off&filter=off&{query}&hl={lang}'
24 24
 
25 25
 
26 26
 # do search-request
@@ -33,7 +33,7 @@ def request(query, params):
33 33
 
34 34
     params['url'] = search_url.format(offset=offset,
35 35
                                       query=urlencode({'q': query}),
36
-                                      language=language)
36
+                                      lang=language)
37 37
 
38 38
     return params
39 39
 
@@ -52,6 +52,8 @@ def response(resp):
52 52
     for result in search_res['responseData']['results']:
53 53
         # parse publishedDate
54 54
         publishedDate = parser.parse(result['publishedDate'])
55
+        if 'url' not in result:
56
+            continue
55 57
 
56 58
         # append result
57 59
         results.append({'url': result['unescapedUrl'],

+ 4
- 4
searx/engines/kickass.py View File

@@ -13,6 +13,7 @@ from cgi import escape
13 13
 from urllib import quote
14 14
 from lxml import html
15 15
 from operator import itemgetter
16
+from searx.engines.xpath import extract_text
16 17
 
17 18
 # engine dependent config
18 19
 categories = ['videos', 'music', 'files']
@@ -56,9 +57,8 @@ def response(resp):
56 57
     for result in search_res[1:]:
57 58
         link = result.xpath('.//a[@class="cellMainLink"]')[0]
58 59
         href = urljoin(url, link.attrib['href'])
59
-        title = ' '.join(link.xpath('.//text()'))
60
-        content = escape(html.tostring(result.xpath(content_xpath)[0],
61
-                                       method="text"))
60
+        title = extract_text(link)
61
+        content = escape(extract_text(result.xpath(content_xpath)))
62 62
         seed = result.xpath('.//td[contains(@class, "green")]/text()')[0]
63 63
         leech = result.xpath('.//td[contains(@class, "red")]/text()')[0]
64 64
         filesize = result.xpath('.//td[contains(@class, "nobr")]/text()')[0]
@@ -88,7 +88,7 @@ def response(resp):
88 88
                 filesize = int(filesize * 1024 * 1024 * 1024)
89 89
             elif filesize_multiplier == 'MB':
90 90
                 filesize = int(filesize * 1024 * 1024)
91
-            elif filesize_multiplier == 'kb':
91
+            elif filesize_multiplier == 'KB':
92 92
                 filesize = int(filesize * 1024)
93 93
         except:
94 94
             filesize = None

+ 8
- 4
searx/engines/piratebay.py View File

@@ -13,6 +13,7 @@ from cgi import escape
13 13
 from urllib import quote
14 14
 from lxml import html
15 15
 from operator import itemgetter
16
+from searx.engines.xpath import extract_text
16 17
 
17 18
 # engine dependent config
18 19
 categories = ['videos', 'music', 'files']
@@ -29,7 +30,8 @@ search_types = {'files': '0',
29 30
 
30 31
 # specific xpath variables
31 32
 magnet_xpath = './/a[@title="Download this torrent using magnet"]'
32
-content_xpath = './/font[@class="detDesc"]//text()'
33
+torrent_xpath = './/a[@title="Download this torrent"]'
34
+content_xpath = './/font[@class="detDesc"]'
33 35
 
34 36
 
35 37
 # do search-request
@@ -59,8 +61,8 @@ def response(resp):
59 61
     for result in search_res[1:]:
60 62
         link = result.xpath('.//div[@class="detName"]//a')[0]
61 63
         href = urljoin(url, link.attrib.get('href'))
62
-        title = ' '.join(link.xpath('.//text()'))
63
-        content = escape(' '.join(result.xpath(content_xpath)))
64
+        title = extract_text(link)
65
+        content = escape(extract_text(result.xpath(content_xpath)))
64 66
         seed, leech = result.xpath('.//td[@align="right"]/text()')[:2]
65 67
 
66 68
         # convert seed to int if possible
@@ -76,6 +78,7 @@ def response(resp):
76 78
             leech = 0
77 79
 
78 80
         magnetlink = result.xpath(magnet_xpath)[0]
81
+        torrentfile = result.xpath(torrent_xpath)[0]
79 82
 
80 83
         # append result
81 84
         results.append({'url': href,
@@ -83,7 +86,8 @@ def response(resp):
83 86
                         'content': content,
84 87
                         'seed': seed,
85 88
                         'leech': leech,
86
-                        'magnetlink': magnetlink.attrib['href'],
89
+                        'magnetlink': magnetlink.attrib.get('href'),
90
+                        'torrentfile': torrentfile.attrib.get('href'),
87 91
                         'template': 'torrent.html'})
88 92
 
89 93
     # return results sorted by seeder

+ 1
- 1
searx/engines/searchcode_code.py View File

@@ -42,7 +42,7 @@ def response(resp):
42 42
     search_results = loads(resp.text)
43 43
 
44 44
     # parse results
45
-    for result in search_results['results']:
45
+    for result in search_results.get('results', []):
46 46
         href = result['url']
47 47
         title = "" + result['name'] + " - " + result['filename']
48 48
         repo = result['repo']

+ 1
- 1
searx/engines/searchcode_doc.py View File

@@ -35,7 +35,7 @@ def response(resp):
35 35
     search_results = loads(resp.text)
36 36
 
37 37
     # parse results
38
-    for result in search_results['results']:
38
+    for result in search_results.get('results', []):
39 39
         href = result['url']
40 40
         title = "[" + result['type'] + "] " +\
41 41
                 result['namespace'] +\

+ 4
- 4
searx/engines/stackoverflow.py View File

@@ -12,6 +12,7 @@ from urlparse import urljoin
12 12
 from cgi import escape
13 13
 from urllib import urlencode
14 14
 from lxml import html
15
+from searx.engines.xpath import extract_text
15 16
 
16 17
 # engine dependent config
17 18
 categories = ['it']
@@ -24,8 +25,7 @@ search_url = url+'search?{query}&page={pageno}'
24 25
 # specific xpath variables
25 26
 results_xpath = '//div[contains(@class,"question-summary")]'
26 27
 link_xpath = './/div[@class="result-link"]//a|.//div[@class="summary"]//h3//a'
27
-title_xpath = './/text()'
28
-content_xpath = './/div[@class="excerpt"]//text()'
28
+content_xpath = './/div[@class="excerpt"]'
29 29
 
30 30
 
31 31
 # do search-request
@@ -46,8 +46,8 @@ def response(resp):
46 46
     for result in dom.xpath(results_xpath):
47 47
         link = result.xpath(link_xpath)[0]
48 48
         href = urljoin(url, link.attrib.get('href'))
49
-        title = escape(' '.join(link.xpath(title_xpath)))
50
-        content = escape(' '.join(result.xpath(content_xpath)))
49
+        title = escape(extract_text(link))
50
+        content = escape(extract_text(result.xpath(content_xpath)))
51 51
 
52 52
         # append result
53 53
         results.append({'url': href,

+ 1
- 2
searx/engines/vimeo.py View File

@@ -59,8 +59,7 @@ def response(resp):
59 59
         url = base_url + videoid
60 60
         title = p.unescape(extract_text(result.xpath(title_xpath)))
61 61
         thumbnail = extract_text(result.xpath(content_xpath)[0])
62
-        publishedDate = parser.parse(extract_text(
63
-            result.xpath(publishedDate_xpath)[0]))
62
+        publishedDate = parser.parse(extract_text(result.xpath(publishedDate_xpath)[0]))
64 63
         embedded = embedded_url.format(videoid=videoid)
65 64
 
66 65
         # append result

+ 6
- 5
searx/engines/www500px.py View File

@@ -15,6 +15,7 @@ from urllib import urlencode
15 15
 from urlparse import urljoin
16 16
 from lxml import html
17 17
 import re
18
+from searx.engines.xpath import extract_text
18 19
 
19 20
 # engine dependent config
20 21
 categories = ['images']
@@ -22,7 +23,7 @@ paging = True
22 23
 
23 24
 # search-url
24 25
 base_url = 'https://500px.com'
25
-search_url = base_url+'/search?search?page={pageno}&type=photos&{query}'
26
+search_url = base_url + '/search?search?page={pageno}&type=photos&{query}'
26 27
 
27 28
 
28 29
 # do search-request
@@ -44,11 +45,11 @@ def response(resp):
44 45
     for result in dom.xpath('//div[@class="photo"]'):
45 46
         link = result.xpath('.//a')[0]
46 47
         url = urljoin(base_url, link.attrib.get('href'))
47
-        title = result.xpath('.//div[@class="title"]//text()')[0]
48
-        thumbnail_src = link.xpath('.//img')[0].attrib['src']
48
+        title = extract_text(result.xpath('.//div[@class="title"]'))
49
+        thumbnail_src = link.xpath('.//img')[0].attrib.get('src')
49 50
         # To have a bigger thumbnail, uncomment the next line
50
-        #thumbnail_src = regex.sub('4.jpg', thumbnail_src)
51
-        content = result.xpath('.//div[@class="info"]//text()')[0]
51
+        # thumbnail_src = regex.sub('4.jpg', thumbnail_src)
52
+        content = extract_text(result.xpath('.//div[@class="info"]'))
52 53
         img_src = regex.sub('2048.jpg', thumbnail_src)
53 54
 
54 55
         # append result

+ 2
- 2
searx/engines/xpath.py View File

@@ -28,13 +28,13 @@ def extract_text(xpath_results):
28 28
         result = ''
29 29
         for e in xpath_results:
30 30
             result = result + extract_text(e)
31
-        return result
31
+        return result.strip()
32 32
     elif type(xpath_results) in [_ElementStringResult, _ElementUnicodeResult]:
33 33
         # it's a string
34 34
         return ''.join(xpath_results)
35 35
     else:
36 36
         # it's a element
37
-        return html_to_text(xpath_results.text_content())
37
+        return html_to_text(xpath_results.text_content()).strip()
38 38
 
39 39
 
40 40
 def extract_url(xpath_results, search_url):

+ 2
- 2
searx/engines/youtube.py View File

@@ -57,7 +57,7 @@ def response(resp):
57 57
         url = [x['href'] for x in result['link'] if x['type'] == 'text/html']
58 58
 
59 59
         if not url:
60
-            return
60
+            continue
61 61
 
62 62
         # remove tracking
63 63
         url = url[0].replace('feature=youtube_gdata', '')
@@ -73,7 +73,7 @@ def response(resp):
73 73
         pubdate = result['published']['$t']
74 74
         publishedDate = parser.parse(pubdate)
75 75
 
76
-        if result['media$group']['media$thumbnail']:
76
+        if 'media$thumbnail' in result['media$group']:
77 77
             thumbnail = result['media$group']['media$thumbnail'][0]['url']
78 78
 
79 79
         content = result['content']['$t']

+ 3
- 3
searx/settings.yml View File

@@ -161,9 +161,9 @@ engines:
161 161
     engine : photon
162 162
     shortcut : ph
163 163
 
164
-#  - name : piratebay
165
-#    engine : piratebay
166
-#    shortcut : tpb
164
+  - name : piratebay
165
+    engine : piratebay
166
+    shortcut : tpb
167 167
 
168 168
   - name : kickass
169 169
     engine : kickass

+ 90
- 0
searx/tests/engines/test_bing.py View File

@@ -0,0 +1,90 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import bing
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestBingEngine(SearxTestCase):
8
+
9
+    def test_request(self):
10
+        query = 'test_query'
11
+        dicto = defaultdict(dict)
12
+        dicto['pageno'] = 0
13
+        dicto['language'] = 'fr_FR'
14
+        params = bing.request(query, dicto)
15
+        self.assertTrue('url' in params)
16
+        self.assertTrue(query in params['url'])
17
+        self.assertTrue('bing.com' in params['url'])
18
+        self.assertTrue('SRCHHPGUSR' in params['cookies'])
19
+        self.assertTrue('fr' in params['cookies']['SRCHHPGUSR'])
20
+
21
+        dicto['language'] = 'all'
22
+        params = bing.request(query, dicto)
23
+        self.assertTrue('SRCHHPGUSR' in params['cookies'])
24
+        self.assertTrue('en' in params['cookies']['SRCHHPGUSR'])
25
+
26
+    def test_response(self):
27
+        self.assertRaises(AttributeError, bing.response, None)
28
+        self.assertRaises(AttributeError, bing.response, [])
29
+        self.assertRaises(AttributeError, bing.response, '')
30
+        self.assertRaises(AttributeError, bing.response, '[]')
31
+
32
+        response = mock.Mock(content='<html></html>')
33
+        self.assertEqual(bing.response(response), [])
34
+
35
+        response = mock.Mock(content='<html></html>')
36
+        self.assertEqual(bing.response(response), [])
37
+
38
+        html = """
39
+        <div class="sa_cc" u="0|5109|4755453613245655|UAGjXgIrPH5yh-o5oNHRx_3Zta87f_QO">
40
+            <div Class="sa_mc">
41
+                <div class="sb_tlst">
42
+                    <h3>
43
+                        <a href="http://this.should.be.the.link/" h="ID=SERP,5124.1">
44
+                        <strong>This</strong> should be the title</a>
45
+                    </h3>
46
+                </div>
47
+                <div class="sb_meta"><cite><strong>this</strong>.meta.com</cite>
48
+                    <span class="c_tlbxTrg">
49
+                        <span class="c_tlbxH" H="BASE:CACHEDPAGEDEFAULT" K="SERP,5125.1">
50
+                        </span>
51
+                    </span>
52
+                </div>
53
+                <p><strong>This</strong> should be the content.</p>
54
+            </div>
55
+        </div>
56
+        """
57
+        response = mock.Mock(content=html)
58
+        results = bing.response(response)
59
+        self.assertEqual(type(results), list)
60
+        self.assertEqual(len(results), 1)
61
+        self.assertEqual(results[0]['title'], 'This should be the title')
62
+        self.assertEqual(results[0]['url'], 'http://this.should.be.the.link/')
63
+        self.assertEqual(results[0]['content'], 'This should be the content.')
64
+
65
+        html = """
66
+        <li class="b_algo" u="0|5109|4755453613245655|UAGjXgIrPH5yh-o5oNHRx_3Zta87f_QO">
67
+            <div Class="sa_mc">
68
+                <div class="sb_tlst">
69
+                    <h2>
70
+                        <a href="http://this.should.be.the.link/" h="ID=SERP,5124.1">
71
+                        <strong>This</strong> should be the title</a>
72
+                    </h2>
73
+                </div>
74
+                <div class="sb_meta"><cite><strong>this</strong>.meta.com</cite>
75
+                    <span class="c_tlbxTrg">
76
+                        <span class="c_tlbxH" H="BASE:CACHEDPAGEDEFAULT" K="SERP,5125.1">
77
+                        </span>
78
+                    </span>
79
+                </div>
80
+                <p><strong>This</strong> should be the content.</p>
81
+            </div>
82
+        </li>
83
+        """
84
+        response = mock.Mock(content=html)
85
+        results = bing.response(response)
86
+        self.assertEqual(type(results), list)
87
+        self.assertEqual(len(results), 1)
88
+        self.assertEqual(results[0]['title'], 'This should be the title')
89
+        self.assertEqual(results[0]['url'], 'http://this.should.be.the.link/')
90
+        self.assertEqual(results[0]['content'], 'This should be the content.')

+ 268
- 0
searx/tests/engines/test_bing_images.py View File

@@ -0,0 +1,268 @@
1
+# -*- coding: utf-8 -*-
2
+from collections import defaultdict
3
+import mock
4
+from searx.engines import bing_images
5
+from searx.testing import SearxTestCase
6
+
7
+
8
+class TestBingImagesEngine(SearxTestCase):
9
+
10
+    def test_request(self):
11
+        query = 'test_query'
12
+        dicto = defaultdict(dict)
13
+        dicto['pageno'] = 1
14
+        dicto['language'] = 'fr_FR'
15
+        params = bing_images.request(query, dicto)
16
+        self.assertTrue('url' in params)
17
+        self.assertTrue(query in params['url'])
18
+        self.assertTrue('bing.com' in params['url'])
19
+        self.assertTrue('SRCHHPGUSR' in params['cookies'])
20
+        self.assertTrue('fr' in params['cookies']['SRCHHPGUSR'])
21
+
22
+        dicto['language'] = 'all'
23
+        params = bing_images.request(query, dicto)
24
+        self.assertIn('SRCHHPGUSR', params['cookies'])
25
+        self.assertIn('en', params['cookies']['SRCHHPGUSR'])
26
+
27
+    def test_response(self):
28
+        self.assertRaises(AttributeError, bing_images.response, None)
29
+        self.assertRaises(AttributeError, bing_images.response, [])
30
+        self.assertRaises(AttributeError, bing_images.response, '')
31
+        self.assertRaises(AttributeError, bing_images.response, '[]')
32
+
33
+        response = mock.Mock(content='<html></html>')
34
+        self.assertEqual(bing_images.response(response), [])
35
+
36
+        response = mock.Mock(content='<html></html>')
37
+        self.assertEqual(bing_images.response(response), [])
38
+
39
+        html = """
40
+        <div class="dg_u" style="width:178px;height:144px;left:17px;top:0px">
41
+            <a href="#" ihk="HN.608003696942779811"
42
+                m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
43
+mid:&quot;659EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
44
+surl:&quot;http://www.page.url/&quot;,imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,
45
+oh:&quot;238&quot;,tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
46
+                mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
47
+                t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
48
+                <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
49
+                style="height:144px;" width="178" height="144"/>
50
+            </a>
51
+        </div>
52
+        """
53
+        html = html.replace('\r\n', '').replace('\n', '').replace('\r', '')
54
+        response = mock.Mock(content=html)
55
+        results = bing_images.response(response)
56
+        self.assertEqual(type(results), list)
57
+        self.assertEqual(len(results), 1)
58
+        self.assertEqual(results[0]['title'], 'Test Query')
59
+        self.assertEqual(results[0]['url'], 'http://www.page.url/')
60
+        self.assertEqual(results[0]['content'], '')
61
+        self.assertEqual(results[0]['thumbnail_src'], 'http://ts1.mm.bing.net/th?id=HN.608003696942779811')
62
+        self.assertEqual(results[0]['img_src'], 'http://test.url/Test%20Query.jpg')
63
+
64
+        html = """
65
+        <a href="#" ihk="HN.608003696942779811"
66
+            m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
67
+            mid:&quot;59EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
68
+            surl:&quot;http://www.page.url/&quot;,
69
+            imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,oh:&quot;238&quot;,
70
+            tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
71
+            mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
72
+            t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
73
+            <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
74
+            style="height:144px;" width="178" height="144"/>
75
+        </a>
76
+        """
77
+        response = mock.Mock(content=html)
78
+        results = bing_images.response(response)
79
+        self.assertEqual(type(results), list)
80
+        self.assertEqual(len(results), 0)
81
+
82
+        html = """
83
+        <div class="dg_u" style="width:178px;height:144px;left:17px;top:0px">
84
+            <a href="#" ihk="HN.608003696942779811"
85
+                m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
86
+mid:&quot;659EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
87
+surl:&quot;http://www.page.url/&quot;,imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,
88
+oh:&quot;238&quot;,tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
89
+                mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
90
+                t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
91
+                <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
92
+                style="height:144px;" width="178" height="144"/>
93
+            </a>
94
+        </div>
95
+        <div class="dg_u" style="width:178px;height:144px;left:17px;top:0px">
96
+            <a href="#" ihk="HN.608003696942779811"
97
+                m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
98
+mid:&quot;659EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
99
+surl:&quot;http://www.page.url/&quot;,imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,
100
+oh:&quot;238&quot;,tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
101
+                mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
102
+                t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
103
+                <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
104
+                style="height:144px;" width="178" height="144"/>
105
+            </a>
106
+        </div>
107
+        <div class="dg_u" style="width:178px;height:144px;left:17px;top:0px">
108
+            <a href="#" ihk="HN.608003696942779811"
109
+                m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
110
+mid:&quot;659EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
111
+surl:&quot;http://www.page.url/&quot;,imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,
112
+oh:&quot;238&quot;,tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
113
+                mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
114
+                t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
115
+                <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
116
+                style="height:144px;" width="178" height="144"/>
117
+            </a>
118
+        </div>
119
+        <div class="dg_u" style="width:178px;height:144px;left:17px;top:0px">
120
+            <a href="#" ihk="HN.608003696942779811"
121
+                m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
122
+mid:&quot;659EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
123
+surl:&quot;http://www.page.url/&quot;,imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,
124
+oh:&quot;238&quot;,tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
125
+                mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
126
+                t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
127
+                <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
128
+                style="height:144px;" width="178" height="144"/>
129
+            </a>
130
+        </div>
131
+        <div class="dg_u" style="width:178px;height:144px;left:17px;top:0px">
132
+            <a href="#" ihk="HN.608003696942779811"
133
+                m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
134
+mid:&quot;659EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
135
+surl:&quot;http://www.page.url/&quot;,imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,
136
+oh:&quot;238&quot;,tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
137
+                mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
138
+                t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
139
+                <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
140
+                style="height:144px;" width="178" height="144"/>
141
+            </a>
142
+        </div>
143
+        <div class="dg_u" style="width:178px;height:144px;left:17px;top:0px">
144
+            <a href="#" ihk="HN.608003696942779811"
145
+                m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
146
+mid:&quot;659EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
147
+surl:&quot;http://www.page.url/&quot;,imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,
148
+oh:&quot;238&quot;,tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
149
+                mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
150
+                t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
151
+                <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
152
+                style="height:144px;" width="178" height="144"/>
153
+            </a>
154
+        </div>
155
+        <div class="dg_u" style="width:178px;height:144px;left:17px;top:0px">
156
+            <a href="#" ihk="HN.608003696942779811"
157
+                m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
158
+mid:&quot;659EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
159
+surl:&quot;http://www.page.url/&quot;,imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,
160
+oh:&quot;238&quot;,tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
161
+                mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
162
+                t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
163
+                <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
164
+                style="height:144px;" width="178" height="144"/>
165
+            </a>
166
+        </div>
167
+        <div class="dg_u" style="width:178px;height:144px;left:17px;top:0px">
168
+            <a href="#" ihk="HN.608003696942779811"
169
+                m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
170
+mid:&quot;659EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
171
+surl:&quot;http://www.page.url/&quot;,imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,
172
+oh:&quot;238&quot;,tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
173
+                mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
174
+                t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
175
+                <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
176
+                style="height:144px;" width="178" height="144"/>
177
+            </a>
178
+        </div>
179
+        <div class="dg_u" style="width:178px;height:144px;left:17px;top:0px">
180
+            <a href="#" ihk="HN.608003696942779811"
181
+                m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
182
+mid:&quot;659EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
183
+surl:&quot;http://www.page.url/&quot;,imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,
184
+oh:&quot;238&quot;,tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
185
+                mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
186
+                t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
187
+                <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
188
+                style="height:144px;" width="178" height="144"/>
189
+            </a>
190
+        </div>
191
+        <div class="dg_u" style="width:178px;height:144px;left:17px;top:0px">
192
+            <a href="#" ihk="HN.608003696942779811"
193
+                m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
194
+mid:&quot;659EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
195
+surl:&quot;http://www.page.url/&quot;,imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,
196
+oh:&quot;238&quot;,tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
197
+                mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
198
+                t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
199
+                <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
200
+                style="height:144px;" width="178" height="144"/>
201
+            </a>
202
+        </div>
203
+        <div class="dg_u" style="width:178px;height:144px;left:17px;top:0px">
204
+            <a href="#" ihk="HN.608003696942779811"
205
+                m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
206
+mid:&quot;659EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
207
+surl:&quot;http://www.page.url/&quot;,imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,
208
+oh:&quot;238&quot;,tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
209
+                mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
210
+                t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
211
+                <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
212
+                style="height:144px;" width="178" height="144"/>
213
+            </a>
214
+        </div>
215
+        <div class="dg_u" style="width:178px;height:144px;left:17px;top:0px">
216
+            <a href="#" ihk="HN.608003696942779811"
217
+                m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
218
+mid:&quot;659EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
219
+surl:&quot;http://www.page.url/&quot;,imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,
220
+oh:&quot;238&quot;,tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
221
+                mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
222
+                t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
223
+                <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
224
+                style="height:144px;" width="178" height="144"/>
225
+            </a>
226
+        </div>
227
+        <div class="dg_u" style="width:178px;height:144px;left:17px;top:0px">
228
+            <a href="#" ihk="HN.608003696942779811"
229
+                m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
230
+mid:&quot;659EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
231
+surl:&quot;http://www.page.url/&quot;,imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,
232
+oh:&quot;238&quot;,tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
233
+                mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
234
+                t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
235
+                <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
236
+                style="height:144px;" width="178" height="144"/>
237
+            </a>
238
+        </div>
239
+        <div class="dg_u" style="width:178px;height:144px;left:17px;top:0px">
240
+            <a href="#" ihk="HN.608003696942779811"
241
+                m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
242
+mid:&quot;659EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
243
+surl:&quot;http://www.page.url/&quot;,imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,
244
+oh:&quot;238&quot;,tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
245
+                mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
246
+                t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
247
+                <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
248
+                style="height:144px;" width="178" height="144"/>
249
+            </a>
250
+        </div>
251
+        <div class="dg_u" style="width:178px;height:144px;left:17px;top:0px">
252
+            <a href="#" ihk="HN.608003696942779811"
253
+                m="{ns:&quot;images&quot;,k:&quot;5045&quot;,
254
+mid:&quot;659EB92C317974F34517A1CCAEBEF76A578E08DEE&quot;,
255
+surl:&quot;http://www.page.url/&quot;,imgurl:&quot;http://test.url/Test%20Query.jpg&quot;,
256
+oh:&quot;238&quot;,tft:&quot;0&quot;,oi:&quot;http://www.image.url/Images/Test%20Query.jpg&quot;}"
257
+                mid="59EB92C317974F34517A1CCAEBEF76A578E08DEE" onclick="return false;"
258
+                t1="Test Query" t2="650 x 517 · 31 kB · jpeg" t3="www.short.url" h="ID=images,5045.1">
259
+                <img src="https://tse4.mm.bing.net/th?id=HN.608003696942779811&amp;o=4&amp;pid=1.7"
260
+                style="height:144px;" width="178" height="144"/>
261
+            </a>
262
+        </div>
263
+        """
264
+        html = html.replace('\r\n', '').replace('\n', '').replace('\r', '')
265
+        response = mock.Mock(content=html)
266
+        results = bing_images.response(response)
267
+        self.assertEqual(type(results), list)
268
+        self.assertEqual(len(results), 10)

+ 236
- 0
searx/tests/engines/test_bing_news.py View File

@@ -0,0 +1,236 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import bing_news
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestBingNewsEngine(SearxTestCase):
8
+
9
+    def test_request(self):
10
+        query = 'test_query'
11
+        dicto = defaultdict(dict)
12
+        dicto['pageno'] = 1
13
+        dicto['language'] = 'fr_FR'
14
+        params = bing_news.request(query, dicto)
15
+        self.assertIn('url', params)
16
+        self.assertIn(query, params['url'])
17
+        self.assertIn('bing.com', params['url'])
18
+        self.assertIn('fr', params['url'])
19
+        self.assertIn('_FP', params['cookies'])
20
+        self.assertIn('en', params['cookies']['_FP'])
21
+
22
+        dicto['language'] = 'all'
23
+        params = bing_news.request(query, dicto)
24
+        self.assertIn('en', params['url'])
25
+        self.assertIn('_FP', params['cookies'])
26
+        self.assertIn('en', params['cookies']['_FP'])
27
+
28
+    def test_response(self):
29
+        self.assertRaises(AttributeError, bing_news.response, None)
30
+        self.assertRaises(AttributeError, bing_news.response, [])
31
+        self.assertRaises(AttributeError, bing_news.response, '')
32
+        self.assertRaises(AttributeError, bing_news.response, '[]')
33
+
34
+        response = mock.Mock(content='<html></html>')
35
+        self.assertEqual(bing_news.response(response), [])
36
+
37
+        response = mock.Mock(content='<html></html>')
38
+        self.assertEqual(bing_news.response(response), [])
39
+
40
+        html = """
41
+        <div class="sn_r">
42
+            <div class="newstitle">
43
+                <a href="http://url.of.article/" target="_blank" h="ID=news,5022.1">
44
+                    Title
45
+                </a>
46
+            </div>
47
+            <div class="sn_img">
48
+                <a href="http://url.of.article2/" target="_blank" h="ID=news,5024.1">
49
+                    <img class="rms_img" height="80" id="emb1" src="/image.src" title="Title" width="80" />
50
+                </a>
51
+            </div>
52
+            <div class="sn_txt">
53
+                <div class="sn_oi">
54
+                    <span class="sn_snip">Article Content</span>
55
+                    <span class="sn_ST">
56
+                        <cite class="sn_src">metronews.fr</cite>
57
+                        &nbsp;&#0183;&#32;
58
+                        <span class="sn_tm">44 minutes ago</span>
59
+                    </span>
60
+                </div>
61
+            </div>
62
+        </div>
63
+        """
64
+        response = mock.Mock(content=html)
65
+        results = bing_news.response(response)
66
+        self.assertEqual(type(results), list)
67
+        self.assertEqual(len(results), 1)
68
+        self.assertEqual(results[0]['title'], 'Title')
69
+        self.assertEqual(results[0]['url'], 'http://url.of.article/')
70
+        self.assertEqual(results[0]['content'], 'Article Content')
71
+
72
+        html = """
73
+        <div class="sn_r">
74
+            <div class="newstitle">
75
+                <a href="http://url.of.article/" target="_blank" h="ID=news,5022.1">
76
+                    Title
77
+                </a>
78
+            </div>
79
+            <div class="sn_img">
80
+                <a href="http://url.of.article2/" target="_blank" h="ID=news,5024.1">
81
+                    <img class="rms_img" height="80" id="emb1" src="/image.src" title="Title" width="80" />
82
+                </a>
83
+            </div>
84
+            <div class="sn_txt">
85
+                <div class="sn_oi">
86
+                    <span class="sn_snip">Article Content</span>
87
+                    <span class="sn_ST">
88
+                        <cite class="sn_src">metronews.fr</cite>
89
+                        &nbsp;&#0183;&#32;
90
+                        <span class="sn_tm">44 minutes ago</span>
91
+                    </span>
92
+                </div>
93
+            </div>
94
+        </div>
95
+        <div class="sn_r">
96
+            <div class="newstitle">
97
+                <a href="http://url.of.article/" target="_blank" h="ID=news,5022.1">
98
+                    Title
99
+                </a>
100
+            </div>
101
+            <div class="sn_img">
102
+                <a href="http://url.of.article2/" target="_blank" h="ID=news,5024.1">
103
+                    <img class="rms_img" height="80" id="emb1" src="/image.src" title="Title" width="80" />
104
+                </a>
105
+            </div>
106
+            <div class="sn_txt">
107
+                <div class="sn_oi">
108
+                    <span class="sn_snip">Article Content</span>
109
+                    <span class="sn_ST">
110
+                        <cite class="sn_src">metronews.fr</cite>
111
+                        &nbsp;&#0183;&#32;
112
+                        <span class="sn_tm">3 hours, 44 minutes ago</span>
113
+                    </span>
114
+                </div>
115
+            </div>
116
+        </div>
117
+        <div class="sn_r">
118
+            <div class="newstitle">
119
+                <a href="http://url.of.article/" target="_blank" h="ID=news,5022.1">
120
+                    Title
121
+                </a>
122
+            </div>
123
+            <div class="sn_img">
124
+                <a href="http://url.of.article2/" target="_blank" h="ID=news,5024.1">
125
+                    <img class="rms_img" height="80" id="emb1" src="/image.src" title="Title" width="80" />
126
+                </a>
127
+            </div>
128
+            <div class="sn_txt">
129
+                <div class="sn_oi">
130
+                    <span class="sn_snip">Article Content</span>
131
+                    <span class="sn_ST">
132
+                        <cite class="sn_src">metronews.fr</cite>
133
+                        &nbsp;&#0183;&#32;
134
+                        <span class="sn_tm">44 hours ago</span>
135
+                    </span>
136
+                </div>
137
+            </div>
138
+        </div>
139
+        <div class="sn_r">
140
+            <div class="newstitle">
141
+                <a href="http://url.of.article/" target="_blank" h="ID=news,5022.1">
142
+                    Title
143
+                </a>
144
+            </div>
145
+            <div class="sn_img">
146
+                <a href="http://url.of.article2/" target="_blank" h="ID=news,5024.1">
147
+                    <img class="rms_img" height="80" id="emb1" src="/image.src" title="Title" width="80" />
148
+                </a>
149
+            </div>
150
+            <div class="sn_txt">
151
+                <div class="sn_oi">
152
+                    <span class="sn_snip">Article Content</span>
153
+                    <span class="sn_ST">
154
+                        <cite class="sn_src">metronews.fr</cite>
155
+                        &nbsp;&#0183;&#32;
156
+                        <span class="sn_tm">2 days ago</span>
157
+                    </span>
158
+                </div>
159
+            </div>
160
+        </div>
161
+        <div class="sn_r">
162
+            <div class="newstitle">
163
+                <a href="http://url.of.article/" target="_blank" h="ID=news,5022.1">
164
+                    Title
165
+                </a>
166
+            </div>
167
+            <div class="sn_img">
168
+                <a href="http://url.of.article2/" target="_blank" h="ID=news,5024.1">
169
+                    <img class="rms_img" height="80" id="emb1" src="/image.src" title="Title" width="80" />
170
+                </a>
171
+            </div>
172
+            <div class="sn_txt">
173
+                <div class="sn_oi">
174
+                    <span class="sn_snip">Article Content</span>
175
+                    <span class="sn_ST">
176
+                        <cite class="sn_src">metronews.fr</cite>
177
+                        &nbsp;&#0183;&#32;
178
+                        <span class="sn_tm">27/01/2015</span>
179
+                    </span>
180
+                </div>
181
+            </div>
182
+        </div>
183
+        <div class="sn_r">
184
+            <div class="newstitle">
185
+                <a href="http://url.of.article/" target="_blank" h="ID=news,5022.1">
186
+                    Title
187
+                </a>
188
+            </div>
189
+            <div class="sn_img">
190
+                <a href="http://url.of.article2/" target="_blank" h="ID=news,5024.1">
191
+                    <img class="rms_img" height="80" id="emb1" src="/image.src" title="Title" width="80" />
192
+                </a>
193
+            </div>
194
+            <div class="sn_txt">
195
+                <div class="sn_oi">
196
+                    <span class="sn_snip">Article Content</span>
197
+                    <span class="sn_ST">
198
+                        <cite class="sn_src">metronews.fr</cite>
199
+                        &nbsp;&#0183;&#32;
200
+                        <span class="sn_tm">Il y a 3 heures</span>
201
+                    </span>
202
+                </div>
203
+            </div>
204
+        </div>
205
+        """
206
+        response = mock.Mock(content=html)
207
+        results = bing_news.response(response)
208
+        self.assertEqual(type(results), list)
209
+        self.assertEqual(len(results), 6)
210
+
211
+        html = """
212
+        <div class="newstitle">
213
+            <a href="http://url.of.article/" target="_blank" h="ID=news,5022.1">
214
+                Title
215
+            </a>
216
+        </div>
217
+        <div class="sn_img">
218
+            <a href="http://url.of.article2/" target="_blank" h="ID=news,5024.1">
219
+                <img class="rms_img" height="80" id="emb1" src="/image.src" title="Title" width="80" />
220
+            </a>
221
+        </div>
222
+        <div class="sn_txt">
223
+            <div class="sn_oi">
224
+                <span class="sn_snip">Article Content</span>
225
+                <span class="sn_ST">
226
+                    <cite class="sn_src">metronews.fr</cite>
227
+                    &nbsp;&#0183;&#32;
228
+                    <span class="sn_tm">44 minutes ago</span>
229
+                </span>
230
+            </div>
231
+        </div>
232
+        """
233
+        response = mock.Mock(content=html)
234
+        results = bing_news.response(response)
235
+        self.assertEqual(type(results), list)
236
+        self.assertEqual(len(results), 0)

+ 384
- 0
searx/tests/engines/test_btdigg.py View File

@@ -0,0 +1,384 @@
1
+# -*- coding: utf-8 -*-
2
+from collections import defaultdict
3
+import mock
4
+from searx.engines import btdigg
5
+from searx.testing import SearxTestCase
6
+
7
+
8
+class TestBtdiggEngine(SearxTestCase):
9
+
10
+    def test_request(self):
11
+        query = 'test_query'
12
+        dicto = defaultdict(dict)
13
+        dicto['pageno'] = 0
14
+        params = btdigg.request(query, dicto)
15
+        self.assertIn('url', params)
16
+        self.assertIn(query, params['url'])
17
+        self.assertIn('btdigg.org', params['url'])
18
+
19
+    def test_response(self):
20
+        self.assertRaises(AttributeError, btdigg.response, None)
21
+        self.assertRaises(AttributeError, btdigg.response, [])
22
+        self.assertRaises(AttributeError, btdigg.response, '')
23
+        self.assertRaises(AttributeError, btdigg.response, '[]')
24
+
25
+        response = mock.Mock(text='<html></html>')
26
+        self.assertEqual(btdigg.response(response), [])
27
+
28
+        html = """
29
+        <div id="search_res">
30
+            <table>
31
+                <tr>
32
+                    <td class="idx">1</td>
33
+                    <td>
34
+                        <table class="torrent_name_tbl">
35
+                            <tr>
36
+                                <td class="torrent_name">
37
+                                    <a href="/url">Should be the title</a>
38
+                                </td>
39
+                            </tr>
40
+                        </table>
41
+                        <table class="torrent_name_tbl">
42
+                            <tr>
43
+                                <td class="ttth">
44
+                                    <a onclick="fclck(this.href)" href="magnet:?xt=urn:btih:magnet&amp;dn=Test"
45
+                                    title="Télécharger des liens Magnet">[magnet]</a>
46
+                                </td>
47
+                                <td class="ttth">
48
+                                    <a href="https://btcloud.io/manager?cmd=add&amp;info_hash=hash"
49
+                                    target="_blank" title="Ajouter à BTCloud">[cloud]</a>
50
+                                </td>
51
+                                <td>
52
+                                    <span class="attr_name">Taille:</span>
53
+                                    <span class="attr_val">8 B</span>
54
+                                </td>
55
+                                <td>
56
+                                    <span class="attr_name">Fichiers:</span>
57
+                                    <span class="attr_val">710</span>
58
+                                </td>
59
+                                <td>
60
+                                    <span class="attr_name">Téléchargements:</span>
61
+                                    <span class="attr_val">5</span>
62
+                                </td>
63
+                                <td>
64
+                                    <span class="attr_name">Temps:</span>
65
+                                    <span class="attr_val">417.8&nbsp;jours</span>
66
+                                </td>
67
+                                <td>
68
+                                    <span class="attr_name">Dernière&nbsp;mise&nbsp;à&nbsp;jour:</span>
69
+                                    <span class="attr_val">5.3&nbsp;jours</span>
70
+                                </td>
71
+                                <td>
72
+                                    <span class="attr_name">Faux:</span>
73
+                                    <span class="attr_val">Aucun</span>
74
+                                </td>
75
+                            </tr>
76
+                        </table>
77
+                        <pre class="snippet">
78
+                            Content
79
+                        </pre>
80
+                    </td>
81
+                </tr>
82
+            </table>
83
+        </div>
84
+        """
85
+        response = mock.Mock(text=html)
86
+        results = btdigg.response(response)
87
+        self.assertEqual(type(results), list)
88
+        self.assertEqual(len(results), 1)
89
+        self.assertEqual(results[0]['title'], 'Should be the title')
90
+        self.assertEqual(results[0]['url'], 'https://btdigg.org/url')
91
+        self.assertEqual(results[0]['content'], 'Content')
92
+        self.assertEqual(results[0]['seed'], 5)
93
+        self.assertEqual(results[0]['leech'], 0)
94
+        self.assertEqual(results[0]['filesize'], 8)
95
+        self.assertEqual(results[0]['files'], 710)
96
+        self.assertEqual(results[0]['magnetlink'], 'magnet:?xt=urn:btih:magnet&dn=Test')
97
+
98
+        html = """
99
+        <div id="search_res">
100
+            <table>
101
+            </table>
102
+        </div>
103
+        """
104
+        response = mock.Mock(text=html)
105
+        results = btdigg.response(response)
106
+        self.assertEqual(type(results), list)
107
+        self.assertEqual(len(results), 0)
108
+
109
+        html = """
110
+        <div id="search_res">
111
+            <table>
112
+                <tr>
113
+                    <td class="idx">1</td>
114
+                    <td>
115
+                        <table class="torrent_name_tbl">
116
+                            <tr>
117
+                                <td class="torrent_name">
118
+                                    <a href="/url">Should be the title</a>
119
+                                </td>
120
+                            </tr>
121
+                        </table>
122
+                        <table class="torrent_name_tbl">
123
+                            <tr>
124
+                                <td class="ttth">
125
+                                    <a onclick="fclck(this.href)" href="magnet:?xt=urn:btih:magnet&amp;dn=Test"
126
+                                    title="Télécharger des liens Magnet">[magnet]</a>
127
+                                </td>
128
+                                <td class="ttth">
129
+                                    <a href="https://btcloud.io/manager?cmd=add&amp;info_hash=hash"
130
+                                    target="_blank" title="Ajouter à BTCloud">[cloud]</a>
131
+                                </td>
132
+                                <td>
133
+                                    <span class="attr_name">Taille:</span>
134
+                                    <span class="attr_val">1 KB</span>
135
+                                </td>
136
+                                <td>
137
+                                    <span class="attr_name">Fichiers:</span>
138
+                                    <span class="attr_val">710</span>
139
+                                </td>
140
+                                <td>
141
+                                    <span class="attr_name">Téléchargements:</span>
142
+                                    <span class="attr_val">5</span>
143
+                                </td>
144
+                                <td>
145
+                                    <span class="attr_name">Temps:</span>
146
+                                    <span class="attr_val">417.8&nbsp;jours</span>
147
+                                </td>
148
+                                <td>
149
+                                    <span class="attr_name">Dernière&nbsp;mise&nbsp;à&nbsp;jour:</span>
150
+                                    <span class="attr_val">5.3&nbsp;jours</span>
151
+                                </td>
152
+                                <td>
153
+                                    <span class="attr_name">Faux:</span>
154
+                                    <span class="attr_val">Aucun</span>
155
+                                </td>
156
+                            </tr>
157
+                        </table>
158
+                        <pre class="snippet">
159
+                            Content
160
+                        </pre>
161
+                    </td>
162
+                </tr>
163
+                <tr>
164
+                    <td class="idx">1</td>
165
+                    <td>
166
+                        <table class="torrent_name_tbl">
167
+                            <tr>
168
+                                <td class="torrent_name">
169
+                                    <a href="/url">Should be the title</a>
170
+                                </td>
171
+                            </tr>
172
+                        </table>
173
+                        <table class="torrent_name_tbl">
174
+                            <tr>
175
+                                <td class="ttth">
176
+                                    <a onclick="fclck(this.href)" href="magnet:?xt=urn:btih:magnet&amp;dn=Test"
177
+                                    title="Télécharger des liens Magnet">[magnet]</a>
178
+                                </td>
179
+                                <td class="ttth">
180
+                                    <a href="https://btcloud.io/manager?cmd=add&amp;info_hash=hash"
181
+                                    target="_blank" title="Ajouter à BTCloud">[cloud]</a>
182
+                                </td>
183
+                                <td>
184
+                                    <span class="attr_name">Taille:</span>
185
+                                    <span class="attr_val">1 MB</span>
186
+                                </td>
187
+                                <td>
188
+                                    <span class="attr_name">Fichiers:</span>
189
+                                    <span class="attr_val">a</span>
190
+                                </td>
191
+                                <td>
192
+                                    <span class="attr_name">Téléchargements:</span>
193
+                                    <span class="attr_val">4</span>
194
+                                </td>
195
+                                <td>
196
+                                    <span class="attr_name">Temps:</span>
197
+                                    <span class="attr_val">417.8&nbsp;jours</span>
198
+                                </td>
199
+                                <td>
200
+                                    <span class="attr_name">Dernière&nbsp;mise&nbsp;à&nbsp;jour:</span>
201
+                                    <span class="attr_val">5.3&nbsp;jours</span>
202
+                                </td>
203
+                                <td>
204
+                                    <span class="attr_name">Faux:</span>
205
+                                    <span class="attr_val">Aucun</span>
206
+                                </td>
207
+                            </tr>
208
+                        </table>
209
+                        <pre class="snippet">
210
+                            Content
211
+                        </pre>
212
+                    </td>
213
+                </tr>
214
+                <tr>
215
+                    <td class="idx">1</td>
216
+                    <td>
217
+                        <table class="torrent_name_tbl">
218
+                            <tr>
219
+                                <td class="torrent_name">
220
+                                    <a href="/url">Should be the title</a>
221
+                                </td>
222
+                            </tr>
223
+                        </table>
224
+                        <table class="torrent_name_tbl">
225
+                            <tr>
226
+                                <td class="ttth">
227
+                                    <a onclick="fclck(this.href)" href="magnet:?xt=urn:btih:magnet&amp;dn=Test"
228
+                                    title="Télécharger des liens Magnet">[magnet]</a>
229
+                                </td>
230
+                                <td class="ttth">
231
+                                    <a href="https://btcloud.io/manager?cmd=add&amp;info_hash=hash"
232
+                                    target="_blank" title="Ajouter à BTCloud">[cloud]</a>
233
+                                </td>
234
+                                <td>
235
+                                    <span class="attr_name">Taille:</span>
236
+                                    <span class="attr_val">1 GB</span>
237
+                                </td>
238
+                                <td>
239
+                                    <span class="attr_name">Fichiers:</span>
240
+                                    <span class="attr_val">710</span>
241
+                                </td>
242
+                                <td>
243
+                                    <span class="attr_name">Téléchargements:</span>
244
+                                    <span class="attr_val">3</span>
245
+                                </td>
246
+                                <td>
247
+                                    <span class="attr_name">Temps:</span>
248
+                                    <span class="attr_val">417.8&nbsp;jours</span>
249
+                                </td>
250
+                                <td>
251
+                                    <span class="attr_name">Dernière&nbsp;mise&nbsp;à&nbsp;jour:</span>
252
+                                    <span class="attr_val">5.3&nbsp;jours</span>
253
+                                </td>
254
+                                <td>
255
+                                    <span class="attr_name">Faux:</span>
256
+                                    <span class="attr_val">Aucun</span>
257
+                                </td>
258
+                            </tr>
259
+                        </table>
260
+                        <pre class="snippet">
261
+                            Content
262
+                        </pre>
263
+                    </td>
264
+                </tr>
265
+                <tr>
266
+                    <td class="idx">1</td>
267
+                    <td>
268
+                        <table class="torrent_name_tbl">
269
+                            <tr>
270
+                                <td class="torrent_name">
271
+                                    <a href="/url">Should be the title</a>
272
+                                </td>
273
+                            </tr>
274
+                        </table>
275
+                        <table class="torrent_name_tbl">
276
+                            <tr>
277
+                                <td class="ttth">
278
+                                    <a onclick="fclck(this.href)" href="magnet:?xt=urn:btih:magnet&amp;dn=Test"
279
+                                    title="Télécharger des liens Magnet">[magnet]</a>
280
+                                </td>
281
+                                <td class="ttth">
282
+                                    <a href="https://btcloud.io/manager?cmd=add&amp;info_hash=hash"
283
+                                    target="_blank" title="Ajouter à BTCloud">[cloud]</a>
284
+                                </td>
285
+                                <td>
286
+                                    <span class="attr_name">Taille:</span>
287
+                                    <span class="attr_val">1 TB</span>
288
+                                </td>
289
+                                <td>
290
+                                    <span class="attr_name">Fichiers:</span>
291
+                                    <span class="attr_val">710</span>
292
+                                </td>
293
+                                <td>
294
+                                    <span class="attr_name">Téléchargements:</span>
295
+                                    <span class="attr_val">2</span>
296
+                                </td>
297
+                                <td>
298
+                                    <span class="attr_name">Temps:</span>
299
+                                    <span class="attr_val">417.8&nbsp;jours</span>
300
+                                </td>
301
+                                <td>
302
+                                    <span class="attr_name">Dernière&nbsp;mise&nbsp;à&nbsp;jour:</span>
303
+                                    <span class="attr_val">5.3&nbsp;jours</span>
304
+                                </td>
305
+                                <td>
306
+                                    <span class="attr_name">Faux:</span>
307
+                                    <span class="attr_val">Aucun</span>
308
+                                </td>
309
+                            </tr>
310
+                        </table>
311
+                        <pre class="snippet">
312
+                            Content
313
+                        </pre>
314
+                    </td>
315
+                </tr>
316
+                <tr>
317
+                    <td class="idx">1</td>
318
+                    <td>
319
+                        <table class="torrent_name_tbl">
320
+                            <tr>
321
+                                <td class="torrent_name">
322
+                                    <a href="/url">Should be the title</a>
323
+                                </td>
324
+                            </tr>
325
+                        </table>
326
+                        <table class="torrent_name_tbl">
327
+                            <tr>
328
+                                <td class="ttth">
329
+                                    <a onclick="fclck(this.href)" href="magnet:?xt=urn:btih:magnet&amp;dn=Test"
330
+                                    title="Télécharger des liens Magnet">[magnet]</a>
331
+                                </td>
332
+                                <td class="ttth">
333
+                                    <a href="https://btcloud.io/manager?cmd=add&amp;info_hash=hash"
334
+                                    target="_blank" title="Ajouter à BTCloud">[cloud]</a>
335
+                                </td>
336
+                                <td>
337
+                                    <span class="attr_name">Taille:</span>
338
+                                    <span class="attr_val">a TB</span>
339
+                                </td>
340
+                                <td>
341
+                                    <span class="attr_name">Fichiers:</span>
342
+                                    <span class="attr_val">710</span>
343
+                                </td>
344
+                                <td>
345
+                                    <span class="attr_name">Téléchargements:</span>
346
+                                    <span class="attr_val">z</span>
347
+                                </td>
348
+                                <td>
349
+                                    <span class="attr_name">Temps:</span>
350
+                                    <span class="attr_val">417.8&nbsp;jours</span>
351
+                                </td>
352
+                                <td>
353
+                                    <span class="attr_name">Dernière&nbsp;mise&nbsp;à&nbsp;jour:</span>
354
+                                    <span class="attr_val">5.3&nbsp;jours</span>
355
+                                </td>
356
+                                <td>
357
+                                    <span class="attr_name">Faux:</span>
358
+                                    <span class="attr_val">Aucun</span>
359
+                                </td>
360
+                            </tr>
361
+                        </table>
362
+                        <pre class="snippet">
363
+                            Content
364
+                        </pre>
365
+                    </td>
366
+                </tr>
367
+            </table>
368
+        </div>
369
+        """
370
+        response = mock.Mock(text=html)
371
+        results = btdigg.response(response)
372
+        self.assertEqual(type(results), list)
373
+        self.assertEqual(len(results), 5)
374
+        self.assertEqual(results[0]['title'], 'Should be the title')
375
+        self.assertEqual(results[0]['url'], 'https://btdigg.org/url')
376
+        self.assertEqual(results[0]['content'], 'Content')
377
+        self.assertEqual(results[0]['seed'], 5)
378
+        self.assertEqual(results[0]['leech'], 0)
379
+        self.assertEqual(results[0]['files'], 710)
380
+        self.assertEqual(results[0]['magnetlink'], 'magnet:?xt=urn:btih:magnet&dn=Test')
381
+        self.assertEqual(results[0]['filesize'], 1024)
382
+        self.assertEqual(results[1]['filesize'], 1048576)
383
+        self.assertEqual(results[2]['filesize'], 1073741824)
384
+        self.assertEqual(results[3]['filesize'], 1099511627776)

+ 74
- 0
searx/tests/engines/test_dailymotion.py View File

@@ -0,0 +1,74 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import dailymotion
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestDailymotionEngine(SearxTestCase):
8
+
9
+    def test_request(self):
10
+        query = 'test_query'
11
+        dicto = defaultdict(dict)
12
+        dicto['pageno'] = 0
13
+        dicto['language'] = 'fr_FR'
14
+        params = dailymotion.request(query, dicto)
15
+        self.assertTrue('url' in params)
16
+        self.assertTrue(query in params['url'])
17
+        self.assertTrue('dailymotion.com' in params['url'])
18
+        self.assertTrue('fr' in params['url'])
19
+
20
+        dicto['language'] = 'all'
21
+        params = dailymotion.request(query, dicto)
22
+        self.assertTrue('en' in params['url'])
23
+
24
+    def test_response(self):
25
+        self.assertRaises(AttributeError, dailymotion.response, None)
26
+        self.assertRaises(AttributeError, dailymotion.response, [])
27
+        self.assertRaises(AttributeError, dailymotion.response, '')
28
+        self.assertRaises(AttributeError, dailymotion.response, '[]')
29
+
30
+        response = mock.Mock(text='{}')
31
+        self.assertEqual(dailymotion.response(response), [])
32
+
33
+        response = mock.Mock(text='{"data": []}')
34
+        self.assertEqual(dailymotion.response(response), [])
35
+
36
+        json = """
37
+        {
38
+        "page": 1,
39
+        "limit": 5,
40
+        "explicit": false,
41
+        "total": 289487,
42
+        "has_more": true,
43
+        "list": [
44
+            {
45
+            "created_time": 1422173451,
46
+            "title": "Title",
47
+            "description": "Description",
48
+            "duration": 81,
49
+            "url": "http://www.url",
50
+            "thumbnail_360_url": "http://thumbnail",
51
+            "id": "x2fit7q"
52
+            }
53
+        ]
54
+        }
55
+        """
56
+        response = mock.Mock(text=json)
57
+        results = dailymotion.response(response)
58
+        self.assertEqual(type(results), list)
59
+        self.assertEqual(len(results), 1)
60
+        self.assertEqual(results[0]['title'], 'Title')
61
+        self.assertEqual(results[0]['url'], 'http://www.url')
62
+        self.assertEqual(results[0]['content'], 'Description')
63
+        self.assertIn('x2fit7q', results[0]['embedded'])
64
+
65
+        json = """
66
+        {"toto":[
67
+            {"id":200,"name":"Artist Name",
68
+            "link":"http:\/\/www.dailymotion.com\/artist\/1217","type":"artist"}
69
+        ]}
70
+        """
71
+        response = mock.Mock(text=json)
72
+        results = dailymotion.response(response)
73
+        self.assertEqual(type(results), list)
74
+        self.assertEqual(len(results), 0)

+ 57
- 0
searx/tests/engines/test_deezer.py View File

@@ -0,0 +1,57 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import deezer
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestDeezerEngine(SearxTestCase):
8
+
9
+    def test_request(self):
10
+        query = 'test_query'
11
+        dicto = defaultdict(dict)
12
+        dicto['pageno'] = 0
13
+        params = deezer.request(query, dicto)
14
+        self.assertTrue('url' in params)
15
+        self.assertTrue(query in params['url'])
16
+        self.assertTrue('deezer.com' in params['url'])
17
+
18
+    def test_response(self):
19
+        self.assertRaises(AttributeError, deezer.response, None)
20
+        self.assertRaises(AttributeError, deezer.response, [])
21
+        self.assertRaises(AttributeError, deezer.response, '')
22
+        self.assertRaises(AttributeError, deezer.response, '[]')
23
+
24
+        response = mock.Mock(text='{}')
25
+        self.assertEqual(deezer.response(response), [])
26
+
27
+        response = mock.Mock(text='{"data": []}')
28
+        self.assertEqual(deezer.response(response), [])
29
+
30
+        json = """
31
+        {"data":[
32
+            {"id":100, "title":"Title of track",
33
+            "link":"http:\/\/www.deezer.com\/track\/1094042","duration":232,
34
+            "artist":{"id":200,"name":"Artist Name",
35
+                "link":"http:\/\/www.deezer.com\/artist\/1217","type":"artist"},
36
+            "album":{"id":118106,"title":"Album Title","type":"album"},"type":"track"}
37
+        ]}
38
+        """
39
+        response = mock.Mock(text=json)
40
+        results = deezer.response(response)
41
+        self.assertEqual(type(results), list)
42
+        self.assertEqual(len(results), 1)
43
+        self.assertEqual(results[0]['title'], 'Title of track')
44
+        self.assertEqual(results[0]['url'], 'http://www.deezer.com/track/1094042')
45
+        self.assertEqual(results[0]['content'], 'Artist Name &bull; Album Title &bull; Title of track')
46
+        self.assertTrue('100' in results[0]['embedded'])
47
+
48
+        json = """
49
+        {"data":[
50
+            {"id":200,"name":"Artist Name",
51
+            "link":"http:\/\/www.deezer.com\/artist\/1217","type":"artist"}
52
+        ]}
53
+        """
54
+        response = mock.Mock(text=json)
55
+        results = deezer.response(response)
56
+        self.assertEqual(type(results), list)
57
+        self.assertEqual(len(results), 0)

+ 118
- 0
searx/tests/engines/test_deviantart.py View File

@@ -0,0 +1,118 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import deviantart
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestDeviantartEngine(SearxTestCase):
8
+
9
+    def test_request(self):
10
+        query = 'test_query'
11
+        dicto = defaultdict(dict)
12
+        dicto['pageno'] = 0
13
+        params = deviantart.request(query, dicto)
14
+        self.assertTrue('url' in params)
15
+        self.assertTrue(query in params['url'])
16
+        self.assertTrue('deviantart.com' in params['url'])
17
+
18
+    def test_response(self):
19
+        self.assertRaises(AttributeError, deviantart.response, None)
20
+        self.assertRaises(AttributeError, deviantart.response, [])
21
+        self.assertRaises(AttributeError, deviantart.response, '')
22
+        self.assertRaises(AttributeError, deviantart.response, '[]')
23
+
24
+        response = mock.Mock(text='<html></html>')
25
+        self.assertEqual(deviantart.response(response), [])
26
+
27
+        response = mock.Mock(status_code=302)
28
+        self.assertEqual(deviantart.response(response), [])
29
+
30
+        html = """
31
+        <div class="tt-a tt-fh tt-boxed" collect_rid="1:149167425"
32
+            usericon="http://a.deviantart.net/avatars/t/e/test-0.gif" userid="233301"
33
+            username="test-0" symbol="~" category="digitalart/animation">
34
+            <span class="tt-w" style="width: auto; max-width: 277px;">
35
+                <span class="tt-fh-tc" style="width: 202px;">
36
+                    <span class="tt-bb" style="width: 202px;">
37
+                    </span>
38
+                    <span class="shadow">
39
+                        <a class="thumb" href="http://url.of.result/2nd.part.of.url"
40
+                            title="Behoimi BE Animation Test by test-0, Jan 4,
41
+                            2010 in Digital Art &gt; Animation"> <i></i>
42
+                            <img width="200" height="200" alt="Test"
43
+                                src="http://url.of.thumbnail" data-src="http://th08.deviantart.net/test.jpg">
44
+                        </a>
45
+                    </span>
46
+                    <!-- ^TTT -->
47
+                </span>
48
+                <span class="details">
49
+                    <a href="http://test-0.deviantart.com/art/Test" class="t"
50
+                        title="Behoimi BE Animation Test by test-0, Jan 4, 2010">
51
+                        <span class="tt-fh-oe">Title of image</span> </a>
52
+                    <small>
53
+                    <span class="category">
54
+                        <span class="age">
55
+                            5 years ago
56
+                        </span>
57
+                        in <a title="Behoimi BE Animation Test by test-0, Jan 4, 2010"
58
+                            href="http://www.deviantart.com/browse/all/digitalart/animation/">Animation</a>
59
+                    </span>
60
+                    <div class="commentcount">
61
+                        <a href="http://test-0.deviantart.com/art/Test#comments">
62
+                        <span class="iconcommentsstats"></span>9 Comments</a>
63
+                    </div>
64
+                    <a class="mlt-link" href="http://www.deviantart.com/morelikethis/149167425">
65
+                    <span class="mlt-icon"></span> <span class="mlt-text">More Like This</span> </a>
66
+                </span>
67
+                </small> <!-- TTT$ -->
68
+            </span>
69
+        </div>
70
+        """
71
+        response = mock.Mock(text=html)
72
+        results = deviantart.response(response)
73
+        self.assertEqual(type(results), list)
74
+        self.assertEqual(len(results), 1)
75
+        self.assertEqual(results[0]['title'], 'Title of image')
76
+        self.assertEqual(results[0]['url'], 'http://url.of.result/2nd.part.of.url')
77
+        self.assertNotIn('content', results[0])
78
+        self.assertEqual(results[0]['thumbnail_src'], 'http://url.of.thumbnail')
79
+
80
+        html = """
81
+        <span class="tt-fh-tc" style="width: 202px;">
82
+            <span class="tt-bb" style="width: 202px;">
83
+            </span>
84
+            <span class="shadow">
85
+                <a class="thumb" href="http://url.of.result/2nd.part.of.url"
86
+                    title="Behoimi BE Animation Test by test-0, Jan 4,
87
+                    2010 in Digital Art &gt; Animation"> <i></i>
88
+                    <img width="200" height="200" alt="Test"
89
+                        src="http://url.of.thumbnail" data-src="http://th08.deviantart.net/test.jpg">
90
+                </a>
91
+            </span>
92
+            <!-- ^TTT -->
93
+        </span>
94
+        <span class="details">
95
+            <a href="http://test-0.deviantart.com/art/Test" class="t"
96
+                title="Behoimi BE Animation Test by test-0, Jan 4, 2010">
97
+                <span class="tt-fh-oe">Title of image</span> </a>
98
+            <small>
99
+            <span class="category">
100
+                <span class="age">
101
+                    5 years ago
102
+                </span>
103
+                in <a title="Behoimi BE Animation Test by test-0, Jan 4, 2010"
104
+                    href="http://www.deviantart.com/browse/all/digitalart/animation/">Animation</a>
105
+            </span>
106
+            <div class="commentcount">
107
+                <a href="http://test-0.deviantart.com/art/Test#comments">
108
+                <span class="iconcommentsstats"></span>9 Comments</a>
109
+            </div>
110
+            <a class="mlt-link" href="http://www.deviantart.com/morelikethis/149167425">
111
+            <span class="mlt-icon"></span> <span class="mlt-text">More Like This</span> </a>
112
+        </span>
113
+        </small> <!-- TTT$ -->
114
+        """
115
+        response = mock.Mock(text=html)
116
+        results = deviantart.response(response)
117
+        self.assertEqual(type(results), list)
118
+        self.assertEqual(len(results), 0)

+ 101
- 0
searx/tests/engines/test_digg.py View File

@@ -0,0 +1,101 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import digg
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestDiggEngine(SearxTestCase):
8
+
9
+    def test_request(self):
10
+        query = 'test_query'
11
+        dicto = defaultdict(dict)
12
+        dicto['pageno'] = 1
13
+        params = digg.request(query, dicto)
14
+        self.assertIn('url', params)
15
+        self.assertIn(query, params['url'])
16
+        self.assertIn('digg.com', params['url'])
17
+
18
+    def test_response(self):
19
+        self.assertRaises(AttributeError, digg.response, None)
20
+        self.assertRaises(AttributeError, digg.response, [])
21
+        self.assertRaises(AttributeError, digg.response, '')
22
+        self.assertRaises(AttributeError, digg.response, '[]')
23
+
24
+        response = mock.Mock(text='{}')
25
+        self.assertEqual(digg.response(response), [])
26
+
27
+        response = mock.Mock(text='{"data": []}')
28
+        self.assertEqual(digg.response(response), [])
29
+
30
+        json = """
31
+        {
32
+        "status": "ok",
33
+        "num": 10,
34
+        "next_position": 20,
35
+        "html": "<article itemscope itemtype=\\"http://schema.org/Article\\"
36
+        class=\\"story-container digg-story-el hentry entry story-1sRANah col-1\\"
37
+        data-content-id=\\"1sRANah\\" data-contenturl=\\"http://url.of.link\\"
38
+        data-position=\\"0\\" data-diggs=\\"24\\" data-tweets=\\"69\\"
39
+        data-digg-score=\\"1190\\"> <div class=\\"story-image story-image-thumb\\">
40
+        <a data-position=\\"0\\" data-content-id=\\"1sRANah\\"
41
+        class=\\"story-link\\" href=\\"http://www.thedailybeast.com/\\"
42
+        target=\\"_blank\\"><img class=\\"story-image-img\\"
43
+        src=\\"http://url.of.image.jpeg\\" width=\\"312\\" height=\\"170\\"
44
+        alt=\\"\\" /> </a> </div> <div class=\\"story-content\\"><header
45
+        class=\\"story-header\\"> <div itemprop=\\"alternativeHeadline\\"
46
+        class=\\"story-kicker\\" >Kicker</div> <h2 itemprop=\\"headline\\"
47
+        class=\\"story-title entry-title\\"><a class=\\"story-title-link story-link\\"
48
+        rel=\\"bookmark\\" itemprop=\\"url\\" href=\\"http://www.thedailybeast.com/\\"
49
+        target=\\"_blank\\">Title of article</h2> <div class=\\"story-meta\\">
50
+        <div class=\\"story-score \\">
51
+        <div class=\\"story-score-diggscore diggscore-1sRANah\\">1190</div>
52
+        <div class=\\"story-score-details\\"> <div class=\\"arrow\\"></div>
53
+        <ul class=\\"story-score-details-list\\"> <li
54
+        class=\\"story-score-detail story-score-diggs\\"><span
55
+        class=\\"label\\">Diggs:</span> <span class=\\"count diggs-1sRANah\\">24</span>
56
+        </li> <li class=\\"story-score-detail story-score-twitter\\"><span
57
+        class=\\"label\\">Tweets:</span> <span class=\\"count tweets-1sRANah\\">69</span>
58
+        </li> <li class=\\"story-score-detail story-score-facebook\\"><span
59
+        class=\\"label\\">Facebook Shares:</span> <span
60
+        class=\\"count fb_shares-1sRANah\\">1097</span></li> </ul> </div> </div>
61
+        <span class=\\"story-meta-item story-source\\"> <a
62
+        itemprop=\\"publisher copyrightHolder sourceOrganization provider\\"
63
+        class=\\"story-meta-item-link story-source-link\\"
64
+        href=\\"/source/thedailybeast.com\\">The Daily Beast </a> </span>
65
+        <span class=\\"story-meta-item story-tag first-tag\\"> <a
66
+        itemprop=\\"keywords\\" rel=\\"tag\\"
67
+        class=\\"story-meta-item-link story-tag-link\\" href=\\"/tag/news\\">News</a>
68
+        </span> <abbr class=\\"published story-meta-item story-timestamp\\"
69
+        title=\\"2014-10-18 14:53:45\\"> <time datetime=\\"2014-10-18 14:53:45\\">18 Oct 2014</time>
70
+        </abbr> </div> </header> </div> <ul class=\\"story-actions\\"> <li
71
+        class=\\"story-action story-action-digg btn-story-action-container\\">
72
+        <a class=\\"target digg-1sRANah\\" href=\\"#\\">Digg</a></li> <li
73
+        class=\\"story-action story-action-save btn-story-action-container\\">
74
+        <a class=\\"target save-1sRANah\\" href=\\"#\\">Save</a></li> <li
75
+        class=\\"story-action story-action-share\\"><a
76
+        class=\\"target share-facebook\\" href=\\"https://www.facebook.com/\\">Facebook</a></li>
77
+        <li class=\\"story-action story-action-share\\"><a class=\\"target share-twitter\\"
78
+        href=\\"https://twitter.com/\\">Twitter</a></li> </ul> </article>"
79
+        }
80
+        """
81
+        json = json.replace('\r\n', '').replace('\n', '').replace('\r', '')
82
+        response = mock.Mock(text=json)
83
+        results = digg.response(response)
84
+        self.assertEqual(type(results), list)
85
+        self.assertEqual(len(results), 1)
86
+        self.assertEqual(results[0]['title'], 'Title of article')
87
+        self.assertEqual(results[0]['url'], 'http://url.of.link')
88
+        self.assertEqual(results[0]['thumbnail'], 'http://url.of.image.jpeg')
89
+        self.assertEqual(results[0]['content'], '')
90
+
91
+        json = """
92
+        {
93
+        "status": "error",
94
+        "num": 10,
95
+        "next_position": 20
96
+        }
97
+        """
98
+        response = mock.Mock(text=json)
99
+        results = digg.response(response)
100
+        self.assertEqual(type(results), list)
101
+        self.assertEqual(len(results), 0)

+ 142
- 0
searx/tests/engines/test_flickr.py View File

@@ -0,0 +1,142 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import flickr
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestFlickrEngine(SearxTestCase):
8
+
9
+    def test_request(self):
10
+        query = 'test_query'
11
+        dicto = defaultdict(dict)
12
+        dicto['pageno'] = 0
13
+        params = flickr.request(query, dicto)
14
+        self.assertTrue('url' in params)
15
+        self.assertTrue(query in params['url'])
16
+        self.assertTrue('flickr.com' in params['url'])
17
+
18
+    def test_response(self):
19
+        self.assertRaises(AttributeError, flickr.response, None)
20
+        self.assertRaises(AttributeError, flickr.response, [])
21
+        self.assertRaises(AttributeError, flickr.response, '')
22
+        self.assertRaises(AttributeError, flickr.response, '[]')
23
+
24
+        response = mock.Mock(text='{}')
25
+        self.assertEqual(flickr.response(response), [])
26
+
27
+        response = mock.Mock(text='{"data": []}')
28
+        self.assertEqual(flickr.response(response), [])
29
+
30
+        json = """
31
+        { "photos": { "page": 1, "pages": "41001", "perpage": 100, "total": "4100032",
32
+            "photo": [
33
+            { "id": "15751017054", "owner": "66847915@N08",
34
+            "secret": "69c22afc40", "server": "7285", "farm": 8,
35
+            "title": "Photo title", "ispublic": 1,
36
+            "isfriend": 0, "isfamily": 0,
37
+            "description": { "_content": "Description" },
38
+            "ownername": "Owner",
39
+            "url_o": "https:\/\/farm8.staticflickr.com\/7285\/15751017054_9178e0f963_o.jpg",
40
+            "height_o": "2100", "width_o": "2653",
41
+            "url_n": "https:\/\/farm8.staticflickr.com\/7285\/15751017054_69c22afc40_n.jpg",
42
+            "height_n": "253", "width_n": "320",
43
+            "url_z": "https:\/\/farm8.staticflickr.com\/7285\/15751017054_69c22afc40_z.jpg",
44
+            "height_z": "507", "width_z": "640" }
45
+        ] }, "stat": "ok" }
46
+        """
47
+        response = mock.Mock(text=json)
48
+        results = flickr.response(response)
49
+        self.assertEqual(type(results), list)
50
+        self.assertEqual(len(results), 1)
51
+        self.assertEqual(results[0]['title'], 'Photo title')
52
+        self.assertEqual(results[0]['url'], 'https://www.flickr.com/photos/66847915@N08/15751017054')
53
+        self.assertTrue('o.jpg' in results[0]['img_src'])
54
+        self.assertTrue('n.jpg' in results[0]['thumbnail_src'])
55
+        self.assertTrue('Owner' in results[0]['content'])
56
+        self.assertTrue('Description' in results[0]['content'])
57
+
58
+        json = """
59
+        { "photos": { "page": 1, "pages": "41001", "perpage": 100, "total": "4100032",
60
+            "photo": [
61
+            { "id": "15751017054", "owner": "66847915@N08",
62
+            "secret": "69c22afc40", "server": "7285", "farm": 8,
63
+            "title": "Photo title", "ispublic": 1,
64
+            "isfriend": 0, "isfamily": 0,
65
+            "description": { "_content": "Description" },
66
+            "ownername": "Owner",
67
+            "url_z": "https:\/\/farm8.staticflickr.com\/7285\/15751017054_69c22afc40_z.jpg",
68
+            "height_z": "507", "width_z": "640" }
69
+        ] }, "stat": "ok" }
70
+        """
71
+        response = mock.Mock(text=json)
72
+        results = flickr.response(response)
73
+        self.assertEqual(type(results), list)
74
+        self.assertEqual(len(results), 1)
75
+        self.assertEqual(results[0]['title'], 'Photo title')
76
+        self.assertEqual(results[0]['url'], 'https://www.flickr.com/photos/66847915@N08/15751017054')
77
+        self.assertTrue('z.jpg' in results[0]['img_src'])
78
+        self.assertTrue('z.jpg' in results[0]['thumbnail_src'])
79
+        self.assertTrue('Owner' in results[0]['content'])
80
+        self.assertTrue('Description' in results[0]['content'])
81
+
82
+        json = """
83
+        { "photos": { "page": 1, "pages": "41001", "perpage": 100, "total": "4100032",
84
+            "photo": [
85
+            { "id": "15751017054", "owner": "66847915@N08",
86
+            "secret": "69c22afc40", "server": "7285", "farm": 8,
87
+            "title": "Photo title", "ispublic": 1,
88
+            "isfriend": 0, "isfamily": 0,
89
+            "description": { "_content": "Description" },
90
+            "ownername": "Owner",
91
+            "url_o": "https:\/\/farm8.staticflickr.com\/7285\/15751017054_9178e0f963_o.jpg",
92
+            "height_o": "2100", "width_o": "2653" }
93
+        ] }, "stat": "ok" }
94
+        """
95
+        response = mock.Mock(text=json)
96
+        results = flickr.response(response)
97
+        self.assertEqual(type(results), list)
98
+        self.assertEqual(len(results), 1)
99
+        self.assertEqual(results[0]['title'], 'Photo title')
100
+        self.assertEqual(results[0]['url'], 'https://www.flickr.com/photos/66847915@N08/15751017054')
101
+        self.assertTrue('o.jpg' in results[0]['img_src'])
102
+        self.assertTrue('o.jpg' in results[0]['thumbnail_src'])
103
+        self.assertTrue('Owner' in results[0]['content'])
104
+        self.assertTrue('Description' in results[0]['content'])
105
+
106
+        json = """
107
+        { "photos": { "page": 1, "pages": "41001", "perpage": 100, "total": "4100032",
108
+            "photo": [
109
+            { "id": "15751017054", "owner": "66847915@N08",
110
+            "secret": "69c22afc40", "server": "7285", "farm": 8,
111
+            "title": "Photo title", "ispublic": 1,
112
+            "isfriend": 0, "isfamily": 0,
113
+            "description": { "_content": "Description" },
114
+            "ownername": "Owner",
115
+            "url_n": "https:\/\/farm8.staticflickr.com\/7285\/15751017054_69c22afc40_n.jpg",
116
+            "height_n": "253", "width_n": "320" }
117
+        ] }, "stat": "ok" }
118
+        """
119
+        response = mock.Mock(text=json)
120
+        results = flickr.response(response)
121
+        self.assertEqual(type(results), list)
122
+        self.assertEqual(len(results), 0)
123
+
124
+        json = """
125
+        { "photos": { "page": 1, "pages": "41001", "perpage": 100, "total": "4100032",
126
+            "toto": [] }, "stat": "ok" }
127
+        """
128
+        response = mock.Mock(text=json)
129
+        results = flickr.response(response)
130
+        self.assertEqual(type(results), list)
131
+        self.assertEqual(len(results), 0)
132
+
133
+        json = """
134
+        {"toto":[
135
+            {"id":200,"name":"Artist Name",
136
+            "link":"http:\/\/www.flickr.com\/artist\/1217","type":"artist"}
137
+        ]}
138
+        """
139
+        response = mock.Mock(text=json)
140
+        results = flickr.response(response)
141
+        self.assertEqual(type(results), list)
142
+        self.assertEqual(len(results), 0)

+ 442
- 0
searx/tests/engines/test_flickr_noapi.py View File

@@ -0,0 +1,442 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import flickr_noapi
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestFlickrNoapiEngine(SearxTestCase):
8
+
9
+    def test_build_flickr_url(self):
10
+        url = flickr_noapi.build_flickr_url("uid", "pid")
11
+        self.assertIn("uid", url)
12
+        self.assertIn("pid", url)
13
+
14
+    def test_request(self):
15
+        query = 'test_query'
16
+        dicto = defaultdict(dict)
17
+        dicto['pageno'] = 1
18
+        params = flickr_noapi.request(query, dicto)
19
+        self.assertIn('url', params)
20
+        self.assertIn(query, params['url'])
21
+        self.assertIn('flickr.com', params['url'])
22
+
23
+    def test_response(self):
24
+        self.assertRaises(AttributeError, flickr_noapi.response, None)
25
+        self.assertRaises(AttributeError, flickr_noapi.response, [])
26
+        self.assertRaises(AttributeError, flickr_noapi.response, '')
27
+        self.assertRaises(AttributeError, flickr_noapi.response, '[]')
28
+
29
+        response = mock.Mock(text='"search-photos-models","photos":{},"totalItems":')
30
+        self.assertEqual(flickr_noapi.response(response), [])
31
+
32
+        response = mock.Mock(text='search-photos-models","photos":{"data": []},"totalItems":')
33
+        self.assertEqual(flickr_noapi.response(response), [])
34
+
35
+        json = """
36
+        "search-photos-models","photos":
37
+        {
38
+          "_data": [
39
+            {
40
+              "_flickrModelRegistry": "photo-models",
41
+              "title": "This is the title",
42
+              "sizes": {
43
+                "c": {
44
+                  "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_c.jpg",
45
+                  "width": 541,
46
+                  "height": 800,
47
+                  "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_c.jpg",
48
+                  "key": "c"
49
+                },
50
+                "h": {
51
+                  "displayUrl": "//farm8.staticflickr.com/7246/14001294434_761d32237a_h.jpg",
52
+                  "width": 1081,
53
+                  "height": 1600,
54
+                  "url": "//c4.staticflickr.com/8/7246/14001294434_761d32237a_h.jpg",
55
+                  "key": "h"
56
+                },
57
+                "k": {
58
+                  "displayUrl": "//farm8.staticflickr.com/7246/14001294434_f145a2c11a_k.jpg",
59
+                  "width": 1383,
60
+                  "height": 2048,
61
+                  "url": "//c4.staticflickr.com/8/7246/14001294434_f145a2c11a_k.jpg",
62
+                  "key": "k"
63
+                },
64
+                "l": {
65
+                  "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_b.jpg",
66
+                  "width": 692,
67
+                  "height": 1024,
68
+                  "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_b.jpg",
69
+                  "key": "l"
70
+                },
71
+                "m": {
72
+                  "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777.jpg",
73
+                  "width": 338,
74
+                  "height": 500,
75
+                  "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777.jpg",
76
+                  "key": "m"
77
+                },
78
+                "n": {
79
+                  "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_n.jpg",
80
+                  "width": 216,
81
+                  "height": 320,
82
+                  "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_n.jpg",
83
+                  "key": "n"
84
+                },
85
+                "q": {
86
+                  "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_q.jpg",
87
+                  "width": 150,
88
+                  "height": 150,
89
+                  "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_q.jpg",
90
+                  "key": "q"
91
+                },
92
+                "s": {
93
+                  "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_m.jpg",
94
+                  "width": 162,
95
+                  "height": 240,
96
+                  "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_m.jpg",
97
+                  "key": "s"
98
+                },
99
+                "sq": {
100
+                  "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_s.jpg",
101
+                  "width": 75,
102
+                  "height": 75,
103
+                  "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_s.jpg",
104
+                  "key": "sq"
105
+                },
106
+                "t": {
107
+                  "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_t.jpg",
108
+                  "width": 68,
109
+                  "height": 100,
110
+                  "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_t.jpg",
111
+                  "key": "t"
112
+                },
113
+                "z": {
114
+                  "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_z.jpg",
115
+                  "width": 433,
116
+                  "height": 640,
117
+                  "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_z.jpg",
118
+                  "key": "z"
119
+                }
120
+              },
121
+              "canComment": false,
122
+              "rotation": 0,
123
+              "owner": {
124
+                "_flickrModelRegistry": "person-models",
125
+                "pathAlias": "klink692",
126
+                "username": "Owner",
127
+                "buddyicon": {
128
+                  "retina": null,
129
+                  "large": null,
130
+                  "medium": null,
131
+                  "small": null,
132
+                  "default": "//c1.staticflickr.com/9/8108/buddyicons/59729010@N00.jpg?1361642376#59729010@N00"
133
+                },
134
+                "isPro": true,
135
+                "id": "59729010@N00"
136
+              },
137
+              "engagement": {
138
+                "_flickrModelRegistry": "photo-engagement-models",
139
+                "ownerNsid": "59729010@N00",
140
+                "faveCount": 21,
141
+                "commentCount": 14,
142
+                "viewCount": 10160,
143
+                "id": "14001294434"
144
+              },
145
+              "description": "Description",
146
+              "isHD": false,
147
+              "secret": "410f653777",
148
+              "canAddMeta": false,
149
+              "license": 0,
150
+              "oWidth": 1803,
151
+              "oHeight": 2669,
152
+              "safetyLevel": 0,
153
+              "id": "14001294434"
154
+            }
155
+          ],
156
+          "fetchedStart": true,
157
+          "fetchedEnd": false,
158
+          "totalItems": "4386039"
159
+        },"totalItems":
160
+        """
161
+        json = json.replace('\r\n', '').replace('\n', '').replace('\r', '')
162
+        response = mock.Mock(text=json)
163
+        results = flickr_noapi.response(response)
164
+        self.assertEqual(type(results), list)
165
+        self.assertEqual(len(results), 1)
166
+        self.assertEqual(results[0]['title'], 'This is the title')
167
+        self.assertEqual(results[0]['url'], 'https://www.flickr.com/photos/59729010@N00/14001294434')
168
+        self.assertIn('k.jpg', results[0]['img_src'])
169
+        self.assertIn('n.jpg', results[0]['thumbnail_src'])
170
+        self.assertIn('Owner', results[0]['content'])
171
+        self.assertIn('Description', results[0]['content'])
172
+
173
+        json = """
174
+        "search-photos-models","photos":
175
+        {
176
+          "_data": [
177
+            {
178
+              "_flickrModelRegistry": "photo-models",
179
+              "title": "This is the title",
180
+              "sizes": {
181
+                "z": {
182
+                  "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_z.jpg",
183
+                  "width": 433,
184
+                  "height": 640,
185
+                  "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_z.jpg",
186
+                  "key": "z"
187
+                }
188
+              },
189
+              "canComment": false,
190
+              "rotation": 0,
191
+              "owner": {
192
+                "_flickrModelRegistry": "person-models",
193
+                "pathAlias": "klink692",
194
+                "username": "Owner",
195
+                "buddyicon": {
196
+                  "retina": null,
197
+                  "large": null,
198
+                  "medium": null,
199
+                  "small": null,
200
+                  "default": "//c1.staticflickr.com/9/8108/buddyicons/59729010@N00.jpg?1361642376#59729010@N00"
201
+                },
202
+                "isPro": true,
203
+                "id": "59729010@N00"
204
+              },
205
+              "engagement": {
206
+                "_flickrModelRegistry": "photo-engagement-models",
207
+                "ownerNsid": "59729010@N00",
208
+                "faveCount": 21,
209
+                "commentCount": 14,
210
+                "viewCount": 10160,
211
+                "id": "14001294434"
212
+              },
213
+              "description": "Description",
214
+              "isHD": false,
215
+              "secret": "410f653777",
216
+              "canAddMeta": false,
217
+              "license": 0,
218
+              "oWidth": 1803,
219
+              "oHeight": 2669,
220
+              "safetyLevel": 0,
221
+              "id": "14001294434"
222
+            }
223
+          ],
224
+          "fetchedStart": true,
225
+          "fetchedEnd": false,
226
+          "totalItems": "4386039"
227
+        },"totalItems":
228
+        """
229
+        response = mock.Mock(text=json)
230
+        results = flickr_noapi.response(response)
231
+        self.assertEqual(type(results), list)
232
+        self.assertEqual(len(results), 1)
233
+        self.assertEqual(results[0]['title'], 'This is the title')
234
+        self.assertEqual(results[0]['url'], 'https://www.flickr.com/photos/59729010@N00/14001294434')
235
+        self.assertIn('z.jpg', results[0]['img_src'])
236
+        self.assertIn('z.jpg', results[0]['thumbnail_src'])
237
+        self.assertIn('Owner', results[0]['content'])
238
+        self.assertIn('Description', results[0]['content'])
239
+
240
+        json = """
241
+        "search-photos-models","photos":
242
+        {
243
+          "_data": [
244
+            {
245
+              "_flickrModelRegistry": "photo-models",
246
+              "title": "This is the title",
247
+              "sizes": {
248
+                "o": {
249
+                  "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_o.jpg",
250
+                  "width": 433,
251
+                  "height": 640,
252
+                  "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_o.jpg",
253
+                  "key": "o"
254
+                }
255
+              },
256
+              "canComment": false,
257
+              "rotation": 0,
258
+              "owner": {
259
+                "_flickrModelRegistry": "person-models",
260
+                "pathAlias": "klink692",
261
+                "username": "Owner",
262
+                "buddyicon": {
263
+                  "retina": null,
264
+                  "large": null,
265
+                  "medium": null,
266
+                  "small": null,
267
+                  "default": "//c1.staticflickr.com/9/8108/buddyicons/59729010@N00.jpg?1361642376#59729010@N00"
268
+                },
269
+                "isPro": true,
270
+                "id": "59729010@N00"
271
+              },
272
+              "engagement": {
273
+                "_flickrModelRegistry": "photo-engagement-models",
274
+                "ownerNsid": "59729010@N00",
275
+                "faveCount": 21,
276
+                "commentCount": 14,
277
+                "viewCount": 10160,
278
+                "id": "14001294434"
279
+              },
280
+              "isHD": false,
281
+              "secret": "410f653777",
282
+              "canAddMeta": false,
283
+              "license": 0,
284
+              "oWidth": 1803,
285
+              "oHeight": 2669,
286
+              "safetyLevel": 0,
287
+              "id": "14001294434"
288
+            }
289
+          ],
290
+          "fetchedStart": true,
291
+          "fetchedEnd": false,
292
+          "totalItems": "4386039"
293
+        },"totalItems":
294
+        """
295
+        response = mock.Mock(text=json)
296
+        results = flickr_noapi.response(response)
297
+        self.assertEqual(type(results), list)
298
+        self.assertEqual(len(results), 1)
299
+        self.assertEqual(results[0]['title'], 'This is the title')
300
+        self.assertEqual(results[0]['url'], 'https://www.flickr.com/photos/59729010@N00/14001294434')
301
+        self.assertIn('o.jpg', results[0]['img_src'])
302
+        self.assertIn('o.jpg', results[0]['thumbnail_src'])
303
+        self.assertIn('Owner', results[0]['content'])
304
+
305
+        json = """
306
+        "search-photos-models","photos":
307
+        {
308
+          "_data": [
309
+            {
310
+              "_flickrModelRegistry": "photo-models",
311
+              "title": "This is the title",
312
+              "sizes": {
313
+              },
314
+              "canComment": false,
315
+              "rotation": 0,
316
+              "owner": {
317
+                "_flickrModelRegistry": "person-models",
318
+                "pathAlias": "klink692",
319
+                "username": "Owner",
320
+                "buddyicon": {
321
+                  "retina": null,
322
+                  "large": null,
323
+                  "medium": null,
324
+                  "small": null,
325
+                  "default": "//c1.staticflickr.com/9/8108/buddyicons/59729010@N00.jpg?1361642376#59729010@N00"
326
+                },
327
+                "isPro": true,
328
+                "id": "59729010@N00"
329
+              },
330
+              "engagement": {
331
+                "_flickrModelRegistry": "photo-engagement-models",
332
+                "ownerNsid": "59729010@N00",
333
+                "faveCount": 21,
334
+                "commentCount": 14,
335
+                "viewCount": 10160,
336
+                "id": "14001294434"
337
+              },
338
+              "description": "Description",
339
+              "isHD": false,
340
+              "secret": "410f653777",
341
+              "canAddMeta": false,
342
+              "license": 0,
343
+              "oWidth": 1803,
344
+              "oHeight": 2669,
345
+              "safetyLevel": 0,
346
+              "id": "14001294434"
347
+            }
348
+          ],
349
+          "fetchedStart": true,
350
+          "fetchedEnd": false,
351
+          "totalItems": "4386039"
352
+        },"totalItems":
353
+        """
354
+        response = mock.Mock(text=json)
355
+        results = flickr_noapi.response(response)
356
+        self.assertEqual(type(results), list)
357
+        self.assertEqual(len(results), 0)
358
+
359
+        json = """
360
+        "search-photos-models","photos":
361
+        {
362
+          "_data": [null],
363
+          "fetchedStart": true,
364
+          "fetchedEnd": false,
365
+          "totalItems": "4386039"
366
+        },"totalItems":
367
+        """
368
+        response = mock.Mock(text=json)
369
+        results = flickr_noapi.response(response)
370
+        self.assertEqual(type(results), list)
371
+        self.assertEqual(len(results), 0)
372
+
373
+        json = """
374
+        "search-photos-models","photos":
375
+        {
376
+          "_data": [
377
+            {
378
+              "_flickrModelRegistry": "photo-models",
379
+              "title": "This is the title",
380
+              "sizes": {
381
+                "o": {
382
+                  "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_o.jpg",
383
+                  "width": 433,
384
+                  "height": 640,
385
+                  "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_o.jpg",
386
+                  "key": "o"
387
+                }
388
+              },
389
+              "canComment": false,
390
+              "rotation": 0,
391
+              "owner": {
392
+                "_flickrModelRegistry": "person-models",
393
+                "pathAlias": "klink692",
394
+                "username": "Owner",
395
+                "buddyicon": {
396
+                  "retina": null,
397
+                  "large": null,
398
+                  "medium": null,
399
+                  "small": null,
400
+                  "default": "//c1.staticflickr.com/9/8108/buddyicons/59729010@N00.jpg?1361642376#59729010@N00"
401
+                },
402
+                "isPro": true
403
+              },
404
+              "engagement": {
405
+                "_flickrModelRegistry": "photo-engagement-models",
406
+                "ownerNsid": "59729010@N00",
407
+                "faveCount": 21,
408
+                "commentCount": 14,
409
+                "viewCount": 10160,
410
+                "id": "14001294434"
411
+              },
412
+              "description": "Description",
413
+              "isHD": false,
414
+              "secret": "410f653777",
415
+              "canAddMeta": false,
416
+              "license": 0,
417
+              "oWidth": 1803,
418
+              "oHeight": 2669,
419
+              "safetyLevel": 0,
420
+              "id": "14001294434"
421
+            }
422
+          ],
423
+          "fetchedStart": true,
424
+          "fetchedEnd": false,
425
+          "totalItems": "4386039"
426
+        },"totalItems":
427
+        """
428
+        response = mock.Mock(text=json)
429
+        results = flickr_noapi.response(response)
430
+        self.assertEqual(type(results), list)
431
+        self.assertEqual(len(results), 0)
432
+
433
+        json = """
434
+        {"toto":[
435
+            {"id":200,"name":"Artist Name",
436
+            "link":"http:\/\/www.flickr.com\/artist\/1217","type":"artist"}
437
+        ]}
438
+        """
439
+        response = mock.Mock(text=json)
440
+        results = flickr_noapi.response(response)
441
+        self.assertEqual(type(results), list)
442
+        self.assertEqual(len(results), 0)

+ 108
- 0
searx/tests/engines/test_google_images.py View File

@@ -0,0 +1,108 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import google_images
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestGoogleImagesEngine(SearxTestCase):
8
+
9
+    def test_request(self):
10
+        query = 'test_query'
11
+        dicto = defaultdict(dict)
12
+        dicto['pageno'] = 1
13
+        params = google_images.request(query, dicto)
14
+        self.assertTrue('url' in params)
15
+        self.assertTrue(query in params['url'])
16
+        self.assertTrue('googleapis.com' in params['url'])
17
+
18
+    def test_response(self):
19
+        self.assertRaises(AttributeError, google_images.response, None)
20
+        self.assertRaises(AttributeError, google_images.response, [])
21
+        self.assertRaises(AttributeError, google_images.response, '')
22
+        self.assertRaises(AttributeError, google_images.response, '[]')
23
+
24
+        response = mock.Mock(text='{}')
25
+        self.assertEqual(google_images.response(response), [])
26
+
27
+        response = mock.Mock(text='{"data": []}')
28
+        self.assertEqual(google_images.response(response), [])
29
+
30
+        json = """
31
+        {
32
+        "responseData": {
33
+            "results": [
34
+            {
35
+                "GsearchResultClass": "GimageSearch",
36
+                "width": "400",
37
+                "height": "400",
38
+                "imageId": "ANd9GcQbYb9FJuAbG_hT4i8FeC0O0x-P--EHdzgRIF9ao97nHLl7C2mREn6qTQ",
39
+                "tbWidth": "124",
40
+                "tbHeight": "124",
41
+                "unescapedUrl": "http://unescaped.url.jpg",
42
+                "url": "http://image.url.jpg",
43
+                "visibleUrl": "insolitebuzz.fr",
44
+                "title": "This is the title",
45
+                "titleNoFormatting": "Petit test sympa qui rend fou tout le monde ! A faire",
46
+                "originalContextUrl": "http://this.is.the.url",
47
+                "content": "<b>test</b>",
48
+                "contentNoFormatting": "test",
49
+                "tbUrl": "http://thumbnail.url"
50
+            }
51
+            ]
52
+        },
53
+        "responseDetails": null,
54
+        "responseStatus": 200
55
+        }
56
+        """
57
+        response = mock.Mock(text=json)
58
+        results = google_images.response(response)
59
+        self.assertEqual(type(results), list)
60
+        self.assertEqual(len(results), 1)
61
+        self.assertEqual(results[0]['title'], 'This is the title')
62
+        self.assertEqual(results[0]['url'], 'http://this.is.the.url')
63
+        self.assertEqual(results[0]['thumbnail_src'], 'http://thumbnail.url')
64
+        self.assertEqual(results[0]['img_src'], 'http://image.url.jpg')
65
+        self.assertEqual(results[0]['content'], '<b>test</b>')
66
+
67
+        json = """
68
+        {
69
+        "responseData": {
70
+            "results": [
71
+            {
72
+                "GsearchResultClass": "GimageSearch",
73
+                "width": "400",
74
+                "height": "400",
75
+                "imageId": "ANd9GcQbYb9FJuAbG_hT4i8FeC0O0x-P--EHdzgRIF9ao97nHLl7C2mREn6qTQ",
76
+                "tbWidth": "124",
77
+                "tbHeight": "124",
78
+                "unescapedUrl": "http://unescaped.url.jpg",
79
+                "visibleUrl": "insolitebuzz.fr",
80
+                "title": "This is the title",
81
+                "titleNoFormatting": "Petit test sympa qui rend fou tout le monde ! A faire",
82
+                "originalContextUrl": "http://this.is.the.url",
83
+                "content": "<b>test</b>",
84
+                "contentNoFormatting": "test",
85
+                "tbUrl": "http://thumbnail.url"
86
+            }
87
+            ]
88
+        },
89
+        "responseDetails": null,
90
+        "responseStatus": 200
91
+        }
92
+        """
93
+        response = mock.Mock(text=json)
94
+        results = google_images.response(response)
95
+        self.assertEqual(type(results), list)
96
+        self.assertEqual(len(results), 0)
97
+
98
+        json = """
99
+        {
100
+        "responseData": {},
101
+        "responseDetails": null,
102
+        "responseStatus": 200
103
+        }
104
+        """
105
+        response = mock.Mock(text=json)
106
+        results = google_images.response(response)
107
+        self.assertEqual(type(results), list)
108
+        self.assertEqual(len(results), 0)

+ 136
- 0
searx/tests/engines/test_google_news.py View File

@@ -0,0 +1,136 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import google_news
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestGoogleNewsEngine(SearxTestCase):
8
+
9
+    def test_request(self):
10
+        query = 'test_query'
11
+        dicto = defaultdict(dict)
12
+        dicto['pageno'] = 1
13
+        dicto['language'] = 'fr_FR'
14
+        params = google_news.request(query, dicto)
15
+        self.assertIn('url', params)
16
+        self.assertIn(query, params['url'])
17
+        self.assertIn('googleapis.com', params['url'])
18
+        self.assertIn('fr', params['url'])
19
+
20
+        dicto['language'] = 'all'
21
+        params = google_news.request(query, dicto)
22
+        self.assertIn('url', params)
23
+        self.assertIn('en', params['url'])
24
+
25
+    def test_response(self):
26
+        self.assertRaises(AttributeError, google_news.response, None)
27
+        self.assertRaises(AttributeError, google_news.response, [])
28
+        self.assertRaises(AttributeError, google_news.response, '')
29
+        self.assertRaises(AttributeError, google_news.response, '[]')
30
+
31
+        response = mock.Mock(text='{}')
32
+        self.assertEqual(google_news.response(response), [])
33
+
34
+        response = mock.Mock(text='{"data": []}')
35
+        self.assertEqual(google_news.response(response), [])
36
+
37
+        json = """
38
+        {
39
+        "responseData": {
40
+            "results": [
41
+            {
42
+                "GsearchResultClass": "GnewsSearch",
43
+                "clusterUrl": "http://news.google.com/news/story?ncl=d2d3t1LMDpNIj2MPPhdTT0ycN4sWM&hl=fr&ned=fr",
44
+                "content": "This is the content",
45
+                "unescapedUrl": "http://this.is.the.url",
46
+                "url": "http://this.is.the.url",
47
+                "title": "This is the title",
48
+                "titleNoFormatting": "This is the title",
49
+                "location": "",
50
+                "publisher": "Jeux Actu",
51
+                "publishedDate": "Fri, 30 Jan 2015 11:00:25 -0800",
52
+                "signedRedirectUrl": "http://news.google.com/",
53
+                "language": "fr",
54
+                "image": {
55
+                "url": "http://i.jeuxactus.com/datas/jeux/d/y/dying-light/vu/dying-light-54cc080b568fb.jpg",
56
+                "tbUrl": "http://t1.gstatic.com/images?q=tbn:ANd9GcSF4yYrs9Ycw23DGiOSAZ-5SEPXYwG3LNs",
57
+                "originalContextUrl": "http://www.jeuxactu.com/test-dying-light-sur-ps4-97208.htm",
58
+                "publisher": "Jeux Actu",
59
+                "tbWidth": 80,
60
+                "tbHeight": 30
61
+                },
62
+                "relatedStories": [
63
+                {
64
+                    "unescapedUrl": "http://www.jeuxvideo.com/test/415823/dying-light.htm",
65
+                    "url": "http%3A%2F%2Fwww.jeuxvideo.com%2Ftest%2F415823%2Fdying-light.htm",
66
+                    "title": "<b>Test</b> du jeu Dying Light - jeuxvideo.com",
67
+                    "titleNoFormatting": "Test du jeu Dying Light - jeuxvideo.com",
68
+                    "location": "",
69
+                    "publisher": "JeuxVideo.com",
70
+                    "publishedDate": "Fri, 30 Jan 2015 08:52:30 -0800",
71
+                    "signedRedirectUrl": "http://news.google.com/news/url?sa=T&",
72
+                    "language": "fr"
73
+                }
74
+                ]
75
+            }
76
+            ]
77
+        },
78
+        "responseDetails": null,
79
+        "responseStatus": 200
80
+        }
81
+        """
82
+        response = mock.Mock(text=json)
83
+        results = google_news.response(response)
84
+        self.assertEqual(type(results), list)
85
+        self.assertEqual(len(results), 1)
86
+        self.assertEqual(results[0]['title'], 'This is the title')
87
+        self.assertEqual(results[0]['url'], 'http://this.is.the.url')
88
+        self.assertEqual(results[0]['content'], 'This is the content')
89
+
90
+        json = """
91
+        {
92
+        "responseData": {
93
+            "results": [
94
+            {
95
+                "GsearchResultClass": "GnewsSearch",
96
+                "clusterUrl": "http://news.google.com/news/story?ncl=d2d3t1LMDpNIj2MPPhdTT0ycN4sWM&hl=fr&ned=fr",
97
+                "content": "This is the content",
98
+                "unescapedUrl": "http://this.is.the.url",
99
+                "title": "This is the title",
100
+                "titleNoFormatting": "This is the title",
101
+                "location": "",
102
+                "publisher": "Jeux Actu",
103
+                "publishedDate": "Fri, 30 Jan 2015 11:00:25 -0800",
104
+                "signedRedirectUrl": "http://news.google.com/news/",
105
+                "language": "fr",
106
+                "image": {
107
+                "url": "http://i.jeuxactus.com/datas/jeux/d/y/dying-light/vu/dying-light-54cc080b568fb.jpg",
108
+                "tbUrl": "http://t1.gstatic.com/images?q=tbn:b_6f-OSAZ-5SEPXYwG3LNs",
109
+                "originalContextUrl": "http://www.jeuxactu.com/test-dying-light-sur-ps4-97208.htm",
110
+                "publisher": "Jeux Actu",
111
+                "tbWidth": 80,
112
+                "tbHeight": 30
113
+                }
114
+            }
115
+            ]
116
+        },
117
+        "responseDetails": null,
118
+        "responseStatus": 200
119
+        }
120
+        """
121
+        response = mock.Mock(text=json)
122
+        results = google_news.response(response)
123
+        self.assertEqual(type(results), list)
124
+        self.assertEqual(len(results), 0)
125
+
126
+        json = """
127
+        {
128
+        "responseData": {},
129
+        "responseDetails": null,
130
+        "responseStatus": 200
131
+        }
132
+        """
133
+        response = mock.Mock(text=json)
134
+        results = google_news.response(response)
135
+        self.assertEqual(type(results), list)
136
+        self.assertEqual(len(results), 0)

+ 398
- 0
searx/tests/engines/test_kickass.py View File

@@ -0,0 +1,398 @@
1
+# -*- coding: utf-8 -*-
2
+from collections import defaultdict
3
+import mock
4
+from searx.engines import kickass
5
+from searx.testing import SearxTestCase
6
+
7
+
8
+class TestKickassEngine(SearxTestCase):
9
+
10
+    def test_request(self):
11
+        query = 'test_query'
12
+        dicto = defaultdict(dict)
13
+        dicto['pageno'] = 1
14
+        params = kickass.request(query, dicto)
15
+        self.assertIn('url', params)
16
+        self.assertIn(query, params['url'])
17
+        self.assertIn('kickass.so', params['url'])
18
+        self.assertIn('verify', params)
19
+        self.assertFalse(params['verify'])
20
+
21
+    def test_response(self):
22
+        self.assertRaises(AttributeError, kickass.response, None)
23
+        self.assertRaises(AttributeError, kickass.response, [])
24
+        self.assertRaises(AttributeError, kickass.response, '')
25
+        self.assertRaises(AttributeError, kickass.response, '[]')
26
+
27
+        response = mock.Mock(text='<html></html>')
28
+        self.assertEqual(kickass.response(response), [])
29
+
30
+        html = """
31
+        <table cellpadding="0" cellspacing="0" class="data" style="width: 100%">
32
+            <tr class="firstr">
33
+                <th class="width100perc nopad">torrent name</th>
34
+                <th class="center">
35
+                    <a href="/search/test/?field=size&sorder=desc" rel="nofollow">size</a>
36
+                </th>
37
+                <th class="center"><span class="files">
38
+                    <a href="/search/test/?field=files_count&sorder=desc" rel="nofollow">files</a></span>
39
+                </th>
40
+                <th class="center"><span>
41
+                    <a href="/search/test/?field=time_add&sorder=desc" rel="nofollow">age</a></span>
42
+                </th>
43
+                <th class="center"><span class="seed">
44
+                    <a href="/search/test/?field=seeders&sorder=desc" rel="nofollow">seed</a></span>
45
+                </th>
46
+                <th class="lasttd nobr center">
47
+                    <a href="/search/test/?field=leechers&sorder=desc" rel="nofollow">leech</a>
48
+                </th>
49
+            </tr>
50
+            <tr class="even" id="torrent_test6478745">
51
+                <td>
52
+                    <div class="iaconbox center floatright">
53
+                        <a rel="6478745,0" class="icommentjs icon16" href="/test-t6478745.html#comment">
54
+                            <em style="font-size: 12px; margin: 0 4px 0 4px;" class="iconvalue">3</em>
55
+                            <i class="ka ka-comment"></i>
56
+                        </a>
57
+                        <a class="iverify icon16" href="/test-t6478745.html" title="Verified Torrent">
58
+                            <i class="ka ka16 ka-verify ka-green"></i>
59
+                        </a>
60
+                        <a href="#" onclick="_scq.push([]); return false;" class="partner1Button idownload icon16">
61
+                            <i class="ka ka16 ka-arrow-down partner1Button"></i>
62
+                        </a>
63
+                        <a title="Torrent magnet link"
64
+                            href="magnet:?xt=urn:btih:MAGNETURL&dn=test" class="imagnet icon16">
65
+                            <i class="ka ka16 ka-magnet"></i>
66
+                        </a>
67
+                        <a title="Download torrent file"
68
+                            href="http://torcache.net/torrent/53917.torrent?title=test" class="idownload icon16">
69
+                            <i class="ka ka16 ka-arrow-down"></i>
70
+                        </a>
71
+                    </div>
72
+                    <div class="torrentname">
73
+                    <a href="/test-t6478745.html" class="torType txtType"></a>
74
+                    <a href="/test-t6478745.html" class="normalgrey font12px plain bold"></a>
75
+                    <div class="markeredBlock torType txtType">
76
+                        <a href="/url.html" class="cellMainLink">
77
+                            <strong class="red">This should be the title</strong>
78
+                        </a>
79
+                        <span class="font11px lightgrey block">
80
+                            Posted by <i class="ka ka-verify" style="font-size: 16px;color:orange;"></i>
81
+                            <a class="plain" href="/user/riri/">riri</a> in
82
+                            <span id="cat_6478745">
83
+                                <strong><a href="/other/">Other</a> > <a href="/unsorted/">Unsorted</a></strong>
84
+                            </span>
85
+                        </span>
86
+                    </div>
87
+                </td>
88
+                <td class="nobr center">449 <span>bytes</span></td>
89
+                <td class="center">4</td>
90
+                <td class="center">2&nbsp;years</td>
91
+                <td class="green center">10</td>
92
+                <td class="red lasttd center">1</td>
93
+            </tr>
94
+        </table>
95
+        """
96
+        response = mock.Mock(text=html)
97
+        results = kickass.response(response)
98
+        self.assertEqual(type(results), list)
99
+        self.assertEqual(len(results), 1)
100
+        self.assertEqual(results[0]['title'], 'This should be the title')
101
+        self.assertEqual(results[0]['url'], 'https://kickass.so/url.html')
102
+        self.assertEqual(results[0]['content'], 'Posted by riri in Other &gt; Unsorted')
103
+        self.assertEqual(results[0]['seed'], 10)
104
+        self.assertEqual(results[0]['leech'], 1)
105
+        self.assertEqual(results[0]['filesize'], 449)
106
+        self.assertEqual(results[0]['files'], 4)
107
+        self.assertEqual(results[0]['magnetlink'], 'magnet:?xt=urn:btih:MAGNETURL&dn=test')
108
+        self.assertEqual(results[0]['torrentfile'], 'http://torcache.net/torrent/53917.torrent?title=test')
109
+
110
+        html = """
111
+        <table cellpadding="0" cellspacing="0" class="data" style="width: 100%">
112
+            <tr class="firstr">
113
+                <th class="width100perc nopad">torrent name</th>
114
+                <th class="center">
115
+                    <a href="/search/test/?field=size&sorder=desc" rel="nofollow">size</a>
116
+                </th>
117
+                <th class="center"><span class="files">
118
+                    <a href="/search/test/?field=files_count&sorder=desc" rel="nofollow">files</a></span>
119
+                </th>
120
+                <th class="center"><span>
121
+                    <a href="/search/test/?field=time_add&sorder=desc" rel="nofollow">age</a></span>
122
+                </th>
123
+                <th class="center"><span class="seed">
124
+                    <a href="/search/test/?field=seeders&sorder=desc" rel="nofollow">seed</a></span>
125
+                </th>
126
+                <th class="lasttd nobr center">
127
+                    <a href="/search/test/?field=leechers&sorder=desc" rel="nofollow">leech</a>
128
+                </th>
129
+            </tr>
130
+        </table>
131
+        """
132
+        response = mock.Mock(text=html)
133
+        results = kickass.response(response)
134
+        self.assertEqual(type(results), list)
135
+        self.assertEqual(len(results), 0)
136
+
137
+        html = """
138
+        <table cellpadding="0" cellspacing="0" class="data" style="width: 100%">
139
+            <tr class="firstr">
140
+                <th class="width100perc nopad">torrent name</th>
141
+                <th class="center">
142
+                    <a href="/search/test/?field=size&sorder=desc" rel="nofollow">size</a>
143
+                </th>
144
+                <th class="center"><span class="files">
145
+                    <a href="/search/test/?field=files_count&sorder=desc" rel="nofollow">files</a></span>
146
+                </th>
147
+                <th class="center"><span>
148
+                    <a href="/search/test/?field=time_add&sorder=desc" rel="nofollow">age</a></span>
149
+                </th>
150
+                <th class="center"><span class="seed">
151
+                    <a href="/search/test/?field=seeders&sorder=desc" rel="nofollow">seed</a></span>
152
+                </th>
153
+                <th class="lasttd nobr center">
154
+                    <a href="/search/test/?field=leechers&sorder=desc" rel="nofollow">leech</a>
155
+                </th>
156
+            </tr>
157
+            <tr class="even" id="torrent_test6478745">
158
+                <td>
159
+                    <div class="iaconbox center floatright">
160
+                        <a rel="6478745,0" class="icommentjs icon16" href="/test-t6478745.html#comment">
161
+                            <em style="font-size: 12px; margin: 0 4px 0 4px;" class="iconvalue">3</em>
162
+                            <i class="ka ka-comment"></i>
163
+                        </a>
164
+                        <a class="iverify icon16" href="/test-t6478745.html" title="Verified Torrent">
165
+                            <i class="ka ka16 ka-verify ka-green"></i>
166
+                        </a>
167
+                        <a href="#" onclick="_scq.push([]); return false;" class="partner1Button idownload icon16">
168
+                            <i class="ka ka16 ka-arrow-down partner1Button"></i>
169
+                        </a>
170
+                        <a title="Torrent magnet link"
171
+                            href="magnet:?xt=urn:btih:MAGNETURL&dn=test" class="imagnet icon16">
172
+                            <i class="ka ka16 ka-magnet"></i>
173
+                        </a>
174
+                        <a title="Download torrent file"
175
+                            href="http://torcache.net/torrent/53917.torrent?title=test" class="idownload icon16">
176
+                            <i class="ka ka16 ka-arrow-down"></i>
177
+                        </a>
178
+                    </div>
179
+                    <div class="torrentname">
180
+                    <a href="/test-t6478745.html" class="torType txtType"></a>
181
+                    <a href="/test-t6478745.html" class="normalgrey font12px plain bold"></a>
182
+                    <div class="markeredBlock torType txtType">
183
+                        <a href="/url.html" class="cellMainLink">
184
+                            <strong class="red">This should be the title</strong>
185
+                        </a>
186
+                        <span class="font11px lightgrey block">
187
+                            Posted by <i class="ka ka-verify" style="font-size: 16px;color:orange;"></i>
188
+                            <a class="plain" href="/user/riri/">riri</a> in
189
+                            <span id="cat_6478745">
190
+                                <strong><a href="/other/">Other</a> > <a href="/unsorted/">Unsorted</a></strong>
191
+                            </span>
192
+                        </span>
193
+                    </div>
194
+                </td>
195
+                <td class="nobr center">1 <span>KB</span></td>
196
+                <td class="center">4</td>
197
+                <td class="center">2&nbsp;years</td>
198
+                <td class="green center">10</td>
199
+                <td class="red lasttd center">1</td>
200
+            </tr>
201
+            <tr class="even" id="torrent_test6478745">
202
+                <td>
203
+                    <div class="iaconbox center floatright">
204
+                        <a rel="6478745,0" class="icommentjs icon16" href="/test-t6478745.html#comment">
205
+                            <em style="font-size: 12px; margin: 0 4px 0 4px;" class="iconvalue">3</em>
206
+                            <i class="ka ka-comment"></i>
207
+                        </a>
208
+                        <a class="iverify icon16" href="/test-t6478745.html" title="Verified Torrent">
209
+                            <i class="ka ka16 ka-verify ka-green"></i>
210
+                        </a>
211
+                        <a href="#" onclick="_scq.push([]); return false;" class="partner1Button idownload icon16">
212
+                            <i class="ka ka16 ka-arrow-down partner1Button"></i>
213
+                        </a>
214
+                        <a title="Torrent magnet link"
215
+                            href="magnet:?xt=urn:btih:MAGNETURL&dn=test" class="imagnet icon16">
216
+                            <i class="ka ka16 ka-magnet"></i>
217
+                        </a>
218
+                        <a title="Download torrent file"
219
+                            href="http://torcache.net/torrent/53917.torrent?title=test" class="idownload icon16">
220
+                            <i class="ka ka16 ka-arrow-down"></i>
221
+                        </a>
222
+                    </div>
223
+                    <div class="torrentname">
224
+                    <a href="/test-t6478745.html" class="torType txtType"></a>
225
+                    <a href="/test-t6478745.html" class="normalgrey font12px plain bold"></a>
226
+                    <div class="markeredBlock torType txtType">
227
+                        <a href="/url.html" class="cellMainLink">
228
+                            <strong class="red">This should be the title</strong>
229
+                        </a>
230
+                        <span class="font11px lightgrey block">
231
+                            Posted by <i class="ka ka-verify" style="font-size: 16px;color:orange;"></i>
232
+                            <a class="plain" href="/user/riri/">riri</a> in
233
+                            <span id="cat_6478745">
234
+                                <strong><a href="/other/">Other</a> > <a href="/unsorted/">Unsorted</a></strong>
235
+                            </span>
236
+                        </span>
237
+                    </div>
238
+                </td>
239
+                <td class="nobr center">1 <span>MB</span></td>
240
+                <td class="center">4</td>
241
+                <td class="center">2&nbsp;years</td>
242
+                <td class="green center">9</td>
243
+                <td class="red lasttd center">1</td>
244
+            </tr>
245
+            <tr class="even" id="torrent_test6478745">
246
+                <td>
247
+                    <div class="iaconbox center floatright">
248
+                        <a rel="6478745,0" class="icommentjs icon16" href="/test-t6478745.html#comment">
249
+                            <em style="font-size: 12px; margin: 0 4px 0 4px;" class="iconvalue">3</em>
250
+                            <i class="ka ka-comment"></i>
251
+                        </a>
252
+                        <a class="iverify icon16" href="/test-t6478745.html" title="Verified Torrent">
253
+                            <i class="ka ka16 ka-verify ka-green"></i>
254
+                        </a>
255
+                        <a href="#" onclick="_scq.push([]); return false;" class="partner1Button idownload icon16">
256
+                            <i class="ka ka16 ka-arrow-down partner1Button"></i>
257
+                        </a>
258
+                        <a title="Torrent magnet link"
259
+                            href="magnet:?xt=urn:btih:MAGNETURL&dn=test" class="imagnet icon16">
260
+                            <i class="ka ka16 ka-magnet"></i>
261
+                        </a>
262
+                        <a title="Download torrent file"
263
+                            href="http://torcache.net/torrent/53917.torrent?title=test" class="idownload icon16">
264
+                            <i class="ka ka16 ka-arrow-down"></i>
265
+                        </a>
266
+                    </div>
267
+                    <div class="torrentname">
268
+                    <a href="/test-t6478745.html" class="torType txtType"></a>
269
+                    <a href="/test-t6478745.html" class="normalgrey font12px plain bold"></a>
270
+                    <div class="markeredBlock torType txtType">
271
+                        <a href="/url.html" class="cellMainLink">
272
+                            <strong class="red">This should be the title</strong>
273
+                        </a>
274
+                        <span class="font11px lightgrey block">
275
+                            Posted by <i class="ka ka-verify" style="font-size: 16px;color:orange;"></i>
276
+                            <a class="plain" href="/user/riri/">riri</a> in
277
+                            <span id="cat_6478745">
278
+                                <strong><a href="/other/">Other</a> > <a href="/unsorted/">Unsorted</a></strong>
279
+                            </span>
280
+                        </span>
281
+                    </div>
282
+                </td>
283
+                <td class="nobr center">1 <span>GB</span></td>
284
+                <td class="center">4</td>
285
+                <td class="center">2&nbsp;years</td>
286
+                <td class="green center">8</td>
287
+                <td class="red lasttd center">1</td>
288
+            </tr>
289
+            <tr class="even" id="torrent_test6478745">
290
+                <td>
291
+                    <div class="iaconbox center floatright">
292
+                        <a rel="6478745,0" class="icommentjs icon16" href="/test-t6478745.html#comment">
293
+                            <em style="font-size: 12px; margin: 0 4px 0 4px;" class="iconvalue">3</em>
294
+                            <i class="ka ka-comment"></i>
295
+                        </a>
296
+                        <a class="iverify icon16" href="/test-t6478745.html" title="Verified Torrent">
297
+                            <i class="ka ka16 ka-verify ka-green"></i>
298
+                        </a>
299
+                        <a href="#" onclick="_scq.push([]); return false;" class="partner1Button idownload icon16">
300
+                            <i class="ka ka16 ka-arrow-down partner1Button"></i>
301
+                        </a>
302
+                        <a title="Torrent magnet link"
303
+                            href="magnet:?xt=urn:btih:MAGNETURL&dn=test" class="imagnet icon16">
304
+                            <i class="ka ka16 ka-magnet"></i>
305
+                        </a>
306
+                        <a title="Download torrent file"
307
+                            href="http://torcache.net/torrent/53917.torrent?title=test" class="idownload icon16">
308
+                            <i class="ka ka16 ka-arrow-down"></i>
309
+                        </a>
310
+                    </div>
311
+                    <div class="torrentname">
312
+                    <a href="/test-t6478745.html" class="torType txtType"></a>
313
+                    <a href="/test-t6478745.html" class="normalgrey font12px plain bold"></a>
314
+                    <div class="markeredBlock torType txtType">
315
+                        <a href="/url.html" class="cellMainLink">
316
+                            <strong class="red">This should be the title</strong>
317
+                        </a>
318
+                        <span class="font11px lightgrey block">
319
+                            Posted by <i class="ka ka-verify" style="font-size: 16px;color:orange;"></i>
320
+                            <a class="plain" href="/user/riri/">riri</a> in
321
+                            <span id="cat_6478745">
322
+                                <strong><a href="/other/">Other</a> > <a href="/unsorted/">Unsorted</a></strong>
323
+                            </span>
324
+                        </span>
325
+                    </div>
326
+                </td>
327
+                <td class="nobr center">1 <span>TB</span></td>
328
+                <td class="center">4</td>
329
+                <td class="center">2&nbsp;years</td>
330
+                <td class="green center">7</td>
331
+                <td class="red lasttd center">1</td>
332
+            </tr>
333
+            <tr class="even" id="torrent_test6478745">
334
+                <td>
335
+                    <div class="iaconbox center floatright">
336
+                        <a rel="6478745,0" class="icommentjs icon16" href="/test-t6478745.html#comment">
337
+                            <em style="font-size: 12px; margin: 0 4px 0 4px;" class="iconvalue">3</em>
338
+                            <i class="ka ka-comment"></i>
339
+                        </a>
340
+                        <a class="iverify icon16" href="/test-t6478745.html" title="Verified Torrent">
341
+                            <i class="ka ka16 ka-verify ka-green"></i>
342
+                        </a>
343
+                        <a href="#" onclick="_scq.push([]); return false;" class="partner1Button idownload icon16">
344
+                            <i class="ka ka16 ka-arrow-down partner1Button"></i>
345
+                        </a>
346
+                        <a title="Torrent magnet link"
347
+                            href="magnet:?xt=urn:btih:MAGNETURL&dn=test" class="imagnet icon16">
348
+                            <i class="ka ka16 ka-magnet"></i>
349
+                        </a>
350
+                        <a title="Download torrent file"
351
+                            href="http://torcache.net/torrent/53917.torrent?title=test" class="idownload icon16">
352
+                            <i class="ka ka16 ka-arrow-down"></i>
353
+                        </a>
354
+                    </div>
355
+                    <div class="torrentname">
356
+                    <a href="/test-t6478745.html" class="torType txtType"></a>
357
+                    <a href="/test-t6478745.html" class="normalgrey font12px plain bold"></a>
358
+                    <div class="markeredBlock torType txtType">
359
+                        <a href="/url.html" class="cellMainLink">
360
+                            <strong class="red">This should be the title</strong>
361
+                        </a>
362
+                        <span class="font11px lightgrey block">
363
+                            Posted by <i class="ka ka-verify" style="font-size: 16px;color:orange;"></i>
364
+                            <a class="plain" href="/user/riri/">riri</a> in
365
+                            <span id="cat_6478745">
366
+                                <strong><a href="/other/">Other</a> > <a href="/unsorted/">Unsorted</a></strong>
367
+                            </span>
368
+                        </span>
369
+                    </div>
370
+                </td>
371
+                <td class="nobr center">z <span>bytes</span></td>
372
+                <td class="center">r</td>
373
+                <td class="center">2&nbsp;years</td>
374
+                <td class="green center">a</td>
375
+                <td class="red lasttd center">t</td>
376
+            </tr>
377
+        </table>
378
+        """
379
+        response = mock.Mock(text=html)
380
+        results = kickass.response(response)
381
+        self.assertEqual(type(results), list)
382
+        self.assertEqual(len(results), 5)
383
+        self.assertEqual(results[0]['title'], 'This should be the title')
384
+        self.assertEqual(results[0]['url'], 'https://kickass.so/url.html')
385
+        self.assertEqual(results[0]['content'], 'Posted by riri in Other &gt; Unsorted')
386
+        self.assertEqual(results[0]['seed'], 10)
387
+        self.assertEqual(results[0]['leech'], 1)
388
+        self.assertEqual(results[0]['files'], 4)
389
+        self.assertEqual(results[0]['magnetlink'], 'magnet:?xt=urn:btih:MAGNETURL&dn=test')
390
+        self.assertEqual(results[0]['torrentfile'], 'http://torcache.net/torrent/53917.torrent?title=test')
391
+        self.assertEqual(results[0]['filesize'], 1024)
392
+        self.assertEqual(results[1]['filesize'], 1048576)
393
+        self.assertEqual(results[2]['filesize'], 1073741824)
394
+        self.assertEqual(results[3]['filesize'], 1099511627776)
395
+        self.assertEqual(results[4]['seed'], 0)
396
+        self.assertEqual(results[4]['leech'], 0)
397
+        self.assertEqual(results[4]['files'], None)
398
+        self.assertEqual(results[4]['filesize'], None)

+ 67
- 0
searx/tests/engines/test_mixcloud.py View File

@@ -0,0 +1,67 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import mixcloud
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestMixcloudEngine(SearxTestCase):
8
+
9
+    def test_request(self):
10
+        query = 'test_query'
11
+        dicto = defaultdict(dict)
12
+        dicto['pageno'] = 0
13
+        params = mixcloud.request(query, dicto)
14
+        self.assertTrue('url' in params)
15
+        self.assertTrue(query in params['url'])
16
+        self.assertTrue('mixcloud.com' in params['url'])
17
+
18
+    def test_response(self):
19
+        self.assertRaises(AttributeError, mixcloud.response, None)
20
+        self.assertRaises(AttributeError, mixcloud.response, [])
21
+        self.assertRaises(AttributeError, mixcloud.response, '')
22
+        self.assertRaises(AttributeError, mixcloud.response, '[]')
23
+
24
+        response = mock.Mock(text='{}')
25
+        self.assertEqual(mixcloud.response(response), [])
26
+
27
+        response = mock.Mock(text='{"data": []}')
28
+        self.assertEqual(mixcloud.response(response), [])
29
+
30
+        json = """
31
+        {"data":[
32
+            {
33
+            "user": {
34
+                "url": "http://www.mixcloud.com/user/",
35
+                "username": "user",
36
+                "name": "User",
37
+                "key": "/user/"
38
+            },
39
+            "key": "/user/this-is-the-url/",
40
+            "created_time": "2014-11-14T13:30:02Z",
41
+            "audio_length": 3728,
42
+            "slug": "this-is-the-url",
43
+            "name": "Title of track",
44
+            "url": "http://www.mixcloud.com/user/this-is-the-url/",
45
+            "updated_time": "2014-11-14T13:14:10Z"
46
+        }
47
+        ]}
48
+        """
49
+        response = mock.Mock(text=json)
50
+        results = mixcloud.response(response)
51
+        self.assertEqual(type(results), list)
52
+        self.assertEqual(len(results), 1)
53
+        self.assertEqual(results[0]['title'], 'Title of track')
54
+        self.assertEqual(results[0]['url'], 'http://www.mixcloud.com/user/this-is-the-url/')
55
+        self.assertEqual(results[0]['content'], 'User')
56
+        self.assertTrue('http://www.mixcloud.com/user/this-is-the-url/' in results[0]['embedded'])
57
+
58
+        json = """
59
+        {"toto":[
60
+            {"id":200,"name":"Artist Name",
61
+            "link":"http:\/\/www.mixcloud.com\/artist\/1217","type":"artist"}
62
+        ]}
63
+        """
64
+        response = mock.Mock(text=json)
65
+        results = mixcloud.response(response)
66
+        self.assertEqual(type(results), list)
67
+        self.assertEqual(len(results), 0)

+ 137
- 0
searx/tests/engines/test_piratebay.py View File

@@ -0,0 +1,137 @@
1
+# -*- coding: utf-8 -*-
2
+from collections import defaultdict
3
+import mock
4
+from searx.engines import piratebay
5
+from searx.testing import SearxTestCase
6
+
7
+
8
+class TestPiratebayEngine(SearxTestCase):
9
+
10
+    def test_request(self):
11
+        query = 'test_query'
12
+        dicto = defaultdict(dict)
13
+        dicto['pageno'] = 1
14
+        dicto['category'] = 'Toto'
15
+        params = piratebay.request(query, dicto)
16
+        self.assertIn('url', params)
17
+        self.assertIn(query, params['url'])
18
+        self.assertIn('piratebay.cr', params['url'])
19
+        self.assertIn('0', params['url'])
20
+
21
+        dicto['category'] = 'music'
22
+        params = piratebay.request(query, dicto)
23
+        self.assertIn('100', params['url'])
24
+
25
+    def test_response(self):
26
+        self.assertRaises(AttributeError, piratebay.response, None)
27
+        self.assertRaises(AttributeError, piratebay.response, [])
28
+        self.assertRaises(AttributeError, piratebay.response, '')
29
+        self.assertRaises(AttributeError, piratebay.response, '[]')
30
+
31
+        response = mock.Mock(text='<html></html>')
32
+        self.assertEqual(piratebay.response(response), [])
33
+
34
+        html = """
35
+        <table id="searchResult">
36
+            <tr>
37
+            </tr>
38
+            <tr>
39
+                <td class="vertTh">
40
+                    <center>
41
+                        <a href="#" title="More from this category">Anime</a><br/>
42
+                        (<a href="#" title="More from this category">Anime</a>)
43
+                    </center>
44
+                </td>
45
+                <td>
46
+                    <div class="detName">
47
+                        <a href="/this.is.the.link" class="detLink" title="Title">
48
+                            This is the title
49
+                        </a>
50
+                    </div>
51
+                    <a href="magnet:?xt=urn:btih:MAGNETLINK" title="Download this torrent using magnet">
52
+                        <img src="/static/img/icon-magnet.gif" alt="Magnet link"/>
53
+                    </a>
54
+                    <a href="http://torcache.net/torrent/TORRENTFILE.torrent" title="Download this torrent">
55
+                        <img src="/static/img/dl.gif" class="dl" alt="Download"/>
56
+                    </a>
57
+                    <a href="/user/HorribleSubs">
58
+                        <img src="/static/img/vip.gif" alt="VIP" title="VIP" style="width:11px;" border='0'/>
59
+                    </a>
60
+                    <img src="/static/img/11x11p.png"/>
61
+                    <font class="detDesc">
62
+                        This is the content <span>and should be</span> OK
63
+                    </font>
64
+                </td>
65
+                <td align="right">13</td>
66
+                <td align="right">334</td>
67
+            </tr>
68
+        </table>
69
+        """
70
+        response = mock.Mock(text=html)
71
+        results = piratebay.response(response)
72
+        self.assertEqual(type(results), list)
73
+        self.assertEqual(len(results), 1)
74
+        self.assertEqual(results[0]['title'], 'This is the title')
75
+        self.assertEqual(results[0]['url'], 'https://thepiratebay.cr/this.is.the.link')
76
+        self.assertEqual(results[0]['content'], 'This is the content and should be OK')
77
+        self.assertEqual(results[0]['seed'], 13)
78
+        self.assertEqual(results[0]['leech'], 334)
79
+        self.assertEqual(results[0]['magnetlink'], 'magnet:?xt=urn:btih:MAGNETLINK')
80
+        self.assertEqual(results[0]['torrentfile'], 'http://torcache.net/torrent/TORRENTFILE.torrent')
81
+
82
+        html = """
83
+        <table id="searchResult">
84
+            <tr>
85
+            </tr>
86
+            <tr>
87
+                <td class="vertTh">
88
+                    <center>
89
+                        <a href="#" title="More from this category">Anime</a><br/>
90
+                        (<a href="#" title="More from this category">Anime</a>)
91
+                    </center>
92
+                </td>
93
+                <td>
94
+                    <div class="detName">
95
+                        <a href="/this.is.the.link" class="detLink" title="Title">
96
+                            This is the title
97
+                        </a>
98
+                    </div>
99
+                    <a href="magnet:?xt=urn:btih:MAGNETLINK" title="Download this torrent using magnet">
100
+                        <img src="/static/img/icon-magnet.gif" alt="Magnet link"/>
101
+                    </a>
102
+                    <a href="http://torcache.net/torrent/TORRENTFILE.torrent" title="Download this torrent">
103
+                        <img src="/static/img/dl.gif" class="dl" alt="Download"/>
104
+                    </a>
105
+                    <a href="/user/HorribleSubs">
106
+                        <img src="/static/img/vip.gif" alt="VIP" title="VIP" style="width:11px;" border='0'/>
107
+                    </a>
108
+                    <img src="/static/img/11x11p.png"/>
109
+                    <font class="detDesc">
110
+                        This is the content <span>and should be</span> OK
111
+                    </font>
112
+                </td>
113
+                <td align="right">s</td>
114
+                <td align="right">d</td>
115
+            </tr>
116
+        </table>
117
+        """
118
+        response = mock.Mock(text=html)
119
+        results = piratebay.response(response)
120
+        self.assertEqual(type(results), list)
121
+        self.assertEqual(len(results), 1)
122
+        self.assertEqual(results[0]['title'], 'This is the title')
123
+        self.assertEqual(results[0]['url'], 'https://thepiratebay.cr/this.is.the.link')
124
+        self.assertEqual(results[0]['content'], 'This is the content and should be OK')
125
+        self.assertEqual(results[0]['seed'], 0)
126
+        self.assertEqual(results[0]['leech'], 0)
127
+        self.assertEqual(results[0]['magnetlink'], 'magnet:?xt=urn:btih:MAGNETLINK')
128
+        self.assertEqual(results[0]['torrentfile'], 'http://torcache.net/torrent/TORRENTFILE.torrent')
129
+
130
+        html = """
131
+        <table id="searchResult">
132
+        </table>
133
+        """
134
+        response = mock.Mock(text=html)
135
+        results = piratebay.response(response)
136
+        self.assertEqual(type(results), list)
137
+        self.assertEqual(len(results), 0)

+ 75
- 0
searx/tests/engines/test_searchcode_code.py View File

@@ -0,0 +1,75 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import searchcode_code
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestSearchcodeCodeEngine(SearxTestCase):
8
+
9
+    def test_request(self):
10
+        query = 'test_query'
11
+        dicto = defaultdict(dict)
12
+        dicto['pageno'] = 0
13
+        params = searchcode_code.request(query, dicto)
14
+        self.assertIn('url', params)
15
+        self.assertIn(query, params['url'])
16
+        self.assertIn('searchcode.com', params['url'])
17
+
18
+    def test_response(self):
19
+        self.assertRaises(AttributeError, searchcode_code.response, None)
20
+        self.assertRaises(AttributeError, searchcode_code.response, [])
21
+        self.assertRaises(AttributeError, searchcode_code.response, '')
22
+        self.assertRaises(AttributeError, searchcode_code.response, '[]')
23
+
24
+        response = mock.Mock(text='{}')
25
+        self.assertEqual(searchcode_code.response(response), [])
26
+
27
+        response = mock.Mock(text='{"data": []}')
28
+        self.assertEqual(searchcode_code.response(response), [])
29
+
30
+        json = """
31
+        {
32
+        "matchterm": "test",
33
+        "previouspage": null,
34
+        "searchterm": "test",
35
+        "query": "test",
36
+        "total": 1000,
37
+        "page": 0,
38
+        "nextpage": 1,
39
+        "results": [
40
+            {
41
+            "repo": "https://repo",
42
+            "linescount": 1044,
43
+            "location": "/tests",
44
+            "name": "Name",
45
+            "url": "https://url",
46
+            "md5hash": "ecac6e479edd2b9406c9e08603cec655",
47
+            "lines": {
48
+                "1": "// Test 011",
49
+                "2": "// Source: "
50
+            },
51
+            "id": 51223527,
52
+            "filename": "File.CPP"
53
+            }
54
+        ]
55
+        }
56
+        """
57
+        response = mock.Mock(text=json)
58
+        results = searchcode_code.response(response)
59
+        self.assertEqual(type(results), list)
60
+        self.assertEqual(len(results), 1)
61
+        self.assertEqual(results[0]['title'], 'Name - File.CPP')
62
+        self.assertEqual(results[0]['url'], 'https://url')
63
+        self.assertEqual(results[0]['repository'], 'https://repo')
64
+        self.assertEqual(results[0]['code_language'], 'cpp')
65
+
66
+        json = """
67
+        {"toto":[
68
+            {"id":200,"name":"Artist Name",
69
+            "link":"http:\/\/www.searchcode_code.com\/artist\/1217","type":"artist"}
70
+        ]}
71
+        """
72
+        response = mock.Mock(text=json)
73
+        results = searchcode_code.response(response)
74
+        self.assertEqual(type(results), list)
75
+        self.assertEqual(len(results), 0)

+ 73
- 0
searx/tests/engines/test_searchcode_doc.py View File

@@ -0,0 +1,73 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import searchcode_doc
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestSearchcodeDocEngine(SearxTestCase):
8
+
9
+    def test_request(self):
10
+        query = 'test_query'
11
+        dicto = defaultdict(dict)
12
+        dicto['pageno'] = 0
13
+        params = searchcode_doc.request(query, dicto)
14
+        self.assertIn('url', params)
15
+        self.assertIn(query, params['url'])
16
+        self.assertIn('searchcode.com', params['url'])
17
+
18
+    def test_response(self):
19
+        self.assertRaises(AttributeError, searchcode_doc.response, None)
20
+        self.assertRaises(AttributeError, searchcode_doc.response, [])
21
+        self.assertRaises(AttributeError, searchcode_doc.response, '')
22
+        self.assertRaises(AttributeError, searchcode_doc.response, '[]')
23
+
24
+        response = mock.Mock(text='{}')
25
+        self.assertEqual(searchcode_doc.response(response), [])
26
+
27
+        response = mock.Mock(text='{"data": []}')
28
+        self.assertEqual(searchcode_doc.response(response), [])
29
+
30
+        json = """
31
+        {
32
+        "matchterm": "test",
33
+        "previouspage": null,
34
+        "searchterm": "test",
35
+        "query": "test",
36
+        "total": 60,
37
+        "page": 0,
38
+        "nextpage": 1,
39
+        "results": [
40
+            {
41
+            "synopsis": "Synopsis",
42
+            "displayname": null,
43
+            "name": "test",
44
+            "url": "http://url",
45
+            "type": "Type",
46
+            "icon": null,
47
+            "namespace": "Namespace",
48
+            "description": "Description"
49
+            }
50
+        ]
51
+        }
52
+        """
53
+        response = mock.Mock(text=json)
54
+        results = searchcode_doc.response(response)
55
+        self.assertEqual(type(results), list)
56
+        self.assertEqual(len(results), 1)
57
+        self.assertEqual(results[0]['title'], '[Type] Namespace test')
58
+        self.assertEqual(results[0]['url'], 'http://url')
59
+        self.assertIn('Synopsis', results[0]['content'])
60
+        self.assertIn('Type', results[0]['content'])
61
+        self.assertIn('test', results[0]['content'])
62
+        self.assertIn('Description', results[0]['content'])
63
+
64
+        json = """
65
+        {"toto":[
66
+            {"id":200,"name":"Artist Name",
67
+            "link":"http:\/\/www.searchcode_doc.com\/artist\/1217","type":"artist"}
68
+        ]}
69
+        """
70
+        response = mock.Mock(text=json)
71
+        results = searchcode_doc.response(response)
72
+        self.assertEqual(type(results), list)
73
+        self.assertEqual(len(results), 0)

+ 192
- 0
searx/tests/engines/test_soundcloud.py View File

@@ -0,0 +1,192 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import soundcloud
4
+from searx.testing import SearxTestCase
5
+from urllib import quote_plus
6
+
7
+
8
+class TestSoundcloudEngine(SearxTestCase):
9
+
10
+    def test_request(self):
11
+        query = 'test_query'
12
+        dicto = defaultdict(dict)
13
+        dicto['pageno'] = 1
14
+        params = soundcloud.request(query, dicto)
15
+        self.assertIn('url', params)
16
+        self.assertIn(query, params['url'])
17
+        self.assertIn('soundcloud.com', params['url'])
18
+
19
+    def test_response(self):
20
+        self.assertRaises(AttributeError, soundcloud.response, None)
21
+        self.assertRaises(AttributeError, soundcloud.response, [])
22
+        self.assertRaises(AttributeError, soundcloud.response, '')
23
+        self.assertRaises(AttributeError, soundcloud.response, '[]')
24
+
25
+        response = mock.Mock(text='{}')
26
+        self.assertEqual(soundcloud.response(response), [])
27
+
28
+        response = mock.Mock(text='{"data": []}')
29
+        self.assertEqual(soundcloud.response(response), [])
30
+
31
+        json = """
32
+        {
33
+        "collection": [
34
+            {
35
+            "kind": "track",
36
+            "id": 159723640,
37
+            "created_at": "2014/07/22 00:51:21 +0000",
38
+            "user_id": 2976616,
39
+            "duration": 303780,
40
+            "commentable": true,
41
+            "state": "finished",
42
+            "original_content_size": 13236349,
43
+            "last_modified": "2015/01/31 15:14:50 +0000",
44
+            "sharing": "public",
45
+            "tag_list": "seekae flume",
46
+            "permalink": "seekae-test-recognise-flume-re-work",
47
+            "streamable": true,
48
+            "embeddable_by": "all",
49
+            "downloadable": true,
50
+            "purchase_url": "http://www.facebook.com/seekaemusic",
51
+            "label_id": null,
52
+            "purchase_title": "Seekae",
53
+            "genre": "freedownload",
54
+            "title": "This is the title",
55
+            "description": "This is the content",
56
+            "label_name": "Future Classic",
57
+            "release": "",
58
+            "track_type": "remix",
59
+            "key_signature": "",
60
+            "isrc": "",
61
+            "video_url": null,
62
+            "bpm": null,
63
+            "release_year": 2014,
64
+            "release_month": 7,
65
+            "release_day": 22,
66
+            "original_format": "mp3",
67
+            "license": "all-rights-reserved",
68
+            "uri": "https://api.soundcloud.com/tracks/159723640",
69
+            "user": {
70
+                "id": 2976616,
71
+                "kind": "user",
72
+                "permalink": "flume",
73
+                "username": "Flume",
74
+                "last_modified": "2014/11/24 19:21:29 +0000",
75
+                "uri": "https://api.soundcloud.com/users/2976616",
76
+                "permalink_url": "http://soundcloud.com/flume",
77
+                "avatar_url": "https://i1.sndcdn.com/avatars-000044475439-4zi7ii-large.jpg"
78
+            },
79
+            "permalink_url": "http://soundcloud.com/this.is.the.url",
80
+            "artwork_url": "https://i1.sndcdn.com/artworks-000085857162-xdxy5c-large.jpg",
81
+            "waveform_url": "https://w1.sndcdn.com/DWrL1lAN8BkP_m.png",
82
+            "stream_url": "https://api.soundcloud.com/tracks/159723640/stream",
83
+            "download_url": "https://api.soundcloud.com/tracks/159723640/download",
84
+            "playback_count": 2190687,
85
+            "download_count": 54856,
86
+            "favoritings_count": 49061,
87
+            "comment_count": 826,
88
+            "likes_count": 49061,
89
+            "reposts_count": 15910,
90
+            "attachments_uri": "https://api.soundcloud.com/tracks/159723640/attachments",
91
+            "policy": "ALLOW"
92
+            }
93
+        ],
94
+        "total_results": 375750,
95
+        "next_href": "https://api.soundcloud.com/search?&q=test",
96
+        "tx_id": ""
97
+        }
98
+        """
99
+        response = mock.Mock(text=json)
100
+        results = soundcloud.response(response)
101
+        self.assertEqual(type(results), list)
102
+        self.assertEqual(len(results), 1)
103
+        self.assertEqual(results[0]['title'], 'This is the title')
104
+        self.assertEqual(results[0]['url'], 'http://soundcloud.com/this.is.the.url')
105
+        self.assertEqual(results[0]['content'], 'This is the content')
106
+        self.assertIn(quote_plus('https://api.soundcloud.com/tracks/159723640'), results[0]['embedded'])
107
+
108
+        json = """
109
+        {
110
+        "collection": [
111
+            {
112
+            "kind": "user",
113
+            "id": 159723640,
114
+            "created_at": "2014/07/22 00:51:21 +0000",
115
+            "user_id": 2976616,
116
+            "duration": 303780,
117
+            "commentable": true,
118
+            "state": "finished",
119
+            "original_content_size": 13236349,
120
+            "last_modified": "2015/01/31 15:14:50 +0000",
121
+            "sharing": "public",
122
+            "tag_list": "seekae flume",
123
+            "permalink": "seekae-test-recognise-flume-re-work",
124
+            "streamable": true,
125
+            "embeddable_by": "all",
126
+            "downloadable": true,
127
+            "purchase_url": "http://www.facebook.com/seekaemusic",
128
+            "label_id": null,
129
+            "purchase_title": "Seekae",
130
+            "genre": "freedownload",
131
+            "title": "This is the title",
132
+            "description": "This is the content",
133
+            "label_name": "Future Classic",
134
+            "release": "",
135
+            "track_type": "remix",
136
+            "key_signature": "",
137
+            "isrc": "",
138
+            "video_url": null,
139
+            "bpm": null,
140
+            "release_year": 2014,
141
+            "release_month": 7,
142
+            "release_day": 22,
143
+            "original_format": "mp3",
144
+            "license": "all-rights-reserved",
145
+            "uri": "https://api.soundcloud.com/tracks/159723640",
146
+            "user": {
147
+                "id": 2976616,
148
+                "kind": "user",
149
+                "permalink": "flume",
150
+                "username": "Flume",
151
+                "last_modified": "2014/11/24 19:21:29 +0000",
152
+                "uri": "https://api.soundcloud.com/users/2976616",
153
+                "permalink_url": "http://soundcloud.com/flume",
154
+                "avatar_url": "https://i1.sndcdn.com/avatars-000044475439-4zi7ii-large.jpg"
155
+            },
156
+            "permalink_url": "http://soundcloud.com/this.is.the.url",
157
+            "artwork_url": "https://i1.sndcdn.com/artworks-000085857162-xdxy5c-large.jpg",
158
+            "waveform_url": "https://w1.sndcdn.com/DWrL1lAN8BkP_m.png",
159
+            "stream_url": "https://api.soundcloud.com/tracks/159723640/stream",
160
+            "download_url": "https://api.soundcloud.com/tracks/159723640/download",
161
+            "playback_count": 2190687,
162
+            "download_count": 54856,
163
+            "favoritings_count": 49061,
164
+            "comment_count": 826,
165
+            "likes_count": 49061,
166
+            "reposts_count": 15910,
167
+            "attachments_uri": "https://api.soundcloud.com/tracks/159723640/attachments",
168
+            "policy": "ALLOW"
169
+            }
170
+        ],
171
+        "total_results": 375750,
172
+        "next_href": "https://api.soundcloud.com/search?&q=test",
173
+        "tx_id": ""
174
+        }
175
+        """
176
+        response = mock.Mock(text=json)
177
+        results = soundcloud.response(response)
178
+        self.assertEqual(type(results), list)
179
+        self.assertEqual(len(results), 0)
180
+
181
+        json = """
182
+        {
183
+        "collection": [],
184
+        "total_results": 375750,
185
+        "next_href": "https://api.soundcloud.com/search?&q=test",
186
+        "tx_id": ""
187
+        }
188
+        """
189
+        response = mock.Mock(text=json)
190
+        results = soundcloud.response(response)
191
+        self.assertEqual(type(results), list)
192
+        self.assertEqual(len(results), 0)

+ 106
- 0
searx/tests/engines/test_stackoverflow.py View File

@@ -0,0 +1,106 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import stackoverflow
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestStackoverflowEngine(SearxTestCase):
8
+
9
+    def test_request(self):
10
+        query = 'test_query'
11
+        dicto = defaultdict(dict)
12
+        dicto['pageno'] = 0
13
+        params = stackoverflow.request(query, dicto)
14
+        self.assertTrue('url' in params)
15
+        self.assertTrue(query in params['url'])
16
+        self.assertTrue('stackoverflow.com' in params['url'])
17
+
18
+    def test_response(self):
19
+        self.assertRaises(AttributeError, stackoverflow.response, None)
20
+        self.assertRaises(AttributeError, stackoverflow.response, [])
21
+        self.assertRaises(AttributeError, stackoverflow.response, '')
22
+        self.assertRaises(AttributeError, stackoverflow.response, '[]')
23
+
24
+        response = mock.Mock(text='<html></html>')
25
+        self.assertEqual(stackoverflow.response(response), [])
26
+
27
+        html = """
28
+        <div class="question-summary search-result" id="answer-id-1783426">
29
+            <div class="statscontainer">
30
+                <div class="statsarrow"></div>
31
+                <div class="stats">
32
+                    <div class="vote">
33
+                        <div class="votes answered">
34
+                            <span class="vote-count-post "><strong>2583</strong></span>
35
+                            <div class="viewcount">votes</div>
36
+                        </div>
37
+                    </div>
38
+                </div>
39
+            </div>
40
+            <div class="summary">
41
+                <div class="result-link">
42
+                    <span>
43
+                        <a href="/questions/this.is.the.url"
44
+                            data-searchsession="/questions"
45
+                            title="Checkout remote Git branch">
46
+                            This is the title
47
+                        </a>
48
+                    </span>
49
+                </div>
50
+                <div class="excerpt">
51
+                    This is the content
52
+                </div>
53
+                <div class="tags user-tags t-git t-git-checkout t-remote-branch">
54
+                </div>
55
+                <div class="started fr">
56
+                    answered <span title="2009-11-23 14:26:08Z" class="relativetime">nov 23 '09</span> by
57
+                    <a href="/users/214090/hallski">hallski</a>
58
+                </div>
59
+            </div>
60
+        </div>
61
+        """
62
+        response = mock.Mock(text=html)
63
+        results = stackoverflow.response(response)
64
+        self.assertEqual(type(results), list)
65
+        self.assertEqual(len(results), 1)
66
+        self.assertEqual(results[0]['title'], 'This is the title')
67
+        self.assertEqual(results[0]['url'], 'http://stackoverflow.com/questions/this.is.the.url')
68
+        self.assertEqual(results[0]['content'], 'This is the content')
69
+
70
+        html = """
71
+        <div class="statscontainer">
72
+            <div class="statsarrow"></div>
73
+            <div class="stats">
74
+                <div class="vote">
75
+                    <div class="votes answered">
76
+                        <span class="vote-count-post "><strong>2583</strong></span>
77
+                        <div class="viewcount">votes</div>
78
+                    </div>
79
+                </div>
80
+            </div>
81
+        </div>
82
+        <div class="summary">
83
+            <div class="result-link">
84
+                <span>
85
+                    <a href="/questions/this.is.the.url"
86
+                        data-searchsession="/questions"
87
+                        title="Checkout remote Git branch">
88
+                        This is the title
89
+                    </a>
90
+                </span>
91
+            </div>
92
+            <div class="excerpt">
93
+                This is the content
94
+            </div>
95
+            <div class="tags user-tags t-git t-git-checkout t-remote-branch">
96
+            </div>
97
+            <div class="started fr">
98
+                answered <span title="2009-11-23 14:26:08Z" class="relativetime">nov 23 '09</span> by
99
+                <a href="/users/214090/hallski">hallski</a>
100
+            </div>
101
+        </div>
102
+        """
103
+        response = mock.Mock(text=html)
104
+        results = stackoverflow.response(response)
105
+        self.assertEqual(type(results), list)
106
+        self.assertEqual(len(results), 0)

+ 84
- 0
searx/tests/engines/test_vimeo.py View File

@@ -0,0 +1,84 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import vimeo
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestVimeoEngine(SearxTestCase):
8
+
9
+    def test_request(self):
10
+        query = 'test_query'
11
+        dicto = defaultdict(dict)
12
+        dicto['pageno'] = 0
13
+        params = vimeo.request(query, dicto)
14
+        self.assertTrue('url' in params)
15
+        self.assertTrue(query in params['url'])
16
+        self.assertTrue('vimeo.com' in params['url'])
17
+
18
+    def test_response(self):
19
+        self.assertRaises(AttributeError, vimeo.response, None)
20
+        self.assertRaises(AttributeError, vimeo.response, [])
21
+        self.assertRaises(AttributeError, vimeo.response, '')
22
+        self.assertRaises(AttributeError, vimeo.response, '[]')
23
+
24
+        response = mock.Mock(text='<html></html>')
25
+        self.assertEqual(vimeo.response(response), [])
26
+
27
+        html = """
28
+        <div id="browse_content" class="" data-search-id="696d5f8366914ec4ffec33cf7652de384976d4f4">
29
+            <ol class="js-browse_list clearfix browse browse_videos browse_videos_thumbnails kane"
30
+                data-stream="c2VhcmNoOjo6ZGVzYzp7InF1ZXJ5IjoidGVzdCJ9">
31
+                <li id="clip_100785455" data-start-page="/search/page:1/sort:relevant/" data-position="1">
32
+                    <a href="/videoid" title="Futurama 3d (test shot)">
33
+                        <img src="http://image.url.webp"
34
+                            srcset="http://i.vimeocdn.com/video/482375085_590x332.webp 2x" alt=""
35
+                            class="thumbnail thumbnail_lg_wide">
36
+                        <div class="data">
37
+                            <p class="title">
38
+                                This is the title
39
+                            </p>
40
+                            <p class="meta">
41
+                                <time datetime="2014-07-15T04:16:27-04:00"
42
+                                    title="mardi 15 juillet 2014 04:16">Il y a 6 mois</time>
43
+                            </p>
44
+                        </div>
45
+                    </a>
46
+                </li>
47
+            </ol>
48
+        </div>
49
+        """
50
+        response = mock.Mock(text=html)
51
+        results = vimeo.response(response)
52
+        self.assertEqual(type(results), list)
53
+        self.assertEqual(len(results), 1)
54
+        self.assertEqual(results[0]['title'], 'This is the title')
55
+        self.assertEqual(results[0]['url'], 'http://vimeo.com/videoid')
56
+        self.assertEqual(results[0]['content'], '')
57
+        self.assertEqual(results[0]['thumbnail'], 'http://image.url.webp')
58
+        self.assertIn('/videoid', results[0]['embedded'])
59
+
60
+        html = """
61
+        <ol class="js-browse_list clearfix browse browse_videos browse_videos_thumbnails kane"
62
+            data-stream="c2VhcmNoOjo6ZGVzYzp7InF1ZXJ5IjoidGVzdCJ9">
63
+            <li id="clip_100785455" data-start-page="/search/page:1/sort:relevant/" data-position="1">
64
+                <a href="/videoid" title="Futurama 3d (test shot)">
65
+                    <img src="http://image.url.webp"
66
+                        srcset="http://i.vimeocdn.com/video/482375085_590x332.webp 2x" alt=""
67
+                        class="thumbnail thumbnail_lg_wide">
68
+                    <div class="data">
69
+                        <p class="title">
70
+                            This is the title
71
+                        </p>
72
+                        <p class="meta">
73
+                            <time datetime="2014-07-15T04:16:27-04:00"
74
+                                title="mardi 15 juillet 2014 04:16">Il y a 6 mois</time>
75
+                        </p>
76
+                    </div>
77
+                </a>
78
+            </li>
79
+        </ol>
80
+        """
81
+        response = mock.Mock(text=html)
82
+        results = vimeo.response(response)
83
+        self.assertEqual(type(results), list)
84
+        self.assertEqual(len(results), 0)

+ 83
- 0
searx/tests/engines/test_www500px.py View File

@@ -0,0 +1,83 @@
1
+# -*- coding: utf-8 -*-
2
+from collections import defaultdict
3
+import mock
4
+from searx.engines import www500px
5
+from searx.testing import SearxTestCase
6
+
7
+
8
+class TestWww500pxImagesEngine(SearxTestCase):
9
+
10
+    def test_request(self):
11
+        query = 'test_query'
12
+        dicto = defaultdict(dict)
13
+        dicto['pageno'] = 1
14
+        params = www500px.request(query, dicto)
15
+        self.assertTrue('url' in params)
16
+        self.assertTrue(query in params['url'])
17
+        self.assertTrue('500px.com' in params['url'])
18
+
19
+    def test_response(self):
20
+        self.assertRaises(AttributeError, www500px.response, None)
21
+        self.assertRaises(AttributeError, www500px.response, [])
22
+        self.assertRaises(AttributeError, www500px.response, '')
23
+        self.assertRaises(AttributeError, www500px.response, '[]')
24
+
25
+        response = mock.Mock(text='<html></html>')
26
+        self.assertEqual(www500px.response(response), [])
27
+
28
+        html = """
29
+        <div class="photo">
30
+            <a href="/this.should.be.the.url" data-ga-category="Photo Thumbnail" data-ga-action="Title">
31
+                <img src="https://image.url/3.jpg?v=0" />
32
+            </a>
33
+            <div class="details">
34
+                <div class="inside">
35
+                    <div class="title">
36
+                        <a href="/photo/64312705/branch-out-by-oliver-turpin?feature=">
37
+                            This is the title
38
+                        </a>
39
+                    </div>
40
+                    <div class="info">
41
+                        <a href="/ChronicleUK" data-ga-action="Image" data-ga-category="Photo Thumbnail">
42
+                            This is the content
43
+                        </a>
44
+                    </div>
45
+                    <div class="rating">44.8</div>
46
+                </div>
47
+            </div>
48
+        </div>
49
+        """
50
+        response = mock.Mock(text=html)
51
+        results = www500px.response(response)
52
+        self.assertEqual(type(results), list)
53
+        self.assertEqual(len(results), 1)
54
+        self.assertEqual(results[0]['title'], 'This is the title')
55
+        self.assertEqual(results[0]['url'], 'https://500px.com/this.should.be.the.url')
56
+        self.assertEqual(results[0]['content'], 'This is the content')
57
+        self.assertEqual(results[0]['thumbnail_src'], 'https://image.url/3.jpg?v=0')
58
+        self.assertEqual(results[0]['img_src'], 'https://image.url/2048.jpg')
59
+
60
+        html = """
61
+        <a href="/this.should.be.the.url" data-ga-category="Photo Thumbnail" data-ga-action="Title">
62
+            <img src="https://image.url/3.jpg?v=0" />
63
+        </a>
64
+        <div class="details">
65
+            <div class="inside">
66
+                <div class="title">
67
+                    <a href="/photo/64312705/branch-out-by-oliver-turpin?feature=">
68
+                        This is the title
69
+                    </a>
70
+                </div>
71
+                <div class="info">
72
+                    <a href="/ChronicleUK" data-ga-action="Image" data-ga-category="Photo Thumbnail">
73
+                        Oliver Turpin
74
+                    </a>
75
+                </div>
76
+                <div class="rating">44.8</div>
77
+            </div>
78
+        </div>
79
+        """
80
+        response = mock.Mock(text=html)
81
+        results = www500px.response(response)
82
+        self.assertEqual(type(results), list)
83
+        self.assertEqual(len(results), 0)

+ 204
- 0
searx/tests/engines/test_youtube.py View File

@@ -0,0 +1,204 @@
1
+from collections import defaultdict
2
+import mock
3
+from searx.engines import youtube
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestYoutubeEngine(SearxTestCase):
8
+
9
+    def test_request(self):
10
+        query = 'test_query'
11
+        dicto = defaultdict(dict)
12
+        dicto['pageno'] = 0
13
+        dicto['language'] = 'fr_FR'
14
+        params = youtube.request(query, dicto)
15
+        self.assertTrue('url' in params)
16
+        self.assertTrue(query in params['url'])
17
+        self.assertTrue('youtube.com' in params['url'])
18
+        self.assertTrue('fr' in params['url'])
19
+
20
+        dicto['language'] = 'all'
21
+        params = youtube.request(query, dicto)
22
+        self.assertFalse('fr' in params['url'])
23
+
24
+    def test_response(self):
25
+        self.assertRaises(AttributeError, youtube.response, None)
26
+        self.assertRaises(AttributeError, youtube.response, [])
27
+        self.assertRaises(AttributeError, youtube.response, '')
28
+        self.assertRaises(AttributeError, youtube.response, '[]')
29
+
30
+        response = mock.Mock(text='{}')
31
+        self.assertEqual(youtube.response(response), [])
32
+
33
+        response = mock.Mock(text='{"data": []}')
34
+        self.assertEqual(youtube.response(response), [])
35
+
36
+        json = """
37
+        {"feed":{"entry":[{
38
+            "id":{"$t":"http://gdata.youtube.com/feeds/api/videos/DIVZCPfAOeM"},
39
+            "published":{"$t":"2015-01-23T21:25:00.000Z"},
40
+            "updated":{"$t":"2015-01-26T14:38:15.000Z"},
41
+            "title":{"$t":"Title",
42
+                "type":"text"},"content":{"$t":"Description","type":"text"},
43
+            "link":[{"rel":"alternate","type":"text/html",
44
+                "href":"https://www.youtube.com/watch?v=DIVZCPfAOeM&feature=youtube_gdata"},
45
+                {"rel":"http://gdata.youtube.com/schemas/2007#video.related",
46
+                "type":"application/atom+xml",
47
+                "href":"https://gdata.youtube.com/feeds/api/videos/DIVZCPfAOeM/related"},
48
+                {"rel":"http://gdata.youtube.com/schemas/2007#mobile","type":"text/html",
49
+                "href":"https://m.youtube.com/details?v=DIVZCPfAOeM"},
50
+                {"rel":"self","type":"application/atom+xml",
51
+                "href":"https://gdata.youtube.com/feeds/api/videos/DIVZCPfAOeM"}],
52
+            "author":[{"name":{"$t":"Cauet"},
53
+                "uri":{"$t":"https://gdata.youtube.com/feeds/api/users/cauetofficiel"} }],
54
+            "gd$comments":{"gd$feedLink":{"rel":"http://gdata.youtube.com/schemas/2007#comments",
55
+                "href":"https://gdata.youtube.com/feeds/api/videos/DIVZCPfAOeM/comments",
56
+                "countHint":8} },
57
+            "media$group":{"media$category":[{"$t":"Comedy","label":"Comedy",
58
+                "scheme":"http://gdata.youtube.com/schemas/2007/categories.cat"}],
59
+            "media$content":[{"url":"https://www.youtube.com/v/DIVZCPfAOeM?version=3&f=videos&app=youtube_gdata",
60
+                "type":"application/x-shockwave-flash","medium":"video",
61
+                "isDefault":"true","expression":"full","duration":354,"yt$format":5},
62
+    {"url":"rtsp://r1---sn-cg07luel.c.youtube.com/CiILENy73wIaGQnjOcD3CFmFDBMYDSANFEgGUgZ2aWRlb3MM/0/0/0/video.3gp",
63
+                "type":"video/3gpp","medium":"video","expression":"full","duration":354,
64
+                "yt$format":1},
65
+    {"url":"rtsp://r1---sn-cg07luel.c.youtube.com/CiILENy73wIaGQnjOcD3CFmFDBMYESARFEgGUgZ2aWRlb3MM/0/0/0/video.3gp",
66
+                "type":"video/3gpp","medium":"video","expression":"full","duration":354,"yt$format":6}],
67
+            "media$description":{"$t":"Desc","type":"plain"},
68
+            "media$keywords":{},
69
+            "media$player":[{"url":"https://www.youtube.com/watch?v=DIVZCPfAOeM&feature=youtube_gdata_player"}],
70
+            "media$thumbnail":[{"url":"https://i.ytimg.com/vi/DIVZCPfAOeM/0.jpg",
71
+                    "height":360,"width":480,"time":"00:02:57"},
72
+                {"url":"https://i.ytimg.com/vi/DIVZCPfAOeM/1.jpg","height":90,"width":120,"time":"00:01:28.500"},
73
+                {"url":"https://i.ytimg.com/vi/DIVZCPfAOeM/2.jpg","height":90,"width":120,"time":"00:02:57"},
74
+                {"url":"https://i.ytimg.com/vi/DIVZCPfAOeM/3.jpg","height":90,"width":120,"time":"00:04:25.500"}],
75
+            "media$title":{"$t":"Title","type":"plain"},
76
+            "yt$duration":{"seconds":"354"} },
77
+            "gd$rating":{"average":4.932159,"max":5,"min":1,"numRaters":1533,
78
+                "rel":"http://schemas.google.com/g/2005#overall"},
79
+            "yt$statistics":{"favoriteCount":"0","viewCount":"92464"} }
80
+            ]
81
+        }
82
+        }
83
+        """
84
+        response = mock.Mock(text=json)
85
+        results = youtube.response(response)
86
+        self.assertEqual(type(results), list)
87
+        self.assertEqual(len(results), 1)
88
+        self.assertEqual(results[0]['title'], 'Title')
89
+        self.assertEqual(results[0]['url'], 'https://www.youtube.com/watch?v=DIVZCPfAOeM')
90
+        self.assertEqual(results[0]['content'], 'Description')
91
+        self.assertEqual(results[0]['thumbnail'], 'https://i.ytimg.com/vi/DIVZCPfAOeM/0.jpg')
92
+        self.assertTrue('DIVZCPfAOeM' in results[0]['embedded'])
93
+
94
+        json = """
95
+        {"feed":{"entry":[{
96
+            "id":{"$t":"http://gdata.youtube.com/feeds/api/videos/DIVZCPfAOeM"},
97
+            "published":{"$t":"2015-01-23T21:25:00.000Z"},
98
+            "updated":{"$t":"2015-01-26T14:38:15.000Z"},
99
+            "title":{"$t":"Title",
100
+                "type":"text"},"content":{"$t":"Description","type":"text"},
101
+            "link":[{"rel":"http://gdata.youtube.com/schemas/2007#video.related",
102
+                "type":"application/atom+xml",
103
+                "href":"https://gdata.youtube.com/feeds/api/videos/DIVZCPfAOeM/related"},
104
+                {"rel":"self","type":"application/atom+xml",
105
+                "href":"https://gdata.youtube.com/feeds/api/videos/DIVZCPfAOeM"}],
106
+            "author":[{"name":{"$t":"Cauet"},
107
+                "uri":{"$t":"https://gdata.youtube.com/feeds/api/users/cauetofficiel"} }],
108
+            "gd$comments":{"gd$feedLink":{"rel":"http://gdata.youtube.com/schemas/2007#comments",
109
+                "href":"https://gdata.youtube.com/feeds/api/videos/DIVZCPfAOeM/comments",
110
+                "countHint":8} },
111
+            "media$group":{"media$category":[{"$t":"Comedy","label":"Comedy",
112
+                "scheme":"http://gdata.youtube.com/schemas/2007/categories.cat"}],
113
+            "media$content":[{"url":"https://www.youtube.com/v/DIVZCPfAOeM?version=3&f=videos&app=youtube_gdata",
114
+                "type":"application/x-shockwave-flash","medium":"video",
115
+                "isDefault":"true","expression":"full","duration":354,"yt$format":5},
116
+    {"url":"rtsp://r1---sn-cg07luel.c.youtube.com/CiILENy73wIaGQnjOcD3CFmFDBMYDSANFEgGUgZ2aWRlb3MM/0/0/0/video.3gp",
117
+                "type":"video/3gpp","medium":"video","expression":"full","duration":354,
118
+                "yt$format":1},
119
+    {"url":"rtsp://r1---sn-cg07luel.c.youtube.com/CiILENy73wIaGQnjOcD3CFmFDBMYESARFEgGUgZ2aWRlb3MM/0/0/0/video.3gp",
120
+                "type":"video/3gpp","medium":"video","expression":"full","duration":354,"yt$format":6}],
121
+            "media$description":{"$t":"Desc","type":"plain"},
122
+            "media$keywords":{},
123
+            "media$player":[{"url":"https://www.youtube.com/watch?v=DIVZCPfAOeM&feature=youtube_gdata_player"}],
124
+            "media$thumbnail":[{"url":"https://i.ytimg.com/vi/DIVZCPfAOeM/0.jpg",
125
+                    "height":360,"width":480,"time":"00:02:57"},
126
+                {"url":"https://i.ytimg.com/vi/DIVZCPfAOeM/1.jpg","height":90,"width":120,"time":"00:01:28.500"},
127
+                {"url":"https://i.ytimg.com/vi/DIVZCPfAOeM/2.jpg","height":90,"width":120,"time":"00:02:57"},
128
+                {"url":"https://i.ytimg.com/vi/DIVZCPfAOeM/3.jpg","height":90,"width":120,"time":"00:04:25.500"}],
129
+            "media$title":{"$t":"Title","type":"plain"},
130
+            "yt$duration":{"seconds":"354"} },
131
+            "gd$rating":{"average":4.932159,"max":5,"min":1,"numRaters":1533,
132
+                "rel":"http://schemas.google.com/g/2005#overall"},
133
+            "yt$statistics":{"favoriteCount":"0","viewCount":"92464"} }
134
+            ]
135
+        }
136
+        }
137
+        """
138
+        response = mock.Mock(text=json)
139
+        results = youtube.response(response)
140
+        self.assertEqual(type(results), list)
141
+        self.assertEqual(len(results), 0)
142
+
143
+        json = """
144
+        {"feed":{"entry":[{
145
+            "id":{"$t":"http://gdata.youtube.com/feeds/api/videos/DIVZCPfAOeM"},
146
+            "published":{"$t":"2015-01-23T21:25:00.000Z"},
147
+            "updated":{"$t":"2015-01-26T14:38:15.000Z"},
148
+            "title":{"$t":"Title",
149
+                "type":"text"},"content":{"$t":"Description","type":"text"},
150
+            "link":[{"rel":"alternate","type":"text/html",
151
+                "href":"https://www.youtube.com/watch?v=DIVZCPfAOeM"},
152
+                {"rel":"http://gdata.youtube.com/schemas/2007#video.related",
153
+                "type":"application/atom+xml",
154
+                "href":"https://gdata.youtube.com/feeds/api/videos/DIVZCPfAOeM/related"},
155
+                {"rel":"http://gdata.youtube.com/schemas/2007#mobile","type":"text/html",
156
+                "href":"https://m.youtube.com/details?v=DIVZCPfAOeM"},
157
+                {"rel":"self","type":"application/atom+xml",
158
+                "href":"https://gdata.youtube.com/feeds/api/videos/DIVZCPfAOeM"}],
159
+            "author":[{"name":{"$t":"Cauet"},
160
+                "uri":{"$t":"https://gdata.youtube.com/feeds/api/users/cauetofficiel"} }],
161
+            "gd$comments":{"gd$feedLink":{"rel":"http://gdata.youtube.com/schemas/2007#comments",
162
+                "href":"https://gdata.youtube.com/feeds/api/videos/DIVZCPfAOeM/comments",
163
+                "countHint":8} },
164
+            "media$group":{"media$category":[{"$t":"Comedy","label":"Comedy",
165
+                "scheme":"http://gdata.youtube.com/schemas/2007/categories.cat"}],
166
+            "media$content":[{"url":"https://www.youtube.com/v/DIVZCPfAOeM?version=3&f=videos&app=youtube_gdata",
167
+                "type":"application/x-shockwave-flash","medium":"video",
168
+                "isDefault":"true","expression":"full","duration":354,"yt$format":5},
169
+    {"url":"rtsp://r1---sn-cg07luel.c.youtube.com/CiILENy73wIaGQnjOcD3CFmFDBMYDSANFEgGUgZ2aWRlb3MM/0/0/0/video.3gp",
170
+                "type":"video/3gpp","medium":"video","expression":"full","duration":354,
171
+                "yt$format":1},
172
+    {"url":"rtsp://r1---sn-cg07luel.c.youtube.com/CiILENy73wIaGQnjOcD3CFmFDBMYESARFEgGUgZ2aWRlb3MM/0/0/0/video.3gp",
173
+                "type":"video/3gpp","medium":"video","expression":"full","duration":354,"yt$format":6}],
174
+            "media$description":{"$t":"Desc","type":"plain"},
175
+            "media$keywords":{},
176
+            "media$player":[{"url":"https://www.youtube.com/watch?v=DIVZCPfAOeM&feature=youtube_gdata_player"}],
177
+            "media$title":{"$t":"Title","type":"plain"},
178
+            "yt$duration":{"seconds":"354"} },
179
+            "gd$rating":{"average":4.932159,"max":5,"min":1,"numRaters":1533,
180
+                "rel":"http://schemas.google.com/g/2005#overall"},
181
+            "yt$statistics":{"favoriteCount":"0","viewCount":"92464"} }
182
+            ]
183
+        }
184
+        }
185
+        """
186
+        response = mock.Mock(text=json)
187
+        results = youtube.response(response)
188
+        self.assertEqual(type(results), list)
189
+        self.assertEqual(len(results), 1)
190
+        self.assertEqual(results[0]['title'], 'Title')
191
+        self.assertEqual(results[0]['url'], 'https://www.youtube.com/watch?v=DIVZCPfAOeM')
192
+        self.assertEqual(results[0]['content'], 'Description')
193
+        self.assertEqual(results[0]['thumbnail'], '')
194
+        self.assertTrue('DIVZCPfAOeM' in results[0]['embedded'])
195
+
196
+        json = """
197
+        {"toto":{"entry":[]
198
+        }
199
+        }
200
+        """
201
+        response = mock.Mock(text=json)
202
+        results = youtube.response(response)
203
+        self.assertEqual(type(results), list)
204
+        self.assertEqual(len(results), 0)

+ 22
- 0
searx/tests/test_engines.py View File

@@ -1,3 +1,25 @@
1
+from searx.tests.engines.test_bing import *  # noqa
2
+from searx.tests.engines.test_bing_images import *  # noqa
3
+from searx.tests.engines.test_bing_news import *  # noqa
4
+from searx.tests.engines.test_btdigg import *  # noqa
5
+from searx.tests.engines.test_dailymotion import *  # noqa
6
+from searx.tests.engines.test_deezer import *  # noqa
7
+from searx.tests.engines.test_deviantart import *  # noqa
8
+from searx.tests.engines.test_digg import *  # noqa
1 9
 from searx.tests.engines.test_dummy import *  # noqa
10
+from searx.tests.engines.test_flickr import *  # noqa
11
+from searx.tests.engines.test_flickr_noapi import *  # noqa
2 12
 from searx.tests.engines.test_github import *  # noqa
3 13
 from searx.tests.engines.test_www1x import *  # noqa
14
+from searx.tests.engines.test_google_images import *  # noqa
15
+from searx.tests.engines.test_google_news import *  # noqa
16
+from searx.tests.engines.test_kickass import *  # noqa
17
+from searx.tests.engines.test_mixcloud import *  # noqa
18
+from searx.tests.engines.test_piratebay import *  # noqa
19
+from searx.tests.engines.test_searchcode_code import *  # noqa
20
+from searx.tests.engines.test_searchcode_doc import *  # noqa
21
+from searx.tests.engines.test_soundcloud import *  # noqa
22
+from searx.tests.engines.test_stackoverflow import *  # noqa
23
+from searx.tests.engines.test_vimeo import *  # noqa
24
+from searx.tests.engines.test_www500px import *  # noqa
25
+from searx.tests.engines.test_youtube import *  # noqa

+ 22
- 0
searx/tests/test_utils.py View File

@@ -10,6 +10,11 @@ class TestUtils(SearxTestCase):
10 10
         self.assertIsNotNone(utils.gen_useragent())
11 11
         self.assertTrue(utils.gen_useragent().startswith('Mozilla'))
12 12
 
13
+    def test_searx_useragent(self):
14
+        self.assertIsInstance(utils.searx_useragent(), str)
15
+        self.assertIsNotNone(utils.searx_useragent())
16
+        self.assertTrue(utils.searx_useragent().startswith('searx'))
17
+
13 18
     def test_highlight_content(self):
14 19
         self.assertEqual(utils.highlight_content(0, None), None)
15 20
         self.assertEqual(utils.highlight_content(None, None), None)
@@ -29,6 +34,23 @@ class TestUtils(SearxTestCase):
29 34
         query = 'a test'
30 35
         self.assertEqual(utils.highlight_content(content, query), content)
31 36
 
37
+    def test_html_to_text(self):
38
+        html = """
39
+        <a href="/testlink" class="link_access_account">
40
+            <span class="toto">
41
+                <span>
42
+                    <img src="test.jpg" />
43
+                </span>
44
+            </span>
45
+            <span class="titi">
46
+                            Test text
47
+            </span>
48
+        </a>
49
+        """
50
+        self.assertIsInstance(utils.html_to_text(html), unicode)
51
+        self.assertIsNotNone(utils.html_to_text(html))
52
+        self.assertEqual(utils.html_to_text(html), "Test text")
53
+
32 54
 
33 55
 class TestHTMLTextExtractor(SearxTestCase):
34 56
 

+ 3
- 1
searx/utils.py View File

@@ -115,10 +115,12 @@ class HTMLTextExtractor(HTMLParser):
115 115
         self.result.append(name)
116 116
 
117 117
     def get_text(self):
118
-        return u''.join(self.result)
118
+        return u''.join(self.result).strip()
119 119
 
120 120
 
121 121
 def html_to_text(html):
122
+    html = html.replace('\n', ' ')
123
+    html = ' '.join(html.split())
122 124
     s = HTMLTextExtractor()
123 125
     s.feed(html)
124 126
     return s.get_text()