1 """ Steps for checking the results of queries.
4 from nose.tools import *
6 from tidylib import tidy_document
7 from collections import OrderedDict
11 from xml.dom.minidom import parseString
13 logger = logging.getLogger(__name__)
16 """ Puts the DOM structure into more convenient python
17 with a similar structure as the json document, so
18 that the same the semantics can be used. It does not
19 check if the content is valid (or at least not more than
20 necessary to transform it into a dict structure).
22 page = parseString(world.page).documentElement
25 world.result_header = OrderedDict(page.attributes.items())
26 logger.debug('Result header: %r' % (world.result_header))
30 if page.nodeName == 'searchresults':
31 for node in page.childNodes:
32 if node.nodeName != "#text":
33 assert_equals(node.nodeName, 'place', msg="Unexpected element '%s'" % node.nodeName)
34 newresult = OrderedDict(node.attributes.items())
35 assert_not_in('address', newresult)
36 assert_not_in('geokml', newresult)
37 address = OrderedDict()
38 for sub in node.childNodes:
39 if sub.nodeName == 'geokml':
40 newresult['geokml'] = sub.childNodes[0].toxml()
41 elif sub.nodeName == '#text':
44 address[sub.nodeName] = sub.firstChild.nodeValue.strip()
46 newresult['address'] = address
47 world.results.append(newresult)
48 elif page.nodeName == 'reversegeocode':
51 for node in page.childNodes:
52 if node.nodeName == 'result':
53 assert_equals(len(world.results), 0)
55 world.results.append(OrderedDict(node.attributes.items()))
56 assert_not_in('display_name', world.results[0])
57 assert_not_in('address', world.results[0])
58 world.results[0]['display_name'] = node.firstChild.nodeValue.strip()
59 elif node.nodeName == 'error':
60 assert_equals(len(world.results), 0)
62 elif node.nodeName == 'addressparts':
64 address = OrderedDict()
65 for sub in node.childNodes:
66 address[sub.nodeName] = sub.firstChild.nodeValue.strip()
67 world.results[0]['address'] = address
68 elif node.nodeName == "#text":
71 assert False, "Unknown content '%s' in XML" % node.nodeName
73 assert False, "Unknown document node name %s in XML" % page.nodeName
75 logger.debug("The following was parsed out of XML:")
76 logger.debug(world.results)
78 @step(u'a HTTP (\d+) is returned')
79 def api_result_http_error(step, error):
80 assert_equals(world.returncode, int(error))
82 @step(u'the result is valid( \w+)?')
83 def api_result_is_valid(step, fmt):
84 assert_equals(world.returncode, 200)
86 if world.response_format == 'html':
87 document, errors = tidy_document(world.page,
88 options={'char-encoding' : 'utf8'})
89 assert(len(errors) == 0), "Errors found in HTML document:\n%s" % errors
90 world.results = document
91 elif world.response_format == 'xml':
93 elif world.response_format == 'json':
94 world.results = json.JSONDecoder(object_pairs_hook=OrderedDict).decode(world.page)
96 assert False, "Unknown page format: %s" % (world.response_format)
99 assert_equals (fmt.strip(), world.response_format)
102 def compare(operator, op1, op2):
103 if operator == 'less than':
105 elif operator == 'more than':
107 elif operator == 'exactly':
109 elif operator == 'at least':
111 elif operator == 'at most':
114 raise Exception("unknown operator '%s'" % operator)
116 @step(u'(less than|more than|exactly|at least|at most) (\d+) results? (?:is|are) returned')
117 def validate_result_number(step, operator, number):
118 step.given('the result is valid')
119 numres = len(world.results)
120 assert compare(operator, numres, int(number)), \
121 "Bad number of results: expected %s %s, got %d." % (operator, number, numres)
123 @step(u'result (\d+) has( not)? attributes (\S+)')
124 def search_check_for_result_attribute(step, num, invalid, attrs):
126 step.given('at least %d results are returned' % (num + 1))
127 res = world.results[num]
128 for attr in attrs.split(','):
130 assert_not_in(attr.strip(), res)
132 assert_in(attr.strip(),res)
134 @step(u'there is a json wrapper "([^"]*)"')
135 def api_result_check_json_wrapper(step, wrapper):
136 step.given('the result is valid json')
137 assert_equals(world.json_callback, wrapper)
139 @step(u'result header contains')
140 def api_result_header_contains(step):
141 step.given('the result is valid')
142 for line in step.hashes:
143 assert_in(line['attr'], world.result_header)
144 m = re.match("%s$" % (line['value'],), world.result_header[line['attr']])
146 @step(u'result header has no attribute (.*)')
147 def api_result_header_contains_not(step, attr):
148 step.given('the result is valid')
149 assert_not_in(attr, world.result_header)
151 @step(u'results contain$')
152 def api_result_contains(step):
153 step.given('at least 1 result is returned')
154 for line in step.hashes:
156 reslist = (world.results[int(line['ID'])],)
158 reslist = world.results
159 for k,v in line.iteritems():
161 for curres in reslist:
162 world.match_geometry((float(curres['lat']), float(curres['lon'])), v)
164 for curres in reslist:
167 # mathematical operation
168 evalexp = '%s %s' % (curres[k], v)
170 logger.debug('Evaluating: %s = %s' % (res, evalexp))
171 assert_true(res, "Evaluation failed: %s" % (evalexp, ))
174 m = re.match("%s$" % (v,), curres[k])
175 assert_is_not_none(m, msg="field %s does not match: %s$ != %s." % (k, v, curres[k]))
178 @step(u'result addresses contain$')
179 def api_result_address_contains(step):
180 step.given('the result is valid')
181 for line in step.hashes:
183 reslist = (world.results[int(line['ID'])],)
185 reslist = world.results
186 for k,v in line.iteritems():
189 curres = res['address']
191 m = re.match("%s$" % (v,), curres[k])
192 assert_is_not_none(m, msg="field %s does not match: %s$ != %s." % (k, v, curres[k]))
195 @step(u'address of result (\d+) contains')
196 def api_result_address_exact(step, resid):
198 step.given('at least %d results are returned' % (resid + 1))
199 addr = world.results[resid]['address']
200 for line in step.hashes:
201 assert_in(line['type'], addr)
202 assert_equals(line['value'], addr[line['type']])
204 @step(u'address of result (\d+) does not contain (.*)')
205 def api_result_address_details_missing(step, resid, types):
207 step.given('at least %d results are returned' % (resid + 1))
208 addr = world.results[resid]['address']
209 for t in types.split(','):
210 assert_not_in(t.strip(), addr)
213 @step(u'address of result (\d+) is')
214 def api_result_address_exact(step, resid):
216 step.given('at least %d results are returned' % (resid + 1))
217 result = world.results[resid]
219 assert_equals(len(step.hashes), len(result['address']))
220 for k,v in result['address'].iteritems():
221 assert_equals(step.hashes[linenr]['type'], k)
222 assert_equals(step.hashes[linenr]['value'], v)
226 @step('there are( no)? duplicates')
227 def api_result_check_for_duplicates(step, nodups=None):
228 step.given('at least 1 result is returned')
230 for res in world.results:
231 resarr.append((res['osm_type'], res['class'],
232 res['type'], res['display_name']))
235 assert len(resarr) > len(set(resarr))
237 assert_equal(len(resarr), len(set(resarr)))