# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: # Copyright 2014-2016 Florian Bruhin (The Compiler) # # This file is part of qutebrowser. # # qutebrowser is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # qutebrowser is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . """Tests for the webelement utils.""" from unittest import mock import collections.abc import operator import itertools from PyQt5.QtCore import QRect, QPoint, QUrl from PyQt5.QtWebKit import QWebElement import pytest from qutebrowser.browser import webelem from qutebrowser.browser.webkit import webkitelem def get_webelem(geometry=None, frame=None, *, null=False, style=None, attributes=None, tagname=None, classes=None, parent=None, js_rect_return=None, zoom_text_only=False): """Factory for WebKitElement objects based on a mock. Args: geometry: The geometry of the QWebElement as QRect. frame: The QWebFrame the element is in. null: Whether the element is null or not. style: A dict with the styleAttributes of the element. attributes: Boolean HTML attributes to be added. tagname: The tag name. classes: HTML classes to be added. js_rect_return: If None, what evaluateJavaScript returns is based on geometry. If set, the return value of evaluateJavaScript. zoom_text_only: Whether zoom-text-only is set in the config """ # pylint: disable=too-many-locals,too-many-branches elem = mock.Mock() elem.isNull.return_value = null elem.geometry.return_value = geometry elem.webFrame.return_value = frame elem.tagName.return_value = tagname elem.toOuterXml.return_value = '' elem.toPlainText.return_value = 'text' elem.parent.return_value = parent if geometry is not None: if frame is None: scroll_x = 0 scroll_y = 0 else: scroll_x = frame.scrollPosition().x() scroll_y = frame.scrollPosition().y() if js_rect_return is None: if frame is None or zoom_text_only: zoom = 1.0 else: zoom = frame.zoomFactor() elem.evaluateJavaScript.return_value = { "length": 1, "0": { "left": (geometry.left() - scroll_x) / zoom, "top": (geometry.top() - scroll_y) / zoom, "right": (geometry.right() - scroll_x) / zoom, "bottom": (geometry.bottom() - scroll_y) / zoom, "width": geometry.width() / zoom, "height": geometry.height() / zoom, } } else: elem.evaluateJavaScript.return_value = js_rect_return attribute_dict = {} if attributes is None: pass elif not isinstance(attributes, collections.abc.Mapping): attribute_dict.update({e: None for e in attributes}) else: attribute_dict.update(attributes) elem.hasAttribute.side_effect = lambda k: k in attribute_dict elem.attribute.side_effect = lambda k: attribute_dict.get(k, '') elem.setAttribute.side_effect = (lambda k, v: operator.setitem(attribute_dict, k, v)) elem.removeAttribute.side_effect = attribute_dict.pop elem.attributeNames.return_value = list(attribute_dict) if classes is not None: elem.classes.return_value = classes.split(' ') else: elem.classes.return_value = [] style_dict = {'visibility': '', 'display': '', 'foo': 'bar'} if style is not None: style_dict.update(style) def _style_property(name, strategy): """Helper function to act as styleProperty method.""" if strategy != QWebElement.ComputedStyle: raise ValueError("styleProperty called with strategy != " "ComputedStyle ({})!".format(strategy)) return style_dict[name] elem.styleProperty.side_effect = _style_property wrapped = webkitelem.WebKitElement(elem) return wrapped class SelectionAndFilterTests: """Generator for tests for TestSelectionsAndFilters.""" # A mapping of an HTML element to a list of groups where the selectors # (after filtering) should match. # # Based on this, test cases are generated to make sure it matches those # groups and not the others. TESTS = [ ('', []), ('', []), ('', [webelem.Group.url]), ('', [webelem.Group.url]), ('', [webelem.Group.all]), ('', [webelem.Group.all, webelem.Group.links, webelem.Group.prevnext, webelem.Group.url]), ('', [webelem.Group.all, webelem.Group.url]), ('', [webelem.Group.all]), ('', [webelem.Group.all, webelem.Group.links, webelem.Group.prevnext, webelem.Group.url]), ('', [webelem.Group.all, webelem.Group.url]), ('', [webelem.Group.all]), ('', [webelem.Group.all, webelem.Group.links, webelem.Group.prevnext, webelem.Group.url]), ('', [webelem.Group.all, webelem.Group.url]), ('