more tests

pull/14/head
sezanzeb 4 years ago
parent 2235fb6fcf
commit 7e1193583a

@ -22,6 +22,7 @@
"""Sets up key-mapper for the tests and runs them.""" """Sets up key-mapper for the tests and runs them."""
import os
import sys import sys
import time import time
import unittest import unittest
@ -34,6 +35,11 @@ import evdev
from keymapper.logger import update_verbosity from keymapper.logger import update_verbosity
assert not os.getcwd().endswith('tests')
sys.path = [os.path.abspath('.')] + sys.path
tmp = '/tmp/key-mapper-test' tmp = '/tmp/key-mapper-test'
uinput_write_history = [] uinput_write_history = []
# for tests that makes the injector create its processes # for tests that makes the injector create its processes

@ -74,7 +74,7 @@ class FakeDropdown(Gtk.ComboBoxText):
return self.name return self.name
class Integration(unittest.TestCase): class TestIntegration(unittest.TestCase):
"""For tests that use the window. """For tests that use the window.
Try to modify the configuration only by calling functions of the window. Try to modify the configuration only by calling functions of the window.
@ -147,18 +147,38 @@ class Integration(unittest.TestCase):
self.assertIsNotNone(self.window) self.assertIsNotNone(self.window)
self.assertTrue(self.window.window.get_visible()) self.assertTrue(self.window.window.get_visible())
def test_adds_empty_rows(self): def test_row_simple(self):
rows = len(self.window.get('key_list').get_children()) rows = self.window.get('key_list').get_children()
self.assertEqual(rows, 1) self.assertEqual(len(rows), 1)
row = rows[0]
row.set_new_keycode(None)
self.assertIsNone(row.get_keycode())
self.assertEqual(len(custom_mapping), 0)
row.set_new_keycode(30)
self.assertEqual(len(custom_mapping), 0)
self.assertEqual(row.get_keycode(), 30)
row.set_new_keycode(30)
self.assertEqual(len(custom_mapping), 0)
self.assertEqual(row.get_keycode(), 30)
custom_mapping.change(13, 'a', None)
time.sleep(0.2) time.sleep(0.2)
gtk_iteration() gtk_iteration()
self.assertEqual(len(self.window.get('key_list').get_children()), 1)
rows = len(self.window.get('key_list').get_children()) row.character_input.set_text('Shift_L')
self.assertEqual(rows, 2) self.assertEqual(len(custom_mapping), 1)
def change_empty_row(self, keycode, character): time.sleep(0.2)
gtk_iteration()
self.assertEqual(len(self.window.get('key_list').get_children()), 2)
self.assertEqual(custom_mapping.get_keycode('Shift_L'), 30)
self.assertEqual(row.get_character(), 'Shift_L')
self.assertEqual(row.get_keycode(), 30)
def change_empty_row(self, code, char, code_first=True, success=True):
"""Modify the one empty row that always exists.""" """Modify the one empty row that always exists."""
# wait for the window to create a new empty row if needed # wait for the window to create a new empty row if needed
time.sleep(0.2) time.sleep(0.2)
@ -168,32 +188,53 @@ class Integration(unittest.TestCase):
rows = self.get_rows() rows = self.get_rows()
row = rows[-1] row = rows[-1]
self.assertNotIn('changed', row.get_style_context().list_classes()) self.assertNotIn('changed', row.get_style_context().list_classes())
self.assertIsNone(row.keycode.get_label()) self.assertIsNone(row.keycode_input.get_label())
self.assertEqual(row.character_input.get_text(), '') self.assertEqual(row.character_input.get_text(), '')
self.window.window.set_focus(row.keycode) if char and not code_first:
# set the character to make the new row complete
pending_events[self.window.selected_device] = [ self.assertIsNone(row.get_character())
Event(evdev.events.EV_KEY, keycode - 8, 1) row.character_input.set_text(char)
] self.assertEqual(row.get_character(), char)
self.window.on_window_event(None, None) self.window.window.set_focus(row.keycode_input)
self.assertEqual(int(row.keycode.get_label()), keycode) if code:
# modifies the keycode in the row not by writing into the input,
# set the character to make the new row complete # but by sending an event
row.character_input.set_text(character) pending_events[self.window.selected_device] = [
Event(evdev.events.EV_KEY, code - 8, 1)
self.assertIn('changed', row.get_style_context().list_classes()) ]
self.window.on_window_event(None, None)
if success:
self.assertEqual(row.get_keycode(), code)
self.assertIn(
'changed',
row.get_style_context().list_classes()
)
if not success:
self.assertIsNone(row.get_keycode())
self.assertIsNone(row.get_character())
self.assertNotIn('changed', row.get_style_context().list_classes())
if char and code_first:
# set the character to make the new row complete
self.assertIsNone(row.get_character())
row.character_input.set_text(char)
self.assertEqual(row.get_character(), char)
return row return row
def test_rows(self): def test_rows(self):
"""Comprehensive test for rows.""" """Comprehensive test for rows."""
# how many rows there should be in the end
num_rows_target = 3
# add two rows by modifiying the one empty row that exists # add two rows by modifiying the one empty row that exists
self.change_empty_row(10, 'a') self.change_empty_row(10, 'a', code_first=False)
self.change_empty_row(11, 'b') self.change_empty_row(11, 'k(b).k(c)')
# one empty row added automatically again # one empty row added automatically again
time.sleep(0.2) time.sleep(0.2)
@ -201,10 +242,10 @@ class Integration(unittest.TestCase):
# sleep one more time because it's funny to watch the ui # sleep one more time because it's funny to watch the ui
# during the test, how rows turn blue and stuff # during the test, how rows turn blue and stuff
time.sleep(0.2) time.sleep(0.2)
self.assertEqual(len(self.get_rows()), 3) self.assertEqual(len(self.get_rows()), num_rows_target)
self.assertEqual(custom_mapping.get_character(10), 'a') self.assertEqual(custom_mapping.get_character(10), 'a')
self.assertEqual(custom_mapping.get_character(11), 'b') self.assertEqual(custom_mapping.get_character(11), 'k(b).k(c)')
self.assertTrue(custom_mapping.changed) self.assertTrue(custom_mapping.changed)
self.window.on_save_preset_clicked(None) self.window.on_save_preset_clicked(None)
@ -227,9 +268,54 @@ class Integration(unittest.TestCase):
) )
self.assertEqual(custom_mapping.get_character(10), 'c') self.assertEqual(custom_mapping.get_character(10), 'c')
self.assertEqual(custom_mapping.get_character(11), 'b') self.assertEqual(custom_mapping.get_character(11), 'k(b).k(c)')
self.assertTrue(custom_mapping.changed) self.assertTrue(custom_mapping.changed)
# try to add a duplicate keycode, it should be ignored
self.change_empty_row(11, 'd', success=False)
self.assertEqual(custom_mapping.get_character(11), 'k(b).k(c)')
self.assertIsNone(custom_mapping.get_keycode('d'))
# and the number of rows shouldn't change
self.assertEqual(len(self.get_rows()), num_rows_target)
def test_remove_row(self):
"""Comprehensive test for rows 2."""
# sleeps are added to be able to visually follow and debug the test
# add two rows by modifiying the one empty row that exists
row_1 = self.change_empty_row(10, 'a')
row_2 = self.change_empty_row(11, 'b')
row_3 = self.change_empty_row(None, 'c')
# no empty row added because one is unfinished
time.sleep(0.2)
gtk_iteration()
self.assertEqual(len(self.get_rows()), 3)
self.assertEqual(custom_mapping.get_character(11), 'b')
self.assertEqual(custom_mapping.get_keycode('b'), 11)
def remove(row, code, char, num_rows_after):
if code is not None and char is not None:
self.assertEqual(custom_mapping.get_character(code), char)
self.assertEqual(custom_mapping.get_keycode(char), code)
self.assertEqual(row.get_character(), char)
self.assertEqual(row.get_keycode(), code)
row.on_delete_button_clicked()
time.sleep(0.2)
gtk_iteration()
self.assertIsNone(row.get_keycode())
self.assertIsNone(row.get_character())
self.assertIsNone(custom_mapping.get_keycode(char))
self.assertIsNone(custom_mapping.get_character(code))
self.assertEqual(len(self.get_rows()), num_rows_after)
remove(row_1, 10, 'a', 2)
remove(row_2, 11, 'b', 1)
# there is no empty row at the moment, so after removing that one,
# which is the only row, one empty row will be there. So the number
# of rows won't change.
remove(row_3, None, 'c', 1)
def test_rename_and_save(self): def test_rename_and_save(self):
custom_mapping.change(14, 'a', None) custom_mapping.change(14, 'a', None)
self.assertEqual(self.window.selected_preset, 'new preset') self.assertEqual(self.window.selected_preset, 'new preset')

@ -0,0 +1,130 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# key-mapper - GUI for device specific keyboard mappings
# Copyright (C) 2020 sezanzeb <proxima@hip70890b.de>
#
# This file is part of key-mapper.
#
# key-mapper 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.
#
# key-mapper 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 key-mapper. If not, see <https://www.gnu.org/licenses/>.
import os
import shutil
import unittest
import logging
from keymapper.logger import logger, add_filehandler, update_verbosity, \
log_info
from test import tmp
class TestLogger(unittest.TestCase):
def tearDown(self):
# remove the file handler
logger.handlers = [
handler for handler in logger.handlers
if not isinstance(logger.handlers, logging.FileHandler)
]
path = os.path.join(tmp, 'logger-test')
if os.path.exists(path):
shutil.rmtree(path)
update_verbosity(debug=True)
def test_log_info(self):
update_verbosity(debug=False)
path = add_filehandler(os.path.join(tmp, 'logger-test'))
log_info()
with open(path, 'r') as f:
content = f.read().lower()
self.assertIn('key-mapper', content)
def test_makes_path(self):
path = os.path.join(tmp, 'logger-test')
if os.path.exists(path):
shutil.rmtree(path)
new_path = os.path.join(tmp, 'logger-test', 'a', 'b', 'c')
add_filehandler(new_path)
self.assertTrue(os.path.exists(new_path))
def test_clears_log(self):
path = os.path.join(tmp, 'logger-test', 'log')
os.makedirs(os.path.dirname(path), exist_ok=True)
os.mknod(path)
with open(path, 'w') as f:
f.write('foo')
add_filehandler(os.path.join(tmp, 'logger-test'))
with open(path, 'r') as f:
self.assertEqual(f.read(), '')
def test_debug(self):
path = add_filehandler(os.path.join(tmp, 'logger-test'))
logger.error('abc')
logger.warn('foo')
logger.info('123')
logger.debug('456')
logger.spam('789')
with open(path, 'r') as f:
content = f.read().lower()
self.assertIn('logger.py', content)
self.assertIn('line', content)
self.assertIn('error', content)
self.assertIn('abc', content)
self.assertIn('warn', content)
self.assertIn('foo', content)
self.assertIn('info', content)
self.assertIn('123', content)
self.assertIn('debug', content)
self.assertIn('456', content)
self.assertIn('spam', content)
self.assertIn('789', content)
def test_default(self):
path = add_filehandler(os.path.join(tmp, 'logger-test'))
update_verbosity(debug=False)
logger.error('abc')
logger.warn('foo')
logger.info('123')
logger.debug('456')
logger.spam('789')
with open(path, 'r') as f:
content = f.read().lower()
self.assertNotIn('logger.py', content)
self.assertNotIn('line', content)
self.assertIn('error', content)
self.assertIn('abc', content)
self.assertIn('warn', content)
self.assertIn('foo', content)
self.assertNotIn('info', content)
self.assertIn('123', content)
self.assertNotIn('debug', content)
self.assertNotIn('456', content)
self.assertNotIn('spam', content)
self.assertNotIn('789', content)
if __name__ == "__main__":
unittest.main()

@ -0,0 +1,54 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# key-mapper - GUI for device specific keyboard mappings
# Copyright (C) 2020 sezanzeb <proxima@hip70890b.de>
#
# This file is part of key-mapper.
#
# key-mapper 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.
#
# key-mapper 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 key-mapper. If not, see <https://www.gnu.org/licenses/>.
import os
import grp
import unittest
from keymapper.dev.permissions import can_read_devices
class TestPermissions(unittest.TestCase):
def setUp(self):
self.getgrnam = grp.getgrnam
def tearDown(self):
grp.getgrnam = self.getgrnam
def test_cannot_access(self):
class Grnam:
def __init__(self, group):
self.gr_mem = []
grp.getgrnam = Grnam
self.assertFalse(can_read_devices())
def test_can_access(self):
class Grnam:
def __init__(self, group):
self.gr_mem = [os.getlogin()]
grp.getgrnam = Grnam
self.assertTrue(can_read_devices())
if __name__ == "__main__":
unittest.main()
Loading…
Cancel
Save