def test_type_trans(self): qp = "/ A='xxx' & B=-0X2121 & C=True" data,_ = QPathParser().parse(qp) data = data[0] self.assertEqual(data['A'][1], 'xxx') self.assertEqual(data['B'][1], -0X2121) self.assertEqual(data['C'][1], True)
def test_escape(self): qp = "/ A='xxx' & B='\"' & C=True" data,_ = QPathParser().parse(qp) self.assertEqual(data[0]['B'][1], '\"') qp = "/ A='xxx' & B='\\'' & C=True" data,_ = QPathParser().parse(qp) self.assertEqual(data[0]['B'][1], "'") qp = "/ A='xxx' & B='\d' & C=True" data,_ = QPathParser().parse(qp) self.assertEqual(data[0]['B'][1], "\d") qp = "/ A='xxx' & B='\\d' & C=True" data,_ = QPathParser().parse(qp) self.assertEqual(data[0]['B'][1], "\\d")
class QPath(str): '''QPath基类 ''' parser = QPathParser() def __init__(self, qpath=None): '''构造函数 :param qpath: QPath字符串 :type qpath: string ''' # -*- pattern = '|'.join(['=', '~', '!']) result = re.search(pattern, qpath, re.I) if result: sys.stderr.write('警告: QPath中含有中文关系运算符 [%s] in [ %s ]\n' % (result.group(), qpath)) # -*- # if qpath: # parsed_qpath, _ = self.parser.parse(qpath) # locators = [] # for locator in parsed_qpath: # props = [] # for propname in locator: # prop = locator[propname] # props.append('%s%s\'%s\''%(propname, prop[0], prop[1])) # locators.append(' && '.join(props)) # qpath = '/' + ' /'.join(locators) self._qpath = qpath def __str__(self): '''获取qpath字符串,实例化控件时调用server.find时传参为qpath字符串 ''' return self._qpath
def test_dumps(self): qp = "/ ClassName='TxGuiFoundation' & Caption='QQ' / name=true" data, _ = QPathParser().parse(qp) self.assertEqual([{ 'ClassName': ['=', 'TxGuiFoundation'], 'Caption': ['=', 'QQ'] }, { 'name': ['=', True] }], data)
def parsed_qpath(self): '''解析后的内容 ''' result = QPathParser().parse(self._qpath_str)[0] for it in result: for key in it: if not key in [ 'Id', 'Text', 'Type', 'Visible', 'Desc', 'MaxDepth', 'Instance' ]: if not key.startswith('Field_') and not key.startswith( 'Method_'): raise RuntimeError('QPath(%s) keyword error: %s' % (self._qpath_str, key)) return result
def xctest2instruments(locator): qpath_array, _ = QPathParser().parse(locator) for node in qpath_array: if 'classname' in node: if node['classname'][1] in XCT_UIA_MAPS.keys(): node['classname'][1] = XCT_UIA_MAPS[node['classname'][1]] new_locator = '' for node in qpath_array: new_locator += '/' properties = [] for p in node.keys(): if isinstance(node[p][1], basestring): value = node[p][1] if isinstance(node[p][1], unicode): value = value.encode('utf-8') node_str = "{}{}\'{}\'".format(p, node[p][0], value) else: node_str = "{}{}{}".format(p, node[p][0], node[p][1]) properties.append(node_str) properties = ' & '.join(properties) new_locator += properties.decode('utf-8') return new_locator
def find_elements(self, locator, timeout=3, interval=0.005, strategy=By.QPATH, parent_id=None): '''查找单个element对象,返回查找到的element对象的缓存id。不指定parent_id则从UIAApplication下开始搜索。 :param locator: 定位element的字符串,例如: "/classname='UIAWindow'" :type locator: str :param timeout: 查找element的超时值(单位: 秒) :type timeout: float :param interval: 在查找element的超时范围内,循环的间隔(单位: 秒) :type interval: float :param strategy: locator的类型,例如: "qpath", "xpath", "id", "name" :type strategy: str :param parent_id: 父element的id,如不指定则从UIAApplication下查找 :type parent_id: int :returns: dict : {'elements': [{'element':id, 'attributes':<encode str>}], 'path': <encode str>, 'valid_path_part': <encode str>, 'invalid_path_part': <encode str>, 'find_count': <int>, "find_time": int} ''' if strategy == "qpath": #解析QPath qpath_array, qpath_lex = QPathParser().parse(locator) for node in qpath_array: if 'classname' in node: if node['classname'][1] in UIA_XCT_MAPS.keys(): node['classname'][1] = UIA_XCT_MAPS[node['classname'][1]] locator_value = qpath_array valid_path = None invalid_path = None else: locator_value = locator start_time = time.time() elements = [] count = 0 parent_id = parent_id if parent_id else 1 while True: before_step_time = time.time() count += 1 response = self.agent.execute(Command.QTA_FIND_ELEMENTS, {'using': strategy, 'value': locator_value, 'id':parent_id}) elements = response['value'] after_step_time = time.time() step_time = after_step_time - before_step_time if elements or after_step_time - start_time >= timeout: break if interval > 0: sleep_time = interval - step_time if sleep_time > 0: time.sleep(sleep_time) if elements: elements = [{'element': int(e['ELEMENT'])} for e in elements] if strategy == "qpath": valid_path = locator invalid_path = "" else: if strategy == "qpath": valid_path_index = response['info']['index'] locations = [] if valid_path_index + 1 < len(qpath_lex): valid_path_index = valid_path_index + 1 for _ in qpath_lex[valid_path_index].values(): locations.extend(_) locations.sort() valid_index = locations[0] - 1 valid_path = locator[0:valid_index] invalid_path = locator[valid_index+1:] find_time = int((time.time() - start_time)*1000) result = {'elements':elements, 'find_count':count, 'find_time':find_time} if strategy == "qpath": result['valid_path_part'] = valid_path result['invalid_path_part'] = invalid_path return result
def test_maxdepth_smaller_than_zero(self): qp = "/ ClassName='TxGuiFoundation' & Caption='xxx' / Instance=-1 & maxdepth=0 & name='xxx'" with self.assertRaises(QPathSyntaxError) as cm: QPathParser().parse(qp) self.assertEqual(qp.find('0'), cm.exception.lexpos)
def test_invalid_seperator(self): qp = "| ClassName='TxGuiFoundation' & Caption='QQ' | name~=true" with self.assertRaises(QPathSyntaxError) as cm: QPathParser().parse(qp) self.assertEqual(0, cm.exception.lexpos)
def test_invalid_value_of_match_operator(self): qp = "/ ClassName='TxGuiFoundation' & Caption='QQ' / name~=true" with self.assertRaises(QPathSyntaxError) as cm: QPathParser().parse(qp) self.assertEqual(qp.find('~='), cm.exception.lexpos)
def test_invalid_value_of_instance(self): qp = "/ ClassName='TxGuiFoundation' & Caption='QQ' / instance='xxx' & name='mainpanel'" with self.assertRaises(QPathSyntaxError) as cm: QPathParser().parse(qp) self.assertEqual(qp.find('\'xxx\''), cm.exception.lexpos)
def test_invalid_operator_in_maxdepth(self): qp = "/ ClassName='TxGuiFoundation' & Caption='QQ' / maxdepth~=2 & name='mainpanel'" with self.assertRaises(QPathSyntaxError) as cm: QPathParser().parse(qp) self.assertEqual(qp.find('~='), cm.exception.lexpos)
def _check_locator(self, _locator): pass if isinstance(_locator, (QPath, basestring)): parsed_qpath, _ = QPathParser().parse(_locator)
def dumps(self): '''serialize ''' return QPathParser().parse(self._qpath_string)