|  | @@ -0,0 +1,307 @@
 | 
	
		
			
			|  | 1 | +# -*- coding: utf-8 -*-
 | 
	
		
			
			|  | 2 | +from collections import defaultdict
 | 
	
		
			
			|  | 3 | +import mock
 | 
	
		
			
			|  | 4 | +from searx.engines import wolframalpha_api
 | 
	
		
			
			|  | 5 | +from searx.testing import SearxTestCase
 | 
	
		
			
			|  | 6 | +
 | 
	
		
			
			|  | 7 | +
 | 
	
		
			
			|  | 8 | +class TestWolframAlphaAPIEngine(SearxTestCase):
 | 
	
		
			
			|  | 9 | +
 | 
	
		
			
			|  | 10 | +    def test_request(self):
 | 
	
		
			
			|  | 11 | +        query = 'test_query'
 | 
	
		
			
			|  | 12 | +        api_key = 'XXXXXX-XXXXXXXXXX'
 | 
	
		
			
			|  | 13 | +        dicto = defaultdict(dict)
 | 
	
		
			
			|  | 14 | +        dicto['api_key'] = api_key
 | 
	
		
			
			|  | 15 | +        params = wolframalpha_api.request(query, dicto)
 | 
	
		
			
			|  | 16 | +
 | 
	
		
			
			|  | 17 | +        self.assertIn('url', params)
 | 
	
		
			
			|  | 18 | +        self.assertIn(query, params['url'])
 | 
	
		
			
			|  | 19 | +        self.assertIn('wolframalpha.com', params['url'])
 | 
	
		
			
			|  | 20 | +
 | 
	
		
			
			|  | 21 | +        self.assertIn('api_key', params)
 | 
	
		
			
			|  | 22 | +        self.assertIn(api_key, params['api_key'])
 | 
	
		
			
			|  | 23 | +
 | 
	
		
			
			|  | 24 | +    def test_response(self):
 | 
	
		
			
			|  | 25 | +        self.assertRaises(AttributeError, wolframalpha_api.response, None)
 | 
	
		
			
			|  | 26 | +        self.assertRaises(AttributeError, wolframalpha_api.response, [])
 | 
	
		
			
			|  | 27 | +        self.assertRaises(AttributeError, wolframalpha_api.response, '')
 | 
	
		
			
			|  | 28 | +        self.assertRaises(AttributeError, wolframalpha_api.response, '[]')
 | 
	
		
			
			|  | 29 | +
 | 
	
		
			
			|  | 30 | +        xml = '''<?xml version='1.0' encoding='UTF-8'?>
 | 
	
		
			
			|  | 31 | +        <queryresult success='false' error='false' />
 | 
	
		
			
			|  | 32 | +        '''
 | 
	
		
			
			|  | 33 | +        # test failure
 | 
	
		
			
			|  | 34 | +        response = mock.Mock(content=xml)
 | 
	
		
			
			|  | 35 | +        self.assertEqual(wolframalpha_api.response(response), [])
 | 
	
		
			
			|  | 36 | +
 | 
	
		
			
			|  | 37 | +        xml = """<?xml version='1.0' encoding='UTF-8'?>
 | 
	
		
			
			|  | 38 | +        <queryresult success='true'
 | 
	
		
			
			|  | 39 | +            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?...'
 | 
	
		
			
			|  | 52 | +            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'
 | 
	
		
			
			|  | 153 | +                 numsubpods='1'
 | 
	
		
			
			|  | 154 | +                 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>
 | 
	
		
			
			|  | 175 | +             </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>
 | 
	
		
			
			|  | 208 | +             </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>
 | 
	
		
			
			|  | 223 | +        """
 | 
	
		
			
			|  | 224 | +        # test integral
 | 
	
		
			
			|  | 225 | +        response = mock.Mock(content=xml)
 | 
	
		
			
			|  | 226 | +        results = wolframalpha_api.response(response)
 | 
	
		
			
			|  | 227 | +        self.assertEqual(type(results), list)
 | 
	
		
			
			|  | 228 | +        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'])
 | 
	
		
			
			|  | 232 | +
 | 
	
		
			
			|  | 233 | +        xml = """<?xml version='1.0' encoding='UTF-8'?>
 | 
	
		
			
			|  | 234 | +        <queryresult success='true'
 | 
	
		
			
			|  | 235 | +            error='false'
 | 
	
		
			
			|  | 236 | +            numpods='4'
 | 
	
		
			
			|  | 237 | +            datatypes='Solve'
 | 
	
		
			
			|  | 238 | +            timedout=''
 | 
	
		
			
			|  | 239 | +            timedoutpods=''
 | 
	
		
			
			|  | 240 | +            timing='0.79'
 | 
	
		
			
			|  | 241 | +            parsetiming='0.338'
 | 
	
		
			
			|  | 242 | +            parsetimedout='false'
 | 
	
		
			
			|  | 243 | +            recalculate=''
 | 
	
		
			
			|  | 244 | +            id='MSPa7481f7i06d25h3deh2900004810i3a78d9b4fdc'
 | 
	
		
			
			|  | 245 | +            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>
 | 
	
		
			
			|  | 297 | +        </queryresult>
 | 
	
		
			
			|  | 298 | +        """
 | 
	
		
			
			|  | 299 | +        # test ecuation with multiple answers
 | 
	
		
			
			|  | 300 | +        response = mock.Mock(content=xml)
 | 
	
		
			
			|  | 301 | +        results = wolframalpha_api.response(response)
 | 
	
		
			
			|  | 302 | +        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'])
 |