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

Compare commits

...

314 Commits
3.9 ... 3.17

Author SHA1 Message Date
Vladimir Iakovlev
3a134f250d Bump to 3.17 2017-05-10 15:34:06 +02:00
Vladimir Iakovlev
b54cdf7c49 #637: Suggest yarn add on yarn require 2017-05-10 15:32:11 +02:00
Vladimir Iakovlev
1b05a497e8 #635: Show "Nothing found" instead of 'No fucks given' when different alias are used 2017-05-10 15:22:26 +02:00
Vladimir Iakovlev
79602383ec #549: Fix aliases with bash 2017-05-10 15:14:01 +02:00
Vladimir Iakovlev
84c42168df #N/A: Add new line after version 2017-05-10 15:06:29 +02:00
Vladimir Iakovlev
f53d772ac3 Merge pull request #640 from bam241/add_macport_to_sudo
fix sudo.py for macport
2017-05-03 12:08:53 +04:00
Mouginot B
93d4a4fc3a fix sudo.py for macport 2017-05-02 17:36:35 -05:00
Vladimir Iakovlev
2cb23b1805 #N/A: Fix docstring 2017-05-01 17:49:13 +02:00
Vladimir Iakovlev
33f28cf76d #633: Show ci badges for master 2017-04-20 21:34:47 +02:00
Vladimir Iakovlev
6322dbd9ed #N/A: Fix flake8 warnings 2017-04-10 23:23:23 +02:00
Vladimir Iakovlev
fc09818351 Bump to 3.16 2017-04-10 23:16:06 +02:00
Vladimir Iakovlev
2788ef1471 #N/A: Make missing_space_before_subcommand handle aliases correctly 2017-04-10 23:15:12 +02:00
Vladimir Iakovlev
ef3aabe7c5 Merge branch '614-repeate-option' 2017-03-28 18:51:25 +02:00
Vladimir Iakovlev
2af54d036d #623: Fix UnicodeDecodeError with Python 2 2017-03-28 18:50:51 +02:00
Vladimir Iakovlev
99c10b50ff Merge branch 'dfadev-master' 2017-03-28 18:35:54 +02:00
Vladimir Iakovlev
802fcd96fd #621: Refine yarn_command_replaced rule tests 2017-03-28 18:35:40 +02:00
Russ Panula
900e83e028 add rule for: yarn install [pkg]
--- `install` has been replaced with `add` to add new dependencies. Run $0 instead.

6e9a9a6596/src/reporters/lang/en.js (L18)
2017-03-28 18:31:01 +02:00
Joseph Frazier
d41cbb6810 Fix heroku_not_command for new stderr format
heroku updated its command suggestion formatting, so account for that.
For example:

    $ heroku log
     ▸    log is not a heroku command.
     ▸    Perhaps you meant logs?
     ▸    Run heroku _ to run heroku logs.
     ▸    Run heroku help for a list of available commands.
    $ fuck
    heroku logs [enter/↑/↓/ctrl+c]
2017-03-28 18:31:01 +02:00
Vladimir Iakovlev
b36cf59b46 #614: Refine argument_parser 2017-03-28 18:18:01 +02:00
Vladimir Iakovlev
cfa831c88d #614: Add --repeat option 2017-03-28 18:09:38 +02:00
Vladimir Iakovlev
818d06fb95 Merge pull request #622 from josephfrazier/heroku-format
Fix heroku_not_command for new stderr format
2017-03-28 16:56:03 +04:00
Vladimir Iakovlev
c3eca8234a #620: Add --debug 2017-03-28 13:09:11 +02:00
Vladimir Iakovlev
d47ff8cbf2 #620: Fix functional tests 2017-03-28 12:28:34 +02:00
Vladimir Iakovlev
1a52e98fbd #620: Fix code style 2017-03-28 12:25:33 +02:00
Vladimir Iakovlev
53c11d2ef4 #620: Fix python 2 support 2017-03-28 12:08:32 +02:00
Vladimir Iakovlev
beda1854cf #620: Add bash support 2017-03-28 12:01:09 +02:00
Vladimir Iakovlev
7532c65c62 #620: Fix aliases with zsh 2017-03-28 11:38:28 +02:00
Vladimir Iakovlev
ec37998a10 #620: Add support of arguments to fuck, like fuck -y on zsh 2017-03-28 11:31:06 +02:00
Joseph Frazier
58d5eff6d0 Fix heroku_not_command for new stderr format
heroku updated its command suggestion formatting, so account for that.
For example:

    $ heroku log
     ▸    log is not a heroku command.
     ▸    Perhaps you meant logs?
     ▸    Run heroku _ to run heroku logs.
     ▸    Run heroku help for a list of available commands.
    $ fuck
    heroku logs [enter/↑/↓/ctrl+c]
2017-03-26 15:55:03 -04:00
Vladimir Iakovlev
d28567bb31 #585: Fix suggestion of .bash_profile 2017-03-23 16:55:24 +01:00
Vladimir Iakovlev
b016bb2255 Merge pull request #619 from josephfrazier/yarn-alias-scripts
Extend yarn_alias rule to handle package.json scripts
2017-03-23 19:39:11 +04:00
Joseph Frazier
bf109ee548 Extend yarn_alias rule to handle package.json scripts
For example, if an "etl" script is defined in package.json, it can be
run with `yarn etl`. However, if `yarn etil` is run, `yarn` will
suggest the correction. This change lets `thefuck` take advantage of
that:

    $ yarn etil
    yarn etil v0.21.3
    error Command "etil" not found. Did you mean "etl"?
    $ fuck
    yarn etl [enter/?/?/ctrl+c]
2017-03-22 16:52:30 -04:00
Vladimir Iakovlev
1aaaca1220 Merge branch 'Asday-master' 2017-03-22 14:00:18 +01:00
Vladimir Iakovlev
b096560469 #618: Refine git_push_without_commits rule 2017-03-22 14:00:03 +01:00
Vladimir Iakovlev
5b1f3ff816 Merge branch 'master' of git://github.com/Asday/thefuck into Asday-master 2017-03-22 13:57:18 +01:00
Vladimir Iakovlev
c5f7c89222 Merge pull request #617 from josephfrazier/git-stash-add-updated
git_stash_pop: Add only updated files
2017-03-22 15:25:25 +04:00
Adam Barnes
e61271dae3 Removed another unused import.
Goodness.
2017-03-22 10:59:27 +00:00
Adam Barnes
bddb43b987 Removed an unused import. 2017-03-22 10:29:50 +00:00
Adam Barnes
b22a3ac891 Created a rule for trying to push a new repository with no commits. 2017-03-22 10:23:35 +00:00
Joseph Frazier
f4cc88f6c7 git_stash_pop: Add only updated files
This avoids adding untracked files to the repo. See here for a
description of the difference between `git add .` and `git add --update`:

https://stackoverflow.com/questions/572549/difference-between-git-add-a-and-git-add/572660#572660
2017-03-21 20:12:15 -04:00
Vladimir Iakovlev
5734412d82 Bump to 3.15 2017-03-14 16:38:07 +01:00
Vladimir Iakovlev
24588b23e2 #N/A: Add .tox to flake8 exclude 2017-03-14 11:14:23 +01:00
Vladimir Iakovlev
825f7986c7 #322: Use unicode in vagrant_up rule 2017-03-14 11:13:43 +01:00
Vladimir Iakovlev
971c7e1b3f #322: Add vagrant to slow commands 2017-03-14 11:13:10 +01:00
Vladimir Iakovlev
8375b78877 #N/A: Use unicode in all log functions 2017-03-14 09:49:36 +01:00
Vladimir Iakovlev
6f39edc155 #611: Force use MagicMock in tests 2017-03-13 23:35:57 +01:00
Vladimir Iakovlev
408cb5fa09 #611: Fix python 2 support 2017-03-13 23:26:57 +01:00
Vladimir Iakovlev
2315929875 #579: Add missing_space_before_subcommand rule 2017-03-13 22:21:34 +01:00
Vladimir Iakovlev
14a9cd85aa #611: Allow to configure alias automatically by calling fuck twice 2017-03-13 21:50:13 +01:00
Vladimir Iakovlev
2379573cf2 #591: Add path_from_history rule 2017-03-13 19:05:34 +01:00
Vladimir Iakovlev
350be285b8 #591: Treat builtin commands as executables 2017-03-13 18:27:01 +01:00
Vladimir Iakovlev
76aa5546df #593: Remove unned underscores from readme 2017-03-13 17:22:58 +01:00
Vladimir Iakovlev
5179015b84 #531: Add example of alias for running without confirmation to readme 2017-03-13 16:59:29 +01:00
Vladimir Iakovlev
dee99ed705 #220: Use pip3 install --user for upgrade too 2017-03-13 14:15:24 +01:00
Vladimir Iakovlev
e101f1fcc9 #220: Use pip3 install --user in readme 2017-03-13 14:01:38 +01:00
Vladimir Iakovlev
73b884df5f Merge branch 'ds-forks-master' 2017-03-13 13:53:55 +01:00
Vladimir Iakovlev
9e8b4f594d #602: Little cleanup 2017-03-13 13:53:43 +01:00
Vladimir Iakovlev
c2b597f22b Merge branch 'master' of https://github.com/ds-forks/thefuck into ds-forks-master 2017-03-13 13:47:56 +01:00
Vladimir Iakovlev
8c783b7405 Merge branch 'awonnacott-master' 2017-03-13 13:47:10 +01:00
Vladimir Iakovlev
3efa42ec06 Merge branch 'master' of https://github.com/awonnacott/thefuck into awonnacott-master 2017-03-13 13:45:45 +01:00
Vladimir Iakovlev
02bcd8331d Merge branch 'josephfrazier-flake8' 2017-03-13 13:39:16 +01:00
Vladimir Iakovlev
bd750ff9a3 #563: Exclude build from flake8 check 2017-03-13 13:39:00 +01:00
Vladimir Iakovlev
725ef271b1 Merge branch 'flake8' of https://github.com/josephfrazier/thefuck into josephfrazier-flake8
# Conflicts:
#	thefuck/system/unix.py
#	thefuck/system/win32.py
2017-03-13 13:35:11 +01:00
Vladimir Iakovlev
d2f8cebfd8 Merge branch 'josephfrazier-yarn_help' 2017-03-13 13:32:02 +01:00
Vladimir Iakovlev
c7d7a6d1d7 #612: Little cleanup 2017-03-13 13:30:07 +01:00
Joseph Frazier
4b53b1d3e3 Support Linux/Windows in yarn_help rule
See https://www.dwheeler.com/essays/open-files-urls.html
and https://stackoverflow.com/questions/5226958/which-equivalent-function-in-python/15133367#15133367
2017-03-10 15:22:48 -05:00
Joseph Frazier
35ea4dce71 Add yarn_help rule
Yarn likes to keep its documentation online, rather than in `yarn help`
output. For example, `yarn help clean` doesn't tell you anything about
the `clean` subcommand. Instead, it points you towards
https://yarnpkg.com/en/docs/cli/clean

This rule detects when that happens, and suggests opening the URL. One
caveat is the currently only OSX is supported, as Linux uses `xdg-open`
instead of `open`.
2017-03-10 13:07:46 -05:00
Joseph Frazier
2fea1f3846 Run flake8 on AppVeyor 2017-03-10 12:18:59 -05:00
Joseph Frazier
e009f0a05b Fix flake8 errors: E305 expected 2 blank lines after class or function definition 2017-03-08 19:53:54 -05:00
Joseph Frazier
78515c7bbb Fix flake8 errors: W391 blank line at end of file 2017-03-08 12:43:34 -05:00
Joseph Frazier
62a845fd94 fixup! Fix flake8 errors: E302 expected 2 blank lines, found 1 2017-03-08 12:43:05 -05:00
Joseph Frazier
2c7ce91dd5 Fix flake8 errors: F401 'sys' imported but unused 2017-03-08 12:42:24 -05:00
Joseph Frazier
c775937d17 fixup! Fix flake8 errors: E101/W191 indentation contains (mixed spaces and) tabs 2017-03-08 12:40:11 -05:00
Joseph Frazier
aaf01394db fixup! Fix flake8 errors: E126 continuation line over-indented for hanging indent 2017-03-08 12:39:24 -05:00
Joseph Frazier
0b0a2220a0 fixup! Ignore flake8 errors with inline comments: W291 trailing whitespace 2017-03-08 12:34:49 -05:00
Joseph Frazier
b038ea4541 Merge branch 'master' into flake8 2017-03-08 12:21:54 -05:00
Vladimir Iakovlev
7d3ddfc8d9 Merge branch 'josephfrazier-yarn-command-not-found' 2017-03-06 17:32:34 +01:00
Vladimir Iakovlev
02f3250d39 #609: Use replace_command in yarn_command_not_found 2017-03-06 17:31:57 +01:00
Joseph Frazier
df5428c5e4 Add yarn_command_not_found rule
This addresses https://github.com/nvbn/thefuck/pull/607#issuecomment-283945505

The code was adapted from the `grunt_task_not_found` rule
2017-03-03 23:38:20 -05:00
Vladimir Iakovlev
ef5ff6210a Merge pull request #606 from josephfrazier/git-rm-staged
Add git_rm_staged rule for removing locally staged changes
2017-03-03 13:52:43 +01:00
Vladimir Iakovlev
fbb73f262b Merge pull request #607 from josephfrazier/yarn-alias
Fix aliased `yarn` commands like `yarn ls`
2017-03-03 13:50:58 +01:00
Vladimir Iakovlev
20246e5be6 Merge pull request #608 from MattKotsenas/bugfix/no-history
Update PowerShell alias to handle no history
2017-03-03 13:45:23 +01:00
Matt Kotsenas
4669a033ee Update PowerShell alias to handle no history
If history is cleared (or the shell is new and there is no history),
invoking thefuck results in an error because the alias attempts to execute
the usage string.

The fix is to check if Get-History returns anything before invoking
thefuck.
2017-03-01 09:36:30 -08:00
Joseph Frazier
7e16a2eb7c Fix aliased yarn commands like yarn ls
[Yarn] has a handful of subcommand [aliases], but does not automatically
[correct] them for the user. This makes it so that `fuck` will do the
trick. For example:

    $ yarn ls
    yarn ls v0.20.3
    error Did you mean `yarn list`?
    info Visit https://yarnpkg.com/en/docs/cli/list for documentation about this command.
    $ fuck
    yarn list [enter/?/?/ctrl+c]

[Yarn]: https://yarnpkg.com/en/
[aliases]: 0adbc59b18/src/cli/aliases.js
[correct]: https://github.com/yarnpkg/yarn/pull/1044#issuecomment-253763230
2017-02-26 20:50:41 -05:00
Joseph Frazier
42ec01dab1 Add git_rm_staged rule for removing locally staged changes
It would be nice if `thefuck` could help me `git rm` a file I had
already staged. This rule, adapted from `git_rm_local_modifications`,
does that.
2017-02-26 19:16:15 -05:00
Vladimir Iakovlev
91c27e1a62 Merge pull request #605 from andrew-epstein/master
Improve performance of history rule
2017-02-24 13:46:56 +01:00
Andrew Epstein
778f2bdf1a Improve performance of history rule 2017-02-22 07:56:40 -05:00
Vladimir Iakovlev
e893521872 #N/A: Run coveralls only on full test run (python 3.6 with linux) 2017-02-09 16:13:09 +01:00
Vladimir Iakovlev
bbed17fe07 #N/A: Add sudo_command_from_user_path rule 2017-02-09 16:09:37 +01:00
dhilipsiva
309fe8f6ee Fix test cases 2017-02-09 09:16:20 +05:30
dhilipsiva
8a8ade1e6b Fix regex 2017-02-09 08:52:20 +05:30
dhilipsiva
7f9025c7ad Make Changes suggested by @nvbn
* remove comments/doctrings at the top of files;
* move sudo-related stuff to sudo rule;
* for no_command case try to find most similar command, like, for example, in react_native_command_unrecognized rule.
2017-02-09 08:46:54 +05:30
Vladimir Iakovlev
6f842ab747 Merge pull request #604 from wbolster/add-colemak-nav-bindings
add support for colemak style vi bindings
2017-02-08 13:01:28 +01:00
wouter bolsterlee
ae68bcbac1 add support for colemak style vi bindings
this allows e/n in addition to j/k (same places on the keyboard on
colemak and qwerty) to be used as arrow keys when selecting a command
from the suggested fixups.

fixes #603
2017-02-08 12:06:11 +01:00
dhilipsiva
fb07cdfb4a Add hostscli to readme 2017-02-05 14:58:36 +05:30
dhilipsiva
55dcf06569 Hostscli 2017-02-05 14:50:36 +05:30
Vladimir Iakovlev
28a0150e45 Merge branch 'juzim-apt_get_not_installed' 2017-01-30 13:06:34 +01:00
Vladimir Iakovlev
430a7135af #599: Remove unused import 2017-01-30 13:06:19 +01:00
Vladimir Iakovlev
ff2be6c9a3 Merge branch 'apt_get_not_installed' of git://github.com/juzim/thefuck into juzim-apt_get_not_installed 2017-01-30 13:03:28 +01:00
Vladimir Iakovlev
4748776296 Merge pull request #598 from josephfrazier/git_add_force
Add git_add_force rule
2017-01-30 13:02:20 +01:00
Vladimir Iakovlev
1885196a11 Merge pull request #597 from josephfrazier/readme-git_stash-typo
README.md: fix typo in git_stash description
2017-01-30 13:00:42 +01:00
Vladimir Iakovlev
c127040a4c Merge pull request #596 from josephfrazier/git-tag-force
Add git_tag_force rule
2017-01-30 13:00:19 +01:00
Julian Zimmermann
ac7b633e28 Added support for "not installed" message in apt_get 2017-01-29 00:15:55 +01:00
Joseph Frazier
4d0388b53c Add git_add_force rule
This adds `--force` to `git add` when needed. For example:

    $ git add dist/*.js
    The following paths are ignored by one of your .gitignore files:
    dist/app.js
    dist/background.js
    dist/options.js
    Use -f if you really want to add them.
    $ fuck
    git add --force dist/app.js dist/background.js dist/options.js [enter/↑/↓/ctrl+c]
    $
2017-01-28 13:26:40 -05:00
Joseph Frazier
8da4dce5f2 Add git_tag_force rule
This adds `--force` to `git tag` when needed. For example:

    $ git tag alert
    fatal: tag 'alert' already exists
    $ fuck
    git tag --force alert [enter/↑/↓/ctrl+c]
    Updated tag 'alert' (was dec6956)
    $
2017-01-28 13:26:14 -05:00
Joseph Frazier
ace6e88269 README.md: fix typo in git_stash description
from "stashes you local modifications"
to   "stashes your local modifications"
2017-01-27 19:44:40 -05:00
Vladimir Iakovlev
a015c0f5e2 #N/A: Add gem unknown command rule 2017-01-15 15:14:53 +01:00
Vladimir Iakovlev
dbe324bcd8 #587: Add scm correction rule 2017-01-15 14:40:50 +01:00
Vladimir Iakovlev
8447b5caa2 #585: Add note about reloading changes in how to configure message 2017-01-15 14:03:09 +01:00
Vladimir Iakovlev
3a9942061d Bump to 3.14 2017-01-11 15:05:29 +01:00
Vladimir Iakovlev
a65f90813b Bump to 3.13 2017-01-11 14:59:18 +01:00
Vladimir Iakovlev
a778ea6203 #588: Stop using bashlex 2017-01-11 14:58:50 +01:00
Vladimir Iakovlev
03a828d586 Bump to 3.12 2017-01-09 18:17:50 +01:00
Vladimir Iakovlev
4a0d71c1c4 #N/A: Add ifconfig_device_not_found rule 2017-01-09 18:13:37 +01:00
Vladimir Iakovlev
a6f63c0568 #580: Use bashlex in generic shell 2017-01-09 17:50:23 +01:00
Vladimir Iakovlev
d1b9492085 Merge pull request #586 from duboviy/master
Add Python 3.6 support
2017-01-09 17:38:37 +01:00
Eugene Duboviy
993a661c60 Update .travis.yml 2017-01-08 17:13:22 +02:00
Eugene Duboviy
bc9121cb13 Update appveyor.yml 2017-01-08 17:08:38 +02:00
Eugene Duboviy
7db140c456 Update tox.ini 2017-01-08 17:06:45 +02:00
Vladimir Iakovlev
e313ff73a9 Merge pull request #582 from josephfrazier/git_stash_pop
Fix `git stash pop` with local changes
2016-12-22 14:02:05 +01:00
Joseph Frazier
8c62706db4 Fix git stash pop with local changes
When there are local changes to a file, and a git stash is popped that
contains other changes to that same file, git fails as follows:

    $ git stash pop
    error: Your local changes to the following files would be overwritten by merge:
            src/index.js
    Please commit your changes or stash them before you merge.
    Aborting
    $

This change adds a rule that corrects this problem as suggested [here]:

    $ git stash pop
    error: Your local changes to the following files would be overwritten by merge:
            src/index.js
    Please commit your changes or stash them before you merge.
    Aborting
    $ fuck
    git add . && git stash pop && git reset . [enter/↑/↓/ctrl+c]
    Auto-merging src/index.js
    On branch flow
    Changes to be committed:
      (use "git reset HEAD <file>..." to unstage)

            modified:   src/index.js

    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git checkout -- <file>..." to discard changes in working directory)

            modified:   src/index.js

    Dropped refs/stash@{0} (f94776d484c4278997ac6837a7b138b9b9cdead1)
    Unstaged changes after reset:
    M        src/index.js
    $

[here]: https://stackoverflow.com/questions/15126463/how-do-i-merge-local-modifications-with-a-git-stash-without-an-extra-commit/15126489#15126489
2016-12-11 12:44:04 -05:00
Vladimir Iakovlev
6baa7f650e Merge pull request #580 from josephfrazier/bash-command-substitution
bash: fix parsing of command substitution
2016-11-30 15:49:47 +01:00
Joseph Frazier
4ae32cf4ee bash: use generic shell's UTF-8 methods 2016-11-23 22:42:16 -05:00
Joseph Frazier
385746850e generic shell: extract UTF-8 encoding/decoding into methods 2016-11-23 07:53:22 -05:00
Joseph Frazier
4f87141f0c bash: fallback to generic parser if bashlex fails 2016-11-23 07:43:25 -05:00
Joseph Frazier
dbedcc7aa6 Test parsing bash arithmetic expressions 2016-11-23 07:36:58 -05:00
Vladimir Iakovlev
e0b5d47fa5 Merge pull request #578 from scorphus/fish-builtin-history
#577: Use builtin `history` in Fish function
2016-11-22 12:03:06 +01:00
Joseph Frazier
ca44ee0640 bash: use bashlex for split_command, not shlex 2016-11-18 14:43:07 -05:00
Joseph Frazier
892e8a8e65 Test parsing bash command substitution
This is to help address bad corrections like the following (note the
position of the -p flag):

    thefuck 'git log $(git ls-files thefuck | grep python_command) -p'
    git log $(git ls-files thefuck | grep -p python_command) [enter/↑/↓/ctrl+c]
2016-11-18 14:43:00 -05:00
Pablo Santiago Blum de Aguiar
a947259eef #577: Use builtin history in Fish function
Fix #577
2016-11-17 22:57:11 -02:00
Vladimir Iakovlev
785cb83ff3 Merge branch 'josephfrazier-git-flag-after-filename' 2016-11-08 23:53:50 +01:00
Vladimir Iakovlev
aec8fe3233 #570: Refine tests 2016-11-08 23:53:40 +01:00
Vladimir Iakovlev
c21dbd2be3 Merge branch 'git-flag-after-filename' of https://github.com/josephfrazier/thefuck into josephfrazier-git-flag-after-filename 2016-11-08 23:48:40 +01:00
Andrew Wonnacott
b4fda04acb Now only return [] when correct error was caught 2016-11-03 03:46:27 -04:00
Andrew Wonnacott
5f6c55d839 Fix issue with attempting to scroll through options when not-found package has no packages with matching names causing crash. 2016-11-03 03:34:41 -04:00
Vladimir Iakovlev
6173913291 Merge pull request #572 from josephfrazier/ls_all
Suggest `ls -A` when `ls` has no output
2016-11-01 12:51:04 +01:00
Vladimir Iakovlev
6f0d1e287d #571: Don't put empty string in history in zsh 2016-10-31 18:52:48 +01:00
Joseph Frazier
756044e087 Suggest ls -A when ls has no output 2016-10-31 13:49:38 -04:00
Vladimir Iakovlev
ddd8788353 #571: always honor alter_history setting in zsh 2016-10-31 12:57:31 +01:00
Vladimir Iakovlev
76c0e7bc70 Merge pull request #571 from josephfrazier/bash-honor-alter-history
bash: always honor alter_history setting
2016-10-31 12:56:31 +01:00
Vladimir Iakovlev
4865bdd81f Merge pull request #569 from scorphus/rebase-skip
#N/A: Add `git_rebase_merge_dir` rule
2016-10-31 12:55:05 +01:00
Joseph Frazier
fa169c686c test_git_flag_after_filename.py: dedupe test commands 2016-10-31 00:22:24 -04:00
Joseph Frazier
9cae0bffff git_flag_after_filename: fix flake8 errors
These were found by creating a `.flake8` file containing:

    [flake8]
    ignore = E501,W503
    exclude = venv

then running:

    flake8 $(git diff master... --name-only)

See https://github.com/nvbn/thefuck/pull/563 for running `flake8` in CI
2016-10-31 00:22:24 -04:00
Joseph Frazier
b519d317f7 bash: always honor alter_history setting
This ensures that even if the command suggested and run by `thefuck`
fails, it will still be added to the history, allowing the user to tweak
it further (or run `fuck` again) if desired.

Note that the fish shell appears to already behave this way.
2016-10-30 23:17:52 -04:00
Joseph Frazier
5b420204c9 git: fix fatal: bad flag '...' after filename
For example:

    $ git log README.md -p
    fatal: bad flag '-p' used after filename
    $ fuck
    git log -p README.md [enter/↑/↓/ctrl+c]
    Aborted

    $ git log -p README.md --name-only
    fatal: bad flag '--name-only' used after filename
    $ fuck
    git log -p --name-only README.md [enter/↑/↓/ctrl+c]
    Aborted

    $ git log README.md -p CONTRIBUTING.md
    fatal: bad flag '-p' used after filename
    $ fuck
    git log -p README.md CONTRIBUTING.md [enter/↑/↓/ctrl+c]
2016-10-30 21:40:25 -04:00
Pablo Santiago Blum de Aguiar
07005b591a #N/A: Add git_rebase_merge_dir rule 2016-10-30 20:30:26 -02:00
Vladimir Iakovlev
cb99e42e02 Merge pull request #567 from scorphus/git-rm-local-modifications
#N/A: Add `git_rm_local_modifications` rule
2016-10-30 19:51:20 +01:00
Vladimir Iakovlev
51f77964c6 Merge pull request #568 from scorphus/osx-brew-install
#N/A: Do not fail if formula is already installed
2016-10-30 19:50:02 +01:00
Pablo Santiago Blum de Aguiar
30b1c44f91 #N/A: Do not fail if formula is already installed 2016-10-30 15:02:12 -02:00
Pablo Santiago Blum de Aguiar
af28f0334a #N/A: Add git_rm_local_modifications rule 2016-10-29 17:51:55 -02:00
Vladimir Iakovlev
5ee5439c1e #565: Refine git_push rule 2016-10-08 12:24:48 +02:00
Vladimir Iakovlev
cf006dac2c Merge branch 'master' into josephfrazier-git-push-u
# Conflicts:
#	thefuck/rules/git_push.py
2016-10-08 12:20:23 +02:00
Vladimir Iakovlev
5b535077bf #N/A: Stop changing Command inside rules 2016-10-08 12:18:33 +02:00
Joseph Frazier
dda9d55989 Add flake8 instructions to README.md
Also add flake8 to requirements.txt so that it will be installed by:

    pip install -r requirements.txt
2016-10-07 22:27:07 -04:00
Joseph Frazier
f0b9c7cb67 Ignore remaining flake8 rules and exclude ./venv/
This should fix the builds.
2016-10-07 22:27:07 -04:00
Joseph Frazier
521eb03d7a Fix flake8 errors: E127 continuation line over-indented for visual indent 2016-10-07 22:27:07 -04:00
Joseph Frazier
e0cab4fa1b Fix flake8 errors: E126 continuation line over-indented for hanging indent 2016-10-07 22:27:07 -04:00
Joseph Frazier
1b30c00546 Fix flake8 errors: E122 continuation line missing indentation or outdented 2016-10-07 22:27:07 -04:00
Joseph Frazier
a9d55e9c62 Fix flake8 errors: E128 continuation line under-indented for visual indent
See https://github.com/nvbn/thefuck/pull/563#discussion_r82492221
2016-10-07 22:26:57 -04:00
Vladimir Iakovlev
cf3acbfa2e Merge branch 'git-push-u' of https://github.com/josephfrazier/thefuck into josephfrazier-git-push-u 2016-10-07 10:40:02 +02:00
Vladimir Iakovlev
4d714994a3 Merge pull request #564 from josephfrazier/docker-python
Use official Python images for Docker tests
2016-10-07 10:38:49 +02:00
Vladimir Iakovlev
02f717a0e8 Merge pull request #562 from josephfrazier/man-help
Suggest `foo --help` when `man foo` shows no pages
2016-10-07 10:37:33 +02:00
Vladimir Iakovlev
8f4f2f03a7 Merge pull request #561 from josephfrazier/ag-literal
Suggest `ag -Q` when relevant
2016-10-07 10:35:34 +02:00
Joseph Frazier
432878bd77 Ignore flake8 errors with inline comments: W291 trailing whitespace
See https://github.com/PyCQA/pycodestyle/pull/243
2016-10-06 15:31:55 -04:00
Joseph Frazier
fb3d8d1e01 Ignore flake8 errors with inline comments: F401,F403 2016-10-06 15:31:55 -04:00
Joseph Frazier
c4c6f506f4 Ignore flake8 errors with inline comments: E402 module level import not at top of file
https://github.com/nvbn/thefuck/pull/563#discussion_r82105200
2016-10-06 15:31:55 -04:00
Joseph Frazier
725605cd20 Fix flake8 errors: E711 comparison to None should be 'if cond is not None:' 2016-10-06 15:31:55 -04:00
Joseph Frazier
797b42cfd7 Fix flake8 errors: E302 expected 2 blank lines, found 1 2016-10-06 15:31:55 -04:00
Joseph Frazier
37161832aa Fix flake8 errors: E123 closing bracket does not match indentation of opening bracket's line 2016-10-06 15:31:55 -04:00
Joseph Frazier
b221b04d0f Fix flake8 errors: F811 redefinition of unused... 2016-10-06 15:31:55 -04:00
Joseph Frazier
dcc13bd2d2 Fix flake8 errors: F841, E265
This commented-out test caused a couple flake8 errors, so get rid of it:
* F841 local variable 'cmd' is assigned to but never used
* E265 block comment should start with '# '

See https://github.com/nvbn/thefuck/pull/563#discussion_r82104360
2016-10-06 15:30:53 -04:00
Joseph Frazier
283eb09c19 Fix flake8 errors: E231 missing whitespace after ',' 2016-10-06 13:30:39 -04:00
Joseph Frazier
10d409e6e2 Fix flake8 errors: E225 missing whitespace around operator 2016-10-06 13:30:13 -04:00
Joseph Frazier
93302c74b5 Fix flake8 errors: E101/W191 indentation contains (mixed spaces and) tabs 2016-10-06 13:30:13 -04:00
Joseph Frazier
22b005cebb Fix flake8 errors: E731 do not assign a lambda expression, use a def 2016-10-06 13:30:05 -04:00
Joseph Frazier
feb36ede5c Fix suggestion for git push -u
This was broken by https://github.com/nvbn/thefuck/pull/559
2016-10-06 13:09:40 -04:00
Joseph Frazier
16a440cb9d test_zsh.py: use official python images, not ubuntu
This should help reduce build times.
2016-10-06 11:15:18 -04:00
Joseph Frazier
10b20574d1 test_tcsh.py: use official python images, not ubuntu
This should help reduce build times.
2016-10-06 11:12:38 -04:00
Joseph Frazier
91fceb401a test_fish.py: use official python images, not ubuntu
This should help reduce build times.
2016-10-06 11:09:19 -04:00
Joseph Frazier
4b79e23ba7 test_bash.py: use official python images, not ubuntu
This should help reduce build times.
2016-10-06 10:56:37 -04:00
Joseph Frazier
f915a6ed0c test_performance.py: use python:3 image, not ubuntu
This should help reduce build times.
2016-10-06 10:54:47 -04:00
Joseph Frazier
e9d29726bc Run flake8 using Travis CI 2016-10-05 11:00:39 -04:00
Joseph Frazier
a964af7e95 ag_literal.py: use endswith() rather than in
https://github.com/nvbn/thefuck/pull/561#discussion_r81898499
2016-10-05 10:55:49 -04:00
Joseph Frazier
77fc021a6c Refactor tests/rules/test_ag_literal.py
https://github.com/nvbn/thefuck/pull/561#discussion_r81894710
2016-10-05 10:52:24 -04:00
Joseph Frazier
4822ceb87a ag_literal.py: remove unused import (Flake8 F401)
https://github.com/nvbn/thefuck/pull/561#discussion_r81892699
2016-10-05 10:34:17 -04:00
Joseph Frazier
b2947aba8d test_ag_literal.py: Add blank line (PEP 8 E302)
https://github.com/nvbn/thefuck/pull/561#discussion_r81892174
2016-10-05 10:32:14 -04:00
Joseph Frazier
d2e0a19aae Add missing semicolon to aws_cli entry in README 2016-10-03 14:22:17 -04:00
Joseph Frazier
0c84eefa55 Don't suggest man 2/3 foo if no man pages exist
Suggest `foo --help` instead. However, if there are man pages, suggest
`foo --help` after `man 2/3 foo`

This addresses the comment in the previous commit message:

> However, in cases where multiple sections have man pages for `foo`,
> running `man foo` could bring up the "wrong" section of man pages.
> `man read` is an example of this, but that should probably be handled in
> a way that still suggests `foo --help` first when there are *no* man
> pages for `foo` in any section.
2016-10-03 14:10:42 -04:00
Joseph Frazier
8bd6c5da67 For man foo, try foo --help before man 3 foo
`man` without a section searches all sections, so having `foo --help`
suggested first makes more sense than adding a specific section. See
https://github.com/nvbn/thefuck/pull/562#issuecomment-251142710

However, in cases where multiple sections have man pages for `foo`,
running `man foo` could bring up the "wrong" section of man pages.
`man read` is an example of this, but that should probably be handled in
a way that still suggests `foo --help` first when there are *no* man
pages for `foo` in any section.

Closes https://github.com/nvbn/thefuck/issues/546
2016-10-03 12:03:57 -04:00
Vladimir Iakovlev
ce6b82c92d #560: Fix code style 2016-10-03 13:07:30 +02:00
Joseph Frazier
5dbbb3b1ed Add ... --help to man suggestions
This is along the lines of what @waldyrious suggested in
https://github.com/nvbn/thefuck/issues/546, but it just adds a new
suggestion rather than replacing the other ones.
2016-10-03 03:57:53 -04:00
Joseph Frazier
db4b37910d Suggest ag -Q when relevant
This detects when `ag` suggests the `-Q` option, and adds it.
2016-10-03 00:33:40 -04:00
Joseph Frazier
2b88ea11ea Suggest git diff --no-index when relevant
This makes it easier to use `git diff` on untracked files.
2016-10-03 00:05:01 -04:00
Vladimir Iakovlev
db7dffdb44 Merge pull request #559 from josephfrazier/git-push-explicit-upstream
Fix suggestions for `git push -u origin`
2016-10-02 17:21:53 +02:00
Vladimir Iakovlev
92f3c8fb52 Merge pull request #557 from OJFord/patch-1
Add sudo rule for Aura
2016-10-02 17:21:04 +02:00
Vladimir Iakovlev
7c4f0d2e55 Merge pull request #551 from scorphus/git-bisect-usage
#N/A: Add `git_bisect_usage` rule
2016-10-02 17:20:43 +02:00
Vladimir Iakovlev
d05eb0a6dc #552: Fix code style 2016-10-02 17:19:33 +02:00
Vladimir Iakovlev
cf352fd788 Merge branch 'remove-trailing-cedilla' of https://github.com/wikiti/thefuck into wikiti-remove-trailing-cedilla 2016-10-02 17:18:24 +02:00
Vladimir Iakovlev
3c1cce6bd2 Merge branch 'brew-link' of https://github.com/josephfrazier/thefuck into josephfrazier-brew-link
# Conflicts:
#	README.md
2016-10-02 17:17:15 +02:00
Vladimir Iakovlev
5d3a727d1a Merge pull request #555 from josephfrazier/brew-uninstall-force
Suggest `brew uninstall --force` when relevant
2016-10-02 17:14:54 +02:00
Vladimir Iakovlev
ea87d55771 Merge pull request #554 from JordonPhillips/aws-rule
Add new aws cli rule
2016-10-02 17:14:14 +02:00
Joseph Frazier
aa6b18d0ce Fix suggestions for git push -u origin
Resolves https://github.com/nvbn/thefuck/issues/558
2016-09-30 16:13:50 -04:00
Joseph Frazier
934eeaf4fc Test that git push -u origin still works
This was broken by https://github.com/nvbn/thefuck/pull/538
2016-09-30 16:11:46 -04:00
Ollie Ford
3ad8d52a84 Add sudo rule for Aura
When installing from Arch User Repository without root:
    aura >>= You have to use `sudo` for that.

This commit adds the slightly more general, but unambiguous, "use `sudo`".

This commit closes #543.
2016-09-30 20:32:40 +01:00
Joseph Frazier
bb5c7c576f Suggest brew link --overwrite --dry-run when relevant
This makes it easier to see which files would be overwritten by
`brew link --overwrite`
2016-09-30 15:31:25 -04:00
Joseph Frazier
17c3935078 Test brew uninstall --force suggestion 2016-09-29 17:44:07 -04:00
Joseph Frazier
a734b94fec Suggest brew uninstall --force when relevant
Resolves https://github.com/nvbn/thefuck/issues/553
2016-09-29 17:26:20 -04:00
JordonPhillips
7bf405e9c3 Add aws cli rule
This rule corrects spelling mistakes for aws cli commands and
subcommands.
2016-09-29 14:22:08 -07:00
Daniel Herzog
c3bcdd7dee Update README 2016-09-29 21:43:02 +01:00
Daniel Herzog
ad53023860 Fix encoding for Python 2.7 2016-09-29 21:41:50 +01:00
Daniel
8938323229 Fix encoding 2016-09-29 11:06:56 +01:00
Daniel
92133f77d6 Add test file 2016-09-29 10:44:17 +01:00
Daniel
64eaf96eb8 Add rule 2016-09-29 10:34:41 +01:00
Pablo Santiago Blum de Aguiar
c9264aff10 #N/A: Add git_bisect_usage rule 2016-09-27 19:42:01 -03:00
Vladimir Iakovlev
9660ec7813 Merge branch 'juzim-git-pull-uncommitted-changes' 2016-09-20 00:28:51 +02:00
Vladimir Iakovlev
9ac47d8f78 #550: Use shell.and_ 2016-09-20 00:28:09 +02:00
Julian Zimmermann
6e2b82911f Removed linebreak 2016-09-19 13:07:48 +02:00
Julian Zimmermann
af9d34c299 Added rule that stashes changed files before pulling and pops them afterwards. 2016-09-19 12:52:23 +02:00
Vladimir Iakovlev
bcc11219e6 Merge pull request #545 from waldyrious/patch-1
readme: add -H flag to second sudo pip command
2016-09-06 22:38:17 +02:00
Waldir Pimenta
495a66088b readme: add -H flag to second sudo pip command 2016-09-06 17:01:09 +01:00
Vladimir Iakovlev
4fe64e3dfa #N/A: Match git_add only if pathspec exists 2016-08-23 13:03:49 +03:00
Vladimir Iakovlev
cae76eb55f Merge branch 'kthrift-fix/prevent-cwd-tilde-dir-creation' 2016-08-22 05:45:41 +03:00
Vladimir Iakovlev
afd2ed4e51 #540: Fix code style, add test 2016-08-22 05:45:27 +03:00
Vladimir Iakovlev
1a4d74d487 Merge branch 'fix/prevent-cwd-tilde-dir-creation' of https://github.com/kthrift/thefuck into kthrift-fix/prevent-cwd-tilde-dir-creation 2016-08-22 05:20:29 +03:00
Kyle Thrift
0bd3e85e08 fix: new config dirs created in $HOME/.config/thefuck instead of $CWD
fix: use correct path in warning message when XDG_CONFIG_HOME defined
2016-08-21 15:59:16 -04:00
Vladimir Iakovlev
faeeef7666 Merge pull request #539 from blahgeek/master
prevent infinity loop while detecting shell
2016-08-21 15:22:36 +08:00
Vladimir Iakovlev
4d65d6a1df Merge pull request #538 from lukechilds/git-push-with-args
Preserve args for git_push
2016-08-21 15:20:54 +08:00
BlahGeek
cfa51506fb prevent infinity loop while detecting shell
In OS X, Process(pid=0).parent() == Process(pid=0)
2016-08-20 12:00:03 +08:00
Luke Childs
5df350254e Check arguments are preserved in git_push 2016-08-19 22:29:43 +01:00
Luke Childs
612c393ec4 Check git_push matches without specifying a branch 2016-08-19 22:19:09 +01:00
Luke Childs
4d89b3499e Preserve args for git_push 2016-08-19 22:08:30 +01:00
Vladimir Iakovlev
070bb2ff28 #N/A: Show deprecation warning when ~/.thefuck used 2016-08-14 20:02:33 +03:00
Vladimir Iakovlev
71025dff17 #N/A: Monkeypatch old pathlib even on unix 2016-08-14 15:32:53 +03:00
Vladimir Iakovlev
621b455334 #N/A: Monkeypatch pathlib on windows 2016-08-14 15:15:03 +03:00
Vladimir Iakovlev
176924c18d #N/A: Move imports from pathlib/pathlib2 to utils 2016-08-14 15:01:00 +03:00
Vladimir Iakovlev
1f75fc1ea9 #N/A: Remove deprecated thefuck-alias entry point 2016-08-14 14:43:13 +03:00
Vladimir Iakovlev
46cb87615e #N/A: Remove old-style rules support 2016-08-14 14:37:32 +03:00
Vladimir Iakovlev
c63e0d1582 Bump to 3.11 2016-08-14 13:18:43 +03:00
Vladimir Iakovlev
a3eb124033 #N/A: Disable port_already_in_use on systems without lsof 2016-08-14 08:39:26 +03:00
Vladimir Iakovlev
a1f115eb19 N/A: Add osx to travis-ci config 2016-08-14 08:18:02 +03:00
Vladimir Iakovlev
56851e8d31 #N/A: Add port_already_in_use rule 2016-08-14 06:59:26 +03:00
Vladimir Iakovlev
a8c3c2d728 #N/A: Fix tests on python 2 2016-08-13 21:46:12 +03:00
Vladimir Iakovlev
844d3af8ae #N/A: Add grunt_task_not_found rule 2016-08-13 21:13:05 +03:00
Vladimir Iakovlev
a2693bd737 #N/A: Add workon_doesnt_exists rule 2016-08-13 20:55:00 +03:00
Vladimir Iakovlev
ae3e231a5f #N/A: Add gradle_no_task rule 2016-08-13 20:31:33 +03:00
Vladimir Iakovlev
21bb439d7c #N/A: Add gradle_wrapper rule 2016-08-13 19:30:46 +03:00
Vladimir Iakovlev
efcf7da7db #N/A: Add react_native_command_unrecognized rule 2016-08-13 19:14:55 +03:00
Vladimir Iakovlev
5f79217e97 #N/A: Add slow_commands and wait_slow_command settings options 2016-08-13 18:55:11 +03:00
Vladimir Iakovlev
fdfbfc80c0 #N/A: Add npm_missing_script rule 2016-08-13 18:28:45 +03:00
Vladimir Iakovlev
b09a4e394e #N/A: Add npm_run_script rule 2016-08-13 17:38:40 +03:00
Vladimir Iakovlev
34973fe97e #N/A: Fix tests without CommandNotFound 2016-08-13 17:33:16 +03:00
Vladimir Iakovlev
379d2953c9 #N/A: Use for_app helper 2016-08-13 16:14:05 +03:00
Vladimir Iakovlev
065b350ada #N/A: Add fab_command_not_found rule 2016-08-13 16:10:12 +03:00
Vladimir Iakovlev
ca787a1cba #N/A: Ensure that command doesn't exists in no_command rule 2016-08-13 15:39:42 +03:00
Vladimir Iakovlev
4c2fc490f2 Merge branch 'master' of github.com:nvbn/thefuck 2016-08-13 15:33:12 +03:00
Vladimir Iakovlev
0c2083485d #N/A: Make apt-get rule more accurate, remove unstable tests 2016-08-13 15:30:57 +03:00
Vladimir Iakovlev
bc78c83224 Merge pull request #535 from scorphus/534-improve-open
#534: Improve open rule
2016-08-13 20:20:12 +08:00
Vladimir Iakovlev
b2a5009116 #N/A: Ensure that thefuck successfully installed in functional tests 2016-08-13 14:50:21 +03:00
Vladimir Iakovlev
087584a1e0 #N/A: Remove ability to run functional tests without docker 2016-08-13 14:11:18 +03:00
Pablo Santiago Blum de Aguiar
b6b15bf0d1 #534: Improve open rule by creating the file or dir 2016-08-12 01:09:05 -03:00
Pablo Santiago Blum de Aguiar
a169575b0f #534: Move “is arg a url?” logic to a function
This function will be used in `get_new_command`.
2016-08-12 00:53:11 -03:00
Pablo Santiago Blum de Aguiar
fbea803a9b #534: Use a stderr fixture on open rule tests 2016-08-12 00:20:12 -03:00
Vladimir Iakovlev
51415a5cb1 Merge pull request #530 from scorphus/git-branch-exists-checkout
#N/A: Use git_branch_exists rule with `checkout` too
2016-07-22 13:11:05 +03:00
Pablo Santiago Blum de Aguiar
237bc57999 #N/A: Use git_branch_exists rule with checkout too 2016-07-21 13:59:41 -03:00
nvbn
2af65071d8 Merge branch 'yeahbert-git_push_contains_work' 2016-07-07 15:42:02 +03:00
nvbn
c93b547624 #529: Minor style changes 2016-07-07 15:41:51 +03:00
Julian Zimmermann
837ca73f50 Added "contains work" error for git push 2016-07-07 11:47:51 +02:00
Vladimir Iakovlev
a3b2e6872b Merge pull request #527 from josephfrazier/brew-update
Add `brew update` to Homebrew commands
2016-06-30 01:46:36 +03:00
Joseph Frazier
29ed1800e1 Add brew update to Homebrew commands
`brew update` is implemented in shell instead of ruby, so
`_get_brew_commands` needs to list .sh files as well as .rb

Resolves https://github.com/nvbn/thefuck/issues/526
2016-06-29 15:50:01 -04:00
Vladimir Iakovlev
965c05bfdf Merge pull request #525 from tdsmith/patch-1
Avoid importing pip
2016-06-29 14:11:26 +03:00
Tim D. Smith
a7d1c725e4 Keep working if pip isn't installed
This might be installed by invoking setup.py directly.
2016-06-28 21:50:06 -07:00
Tim D. Smith
99e828d15d Avoid importing pip
pip doesn't have a stable Python API and shouldn't be `import`ed. `pkg_resources` is provided by setuptools.
2016-06-28 21:48:06 -07:00
nvbn
ae2b767a4d Merge branch 'scorphus-update-cargo-no-command' 2016-06-28 15:51:01 +03:00
nvbn
3893e0cdca #517: Little refactoring 2016-06-28 15:50:41 +03:00
nvbn
2988e4871f Merge branch 'update-cargo-no-command' of https://github.com/scorphus/thefuck into scorphus-update-cargo-no-command 2016-06-28 15:49:04 +03:00
nvbn
d5e333b727 Bump to 3.10 2016-06-28 03:30:27 +03:00
nvbn
1755bcd1b5 #524: Run functional tests only with python 3.5 2016-06-28 03:05:42 +03:00
nvbn
f773b57bea #511: Add ln_s_order rule 2016-06-28 03:00:00 +03:00
Vladimir Iakovlev
5866ea8433 Merge pull request #524 from nvbn/fix-func-tests-on-travis-ci
Fix functional tests on travis-ci
2016-06-28 00:38:58 +03:00
nvbn
729508e581 #524: Add commandnotfound to travis config 2016-06-28 00:38:38 +03:00
nvbn
1b7c8b5498 #524: Don't wait for prompt in zsh 2016-06-28 00:22:25 +03:00
nvbn
9b6cd0cd7b #524: Exit with 1 if no fixed command selected 2016-06-28 00:22:04 +03:00
nvbn
77ea630d84 #524: Remove skip_without_docker hacks 2016-06-28 00:11:56 +03:00
nvbn
917c6ac887 #524: Fix tcsh encoding 2016-06-28 00:00:49 +03:00
nvbn
8bea63eb23 #524: Remove unned dependencies from .travis.yml 2016-06-27 23:48:26 +03:00
nvbn
2bf21d9f0e #524: Wait for prompt in zsh tests 2016-06-27 23:48:06 +03:00
nvbn
e2f66cb26b #N/A: Enable docker service 2016-06-27 23:18:38 +03:00
Vladimir Iakovlev
ff1ee979f0 Merge pull request #518 from mklkj/master
Fix a typo
2016-06-27 23:15:41 +03:00
Vladimir Iakovlev
25343dbfb4 Merge pull request #523 from MattKotsenas/refactor/powershell-config
Add semi-colons in powershell alias
2016-06-27 23:15:14 +03:00
Vladimir Iakovlev
ea3671f98c Merge pull request #521 from b1101/master
ui: accept 'q' as quit character
2016-06-27 23:14:16 +03:00
nvbn
4584903beb #N/A: Temporary disable functional tests on travis-ci 2016-06-27 23:13:57 +03:00
nvbn
990ba57159 #N/A: Disable zsh test_with_confirmation without docker 2016-06-27 23:12:05 +03:00
Matt Kotsenas
16c110823d Add semi-colons in powershell alias
Add semi-colons in powershell alias so that if line breaks get lost the
function can still be invoked directly. This makes it possible to add
thefuck to the current session by running

    iex "$(thefuck --alias)"

which mirrors the eval syntax in bash
2016-06-27 13:29:24 -04:00
Romans Volosatovs
01418526b4 ui: accept 'q' as quit character
'q' is a standard character used in traditional UNIX environment
for 'quit', so it makes sense to support it in my opinion
2016-06-25 12:31:08 +02:00
mklkj
d2845a0d2e Fix a typo 2016-06-23 14:28:37 +02:00
Pablo Santiago Blum de Aguiar
2c1666abc4 #N/A: Update cargo_no_command rule to support current Cargo 2016-06-18 13:50:59 -03:00
nvbn
42853f41bb Merge branch 'TheJakeSchmidt-add-git_rebase_continue_no_changes' 2016-06-15 19:29:14 +04:00
nvbn
5f11ecc4f8 #515: Allow less strict check, use git_support 2016-06-15 19:28:58 +04:00
Jake
4bd4c0f731 Add a new rule git_rebase_no_changes. 2016-06-11 19:20:33 -04:00
Vladimir Iakovlev
b8c5433dc4 Merge pull request #513 from scorphus/cleanup_
#N/A: Cleanup shells/fish.py a bit
2016-06-06 06:46:36 +03:00
Pablo Santiago Blum de Aguiar
e2883430bc #N/A: Cleanup shells/fish.py a bit 2016-06-04 23:18:30 -03:00
Vladimir Iakovlev
a4b690369c Merge pull request #506 from asergi/pathlib2
Switch from pathlib to pathlib2
2016-05-17 02:23:03 +03:00
Vladimir Iakovlev
6bbd680e56 Merge pull request #507 from scorphus/assert-warns
#N/A: Assert deprecated warnings are raised
2016-05-17 02:22:34 +03:00
Pablo Santiago Blum de Aguiar
e5f8e9c0de #N/A: Assert deprecated warnings are raised 2016-05-15 17:04:09 -03:00
Alessio Sergi
ebf1ea88f5 Switch from pathlib to pathlib2
The pathlib backport module is no longer maintained. The development
has moved to the pathlib2 module instead.

Quoting from the pathlib's README:
"Attention: this backport module isn't maintained anymore. If you want
to report issues or contribute patches, please consider the pathlib2
project instead."
2016-05-12 17:17:17 +02:00
Vladimir Iakovlev
d2b0b6e8ec Merge pull request #505 from scorphus/decode-bin
#504: Decode binary name if on Python 2
2016-05-12 04:47:57 +03:00
Pablo Santiago Blum de Aguiar
561eb12c08 #504: UTF8-decode bin names if on Python 2
Fix #504
2016-05-11 13:31:57 -03:00
Pablo Santiago Blum de Aguiar
ed38fedf26 #504: Mock get_all_executables internals instead 2016-05-11 02:04:05 -03:00
nvbn
15bcd7f03f #501: Deprecate installation script 2016-05-09 18:54:40 +03:00
Vladimir Iakovlev
9e39bcd55c Merge pull request #503 from scorphus/readme-osx
#501: Split Ubuntu and OS X installation instructions
2016-05-09 15:14:05 +03:00
Pablo Santiago Blum de Aguiar
cfa73f10d6 #501: Split Ubuntu and OS X installation instructions 2016-05-03 22:54:22 -03:00
Vladimir Iakovlev
c3709682d5 Merge pull request #500 from scorphus/history-merge
#495: Alter history only when configured to do so
2016-05-03 13:18:12 +03:00
Pablo Santiago Blum de Aguiar
96f7e53aa2 #495: Alter history only when configured to do so 2016-04-30 18:39:08 -03:00
Pablo Santiago Blum de Aguiar
d1f55603fe #495: Merge history only when alter_history is set 2016-04-29 23:21:28 -03:00
189 changed files with 4169 additions and 760 deletions

View File

@@ -1,28 +1,51 @@
language: python
sudo: false
python:
- "3.5"
- "3.4"
- "3.3"
- "2.7"
matrix:
include:
- os: linux
dist: trusty
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:
apt:
sources:
- fish-shell/release-2
packages:
- bash
- zsh
- fish
- tcsh
- pandoc
- git
install:
- python-commandnotfound
- python3-commandnotfound
before_install:
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then brew update ; fi
- 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
- 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:
- pip install -Ur requirements.txt
- python setup.py develop
- rm -rf build
script:
- flake8
- 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
after_success: coveralls
- export RUN_TESTS="coverage run --source=thefuck,tests -m py.test -v --capture=sys tests"
- 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:
- if [[ $TRAVIS_PYTHON_VERSION == 3.6 && $TRAVIS_OS_NAME != "osx" ]]; then coveralls; fi

View File

@@ -94,20 +94,25 @@ Reading package lists... Done
- pip
- python-dev
## Installation [*experimental*]
## Installation
On Ubuntu and OS X you can install `The Fuck` with installation script:
On OS X you can install `The Fuck` with [Homebrew][homebrew]:
```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
pip3 install --user thefuck
```
Install `The Fuck` with `pip`:
On other systems you can install `The Fuck` with `pip`:
```bash
sudo -H pip install thefuck
pip install --user thefuck
```
[Or using an OS package manager (OS X, Ubuntu, Arch).](https://github.com/nvbn/thefuck/wiki/Installation)
@@ -115,9 +120,9 @@ sudo -H pip install thefuck
You should place this command in your `.bash_profile`, `.bashrc`, `.zshrc` or other startup script:
```bash
eval "$(thefuck --alias)"
eval $(thefuck --alias)
# You can use whatever you want as an alias, like for Mondays:
eval "$(thefuck --alias FUCK)"
eval $(thefuck --alias FUCK)
```
[Or in your shell config (Bash, Zsh, Fish, Powershell, tcsh).](https://github.com/nvbn/thefuck/wiki/Shell-aliases)
@@ -125,11 +130,16 @@ eval "$(thefuck --alias FUCK)"
Changes will be available only in a new shell session.
To make them available immediately, run `source ~/.bashrc` (or your shell config file like `.zshrc`).
If you want separate alias for running fixed command without confirmation you can use alias like:
```bash
alias fuck-it='export THEFUCK_REQUIRE_CONFIRMATION=False; fuck; export THEFUCK_REQUIRE_CONFIRMATION=True'
```
## Update
```bash
sudo pip install thefuck --upgrade
pip install --user thefuck --upgrade
```
**Aliases changed in 1.34.**
@@ -139,6 +149,8 @@ sudo pip install thefuck --upgrade
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:
* `ag_literal` &ndash; adds `-Q` to `ag` when suggested;
* `aws_cli` &ndash; fixes misspelled commands like `aws dynamdb scan`;
* `cargo` &ndash; runs `cargo build` instead of `cargo`;
* `cargo_no_command` &ndash; fixes wrongs commands like `cargo buid`;
* `cd_correction` &ndash; spellchecks and correct failed cd commands;
@@ -154,56 +166,86 @@ using the matched rule and runs it. Rules enabled by default are as follows:
* `django_south_merge` &ndash; adds `--merge` to inconsistent django south migration;
* `docker_not_command` &ndash; fixes wrong docker commands like `docker tags`;
* `dry` &ndash; fixes repetitions like `git git push`;
* `fab_command_not_found` &ndash; fix misspelled fabric commands;
* `fix_alt_space` &ndash; replaces Alt+Space with Space character;
* `fix_file` &ndash; opens a file with an error in your `$EDITOR`;
* `gem_unknown_command` &ndash; fixes wrong `gem` commands;
* `git_add` &ndash; fixes *"pathspec 'foo' did not match any file(s) known to git."*;
* `git_add_force` &ndash; adds `--force` to `git add <pathspec>...` when paths are .gitignore'd;
* `git_bisect_usage` &ndash; fixes `git bisect strt`, `git bisect goood`, `git bisect rset`, etc. when bisecting;
* `git_branch_delete` &ndash; changes `git branch -d` to `git branch -D`;
* `git_branch_exists` &ndash; offers `git branch -d foo`, `git branch -D foo` or `git checkout foo` when creating a branch that already exists;
* `git_branch_list` &ndash; catches `git branch list` in place of `git branch` and removes created branch;
* `git_checkout` &ndash; fixes branch name or creates new branch;
* `git_diff_no_index` &ndash; adds `--no-index` to previous `git diff` on untracked files;
* `git_diff_staged` &ndash; adds `--staged` to previous `git diff` with unexpected output;
* `git_fix_stash` &ndash; fixes `git stash` commands (misspelled subcommand and missing `save`);
* `git_flag_after_filename` &ndash; fixes `fatal: bad flag '...' after filename`
* `git_help_aliased` &ndash; fixes `git help <alias>` commands replacing <alias> with the aliased command;
* `git_not_command` &ndash; fixes wrong git commands like `git brnch`;
* `git_pull` &ndash; sets upstream before executing previous `git pull`;
* `git_pull_clone` &ndash; clones instead of pulling when the repo does not exist;
* `git_pull_uncommitted_changes` &ndash; stashes changes before pulling and pops them afterwards;
* `git_push` &ndash; adds `--set-upstream origin $branch` to previous failed `git push`;
* `git_push_pull` &ndash; runs `git pull` when `push` was rejected;
* `git_push_without_commits` &ndash; Creates an initial commit if you forget and only `git add .`, when setting up a new project;
* `git_rebase_no_changes` &ndash; runs `git rebase --skip` instead of `git rebase --continue` when there are no changes;
* `git_rm_local_modifications` &ndash; adds `-f` or `--cached` when you try to `rm` a locally modified file;
* `git_rm_recursive` &ndash; adds `-r` when you try to `rm` a directory;
* `git_rm_staged` &ndash; adds `-f` or `--cached` when you try to `rm` a file with staged changes
* `git_rebase_merge_dir` &ndash; offers `git rebase (--continue | --abort | --skip)` or removing the `.git/rebase-merge` dir when a rebase is in progress;
* `git_remote_seturl_add` &ndash; runs `git remote add` when `git remote set_url` on nonexistant remote;
* `git_stash` &ndash; stashes you local modifications before rebasing or switching branch;
* `git_stash` &ndash; stashes your local modifications before rebasing or switching branch;
* `git_stash_pop` &ndash; adds your local modifications before popping stash, then resets;
* `git_tag_force` &ndash; adds `--force` to `git tag <tagname>` when the tag already exists;
* `git_two_dashes` &ndash; adds a missing dash to commands like `git commit -amend` or `git rebase -continue`;
* `go_run` &ndash; appends `.go` extension when compiling/running Go programs;
* `gradle_no_task` &ndash; fixes not found or ambiguous `gradle` task;
* `gradle_wrapper` &ndash; replaces `gradle` with `./gradlew`;
* `grep_arguments_order` &ndash; fixes grep arguments order for situations like `grep -lir . test`;
* `grep_recursive` &ndash; adds `-r` when you trying to `grep` directory;
* `grunt_task_not_found` &ndash; fixes misspelled `grunt` commands;
* `gulp_not_task` &ndash; fixes misspelled `gulp` tasks;
* `has_exists_script` &ndash; prepends `./` when script/binary exists;
* `heroku_not_command` &ndash; fixes wrong `heroku` commands like `heroku log`;
* `history` &ndash; tries to replace command with most similar command from history;
* `hostscli` &ndash; tries to fix `hostscli` usage;
* `ifconfig_device_not_found` &ndash; fixes wrong device names like `wlan0` to `wlp2s0`;
* `java` &ndash; removes `.java` extension when running Java programs;
* `javac` &ndash; appends missing `.java` when compiling Java files;
* `lein_not_task` &ndash; fixes wrong `lein` tasks like `lein rpl`;
* `ln_no_hard_link` &ndash; catches hard link creation on directories, suggest symbolic link;
* `ln_s_order` &ndash; fixes `ln -s` arguments order;
* `ls_all` &ndash; adds `-A` to `ls` when output is empty;
* `ls_lah` &ndash; adds `-lah` to `ls`;
* `man` &ndash; changes manual section;
* `man_no_space` &ndash; fixes man commands without spaces, for example `mandiff`;
* `mercurial` &ndash; fixes wrong `hg` commands;
* `missing_space_before_subcommand` &ndash; fixes command with missing space like `npminstall`;
* `mkdir_p` &ndash; adds `-p` when you trying to create directory without parent;
* `mvn_no_command` &ndash; adds `clean package` to `mvn`;
* `mvn_unknown_lifecycle_phase` &ndash; fixes misspelled lifecycle phases with `mvn`;
* `npm_missing_script` &ndash; fixes `npm` custom script name in `npm run-script <script>`;
* `npm_run_script` &ndash; adds missing `run-script` for custom `npm` scripts;
* `npm_wrong_command` &ndash; fixes wrong npm commands like `npm urgrade`;
* `no_command` &ndash; fixes wrong console commands, for example `vom/vim`;
* `no_such_file` &ndash; creates missing directories with `mv` and `cp` commands;
* `open` &ndash; prepends `http` to address passed to `open`;
* `open` &ndash; either prepends `http://` to address passed to `open` or create a new file or directory and passes it to `open`;
* `pip_unknown_command` &ndash; fixes wrong `pip` commands, for example `pip instatl/pip install`;
* `port_already_in_use` &ndash; kills process that bound port;
* `python_command` &ndash; prepends `python` when you trying to run not executable/without `./` python script;
* `python_execute` &ndash; appends missing `.py` when executing Python files;
* `quotation_marks` &ndash; fixes uneven usage of `'` and `"` when containing args';
* `path_from_history` &ndash; replaces not found path with similar absolute path from history;
* `react_native_command_unrecognized` &ndash; fixes unrecognized `react-native` commands;
* `remove_trailing_cedilla` &ndash; remove trailling cedillas `ç`, a common typo for european keyboard layouts;
* `rm_dir` &ndash; adds `-rf` when you trying to remove directory;
* `scm_correction` &ndash; corrects wrong scm like `hg log` to `git log`;
* `sed_unterminated_s` &ndash; adds missing '/' to `sed`'s `s` commands;
* `sl_ls` &ndash; changes `sl` to `ls`;
* `ssh_known_hosts` &ndash; removes host from `known_hosts` on warning;
* `sudo` &ndash; prepends `sudo` to previous command if it failed because of permissions;
* `sudo_command_from_user_path` &ndash; runs commands from users `$PATH` with `sudo`;
* `switch_lang` &ndash; switches command from your local layout to en;
* `systemctl` &ndash; correctly orders parameters of confusing `systemctl`;
* `test.py` &ndash; runs `py.test` instead of `test.py`;
@@ -213,7 +255,12 @@ using the matched rule and runs it. Rules enabled by default are as follows:
* `tmux` &ndash; fixes `tmux` commands;
* `unknown_command` &ndash; fixes hadoop hdfs-style "unknown command", for example adds missing '-' to the command on `hdfs dfs ls`;
* `vagrant_up` &ndash; starts up the vagrant instance;
* `whois` &ndash; fixes `whois` command.
* `whois` &ndash; fixes `whois` command;
* `workon_doesnt_exists` &ndash; fixes `virtualenvwrapper` env name os suggests to create new.
* `yarn_alias` &ndash; fixes aliased `yarn` commands like `yarn ls`;
* `yarn_command_not_found` &ndash; fixes misspelled `yarn` commands;
* `yarn_command_replaced` &ndash; fixes replaced `yarn` commands;
* `yarn_help` &ndash; makes it easier to open `yarn` documentation;
Enabled by default only on specific platforms:
@@ -221,6 +268,8 @@ Enabled by default only on specific platforms:
* `apt_get_search` &ndash; changes trying to search using `apt-get` with searching using `apt-cache`;
* `apt_invalid_operation` &ndash; fixes invalid `apt` and `apt-get` calls, like `apt-get isntall vim`;
* `brew_install` &ndash; fixes formula name for `brew install`;
* `brew_link` &ndash; adds `--overwrite --dry-run` if linking fails;
* `brew_uninstall` &ndash; adds `--force` to `brew uninstall` if multiple versions were installed;
* `brew_unknown_command` &ndash; fixes wrong brew commands, for example `brew docto/brew doctor`;
* `brew_update_formula` &ndash; turns `brew update <formula>` into `brew upgrade <formula>`;
* `brew_upgrade` &ndash; appends `--all` to `brew upgrade` as per Homebrew's new behaviour;
@@ -249,7 +298,9 @@ side_effect(old_command: Command, fixed_command: str) -> None
```
and optional `enabled_by_default`, `requires_output` and `priority` variables.
`Command` has three attributes: `script`, `stdout` and `stderr`.
`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`.
`settings` is a special object filled with `~/.config/thefuck/settings.py` and values from env ([see more below](#settings)).
@@ -292,7 +343,9 @@ The Fuck has a few settings parameters which can be changed in `$XDG_CONFIG_HOME
* `priority` &ndash; dict with rules priorities, rule with lower `priority` will be matched first;
* `debug` &ndash; enables debug output, by default `False`;
* `history_limit` &ndash; numeric value of how many history commands will be scanned, like `2000`;
* `alter_history` &ndash; push fixed command to history, by default `True`.
* `alter_history` &ndash; push fixed command to history, by default `True`;
* `wait_slow_command` &ndash; max amount of time in seconds for getting previous command output if it in `slow_commands` list;
* `slow_commands` &ndash; list of slow commands.
Example of `settings.py`:
@@ -304,6 +357,9 @@ wait_command = 10
no_colors = False
priority = {'sudo': 100, 'no_command': 9999}
debug = False
history_limit = 9999
wait_slow_command = 20
slow_commands = ['react-native', 'gradle']
```
Or via environment variables:
@@ -317,7 +373,9 @@ Or via environment variables:
rule with lower `priority` will be matched first;
* `THEFUCK_DEBUG` &ndash; enables debug output, `true/false`;
* `THEFUCK_HISTORY_LIMIT` &ndash; how many history commands will be scanned, like `2000`;
* `THEFUCK_ALTER_HISTORY` &ndash; push fixed command to history `true/false`.
* `THEFUCK_ALTER_HISTORY` &ndash; push fixed command to history `true/false`;
* `THEFUCK_WAIT_SLOW_COMMAND` &ndash; max amount of time in seconds for getting previous command output if it in `slow_commands` list;
* `THEFUCK_SLOW_COMMANDS` &ndash; list of slow commands, like `lein:gradle`.
For example:
@@ -340,6 +398,12 @@ pip install -r requirements.txt
python setup.py develop
```
Run code style checks:
```bash
flake8
```
Run unit tests:
```bash
@@ -365,11 +429,12 @@ 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-badge]: https://travis-ci.org/nvbn/thefuck.svg?branch=master
[travis-link]: https://travis-ci.org/nvbn/thefuck
[appveyor-badge]: https://img.shields.io/appveyor/ci/nvbn/thefuck.svg?label=windows%20build
[appveyor-badge]: https://ci.appveyor.com/api/projects/status/1sskj4imj02um0gu/branch/master?svg=true
[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/

View File

@@ -6,6 +6,7 @@ environment:
- PYTHON: "C:/Python33"
- PYTHON: "C:/Python34"
- PYTHON: "C:/Python35"
- PYTHON: "C:/Python36"
init:
- "ECHO %PYTHON%"
@@ -19,4 +20,5 @@ install:
- "%PYTHON%/Scripts/pip.exe install -U -r requirements.txt"
test_script:
- "%PYTHON%/python.exe -m flake8"
- "%PYTHON%/Scripts/py.test.exe -sv"

View File

@@ -1,61 +1,4 @@
#!/bin/sh
should_add_alias () {
[ -f $1 ] && ! grep -q thefuck $1
}
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
echo "Installation script is deprecated!"
echo "For installation instruction please visit https://github.com/nvbn/thefuck"

View File

@@ -1,4 +1,5 @@
pip
flake8
pytest
mock
pytest-mock

View File

@@ -1,13 +1,16 @@
#!/usr/bin/env python
from setuptools import setup, find_packages
import pip
import pkg_resources
import sys
import os
if int(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)
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'):
import pypandoc
@@ -26,10 +29,10 @@ elif (3, 0) < version < (3, 3):
' ({}.{} detected).'.format(*version))
sys.exit(-1)
VERSION = '3.9'
VERSION = '3.17'
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']}
setup(name='thefuck',
@@ -48,5 +51,4 @@ setup(name='thefuck',
extras_require=extras_require,
entry_points={'console_scripts': [
'thefuck = thefuck.main:main',
'thefuck-alias = thefuck.main:print_alias',
'fuck = thefuck.main:how_to_configure_alias']})
'fuck = thefuck.not_configured:main']})

View File

@@ -1,13 +1,13 @@
from pathlib import Path
import pytest
from thefuck import shells
from thefuck import conf, const
from thefuck.system import Path
shells.shell = shells.Generic()
def pytest_addoption(parser):
"""Adds `--run-without-docker` argument."""
"""Adds `--enable-functional` argument."""
group = parser.getgroup("thefuck")
group.addoption('--enable-functional', action="store_true", default=False,
help="Enable functional tests")

View File

@@ -81,6 +81,5 @@ def without_confirmation(proc, TIMEOUT):
def how_to_configure(proc, TIMEOUT):
proc.sendline(u'unalias fuck')
proc.sendline(u'fuck')
assert proc.expect([TIMEOUT, u"alias isn't configured"])

View File

@@ -3,26 +3,19 @@ from tests.functional.plots import with_confirmation, without_confirmation, \
refuse_with_confirmation, history_changed, history_not_changed, \
select_command_with_arrows, how_to_configure
containers = ((u'thefuck/ubuntu-python3-bash',
u'''FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python3 python3-pip python3-dev git
RUN pip3 install -U setuptools
RUN ln -s /usr/bin/pip3 /usr/bin/pip''',
containers = ((u'thefuck/python3-bash',
u'FROM python:3',
u'bash'),
(u'thefuck/ubuntu-python2-bash',
u'''FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python python-pip python-dev git
RUN pip2 install -U pip setuptools''',
(u'thefuck/python2-bash',
u'FROM python:2',
u'bash'))
@pytest.fixture(params=containers)
def proc(request, spawnu, run_without_docker):
def proc(request, spawnu, TIMEOUT):
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'eval $(thefuck --alias)')
proc.sendline(u'echo > $HISTFILE')
@@ -30,38 +23,30 @@ def proc(request, spawnu, run_without_docker):
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_with_confirmation(proc, TIMEOUT, run_without_docker):
def test_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.once_without_docker
def test_select_command_with_arrows(proc, TIMEOUT, run_without_docker):
def test_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.once_without_docker
def test_refuse_with_confirmation(proc, TIMEOUT, run_without_docker):
def test_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.once_without_docker
def test_without_confirmation(proc, TIMEOUT, run_without_docker):
def test_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.once_without_docker
def test_how_to_configure_alias(proc, TIMEOUT):
proc.sendline('unset -f fuck')
how_to_configure(proc, TIMEOUT)

View File

@@ -2,52 +2,50 @@ import pytest
from tests.functional.plots import with_confirmation, without_confirmation, \
refuse_with_confirmation, select_command_with_arrows
containers = (('thefuck/ubuntu-python3-fish',
u'''FROM ubuntu:latest
containers = (('thefuck/python3-fish',
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 install -yy python3 python3-pip python3-dev fish git
RUN pip3 install -U setuptools
RUN ln -s /usr/bin/pip3 /usr/bin/pip
RUN apt-get install -yy fish''',
u'fish'),
('thefuck/ubuntu-python2-fish',
u'''FROM ubuntu:latest
('thefuck/python2-fish',
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 install -yy python python-pip python-dev git
RUN pip2 install -U pip setuptools
RUN apt-get install -yy fish''',
u'fish'))
@pytest.fixture(params=containers)
def proc(request, spawnu):
def proc(request, spawnu, TIMEOUT):
proc = spawnu(*request.param)
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'fish')
return proc
@pytest.mark.functional
@pytest.mark.skip_without_docker
def test_with_confirmation(proc, TIMEOUT):
with_confirmation(proc, TIMEOUT)
@pytest.mark.functional
@pytest.mark.skip_without_docker
def test_select_command_with_arrows(proc, TIMEOUT):
select_command_with_arrows(proc, TIMEOUT)
@pytest.mark.functional
@pytest.mark.skip_without_docker
def test_refuse_with_confirmation(proc, TIMEOUT):
refuse_with_confirmation(proc, TIMEOUT)
@pytest.mark.functional
@pytest.mark.skip_without_docker
def test_without_confirmation(proc, TIMEOUT):
without_confirmation(proc, TIMEOUT)

View File

@@ -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'])

View File

@@ -2,11 +2,7 @@ import pytest
import time
dockerfile = u'''
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python3 python3-pip python3-dev git
RUN pip3 install -U setuptools
RUN ln -s /usr/bin/pip3 /usr/bin/pip
FROM python:3
RUN adduser --disabled-password --gecos '' test
ENV SEED "{seed}"
WORKDIR /src
@@ -40,10 +36,9 @@ def plot(proc, TIMEOUT):
@pytest.mark.functional
@pytest.mark.skip_without_docker
@pytest.mark.benchmark(min_rounds=10)
def test_performance(spawnu, TIMEOUT, benchmark):
proc = spawnu(u'thefuck/ubuntu-python3-bash-performance',
proc = spawnu(u'thefuck/python3-bash-performance',
dockerfile, u'bash')
proc.sendline(u'pip install /src')
proc.sendline(u'su test')

View File

@@ -2,53 +2,45 @@ import pytest
from tests.functional.plots import with_confirmation, without_confirmation, \
refuse_with_confirmation, select_command_with_arrows
containers = (('thefuck/ubuntu-python3-tcsh',
u'''FROM ubuntu:latest
containers = (('thefuck/python3-tcsh',
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
RUN apt-get install -yy tcsh''',
u'tcsh'),
('thefuck/ubuntu-python2-tcsh',
u'''FROM ubuntu:latest
('thefuck/python2-tcsh',
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
RUN apt-get install -yy tcsh''',
u'tcsh'))
@pytest.fixture(params=containers)
def proc(request, spawnu, run_without_docker):
def proc(request, spawnu, TIMEOUT):
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'setenv PYTHONIOENCODING utf8')
proc.sendline(u'eval `thefuck --alias`')
return proc
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_with_confirmation(proc, TIMEOUT):
with_confirmation(proc, TIMEOUT)
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_select_command_with_arrows(proc, TIMEOUT):
select_command_with_arrows(proc, TIMEOUT)
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_refuse_with_confirmation(proc, TIMEOUT):
refuse_with_confirmation(proc, TIMEOUT)
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_without_confirmation(proc, TIMEOUT):
without_confirmation(proc, TIMEOUT)

View File

@@ -3,28 +3,23 @@ from tests.functional.plots import with_confirmation, without_confirmation, \
refuse_with_confirmation, history_changed, history_not_changed, \
select_command_with_arrows, how_to_configure
containers = (('thefuck/ubuntu-python3-zsh',
u'''FROM ubuntu:latest
containers = (('thefuck/python3-zsh',
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
RUN apt-get install -yy zsh''',
u'zsh'),
('thefuck/ubuntu-python2-zsh',
u'''FROM ubuntu:latest
('thefuck/python2-zsh',
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
RUN apt-get install -yy zsh''',
u'zsh'))
@pytest.fixture(params=containers)
def proc(request, spawnu, run_without_docker):
def proc(request, spawnu, TIMEOUT):
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'export HISTFILE=~/.zsh_history')
proc.sendline(u'echo > $HISTFILE')
@@ -35,34 +30,30 @@ def proc(request, spawnu, run_without_docker):
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_with_confirmation(proc, TIMEOUT):
with_confirmation(proc, TIMEOUT)
history_changed(proc, TIMEOUT, u'echo test')
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_select_command_with_arrows(proc, TIMEOUT):
select_command_with_arrows(proc, TIMEOUT)
history_changed(proc, TIMEOUT, u'git help')
@pytest.mark.functional
@pytest.mark.skip_without_docker
def test_refuse_with_confirmation(proc, TIMEOUT):
refuse_with_confirmation(proc, TIMEOUT)
history_not_changed(proc, TIMEOUT)
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_without_confirmation(proc, TIMEOUT):
without_confirmation(proc, TIMEOUT)
history_changed(proc, TIMEOUT, u'echo test')
@pytest.mark.functional
@pytest.mark.once_without_docker
def test_how_to_configure_alias(proc, TIMEOUT):
proc.sendline(u'unfunction fuck')
how_to_configure(proc, TIMEOUT)

View 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

View File

@@ -1,68 +1,43 @@
import pytest
from mock import Mock, patch
from thefuck.rules import apt_get
from thefuck.rules.apt_get import match, get_new_command
from tests.utils import Command
# python-commandnotfound is available in ubuntu 14.04+
@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', [
@pytest.mark.parametrize('command, packages', [
(Command(script='vim', stderr='vim: command not found'),
[('vim', 'main'), ('vim-tiny', 'main')]),
(Command(script='sudo vim', stderr='vim: command not found'),
[('vim', 'main'), ('vim-tiny', 'main')]),
(Command(script='vim', stderr="The program 'vim' is currently not installed. You can install it by typing: sudo apt install vim"),
[('vim', 'main'), ('vim-tiny', 'main')])])
@patch('thefuck.rules.apt_get.CommandNotFound', create=True)
@patch.multiple(apt_get, create=True, apt_get='apt_get')
def test_match_mocked(cmdnf_mock, command, return_value):
get_packages = Mock(return_value=return_value)
cmdnf_mock.CommandNotFound.return_value = Mock(getPackages=get_packages)
def test_match(mocker, command, packages):
mocker.patch('thefuck.rules.apt_get.which', return_value=None)
mock = mocker.patch('thefuck.rules.apt_get.command_not_found',
create=True)
mock.getPackages.return_value = packages
assert match(command)
assert cmdnf_mock.CommandNotFound.called
assert get_packages.called
# python-commandnotfound is available in ubuntu 14.04+
@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='a_bad_cmd', stderr='a_bad_cmd: command not found'),
Command(script='vim', stderr=''), Command()])
def test_not_match(command):
@pytest.mark.parametrize('command, packages, which', [
(Command(script='a_bad_cmd', stderr='a_bad_cmd: command not found'),
[], 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)
@pytest.mark.parametrize('command, return_value', [
(Command(script='a_bad_cmd', stderr='a_bad_cmd: command not found'), []),
(Command(script='vim', stderr=''), []), (Command(), [])])
@patch('thefuck.rules.apt_get.CommandNotFound', create=True)
@patch.multiple(apt_get, create=True, apt_get='apt_get')
def test_not_match_mocked(cmdnf_mock, command, return_value):
get_packages = Mock(return_value=return_value)
cmdnf_mock.CommandNotFound.return_value = Mock(getPackages=get_packages)
assert not match(command)
# python-commandnotfound is available in ubuntu 14.04+
@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', [
@pytest.mark.parametrize('command, new_command, packages', [
(Command('vim'), 'sudo apt-get install vim && vim',
[('vim', 'main'), ('vim-tiny', 'main')]),
(Command('convert'), 'sudo apt-get install imagemagick && convert',
@@ -73,9 +48,8 @@ def test_get_new_command(command, new_command):
(Command('sudo convert'), 'sudo apt-get install imagemagick && sudo convert',
[('imagemagick', 'main'),
('graphicsmagick-imagemagick-compat', 'universe')])])
@patch('thefuck.rules.apt_get.CommandNotFound', create=True)
@patch.multiple(apt_get, create=True, apt_get='apt_get')
def test_get_new_command_mocked(cmdnf_mock, command, new_command, return_value):
get_packages = Mock(return_value=return_value)
cmdnf_mock.CommandNotFound.return_value = Mock(getPackages=get_packages)
def test_get_new_command(mocker, command, new_command, packages):
mock = mocker.patch('thefuck.rules.apt_get.command_not_found',
create=True)
mock.getPackages.return_value = packages
assert get_new_command(command) == new_command

101
tests/rules/test_aws_cli.py Normal file
View 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

View 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

View 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

View File

@@ -21,8 +21,8 @@ def test_match(brew_unknown_cmd):
def test_get_new_command(brew_unknown_cmd, brew_unknown_cmd2):
assert get_new_command(Command('brew inst', stderr=brew_unknown_cmd)) \
== ['brew list', 'brew install', 'brew uninstall']
assert (get_new_command(Command('brew inst', stderr=brew_unknown_cmd))
== ['brew list', 'brew install', 'brew uninstall'])
cmds = get_new_command(Command('brew instaa', stderr=brew_unknown_cmd2))
assert 'brew install' in cmds

View File

@@ -3,19 +3,26 @@ from thefuck.rules.cargo_no_command import match, get_new_command
from tests.utils import Command
no_such_subcommand = """No such subcommand
no_such_subcommand_old = """No such subcommand
Did you mean `build`?
"""
no_such_subcommand = """error: no such subcommand
\tDid you mean `build`?
"""
@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):
assert match(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):
assert get_new_command(command) == new_command

View File

@@ -48,9 +48,9 @@ def test_match(composer_not_command, composer_not_command_one_of_this):
def test_get_new_command(composer_not_command, composer_not_command_one_of_this):
assert get_new_command(Command('composer udpate',
stderr=composer_not_command)) \
== 'composer update'
assert get_new_command(
Command('composer pdate', stderr=composer_not_command_one_of_this)) \
== 'composer selfupdate'
assert (get_new_command(Command('composer udpate',
stderr=composer_not_command))
== 'composer update')
assert (get_new_command(Command('composer pdate',
stderr=composer_not_command_one_of_this))
== 'composer selfupdate')

View File

@@ -2,7 +2,7 @@ import os
import pytest
import tarfile
from thefuck.rules.dirty_untar import match, get_new_command, side_effect, \
tar_extensions
tar_extensions # noqa: E126
from tests.utils import Command
@@ -33,6 +33,7 @@ def tar_error(tmpdir):
return fixture
parametrize_extensions = pytest.mark.parametrize('ext', tar_extensions)
# (filename as typed by the user, unquoted filename, quoted filename as per shells.quote)

View File

@@ -37,7 +37,7 @@ south.exceptions.GhostMigrations:
! I'm not trusting myself; either fix this yourself by fiddling
! with the south_migrationhistory table, or pass --delete-ghost-migrations
! to South to have it delete ALL of these records (this may not be good).
'''
''' # noqa
def test_match(stderr):

View File

@@ -39,5 +39,5 @@ def test_match(stderr):
def test_get_new_command():
assert get_new_command(Command('./manage.py migrate auth')) \
== './manage.py migrate auth --merge'
assert (get_new_command(Command('./manage.py migrate auth'))
== './manage.py migrate auth --merge')

View 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

View File

@@ -18,5 +18,5 @@ def test_match():
def test_get_new_command():
""" Replace the Alt+Space character by a simple space """
assert get_new_command(Command(u'ps -ef | grep foo'))\
== 'ps -ef | grep foo'
assert (get_new_command(Command(u'ps -ef | grep foo'))
== 'ps -ef | grep foo')

View File

@@ -191,7 +191,7 @@ E NameError: name 'mocker' is not defined
/home/thefuck/tests/rules/test_fix_file.py:218: NameError
""", ''),
)
) # noqa
@pytest.mark.parametrize('test', tests)
@@ -227,10 +227,6 @@ def test_get_new_command(mocker, monkeypatch, test):
mocker.patch('os.path.isfile', return_value=True)
monkeypatch.setenv('EDITOR', 'dummy_editor')
cmd = Command(script=test[0], stdout=test[4], stderr=test[5])
#assert (get_new_command(cmd, Settings({})) ==
# 'dummy_editor {} +{} && {}'.format(test[1], test[2], test[0]))
@pytest.mark.parametrize('test', tests)
@pytest.mark.usefixtures('no_memoize')
@@ -243,7 +239,7 @@ def test_get_new_command_with_settings(mocker, monkeypatch, test, settings):
if test[3]:
assert (get_new_command(cmd) ==
u'dummy_editor {} +{}:{} && {}'.format(test[1], test[2], test[3], test[0]))
u'dummy_editor {} +{}:{} && {}'.format(test[1], test[2], test[3], test[0]))
else:
assert (get_new_command(cmd) ==
u'dummy_editor {} +{} && {}'.format(test[1], test[2], test[0]))
u'dummy_editor {} +{} && {}'.format(test[1], test[2], test[0]))

View File

@@ -0,0 +1,82 @@
import pytest
from six import BytesIO
from thefuck.rules.gem_unknown_command import match, get_new_command
from tests.utils import Command
stderr = '''
ERROR: While executing gem ... (Gem::CommandLineError)
Unknown command {}
'''
gem_help_commands_stdout = b'''
GEM commands are:
build Build a gem from a gemspec
cert Manage RubyGems certificates and signing settings
check Check a gem repository for added or missing files
cleanup Clean up old versions of installed gems
contents Display the contents of the installed gems
dependency Show the dependencies of an installed gem
environment Display information about the RubyGems environment
fetch Download a gem and place it in the current directory
generate_index Generates the index files for a gem server directory
help Provide help on the 'gem' command
install Install a gem into the local repository
list Display local gems whose name matches REGEXP
lock Generate a lockdown list of gems
mirror Mirror all gem files (requires rubygems-mirror)
open Open gem sources in editor
outdated Display all gems that need updates
owner Manage gem owners of a gem on the push server
pristine Restores installed gems to pristine condition from files
located in the gem cache
push Push a gem up to the gem server
query Query gem information in local or remote repositories
rdoc Generates RDoc for pre-installed gems
search Display remote gems whose name matches REGEXP
server Documentation and gem repository HTTP server
sources Manage the sources and cache file RubyGems uses to search
for gems
specification Display gem specification (in yaml)
stale List gems along with access times
uninstall Uninstall gems from the local repository
unpack Unpack an installed gem to the current directory
update Update installed gems to the latest version
which Find the location of a library file you can require
yank Remove a pushed gem from the index
For help on a particular command, use 'gem help COMMAND'.
Commands may be abbreviated, so long as they are unambiguous.
e.g. 'gem i rake' is short for 'gem install rake'.
'''
@pytest.fixture(autouse=True)
def gem_help_commands(mocker):
patch = mocker.patch('subprocess.Popen')
patch.return_value.stdout = BytesIO(gem_help_commands_stdout)
return patch
@pytest.mark.parametrize('script, command', [
('gem isntall jekyll', 'isntall'),
('gem last --local', 'last')])
def test_match(script, command):
assert match(Command(script, stderr=stderr.format(command)))
@pytest.mark.parametrize('script, stderr', [
('gem install jekyll', ''),
('git log', stderr.format('log'))])
def test_not_match(script, stderr):
assert not match(Command(script, stderr=stderr))
@pytest.mark.parametrize('script, stderr, result', [
('gem isntall jekyll', stderr.format('isntall'), 'gem install jekyll'),
('gem last --local', stderr.format('last'), 'gem list --local')])
def test_get_new_command(script, stderr, result):
new_command = get_new_command(Command(script, stderr=stderr))
assert new_command[0] == result

View File

@@ -3,6 +3,12 @@ from thefuck.rules.git_add import match, get_new_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
def stderr(target):
return ("error: pathspec '{}' did not match any "
@@ -16,10 +22,13 @@ def test_match(stderr, script, target):
assert match(Command(script=script, stderr=stderr))
@pytest.mark.parametrize('script', [
'git submodule update known', 'git commit known'])
def test_not_match(script):
assert not match(Command(script=script, stderr=''))
@pytest.mark.parametrize('script, target, exists', [
('git submodule update known', '', True),
('git commit known', '', True),
('git submodule update known', stderr, False)])
def test_not_match(path_exists, stderr, script, target, exists):
path_exists.return_value = exists
assert not match(Command(script=script, stderr=stderr))
@pytest.mark.parametrize('script, target, new_command', [

View File

@@ -0,0 +1,22 @@
import pytest
from thefuck.rules.git_add_force import match, get_new_command
from tests.utils import Command
@pytest.fixture
def stderr():
return ('The following paths are ignored by one of your .gitignore files:\n'
'dist/app.js\n'
'dist/background.js\n'
'dist/options.js\n'
'Use -f if you really want to add them.\n')
def test_match(stderr):
assert match(Command('git add dist/*.js', stderr=stderr))
assert not match(Command('git add dist/*.js'))
def test_get_new_command(stderr):
assert (get_new_command(Command('git add dist/*.js', stderr=stderr))
== "git add --force dist/*.js")

View 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

View File

@@ -12,22 +12,23 @@ def stderr(branch_name):
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 branch {0}', 'git checkout {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 branch bar', 'bar')])
('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 branch bar'])
@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 branch bar', 'bar')])
('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

View 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

View 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

View File

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

View File

@@ -25,5 +25,5 @@ def test_match(stderr):
def test_get_new_command(stderr):
assert get_new_command(Command('git pull', stderr=stderr)) \
== "git branch --set-upstream-to=origin/master master && git pull"
assert (get_new_command(Command('git pull', stderr=stderr))
== "git branch --set-upstream-to=origin/master master && git pull")

View 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")

View 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")

View File

@@ -14,6 +14,7 @@ To push the current branch and set the remote as upstream, use
def test_match(stderr):
assert match(Command('git push', stderr=stderr))
assert match(Command('git push master', stderr=stderr))
assert not match(Command('git push master'))
assert not match(Command('ls', stderr=stderr))
@@ -22,3 +23,11 @@ def test_match(stderr):
def test_get_new_command(stderr):
assert get_new_command(Command('git push', stderr=stderr))\
== "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"

View File

@@ -13,6 +13,17 @@ To /tmp/foo
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_ok = '''
Counting objects: 3, done.
@@ -28,7 +39,10 @@ To /tmp/bar
@pytest.mark.parametrize('command', [
Command(script='git push', stderr=git_err),
Command(script='git push nvbn', stderr=git_err),
Command(script='git push nvbn master', stderr=git_err)])
Command(script='git push nvbn master', stderr=git_err),
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)
@@ -49,6 +63,11 @@ def test_not_match(command):
(Command(script='git push nvbn', stderr=git_err),
'git pull nvbn && git push nvbn'),
(Command(script='git push nvbn master', stderr=git_err),
'git pull nvbn master && git push nvbn master'),
(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

View File

@@ -0,0 +1,27 @@
import pytest
from tests.utils import Command
from thefuck.rules.git_push_without_commits import (
fix,
get_new_command,
match,
)
command = 'git push -u origin master'
expected_error = '''
error: src refspec master does not match any.
error: failed to push some refs to 'git@github.com:User/repo.git'
'''
@pytest.mark.parametrize('command', [Command(command, stderr=expected_error)])
def test_match(command):
assert match(command)
@pytest.mark.parametrize('command, result', [(
Command(command, stderr=expected_error),
fix.format(command=command),
)])
def test_get_new_command(command, result):
assert get_new_command(command) == result

View 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

View 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')

View File

@@ -14,11 +14,11 @@ def test_match(command):
Command('git remote add origin url'),
Command('git remote remove origin'),
Command('git remote prune origin'),
Command('git remote set-branches origin branch')
])
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')])

View 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

View File

@@ -0,0 +1,28 @@
import pytest
from thefuck.rules.git_rm_staged import match, get_new_command
from tests.utils import Command
@pytest.fixture
def stderr(target):
return ('error: the following file has changes staged in the index:\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

View File

@@ -4,14 +4,14 @@ from tests.utils import Command
cherry_pick_error = (
'error: Your local changes would be overwritten by cherry-pick.\n'
'hint: Commit your changes or stash them to proceed.\n'
'fatal: cherry-pick failed')
'error: Your local changes would be overwritten by cherry-pick.\n'
'hint: Commit your changes or stash them to proceed.\n'
'fatal: cherry-pick failed')
rebase_error = (
'Cannot rebase: Your index contains uncommitted changes.\n'
'Please commit or stash them.')
'Cannot rebase: Your index contains uncommitted changes.\n'
'Please commit or stash them.')
@pytest.mark.parametrize('command', [

View 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 --update && git stash pop && git reset .")

View File

@@ -0,0 +1,18 @@
import pytest
from thefuck.rules.git_tag_force import match, get_new_command
from tests.utils import Command
@pytest.fixture
def stderr():
return '''fatal: tag 'alert' already exists'''
def test_match(stderr):
assert match(Command('git tag alert', stderr=stderr))
assert not match(Command('git tag alert'))
def test_get_new_command(stderr):
assert (get_new_command(Command('git tag alert', stderr=stderr))
== "git tag --force alert")

View 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

View 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

View 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

View File

@@ -7,7 +7,7 @@ def test_match():
with patch('os.path.exists', return_value=True):
assert match(Command(script='main', stderr='main: command not found'))
assert match(Command(script='main --help',
stderr='main: command not found'))
stderr='main: command not found'))
assert not match(Command(script='main', stderr=''))
with patch('os.path.exists', return_value=False):

View File

@@ -1,34 +1,31 @@
# -*- coding: utf-8 -*-
import pytest
from tests.utils import Command
from thefuck.rules.heroku_not_command import match, get_new_command
def suggest_stderr(cmd):
return ''' ! `{}` is not a heroku command.
! Perhaps you meant `logs`, `pg`.
! See `heroku help` for a list of available commands.'''.format(cmd)
suggest_stderr = '''
log is not a heroku command.
Perhaps you meant logs?
▸ Run heroku _ to run heroku logs.
▸ Run heroku help for a list of available commands.'''
no_suggest_stderr = ''' ! `aaaaa` is not a heroku command.
! See `heroku help` for a list of available commands.'''
@pytest.mark.parametrize('cmd', ['log', 'pge'])
@pytest.mark.parametrize('cmd', ['log'])
def test_match(cmd):
assert match(
Command('heroku {}'.format(cmd), stderr=suggest_stderr(cmd)))
Command('heroku {}'.format(cmd), stderr=suggest_stderr))
@pytest.mark.parametrize('script, stderr', [
('cat log', suggest_stderr('log')),
('heroku aaa', no_suggest_stderr)])
('cat log', suggest_stderr)])
def test_not_match(script, stderr):
assert not match(Command(script, stderr=stderr))
@pytest.mark.parametrize('cmd, result', [
('log', ['heroku logs', 'heroku pg']),
('pge', ['heroku pg', 'heroku logs'])])
('log', 'heroku logs')])
def test_get_new_command(cmd, result):
command = Command('heroku {}'.format(cmd), stderr=suggest_stderr(cmd))
command = Command('heroku {}'.format(cmd), stderr=suggest_stderr)
assert get_new_command(command) == result

View File

@@ -0,0 +1,29 @@
import pytest
from thefuck.rules.hostscli import no_website, get_new_command, match
from tests.utils import Command
no_website_long = '''
{}:
No Domain list found for website: a_website_that_does_not_exist
Please raise a Issue here: https://github.com/dhilipsiva/hostscli/issues/new
if you think we should add domains for this website.
type `hostscli websites` to see a list of websites that you can block/unblock
'''.format(no_website)
@pytest.mark.parametrize('command', [
Command('hostscli block a_website_that_does_not_exist',
stderr=no_website_long)])
def test_match(command):
assert match(command)
@pytest.mark.parametrize('command, result', [(
Command('hostscli block a_website_that_does_not_exist',
stderr=no_website_long),
['hostscli websites'])])
def test_get_new_command(command, result):
assert get_new_command(command) == result

View 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

View File

@@ -19,5 +19,5 @@ def test_match(is_not_task):
def test_get_new_command(is_not_task):
assert get_new_command(Command(script='lein rpl --help', stderr=is_not_task)) \
== ['lein repl --help', 'lein jar --help']
assert (get_new_command(Command(script='lein rpl --help', stderr=is_not_task))
== ['lein repl --help', 'lein jar --help'])

View File

@@ -20,7 +20,7 @@ def test_match(script, stderr):
("ln a b", "... hard link"),
("sudo ln a b", "... hard link"),
("a b", error)])
def test_assert_not_match(script, stderr):
def test_not_match(script, stderr):
command = Command(script, stderr=stderr)
assert not match(command)

View File

@@ -0,0 +1,32 @@
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.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 match(Command(script, stderr=stderr))
assert get_new_command(Command(script, stderr=stderr)) == result

View 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'

View File

@@ -23,7 +23,8 @@ def test_not_match(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 3 read'), 'man 2 read'),
(Command('man -s2 read'), 'man -s3 read'),

View File

@@ -0,0 +1,30 @@
import pytest
from thefuck.rules.missing_space_before_subcommand import (
match, get_new_command)
from tests.utils import Command
@pytest.fixture(autouse=True)
def all_executables(mocker):
return mocker.patch(
'thefuck.rules.missing_space_before_subcommand.get_all_executables',
return_value=['git', 'ls', 'npm'])
@pytest.mark.parametrize('script', [
'gitbranch', 'ls-la', 'npminstall'])
def test_match(script):
assert match(Command(script))
@pytest.mark.parametrize('script', ['git branch', 'vimfile'])
def test_not_match(script):
assert not match(Command(script))
@pytest.mark.parametrize('script, result', [
('gitbranch', 'git branch'),
('ls-la', 'ls -la'),
('npminstall webpack', 'npm install webpack')])
def test_get_new_command(script, result):
assert get_new_command(Command(script)) == result

View File

@@ -25,7 +25,7 @@ def test_match(command):
[INFO] Finished at: Wed Aug 26 13:05:47 BST 2015
[INFO] Final Memory: 6M/240M
[INFO] ------------------------------------------------------------------------
"""),
"""), # noqa
Command(script='mvn --help'),
Command(script='mvn -v')
])

View File

@@ -25,7 +25,7 @@ def test_match(command):
[INFO] Finished at: Wed Aug 26 13:05:47 BST 2015
[INFO] Final Memory: 6M/240M
[INFO] ------------------------------------------------------------------------
"""),
"""), # noqa
Command(script='mvn --help'),
Command(script='mvn -v')
])

View File

@@ -21,15 +21,20 @@ def history_without_current(mocker):
('vom file.py', 'vom: not found'),
('fucck', 'fucck: not found'),
('got commit', 'got: command not found')])
def test_match(script, stderr):
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.parametrize('script, stderr', [
('qweqwe', 'qweqwe: not found'),
('vom file.py', 'some text')])
def test_not_match(script, stderr):
@pytest.mark.parametrize('script, stderr, which', [
('qweqwe', 'qweqwe: not found', None),
('vom file.py', 'some text', None),
('vim file.py', 'vim: not found', 'vim')])
def test_not_match(mocker, script, stderr, which):
mocker.patch('thefuck.rules.no_command.which', return_value=which)
assert not match(Command(script, stderr=stderr))

View 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

View 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

View File

@@ -1,31 +1,49 @@
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
@pytest.mark.parametrize('command', [
Command(script='open foo.com'),
Command(script='open foo.ly'),
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.fixture
def stderr(script):
return 'The file {} does not exist.\n'.format(script.split(' ', 1)[1])
@pytest.mark.parametrize('command, new_command', [
(Command('open foo.com'), 'open http://foo.com'),
(Command('open foo.ly'), 'open http://foo.ly'),
(Command('open foo.org'), 'open http://foo.org'),
(Command('open foo.net'), 'open http://foo.net'),
(Command('open foo.se'), 'open http://foo.se'),
(Command('open foo.io'), 'open http://foo.io'),
(Command('xdg-open foo.io'), 'xdg-open http://foo.io'),
(Command('gnome-open foo.io'), 'gnome-open http://foo.io'),
(Command('kde-open foo.io'), 'kde-open http://foo.io')])
def test_get_new_command(command, new_command):
assert get_new_command(command) == new_command
@pytest.mark.parametrize('script', [
'open foo.com',
'open foo.edu',
'open foo.info',
'open foo.io',
'open foo.ly',
'open foo.me',
'open foo.net',
'open foo.org',
'open foo.se',
'open www.foo.ru'])
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

View File

@@ -0,0 +1,43 @@
import pytest
from thefuck.rules.path_from_history import match, get_new_command
from tests.utils import Command
@pytest.fixture(autouse=True)
def history(mocker):
return mocker.patch(
'thefuck.rules.path_from_history.get_valid_history_without_current',
return_value=['cd /opt/java', 'ls ~/work/project/'])
@pytest.fixture(autouse=True)
def path_exists(mocker):
path_mock = mocker.patch('thefuck.rules.path_from_history.Path')
exists_mock = path_mock.return_value.expanduser.return_value.exists
exists_mock.return_value = True
return exists_mock
@pytest.mark.parametrize('script, stderr', [
('ls project', 'no such file or directory: project'),
('cd project', "can't cd to project"),
])
def test_match(script, stderr):
assert match(Command(script, stderr=stderr))
@pytest.mark.parametrize('script, stderr', [
('myapp cats', 'no such file or directory: project'),
('cd project', ""),
])
def test_not_match(script, stderr):
assert not match(Command(script, stderr=stderr))
@pytest.mark.parametrize('script, stderr, result', [
('ls project', 'no such file or directory: project', 'ls ~/work/project'),
('cd java', "can't cd to java", 'cd /opt/java'),
])
def test_get_new_command(script, stderr, result):
new_command = get_new_command(Command(script, stderr=stderr))
assert new_command[0] == result

View 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'

View File

@@ -8,5 +8,5 @@ def test_match():
def test_get_new_command():
assert get_new_command(Command('./test_sudo.py'))\
== 'python ./test_sudo.py'
assert (get_new_command(Command('./test_sudo.py'))
== 'python ./test_sudo.py')

View 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

View 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

View File

@@ -17,5 +17,5 @@ def test_not_match(command):
def test_get_new_command():
assert get_new_command(Command(script='rm -rf /')) \
== 'rm -rf / --no-preserve-root'
assert (get_new_command(Command(script='rm -rf /'))
== 'rm -rf / --no-preserve-root')

View File

@@ -0,0 +1,46 @@
import pytest
from thefuck.rules.scm_correction import match, get_new_command
from tests.utils import Command
@pytest.fixture
def get_actual_scm_mock(mocker):
return mocker.patch('thefuck.rules.scm_correction._get_actual_scm',
return_value=None)
@pytest.mark.parametrize('script, stderr, actual_scm', [
('git log', 'fatal: Not a git repository '
'(or any of the parent directories): .git',
'hg'),
('hg log', "abort: no repository found in '/home/nvbn/exp/thefuck' "
"(.hg not found)!",
'git')])
def test_match(get_actual_scm_mock, script, stderr, actual_scm):
get_actual_scm_mock.return_value = actual_scm
assert match(Command(script, stderr=stderr))
@pytest.mark.parametrize('script, stderr, actual_scm', [
('git log', '', 'hg'),
('git log', 'fatal: Not a git repository '
'(or any of the parent directories): .git',
None),
('hg log', "abort: no repository found in '/home/nvbn/exp/thefuck' "
"(.hg not found)!",
None),
('not-scm log', "abort: no repository found in '/home/nvbn/exp/thefuck' "
"(.hg not found)!",
'git')])
def test_not_match(get_actual_scm_mock, script, stderr, actual_scm):
get_actual_scm_mock.return_value = actual_scm
assert not match(Command(script, stderr=stderr))
@pytest.mark.parametrize('script, actual_scm, result', [
('git log', 'hg', 'hg log'),
('hg log', 'git', 'git log')])
def test_get_new_command(get_actual_scm_mock, script, actual_scm, result):
get_actual_scm_mock.return_value = actual_scm
new_command = get_new_command(Command(script))
assert new_command == result

View File

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

View File

@@ -0,0 +1,39 @@
import pytest
from thefuck.rules.sudo_command_from_user_path import match, get_new_command
from tests.utils import Command
stderr = 'sudo: {}: command not found'
@pytest.fixture(autouse=True)
def which(mocker):
return mocker.patch('thefuck.rules.sudo_command_from_user_path.which',
return_value='/usr/bin/app')
@pytest.mark.parametrize('script, stderr', [
('sudo npm install -g react-native-cli', stderr.format('npm')),
('sudo -u app appcfg update .', stderr.format('appcfg'))])
def test_match(script, stderr):
assert match(Command(script, stderr=stderr))
@pytest.mark.parametrize('script, stderr, which_result', [
('npm --version', stderr.format('npm'), '/usr/bin/npm'),
('sudo npm --version', '', '/usr/bin/npm'),
('sudo npm --version', stderr.format('npm'), None)])
def test_not_match(which, script, stderr, which_result):
which.return_value = which_result
assert not match(Command(script, stderr=stderr))
@pytest.mark.parametrize('script, stderr, result', [
('sudo npm install -g react-native-cli',
stderr.format('npm'),
'sudo env "PATH=$PATH" npm install -g react-native-cli'),
('sudo -u app appcfg update .',
stderr.format('appcfg'),
'sudo -u app env "PATH=$PATH" appcfg update .')])
def test_get_new_command(script, stderr, result):
assert get_new_command(Command(script, stderr=stderr)) == result

View File

@@ -23,12 +23,12 @@ def test_not_match(command):
@pytest.mark.parametrize('command, new_command', [
(Command('hdfs dfs ls',
stderr='ls: Unknown command\nDid you mean -ls? This command begins with a dash.'), ['hdfs dfs -ls']),
stderr='ls: Unknown command\nDid you mean -ls? This command begins with a dash.'), ['hdfs dfs -ls']),
(Command('hdfs dfs rm /foo/bar',
stderr='rm: Unknown command\nDid you mean -rm? This command begins with a dash.'), ['hdfs dfs -rm /foo/bar']),
stderr='rm: Unknown command\nDid you mean -rm? This command begins with a dash.'), ['hdfs dfs -rm /foo/bar']),
(Command('./bin/hdfs dfs ls -R /foo/bar',
stderr='ls: Unknown command\nDid you mean -ls? This command begins with a dash.'), ['./bin/hdfs dfs -ls -R /foo/bar']),
stderr='ls: Unknown command\nDid you mean -ls? This command begins with a dash.'), ['./bin/hdfs dfs -ls -R /foo/bar']),
(Command('./bin/hdfs dfs -Dtest=fred ls -R /foo/bar',
stderr='ls: Unknown command\nDid you mean -ls? This command begins with a dash.'), ['./bin/hdfs dfs -Dtest=fred -ls -R /foo/bar'])])
stderr='ls: Unknown command\nDid you mean -ls? This command begins with a dash.'), ['./bin/hdfs dfs -Dtest=fred -ls -R /foo/bar'])])
def test_get_new_command(command, new_command):
assert get_new_command(command) == new_command

View File

@@ -27,8 +27,8 @@ def test_not_match(command):
(Command(script='vagrant ssh', stderr='VM must be running to open SSH connection. Run `vagrant up`\nto start the virtual machine.'), 'vagrant up && vagrant ssh'),
(Command(script='vagrant ssh devbox', stderr='VM must be running to open SSH connection. Run `vagrant up`\nto start the virtual machine.'), ['vagrant up devbox && vagrant ssh devbox', 'vagrant up && vagrant ssh devbox']),
(Command(script='vagrant rdp',
stderr='VM must be created before running this command. Run `vagrant up` first.'), 'vagrant up && vagrant rdp'),
stderr='VM must be created before running this command. Run `vagrant up` first.'), 'vagrant up && vagrant rdp'),
(Command(script='vagrant rdp devbox',
stderr='VM must be created before running this command. Run `vagrant up` first.'), ['vagrant up devbox && vagrant rdp devbox', 'vagrant up && vagrant rdp devbox'])])
stderr='VM must be created before running this command. Run `vagrant up` first.'), ['vagrant up devbox && vagrant rdp devbox', 'vagrant up && vagrant rdp devbox'])])
def test_get_new_command(command, new_command):
assert get_new_command(command) == new_command

View 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

View File

@@ -0,0 +1,24 @@
import pytest
from thefuck.rules.yarn_alias import match, get_new_command
from tests.utils import Command
stderr_remove = 'error Did you mean `yarn remove`?'
stderr_etl = 'error Command "etil" not found. Did you mean "etl"?'
stderr_list = 'error Did you mean `yarn list`?'
@pytest.mark.parametrize('command', [
Command(script='yarn rm', stderr=stderr_remove),
Command(script='yarn etil', stderr=stderr_etl),
Command(script='yarn ls', stderr=stderr_list)])
def test_match(command):
assert match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('yarn rm', stderr=stderr_remove), 'yarn remove'),
(Command('yarn etil', stderr=stderr_etl), 'yarn etl'),
(Command('yarn ls', stderr=stderr_list), 'yarn list')])
def test_get_new_command(command, new_command):
assert get_new_command(command) == new_command

View File

@@ -0,0 +1,118 @@
# -*- encoding: utf-8 -*-
from io import BytesIO
import pytest
from tests.utils import Command
from thefuck.rules.yarn_command_not_found import match, get_new_command
stderr = '''
error Command "{}" not found.
'''.format
yarn_help_stdout = b'''
Usage: yarn [command] [flags]
Options:
-h, --help output usage information
-V, --version output the version number
--verbose output verbose messages on internal operations
--offline trigger an error if any required dependencies are not available in local cache
--prefer-offline use network only if dependencies are not available in local cache
--strict-semver
--json
--ignore-scripts don't run lifecycle scripts
--har save HAR output of network traffic
--ignore-platform ignore platform checks
--ignore-engines ignore engines check
--ignore-optional ignore optional dependencies
--force ignore all caches
--no-bin-links don't generate bin links when setting up packages
--flat only allow one version of a package
--prod, --production [prod]
--no-lockfile don't read or generate a lockfile
--pure-lockfile don't generate a lockfile
--frozen-lockfile don't generate a lockfile and fail if an update is needed
--link-duplicates create hardlinks to the repeated modules in node_modules
--global-folder <path>
--modules-folder <path> rather than installing modules into the node_modules folder relative to the cwd, output them here
--cache-folder <path> specify a custom folder to store the yarn cache
--mutex <type>[:specifier] use a mutex to ensure only one yarn instance is executing
--no-emoji disable emoji in output
--proxy <host>
--https-proxy <host>
--no-progress disable progress bar
--network-concurrency <number> maximum number of concurrent network requests
Commands:
- access
- add
- bin
- cache
- check
- clean
- config
- generate-lock-entry
- global
- import
- info
- init
- install
- licenses
- link
- list
- login
- logout
- outdated
- owner
- pack
- publish
- remove
- run
- tag
- team
- unlink
- upgrade
- upgrade-interactive
- version
- versions
- why
Run `yarn help COMMAND` for more information on specific commands.
Visit https://yarnpkg.com/en/docs/cli/ to learn more about Yarn.
''' # noqa
@pytest.fixture(autouse=True)
def yarn_help(mocker):
patch = mocker.patch('thefuck.rules.yarn_command_not_found.Popen')
patch.return_value.stdout = BytesIO(yarn_help_stdout)
return patch
@pytest.mark.parametrize('command', [
Command('yarn whyy webpack', stderr=stderr('whyy'))])
def test_match(command):
assert match(command)
@pytest.mark.parametrize('command', [
Command('npm nuild', stderr=stderr('nuild')),
Command('yarn install')])
def test_not_match(command):
assert not match(command)
@pytest.mark.parametrize('command, result', [
(Command('yarn whyy webpack', stderr=stderr('whyy')),
'yarn why webpack'),
(Command('yarn require lodash', stderr=stderr('require')),
'yarn add lodash')])
def test_get_new_command(command, result):
fixed_command = get_new_command(command)
if isinstance(fixed_command, list):
fixed_command = fixed_command[0]
assert fixed_command == result

View File

@@ -0,0 +1,32 @@
import pytest
from tests.utils import Command
from thefuck.rules.yarn_command_replaced import match, get_new_command
stderr = ('error `install` has been replaced with `add` to add new '
'dependencies. Run "yarn add {}" instead.').format
@pytest.mark.parametrize('command', [
Command(script='yarn install redux', stderr=stderr('redux')),
Command(script='yarn install moment', stderr=stderr('moment')),
Command(script='yarn install lodash', stderr=stderr('lodash'))])
def test_match(command):
assert match(command)
@pytest.mark.parametrize('command', [
Command('yarn install')])
def test_not_match(command):
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('yarn install redux', stderr=stderr('redux')),
'yarn add redux'),
(Command('yarn install moment', stderr=stderr('moment')),
'yarn add moment'),
(Command('yarn install lodash', stderr=stderr('lodash')),
'yarn add lodash')])
def test_get_new_command(command, new_command):
assert get_new_command(command) == new_command

View File

@@ -0,0 +1,57 @@
import pytest
from thefuck.rules.yarn_help import match, get_new_command
from tests.utils import Command
from thefuck.system import open_command
stdout_clean = '''
Usage: yarn [command] [flags]
Options:
-h, --help output usage information
-V, --version output the version number
--verbose output verbose messages on internal operations
--offline trigger an error if any required dependencies are not available in local cache
--prefer-offline use network only if dependencies are not available in local cache
--strict-semver
--json
--ignore-scripts don't run lifecycle scripts
--har save HAR output of network traffic
--ignore-platform ignore platform checks
--ignore-engines ignore engines check
--ignore-optional ignore optional dependencies
--force ignore all caches
--no-bin-links don't generate bin links when setting up packages
--flat only allow one version of a package
--prod, --production [prod]
--no-lockfile don't read or generate a lockfile
--pure-lockfile don't generate a lockfile
--frozen-lockfile don't generate a lockfile and fail if an update is needed
--link-duplicates create hardlinks to the repeated modules in node_modules
--global-folder <path>
--modules-folder <path> rather than installing modules into the node_modules folder relative to the cwd, output them here
--cache-folder <path> specify a custom folder to store the yarn cache
--mutex <type>[:specifier] use a mutex to ensure only one yarn instance is executing
--no-emoji disable emoji in output
--proxy <host>
--https-proxy <host>
--no-progress disable progress bar
--network-concurrency <number> maximum number of concurrent network requests
Visit https://yarnpkg.com/en/docs/cli/clean for documentation about this command.
''' # noqa
@pytest.mark.parametrize('command', [
Command(script='yarn help clean', stdout=stdout_clean)])
def test_match(command):
assert match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('yarn help clean', stdout=stdout_clean),
open_command('https://yarnpkg.com/en/docs/cli/clean'))])
def test_get_new_command(command, new_command):
assert get_new_command(command) == new_command

View File

@@ -20,3 +20,11 @@ def history_lines(mocker):
.return_value.readlines.return_value = lines
return aux
@pytest.fixture
def config_exists(mocker):
path_mock = mocker.patch('thefuck.shells.generic.Path')
return path_mock.return_value \
.expanduser.return_value \
.exists

View File

@@ -33,6 +33,9 @@ class TestBash(object):
def test_and_(self, shell):
assert shell.and_('ls', 'cd') == 'ls && cd'
def test_or_(self, shell):
assert shell.or_('ls', 'cd') == 'ls || cd'
def test_get_aliases(self, shell):
assert shell.get_aliases() == {'fuck': 'eval $(thefuck $(fc -ln -1))',
'l': 'ls -CF',
@@ -40,19 +43,32 @@ class TestBash(object):
'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 'fuck () {' in shell.app_alias('fuck')
assert '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')
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
assert "fuck () {" in alias
assert "TF_ALIAS=fuck" in alias
assert 'PYTHONIOENCODING=utf-8' in alias
assert 'TF_SHELL_ALIASES=$(alias)' 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
def test_how_to_configure(self, shell, config_exists):
config_exists.return_value = True
assert shell.how_to_configure().can_configure_automatically
def test_how_to_configure_when_config_not_found(self, shell,
config_exists):
config_exists.return_value = False
assert not shell.how_to_configure().can_configure_automatically

View File

@@ -55,6 +55,9 @@ class TestFish(object):
def test_and_(self, shell):
assert shell.and_('foo', 'bar') == 'foo; and bar'
def test_or_(self, shell):
assert shell.or_('foo', 'bar') == 'foo; or bar'
def test_get_aliases(self, shell):
assert shell.get_aliases() == {'fish_config': 'fish_config',
'fuck': 'fuck',
@@ -74,6 +77,14 @@ class TestFish(object):
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'])
@@ -87,3 +98,12 @@ class TestFish(object):
shell.put_to_history(entry)
builtins_open.return_value.__enter__.return_value. \
write.assert_called_once_with(entry_utf8)
def test_how_to_configure(self, shell, config_exists):
config_exists.return_value = True
assert shell.how_to_configure().can_configure_automatically
def test_how_to_configure_when_config_not_found(self, shell,
config_exists):
config_exists.return_value = False
assert not shell.how_to_configure().can_configure_automatically

View File

@@ -18,6 +18,9 @@ class TestGeneric(object):
def test_and_(self, shell):
assert shell.and_('ls', 'cd') == 'ls && cd'
def test_or_(self, shell):
assert shell.or_('ls', 'cd') == 'ls || cd'
def test_get_aliases(self, shell):
assert shell.get_aliases() == {}
@@ -37,3 +40,6 @@ class TestGeneric(object):
def test_split_command(self, shell):
assert shell.split_command('ls') == ['ls']
assert shell.split_command(u'echo café') == [u'echo', u'café']
def test_how_to_configure(self, shell):
assert shell.how_to_configure() is None

View File

@@ -17,3 +17,6 @@ class TestPowershell(object):
assert 'function fuck' in shell.app_alias('fuck')
assert 'function FUCK' in shell.app_alias('FUCK')
assert 'thefuck' in shell.app_alias('fuck')
def test_how_to_configure(self, shell):
assert not shell.how_to_configure().can_configure_automatically

View File

@@ -34,6 +34,9 @@ class TestTcsh(object):
def test_and_(self, shell):
assert shell.and_('ls', 'cd') == 'ls && cd'
def test_or_(self, shell):
assert shell.or_('ls', 'cd') == 'ls || cd'
def test_get_aliases(self, shell):
assert shell.get_aliases() == {'fuck': 'eval $(thefuck $(fc -ln -1))',
'l': 'ls -CF',
@@ -48,3 +51,12 @@ class TestTcsh(object):
def test_get_history(self, history_lines, shell):
history_lines(['ls', 'rm'])
assert list(shell.get_history()) == ['ls', 'rm']
def test_how_to_configure(self, shell, config_exists):
config_exists.return_value = True
assert shell.how_to_configure().can_configure_automatically
def test_how_to_configure_when_config_not_found(self, shell,
config_exists):
config_exists.return_value = False
assert not shell.how_to_configure().can_configure_automatically

View File

@@ -32,6 +32,9 @@ class TestZsh(object):
def test_and_(self, shell):
assert shell.and_('ls', 'cd') == 'ls && cd'
def test_or_(self, shell):
assert shell.or_('ls', 'cd') == 'ls || cd'
def test_get_aliases(self, shell):
assert shell.get_aliases() == {
'fuck': 'eval $(thefuck $(fc -ln -1 | tail -n 1))',
@@ -40,18 +43,27 @@ class TestZsh(object):
'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 'fuck () {' in shell.app_alias('fuck')
assert '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
assert "fuck () {" in alias
assert "TF_ALIAS=fuck" in alias
assert 'PYTHONIOENCODING=utf-8' in alias
assert 'TF_SHELL_ALIASES=$(alias)' 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']
def test_how_to_configure(self, shell, config_exists):
config_exists.return_value = True
assert shell.how_to_configure().can_configure_automatically
def test_how_to_configure_when_config_not_found(self, shell,
config_exists):
config_exists.return_value = False
assert not shell.how_to_configure().can_configure_automatically

View 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']

View File

@@ -0,0 +1,29 @@
import pytest
from thefuck.argument_parser import Parser
from thefuck.const import ARGUMENT_PLACEHOLDER
def _args(**override):
args = {'alias': None, 'command': [], 'yes': False,
'help': False, 'version': False, 'debug': False,
'force_command': None, 'repeat': False}
args.update(override)
return args
@pytest.mark.parametrize('argv, result', [
(['thefuck'], _args()),
(['thefuck', '-a'], _args(alias='fuck')),
(['thefuck', '-a', 'fix'], _args(alias='fix')),
(['thefuck', 'git', 'branch', ARGUMENT_PLACEHOLDER, '-y'],
_args(command=['git', 'branch'], yes=True)),
(['thefuck', 'git', 'branch', '-a', ARGUMENT_PLACEHOLDER, '-y'],
_args(command=['git', 'branch', '-a'], yes=True)),
(['thefuck', ARGUMENT_PLACEHOLDER, '-v'], _args(version=True)),
(['thefuck', ARGUMENT_PLACEHOLDER, '--help'], _args(help=True)),
(['thefuck', 'git', 'branch', '-a', ARGUMENT_PLACEHOLDER, '-y', '-d'],
_args(command=['git', 'branch', '-a'], yes=True, debug=True)),
(['thefuck', 'git', 'branch', '-a', ARGUMENT_PLACEHOLDER, '-r', '-d'],
_args(command=['git', 'branch', '-a'], repeat=True, debug=True))])
def test_parse(argv, result):
assert vars(Parser().parse(argv)) == result

View File

@@ -1,5 +1,6 @@
import pytest
import six
import os
from mock import Mock
from thefuck import const
@@ -59,7 +60,9 @@ class TestSettingsFromEnv(object):
'THEFUCK_WAIT_COMMAND': '55',
'THEFUCK_REQUIRE_CONFIRMATION': 'true',
'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()
assert settings.rules == ['bash', 'lisp']
assert settings.exclude_rules == ['git', 'vim']
@@ -67,6 +70,8 @@ class TestSettingsFromEnv(object):
assert settings.require_confirmation is True
assert settings.no_colors is False
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):
environ.update({'THEFUCK_RULES': 'DEFAULT_RULES:bash:lisp'})
@@ -74,6 +79,13 @@ class TestSettingsFromEnv(object):
assert settings.rules == const.DEFAULT_RULES + ['bash', 'lisp']
def test_settings_from_args(settings):
settings.init(Mock(yes=True, debug=True, repeat=True))
assert not settings.require_confirmation
assert settings.debug
assert settings.repeat
class TestInitializeSettingsFile(object):
def test_ignore_if_exists(self, settings):
settings_path_mock = Mock(is_file=Mock(return_value=True), open=Mock())
@@ -97,3 +109,22 @@ class TestInitializeSettingsFile(object):
for setting in const.DEFAULT_SETTINGS.items():
assert '# {} = {}\n'.format(*setting) in settings_file_contents
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)

View File

@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
import pytest
from pathlib import Path
from thefuck import corrector, const
from thefuck.system import Path
from tests.utils import Rule, Command, CorrectedCommand
from thefuck.corrector import get_corrected_commands, organize_commands
@@ -11,7 +11,7 @@ class TestGetRules(object):
@pytest.fixture
def glob(self, mocker):
results = {}
mocker.patch('pathlib.Path.glob',
mocker.patch('thefuck.system.Path.glob',
new_callable=lambda: lambda *_: results.pop('value', []))
return lambda value: results.update({'value': value})
@@ -47,8 +47,8 @@ def test_get_corrected_commands(mocker):
get_new_command=lambda x: [x.script + '@', x.script + ';'],
priority=60)]
mocker.patch('thefuck.corrector.get_rules', return_value=rules)
assert [cmd.script for cmd in get_corrected_commands(command)] \
== ['test!', 'test@', 'test;']
assert ([cmd.script for cmd in get_corrected_commands(command)]
== ['test!', 'test@', 'test;'])
def test_organize_commands():

View File

@@ -0,0 +1,125 @@
import pytest
from mock import MagicMock
from thefuck.shells.generic import ShellConfiguration
from thefuck.not_configured import main
@pytest.fixture(autouse=True)
def usage_tracker(mocker):
return mocker.patch(
'thefuck.not_configured._get_not_configured_usage_tracker_path',
new_callable=MagicMock)
def _assert_tracker_updated(usage_tracker, pid):
usage_tracker.return_value \
.open.return_value \
.__enter__.return_value \
.write.assert_called_once_with(str(pid))
def _change_tracker(usage_tracker, pid):
usage_tracker.return_value.exists.return_value = True
usage_tracker.return_value \
.open.return_value \
.__enter__.return_value \
.read.return_value = str(pid)
@pytest.fixture(autouse=True)
def shell_pid(mocker):
return mocker.patch('thefuck.not_configured._get_shell_pid',
new_callable=MagicMock)
@pytest.fixture(autouse=True)
def shell(mocker):
shell = mocker.patch('thefuck.not_configured.shell',
new_callable=MagicMock)
shell.get_history.return_value = []
shell.how_to_configure.return_value = ShellConfiguration(
content='eval $(thefuck --alias)',
path='/tmp/.bashrc',
reload='bash',
can_configure_automatically=True)
return shell
@pytest.fixture(autouse=True)
def shell_config(mocker):
path_mock = mocker.patch('thefuck.not_configured.Path',
new_callable=MagicMock)
return path_mock.return_value \
.expanduser.return_value \
.open.return_value \
.__enter__.return_value
@pytest.fixture(autouse=True)
def logs(mocker):
return mocker.patch('thefuck.not_configured.logs',
new_callable=MagicMock)
def test_for_generic_shell(shell, logs):
shell.how_to_configure.return_value = None
main()
logs.how_to_configure_alias.assert_called_once()
def test_on_first_run(usage_tracker, shell_pid, logs):
shell_pid.return_value = 12
usage_tracker.return_value.exists.return_value = False
main()
_assert_tracker_updated(usage_tracker, 12)
logs.how_to_configure_alias.assert_called_once()
def test_on_run_after_other_commands(usage_tracker, shell_pid, shell, logs):
shell_pid.return_value = 12
shell.get_history.return_value = ['fuck', 'ls']
_change_tracker(usage_tracker, 12)
main()
logs.how_to_configure_alias.assert_called_once()
def test_on_first_run_from_current_shell(usage_tracker, shell_pid,
shell, logs):
shell.get_history.return_value = ['fuck']
shell_pid.return_value = 12
_change_tracker(usage_tracker, 55)
main()
_assert_tracker_updated(usage_tracker, 12)
logs.how_to_configure_alias.assert_called_once()
def test_when_cant_configure_automatically(shell_pid, shell, logs):
shell_pid.return_value = 12
shell.how_to_configure.return_value = ShellConfiguration(
content='eval $(thefuck --alias)',
path='/tmp/.bashrc',
reload='bash',
can_configure_automatically=False)
main()
logs.how_to_configure_alias.assert_called_once()
def test_when_already_configured(usage_tracker, shell_pid,
shell, shell_config, logs):
shell.get_history.return_value = ['fuck']
shell_pid.return_value = 12
_change_tracker(usage_tracker, 12)
shell_config.read.return_value = 'eval $(thefuck --alias)'
main()
logs.already_configured.assert_called_once()
def test_when_successfuly_configured(usage_tracker, shell_pid,
shell, shell_config, logs):
shell.get_history.return_value = ['fuck']
shell_pid.return_value = 12
_change_tracker(usage_tracker, 12)
shell_config.read.return_value = ''
main()
shell_config.write.assert_any_call('eval $(thefuck --alias)')
logs.configured_successfully.assert_called_once()

View File

@@ -3,20 +3,20 @@
import os
from subprocess import PIPE
from mock import Mock
from pathlib import Path
import pytest
from tests.utils import CorrectedCommand, Rule, Command
from thefuck import const
from thefuck.exceptions import EmptyCommand
from thefuck.system import Path
class TestCorrectedCommand(object):
def test_equality(self):
assert CorrectedCommand('ls', None, 100) == \
CorrectedCommand('ls', None, 200)
assert CorrectedCommand('ls', None, 100) != \
CorrectedCommand('ls', lambda *_: _, 100)
assert (CorrectedCommand('ls', None, 100) ==
CorrectedCommand('ls', None, 200))
assert (CorrectedCommand('ls', None, 100) !=
CorrectedCommand('ls', lambda *_: _, 100))
def test_hashable(self):
assert {CorrectedCommand('ls', None, 100),
@@ -28,6 +28,20 @@ class TestCorrectedCommand(object):
assert u'{}'.format(CorrectedCommand(u'echo café', None, 100)) == \
u'CorrectedCommand(script=echo café, side_effect=None, priority=100)'
@pytest.mark.parametrize('script, printed, override_settings', [
('git branch', 'git branch', {'repeat': False, 'debug': False}),
('git brunch',
"git brunch || fuck --repeat --force-command 'git brunch'",
{'repeat': True, 'debug': False}),
('git brunch',
"git brunch || fuck --repeat --debug --force-command 'git brunch'",
{'repeat': True, 'debug': True})])
def test_run(self, capsys, settings, script, printed, override_settings):
settings.update(override_settings)
CorrectedCommand(script, None, 1000).run(Command())
out, _ = capsys.readouterr()
assert out[:-1] == printed
class TestRule(object):
def test_from_path(self, mocker):
@@ -41,8 +55,8 @@ class TestRule(object):
priority=900,
requires_output=True))
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)
assert (Rule.from_path(Path(rule_path))
== Rule('bash', match, get_new_command, priority=900))
load_source.assert_called_once_with('bash', rule_path)
@pytest.mark.parametrize('rules, exclude_rules, rule, is_enabled', [
@@ -79,15 +93,15 @@ class TestRule(object):
def test_get_corrected_commands_with_rule_returns_list(self):
rule = Rule(get_new_command=lambda x: [x.script + '!', x.script + '@'],
priority=100)
assert list(rule.get_corrected_commands(Command(script='test'))) \
== [CorrectedCommand(script='test!', priority=100),
CorrectedCommand(script='test@', priority=200)]
assert (list(rule.get_corrected_commands(Command(script='test')))
== [CorrectedCommand(script='test!', priority=100),
CorrectedCommand(script='test@', priority=200)])
def test_get_corrected_commands_with_rule_returns_command(self):
rule = Rule(get_new_command=lambda x: x.script + '!',
priority=100)
assert list(rule.get_corrected_commands(Command(script='test'))) \
== [CorrectedCommand(script='test!', priority=100)]
assert (list(rule.get_corrected_commands(Command(script='test')))
== [CorrectedCommand(script='test!', priority=100)])
class TestCommand(object):

View File

@@ -25,15 +25,16 @@ def test_read_actions(patch_get_key):
# Ignored:
'x', 'y',
# Up:
const.KEY_UP,
const.KEY_UP, 'k',
# Down:
const.KEY_DOWN,
const.KEY_DOWN, 'j',
# Ctrl+C:
const.KEY_CTRL_C])
assert list(islice(ui.read_actions(), 5)) \
== [const.ACTION_SELECT, const.ACTION_SELECT,
const.ACTION_PREVIOUS, const.ACTION_NEXT,
const.ACTION_ABORT]
const.KEY_CTRL_C, 'q'])
assert (list(islice(ui.read_actions(), 8))
== [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():
@@ -73,8 +74,8 @@ class TestSelectCommand(object):
def test_without_confirmation_with_side_effects(
self, capsys, commands_with_side_effect, settings):
settings.require_confirmation = False
assert ui.select_command(iter(commands_with_side_effect)) \
== commands_with_side_effect[0]
assert (ui.select_command(iter(commands_with_side_effect))
== commands_with_side_effect[0])
assert capsys.readouterr() == ('', 'ls (+side effect)\n')
def test_with_confirmation(self, capsys, patch_get_key, commands):
@@ -90,8 +91,8 @@ class TestSelectCommand(object):
def test_with_confirmation_with_side_effct(self, capsys, patch_get_key,
commands_with_side_effect):
patch_get_key(['\n'])
assert ui.select_command(iter(commands_with_side_effect)) \
== commands_with_side_effect[0]
assert (ui.select_command(iter(commands_with_side_effect))
== commands_with_side_effect[0])
assert capsys.readouterr() == ('', u'\x1b[1K\rls (+side effect) [enter/↑/↓/ctrl+c]\n')
def test_with_confirmation_select_second(self, capsys, patch_get_key, commands):

View File

@@ -1,9 +1,12 @@
# -*- coding: utf-8 -*-
import pytest
import warnings
from mock import Mock
import six
from thefuck.utils import default_settings, \
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
@@ -15,8 +18,7 @@ from tests.utils import Command
def test_default_settings(settings, override, old, new):
settings.clear()
settings.update(old)
fn = lambda _: _
default_settings(override)(fn)(None)
default_settings(override)(lambda _: _)(None)
assert settings == new
@@ -185,59 +187,18 @@ class TestCache(object):
assert shelve == {key: {'etag': '0', 'value': 'test'}}
class TestCompatibilityCall(object):
def test_match(self):
def match(command):
assert command == Command()
return True
assert compatibility_call(match, Command())
def test_old_match(self, settings):
def match(command, _settings):
assert command == Command()
assert settings == _settings
return True
assert compatibility_call(match, Command())
def test_get_new_command(self):
def get_new_command(command):
assert command == Command()
return True
assert compatibility_call(get_new_command, Command())
def test_old_get_new_command(self, settings):
def get_new_command(command, _settings):
assert command == Command()
assert settings == _settings
return True
assert compatibility_call(get_new_command, Command())
def test_side_effect(self):
def side_effect(command, new_command):
assert command == Command() == new_command
return True
assert compatibility_call(side_effect, Command(), Command())
def test_old_side_effect(self, settings):
def side_effect(command, new_command, _settings):
assert command == Command() == new_command
assert settings == _settings
return True
assert compatibility_call(side_effect, Command(), Command())
class TestGetValidHistoryWithoutCurrent(object):
@pytest.yield_fixture(autouse=True)
def fail_on_warning(self):
warnings.simplefilter('error')
yield
warnings.resetwarnings()
@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'])
'diff x', 'nocommand x', u'café ô'])
@pytest.fixture(autouse=True)
def alias(self, mocker):
@@ -245,14 +206,22 @@ class TestGetValidHistoryWithoutCurrent(object):
return_value='fuck')
@pytest.fixture(autouse=True)
def callables(self, mocker):
return mocker.patch('thefuck.utils.get_all_executables',
return_value=['diff', 'ls'])
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)
@pytest.mark.parametrize('script, result', [
('le cat', ['ls cat', 'diff x']),
('diff x', ['ls cat']),
('fuck', ['ls cat', 'diff x'])])
('le cat', ['ls cat', 'diff x', u'café ô']),
('diff x', ['ls cat', u'café ô']),
('fuck', ['ls cat', 'diff x', u'café ô']),
(u'cafe ô', ['ls cat', 'diff x', u'café ô']),
])
def test_get_valid_history_without_current(self, script, result):
command = Command(script=script)
assert get_valid_history_without_current(command) == result

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