chore(repo): baseline du fork input-remapper (upstream v2.2.1)
Le dépôt ne contenait que README.md ; ajout de l'intégralité du code fonctionnel du fork comme socle stable de la branche de release. L'état runtime d'orchestration (.ideai/) est exclu du suivi. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
259
tests/system/gui/test_autocompletion.py
Normal file
259
tests/system/gui/test_autocompletion.py
Normal file
@ -0,0 +1,259 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# input-remapper - GUI for device specific keyboard mappings
|
||||
# Copyright (C) 2025 sezanzeb <b8x45ygc9@mozmail.com>
|
||||
#
|
||||
# This file is part of input-remapper.
|
||||
#
|
||||
# input-remapper 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.
|
||||
#
|
||||
# input-remapper 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 input-remapper. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import time
|
||||
import unittest
|
||||
|
||||
import gi
|
||||
|
||||
from inputremapper.gui.autocompletion import (
|
||||
get_incomplete_parameter,
|
||||
get_incomplete_function_name,
|
||||
)
|
||||
|
||||
gi.require_version("Gdk", "3.0")
|
||||
gi.require_version("Gtk", "3.0")
|
||||
gi.require_version("GtkSource", "4")
|
||||
gi.require_version("GLib", "2.0")
|
||||
from gi.repository import Gtk, Gdk
|
||||
|
||||
from inputremapper.configs.keyboard_layout import keyboard_layout
|
||||
from inputremapper.gui.utils import gtk_iteration
|
||||
|
||||
from tests.lib.test_setup import test_setup
|
||||
from tests.system.gui.gui_test_base import GuiTestBase
|
||||
|
||||
|
||||
@test_setup
|
||||
class TestAutocompletion(GuiTestBase):
|
||||
def press_key(self, keyval):
|
||||
event = Gdk.EventKey()
|
||||
event.keyval = keyval
|
||||
self.user_interface.autocompletion.navigate(None, event)
|
||||
|
||||
def get_suggestions(self, autocompletion):
|
||||
return [
|
||||
row.get_children()[0].get_text()
|
||||
for row in autocompletion.list_box.get_children()
|
||||
]
|
||||
|
||||
def test_get_incomplete_parameter(self):
|
||||
def test(text, expected):
|
||||
text_view = Gtk.TextView()
|
||||
Gtk.TextView.do_insert_at_cursor(text_view, text)
|
||||
text_iter = text_view.get_iter_at_location(0, 0)[1]
|
||||
text_iter.set_offset(len(text))
|
||||
self.assertEqual(get_incomplete_parameter(text_iter), expected)
|
||||
|
||||
test("bar(foo", "foo")
|
||||
test("bar(a=foo", "foo")
|
||||
test("bar(qux, foo", "foo")
|
||||
test("foo", "foo")
|
||||
test("bar + foo", "foo")
|
||||
|
||||
def test_get_incomplete_function_name(self):
|
||||
def test(text, expected):
|
||||
text_view = Gtk.TextView()
|
||||
Gtk.TextView.do_insert_at_cursor(text_view, text)
|
||||
text_iter = text_view.get_iter_at_location(0, 0)[1]
|
||||
text_iter.set_offset(len(text))
|
||||
self.assertEqual(get_incomplete_function_name(text_iter), expected)
|
||||
|
||||
test("bar().foo", "foo")
|
||||
test("bar()\n.foo", "foo")
|
||||
test("bar().\nfoo", "foo")
|
||||
test("bar(\nfoo", "foo")
|
||||
test("bar(\nqux=foo", "foo")
|
||||
test("bar(KEY_A,\nfoo", "foo")
|
||||
test("foo", "foo")
|
||||
|
||||
def test_autocomplete_names(self):
|
||||
autocompletion = self.user_interface.autocompletion
|
||||
|
||||
def setup(text):
|
||||
self.set_focus(self.code_editor)
|
||||
self.code_editor.get_buffer().set_text("")
|
||||
Gtk.TextView.do_insert_at_cursor(self.code_editor, text)
|
||||
self.throttle(200)
|
||||
text_iter = self.code_editor.get_iter_at_location(0, 0)[1]
|
||||
text_iter.set_offset(len(text))
|
||||
|
||||
setup("disa")
|
||||
self.assertNotIn("KEY_A", self.get_suggestions(autocompletion))
|
||||
self.assertIn("disable", self.get_suggestions(autocompletion))
|
||||
|
||||
setup(" + _A")
|
||||
self.assertIn("KEY_A", self.get_suggestions(autocompletion))
|
||||
self.assertNotIn("disable", self.get_suggestions(autocompletion))
|
||||
|
||||
def test_autocomplete_key(self):
|
||||
self.controller.update_mapping(output_symbol="")
|
||||
gtk_iteration()
|
||||
|
||||
self.set_focus(self.code_editor)
|
||||
self.code_editor.get_buffer().set_text("")
|
||||
|
||||
complete_key_name = "Test_Foo_Bar"
|
||||
|
||||
keyboard_layout.clear()
|
||||
keyboard_layout._set(complete_key_name, 1)
|
||||
keyboard_layout._set("KEY_A", 30) # we need this for the UIMapping to work
|
||||
|
||||
# it can autocomplete a combination inbetween other things
|
||||
incomplete = "qux_1\n + + qux_2"
|
||||
Gtk.TextView.do_insert_at_cursor(self.code_editor, incomplete)
|
||||
Gtk.TextView.do_move_cursor(
|
||||
self.code_editor,
|
||||
Gtk.MovementStep.VISUAL_POSITIONS,
|
||||
-8,
|
||||
False,
|
||||
)
|
||||
|
||||
Gtk.TextView.do_insert_at_cursor(self.code_editor, "foo")
|
||||
self.throttle(200)
|
||||
gtk_iteration()
|
||||
|
||||
autocompletion = self.user_interface.autocompletion
|
||||
self.assertTrue(autocompletion.visible)
|
||||
|
||||
self.press_key(Gdk.KEY_Down)
|
||||
self.press_key(Gdk.KEY_Return)
|
||||
self.throttle(200)
|
||||
gtk_iteration()
|
||||
|
||||
# the first suggestion should have been selected
|
||||
|
||||
modified_symbol = self.get_code_input()
|
||||
self.assertEqual(modified_symbol, f"qux_1\n + {complete_key_name} + qux_2")
|
||||
|
||||
# try again, but a whitespace completes the word and so no autocompletion
|
||||
# should be shown
|
||||
Gtk.TextView.do_insert_at_cursor(self.code_editor, " + foo ")
|
||||
|
||||
time.sleep(0.11)
|
||||
gtk_iteration()
|
||||
|
||||
self.assertFalse(autocompletion.visible)
|
||||
|
||||
def test_autocomplete_function(self):
|
||||
self.controller.update_mapping(output_symbol="")
|
||||
gtk_iteration()
|
||||
|
||||
source_view = self.focus_source_view()
|
||||
|
||||
incomplete = "key(KEY_A).\nepea"
|
||||
Gtk.TextView.do_insert_at_cursor(source_view, incomplete)
|
||||
|
||||
time.sleep(0.11)
|
||||
gtk_iteration()
|
||||
|
||||
autocompletion = self.user_interface.autocompletion
|
||||
self.assertTrue(autocompletion.visible)
|
||||
|
||||
self.press_key(Gdk.KEY_Down)
|
||||
self.press_key(Gdk.KEY_Return)
|
||||
|
||||
# the first suggestion should have been selected
|
||||
modified_symbol = self.get_code_input()
|
||||
self.assertEqual(modified_symbol, "key(KEY_A).\nrepeat")
|
||||
|
||||
def test_close_autocompletion(self):
|
||||
self.controller.update_mapping(output_symbol="")
|
||||
gtk_iteration()
|
||||
|
||||
source_view = self.focus_source_view()
|
||||
|
||||
Gtk.TextView.do_insert_at_cursor(source_view, "KEY_")
|
||||
|
||||
time.sleep(0.11)
|
||||
gtk_iteration()
|
||||
|
||||
autocompletion = self.user_interface.autocompletion
|
||||
self.assertTrue(autocompletion.visible)
|
||||
|
||||
self.press_key(Gdk.KEY_Down)
|
||||
self.press_key(Gdk.KEY_Escape)
|
||||
|
||||
self.assertFalse(autocompletion.visible)
|
||||
|
||||
symbol = self.get_code_input()
|
||||
self.assertEqual(symbol, "KEY_")
|
||||
|
||||
def test_writing_still_works(self):
|
||||
self.controller.update_mapping(output_symbol="")
|
||||
gtk_iteration()
|
||||
source_view = self.focus_source_view()
|
||||
|
||||
Gtk.TextView.do_insert_at_cursor(source_view, "KEY_")
|
||||
|
||||
autocompletion = self.user_interface.autocompletion
|
||||
|
||||
time.sleep(0.11)
|
||||
gtk_iteration()
|
||||
self.assertTrue(autocompletion.visible)
|
||||
|
||||
# writing still works while an entry is selected
|
||||
self.press_key(Gdk.KEY_Down)
|
||||
|
||||
Gtk.TextView.do_insert_at_cursor(source_view, "A")
|
||||
|
||||
time.sleep(0.11)
|
||||
gtk_iteration()
|
||||
self.assertTrue(autocompletion.visible)
|
||||
|
||||
Gtk.TextView.do_insert_at_cursor(source_view, "1234foobar")
|
||||
|
||||
time.sleep(0.11)
|
||||
gtk_iteration()
|
||||
# no key matches this completion, so it closes again
|
||||
self.assertFalse(autocompletion.visible)
|
||||
|
||||
def test_cycling(self):
|
||||
self.controller.update_mapping(output_symbol="")
|
||||
gtk_iteration()
|
||||
source_view = self.focus_source_view()
|
||||
|
||||
Gtk.TextView.do_insert_at_cursor(source_view, "KEY_")
|
||||
|
||||
autocompletion = self.user_interface.autocompletion
|
||||
|
||||
time.sleep(0.11)
|
||||
gtk_iteration()
|
||||
self.assertTrue(autocompletion.visible)
|
||||
|
||||
self.assertEqual(
|
||||
autocompletion.scrolled_window.get_vadjustment().get_value(), 0
|
||||
)
|
||||
|
||||
# cycle to the end of the list because there is no element higher than index 0
|
||||
self.press_key(Gdk.KEY_Up)
|
||||
self.assertGreater(
|
||||
autocompletion.scrolled_window.get_vadjustment().get_value(), 0
|
||||
)
|
||||
|
||||
# go back to the start, because it can't go down further
|
||||
self.press_key(Gdk.KEY_Down)
|
||||
self.assertEqual(
|
||||
autocompletion.scrolled_window.get_vadjustment().get_value(), 0
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user