From adaf7488523377da5fc8ecf6c765a37be5808ca7 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 16 Oct 2016 20:36:27 +0530 Subject: [PATCH] Framework for testing --- kitty/data_types.py | 6 +-- kitty_tests/__init__.py | 20 +++++++++ kitty_tests/datatypes.py | 23 ++++++++++ test.py | 94 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 kitty_tests/__init__.py create mode 100644 kitty_tests/datatypes.py create mode 100755 test.py diff --git a/kitty/data_types.py b/kitty/data_types.py index c8ab750a2..1c490ea66 100644 --- a/kitty/data_types.py +++ b/kitty/data_types.py @@ -45,8 +45,7 @@ class Cursor: class Line: - __slots__ = 'char fg bg bold italic reverse strikethrough decoration decoration_fg width'.split() - continued = False + __slots__ = 'char fg bg bold italic reverse strikethrough decoration decoration_fg width continued'.split() def __init__(self, sz: int, other=None): if other is None: @@ -61,6 +60,7 @@ class Line: self.decoration = z1[:] self.decoration_fg = z4[:] self.width = z1[:] + self.continued = False else: self.char = other.char[:] self.fg = other.fg[:] @@ -149,7 +149,7 @@ class Line: self.copy_slice(src_start, dest_start, snum) def __str__(self) -> str: - return ''.join(map(ord, filter(None, self.char))) + return ''.join(map(chr, filter(None, self.char))) def __repr__(self) -> str: return repr(str(self)) diff --git a/kitty_tests/__init__.py b/kitty_tests/__init__.py new file mode 100644 index 000000000..004698e12 --- /dev/null +++ b/kitty_tests/__init__.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +# License: GPL v3 Copyright: 2016, Kovid Goyal + +from unittest import TestCase + + +class BaseTest(TestCase): + + ae = TestCase.assertEqual + + +def set_text_in_line(line, text, offset=0): + pos = offset + for ch in text: + line.char[pos] = ord(ch) + line.width[pos] = 1 + pos += 1 + if pos >= len(line): + break diff --git a/kitty_tests/datatypes.py b/kitty_tests/datatypes.py new file mode 100644 index 000000000..30900cac0 --- /dev/null +++ b/kitty_tests/datatypes.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +# License: GPL v3 Copyright: 2016, Kovid Goyal + +from . import BaseTest, set_text_in_line + +from kitty.data_types import Line + + +class TestDataTypes(BaseTest): + + def test_line_ops(self): + t = 'Testing with simple text' + l = Line(len(t)) + set_text_in_line(l, t) + self.ae(str(l), t) + self.ae(str(l.copy()), t) + l.continued = False + l2 = l.copy() + self.assertFalse(l2.continued) + self.ae(l, l2) + l2.char[1] = 23 + self.assertNotEqual(l, l2) diff --git a/test.py b/test.py new file mode 100755 index 000000000..f34d4f595 --- /dev/null +++ b/test.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +# vim:fileencoding=utf-8 +# License: GPL v3 Copyright: 2016, Kovid Goyal + +import unittest +import os +import sys +import importlib + +base = os.path.dirname(os.path.abspath(__file__)) + + +def init_env(): + sys.path.insert(0, base) + + +def itertests(suite): + stack = [suite] + while stack: + suite = stack.pop() + for test in suite: + if isinstance(test, unittest.TestSuite): + stack.append(test) + continue + if test.__class__.__name__ == 'ModuleImportFailure': + raise Exception('Failed to import a test module: %s' % test) + yield test + + +def find_tests_in_dir(path, excludes=('main.py',)): + package = os.path.relpath(path, base).replace(os.sep, '/').replace('/', '.') + items = os.listdir(path) + suits = [] + for x in items: + if x.endswith('.py') and x not in excludes: + m = importlib.import_module(package + '.' + x.partition('.')[0]) + suits.append(unittest.defaultTestLoader.loadTestsFromModule(m)) + return unittest.TestSuite(suits) + + +def filter_tests(suite, test_ok): + ans = unittest.TestSuite() + added = set() + for test in itertests(suite): + if test_ok(test) and test not in added: + ans.addTest(test) + added.add(test) + return ans + + +def filter_tests_by_name(suite, *names): + names = {x if x.startswith('test_') else 'test_' + x for x in names} + + def q(test): + return test._testMethodName in names + return filter_tests(suite, q) + + +def filter_tests_by_module(suite, *names): + names = frozenset(names) + + def q(test): + m = test.__class__.__module__.rpartition('.')[-1] + return m in names + return filter_tests(suite, q) + + +def run_tests(find_tests, verbosity=4): + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('name', nargs='?', default=None, + help='The name of the test to run, for e.g. writing.WritingTest.many_many_basic or .many_many_basic for a shortcut') + args = parser.parse_args() + tests = find_tests() + if args.name: + if args.name.startswith('.'): + tests = filter_tests_by_name(tests, args.name[1:]) + else: + tests = filter_tests_by_module(tests, args.name) + if not tests._tests: + raise SystemExit('No test named %s found' % args.name) + run_cli(tests, verbosity) + + +def run_cli(suite, verbosity=4): + r = unittest.TextTestRunner + r.resultclass = unittest.TextTestResult + init_env() + result = r(verbosity=verbosity).run(suite) + if not result.wasSuccessful(): + raise SystemExit(1) + +if __name__ == '__main__': + run_cli(find_tests_in_dir(os.path.join(base, 'kitty_tests')))