mirror of
https://github.com/sezanzeb/input-remapper
synced 2024-11-12 01:10:38 +00:00
168 lines
5.4 KiB
Python
168 lines
5.4 KiB
Python
#!/usr/bin/python3
|
|
# -*- coding: utf-8 -*-
|
|
# input-remapper - GUI for device specific keyboard mappings
|
|
# Copyright (C) 2023 sezanzeb <proxima@sezanzeb.de>
|
|
#
|
|
# 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/>.
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import os
|
|
import sys
|
|
import tracemalloc
|
|
|
|
tracemalloc.start()
|
|
|
|
# ensure nothing has loaded
|
|
if module := sys.modules.get("inputremapper"):
|
|
imported = [m for m in module.__dict__ if not m.startswith("__")]
|
|
raise AssertionError(
|
|
f"The modules {imported} from inputremapper where already imported, this can "
|
|
f"cause issues with the tests. Make sure to always import tests.test before any"
|
|
f" inputremapper module."
|
|
)
|
|
try:
|
|
sys.modules.get("tests.test").main
|
|
raise AssertionError(
|
|
"test.py was already imported. "
|
|
"Always use 'from tests.test import ...' "
|
|
"not 'from test import ...' to import this"
|
|
)
|
|
# have fun debugging infinitely blocking tests without this
|
|
except AttributeError:
|
|
pass
|
|
|
|
|
|
def get_project_root():
|
|
"""Find the projects root, i.e. the uppermost directory of the repo."""
|
|
# when tests are started in pycharm via the green arrow, the working directory
|
|
# is not the project root. Go up until it is found.
|
|
root = os.getcwd()
|
|
for _ in range(10):
|
|
if "setup.py" in os.listdir(root):
|
|
return root
|
|
|
|
root = os.path.dirname(root)
|
|
|
|
raise Exception("Could not find project root")
|
|
|
|
|
|
# make sure the "tests" module visible
|
|
sys.path.append(get_project_root())
|
|
if __name__ == "__main__":
|
|
# import this file to itself to make sure is not run twice and all global
|
|
# variables end up in sys.modules
|
|
# https://stackoverflow.com/questions/13181559/importing-modules-main-vs-import-as-module
|
|
import tests.test
|
|
|
|
tests.test.main()
|
|
|
|
import unittest
|
|
import subprocess
|
|
|
|
os.environ["UNITTEST"] = "1"
|
|
|
|
from tests.lib.fixtures import fixtures
|
|
from tests.lib.pipes import setup_pipe
|
|
from tests.lib.patches import (
|
|
patch_paths,
|
|
patch_events,
|
|
patch_os_system,
|
|
patch_check_output,
|
|
patch_regrab_timeout,
|
|
patch_is_running,
|
|
patch_evdev,
|
|
)
|
|
from tests.lib.cleanup import cleanup
|
|
from tests.lib.logger import update_inputremapper_verbosity
|
|
|
|
|
|
def is_service_running():
|
|
"""Check if the daemon is running."""
|
|
try:
|
|
subprocess.check_output(["pgrep", "-f", "input-remapper-service"])
|
|
return True
|
|
except subprocess.CalledProcessError:
|
|
return False
|
|
|
|
|
|
if is_service_running():
|
|
# let tests control daemon existance
|
|
raise Exception("Expected the service not to be running already.")
|
|
|
|
|
|
# make sure those pipes exist before any process (the reader-service) gets forked,
|
|
# so that events can be pushed after the fork.
|
|
for _fixture in fixtures:
|
|
setup_pipe(_fixture)
|
|
|
|
|
|
# applying patches before importing input-remappers modules is important, otherwise
|
|
# input-remapper might use non-patched modules. Importing modules from inputremapper
|
|
# just-in-time in the test-setup functions instead of globally helps. This way,
|
|
# it is ensured that the patches on evdev and such are already applied, without having
|
|
# to take care about ordering the files in a special way.
|
|
patch_paths()
|
|
patch_evdev()
|
|
patch_events()
|
|
patch_os_system()
|
|
patch_check_output()
|
|
patch_regrab_timeout()
|
|
patch_is_running()
|
|
# patch_warnings()
|
|
|
|
|
|
update_inputremapper_verbosity()
|
|
|
|
|
|
def main():
|
|
cleanup()
|
|
# https://docs.python.org/3/library/argparse.html
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
# repeated argument 0 or more times with modules
|
|
parser.add_argument("modules", type=str, nargs="*")
|
|
# start-dir value if not using modules, allows eg python tests/test.py --start-dir unit
|
|
parser.add_argument("--start-dir", type=str, default=".")
|
|
parsed_args = parser.parse_args() # takes from sys.argv by default
|
|
modules = parsed_args.modules
|
|
|
|
# discoverer is really convenient, but it can't find a specific test
|
|
# in all of the available tests like unittest.main() does...,
|
|
# so provide both options.
|
|
if len(modules) > 0:
|
|
# for example
|
|
# `tests/test.py integration.test_gui.TestGui.test_can_start`
|
|
# or `tests/test.py integration.test_gui integration.test_daemon`
|
|
testsuite = unittest.defaultTestLoader.loadTestsFromNames(modules)
|
|
else:
|
|
# run all tests by default
|
|
testsuite = unittest.defaultTestLoader.discover(
|
|
parsed_args.start_dir, pattern="test_*.py"
|
|
)
|
|
|
|
# add a newline to each "qux (foo.bar)..." output before each test,
|
|
# because the first log will be on the same line otherwise
|
|
original_start_test = unittest.TextTestResult.startTest
|
|
|
|
def start_test(self, test):
|
|
original_start_test(self, test)
|
|
print()
|
|
|
|
unittest.TextTestResult.startTest = start_test
|
|
result = unittest.TextTestRunner(verbosity=2).run(testsuite)
|
|
sys.exit(not result.wasSuccessful())
|