2018-09-08 12:15:32 +02:00
|
|
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
|
|
|
|
|
|
|
# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
|
|
|
#
|
|
|
|
# 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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
"""Tests for caret browsing mode."""
|
|
|
|
|
|
|
|
import textwrap
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
from PyQt5.QtCore import QUrl
|
|
|
|
|
2018-10-06 19:04:28 +02:00
|
|
|
from qutebrowser.utils import usertypes, qtutils
|
2018-09-08 12:15:32 +02:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def caret(web_tab, qtbot, mode_manager):
|
|
|
|
with qtbot.wait_signal(web_tab.load_finished):
|
2018-11-30 08:31:03 +01:00
|
|
|
web_tab.load_url(QUrl('qute://testdata/data/caret.html'))
|
2018-09-08 12:15:32 +02:00
|
|
|
|
|
|
|
mode_manager.enter(usertypes.KeyMode.caret)
|
|
|
|
|
|
|
|
return web_tab.caret
|
|
|
|
|
|
|
|
|
|
|
|
class Selection:
|
|
|
|
|
|
|
|
"""Helper to interact with the caret selection."""
|
|
|
|
|
|
|
|
def __init__(self, qtbot, caret):
|
|
|
|
self._qtbot = qtbot
|
|
|
|
self._caret = caret
|
|
|
|
|
2018-09-15 20:39:35 +02:00
|
|
|
def check(self, expected, *, strip=False):
|
2018-09-13 22:41:30 +02:00
|
|
|
"""Check whether we got the expected selection.
|
|
|
|
|
2018-09-15 20:41:56 +02:00
|
|
|
Since (especially on Windows) the selection is empty if we're checking
|
|
|
|
too quickly, we try to read it multiple times.
|
2018-09-13 22:41:30 +02:00
|
|
|
"""
|
|
|
|
for _ in range(10):
|
2018-09-26 11:39:52 +02:00
|
|
|
with self._qtbot.wait_callback() as callback:
|
|
|
|
self._caret.selection(callback)
|
2018-09-13 22:41:30 +02:00
|
|
|
|
2018-09-26 11:39:52 +02:00
|
|
|
selection = callback.args[0]
|
2018-09-13 22:41:30 +02:00
|
|
|
if selection:
|
2018-09-15 20:39:35 +02:00
|
|
|
if strip:
|
|
|
|
selection = selection.strip()
|
2018-09-13 22:41:30 +02:00
|
|
|
assert selection == expected
|
|
|
|
return
|
|
|
|
|
|
|
|
self._qtbot.wait(50)
|
2018-09-08 12:15:32 +02:00
|
|
|
|
2018-09-15 20:39:35 +02:00
|
|
|
def check_multiline(self, expected, *, strip=False):
|
|
|
|
self.check(textwrap.dedent(expected).strip(), strip=strip)
|
2018-09-08 12:15:32 +02:00
|
|
|
|
|
|
|
def toggle(self):
|
|
|
|
with self._qtbot.wait_signal(self._caret.selection_toggled):
|
|
|
|
self._caret.toggle_selection()
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
2018-09-26 11:39:52 +02:00
|
|
|
def selection(qtbot, caret):
|
2018-09-08 12:15:32 +02:00
|
|
|
return Selection(qtbot, caret)
|
|
|
|
|
|
|
|
|
|
|
|
class TestDocument:
|
|
|
|
|
|
|
|
def test_selecting_entire_document(self, caret, selection):
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_end_of_document()
|
|
|
|
selection.check_multiline("""
|
|
|
|
one two three
|
|
|
|
eins zwei drei
|
|
|
|
|
|
|
|
four five six
|
|
|
|
vier fünf sechs
|
2018-09-15 20:39:35 +02:00
|
|
|
""", strip=True)
|
2018-09-08 12:15:32 +02:00
|
|
|
|
|
|
|
def test_moving_to_end_and_start(self, caret, selection):
|
|
|
|
caret.move_to_end_of_document()
|
|
|
|
caret.move_to_start_of_document()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_end_of_word()
|
|
|
|
selection.check("one")
|
|
|
|
|
|
|
|
def test_moving_to_end_and_start_with_selection(self, caret, selection):
|
|
|
|
caret.move_to_end_of_document()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_start_of_document()
|
|
|
|
selection.check_multiline("""
|
|
|
|
one two three
|
|
|
|
eins zwei drei
|
|
|
|
|
|
|
|
four five six
|
|
|
|
vier fünf sechs
|
2018-09-15 20:39:35 +02:00
|
|
|
""", strip=True)
|
2018-09-08 12:15:32 +02:00
|
|
|
|
|
|
|
|
|
|
|
class TestBlock:
|
|
|
|
|
|
|
|
def test_selecting_block(self, caret, selection):
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_end_of_next_block()
|
|
|
|
selection.check_multiline("""
|
|
|
|
one two three
|
|
|
|
eins zwei drei
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_moving_back_to_the_end_of_prev_block_with_sel(self, caret, selection):
|
|
|
|
caret.move_to_end_of_next_block(2)
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_end_of_prev_block()
|
|
|
|
caret.move_to_prev_word()
|
|
|
|
selection.check_multiline("""
|
|
|
|
drei
|
|
|
|
|
|
|
|
four five six
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_moving_back_to_the_end_of_prev_block(self, caret, selection):
|
|
|
|
caret.move_to_end_of_next_block(2)
|
|
|
|
caret.move_to_end_of_prev_block()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_prev_word()
|
|
|
|
selection.check("drei")
|
|
|
|
|
2018-09-08 13:59:11 +02:00
|
|
|
def test_moving_back_to_the_start_of_prev_block_with_sel(self, caret, selection):
|
2018-09-08 12:15:32 +02:00
|
|
|
caret.move_to_end_of_next_block(2)
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_start_of_prev_block()
|
|
|
|
selection.check_multiline("""
|
|
|
|
eins zwei drei
|
|
|
|
|
|
|
|
four five six
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_moving_back_to_the_start_of_prev_block(self, caret, selection):
|
|
|
|
caret.move_to_end_of_next_block(2)
|
|
|
|
caret.move_to_start_of_prev_block()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_next_word()
|
|
|
|
selection.check("eins ")
|
|
|
|
|
2018-09-08 13:59:11 +02:00
|
|
|
def test_moving_to_the_start_of_next_block_with_sel(self, caret, selection):
|
2018-09-08 12:15:32 +02:00
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_start_of_next_block()
|
|
|
|
selection.check("one two three\n")
|
|
|
|
|
|
|
|
def test_moving_to_the_start_of_next_block(self, caret, selection):
|
|
|
|
caret.move_to_start_of_next_block()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_end_of_word()
|
|
|
|
selection.check("eins")
|
|
|
|
|
|
|
|
|
|
|
|
class TestLine:
|
|
|
|
|
|
|
|
def test_selecting_a_line(self, caret, selection):
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_end_of_line()
|
|
|
|
selection.check("one two three")
|
|
|
|
|
|
|
|
def test_moving_and_selecting_a_line(self, caret, selection):
|
|
|
|
caret.move_to_next_line()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_end_of_line()
|
|
|
|
selection.check("eins zwei drei")
|
|
|
|
|
|
|
|
def test_selecting_next_line(self, caret, selection):
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_next_line()
|
|
|
|
selection.check("one two three\n")
|
|
|
|
|
|
|
|
def test_moving_to_end_and_to_start_of_line(self, caret, selection):
|
|
|
|
caret.move_to_end_of_line()
|
|
|
|
caret.move_to_start_of_line()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_end_of_word()
|
|
|
|
selection.check("one")
|
|
|
|
|
|
|
|
def test_selecting_a_line_backwards(self, caret, selection):
|
|
|
|
caret.move_to_end_of_line()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_start_of_line()
|
|
|
|
selection.check("one two three")
|
|
|
|
|
|
|
|
def test_selecting_previous_line(self, caret, selection):
|
|
|
|
caret.move_to_next_line()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_prev_line()
|
|
|
|
selection.check("one two three\n")
|
|
|
|
|
|
|
|
def test_moving_to_previous_line(self, caret, selection):
|
|
|
|
caret.move_to_next_line()
|
|
|
|
caret.move_to_prev_line()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_next_line()
|
|
|
|
selection.check("one two three\n")
|
|
|
|
|
|
|
|
|
|
|
|
class TestWord:
|
|
|
|
|
|
|
|
def test_selecting_a_word(self, caret, selection):
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_end_of_word()
|
|
|
|
selection.check("one")
|
|
|
|
|
|
|
|
def test_moving_to_end_and_selecting_a_word(self, caret, selection):
|
|
|
|
caret.move_to_end_of_word()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_end_of_word()
|
|
|
|
selection.check(" two")
|
|
|
|
|
|
|
|
def test_moving_to_next_word_and_selecting_a_word(self, caret, selection):
|
|
|
|
caret.move_to_next_word()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_end_of_word()
|
|
|
|
selection.check("two")
|
|
|
|
|
|
|
|
def test_moving_to_next_word_and_selecting_until_next_word(self, caret, selection):
|
|
|
|
caret.move_to_next_word()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_next_word()
|
|
|
|
selection.check("two ")
|
|
|
|
|
|
|
|
def test_moving_to_previous_word_and_selecting_a_word(self, caret, selection):
|
|
|
|
caret.move_to_end_of_word()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_prev_word()
|
|
|
|
selection.check("one")
|
|
|
|
|
|
|
|
def test_moving_to_previous_word(self, caret, selection):
|
|
|
|
caret.move_to_end_of_word()
|
|
|
|
caret.move_to_prev_word()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_end_of_word()
|
|
|
|
selection.check("one")
|
|
|
|
|
|
|
|
|
|
|
|
class TestChar:
|
|
|
|
|
|
|
|
def test_selecting_a_char(self, caret, selection):
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_next_char()
|
|
|
|
selection.check("o")
|
|
|
|
|
|
|
|
def test_moving_and_selecting_a_char(self, caret, selection):
|
|
|
|
caret.move_to_next_char()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_next_char()
|
|
|
|
selection.check("n")
|
|
|
|
|
|
|
|
def test_selecting_previous_char(self, caret, selection):
|
|
|
|
caret.move_to_end_of_word()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_prev_char()
|
|
|
|
selection.check("e")
|
|
|
|
|
|
|
|
def test_moving_to_previous_char(self, caret, selection):
|
|
|
|
caret.move_to_end_of_word()
|
|
|
|
caret.move_to_prev_char()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_end_of_word()
|
|
|
|
selection.check("e")
|
|
|
|
|
|
|
|
|
|
|
|
def test_drop_selection(caret, selection):
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_end_of_word()
|
|
|
|
caret.drop_selection()
|
|
|
|
selection.check("")
|
|
|
|
|
|
|
|
|
|
|
|
class TestSearch:
|
|
|
|
|
|
|
|
# https://bugreports.qt.io/browse/QTBUG-60673
|
|
|
|
|
|
|
|
@pytest.mark.qtbug60673
|
2018-09-08 12:26:00 +02:00
|
|
|
@pytest.mark.no_xvfb
|
2018-09-26 11:39:52 +02:00
|
|
|
def test_yanking_a_searched_line(self, caret, selection, mode_manager, web_tab, qtbot):
|
2018-09-08 12:26:00 +02:00
|
|
|
web_tab.show()
|
2018-09-08 12:15:32 +02:00
|
|
|
mode_manager.leave(usertypes.KeyMode.caret)
|
|
|
|
|
2018-09-26 11:39:52 +02:00
|
|
|
with qtbot.wait_callback() as callback:
|
|
|
|
web_tab.search.search('fiv', result_cb=callback)
|
2018-09-27 10:06:50 +02:00
|
|
|
callback.assert_called_with(True)
|
2018-09-08 12:15:32 +02:00
|
|
|
|
|
|
|
mode_manager.enter(usertypes.KeyMode.caret)
|
|
|
|
caret.move_to_end_of_line()
|
|
|
|
selection.check('five six')
|
|
|
|
|
|
|
|
@pytest.mark.qtbug60673
|
2018-09-08 12:26:00 +02:00
|
|
|
@pytest.mark.no_xvfb
|
2018-09-26 11:39:52 +02:00
|
|
|
def test_yanking_a_searched_line_with_multiple_matches(self, caret, selection, mode_manager, web_tab, qtbot):
|
2018-09-08 12:26:00 +02:00
|
|
|
web_tab.show()
|
2018-09-08 12:15:32 +02:00
|
|
|
mode_manager.leave(usertypes.KeyMode.caret)
|
|
|
|
|
2018-09-26 11:39:52 +02:00
|
|
|
with qtbot.wait_callback() as callback:
|
|
|
|
web_tab.search.search('w', result_cb=callback)
|
2018-09-27 10:06:50 +02:00
|
|
|
callback.assert_called_with(True)
|
2018-09-08 12:15:32 +02:00
|
|
|
|
2018-09-26 11:39:52 +02:00
|
|
|
with qtbot.wait_callback() as callback:
|
|
|
|
web_tab.search.next_result(result_cb=callback)
|
2018-09-27 10:06:50 +02:00
|
|
|
callback.assert_called_with(True)
|
2018-09-08 12:15:32 +02:00
|
|
|
|
|
|
|
mode_manager.enter(usertypes.KeyMode.caret)
|
|
|
|
|
|
|
|
caret.move_to_end_of_line()
|
|
|
|
selection.check('wei drei')
|
2018-09-08 16:01:38 +02:00
|
|
|
|
|
|
|
|
|
|
|
class TestFollowSelected:
|
|
|
|
|
2018-09-14 20:23:56 +02:00
|
|
|
LOAD_STARTED_DELAY = 50
|
|
|
|
|
2018-09-14 22:49:18 +02:00
|
|
|
@pytest.fixture(params=[True, False], autouse=True)
|
|
|
|
def toggle_js(self, request, config_stub):
|
|
|
|
config_stub.val.content.javascript.enabled = request.param
|
|
|
|
|
2018-10-06 19:04:28 +02:00
|
|
|
@pytest.fixture(autouse=True)
|
|
|
|
def expose(self, web_tab):
|
|
|
|
"""Expose the web view if needed.
|
|
|
|
|
|
|
|
On QtWebKit, or Qt < 5.11 on QtWebEngine, we need to show the tab for
|
|
|
|
selections to work properly.
|
|
|
|
"""
|
|
|
|
if (web_tab.backend == usertypes.Backend.QtWebKit or
|
|
|
|
not qtutils.version_check('5.11', compiled=False)):
|
|
|
|
web_tab.container.expose()
|
|
|
|
|
2018-09-14 20:23:56 +02:00
|
|
|
def test_follow_selected_without_a_selection(self, qtbot, caret, selection, web_tab,
|
|
|
|
mode_manager):
|
2018-09-14 22:46:31 +02:00
|
|
|
caret.move_to_next_word() # Move cursor away from the link
|
2018-09-14 20:23:56 +02:00
|
|
|
mode_manager.leave(usertypes.KeyMode.caret)
|
2018-09-14 22:40:47 +02:00
|
|
|
with qtbot.wait_signal(caret.follow_selected_done):
|
2018-09-26 11:27:58 +02:00
|
|
|
with qtbot.assert_not_emitted(web_tab.load_started,
|
2018-09-26 11:39:52 +02:00
|
|
|
wait=self.LOAD_STARTED_DELAY):
|
2018-09-14 22:40:47 +02:00
|
|
|
caret.follow_selected()
|
2018-09-08 16:01:38 +02:00
|
|
|
|
2018-09-14 20:23:56 +02:00
|
|
|
def test_follow_selected_with_text(self, qtbot, caret, selection, web_tab):
|
2018-09-08 16:01:38 +02:00
|
|
|
caret.move_to_next_word()
|
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_end_of_word()
|
2018-09-14 22:40:47 +02:00
|
|
|
with qtbot.wait_signal(caret.follow_selected_done):
|
2018-09-26 11:27:58 +02:00
|
|
|
with qtbot.assert_not_emitted(web_tab.load_started,
|
2018-09-26 11:39:52 +02:00
|
|
|
wait=self.LOAD_STARTED_DELAY):
|
2018-09-14 22:40:47 +02:00
|
|
|
caret.follow_selected()
|
2018-09-08 16:01:38 +02:00
|
|
|
|
|
|
|
def test_follow_selected_with_link(self, caret, selection, config_stub,
|
2018-09-14 22:49:18 +02:00
|
|
|
qtbot, web_tab):
|
2018-09-08 16:01:38 +02:00
|
|
|
selection.toggle()
|
|
|
|
caret.move_to_end_of_word()
|
|
|
|
with qtbot.wait_signal(web_tab.load_finished):
|
2018-09-15 20:46:11 +02:00
|
|
|
with qtbot.wait_signal(caret.follow_selected_done):
|
|
|
|
caret.follow_selected()
|
2018-09-08 16:01:38 +02:00
|
|
|
assert web_tab.url().path() == '/data/hello.txt'
|