@@ -1,6 +1,7 @@
11# -*- coding: utf-8 -*-
22from collections import defaultdict
33import mock
4+from requests import Request
45from searx.engines import wolframalpha_api
56from searx.testing import SearxTestCase
67
@@ -9,17 +10,17 @@ class TestWolframAlphaAPIEngine(SearxTestCase):
910
1011 def test_request(self):
1112 query = 'test_query'
12− api_key = 'XXXXXX-XXXXXXXXXX'
1313 dicto = defaultdict(dict)
14− dicto['api_key'] = api_key
1514 params = wolframalpha_api.request(query, dicto)
1615
16+ # TODO: test api_key
1717 self.assertIn('url', params)
18+ self.assertIn('https://api.wolframalpha.com/v2/query?', params['url'])
1819 self.assertIn(query, params['url'])
19− self.assertIn('wolframalpha.com', params['url'])
20+ self.assertEqual('https://www.wolframalpha.com/input/?i=test_query', params['headers']['Referer'])
2021
21− self.assertIn('api_key', params)
22− self.assertIn(api_key, params['api_key'])
22+ def test_replace_pua_chars(self):
23+ self.assertEqual('i', wolframalpha_api.replace_pua_chars(u'\uf74e'))
2324
2425 def test_response(self):
2526 self.assertRaises(AttributeError, wolframalpha_api.response, None)
@@ -27,281 +28,137 @@ class TestWolframAlphaAPIEngine(SearxTestCase):
2728 self.assertRaises(AttributeError, wolframalpha_api.response, '')
2829 self.assertRaises(AttributeError, wolframalpha_api.response, '[]')
2930
31+ referer_url = 'referer_url'
32+ request = Request(headers={'Referer': referer_url})
33+
34+ # test failure
3035 xml = '''<?xml version='1.0' encoding='UTF-8'?>
3136 <queryresult success='false' error='false' />
3237 '''
33− # test failure
3438 response = mock.Mock(content=xml)
3539 self.assertEqual(wolframalpha_api.response(response), [])
3640
41+ # test basic case
3742 xml = """<?xml version='1.0' encoding='UTF-8'?>
3843 <queryresult success='true'
3944 error='false'
40− numpods='6'
41− datatypes=''
42− timedout=''
43− timedoutpods=''
44− timing='0.684'
45− parsetiming='0.138'
46− parsetimedout='false'
47− recalculate=''
48− id='MSPa416020a7966dachc463600000f9c66cc21444cfg'
49− host='http://www3.wolframalpha.com'
50− server='6'
51− related='http://www3.wolframalpha.com/api/v2/relatedQueries.jsp?...'
45+ numpods='3'
46+ datatypes='Math'
47+ id='queryresult_id'
48+ host='http://www4c.wolframalpha.com'
49+ related='related_url'
5250 version='2.6'>
53− <pod title='Input'
54− scanner='Identity'
55− id='Input'
56− position='100'
57− error='false'
58− numsubpods='1'>
59− <subpod title=''>
60− <plaintext>sqrt(-1)</plaintext>
61− </subpod>
62− </pod>
63− <pod title='Result'
64− scanner='Simplification'
65− id='Result'
66− position='200'
67− error='false'
68− numsubpods='1'
69− primary='true'>
70− <subpod title=''>
71− <plaintext></plaintext>
72− </subpod>
73− <states count='1'>
74− <state name='Step-by-step solution'
75− input='Result__Step-by-step solution' />
76− </states>
77− </pod>
78− <pod title='Polar coordinates'
79− scanner='Numeric'
80− id='PolarCoordinates'
81− position='300'
82− error='false'
83− numsubpods='1'>
84− <subpod title=''>
85− <plaintext>r1 (radius), θ90° (angle)</plaintext>
86− </subpod>
87− </pod>
88− <pod title='Position in the complex plane'
89− scanner='Numeric'
90− id='PositionInTheComplexPlane'
91− position='400'
92− error='false'
93− numsubpods='1'>
94− <subpod title=''>
95− <plaintext></plaintext>
96− </subpod>
97− </pod>
98− <pod title='All 2nd roots of -1'
99− scanner='RootsOfUnity'
100− id=''
101− position='500'
102− error='false'
103− numsubpods='2'>
104− <subpod title=''>
105− <plaintext> (principal root)</plaintext>
106− </subpod>
107− <subpod title=''>
108− <plaintext>-</plaintext>
109− </subpod>
110− </pod>
111− <pod title='Plot of all roots in the complex plane'
112− scanner='RootsOfUnity'
113− id='PlotOfAllRootsInTheComplexPlane'
114− position='600'
115− error='false'
116− numsubpods='1'>
117− <subpod title=''>
118− <plaintext></plaintext>
119− </subpod>
120− </pod>
121− </queryresult>
122− """
123− # test private user area char in response
124− response = mock.Mock(content=xml)
125− results = wolframalpha_api.response(response)
126− self.assertEqual(type(results), list)
127− self.assertEqual(len(results), 2)
128− self.assertIn('i', results[0]['answer'])
129− self.assertIn('sqrt(-1) - Wolfram|Alpha', results[1]['title'])
130− self.assertEquals('http://www.wolframalpha.com/input/?i=sqrt%28-1%29', results[1]['url'])
131−
132− xml = """<?xml version='1.0' encoding='UTF-8'?>
133− <queryresult success='true'
134− error='false'
135− numpods='2'
136− datatypes=''
137− timedout=''
138− timedoutpods=''
139− timing='1.286'
140− parsetiming='0.255'
141− parsetimedout='false'
142− recalculate=''
143− id='MSPa195222ad740ede5214h30000480ca61h003d3gd6'
144− host='http://www3.wolframalpha.com'
145− server='20'
146− related='http://www3.wolframalpha.com/api/v2/relatedQueries.jsp?id=...'
147− version='2.6'>
148− <pod title='Indefinite integral'
149− scanner='Integral'
150− id='IndefiniteIntegral'
151− position='100'
152− error='false'
51+ <pod title='Input'
52+ scanner='Identity'
53+ id='Input'
54+ numsubpods='1'>
55+ <subpod title=''>
56+ <img src='input_img_src.gif'
57+ alt='input_img_alt'
58+ title='input_img_title' />
59+ <plaintext>input_plaintext</plaintext>
60+ </subpod>
61+ </pod>
62+ <pod title='Result'
63+ scanner='Simplification'
64+ id='Result'
15365 numsubpods='1'
15466 primary='true'>
155− <subpod title=''>
156− <plaintext>∫1/xxlog(x)+constant</plaintext>
157− </subpod>
158− <states count='1'>
159− <state name='Step-by-step solution'
160− input='IndefiniteIntegral__Step-by-step solution' />
161− </states>
162− <infos count='1'>
163− <info text='log(x) is the natural logarithm'>
164− <link url='http://reference.wolfram.com/mathematica/ref/Log.html'
165− text='Documentation'
166− title='Mathematica' />
167− <link url='http://functions.wolfram.com/ElementaryFunctions/Log'
168− text='Properties'
169− title='Wolfram Functions Site' />
170− <link url='http://mathworld.wolfram.com/NaturalLogarithm.html'
171− text='Definition'
172− title='MathWorld' />
173− </info>
174− </infos>
67+ <subpod title=''>
68+ <img src='result_img_src.gif'
69+ alt='result_img_alt'
70+ title='result_img_title' />
71+ <plaintext>result_plaintext</plaintext>
72+ </subpod>
17573 </pod>
176− <pod title='Plots of the integral'
177− scanner='Integral'
178− id='Plot'
179− position='200'
180− error='false'
181− numsubpods='2'>
182− <subpod title=''>
183− <plaintext></plaintext>
184− <states count='1'>
185− <statelist count='2'
186− value='Complex-valued plot'
187− delimiters=''>
188− <state name='Complex-valued plot'
189− input='Plot__1_Complex-valued plot' />
190− <state name='Real-valued plot'
191− input='Plot__1_Real-valued plot' />
192− </statelist>
193− </states>
194− </subpod>
195− <subpod title=''>
196− <plaintext></plaintext>
197− <states count='1'>
198− <statelist count='2'
199− value='Complex-valued plot'
200− delimiters=''>
201− <state name='Complex-valued plot'
202− input='Plot__2_Complex-valued plot' />
203− <state name='Real-valued plot'
204− input='Plot__2_Real-valued plot' />
205− </statelist>
206− </states>
207− </subpod>
74+ <pod title='Manipulatives illustration'
75+ scanner='Arithmetic'
76+ id='Illustration'
77+ numsubpods='1'>
78+ <subpod title=''>
79+ <img src='illustration_img_src.gif'
80+ alt='illustration_img_alt' />
81+ <plaintext>illustration_plaintext</plaintext>
82+ </subpod>
20883 </pod>
209− <assumptions count='1'>
210− <assumption type='Clash'
211− word='integral'
212− template='Assuming "${word}" is ${desc1}. Use as ${desc2} instead'
213− count='2'>
214− <value name='IntegralsWord'
215− desc='an integral'
216− input='*C.integral-_*IntegralsWord-' />
217− <value name='MathematicalFunctionIdentityPropertyClass'
218− desc='a function property'
219− input='*C.integral-_*MathematicalFunctionIdentityPropertyClass-' />
220− </assumption>
221− </assumptions>
222− </queryresult>
84+ </queryresult>
22385 """
224− # test integral
225− response = mock.Mock(content=xml)
86+ response = mock.Mock(content=xml, request=request)
22687 results = wolframalpha_api.response(response)
22788 self.assertEqual(type(results), list)
22889 self.assertEqual(len(results), 2)
229− self.assertIn('log(x)+c', results[0]['answer'])
230− self.assertIn('∫1/xx - Wolfram|Alpha'.decode('utf-8'), results[1]['title'])
231− self.assertEquals('http://www.wolframalpha.com/input/?i=%E2%88%AB1%2Fx%EF%9D%8Cx', results[1]['url'])
90+ self.assertEqual('input_plaintext', results[0]['infobox'])
91+
92+ self.assertEqual(len(results[0]['attributes']), 3)
93+ self.assertEqual('Input', results[0]['attributes'][0]['label'])
94+ self.assertEqual('input_plaintext', results[0]['attributes'][0]['value'])
95+ self.assertEqual('Result', results[0]['attributes'][1]['label'])
96+ self.assertEqual('result_plaintext', results[0]['attributes'][1]['value'])
97+ self.assertEqual('Manipulatives illustration', results[0]['attributes'][2]['label'])
98+ self.assertEqual('illustration_img_src.gif', results[0]['attributes'][2]['image']['src'])
99+ self.assertEqual('illustration_img_alt', results[0]['attributes'][2]['image']['alt'])
100+
101+ self.assertEqual(len(results[0]['urls']), 1)
232102
103+ self.assertEqual(referer_url, results[0]['urls'][0]['url'])
104+ self.assertEqual('Wolfram|Alpha', results[0]['urls'][0]['title'])
105+ self.assertEqual(referer_url, results[1]['url'])
106+ self.assertEqual('Wolfram|Alpha', results[1]['title'])
107+
108+ # test calc
233109 xml = """<?xml version='1.0' encoding='UTF-8'?>
234110 <queryresult success='true'
235111 error='false'
236− numpods='4'
237− datatypes='Solve'
238− timedout=''
239− timedoutpods=''
240− timing='0.79'
241− parsetiming='0.338'
112+ numpods='2'
113+ datatypes=''
242114 parsetimedout='false'
243− recalculate=''
244− id='MSPa7481f7i06d25h3deh2900004810i3a78d9b4fdc'
115+ id='queryresult_id'
245116 host='http://www5b.wolframalpha.com'
246− server='23'
247− related='http://www5b.wolframalpha.com/api/v2/relatedQueries.jsp?id=...'
248− version='2.6'>
249− <pod title='Input interpretation'
250− scanner='Identity'
251− id='Input'
252− position='100'
253− error='false'
254− numsubpods='1'>
255− <subpod title=''>
256− <plaintext>solve x^2+x0</plaintext>
257− </subpod>
258− </pod>
259− <pod title='Results'
260− scanner='Solve'
261− id='Result'
262− position='200'
263− error='false'
264− numsubpods='2'
265− primary='true'>
266− <subpod title=''>
267− <plaintext>x-1</plaintext>
268− </subpod>
269− <subpod title=''>
270− <plaintext>x0</plaintext>
271− </subpod>
272− <states count='1'>
273− <state name='Step-by-step solution'
274− input='Result__Step-by-step solution' />
275− </states>
276− </pod>
277− <pod title='Root plot'
278− scanner='Solve'
279− id='RootPlot'
280− position='300'
281− error='false'
282− numsubpods='1'>
283− <subpod title=''>
284− <plaintext></plaintext>
285− </subpod>
286− </pod>
287− <pod title='Number line'
288− scanner='Solve'
289− id='NumberLine'
290− position='400'
291− error='false'
292− numsubpods='1'>
293− <subpod title=''>
294− <plaintext></plaintext>
295− </subpod>
296− </pod>
117+ related='related_url'
118+ version='2.6' >
119+ <pod title='Indefinite integral'
120+ scanner='Integral'
121+ id='IndefiniteIntegral'
122+ error='false'
123+ numsubpods='1'
124+ primary='true'>
125+ <subpod title=''>
126+ <img src='integral_image.gif'
127+ alt='integral_img_alt'
128+ title='integral_img_title' />
129+ <plaintext>integral_plaintext</plaintext>
130+ </subpod>
131+ </pod>
132+ <pod title='Plot of the integral'
133+ scanner='Integral'
134+ id='Plot'
135+ error='false'
136+ numsubpods='1'>
137+ <subpod title=''>
138+ <img src='plot.gif'
139+ alt='plot_alt'
140+ title='' />
141+ <plaintext></plaintext>
142+ </subpod>
143+ </pod>
297144 </queryresult>
298145 """
299− # test ecuation with multiple answers
300− response = mock.Mock(content=xml)
146+ response = mock.Mock(content=xml, request=request)
301147 results = wolframalpha_api.response(response)
302148 self.assertEqual(type(results), list)
303− self.assertEqual(len(results), 3)
304− self.assertIn('x=-1', results[0]['answer'])
305− self.assertIn('x=0', results[1]['answer'])
306− self.assertIn('solve x^2+x0 - Wolfram|Alpha'.decode('utf-8'), results[2]['title'])
307− self.assertEquals('http://www.wolframalpha.com/input/?i=solve+x%5E2%2Bx%EF%9F%990', results[2]['url'])
149+ self.assertEqual(len(results), 2)
150+ self.assertEqual('integral_plaintext', results[0]['infobox'])
151+
152+ self.assertEqual(len(results[0]['attributes']), 2)
153+ self.assertEqual('Indefinite integral', results[0]['attributes'][0]['label'])
154+ self.assertEqual('integral_plaintext', results[0]['attributes'][0]['value'])
155+ self.assertEqual('Plot of the integral', results[0]['attributes'][1]['label'])
156+ self.assertEqual('plot.gif', results[0]['attributes'][1]['image']['src'])
157+ self.assertEqual('plot_alt', results[0]['attributes'][1]['image']['alt'])
158+
159+ self.assertEqual(len(results[0]['urls']), 1)
160+
161+ self.assertEqual(referer_url, results[0]['urls'][0]['url'])
162+ self.assertEqual('Wolfram|Alpha', results[0]['urls'][0]['title'])
163+ self.assertEqual(referer_url, results[1]['url'])
164+ self.assertEqual('Wolfram|Alpha', results[1]['title'])