diff options
Diffstat (limited to '')
100 files changed, 11683 insertions, 0 deletions
diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/__init__.py diff --git a/tests/install.sh b/tests/install.sh new file mode 100755 index 0000000..6925a34 --- /dev/null +++ b/tests/install.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +set -e +set -x + +remote_master_hex() { + local url="$1" + git ls-remote "$url" refs/heads/master | cut -f1 +} + +checkout_cached_dir() { + local url="$1" + local target="$2" + if ! test -e "$target/.version" || \ + test "$(cat "$target/.version")" != "$(remote_master_hex "$url")" ; then + rm -rf "$target" + fi + if ! test -d "$target" ; then + git clone --depth=1 "$url" "$target" + git rev-parse HEAD > "$target/.version" + rm -rf "$target"/.git + fi +} + +checkout_cached_dir git://github.com/powerline/bot-ci tests/bot-ci +checkout_cached_dir git://github.com/powerline/deps tests/bot-ci/deps + +. tests/bot-ci/scripts/common/main.sh + +mkdir -p "$HOME/opt" + +if test -n "$USE_UCS2_PYTHON" ; then + if test "$UCS2_PYTHON_VARIANT" = "2.6" ; then + pip install 'virtualenvwrapper==4.6.0' + else + pip install virtualenvwrapper + fi + set +e + . virtualenvwrapper.sh + set -e + archive="${PWD:-$(pwd)}/tests/bot-ci/deps/cpython-ucs2/cpython-ucs2-${UCS2_PYTHON_VARIANT}.tar.gz" + sh -c "cd $HOME/opt && tar xzf $archive" + PYTHON="$HOME/opt/cpython-ucs2-$UCS2_PYTHON_VARIANT/bin/python$UCS2_PYTHON_VARIANT" + export LD_LIBRARY_PATH="$HOME/opt/cpython-ucs2-$UCS2_PYTHON_VARIANT/lib${LD_LIBRARY_PATH:+:}${LD_LIBRARY_PATH}" + set +e + mkvirtualenv -p "$PYTHON" cpython-ucs2-$UCS2_PYTHON_VARIANT + set -e + . tests/bot-ci/scripts/common/main.sh + pip install --verbose --verbose --verbose . + if test "$UCS2_PYTHON_VARIANT" = "2.6" ; then + rm tests/bot-ci/deps/wheels/ucs2-CPython-${UCS2_PYTHON_VARIANT}*/pyuv*.whl + fi + pip install --no-deps tests/bot-ci/deps/wheels/ucs2-CPython-${UCS2_PYTHON_VARIANT}*/*.whl +else + pip install --verbose --verbose --verbose . + # FIXME Uv watcher sometimes misses events and INotify is not available in + # Python-2.6, thus pyuv should be removed in order for VCS tests to + # pass. + if test "$PYTHON_VERSION_MAJOR" -eq 2 && test "$PYTHON_VERSION_MINOR" -lt 7 ; then + rm tests/bot-ci/deps/wheels/$PYTHON_SUFFIX/pyuv*.whl + fi + pip install --no-deps tests/bot-ci/deps/wheels/$PYTHON_SUFFIX/*.whl +fi +if test "$PYTHON_IMPLEMENTATION" = "CPython" ; then + archive="${PWD:-$(pwd)}/tests/bot-ci/deps/zpython/zsh-${PYTHON_MM}${USE_UCS2_PYTHON:+-ucs2}.tar.gz" + sh -c "cd $HOME/opt && tar xzf $archive" +fi + +archive="${PWD:-$(pwd)}/tests/bot-ci/deps/fish/fish.tar.gz" +sh -c "cd $HOME/opt && tar xzf $archive" + +mkdir tests/vim-plugins + +for archive in "$ROOT"/tests/bot-ci/deps/vim-plugins/*.tar.gz ; do + ( + cd tests/vim-plugins + tar -xzvf "$archive" + ) +done + +true diff --git a/tests/modules/__init__.py b/tests/modules/__init__.py new file mode 100644 index 0000000..12aae20 --- /dev/null +++ b/tests/modules/__init__.py @@ -0,0 +1,94 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys +import os + +if sys.version_info < (2, 7): + from unittest2 import TestCase as _TestCase # NOQA + from unittest2 import main as _main # NOQA + from unittest2.case import SkipTest # NOQA +else: + from unittest import TestCase as _TestCase # NOQA + from unittest import main as _main # NOQA + from unittest.case import SkipTest # NOQA + +from tests.modules.lib import PowerlineSingleTest + + +class PowerlineDummyTest(object): + def __enter__(self): + return self + + def __exit__(self, *args): + pass + + def fail(self, *args, **kwargs): + pass + + def exception(self, *args, **kwargs): + pass + + +class PowerlineTestSuite(object): + def __init__(self, name): + self.name = name + + def __enter__(self): + self.saved_current_suite = os.environ['POWERLINE_CURRENT_SUITE'] + os.environ['POWERLINE_CURRENT_SUITE'] = ( + self.saved_current_suite + '/' + self.name) + self.suite = self.saved_current_suite + '/' + self.name + return self + + def __exit__(self, exc_type, exc_value, traceback): + if exc_type is not None: + self.exception( + 'suite_noexcept', + 'Exception while running test suite: {0!r}'.format(exc_value), + ) + os.environ['POWERLINE_CURRENT_SUITE'] = self.saved_current_suite + + def record_test_failure(self, fail_char, test_name, message, allow_failure=False): + if allow_failure: + fail_char = 'A' + fail_char + full_msg = '{fail_char} {suite}|{test_name} :: {message}'.format( + fail_char=fail_char, + suite=self.suite, + test_name=test_name, + message=message, + ) + with open(os.environ['FAILURES_FILE'], 'a') as ffd: + ffd.write(full_msg + '\n') + return False + + def exception(self, test_name, message, allow_failure=False): + return self.record_test_failure('E', test_name, message, allow_failure) + + def fail(self, test_name, message, allow_failure=False): + return self.record_test_failure('F', test_name, message, allow_failure) + + def test(self, name, attempts_left=0): + if not attempts_left: + return PowerlineSingleTest(self, name) + else: + return PowerlineDummyTest() + + def subsuite(self, name): + return PowerlineTestSuite(name) + + +suite = None + + +def main(*args, **kwargs): + global suite + suite = PowerlineTestSuite(sys.argv[0]) + _main(*args, **kwargs) + + +class TestCase(_TestCase): + def fail(self, msg=None): + suite.fail(self.__class__.__name__, + msg or 'Test failed without message') + super(TestCase, self).fail(*args, **kwargs) diff --git a/tests/modules/lib/__init__.py b/tests/modules/lib/__init__.py new file mode 100644 index 0000000..f3e36b8 --- /dev/null +++ b/tests/modules/lib/__init__.py @@ -0,0 +1,183 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import imp +import sys + + +class Pl(object): + def __init__(self): + self.exceptions = [] + self.errors = [] + self.warns = [] + self.debugs = [] + self.infos = [] + self.prefix = None + self.use_daemon_threads = True + + for meth in ('error', 'warn', 'debug', 'exception', 'info'): + exec(( + 'def {0}(self, msg, *args, **kwargs):\n' + ' self.{0}s.append((kwargs.get("prefix") or self.prefix, msg, args, kwargs))\n' + ).format(meth)) + + def __nonzero__(self): + return bool(self.exceptions or self.errors or self.warns) + + __bool__ = __nonzero__ + + +class Args(object): + theme_override = {} + config_override = {} + config_path = None + ext = ['shell'] + renderer_module = None + + def __init__(self, **kwargs): + self.__dict__.update(kwargs) + + +def urllib_read(query_url): + if query_url.startswith('http://ipv'): + if query_url.startswith('http://ipv4.icanhazip.com'): + return '127.0.0.1' + elif query_url.startswith('http://ipv6.icanhazip.com'): + return '2001:4801:7818:6:abc5:ba2c:ff10:275f' + elif query_url.startswith('http://geoip.nekudo.com/api/'): + return '{"city":"Meppen","country":{"name":"Germany", "code":"DE"},"location":{"accuracy_radius":100,"latitude":52.6833,"longitude":7.3167,"time_zone":"Europe\/Berlin"},"ip":"82.145.55.16"}' + elif query_url.startswith('http://query.yahooapis.com/v1/public/'): + if 'Meppen' in query_url: + return r'{"query":{"count":1,"created":"2016-05-13T19:43:18Z","lang":"en-US","results":{"channel":{"units":{"distance":"mi","pressure":"in","speed":"mph","temperature":"C"},"title":"Yahoo! Weather - Meppen, NI, DE","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-674836/","description":"Yahoo! Weather for Meppen, NI, DE","language":"en-us","lastBuildDate":"Fri, 13 May 2016 09:43 PM CEST","ttl":"60","location":{"city":"Meppen","country":"Germany","region":" NI"},"wind":{"chill":"55","direction":"350","speed":"25"},"atmosphere":{"humidity":"57","pressure":"1004.0","rising":"0","visibility":"16.1"},"astronomy":{"sunrise":"5:35 am","sunset":"9:21 pm"},"image":{"title":"Yahoo! Weather","width":"142","height":"18","link":"http://weather.yahoo.com","url":"http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif"},"item":{"title":"Conditions for Meppen, NI, DE at 08:00 PM CEST","lat":"52.68993","long":"7.29115","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-674836/","pubDate":"Fri, 13 May 2016 08:00 PM CEST","condition":{"code":"23","date":"Fri, 13 May 2016 08:00 PM CEST","temp":"14","text":"Breezy"},"forecast":[{"code":"30","date":"13 May 2016","day":"Fri","high":"71","low":"48","text":"Partly Cloudy"},{"code":"28","date":"14 May 2016","day":"Sat","high":"54","low":"44","text":"Mostly Cloudy"},{"code":"11","date":"15 May 2016","day":"Sun","high":"55","low":"43","text":"Showers"},{"code":"28","date":"16 May 2016","day":"Mon","high":"54","low":"42","text":"Mostly Cloudy"},{"code":"28","date":"17 May 2016","day":"Tue","high":"57","low":"43","text":"Mostly Cloudy"},{"code":"12","date":"18 May 2016","day":"Wed","high":"62","low":"45","text":"Rain"},{"code":"28","date":"19 May 2016","day":"Thu","high":"63","low":"48","text":"Mostly Cloudy"},{"code":"28","date":"20 May 2016","day":"Fri","high":"67","low":"50","text":"Mostly Cloudy"},{"code":"30","date":"21 May 2016","day":"Sat","high":"71","low":"50","text":"Partly Cloudy"},{"code":"30","date":"22 May 2016","day":"Sun","high":"74","low":"54","text":"Partly Cloudy"}],"description":"<![CDATA[<img src=\"http://l.yimg.com/a/i/us/we/52/23.gif\"/>\n<BR />\n<b>Current Conditions:</b>\n<BR />Breezy\n<BR />\n<BR />\n<b>Forecast:</b>\n<BR /> Fri - Partly Cloudy. High: 71Low: 48\n<BR /> Sat - Mostly Cloudy. High: 54Low: 44\n<BR /> Sun - Showers. High: 55Low: 43\n<BR /> Mon - Mostly Cloudy. High: 54Low: 42\n<BR /> Tue - Mostly Cloudy. High: 57Low: 43\n<BR />\n<BR />\n<a href=\"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-674836/\">Full Forecast at Yahoo! Weather</a>\n<BR />\n<BR />\n(provided by <a href=\"http://www.weather.com\" >The Weather Channel</a>)\n<BR />\n]]>","guid":{"isPermaLink":"false"}}}}}}' + elif 'Moscow' in query_url: + return r'{"query":{"count":1,"created":"2016-05-13T19:47:01Z","lang":"en-US","results":{"channel":{"units":{"distance":"mi","pressure":"in","speed":"mph","temperature":"C"},"title":"Yahoo! Weather - Moscow, Moscow Federal City, RU","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-2122265/","description":"Yahoo! Weather for Moscow, Moscow Federal City, RU","language":"en-us","lastBuildDate":"Fri, 13 May 2016 10:47 PM MSK","ttl":"60","location":{"city":"Moscow","country":"Russia","region":" Moscow Federal City"},"wind":{"chill":"45","direction":"80","speed":"11"},"atmosphere":{"humidity":"52","pressure":"993.0","rising":"0","visibility":"16.1"},"astronomy":{"sunrise":"4:19 am","sunset":"8:34 pm"},"image":{"title":"Yahoo! Weather","width":"142","height":"18","link":"http://weather.yahoo.com","url":"http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif"},"item":{"title":"Conditions for Moscow, Moscow Federal City, RU at 09:00 PM MSK","lat":"55.741638","long":"37.605061","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-2122265/","pubDate":"Fri, 13 May 2016 09:00 PM MSK","condition":{"code":"33","date":"Fri, 13 May 2016 09:00 PM MSK","temp":"9","text":"Mostly Clear"},"forecast":[{"code":"30","date":"13 May 2016","day":"Fri","high":"62","low":"41","text":"Partly Cloudy"},{"code":"30","date":"14 May 2016","day":"Sat","high":"64","low":"43","text":"Partly Cloudy"},{"code":"30","date":"15 May 2016","day":"Sun","high":"63","low":"44","text":"Partly Cloudy"},{"code":"12","date":"16 May 2016","day":"Mon","high":"60","low":"47","text":"Rain"},{"code":"12","date":"17 May 2016","day":"Tue","high":"64","low":"48","text":"Rain"},{"code":"28","date":"18 May 2016","day":"Wed","high":"67","low":"48","text":"Mostly Cloudy"},{"code":"12","date":"19 May 2016","day":"Thu","high":"68","low":"49","text":"Rain"},{"code":"39","date":"20 May 2016","day":"Fri","high":"66","low":"50","text":"Scattered Showers"},{"code":"39","date":"21 May 2016","day":"Sat","high":"69","low":"49","text":"Scattered Showers"},{"code":"30","date":"22 May 2016","day":"Sun","high":"73","low":"50","text":"Partly Cloudy"}],"description":"<![CDATA[<img src=\"http://l.yimg.com/a/i/us/we/52/33.gif\"/>\n<BR />\n<b>Current Conditions:</b>\n<BR />Mostly Clear\n<BR />\n<BR />\n<b>Forecast:</b>\n<BR /> Fri - Partly Cloudy. High: 62Low: 41\n<BR /> Sat - Partly Cloudy. High: 64Low: 43\n<BR /> Sun - Partly Cloudy. High: 63Low: 44\n<BR /> Mon - Rain. High: 60Low: 47\n<BR /> Tue - Rain. High: 64Low: 48\n<BR />\n<BR />\n<a href=\"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-2122265/\">Full Forecast at Yahoo! Weather</a>\n<BR />\n<BR />\n(provided by <a href=\"http://www.weather.com\" >The Weather Channel</a>)\n<BR />\n]]>","guid":{"isPermaLink":"false"}}}}}}' + else: + raise NotImplementedError + + +class Process(object): + def __init__(self, output, err): + self.output = output + self.err = err + + def communicate(self): + return self.output, self.err + + +class ModuleReplace(object): + def __init__(self, name, new): + self.name = name + self.new = new + + def __enter__(self): + self.old = sys.modules.get(self.name) + if not self.old: + try: + self.old = __import__(self.name) + except ImportError: + pass + sys.modules[self.name] = self.new + + def __exit__(self, *args): + if self.old: + sys.modules[self.name] = self.old + else: + sys.modules.pop(self.name) + + +def replace_module(name, new=None, **kwargs): + if not new: + new = new_module(name, **kwargs) + return ModuleReplace(name, new) + + +def new_module(name, **kwargs): + module = imp.new_module(name) + for k, v in kwargs.items(): + setattr(module, k, v) + return module + + +class AttrReplace(object): + def __init__(self, obj, *args): + self.obj = obj + self.attrs = args[::2] + self.new = args[1::2] + + def __enter__(self): + self.old = {} + for i, attr in enumerate(self.attrs): + try: + self.old[i] = getattr(self.obj, attr) + except AttributeError: + pass + for attr, new in zip(self.attrs, self.new): + setattr(self.obj, attr, new) + + def __exit__(self, *args): + for i, attr in enumerate(self.attrs): + try: + old = self.old[i] + except KeyError: + delattr(self.obj, attr) + else: + setattr(self.obj, attr, old) + + +replace_attr = AttrReplace + + +def replace_module_module(module, name, **kwargs): + return replace_attr(module, name, new_module(name, **kwargs)) + + +class ItemReplace(object): + def __init__(self, d, key, new, r=None): + self.key = key + self.new = new + self.d = d + self.r = r + + def __enter__(self): + self.old = self.d.get(self.key) + self.d[self.key] = self.new + return self.r + + def __exit__(self, *args): + if self.old is None: + try: + self.d.pop(self.key) + except KeyError: + pass + else: + self.d[self.key] = self.old + + +def replace_item(d, key, new): + return ItemReplace(d, key, new, d) + + +def replace_env(key, new, environ=None, **kwargs): + r = kwargs.copy() + r['environ'] = environ or {} + return ItemReplace(r['environ'], key, new, r) + + +class PowerlineSingleTest(object): + def __init__(self, suite, name): + self.suite = suite + self.name = name + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + if exc_type is not None: + self.exception('Exception while running test: {0!r}'.format( + exc_value)) + + def fail(self, message, allow_failure=False): + return self.suite.fail(self.name, message, allow_failure) + + def exception(self, message, allow_failure=False): + return self.suite.exception(self.name, message, allow_failure) diff --git a/tests/modules/lib/config_mock.py b/tests/modules/lib/config_mock.py new file mode 100644 index 0000000..900b60f --- /dev/null +++ b/tests/modules/lib/config_mock.py @@ -0,0 +1,230 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os + +from threading import Lock +from copy import deepcopy +from time import sleep +from functools import wraps + +from powerline.renderer import Renderer +from powerline.lib.config import ConfigLoader +from powerline import Powerline, get_default_theme + +from tests.modules.lib import Args, replace_attr + + +UT = get_default_theme(is_unicode=True) +AT = get_default_theme(is_unicode=False) + + +class TestHelpers(object): + def __init__(self, config): + self.config = config + self.access_log = [] + self.access_lock = Lock() + + def loader_condition(self, path): + return (path in self.config) and path + + def find_config_files(self, cfg_path, config_loader, loader_callback): + if cfg_path.endswith('.json'): + cfg_path = cfg_path[:-5] + if cfg_path.startswith('/'): + cfg_path = cfg_path.lstrip('/') + with self.access_lock: + self.access_log.append('check:' + cfg_path) + if cfg_path in self.config: + yield cfg_path + else: + if config_loader: + config_loader.register_missing(self.loader_condition, loader_callback, cfg_path) + raise IOError(('fcf:' if cfg_path.endswith('raise') else '') + cfg_path) + + def load_json_config(self, config_file_path, *args, **kwargs): + if config_file_path.endswith('.json'): + config_file_path = config_file_path[:-5] + if config_file_path.startswith('/'): + config_file_path = config_file_path.lstrip('/') + with self.access_lock: + self.access_log.append('load:' + config_file_path) + try: + return deepcopy(self.config[config_file_path]) + except KeyError: + raise IOError(config_file_path) + + def pop_events(self): + with self.access_lock: + r = self.access_log[:] + self.access_log = [] + return r + + +def log_call(func): + @wraps(func) + def ret(self, *args, **kwargs): + self._calls.append((func.__name__, args, kwargs)) + return func(self, *args, **kwargs) + return ret + + +class TestWatcher(object): + events = set() + lock = Lock() + + def __init__(self): + self._calls = [] + + @log_call + def watch(self, file): + pass + + @log_call + def __call__(self, file): + with self.lock: + if file in self.events: + self.events.remove(file) + return True + return False + + def _reset(self, files): + with self.lock: + self.events.clear() + self.events.update(files) + + @log_call + def unsubscribe(self): + pass + + +class Logger(object): + def __init__(self): + self.messages = [] + self.lock = Lock() + + def _add_msg(self, attr, msg): + with self.lock: + self.messages.append(attr + ':' + msg) + + def _pop_msgs(self): + with self.lock: + r = self.messages + self.messages = [] + return r + + def __getattr__(self, attr): + return lambda *args, **kwargs: self._add_msg(attr, *args, **kwargs) + + +class SimpleRenderer(Renderer): + def hlstyle(self, fg=None, bg=None, attrs=None): + return '<{fg} {bg} {attrs}>'.format(fg=fg and fg[0], bg=bg and bg[0], attrs=attrs) + + +class EvenSimplerRenderer(Renderer): + def hlstyle(self, fg=None, bg=None, attrs=None): + return '{{{fg}{bg}{attrs}}}'.format( + fg=fg and fg[0] or '-', + bg=bg and bg[0] or '-', + attrs=attrs if attrs else '', + ) + + +class TestPowerline(Powerline): + _created = False + + def __init__(self, _helpers, **kwargs): + super(TestPowerline, self).__init__(**kwargs) + self._helpers = _helpers + self.find_config_files = _helpers.find_config_files + + @staticmethod + def get_local_themes(local_themes): + return local_themes + + @staticmethod + def get_config_paths(): + return [''] + + def _will_create_renderer(self): + return self.cr_kwargs + + def _pop_events(self): + return self._helpers.pop_events() + + +renderer = EvenSimplerRenderer + + +class TestConfigLoader(ConfigLoader): + def __init__(self, _helpers, **kwargs): + watcher = TestWatcher() + super(TestConfigLoader, self).__init__( + load=_helpers.load_json_config, + watcher=watcher, + watcher_type='test', + **kwargs + ) + + +def get_powerline(config, **kwargs): + helpers = TestHelpers(config) + return get_powerline_raw( + helpers, + TestPowerline, + _helpers=helpers, + ext='test', + renderer_module='tests.modules.lib.config_mock', + logger=Logger(), + **kwargs + ) + + +def select_renderer(simpler_renderer=False): + global renderer + renderer = EvenSimplerRenderer if simpler_renderer else SimpleRenderer + + +def get_powerline_raw(helpers, PowerlineClass, replace_gcp=False, **kwargs): + if not isinstance(helpers, TestHelpers): + helpers = TestHelpers(helpers) + select_renderer(kwargs.pop('simpler_renderer', False)) + + if replace_gcp: + class PowerlineClass(PowerlineClass): + @staticmethod + def get_config_paths(): + return ['/'] + + pl = PowerlineClass( + config_loader=TestConfigLoader( + _helpers=helpers, + run_once=kwargs.get('run_once') + ), + **kwargs + ) + pl._watcher = pl.config_loader.watcher + return pl + + +def swap_attributes(config, powerline_module): + return replace_attr(powerline_module, 'os', Args( + path=Args( + isfile=lambda path: path.lstrip('/').replace('.json', '') in config, + join=os.path.join, + expanduser=lambda path: path, + realpath=lambda path: path, + dirname=os.path.dirname, + ), + environ={}, + )) + + +def add_watcher_events(p, *args, **kwargs): + if isinstance(p._watcher, TestWatcher): + p._watcher._reset(args) + while not p._will_create_renderer(): + sleep(kwargs.get('interval', 0.1)) + if not kwargs.get('wait', True): + return diff --git a/tests/modules/lib/fsconfig.py b/tests/modules/lib/fsconfig.py new file mode 100644 index 0000000..757e874 --- /dev/null +++ b/tests/modules/lib/fsconfig.py @@ -0,0 +1,83 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os +import json + +from subprocess import check_call +from shutil import rmtree +from itertools import chain + +from powerline import Powerline + + +CONFIG_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'config') + + +class TestPowerline(Powerline): + def __init__(self, _paths, *args, **kwargs): + super(TestPowerline, self).__init__(*args, **kwargs) + self._paths = _paths + + def get_config_paths(self): + return self._paths + + +def mkdir_recursive(directory): + if os.path.isdir(directory): + return + mkdir_recursive(os.path.dirname(directory)) + os.mkdir(directory) + + +class FSTree(object): + __slots__ = ('tree', 'p', 'p_kwargs', 'create_p', 'get_config_paths', 'root') + + def __init__( + self, + tree, + p_kwargs={'run_once': True}, + root=CONFIG_DIR, + get_config_paths=lambda p: (p,), + create_p=False + ): + self.tree = tree + self.root = root + self.get_config_paths = get_config_paths + self.create_p = create_p + self.p = None + self.p_kwargs = p_kwargs + + def __enter__(self, *args): + os.mkdir(self.root) + for k, v in self.tree.items(): + fname = os.path.join(self.root, k) + '.json' + mkdir_recursive(os.path.dirname(fname)) + with open(fname, 'w') as F: + json.dump(v, F) + if self.create_p: + self.p = TestPowerline( + _paths=self.get_config_paths(self.root), + ext='test', + renderer_module='tests.modules.lib.config_mock', + **self.p_kwargs + ) + if os.environ.get('POWERLINE_RUN_LINT_DURING_TESTS'): + try: + check_call(chain(['scripts/powerline-lint'], *[ + ('-p', d) for d in ( + self.p.get_config_paths() if self.p + else self.get_config_paths(self.root) + ) + ])) + except: + self.__exit__() + raise + return self.p and self.p.__enter__(*args) + + def __exit__(self, *args): + try: + rmtree(self.root) + finally: + if self.p: + self.p.__exit__(*args) diff --git a/tests/modules/lib/terminal.py b/tests/modules/lib/terminal.py new file mode 100644 index 0000000..540135d --- /dev/null +++ b/tests/modules/lib/terminal.py @@ -0,0 +1,307 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import threading +import os + +from time import sleep +from itertools import groupby +from signal import SIGKILL +from difflib import ndiff + +import pexpect + +from powerline.lib.unicode import u + +from tests.modules.lib.vterm import VTerm, Dimensions + + +class MutableDimensions(object): + def __init__(self, rows, cols): + super(MutableDimensions, self).__init__() + self._list = [rows, cols] + + def __getitem__(self, idx): + return self._list[idx] + + def __setitem__(self, idx, val): + self._list[idx] = val + + def __iter__(self): + return iter(self._list) + + def __len__(self): + return 2 + + def __nonzero__(self): + return True + + __bool__ = __nonzero__ + + rows = property( + fget = lambda self: self._list[0], + fset = lambda self, val: self._list.__setitem__(0, val), + ) + cols = property( + fget = lambda self: self._list[1], + fset = lambda self, val: self._list.__setitem__(1, val), + ) + + +class ExpectProcess(threading.Thread): + def __init__(self, lib, dim, cmd, args, cwd=None, env=None): + super(ExpectProcess, self).__init__() + self.vterm = VTerm(lib, dim) + self.lock = threading.Lock() + self.dim = Dimensions(*dim) + self.cmd = cmd + self.args = args + self.cwd = cwd + self.env = env + self.buffer = [] + self.child_lock = threading.Lock() + self.shutdown_event = threading.Event() + self.started_event = threading.Event() + + def run(self): + with self.child_lock: + child = pexpect.spawn(self.cmd, self.args, cwd=self.cwd, + env=self.env) + sleep(0.5) + child.setwinsize(self.dim.rows, self.dim.cols) + sleep(0.5) + self.child = child + self.started_event.set() + status = None + while status is None and not self.shutdown_event.is_set(): + try: + with self.child_lock: + s = child.read_nonblocking(size=1024, timeout=0) + status = child.status + except pexpect.TIMEOUT: + pass + except pexpect.EOF: + break + else: + with self.lock: + self.vterm.push(s) + self.buffer.append(s) + + if status is None: + child.kill(SIGKILL) + + def kill(self): + self.shutdown_event.set() + + def resize(self, dim): + with self.child_lock: + self.dim = Dimensions(*dim) + self.child.setwinsize(self.dim.rows, self.dim.cols) + self.vterm.resize(self.dim) + + def __getitem__(self, position): + with self.lock: + return self.vterm.vtscreen[position] + + def read(self): + with self.lock: + ret = b''.join(self.buffer) + del self.buffer[:] + return ret + + def send(self, data): + with self.child_lock: + self.child.send(data) + + def get_highlighted_text(self, text, attrs, default_props=(), + use_escapes=False): + ret = [] + new_attrs = attrs.copy() + for cell_properties, segment_text in text: + if use_escapes: + escapes = ('\033[38;2;{0};{1};{2};48;2;{3};{4};{5}'.format( + *(cell_properties[0] + cell_properties[1]))) + ( + ';1' if cell_properties[2] else '' + ) + ( + ';3' if cell_properties[3] else '' + ) + ( + ';4' if cell_properties[4] else '' + ) + 'm' + ret.append(escapes + segment_text + '\033[0m') + else: + segment_text = segment_text.translate({'{': '{{', '}': '}}'}) + if cell_properties not in new_attrs: + new_attrs[cell_properties] = len(new_attrs) + 1 + props_name = new_attrs[cell_properties] + if props_name in default_props: + ret.append(segment_text) + else: + ret.append('{' + str(props_name) + ':' + segment_text + '}') + return ''.join(ret), new_attrs + + def get_row(self, row, attrs, default_props=(), use_escapes=False): + with self.lock: + return self.get_highlighted_text(( + (key, ''.join((cell.text for cell in subline))) + for key, subline in groupby(( + self.vterm.vtscreen[row, col] + for col in range(self.dim.cols) + ), lambda cell: cell.cell_properties_key) + ), attrs, default_props, use_escapes) + + def get_screen(self, attrs, default_props=(), use_escapes=False): + lines = [] + for row in range(self.dim.rows): + line, attrs = self.get_row(row, attrs, default_props, use_escapes) + lines.append(line) + return '\n'.join(lines), attrs + + +def test_expected_result(p, test, last_attempt, last_attempt_cb, attempts): + debugging_tests = not not os.environ.get('_POWERLINE_DEBUGGING_TESTS') + expected_text, attrs = test['expected_result'] + result = None + while attempts: + if 'row' in test: + row = test['row'] + else: + row = p.dim.rows - 1 + while row >= 0 and not p[row, 0].text: + row -= 1 + if row < 0: + row = 0 + actual_text, all_attrs = p.get_row(row, attrs) + if actual_text == expected_text: + return True + attempts -= 1 + print('Actual result does not match expected for row {0}. Attempts left: {1}.'.format( + row, attempts)) + sleep(2) + print('Result (row {0}):'.format(row)) + print(actual_text) + print('Expected:') + print(expected_text) + print('Attributes:') + for v, k in sorted( + ((v, k) for k, v in all_attrs.items()), + key=(lambda t: '%02u'.format(t[0]) if isinstance(t[0], int) else t[0]), + ): + print('{k!r}: {v!r},'.format(v=v, k=k)) + print('Screen:') + screen, screen_attrs = p.get_screen(attrs, use_escapes=debugging_tests) + print(screen) + print(screen_attrs) + print('_' * 80) + print('Diff:') + print('=' * 80) + print(''.join(( + u(line) for line in ndiff([actual_text + '\n'], [expected_text + '\n'])) + )) + if last_attempt and last_attempt_cb: + last_attempt_cb() + return False + + +ENV_BASE = { + # Reasoning: + # 1. vt* TERMs (used to be vt100 here) make tmux-1.9 use different and + # identical colors for inactive windows. This is not like tmux-1.6: + # foreground color is different from separator color and equal to (0, + # 102, 153) for some reason (separator has correct color). tmux-1.8 is + # fine, so are older versions (though tmux-1.6 and tmux-1.7 do not have + # highlighting for previously active window) and my system tmux-1.9a. + # 2. screen, xterm and some other non-256color terminals both have the same + # issue and make libvterm emit complains like `Unhandled CSI SGR 3231`. + # 3. screen-256color, xterm-256color and other -256color terminals make + # libvterm emit complains about unhandled escapes to stderr. + # 4. `st-256color` does not have any of the above problems, but it may be + # not present on the target system because it is installed with + # x11-terms/st and not with sys-libs/ncurses. + # + # For the given reasons decision was made: to fix tmux-1.9 tests and not + # make libvterm emit any data to stderr st-256color $TERM should be used, up + # until libvterm has its own terminfo database entry (if it ever will). To + # make sure that relevant terminfo entry is present on the target system it + # should be distributed with powerline test package. To make distribution + # not require modifying anything outside of powerline test directory + # TERMINFO variable is set. + # + # This fix propagates to non-tmux vterm tests just in case. + 'TERM': 'st-256color', + # Also $TERMINFO definition in get_env + + 'POWERLINE_CONFIG_PATHS': os.path.abspath('powerline/config_files'), + 'POWERLINE_COMMAND': 'powerline-render', + 'LD_LIBRARY_PATH': os.environ.get('LD_LIBRARY_PATH', ''), + 'PYTHONPATH': os.environ.get('PYTHONPATH', ''), +} + + +def get_env(vterm_path, test_dir, *args, **kwargs): + env = ENV_BASE.copy() + env.update({ + 'TERMINFO': os.path.join(test_dir, 'terminfo'), + 'PATH': vterm_path, + 'SHELL': os.path.join(vterm_path, 'bash'), + }) + env.update(*args, **kwargs) + return env + + +def do_terminal_tests(tests, cmd, dim, args, env, suite, cwd=None, fin_cb=None, + last_attempt_cb=None, attempts=None): + debugging_tests = not not os.environ.get('_POWERLINE_DEBUGGING_TESTS') + default_attempts = 2 if debugging_tests else 3 + if attempts is None: + attempts = default_attempts + lib = os.environ.get('POWERLINE_LIBVTERM') + if not lib: + if os.path.exists('tests/bot-ci/deps/libvterm/libvterm.so'): + lib = 'tests/bot-ci/deps/libvterm/libvterm.so' + else: + lib = 'libvterm.so' + + while attempts: + try: + p = ExpectProcess( + lib=lib, + dim=dim, + cmd=cmd, + args=args, + cwd=cwd, + env=env, + ) + p.start() + p.started_event.wait() + + ret = True + + for i, test in enumerate(tests): + with suite.test(test.get('name', 'test_{0}'.format(i)), + attempts - 1) as ptest: + try: + test_prep = test['prep_cb'] + except KeyError: + pass + else: + test_prep(p) + test_result = test_expected_result( + p, test, attempts == 0, last_attempt_cb, + test.get('attempts', default_attempts) + ) + if not test_result: + ptest.fail('Result does not match expected') + ret = ret and test_result + + if ret: + return ret + finally: + if fin_cb: + fin_cb(p=p, cmd=cmd, env=env) + p.kill() + p.join(10) + assert(not p.isAlive()) + + attempts -= 1 + + return False diff --git a/tests/modules/lib/vterm.py b/tests/modules/lib/vterm.py new file mode 100644 index 0000000..1984e1b --- /dev/null +++ b/tests/modules/lib/vterm.py @@ -0,0 +1,193 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import ctypes + +from collections import namedtuple + +from powerline.lib.unicode import unicode, unichr, tointiter + + +Dimensions = namedtuple('Dimensions', ('rows', 'cols')) + + +class CTypesFunction(object): + def __init__(self, library, name, rettype, args): + self.name = name + self.prototype = ctypes.CFUNCTYPE(rettype, *[ + arg[1] for arg in args + ]) + self.args = args + self.func = self.prototype((name, library), tuple(( + (1, arg[0]) for arg in args + ))) + + def __call__(self, *args, **kwargs): + return self.func(*args, **kwargs) + + def __repr__(self): + return '{cls}(<library>, {name!r}, {rettype!r}, {args!r})'.format( + cls=self.__class__.__name__, + **self.__dict__ + ) + + +class CTypesLibraryFuncsCollection(object): + def __init__(self, lib, **kwargs): + self.lib = lib + library_loader = ctypes.LibraryLoader(ctypes.CDLL) + library = library_loader.LoadLibrary(lib) + self.library = library + for name, args in kwargs.items(): + self.__dict__[name] = CTypesFunction(library, name, *args) + + +class VTermPos_s(ctypes.Structure): + _fields_ = ( + ('row', ctypes.c_int), + ('col', ctypes.c_int), + ) + + +class VTermColor_s(ctypes.Structure): + _fields_ = ( + ('red', ctypes.c_uint8), + ('green', ctypes.c_uint8), + ('blue', ctypes.c_uint8), + ) + + +class VTermScreenCellAttrs_s(ctypes.Structure): + _fields_ = ( + ('bold', ctypes.c_uint, 1), + ('underline', ctypes.c_uint, 2), + ('italic', ctypes.c_uint, 1), + ('blink', ctypes.c_uint, 1), + ('reverse', ctypes.c_uint, 1), + ('strike', ctypes.c_uint, 1), + ('font', ctypes.c_uint, 4), + ('dwl', ctypes.c_uint, 1), + ('dhl', ctypes.c_uint, 2), + ) + + +VTERM_MAX_CHARS_PER_CELL = 6 + + +class VTermScreenCell_s(ctypes.Structure): + _fields_ = ( + ('chars', ctypes.ARRAY(ctypes.c_uint32, VTERM_MAX_CHARS_PER_CELL)), + ('width', ctypes.c_char), + ('attrs', VTermScreenCellAttrs_s), + ('fg', VTermColor_s), + ('bg', VTermColor_s), + ) + + +VTerm_p = ctypes.c_void_p +VTermScreen_p = ctypes.c_void_p + + +def get_functions(lib): + return CTypesLibraryFuncsCollection( + lib, + vterm_new=(VTerm_p, ( + ('rows', ctypes.c_int), + ('cols', ctypes.c_int) + )), + vterm_obtain_screen=(VTermScreen_p, (('vt', VTerm_p),)), + vterm_set_size=(None, ( + ('vt', VTerm_p), + ('rows', ctypes.c_int), + ('cols', ctypes.c_int) + )), + vterm_screen_reset=(None, ( + ('screen', VTermScreen_p), + ('hard', ctypes.c_int) + )), + vterm_input_write=(ctypes.c_size_t, ( + ('vt', VTerm_p), + ('bytes', ctypes.POINTER(ctypes.c_char)), + ('size', ctypes.c_size_t), + )), + vterm_screen_get_cell=(ctypes.c_int, ( + ('screen', VTermScreen_p), + ('pos', VTermPos_s), + ('cell', ctypes.POINTER(VTermScreenCell_s)) + )), + vterm_free=(None, (('vt', VTerm_p),)), + vterm_set_utf8=(None, (('vt', VTerm_p), ('is_utf8', ctypes.c_int))), + ) + + +class VTermColor(object): + __slots__ = ('red', 'green', 'blue') + + def __init__(self, color): + self.red = color.red + self.green = color.green + self.blue = color.blue + + @property + def color_key(self): + return (self.red, self.green, self.blue) + + +class VTermScreenCell(object): + def __init__(self, vtsc): + for field in VTermScreenCellAttrs_s._fields_: + field_name = field[0] + setattr(self, field_name, getattr(vtsc.attrs, field_name)) + self.text = ''.join(( + unichr(vtsc.chars[i]) for i in range(VTERM_MAX_CHARS_PER_CELL) + )).rstrip('\x00') + self.width = next(tointiter(vtsc.width)) + self.fg = VTermColor(vtsc.fg) + self.bg = VTermColor(vtsc.bg) + self.cell_properties_key = ( + self.fg.color_key, + self.bg.color_key, + self.bold, + self.underline, + self.italic, + ) + + +class VTermScreen(object): + def __init__(self, functions, screen): + self.functions = functions + self.screen = screen + + def __getitem__(self, position): + pos = VTermPos_s(*position) + cell = VTermScreenCell_s() + ret = self.functions.vterm_screen_get_cell(self.screen, pos, cell) + if ret != 1: + raise ValueError('vterm_screen_get_cell returned {0}'.format(ret)) + return VTermScreenCell(cell) + + def reset(self, hard): + self.functions.vterm_screen_reset(self.screen, int(bool(hard))) + + +class VTerm(object): + def __init__(self, lib, dim): + self.functions = get_functions(lib) + self.vt = self.functions.vterm_new(dim.rows, dim.cols) + self.functions.vterm_set_utf8(self.vt, 1) + self.vtscreen = VTermScreen(self.functions, self.functions.vterm_obtain_screen(self.vt)) + self.vtscreen.reset(True) + + def push(self, data): + if isinstance(data, unicode): + data = data.encode('utf-8') + return self.functions.vterm_input_write(self.vt, data, len(data)) + + def resize(self, dim): + self.functions.vterm_set_size(self.vt, dim.rows, dim.cols) + + def __del__(self): + try: + self.functions.vterm_free(self.vt) + except AttributeError: + pass diff --git a/tests/modules/matchers.py b/tests/modules/matchers.py new file mode 100644 index 0000000..e905de3 --- /dev/null +++ b/tests/modules/matchers.py @@ -0,0 +1,6 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + + +def always_true(matcher_info): + return True diff --git a/tests/modules/vim.py b/tests/modules/vim.py new file mode 100644 index 0000000..3f6882c --- /dev/null +++ b/tests/modules/vim.py @@ -0,0 +1,927 @@ +# vim:fileencoding=utf-8:noet +_log = [] +vars = {} +vvars = {'version': 703} +_tabpage = 0 +_mode = 'n' +_buf_purge_events = set() +options = { + 'paste': 0, + 'ambiwidth': 'single', + 'columns': 80, + 'encoding': 'utf-8', +} +_last_bufnr = 0 +_highlights = {} +from collections import defaultdict as _defaultdict +_environ = _defaultdict(lambda: '') +del _defaultdict + + +_thread_id = None + + +def _set_thread_id(): + global _thread_id + from threading import current_thread + _thread_id = current_thread().ident + + +# Assuming import is done from the main thread +_set_thread_id() + + +def _print_log(): + for item in _log: + print (item) + _log[:] = () + + +def _vim(func): + from functools import wraps + from threading import current_thread + + @wraps(func) + def f(*args, **kwargs): + global _thread_id + if _thread_id != current_thread().ident: + raise RuntimeError('Accessing vim from separate threads is not allowed') + _log.append((func.__name__, args)) + return func(*args, **kwargs) + + return f + + +def _unicode(func): + from functools import wraps + import sys + + if sys.version_info < (3,): + return func + + @wraps(func) + def f(*args, **kwargs): + from powerline.lib.unicode import u + ret = func(*args, **kwargs) + if isinstance(ret, bytes): + ret = u(ret) + return ret + + return f + + +class _Buffers(object): + @_vim + def __init__(self): + self.d = {} + + @_vim + def __len__(self): + return len(self.d) + + @_vim + def __getitem__(self, item): + return self.d[item] + + @_vim + def __setitem__(self, item, value): + self.d[item] = value + + @_vim + def __iter__(self): + return iter(self.d.values()) + + @_vim + def __contains__(self, item): + return item in self.d + + @_vim + def _keys(self): + return self.d.keys() + + @_vim + def _pop(self, *args, **kwargs): + return self.d.pop(*args, **kwargs) + + +buffers = _Buffers() + + +class _ObjList(object): + @_vim + def __init__(self, objtype): + self.l = [] + self.objtype = objtype + + @_vim + def __getitem__(self, item): + return self.l[item - int(item > 0)] + + @_vim + def __len__(self): + return len(self.l) + + @_vim + def __iter__(self): + return iter(self.l) + + @_vim + def _pop(self, idx): + obj = self.l.pop(idx - 1) + for moved_obj in self.l[idx - 1:]: + moved_obj.number -= 1 + return obj + + @_vim + def _append(self, *args, **kwargs): + return self.l.append(*args, **kwargs) + + @_vim + def _new(self, *args, **kwargs): + number = len(self) + 1 + new_obj = self.objtype(number, *args, **kwargs) + self._append(new_obj) + return new_obj + + +def _construct_result(r): + import sys + if sys.version_info < (3,): + return r + else: + if isinstance(r, str): + return r.encode('utf-8') + elif isinstance(r, list): + return [_construct_result(i) for i in r] + elif isinstance(r, dict): + return dict(( + (_construct_result(k), _construct_result(v)) + for k, v in r.items() + )) + return r + + +def _str_func(func): + from functools import wraps + + @wraps(func) + def f(*args, **kwargs): + return _construct_result(func(*args, **kwargs)) + return f + + +def _log_print(): + import sys + for entry in _log: + sys.stdout.write(repr(entry) + '\n') + + +_current_group = None +_on_wipeout = [] + + +@_vim +def command(cmd): + global _current_group + cmd = cmd.lstrip() + if cmd.startswith('let g:'): + import re + varname, value = re.compile(r'^let g:(\w+)\s*=\s*(.*)').match(cmd).groups() + vars[varname] = value + elif cmd.startswith('hi '): + sp = cmd.split() + _highlights[sp[1]] = sp[2:] + elif cmd.startswith('augroup'): + augroup = cmd.partition(' ')[2] + if augroup.upper() == 'END': + _current_group = None + else: + _current_group = augroup + elif cmd.startswith('autocmd'): + rest = cmd.partition(' ')[2] + auevent, rest = rest.partition(' ')[::2] + pattern, aucmd = rest.partition(' ')[::2] + if auevent != 'BufWipeout' or pattern != '*': + raise NotImplementedError + import sys + if sys.version_info < (3,): + if not aucmd.startswith(':python '): + raise NotImplementedError + else: + if not aucmd.startswith(':python3 '): + raise NotImplementedError + _on_wipeout.append(aucmd.partition(' ')[2]) + elif cmd.startswith('set '): + if cmd.startswith('set statusline='): + options['statusline'] = cmd[len('set statusline='):] + elif cmd.startswith('set tabline='): + options['tabline'] = cmd[len('set tabline='):] + else: + raise NotImplementedError(cmd) + else: + raise NotImplementedError(cmd) + + +@_vim +@_unicode +def eval(expr): + if expr.startswith('g:'): + return vars[expr[2:]] + elif expr.startswith('v:'): + return vvars[expr[2:]] + elif expr.startswith('&'): + return options[expr[1:]] + elif expr.startswith('$'): + return _environ[expr[1:]] + elif expr.startswith('PowerlineRegisterCachePurgerEvent'): + _buf_purge_events.add(expr[expr.find('"') + 1:expr.rfind('"') - 1]) + return '0' + elif expr.startswith('exists('): + return '0' + elif expr.startswith('getwinvar('): + import re + match = re.match(r'^getwinvar\((\d+), "(\w+)"\)$', expr) + if not match: + raise NotImplementedError(expr) + winnr = int(match.group(1)) + varname = match.group(2) + return _emul_getwinvar(winnr, varname) + elif expr.startswith('has_key('): + import re + match = re.match(r'^has_key\(getwinvar\((\d+), ""\), "(\w+)"\)$', expr) + if match: + winnr = int(match.group(1)) + varname = match.group(2) + return 0 + (varname in current.tabpage.windows[winnr].vars) + else: + match = re.match(r'^has_key\(gettabwinvar\((\d+), (\d+), ""\), "(\w+)"\)$', expr) + if not match: + raise NotImplementedError(expr) + tabnr = int(match.group(1)) + winnr = int(match.group(2)) + varname = match.group(3) + return 0 + (varname in tabpages[tabnr].windows[winnr].vars) + elif expr == 'getbufvar("%", "NERDTreeRoot").path.str()': + import os + assert os.path.basename(current.buffer.name).startswith('NERD_tree_') + return '/usr/include' + elif expr.startswith('getbufvar('): + import re + match = re.match(r'^getbufvar\((\d+), ["\'](.+)["\']\)$', expr) + if not match: + raise NotImplementedError(expr) + bufnr = int(match.group(1)) + varname = match.group(2) + return _emul_getbufvar(bufnr, varname) + elif expr == 'tabpagenr()': + return current.tabpage.number + elif expr == 'tabpagenr("$")': + return len(tabpages) + elif expr.startswith('tabpagewinnr('): + tabnr = int(expr[len('tabpagewinnr('):-1]) + return tabpages[tabnr].window.number + elif expr.startswith('tabpagebuflist('): + import re + match = re.match(r'tabpagebuflist\((\d+)\)\[(\d+)\]', expr) + tabnr = int(match.group(1)) + winnr = int(match.group(2)) + 1 + return tabpages[tabnr].windows[winnr].buffer.number + elif expr.startswith('gettabwinvar('): + import re + match = re.match(r'gettabwinvar\((\d+), (\d+), "(\w+)"\)', expr) + tabnr = int(match.group(1)) + winnr = int(match.group(2)) + varname = match.group(3) + return tabpages[tabnr].windows[winnr].vars[varname] + elif expr.startswith('type(function('): + import re + match = re.match(r'^type\(function\("([^"]+)"\)\) == 2$', expr) + if not match: + raise NotImplementedError(expr) + return 0 + raise NotImplementedError(expr) + + +@_vim +def bindeval(expr): + if expr == 'g:': + return vars + elif expr == '{}': + return {} + elif expr == '[]': + return [] + import re + match = re.compile(r'^function\("([^"\\]+)"\)$').match(expr) + if match: + return globals()['_emul_' + match.group(1)] + else: + raise NotImplementedError + + +@_vim +@_str_func +def _emul_mode(*args): + if args and args[0]: + return _mode + else: + return _mode[0] + + +@_vim +@_str_func +def _emul_getbufvar(bufnr, varname): + import re + if varname[0] == '&': + if bufnr == '%': + bufnr = current.buffer.number + if bufnr not in buffers: + return '' + try: + return buffers[bufnr].options[varname[1:]] + except KeyError: + try: + return options[varname[1:]] + except KeyError: + return '' + elif re.match('^[a-zA-Z_]+$', varname): + if bufnr == '%': + bufnr = current.buffer.number + if bufnr not in buffers: + return '' + return buffers[bufnr].vars[varname] + raise NotImplementedError + + +@_vim +@_str_func +def _emul_getwinvar(winnr, varname): + return current.tabpage.windows[winnr].vars.get(varname, '') + + +@_vim +def _emul_setwinvar(winnr, varname, value): + current.tabpage.windows[winnr].vars[varname] = value + + +@_vim +def _emul_virtcol(expr): + if expr == '.': + return current.window.cursor[1] + 1 + if isinstance(expr, list) and len(expr) == 3: + return expr[-2] + expr[-1] + raise NotImplementedError + + +_v_pos = None + + +@_vim +def _emul_getpos(expr): + if expr == '.': + return [0, current.window.cursor[0] + 1, current.window.cursor[1] + 1, 0] + if expr == 'v': + return _v_pos or [0, current.window.cursor[0] + 1, current.window.cursor[1] + 1, 0] + raise NotImplementedError + + +@_vim +@_str_func +def _emul_fnamemodify(path, modstring): + import os + _modifiers = { + '~': lambda path: path.replace(os.environ['HOME'].encode('utf-8'), b'~') if path.startswith(os.environ['HOME'].encode('utf-8')) else path, + '.': lambda path: (lambda tpath: path if tpath[:3] == b'..' + os.sep.encode() else tpath)(os.path.relpath(path)), + 't': lambda path: os.path.basename(path), + 'h': lambda path: os.path.dirname(path), + } + + for mods in modstring.split(':')[1:]: + path = _modifiers[mods](path) + return path + + +@_vim +@_str_func +def _emul_expand(expr): + global _abuf + if expr == '<abuf>': + return _abuf or current.buffer.number + raise NotImplementedError + + +@_vim +def _emul_bufnr(expr): + if expr == '$': + return _last_bufnr + raise NotImplementedError + + +@_vim +def _emul_exists(ident): + if ident.startswith('g:'): + return ident[2:] in vars + elif ident.startswith(':'): + return 0 + raise NotImplementedError + + +@_vim +def _emul_line2byte(line): + buflines = current.buffer._buf_lines + if line == len(buflines) + 1: + return sum((len(s) for s in buflines)) + 1 + raise NotImplementedError + + +@_vim +def _emul_line(expr): + cursorline = current.window.cursor[0] + 1 + numlines = len(current.buffer._buf_lines) + if expr == 'w0': + return max(cursorline - 5, 1) + if expr == 'w$': + return min(cursorline + 5, numlines) + raise NotImplementedError + + +@_vim +@_str_func +def _emul_strtrans(s): + # FIXME Do more replaces + return s.replace(b'\xFF', b'<ff>') + + +@_vim +@_str_func +def _emul_bufname(bufnr): + try: + return buffers[bufnr]._name or b'' + except KeyError: + return b'' + + +_window_id = 0 + + +class _Window(object): + def __init__(self, number, buffer=None, cursor=(1, 0), width=80): + global _window_id + self.cursor = cursor + self.width = width + self.number = number + if buffer: + if type(buffer) is _Buffer: + self.buffer = buffer + else: + self.buffer = _Buffer(**buffer) + else: + self.buffer = _Buffer() + _window_id += 1 + self._window_id = _window_id + self.options = {} + self.vars = { + 'powerline_window_id': self._window_id, + } + + def __repr__(self): + return '<window ' + str(self.number - 1) + '>' + + +class _Tabpage(object): + def __init__(self, number): + self.windows = _ObjList(_Window) + self.number = number + + def _new_window(self, **kwargs): + self.window = self.windows._new(**kwargs) + return self.window + + def _close_window(self, winnr, open_window=True): + curwinnr = self.window.number + win = self.windows._pop(winnr) + if self.windows and winnr == curwinnr: + self.window = self.windows[-1] + elif open_window: + current.tabpage._new_window() + return win + + def _close(self): + global _tabpage + while self.windows: + self._close_window(1, False) + tabpages._pop(self.number) + _tabpage = len(tabpages) + + +tabpages = _ObjList(_Tabpage) + + +_abuf = None + + +class _Buffer(object): + def __init__(self, name=None): + global _last_bufnr + _last_bufnr += 1 + bufnr = _last_bufnr + self.number = bufnr + # FIXME Use unicode() for python-3 + self.name = name + self.vars = {'changedtick': 1} + self.options = { + 'modified': 0, + 'readonly': 0, + 'fileformat': 'unix', + 'filetype': '', + 'buftype': '', + 'fileencoding': 'utf-8', + 'textwidth': 80, + } + self._buf_lines = [''] + self._undostate = [self._buf_lines[:]] + self._undo_written = len(self._undostate) + buffers[bufnr] = self + + @property + def name(self): + import sys + if sys.version_info < (3,): + return self._name + else: + return str(self._name, 'utf-8') if self._name else None + + @name.setter + def name(self, name): + if name is None: + self._name = None + else: + import os + if type(name) is not bytes: + name = name.encode('utf-8') + if b':/' in name: + self._name = name + else: + self._name = os.path.abspath(name) + + def __getitem__(self, line): + return self._buf_lines[line] + + def __setitem__(self, line, value): + self.options['modified'] = 1 + self.vars['changedtick'] += 1 + self._buf_lines[line] = value + from copy import copy + self._undostate.append(copy(self._buf_lines)) + + def __setslice__(self, *args): + self.options['modified'] = 1 + self.vars['changedtick'] += 1 + self._buf_lines.__setslice__(*args) + from copy import copy + self._undostate.append(copy(self._buf_lines)) + + def __getslice__(self, *args): + return self._buf_lines.__getslice__(*args) + + def __len__(self): + return len(self._buf_lines) + + def __repr__(self): + return '<buffer ' + str(self.name) + '>' + + def __del__(self): + global _abuf + bufnr = self.number + try: + import __main__ + except ImportError: + pass + except RuntimeError: + # Module may have already been garbage-collected + pass + else: + if _on_wipeout: + _abuf = bufnr + try: + for event in _on_wipeout: + exec(event, __main__.__dict__) + finally: + _abuf = None + + +class _Current(object): + @property + def buffer(self): + return self.window.buffer + + @property + def window(self): + return self.tabpage.window + + @property + def tabpage(self): + return tabpages[_tabpage - 1] + + +current = _Current() + + +_dict = None + + +@_vim +def _init(): + global _dict + + if _dict: + return _dict + + _dict = {} + for varname, value in globals().items(): + if varname[0] != '_': + _dict[varname] = value + _tabnew() + return _dict + + +@_vim +def _get_segment_info(): + mode_translations = { + chr(ord('V') - 0x40): '^V', + chr(ord('S') - 0x40): '^S', + } + mode = _mode + mode = mode_translations.get(mode, mode) + window = current.window + buffer = current.buffer + tabpage = current.tabpage + return { + 'window': window, + 'winnr': window.number, + 'buffer': buffer, + 'bufnr': buffer.number, + 'tabpage': tabpage, + 'tabnr': tabpage.number, + 'window_id': window._window_id, + 'mode': mode, + 'encoding': options['encoding'], + } + + +@_vim +def _launch_event(event): + pass + + +@_vim +def _start_mode(mode): + global _mode + if mode == 'i': + _launch_event('InsertEnter') + elif _mode == 'i': + _launch_event('InsertLeave') + _mode = mode + + +@_vim +def _undo(): + if len(current.buffer._undostate) == 1: + return + buffer = current.buffer + buffer._undostate.pop(-1) + buffer._buf_lines = buffer._undostate[-1] + if buffer._undo_written == len(buffer._undostate): + buffer.options['modified'] = 0 + + +@_vim +def _edit(name=None): + if current.buffer.name is None: + buffer = current.buffer + buffer.name = name + else: + buffer = _Buffer(name) + current.window.buffer = buffer + + +@_vim +def _tabnew(name=None): + global windows + global _tabpage + tabpage = tabpages._new() + windows = tabpage.windows + _tabpage = len(tabpages) + _new(name) + return tabpage + + +@_vim +def _new(name=None): + current.tabpage._new_window(buffer={'name': name}) + + +@_vim +def _split(): + current.tabpage._new_window(buffer=current.buffer) + + +@_vim +def _close(winnr, wipe=True): + win = current.tabpage._close_window(winnr) + if wipe: + for w in current.tabpage.windows: + if w.buffer.number == win.buffer.number: + break + else: + _bw(win.buffer.number) + + +@_vim +def _bw(bufnr=None): + bufnr = bufnr or current.buffer.number + winnr = 1 + for win in current.tabpage.windows: + if win.buffer.number == bufnr: + _close(winnr, wipe=False) + winnr += 1 + buffers._pop(bufnr) + if not buffers: + _Buffer() + _b(max(buffers._keys())) + + +@_vim +def _b(bufnr): + current.window.buffer = buffers[bufnr] + + +@_vim +def _set_cursor(line, col): + current.window.cursor = (line, col) + if _mode == 'n': + _launch_event('CursorMoved') + elif _mode == 'i': + _launch_event('CursorMovedI') + + +@_vim +def _get_buffer(): + return current.buffer + + +@_vim +def _set_bufoption(option, value, bufnr=None): + buffers[bufnr or current.buffer.number].options[option] = value + if option == 'filetype': + _launch_event('FileType') + + +class _WithNewBuffer(object): + def __init__(self, func, *args, **kwargs): + self.call = lambda: func(*args, **kwargs) + + def __enter__(self): + self.call() + self.bufnr = current.buffer.number + return _get_segment_info() + + def __exit__(self, *args): + _bw(self.bufnr) + + +@_vim +def _set_dict(d, new, setfunc=None): + if not setfunc: + def setfunc(k, v): + d[k] = v + + old = {} + na = [] + for k, v in new.items(): + try: + old[k] = d[k] + except KeyError: + na.append(k) + setfunc(k, v) + return old, na + + +class _WithBufOption(object): + def __init__(self, **new): + self.new = new + + def __enter__(self): + self.buffer = current.buffer + self.old = _set_dict(self.buffer.options, self.new, _set_bufoption)[0] + + def __exit__(self, *args): + self.buffer.options.update(self.old) + + +class _WithMode(object): + def __init__(self, new): + self.new = new + + def __enter__(self): + self.old = _mode + _start_mode(self.new) + return _get_segment_info() + + def __exit__(self, *args): + _start_mode(self.old) + + +class _WithDict(object): + def __init__(self, d, **new): + self.new = new + self.d = d + + def __enter__(self): + self.old, self.na = _set_dict(self.d, self.new) + + def __exit__(self, *args): + self.d.update(self.old) + for k in self.na: + self.d.pop(k) + + +class _WithSplit(object): + def __enter__(self): + _split() + + def __exit__(self, *args): + _close(2, wipe=False) + + +class _WithBufName(object): + def __init__(self, new): + self.new = new + + def __enter__(self): + import os + buffer = current.buffer + self.buffer = buffer + self.old = buffer.name + buffer.name = self.new + + def __exit__(self, *args): + self.buffer.name = self.old + + +class _WithNewTabPage(object): + def __init__(self, *args, **kwargs): + self.args = args + self.kwargs = kwargs + + def __enter__(self): + self.tab = _tabnew(*self.args, **self.kwargs) + + def __exit__(self, *args): + self.tab._close() + + +class _WithGlobal(object): + def __init__(self, **kwargs): + self.kwargs = kwargs + + def __enter__(self): + self.empty = object() + self.old = dict(((key, globals().get(key, self.empty)) for key in self.kwargs)) + globals().update(self.kwargs) + + def __exit__(self, *args): + for k, v in self.old.items(): + if v is self.empty: + globals().pop(k, None) + else: + globals()[k] = v + + +@_vim +def _with(key, *args, **kwargs): + if key == 'buffer': + return _WithNewBuffer(_edit, *args, **kwargs) + elif key == 'bufname': + return _WithBufName(*args, **kwargs) + elif key == 'mode': + return _WithMode(*args, **kwargs) + elif key == 'bufoptions': + return _WithBufOption(**kwargs) + elif key == 'options': + return _WithDict(options, **kwargs) + elif key == 'globals': + return _WithDict(vars, **kwargs) + elif key == 'wvars': + return _WithDict(current.window.vars, **kwargs) + elif key == 'environ': + return _WithDict(_environ, **kwargs) + elif key == 'split': + return _WithSplit() + elif key == 'tabpage': + return _WithNewTabPage(*args, **kwargs) + elif key == 'vpos': + return _WithGlobal(_v_pos=[0, kwargs['line'], kwargs['col'], kwargs['off']]) + + +class error(Exception): + pass diff --git a/tests/shlib/common.sh b/tests/shlib/common.sh new file mode 100644 index 0000000..7794192 --- /dev/null +++ b/tests/shlib/common.sh @@ -0,0 +1,150 @@ +: ${USER:=`id -un`} +: ${HOME:=`getent passwd $USER | cut -d: -f6`} + +if test -z "${PYTHON}" ; then + if test -n "$USE_UCS2_PYTHON" ; then + LD_LIBRARY_PATH="$HOME/opt/cpython-ucs2-$UCS2_PYTHON_VARIANT/lib${LD_LIBRARY_PATH:+:}${LD_LIBRARY_PATH}" + fi +fi + +export LD_LIBRARY_PATH +export USER +export HOME + +if test -n "$USE_UCS2_PYTHON" ; then + POWERLINE_VIRTUALENV="cpython-ucs2-$UCS2_PYTHON_VARIANT" + PYTHON="$HOME/.virtualenvs/$POWERLINE_VIRTUALENV/bin/python" + if test -n "$BASH_VERSION" ; then + set +e + . virtualenvwrapper.sh + workon "$POWERLINE_VIRTUALENV" + set -e + fi +fi + +. tests/bot-ci/scripts/common/main.sh silent + +export USER HOME + +if test -z "$FAILED" ; then + FAILED=0 + + FAIL_SUMMARY="" + + TMP_ROOT="$ROOT/tests/tmp" + export FAILURES_FILE="$ROOT/tests/status" +fi + +ANSI_CLEAR="\033[0K" + +travis_fold() { + local action="$1" + local name="$2" + name="$(echo -n "$name" | tr '\n\0' '--' | sed -r 's/[^A-Za-z0-9]+/-/g')" + name="$(echo -n "$name" | sed -r 's/-$//')" + echo -en "travis_fold:${action}:${name}\r${ANSI_CLEAR}" +} + +print_environ() { + echo "Using $PYTHON_IMPLEMENTATION version $PYTHON_VERSION." + echo "Path to Python executable: $PYTHON." + echo "Root: $ROOT." + echo "Branch: $BRANCH_NAME." + echo "sys.path:" + "$PYTHON" -c "for path in __import__('sys').path: print(' %r' % path)" +} + +enter_suite() { + set +x + local suite_name="$1" ; shift + local final="$1" + export POWERLINE_CURRENT_SUITE="${POWERLINE_CURRENT_SUITE}/$suite_name" + travis_fold start "$POWERLINE_CURRENT_SUITE" + print_environ + if test "$final" = final ; then + if test -n "$POWERLINE_SUITE_FINAL" ; then + fail __suite__/enter/final E "Final suites do not allow nesting" + fi + export POWERLINE_SUITE_FINAL=1 + # set -x + fi +} + +exit_suite() { + if test "$POWERLINE_CURRENT_SUITE" = "$POWERLINE_TMP_DIR_SUITE" ; then + rm_test_root + fi + if test $FAILED -ne 0 ; then + echo "Suite ${POWERLINE_CURRENT_SUITE} failed, summary:" + echo "${FAIL_SUMMARY}" + fi + set +x + travis_fold end "$POWERLINE_CURRENT_SUITE" + export POWERLINE_CURRENT_SUITE="${POWERLINE_CURRENT_SUITE%/*}" + if test "$1" != "--continue" ; then + exit $FAILED + else + unset POWERLINE_SUITE_FINAL + fi +} + +_fail() { + local allow_failure= + if test "$1" = "--allow-failure" ; then + shift + allow_failure=A + fi + local test_name="$1" ; shift + local fail_char="$allow_failure$1" ; shift + local message="$1" ; shift + local verb="$1" ; shift + local full_msg="$fail_char $POWERLINE_CURRENT_SUITE|$test_name :: $message" + FAIL_SUMMARY="${FAIL_SUMMARY}${NL}${full_msg}" + echo "$verb: $full_msg" + echo "$full_msg" >> "$FAILURES_FILE" + if test -z "$allow_failure" ; then + FAILED=1 + fi +} + +fail() { + _fail "$@" "Failed" +} + +skip() { + local test_name="$1" ; shift + local message="$1" ; shift + _fail --allow-failure "$test_name" S "$message" "Skipped" +} + +make_test_root() { + local suffix="${POWERLINE_CURRENT_SUITE##*/}" + + local tmpdir="$TMP_ROOT/$suffix/" + export POWERLINE_TMP_DIR_SUITE="$POWERLINE_CURRENT_SUITE" + + if test -d "$tmpdir" ; then + rm -r "$tmpdir" + fi + + mkdir -p "$tmpdir" + + export TEST_ROOT="$tmpdir" +} + +rm_test_root() { + if test -e "$FAILURES_FILE" ; then + return 0 + fi + local suffix="${POWERLINE_CURRENT_SUITE##*/}" + if test -d "$TMP_ROOT/$suffix" ; then + rm -r "$TMP_ROOT/$suffix" + rmdir "$TMP_ROOT" &>/dev/null || true + fi +} + +if ! command -v realpath ; then + realpath() { + $PYTHON -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$1" + } +fi diff --git a/tests/shlib/vim.sh b/tests/shlib/vim.sh new file mode 100644 index 0000000..49346da --- /dev/null +++ b/tests/shlib/vim.sh @@ -0,0 +1,33 @@ +. tests/bot-ci/scripts/common/main.sh + +if test -z "$POWERLINE_VIM_EXE" ; then + if test -n "$USE_UCS2_PYTHON" ; then + NEW_VIM="$ROOT/tests/bot-ci/deps/vim/master-$UCS2_PYTHON_VARIANT-ucs2-double/vim" + OLD_VIM="$ROOT/tests/bot-ci/deps/vim/v7.0.112-$UCS2_PYTHON_VARIANT-ucs2/vim" + opt_dir="$HOME/opt/cpython-ucs2-$UCS2_PYTHON_VARIANT" + main_path="$opt_dir/lib/python$UCS2_PYTHON_VARIANT" + site_path="$main_path/site-packages" + venv_main_path="$VIRTUAL_ENV/lib/python$UCS2_PYTHON_VARIANT" + venv_site_path="$venv_main_path/site-packages" + new_paths="${main_path}:${site_path}:${venv_main_path}:${venv_site_path}" + export PYTHONPATH="$new_paths${PYTHONPATH:+:}$PYTHONPATH" + else + if test "$PYTHON_IMPLEMENTATION" != "CPython" ; then + exit 0 + fi + if test -d "$ROOT/tests/bot-ci/deps" ; then + NEW_VIM="$ROOT/tests/bot-ci/deps/vim/master-$PYTHON_MM/vim" + OLD_VIM="$ROOT/tests/bot-ci/deps/vim/v7.0.112-$PYTHON_MM/vim" + else + NEW_VIM="vim" + fi + if test -e "$OLD_VIM" ; then + VIMS="NEW_VIM OLD_VIM" + else + VIMS="NEW_VIM" + fi + fi +else + NEW_VIM="$POWERLINE_VIM_EXE" + OLD_VIM="$POWERLINE_VIM_EXE" +fi diff --git a/tests/shlib/vterm.sh b/tests/shlib/vterm.sh new file mode 100644 index 0000000..bf95bb1 --- /dev/null +++ b/tests/shlib/vterm.sh @@ -0,0 +1,17 @@ +. tests/shlib/common.sh +set +x + +vterm_setup() { + make_test_root + + mkdir "$TEST_ROOT/path" + + ln -s "$(command -v "${PYTHON}")" "$TEST_ROOT/path/python" + ln -s "$(command -v bash)" "$TEST_ROOT/path" + + cp -r "$ROOT/tests/terminfo" "$TEST_ROOT" +} + +vterm_shutdown() { + rm_test_root +} diff --git a/tests/terminfo/s/screen b/tests/terminfo/s/screen Binary files differnew file mode 100644 index 0000000..d380072 --- /dev/null +++ b/tests/terminfo/s/screen diff --git a/tests/terminfo/s/st-256color b/tests/terminfo/s/st-256color Binary files differnew file mode 100644 index 0000000..9c2db04 --- /dev/null +++ b/tests/terminfo/s/st-256color diff --git a/tests/test.sh b/tests/test.sh new file mode 100755 index 0000000..a08806f --- /dev/null +++ b/tests/test.sh @@ -0,0 +1,42 @@ +#!/bin/bash +. tests/shlib/common.sh + +enter_suite root + +if test "$TRAVIS" = true ; then + export PATH="$HOME/opt/fish/bin:${PATH}" + export PATH="$PWD/tests/bot-ci/deps/rc:$PATH" + + if test "$PYTHON_IMPLEMENTATION" = "CPython" ; then + export PATH="$HOME/opt/zsh-${PYTHON_MM}${USE_UCS2_PYTHON:+-ucs2}/bin:${PATH}" + fi + + if test -n "$USE_UCS2_PYTHON" ; then + export LD_LIBRARY_PATH="$HOME/opt/cpython-ucs2-$UCS2_PYTHON_VARIANT/lib${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH" + set +e + . virtualenvwrapper.sh + workon cpython-ucs2-$UCS2_PYTHON_VARIANT + set -e + else + LIBRARY_PATH="$(ldd "$(command -v python)" | grep libpython | sed 's/^.* => //;s/ .*$//')" + LIBRARY_DIR="$(dirname "${LIBRARY_PATH}")" + export LD_LIBRARY_PATH="$LIBRARY_DIR${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH" + fi +fi + +export PYTHON="${PYTHON:=python}" +export PYTHONPATH="${PYTHONPATH}${PYTHONPATH:+:}`realpath .`" +for script in "$ROOT"/tests/test_*/test.sh ; do + test_name="${script##*/run_}" + if ! sh $script ; then + fail "${test_name%_tests.sh}" F "Failed $script" + fi +done + +if test -e "$FAILURES_FILE" ; then + echo "Fails and skips summary:" + cat "$FAILURES_FILE" + rm "$FAILURES_FILE" +fi + +exit_suite diff --git a/tests/test_awesome/path/awesome-client b/tests/test_awesome/path/awesome-client new file mode 100755 index 0000000..2088ff0 --- /dev/null +++ b/tests/test_awesome/path/awesome-client @@ -0,0 +1,3 @@ +#!/bin/sh +echo "$@" >> "$TEST_ROOT/results/args" +cat >> "$TEST_ROOT/results/requests" diff --git a/tests/test_awesome/powerline/config.json b/tests/test_awesome/powerline/config.json new file mode 100644 index 0000000..b8dfd01 --- /dev/null +++ b/tests/test_awesome/powerline/config.json @@ -0,0 +1,7 @@ +{ + "ext": { + "wm": { + "update_interval": 0.5 + } + } +} diff --git a/tests/test_awesome/powerline/themes/wm/default.json b/tests/test_awesome/powerline/themes/wm/default.json new file mode 100644 index 0000000..d9eaf5f --- /dev/null +++ b/tests/test_awesome/powerline/themes/wm/default.json @@ -0,0 +1,18 @@ +{ + "segments": { + "left": [ + { + "type": "string", + "highlight_groups": ["time"], + "contents": "default-left" + } + ], + "right": [ + { + "type": "string", + "highlight_groups": ["time"], + "contents": "default-right" + } + ] + } +} diff --git a/tests/test_awesome/powerline/themes/wm/dvi.json b/tests/test_awesome/powerline/themes/wm/dvi.json new file mode 100644 index 0000000..4cf3731 --- /dev/null +++ b/tests/test_awesome/powerline/themes/wm/dvi.json @@ -0,0 +1,18 @@ +{ + "segments": { + "left": [ + { + "type": "string", + "highlight_groups": ["time"], + "contents": "dvi-left" + } + ], + "right": [ + { + "type": "string", + "highlight_groups": ["time"], + "contents": "dvi-right" + } + ] + } +} diff --git a/tests/test_awesome/test.sh b/tests/test_awesome/test.sh new file mode 100755 index 0000000..7a5614e --- /dev/null +++ b/tests/test_awesome/test.sh @@ -0,0 +1,188 @@ +#!/bin/sh +. tests/shlib/common.sh + +enter_suite awesome + +make_test_root + +TEST_PATH="$TEST_ROOT/path" +TEST_STATIC_ROOT="$ROOT/tests/test_awesome" + +cp -r "$TEST_STATIC_ROOT/path" "$TEST_ROOT" +cp -r "$TEST_STATIC_ROOT/powerline" "$TEST_ROOT" + +export PYTHONPATH="$ROOT${PYTHONPATH:+:}$PYTHONPATH" + +ln -s "$(command -v "${PYTHON}")" "$TEST_PATH"/python +ln -s "$(command -v cat)" "$TEST_PATH" +ln -s "$(command -v sh)" "$TEST_PATH" +ln -s "$(command -v env)" "$TEST_PATH" +if command -v socat ; then + ln -s "$(command -v socat)" "$TEST_PATH" +fi +for pexe in powerline powerline.sh powerline.py ; do + if test -e scripts/$pexe ; then + ln -s "$PWD/scripts/$pexe" $TEST_ROOT/path + elif test -e client/$pexe ; then + ln -s "$PWD/client/$pexe" $TEST_ROOT/path + elif command -v $pexe ; then + ln -s "$(command -v $pexe)" $TEST_ROOT/path + else + continue + fi + if test "$pexe" != 'powerline.sh' || test -e "$TEST_PATH/socat" ; then + POWERLINE_COMMAND="$pexe" + break + fi +done + +DEPRECATED_SCRIPT="$ROOT/powerline/bindings/awesome/powerline-awesome.py" +POWERLINE_DAEMON="scripts/powerline-daemon" + +run() { + env -i \ + LANG=C \ + PATH="$TEST_PATH" \ + XDG_CONFIG_HOME="$TEST_ROOT" \ + XDG_CONFIG_DIRS="$TEST_ROOT/dummy" \ + PYTHONPATH="$PYTHONPATH" \ + TEST_ROOT="$TEST_ROOT" \ + LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \ + "$@" || true +} + +display_log() { + local log_file="$1" + echo "$log_file:" + echo '============================================================' + cat -v "$log_file" + echo + echo '____________________________________________________________' +} + +check_log() { + local args_file="$TEST_ROOT/results/args" + local log_file="$TEST_ROOT/results/requests" + local line="$(head -n1 "$log_file")" + local linenum="$(cat "$log_file" | wc -l)" + echo "Number of runs: $linenum (expected approx 5 / 0.5 = 10 runs)" + if test $linenum -lt 5 ; then + fail "log:lt" F "Script was run not enough times: $linenum < 5" + return 1 + elif test $linenum -gt 15 ; then + fail "log:gt" E "Script was run too many times: $linenum > 15" + return 1 + fi + local expline="powerline_widget:set_markup('<span foreground=\"#303030\"> </span><span foreground=\"#d0d0d0\" background=\"#303030\" font_weight=\"bold\"> default-right </span>')" + if test "$expline" != "$line" ; then + echo "Line: '$line'" + echo "Expected: '$expline'" + fail "log:line" F "Unexpected line" + return 1 + fi + local ret=0 + while test $linenum -gt 0 ; do + echo "$line" >> "$TEST_ROOT/ok" + linenum=$(( linenum - 1 )) + done + if ! diff "$TEST_ROOT/ok" "$log_file" ; then + fail "log:diff" F "Unexpected output" + ret=1 + fi + rm "$TEST_ROOT/ok" + return $ret +} + +killscript() { + kill -KILL $1 || true +} + +if ! test -e "$DEPRECATED_SCRIPT" ; then + # TODO: uncomment when skip is available + # skip "deprecated" "Missing deprecated bar bindings script" + : +else + enter_suite "deprecated" final + for args in "" "0.5"; do + rm -rf "$TEST_ROOT/results" + mkdir "$TEST_ROOT/results" + DEPRECATED_LOG="$TEST_ROOT/deprecated.log" + run env \ + DEPRECATED_SCRIPT="$DEPRECATED_SCRIPT" \ + args="$args" \ + DEPRECATED_LOG="$DEPRECATED_LOG" \ + TEST_ROOT="$TEST_ROOT" \ + sh -c ' + echo $$ > "$TEST_ROOT/$args-pid" + exec "$DEPRECATED_SCRIPT" $args > "$DEPRECATED_LOG" 2>&1 + ' & + sleep 5 + killscript "$(cat "$TEST_ROOT/$args-pid")" + rm "$TEST_ROOT/$args-pid" + if test -n "$(cat "$DEPRECATED_LOG")" ; then + display_log "$DEPRECATED_LOG" + fail "output" E "Nonempty $DEPRECATED_SCRIPT output" + fi + rm "$DEPRECATED_LOG" + if ! check_log ; then + display_log "$TEST_ROOT/results/args" + fail "log" F "Checking log failed" + fi + done + exit_suite --continue +fi + +enter_suite "awesome" final +ADDRESS="powerline-ipc-test-$$" +echo "Powerline address: $ADDRESS" +rm -rf "$TEST_ROOT/results" +mkdir "$TEST_ROOT/results" +run env \ + POWERLINE_DAEMON="$POWERLINE_DAEMON" \ + TEST_ROOT="$TEST_ROOT" \ + ADDRESS="$ADDRESS" \ + sh -c ' + echo $$ > "$TEST_ROOT/dpid" + exec python "$POWERLINE_DAEMON" --socket $ADDRESS --foreground > "$TEST_ROOT/daemon.log" 2>&1 + ' & +DPID=$! +sleep 2 +run "$POWERLINE_COMMAND" --socket $ADDRESS wm.awesome > "$TEST_ROOT/output.log.1" 2>&1 +run "$POWERLINE_COMMAND" --socket $ADDRESS wm.awesome > "$TEST_ROOT/output.log.2" 2>&1 +run "$POWERLINE_COMMAND" --socket $ADDRESS wm.awesome > "$TEST_ROOT/output.log.3" 2>&1 +run "$POWERLINE_COMMAND" --socket $ADDRESS wm.awesome > "$TEST_ROOT/output.log.4" 2>&1 +run "$POWERLINE_COMMAND" --socket $ADDRESS wm.awesome > "$TEST_ROOT/output.log.5" 2>&1 +for log_file in "$TEST_ROOT"/output.log.* ; do + if test -n "$(cat "$log_file")" ; then + display_log "$log_file" + fail "output" E "Nonempty $POWERLINE_COMMAND output at run ${log_file#*.}" + fi + rm "$log_file" +done +sleep 5 +run python "$POWERLINE_DAEMON" --socket $ADDRESS --quiet --kill > "$TEST_ROOT/kill.log" 2>&1 +if test -n "$(cat "$TEST_ROOT/kill.log")" ; then + display_log "$TEST_ROOT/kill.log" + fail "daemonlog" E "Nonempty kill log" +fi +rm "$TEST_ROOT/kill.log" +wait $DPID +if test -n "$(cat "$TEST_ROOT/daemon.log")" ; then + display_log "$TEST_ROOT/daemon.log" + fail "daemonlog" E "Nonempty daemon log" +fi +rm "$TEST_ROOT/daemon.log" +if ! check_log ; then + display_log "$TEST_ROOT/results/args" + fail "log" F "Checking log failed" +fi +exit_suite --continue + +if ! powerline-lint \ + -p "$ROOT/powerline/config_files" \ + -p "$TEST_STATIC_ROOT/powerline" +then + fail "lint" F "Checking test config failed" +fi + +exit_suite diff --git a/tests/test_bar/path/lemonbar b/tests/test_bar/path/lemonbar new file mode 100755 index 0000000..13c6030 --- /dev/null +++ b/tests/test_bar/path/lemonbar @@ -0,0 +1,11 @@ +#!/bin/sh + +RES_DIR="$TEST_ROOT/results" +mkdir -p "$RES_DIR" +RES_FILE="$RES_DIR/$$" +while test -e "$RES_FILE.log" ; do + RES_FILE="$RES_FILE.${RANDOM:-`date +%N | sed s/^0*//`}" +done + +echo $(basename $0) "$@" > "$RES_FILE.args" +cat > "$RES_FILE.log" diff --git a/tests/test_bar/path/xrandr b/tests/test_bar/path/xrandr new file mode 100755 index 0000000..d02e300 --- /dev/null +++ b/tests/test_bar/path/xrandr @@ -0,0 +1,31 @@ +#!/bin/sh + +cat << EOF +Screen 0: minimum 8 x 8, current 1920 x 1200, maximum 16384 x 16384 +DVI-I-0 disconnected (normal left inverted right x axis y axis) +VGA-0 connected 1920x1200+1+0 (normal left inverted right x axis y axis) 520mm x 330mm + 1920x1200 59.95*+ + 1920x1080 60.00 + 1680x1050 59.95 + 1600x1200 60.00 + 1440x900 59.89 + 1280x1024 75.02 60.02 + 1280x800 59.81 + 1152x864 75.00 + 1024x768 75.03 60.00 + 800x600 75.00 60.32 + 640x480 75.00 59.94 +DVI-I-1 connected 1920x1200+0+0 (normal left inverted right x axis y axis) 520mm x 330mm + 1920x1200 59.95*+ + 1920x1080 60.00 + 1680x1050 59.95 + 1600x1200 60.00 + 1440x900 59.89 + 1280x1024 75.02 60.02 + 1280x800 59.81 + 1152x864 75.00 + 1024x768 75.03 60.00 + 800x600 75.00 60.32 + 640x480 75.00 59.94 +HDMI-0 disconnected (normal left inverted right x axis y axis) +EOF diff --git a/tests/test_bar/powerline/config.json b/tests/test_bar/powerline/config.json new file mode 100644 index 0000000..0b35d56 --- /dev/null +++ b/tests/test_bar/powerline/config.json @@ -0,0 +1,9 @@ +{ + "ext": { + "wm": { + "local_themes": { + "DVI-I-1": "dvi" + } + } + } +} diff --git a/tests/test_bar/powerline/themes/wm/default.json b/tests/test_bar/powerline/themes/wm/default.json new file mode 100644 index 0000000..d9eaf5f --- /dev/null +++ b/tests/test_bar/powerline/themes/wm/default.json @@ -0,0 +1,18 @@ +{ + "segments": { + "left": [ + { + "type": "string", + "highlight_groups": ["time"], + "contents": "default-left" + } + ], + "right": [ + { + "type": "string", + "highlight_groups": ["time"], + "contents": "default-right" + } + ] + } +} diff --git a/tests/test_bar/powerline/themes/wm/dvi.json b/tests/test_bar/powerline/themes/wm/dvi.json new file mode 100644 index 0000000..4cf3731 --- /dev/null +++ b/tests/test_bar/powerline/themes/wm/dvi.json @@ -0,0 +1,18 @@ +{ + "segments": { + "left": [ + { + "type": "string", + "highlight_groups": ["time"], + "contents": "dvi-left" + } + ], + "right": [ + { + "type": "string", + "highlight_groups": ["time"], + "contents": "dvi-right" + } + ] + } +} diff --git a/tests/test_bar/test.sh b/tests/test_bar/test.sh new file mode 100755 index 0000000..fa36799 --- /dev/null +++ b/tests/test_bar/test.sh @@ -0,0 +1,195 @@ +#!/bin/sh +. tests/shlib/common.sh + +enter_suite bar + +make_test_root +TEST_PATH="$TEST_ROOT/path" +TEST_STATIC_ROOT="$ROOT/tests/test_bar" + +cp -r "$TEST_STATIC_ROOT/path" "$TEST_ROOT" +cp -r "$TEST_STATIC_ROOT/powerline" "$TEST_ROOT" + +export PYTHONPATH="$ROOT${PYTHONPATH:+:}$PYTHONPATH" + +ln -s "$(command -v "${PYTHON}")" "$TEST_PATH"/python +ln -s "$(command -v sed)" "$TEST_PATH" +ln -s "$(command -v cat)" "$TEST_PATH" +ln -s "$(command -v mkdir)" "$TEST_PATH" +ln -s "$(command -v basename)" "$TEST_PATH" +ln -s "$TEST_PATH/lemonbar" "$TEST_PATH/bar-aint-recursive" + +DEPRECATED_SCRIPT="$ROOT/powerline/bindings/bar/powerline-bar.py" + +run() { + env -i \ + LANG=C \ + PATH="$TEST_PATH" \ + XDG_CONFIG_HOME="$TEST_ROOT" \ + XDG_CONFIG_DIRS="$TEST_ROOT/dummy" \ + PYTHONPATH="$PYTHONPATH" \ + TEST_ROOT="$TEST_ROOT" \ + LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \ + "$@" || true +} + +display_log() { + local log_file="$1" + echo "$log_file:" + echo '============================================================' + cat -v "$log_file" + echo + echo '____________________________________________________________' +} + +check_log() { + local log_file="$1" + local text="$2" + local warns="$3" + if test "$warns" = "warns" ; then + local warning="$(head -n1 "$log_file" | sed 's/.*://')" + local expwarning="The 'bar' bindings are deprecated, please switch to 'lemonbar'" + if test "$warning" != "$expwarning" ; then + echo "Got: $warning" + echo "Exp: $expwarning" + fail "warn" F "Expected warning" + fi + sed -r -i -e '1d' "$log_file" + fi + local line="$(head -n1 "$log_file")" + local linenum="$(cat "$log_file" | wc -l)" + if test $linenum -lt 5 ; then + fail "log:lt" F "Script was run not enough times" + return 1 + elif test $linenum -gt 15 ; then + fail "log:gt" E "Script was run too many times" + return 1 + fi + local expline="%{l}%{F#ffd0d0d0}%{B#ff303030} $text-left %{F-B--u}%{F#ff303030} %{F-B--u}%{r}%{F#ff303030} %{F-B--u}%{F#ffd0d0d0}%{B#ff303030} $text-right %{F-B--u}" + if test "$expline" != "$line" ; then + echo "Line: '$line'" + echo "Expected: '$expline'" + fail "log:line" F "Unexpected line" + return 1 + fi + local ret=0 + while test $linenum -gt 0 ; do + echo "$line" >> "$TEST_ROOT/ok" + linenum=$(( linenum - 1 )) + done + if ! diff "$TEST_ROOT/ok" "$log_file" ; then + fail "log:diff" F "Unexpected output" + ret=1 + fi + rm "$TEST_ROOT/ok" + return $ret +} + +killscript() { + kill -KILL $1 || true +} + +if ! test -e "$DEPRECATED_SCRIPT" ; then + # TODO: uncomment when skip is available + # skip "deprecated" "Missing deprecated bar bindings script" + : +else + enter_suite "deprecated" final + run python "$DEPRECATED_SCRIPT" $args > "$TEST_ROOT/deprecated.log" 2>&1 & + SPID=$! + sleep 5 + killscript $SPID + if ! check_log "$TEST_ROOT/deprecated.log" "default" warns ; then + display_log "$TEST_ROOT/deprecated.log" + fail "log" F "Checking log failed" + fi + rm "$TEST_ROOT/deprecated.log" + exit_suite --continue +fi + +LEMONBAR_SCRIPT="$ROOT/powerline/bindings/lemonbar/powerline-lemonbar.py" + +if ! test -e "$LEMONBAR_SCRIPT" ; then + # TODO: uncomment when skip is available + # skip "lemonbar" "Missing lemonbar bindings script" + : +else + enter_suite "lemonbar" + for args in "" "-i0.5" "--interval=0.5" "-- test args" "--bar-command bar-aint-recursive" "--height=10"; do + rm -rf "$TEST_ROOT/results" + run python "$LEMONBAR_SCRIPT" $args > "$TEST_ROOT/lemonbar.log" 2>&1 & + SPID=$! + sleep 5 + killscript $SPID + sleep 0.5 + enter_suite "args($args)" final + fnum=0 + for file in "$TEST_ROOT/results"/*.log ; do + if ! test -e "$file" ; then + fail "log" E "Log file is missing" + break + fi + fnum=$(( fnum + 1 )) + args_file="${file%.log}.args" + if ! test -e "$args_file" ; then + fail "args" E "$args_file is missing" + else + cat "$args_file" >> "$TEST_ROOT/args.log" + fi + text="dvi" + if cat "$args_file" | grep -q +1 ; then + text="default" + fi + if ! check_log "$file" "$text" ; then + display_log "$file" + fail "log" F "Checking log failed" + fi + rm "$file" + done + if test "$fnum" -ne 2 ; then + fail "fnum" F "Expected two output files" + fi + if test "${args#--height}" != "$args" ; then + height="${args#--height}" + height="${height# }" + height="${height#=}" + height="${height%% *}" + fi + command="lemonbar" + if test "${args#--bar-command}" != "$args" ; then + command="${args#--bar-command}" + command="${command# }" + command="${command#=}" + command="${command%% *}" + fi + received_args="$(cat "$TEST_ROOT/args.log" | sort)" + rm "$TEST_ROOT/args.log" + script_args="${args#*-- }" + script_args="${script_args# }" + if test "${script_args}" = "$args" ; then + script_args= + fi + expected_args="$command -g 1920x$height+0+0${script_args:+ }$script_args${NL}$command -g 1920x$height+1+0${script_args:+ }$script_args" + if test "$expected_args" != "$received_args" ; then + echo "args:${NL}<$received_args>" + echo "expected:${NL}<$expected_args>" + fail "args" F "Expected different args" + fi + if ! test -z "$(cat "$TEST_ROOT/lemonbar.log")" ; then + display_log "$TEST_ROOT/lemonbar.log" + fail "stderr" E "Unexpected script output" + fi + rm "$TEST_ROOT/lemonbar.log" + exit_suite --continue + done + exit_suite --continue +fi + +if ! powerline-lint \ + -p "$ROOT/powerline/config_files" \ + -p "$TEST_STATIC_ROOT/powerline" +then + fail "lint" F "Checking test config failed" +fi + +exit_suite diff --git a/tests/test_daemon/test.sh b/tests/test_daemon/test.sh new file mode 100755 index 0000000..a5c12c1 --- /dev/null +++ b/tests/test_daemon/test.sh @@ -0,0 +1,41 @@ +#!/bin/sh +. tests/shlib/common.sh + +enter_suite daemon final + +export ADDRESS="powerline-ipc-test-$$" +echo "Powerline address: $ADDRESS" +if "$PYTHON" "$ROOT/scripts/powerline-daemon" -s"$ADDRESS" ; then + sleep 1 + if ! ( \ + "$PYTHON" "$ROOT/client/powerline.py" \ + --socket "$ADDRESS" -p/dev/null shell left \ + | grep "file not found" + ) ; then + fail "devnull" F "-p/dev/null argument ignored or not treated properly" + fi + if ( \ + "$PYTHON" "$ROOT/client/powerline.py" --socket "$ADDRESS" \ + -p"$ROOT/powerline/config_files" shell left \ + | grep "file not found" + ) ; then + fail "nodevnull" F "-p/dev/null argument remembered while it should not" + fi + if ! ( \ + cd "$ROOT/tests/test_daemon" \ + && "$PYTHON" "$ROOT/client/powerline.py" --socket "$ADDRESS" \ + -p"$ROOT/powerline/config_files" shell left \ + | grep "test_daemon" + ) ; then + fail "segment" F "Output lacks string “tests”" + fi +else + fail "exitcode" E "Daemon exited with status $?" +fi +if "$PYTHON" "$ROOT/scripts/powerline-daemon" -s"$ADDRESS" -k ; then + : +else + fail "-k" F "powerline-daemon -k failed with exit code $?" +fi + +exit_suite diff --git a/tests/test_in_vterm/shell/inits/dash b/tests/test_in_vterm/shell/inits/dash new file mode 100644 index 0000000..7b146ff --- /dev/null +++ b/tests/test_in_vterm/shell/inits/dash @@ -0,0 +1,16 @@ +# vim: ft=sh + +set_theme_option() { + export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2" +} +set_theme() { + export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1" +} +set_virtual_env() { + export VIRTUAL_ENV="$HOME/.virtenvs/$1" +} +set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false +set_theme default_leftonly +. "$ROOT/powerline/bindings/shell/powerline.sh" +export VIRTUAL_ENV= +cd "$TEST_ROOT/3rd" diff --git a/tests/test_in_vterm/test.sh b/tests/test_in_vterm/test.sh new file mode 100755 index 0000000..ad8d72a --- /dev/null +++ b/tests/test_in_vterm/test.sh @@ -0,0 +1,14 @@ +#!/bin/sh +. tests/shlib/common.sh + +enter_suite vterm + +# (Disabled) +#for t in "$ROOT"/tests/test_in_vterm/test_*.sh ; do +# test_name="${t##*/test_}" +# if ! "$t" ; then +# fail "${test_name%.sh}" F "Failed running $t" +# fi +#done + +exit_suite diff --git a/tests/test_in_vterm/test_shells.py b/tests/test_in_vterm/test_shells.py new file mode 100755 index 0000000..faf7976 --- /dev/null +++ b/tests/test_in_vterm/test_shells.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os +import sys + +from time import sleep +from subprocess import check_call +from glob import glob1 +from traceback import print_exc + +from argparse import ArgumentParser + +from powerline.lib.dict import updated + +from tests.modules.lib.terminal import (ExpectProcess, MutableDimensions, + do_terminal_tests, get_env) +from tests.modules import PowerlineTestSuite + + +TEST_ROOT = os.path.abspath(os.environ['TEST_ROOT']) + + +def get_parser(): + parser = ArgumentParser() + parser.add_argument('--type', action='store') + parser.add_argument('--client', action='store') + parser.add_argument('--binding', action='store') + parser.add_argument('args', action='append') + return parser + + +BINDING_OPTIONS = { + 'dash': { + 'cmd': 'dash', + 'args': ['-i'], + 'init': [ + '. "$ROOT/tests/test_in_vterm/shell/inits/dash"', + ], + }, +} + + +def main(argv): + script_args = get_parser().parse_args(argv) + + vterm_path = os.path.join(TEST_ROOT, 'path') + + env = get_env(vterm_path, TEST_ROOT) + env['ROOT'] = os.path.abspath('.') + env['TEST_ROOT'] = TEST_ROOT + env['TEST_TYPE'] = script_args.type + env['TEST_CLIENT'] = script_args.client + env['LANG'] = 'en_US.UTF_8' + env['_POWERLINE_RUNNING_SHELL_TESTS'] = ( + 'ee5bcdc6-b749-11e7-9456-50465d597777') + + dim = MutableDimensions(rows=50, cols=200) + + binding_opts = BINDING_OPTIONS[script_args.binding] + + cmd = os.path.join(vterm_path, binding_opts['cmd']) + args = binding_opts['args'] + + def gen_init(binding): + def init(p): + for line in binding_opts['init']: + p.send(line + '\n') + sleep(1) + + return init + + def gen_feed(line): + def feed(p): + p.send(line + '\n') + sleep(0.1) + + return feed + + base_attrs = { + ((255, 204,0), (204, 51, 0), 0, 0, 0): 'H', + ((204, 51, 0), (0, 102, 153), 0, 0, 0): 'sHU', + ((255, 255, 255), (0, 102, 153), 1, 0, 0): 'U', + ((0, 102, 153), (44, 44, 44), 0, 0, 0): 'sUB', + ((199, 199, 199), (44, 44, 44), 0, 0, 0): 'B', + ((44, 44, 44), (88, 88, 88), 0, 0, 0): 'sBD', + ((199, 199, 199), (88, 88, 88), 0, 0, 0): 'D', + ((144, 144, 144), (88, 88, 88), 0, 0, 0): 'sD', + ((221, 221, 221), (88, 88, 88), 1, 0, 0): 'C', + ((88, 88, 88), (0, 0, 0), 0, 0, 0): 'sDN', + ((240, 240, 240), (0, 0, 0), 0, 0, 0): 'N', + ((0, 102, 153), (51, 153, 204), 0, 0, 0): 'sUE', + ((255, 255, 255), (51, 153, 204), 0, 0, 0): 'E', + ((51, 153, 204), (44, 44, 44), 0, 0, 0): 'sEB', + } + + tests = ( + { + 'expected_result': ( + '{H: hostname }{sHU: }' + '{U:user }{sUB: }' + '{B: BRANCH }{sBD: }' + '{D:… }{sD: }{D:tmp }{sD: }{D:vshells }{sD: }{C:3rd }{sDN: }' + '{N:}', + base_attrs, + ), + 'prep_cb': gen_init(script_args.binding), + }, + { + 'expected_result': ( + '{H: hostname }{sHU: }' + '{U:user }{sUB: }' + '{B: BRANCH }{sBD: }' + '{D:… }{sD: }{D:vshells }{sD: }{D:3rd }{sD: }{C:.git }{sDN: }' + '{N:}', + base_attrs + ), + 'prep_cb': gen_feed('cd .git'), + }, + { + 'expected_result': ( + '{H: hostname }{sHU: }' + '{U:user }{sUB: }' + '{B: BRANCH }{sBD: }' + '{D:… }{sD: }{D:tmp }{sD: }{D:vshells }{sD: }{C:3rd }{sDN: }' + '{N:}', + base_attrs, + ), + 'prep_cb': gen_feed('cd ..'), + }, + { + 'expected_result': ( + '{H: hostname }{sHU: }' + '{U:user }{sUE: }' + '{E:(e) some-venv }{sEB: }' + '{B: BRANCH }{sBD: }' + '{D:… }{sD: }{D:tmp }{sD: }{D:vshells }{sD: }{C:3rd }{sDN: }' + '{N:}', + base_attrs, + ), + 'prep_cb': gen_feed('set_virtual_env some-venv'), + }, + ) + + with PowerlineTestSuite('shell') as suite: + return do_terminal_tests( + tests=tests, + cmd=cmd, + dim=dim, + args=args, + env=env, + cwd=TEST_ROOT, + suite=suite, + ) + + +if __name__ == '__main__': + if main(sys.argv[1:]): + raise SystemExit(0) + else: + raise SystemExit(1) diff --git a/tests/test_in_vterm/test_shells.sh b/tests/test_in_vterm/test_shells.sh new file mode 100755 index 0000000..f27442a --- /dev/null +++ b/tests/test_in_vterm/test_shells.sh @@ -0,0 +1,119 @@ +#!/bin/bash +. tests/shlib/common.sh +. tests/shlib/vterm.sh + +enter_suite vshells + +vterm_setup + +HAS_SOCAT= +HAS_C_CLIENT= + +git init "$TEST_ROOT/3rd" +git --git-dir="$TEST_ROOT/3rd/.git" checkout -b BRANCH +export DIR1="[32m" +export DIR2="" +mkdir "$TEST_ROOT/3rd/$DIR1" +mkdir "$TEST_ROOT/3rd/$DIR2" +mkdir "$TEST_ROOT"/3rd/'\[\]' +mkdir "$TEST_ROOT"/3rd/'%%' +mkdir "$TEST_ROOT"/3rd/'#[bold]' +mkdir "$TEST_ROOT"/3rd/'(echo)' +mkdir "$TEST_ROOT"/3rd/'$(echo)' +mkdir "$TEST_ROOT"/3rd/'`echo`' +mkdir "$TEST_ROOT"/3rd/'«Unicode!»' +mkdir "$TEST_ROOT/fish_home" +mkdir "$TEST_ROOT/fish_home/fish" +mkdir "$TEST_ROOT/fish_home/fish/generated_completions" +cp -r "$ROOT/tests/test_shells/ipython_home" "$TEST_ROOT" + +ln -s "$(command -v env)" "$TEST_ROOT/path" +ln -s "$(command -v git)" "$TEST_ROOT/path" +ln -s "$(command -v sleep)" "$TEST_ROOT/path" +ln -s "$(command -v cat)" "$TEST_ROOT/path" +ln -s "$(command -v false)" "$TEST_ROOT/path" +ln -s "$(command -v true)" "$TEST_ROOT/path" +ln -s "$(command -v kill)" "$TEST_ROOT/path" +ln -s "$(command -v echo)" "$TEST_ROOT/path" +ln -s "$(command -v which)" "$TEST_ROOT/path" +ln -s "$(command -v dirname)" "$TEST_ROOT/path" +ln -s "$(command -v wc)" "$TEST_ROOT/path" +ln -s "$(command -v stty)" "$TEST_ROOT/path" +ln -s "$(command -v cut)" "$TEST_ROOT/path" +ln -s "$(command -v bc)" "$TEST_ROOT/path" +ln -s "$(command -v expr)" "$TEST_ROOT/path" +ln -s "$(command -v mktemp)" "$TEST_ROOT/path" +ln -s "$(command -v grep)" "$TEST_ROOT/path" +ln -s "$(command -v sed)" "$TEST_ROOT/path" +ln -s "$(command -v rm)" "$TEST_ROOT/path" +ln -s "$(command -v tr)" "$TEST_ROOT/path" +ln -s "$(command -v uname)" "$TEST_ROOT/path" +ln -s "$(command -v test)" "$TEST_ROOT/path" +ln -s "$(command -v pwd)" "$TEST_ROOT/path" +ln -s "$(command -v hostname)" "$TEST_ROOT/path" +ln -s "$ROOT/tests/test_shells/bgscript.sh" "$TEST_ROOT/path" +ln -s "$ROOT/tests/test_shells/waitpid.sh" "$TEST_ROOT/path" + +ln -s "$ROOT/scripts/powerline-config" "$TEST_ROOT/path" +ln -s "$ROOT/scripts/powerline-render" "$TEST_ROOT/path" +ln -s "$ROOT/client/powerline.py" "$TEST_ROOT/path" + +if test -e "$ROOT/scripts/powerline" ; then + ln -s "$ROOT/scripts/powerline" "$TEST_ROOT/path" +elif test -e client/powerline ; then + ln -s "$ROOT/client/powerline" "$TEST_ROOT/path" +elif command -v powerline ; then + ln -s "$(command -v powerline)" "$TEST_ROOT/path" +else + echo "Executable powerline was not found" + exit 1 +fi + +if test "$( + file --mime-type --brief --dereference "$TEST_ROOT/path/powerline" \ + | cut -d/ -f1)" = "application" ; then + HAS_C_CLIENT=1 +fi + +if command -v socat ; then + HAS_SOCAT=1 + ln -s "$(command -v socat)" "$TEST_ROOT/path" + ln -s "$ROOT/client/powerline.sh" "$TEST_ROOT/path" +fi + +# Test type: daemon, renderer, … +# Test client: python, shell, c, none +# Test binding: *sh, ipython, pdb, … +test_shell() { + local test_type="$1" ; shift + local test_client="$1" ; shift + local test_binding="$1" ; shift + + if test "$test_client" = shell && test -z "$HAS_SOCAT" ; then + echo "Skipping test, socat not available" + return + fi + if test "$test_client" = c && test -z "$HAS_C_CLIENT" ; then + echo "Skipping test, C client not available" + return + fi + if command -v "$test_binding" ; then + ln -s "$(command -v "$test_binding")" "$TEST_ROOT/path" + fi + + if ! "${PYTHON}" "$ROOT/tests/test_in_vterm/test_shells.py" \ + --type=$test_type \ + --client=$test_client \ + --binding=$test_binding \ + -- "$@" + then + local test_name="$test_type-$test_client-$test_binding" + fail "$test_name" F "Failed vterm shell test" + fi +} + +test_shell renderer python dash -i || true + +vterm_shutdown + +exit_suite diff --git a/tests/test_in_vterm/test_tmux.py b/tests/test_in_vterm/test_tmux.py new file mode 100755 index 0000000..c1e126b --- /dev/null +++ b/tests/test_in_vterm/test_tmux.py @@ -0,0 +1,251 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os +import sys +import json + +from time import sleep +from subprocess import check_call +from glob import glob1 +from traceback import print_exc + +from powerline.lib.dict import updated +from powerline.bindings.tmux import get_tmux_version +from powerline import get_fallback_logger + +from tests.modules.lib.terminal import (ExpectProcess, MutableDimensions, + do_terminal_tests, get_env) +from tests.modules import PowerlineTestSuite + + +TEST_ROOT = os.path.abspath(os.environ['TEST_ROOT']) + + +def tmux_logs_iter(test_dir): + for tail in glob1(test_dir, '*.log'): + yield os.path.join(test_dir, tail) + + +def print_tmux_logs(): + for f in tmux_logs_iter(TEST_ROOT): + print('_' * 80) + print(os.path.basename(f) + ':') + print('=' * 80) + with open(f, 'r') as fp: + for line in fp: + sys.stdout.write(line) + os.unlink(f) + + +def get_expected_result(tmux_version, + expected_result_old, + expected_result_1_7=None, + expected_result_1_8=None, + expected_result_2_0=None): + if tmux_version >= (2, 0) and expected_result_2_0: + return expected_result_2_0 + elif tmux_version >= (1, 8) and expected_result_1_8: + return expected_result_1_8 + elif tmux_version >= (1, 7) and expected_result_1_7: + return expected_result_1_7 + else: + return expected_result_old + + +def tmux_fin_cb(p, cmd, env): + try: + check_call([ + cmd, '-S', env['POWERLINE_TMUX_SOCKET_PATH'], 'kill-server' + ], env=env, cwd=TEST_ROOT) + except Exception: + print_exc() + for f in tmux_logs_iter(TEST_ROOT): + os.unlink(f) + + +def main(attempts=3): + vterm_path = os.path.join(TEST_ROOT, 'path') + + tmux_exe = os.path.join(vterm_path, 'tmux') + + socket_path = os.path.abspath('tmux-socket-{0}'.format(attempts)) + if os.path.exists(socket_path): + os.unlink(socket_path) + + env = get_env(vterm_path, TEST_ROOT, { + 'POWERLINE_THEME_OVERRIDES': ';'.join(( + key + '=' + json.dumps(val) + for key, val in ( + ('default.segments.right', [{ + 'type': 'string', + 'name': 's1', + 'highlight_groups': ['cwd'], + 'priority':50, + }]), + ('default.segments.left', [{ + 'type': 'string', + 'name': 's2', + 'highlight_groups': ['background'], + 'priority':20, + }]), + ('default.segment_data.s1.contents', 'S1 string here'), + ('default.segment_data.s2.contents', 'S2 string here'), + ) + )), + 'POWERLINE_TMUX_SOCKET_PATH': socket_path, + }) + + conf_path = os.path.abspath('powerline/bindings/tmux/powerline.conf') + conf_line = 'source "' + ( + conf_path.replace('\\', '\\\\').replace('"', '\\"')) + '"\n' + conf_file = os.path.realpath(os.path.join(TEST_ROOT, 'tmux.conf')) + with open(conf_file, 'w') as cf_fd: + cf_fd.write(conf_line) + + tmux_version = get_tmux_version(get_fallback_logger()) + + dim = MutableDimensions(rows=50, cols=200) + + def prepare_test_1(p): + sleep(5) + + def prepare_test_2(p): + dim.cols = 40 + p.resize(dim) + sleep(5) + + base_attrs = { + ((0, 0, 0), (243, 243, 243), 1, 0, 0): 'lead', + ((243, 243, 243), (11, 11, 11), 0, 0, 0): 'leadsep', + ((255, 255, 255), (11, 11, 11), 0, 0, 0): 'bg', + ((199, 199, 199), (88, 88, 88), 0, 0, 0): 'cwd', + ((88, 88, 88), (11, 11, 11), 0, 0, 0): 'cwdhsep', + ((0, 0, 0), (0, 224, 0), 0, 0, 0): 'defstl', + } + tests = ( + { + 'expected_result': get_expected_result( + tmux_version, + expected_result_old=( + '{lead: 0 }{leadsep: }{bg: S2 string here }' + '{4: 0 }{cwdhsep:| }{6:bash }' + '{bg: }{4: 1- }{cwdhsep:| }{6:bash }' + '{bg: }{7: }{8:2* | }{9:bash }{10: }' + '{bg:' + (' ' * 124) + '}' + '{cwdhsep: }{cwd: S1 string here }', updated(base_attrs, { + ((133, 133, 133), (11, 11, 11), 0, 0, 0): 4, + ((188, 188, 188), (11, 11, 11), 0, 0, 0): 6, + ((11, 11, 11), (0, 102, 153), 0, 0, 0): 7, + ((102, 204, 255), (0, 102, 153), 0, 0, 0): 8, + ((255, 255, 255), (0, 102, 153), 1, 0, 0): 9, + ((0, 102, 153), (11, 11, 11), 0, 0, 0): 10, + })), + expected_result_1_8=( + '{lead: 0 }{leadsep: }{bg: S2 string here }' + '{4: 0 }{cwdhsep:| }{6:bash }' + '{bg: }{4: 1- }{cwdhsep:| }{7:bash }' + '{bg: }{8: }{9:2* | }{10:bash }{7: }' + '{bg:' + (' ' * 124) + '}' + '{cwdhsep: }{cwd: S1 string here }', updated(base_attrs, { + ((133, 133, 133), (11, 11, 11), 0, 0, 0): 4, + ((188, 188, 188), (11, 11, 11), 0, 0, 0): 6, + ((0, 102, 153), (11, 11, 11), 0, 0, 0): 7, + ((11, 11, 11), (0, 102, 153), 0, 0, 0): 8, + ((102, 204, 255), (0, 102, 153), 0, 0, 0): 9, + ((255, 255, 255), (0, 102, 153), 1, 0, 0): 10, + })), + expected_result_2_0=( + '{lead: 0 }{leadsep: }{bg: S2 string here }' + '{4: 0 }{cwdhsep:| }{6:bash }' + '{bg: }{4: 1- }{cwdhsep:| }{7:bash }' + '{bg: }{8: }{9:2* | }{10:bash }{7: }' + '{bg:' + (' ' * 125) + '}' + '{cwdhsep: }{cwd: S1 string here }', updated(base_attrs, { + ((133, 133, 133), (11, 11, 11), 0, 0, 0): 4, + ((188, 188, 188), (11, 11, 11), 0, 0, 0): 6, + ((0, 102, 153), (11, 11, 11), 0, 0, 0): 7, + ((11, 11, 11), (0, 102, 153), 0, 0, 0): 8, + ((102, 204, 255), (0, 102, 153), 0, 0, 0): 9, + ((255, 255, 255), (0, 102, 153), 1, 0, 0): 10, + })), + ), + 'prep_cb': prepare_test_1, + 'row': dim.rows - 1, + }, { + 'expected_result': get_expected_result( + tmux_version, + expected_result_old=('{bg:' + (' ' * 40) + '}', base_attrs), + expected_result_1_7=( + '{lead: 0 }' + '{leadsep: }{bg: <}{4:h }{bg: }{5: }' + '{6:2* | }{7:bash }{8: }{bg: }{cwdhsep: }' + '{cwd: S1 string here }', updated(base_attrs, { + ((188, 188, 188), (11, 11, 11), 0, 0, 0): 4, + ((11, 11, 11), (0, 102, 153), 0, 0, 0): 5, + ((102, 204, 255), (0, 102, 153), 0, 0, 0): 6, + ((255, 255, 255), (0, 102, 153), 1, 0, 0): 7, + ((0, 102, 153), (11, 11, 11), 0, 0, 0): 8, + })), + expected_result_1_8=( + '{lead: 0 }' + '{leadsep: }{bg: <}{4:h }{bg: }{5: }' + '{6:2* | }{7:bash }{4: }{bg: }{cwdhsep: }' + '{cwd: S1 string here }', updated(base_attrs, { + ((0, 102, 153), (11, 11, 11), 0, 0, 0): 4, + ((11, 11, 11), (0, 102, 153), 0, 0, 0): 5, + ((102, 204, 255), (0, 102, 153), 0, 0, 0): 6, + ((255, 255, 255), (0, 102, 153), 1, 0, 0): 7, + })), + expected_result_2_0=( + '{lead: 0 }' + '{leadsep: }{bg:<}{4:ash }{bg: }{5: }' + '{6:2* | }{7:bash }{4: }{cwdhsep: }' + '{cwd: S1 string here }', updated(base_attrs, { + ((0, 102, 153), (11, 11, 11), 0, 0, 0): 4, + ((11, 11, 11), (0, 102, 153), 0, 0, 0): 5, + ((102, 204, 255), (0, 102, 153), 0, 0, 0): 6, + ((255, 255, 255), (0, 102, 153), 1, 0, 0): 7, + })), + ), + 'prep_cb': prepare_test_2, + 'row': dim.rows - 1, + } + ) + + args = [ + # Specify full path to tmux socket (testing tmux instance must not + # interfere with user one) + '-S', socket_path, + # Force 256-color mode + '-2', + # Request verbose logging just in case + '-v', + # Specify configuration file + '-f', conf_file, + # Run bash three times + 'new-session', 'bash --norc --noprofile -i', ';', + 'new-window', 'bash --norc --noprofile -i', ';', + 'new-window', 'bash --norc --noprofile -i', ';', + ] + + with PowerlineTestSuite('tmux') as suite: + return do_terminal_tests( + tests=tests, + cmd=tmux_exe, + dim=dim, + args=args, + env=env, + cwd=TEST_ROOT, + fin_cb=tmux_fin_cb, + last_attempt_cb=print_tmux_logs, + suite=suite, + ) + + +if __name__ == '__main__': + if main(): + raise SystemExit(0) + else: + raise SystemExit(1) diff --git a/tests/test_in_vterm/test_tmux.sh b/tests/test_in_vterm/test_tmux.sh new file mode 100755 index 0000000..ab4e007 --- /dev/null +++ b/tests/test_in_vterm/test_tmux.sh @@ -0,0 +1,44 @@ +#!/bin/bash +. tests/shlib/common.sh +. tests/shlib/vterm.sh + +enter_suite tmux final + +vterm_setup + +ln -s "$(command -v env)" "$TEST_ROOT/path" +ln -s "$(command -v cut)" "$TEST_ROOT/path" +ln -s "$ROOT/scripts/powerline-render" "$TEST_ROOT/path" +ln -s "$ROOT/scripts/powerline-config" "$TEST_ROOT/path" + +test_tmux() { + if test "$PYTHON_IMPLEMENTATION" = PyPy; then + # FIXME PyPy3 segfaults for some reason, PyPy does it as well, but + # occasionally. + return 0 + fi + if ! command -v "${POWERLINE_TMUX_EXE}" ; then + return 0 + fi + ln -sf "$(command -v "${POWERLINE_TMUX_EXE}")" "$TEST_ROOT/path/tmux" + f="$ROOT/tests/test_in_vterm/test_tmux.py" + if ! "${PYTHON}" "$f" ; then + local test_name="$("$POWERLINE_TMUX_EXE" -V 2>&1 | cut -d' ' -f2)" + fail "$test_name" F "Failed vterm test $f" + fi +} + +if test -z "$POWERLINE_TMUX_EXE" && test -d "$ROOT/tests/bot-ci/deps/tmux" +then + for tmux in "$ROOT"/tests/bot-ci/deps/tmux/tmux-*/tmux ; do + export POWERLINE_TMUX_EXE="$tmux" + test_tmux || true + done +else + export POWERLINE_TMUX_EXE="${POWERLINE_TMUX_EXE:-tmux}" + test_tmux || true +fi + +vterm_shutdown + +exit_suite diff --git a/tests/test_in_vterm/test_vim.py b/tests/test_in_vterm/test_vim.py new file mode 100755 index 0000000..0fbc319 --- /dev/null +++ b/tests/test_in_vterm/test_vim.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os +import sys + +from time import sleep +from subprocess import check_call +from glob import glob1 +from traceback import print_exc + +from powerline.lib.dict import updated + +from tests.modules.lib.terminal import (ExpectProcess, MutableDimensions, + do_terminal_tests, get_env) +from tests.modules import PowerlineTestSuite + + +TEST_ROOT = os.path.abspath(os.environ['TEST_ROOT']) + + +def main(attempts=3): + vterm_path = os.path.join(TEST_ROOT, 'path') + + vim_exe = os.path.join(vterm_path, 'vim') + + env = get_env(vterm_path, TEST_ROOT) + env['ROOT'] = os.path.abspath('.') + + dim = MutableDimensions(rows=50, cols=200) + + vimrc = os.path.join(TEST_ROOT, 'init.vim') + vimrc_contents = ''' + set laststatus=2 + set runtimepath=$ROOT/powerline/bindings/vim + ''' + with open(vimrc, 'w') as vd: + vd.write(vimrc_contents) + + base_attrs = { + (( 64, 64, 255), (0, 0, 0), 0, 0, 0): 'NT', # NonText + ((240, 240, 240), (0, 0, 0), 0, 0, 0): 'N', # Normal + } + + args = [ + '-u', vimrc, + '-i', 'NONE', + ] + + def feed(p): + p.send(':echo strtrans(eval(&statusline[2:]))\n') + + tests = ( + ) + + with PowerlineTestSuite('vim') as suite: + return do_terminal_tests( + tests=tests, + cmd=vim_exe, + dim=dim, + args=args, + env=env, + cwd=TEST_ROOT, + suite=suite, + ) + + +if __name__ == '__main__': + if main(): + raise SystemExit(0) + else: + raise SystemExit(1) diff --git a/tests/test_in_vterm/test_vim.sh b/tests/test_in_vterm/test_vim.sh new file mode 100755 index 0000000..2811e45 --- /dev/null +++ b/tests/test_in_vterm/test_vim.sh @@ -0,0 +1,39 @@ +#!/bin/sh +. tests/shlib/common.sh +. tests/shlib/vterm.sh +. tests/shlib/vim.sh + +enter_suite vvim final + +vterm_setup + +test_vim() { + if test "$PYTHON_IMPLEMENTATION" != CPython ; then + # Can only link with cpython + return 0 + fi + if ! command -v "$POWERLINE_VIM_EXE" ; then + return 0 + fi + ln -sf "$(command -v "${POWERLINE_VIM_EXE}")" "$TEST_ROOT/path/vim" + f="$ROOT/tests/test_in_vterm/test_vim.py" + if ! "${PYTHON}" "$f" ; then + local test_name="$(LANG=C "$POWERLINE_VIM_EXE" --cmd 'echo version' --cmd qa 2>&1 | tail -n2)" + fail "$test_name" F "Failed vterm test $f" + fi +} + +if test -z "$POWERLINE_VIM_EXE" && test -d "$ROOT/tests/bot-ci/deps/vim" +then + for vim in "$OLD_VIM" "$NEW_VIM" ; do + export POWERLINE_VIM_EXE="$vim" + test_vim || true + done +else + export POWERLINE_VIM_EXE="${POWERLINE_VIM_EXE:-vim}" + test_vim || true +fi + +vterm_shutdown + +exit_suite diff --git a/tests/test_lint/test.sh b/tests/test_lint/test.sh new file mode 100755 index 0000000..03c2f8a --- /dev/null +++ b/tests/test_lint/test.sh @@ -0,0 +1,10 @@ +#!/bin/sh +. tests/shlib/common.sh + +enter_suite lint final + +if ! "$PYTHON" "$ROOT/scripts/powerline-lint" -p "$ROOT/powerline/config_files" ; then + fail "test" F "Running powerline-lint failed" +fi + +exit_suite diff --git a/tests/test_python/empty b/tests/test_python/empty new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/test_python/empty diff --git a/tests/test_python/test.sh b/tests/test_python/test.sh new file mode 100755 index 0000000..f042237 --- /dev/null +++ b/tests/test_python/test.sh @@ -0,0 +1,13 @@ +#!/bin/sh +. tests/shlib/common.sh + +enter_suite python final + +for file in "$ROOT"/tests/test_python/test_*.py ; do + test_name="${file##*/test_}" + if ! "$PYTHON" "$file" --verbose --catch ; then + fail "${test_name%.py}" F "Failed test(s) from $file" + fi +done + +exit_suite diff --git a/tests/test_python/test_cmdline.py b/tests/test_python/test_cmdline.py new file mode 100644 index 0000000..470a7b4 --- /dev/null +++ b/tests/test_python/test_cmdline.py @@ -0,0 +1,149 @@ +# vim:fileencoding=utf-8:noet + +'''Tests for shell.py parser''' + +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys + +if sys.version_info < (3,): + from io import BytesIO as StrIO +else: + from io import StringIO as StrIO + +from powerline.commands.main import get_argparser, finish_args + +from tests.modules import TestCase +from tests.modules.lib import replace_attr + + +class TestParser(TestCase): + def test_main_err(self): + parser = get_argparser() + out = StrIO() + err = StrIO() + + def flush(): + out.truncate(0) + err.truncate(0) + + with replace_attr(sys, 'stdout', out, 'stderr', err): + for raising_args, raising_reg in [ + ([], 'too few arguments|the following arguments are required: ext'), + (['-r'], 'expected one argument'), + (['shell', '-r'], 'expected one argument'), + (['shell', '-w'], 'expected one argument'), + (['shell', '-c'], 'expected one argument'), + (['shell', '-t'], 'expected one argument'), + (['shell', '-p'], 'expected one argument'), + (['shell', '-R'], 'expected one argument'), + (['shell', '--renderer-module'], 'expected one argument'), + (['shell', '--width'], 'expected one argument'), + (['shell', '--last-exit-code'], 'expected one argument'), + (['shell', '--last-pipe-status'], 'expected one argument'), + (['shell', '--config-override'], 'expected one argument'), + (['shell', '--theme-override'], 'expected one argument'), + (['shell', '--config-path'], 'expected one argument'), + (['shell', '--renderer-arg'], 'expected one argument'), + (['shell', '--jobnum'], 'expected one argument'), + (['-r', '.zsh'], 'too few arguments|the following arguments are required: ext'), + (['shell', '--last-exit-code', 'i'], 'invalid int_or_sig value'), + (['shell', '--last-pipe-status', '1 i'], 'invalid <lambda> value'), + ]: + self.assertRaises(SystemExit, parser.parse_args, raising_args) + self.assertFalse(out.getvalue()) + self.assertRegexpMatches(err.getvalue(), raising_reg) + flush() + + def test_main_normal(self): + parser = get_argparser() + out = StrIO() + err = StrIO() + with replace_attr(sys, 'stdout', out, 'stderr', err): + for argv, expargs in [ + (['shell', 'left'], {'ext': ['shell'], 'side': 'left'}), + (['shell', 'left', '-r', '.zsh'], {'ext': ['shell'], 'renderer_module': '.zsh', 'side': 'left'}), + ([ + 'shell', + 'left', + '-r', '.zsh', + '--last-exit-code', '10', + '--last-pipe-status', '10 20 30', + '--jobnum=10', + '-w', '100', + '-c', 'common.term_truecolor=true', + '-c', 'common.spaces=4', + '-t', 'default.segment_data.hostname.before=H:', + '-p', '.', + '-p', '..', + '-R', 'smth={"abc":"def"}', + ], { + 'ext': ['shell'], + 'side': 'left', + 'renderer_module': '.zsh', + 'last_exit_code': 10, + 'last_pipe_status': [10, 20, 30], + 'jobnum': 10, + 'width': 100, + 'config_override': {'common': {'term_truecolor': True, 'spaces': 4}}, + 'theme_override': { + 'default': { + 'segment_data': { + 'hostname': { + 'before': 'H:' + } + } + } + }, + 'config_path': ['.', '..'], + 'renderer_arg': {'smth': {'abc': 'def'}}, + }), + (['shell', 'left', '-R', 'arg=true'], { + 'ext': ['shell'], + 'side': 'left', + 'renderer_arg': {'arg': True}, + }), + (['shell', 'left', '-R', 'arg=true', '-R', 'arg='], { + 'ext': ['shell'], + 'side': 'left', + 'renderer_arg': {}, + }), + (['shell', 'left', '-R', 'arg='], {'ext': ['shell'], 'renderer_arg': {}, 'side': 'left'}), + (['shell', 'left', '-t', 'default.segment_info={"hostname": {}}'], { + 'ext': ['shell'], + 'side': 'left', + 'theme_override': { + 'default': { + 'segment_info': { + 'hostname': {} + } + } + }, + }), + (['shell', 'left', '-c', 'common={ }'], { + 'ext': ['shell'], + 'side': 'left', + 'config_override': {'common': {}}, + }), + (['shell', 'left', '--last-pipe-status='], { + 'ext': ['shell'], + 'side': 'left', + 'last_pipe_status': [], + }), + ]: + args = parser.parse_args(argv) + finish_args(parser, {}, args) + for key, val in expargs.items(): + self.assertEqual(getattr(args, key), val) + for key, val in args.__dict__.items(): + if key not in expargs: + self.assertFalse(val, msg='key {0} is {1} while it should be something false'.format(key, val)) + self.assertFalse(err.getvalue() + out.getvalue(), msg='unexpected output: {0!r} {1!r}'.format( + err.getvalue(), + out.getvalue(), + )) + + +if __name__ == '__main__': + from tests.modules import main + main() diff --git a/tests/test_python/test_config_merging.py b/tests/test_python/test_config_merging.py new file mode 100644 index 0000000..3f4fa2a --- /dev/null +++ b/tests/test_python/test_config_merging.py @@ -0,0 +1,270 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os +import json + +from subprocess import check_call +from operator import add +from shutil import rmtree + +from powerline.lib.dict import mergedicts_copy as mdc +from powerline import Powerline + +from tests.modules import TestCase +from tests.modules.lib.config_mock import select_renderer, UT + + +CONFIG_DIR = 'tests/config' + + +root_config = lambda: { + 'common': { + 'interval': None, + 'watcher': 'auto', + }, + 'ext': { + 'test': { + 'theme': 'default', + 'colorscheme': 'default', + }, + }, +} + + +colors_config = lambda: { + 'colors': { + 'c1': 1, + 'c2': 2, + }, + 'gradients': { + }, +} + + +colorscheme_config = lambda: { + 'groups': { + 'g': {'fg': 'c1', 'bg': 'c2', 'attrs': []}, + } +} + + +theme_config = lambda: { + 'segment_data': { + 's': { + 'before': 'b', + }, + }, + 'segments': { + 'left': [ + { + 'type': 'string', + 'name': 's', + 'contents': 't', + 'highlight_groups': ['g'], + }, + ], + 'right': [], + } +} + +top_theme_config = lambda: { + 'dividers': { + 'left': { + 'hard': '#>', + 'soft': '|>', + }, + 'right': { + 'hard': '<#', + 'soft': '<|', + }, + }, + 'spaces': 0, +} + + +main_tree = lambda: { + '1/config': root_config(), + '1/colors': colors_config(), + '1/colorschemes/default': colorscheme_config(), + '1/themes/test/default': theme_config(), + '1/themes/' + UT: top_theme_config(), + '1/themes/other1': mdc(top_theme_config(), { + 'dividers': { + 'left': { + 'hard': '!>', + } + } + }), + '1/themes/other2': mdc(top_theme_config(), { + 'dividers': { + 'left': { + 'hard': '>>', + } + } + }), +} + + +def mkdir_recursive(directory): + if os.path.isdir(directory): + return + mkdir_recursive(os.path.dirname(directory)) + os.mkdir(directory) + + +class TestPowerline(Powerline): + def get_config_paths(self): + return tuple(sorted([ + os.path.join(CONFIG_DIR, d) + for d in os.listdir(CONFIG_DIR) + ])) + + +class WithConfigTree(object): + __slots__ = ('tree', 'p', 'p_kwargs') + + def __init__(self, tree, p_kwargs={'run_once': True}): + self.tree = tree + self.p = None + self.p_kwargs = p_kwargs + + def __enter__(self, *args): + os.mkdir(CONFIG_DIR) + for k, v in self.tree.items(): + fname = os.path.join(CONFIG_DIR, k) + '.json' + mkdir_recursive(os.path.dirname(fname)) + with open(fname, 'w') as F: + json.dump(v, F) + select_renderer(simpler_renderer=True) + self.p = TestPowerline( + ext='test', + renderer_module='tests.modules.lib.config_mock', + **self.p_kwargs + ) + if os.environ.get('POWERLINE_RUN_LINT_DURING_TESTS'): + try: + check_call(['scripts/powerline-lint'] + reduce(add, ( + ['-p', d] for d in self.p.get_config_paths() + ))) + except: + self.__exit__() + raise + return self.p.__enter__(*args) + + def __exit__(self, *args): + try: + rmtree(CONFIG_DIR) + finally: + if self.p: + self.p.__exit__(*args) + + +class TestMerging(TestCase): + def assertRenderEqual(self, p, output, **kwargs): + self.assertEqual(p.render(**kwargs).replace(' ', ' '), output) + + def test_not_merged_config(self): + with WithConfigTree(main_tree()) as p: + self.assertRenderEqual(p, '{12} bt{2-}#>{--}') + + def test_root_config_merging(self): + with WithConfigTree(mdc(main_tree(), { + '2/config': { + 'common': { + 'default_top_theme': 'other1', + } + }, + })) as p: + self.assertRenderEqual(p, '{12} bt{2-}!>{--}') + with WithConfigTree(mdc(main_tree(), { + '2/config': { + 'common': { + 'default_top_theme': 'other1', + } + }, + '3/config': { + 'common': { + 'default_top_theme': 'other2', + } + }, + })) as p: + self.assertRenderEqual(p, '{12} bt{2-}>>{--}') + + def test_top_theme_merging(self): + with WithConfigTree(mdc(main_tree(), { + '2/themes/' + UT: { + 'spaces': 1, + }, + '3/themes/' + UT: { + 'dividers': { + 'left': { + 'hard': '>>', + } + } + }, + })) as p: + self.assertRenderEqual(p, '{12} bt {2-}>>{--}') + + def test_colors_config_merging(self): + with WithConfigTree(mdc(main_tree(), { + '2/colors': { + 'colors': { + 'c1': 3, + } + }, + })) as p: + self.assertRenderEqual(p, '{32} bt{2-}#>{--}') + with WithConfigTree(mdc(main_tree(), { + '2/colors': { + 'colors': { + 'c1': 3, + } + }, + '3/colors': { + 'colors': { + 'c1': 4, + } + }, + })) as p: + self.assertRenderEqual(p, '{42} bt{2-}#>{--}') + with WithConfigTree(mdc(main_tree(), { + '2/colors': { + 'colors': { + 'c1': 3, + } + }, + '3/colors': { + 'colors': { + 'c2': 4, + } + }, + })) as p: + self.assertRenderEqual(p, '{34} bt{4-}#>{--}') + + def test_colorschemes_merging(self): + with WithConfigTree(mdc(main_tree(), { + '2/colorschemes/default': { + 'groups': { + 'g': {'fg': 'c2', 'bg': 'c1', 'attrs': []}, + } + }, + })) as p: + self.assertRenderEqual(p, '{21} bt{1-}#>{--}') + + def test_theme_merging(self): + with WithConfigTree(mdc(main_tree(), { + '2/themes/test/default': { + 'segment_data': { + 's': { + 'after': 'a', + } + } + }, + })) as p: + self.assertRenderEqual(p, '{12} bta{2-}#>{--}') + + +if __name__ == '__main__': + from tests.modules import main + main() diff --git a/tests/test_python/test_config_reload.py b/tests/test_python/test_config_reload.py new file mode 100644 index 0000000..a418d49 --- /dev/null +++ b/tests/test_python/test_config_reload.py @@ -0,0 +1,319 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +from time import sleep +from copy import deepcopy +from functools import wraps + +from tests.modules import TestCase +from tests.modules.lib.config_mock import get_powerline, add_watcher_events, UT + + +config = { + 'config': { + 'common': { + 'interval': 0, + 'watcher': 'test', + }, + 'ext': { + 'test': { + 'theme': 'default', + 'colorscheme': 'default', + }, + }, + }, + 'colors': { + 'colors': { + "col1": 1, + "col2": 2, + "col3": 3, + "col4": 4, + }, + 'gradients': { + }, + }, + 'colorschemes/test/default': { + 'groups': { + 'str1': {'fg': 'col1', 'bg': 'col2', 'attrs': ['bold']}, + 'str2': {'fg': 'col3', 'bg': 'col4', 'attrs': ['underline']}, + }, + }, + 'colorschemes/test/2': { + 'groups': { + 'str1': {'fg': 'col2', 'bg': 'col3', 'attrs': ['bold']}, + 'str2': {'fg': 'col1', 'bg': 'col4', 'attrs': ['underline']}, + }, + }, + 'themes/test/default': { + 'segments': { + "left": [ + { + "type": "string", + "contents": "s", + "highlight_groups": ["str1"], + }, + { + "type": "string", + "contents": "g", + "highlight_groups": ["str2"], + }, + ], + "right": [ + ], + }, + }, + 'themes/' + UT: { + 'dividers': { + "left": { + "hard": ">>", + "soft": ">", + }, + "right": { + "hard": "<<", + "soft": "<", + }, + }, + 'spaces': 0, + }, + 'themes/other': { + 'dividers': { + "left": { + "hard": ">>", + "soft": ">", + }, + "right": { + "hard": "<<", + "soft": "<", + }, + }, + 'spaces': 1, + }, + 'themes/test/2': { + 'segments': { + "left": [ + { + "type": "string", + "contents": "t", + "highlight_groups": ["str1"], + }, + { + "type": "string", + "contents": "b", + "highlight_groups": ["str2"], + }, + ], + "right": [ + ], + }, + }, +} + + +def with_new_config(func): + @wraps(func) + def f(self): + return func(self, deepcopy(config)) + return f + + +class TestConfigReload(TestCase): + def assertAccessEvents(self, p, *args): + events = set() + for event in args: + if ':' not in event: + events.add('check:' + event) + events.add('load:' + event) + else: + events.add(event) + self.assertEqual(set(p._pop_events()), events) + + @with_new_config + def test_noreload(self, config): + with get_powerline(config, run_once=True) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>><None None None>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') + config['config']['common']['spaces'] = 1 + add_watcher_events(p, 'config', wait=False, interval=0.05) + # When running once thread should not start + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>><None None None>') + self.assertAccessEvents(p) + self.assertEqual(p.logger._pop_msgs(), []) + + @with_new_config + def test_reload_main(self, config): + with get_powerline(config, run_once=False) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>><None None None>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') + + config['config']['common']['default_top_theme'] = 'other' + add_watcher_events(p, 'config') + p.render() + self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>><None None None>') + self.assertAccessEvents(p, 'config', 'themes/other', 'check:themes/test/__main__', 'themes/test/default') + self.assertEqual(p.logger._pop_msgs(), []) + + config['config']['ext']['test']['theme'] = 'nonexistent' + add_watcher_events(p, 'config') + self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>><None None None>') + self.assertAccessEvents(p, 'config', 'check:themes/test/nonexistent', 'themes/other', 'check:themes/test/__main__') + # It should normally handle file missing error + self.assertEqual(p.logger._pop_msgs(), [ + 'exception:test:powerline:Failed to load theme: themes/test/__main__', + 'exception:test:powerline:Failed to load theme: themes/test/nonexistent', + 'exception:test:powerline:Failed to create renderer: themes/test/nonexistent' + ]) + + config['config']['ext']['test']['theme'] = 'default' + add_watcher_events(p, 'config') + self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>><None None None>') + self.assertAccessEvents(p, 'config', 'themes/test/default', 'themes/other', 'check:themes/test/__main__') + self.assertEqual(p.logger._pop_msgs(), []) + + config['config']['ext']['test']['colorscheme'] = 'nonexistent' + add_watcher_events(p, 'config') + self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>><None None None>') + self.assertAccessEvents(p, 'config', 'check:colorschemes/nonexistent', 'check:colorschemes/test/__main__', 'check:colorschemes/test/nonexistent') + # It should normally handle file missing error + self.assertEqual(p.logger._pop_msgs(), [ + 'exception:test:powerline:Failed to load colorscheme: colorschemes/nonexistent', + 'exception:test:powerline:Failed to load colorscheme: colorschemes/test/__main__', + 'exception:test:powerline:Failed to load colorscheme: colorschemes/test/nonexistent', + 'exception:test:powerline:Failed to create renderer: colorschemes/test/nonexistent' + ]) + + config['config']['ext']['test']['colorscheme'] = '2' + add_watcher_events(p, 'config') + self.assertEqual(p.render(), '<2 3 1> s <3 4 False>>><1 4 4>g <4 False False>>><None None None>') + self.assertAccessEvents(p, 'config', 'check:colorschemes/2', 'check:colorschemes/test/__main__', 'colorschemes/test/2') + self.assertEqual(p.logger._pop_msgs(), []) + + config['config']['ext']['test']['theme'] = '2' + add_watcher_events(p, 'config') + self.assertEqual(p.render(), '<2 3 1> t <3 4 False>>><1 4 4>b <4 False False>>><None None None>') + self.assertAccessEvents(p, 'config', 'themes/test/2', 'themes/other', 'check:themes/test/__main__') + self.assertEqual(p.logger._pop_msgs(), []) + + self.assertEqual(p.renderer.local_themes, None) + config['config']['ext']['test']['local_themes'] = 'something' + add_watcher_events(p, 'config') + self.assertEqual(p.render(), '<2 3 1> t <3 4 False>>><1 4 4>b <4 False False>>><None None None>') + self.assertAccessEvents(p, 'config') + self.assertEqual(p.logger._pop_msgs(), []) + self.assertEqual(p.renderer.local_themes, 'something') + + @with_new_config + def test_reload_unexistent(self, config): + with get_powerline(config, run_once=False) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>><None None None>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') + + config['config']['ext']['test']['colorscheme'] = 'nonexistentraise' + add_watcher_events(p, 'config') + # It may appear that p.logger._pop_msgs() is called after given + # exception is added to the mesagges, but before config_loader + # exception was added (this one: + # “exception:test:config_loader:Error while running condition + # function for key colorschemes/test/nonexistentraise: + # fcf:colorschemes/test/nonexistentraise”). + # sleep(0.1) + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>><None None None>') + # For colorschemes/{test/,}*raise find_config_file raises + # IOError, but it does not do so for check:colorschemes/test/__main__, + # so powerline is trying to load this, but not other + # colorschemes/* + self.assertAccessEvents(p, 'config', 'check:colorschemes/test/__main__', 'check:colorschemes/nonexistentraise', 'check:colorschemes/test/nonexistentraise') + self.assertIn('exception:test:powerline:Failed to create renderer: fcf:colorschemes/test/nonexistentraise', p.logger._pop_msgs()) + + config['colorschemes/nonexistentraise'] = {} + config['colorschemes/test/nonexistentraise'] = { + 'groups': { + 'str1': {'fg': 'col1', 'bg': 'col3', 'attrs': ['bold']}, + 'str2': {'fg': 'col2', 'bg': 'col4', 'attrs': ['underline']}, + }, + } + while not p._will_create_renderer(): + sleep(0.1) + self.assertEqual(p.render(), '<1 3 1> s<3 4 False>>><2 4 4>g<4 False False>>><None None None>') + # Same as above + self.assertAccessEvents(p, 'colorschemes/nonexistentraise', 'colorschemes/test/nonexistentraise', 'check:colorschemes/test/__main__') + self.assertEqual(p.logger._pop_msgs(), []) + + @with_new_config + def test_reload_colors(self, config): + with get_powerline(config, run_once=False) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>><None None None>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') + + config['colors']['colors']['col1'] = 5 + add_watcher_events(p, 'colors') + self.assertEqual(p.render(), '<5 2 1> s<2 4 False>>><3 4 4>g<4 False False>>><None None None>') + self.assertAccessEvents(p, 'colors') + self.assertEqual(p.logger._pop_msgs(), []) + + @with_new_config + def test_reload_colorscheme(self, config): + with get_powerline(config, run_once=False) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>><None None None>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') + + config['colorschemes/test/default']['groups']['str1']['bg'] = 'col3' + add_watcher_events(p, 'colorschemes/test/default') + self.assertEqual(p.render(), '<1 3 1> s<3 4 False>>><3 4 4>g<4 False False>>><None None None>') + self.assertAccessEvents(p, 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default') + self.assertEqual(p.logger._pop_msgs(), []) + + @with_new_config + def test_reload_theme(self, config): + with get_powerline(config, run_once=False) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>><None None None>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') + + config['themes/test/default']['segments']['left'][0]['contents'] = 'col3' + add_watcher_events(p, 'themes/test/default') + self.assertEqual(p.render(), '<1 2 1> col3<2 4 False>>><3 4 4>g<4 False False>>><None None None>') + self.assertAccessEvents(p, 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') + self.assertEqual(p.logger._pop_msgs(), []) + + @with_new_config + def test_reload_top_theme(self, config): + with get_powerline(config, run_once=False) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>><None None None>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') + + config['themes/' + UT]['dividers']['left']['hard'] = '|>' + add_watcher_events(p, 'themes/' + UT) + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>|><3 4 4>g<4 False False>|><None None None>') + self.assertAccessEvents(p, 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') + self.assertEqual(p.logger._pop_msgs(), []) + + @with_new_config + def test_reload_theme_main(self, config): + config['config']['common']['interval'] = None + with get_powerline(config, run_once=False) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>><None None None>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') + + config['themes/test/default']['segments']['left'][0]['contents'] = 'col3' + add_watcher_events(p, 'themes/test/default', wait=False) + self.assertEqual(p.render(), '<1 2 1> col3<2 4 False>>><3 4 4>g<4 False False>>><None None None>') + self.assertAccessEvents(p, 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') + self.assertEqual(p.logger._pop_msgs(), []) + self.assertTrue(p._watcher._calls) + + @with_new_config + def test_run_once_no_theme_reload(self, config): + config['config']['common']['interval'] = None + with get_powerline(config, run_once=True) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>><None None None>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') + + config['themes/test/default']['segments']['left'][0]['contents'] = 'col3' + add_watcher_events(p, 'themes/test/default', wait=False) + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>><None None None>') + self.assertAccessEvents(p) + self.assertEqual(p.logger._pop_msgs(), []) + + +if __name__ == '__main__': + from tests.modules import main + main() diff --git a/tests/test_python/test_configuration.py b/tests/test_python/test_configuration.py new file mode 100644 index 0000000..aa9e844 --- /dev/null +++ b/tests/test_python/test_configuration.py @@ -0,0 +1,877 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys +import os + +from functools import wraps +from copy import deepcopy + +import tests.modules.vim as vim_module + +from tests.modules import TestCase +from tests.modules.lib.config_mock import (get_powerline, get_powerline_raw, + swap_attributes, UT) +from tests.modules.lib import Args, replace_item + + +def highlighted_string(s, group, **kwargs): + ret = { + 'type': 'string', + 'contents': s, + 'highlight_groups': [group], + } + ret.update(kwargs) + return ret + + +config = { + 'config': { + 'common': { + 'interval': 0, + 'watcher': 'test', + }, + 'ext': { + 'test': { + 'theme': 'default', + 'colorscheme': 'default', + }, + 'vim': { + 'theme': 'default', + 'colorscheme': 'default', + }, + 'shell': { + 'theme': 'default', + 'colorscheme': 'default', + }, + 'wm': { + 'theme': 'default', + 'colorscheme': 'default', + }, + }, + }, + 'colors': { + 'colors': { + 'col1': 1, + 'col2': 2, + 'col3': 3, + 'col4': 4, + 'col5': 5, + 'col6': 6, + 'col7': 7, + 'col8': 8, + 'col9': 9, + 'col10': 10, + 'col11': 11, + 'col12': 12, + }, + 'gradients': { + }, + }, + 'colorschemes/test/__main__': { + 'groups': { + 'm1': 'g1', + 'm2': 'g3', + 'm3': {'fg': 'col11', 'bg': 'col12', 'attrs': []}, + } + }, + 'colorschemes/default': { + 'groups': { + 'g1': {'fg': 'col5', 'bg': 'col6', 'attrs': []}, + 'g2': {'fg': 'col7', 'bg': 'col8', 'attrs': []}, + 'g3': {'fg': 'col9', 'bg': 'col10', 'attrs': []}, + } + }, + 'colorschemes/test/default': { + 'groups': { + 'str1': {'fg': 'col1', 'bg': 'col2', 'attrs': ['bold']}, + 'str2': {'fg': 'col3', 'bg': 'col4', 'attrs': ['underline']}, + 'd1': 'g2', + 'd2': 'm2', + 'd3': 'm3', + }, + }, + 'colorschemes/vim/default': { + 'groups': { + 'environment': {'fg': 'col3', 'bg': 'col4', 'attrs': ['underline']}, + }, + }, + 'colorschemes/wm/default': { + 'groups': { + 'hl1': {'fg': 'col1', 'bg': 'col2', 'attrs': ['underline']}, + 'hl2': {'fg': 'col2', 'bg': 'col1', 'attrs': []}, + 'hl3': {'fg': 'col3', 'bg': 'col1', 'attrs': ['underline']}, + 'hl4': {'fg': 'col2', 'bg': 'col4', 'attrs': []}, + }, + }, + 'themes/test/default': { + 'segments': { + 'left': [ + highlighted_string('s', 'str1', width='auto'), + highlighted_string('g', 'str2'), + ], + 'right': [ + highlighted_string('f', 'str2', width='auto', align='r'), + ], + }, + }, + 'themes/' + UT: { + 'dividers': { + 'left': { + 'hard': '>>', + 'soft': '>', + }, + 'right': { + 'hard': '<<', + 'soft': '<', + }, + }, + 'spaces': 0, + }, + 'themes/test/__main__': { + 'dividers': { + 'right': { + 'soft': '|', + }, + }, + }, + 'themes/vim/default': { + 'segments': { + 'left': [ + { + 'function': 'powerline.segments.common.env.environment', + 'args': { + 'variable': 'TEST', + }, + }, + ], + }, + }, + 'themes/shell/default': { + 'default_module': 'powerline.segments.common', + 'segments': { + 'left': [ + highlighted_string('s', 'g1', width='auto'), + ], + }, + }, + 'themes/wm/default': { + 'default_module': 'powerline.segments.common', + 'segments': { + 'left': [ + highlighted_string('A', 'hl1'), + highlighted_string('B', 'hl2'), + ], + 'right': [ + highlighted_string('C', 'hl3'), + highlighted_string('D', 'hl4'), + ], + }, + }, +} + + +def with_new_config(func): + @wraps(func) + def f(self): + return func(self, deepcopy(config)) + return f + + +def add_args(func): + @wraps(func) + def f(self): + new_config = deepcopy(config) + with get_powerline(new_config, run_once=True, simpler_renderer=True) as p: + func(self, p, new_config) + return f + + +class TestRender(TestCase): + def assertRenderEqual(self, p, output, **kwargs): + self.assertEqual(p.render(**kwargs).replace(' ', ' '), output) + + def assertRenderLinesEqual(self, p, output, **kwargs): + self.assertEqual([l.replace(' ', ' ') for l in p.render_above_lines(**kwargs)], output) + + +class TestLines(TestRender): + @add_args + def test_without_above(self, p, config): + self.assertRenderEqual(p, '{121} s{24}>>{344}g{34}>{34}|{344}f {--}') + self.assertRenderEqual(p, '{121} s {24}>>{344}g{34}>{34}|{344}f {--}', width=10) + # self.assertRenderEqual(p, '{121} s {24}>>{344}g{34}>{34}|{344} f {--}', width=11) + self.assertEqual(list(p.render_above_lines()), []) + + @with_new_config + def test_with_above(self, config): + old_segments = deepcopy(config['themes/test/default']['segments']) + config['themes/test/default']['segments']['above'] = [old_segments] + with get_powerline(config, run_once=True, simpler_renderer=True) as p: + self.assertRenderLinesEqual(p, [ + '{121} s{24}>>{344}g{34}>{34}|{344}f {--}', + ]) + self.assertRenderLinesEqual(p, [ + '{121} s {24}>>{344}g{34}>{34}|{344}f {--}', + ], width=10) + + config['themes/test/default']['segments']['above'] = [old_segments] * 2 + with get_powerline(config, run_once=True, simpler_renderer=True) as p: + self.assertRenderLinesEqual(p, [ + '{121} s{24}>>{344}g{34}>{34}|{344}f {--}', + '{121} s{24}>>{344}g{34}>{34}|{344}f {--}', + ]) + self.assertRenderLinesEqual(p, [ + '{121} s {24}>>{344}g{34}>{34}|{344}f {--}', + '{121} s {24}>>{344}g{34}>{34}|{344}f {--}', + ], width=10) + + +class TestSegments(TestRender): + @add_args + def test_display(self, p, config): + config['themes/test/default']['segments']['left'][0]['display'] = False + config['themes/test/default']['segments']['left'][1]['display'] = True + config['themes/test/default']['segments']['right'][0]['display'] = False + self.assertRenderEqual(p, '{344} g{4-}>>{--}') + + +class TestColorschemesHierarchy(TestRender): + @add_args + def test_group_redirects(self, p, config): + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('a', 'd1', draw_hard_divider=False), + highlighted_string('b', 'd2', draw_hard_divider=False), + highlighted_string('c', 'd3', draw_hard_divider=False), + highlighted_string('A', 'm1', draw_hard_divider=False), + highlighted_string('B', 'm2', draw_hard_divider=False), + highlighted_string('C', 'm3', draw_hard_divider=False), + highlighted_string('1', 'g1', draw_hard_divider=False), + highlighted_string('2', 'g2', draw_hard_divider=False), + highlighted_string('3', 'g3', draw_hard_divider=False), + ], + 'right': [], + } + self.assertRenderEqual(p, '{78} a{910}b{1112}c{56}A{910}B{1112}C{56}1{78}2{910}3{--}') + self.assertEqual(p.logger._pop_msgs(), []) + + @add_args + def test_group_redirects_no_main(self, p, config): + del config['colorschemes/test/__main__'] + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('a', 'd1', draw_hard_divider=False), + highlighted_string('1', 'g1', draw_hard_divider=False), + highlighted_string('2', 'g2', draw_hard_divider=False), + highlighted_string('3', 'g3', draw_hard_divider=False), + ], + 'right': [], + } + self.assertRenderEqual(p, '{78} a{56}1{78}2{910}3{--}') + self.assertEqual(p.logger._pop_msgs(), []) + + @add_args + def test_group_redirects_no_top_default(self, p, config): + del config['colorschemes/default'] + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('c', 'd3', draw_soft_divider=False), + highlighted_string('C', 'm3', draw_hard_divider=False), + ], + 'right': [], + } + self.assertRenderEqual(p, '{1112} c{1112}C{--}') + self.assertEqual(p.logger._pop_msgs(), []) + + @add_args + def test_group_redirects_no_test_default(self, p, config): + del config['colorschemes/test/default'] + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('A', 'm1', draw_hard_divider=False), + highlighted_string('B', 'm2', draw_hard_divider=False), + highlighted_string('C', 'm3', draw_hard_divider=False), + highlighted_string('1', 'g1', draw_hard_divider=False), + highlighted_string('2', 'g2', draw_hard_divider=False), + highlighted_string('3', 'g3', draw_hard_divider=False), + ], + 'right': [], + } + self.assertRenderEqual(p, '{56} A{910}B{1112}C{56}1{78}2{910}3{--}') + self.assertEqual(p.logger._pop_msgs(), []) + + @add_args + def test_group_redirects_only_main(self, p, config): + del config['colorschemes/default'] + del config['colorschemes/test/default'] + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('C', 'm3', draw_hard_divider=False), + ], + 'right': [], + } + # Powerline is not able to work without default colorscheme + # somewhere, thus it will output error string + self.assertRenderEqual(p, 'colorschemes/test/default') + self.assertEqual(p.logger._pop_msgs(), [ + 'exception:test:powerline:Failed to load colorscheme: colorschemes/default', + 'exception:test:powerline:Failed to load colorscheme: colorschemes/test/default', + 'exception:test:powerline:Failed to create renderer: colorschemes/test/default', + 'exception:test:powerline:Failed to render: colorschemes/test/default', + ]) + + @add_args + def test_group_redirects_only_top_default(self, p, config): + del config['colorschemes/test/__main__'] + del config['colorschemes/test/default'] + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('1', 'g1', draw_hard_divider=False), + highlighted_string('2', 'g2', draw_hard_divider=False), + highlighted_string('3', 'g3', draw_hard_divider=False), + ], + 'right': [], + } + self.assertRenderEqual(p, '{56} 1{78}2{910}3{--}') + self.assertEqual(p.logger._pop_msgs(), []) + + @add_args + def test_group_redirects_only_test_default(self, p, config): + del config['colorschemes/default'] + del config['colorschemes/test/__main__'] + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('s', 'str1', draw_hard_divider=False), + ], + 'right': [], + } + self.assertRenderEqual(p, '{121} s{--}') + self.assertEqual(p.logger._pop_msgs(), []) + + +class TestThemeHierarchy(TestRender): + @add_args + def test_hierarchy(self, p, config): + self.assertRenderEqual(p, '{121} s{24}>>{344}g{34}>{34}|{344}f {--}') + + @add_args + def test_no_main(self, p, config): + del config['themes/test/__main__'] + self.assertRenderEqual(p, '{121} s{24}>>{344}g{34}>{34}<{344}f {--}') + self.assertEqual(p.logger._pop_msgs(), []) + + @add_args + def test_no_powerline(self, p, config): + config['themes/test/__main__']['dividers'] = config['themes/' + UT]['dividers'] + config['themes/test/__main__']['spaces'] = 1 + del config['themes/' + UT] + self.assertRenderEqual(p, '{121} s {24}>>{344}g {34}>{34}<{344} f {--}') + self.assertEqual(p.logger._pop_msgs(), []) + + @add_args + def test_no_default(self, p, config): + del config['themes/test/default'] + self.assertRenderEqual(p, 'themes/test/default') + self.assertEqual(p.logger._pop_msgs(), [ + 'exception:test:powerline:Failed to load theme: themes/test/default', + 'exception:test:powerline:Failed to create renderer: themes/test/default', + 'exception:test:powerline:Failed to render: themes/test/default', + ]) + + @add_args + def test_only_default(self, p, config): + config['themes/test/default']['dividers'] = config['themes/' + UT]['dividers'] + config['themes/test/default']['spaces'] = 1 + del config['themes/test/__main__'] + del config['themes/' + UT] + self.assertRenderEqual(p, '{121} s {24}>>{344}g {34}>{34}<{344} f {--}') + + @add_args + def test_only_main(self, p, config): + del config['themes/test/default'] + del config['themes/' + UT] + self.assertRenderEqual(p, 'themes/test/default') + self.assertEqual(p.logger._pop_msgs(), [ + 'exception:test:powerline:Failed to load theme: themes/' + UT, + 'exception:test:powerline:Failed to load theme: themes/test/default', + 'exception:test:powerline:Failed to create renderer: themes/test/default', + 'exception:test:powerline:Failed to render: themes/test/default', + ]) + + @add_args + def test_only_powerline(self, p, config): + del config['themes/test/default'] + del config['themes/test/__main__'] + self.assertRenderEqual(p, 'themes/test/default') + self.assertEqual(p.logger._pop_msgs(), [ + 'exception:test:powerline:Failed to load theme: themes/test/__main__', + 'exception:test:powerline:Failed to load theme: themes/test/default', + 'exception:test:powerline:Failed to create renderer: themes/test/default', + 'exception:test:powerline:Failed to render: themes/test/default', + ]) + + @add_args + def test_nothing(self, p, config): + del config['themes/test/default'] + del config['themes/' + UT] + del config['themes/test/__main__'] + self.assertRenderEqual(p, 'themes/test/default') + self.assertEqual(p.logger._pop_msgs(), [ + 'exception:test:powerline:Failed to load theme: themes/' + UT, + 'exception:test:powerline:Failed to load theme: themes/test/__main__', + 'exception:test:powerline:Failed to load theme: themes/test/default', + 'exception:test:powerline:Failed to create renderer: themes/test/default', + 'exception:test:powerline:Failed to render: themes/test/default', + ]) + + +class TestDisplayCondition(TestRender): + @add_args + def test_include_modes(self, p, config): + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('s1', 'g1', include_modes=['m1']), + highlighted_string('s2', 'g1', include_modes=['m1', 'm2']), + highlighted_string('s3', 'g1', include_modes=['m3']), + ] + } + self.assertRenderEqual(p, '{--}') + self.assertRenderEqual(p, '{56} s1{56}>{56}s2{6-}>>{--}', mode='m1') + self.assertRenderEqual(p, '{56} s2{6-}>>{--}', mode='m2') + self.assertRenderEqual(p, '{56} s3{6-}>>{--}', mode='m3') + + @add_args + def test_exclude_modes(self, p, config): + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('s1', 'g1', exclude_modes=['m1']), + highlighted_string('s2', 'g1', exclude_modes=['m1', 'm2']), + highlighted_string('s3', 'g1', exclude_modes=['m3']), + ] + } + self.assertRenderEqual(p, '{56} s1{56}>{56}s2{56}>{56}s3{6-}>>{--}') + self.assertRenderEqual(p, '{56} s3{6-}>>{--}', mode='m1') + self.assertRenderEqual(p, '{56} s1{56}>{56}s3{6-}>>{--}', mode='m2') + self.assertRenderEqual(p, '{56} s1{56}>{56}s2{6-}>>{--}', mode='m3') + + @add_args + def test_exinclude_modes(self, p, config): + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('s1', 'g1', exclude_modes=['m1'], include_modes=['m2']), + highlighted_string('s2', 'g1', exclude_modes=['m1', 'm2'], include_modes=['m3']), + highlighted_string('s3', 'g1', exclude_modes=['m3'], include_modes=['m3']), + ] + } + self.assertRenderEqual(p, '{--}') + self.assertRenderEqual(p, '{--}', mode='m1') + self.assertRenderEqual(p, '{56} s1{6-}>>{--}', mode='m2') + self.assertRenderEqual(p, '{56} s2{6-}>>{--}', mode='m3') + + @add_args + def test_exinclude_function_nonexistent_module(self, p, config): + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('s1', 'g1', exclude_function='xxx_nonexistent_module.foo'), + highlighted_string('s2', 'g1', exclude_function='xxx_nonexistent_module.foo', include_function='xxx_nonexistent_module.bar'), + highlighted_string('s3', 'g1', include_function='xxx_nonexistent_module.bar'), + ] + } + self.assertRenderEqual(p, '{56} s1{56}>{56}s2{56}>{56}s3{6-}>>{--}') + + @add_args + def test_exinclude_function(self, p, config): + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('s1', 'g1', exclude_function='mod.foo'), + highlighted_string('s2', 'g1', exclude_function='mod.foo', include_function='mod.bar'), + highlighted_string('s3', 'g1', include_function='mod.bar'), + ] + } + launched = set() + fool = [None] + barl = [None] + + def foo(*args, **kwargs): + launched.add('foo') + self.assertEqual(set(kwargs.keys()), set(('pl', 'segment_info', 'mode'))) + self.assertEqual(args, ()) + return fool[0] + + def bar(*args, **kwargs): + launched.add('bar') + self.assertEqual(set(kwargs.keys()), set(('pl', 'segment_info', 'mode'))) + self.assertEqual(args, ()) + return barl[0] + + with replace_item(sys.modules, 'mod', Args(foo=foo, bar=bar)): + fool[0] = True + barl[0] = True + self.assertRenderEqual(p, '{56} s3{6-}>>{--}') + self.assertEqual(launched, set(('foo', 'bar'))) + + fool[0] = False + barl[0] = True + self.assertRenderEqual(p, '{56} s1{56}>{56}s2{56}>{56}s3{6-}>>{--}') + self.assertEqual(launched, set(('foo', 'bar'))) + + fool[0] = False + barl[0] = False + self.assertRenderEqual(p, '{56} s1{6-}>>{--}') + self.assertEqual(launched, set(('foo', 'bar'))) + + fool[0] = True + barl[0] = False + self.assertRenderEqual(p, '{--}') + self.assertEqual(launched, set(('foo', 'bar'))) + + @add_args + def test_exinclude_modes_override_functions(self, p, config): + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('s1', 'g1', exclude_function='mod.foo', exclude_modes=['m2']), + highlighted_string('s2', 'g1', exclude_function='mod.foo', include_modes=['m2']), + highlighted_string('s3', 'g1', include_function='mod.foo', exclude_modes=['m2']), + highlighted_string('s4', 'g1', include_function='mod.foo', include_modes=['m2']), + ] + } + fool = [None] + + def foo(*args, **kwargs): + return fool[0] + + with replace_item(sys.modules, 'mod', Args(foo=foo)): + fool[0] = True + self.assertRenderEqual(p, '{56} s4{6-}>>{--}', mode='m2') + self.assertRenderEqual(p, '{56} s3{56}>{56}s4{6-}>>{--}', mode='m1') + + fool[0] = False + self.assertRenderEqual(p, '{56} s2{56}>{56}s4{6-}>>{--}', mode='m2') + self.assertRenderEqual(p, '{56} s1{6-}>>{--}', mode='m1') + + +class TestOuterPadding(TestRender): + @add_args + def test_outer_padding_left(self, p, config): + config['themes/' + UT]['outer_padding'] = 5 + self.assertRenderEqual(p, '{121} s{24}>>{344}g{4-}>>{--}', side='left') + + @add_args + def test_outer_padding_right(self, p, config): + config['themes/' + UT]['outer_padding'] = 5 + self.assertRenderEqual(p, '{4-}<<{344}f {--}', side='right') + + @add_args + def test_outer_padding_ten(self, p, config): + config['themes/' + UT]['outer_padding'] = 10 + self.assertRenderEqual(p, '{121} s {24}>>{344}g{34}>{34}|{344} f {--}', width=30) + + @add_args + def test_outer_padding_zero(self, p, config): + config['themes/' + UT]['outer_padding'] = 0 + self.assertRenderEqual(p, '{121}s {24}>>{344}g{34}>{34}|{344} f{--}', width=30) + + +class TestSegmentAttributes(TestRender): + @add_args + def test_no_attributes(self, p, config): + def m1(divider=',', **kwargs): + return divider.join(kwargs.keys()) + divider + config['themes/test/default']['segments'] = { + 'left': [ + { + 'function': 'bar.m1' + } + ] + } + with replace_item(sys.modules, 'bar', Args(m1=m1)): + self.assertRenderEqual(p, '{56} pl,{6-}>>{--}') + + @add_args + def test_segment_datas(self, p, config): + def m1(divider=',', **kwargs): + return divider.join(kwargs.keys()) + divider + m1.powerline_segment_datas = { + UT: { + 'args': { + 'divider': ';' + } + }, + 'ascii': { + 'args': { + 'divider': '--' + } + } + } + config['themes/test/default']['segments'] = { + 'left': [ + { + 'function': 'bar.m1' + } + ] + } + with replace_item(sys.modules, 'bar', Args(m1=m1)): + self.assertRenderEqual(p, '{56} pl;{6-}>>{--}') + + @add_args + def test_expand(self, p, config): + def m1(divider=',', **kwargs): + return divider.join(kwargs.keys()) + divider + + def expand(pl, amount, segment, **kwargs): + return ('-' * amount) + segment['contents'] + + m1.expand = expand + config['themes/test/default']['segments'] = { + 'left': [ + { + 'function': 'bar.m1', + 'width': 'auto' + } + ] + } + with replace_item(sys.modules, 'bar', Args(m1=m1)): + self.assertRenderEqual(p, '{56} ----pl,{6-}>>{--}', width=10) + + @add_args + def test_truncate(self, p, config): + def m1(divider=',', **kwargs): + return divider.join(kwargs.keys()) + divider + + def truncate(pl, amount, segment, **kwargs): + return segment['contents'][:-amount] + + m1.truncate = truncate + config['themes/test/default']['segments'] = { + 'left': [ + { + 'function': 'bar.m1' + } + ] + } + with replace_item(sys.modules, 'bar', Args(m1=m1)): + self.assertRenderEqual(p, '{56} p{6-}>>{--}', width=4) + + +class TestSegmentData(TestRender): + @add_args + def test_segment_data(self, p, config): + def m1(**kwargs): + return 'S' + + def m2(**kwargs): + return 'S' + sys.modules['bar'] = Args(m1=m1, m2=m2) + config['themes/' + UT]['segment_data'] = { + 'm1': { + 'before': '1' + }, + 'bar.m2': { + 'before': '2' + }, + 'n': { + 'before': '3' + }, + 'm2': { + 'before': '4' + }, + } + config['themes/test/default']['segments'] = { + 'left': [ + { + 'function': 'bar.m1' + }, + { + 'function': 'bar.m1', + 'name': 'n' + }, + { + 'function': 'bar.m2', + 'name': 'n' + }, + { + 'function': 'bar.m2' + } + ] + } + self.assertRenderEqual(p, '{56} 1S{56}>{56}3S{610}>>{910}3S{910}>{910}2S{10-}>>{--}') + + +class TestShellEscapes(TestCase): + @with_new_config + def test_escapes(self, config): + from powerline.shell import ShellPowerline + import powerline as powerline_module + with swap_attributes(config, powerline_module): + with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: + self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1b[0;38;5;5;48;5;6m\xa0s\x1b[0;38;5;6;49;22m>>\x1b[0m') + + @with_new_config + def test_tmux_escapes(self, config): + from powerline.shell import ShellPowerline + import powerline as powerline_module + config['config']['common']['additional_escapes'] = 'tmux' + with swap_attributes(config, powerline_module): + with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: + self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bPtmux;\x1b\x1b[0;38;5;5;48;5;6m\x1b\\\xa0s\x1bPtmux;\x1b\x1b[0;38;5;6;49;22m\x1b\\>>\x1bPtmux;\x1b\x1b[0m\x1b\\') + + @with_new_config + def test_screen_escapes(self, config): + from powerline.shell import ShellPowerline + import powerline as powerline_module + config['config']['common']['additional_escapes'] = 'screen' + with swap_attributes(config, powerline_module): + with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: + self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bP\x1b\x1b[0;38;5;5;48;5;6m\x1b\\\xa0s\x1bP\x1b\x1b[0;38;5;6;49;22m\x1b\\>>\x1bP\x1b\x1b[0m\x1b\\') + + @with_new_config + def test_fbterm_escapes(self, config): + from powerline.shell import ShellPowerline + import powerline as powerline_module + config['config']['common']['term_escape_style'] = 'fbterm' + with swap_attributes(config, powerline_module): + with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: + self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1b[0m\x1b[1;5}\x1b[2;6}\xa0s\x1b[0m\x1b[1;6}\x1b[49m\x1b[22m>>\x1b[0m') + + @with_new_config + def test_fbterm_tmux_escapes(self, config): + from powerline.shell import ShellPowerline + import powerline as powerline_module + config['config']['common']['term_escape_style'] = 'fbterm' + config['config']['common']['additional_escapes'] = 'tmux' + with swap_attributes(config, powerline_module): + with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: + self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bPtmux;\x1b\x1b[0m\x1b\x1b[1;5}\x1b\x1b[2;6}\x1b\\\xa0s\x1bPtmux;\x1b\x1b[0m\x1b\x1b[1;6}\x1b\x1b[49m\x1b\x1b[22m\x1b\\>>\x1bPtmux;\x1b\x1b[0m\x1b\\') + + @with_new_config + def test_fbterm_screen_escapes(self, config): + from powerline.shell import ShellPowerline + import powerline as powerline_module + config['config']['common']['term_escape_style'] = 'fbterm' + config['config']['common']['additional_escapes'] = 'screen' + with swap_attributes(config, powerline_module): + with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: + self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bP\x1b\x1b[0m\x1b\x1b[1;5}\x1b\x1b[2;6}\x1b\\\xa0s\x1bP\x1b\x1b[0m\x1b\x1b[1;6}\x1b\x1b[49m\x1b\x1b[22m\x1b\\>>\x1bP\x1b\x1b[0m\x1b\\') + + @with_new_config + def test_term_truecolor_escapes(self, config): + from powerline.shell import ShellPowerline + import powerline as powerline_module + config['config']['common']['term_truecolor'] = True + with swap_attributes(config, powerline_module): + with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: + self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1b[0;38;2;192;0;192;48;2;0;128;128m\xa0s\x1b[0;38;2;0;128;128;49;22m>>\x1b[0m') + + @with_new_config + def test_term_truecolor_fbterm_escapes(self, config): + from powerline.shell import ShellPowerline + import powerline as powerline_module + config['config']['common']['term_escape_style'] = 'fbterm' + config['config']['common']['term_truecolor'] = True + with swap_attributes(config, powerline_module): + with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: + self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1b[0m\x1b[1;5}\x1b[2;6}\xa0s\x1b[0m\x1b[1;6}\x1b[49m\x1b[22m>>\x1b[0m') + + @with_new_config + def test_term_truecolor_tmux_escapes(self, config): + from powerline.shell import ShellPowerline + import powerline as powerline_module + config['config']['common']['term_truecolor'] = True + config['config']['common']['additional_escapes'] = 'tmux' + with swap_attributes(config, powerline_module): + with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: + self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bPtmux;\x1b\x1b[0;38;2;192;0;192;48;2;0;128;128m\x1b\\\xa0s\x1bPtmux;\x1b\x1b[0;38;2;0;128;128;49;22m\x1b\\>>\x1bPtmux;\x1b\x1b[0m\x1b\\') + + @with_new_config + def test_term_truecolor_screen_escapes(self, config): + from powerline.shell import ShellPowerline + import powerline as powerline_module + config['config']['common']['term_truecolor'] = True + config['config']['common']['additional_escapes'] = 'screen' + with swap_attributes(config, powerline_module): + with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: + self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bP\x1b\x1b[0;38;2;192;0;192;48;2;0;128;128m\x1b\\\xa0s\x1bP\x1b\x1b[0;38;2;0;128;128;49;22m\x1b\\>>\x1bP\x1b\x1b[0m\x1b\\') + + +class TestVim(TestCase): + def test_environ_update(self): + # Regression test: test that segment obtains environment from vim, not + # from os.environ. + with vim_module._with('globals', powerline_config_paths=['/']): + from powerline.vim import VimPowerline + import powerline as powerline_module + with swap_attributes(config, powerline_module): + with vim_module._with('environ', TEST='abc'): + with get_powerline_raw(config, VimPowerline) as powerline: + window = vim_module.current.window + window_id = 1 + winnr = window.number + self.assertEqual(powerline.render(window, window_id, winnr), b'%#Pl_3_8404992_4_192_underline#\xc2\xa0abc%#Pl_4_192_NONE_None_NONE#>>') + vim_module._environ['TEST'] = 'def' + self.assertEqual(powerline.render(window, window_id, winnr), b'%#Pl_3_8404992_4_192_underline#\xc2\xa0def%#Pl_4_192_NONE_None_NONE#>>') + + def test_local_themes(self): + # Regression test: VimPowerline.add_local_theme did not work properly. + from powerline.vim import VimPowerline + import powerline as powerline_module + with swap_attributes(config, powerline_module): + with get_powerline_raw(config, VimPowerline, replace_gcp=True) as powerline: + powerline.add_local_theme('tests.modules.matchers.always_true', { + 'segment_data': { + 'foo': { + 'contents': '“bar”' + } + }, + 'segments': { + 'left': [ + { + 'type': 'string', + 'name': 'foo', + 'highlight_groups': ['g1'] + } + ] + } + }) + window = vim_module.current.window + window_id = 1 + winnr = window.number + self.assertEqual(powerline.render(window, window_id, winnr), b'%#Pl_5_12583104_6_32896_NONE#\xc2\xa0\xe2\x80\x9cbar\xe2\x80\x9d%#Pl_6_32896_NONE_None_NONE#>>') + + @classmethod + def setUpClass(cls): + sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'vim_sys_path'))) + + @classmethod + def tearDownClass(cls): + sys.path.pop(0) + + +class TestLemonbar(TestRender): + def test_lemonbar(self): + import powerline as powerline_module + with swap_attributes(config, powerline_module): + with get_powerline_raw(config, powerline_module.Powerline, replace_gcp=True, ext='wm', renderer_module='lemonbar') as powerline: + self.assertRenderEqual( + powerline, + '%{l}%{F#ffc00000}%{B#ff008000}%{+u} A%{F-B--u}%{F#ff008000}%{B#ffc00000}>>%{F-B--u}%{F#ff008000}%{B#ffc00000}B%{F-B--u}%{F#ffc00000}>>%{F-B--u}%{r}%{F#ffc00000}<<%{F-B--u}%{F#ff804000}%{B#ffc00000}%{+u}C%{F-B--u}%{F#ff0000c0}%{B#ffc00000}<<%{F-B--u}%{F#ff008000}%{B#ff0000c0}D %{F-B--u}' + ) + + @with_new_config + def test_lemonbar_escape(self, config): + import powerline as powerline_module + config['themes/wm/default']['segments']['left'] = ( + highlighted_string('%{asd}', 'hl1'), + highlighted_string('10% %', 'hl2'), + ) + with swap_attributes(config, powerline_module): + with get_powerline_raw(config, powerline_module.Powerline, replace_gcp=True, ext='wm', renderer_module='lemonbar') as powerline: + self.assertRenderEqual( + powerline, + '%{l}%{F#ffc00000}%{B#ff008000}%{+u} %%{}{asd}%{F-B--u}%{F#ff008000}%{B#ffc00000}>>%{F-B--u}%{F#ff008000}%{B#ffc00000}10%%{} %%{}%{F-B--u}%{F#ffc00000}>>%{F-B--u}%{r}%{F#ffc00000}<<%{F-B--u}%{F#ff804000}%{B#ffc00000}%{+u}C%{F-B--u}%{F#ff0000c0}%{B#ffc00000}<<%{F-B--u}%{F#ff008000}%{B#ff0000c0}D %{F-B--u}' + ) + + +if __name__ == '__main__': + from tests.modules import main + main() diff --git a/tests/test_python/test_lib.py b/tests/test_python/test_lib.py new file mode 100644 index 0000000..4c85436 --- /dev/null +++ b/tests/test_python/test_lib.py @@ -0,0 +1,733 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import threading +import os +import sys +import re +import shutil +import unicodedata + +from time import sleep +from subprocess import call, PIPE + +from powerline.lib import add_divider_highlight_group +from powerline.lib.dict import mergedicts, REMOVE_THIS_KEY +from powerline.lib.humanize_bytes import humanize_bytes +from powerline.lib.vcs import guess, get_fallback_create_watcher +from powerline.lib.threaded import ThreadedSegment, KwThreadedSegment +from powerline.lib.monotonic import monotonic +from powerline.lib.vcs.git import git_directory +from powerline.lib.shell import run_cmd + +import powerline.lib.unicode as plu + +from tests.modules.lib import Pl, replace_attr +from tests.modules import TestCase, SkipTest + + +try: + __import__('bzrlib') +except ImportError: + use_bzr = False +else: + use_bzr = True + +try: + __import__('hglib') +except ImportError: + use_mercurial = False +else: + use_mercurial = True + + +GIT_REPO = 'git_repo' +HG_REPO = 'hg_repo' +BZR_REPO = 'bzr_repo' + + +def thread_number(): + return len(threading.enumerate()) + + +class TestShell(TestCase): + def test_run_cmd(self): + pl = Pl() + self.assertEqual(run_cmd(pl, ['xxx_nonexistent_command_xxx']), None) + self.assertEqual(len(pl.exceptions), 1) + pl = Pl() + self.assertEqual(run_cmd(pl, ['echo', ' test ']), 'test') + self.assertFalse(pl) + self.assertEqual(run_cmd(pl, ['echo', ' test '], strip=True), 'test') + self.assertFalse(pl) + self.assertEqual(run_cmd(pl, ['echo', ' test '], strip=False), ' test \n') + self.assertFalse(pl) + self.assertEqual(run_cmd(pl, ['cat'], stdin='test'), 'test') + self.assertFalse(pl) + self.assertEqual(run_cmd(pl, ['sh', '-c', 'cat >&2'], stdin='test'), '') + self.assertFalse(pl) + + +class TestThreaded(TestCase): + def test_threaded_segment(self): + log = [] + pl = Pl() + updates = [(None,)] + lock = threading.Lock() + event = threading.Event() + block_event = threading.Event() + + class TestSegment(ThreadedSegment): + interval = 10 + + def set_state(self, **kwargs): + event.clear() + log.append(('set_state', kwargs)) + return super(TestSegment, self).set_state(**kwargs) + + def update(self, update_value): + block_event.wait() + event.set() + # Make sleep first to prevent some race conditions + log.append(('update', update_value)) + with lock: + ret = updates[0] + if isinstance(ret, Exception): + raise ret + else: + return ret[0] + + def render(self, update, **kwargs): + log.append(('render', update, kwargs)) + if isinstance(update, Exception): + raise update + else: + return update + + # Non-threaded tests + segment = TestSegment() + block_event.set() + updates[0] = (None,) + self.assertEqual(segment(pl=pl), None) + self.assertEqual(thread_number(), 1) + self.assertEqual(log, [ + ('set_state', {}), + ('update', None), + ('render', None, {'pl': pl, 'update_first': True}), + ]) + log[:] = () + + segment = TestSegment() + block_event.set() + updates[0] = ('abc',) + self.assertEqual(segment(pl=pl), 'abc') + self.assertEqual(thread_number(), 1) + self.assertEqual(log, [ + ('set_state', {}), + ('update', None), + ('render', 'abc', {'pl': pl, 'update_first': True}), + ]) + log[:] = () + + segment = TestSegment() + block_event.set() + updates[0] = ('abc',) + self.assertEqual(segment(pl=pl, update_first=False), 'abc') + self.assertEqual(thread_number(), 1) + self.assertEqual(log, [ + ('set_state', {}), + ('update', None), + ('render', 'abc', {'pl': pl, 'update_first': False}), + ]) + log[:] = () + + segment = TestSegment() + block_event.set() + updates[0] = ValueError('abc') + self.assertEqual(segment(pl=pl), None) + self.assertEqual(thread_number(), 1) + self.assertEqual(len(pl.exceptions), 1) + self.assertEqual(log, [ + ('set_state', {}), + ('update', None), + ]) + log[:] = () + pl.exceptions[:] = () + + segment = TestSegment() + block_event.set() + updates[0] = (TypeError('def'),) + self.assertRaises(TypeError, segment, pl=pl) + self.assertEqual(thread_number(), 1) + self.assertEqual(log, [ + ('set_state', {}), + ('update', None), + ('render', updates[0][0], {'pl': pl, 'update_first': True}), + ]) + log[:] = () + + # Threaded tests + segment = TestSegment() + block_event.clear() + kwargs = {'pl': pl, 'update_first': False, 'other': 1} + with lock: + updates[0] = ('abc',) + segment.startup(**kwargs) + ret = segment(**kwargs) + self.assertEqual(thread_number(), 2) + block_event.set() + event.wait() + segment.shutdown_event.set() + segment.thread.join() + self.assertEqual(ret, None) + self.assertEqual(log, [ + ('set_state', {'update_first': False, 'other': 1}), + ('render', None, {'pl': pl, 'update_first': False, 'other': 1}), + ('update', None), + ]) + log[:] = () + + segment = TestSegment() + block_event.set() + kwargs = {'pl': pl, 'update_first': True, 'other': 1} + with lock: + updates[0] = ('def',) + segment.startup(**kwargs) + ret = segment(**kwargs) + self.assertEqual(thread_number(), 2) + segment.shutdown_event.set() + segment.thread.join() + self.assertEqual(ret, 'def') + self.assertEqual(log, [ + ('set_state', {'update_first': True, 'other': 1}), + ('update', None), + ('render', 'def', {'pl': pl, 'update_first': True, 'other': 1}), + ]) + log[:] = () + + segment = TestSegment() + block_event.set() + kwargs = {'pl': pl, 'update_first': True, 'interval': 0.2} + with lock: + updates[0] = ('abc',) + segment.startup(**kwargs) + start = monotonic() + ret1 = segment(**kwargs) + with lock: + updates[0] = ('def',) + self.assertEqual(thread_number(), 2) + sleep(0.5) + ret2 = segment(**kwargs) + segment.shutdown_event.set() + segment.thread.join() + end = monotonic() + duration = end - start + self.assertEqual(ret1, 'abc') + self.assertEqual(ret2, 'def') + self.assertEqual(log[:5], [ + ('set_state', {'update_first': True, 'interval': 0.2}), + ('update', None), + ('render', 'abc', {'pl': pl, 'update_first': True, 'interval': 0.2}), + ('update', 'abc'), + ('update', 'def'), + ]) + num_runs = len([e for e in log if e[0] == 'update']) + self.assertAlmostEqual(duration / 0.2, num_runs, delta=1) + log[:] = () + + segment = TestSegment() + block_event.set() + kwargs = {'pl': pl, 'update_first': True, 'interval': 0.2} + with lock: + updates[0] = ('ghi',) + segment.startup(**kwargs) + start = monotonic() + ret1 = segment(**kwargs) + with lock: + updates[0] = TypeError('jkl') + self.assertEqual(thread_number(), 2) + sleep(0.5) + ret2 = segment(**kwargs) + segment.shutdown_event.set() + segment.thread.join() + end = monotonic() + duration = end - start + self.assertEqual(ret1, 'ghi') + self.assertEqual(ret2, None) + self.assertEqual(log[:5], [ + ('set_state', {'update_first': True, 'interval': 0.2}), + ('update', None), + ('render', 'ghi', {'pl': pl, 'update_first': True, 'interval': 0.2}), + ('update', 'ghi'), + ('update', 'ghi'), + ]) + num_runs = len([e for e in log if e[0] == 'update']) + self.assertAlmostEqual(duration / 0.2, num_runs, delta=1) + self.assertEqual(num_runs - 1, len(pl.exceptions)) + log[:] = () + + def test_kw_threaded_segment(self): + log = [] + pl = Pl() + event = threading.Event() + + class TestSegment(KwThreadedSegment): + interval = 10 + + @staticmethod + def key(_key=(None,), **kwargs): + log.append(('key', _key, kwargs)) + return _key + + def compute_state(self, key): + event.set() + sleep(0.1) + log.append(('compute_state', key)) + ret = key + if isinstance(ret, Exception): + raise ret + else: + return ret[0] + + def render_one(self, state, **kwargs): + log.append(('render_one', state, kwargs)) + if isinstance(state, Exception): + raise state + else: + return state + + # Non-threaded tests + segment = TestSegment() + event.clear() + self.assertEqual(segment(pl=pl), None) + self.assertEqual(thread_number(), 1) + self.assertEqual(log, [ + ('key', (None,), {'pl': pl}), + ('compute_state', (None,)), + ('render_one', None, {'pl': pl}), + ]) + log[:] = () + + segment = TestSegment() + kwargs = {'pl': pl, '_key': ('abc',), 'update_first': False} + event.clear() + self.assertEqual(segment(**kwargs), 'abc') + kwargs.update(_key=('def',)) + self.assertEqual(segment(**kwargs), 'def') + self.assertEqual(thread_number(), 1) + self.assertEqual(log, [ + ('key', ('abc',), {'pl': pl}), + ('compute_state', ('abc',)), + ('render_one', 'abc', {'pl': pl, '_key': ('abc',)}), + ('key', ('def',), {'pl': pl}), + ('compute_state', ('def',)), + ('render_one', 'def', {'pl': pl, '_key': ('def',)}), + ]) + log[:] = () + + segment = TestSegment() + kwargs = {'pl': pl, '_key': ValueError('xyz'), 'update_first': False} + event.clear() + self.assertEqual(segment(**kwargs), None) + self.assertEqual(thread_number(), 1) + self.assertEqual(log, [ + ('key', kwargs['_key'], {'pl': pl}), + ('compute_state', kwargs['_key']), + ]) + log[:] = () + + segment = TestSegment() + kwargs = {'pl': pl, '_key': (ValueError('abc'),), 'update_first': False} + event.clear() + self.assertRaises(ValueError, segment, **kwargs) + self.assertEqual(thread_number(), 1) + self.assertEqual(log, [ + ('key', kwargs['_key'], {'pl': pl}), + ('compute_state', kwargs['_key']), + ('render_one', kwargs['_key'][0], {'pl': pl, '_key': kwargs['_key']}), + ]) + log[:] = () + + # Threaded tests + segment = TestSegment() + kwargs = {'pl': pl, 'update_first': False, '_key': ('_abc',)} + event.clear() + segment.startup(**kwargs) + ret = segment(**kwargs) + self.assertEqual(thread_number(), 2) + segment.shutdown_event.set() + segment.thread.join() + self.assertEqual(ret, None) + self.assertEqual(log[:2], [ + ('key', kwargs['_key'], {'pl': pl}), + ('render_one', None, {'pl': pl, '_key': kwargs['_key']}), + ]) + self.assertLessEqual(len(log), 3) + if len(log) > 2: + self.assertEqual(log[2], ('compute_state', kwargs['_key'])) + log[:] = () + + segment = TestSegment() + kwargs = {'pl': pl, 'update_first': True, '_key': ('_abc',)} + event.clear() + segment.startup(**kwargs) + ret1 = segment(**kwargs) + kwargs.update(_key=('_def',)) + ret2 = segment(**kwargs) + self.assertEqual(thread_number(), 2) + segment.shutdown_event.set() + segment.thread.join() + self.assertEqual(ret1, '_abc') + self.assertEqual(ret2, '_def') + self.assertEqual(log, [ + ('key', ('_abc',), {'pl': pl}), + ('compute_state', ('_abc',)), + ('render_one', '_abc', {'pl': pl, '_key': ('_abc',)}), + ('key', ('_def',), {'pl': pl}), + ('compute_state', ('_def',)), + ('render_one', '_def', {'pl': pl, '_key': ('_def',)}), + ]) + log[:] = () + + +class TestLib(TestCase): + def test_mergedicts(self): + d = {} + mergedicts(d, {'abc': {'def': 'ghi'}}) + self.assertEqual(d, {'abc': {'def': 'ghi'}}) + mergedicts(d, {'abc': {'def': {'ghi': 'jkl'}}}) + self.assertEqual(d, {'abc': {'def': {'ghi': 'jkl'}}}) + mergedicts(d, {}) + self.assertEqual(d, {'abc': {'def': {'ghi': 'jkl'}}}) + mergedicts(d, {'abc': {'mno': 'pqr'}}) + self.assertEqual(d, {'abc': {'def': {'ghi': 'jkl'}, 'mno': 'pqr'}}) + mergedicts(d, {'abc': {'def': REMOVE_THIS_KEY}}) + self.assertEqual(d, {'abc': {'mno': 'pqr'}}) + + def test_add_divider_highlight_group(self): + def decorated_function_name(**kwargs): + return str(kwargs) + func = add_divider_highlight_group('hl_group')(decorated_function_name) + self.assertEqual(func.__name__, 'decorated_function_name') + self.assertEqual(func(kw={}), [{'contents': repr({str('kw'): {}}), 'divider_highlight_group': 'hl_group'}]) + + def test_humanize_bytes(self): + self.assertEqual(humanize_bytes(0), '0 B') + self.assertEqual(humanize_bytes(1), '1 B') + self.assertEqual(humanize_bytes(1, suffix='bit'), '1 bit') + self.assertEqual(humanize_bytes(1000, si_prefix=True), '1 kB') + self.assertEqual(humanize_bytes(1024, si_prefix=True), '1 kB') + self.assertEqual(humanize_bytes(1000000000, si_prefix=True), '1.00 GB') + self.assertEqual(humanize_bytes(1000000000, si_prefix=False), '953.7 MiB') + + +width_data = { + 'N': 1, # Neutral + 'Na': 1, # Narrow + 'A': 1, # Ambiguous + 'H': 1, # Half-width + 'W': 2, # Wide + 'F': 2, # Fullwidth +} + + +class TestUnicode(TestCase): + def assertStringsIdentical(self, s1, s2): + self.assertTrue(type(s1) is type(s2), msg='string types differ') + self.assertEqual(s1, s2) + + def test_unicode(self): + self.assertTrue(type('abc') is plu.unicode) + + def test_unichr(self): + self.assertStringsIdentical('\U0010FFFF', plu.unichr(0x10FFFF)) + self.assertStringsIdentical('\uFFFF', plu.unichr(0xFFFF)) + self.assertStringsIdentical('\x20', plu.unichr(0x20)) + + def test_u(self): + self.assertStringsIdentical('Test', plu.u('Test')) + self.assertStringsIdentical('Test', plu.u(b'Test')) + self.assertStringsIdentical('«»', plu.u(b'\xC2\xAB\xC2\xBB')) + self.assertRaises(UnicodeDecodeError, plu.u, b'\xFF') + + def test_tointiter(self): + self.assertEqual([1, 2, 3], list(plu.tointiter(b'\x01\x02\x03'))) + + def test_decode_error(self): + self.assertStringsIdentical('<FF>', b'\xFF'.decode('utf-8', 'powerline_decode_error')) + self.assertStringsIdentical('abc', b'abc'.decode('utf-8', 'powerline_decode_error')) + + def test_register_strwidth_error(self): + ename = plu.register_strwidth_error(lambda s: 3) + self.assertStringsIdentical(b'???', 'A'.encode('latin1', ename)) + self.assertStringsIdentical(b'abc', 'abc'.encode('latin1', ename)) + + def test_out_u(self): + self.assertStringsIdentical('abc', plu.out_u('abc')) + self.assertStringsIdentical('abc', plu.out_u(b'abc')) + self.assertRaises(TypeError, plu.out_u, None) + + def test_safe_unicode(self): + self.assertStringsIdentical('abc', plu.safe_unicode('abc')) + self.assertStringsIdentical('abc', plu.safe_unicode(b'abc')) + self.assertStringsIdentical('«»', plu.safe_unicode(b'\xc2\xab\xc2\xbb')) + with replace_attr(plu, 'get_preferred_output_encoding', lambda: 'latin1'): + self.assertStringsIdentical('ÿ', plu.safe_unicode(b'\xFF')) + self.assertStringsIdentical('None', plu.safe_unicode(None)) + + class FailingStr(object): + def __str__(self): + raise NotImplementedError('Fail!') + + self.assertStringsIdentical('Fail!', plu.safe_unicode(FailingStr())) + + def test_FailedUnicode(self): + self.assertTrue(isinstance(plu.FailedUnicode('abc'), plu.unicode)) + self.assertEqual('abc', plu.FailedUnicode('abc')) + + def test_string(self): + self.assertStringsIdentical(str('abc'), plu.string('abc')) + self.assertStringsIdentical(str('abc'), plu.string(b'abc')) + + def test_surrogate_pair_to_character(self): + self.assertEqual(0x1F48E, plu.surrogate_pair_to_character(0xD83D, 0xDC8E)) + + def test_strwidth_ucs_4(self): + self.assertEqual(4, plu.strwidth_ucs_4(width_data, 'abcd')) + self.assertEqual(4, plu.strwidth_ucs_4(width_data, 'AB')) + if sys.maxunicode < 0x10FFFF: + raise SkipTest('Can only test strwidth_ucs_4 in UCS-4 Pythons') + + self.assertEqual(1, plu.strwidth_ucs_4(width_data, '\U0001F063')) + + def test_strwidth_ucs_2(self): + self.assertEqual(4, plu.strwidth_ucs_2(width_data, 'abcd')) + self.assertEqual(4, plu.strwidth_ucs_2(width_data, 'AB')) + if not sys.maxunicode < 0x10FFFF: + raise SkipTest('Can only test strwidth_ucs_2 in UCS-2 Pythons') + self.assertEqual(1, plu.strwidth_ucs_2(width_data, '\ud83c\udc30')) + + +class TestVCS(TestCase): + def do_branch_rename_test(self, repo, q): + st = monotonic() + while monotonic() - st < 1: + # Give inotify time to deliver events + ans = repo.branch() + if hasattr(q, '__call__'): + if q(ans): + break + else: + if ans == q: + break + sleep(0.01) + if hasattr(q, '__call__'): + self.assertTrue(q(ans)) + else: + self.assertEqual(ans, q) + + def test_git(self): + create_watcher = get_fallback_create_watcher() + repo = guess(path=GIT_REPO, create_watcher=create_watcher) + self.assertNotEqual(repo, None) + self.assertEqual(repo.branch(), 'master') + self.assertEqual(repo.status(), None) + self.assertEqual(repo.status('file'), None) + with open(os.path.join(GIT_REPO, 'file'), 'w') as f: + f.write('abc') + f.flush() + self.assertEqual(repo.status(), ' U') + self.assertEqual(repo.status('file'), '??') + call(['git', 'add', '.'], cwd=GIT_REPO) + self.assertEqual(repo.status(), ' I ') + self.assertEqual(repo.status('file'), 'A ') + f.write('def') + f.flush() + self.assertEqual(repo.status(), 'DI ') + self.assertEqual(repo.status('file'), 'AM') + os.remove(os.path.join(GIT_REPO, 'file')) + # Test changing branch + self.assertEqual(repo.branch(), 'master') + try: + call(['git', 'branch', 'branch1'], cwd=GIT_REPO) + call(['git', 'checkout', '-q', 'branch1'], cwd=GIT_REPO) + self.do_branch_rename_test(repo, 'branch1') + call(['git', 'branch', 'branch2'], cwd=GIT_REPO) + call(['git', 'checkout', '-q', 'branch2'], cwd=GIT_REPO) + self.do_branch_rename_test(repo, 'branch2') + call(['git', 'checkout', '-q', '--detach', 'branch1'], cwd=GIT_REPO) + self.do_branch_rename_test(repo, lambda b: re.match(r'^[a-f0-9]+$', b)) + finally: + call(['git', 'checkout', '-q', 'master'], cwd=GIT_REPO) + # Test stashing + self.assertEqual(repo.stash(), 0) + + def stash_save(): + with open(os.path.join(GIT_REPO, 'file'), 'w') as f: + f.write('abc') + return call(['git', 'stash', '-u'], cwd=GIT_REPO, stdout=PIPE) + + def stash_drop(): + return call(['git', 'stash', 'drop'], cwd=GIT_REPO, stdout=PIPE) + + def stash_list(): + return call(['git', 'stash', 'list'], cwd=GIT_REPO, stdout=PIPE) + + try: + stash_save() + self.assertEqual(repo.stash(), 1) + stash_save() + self.assertEqual(repo.stash(), 2) + stash_drop() + self.assertEqual(repo.stash(), 1) + stash_drop() + self.assertEqual(repo.stash(), 0) + finally: + while stash_list(): + stash_drop() + + def test_git_sym(self): + create_watcher = get_fallback_create_watcher() + dotgit = os.path.join(GIT_REPO, '.git') + spacegit = os.path.join(GIT_REPO, ' .git ') + os.rename(dotgit, spacegit) + try: + with open(dotgit, 'w') as F: + F.write('gitdir: .git \n') + gitdir = git_directory(GIT_REPO) + self.assertTrue(os.path.isdir(gitdir)) + self.assertEqual(gitdir, os.path.abspath(spacegit)) + repo = guess(path=GIT_REPO, create_watcher=create_watcher) + self.assertEqual(repo.branch(), 'master') + finally: + os.remove(dotgit) + os.rename(spacegit, dotgit) + + def test_mercurial(self): + if not use_mercurial: + raise SkipTest('Mercurial is not available') + create_watcher = get_fallback_create_watcher() + repo = guess(path=HG_REPO, create_watcher=create_watcher) + self.assertNotEqual(repo, None) + self.assertEqual(repo.branch(), 'default') + self.assertEqual(repo.status(), None) + with open(os.path.join(HG_REPO, 'file'), 'w') as f: + f.write('abc') + f.flush() + self.assertEqual(repo.status(), ' U') + self.assertEqual(repo.status('file'), 'U') + call(['hg', 'add', '.'], cwd=HG_REPO, stdout=PIPE) + self.assertEqual(repo.status(), 'D ') + self.assertEqual(repo.status('file'), 'A') + os.remove(os.path.join(HG_REPO, 'file')) + + def test_bzr(self): + if not use_bzr: + raise SkipTest('Bazaar is not available') + create_watcher = get_fallback_create_watcher() + repo = guess(path=BZR_REPO, create_watcher=create_watcher) + self.assertNotEqual(repo, None, 'No bzr repo found. Do you have bzr installed?') + self.assertEqual(repo.branch(), 'test_powerline') + self.assertEqual(repo.status(), None) + with open(os.path.join(BZR_REPO, 'file'), 'w') as f: + f.write('abc') + self.assertEqual(repo.status(), ' U') + self.assertEqual(repo.status('file'), '? ') + call(['bzr', 'add', '-q', '.'], cwd=BZR_REPO, stdout=PIPE) + self.assertEqual(repo.status(), 'D ') + self.assertEqual(repo.status('file'), '+N') + call(['bzr', 'commit', '-q', '-m', 'initial commit'], cwd=BZR_REPO) + self.assertEqual(repo.status(), None) + with open(os.path.join(BZR_REPO, 'file'), 'w') as f: + f.write('def') + self.assertEqual(repo.status(), 'D ') + self.assertEqual(repo.status('file'), ' M') + self.assertEqual(repo.status('notexist'), None) + with open(os.path.join(BZR_REPO, 'ignored'), 'w') as f: + f.write('abc') + self.assertEqual(repo.status('ignored'), '? ') + # Test changing the .bzrignore file should update status + with open(os.path.join(BZR_REPO, '.bzrignore'), 'w') as f: + f.write('ignored') + self.assertEqual(repo.status('ignored'), None) + # Test changing the dirstate file should invalidate the cache for + # all files in the repo + with open(os.path.join(BZR_REPO, 'file2'), 'w') as f: + f.write('abc') + call(['bzr', 'add', 'file2'], cwd=BZR_REPO, stdout=PIPE) + call(['bzr', 'commit', '-q', '-m', 'file2 added'], cwd=BZR_REPO) + with open(os.path.join(BZR_REPO, 'file'), 'a') as f: + f.write('hello') + with open(os.path.join(BZR_REPO, 'file2'), 'a') as f: + f.write('hello') + self.assertEqual(repo.status('file'), ' M') + self.assertEqual(repo.status('file2'), ' M') + call(['bzr', 'commit', '-q', '-m', 'multi'], cwd=BZR_REPO) + self.assertEqual(repo.status('file'), None) + self.assertEqual(repo.status('file2'), None) + + # Test changing branch + call(['bzr', 'nick', 'branch1'], cwd=BZR_REPO, stdout=PIPE, stderr=PIPE) + self.do_branch_rename_test(repo, 'branch1') + + # Test branch name/status changes when swapping repos + for x in ('b1', 'b2'): + d = os.path.join(BZR_REPO, x) + os.mkdir(d) + call(['bzr', 'init', '-q'], cwd=d) + call(['bzr', 'nick', '-q', x], cwd=d) + repo = guess(path=d, create_watcher=create_watcher) + self.assertEqual(repo.branch(), x) + self.assertFalse(repo.status()) + if x == 'b1': + open(os.path.join(d, 'dirty'), 'w').close() + self.assertTrue(repo.status()) + os.rename(os.path.join(BZR_REPO, 'b1'), os.path.join(BZR_REPO, 'b')) + os.rename(os.path.join(BZR_REPO, 'b2'), os.path.join(BZR_REPO, 'b1')) + os.rename(os.path.join(BZR_REPO, 'b'), os.path.join(BZR_REPO, 'b2')) + for x, y in (('b1', 'b2'), ('b2', 'b1')): + d = os.path.join(BZR_REPO, x) + repo = guess(path=d, create_watcher=create_watcher) + self.do_branch_rename_test(repo, y) + if x == 'b1': + self.assertFalse(repo.status()) + else: + self.assertTrue(repo.status()) + + @classmethod + def setUpClass(cls): + cls.powerline_old_cwd = os.getcwd() + os.chdir(os.path.dirname(os.path.dirname(__file__))) + call(['git', 'init', '--quiet', GIT_REPO]) + assert os.path.isdir(GIT_REPO) + call(['git', 'config', '--local', 'user.name', 'Foo'], cwd=GIT_REPO) + call(['git', 'config', '--local', 'user.email', 'bar@example.org'], cwd=GIT_REPO) + call(['git', 'commit', '--allow-empty', '--message', 'Initial commit', '--quiet'], cwd=GIT_REPO) + if use_mercurial: + cls.powerline_old_HGRCPATH = os.environ.get('HGRCPATH') + os.environ['HGRCPATH'] = '' + call(['hg', 'init', HG_REPO]) + with open(os.path.join(HG_REPO, '.hg', 'hgrc'), 'w') as hgrc: + hgrc.write('[ui]\n') + hgrc.write('username = Foo <bar@example.org>\n') + if use_bzr: + call(['bzr', 'init', '--quiet', BZR_REPO]) + call(['bzr', 'config', 'email=Foo <bar@example.org>'], cwd=BZR_REPO) + call(['bzr', 'config', 'nickname=test_powerline'], cwd=BZR_REPO) + call(['bzr', 'config', 'create_signatures=0'], cwd=BZR_REPO) + + @classmethod + def tearDownClass(cls): + for repo_dir in [GIT_REPO] + ([HG_REPO] if use_mercurial else []) + ([BZR_REPO] if use_bzr else []): + shutil.rmtree(repo_dir) + if use_mercurial: + if cls.powerline_old_HGRCPATH is None: + os.environ.pop('HGRCPATH') + else: + os.environ['HGRCPATH'] = cls.powerline_old_HGRCPATH + os.chdir(cls.powerline_old_cwd) + + +if __name__ == '__main__': + from tests.modules import main + main() diff --git a/tests/test_python/test_lib_config.py b/tests/test_python/test_lib_config.py new file mode 100644 index 0000000..053462a --- /dev/null +++ b/tests/test_python/test_lib_config.py @@ -0,0 +1,52 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os + +from powerline.lib.config import ConfigLoader + +from tests.modules import TestCase +from tests.modules.lib.fsconfig import FSTree + + +FILE_ROOT = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'cfglib') + + +class LoadedList(list): + def pop_all(self): + try: + return self[:] + finally: + self[:] = () + + +loaded = LoadedList() + + +def on_load(key): + loaded.append(key) + + +def check_file(path): + if os.path.exists(path): + return path + else: + raise IOError + + +class TestLoaderCondition(TestCase): + def test_update_missing(self): + loader = ConfigLoader(run_once=True) + fpath = os.path.join(FILE_ROOT, 'file.json') + self.assertRaises(IOError, loader.load, fpath) + loader.register_missing(check_file, on_load, fpath) + loader.update() # This line must not raise IOError + with FSTree({'file': {'test': 1}}, root=FILE_ROOT): + loader.update() + self.assertEqual(loader.load(fpath), {'test': 1}) + self.assertEqual(loaded.pop_all(), [fpath]) + + +if __name__ == '__main__': + from tests.modules import main + main() diff --git a/tests/test_python/test_listers.py b/tests/test_python/test_listers.py new file mode 100644 index 0000000..a33f033 --- /dev/null +++ b/tests/test_python/test_listers.py @@ -0,0 +1,227 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import powerline.listers.i3wm as i3wm + +from tests.modules.lib import Args, replace_attr, Pl +from tests.modules import TestCase + + +class TestI3WM(TestCase): + @staticmethod + def get_workspaces(): + return iter([ + {'name': '1: w1', 'output': 'LVDS1', 'focused': False, 'urgent': False, 'visible': False}, + {'name': '2: w2', 'output': 'LVDS1', 'focused': False, 'urgent': False, 'visible': True}, + {'name': '3: w3', 'output': 'HDMI1', 'focused': False, 'urgent': True, 'visible': True}, + {'name': '4: w4', 'output': 'DVI01', 'focused': True, 'urgent': True, 'visible': True}, + ]) + + @staticmethod + def get_outputs(pl): + return iter([ + {'name': 'LVDS1'}, + {'name': 'HDMI1'}, + {'name': 'DVI01'}, + ]) + + def test_output_lister(self): + pl = Pl() + with replace_attr(i3wm, 'get_connected_xrandr_outputs', self.get_outputs): + self.assertEqual( + list(i3wm.output_lister(pl=pl, segment_info={'a': 1})), + [ + ({'a': 1, 'output': 'LVDS1'}, {'draw_inner_divider': None}), + ({'a': 1, 'output': 'HDMI1'}, {'draw_inner_divider': None}), + ({'a': 1, 'output': 'DVI01'}, {'draw_inner_divider': None}), + ] + ) + + def test_workspace_lister(self): + pl = Pl() + with replace_attr(i3wm, 'get_i3_connection', lambda: Args(get_workspaces=self.get_workspaces)): + self.assertEqual( + list(i3wm.workspace_lister(pl=pl, segment_info={'a': 1})), + [ + ({ + 'a': 1, + 'output': 'LVDS1', + 'workspace': { + 'name': '1: w1', + 'focused': False, + 'urgent': False, + 'visible': False + } + }, {'draw_inner_divider': None}), + ({ + 'a': 1, + 'output': 'LVDS1', + 'workspace': { + 'name': '2: w2', + 'focused': False, + 'urgent': False, + 'visible': True + } + }, {'draw_inner_divider': None}), + ({ + 'a': 1, + 'output': 'HDMI1', + 'workspace': { + 'name': '3: w3', + 'focused': False, + 'urgent': True, + 'visible': True + } + }, {'draw_inner_divider': None}), + ({ + 'a': 1, + 'output': 'DVI01', + 'workspace': { + 'name': '4: w4', + 'focused': True, + 'urgent': True, + 'visible': True + } + }, {'draw_inner_divider': None}), + ] + ) + + self.assertEqual( + list(i3wm.workspace_lister(pl=pl, segment_info={'a': 1}, output='LVDS1')), + [ + ({ + 'a': 1, + 'output': 'LVDS1', + 'workspace': { + 'name': '1: w1', + 'focused': False, + 'urgent': False, + 'visible': False + } + }, {'draw_inner_divider': None}), + ({ + 'a': 1, + 'output': 'LVDS1', + 'workspace': { + 'name': '2: w2', + 'focused': False, + 'urgent': False, + 'visible': True + } + }, {'draw_inner_divider': None}), + ] + ) + + self.assertEqual( + list(i3wm.workspace_lister( + pl=pl, + segment_info={'a': 1, 'output': 'LVDS1'} + )), + [ + ({ + 'a': 1, + 'output': 'LVDS1', + 'workspace': { + 'name': '1: w1', + 'focused': False, + 'urgent': False, + 'visible': False + } + }, {'draw_inner_divider': None}), + ({ + 'a': 1, + 'output': 'LVDS1', + 'workspace': { + 'name': '2: w2', + 'focused': False, + 'urgent': False, + 'visible': True + } + }, {'draw_inner_divider': None}), + ] + ) + + self.assertEqual( + list(i3wm.workspace_lister( + pl=pl, + segment_info={'a': 1, 'output': 'LVDS1'}, + output=False + )), + [ + ({ + 'a': 1, + 'output': 'LVDS1', + 'workspace': { + 'name': '1: w1', + 'focused': False, + 'urgent': False, + 'visible': False + } + }, {'draw_inner_divider': None}), + ({ + 'a': 1, + 'output': 'LVDS1', + 'workspace': { + 'name': '2: w2', + 'focused': False, + 'urgent': False, + 'visible': True + } + }, {'draw_inner_divider': None}), + ({ + 'a': 1, + 'output': 'HDMI1', + 'workspace': { + 'name': '3: w3', + 'focused': False, + 'urgent': True, + 'visible': True + } + }, {'draw_inner_divider': None}), + ({ + 'a': 1, + 'output': 'DVI01', + 'workspace': { + 'name': '4: w4', + 'focused': True, + 'urgent': True, + 'visible': True + } + }, {'draw_inner_divider': None}), + ] + ) + + self.assertEqual( + list(i3wm.workspace_lister( + pl=pl, + segment_info={'a': 1}, + only_show=['focused', 'urgent'] + )), + [ + ({ + 'a': 1, + 'output': 'HDMI1', + 'workspace': { + 'name': '3: w3', + 'focused': False, + 'urgent': True, + 'visible': True + } + }, {'draw_inner_divider': None}), + ({ + 'a': 1, + 'output': 'DVI01', + 'workspace': { + 'name': '4: w4', + 'focused': True, + 'urgent': True, + 'visible': True + } + }, {'draw_inner_divider': None}), + ] + ) + + +if __name__ == '__main__': + from tests.modules import main + main() diff --git a/tests/test_python/test_logging.py b/tests/test_python/test_logging.py new file mode 100644 index 0000000..d7cfe4a --- /dev/null +++ b/tests/test_python/test_logging.py @@ -0,0 +1,467 @@ +# vim:fileencoding=utf-8:noet + +'''Tests for various logging features''' + +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys +import re +import codecs +import os + +from io import StringIO +from shutil import rmtree + +from powerline import finish_common_config, create_logger + +from tests.modules import TestCase +from tests.modules.lib import replace_attr + + +TIMESTAMP_RE = r'\d{4}-\d\d-\d\d \d\d:\d\d:\d\d,\d{3}' + + +class TestRE(TestCase): + def assertMatches(self, text, regexp): + self.assertTrue( + re.match(regexp, text), + '{0!r} did not match {1!r}'.format(text, regexp), + ) + + +def close_handlers(logger): + for handler in logger.handlers: + handler.close() + + +class TestHandlers(TestRE): + def test_stderr_handler_is_default(self): + out = StringIO() + err = StringIO() + + with replace_attr(sys, 'stdout', out, 'stderr', err): + common_config = finish_common_config('utf-8', {}) + logger, pl, get_module_attr = create_logger(common_config) + pl.error('Foo') + close_handlers(logger) + self.assertMatches(err.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') + self.assertEqual(out.getvalue(), '') + + def test_stream_override(self): + out = StringIO() + err = StringIO() + stream = StringIO() + + with replace_attr(sys, 'stdout', out, 'stderr', err): + common_config = finish_common_config('utf-8', {}) + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.error('Foo') + close_handlers(logger) + self.assertMatches(stream.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') + self.assertEqual(err.getvalue(), '') + self.assertEqual(out.getvalue(), '') + + def test_explicit_none(self): + out = StringIO() + err = StringIO() + stream = StringIO() + + with replace_attr(sys, 'stdout', out, 'stderr', err): + common_config = finish_common_config('utf-8', {'log_file': [None]}) + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.error('Foo') + close_handlers(logger) + self.assertMatches(stream.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') + self.assertEqual(err.getvalue(), '') + self.assertEqual(out.getvalue(), '') + + def test_explicit_stream_handler(self): + out = StringIO() + err = StringIO() + stream = StringIO() + + with replace_attr(sys, 'stdout', out, 'stderr', err): + common_config = finish_common_config('utf-8', {'log_file': [['logging.StreamHandler', [[]]]]}) + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.error('Foo') + close_handlers(logger) + self.assertEqual(stream.getvalue(), '') + self.assertMatches(err.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') + self.assertEqual(out.getvalue(), '') + + def test_explicit_stream_handler_implicit_stream(self): + out = StringIO() + err = StringIO() + stream = StringIO() + + with replace_attr(sys, 'stdout', out, 'stderr', err): + common_config = finish_common_config('utf-8', {'log_file': [['logging.StreamHandler', []]]}) + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.error('Foo') + close_handlers(logger) + self.assertMatches(stream.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') + self.assertEqual(err.getvalue(), '') + self.assertEqual(out.getvalue(), '') + + def test_file_handler(self): + out = StringIO() + err = StringIO() + stream = StringIO() + file_name = 'test_logging-test_file_handler' + + with replace_attr(sys, 'stdout', out, 'stderr', err): + common_config = finish_common_config('utf-8', {'log_file': file_name}) + try: + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.error('Foo') + close_handlers(logger) + with codecs.open(file_name, encoding='utf-8') as fp: + self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') + finally: + os.unlink(file_name) + self.assertEqual(stream.getvalue(), '') + self.assertEqual(err.getvalue(), '') + self.assertEqual(out.getvalue(), '') + + def test_file_handler_create_dir(self): + out = StringIO() + err = StringIO() + stream = StringIO() + file_name = 'test_logging-test_file_handler_create_dir/file' + + self.assertFalse(os.path.isdir(os.path.dirname(file_name))) + + with replace_attr(sys, 'stdout', out, 'stderr', err): + common_config = finish_common_config('utf-8', {'log_file': file_name}) + try: + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.error('Foo') + close_handlers(logger) + self.assertTrue(os.path.isdir(os.path.dirname(file_name))) + with codecs.open(file_name, encoding='utf-8') as fp: + self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') + finally: + rmtree(os.path.dirname(file_name)) + self.assertEqual(stream.getvalue(), '') + self.assertEqual(err.getvalue(), '') + self.assertEqual(out.getvalue(), '') + + def test_multiple_files(self): + out = StringIO() + err = StringIO() + stream = StringIO() + file_name_1 = 'test_logging-test_multiple_files-1' + file_name_2 = file_name_1[:-1] + '2' + + with replace_attr(sys, 'stdout', out, 'stderr', err): + common_config = finish_common_config('utf-8', {'log_file': [file_name_1, file_name_2]}) + try: + try: + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.error('Foo') + close_handlers(logger) + for file_name in (file_name_1, file_name_2): + with codecs.open(file_name, encoding='utf-8') as fp: + self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') + finally: + os.unlink(file_name_1) + finally: + os.unlink(file_name_2) + self.assertEqual(stream.getvalue(), '') + self.assertEqual(err.getvalue(), '') + self.assertEqual(out.getvalue(), '') + + def test_multiple_files_and_stream(self): + out = StringIO() + err = StringIO() + stream = StringIO() + file_name_1 = 'test_logging-test_multiple_files_and_stream-1' + file_name_2 = file_name_1[:-1] + '2' + + with replace_attr(sys, 'stdout', out, 'stderr', err): + common_config = finish_common_config('utf-8', {'log_file': [file_name_1, file_name_2, None]}) + try: + try: + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.error('Foo') + close_handlers(logger) + for file_name in (file_name_1, file_name_2): + with codecs.open(file_name, encoding='utf-8') as fp: + self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') + finally: + os.unlink(file_name_1) + finally: + os.unlink(file_name_2) + self.assertMatches(stream.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') + self.assertEqual(err.getvalue(), '') + self.assertEqual(out.getvalue(), '') + + def test_handler_args(self): + out = StringIO() + err = StringIO() + stream = StringIO() + file_name = 'test_logging-test_handler_args' + + with replace_attr(sys, 'stdout', out, 'stderr', err): + common_config = finish_common_config('utf-8', {'log_file': [ + ['RotatingFileHandler', [[file_name]]] + ]}) + try: + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.error('Foo') + close_handlers(logger) + with codecs.open(file_name, encoding='utf-8') as fp: + self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') + finally: + os.unlink(file_name) + self.assertEqual(stream.getvalue(), '') + self.assertEqual(err.getvalue(), '') + self.assertEqual(out.getvalue(), '') + + def test_handler_args_kwargs(self): + out = StringIO() + err = StringIO() + stream = StringIO() + file_name = 'test_logging-test_handler_args_kwargs' + + with replace_attr(sys, 'stdout', out, 'stderr', err): + common_config = finish_common_config('utf-8', {'log_file': [ + ['RotatingFileHandler', [[file_name], {'maxBytes': 1, 'backupCount': 1}]] + ]}) + try: + try: + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.error('Foo') + pl.error('Bar') + close_handlers(logger) + with codecs.open(file_name, encoding='utf-8') as fp: + self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Bar\n$') + with codecs.open(file_name + '.1', encoding='utf-8') as fp: + self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') + finally: + os.unlink(file_name + '.1') + finally: + os.unlink(file_name) + self.assertEqual(stream.getvalue(), '') + self.assertEqual(err.getvalue(), '') + self.assertEqual(out.getvalue(), '') + + def test_logger_level(self): + out = StringIO() + err = StringIO() + stream = StringIO() + stream1 = StringIO() + stream2 = StringIO() + + with replace_attr(sys, 'stdout', out, 'stderr', err): + common_config = finish_common_config('utf-8', {'log_file': [ + ['logging.StreamHandler', [[stream1]], 'WARNING'], + ['logging.StreamHandler', [[stream2]], 'ERROR'], + ]}) + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.warn('Foo') + pl.error('Bar') + close_handlers(logger) + self.assertMatches(stream1.getvalue(), ( + '^' + TIMESTAMP_RE + ':WARNING:__unknown__:Foo\n' + + TIMESTAMP_RE + ':ERROR:__unknown__:Bar\n$' + )) + self.assertMatches(stream2.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Bar\n$') + self.assertEqual(stream.getvalue(), '') + self.assertEqual(err.getvalue(), '') + self.assertEqual(out.getvalue(), '') + + def test_logger_level_not_overriding_default(self): + out = StringIO() + err = StringIO() + stream = StringIO() + stream1 = StringIO() + + with replace_attr(sys, 'stdout', out, 'stderr', err): + common_config = finish_common_config('utf-8', {'log_file': [ + ['logging.StreamHandler', [[stream1]], 'DEBUG'], + ]}) + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.debug('Foo') + pl.error('Bar') + close_handlers(logger) + self.assertMatches(stream1.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Bar\n$') + self.assertEqual(stream.getvalue(), '') + self.assertEqual(err.getvalue(), '') + self.assertEqual(out.getvalue(), '') + + def test_top_log_level(self): + out = StringIO() + err = StringIO() + stream = StringIO() + stream1 = StringIO() + + with replace_attr(sys, 'stdout', out, 'stderr', err): + common_config = finish_common_config('utf-8', {'log_file': [ + ['logging.StreamHandler', [[stream1]], 'DEBUG'], + ], 'log_level': 'DEBUG'}) + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.debug('Foo') + pl.error('Bar') + close_handlers(logger) + self.assertMatches(stream1.getvalue(), ( + '^' + TIMESTAMP_RE + ':DEBUG:__unknown__:Foo\n' + + TIMESTAMP_RE + ':ERROR:__unknown__:Bar\n$' + )) + self.assertEqual(stream.getvalue(), '') + self.assertEqual(err.getvalue(), '') + self.assertEqual(out.getvalue(), '') + + def test_logger_format(self): + out = StringIO() + err = StringIO() + stream = StringIO() + stream1 = StringIO() + + with replace_attr(sys, 'stdout', out, 'stderr', err): + common_config = finish_common_config('utf-8', {'log_file': [ + ['logging.StreamHandler', [[stream1]], 'WARNING', 'FOO'], + ]}) + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.warn('Foo') + pl.error('Bar') + close_handlers(logger) + self.assertEqual(stream1.getvalue(), 'FOO\nFOO\n') + self.assertEqual(stream.getvalue(), '') + self.assertEqual(err.getvalue(), '') + self.assertEqual(out.getvalue(), '') + + def test_top_log_format(self): + out = StringIO() + err = StringIO() + stream = StringIO() + stream1 = StringIO() + stream2 = StringIO() + + with replace_attr(sys, 'stdout', out, 'stderr', err): + common_config = finish_common_config('utf-8', {'log_file': [ + ['logging.StreamHandler', [[stream1]], 'WARNING', 'FOO'], + ['logging.StreamHandler', [[stream2]], 'WARNING'], + ], 'log_format': 'BAR'}) + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.warn('Foo') + pl.error('Bar') + close_handlers(logger) + self.assertEqual(stream2.getvalue(), 'BAR\nBAR\n') + self.assertEqual(stream1.getvalue(), 'FOO\nFOO\n') + self.assertEqual(stream.getvalue(), '') + self.assertEqual(err.getvalue(), '') + self.assertEqual(out.getvalue(), '') + + +class TestPowerlineLogger(TestRE): + def test_args_formatting(self): + stream = StringIO() + + common_config = finish_common_config('utf-8', {}) + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.warn('foo {0}', 'Test') + pl.warn('bar {0!r}', 'Test') + close_handlers(logger) + self.assertMatches(stream.getvalue(), ( + '^' + TIMESTAMP_RE + ':WARNING:__unknown__:foo Test\n' + + TIMESTAMP_RE + ':WARNING:__unknown__:bar u?\'Test\'\n$' + )) + + def test_prefix_formatting(self): + stream = StringIO() + + common_config = finish_common_config('utf-8', {}) + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.prefix = '1' + pl.warn('foo') + pl.prefix = '2' + pl.warn('bar') + close_handlers(logger) + self.assertMatches(stream.getvalue(), ( + '^' + TIMESTAMP_RE + ':WARNING:__unknown__:1:foo\n' + + TIMESTAMP_RE + ':WARNING:__unknown__:2:bar\n$' + )) + + def test_kwargs_formatting(self): + stream = StringIO() + + common_config = finish_common_config('utf-8', {}) + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.warn('foo {arg}', arg='Test') + pl.warn('bar {arg!r}', arg='Test') + close_handlers(logger) + self.assertMatches(stream.getvalue(), ( + '^' + TIMESTAMP_RE + ':WARNING:__unknown__:foo Test\n' + + TIMESTAMP_RE + ':WARNING:__unknown__:bar u?\'Test\'\n$' + )) + + def test_args_kwargs_formatting(self): + stream = StringIO() + + common_config = finish_common_config('utf-8', {}) + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.warn('foo {0!r} {arg}', 'Test0', arg='Test') + pl.warn('bar {0} {arg!r}', 'Test0', arg='Test') + close_handlers(logger) + self.assertMatches(stream.getvalue(), ( + '^' + TIMESTAMP_RE + ':WARNING:__unknown__:foo u?\'Test0\' Test\n' + + TIMESTAMP_RE + ':WARNING:__unknown__:bar Test0 u?\'Test\'\n$' + )) + + def test_exception_formatting(self): + stream = StringIO() + + common_config = finish_common_config('utf-8', {}) + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + try: + raise ValueError('foo') + except ValueError: + pl.exception('Message') + close_handlers(logger) + self.assertMatches(stream.getvalue(), ( + '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Message\n' + + 'Traceback \\(most recent call last\\):\n' + + '(?: File ".*?", line \\d+, in \\w+\n [^\n]*\n)+' + + 'ValueError: foo\n$' + )) + + def test_levels(self): + stream = StringIO() + + common_config = finish_common_config('utf-8', {'log_level': 'DEBUG'}) + logger, pl, get_module_attr = create_logger(common_config, stream=stream) + pl.debug('1') + pl.info('2') + pl.warn('3') + pl.error('4') + pl.critical('5') + close_handlers(logger) + self.assertMatches(stream.getvalue(), ( + '^' + TIMESTAMP_RE + ':DEBUG:__unknown__:1\n' + + TIMESTAMP_RE + ':INFO:__unknown__:2\n' + + TIMESTAMP_RE + ':WARNING:__unknown__:3\n' + + TIMESTAMP_RE + ':ERROR:__unknown__:4\n' + + TIMESTAMP_RE + ':CRITICAL:__unknown__:5\n$' + )) + + +old_cwd = None + + +def setUpModule(): + global old_cwd + global __file__ + old_cwd = os.getcwd() + __file__ = os.path.abspath(__file__) + os.chdir(os.path.dirname(os.path.dirname(__file__))) + + +def tearDownModule(): + global old_cwd + os.chdir(old_cwd) + + +if __name__ == '__main__': + from tests.modules import main + main() diff --git a/tests/test_python/test_provided_config_files.py b/tests/test_python/test_provided_config_files.py new file mode 100644 index 0000000..fd8b16e --- /dev/null +++ b/tests/test_python/test_provided_config_files.py @@ -0,0 +1,201 @@ +# vim:fileencoding=utf-8:noet + +'''Dynamic configuration files tests.''' + +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys +import os +import json +import logging + +import tests.modules.vim as vim_module + +from tests.modules.lib import Args, urllib_read, replace_attr +from tests.modules import TestCase + +from powerline import NotInterceptedError +from powerline.segments.common import wthr + + +VBLOCK = chr(ord('V') - 0x40) +SBLOCK = chr(ord('S') - 0x40) + + +class FailingLogger(logging.Logger): + def exception(self, *args, **kwargs): + super(FailingLogger, self).exception(*args, **kwargs) + raise NotInterceptedError('Unexpected exception occurred') + + +def get_logger(stream=None): + log_format = '%(asctime)s:%(levelname)s:%(message)s' + formatter = logging.Formatter(log_format) + + level = logging.WARNING + handler = logging.StreamHandler(stream) + handler.setLevel(level) + handler.setFormatter(formatter) + + logger = FailingLogger('powerline') + logger.setLevel(level) + logger.addHandler(handler) + return logger + + +class TestVimConfig(TestCase): + def test_vim(self): + from powerline.vim import VimPowerline + cfg_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'powerline', 'config_files') + buffers = ( + (('bufoptions',), {'buftype': 'help'}), + (('bufname', '[Command Line]'), {}), + (('bufoptions',), {'buftype': 'quickfix'}), + (('bufname', 'NERD_tree_1'), {}), + (('bufname', '__Gundo__'), {}), + (('bufname', '__Gundo_Preview__'), {}), + # No Command-T tests here: requires +ruby or emulation + # No tabline here: tablines are tested separately + ) + with open(os.path.join(cfg_path, 'config.json'), 'r') as f: + local_themes_raw = json.load(f)['ext']['vim']['local_themes'] + # Don’t run tests on external/plugin segments + local_themes = dict((k, v) for (k, v) in local_themes_raw.items()) + # See end of the buffers definition above for `- 2` + self.assertEqual(len(buffers), len(local_themes) - 2) + outputs = {} + i = 0 + + with vim_module._with('split'): + with VimPowerline(logger=get_logger()) as powerline: + def check_output(mode, args, kwargs): + if mode == 'nc': + window = vim_module.windows[0] + window_id = 2 + else: + vim_module._start_mode(mode) + window = vim_module.current.window + window_id = 1 + winnr = window.number + out = powerline.render(window, window_id, winnr) + if out in outputs: + self.fail('Duplicate in set #{0} ({1}) for mode {2!r} (previously defined in set #{3} ({4!r}) for mode {5!r})'.format(i, (args, kwargs), mode, *outputs[out])) + outputs[out] = (i, (args, kwargs), mode) + + with vim_module._with('bufname', '/tmp/foo.txt'): + out = powerline.render(vim_module.current.window, 1, vim_module.current.window.number, is_tabline=True) + outputs[out] = (-1, (None, None), 'tab') + with vim_module._with('globals', powerline_config_paths=[cfg_path]): + exclude = set(('no', 'v', 'V', VBLOCK, 's', 'S', SBLOCK, 'R', 'Rv', 'c', 'cv', 'ce', 'r', 'rm', 'r?', '!')) + try: + for mode in ['n', 'nc', 'no', 'v', 'V', VBLOCK, 's', 'S', SBLOCK, 'i', 'R', 'Rv', 'c', 'cv', 'ce', 'r', 'rm', 'r?', '!']: + check_output(mode, None, None) + for args, kwargs in buffers: + i += 1 + if mode in exclude: + continue + with vim_module._with(*args, **kwargs): + check_output(mode, args, kwargs) + finally: + vim_module._start_mode('n') + + @classmethod + def setUpClass(cls): + sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'vim_sys_path'))) + + @classmethod + def tearDownClass(cls): + sys.path.pop(0) + + +class TestConfig(TestCase): + def test_tmux(self): + from powerline.segments import common + from imp import reload + reload(common) + from powerline.shell import ShellPowerline + with replace_attr(common, 'urllib_read', urllib_read): + with ShellPowerline(Args(ext=['tmux']), logger=get_logger(), run_once=False) as powerline: + powerline.render() + with ShellPowerline(Args(ext=['tmux']), logger=get_logger(), run_once=False) as powerline: + powerline.render() + + def test_zsh(self): + from powerline.shell import ShellPowerline + args = Args(last_pipe_status=[1, 0], jobnum=0, ext=['shell'], renderer_module='.zsh') + segment_info = {'args': args} + with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline: + powerline.render(segment_info=segment_info) + with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline: + powerline.render(segment_info=segment_info) + segment_info['local_theme'] = 'select' + with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline: + powerline.render(segment_info=segment_info) + segment_info['local_theme'] = 'continuation' + segment_info['parser_state'] = 'if cmdsubst' + with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline: + powerline.render(segment_info=segment_info) + + def test_bash(self): + from powerline.shell import ShellPowerline + args = Args(last_exit_code=1, last_pipe_status=[], jobnum=0, ext=['shell'], renderer_module='.bash', config_override={'ext': {'shell': {'theme': 'default_leftonly'}}}) + with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline: + powerline.render(segment_info={'args': args}) + with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline: + powerline.render(segment_info={'args': args}) + + def test_ipython(self): + from powerline.ipython import IPythonPowerline + + class IpyPowerline(IPythonPowerline): + config_paths = None + config_overrides = None + theme_overrides = {} + + segment_info = Args(prompt_count=1) + + with IpyPowerline(logger=get_logger(), renderer_module='.pre_5') as powerline: + for prompt_type in ['in', 'in2']: + powerline.render(is_prompt=True, matcher_info=prompt_type, segment_info=segment_info) + powerline.render(is_prompt=True, matcher_info=prompt_type, segment_info=segment_info) + with IpyPowerline(logger=get_logger(), renderer_module='.pre_5') as powerline: + for prompt_type in ['out', 'rewrite']: + powerline.render(is_prompt=False, matcher_info=prompt_type, segment_info=segment_info) + powerline.render(is_prompt=False, matcher_info=prompt_type, segment_info=segment_info) + + def test_wm(self): + from powerline.segments import common + from imp import reload + reload(common) + from powerline import Powerline + with replace_attr(wthr, 'urllib_read', urllib_read): + Powerline(logger=get_logger(), ext='wm', renderer_module='pango_markup', run_once=True).render() + reload(common) + + +old_cwd = None +saved_get_config_paths = None + + +def setUpModule(): + global old_cwd + global saved_get_config_paths + import powerline + saved_get_config_paths = powerline.get_config_paths + path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'powerline', 'config_files') + powerline.get_config_paths = lambda: [path] + old_cwd = os.getcwd() + + +def tearDownModule(): + global old_cwd + global saved_get_config_paths + import powerline + powerline.get_config_paths = saved_get_config_paths + os.chdir(old_cwd) + old_cwd = None + + +if __name__ == '__main__': + from tests.modules import main + main() diff --git a/tests/test_python/test_segments.py b/tests/test_python/test_segments.py new file mode 100644 index 0000000..8d6cbae --- /dev/null +++ b/tests/test_python/test_segments.py @@ -0,0 +1,1732 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys +import os + +from functools import partial +from collections import namedtuple +from time import sleep +from platform import python_implementation + +from powerline.segments import shell, tmux, pdb, i3wm +from powerline.lib.vcs import get_fallback_create_watcher +from powerline.lib.unicode import out_u + +import tests.modules.vim as vim_module + +from tests.modules.lib import (Args, urllib_read, replace_attr, new_module, + replace_module_module, replace_env, Pl) +from tests.modules import TestCase, SkipTest + + +def get_dummy_guess(**kwargs): + if 'directory' in kwargs: + def guess(path, create_watcher): + return Args(branch=lambda: out_u(os.path.basename(path)), **kwargs) + else: + def guess(path, create_watcher): + return Args(branch=lambda: out_u(os.path.basename(path)), directory=path, **kwargs) + return guess + + +class TestShell(TestCase): + def test_last_status(self): + pl = Pl() + segment_info = {'args': Args(last_exit_code=10)} + self.assertEqual(shell.last_status(pl=pl, segment_info=segment_info), [ + {'contents': '10', 'highlight_groups': ['exit_fail']} + ]) + segment_info['args'].last_exit_code = 137 + self.assertEqual(shell.last_status(pl=pl, segment_info=segment_info), [ + {'contents': 'SIGKILL', 'highlight_groups': ['exit_fail']} + ]) + self.assertEqual(shell.last_status(pl=pl, segment_info=segment_info, signal_names=False), [ + {'contents': '137', 'highlight_groups': ['exit_fail']} + ]) + segment_info['args'].last_exit_code = 0 + self.assertEqual(shell.last_status(pl=pl, segment_info=segment_info), None) + segment_info['args'].last_exit_code = None + self.assertEqual(shell.last_status(pl=pl, segment_info=segment_info), None) + segment_info['args'].last_exit_code = 'sigsegv' + self.assertEqual(shell.last_status(pl=pl, segment_info=segment_info), [ + {'contents': 'sigsegv', 'highlight_groups': ['exit_fail']} + ]) + segment_info['args'].last_exit_code = 'sigsegv+core' + self.assertEqual(shell.last_status(pl=pl, segment_info=segment_info), [ + {'contents': 'sigsegv+core', 'highlight_groups': ['exit_fail']} + ]) + + def test_last_pipe_status(self): + pl = Pl() + segment_info = {'args': Args(last_pipe_status=[], last_exit_code=0)} + self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None) + segment_info['args'].last_pipe_status = [0, 0, 0] + self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None) + segment_info['args'].last_pipe_status = [0, 0] + self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None) + segment_info['args'].last_pipe_status = [0] + self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None) + segment_info['args'].last_pipe_status = [0, 2, 0] + self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ + {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, + {'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, + {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, + ]) + segment_info['args'].last_pipe_status = [2, 0, 0] + self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ + {'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, + {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, + {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, + ]) + segment_info['args'].last_pipe_status = [137, 0, 0] + self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ + {'contents': 'SIGKILL', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, + {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, + {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, + ]) + + self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info, signal_names=False), [ + {'contents': '137', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, + {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, + {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, + ]) + + segment_info['args'].last_pipe_status = [0, 0, 2] + self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ + {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, + {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, + {'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, + ]) + segment_info['args'].last_pipe_status = [2] + self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ + {'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, + ]) + segment_info['args'].last_pipe_status = [0, 'sigsegv', 'sigsegv+core'] + self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ + {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, + {'contents': 'sigsegv', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, + {'contents': 'sigsegv+core', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True} + ]) + segment_info['args'].last_pipe_status = [0, 'sigsegv', 0] + self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ + {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, + {'contents': 'sigsegv', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, + {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True} + ]) + segment_info['args'].last_pipe_status = [0, 'sigsegv+core', 0] + self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ + {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, + {'contents': 'sigsegv+core', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, + {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True} + ]) + segment_info['args'].last_pipe_status = [] + segment_info['args'].last_exit_code = 5 + self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ + {'contents': '5', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, + ]) + + def test_jobnum(self): + pl = Pl() + segment_info = {'args': Args(jobnum=0)} + self.assertEqual(shell.jobnum(pl=pl, segment_info=segment_info), None) + self.assertEqual(shell.jobnum(pl=pl, segment_info=segment_info, show_zero=False), None) + self.assertEqual(shell.jobnum(pl=pl, segment_info=segment_info, show_zero=True), '0') + segment_info = {'args': Args(jobnum=1)} + self.assertEqual(shell.jobnum(pl=pl, segment_info=segment_info), '1') + self.assertEqual(shell.jobnum(pl=pl, segment_info=segment_info, show_zero=False), '1') + self.assertEqual(shell.jobnum(pl=pl, segment_info=segment_info, show_zero=True), '1') + + def test_continuation(self): + pl = Pl() + self.assertEqual(shell.continuation(pl=pl, segment_info={}), [{ + 'contents': '', + 'width': 'auto', + 'highlight_groups': ['continuation:current', 'continuation'], + }]) + segment_info = {'parser_state': 'if cmdsubst'} + self.assertEqual(shell.continuation(pl=pl, segment_info=segment_info), [ + { + 'contents': 'if', + 'draw_inner_divider': True, + 'highlight_groups': ['continuation:current', 'continuation'], + 'width': 'auto', + 'align': 'l', + }, + ]) + self.assertEqual(shell.continuation(pl=pl, segment_info=segment_info, right_align=True), [ + { + 'contents': 'if', + 'draw_inner_divider': True, + 'highlight_groups': ['continuation:current', 'continuation'], + 'width': 'auto', + 'align': 'r', + }, + ]) + self.assertEqual(shell.continuation(pl=pl, segment_info=segment_info, omit_cmdsubst=False), [ + { + 'contents': 'if', + 'draw_inner_divider': True, + 'highlight_groups': ['continuation'], + }, + { + 'contents': 'cmdsubst', + 'draw_inner_divider': True, + 'highlight_groups': ['continuation:current', 'continuation'], + 'width': 'auto', + 'align': 'l', + }, + ]) + self.assertEqual(shell.continuation(pl=pl, segment_info=segment_info, omit_cmdsubst=False, right_align=True), [ + { + 'contents': 'if', + 'draw_inner_divider': True, + 'highlight_groups': ['continuation'], + 'width': 'auto', + 'align': 'r', + }, + { + 'contents': 'cmdsubst', + 'draw_inner_divider': True, + 'highlight_groups': ['continuation:current', 'continuation'], + }, + ]) + self.assertEqual(shell.continuation(pl=pl, segment_info=segment_info, omit_cmdsubst=True, right_align=True), [ + { + 'contents': 'if', + 'draw_inner_divider': True, + 'highlight_groups': ['continuation:current', 'continuation'], + 'width': 'auto', + 'align': 'r', + }, + ]) + self.assertEqual(shell.continuation(pl=pl, segment_info=segment_info, omit_cmdsubst=True, right_align=True, renames={'if': 'IF'}), [ + { + 'contents': 'IF', + 'draw_inner_divider': True, + 'highlight_groups': ['continuation:current', 'continuation'], + 'width': 'auto', + 'align': 'r', + }, + ]) + self.assertEqual(shell.continuation(pl=pl, segment_info=segment_info, omit_cmdsubst=True, right_align=True, renames={'if': None}), [ + { + 'contents': '', + 'highlight_groups': ['continuation:current', 'continuation'], + 'width': 'auto', + 'align': 'r', + }, + ]) + segment_info = {'parser_state': 'then then then cmdsubst'} + self.assertEqual(shell.continuation(pl=pl, segment_info=segment_info), [ + { + 'contents': 'then', + 'draw_inner_divider': True, + 'highlight_groups': ['continuation'], + }, + { + 'contents': 'then', + 'draw_inner_divider': True, + 'highlight_groups': ['continuation'], + }, + { + 'contents': 'then', + 'draw_inner_divider': True, + 'highlight_groups': ['continuation:current', 'continuation'], + 'width': 'auto', + 'align': 'l', + }, + ]) + + def test_cwd(self): + new_os = new_module('os', path=os.path, sep='/') + pl = Pl() + cwd = [None] + + def getcwd(): + wd = cwd[0] + if isinstance(wd, Exception): + raise wd + else: + return wd + + segment_info = {'getcwd': getcwd, 'home': None} + with replace_attr(shell, 'os', new_os): + cwd[0] = '/abc/def/ghi/foo/bar' + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info), [ + {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'abc', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'def', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'ghi', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, + ]) + segment_info['home'] = '/abc/def/ghi' + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info), [ + {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, + ]) + segment_info.update(shortened_path='~foo/ghi') + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info), [ + {'contents': '~foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'ghi', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, use_shortened_path=False), [ + {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, + ]) + segment_info.pop('shortened_path') + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=3), [ + {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=3, shorten_home=False), [ + {'contents': '...', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'ghi', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1), [ + {'contents': '...', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, ellipsis='---'), [ + {'contents': '---', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, ellipsis=None), [ + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, use_path_separator=True), [ + {'contents': '.../', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, use_path_separator=True, ellipsis='---'), [ + {'contents': '---/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, use_path_separator=True, ellipsis=None), [ + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2), [ + {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'fo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2, use_path_separator=True), [ + {'contents': '~/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, + {'contents': 'fo/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + cwd[0] = '/etc' + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, use_path_separator=False), [ + {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'etc', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, use_path_separator=True), [ + {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, + {'contents': 'etc', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']}, + ]) + cwd[0] = '/' + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, use_path_separator=False), [ + {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, + ]) + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, use_path_separator=True), [ + {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']}, + ]) + ose = OSError() + ose.errno = 2 + cwd[0] = ose + self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2), [ + {'contents': '[not found]', 'divider_highlight_group': 'cwd:divider', 'highlight_groups': ['cwd:current_folder', 'cwd'], 'draw_inner_divider': True} + ]) + cwd[0] = OSError() + self.assertRaises(OSError, shell.cwd, pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2) + cwd[0] = ValueError() + self.assertRaises(ValueError, shell.cwd, pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2) + + +class TestTmux(TestCase): + def test_attached_clients(self): + def get_tmux_output(pl, cmd, *args): + if cmd == 'list-panes': + return 'session_name\n' + elif cmd == 'list-clients': + return '/dev/pts/2: 0 [191x51 xterm-256color] (utf8)\n/dev/pts/3: 0 [191x51 xterm-256color] (utf8)' + + pl = Pl() + with replace_attr(tmux, 'get_tmux_output', get_tmux_output): + self.assertEqual(tmux.attached_clients(pl=pl), '2') + self.assertEqual(tmux.attached_clients(pl=pl, minimum=3), None) + + +class TestCommon(TestCase): + @classmethod + def setUpClass(cls): + module = __import__(str('powerline.segments.common.{0}'.format(cls.module_name))) + cls.module = getattr(module.segments.common, str(cls.module_name)) + + +class TestNet(TestCommon): + module_name = 'net' + + def test_hostname(self): + pl = Pl() + with replace_env('SSH_CLIENT', '192.168.0.12 40921 22') as segment_info: + with replace_module_module(self.module, 'socket', gethostname=lambda: 'abc'): + self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info), 'abc') + self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info, only_if_ssh=True), 'abc') + with replace_module_module(self.module, 'socket', gethostname=lambda: 'abc.mydomain'): + self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info), 'abc.mydomain') + self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info, exclude_domain=True), 'abc') + self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info, only_if_ssh=True), 'abc.mydomain') + self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info, only_if_ssh=True, exclude_domain=True), 'abc') + segment_info['environ'].pop('SSH_CLIENT') + with replace_module_module(self.module, 'socket', gethostname=lambda: 'abc'): + self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info), 'abc') + self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info, only_if_ssh=True), None) + with replace_module_module(self.module, 'socket', gethostname=lambda: 'abc.mydomain'): + self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info), 'abc.mydomain') + self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info, exclude_domain=True), 'abc') + self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info, only_if_ssh=True, exclude_domain=True), None) + + def test_external_ip(self): + pl = Pl() + with replace_attr(self.module, 'urllib_read', urllib_read): + self.assertEqual(self.module.external_ip(pl=pl), [{'contents': '127.0.0.1', 'divider_highlight_group': 'background:divider'}]) + + def test_internal_ip(self): + try: + import netifaces + except ImportError: + raise SkipTest('netifaces module is not available') + pl = Pl() + addr = { + 'enp2s0': { + netifaces.AF_INET: [{'addr': '192.168.100.200'}], + netifaces.AF_INET6: [{'addr': 'feff::5446:5eff:fe5a:7777%enp2s0'}] + }, + 'lo': { + netifaces.AF_INET: [{'addr': '127.0.0.1'}], + netifaces.AF_INET6: [{'addr': '::1'}] + }, + 'teredo': { + netifaces.AF_INET6: [{'addr': 'feff::5446:5eff:fe5a:7777'}] + }, + } + interfaces = ['lo', 'enp2s0', 'teredo'] + with replace_module_module( + self.module, 'netifaces', + interfaces=(lambda: interfaces), + ifaddresses=(lambda interface: addr[interface]), + AF_INET=netifaces.AF_INET, + AF_INET6=netifaces.AF_INET6, + ): + self.assertEqual(self.module.internal_ip(pl=pl), '192.168.100.200') + self.assertEqual(self.module.internal_ip(pl=pl, interface='auto'), '192.168.100.200') + self.assertEqual(self.module.internal_ip(pl=pl, interface='lo'), '127.0.0.1') + self.assertEqual(self.module.internal_ip(pl=pl, interface='teredo'), None) + self.assertEqual(self.module.internal_ip(pl=pl, ipv=4), '192.168.100.200') + self.assertEqual(self.module.internal_ip(pl=pl, interface='auto', ipv=4), '192.168.100.200') + self.assertEqual(self.module.internal_ip(pl=pl, interface='lo', ipv=4), '127.0.0.1') + self.assertEqual(self.module.internal_ip(pl=pl, interface='teredo', ipv=4), None) + self.assertEqual(self.module.internal_ip(pl=pl, ipv=6), 'feff::5446:5eff:fe5a:7777%enp2s0') + self.assertEqual(self.module.internal_ip(pl=pl, interface='auto', ipv=6), 'feff::5446:5eff:fe5a:7777%enp2s0') + self.assertEqual(self.module.internal_ip(pl=pl, interface='lo', ipv=6), '::1') + self.assertEqual(self.module.internal_ip(pl=pl, interface='teredo', ipv=6), 'feff::5446:5eff:fe5a:7777') + interfaces[1:2] = () + self.assertEqual(self.module.internal_ip(pl=pl, ipv=6), 'feff::5446:5eff:fe5a:7777') + interfaces[1:2] = () + self.assertEqual(self.module.internal_ip(pl=pl, ipv=6), '::1') + interfaces[:] = () + self.assertEqual(self.module.internal_ip(pl=pl, ipv=6), None) + + gateways = { + 'default': { + netifaces.AF_INET: ('192.168.100.1', 'enp2s0'), + netifaces.AF_INET6: ('feff::5446:5eff:fe5a:0001', 'enp2s0') + } + } + + with replace_module_module( + self.module, 'netifaces', + interfaces=(lambda: interfaces), + ifaddresses=(lambda interface: addr[interface]), + gateways=(lambda: gateways), + AF_INET=netifaces.AF_INET, + AF_INET6=netifaces.AF_INET6, + ): + # default gateway has specified address family + self.assertEqual(self.module.internal_ip(pl=pl, interface='default_gateway', ipv=4), '192.168.100.200') + self.assertEqual(self.module.internal_ip(pl=pl, interface='default_gateway', ipv=6), 'feff::5446:5eff:fe5a:7777%enp2s0') + # default gateway doesn't have specified address family + gateways['default'] = {} + self.assertEqual(self.module.internal_ip(pl=pl, interface='default_gateway', ipv=4), None) + self.assertEqual(self.module.internal_ip(pl=pl, interface='default_gateway', ipv=6), None) + +# TODO: fix network load +#def test_network_load(self): +# def gb(interface): +# return None +# +# f = [gb] +# +# def _get_bytes(interface): +# return f[0](interface) +# +# pl = Pl() +# +# with replace_attr(self.module, '_get_bytes', _get_bytes): +# self.module.network_load.startup(pl=pl) +# try: +# self.assertEqual(self.module.network_load(pl=pl, interface='eth0'), None) +# sleep(self.module.network_load.interval) +# self.assertEqual(self.module.network_load(pl=pl, interface='eth0'), None) +# while 'prev' not in self.module.network_load.interfaces.get('eth0', {}): +# sleep(0.1) +# self.assertEqual(self.module.network_load(pl=pl, interface='eth0'), None) +# +# l = [0, 0] +# +# def gb2(interface): +# l[0] += 1200 +# l[1] += 2400 +# return tuple(l) +# f[0] = gb2 +# +# while not self.module.network_load.interfaces.get('eth0', {}).get('prev', (None, None))[1]: +# sleep(0.1) +# self.assertEqual(self.module.network_load(pl=pl, interface='eth0'), [ +# {'divider_highlight_group': 'network_load:divider', 'contents': 'DL 1 KiB/s', 'highlight_groups': ['network_load_recv', 'network_load']}, +# {'divider_highlight_group': 'network_load:divider', 'contents': 'UL 2 KiB/s', 'highlight_groups': ['network_load_sent', 'network_load']}, +# ]) +# self.assertEqual(self.module.network_load(pl=pl, interface='eth0', recv_format='r {value}', sent_format='s {value}'), [ +# {'divider_highlight_group': 'network_load:divider', 'contents': 'r 1 KiB/s', 'highlight_groups': ['network_load_recv', 'network_load']}, +# {'divider_highlight_group': 'network_load:divider', 'contents': 's 2 KiB/s', 'highlight_groups': ['network_load_sent', 'network_load']}, +# ]) +# self.assertEqual(self.module.network_load(pl=pl, recv_format='r {value}', sent_format='s {value}', suffix='bps', interface='eth0'), [ +# {'divider_highlight_group': 'network_load:divider', 'contents': 'r 1 Kibps', 'highlight_groups': ['network_load_recv', 'network_load']}, +# {'divider_highlight_group': 'network_load:divider', 'contents': 's 2 Kibps', 'highlight_groups': ['network_load_sent', 'network_load']}, +# ]) +# self.assertEqual(self.module.network_load(pl=pl, recv_format='r {value}', sent_format='s {value}', si_prefix=True, interface='eth0'), [ +# {'divider_highlight_group': 'network_load:divider', 'contents': 'r 1 kB/s', 'highlight_groups': ['network_load_recv', 'network_load']}, +# {'divider_highlight_group': 'network_load:divider', 'contents': 's 2 kB/s', 'highlight_groups': ['network_load_sent', 'network_load']}, +# ]) +# self.assertEqual(self.module.network_load(pl=pl, recv_format='r {value}', sent_format='s {value}', recv_max=0, interface='eth0'), [ +# {'divider_highlight_group': 'network_load:divider', 'contents': 'r 1 KiB/s', 'highlight_groups': ['network_load_recv_gradient', 'network_load_gradient', 'network_load_recv', 'network_load'], 'gradient_level': 100}, +# {'divider_highlight_group': 'network_load:divider', 'contents': 's 2 KiB/s', 'highlight_groups': ['network_load_sent', 'network_load']}, +# ]) +# +# class ApproxEqual(object): +# def __eq__(self, i): +# return abs(i - 50.0) < 1 +# +# self.assertEqual(self.module.network_load(pl=pl, recv_format='r {value}', sent_format='s {value}', sent_max=4800, interface='eth0'), [ +# {'divider_highlight_group': 'network_load:divider', 'contents': 'r 1 KiB/s', 'highlight_groups': ['network_load_recv', 'network_load']}, +# {'divider_highlight_group': 'network_load:divider', 'contents': 's 2 KiB/s', 'highlight_groups': ['network_load_sent_gradient', 'network_load_gradient', 'network_load_sent', 'network_load'], 'gradient_level': ApproxEqual()}, +# ]) +# finally: +# self.module.network_load.shutdown() + + +class TestEnv(TestCommon): + module_name = 'env' + + def test_user(self): + new_os = new_module('os', getpid=lambda: 1) + + class Process(object): + def __init__(self, pid): + pass + + def username(self): + return 'def@DOMAIN.COM' + + if hasattr(self.module, 'psutil') and not callable(self.module.psutil.Process.username): + username = property(username) + + segment_info = {'environ': {}} + + def user(*args, **kwargs): + return self.module.user(pl=pl, segment_info=segment_info, *args, **kwargs) + + struct_passwd = namedtuple('struct_passwd', ('pw_name',)) + new_psutil = new_module('psutil', Process=Process) + new_pwd = new_module('pwd', getpwuid=lambda uid: struct_passwd(pw_name='def@DOMAIN.COM')) + new_getpass = new_module('getpass', getuser=lambda: 'def@DOMAIN.COM') + pl = Pl() + with replace_attr(self.module, 'pwd', new_pwd): + with replace_attr(self.module, 'getpass', new_getpass): + with replace_attr(self.module, 'os', new_os): + with replace_attr(self.module, 'psutil', new_psutil): + with replace_attr(self.module, '_geteuid', lambda: 5): + self.assertEqual(user(), [ + {'contents': 'def@DOMAIN.COM', 'highlight_groups': ['user']} + ]) + self.assertEqual(user(hide_user='abc'), [ + {'contents': 'def@DOMAIN.COM', 'highlight_groups': ['user']} + ]) + self.assertEqual(user(hide_domain=False), [ + {'contents': 'def@DOMAIN.COM', 'highlight_groups': ['user']} + ]) + self.assertEqual(user(hide_user='def@DOMAIN.COM'), None) + self.assertEqual(user(hide_domain=True), [ + {'contents': 'def', 'highlight_groups': ['user']} + ]) + with replace_attr(self.module, '_geteuid', lambda: 0): + self.assertEqual(user(), [ + {'contents': 'def', 'highlight_groups': ['superuser', 'user']} + ]) + + def test_cwd(self): + new_os = new_module('os', path=os.path, sep='/') + pl = Pl() + cwd = [None] + + def getcwd(): + wd = cwd[0] + if isinstance(wd, Exception): + raise wd + else: + return wd + + segment_info = {'getcwd': getcwd, 'home': None} + with replace_attr(self.module, 'os', new_os): + cwd[0] = '/abc/def/ghi/foo/bar' + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info), [ + {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'abc', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'def', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'ghi', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, + ]) + segment_info['home'] = '/abc/def/ghi' + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info), [ + {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, + ]) + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=3), [ + {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=3, shorten_home=False), [ + {'contents': '...', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'ghi', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1), [ + {'contents': '...', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, ellipsis='---'), [ + {'contents': '---', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, ellipsis=None), [ + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, use_path_separator=True), [ + {'contents': '.../', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, use_path_separator=True, ellipsis='---'), [ + {'contents': '---/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, use_path_separator=True, ellipsis=None), [ + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2), [ + {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'fo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2, use_path_separator=True), [ + {'contents': '~/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, + {'contents': 'fo/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, + {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']} + ]) + cwd[0] = '/etc' + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, use_path_separator=False), [ + {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, + {'contents': 'etc', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, + ]) + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, use_path_separator=True), [ + {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, + {'contents': 'etc', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']}, + ]) + cwd[0] = '/' + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, use_path_separator=False), [ + {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, + ]) + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, use_path_separator=True), [ + {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']}, + ]) + ose = OSError() + ose.errno = 2 + cwd[0] = ose + self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2), [ + {'contents': '[not found]', 'divider_highlight_group': 'cwd:divider', 'highlight_groups': ['cwd:current_folder', 'cwd'], 'draw_inner_divider': True} + ]) + cwd[0] = OSError() + self.assertRaises(OSError, self.module.cwd, pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2) + cwd[0] = ValueError() + self.assertRaises(ValueError, self.module.cwd, pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2) + + def test_virtualenv(self): + pl = Pl() + with replace_env('VIRTUAL_ENV', '/abc/def/ghi') as segment_info: + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), 'ghi') + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), 'ghi') + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), None) + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None) + + segment_info['environ'].pop('VIRTUAL_ENV') + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), None) + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), None) + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), None) + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None) + + with replace_env('CONDA_DEFAULT_ENV', 'foo') as segment_info: + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), 'foo') + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), None) + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), 'foo') + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None) + + segment_info['environ'].pop('CONDA_DEFAULT_ENV') + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), None) + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), None) + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), None) + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None) + + with replace_env('CONDA_DEFAULT_ENV', 'foo', environ={'VIRTUAL_ENV': '/sbc/def/ghi'}) as segment_info: + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), 'ghi') + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), 'ghi') + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), 'foo') + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None) + + segment_info['environ'].pop('CONDA_DEFAULT_ENV') + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), 'ghi') + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), 'ghi') + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), None) + self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None) + + def test_environment(self): + pl = Pl() + variable = 'FOO' + value = 'bar' + with replace_env(variable, value) as segment_info: + self.assertEqual(self.module.environment(pl=pl, segment_info=segment_info, variable=variable), value) + segment_info['environ'].pop(variable) + self.assertEqual(self.module.environment(pl=pl, segment_info=segment_info, variable=variable), None) + + +class TestVcs(TestCommon): + module_name = 'vcs' + + def test_branch(self): + pl = Pl() + create_watcher = get_fallback_create_watcher() + segment_info = {'getcwd': os.getcwd} + branch = partial(self.module.branch, pl=pl, create_watcher=create_watcher) + with replace_attr(self.module, 'guess', get_dummy_guess(status=lambda: None, directory='/tmp/tests')): + with replace_attr(self.module, 'tree_status', lambda repo, pl: None): + self.assertEqual(branch(segment_info=segment_info, status_colors=False), [{ + 'highlight_groups': ['branch'], + 'contents': 'tests', + 'divider_highlight_group': None + }]) + self.assertEqual(branch(segment_info=segment_info, status_colors=True), [{ + 'contents': 'tests', + 'highlight_groups': ['branch_clean', 'branch'], + 'divider_highlight_group': None + }]) + with replace_attr(self.module, 'guess', get_dummy_guess(status=lambda: 'D ', directory='/tmp/tests')): + with replace_attr(self.module, 'tree_status', lambda repo, pl: 'D '): + self.assertEqual(branch(segment_info=segment_info, status_colors=False), [{ + 'highlight_groups': ['branch'], + 'contents': 'tests', + 'divider_highlight_group': None + }]) + self.assertEqual(branch(segment_info=segment_info, status_colors=True), [{ + 'contents': 'tests', + 'highlight_groups': ['branch_dirty', 'branch'], + 'divider_highlight_group': None + }]) + self.assertEqual(branch(segment_info=segment_info, status_colors=False), [{ + 'highlight_groups': ['branch'], + 'contents': 'tests', + 'divider_highlight_group': None + }]) + with replace_attr(self.module, 'guess', lambda path, create_watcher: None): + self.assertEqual(branch(segment_info=segment_info, status_colors=False), None) + with replace_attr(self.module, 'guess', get_dummy_guess(status=lambda: 'U')): + with replace_attr(self.module, 'tree_status', lambda repo, pl: 'U'): + self.assertEqual(branch(segment_info=segment_info, status_colors=False, ignore_statuses=['U']), [{ + 'highlight_groups': ['branch'], + 'contents': 'tests', + 'divider_highlight_group': None + }]) + self.assertEqual(branch(segment_info=segment_info, status_colors=True, ignore_statuses=['DU']), [{ + 'highlight_groups': ['branch_dirty', 'branch'], + 'contents': 'tests', + 'divider_highlight_group': None + }]) + self.assertEqual(branch(segment_info=segment_info, status_colors=True), [{ + 'highlight_groups': ['branch_dirty', 'branch'], + 'contents': 'tests', + 'divider_highlight_group': None + }]) + self.assertEqual(branch(segment_info=segment_info, status_colors=True, ignore_statuses=['U']), [{ + 'highlight_groups': ['branch_clean', 'branch'], + 'contents': 'tests', + 'divider_highlight_group': None + }]) + + def test_stash(self): + pl = Pl() + create_watcher = get_fallback_create_watcher() + stash = partial(self.module.stash, pl=pl, create_watcher=create_watcher, segment_info={'getcwd': os.getcwd}) + + def forge_stash(n): + return replace_attr(self.module, 'guess', get_dummy_guess(stash=lambda: n, directory='/tmp/tests')) + + with forge_stash(0): + self.assertEqual(stash(), None) + with forge_stash(1): + self.assertEqual(stash(), [{ + 'highlight_groups': ['stash'], + 'contents': '1', + 'divider_highlight_group': None + }]) + with forge_stash(2): + self.assertEqual(stash(), [{ + 'highlight_groups': ['stash'], + 'contents': '2', + 'divider_highlight_group': None + }]) + + +class TestTime(TestCommon): + module_name = 'time' + + def test_date(self): + pl = Pl() + with replace_attr(self.module, 'datetime', Args(now=lambda: Args(strftime=lambda fmt: fmt))): + self.assertEqual(self.module.date(pl=pl), [{'contents': '%Y-%m-%d', 'highlight_groups': ['date'], 'divider_highlight_group': None}]) + self.assertEqual(self.module.date(pl=pl, format='%H:%M', istime=True), [{'contents': '%H:%M', 'highlight_groups': ['time', 'date'], 'divider_highlight_group': 'time:divider'}]) + unicode_date = self.module.date(pl=pl, format='\u231a', istime=True) + expected_unicode_date = [{'contents': '\u231a', 'highlight_groups': ['time', 'date'], 'divider_highlight_group': 'time:divider'}] + if python_implementation() == 'PyPy' and sys.version_info >= (3,): + if unicode_date != expected_unicode_date: + raise SkipTest('Dates do not match, see https://bitbucket.org/pypy/pypy/issues/2161/pypy3-strftime-does-not-accept-unicode') + self.assertEqual(unicode_date, expected_unicode_date) + + def test_fuzzy_time(self): + time = Args(hour=0, minute=45) + pl = Pl() + with replace_attr(self.module, 'datetime', Args(now=lambda: time)): + self.assertEqual(self.module.fuzzy_time(pl=pl), 'quarter to one') + time.hour = 23 + time.minute = 59 + self.assertEqual(self.module.fuzzy_time(pl=pl), 'round about midnight') + time.minute = 33 + self.assertEqual(self.module.fuzzy_time(pl=pl), 'twenty-five to twelve') + time.minute = 60 + self.assertEqual(self.module.fuzzy_time(pl=pl), 'twelve o\'clock') + time.minute = 33 + self.assertEqual(self.module.fuzzy_time(pl=pl, unicode_text=False), 'twenty-five to twelve') + time.minute = 60 + self.assertEqual(self.module.fuzzy_time(pl=pl, unicode_text=False), 'twelve o\'clock') + time.minute = 33 + self.assertEqual(self.module.fuzzy_time(pl=pl, unicode_text=True), 'twenty‐five to twelve') + time.minute = 60 + self.assertEqual(self.module.fuzzy_time(pl=pl, unicode_text=True), 'twelve o’clock') + + +class TestSys(TestCommon): + module_name = 'sys' + + def test_uptime(self): + pl = Pl() + with replace_attr(self.module, '_get_uptime', lambda: 259200): + self.assertEqual(self.module.uptime(pl=pl), [{'contents': '3d', 'divider_highlight_group': 'background:divider'}]) + with replace_attr(self.module, '_get_uptime', lambda: 93784): + self.assertEqual(self.module.uptime(pl=pl), [{'contents': '1d 2h 3m', 'divider_highlight_group': 'background:divider'}]) + self.assertEqual(self.module.uptime(pl=pl, shorten_len=4), [{'contents': '1d 2h 3m 4s', 'divider_highlight_group': 'background:divider'}]) + with replace_attr(self.module, '_get_uptime', lambda: 65536): + self.assertEqual(self.module.uptime(pl=pl), [{'contents': '18h 12m 16s', 'divider_highlight_group': 'background:divider'}]) + self.assertEqual(self.module.uptime(pl=pl, shorten_len=2), [{'contents': '18h 12m', 'divider_highlight_group': 'background:divider'}]) + self.assertEqual(self.module.uptime(pl=pl, shorten_len=1), [{'contents': '18h', 'divider_highlight_group': 'background:divider'}]) + + def _get_uptime(): + raise NotImplementedError + + with replace_attr(self.module, '_get_uptime', _get_uptime): + self.assertEqual(self.module.uptime(pl=pl), None) + + def test_system_load(self): + pl = Pl() + with replace_module_module(self.module, 'os', getloadavg=lambda: (7.5, 3.5, 1.5)): + with replace_attr(self.module, '_cpu_count', lambda: 2): + self.assertEqual(self.module.system_load(pl=pl), [ + {'contents': '7.5 ', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 100}, + {'contents': '3.5 ', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 75.0}, + {'contents': '1.5', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 0} + ]) + self.assertEqual(self.module.system_load(pl=pl, format='{avg:.0f}', threshold_good=0, threshold_bad=1), [ + {'contents': '8 ', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 100}, + {'contents': '4 ', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 100}, + {'contents': '2', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 75.0} + ]) + self.assertEqual(self.module.system_load(pl=pl, short=True), [ + {'contents': '7.5', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 100}, + ]) + self.assertEqual(self.module.system_load(pl=pl, format='{avg:.0f}', threshold_good=0, threshold_bad=1, short=True), [ + {'contents': '8', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 100}, + ]) + + def test_cpu_load_percent(self): + try: + __import__('psutil') + except ImportError as e: + raise SkipTest('Failed to import psutil: {0}'.format(e)) + pl = Pl() + with replace_module_module(self.module, 'psutil', cpu_percent=lambda **kwargs: 52.3): + self.assertEqual(self.module.cpu_load_percent(pl=pl), [{ + 'contents': '52%', + 'gradient_level': 52.3, + 'highlight_groups': ['cpu_load_percent_gradient', 'cpu_load_percent'], + }]) + self.assertEqual(self.module.cpu_load_percent(pl=pl, format='{0:.1f}%'), [{ + 'contents': '52.3%', + 'gradient_level': 52.3, + 'highlight_groups': ['cpu_load_percent_gradient', 'cpu_load_percent'], + }]) + + +class TestWthr(TestCommon): + module_name = 'wthr' + + def test_weather(self): + pl = Pl() + with replace_attr(self.module, 'urllib_read', urllib_read): + self.assertEqual(self.module.weather(pl=pl), [ + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'WINDY '}, + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '14°C', 'gradient_level': 62.857142857142854} + ]) + self.assertEqual(self.module.weather(pl=pl, temp_coldest=0, temp_hottest=100), [ + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'WINDY '}, + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '14°C', 'gradient_level': 14.0} + ]) + self.assertEqual(self.module.weather(pl=pl, temp_coldest=-100, temp_hottest=-50), [ + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'WINDY '}, + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '14°C', 'gradient_level': 100} + ]) + self.assertEqual(self.module.weather(pl=pl, icons={'blustery': 'o'}), [ + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'o '}, + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '14°C', 'gradient_level': 62.857142857142854} + ]) + self.assertEqual(self.module.weather(pl=pl, icons={'windy': 'x'}), [ + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'x '}, + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '14°C', 'gradient_level': 62.857142857142854} + ]) + self.assertEqual(self.module.weather(pl=pl, unit='F'), [ + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'WINDY '}, + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '57°F', 'gradient_level': 62.857142857142854} + ]) + self.assertEqual(self.module.weather(pl=pl, unit='K'), [ + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'WINDY '}, + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '287K', 'gradient_level': 62.857142857142854} + ]) + self.assertEqual(self.module.weather(pl=pl, temp_format='{temp:.1e}C'), [ + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'WINDY '}, + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '1.4e+01C', 'gradient_level': 62.857142857142854} + ]) + with replace_attr(self.module, 'urllib_read', urllib_read): + self.module.weather.startup(pl=pl, location_query='Meppen,06,DE') + self.assertEqual(self.module.weather(pl=pl), [ + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'WINDY '}, + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '14°C', 'gradient_level': 62.857142857142854} + ]) + self.assertEqual(self.module.weather(pl=pl, location_query='Moscow,RU'), [ + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_fair_night', 'weather_condition_night', 'weather_conditions', 'weather'], 'contents': 'NIGHT '}, + {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '9°C', 'gradient_level': 55.714285714285715} + ]) + self.module.weather.shutdown() + + +class TestI3WM(TestCase): + @staticmethod + def get_workspaces(): + return iter([ + {'name': '1: w1', 'output': 'LVDS1', 'focused': False, 'urgent': False, 'visible': False}, + {'name': '2: w2', 'output': 'LVDS1', 'focused': False, 'urgent': False, 'visible': True}, + {'name': '3: w3', 'output': 'HDMI1', 'focused': False, 'urgent': True, 'visible': True}, + {'name': '4: w4', 'output': 'DVI01', 'focused': True, 'urgent': True, 'visible': True}, + ]) + + def test_workspaces(self): + pl = Pl() + with replace_attr(i3wm, 'get_i3_connection', lambda: Args(get_workspaces=self.get_workspaces)): + segment_info = {} + + self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info), [ + {'contents': '1: w1', 'highlight_groups': ['workspace']}, + {'contents': '2: w2', 'highlight_groups': ['w_visible', 'workspace']}, + {'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']}, + {'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']}, + ]) + self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=None), [ + {'contents': '1: w1', 'highlight_groups': ['workspace']}, + {'contents': '2: w2', 'highlight_groups': ['w_visible', 'workspace']}, + {'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']}, + {'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']}, + ]) + self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['focused', 'urgent']), [ + {'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']}, + {'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']}, + ]) + self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible']), [ + {'contents': '2: w2', 'highlight_groups': ['w_visible', 'workspace']}, + {'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']}, + {'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']}, + ]) + self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], strip=3), [ + {'contents': 'w2', 'highlight_groups': ['w_visible', 'workspace']}, + {'contents': 'w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']}, + {'contents': 'w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']}, + ]) + self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['focused', 'urgent'], output='DVI01'), [ + {'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']}, + ]) + self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], output='HDMI1'), [ + {'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']}, + ]) + self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], strip=3, output='LVDS1'), [ + {'contents': 'w2', 'highlight_groups': ['w_visible', 'workspace']}, + ]) + segment_info['output'] = 'LVDS1' + self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], output='HDMI1'), [ + {'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']}, + ]) + self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], strip=3), [ + {'contents': 'w2', 'highlight_groups': ['w_visible', 'workspace']}, + ]) + + def test_workspace(self): + pl = Pl() + with replace_attr(i3wm, 'get_i3_connection', lambda: Args(get_workspaces=self.get_workspaces)): + segment_info = {} + + self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, workspace='1: w1'), [ + {'contents': '1: w1', 'highlight_groups': ['workspace']}, + ]) + self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, workspace='3: w3', strip=True), [ + {'contents': 'w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']}, + ]) + self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, workspace='9: w9'), None) + self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info), [ + {'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']}, + ]) + segment_info['workspace'] = next(self.get_workspaces()) + self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, workspace='4: w4'), [ + {'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']}, + ]) + self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, strip=True), [ + {'contents': 'w1', 'highlight_groups': ['workspace']}, + ]) + + def test_mode(self): + pl = Pl() + self.assertEqual(i3wm.mode(pl=pl, segment_info={'mode': 'default'}), None) + self.assertEqual(i3wm.mode(pl=pl, segment_info={'mode': 'test'}), 'test') + self.assertEqual(i3wm.mode(pl=pl, segment_info={'mode': 'default'}, names={'default': 'test'}), 'test') + self.assertEqual(i3wm.mode(pl=pl, segment_info={'mode': 'test'}, names={'default': 'test', 'test': 't'}), 't') + + def test_scratchpad(self): + class Conn(object): + def get_tree(self): + return self + + def descendents(self): + nodes_unfocused = [Args(focused = False)] + nodes_focused = [Args(focused = True)] + + workspace_scratch = lambda: Args(name='__i3_scratch') + workspace_noscratch = lambda: Args(name='2: www') + return [ + Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_unfocused), + Args(scratchpad_state='changed', urgent=True, workspace=workspace_noscratch, nodes=nodes_focused), + Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_unfocused), + Args(scratchpad_state=None, urgent=False, workspace=workspace_noscratch, nodes=nodes_unfocused), + Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_focused), + Args(scratchpad_state=None, urgent=True, workspace=workspace_noscratch, nodes=nodes_unfocused), + ] + + pl = Pl() + with replace_attr(i3wm, 'get_i3_connection', lambda: Conn()): + self.assertEqual(i3wm.scratchpad(pl=pl), [ + {'contents': 'O', 'highlight_groups': ['scratchpad']}, + {'contents': 'X', 'highlight_groups': ['scratchpad:urgent', 'scratchpad:focused', 'scratchpad:visible', 'scratchpad']}, + {'contents': 'O', 'highlight_groups': ['scratchpad']}, + {'contents': 'X', 'highlight_groups': ['scratchpad:visible', 'scratchpad']}, + {'contents': 'O', 'highlight_groups': ['scratchpad:focused', 'scratchpad']}, + {'contents': 'X', 'highlight_groups': ['scratchpad:urgent', 'scratchpad:visible', 'scratchpad']}, + ]) + self.assertEqual(i3wm.scratchpad(pl=pl, icons={'changed': '-', 'fresh': 'o'}), [ + {'contents': 'o', 'highlight_groups': ['scratchpad']}, + {'contents': '-', 'highlight_groups': ['scratchpad:urgent', 'scratchpad:focused', 'scratchpad:visible', 'scratchpad']}, + {'contents': 'o', 'highlight_groups': ['scratchpad']}, + {'contents': '-', 'highlight_groups': ['scratchpad:visible', 'scratchpad']}, + {'contents': 'o', 'highlight_groups': ['scratchpad:focused', 'scratchpad']}, + {'contents': '-', 'highlight_groups': ['scratchpad:urgent', 'scratchpad:visible', 'scratchpad']}, + ]) + + +class TestMail(TestCommon): + module_name = 'mail' + + def test_email_imap_alert(self): + # TODO + pass + + +class TestPlayers(TestCommon): + module_name = 'players' + + def test_now_playing(self): + # TODO + pass + + +class TestBat(TestCommon): + module_name = 'bat' + + def test_battery(self): + pl = Pl() + + def _get_battery_status(pl): + return 86, False + + with replace_attr(self.module, '_get_battery_status', _get_battery_status): + self.assertEqual(self.module.battery(pl=pl), [{ + 'contents': ' 86%', + 'highlight_groups': ['battery_gradient', 'battery'], + 'gradient_level': 14, + }]) + self.assertEqual(self.module.battery(pl=pl, format='{capacity:.2f}'), [{ + 'contents': '0.86', + 'highlight_groups': ['battery_gradient', 'battery'], + 'gradient_level': 14, + }]) + self.assertEqual(self.module.battery(pl=pl, steps=7), [{ + 'contents': ' 86%', + 'highlight_groups': ['battery_gradient', 'battery'], + 'gradient_level': 14, + }]) + self.assertEqual(self.module.battery(pl=pl, gamify=True), [ + { + 'contents': ' ', + 'draw_inner_divider': False, + 'highlight_groups': ['battery_offline', 'battery_ac_state', 'battery_gradient', 'battery'], + 'gradient_level': 0 + }, + { + 'contents': 'OOOO', + 'draw_inner_divider': False, + 'highlight_groups': ['battery_full', 'battery_gradient', 'battery'], + 'gradient_level': 0 + }, + { + 'contents': 'O', + 'draw_inner_divider': False, + 'highlight_groups': ['battery_empty', 'battery_gradient', 'battery'], + 'gradient_level': 100 + } + ]) + self.assertEqual(self.module.battery(pl=pl, gamify=True, full_heart='+', empty_heart='-', steps='10'), [ + { + 'contents': ' ', + 'draw_inner_divider': False, + 'highlight_groups': ['battery_offline', 'battery_ac_state', 'battery_gradient', 'battery'], + 'gradient_level': 0 + }, + { + 'contents': '++++++++', + 'draw_inner_divider': False, + 'highlight_groups': ['battery_full', 'battery_gradient', 'battery'], + 'gradient_level': 0 + }, + { + 'contents': '--', + 'draw_inner_divider': False, + 'highlight_groups': ['battery_empty', 'battery_gradient', 'battery'], + 'gradient_level': 100 + } + ]) + + def test_battery_with_ac_online(self): + pl = Pl() + + def _get_battery_status(pl): + return 86, True + + with replace_attr(self.module, '_get_battery_status', _get_battery_status): + self.assertEqual(self.module.battery(pl=pl, online='C', offline=' '), [ + { + 'contents': 'C 86%', + 'highlight_groups': ['battery_gradient', 'battery'], + 'gradient_level': 14, + }]) + + def test_battery_with_ac_offline(self): + pl = Pl() + + def _get_battery_status(pl): + return 86, False + + with replace_attr(self.module, '_get_battery_status', _get_battery_status): + self.assertEqual(self.module.battery(pl=pl, online='C', offline=' '), [ + { + 'contents': ' 86%', + 'highlight_groups': ['battery_gradient', 'battery'], + 'gradient_level': 14, + }]) + + +class TestVim(TestCase): + def test_mode(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info), 'NORMAL') + self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info, override={'i': 'INS'}), 'NORMAL') + self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info, override={'n': 'NORM'}), 'NORM') + with vim_module._with('mode', 'i') as segment_info: + self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info), 'INSERT') + with vim_module._with('mode', 'i\0') as segment_info: + self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info), 'INSERT') + with vim_module._with('mode', chr(ord('V') - 0x40)) as segment_info: + self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info), 'V-BLCK') + self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info, override={'^V': 'VBLK'}), 'VBLK') + + def test_visual_range(self): + pl = Pl() + vr = partial(self.vim.visual_range, pl=pl) + vim_module.current.window.cursor = [0, 0] + try: + with vim_module._with('mode', 'i') as segment_info: + self.assertEqual(vr(segment_info=segment_info), '') + with vim_module._with('mode', '^V') as segment_info: + self.assertEqual(vr(segment_info=segment_info), '1 x 1') + with vim_module._with('vpos', line=5, col=5, off=0): + self.assertEqual(vr(segment_info=segment_info), '5 x 5') + with vim_module._with('vpos', line=5, col=4, off=0): + self.assertEqual(vr(segment_info=segment_info), '5 x 4') + with vim_module._with('mode', '^S') as segment_info: + self.assertEqual(vr(segment_info=segment_info), '1 x 1') + with vim_module._with('vpos', line=5, col=5, off=0): + self.assertEqual(vr(segment_info=segment_info), '5 x 5') + with vim_module._with('vpos', line=5, col=4, off=0): + self.assertEqual(vr(segment_info=segment_info), '5 x 4') + with vim_module._with('mode', 'V') as segment_info: + self.assertEqual(vr(segment_info=segment_info), 'L:1') + with vim_module._with('vpos', line=5, col=5, off=0): + self.assertEqual(vr(segment_info=segment_info), 'L:5') + with vim_module._with('vpos', line=5, col=4, off=0): + self.assertEqual(vr(segment_info=segment_info), 'L:5') + with vim_module._with('mode', 'S') as segment_info: + self.assertEqual(vr(segment_info=segment_info), 'L:1') + with vim_module._with('vpos', line=5, col=5, off=0): + self.assertEqual(vr(segment_info=segment_info), 'L:5') + with vim_module._with('vpos', line=5, col=4, off=0): + self.assertEqual(vr(segment_info=segment_info), 'L:5') + with vim_module._with('mode', 'v') as segment_info: + self.assertEqual(vr(segment_info=segment_info), 'C:1') + with vim_module._with('vpos', line=5, col=5, off=0): + self.assertEqual(vr(segment_info=segment_info), 'L:5') + with vim_module._with('vpos', line=5, col=4, off=0): + self.assertEqual(vr(segment_info=segment_info), 'L:5') + with vim_module._with('mode', 's') as segment_info: + self.assertEqual(vr(segment_info=segment_info), 'C:1') + with vim_module._with('vpos', line=5, col=5, off=0): + self.assertEqual(vr(segment_info=segment_info), 'L:5') + with vim_module._with('vpos', line=5, col=4, off=0): + self.assertEqual(vr(segment_info=segment_info), 'L:5') + finally: + vim_module._close(1) + + def test_modified_indicator(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + self.assertEqual(self.vim.modified_indicator(pl=pl, segment_info=segment_info), None) + segment_info['buffer'][0] = 'abc' + try: + self.assertEqual(self.vim.modified_indicator(pl=pl, segment_info=segment_info), '+') + self.assertEqual(self.vim.modified_indicator(pl=pl, segment_info=segment_info, text='-'), '-') + finally: + vim_module._bw(segment_info['bufnr']) + + def test_paste_indicator(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + self.assertEqual(self.vim.paste_indicator(pl=pl, segment_info=segment_info), None) + with vim_module._with('options', paste=1): + self.assertEqual(self.vim.paste_indicator(pl=pl, segment_info=segment_info), 'PASTE') + self.assertEqual(self.vim.paste_indicator(pl=pl, segment_info=segment_info, text='P'), 'P') + + def test_readonly_indicator(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + self.assertEqual(self.vim.readonly_indicator(pl=pl, segment_info=segment_info), None) + with vim_module._with('bufoptions', readonly=1): + self.assertEqual(self.vim.readonly_indicator(pl=pl, segment_info=segment_info), 'RO') + self.assertEqual(self.vim.readonly_indicator(pl=pl, segment_info=segment_info, text='L'), 'L') + + def test_file_scheme(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + self.assertEqual(self.vim.file_scheme(pl=pl, segment_info=segment_info), None) + with vim_module._with('buffer', '/tmp/’’/abc') as segment_info: + self.assertEqual(self.vim.file_scheme(pl=pl, segment_info=segment_info), None) + with vim_module._with('buffer', 'zipfile:/tmp/abc.zip::abc/abc.vim') as segment_info: + self.assertEqual(self.vim.file_scheme(pl=pl, segment_info=segment_info), 'zipfile') + + def test_file_directory(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info), None) + with replace_env('HOME', '/home/foo', os.environ): + with vim_module._with('buffer', '/tmp/’’/abc') as segment_info: + self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info), '/tmp/’’/') + with vim_module._with('buffer', b'/tmp/\xFF\xFF/abc') as segment_info: + self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info), '/tmp/<ff><ff>/') + with vim_module._with('buffer', '/tmp/abc') as segment_info: + self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info), '/tmp/') + os.environ['HOME'] = '/tmp' + self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info), '~/') + with vim_module._with('buffer', 'zipfile:/tmp/abc.zip::abc/abc.vim') as segment_info: + self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info, remove_scheme=False), 'zipfile:/tmp/abc.zip::abc/') + self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info, remove_scheme=True), '/tmp/abc.zip::abc/') + self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info), '/tmp/abc.zip::abc/') + os.environ['HOME'] = '/tmp' + self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info, remove_scheme=False), 'zipfile:/tmp/abc.zip::abc/') + self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info, remove_scheme=True), '/tmp/abc.zip::abc/') + self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info), '/tmp/abc.zip::abc/') + + def test_file_name(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + self.assertEqual(self.vim.file_name(pl=pl, segment_info=segment_info), None) + self.assertEqual(self.vim.file_name(pl=pl, segment_info=segment_info, display_no_file=True), [ + {'contents': '[No file]', 'highlight_groups': ['file_name_no_file', 'file_name']} + ]) + self.assertEqual(self.vim.file_name(pl=pl, segment_info=segment_info, display_no_file=True, no_file_text='X'), [ + {'contents': 'X', 'highlight_groups': ['file_name_no_file', 'file_name']} + ]) + with vim_module._with('buffer', '/tmp/abc') as segment_info: + self.assertEqual(self.vim.file_name(pl=pl, segment_info=segment_info), 'abc') + with vim_module._with('buffer', '/tmp/’’') as segment_info: + self.assertEqual(self.vim.file_name(pl=pl, segment_info=segment_info), '’’') + with vim_module._with('buffer', b'/tmp/\xFF\xFF') as segment_info: + self.assertEqual(self.vim.file_name(pl=pl, segment_info=segment_info), '<ff><ff>') + + def test_file_size(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + self.assertEqual(self.vim.file_size(pl=pl, segment_info=segment_info), '0 B') + with vim_module._with( + 'buffer', + os.path.join( + os.path.dirname(os.path.dirname(__file__)), 'empty') + ) as segment_info: + self.assertEqual(self.vim.file_size(pl=pl, segment_info=segment_info), '0 B') + + def test_file_opts(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + self.assertEqual(self.vim.file_format(pl=pl, segment_info=segment_info), [ + {'divider_highlight_group': 'background:divider', 'contents': 'unix'} + ]) + self.assertEqual(self.vim.file_encoding(pl=pl, segment_info=segment_info), [ + {'divider_highlight_group': 'background:divider', 'contents': 'utf-8'} + ]) + self.assertEqual(self.vim.file_type(pl=pl, segment_info=segment_info), None) + with vim_module._with('bufoptions', filetype='python'): + self.assertEqual(self.vim.file_type(pl=pl, segment_info=segment_info), [ + {'divider_highlight_group': 'background:divider', 'contents': 'python'} + ]) + + def test_window_title(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + self.assertEqual(self.vim.window_title(pl=pl, segment_info=segment_info), None) + with vim_module._with('wvars', quickfix_title='Abc'): + self.assertEqual(self.vim.window_title(pl=pl, segment_info=segment_info), 'Abc') + + def test_line_percent(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + segment_info['buffer'][0:-1] = [str(i) for i in range(100)] + try: + self.assertEqual(self.vim.line_percent(pl=pl, segment_info=segment_info), '1') + vim_module._set_cursor(50, 0) + self.assertEqual(self.vim.line_percent(pl=pl, segment_info=segment_info), '50') + self.assertEqual(self.vim.line_percent(pl=pl, segment_info=segment_info, gradient=True), [ + {'contents': '50', 'highlight_groups': ['line_percent_gradient', 'line_percent'], 'gradient_level': 50 * 100.0 / 101} + ]) + finally: + vim_module._bw(segment_info['bufnr']) + + def test_line_count(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + segment_info['buffer'][0:-1] = [str(i) for i in range(99)] + try: + self.assertEqual(self.vim.line_count(pl=pl, segment_info=segment_info), '100') + vim_module._set_cursor(50, 0) + self.assertEqual(self.vim.line_count(pl=pl, segment_info=segment_info), '100') + finally: + vim_module._bw(segment_info['bufnr']) + + def test_position(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + try: + segment_info['buffer'][0:-1] = [str(i) for i in range(99)] + vim_module._set_cursor(49, 0) + self.assertEqual(self.vim.position(pl=pl, segment_info=segment_info), '50%') + self.assertEqual(self.vim.position(pl=pl, segment_info=segment_info, gradient=True), [ + {'contents': '50%', 'highlight_groups': ['position_gradient', 'position'], 'gradient_level': 50.0} + ]) + vim_module._set_cursor(0, 0) + self.assertEqual(self.vim.position(pl=pl, segment_info=segment_info), 'Top') + vim_module._set_cursor(97, 0) + self.assertEqual(self.vim.position(pl=pl, segment_info=segment_info, position_strings={'top': 'Comienzo', 'bottom': 'Final', 'all': 'Todo'}), 'Final') + segment_info['buffer'][0:-1] = [str(i) for i in range(2)] + vim_module._set_cursor(0, 0) + self.assertEqual(self.vim.position(pl=pl, segment_info=segment_info, position_strings={'top': 'Comienzo', 'bottom': 'Final', 'all': 'Todo'}), 'Todo') + self.assertEqual(self.vim.position(pl=pl, segment_info=segment_info, gradient=True), [ + {'contents': 'All', 'highlight_groups': ['position_gradient', 'position'], 'gradient_level': 0.0} + ]) + finally: + vim_module._bw(segment_info['bufnr']) + + def test_cursor_current(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + self.assertEqual(self.vim.line_current(pl=pl, segment_info=segment_info), '1') + self.assertEqual(self.vim.col_current(pl=pl, segment_info=segment_info), '1') + self.assertEqual(self.vim.virtcol_current(pl=pl, segment_info=segment_info), [{ + 'highlight_groups': ['virtcol_current_gradient', 'virtcol_current', 'col_current'], 'contents': '1', 'gradient_level': 100.0 / 80, + }]) + self.assertEqual(self.vim.virtcol_current(pl=pl, segment_info=segment_info, gradient=False), [{ + 'highlight_groups': ['virtcol_current', 'col_current'], 'contents': '1', + }]) + + def test_modified_buffers(self): + pl = Pl() + self.assertEqual(self.vim.modified_buffers(pl=pl), None) + + def test_branch(self): + pl = Pl() + create_watcher = get_fallback_create_watcher() + branch = partial(self.vim.branch, pl=pl, create_watcher=create_watcher) + with vim_module._with('buffer', '/foo') as segment_info: + with replace_attr(self.vcs, 'guess', get_dummy_guess(status=lambda: None)): + with replace_attr(self.vcs, 'tree_status', lambda repo, pl: None): + self.assertEqual(branch(segment_info=segment_info, status_colors=False), [ + {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch'], 'contents': 'foo'} + ]) + self.assertEqual(branch(segment_info=segment_info, status_colors=True), [ + {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch_clean', 'branch'], 'contents': 'foo'} + ]) + with replace_attr(self.vcs, 'guess', get_dummy_guess(status=lambda: 'DU')): + with replace_attr(self.vcs, 'tree_status', lambda repo, pl: 'DU'): + self.assertEqual(branch(segment_info=segment_info, status_colors=False), [ + {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch'], 'contents': 'foo'} + ]) + self.assertEqual(branch(segment_info=segment_info, status_colors=True), [ + {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch_dirty', 'branch'], 'contents': 'foo'} + ]) + with replace_attr(self.vcs, 'guess', get_dummy_guess(status=lambda: 'U')): + with replace_attr(self.vcs, 'tree_status', lambda repo, pl: 'U'): + self.assertEqual(branch(segment_info=segment_info, status_colors=False, ignore_statuses=['U']), [ + {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch'], 'contents': 'foo'} + ]) + self.assertEqual(branch(segment_info=segment_info, status_colors=True, ignore_statuses=['DU']), [ + {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch_dirty', 'branch'], 'contents': 'foo'} + ]) + self.assertEqual(branch(segment_info=segment_info, status_colors=True), [ + {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch_dirty', 'branch'], 'contents': 'foo'} + ]) + self.assertEqual(branch(segment_info=segment_info, status_colors=True, ignore_statuses=['U']), [ + {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch_clean', 'branch'], 'contents': 'foo'} + ]) + + def test_stash(self): + pl = Pl() + create_watcher = get_fallback_create_watcher() + with vim_module._with('buffer', '/foo') as segment_info: + stash = partial(self.vim.stash, pl=pl, create_watcher=create_watcher, segment_info=segment_info) + + def forge_stash(n): + return replace_attr(self.vcs, 'guess', get_dummy_guess(stash=lambda: n)) + + with forge_stash(0): + self.assertEqual(stash(), None) + with forge_stash(1): + self.assertEqual(stash(), [{ + 'divider_highlight_group': 'stash:divider', + 'highlight_groups': ['stash'], + 'contents': '1' + }]) + with forge_stash(2): + self.assertEqual(stash(), [{ + 'divider_highlight_group': 'stash:divider', + 'highlight_groups': ['stash'], + 'contents': '2' + }]) + + def test_file_vcs_status(self): + pl = Pl() + create_watcher = get_fallback_create_watcher() + file_vcs_status = partial(self.vim.file_vcs_status, pl=pl, create_watcher=create_watcher) + with vim_module._with('buffer', '/foo') as segment_info: + with replace_attr(self.vim, 'guess', get_dummy_guess(status=lambda file: 'M')): + self.assertEqual(file_vcs_status(segment_info=segment_info), [ + {'highlight_groups': ['file_vcs_status_M', 'file_vcs_status'], 'contents': 'M'} + ]) + with replace_attr(self.vim, 'guess', get_dummy_guess(status=lambda file: None)): + self.assertEqual(file_vcs_status(segment_info=segment_info), None) + with vim_module._with('buffer', '/bar') as segment_info: + with vim_module._with('bufoptions', buftype='nofile'): + with replace_attr(self.vim, 'guess', get_dummy_guess(status=lambda file: 'M')): + self.assertEqual(file_vcs_status(segment_info=segment_info), None) + + def test_trailing_whitespace(self): + pl = Pl() + with vim_module._with('buffer', 'tws') as segment_info: + trailing_whitespace = partial(self.vim.trailing_whitespace, pl=pl, segment_info=segment_info) + self.assertEqual(trailing_whitespace(), None) + self.assertEqual(trailing_whitespace(), None) + vim_module.current.buffer[0] = ' ' + self.assertEqual(trailing_whitespace(), [{ + 'highlight_groups': ['trailing_whitespace', 'warning'], + 'contents': '1', + }]) + self.assertEqual(trailing_whitespace(), [{ + 'highlight_groups': ['trailing_whitespace', 'warning'], + 'contents': '1', + }]) + vim_module.current.buffer[0] = '' + self.assertEqual(trailing_whitespace(), None) + self.assertEqual(trailing_whitespace(), None) + + def test_tabnr(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + self.assertEqual(self.vim.tabnr(pl=pl, segment_info=segment_info, show_current=True), '1') + self.assertEqual(self.vim.tabnr(pl=pl, segment_info=segment_info, show_current=False), None) + + def test_tab(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + self.assertEqual(self.vim.tab(pl=pl, segment_info=segment_info), [{ + 'contents': None, + 'literal_contents': (0, '%1T'), + }]) + self.assertEqual(self.vim.tab(pl=pl, segment_info=segment_info, end=True), [{ + 'contents': None, + 'literal_contents': (0, '%T'), + }]) + + def test_bufnr(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + self.assertEqual(self.vim.bufnr(pl=pl, segment_info=segment_info, show_current=True), str(segment_info['bufnr'])) + self.assertEqual(self.vim.bufnr(pl=pl, segment_info=segment_info, show_current=False), None) + + def test_winnr(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + self.assertEqual(self.vim.winnr(pl=pl, segment_info=segment_info, show_current=True), str(segment_info['winnr'])) + self.assertEqual(self.vim.winnr(pl=pl, segment_info=segment_info, show_current=False), None) + + def test_segment_info(self): + pl = Pl() + with vim_module._with('tabpage'): + with vim_module._with('buffer', '1') as segment_info: + self.assertEqual(self.vim.tab_modified_indicator(pl=pl, segment_info=segment_info), None) + vim_module.current.buffer[0] = ' ' + self.assertEqual(self.vim.tab_modified_indicator(pl=pl, segment_info=segment_info), [{ + 'contents': '+', + 'highlight_groups': ['tab_modified_indicator', 'modified_indicator'], + }]) + vim_module._undo() + self.assertEqual(self.vim.tab_modified_indicator(pl=pl, segment_info=segment_info), None) + old_buffer = vim_module.current.buffer + vim_module._new('2') + segment_info = vim_module._get_segment_info() + self.assertEqual(self.vim.tab_modified_indicator(pl=pl, segment_info=segment_info), None) + old_buffer[0] = ' ' + self.assertEqual(self.vim.modified_indicator(pl=pl, segment_info=segment_info), None) + self.assertEqual(self.vim.tab_modified_indicator(pl=pl, segment_info=segment_info), [{ + 'contents': '+', + 'highlight_groups': ['tab_modified_indicator', 'modified_indicator'], + }]) + + def test_csv_col_current(self): + pl = Pl() + segment_info = vim_module._get_segment_info() + + def csv_col_current(**kwargs): + self.vim.csv_cache and self.vim.csv_cache.clear() + return self.vim.csv_col_current(pl=pl, segment_info=segment_info, **kwargs) + + buffer = segment_info['buffer'] + try: + self.assertEqual(csv_col_current(), None) + buffer.options['filetype'] = 'csv' + self.assertEqual(csv_col_current(), None) + buffer[:] = ['1;2;3', '4;5;6'] + vim_module._set_cursor(1, 1) + self.assertEqual(csv_col_current(), [{ + 'contents': '1', 'highlight_groups': ['csv:column_number', 'csv'] + }]) + vim_module._set_cursor(2, 3) + self.assertEqual(csv_col_current(), [{ + 'contents': '2', 'highlight_groups': ['csv:column_number', 'csv'] + }]) + vim_module._set_cursor(2, 3) + self.assertEqual(csv_col_current(display_name=True), [{ + 'contents': '2', 'highlight_groups': ['csv:column_number', 'csv'] + }, { + 'contents': ' (2)', 'highlight_groups': ['csv:column_name', 'csv'] + }]) + buffer[:0] = ['Foo;Bar;Baz'] + vim_module._set_cursor(2, 3) + self.assertEqual(csv_col_current(), [{ + 'contents': '2', 'highlight_groups': ['csv:column_number', 'csv'] + }, { + 'contents': ' (Bar)', 'highlight_groups': ['csv:column_name', 'csv'] + }]) + if sys.version_info < (2, 7): + raise SkipTest('csv module in Python-2.6 does not handle multiline csv files well') + buffer[len(buffer):] = ['1;"bc', 'def', 'ghi', 'jkl";3'] + vim_module._set_cursor(5, 1) + self.assertEqual(csv_col_current(), [{ + 'contents': '2', 'highlight_groups': ['csv:column_number', 'csv'] + }, { + 'contents': ' (Bar)', 'highlight_groups': ['csv:column_name', 'csv'] + }]) + vim_module._set_cursor(7, 6) + self.assertEqual(csv_col_current(), [{ + 'contents': '3', 'highlight_groups': ['csv:column_number', 'csv'] + }, { + 'contents': ' (Baz)', 'highlight_groups': ['csv:column_name', 'csv'] + }]) + self.assertEqual(csv_col_current(name_format=' ({column_name:.1})'), [{ + 'contents': '3', 'highlight_groups': ['csv:column_number', 'csv'] + }, { + 'contents': ' (B)', 'highlight_groups': ['csv:column_name', 'csv'] + }]) + self.assertEqual(csv_col_current(display_name=True, name_format=' ({column_name:.1})'), [{ + 'contents': '3', 'highlight_groups': ['csv:column_number', 'csv'] + }, { + 'contents': ' (B)', 'highlight_groups': ['csv:column_name', 'csv'] + }]) + self.assertEqual(csv_col_current(display_name=False, name_format=' ({column_name:.1})'), [{ + 'contents': '3', 'highlight_groups': ['csv:column_number', 'csv'] + }]) + self.assertEqual(csv_col_current(display_name=False), [{ + 'contents': '3', 'highlight_groups': ['csv:column_number', 'csv'] + }]) + finally: + vim_module._bw(segment_info['bufnr']) + + @classmethod + def setUpClass(cls): + sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'vim_sys_path'))) + from powerline.segments import vim + cls.vim = vim + from powerline.segments.common import vcs + cls.vcs = vcs + + @classmethod + def tearDownClass(cls): + sys.path.pop(0) + + +class TestPDB(TestCase): + def test_current_line(self): + pl = Pl() + self.assertEqual(pdb.current_line(pl=pl, segment_info={'curframe': Args(f_lineno=10)}), '10') + + def test_current_file(self): + pl = Pl() + cf = lambda **kwargs: pdb.current_file( + pl=pl, + segment_info={'curframe': Args(f_code=Args(co_filename='/tmp/abc.py'))}, + **kwargs + ) + self.assertEqual(cf(), 'abc.py') + self.assertEqual(cf(basename=True), 'abc.py') + self.assertEqual(cf(basename=False), '/tmp/abc.py') + + def test_current_code_name(self): + pl = Pl() + ccn = lambda **kwargs: pdb.current_code_name( + pl=pl, + segment_info={'curframe': Args(f_code=Args(co_name='<module>'))}, + **kwargs + ) + self.assertEqual(ccn(), '<module>') + + def test_current_context(self): + pl = Pl() + cc = lambda **kwargs: pdb.current_context( + pl=pl, + segment_info={'curframe': Args(f_code=Args(co_name='<module>', co_filename='/tmp/abc.py'))}, + **kwargs + ) + self.assertEqual(cc(), 'abc.py') + + def test_stack_depth(self): + pl = Pl() + sd = lambda **kwargs: pdb.stack_depth( + pl=pl, + segment_info={'pdb': Args(stack=[1, 2, 3]), 'initial_stack_length': 1}, + **kwargs + ) + self.assertEqual(sd(), '2') + self.assertEqual(sd(full_stack=False), '2') + self.assertEqual(sd(full_stack=True), '3') + + +old_cwd = None + + +def setUpModule(): + global old_cwd + global __file__ + old_cwd = os.getcwd() + __file__ = os.path.abspath(__file__) + os.chdir(os.path.dirname(os.path.dirname(__file__))) + + +def tearDownModule(): + global old_cwd + os.chdir(old_cwd) + + +if __name__ == '__main__': + from tests.modules import main + main() diff --git a/tests/test_python/test_selectors.py b/tests/test_python/test_selectors.py new file mode 100644 index 0000000..74ace8d --- /dev/null +++ b/tests/test_python/test_selectors.py @@ -0,0 +1,36 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os +import sys + +from functools import partial + +import tests.modules.vim as vim_module + +from tests.modules.lib import Pl +from tests.modules import TestCase + + +class TestVim(TestCase): + def test_single_tab(self): + pl = Pl() + single_tab = partial(self.vim.single_tab, pl=pl, segment_info=None, mode=None) + with vim_module._with('tabpage'): + self.assertEqual(single_tab(), False) + self.assertEqual(single_tab(), True) + + @classmethod + def setUpClass(cls): + sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'vim_sys_path'))) + from powerline.selectors import vim + cls.vim = vim + + @classmethod + def tearDownClass(cls): + sys.path.pop(0) + + +if __name__ == '__main__': + from tests.modules import main + main() diff --git a/tests/test_python/test_watcher.py b/tests/test_python/test_watcher.py new file mode 100644 index 0000000..a246d0b --- /dev/null +++ b/tests/test_python/test_watcher.py @@ -0,0 +1,245 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import shutil +import os + +from time import sleep +from functools import partial +from errno import ENOENT + +from powerline.lib.watcher import create_file_watcher, create_tree_watcher, INotifyError +from powerline.lib.watcher.uv import UvNotFound +from powerline import get_fallback_logger +from powerline.lib.monotonic import monotonic + +from tests.modules import TestCase, SkipTest + + +INOTIFY_DIR = 'inotify' + os.path.basename(os.environ.get('PYTHON', '')) + + +def clear_dir(dir): + for root, dirs, files in list(os.walk(dir, topdown=False)): + for f in files: + os.remove(os.path.join(root, f)) + for d in dirs: + os.rmdir(os.path.join(root, d)) + + +def set_watcher_tests(l): + byte_tests = (('bytes', True), ('unicode', False)) + + for btn, use_bytes in byte_tests: + def test_inotify_file_watcher(self, use_bytes=use_bytes): + try: + w = create_file_watcher(pl=get_fallback_logger(), watcher_type='inotify') + except INotifyError: + raise SkipTest('This test is not suitable for a stat based file watcher') + self.do_test_file_watcher(w, use_bytes) + + def test_uv_file_watcher(self, use_bytes=use_bytes): + raise SkipTest('Uv watcher tests are not stable') + try: + w = create_file_watcher(pl=get_fallback_logger(), watcher_type='uv') + except UvNotFound: + raise SkipTest('Pyuv is not available') + self.do_test_file_watcher(w, use_bytes) + + def test_inotify_tree_watcher(self, use_bytes=use_bytes): + try: + tw = create_tree_watcher(get_fallback_logger(), watcher_type='inotify') + except INotifyError: + raise SkipTest('INotify is not available') + self.do_test_tree_watcher(tw, use_bytes) + + def test_uv_tree_watcher(self, use_bytes=use_bytes): + raise SkipTest('Uv watcher tests are not stable') + try: + tw = create_tree_watcher(get_fallback_logger(), 'uv') + except UvNotFound: + raise SkipTest('Pyuv is not available') + self.do_test_tree_watcher(tw, use_bytes) + + def test_inotify_file_watcher_is_watching(self, use_bytes=use_bytes): + try: + w = create_file_watcher(pl=get_fallback_logger(), watcher_type='inotify') + except INotifyError: + raise SkipTest('INotify is not available') + self.do_test_file_watcher_is_watching(w, use_bytes) + + def test_stat_file_watcher_is_watching(self, use_bytes=use_bytes): + w = create_file_watcher(pl=get_fallback_logger(), watcher_type='stat') + self.do_test_file_watcher_is_watching(w, use_bytes) + + def test_uv_file_watcher_is_watching(self, use_bytes=use_bytes): + try: + w = create_file_watcher(pl=get_fallback_logger(), watcher_type='uv') + except UvNotFound: + raise SkipTest('Pyuv is not available') + self.do_test_file_watcher_is_watching(w, use_bytes) + + for wt in ('uv', 'inotify'): + l['test_{0}_file_watcher_{1}'.format(wt, btn)] = locals()['test_{0}_file_watcher'.format(wt)] + l['test_{0}_tree_watcher_{1}'.format(wt, btn)] = locals()['test_{0}_tree_watcher'.format(wt)] + l['test_{0}_file_watcher_is_watching_{1}'.format(wt, btn)] = ( + locals()['test_{0}_file_watcher_is_watching'.format(wt)]) + l['test_{0}_file_watcher_is_watching_{1}'.format('stat', btn)] = ( + locals()['test_{0}_file_watcher_is_watching'.format('stat')]) + + +class TestFilesystemWatchers(TestCase): + def do_test_for_change(self, watcher, path): + st = monotonic() + while monotonic() - st < 1: + if watcher(path): + return + sleep(0.1) + self.fail('The change to {0} was not detected'.format(path)) + + def do_test_file_watcher(self, w, use_bytes=False): + try: + f1, f2, f3 = map(lambda x: os.path.join(INOTIFY_DIR, 'file%d' % x), (1, 2, 3)) + ne = os.path.join(INOTIFY_DIR, 'notexists') + if use_bytes: + f1 = f1.encode('utf-8') + f2 = f2.encode('utf-8') + f3 = f3.encode('utf-8') + ne = ne.encode('utf-8') + with open(f1, 'wb'): + with open(f2, 'wb'): + with open(f3, 'wb'): + pass + self.assertRaises(OSError, w, ne) + self.assertTrue(w(f1)) + self.assertTrue(w(f2)) + os.utime(f1, None), os.utime(f2, None) + self.do_test_for_change(w, f1) + self.do_test_for_change(w, f2) + # Repeat once + os.utime(f1, None), os.utime(f2, None) + self.do_test_for_change(w, f1) + self.do_test_for_change(w, f2) + # Check that no false changes are reported + self.assertFalse(w(f1), 'Spurious change detected') + self.assertFalse(w(f2), 'Spurious change detected') + # Check that open the file with 'w' triggers a change + with open(f1, 'wb'): + with open(f2, 'wb'): + pass + self.do_test_for_change(w, f1) + self.do_test_for_change(w, f2) + # Check that writing to a file with 'a' triggers a change + with open(f1, 'ab') as f: + f.write(b'1') + self.do_test_for_change(w, f1) + # Check that deleting a file registers as a change + os.unlink(f1) + self.do_test_for_change(w, f1) + # Test that changing the inode of a file does not cause it to stop + # being watched + os.rename(f3, f2) + self.do_test_for_change(w, f2) + self.assertFalse(w(f2), 'Spurious change detected') + os.utime(f2, None) + self.do_test_for_change(w, f2) + finally: + clear_dir(INOTIFY_DIR) + + def do_test_tree_watcher(self, tw, use_bytes=False): + try: + inotify_dir = INOTIFY_DIR + subdir = os.path.join(inotify_dir, 'subdir') + t1 = os.path.join(inotify_dir, 'tree1') + ts1 = os.path.join(subdir, 'tree1') + suffix = '1' + f = os.path.join(subdir, 'f') + if use_bytes: + inotify_dir = inotify_dir.encode('utf-8') + subdir = subdir.encode('utf-8') + t1 = t1.encode('utf-8') + ts1 = ts1.encode('utf-8') + suffix = suffix.encode('utf-8') + f = f.encode('utf-8') + os.mkdir(subdir) + try: + if tw.watch(inotify_dir).is_dummy: + raise SkipTest('No tree watcher available') + except UvNotFound: + raise SkipTest('Pyuv is not available') + except INotifyError: + raise SkipTest('INotify is not available') + self.assertTrue(tw(inotify_dir)) + self.assertFalse(tw(inotify_dir)) + changed = partial(self.do_test_for_change, tw, inotify_dir) + open(t1, 'w').close() + changed() + open(ts1, 'w').close() + changed() + os.unlink(ts1) + changed() + os.rmdir(subdir) + changed() + os.mkdir(subdir) + changed() + os.rename(subdir, subdir + suffix) + changed() + shutil.rmtree(subdir + suffix) + changed() + os.mkdir(subdir) + open(f, 'w').close() + changed() + with open(f, 'a') as s: + s.write(' ') + changed() + os.rename(f, f + suffix) + changed() + finally: + clear_dir(inotify_dir) + + def do_test_file_watcher_is_watching(self, w, use_bytes=False): + try: + f1, f2, f3 = map(lambda x: os.path.join(INOTIFY_DIR, 'file%d' % x), (1, 2, 3)) + ne = os.path.join(INOTIFY_DIR, 'notexists') + if use_bytes: + f1 = f1.encode('utf-8') + f2 = f2.encode('utf-8') + f3 = f3.encode('utf-8') + ne = ne.encode('utf-8') + with open(f1, 'wb'): + with open(f2, 'wb'): + with open(f3, 'wb'): + pass + self.assertRaises(OSError, w, ne) + try: + w(ne) + except OSError as e: + self.assertEqual(e.errno, ENOENT) + self.assertTrue(w(f1)) + self.assertFalse(w.is_watching(ne)) + self.assertTrue(w.is_watching(f1)) + self.assertFalse(w.is_watching(f2)) + finally: + clear_dir(INOTIFY_DIR) + + set_watcher_tests(locals()) + + +old_cwd = None + + +def setUpModule(): + global old_cwd + old_cwd = os.getcwd() + os.chdir(os.path.dirname(os.path.dirname(__file__))) + os.mkdir(INOTIFY_DIR) + + +def tearDownModule(): + shutil.rmtree(INOTIFY_DIR) + os.chdir(old_cwd) + + +if __name__ == '__main__': + from tests.modules import main + main() diff --git a/tests/test_shells/bgscript.sh b/tests/test_shells/bgscript.sh new file mode 100755 index 0000000..71886e6 --- /dev/null +++ b/tests/test_shells/bgscript.sh @@ -0,0 +1,5 @@ +#!/bin/sh +echo $$ > pid +while true ; do + sleep 0.1s +done diff --git a/tests/test_shells/inputs/bash b/tests/test_shells/inputs/bash new file mode 100644 index 0000000..1b68b6f --- /dev/null +++ b/tests/test_shells/inputs/bash @@ -0,0 +1,69 @@ +set_theme_option() { + export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2" +} +set_theme() { + export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1" +} +set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false +ABOVE_LEFT='[{ + "left": [ + { + "function": "powerline.segments.common.env.environment", + "args": {"variable": "DISPLAYED_ENV_VAR"} + } + ] +}]' +ABOVE_FULL='[{ + "left": [ + { + "type": "string", + "name": "background", + "draw_hard_divider": false, + "width": "auto" + } + ], + "right": [ + { + "function": "powerline.segments.common.env.environment", + "args": {"variable": "DISPLAYED_ENV_VAR"} + } + ] +}]' +set_theme default_leftonly +export VIRTUAL_ENV= +source powerline/bindings/bash/powerline.sh +cd "$TEST_ROOT"/3rd +cd .git +cd .. +VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" +VIRTUAL_ENV= +bgscript.sh & waitpid.sh +false +kill `cat pid` ; sleep 1s +set_theme_option default_leftonly.segment_data.hostname.display false +set_theme_option default_leftonly.segment_data.user.display false +echo ' +abc +def +' +cd "$DIR1" +cd ../"$DIR2" +cd ../'\[\]' +cd ../'%%' +cd ../'#[bold]' +cd ../'(echo)' +cd ../'$(echo)' +cd ../'`echo`' +cd ../'«Unicode!»' +(exit 42)|(exit 43) +set_theme_option default_leftonly.segments.above "$ABOVE_LEFT" +export DISPLAYED_ENV_VAR=foo +unset DISPLAYED_ENV_VAR +set_theme_option default_leftonly.segments.above "$ABOVE_FULL" +export DISPLAYED_ENV_VAR=foo +unset DISPLAYED_ENV_VAR +set_theme_option default_leftonly.segments.above +set_theme_option default_leftonly.dividers.left.hard \$ABC +false +true is the last line +exit diff --git a/tests/test_shells/inputs/busybox b/tests/test_shells/inputs/busybox new file mode 100644 index 0000000..5d1495a --- /dev/null +++ b/tests/test_shells/inputs/busybox @@ -0,0 +1,37 @@ +set_theme_option() { + export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2" +} +set_theme() { + export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1" +} +set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false +set_theme default_leftonly +. powerline/bindings/shell/powerline.sh +export VIRTUAL_ENV= +cd "$TEST_ROOT"/3rd +cd .git +cd .. +VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" +VIRTUAL_ENV= +bgscript.sh & waitpid.sh +false +kill `cat pid` ; sleep 1s +set_theme_option default_leftonly.segment_data.hostname.display false +set_theme_option default_leftonly.segment_data.user.display false +echo ' +abc +def +' +cd "$DIR1" +cd ../"$DIR2" +cd ../'\[\]' +cd ../'%%' +cd ../'#[bold]' +cd ../'(echo)' +cd ../'$(echo)' +cd ../'`echo`' +cd ../'«Unicode!»' +set_theme_option default_leftonly.dividers.left.hard \$ABC +false +true is the last line +exit diff --git a/tests/test_shells/inputs/dash b/tests/test_shells/inputs/dash new file mode 100644 index 0000000..5d1495a --- /dev/null +++ b/tests/test_shells/inputs/dash @@ -0,0 +1,37 @@ +set_theme_option() { + export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2" +} +set_theme() { + export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1" +} +set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false +set_theme default_leftonly +. powerline/bindings/shell/powerline.sh +export VIRTUAL_ENV= +cd "$TEST_ROOT"/3rd +cd .git +cd .. +VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" +VIRTUAL_ENV= +bgscript.sh & waitpid.sh +false +kill `cat pid` ; sleep 1s +set_theme_option default_leftonly.segment_data.hostname.display false +set_theme_option default_leftonly.segment_data.user.display false +echo ' +abc +def +' +cd "$DIR1" +cd ../"$DIR2" +cd ../'\[\]' +cd ../'%%' +cd ../'#[bold]' +cd ../'(echo)' +cd ../'$(echo)' +cd ../'`echo`' +cd ../'«Unicode!»' +set_theme_option default_leftonly.dividers.left.hard \$ABC +false +true is the last line +exit diff --git a/tests/test_shells/inputs/fish b/tests/test_shells/inputs/fish new file mode 100644 index 0000000..9a20613 --- /dev/null +++ b/tests/test_shells/inputs/fish @@ -0,0 +1,69 @@ +function set_theme_option + set -g -x POWERLINE_THEME_OVERRIDES "$POWERLINE_THEME_OVERRIDES;$argv[1]=$argv[2]" +end +function set_theme + set -g -x POWERLINE_CONFIG_OVERRIDES "ext.shell.theme=$argv" +end +set -g -x POWERLINE_ +set -g ABOVE_LEFT '[{ + "left": [ + { + "function": "powerline.segments.common.env.environment", + "args": {"variable": "DISPLAYED_ENV_VAR"} + } + ] +}]' +set -g ABOVE_FULL '[{ + "left": [ + { + "type": "string", + "name": "background", + "draw_hard_divider": false, + "width": "auto" + } + ], + "right": [ + { + "function": "powerline.segments.common.env.environment", + "args": {"variable": "DISPLAYED_ENV_VAR"} + } + ] +}]' +set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false +set_theme default_leftonly +set fish_function_path "$PWD/powerline/bindings/fish" $fish_function_path +while jobs | grep fish_update_completions + sleep 1 +end +powerline-setup +setenv VIRTUAL_ENV +cd "$TEST_ROOT"/3rd +cd .git +cd .. +setenv VIRTUAL_ENV "$HOME/.virtenvs/some-virtual-environment" +setenv VIRTUAL_ENV +bgscript.sh & waitpid.sh +false +kill (cat pid) ; sleep 1s +cd "$DIR1" +cd ../"$DIR2" +cd ../'\[\]' +cd ../'%%' +cd ../'#[bold]' +cd ../'(echo)' +cd ../'$(echo)' +cd ../'`echo`' +cd ../'«Unicode!»' +set_theme default +set_theme_option default.segments.above "$ABOVE_LEFT" +set -g -x DISPLAYED_ENV_VAR foo +set -g -x -e DISPLAYED_ENV_VAR +set_theme_option default.segments.above "$ABOVE_FULL" +set -g -x DISPLAYED_ENV_VAR foo +set -g -x -e DISPLAYED_ENV_VAR +set_theme_option default.segments.above '' +set -g fish_key_bindings fish_vi_key_bindings +ii +false +true is the last line +exit diff --git a/tests/test_shells/inputs/ipython b/tests/test_shells/inputs/ipython new file mode 100644 index 0000000..257cba6 --- /dev/null +++ b/tests/test_shells/inputs/ipython @@ -0,0 +1,7 @@ +print ('cd ' + '"$TEST_ROOT"/3rd') # Start of the test marker +bool 42 +bool 44 +class Test(object): +pass + +exit diff --git a/tests/test_shells/inputs/mksh b/tests/test_shells/inputs/mksh new file mode 100644 index 0000000..ca45783 --- /dev/null +++ b/tests/test_shells/inputs/mksh @@ -0,0 +1,38 @@ +set_theme_option() { + export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2" +} +set_theme() { + export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1" +} +set_theme default_leftonly +set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false +. powerline/bindings/shell/powerline.sh +export VIRTUAL_ENV= +cd "$TEST_ROOT"/3rd +cd .git +cd .. +VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" +VIRTUAL_ENV= +bgscript.sh & waitpid.sh +false +kill `cat pid` ; sleep 1 +set_theme_option default_leftonly.segment_data.hostname.display false +set_theme_option default_leftonly.segment_data.user.display false +echo -n +echo ' +abc +def +' +cd "$DIR1" +cd ../"$DIR2" +cd ../'\[\]' +cd ../'%%' +cd ../'#[bold]' +cd ../'(echo)' +cd ../'$(echo)' +cd ../'`echo`' +cd ../'«Unicode!»' +set_theme_option default_leftonly.dividers.left.hard \$ABC +false +true is the last line +exit diff --git a/tests/test_shells/inputs/pdb b/tests/test_shells/inputs/pdb new file mode 100644 index 0000000..e9ac498 --- /dev/null +++ b/tests/test_shells/inputs/pdb @@ -0,0 +1,89 @@ +s + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_shells/inputs/rc b/tests/test_shells/inputs/rc new file mode 100644 index 0000000..c88bcf9 --- /dev/null +++ b/tests/test_shells/inputs/rc @@ -0,0 +1,33 @@ +fn set_theme_option { + POWERLINE_THEME_OVERRIDES = $POWERLINE_THEME_OVERRIDES';'$1'='$2 +} +set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false +POWERLINE_CONFIG_OVERRIDES = 'ext.shell.theme=default_leftonly' +. powerline/bindings/rc/powerline.rc +VIRTUAL_ENV = () +cd $TEST_ROOT/3rd +true cd "$TEST_ROOT"/3rd # Test start marker +cd .git +cd .. +VIRTUAL_ENV = '/home/foo/.virtenvs/some-virtual-environment' +VIRTUAL_ENV = () +bgscript.sh & waitpid.sh +false +kill `{cat pid} ; sleep 1s +cd $DIR1 +cd ../$DIR2 +cd ../'\[\]' +cd ../'%%' +cd ../'#[bold]' +cd ../'(echo)' +cd ../'$(echo)' +cd ../'`echo`' +cd ../'«Unicode!»' +false +set_theme_option default_leftonly.segment_data.hostname.display false +set_theme_option default_leftonly.segment_data.user.display false +echo `{ + echo Continuation! +} +true is the last line +exit diff --git a/tests/test_shells/inputs/tcsh b/tests/test_shells/inputs/tcsh new file mode 100644 index 0000000..c7d722a --- /dev/null +++ b/tests/test_shells/inputs/tcsh @@ -0,0 +1,24 @@ +setenv POWERLINE_THEME_OVERRIDES "default_leftonly.segment_data.hostname.args.only_if_ssh=false" +setenv POWERLINE_CONFIG_OVERRIDES "ext.shell.theme=default_leftonly" +source powerline/bindings/tcsh/powerline.tcsh +unsetenv VIRTUAL_ENV +cd "$TEST_ROOT"/3rd +cd .git +cd .. +setenv VIRTUAL_ENV "/home/foo/.virtenvs/some-virtual-environment" +unsetenv VIRTUAL_ENV +bgscript.sh & waitpid.sh +false # Warning: currently tcsh bindings do not support job count +kill `cat pid` ; sleep 1s +cd $DIR1:q +cd ../$DIR2:q +cd ../'\[\]' +cd ../'%%' +cd ../'#[bold]' +cd ../'(echo)' +cd ../'$(echo)' +cd ../'`echo`' +cd ../'«Unicode\!»' +false +true is the last line +exit diff --git a/tests/test_shells/inputs/zsh b/tests/test_shells/inputs/zsh new file mode 100644 index 0000000..811684e --- /dev/null +++ b/tests/test_shells/inputs/zsh @@ -0,0 +1,90 @@ +unset HOME +unsetopt promptsp notransientrprompt +setopt interactivecomments +setopt autonamedirs +setopt warncreateglobal +function set_theme_option() { + export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2" + powerline-reload-config +} +function set_theme() { + export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1" + powerline-reload-config +} +if test -n "$POWERLINE_NO_ZSH_ZPYTHON" ; then + powerline-reload-config(): +fi +source powerline/bindings/zsh/powerline.zsh +set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false +set_theme_option default.segment_data.hostname.args.only_if_ssh false +ABOVE_LEFT='[{ + "left": [ + { + "function": "powerline.segments.common.env.environment", + "args": {"variable": "DISPLAYED_ENV_VAR"} + } + ] +}]' +ABOVE_FULL='[{ + "left": [ + { + "type": "string", + "name": "background", + "draw_hard_divider": false, + "width": "auto" + } + ], + "right": [ + { + "function": "powerline.segments.common.env.environment", + "args": {"variable": "DISPLAYED_ENV_VAR"} + } + ] +}]' +set_theme default_leftonly +export VIRTUAL_ENV= +cd "$TEST_ROOT"/3rd +cd .git +cd .. +VIRTUAL_ENV="/home/USER/.virtenvs/some-virtual-environment" +VIRTUAL_ENV= +bgscript.sh & waitpid.sh +false +kill `cat pid` ; sleep 1s +cd "$DIR1" +cd ../"$DIR2" +cd ../'\[\]' +cd ../'%%' +cd ../'#[bold]' +cd ../'(echo)' +cd ../'$(echo)' +cd ../'`echo`' +cd ../'«Unicode!»' +cd .. +bindkey -v ; set_theme default + + +echo abc +false +set_theme_option default.segment_data.hostname.display false +set_theme_option default.segment_data.user.display false +select abc in def ghi jkl +do + echo $abc + break +done +1 +cd . +cd . +set_theme_option default.segments.above "$ABOVE_LEFT" +export DISPLAYED_ENV_VAR=foo +unset DISPLAYED_ENV_VAR +set_theme_option default.segments.above "$ABOVE_FULL" +export DISPLAYED_ENV_VAR=foo +unset DISPLAYED_ENV_VAR +set_theme_option default.segments.above +hash -d foo=$PWD:h ; cd . +set_theme_option default.dividers.left.hard \$ABC +true +true is the last line +exit diff --git a/tests/test_shells/ipython_home/profile_default/ipython_config.py b/tests/test_shells/ipython_home/profile_default/ipython_config.py new file mode 100644 index 0000000..ffb5865 --- /dev/null +++ b/tests/test_shells/ipython_home/profile_default/ipython_config.py @@ -0,0 +1,22 @@ +from powerline.bindings.ipython.since_7 import PowerlinePrompts +import os +c = get_config() +c.TerminalInteractiveShell.simple_prompt = False +c.TerminalIPythonApp.display_banner = False +c.TerminalInteractiveShell.prompts_class = PowerlinePrompts +c.TerminalInteractiveShell.autocall = 1 +c.Powerline.config_paths = [os.path.abspath('powerline/config_files')] +c.Powerline.theme_overrides = { + 'in': { + 'segment_data': { + 'virtualenv': { + 'display': False + } + } + } +} +c.Powerline.config_overrides = { + 'common': { + 'default_top_theme': 'ascii' + } +} diff --git a/tests/test_shells/outputs/bash.daemon.ok b/tests/test_shells/outputs/bash.daemon.ok new file mode 100644 index 0000000..89907c8 --- /dev/null +++ b/tests/test_shells/outputs/bash.daemon.ok @@ -0,0 +1,42 @@ +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd .git +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m.git [0;38;5;240;49;22m [0mcd .. +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;74;22m [0;38;5;231;48;5;74m(e) some-virtual-environment [0;38;5;74;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV= +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mbgscript.sh & waitpid.sh +[1] PID +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0mfalse +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m [0mkill `cat pid` ; sleep 1s +[1]+ Terminated bgscript.sh +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segment_data.hostname.display false +[0;38;5;231;48;5;31;1m USER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segment_data.user.display false +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mecho ' +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0mabc +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0mdef +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0m' + +abc +def + +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd "$DIR1" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^[[32m [0;38;5;240;49;22m [0mcd ../"$DIR2" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^H [0;38;5;240;49;22m [0mcd ../'\[\]' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m\[\] [0;38;5;240;49;22m [0mcd ../'%%' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m%% [0;38;5;240;49;22m [0mcd ../'#[bold]' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m#[bold] [0;38;5;240;49;22m [0mcd ../'(echo)' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m(echo) [0;38;5;240;49;22m [0mcd ../'$(echo)' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m$(echo) [0;38;5;240;49;22m [0mcd ../'`echo`' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m`echo` [0;38;5;240;49;22m [0mcd ../'«Unicode!»' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0m(exit 42)|(exit 43) +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;48;5;52;22m [0;38;5;231;48;5;52m42 [0;38;5;231;48;5;52;22m [0;38;5;231;48;5;52m43 [0;38;5;52;49;22m [0mset_theme_option default_leftonly.segments.above "$ABOVE_LEFT" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mexport DISPLAYED_ENV_VAR=foo +[0;38;5;231;48;5;22m foo [0;38;5;22;49;22m [0m +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0munset DISPLAYED_ENV_VAR +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segments.above "$ABOVE_FULL" +[0;38;5;231;48;5;233m [0m +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mexport DISPLAYED_ENV_VAR=foo +[0;38;5;231;48;5;233m [0;38;5;22;48;5;233;22m [0;38;5;231;48;5;22m foo [0m +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0munset DISPLAYED_ENV_VAR +[0;38;5;231;48;5;233m [0m +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segments.above +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mset_theme_option default_leftonly.dividers.left.hard \$ABC +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m$ABC[0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m$ABC[0mfalse diff --git a/tests/test_shells/outputs/bash.nodaemon.ok b/tests/test_shells/outputs/bash.nodaemon.ok new file mode 100644 index 0000000..c65dcc1 --- /dev/null +++ b/tests/test_shells/outputs/bash.nodaemon.ok @@ -0,0 +1,42 @@ +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd .git +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m.git [0;38;5;240;49;22m [0mcd .. +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;74;22m [0;38;5;231;48;5;74m(e) some-virtual-environment [0;38;5;74;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV= +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mbgscript.sh & waitpid.sh +[1] PID +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0mfalse +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m [0mkill `cat pid` ; sleep 1s +[1]+ Terminated bgscript.sh +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segment_data.hostname.display false +[0;38;5;231;48;5;31;1m USER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segment_data.user.display false +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mecho ' +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0mabc +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0mdef +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0m' + +abc +def + +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd "$DIR1" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^[[32m [0;38;5;240;49;22m [0mcd ../"$DIR2" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^H [0;38;5;240;49;22m [0mcd ../'\[\]' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m\[\] [0;38;5;240;49;22m [0mcd ../'%%' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m%% [0;38;5;240;49;22m [0mcd ../'#[bold]' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m#[bold] [0;38;5;240;49;22m [0mcd ../'(echo)' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m(echo) [0;38;5;240;49;22m [0mcd ../'$(echo)' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m$(echo) [0;38;5;240;49;22m [0mcd ../'`echo`' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m`echo` [0;38;5;240;49;22m [0mcd ../'«Unicode!»' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0m(exit 42)|(exit 43) +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;48;5;52;22m [0;38;5;231;48;5;52m42 [0;38;5;231;48;5;52;22m [0;38;5;231;48;5;52m43 [0;38;5;52;49;22m [0mset_theme_option default_leftonly.segments.above "$ABOVE_LEFT" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mexport DISPLAYED_ENV_VAR=foo +[0;38;5;231;48;5;22m foo [0;38;5;22;49;22m [0m +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0munset DISPLAYED_ENV_VAR +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segments.above "$ABOVE_FULL" +[0;38;5;231;48;5;233m [0m +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mexport DISPLAYED_ENV_VAR=foo +[0;38;5;231;48;5;233m [0;38;5;22;48;5;233;22m [0;38;5;231;48;5;22m foo [0m +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0munset DISPLAYED_ENV_VAR +[0;38;5;231;48;5;233m [0m +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segments.above +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mset_theme_option default_leftonly.dividers.left.hard \$ABC +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m$ABC[0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m$ABC[0mfalse diff --git a/tests/test_shells/outputs/busybox.daemon.ok b/tests/test_shells/outputs/busybox.daemon.ok new file mode 100644 index 0000000..446d88e --- /dev/null +++ b/tests/test_shells/outputs/busybox.daemon.ok @@ -0,0 +1,29 @@ +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd .git +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m.git [0;38;5;240;49;22m [0mcd .. +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;74;22m [0;38;5;231;48;5;74m(e) some-virtual-environment [0;38;5;74;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV= +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mbgscript.sh & waitpid.sh +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0mfalse +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m [0mkill `cat pid` ; sleep 1s +[1]+ Terminated bgscript.sh +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0mset_theme_option default_leftonly.segment_data.hostname.display false +[0;38;5;231;48;5;31;1m USER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segment_data.user.display false +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mecho ' +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0mabc +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0mdef +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0m' + +abc +def + +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd "$DIR1" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^[[32m [0;38;5;240;49;22m [0mcd ../"$DIR2" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^H [0;38;5;240;49;22m [0mcd ../'\[\]' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m\[\] [0;38;5;240;49;22m [0mcd ../'%%' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m%% [0;38;5;240;49;22m [0mcd ../'#[bold]' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m#[bold] [0;38;5;240;49;22m [0mcd ../'(echo)' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m(echo) [0;38;5;240;49;22m [0mcd ../'$(echo)' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m$(echo) [0;38;5;240;49;22m [0mcd ../'`echo`' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m`echo` [0;38;5;240;49;22m [0mcd ../'«Unicode!»' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mset_theme_option default_leftonly.dividers.left.hard \$ABC +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m$ABC[0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m$ABC[0mfalse diff --git a/tests/test_shells/outputs/busybox.nodaemon.ok b/tests/test_shells/outputs/busybox.nodaemon.ok new file mode 100644 index 0000000..afda9a5 --- /dev/null +++ b/tests/test_shells/outputs/busybox.nodaemon.ok @@ -0,0 +1,29 @@ +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd .git +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m.git [0;38;5;240;49;22m [0mcd .. +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;74;22m [0;38;5;231;48;5;74m(e) some-virtual-environment [0;38;5;74;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV= +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mbgscript.sh & waitpid.sh +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0mfalse +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m [0mkill `cat pid` ; sleep 1s +[1]+ Terminated bgscript.sh +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0mset_theme_option default_leftonly.segment_data.hostname.display false +[0;38;5;231;48;5;31;1m USER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segment_data.user.display false +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mecho ' +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0mabc +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0mdef +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0m' + +abc +def + +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd "$DIR1" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^[[32m [0;38;5;240;49;22m [0mcd ../"$DIR2" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^H [0;38;5;240;49;22m [0mcd ../'\[\]' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m\[\] [0;38;5;240;49;22m [0mcd ../'%%' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m%% [0;38;5;240;49;22m [0mcd ../'#[bold]' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m#[bold] [0;38;5;240;49;22m [0mcd ../'(echo)' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m(echo) [0;38;5;240;49;22m [0mcd ../'$(echo)' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m$(echo) [0;38;5;240;49;22m [0mcd ../'`echo`' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m`echo` [0;38;5;240;49;22m [0mcd ../'«Unicode!»' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mset_theme_option default_leftonly.dividers.left.hard \$ABC +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m$ABC[0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m$ABC[0mfalse diff --git a/tests/test_shells/outputs/dash.daemon.ok b/tests/test_shells/outputs/dash.daemon.ok new file mode 100644 index 0000000..71ca500 --- /dev/null +++ b/tests/test_shells/outputs/dash.daemon.ok @@ -0,0 +1,28 @@ +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd .git +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m.git [0;38;5;240;49;22m [0mcd .. +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;74;22m [0;38;5;231;48;5;74m(e) some-virtual-environment [0;38;5;74;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV= +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mbgscript.sh & waitpid.sh +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0mfalse +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m [0mkill `cat pid` ; sleep 1s +set_theme_option default_leftonly.segment_data.hostname.display false +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0m[0;38;5;231;48;5;31;1m USER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segment_data.user.display false +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mecho ' +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0mabc +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0mdef +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0m' + +abc +def + +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd "$DIR1" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^[[32m [0;38;5;240;49;22m [0mcd ../"$DIR2" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^H [0;38;5;240;49;22m [0mcd ../'\[\]' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m\[\] [0;38;5;240;49;22m [0mcd ../'%%' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m%% [0;38;5;240;49;22m [0mcd ../'#[bold]' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m#[bold] [0;38;5;240;49;22m [0mcd ../'(echo)' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m(echo) [0;38;5;240;49;22m [0mcd ../'$(echo)' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m$(echo) [0;38;5;240;49;22m [0mcd ../'`echo`' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m`echo` [0;38;5;240;49;22m [0mcd ../'«Unicode!»' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mset_theme_option default_leftonly.dividers.left.hard \$ABC +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m$ABC[0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m$ABC[0mfalse diff --git a/tests/test_shells/outputs/dash.nodaemon.ok b/tests/test_shells/outputs/dash.nodaemon.ok new file mode 100644 index 0000000..c289cd2 --- /dev/null +++ b/tests/test_shells/outputs/dash.nodaemon.ok @@ -0,0 +1,28 @@ +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd .git +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m.git [0;38;5;240;49;22m [0mcd .. +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;74;22m [0;38;5;231;48;5;74m(e) some-virtual-environment [0;38;5;74;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV= +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mbgscript.sh & waitpid.sh +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0mfalse +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m [0mkill `cat pid` ; sleep 1s +set_theme_option default_leftonly.segment_data.hostname.display false +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0m[0;38;5;231;48;5;31;1m USER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segment_data.user.display false +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mecho ' +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0mabc +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0mdef +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0m' + +abc +def + +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd "$DIR1" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^[[32m [0;38;5;240;49;22m [0mcd ../"$DIR2" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^H [0;38;5;240;49;22m [0mcd ../'\[\]' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m\[\] [0;38;5;240;49;22m [0mcd ../'%%' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m%% [0;38;5;240;49;22m [0mcd ../'#[bold]' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m#[bold] [0;38;5;240;49;22m [0mcd ../'(echo)' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m(echo) [0;38;5;240;49;22m [0mcd ../'$(echo)' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m$(echo) [0;38;5;240;49;22m [0mcd ../'`echo`' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m`echo` [0;38;5;240;49;22m [0mcd ../'«Unicode!»' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mset_theme_option default_leftonly.dividers.left.hard \$ABC +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m$ABC[0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m$ABC[0mfalse diff --git a/tests/test_shells/outputs/fish.ok b/tests/test_shells/outputs/fish.ok new file mode 100644 index 0000000..4d208bb --- /dev/null +++ b/tests/test_shells/outputs/fish.ok @@ -0,0 +1,52 @@ +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m.git [0;38;5;240;49;22m [0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;74;22m [0;38;5;231;48;5;74m(e) some-virtual-environment [0;38;5;74;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m [0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^[[32m [0;38;5;240;49;22m [0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^H [0;38;5;240;49;22m [0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m\[\] [0;38;5;240;49;22m [0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m%% [0;38;5;240;49;22m [0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m#[bold] [0;38;5;240;49;22m [0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m(echo) [0;38;5;240;49;22m [0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m$(echo) [0;38;5;240;49;22m [0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m`echo` [0;38;5;240;49;22m [0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0m +[0;38;5;231;48;5;31;1m USER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;231;48;5;31;1m USER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;231;48;5;22m foo [0;38;5;22;49;22m [0m +[0;38;5;231;48;5;31;1m USER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;231;48;5;233m [0m +[0;38;5;231;48;5;233m [0;38;5;22;48;5;233;22m [0;38;5;231;48;5;22m foo [0m +[0;38;5;231;48;5;233m [0m +[0;38;5;231;48;5;31;1m USER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;22;48;5;148;1m DEFAULT [0;38;5;148;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;22;48;5;148;1m DEFAULT [0;38;5;148;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m +[0;38;5;236;49;22m [0;38;5;250;48;5;236m BRANCH [0m diff --git a/tests/test_shells/outputs/ipython.ok b/tests/test_shells/outputs/ipython.ok new file mode 100644 index 0000000..166604d --- /dev/null +++ b/tests/test_shells/outputs/ipython.ok @@ -0,0 +1,14 @@ + +[0;38;5;250;48;5;240m In [[0;38;5;231;48;5;240m2[0;38;5;250;48;5;240m] [0;38;5;240;49;22m [0mbool 42 +[0;38;5;250;48;5;240m [0;38;5;231;48;5;240m2[0;38;5;250;48;5;240m> [0;38;5;240;49;22m [0mbool(42) +[0;38;5;250;48;5;240m Out[[0;38;5;231;48;5;240m2[0;38;5;250;48;5;240m] [0;38;5;240;49;22m [0mTrue + +[0;38;5;250;48;5;240m In [[0;38;5;231;48;5;240m3[0;38;5;250;48;5;240m] [0;38;5;240;49;22m [0mbool 44 +[0;38;5;250;48;5;240m [0;38;5;231;48;5;240m3[0;38;5;250;48;5;240m> [0;38;5;240;49;22m [0mbool(44) +[0;38;5;250;48;5;240m Out[[0;38;5;231;48;5;240m3[0;38;5;250;48;5;240m] [0;38;5;240;49;22m [0mTrue + +[0;38;5;250;48;5;240m In [[0;38;5;231;48;5;240m4[0;38;5;250;48;5;240m] [0;38;5;240;49;22m [0mclass Test(object): +[0;38;5;250;48;5;240m [0;38;5;240;49;22m [0m pass +[0;38;5;250;48;5;240m [0;38;5;240;49;22m [0m + +[0;38;5;250;48;5;240m In [[0;38;5;231;48;5;240m5[0;38;5;250;48;5;240m] [0;38;5;240;49;22m [0mexit diff --git a/tests/test_shells/outputs/mksh.daemon.ok b/tests/test_shells/outputs/mksh.daemon.ok new file mode 100644 index 0000000..264dff8 --- /dev/null +++ b/tests/test_shells/outputs/mksh.daemon.ok @@ -0,0 +1,32 @@ + +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd .git +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m.git [0;38;5;240;49;22m [0mcd .. +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;74;22m [0;38;5;231;48;5;74m(e) some-virtual-environment [0;38;5;74;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV= +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mbgscript.sh & waitpid.sh +[1] PID +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0mfalse +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m [0mkill `cat pid` ; sleep 1 +[1] + Terminated bash -c ... +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segment_data.hostname.display false +[0;38;5;231;48;5;31;1m USER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segment_data.user.display false +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mecho -n +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mecho ' +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0mabc +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0mdef +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0m' + +abc +def + +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd "$DIR1" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^[[32m [0;38;5;240;49;22m [0mcd ../"$DIR2" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^H [0;38;5;240;49;22m [0mcd ../'\[\]' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m\[\] [0;38;5;240;49;22m [0mcd ../'%%' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m%% [0;38;5;240;49;22m [0mcd ../'#[bold]' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m#[bold] [0;38;5;240;49;22m [0mcd ../'(echo)' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m(echo) [0;38;5;240;49;22m [0mcd ../'$(echo)' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m$(echo) [0;38;5;240;49;22m [0mcd ../'`echo`' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m`echo` [0;38;5;240;49;22m [0mcd ../'«Unicode!»' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mset_theme_option default_leftonly.dividers.left.hard \$ABC +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m$ABC[0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m$ABC[0mfalse diff --git a/tests/test_shells/outputs/mksh.nodaemon.ok b/tests/test_shells/outputs/mksh.nodaemon.ok new file mode 100644 index 0000000..d8d9d70 --- /dev/null +++ b/tests/test_shells/outputs/mksh.nodaemon.ok @@ -0,0 +1,32 @@ + +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd .git +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m.git [0;38;5;240;49;22m [0mcd .. +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;74;22m [0;38;5;231;48;5;74m(e) some-virtual-environment [0;38;5;74;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV= +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mbgscript.sh & waitpid.sh +[1] PID +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0mfalse +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m [0mkill `cat pid` ; sleep 1 +[1] + Terminated bash -c ... +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segment_data.hostname.display false +[0;38;5;231;48;5;31;1m USER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segment_data.user.display false +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mecho -n +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mecho ' +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0mabc +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0mdef +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0m' + +abc +def + +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd "$DIR1" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^[[32m [0;38;5;240;49;22m [0mcd ../"$DIR2" +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^H [0;38;5;240;49;22m [0mcd ../'\[\]' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m\[\] [0;38;5;240;49;22m [0mcd ../'%%' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m%% [0;38;5;240;49;22m [0mcd ../'#[bold]' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m#[bold] [0;38;5;240;49;22m [0mcd ../'(echo)' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m(echo) [0;38;5;240;49;22m [0mcd ../'$(echo)' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m$(echo) [0;38;5;240;49;22m [0mcd ../'`echo`' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m`echo` [0;38;5;240;49;22m [0mcd ../'«Unicode!»' +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mset_theme_option default_leftonly.dividers.left.hard \$ABC +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m$ABC[0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m$ABC[0mfalse diff --git a/tests/test_shells/outputs/pdb.module.ok b/tests/test_shells/outputs/pdb.module.ok new file mode 100644 index 0000000..7554dd6 --- /dev/null +++ b/tests/test_shells/outputs/pdb.module.ok @@ -0,0 +1,222 @@ +[0;38;5;235;48;5;252;1m 1 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> class Foo(object): +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240mFoo [0;38;5;240;49;22m [0m +-> class Foo(object): +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240mFoo [0;38;5;240;49;22m [0m +-> def __init__(self): +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m7 [0;38;5;250;48;5;240mFoo [0;38;5;240;49;22m [0m +-> @classmethod +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m13 [0;38;5;250;48;5;240mFoo [0;38;5;240;49;22m [0m +-> @staticmethod +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m17 [0;38;5;250;48;5;240mFoo [0;38;5;240;49;22m [0m +-> def bra(self): +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m21 [0;38;5;250;48;5;240mFoo [0;38;5;240;49;22m [0m +--Return-- +-> def bra(self): +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m21 [0;38;5;250;48;5;240mFoo [0;38;5;240;49;22m [0m +-> def brah(): +[0;38;5;235;48;5;252;1m 1 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m25 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +-> f = Foo() +[0;38;5;235;48;5;252;1m 1 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> def __init__(self): +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m7 [0;38;5;250;48;5;240m__init__ [0;38;5;240;49;22m [0m +-> nop('__init__') +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m8 [0;38;5;250;48;5;240m__init__ [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m8 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m8 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m8 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> self.bar() +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m9 [0;38;5;250;48;5;240m__init__ [0;38;5;240;49;22m [0m +--Call-- +-> @classmethod +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m9 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m13 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +-> nop(cls.__name__) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m9 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m9 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m9 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m9 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(cls.__name__) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m9 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +-> self.baz() +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m10 [0;38;5;250;48;5;240m__init__ [0;38;5;240;49;22m [0m +--Call-- +-> @staticmethod +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m10 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m17 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +-> nop(1) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m10 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m10 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m10 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m10 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(1) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m10 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +-> self.bra() +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m11 [0;38;5;250;48;5;240m__init__ [0;38;5;240;49;22m [0m +--Call-- +-> def bra(self): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m11 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m21 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +-> nop(self.__class__.__name__) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m11 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m11 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m11 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m11 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(self.__class__.__name__) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m11 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +--Return-- +-> self.bra() +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m11 [0;38;5;250;48;5;240m__init__ [0;38;5;240;49;22m [0m +-> Foo.bar() +[0;38;5;235;48;5;252;1m 1 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m30 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> @classmethod +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m30 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m13 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +-> nop(cls.__name__) +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m30 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m30 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m30 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m30 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(cls.__name__) +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m30 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +-> Foo.baz() +[0;38;5;235;48;5;252;1m 1 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m31 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> @staticmethod +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m31 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m17 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +-> nop(1) +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m31 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m31 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m31 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m31 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(1) +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m31 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +-> Foo.bra(f) +[0;38;5;235;48;5;252;1m 1 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m32 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> def bra(self): +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m32 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m21 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +-> nop(self.__class__.__name__) +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m32 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m32 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m32 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m32 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(self.__class__.__name__) +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m32 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +-> f.bar() +[0;38;5;235;48;5;252;1m 1 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m34 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> @classmethod +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m34 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m13 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +-> nop(cls.__name__) +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m34 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m34 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m34 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m34 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(cls.__name__) +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m34 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +-> f.baz() +[0;38;5;235;48;5;252;1m 1 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m35 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> @staticmethod +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m35 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m17 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +-> nop(1) +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m35 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m35 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m35 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m35 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(1) +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m35 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +-> f.bra() +[0;38;5;235;48;5;252;1m 1 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m36 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> def bra(self): +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m36 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m21 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +-> nop(self.__class__.__name__) +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m36 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m36 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m36 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m36 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(self.__class__.__name__) +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m36 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +-> brah() +[0;38;5;235;48;5;252;1m 1 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m38 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> def brah(): +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m38 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m25 [0;38;5;250;48;5;240mbrah [0;38;5;240;49;22m [0m +-> nop('brah') +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m38 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m26 [0;38;5;250;48;5;240mbrah [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m38 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m26 [0;38;5;250;48;5;240mbrah [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m38 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m26 [0;38;5;250;48;5;240mbrah [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m38 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m26 [0;38;5;250;48;5;240mbrah [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop('brah') +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m38 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m26 [0;38;5;250;48;5;240mbrah [0;38;5;240;49;22m [0m +--Return-- +-> brah() +[0;38;5;235;48;5;252;1m 1 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m38 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Return-- +[0;38;5;235;48;5;252;1m 0 [0;38;5;252;49;22m [0m diff --git a/tests/test_shells/outputs/pdb.subclass.ok b/tests/test_shells/outputs/pdb.subclass.ok new file mode 100644 index 0000000..d8eba5e --- /dev/null +++ b/tests/test_shells/outputs/pdb.subclass.ok @@ -0,0 +1,217 @@ +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> class Foo(object): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240mFoo [0;38;5;240;49;22m [0m +-> class Foo(object): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240mFoo [0;38;5;240;49;22m [0m +-> def __init__(self): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m7 [0;38;5;250;48;5;240mFoo [0;38;5;240;49;22m [0m +-> @classmethod +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m13 [0;38;5;250;48;5;240mFoo [0;38;5;240;49;22m [0m +-> @staticmethod +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m17 [0;38;5;250;48;5;240mFoo [0;38;5;240;49;22m [0m +-> def bra(self): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m21 [0;38;5;250;48;5;240mFoo [0;38;5;240;49;22m [0m +--Return-- +-> def bra(self): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m6 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m21 [0;38;5;250;48;5;240mFoo [0;38;5;240;49;22m [0m +-> def brah(): +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m25 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +-> f = Foo() +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> def __init__(self): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m7 [0;38;5;250;48;5;240m__init__ [0;38;5;240;49;22m [0m +-> nop('__init__') +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m8 [0;38;5;250;48;5;240m__init__ [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m8 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m8 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m8 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> self.bar() +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m9 [0;38;5;250;48;5;240m__init__ [0;38;5;240;49;22m [0m +--Call-- +-> @classmethod +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m9 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m13 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +-> nop(cls.__name__) +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m9 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 5 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m9 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 5 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m9 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 5 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m9 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(cls.__name__) +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m9 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +-> self.baz() +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m10 [0;38;5;250;48;5;240m__init__ [0;38;5;240;49;22m [0m +--Call-- +-> @staticmethod +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m10 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m17 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +-> nop(1) +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m10 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 5 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m10 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 5 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m10 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 5 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m10 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(1) +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m10 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +-> self.bra() +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m11 [0;38;5;250;48;5;240m__init__ [0;38;5;240;49;22m [0m +--Call-- +-> def bra(self): +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m11 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m21 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +-> nop(self.__class__.__name__) +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m11 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 5 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m11 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 5 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m11 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 5 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m11 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(self.__class__.__name__) +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m11 [0;38;5;250;48;5;240m__init__ [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +--Return-- +-> self.bra() +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m29 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m11 [0;38;5;250;48;5;240m__init__ [0;38;5;240;49;22m [0m +-> Foo.bar() +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m30 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> @classmethod +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m30 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m13 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +-> nop(cls.__name__) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m30 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m30 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m30 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m30 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(cls.__name__) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m30 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +-> Foo.baz() +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m31 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> @staticmethod +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m31 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m17 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +-> nop(1) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m31 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m31 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m31 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m31 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(1) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m31 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +-> Foo.bra(f) +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m32 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> def bra(self): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m32 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m21 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +-> nop(self.__class__.__name__) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m32 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m32 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m32 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m32 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(self.__class__.__name__) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m32 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +-> f.bar() +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m34 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> @classmethod +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m34 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m13 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +-> nop(cls.__name__) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m34 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m34 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m34 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m34 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(cls.__name__) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m34 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m15 [0;38;5;250;48;5;240mbar [0;38;5;240;49;22m [0m +-> f.baz() +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m35 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> @staticmethod +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m35 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m17 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +-> nop(1) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m35 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m35 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m35 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m35 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(1) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m35 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m19 [0;38;5;250;48;5;240mbaz [0;38;5;240;49;22m [0m +-> f.bra() +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m36 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> def bra(self): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m36 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m21 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +-> nop(self.__class__.__name__) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m36 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m36 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m36 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m36 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop(self.__class__.__name__) +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m36 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m22 [0;38;5;250;48;5;240mbra [0;38;5;240;49;22m [0m +-> brah() +[0;38;5;235;48;5;252;1m 2 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m38 [0;38;5;250;48;5;240m<module> [0;38;5;240;49;22m [0m +--Call-- +-> def brah(): +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m38 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m25 [0;38;5;250;48;5;240mbrah [0;38;5;240;49;22m [0m +-> nop('brah') +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m38 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m26 [0;38;5;250;48;5;240mbrah [0;38;5;240;49;22m [0m +--Call-- +-> def nop(_): +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m38 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m26 [0;38;5;250;48;5;240mbrah [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m2 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m38 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m26 [0;38;5;250;48;5;240mbrah [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> pass +[0;38;5;235;48;5;252;1m 4 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m38 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m26 [0;38;5;250;48;5;240mbrah [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m3 [0;38;5;250;48;5;240mnop [0;38;5;240;49;22m [0m +--Return-- +-> nop('brah') +[0;38;5;235;48;5;252;1m 3 [0;38;5;252;48;5;240;22m [0;38;5;252;48;5;240;1m<string>:[0;38;5;252;48;5;240;1m1 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m38 [0;38;5;250;48;5;240m<module> [0;38;5;250;48;5;240;22m [0;38;5;252;48;5;240;1mpdb-script.py:[0;38;5;252;48;5;240;1m26 [0;38;5;250;48;5;240mbrah [0;38;5;240;49;22m [0m diff --git a/tests/test_shells/outputs/rc.daemon.ok b/tests/test_shells/outputs/rc.daemon.ok new file mode 100644 index 0000000..c49b9a3 --- /dev/null +++ b/tests/test_shells/outputs/rc.daemon.ok @@ -0,0 +1,24 @@ +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd .git +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m.git [0;38;5;240;49;22m [0mcd .. +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV = '/home/foo/.virtenvs/some-virtual-environment' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;74;22m [0;38;5;231;48;5;74m(e) some-virtual-environment [0;38;5;74;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV = () +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mbgscript.sh & waitpid.sh +PID +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0mfalse +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m [0mkill `{cat pid} ; sleep 1s +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd $DIR1 +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^[[32m [0;38;5;240;49;22m [0mcd ../$DIR2 +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^H [0;38;5;240;49;22m [0mcd ../'\[\]' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m\[\] [0;38;5;240;49;22m [0mcd ../'%%' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m%% [0;38;5;240;49;22m [0mcd ../'#[bold]' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m#[bold] [0;38;5;240;49;22m [0mcd ../'(echo)' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m(echo) [0;38;5;240;49;22m [0mcd ../'$(echo)' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m$(echo) [0;38;5;240;49;22m [0mcd ../'`echo`' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m`echo` [0;38;5;240;49;22m [0mcd ../'«Unicode!»' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mfalse +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m [0mset_theme_option default_leftonly.segment_data.hostname.display false +[0;38;5;231;48;5;31;1m USER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segment_data.user.display false +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mecho `{ +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0m echo Continuation! +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0m} +Continuation! diff --git a/tests/test_shells/outputs/rc.nodaemon.ok b/tests/test_shells/outputs/rc.nodaemon.ok new file mode 100644 index 0000000..28376cb --- /dev/null +++ b/tests/test_shells/outputs/rc.nodaemon.ok @@ -0,0 +1,24 @@ +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd .git +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m.git [0;38;5;240;49;22m [0mcd .. +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV = '/home/foo/.virtenvs/some-virtual-environment' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;74;22m [0;38;5;231;48;5;74m(e) some-virtual-environment [0;38;5;74;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV = () +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mbgscript.sh & waitpid.sh +PID +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0mfalse +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m [0mkill `{cat pid} ; sleep 1s +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd $DIR1 +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^[[32m [0;38;5;240;49;22m [0mcd ../$DIR2 +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^H [0;38;5;240;49;22m [0mcd ../'\[\]' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m\[\] [0;38;5;240;49;22m [0mcd ../'%%' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m%% [0;38;5;240;49;22m [0mcd ../'#[bold]' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m#[bold] [0;38;5;240;49;22m [0mcd ../'(echo)' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m(echo) [0;38;5;240;49;22m [0mcd ../'$(echo)' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m$(echo) [0;38;5;240;49;22m [0mcd ../'`echo`' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m`echo` [0;38;5;240;49;22m [0mcd ../'«Unicode!»' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mfalse +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m [0mset_theme_option default_leftonly.segment_data.hostname.display false +[0;38;5;231;48;5;31;1m USER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mset_theme_option default_leftonly.segment_data.user.display false +[0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mecho `{ +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0m echo Continuation! +[0;38;5;252;48;5;240;1m [0;38;5;240;49;22m [0m} +Continuation! diff --git a/tests/test_shells/outputs/tcsh.ok b/tests/test_shells/outputs/tcsh.ok new file mode 100644 index 0000000..07089bf --- /dev/null +++ b/tests/test_shells/outputs/tcsh.ok @@ -0,0 +1,17 @@ +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m[0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m.git [0;38;5;240;49;22m[0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m[0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;74;22m [0;38;5;231;48;5;74m(e) some-virtual-environment [0;38;5;74;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m[0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m[0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m[0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m[0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m[0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^[[32m [0;38;5;240;49;22m[0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^H [0;38;5;240;49;22m[0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m\[\] [0;38;5;240;49;22m[0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m%% [0;38;5;240;49;22m[0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m#[bold] [0;38;5;240;49;22m[0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m(echo) [0;38;5;240;49;22m[0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m$(echo) [0;38;5;240;49;22m[0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m`echo` [0;38;5;240;49;22m[0m +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m[0m diff --git a/tests/test_shells/outputs/zsh.daemon.ok b/tests/test_shells/outputs/zsh.daemon.ok new file mode 100644 index 0000000..32e80d8 --- /dev/null +++ b/tests/test_shells/outputs/zsh.daemon.ok @@ -0,0 +1,52 @@ + +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd .git +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m.git [0;38;5;240;49;22m [0mcd .. +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV="/home/USER/.virtenvs/some-virtual-environment" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;74;22m [0;38;5;231;48;5;74m(e) some-virtual-environment [0;38;5;74;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV= +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mbgscript.sh & waitpid.sh +[1] PID +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0mfalse +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m [0mkill `cat pid` ; sleep 1s +[1] + terminated bgscript.sh +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd "$DIR1" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^[[32m [0;38;5;240;49;22m [0mcd ../"$DIR2" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^H [0;38;5;240;49;22m [0mcd ../'\[\]' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m\[\] [0;38;5;240;49;22m [0mcd ../'%%' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m%% [0;38;5;240;49;22m [0mcd ../'#[bold]' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m#[bold] [0;38;5;240;49;22m [0mcd ../'(echo)' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m(echo) [0;38;5;240;49;22m [0mcd ../'$(echo)' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m$(echo) [0;38;5;240;49;22m [0mcd ../'`echo`' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m`echo` [0;38;5;240;49;22m [0mcd ../'«Unicode!»' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mcd .. +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mbindkey -v ; set_theme default +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0m[0;38;5;23;48;5;231;1m COMMND [0;38;5;231;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mecho abc +abc +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mfalse +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.segment_data.hostname.display false +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.segment_data.user.display false +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mselect abc in def ghi jkl +[0;38;5;252;48;5;240;1m select [0;38;5;240;49;22m [0mdo +[0;38;5;252;48;5;240;1m select [0;38;5;240;49;22m [0m echo $abc +[0;38;5;252;48;5;240;1m select [0;38;5;240;49;22m [0m break +[0;38;5;252;48;5;240;1m select [0;38;5;240;49;22m [0mdone +1) def 2) ghi 3) jkl +[0;38;5;252;48;5;240;1m Select variant [0;38;5;240;49;22m [0m1 +def +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd . +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd . +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.segments.above "$ABOVE_LEFT" +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mexport DISPLAYED_ENV_VAR=foo +[0;38;5;231;48;5;22m foo [0;38;5;22;49;22m [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0munset DISPLAYED_ENV_VAR +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.segments.above "$ABOVE_FULL" +[0;38;5;231;48;5;233m [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mexport DISPLAYED_ENV_VAR=foo +[0;38;5;231;48;5;233m [0;38;5;22;48;5;233;22m [0;38;5;231;48;5;22m foo [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0munset DISPLAYED_ENV_VAR +[0;38;5;231;48;5;233m [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.segments.above +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mhash -d foo=$PWD:h ; cd . +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m~foo [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.dividers.left.hard \$ABC +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m$ABC[0;38;5;250;48;5;240m~foo [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m$ABC[0mtrue diff --git a/tests/test_shells/outputs/zsh.nodaemon.ok b/tests/test_shells/outputs/zsh.nodaemon.ok new file mode 100644 index 0000000..3aa285f --- /dev/null +++ b/tests/test_shells/outputs/zsh.nodaemon.ok @@ -0,0 +1,52 @@ + +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd .git +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m.git [0;38;5;240;49;22m [0mcd .. +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV="/home/USER/.virtenvs/some-virtual-environment" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;74;22m [0;38;5;231;48;5;74m(e) some-virtual-environment [0;38;5;74;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV= +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mbgscript.sh & waitpid.sh +[1] PID +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0mfalse +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m [0mkill `cat pid` ; sleep 1s +[1] + terminated bgscript.sh +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd "$DIR1" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^[[32m [0;38;5;240;49;22m [0mcd ../"$DIR2" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^H [0;38;5;240;49;22m [0mcd ../'\[\]' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m\[\] [0;38;5;240;49;22m [0mcd ../'%%' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m%% [0;38;5;240;49;22m [0mcd ../'#[bold]' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m#[bold] [0;38;5;240;49;22m [0mcd ../'(echo)' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m(echo) [0;38;5;240;49;22m [0mcd ../'$(echo)' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m$(echo) [0;38;5;240;49;22m [0mcd ../'`echo`' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m`echo` [0;38;5;240;49;22m [0mcd ../'«Unicode!»' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mcd .. +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mbindkey -v ; set_theme default +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0m[0;38;5;23;48;5;231;1m COMMND [0;38;5;231;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mecho abc +abc +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mfalse +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.segment_data.hostname.display false +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.segment_data.user.display false +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mselect abc in def ghi jkl +[0;38;5;252;48;5;240;1m select [0;38;5;240;49;22m [0mdo +[0;38;5;252;48;5;240;1m select [0;38;5;240;49;22m [0m echo $abc +[0;38;5;252;48;5;240;1m select [0;38;5;240;49;22m [0m break +[0;38;5;252;48;5;240;1m select [0;38;5;240;49;22m [0mdone +1) def 2) ghi 3) jkl +[0;38;5;252;48;5;240;1m Select variant [0;38;5;240;49;22m [0m1 +def +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd . +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd . +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.segments.above "$ABOVE_LEFT" +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mexport DISPLAYED_ENV_VAR=foo +[0;38;5;231;48;5;22m foo [0;38;5;22;49;22m [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0munset DISPLAYED_ENV_VAR +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.segments.above "$ABOVE_FULL" +[0;38;5;231;48;5;233m [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mexport DISPLAYED_ENV_VAR=foo +[0;38;5;231;48;5;233m [0;38;5;22;48;5;233;22m [0;38;5;231;48;5;22m foo [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0munset DISPLAYED_ENV_VAR +[0;38;5;231;48;5;233m [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.segments.above +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mhash -d foo=$PWD:h ; cd . +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m~foo [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.dividers.left.hard \$ABC +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m$ABC[0;38;5;250;48;5;240m~foo [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m$ABC[0mtrue diff --git a/tests/test_shells/outputs/zsh.zpython.ok b/tests/test_shells/outputs/zsh.zpython.ok new file mode 100644 index 0000000..32e80d8 --- /dev/null +++ b/tests/test_shells/outputs/zsh.zpython.ok @@ -0,0 +1,52 @@ + +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd .git +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m.git [0;38;5;240;49;22m [0mcd .. +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV="/home/USER/.virtenvs/some-virtual-environment" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;74;22m [0;38;5;231;48;5;74m(e) some-virtual-environment [0;38;5;74;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mVIRTUAL_ENV= +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mbgscript.sh & waitpid.sh +[1] PID +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;49;22m [0mfalse +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;48;5;166;22m [0;38;5;220;48;5;166m1 [0;38;5;166;48;5;52;22m [0;38;5;231;48;5;52m1 [0;38;5;52;49;22m [0mkill `cat pid` ; sleep 1s +[1] + terminated bgscript.sh +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd "$DIR1" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^[[32m [0;38;5;240;49;22m [0mcd ../"$DIR2" +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m^H [0;38;5;240;49;22m [0mcd ../'\[\]' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m\[\] [0;38;5;240;49;22m [0mcd ../'%%' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m%% [0;38;5;240;49;22m [0mcd ../'#[bold]' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m#[bold] [0;38;5;240;49;22m [0mcd ../'(echo)' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m(echo) [0;38;5;240;49;22m [0mcd ../'$(echo)' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m$(echo) [0;38;5;240;49;22m [0mcd ../'`echo`' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m`echo` [0;38;5;240;49;22m [0mcd ../'«Unicode!»' +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240m3rd [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m«Unicode!» [0;38;5;240;49;22m [0mcd .. +[0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;236;22m [0;38;5;250;48;5;236m BRANCH [0;38;5;236;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mbindkey -v ; set_theme default +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0m[0;38;5;23;48;5;231;1m COMMND [0;38;5;231;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mecho abc +abc +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mfalse +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;166;22m [0;38;5;220;48;5;166m HOSTNAME [0;38;5;166;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.segment_data.hostname.display false +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;31;22m [0;38;5;231;48;5;31;1mUSER [0;38;5;31;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.segment_data.user.display false +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mselect abc in def ghi jkl +[0;38;5;252;48;5;240;1m select [0;38;5;240;49;22m [0mdo +[0;38;5;252;48;5;240;1m select [0;38;5;240;49;22m [0m echo $abc +[0;38;5;252;48;5;240;1m select [0;38;5;240;49;22m [0m break +[0;38;5;252;48;5;240;1m select [0;38;5;240;49;22m [0mdone +1) def 2) ghi 3) jkl +[0;38;5;252;48;5;240;1m Select variant [0;38;5;240;49;22m [0m1 +def +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd . +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mcd . +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.segments.above "$ABOVE_LEFT" +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mexport DISPLAYED_ENV_VAR=foo +[0;38;5;231;48;5;22m foo [0;38;5;22;49;22m [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0munset DISPLAYED_ENV_VAR +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.segments.above "$ABOVE_FULL" +[0;38;5;231;48;5;233m [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mexport DISPLAYED_ENV_VAR=foo +[0;38;5;231;48;5;233m [0;38;5;22;48;5;233;22m [0;38;5;231;48;5;22m foo [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0munset DISPLAYED_ENV_VAR +[0;38;5;231;48;5;233m [0m +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.segments.above +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m… [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mtmp [0;38;5;245;48;5;240;22m [0;38;5;250;48;5;240mshell [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mhash -d foo=$PWD:h ; cd . +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m [0;38;5;250;48;5;240m~foo [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m [0mset_theme_option default.dividers.left.hard \$ABC +[0;38;5;22;48;5;148;1m INSERT [0;38;5;148;48;5;240;22m$ABC[0;38;5;250;48;5;240m~foo [0;38;5;245;48;5;240;22m [0;38;5;252;48;5;240;1m3rd [0;38;5;240;49;22m$ABC[0mtrue diff --git a/tests/test_shells/pdb-main.py b/tests/test_shells/pdb-main.py new file mode 100644 index 0000000..37af785 --- /dev/null +++ b/tests/test_shells/pdb-main.py @@ -0,0 +1,24 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import pdb +import os +import sys + +from powerline.bindings.pdb import use_powerline_prompt + + +@use_powerline_prompt +class Pdb(pdb.Pdb): + pass + + +p = Pdb() + + +script = os.path.join(os.path.dirname(__file__), 'pdb-script.py') +with open(script, 'r') as fd: + code = compile(fd.read(), script, 'exec') + + +p.run('exec(code)', globals={'code': code}) diff --git a/tests/test_shells/pdb-script.py b/tests/test_shells/pdb-script.py new file mode 100644 index 0000000..40db5e8 --- /dev/null +++ b/tests/test_shells/pdb-script.py @@ -0,0 +1,38 @@ +# vim:fileencoding=utf-8:noet +def nop(_): + pass + + +class Foo(object): + def __init__(self): + nop('__init__') + self.bar() + self.baz() + self.bra() + + @classmethod + def bar(cls): + nop(cls.__name__) + + @staticmethod + def baz(): + nop(1) + + def bra(self): + nop(self.__class__.__name__) + + +def brah(): + nop('brah') + + +f = Foo() +Foo.bar() +Foo.baz() +Foo.bra(f) + +f.bar() +f.baz() +f.bra() + +brah() diff --git a/tests/test_shells/postproc.py b/tests/test_shells/postproc.py new file mode 100755 index 0000000..7926155 --- /dev/null +++ b/tests/test_shells/postproc.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os +import socket +import sys +import codecs +import platform +import re + + +test_root = os.environ['TEST_ROOT'] +test_type = sys.argv[1] +test_client = sys.argv[2] +shell = sys.argv[3] +fname = os.path.join(test_root, '.'.join((shell, test_type, test_client, 'full.log'))) +new_fname = os.path.join(test_root, '.'.join((shell, test_type, test_client, 'log'))) +pid_fname = os.path.join(test_root, '3rd', 'pid') + +is_pypy = platform.python_implementation() == 'PyPy' + + +try: + with open(pid_fname, 'r') as P: + pid = P.read().strip() +except IOError: + pid = None +hostname = socket.gethostname() +user = os.environ['USER'] + +REFS_RE = re.compile(r'^\[\d+ refs\]\n') +IPYPY_DEANSI_RE = re.compile(r'\033(?:\[(?:\?\d+[lh]|[^a-zA-Z]+[a-ln-zA-Z])|[=>])') +ZSH_HL_RE = re.compile(r'\033\[\?\d+[hl]') + +start_str = 'cd "$TEST_ROOT"/3rd' +if shell == 'pdb': + start_str = 'class Foo(object):' + +with codecs.open(fname, 'r', encoding='utf-8') as R: + with codecs.open(new_fname, 'w', encoding='utf-8') as W: + found_cd = False + i = -1 + for line in (R if shell != 'fish' else R.read().split('\n')): + i += 1 + if not found_cd: + found_cd = (start_str in line) + continue + if 'true is the last line' in line: + break + line = line.translate({ + ord('\r'): None + }) + if REFS_RE.match(line): + continue + line = line.replace(hostname, 'HOSTNAME') + line = line.replace(user, 'USER') + if pid is not None: + line = line.replace(pid, 'PID') + if shell == 'zsh': + line = line.replace('\033[0m\033[23m\033[24m\033[J', '') + line = ZSH_HL_RE.subn('', line)[0] + elif shell == 'fish': + res = '' + try: + while line.index('\033[0;'): + start = line.index('\033[0;') + end = line.index('\033[0m', start) + res += line[start:end + 4] + '\n' + line = line[end + 4:] + except ValueError: + pass + line = res + elif shell == 'tcsh': + try: + start = line.index('\033[0;') + end = line.index(' ', start) + line = line[start:end] + '\n' + except ValueError: + line = '' + elif shell == 'mksh': + # Output is different in travis: on my machine I see full + # command, in travis it is truncated just after `true`. + if line.startswith('[1] + Terminated'): + line = '[1] + Terminated bash -c ...\n' + elif shell == 'dash': + # Position of this line is not stable: it may go both before and + # after the next line + if line.startswith('[1] + Terminated'): + continue + elif shell == 'ipython' and is_pypy: + try: + end_idx = line.rindex('\033[0m') + try: + idx = line[:end_idx].rindex('\033[1;1H') + except ValueError: + idx = line[:end_idx].rindex('\033[?25h') + line = line[idx + len('\033[1;1H'):] + except ValueError: + pass + try: + data_end_idx = line.rindex('\033[1;1H') + line = line[:data_end_idx] + '\n' + except ValueError: + pass + if line == '\033[1;1H\n': + continue + was_empty = line == '\n' + line = IPYPY_DEANSI_RE.subn('', line)[0] + if line == '\n' and not was_empty: + line = '' + elif shell == 'rc': + if line == 'read() failed: Connection reset by peer\n': + line = '' + elif shell == 'pdb': + if is_pypy: + if line == '\033[?1h\033=\033[?25l\033[1A\n': + line = '' + line = IPYPY_DEANSI_RE.subn('', line)[0] + if line == '\n': + line = '' + if line.startswith(('>',)): + line = '' + elif line == '-> self.quitting = 1\n': + line = '-> self.quitting = True\n' + elif line == '\n': + line = '' + if line == '-> self.quitting = True\n': + break + W.write(line) diff --git a/tests/test_shells/run_script.py b/tests/test_shells/run_script.py new file mode 100755 index 0000000..2eebca1 --- /dev/null +++ b/tests/test_shells/run_script.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import argparse +import os +import re + +from time import sleep +from subprocess import check_call +from io import BytesIO + +import pexpect + + +def get_argparser(ArgumentParser=argparse.ArgumentParser): + parser = ArgumentParser(description='Run powerline shell test using pexpect') + parser.add_argument('--wait-for-echo', action='store_true', help='Wait until the input is echoed back.') + parser.add_argument('--type', metavar='TYPE', help='Test type (daemon, nodaemon, …).') + parser.add_argument('--client', metavar='CLIENT', help='Type of the client used (C, shell, zpython, …).') + parser.add_argument('--shell', metavar='SHELL', help='Shell name.') + parser.add_argument('command', nargs=argparse.REMAINDER, metavar='COMMAND', + help='Command to run and its argument.') + return parser + + +def main(): + test_root = os.environ['TEST_ROOT'] + parser = get_argparser() + args = parser.parse_args() + + shell = args.shell or args.command[0] + test_type = args.type or shell + test_client = args.client or test_type + + log_file_base = '{0}.{1}.{2}'.format(shell, test_type, test_client) + full_log_file_name = os.path.join(test_root, '{0}.full.log'.format(log_file_base)) + + local_paths = [ + os.path.abspath(os.path.join(test_root, 'path')), + os.path.abspath('scripts'), + ] + + if test_type == 'fish': + local_paths += ['/usr/bin', '/bin'] + + python_paths = os.environ.get('PYTHONPATH', '') + if python_paths: + python_paths = ':' + python_paths + python_paths = os.path.abspath('.') + python_paths + + environ = { + 'LANG': 'en_US.UTF-8', + 'PATH': os.pathsep.join(local_paths), + 'TERM': 'screen-256color', + 'DIR1': os.environ['DIR1'], + 'DIR2': os.environ['DIR2'], + 'XDG_CONFIG_HOME': os.path.abspath(os.path.join(test_root, 'fish_home')), + 'IPYTHONDIR': os.path.abspath(os.path.join(test_root, 'ipython_home')), + 'PYTHONPATH': python_paths, + 'POWERLINE_CONFIG_OVERRIDES': os.environ.get('POWERLINE_CONFIG_OVERRIDES', ''), + 'POWERLINE_THEME_OVERRIDES': os.environ.get('POWERLINE_THEME_OVERRIDES', ''), + 'POWERLINE_CONFIG_PATHS': os.path.abspath(os.path.join('powerline', 'config_files')), + 'POWERLINE_COMMAND_ARGS': os.environ.get('POWERLINE_COMMAND_ARGS', ''), + 'POWERLINE_COMMAND': os.environ.get('POWERLINE_COMMAND', ''), + 'LD_LIBRARY_PATH': os.environ.get('LD_LIBRARY_PATH', ''), + 'TEST_ROOT': test_root, + } + + os.environ['PATH'] = environ['PATH'] + + if test_type == 'daemon': + environ['POWERLINE_SHELL_CONTINUATION'] = '1' + environ['POWERLINE_SHELL_SELECT'] = '1' + + if test_type != 'zpython' and shell == 'zsh': + environ['POWERLINE_NO_ZSH_ZPYTHON'] = '1' + + sio = BytesIO() + + child = pexpect.spawn( + args.command[0], + args.command[1:], + env=environ, + logfile=sio, + timeout=30, + ) + child.expect(re.compile(b'.*')) + sleep(0.5) + child.setwinsize(1, 300) + + with open(os.path.join('tests', 'test_shells', 'inputs', shell), 'rb') as F: + if not args.wait_for_echo: + child.send(F.read()) + else: + for line in F: + child.send(line) + sleep(1) + # TODO Implement something more smart + + with open(full_log_file_name, 'wb') as LF: + while True: + try: + s = child.read_nonblocking(1000) + except pexpect.TIMEOUT: + break + except pexpect.EOF: + break + else: + LF.write(s) + + child.close(force=True) + + check_call([ + os.path.join(test_root, 'path', 'python'), + os.path.join('tests', 'test_shells', 'postproc.py'), + test_type, test_client, shell + ]) + pidfile = os.path.join(test_root, '3rd', 'pid') + if os.path.exists(pidfile): + os.unlink(pidfile) + + +if __name__ == '__main__': + main() diff --git a/tests/test_shells/test.sh b/tests/test_shells/test.sh new file mode 100755 index 0000000..4494302 --- /dev/null +++ b/tests/test_shells/test.sh @@ -0,0 +1,491 @@ +#!/bin/sh +. tests/shlib/common.sh + +enter_suite shell final + +if test $# -eq 0 ; then + FAST=1 +fi +ONLY_SHELL="$1" +ONLY_TEST_TYPE="$2" +ONLY_TEST_CLIENT="$3" + +export PYTHON + +if test "$ONLY_SHELL" = "--help" ; then +cat << EOF +Usage: + $0 [[[ONLY_SHELL | ""] (ONLY_TEST_TYPE | "")] (ONLY_TEST_CLIENT | "")] + +ONLY_SHELL: execute only tests for given shell +ONLY_TEST_TYPE: execute only "daemon" or "nodaemon" tests +ONLY_TEST_CLIENT: use only given test client (one of C, python, render, shell) +EOF +exit 0 +fi + +check_screen_log() { + TEST_TYPE="$1" + TEST_CLIENT="$2" + SH="$3" + if test -e "$ROOT/tests/test_shells/outputs/${SH}.${TEST_TYPE}.ok" ; then + diff -a -u "$ROOT/tests/test_shells/outputs/${SH}.${TEST_TYPE}.ok" \ + "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log" + return $? + elif test -e "$ROOT/tests/test_shells/outputs/${SH}.ok" ; then + diff -a -u "$ROOT/tests/test_shells/outputs/${SH}.ok" \ + "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log" + return $? + else + cat "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log" + return 1 + fi +} + +# HACK: get newline for use in strings given that "\n" and $'' do not work. +NL="$(printf '\nE')" +NL="${NL%E}" + +print_full_output() { + TEST_TYPE="$1" + TEST_CLIENT="$2" + SH="$3" + echo "Full output:" + echo '============================================================' + cat "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.full.log" + echo + echo '____________________________________________________________' + if test "$POWERLINE_TEST_NO_CAT_V" != "1" ; then + echo "Full output (cat -v):" + echo '============================================================' + cat -v "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.full.log" + echo + echo '____________________________________________________________' + fi +} + +do_run_test() { + TEST_TYPE="$1" + shift + TEST_CLIENT="$1" + shift + SH="$1" + + local wait_for_echo_arg= + if ( \ + test "${SH}" = "dash" \ + || ( \ + test "${SH}" = "pdb" \ + && ( \ + ( \ + test "$PYTHON_VERSION_MAJOR" -eq 3 \ + && test "$PYTHON_VERSION_MINOR" -eq 2 \ + && test "$PYTHON_IMPLEMENTATION" = "CPython" \ + ) \ + || test "$PYTHON_IMPLEMENTATION" = "PyPy" \ + ) \ + ) \ + || ( \ + test "${SH}" = "ipython" \ + && test "$("${PYTHON}" -mIPython --version | head -n1 | cut -d. -f1)" -ge 5 \ + ) \ + ) ; then + wait_for_echo_arg="--wait-for-echo" + fi + "${PYTHON}" tests/test_shells/run_script.py \ + $wait_for_echo_arg --type=${TEST_TYPE} --client=${TEST_CLIENT} --shell=${SH} \ + "$@" + if ! check_screen_log ${TEST_TYPE} ${TEST_CLIENT} ${SH} ; then + echo '____________________________________________________________' + if test "$POWERLINE_TEST_NO_CAT_V" != "1" ; then + # Repeat the diff to make it better viewable in travis output + echo "Diff (cat -v):" + echo '============================================================' + check_screen_log ${TEST_TYPE} ${TEST_CLIENT} ${SH} | cat -v + echo '____________________________________________________________' + fi + echo -n "Failed ${SH}. " + print_full_output ${TEST_TYPE} ${TEST_CLIENT} ${SH} + case "${SH}" in + *ksh) + "$TEST_ROOT/path/${SH}" -c 'echo ${KSH_VERSION}' + ;; + dash) + # ? + ;; + busybox) + busybox --help + ;; + *) + "$TEST_ROOT/path/${SH}" --version + ;; + esac + if which dpkg >/dev/null ; then + dpkg -s ${SH} + fi + return 1 + fi + return 0 +} + +run_test() { + TEST_TYPE="$1" + TEST_CLIENT="$2" + SH="$3" + local attempts=3 + if test -n "$ONLY_SHELL$ONLY_TEST_TYPE$ONLY_TEST_CLIENT" ; then + attempts=1 + fi + while test $attempts -gt 0 ; do + rm -f "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log" + rm -f "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.full.log" + do_run_test "$@" && return 0 + attempts=$(( attempts - 1 )) + done + return 1 +} + +make_test_root + +git init "$TEST_ROOT/3rd" +git --git-dir="$TEST_ROOT/3rd/.git" checkout -b BRANCH +export DIR1="[32m" +export DIR2="" +mkdir "$TEST_ROOT/3rd/$DIR1" +mkdir "$TEST_ROOT/3rd/$DIR2" +mkdir "$TEST_ROOT"/3rd/'\[\]' +mkdir "$TEST_ROOT"/3rd/'%%' +mkdir "$TEST_ROOT"/3rd/'#[bold]' +mkdir "$TEST_ROOT"/3rd/'(echo)' +mkdir "$TEST_ROOT"/3rd/'$(echo)' +mkdir "$TEST_ROOT"/3rd/'`echo`' +mkdir "$TEST_ROOT"/3rd/'«Unicode!»' + +mkdir "$TEST_ROOT/fish_home" +mkdir "$TEST_ROOT/fish_home/fish" +mkdir "$TEST_ROOT/fish_home/fish/generated_completions" +cp -r "$ROOT/tests/test_shells/ipython_home" "$TEST_ROOT" + +mkdir "$TEST_ROOT/path" +ln -s "$(which "${PYTHON}")" "$TEST_ROOT/path/python" +ln -s "$(which env)" "$TEST_ROOT/path" +ln -s "$(which git)" "$TEST_ROOT/path" +ln -s "$(which sleep)" "$TEST_ROOT/path" +ln -s "$(which cat)" "$TEST_ROOT/path" +ln -s "$(which false)" "$TEST_ROOT/path" +ln -s "$(which true)" "$TEST_ROOT/path" +ln -s "$(which kill)" "$TEST_ROOT/path" +ln -s "$(which echo)" "$TEST_ROOT/path" +ln -s "$(which which)" "$TEST_ROOT/path" +ln -s "$(which dirname)" "$TEST_ROOT/path" +ln -s "$(which wc)" "$TEST_ROOT/path" +ln -s "$(which stty)" "$TEST_ROOT/path" +ln -s "$(which cut)" "$TEST_ROOT/path" +ln -s "$(which bc)" "$TEST_ROOT/path" +ln -s "$(which expr)" "$TEST_ROOT/path" +ln -s "$(which mktemp)" "$TEST_ROOT/path" +ln -s "$(which grep)" "$TEST_ROOT/path" +ln -s "$(which sed)" "$TEST_ROOT/path" +ln -s "$(which rm)" "$TEST_ROOT/path" +ln -s "$(which tr)" "$TEST_ROOT/path" +ln -s "$(which uname)" "$TEST_ROOT/path" +ln -s "$(which test)" "$TEST_ROOT/path" +ln -s "$(which pwd)" "$TEST_ROOT/path" +ln -s "$(which hostname)" "$TEST_ROOT/path" +ln -s "$ROOT/tests/test_shells/bgscript.sh" "$TEST_ROOT/path" +ln -s "$ROOT/tests/test_shells/waitpid.sh" "$TEST_ROOT/path" +if which socat ; then + ln -s "$(which socat)" "$TEST_ROOT/path" +fi +for pexe in powerline powerline-config powerline-render powerline.sh powerline.py ; do + if test -e "$ROOT/scripts/$pexe" ; then + ln -s "$ROOT/scripts/$pexe" "$TEST_ROOT/path" + elif test -e client/$pexe ; then + ln -s "$ROOT/client/$pexe" "$TEST_ROOT/path" + elif which $pexe ; then + ln -s "$(which $pexe)" "$TEST_ROOT/path" + else + echo "Executable $pexe was not found" + exit 1 + fi +done + +ln -s python "$TEST_ROOT/path/pdb" +PDB_PYTHON=pdb +ln -s python "$TEST_ROOT/path/ipython" +IPYTHON_PYTHON=ipython + +if test -z "$POWERLINE_RC_EXE" ; then + if which rc-status >/dev/null ; then + # On Gentoo `rc` executable is from OpenRC. Thus app-shells/rc instals + # `rcsh` executable. + POWERLINE_RC_EXE=rcsh + else + POWERLINE_RC_EXE=rc + fi +fi + +if which "$POWERLINE_RC_EXE" >/dev/null ; then + ln -s "$(which $POWERLINE_RC_EXE)" "$TEST_ROOT/path/rc" +fi + +exes="bash zsh busybox tcsh mksh" + +if test "$TRAVIS" != "true" ; then + # For some reason fish does not work on travis + exes="$exes fish" +fi + +# dash has some problems with job control +#exes="$exes dash" + +for exe in $exes ; do + if which $exe >/dev/null ; then + if test "$exe" = "fish" ; then + fish_version="$(fish --version 2>&1)" + fish_version="${fish_version##* }" + fish_version_major="${fish_version%%.*}" + if test "$fish_version_major" != "$fish_version" ; then + # No dot is in development version compiled by bot-ci + fish_version_minor="${fish_version#*.}" + fish_version_patch="${fish_version_minor#*.}" + fish_version_dev="${fish_version_patch#*-}" + if test "$fish_version_dev" = "$fish_version_patch" ; then + fish_version_dev="" + fi + fish_version_minor="${fish_version_minor%%.*}" + fish_version_patch="${fish_version_patch%%-*}" + if test $fish_version_major -lt 2 || ( \ + test $fish_version_major -eq 2 && (\ + test $fish_version_minor -lt 1 || (\ + test $fish_version_minor -eq 1 && + test $fish_version_patch -lt 2 && \ + test -z "$fish_version_dev" + ) \ + ) \ + ) ; then + continue + fi + fi + fi + ln -s "$(which $exe)" "$TEST_ROOT/path" + fi +done + +mkdir "$TEST_ROOT/home" +export HOME="$TEST_ROOT/home" + +unset ENV + +export ADDRESS="powerline-ipc-test-$$" +export PYTHON +echo "Powerline address: $ADDRESS" + +check_test_client() { + local executable="$1" + local client_type="$2" + local actual_mime_type="$( + file --mime-type --brief --dereference "$TEST_ROOT/path/$executable" \ + | cut -d/ -f1 + )" + local expected_mime_type + case "$client_type" in + C) expected_mime_type="application/x-executable" ;; + python) expected_mime_type="text/x-python" ;; + render) expected_mime_type="text/x-python" ;; + shell) expected_mime_type="text/x-shellscript" ;; + esac + expected_mime_type="${expected_mime_type%/*}" + if test "$expected_mime_type" != "$actual_mime_type" ; then + fail "MIME-$executable" "M" "Expected $executable to have MIME type $expected_mime_type, but got $actual_mime_type" + fi +} + +if ( \ + test -z "${ONLY_SHELL}" \ + || test "${ONLY_SHELL%sh}" != "${ONLY_SHELL}" \ + || test "${ONLY_SHELL}" = "busybox" \ + || test "${ONLY_SHELL}" = "rc" \ +) ; then + scripts/powerline-config shell command + + for TEST_TYPE in "daemon" "nodaemon" ; do + if test -n "$ONLY_TEST_TYPE" && test "$ONLY_TEST_TYPE" != "$TEST_TYPE" + then + continue + fi + if test "$FAST" = 1 ; then + if test $TEST_TYPE = daemon ; then + VARIANTS=3 + else + VARIANTS=4 + fi + EXETEST="$(( ${RANDOM:-`date +%N | sed s/^0*//`} % $VARIANTS ))" + echo "Execute tests: $EXETEST" + fi + + if test $TEST_TYPE = daemon ; then + sh -c ' + echo $$ > "$TEST_ROOT/daemon_pid" + exec "$PYTHON" ./scripts/powerline-daemon -s"$ADDRESS" -f >"$TEST_ROOT/daemon_log" 2>&1 + ' & + fi + echo "> Testing $TEST_TYPE" + I=-1 + for POWERLINE_COMMAND in \ + powerline \ + powerline-render \ + powerline.py \ + powerline.sh + do + case "$POWERLINE_COMMAND" in + powerline) TEST_CLIENT=C ;; + powerline-render) TEST_CLIENT=render ;; + powerline.py) TEST_CLIENT=python ;; + powerline.sh) TEST_CLIENT=shell ;; + esac + check_test_client "$POWERLINE_COMMAND" $TEST_CLIENT + if test "$TEST_CLIENT" = render && test "$TEST_TYPE" = daemon ; then + continue + fi + I="$(( I + 1 ))" + if test "$TEST_CLIENT" = "C" && ! test -x "$ROOT/scripts/powerline" + then + if which powerline >/dev/null ; then + POWERLINE_COMMAND=powerline + else + continue + fi + fi + if ( \ + test "$TEST_CLIENT" = "shell" \ + && ! test -x "$TEST_ROOT/path/socat" \ + ) ; then + continue + fi + if ( \ + test -n "$ONLY_TEST_CLIENT" \ + && test "$TEST_CLIENT" != "$ONLY_TEST_CLIENT" \ + ) ; then + continue + fi + export POWERLINE_COMMAND_ARGS="--socket $ADDRESS" + export POWERLINE_COMMAND="$POWERLINE_COMMAND" + echo ">> powerline command is ${POWERLINE_COMMAND:-empty}" + J=-1 + for TEST_COMMAND in \ + "bash --norc --noprofile -i" \ + "zsh -f -i" \ + "fish -i" \ + "tcsh -f -i" \ + "busybox ash -i" \ + "mksh -i" \ + "dash -i" \ + "rc -i -p" + do + J="$(( J + 1 ))" + if test "$FAST" = 1 ; then + if test $(( (I + J) % $VARIANTS )) -ne $EXETEST ; then + continue + fi + fi + SH="${TEST_COMMAND%% *}" + if test -n "$ONLY_SHELL" && test "$ONLY_SHELL" != "$SH" ; then + continue + fi + if ! test -x "$TEST_ROOT/path/$SH" ; then + continue + fi + echo ">>> $(readlink "$TEST_ROOT/path/$SH")" + if ! run_test $TEST_TYPE $TEST_CLIENT $TEST_COMMAND ; then + fail "$SH-$TEST_TYPE-$TEST_CLIENT:test" F \ + "Failed checking $TEST_COMMAND" + fi + done + done + if test $TEST_TYPE = daemon ; then + "$PYTHON" ./scripts/powerline-daemon -s"$ADDRESS" -k + wait $(cat "$TEST_ROOT/daemon_pid") + if ! test -z "$(cat "$TEST_ROOT/daemon_log")" ; then + echo '____________________________________________________________' + echo "Daemon log:" + echo '============================================================' + cat "$TEST_ROOT/daemon_log" + fail "$SH-$TEST_TYPE-$TEST_CLIENT:log" E \ + "Non-empty daemon log for ${TEST_COMMAND}" + fi + fi + done +fi + +if "$PYTHON" scripts/powerline-daemon -s"$ADDRESS" \ + > "$TEST_ROOT/daemon_log_2" 2>&1 +then + sleep 1 + "$PYTHON" scripts/powerline-daemon -s"$ADDRESS" -k +else + fail "daemon:run" F "Daemon exited with status $?" +fi + +if ! test -z "$(cat "$TEST_ROOT/daemon_log_2")" ; then + echo '____________________________________________________________' + echo "Daemon log (2nd):" + echo '============================================================' + cat "$TEST_ROOT/daemon_log_2" + fail "daemon:log" E "Daemon run with non-empty log" +fi + +if ( test -z "${ONLY_SHELL}" || test "${ONLY_SHELL}" = "zsh" ) \ + && ( test -z "${ONLY_TEST_TYPE}" || test "${ONLY_TEST_TYPE}" = "zpython" ) \ + && "$TEST_ROOT/path/zsh" "$ROOT/tests/test_shells/zsh_test_script.zsh" +then + echo "> zpython" + if ! run_test zpython zpython zsh -f -i ; then + fail "zsh-zpython:test" F "Failed checking zsh -f -i" + fi +fi + +if test -z "${ONLY_SHELL}" || test "${ONLY_SHELL}" = "pdb" ; then + if test "$PYTHON_IMPLEMENTATION" != "PyPy" ; then + if test -z "${ONLY_TEST_TYPE}" || test "${ONLY_TEST_TYPE}" = "subclass" + then + echo "> pdb subclass" + if ! run_test subclass python $PDB_PYTHON \ + "$ROOT/tests/test_shells/pdb-main.py" + then + fail --allow-failure "pdb-subclass:test" F \ + "Failed checking $PDB_PYTHON $ROOT/tests/test_shells/pdb-main.py" + fi + fi + if test -z "${ONLY_TEST_TYPE}" || test "${ONLY_TEST_TYPE}" = "module" ; then + echo "> pdb module" + MODULE="powerline.bindings.pdb" + if test "$PYTHON_MM" = "2.6" ; then + MODULE="powerline.bindings.pdb.__main__" + fi + if ! run_test module python "$PDB_PYTHON" -m"$MODULE" \ + "$ROOT/tests/test_shells/pdb-script.py" + then + fail --allow-failure "pdb-module:test" F \ + "Failed checking $PDB_PYTHON -m$MODULE $ROOT/tests/test_shells/pdb-script" + fi + fi + fi +fi + +if test -z "${ONLY_SHELL}" || test "${ONLY_SHELL}" = "ipython" ; then + if "${PYTHON}" -c "try: import IPython${NL}except ImportError: raise SystemExit(1)" ; then + # Define some overrides which should be ignored by IPython. + export POWERLINE_CONFIG_OVERRIDES='common.term_escape_style=fbterm' + export POWERLINE_THEME_OVERRIDES='in.segments.left=[]' + echo "> ipython" + if ! run_test ipython ipython ${IPYTHON_PYTHON} -mIPython ; then + # Do not allow ipython tests to spoil the build + fail --allow-failure "ipython:test" F "Failed checking ${IPYTHON_PYTHON} -mIPython" + fi + unset POWERLINE_THEME_OVERRIDES + unset POWERLINE_CONFIG_OVERRIDES + fi +fi + +exit_suite diff --git a/tests/test_shells/waitpid.sh b/tests/test_shells/waitpid.sh new file mode 100755 index 0000000..8d98e21 --- /dev/null +++ b/tests/test_shells/waitpid.sh @@ -0,0 +1,4 @@ +#!/bin/sh +while ! test -e pid ; do + sleep 0.1s +done diff --git a/tests/test_shells/zsh_test_script.zsh b/tests/test_shells/zsh_test_script.zsh new file mode 100644 index 0000000..3957f56 --- /dev/null +++ b/tests/test_shells/zsh_test_script.zsh @@ -0,0 +1,11 @@ +set -e +set -x +. tests/bot-ci/scripts/common/main.sh +zmodload zpython || zmodload libzpython +zpython 'import zsh' +zpython 'import platform' +zpython 'zsh.setvalue("ZSH_PYTHON_VERSION", platform.python_version())' +zpython 'zsh.setvalue("ZSH_PYTHON_IMPLEMENTATION", platform.python_implementation())' + +[[ $ZSH_PYTHON_IMPLEMENTATION = $PYTHON_IMPLEMENTATION ]] +[[ $ZSH_PYTHON_VERSION = $PYTHON_VERSION ]] diff --git a/tests/test_vim/pyfiles/setup_statusline_catcher.py b/tests/test_vim/pyfiles/setup_statusline_catcher.py new file mode 100644 index 0000000..014a2e9 --- /dev/null +++ b/tests/test_vim/pyfiles/setup_statusline_catcher.py @@ -0,0 +1,18 @@ +# vim:fileencoding=utf-8:noet +import json + +import vim + +from powerline.lib.unicode import u + + +_powerline_old_render = powerline.render # NOQA + + +def _powerline_test_render_function(*args, **kwargs): + ret = _powerline_old_render(*args, **kwargs) + vim.eval('add(g:statusline_values, %s)' % json.dumps(u(ret))) + return ret + + +powerline.render = _powerline_test_render_function # NOQA diff --git a/tests/test_vim/test.sh b/tests/test_vim/test.sh new file mode 100755 index 0000000..ecd0285 --- /dev/null +++ b/tests/test_vim/test.sh @@ -0,0 +1,60 @@ +#!/bin/sh +. tests/shlib/common.sh +. tests/shlib/vterm.sh +. tests/shlib/vim.sh + +enter_suite vim final + +vterm_setup vim + +# Define some overrides. These ones must be ignored and do not affect Vim +# status/tab lines. +export POWERLINE_CONFIG_OVERRIDES='common.default_top_theme=ascii' +export POWERLINE_THEME_OVERRIDES='default.segments.left=[]' + +test_script() { + local vim="$1" ; shift + local script="$1" ; shift + local allow_failure_arg="$1" ; shift + echo "Running script $script with $vim" + if ! test -e "$vim" ; then + return 0 + fi + if ! script="$script" "$vim" -u NONE -c 'source $script' \ + || test -f message.fail + then + local test_name="${script##*/}" + fail $allow_failure_arg "${test_name%.vim}" \ + F "Failed script $script run with $vim" + if test -e message.fail ; then + cat message.fail >&2 + rm message.fail + fi + fi +} + +TEST_SCRIPT_ROOT="$ROOT/tests/test_vim/tests" + +cd "$TEST_ROOT" + +for script in "$TEST_SCRIPT_ROOT"/*.vim ; do + if test "${script%.old.vim}" = "${script}" ; then + test_script "$NEW_VIM" "$script" "" + fi +done + +if test "$PYTHON_VERSION_MAJOR.$PYTHON_VERSION_MINOR" = "2.7" ; then + ALLOW_FAILURE_ARG=--allow-failure +else + ALLOW_FAILURE_ARG= +fi + +if test -e "$OLD_VIM" ; then + for script in "$TEST_SCRIPT_ROOT"/*.old.vim ; do + test_script "$OLD_VIM" "$script" "$ALLOW_FAILURE_ARG" + done +fi + +vterm_shutdown + +exit_suite diff --git a/tests/test_vim/tests/commandt_plugin.vim b/tests/test_vim/tests/commandt_plugin.vim new file mode 100755 index 0000000..9f944b9 --- /dev/null +++ b/tests/test_vim/tests/commandt_plugin.vim @@ -0,0 +1,17 @@ +#!/usr/bin/vim -S +set nocompatible +set columns=80 +execute 'source' fnameescape(expand('<sfile>:p:h:h').'/vim_utils.vim') +call EnablePlugins('command-t') +call SourcePowerline() +let g:statusline_values = [] +call PyFile('setup_statusline_catcher') +execute 'CommandTBuffer'|call feedkeys("\<C-c>") +call RunPython('powerline.render = _powerline_old_render') +let g:expected_statusline = '%#Pl_231_16777215_240_5789784_bold# Command-T %#Pl_231_16777215_240_5789784_NONE# %#Pl_231_16777215_240_5789784_bold#BufferFinder %#Pl_240_5789784_236_3158064_NONE# %#Pl_231_16777215_236_3158064_NONE# ' +call CheckMessages() +if index(g:statusline_values, g:expected_statusline) == -1 + call CheckStatuslineValue(get(g:statusline_values, -1, ''), g:expected_statusline) + cquit +endif +qall diff --git a/tests/test_vim/tests/empty_encoding.old.vim b/tests/test_vim/tests/empty_encoding.old.vim new file mode 100755 index 0000000..124a10a --- /dev/null +++ b/tests/test_vim/tests/empty_encoding.old.vim @@ -0,0 +1,32 @@ +#!/usr/bin/vim -S +if has('multi_byte') + if empty(&encoding) + call writefile(['&encoding option value is empty, even though Vim has +multibyte'], 'message.fail') + cquit + endif + qall +endif +if !empty(&encoding) + call writefile(['&encoding option value is not empty, even though Vim does not have +multibyte'], 'message.fail') + cquit +endif + +let g:powerline_config_paths = [expand('<sfile>:p:h:h:h:h') . '/powerline/config_files'] + +try + source <sfile>:p:h:h:h:h/powerline/bindings/vim/plugin/powerline.vim +catch + call writefile(['Unexpected exception:', v:exception], 'message.fail') + cquit +endtry +set ls=2 +redrawstatus! +redir => g:messages + messages +redir END +let mess=split(g:messages, "\n") +if len(mess)>1 + call writefile(['Unexpected message(s):']+mess, 'message.fail') + cquit +endif +qall! diff --git a/tests/test_vim/tests/foreign_stl_override.vim b/tests/test_vim/tests/foreign_stl_override.vim new file mode 100644 index 0000000..2a5b8c0 --- /dev/null +++ b/tests/test_vim/tests/foreign_stl_override.vim @@ -0,0 +1,22 @@ +scriptencoding utf-8 +set encoding=utf-8 +let g:powerline_config_paths = [expand('<sfile>:p:h:h:h:h') . '/powerline/config_files'] +set laststatus=2 +redir => g:messages + try + source <sfile>:p:h:h:h:h/powerline/bindings/vim/plugin/powerline.vim + redrawstatus! + vsplit + redrawstatus! + setlocal statusline=«» + redrawstatus! + catch + call writefile(['Unexpected exception', v:exception], 'message.fail') + cquit + endtry +redir END +if g:messages =~# '\v\S' + call writefile(['Unexpected messages'] + split(g:messages, "\n", 1), 'message.fail') + cquit +endif +qall! diff --git a/tests/test_vim/tests/invalid_unicode.vim b/tests/test_vim/tests/invalid_unicode.vim new file mode 100644 index 0000000..ac91f3c --- /dev/null +++ b/tests/test_vim/tests/invalid_unicode.vim @@ -0,0 +1,19 @@ +set encoding=utf-8 +let g:powerline_config_paths = [expand('<sfile>:p:h:h:h:h') . '/powerline/config_files'] +set laststatus=2 +set showtabline=2 +edit `="\xFF"` +redir => g:messages + try + source <sfile>:p:h:h:h:h/powerline/bindings/vim/plugin/powerline.vim + redrawstatus! + catch + call writefile(['Unexpected exception', v:exception], 'message.fail') + cquit + endtry +redir END +if g:messages =~# '\v\S' + call writefile(['Unexpected messages'] + split(g:messages, "\n", 1), 'message.fail') + cquit +endif +qall! diff --git a/tests/test_vim/tests/local_overrides.vim b/tests/test_vim/tests/local_overrides.vim new file mode 100755 index 0000000..aba14e2 --- /dev/null +++ b/tests/test_vim/tests/local_overrides.vim @@ -0,0 +1,48 @@ +#!/usr/bin/vim -S +set encoding=utf-8 +let g:powerline_config_paths = [expand('<sfile>:p:h:h:h:h') . '/powerline/config_files'] +let g:powerline_config_overrides = {'common': {'default_top_theme': 'ascii'}} +let g:powerline_theme_overrides = {'default': {'segment_data': {'line_current_symbol': {'contents': 'LN '}, 'branch': {'before': 'B '}}}} + +redir => g:messages + +try + python import powerline.vim + let pycmd = 'python' +catch + try + python3 import powerline.vim + let pycmd = 'python3' + catch + call writefile(['Unable to determine python version', v:exception], 'message.fail') + cquit + endtry +endtry + +try + execute pycmd 'powerline.vim.setup()' +catch + call writefile(['Failed to run setup function', v:exception], 'message.fail') + cquit +endtry + +try + let &columns = 80 + let result = eval(&statusline[2:]) +catch + call writefile(['Exception while evaluating &stl', v:exception], 'message.fail') + cquit +endtry + +if result isnot# '%#Pl_22_24320_148_11523840_bold# NORMAL %#Pl_148_11523840_236_3158064_NONE# %#Pl_231_16777215_236_3158064_NONE# %#Pl_247_10395294_236_3158064_NONE#unix%#Pl_240_5789784_236_3158064_NONE# %#Pl_247_10329757_240_5789784_NONE# 100%%%#Pl_252_13684944_240_5789784_NONE# %#Pl_235_2500134_252_13684944_NONE# LN %#Pl_235_2500134_252_13684944_bold# 1%#Pl_22_24576_252_13684944_NONE#:1 ' + call writefile(['Unexpected result', result], 'message.fail') + cquit +endif + +redir END +if g:messages =~ '\S' + call writefile(['Non-empty messages:', g:messages], 'message.fail') + cquit +endif + +qall! diff --git a/tests/test_vim/tests/nerdtree_plugin.vim b/tests/test_vim/tests/nerdtree_plugin.vim new file mode 100755 index 0000000..761cb5f --- /dev/null +++ b/tests/test_vim/tests/nerdtree_plugin.vim @@ -0,0 +1,11 @@ +#!/usr/bin/vim -S +set nocompatible +set columns=80 +execute 'source' fnameescape(expand('<sfile>:p:h:h').'/vim_utils.vim') +call EnablePlugins('nerdtree') +call SourcePowerline() +NERDTree /home +redrawstatus +call CheckCurrentStatusline('%#Pl_231_16777215_240_5789784_bold# /home %#Pl_240_5789784_236_3158064_NONE# %#Pl_231_16777215_236_3158064_NONE# ') +call CheckMessages() +qall diff --git a/tests/test_vim/tests/plugin_file.vim b/tests/test_vim/tests/plugin_file.vim new file mode 100755 index 0000000..1848933 --- /dev/null +++ b/tests/test_vim/tests/plugin_file.vim @@ -0,0 +1,22 @@ +#!/usr/bin/vim -S +set encoding=utf-8 +let g:powerline_config_paths = [expand('<sfile>:p:h:h:h:h') . '/powerline/config_files'] +tabedit abc +tabedit def +try + source <sfile>:p:h:h:h:h/powerline/bindings/vim/plugin/powerline.vim +catch + call writefile([v:exception], 'message.fail') + cquit +endtry +set ls=2 +redrawstatus! +redir =>mes + messages +redir END +let mess=split(mes, "\n") +if len(mess)>1 + call writefile(mess, 'message.fail') + cquit +endif +qall! diff --git a/tests/test_vim/tests/tabline.vim b/tests/test_vim/tests/tabline.vim new file mode 100755 index 0000000..ff76dc0 --- /dev/null +++ b/tests/test_vim/tests/tabline.vim @@ -0,0 +1,56 @@ +#!/usr/bin/vim -S +set encoding=utf-8 +let g:powerline_config_paths = [expand('<sfile>:p:h:h:h:h') . '/powerline/config_files'] +source <sfile>:p:h:h:h:h/powerline/bindings/vim/plugin/powerline.vim +edit abc +tabedit def +tabedit ghi + +redir => g:messages + +try + let &columns = 80 + let result = eval(&tabline[2:]) +catch + call writefile(['Exception while evaluating &tabline', v:exception], 'message.fail') + cquit +endtry + +if result isnot# '%1T%#Pl_247_10395294_236_3158064_NONE# 1 ./abc %#Pl_244_8421504_236_3158064_NONE# %2T%#Pl_247_10395294_236_3158064_NONE#2 ./def %#Pl_236_3158064_240_5789784_NONE# %3T%#Pl_250_12369084_240_5789784_NONE#3 ./%#Pl_231_16777215_240_5789784_bold#ghi %#Pl_240_5789784_236_3158064_NONE# %T%#Pl_231_16777215_236_3158064_NONE# %#Pl_252_13684944_236_3158064_NONE# %#Pl_235_2500134_252_13684944_bold# Tabs ' + call writefile(['Unexpected tabline', result], 'message.fail') + cquit +endif + +tabonly! + +try + let result = eval(&tabline[2:]) +catch + call writefile(['Exception while evaluating &tabline (2)', v:exception], 'message.fail') + cquit +endtry + +if result isnot# '%T%#Pl_247_10395294_236_3158064_NONE# 1 ./abc %#Pl_244_8421504_236_3158064_NONE# %#Pl_247_10395294_236_3158064_NONE#2 ./def %#Pl_236_3158064_240_5789784_NONE# %#Pl_250_12369084_240_5789784_NONE#3 ./%#Pl_231_16777215_240_5789784_bold#ghi %#Pl_240_5789784_236_3158064_NONE# %#Pl_231_16777215_236_3158064_NONE# %#Pl_252_13684944_236_3158064_NONE# %#Pl_235_2500134_252_13684944_bold# Bufs ' + call writefile(['Unexpected tabline (2)', result], 'message.fail') + cquit +endif + +try + vsplit + let result = eval(&tabline[2:]) +catch + call writefile(['Exception while evaluating &tabline (3)', v:exception], 'message.fail') +endtry + +if result isnot# '%T%#Pl_247_10395294_236_3158064_NONE# 1 ./abc %#Pl_244_8421504_236_3158064_NONE# %#Pl_247_10395294_236_3158064_NONE#2 ./def %#Pl_236_3158064_240_5789784_NONE# %#Pl_250_12369084_240_5789784_NONE#3 ./%#Pl_231_16777215_240_5789784_bold#ghi %#Pl_240_5789784_236_3158064_NONE# %#Pl_231_16777215_236_3158064_NONE# %#Pl_252_13684944_236_3158064_NONE# %#Pl_235_2500134_252_13684944_bold# Bufs ' + call writefile(['Unexpected tabline (3)', result], 'message.fail') + cquit +endif + +redir END +if g:messages =~ '\S' + call writefile(['Non-empty messages:', g:messages], 'message.fail') + cquit +endif + +qall! diff --git a/tests/test_vim/vim_utils.vim b/tests/test_vim/vim_utils.vim new file mode 100644 index 0000000..6219ec4 --- /dev/null +++ b/tests/test_vim/vim_utils.vim @@ -0,0 +1,88 @@ +let g:powerline_use_var_handler = 1 + +let g:pyfiles_root=expand('<sfile>:p:h').'/pyfiles' +let g:root=expand('<sfile>:p:h:h:h') +let g:mf=fnamemodify('message.fail', ':p') + +command -nargs=1 LST :call writefile(<args>, g:mf, 'a') | cquit +command -nargs=1 ERR :LST [<args>] +command -nargs=1 EXC :ERR 'Unexpected exception', <q-args>, v:exception, v:throwpoint + +function EnablePlugins(...) + let &runtimepath = join(map(copy(a:000), 'escape(g:root."/tests/vim-plugins/".v:val, "\\,")'), ',') + try + runtime! plugin/*.vim + silent doautocmd BufWinEnter + silent doautocmd BufEnter + silent doautocmd VimEnter + catch + EXC EnablePlugins + endtry +endfunction +function RecordStatusline() + let g:statusline = &l:statusline + if g:statusline[:1] is# '%!' + let g:statusline_value=eval(g:statusline[2:]) + else + ERR 'Statusline does not start with %!', g:statusline + endif + return '' +endfunction +function SourcePowerline() + let g:powerline_config_paths = [g:root . '/powerline/config_files'] + try + execute 'source' fnameescape(g:root . '/powerline/bindings/vim/plugin/powerline.vim') + catch + EXC SourcePowerline + endtry +endfunction +function NDiff(actual, expected) + return systemlist(shellescape(g:root.'/tests/bot-ci/scripts/ndiff-strings.py').' '.shellescape(a:actual).' '.shellescape(a:expected)) +endfunction +function CheckStatuslineValue(actual, expected) + if a:actual isnot# a:expected + LST ['Expected different statusline value', a:actual, a:expected] + NDiff(a:actual, a:expected) + endif +endfunction +function CheckRecordedStatuslineValue(expected) + return CheckStatuslineValue(g:statusline_value, a:expected) +endfunction +function GetCurrentStatusline() + if &l:statusline[:1] isnot# '%!' + ERR 'Statusline does not start with %!', &l:statusline + endif + return eval(&l:statusline[2:]) +endfunction +function CheckCurrentStatusline(expected) + return CheckStatuslineValue(GetCurrentStatusline(), a:expected) +endfunction +function CheckMessages() + if !empty(g:powerline_log_messages) + LST ['Unexpected messages in log'] + g:powerline_log_messages + endif + redir => mes + messages + redir END + let mesl = split(mes, "\n")[1:] + if !empty(mesl) + LST ['Unexpected messages'] + split(mes, "\n", 1) + endif +endfunction +function RunPython(s) + if has('python') + execute 'python' a:s + else + execute 'python3' a:s + endif +endfunction +function PyFile(f) + if has('python') + execute 'pyfile' fnameescape(g:pyfiles_root.'/'.a:f.'.py') + else + execute 'py3file' fnameescape(g:pyfiles_root.'/'.a:f.'.py') + endif +endfunction + +for s:c in ['noremap', 'noremap!'] + execute s:c '<special><expr>' '<Plug>(PowerlineTestRecordStatusline)' 'RecordStatusline()' +endfor diff --git a/tests/vim_sys_path/vim.py b/tests/vim_sys_path/vim.py new file mode 100644 index 0000000..e9dba66 --- /dev/null +++ b/tests/vim_sys_path/vim.py @@ -0,0 +1,7 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import tests.modules.vim as vim + + +globals().update(vim._init()) |