more tests

This commit is contained in:
sezanzeb 2020-11-29 16:21:34 +01:00 committed by sezanzeb
parent 01d29a5f72
commit b00de9f16a
4 changed files with 299 additions and 23 deletions

View File

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

View File

@ -74,7 +74,7 @@ class FakeDropdown(Gtk.ComboBoxText):
return self.name
class Integration(unittest.TestCase):
class TestIntegration(unittest.TestCase):
"""For tests that use 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.assertTrue(self.window.window.get_visible())
def test_adds_empty_rows(self):
rows = len(self.window.get('key_list').get_children())
self.assertEqual(rows, 1)
def test_row_simple(self):
rows = self.window.get('key_list').get_children()
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)
gtk_iteration()
self.assertEqual(len(self.window.get('key_list').get_children()), 1)
rows = len(self.window.get('key_list').get_children())
self.assertEqual(rows, 2)
row.character_input.set_text('Shift_L')
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."""
# wait for the window to create a new empty row if needed
time.sleep(0.2)
@ -168,32 +188,53 @@ class Integration(unittest.TestCase):
rows = self.get_rows()
row = rows[-1]
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.window.window.set_focus(row.keycode)
if char and not 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)
pending_events[self.window.selected_device] = [
Event(evdev.events.EV_KEY, keycode - 8, 1)
]
self.window.window.set_focus(row.keycode_input)
self.window.on_window_event(None, None)
if code:
# modifies the keycode in the row not by writing into the input,
# but by sending an event
pending_events[self.window.selected_device] = [
Event(evdev.events.EV_KEY, code - 8, 1)
]
self.window.on_window_event(None, None)
self.assertEqual(int(row.keycode.get_label()), keycode)
if success:
self.assertEqual(row.get_keycode(), code)
self.assertIn(
'changed',
row.get_style_context().list_classes()
)
# set the character to make the new row complete
row.character_input.set_text(character)
if not success:
self.assertIsNone(row.get_keycode())
self.assertIsNone(row.get_character())
self.assertNotIn('changed', row.get_style_context().list_classes())
self.assertIn('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
def test_rows(self):
"""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
self.change_empty_row(10, 'a')
self.change_empty_row(11, 'b')
self.change_empty_row(10, 'a', code_first=False)
self.change_empty_row(11, 'k(b).k(c)')
# one empty row added automatically again
time.sleep(0.2)
@ -201,10 +242,10 @@ class Integration(unittest.TestCase):
# sleep one more time because it's funny to watch the ui
# during the test, how rows turn blue and stuff
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(11), 'b')
self.assertEqual(custom_mapping.get_character(11), 'k(b).k(c)')
self.assertTrue(custom_mapping.changed)
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(11), 'b')
self.assertEqual(custom_mapping.get_character(11), 'k(b).k(c)')
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):
custom_mapping.change(14, 'a', None)
self.assertEqual(self.window.selected_preset, 'new preset')

130
tests/testcases/logger.py Normal file
View File

@ -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()

View File

@ -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()