diff --git a/README.md b/README.md index f44c816a..38f08a26 100644 --- a/README.md +++ b/README.md @@ -292,11 +292,17 @@ pip install -r requirements.txt python setup.py develop ``` -Run tests: +Run unit tests: ```bash py.test ``` +Run unit and functional tests (requires docker): + +```bash +FUNCTIONAL=true py.test +``` + ## License MIT Project License can be found [here](LICENSE.md). diff --git a/requirements.txt b/requirements.txt index 3e46cdce..40ce7169 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ mock pytest-mock wheel setuptools>=17.1 +pexpect diff --git a/tests/functional/__init__.py b/tests/functional/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/functional/test_bash.py b/tests/functional/test_bash.py new file mode 100644 index 00000000..ef4b5d42 --- /dev/null +++ b/tests/functional/test_bash.py @@ -0,0 +1,49 @@ +import pytest +from tests.functional.utils import build_container, spawn, run, read_until, \ + root, functional + +containers = [('thefuck/ubuntu-python3-bash', ''' +FROM ubuntu:latest +RUN apt-get update +RUN apt-get install -yy python3 python3-pip python3-dev +RUN pip3 install -U setuptools +RUN ln -s /usr/bin/pip3 /usr/bin/pip +RUN echo "PS1='$ '" > /root/.bashrc +CMD ["/bin/bash"] +'''), + ('thefuck/ubuntu-python2-bash', ''' +FROM ubuntu:latest +RUN apt-get update +RUN apt-get install -yy python python-pip python-dev +RUN pip2 install -U pip setuptools +RUN echo "PS1='$ '" > /root/.bashrc +CMD ["/bin/bash"] +''')] + + +@functional +@pytest.mark.parametrize('tag, dockerfile', containers) +def test_with_confirmation(tag, dockerfile): + build_container(tag, dockerfile) + with spawn(tag, '{}:/src'.format(root), + ['cd /src', 'pip install .', 'eval $(thefuck-alias)']) as proc: + run(proc, 'ehco test') + proc.sendline('fuck') + read_until(proc, '[') + proc.send('\n') + out = read_until(proc) + assert out.split('\n')[-2] == 'test\r\r' + + +@functional +@pytest.mark.parametrize('tag, dockerfile', containers) +def test_without_confirmation(tag, dockerfile): + build_container(tag, dockerfile) + with spawn(tag, '{}:/src'.format(root), + ['cd /src', 'pip install .', + 'export THEFUCK_REQUIRE_CONFIRMATION=false', + 'eval $(thefuck-alias)']) as proc: + run(proc, 'ehco test') + run(proc, 'fuck') + out = read_until(proc) + assert out.split('\n')[-2] == 'test\r\r' diff --git a/tests/functional/test_zsh.py b/tests/functional/test_zsh.py new file mode 100644 index 00000000..bd311b27 --- /dev/null +++ b/tests/functional/test_zsh.py @@ -0,0 +1,50 @@ +import pytest +from tests.functional.utils import build_container, spawn, run, read_until, \ + root, functional + +containers = [('thefuck/ubuntu-python3-zsh', ''' +FROM ubuntu:latest +RUN apt-get update +RUN apt-get install -yy python3 python3-pip python3-dev zsh +RUN pip3 install -U setuptools +RUN ln -s /usr/bin/pip3 /usr/bin/pip +RUN echo "PS1='\\n$ '" > /root/.zshrc +CMD ["/bin/zsh"] +'''), + ('thefuck/ubuntu-python2-zsh', ''' +FROM ubuntu:latest +RUN apt-get update +RUN apt-get install -yy python python-pip python-dev zsh +RUN pip2 install -U pip setuptools +RUN echo "PS1='\\n$ '" > /root/.zshrc +CMD ["/bin/zsh"] +''')] + + +@functional +@pytest.mark.parametrize('tag, dockerfile', containers) +def test_with_confirmation(tag, dockerfile): + build_container(tag, dockerfile) + with spawn(tag, '{}:/src'.format(root), + ['cd /src', 'pip install .', 'eval $(thefuck-alias)']) as proc: + run(proc, 'ehco "\ntest"') + proc.sendline('fuck') + read_until(proc, '[') + proc.send('\n') + read_until(proc) + out = read_until(proc) + assert out.split('\n')[-3] == 'test\r\r' + + +@functional +@pytest.mark.parametrize('tag, dockerfile', containers) +def test_without_confirmation(tag, dockerfile): + build_container(tag, dockerfile) + with spawn(tag, '{}:/src'.format(root), + ['cd /src', 'pip install .', + 'export THEFUCK_REQUIRE_CONFIRMATION=false', + 'eval $(thefuck-alias)']) as proc: + run(proc, 'ehco "\ntest"') + run(proc, 'fuck') + out = read_until(proc) + assert out.split('\n')[-3] == 'test\r\r' diff --git a/tests/functional/utils.py b/tests/functional/utils.py new file mode 100644 index 00000000..684dc93b --- /dev/null +++ b/tests/functional/utils.py @@ -0,0 +1,57 @@ +import sys +import os +import pytest +from contextlib import contextmanager +import pexpect +import subprocess +import shutil +from tempfile import mkdtemp +from pathlib import Path + +root = str(Path(__file__).parent.parent.parent.resolve()) + + +def build_container(tag, dockerfile): + tmpdir = mkdtemp() + with Path(tmpdir).joinpath('Dockerfile').open('w') as file: + file.write(dockerfile) + if subprocess.call(['docker', 'build', '--tag={}'.format(tag), tmpdir]) != 0: + raise Exception("Can't build container") + shutil.rmtree(tmpdir) + + +def read_until(proc, string='\n$ '): + text = '' + while True: + text += proc.read(1) + sys.stdout.write(text[-1]) + sys.stdout.flush() + if text.endswith(string): + return text + + +def run(proc, cmd): + proc.sendline(cmd) + return read_until(proc) + + +@contextmanager +def spawn(tag, volume, prepare=None): + if prepare is None: + prepare = [] + + proc = pexpect.spawnu( + 'docker run --volume {} --tty=true --interactive=true {}'.format( + volume, tag)) + + try: + for line in prepare: + run(proc, line) + yield proc + finally: + proc.terminate() + + +functional = pytest.mark.skipif( + not os.environ.get('FUNCTIONAL'), + reason='Functional tests are disabled by default.')