mirror of
https://github.com/nvbn/thefuck.git
synced 2025-11-06 01:52:02 +00:00
Compare commits
291 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a9942061d | ||
|
|
a65f90813b | ||
|
|
a778ea6203 | ||
|
|
03a828d586 | ||
|
|
4a0d71c1c4 | ||
|
|
a6f63c0568 | ||
|
|
d1b9492085 | ||
|
|
993a661c60 | ||
|
|
bc9121cb13 | ||
|
|
7db140c456 | ||
|
|
e313ff73a9 | ||
|
|
8c62706db4 | ||
|
|
6baa7f650e | ||
|
|
4ae32cf4ee | ||
|
|
385746850e | ||
|
|
4f87141f0c | ||
|
|
dbedcc7aa6 | ||
|
|
e0b5d47fa5 | ||
|
|
ca44ee0640 | ||
|
|
892e8a8e65 | ||
|
|
a947259eef | ||
|
|
785cb83ff3 | ||
|
|
aec8fe3233 | ||
|
|
c21dbd2be3 | ||
|
|
6173913291 | ||
|
|
6f0d1e287d | ||
|
|
756044e087 | ||
|
|
ddd8788353 | ||
|
|
76c0e7bc70 | ||
|
|
4865bdd81f | ||
|
|
fa169c686c | ||
|
|
9cae0bffff | ||
|
|
b519d317f7 | ||
|
|
5b420204c9 | ||
|
|
07005b591a | ||
|
|
cb99e42e02 | ||
|
|
51f77964c6 | ||
|
|
30b1c44f91 | ||
|
|
af28f0334a | ||
|
|
5ee5439c1e | ||
|
|
cf006dac2c | ||
|
|
5b535077bf | ||
|
|
cf3acbfa2e | ||
|
|
4d714994a3 | ||
|
|
02f717a0e8 | ||
|
|
8f4f2f03a7 | ||
|
|
feb36ede5c | ||
|
|
16a440cb9d | ||
|
|
10b20574d1 | ||
|
|
91fceb401a | ||
|
|
4b79e23ba7 | ||
|
|
f915a6ed0c | ||
|
|
a964af7e95 | ||
|
|
77fc021a6c | ||
|
|
4822ceb87a | ||
|
|
b2947aba8d | ||
|
|
d2e0a19aae | ||
|
|
0c84eefa55 | ||
|
|
8bd6c5da67 | ||
|
|
ce6b82c92d | ||
|
|
5dbbb3b1ed | ||
|
|
db4b37910d | ||
|
|
2b88ea11ea | ||
|
|
db7dffdb44 | ||
|
|
92f3c8fb52 | ||
|
|
7c4f0d2e55 | ||
|
|
d05eb0a6dc | ||
|
|
cf352fd788 | ||
|
|
3c1cce6bd2 | ||
|
|
5d3a727d1a | ||
|
|
ea87d55771 | ||
|
|
aa6b18d0ce | ||
|
|
934eeaf4fc | ||
|
|
3ad8d52a84 | ||
|
|
bb5c7c576f | ||
|
|
17c3935078 | ||
|
|
a734b94fec | ||
|
|
7bf405e9c3 | ||
|
|
c3bcdd7dee | ||
|
|
ad53023860 | ||
|
|
8938323229 | ||
|
|
92133f77d6 | ||
|
|
64eaf96eb8 | ||
|
|
c9264aff10 | ||
|
|
9660ec7813 | ||
|
|
9ac47d8f78 | ||
|
|
6e2b82911f | ||
|
|
af9d34c299 | ||
|
|
bcc11219e6 | ||
|
|
495a66088b | ||
|
|
4fe64e3dfa | ||
|
|
cae76eb55f | ||
|
|
afd2ed4e51 | ||
|
|
1a4d74d487 | ||
|
|
0bd3e85e08 | ||
|
|
faeeef7666 | ||
|
|
4d65d6a1df | ||
|
|
cfa51506fb | ||
|
|
5df350254e | ||
|
|
612c393ec4 | ||
|
|
4d89b3499e | ||
|
|
070bb2ff28 | ||
|
|
71025dff17 | ||
|
|
621b455334 | ||
|
|
176924c18d | ||
|
|
1f75fc1ea9 | ||
|
|
46cb87615e | ||
|
|
c63e0d1582 | ||
|
|
a3eb124033 | ||
|
|
a1f115eb19 | ||
|
|
56851e8d31 | ||
|
|
a8c3c2d728 | ||
|
|
844d3af8ae | ||
|
|
a2693bd737 | ||
|
|
ae3e231a5f | ||
|
|
21bb439d7c | ||
|
|
efcf7da7db | ||
|
|
5f79217e97 | ||
|
|
fdfbfc80c0 | ||
|
|
b09a4e394e | ||
|
|
34973fe97e | ||
|
|
379d2953c9 | ||
|
|
065b350ada | ||
|
|
ca787a1cba | ||
|
|
4c2fc490f2 | ||
|
|
0c2083485d | ||
|
|
bc78c83224 | ||
|
|
b2a5009116 | ||
|
|
087584a1e0 | ||
|
|
b6b15bf0d1 | ||
|
|
a169575b0f | ||
|
|
fbea803a9b | ||
|
|
51415a5cb1 | ||
|
|
237bc57999 | ||
|
|
2af65071d8 | ||
|
|
c93b547624 | ||
|
|
837ca73f50 | ||
|
|
a3b2e6872b | ||
|
|
29ed1800e1 | ||
|
|
965c05bfdf | ||
|
|
a7d1c725e4 | ||
|
|
99e828d15d | ||
|
|
ae2b767a4d | ||
|
|
3893e0cdca | ||
|
|
2988e4871f | ||
|
|
d5e333b727 | ||
|
|
1755bcd1b5 | ||
|
|
f773b57bea | ||
|
|
5866ea8433 | ||
|
|
729508e581 | ||
|
|
1b7c8b5498 | ||
|
|
9b6cd0cd7b | ||
|
|
77ea630d84 | ||
|
|
917c6ac887 | ||
|
|
8bea63eb23 | ||
|
|
2bf21d9f0e | ||
|
|
e2f66cb26b | ||
|
|
ff1ee979f0 | ||
|
|
25343dbfb4 | ||
|
|
ea3671f98c | ||
|
|
4584903beb | ||
|
|
990ba57159 | ||
|
|
16c110823d | ||
|
|
01418526b4 | ||
|
|
d2845a0d2e | ||
|
|
2c1666abc4 | ||
|
|
42853f41bb | ||
|
|
5f11ecc4f8 | ||
|
|
4bd4c0f731 | ||
|
|
b8c5433dc4 | ||
|
|
e2883430bc | ||
|
|
a4b690369c | ||
|
|
6bbd680e56 | ||
|
|
e5f8e9c0de | ||
|
|
ebf1ea88f5 | ||
|
|
d2b0b6e8ec | ||
|
|
561eb12c08 | ||
|
|
ed38fedf26 | ||
|
|
15bcd7f03f | ||
|
|
9e39bcd55c | ||
|
|
cfa73f10d6 | ||
|
|
c3709682d5 | ||
|
|
96f7e53aa2 | ||
|
|
d1f55603fe | ||
|
|
f74bbb7a9a | ||
|
|
d6c2c7266d | ||
|
|
51839e65cd | ||
|
|
d5ae3a6b41 | ||
|
|
9f421a17e5 | ||
|
|
9d9820676a | ||
|
|
5ec4909d2f | ||
|
|
c6d2766553 | ||
|
|
c6af8409d9 | ||
|
|
95e7d00aec | ||
|
|
cdccf1881e | ||
|
|
db6053b301 | ||
|
|
183b70c8b8 | ||
|
|
5e0cc8c703 | ||
|
|
1aa2ec1795 | ||
|
|
0c98053f74 | ||
|
|
17b2fba48d | ||
|
|
43886c38ff | ||
|
|
9070748a86 | ||
|
|
61de6f4a51 | ||
|
|
d102af41d9 | ||
|
|
b7002bb9f9 | ||
|
|
18b4f5df6a | ||
|
|
28153db4a8 | ||
|
|
047a1a6072 | ||
|
|
69db5c70e6 | ||
|
|
fa1edd4bae | ||
|
|
333c4b2a3f | ||
|
|
b1f10642fa | ||
|
|
047efd5575 | ||
|
|
f604756cb7 | ||
|
|
a27115bff1 | ||
|
|
5d00b3bc25 | ||
|
|
0cf4f5e8b0 | ||
|
|
41707b80c6 | ||
|
|
3a39deb485 | ||
|
|
d4bc8cebf1 | ||
|
|
6daf687237 | ||
|
|
2207dd2668 | ||
|
|
d1ab08a797 | ||
|
|
51e89a36ef | ||
|
|
39f7cc37eb | ||
|
|
251b69b5a0 | ||
|
|
8b1f078e27 | ||
|
|
a47e84fa6b | ||
|
|
bcab700215 | ||
|
|
4fb99fd7a8 | ||
|
|
bb5f6bb705 | ||
|
|
d92765d5df | ||
|
|
d8de5cfd20 | ||
|
|
d73b14ce4b | ||
|
|
04b83cf7e8 | ||
|
|
019f0abf67 | ||
|
|
c8d3dcd1bf | ||
|
|
4f5b382df4 | ||
|
|
77ad68b04b | ||
|
|
6b0311181d | ||
|
|
48808f93ac | ||
|
|
7ce4307c87 | ||
|
|
f7f0660114 | ||
|
|
46f2351907 | ||
|
|
e9de01fa41 | ||
|
|
9b260eb239 | ||
|
|
f20d4dbf85 | ||
|
|
4af7dc2748 | ||
|
|
c8e9606c7d | ||
|
|
d71b9c2e62 | ||
|
|
60497b9d04 | ||
|
|
619af2638a | ||
|
|
a1f15bfe5f | ||
|
|
ce959b2a8b | ||
|
|
3cc4940842 | ||
|
|
470c0ef699 | ||
|
|
4f95b3365a | ||
|
|
bbfd53d718 | ||
|
|
28d078708b | ||
|
|
778d5f3e6e | ||
|
|
c5acee54ea | ||
|
|
c3e9c1bfc1 | ||
|
|
6c25b33b9e | ||
|
|
052f415d94 | ||
|
|
3438d6dde7 | ||
|
|
af0fe66a9f | ||
|
|
fe07fcaa62 | ||
|
|
b5dc7aab6d | ||
|
|
a2ec5aa3ff | ||
|
|
0b2bda9e85 | ||
|
|
68c882cf1a | ||
|
|
abe8fb84c6 | ||
|
|
86b17eb570 | ||
|
|
dcc0ce7ff3 | ||
|
|
fee874cddc | ||
|
|
2ce1c6bf90 | ||
|
|
9b129fad08 | ||
|
|
20adefbe7d | ||
|
|
52ef1fa47d | ||
|
|
94f8652175 | ||
|
|
abe287a52b | ||
|
|
60e19a054a | ||
|
|
45add1e3d6 | ||
|
|
934870f650 | ||
|
|
738cc0c9a8 | ||
|
|
cb6f964a30 | ||
|
|
9c9a7343de | ||
|
|
3803452980 | ||
|
|
a19833d0c7 | ||
|
|
084b907ac0 |
57
.travis.yml
57
.travis.yml
@@ -1,27 +1,50 @@
|
|||||||
language: python
|
language: python
|
||||||
sudo: false
|
sudo: false
|
||||||
python:
|
matrix:
|
||||||
- "3.5"
|
include:
|
||||||
- "3.4"
|
- os: linux
|
||||||
- "3.3"
|
dist: trusty
|
||||||
- "2.7"
|
python: "3.6"
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
python: "3.5"
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
python: "3.4"
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
python: "3.3"
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
python: "2.7"
|
||||||
|
- os: osx
|
||||||
|
env: FORMULA="python"
|
||||||
|
language: generic
|
||||||
|
- os: osx
|
||||||
|
env: FORMULA="python3"
|
||||||
|
language: generic
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
|
||||||
- fish-shell/release-2
|
|
||||||
packages:
|
packages:
|
||||||
- bash
|
- python-commandnotfound
|
||||||
- zsh
|
- python3-commandnotfound
|
||||||
- fish
|
before_install:
|
||||||
- tcsh
|
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then brew update ; fi
|
||||||
- pandoc
|
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then if brew ls --versions $FORMULA; then brew upgrade $FORMULA || echo Python is up to date; else brew install $FORMULA; fi; fi
|
||||||
- git
|
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then virtualenv venv -p $FORMULA; fi
|
||||||
|
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then source venv/bin/activate; fi
|
||||||
|
- pip install -U pip
|
||||||
|
- pip install -U coveralls
|
||||||
install:
|
install:
|
||||||
- pip install coveralls
|
- pip install -Ur requirements.txt
|
||||||
- pip install -r requirements.txt
|
|
||||||
- python setup.py develop
|
- python setup.py develop
|
||||||
- rm -rf build
|
- rm -rf build
|
||||||
script:
|
script:
|
||||||
- export COVERAGE_PYTHON_VERSION=python-${TRAVIS_PYTHON_VERSION:0:1}
|
- export COVERAGE_PYTHON_VERSION=python-${TRAVIS_PYTHON_VERSION:0:1}
|
||||||
- coverage run --source=thefuck,tests -m py.test -v --capture=sys --run-without-docker --enable-functional
|
- export RUN_TESTS="coverage run --source=thefuck,tests -m py.test -v --capture=sys tests"
|
||||||
after_success: coveralls
|
- if [[ $TRAVIS_PYTHON_VERSION == 3.6 && $TRAVIS_OS_NAME != "osx" ]]; then $RUN_TESTS --enable-functional; fi
|
||||||
|
- if [[ $TRAVIS_PYTHON_VERSION != 3.6 || $TRAVIS_OS_NAME == "osx" ]]; then $RUN_TESTS; fi
|
||||||
|
after_success:
|
||||||
|
- coveralls
|
||||||
|
|||||||
99
README.md
99
README.md
@@ -1,10 +1,10 @@
|
|||||||
# The Fuck [](https://travis-ci.org/nvbn/thefuck)
|
# The Fuck [![Version][version-badge]][version-link] [![Build Status][travis-badge]][travis-link] [![Windows Build Status][appveyor-badge]][appveyor-link] [![Coverage][coverage-badge]][coverage-link] [![MIT License][license-badge]](LICENSE.md)
|
||||||
|
|
||||||
Magnificent app which corrects your previous console command,
|
Magnificent app which corrects your previous console command,
|
||||||
inspired by a [@liamosaur](https://twitter.com/liamosaur/)
|
inspired by a [@liamosaur](https://twitter.com/liamosaur/)
|
||||||
[tweet](https://twitter.com/liamosaur/status/506975850596536320).
|
[tweet](https://twitter.com/liamosaur/status/506975850596536320).
|
||||||
|
|
||||||
[](https://raw.githubusercontent.com/nvbn/thefuck/master/example.gif)
|
[![gif with examples][examples-link]][examples-link]
|
||||||
|
|
||||||
Few more examples:
|
Few more examples:
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ Python 3.4.2 (default, Oct 8 2014, 13:08:17)
|
|||||||
git: 'brnch' is not a git command. See 'git --help'.
|
git: 'brnch' is not a git command. See 'git --help'.
|
||||||
|
|
||||||
Did you mean this?
|
Did you mean this?
|
||||||
branch
|
branch
|
||||||
|
|
||||||
➜ fuck
|
➜ fuck
|
||||||
git branch [enter/↑/↓/ctrl+c]
|
git branch [enter/↑/↓/ctrl+c]
|
||||||
@@ -94,20 +94,25 @@ Reading package lists... Done
|
|||||||
- pip
|
- pip
|
||||||
- python-dev
|
- python-dev
|
||||||
|
|
||||||
## Installation [*experimental*]
|
## Installation
|
||||||
|
|
||||||
|
On OS X you can install `The Fuck` with [Homebrew][homebrew]:
|
||||||
|
|
||||||
On Ubuntu and OS X you can install `The Fuck` with installation script:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget -O - https://raw.githubusercontent.com/nvbn/thefuck/master/install.sh | sh - && $0
|
brew install thefuck
|
||||||
```
|
```
|
||||||
|
|
||||||
## Manual installation
|
On Ubuntu you can install `The Fuck` with:
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install python3-dev python3-pip
|
||||||
|
sudo -H pip3 install thefuck
|
||||||
|
```
|
||||||
|
|
||||||
Install `The Fuck` with `pip`:
|
On other systems you can install `The Fuck` with `pip`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo pip install thefuck
|
sudo -H pip install thefuck
|
||||||
```
|
```
|
||||||
|
|
||||||
[Or using an OS package manager (OS X, Ubuntu, Arch).](https://github.com/nvbn/thefuck/wiki/Installation)
|
[Or using an OS package manager (OS X, Ubuntu, Arch).](https://github.com/nvbn/thefuck/wiki/Installation)
|
||||||
@@ -129,7 +134,7 @@ To make them available immediately, run `source ~/.bashrc` (or your shell config
|
|||||||
## Update
|
## Update
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo pip install thefuck --upgrade
|
sudo -H pip install thefuck --upgrade
|
||||||
```
|
```
|
||||||
|
|
||||||
**Aliases changed in 1.34.**
|
**Aliases changed in 1.34.**
|
||||||
@@ -139,11 +144,14 @@ sudo pip install thefuck --upgrade
|
|||||||
The Fuck tries to match a rule for the previous command, creates a new command
|
The Fuck tries to match a rule for the previous command, creates a new command
|
||||||
using the matched rule and runs it. Rules enabled by default are as follows:
|
using the matched rule and runs it. Rules enabled by default are as follows:
|
||||||
|
|
||||||
|
* `ag_literal` – adds `-Q` to `ag` when suggested;
|
||||||
|
* `aws_cli` – fixes misspelled commands like `aws dynamdb scan`;
|
||||||
* `cargo` – runs `cargo build` instead of `cargo`;
|
* `cargo` – runs `cargo build` instead of `cargo`;
|
||||||
* `cargo_no_command` – fixes wrongs commands like `cargo buid`;
|
* `cargo_no_command` – fixes wrongs commands like `cargo buid`;
|
||||||
* `cd_correction` – spellchecks and correct failed cd commands;
|
* `cd_correction` – spellchecks and correct failed cd commands;
|
||||||
* `cd_mkdir` – creates directories before cd'ing into them;
|
* `cd_mkdir` – creates directories before cd'ing into them;
|
||||||
* `cd_parent` – changes `cd..` to `cd ..`;
|
* `cd_parent` – changes `cd..` to `cd ..`;
|
||||||
|
* `chmod_x` – add execution bit;
|
||||||
* `composer_not_command` – fixes composer command name;
|
* `composer_not_command` – fixes composer command name;
|
||||||
* `cp_omitting_directory` – adds `-a` when you `cp` directory;
|
* `cp_omitting_directory` – adds `-a` when you `cp` directory;
|
||||||
* `cpp11` – adds missing `-std=c++11` to `g++` or `clang++`;
|
* `cpp11` – adds missing `-std=c++11` to `g++` or `clang++`;
|
||||||
@@ -153,30 +161,51 @@ using the matched rule and runs it. Rules enabled by default are as follows:
|
|||||||
* `django_south_merge` – adds `--merge` to inconsistent django south migration;
|
* `django_south_merge` – adds `--merge` to inconsistent django south migration;
|
||||||
* `docker_not_command` – fixes wrong docker commands like `docker tags`;
|
* `docker_not_command` – fixes wrong docker commands like `docker tags`;
|
||||||
* `dry` – fixes repetitions like `git git push`;
|
* `dry` – fixes repetitions like `git git push`;
|
||||||
|
* `fab_command_not_found` – fix misspelled fabric commands;
|
||||||
* `fix_alt_space` – replaces Alt+Space with Space character;
|
* `fix_alt_space` – replaces Alt+Space with Space character;
|
||||||
* `fix_file` – opens a file with an error in your `$EDITOR`;
|
* `fix_file` – opens a file with an error in your `$EDITOR`;
|
||||||
* `git_add` – fixes *"Did you forget to 'git add'?"*;
|
* `git_add` – fixes *"pathspec 'foo' did not match any file(s) known to git."*;
|
||||||
|
* `git_bisect_usage` – fixes `git bisect strt`, `git bisect goood`, `git bisect rset`, etc. when bisecting;
|
||||||
* `git_branch_delete` – changes `git branch -d` to `git branch -D`;
|
* `git_branch_delete` – changes `git branch -d` to `git branch -D`;
|
||||||
|
* `git_branch_exists` – offers `git branch -d foo`, `git branch -D foo` or `git checkout foo` when creating a branch that already exists;
|
||||||
* `git_branch_list` – catches `git branch list` in place of `git branch` and removes created branch;
|
* `git_branch_list` – catches `git branch list` in place of `git branch` and removes created branch;
|
||||||
* `git_checkout` – fixes branch name or creates new branch;
|
* `git_checkout` – fixes branch name or creates new branch;
|
||||||
|
* `git_diff_no_index` – adds `--no-index` to previous `git diff` on untracked files;
|
||||||
* `git_diff_staged` – adds `--staged` to previous `git diff` with unexpected output;
|
* `git_diff_staged` – adds `--staged` to previous `git diff` with unexpected output;
|
||||||
* `git_fix_stash` – fixes `git stash` commands (misspelled subcommand and missing `save`);
|
* `git_fix_stash` – fixes `git stash` commands (misspelled subcommand and missing `save`);
|
||||||
|
* `git_flag_after_filename` – fixes `fatal: bad flag '...' after filename`
|
||||||
|
* `git_help_aliased` – fixes `git help <alias>` commands replacing <alias> with the aliased command;
|
||||||
* `git_not_command` – fixes wrong git commands like `git brnch`;
|
* `git_not_command` – fixes wrong git commands like `git brnch`;
|
||||||
* `git_pull` – sets upstream before executing previous `git pull`;
|
* `git_pull` – sets upstream before executing previous `git pull`;
|
||||||
* `git_pull_clone` – clones instead of pulling when the repo does not exist;
|
* `git_pull_clone` – clones instead of pulling when the repo does not exist;
|
||||||
|
* `git_pull_uncommitted_changes` – stashes changes before pulling and pops them afterwards;
|
||||||
* `git_push` – adds `--set-upstream origin $branch` to previous failed `git push`;
|
* `git_push` – adds `--set-upstream origin $branch` to previous failed `git push`;
|
||||||
* `git_push_pull` – runs `git pull` when `push` was rejected;
|
* `git_push_pull` – runs `git pull` when `push` was rejected;
|
||||||
|
* `git_rebase_no_changes` – runs `git rebase --skip` instead of `git rebase --continue` when there are no changes;
|
||||||
|
* `git_rm_local_modifications` – adds `-f` or `--cached` when you try to `rm` a locally modified file;
|
||||||
|
* `git_rm_recursive` – adds `-r` when you try to `rm` a directory;
|
||||||
|
* `git_rebase_merge_dir` – offers `git rebase (--continue | --abort | --skip)` or removing the `.git/rebase-merge` dir when a rebase is in progress;
|
||||||
|
* `git_remote_seturl_add` – runs `git remote add` when `git remote set_url` on nonexistant remote;
|
||||||
* `git_stash` – stashes you local modifications before rebasing or switching branch;
|
* `git_stash` – stashes you local modifications before rebasing or switching branch;
|
||||||
|
* `git_stash_pop` – adds your local modifications before popping stash, then resets;
|
||||||
* `git_two_dashes` – adds a missing dash to commands like `git commit -amend` or `git rebase -continue`;
|
* `git_two_dashes` – adds a missing dash to commands like `git commit -amend` or `git rebase -continue`;
|
||||||
* `go_run` – appends `.go` extension when compiling/running Go programs
|
* `go_run` – appends `.go` extension when compiling/running Go programs;
|
||||||
|
* `gradle_no_task` – fixes not found or ambiguous `gradle` task;
|
||||||
|
* `gradle_wrapper` – replaces `gradle` with `./gradlew`;
|
||||||
|
* `grep_arguments_order` – fixes grep arguments order for situations like `grep -lir . test`;
|
||||||
* `grep_recursive` – adds `-r` when you trying to `grep` directory;
|
* `grep_recursive` – adds `-r` when you trying to `grep` directory;
|
||||||
|
* `grunt_task_not_found` – fixes misspelled `grunt` commands;
|
||||||
* `gulp_not_task` – fixes misspelled `gulp` tasks;
|
* `gulp_not_task` – fixes misspelled `gulp` tasks;
|
||||||
* `has_exists_script` – prepends `./` when script/binary exists;
|
* `has_exists_script` – prepends `./` when script/binary exists;
|
||||||
* `heroku_not_command` – fixes wrong `heroku` commands like `heroku log`;
|
* `heroku_not_command` – fixes wrong `heroku` commands like `heroku log`;
|
||||||
* `history` – tries to replace command with most similar command from history;
|
* `history` – tries to replace command with most similar command from history;
|
||||||
|
* `ifconfig_device_not_found` – fixes wrong device names like `wlan0` to `wlp2s0`;
|
||||||
* `java` – removes `.java` extension when running Java programs;
|
* `java` – removes `.java` extension when running Java programs;
|
||||||
* `javac` – appends missing `.java` when compiling Java files;
|
* `javac` – appends missing `.java` when compiling Java files;
|
||||||
* `lein_not_task` – fixes wrong `lein` tasks like `lein rpl`;
|
* `lein_not_task` – fixes wrong `lein` tasks like `lein rpl`;
|
||||||
|
* `ln_no_hard_link` – catches hard link creation on directories, suggest symbolic link;
|
||||||
|
* `ln_s_order` – fixes `ln -s` arguments order;
|
||||||
|
* `ls_all` – adds `-A` to `ls` when output is empty;
|
||||||
* `ls_lah` – adds `-lah` to `ls`;
|
* `ls_lah` – adds `-lah` to `ls`;
|
||||||
* `man` – changes manual section;
|
* `man` – changes manual section;
|
||||||
* `man_no_space` – fixes man commands without spaces, for example `mandiff`;
|
* `man_no_space` – fixes man commands without spaces, for example `mandiff`;
|
||||||
@@ -184,13 +213,19 @@ using the matched rule and runs it. Rules enabled by default are as follows:
|
|||||||
* `mkdir_p` – adds `-p` when you trying to create directory without parent;
|
* `mkdir_p` – adds `-p` when you trying to create directory without parent;
|
||||||
* `mvn_no_command` – adds `clean package` to `mvn`;
|
* `mvn_no_command` – adds `clean package` to `mvn`;
|
||||||
* `mvn_unknown_lifecycle_phase` – fixes misspelled lifecycle phases with `mvn`;
|
* `mvn_unknown_lifecycle_phase` – fixes misspelled lifecycle phases with `mvn`;
|
||||||
|
* `npm_missing_script` – fixes `npm` custom script name in `npm run-script <script>`;
|
||||||
|
* `npm_run_script` – adds missing `run-script` for custom `npm` scripts;
|
||||||
|
* `npm_wrong_command` – fixes wrong npm commands like `npm urgrade`;
|
||||||
* `no_command` – fixes wrong console commands, for example `vom/vim`;
|
* `no_command` – fixes wrong console commands, for example `vom/vim`;
|
||||||
* `no_such_file` – creates missing directories with `mv` and `cp` commands;
|
* `no_such_file` – creates missing directories with `mv` and `cp` commands;
|
||||||
* `open` – prepends `http` to address passed to `open`;
|
* `open` – either prepends `http://` to address passed to `open` or create a new file or directory and passes it to `open`;
|
||||||
* `pip_unknown_command` – fixes wrong `pip` commands, for example `pip instatl/pip install`;
|
* `pip_unknown_command` – fixes wrong `pip` commands, for example `pip instatl/pip install`;
|
||||||
|
* `port_already_in_use` – kills process that bound port;
|
||||||
* `python_command` – prepends `python` when you trying to run not executable/without `./` python script;
|
* `python_command` – prepends `python` when you trying to run not executable/without `./` python script;
|
||||||
* `python_execute` – appends missing `.py` when executing Python files;
|
* `python_execute` – appends missing `.py` when executing Python files;
|
||||||
* `quotation_marks` – fixes uneven usage of `'` and `"` when containing args';
|
* `quotation_marks` – fixes uneven usage of `'` and `"` when containing args';
|
||||||
|
* `react_native_command_unrecognized` – fixes unrecognized `react-native` commands;
|
||||||
|
* `remove_trailing_cedilla` – remove trailling cedillas `ç`, a common typo for european keyboard layouts;
|
||||||
* `rm_dir` – adds `-rf` when you trying to remove directory;
|
* `rm_dir` – adds `-rf` when you trying to remove directory;
|
||||||
* `sed_unterminated_s` – adds missing '/' to `sed`'s `s` commands;
|
* `sed_unterminated_s` – adds missing '/' to `sed`'s `s` commands;
|
||||||
* `sl_ls` – changes `sl` to `ls`;
|
* `sl_ls` – changes `sl` to `ls`;
|
||||||
@@ -205,7 +240,8 @@ using the matched rule and runs it. Rules enabled by default are as follows:
|
|||||||
* `tmux` – fixes `tmux` commands;
|
* `tmux` – fixes `tmux` commands;
|
||||||
* `unknown_command` – fixes hadoop hdfs-style "unknown command", for example adds missing '-' to the command on `hdfs dfs ls`;
|
* `unknown_command` – fixes hadoop hdfs-style "unknown command", for example adds missing '-' to the command on `hdfs dfs ls`;
|
||||||
* `vagrant_up` – starts up the vagrant instance;
|
* `vagrant_up` – starts up the vagrant instance;
|
||||||
* `whois` – fixes `whois` command.
|
* `whois` – fixes `whois` command;
|
||||||
|
* `workon_doesnt_exists` – fixes `virtualenvwrapper` env name os suggests to create new.
|
||||||
|
|
||||||
Enabled by default only on specific platforms:
|
Enabled by default only on specific platforms:
|
||||||
|
|
||||||
@@ -213,7 +249,10 @@ Enabled by default only on specific platforms:
|
|||||||
* `apt_get_search` – changes trying to search using `apt-get` with searching using `apt-cache`;
|
* `apt_get_search` – changes trying to search using `apt-get` with searching using `apt-cache`;
|
||||||
* `apt_invalid_operation` – fixes invalid `apt` and `apt-get` calls, like `apt-get isntall vim`;
|
* `apt_invalid_operation` – fixes invalid `apt` and `apt-get` calls, like `apt-get isntall vim`;
|
||||||
* `brew_install` – fixes formula name for `brew install`;
|
* `brew_install` – fixes formula name for `brew install`;
|
||||||
|
* `brew_link` – adds `--overwrite --dry-run` if linking fails;
|
||||||
|
* `brew_uninstall` – adds `--force` to `brew uninstall` if multiple versions were installed;
|
||||||
* `brew_unknown_command` – fixes wrong brew commands, for example `brew docto/brew doctor`;
|
* `brew_unknown_command` – fixes wrong brew commands, for example `brew docto/brew doctor`;
|
||||||
|
* `brew_update_formula` – turns `brew update <formula>` into `brew upgrade <formula>`;
|
||||||
* `brew_upgrade` – appends `--all` to `brew upgrade` as per Homebrew's new behaviour;
|
* `brew_upgrade` – appends `--all` to `brew upgrade` as per Homebrew's new behaviour;
|
||||||
* `pacman` – installs app with `pacman` if it is not installed (uses `yaourt` if available);
|
* `pacman` – installs app with `pacman` if it is not installed (uses `yaourt` if available);
|
||||||
* `pacman_not_found` – fixes package name with `pacman` or `yaourt`.
|
* `pacman_not_found` – fixes package name with `pacman` or `yaourt`.
|
||||||
@@ -240,7 +279,9 @@ side_effect(old_command: Command, fixed_command: str) -> None
|
|||||||
```
|
```
|
||||||
and optional `enabled_by_default`, `requires_output` and `priority` variables.
|
and optional `enabled_by_default`, `requires_output` and `priority` variables.
|
||||||
|
|
||||||
`Command` has three attributes: `script`, `stdout` and `stderr`.
|
`Command` has three attributes: `script`, `stdout`, `stderr` and `script_parts`.
|
||||||
|
Rule shouldn't change `Command`.
|
||||||
|
|
||||||
|
|
||||||
*Rules api changed in 3.0:* For accessing settings in rule you need to import it with `from thefuck.conf import 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 `~/.config/thefuck/settings.py` and values from env ([see more below](#settings)).
|
`settings` is a special object filled with `~/.config/thefuck/settings.py` and values from env ([see more below](#settings)).
|
||||||
@@ -283,7 +324,9 @@ The Fuck has a few settings parameters which can be changed in `$XDG_CONFIG_HOME
|
|||||||
* `priority` – dict with rules priorities, rule with lower `priority` will be matched first;
|
* `priority` – dict with rules priorities, rule with lower `priority` will be matched first;
|
||||||
* `debug` – enables debug output, by default `False`;
|
* `debug` – enables debug output, by default `False`;
|
||||||
* `history_limit` – numeric value of how many history commands will be scanned, like `2000`;
|
* `history_limit` – numeric value of how many history commands will be scanned, like `2000`;
|
||||||
* `alter_history` – push fixed command to history, by default `True`.
|
* `alter_history` – push fixed command to history, by default `True`;
|
||||||
|
* `wait_slow_command` – max amount of time in seconds for getting previous command output if it in `slow_commands` list;
|
||||||
|
* `slow_commands` – list of slow commands.
|
||||||
|
|
||||||
Example of `settings.py`:
|
Example of `settings.py`:
|
||||||
|
|
||||||
@@ -295,12 +338,15 @@ wait_command = 10
|
|||||||
no_colors = False
|
no_colors = False
|
||||||
priority = {'sudo': 100, 'no_command': 9999}
|
priority = {'sudo': 100, 'no_command': 9999}
|
||||||
debug = False
|
debug = False
|
||||||
|
history_limit = 9999
|
||||||
|
wait_slow_command = 20
|
||||||
|
slow_commands = ['react-native', 'gradle']
|
||||||
```
|
```
|
||||||
|
|
||||||
Or via environment variables:
|
Or via environment variables:
|
||||||
|
|
||||||
* `THEFUCK_RULES` – list of enabled rules, like `DEFAULT_RULES:rm_root` or `sudo:no_command`;
|
* `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_EXCLUDE_RULES` – list of disabled rules, like `git_pull:git_push`;
|
||||||
* `THEFUCK_REQUIRE_CONFIRMATION` – require confirmation before running new command, `true/false`;
|
* `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_WAIT_COMMAND` – max amount of time in seconds for getting previous command output;
|
||||||
* `THEFUCK_NO_COLORS` – disable colored output, `true/false`;
|
* `THEFUCK_NO_COLORS` – disable colored output, `true/false`;
|
||||||
@@ -308,7 +354,9 @@ Or via environment variables:
|
|||||||
rule with lower `priority` will be matched first;
|
rule with lower `priority` will be matched first;
|
||||||
* `THEFUCK_DEBUG` – enables debug output, `true/false`;
|
* `THEFUCK_DEBUG` – enables debug output, `true/false`;
|
||||||
* `THEFUCK_HISTORY_LIMIT` – how many history commands will be scanned, like `2000`;
|
* `THEFUCK_HISTORY_LIMIT` – how many history commands will be scanned, like `2000`;
|
||||||
* `THEFUCK_ALTER_HISTORY` – push fixed command to history `true/false`.
|
* `THEFUCK_ALTER_HISTORY` – push fixed command to history `true/false`;
|
||||||
|
* `THEFUCK_WAIT_SLOW_COMMAND` – max amount of time in seconds for getting previous command output if it in `slow_commands` list;
|
||||||
|
* `THEFUCK_SLOW_COMMANDS` – list of slow commands, like `lein:gradle`.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
@@ -352,3 +400,16 @@ sudo apt-get install pandoc
|
|||||||
|
|
||||||
## License MIT
|
## License MIT
|
||||||
Project License can be found [here](LICENSE.md).
|
Project License can be found [here](LICENSE.md).
|
||||||
|
|
||||||
|
|
||||||
|
[version-badge]: https://img.shields.io/pypi/v/thefuck.svg?label=version
|
||||||
|
[version-link]: https://pypi.python.org/pypi/thefuck/
|
||||||
|
[travis-badge]: https://img.shields.io/travis/nvbn/thefuck.svg
|
||||||
|
[travis-link]: https://travis-ci.org/nvbn/thefuck
|
||||||
|
[appveyor-badge]: https://img.shields.io/appveyor/ci/nvbn/thefuck.svg?label=windows%20build
|
||||||
|
[appveyor-link]: https://ci.appveyor.com/project/nvbn/thefuck
|
||||||
|
[coverage-badge]: https://img.shields.io/coveralls/nvbn/thefuck.svg
|
||||||
|
[coverage-link]: https://coveralls.io/github/nvbn/thefuck
|
||||||
|
[license-badge]: https://img.shields.io/badge/license-MIT-007EC7.svg
|
||||||
|
[examples-link]: https://raw.githubusercontent.com/nvbn/thefuck/master/example.gif
|
||||||
|
[homebrew]: http://brew.sh/
|
||||||
|
|||||||
23
appveyor.yml
Normal file
23
appveyor.yml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
build: false
|
||||||
|
|
||||||
|
environment:
|
||||||
|
matrix:
|
||||||
|
- PYTHON: "C:/Python27"
|
||||||
|
- PYTHON: "C:/Python33"
|
||||||
|
- PYTHON: "C:/Python34"
|
||||||
|
- PYTHON: "C:/Python35"
|
||||||
|
- PYTHON: "C:/Python36"
|
||||||
|
|
||||||
|
init:
|
||||||
|
- "ECHO %PYTHON%"
|
||||||
|
- ps: "ls C:/Python*"
|
||||||
|
|
||||||
|
install:
|
||||||
|
- ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py')
|
||||||
|
- "%PYTHON%/python.exe C:/get-pip.py"
|
||||||
|
- "%PYTHON%/Scripts/pip.exe install -U setuptools"
|
||||||
|
- "%PYTHON%/python.exe setup.py develop"
|
||||||
|
- "%PYTHON%/Scripts/pip.exe install -U -r requirements.txt"
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
- "%PYTHON%/Scripts/py.test.exe -sv"
|
||||||
61
install.sh
61
install.sh
@@ -1,61 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
should_add_alias () {
|
echo "Installation script is deprecated!"
|
||||||
[ -f $1 ] && ! grep -q thefuck $1
|
echo "For installation instruction please visit https://github.com/nvbn/thefuck"
|
||||||
}
|
|
||||||
|
|
||||||
installed () {
|
|
||||||
hash $1 2>/dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
install_thefuck () {
|
|
||||||
# Install OS dependencies:
|
|
||||||
if installed apt-get; then
|
|
||||||
# Debian/Ubuntu:
|
|
||||||
sudo apt-get update -yy
|
|
||||||
sudo apt-get install -yy python-pip python-dev command-not-found python-gdbm
|
|
||||||
|
|
||||||
if [[ -n $(apt-cache search python-commandnotfound) ]]; then
|
|
||||||
# In case of different python versions:
|
|
||||||
sudo apt-get install -yy python-commandnotfound
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if installed brew; then
|
|
||||||
# OS X:
|
|
||||||
brew update
|
|
||||||
brew install python
|
|
||||||
else
|
|
||||||
# Generic way:
|
|
||||||
wget https://bootstrap.pypa.io/get-pip.py
|
|
||||||
sudo python get-pip.py
|
|
||||||
rm get-pip.py
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# thefuck requires fresh versions of setuptools and pip:
|
|
||||||
sudo pip install -U pip setuptools
|
|
||||||
sudo pip install -U thefuck
|
|
||||||
|
|
||||||
# Setup aliases:
|
|
||||||
if should_add_alias ~/.bashrc; then
|
|
||||||
echo 'eval $(thefuck --alias)' >> ~/.bashrc
|
|
||||||
fi
|
|
||||||
|
|
||||||
if should_add_alias ~/.bash_profile; then
|
|
||||||
echo 'eval $(thefuck --alias)' >> ~/.bash_profile
|
|
||||||
fi
|
|
||||||
|
|
||||||
if should_add_alias ~/.zshrc; then
|
|
||||||
echo 'eval $(thefuck --alias)' >> ~/.zshrc
|
|
||||||
fi
|
|
||||||
|
|
||||||
if should_add_alias ~/.config/fish/config.fish; then
|
|
||||||
thefuck --alias >> ~/.config/fish/config.fish
|
|
||||||
fi
|
|
||||||
|
|
||||||
if should_add_alias ~/.tcshrc; then
|
|
||||||
echo 'eval `thefuck --alias`' >> ~/.tcshrc
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
install_thefuck
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
pip
|
||||||
pytest
|
pytest
|
||||||
mock
|
mock
|
||||||
pytest-mock
|
pytest-mock
|
||||||
|
|||||||
16
setup.py
16
setup.py
@@ -1,8 +1,17 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
|
import pkg_resources
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
try:
|
||||||
|
if int(pkg_resources.get_distribution("pip").version.split('.')[0]) < 6:
|
||||||
|
print('pip older than 6.0 not supported, please upgrade pip with:\n\n'
|
||||||
|
' pip install -U pip')
|
||||||
|
sys.exit(-1)
|
||||||
|
except pkg_resources.DistributionNotFound:
|
||||||
|
pass
|
||||||
|
|
||||||
if os.environ.get('CONVERT_README'):
|
if os.environ.get('CONVERT_README'):
|
||||||
import pypandoc
|
import pypandoc
|
||||||
|
|
||||||
@@ -20,10 +29,10 @@ elif (3, 0) < version < (3, 3):
|
|||||||
' ({}.{} detected).'.format(*version))
|
' ({}.{} detected).'.format(*version))
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
VERSION = '3.3'
|
VERSION = '3.14'
|
||||||
|
|
||||||
install_requires = ['psutil', 'colorama', 'six', 'decorator']
|
install_requires = ['psutil', 'colorama', 'six', 'decorator']
|
||||||
extras_require = {':python_version<"3.4"': ['pathlib'],
|
extras_require = {':python_version<"3.4"': ['pathlib2'],
|
||||||
":sys_platform=='win32'": ['win_unicode_console']}
|
":sys_platform=='win32'": ['win_unicode_console']}
|
||||||
|
|
||||||
setup(name='thefuck',
|
setup(name='thefuck',
|
||||||
@@ -35,12 +44,11 @@ setup(name='thefuck',
|
|||||||
url='https://github.com/nvbn/thefuck',
|
url='https://github.com/nvbn/thefuck',
|
||||||
license='MIT',
|
license='MIT',
|
||||||
packages=find_packages(exclude=['ez_setup', 'examples',
|
packages=find_packages(exclude=['ez_setup', 'examples',
|
||||||
'tests', 'release']),
|
'tests', 'tests.*', 'release']),
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
install_requires=install_requires,
|
install_requires=install_requires,
|
||||||
extras_require=extras_require,
|
extras_require=extras_require,
|
||||||
entry_points={'console_scripts': [
|
entry_points={'console_scripts': [
|
||||||
'thefuck = thefuck.main:main',
|
'thefuck = thefuck.main:main',
|
||||||
'thefuck-alias = thefuck.main:print_alias',
|
|
||||||
'fuck = thefuck.main:how_to_configure_alias']})
|
'fuck = thefuck.main:how_to_configure_alias']})
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
from pathlib import Path
|
|
||||||
import pytest
|
import pytest
|
||||||
from thefuck import conf
|
from thefuck import shells
|
||||||
|
from thefuck import conf, const
|
||||||
|
from thefuck.system import Path
|
||||||
|
|
||||||
|
shells.shell = shells.Generic()
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
@@ -19,7 +22,7 @@ def no_memoize(monkeypatch):
|
|||||||
def settings(request):
|
def settings(request):
|
||||||
def _reset_settings():
|
def _reset_settings():
|
||||||
conf.settings.clear()
|
conf.settings.clear()
|
||||||
conf.settings.update(conf.DEFAULT_SETTINGS)
|
conf.settings.update(const.DEFAULT_SETTINGS)
|
||||||
|
|
||||||
request.addfinalizer(_reset_settings)
|
request.addfinalizer(_reset_settings)
|
||||||
conf.settings.user_dir = Path('~/.thefuck')
|
conf.settings.user_dir = Path('~/.thefuck')
|
||||||
@@ -46,3 +49,14 @@ def functional(request):
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def source_root():
|
def source_root():
|
||||||
return Path(__file__).parent.parent.resolve()
|
return Path(__file__).parent.parent.resolve()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def set_shell(monkeypatch, request):
|
||||||
|
def _set(cls):
|
||||||
|
shell = cls()
|
||||||
|
monkeypatch.setattr('thefuck.shells.shell', shell)
|
||||||
|
request.addfinalizer()
|
||||||
|
return shell
|
||||||
|
|
||||||
|
return _set
|
||||||
|
|||||||
@@ -3,26 +3,19 @@ from tests.functional.plots import with_confirmation, without_confirmation, \
|
|||||||
refuse_with_confirmation, history_changed, history_not_changed, \
|
refuse_with_confirmation, history_changed, history_not_changed, \
|
||||||
select_command_with_arrows, how_to_configure
|
select_command_with_arrows, how_to_configure
|
||||||
|
|
||||||
containers = ((u'thefuck/ubuntu-python3-bash',
|
containers = ((u'thefuck/python3-bash',
|
||||||
u'''FROM ubuntu:latest
|
u'FROM python:3',
|
||||||
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'bash'),
|
||||||
(u'thefuck/ubuntu-python2-bash',
|
(u'thefuck/python2-bash',
|
||||||
u'''FROM ubuntu:latest
|
u'FROM python:2',
|
||||||
RUN apt-get update
|
|
||||||
RUN apt-get install -yy python python-pip python-dev git
|
|
||||||
RUN pip2 install -U pip setuptools''',
|
|
||||||
u'bash'))
|
u'bash'))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(params=containers)
|
@pytest.fixture(params=containers)
|
||||||
def proc(request, spawnu, run_without_docker):
|
def proc(request, spawnu, TIMEOUT):
|
||||||
proc = spawnu(*request.param)
|
proc = spawnu(*request.param)
|
||||||
if not run_without_docker:
|
proc.sendline(u"pip install /src")
|
||||||
proc.sendline(u"pip install /src")
|
assert proc.expect([TIMEOUT, u'Successfully installed'])
|
||||||
proc.sendline(u"export PS1='$ '")
|
proc.sendline(u"export PS1='$ '")
|
||||||
proc.sendline(u'eval $(thefuck --alias)')
|
proc.sendline(u'eval $(thefuck --alias)')
|
||||||
proc.sendline(u'echo > $HISTFILE')
|
proc.sendline(u'echo > $HISTFILE')
|
||||||
@@ -30,38 +23,29 @@ def proc(request, spawnu, run_without_docker):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.once_without_docker
|
def test_with_confirmation(proc, TIMEOUT):
|
||||||
def test_with_confirmation(proc, TIMEOUT, run_without_docker):
|
|
||||||
with_confirmation(proc, TIMEOUT)
|
with_confirmation(proc, TIMEOUT)
|
||||||
if not run_without_docker:
|
history_changed(proc, TIMEOUT, u'echo test')
|
||||||
history_changed(proc, TIMEOUT, u'echo test')
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.once_without_docker
|
def test_select_command_with_arrows(proc, TIMEOUT):
|
||||||
def test_select_command_with_arrows(proc, TIMEOUT, run_without_docker):
|
|
||||||
select_command_with_arrows(proc, TIMEOUT)
|
select_command_with_arrows(proc, TIMEOUT)
|
||||||
if not run_without_docker:
|
history_changed(proc, TIMEOUT, u'git help')
|
||||||
history_changed(proc, TIMEOUT, u'git help')
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.once_without_docker
|
def test_refuse_with_confirmation(proc, TIMEOUT):
|
||||||
def test_refuse_with_confirmation(proc, TIMEOUT, run_without_docker):
|
|
||||||
refuse_with_confirmation(proc, TIMEOUT)
|
refuse_with_confirmation(proc, TIMEOUT)
|
||||||
if not run_without_docker:
|
history_not_changed(proc, TIMEOUT)
|
||||||
history_not_changed(proc, TIMEOUT)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.once_without_docker
|
def test_without_confirmation(proc, TIMEOUT):
|
||||||
def test_without_confirmation(proc, TIMEOUT, run_without_docker):
|
|
||||||
without_confirmation(proc, TIMEOUT)
|
without_confirmation(proc, TIMEOUT)
|
||||||
if not run_without_docker:
|
history_changed(proc, TIMEOUT, u'echo test')
|
||||||
history_changed(proc, TIMEOUT, u'echo test')
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.once_without_docker
|
|
||||||
def test_how_to_configure_alias(proc, TIMEOUT):
|
def test_how_to_configure_alias(proc, TIMEOUT):
|
||||||
how_to_configure(proc, TIMEOUT)
|
how_to_configure(proc, TIMEOUT)
|
||||||
|
|||||||
@@ -2,52 +2,50 @@ import pytest
|
|||||||
from tests.functional.plots import with_confirmation, without_confirmation, \
|
from tests.functional.plots import with_confirmation, without_confirmation, \
|
||||||
refuse_with_confirmation, select_command_with_arrows
|
refuse_with_confirmation, select_command_with_arrows
|
||||||
|
|
||||||
containers = (('thefuck/ubuntu-python3-fish',
|
containers = (('thefuck/python3-fish',
|
||||||
u'''FROM ubuntu:latest
|
u'''FROM python:3
|
||||||
|
# Use jessie-backports since it has the fish package. See here for details:
|
||||||
|
# https://github.com/tianon/docker-brew-debian/blob/88ae21052affd8a14553bb969f9d41c464032122/jessie/backports/Dockerfile
|
||||||
|
RUN awk '$1 ~ "^deb" { $3 = $3 "-backports"; print; exit }' /etc/apt/sources.list > /etc/apt/sources.list.d/backports.list
|
||||||
RUN apt-get update
|
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''',
|
RUN apt-get install -yy fish''',
|
||||||
u'fish'),
|
u'fish'),
|
||||||
('thefuck/ubuntu-python2-fish',
|
('thefuck/python2-fish',
|
||||||
u'''FROM ubuntu:latest
|
u'''FROM python:2
|
||||||
|
# Use jessie-backports since it has the fish package. See here for details:
|
||||||
|
# https://github.com/tianon/docker-brew-debian/blob/88ae21052affd8a14553bb969f9d41c464032122/jessie/backports/Dockerfile
|
||||||
|
RUN awk '$1 ~ "^deb" { $3 = $3 "-backports"; print; exit }' /etc/apt/sources.list > /etc/apt/sources.list.d/backports.list
|
||||||
RUN apt-get update
|
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''',
|
RUN apt-get install -yy fish''',
|
||||||
u'fish'))
|
u'fish'))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(params=containers)
|
@pytest.fixture(params=containers)
|
||||||
def proc(request, spawnu):
|
def proc(request, spawnu, TIMEOUT):
|
||||||
proc = spawnu(*request.param)
|
proc = spawnu(*request.param)
|
||||||
proc.sendline(u"pip install /src")
|
proc.sendline(u"pip install /src")
|
||||||
|
assert proc.expect([TIMEOUT, u'Successfully installed'])
|
||||||
proc.sendline(u'thefuck --alias > ~/.config/fish/config.fish')
|
proc.sendline(u'thefuck --alias > ~/.config/fish/config.fish')
|
||||||
proc.sendline(u'fish')
|
proc.sendline(u'fish')
|
||||||
return proc
|
return proc
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.skip_without_docker
|
|
||||||
def test_with_confirmation(proc, TIMEOUT):
|
def test_with_confirmation(proc, TIMEOUT):
|
||||||
with_confirmation(proc, TIMEOUT)
|
with_confirmation(proc, TIMEOUT)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.skip_without_docker
|
|
||||||
def test_select_command_with_arrows(proc, TIMEOUT):
|
def test_select_command_with_arrows(proc, TIMEOUT):
|
||||||
select_command_with_arrows(proc, TIMEOUT)
|
select_command_with_arrows(proc, TIMEOUT)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.skip_without_docker
|
|
||||||
def test_refuse_with_confirmation(proc, TIMEOUT):
|
def test_refuse_with_confirmation(proc, TIMEOUT):
|
||||||
refuse_with_confirmation(proc, TIMEOUT)
|
refuse_with_confirmation(proc, TIMEOUT)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.skip_without_docker
|
|
||||||
def test_without_confirmation(proc, TIMEOUT):
|
def test_without_confirmation(proc, TIMEOUT):
|
||||||
without_confirmation(proc, TIMEOUT)
|
without_confirmation(proc, TIMEOUT)
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
import pytest
|
|
||||||
from thefuck.utils import get_installation_info
|
|
||||||
|
|
||||||
envs = ((u'bash', 'thefuck/ubuntu-bash', u'''
|
|
||||||
FROM ubuntu:latest
|
|
||||||
RUN apt-get update
|
|
||||||
RUN apt-get install -yy bash
|
|
||||||
'''), (u'bash', 'thefuck/generic-bash', u'''
|
|
||||||
FROM fedora:latest
|
|
||||||
RUN dnf install -yy python-devel sudo wget gcc
|
|
||||||
'''))
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
|
||||||
@pytest.mark.skip_without_docker
|
|
||||||
@pytest.mark.parametrize('shell, tag, dockerfile', envs)
|
|
||||||
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')
|
|
||||||
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'])
|
|
||||||
@@ -2,11 +2,7 @@ import pytest
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
dockerfile = u'''
|
dockerfile = u'''
|
||||||
FROM ubuntu:latest
|
FROM python:3
|
||||||
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 adduser --disabled-password --gecos '' test
|
RUN adduser --disabled-password --gecos '' test
|
||||||
ENV SEED "{seed}"
|
ENV SEED "{seed}"
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
@@ -40,10 +36,9 @@ def plot(proc, TIMEOUT):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.skip_without_docker
|
|
||||||
@pytest.mark.benchmark(min_rounds=10)
|
@pytest.mark.benchmark(min_rounds=10)
|
||||||
def test_performance(spawnu, TIMEOUT, benchmark):
|
def test_performance(spawnu, TIMEOUT, benchmark):
|
||||||
proc = spawnu(u'thefuck/ubuntu-python3-bash-performance',
|
proc = spawnu(u'thefuck/python3-bash-performance',
|
||||||
dockerfile, u'bash')
|
dockerfile, u'bash')
|
||||||
proc.sendline(u'pip install /src')
|
proc.sendline(u'pip install /src')
|
||||||
proc.sendline(u'su test')
|
proc.sendline(u'su test')
|
||||||
|
|||||||
@@ -2,53 +2,45 @@ import pytest
|
|||||||
from tests.functional.plots import with_confirmation, without_confirmation, \
|
from tests.functional.plots import with_confirmation, without_confirmation, \
|
||||||
refuse_with_confirmation, select_command_with_arrows
|
refuse_with_confirmation, select_command_with_arrows
|
||||||
|
|
||||||
containers = (('thefuck/ubuntu-python3-tcsh',
|
containers = (('thefuck/python3-tcsh',
|
||||||
u'''FROM ubuntu:latest
|
u'''FROM python:3
|
||||||
RUN apt-get update
|
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''',
|
RUN apt-get install -yy tcsh''',
|
||||||
u'tcsh'),
|
u'tcsh'),
|
||||||
('thefuck/ubuntu-python2-tcsh',
|
('thefuck/python2-tcsh',
|
||||||
u'''FROM ubuntu:latest
|
u'''FROM python:2
|
||||||
RUN apt-get update
|
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''',
|
RUN apt-get install -yy tcsh''',
|
||||||
u'tcsh'))
|
u'tcsh'))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(params=containers)
|
@pytest.fixture(params=containers)
|
||||||
def proc(request, spawnu, run_without_docker):
|
def proc(request, spawnu, TIMEOUT):
|
||||||
proc = spawnu(*request.param)
|
proc = spawnu(*request.param)
|
||||||
if not run_without_docker:
|
proc.sendline(u'pip install /src')
|
||||||
proc.sendline(u'pip install /src')
|
assert proc.expect([TIMEOUT, u'Successfully installed'])
|
||||||
proc.sendline(u'tcsh')
|
proc.sendline(u'tcsh')
|
||||||
|
proc.sendline(u'setenv PYTHONIOENCODING utf8')
|
||||||
proc.sendline(u'eval `thefuck --alias`')
|
proc.sendline(u'eval `thefuck --alias`')
|
||||||
return proc
|
return proc
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.once_without_docker
|
|
||||||
def test_with_confirmation(proc, TIMEOUT):
|
def test_with_confirmation(proc, TIMEOUT):
|
||||||
with_confirmation(proc, TIMEOUT)
|
with_confirmation(proc, TIMEOUT)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.once_without_docker
|
|
||||||
def test_select_command_with_arrows(proc, TIMEOUT):
|
def test_select_command_with_arrows(proc, TIMEOUT):
|
||||||
select_command_with_arrows(proc, TIMEOUT)
|
select_command_with_arrows(proc, TIMEOUT)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.once_without_docker
|
|
||||||
def test_refuse_with_confirmation(proc, TIMEOUT):
|
def test_refuse_with_confirmation(proc, TIMEOUT):
|
||||||
refuse_with_confirmation(proc, TIMEOUT)
|
refuse_with_confirmation(proc, TIMEOUT)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.once_without_docker
|
|
||||||
def test_without_confirmation(proc, TIMEOUT):
|
def test_without_confirmation(proc, TIMEOUT):
|
||||||
without_confirmation(proc, TIMEOUT)
|
without_confirmation(proc, TIMEOUT)
|
||||||
|
|
||||||
|
|||||||
@@ -3,28 +3,23 @@ from tests.functional.plots import with_confirmation, without_confirmation, \
|
|||||||
refuse_with_confirmation, history_changed, history_not_changed, \
|
refuse_with_confirmation, history_changed, history_not_changed, \
|
||||||
select_command_with_arrows, how_to_configure
|
select_command_with_arrows, how_to_configure
|
||||||
|
|
||||||
containers = (('thefuck/ubuntu-python3-zsh',
|
containers = (('thefuck/python3-zsh',
|
||||||
u'''FROM ubuntu:latest
|
u'''FROM python:3
|
||||||
RUN apt-get update
|
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''',
|
RUN apt-get install -yy zsh''',
|
||||||
u'zsh'),
|
u'zsh'),
|
||||||
('thefuck/ubuntu-python2-zsh',
|
('thefuck/python2-zsh',
|
||||||
u'''FROM ubuntu:latest
|
u'''FROM python:2
|
||||||
RUN apt-get update
|
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''',
|
RUN apt-get install -yy zsh''',
|
||||||
u'zsh'))
|
u'zsh'))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(params=containers)
|
@pytest.fixture(params=containers)
|
||||||
def proc(request, spawnu, run_without_docker):
|
def proc(request, spawnu, TIMEOUT):
|
||||||
proc = spawnu(*request.param)
|
proc = spawnu(*request.param)
|
||||||
if not run_without_docker:
|
proc.sendline(u'pip install /src')
|
||||||
proc.sendline(u'pip install /src')
|
assert proc.expect([TIMEOUT, u'Successfully installed'])
|
||||||
proc.sendline(u'eval $(thefuck --alias)')
|
proc.sendline(u'eval $(thefuck --alias)')
|
||||||
proc.sendline(u'export HISTFILE=~/.zsh_history')
|
proc.sendline(u'export HISTFILE=~/.zsh_history')
|
||||||
proc.sendline(u'echo > $HISTFILE')
|
proc.sendline(u'echo > $HISTFILE')
|
||||||
@@ -35,34 +30,29 @@ def proc(request, spawnu, run_without_docker):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.once_without_docker
|
|
||||||
def test_with_confirmation(proc, TIMEOUT):
|
def test_with_confirmation(proc, TIMEOUT):
|
||||||
with_confirmation(proc, TIMEOUT)
|
with_confirmation(proc, TIMEOUT)
|
||||||
history_changed(proc, TIMEOUT, u'echo test')
|
history_changed(proc, TIMEOUT, u'echo test')
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.once_without_docker
|
|
||||||
def test_select_command_with_arrows(proc, TIMEOUT):
|
def test_select_command_with_arrows(proc, TIMEOUT):
|
||||||
select_command_with_arrows(proc, TIMEOUT)
|
select_command_with_arrows(proc, TIMEOUT)
|
||||||
history_changed(proc, TIMEOUT, u'git help')
|
history_changed(proc, TIMEOUT, u'git help')
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.once_without_docker
|
|
||||||
def test_refuse_with_confirmation(proc, TIMEOUT):
|
def test_refuse_with_confirmation(proc, TIMEOUT):
|
||||||
refuse_with_confirmation(proc, TIMEOUT)
|
refuse_with_confirmation(proc, TIMEOUT)
|
||||||
history_not_changed(proc, TIMEOUT)
|
history_not_changed(proc, TIMEOUT)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.once_without_docker
|
|
||||||
def test_without_confirmation(proc, TIMEOUT):
|
def test_without_confirmation(proc, TIMEOUT):
|
||||||
without_confirmation(proc, TIMEOUT)
|
without_confirmation(proc, TIMEOUT)
|
||||||
history_changed(proc, TIMEOUT, u'echo test')
|
history_changed(proc, TIMEOUT, u'echo test')
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.once_without_docker
|
|
||||||
def test_how_to_configure_alias(proc, TIMEOUT):
|
def test_how_to_configure_alias(proc, TIMEOUT):
|
||||||
how_to_configure(proc, TIMEOUT)
|
how_to_configure(proc, TIMEOUT)
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
import pytest
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
|
||||||
def generic_shell(monkeypatch):
|
|
||||||
monkeypatch.setattr('thefuck.shells.and_', lambda *x: u' && '.join(x))
|
|
||||||
25
tests/rules/test_ag_literal.py
Normal file
25
tests/rules/test_ag_literal.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.ag_literal import get_new_command, match
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def stderr():
|
||||||
|
return ('ERR: Bad regex! pcre_compile() failed at position 1: missing )\n'
|
||||||
|
'If you meant to search for a literal string, run ag with -Q\n')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', ['ag \('])
|
||||||
|
def test_match(script, stderr):
|
||||||
|
assert match(Command(script=script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', ['ag foo'])
|
||||||
|
def test_not_match(script):
|
||||||
|
assert not match(Command(script=script))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, new_cmd', [
|
||||||
|
('ag \(', 'ag -Q \(')])
|
||||||
|
def test_get_new_command(script, new_cmd, stderr):
|
||||||
|
assert get_new_command((Command(script=script, stderr=stderr))) == new_cmd
|
||||||
@@ -1,53 +1,41 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from mock import Mock, patch
|
|
||||||
from thefuck.rules import apt_get
|
|
||||||
from thefuck.rules.apt_get import match, get_new_command
|
from thefuck.rules.apt_get import match, get_new_command
|
||||||
from tests.utils import Command
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
# python-commandnotfound is available in ubuntu 14.04+
|
@pytest.mark.parametrize('command, packages', [
|
||||||
@pytest.mark.skipif(not getattr(apt_get, 'enabled_by_default', True),
|
|
||||||
reason='Skip if python-commandnotfound is not available')
|
|
||||||
@pytest.mark.parametrize('command', [
|
|
||||||
Command(script='vim', stderr='vim: command not found')])
|
|
||||||
def test_match(command):
|
|
||||||
assert match(command)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('command, return_value', [
|
|
||||||
(Command(script='vim', stderr='vim: command not found'),
|
(Command(script='vim', stderr='vim: command not found'),
|
||||||
[('vim', 'main'), ('vim-tiny', 'main')]),
|
[('vim', 'main'), ('vim-tiny', 'main')]),
|
||||||
(Command(script='sudo vim', stderr='vim: command not found'),
|
(Command(script='sudo vim', stderr='vim: command not found'),
|
||||||
[('vim', 'main'), ('vim-tiny', 'main')])])
|
[('vim', 'main'), ('vim-tiny', 'main')])])
|
||||||
@patch('thefuck.rules.apt_get.CommandNotFound', create=True)
|
def test_match(mocker, command, packages):
|
||||||
@patch.multiple(apt_get, create=True, apt_get='apt_get')
|
mocker.patch('thefuck.rules.apt_get.which', return_value=None)
|
||||||
def test_match_mocked(cmdnf_mock, command, return_value):
|
mock = mocker.patch('thefuck.rules.apt_get.command_not_found',
|
||||||
get_packages = Mock(return_value=return_value)
|
create=True)
|
||||||
cmdnf_mock.CommandNotFound.return_value = Mock(getPackages=get_packages)
|
mock.getPackages.return_value = packages
|
||||||
|
|
||||||
assert match(command)
|
assert match(command)
|
||||||
assert cmdnf_mock.CommandNotFound.called
|
|
||||||
assert get_packages.called
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('command', [
|
@pytest.mark.parametrize('command, packages, which', [
|
||||||
Command(script='vim', stderr=''), Command()])
|
(Command(script='a_bad_cmd', stderr='a_bad_cmd: command not found'),
|
||||||
def test_not_match(command):
|
[], None),
|
||||||
|
(Command(script='vim', stderr=''), [], None),
|
||||||
|
(Command(), [], None),
|
||||||
|
(Command(script='vim', stderr='vim: command not found'),
|
||||||
|
['vim'], '/usr/bin/vim'),
|
||||||
|
(Command(script='sudo vim', stderr='vim: command not found'),
|
||||||
|
['vim'], '/usr/bin/vim')])
|
||||||
|
def test_not_match(mocker, command, packages, which):
|
||||||
|
mocker.patch('thefuck.rules.apt_get.which', return_value=which)
|
||||||
|
mock = mocker.patch('thefuck.rules.apt_get.command_not_found',
|
||||||
|
create=True)
|
||||||
|
mock.getPackages.return_value = packages
|
||||||
|
|
||||||
assert not match(command)
|
assert not match(command)
|
||||||
|
|
||||||
|
|
||||||
# python-commandnotfound is available in ubuntu 14.04+
|
@pytest.mark.parametrize('command, new_command, packages', [
|
||||||
@pytest.mark.skipif(not getattr(apt_get, 'enabled_by_default', True),
|
|
||||||
reason='Skip if python-commandnotfound is not available')
|
|
||||||
@pytest.mark.parametrize('command, new_command', [
|
|
||||||
(Command('vim'), 'sudo apt-get install vim && vim'),
|
|
||||||
(Command('convert'), 'sudo apt-get install imagemagick && convert'),
|
|
||||||
(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) == new_command
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('command, new_command, return_value', [
|
|
||||||
(Command('vim'), 'sudo apt-get install vim && vim',
|
(Command('vim'), 'sudo apt-get install vim && vim',
|
||||||
[('vim', 'main'), ('vim-tiny', 'main')]),
|
[('vim', 'main'), ('vim-tiny', 'main')]),
|
||||||
(Command('convert'), 'sudo apt-get install imagemagick && convert',
|
(Command('convert'), 'sudo apt-get install imagemagick && convert',
|
||||||
@@ -58,9 +46,8 @@ def test_get_new_command(command, new_command):
|
|||||||
(Command('sudo convert'), 'sudo apt-get install imagemagick && sudo convert',
|
(Command('sudo convert'), 'sudo apt-get install imagemagick && sudo convert',
|
||||||
[('imagemagick', 'main'),
|
[('imagemagick', 'main'),
|
||||||
('graphicsmagick-imagemagick-compat', 'universe')])])
|
('graphicsmagick-imagemagick-compat', 'universe')])])
|
||||||
@patch('thefuck.rules.apt_get.CommandNotFound', create=True)
|
def test_get_new_command(mocker, command, new_command, packages):
|
||||||
@patch.multiple(apt_get, create=True, apt_get='apt_get')
|
mock = mocker.patch('thefuck.rules.apt_get.command_not_found',
|
||||||
def test_get_new_command_mocked(cmdnf_mock, command, new_command, return_value):
|
create=True)
|
||||||
get_packages = Mock(return_value=return_value)
|
mock.getPackages.return_value = packages
|
||||||
cmdnf_mock.CommandNotFound.return_value = Mock(getPackages=get_packages)
|
|
||||||
assert get_new_command(command) == new_command
|
assert get_new_command(command) == new_command
|
||||||
|
|||||||
101
tests/rules/test_aws_cli.py
Normal file
101
tests/rules/test_aws_cli.py
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from thefuck.rules.aws_cli import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
no_suggestions = '''\
|
||||||
|
usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
|
||||||
|
To see help text, you can run:
|
||||||
|
|
||||||
|
aws help
|
||||||
|
aws <command> help
|
||||||
|
aws <command> <subcommand> help
|
||||||
|
aws: error: argument command: Invalid choice, valid choices are:
|
||||||
|
|
||||||
|
dynamodb | dynamodbstreams
|
||||||
|
ec2 | ecr
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
misspelled_command = '''\
|
||||||
|
usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
|
||||||
|
To see help text, you can run:
|
||||||
|
|
||||||
|
aws help
|
||||||
|
aws <command> help
|
||||||
|
aws <command> <subcommand> help
|
||||||
|
aws: error: argument command: Invalid choice, valid choices are:
|
||||||
|
|
||||||
|
dynamodb | dynamodbstreams
|
||||||
|
ec2 | ecr
|
||||||
|
|
||||||
|
|
||||||
|
Invalid choice: 'dynamdb', maybe you meant:
|
||||||
|
|
||||||
|
* dynamodb
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
misspelled_subcommand = '''\
|
||||||
|
usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
|
||||||
|
To see help text, you can run:
|
||||||
|
|
||||||
|
aws help
|
||||||
|
aws <command> help
|
||||||
|
aws <command> <subcommand> help
|
||||||
|
aws: error: argument operation: Invalid choice, valid choices are:
|
||||||
|
|
||||||
|
query | scan
|
||||||
|
update-item | update-table
|
||||||
|
|
||||||
|
|
||||||
|
Invalid choice: 'scn', maybe you meant:
|
||||||
|
|
||||||
|
* scan
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
misspelled_subcommand_with_multiple_options = '''\
|
||||||
|
usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
|
||||||
|
To see help text, you can run:
|
||||||
|
|
||||||
|
aws help
|
||||||
|
aws <command> help
|
||||||
|
aws <command> <subcommand> help
|
||||||
|
aws: error: argument operation: Invalid choice, valid choices are:
|
||||||
|
|
||||||
|
describe-table | get-item
|
||||||
|
list-tables | put-item
|
||||||
|
|
||||||
|
|
||||||
|
Invalid choice: 't-item', maybe you meant:
|
||||||
|
|
||||||
|
* put-item
|
||||||
|
* get-item
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command('aws dynamdb scan', stderr=misspelled_command),
|
||||||
|
Command('aws dynamodb scn', stderr=misspelled_subcommand),
|
||||||
|
Command('aws dynamodb t-item',
|
||||||
|
stderr=misspelled_subcommand_with_multiple_options)])
|
||||||
|
def test_match(command):
|
||||||
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
|
def test_not_match():
|
||||||
|
assert not match(Command('aws dynamodb invalid', stderr=no_suggestions))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command, result', [
|
||||||
|
(Command('aws dynamdb scan', stderr=misspelled_command),
|
||||||
|
['aws dynamodb scan']),
|
||||||
|
(Command('aws dynamodb scn', stderr=misspelled_subcommand),
|
||||||
|
['aws dynamodb scan']),
|
||||||
|
(Command('aws dynamodb t-item',
|
||||||
|
stderr=misspelled_subcommand_with_multiple_options),
|
||||||
|
['aws dynamodb put-item', 'aws dynamodb get-item'])])
|
||||||
|
def test_get_new_command(command, result):
|
||||||
|
assert get_new_command(command) == result
|
||||||
38
tests/rules/test_brew_link.py
Normal file
38
tests/rules/test_brew_link.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import pytest
|
||||||
|
from tests.utils import Command
|
||||||
|
from thefuck.rules.brew_link import get_new_command, match
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def stderr():
|
||||||
|
return ("Error: Could not symlink bin/gcp\n"
|
||||||
|
"Target /usr/local/bin/gcp\n"
|
||||||
|
"already exists. You may want to remove it:\n"
|
||||||
|
"rm '/usr/local/bin/gcp'\n"
|
||||||
|
"\n"
|
||||||
|
"To force the link and overwrite all conflicting files:\n"
|
||||||
|
"brew link --overwrite coreutils\n"
|
||||||
|
"\n"
|
||||||
|
"To list all files that would be deleted:\n"
|
||||||
|
"brew link --overwrite --dry-run coreutils\n")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def new_command(formula):
|
||||||
|
return 'brew link --overwrite --dry-run {}'.format(formula)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', ['brew link coreutils', 'brew ln coreutils'])
|
||||||
|
def test_match(stderr, script):
|
||||||
|
assert match(Command(script=script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', ['brew link coreutils'])
|
||||||
|
def test_not_match(script):
|
||||||
|
stderr=''
|
||||||
|
assert not match(Command(script=script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, formula, ', [('brew link coreutils', 'coreutils')])
|
||||||
|
def test_get_new_command(stderr, new_command, script, formula):
|
||||||
|
assert get_new_command(Command(script=script, stderr=stderr)) == new_command
|
||||||
31
tests/rules/test_brew_uninstall.py
Normal file
31
tests/rules/test_brew_uninstall.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import pytest
|
||||||
|
from tests.utils import Command
|
||||||
|
from thefuck.rules.brew_uninstall import get_new_command, match
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def stdout():
|
||||||
|
return ("Uninstalling /usr/local/Cellar/tbb/4.4-20160916... (118 files, 1.9M)\n"
|
||||||
|
"tbb 4.4-20160526, 4.4-20160722 are still installed.\n"
|
||||||
|
"Remove all versions with `brew uninstall --force tbb`.\n")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def new_command(formula):
|
||||||
|
return 'brew uninstall --force {}'.format(formula)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', ['brew uninstall tbb', 'brew rm tbb', 'brew remove tbb'])
|
||||||
|
def test_match(stdout, script):
|
||||||
|
assert match(Command(script=script, stdout=stdout))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', ['brew remove gnuplot'])
|
||||||
|
def test_not_match(script):
|
||||||
|
stdout='Uninstalling /usr/local/Cellar/gnuplot/5.0.4_1... (44 files, 2.3M)\n'
|
||||||
|
assert not match(Command(script=script, stdout=stdout))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, formula, ', [('brew uninstall tbb', 'tbb')])
|
||||||
|
def test_get_new_command(stdout, new_command, script, formula):
|
||||||
|
assert get_new_command(Command(script=script, stdout=stdout)) == new_command
|
||||||
30
tests/rules/test_brew_update_formula.py
Normal file
30
tests/rules/test_brew_update_formula.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import pytest
|
||||||
|
from tests.utils import Command
|
||||||
|
from thefuck.rules.brew_update_formula import get_new_command, match
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def stderr():
|
||||||
|
return ("Error: This command updates brew itself, and does not take formula"
|
||||||
|
" names.\nUse 'brew upgrade <formula>'.")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def new_command(formula):
|
||||||
|
return 'brew upgrade {}'.format(formula)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', ['brew update foo', 'brew update bar zap'])
|
||||||
|
def test_match(stderr, script):
|
||||||
|
assert match(Command(script=script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', ['brew upgrade foo', 'brew update'])
|
||||||
|
def test_not_match(script):
|
||||||
|
assert not match(Command(script=script, stderr=''))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, formula, ', [
|
||||||
|
('brew update foo', 'foo'), ('brew update bar zap', 'bar zap')])
|
||||||
|
def test_get_new_command(stderr, new_command, script, formula):
|
||||||
|
assert get_new_command(Command(script=script, stderr=stderr)) == new_command
|
||||||
@@ -3,19 +3,26 @@ from thefuck.rules.cargo_no_command import match, get_new_command
|
|||||||
from tests.utils import Command
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
no_such_subcommand = """No such subcommand
|
no_such_subcommand_old = """No such subcommand
|
||||||
|
|
||||||
Did you mean `build`?
|
Did you mean `build`?
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
no_such_subcommand = """error: no such subcommand
|
||||||
|
|
||||||
|
\tDid you mean `build`?
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('command', [
|
@pytest.mark.parametrize('command', [
|
||||||
Command(script='cargo buid', stderr=no_such_subcommand)])
|
Command(script='cargo buid', stderr=no_such_subcommand_old),
|
||||||
|
Command(script='cargo buils', stderr=no_such_subcommand)])
|
||||||
def test_match(command):
|
def test_match(command):
|
||||||
assert match(command)
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('command, new_command', [
|
@pytest.mark.parametrize('command, new_command', [
|
||||||
(Command('cargo buid', stderr=no_such_subcommand), 'cargo build')])
|
(Command('cargo buid', stderr=no_such_subcommand_old), 'cargo build'),
|
||||||
|
(Command('cargo buils', stderr=no_such_subcommand), 'cargo build')])
|
||||||
def test_get_new_command(command, new_command):
|
def test_get_new_command(command, new_command):
|
||||||
assert get_new_command(command) == new_command
|
assert get_new_command(command) == new_command
|
||||||
|
|||||||
39
tests/rules/test_chmod_x.py
Normal file
39
tests/rules/test_chmod_x.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import pytest
|
||||||
|
from tests.utils import Command
|
||||||
|
from thefuck.rules.chmod_x import match, get_new_command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def file_exists(mocker):
|
||||||
|
return mocker.patch('os.path.exists', return_value=True)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def file_access(mocker):
|
||||||
|
return mocker.patch('os.access', return_value=False)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('file_exists', 'file_access')
|
||||||
|
@pytest.mark.parametrize('script, stderr', [
|
||||||
|
('./gradlew build', 'gradlew: Permission denied'),
|
||||||
|
('./install.sh --help', 'install.sh: permission denied')])
|
||||||
|
def test_match(script, stderr):
|
||||||
|
assert match(Command(script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, stderr, exists, callable', [
|
||||||
|
('./gradlew build', 'gradlew: Permission denied', True, True),
|
||||||
|
('./gradlew build', 'gradlew: Permission denied', False, False),
|
||||||
|
('./gradlew build', 'gradlew: error', True, False),
|
||||||
|
('gradlew build', 'gradlew: Permission denied', True, False)])
|
||||||
|
def test_not_match(file_exists, file_access, script, stderr, exists, callable):
|
||||||
|
file_exists.return_value = exists
|
||||||
|
file_access.return_value = callable
|
||||||
|
assert not match(Command(script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, result', [
|
||||||
|
('./gradlew build', 'chmod +x gradlew && ./gradlew build'),
|
||||||
|
('./install.sh --help', 'chmod +x install.sh && ./install.sh --help')])
|
||||||
|
def test_get_new_command(script, result):
|
||||||
|
assert get_new_command(Command(script)) == result
|
||||||
49
tests/rules/test_fab_command_not_found.py
Normal file
49
tests/rules/test_fab_command_not_found.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.fab_command_not_found import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
stderr = '''
|
||||||
|
Warning: Command(s) not found:
|
||||||
|
extenson
|
||||||
|
deloyp
|
||||||
|
'''
|
||||||
|
stdout = '''
|
||||||
|
Available commands:
|
||||||
|
|
||||||
|
update_config
|
||||||
|
prepare_extension
|
||||||
|
Template A string class for supporting $-substitutions.
|
||||||
|
deploy
|
||||||
|
glob Return a list of paths matching a pathname pattern.
|
||||||
|
install_web
|
||||||
|
set_version
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command('fab extenson', stderr=stderr),
|
||||||
|
Command('fab deloyp', stderr=stderr),
|
||||||
|
Command('fab extenson deloyp', stderr=stderr)])
|
||||||
|
def test_match(command):
|
||||||
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command('gulp extenson', stderr=stderr),
|
||||||
|
Command('fab deloyp')])
|
||||||
|
def test_not_match(command):
|
||||||
|
assert not match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, result', [
|
||||||
|
('fab extenson', 'fab prepare_extension'),
|
||||||
|
('fab extenson:version=2016',
|
||||||
|
'fab prepare_extension:version=2016'),
|
||||||
|
('fab extenson:version=2016 install_web set_version:val=0.5.0',
|
||||||
|
'fab prepare_extension:version=2016 install_web set_version:val=0.5.0'),
|
||||||
|
('fab extenson:version=2016 deloyp:beta=true -H the.fuck',
|
||||||
|
'fab prepare_extension:version=2016 deploy:beta=true -H the.fuck'),
|
||||||
|
])
|
||||||
|
def test_get_new_command(script, result):
|
||||||
|
command = Command(script, stdout,stderr)
|
||||||
|
assert get_new_command(command) == result
|
||||||
@@ -3,37 +3,38 @@ from thefuck.rules.git_add import match, get_new_command
|
|||||||
from tests.utils import Command
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def path_exists(mocker):
|
||||||
|
return mocker.patch('thefuck.rules.git_add.Path.exists',
|
||||||
|
return_value=True)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def did_not_match(target, did_you_forget=True):
|
def stderr(target):
|
||||||
error = ("error: pathspec '{}' did not match any "
|
return ("error: pathspec '{}' did not match any "
|
||||||
"file(s) known to git.".format(target))
|
'file(s) known to git.'.format(target))
|
||||||
if did_you_forget:
|
|
||||||
error = ("{}\nDid you forget to 'git add'?'".format(error))
|
|
||||||
return error
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('command', [
|
@pytest.mark.parametrize('script, target', [
|
||||||
Command(script='git submodule update unknown',
|
('git submodule update unknown', 'unknown'),
|
||||||
stderr=did_not_match('unknown')),
|
('git commit unknown', 'unknown')])
|
||||||
Command(script='git commit unknown',
|
def test_match(stderr, script, target):
|
||||||
stderr=did_not_match('unknown'))]) # Older versions of Git
|
assert match(Command(script=script, stderr=stderr))
|
||||||
def test_match(command):
|
|
||||||
assert match(command)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('command', [
|
@pytest.mark.parametrize('script, target, exists', [
|
||||||
Command(script='git submodule update known', stderr=('')),
|
('git submodule update known', '', True),
|
||||||
Command(script='git commit known', stderr=('')),
|
('git commit known', '', True),
|
||||||
Command(script='git commit unknown', # Newer versions of Git
|
('git submodule update known', stderr, False)])
|
||||||
stderr=did_not_match('unknown', False))])
|
def test_not_match(path_exists, stderr, script, target, exists):
|
||||||
def test_not_match(command):
|
path_exists.return_value = exists
|
||||||
assert not match(command)
|
assert not match(Command(script=script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('command, new_command', [
|
@pytest.mark.parametrize('script, target, new_command', [
|
||||||
(Command('git submodule update unknown', stderr=did_not_match('unknown')),
|
('git submodule update unknown', 'unknown',
|
||||||
'git add -- unknown && git submodule update unknown'),
|
'git add -- unknown && git submodule update unknown'),
|
||||||
(Command('git commit unknown', stderr=did_not_match('unknown')), # Old Git
|
('git commit unknown', 'unknown',
|
||||||
'git add -- unknown && git commit unknown')])
|
'git add -- unknown && git commit unknown')])
|
||||||
def test_get_new_command(command, new_command):
|
def test_get_new_command(stderr, script, target, new_command):
|
||||||
assert get_new_command(command) == new_command
|
assert get_new_command(Command(script=script, stderr=stderr)) == new_command
|
||||||
|
|||||||
30
tests/rules/test_git_bisect_usage.py
Normal file
30
tests/rules/test_git_bisect_usage.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import pytest
|
||||||
|
from tests.utils import Command
|
||||||
|
from thefuck.rules.git_bisect_usage import match, get_new_command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def stderr():
|
||||||
|
return ("usage: git bisect [help|start|bad|good|new|old"
|
||||||
|
"|terms|skip|next|reset|visualize|replay|log|run]")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', [
|
||||||
|
'git bisect strt', 'git bisect rset', 'git bisect goood'])
|
||||||
|
def test_match(stderr, script):
|
||||||
|
assert match(Command(script=script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', [
|
||||||
|
'git bisect', 'git bisect start', 'git bisect good'])
|
||||||
|
def test_not_match(script):
|
||||||
|
assert not match(Command(script=script, stderr=''))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, new_cmd, ', [
|
||||||
|
('git bisect goood', ['good', 'old', 'log']),
|
||||||
|
('git bisect strt', ['start', 'terms', 'reset']),
|
||||||
|
('git bisect rset', ['reset', 'next', 'start'])])
|
||||||
|
def test_get_new_command(stderr, script, new_cmd):
|
||||||
|
new_cmd = ['git bisect %s' % cmd for cmd in new_cmd]
|
||||||
|
assert get_new_command(Command(script=script, stderr=stderr)) == new_cmd
|
||||||
34
tests/rules/test_git_branch_exists.py
Normal file
34
tests/rules/test_git_branch_exists.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.git_branch_exists import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def stderr(branch_name):
|
||||||
|
return "fatal: A branch named '{}' already exists.".format(branch_name)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def new_command(branch_name):
|
||||||
|
return [cmd.format(branch_name) for cmd in [
|
||||||
|
'git branch -d {0} && git branch {0}',
|
||||||
|
'git branch -d {0} && git checkout -b {0}',
|
||||||
|
'git branch -D {0} && git branch {0}',
|
||||||
|
'git branch -D {0} && git checkout -b {0}', 'git checkout {0}']]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, branch_name', [
|
||||||
|
('git branch foo', 'foo'), ('git checkout bar', 'bar')])
|
||||||
|
def test_match(stderr, script, branch_name):
|
||||||
|
assert match(Command(script=script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', ['git branch foo', 'git checkout bar'])
|
||||||
|
def test_not_match(script):
|
||||||
|
assert not match(Command(script=script, stderr=''))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, branch_name, ', [
|
||||||
|
('git branch foo', 'foo'), ('git checkout bar', 'bar')])
|
||||||
|
def test_get_new_command(stderr, new_command, script, branch_name):
|
||||||
|
assert get_new_command(Command(script=script, stderr=stderr)) == new_command
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
from thefuck import shells
|
|
||||||
from thefuck.rules.git_branch_list import match, get_new_command
|
from thefuck.rules.git_branch_list import match, get_new_command
|
||||||
|
from thefuck.shells import shell
|
||||||
from tests.utils import Command
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
@@ -16,4 +16,4 @@ def test_not_match():
|
|||||||
|
|
||||||
def test_get_new_command():
|
def test_get_new_command():
|
||||||
assert (get_new_command(Command('git branch list')) ==
|
assert (get_new_command(Command('git branch list')) ==
|
||||||
shells.and_('git branch --delete list', 'git branch'))
|
shell.and_('git branch --delete list', 'git branch'))
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from thefuck.rules.git_checkout import match, get_new_command
|
from io import BytesIO
|
||||||
|
from thefuck.rules.git_checkout import match, get_branches, get_new_command
|
||||||
from tests.utils import Command
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
@@ -13,8 +14,10 @@ def did_not_match(target, did_you_forget=False):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def get_branches(mocker):
|
def git_branch(mocker, branches):
|
||||||
return mocker.patch('thefuck.rules.git_checkout.get_branches')
|
mock = mocker.patch('subprocess.Popen')
|
||||||
|
mock.return_value.stdout = BytesIO(branches)
|
||||||
|
return mock
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('command', [
|
@pytest.mark.parametrize('command', [
|
||||||
@@ -33,21 +36,34 @@ def test_not_match(command):
|
|||||||
assert not match(command)
|
assert not match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('branches, branch_list', [
|
||||||
|
(b'', []),
|
||||||
|
(b'* master', ['master']),
|
||||||
|
(b' remotes/origin/master', ['master']),
|
||||||
|
(b' just-another-branch', ['just-another-branch']),
|
||||||
|
(b'* master\n just-another-branch', ['master', 'just-another-branch']),
|
||||||
|
(b'* master\n remotes/origin/master\n just-another-branch',
|
||||||
|
['master', 'master', 'just-another-branch'])])
|
||||||
|
def test_get_branches(branches, branch_list, git_branch):
|
||||||
|
git_branch(branches)
|
||||||
|
assert list(get_branches()) == branch_list
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('branches, command, new_command', [
|
@pytest.mark.parametrize('branches, command, new_command', [
|
||||||
([],
|
(b'',
|
||||||
Command(script='git checkout unknown', stderr=did_not_match('unknown')),
|
Command(script='git checkout unknown', stderr=did_not_match('unknown')),
|
||||||
'git branch unknown && git checkout unknown'),
|
'git branch unknown && git checkout unknown'),
|
||||||
([],
|
(b'',
|
||||||
Command('git commit unknown', stderr=did_not_match('unknown')),
|
Command('git commit unknown', stderr=did_not_match('unknown')),
|
||||||
'git branch unknown && git commit unknown'),
|
'git branch unknown && git commit unknown'),
|
||||||
(['test-random-branch-123'],
|
(b' test-random-branch-123',
|
||||||
Command(script='git checkout tst-rdm-brnch-123',
|
Command(script='git checkout tst-rdm-brnch-123',
|
||||||
stderr=did_not_match('tst-rdm-brnch-123')),
|
stderr=did_not_match('tst-rdm-brnch-123')),
|
||||||
'git checkout test-random-branch-123'),
|
'git checkout test-random-branch-123'),
|
||||||
(['test-random-branch-123'],
|
(b' test-random-branch-123',
|
||||||
Command(script='git commit tst-rdm-brnch-123',
|
Command(script='git commit tst-rdm-brnch-123',
|
||||||
stderr=did_not_match('tst-rdm-brnch-123')),
|
stderr=did_not_match('tst-rdm-brnch-123')),
|
||||||
'git commit test-random-branch-123')])
|
'git commit test-random-branch-123')])
|
||||||
def test_get_new_command(branches, command, new_command, get_branches):
|
def test_get_new_command(branches, command, new_command, git_branch):
|
||||||
get_branches.return_value = branches
|
git_branch(branches)
|
||||||
assert get_new_command(command) == new_command
|
assert get_new_command(command) == new_command
|
||||||
|
|||||||
23
tests/rules/test_git_diff_no_index.py
Normal file
23
tests/rules/test_git_diff_no_index.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.git_diff_no_index import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command(script='git diff foo bar')])
|
||||||
|
def test_match(command):
|
||||||
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command(script='git diff --no-index foo bar'),
|
||||||
|
Command(script='git diff foo'),
|
||||||
|
Command(script='git diff foo bar baz')])
|
||||||
|
def test_not_match(command):
|
||||||
|
assert not match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command, new_command', [
|
||||||
|
(Command('git diff foo bar'), 'git diff --no-index foo bar')])
|
||||||
|
def test_get_new_command(command, new_command):
|
||||||
|
assert get_new_command(command) == new_command
|
||||||
31
tests/rules/test_git_flag_after_filename.py
Normal file
31
tests/rules/test_git_flag_after_filename.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.git_flag_after_filename import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
command1 = Command('git log README.md -p',
|
||||||
|
stderr="fatal: bad flag '-p' used after filename")
|
||||||
|
command2 = Command('git log README.md -p CONTRIBUTING.md',
|
||||||
|
stderr="fatal: bad flag '-p' used after filename")
|
||||||
|
command3 = Command('git log -p README.md --name-only',
|
||||||
|
stderr="fatal: bad flag '--name-only' used after filename")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
command1, command2, command3])
|
||||||
|
def test_match(command):
|
||||||
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command('git log README.md'),
|
||||||
|
Command('git log -p README.md')])
|
||||||
|
def test_not_match(command):
|
||||||
|
assert not match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command, result', [
|
||||||
|
(command1, "git log -p README.md"),
|
||||||
|
(command2, "git log -p README.md CONTRIBUTING.md"),
|
||||||
|
(command3, "git log -p --name-only README.md")])
|
||||||
|
def test_get_new_command(command, result):
|
||||||
|
assert get_new_command(command) == result
|
||||||
24
tests/rules/test_git_help_aliased.py
Normal file
24
tests/rules/test_git_help_aliased.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.git_help_aliased import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, stdout', [
|
||||||
|
('git help st', "`git st' is aliased to `status'"),
|
||||||
|
('git help ds', "`git ds' is aliased to `diff --staged'")])
|
||||||
|
def test_match(script, stdout):
|
||||||
|
assert match(Command(script=script, stdout=stdout))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, stdout', [
|
||||||
|
('git help status', "GIT-STATUS(1)...Git Manual...GIT-STATUS(1)"),
|
||||||
|
('git help diff', "GIT-DIFF(1)...Git Manual...GIT-DIFF(1)")])
|
||||||
|
def test_not_match(script, stdout):
|
||||||
|
assert not match(Command(script=script, stdout=stdout))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, stdout, new_command', [
|
||||||
|
('git help st', "`git st' is aliased to `status'", 'git help status'),
|
||||||
|
('git help ds', "`git ds' is aliased to `diff --staged'", 'git help diff')])
|
||||||
|
def test_get_new_command(script, stdout, new_command):
|
||||||
|
assert get_new_command(Command(script=script, stdout=stdout)) == new_command
|
||||||
19
tests/rules/test_git_pull_uncommitted_changes.py
Normal file
19
tests/rules/test_git_pull_uncommitted_changes.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.git_pull_uncommitted_changes import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def stderr():
|
||||||
|
return '''error: Cannot pull with rebase: You have unstaged changes.'''
|
||||||
|
|
||||||
|
|
||||||
|
def test_match(stderr):
|
||||||
|
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)) \
|
||||||
|
== "git stash && git pull && git stash pop"
|
||||||
19
tests/rules/test_git_pull_unstaged_changes.py
Normal file
19
tests/rules/test_git_pull_unstaged_changes.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.git_pull_uncommitted_changes import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def stderr():
|
||||||
|
return '''error: Cannot pull with rebase: Your index contains uncommitted changes.'''
|
||||||
|
|
||||||
|
|
||||||
|
def test_match(stderr):
|
||||||
|
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)) \
|
||||||
|
== "git stash && git pull && git stash pop"
|
||||||
@@ -14,6 +14,7 @@ To push the current branch and set the remote as upstream, use
|
|||||||
|
|
||||||
|
|
||||||
def test_match(stderr):
|
def test_match(stderr):
|
||||||
|
assert match(Command('git push', stderr=stderr))
|
||||||
assert match(Command('git push master', stderr=stderr))
|
assert match(Command('git push master', stderr=stderr))
|
||||||
assert not match(Command('git push master'))
|
assert not match(Command('git push master'))
|
||||||
assert not match(Command('ls', stderr=stderr))
|
assert not match(Command('ls', stderr=stderr))
|
||||||
@@ -22,3 +23,11 @@ def test_match(stderr):
|
|||||||
def test_get_new_command(stderr):
|
def test_get_new_command(stderr):
|
||||||
assert get_new_command(Command('git push', stderr=stderr))\
|
assert get_new_command(Command('git push', stderr=stderr))\
|
||||||
== "git push --set-upstream origin master"
|
== "git push --set-upstream origin master"
|
||||||
|
assert get_new_command(Command('git push -u', stderr=stderr))\
|
||||||
|
== "git push --set-upstream origin master"
|
||||||
|
assert get_new_command(Command('git push -u origin', stderr=stderr))\
|
||||||
|
== "git push --set-upstream origin master"
|
||||||
|
assert get_new_command(Command('git push --set-upstream origin', stderr=stderr))\
|
||||||
|
== "git push --set-upstream origin master"
|
||||||
|
assert get_new_command(Command('git push --quiet', stderr=stderr))\
|
||||||
|
== "git push --set-upstream origin master --quiet"
|
||||||
|
|||||||
@@ -13,6 +13,17 @@ To /tmp/foo
|
|||||||
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
|
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
git_err2 = '''
|
||||||
|
To /tmp/foo
|
||||||
|
! [rejected] master -> master (non-fast-forward)
|
||||||
|
error: failed to push some refs to '/tmp/bar'
|
||||||
|
hint: Updates were rejected because the remote contains work that you do
|
||||||
|
hint: not have locally. This is usually caused by another repository pushing
|
||||||
|
hint: to the same ref. You may want to first integrate the remote changes
|
||||||
|
hint: (e.g., 'git pull ...') before pushing again.
|
||||||
|
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
|
||||||
|
'''
|
||||||
|
|
||||||
git_uptodate = 'Everything up-to-date'
|
git_uptodate = 'Everything up-to-date'
|
||||||
git_ok = '''
|
git_ok = '''
|
||||||
Counting objects: 3, done.
|
Counting objects: 3, done.
|
||||||
@@ -33,6 +44,14 @@ def test_match(command):
|
|||||||
assert match(command)
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command(script='git push', stderr=git_err2),
|
||||||
|
Command(script='git push nvbn', stderr=git_err2),
|
||||||
|
Command(script='git push nvbn master', stderr=git_err2)])
|
||||||
|
def test_match(command):
|
||||||
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('command', [
|
@pytest.mark.parametrize('command', [
|
||||||
Command(script='git push', stderr=git_ok),
|
Command(script='git push', stderr=git_ok),
|
||||||
Command(script='git push', stderr=git_uptodate),
|
Command(script='git push', stderr=git_uptodate),
|
||||||
@@ -52,3 +71,13 @@ def test_not_match(command):
|
|||||||
'git pull nvbn master && git push nvbn master')])
|
'git pull nvbn master && git push nvbn master')])
|
||||||
def test_get_new_command(command, output):
|
def test_get_new_command(command, output):
|
||||||
assert get_new_command(command) == output
|
assert get_new_command(command) == output
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command, output', [
|
||||||
|
(Command(script='git push', stderr=git_err2), 'git pull && git push'),
|
||||||
|
(Command(script='git push nvbn', stderr=git_err2),
|
||||||
|
'git pull nvbn && git push nvbn'),
|
||||||
|
(Command(script='git push nvbn master', stderr=git_err2),
|
||||||
|
'git pull nvbn master && git push nvbn master')])
|
||||||
|
def test_get_new_command(command, output):
|
||||||
|
assert get_new_command(command) == output
|
||||||
|
|||||||
40
tests/rules/test_git_rebase_merge_dir.py
Normal file
40
tests/rules/test_git_rebase_merge_dir.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.git_rebase_merge_dir import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def stderr():
|
||||||
|
return ('\n\nIt seems that there is already a rebase-merge directory, and\n'
|
||||||
|
'I wonder if you are in the middle of another rebase. If that is the\n'
|
||||||
|
'case, please try\n'
|
||||||
|
'\tgit rebase (--continue | --abort | --skip)\n'
|
||||||
|
'If that is not the case, please\n'
|
||||||
|
'\trm -fr "/foo/bar/baz/egg/.git/rebase-merge"\n'
|
||||||
|
'and run me again. I am stopping in case you still have something\n'
|
||||||
|
'valuable there.\n')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', [
|
||||||
|
('git rebase master'), ('git rebase -skip'), ('git rebase')])
|
||||||
|
def test_match(stderr, script):
|
||||||
|
assert match(Command(script=script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', ['git rebase master', 'git rebase -abort'])
|
||||||
|
def test_not_match(script):
|
||||||
|
assert not match(Command(script=script))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, result', [
|
||||||
|
('git rebase master', [
|
||||||
|
'git rebase --abort', 'git rebase --skip', 'git rebase --continue',
|
||||||
|
'rm -fr "/foo/bar/baz/egg/.git/rebase-merge"']),
|
||||||
|
('git rebase -skip', [
|
||||||
|
'git rebase --skip', 'git rebase --abort', 'git rebase --continue',
|
||||||
|
'rm -fr "/foo/bar/baz/egg/.git/rebase-merge"']),
|
||||||
|
('git rebase', [
|
||||||
|
'git rebase --skip', 'git rebase --abort', 'git rebase --continue',
|
||||||
|
'rm -fr "/foo/bar/baz/egg/.git/rebase-merge"'])])
|
||||||
|
def test_get_new_command(stderr, script, result):
|
||||||
|
assert get_new_command(Command(script=script, stderr=stderr)) == result
|
||||||
28
tests/rules/test_git_rebase_no_changes.py
Normal file
28
tests/rules/test_git_rebase_no_changes.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.git_rebase_no_changes import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def stdout():
|
||||||
|
return '''Applying: Test commit
|
||||||
|
No changes - did you forget to use 'git add'?
|
||||||
|
If there is nothing left to stage, chances are that something else
|
||||||
|
already introduced the same changes; you might want to skip this patch.
|
||||||
|
|
||||||
|
When you have resolved this problem, run "git rebase --continue".
|
||||||
|
If you prefer to skip this patch, run "git rebase --skip" instead.
|
||||||
|
To check out the original branch and stop rebasing, run "git rebase --abort".
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def test_match(stdout):
|
||||||
|
assert match(Command('git rebase --continue', stdout=stdout))
|
||||||
|
assert not match(Command('git rebase --continue'))
|
||||||
|
assert not match(Command('git rebase --skip'))
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_new_command(stdout):
|
||||||
|
assert (get_new_command(Command('git rebase --continue', stdout=stdout)) ==
|
||||||
|
'git rebase --skip')
|
||||||
26
tests/rules/test_git_remote_seturl_add.py
Normal file
26
tests/rules/test_git_remote_seturl_add.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.git_remote_seturl_add import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command(script='git remote set-url origin url', stderr="fatal: No such remote")])
|
||||||
|
def test_match(command):
|
||||||
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command('git remote set-url origin url', stderr=""),
|
||||||
|
Command('git remote add origin url'),
|
||||||
|
Command('git remote remove origin'),
|
||||||
|
Command('git remote prune origin'),
|
||||||
|
Command('git remote set-branches origin branch')
|
||||||
|
])
|
||||||
|
def test_not_match(command):
|
||||||
|
assert not match(command)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command, new_command', [
|
||||||
|
(Command('git remote set-url origin git@github.com:nvbn/thefuck.git'),
|
||||||
|
'git remote add origin git@github.com:nvbn/thefuck.git')])
|
||||||
|
def test_get_new_command(command, new_command):
|
||||||
|
assert get_new_command(command) == new_command
|
||||||
28
tests/rules/test_git_rm_local_modifications.py
Normal file
28
tests/rules/test_git_rm_local_modifications.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.git_rm_local_modifications import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def stderr(target):
|
||||||
|
return ('error: the following file has local modifications:\n {}\n(use '
|
||||||
|
'--cached to keep the file, or -f to force removal)').format(target)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, target', [
|
||||||
|
('git rm foo', 'foo'),
|
||||||
|
('git rm foo bar', 'bar')])
|
||||||
|
def test_match(stderr, script, target):
|
||||||
|
assert match(Command(script=script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', ['git rm foo', 'git rm foo bar', 'git rm'])
|
||||||
|
def test_not_match(script):
|
||||||
|
assert not match(Command(script=script, stderr=''))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, target, new_command', [
|
||||||
|
('git rm foo', 'foo', ['git rm --cached foo', 'git rm -f foo']),
|
||||||
|
('git rm foo bar', 'bar', ['git rm --cached foo bar', 'git rm -f foo bar'])])
|
||||||
|
def test_get_new_command(stderr, script, target, new_command):
|
||||||
|
assert get_new_command(Command(script=script, stderr=stderr)) == new_command
|
||||||
27
tests/rules/test_git_rm_recursive.py
Normal file
27
tests/rules/test_git_rm_recursive.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.git_rm_recursive import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def stderr(target):
|
||||||
|
return "fatal: not removing '{}' recursively without -r".format(target)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, target', [
|
||||||
|
('git rm foo', 'foo'),
|
||||||
|
('git rm foo bar', 'foo bar')])
|
||||||
|
def test_match(stderr, script, target):
|
||||||
|
assert match(Command(script=script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', ['git rm foo', 'git rm foo bar'])
|
||||||
|
def test_not_match(script):
|
||||||
|
assert not match(Command(script=script, stderr=''))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, target, new_command', [
|
||||||
|
('git rm foo', 'foo', 'git rm -r foo'),
|
||||||
|
('git rm foo bar', 'foo bar', 'git rm -r foo bar')])
|
||||||
|
def test_get_new_command(stderr, script, target, new_command):
|
||||||
|
assert get_new_command(Command(script=script, stderr=stderr)) == new_command
|
||||||
18
tests/rules/test_git_stash_pop.py
Normal file
18
tests/rules/test_git_stash_pop.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.git_stash_pop import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def stderr():
|
||||||
|
return '''error: Your local changes to the following files would be overwritten by merge:'''
|
||||||
|
|
||||||
|
|
||||||
|
def test_match(stderr):
|
||||||
|
assert match(Command('git stash pop', stderr=stderr))
|
||||||
|
assert not match(Command('git stash'))
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_new_command(stderr):
|
||||||
|
assert get_new_command(Command('git stash pop', stderr=stderr)) \
|
||||||
|
== "git add . && git stash pop && git reset ."
|
||||||
158
tests/rules/test_gradle_not_task.py
Normal file
158
tests/rules/test_gradle_not_task.py
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
import pytest
|
||||||
|
from io import BytesIO
|
||||||
|
from thefuck.rules.gradle_no_task import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
gradle_tasks = b'''
|
||||||
|
:tasks
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
All tasks runnable from root project
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Android tasks
|
||||||
|
-------------
|
||||||
|
androidDependencies - Displays the Android dependencies of the project.
|
||||||
|
signingReport - Displays the signing info for each variant.
|
||||||
|
sourceSets - Prints out all the source sets defined in this project.
|
||||||
|
|
||||||
|
Build tasks
|
||||||
|
-----------
|
||||||
|
assemble - Assembles all variants of all applications and secondary packages.
|
||||||
|
assembleAndroidTest - Assembles all the Test applications.
|
||||||
|
assembleDebug - Assembles all Debug builds.
|
||||||
|
assembleRelease - Assembles all Release builds.
|
||||||
|
build - Assembles and tests this project.
|
||||||
|
buildDependents - Assembles and tests this project and all projects that depend on it.
|
||||||
|
buildNeeded - Assembles and tests this project and all projects it depends on.
|
||||||
|
compileDebugAndroidTestSources
|
||||||
|
compileDebugSources
|
||||||
|
compileDebugUnitTestSources
|
||||||
|
compileReleaseSources
|
||||||
|
compileReleaseUnitTestSources
|
||||||
|
extractDebugAnnotations - Extracts Android annotations for the debug variant into the archive file
|
||||||
|
extractReleaseAnnotations - Extracts Android annotations for the release variant into the archive file
|
||||||
|
mockableAndroidJar - Creates a version of android.jar that's suitable for unit tests.
|
||||||
|
|
||||||
|
Build Setup tasks
|
||||||
|
-----------------
|
||||||
|
init - Initializes a new Gradle build. [incubating]
|
||||||
|
wrapper - Generates Gradle wrapper files. [incubating]
|
||||||
|
|
||||||
|
Help tasks
|
||||||
|
----------
|
||||||
|
components - Displays the components produced by root project 'org.rerenderer_example.snake'. [incubating]
|
||||||
|
dependencies - Displays all dependencies declared in root project 'org.rerenderer_example.snake'.
|
||||||
|
dependencyInsight - Displays the insight into a specific dependency in root project 'org.rerenderer_example.snake'.
|
||||||
|
help - Displays a help message.
|
||||||
|
model - Displays the configuration model of root project 'org.rerenderer_example.snake'. [incubating]
|
||||||
|
projects - Displays the sub-projects of root project 'org.rerenderer_example.snake'.
|
||||||
|
properties - Displays the properties of root project 'org.rerenderer_example.snake'.
|
||||||
|
tasks - Displays the tasks runnable from root project 'org.rerenderer_example.snake' (some of the displayed tasks may belong to subprojects).
|
||||||
|
|
||||||
|
Install tasks
|
||||||
|
-------------
|
||||||
|
installDebug - Installs the Debug build.
|
||||||
|
installDebugAndroidTest - Installs the android (on device) tests for the Debug build.
|
||||||
|
installRelease - Installs the Release build.
|
||||||
|
uninstallAll - Uninstall all applications.
|
||||||
|
uninstallDebug - Uninstalls the Debug build.
|
||||||
|
uninstallDebugAndroidTest - Uninstalls the android (on device) tests for the Debug build.
|
||||||
|
uninstallRelease - Uninstalls the Release build.
|
||||||
|
|
||||||
|
React tasks
|
||||||
|
-----------
|
||||||
|
bundleDebugJsAndAssets - bundle JS and assets for Debug.
|
||||||
|
bundleReleaseJsAndAssets - bundle JS and assets for Release.
|
||||||
|
|
||||||
|
Verification tasks
|
||||||
|
------------------
|
||||||
|
check - Runs all checks.
|
||||||
|
clean - Deletes the build directory.
|
||||||
|
connectedAndroidTest - Installs and runs instrumentation tests for all flavors on connected devices.
|
||||||
|
connectedCheck - Runs all device checks on currently connected devices.
|
||||||
|
connectedDebugAndroidTest - Installs and runs the tests for debug on connected devices.
|
||||||
|
deviceAndroidTest - Installs and runs instrumentation tests using all Device Providers.
|
||||||
|
deviceCheck - Runs all device checks using Device Providers and Test Servers.
|
||||||
|
lint - Runs lint on all variants.
|
||||||
|
lintDebug - Runs lint on the Debug build.
|
||||||
|
lintRelease - Runs lint on the Release build.
|
||||||
|
test - Run unit tests for all variants.
|
||||||
|
testDebugUnitTest - Run unit tests for the debug build.
|
||||||
|
testReleaseUnitTest - Run unit tests for the release build.
|
||||||
|
|
||||||
|
Other tasks
|
||||||
|
-----------
|
||||||
|
assembleDefault
|
||||||
|
copyDownloadableDepsToLibs
|
||||||
|
jarDebugClasses
|
||||||
|
jarReleaseClasses
|
||||||
|
|
||||||
|
To see all tasks and more detail, run gradlew tasks --all
|
||||||
|
|
||||||
|
To see more detail about a task, run gradlew help --task <task>
|
||||||
|
|
||||||
|
BUILD SUCCESSFUL
|
||||||
|
|
||||||
|
Total time: 1.936 secs
|
||||||
|
'''
|
||||||
|
|
||||||
|
stderr_not_found = '''
|
||||||
|
|
||||||
|
FAILURE: Build failed with an exception.
|
||||||
|
|
||||||
|
* What went wrong:
|
||||||
|
Task '{}' not found in root project 'org.rerenderer_example.snake'.
|
||||||
|
|
||||||
|
* Try:
|
||||||
|
Run gradlew tasks to get a list of available tasks. Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
|
||||||
|
'''.format
|
||||||
|
|
||||||
|
stderr_ambiguous = '''
|
||||||
|
|
||||||
|
FAILURE: Build failed with an exception.
|
||||||
|
|
||||||
|
* What went wrong:
|
||||||
|
Task '{}' is ambiguous in root project 'org.rerenderer_example.snake'. Candidates are: 'assembleRelease', 'assembleReleaseUnitTest'.
|
||||||
|
|
||||||
|
* Try:
|
||||||
|
Run gradlew tasks to get a list of available tasks. Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
|
||||||
|
'''.format
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def tasks(mocker):
|
||||||
|
patch = mocker.patch('thefuck.rules.gradle_no_task.Popen')
|
||||||
|
patch.return_value.stdout = BytesIO(gradle_tasks)
|
||||||
|
return patch
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command('./gradlew assembler', stderr=stderr_ambiguous('assembler')),
|
||||||
|
Command('./gradlew instar', stderr=stderr_not_found('instar')),
|
||||||
|
Command('gradle assembler', stderr=stderr_ambiguous('assembler')),
|
||||||
|
Command('gradle instar', stderr=stderr_not_found('instar'))])
|
||||||
|
def test_match(command):
|
||||||
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command('./gradlew assemble'),
|
||||||
|
Command('gradle assemble'),
|
||||||
|
Command('npm assembler', stderr=stderr_ambiguous('assembler')),
|
||||||
|
Command('npm instar', stderr=stderr_not_found('instar'))])
|
||||||
|
def test_not_match(command):
|
||||||
|
assert not match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command, result', [
|
||||||
|
(Command('./gradlew assembler', stderr=stderr_ambiguous('assembler')),
|
||||||
|
'./gradlew assemble'),
|
||||||
|
(Command('./gradlew instardebug', stderr=stderr_not_found('instardebug')),
|
||||||
|
'./gradlew installDebug'),
|
||||||
|
(Command('gradle assembler', stderr=stderr_ambiguous('assembler')),
|
||||||
|
'gradle assemble'),
|
||||||
|
(Command('gradle instardebug', stderr=stderr_not_found('instardebug')),
|
||||||
|
'gradle installDebug')])
|
||||||
|
def test_get_new_command(command, result):
|
||||||
|
assert get_new_command(command)[0] == result
|
||||||
38
tests/rules/test_gradle_wrapper.py
Normal file
38
tests/rules/test_gradle_wrapper.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.gradle_wrapper import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def exists(mocker):
|
||||||
|
return mocker.patch('thefuck.rules.gradle_wrapper.os.path.isfile',
|
||||||
|
return_value=True)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command('gradle tasks', stderr='gradle: not found'),
|
||||||
|
Command('gradle build', stderr='gradle: not found')])
|
||||||
|
def test_match(mocker, command):
|
||||||
|
mocker.patch('thefuck.rules.gradle_wrapper.which', return_value=None)
|
||||||
|
|
||||||
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command, gradlew, which', [
|
||||||
|
(Command('gradle tasks', stderr='gradle: not found'), False, None),
|
||||||
|
(Command('gradle tasks', stderr='command not found'), True, '/usr/bin/gradle'),
|
||||||
|
(Command('npm tasks', stderr='npm: not found'), True, None)])
|
||||||
|
def test_not_match(mocker, exists, command, gradlew, which):
|
||||||
|
mocker.patch('thefuck.rules.gradle_wrapper.which', return_value=which)
|
||||||
|
exists.return_value = gradlew
|
||||||
|
|
||||||
|
assert not match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, result', [
|
||||||
|
('gradle assemble', './gradlew assemble'),
|
||||||
|
('gradle --help', './gradlew --help'),
|
||||||
|
('gradle build -c', './gradlew build -c')])
|
||||||
|
def test_get_new_command(script, result):
|
||||||
|
command = Command(script)
|
||||||
|
assert get_new_command(command) == result
|
||||||
40
tests/rules/test_grep_arguments_order.py
Normal file
40
tests/rules/test_grep_arguments_order.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.grep_arguments_order import get_new_command, match
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
stderr = 'grep: {}: No such file or directory'.format
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def os_path(monkeypatch):
|
||||||
|
monkeypatch.setattr('os.path.isfile', lambda x: not x.startswith('-'))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, file', [
|
||||||
|
('grep test.py test', 'test'),
|
||||||
|
('grep -lir . test', 'test'),
|
||||||
|
('egrep test.py test', 'test'),
|
||||||
|
('egrep -lir . test', 'test')])
|
||||||
|
def test_match(script, file):
|
||||||
|
assert match(Command(script, stderr=stderr(file)))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, stderr', [
|
||||||
|
('cat test.py', stderr('test')),
|
||||||
|
('grep test test.py', ''),
|
||||||
|
('grep -lir test .', ''),
|
||||||
|
('egrep test test.py', ''),
|
||||||
|
('egrep -lir test .', '')])
|
||||||
|
def test_not_match(script, stderr):
|
||||||
|
assert not match(Command(script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, stderr, result', [
|
||||||
|
('grep test.py test', stderr('test'), 'grep test test.py'),
|
||||||
|
('grep -lir . test', stderr('test'), 'grep -lir test .'),
|
||||||
|
('grep . test -lir', stderr('test'), 'grep test -lir .'),
|
||||||
|
('egrep test.py test', stderr('test'), 'egrep test test.py'),
|
||||||
|
('egrep -lir . test', stderr('test'), 'egrep -lir test .'),
|
||||||
|
('egrep . test -lir', stderr('test'), 'egrep test -lir .')])
|
||||||
|
def test_get_new_command(script, stderr, result):
|
||||||
|
assert get_new_command(Command(script, stderr=stderr)) == result
|
||||||
129
tests/rules/test_grunt_task_not_found.py
Normal file
129
tests/rules/test_grunt_task_not_found.py
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
from io import BytesIO
|
||||||
|
import pytest
|
||||||
|
from tests.utils import Command
|
||||||
|
from thefuck.rules.grunt_task_not_found import match, get_new_command
|
||||||
|
|
||||||
|
stdout = '''
|
||||||
|
Warning: Task "{}" not found. Use --force to continue.
|
||||||
|
|
||||||
|
Aborted due to warnings.
|
||||||
|
|
||||||
|
|
||||||
|
Execution Time (2016-08-13 21:01:40 UTC+3)
|
||||||
|
loading tasks 11ms ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 92%
|
||||||
|
Total 12ms
|
||||||
|
|
||||||
|
'''.format
|
||||||
|
|
||||||
|
grunt_help_stdout = b'''
|
||||||
|
Grunt: The JavaScript Task Runner (v0.4.5)
|
||||||
|
|
||||||
|
Usage
|
||||||
|
grunt [options] [task [task ...]]
|
||||||
|
|
||||||
|
Options
|
||||||
|
--help, -h Display this help text.
|
||||||
|
--base Specify an alternate base path. By default, all file paths are
|
||||||
|
relative to the Gruntfile. (grunt.file.setBase) *
|
||||||
|
--no-color Disable colored output.
|
||||||
|
--gruntfile Specify an alternate Gruntfile. By default, grunt looks in the
|
||||||
|
current or parent directories for the nearest Gruntfile.js or
|
||||||
|
Gruntfile.coffee file.
|
||||||
|
--debug, -d Enable debugging mode for tasks that support it.
|
||||||
|
--stack Print a stack trace when exiting with a warning or fatal error.
|
||||||
|
--force, -f A way to force your way past warnings. Want a suggestion? Don't
|
||||||
|
use this option, fix your code.
|
||||||
|
--tasks Additional directory paths to scan for task and "extra" files.
|
||||||
|
(grunt.loadTasks) *
|
||||||
|
--npm Npm-installed grunt plugins to scan for task and "extra" files.
|
||||||
|
(grunt.loadNpmTasks) *
|
||||||
|
--no-write Disable writing files (dry run).
|
||||||
|
--verbose, -v Verbose mode. A lot more information output.
|
||||||
|
--version, -V Print the grunt version. Combine with --verbose for more info.
|
||||||
|
--completion Output shell auto-completion rules. See the grunt-cli
|
||||||
|
documentation for more information.
|
||||||
|
|
||||||
|
Options marked with * have methods exposed via the grunt API and should instead
|
||||||
|
be specified inside the Gruntfile wherever possible.
|
||||||
|
|
||||||
|
Available tasks
|
||||||
|
autoprefixer Prefix CSS files. *
|
||||||
|
concurrent Run grunt tasks concurrently *
|
||||||
|
clean Clean files and folders. *
|
||||||
|
compass Compile Sass to CSS using Compass *
|
||||||
|
concat Concatenate files. *
|
||||||
|
connect Start a connect web server. *
|
||||||
|
copy Copy files. *
|
||||||
|
cssmin Minify CSS *
|
||||||
|
htmlmin Minify HTML *
|
||||||
|
imagemin Minify PNG, JPEG, GIF and SVG images *
|
||||||
|
jshint Validate files with JSHint. *
|
||||||
|
uglify Minify files with UglifyJS. *
|
||||||
|
watch Run predefined tasks whenever watched files change.
|
||||||
|
filerev File revisioning based on content hashing *
|
||||||
|
cdnify Replace scripts with refs to the Google CDN *
|
||||||
|
karma run karma. *
|
||||||
|
newer Run a task with only those source files that have been modified
|
||||||
|
since the last successful run.
|
||||||
|
any-newer DEPRECATED TASK. Use the "newer" task instead
|
||||||
|
newer-postrun Internal task.
|
||||||
|
newer-clean Remove cached timestamps.
|
||||||
|
ngAnnotate Add, remove and rebuild AngularJS dependency injection
|
||||||
|
annotations *
|
||||||
|
ngconstant Dynamic angular constant generator task. *
|
||||||
|
svgmin Minify SVG *
|
||||||
|
usemin Replaces references to non-minified scripts / stylesheets *
|
||||||
|
useminPrepare Using HTML markup as the primary source of information *
|
||||||
|
wiredep Inject Bower components into your source code. *
|
||||||
|
serve Compile then start a connect web server
|
||||||
|
server DEPRECATED TASK. Use the "serve" task instead
|
||||||
|
test Alias for "clean:server", "ngconstant:test", "wiredep",
|
||||||
|
"concurrent:test", "autoprefixer", "connect:test", "karma"
|
||||||
|
tasks.
|
||||||
|
build Alias for "ngconstant:production", "clean:dist", "wiredep",
|
||||||
|
"useminPrepare", "concurrent:dist", "autoprefixer", "concat",
|
||||||
|
"ngAnnotate", "copy:dist", "cdnify", "cssmin", "uglify",
|
||||||
|
"filerev", "usemin", "htmlmin" tasks.
|
||||||
|
default Alias for "newer:jshint", "test", "build" tasks.
|
||||||
|
|
||||||
|
Tasks run in the order specified. Arguments may be passed to tasks that accept
|
||||||
|
them by using colons, like "lint:files". Tasks marked with * are "multi tasks"
|
||||||
|
and will iterate over all sub-targets if no argument is specified.
|
||||||
|
|
||||||
|
The list of available tasks may change based on tasks directories or grunt
|
||||||
|
plugins specified in the Gruntfile or via command-line options.
|
||||||
|
|
||||||
|
For more information, see http://gruntjs.com/
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def grunt_help(mocker):
|
||||||
|
patch = mocker.patch('thefuck.rules.grunt_task_not_found.Popen')
|
||||||
|
patch.return_value.stdout = BytesIO(grunt_help_stdout)
|
||||||
|
return patch
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command('grunt defualt', stdout('defualt')),
|
||||||
|
Command('grunt buld:css', stdout('buld:css'))])
|
||||||
|
def test_match(command):
|
||||||
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command('npm nuild', stdout('nuild')),
|
||||||
|
Command('grunt rm')])
|
||||||
|
def test_not_match(command):
|
||||||
|
assert not match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command, result', [
|
||||||
|
(Command('grunt defualt', stdout('defualt')), 'grunt default'),
|
||||||
|
(Command('grunt cmpass:all', stdout('cmpass:all')), 'grunt compass:all'),
|
||||||
|
(Command('grunt cmpass:all --color', stdout('cmpass:all')),
|
||||||
|
'grunt compass:all --color')])
|
||||||
|
def test_get_new_command(command, result):
|
||||||
|
assert get_new_command(command) == result
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
from io import BytesIO
|
||||||
from tests.utils import Command
|
from tests.utils import Command
|
||||||
from thefuck.rules.gulp_not_task import match, get_new_command
|
from thefuck.rules.gulp_not_task import match, get_new_command
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ def test_not_march(script, stdout):
|
|||||||
|
|
||||||
|
|
||||||
def test_get_new_command(mocker):
|
def test_get_new_command(mocker):
|
||||||
mocker.patch('thefuck.rules.gulp_not_task.get_gulp_tasks', return_value=[
|
mock = mocker.patch('subprocess.Popen')
|
||||||
'serve', 'build', 'default'])
|
mock.return_value.stdout = BytesIO(b'serve \nbuild \ndefault \n')
|
||||||
command = Command('gulp srve', stdout('srve'))
|
command = Command('gulp srve', stdout('srve'))
|
||||||
assert get_new_command(command) == ['gulp serve', 'gulp default']
|
assert get_new_command(command) == ['gulp serve', 'gulp default']
|
||||||
|
|||||||
@@ -3,38 +3,23 @@ from thefuck.rules.history import match, get_new_command
|
|||||||
from tests.utils import Command
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture(autouse=True)
|
||||||
def history(mocker):
|
def history_without_current(mocker):
|
||||||
return mocker.patch('thefuck.rules.history.get_history',
|
return mocker.patch(
|
||||||
return_value=['le cat', 'fuck', 'ls cat',
|
'thefuck.rules.history.get_valid_history_without_current',
|
||||||
'diff x', 'nocommand x'])
|
return_value=['ls cat', 'diff x'])
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def alias(mocker):
|
|
||||||
return mocker.patch('thefuck.rules.history.thefuck_alias',
|
|
||||||
return_value='fuck')
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def callables(mocker):
|
|
||||||
return mocker.patch('thefuck.rules.history.get_all_executables',
|
|
||||||
return_value=['diff', 'ls'])
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures('history', 'callables', 'no_memoize', 'alias')
|
|
||||||
@pytest.mark.parametrize('script', ['ls cet', 'daff x'])
|
@pytest.mark.parametrize('script', ['ls cet', 'daff x'])
|
||||||
def test_match(script):
|
def test_match(script):
|
||||||
assert match(Command(script=script))
|
assert match(Command(script=script))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures('history', 'callables', 'no_memoize', 'alias')
|
|
||||||
@pytest.mark.parametrize('script', ['apt-get', 'nocommand y'])
|
@pytest.mark.parametrize('script', ['apt-get', 'nocommand y'])
|
||||||
def test_not_match(script):
|
def test_not_match(script):
|
||||||
assert not match(Command(script=script))
|
assert not match(Command(script=script))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures('history', 'callables', 'no_memoize', 'alias')
|
|
||||||
@pytest.mark.parametrize('script, result', [
|
@pytest.mark.parametrize('script, result', [
|
||||||
('ls cet', 'ls cat'),
|
('ls cet', 'ls cat'),
|
||||||
('daff x', 'diff x')])
|
('daff x', 'diff x')])
|
||||||
|
|||||||
53
tests/rules/test_ifconfig_device_not_found.py
Normal file
53
tests/rules/test_ifconfig_device_not_found.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import pytest
|
||||||
|
from six import BytesIO
|
||||||
|
from thefuck.rules.ifconfig_device_not_found import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
stderr = '{}: error fetching interface information: Device not found'
|
||||||
|
|
||||||
|
stdout = b'''
|
||||||
|
wlp2s0 Link encap:Ethernet HWaddr 5c:51:4f:7c:58:5d
|
||||||
|
inet addr:192.168.0.103 Bcast:192.168.0.255 Mask:255.255.255.0
|
||||||
|
inet6 addr: fe80::be23:69b9:96d2:6d39/64 Scope:Link
|
||||||
|
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
|
||||||
|
RX packets:23581604 errors:0 dropped:0 overruns:0 frame:0
|
||||||
|
TX packets:17017655 errors:0 dropped:0 overruns:0 carrier:0
|
||||||
|
collisions:0 txqueuelen:1000
|
||||||
|
RX bytes:16148429061 (16.1 GB) TX bytes:7067533695 (7.0 GB)
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def ifconfig(mocker):
|
||||||
|
mock = mocker.patch(
|
||||||
|
'thefuck.rules.ifconfig_device_not_found.subprocess.Popen')
|
||||||
|
mock.return_value.stdout = BytesIO(stdout)
|
||||||
|
return mock
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, stderr', [
|
||||||
|
('ifconfig wlan0', stderr.format('wlan0')),
|
||||||
|
('ifconfig -s eth0', stderr.format('eth0')),
|
||||||
|
])
|
||||||
|
def test_match(script, stderr):
|
||||||
|
assert match(Command(script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, stderr', [
|
||||||
|
('config wlan0',
|
||||||
|
'wlan0: error fetching interface information: Device not found'),
|
||||||
|
('ifconfig eth0', ''),
|
||||||
|
])
|
||||||
|
def test_not_match(script, stderr):
|
||||||
|
assert not match(Command(script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, result', [
|
||||||
|
('ifconfig wlan0', ['ifconfig wlp2s0']),
|
||||||
|
('ifconfig -s wlan0', ['ifconfig -s wlp2s0']),
|
||||||
|
])
|
||||||
|
def test_get_new_comman(script, result):
|
||||||
|
new_command = get_new_command(
|
||||||
|
Command(script, stderr=stderr.format('wlan0')))
|
||||||
|
assert new_command == result
|
||||||
37
tests/rules/test_ln_no_hard_link.py
Normal file
37
tests/rules/test_ln_no_hard_link.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import pytest
|
||||||
|
from thefuck.rules.ln_no_hard_link import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
error = "hard link not allowed for directory"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, stderr', [
|
||||||
|
("ln barDir barLink", "ln: ‘barDir’: {}"),
|
||||||
|
("sudo ln a b", "ln: ‘a’: {}"),
|
||||||
|
("sudo ln -nbi a b", "ln: ‘a’: {}")])
|
||||||
|
def test_match(script, stderr):
|
||||||
|
command = Command(script, stderr=stderr.format(error))
|
||||||
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, stderr', [
|
||||||
|
('', ''),
|
||||||
|
("ln a b", "... hard link"),
|
||||||
|
("sudo ln a b", "... hard link"),
|
||||||
|
("a b", error)])
|
||||||
|
def test_not_match(script, stderr):
|
||||||
|
command = Command(script, stderr=stderr)
|
||||||
|
assert not match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, result', [
|
||||||
|
("ln barDir barLink", "ln -s barDir barLink"),
|
||||||
|
("sudo ln barDir barLink", "sudo ln -s barDir barLink"),
|
||||||
|
("sudo ln -nbi a b", "sudo ln -s -nbi a b"),
|
||||||
|
("ln -nbi a b && ls", "ln -s -nbi a b && ls"),
|
||||||
|
("ln a ln", "ln -s a ln"),
|
||||||
|
("sudo ln a ln", "sudo ln -s a ln")])
|
||||||
|
def test_get_new_command(script, result):
|
||||||
|
command = Command(script)
|
||||||
|
assert get_new_command(command) == result
|
||||||
41
tests/rules/test_ln_s_order.py
Normal file
41
tests/rules/test_ln_s_order.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.ln_s_order import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def file_exists(mocker):
|
||||||
|
return mocker.patch('os.path.exists', return_value=True)
|
||||||
|
|
||||||
|
|
||||||
|
get_stderr = "ln: failed to create symbolic link '{}': File exists".format
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('file_exists')
|
||||||
|
@pytest.mark.parametrize('script', [
|
||||||
|
'ln -s dest source',
|
||||||
|
'ln dest -s source',
|
||||||
|
'ln dest source -s'])
|
||||||
|
def test_match(script):
|
||||||
|
stderr = get_stderr('source')
|
||||||
|
assert match(Command(script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, stderr, exists', [
|
||||||
|
('ln dest source', get_stderr('source'), True),
|
||||||
|
('ls -s dest source', get_stderr('source'), True),
|
||||||
|
('ln -s dest source', '', True),
|
||||||
|
('ln -s dest source', get_stderr('source'), False)])
|
||||||
|
def test_not_match(file_exists, script, stderr, exists):
|
||||||
|
file_exists.return_value = exists
|
||||||
|
assert not match(Command(script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('file_exists')
|
||||||
|
@pytest.mark.parametrize('script, result', [
|
||||||
|
('ln -s dest source', 'ln -s source dest'),
|
||||||
|
('ln dest -s source', 'ln -s source dest'),
|
||||||
|
('ln dest source -s', 'ln source -s dest')])
|
||||||
|
def test_match(script, result):
|
||||||
|
stderr = get_stderr('source')
|
||||||
|
assert get_new_command(Command(script, stderr=stderr)) == result
|
||||||
12
tests/rules/test_ls_all.py
Normal file
12
tests/rules/test_ls_all.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from thefuck.rules.ls_all import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
def test_match():
|
||||||
|
assert match(Command(script='ls'))
|
||||||
|
assert not match(Command(script='ls', stdout='file.py\n'))
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_new_command():
|
||||||
|
assert get_new_command(Command(script='ls empty_dir')) == 'ls -A empty_dir'
|
||||||
|
assert get_new_command(Command(script='ls')) == 'ls -A'
|
||||||
@@ -23,7 +23,8 @@ def test_not_match(command):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('command, new_command', [
|
@pytest.mark.parametrize('command, new_command', [
|
||||||
(Command('man read'), ['man 3 read', 'man 2 read']),
|
(Command('man read'), ['man 3 read', 'man 2 read', 'read --help']),
|
||||||
|
(Command('man missing', stderr="No manual entry for missing\n"), ['missing --help']),
|
||||||
(Command('man 2 read'), 'man 3 read'),
|
(Command('man 2 read'), 'man 3 read'),
|
||||||
(Command('man 3 read'), 'man 2 read'),
|
(Command('man 3 read'), 'man 2 read'),
|
||||||
(Command('man -s2 read'), 'man -s3 read'),
|
(Command('man -s2 read'), 'man -s3 read'),
|
||||||
|
|||||||
@@ -6,22 +6,42 @@ from tests.utils import Command
|
|||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def get_all_executables(mocker):
|
def get_all_executables(mocker):
|
||||||
mocker.patch('thefuck.rules.no_command.get_all_executables',
|
mocker.patch('thefuck.rules.no_command.get_all_executables',
|
||||||
return_value=['vim', 'apt-get', 'fsck'])
|
return_value=['vim', 'fsck', 'git', 'go'])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def history_without_current(mocker):
|
||||||
|
return mocker.patch(
|
||||||
|
'thefuck.rules.no_command.get_valid_history_without_current',
|
||||||
|
return_value=['git commit'])
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures('no_memoize')
|
@pytest.mark.usefixtures('no_memoize')
|
||||||
def test_match():
|
@pytest.mark.parametrize('script, stderr', [
|
||||||
assert match(Command(stderr='vom: not found', script='vom file.py'))
|
('vom file.py', 'vom: not found'),
|
||||||
assert match(Command(stderr='fucck: not found', script='fucck'))
|
('fucck', 'fucck: not found'),
|
||||||
assert not match(Command(stderr='qweqwe: not found', script='qweqwe'))
|
('got commit', 'got: command not found')])
|
||||||
assert not match(Command(stderr='some text', script='vom file.py'))
|
def test_match(mocker, script, stderr):
|
||||||
|
mocker.patch('thefuck.rules.no_command.which', return_value=None)
|
||||||
|
|
||||||
|
assert match(Command(script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures('no_memoize')
|
@pytest.mark.usefixtures('no_memoize')
|
||||||
def test_get_new_command():
|
@pytest.mark.parametrize('script, stderr, which', [
|
||||||
assert get_new_command(
|
('qweqwe', 'qweqwe: not found', None),
|
||||||
Command(stderr='vom: not found',
|
('vom file.py', 'some text', None),
|
||||||
script='vom file.py')) == ['vim file.py']
|
('vim file.py', 'vim: not found', 'vim')])
|
||||||
assert get_new_command(
|
def test_not_match(mocker, script, stderr, which):
|
||||||
Command(stderr='fucck: not found',
|
mocker.patch('thefuck.rules.no_command.which', return_value=which)
|
||||||
script='fucck')) == ['fsck']
|
|
||||||
|
assert not match(Command(script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('no_memoize')
|
||||||
|
@pytest.mark.parametrize('script, result', [
|
||||||
|
('vom file.py', ['vim file.py']),
|
||||||
|
('fucck', ['fsck']),
|
||||||
|
('got commit', ['git commit', 'go commit'])])
|
||||||
|
def test_get_new_command(script, result):
|
||||||
|
assert get_new_command(Command(script)) == result
|
||||||
|
|||||||
69
tests/rules/test_npm_missing_script.py
Normal file
69
tests/rules/test_npm_missing_script.py
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import pytest
|
||||||
|
from io import BytesIO
|
||||||
|
from tests.utils import Command
|
||||||
|
from thefuck.rules.npm_missing_script import match, get_new_command
|
||||||
|
|
||||||
|
stderr = '''
|
||||||
|
npm ERR! Linux 4.4.0-31-generic
|
||||||
|
npm ERR! argv "/opt/node/bin/node" "/opt/node/bin/npm" "run" "dvelop"
|
||||||
|
npm ERR! node v4.4.7
|
||||||
|
npm ERR! npm v2.15.8
|
||||||
|
|
||||||
|
npm ERR! missing script: {}
|
||||||
|
npm ERR!
|
||||||
|
npm ERR! If you need help, you may report this error at:
|
||||||
|
npm ERR! <https://github.com/npm/npm/issues>
|
||||||
|
|
||||||
|
npm ERR! Please include the following file with any support request:
|
||||||
|
npm ERR! /home/nvbn/exp/code_view/client_web/npm-debug.log
|
||||||
|
'''.format
|
||||||
|
|
||||||
|
run_script_stdout = b'''
|
||||||
|
Lifecycle scripts included in code-view-web:
|
||||||
|
test
|
||||||
|
jest
|
||||||
|
|
||||||
|
available via `npm run-script`:
|
||||||
|
build
|
||||||
|
cp node_modules/ace-builds/src-min/ -a resources/ace/ && webpack --progress --colors -p --config ./webpack.production.config.js
|
||||||
|
develop
|
||||||
|
cp node_modules/ace-builds/src/ -a resources/ace/ && webpack-dev-server --progress --colors
|
||||||
|
watch-test
|
||||||
|
jest --verbose --watch
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def run_script(mocker):
|
||||||
|
patch = mocker.patch('thefuck.specific.npm.Popen')
|
||||||
|
patch.return_value.stdout = BytesIO(run_script_stdout)
|
||||||
|
return patch.return_value
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command('npm ru wach', stderr=stderr('wach')),
|
||||||
|
Command('npm run live-tes', stderr=stderr('live-tes')),
|
||||||
|
Command('npm run-script sahare', stderr=stderr('sahare'))])
|
||||||
|
def test_match(command):
|
||||||
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command('npm wach', stderr=stderr('wach')),
|
||||||
|
Command('vim live-tes', stderr=stderr('live-tes')),
|
||||||
|
Command('npm run-script sahare')])
|
||||||
|
def test_not_match(command):
|
||||||
|
assert not match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, stderr, result', [
|
||||||
|
('npm ru wach-tests', stderr('wach-tests'), 'npm ru watch-test'),
|
||||||
|
('npm -i run-script dvelop', stderr('dvelop'),
|
||||||
|
'npm -i run-script develop'),
|
||||||
|
('npm -i run-script buld -X POST', stderr('buld'),
|
||||||
|
'npm -i run-script build -X POST')])
|
||||||
|
def test_get_new_command(script, stderr, result):
|
||||||
|
command = Command(script, stderr=stderr)
|
||||||
|
|
||||||
|
assert get_new_command(command)[0] == result
|
||||||
84
tests/rules/test_npm_run_script.py
Normal file
84
tests/rules/test_npm_run_script.py
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import pytest
|
||||||
|
from io import BytesIO
|
||||||
|
from thefuck.rules.npm_run_script import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
stdout = '''
|
||||||
|
Usage: npm <command>
|
||||||
|
|
||||||
|
where <command> is one of:
|
||||||
|
access, add-user, adduser, apihelp, author, bin, bugs, c,
|
||||||
|
cache, completion, config, ddp, dedupe, deprecate, dist-tag,
|
||||||
|
dist-tags, docs, edit, explore, faq, find, find-dupes, get,
|
||||||
|
help, help-search, home, i, info, init, install, issues, la,
|
||||||
|
link, list, ll, ln, login, logout, ls, outdated, owner,
|
||||||
|
pack, ping, prefix, prune, publish, r, rb, rebuild, remove,
|
||||||
|
repo, restart, rm, root, run-script, s, se, search, set,
|
||||||
|
show, shrinkwrap, star, stars, start, stop, t, tag, team,
|
||||||
|
test, tst, un, uninstall, unlink, unpublish, unstar, up,
|
||||||
|
update, upgrade, v, version, view, whoami
|
||||||
|
|
||||||
|
npm <cmd> -h quick help on <cmd>
|
||||||
|
npm -l display full usage info
|
||||||
|
npm faq commonly asked questions
|
||||||
|
npm help <term> search for help on <term>
|
||||||
|
npm help npm involved overview
|
||||||
|
|
||||||
|
Specify configs in the ini-formatted file:
|
||||||
|
/home/nvbn/.npmrc
|
||||||
|
or on the command line via: npm <command> --key value
|
||||||
|
Config info can be viewed via: npm help config
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
run_script_stdout = b'''
|
||||||
|
Lifecycle scripts included in code-view-web:
|
||||||
|
test
|
||||||
|
jest
|
||||||
|
|
||||||
|
available via `npm run-script`:
|
||||||
|
build
|
||||||
|
cp node_modules/ace-builds/src-min/ -a resources/ace/ && webpack --progress --colors -p --config ./webpack.production.config.js
|
||||||
|
develop
|
||||||
|
cp node_modules/ace-builds/src/ -a resources/ace/ && webpack-dev-server --progress --colors
|
||||||
|
watch-test
|
||||||
|
jest --verbose --watch
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def run_script(mocker):
|
||||||
|
patch = mocker.patch('thefuck.specific.npm.Popen')
|
||||||
|
patch.return_value.stdout = BytesIO(run_script_stdout)
|
||||||
|
return patch.return_value
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('no_memoize')
|
||||||
|
@pytest.mark.parametrize('script', [
|
||||||
|
'npm watch-test', 'npm develop'])
|
||||||
|
def test_match(script):
|
||||||
|
command = Command(script, stdout)
|
||||||
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('no_memoize')
|
||||||
|
@pytest.mark.parametrize('command, run_script_out', [
|
||||||
|
(Command('npm test', 'TEST FAIL'), run_script_stdout),
|
||||||
|
(Command('npm watch-test', 'TEST FAIL'), run_script_stdout),
|
||||||
|
(Command('npm test', stdout), run_script_stdout),
|
||||||
|
(Command('vim watch-test', stdout), run_script_stdout)])
|
||||||
|
def test_not_match(run_script, command, run_script_out):
|
||||||
|
run_script.stdout = BytesIO(run_script_out)
|
||||||
|
assert not match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('no_memoize')
|
||||||
|
@pytest.mark.parametrize('script, result', [
|
||||||
|
('npm watch-test', 'npm run-script watch-test'),
|
||||||
|
('npm -i develop', 'npm run-script -i develop'),
|
||||||
|
('npm -i watch-script --path ..',
|
||||||
|
'npm run-script -i watch-script --path ..')])
|
||||||
|
def test_get_new_command(script, result):
|
||||||
|
command = Command(script, stdout)
|
||||||
|
assert get_new_command(command) == result
|
||||||
58
tests/rules/test_npm_wrong_command.py
Normal file
58
tests/rules/test_npm_wrong_command.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.npm_wrong_command import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
stdout = '''
|
||||||
|
Usage: npm <command>
|
||||||
|
|
||||||
|
where <command> is one of:
|
||||||
|
access, add-user, adduser, apihelp, author, bin, bugs, c,
|
||||||
|
cache, completion, config, ddp, dedupe, deprecate, dist-tag,
|
||||||
|
dist-tags, docs, edit, explore, faq, find, find-dupes, get,
|
||||||
|
help, help-search, home, i, info, init, install, issues, la,
|
||||||
|
link, list, ll, ln, login, logout, ls, outdated, owner,
|
||||||
|
pack, ping, prefix, prune, publish, r, rb, rebuild, remove,
|
||||||
|
repo, restart, rm, root, run-script, s, se, search, set,
|
||||||
|
show, shrinkwrap, star, stars, start, stop, t, tag, team,
|
||||||
|
test, tst, un, uninstall, unlink, unpublish, unstar, up,
|
||||||
|
update, upgrade, v, verison, version, view, whoami
|
||||||
|
|
||||||
|
npm <cmd> -h quick help on <cmd>
|
||||||
|
npm -l display full usage info
|
||||||
|
npm faq commonly asked questions
|
||||||
|
npm help <term> search for help on <term>
|
||||||
|
npm help npm involved overview
|
||||||
|
|
||||||
|
Specify configs in the ini-formatted file:
|
||||||
|
/home/nvbn/.npmrc
|
||||||
|
or on the command line via: npm <command> --key value
|
||||||
|
Config info can be viewed via: npm help config
|
||||||
|
|
||||||
|
npm@2.14.7 /opt/node/lib/node_modules/npm
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', [
|
||||||
|
'npm urgrdae',
|
||||||
|
'npm urgrade -g',
|
||||||
|
'npm -f urgrade -g',
|
||||||
|
'npm urg'])
|
||||||
|
def test_match(script):
|
||||||
|
assert match(Command(script, stdout))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, stdout', [
|
||||||
|
('npm urgrade', ''),
|
||||||
|
('npm', stdout),
|
||||||
|
('test urgrade', stdout),
|
||||||
|
('npm -e', stdout)])
|
||||||
|
def test_not_match(script, stdout):
|
||||||
|
assert not match(Command(script, stdout))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, result', [
|
||||||
|
('npm urgrade', 'npm upgrade'),
|
||||||
|
('npm -g isntall gulp', 'npm -g install gulp'),
|
||||||
|
('npm isntall -g gulp', 'npm install -g gulp')])
|
||||||
|
def test_get_new_command(script, result):
|
||||||
|
assert get_new_command(Command(script, stdout)) == result
|
||||||
@@ -1,31 +1,49 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from thefuck.rules.open import match, get_new_command
|
from thefuck.rules.open import is_arg_url, match, get_new_command
|
||||||
from tests.utils import Command
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('command', [
|
@pytest.fixture
|
||||||
Command(script='open foo.com'),
|
def stderr(script):
|
||||||
Command(script='open foo.ly'),
|
return 'The file {} does not exist.\n'.format(script.split(' ', 1)[1])
|
||||||
Command(script='open foo.org'),
|
|
||||||
Command(script='open foo.net'),
|
|
||||||
Command(script='open foo.se'),
|
|
||||||
Command(script='open foo.io'),
|
|
||||||
Command(script='xdg-open foo.com'),
|
|
||||||
Command(script='gnome-open foo.com'),
|
|
||||||
Command(script='kde-open foo.com')])
|
|
||||||
def test_match(command):
|
|
||||||
assert match(command)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('command, new_command', [
|
@pytest.mark.parametrize('script', [
|
||||||
(Command('open foo.com'), 'open http://foo.com'),
|
'open foo.com',
|
||||||
(Command('open foo.ly'), 'open http://foo.ly'),
|
'open foo.edu',
|
||||||
(Command('open foo.org'), 'open http://foo.org'),
|
'open foo.info',
|
||||||
(Command('open foo.net'), 'open http://foo.net'),
|
'open foo.io',
|
||||||
(Command('open foo.se'), 'open http://foo.se'),
|
'open foo.ly',
|
||||||
(Command('open foo.io'), 'open http://foo.io'),
|
'open foo.me',
|
||||||
(Command('xdg-open foo.io'), 'xdg-open http://foo.io'),
|
'open foo.net',
|
||||||
(Command('gnome-open foo.io'), 'gnome-open http://foo.io'),
|
'open foo.org',
|
||||||
(Command('kde-open foo.io'), 'kde-open http://foo.io')])
|
'open foo.se',
|
||||||
def test_get_new_command(command, new_command):
|
'open www.foo.ru'])
|
||||||
assert get_new_command(command) == new_command
|
def test_is_arg_url(script):
|
||||||
|
assert is_arg_url(Command(script))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', ['open foo', 'open bar.txt', 'open egg.doc'])
|
||||||
|
def test_not_is_arg_url(script):
|
||||||
|
assert not is_arg_url(Command(script))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', [
|
||||||
|
'open foo.com',
|
||||||
|
'xdg-open foo.com',
|
||||||
|
'gnome-open foo.com',
|
||||||
|
'kde-open foo.com',
|
||||||
|
'open nonest'])
|
||||||
|
def test_match(script, stderr):
|
||||||
|
assert match(Command(script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, new_command', [
|
||||||
|
('open foo.io', ['open http://foo.io']),
|
||||||
|
('xdg-open foo.io', ['xdg-open http://foo.io']),
|
||||||
|
('gnome-open foo.io', ['gnome-open http://foo.io']),
|
||||||
|
('kde-open foo.io', ['kde-open http://foo.io']),
|
||||||
|
('open nonest', ['touch nonest && open nonest',
|
||||||
|
'mkdir nonest && open nonest'])])
|
||||||
|
def test_get_new_command(script, new_command, stderr):
|
||||||
|
assert get_new_command(Command(script, stderr=stderr)) == new_command
|
||||||
|
|||||||
101
tests/rules/test_port_already_in_use.py
Normal file
101
tests/rules/test_port_already_in_use.py
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from thefuck.rules.port_already_in_use import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
outputs = [
|
||||||
|
'''
|
||||||
|
|
||||||
|
DE 70% 1/1 build modulesevents.js:141
|
||||||
|
throw er; // Unhandled 'error' event
|
||||||
|
^
|
||||||
|
|
||||||
|
Error: listen EADDRINUSE 127.0.0.1:8080
|
||||||
|
at Object.exports._errnoException (util.js:873:11)
|
||||||
|
at exports._exceptionWithHostPort (util.js:896:20)
|
||||||
|
at Server._listen2 (net.js:1250:14)
|
||||||
|
at listen (net.js:1286:10)
|
||||||
|
at net.js:1395:9
|
||||||
|
at GetAddrInfoReqWrap.asyncCallback [as callback] (dns.js:64:16)
|
||||||
|
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:83:10)
|
||||||
|
|
||||||
|
''',
|
||||||
|
'''
|
||||||
|
[6:40:01 AM] <START> Building Dependency Graph
|
||||||
|
[6:40:01 AM] <START> Crawling File System
|
||||||
|
ERROR Packager can't listen on port 8080
|
||||||
|
Most likely another process is already using this port
|
||||||
|
Run the following command to find out which process:
|
||||||
|
|
||||||
|
lsof -n -i4TCP:8080
|
||||||
|
|
||||||
|
You can either shut down the other process:
|
||||||
|
|
||||||
|
kill -9 <PID>
|
||||||
|
|
||||||
|
or run packager on different port.
|
||||||
|
|
||||||
|
''',
|
||||||
|
'''
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "/usr/lib/python3.5/runpy.py", line 184, in _run_module_as_main
|
||||||
|
"__main__", mod_spec)
|
||||||
|
File "/usr/lib/python3.5/runpy.py", line 85, in _run_code
|
||||||
|
exec(code, run_globals)
|
||||||
|
File "/home/nvbn/exp/code_view/server/code_view/main.py", line 14, in <module>
|
||||||
|
web.run_app(app)
|
||||||
|
File "/home/nvbn/.virtualenvs/code_view/lib/python3.5/site-packages/aiohttp/web.py", line 310, in run_app
|
||||||
|
backlog=backlog))
|
||||||
|
File "/usr/lib/python3.5/asyncio/base_events.py", line 373, in run_until_complete
|
||||||
|
return future.result()
|
||||||
|
File "/usr/lib/python3.5/asyncio/futures.py", line 274, in result
|
||||||
|
raise self._exception
|
||||||
|
File "/usr/lib/python3.5/asyncio/tasks.py", line 240, in _step
|
||||||
|
result = coro.send(None)
|
||||||
|
File "/usr/lib/python3.5/asyncio/base_events.py", line 953, in create_server
|
||||||
|
% (sa, err.strerror.lower()))
|
||||||
|
OSError: [Errno 98] error while attempting to bind on address ('0.0.0.0', 8080): address already in use
|
||||||
|
Task was destroyed but it is pending!
|
||||||
|
task: <Task pending coro=<RedisProtocol._reader_coroutine() running at /home/nvbn/.virtualenvs/code_view/lib/python3.5/site-packages/asyncio_redis/protocol.py:921> wait_for=<Future pending cb=[Task._wakeup()]>>
|
||||||
|
'''
|
||||||
|
]
|
||||||
|
|
||||||
|
lsof_stdout = b'''COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
|
||||||
|
node 18233 nvbn 16u IPv4 557134 0t0 TCP localhost:http-alt (LISTEN)
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def lsof(mocker):
|
||||||
|
patch = mocker.patch('thefuck.rules.port_already_in_use.Popen')
|
||||||
|
patch.return_value.stdout = BytesIO(lsof_stdout)
|
||||||
|
return patch
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('no_memoize')
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'command',
|
||||||
|
[Command('./app', stdout=output) for output in outputs]
|
||||||
|
+ [Command('./app', stderr=output) for output in outputs])
|
||||||
|
def test_match(command):
|
||||||
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('no_memoize')
|
||||||
|
@pytest.mark.parametrize('command, lsof_output', [
|
||||||
|
(Command('./app'), lsof_stdout),
|
||||||
|
(Command('./app', stdout=outputs[1]), b''),
|
||||||
|
(Command('./app', stderr=outputs[2]), b'')])
|
||||||
|
def test_not_match(lsof, command, lsof_output):
|
||||||
|
lsof.return_value.stdout = BytesIO(lsof_output)
|
||||||
|
|
||||||
|
assert not match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'command',
|
||||||
|
[Command('./app', stdout=output) for output in outputs]
|
||||||
|
+ [Command('./app', stderr=output) for output in outputs])
|
||||||
|
def test_get_new_command(command):
|
||||||
|
assert get_new_command(command) == 'kill 18233 && ./app'
|
||||||
46
tests/rules/test_react_native_command_unrecognized.py
Normal file
46
tests/rules/test_react_native_command_unrecognized.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.react_native_command_unrecognized import match, \
|
||||||
|
get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
stderr = 'Command `{}` unrecognized'.format
|
||||||
|
|
||||||
|
stdout = '''
|
||||||
|
Usage: react-native <command>
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
- start: starts the webserver
|
||||||
|
- bundle: builds the javascript bundle for offline use
|
||||||
|
- unbundle: builds javascript as "unbundle" for offline use
|
||||||
|
- new-library: generates a native library bridge
|
||||||
|
- android: generates an Android project for your app
|
||||||
|
- run-android: builds your app and starts it on a connected Android emulator or device
|
||||||
|
- log-android: print Android logs
|
||||||
|
- run-ios: builds your app and starts it on iOS simulator
|
||||||
|
- log-ios: print iOS logs
|
||||||
|
- upgrade: upgrade your app's template files to the latest version; run this after updating the react-native version in your package.json and running npm install
|
||||||
|
- link: link a library
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command('react-native star', stderr=stderr('star')),
|
||||||
|
Command('react-native android-logs', stderr=stderr('android-logs'))])
|
||||||
|
def test_match(command):
|
||||||
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command('gradle star', stderr=stderr('star')),
|
||||||
|
Command('react-native start')])
|
||||||
|
def test_not_match(command):
|
||||||
|
assert not match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command, result', [
|
||||||
|
(Command('react-native star', stdout, stderr('star')),
|
||||||
|
'react-native start'),
|
||||||
|
(Command('react-native logsandroid -f', stdout, stderr('logsandroid')),
|
||||||
|
'react-native log-android -f')])
|
||||||
|
def test_get_new_command(command, result):
|
||||||
|
assert get_new_command(command)[0] == result
|
||||||
17
tests/rules/test_remove_trailing_cedilla.py
Normal file
17
tests/rules/test_remove_trailing_cedilla.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.remove_trailing_cedilla import match, get_new_command, CEDILLA
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command', [
|
||||||
|
Command(script='wrong' + CEDILLA),
|
||||||
|
Command(script='wrong with args' + CEDILLA)])
|
||||||
|
def test_match(command):
|
||||||
|
assert match(command)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('command, new_command', [
|
||||||
|
(Command('wrong' + CEDILLA), 'wrong'),
|
||||||
|
(Command('wrong with args' + CEDILLA), 'wrong with args')])
|
||||||
|
def test_get_new_command(command, new_command):
|
||||||
|
assert get_new_command(command) == new_command
|
||||||
@@ -52,6 +52,7 @@ def test_match(ssh_error):
|
|||||||
assert not match(Command('ssh'))
|
assert not match(Command('ssh'))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(os.name == 'nt', reason='Skip if testing on Windows')
|
||||||
def test_side_effect(ssh_error):
|
def test_side_effect(ssh_error):
|
||||||
errormsg, path, reset, known_hosts = ssh_error
|
errormsg, path, reset, known_hosts = ssh_error
|
||||||
command = Command('ssh user@host', stderr=errormsg)
|
command = Command('ssh user@host', stderr=errormsg)
|
||||||
|
|||||||
30
tests/rules/test_workon_doesnt_exists.py
Normal file
30
tests/rules/test_workon_doesnt_exists.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.workon_doesnt_exists import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def envs(mocker):
|
||||||
|
return mocker.patch(
|
||||||
|
'thefuck.rules.workon_doesnt_exists._get_all_environments',
|
||||||
|
return_value=['thefuck', 'code_view'])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', [
|
||||||
|
'workon tehfuck', 'workon code-view', 'workon new-env'])
|
||||||
|
def test_match(script):
|
||||||
|
assert match(Command(script))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script', [
|
||||||
|
'workon thefuck', 'workon code_view', 'work on tehfuck'])
|
||||||
|
def test_not_match(script):
|
||||||
|
assert not match(Command(script))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('script, result', [
|
||||||
|
('workon tehfuck', 'workon thefuck'),
|
||||||
|
('workon code-view', 'workon code_view'),
|
||||||
|
('workon zzzz', 'mkvirtualenv zzzz')])
|
||||||
|
def test_get_new_command(script, result):
|
||||||
|
assert get_new_command(Command(script))[0] == result
|
||||||
0
tests/shells/__init__.py
Normal file
0
tests/shells/__init__.py
Normal file
22
tests/shells/conftest.py
Normal file
22
tests/shells/conftest.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def builtins_open(mocker):
|
||||||
|
return mocker.patch('six.moves.builtins.open')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def isfile(mocker):
|
||||||
|
return mocker.patch('os.path.isfile', return_value=True)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
@pytest.mark.usefixtures('isfile')
|
||||||
|
def history_lines(mocker):
|
||||||
|
def aux(lines):
|
||||||
|
mock = mocker.patch('io.open')
|
||||||
|
mock.return_value.__enter__ \
|
||||||
|
.return_value.readlines.return_value = lines
|
||||||
|
|
||||||
|
return aux
|
||||||
63
tests/shells/test_bash.py
Normal file
63
tests/shells/test_bash.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pytest
|
||||||
|
from thefuck.shells import Bash
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('isfile', 'no_memoize', 'no_cache')
|
||||||
|
class TestBash(object):
|
||||||
|
@pytest.fixture
|
||||||
|
def shell(self):
|
||||||
|
return Bash()
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def shell_aliases(self):
|
||||||
|
os.environ['TF_SHELL_ALIASES'] = (
|
||||||
|
'alias fuck=\'eval $(thefuck $(fc -ln -1))\'\n'
|
||||||
|
'alias l=\'ls -CF\'\n'
|
||||||
|
'alias la=\'ls -A\'\n'
|
||||||
|
'alias ll=\'ls -alF\'')
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('before, after', [
|
||||||
|
('pwd', 'pwd'),
|
||||||
|
('fuck', 'eval $(thefuck $(fc -ln -1))'),
|
||||||
|
('awk', 'awk'),
|
||||||
|
('ll', 'ls -alF')])
|
||||||
|
def test_from_shell(self, before, after, shell):
|
||||||
|
assert shell.from_shell(before) == after
|
||||||
|
|
||||||
|
def test_to_shell(self, shell):
|
||||||
|
assert shell.to_shell('pwd') == 'pwd'
|
||||||
|
|
||||||
|
def test_and_(self, shell):
|
||||||
|
assert shell.and_('ls', 'cd') == 'ls && cd'
|
||||||
|
|
||||||
|
def test_get_aliases(self, shell):
|
||||||
|
assert shell.get_aliases() == {'fuck': 'eval $(thefuck $(fc -ln -1))',
|
||||||
|
'l': 'ls -CF',
|
||||||
|
'la': 'ls -A',
|
||||||
|
'll': 'ls -alF'}
|
||||||
|
|
||||||
|
def test_app_alias(self, shell):
|
||||||
|
assert 'alias fuck' in shell.app_alias('fuck')
|
||||||
|
assert 'alias FUCK' in shell.app_alias('FUCK')
|
||||||
|
assert 'thefuck' in shell.app_alias('fuck')
|
||||||
|
assert 'TF_ALIAS=fuck' in shell.app_alias('fuck')
|
||||||
|
assert 'PYTHONIOENCODING=utf-8' in shell.app_alias('fuck')
|
||||||
|
|
||||||
|
def test_app_alias_variables_correctly_set(self, shell):
|
||||||
|
alias = shell.app_alias('fuck')
|
||||||
|
assert "alias fuck='TF_CMD=$(TF_ALIAS" in alias
|
||||||
|
assert '$(TF_ALIAS=fuck PYTHONIOENCODING' in alias
|
||||||
|
assert 'PYTHONIOENCODING=utf-8 TF_SHELL_ALIASES' in alias
|
||||||
|
assert 'ALIASES=$(alias) thefuck' in alias
|
||||||
|
|
||||||
|
def test_get_history(self, history_lines, shell):
|
||||||
|
history_lines(['ls', 'rm'])
|
||||||
|
assert list(shell.get_history()) == ['ls', 'rm']
|
||||||
|
|
||||||
|
def test_split_command(self, shell):
|
||||||
|
command = 'git log -p'
|
||||||
|
command_parts = ['git', 'log', '-p']
|
||||||
|
assert shell.split_command(command) == command_parts
|
||||||
97
tests/shells/test_fish.py
Normal file
97
tests/shells/test_fish.py
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from thefuck.shells import Fish
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('isfile', 'no_memoize', 'no_cache')
|
||||||
|
class TestFish(object):
|
||||||
|
@pytest.fixture
|
||||||
|
def shell(self):
|
||||||
|
return Fish()
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def Popen(self, mocker):
|
||||||
|
mock = mocker.patch('thefuck.shells.fish.Popen')
|
||||||
|
mock.return_value.stdout.read.return_value = (
|
||||||
|
b'cd\nfish_config\nfuck\nfunced\nfuncsave\ngrep\nhistory\nll\nls\n'
|
||||||
|
b'man\nmath\npopd\npushd\nruby')
|
||||||
|
return mock
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def os_environ(self, monkeypatch, key, value):
|
||||||
|
monkeypatch.setattr('os.environ', {key: value})
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('key, value', [
|
||||||
|
('TF_OVERRIDDEN_ALIASES', 'cut,git,sed'), # legacy
|
||||||
|
('THEFUCK_OVERRIDDEN_ALIASES', 'cut,git,sed'),
|
||||||
|
('THEFUCK_OVERRIDDEN_ALIASES', 'cut, git, sed'),
|
||||||
|
('THEFUCK_OVERRIDDEN_ALIASES', ' cut,\tgit,sed\n'),
|
||||||
|
('THEFUCK_OVERRIDDEN_ALIASES', '\ncut,\n\ngit,\tsed\r')])
|
||||||
|
def test_get_overridden_aliases(self, shell, os_environ):
|
||||||
|
assert shell._get_overridden_aliases() == {'cd', 'cut', 'git', 'grep',
|
||||||
|
'ls', 'man', 'open', 'sed'}
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('before, after', [
|
||||||
|
('cd', 'cd'),
|
||||||
|
('pwd', 'pwd'),
|
||||||
|
('fuck', 'fish -ic "fuck"'),
|
||||||
|
('find', 'find'),
|
||||||
|
('funced', 'fish -ic "funced"'),
|
||||||
|
('grep', 'grep'),
|
||||||
|
('awk', 'awk'),
|
||||||
|
('math "2 + 2"', r'fish -ic "math \"2 + 2\""'),
|
||||||
|
('man', 'man'),
|
||||||
|
('open', 'open'),
|
||||||
|
('vim', 'vim'),
|
||||||
|
('ll', 'fish -ic "ll"'),
|
||||||
|
('ls', 'ls')]) # Fish has no aliases but functions
|
||||||
|
def test_from_shell(self, before, after, shell):
|
||||||
|
assert shell.from_shell(before) == after
|
||||||
|
|
||||||
|
def test_to_shell(self, shell):
|
||||||
|
assert shell.to_shell('pwd') == 'pwd'
|
||||||
|
|
||||||
|
def test_and_(self, shell):
|
||||||
|
assert shell.and_('foo', 'bar') == 'foo; and bar'
|
||||||
|
|
||||||
|
def test_get_aliases(self, shell):
|
||||||
|
assert shell.get_aliases() == {'fish_config': 'fish_config',
|
||||||
|
'fuck': 'fuck',
|
||||||
|
'funced': 'funced',
|
||||||
|
'funcsave': 'funcsave',
|
||||||
|
'history': 'history',
|
||||||
|
'll': 'll',
|
||||||
|
'math': 'math',
|
||||||
|
'popd': 'popd',
|
||||||
|
'pushd': 'pushd',
|
||||||
|
'ruby': 'ruby'}
|
||||||
|
|
||||||
|
def test_app_alias(self, shell):
|
||||||
|
assert 'function fuck' in shell.app_alias('fuck')
|
||||||
|
assert 'function FUCK' in shell.app_alias('FUCK')
|
||||||
|
assert 'thefuck' in shell.app_alias('fuck')
|
||||||
|
assert 'TF_ALIAS=fuck PYTHONIOENCODING' in shell.app_alias('fuck')
|
||||||
|
assert 'PYTHONIOENCODING=utf-8 thefuck' in shell.app_alias('fuck')
|
||||||
|
|
||||||
|
def test_app_alias_alter_history(self, settings, shell):
|
||||||
|
settings.alter_history = True
|
||||||
|
assert 'builtin history delete' in shell.app_alias('FUCK')
|
||||||
|
assert 'builtin history merge' in shell.app_alias('FUCK')
|
||||||
|
settings.alter_history = False
|
||||||
|
assert 'builtin history delete' not in shell.app_alias('FUCK')
|
||||||
|
assert 'builtin history merge' not in shell.app_alias('FUCK')
|
||||||
|
|
||||||
|
def test_get_history(self, history_lines, shell):
|
||||||
|
history_lines(['- cmd: ls', ' when: 1432613911',
|
||||||
|
'- cmd: rm', ' when: 1432613916'])
|
||||||
|
assert list(shell.get_history()) == ['ls', 'rm']
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('entry, entry_utf8', [
|
||||||
|
('ls', '- cmd: ls\n when: 1430707243\n'),
|
||||||
|
(u'echo café', '- cmd: echo café\n when: 1430707243\n')])
|
||||||
|
def test_put_to_history(self, entry, entry_utf8, builtins_open, mocker, shell):
|
||||||
|
mocker.patch('thefuck.shells.fish.time', return_value=1430707243.3517463)
|
||||||
|
shell.put_to_history(entry)
|
||||||
|
builtins_open.return_value.__enter__.return_value. \
|
||||||
|
write.assert_called_once_with(entry_utf8)
|
||||||
39
tests/shells/test_generic.py
Normal file
39
tests/shells/test_generic.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from thefuck.shells import Generic
|
||||||
|
|
||||||
|
|
||||||
|
class TestGeneric(object):
|
||||||
|
@pytest.fixture
|
||||||
|
def shell(self):
|
||||||
|
return Generic()
|
||||||
|
|
||||||
|
def test_from_shell(self, shell):
|
||||||
|
assert shell.from_shell('pwd') == 'pwd'
|
||||||
|
|
||||||
|
def test_to_shell(self, shell):
|
||||||
|
assert shell.to_shell('pwd') == 'pwd'
|
||||||
|
|
||||||
|
def test_and_(self, shell):
|
||||||
|
assert shell.and_('ls', 'cd') == 'ls && cd'
|
||||||
|
|
||||||
|
def test_get_aliases(self, shell):
|
||||||
|
assert shell.get_aliases() == {}
|
||||||
|
|
||||||
|
def test_app_alias(self, shell):
|
||||||
|
assert 'alias fuck' in shell.app_alias('fuck')
|
||||||
|
assert 'alias FUCK' in shell.app_alias('FUCK')
|
||||||
|
assert 'thefuck' in shell.app_alias('fuck')
|
||||||
|
assert 'TF_ALIAS=fuck PYTHONIOENCODING' in shell.app_alias('fuck')
|
||||||
|
assert 'PYTHONIOENCODING=utf-8 thefuck' in shell.app_alias('fuck')
|
||||||
|
|
||||||
|
def test_get_history(self, history_lines, shell):
|
||||||
|
history_lines(['ls', 'rm'])
|
||||||
|
# We don't know what to do in generic shell with history lines,
|
||||||
|
# so just ignore them:
|
||||||
|
assert list(shell.get_history()) == []
|
||||||
|
|
||||||
|
def test_split_command(self, shell):
|
||||||
|
assert shell.split_command('ls') == ['ls']
|
||||||
|
assert shell.split_command(u'echo café') == [u'echo', u'café']
|
||||||
19
tests/shells/test_powershell.py
Normal file
19
tests/shells/test_powershell.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from thefuck.shells import Powershell
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('isfile', 'no_memoize', 'no_cache')
|
||||||
|
class TestPowershell(object):
|
||||||
|
@pytest.fixture
|
||||||
|
def shell(self):
|
||||||
|
return Powershell()
|
||||||
|
|
||||||
|
def test_and_(self, shell):
|
||||||
|
assert shell.and_('ls', 'cd') == '(ls) -and (cd)'
|
||||||
|
|
||||||
|
def test_app_alias(self, shell):
|
||||||
|
assert 'function fuck' in shell.app_alias('fuck')
|
||||||
|
assert 'function FUCK' in shell.app_alias('FUCK')
|
||||||
|
assert 'thefuck' in shell.app_alias('fuck')
|
||||||
50
tests/shells/test_tcsh.py
Normal file
50
tests/shells/test_tcsh.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from thefuck.shells.tcsh import Tcsh
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('isfile', 'no_memoize', 'no_cache')
|
||||||
|
class TestTcsh(object):
|
||||||
|
@pytest.fixture
|
||||||
|
def shell(self):
|
||||||
|
return Tcsh()
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def Popen(self, mocker):
|
||||||
|
mock = mocker.patch('thefuck.shells.tcsh.Popen')
|
||||||
|
mock.return_value.stdout.read.return_value = (
|
||||||
|
b'fuck\teval $(thefuck $(fc -ln -1))\n'
|
||||||
|
b'l\tls -CF\n'
|
||||||
|
b'la\tls -A\n'
|
||||||
|
b'll\tls -alF')
|
||||||
|
return mock
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('before, after', [
|
||||||
|
('pwd', 'pwd'),
|
||||||
|
('fuck', 'eval $(thefuck $(fc -ln -1))'),
|
||||||
|
('awk', 'awk'),
|
||||||
|
('ll', 'ls -alF')])
|
||||||
|
def test_from_shell(self, before, after, shell):
|
||||||
|
assert shell.from_shell(before) == after
|
||||||
|
|
||||||
|
def test_to_shell(self, shell):
|
||||||
|
assert shell.to_shell('pwd') == 'pwd'
|
||||||
|
|
||||||
|
def test_and_(self, shell):
|
||||||
|
assert shell.and_('ls', 'cd') == 'ls && cd'
|
||||||
|
|
||||||
|
def test_get_aliases(self, shell):
|
||||||
|
assert shell.get_aliases() == {'fuck': 'eval $(thefuck $(fc -ln -1))',
|
||||||
|
'l': 'ls -CF',
|
||||||
|
'la': 'ls -A',
|
||||||
|
'll': 'ls -alF'}
|
||||||
|
|
||||||
|
def test_app_alias(self, shell):
|
||||||
|
assert 'alias fuck' in shell.app_alias('fuck')
|
||||||
|
assert 'alias FUCK' in shell.app_alias('FUCK')
|
||||||
|
assert 'thefuck' in shell.app_alias('fuck')
|
||||||
|
|
||||||
|
def test_get_history(self, history_lines, shell):
|
||||||
|
history_lines(['ls', 'rm'])
|
||||||
|
assert list(shell.get_history()) == ['ls', 'rm']
|
||||||
57
tests/shells/test_zsh.py
Normal file
57
tests/shells/test_zsh.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pytest
|
||||||
|
from thefuck.shells.zsh import Zsh
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('isfile', 'no_memoize', 'no_cache')
|
||||||
|
class TestZsh(object):
|
||||||
|
@pytest.fixture
|
||||||
|
def shell(self):
|
||||||
|
return Zsh()
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def shell_aliases(self):
|
||||||
|
os.environ['TF_SHELL_ALIASES'] = (
|
||||||
|
'fuck=\'eval $(thefuck $(fc -ln -1 | tail -n 1))\'\n'
|
||||||
|
'l=\'ls -CF\'\n'
|
||||||
|
'la=\'ls -A\'\n'
|
||||||
|
'll=\'ls -alF\'')
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('before, after', [
|
||||||
|
('fuck', 'eval $(thefuck $(fc -ln -1 | tail -n 1))'),
|
||||||
|
('pwd', 'pwd'),
|
||||||
|
('ll', 'ls -alF')])
|
||||||
|
def test_from_shell(self, before, after, shell):
|
||||||
|
assert shell.from_shell(before) == after
|
||||||
|
|
||||||
|
def test_to_shell(self, shell):
|
||||||
|
assert shell.to_shell('pwd') == 'pwd'
|
||||||
|
|
||||||
|
def test_and_(self, shell):
|
||||||
|
assert shell.and_('ls', 'cd') == 'ls && cd'
|
||||||
|
|
||||||
|
def test_get_aliases(self, shell):
|
||||||
|
assert shell.get_aliases() == {
|
||||||
|
'fuck': 'eval $(thefuck $(fc -ln -1 | tail -n 1))',
|
||||||
|
'l': 'ls -CF',
|
||||||
|
'la': 'ls -A',
|
||||||
|
'll': 'ls -alF'}
|
||||||
|
|
||||||
|
def test_app_alias(self, shell):
|
||||||
|
assert 'alias fuck' in shell.app_alias('fuck')
|
||||||
|
assert 'alias FUCK' in shell.app_alias('FUCK')
|
||||||
|
assert 'thefuck' in shell.app_alias('fuck')
|
||||||
|
assert 'PYTHONIOENCODING' in shell.app_alias('fuck')
|
||||||
|
|
||||||
|
def test_app_alias_variables_correctly_set(self, shell):
|
||||||
|
alias = shell.app_alias('fuck')
|
||||||
|
assert "alias fuck='TF_CMD=$(TF_ALIAS" in alias
|
||||||
|
assert '$(TF_ALIAS=fuck PYTHONIOENCODING' in alias
|
||||||
|
assert 'PYTHONIOENCODING=utf-8 TF_SHELL_ALIASES' in alias
|
||||||
|
assert 'ALIASES=$(alias) thefuck' in alias
|
||||||
|
|
||||||
|
def test_get_history(self, history_lines, shell):
|
||||||
|
history_lines([': 1432613911:0;ls', ': 1432613916:0;rm'])
|
||||||
|
assert list(shell.get_history()) == ['ls', 'rm']
|
||||||
26
tests/specific/test_npm.py
Normal file
26
tests/specific/test_npm.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from thefuck.specific.npm import get_scripts
|
||||||
|
|
||||||
|
run_script_stdout = b'''
|
||||||
|
Lifecycle scripts included in code-view-web:
|
||||||
|
test
|
||||||
|
jest
|
||||||
|
|
||||||
|
available via `npm run-script`:
|
||||||
|
build
|
||||||
|
cp node_modules/ace-builds/src-min/ -a resources/ace/ && webpack --progress --colors -p --config ./webpack.production.config.js
|
||||||
|
develop
|
||||||
|
cp node_modules/ace-builds/src/ -a resources/ace/ && webpack-dev-server --progress --colors
|
||||||
|
watch-test
|
||||||
|
jest --verbose --watch
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('no_memoize')
|
||||||
|
def test_get_scripts(mocker):
|
||||||
|
patch = mocker.patch('thefuck.specific.npm.Popen')
|
||||||
|
patch.return_value.stdout = BytesIO(run_script_stdout)
|
||||||
|
assert get_scripts() == ['build', 'develop', 'watch-test']
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import six
|
import six
|
||||||
|
import os
|
||||||
from mock import Mock
|
from mock import Mock
|
||||||
from thefuck import conf
|
from thefuck import const
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@@ -20,7 +21,7 @@ def environ(monkeypatch):
|
|||||||
def test_settings_defaults(load_source, settings):
|
def test_settings_defaults(load_source, settings):
|
||||||
load_source.return_value = object()
|
load_source.return_value = object()
|
||||||
settings.init()
|
settings.init()
|
||||||
for key, val in conf.DEFAULT_SETTINGS.items():
|
for key, val in const.DEFAULT_SETTINGS.items():
|
||||||
assert getattr(settings, key) == val
|
assert getattr(settings, key) == val
|
||||||
|
|
||||||
|
|
||||||
@@ -42,13 +43,13 @@ class TestSettingsFromFile(object):
|
|||||||
assert settings.exclude_rules == ['git']
|
assert settings.exclude_rules == ['git']
|
||||||
|
|
||||||
def test_from_file_with_DEFAULT(self, load_source, settings):
|
def test_from_file_with_DEFAULT(self, load_source, settings):
|
||||||
load_source.return_value = Mock(rules=conf.DEFAULT_RULES + ['test'],
|
load_source.return_value = Mock(rules=const.DEFAULT_RULES + ['test'],
|
||||||
wait_command=10,
|
wait_command=10,
|
||||||
exclude_rules=[],
|
exclude_rules=[],
|
||||||
require_confirmation=True,
|
require_confirmation=True,
|
||||||
no_colors=True)
|
no_colors=True)
|
||||||
settings.init()
|
settings.init()
|
||||||
assert settings.rules == conf.DEFAULT_RULES + ['test']
|
assert settings.rules == const.DEFAULT_RULES + ['test']
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixture('load_source')
|
@pytest.mark.usefixture('load_source')
|
||||||
@@ -59,7 +60,9 @@ class TestSettingsFromEnv(object):
|
|||||||
'THEFUCK_WAIT_COMMAND': '55',
|
'THEFUCK_WAIT_COMMAND': '55',
|
||||||
'THEFUCK_REQUIRE_CONFIRMATION': 'true',
|
'THEFUCK_REQUIRE_CONFIRMATION': 'true',
|
||||||
'THEFUCK_NO_COLORS': 'false',
|
'THEFUCK_NO_COLORS': 'false',
|
||||||
'THEFUCK_PRIORITY': 'bash=10:lisp=wrong:vim=15'})
|
'THEFUCK_PRIORITY': 'bash=10:lisp=wrong:vim=15',
|
||||||
|
'THEFUCK_WAIT_SLOW_COMMAND': '999',
|
||||||
|
'THEFUCK_SLOW_COMMANDS': 'lein:react-native:./gradlew'})
|
||||||
settings.init()
|
settings.init()
|
||||||
assert settings.rules == ['bash', 'lisp']
|
assert settings.rules == ['bash', 'lisp']
|
||||||
assert settings.exclude_rules == ['git', 'vim']
|
assert settings.exclude_rules == ['git', 'vim']
|
||||||
@@ -67,11 +70,13 @@ class TestSettingsFromEnv(object):
|
|||||||
assert settings.require_confirmation is True
|
assert settings.require_confirmation is True
|
||||||
assert settings.no_colors is False
|
assert settings.no_colors is False
|
||||||
assert settings.priority == {'bash': 10, 'vim': 15}
|
assert settings.priority == {'bash': 10, 'vim': 15}
|
||||||
|
assert settings.wait_slow_command == 999
|
||||||
|
assert settings.slow_commands == ['lein', 'react-native', './gradlew']
|
||||||
|
|
||||||
def test_from_env_with_DEFAULT(self, environ, settings):
|
def test_from_env_with_DEFAULT(self, environ, settings):
|
||||||
environ.update({'THEFUCK_RULES': 'DEFAULT_RULES:bash:lisp'})
|
environ.update({'THEFUCK_RULES': 'DEFAULT_RULES:bash:lisp'})
|
||||||
settings.init()
|
settings.init()
|
||||||
assert settings.rules == conf.DEFAULT_RULES + ['bash', 'lisp']
|
assert settings.rules == const.DEFAULT_RULES + ['bash', 'lisp']
|
||||||
|
|
||||||
|
|
||||||
class TestInitializeSettingsFile(object):
|
class TestInitializeSettingsFile(object):
|
||||||
@@ -93,7 +98,26 @@ class TestInitializeSettingsFile(object):
|
|||||||
settings_file_contents = settings_file.getvalue()
|
settings_file_contents = settings_file.getvalue()
|
||||||
assert settings_path_mock.is_file.call_count == 1
|
assert settings_path_mock.is_file.call_count == 1
|
||||||
assert settings_path_mock.open.call_count == 1
|
assert settings_path_mock.open.call_count == 1
|
||||||
assert conf.SETTINGS_HEADER in settings_file_contents
|
assert const.SETTINGS_HEADER in settings_file_contents
|
||||||
for setting in conf.DEFAULT_SETTINGS.items():
|
for setting in const.DEFAULT_SETTINGS.items():
|
||||||
assert '# {} = {}\n'.format(*setting) in settings_file_contents
|
assert '# {} = {}\n'.format(*setting) in settings_file_contents
|
||||||
settings_file.close()
|
settings_file.close()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('legacy_dir_exists, xdg_config_home, result', [
|
||||||
|
(False, '~/.config', '~/.config/thefuck'),
|
||||||
|
(False, '/user/test/config/', '/user/test/config/thefuck'),
|
||||||
|
(True, '~/.config', '~/.thefuck'),
|
||||||
|
(True, '/user/test/config/', '~/.thefuck')])
|
||||||
|
def test_get_user_dir_path(mocker, environ, settings, legacy_dir_exists,
|
||||||
|
xdg_config_home, result):
|
||||||
|
mocker.patch('thefuck.conf.Path.is_dir',
|
||||||
|
return_value=legacy_dir_exists)
|
||||||
|
|
||||||
|
if xdg_config_home is not None:
|
||||||
|
environ['XDG_CONFIG_HOME'] = xdg_config_home
|
||||||
|
else:
|
||||||
|
environ.pop('XDG_CONFIG_HOME', None)
|
||||||
|
|
||||||
|
path = settings._get_user_dir_path().as_posix()
|
||||||
|
assert path == os.path.expanduser(result)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from pathlib import PosixPath
|
from thefuck import corrector, const
|
||||||
from thefuck import corrector, conf
|
from thefuck.system import Path
|
||||||
from tests.utils import Rule, Command, CorrectedCommand
|
from tests.utils import Rule, Command, CorrectedCommand
|
||||||
from thefuck.corrector import get_corrected_commands, organize_commands
|
from thefuck.corrector import get_corrected_commands, organize_commands
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ class TestGetRules(object):
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def glob(self, mocker):
|
def glob(self, mocker):
|
||||||
results = {}
|
results = {}
|
||||||
mocker.patch('pathlib.Path.glob',
|
mocker.patch('thefuck.system.Path.glob',
|
||||||
new_callable=lambda: lambda *_: results.pop('value', []))
|
new_callable=lambda: lambda *_: results.pop('value', []))
|
||||||
return lambda value: results.update({'value': value})
|
return lambda value: results.update({'value': value})
|
||||||
|
|
||||||
@@ -24,13 +24,13 @@ class TestGetRules(object):
|
|||||||
assert {r.name for r in rules} == set(names)
|
assert {r.name for r in rules} == set(names)
|
||||||
|
|
||||||
@pytest.mark.parametrize('paths, conf_rules, exclude_rules, loaded_rules', [
|
@pytest.mark.parametrize('paths, conf_rules, exclude_rules, loaded_rules', [
|
||||||
(['git.py', 'bash.py'], conf.DEFAULT_RULES, [], ['git', 'bash']),
|
(['git.py', 'bash.py'], const.DEFAULT_RULES, [], ['git', 'bash']),
|
||||||
(['git.py', 'bash.py'], ['git'], [], ['git']),
|
(['git.py', 'bash.py'], ['git'], [], ['git']),
|
||||||
(['git.py', 'bash.py'], conf.DEFAULT_RULES, ['git'], ['bash']),
|
(['git.py', 'bash.py'], const.DEFAULT_RULES, ['git'], ['bash']),
|
||||||
(['git.py', 'bash.py'], ['git'], ['git'], [])])
|
(['git.py', 'bash.py'], ['git'], ['git'], [])])
|
||||||
def test_get_rules(self, glob, settings, paths, conf_rules, exclude_rules,
|
def test_get_rules(self, glob, settings, paths, conf_rules, exclude_rules,
|
||||||
loaded_rules):
|
loaded_rules):
|
||||||
glob([PosixPath(path) for path in paths])
|
glob([Path(path) for path in paths])
|
||||||
settings.update(rules=conf_rules,
|
settings.update(rules=conf_rules,
|
||||||
priority={},
|
priority={},
|
||||||
exclude_rules=exclude_rules)
|
exclude_rules=exclude_rules)
|
||||||
|
|||||||
@@ -1,260 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
from thefuck import shells
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def builtins_open(mocker):
|
|
||||||
return mocker.patch('six.moves.builtins.open')
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def isfile(mocker):
|
|
||||||
return mocker.patch('os.path.isfile', return_value=True)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
@pytest.mark.usefixtures('isfile')
|
|
||||||
def history_lines(mocker):
|
|
||||||
def aux(lines):
|
|
||||||
mock = mocker.patch('io.open')
|
|
||||||
mock.return_value.__enter__\
|
|
||||||
.return_value.readlines.return_value = lines
|
|
||||||
return aux
|
|
||||||
|
|
||||||
|
|
||||||
class TestGeneric(object):
|
|
||||||
@pytest.fixture
|
|
||||||
def shell(self):
|
|
||||||
return shells.Generic()
|
|
||||||
|
|
||||||
def test_from_shell(self, shell):
|
|
||||||
assert shell.from_shell('pwd') == 'pwd'
|
|
||||||
|
|
||||||
def test_to_shell(self, shell):
|
|
||||||
assert shell.to_shell('pwd') == 'pwd'
|
|
||||||
|
|
||||||
def test_put_to_history(self, builtins_open, shell):
|
|
||||||
assert shell.put_to_history('ls') is None
|
|
||||||
assert shell.put_to_history(u'echo café') is None
|
|
||||||
assert builtins_open.call_count == 0
|
|
||||||
|
|
||||||
def test_and_(self, shell):
|
|
||||||
assert shell.and_('ls', 'cd') == 'ls && cd'
|
|
||||||
|
|
||||||
def test_get_aliases(self, shell):
|
|
||||||
assert shell.get_aliases() == {}
|
|
||||||
|
|
||||||
def test_app_alias(self, shell):
|
|
||||||
assert 'alias fuck' in shell.app_alias('fuck')
|
|
||||||
assert 'alias FUCK' in shell.app_alias('FUCK')
|
|
||||||
assert 'thefuck' in shell.app_alias('fuck')
|
|
||||||
assert 'TF_ALIAS' in shell.app_alias('fuck')
|
|
||||||
assert 'PYTHONIOENCODING=utf-8' in shell.app_alias('fuck')
|
|
||||||
|
|
||||||
def test_get_history(self, history_lines, shell):
|
|
||||||
history_lines(['ls', 'rm'])
|
|
||||||
# We don't know what to do in generic shell with history lines,
|
|
||||||
# so just ignore them:
|
|
||||||
assert list(shell.get_history()) == []
|
|
||||||
|
|
||||||
def test_split_command(self, shell):
|
|
||||||
assert shell.split_command('ls') == ['ls']
|
|
||||||
assert shell.split_command(u'echo café') == [u'echo', u'café']
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures('isfile')
|
|
||||||
class TestBash(object):
|
|
||||||
@pytest.fixture
|
|
||||||
def shell(self):
|
|
||||||
return shells.Bash()
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
|
||||||
def Popen(self, mocker):
|
|
||||||
mock = mocker.patch('thefuck.shells.Popen')
|
|
||||||
mock.return_value.stdout.read.return_value = (
|
|
||||||
b'alias fuck=\'eval $(thefuck $(fc -ln -1))\'\n'
|
|
||||||
b'alias l=\'ls -CF\'\n'
|
|
||||||
b'alias la=\'ls -A\'\n'
|
|
||||||
b'alias ll=\'ls -alF\'')
|
|
||||||
return mock
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('before, after', [
|
|
||||||
('pwd', 'pwd'),
|
|
||||||
('fuck', 'eval $(thefuck $(fc -ln -1))'),
|
|
||||||
('awk', 'awk'),
|
|
||||||
('ll', 'ls -alF')])
|
|
||||||
def test_from_shell(self, before, after, shell):
|
|
||||||
assert shell.from_shell(before) == after
|
|
||||||
|
|
||||||
def test_to_shell(self, shell):
|
|
||||||
assert shell.to_shell('pwd') == 'pwd'
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('entry, entry_utf8', [
|
|
||||||
('ls', 'ls\n'),
|
|
||||||
(u'echo café', 'echo café\n')])
|
|
||||||
def test_put_to_history(self, entry, entry_utf8, builtins_open, shell):
|
|
||||||
shell.put_to_history(entry)
|
|
||||||
builtins_open.return_value.__enter__.return_value. \
|
|
||||||
write.assert_called_once_with(entry_utf8)
|
|
||||||
|
|
||||||
def test_and_(self, shell):
|
|
||||||
assert shell.and_('ls', 'cd') == 'ls && cd'
|
|
||||||
|
|
||||||
def test_get_aliases(self, shell):
|
|
||||||
assert shell.get_aliases() == {'fuck': 'eval $(thefuck $(fc -ln -1))',
|
|
||||||
'l': 'ls -CF',
|
|
||||||
'la': 'ls -A',
|
|
||||||
'll': 'ls -alF'}
|
|
||||||
|
|
||||||
def test_app_alias(self, shell):
|
|
||||||
assert 'alias fuck' in shell.app_alias('fuck')
|
|
||||||
assert 'alias FUCK' in shell.app_alias('FUCK')
|
|
||||||
assert 'thefuck' in shell.app_alias('fuck')
|
|
||||||
assert 'TF_ALIAS' in shell.app_alias('fuck')
|
|
||||||
assert 'PYTHONIOENCODING=utf-8' in shell.app_alias('fuck')
|
|
||||||
|
|
||||||
def test_get_history(self, history_lines, shell):
|
|
||||||
history_lines(['ls', 'rm'])
|
|
||||||
assert list(shell.get_history()) == ['ls', 'rm']
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures('isfile')
|
|
||||||
class TestFish(object):
|
|
||||||
@pytest.fixture
|
|
||||||
def shell(self):
|
|
||||||
return shells.Fish()
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
|
||||||
def Popen(self, mocker):
|
|
||||||
mock = mocker.patch('thefuck.shells.Popen')
|
|
||||||
mock.return_value.stdout.read.return_value = (
|
|
||||||
b'cd\nfish_config\nfuck\nfunced\nfuncsave\ngrep\nhistory\nll\nls\n'
|
|
||||||
b'man\nmath\npopd\npushd\nruby')
|
|
||||||
return mock
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def environ(self, monkeypatch):
|
|
||||||
data = {'TF_OVERRIDDEN_ALIASES': 'cd, ls, man, open'}
|
|
||||||
monkeypatch.setattr('thefuck.shells.os.environ', data)
|
|
||||||
return data
|
|
||||||
|
|
||||||
@pytest.mark.usefixture('environ')
|
|
||||||
def test_get_overridden_aliases(self, shell, environ):
|
|
||||||
assert shell._get_overridden_aliases() == ['cd', 'ls', 'man', 'open']
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('before, after', [
|
|
||||||
('cd', 'cd'),
|
|
||||||
('pwd', 'pwd'),
|
|
||||||
('fuck', 'fish -ic "fuck"'),
|
|
||||||
('find', 'find'),
|
|
||||||
('funced', 'fish -ic "funced"'),
|
|
||||||
('grep', 'grep'),
|
|
||||||
('awk', 'awk'),
|
|
||||||
('math "2 + 2"', r'fish -ic "math \"2 + 2\""'),
|
|
||||||
('man', 'man'),
|
|
||||||
('open', 'open'),
|
|
||||||
('vim', 'vim'),
|
|
||||||
('ll', 'fish -ic "ll"'),
|
|
||||||
('ls', 'ls')]) # Fish has no aliases but functions
|
|
||||||
def test_from_shell(self, before, after, shell):
|
|
||||||
assert shell.from_shell(before) == after
|
|
||||||
|
|
||||||
def test_to_shell(self, shell):
|
|
||||||
assert shell.to_shell('pwd') == 'pwd'
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('entry, entry_utf8', [
|
|
||||||
('ls', '- cmd: ls\n when: 1430707243\n'),
|
|
||||||
(u'echo café', '- cmd: echo café\n when: 1430707243\n')])
|
|
||||||
def test_put_to_history(self, entry, entry_utf8, builtins_open, mocker, shell):
|
|
||||||
mocker.patch('thefuck.shells.time',
|
|
||||||
return_value=1430707243.3517463)
|
|
||||||
shell.put_to_history(entry)
|
|
||||||
builtins_open.return_value.__enter__.return_value. \
|
|
||||||
write.assert_called_once_with(entry_utf8)
|
|
||||||
|
|
||||||
def test_and_(self, shell):
|
|
||||||
assert shell.and_('foo', 'bar') == 'foo; and bar'
|
|
||||||
|
|
||||||
def test_get_aliases(self, shell):
|
|
||||||
assert shell.get_aliases() == {'fish_config': 'fish_config',
|
|
||||||
'fuck': 'fuck',
|
|
||||||
'funced': 'funced',
|
|
||||||
'funcsave': 'funcsave',
|
|
||||||
'history': 'history',
|
|
||||||
'll': 'll',
|
|
||||||
'math': 'math',
|
|
||||||
'popd': 'popd',
|
|
||||||
'pushd': 'pushd',
|
|
||||||
'ruby': 'ruby'}
|
|
||||||
|
|
||||||
def test_app_alias(self, shell):
|
|
||||||
assert 'function fuck' in shell.app_alias('fuck')
|
|
||||||
assert 'function FUCK' in shell.app_alias('FUCK')
|
|
||||||
assert 'thefuck' in shell.app_alias('fuck')
|
|
||||||
assert 'TF_ALIAS' in shell.app_alias('fuck')
|
|
||||||
assert 'PYTHONIOENCODING=utf-8' in shell.app_alias('fuck')
|
|
||||||
|
|
||||||
def test_get_history(self, history_lines, shell):
|
|
||||||
history_lines(['- cmd: ls', ' when: 1432613911',
|
|
||||||
'- cmd: rm', ' when: 1432613916'])
|
|
||||||
assert list(shell.get_history()) == ['ls', 'rm']
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures('isfile')
|
|
||||||
class TestZsh(object):
|
|
||||||
@pytest.fixture
|
|
||||||
def shell(self):
|
|
||||||
return shells.Zsh()
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
|
||||||
def Popen(self, mocker):
|
|
||||||
mock = mocker.patch('thefuck.shells.Popen')
|
|
||||||
mock.return_value.stdout.read.return_value = (
|
|
||||||
b'fuck=\'eval $(thefuck $(fc -ln -1 | tail -n 1))\'\n'
|
|
||||||
b'l=\'ls -CF\'\n'
|
|
||||||
b'la=\'ls -A\'\n'
|
|
||||||
b'll=\'ls -alF\'')
|
|
||||||
return mock
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('before, after', [
|
|
||||||
('fuck', 'eval $(thefuck $(fc -ln -1 | tail -n 1))'),
|
|
||||||
('pwd', 'pwd'),
|
|
||||||
('ll', 'ls -alF')])
|
|
||||||
def test_from_shell(self, before, after, shell):
|
|
||||||
assert shell.from_shell(before) == after
|
|
||||||
|
|
||||||
def test_to_shell(self, shell):
|
|
||||||
assert shell.to_shell('pwd') == 'pwd'
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('entry, entry_utf8', [
|
|
||||||
('ls', ': 1430707243:0;ls\n'),
|
|
||||||
(u'echo café', ': 1430707243:0;echo café\n')])
|
|
||||||
def test_put_to_history(self, entry, entry_utf8, builtins_open, mocker, shell):
|
|
||||||
mocker.patch('thefuck.shells.time',
|
|
||||||
return_value=1430707243.3517463)
|
|
||||||
shell.put_to_history(entry)
|
|
||||||
builtins_open.return_value.__enter__.return_value. \
|
|
||||||
write.assert_called_once_with(entry_utf8)
|
|
||||||
|
|
||||||
def test_and_(self, shell):
|
|
||||||
assert shell.and_('ls', 'cd') == 'ls && cd'
|
|
||||||
|
|
||||||
def test_get_aliases(self, shell):
|
|
||||||
assert shell.get_aliases() == {
|
|
||||||
'fuck': 'eval $(thefuck $(fc -ln -1 | tail -n 1))',
|
|
||||||
'l': 'ls -CF',
|
|
||||||
'la': 'ls -A',
|
|
||||||
'll': 'ls -alF'}
|
|
||||||
|
|
||||||
def test_app_alias(self, shell):
|
|
||||||
assert 'alias fuck' in shell.app_alias('fuck')
|
|
||||||
assert 'alias FUCK' in shell.app_alias('FUCK')
|
|
||||||
assert 'thefuck' in shell.app_alias('fuck')
|
|
||||||
assert 'TF_ALIAS' in shell.app_alias('fuck')
|
|
||||||
assert 'PYTHONIOENCODING=utf-8' in shell.app_alias('fuck')
|
|
||||||
|
|
||||||
def test_get_history(self, history_lines, shell):
|
|
||||||
history_lines([': 1432613911:0;ls', ': 1432613916:0;rm'])
|
|
||||||
assert list(shell.get_history()) == ['ls', 'rm']
|
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
from subprocess import PIPE
|
from subprocess import PIPE
|
||||||
from mock import Mock
|
from mock import Mock
|
||||||
from pathlib import Path
|
|
||||||
import pytest
|
import pytest
|
||||||
from tests.utils import CorrectedCommand, Rule, Command
|
from tests.utils import CorrectedCommand, Rule, Command
|
||||||
from thefuck import conf
|
from thefuck import const
|
||||||
from thefuck.exceptions import EmptyCommand
|
from thefuck.exceptions import EmptyCommand
|
||||||
|
from thefuck.system import Path
|
||||||
|
|
||||||
|
|
||||||
class TestCorrectedCommand(object):
|
class TestCorrectedCommand(object):
|
||||||
@@ -39,19 +40,20 @@ class TestRule(object):
|
|||||||
enabled_by_default=True,
|
enabled_by_default=True,
|
||||||
priority=900,
|
priority=900,
|
||||||
requires_output=True))
|
requires_output=True))
|
||||||
assert Rule.from_path(Path('/rules/bash.py')) \
|
rule_path = os.path.join(os.sep, 'rules', 'bash.py')
|
||||||
|
assert Rule.from_path(Path(rule_path)) \
|
||||||
== Rule('bash', match, get_new_command, priority=900)
|
== Rule('bash', match, get_new_command, priority=900)
|
||||||
load_source.assert_called_once_with('bash', '/rules/bash.py')
|
load_source.assert_called_once_with('bash', rule_path)
|
||||||
|
|
||||||
@pytest.mark.parametrize('rules, exclude_rules, rule, is_enabled', [
|
@pytest.mark.parametrize('rules, exclude_rules, rule, is_enabled', [
|
||||||
(conf.DEFAULT_RULES, [], Rule('git', enabled_by_default=True), True),
|
(const.DEFAULT_RULES, [], Rule('git', enabled_by_default=True), True),
|
||||||
(conf.DEFAULT_RULES, [], Rule('git', enabled_by_default=False), False),
|
(const.DEFAULT_RULES, [], Rule('git', enabled_by_default=False), False),
|
||||||
([], [], Rule('git', enabled_by_default=False), False),
|
([], [], Rule('git', enabled_by_default=False), False),
|
||||||
([], [], Rule('git', enabled_by_default=True), False),
|
([], [], Rule('git', enabled_by_default=True), False),
|
||||||
(conf.DEFAULT_RULES + ['git'], [], Rule('git', enabled_by_default=False), True),
|
(const.DEFAULT_RULES + ['git'], [], Rule('git', enabled_by_default=False), True),
|
||||||
(['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),
|
(const.DEFAULT_RULES, ['git'], Rule('git', enabled_by_default=True), False),
|
||||||
(conf.DEFAULT_RULES, ['git'], Rule('git', enabled_by_default=False), False),
|
(const.DEFAULT_RULES, ['git'], Rule('git', enabled_by_default=False), False),
|
||||||
([], ['git'], Rule('git', enabled_by_default=True), False),
|
([], ['git'], Rule('git', enabled_by_default=True), False),
|
||||||
([], ['git'], Rule('git', enabled_by_default=False), False)])
|
([], ['git'], Rule('git', enabled_by_default=False), False)])
|
||||||
def test_is_enabled(self, settings, rules, exclude_rules, rule, is_enabled):
|
def test_is_enabled(self, settings, rules, exclude_rules, rule, is_enabled):
|
||||||
@@ -103,11 +105,6 @@ class TestCommand(object):
|
|||||||
monkeypatch.setattr('thefuck.types.Command._wait_output',
|
monkeypatch.setattr('thefuck.types.Command._wait_output',
|
||||||
staticmethod(lambda *_: True))
|
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):
|
def test_from_script_calls(self, Popen, settings):
|
||||||
settings.env = {}
|
settings.env = {}
|
||||||
assert Command.from_raw_script(
|
assert Command.from_raw_script(
|
||||||
@@ -115,6 +112,7 @@ class TestCommand(object):
|
|||||||
'apt-get search vim', 'stdout', 'stderr')
|
'apt-get search vim', 'stdout', 'stderr')
|
||||||
Popen.assert_called_once_with('apt-get search vim',
|
Popen.assert_called_once_with('apt-get search vim',
|
||||||
shell=True,
|
shell=True,
|
||||||
|
stdin=PIPE,
|
||||||
stdout=PIPE,
|
stdout=PIPE,
|
||||||
stderr=PIPE,
|
stderr=PIPE,
|
||||||
env={})
|
env={})
|
||||||
|
|||||||
@@ -25,13 +25,16 @@ def test_read_actions(patch_get_key):
|
|||||||
# Ignored:
|
# Ignored:
|
||||||
'x', 'y',
|
'x', 'y',
|
||||||
# Up:
|
# Up:
|
||||||
const.KEY_UP,
|
const.KEY_UP, 'k',
|
||||||
# Down:
|
# Down:
|
||||||
const.KEY_DOWN,
|
const.KEY_DOWN, 'j',
|
||||||
# Ctrl+C:
|
# Ctrl+C:
|
||||||
const.KEY_CTRL_C])
|
const.KEY_CTRL_C, 'q'])
|
||||||
assert list(islice(ui.read_actions(), 5)) \
|
assert list(islice(ui.read_actions(), 8)) \
|
||||||
== [ui.SELECT, ui.SELECT, ui.PREVIOUS, ui.NEXT, ui.ABORT]
|
== [const.ACTION_SELECT, const.ACTION_SELECT,
|
||||||
|
const.ACTION_PREVIOUS, const.ACTION_PREVIOUS,
|
||||||
|
const.ACTION_NEXT, const.ACTION_NEXT,
|
||||||
|
const.ACTION_ABORT, const.ACTION_ABORT]
|
||||||
|
|
||||||
|
|
||||||
def test_command_selector():
|
def test_command_selector():
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
import warnings
|
||||||
from mock import Mock
|
from mock import Mock
|
||||||
import six
|
import six
|
||||||
from thefuck.utils import default_settings, \
|
from thefuck.utils import default_settings, \
|
||||||
memoize, get_closest, get_all_executables, replace_argument, \
|
memoize, get_closest, get_all_executables, replace_argument, \
|
||||||
get_all_matched_commands, is_app, for_app, cache, compatibility_call
|
get_all_matched_commands, is_app, for_app, cache, \
|
||||||
|
get_valid_history_without_current
|
||||||
from tests.utils import Command
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
@@ -50,7 +54,7 @@ class TestGetClosest(object):
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def get_aliases(mocker):
|
def get_aliases(mocker):
|
||||||
mocker.patch('thefuck.shells.get_aliases',
|
mocker.patch('thefuck.shells.shell.get_aliases',
|
||||||
return_value=['vim', 'apt-get', 'fsck', 'fuck'])
|
return_value=['vim', 'apt-get', 'fsck', 'fuck'])
|
||||||
|
|
||||||
|
|
||||||
@@ -162,10 +166,10 @@ class TestCache(object):
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def key(self):
|
def key(self):
|
||||||
if six.PY3:
|
if six.PY2:
|
||||||
return 'tests.test_utils.<function TestCache.fn.<locals>.fn '
|
|
||||||
else:
|
|
||||||
return 'tests.test_utils.<function fn '
|
return 'tests.test_utils.<function fn '
|
||||||
|
else:
|
||||||
|
return 'tests.test_utils.<function TestCache.fn.<locals>.fn '
|
||||||
|
|
||||||
def test_with_blank_cache(self, shelve, fn, key):
|
def test_with_blank_cache(self, shelve, fn, key):
|
||||||
assert shelve == {}
|
assert shelve == {}
|
||||||
@@ -184,48 +188,41 @@ class TestCache(object):
|
|||||||
assert shelve == {key: {'etag': '0', 'value': 'test'}}
|
assert shelve == {key: {'etag': '0', 'value': 'test'}}
|
||||||
|
|
||||||
|
|
||||||
class TestCompatibilityCall(object):
|
class TestGetValidHistoryWithoutCurrent(object):
|
||||||
def test_match(self):
|
@pytest.yield_fixture(autouse=True)
|
||||||
def match(command):
|
def fail_on_warning(self):
|
||||||
assert command == Command()
|
warnings.simplefilter('error')
|
||||||
return True
|
yield
|
||||||
|
warnings.resetwarnings()
|
||||||
|
|
||||||
assert compatibility_call(match, Command())
|
@pytest.fixture(autouse=True)
|
||||||
|
def history(self, mocker):
|
||||||
|
return mocker.patch('thefuck.shells.shell.get_history',
|
||||||
|
return_value=['le cat', 'fuck', 'ls cat',
|
||||||
|
'diff x', 'nocommand x', u'café ô'])
|
||||||
|
|
||||||
def test_old_match(self, settings):
|
@pytest.fixture(autouse=True)
|
||||||
def match(command, _settings):
|
def alias(self, mocker):
|
||||||
assert command == Command()
|
return mocker.patch('thefuck.utils.get_alias',
|
||||||
assert settings == _settings
|
return_value='fuck')
|
||||||
return True
|
|
||||||
|
|
||||||
assert compatibility_call(match, Command())
|
@pytest.fixture(autouse=True)
|
||||||
|
def bins(self, mocker, monkeypatch):
|
||||||
|
monkeypatch.setattr('thefuck.conf.os.environ', {'PATH': 'path'})
|
||||||
|
callables = list()
|
||||||
|
for name in ['diff', 'ls', 'café']:
|
||||||
|
bin_mock = mocker.Mock(name=name)
|
||||||
|
bin_mock.configure_mock(name=name, is_dir=lambda: False)
|
||||||
|
callables.append(bin_mock)
|
||||||
|
path_mock = mocker.Mock(iterdir=mocker.Mock(return_value=callables))
|
||||||
|
return mocker.patch('thefuck.utils.Path', return_value=path_mock)
|
||||||
|
|
||||||
def test_get_new_command(self):
|
@pytest.mark.parametrize('script, result', [
|
||||||
def get_new_command(command):
|
('le cat', ['ls cat', 'diff x', u'café ô']),
|
||||||
assert command == Command()
|
('diff x', ['ls cat', u'café ô']),
|
||||||
return True
|
('fuck', ['ls cat', 'diff x', u'café ô']),
|
||||||
|
(u'cafe ô', ['ls cat', 'diff x', u'café ô']),
|
||||||
assert compatibility_call(get_new_command, Command())
|
])
|
||||||
|
def test_get_valid_history_without_current(self, script, result):
|
||||||
def test_old_get_new_command(self, settings):
|
command = Command(script=script)
|
||||||
def get_new_command(command, _settings):
|
assert get_valid_history_without_current(command) == result
|
||||||
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())
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from thefuck import types
|
from thefuck import types
|
||||||
from thefuck.conf import DEFAULT_PRIORITY
|
from thefuck.const import DEFAULT_PRIORITY
|
||||||
|
|
||||||
|
|
||||||
class Command(types.Command):
|
class Command(types.Command):
|
||||||
|
|||||||
@@ -1,46 +1,10 @@
|
|||||||
from imp import load_source
|
from imp import load_source
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from warnings import warn
|
||||||
from six import text_type
|
from six import text_type
|
||||||
|
from . import const
|
||||||
|
from .system import Path
|
||||||
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,
|
|
||||||
'debug': False,
|
|
||||||
'priority': {},
|
|
||||||
'history_limit': None,
|
|
||||||
'alter_history': True,
|
|
||||||
'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_DEBUG': 'debug',
|
|
||||||
'THEFUCK_PRIORITY': 'priority',
|
|
||||||
'THEFUCK_HISTORY_LIMIT': 'history_limit',
|
|
||||||
'THEFUCK_ALTER_HISTORY': 'alter_history'}
|
|
||||||
|
|
||||||
SETTINGS_HEADER = u"""# The Fuck settings file
|
|
||||||
#
|
|
||||||
# The rules are defined as in the example bellow:
|
|
||||||
#
|
|
||||||
# rules = ['cd_parent', 'git_push', 'python_command', 'sudo']
|
|
||||||
#
|
|
||||||
# The default values are as follows. Uncomment and change to fit your needs.
|
|
||||||
# See https://github.com/nvbn/thefuck#settings for more information.
|
|
||||||
#
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class Settings(dict):
|
class Settings(dict):
|
||||||
@@ -71,20 +35,23 @@ class Settings(dict):
|
|||||||
settings_path = self.user_dir.joinpath('settings.py')
|
settings_path = self.user_dir.joinpath('settings.py')
|
||||||
if not settings_path.is_file():
|
if not settings_path.is_file():
|
||||||
with settings_path.open(mode='w') as settings_file:
|
with settings_path.open(mode='w') as settings_file:
|
||||||
settings_file.write(SETTINGS_HEADER)
|
settings_file.write(const.SETTINGS_HEADER)
|
||||||
for setting in DEFAULT_SETTINGS.items():
|
for setting in const.DEFAULT_SETTINGS.items():
|
||||||
settings_file.write(u'# {} = {}\n'.format(*setting))
|
settings_file.write(u'# {} = {}\n'.format(*setting))
|
||||||
|
|
||||||
def _get_user_dir_path(self):
|
def _get_user_dir_path(self):
|
||||||
# for backward compatibility, use `~/.thefuck` if it exists
|
"""Returns Path object representing the user config resource"""
|
||||||
legacy_user_dir = Path(os.path.expanduser('~/.thefuck'))
|
xdg_config_home = os.environ.get('XDG_CONFIG_HOME', '~/.config')
|
||||||
|
user_dir = Path(xdg_config_home, 'thefuck').expanduser()
|
||||||
|
legacy_user_dir = Path('~', '.thefuck').expanduser()
|
||||||
|
|
||||||
|
# For backward compatibility use legacy '~/.thefuck' if it exists:
|
||||||
if legacy_user_dir.is_dir():
|
if legacy_user_dir.is_dir():
|
||||||
|
warn(u'Config path {} is deprecated. Please move to {}'.format(
|
||||||
|
legacy_user_dir, user_dir))
|
||||||
return legacy_user_dir
|
return legacy_user_dir
|
||||||
else:
|
else:
|
||||||
default_xdg_config_dir = os.path.expanduser("~/.config")
|
return user_dir
|
||||||
xdg_config_dir = os.getenv("XDG_CONFIG_HOME", default_xdg_config_dir)
|
|
||||||
return Path(os.path.join(xdg_config_dir, 'thefuck'))
|
|
||||||
|
|
||||||
def _setup_user_dir(self):
|
def _setup_user_dir(self):
|
||||||
"""Returns user config dir, create it when it doesn't exist."""
|
"""Returns user config dir, create it when it doesn't exist."""
|
||||||
@@ -100,14 +67,14 @@ class Settings(dict):
|
|||||||
settings = load_source(
|
settings = load_source(
|
||||||
'settings', text_type(self.user_dir.joinpath('settings.py')))
|
'settings', text_type(self.user_dir.joinpath('settings.py')))
|
||||||
return {key: getattr(settings, key)
|
return {key: getattr(settings, key)
|
||||||
for key in DEFAULT_SETTINGS.keys()
|
for key in const.DEFAULT_SETTINGS.keys()
|
||||||
if hasattr(settings, key)}
|
if hasattr(settings, key)}
|
||||||
|
|
||||||
def _rules_from_env(self, val):
|
def _rules_from_env(self, val):
|
||||||
"""Transforms rules list from env-string to python."""
|
"""Transforms rules list from env-string to python."""
|
||||||
val = val.split(':')
|
val = val.split(':')
|
||||||
if 'DEFAULT_RULES' in val:
|
if 'DEFAULT_RULES' in val:
|
||||||
val = DEFAULT_RULES + [rule for rule in val if rule != 'DEFAULT_RULES']
|
val = const.DEFAULT_RULES + [rule for rule in val if rule != 'DEFAULT_RULES']
|
||||||
return val
|
return val
|
||||||
|
|
||||||
def _priority_from_env(self, val):
|
def _priority_from_env(self, val):
|
||||||
@@ -126,21 +93,21 @@ class Settings(dict):
|
|||||||
return self._rules_from_env(val)
|
return self._rules_from_env(val)
|
||||||
elif attr == 'priority':
|
elif attr == 'priority':
|
||||||
return dict(self._priority_from_env(val))
|
return dict(self._priority_from_env(val))
|
||||||
elif attr == 'wait_command':
|
elif attr in ('wait_command', 'history_limit', 'wait_slow_command'):
|
||||||
return int(val)
|
return int(val)
|
||||||
elif attr in ('require_confirmation', 'no_colors', 'debug',
|
elif attr in ('require_confirmation', 'no_colors', 'debug',
|
||||||
'alter_history'):
|
'alter_history'):
|
||||||
return val.lower() == 'true'
|
return val.lower() == 'true'
|
||||||
elif attr == 'history_limit':
|
elif attr == 'slow_commands':
|
||||||
return int(val)
|
return val.split(':')
|
||||||
else:
|
else:
|
||||||
return val
|
return val
|
||||||
|
|
||||||
def _settings_from_env(self):
|
def _settings_from_env(self):
|
||||||
"""Loads settings from env."""
|
"""Loads settings from env."""
|
||||||
return {attr: self._val_from_env(env, attr)
|
return {attr: self._val_from_env(env, attr)
|
||||||
for env, attr in ENV_TO_ATTR.items()
|
for env, attr in const.ENV_TO_ATTR.items()
|
||||||
if env in os.environ}
|
if env in os.environ}
|
||||||
|
|
||||||
|
|
||||||
settings = Settings(DEFAULT_SETTINGS)
|
settings = Settings(const.DEFAULT_SETTINGS)
|
||||||
|
|||||||
@@ -12,3 +12,50 @@ class _GenConst(object):
|
|||||||
KEY_UP = _GenConst('↑')
|
KEY_UP = _GenConst('↑')
|
||||||
KEY_DOWN = _GenConst('↓')
|
KEY_DOWN = _GenConst('↓')
|
||||||
KEY_CTRL_C = _GenConst('Ctrl+C')
|
KEY_CTRL_C = _GenConst('Ctrl+C')
|
||||||
|
|
||||||
|
ACTION_SELECT = _GenConst('select')
|
||||||
|
ACTION_ABORT = _GenConst('abort')
|
||||||
|
ACTION_PREVIOUS = _GenConst('previous')
|
||||||
|
ACTION_NEXT = _GenConst('next')
|
||||||
|
|
||||||
|
ALL_ENABLED = _GenConst('All rules enabled')
|
||||||
|
DEFAULT_RULES = [ALL_ENABLED]
|
||||||
|
DEFAULT_PRIORITY = 1000
|
||||||
|
|
||||||
|
DEFAULT_SETTINGS = {'rules': DEFAULT_RULES,
|
||||||
|
'exclude_rules': [],
|
||||||
|
'wait_command': 3,
|
||||||
|
'require_confirmation': True,
|
||||||
|
'no_colors': False,
|
||||||
|
'debug': False,
|
||||||
|
'priority': {},
|
||||||
|
'history_limit': None,
|
||||||
|
'alter_history': True,
|
||||||
|
'wait_slow_command': 15,
|
||||||
|
'slow_commands': ['lein', 'react-native', 'gradle',
|
||||||
|
'./gradlew'],
|
||||||
|
'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_DEBUG': 'debug',
|
||||||
|
'THEFUCK_PRIORITY': 'priority',
|
||||||
|
'THEFUCK_HISTORY_LIMIT': 'history_limit',
|
||||||
|
'THEFUCK_ALTER_HISTORY': 'alter_history',
|
||||||
|
'THEFUCK_WAIT_SLOW_COMMAND': 'wait_slow_command',
|
||||||
|
'THEFUCK_SLOW_COMMANDS': 'slow_commands'}
|
||||||
|
|
||||||
|
SETTINGS_HEADER = u"""# The Fuck settings file
|
||||||
|
#
|
||||||
|
# The rules are defined as in the example bellow:
|
||||||
|
#
|
||||||
|
# rules = ['cd_parent', 'git_push', 'python_command', 'sudo']
|
||||||
|
#
|
||||||
|
# The default values are as follows. Uncomment and change to fit your needs.
|
||||||
|
# See https://github.com/nvbn/thefuck#settings for more information.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from pathlib import Path
|
|
||||||
from .conf import settings
|
from .conf import settings
|
||||||
from .types import Rule
|
from .types import Rule
|
||||||
|
from .system import Path
|
||||||
from . import logs
|
from . import logs
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ from .system import init_output
|
|||||||
init_output()
|
init_output()
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from warnings import warn
|
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
import sys
|
import sys
|
||||||
from . import logs, types, shells
|
from . import logs, types
|
||||||
|
from .shells import shell
|
||||||
from .conf import settings
|
from .conf import settings
|
||||||
from .corrector import get_corrected_commands
|
from .corrector import get_corrected_commands
|
||||||
from .exceptions import EmptyCommand
|
from .exceptions import EmptyCommand
|
||||||
from .utils import get_installation_info
|
from .utils import get_installation_info, get_alias
|
||||||
from .ui import select_command
|
from .ui import select_command
|
||||||
|
|
||||||
|
|
||||||
@@ -32,20 +32,18 @@ def fix_command():
|
|||||||
|
|
||||||
if selected_command:
|
if selected_command:
|
||||||
selected_command.run(command)
|
selected_command.run(command)
|
||||||
|
else:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def print_alias(entry_point=True):
|
def print_alias():
|
||||||
"""Prints alias for current shell."""
|
"""Prints alias for current shell."""
|
||||||
if entry_point:
|
try:
|
||||||
warn('`thefuck-alias` is deprecated, use `thefuck --alias` instead.')
|
alias = sys.argv[2]
|
||||||
position = 1
|
except IndexError:
|
||||||
else:
|
alias = get_alias()
|
||||||
position = 2
|
|
||||||
|
|
||||||
alias = shells.thefuck_alias()
|
print(shell.app_alias(alias))
|
||||||
if len(sys.argv) > position:
|
|
||||||
alias = sys.argv[position]
|
|
||||||
print(shells.app_alias(alias))
|
|
||||||
|
|
||||||
|
|
||||||
def how_to_configure_alias():
|
def how_to_configure_alias():
|
||||||
@@ -55,17 +53,17 @@ def how_to_configure_alias():
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
settings.init()
|
settings.init()
|
||||||
logs.how_to_configure_alias(shells.how_to_configure())
|
logs.how_to_configure_alias(shell.how_to_configure())
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = ArgumentParser(prog='thefuck')
|
parser = ArgumentParser(prog='thefuck')
|
||||||
version = get_installation_info().version
|
version = get_installation_info().version
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-v', '--version',
|
'-v', '--version',
|
||||||
action='version',
|
action='version',
|
||||||
version='The Fuck {} using Python {}'.format(
|
version='The Fuck {} using Python {}'.format(
|
||||||
version, sys.version.split()[0]))
|
version, sys.version.split()[0]))
|
||||||
parser.add_argument('-a', '--alias',
|
parser.add_argument('-a', '--alias',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help='[custom-alias-name] prints alias for current shell')
|
help='[custom-alias-name] prints alias for current shell')
|
||||||
@@ -73,8 +71,9 @@ def main():
|
|||||||
nargs='*',
|
nargs='*',
|
||||||
help='command that should be fixed')
|
help='command that should be fixed')
|
||||||
known_args = parser.parse_args(sys.argv[1:2])
|
known_args = parser.parse_args(sys.argv[1:2])
|
||||||
|
|
||||||
if known_args.alias:
|
if known_args.alias:
|
||||||
print_alias(False)
|
print_alias()
|
||||||
elif known_args.command:
|
elif known_args.command:
|
||||||
fix_command()
|
fix_command()
|
||||||
else:
|
else:
|
||||||
|
|||||||
10
thefuck/rules/ag_literal.py
Normal file
10
thefuck/rules/ag_literal.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from thefuck.utils import for_app
|
||||||
|
|
||||||
|
|
||||||
|
@for_app('ag')
|
||||||
|
def match(command):
|
||||||
|
return command.stderr.endswith('run ag with -Q\n')
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command):
|
||||||
|
return command.script.replace('ag', 'ag -Q', 1)
|
||||||
@@ -1,30 +1,43 @@
|
|||||||
from thefuck import shells
|
from thefuck.specific.apt import apt_available
|
||||||
from thefuck.utils import memoize
|
from thefuck.utils import memoize, which
|
||||||
|
from thefuck.shells import shell
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import CommandNotFound
|
from CommandNotFound import CommandNotFound
|
||||||
|
|
||||||
|
command_not_found = CommandNotFound()
|
||||||
|
enabled_by_default = apt_available
|
||||||
except ImportError:
|
except ImportError:
|
||||||
enabled_by_default = False
|
enabled_by_default = False
|
||||||
|
|
||||||
|
|
||||||
|
def _get_executable(command):
|
||||||
|
if command.script_parts[0] == 'sudo':
|
||||||
|
return command.script_parts[1]
|
||||||
|
else:
|
||||||
|
return command.script_parts[0]
|
||||||
|
|
||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
def get_package(command):
|
def get_package(executable):
|
||||||
try:
|
try:
|
||||||
c = CommandNotFound.CommandNotFound()
|
packages = command_not_found.getPackages(executable)
|
||||||
cmd = command.split(' ')
|
return packages[0][0]
|
||||||
pkgs = c.getPackages(cmd[0] if cmd[0] != 'sudo' else cmd[1])
|
|
||||||
name, _ = pkgs[0]
|
|
||||||
return name
|
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# IndexError is thrown when no matching package is found
|
# IndexError is thrown when no matching package is found
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def match(command):
|
def match(command):
|
||||||
return 'not found' in command.stderr and get_package(command.script)
|
if 'not found' in command.stderr:
|
||||||
|
executable = _get_executable(command)
|
||||||
|
return not which(executable) and get_package(executable)
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_new_command(command):
|
def get_new_command(command):
|
||||||
name = get_package(command.script)
|
executable = _get_executable(command)
|
||||||
formatme = shells.and_('sudo apt-get install {}', '{}')
|
name = get_package(executable)
|
||||||
|
formatme = shell.and_('sudo apt-get install {}', '{}')
|
||||||
return formatme.format(name, command.script)
|
return formatme.format(name, command.script)
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import re
|
import re
|
||||||
|
from thefuck.specific.apt import apt_available
|
||||||
from thefuck.utils import for_app
|
from thefuck.utils import for_app
|
||||||
|
|
||||||
|
enabled_by_default = apt_available
|
||||||
|
|
||||||
|
|
||||||
@for_app('apt-get')
|
@for_app('apt-get')
|
||||||
def match(command):
|
def match(command):
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
from thefuck.specific.apt import apt_available
|
||||||
from thefuck.specific.sudo import sudo_support
|
from thefuck.specific.sudo import sudo_support
|
||||||
from thefuck.utils import for_app, eager, replace_command
|
from thefuck.utils import for_app, eager, replace_command
|
||||||
|
|
||||||
|
enabled_by_default = apt_available
|
||||||
|
|
||||||
|
|
||||||
@for_app('apt', 'apt-get', 'apt-cache')
|
@for_app('apt', 'apt-get', 'apt-cache')
|
||||||
@sudo_support
|
@sudo_support
|
||||||
|
|||||||
17
thefuck/rules/aws_cli.py
Normal file
17
thefuck/rules/aws_cli.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
from thefuck.utils import for_app, replace_argument
|
||||||
|
|
||||||
|
INVALID_CHOICE = "(?<=Invalid choice: ')(.*)(?=', maybe you meant:)"
|
||||||
|
OPTIONS = "^\s*\*\s(.*)"
|
||||||
|
|
||||||
|
|
||||||
|
@for_app('aws')
|
||||||
|
def match(command):
|
||||||
|
return "usage:" in command.stderr and "maybe you meant:" in command.stderr
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command):
|
||||||
|
mistake = re.search(INVALID_CHOICE, command.stderr).group(0)
|
||||||
|
options = re.findall(OPTIONS, command.stderr, flags=re.MULTILINE)
|
||||||
|
return [replace_argument(command.script, mistake, o) for o in options]
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from thefuck.utils import get_closest, replace_argument, which
|
from thefuck.utils import get_closest, replace_argument
|
||||||
from thefuck.specific.brew import get_brew_path_prefix
|
from thefuck.specific.brew import get_brew_path_prefix, brew_available
|
||||||
|
|
||||||
|
enabled_by_default = brew_available
|
||||||
enabled_by_default = bool(which('brew'))
|
|
||||||
|
|
||||||
|
|
||||||
def _get_formulas():
|
def _get_formulas():
|
||||||
|
|||||||
15
thefuck/rules/brew_link.py
Normal file
15
thefuck/rules/brew_link.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
from thefuck.utils import for_app
|
||||||
|
|
||||||
|
|
||||||
|
@for_app('brew', at_least=2)
|
||||||
|
def match(command):
|
||||||
|
return (command.script_parts[1] in ['ln', 'link']
|
||||||
|
and "brew link --overwrite --dry-run" in command.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command):
|
||||||
|
command_parts = command.script_parts[:]
|
||||||
|
command_parts[1] = 'link'
|
||||||
|
command_parts.insert(2, '--overwrite')
|
||||||
|
command_parts.insert(3, '--dry-run')
|
||||||
|
return ' '.join(command_parts)
|
||||||
14
thefuck/rules/brew_uninstall.py
Normal file
14
thefuck/rules/brew_uninstall.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
from thefuck.utils import for_app
|
||||||
|
|
||||||
|
|
||||||
|
@for_app('brew', at_least=2)
|
||||||
|
def match(command):
|
||||||
|
return (command.script_parts[1] in ['uninstall', 'rm', 'remove']
|
||||||
|
and "brew uninstall --force" in command.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command):
|
||||||
|
command_parts = command.script_parts[:]
|
||||||
|
command_parts[1] = 'uninstall'
|
||||||
|
command_parts.insert(2, '--force')
|
||||||
|
return ' '.join(command_parts)
|
||||||
@@ -1,19 +1,21 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from thefuck.utils import get_closest, replace_command
|
from thefuck.utils import get_closest, replace_command
|
||||||
from thefuck.specific.brew import get_brew_path_prefix
|
from thefuck.specific.brew import get_brew_path_prefix, brew_available
|
||||||
|
|
||||||
BREW_CMD_PATH = '/Library/Homebrew/cmd'
|
BREW_CMD_PATH = '/Library/Homebrew/cmd'
|
||||||
TAP_PATH = '/Library/Taps'
|
TAP_PATH = '/Library/Taps'
|
||||||
TAP_CMD_PATH = '/%s/%s/cmd'
|
TAP_CMD_PATH = '/%s/%s/cmd'
|
||||||
|
|
||||||
|
enabled_by_default = brew_available
|
||||||
|
|
||||||
|
|
||||||
def _get_brew_commands(brew_path_prefix):
|
def _get_brew_commands(brew_path_prefix):
|
||||||
"""To get brew default commands on local environment"""
|
"""To get brew default commands on local environment"""
|
||||||
brew_cmd_path = brew_path_prefix + BREW_CMD_PATH
|
brew_cmd_path = brew_path_prefix + BREW_CMD_PATH
|
||||||
|
|
||||||
return [name[:-3] for name in os.listdir(brew_cmd_path)
|
return [name[:-3] for name in os.listdir(brew_cmd_path)
|
||||||
if name.endswith('.rb')]
|
if name.endswith(('.rb', '.sh'))]
|
||||||
|
|
||||||
|
|
||||||
def _get_brew_tap_specific_commands(brew_path_prefix):
|
def _get_brew_tap_specific_commands(brew_path_prefix):
|
||||||
@@ -53,7 +55,7 @@ def _brew_commands():
|
|||||||
if brew_path_prefix:
|
if brew_path_prefix:
|
||||||
try:
|
try:
|
||||||
return _get_brew_commands(brew_path_prefix) \
|
return _get_brew_commands(brew_path_prefix) \
|
||||||
+ _get_brew_tap_specific_commands(brew_path_prefix)
|
+ _get_brew_tap_specific_commands(brew_path_prefix)
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
12
thefuck/rules/brew_update_formula.py
Normal file
12
thefuck/rules/brew_update_formula.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from thefuck.utils import for_app
|
||||||
|
|
||||||
|
|
||||||
|
@for_app('brew', at_least=2)
|
||||||
|
def match(command):
|
||||||
|
return ('update' in command.script
|
||||||
|
and "Error: This command updates brew itself" in command.stderr
|
||||||
|
and "Use 'brew upgrade <formula>'" in command.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command):
|
||||||
|
return command.script.replace('update', 'upgrade')
|
||||||
@@ -4,6 +4,9 @@
|
|||||||
# > brew upgrade
|
# > brew upgrade
|
||||||
# Warning: brew upgrade with no arguments will change behaviour soon!
|
# Warning: brew upgrade with no arguments will change behaviour soon!
|
||||||
# It currently upgrades all formula but this will soon change to require '--all'.
|
# It currently upgrades all formula but this will soon change to require '--all'.
|
||||||
|
from thefuck.specific.brew import brew_available
|
||||||
|
|
||||||
|
enabled_by_default = brew_available
|
||||||
|
|
||||||
|
|
||||||
def match(command):
|
def match(command):
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from thefuck.utils import replace_argument, for_app
|
|||||||
|
|
||||||
@for_app('cargo', at_least=1)
|
@for_app('cargo', at_least=1)
|
||||||
def match(command):
|
def match(command):
|
||||||
return ('No such subcommand' in command.stderr
|
return ('no such subcommand' in command.stderr.lower()
|
||||||
and 'Did you mean' in command.stderr)
|
and 'Did you mean' in command.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import re
|
import re
|
||||||
from thefuck import shells
|
|
||||||
from thefuck.utils import for_app
|
from thefuck.utils import for_app
|
||||||
from thefuck.specific.sudo import sudo_support
|
from thefuck.specific.sudo import sudo_support
|
||||||
|
from thefuck.shells import shell
|
||||||
|
|
||||||
|
|
||||||
@sudo_support
|
@sudo_support
|
||||||
@@ -14,5 +14,5 @@ def match(command):
|
|||||||
|
|
||||||
@sudo_support
|
@sudo_support
|
||||||
def get_new_command(command):
|
def get_new_command(command):
|
||||||
repl = shells.and_('mkdir -p \\1', 'cd \\1')
|
repl = shell.and_('mkdir -p \\1', 'cd \\1')
|
||||||
return re.sub(r'^cd (.*)', repl, command.script)
|
return re.sub(r'^cd (.*)', repl, command.script)
|
||||||
|
|||||||
15
thefuck/rules/chmod_x.py
Normal file
15
thefuck/rules/chmod_x.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import os
|
||||||
|
from thefuck.shells import shell
|
||||||
|
|
||||||
|
|
||||||
|
def match(command):
|
||||||
|
return (command.script.startswith('./')
|
||||||
|
and 'permission denied' in command.stderr.lower()
|
||||||
|
and os.path.exists(command.script_parts[0])
|
||||||
|
and not os.access(command.script_parts[0], os.X_OK))
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command):
|
||||||
|
return shell.and_(
|
||||||
|
'chmod +x {}'.format(command.script_parts[0][2:]),
|
||||||
|
command.script)
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import tarfile
|
import tarfile
|
||||||
import os
|
import os
|
||||||
from thefuck import shells
|
|
||||||
from thefuck.utils import for_app
|
from thefuck.utils import for_app
|
||||||
|
from thefuck.shells import shell
|
||||||
|
|
||||||
|
|
||||||
tar_extensions = ('.tar', '.tar.Z', '.tar.bz2', '.tar.gz', '.tar.lz',
|
tar_extensions = ('.tar', '.tar.Z', '.tar.bz2', '.tar.gz', '.tar.lz',
|
||||||
@@ -33,8 +33,8 @@ def match(command):
|
|||||||
|
|
||||||
|
|
||||||
def get_new_command(command):
|
def get_new_command(command):
|
||||||
dir = shells.quote(_tar_file(command.script_parts)[1])
|
dir = shell.quote(_tar_file(command.script_parts)[1])
|
||||||
return shells.and_('mkdir -p {dir}', '{cmd} -C {dir}') \
|
return shell.and_('mkdir -p {dir}', '{cmd} -C {dir}') \
|
||||||
.format(dir=dir, cmd=command.script)
|
.format(dir=dir, cmd=command.script)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import zipfile
|
import zipfile
|
||||||
from thefuck.utils import for_app
|
from thefuck.utils import for_app
|
||||||
from thefuck.shells import quote
|
from thefuck.shells import shell
|
||||||
|
|
||||||
|
|
||||||
def _is_bad_zip(file):
|
def _is_bad_zip(file):
|
||||||
@@ -38,7 +38,8 @@ def match(command):
|
|||||||
|
|
||||||
|
|
||||||
def get_new_command(command):
|
def get_new_command(command):
|
||||||
return u'{} -d {}'.format(command.script, quote(_zip_file(command)[:-4]))
|
return u'{} -d {}'.format(
|
||||||
|
command.script, shell.quote(_zip_file(command)[:-4]))
|
||||||
|
|
||||||
|
|
||||||
def side_effect(old_cmd, command):
|
def side_effect(old_cmd, command):
|
||||||
|
|||||||
37
thefuck/rules/fab_command_not_found.py
Normal file
37
thefuck/rules/fab_command_not_found.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
from thefuck.utils import eager, get_closest, for_app
|
||||||
|
|
||||||
|
|
||||||
|
@for_app('fab')
|
||||||
|
def match(command):
|
||||||
|
return 'Warning: Command(s) not found:' in command.stderr
|
||||||
|
|
||||||
|
|
||||||
|
# We need different behavior then in get_all_matched_commands.
|
||||||
|
@eager
|
||||||
|
def _get_between(content, start, end=None):
|
||||||
|
should_yield = False
|
||||||
|
for line in content.split('\n'):
|
||||||
|
if start in line:
|
||||||
|
should_yield = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if end and end in line:
|
||||||
|
return
|
||||||
|
|
||||||
|
if should_yield and line:
|
||||||
|
yield line.strip().split(' ')[0]
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command):
|
||||||
|
not_found_commands = _get_between(
|
||||||
|
command.stderr, 'Warning: Command(s) not found:', 'Available commands:')
|
||||||
|
possible_commands = _get_between(
|
||||||
|
command.stdout, 'Available commands:')
|
||||||
|
|
||||||
|
script = command.script
|
||||||
|
for not_found in not_found_commands:
|
||||||
|
fix = get_closest(not_found, possible_commands)
|
||||||
|
script = script.replace(' {}'.format(not_found),
|
||||||
|
' {}'.format(fix))
|
||||||
|
|
||||||
|
return script
|
||||||
@@ -2,7 +2,7 @@ import re
|
|||||||
import os
|
import os
|
||||||
from thefuck.utils import memoize, default_settings
|
from thefuck.utils import memoize, default_settings
|
||||||
from thefuck.conf import settings
|
from thefuck.conf import settings
|
||||||
from thefuck import shells
|
from thefuck.shells import shell
|
||||||
|
|
||||||
|
|
||||||
# order is important: only the first match is considered
|
# order is important: only the first match is considered
|
||||||
@@ -75,4 +75,4 @@ def get_new_command(command):
|
|||||||
file=m.group('file'),
|
file=m.group('file'),
|
||||||
line=m.group('line'))
|
line=m.group('line'))
|
||||||
|
|
||||||
return shells.and_(editor_call, command.script)
|
return shell.and_(editor_call, command.script)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user