1
0
mirror of https://github.com/nvbn/thefuck.git synced 2025-11-01 15:42:06 +00:00

Compare commits

...

50 Commits

Author SHA1 Message Date
nvbn
0fcc35c227 #380 merge cd_mkdir and cd_correction rules 2015-10-12 17:52:44 +08:00
nvbn
3da26192cb Bump to 3.1 2015-10-08 10:30:38 +08:00
Vladimir Iakovlev
11c133523a Merge pull request #375 from jab/patch-1
rm -f $eval_script
2015-10-03 10:24:39 +08:00
Vladimir Iakovlev
4b3e6a1448 Merge pull request #374 from mcarton/python3.5
Test on python 3.5
2015-10-03 10:23:41 +08:00
jab
09d9f63c98 use /bin/rm rather than rm -f 2015-10-02 10:12:50 -04:00
jab
e8883429c6 rm -f $eval_script
Without this change, users who have "rm" aliased to "rm -i"
have to confirm removal of the file after running fuck. This
change allows such users to run fuck without having to do
the superfluous rm confirmation.
2015-10-02 10:09:19 -04:00
nvbn
c1b67f2514 Show python version in --version 2015-09-28 16:47:54 +08:00
mcarton
3d6e7b17db Test on python 3.5 2015-09-15 02:17:56 +02:00
Vladimir Iakovlev
75ef866214 Merge pull request #373 from grammaright/master
Add j, k key for arrow action at read_actions
2015-09-13 12:38:55 +03:00
grammaright
5021d16cea Add j, k key for arrow action at read_actions 2015-09-13 01:27:21 +09:00
Vladimir Iakovlev
af259846b4 Merge pull request #370 from nvbn/369-git-fix-stash-fails
#369 Fix `git_fix_stash` fails when script is just `git`
2015-09-10 15:11:34 +03:00
nvbn
213791d3c2 #369 Fix git_fix_stash fails when script is just git 2015-09-10 14:28:22 +03:00
nvbn
71dc2666cc Bump to 3.0 2015-09-09 10:59:07 +03:00
Vladimir Iakovlev
3e66a294c4 Merge pull request #367 from nvbn/355-touch-rule
#355 Add `touch` rule
2015-09-09 10:57:55 +03:00
nvbn
3e8db28a73 #355 Add touch rule 2015-09-09 10:53:56 +03:00
Vladimir Iakovlev
6e886c6b4f Merge pull request #366 from nvbn/unned-abstractions
Improve code structure
2015-09-08 17:53:37 +03:00
nvbn
3fc2efee0f #366 Don't make bash history checks in travis-ci, it works incorrectly 2015-09-08 17:48:33 +03:00
nvbn
cb14aded6b #366 Remove sleep before checking history 2015-09-08 17:47:04 +03:00
nvbn
08af616e3d #366 Add sleep before checking history 2015-09-08 17:39:52 +03:00
nvbn
dfa22bc92b #366 Add type annotations in core components 2015-09-08 15:54:07 +03:00
nvbn
eb17e696c3 #366 Fix python 2 support 2015-09-08 15:32:19 +03:00
nvbn
b8ce95ad68 Minor refactoring 2015-09-08 15:24:49 +03:00
nvbn
1173f9f59c Organize settings initialization logic in Settings 2015-09-08 15:15:53 +03:00
nvbn
a8dbc48fd4 Move commands-related logic to Command and CorrectedCommand 2015-09-08 15:00:57 +03:00
nvbn
4a27595e97 Move rule-related code to Rule 2015-09-08 14:18:11 +03:00
nvbn
bf80d97062 Remove obscure SortedCorrectedCommandsSequence 2015-09-08 12:52:10 +03:00
nvbn
1fb6dd925b Remove on_change from CommandSelector 2015-09-08 12:27:17 +03:00
nvbn
b2be0b3cad Remove obscure RulesNamesList and DefaultRulesNames 2015-09-08 12:14:39 +03:00
Vladimir Iakovlev
122541b7d8 Merge pull request #365 from mcarton/fix-unzip
Fix #363
2015-09-07 23:36:13 +03:00
mcarton
488c1dad79 Merge branch 'master' of github.com:nvbn/thefuck into fix-unzip 2015-09-07 21:12:14 +02:00
mcarton
c3fe7e5e68 Fix #363 2015-09-07 20:48:10 +02:00
nvbn
3d56204f92 Update readme 2015-09-07 19:13:17 +03:00
Vladimir Iakovlev
293f16c3c8 Merge pull request #364 from nvbn/global-settings
Don't pass `settings` explicitly
2015-09-07 19:09:31 +03:00
nvbn
7339a97b90 #364 Make aliases cache persistent 2015-09-07 19:05:38 +03:00
nvbn
f3525e9fe0 #364 Attach user_dir to settings 2015-09-07 18:59:10 +03:00
nvbn
df4d2cc88d ⚠️ Remove settings param from rules match, get_new_command and side_effect 2015-09-07 13:00:29 +03:00
nvbn
382eb8b86c Fix tests 2015-09-07 12:12:16 +03:00
nvbn
105d3d8137 Make settings a global singleton 2015-09-06 21:47:12 +03:00
Vladimir Iakovlev
191a2e588d Merge pull request #362 from nvbn/356-fuck-endpoint
#356 fuck endpoint
2015-09-06 13:43:24 +03:00
nvbn
f964c65f16 #362 Fix tests for python 2 2015-09-06 13:40:29 +03:00
nvbn
dd0667ea8f #356 Ignore thefuck entry points 2015-09-06 13:37:48 +03:00
nvbn
4392872568 #356 Print useful information when fuck called and alias isn't configured 2015-09-06 13:29:42 +03:00
Vladimir Iakovlev
f7ce0fda25 Merge pull request #361 from nvbn/357-exclude-rules
#357 Add `exclude_rules` settings option
2015-09-06 12:59:34 +03:00
nvbn
2f9db24ed1 #357 Add exclude_rules settings option 2015-09-06 12:55:59 +03:00
Vladimir Iakovlev
4ae2e9bbc4 Merge pull request #359 from nvbn/use-pytest-docker-pexpect
Use pytest-docker-pexpect
2015-09-06 01:28:37 +03:00
nvbn
5cfd493d05 Make "arrows" tests less dependent on environment 2015-09-06 01:24:29 +03:00
nvbn
22eac045c8 Use @pytest.mark.once_without_docker 2015-09-06 01:14:49 +03:00
nvbn
cdd5f21e88 Add functional marker 2015-09-06 01:13:44 +03:00
nvbn
8cc19daaaa Use pytest-docker-pexpect for func tests 2015-09-06 00:56:18 +03:00
nvbn
8bf4182f86 Fix install script on non-ubuntu 2015-09-05 11:54:59 +03:00
182 changed files with 1636 additions and 1369 deletions

View File

@@ -1,5 +1,7 @@
language: python
sudo: false
python:
- "3.5"
- "3.4"
- "3.3"
- "2.7"
@@ -14,8 +16,6 @@ addons:
- tcsh
- pandoc
- git
env:
- FUNCTIONAL=true BARE=true
install:
- pip install coveralls
- pip install -r requirements.txt
@@ -23,5 +23,5 @@ install:
- rm -rf build
script:
- export COVERAGE_PYTHON_VERSION=python-${TRAVIS_PYTHON_VERSION:0:1}
- coverage run --source=thefuck,tests -m py.test -v --capture=sys
- coverage run --source=thefuck,tests -m py.test -v --capture=sys --run-without-docker --enable-functional
after_success: coveralls

View File

@@ -141,8 +141,8 @@ using the matched rule and runs it. Rules enabled by default are as follows:
* `cargo` – runs `cargo build` instead of `cargo`;
* `cargo_no_command` – fixes wrongs commands like `cargo buid`;
* `cd_correction` – spellchecks and correct failed cd commands;
* `cd_mkdir` – creates directories before cd'ing into them;
* `cd_correction` – spellchecks and correct failed cd commands, when it's not possible
creates directories before cd'ing into them;
* `cd_parent` – changes `cd..` to `cd ..`;
* `composer_not_command` – fixes composer command name;
* `cp_omitting_directory` – adds `-a` when you `cp` directory;
@@ -198,6 +198,7 @@ using the matched rule and runs it. Rules enabled by default are as follows:
* `switch_lang` – switches command from your local layout to en;
* `systemctl` – correctly orders parameters of confusing `systemctl`;
* `test.py` – runs `py.test` instead of `test.py`;
* `touch` – creates missing directories before "touching";
* `tsuru_login` – runs `tsuru login` if not authenticated or session expired;
* `tsuru_not_command` – fixes wrong `tsuru` commands like `tsuru shell`;
* `tmux` – fixes `tmux` commands;
@@ -226,36 +227,37 @@ For adding your own rule you should create `your-rule-name.py`
in `~/.thefuck/rules`. The rule should contain two functions:
```python
match(command: Command, settings: Settings) -> bool
get_new_command(command: Command, settings: Settings) -> str | list[str]
match(command: Command) -> bool
get_new_command(command: Command) -> str | list[str]
```
Also the rule can contain an optional function
```python
side_effect(old_command: Command, fixed_command: str, settings: Settings) -> None
side_effect(old_command: Command, fixed_command: str) -> None
```
and optional `enabled_by_default`, `requires_output` and `priority` variables.
`Command` has three attributes: `script`, `stdout` and `stderr`.
`Settings` is a special object filled with `~/.thefuck/settings.py` and values from env ([see more below](#settings)).
*Rules api changed in 3.0:* For accessing settings in rule you need to import it with `from thefuck.conf import settings`.
`settings` is a special object filled with `~/.thefuck/settings.py` and values from env ([see more below](#settings)).
Simple example of the rule for running script with `sudo`:
```python
def match(command, settings):
def match(command):
return ('permission denied' in command.stderr.lower()
or 'EACCES' in command.stderr)
def get_new_command(command, settings):
def get_new_command(command):
return 'sudo {}'.format(command.script)
# Optional:
enabled_by_default = True
def side_effect(command, settings):
def side_effect(command, fixed_command):
subprocess.call('chmod 777 .', shell=True)
priority = 1000 # Lower first, default is 1000
@@ -264,13 +266,15 @@ requires_output = True
```
[More examples of rules](https://github.com/nvbn/thefuck/tree/master/thefuck/rules),
[utility functions for rules](https://github.com/nvbn/thefuck/tree/master/thefuck/utils.py).
[utility functions for rules](https://github.com/nvbn/thefuck/tree/master/thefuck/utils.py),
[app/os-specific helpers](https://github.com/nvbn/thefuck/tree/master/thefuck/specific/).
## Settings
The Fuck has a few settings parameters which can be changed in `~/.thefuck/settings.py`:
* `rules` – list of enabled rules, by default `thefuck.conf.DEFAULT_RULES`;
* `exclude_rules` – list of disabled rules, by default `[]`;
* `require_confirmation` – requires confirmation before running new command, by default `True`;
* `wait_command` – max amount of time in seconds for getting previous command output;
* `no_colors` – disable colored output;
@@ -281,6 +285,7 @@ Example of `settings.py`:
```python
rules = ['sudo', 'no_command']
exclude_rules = ['git_push']
require_confirmation = True
wait_command = 10
no_colors = False
@@ -291,6 +296,7 @@ debug = False
Or via environment variables:
* `THEFUCK_RULES` – list of enabled rules, like `DEFAULT_RULES:rm_root` or `sudo:no_command`;
* `THEFUCK_EXCLUDE_RULES` – list of disabled rules, like `git_pull:git_push`;
* `THEFUCK_REQUIRE_CONFIRMATION` – require confirmation before running new command, `true/false`;
* `THEFUCK_WAIT_COMMAND` – max amount of time in seconds for getting previous command output;
* `THEFUCK_NO_COLORS` – disable colored output, `true/false`;
@@ -302,6 +308,7 @@ For example:
```bash
export THEFUCK_RULES='sudo:no_command'
export THEFUCK_EXCLUDE_RULES='git_pull:git_push'
export THEFUCK_REQUIRE_CONFIRMATION='true'
export THEFUCK_WAIT_COMMAND=10
export THEFUCK_NO_COLORS='false'
@@ -326,7 +333,7 @@ py.test
Run unit and functional tests (requires docker):
```bash
FUNCTIONAL=true py.test
py.test --enable-functional
```
For sending package to pypi:

View File

@@ -4,8 +4,12 @@ should_add_alias () {
[ -f $1 ] && ! grep -q thefuck $1
}
installed () {
hash $1 2>/dev/null
}
# Install os dependencies:
if [ -f $(which apt-get) ]; then
if installed apt-get; then
# Debian/ubuntu:
sudo apt-get update -yy
sudo apt-get install -yy python-pip python-dev command-not-found
@@ -15,7 +19,7 @@ if [ -f $(which apt-get) ]; then
sudo apt-get install -yy python-commandnotfound
fi
else
if [ -f $(which brew) ]; then
if installed brew; then
# OS X:
brew update
brew install python

View File

@@ -6,3 +6,4 @@ setuptools>=17.1
pexpect
pypandoc
pytest-benchmark
pytest-docker-pexpect

View File

@@ -20,7 +20,7 @@ elif (3, 0) < version < (3, 3):
' ({}.{} detected).'.format(*version))
sys.exit(-1)
VERSION = '2.9.1'
VERSION = '3.1'
install_requires = ['psutil', 'colorama', 'six', 'decorator']
extras_require = {':python_version<"3.4"': ['pathlib']}
@@ -41,4 +41,5 @@ setup(name='thefuck',
extras_require=extras_require,
entry_points={'console_scripts': [
'thefuck = thefuck.main:main',
'thefuck-alias = thefuck.main:print_alias']})
'thefuck-alias = thefuck.main:print_alias',
'fuck = thefuck.main:how_to_configure_alias']})

View File

@@ -1,5 +1,13 @@
from pathlib import Path
import pytest
from mock import Mock
from thefuck import conf
def pytest_addoption(parser):
"""Adds `--run-without-docker` argument."""
group = parser.getgroup("thefuck")
group.addoption('--enable-functional', action="store_true", default=False,
help="Enable functional tests")
@pytest.fixture
@@ -7,11 +15,34 @@ def no_memoize(monkeypatch):
monkeypatch.setattr('thefuck.utils.memoize.disabled', True)
@pytest.fixture(autouse=True)
def settings(request):
def _reset_settings():
conf.settings.clear()
conf.settings.update(conf.DEFAULT_SETTINGS)
request.addfinalizer(_reset_settings)
conf.settings.user_dir = Path('~/.thefuck')
return conf.settings
@pytest.fixture
def settings():
return Mock(debug=False, no_colors=True)
def no_colors(settings):
settings.no_colors = True
@pytest.fixture(autouse=True)
def no_cache(monkeypatch):
monkeypatch.setattr('thefuck.utils.cache.disabled', True)
@pytest.fixture(autouse=True)
def functional(request):
if request.node.get_marker('functional') \
and not request.config.getoption('enable_functional'):
pytest.skip('functional tests are disabled')
@pytest.fixture
def source_root():
return Path(__file__).parent.parent.resolve()

View File

@@ -1,6 +1,3 @@
from pexpect import TIMEOUT
def _set_confirmation(proc, require):
proc.sendline(u'mkdir -p ~/.thefuck')
proc.sendline(
@@ -8,7 +5,7 @@ def _set_confirmation(proc, require):
require))
def with_confirmation(proc):
def with_confirmation(proc, TIMEOUT):
"""Ensures that command can be fixed when confirmation enabled."""
_set_confirmation(proc, True)
@@ -23,19 +20,19 @@ def with_confirmation(proc):
assert proc.expect([TIMEOUT, u'test'])
def history_changed(proc, to):
def history_changed(proc, TIMEOUT, to):
"""Ensures that history changed."""
proc.send('\033[A')
assert proc.expect([TIMEOUT, to])
def history_not_changed(proc):
def history_not_changed(proc, TIMEOUT):
"""Ensures that history not changed."""
proc.send('\033[A')
assert proc.expect([TIMEOUT, u'fuck'])
def select_command_with_arrows(proc):
def select_command_with_arrows(proc, TIMEOUT):
"""Ensures that command can be selected with arrow keys."""
_set_confirmation(proc, True)
@@ -50,12 +47,14 @@ def select_command_with_arrows(proc):
assert proc.expect([TIMEOUT, u'git help'])
proc.send('\033[A')
assert proc.expect([TIMEOUT, u'git push'])
proc.send('\033[B')
assert proc.expect([TIMEOUT, u'git help'])
proc.send('\n')
assert proc.expect([TIMEOUT, u'Not a git repository'])
assert proc.expect([TIMEOUT, u'usage'])
def refuse_with_confirmation(proc):
def refuse_with_confirmation(proc, TIMEOUT):
"""Ensures that fix can be refused when confirmation enabled."""
_set_confirmation(proc, True)
@@ -70,7 +69,7 @@ def refuse_with_confirmation(proc):
assert proc.expect([TIMEOUT, u'Aborted'])
def without_confirmation(proc):
def without_confirmation(proc, TIMEOUT):
"""Ensures that command can be fixed when confirmation disabled."""
_set_confirmation(proc, False)
@@ -79,3 +78,9 @@ def without_confirmation(proc):
proc.sendline(u'fuck')
assert proc.expect([TIMEOUT, u'echo test'])
assert proc.expect([TIMEOUT, u'test'])
def how_to_configure(proc, TIMEOUT):
proc.sendline(u'unalias fuck')
proc.sendline(u'fuck')
assert proc.expect([TIMEOUT, u"alias isn't configured"])

View File

@@ -1,53 +1,67 @@
import pytest
from tests.functional.plots import with_confirmation, without_confirmation, \
refuse_with_confirmation, history_changed, history_not_changed, \
select_command_with_arrows
from tests.functional.utils import spawn, functional, images
select_command_with_arrows, how_to_configure
containers = images(('ubuntu-python3-bash', u'''
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python3 python3-pip python3-dev git
RUN pip3 install -U setuptools
RUN ln -s /usr/bin/pip3 /usr/bin/pip
'''),
('ubuntu-python2-bash', u'''
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python python-pip python-dev git
RUN pip2 install -U pip setuptools
'''))
containers = ((u'thefuck/ubuntu-python3-bash',
u'''FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python3 python3-pip python3-dev git
RUN pip3 install -U setuptools
RUN ln -s /usr/bin/pip3 /usr/bin/pip''',
u'bash'),
(u'thefuck/ubuntu-python2-bash',
u'''FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python python-pip python-dev git
RUN pip2 install -U pip setuptools''',
u'bash'))
@pytest.fixture(params=containers)
def proc(request):
tag, dockerfile = request.param
proc = spawn(request, tag, dockerfile, u'bash')
def proc(request, spawnu, run_without_docker):
proc = spawnu(*request.param)
if not run_without_docker:
proc.sendline(u"pip install /src")
proc.sendline(u"export PS1='$ '")
proc.sendline(u'eval $(thefuck --alias)')
proc.sendline(u'echo > $HISTFILE')
return proc
@functional
def test_with_confirmation(proc):
with_confirmation(proc)
history_changed(proc, u'echo test')
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_with_confirmation(proc, TIMEOUT, run_without_docker):
with_confirmation(proc, TIMEOUT)
if not run_without_docker:
history_changed(proc, TIMEOUT, u'echo test')
@functional
def test_select_command_with_arrows(proc):
select_command_with_arrows(proc)
history_changed(proc, u'git push')
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_select_command_with_arrows(proc, TIMEOUT, run_without_docker):
select_command_with_arrows(proc, TIMEOUT)
if not run_without_docker:
history_changed(proc, TIMEOUT, u'git help')
@functional
def test_refuse_with_confirmation(proc):
refuse_with_confirmation(proc)
history_not_changed(proc)
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_refuse_with_confirmation(proc, TIMEOUT, run_without_docker):
refuse_with_confirmation(proc, TIMEOUT)
if not run_without_docker:
history_not_changed(proc, TIMEOUT)
@functional
def test_without_confirmation(proc):
without_confirmation(proc)
history_changed(proc, u'echo test')
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_without_confirmation(proc, TIMEOUT, run_without_docker):
without_confirmation(proc, TIMEOUT)
if not run_without_docker:
history_changed(proc, TIMEOUT, u'echo test')
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_how_to_configure_alias(proc, TIMEOUT):
how_to_configure(proc, TIMEOUT)

View File

@@ -1,59 +1,54 @@
import pytest
from tests.functional.plots import with_confirmation, without_confirmation, \
refuse_with_confirmation, select_command_with_arrows
from tests.functional.utils import spawn, functional, images, bare
containers = images(('ubuntu-python3-fish', u'''
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python3 python3-pip python3-dev fish git
RUN pip3 install -U setuptools
RUN ln -s /usr/bin/pip3 /usr/bin/pip
RUN apt-get install -yy fish
'''),
('ubuntu-python2-fish', u'''
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python python-pip python-dev git
RUN pip2 install -U pip setuptools
RUN apt-get install -yy fish
'''))
containers = (('thefuck/ubuntu-python3-fish',
u'''FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python3 python3-pip python3-dev fish git
RUN pip3 install -U setuptools
RUN ln -s /usr/bin/pip3 /usr/bin/pip
RUN apt-get install -yy fish''',
u'fish'),
('thefuck/ubuntu-python2-fish',
u'''FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python python-pip python-dev git
RUN pip2 install -U pip setuptools
RUN apt-get install -yy fish''',
u'fish'))
@pytest.fixture(params=containers)
def proc(request):
tag, dockerfile = request.param
proc = spawn(request, tag, dockerfile, u'fish')
def proc(request, spawnu):
proc = spawnu(*request.param)
proc.sendline(u"pip install /src")
proc.sendline(u'thefuck --alias > ~/.config/fish/config.fish')
proc.sendline(u'fish')
return proc
@functional
@pytest.mark.skipif(
bool(bare), reason='https://github.com/travis-ci/apt-source-whitelist/issues/71')
def test_with_confirmation(proc):
with_confirmation(proc)
@pytest.mark.functional
@pytest.mark.skip_without_docker
def test_with_confirmation(proc, TIMEOUT):
with_confirmation(proc, TIMEOUT)
@functional
@pytest.mark.skipif(
bool(bare), reason='https://github.com/travis-ci/apt-source-whitelist/issues/71')
def test_select_command_with_arrows(proc):
select_command_with_arrows(proc)
@pytest.mark.functional
@pytest.mark.skip_without_docker
def test_select_command_with_arrows(proc, TIMEOUT):
select_command_with_arrows(proc, TIMEOUT)
@functional
@pytest.mark.skipif(
bool(bare), reason='https://github.com/travis-ci/apt-source-whitelist/issues/71')
def test_refuse_with_confirmation(proc):
refuse_with_confirmation(proc)
@pytest.mark.functional
@pytest.mark.skip_without_docker
def test_refuse_with_confirmation(proc, TIMEOUT):
refuse_with_confirmation(proc, TIMEOUT)
@functional
@pytest.mark.skipif(
bool(bare), reason='https://github.com/travis-ci/apt-source-whitelist/issues/71')
def test_without_confirmation(proc):
without_confirmation(proc)
@pytest.mark.functional
@pytest.mark.skip_without_docker
def test_without_confirmation(proc, TIMEOUT):
without_confirmation(proc, TIMEOUT)
# TODO: ensure that history changes.

View File

@@ -1,25 +1,25 @@
import pytest
from pexpect import TIMEOUT
from tests.functional.utils import spawn, functional, bare
from thefuck.utils import get_installation_info
envs = ((u'bash', 'ubuntu-bash', u'''
envs = ((u'bash', 'thefuck/ubuntu-bash', u'''
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy bash
'''), (u'bash', 'generic-bash', u'''
'''), (u'bash', 'thefuck/generic-bash', u'''
FROM fedora:latest
RUN dnf install -yy python-devel sudo which gcc
RUN dnf install -yy python-devel sudo wget gcc
'''))
@functional
@pytest.mark.skipif(
bool(bare), reason="Can't be tested in bare run")
@pytest.mark.functional
@pytest.mark.skip_without_docker
@pytest.mark.parametrize('shell, tag, dockerfile', envs)
def test_installation(request, shell, tag, dockerfile):
proc = spawn(request, tag, dockerfile, shell, install=False)
def test_installation(spawnu, shell, TIMEOUT, tag, dockerfile):
proc = spawnu(tag, dockerfile, shell)
proc.sendline(u'cat /src/install.sh | sh - && $0')
proc.sendline(u'thefuck --version')
assert proc.expect([TIMEOUT, u'The Fuck'], timeout=600)
version = get_installation_info().version
assert proc.expect([TIMEOUT, u'thefuck {}'.format(version)],
timeout=600)
proc.sendline(u'fuck')
assert proc.expect([TIMEOUT, u'No fucks given'])

View File

@@ -1,7 +1,5 @@
from pexpect import TIMEOUT
import pytest
import time
from tests.functional.utils import spawn, functional, bare
dockerfile = u'''
FROM ubuntu:latest
@@ -11,24 +9,17 @@ RUN pip3 install -U setuptools
RUN ln -s /usr/bin/pip3 /usr/bin/pip
RUN adduser --disabled-password --gecos '' test
ENV SEED "{seed}"
COPY thefuck /src
WORKDIR /src
RUN pip install .
USER test
RUN echo 'eval $(thefuck --alias)' > /home/test/.bashrc
RUN echo > /home/test/.bash_history
RUN git config --global user.email "you@example.com"
RUN git config --global user.name "Your Name"
USER root
'''.format(seed=time.time())
@pytest.fixture
def proc(request):
return spawn(request, 'ubuntu-python3-bash-performance',
dockerfile, u'bash', install=False, copy_src=True)
def plot(proc):
def plot(proc, TIMEOUT):
proc.sendline(u'cd /home/test/')
proc.sendline(u'fuck')
assert proc.expect([TIMEOUT, u'No fucks given'])
@@ -48,9 +39,12 @@ def plot(proc):
assert proc.expect([TIMEOUT, u'test'])
@functional
@pytest.mark.skipif(
bool(bare), reason='Would lie on a bare run')
@pytest.mark.functional
@pytest.mark.skip_without_docker
@pytest.mark.benchmark(min_rounds=10)
def test_performance(proc, benchmark):
assert benchmark(plot, proc) is None
def test_performance(spawnu, TIMEOUT, benchmark):
proc = spawnu(u'thefuck/ubuntu-python3-bash-performance',
dockerfile, u'bash')
proc.sendline(u'pip install /src')
proc.sendline(u'su test')
assert benchmark(plot, proc, TIMEOUT) is None

View File

@@ -1,51 +1,55 @@
import pytest
from tests.functional.utils import spawn, functional, images
from tests.functional.plots import with_confirmation, without_confirmation, \
refuse_with_confirmation, select_command_with_arrows
containers = images(('ubuntu-python3-tcsh', u'''
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python3 python3-pip python3-dev git
RUN pip3 install -U setuptools
RUN ln -s /usr/bin/pip3 /usr/bin/pip
RUN apt-get install -yy tcsh
'''),
('ubuntu-python2-tcsh', u'''
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python python-pip python-dev git
RUN pip2 install -U pip setuptools
RUN apt-get install -yy tcsh
'''))
containers = (('thefuck/ubuntu-python3-tcsh',
u'''FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python3 python3-pip python3-dev git
RUN pip3 install -U setuptools
RUN ln -s /usr/bin/pip3 /usr/bin/pip
RUN apt-get install -yy tcsh''',
u'tcsh'),
('thefuck/ubuntu-python2-tcsh',
u'''FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python python-pip python-dev git
RUN pip2 install -U pip setuptools
RUN apt-get install -yy tcsh''',
u'tcsh'))
@pytest.fixture(params=containers)
def proc(request):
tag, dockerfile = request.param
proc = spawn(request, tag, dockerfile, u'tcsh')
def proc(request, spawnu, run_without_docker):
proc = spawnu(*request.param)
if not run_without_docker:
proc.sendline(u'pip install /src')
proc.sendline(u'tcsh')
proc.sendline(u'eval `thefuck --alias`')
return proc
@functional
def test_with_confirmation(proc):
with_confirmation(proc)
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_with_confirmation(proc, TIMEOUT):
with_confirmation(proc, TIMEOUT)
@functional
def test_select_command_with_arrows(proc):
select_command_with_arrows(proc)
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_select_command_with_arrows(proc, TIMEOUT):
select_command_with_arrows(proc, TIMEOUT)
@functional
def test_refuse_with_confirmation(proc):
refuse_with_confirmation(proc)
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_refuse_with_confirmation(proc, TIMEOUT):
refuse_with_confirmation(proc, TIMEOUT)
@functional
def test_without_confirmation(proc):
without_confirmation(proc)
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_without_confirmation(proc, TIMEOUT):
without_confirmation(proc, TIMEOUT)
# TODO: ensure that history changes.

View File

@@ -1,29 +1,30 @@
import pytest
from tests.functional.utils import spawn, functional, images
from tests.functional.plots import with_confirmation, without_confirmation, \
refuse_with_confirmation, history_changed, history_not_changed, select_command_with_arrows
refuse_with_confirmation, history_changed, history_not_changed, \
select_command_with_arrows, how_to_configure
containers = images(('ubuntu-python3-zsh', u'''
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python3 python3-pip python3-dev git
RUN pip3 install -U setuptools
RUN ln -s /usr/bin/pip3 /usr/bin/pip
RUN apt-get install -yy zsh
'''),
('ubuntu-python2-zsh', u'''
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python python-pip python-dev git
RUN pip2 install -U pip setuptools
RUN apt-get install -yy zsh
'''))
containers = (('thefuck/ubuntu-python3-zsh',
u'''FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python3 python3-pip python3-dev git
RUN pip3 install -U setuptools
RUN ln -s /usr/bin/pip3 /usr/bin/pip
RUN apt-get install -yy zsh''',
u'zsh'),
('thefuck/ubuntu-python2-zsh',
u'''FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python python-pip python-dev git
RUN pip2 install -U pip setuptools
RUN apt-get install -yy zsh''',
u'zsh'))
@pytest.fixture(params=containers)
def proc(request):
tag, dockerfile = request.param
proc = spawn(request, tag, dockerfile, u'zsh')
def proc(request, spawnu, run_without_docker):
proc = spawnu(*request.param)
if not run_without_docker:
proc.sendline(u'pip install /src')
proc.sendline(u'eval $(thefuck --alias)')
proc.sendline(u'export HISTFILE=~/.zsh_history')
proc.sendline(u'echo > $HISTFILE')
@@ -33,25 +34,35 @@ def proc(request):
return proc
@functional
def test_with_confirmation(proc):
with_confirmation(proc)
history_changed(proc, u'echo test')
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_with_confirmation(proc, TIMEOUT):
with_confirmation(proc, TIMEOUT)
history_changed(proc, TIMEOUT, u'echo test')
@functional
def test_select_command_with_arrows(proc):
select_command_with_arrows(proc)
history_changed(proc, u'git push')
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_select_command_with_arrows(proc, TIMEOUT):
select_command_with_arrows(proc, TIMEOUT)
history_changed(proc, TIMEOUT, u'git help')
@functional
def test_refuse_with_confirmation(proc):
refuse_with_confirmation(proc)
history_not_changed(proc)
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_refuse_with_confirmation(proc, TIMEOUT):
refuse_with_confirmation(proc, TIMEOUT)
history_not_changed(proc, TIMEOUT)
@functional
def test_without_confirmation(proc):
without_confirmation(proc)
history_changed(proc, u'echo test')
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_without_confirmation(proc, TIMEOUT):
without_confirmation(proc, TIMEOUT)
history_changed(proc, TIMEOUT, u'echo test')
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_how_to_configure_alias(proc, TIMEOUT):
how_to_configure(proc, TIMEOUT)

View File

@@ -1,65 +0,0 @@
import pytest
import os
import subprocess
import shutil
from tempfile import mkdtemp
from pathlib import Path
import sys
import pexpect
from tests.utils import root
bare = os.environ.get('BARE')
enabled = os.environ.get('FUNCTIONAL')
def build_container(tag, dockerfile, copy_src=False):
tmpdir = mkdtemp()
try:
if copy_src:
subprocess.call(['cp', '-a', str(root), tmpdir])
dockerfile_path = Path(tmpdir).joinpath('Dockerfile')
with dockerfile_path.open('w') as file:
file.write(dockerfile)
if subprocess.call(['docker', 'build', '--tag={}'.format(tag), tmpdir]) != 0:
raise Exception("Can't build a container")
finally:
shutil.rmtree(tmpdir)
def spawn(request, tag, dockerfile, cmd, install=True, copy_src=False):
if bare:
proc = pexpect.spawnu(cmd)
else:
tag = 'thefuck/{}'.format(tag)
build_container(tag, dockerfile, copy_src)
proc = pexpect.spawnu('docker run --rm=true --volume {}:/src --tty=true '
'--interactive=true {} {}'.format(root, tag, cmd))
if install:
proc.sendline('pip install /src')
proc.sendline('cd /')
proc.logfile = sys.stdout
def _finalizer():
proc.terminate()
if not bare:
container_id = subprocess.check_output(['docker', 'ps']) \
.decode('utf-8').split('\n')[-2].split()[0]
subprocess.check_call(['docker', 'kill', container_id])
request.addfinalizer(_finalizer)
return proc
def images(*items):
if bare:
return [items[0]]
else:
return items
functional = pytest.mark.skipif(
not enabled,
reason='Functional tests are disabled by default.')

View File

@@ -11,7 +11,7 @@ from tests.utils import Command
@pytest.mark.parametrize('command', [
Command(script='vim', stderr='vim: command not found')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command, return_value', [
@@ -24,7 +24,7 @@ def test_match(command):
def test_match_mocked(cmdnf_mock, command, return_value):
get_packages = Mock(return_value=return_value)
cmdnf_mock.CommandNotFound.return_value = Mock(getPackages=get_packages)
assert match(command, None)
assert match(command)
assert cmdnf_mock.CommandNotFound.called
assert get_packages.called
@@ -32,7 +32,7 @@ def test_match_mocked(cmdnf_mock, command, return_value):
@pytest.mark.parametrize('command', [
Command(script='vim', stderr=''), Command()])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
# python-commandnotfound is available in ubuntu 14.04+
@@ -44,7 +44,7 @@ def test_not_match(command):
(Command('sudo vim'), 'sudo apt-get install vim && sudo vim'),
(Command('sudo convert'), 'sudo apt-get install imagemagick && sudo convert')])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command
@pytest.mark.parametrize('command, new_command, return_value', [
@@ -63,4 +63,4 @@ def test_get_new_command(command, new_command):
def test_get_new_command_mocked(cmdnf_mock, command, new_command, return_value):
get_packages = Mock(return_value=return_value)
cmdnf_mock.CommandNotFound.return_value = Mock(getPackages=get_packages)
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -4,7 +4,7 @@ from tests.utils import Command
def test_match():
assert match(Command('apt-get search foo'), None)
assert match(Command('apt-get search foo'))
@pytest.mark.parametrize('command', [
@@ -18,8 +18,8 @@ def test_match():
Command('apt-get update')
])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
def test_get_new_command():
assert get_new_command(Command('apt-get search foo'), None) == 'apt-cache search foo'
assert get_new_command(Command('apt-get search foo')) == 'apt-cache search foo'

View File

@@ -28,9 +28,9 @@ def _is_not_okay_to_test():
def test_match(brew_no_available_formula, brew_already_installed,
brew_install_no_argument):
assert match(Command('brew install elsticsearch',
stderr=brew_no_available_formula), None)
stderr=brew_no_available_formula))
assert not match(Command('brew install git',
stderr=brew_already_installed), None)
stderr=brew_already_installed))
assert not match(Command('brew install', stderr=brew_install_no_argument),
None)
@@ -39,7 +39,7 @@ def test_match(brew_no_available_formula, brew_already_installed,
reason='No need to run if there\'s no formula')
def test_get_new_command(brew_no_available_formula):
assert get_new_command(Command('brew install elsticsearch',
stderr=brew_no_available_formula), None)\
stderr=brew_no_available_formula))\
== 'brew install elasticsearch'
assert get_new_command(Command('brew install aa',

View File

@@ -15,15 +15,15 @@ def brew_unknown_cmd2():
def test_match(brew_unknown_cmd):
assert match(Command('brew inst', stderr=brew_unknown_cmd), None)
assert match(Command('brew inst', stderr=brew_unknown_cmd))
for command in _brew_commands():
assert not match(Command('brew ' + command), None)
assert not match(Command('brew ' + command))
def test_get_new_command(brew_unknown_cmd, brew_unknown_cmd2):
assert get_new_command(Command('brew inst', stderr=brew_unknown_cmd),
None) == ['brew list', 'brew install', 'brew uninstall']
assert get_new_command(Command('brew inst', stderr=brew_unknown_cmd)) \
== ['brew list', 'brew install', 'brew uninstall']
cmds = get_new_command(Command('brew instaa', stderr=brew_unknown_cmd2), None)
cmds = get_new_command(Command('brew instaa', stderr=brew_unknown_cmd2))
assert 'brew install' in cmds
assert 'brew uninstall' in cmds

View File

@@ -6,10 +6,10 @@ from tests.utils import Command
@pytest.mark.parametrize('command', [
Command(script='brew upgrade')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('brew upgrade'), 'brew upgrade --all')])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -12,10 +12,10 @@ no_such_subcommand = """No such subcommand
@pytest.mark.parametrize('command', [
Command(script='cargo buid', stderr=no_such_subcommand)])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('cargo buid', stderr=no_such_subcommand), 'cargo build')])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -1,5 +1,5 @@
import pytest
from thefuck.rules.cd_mkdir import match, get_new_command
from thefuck.rules.cd_correction import match, get_new_command
from tests.utils import Command
@@ -9,17 +9,17 @@ from tests.utils import Command
stderr='cd: foo: No such file or directory'),
Command(script='cd foo/bar/baz', stderr='cd: can\'t cd to foo/bar/baz')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
Command(script='cd foo', stderr=''), Command()])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('cd foo'), 'mkdir -p foo && cd foo'),
(Command('cd foo/bar/baz'), 'mkdir -p foo/bar/baz && cd foo/bar/baz')])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -3,10 +3,10 @@ from tests.utils import Command
def test_match():
assert match(Command('cd..', stderr='cd..: command not found'), None)
assert not match(Command(), None)
assert match(Command('cd..', stderr='cd..: command not found'))
assert not match(Command())
def test_get_new_command():
assert get_new_command(
Command('cd..'), None) == 'cd ..'
Command('cd..')) == 'cd ..'

View File

@@ -41,17 +41,16 @@ def composer_not_command_one_of_this():
def test_match(composer_not_command, composer_not_command_one_of_this):
assert match(Command('composer udpate',
stderr=composer_not_command), None)
stderr=composer_not_command))
assert match(Command('composer pdate',
stderr=composer_not_command_one_of_this), None)
assert not match(Command('ls update', stderr=composer_not_command),
None)
stderr=composer_not_command_one_of_this))
assert not match(Command('ls update', stderr=composer_not_command))
def test_get_new_command(composer_not_command, composer_not_command_one_of_this):
assert get_new_command(Command('composer udpate',
stderr=composer_not_command), None) \
stderr=composer_not_command)) \
== 'composer update'
assert get_new_command(
Command('composer pdate', stderr=composer_not_command_one_of_this),
None) == 'composer selfupdate'
Command('composer pdate', stderr=composer_not_command_one_of_this)) \
== 'composer selfupdate'

View File

@@ -7,7 +7,7 @@ from tests.utils import Command
('cp dir', 'cp: dor: is a directory'),
('cp dir', "cp: omitting directory 'dir'")])
def test_match(script, stderr):
assert match(Command(script, stderr=stderr), None)
assert match(Command(script, stderr=stderr))
@pytest.mark.parametrize('script, stderr', [
@@ -15,8 +15,8 @@ def test_match(script, stderr):
('some dir', "cp: omitting directory 'dir'"),
('cp dir', '')])
def test_not_match(script, stderr):
assert not match(Command(script, stderr=stderr), None)
assert not match(Command(script, stderr=stderr))
def test_get_new_command():
assert get_new_command(Command(script='cp dir'), None) == 'cp -a dir'
assert get_new_command(Command(script='cp dir')) == 'cp -a dir'

View File

@@ -11,8 +11,9 @@ def tar_error(tmpdir):
path = os.path.join(str(tmpdir), filename)
def reset(path):
os.mkdir('d')
with tarfile.TarFile(path, 'w') as archive:
for file in ('a', 'b', 'c'):
for file in ('a', 'b', 'c', 'd/e'):
with open(file, 'w') as f:
f.write('*')
@@ -26,7 +27,8 @@ def tar_error(tmpdir):
os.chdir(str(tmpdir))
reset(path)
assert(set(os.listdir('.')) == {filename, 'a', 'b', 'c'})
assert set(os.listdir('.')) == {filename, 'a', 'b', 'c', 'd'}
assert set(os.listdir('./d')) == {'e'}
return fixture
@@ -45,19 +47,19 @@ parametrize_script = pytest.mark.parametrize('script, fixed', [
@parametrize_script
def test_match(tar_error, filename, script, fixed):
tar_error(filename)
assert match(Command(script=script.format(filename)), None)
assert match(Command(script=script.format(filename)))
@parametrize_filename
@parametrize_script
def test_side_effect(tar_error, filename, script, fixed):
tar_error(filename)
side_effect(Command(script=script.format(filename)), None, None)
assert(os.listdir('.') == [filename])
side_effect(Command(script=script.format(filename)), None)
assert set(os.listdir('.')) == {filename, 'd'}
@parametrize_filename
@parametrize_script
def test_get_new_command(tar_error, filename, script, fixed):
tar_error(filename)
assert get_new_command(Command(script=script.format(filename)), None) == fixed.format(filename)
assert get_new_command(Command(script=script.format(filename))) == fixed.format(filename)

View File

@@ -15,31 +15,34 @@ def zip_error(tmpdir):
archive.writestr('b', '2')
archive.writestr('c', '3')
archive.writestr('d/e', '4')
archive.extractall()
os.chdir(str(tmpdir))
reset(path)
assert(set(os.listdir('.')) == {'foo.zip', 'a', 'b', 'c'})
assert set(os.listdir('.')) == {'foo.zip', 'a', 'b', 'c', 'd'}
assert set(os.listdir('./d')) == {'e'}
@pytest.mark.parametrize('script', [
'unzip foo',
'unzip foo.zip'])
def test_match(zip_error, script):
assert match(Command(script=script), None)
assert match(Command(script=script))
@pytest.mark.parametrize('script', [
'unzip foo',
'unzip foo.zip'])
def test_side_effect(zip_error, script):
side_effect(Command(script=script), None, None)
assert(os.listdir('.') == ['foo.zip'])
side_effect(Command(script=script), None)
assert set(os.listdir('.')) == {'foo.zip', 'd'}
@pytest.mark.parametrize('script,fixed', [
('unzip foo', 'unzip foo -d foo'),
('unzip foo.zip', 'unzip foo.zip -d foo')])
def test_get_new_command(zip_error, script, fixed):
assert get_new_command(Command(script=script), None) == fixed
assert get_new_command(Command(script=script)) == fixed

View File

@@ -41,13 +41,13 @@ south.exceptions.GhostMigrations:
def test_match(stderr):
assert match(Command('./manage.py migrate', stderr=stderr), None)
assert match(Command('python manage.py migrate', stderr=stderr), None)
assert not match(Command('./manage.py migrate'), None)
assert not match(Command('app migrate', stderr=stderr), None)
assert not match(Command('./manage.py test', stderr=stderr), None)
assert match(Command('./manage.py migrate', stderr=stderr))
assert match(Command('python manage.py migrate', stderr=stderr))
assert not match(Command('./manage.py migrate'))
assert not match(Command('app migrate', stderr=stderr))
assert not match(Command('./manage.py test', stderr=stderr))
def test_get_new_command():
assert get_new_command(Command('./manage.py migrate auth'), None)\
assert get_new_command(Command('./manage.py migrate auth'))\
== './manage.py migrate auth --delete-ghost-migrations'

View File

@@ -31,13 +31,13 @@ The following options are available:
def test_match(stderr):
assert match(Command('./manage.py migrate', stderr=stderr), None)
assert match(Command('python manage.py migrate', stderr=stderr), None)
assert not match(Command('./manage.py migrate'), None)
assert not match(Command('app migrate', stderr=stderr), None)
assert not match(Command('./manage.py test', stderr=stderr), None)
assert match(Command('./manage.py migrate', stderr=stderr))
assert match(Command('python manage.py migrate', stderr=stderr))
assert not match(Command('./manage.py migrate'))
assert not match(Command('app migrate', stderr=stderr))
assert not match(Command('./manage.py test', stderr=stderr))
def test_get_new_command():
assert get_new_command(Command('./manage.py migrate auth'), None) \
assert get_new_command(Command('./manage.py migrate auth')) \
== './manage.py migrate auth --merge'

View File

@@ -110,14 +110,14 @@ def stderr(cmd):
def test_match():
assert match(Command('docker pes', stderr=stderr('pes')), None)
assert match(Command('docker pes', stderr=stderr('pes')))
@pytest.mark.parametrize('script, stderr', [
('docker ps', ''),
('cat pes', stderr('pes'))])
def test_not_match(script, stderr):
assert not match(Command(script, stderr=stderr), None)
assert not match(Command(script, stderr=stderr))
@pytest.mark.usefixtures('docker_help')
@@ -126,4 +126,4 @@ def test_not_match(script, stderr):
('tags', ['tag', 'stats', 'images'])])
def test_get_new_command(wrong, fixed):
command = Command('docker {}'.format(wrong), stderr=stderr(wrong))
assert get_new_command(command, None) == ['docker {}'.format(x) for x in fixed]
assert get_new_command(command) == ['docker {}'.format(x) for x in fixed]

View File

@@ -7,11 +7,11 @@ from tests.utils import Command
Command(script='cd cd foo'),
Command(script='git git push origin/master')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('cd cd foo'), 'cd foo'),
(Command('git git push origin/master'), 'git push origin/master')])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -11,12 +11,12 @@ def test_match():
"""
assert match(Command(u'ps -ef | grep foo',
stderr=u'-bash:  grep: command not found'), None)
assert not match(Command('ps -ef | grep foo'), None)
assert not match(Command(), None)
stderr=u'-bash:  grep: command not found'))
assert not match(Command('ps -ef | grep foo'))
assert not match(Command())
def test_get_new_command():
""" Replace the Alt+Space character by a simple space """
assert get_new_command(Command(u'ps -ef | grep foo'), None)\
assert get_new_command(Command(u'ps -ef | grep foo'))\
== 'ps -ef | grep foo'

View File

@@ -2,7 +2,6 @@ import pytest
import os
from thefuck.rules.fix_file import match, get_new_command
from tests.utils import Command
from thefuck.types import Settings
# (script, file, line, col (or None), stdout, stderr)
@@ -184,7 +183,7 @@ E NameError: name 'mocker' is not defined
def test_match(mocker, monkeypatch, test):
mocker.patch('os.path.isfile', return_value=True)
monkeypatch.setenv('EDITOR', 'dummy_editor')
assert match(Command(stdout=test[4], stderr=test[5]), None)
assert match(Command(stdout=test[4], stderr=test[5]))
@pytest.mark.parametrize('test', tests)
@@ -194,7 +193,7 @@ def test_no_editor(mocker, monkeypatch, test):
if 'EDITOR' in os.environ:
monkeypatch.delenv('EDITOR')
assert not match(Command(stdout=test[4], stderr=test[5]), None)
assert not match(Command(stdout=test[4], stderr=test[5]))
@pytest.mark.parametrize('test', tests)
@@ -203,7 +202,7 @@ def test_not_file(mocker, monkeypatch, test):
mocker.patch('os.path.isfile', return_value=False)
monkeypatch.setenv('EDITOR', 'dummy_editor')
assert not match(Command(stdout=test[4], stderr=test[5]), None)
assert not match(Command(stdout=test[4], stderr=test[5]))
@pytest.mark.parametrize('test', tests)
@@ -219,16 +218,16 @@ def test_get_new_command(mocker, monkeypatch, test):
@pytest.mark.parametrize('test', tests)
@pytest.mark.usefixtures('no_memoize')
def test_get_new_command_with_settings(mocker, monkeypatch, test):
def test_get_new_command_with_settings(mocker, monkeypatch, test, settings):
mocker.patch('os.path.isfile', return_value=True)
monkeypatch.setenv('EDITOR', 'dummy_editor')
cmd = Command(script=test[0], stdout=test[4], stderr=test[5])
settings = Settings({'fixcolcmd': '{editor} {file} +{line}:{col}'})
settings.fixcolcmd = '{editor} {file} +{line}:{col}'
if test[3]:
assert (get_new_command(cmd, settings) ==
assert (get_new_command(cmd) ==
'dummy_editor {} +{}:{} && {}'.format(test[1], test[2], test[3], test[0]))
else:
assert (get_new_command(cmd, settings) ==
assert (get_new_command(cmd) ==
'dummy_editor {} +{} && {}'.format(test[1], test[2], test[0]))

View File

@@ -18,7 +18,7 @@ def did_not_match(target, did_you_forget=True):
Command(script='git commit unknown',
stderr=did_not_match('unknown'))]) # Older versions of Git
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
@@ -27,7 +27,7 @@ def test_match(command):
Command(script='git commit unknown', # Newer versions of Git
stderr=did_not_match('unknown', False))])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
@@ -36,4 +36,4 @@ def test_not_match(command):
(Command('git commit unknown', stderr=did_not_match('unknown')), # Old Git
'git add -- unknown && git commit unknown')])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -12,11 +12,11 @@ If you are sure you want to delete it, run 'git branch -D branch'.
def test_match(stderr):
assert match(Command('git branch -d branch', stderr=stderr), None)
assert not match(Command('git branch -d branch'), None)
assert not match(Command('ls', stderr=stderr), None)
assert match(Command('git branch -d branch', stderr=stderr))
assert not match(Command('git branch -d branch'))
assert not match(Command('ls', stderr=stderr))
def test_get_new_command(stderr):
assert get_new_command(Command('git branch -d branch', stderr=stderr), None)\
assert get_new_command(Command('git branch -d branch', stderr=stderr))\
== "git branch -D branch"

View File

@@ -4,16 +4,16 @@ from tests.utils import Command
def test_match():
assert match(Command('git branch list'), None)
assert match(Command('git branch list'))
def test_not_match():
assert not match(Command(), None)
assert not match(Command('git commit'), None)
assert not match(Command('git branch'), None)
assert not match(Command('git stash list'), None)
assert not match(Command())
assert not match(Command('git commit'))
assert not match(Command('git branch'))
assert not match(Command('git stash list'))
def test_get_new_command():
assert (get_new_command(Command('git branch list'), None) ==
assert (get_new_command(Command('git branch list')) ==
shells.and_('git branch --delete list', 'git branch'))

View File

@@ -21,7 +21,7 @@ def get_branches(mocker):
Command(script='git checkout unknown', stderr=did_not_match('unknown')),
Command(script='git commit unknown', stderr=did_not_match('unknown'))])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
@@ -30,7 +30,7 @@ def test_match(command):
Command(script='git checkout known', stderr=('')),
Command(script='git commit known', stderr=(''))])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('branches, command, new_command', [
@@ -50,4 +50,4 @@ def test_not_match(command):
'git commit test-random-branch-123')])
def test_get_new_command(branches, command, new_command, get_branches):
get_branches.return_value = branches
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -7,7 +7,7 @@ from tests.utils import Command
Command(script='git diff foo'),
Command(script='git diff')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
@@ -16,11 +16,11 @@ def test_match(command):
Command(script='git branch'),
Command(script='git log')])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('git diff'), 'git diff --staged'),
(Command('git diff foo'), 'git diff --staged foo')])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -20,7 +20,11 @@ usage: git stash list [<options>]
'git stash Some message',
'git stash saev Some message'])
def test_match(wrong):
assert match(Command(wrong, stderr=git_stash_err), None)
assert match(Command(wrong, stderr=git_stash_err))
def test_not_match():
assert not match(Command("git", stderr=git_stash_err))
@pytest.mark.parametrize('wrong,fixed', [
@@ -28,4 +32,4 @@ def test_match(wrong):
('git stash Some message', 'git stash save Some message'),
('git stash saev Some message', 'git stash save Some message')])
def test_get_new_command(wrong, fixed):
assert get_new_command(Command(wrong, stderr=git_stash_err), None) == fixed
assert get_new_command(Command(wrong, stderr=git_stash_err)) == fixed

View File

@@ -41,17 +41,17 @@ def git_command():
def test_match(git_not_command, git_command, git_not_command_one_of_this):
assert match(Command('git brnch', stderr=git_not_command), None)
assert match(Command('git st', stderr=git_not_command_one_of_this), None)
assert not match(Command('ls brnch', stderr=git_not_command), None)
assert not match(Command('git branch', stderr=git_command), None)
assert match(Command('git brnch', stderr=git_not_command))
assert match(Command('git st', stderr=git_not_command_one_of_this))
assert not match(Command('ls brnch', stderr=git_not_command))
assert not match(Command('git branch', stderr=git_command))
def test_get_new_command(git_not_command, git_not_command_one_of_this,
git_not_command_closest):
assert get_new_command(Command('git brnch', stderr=git_not_command), None) \
assert get_new_command(Command('git brnch', stderr=git_not_command)) \
== ['git branch']
assert get_new_command(Command('git st', stderr=git_not_command_one_of_this),
None) == ['git stats', 'git stash', 'git stage']
assert get_new_command(Command('git tags', stderr=git_not_command_closest),
None) == ['git tag', 'git stage']
assert get_new_command(Command('git st', stderr=git_not_command_one_of_this)) \
== ['git stats', 'git stash', 'git stage']
assert get_new_command(Command('git tags', stderr=git_not_command_closest)) \
== ['git tag', 'git stage']

View File

@@ -19,11 +19,11 @@ If you wish to set tracking information for this branch you can do so with:
def test_match(stderr):
assert match(Command('git pull', stderr=stderr), None)
assert not match(Command('git pull'), None)
assert not match(Command('ls', stderr=stderr), None)
assert match(Command('git pull', stderr=stderr))
assert not match(Command('git pull'))
assert not match(Command('ls', stderr=stderr))
def test_get_new_command(stderr):
assert get_new_command(Command('git pull', stderr=stderr), None) \
assert get_new_command(Command('git pull', stderr=stderr)) \
== "git branch --set-upstream-to=origin/master master && git pull"

View File

@@ -12,10 +12,10 @@ Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).
@pytest.mark.parametrize('command', [
Command(script='git pull git@github.com:mcarton/thefuck.git', stderr=git_err)])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command, output', [
(Command(script='git pull git@github.com:mcarton/thefuck.git', stderr=git_err), 'git clone git@github.com:mcarton/thefuck.git')])
def test_get_new_command(command, output):
assert get_new_command(command, None) == output
assert get_new_command(command) == output

View File

@@ -14,11 +14,11 @@ To push the current branch and set the remote as upstream, use
def test_match(stderr):
assert match(Command('git push master', stderr=stderr), None)
assert not match(Command('git push master'), None)
assert not match(Command('ls', stderr=stderr), None)
assert match(Command('git push master', stderr=stderr))
assert not match(Command('git push master'))
assert not match(Command('ls', stderr=stderr))
def test_get_new_command(stderr):
assert get_new_command(Command('git push', stderr=stderr), None)\
assert get_new_command(Command('git push', stderr=stderr))\
== "git push --set-upstream origin master"

View File

@@ -30,7 +30,7 @@ To /tmp/bar
Command(script='git push nvbn', stderr=git_err),
Command(script='git push nvbn master', stderr=git_err)])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
@@ -41,7 +41,7 @@ def test_match(command):
Command(script='git push nvbn', stderr=git_ok),
Command(script='git push nvbn master', stderr=git_uptodate)])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('command, output', [
@@ -49,4 +49,4 @@ def test_not_match(command):
(Command(script='git push nvbn', stderr=git_err), 'git push --force nvbn'),
(Command(script='git push nvbn master', stderr=git_err), 'git push --force nvbn master')])
def test_get_new_command(command, output):
assert get_new_command(command, None) == output
assert get_new_command(command) == output

View File

@@ -30,7 +30,7 @@ To /tmp/bar
Command(script='git push nvbn', stderr=git_err),
Command(script='git push nvbn master', stderr=git_err)])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
@@ -41,7 +41,7 @@ def test_match(command):
Command(script='git push nvbn', stderr=git_ok),
Command(script='git push nvbn master', stderr=git_uptodate)])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('command, output', [
@@ -51,4 +51,4 @@ def test_not_match(command):
(Command(script='git push nvbn master', stderr=git_err),
'git pull nvbn master && git push nvbn master')])
def test_get_new_command(command, output):
assert get_new_command(command, None) == output
assert get_new_command(command) == output

View File

@@ -18,14 +18,14 @@ rebase_error = (
Command(script='git cherry-pick a1b2c3d', stderr=cherry_pick_error),
Command(script='git rebase -i HEAD~7', stderr=rebase_error)])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
Command(script='git cherry-pick a1b2c3d', stderr=('')),
Command(script='git rebase -i HEAD~7', stderr=(''))])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
@@ -34,4 +34,4 @@ def test_not_match(command):
(Command('git rebase -i HEAD~7', stderr=rebase_error),
'git stash && git rebase -i HEAD~7')])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -7,11 +7,11 @@ from tests.utils import Command
Command(script='go run foo'),
Command(script='go run bar')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('go run foo'), 'go run foo.go'),
(Command('go run bar'), 'go run bar.go')])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -3,10 +3,10 @@ from tests.utils import Command
def test_match():
assert match(Command('grep blah .', stderr='grep: .: Is a directory'), None)
assert not match(Command(), None)
assert match(Command('grep blah .', stderr='grep: .: Is a directory'))
assert not match(Command())
def test_get_new_command():
assert get_new_command(
Command('grep blah .'), None) == 'grep -r blah .'
Command('grep blah .')) == 'grep -r blah .'

View File

@@ -11,18 +11,18 @@ def stdout(task):
def test_match():
assert match(Command('gulp srve', stdout('srve')), None)
assert match(Command('gulp srve', stdout('srve')))
@pytest.mark.parametrize('script, stdout', [
('gulp serve', ''),
('cat srve', stdout('srve'))])
def test_not_march(script, stdout):
assert not match(Command(script, stdout), None)
assert not match(Command(script, stdout))
def test_get_new_command(mocker):
mocker.patch('thefuck.rules.gulp_not_task.get_gulp_tasks', return_value=[
'serve', 'build', 'default'])
command = Command('gulp srve', stdout('srve'))
assert get_new_command(command, None) == ['gulp serve', 'gulp default']
assert get_new_command(command) == ['gulp serve', 'gulp default']

View File

@@ -4,17 +4,14 @@ from thefuck.rules.has_exists_script import match, get_new_command
def test_match():
with patch('os.path.exists', return_value=True):
assert match(Mock(script='main', stderr='main: command not found'),
None)
assert match(Mock(script='main', stderr='main: command not found'))
assert match(Mock(script='main --help',
stderr='main: command not found'),
None)
assert not match(Mock(script='main', stderr=''), None)
stderr='main: command not found'))
assert not match(Mock(script='main', stderr=''))
with patch('os.path.exists', return_value=False):
assert not match(Mock(script='main', stderr='main: command not found'),
None)
assert not match(Mock(script='main', stderr='main: command not found'))
def test_get_new_command():
assert get_new_command(Mock(script='main --help'), None) == './main --help'
assert get_new_command(Mock(script='main --help')) == './main --help'

View File

@@ -16,14 +16,14 @@ no_suggest_stderr = ''' ! `aaaaa` is not a heroku command.
@pytest.mark.parametrize('cmd', ['log', 'pge'])
def test_match(cmd):
assert match(
Command('heroku {}'.format(cmd), stderr=suggest_stderr(cmd)), None)
Command('heroku {}'.format(cmd), stderr=suggest_stderr(cmd)))
@pytest.mark.parametrize('script, stderr', [
('cat log', suggest_stderr('log')),
('heroku aaa', no_suggest_stderr)])
def test_not_match(script, stderr):
assert not match(Command(script, stderr=stderr), None)
assert not match(Command(script, stderr=stderr))
@pytest.mark.parametrize('cmd, result', [
@@ -31,4 +31,4 @@ def test_not_match(script, stderr):
('pge', ['heroku pg', 'heroku logs'])])
def test_get_new_command(cmd, result):
command = Command('heroku {}'.format(cmd), stderr=suggest_stderr(cmd))
assert get_new_command(command, None) == result
assert get_new_command(command) == result

View File

@@ -25,13 +25,13 @@ def callables(mocker):
@pytest.mark.usefixtures('history', 'callables', 'no_memoize', 'alias')
@pytest.mark.parametrize('script', ['ls cet', 'daff x'])
def test_match(script):
assert match(Command(script=script), None)
assert match(Command(script=script))
@pytest.mark.usefixtures('history', 'callables', 'no_memoize', 'alias')
@pytest.mark.parametrize('script', ['apt-get', 'nocommand y'])
def test_not_match(script):
assert not match(Command(script=script), None)
assert not match(Command(script=script))
@pytest.mark.usefixtures('history', 'callables', 'no_memoize', 'alias')
@@ -39,4 +39,4 @@ def test_not_match(script):
('ls cet', 'ls cat'),
('daff x', 'diff x')])
def test_get_new_command(script, result):
assert get_new_command(Command(script), None) == result
assert get_new_command(Command(script)) == result

View File

@@ -7,11 +7,11 @@ from tests.utils import Command
Command(script='java foo.java'),
Command(script='java bar.java')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('java foo.java'), 'java foo'),
(Command('java bar.java'), 'java bar')])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -7,11 +7,11 @@ from tests.utils import Command
Command(script='javac foo'),
Command(script='javac bar')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('javac foo'), 'javac foo.java'),
(Command('javac bar'), 'javac bar.java')])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -14,10 +14,10 @@ Did you mean this?
def test_match(is_not_task):
assert match(Command(script='lein rpl', stderr=is_not_task), None)
assert not match(Command(script='ls', stderr=is_not_task), None)
assert match(Command(script='lein rpl', stderr=is_not_task))
assert not match(Command(script='ls', stderr=is_not_task))
def test_get_new_command(is_not_task):
assert get_new_command(Command(script='lein rpl --help', stderr=is_not_task),
None) == ['lein repl --help', 'lein jar --help']
assert get_new_command(Command(script='lein rpl --help', stderr=is_not_task)) \
== ['lein repl --help', 'lein jar --help']

View File

@@ -3,14 +3,14 @@ from tests.utils import Command
def test_match():
assert match(Command(script='ls'), None)
assert match(Command(script='ls file.py'), None)
assert match(Command(script='ls /opt'), None)
assert not match(Command(script='ls -lah /opt'), None)
assert not match(Command(script='pacman -S binutils'), None)
assert not match(Command(script='lsof'), None)
assert match(Command(script='ls'))
assert match(Command(script='ls file.py'))
assert match(Command(script='ls /opt'))
assert not match(Command(script='ls -lah /opt'))
assert not match(Command(script='pacman -S binutils'))
assert not match(Command(script='lsof'))
def test_get_new_command():
assert get_new_command(Command(script='ls file.py'), None) == 'ls -lah file.py'
assert get_new_command(Command(script='ls'), None) == 'ls -lah'
assert get_new_command(Command(script='ls file.py')) == 'ls -lah file.py'
assert get_new_command(Command(script='ls')) == 'ls -lah'

View File

@@ -12,14 +12,14 @@ from tests.utils import Command
Command('man -s 2 read'),
Command('man -s 3 read')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
Command('man'),
Command('man ')])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
@@ -31,4 +31,4 @@ def test_not_match(command):
(Command('man -s 2 read'), 'man -s 3 read'),
(Command('man -s 3 read'), 'man -s 2 read')])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -3,10 +3,10 @@ from tests.utils import Command
def test_match():
assert match(Command('mandiff', stderr='mandiff: command not found'), None)
assert not match(Command(), None)
assert match(Command('mandiff', stderr='mandiff: command not found'))
assert not match(Command())
def test_get_new_command():
assert get_new_command(
Command('mandiff'), None) == 'man diff'
Command('mandiff')) == 'man diff'

View File

@@ -37,7 +37,7 @@ from thefuck.rules.mercurial import (
)),
])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
@@ -63,7 +63,7 @@ def test_match(command):
)),
])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('command, possibilities', [
@@ -131,4 +131,4 @@ def test_extract_possibilities(command, possibilities):
)), 'hg rebase re'),
])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -9,7 +9,7 @@ from tests.utils import Command
Command('hdfs dfs -mkdir foo/bar/baz', stderr='mkdir: `foo/bar/baz\': No such file or directory')
])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
@@ -19,7 +19,7 @@ def test_match(command):
Command('./bin/hdfs dfs -mkdir foo/bar/baz'),
Command()])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
@@ -27,5 +27,5 @@ def test_not_match(command):
(Command('hdfs dfs -mkdir foo/bar/baz'), 'hdfs dfs -mkdir -p foo/bar/baz'),
(Command('./bin/hdfs dfs -mkdir foo/bar/baz'), './bin/hdfs dfs -mkdir -p foo/bar/baz')])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -6,7 +6,7 @@ from tests.utils import Command
@pytest.mark.parametrize('command', [
Command(script='mvn', stdout='[ERROR] No goals have been specified for this build. You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1]')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
@@ -30,11 +30,11 @@ def test_match(command):
Command(script='mvn -v')
])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
(Command(script='mvn', stdout='[ERROR] No goals have been specified for this build. You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1]'), ['mvn clean package', 'mvn clean install']),
(Command(script='mvn -N', stdout='[ERROR] No goals have been specified for this build. You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1]'), ['mvn -N clean package', 'mvn -N clean install'])])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -6,7 +6,7 @@ from tests.utils import Command
@pytest.mark.parametrize('command', [
Command(script='mvn cle', stdout='[ERROR] Unknown lifecycle phase "cle". You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1]')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
@@ -30,11 +30,11 @@ def test_match(command):
Command(script='mvn -v')
])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
(Command(script='mvn cle', stdout='[ERROR] Unknown lifecycle phase "cle". You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1]'), ['mvn clean', 'mvn compile']),
(Command(script='mvn claen package', stdout='[ERROR] Unknown lifecycle phase "claen". You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1]'), ['mvn clean package'])])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -11,19 +11,17 @@ def get_all_executables(mocker):
@pytest.mark.usefixtures('no_memoize')
def test_match():
assert match(Command(stderr='vom: not found', script='vom file.py'), None)
assert match(Command(stderr='fucck: not found', script='fucck'), None)
assert not match(Command(stderr='qweqwe: not found', script='qweqwe'), None)
assert not match(Command(stderr='some text', script='vom file.py'), None)
assert match(Command(stderr='vom: not found', script='vom file.py'))
assert match(Command(stderr='fucck: not found', script='fucck'))
assert not match(Command(stderr='qweqwe: not found', script='qweqwe'))
assert not match(Command(stderr='some text', script='vom file.py'))
@pytest.mark.usefixtures('no_memoize')
def test_get_new_command():
assert get_new_command(
Command(stderr='vom: not found',
script='vom file.py'),
None) == ['vim file.py']
script='vom file.py')) == ['vim file.py']
assert get_new_command(
Command(stderr='fucck: not found',
script='fucck'),
Command) == ['fsck']
script='fucck')) == ['fsck']

View File

@@ -8,7 +8,7 @@ from tests.utils import Command
Command(script='mv foo bar/', stderr="mv: cannot move 'foo' to 'bar/': No such file or directory"),
])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
@@ -16,7 +16,7 @@ def test_match(command):
Command(script='mv foo bar/foo', stderr="mv: permission denied"),
])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
@@ -24,4 +24,4 @@ def test_not_match(command):
(Command(script='mv foo bar/', stderr="mv: cannot move 'foo' to 'bar/': No such file or directory"), 'mkdir -p bar && mv foo bar/'),
])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -14,7 +14,7 @@ from tests.utils import Command
Command(script='gnome-open foo.com'),
Command(script='kde-open foo.com')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command, new_command', [
@@ -28,4 +28,4 @@ def test_match(command):
(Command('gnome-open foo.io'), 'gnome-open http://foo.io'),
(Command('kde-open foo.io'), 'kde-open http://foo.io')])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -23,7 +23,7 @@ extra/vim-python3 7.4.712-1 \t/usr/bin/vim'''
Command(script='vim', stderr='vim: command not found'),
Command(script='sudo vim', stderr='sudo: vim: command not found')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command, return_value', [
@@ -33,14 +33,14 @@ def test_match(command):
@patch.multiple(pacman, create=True, pacman=pacman_cmd)
def test_match_mocked(subp_mock, command, return_value):
subp_mock.check_output.return_value = return_value
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
Command(script='vim', stderr=''), Command(),
Command(script='sudo vim', stderr=''), Command()])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
sudo_vim_possibilities = ['{} -S extra/gvim && sudo vim',
@@ -66,7 +66,7 @@ vim_possibilities = [s.format(pacman_cmd) for s in vim_possibilities]
(Command('convert'), ['{} -S extra/imagemagick && convert'.format(pacman_cmd)]),
(Command('sudo convert'), ['{} -S extra/imagemagick && sudo convert'.format(pacman_cmd)])])
def test_get_new_command(command, new_command, mocker):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command
@pytest.mark.parametrize('command, new_command, return_value', [
@@ -79,4 +79,4 @@ def test_get_new_command(command, new_command, mocker):
@patch.multiple(pacman, create=True, pacman=pacman_cmd)
def test_get_new_command_mocked(subp_mock, command, new_command, return_value):
subp_mock.check_output.return_value = return_value
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -15,7 +15,7 @@ extra/llvm35 3.5.2-13/usr/bin/llc'''
Command(script='pacman llc', stderr='error: target not found: llc'),
Command(script='sudo pacman llc', stderr='error: target not found: llc')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
@@ -25,7 +25,7 @@ def test_match(command):
@patch('thefuck.specific.archlinux.subprocess')
def test_match_mocked(subp_mock, command):
subp_mock.check_output.return_value = PKGFILE_OUTPUT_LLC
assert match(command, None)
assert match(command)
@pytest.mark.skipif(not getattr(pacman_not_found, 'enabled_by_default', True),
@@ -35,7 +35,7 @@ def test_match_mocked(subp_mock, command):
(Command(script='pacman -S llc', stderr='error: target not found: llc'), ['pacman -S extra/llvm', 'pacman -S extra/llvm35']),
(Command(script='sudo pacman -S llc', stderr='error: target not found: llc'), ['sudo pacman -S extra/llvm', 'sudo pacman -S extra/llvm35'])])
def test_get_new_command(command, fixed):
assert get_new_command(command, None) == fixed
assert get_new_command(command) == fixed
@pytest.mark.parametrize('command, fixed', [
@@ -45,4 +45,4 @@ def test_get_new_command(command, fixed):
@patch('thefuck.specific.archlinux.subprocess')
def test_get_new_command_mocked(subp_mock, command, fixed):
subp_mock.check_output.return_value = PKGFILE_OUTPUT_LLC
assert get_new_command(command, None) == fixed
assert get_new_command(command) == fixed

View File

@@ -14,12 +14,11 @@ def pip_unknown_cmd_without_recommend():
def test_match(pip_unknown_cmd, pip_unknown_cmd_without_recommend):
assert match(Command('pip instatl', stderr=pip_unknown_cmd), None)
assert match(Command('pip instatl', stderr=pip_unknown_cmd))
assert not match(Command('pip i',
stderr=pip_unknown_cmd_without_recommend),
None)
stderr=pip_unknown_cmd_without_recommend))
def test_get_new_command(pip_unknown_cmd):
assert get_new_command(Command('pip instatl', stderr=pip_unknown_cmd),
None) == 'pip install'
assert get_new_command(Command('pip instatl',
stderr=pip_unknown_cmd)) == 'pip install'

View File

@@ -3,10 +3,10 @@ from tests.utils import Command
def test_match():
assert match(Command('temp.py', stderr='Permission denied'), None)
assert not match(Command(), None)
assert match(Command('temp.py', stderr='Permission denied'))
assert not match(Command())
def test_get_new_command():
assert get_new_command(Command('./test_sudo.py'), None)\
assert get_new_command(Command('./test_sudo.py'))\
== 'python ./test_sudo.py'

View File

@@ -7,11 +7,11 @@ from tests.utils import Command
Command(script='python foo'),
Command(script='python bar')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('python foo'), 'python foo.py'),
(Command('python bar'), 'python bar.py')])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -8,7 +8,7 @@ from tests.utils import Command
Command(script="git commit -am \"Mismatched Quotation Marks\'"),
Command(script="echo \"hello\'")])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command, new_command', [
@@ -16,4 +16,4 @@ def test_match(command):
(Command("git commit -am \"Mismatched Quotation Marks\'"), "git commit -am \"Mismatched Quotation Marks\""),
(Command("echo \"hello\'"), "echo \"hello\"")])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -10,7 +10,7 @@ from tests.utils import Command
Command('./bin/hdfs dfs -rm foo', stderr='rm: `foo`: Is a directory')
])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
@@ -19,13 +19,13 @@ def test_match(command):
Command('./bin/hdfs dfs -rm foo'),
Command()])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('rm foo'), 'rm -rf foo'),
(Command('hdfs dfs -rm foo'), 'hdfs dfs -rm -r foo')])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -5,7 +5,7 @@ from tests.utils import Command
def test_match():
assert match(Command(script='rm -rf /',
stderr='add --no-preserve-root'), None)
stderr='add --no-preserve-root'))
@pytest.mark.parametrize('command', [
@@ -13,9 +13,9 @@ def test_match():
Command(script='rm --no-preserve-root /', stderr='add --no-preserve-root'),
Command(script='rm -rf /', stderr='')])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
def test_get_new_command():
assert get_new_command(Command(script='rm -rf /'), None) \
assert get_new_command(Command(script='rm -rf /')) \
== 'rm -rf / --no-preserve-root'

View File

@@ -9,20 +9,20 @@ def sed_unterminated_s():
def test_match(sed_unterminated_s):
assert match(Command('sed -e s/foo/bar', stderr=sed_unterminated_s), None)
assert match(Command('sed -es/foo/bar', stderr=sed_unterminated_s), None)
assert match(Command('sed -e s/foo/bar -e s/baz/quz', stderr=sed_unterminated_s), None)
assert not match(Command('sed -e s/foo/bar'), None)
assert not match(Command('sed -es/foo/bar'), None)
assert not match(Command('sed -e s/foo/bar -e s/baz/quz'), None)
assert match(Command('sed -e s/foo/bar', stderr=sed_unterminated_s))
assert match(Command('sed -es/foo/bar', stderr=sed_unterminated_s))
assert match(Command('sed -e s/foo/bar -e s/baz/quz', stderr=sed_unterminated_s))
assert not match(Command('sed -e s/foo/bar'))
assert not match(Command('sed -es/foo/bar'))
assert not match(Command('sed -e s/foo/bar -e s/baz/quz'))
def test_get_new_command(sed_unterminated_s):
assert get_new_command(Command('sed -e s/foo/bar', stderr=sed_unterminated_s), None) \
assert get_new_command(Command('sed -e s/foo/bar', stderr=sed_unterminated_s)) \
== 'sed -e s/foo/bar/'
assert get_new_command(Command('sed -es/foo/bar', stderr=sed_unterminated_s), None) \
assert get_new_command(Command('sed -es/foo/bar', stderr=sed_unterminated_s)) \
== 'sed -es/foo/bar/'
assert get_new_command(Command(r"sed -e 's/\/foo/bar'", stderr=sed_unterminated_s), None) \
assert get_new_command(Command(r"sed -e 's/\/foo/bar'", stderr=sed_unterminated_s)) \
== r"sed -e 's/\/foo/bar/'"
assert get_new_command(Command(r"sed -e s/foo/bar -es/baz/quz", stderr=sed_unterminated_s), None) \
assert get_new_command(Command(r"sed -e s/foo/bar -es/baz/quz", stderr=sed_unterminated_s)) \
== r"sed -e s/foo/bar/ -es/baz/quz/"

View File

@@ -4,9 +4,9 @@ from tests.utils import Command
def test_match():
assert match(Command('sl'), None)
assert not match(Command('ls'), None)
assert match(Command('sl'))
assert not match(Command('ls'))
def test_get_new_command():
assert get_new_command(Command('sl'), None) == 'ls'
assert get_new_command(Command('sl')) == 'ls'

View File

@@ -44,23 +44,23 @@ Host key verification failed.""".format(path, '98.765.432.321')
def test_match(ssh_error):
errormsg, _, _, _ = ssh_error
assert match(Command('ssh', stderr=errormsg), None)
assert match(Command('ssh', stderr=errormsg), None)
assert match(Command('scp something something', stderr=errormsg), None)
assert match(Command('scp something something', stderr=errormsg), None)
assert not match(Command(stderr=errormsg), None)
assert not match(Command('notssh', stderr=errormsg), None)
assert not match(Command('ssh'), None)
assert match(Command('ssh', stderr=errormsg))
assert match(Command('ssh', stderr=errormsg))
assert match(Command('scp something something', stderr=errormsg))
assert match(Command('scp something something', stderr=errormsg))
assert not match(Command(stderr=errormsg))
assert not match(Command('notssh', stderr=errormsg))
assert not match(Command('ssh'))
def test_side_effect(ssh_error):
errormsg, path, reset, known_hosts = ssh_error
command = Command('ssh user@host', stderr=errormsg)
side_effect(command, None, None)
side_effect(command, None)
expected = ['123.234.567.890 asdjkasjdakjsd\n', '111.222.333.444 qwepoiwqepoiss\n']
assert known_hosts(path) == expected
def test_get_new_command(ssh_error, monkeypatch):
errormsg, _, _, _ = ssh_error
assert get_new_command(Command('ssh user@host', stderr=errormsg), None) == 'ssh user@host'
assert get_new_command(Command('ssh user@host', stderr=errormsg)) == 'ssh user@host'

View File

@@ -14,11 +14,11 @@ from tests.utils import Command
('You don\'t have access to the history DB.', ''),
('', "error: [Errno 13] Permission denied: '/usr/local/lib/python2.7/dist-packages/ipaddr.py'")])
def test_match(stderr, stdout):
assert match(Command(stderr=stderr, stdout=stdout), None)
assert match(Command(stderr=stderr, stdout=stdout))
def test_not_match():
assert not match(Command(), None)
assert not match(Command())
@pytest.mark.parametrize('before, after', [
@@ -26,4 +26,4 @@ def test_not_match():
('echo a > b', 'sudo sh -c "echo a > b"'),
('echo "a" >> b', 'sudo sh -c "echo \\"a\\" >> b"')])
def test_get_new_command(before, after):
assert get_new_command(Command(before), None) == after
assert get_new_command(Command(before)) == after

View File

@@ -9,7 +9,7 @@ from tests.utils import Command
Command(stderr='command not found: фзе-пуе', script=u'фзе-пуе'),
Command(stderr='command not found: λσ', script=u'λσ')])
def test_match(command):
assert switch_lang.match(command, None)
assert switch_lang.match(command)
@pytest.mark.parametrize('command', [
@@ -18,11 +18,11 @@ def test_match(command):
Command(stderr='command not found: агсл', script=u'агсл'),
Command(stderr='some info', script=u'фзе-пуе')])
def test_not_match(command):
assert not switch_lang.match(command, None)
assert not switch_lang.match(command)
@pytest.mark.parametrize('command, new_command', [
(Command(u'фзе-пуе штыефдд мшь'), 'apt-get install vim'),
(Command(u'λσ -λα'), 'ls -la')])
def test_get_new_command(command, new_command):
assert switch_lang.get_new_command(command, None) == new_command
assert switch_lang.get_new_command(command) == new_command

View File

@@ -4,15 +4,15 @@ from tests.utils import Command
def test_match():
assert match(Command('systemctl nginx start', stderr='Unknown operation \'nginx\'.'), None)
assert match(Command('sudo systemctl nginx start', stderr='Unknown operation \'nginx\'.'), None)
assert not match(Command('systemctl start nginx'), None)
assert not match(Command('systemctl start nginx'), None)
assert not match(Command('sudo systemctl nginx', stderr='Unknown operation \'nginx\'.'), None)
assert not match(Command('systemctl nginx', stderr='Unknown operation \'nginx\'.'), None)
assert not match(Command('systemctl start wtf', stderr='Failed to start wtf.service: Unit wtf.service failed to load: No such file or directory.'), None)
assert match(Command('systemctl nginx start', stderr='Unknown operation \'nginx\'.'))
assert match(Command('sudo systemctl nginx start', stderr='Unknown operation \'nginx\'.'))
assert not match(Command('systemctl start nginx'))
assert not match(Command('systemctl start nginx'))
assert not match(Command('sudo systemctl nginx', stderr='Unknown operation \'nginx\'.'))
assert not match(Command('systemctl nginx', stderr='Unknown operation \'nginx\'.'))
assert not match(Command('systemctl start wtf', stderr='Failed to start wtf.service: Unit wtf.service failed to load: No such file or directory.'))
def test_get_new_command():
assert get_new_command(Command('systemctl nginx start'), None) == "systemctl start nginx"
assert get_new_command(Command('sudo systemctl nginx start'), None) == "sudo systemctl start nginx"
assert get_new_command(Command('systemctl nginx start')) == "systemctl start nginx"
assert get_new_command(Command('sudo systemctl nginx start')) == "sudo systemctl start nginx"

View File

@@ -11,9 +11,9 @@ def tmux_ambiguous():
def test_match(tmux_ambiguous):
assert match(Command('tmux list', stderr=tmux_ambiguous), None)
assert match(Command('tmux list', stderr=tmux_ambiguous))
def test_get_new_command(tmux_ambiguous):
assert get_new_command(Command('tmux list', stderr=tmux_ambiguous), None)\
assert get_new_command(Command('tmux list', stderr=tmux_ambiguous))\
== ['tmux list-keys', 'tmux list-panes', 'tmux list-windows']

View File

@@ -15,7 +15,7 @@ error_msg = (
Command(script='tsuru app-log -f', stderr=error_msg[1]),
])
def test_match(command):
assert match(command, {})
assert match(command)
@pytest.mark.parametrize('command', [
@@ -24,7 +24,7 @@ def test_match(command):
Command(script='tsuru app-log -f', stderr=('Error: unparseable data')),
])
def test_not_match(command):
assert not match(command, {})
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
@@ -34,4 +34,4 @@ def test_not_match(command):
'tsuru login && tsuru app-log -f'),
])
def test_get_new_command(command, new_command):
assert get_new_command(command, {}) == new_command
assert get_new_command(command) == new_command

View File

@@ -30,7 +30,7 @@ from thefuck.rules.tsuru_not_command import match, get_new_command
)),
])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
@@ -58,7 +58,7 @@ def test_match(command):
Command('tsuru env-get', stderr='Error: App thefuck not found.'),
])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('command, new_commands', [
@@ -87,4 +87,4 @@ def test_not_match(command):
)), ['tsuru target-list']),
])
def test_get_new_command(command, new_commands):
assert get_new_command(command, None) == new_commands
assert get_new_command(command) == new_commands

View File

@@ -9,7 +9,7 @@ from tests.utils import Command
stderr='ls: Unknown command\nDid you mean -ls? This command begins with a dash.'),
Command(script='hdfs dfs ls /foo/bar', stderr='ls: Unknown command\nDid you mean -ls? This command begins with a dash.')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
@@ -18,7 +18,7 @@ def test_match(command):
Command(script='hdfs dfs -ls -R /foo/bar', stderr=''),
Command()])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
@@ -31,5 +31,5 @@ def test_not_match(command):
(Command('./bin/hdfs dfs -Dtest=fred ls -R /foo/bar',
stderr='ls: Unknown command\nDid you mean -ls? This command begins with a dash.'), ['./bin/hdfs dfs -Dtest=fred -ls -R /foo/bar'])])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -11,7 +11,7 @@ from tests.utils import Command
Command(script='vagrant rdp devbox',
stderr='VM must be created before running this command. Run `vagrant up` first.')])
def test_match(command):
assert match(command, None)
assert match(command)
@pytest.mark.parametrize('command', [
@@ -20,7 +20,7 @@ def test_match(command):
Command(script='vagrant ssh', stderr='A Vagrant environment or target machine is required to run this command. Run `vagrant init` to create a new Vagrant environment. Or, get an ID of a target machine from `vagrant global-status` to run this command on. A final option is to change to a directory with a Vagrantfile and to try again.'),
Command()])
def test_not_match(command):
assert not match(command, None)
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
@@ -31,5 +31,5 @@ def test_not_match(command):
(Command(script='vagrant rdp devbox',
stderr='VM must be created before running this command. Run `vagrant up` first.'), ['vagrant up devbox && vagrant rdp devbox', 'vagrant up && vagrant rdp devbox'])])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -8,11 +8,11 @@ from tests.utils import Command
Command(script='whois https://en.wikipedia.org/'),
Command(script='whois meta.unix.stackexchange.com')])
def test_match(command):
assert match(command, None)
assert match(command)
def test_not_match():
assert not match(Command(script='whois'), None)
assert not match(Command(script='whois'))
# `whois com` actually makes sense
@@ -23,4 +23,4 @@ def test_not_match():
'whois stackexchange.com',
'whois com'])])
def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command
assert get_new_command(command) == new_command

View File

@@ -9,9 +9,10 @@ from tests.utils import Command
"19:23:25.470911 git.c:282 trace: alias expansion: com => 'commit' '--verbose'")])
def test_git_support(called, command, stderr):
@git_support
def fn(command, settings): return command.script
def fn(command):
return command.script
assert fn(Command(script=called, stderr=stderr), None) == command
assert fn(Command(script=called, stderr=stderr)) == command
@pytest.mark.parametrize('command, is_git', [
@@ -24,6 +25,7 @@ def test_git_support(called, command, stderr):
('cat hub', False)])
def test_git_support_match(command, is_git):
@git_support
def fn(command, settings): return True
def fn(command):
return True
assert fn(Command(script=command), None) == is_git
assert fn(Command(script=command)) == is_git

View File

@@ -13,8 +13,8 @@ from tests.utils import Command
(False, 'sudo ls', 'ls', False),
(False, 'ls', 'ls', False)])
def test_sudo_support(return_value, command, called, result):
def fn(command, settings):
def fn(command):
assert command == Command(called)
return return_value
assert sudo_support(fn)(Command(command), None) == result
assert sudo_support(fn)(Command(command)) == result

View File

@@ -2,15 +2,6 @@ import pytest
import six
from mock import Mock
from thefuck import conf
from tests.utils import Rule
@pytest.mark.parametrize('enabled, rules, result', [
(True, conf.DEFAULT_RULES, True),
(False, conf.DEFAULT_RULES, False),
(False, conf.DEFAULT_RULES + ['test'], True)])
def test_default(enabled, rules, result):
assert (Rule('test', enabled_by_default=enabled) in rules) == result
@pytest.fixture
@@ -26,73 +17,79 @@ def environ(monkeypatch):
@pytest.mark.usefixture('environ')
def test_settings_defaults(load_source):
def test_settings_defaults(load_source, settings):
load_source.return_value = object()
settings.init()
for key, val in conf.DEFAULT_SETTINGS.items():
assert getattr(conf.get_settings(Mock()), key) == val
assert getattr(settings, key) == val
@pytest.mark.usefixture('environ')
class TestSettingsFromFile(object):
def test_from_file(self, load_source):
def test_from_file(self, load_source, settings):
load_source.return_value = Mock(rules=['test'],
wait_command=10,
require_confirmation=True,
no_colors=True,
priority={'vim': 100})
settings = conf.get_settings(Mock())
priority={'vim': 100},
exclude_rules=['git'])
settings.init()
assert settings.rules == ['test']
assert settings.wait_command == 10
assert settings.require_confirmation is True
assert settings.no_colors is True
assert settings.priority == {'vim': 100}
assert settings.exclude_rules == ['git']
def test_from_file_with_DEFAULT(self, load_source):
def test_from_file_with_DEFAULT(self, load_source, settings):
load_source.return_value = Mock(rules=conf.DEFAULT_RULES + ['test'],
wait_command=10,
exclude_rules=[],
require_confirmation=True,
no_colors=True)
settings = conf.get_settings(Mock())
settings.init()
assert settings.rules == conf.DEFAULT_RULES + ['test']
@pytest.mark.usefixture('load_source')
class TestSettingsFromEnv(object):
def test_from_env(self, environ):
def test_from_env(self, environ, settings):
environ.update({'THEFUCK_RULES': 'bash:lisp',
'THEFUCK_EXCLUDE_RULES': 'git:vim',
'THEFUCK_WAIT_COMMAND': '55',
'THEFUCK_REQUIRE_CONFIRMATION': 'true',
'THEFUCK_NO_COLORS': 'false',
'THEFUCK_PRIORITY': 'bash=10:lisp=wrong:vim=15'})
settings = conf.get_settings(Mock())
settings.init()
assert settings.rules == ['bash', 'lisp']
assert settings.exclude_rules == ['git', 'vim']
assert settings.wait_command == 55
assert settings.require_confirmation is True
assert settings.no_colors is False
assert settings.priority == {'bash': 10, 'vim': 15}
def test_from_env_with_DEFAULT(self, environ):
def test_from_env_with_DEFAULT(self, environ, settings):
environ.update({'THEFUCK_RULES': 'DEFAULT_RULES:bash:lisp'})
settings = conf.get_settings(Mock())
settings.init()
assert settings.rules == conf.DEFAULT_RULES + ['bash', 'lisp']
class TestInitializeSettingsFile(object):
def test_ignore_if_exists(self):
def test_ignore_if_exists(self, settings):
settings_path_mock = Mock(is_file=Mock(return_value=True), open=Mock())
user_dir_mock = Mock(joinpath=Mock(return_value=settings_path_mock))
conf.initialize_settings_file(user_dir_mock)
settings.user_dir = Mock(joinpath=Mock(return_value=settings_path_mock))
settings._init_settings_file()
assert settings_path_mock.is_file.call_count == 1
assert not settings_path_mock.open.called
def test_create_if_doesnt_exists(self):
def test_create_if_doesnt_exists(self, settings):
settings_file = six.StringIO()
settings_path_mock = Mock(
is_file=Mock(return_value=False),
open=Mock(return_value=Mock(
__exit__=lambda *args: None, __enter__=lambda *args: settings_file)))
user_dir_mock = Mock(joinpath=Mock(return_value=settings_path_mock))
conf.initialize_settings_file(user_dir_mock)
settings.user_dir = Mock(joinpath=Mock(return_value=settings_path_mock))
settings._init_settings_file()
settings_file_contents = settings_file.getvalue()
assert settings_path_mock.is_file.call_count == 1
assert settings_path_mock.open.call_count == 1

View File

@@ -1,85 +1,59 @@
import pytest
from pathlib import PosixPath, Path
from mock import Mock
from thefuck import corrector, conf, types
from pathlib import PosixPath
from thefuck import corrector, conf
from tests.utils import Rule, Command, CorrectedCommand
from thefuck.corrector import make_corrected_commands, get_corrected_commands
def test_load_rule(mocker):
match = object()
get_new_command = object()
load_source = mocker.patch(
'thefuck.corrector.load_source',
return_value=Mock(match=match,
get_new_command=get_new_command,
enabled_by_default=True,
priority=900,
requires_output=True))
assert corrector.load_rule(Path('/rules/bash.py'), settings=Mock(priority={})) \
== Rule('bash', match, get_new_command, priority=900)
load_source.assert_called_once_with('bash', '/rules/bash.py')
from thefuck.corrector import get_corrected_commands, organize_commands
class TestGetRules(object):
@pytest.fixture(autouse=True)
@pytest.fixture
def glob(self, mocker):
return mocker.patch('thefuck.corrector.Path.glob', return_value=[])
results = {}
mocker.patch('pathlib.Path.glob',
new_callable=lambda: lambda *_: results.pop('value', []))
return lambda value: results.update({'value': value})
@pytest.fixture(autouse=True)
def load_source(self, monkeypatch):
monkeypatch.setattr('thefuck.types.load_source',
lambda x, _: Rule(x))
def _compare_names(self, rules, names):
return [r.name for r in rules] == names
assert {r.name for r in rules} == set(names)
@pytest.mark.parametrize('conf_rules, rules', [
(conf.DEFAULT_RULES, ['bash', 'lisp', 'bash', 'lisp']),
(types.RulesNamesList(['bash']), ['bash', 'bash'])])
def test_get(self, monkeypatch, glob, conf_rules, rules):
glob.return_value = [PosixPath('bash.py'), PosixPath('lisp.py')]
monkeypatch.setattr('thefuck.corrector.load_source',
lambda x, _: Rule(x))
assert self._compare_names(
corrector.get_rules(Path('~'), Mock(rules=conf_rules, priority={})),
rules)
@pytest.mark.parametrize('paths, conf_rules, exclude_rules, loaded_rules', [
(['git.py', 'bash.py'], conf.DEFAULT_RULES, [], ['git', 'bash']),
(['git.py', 'bash.py'], ['git'], [], ['git']),
(['git.py', 'bash.py'], conf.DEFAULT_RULES, ['git'], ['bash']),
(['git.py', 'bash.py'], ['git'], ['git'], [])])
def test_get_rules(self, glob, settings, paths, conf_rules, exclude_rules,
loaded_rules):
glob([PosixPath(path) for path in paths])
settings.update(rules=conf_rules,
priority={},
exclude_rules=exclude_rules)
rules = corrector.get_rules()
self._compare_names(rules, loaded_rules)
class TestIsRuleMatch(object):
def test_no_match(self, settings):
assert not corrector.is_rule_match(
Command('ls'), Rule('', lambda *_: False), settings)
def test_match(self, settings):
rule = Rule('', lambda x, _: x.script == 'cd ..')
assert corrector.is_rule_match(Command('cd ..'), rule, settings)
def test_when_rule_failed(self, capsys, settings):
rule = Rule('test', Mock(side_effect=OSError('Denied')),
requires_output=False)
assert not corrector.is_rule_match(
Command('ls'), rule, settings)
assert capsys.readouterr()[1].split('\n')[0] == '[WARN] Rule test:'
class TestMakeCorrectedCommands(object):
def test_with_rule_returns_list(self):
rule = Rule(get_new_command=lambda x, _: [x.script + '!', x.script + '@'],
priority=100)
assert list(make_corrected_commands(Command(script='test'), rule, None)) \
== [CorrectedCommand(script='test!', priority=100),
CorrectedCommand(script='test@', priority=200)]
def test_with_rule_returns_command(self):
rule = Rule(get_new_command=lambda x, _: x.script + '!',
priority=100)
assert list(make_corrected_commands(Command(script='test'), rule, None)) \
== [CorrectedCommand(script='test!', priority=100)]
def test_get_corrected_commands(mocker):
command = Command('test', 'test', 'test')
rules = [Rule(match=lambda *_: False),
Rule(match=lambda *_: True,
get_new_command=lambda x, _: x.script + '!', priority=100),
Rule(match=lambda *_: True,
get_new_command=lambda x, _: [x.script + '@', x.script + ';'],
rules = [Rule(match=lambda _: False),
Rule(match=lambda _: True,
get_new_command=lambda x: x.script + '!', priority=100),
Rule(match=lambda _: True,
get_new_command=lambda x: [x.script + '@', x.script + ';'],
priority=60)]
mocker.patch('thefuck.corrector.get_rules', return_value=rules)
assert [cmd.script for cmd in get_corrected_commands(command, None, Mock(debug=False))] \
assert [cmd.script for cmd in get_corrected_commands(command)] \
== ['test!', 'test@', 'test;']
def test_organize_commands():
"""Ensures that the function removes duplicates and sorts commands."""
commands = [CorrectedCommand('ls'), CorrectedCommand('ls -la', priority=9000),
CorrectedCommand('ls -lh', priority=100),
CorrectedCommand('ls -lh', priority=9999)]
assert list(organize_commands(iter(commands))) \
== [CorrectedCommand('ls'), CorrectedCommand('ls -lh', priority=100),
CorrectedCommand('ls -la', priority=9000)]

View File

@@ -1,14 +1,20 @@
import pytest
from mock import Mock
from thefuck import logs
def test_color():
assert logs.color('red', Mock(no_colors=False)) == 'red'
assert logs.color('red', Mock(no_colors=True)) == ''
def test_color(settings):
settings.no_colors = False
assert logs.color('red') == 'red'
settings.no_colors = True
assert logs.color('red') == ''
def test_debug(capsys):
logs.debug('test', Mock(no_colors=True, debug=True))
assert capsys.readouterr() == ('', 'DEBUG: test\n')
logs.debug('test', Mock(no_colors=True, debug=False))
assert capsys.readouterr() == ('', '')
@pytest.mark.usefixtures('no_colors')
@pytest.mark.parametrize('debug, stderr', [
(True, 'DEBUG: test\n'),
(False, '')])
def test_debug(capsys, settings, debug, stderr):
settings.debug = debug
logs.debug('test')
assert capsys.readouterr() == ('', stderr)

View File

@@ -1,46 +0,0 @@
import pytest
from subprocess import PIPE
from mock import Mock
from thefuck import main
from tests.utils import Command
class TestGetCommand(object):
@pytest.fixture(autouse=True)
def Popen(self, monkeypatch):
Popen = Mock()
Popen.return_value.stdout.read.return_value = b'stdout'
Popen.return_value.stderr.read.return_value = b'stderr'
monkeypatch.setattr('thefuck.main.Popen', Popen)
return Popen
@pytest.fixture(autouse=True)
def prepare(self, monkeypatch):
monkeypatch.setattr('thefuck.main.os.environ', {})
monkeypatch.setattr('thefuck.main.wait_output', lambda *_: True)
@pytest.fixture(autouse=True)
def generic_shell(self, monkeypatch):
monkeypatch.setattr('thefuck.shells.from_shell', lambda x: x)
monkeypatch.setattr('thefuck.shells.to_shell', lambda x: x)
def test_get_command_calls(self, Popen):
assert main.get_command(Mock(env={}),
['thefuck', 'apt-get', 'search', 'vim']) \
== Command('apt-get search vim', 'stdout', 'stderr')
Popen.assert_called_once_with('apt-get search vim',
shell=True,
stdout=PIPE,
stderr=PIPE,
env={})
@pytest.mark.parametrize('args, result', [
(['thefuck', ''], None),
(['thefuck', '', ''], None),
(['thefuck', 'ls', '-la'], 'ls -la'),
(['thefuck', 'ls'], 'ls')])
def test_get_command_script(self, args, result):
if result:
assert main.get_command(Mock(env={}), args).script == result
else:
assert main.get_command(Mock(env={}), args) is None

View File

@@ -1,14 +1,10 @@
from tests.utils import root
def test_readme():
with root.joinpath('README.md').open() as f:
def test_readme(source_root):
with source_root.joinpath('README.md').open() as f:
readme = f.read()
bundled = root \
.joinpath('thefuck') \
.joinpath('rules') \
.glob('*.py')
bundled = source_root.joinpath('thefuck') \
.joinpath('rules') \
.glob('*.py')
for rule in bundled:
if rule.stem != '__init__':

29
tests/test_touch.py Normal file
View File

@@ -0,0 +1,29 @@
import pytest
from thefuck.rules.touch import match, get_new_command
from tests.utils import Command
@pytest.fixture
def stderr():
return "touch: cannot touch '/a/b/c':" \
" No such file or directory"
def test_match(stderr):
command = Command(
'touch /a/b/c', stderr=stderr)
assert match(command)
@pytest.mark.parametrize('command', [
Command('touch /a/b/c'),
Command('touch /a/b/c', stdout=stderr()),
Command('ls /a/b/c', stderr=stderr())])
def test_not_match(command):
assert not match(command)
def test_get_new_command(stderr):
command = Command('touch /a/b/c', stderr=stderr)
fixed_command = get_new_command(command)
assert fixed_command == 'mkdir -p /a/b && touch /a/b/c'

View File

@@ -1,52 +1,10 @@
from thefuck.types import RulesNamesList, Settings, \
SortedCorrectedCommandsSequence
from tests.utils import Rule, CorrectedCommand
def test_rules_names_list():
assert RulesNamesList(['bash', 'lisp']) == ['bash', 'lisp']
assert RulesNamesList(['bash', 'lisp']) == RulesNamesList(['bash', 'lisp'])
assert Rule('lisp') in RulesNamesList(['lisp'])
assert Rule('bash') not in RulesNamesList(['lisp'])
def test_update_settings():
settings = Settings({'key': 'val'})
new_settings = settings.update(key='new-val', unset='unset-value')
assert new_settings.key == 'val'
assert new_settings.unset == 'unset-value'
assert settings.key == 'val'
class TestSortedCorrectedCommandsSequence(object):
def test_realises_generator_only_on_demand(self, settings):
should_realise = False
def gen():
yield CorrectedCommand('git commit')
yield CorrectedCommand('git branch', priority=200)
assert should_realise
yield CorrectedCommand('git checkout', priority=100)
commands = SortedCorrectedCommandsSequence(gen(), settings)
assert commands[0] == CorrectedCommand('git commit')
should_realise = True
assert commands[1] == CorrectedCommand('git checkout', priority=100)
assert commands[2] == CorrectedCommand('git branch', priority=200)
def test_remove_duplicates(self, settings):
side_effect = lambda *_: None
seq = SortedCorrectedCommandsSequence(
iter([CorrectedCommand('ls', priority=100),
CorrectedCommand('ls', priority=200),
CorrectedCommand('ls', side_effect, 300)]),
settings)
assert set(seq) == {CorrectedCommand('ls', priority=100),
CorrectedCommand('ls', side_effect, 300)}
def test_with_blank(self, settings):
seq = SortedCorrectedCommandsSequence(iter([]), settings)
assert list(seq) == []
from subprocess import PIPE
from mock import Mock
from pathlib import Path
import pytest
from tests.utils import CorrectedCommand, Rule, Command
from thefuck import conf
from thefuck.exceptions import EmptyCommand
class TestCorrectedCommand(object):
@@ -60,3 +18,108 @@ class TestCorrectedCommand(object):
def test_hashable(self):
assert {CorrectedCommand('ls', None, 100),
CorrectedCommand('ls', None, 200)} == {CorrectedCommand('ls')}
class TestRule(object):
def test_from_path(self, mocker):
match = object()
get_new_command = object()
load_source = mocker.patch(
'thefuck.types.load_source',
return_value=Mock(match=match,
get_new_command=get_new_command,
enabled_by_default=True,
priority=900,
requires_output=True))
assert Rule.from_path(Path('/rules/bash.py')) \
== Rule('bash', match, get_new_command, priority=900)
load_source.assert_called_once_with('bash', '/rules/bash.py')
@pytest.mark.parametrize('rules, exclude_rules, rule, is_enabled', [
(conf.DEFAULT_RULES, [], Rule('git', enabled_by_default=True), True),
(conf.DEFAULT_RULES, [], Rule('git', enabled_by_default=False), False),
([], [], Rule('git', enabled_by_default=False), False),
([], [], Rule('git', enabled_by_default=True), False),
(conf.DEFAULT_RULES + ['git'], [], Rule('git', enabled_by_default=False), True),
(['git'], [], Rule('git', enabled_by_default=False), True),
(conf.DEFAULT_RULES, ['git'], Rule('git', enabled_by_default=True), False),
(conf.DEFAULT_RULES, ['git'], Rule('git', enabled_by_default=False), False),
([], ['git'], Rule('git', enabled_by_default=True), False),
([], ['git'], Rule('git', enabled_by_default=False), False)])
def test_is_enabled(self, settings, rules, exclude_rules, rule, is_enabled):
settings.update(rules=rules,
exclude_rules=exclude_rules)
assert rule.is_enabled == is_enabled
def test_isnt_match(self):
assert not Rule('', lambda _: False).is_match(
Command('ls'))
def test_is_match(self):
rule = Rule('', lambda x: x.script == 'cd ..')
assert rule.is_match(Command('cd ..'))
@pytest.mark.usefixtures('no_colors')
def test_isnt_match_when_rule_failed(self, capsys):
rule = Rule('test', Mock(side_effect=OSError('Denied')),
requires_output=False)
assert not rule.is_match(Command('ls'))
assert capsys.readouterr()[1].split('\n')[0] == '[WARN] Rule test:'
def test_get_corrected_commands_with_rule_returns_list(self):
rule = Rule(get_new_command=lambda x: [x.script + '!', x.script + '@'],
priority=100)
assert list(rule.get_corrected_commands(Command(script='test'))) \
== [CorrectedCommand(script='test!', priority=100),
CorrectedCommand(script='test@', priority=200)]
def test_get_corrected_commands_with_rule_returns_command(self):
rule = Rule(get_new_command=lambda x: x.script + '!',
priority=100)
assert list(rule.get_corrected_commands(Command(script='test'))) \
== [CorrectedCommand(script='test!', priority=100)]
class TestCommand(object):
@pytest.fixture(autouse=True)
def Popen(self, monkeypatch):
Popen = Mock()
Popen.return_value.stdout.read.return_value = b'stdout'
Popen.return_value.stderr.read.return_value = b'stderr'
monkeypatch.setattr('thefuck.types.Popen', Popen)
return Popen
@pytest.fixture(autouse=True)
def prepare(self, monkeypatch):
monkeypatch.setattr('thefuck.types.os.environ', {})
monkeypatch.setattr('thefuck.types.Command._wait_output',
staticmethod(lambda *_: True))
@pytest.fixture(autouse=True)
def generic_shell(self, monkeypatch):
monkeypatch.setattr('thefuck.shells.from_shell', lambda x: x)
monkeypatch.setattr('thefuck.shells.to_shell', lambda x: x)
def test_from_script_calls(self, Popen, settings):
settings.env = {}
assert Command.from_raw_script(
['apt-get', 'search', 'vim']) == Command(
'apt-get search vim', 'stdout', 'stderr')
Popen.assert_called_once_with('apt-get search vim',
shell=True,
stdout=PIPE,
stderr=PIPE,
env={})
@pytest.mark.parametrize('script, result', [
([''], None),
(['', ''], None),
(['ls', '-la'], 'ls -la'),
(['ls'], 'ls')])
def test_from_script(self, script, result):
if result:
assert Command.from_raw_script(script).script == result
else:
with pytest.raises(EmptyCommand):
Command.from_raw_script(script)

View File

@@ -1,10 +1,9 @@
# -*- encoding: utf-8 -*-
from mock import Mock
import pytest
from itertools import islice
from thefuck import ui
from thefuck.types import CorrectedCommand, SortedCorrectedCommandsSequence
from thefuck.types import CorrectedCommand
@pytest.fixture
@@ -41,10 +40,8 @@ def test_read_actions(patch_getch):
def test_command_selector():
selector = ui.CommandSelector([1, 2, 3])
selector = ui.CommandSelector(iter([1, 2, 3]))
assert selector.value == 1
changes = []
selector.on_change(changes.append)
selector.next()
assert selector.value == 2
selector.next()
@@ -53,69 +50,55 @@ def test_command_selector():
assert selector.value == 1
selector.previous()
assert selector.value == 3
assert changes == [1, 2, 3, 1, 3]
@pytest.mark.usefixtures('no_colors')
class TestSelectCommand(object):
@pytest.fixture
def commands_with_side_effect(self, settings):
return SortedCorrectedCommandsSequence(
iter([CorrectedCommand('ls', lambda *_: None, 100),
CorrectedCommand('cd', lambda *_: None, 100)]),
settings)
def commands_with_side_effect(self):
return [CorrectedCommand('ls', lambda *_: None, 100),
CorrectedCommand('cd', lambda *_: None, 100)]
@pytest.fixture
def commands(self, settings):
return SortedCorrectedCommandsSequence(
iter([CorrectedCommand('ls', None, 100),
CorrectedCommand('cd', None, 100)]),
settings)
def commands(self):
return [CorrectedCommand('ls', None, 100),
CorrectedCommand('cd', None, 100)]
def test_without_commands(self, capsys):
assert ui.select_command([], Mock(debug=False, no_color=True)) is None
assert ui.select_command(iter([])) is None
assert capsys.readouterr() == ('', 'No fucks given\n')
def test_without_confirmation(self, capsys, commands):
assert ui.select_command(commands,
Mock(debug=False, no_color=True,
require_confirmation=False)) == commands[0]
def test_without_confirmation(self, capsys, commands, settings):
settings.require_confirmation = False
assert ui.select_command(iter(commands)) == commands[0]
assert capsys.readouterr() == ('', 'ls\n')
def test_without_confirmation_with_side_effects(self, capsys,
commands_with_side_effect):
assert ui.select_command(commands_with_side_effect,
Mock(debug=False, no_color=True,
require_confirmation=False)) \
def test_without_confirmation_with_side_effects(
self, capsys, commands_with_side_effect, settings):
settings.require_confirmation = False
assert ui.select_command(iter(commands_with_side_effect)) \
== commands_with_side_effect[0]
assert capsys.readouterr() == ('', 'ls (+side effect)\n')
def test_with_confirmation(self, capsys, patch_getch, commands):
patch_getch(['\n'])
assert ui.select_command(commands,
Mock(debug=False, no_color=True,
require_confirmation=True)) == commands[0]
assert ui.select_command(iter(commands)) == commands[0]
assert capsys.readouterr() == ('', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\n')
def test_with_confirmation_abort(self, capsys, patch_getch, commands):
patch_getch([KeyboardInterrupt])
assert ui.select_command(commands,
Mock(debug=False, no_color=True,
require_confirmation=True)) is None
assert ui.select_command(iter(commands)) is None
assert capsys.readouterr() == ('', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\nAborted\n')
def test_with_confirmation_with_side_effct(self, capsys, patch_getch,
commands_with_side_effect):
patch_getch(['\n'])
assert ui.select_command(commands_with_side_effect,
Mock(debug=False, no_color=True,
require_confirmation=True))\
assert ui.select_command(iter(commands_with_side_effect))\
== commands_with_side_effect[0]
assert capsys.readouterr() == ('', u'\x1b[1K\rls (+side effect) [enter/↑/↓/ctrl+c]\n')
def test_with_confirmation_select_second(self, capsys, patch_getch, commands):
patch_getch(['\x1b', '[', 'B', '\n'])
assert ui.select_command(commands,
Mock(debug=False, no_color=True,
require_confirmation=True)) == commands[1]
assert ui.select_command(iter(commands)) == commands[1]
assert capsys.readouterr() == (
'', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\x1b[1K\rcd [enter/↑/↓/ctrl+c]\n')

View File

@@ -1,10 +1,9 @@
import pytest
from mock import Mock
import six
from thefuck.utils import wrap_settings, \
from thefuck.utils import default_settings, \
memoize, get_closest, get_all_executables, replace_argument, \
get_all_matched_commands, is_app, for_app, cache
from thefuck.types import Settings
get_all_matched_commands, is_app, for_app, cache, compatibility_call
from tests.utils import Command
@@ -12,9 +11,12 @@ from tests.utils import Command
({'key': 'val'}, {}, {'key': 'val'}),
({'key': 'new-val'}, {'key': 'val'}, {'key': 'val'}),
({'key': 'new-val', 'unset': 'unset'}, {'key': 'val'}, {'key': 'val', 'unset': 'unset'})])
def test_wrap_settings(override, old, new):
fn = lambda _, settings: settings
assert wrap_settings(override)(fn)(None, Settings(old)) == new
def test_default_settings(settings, override, old, new):
settings.clear()
settings.update(old)
fn = lambda _: _
default_settings(override)(fn)(None)
assert settings == new
def test_memoize():
@@ -53,7 +55,7 @@ def get_aliases(mocker):
@pytest.mark.usefixtures('no_memoize', 'get_aliases')
def test_get_all_callables():
def test_get_all_executables():
all_callables = get_all_executables()
assert 'vim' in all_callables
assert 'fsck' in all_callables
@@ -112,10 +114,10 @@ def test_is_app(script, names, result):
('hg diff', ['git', 'hub'], False)])
def test_for_app(script, names, result):
@for_app(*names)
def match(command, settings):
def match(command):
return True
assert match(Command(script), None) == result
assert match(Command(script)) == result
class TestCache(object):
@@ -180,3 +182,50 @@ class TestCache(object):
shelve.update({key: {'etag': '-1', 'value': 'old-value'}})
assert fn() == 'test'
assert shelve == {key: {'etag': '0', 'value': 'test'}}
class TestCompatibilityCall(object):
def test_match(self):
def match(command):
assert command == Command()
return True
assert compatibility_call(match, Command())
def test_old_match(self, settings):
def match(command, _settings):
assert command == Command()
assert settings == _settings
return True
assert compatibility_call(match, Command())
def test_get_new_command(self):
def get_new_command(command):
assert command == Command()
return True
assert compatibility_call(get_new_command, Command())
def test_old_get_new_command(self, settings):
def get_new_command(command, _settings):
assert command == Command()
assert settings == _settings
return True
assert compatibility_call(get_new_command, Command())
def test_side_effect(self):
def side_effect(command, new_command):
assert command == Command() == new_command
return True
assert compatibility_call(side_effect, Command(), Command())
def test_old_side_effect(self, settings):
def side_effect(command, new_command, _settings):
assert command == Command() == new_command
assert settings == _settings
return True
assert compatibility_call(side_effect, Command(), Command())

View File

@@ -1,25 +1,25 @@
from pathlib import Path
from thefuck import types
from thefuck.conf import DEFAULT_PRIORITY
def Command(script='', stdout='', stderr=''):
return types.Command(script, stdout, stderr)
class Command(types.Command):
def __init__(self, script='', stdout='', stderr=''):
super(Command, self).__init__(script, stdout, stderr)
def Rule(name='', match=lambda *_: True,
get_new_command=lambda *_: '',
enabled_by_default=True,
side_effect=None,
priority=DEFAULT_PRIORITY,
requires_output=True):
return types.Rule(name, match, get_new_command,
enabled_by_default, side_effect,
priority, requires_output)
class Rule(types.Rule):
def __init__(self, name='', match=lambda *_: True,
get_new_command=lambda *_: '',
enabled_by_default=True,
side_effect=None,
priority=DEFAULT_PRIORITY,
requires_output=True):
super(Rule, self).__init__(name, match, get_new_command,
enabled_by_default, side_effect,
priority, requires_output)
def CorrectedCommand(script='', side_effect=None, priority=DEFAULT_PRIORITY):
return types.CorrectedCommand(script, side_effect, priority)
root = Path(__file__).parent.parent.resolve()
class CorrectedCommand(types.CorrectedCommand):
def __init__(self, script='', side_effect=None, priority=DEFAULT_PRIORITY):
super(CorrectedCommand, self).__init__(
script, side_effect, priority)

View File

@@ -1,31 +1,16 @@
from copy import copy
from imp import load_source
import os
import sys
from pathlib import Path
from six import text_type
from . import logs, types
class _DefaultRulesNames(types.RulesNamesList):
def __add__(self, items):
return _DefaultRulesNames(list(self) + items)
def __contains__(self, item):
return item.enabled_by_default or \
super(_DefaultRulesNames, self).__contains__(item)
def __eq__(self, other):
if isinstance(other, _DefaultRulesNames):
return super(_DefaultRulesNames, self).__eq__(other)
else:
return False
DEFAULT_RULES = _DefaultRulesNames([])
ALL_ENABLED = object()
DEFAULT_RULES = [ALL_ENABLED]
DEFAULT_PRIORITY = 1000
DEFAULT_SETTINGS = {'rules': DEFAULT_RULES,
'exclude_rules': [],
'wait_command': 3,
'require_confirmation': True,
'no_colors': False,
@@ -34,13 +19,13 @@ DEFAULT_SETTINGS = {'rules': DEFAULT_RULES,
'env': {'LC_ALL': 'C', 'LANG': 'C', 'GIT_TRACE': '1'}}
ENV_TO_ATTR = {'THEFUCK_RULES': 'rules',
'THEFUCK_EXCLUDE_RULES': 'exclude_rules',
'THEFUCK_WAIT_COMMAND': 'wait_command',
'THEFUCK_REQUIRE_CONFIRMATION': 'require_confirmation',
'THEFUCK_NO_COLORS': 'no_colors',
'THEFUCK_PRIORITY': 'priority',
'THEFUCK_DEBUG': 'debug'}
SETTINGS_HEADER = u"""# ~/.thefuck/settings.py: The Fuck settings file
#
# The rules are defined as in the example bellow:
@@ -54,82 +39,89 @@ SETTINGS_HEADER = u"""# ~/.thefuck/settings.py: The Fuck settings file
"""
def _settings_from_file(user_dir):
"""Loads settings from file."""
settings = load_source('settings',
text_type(user_dir.joinpath('settings.py')))
return {key: getattr(settings, key)
for key in DEFAULT_SETTINGS.keys()
if hasattr(settings, key)}
class Settings(dict):
def __getattr__(self, item):
return self.get(item)
def __setattr__(self, key, value):
self[key] = value
def _rules_from_env(val):
"""Transforms rules list from env-string to python."""
val = val.split(':')
if 'DEFAULT_RULES' in val:
val = DEFAULT_RULES + [rule for rule in val if rule != 'DEFAULT_RULES']
return val
def init(self):
"""Fills `settings` with values from `settings.py` and env."""
from .logs import exception
self._setup_user_dir()
self._init_settings_file()
def _priority_from_env(val):
"""Gets priority pairs from env."""
for part in val.split(':'):
try:
rule, priority = part.split('=')
yield rule, int(priority)
except ValueError:
continue
self.update(self._settings_from_file())
except Exception:
exception("Can't load settings from file", sys.exc_info())
try:
self.update(self._settings_from_env())
except Exception:
exception("Can't load settings from env", sys.exc_info())
def _val_from_env(env, attr):
"""Transforms env-strings to python."""
val = os.environ[env]
if attr == 'rules':
return _rules_from_env(val)
elif attr == 'priority':
return dict(_priority_from_env(val))
elif attr == 'wait_command':
return int(val)
elif attr in ('require_confirmation', 'no_colors', 'debug'):
return val.lower() == 'true'
else:
def _init_settings_file(self):
settings_path = self.user_dir.joinpath('settings.py')
if not settings_path.is_file():
with settings_path.open(mode='w') as settings_file:
settings_file.write(SETTINGS_HEADER)
for setting in DEFAULT_SETTINGS.items():
settings_file.write(u'# {} = {}\n'.format(*setting))
def _setup_user_dir(self):
"""Returns user config dir, create it when it doesn't exist."""
user_dir = Path(os.path.expanduser('~/.thefuck'))
rules_dir = user_dir.joinpath('rules')
if not rules_dir.is_dir():
rules_dir.mkdir(parents=True)
self.user_dir = user_dir
def _settings_from_file(self):
"""Loads settings from file."""
settings = load_source(
'settings', text_type(self.user_dir.joinpath('settings.py')))
return {key: getattr(settings, key)
for key in DEFAULT_SETTINGS.keys()
if hasattr(settings, key)}
def _rules_from_env(self, val):
"""Transforms rules list from env-string to python."""
val = val.split(':')
if 'DEFAULT_RULES' in val:
val = DEFAULT_RULES + [rule for rule in val if rule != 'DEFAULT_RULES']
return val
def _priority_from_env(self, val):
"""Gets priority pairs from env."""
for part in val.split(':'):
try:
rule, priority = part.split('=')
yield rule, int(priority)
except ValueError:
continue
def _settings_from_env():
"""Loads settings from env."""
return {attr: _val_from_env(env, attr)
for env, attr in ENV_TO_ATTR.items()
if env in os.environ}
def _val_from_env(self, env, attr):
"""Transforms env-strings to python."""
val = os.environ[env]
if attr in ('rules', 'exclude_rules'):
return self._rules_from_env(val)
elif attr == 'priority':
return dict(self._priority_from_env(val))
elif attr == 'wait_command':
return int(val)
elif attr in ('require_confirmation', 'no_colors', 'debug'):
return val.lower() == 'true'
else:
return val
def _settings_from_env(self):
"""Loads settings from env."""
return {attr: self._val_from_env(env, attr)
for env, attr in ENV_TO_ATTR.items()
if env in os.environ}
def get_settings(user_dir):
"""Returns settings filled with values from `settings.py` and env."""
conf = copy(DEFAULT_SETTINGS)
try:
conf.update(_settings_from_file(user_dir))
except Exception:
logs.exception("Can't load settings from file",
sys.exc_info(),
types.Settings(conf))
try:
conf.update(_settings_from_env())
except Exception:
logs.exception("Can't load settings from env",
sys.exc_info(),
types.Settings(conf))
if not isinstance(conf['rules'], types.RulesNamesList):
conf['rules'] = types.RulesNamesList(conf['rules'])
return types.Settings(conf)
def initialize_settings_file(user_dir):
settings_path = user_dir.joinpath('settings.py')
if not settings_path.is_file():
with settings_path.open(mode='w') as settings_file:
settings_file.write(SETTINGS_HEADER)
for setting in DEFAULT_SETTINGS.items():
settings_file.write(u'# {} = {}\n'.format(*setting))
settings = Settings(DEFAULT_SETTINGS)

View File

@@ -1,71 +1,75 @@
import sys
from imp import load_source
from pathlib import Path
from . import conf, types, logs
from .conf import settings
from .types import Rule
from . import logs
def load_rule(rule, settings):
"""Imports rule module and returns it."""
name = rule.name[:-3]
with logs.debug_time(u'Importing rule: {};'.format(name), settings):
rule_module = load_source(name, str(rule))
priority = getattr(rule_module, 'priority', conf.DEFAULT_PRIORITY)
return types.Rule(name, rule_module.match,
rule_module.get_new_command,
getattr(rule_module, 'enabled_by_default', True),
getattr(rule_module, 'side_effect', None),
settings.priority.get(name, priority),
getattr(rule_module, 'requires_output', True))
def get_loaded_rules(rules_paths):
"""Yields all available rules.
:type rules_paths: [Path]
:rtype: Iterable[Rule]
"""
for path in rules_paths:
if path.name != '__init__.py':
rule = Rule.from_path(path)
if rule.is_enabled:
yield rule
def get_loaded_rules(rules, settings):
"""Yields all available rules."""
for rule in rules:
if rule.name != '__init__.py':
loaded_rule = load_rule(rule, settings)
if loaded_rule in settings.rules:
yield loaded_rule
def get_rules():
"""Returns all enabled rules.
:rtype: [Rule]
def get_rules(user_dir, settings):
"""Returns all enabled rules."""
"""
bundled = Path(__file__).parent \
.joinpath('rules') \
.glob('*.py')
user = user_dir.joinpath('rules').glob('*.py')
return sorted(get_loaded_rules(sorted(bundled) + sorted(user), settings),
user = settings.user_dir.joinpath('rules').glob('*.py')
return sorted(get_loaded_rules(sorted(bundled) + sorted(user)),
key=lambda rule: rule.priority)
def is_rule_match(command, rule, settings):
"""Returns first matched rule for command."""
script_only = command.stdout is None and command.stderr is None
def organize_commands(corrected_commands):
"""Yields sorted commands without duplicates.
if script_only and rule.requires_output:
return False
:type corrected_commands: Iterable[thefuck.types.CorrectedCommand]
:rtype: Iterable[thefuck.types.CorrectedCommand]
"""
try:
with logs.debug_time(u'Trying rule: {};'.format(rule.name),
settings):
if rule.match(command, settings):
return True
except Exception:
logs.rule_failed(rule, sys.exc_info(), settings)
first_command = next(corrected_commands)
yield first_command
except StopIteration:
return
without_duplicates = {
command for command in sorted(
corrected_commands, key=lambda command: command.priority)
if command != first_command}
sorted_commands = sorted(
without_duplicates,
key=lambda corrected_command: corrected_command.priority)
logs.debug('Corrected commands: '.format(
', '.join(str(cmd) for cmd in [first_command] + sorted_commands)))
for command in sorted_commands:
yield command
def make_corrected_commands(command, rule, settings):
new_commands = rule.get_new_command(command, settings)
if not isinstance(new_commands, list):
new_commands = (new_commands,)
for n, new_command in enumerate(new_commands):
yield types.CorrectedCommand(script=new_command,
side_effect=rule.side_effect,
priority=(n + 1) * rule.priority)
def get_corrected_commands(command):
"""Returns generator with sorted and unique corrected commands.
:type command: thefuck.types.Command
:rtype: Iterable[thefuck.types.CorrectedCommand]
def get_corrected_commands(command, user_dir, settings):
"""
corrected_commands = (
corrected for rule in get_rules(user_dir, settings)
if is_rule_match(command, rule, settings)
for corrected in make_corrected_commands(command, rule, settings))
return types.SortedCorrectedCommandsSequence(corrected_commands, settings)
corrected for rule in get_rules()
if rule.is_match(command)
for corrected in rule.get_corrected_commands(command))
return organize_commands(corrected_commands)

6
thefuck/exceptions.py Normal file
View File

@@ -0,0 +1,6 @@
class EmptyCommand(Exception):
"""Raised when empty command passed to `thefuck`."""
class NoRuleMatched(Exception):
"""Raised when no rule matched for some command."""

View File

@@ -5,9 +5,10 @@ from datetime import datetime
import sys
from traceback import format_exception
import colorama
from .conf import settings
def color(color_, settings):
def color(color_):
"""Utility for ability to disabling colored output."""
if settings.no_colors:
return ''
@@ -15,37 +16,37 @@ def color(color_, settings):
return color_
def exception(title, exc_info, settings):
def exception(title, exc_info):
sys.stderr.write(
u'{warn}[WARN] {title}:{reset}\n{trace}'
u'{warn}----------------------------{reset}\n\n'.format(
warn=color(colorama.Back.RED + colorama.Fore.WHITE
+ colorama.Style.BRIGHT, settings),
reset=color(colorama.Style.RESET_ALL, settings),
+ colorama.Style.BRIGHT),
reset=color(colorama.Style.RESET_ALL),
title=title,
trace=''.join(format_exception(*exc_info))))
def rule_failed(rule, exc_info, settings):
exception('Rule {}'.format(rule.name), exc_info, settings)
def rule_failed(rule, exc_info):
exception('Rule {}'.format(rule.name), exc_info)
def failed(msg, settings):
def failed(msg):
sys.stderr.write('{red}{msg}{reset}\n'.format(
msg=msg,
red=color(colorama.Fore.RED, settings),
reset=color(colorama.Style.RESET_ALL, settings)))
red=color(colorama.Fore.RED),
reset=color(colorama.Style.RESET_ALL)))
def show_corrected_command(corrected_command, settings):
def show_corrected_command(corrected_command):
sys.stderr.write('{bold}{script}{reset}{side_effect}\n'.format(
script=corrected_command.script,
side_effect=' (+side effect)' if corrected_command.side_effect else '',
bold=color(colorama.Style.BRIGHT, settings),
reset=color(colorama.Style.RESET_ALL, settings)))
bold=color(colorama.Style.BRIGHT),
reset=color(colorama.Style.RESET_ALL)))
def confirm_text(corrected_command, settings):
def confirm_text(corrected_command):
sys.stderr.write(
('{clear}{bold}{script}{reset}{side_effect} '
'[{green}enter{reset}/{blue}{reset}/{blue}{reset}'
@@ -53,26 +54,42 @@ def confirm_text(corrected_command, settings):
script=corrected_command.script,
side_effect=' (+side effect)' if corrected_command.side_effect else '',
clear='\033[1K\r',
bold=color(colorama.Style.BRIGHT, settings),
green=color(colorama.Fore.GREEN, settings),
red=color(colorama.Fore.RED, settings),
reset=color(colorama.Style.RESET_ALL, settings),
blue=color(colorama.Fore.BLUE, settings)))
bold=color(colorama.Style.BRIGHT),
green=color(colorama.Fore.GREEN),
red=color(colorama.Fore.RED),
reset=color(colorama.Style.RESET_ALL),
blue=color(colorama.Fore.BLUE)))
def debug(msg, settings):
def debug(msg):
if settings.debug:
sys.stderr.write(u'{blue}{bold}DEBUG:{reset} {msg}\n'.format(
msg=msg,
reset=color(colorama.Style.RESET_ALL, settings),
blue=color(colorama.Fore.BLUE, settings),
bold=color(colorama.Style.BRIGHT, settings)))
reset=color(colorama.Style.RESET_ALL),
blue=color(colorama.Fore.BLUE),
bold=color(colorama.Style.BRIGHT)))
@contextmanager
def debug_time(msg, settings):
def debug_time(msg):
started = datetime.now()
try:
yield
finally:
debug(u'{} took: {}'.format(msg, datetime.now() - started), settings)
debug(u'{} took: {}'.format(msg, datetime.now() - started))
def how_to_configure_alias(configuration_details):
print("Seems like {bold}fuck{reset} alias isn't configured!".format(
bold=color(colorama.Style.BRIGHT),
reset=color(colorama.Style.RESET_ALL)))
if configuration_details:
content, path = configuration_details
print(
"Please put {bold}{content}{reset} in your "
"{bold}{path}{reset}.".format(
bold=color(colorama.Style.BRIGHT),
reset=color(colorama.Style.RESET_ALL),
path=path,
content=content))
print('More details - https://github.com/nvbn/thefuck#manual-installation')

Some files were not shown because too many files have changed in this diff Show More