summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--test/.gitignore2
-rw-r--r--test/Makefile.am14
-rw-r--r--test/config/bashrc62
-rw-r--r--test/config/inputrc22
-rw-r--r--test/docker/Dockerfile6
-rwxr-xr-xtest/docker/docker-script.sh16
-rw-r--r--test/fixtures/7z/a.7zbin0 -> 109 bytes
-rw-r--r--test/fixtures/7z/f.txt1
-rw-r--r--test/fixtures/_filedir/a b/i0
-rw-r--r--test/fixtures/_filedir/a$b/h0
-rw-r--r--test/fixtures/_filedir/a&b/f0
-rw-r--r--test/fixtures/_filedir/a'b/c0
-rw-r--r--test/fixtures/_filedir/ab/e0
-rw-r--r--test/fixtures/_filedir/aé/g0
-rw-r--r--test/fixtures/_filedir/brackets/[x]1
-rw-r--r--test/fixtures/_filedir/brackets/x1
-rw-r--r--test/fixtures/_filedir/ext/ee.e10
-rw-r--r--test/fixtures/_filedir/ext/ff.e20
-rw-r--r--test/fixtures/_filedir/ext/foo/.gitignore0
-rw-r--r--test/fixtures/_filedir/ext/gg.e10
-rw-r--r--test/fixtures/_filedir/ext/hh.e20
-rw-r--r--test/fixtures/_filedir/ext/ii.E10
-rw-r--r--test/fixtures/_get_cword/sea0
-rw-r--r--test/fixtures/_get_cword/seb0
-rw-r--r--test/fixtures/_get_cword/sec0
-rw-r--r--test/fixtures/_get_cword/ääää§0
-rw-r--r--test/fixtures/_known_hosts_real/.ssh/config_asterisk_11
-rw-r--r--test/fixtures/_known_hosts_real/.ssh/config_asterisk_21
-rw-r--r--test/fixtures/_known_hosts_real/.ssh/config_question_mark1
-rw-r--r--test/fixtures/_known_hosts_real/.ssh/config_relative_path1
-rw-r--r--test/fixtures/_known_hosts_real/config7
-rw-r--r--test/fixtures/_known_hosts_real/config_full_path1
-rw-r--r--test/fixtures/_known_hosts_real/config_include7
-rw-r--r--test/fixtures/_known_hosts_real/config_include_recursion1
-rw-r--r--test/fixtures/_known_hosts_real/config_tilde4
-rw-r--r--test/fixtures/_known_hosts_real/gee-filename-canary0
-rw-r--r--test/fixtures/_known_hosts_real/known_hosts14
-rw-r--r--test/fixtures/_known_hosts_real/known_hosts21
-rw-r--r--test/fixtures/_known_hosts_real/known_hosts31
-rw-r--r--test/fixtures/_known_hosts_real/known_hosts41
-rw-r--r--test/fixtures/_known_hosts_real/localhost_config1
-rw-r--r--test/fixtures/_known_hosts_real/localhost_hosts3
-rw-r--r--test/fixtures/_known_hosts_real/spaced conf8
-rw-r--r--test/fixtures/_known_hosts_real/spaced known_hosts4
-rw-r--r--test/fixtures/_longopt/grep--help.txt70
-rw-r--r--test/fixtures/_longopt/various.txt5
-rw-r--r--test/fixtures/acroread/bar0
-rw-r--r--test/fixtures/acroread/foo.d/.gitignore0
-rw-r--r--test/fixtures/acroread/t.pdf0
-rw-r--r--test/fixtures/ant/.gitignore1
-rw-r--r--test/fixtures/ant/build-with-import.xml8
-rw-r--r--test/fixtures/ant/build.xml17
-rw-r--r--test/fixtures/ant/imported-build.xml6
-rw-r--r--test/fixtures/ant/named-build.xml6
-rw-r--r--test/fixtures/compgen/a'b/c0
-rw-r--r--test/fixtures/compgen/t1.txt121
-rw-r--r--test/fixtures/compgen/t2.txt121
-rw-r--r--test/fixtures/compgen/t3.txt121
-rw-r--r--test/fixtures/cvs/.cvspass2
-rw-r--r--test/fixtures/cvs/foo/CVS/Entries2
-rw-r--r--test/fixtures/cvs/foo/bar0
-rw-r--r--test/fixtures/cvs/foo/quux0
-rwxr-xr-xtest/fixtures/dnssec-keygen/dnssec-keygen76
-rw-r--r--test/fixtures/dpkg/bash-completion-test-nonsubject.txt0
-rw-r--r--test/fixtures/dpkg/bash-completion-test-subject.deb0
-rw-r--r--test/fixtures/evince/.BMP0
-rw-r--r--test/fixtures/evince/.CBR0
-rw-r--r--test/fixtures/evince/.CBZ0
-rw-r--r--test/fixtures/evince/.DJV0
-rw-r--r--test/fixtures/evince/.DJVU0
-rw-r--r--test/fixtures/evince/.DVI0
-rw-r--r--test/fixtures/evince/.DVI.BZ20
-rw-r--r--test/fixtures/evince/.DVI.GZ0
-rw-r--r--test/fixtures/evince/.DVI.bz20
-rw-r--r--test/fixtures/evince/.DVI.gz0
-rw-r--r--test/fixtures/evince/.EPS0
-rw-r--r--test/fixtures/evince/.EPS.BZ20
-rw-r--r--test/fixtures/evince/.EPS.GZ0
-rw-r--r--test/fixtures/evince/.EPS.bz20
-rw-r--r--test/fixtures/evince/.EPS.gz0
-rw-r--r--test/fixtures/evince/.GIF0
-rw-r--r--test/fixtures/evince/.ICO0
-rw-r--r--test/fixtures/evince/.JPEG0
-rw-r--r--test/fixtures/evince/.JPG0
-rw-r--r--test/fixtures/evince/.MIFF0
-rw-r--r--test/fixtures/evince/.PBM0
-rw-r--r--test/fixtures/evince/.PCX0
-rw-r--r--test/fixtures/evince/.PDF0
-rw-r--r--test/fixtures/evince/.PDF.BZ20
-rw-r--r--test/fixtures/evince/.PDF.GZ0
-rw-r--r--test/fixtures/evince/.PDF.bz20
-rw-r--r--test/fixtures/evince/.PDF.gz0
-rw-r--r--test/fixtures/evince/.PGM0
-rw-r--r--test/fixtures/evince/.PNG0
-rw-r--r--test/fixtures/evince/.PNM0
-rw-r--r--test/fixtures/evince/.PPM0
-rw-r--r--test/fixtures/evince/.PS0
-rw-r--r--test/fixtures/evince/.PS.BZ20
-rw-r--r--test/fixtures/evince/.PS.GZ0
-rw-r--r--test/fixtures/evince/.PS.bz20
-rw-r--r--test/fixtures/evince/.PS.gz0
-rw-r--r--test/fixtures/evince/.TGA0
-rw-r--r--test/fixtures/evince/.TIF0
-rw-r--r--test/fixtures/evince/.TIFF0
-rw-r--r--test/fixtures/evince/.XPM0
-rw-r--r--test/fixtures/evince/.XWD0
-rw-r--r--test/fixtures/evince/.bmp0
-rw-r--r--test/fixtures/evince/.cbr0
-rw-r--r--test/fixtures/evince/.cbz0
-rw-r--r--test/fixtures/evince/.djv0
-rw-r--r--test/fixtures/evince/.djvu0
-rw-r--r--test/fixtures/evince/.dvi0
-rw-r--r--test/fixtures/evince/.dvi.BZ20
-rw-r--r--test/fixtures/evince/.dvi.GZ0
-rw-r--r--test/fixtures/evince/.dvi.bz20
-rw-r--r--test/fixtures/evince/.dvi.gz0
-rw-r--r--test/fixtures/evince/.eps0
-rw-r--r--test/fixtures/evince/.eps.BZ20
-rw-r--r--test/fixtures/evince/.eps.GZ0
-rw-r--r--test/fixtures/evince/.eps.bz20
-rw-r--r--test/fixtures/evince/.eps.gz0
-rw-r--r--test/fixtures/evince/.gif0
-rw-r--r--test/fixtures/evince/.ico0
-rw-r--r--test/fixtures/evince/.jpeg0
-rw-r--r--test/fixtures/evince/.jpg0
-rw-r--r--test/fixtures/evince/.miff0
-rw-r--r--test/fixtures/evince/.pbm0
-rw-r--r--test/fixtures/evince/.pcx0
-rw-r--r--test/fixtures/evince/.pdf0
-rw-r--r--test/fixtures/evince/.pdf.BZ20
-rw-r--r--test/fixtures/evince/.pdf.GZ0
-rw-r--r--test/fixtures/evince/.pdf.bz20
-rw-r--r--test/fixtures/evince/.pdf.gz0
-rw-r--r--test/fixtures/evince/.pgm0
-rw-r--r--test/fixtures/evince/.png0
-rw-r--r--test/fixtures/evince/.pnm0
-rw-r--r--test/fixtures/evince/.ppm0
-rw-r--r--test/fixtures/evince/.ps0
-rw-r--r--test/fixtures/evince/.ps.BZ20
-rw-r--r--test/fixtures/evince/.ps.GZ0
-rw-r--r--test/fixtures/evince/.ps.bz20
-rw-r--r--test/fixtures/evince/.ps.gz0
-rw-r--r--test/fixtures/evince/.tga0
-rw-r--r--test/fixtures/evince/.tif0
-rw-r--r--test/fixtures/evince/.tiff0
-rw-r--r--test/fixtures/evince/.txt0
-rw-r--r--test/fixtures/evince/.xpm0
-rw-r--r--test/fixtures/evince/.xwd0
-rw-r--r--test/fixtures/evince/foo/.gitignore0
-rw-r--r--test/fixtures/gdb/core0
-rw-r--r--test/fixtures/gdb/core-NOT0
-rw-r--r--test/fixtures/gdb/core.123450
-rw-r--r--test/fixtures/gdb/core.weston.1000.deadbeef.5308.15553621320000000
-rw-r--r--test/fixtures/gdb/corenot0
-rw-r--r--test/fixtures/htpasswd/htpasswd2
-rw-r--r--test/fixtures/info/bash-completion.info0
-rw-r--r--test/fixtures/isql/odbc.ini3
-rw-r--r--test/fixtures/java/a/b$c.class0
-rw-r--r--test/fixtures/java/a/b.class0
-rw-r--r--test/fixtures/java/a/c/README.txt2
-rw-r--r--test/fixtures/java/a/c/d.class0
-rw-r--r--test/fixtures/java/a/d.txt0
-rw-r--r--test/fixtures/java/bashcomp.jarbin0 -> 788 bytes
-rw-r--r--test/fixtures/java/bashcomp.war0
-rw-r--r--test/fixtures/java/no-complete.txt1
-rw-r--r--test/fixtures/kdvi/.DVI0
-rw-r--r--test/fixtures/kdvi/.DVI.Z0
-rw-r--r--test/fixtures/kdvi/.DVI.bz20
-rw-r--r--test/fixtures/kdvi/.DVI.gz0
-rw-r--r--test/fixtures/kdvi/.dvi0
-rw-r--r--test/fixtures/kdvi/.dvi.Z0
-rw-r--r--test/fixtures/kdvi/.dvi.bz20
-rw-r--r--test/fixtures/kdvi/.dvi.gz0
-rw-r--r--test/fixtures/kdvi/.txt0
-rw-r--r--test/fixtures/kdvi/foo/.gitignore0
-rw-r--r--test/fixtures/kpdf/.EPS0
-rw-r--r--test/fixtures/kpdf/.PDF0
-rw-r--r--test/fixtures/kpdf/.PS0
-rw-r--r--test/fixtures/kpdf/.eps0
-rw-r--r--test/fixtures/kpdf/.pdf0
-rw-r--r--test/fixtures/kpdf/.ps0
-rw-r--r--test/fixtures/kpdf/.txt0
-rw-r--r--test/fixtures/kpdf/foo/.gitignore0
-rw-r--r--test/fixtures/lftp/.lftp/bookmarks3
-rw-r--r--test/fixtures/lilo/lilo.conf34
-rw-r--r--test/fixtures/make/.gitignore1
-rw-r--r--test/fixtures/make/Makefile46
-rw-r--r--test/fixtures/make/sample.c8
-rw-r--r--test/fixtures/make/sample.d3
-rw-r--r--test/fixtures/make/sample.h0
-rw-r--r--test/fixtures/man/man/quux.80
-rw-r--r--test/fixtures/man/man1/bash-completion-testcase.1.bz20
-rw-r--r--test/fixtures/man/man1/foo.10
-rwxr-xr-xtest/fixtures/mount/bin/showmount12
-rw-r--r--test/fixtures/mount/test-fstab24
-rw-r--r--test/fixtures/mplayer/.mplayer/config2
-rw-r--r--test/fixtures/mplayer/.mplayer/mencoder.conf1
-rw-r--r--test/fixtures/mutt/bar/.gitignore0
-rw-r--r--test/fixtures/mutt/bar/muttrc_b1
-rw-r--r--test/fixtures/mutt/foo/.gitignore0
-rw-r--r--test/fixtures/mutt/foo/muttrc_f0
-rw-r--r--test/fixtures/mutt/muttrc4
-rw-r--r--test/fixtures/nmap/nmap-h.txt114
-rw-r--r--test/fixtures/perl/Devel/BashCompletion.pm3
-rw-r--r--test/fixtures/perldoc/BashCompletionDoc.pod0
-rw-r--r--test/fixtures/perldoc/BashCompletionModule.pm4
-rw-r--r--test/fixtures/pkgtools/db/a-1.0,1/.gitignore0
-rw-r--r--test/fixtures/pkgtools/db/b-c-d-2.0_2/.gitignore0
-rw-r--r--test/fixtures/pkgtools/ports/.gitignore2
-rw-r--r--test/fixtures/pkgtools/ports/INDEX.dist3
-rw-r--r--test/fixtures/pytest/test_async.py17
-rw-r--r--test/fixtures/ri/BashCompletion/cdesc-BashCompletion.ribin0 -> 197 bytes
-rw-r--r--test/fixtures/ri/BashCompletion/cdesc-BashCompletion.yaml15
-rw-r--r--test/fixtures/ri/bashcompletion.rb2
-rw-r--r--test/fixtures/ri/cache.ribin0 -> 136 bytes
-rw-r--r--test/fixtures/ri/created.rid1
-rw-r--r--test/fixtures/scp/config8
-rw-r--r--test/fixtures/scp/known_hosts5
-rw-r--r--test/fixtures/scp/spaced conf6
-rw-r--r--test/fixtures/sftp/config8
-rw-r--r--test/fixtures/sftp/known_hosts5
-rw-r--r--test/fixtures/sftp/spaced conf6
-rw-r--r--test/fixtures/shared/.ssh/known_hosts1
-rwxr-xr-xtest/fixtures/shared/bin/arp16
-rwxr-xr-xtest/fixtures/shared/bin/ifconfig24
-rw-r--r--test/fixtures/shared/default/bar0
-rw-r--r--test/fixtures/shared/default/bar bar.d/foo0
-rw-r--r--test/fixtures/shared/default/foo1
-rw-r--r--test/fixtures/shared/default/foo.d/foo0
-rw-r--r--test/fixtures/shared/empty_dir/.nothing_here0
-rw-r--r--test/fixtures/shared/ld.so.conf.d/foo.txt0
-rw-r--r--test/fixtures/shared/ld.so.conf.d/libfoo.conf0
-rw-r--r--test/fixtures/shared/ld.so.conf.d/libfoo.so0
-rw-r--r--test/fixtures/shared/ld.so.conf.d/libfoo.so.10
-rw-r--r--test/fixtures/slackware/home/abc-4-i686-1.txz1
-rw-r--r--test/fixtures/slackware/home/opq-1.0-2.i386.rpm1
-rw-r--r--test/fixtures/slackware/home/tcl.d/tcl.tgz1
-rw-r--r--test/fixtures/slackware/usr/src/slapt-src/slackbuilds_data20
-rw-r--r--test/fixtures/slackware/var/log/packages/radeontool-1.6.1-i486-124
-rw-r--r--test/fixtures/slackware/var/log/packages/rzip-2.1-i486-129
-rw-r--r--test/fixtures/slackware/var/slapt-get/package_data47
-rw-r--r--test/fixtures/ssh-copy-id/.ssh/id_rsa0
-rw-r--r--test/fixtures/ssh-copy-id/.ssh/id_rsa.pub1
-rw-r--r--test/fixtures/ssh/config1
-rw-r--r--test/fixtures/ssh/known_hosts5
-rw-r--r--test/fixtures/ssh/spaced conf6
-rw-r--r--test/fixtures/tar/archive.tar.xzbin0 -> 10240 bytes
-rw-r--r--test/fixtures/tar/dir/fileA0
-rw-r--r--test/fixtures/tar/dir/fileB0
-rw-r--r--test/fixtures/tar/dir/fileC0
-rw-r--r--test/fixtures/tar/dir/hello0
-rw-r--r--test/fixtures/tar/dir2/.nothing_here0
-rw-r--r--test/fixtures/tar/escape.tarbin0 -> 10240 bytes
-rw-r--r--test/fixtures/tox/tox.ini6
-rw-r--r--test/fixtures/xz/a/b0
-rw-r--r--test/fixtures/xz/bashcomp.lzma0
-rw-r--r--test/fixtures/xz/bashcomp.tar0
-rw-r--r--test/fixtures/xz/bashcomp.tar.xzbin0 -> 196 bytes
-rw-r--r--test/fixtures/xz/bashcomp.tlz0
-rw-r--r--test/fixtures/xz/bashcomp.xz0
-rwxr-xr-xtest/generate60
-rw-r--r--test/requirements-dev.txt4
-rw-r--r--test/requirements.txt5
-rwxr-xr-xtest/runLint51
-rw-r--r--test/setup.cfg18
-rw-r--r--test/t/Makefile.am698
-rw-r--r--test/t/conftest.py637
-rw-r--r--test/t/test_2to3.py11
-rw-r--r--test/t/test_7z.py33
-rw-r--r--test/t/test_a2ps.py11
-rw-r--r--test/t/test_a2x.py11
-rw-r--r--test/t/test_abook.py7
-rw-r--r--test/t/test_aclocal.py11
-rw-r--r--test/t/test_acpi.py7
-rw-r--r--test/t/test_acroread.py7
-rw-r--r--test/t/test_adb.py11
-rw-r--r--test/t/test_add_members.py7
-rw-r--r--test/t/test_alias.py21
-rw-r--r--test/t/test_alpine.py7
-rw-r--r--test/t/test_animate.py7
-rw-r--r--test/t/test_ant.py35
-rw-r--r--test/t/test_apache2ctl.py7
-rw-r--r--test/t/test_appdata_validate.py12
-rw-r--r--test/t/test_apt_build.py8
-rw-r--r--test/t/test_apt_cache.py17
-rw-r--r--test/t/test_apt_get.py16
-rw-r--r--test/t/test_aptitude.py23
-rw-r--r--test/t/test_arch.py8
-rw-r--r--test/t/test_arp.py13
-rw-r--r--test/t/test_arping.py11
-rw-r--r--test/t/test_arpspoof.py12
-rw-r--r--test/t/test_asciidoc.py11
-rw-r--r--test/t/test_aspell.py7
-rw-r--r--test/t/test_autoconf.py7
-rw-r--r--test/t/test_autoheader.py7
-rw-r--r--test/t/test_automake.py11
-rw-r--r--test/t/test_autoreconf.py7
-rw-r--r--test/t/test_autorpm.py7
-rw-r--r--test/t/test_autoscan.py11
-rw-r--r--test/t/test_autossh.py7
-rw-r--r--test/t/test_autoupdate.py7
-rw-r--r--test/t/test_avctrl.py7
-rw-r--r--test/t/test_awk.py11
-rw-r--r--test/t/test_badblocks.py12
-rw-r--r--test/t/test_base64.py11
-rw-r--r--test/t/test_bash.py7
-rw-r--r--test/t/test_bc.py7
-rw-r--r--test/t/test_bind.py11
-rw-r--r--test/t/test_bison.py7
-rw-r--r--test/t/test_bk.py7
-rw-r--r--test/t/test_bmake.py7
-rw-r--r--test/t/test_brctl.py7
-rw-r--r--test/t/test_btdownloadcurses_py.py8
-rw-r--r--test/t/test_btdownloadgui_py.py8
-rw-r--r--test/t/test_btdownloadheadless_py.py8
-rw-r--r--test/t/test_bts.py11
-rw-r--r--test/t/test_bzip2.py15
-rw-r--r--test/t/test_cal.py11
-rw-r--r--test/t/test_cancel.py34
-rw-r--r--test/t/test_cardctl.py7
-rw-r--r--test/t/test_carton.py11
-rw-r--r--test/t/test_cat.py11
-rw-r--r--test/t/test_cc.py7
-rw-r--r--test/t/test_ccache.py27
-rw-r--r--test/t/test_ccze.py19
-rw-r--r--test/t/test_cd.py26
-rw-r--r--test/t/test_cdrecord.py7
-rw-r--r--test/t/test_cfagent.py7
-rw-r--r--test/t/test_cfrun.py7
-rw-r--r--test/t/test_chage.py11
-rw-r--r--test/t/test_change_pw.py8
-rw-r--r--test/t/test_check_db.py7
-rw-r--r--test/t/test_check_perms.py7
-rw-r--r--test/t/test_checksec.py7
-rw-r--r--test/t/test_chfn.py7
-rw-r--r--test/t/test_chgrp.py7
-rw-r--r--test/t/test_chkconfig.py15
-rw-r--r--test/t/test_chmod.py25
-rw-r--r--test/t/test_chown.py82
-rw-r--r--test/t/test_chpasswd.py7
-rw-r--r--test/t/test_chromium_browser.py25
-rw-r--r--test/t/test_chronyc.py11
-rw-r--r--test/t/test_chroot.py16
-rw-r--r--test/t/test_chrpath.py11
-rw-r--r--test/t/test_chsh.py15
-rw-r--r--test/t/test_ci.py7
-rw-r--r--test/t/test_ciptool.py7
-rw-r--r--test/t/test_civclient.py7
-rw-r--r--test/t/test_civserver.py7
-rw-r--r--test/t/test_cksfv.py7
-rw-r--r--test/t/test_cleanarch.py8
-rw-r--r--test/t/test_clisp.py7
-rw-r--r--test/t/test_clone_member.py7
-rw-r--r--test/t/test_co.py7
-rw-r--r--test/t/test_colordiff.py11
-rw-r--r--test/t/test_compare.py7
-rw-r--r--test/t/test_compgen.py7
-rw-r--r--test/t/test_complete.py11
-rw-r--r--test/t/test_composite.py7
-rw-r--r--test/t/test_config_list.py7
-rw-r--r--test/t/test_configure.py17
-rw-r--r--test/t/test_conjure.py7
-rw-r--r--test/t/test_convert.py15
-rw-r--r--test/t/test_cowsay.py7
-rw-r--r--test/t/test_cp.py11
-rw-r--r--test/t/test_cpan2dist.py9
-rw-r--r--test/t/test_cpio.py12
-rw-r--r--test/t/test_cplusplus.py8
-rw-r--r--test/t/test_cppcheck.py31
-rw-r--r--test/t/test_createdb.py11
-rw-r--r--test/t/test_createuser.py11
-rw-r--r--test/t/test_crontab.py16
-rw-r--r--test/t/test_cryptsetup.py11
-rw-r--r--test/t/test_csplit.py11
-rw-r--r--test/t/test_curl.py28
-rw-r--r--test/t/test_cut.py11
-rw-r--r--test/t/test_cvs.py20
-rw-r--r--test/t/test_cvsps.py12
-rw-r--r--test/t/test_date.py11
-rw-r--r--test/t/test_dcop.py7
-rw-r--r--test/t/test_dd.py17
-rw-r--r--test/t/test_declare.py20
-rw-r--r--test/t/test_deja_dup.py12
-rw-r--r--test/t/test_desktop_file_validate.py12
-rw-r--r--test/t/test_df.py11
-rw-r--r--test/t/test_dfutool.py7
-rw-r--r--test/t/test_dhclient.py7
-rw-r--r--test/t/test_dict.py7
-rw-r--r--test/t/test_diff.py7
-rw-r--r--test/t/test_dir.py11
-rw-r--r--test/t/test_display.py11
-rw-r--r--test/t/test_dmesg.py7
-rw-r--r--test/t/test_dmypy.py14
-rw-r--r--test/t/test_dnssec_keygen.py80
-rw-r--r--test/t/test_dnsspoof.py7
-rw-r--r--test/t/test_dot.py7
-rw-r--r--test/t/test_dpkg.py15
-rw-r--r--test/t/test_dpkg_deb.py12
-rw-r--r--test/t/test_dpkg_query.py18
-rw-r--r--test/t/test_dpkg_reconfigure.py8
-rw-r--r--test/t/test_dpkg_source.py8
-rw-r--r--test/t/test_dropdb.py11
-rw-r--r--test/t/test_dropuser.py7
-rw-r--r--test/t/test_dselect.py11
-rw-r--r--test/t/test_dsniff.py7
-rw-r--r--test/t/test_du.py11
-rw-r--r--test/t/test_dumpdb.py8
-rw-r--r--test/t/test_dumpe2fs.py11
-rw-r--r--test/t/test_e2freefrag.py11
-rw-r--r--test/t/test_e2label.py7
-rw-r--r--test/t/test_ebtables.py7
-rw-r--r--test/t/test_ecryptfs_migrate_home.py12
-rw-r--r--test/t/test_eject.py7
-rw-r--r--test/t/test_enscript.py7
-rw-r--r--test/t/test_env.py7
-rw-r--r--test/t/test_eog.py11
-rw-r--r--test/t/test_ether_wake.py18
-rw-r--r--test/t/test_etherwake.py7
-rw-r--r--test/t/test_evince.py22
-rw-r--r--test/t/test_expand.py7
-rw-r--r--test/t/test_explodepkg.py23
-rw-r--r--test/t/test_export.py36
-rw-r--r--test/t/test_faillog.py7
-rw-r--r--test/t/test_fbgs.py7
-rw-r--r--test/t/test_fbi.py7
-rw-r--r--test/t/test_feh.py31
-rw-r--r--test/t/test_file.py11
-rw-r--r--test/t/test_file_roller.py8
-rw-r--r--test/t/test_filefrag.py11
-rw-r--r--test/t/test_filesnarf.py7
-rw-r--r--test/t/test_find.py37
-rw-r--r--test/t/test_find_member.py7
-rw-r--r--test/t/test_finger.py33
-rw-r--r--test/t/test_fio.py15
-rw-r--r--test/t/test_firefox.py12
-rw-r--r--test/t/test_flake8.py17
-rw-r--r--test/t/test_fmt.py9
-rw-r--r--test/t/test_fold.py7
-rw-r--r--test/t/test_freebsd_update.py8
-rw-r--r--test/t/test_freeciv.py7
-rw-r--r--test/t/test_freeciv_server.py8
-rw-r--r--test/t/test_function.py7
-rw-r--r--test/t/test_fusermount.py11
-rw-r--r--test/t/test_g4.py7
-rw-r--r--test/t/test_g77.py7
-rw-r--r--test/t/test_gcc.py64
-rw-r--r--test/t/test_gcj.py7
-rw-r--r--test/t/test_gcl.py7
-rw-r--r--test/t/test_gdb.py14
-rw-r--r--test/t/test_genaliases.py8
-rw-r--r--test/t/test_gendiff.py7
-rw-r--r--test/t/test_genisoimage.py11
-rw-r--r--test/t/test_geoiplookup.py7
-rw-r--r--test/t/test_getconf.py25
-rw-r--r--test/t/test_getent.py18
-rw-r--r--test/t/test_gkrellm.py10
-rw-r--r--test/t/test_gm.py19
-rw-r--r--test/t/test_gmplayer.py7
-rw-r--r--test/t/test_gnatmake.py7
-rw-r--r--test/t/test_gnokii.py11
-rw-r--r--test/t/test_gnome_mplayer.py17
-rw-r--r--test/t/test_gnome_screenshot.py8
-rw-r--r--test/t/test_gpasswd.py11
-rw-r--r--test/t/test_gpc.py7
-rw-r--r--test/t/test_gperf.py7
-rw-r--r--test/t/test_gpg.py7
-rw-r--r--test/t/test_gpg2.py7
-rw-r--r--test/t/test_gpgv.py15
-rw-r--r--test/t/test_gphoto2.py7
-rw-r--r--test/t/test_gplusplus.py8
-rw-r--r--test/t/test_gprof.py7
-rw-r--r--test/t/test_grep.py16
-rw-r--r--test/t/test_groupadd.py11
-rw-r--r--test/t/test_groupdel.py11
-rw-r--r--test/t/test_groupmems.py7
-rw-r--r--test/t/test_groupmod.py11
-rw-r--r--test/t/test_growisofs.py7
-rw-r--r--test/t/test_grpck.py11
-rw-r--r--test/t/test_grub.py7
-rw-r--r--test/t/test_gssdp_discover.py22
-rw-r--r--test/t/test_gzip.py15
-rw-r--r--test/t/test_hciattach.py7
-rw-r--r--test/t/test_hciconfig.py7
-rw-r--r--test/t/test_hcitool.py11
-rw-r--r--test/t/test_hddtemp.py7
-rw-r--r--test/t/test_head.py7
-rw-r--r--test/t/test_hexdump.py7
-rw-r--r--test/t/test_hid2hci.py8
-rw-r--r--test/t/test_host.py7
-rw-r--r--test/t/test_hostname.py7
-rw-r--r--test/t/test_hping2.py11
-rw-r--r--test/t/test_hping3.py7
-rw-r--r--test/t/test_htop.py7
-rw-r--r--test/t/test_htpasswd.py23
-rw-r--r--test/t/test_hunspell.py11
-rw-r--r--test/t/test_hwclock.py7
-rw-r--r--test/t/test_iconv.py21
-rw-r--r--test/t/test_id.py7
-rw-r--r--test/t/test_identify.py7
-rw-r--r--test/t/test_idn.py7
-rw-r--r--test/t/test_ifdown.py14
-rw-r--r--test/t/test_ifstat.py21
-rw-r--r--test/t/test_iftop.py11
-rw-r--r--test/t/test_ifup.py20
-rw-r--r--test/t/test_import.py7
-rw-r--r--test/t/test_influx.py15
-rw-r--r--test/t/test_info.py12
-rw-r--r--test/t/test_inject.py8
-rw-r--r--test/t/test_inotifywait.py15
-rw-r--r--test/t/test_inotifywatch.py15
-rw-r--r--test/t/test_insmod.py7
-rw-r--r--test/t/test_installpkg.py39
-rw-r--r--test/t/test_interdiff.py11
-rw-r--r--test/t/test_invoke_rc_d.py14
-rw-r--r--test/t/test_ionice.py7
-rw-r--r--test/t/test_ip.py15
-rw-r--r--test/t/test_ipcalc.py23
-rw-r--r--test/t/test_iperf.py24
-rw-r--r--test/t/test_iperf3.py20
-rw-r--r--test/t/test_ipmitool.py11
-rw-r--r--test/t/test_ipsec.py7
-rw-r--r--test/t/test_iptables.py7
-rw-r--r--test/t/test_ipv6calc.py11
-rw-r--r--test/t/test_irb.py11
-rw-r--r--test/t/test_iscsiadm.py7
-rw-r--r--test/t/test_isort.py11
-rw-r--r--test/t/test_isql.py8
-rw-r--r--test/t/test_iwconfig.py7
-rw-r--r--test/t/test_iwlist.py7
-rw-r--r--test/t/test_iwpriv.py7
-rw-r--r--test/t/test_iwspy.py7
-rw-r--r--test/t/test_jar.py7
-rw-r--r--test/t/test_jarsigner.py7
-rw-r--r--test/t/test_java.py49
-rw-r--r--test/t/test_javac.py11
-rw-r--r--test/t/test_javadoc.py17
-rw-r--r--test/t/test_javaws.py11
-rw-r--r--test/t/test_jpegoptim.py11
-rw-r--r--test/t/test_jps.py7
-rw-r--r--test/t/test_jq.py30
-rw-r--r--test/t/test_jshint.py11
-rw-r--r--test/t/test_json_xs.py11
-rw-r--r--test/t/test_jsonschema.py13
-rw-r--r--test/t/test_k3b.py11
-rw-r--r--test/t/test_kcov.py16
-rw-r--r--test/t/test_kdvi.py10
-rw-r--r--test/t/test_kill.py15
-rw-r--r--test/t/test_killall.py21
-rw-r--r--test/t/test_kldload.py7
-rw-r--r--test/t/test_kldunload.py16
-rw-r--r--test/t/test_koji.py11
-rw-r--r--test/t/test_kpdf.py7
-rw-r--r--test/t/test_kplayer.py7
-rw-r--r--test/t/test_ktutil.py11
-rw-r--r--test/t/test_l2ping.py7
-rw-r--r--test/t/test_larch.py7
-rw-r--r--test/t/test_lastlog.py7
-rw-r--r--test/t/test_ld.py11
-rw-r--r--test/t/test_ldapadd.py7
-rw-r--r--test/t/test_ldapcompare.py7
-rw-r--r--test/t/test_ldapdelete.py7
-rw-r--r--test/t/test_ldapmodrdn.py7
-rw-r--r--test/t/test_ldappasswd.py7
-rw-r--r--test/t/test_ldapsearch.py7
-rw-r--r--test/t/test_ldapvi.py7
-rw-r--r--test/t/test_ldapwhoami.py7
-rw-r--r--test/t/test_ldd.py13
-rw-r--r--test/t/test_less.py11
-rw-r--r--test/t/test_lftp.py16
-rw-r--r--test/t/test_lftpget.py7
-rw-r--r--test/t/test_lilo.py16
-rw-r--r--test/t/test_links.py11
-rw-r--r--test/t/test_lintian.py7
-rw-r--r--test/t/test_lintian_info.py12
-rw-r--r--test/t/test_lisp.py7
-rw-r--r--test/t/test_list_admins.py7
-rw-r--r--test/t/test_list_lists.py7
-rw-r--r--test/t/test_list_members.py7
-rw-r--r--test/t/test_list_owners.py8
-rw-r--r--test/t/test_ln.py11
-rw-r--r--test/t/test_locale_gen.py13
-rw-r--r--test/t/test_look.py16
-rw-r--r--test/t/test_lpq.py7
-rw-r--r--test/t/test_lpr.py7
-rw-r--r--test/t/test_lrzip.py15
-rw-r--r--test/t/test_ls.py40
-rw-r--r--test/t/test_lsof.py11
-rw-r--r--test/t/test_lspci.py13
-rw-r--r--test/t/test_lsscsi.py11
-rw-r--r--test/t/test_lsusb.py10
-rw-r--r--test/t/test_lua.py11
-rw-r--r--test/t/test_luac.py11
-rw-r--r--test/t/test_luseradd.py7
-rw-r--r--test/t/test_luserdel.py11
-rw-r--r--test/t/test_lusermod.py7
-rw-r--r--test/t/test_lvchange.py9
-rw-r--r--test/t/test_lvcreate.py9
-rw-r--r--test/t/test_lvdisplay.py11
-rw-r--r--test/t/test_lvextend.py9
-rw-r--r--test/t/test_lvm.py7
-rw-r--r--test/t/test_lvmdiskscan.py11
-rw-r--r--test/t/test_lvreduce.py9
-rw-r--r--test/t/test_lvremove.py9
-rw-r--r--test/t/test_lvrename.py9
-rw-r--r--test/t/test_lvresize.py9
-rw-r--r--test/t/test_lvs.py9
-rw-r--r--test/t/test_lvscan.py9
-rw-r--r--test/t/test_lz4.py15
-rw-r--r--test/t/test_lzip.py11
-rw-r--r--test/t/test_lzma.py19
-rw-r--r--test/t/test_lzop.py11
-rw-r--r--test/t/test_m4.py9
-rw-r--r--test/t/test_macof.py7
-rw-r--r--test/t/test_mailmanctl.py8
-rw-r--r--test/t/test_mailsnarf.py7
-rw-r--r--test/t/test_make.py47
-rw-r--r--test/t/test_makepkg.py17
-rw-r--r--test/t/test_man.py115
-rw-r--r--test/t/test_mc.py7
-rw-r--r--test/t/test_mcrypt.py19
-rw-r--r--test/t/test_md5sum.py11
-rw-r--r--test/t/test_mdadm.py7
-rw-r--r--test/t/test_mdecrypt.py7
-rw-r--r--test/t/test_mdtool.py7
-rw-r--r--test/t/test_medusa.py7
-rw-r--r--test/t/test_mencoder.py12
-rw-r--r--test/t/test_mii_diag.py12
-rw-r--r--test/t/test_mii_tool.py12
-rw-r--r--test/t/test_minicom.py7
-rw-r--r--test/t/test_mkdir.py21
-rw-r--r--test/t/test_mkfifo.py11
-rw-r--r--test/t/test_mkinitrd.py7
-rw-r--r--test/t/test_mkisofs.py15
-rw-r--r--test/t/test_mknod.py11
-rw-r--r--test/t/test_mktemp.py7
-rw-r--r--test/t/test_mmsitepass.py7
-rw-r--r--test/t/test_mock.py13
-rw-r--r--test/t/test_modinfo.py32
-rw-r--r--test/t/test_modprobe.py36
-rw-r--r--test/t/test_module.py7
-rw-r--r--test/t/test_mogrify.py7
-rw-r--r--test/t/test_monodevelop.py11
-rw-r--r--test/t/test_montage.py7
-rw-r--r--test/t/test_mount.py22
-rw-r--r--test/t/test_mplayer.py12
-rw-r--r--test/t/test_mr.py58
-rw-r--r--test/t/test_msgsnarf.py7
-rw-r--r--test/t/test_msynctool.py7
-rw-r--r--test/t/test_mtx.py7
-rw-r--r--test/t/test_munin_node_configure.py19
-rw-r--r--test/t/test_munin_run.py8
-rw-r--r--test/t/test_munindoc.py10
-rw-r--r--test/t/test_mussh.py7
-rw-r--r--test/t/test_mutt.py33
-rw-r--r--test/t/test_muttng.py7
-rw-r--r--test/t/test_mv.py11
-rw-r--r--test/t/test_mypy.py15
-rw-r--r--test/t/test_mysql.py15
-rw-r--r--test/t/test_mysqladmin.py7
-rw-r--r--test/t/test_nc.py7
-rw-r--r--test/t/test_ncftp.py11
-rw-r--r--test/t/test_nethogs.py11
-rw-r--r--test/t/test_netstat.py11
-rw-r--r--test/t/test_newgrp.py7
-rw-r--r--test/t/test_newlist.py7
-rw-r--r--test/t/test_newusers.py11
-rw-r--r--test/t/test_ngrep.py11
-rw-r--r--test/t/test_nl.py11
-rw-r--r--test/t/test_nm.py11
-rw-r--r--test/t/test_nmap.py47
-rw-r--r--test/t/test_nmcli.py7
-rw-r--r--test/t/test_nproc.py17
-rw-r--r--test/t/test_nslookup.py7
-rw-r--r--test/t/test_nsupdate.py11
-rw-r--r--test/t/test_ntpdate.py7
-rw-r--r--test/t/test_objcopy.py11
-rw-r--r--test/t/test_objdump.py7
-rw-r--r--test/t/test_od.py11
-rw-r--r--test/t/test_oggdec.py11
-rw-r--r--test/t/test_op.py11
-rw-r--r--test/t/test_openssl.py16
-rw-r--r--test/t/test_opera.py11
-rw-r--r--test/t/test_optipng.py11
-rw-r--r--test/t/test_p4.py7
-rw-r--r--test/t/test_pack200.py7
-rw-r--r--test/t/test_passwd.py11
-rw-r--r--test/t/test_paste.py11
-rw-r--r--test/t/test_patch.py11
-rw-r--r--test/t/test_pdftotext.py11
-rw-r--r--test/t/test_perl.py91
-rw-r--r--test/t/test_perlcritic.py15
-rw-r--r--test/t/test_perldoc.py18
-rw-r--r--test/t/test_perltidy.py19
-rw-r--r--test/t/test_pgrep.py35
-rw-r--r--test/t/test_phing.py11
-rw-r--r--test/t/test_pidof.py15
-rw-r--r--test/t/test_pine.py7
-rw-r--r--test/t/test_pinfo.py12
-rw-r--r--test/t/test_ping.py11
-rw-r--r--test/t/test_pkg_config.py12
-rw-r--r--test/t/test_pkg_deinstall.py15
-rw-r--r--test/t/test_pkg_delete.py7
-rw-r--r--test/t/test_pkg_get.py8
-rw-r--r--test/t/test_pkg_info.py7
-rw-r--r--test/t/test_pkgadd.py8
-rw-r--r--test/t/test_pkgrm.py8
-rw-r--r--test/t/test_pkgtool.py7
-rw-r--r--test/t/test_pkgutil.py7
-rw-r--r--test/t/test_pkill.py11
-rw-r--r--test/t/test_plague_client.py8
-rw-r--r--test/t/test_pm_hibernate.py8
-rw-r--r--test/t/test_pm_is_supported.py8
-rw-r--r--test/t/test_pm_powersave.py8
-rw-r--r--test/t/test_pngfix.py11
-rw-r--r--test/t/test_portinstall.py27
-rw-r--r--test/t/test_portsnap.py7
-rw-r--r--test/t/test_portupgrade.py8
-rw-r--r--test/t/test_postcat.py11
-rw-r--r--test/t/test_postconf.py20
-rw-r--r--test/t/test_postfix.py22
-rw-r--r--test/t/test_postmap.py11
-rw-r--r--test/t/test_postsuper.py7
-rw-r--r--test/t/test_povray.py7
-rw-r--r--test/t/test_pr.py11
-rw-r--r--test/t/test_prelink.py11
-rw-r--r--test/t/test_printenv.py19
-rw-r--r--test/t/test_protoc.py20
-rw-r--r--test/t/test_psql.py11
-rw-r--r--test/t/test_ptx.py11
-rw-r--r--test/t/test_puppet.py11
-rw-r--r--test/t/test_pushd.py7
-rw-r--r--test/t/test_pv.py15
-rw-r--r--test/t/test_pvchange.py9
-rw-r--r--test/t/test_pvcreate.py9
-rw-r--r--test/t/test_pvdisplay.py11
-rw-r--r--test/t/test_pvmove.py9
-rw-r--r--test/t/test_pvremove.py9
-rw-r--r--test/t/test_pvs.py9
-rw-r--r--test/t/test_pvscan.py9
-rw-r--r--test/t/test_pwck.py11
-rw-r--r--test/t/test_pwd.py7
-rw-r--r--test/t/test_pwdx.py19
-rw-r--r--test/t/test_pwgen.py7
-rw-r--r--test/t/test_pycodestyle.py15
-rw-r--r--test/t/test_pydoc.py11
-rw-r--r--test/t/test_pydocstyle.py13
-rw-r--r--test/t/test_pyflakes.py11
-rw-r--r--test/t/test_pylint.py11
-rw-r--r--test/t/test_pylint_3.py12
-rw-r--r--test/t/test_pytest.py50
-rw-r--r--test/t/test_python.py39
-rw-r--r--test/t/test_python3.py39
-rw-r--r--test/t/test_pyvenv.py7
-rw-r--r--test/t/test_qemu.py11
-rw-r--r--test/t/test_qrunner.py7
-rw-r--r--test/t/test_querybts.py7
-rw-r--r--test/t/test_quota.py11
-rw-r--r--test/t/test_quotacheck.py7
-rw-r--r--test/t/test_quotaon.py7
-rw-r--r--test/t/test_radvdump.py11
-rw-r--r--test/t/test_rcs.py7
-rw-r--r--test/t/test_rcsdiff.py7
-rw-r--r--test/t/test_rdesktop.py7
-rw-r--r--test/t/test_rdict.py7
-rw-r--r--test/t/test_readelf.py7
-rw-r--r--test/t/test_readonly.py7
-rw-r--r--test/t/test_remove_members.py7
-rw-r--r--test/t/test_removepkg.py15
-rw-r--r--test/t/test_renice.py11
-rw-r--r--test/t/test_repomanage.py11
-rw-r--r--test/t/test_reportbug.py7
-rw-r--r--test/t/test_reptyr.py11
-rw-r--r--test/t/test_resolvconf.py7
-rw-r--r--test/t/test_rfcomm.py7
-rw-r--r--test/t/test_rfkill.py11
-rw-r--r--test/t/test_ri.py16
-rw-r--r--test/t/test_rlog.py7
-rw-r--r--test/t/test_rm.py11
-rw-r--r--test/t/test_rmdir.py16
-rw-r--r--test/t/test_rmlist.py7
-rw-r--r--test/t/test_rmmod.py7
-rw-r--r--test/t/test_route.py7
-rw-r--r--test/t/test_rpcdebug.py7
-rw-r--r--test/t/test_rpm.py15
-rw-r--r--test/t/test_rpm2tgz.py26
-rw-r--r--test/t/test_rpmbuild.py7
-rw-r--r--test/t/test_rrdtool.py7
-rw-r--r--test/t/test_rsync.py16
-rw-r--r--test/t/test_rtcwake.py11
-rw-r--r--test/t/test_runuser.py7
-rw-r--r--test/t/test_sbcl.py7
-rw-r--r--test/t/test_sbcl_mt.py8
-rw-r--r--test/t/test_sbopkg.py7
-rw-r--r--test/t/test_scp.py79
-rw-r--r--test/t/test_screen.py48
-rw-r--r--test/t/test_scrub.py19
-rw-r--r--test/t/test_sdptool.py7
-rw-r--r--test/t/test_secret_tool.py12
-rw-r--r--test/t/test_sed.py7
-rw-r--r--test/t/test_seq.py7
-rw-r--r--test/t/test_service.py7
-rw-r--r--test/t/test_set.py7
-rw-r--r--test/t/test_setquota.py11
-rw-r--r--test/t/test_sftp.py46
-rw-r--r--test/t/test_sh.py19
-rw-r--r--test/t/test_sha1sum.py7
-rw-r--r--test/t/test_shar.py7
-rw-r--r--test/t/test_shellcheck.py19
-rw-r--r--test/t/test_sitecopy.py7
-rw-r--r--test/t/test_slackpkg.py7
-rw-r--r--test/t/test_slapt_get.py44
-rw-r--r--test/t/test_slapt_src.py43
-rw-r--r--test/t/test_smartctl.py7
-rw-r--r--test/t/test_smbcacls.py7
-rw-r--r--test/t/test_smbclient.py7
-rw-r--r--test/t/test_smbcquotas.py7
-rw-r--r--test/t/test_smbget.py7
-rw-r--r--test/t/test_smbpasswd.py7
-rw-r--r--test/t/test_smbtar.py7
-rw-r--r--test/t/test_smbtree.py7
-rw-r--r--test/t/test_snownews.py7
-rw-r--r--test/t/test_sort.py7
-rw-r--r--test/t/test_split.py7
-rw-r--r--test/t/test_spovray.py7
-rw-r--r--test/t/test_sqlite3.py15
-rw-r--r--test/t/test_ss.py15
-rw-r--r--test/t/test_ssh.py60
-rw-r--r--test/t/test_ssh_add.py17
-rw-r--r--test/t/test_ssh_copy_id.py16
-rw-r--r--test/t/test_ssh_keygen.py59
-rw-r--r--test/t/test_sshfs.py8
-rw-r--r--test/t/test_sshmitm.py7
-rw-r--r--test/t/test_sshow.py7
-rw-r--r--test/t/test_strace.py7
-rw-r--r--test/t/test_stream.py7
-rw-r--r--test/t/test_strings.py11
-rw-r--r--test/t/test_strip.py7
-rw-r--r--test/t/test_su.py11
-rw-r--r--test/t/test_sudo.py83
-rw-r--r--test/t/test_sum.py11
-rw-r--r--test/t/test_svcadm.py7
-rw-r--r--test/t/test_svk.py7
-rw-r--r--test/t/test_svn.py7
-rw-r--r--test/t/test_svnadmin.py7
-rw-r--r--test/t/test_svnlook.py7
-rw-r--r--test/t/test_sync_members.py7
-rw-r--r--test/t/test_synclient.py16
-rw-r--r--test/t/test_sysbench.py11
-rw-r--r--test/t/test_sysctl.py15
-rw-r--r--test/t/test_tac.py7
-rw-r--r--test/t/test_tail.py7
-rw-r--r--test/t/test_tar.py120
-rw-r--r--test/t/test_tcpdump.py7
-rw-r--r--test/t/test_tcpkill.py7
-rw-r--r--test/t/test_tcpnice.py7
-rw-r--r--test/t/test_tee.py11
-rw-r--r--test/t/test_texindex.py7
-rw-r--r--test/t/test_tightvncviewer.py7
-rw-r--r--test/t/test_time.py23
-rw-r--r--test/t/test_timeout.py11
-rw-r--r--test/t/test_tipc.py7
-rw-r--r--test/t/test_totem.py7
-rw-r--r--test/t/test_touch.py7
-rw-r--r--test/t/test_tox.py19
-rw-r--r--test/t/test_tr.py7
-rw-r--r--test/t/test_tracepath.py11
-rw-r--r--test/t/test_tshark.py34
-rw-r--r--test/t/test_tsig_keygen.py12
-rw-r--r--test/t/test_tune2fs.py11
-rw-r--r--test/t/test_udevadm.py11
-rw-r--r--test/t/test_ulimit.py35
-rw-r--r--test/t/test_umount.py85
-rw-r--r--test/t/test_unace.py7
-rw-r--r--test/t/test_uname.py7
-rw-r--r--test/t/test_unexpand.py7
-rw-r--r--test/t/test_uniq.py7
-rw-r--r--test/t/test_units.py9
-rw-r--r--test/t/test_unpack200.py7
-rw-r--r--test/t/test_unrar.py7
-rw-r--r--test/t/test_unset.py7
-rw-r--r--test/t/test_unshunt.py7
-rw-r--r--test/t/test_update_alternatives.py8
-rw-r--r--test/t/test_update_rc_d.py8
-rw-r--r--test/t/test_upgradepkg.py51
-rw-r--r--test/t/test_urlsnarf.py7
-rw-r--r--test/t/test_uscan.py7
-rw-r--r--test/t/test_useradd.py11
-rw-r--r--test/t/test_userdel.py11
-rw-r--r--test/t/test_usermod.py11
-rw-r--r--test/t/test_valgrind.py42
-rw-r--r--test/t/test_vdir.py11
-rw-r--r--test/t/test_vgcfgbackup.py11
-rw-r--r--test/t/test_vgcfgrestore.py11
-rw-r--r--test/t/test_vgchange.py9
-rw-r--r--test/t/test_vgck.py9
-rw-r--r--test/t/test_vgconvert.py9
-rw-r--r--test/t/test_vgcreate.py13
-rw-r--r--test/t/test_vgdisplay.py9
-rw-r--r--test/t/test_vgexport.py9
-rw-r--r--test/t/test_vgextend.py9
-rw-r--r--test/t/test_vgimport.py9
-rw-r--r--test/t/test_vgmerge.py9
-rw-r--r--test/t/test_vgmknodes.py9
-rw-r--r--test/t/test_vgreduce.py9
-rw-r--r--test/t/test_vgremove.py9
-rw-r--r--test/t/test_vgrename.py9
-rw-r--r--test/t/test_vgs.py9
-rw-r--r--test/t/test_vgscan.py9
-rw-r--r--test/t/test_vgsplit.py9
-rw-r--r--test/t/test_vi.py11
-rw-r--r--test/t/test_vipw.py7
-rw-r--r--test/t/test_vmstat.py7
-rw-r--r--test/t/test_vncviewer.py8
-rw-r--r--test/t/test_vpnc.py13
-rw-r--r--test/t/test_watch.py7
-rw-r--r--test/t/test_wc.py7
-rw-r--r--test/t/test_webmitm.py7
-rw-r--r--test/t/test_wget.py11
-rw-r--r--test/t/test_who.py9
-rw-r--r--test/t/test_wine.py11
-rw-r--r--test/t/test_withlist.py7
-rw-r--r--test/t/test_wodim.py7
-rw-r--r--test/t/test_wol.py20
-rw-r--r--test/t/test_write.py7
-rw-r--r--test/t/test_wsimport.py18
-rw-r--r--test/t/test_wtf.py8
-rw-r--r--test/t/test_wvdial.py7
-rw-r--r--test/t/test_xdg_mime.py28
-rw-r--r--test/t/test_xdg_settings.py16
-rw-r--r--test/t/test_xfreerdp.py60
-rw-r--r--test/t/test_xgamma.py12
-rw-r--r--test/t/test_xhost.py22
-rw-r--r--test/t/test_xm.py7
-rw-r--r--test/t/test_xmllint.py11
-rw-r--r--test/t/test_xmlwf.py11
-rw-r--r--test/t/test_xmms.py11
-rw-r--r--test/t/test_xmodmap.py11
-rw-r--r--test/t/test_xpovray.py7
-rw-r--r--test/t/test_xrandr.py15
-rw-r--r--test/t/test_xrdb.py11
-rw-r--r--test/t/test_xsltproc.py11
-rw-r--r--test/t/test_xvfb_run.py12
-rw-r--r--test/t/test_xvnc4viewer.py15
-rw-r--r--test/t/test_xxd.py11
-rw-r--r--test/t/test_xz.py26
-rw-r--r--test/t/test_xzdec.py11
-rw-r--r--test/t/test_ypcat.py7
-rw-r--r--test/t/test_ypmatch.py8
-rw-r--r--test/t/test_yum.py7
-rw-r--r--test/t/test_yum_arch.py8
-rw-r--r--test/t/test_zopfli.py15
-rw-r--r--test/t/test_zopflipng.py11
-rw-r--r--test/t/unit/Makefile.am24
-rw-r--r--test/t/unit/test_unit_count_args.py66
-rw-r--r--test/t/unit/test_unit_expand.py31
-rw-r--r--test/t/unit/test_unit_expand_tilde_by_ref.py46
-rw-r--r--test/t/unit/test_unit_filedir.py235
-rw-r--r--test/t/unit/test_unit_find_unique_completion_pair.py55
-rw-r--r--test/t/unit/test_unit_get_comp_words_by_ref.py260
-rw-r--r--test/t/unit/test_unit_get_cword.py154
-rw-r--r--test/t/unit/test_unit_init_completion.py34
-rw-r--r--test/t/unit/test_unit_ip_addresses.py49
-rw-r--r--test/t/unit/test_unit_known_hosts_real.py158
-rw-r--r--test/t/unit/test_unit_longopt.py52
-rw-r--r--test/t/unit/test_unit_parse_help.py183
-rw-r--r--test/t/unit/test_unit_parse_usage.py69
-rw-r--r--test/t/unit/test_unit_quote.py36
-rw-r--r--test/t/unit/test_unit_quote_readline.py15
-rw-r--r--test/t/unit/test_unit_tilde.py42
-rw-r--r--test/t/unit/test_unit_variables.py41
-rw-r--r--test/t/unit/test_unit_xinetd_services.py22
-rw-r--r--test/test-cmd-list.txt687
-rwxr-xr-xtest/update-test-cmd-list13
973 files changed, 13816 insertions, 0 deletions
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644
index 0000000..c428b94
--- /dev/null
+++ b/test/.gitignore
@@ -0,0 +1,2 @@
+tmp/
+pytestdebug.log
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..591c8f7
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,14 @@
+SUBDIRS = t
+
+EXTRA_DIST = config \
+ fixtures \
+ setup.cfg
+
+all:
+ $(MKDIR_P) tmp
+
+CLEANFILES = \
+ fixtures/make/extra_makefile
+
+clean-local:
+ $(RM) -rf tmp
diff --git a/test/config/bashrc b/test/config/bashrc
new file mode 100644
index 0000000..141dddc
--- /dev/null
+++ b/test/config/bashrc
@@ -0,0 +1,62 @@
+# bashrc file for bash-completion test suite
+
+# Note that we do some initialization that would be too late to do here in
+# conftest.py.
+
+# Use emacs key bindings
+set -o emacs
+
+# Use bash strict mode
+set -o posix
+
+# Raise error on uninitialized variables
+set -o nounset
+
+# Unset `command_not_found_handle' as defined on Debian/Ubuntu, because this
+# troubles and slows down testing
+unset -f command_not_found_handle
+
+TESTDIR=$(pwd)
+
+export PS2='> '
+
+# Also test completions of system administrator commands, which are
+# installed via the same PATH expansion in `bash_completion.have()'
+export PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin
+
+# ...as well as games on some systems not in PATH by default:
+export PATH=$PATH:/usr/games:/usr/local/games
+
+# For clean test state, avoid sourcing user's ~/.bash_completion
+export BASH_COMPLETION_USER_FILE=/dev/null
+
+# ...and avoid stuff in BASH_COMPLETION_USER_DIR and system install locations
+# overriding in-tree completions. Setting the user dir would otherwise suffice,
+# but simple xspec completions are only installed if a separate one is not
+# found in any completion dirs. Therefore we also point the "system" dirs to
+# locations that should not yield valid completions and helpers paths either.
+export BASH_COMPLETION_USER_DIR=$(
+ cd "$SRCDIR/.." || exit 1
+ pwd
+)
+# /var/empty isn't necessarily actually always empty :P
+export BASH_COMPLETION_COMPAT_DIR=/var/empty/bash_completion.d
+export XDG_DATA_DIRS=/var/empty
+
+# Make sure default settings are in effect
+unset -v \
+ COMP_CONFIGURE_HINTS \
+ COMP_CVS_REMOTE \
+ COMP_KNOWN_HOSTS_WITH_HOSTFILE \
+ COMP_TAR_INTERNAL_PATHS
+
+# @param $1 Char to add to $COMP_WORDBREAKS
+add_comp_wordbreak_char()
+{
+ [[ "${COMP_WORDBREAKS//[^$1]/}" ]] || COMP_WORDBREAKS+=$1
+}
+
+# Local variables:
+# mode: shell-script
+# End:
+# ex: filetype=sh
diff --git a/test/config/inputrc b/test/config/inputrc
new file mode 100644
index 0000000..da896f5
--- /dev/null
+++ b/test/config/inputrc
@@ -0,0 +1,22 @@
+# Readline init file for bash-completion test suite
+# See: info readline
+
+# Press TAB once (instead of twice) to auto-complete
+set show-all-if-ambiguous on
+
+# No bell. No ^G in output
+set bell-style none
+
+# Don't query user about viewing the number of possible completions
+set completion-query-items -1
+
+# Don't use pager when showing completions
+set page-completions off
+
+# Print each completion on its own line
+set completion-display-width 0
+
+# Local variables:
+# mode: shell-script
+# End:
+# ex: filetype=sh
diff --git a/test/docker/Dockerfile b/test/docker/Dockerfile
new file mode 100644
index 0000000..200f918
--- /dev/null
+++ b/test/docker/Dockerfile
@@ -0,0 +1,6 @@
+ARG DIST
+FROM vskytta/bash-completion:$DIST
+
+WORKDIR /work
+COPY . .
+CMD ["test/docker/docker-script.sh"]
diff --git a/test/docker/docker-script.sh b/test/docker/docker-script.sh
new file mode 100755
index 0000000..b3f351f
--- /dev/null
+++ b/test/docker/docker-script.sh
@@ -0,0 +1,16 @@
+#!/bin/sh -ex
+
+if [ "$BSD" ]; then
+ PATH=/usr/local/lib/bsd-bin:$PATH
+ export PATH
+fi
+
+export bashcomp_bash=bash
+env
+
+autoreconf -i
+./configure
+make -j
+
+xvfb-run make distcheck \
+ PYTESTFLAGS="--verbose --numprocesses=auto --dist=loadfile"
diff --git a/test/fixtures/7z/a.7z b/test/fixtures/7z/a.7z
new file mode 100644
index 0000000..3357064
--- /dev/null
+++ b/test/fixtures/7z/a.7z
Binary files differ
diff --git a/test/fixtures/7z/f.txt b/test/fixtures/7z/f.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/test/fixtures/7z/f.txt
@@ -0,0 +1 @@
+
diff --git a/test/fixtures/_filedir/a b/i b/test/fixtures/_filedir/a b/i
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_filedir/a b/i
diff --git a/test/fixtures/_filedir/a$b/h b/test/fixtures/_filedir/a$b/h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_filedir/a$b/h
diff --git a/test/fixtures/_filedir/a&b/f b/test/fixtures/_filedir/a&b/f
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_filedir/a&b/f
diff --git a/test/fixtures/_filedir/a'b/c b/test/fixtures/_filedir/a'b/c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_filedir/a'b/c
diff --git a/test/fixtures/_filedir/ab/e b/test/fixtures/_filedir/ab/e
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_filedir/ab/e
diff --git a/test/fixtures/_filedir/aé/g b/test/fixtures/_filedir/aé/g
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_filedir/aé/g
diff --git a/test/fixtures/_filedir/brackets/[x] b/test/fixtures/_filedir/brackets/[x]
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/test/fixtures/_filedir/brackets/[x]
@@ -0,0 +1 @@
+
diff --git a/test/fixtures/_filedir/brackets/x b/test/fixtures/_filedir/brackets/x
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/test/fixtures/_filedir/brackets/x
@@ -0,0 +1 @@
+
diff --git a/test/fixtures/_filedir/ext/ee.e1 b/test/fixtures/_filedir/ext/ee.e1
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_filedir/ext/ee.e1
diff --git a/test/fixtures/_filedir/ext/ff.e2 b/test/fixtures/_filedir/ext/ff.e2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_filedir/ext/ff.e2
diff --git a/test/fixtures/_filedir/ext/foo/.gitignore b/test/fixtures/_filedir/ext/foo/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_filedir/ext/foo/.gitignore
diff --git a/test/fixtures/_filedir/ext/gg.e1 b/test/fixtures/_filedir/ext/gg.e1
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_filedir/ext/gg.e1
diff --git a/test/fixtures/_filedir/ext/hh.e2 b/test/fixtures/_filedir/ext/hh.e2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_filedir/ext/hh.e2
diff --git a/test/fixtures/_filedir/ext/ii.E1 b/test/fixtures/_filedir/ext/ii.E1
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_filedir/ext/ii.E1
diff --git a/test/fixtures/_get_cword/sea b/test/fixtures/_get_cword/sea
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_get_cword/sea
diff --git a/test/fixtures/_get_cword/seb b/test/fixtures/_get_cword/seb
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_get_cword/seb
diff --git a/test/fixtures/_get_cword/sec b/test/fixtures/_get_cword/sec
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_get_cword/sec
diff --git a/test/fixtures/_get_cword/ääää§ b/test/fixtures/_get_cword/ääää§
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_get_cword/ääää§
diff --git a/test/fixtures/_known_hosts_real/.ssh/config_asterisk_1 b/test/fixtures/_known_hosts_real/.ssh/config_asterisk_1
new file mode 100644
index 0000000..fc09eb0
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/.ssh/config_asterisk_1
@@ -0,0 +1 @@
+Host asterisk_1
diff --git a/test/fixtures/_known_hosts_real/.ssh/config_asterisk_2 b/test/fixtures/_known_hosts_real/.ssh/config_asterisk_2
new file mode 100644
index 0000000..42243ad
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/.ssh/config_asterisk_2
@@ -0,0 +1 @@
+Host asterisk_2
diff --git a/test/fixtures/_known_hosts_real/.ssh/config_question_mark b/test/fixtures/_known_hosts_real/.ssh/config_question_mark
new file mode 100644
index 0000000..08e1201
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/.ssh/config_question_mark
@@ -0,0 +1 @@
+Host question_mark
diff --git a/test/fixtures/_known_hosts_real/.ssh/config_relative_path b/test/fixtures/_known_hosts_real/.ssh/config_relative_path
new file mode 100644
index 0000000..a7ad4d1
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/.ssh/config_relative_path
@@ -0,0 +1 @@
+Host relative_path
diff --git a/test/fixtures/_known_hosts_real/config b/test/fixtures/_known_hosts_real/config
new file mode 100644
index 0000000..fe3fb54
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/config
@@ -0,0 +1,7 @@
+ UserKnownHostsFile _known_hosts_real/known_hosts
+
+ # Unindented
+Host gee* jar?this-part-we-do-not-complete-at-least-yet
+ HostName %h.example.com
+ # Indented
+ Host hus%%eth0 !negated #not-a-comment
diff --git a/test/fixtures/_known_hosts_real/config_full_path b/test/fixtures/_known_hosts_real/config_full_path
new file mode 100644
index 0000000..a91649b
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/config_full_path
@@ -0,0 +1 @@
+Include ~/config_include_recursion
diff --git a/test/fixtures/_known_hosts_real/config_include b/test/fixtures/_known_hosts_real/config_include
new file mode 100644
index 0000000..a1ae763
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/config_include
@@ -0,0 +1,7 @@
+#$HOME set to fixtures/_known_hosts_real in unit test
+# Include with full path (recursive one)
+Include ~/config_full_path
+# Include with relative path
+Include config_relative_path
+# Include with wildcards, and more than one on same row
+Include config_asterisk* config_?uestion_mark
diff --git a/test/fixtures/_known_hosts_real/config_include_recursion b/test/fixtures/_known_hosts_real/config_include_recursion
new file mode 100644
index 0000000..2777069
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/config_include_recursion
@@ -0,0 +1 @@
+Host recursion
diff --git a/test/fixtures/_known_hosts_real/config_tilde b/test/fixtures/_known_hosts_real/config_tilde
new file mode 100644
index 0000000..4181aaf
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/config_tilde
@@ -0,0 +1,4 @@
+# With quotes and tilde
+UserKnownHostsFile "~/_known_hosts_real/known_hosts2"
+# Without quotes, with tilde, and another on the same line
+UserKnownHostsFile ~/_known_hosts_real/known_hosts3 _known_hosts_real/known_hosts4
diff --git a/test/fixtures/_known_hosts_real/gee-filename-canary b/test/fixtures/_known_hosts_real/gee-filename-canary
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/gee-filename-canary
diff --git a/test/fixtures/_known_hosts_real/known_hosts b/test/fixtures/_known_hosts_real/known_hosts
new file mode 100644
index 0000000..646b5b6
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/known_hosts
@@ -0,0 +1,14 @@
+|1|abc
+|1|def
+doo
+# this is a comment
+ike ssh-rsa qwerty1234/Qwerty+1234==
+jub,10.0.0.1
+@cert-authority kyl,100.0.0.2 xxxfoo
+[10.10.0.3]:10022
+[blah]:1234
+fd00:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:5555
+fe80::123:0xff:dead:beef%eth0
+1111:2222:3333:4444:5555:6666:xxxx:abab
+11xx:2222:3333:4444:5555:6666:xxxx:abab
+::42
diff --git a/test/fixtures/_known_hosts_real/known_hosts2 b/test/fixtures/_known_hosts_real/known_hosts2
new file mode 100644
index 0000000..2eb4d4f
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/known_hosts2
@@ -0,0 +1 @@
+two,two2,two3,two*,t?o,two4
diff --git a/test/fixtures/_known_hosts_real/known_hosts3 b/test/fixtures/_known_hosts_real/known_hosts3
new file mode 100644
index 0000000..2bdf67a
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/known_hosts3
@@ -0,0 +1 @@
+three
diff --git a/test/fixtures/_known_hosts_real/known_hosts4 b/test/fixtures/_known_hosts_real/known_hosts4
new file mode 100644
index 0000000..8510665
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/known_hosts4
@@ -0,0 +1 @@
+four
diff --git a/test/fixtures/_known_hosts_real/localhost_config b/test/fixtures/_known_hosts_real/localhost_config
new file mode 100644
index 0000000..30b6623
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/localhost_config
@@ -0,0 +1 @@
+UserKnownHostsFile _known_hosts_real/localhost_hosts
diff --git a/test/fixtures/_known_hosts_real/localhost_hosts b/test/fixtures/_known_hosts_real/localhost_hosts
new file mode 100644
index 0000000..ff752c2
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/localhost_hosts
@@ -0,0 +1,3 @@
+localhost
+127.0.0.1
+::1
diff --git a/test/fixtures/_known_hosts_real/spaced conf b/test/fixtures/_known_hosts_real/spaced conf
new file mode 100644
index 0000000..566b92c
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/spaced conf
@@ -0,0 +1,8 @@
+
+ # Unindented
+Host gee
+ UserKnownHostsFile "_known_hosts_real/spaced known_hosts"
+
+ # Indented
+ Host hus #not-a-comment
+ UserKnownHostsFile "_known_hosts_real/known_hosts2"
diff --git a/test/fixtures/_known_hosts_real/spaced known_hosts b/test/fixtures/_known_hosts_real/spaced known_hosts
new file mode 100644
index 0000000..d54a04d
--- /dev/null
+++ b/test/fixtures/_known_hosts_real/spaced known_hosts
@@ -0,0 +1,4 @@
+|1|abc
+|1|def
+doo
+ike ssh-rsa qwerty1234/Qwerty+1234==
diff --git a/test/fixtures/_longopt/grep--help.txt b/test/fixtures/_longopt/grep--help.txt
new file mode 100644
index 0000000..9266256
--- /dev/null
+++ b/test/fixtures/_longopt/grep--help.txt
@@ -0,0 +1,70 @@
+Usage: grep [OPTION]... PATTERN [FILE]...
+Search for PATTERN in each FILE.
+Example: grep -i 'hello world' menu.h main.c
+
+Pattern selection and interpretation:
+ -E, --extended-regexp PATTERN is an extended regular expression
+ -F, --fixed-strings PATTERN is a set of newline-separated strings
+ -G, --basic-regexp PATTERN is a basic regular expression (default)
+ -P, --perl-regexp PATTERN is a Perl regular expression
+ -e, --regexp=PATTERN use PATTERN for matching
+ -f, --file=FILE obtain PATTERN from FILE
+ -i, --ignore-case ignore case distinctions
+ -w, --word-regexp force PATTERN to match only whole words
+ -x, --line-regexp force PATTERN to match only whole lines
+ -z, --null-data a data line ends in 0 byte, not newline
+
+Miscellaneous:
+ -s, --no-messages suppress error messages
+ -v, --invert-match select non-matching lines
+ -V, --version display version information and exit
+ --help display this help text and exit
+
+Output control:
+ -m, --max-count=NUM stop after NUM selected lines
+ -b, --byte-offset print the byte offset with output lines
+ -n, --line-number print line number with output lines
+ --line-buffered flush output on every line
+ -H, --with-filename print file name with output lines
+ -h, --no-filename suppress the file name prefix on output
+ --label=LABEL use LABEL as the standard input file name prefix
+ -o, --only-matching show only the part of a line matching PATTERN
+ -q, --quiet, --silent suppress all normal output
+ --binary-files=TYPE assume that binary files are TYPE;
+ TYPE is 'binary', 'text', or 'without-match'
+ -a, --text equivalent to --binary-files=text
+ -I equivalent to --binary-files=without-match
+ -d, --directories=ACTION how to handle directories;
+ ACTION is 'read', 'recurse', or 'skip'
+ -D, --devices=ACTION how to handle devices, FIFOs and sockets;
+ ACTION is 'read' or 'skip'
+ -r, --recursive like --directories=recurse
+ -R, --dereference-recursive likewise, but follow all symlinks
+ --include=FILE_PATTERN search only files that match FILE_PATTERN
+ --exclude=FILE_PATTERN skip files and directories matching FILE_PATTERN
+ --exclude-from=FILE skip files matching any file pattern from FILE
+ --exclude-dir=PATTERN directories that match PATTERN will be skipped.
+ -L, --files-without-match print only names of FILEs with no selected lines
+ -l, --files-with-matches print only names of FILEs with selected lines
+ -c, --count print only a count of selected lines per FILE
+ -T, --initial-tab make tabs line up (if needed)
+ -Z, --null print 0 byte after FILE name
+
+Context control:
+ -B, --before-context=NUM print NUM lines of leading context
+ -A, --after-context=NUM print NUM lines of trailing context
+ -C, --context=NUM print NUM lines of output context
+ -NUM same as --context=NUM
+ --color[=WHEN],
+ --colour[=WHEN] use markers to highlight the matching strings;
+ WHEN is 'always', 'never', or 'auto'
+ -U, --binary do not strip CR characters at EOL (MSDOS/Windows)
+
+When FILE is '-', read standard input. With no FILE, read '.' if
+recursive, '-' otherwise. With fewer than two FILEs, assume -h.
+Exit status is 0 if any line is selected, 1 otherwise;
+if any error occurs and -q is not given, the exit status is 2.
+
+Report bugs to: bug-grep@gnu.org
+GNU grep home page: <http://www.gnu.org/software/grep/>
+General help using GNU software: <http://www.gnu.org/gethelp/>
diff --git a/test/fixtures/_longopt/various.txt b/test/fixtures/_longopt/various.txt
new file mode 100644
index 0000000..04c2c25
--- /dev/null
+++ b/test/fixtures/_longopt/various.txt
@@ -0,0 +1,5 @@
+---
+----nonono
+--foo_bar
+--foo-
+--foo=bar
diff --git a/test/fixtures/acroread/bar b/test/fixtures/acroread/bar
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/acroread/bar
diff --git a/test/fixtures/acroread/foo.d/.gitignore b/test/fixtures/acroread/foo.d/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/acroread/foo.d/.gitignore
diff --git a/test/fixtures/acroread/t.pdf b/test/fixtures/acroread/t.pdf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/acroread/t.pdf
diff --git a/test/fixtures/ant/.gitignore b/test/fixtures/ant/.gitignore
new file mode 100644
index 0000000..3a08258
--- /dev/null
+++ b/test/fixtures/ant/.gitignore
@@ -0,0 +1 @@
+.ant-targets-*.xml
diff --git a/test/fixtures/ant/build-with-import.xml b/test/fixtures/ant/build-with-import.xml
new file mode 100644
index 0000000..881981a
--- /dev/null
+++ b/test/fixtures/ant/build-with-import.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project default="build-with-import" name="bash-completion">
+ <import file="imported-build.xml" />
+
+ <target name="build-with-import">
+ <!-- ... -->
+ </target>
+</project>
diff --git a/test/fixtures/ant/build.xml b/test/fixtures/ant/build.xml
new file mode 100644
index 0000000..09b4cd2
--- /dev/null
+++ b/test/fixtures/ant/build.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project basedir="." default="build" name="bash-completion">
+ <target name="clean">
+ <!-- ... -->
+ </target>
+<target
+ name="realclean" depends="clean">
+ <!-- ... -->
+ </target>
+
+ <target description="bar" name="init"></target>
+<target
+description="bar"
+name='bashcomp' >
+<!-- ... -->
+</target>
+</project>
diff --git a/test/fixtures/ant/imported-build.xml b/test/fixtures/ant/imported-build.xml
new file mode 100644
index 0000000..0cc438f
--- /dev/null
+++ b/test/fixtures/ant/imported-build.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project default="imported-build" name="bash-completion">
+ <target name="imported-build">
+ <!-- ... -->
+ </target>
+</project>
diff --git a/test/fixtures/ant/named-build.xml b/test/fixtures/ant/named-build.xml
new file mode 100644
index 0000000..e61386d
--- /dev/null
+++ b/test/fixtures/ant/named-build.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project basedir="." default="named-build" name="bash-completion">
+ <target name="named-build">
+ <!-- ... -->
+ </target>
+</project>
diff --git a/test/fixtures/compgen/a'b/c b/test/fixtures/compgen/a'b/c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/compgen/a'b/c
diff --git a/test/fixtures/compgen/t1.txt b/test/fixtures/compgen/t1.txt
new file mode 100644
index 0000000..322a14d
--- /dev/null
+++ b/test/fixtures/compgen/t1.txt
@@ -0,0 +1,121 @@
+BASH=/bin/bash
+BASH_ARGC=()
+BASH_ARGV=()
+BASH_LINENO=()
+BASH_SOURCE=()
+BASH_VERSINFO=([0]="3" [1]="2" [2]="39" [3]="1" [4]="release" [5]="i486-pc-linux-gnu")
+BASH_VERSION='3.2.39(1)-release'
+CDPL_DIRS=([0]="/home/freddy/proj")
+CDPM_DIRS=
+CDP_DIRS=([0]="/home/freddy/proj" [1]="")
+COLUMNS=130
+COMP_CACHE=/home/freddy/.bash_completion_lib.d/cache~
+COMP_DIR=/etc/bash_completion_lib
+COMP_PATH=/home/freddy/.bash_completion_lib.d:/etc/bash_completion_lib
+COMP_RESTRICT_BY_EXTENSION=0
+COMP_VERSION=bash_completion_lib-1.3.1
+DIRSTACK=()
+EDITOR=/usr/bin/vim
+EUID=1000
+GPGKEY=10A575C3
+GPG_AGENT_INFO=/tmp/gpg-Pg6JXR/S.gpg-agent:4129:1
+GPG_TTY=/dev/pts/0
+GREP_OPTIONS='--exclude '\''distrib/*'\'' --exclude tags'
+GROUPS=()
+HISTCONTROL=ignoreboth
+HISTFILE=/home/freddy/.bash_history
+HISTFILESIZE=500
+HISTIGNORE=exit
+HISTSIZE=500
+HOME=/home/freddy
+HOSTNAME=blondy
+HOSTTYPE=i486
+IFS=$' \t\n'
+LANG=en_US
+LANGUAGE=en_NL:en_US:en_GB:en
+LINES=49
+LOGNAME=freddy
+MACHTYPE=i486-pc-linux-gnu
+MAIL=/var/mail/freddy
+MAILCHECK=60
+OLDPWD=/home/freddy/.bash_completion_lib.d
+OPTERR=1
+OPTIND=1
+OSTYPE=linux-gnu
+PATH=/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:/home/freddy/proj/rc/bin
+PIPESTATUS=([0]="0")
+PPID=29352
+PS1=$'\\[\E[0;34m\\]\\!\\[\E[0m\\]\\[\E[1;32m\\]$(stoppedjobs)\\[\E[0m\\]:\\u@\\h:\\w> \\[\E[m\\]'
+PS2='> '
+PS4='+ '
+PWD=/home/freddy/proj/bashCompletion/bash-completion.git/test/fixtures/compgen
+SHELL=/bin/bash
+SHELLOPTS=braceexpand:hashall:histexpand:interactive-comments:monitor:vi
+SHLVL=1
+SSH_AUTH_SOCK=/tmp/ssh-xhQbo29352/agent.29352
+SSH_CLIENT='192.168.123.143 37670 4822'
+SSH_CONNECTION='192.168.123.143 37670 192.168.123.8 4822'
+SSH_TTY=/dev/pts/0
+TERM=xterm
+UID=1000
+USER=freddy
+VIM=/home/freddy/.vim
+VIMRUNTIME=/usr/share/vim/vimcurrent
+_=GPG_AGENT_INFO
+bash205='3.2.39(1)-release'
+bash205b='3.2.39(1)-release'
+bash3='3.2.39(1)-release'
+cdots ()
+{
+ [ -d "$1$2" ] && cd "$1$2" || eval cd "$1$2"
+}
+comp_load ()
+{
+ local cmd=${COMP_WORDS[0]} dir globs OLDIFS=$IFS;
+ IFS=:;
+ local -a aPaths=($COMP_PATH);
+ IFS='
+';
+ globs=($(
+ for dir in "${aPaths[@]}"; do
+ echo \"$dir\"/complete\*/\*.$cmd
+ echo \"$dir\"/complete\*/$cmd\!
+ echo \"$dir\"/complete\*/$cmd
+ done
+ ));
+ IFS=$OLDIFS;
+ if ! declare -F comp_include >&/dev/null; then
+ for dir in "${aPaths[@]}";
+ do
+ [ -r "$dir/include/comp_include" ] && . "$dir/include/comp_include" && break;
+ done;
+ fi;
+ comp_include comp_load_init;
+ comp_load_init;
+ local script="$(eval find "${globs[@]}" 2> /dev/null | head -1)";
+ local link comp=${script##*/};
+ [[ ${comp: -1:1} == ! ]] || {
+ link=${comp#*.};
+ comp=${comp%.$link}
+ };
+ local path=${script%/*};
+ [ "$script" -a -r "$path/$comp" ] && . "$path/$comp" && declare -F _$comp >&/dev/null && {
+ [ ${COMP_INSTALL:-1} -eq 0 ] || _comp_install $comp "$path"
+ } && _$comp $link;
+ comp_load_deinit
+}
+nameTerminal ()
+{
+ [ "${TERM:0:5}" = "xterm" ] && local ansiNrTab=0;
+ [ "$TERM" = "rxvt" ] && local ansiNrTab=61;
+ [ "$TERM" = "konsole" ] && local ansiNrTab=30 ansiNrWindow=0;
+ [ $ansiNrTab ] && echo -n ''"]$ansiNrTab;$1"'';
+ [ $ansiNrWindow -a "$2" ] && echo -n ''"]$ansiNrWindow;$2"''
+}
+stoppedjobs ()
+{
+ if [ "$(jobs -s)" ]; then
+ echo -n "%";
+ jobs -s | wc -l;
+ fi
+}
diff --git a/test/fixtures/compgen/t2.txt b/test/fixtures/compgen/t2.txt
new file mode 100644
index 0000000..371ab2b
--- /dev/null
+++ b/test/fixtures/compgen/t2.txt
@@ -0,0 +1,121 @@
+BASH=/bin/bash
+BASH_ARGC=()
+BASH_ARGV=()
+BASH_LINENO=()
+BASH_SOURCE=()
+BASH_VERSINFO=([0]="3" [1]="2" [2]="39" [3]="1" [4]="release" [5]="i486-pc-linux-gnu")
+BASH_VERSION='3.2.39(1)-release'
+CDPL_DIRS=([0]="/home/freddy/proj")
+CDPM_DIRS=
+CDP_DIRS=([0]="/home/freddy/proj" [1]="")
+COLUMNS=130
+COMP_CACHE=/home/freddy/.bash_completion_lib.d/cache~
+COMP_DIR=/etc/bash_completion_lib
+COMP_PATH=/home/freddy/.bash_completion_lib.d:/etc/bash_completion_lib
+COMP_RESTRICT_BY_EXTENSION=0
+COMP_VERSION=bash_completion_lib-1.3.1
+DIRSTACK=()
+EDITOR=/usr/bin/vim
+EUID=1000
+GPGKEY=10A575C3
+GPG_AGENT_INFO=/tmp/gpg-Pg6JXR/S.gpg-agent:4129:1
+GPG_TTY=/dev/pts/0
+GREP_OPTIONS='--exclude '\''distrib/*'\'' --exclude tags'
+GROUPS=()
+HISTCONTROL=ignoreboth
+HISTFILE=/home/freddy/.bash_history
+HISTFILESIZE=500
+HISTIGNORE=exit
+HISTSIZE=500
+HOME=/home/freddy
+HOSTNAME=blondy
+HOSTTYPE=i486
+IFS=$' \t\n'
+LANG=en_US
+LANGUAGE=en_NL:en_US:en_GB:en
+LINES=49
+LOGNAME=freddy
+MACHTYPE=i486-pc-linux-gnu
+MAIL=/var/mail/freddy
+MAILCHECK=60
+OLDPWD=/home/freddy/.bash_completion_lib.d
+OPTERR=1
+OPTIND=1
+OSTYPE=linux-gnu
+PATH=/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:/home/freddy/proj/rc/bin
+PIPESTATUS=([0]="0")
+PPID=29352
+PS1=$'\\[\E[0;34m\\]\\!\\[\E[0m\\]\\[\E[1;32m\\]$(stoppedjobs)\\[\E[0m\\]:\\u@\\h:\\w> \\[\E[m\\]'
+PS2='> '
+PS4='+ '
+PWD=/home/freddy/proj/bashCompletion/bash-completion.git/test/fixtures/compgen
+SHELL=/bin/bash
+SHELLOPTS=braceexpand:hashall:histexpand:interactive-comments:monitor:vi
+SHLVL=1
+SSH_AUTH_SOCK=/tmp/ssh-xhQbo29352/agent.29352
+SSH_CLIENT='192.168.123.143 37670 4822'
+SSH_CONNECTION='192.168.123.143 37670 192.168.123.8 4822'
+SSH_TTY=/dev/pts/0
+TERM=xterm
+UID=1000
+USER=freddy
+VIM=/home/freddy/.vim
+VIMRUNTIME=/usr/share/vim/vimcurrent
+_='a\\\'\''b/'
+bash205='3.2.39(1)-release'
+bash205b='3.2.39(1)-release'
+bash3='3.2.39(1)-release'
+cdots ()
+{
+ [ -d "$1$2" ] && cd "$1$2" || eval cd "$1$2"
+}
+comp_load ()
+{
+ local cmd=${COMP_WORDS[0]} dir globs OLDIFS=$IFS;
+ IFS=:;
+ local -a aPaths=($COMP_PATH);
+ IFS='
+';
+ globs=($(
+ for dir in "${aPaths[@]}"; do
+ echo \"$dir\"/complete\*/\*.$cmd
+ echo \"$dir\"/complete\*/$cmd\!
+ echo \"$dir\"/complete\*/$cmd
+ done
+ ));
+ IFS=$OLDIFS;
+ if ! declare -F comp_include >&/dev/null; then
+ for dir in "${aPaths[@]}";
+ do
+ [ -r "$dir/include/comp_include" ] && . "$dir/include/comp_include" && break;
+ done;
+ fi;
+ comp_include comp_load_init;
+ comp_load_init;
+ local script="$(eval find "${globs[@]}" 2> /dev/null | head -1)";
+ local link comp=${script##*/};
+ [[ ${comp: -1:1} == ! ]] || {
+ link=${comp#*.};
+ comp=${comp%.$link}
+ };
+ local path=${script%/*};
+ [ "$script" -a -r "$path/$comp" ] && . "$path/$comp" && declare -F _$comp >&/dev/null && {
+ [ ${COMP_INSTALL:-1} -eq 0 ] || _comp_install $comp "$path"
+ } && _$comp $link;
+ comp_load_deinit
+}
+nameTerminal ()
+{
+ [ "${TERM:0:5}" = "xterm" ] && local ansiNrTab=0;
+ [ "$TERM" = "rxvt" ] && local ansiNrTab=61;
+ [ "$TERM" = "konsole" ] && local ansiNrTab=30 ansiNrWindow=0;
+ [ $ansiNrTab ] && echo -n ''"]$ansiNrTab;$1"'';
+ [ $ansiNrWindow -a "$2" ] && echo -n ''"]$ansiNrWindow;$2"''
+}
+stoppedjobs ()
+{
+ if [ "$(jobs -s)" ]; then
+ echo -n "%";
+ jobs -s | wc -l;
+ fi
+}
diff --git a/test/fixtures/compgen/t3.txt b/test/fixtures/compgen/t3.txt
new file mode 100644
index 0000000..371ab2b
--- /dev/null
+++ b/test/fixtures/compgen/t3.txt
@@ -0,0 +1,121 @@
+BASH=/bin/bash
+BASH_ARGC=()
+BASH_ARGV=()
+BASH_LINENO=()
+BASH_SOURCE=()
+BASH_VERSINFO=([0]="3" [1]="2" [2]="39" [3]="1" [4]="release" [5]="i486-pc-linux-gnu")
+BASH_VERSION='3.2.39(1)-release'
+CDPL_DIRS=([0]="/home/freddy/proj")
+CDPM_DIRS=
+CDP_DIRS=([0]="/home/freddy/proj" [1]="")
+COLUMNS=130
+COMP_CACHE=/home/freddy/.bash_completion_lib.d/cache~
+COMP_DIR=/etc/bash_completion_lib
+COMP_PATH=/home/freddy/.bash_completion_lib.d:/etc/bash_completion_lib
+COMP_RESTRICT_BY_EXTENSION=0
+COMP_VERSION=bash_completion_lib-1.3.1
+DIRSTACK=()
+EDITOR=/usr/bin/vim
+EUID=1000
+GPGKEY=10A575C3
+GPG_AGENT_INFO=/tmp/gpg-Pg6JXR/S.gpg-agent:4129:1
+GPG_TTY=/dev/pts/0
+GREP_OPTIONS='--exclude '\''distrib/*'\'' --exclude tags'
+GROUPS=()
+HISTCONTROL=ignoreboth
+HISTFILE=/home/freddy/.bash_history
+HISTFILESIZE=500
+HISTIGNORE=exit
+HISTSIZE=500
+HOME=/home/freddy
+HOSTNAME=blondy
+HOSTTYPE=i486
+IFS=$' \t\n'
+LANG=en_US
+LANGUAGE=en_NL:en_US:en_GB:en
+LINES=49
+LOGNAME=freddy
+MACHTYPE=i486-pc-linux-gnu
+MAIL=/var/mail/freddy
+MAILCHECK=60
+OLDPWD=/home/freddy/.bash_completion_lib.d
+OPTERR=1
+OPTIND=1
+OSTYPE=linux-gnu
+PATH=/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:/home/freddy/proj/rc/bin
+PIPESTATUS=([0]="0")
+PPID=29352
+PS1=$'\\[\E[0;34m\\]\\!\\[\E[0m\\]\\[\E[1;32m\\]$(stoppedjobs)\\[\E[0m\\]:\\u@\\h:\\w> \\[\E[m\\]'
+PS2='> '
+PS4='+ '
+PWD=/home/freddy/proj/bashCompletion/bash-completion.git/test/fixtures/compgen
+SHELL=/bin/bash
+SHELLOPTS=braceexpand:hashall:histexpand:interactive-comments:monitor:vi
+SHLVL=1
+SSH_AUTH_SOCK=/tmp/ssh-xhQbo29352/agent.29352
+SSH_CLIENT='192.168.123.143 37670 4822'
+SSH_CONNECTION='192.168.123.143 37670 192.168.123.8 4822'
+SSH_TTY=/dev/pts/0
+TERM=xterm
+UID=1000
+USER=freddy
+VIM=/home/freddy/.vim
+VIMRUNTIME=/usr/share/vim/vimcurrent
+_='a\\\'\''b/'
+bash205='3.2.39(1)-release'
+bash205b='3.2.39(1)-release'
+bash3='3.2.39(1)-release'
+cdots ()
+{
+ [ -d "$1$2" ] && cd "$1$2" || eval cd "$1$2"
+}
+comp_load ()
+{
+ local cmd=${COMP_WORDS[0]} dir globs OLDIFS=$IFS;
+ IFS=:;
+ local -a aPaths=($COMP_PATH);
+ IFS='
+';
+ globs=($(
+ for dir in "${aPaths[@]}"; do
+ echo \"$dir\"/complete\*/\*.$cmd
+ echo \"$dir\"/complete\*/$cmd\!
+ echo \"$dir\"/complete\*/$cmd
+ done
+ ));
+ IFS=$OLDIFS;
+ if ! declare -F comp_include >&/dev/null; then
+ for dir in "${aPaths[@]}";
+ do
+ [ -r "$dir/include/comp_include" ] && . "$dir/include/comp_include" && break;
+ done;
+ fi;
+ comp_include comp_load_init;
+ comp_load_init;
+ local script="$(eval find "${globs[@]}" 2> /dev/null | head -1)";
+ local link comp=${script##*/};
+ [[ ${comp: -1:1} == ! ]] || {
+ link=${comp#*.};
+ comp=${comp%.$link}
+ };
+ local path=${script%/*};
+ [ "$script" -a -r "$path/$comp" ] && . "$path/$comp" && declare -F _$comp >&/dev/null && {
+ [ ${COMP_INSTALL:-1} -eq 0 ] || _comp_install $comp "$path"
+ } && _$comp $link;
+ comp_load_deinit
+}
+nameTerminal ()
+{
+ [ "${TERM:0:5}" = "xterm" ] && local ansiNrTab=0;
+ [ "$TERM" = "rxvt" ] && local ansiNrTab=61;
+ [ "$TERM" = "konsole" ] && local ansiNrTab=30 ansiNrWindow=0;
+ [ $ansiNrTab ] && echo -n ''"]$ansiNrTab;$1"'';
+ [ $ansiNrWindow -a "$2" ] && echo -n ''"]$ansiNrWindow;$2"''
+}
+stoppedjobs ()
+{
+ if [ "$(jobs -s)" ]; then
+ echo -n "%";
+ jobs -s | wc -l;
+ fi
+}
diff --git a/test/fixtures/cvs/.cvspass b/test/fixtures/cvs/.cvspass
new file mode 100644
index 0000000..e7e0dce
--- /dev/null
+++ b/test/fixtures/cvs/.cvspass
@@ -0,0 +1,2 @@
+/1 :pserver:anonymous@cvs.savannah.nongnu.org:2401/sources/cvs A
+/1 :pserver:anonymous@cvs.fedoraproject.org:2401/cvs/pkgs A
diff --git a/test/fixtures/cvs/foo/CVS/Entries b/test/fixtures/cvs/foo/CVS/Entries
new file mode 100644
index 0000000..6462f98
--- /dev/null
+++ b/test/fixtures/cvs/foo/CVS/Entries
@@ -0,0 +1,2 @@
+/bar/1.1/Tue Jan 29 05:52:29 2008//
+D
diff --git a/test/fixtures/cvs/foo/bar b/test/fixtures/cvs/foo/bar
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/cvs/foo/bar
diff --git a/test/fixtures/cvs/foo/quux b/test/fixtures/cvs/foo/quux
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/cvs/foo/quux
diff --git a/test/fixtures/dnssec-keygen/dnssec-keygen b/test/fixtures/dnssec-keygen/dnssec-keygen
new file mode 100755
index 0000000..882cd97
--- /dev/null
+++ b/test/fixtures/dnssec-keygen/dnssec-keygen
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+cat <<\EOF >&2
+Usage:
+ dnssec-keygen [options] name
+
+Version: 9.11.3-1ubuntu1.5-Ubuntu
+ name: owner of the key
+Options:
+ -K <directory>: write keys into directory
+ -a <algorithm>:
+ RSA | RSAMD5 | DSA | RSASHA1 | NSEC3RSASHA1 | NSEC3DSA |
+ RSASHA256 | RSASHA512 | ECCGOST |
+ ECDSAP256SHA256 | ECDSAP384SHA384 |
+ ED25519 | ED448 | DH |
+ HMAC-MD5 | HMAC-SHA1 | HMAC-SHA224 | HMAC-SHA256 |
+ HMAC-SHA384 | HMAC-SHA512
+ (default: RSASHA1, or NSEC3RSASHA1 if using -3)
+ -3: use NSEC3-capable algorithm
+ -b <key size in bits>:
+ RSAMD5: [512..4096]
+ RSASHA1: [512..4096]
+ NSEC3RSASHA1: [512..4096]
+ RSASHA256: [512..4096]
+ RSASHA512: [1024..4096]
+ DH: [128..4096]
+ DSA: [512..1024] and divisible by 64
+ NSEC3DSA: [512..1024] and divisible by 64
+ ECCGOST: ignored
+ ECDSAP256SHA256: ignored
+ ECDSAP384SHA384: ignored
+ ED25519: ignored
+ ED448: ignored
+ HMAC-MD5: [1..512]
+ HMAC-SHA1: [1..160]
+ HMAC-SHA224: [1..224]
+ HMAC-SHA256: [1..256]
+ HMAC-SHA384: [1..384]
+ HMAC-SHA512: [1..512]
+ (if using the default algorithm, key size
+ defaults to 2048 for KSK, or 1024 for all others)
+ -n <nametype>: ZONE | HOST | ENTITY | USER | OTHER
+ (DNSKEY generation defaults to ZONE)
+ -c <class>: (default: IN)
+ -d <digest bits> (0 => max, default)
+ -E <engine>:
+ name of an OpenSSL engine to use
+ -f <keyflag>: KSK | REVOKE
+ -g <generator>: use specified generator (DH only)
+ -L <ttl>: default key TTL
+ -p <protocol>: (default: 3 [dnssec])
+ -r <randomdev>: a file containing random data
+ -s <strength>: strength value this key signs DNS records with (default: 0)
+ -T <rrtype>: DNSKEY | KEY (default: DNSKEY; use KEY for SIG(0))
+ -t <type>: AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF (default: AUTHCONF)
+ -h: print usage and exit
+ -m <memory debugging mode>:
+ usage | trace | record | size | mctx
+ -v <level>: set verbosity level (0 - 10)
+ -V: print version information
+Timing options:
+ -P date/[+-]offset/none: set key publication date (default: now)
+ -P sync date/[+-]offset/none: set CDS and CDNSKEY publication date
+ -A date/[+-]offset/none: set key activation date (default: now)
+ -R date/[+-]offset/none: set key revocation date
+ -I date/[+-]offset/none: set key inactivation date
+ -D date/[+-]offset/none: set key deletion date
+ -D sync date/[+-]offset/none: set CDS and CDNSKEY deletion date
+ -G: generate key only; do not set -P or -A
+ -C: generate a backward-compatible key, omitting all dates
+ -S <key>: generate a successor to an existing key
+ -i <interval>: prepublication interval for successor key (default: 30 days)
+Output:
+ K<name>+<alg>+<id>.key, K<name>+<alg>+<id>.private
+EOF
+exit 255
diff --git a/test/fixtures/dpkg/bash-completion-test-nonsubject.txt b/test/fixtures/dpkg/bash-completion-test-nonsubject.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/dpkg/bash-completion-test-nonsubject.txt
diff --git a/test/fixtures/dpkg/bash-completion-test-subject.deb b/test/fixtures/dpkg/bash-completion-test-subject.deb
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/dpkg/bash-completion-test-subject.deb
diff --git a/test/fixtures/evince/.BMP b/test/fixtures/evince/.BMP
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.BMP
diff --git a/test/fixtures/evince/.CBR b/test/fixtures/evince/.CBR
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.CBR
diff --git a/test/fixtures/evince/.CBZ b/test/fixtures/evince/.CBZ
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.CBZ
diff --git a/test/fixtures/evince/.DJV b/test/fixtures/evince/.DJV
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.DJV
diff --git a/test/fixtures/evince/.DJVU b/test/fixtures/evince/.DJVU
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.DJVU
diff --git a/test/fixtures/evince/.DVI b/test/fixtures/evince/.DVI
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.DVI
diff --git a/test/fixtures/evince/.DVI.BZ2 b/test/fixtures/evince/.DVI.BZ2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.DVI.BZ2
diff --git a/test/fixtures/evince/.DVI.GZ b/test/fixtures/evince/.DVI.GZ
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.DVI.GZ
diff --git a/test/fixtures/evince/.DVI.bz2 b/test/fixtures/evince/.DVI.bz2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.DVI.bz2
diff --git a/test/fixtures/evince/.DVI.gz b/test/fixtures/evince/.DVI.gz
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.DVI.gz
diff --git a/test/fixtures/evince/.EPS b/test/fixtures/evince/.EPS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.EPS
diff --git a/test/fixtures/evince/.EPS.BZ2 b/test/fixtures/evince/.EPS.BZ2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.EPS.BZ2
diff --git a/test/fixtures/evince/.EPS.GZ b/test/fixtures/evince/.EPS.GZ
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.EPS.GZ
diff --git a/test/fixtures/evince/.EPS.bz2 b/test/fixtures/evince/.EPS.bz2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.EPS.bz2
diff --git a/test/fixtures/evince/.EPS.gz b/test/fixtures/evince/.EPS.gz
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.EPS.gz
diff --git a/test/fixtures/evince/.GIF b/test/fixtures/evince/.GIF
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.GIF
diff --git a/test/fixtures/evince/.ICO b/test/fixtures/evince/.ICO
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.ICO
diff --git a/test/fixtures/evince/.JPEG b/test/fixtures/evince/.JPEG
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.JPEG
diff --git a/test/fixtures/evince/.JPG b/test/fixtures/evince/.JPG
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.JPG
diff --git a/test/fixtures/evince/.MIFF b/test/fixtures/evince/.MIFF
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.MIFF
diff --git a/test/fixtures/evince/.PBM b/test/fixtures/evince/.PBM
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.PBM
diff --git a/test/fixtures/evince/.PCX b/test/fixtures/evince/.PCX
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.PCX
diff --git a/test/fixtures/evince/.PDF b/test/fixtures/evince/.PDF
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.PDF
diff --git a/test/fixtures/evince/.PDF.BZ2 b/test/fixtures/evince/.PDF.BZ2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.PDF.BZ2
diff --git a/test/fixtures/evince/.PDF.GZ b/test/fixtures/evince/.PDF.GZ
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.PDF.GZ
diff --git a/test/fixtures/evince/.PDF.bz2 b/test/fixtures/evince/.PDF.bz2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.PDF.bz2
diff --git a/test/fixtures/evince/.PDF.gz b/test/fixtures/evince/.PDF.gz
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.PDF.gz
diff --git a/test/fixtures/evince/.PGM b/test/fixtures/evince/.PGM
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.PGM
diff --git a/test/fixtures/evince/.PNG b/test/fixtures/evince/.PNG
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.PNG
diff --git a/test/fixtures/evince/.PNM b/test/fixtures/evince/.PNM
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.PNM
diff --git a/test/fixtures/evince/.PPM b/test/fixtures/evince/.PPM
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.PPM
diff --git a/test/fixtures/evince/.PS b/test/fixtures/evince/.PS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.PS
diff --git a/test/fixtures/evince/.PS.BZ2 b/test/fixtures/evince/.PS.BZ2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.PS.BZ2
diff --git a/test/fixtures/evince/.PS.GZ b/test/fixtures/evince/.PS.GZ
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.PS.GZ
diff --git a/test/fixtures/evince/.PS.bz2 b/test/fixtures/evince/.PS.bz2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.PS.bz2
diff --git a/test/fixtures/evince/.PS.gz b/test/fixtures/evince/.PS.gz
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.PS.gz
diff --git a/test/fixtures/evince/.TGA b/test/fixtures/evince/.TGA
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.TGA
diff --git a/test/fixtures/evince/.TIF b/test/fixtures/evince/.TIF
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.TIF
diff --git a/test/fixtures/evince/.TIFF b/test/fixtures/evince/.TIFF
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.TIFF
diff --git a/test/fixtures/evince/.XPM b/test/fixtures/evince/.XPM
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.XPM
diff --git a/test/fixtures/evince/.XWD b/test/fixtures/evince/.XWD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.XWD
diff --git a/test/fixtures/evince/.bmp b/test/fixtures/evince/.bmp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.bmp
diff --git a/test/fixtures/evince/.cbr b/test/fixtures/evince/.cbr
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.cbr
diff --git a/test/fixtures/evince/.cbz b/test/fixtures/evince/.cbz
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.cbz
diff --git a/test/fixtures/evince/.djv b/test/fixtures/evince/.djv
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.djv
diff --git a/test/fixtures/evince/.djvu b/test/fixtures/evince/.djvu
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.djvu
diff --git a/test/fixtures/evince/.dvi b/test/fixtures/evince/.dvi
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.dvi
diff --git a/test/fixtures/evince/.dvi.BZ2 b/test/fixtures/evince/.dvi.BZ2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.dvi.BZ2
diff --git a/test/fixtures/evince/.dvi.GZ b/test/fixtures/evince/.dvi.GZ
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.dvi.GZ
diff --git a/test/fixtures/evince/.dvi.bz2 b/test/fixtures/evince/.dvi.bz2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.dvi.bz2
diff --git a/test/fixtures/evince/.dvi.gz b/test/fixtures/evince/.dvi.gz
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.dvi.gz
diff --git a/test/fixtures/evince/.eps b/test/fixtures/evince/.eps
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.eps
diff --git a/test/fixtures/evince/.eps.BZ2 b/test/fixtures/evince/.eps.BZ2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.eps.BZ2
diff --git a/test/fixtures/evince/.eps.GZ b/test/fixtures/evince/.eps.GZ
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.eps.GZ
diff --git a/test/fixtures/evince/.eps.bz2 b/test/fixtures/evince/.eps.bz2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.eps.bz2
diff --git a/test/fixtures/evince/.eps.gz b/test/fixtures/evince/.eps.gz
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.eps.gz
diff --git a/test/fixtures/evince/.gif b/test/fixtures/evince/.gif
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.gif
diff --git a/test/fixtures/evince/.ico b/test/fixtures/evince/.ico
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.ico
diff --git a/test/fixtures/evince/.jpeg b/test/fixtures/evince/.jpeg
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.jpeg
diff --git a/test/fixtures/evince/.jpg b/test/fixtures/evince/.jpg
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.jpg
diff --git a/test/fixtures/evince/.miff b/test/fixtures/evince/.miff
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.miff
diff --git a/test/fixtures/evince/.pbm b/test/fixtures/evince/.pbm
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.pbm
diff --git a/test/fixtures/evince/.pcx b/test/fixtures/evince/.pcx
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.pcx
diff --git a/test/fixtures/evince/.pdf b/test/fixtures/evince/.pdf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.pdf
diff --git a/test/fixtures/evince/.pdf.BZ2 b/test/fixtures/evince/.pdf.BZ2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.pdf.BZ2
diff --git a/test/fixtures/evince/.pdf.GZ b/test/fixtures/evince/.pdf.GZ
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.pdf.GZ
diff --git a/test/fixtures/evince/.pdf.bz2 b/test/fixtures/evince/.pdf.bz2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.pdf.bz2
diff --git a/test/fixtures/evince/.pdf.gz b/test/fixtures/evince/.pdf.gz
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.pdf.gz
diff --git a/test/fixtures/evince/.pgm b/test/fixtures/evince/.pgm
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.pgm
diff --git a/test/fixtures/evince/.png b/test/fixtures/evince/.png
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.png
diff --git a/test/fixtures/evince/.pnm b/test/fixtures/evince/.pnm
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.pnm
diff --git a/test/fixtures/evince/.ppm b/test/fixtures/evince/.ppm
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.ppm
diff --git a/test/fixtures/evince/.ps b/test/fixtures/evince/.ps
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.ps
diff --git a/test/fixtures/evince/.ps.BZ2 b/test/fixtures/evince/.ps.BZ2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.ps.BZ2
diff --git a/test/fixtures/evince/.ps.GZ b/test/fixtures/evince/.ps.GZ
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.ps.GZ
diff --git a/test/fixtures/evince/.ps.bz2 b/test/fixtures/evince/.ps.bz2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.ps.bz2
diff --git a/test/fixtures/evince/.ps.gz b/test/fixtures/evince/.ps.gz
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.ps.gz
diff --git a/test/fixtures/evince/.tga b/test/fixtures/evince/.tga
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.tga
diff --git a/test/fixtures/evince/.tif b/test/fixtures/evince/.tif
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.tif
diff --git a/test/fixtures/evince/.tiff b/test/fixtures/evince/.tiff
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.tiff
diff --git a/test/fixtures/evince/.txt b/test/fixtures/evince/.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.txt
diff --git a/test/fixtures/evince/.xpm b/test/fixtures/evince/.xpm
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.xpm
diff --git a/test/fixtures/evince/.xwd b/test/fixtures/evince/.xwd
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/.xwd
diff --git a/test/fixtures/evince/foo/.gitignore b/test/fixtures/evince/foo/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/evince/foo/.gitignore
diff --git a/test/fixtures/gdb/core b/test/fixtures/gdb/core
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/gdb/core
diff --git a/test/fixtures/gdb/core-NOT b/test/fixtures/gdb/core-NOT
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/gdb/core-NOT
diff --git a/test/fixtures/gdb/core.12345 b/test/fixtures/gdb/core.12345
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/gdb/core.12345
diff --git a/test/fixtures/gdb/core.weston.1000.deadbeef.5308.1555362132000000 b/test/fixtures/gdb/core.weston.1000.deadbeef.5308.1555362132000000
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/gdb/core.weston.1000.deadbeef.5308.1555362132000000
diff --git a/test/fixtures/gdb/corenot b/test/fixtures/gdb/corenot
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/gdb/corenot
diff --git a/test/fixtures/htpasswd/htpasswd b/test/fixtures/htpasswd/htpasswd
new file mode 100644
index 0000000..5279c7c
--- /dev/null
+++ b/test/fixtures/htpasswd/htpasswd
@@ -0,0 +1,2 @@
+foo:bar
+quux:baz
diff --git a/test/fixtures/info/bash-completion.info b/test/fixtures/info/bash-completion.info
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/info/bash-completion.info
diff --git a/test/fixtures/isql/odbc.ini b/test/fixtures/isql/odbc.ini
new file mode 100644
index 0000000..96319f3
--- /dev/null
+++ b/test/fixtures/isql/odbc.ini
@@ -0,0 +1,3 @@
+[foo]
+
+[bar]
diff --git a/test/fixtures/java/a/b$c.class b/test/fixtures/java/a/b$c.class
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/java/a/b$c.class
diff --git a/test/fixtures/java/a/b.class b/test/fixtures/java/a/b.class
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/java/a/b.class
diff --git a/test/fixtures/java/a/c/README.txt b/test/fixtures/java/a/c/README.txt
new file mode 100644
index 0000000..e5e6d0b
--- /dev/null
+++ b/test/fixtures/java/a/c/README.txt
@@ -0,0 +1,2 @@
+When CLASSPATH is set to the fixtures/java/a dir, we do *not* expect
+*.class in subdirs to be included in completions, see Debian bug #496828.
diff --git a/test/fixtures/java/a/c/d.class b/test/fixtures/java/a/c/d.class
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/java/a/c/d.class
diff --git a/test/fixtures/java/a/d.txt b/test/fixtures/java/a/d.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/java/a/d.txt
diff --git a/test/fixtures/java/bashcomp.jar b/test/fixtures/java/bashcomp.jar
new file mode 100644
index 0000000..d9c2779
--- /dev/null
+++ b/test/fixtures/java/bashcomp.jar
Binary files differ
diff --git a/test/fixtures/java/bashcomp.war b/test/fixtures/java/bashcomp.war
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/java/bashcomp.war
diff --git a/test/fixtures/java/no-complete.txt b/test/fixtures/java/no-complete.txt
new file mode 100644
index 0000000..8ca1ef6
--- /dev/null
+++ b/test/fixtures/java/no-complete.txt
@@ -0,0 +1 @@
+This file should not be included in classpath etc completions.
diff --git a/test/fixtures/kdvi/.DVI b/test/fixtures/kdvi/.DVI
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kdvi/.DVI
diff --git a/test/fixtures/kdvi/.DVI.Z b/test/fixtures/kdvi/.DVI.Z
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kdvi/.DVI.Z
diff --git a/test/fixtures/kdvi/.DVI.bz2 b/test/fixtures/kdvi/.DVI.bz2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kdvi/.DVI.bz2
diff --git a/test/fixtures/kdvi/.DVI.gz b/test/fixtures/kdvi/.DVI.gz
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kdvi/.DVI.gz
diff --git a/test/fixtures/kdvi/.dvi b/test/fixtures/kdvi/.dvi
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kdvi/.dvi
diff --git a/test/fixtures/kdvi/.dvi.Z b/test/fixtures/kdvi/.dvi.Z
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kdvi/.dvi.Z
diff --git a/test/fixtures/kdvi/.dvi.bz2 b/test/fixtures/kdvi/.dvi.bz2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kdvi/.dvi.bz2
diff --git a/test/fixtures/kdvi/.dvi.gz b/test/fixtures/kdvi/.dvi.gz
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kdvi/.dvi.gz
diff --git a/test/fixtures/kdvi/.txt b/test/fixtures/kdvi/.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kdvi/.txt
diff --git a/test/fixtures/kdvi/foo/.gitignore b/test/fixtures/kdvi/foo/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kdvi/foo/.gitignore
diff --git a/test/fixtures/kpdf/.EPS b/test/fixtures/kpdf/.EPS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kpdf/.EPS
diff --git a/test/fixtures/kpdf/.PDF b/test/fixtures/kpdf/.PDF
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kpdf/.PDF
diff --git a/test/fixtures/kpdf/.PS b/test/fixtures/kpdf/.PS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kpdf/.PS
diff --git a/test/fixtures/kpdf/.eps b/test/fixtures/kpdf/.eps
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kpdf/.eps
diff --git a/test/fixtures/kpdf/.pdf b/test/fixtures/kpdf/.pdf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kpdf/.pdf
diff --git a/test/fixtures/kpdf/.ps b/test/fixtures/kpdf/.ps
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kpdf/.ps
diff --git a/test/fixtures/kpdf/.txt b/test/fixtures/kpdf/.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kpdf/.txt
diff --git a/test/fixtures/kpdf/foo/.gitignore b/test/fixtures/kpdf/foo/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/kpdf/foo/.gitignore
diff --git a/test/fixtures/lftp/.lftp/bookmarks b/test/fixtures/lftp/.lftp/bookmarks
new file mode 100644
index 0000000..074f812
--- /dev/null
+++ b/test/fixtures/lftp/.lftp/bookmarks
@@ -0,0 +1,3 @@
+lftptest ftp://ftp.funet.fi/
+spacetest ftp://ftp.sunet.se/
+badbookmark
diff --git a/test/fixtures/lilo/lilo.conf b/test/fixtures/lilo/lilo.conf
new file mode 100644
index 0000000..c890175
--- /dev/null
+++ b/test/fixtures/lilo/lilo.conf
@@ -0,0 +1,34 @@
+# global options:
+boot=/dev/hda
+prompt
+timeout=150
+lba32
+compact
+vga=normal
+root=/dev/hda1
+read-only
+menu-title=" John's Computer "
+#
+### bootable kernel images ###
+image=/boot/vmlinuz-2.6.29-1-i386
+ label=try
+ initrd=/boot/initrd.img-2.6.29-1-i386
+#image=/boot/vmlinuz-2.4.33-1-i386
+# label=2.4.33
+image=/tamu/vmlinuz
+ label=tamu
+ initrd=/tamu/initrd.img
+ root=/dev/hdb2
+ vga=ask
+#
+### other operating systems ###
+other=/dev/hda3
+ label=PCDOS
+ boot-as=0x80 # must be C:
+other=/dev/hdb1
+ label=WinXP
+ boot-as=0x80 # must be C:
+other=/dev/hdb5
+ label=oldDOS
+ loader=chain
+ table=/dev/hdb5
diff --git a/test/fixtures/make/.gitignore b/test/fixtures/make/.gitignore
new file mode 100644
index 0000000..3d1325c
--- /dev/null
+++ b/test/fixtures/make/.gitignore
@@ -0,0 +1 @@
+extra_makefile
diff --git a/test/fixtures/make/Makefile b/test/fixtures/make/Makefile
new file mode 100644
index 0000000..b04a6eb
--- /dev/null
+++ b/test/fixtures/make/Makefile
@@ -0,0 +1,46 @@
+$(info confuse: make)
+
+CFLAGS=-MMD -MP
+NAME := sample
+
+.PHONY: all
+all: $(NAME)
+
+$(NAME): sample.o
+
+.INTERMEDIATE: sample.o
+sample.o: sample.c
+
+.PHONY: install
+install: all
+ mkdir -p /usr/bin
+ install -m 755 $(NAME) /usr/bin
+
+.PHONY: clean
+clean:
+ -rm -f $(NAME)
+
+.test_passes:
+ ./sample >/dev/null
+ touch ^@
+
+.cache/.1:
+ touch $@
+
+.cache/.2:
+ touch $@
+
+.cache/1:
+ touch $@
+
+.cache/2:
+ touch $@
+
+ifndef __BASH_MAKE_COMPLETION__
+-include sample.d
+endif
+
+VARIABLE_LOOKS_A_BIT_LIKE_A_TARGET := fooled-you
+extra_makefile:
+ touch $@
+include extra_makefile
diff --git a/test/fixtures/make/sample.c b/test/fixtures/make/sample.c
new file mode 100644
index 0000000..4212596
--- /dev/null
+++ b/test/fixtures/make/sample.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+#include "sample.h"
+
+int main(void)
+{
+ puts("Hello, world!");
+ return 0;
+}
diff --git a/test/fixtures/make/sample.d b/test/fixtures/make/sample.d
new file mode 100644
index 0000000..27979ff
--- /dev/null
+++ b/test/fixtures/make/sample.d
@@ -0,0 +1,3 @@
+sample.o: sample.c sample.h
+
+sample.h:
diff --git a/test/fixtures/make/sample.h b/test/fixtures/make/sample.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/make/sample.h
diff --git a/test/fixtures/man/man/quux.8 b/test/fixtures/man/man/quux.8
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/man/man/quux.8
diff --git a/test/fixtures/man/man1/bash-completion-testcase.1.bz2 b/test/fixtures/man/man1/bash-completion-testcase.1.bz2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/man/man1/bash-completion-testcase.1.bz2
diff --git a/test/fixtures/man/man1/foo.1 b/test/fixtures/man/man1/foo.1
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/man/man1/foo.1
diff --git a/test/fixtures/mount/bin/showmount b/test/fixtures/mount/bin/showmount
new file mode 100755
index 0000000..2751c4b
--- /dev/null
+++ b/test/fixtures/mount/bin/showmount
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+if [ "$1" = -e ] && [ "$2" = mocksrv ]; then
+ echo "Header line"
+ echo "/test/path"
+ echo "/test/path2"
+ echo "/second/path"
+ exit 0
+fi
+
+echo "Usage: 'showmount -e mocksrv'; nothing else works."
+exit 1
diff --git a/test/fixtures/mount/test-fstab b/test/fixtures/mount/test-fstab
new file mode 100644
index 0000000..b243417
--- /dev/null
+++ b/test/fixtures/mount/test-fstab
@@ -0,0 +1,24 @@
+proc /proc proc defaults 0 0
+none /debug debugfs defaults,noauto 0 0
+
+# Simple obvious test.
+/mnt/nice-test-path /dev/null auto ro,noauto 0 0
+
+# Test octal escapes
+# Contains ' ' and '-'
+/mnt/nice\040test\055path /dev/null auto ro,noauto 0 0
+# Contains '$' and '-'
+/mnt/nice\044test\055path /dev/null auto ro,noauto 0 0
+# Contains ' ' and '\\'
+/mnt/nice\040test\134path /dev/null auto ro,noauto 0 0
+# Contains '\n' and '\ '
+/mnt/nice\012test\040path /dev/null auto ro,noauto 0 0
+
+# Test apostrophe
+/mnt/nice'test-path /dev/null auto ro,noauto 0 0
+/mnt/other'test\040path /dev/null auto ro,noauto 0 0
+
+# Test some labels
+LABEL=Ubuntu\040Karmic /mnt/ubuntu auto no,noauto 0 0
+LABEL=Fedora /mnt/fedora auto ro,noauto 0 0
+LABEL=Debian-it's\040awesome /mnt/debian auto ro,noauto 0 0
diff --git a/test/fixtures/mplayer/.mplayer/config b/test/fixtures/mplayer/.mplayer/config
new file mode 100644
index 0000000..8af74ee
--- /dev/null
+++ b/test/fixtures/mplayer/.mplayer/config
@@ -0,0 +1,2 @@
+# https://github.com/scop/bash-completion/issues/182
+msglevel=all=3
diff --git a/test/fixtures/mplayer/.mplayer/mencoder.conf b/test/fixtures/mplayer/.mplayer/mencoder.conf
new file mode 100644
index 0000000..9f5aa0f
--- /dev/null
+++ b/test/fixtures/mplayer/.mplayer/mencoder.conf
@@ -0,0 +1 @@
+# mencoder test config file
diff --git a/test/fixtures/mutt/bar/.gitignore b/test/fixtures/mutt/bar/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/mutt/bar/.gitignore
diff --git a/test/fixtures/mutt/bar/muttrc_b b/test/fixtures/mutt/bar/muttrc_b
new file mode 100644
index 0000000..f4a0493
--- /dev/null
+++ b/test/fixtures/mutt/bar/muttrc_b
@@ -0,0 +1 @@
+source ~/foo/muttrc_f
diff --git a/test/fixtures/mutt/foo/.gitignore b/test/fixtures/mutt/foo/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/mutt/foo/.gitignore
diff --git a/test/fixtures/mutt/foo/muttrc_f b/test/fixtures/mutt/foo/muttrc_f
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/mutt/foo/muttrc_f
diff --git a/test/fixtures/mutt/muttrc b/test/fixtures/mutt/muttrc
new file mode 100644
index 0000000..d26c8bc
--- /dev/null
+++ b/test/fixtures/mutt/muttrc
@@ -0,0 +1,4 @@
+set folder=.
+alias a1 a1@example.com
+alias a2 a2@example.com
+source ~/bar/muttrc_b
diff --git a/test/fixtures/nmap/nmap-h.txt b/test/fixtures/nmap/nmap-h.txt
new file mode 100644
index 0000000..0301d37
--- /dev/null
+++ b/test/fixtures/nmap/nmap-h.txt
@@ -0,0 +1,114 @@
+Nmap 7.60 ( https://nmap.org )
+Usage: nmap [Scan Type(s)] [Options] {target specification}
+TARGET SPECIFICATION:
+ Can pass hostnames, IP addresses, networks, etc.
+ Ex: scanme.nmap.org, microsoft.com/24, 192.168.0.1; 10.0.0-255.1-254
+ -iL <inputfilename>: Input from list of hosts/networks
+ -iR <num hosts>: Choose random targets
+ --exclude <host1[,host2][,host3],...>: Exclude hosts/networks
+ --excludefile <exclude_file>: Exclude list from file
+HOST DISCOVERY:
+ -sL: List Scan - simply list targets to scan
+ -sn: Ping Scan - disable port scan
+ -Pn: Treat all hosts as online -- skip host discovery
+ -PS/PA/PU/PY[portlist]: TCP SYN/ACK, UDP or SCTP discovery to given ports
+ -PE/PP/PM: ICMP echo, timestamp, and netmask request discovery probes
+ -PO[protocol list]: IP Protocol Ping
+ -n/-R: Never do DNS resolution/Always resolve [default: sometimes]
+ --dns-servers <serv1[,serv2],...>: Specify custom DNS servers
+ --system-dns: Use OS's DNS resolver
+ --traceroute: Trace hop path to each host
+SCAN TECHNIQUES:
+ -sS/sT/sA/sW/sM: TCP SYN/Connect()/ACK/Window/Maimon scans
+ -sU: UDP Scan
+ -sN/sF/sX: TCP Null, FIN, and Xmas scans
+ --scanflags <flags>: Customize TCP scan flags
+ -sI <zombie host[:probeport]>: Idle scan
+ -sY/sZ: SCTP INIT/COOKIE-ECHO scans
+ -sO: IP protocol scan
+ -b <FTP relay host>: FTP bounce scan
+PORT SPECIFICATION AND SCAN ORDER:
+ -p <port ranges>: Only scan specified ports
+ Ex: -p22; -p1-65535; -p U:53,111,137,T:21-25,80,139,8080,S:9
+ --exclude-ports <port ranges>: Exclude the specified ports from scanning
+ -F: Fast mode - Scan fewer ports than the default scan
+ -r: Scan ports consecutively - don't randomize
+ --top-ports <number>: Scan <number> most common ports
+ --port-ratio <ratio>: Scan ports more common than <ratio>
+SERVICE/VERSION DETECTION:
+ -sV: Probe open ports to determine service/version info
+ --version-intensity <level>: Set from 0 (light) to 9 (try all probes)
+ --version-light: Limit to most likely probes (intensity 2)
+ --version-all: Try every single probe (intensity 9)
+ --version-trace: Show detailed version scan activity (for debugging)
+SCRIPT SCAN:
+ -sC: equivalent to --script=default
+ --script=<Lua scripts>: <Lua scripts> is a comma separated list of
+ directories, script-files or script-categories
+ --script-args=<n1=v1,[n2=v2,...]>: provide arguments to scripts
+ --script-args-file=filename: provide NSE script args in a file
+ --script-trace: Show all data sent and received
+ --script-updatedb: Update the script database.
+ --script-help=<Lua scripts>: Show help about scripts.
+ <Lua scripts> is a comma-separated list of script-files or
+ script-categories.
+OS DETECTION:
+ -O: Enable OS detection
+ --osscan-limit: Limit OS detection to promising targets
+ --osscan-guess: Guess OS more aggressively
+TIMING AND PERFORMANCE:
+ Options which take <time> are in seconds, or append 'ms' (milliseconds),
+ 's' (seconds), 'm' (minutes), or 'h' (hours) to the value (e.g. 30m).
+ -T<0-5>: Set timing template (higher is faster)
+ --min-hostgroup/max-hostgroup <size>: Parallel host scan group sizes
+ --min-parallelism/max-parallelism <numprobes>: Probe parallelization
+ --min-rtt-timeout/max-rtt-timeout/initial-rtt-timeout <time>: Specifies
+ probe round trip time.
+ --max-retries <tries>: Caps number of port scan probe retransmissions.
+ --host-timeout <time>: Give up on target after this long
+ --scan-delay/--max-scan-delay <time>: Adjust delay between probes
+ --min-rate <number>: Send packets no slower than <number> per second
+ --max-rate <number>: Send packets no faster than <number> per second
+FIREWALL/IDS EVASION AND SPOOFING:
+ -f; --mtu <val>: fragment packets (optionally w/given MTU)
+ -D <decoy1,decoy2[,ME],...>: Cloak a scan with decoys
+ -S <IP_Address>: Spoof source address
+ -e <iface>: Use specified interface
+ -g/--source-port <portnum>: Use given port number
+ --proxies <url1,[url2],...>: Relay connections through HTTP/SOCKS4 proxies
+ --data <hex string>: Append a custom payload to sent packets
+ --data-string <string>: Append a custom ASCII string to sent packets
+ --data-length <num>: Append random data to sent packets
+ --ip-options <options>: Send packets with specified ip options
+ --ttl <val>: Set IP time-to-live field
+ --spoof-mac <mac address/prefix/vendor name>: Spoof your MAC address
+ --badsum: Send packets with a bogus TCP/UDP/SCTP checksum
+OUTPUT:
+ -oN/-oX/-oS/-oG <file>: Output scan in normal, XML, s|<rIpt kIddi3,
+ and Grepable format, respectively, to the given filename.
+ -oA <basename>: Output in the three major formats at once
+ -v: Increase verbosity level (use -vv or more for greater effect)
+ -d: Increase debugging level (use -dd or more for greater effect)
+ --reason: Display the reason a port is in a particular state
+ --open: Only show open (or possibly open) ports
+ --packet-trace: Show all packets sent and received
+ --iflist: Print host interfaces and routes (for debugging)
+ --append-output: Append to rather than clobber specified output files
+ --resume <filename>: Resume an aborted scan
+ --stylesheet <path/URL>: XSL stylesheet to transform XML output to HTML
+ --webxml: Reference stylesheet from Nmap.Org for more portable XML
+ --no-stylesheet: Prevent associating of XSL stylesheet w/XML output
+MISC:
+ -6: Enable IPv6 scanning
+ -A: Enable OS detection, version detection, script scanning, and traceroute
+ --datadir <dirname>: Specify custom Nmap data file location
+ --send-eth/--send-ip: Send using raw ethernet frames or IP packets
+ --privileged: Assume that the user is fully privileged
+ --unprivileged: Assume the user lacks raw socket privileges
+ -V: Print version number
+ -h: Print this help summary page.
+EXAMPLES:
+ nmap -v -A scanme.nmap.org
+ nmap -v -sn 192.168.0.0/16 10.0.0.0/8
+ nmap -v -iR 10000 -Pn -p 80
+SEE THE MAN PAGE (https://nmap.org/book/man.html) FOR MORE OPTIONS AND EXAMPLES
diff --git a/test/fixtures/perl/Devel/BashCompletion.pm b/test/fixtures/perl/Devel/BashCompletion.pm
new file mode 100644
index 0000000..f8e829d
--- /dev/null
+++ b/test/fixtures/perl/Devel/BashCompletion.pm
@@ -0,0 +1,3 @@
+use strict;
+use warnings;
+1;
diff --git a/test/fixtures/perldoc/BashCompletionDoc.pod b/test/fixtures/perldoc/BashCompletionDoc.pod
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/perldoc/BashCompletionDoc.pod
diff --git a/test/fixtures/perldoc/BashCompletionModule.pm b/test/fixtures/perldoc/BashCompletionModule.pm
new file mode 100644
index 0000000..b9208f3
--- /dev/null
+++ b/test/fixtures/perldoc/BashCompletionModule.pm
@@ -0,0 +1,4 @@
+package BashCompletionModule;
+use strict;
+use warnings;
+1;
diff --git a/test/fixtures/pkgtools/db/a-1.0,1/.gitignore b/test/fixtures/pkgtools/db/a-1.0,1/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/pkgtools/db/a-1.0,1/.gitignore
diff --git a/test/fixtures/pkgtools/db/b-c-d-2.0_2/.gitignore b/test/fixtures/pkgtools/db/b-c-d-2.0_2/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/pkgtools/db/b-c-d-2.0_2/.gitignore
diff --git a/test/fixtures/pkgtools/ports/.gitignore b/test/fixtures/pkgtools/ports/.gitignore
new file mode 100644
index 0000000..71d2c0c
--- /dev/null
+++ b/test/fixtures/pkgtools/ports/.gitignore
@@ -0,0 +1,2 @@
+INDEX
+INDEX-5
diff --git a/test/fixtures/pkgtools/ports/INDEX.dist b/test/fixtures/pkgtools/ports/INDEX.dist
new file mode 100644
index 0000000..76957d4
--- /dev/null
+++ b/test/fixtures/pkgtools/ports/INDEX.dist
@@ -0,0 +1,3 @@
+bash-3.1.17|PORTSDIR/shells/bash|/usr/local|The GNU Project's Bourne Again SHell|PORTSDIR/shells/bash/pkg-descr|obrien@FreeBSD.org|shells|expat-2.0.0_1 gettext-0.14.5_2 ldconfig_compat-1.0_8 libiconv-1.9.2_2 rc_subr-1.31_1|expat-2.0.0_1 gettext-0.14.5_2 ldconfig_compat-1.0_8 libiconv-1.9.2_2 rc_subr-1.31_1|http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html|||
+bash-completion-20060301_2|PORTSDIR/shells/bash-completion|/usr/local|Programmable completion library for Bash 2.04 and up|PORTSDIR/shells/bash-completion/pkg-descr|kirk@strauser.com|shells||bash-3.1.17 expat-2.0.0_1 gettext-0.14.5_2 ldconfig_compat-1.0_8 libiconv-1.9.2_2 rc_subr-1.31_1|http://www.caliban.org/bash/index.shtml|||
+bash-2.05b.007_6|PORTSDIR/shells/bash2|/usr/local|The GNU Bourne Again Shell|PORTSDIR/shells/bash2/pkg-descr|ports@FreeBSD.org|shells|||http://www.gnu.org/software/bash/|||
diff --git a/test/fixtures/pytest/test_async.py b/test/fixtures/pytest/test_async.py
new file mode 100644
index 0000000..48f91e0
--- /dev/null
+++ b/test/fixtures/pytest/test_async.py
@@ -0,0 +1,17 @@
+"""Async function pytest completion fixture."""
+
+
+async def test_positive():
+ pass
+
+
+async def non_test_negative():
+ pass
+
+
+class Testing:
+ async def test_positive(self):
+ pass
+
+ async def non_test_negative(self):
+ pass
diff --git a/test/fixtures/ri/BashCompletion/cdesc-BashCompletion.ri b/test/fixtures/ri/BashCompletion/cdesc-BashCompletion.ri
new file mode 100644
index 0000000..7263da8
--- /dev/null
+++ b/test/fixtures/ri/BashCompletion/cdesc-BashCompletion.ri
Binary files differ
diff --git a/test/fixtures/ri/BashCompletion/cdesc-BashCompletion.yaml b/test/fixtures/ri/BashCompletion/cdesc-BashCompletion.yaml
new file mode 100644
index 0000000..bc064a8
--- /dev/null
+++ b/test/fixtures/ri/BashCompletion/cdesc-BashCompletion.yaml
@@ -0,0 +1,15 @@
+--- !ruby/object:RI::ClassDescription
+attributes: []
+
+class_methods: []
+
+comment:
+constants: []
+
+full_name: BashCompletion
+includes: []
+
+instance_methods: []
+
+name: BashCompletion
+superclass:
diff --git a/test/fixtures/ri/bashcompletion.rb b/test/fixtures/ri/bashcompletion.rb
new file mode 100644
index 0000000..0e075d2
--- /dev/null
+++ b/test/fixtures/ri/bashcompletion.rb
@@ -0,0 +1,2 @@
+module BashCompletion
+end
diff --git a/test/fixtures/ri/cache.ri b/test/fixtures/ri/cache.ri
new file mode 100644
index 0000000..4a8fc66
--- /dev/null
+++ b/test/fixtures/ri/cache.ri
Binary files differ
diff --git a/test/fixtures/ri/created.rid b/test/fixtures/ri/created.rid
new file mode 100644
index 0000000..1392d20
--- /dev/null
+++ b/test/fixtures/ri/created.rid
@@ -0,0 +1 @@
+Mon, 09 Oct 2017 21:45:15 +0000
diff --git a/test/fixtures/scp/config b/test/fixtures/scp/config
new file mode 100644
index 0000000..9f94b9e
--- /dev/null
+++ b/test/fixtures/scp/config
@@ -0,0 +1,8 @@
+UserKnownHostsFile known_hosts
+
+ # Unindented
+Host gee
+ # Indented, multiple hosts
+ HostName hus ike
+
+Host hut
diff --git a/test/fixtures/scp/known_hosts b/test/fixtures/scp/known_hosts
new file mode 100644
index 0000000..2dfa4b6
--- /dev/null
+++ b/test/fixtures/scp/known_hosts
@@ -0,0 +1,5 @@
+|1|abc
+|1|def
+doo
+ike ssh-rsa qwerty1234/Qwerty+1234==
+[blah]:1234
diff --git a/test/fixtures/scp/spaced conf b/test/fixtures/scp/spaced conf
new file mode 100644
index 0000000..7ad64bc
--- /dev/null
+++ b/test/fixtures/scp/spaced conf
@@ -0,0 +1,6 @@
+ UserKnownHostsFile known_hosts
+
+ # Unindented
+Host gee jar
+ # Indented, multiple hosts
+ HostName hus
diff --git a/test/fixtures/sftp/config b/test/fixtures/sftp/config
new file mode 100644
index 0000000..9f94b9e
--- /dev/null
+++ b/test/fixtures/sftp/config
@@ -0,0 +1,8 @@
+UserKnownHostsFile known_hosts
+
+ # Unindented
+Host gee
+ # Indented, multiple hosts
+ HostName hus ike
+
+Host hut
diff --git a/test/fixtures/sftp/known_hosts b/test/fixtures/sftp/known_hosts
new file mode 100644
index 0000000..6538eb4
--- /dev/null
+++ b/test/fixtures/sftp/known_hosts
@@ -0,0 +1,5 @@
+|1|abc
+|1|def
+doo
+ike ssh-rsa qwerty1234/Qwerty+1234==
+[10.10.10.10]:2222
diff --git a/test/fixtures/sftp/spaced conf b/test/fixtures/sftp/spaced conf
new file mode 100644
index 0000000..7ad64bc
--- /dev/null
+++ b/test/fixtures/sftp/spaced conf
@@ -0,0 +1,6 @@
+ UserKnownHostsFile known_hosts
+
+ # Unindented
+Host gee jar
+ # Indented, multiple hosts
+ HostName hus
diff --git a/test/fixtures/shared/.ssh/known_hosts b/test/fixtures/shared/.ssh/known_hosts
new file mode 100644
index 0000000..03d444a
--- /dev/null
+++ b/test/fixtures/shared/.ssh/known_hosts
@@ -0,0 +1 @@
+bash-completion-canary-host.local
diff --git a/test/fixtures/shared/bin/arp b/test/fixtures/shared/bin/arp
new file mode 100755
index 0000000..49f4296
--- /dev/null
+++ b/test/fixtures/shared/bin/arp
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+# Dummy "arp -an" emulator
+
+# Linux
+echo "? (0.0.0.0) at 00:00:00:00:00:00 [ether] on eth0"
+
+# FreeBSD
+echo "? (0.0.0.0) at 11:11:11:11:11:11 on bge0 expires in 5 seconds [ethernet]"
+
+# Solaris
+cat <<EOF
+Device IP Address Mask Flags Phys Addr
+------ -------------------- --------------- -------- ---------------
+ce0 0.0.0.0 255.255.255.255 o 22:22:22:22:22:22
+EOF
diff --git a/test/fixtures/shared/bin/ifconfig b/test/fixtures/shared/bin/ifconfig
new file mode 100755
index 0000000..59c9140
--- /dev/null
+++ b/test/fixtures/shared/bin/ifconfig
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+# Dummy "ifconfig -a" emulator
+
+cat <<EOF
+eth0 Link encap:Ethernet HWaddr 33:33:33:33:33:33
+ inet addr:192.168.80.11 Bcast:192.168.80.255 Mask:255.255.255.0
+ inet6 addr: fe80::000:0000:0000:0000/64 Scope:Link
+ UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
+ RX packets:855946 errors:42 dropped:0 overruns:0 frame:42
+ TX packets:477196 errors:0 dropped:0 overruns:0 carrier:0
+ collisions:0 txqueuelen:1000
+ RX bytes:1142133425 (1.0 GiB) TX bytes:47621718 (45.4 MiB)
+ Interrupt:23 Base address:0xc000
+
+lo Link encap:Local Loopback
+ inet addr:127.0.0.1 Mask:255.0.0.0
+ inet6 addr: ::1/128 Scope:Host
+ UP LOOPBACK RUNNING MTU:16436 Metric:1
+ RX packets:129059 errors:0 dropped:0 overruns:0 frame:0
+ TX packets:129059 errors:0 dropped:0 overruns:0 carrier:0
+ collisions:0 txqueuelen:0
+ RX bytes:7456154 (7.1 MiB) TX bytes:7456154 (7.1 MiB)
+EOF
diff --git a/test/fixtures/shared/default/bar b/test/fixtures/shared/default/bar
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/shared/default/bar
diff --git a/test/fixtures/shared/default/bar bar.d/foo b/test/fixtures/shared/default/bar bar.d/foo
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/shared/default/bar bar.d/foo
diff --git a/test/fixtures/shared/default/foo b/test/fixtures/shared/default/foo
new file mode 100644
index 0000000..257cc56
--- /dev/null
+++ b/test/fixtures/shared/default/foo
@@ -0,0 +1 @@
+foo
diff --git a/test/fixtures/shared/default/foo.d/foo b/test/fixtures/shared/default/foo.d/foo
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/shared/default/foo.d/foo
diff --git a/test/fixtures/shared/empty_dir/.nothing_here b/test/fixtures/shared/empty_dir/.nothing_here
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/shared/empty_dir/.nothing_here
diff --git a/test/fixtures/shared/ld.so.conf.d/foo.txt b/test/fixtures/shared/ld.so.conf.d/foo.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/shared/ld.so.conf.d/foo.txt
diff --git a/test/fixtures/shared/ld.so.conf.d/libfoo.conf b/test/fixtures/shared/ld.so.conf.d/libfoo.conf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/shared/ld.so.conf.d/libfoo.conf
diff --git a/test/fixtures/shared/ld.so.conf.d/libfoo.so b/test/fixtures/shared/ld.so.conf.d/libfoo.so
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/shared/ld.so.conf.d/libfoo.so
diff --git a/test/fixtures/shared/ld.so.conf.d/libfoo.so.1 b/test/fixtures/shared/ld.so.conf.d/libfoo.so.1
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/shared/ld.so.conf.d/libfoo.so.1
diff --git a/test/fixtures/slackware/home/abc-4-i686-1.txz b/test/fixtures/slackware/home/abc-4-i686-1.txz
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/test/fixtures/slackware/home/abc-4-i686-1.txz
@@ -0,0 +1 @@
+
diff --git a/test/fixtures/slackware/home/opq-1.0-2.i386.rpm b/test/fixtures/slackware/home/opq-1.0-2.i386.rpm
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/test/fixtures/slackware/home/opq-1.0-2.i386.rpm
@@ -0,0 +1 @@
+
diff --git a/test/fixtures/slackware/home/tcl.d/tcl.tgz b/test/fixtures/slackware/home/tcl.d/tcl.tgz
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/test/fixtures/slackware/home/tcl.d/tcl.tgz
@@ -0,0 +1 @@
+
diff --git a/test/fixtures/slackware/usr/src/slapt-src/slackbuilds_data b/test/fixtures/slackware/usr/src/slapt-src/slackbuilds_data
new file mode 100644
index 0000000..0f4ee44
--- /dev/null
+++ b/test/fixtures/slackware/usr/src/slapt-src/slackbuilds_data
@@ -0,0 +1,20 @@
+SLACKBUILD NAME: abc
+SLACKBUILD SOURCEURL: http://www.slackware.org.uk/slackbuilds.org/13.37/
+SLACKBUILD LOCATION: libraries/abc/
+SLACKBUILD FILES: abc.SlackBuild slack-desc
+SLACKBUILD VERSION: 4
+SLACKBUILD DOWNLOAD: http://www.ufl.edu/abc-4.tar.gz
+SLACKBUILD MD5SUM: b3e9679ba20635ac4847f01c01d6e992
+SLACKBUILD REQUIRES:
+SLACKBUILD SHORT DESCRIPTION: abc is a small utility
+
+SLACKBUILD NAME: qwe
+SLACKBUILD SOURCEURL: http://www.slackware.org.uk/slackbuilds.org/13.37/
+SLACKBUILD LOCATION: network/qwe/
+SLACKBUILD FILES: qwe.SlackBuild
+SLACKBUILD VERSION: 2.1
+SLACKBUILD DOWNLOAD: http://php.net/qwe-2.1.tgz
+SLACKBUILD MD5SUM: 1f7a58f850e795b0958a3f99ae8c2cc4
+SLACKBUILD REQUIRES:
+SLACKBUILD SHORT DESCRIPTION: qwe is a program
+
diff --git a/test/fixtures/slackware/var/log/packages/radeontool-1.6.1-i486-1 b/test/fixtures/slackware/var/log/packages/radeontool-1.6.1-i486-1
new file mode 100644
index 0000000..7f53326
--- /dev/null
+++ b/test/fixtures/slackware/var/log/packages/radeontool-1.6.1-i486-1
@@ -0,0 +1,24 @@
+PACKAGE NAME: radeontool-1.6.1-i486-1
+COMPRESSED PACKAGE SIZE: 48K
+UNCOMPRESSED PACKAGE SIZE: 150K
+PACKAGE LOCATION: ./radeontool-1.6.1-i486-1.txz
+PACKAGE DESCRIPTION:
+radeontool: radeontool (small utility for ati radeon-based laptops)
+radeontool:
+radeontool: Radeontool is a small utility to control ATI Radeon-based
+radeontool: laptops' backlight and external output functions
+radeontool:
+radeontool: Homepage: http://fdd.com/software/radeon/
+radeontool:
+radeontool:
+radeontool:
+radeontool:
+radeontool:
+FILE LIST:
+./
+usr/
+usr/bin/
+usr/bin/radeontool
+usr/bin/avivotool
+install/
+install/slack-desc
diff --git a/test/fixtures/slackware/var/log/packages/rzip-2.1-i486-1 b/test/fixtures/slackware/var/log/packages/rzip-2.1-i486-1
new file mode 100644
index 0000000..0fa71f4
--- /dev/null
+++ b/test/fixtures/slackware/var/log/packages/rzip-2.1-i486-1
@@ -0,0 +1,29 @@
+PACKAGE NAME: rzip-2.1-i486-1
+COMPRESSED PACKAGE SIZE: 20K
+UNCOMPRESSED PACKAGE SIZE: 50K
+PACKAGE LOCATION: ./rzip-2.1-i486-1.txz
+PACKAGE DESCRIPTION:
+rzip: rzip (a large-file compression program)
+rzip:
+rzip: rzip is a file compression program designed to do particularly well
+rzip: on very large files containing long distance redundancy.
+rzip:
+rzip: rzip was written by Andrew Tridgell.
+rzip:
+rzip:
+rzip:
+rzip:
+rzip:
+FILE LIST:
+./
+bin/
+bin/rzip
+usr/
+usr/doc/
+usr/doc/rzip-2.1/
+usr/doc/rzip-2.1/COPYING
+usr/man/
+usr/man/man1/
+usr/man/man1/rzip.1.gz
+install/
+install/slack-desc
diff --git a/test/fixtures/slackware/var/slapt-get/package_data b/test/fixtures/slackware/var/slapt-get/package_data
new file mode 100644
index 0000000..410fc3d
--- /dev/null
+++ b/test/fixtures/slackware/var/slapt-get/package_data
@@ -0,0 +1,47 @@
+PACKAGE NAME: abc-4-i686-1.txz
+PACKAGE MIRROR: http://slackware.com/
+PACKAGE PRIORITY: 2
+PACKAGE LOCATION: ./slackware/ap
+PACKAGE SIZE (compressed): 48 K
+PACKAGE SIZE (uncompressed): 150 K
+PACKAGE REQUIRED:
+PACKAGE CONFLICTS:
+PACKAGE SUGGESTS:
+PACKAGE MD5SUM: 53e873df10b9e343a5c58721f10b9131
+PACKAGE DESCRIPTION:
+abc: abc (small utility)
+abc:
+abc: abc is a small utility
+abc:
+
+PACKAGE NAME: ran-1.2-noarch-1.txz
+PACKAGE MIRROR: http://slackware.com/
+PACKAGE PRIORITY: 2
+PACKAGE LOCATION: ./slackware/x
+PACKAGE SIZE (compressed): 36 K
+PACKAGE SIZE (uncompressed): 160 K
+PACKAGE REQUIRED:
+PACKAGE CONFLICTS:
+PACKAGE SUGGESTS:
+PACKAGE MD5SUM: cefa3f087e10f8371d68bea94a829ef8
+PACKAGE DESCRIPTION:
+ran: ran
+ran:
+ran: ran is part of X11.
+ran:
+
+PACKAGE NAME: qwe-2.1-i486-1.txz
+PACKAGE MIRROR: http://slackware.com/
+PACKAGE PRIORITY: 1
+PACKAGE LOCATION: ./slackware/ap
+PACKAGE SIZE (compressed): 20 K
+PACKAGE SIZE (uncompressed): 50 K
+PACKAGE REQUIRED:
+PACKAGE CONFLICTS:
+PACKAGE SUGGESTS:
+PACKAGE MD5SUM: 1a8fe22cb924cde3dc95c89689b20ee3
+PACKAGE DESCRIPTION:
+qwe: qwe
+qwe:
+qwe: qwe is a program
+qwe:
diff --git a/test/fixtures/ssh-copy-id/.ssh/id_rsa b/test/fixtures/ssh-copy-id/.ssh/id_rsa
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/ssh-copy-id/.ssh/id_rsa
diff --git a/test/fixtures/ssh-copy-id/.ssh/id_rsa.pub b/test/fixtures/ssh-copy-id/.ssh/id_rsa.pub
new file mode 100644
index 0000000..4c656eb
--- /dev/null
+++ b/test/fixtures/ssh-copy-id/.ssh/id_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa meh comment
diff --git a/test/fixtures/ssh/config b/test/fixtures/ssh/config
new file mode 100644
index 0000000..806f405
--- /dev/null
+++ b/test/fixtures/ssh/config
@@ -0,0 +1 @@
+UserKnownHostsFile known_hosts
diff --git a/test/fixtures/ssh/known_hosts b/test/fixtures/ssh/known_hosts
new file mode 100644
index 0000000..13b2f0f
--- /dev/null
+++ b/test/fixtures/ssh/known_hosts
@@ -0,0 +1,5 @@
+|1|abc
+|1|def
+doo
+ike ssh-rsa qwerty1234/Qwerty+1234==
+ls_known_host
diff --git a/test/fixtures/ssh/spaced conf b/test/fixtures/ssh/spaced conf
new file mode 100644
index 0000000..7ad64bc
--- /dev/null
+++ b/test/fixtures/ssh/spaced conf
@@ -0,0 +1,6 @@
+ UserKnownHostsFile known_hosts
+
+ # Unindented
+Host gee jar
+ # Indented, multiple hosts
+ HostName hus
diff --git a/test/fixtures/tar/archive.tar.xz b/test/fixtures/tar/archive.tar.xz
new file mode 100644
index 0000000..c8d2725
--- /dev/null
+++ b/test/fixtures/tar/archive.tar.xz
Binary files differ
diff --git a/test/fixtures/tar/dir/fileA b/test/fixtures/tar/dir/fileA
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/tar/dir/fileA
diff --git a/test/fixtures/tar/dir/fileB b/test/fixtures/tar/dir/fileB
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/tar/dir/fileB
diff --git a/test/fixtures/tar/dir/fileC b/test/fixtures/tar/dir/fileC
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/tar/dir/fileC
diff --git a/test/fixtures/tar/dir/hello b/test/fixtures/tar/dir/hello
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/tar/dir/hello
diff --git a/test/fixtures/tar/dir2/.nothing_here b/test/fixtures/tar/dir2/.nothing_here
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/tar/dir2/.nothing_here
diff --git a/test/fixtures/tar/escape.tar b/test/fixtures/tar/escape.tar
new file mode 100644
index 0000000..7af7e9f
--- /dev/null
+++ b/test/fixtures/tar/escape.tar
Binary files differ
diff --git a/test/fixtures/tox/tox.ini b/test/fixtures/tox/tox.ini
new file mode 100644
index 0000000..a64454f
--- /dev/null
+++ b/test/fixtures/tox/tox.ini
@@ -0,0 +1,6 @@
+[tox]
+envlist = py37
+
+[testenv]
+deps = pytest
+commands = pytest
diff --git a/test/fixtures/xz/a/b b/test/fixtures/xz/a/b
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/xz/a/b
diff --git a/test/fixtures/xz/bashcomp.lzma b/test/fixtures/xz/bashcomp.lzma
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/xz/bashcomp.lzma
diff --git a/test/fixtures/xz/bashcomp.tar b/test/fixtures/xz/bashcomp.tar
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/xz/bashcomp.tar
diff --git a/test/fixtures/xz/bashcomp.tar.xz b/test/fixtures/xz/bashcomp.tar.xz
new file mode 100644
index 0000000..b2274e6
--- /dev/null
+++ b/test/fixtures/xz/bashcomp.tar.xz
Binary files differ
diff --git a/test/fixtures/xz/bashcomp.tlz b/test/fixtures/xz/bashcomp.tlz
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/xz/bashcomp.tlz
diff --git a/test/fixtures/xz/bashcomp.xz b/test/fixtures/xz/bashcomp.xz
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/xz/bashcomp.xz
diff --git a/test/generate b/test/generate
new file mode 100755
index 0000000..59f525b
--- /dev/null
+++ b/test/generate
@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+
+# Generate skeleton files for completion of specified command
+
+import fileinput
+import re
+import sys
+
+
+def main():
+ if len(sys.argv) < 2:
+ print("Usage: %s command [args...]" % sys.argv[0], file=sys.stderr)
+ sys.exit(1)
+
+ cmd = testfile = sys.argv[1]
+ args = " ".join(sys.argv[2:]) if len(sys.argv) > 2 else ""
+ marker = ""
+ if re.search("[.+-]", cmd):
+ testfile = re.sub("[.-]", "_", cmd).replace("+", "plus")
+ marker = '\n@pytest.mark.bashcomp(\n cmd="%s",\n)' % cmd
+ testfile = "test_%s.py" % testfile
+ name = re.sub("(^|[_-]+)(.)", lambda m: m.group(2).upper(), cmd)
+ name = name.replace("+", "Plus")
+
+ with open("t/%s" % testfile, "w") as f:
+ print(
+ """\
+import pytest
+
+%s
+class Test%s:
+ @pytest.mark.complete("%s %s")
+ def test_1(self, completion):
+ assert completion"""
+ % (marker, name, cmd, args),
+ file=f,
+ )
+
+ in_extra_dist = False
+ extra_dist_lines = set()
+ with fileinput.input(files=("t/Makefile.am"), inplace=True) as f:
+ for line in f:
+ if line.startswith("EXTRA_DIST "):
+ in_extra_dist = True
+ elif in_extra_dist:
+ if line.startswith("\t"):
+ line = line.strip()
+ if not line.endswith("\\"):
+ line += " \\"
+ extra_dist_lines.add(line)
+ continue
+ extra_dist_lines.add("%s \\" % testfile)
+ sys.stdout.write("\t")
+ print("\n\t".join(sorted(extra_dist_lines))[:-2])
+ in_extra_dist = False
+ sys.stdout.write(line)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/test/requirements-dev.txt b/test/requirements-dev.txt
new file mode 100644
index 0000000..f34f10f
--- /dev/null
+++ b/test/requirements-dev.txt
@@ -0,0 +1,4 @@
+# Python >= 3.6.1 required here
+-r requirements.txt
+black==19.10b0
+pre-commit>=2.4.0
diff --git a/test/requirements.txt b/test/requirements.txt
new file mode 100644
index 0000000..df56f4e
--- /dev/null
+++ b/test/requirements.txt
@@ -0,0 +1,5 @@
+# Python >= 3.4 required here
+pexpect>=4
+pytest>=3.6
+pytest-xdist
+typing;python_version<"3.5"
diff --git a/test/runLint b/test/runLint
new file mode 100755
index 0000000..95c3887
--- /dev/null
+++ b/test/runLint
@@ -0,0 +1,51 @@
+#!/bin/bash -u
+
+gitgrep()
+{
+ local out=$(git grep -I -P -n "$1" |
+ grep -E '^(bash_completion|completions/|test/)' |
+ grep -Ev "^test/runLint\>${filter_out:+|$filter_out}")
+ if [ -n "$out" ]; then
+ printf '***** %s\n' "$2"
+ printf '%s\n\n' "$out"
+ fi
+}
+
+unset CDPATH
+cd $(dirname "$0")/..
+
+cmdstart='(^|[[:space:]]|\()'
+filter_out=
+
+gitgrep $cmdstart"awk\b.*-F([[:space:]]|[[:space:]]*[\"'][^\"']{2,})" \
+ 'awk with -F char or -F ERE, use -Fchar instead (Solaris)'
+
+gitgrep $cmdstart"awk\b.*\[:[a-z]*:\]" \
+ 'awk with POSIX character class not supported in mawk (Debian/Ubuntu)'
+
+gitgrep $cmdstart'sed\b.*\\[?+]' \
+ 'sed with ? or +, use POSIX BRE instead (\{m,n\})'
+
+gitgrep $cmdstart'sed\b.*\\\|' \
+ "sed with \|, use POSIX BRE (possibly multiple sed invocations) or another tool instead"
+
+# TODO: really nonportable? appears to work fine in Linux, FreeBSD, Solaris
+#gitgrep $cmdstart'sed\b.*;' \
+# 'sed with ;, use multiple -e options instead (POSIX?) (false positives?)'
+
+gitgrep $cmdstart'sed\b.*[[:space:]]-[^[:space:]]*[rE]' \
+ 'sed with -r or -E, drop and use POSIX BRE instead'
+
+gitgrep $cmdstart'[ef]grep\b' \
+ '[ef]grep, use grep -[EF] instead (historical/deprecated)'
+
+# TODO: $ in sed subexpression used as an anchor (POSIX BRE optional, not in
+# Solaris/FreeBSD)
+
+gitgrep '(?<!command)'$cmdstart'(grep|ls|sed)(\s|$)' \
+ 'invoke grep, ls, and sed through "command", e.g. "command grep"'
+
+gitgrep '<<<' 'herestrings use temp files, use some other way'
+
+filter_out='^(test/|bash_completion\.sh)' gitgrep ' \[ ' \
+ 'use [[ ]] instead of [ ]'
diff --git a/test/setup.cfg b/test/setup.cfg
new file mode 100644
index 0000000..6abd7d3
--- /dev/null
+++ b/test/setup.cfg
@@ -0,0 +1,18 @@
+[tool:pytest]
+minversion = 3.6
+markers =
+ bashcomp
+ complete
+
+[mypy]
+python_version = 3.4
+ignore_missing_imports = true
+
+[isort]
+known_first_party = conftest
+known_third_party = pexpect,pytest
+profile = black
+line_length = 79
+
+[flake8]
+extend-ignore = D202,E203,E501
diff --git a/test/t/Makefile.am b/test/t/Makefile.am
new file mode 100644
index 0000000..801841f
--- /dev/null
+++ b/test/t/Makefile.am
@@ -0,0 +1,698 @@
+SUBDIRS = unit
+
+EXTRA_DIST = \
+ conftest.py \
+ test_2to3.py \
+ test_7z.py \
+ test_a2ps.py \
+ test_a2x.py \
+ test_abook.py \
+ test_aclocal.py \
+ test_acpi.py \
+ test_acroread.py \
+ test_adb.py \
+ test_add_members.py \
+ test_alias.py \
+ test_alpine.py \
+ test_animate.py \
+ test_ant.py \
+ test_apache2ctl.py \
+ test_appdata_validate.py \
+ test_apt_build.py \
+ test_apt_cache.py \
+ test_apt_get.py \
+ test_aptitude.py \
+ test_arch.py \
+ test_arp.py \
+ test_arping.py \
+ test_arpspoof.py \
+ test_asciidoc.py \
+ test_aspell.py \
+ test_autoconf.py \
+ test_autoheader.py \
+ test_automake.py \
+ test_autoreconf.py \
+ test_autorpm.py \
+ test_autoscan.py \
+ test_autossh.py \
+ test_autoupdate.py \
+ test_avctrl.py \
+ test_awk.py \
+ test_badblocks.py \
+ test_base64.py \
+ test_bash.py \
+ test_bc.py \
+ test_bind.py \
+ test_bison.py \
+ test_bk.py \
+ test_bmake.py \
+ test_brctl.py \
+ test_btdownloadcurses_py.py \
+ test_btdownloadgui_py.py \
+ test_btdownloadheadless_py.py \
+ test_bts.py \
+ test_bzip2.py \
+ test_cal.py \
+ test_cancel.py \
+ test_cardctl.py \
+ test_carton.py \
+ test_cat.py \
+ test_cc.py \
+ test_ccache.py \
+ test_ccze.py \
+ test_cd.py \
+ test_cdrecord.py \
+ test_cfagent.py \
+ test_cfrun.py \
+ test_chage.py \
+ test_change_pw.py \
+ test_check_db.py \
+ test_check_perms.py \
+ test_checksec.py \
+ test_chfn.py \
+ test_chgrp.py \
+ test_chkconfig.py \
+ test_chmod.py \
+ test_chown.py \
+ test_chpasswd.py \
+ test_chromium_browser.py \
+ test_chronyc.py \
+ test_chroot.py \
+ test_chrpath.py \
+ test_chsh.py \
+ test_ci.py \
+ test_ciptool.py \
+ test_civclient.py \
+ test_civserver.py \
+ test_cksfv.py \
+ test_cleanarch.py \
+ test_clisp.py \
+ test_clone_member.py \
+ test_co.py \
+ test_colordiff.py \
+ test_compare.py \
+ test_compgen.py \
+ test_complete.py \
+ test_composite.py \
+ test_config_list.py \
+ test_configure.py \
+ test_conjure.py \
+ test_convert.py \
+ test_cowsay.py \
+ test_cp.py \
+ test_cpan2dist.py \
+ test_cpio.py \
+ test_cplusplus.py \
+ test_cppcheck.py \
+ test_createdb.py \
+ test_createuser.py \
+ test_crontab.py \
+ test_cryptsetup.py \
+ test_csplit.py \
+ test_curl.py \
+ test_cut.py \
+ test_cvs.py \
+ test_cvsps.py \
+ test_date.py \
+ test_dcop.py \
+ test_dd.py \
+ test_declare.py \
+ test_deja_dup.py \
+ test_desktop_file_validate.py \
+ test_df.py \
+ test_dfutool.py \
+ test_dhclient.py \
+ test_dict.py \
+ test_diff.py \
+ test_dir.py \
+ test_display.py \
+ test_dmesg.py \
+ test_dmypy.py \
+ test_dnssec_keygen.py \
+ test_dnsspoof.py \
+ test_dot.py \
+ test_dpkg.py \
+ test_dpkg_deb.py \
+ test_dpkg_query.py \
+ test_dpkg_reconfigure.py \
+ test_dpkg_source.py \
+ test_dropdb.py \
+ test_dropuser.py \
+ test_dselect.py \
+ test_dsniff.py \
+ test_du.py \
+ test_dumpdb.py \
+ test_dumpe2fs.py \
+ test_e2freefrag.py \
+ test_e2label.py \
+ test_ebtables.py \
+ test_ecryptfs_migrate_home.py \
+ test_eject.py \
+ test_enscript.py \
+ test_env.py \
+ test_eog.py \
+ test_ether_wake.py \
+ test_etherwake.py \
+ test_evince.py \
+ test_expand.py \
+ test_explodepkg.py \
+ test_export.py \
+ test_faillog.py \
+ test_fbgs.py \
+ test_fbi.py \
+ test_feh.py \
+ test_file.py \
+ test_file_roller.py \
+ test_filefrag.py \
+ test_filesnarf.py \
+ test_find.py \
+ test_find_member.py \
+ test_finger.py \
+ test_fio.py \
+ test_firefox.py \
+ test_flake8.py \
+ test_fmt.py \
+ test_fold.py \
+ test_freebsd_update.py \
+ test_freeciv.py \
+ test_freeciv_server.py \
+ test_function.py \
+ test_fusermount.py \
+ test_g4.py \
+ test_g77.py \
+ test_gcc.py \
+ test_gcj.py \
+ test_gcl.py \
+ test_gdb.py \
+ test_genaliases.py \
+ test_gendiff.py \
+ test_genisoimage.py \
+ test_geoiplookup.py \
+ test_getconf.py \
+ test_getent.py \
+ test_gkrellm.py \
+ test_gm.py \
+ test_gmplayer.py \
+ test_gnatmake.py \
+ test_gnokii.py \
+ test_gnome_mplayer.py \
+ test_gnome_screenshot.py \
+ test_gpasswd.py \
+ test_gpc.py \
+ test_gperf.py \
+ test_gpg.py \
+ test_gpg2.py \
+ test_gpgv.py \
+ test_gphoto2.py \
+ test_gplusplus.py \
+ test_gprof.py \
+ test_grep.py \
+ test_groupadd.py \
+ test_groupdel.py \
+ test_groupmems.py \
+ test_groupmod.py \
+ test_growisofs.py \
+ test_grpck.py \
+ test_grub.py \
+ test_gssdp_discover.py \
+ test_gzip.py \
+ test_hciattach.py \
+ test_hciconfig.py \
+ test_hcitool.py \
+ test_hddtemp.py \
+ test_head.py \
+ test_hexdump.py \
+ test_hid2hci.py \
+ test_host.py \
+ test_hostname.py \
+ test_hping2.py \
+ test_hping3.py \
+ test_htop.py \
+ test_htpasswd.py \
+ test_hunspell.py \
+ test_hwclock.py \
+ test_iconv.py \
+ test_id.py \
+ test_identify.py \
+ test_idn.py \
+ test_ifdown.py \
+ test_ifstat.py \
+ test_iftop.py \
+ test_ifup.py \
+ test_import.py \
+ test_influx.py \
+ test_info.py \
+ test_inject.py \
+ test_inotifywait.py \
+ test_inotifywatch.py \
+ test_insmod.py \
+ test_installpkg.py \
+ test_interdiff.py \
+ test_invoke_rc_d.py \
+ test_ionice.py \
+ test_ip.py \
+ test_ipcalc.py \
+ test_iperf.py \
+ test_ipmitool.py \
+ test_ipsec.py \
+ test_iptables.py \
+ test_ipv6calc.py \
+ test_irb.py \
+ test_iscsiadm.py \
+ test_isort.py \
+ test_isql.py \
+ test_iwconfig.py \
+ test_iwlist.py \
+ test_iwpriv.py \
+ test_iwspy.py \
+ test_jar.py \
+ test_jarsigner.py \
+ test_java.py \
+ test_javac.py \
+ test_javadoc.py \
+ test_javaws.py \
+ test_jpegoptim.py \
+ test_jps.py \
+ test_jq.py \
+ test_jshint.py \
+ test_json_xs.py \
+ test_jsonschema.py \
+ test_k3b.py \
+ test_kcov.py \
+ test_kdvi.py \
+ test_kill.py \
+ test_killall.py \
+ test_kldload.py \
+ test_kldunload.py \
+ test_koji.py \
+ test_kpdf.py \
+ test_kplayer.py \
+ test_ktutil.py \
+ test_l2ping.py \
+ test_larch.py \
+ test_lastlog.py \
+ test_ld.py \
+ test_ldapadd.py \
+ test_ldapcompare.py \
+ test_ldapdelete.py \
+ test_ldapmodrdn.py \
+ test_ldappasswd.py \
+ test_ldapsearch.py \
+ test_ldapvi.py \
+ test_ldapwhoami.py \
+ test_ldd.py \
+ test_less.py \
+ test_lftp.py \
+ test_lftpget.py \
+ test_lilo.py \
+ test_links.py \
+ test_lintian.py \
+ test_lintian_info.py \
+ test_lisp.py \
+ test_list_admins.py \
+ test_list_lists.py \
+ test_list_members.py \
+ test_list_owners.py \
+ test_ln.py \
+ test_locale_gen.py \
+ test_look.py \
+ test_lpq.py \
+ test_lpr.py \
+ test_lrzip.py \
+ test_ls.py \
+ test_lsof.py \
+ test_lspci.py \
+ test_lsscsi.py \
+ test_lsusb.py \
+ test_lua.py \
+ test_luac.py \
+ test_luseradd.py \
+ test_luserdel.py \
+ test_lusermod.py \
+ test_lvchange.py \
+ test_lvcreate.py \
+ test_lvdisplay.py \
+ test_lvextend.py \
+ test_lvm.py \
+ test_lvmdiskscan.py \
+ test_lvreduce.py \
+ test_lvremove.py \
+ test_lvrename.py \
+ test_lvresize.py \
+ test_lvs.py \
+ test_lvscan.py \
+ test_lz4.py \
+ test_lzip.py \
+ test_lzma.py \
+ test_lzop.py \
+ test_m4.py \
+ test_macof.py \
+ test_mailmanctl.py \
+ test_mailsnarf.py \
+ test_make.py \
+ test_makepkg.py \
+ test_man.py \
+ test_mc.py \
+ test_mcrypt.py \
+ test_md5sum.py \
+ test_mdadm.py \
+ test_mdecrypt.py \
+ test_mdtool.py \
+ test_medusa.py \
+ test_mencoder.py \
+ test_mii_diag.py \
+ test_mii_tool.py \
+ test_minicom.py \
+ test_mkdir.py \
+ test_mkfifo.py \
+ test_mkinitrd.py \
+ test_mkisofs.py \
+ test_mknod.py \
+ test_mktemp.py \
+ test_mmsitepass.py \
+ test_mock.py \
+ test_modinfo.py \
+ test_modprobe.py \
+ test_module.py \
+ test_mogrify.py \
+ test_monodevelop.py \
+ test_montage.py \
+ test_mount.py \
+ test_mplayer.py \
+ test_mr.py \
+ test_msgsnarf.py \
+ test_msynctool.py \
+ test_mtx.py \
+ test_munin_node_configure.py \
+ test_munin_run.py \
+ test_munindoc.py \
+ test_mussh.py \
+ test_mutt.py \
+ test_muttng.py \
+ test_mv.py \
+ test_mypy.py \
+ test_mysql.py \
+ test_mysqladmin.py \
+ test_nc.py \
+ test_ncftp.py \
+ test_nethogs.py \
+ test_netstat.py \
+ test_newgrp.py \
+ test_newlist.py \
+ test_newusers.py \
+ test_ngrep.py \
+ test_nl.py \
+ test_nm.py \
+ test_nmap.py \
+ test_nmcli.py \
+ test_nproc.py \
+ test_nslookup.py \
+ test_nsupdate.py \
+ test_ntpdate.py \
+ test_objcopy.py \
+ test_objdump.py \
+ test_od.py \
+ test_oggdec.py \
+ test_op.py \
+ test_openssl.py \
+ test_opera.py \
+ test_optipng.py \
+ test_p4.py \
+ test_pack200.py \
+ test_passwd.py \
+ test_paste.py \
+ test_patch.py \
+ test_pdftotext.py \
+ test_perl.py \
+ test_perlcritic.py \
+ test_perldoc.py \
+ test_perltidy.py \
+ test_pgrep.py \
+ test_phing.py \
+ test_pidof.py \
+ test_pine.py \
+ test_pinfo.py \
+ test_ping.py \
+ test_pkg_config.py \
+ test_pkg_deinstall.py \
+ test_pkg_delete.py \
+ test_pkg_get.py \
+ test_pkg_info.py \
+ test_pkgadd.py \
+ test_pkgrm.py \
+ test_pkgtool.py \
+ test_pkgutil.py \
+ test_pkill.py \
+ test_plague_client.py \
+ test_pm_hibernate.py \
+ test_pm_is_supported.py \
+ test_pm_powersave.py \
+ test_pngfix.py \
+ test_portinstall.py \
+ test_portsnap.py \
+ test_portupgrade.py \
+ test_postcat.py \
+ test_postconf.py \
+ test_postfix.py \
+ test_postmap.py \
+ test_postsuper.py \
+ test_povray.py \
+ test_pr.py \
+ test_prelink.py \
+ test_printenv.py \
+ test_protoc.py \
+ test_psql.py \
+ test_ptx.py \
+ test_puppet.py \
+ test_pushd.py \
+ test_pv.py \
+ test_pvchange.py \
+ test_pvcreate.py \
+ test_pvdisplay.py \
+ test_pvmove.py \
+ test_pvremove.py \
+ test_pvs.py \
+ test_pvscan.py \
+ test_pwck.py \
+ test_pwd.py \
+ test_pwdx.py \
+ test_pwgen.py \
+ test_pycodestyle.py \
+ test_pydoc.py \
+ test_pydocstyle.py \
+ test_pyflakes.py \
+ test_pylint.py \
+ test_pylint_3.py \
+ test_pytest.py \
+ test_python.py \
+ test_python3.py \
+ test_pyvenv.py \
+ test_qemu.py \
+ test_qrunner.py \
+ test_querybts.py \
+ test_quota.py \
+ test_quotacheck.py \
+ test_quotaon.py \
+ test_radvdump.py \
+ test_rcs.py \
+ test_rcsdiff.py \
+ test_rdesktop.py \
+ test_rdict.py \
+ test_readelf.py \
+ test_readonly.py \
+ test_remove_members.py \
+ test_removepkg.py \
+ test_renice.py \
+ test_repomanage.py \
+ test_reportbug.py \
+ test_reptyr.py \
+ test_resolvconf.py \
+ test_rfcomm.py \
+ test_rfkill.py \
+ test_ri.py \
+ test_rlog.py \
+ test_rm.py \
+ test_rmdir.py \
+ test_rmlist.py \
+ test_rmmod.py \
+ test_route.py \
+ test_rpcdebug.py \
+ test_rpm.py \
+ test_rpm2tgz.py \
+ test_rpmbuild.py \
+ test_rrdtool.py \
+ test_rsync.py \
+ test_rtcwake.py \
+ test_runuser.py \
+ test_sbcl.py \
+ test_sbcl_mt.py \
+ test_sbopkg.py \
+ test_scp.py \
+ test_screen.py \
+ test_scrub.py \
+ test_sdptool.py \
+ test_secret_tool.py \
+ test_sed.py \
+ test_seq.py \
+ test_service.py \
+ test_set.py \
+ test_setquota.py \
+ test_sftp.py \
+ test_sh.py \
+ test_sha1sum.py \
+ test_shar.py \
+ test_shellcheck.py \
+ test_sitecopy.py \
+ test_slackpkg.py \
+ test_slapt_get.py \
+ test_slapt_src.py \
+ test_smartctl.py \
+ test_smbcacls.py \
+ test_smbclient.py \
+ test_smbcquotas.py \
+ test_smbget.py \
+ test_smbpasswd.py \
+ test_smbtar.py \
+ test_smbtree.py \
+ test_snownews.py \
+ test_sort.py \
+ test_split.py \
+ test_spovray.py \
+ test_sqlite3.py \
+ test_ss.py \
+ test_ssh.py \
+ test_ssh_add.py \
+ test_ssh_copy_id.py \
+ test_ssh_keygen.py \
+ test_sshfs.py \
+ test_sshmitm.py \
+ test_sshow.py \
+ test_strace.py \
+ test_stream.py \
+ test_strings.py \
+ test_strip.py \
+ test_su.py \
+ test_sudo.py \
+ test_sum.py \
+ test_svcadm.py \
+ test_svk.py \
+ test_svn.py \
+ test_svnadmin.py \
+ test_svnlook.py \
+ test_sync_members.py \
+ test_synclient.py \
+ test_sysbench.py \
+ test_sysctl.py \
+ test_tac.py \
+ test_tail.py \
+ test_tar.py \
+ test_tcpdump.py \
+ test_tcpkill.py \
+ test_tcpnice.py \
+ test_tee.py \
+ test_texindex.py \
+ test_tightvncviewer.py \
+ test_time.py \
+ test_timeout.py \
+ test_tipc.py \
+ test_totem.py \
+ test_touch.py \
+ test_tox.py \
+ test_tr.py \
+ test_tracepath.py \
+ test_tshark.py \
+ test_tsig_keygen.py \
+ test_tune2fs.py \
+ test_udevadm.py \
+ test_ulimit.py \
+ test_umount.py \
+ test_unace.py \
+ test_uname.py \
+ test_unexpand.py \
+ test_uniq.py \
+ test_units.py \
+ test_unpack200.py \
+ test_unrar.py \
+ test_unset.py \
+ test_unshunt.py \
+ test_update_alternatives.py \
+ test_update_rc_d.py \
+ test_upgradepkg.py \
+ test_urlsnarf.py \
+ test_uscan.py \
+ test_useradd.py \
+ test_userdel.py \
+ test_usermod.py \
+ test_valgrind.py \
+ test_vdir.py \
+ test_vgcfgbackup.py \
+ test_vgcfgrestore.py \
+ test_vgchange.py \
+ test_vgck.py \
+ test_vgconvert.py \
+ test_vgcreate.py \
+ test_vgdisplay.py \
+ test_vgexport.py \
+ test_vgextend.py \
+ test_vgimport.py \
+ test_vgmerge.py \
+ test_vgmknodes.py \
+ test_vgreduce.py \
+ test_vgremove.py \
+ test_vgrename.py \
+ test_vgs.py \
+ test_vgscan.py \
+ test_vgsplit.py \
+ test_vi.py \
+ test_vipw.py \
+ test_vmstat.py \
+ test_vncviewer.py \
+ test_vpnc.py \
+ test_watch.py \
+ test_wc.py \
+ test_webmitm.py \
+ test_wget.py \
+ test_who.py \
+ test_wine.py \
+ test_withlist.py \
+ test_wodim.py \
+ test_wol.py \
+ test_write.py \
+ test_wsimport.py \
+ test_wtf.py \
+ test_wvdial.py \
+ test_xdg_mime.py \
+ test_xdg_settings.py \
+ test_xfreerdp.py \
+ test_xgamma.py \
+ test_xhost.py \
+ test_xm.py \
+ test_xmllint.py \
+ test_xmlwf.py \
+ test_xmms.py \
+ test_xmodmap.py \
+ test_xpovray.py \
+ test_xrandr.py \
+ test_xrdb.py \
+ test_xsltproc.py \
+ test_xvfb_run.py \
+ test_xvnc4viewer.py \
+ test_xxd.py \
+ test_xz.py \
+ test_xzdec.py \
+ test_ypcat.py \
+ test_ypmatch.py \
+ test_yum.py \
+ test_yum_arch.py \
+ test_zopfli.py \
+ test_zopflipng.py
+
+all:
+
+PYTEST = @PYTEST@
+
+check-local:
+ $(PYTEST) $(PYTESTFLAGS) $(srcdir)
+
+clean-local:
+ $(RM) -R __pycache__
diff --git a/test/t/conftest.py b/test/t/conftest.py
new file mode 100644
index 0000000..5c1603d
--- /dev/null
+++ b/test/t/conftest.py
@@ -0,0 +1,637 @@
+import difflib
+import os
+import re
+import shlex
+import subprocess
+import time
+from typing import Callable, Iterable, Iterator, List, Optional, Tuple
+
+import pexpect
+import pytest
+
+PS1 = "/@"
+MAGIC_MARK = "__MaGiC-maRKz!__"
+
+
+def find_unique_completion_pair(
+ items: Iterable[str],
+) -> Optional[Tuple[str, str]]:
+ result = None
+ bestscore = 0
+ sitems = sorted(set(items))
+ for i in range(len(sitems)):
+ cur = sitems[i]
+ curlen = len(cur)
+ prv = sitems[i - 1] if i != 0 else ""
+ prvlen = len(prv)
+ nxt = sitems[i + 1] if i < len(sitems) - 1 else ""
+ nxtlen = len(nxt)
+ diffprv = prv == ""
+ diffnxt = nxt == ""
+ # Analyse each item of the list and look for the minimum length of the
+ # partial prefix which is distinct from both nxt and prv. The list
+ # is sorted so the prefix will be unique in the entire list.
+ for j in range(curlen):
+ curchar = cur[j]
+ if not diffprv and (j >= prvlen or prv[j] != curchar):
+ diffprv = True
+ if not diffnxt and (j >= nxtlen or nxt[j] != curchar):
+ diffnxt = True
+ if diffprv and diffnxt:
+ break
+ # At the end of the loop, j is the index of last character of
+ # the unique partial prefix. The length is one plus that.
+ parlen = j + 1
+ if parlen >= curlen:
+ continue
+ # Try to find the most "readable pair"; look for a long pair where
+ # part is about half of full.
+ if parlen < curlen / 2:
+ parlen = int(curlen / 2)
+ score = curlen - parlen
+ if score > bestscore:
+ bestscore = score
+ result = (cur[:parlen], cur)
+ return result
+
+
+@pytest.fixture(scope="class")
+def output_sort_uniq(bash: pexpect.spawn) -> Callable[[str], List[str]]:
+ def _output_sort_uniq(command: str) -> List[str]:
+ return sorted(
+ set( # weed out possible duplicates
+ assert_bash_exec(bash, command, want_output=True).split()
+ )
+ )
+
+ return _output_sort_uniq
+
+
+@pytest.fixture(scope="class")
+def part_full_user(
+ bash: pexpect.spawn, output_sort_uniq: Callable[[str], List[str]]
+) -> Optional[Tuple[str, str]]:
+ res = output_sort_uniq("compgen -u")
+ pair = find_unique_completion_pair(res)
+ if not pair:
+ pytest.skip("No suitable test user found")
+ return pair
+
+
+@pytest.fixture(scope="class")
+def part_full_group(
+ bash: pexpect.spawn, output_sort_uniq: Callable[[str], List[str]]
+) -> Optional[Tuple[str, str]]:
+ res = output_sort_uniq("compgen -g")
+ pair = find_unique_completion_pair(res)
+ if not pair:
+ pytest.skip("No suitable test user found")
+ return pair
+
+
+@pytest.fixture(scope="class")
+def hosts(bash: pexpect.spawn) -> List[str]:
+ output = assert_bash_exec(bash, "compgen -A hostname", want_output=True)
+ return sorted(set(output.split() + _avahi_hosts(bash)))
+
+
+@pytest.fixture(scope="class")
+def avahi_hosts(bash: pexpect.spawn) -> List[str]:
+ return _avahi_hosts(bash)
+
+
+def _avahi_hosts(bash: pexpect.spawn) -> List[str]:
+ output = assert_bash_exec(
+ bash,
+ "! type avahi-browse &>/dev/null || "
+ "avahi-browse -cpr _workstation._tcp 2>/dev/null "
+ "| command grep ^= | cut -d';' -f7",
+ want_output=None,
+ )
+ return sorted(set(output.split()))
+
+
+@pytest.fixture(scope="class")
+def known_hosts(bash: pexpect.spawn) -> List[str]:
+ output = assert_bash_exec(
+ bash,
+ '_known_hosts_real ""; '
+ r'printf "%s\n" "${COMPREPLY[@]}"; unset COMPREPLY',
+ want_output=True,
+ )
+ return sorted(set(output.split()))
+
+
+@pytest.fixture(scope="class")
+def user_home(bash: pexpect.spawn) -> Tuple[str, str]:
+ user = assert_bash_exec(
+ bash, 'id -un 2>/dev/null || echo "$USER"', want_output=True
+ ).strip()
+ home = assert_bash_exec(bash, 'echo "$HOME"', want_output=True).strip()
+ return (user, home)
+
+
+def partialize(
+ bash: pexpect.spawn, items: Iterable[str]
+) -> Tuple[str, List[str]]:
+ """
+ Get list of items starting with the first char of first of items.
+
+ Disregard items starting with a COMP_WORDBREAKS character
+ (e.g. a colon ~ IPv6 address), they are special cases requiring
+ special tests.
+ """
+ first_char = None
+ comp_wordbreaks = assert_bash_exec(
+ bash,
+ 'printf "%s" "$COMP_WORDBREAKS"',
+ want_output=True,
+ want_newline=False,
+ )
+ partial_items = []
+ for item in sorted(items):
+ if first_char is None:
+ if item[0] not in comp_wordbreaks:
+ first_char = item[0]
+ partial_items.append(item)
+ elif item.startswith(first_char):
+ partial_items.append(item)
+ else:
+ break
+ if first_char is None:
+ pytest.skip("Could not generate partial items list from %s" % items)
+ # superfluous/dead code to assist mypy; pytest.skip always raises
+ assert first_char is not None
+ return first_char, partial_items
+
+
+@pytest.fixture(scope="class")
+def bash(request) -> pexpect.spawn:
+
+ logfile = None
+ if os.environ.get("BASHCOMP_TEST_LOGFILE"):
+ logfile = open(os.environ["BASHCOMP_TEST_LOGFILE"], "w")
+ testdir = os.path.abspath(
+ os.path.join(os.path.dirname(__file__), os.pardir)
+ )
+ env = os.environ.copy()
+ env.update(
+ dict(
+ SRCDIR=testdir, # TODO needed at least by bashrc
+ SRCDIRABS=testdir, # TODO needed?
+ PS1=PS1,
+ INPUTRC="%s/config/inputrc" % testdir,
+ TERM="dumb",
+ LC_COLLATE="C", # to match Python's default locale unaware sort
+ )
+ )
+
+ fixturesdir = os.path.join(testdir, "fixtures")
+ os.chdir(fixturesdir)
+
+ # Start bash
+ bash = pexpect.spawn(
+ "%s --norc" % os.environ.get("BASHCOMP_TEST_BASH", "bash"),
+ maxread=os.environ.get("BASHCOMP_TEST_PEXPECT_MAXREAD", 20000),
+ logfile=logfile,
+ cwd=fixturesdir,
+ env=env,
+ encoding="utf-8", # TODO? or native or...?
+ # FIXME: Tests shouldn't depend on dimensions, but it's difficult to
+ # expect robustly enough for Bash to wrap lines anywhere (e.g. inside
+ # MAGIC_MARK). Increase window width to reduce wrapping.
+ dimensions=(24, 160),
+ # TODO? codec_errors="replace",
+ )
+ bash.expect_exact(PS1)
+
+ # Load bashrc and bash_completion
+ assert_bash_exec(bash, "source '%s/config/bashrc'" % testdir)
+ assert_bash_exec(bash, "source '%s/../bash_completion'" % testdir)
+
+ # Use command name from marker if set, or grab from test filename
+ cmd = None # type: Optional[str]
+ cmd_found = False
+ marker = request.node.get_closest_marker("bashcomp")
+ if marker:
+ cmd = marker.kwargs.get("cmd")
+ cmd_found = "cmd" in marker.kwargs
+ # Run pre-test commands, early so they're usable in skipif
+ for pre_cmd in marker.kwargs.get("pre_cmds", []):
+ assert_bash_exec(bash, pre_cmd)
+ # Process skip and xfail conditions
+ skipif = marker.kwargs.get("skipif")
+ if skipif:
+ try:
+ assert_bash_exec(bash, skipif, want_output=None)
+ except AssertionError:
+ pass
+ else:
+ bash.close()
+ pytest.skip(skipif)
+ xfail = marker.kwargs.get("xfail")
+ if xfail:
+ try:
+ assert_bash_exec(bash, xfail, want_output=None)
+ except AssertionError:
+ pass
+ else:
+ pytest.xfail(xfail)
+ if not cmd_found:
+ match = re.search(
+ r"^test_(.+)\.py$", os.path.basename(str(request.fspath))
+ )
+ if match:
+ cmd = match.group(1)
+
+ request.cls.cmd = cmd
+
+ if (cmd_found and cmd is None) or is_testable(bash, cmd):
+ before_env = get_env(bash)
+ yield bash
+ # Not exactly sure why, but some errors leave bash in state where
+ # getting the env here would fail and trash our test output. So
+ # reset to a good state first (Ctrl+C, expect prompt).
+ bash.sendintr()
+ bash.expect_exact(PS1)
+ diff_env(
+ before_env,
+ get_env(bash),
+ marker.kwargs.get("ignore_env") if marker else "",
+ )
+
+ if marker:
+ for post_cmd in marker.kwargs.get("post_cmds", []):
+ assert_bash_exec(bash, post_cmd)
+
+ # Clean up
+ bash.close()
+ if logfile:
+ logfile.close()
+
+
+def is_testable(bash: pexpect.spawn, cmd: Optional[str]) -> bool:
+ if not cmd:
+ pytest.fail("Could not resolve name of command to test")
+ return False
+ if not load_completion_for(bash, cmd):
+ pytest.skip("No completion for command %s" % cmd)
+ return True
+
+
+def is_bash_type(bash: pexpect.spawn, cmd: Optional[str]) -> bool:
+ if not cmd:
+ return False
+ typecmd = "type %s &>/dev/null && echo -n 0 || echo -n 1" % cmd
+ bash.sendline(typecmd)
+ bash.expect_exact(typecmd + "\r\n")
+ result = bash.expect_exact(["0", "1"]) == 0
+ bash.expect_exact(PS1)
+ return result
+
+
+def load_completion_for(bash: pexpect.spawn, cmd: str) -> bool:
+ try:
+ # Allow __load_completion to fail so we can test completions
+ # that are directly loaded in bash_completion without a separate file.
+ assert_bash_exec(bash, "__load_completion %s || :" % cmd)
+ assert_bash_exec(bash, "complete -p %s &>/dev/null" % cmd)
+ except AssertionError:
+ return False
+ return True
+
+
+def assert_bash_exec(
+ bash: pexpect.spawn,
+ cmd: str,
+ want_output: Optional[bool] = False,
+ want_newline=True,
+) -> str:
+ """
+ :param want_output: if None, don't care if got output or not
+ """
+
+ # Send command
+ bash.sendline(cmd)
+ bash.expect_exact(cmd)
+
+ # Find prompt, output is before it
+ bash.expect_exact("%s%s" % ("\r\n" if want_newline else "", PS1))
+ output = bash.before
+
+ # Retrieve exit status
+ echo = "echo $?"
+ bash.sendline(echo)
+ got = bash.expect(
+ [
+ r"^%s\r\n(\d+)\r\n%s" % (re.escape(echo), re.escape(PS1)),
+ PS1,
+ pexpect.EOF,
+ pexpect.TIMEOUT,
+ ]
+ )
+ status = bash.match.group(1) if got == 0 else "unknown"
+
+ assert status == "0", 'Error running "%s": exit status=%s, output="%s"' % (
+ cmd,
+ status,
+ output,
+ )
+ if want_output is not None:
+ if output:
+ assert want_output, (
+ 'Unexpected output from "%s": exit status=%s, output="%s"'
+ % (cmd, status, output)
+ )
+ else:
+ assert not want_output, (
+ 'Expected output from "%s": exit status=%s, output="%s"'
+ % (cmd, status, output)
+ )
+
+ return output
+
+
+def get_env(bash: pexpect.spawn) -> List[str]:
+ return (
+ assert_bash_exec(
+ bash,
+ "{ (set -o posix ; set); declare -F; shopt -p; set -o; }",
+ want_output=True,
+ )
+ .strip()
+ .splitlines()
+ )
+
+
+def diff_env(before: List[str], after: List[str], ignore: str):
+ diff = [
+ x
+ for x in difflib.unified_diff(before, after, n=0, lineterm="")
+ # Remove unified diff markers:
+ if not re.search(r"^(---|\+\+\+|@@ )", x)
+ # Ignore variables expected to change:
+ and not re.search("^[-+](_|PPID|BASH_REMATCH|OLDPWD)=", x)
+ # Ignore likely completion functions added by us:
+ and not re.search(r"^\+declare -f _.+", x)
+ # ...and additional specified things:
+ and not re.search(ignore or "^$", x)
+ ]
+ # For some reason, COMP_WORDBREAKS gets added to the list after
+ # saving. Remove its changes, and note that it may take two lines.
+ for i in range(0, len(diff)):
+ if re.match("^[-+]COMP_WORDBREAKS=", diff[i]):
+ if i < len(diff) and not re.match(r"^\+[\w]+=", diff[i + 1]):
+ del diff[i + 1]
+ del diff[i]
+ break
+ assert not diff, "Environment should not be modified"
+
+
+class CompletionResult(Iterable[str]):
+ """
+ Class to hold completion results.
+ """
+
+ def __init__(self, output: Optional[str] = None):
+ """
+ :param output: All completion output as-is.
+ """
+ self.output = output or ""
+
+ def endswith(self, suffix: str) -> bool:
+ return self.output.endswith(suffix)
+
+ def startswith(self, prefix: str) -> bool:
+ return self.output.startswith(prefix)
+
+ def _items(self) -> List[str]:
+ return [x.strip() for x in self.output.strip().splitlines()]
+
+ def __eq__(self, expected: object) -> bool:
+ """
+ Returns True if completion contains expected items, and no others.
+
+ Defining __eq__ this way is quite ugly, but facilitates concise
+ testing code.
+ """
+ if isinstance(expected, str):
+ expiter = [expected] # type: Iterable
+ elif not isinstance(expected, Iterable):
+ return False
+ else:
+ expiter = expected
+ return self._items() == expiter
+
+ def __contains__(self, item: str) -> bool:
+ return item in self._items()
+
+ def __iter__(self) -> Iterator[str]:
+ return iter(self._items())
+
+ def __len__(self) -> int:
+ return len(self._items())
+
+ def __repr__(self) -> str:
+ return "<CompletionResult %s>" % self._items()
+
+
+def assert_complete(
+ bash: pexpect.spawn, cmd: str, **kwargs
+) -> CompletionResult:
+ skipif = kwargs.get("skipif")
+ if skipif:
+ try:
+ assert_bash_exec(bash, skipif, want_output=None)
+ except AssertionError:
+ pass
+ else:
+ pytest.skip(skipif)
+ xfail = kwargs.get("xfail")
+ if xfail:
+ try:
+ assert_bash_exec(bash, xfail, want_output=None)
+ except AssertionError:
+ pass
+ else:
+ pytest.xfail(xfail)
+ cwd = kwargs.get("cwd")
+ if cwd:
+ assert_bash_exec(bash, "cd '%s'" % cwd)
+ env_prefix = "_BASHCOMP_TEST_"
+ env = kwargs.get("env", {})
+ if env:
+ # Back up environment and apply new one
+ assert_bash_exec(
+ bash,
+ " ".join('%s%s="${%s-}"' % (env_prefix, k, k) for k in env.keys()),
+ )
+ assert_bash_exec(
+ bash,
+ "export %s" % " ".join("%s=%s" % (k, v) for k, v in env.items()),
+ )
+ try:
+ bash.send(cmd + "\t")
+ # Sleep a bit if requested, to avoid `.*` matching too early
+ time.sleep(kwargs.get("sleep_after_tab", 0))
+ bash.expect_exact(cmd)
+ bash.send(MAGIC_MARK)
+ got = bash.expect(
+ [
+ # 0: multiple lines, result in .before
+ r"\r\n" + re.escape(PS1 + cmd) + ".*" + re.escape(MAGIC_MARK),
+ # 1: no completion
+ r"^" + re.escape(MAGIC_MARK),
+ # 2: on same line, result in .match
+ r"^([^\r]+)%s$" % re.escape(MAGIC_MARK),
+ pexpect.EOF,
+ pexpect.TIMEOUT,
+ ]
+ )
+ if got == 0:
+ output = bash.before
+ if output.endswith(MAGIC_MARK):
+ output = bash.before[: -len(MAGIC_MARK)]
+ result = CompletionResult(output)
+ elif got == 2:
+ output = bash.match.group(1)
+ result = CompletionResult(output)
+ else:
+ # TODO: warn about EOF/TIMEOUT?
+ result = CompletionResult()
+ finally:
+ bash.sendintr()
+ bash.expect_exact(PS1)
+ if env:
+ # Restore environment, and clean up backup
+ # TODO: Test with declare -p if a var was set, backup only if yes, and
+ # similarly restore only backed up vars. Should remove some need
+ # for ignore_env.
+ assert_bash_exec(
+ bash,
+ "export %s"
+ % " ".join(
+ '%s="$%s%s"' % (k, env_prefix, k) for k in env.keys()
+ ),
+ )
+ assert_bash_exec(
+ bash,
+ "unset -v %s"
+ % " ".join("%s%s" % (env_prefix, k) for k in env.keys()),
+ )
+ if cwd:
+ assert_bash_exec(bash, "cd - >/dev/null")
+ return result
+
+
+@pytest.fixture
+def completion(request, bash: pexpect.spawn) -> CompletionResult:
+ marker = request.node.get_closest_marker("complete")
+ if not marker:
+ return CompletionResult()
+ for pre_cmd in marker.kwargs.get("pre_cmds", []):
+ assert_bash_exec(bash, pre_cmd)
+ cmd = getattr(request.cls, "cmd", None)
+ if marker.kwargs.get("require_longopt"):
+ # longopt completions require both command presence and that it
+ # responds something useful to --help
+ if "require_cmd" not in marker.kwargs:
+ marker.kwargs["require_cmd"] = True
+ if "xfail" not in marker.kwargs:
+ marker.kwargs["xfail"] = (
+ "! %s --help &>/dev/null || "
+ "! %s --help 2>&1 | command grep -qF -- --help"
+ ) % ((cmd,) * 2)
+ if marker.kwargs.get("require_cmd") and not is_bash_type(bash, cmd):
+ pytest.skip("Command not found")
+
+ if "trail" in marker.kwargs:
+ return assert_complete_at_point(
+ bash, cmd=marker.args[0], trail=marker.kwargs["trail"]
+ )
+
+ return assert_complete(bash, marker.args[0], **marker.kwargs)
+
+
+def assert_complete_at_point(
+ bash: pexpect.spawn, cmd: str, trail: str
+) -> CompletionResult:
+ # TODO: merge to assert_complete
+ fullcmd = "%s%s%s" % (
+ cmd,
+ trail,
+ "\002" * len(trail),
+ ) # \002 = ^B = cursor left
+ bash.send(fullcmd + "\t")
+ bash.send(MAGIC_MARK)
+ bash.expect_exact(fullcmd.replace("\002", "\b"))
+
+ got = bash.expect_exact(
+ [
+ # 0: multiple lines, result in .before
+ PS1 + fullcmd.replace("\002", "\b"),
+ # 1: no completion
+ MAGIC_MARK,
+ pexpect.EOF,
+ pexpect.TIMEOUT,
+ ]
+ )
+ if got == 0:
+ output = bash.before
+ result = CompletionResult(output)
+
+ # At this point, something weird happens. For most test setups, as
+ # expected (pun intended!), MAGIC_MARK follows as is. But for some
+ # others (e.g. CentOS 6, Ubuntu 14 test containers), we get MAGIC_MARK
+ # one character a time, followed each time by trail and the corresponding
+ # number of \b's. Don't know why, but accept it until/if someone finds out.
+ # Or just be fine with it indefinitely, the visible and practical end
+ # result on a terminal is the same anyway.
+ repeat = "(%s%s)?" % (re.escape(trail), "\b" * len(trail))
+ fullexpected = "".join(
+ "%s%s" % (re.escape(x), repeat) for x in MAGIC_MARK
+ )
+ bash.expect(fullexpected)
+ else:
+ # TODO: warn about EOF/TIMEOUT?
+ result = CompletionResult()
+
+ return result
+
+
+def in_container() -> bool:
+ try:
+ container = subprocess.check_output(
+ "virt-what || systemd-detect-virt --container",
+ stderr=subprocess.DEVNULL,
+ shell=True,
+ ).strip()
+ except subprocess.CalledProcessError:
+ container = b""
+ if container and container != b"none":
+ return True
+ if os.path.exists("/.dockerenv"):
+ return True
+ try:
+ with open("/proc/1/environ", "rb") as f:
+ # LXC, others?
+ if any(
+ x.startswith(b"container=") for x in f.readline().split(b"\0")
+ ):
+ return True
+ except OSError:
+ pass
+ return False
+
+
+class TestUnitBase:
+ def _test_unit(
+ self, func, bash, comp_words, comp_cword, comp_line, comp_point, arg=""
+ ):
+ assert_bash_exec(
+ bash,
+ "COMP_WORDS=%s COMP_CWORD=%d COMP_LINE=%s COMP_POINT=%d"
+ % (comp_words, comp_cword, shlex.quote(comp_line), comp_point),
+ )
+ output = assert_bash_exec(bash, func % arg, want_output=True)
+ return output.strip()
diff --git a/test/t/test_2to3.py b/test/t/test_2to3.py
new file mode 100644
index 0000000..4bce44e
--- /dev/null
+++ b/test/t/test_2to3.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class Test2to3:
+ @pytest.mark.complete("2to3 ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("2to3 -", require_cmd=True, require_longopt=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_7z.py b/test/t/test_7z.py
new file mode 100644
index 0000000..d4308d9
--- /dev/null
+++ b/test/t/test_7z.py
@@ -0,0 +1,33 @@
+import pytest
+
+
+class Test7z:
+ @pytest.mark.complete("7z ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("7z a ar -tzi")
+ def test_2(self, completion):
+ assert completion == "p"
+
+ @pytest.mark.complete(r"7z x -wa\ ", cwd="_filedir")
+ def test_3(self, completion):
+ assert completion == "b/"
+ assert not completion.endswith(" ")
+
+ @pytest.mark.complete("7z x ", cwd="7z")
+ def test_4(self, completion):
+ assert completion == "a.7z"
+
+ @pytest.mark.complete("7z d a.7z ", cwd="7z", require_cmd=True)
+ def test_5(self, completion):
+ assert completion == "abc"
+
+ @pytest.mark.complete("7z a -air@", cwd="7z")
+ def test_6(self, completion):
+ assert completion == sorted("-air@a.7z -air@f.txt".split())
+
+ @pytest.mark.complete("7z a -o")
+ def test_7(self, completion):
+ assert "-o7z/" in completion
+ assert all(x.endswith("/") for x in completion)
diff --git a/test/t/test_a2ps.py b/test/t/test_a2ps.py
new file mode 100644
index 0000000..38365f0
--- /dev/null
+++ b/test/t/test_a2ps.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestA2ps:
+ @pytest.mark.complete("a2ps ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("a2ps -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_a2x.py b/test/t/test_a2x.py
new file mode 100644
index 0000000..4bfb428
--- /dev/null
+++ b/test/t/test_a2x.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestA2x:
+ @pytest.mark.complete("a2x ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("a2x -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_abook.py b/test/t/test_abook.py
new file mode 100644
index 0000000..9542a4c
--- /dev/null
+++ b/test/t/test_abook.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestAbook:
+ @pytest.mark.complete("abook -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_aclocal.py b/test/t/test_aclocal.py
new file mode 100644
index 0000000..ad28b42
--- /dev/null
+++ b/test/t/test_aclocal.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestAclocal:
+ @pytest.mark.complete("aclocal ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("aclocal -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_acpi.py b/test/t/test_acpi.py
new file mode 100644
index 0000000..bd06d93
--- /dev/null
+++ b/test/t/test_acpi.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestAcpi:
+ @pytest.mark.complete("acpi -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_acroread.py b/test/t/test_acroread.py
new file mode 100644
index 0000000..22d6024
--- /dev/null
+++ b/test/t/test_acroread.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestAcroread:
+ @pytest.mark.complete("acroread ", cwd="acroread")
+ def test_1(self, completion):
+ assert completion == "foo.d/ t.pdf".split()
diff --git a/test/t/test_adb.py b/test/t/test_adb.py
new file mode 100644
index 0000000..74b0d37
--- /dev/null
+++ b/test/t/test_adb.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestAdb:
+ @pytest.mark.complete("adb ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("adb -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_add_members.py b/test/t/test_add_members.py
new file mode 100644
index 0000000..095a5de
--- /dev/null
+++ b/test/t/test_add_members.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestAddMembers:
+ @pytest.mark.complete("add_members -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_alias.py b/test/t/test_alias.py
new file mode 100644
index 0000000..cc592a8
--- /dev/null
+++ b/test/t/test_alias.py
@@ -0,0 +1,21 @@
+import pytest
+
+
+@pytest.mark.bashcomp(
+ pre_cmds=("unalias -a", "alias foo=bar", "alias bar='foo foo'"),
+ post_cmds=("unalias -a",),
+)
+class TestAlias:
+ @pytest.mark.complete("alias ")
+ def test_1(self, completion):
+ assert completion == "bar foo".split()
+
+ @pytest.mark.xfail # TODO: Would like this completion to work
+ @pytest.mark.complete("alias foo=")
+ def test_2(self, completion):
+ assert completion == "foo='bar'"
+ assert not completion.endswith(" ")
+
+ @pytest.mark.complete("alias ", trail="foo")
+ def test_alias_at_point(self, completion):
+ assert completion == "bar foo".split()
diff --git a/test/t/test_alpine.py b/test/t/test_alpine.py
new file mode 100644
index 0000000..dcc05d3
--- /dev/null
+++ b/test/t/test_alpine.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestAlpine:
+ @pytest.mark.complete("alpine -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_animate.py b/test/t/test_animate.py
new file mode 100644
index 0000000..2103606
--- /dev/null
+++ b/test/t/test_animate.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestAnimate:
+ @pytest.mark.complete("animate ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ant.py b/test/t/test_ant.py
new file mode 100644
index 0000000..94acea1
--- /dev/null
+++ b/test/t/test_ant.py
@@ -0,0 +1,35 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+@pytest.mark.bashcomp(ignore_env=r"^\+ANT_ARGS=")
+class TestAnt:
+ @pytest.mark.complete("ant -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ant ", cwd="ant")
+ def test_2(self, completion):
+ assert completion == "bashcomp clean init realclean".split()
+
+ @pytest.mark.complete("ant -f build-with-import.xml ", cwd="ant")
+ def test_3(self, completion):
+ assert completion == "build-with-import imported-build".split()
+
+ @pytest.mark.complete(
+ "ant ", cwd="ant", env=dict(ANT_ARGS="'-f named-build.xml'")
+ )
+ def test_4(self, bash, completion):
+ output = assert_bash_exec(bash, "complete -p ant", want_output=True)
+ if "complete-ant-cmd.pl" in output:
+ # Some versions of complete-ant-cmd.pl don't treat ANT_ARGS right;
+ # in those cases we get the correct completion produced by _ant
+ # plus whatever complete-ant-cmd.pl was able to get from build.xml
+ assert "named-build" in completion
+ else:
+ assert completion == "named-build"
+
+ @pytest.mark.complete("ant -l ")
+ def test_5(self, completion):
+ assert completion
diff --git a/test/t/test_apache2ctl.py b/test/t/test_apache2ctl.py
new file mode 100644
index 0000000..856a0e4
--- /dev/null
+++ b/test/t/test_apache2ctl.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestApache2ctl:
+ @pytest.mark.complete("apache2ctl ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_appdata_validate.py b/test/t/test_appdata_validate.py
new file mode 100644
index 0000000..8166cf8
--- /dev/null
+++ b/test/t/test_appdata_validate.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="appdata-validate")
+class TestAppdataValidate:
+ @pytest.mark.complete("appdata-validate ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("appdata-validate -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_apt_build.py b/test/t/test_apt_build.py
new file mode 100644
index 0000000..8346e11
--- /dev/null
+++ b/test/t/test_apt_build.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="apt-build")
+class TestAptBuild:
+ @pytest.mark.complete("apt-build ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_apt_cache.py b/test/t/test_apt_cache.py
new file mode 100644
index 0000000..f9329f2
--- /dev/null
+++ b/test/t/test_apt_cache.py
@@ -0,0 +1,17 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="apt-cache")
+class TestAptCache:
+ @pytest.mark.complete("apt-cache ")
+ def test_1(self, completion):
+ assert "search" in completion
+
+ @pytest.mark.complete("apt-cache showsrc [", require_cmd=True)
+ def test_2(self, completion):
+ # Doesn't actually fail on grep errors, but takes a long time.
+ assert not completion
+
+ @pytest.mark.complete("apt-cache ", trail=" add foo")
+ def test_special_at_point(self, completion):
+ assert not completion
diff --git a/test/t/test_apt_get.py b/test/t/test_apt_get.py
new file mode 100644
index 0000000..dc8299a
--- /dev/null
+++ b/test/t/test_apt_get.py
@@ -0,0 +1,16 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="apt-get")
+class TestAptGet:
+ @pytest.mark.complete("apt-get ")
+ def test_1(self, completion):
+ assert all(x in completion for x in "install update".split())
+
+ @pytest.mark.complete("apt-get install ./", cwd="dpkg")
+ def test_2(self, completion):
+ assert completion == "bash-completion-test-subject.deb"
+
+ @pytest.mark.complete("apt-get build-dep ")
+ def test_build_dep_dirs(self, completion):
+ assert "dpkg/" in completion
diff --git a/test/t/test_aptitude.py b/test/t/test_aptitude.py
new file mode 100644
index 0000000..29569f1
--- /dev/null
+++ b/test/t/test_aptitude.py
@@ -0,0 +1,23 @@
+import pytest
+
+
+class TestAptitude:
+ @pytest.mark.complete("aptitude ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("aptitude -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
+
+ @pytest.mark.complete("aptitude --", require_cmd=True)
+ def test_long_options(self, completion):
+ assert completion
+
+ @pytest.mark.complete("aptitude -u -")
+ def test_no_i_with_u(self, completion):
+ assert "-i" not in completion
+
+ @pytest.mark.complete("aptitude -i -")
+ def test_no_u_with_i(self, completion):
+ assert "-u" not in completion
diff --git a/test/t/test_arch.py b/test/t/test_arch.py
new file mode 100644
index 0000000..7a0f447
--- /dev/null
+++ b/test/t/test_arch.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("PATH=/usr/lib/mailman/bin:$PATH",))
+class TestArch:
+ @pytest.mark.complete("arch -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_arp.py b/test/t/test_arp.py
new file mode 100644
index 0000000..cd038bd
--- /dev/null
+++ b/test/t/test_arp.py
@@ -0,0 +1,13 @@
+import pytest
+
+
+class TestArp:
+ @pytest.mark.complete(
+ "arp ", require_cmd=True, skipif='test -z "$(arp 2>/dev/null)"'
+ )
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("arp -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_arping.py b/test/t/test_arping.py
new file mode 100644
index 0000000..0eef5c9
--- /dev/null
+++ b/test/t/test_arping.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestArping:
+ @pytest.mark.complete("arping ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("arping -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_arpspoof.py b/test/t/test_arpspoof.py
new file mode 100644
index 0000000..74c09a4
--- /dev/null
+++ b/test/t/test_arpspoof.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+class TestArpspoof:
+ @pytest.mark.complete(
+ "arpspoof -",
+ require_cmd=True,
+ # May require privileges even for outputting the usage message
+ skipif="arpspoof 2>&1 | command grep -qF libnet_open_link",
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_asciidoc.py b/test/t/test_asciidoc.py
new file mode 100644
index 0000000..b748dcd
--- /dev/null
+++ b/test/t/test_asciidoc.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestAsciidoc:
+ @pytest.mark.complete("asciidoc ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("asciidoc -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_aspell.py b/test/t/test_aspell.py
new file mode 100644
index 0000000..b7a03c4
--- /dev/null
+++ b/test/t/test_aspell.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestAspell:
+ @pytest.mark.complete("aspell ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_autoconf.py b/test/t/test_autoconf.py
new file mode 100644
index 0000000..9b98b62
--- /dev/null
+++ b/test/t/test_autoconf.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestAutoconf:
+ @pytest.mark.complete("autoconf ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_autoheader.py b/test/t/test_autoheader.py
new file mode 100644
index 0000000..57ad8af
--- /dev/null
+++ b/test/t/test_autoheader.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestAutoheader:
+ @pytest.mark.complete("autoheader ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_automake.py b/test/t/test_automake.py
new file mode 100644
index 0000000..2174e02
--- /dev/null
+++ b/test/t/test_automake.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestAutomake:
+ @pytest.mark.complete("automake ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("automake -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_autoreconf.py b/test/t/test_autoreconf.py
new file mode 100644
index 0000000..10e2a2e
--- /dev/null
+++ b/test/t/test_autoreconf.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestAutoreconf:
+ @pytest.mark.complete("autoreconf ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_autorpm.py b/test/t/test_autorpm.py
new file mode 100644
index 0000000..185585e
--- /dev/null
+++ b/test/t/test_autorpm.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestAutorpm:
+ @pytest.mark.complete("autorpm ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_autoscan.py b/test/t/test_autoscan.py
new file mode 100644
index 0000000..d3d45a1
--- /dev/null
+++ b/test/t/test_autoscan.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestAutoscan:
+ @pytest.mark.complete("autoscan ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("autoscan -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_autossh.py b/test/t/test_autossh.py
new file mode 100644
index 0000000..8640712
--- /dev/null
+++ b/test/t/test_autossh.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestAutossh:
+ @pytest.mark.complete("autossh -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_autoupdate.py b/test/t/test_autoupdate.py
new file mode 100644
index 0000000..13fd8d4
--- /dev/null
+++ b/test/t/test_autoupdate.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestAutoupdate:
+ @pytest.mark.complete("autoupdate ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_avctrl.py b/test/t/test_avctrl.py
new file mode 100644
index 0000000..6ff1ec3
--- /dev/null
+++ b/test/t/test_avctrl.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestAvctrl:
+ @pytest.mark.complete("avctrl ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_awk.py b/test/t/test_awk.py
new file mode 100644
index 0000000..9fd7380
--- /dev/null
+++ b/test/t/test_awk.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestAwk:
+ @pytest.mark.complete("awk ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("awk -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_badblocks.py b/test/t/test_badblocks.py
new file mode 100644
index 0000000..58130b3
--- /dev/null
+++ b/test/t/test_badblocks.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+class TestBadblocks:
+ @pytest.mark.complete("badblocks ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("badblocks -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+ assert all(x not in completion for x in "-w -X".split())
diff --git a/test/t/test_base64.py b/test/t/test_base64.py
new file mode 100644
index 0000000..957f5a3
--- /dev/null
+++ b/test/t/test_base64.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestBase64:
+ @pytest.mark.complete("base64 ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("base64 -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_bash.py b/test/t/test_bash.py
new file mode 100644
index 0000000..97a3b8d
--- /dev/null
+++ b/test/t/test_bash.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestBash:
+ @pytest.mark.complete("bash --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_bc.py b/test/t/test_bc.py
new file mode 100644
index 0000000..7f8056e
--- /dev/null
+++ b/test/t/test_bc.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestBc:
+ @pytest.mark.complete("bc --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_bind.py b/test/t/test_bind.py
new file mode 100644
index 0000000..97a5044
--- /dev/null
+++ b/test/t/test_bind.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestBind:
+ @pytest.mark.complete("bind -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("bind k")
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_bison.py b/test/t/test_bison.py
new file mode 100644
index 0000000..a4a481a
--- /dev/null
+++ b/test/t/test_bison.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestBison:
+ @pytest.mark.complete("bison --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_bk.py b/test/t/test_bk.py
new file mode 100644
index 0000000..8ab44b6
--- /dev/null
+++ b/test/t/test_bk.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestBk:
+ @pytest.mark.complete("bk ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_bmake.py b/test/t/test_bmake.py
new file mode 100644
index 0000000..bc885d3
--- /dev/null
+++ b/test/t/test_bmake.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestBmake:
+ @pytest.mark.complete("bmake -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_brctl.py b/test/t/test_brctl.py
new file mode 100644
index 0000000..7c773e9
--- /dev/null
+++ b/test/t/test_brctl.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestBrctl:
+ @pytest.mark.complete("brctl ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_btdownloadcurses_py.py b/test/t/test_btdownloadcurses_py.py
new file mode 100644
index 0000000..0b65519
--- /dev/null
+++ b/test/t/test_btdownloadcurses_py.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="btdownloadcurses.py")
+class TestBtdownloadcursesPy:
+ @pytest.mark.complete("btdownloadcurses.py ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_btdownloadgui_py.py b/test/t/test_btdownloadgui_py.py
new file mode 100644
index 0000000..c1b1b38
--- /dev/null
+++ b/test/t/test_btdownloadgui_py.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="btdownloadgui.py")
+class TestBtdownloadguiPy:
+ @pytest.mark.complete("btdownloadgui.py ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_btdownloadheadless_py.py b/test/t/test_btdownloadheadless_py.py
new file mode 100644
index 0000000..f84592f
--- /dev/null
+++ b/test/t/test_btdownloadheadless_py.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="btdownloadheadless.py")
+class TestBtdownloadheadlessPy:
+ @pytest.mark.complete("btdownloadheadless.py ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_bts.py b/test/t/test_bts.py
new file mode 100644
index 0000000..53dd62f
--- /dev/null
+++ b/test/t/test_bts.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestBts:
+ @pytest.mark.complete("bts ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("bts -")
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_bzip2.py b/test/t/test_bzip2.py
new file mode 100644
index 0000000..3b501ea
--- /dev/null
+++ b/test/t/test_bzip2.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestBzip2:
+ @pytest.mark.complete("bzip2 ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("bzip2 ~")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("bzip2 -")
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_cal.py b/test/t/test_cal.py
new file mode 100644
index 0000000..83d17ff
--- /dev/null
+++ b/test/t/test_cal.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestCal:
+ @pytest.mark.complete("cal ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("cal -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_cancel.py b/test/t/test_cancel.py
new file mode 100644
index 0000000..4aeafd2
--- /dev/null
+++ b/test/t/test_cancel.py
@@ -0,0 +1,34 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+class TestCancel:
+ @pytest.fixture(scope="class")
+ def added_job(self, request, bash):
+ try:
+ got = (
+ assert_bash_exec(
+ bash, "lp -H hold shared/default/foo", want_output=True
+ )
+ .strip()
+ .split()
+ )
+ except AssertionError:
+ pytest.skip("Could not add test print job")
+ return
+ if len(got) > 3:
+ request.addfinalizer(
+ lambda: assert_bash_exec(bash, "cancel %s" % got[3])
+ )
+
+ @pytest.mark.complete("cancel ")
+ def test_1(self, bash, completion, added_job):
+ got = (
+ assert_bash_exec(
+ bash, "lpstat | awk '{print $1}'", want_output=True
+ )
+ .strip()
+ .split()
+ )
+ assert completion == sorted(got)
diff --git a/test/t/test_cardctl.py b/test/t/test_cardctl.py
new file mode 100644
index 0000000..df28b6b
--- /dev/null
+++ b/test/t/test_cardctl.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCardctl:
+ @pytest.mark.complete("cardctl ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_carton.py b/test/t/test_carton.py
new file mode 100644
index 0000000..1c2e453
--- /dev/null
+++ b/test/t/test_carton.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestCarton:
+ @pytest.mark.complete("carton ", require_cmd=True)
+ def test_commands(self, completion):
+ assert all(x in completion for x in "help install".split())
+
+ @pytest.mark.complete("carton install -", require_cmd=True)
+ def test_install_options(self, completion):
+ assert all(x in completion for x in "--cached --help".split())
diff --git a/test/t/test_cat.py b/test/t/test_cat.py
new file mode 100644
index 0000000..5fa4c8f
--- /dev/null
+++ b/test/t/test_cat.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestCat:
+ @pytest.mark.complete("cat ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("cat -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_cc.py b/test/t/test_cc.py
new file mode 100644
index 0000000..12f6b2b
--- /dev/null
+++ b/test/t/test_cc.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCc:
+ @pytest.mark.complete("cc ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ccache.py b/test/t/test_ccache.py
new file mode 100644
index 0000000..ef55d0d
--- /dev/null
+++ b/test/t/test_ccache.py
@@ -0,0 +1,27 @@
+import pytest
+
+
+class TestCcache:
+ @pytest.mark.complete("ccache -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ccache --clea", require_cmd=True)
+ def test_2(self, completion):
+ assert all(x in completion for x in "--cleanup --clear".split())
+
+ @pytest.mark.complete("ccache stt")
+ def test_3(self, completion):
+ assert completion == "y" or "stty" in completion
+
+ @pytest.mark.complete("ccache --zero-stats stt")
+ def test_4(self, completion):
+ assert completion == "y" or "stty" in completion
+
+ @pytest.mark.complete("ccache --hel", require_cmd=True)
+ def test_5(self, completion):
+ assert completion == "p" or "--help" in completion
+
+ @pytest.mark.complete("ccache --zero-stats sh +")
+ def test_6(self, completion):
+ assert "+x" in completion
diff --git a/test/t/test_ccze.py b/test/t/test_ccze.py
new file mode 100644
index 0000000..abf1234
--- /dev/null
+++ b/test/t/test_ccze.py
@@ -0,0 +1,19 @@
+import pytest
+
+
+class TestCcze:
+ @pytest.mark.complete("ccze ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ccze -? ")
+ def test_2(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("ccze -o ")
+ def test_3(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ccze --plugin=", require_cmd=True)
+ def test_4(self, completion):
+ assert completion
diff --git a/test/t/test_cd.py b/test/t/test_cd.py
new file mode 100644
index 0000000..5b7789a
--- /dev/null
+++ b/test/t/test_cd.py
@@ -0,0 +1,26 @@
+import pytest
+
+
+@pytest.mark.bashcomp(ignore_env=r"^\+CDPATH=$")
+class TestCd:
+ @pytest.mark.complete("cd shared/default/")
+ def test_1(self, completion):
+ assert completion == ["bar bar.d/", "foo.d/"]
+
+ @pytest.mark.complete("cd fo", env=dict(CDPATH="shared/default"))
+ def test_2(self, completion):
+ assert completion == "o.d/"
+
+ @pytest.mark.complete("cd fo")
+ def test_3(self, completion):
+ assert not completion
+
+ @pytest.mark.complete(
+ "cd ", cwd="shared/default/foo.d", env=dict(CDPATH="")
+ )
+ def test_4(self, completion):
+ assert not completion # No subdirs nor CDPATH
+
+ @pytest.mark.complete("cd shared/default/", trail="foo")
+ def test_dir_at_point(self, completion):
+ assert completion == ["bar bar.d/", "foo.d/"]
diff --git a/test/t/test_cdrecord.py b/test/t/test_cdrecord.py
new file mode 100644
index 0000000..d9d2da1
--- /dev/null
+++ b/test/t/test_cdrecord.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCdrecord:
+ @pytest.mark.complete("cdrecord -d")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_cfagent.py b/test/t/test_cfagent.py
new file mode 100644
index 0000000..990fc62
--- /dev/null
+++ b/test/t/test_cfagent.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCfagent:
+ @pytest.mark.complete("cfagent -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_cfrun.py b/test/t/test_cfrun.py
new file mode 100644
index 0000000..a647d76
--- /dev/null
+++ b/test/t/test_cfrun.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCfrun:
+ @pytest.mark.complete("cfrun -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_chage.py b/test/t/test_chage.py
new file mode 100644
index 0000000..3957ae3
--- /dev/null
+++ b/test/t/test_chage.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestChage:
+ @pytest.mark.complete("chage ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("chage -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_change_pw.py b/test/t/test_change_pw.py
new file mode 100644
index 0000000..69909af
--- /dev/null
+++ b/test/t/test_change_pw.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("PATH=/usr/lib/mailman/bin:$PATH",))
+class TestChangePw:
+ @pytest.mark.complete("change_pw -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_check_db.py b/test/t/test_check_db.py
new file mode 100644
index 0000000..a9f4844
--- /dev/null
+++ b/test/t/test_check_db.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCheckDb:
+ @pytest.mark.complete("check_db -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_check_perms.py b/test/t/test_check_perms.py
new file mode 100644
index 0000000..813ae4c
--- /dev/null
+++ b/test/t/test_check_perms.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCheckPerms:
+ @pytest.mark.complete("check_perms -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_checksec.py b/test/t/test_checksec.py
new file mode 100644
index 0000000..5a11037
--- /dev/null
+++ b/test/t/test_checksec.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestChecksec:
+ @pytest.mark.complete("checksec -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_chfn.py b/test/t/test_chfn.py
new file mode 100644
index 0000000..ca719b8
--- /dev/null
+++ b/test/t/test_chfn.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestChfn:
+ @pytest.mark.complete("chfn ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_chgrp.py b/test/t/test_chgrp.py
new file mode 100644
index 0000000..87a583e
--- /dev/null
+++ b/test/t/test_chgrp.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestChgrp:
+ @pytest.mark.complete("chgrp ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_chkconfig.py b/test/t/test_chkconfig.py
new file mode 100644
index 0000000..08e9827
--- /dev/null
+++ b/test/t/test_chkconfig.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestChkconfig:
+ @pytest.mark.complete("chkconfig -")
+ def test_1(self, completion):
+ assert completion
+
+ # systemd may not be running e.g. in a docker container, and listing
+ # services will then fail.
+ @pytest.mark.complete(
+ "chkconfig ", xfail="! systemctl list-units &>/dev/null"
+ )
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_chmod.py b/test/t/test_chmod.py
new file mode 100644
index 0000000..3838b55
--- /dev/null
+++ b/test/t/test_chmod.py
@@ -0,0 +1,25 @@
+import pytest
+
+
+class TestChmod:
+
+ # No completion here until mode completion is implemented
+ @pytest.mark.complete("chmod ")
+ def test_1(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("chmod 755 ")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("chmod -", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
+
+ @pytest.mark.complete("chmod -x ")
+ def test_4(self, completion):
+ assert completion
+
+ @pytest.mark.complete("chmod -77 ")
+ def test_5(self, completion):
+ assert completion
diff --git a/test/t/test_chown.py b/test/t/test_chown.py
new file mode 100644
index 0000000..9643f3e
--- /dev/null
+++ b/test/t/test_chown.py
@@ -0,0 +1,82 @@
+import getpass
+
+import pytest
+
+from conftest import assert_complete
+
+
+@pytest.mark.bashcomp(
+ pre_cmds=(
+ # Fake root command to get all users/groups completed at least for now
+ "root_command=sudo",
+ )
+)
+class TestChown:
+ @pytest.mark.xfail(
+ getpass.getuser() != "root", reason="Only root can chown to all users"
+ )
+ @pytest.mark.complete("chown ")
+ def test_1(self, bash, completion, output_sort_uniq):
+ users = output_sort_uniq("compgen -u")
+ assert completion == users
+
+ @pytest.mark.complete("chown foo: shared/default/")
+ def test_2(self, completion):
+ assert completion == ["bar", "bar bar.d/", "foo", "foo.d/"]
+
+ @pytest.mark.complete("chown :foo shared/default/")
+ def test_3(self, completion):
+ assert completion == ["bar", "bar bar.d/", "foo", "foo.d/"]
+
+ def test_4(self, bash, part_full_user):
+ part, full = part_full_user
+ completion = assert_complete(bash, "chown %s" % part)
+ assert completion == full[len(part) :]
+ assert completion.endswith(" ")
+
+ def test_5(self, bash, part_full_user, part_full_group):
+ _, user = part_full_user
+ partgroup, fullgroup = part_full_group
+ completion = assert_complete(bash, "chown %s:%s" % (user, partgroup))
+ assert completion == fullgroup[len(partgroup) :]
+ assert completion.output.endswith(" ")
+
+ def test_6(self, bash, part_full_group):
+ part, full = part_full_group
+ completion = assert_complete(bash, "chown dot.user:%s" % part)
+ assert completion == full[len(part) :]
+ assert completion.output.endswith(" ")
+
+ @pytest.mark.parametrize(
+ "prefix",
+ [
+ r"funky\ user:",
+ "funky.user:",
+ r"funky\.user:",
+ r"fu\ nky.user:",
+ r"f\ o\ o\.\bar:",
+ r"foo\_b\ a\.r\ :",
+ ],
+ )
+ def test_7(self, bash, part_full_group, prefix):
+ """Test preserving special chars in $prefix$partgroup<TAB>."""
+ part, full = part_full_group
+ completion = assert_complete(bash, "chown %s%s" % (prefix, part))
+ assert completion == full[len(part) :]
+ assert completion.output.endswith(" ")
+
+ def test_8(self, bash, part_full_user, part_full_group):
+ """Test giving up on degenerate cases instead of spewing junk."""
+ _, user = part_full_user
+ partgroup, _ = part_full_group
+ for x in range(2, 5):
+ completion = assert_complete(
+ bash, "chown %s%s:%s" % (user, x * "\\", partgroup)
+ )
+ assert not completion
+
+ def test_9(self, bash, part_full_group):
+ """Test graceful fail on colon in user/group name."""
+ part, _ = part_full_group
+ completion = assert_complete(bash, "chown foo:bar:%s" % part)
+ assert not completion
diff --git a/test/t/test_chpasswd.py b/test/t/test_chpasswd.py
new file mode 100644
index 0000000..ebb292f
--- /dev/null
+++ b/test/t/test_chpasswd.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestChpasswd:
+ @pytest.mark.complete("chpasswd -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_chromium_browser.py b/test/t/test_chromium_browser.py
new file mode 100644
index 0000000..b0b19b2
--- /dev/null
+++ b/test/t/test_chromium_browser.py
@@ -0,0 +1,25 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="chromium-browser")
+class TestChromiumBrowser:
+ @pytest.mark.complete("chromium-browser ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "chromium-browser -", xfail="! chromium-browser --help &>/dev/null"
+ )
+ def test_2(self, completion):
+ assert completion
+ assert not completion.endswith(" ")
+
+ @pytest.mark.complete("chromium-browser --proxy-server=")
+ def test_proxy_server_scheme(self, completion):
+ assert completion
+ assert not completion.endswith(" ")
+ assert all(x.endswith("://") for x in completion)
+
+ @pytest.mark.complete("chromium-browser --proxy-server=http://")
+ def test_proxy_server_host(self, completion):
+ assert completion
diff --git a/test/t/test_chronyc.py b/test/t/test_chronyc.py
new file mode 100644
index 0000000..1fee246
--- /dev/null
+++ b/test/t/test_chronyc.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestChronyc:
+ @pytest.mark.complete("chronyc ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("chronyc -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_chroot.py b/test/t/test_chroot.py
new file mode 100644
index 0000000..08ace86
--- /dev/null
+++ b/test/t/test_chroot.py
@@ -0,0 +1,16 @@
+import pytest
+
+
+class TestChroot:
+ @pytest.mark.complete("chroot ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("/bin/chroot shared/default/")
+ def test_2(self, completion):
+ """Should complete dirs only, also when invoked using full path."""
+ assert completion == ["bar bar.d/", "foo.d/"]
+
+ @pytest.mark.complete("chroot -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_chrpath.py b/test/t/test_chrpath.py
new file mode 100644
index 0000000..8e94dcb
--- /dev/null
+++ b/test/t/test_chrpath.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestChrpath:
+ @pytest.mark.complete("chrpath ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("chrpath -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_chsh.py b/test/t/test_chsh.py
new file mode 100644
index 0000000..fe1c7f6
--- /dev/null
+++ b/test/t/test_chsh.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestChsh:
+ @pytest.mark.complete("chsh ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("chsh -s ")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("chsh -", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_ci.py b/test/t/test_ci.py
new file mode 100644
index 0000000..f941b2c
--- /dev/null
+++ b/test/t/test_ci.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCi:
+ @pytest.mark.complete("ci ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ciptool.py b/test/t/test_ciptool.py
new file mode 100644
index 0000000..0ff5444
--- /dev/null
+++ b/test/t/test_ciptool.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCiptool:
+ @pytest.mark.complete("ciptool ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_civclient.py b/test/t/test_civclient.py
new file mode 100644
index 0000000..bf0c8d8
--- /dev/null
+++ b/test/t/test_civclient.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCivclient:
+ @pytest.mark.complete("civclient -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_civserver.py b/test/t/test_civserver.py
new file mode 100644
index 0000000..0b8e5d5
--- /dev/null
+++ b/test/t/test_civserver.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCivserver:
+ @pytest.mark.complete("civserver -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_cksfv.py b/test/t/test_cksfv.py
new file mode 100644
index 0000000..b365659
--- /dev/null
+++ b/test/t/test_cksfv.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCksfv:
+ @pytest.mark.complete("cksfv -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_cleanarch.py b/test/t/test_cleanarch.py
new file mode 100644
index 0000000..95b268e
--- /dev/null
+++ b/test/t/test_cleanarch.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("PATH=/usr/lib/mailman/bin:$PATH",))
+class TestCleanarch:
+ @pytest.mark.complete("cleanarch -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_clisp.py b/test/t/test_clisp.py
new file mode 100644
index 0000000..3fcb259
--- /dev/null
+++ b/test/t/test_clisp.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestClisp:
+ @pytest.mark.complete("clisp ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_clone_member.py b/test/t/test_clone_member.py
new file mode 100644
index 0000000..8f54298
--- /dev/null
+++ b/test/t/test_clone_member.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCloneMember:
+ @pytest.mark.complete("clone_member -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_co.py b/test/t/test_co.py
new file mode 100644
index 0000000..0404b45
--- /dev/null
+++ b/test/t/test_co.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCo:
+ @pytest.mark.complete("co ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_colordiff.py b/test/t/test_colordiff.py
new file mode 100644
index 0000000..f0e0a29
--- /dev/null
+++ b/test/t/test_colordiff.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestColordiff:
+ @pytest.mark.complete("colordiff ")
+ def test_basic(self, completion):
+ assert completion
+
+ @pytest.mark.complete("colordiff -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_compare.py b/test/t/test_compare.py
new file mode 100644
index 0000000..172c8da
--- /dev/null
+++ b/test/t/test_compare.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCompare:
+ @pytest.mark.complete("compare ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_compgen.py b/test/t/test_compgen.py
new file mode 100644
index 0000000..893abdf
--- /dev/null
+++ b/test/t/test_compgen.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCompgen:
+ @pytest.mark.complete(r"compgen -f a\'b/", cwd="compgen")
+ def test_1(self, completion):
+ assert not completion
diff --git a/test/t/test_complete.py b/test/t/test_complete.py
new file mode 100644
index 0000000..7ff56b4
--- /dev/null
+++ b/test/t/test_complete.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestComplete:
+ @pytest.mark.complete("complete -")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(r"\complete -")
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_composite.py b/test/t/test_composite.py
new file mode 100644
index 0000000..58f4e39
--- /dev/null
+++ b/test/t/test_composite.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestComposite:
+ @pytest.mark.complete("composite ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_config_list.py b/test/t/test_config_list.py
new file mode 100644
index 0000000..d17fadc
--- /dev/null
+++ b/test/t/test_config_list.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestConfigList:
+ @pytest.mark.complete("config_list -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_configure.py b/test/t/test_configure.py
new file mode 100644
index 0000000..0fc6117
--- /dev/null
+++ b/test/t/test_configure.py
@@ -0,0 +1,17 @@
+import pytest
+
+
+@pytest.mark.bashcomp(
+ pre_cmds=(
+ # Make sure our own ./configure is in PATH
+ "PATH=$PWD/../..:$PATH",
+ )
+)
+class TestConfigure:
+ @pytest.mark.complete("configure --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("configure --prefix ")
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_conjure.py b/test/t/test_conjure.py
new file mode 100644
index 0000000..3dcc0db
--- /dev/null
+++ b/test/t/test_conjure.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestConjure:
+ @pytest.mark.complete("conjure ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_convert.py b/test/t/test_convert.py
new file mode 100644
index 0000000..c903ea0
--- /dev/null
+++ b/test/t/test_convert.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestConvert:
+ @pytest.mark.complete("convert ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("convert -format ")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("convert -", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_cowsay.py b/test/t/test_cowsay.py
new file mode 100644
index 0000000..2920d9e
--- /dev/null
+++ b/test/t/test_cowsay.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestCowsay:
+ @pytest.mark.complete("cowsay ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_cp.py b/test/t/test_cp.py
new file mode 100644
index 0000000..7634df7
--- /dev/null
+++ b/test/t/test_cp.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestCp:
+ @pytest.mark.complete("cp ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("cp -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_cpan2dist.py b/test/t/test_cpan2dist.py
new file mode 100644
index 0000000..1ab5de1
--- /dev/null
+++ b/test/t/test_cpan2dist.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestCpan2dist:
+ @pytest.mark.complete(
+ "cpan2dist -", require_cmd=True, require_longopt=True
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_cpio.py b/test/t/test_cpio.py
new file mode 100644
index 0000000..0b73966
--- /dev/null
+++ b/test/t/test_cpio.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+class TestCpio:
+ @pytest.mark.complete("cpio --")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("cpio -R ")
+ def test_2(self, bash, completion, output_sort_uniq):
+ users = output_sort_uniq("compgen -u")
+ assert completion == users
diff --git a/test/t/test_cplusplus.py b/test/t/test_cplusplus.py
new file mode 100644
index 0000000..a2dd3ed
--- /dev/null
+++ b/test/t/test_cplusplus.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="c++")
+class TestCPlusPlus:
+ @pytest.mark.complete("c++ ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_cppcheck.py b/test/t/test_cppcheck.py
new file mode 100644
index 0000000..73e64f5
--- /dev/null
+++ b/test/t/test_cppcheck.py
@@ -0,0 +1,31 @@
+import pytest
+
+
+class TestCppcheck:
+ @pytest.mark.complete("cppcheck ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("cppcheck -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("cppcheck -DFOO=BAR ")
+ def test_3(self, completion):
+ assert completion
+
+ @pytest.mark.complete("cppcheck -D ")
+ def test_4(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("cppcheck --enable=al")
+ def test_5(self, completion):
+ assert completion == "l"
+
+ @pytest.mark.complete("cppcheck --enable=xx,styl")
+ def test_6(self, completion):
+ assert completion == "e"
+
+ @pytest.mark.complete("cppcheck --enable=xx,yy,styl")
+ def test_7(self, completion):
+ assert completion == "e"
diff --git a/test/t/test_createdb.py b/test/t/test_createdb.py
new file mode 100644
index 0000000..030338a
--- /dev/null
+++ b/test/t/test_createdb.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestCreatedb:
+
+ # --help can fail due to missing package dependencies, e.g. on Ubuntu 14
+ @pytest.mark.complete(
+ "createdb -", require_cmd=True, xfail="! createdb --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_createuser.py b/test/t/test_createuser.py
new file mode 100644
index 0000000..ea8d0e3
--- /dev/null
+++ b/test/t/test_createuser.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestCreateuser:
+
+ # --help can fail due to missing package dependencies, e.g. on Ubuntu 14
+ @pytest.mark.complete(
+ "createuser -", xfail="! createuser --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_crontab.py b/test/t/test_crontab.py
new file mode 100644
index 0000000..a476694
--- /dev/null
+++ b/test/t/test_crontab.py
@@ -0,0 +1,16 @@
+import pytest
+
+
+class TestCrontab:
+ @pytest.mark.complete("crontab ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("crontab -l -")
+ def test_only_u_with_l(self, completion):
+ assert completion == "u"
+
+ @pytest.mark.complete("crontab -r -")
+ def test_no_l_with_r(self, completion):
+ assert completion
+ assert "-l" not in completion
diff --git a/test/t/test_cryptsetup.py b/test/t/test_cryptsetup.py
new file mode 100644
index 0000000..fdc981b
--- /dev/null
+++ b/test/t/test_cryptsetup.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestCryptsetup:
+ @pytest.mark.complete("cryptsetup ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("cryptsetup -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_csplit.py b/test/t/test_csplit.py
new file mode 100644
index 0000000..609c7e5
--- /dev/null
+++ b/test/t/test_csplit.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestCsplit:
+ @pytest.mark.complete("csplit ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("csplit -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_curl.py b/test/t/test_curl.py
new file mode 100644
index 0000000..63e969f
--- /dev/null
+++ b/test/t/test_curl.py
@@ -0,0 +1,28 @@
+import pytest
+
+
+class TestCurl:
+ @pytest.mark.complete("curl --h", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("curl -o f", cwd="shared/default/foo.d")
+ def test_2(self, completion):
+ assert completion == "oo"
+
+ @pytest.mark.complete("curl -LRo f", cwd="shared/default/foo.d")
+ def test_3(self, completion):
+ assert completion == "oo"
+
+ @pytest.mark.complete("curl --o f")
+ def test_4(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("curl --data @", cwd="shared/default/foo.d")
+ def test_data_atfile(self, completion):
+ assert completion == "foo"
+
+ @pytest.mark.complete("curl --data @foo.", cwd="shared/default")
+ def test_data_atfile_dir(self, completion):
+ assert completion == "d/"
+ assert not completion.endswith(" ")
diff --git a/test/t/test_cut.py b/test/t/test_cut.py
new file mode 100644
index 0000000..b0faca6
--- /dev/null
+++ b/test/t/test_cut.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestCut:
+ @pytest.mark.complete("cut ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("cut -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_cvs.py b/test/t/test_cvs.py
new file mode 100644
index 0000000..97361e9
--- /dev/null
+++ b/test/t/test_cvs.py
@@ -0,0 +1,20 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("HOME=$PWD/cvs",))
+class TestCvs:
+ @pytest.mark.complete("cvs ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("cvs -d ")
+ def test_2(self, completion):
+ assert [x for x in completion if ":pserver:" in x]
+
+ @pytest.mark.complete("cvs diff foo/", cwd="cvs")
+ def test_3(self, completion):
+ assert completion == "bar"
+
+ @pytest.mark.complete("cvs -", require_cmd=True)
+ def test_4(self, completion):
+ assert completion
diff --git a/test/t/test_cvsps.py b/test/t/test_cvsps.py
new file mode 100644
index 0000000..4039893
--- /dev/null
+++ b/test/t/test_cvsps.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("HOME=$PWD/cvs",))
+class TestCvsps:
+ @pytest.mark.complete("cvsps -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("cvsps ")
+ def test_2(self, completion):
+ assert [x for x in completion if ":pserver:" in x]
diff --git a/test/t/test_date.py b/test/t/test_date.py
new file mode 100644
index 0000000..57d61b8
--- /dev/null
+++ b/test/t/test_date.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestDate:
+ @pytest.mark.complete("date ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("date -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_dcop.py b/test/t/test_dcop.py
new file mode 100644
index 0000000..5c3c04d
--- /dev/null
+++ b/test/t/test_dcop.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestDcop:
+ @pytest.mark.complete("dcop ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_dd.py b/test/t/test_dd.py
new file mode 100644
index 0000000..e082faa
--- /dev/null
+++ b/test/t/test_dd.py
@@ -0,0 +1,17 @@
+import pytest
+
+
+class TestDd:
+ @pytest.mark.complete(
+ "dd --",
+ xfail=(
+ "! dd --help &>/dev/null || "
+ "! dd --help 2>&1 | command grep -qF -- --help"
+ ),
+ )
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("dd bs")
+ def test_2(self, completion):
+ assert completion == "="
diff --git a/test/t/test_declare.py b/test/t/test_declare.py
new file mode 100644
index 0000000..a61d926
--- /dev/null
+++ b/test/t/test_declare.py
@@ -0,0 +1,20 @@
+import pytest
+
+
+class TestDeclare:
+ @pytest.mark.complete("declare -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("declare +", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("declare -p BASH_ARG")
+ def test_3(self, completion):
+ # bash 5.0 has BASH_ARGV0 too
+ assert all(x in completion for x in "BASH_ARGC BASH_ARGV".split())
+
+ @pytest.mark.complete("declare -f _parse_")
+ def test_4(self, completion):
+ assert "_parse_help" in completion
diff --git a/test/t/test_deja_dup.py b/test/t/test_deja_dup.py
new file mode 100644
index 0000000..56e59f9
--- /dev/null
+++ b/test/t/test_deja_dup.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="deja-dup")
+class TestDejaDup:
+ @pytest.mark.complete("deja-dup -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("deja-dup --help ")
+ def test_2(self, completion):
+ assert not completion
diff --git a/test/t/test_desktop_file_validate.py b/test/t/test_desktop_file_validate.py
new file mode 100644
index 0000000..ed4b55b
--- /dev/null
+++ b/test/t/test_desktop_file_validate.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="desktop-file-validate")
+class TestDesktopFileValidate:
+ @pytest.mark.complete("desktop-file-validate ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("desktop-file-validate -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_df.py b/test/t/test_df.py
new file mode 100644
index 0000000..be28e6c
--- /dev/null
+++ b/test/t/test_df.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestDf:
+ @pytest.mark.complete("df ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("df -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_dfutool.py b/test/t/test_dfutool.py
new file mode 100644
index 0000000..7b450bd
--- /dev/null
+++ b/test/t/test_dfutool.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestDfutool:
+ @pytest.mark.complete("dfutool ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_dhclient.py b/test/t/test_dhclient.py
new file mode 100644
index 0000000..c6a1af4
--- /dev/null
+++ b/test/t/test_dhclient.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestDhclient:
+ @pytest.mark.complete("dhclient -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_dict.py b/test/t/test_dict.py
new file mode 100644
index 0000000..99c4a21
--- /dev/null
+++ b/test/t/test_dict.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestDict:
+ @pytest.mark.complete("dict -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_diff.py b/test/t/test_diff.py
new file mode 100644
index 0000000..eb81506
--- /dev/null
+++ b/test/t/test_diff.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestDiff:
+ @pytest.mark.complete("diff --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_dir.py b/test/t/test_dir.py
new file mode 100644
index 0000000..f8568fb
--- /dev/null
+++ b/test/t/test_dir.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestDir:
+ @pytest.mark.complete("dir ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("dir -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_display.py b/test/t/test_display.py
new file mode 100644
index 0000000..4f076b8
--- /dev/null
+++ b/test/t/test_display.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestDisplay:
+ @pytest.mark.complete("display ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("display -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_dmesg.py b/test/t/test_dmesg.py
new file mode 100644
index 0000000..a081fb6
--- /dev/null
+++ b/test/t/test_dmesg.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestDmesg:
+ @pytest.mark.complete("dmesg -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_dmypy.py b/test/t/test_dmypy.py
new file mode 100644
index 0000000..4c031dd
--- /dev/null
+++ b/test/t/test_dmypy.py
@@ -0,0 +1,14 @@
+import pytest
+
+
+class TestDmypy:
+ @pytest.mark.complete(
+ "dmypy ", require_cmd=True, xfail="! dmypy --help &>/dev/null"
+ )
+ def test_commands(self, completion):
+ assert "help" in completion
+ assert not any("," in x for x in completion)
+
+ @pytest.mark.complete("dmypy -", require_cmd=True, require_longopt=True)
+ def test_options(self, completion):
+ assert "--help" in completion
diff --git a/test/t/test_dnssec_keygen.py b/test/t/test_dnssec_keygen.py
new file mode 100644
index 0000000..f8bd6fb
--- /dev/null
+++ b/test/t/test_dnssec_keygen.py
@@ -0,0 +1,80 @@
+import pytest
+
+
+@pytest.mark.bashcomp(
+ cmd="dnssec-keygen", pre_cmds=("PATH=$PATH:$PWD/dnssec-keygen",)
+)
+class TestDnssecKeygen:
+ @pytest.mark.complete("dnssec-keygen -")
+ def test_1(self, completion):
+ assert completion
+ assert not any(x.endswith(":") for x in completion)
+
+ @pytest.mark.complete("dnssec-keygen -a ")
+ def test_2(self, completion):
+ assert completion
+ assert any(x in completion for x in ("HMAC-MD5", "RSASHA1", "ED25519"))
+ assert "|" not in completion
+ assert not any(x.startswith("-") for x in completion)
+
+ @pytest.mark.complete("dnssec-keygen -n ")
+ def test_3(self, completion):
+ assert completion
+ assert "HOST" in completion
+ assert "|" not in completion
+ assert not any(x.startswith("-") for x in completion)
+
+ @pytest.mark.complete("dnssec-keygen -f ")
+ def test_4(self, completion):
+ assert completion
+ assert "|" not in completion
+ assert not any(x.startswith("-") for x in completion)
+
+ @pytest.mark.complete("dnssec-keygen ")
+ def test_5(self, completion):
+ assert not completion
+
+ @pytest.mark.complete(
+ "dnssec-keygen -a ", env=dict(PATH="$PWD/dnssec-keygen:$PATH")
+ )
+ def test_6(self, completion):
+ assert completion == sorted(
+ "RSA RSAMD5 DSA RSASHA1 NSEC3RSASHA1 NSEC3DSA "
+ "RSASHA256 RSASHA512 ECCGOST "
+ "ECDSAP256SHA256 ECDSAP384SHA384 "
+ "ED25519 ED448 DH "
+ "HMAC-MD5 HMAC-SHA1 HMAC-SHA224 HMAC-SHA256 "
+ "HMAC-SHA384 HMAC-SHA512".split()
+ )
+
+ @pytest.mark.complete(
+ "dnssec-keygen -n ", env=dict(PATH="$PWD/dnssec-keygen:$PATH")
+ )
+ def test_7(self, completion):
+ assert completion == sorted("ZONE HOST ENTITY USER OTHER".split())
+
+ @pytest.mark.complete(
+ "dnssec-keygen -f ", env=dict(PATH="$PWD/dnssec-keygen:$PATH")
+ )
+ def test_8(self, completion):
+ assert completion == sorted("KSK REVOKE".split())
+
+ @pytest.mark.complete(
+ "dnssec-keygen -T ", env=dict(PATH="$PWD/dnssec-keygen:$PATH")
+ )
+ def test_9(self, completion):
+ assert completion == sorted("DNSKEY KEY".split())
+
+ @pytest.mark.complete(
+ "dnssec-keygen -t ", env=dict(PATH="$PWD/dnssec-keygen:$PATH")
+ )
+ def test_10(self, completion):
+ assert completion == sorted(
+ "AUTHCONF NOAUTHCONF NOAUTH NOCONF".split()
+ )
+
+ @pytest.mark.complete(
+ "dnssec-keygen -m ", env=dict(PATH="$PWD/dnssec-keygen:$PATH")
+ )
+ def test_11(self, completion):
+ assert completion == sorted("usage trace record size mctx".split())
diff --git a/test/t/test_dnsspoof.py b/test/t/test_dnsspoof.py
new file mode 100644
index 0000000..b3380d1
--- /dev/null
+++ b/test/t/test_dnsspoof.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestDnsspoof:
+ @pytest.mark.complete("dnsspoof -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_dot.py b/test/t/test_dot.py
new file mode 100644
index 0000000..a4aa674
--- /dev/null
+++ b/test/t/test_dot.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestDot:
+ @pytest.mark.complete("dot ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_dpkg.py b/test/t/test_dpkg.py
new file mode 100644
index 0000000..eb1228b
--- /dev/null
+++ b/test/t/test_dpkg.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestDpkg:
+ @pytest.mark.complete("dpkg --c", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("dpkg -L ", xfail='test -z "$(dpkg -l 2>/dev/null)"')
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("dpkg -i ~")
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_dpkg_deb.py b/test/t/test_dpkg_deb.py
new file mode 100644
index 0000000..9be85eb
--- /dev/null
+++ b/test/t/test_dpkg_deb.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="dpkg-deb")
+class TestDpkgDeb:
+ @pytest.mark.complete("dpkg-deb --c", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("dpkg-deb --show b", cwd="dpkg")
+ def test_show(self, completion):
+ assert completion == "ash-completion-test-subject.deb"
diff --git a/test/t/test_dpkg_query.py b/test/t/test_dpkg_query.py
new file mode 100644
index 0000000..37c5621
--- /dev/null
+++ b/test/t/test_dpkg_query.py
@@ -0,0 +1,18 @@
+import os.path
+
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="dpkg-query",)
+class TestDpkgQuery:
+ @pytest.mark.complete("dpkg-query --", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
+
+ @pytest.mark.xfail(
+ not os.path.exists("/etc/debian_version"),
+ reason="Likely fails on systems not based on Debian",
+ )
+ @pytest.mark.complete("dpkg-query -W dpk", require_cmd=True)
+ def test_show(self, completion):
+ assert "dpkg" in completion
diff --git a/test/t/test_dpkg_reconfigure.py b/test/t/test_dpkg_reconfigure.py
new file mode 100644
index 0000000..46347b3
--- /dev/null
+++ b/test/t/test_dpkg_reconfigure.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="dpkg-reconfigure")
+class TestDpkgReconfigure:
+ @pytest.mark.complete("dpkg-reconfigure --")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_dpkg_source.py b/test/t/test_dpkg_source.py
new file mode 100644
index 0000000..f2d5f19
--- /dev/null
+++ b/test/t/test_dpkg_source.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="dpkg-source")
+class TestDpkgSource:
+ @pytest.mark.complete("dpkg-source -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_dropdb.py b/test/t/test_dropdb.py
new file mode 100644
index 0000000..2f65857
--- /dev/null
+++ b/test/t/test_dropdb.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestDropdb:
+
+ # --help can fail due to missing package dependencies, e.g. on Ubuntu 14
+ @pytest.mark.complete(
+ "dropdb -", require_cmd=True, xfail="! dropdb --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_dropuser.py b/test/t/test_dropuser.py
new file mode 100644
index 0000000..83a99d9
--- /dev/null
+++ b/test/t/test_dropuser.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestDropuser:
+ @pytest.mark.complete("dropuser ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_dselect.py b/test/t/test_dselect.py
new file mode 100644
index 0000000..8e9d24e
--- /dev/null
+++ b/test/t/test_dselect.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestDselect:
+ @pytest.mark.complete("dselect ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("dselect -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_dsniff.py b/test/t/test_dsniff.py
new file mode 100644
index 0000000..978c436
--- /dev/null
+++ b/test/t/test_dsniff.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestDsniff:
+ @pytest.mark.complete("dsniff -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_du.py b/test/t/test_du.py
new file mode 100644
index 0000000..3d73e99
--- /dev/null
+++ b/test/t/test_du.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestDu:
+ @pytest.mark.complete("du ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("du -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_dumpdb.py b/test/t/test_dumpdb.py
new file mode 100644
index 0000000..5077682
--- /dev/null
+++ b/test/t/test_dumpdb.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("PATH=/usr/lib/mailman/bin:$PATH",))
+class TestDumpdb:
+ @pytest.mark.complete("dumpdb ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_dumpe2fs.py b/test/t/test_dumpe2fs.py
new file mode 100644
index 0000000..eacb1fe
--- /dev/null
+++ b/test/t/test_dumpe2fs.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestDumpe2fs:
+ @pytest.mark.complete("dumpe2fs ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("dumpe2fs -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_e2freefrag.py b/test/t/test_e2freefrag.py
new file mode 100644
index 0000000..10eb41d
--- /dev/null
+++ b/test/t/test_e2freefrag.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestE2freefrag:
+ @pytest.mark.complete("e2freefrag ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("e2freefrag -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_e2label.py b/test/t/test_e2label.py
new file mode 100644
index 0000000..ca436a6
--- /dev/null
+++ b/test/t/test_e2label.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestE2label:
+ @pytest.mark.complete("e2label ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ebtables.py b/test/t/test_ebtables.py
new file mode 100644
index 0000000..bcca3cb
--- /dev/null
+++ b/test/t/test_ebtables.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestEbtables:
+ @pytest.mark.complete("ebtables -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ecryptfs_migrate_home.py b/test/t/test_ecryptfs_migrate_home.py
new file mode 100644
index 0000000..f2115d2
--- /dev/null
+++ b/test/t/test_ecryptfs_migrate_home.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="ecryptfs-migrate-home")
+class TestEcryptfsMigrateHome:
+ @pytest.mark.complete("ecryptfs-migrate-home ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ecryptfs-migrate-home -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_eject.py b/test/t/test_eject.py
new file mode 100644
index 0000000..d4ec1bd
--- /dev/null
+++ b/test/t/test_eject.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestEject:
+ @pytest.mark.complete("eject -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_enscript.py b/test/t/test_enscript.py
new file mode 100644
index 0000000..97120e3
--- /dev/null
+++ b/test/t/test_enscript.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestEnscript:
+ @pytest.mark.complete("enscript --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_env.py b/test/t/test_env.py
new file mode 100644
index 0000000..3d1a684
--- /dev/null
+++ b/test/t/test_env.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestEnv:
+ @pytest.mark.complete("env --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_eog.py b/test/t/test_eog.py
new file mode 100644
index 0000000..5ae21d9
--- /dev/null
+++ b/test/t/test_eog.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestEog:
+ @pytest.mark.complete("eog ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("eog -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_ether_wake.py b/test/t/test_ether_wake.py
new file mode 100644
index 0000000..7afe286
--- /dev/null
+++ b/test/t/test_ether_wake.py
@@ -0,0 +1,18 @@
+import os
+
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="ether-wake")
+class TestEtherWake:
+ @pytest.mark.xfail(
+ os.environ.get("NETWORK") == "none",
+ reason="MAC addresses may be N/A with no networking configured",
+ )
+ @pytest.mark.complete("ether-wake ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ether-wake -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_etherwake.py b/test/t/test_etherwake.py
new file mode 100644
index 0000000..b444b43
--- /dev/null
+++ b/test/t/test_etherwake.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestEtherwake:
+ @pytest.mark.complete("etherwake -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_evince.py b/test/t/test_evince.py
new file mode 100644
index 0000000..9e9245d
--- /dev/null
+++ b/test/t/test_evince.py
@@ -0,0 +1,22 @@
+import pytest
+
+
+class TestEvince:
+ @pytest.mark.complete("evince ", cwd="evince")
+ def test_1(self, completion):
+ # .txt should not be here
+ assert completion == sorted(
+ "foo/ .bmp .BMP .cbr .CBR .cbz .CBZ .djv .DJV .djvu .DJVU .dvi "
+ ".DVI .dvi.bz2 .dvi.BZ2 .DVI.bz2 .DVI.BZ2 .dvi.gz .dvi.GZ "
+ ".DVI.gz .DVI.GZ .eps .EPS .eps.bz2 .eps.BZ2 .EPS.bz2 .EPS.BZ2 "
+ ".eps.gz .eps.GZ .EPS.gz .EPS.GZ .gif .GIF .ico .ICO .jpeg "
+ ".JPEG .jpg .JPG .miff .MIFF .pbm .PBM .pcx .PCX .pdf .PDF "
+ ".pdf.bz2 .pdf.BZ2 .PDF.bz2 .PDF.BZ2 .pdf.gz .pdf.GZ .PDF.gz "
+ ".PDF.GZ .pgm .PGM .png .PNG .pnm .PNM .ppm .PPM .ps .PS "
+ ".ps.bz2 .ps.BZ2 .PS.bz2 .PS.BZ2 .ps.gz .ps.GZ .PS.gz .PS.GZ "
+ ".tga .TGA .tif .TIF .tiff .TIFF .xpm .XPM .xwd .XWD".split()
+ )
+
+ @pytest.mark.complete("evince -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_expand.py b/test/t/test_expand.py
new file mode 100644
index 0000000..11f4bdb
--- /dev/null
+++ b/test/t/test_expand.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestExpand:
+ @pytest.mark.complete("expand --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_explodepkg.py b/test/t/test_explodepkg.py
new file mode 100644
index 0000000..940fec8
--- /dev/null
+++ b/test/t/test_explodepkg.py
@@ -0,0 +1,23 @@
+import fnmatch
+import os
+
+import pytest
+
+
+class TestExplodepkg:
+ @pytest.mark.complete("explodepkg ", cwd="slackware/home")
+ def test_1(self, completion):
+ expected = sorted(
+ [
+ "%s/" % x
+ for x in os.listdir("slackware/home")
+ if os.path.isdir("./slackware/home/%s" % x)
+ ]
+ + [
+ x
+ for x in os.listdir("slackware/home")
+ if os.path.isfile("./slackware/home/%s" % x)
+ and fnmatch.fnmatch(x, "*.t[bglx]z")
+ ]
+ )
+ assert completion == expected
diff --git a/test/t/test_export.py b/test/t/test_export.py
new file mode 100644
index 0000000..8738913
--- /dev/null
+++ b/test/t/test_export.py
@@ -0,0 +1,36 @@
+import pytest
+
+
+class TestExport:
+ @pytest.mark.complete("export BASH")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("export -n BASH")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("export -p ")
+ def test_3(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("export FOO=", cwd="shared/default")
+ def test_4(self, completion):
+ assert completion == ["bar", "bar bar.d/", "foo", "foo.d/"]
+
+ @pytest.mark.complete("export FOO=f", cwd="shared/default")
+ def test_5(self, completion):
+ assert completion == ["foo", "foo.d/"]
+
+ @pytest.mark.complete("export -fn _ex")
+ def test_6(self, completion):
+ assert "_expand" in completion
+ assert "_export" in completion
+
+ @pytest.mark.complete(r"export FOO=$BASH")
+ def test_7(self, completion):
+ assert completion
+
+ @pytest.mark.complete("export -", require_cmd=True)
+ def test_8(self, completion):
+ assert completion
diff --git a/test/t/test_faillog.py b/test/t/test_faillog.py
new file mode 100644
index 0000000..edf490b
--- /dev/null
+++ b/test/t/test_faillog.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestFaillog:
+ @pytest.mark.complete("faillog -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_fbgs.py b/test/t/test_fbgs.py
new file mode 100644
index 0000000..53ff741
--- /dev/null
+++ b/test/t/test_fbgs.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestFbgs:
+ @pytest.mark.complete("fbgs ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_fbi.py b/test/t/test_fbi.py
new file mode 100644
index 0000000..e27fef5
--- /dev/null
+++ b/test/t/test_fbi.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestFbi:
+ @pytest.mark.complete("fbi ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_feh.py b/test/t/test_feh.py
new file mode 100644
index 0000000..f2d5317
--- /dev/null
+++ b/test/t/test_feh.py
@@ -0,0 +1,31 @@
+import pytest
+
+
+class TestFeh:
+ @pytest.mark.complete("feh ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "feh --lis",
+ xfail="feh --help 2>&1 | command grep -qF 'man feh'",
+ require_cmd=True,
+ )
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("feh -S pix")
+ def test_3(self, completion):
+ assert completion == "els"
+
+ @pytest.mark.complete("feh --zoom ma")
+ def test_4(self, completion):
+ assert completion == "x"
+
+ @pytest.mark.complete("feh -g 640")
+ def test_5(self, completion):
+ assert completion == "0 1 2 3 4 5 6 7 8 9 x".split()
+
+ @pytest.mark.complete("feh -g 640x48")
+ def test_6(self, completion):
+ assert completion == "0 1 2 3 4 5 6 7 8 9".split()
diff --git a/test/t/test_file.py b/test/t/test_file.py
new file mode 100644
index 0000000..0c19eb4
--- /dev/null
+++ b/test/t/test_file.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestFile:
+ @pytest.mark.complete("file ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("file -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_file_roller.py b/test/t/test_file_roller.py
new file mode 100644
index 0000000..80a1bbc
--- /dev/null
+++ b/test/t/test_file_roller.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="file-roller")
+class TestFileRoller:
+ @pytest.mark.complete("file-roller ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_filefrag.py b/test/t/test_filefrag.py
new file mode 100644
index 0000000..342e89c
--- /dev/null
+++ b/test/t/test_filefrag.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestFilefrag:
+ @pytest.mark.complete("filefrag ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("filefrag -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_filesnarf.py b/test/t/test_filesnarf.py
new file mode 100644
index 0000000..cee621e
--- /dev/null
+++ b/test/t/test_filesnarf.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestFilesnarf:
+ @pytest.mark.complete("filesnarf -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_find.py b/test/t/test_find.py
new file mode 100644
index 0000000..9968ade
--- /dev/null
+++ b/test/t/test_find.py
@@ -0,0 +1,37 @@
+import pytest
+
+
+class TestFind:
+ @pytest.mark.complete("find ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("find -fstype ")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("find -")
+ def test_3(self, completion):
+ assert completion
+
+ @pytest.mark.complete("find -wholename ", cwd="shared/default")
+ def test_4(self, completion):
+ assert completion == ["bar", "bar bar.d/", "foo", "foo.d/"]
+
+ @pytest.mark.complete("find -uid ")
+ def test_5(self, completion):
+ assert not [x for x in completion if not x.isdigit()]
+
+ @pytest.mark.complete("find -gid ")
+ def test_6(self, completion):
+ assert not [x for x in completion if not x.isdigit()]
+
+ @pytest.mark.complete("find -exec shared/bin/ar")
+ def test_exec(self, completion):
+ assert completion == "p"
+
+ # sh +: something that produces completions also when command is not
+ # available, and the chosen completion is not one of find's
+ @pytest.mark.complete("find /some/where -exec sh +")
+ def test_exec_args(self, completion):
+ assert "+o" in completion
diff --git a/test/t/test_find_member.py b/test/t/test_find_member.py
new file mode 100644
index 0000000..bfcf588
--- /dev/null
+++ b/test/t/test_find_member.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestFindMember:
+ @pytest.mark.complete("find_member -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_finger.py b/test/t/test_finger.py
new file mode 100644
index 0000000..d765fdd
--- /dev/null
+++ b/test/t/test_finger.py
@@ -0,0 +1,33 @@
+import pytest
+
+from conftest import assert_complete, partialize
+
+
+class TestFinger:
+ @pytest.fixture(scope="class")
+ def users_at(self, bash, output_sort_uniq):
+ return output_sort_uniq("compgen -u -S @")
+
+ @pytest.mark.complete("finger ")
+ def test_1(self, bash, completion, users_at):
+ assert completion == users_at
+
+ @pytest.mark.complete("finger r")
+ def test_2(self, bash, completion, users_at):
+ if not any(x.startswith("r") for x in users_at):
+ pytest.skip("No users starting with r")
+ assert completion
+ idx = 1 if len(completion) == 1 else 0
+ assert completion == sorted(
+ x[idx:] for x in users_at if x.startswith("r")
+ )
+ assert not completion.endswith(" ")
+
+ def test_partial_hostname(self, bash, known_hosts):
+ first_char, partial_hosts = partialize(bash, known_hosts)
+ user = "test"
+ completion = assert_complete(bash, "finger %s@%s" % (user, first_char))
+ if len(completion) == 1:
+ assert completion == partial_hosts[0][1:]
+ else:
+ assert completion == ["%s@%s" % (user, x) for x in partial_hosts]
diff --git a/test/t/test_fio.py b/test/t/test_fio.py
new file mode 100644
index 0000000..0f6eba7
--- /dev/null
+++ b/test/t/test_fio.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestFio:
+ @pytest.mark.complete("fio ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("fio --", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("fio --debug=foo,")
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_firefox.py b/test/t/test_firefox.py
new file mode 100644
index 0000000..2e05255
--- /dev/null
+++ b/test/t/test_firefox.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+class TestFirefox:
+ @pytest.mark.complete("firefox ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("firefox -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+ assert not completion.endswith(" ")
diff --git a/test/t/test_flake8.py b/test/t/test_flake8.py
new file mode 100644
index 0000000..67649fa
--- /dev/null
+++ b/test/t/test_flake8.py
@@ -0,0 +1,17 @@
+import pytest
+
+
+class TestFlake8:
+ @pytest.mark.complete("flake8 ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "flake8 -", require_cmd=True, xfail="! flake8 --help &>/dev/null"
+ )
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("flake8 --doesnt-exist=")
+ def test_3(self, completion):
+ assert not completion
diff --git a/test/t/test_fmt.py b/test/t/test_fmt.py
new file mode 100644
index 0000000..12706da
--- /dev/null
+++ b/test/t/test_fmt.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestFmt:
+ @pytest.mark.complete(
+ "fmt -", require_cmd=True, xfail="! fmt --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_fold.py b/test/t/test_fold.py
new file mode 100644
index 0000000..1cbaef9
--- /dev/null
+++ b/test/t/test_fold.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestFold:
+ @pytest.mark.complete("fold --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_freebsd_update.py b/test/t/test_freebsd_update.py
new file mode 100644
index 0000000..911a49a
--- /dev/null
+++ b/test/t/test_freebsd_update.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="freebsd-update")
+class TestFreebsdUpdate:
+ @pytest.mark.complete("freebsd-update ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_freeciv.py b/test/t/test_freeciv.py
new file mode 100644
index 0000000..a195eb8
--- /dev/null
+++ b/test/t/test_freeciv.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestFreeciv:
+ @pytest.mark.complete("freeciv -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_freeciv_server.py b/test/t/test_freeciv_server.py
new file mode 100644
index 0000000..8543a21
--- /dev/null
+++ b/test/t/test_freeciv_server.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="freeciv-server")
+class TestFreecivServer:
+ @pytest.mark.complete("freeciv-server -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_function.py b/test/t/test_function.py
new file mode 100644
index 0000000..4401f02
--- /dev/null
+++ b/test/t/test_function.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestFunction:
+ @pytest.mark.complete("function _parse_")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_fusermount.py b/test/t/test_fusermount.py
new file mode 100644
index 0000000..dbb2bd9
--- /dev/null
+++ b/test/t/test_fusermount.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestFusermount:
+ @pytest.mark.complete("fusermount ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("fusermount -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_g4.py b/test/t/test_g4.py
new file mode 100644
index 0000000..739c77d
--- /dev/null
+++ b/test/t/test_g4.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestG4:
+ @pytest.mark.complete("g4 ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_g77.py b/test/t/test_g77.py
new file mode 100644
index 0000000..45da624
--- /dev/null
+++ b/test/t/test_g77.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestG77:
+ @pytest.mark.complete("g77 ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_gcc.py b/test/t/test_gcc.py
new file mode 100644
index 0000000..50906db
--- /dev/null
+++ b/test/t/test_gcc.py
@@ -0,0 +1,64 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+class TestGcc:
+ @pytest.fixture(scope="class")
+ def gcc_with_completion(self, bash):
+ got = assert_bash_exec(
+ bash, "gcc --help=common || :", want_output=True
+ )
+ if "--completion" not in got:
+ pytest.skip("GCC does not support --completion")
+
+ @pytest.fixture(scope="class")
+ def gcc_x86(self, bash):
+ got = assert_bash_exec(bash, "gcc -v || :", want_output=True)
+ if "Target: x86" not in got:
+ pytest.skip("Not a x86 GCC")
+
+ @pytest.mark.complete("gcc ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("gcc -fsanitize=add")
+ def test_enum_value(self, completion, gcc_with_completion):
+ assert completion == "ress"
+
+ @pytest.mark.complete("gcc -fsanitize=")
+ def test_enum_value_with_eq(self, completion, gcc_with_completion):
+ assert "address" in completion
+
+ @pytest.mark.complete("gcc -fno-ipa-ic")
+ def test_negative_option(self, completion, gcc_with_completion):
+ assert "-fno-ipa-icf" in completion
+
+ @pytest.mark.complete("gcc -fxyz-abc")
+ def test_no_completion(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("gcc --param ")
+ def test_param_with_space(self, completion, gcc_with_completion):
+ assert len(completion) > 50
+ # starting with GCC 10.1 param end with =
+ assert (
+ "lto-partitions" in completion or "lto-partitions=" in completion
+ )
+
+ @pytest.mark.complete("gcc --param=lto-max-p")
+ def test_param_with_eq(self, completion, gcc_with_completion):
+ # starting with GCC 10.1 param ends with =
+ assert completion in ("artition", "artition=")
+
+ @pytest.mark.complete("gcc -march=amd")
+ def test_march(self, completion, gcc_with_completion, gcc_x86):
+ assert completion == "fam10"
+
+ @pytest.mark.complete("gcc -march=")
+ def test_march_native(self, completion, gcc_with_completion):
+ assert "native" in completion
+
+ @pytest.mark.complete("gcc -mtune=")
+ def test_mtune_generic(self, completion, gcc_with_completion):
+ assert "generic" in completion
diff --git a/test/t/test_gcj.py b/test/t/test_gcj.py
new file mode 100644
index 0000000..17e2f44
--- /dev/null
+++ b/test/t/test_gcj.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestGcj:
+ @pytest.mark.complete("gcj ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_gcl.py b/test/t/test_gcl.py
new file mode 100644
index 0000000..f1e7a5f
--- /dev/null
+++ b/test/t/test_gcl.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestGcl:
+ @pytest.mark.complete("gcl ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_gdb.py b/test/t/test_gdb.py
new file mode 100644
index 0000000..2ad12c4
--- /dev/null
+++ b/test/t/test_gdb.py
@@ -0,0 +1,14 @@
+import pytest
+
+
+class TestGdb:
+ @pytest.mark.complete("gdb - ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("gdb foo ", cwd="gdb")
+ def test_2(self, completion):
+ assert completion == sorted(
+ "core core.12345 "
+ "core.weston.1000.deadbeef.5308.1555362132000000".split()
+ )
diff --git a/test/t/test_genaliases.py b/test/t/test_genaliases.py
new file mode 100644
index 0000000..e2f24d6
--- /dev/null
+++ b/test/t/test_genaliases.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("PATH=/usr/lib/mailman/bin:$PATH",))
+class TestGenaliases:
+ @pytest.mark.complete("genaliases -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_gendiff.py b/test/t/test_gendiff.py
new file mode 100644
index 0000000..0e2ab4c
--- /dev/null
+++ b/test/t/test_gendiff.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestGendiff:
+ @pytest.mark.complete("gendiff ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_genisoimage.py b/test/t/test_genisoimage.py
new file mode 100644
index 0000000..bfcef3b
--- /dev/null
+++ b/test/t/test_genisoimage.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestGenisoimage:
+ @pytest.mark.complete("genisoimage ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("genisoimage -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_geoiplookup.py b/test/t/test_geoiplookup.py
new file mode 100644
index 0000000..9a1422b
--- /dev/null
+++ b/test/t/test_geoiplookup.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestGeoiplookup:
+ @pytest.mark.complete("geoiplookup -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_getconf.py b/test/t/test_getconf.py
new file mode 100644
index 0000000..c80c803
--- /dev/null
+++ b/test/t/test_getconf.py
@@ -0,0 +1,25 @@
+import pytest
+
+
+class TestGetconf:
+ @pytest.mark.complete("getconf P")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("getconf -")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("getconf -a ")
+ def test_3(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "getconf -v ", xfail="! getconf -a 2>&1 | command grep -q ^POSIX_V"
+ )
+ def test_4(self, completion):
+ assert completion
+
+ @pytest.mark.complete("getconf PATH_MAX ")
+ def test_5(self, completion):
+ assert completion
diff --git a/test/t/test_getent.py b/test/t/test_getent.py
new file mode 100644
index 0000000..a1e9fcb
--- /dev/null
+++ b/test/t/test_getent.py
@@ -0,0 +1,18 @@
+import pytest
+
+
+class TestGetent:
+ @pytest.mark.complete("getent ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "getent -",
+ require_cmd=True,
+ xfail=(
+ "! (getent --help 2>&1 || :) | "
+ "command grep -q -- '[[:space:]]-'"
+ ),
+ )
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_gkrellm.py b/test/t/test_gkrellm.py
new file mode 100644
index 0000000..fdc2e16
--- /dev/null
+++ b/test/t/test_gkrellm.py
@@ -0,0 +1,10 @@
+import os
+
+import pytest
+
+
+@pytest.mark.xfail(not os.environ.get("DISPLAY"), reason="X display required")
+class TestGkrellm:
+ @pytest.mark.complete("gkrellm -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_gm.py b/test/t/test_gm.py
new file mode 100644
index 0000000..9cdd73c
--- /dev/null
+++ b/test/t/test_gm.py
@@ -0,0 +1,19 @@
+import pytest
+
+
+class TestGm:
+ @pytest.mark.complete("gm ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("gm help ", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("gm time ", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
+
+ @pytest.mark.complete("gm version ")
+ def test_4(self, completion):
+ assert not completion
diff --git a/test/t/test_gmplayer.py b/test/t/test_gmplayer.py
new file mode 100644
index 0000000..211ef51
--- /dev/null
+++ b/test/t/test_gmplayer.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestGmplayer:
+ @pytest.mark.complete("gmplayer ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_gnatmake.py b/test/t/test_gnatmake.py
new file mode 100644
index 0000000..c9f5609
--- /dev/null
+++ b/test/t/test_gnatmake.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestGnatmake:
+ @pytest.mark.complete("gnatmake ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_gnokii.py b/test/t/test_gnokii.py
new file mode 100644
index 0000000..66af6e9
--- /dev/null
+++ b/test/t/test_gnokii.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestGnokii:
+ @pytest.mark.complete("gnokii ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("gnokii -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_gnome_mplayer.py b/test/t/test_gnome_mplayer.py
new file mode 100644
index 0000000..379c56c
--- /dev/null
+++ b/test/t/test_gnome_mplayer.py
@@ -0,0 +1,17 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="gnome-mplayer", ignore_env=r"^[+-]XDG_DATA_DIRS=")
+class TestGnomeMplayer:
+ @pytest.mark.complete("gnome-mplayer ")
+ def test_1(self, completion):
+ assert completion
+
+ # XDG_DATA_DIRS set to a dir with no schemas results in
+ # "GLib-GIO-ERROR **: No GSettings schemas are installed on the system"
+ # and a core dump on --help on Ubuntu 14.
+ @pytest.mark.complete(
+ "gnome-mplayer -", require_cmd=True, pre_cmds=("unset XDG_DATA_DIRS",)
+ )
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_gnome_screenshot.py b/test/t/test_gnome_screenshot.py
new file mode 100644
index 0000000..977e03f
--- /dev/null
+++ b/test/t/test_gnome_screenshot.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="gnome-screenshot")
+class TestGnomeScreenshot:
+ @pytest.mark.complete("gnome-screenshot --help", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_gpasswd.py b/test/t/test_gpasswd.py
new file mode 100644
index 0000000..4f0221b
--- /dev/null
+++ b/test/t/test_gpasswd.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestGpasswd:
+ @pytest.mark.complete("gpasswd ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("gpasswd -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_gpc.py b/test/t/test_gpc.py
new file mode 100644
index 0000000..9903ef4
--- /dev/null
+++ b/test/t/test_gpc.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestGpc:
+ @pytest.mark.complete("gpc ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_gperf.py b/test/t/test_gperf.py
new file mode 100644
index 0000000..54f75b1
--- /dev/null
+++ b/test/t/test_gperf.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestGperf:
+ @pytest.mark.complete("gperf --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_gpg.py b/test/t/test_gpg.py
new file mode 100644
index 0000000..8ead5e9
--- /dev/null
+++ b/test/t/test_gpg.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestGpg:
+ @pytest.mark.complete("gpg ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_gpg2.py b/test/t/test_gpg2.py
new file mode 100644
index 0000000..27a39fa
--- /dev/null
+++ b/test/t/test_gpg2.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestGpg2:
+ @pytest.mark.complete("gpg2 --h", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_gpgv.py b/test/t/test_gpgv.py
new file mode 100644
index 0000000..d600c74
--- /dev/null
+++ b/test/t/test_gpgv.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestGpgv:
+ @pytest.mark.complete("gpgv ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("gpgv -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("gpgv foo.sig foo ")
+ def test_3(self, completion):
+ assert not completion
diff --git a/test/t/test_gphoto2.py b/test/t/test_gphoto2.py
new file mode 100644
index 0000000..bb987f7
--- /dev/null
+++ b/test/t/test_gphoto2.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestGphoto2:
+ @pytest.mark.complete("gphoto2 --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_gplusplus.py b/test/t/test_gplusplus.py
new file mode 100644
index 0000000..eeeb1bf
--- /dev/null
+++ b/test/t/test_gplusplus.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="g++")
+class TestGPlusPlus:
+ @pytest.mark.complete("g++ ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_gprof.py b/test/t/test_gprof.py
new file mode 100644
index 0000000..a30cc1e
--- /dev/null
+++ b/test/t/test_gprof.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestGprof:
+ @pytest.mark.complete("gprof --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_grep.py b/test/t/test_grep.py
new file mode 100644
index 0000000..a249122
--- /dev/null
+++ b/test/t/test_grep.py
@@ -0,0 +1,16 @@
+import pytest
+
+
+class TestGrep:
+ @pytest.mark.complete("grep --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("grep --no-complete-dir f", cwd="shared/default")
+ def test_2(self, completion):
+ """
+ Test --no-*dir isn't restricted to dirs only.
+
+ Not really a grep option, but tests _longopt.
+ """
+ assert completion == "foo foo.d/".split()
diff --git a/test/t/test_groupadd.py b/test/t/test_groupadd.py
new file mode 100644
index 0000000..f882d1e
--- /dev/null
+++ b/test/t/test_groupadd.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestGroupadd:
+ @pytest.mark.complete("groupadd ")
+ def test_1(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("groupadd -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_groupdel.py b/test/t/test_groupdel.py
new file mode 100644
index 0000000..6e55839
--- /dev/null
+++ b/test/t/test_groupdel.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestGroupdel:
+ @pytest.mark.complete("groupdel ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("groupdel -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_groupmems.py b/test/t/test_groupmems.py
new file mode 100644
index 0000000..c7b9920
--- /dev/null
+++ b/test/t/test_groupmems.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestGroupmems:
+ @pytest.mark.complete("groupmems -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_groupmod.py b/test/t/test_groupmod.py
new file mode 100644
index 0000000..7097118
--- /dev/null
+++ b/test/t/test_groupmod.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestGroupmod:
+ @pytest.mark.complete("groupmod ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("groupmod -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_growisofs.py b/test/t/test_growisofs.py
new file mode 100644
index 0000000..7ce19f6
--- /dev/null
+++ b/test/t/test_growisofs.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestGrowisofs:
+ @pytest.mark.complete("growisofs ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_grpck.py b/test/t/test_grpck.py
new file mode 100644
index 0000000..dcd1485
--- /dev/null
+++ b/test/t/test_grpck.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestGrpck:
+ @pytest.mark.complete("grpck ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("grpck -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_grub.py b/test/t/test_grub.py
new file mode 100644
index 0000000..4a6929f
--- /dev/null
+++ b/test/t/test_grub.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestGrub:
+ @pytest.mark.complete("grub --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_gssdp_discover.py b/test/t/test_gssdp_discover.py
new file mode 100644
index 0000000..b545149
--- /dev/null
+++ b/test/t/test_gssdp_discover.py
@@ -0,0 +1,22 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="gssdp-discover")
+class TestGssdpDiscover:
+ @pytest.mark.complete("gssdp-discover ")
+ def test_no_args(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("gssdp-discover --", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "gssdp-discover --message-type=",
+ skipif=(
+ "! gssdp-discover --help 2>&1 "
+ "| command grep -qF -- --message-type"
+ ),
+ )
+ def test_message_type(self, completion):
+ assert completion
diff --git a/test/t/test_gzip.py b/test/t/test_gzip.py
new file mode 100644
index 0000000..2173cad
--- /dev/null
+++ b/test/t/test_gzip.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestGzip:
+ @pytest.mark.complete("gzip ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("gzip ~")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("gzip -", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_hciattach.py b/test/t/test_hciattach.py
new file mode 100644
index 0000000..2dc1095
--- /dev/null
+++ b/test/t/test_hciattach.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestHciattach:
+ @pytest.mark.complete("hciattach ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_hciconfig.py b/test/t/test_hciconfig.py
new file mode 100644
index 0000000..2a3f1fd
--- /dev/null
+++ b/test/t/test_hciconfig.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestHciconfig:
+ @pytest.mark.complete("hciconfig ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_hcitool.py b/test/t/test_hcitool.py
new file mode 100644
index 0000000..0885385
--- /dev/null
+++ b/test/t/test_hcitool.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestHcitool:
+ @pytest.mark.complete("hcitool ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("hcitool -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_hddtemp.py b/test/t/test_hddtemp.py
new file mode 100644
index 0000000..e80a46c
--- /dev/null
+++ b/test/t/test_hddtemp.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestHddtemp:
+ @pytest.mark.complete("hddtemp -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_head.py b/test/t/test_head.py
new file mode 100644
index 0000000..815b938
--- /dev/null
+++ b/test/t/test_head.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestHead:
+ @pytest.mark.complete("head --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_hexdump.py b/test/t/test_hexdump.py
new file mode 100644
index 0000000..03a7b1f
--- /dev/null
+++ b/test/t/test_hexdump.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestHexdump:
+ @pytest.mark.complete("hexdump -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_hid2hci.py b/test/t/test_hid2hci.py
new file mode 100644
index 0000000..66766fb
--- /dev/null
+++ b/test/t/test_hid2hci.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("PATH=/lib/udev:$PATH",))
+class TestHid2hci:
+ @pytest.mark.complete("hid2hci -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_host.py b/test/t/test_host.py
new file mode 100644
index 0000000..2ef1790
--- /dev/null
+++ b/test/t/test_host.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestHost:
+ @pytest.mark.complete("host -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_hostname.py b/test/t/test_hostname.py
new file mode 100644
index 0000000..f644c1e
--- /dev/null
+++ b/test/t/test_hostname.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestHostname:
+ @pytest.mark.complete("hostname -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_hping2.py b/test/t/test_hping2.py
new file mode 100644
index 0000000..19665ba
--- /dev/null
+++ b/test/t/test_hping2.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestHping2:
+ @pytest.mark.complete("hping2 ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("hping2 -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_hping3.py b/test/t/test_hping3.py
new file mode 100644
index 0000000..a979cfa
--- /dev/null
+++ b/test/t/test_hping3.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestHping3:
+ @pytest.mark.complete("hping3 ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_htop.py b/test/t/test_htop.py
new file mode 100644
index 0000000..e837c5a
--- /dev/null
+++ b/test/t/test_htop.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestHtop:
+ @pytest.mark.complete("htop -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_htpasswd.py b/test/t/test_htpasswd.py
new file mode 100644
index 0000000..92989fa
--- /dev/null
+++ b/test/t/test_htpasswd.py
@@ -0,0 +1,23 @@
+import pytest
+
+
+class TestHtpasswd:
+ @pytest.mark.complete("htpasswd ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("htpasswd -n htpasswd/ht")
+ def test_2(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("htpasswd ", cwd="htpasswd")
+ def test_3(self, completion):
+ assert completion == "htpasswd"
+
+ @pytest.mark.complete("htpasswd -D htpasswd ", cwd="htpasswd")
+ def test_4(self, completion):
+ assert completion == "foo quux".split()
+
+ @pytest.mark.complete("htpasswd -", require_cmd=True)
+ def test_5(self, completion):
+ assert completion
diff --git a/test/t/test_hunspell.py b/test/t/test_hunspell.py
new file mode 100644
index 0000000..0f27185
--- /dev/null
+++ b/test/t/test_hunspell.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestHunspell:
+ @pytest.mark.complete("hunspell ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("hunspell -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_hwclock.py b/test/t/test_hwclock.py
new file mode 100644
index 0000000..4717210
--- /dev/null
+++ b/test/t/test_hwclock.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestHwclock:
+ @pytest.mark.complete("hwclock -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_iconv.py b/test/t/test_iconv.py
new file mode 100644
index 0000000..f42a87f
--- /dev/null
+++ b/test/t/test_iconv.py
@@ -0,0 +1,21 @@
+import pytest
+
+
+class TestIconv:
+ @pytest.mark.complete(
+ "iconv -", require_cmd=True, xfail="! iconv --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("iconv -f UTF", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("iconv ")
+ def test_3(self, completion):
+ assert completion
+
+ @pytest.mark.complete("iconv -f ")
+ def test_4(self, completion):
+ assert "..." not in completion
diff --git a/test/t/test_id.py b/test/t/test_id.py
new file mode 100644
index 0000000..41f2868
--- /dev/null
+++ b/test/t/test_id.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestId:
+ @pytest.mark.complete("id -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_identify.py b/test/t/test_identify.py
new file mode 100644
index 0000000..34ae285
--- /dev/null
+++ b/test/t/test_identify.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestIdentify:
+ @pytest.mark.complete("identify -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_idn.py b/test/t/test_idn.py
new file mode 100644
index 0000000..78172c0
--- /dev/null
+++ b/test/t/test_idn.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestIdn:
+ @pytest.mark.complete("idn -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ifdown.py b/test/t/test_ifdown.py
new file mode 100644
index 0000000..e91e4ba
--- /dev/null
+++ b/test/t/test_ifdown.py
@@ -0,0 +1,14 @@
+import pytest
+
+from conftest import in_container
+
+
+class TestIfdown:
+ @pytest.mark.xfail(in_container(), reason="Probably fails in a container")
+ @pytest.mark.complete("ifdown ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ifdown bash-completion ")
+ def test_2(self, completion):
+ assert not completion
diff --git a/test/t/test_ifstat.py b/test/t/test_ifstat.py
new file mode 100644
index 0000000..89b5a0e
--- /dev/null
+++ b/test/t/test_ifstat.py
@@ -0,0 +1,21 @@
+import pytest
+
+
+class TestIfstat:
+ @pytest.mark.complete("ifstat -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "ifstat -i ", xfail="ifstat -v | command grep -qF iproute2"
+ )
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "ifstat -d ",
+ require_cmd=True,
+ xfail="ifstat -v | command grep -qF iproute2",
+ )
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_iftop.py b/test/t/test_iftop.py
new file mode 100644
index 0000000..4497310
--- /dev/null
+++ b/test/t/test_iftop.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestIftop:
+ @pytest.mark.complete("iftop ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("iftop -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_ifup.py b/test/t/test_ifup.py
new file mode 100644
index 0000000..843190e
--- /dev/null
+++ b/test/t/test_ifup.py
@@ -0,0 +1,20 @@
+import pytest
+
+from conftest import in_container
+
+
+class TestIfup:
+ @pytest.mark.xfail(in_container(), reason="Probably fails in a container")
+ @pytest.mark.complete("ifup ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "ifup -", require_cmd=True, skipif="! ifup --help &>/dev/null"
+ )
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ifup bash-completion ")
+ def test_3(self, completion):
+ assert not completion
diff --git a/test/t/test_import.py b/test/t/test_import.py
new file mode 100644
index 0000000..2e86065
--- /dev/null
+++ b/test/t/test_import.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestImport:
+ @pytest.mark.complete("import ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_influx.py b/test/t/test_influx.py
new file mode 100644
index 0000000..53a15bf
--- /dev/null
+++ b/test/t/test_influx.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestInflux:
+ @pytest.mark.complete("influx ")
+ def test_nothing(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("influx -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
+
+ @pytest.mark.complete("influx -format ", require_cmd=True)
+ def test_format(self, completion):
+ assert completion
diff --git a/test/t/test_info.py b/test/t/test_info.py
new file mode 100644
index 0000000..e12d900
--- /dev/null
+++ b/test/t/test_info.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("INFOPATH+=:$PWD/info:",))
+class TestInfo:
+ @pytest.mark.complete("info bash")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("info -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_inject.py b/test/t/test_inject.py
new file mode 100644
index 0000000..37680dc
--- /dev/null
+++ b/test/t/test_inject.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("PATH=/usr/lib/mailman/bin:$PATH",))
+class TestInject:
+ @pytest.mark.complete("inject ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_inotifywait.py b/test/t/test_inotifywait.py
new file mode 100644
index 0000000..19fa4d5
--- /dev/null
+++ b/test/t/test_inotifywait.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestInotifywait:
+ @pytest.mark.complete("inotifywait ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("inotifywait --", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("inotifywait -e ", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_inotifywatch.py b/test/t/test_inotifywatch.py
new file mode 100644
index 0000000..281fec4
--- /dev/null
+++ b/test/t/test_inotifywatch.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestInotifywatch:
+ @pytest.mark.complete("inotifywatch ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("inotifywatch --", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("inotifywatch -e ", require_cmd=True)
+ def test_3(self, completion):
+ assert len(completion) > 1
diff --git a/test/t/test_insmod.py b/test/t/test_insmod.py
new file mode 100644
index 0000000..9636185
--- /dev/null
+++ b/test/t/test_insmod.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestInsmod:
+ @pytest.mark.complete("insmod ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_installpkg.py b/test/t/test_installpkg.py
new file mode 100644
index 0000000..e665f52
--- /dev/null
+++ b/test/t/test_installpkg.py
@@ -0,0 +1,39 @@
+import fnmatch
+import os
+
+import pytest
+
+
+class TestInstallpkg:
+ @pytest.mark.complete("installpkg -")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("installpkg --")
+ def test_2(self, completion):
+ assert (
+ completion == "--ask --infobox --md5sum --menu "
+ "--priority --root --tagfile --terse --warn".split()
+ )
+
+ @pytest.mark.complete("installpkg --root ")
+ def test_3(self, completion):
+ dirs = sorted(x for x in os.listdir(".") if os.path.isdir("./%s" % x))
+ assert completion == ["%s/" % x for x in dirs]
+
+ @pytest.mark.complete("installpkg ", cwd="slackware/home")
+ def test_4(self, completion):
+ expected = sorted(
+ [
+ "%s/" % x
+ for x in os.listdir("slackware/home")
+ if os.path.isdir("./slackware/home/%s" % x)
+ ]
+ + [
+ x
+ for x in os.listdir("slackware/home")
+ if os.path.isfile("./slackware/home/%s" % x)
+ and fnmatch.fnmatch(x, "*.t[bglx]z")
+ ]
+ )
+ assert completion == expected
diff --git a/test/t/test_interdiff.py b/test/t/test_interdiff.py
new file mode 100644
index 0000000..83be115
--- /dev/null
+++ b/test/t/test_interdiff.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestInterdiff:
+ @pytest.mark.complete("interdiff ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("interdiff -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_invoke_rc_d.py b/test/t/test_invoke_rc_d.py
new file mode 100644
index 0000000..61e2987
--- /dev/null
+++ b/test/t/test_invoke_rc_d.py
@@ -0,0 +1,14 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="invoke-rc.d")
+class TestInvokeRcD:
+ @pytest.mark.complete("invoke-rc.d ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("invoke-rc.d --no-fallback --")
+ def test_2(self, completion):
+ """Test already specified option is not offered."""
+ assert completion
+ assert "--no-fallback" not in completion
diff --git a/test/t/test_ionice.py b/test/t/test_ionice.py
new file mode 100644
index 0000000..b097ebe
--- /dev/null
+++ b/test/t/test_ionice.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestIonice:
+ @pytest.mark.complete("ionice -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ip.py b/test/t/test_ip.py
new file mode 100644
index 0000000..320647f
--- /dev/null
+++ b/test/t/test_ip.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestIp:
+ @pytest.mark.complete("ip ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ip a ")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ip route replace ")
+ def test_r_r(self, completion):
+ assert completion
diff --git a/test/t/test_ipcalc.py b/test/t/test_ipcalc.py
new file mode 100644
index 0000000..5611674
--- /dev/null
+++ b/test/t/test_ipcalc.py
@@ -0,0 +1,23 @@
+import pytest
+
+
+class TestIpcalc:
+ @pytest.mark.complete("ipcalc -", require_cmd=True)
+ def test_options(self, completion):
+ assert any(x in completion for x in "--help -h".split())
+
+ @pytest.mark.complete("ipcalc --split -")
+ def test_split_3args_1(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("ipcalc --split 1 -")
+ def test_split_3args_2(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("ipcalc --split 1 2 -")
+ def test_split_3args_3(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("ipcalc --split 1 2 3 -", require_cmd=True)
+ def test_split_3args_4(self, completion):
+ assert any(x in completion for x in "--help -h".split())
diff --git a/test/t/test_iperf.py b/test/t/test_iperf.py
new file mode 100644
index 0000000..c38e954
--- /dev/null
+++ b/test/t/test_iperf.py
@@ -0,0 +1,24 @@
+import pytest
+
+
+class TestIperf:
+ @pytest.mark.complete("iperf ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("iperf --bind ")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("iperf --client foo --", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
+ assert "--daemon" not in completion
+
+ @pytest.mark.complete("iperf --server --", require_cmd=True)
+ def test_4(self, completion):
+ assert "--daemon" in completion
+
+ @pytest.mark.complete("iperf -", require_cmd=True)
+ def test_5(self, completion):
+ assert completion
diff --git a/test/t/test_iperf3.py b/test/t/test_iperf3.py
new file mode 100644
index 0000000..15f3a03
--- /dev/null
+++ b/test/t/test_iperf3.py
@@ -0,0 +1,20 @@
+import pytest
+
+
+class TestIperf3:
+ @pytest.mark.complete("iperf3 ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("iperf3 --bind ")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("iperf3 --client foo --", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
+ assert "--daemon" not in completion
+
+ @pytest.mark.complete("iperf3 --server --", require_cmd=True)
+ def test_4(self, completion):
+ assert "--daemon" in completion
diff --git a/test/t/test_ipmitool.py b/test/t/test_ipmitool.py
new file mode 100644
index 0000000..f779f91
--- /dev/null
+++ b/test/t/test_ipmitool.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestIpmitool:
+ @pytest.mark.complete("ipmitool ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ipmitool -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_ipsec.py b/test/t/test_ipsec.py
new file mode 100644
index 0000000..5ff29c7
--- /dev/null
+++ b/test/t/test_ipsec.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestIpsec:
+ @pytest.mark.complete("ipsec ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_iptables.py b/test/t/test_iptables.py
new file mode 100644
index 0000000..a5c82e5
--- /dev/null
+++ b/test/t/test_iptables.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestIptables:
+ @pytest.mark.complete("iptables -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ipv6calc.py b/test/t/test_ipv6calc.py
new file mode 100644
index 0000000..872d8a3
--- /dev/null
+++ b/test/t/test_ipv6calc.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestIpv6calc:
+ @pytest.mark.complete("ipv6calc -", require_cmd=True)
+ def test_1(self, completion):
+ assert "--action" in completion
+
+ @pytest.mark.complete("ipv6calc --in ", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_irb.py b/test/t/test_irb.py
new file mode 100644
index 0000000..801d373
--- /dev/null
+++ b/test/t/test_irb.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestIrb:
+ @pytest.mark.complete("irb ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("irb -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_iscsiadm.py b/test/t/test_iscsiadm.py
new file mode 100644
index 0000000..885ca0a
--- /dev/null
+++ b/test/t/test_iscsiadm.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestIscsiadm:
+ @pytest.mark.complete("iscsiadm --mod")
+ def test_1(self, completion):
+ assert completion == "e" or "--mode" in completion
diff --git a/test/t/test_isort.py b/test/t/test_isort.py
new file mode 100644
index 0000000..b142d1c
--- /dev/null
+++ b/test/t/test_isort.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestIsort:
+ @pytest.mark.complete("isort ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("isort -", require_cmd=True, require_longopt=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_isql.py b/test/t/test_isql.py
new file mode 100644
index 0000000..7ff0bdb
--- /dev/null
+++ b/test/t/test_isql.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("ODBCINI=isql/odbc.ini",))
+class TestIsql:
+ @pytest.mark.complete("isql ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_iwconfig.py b/test/t/test_iwconfig.py
new file mode 100644
index 0000000..3ac4b31
--- /dev/null
+++ b/test/t/test_iwconfig.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestIwconfig:
+ @pytest.mark.complete("iwconfig --")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_iwlist.py b/test/t/test_iwlist.py
new file mode 100644
index 0000000..77ffb99
--- /dev/null
+++ b/test/t/test_iwlist.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestIwlist:
+ @pytest.mark.complete("iwlist --")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_iwpriv.py b/test/t/test_iwpriv.py
new file mode 100644
index 0000000..dac214a
--- /dev/null
+++ b/test/t/test_iwpriv.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestIwpriv:
+ @pytest.mark.complete("iwpriv --")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_iwspy.py b/test/t/test_iwspy.py
new file mode 100644
index 0000000..398df37
--- /dev/null
+++ b/test/t/test_iwspy.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestIwspy:
+ @pytest.mark.complete("iwspy --")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_jar.py b/test/t/test_jar.py
new file mode 100644
index 0000000..5d4ed8a
--- /dev/null
+++ b/test/t/test_jar.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestJar:
+ @pytest.mark.complete("jar ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_jarsigner.py b/test/t/test_jarsigner.py
new file mode 100644
index 0000000..a6efa6a
--- /dev/null
+++ b/test/t/test_jarsigner.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestJarsigner:
+ @pytest.mark.complete("jarsigner ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_java.py b/test/t/test_java.py
new file mode 100644
index 0000000..ce0f773
--- /dev/null
+++ b/test/t/test_java.py
@@ -0,0 +1,49 @@
+import pytest
+
+from conftest import is_bash_type
+
+
+@pytest.mark.bashcomp(
+ pre_cmds=("CLASSPATH=$PWD/java/a:$PWD/java/bashcomp.jar",)
+)
+class TestJava:
+ @pytest.fixture(scope="class")
+ def can_list_jar(self, bash):
+ return (
+ is_bash_type(bash, "zipinfo")
+ or is_bash_type(bash, "unzip")
+ or is_bash_type(bash, "jar")
+ )
+
+ @pytest.mark.complete("java -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("java ")
+ def test_2(self, completion, can_list_jar):
+ if can_list_jar:
+ assert completion == "b bashcomp.jarred c. toplevel".split()
+ else:
+ assert completion == "b c.".split()
+
+ @pytest.mark.complete("java -classpath java/bashcomp.jar ")
+ def test_3(self, completion, can_list_jar):
+ if can_list_jar:
+ assert completion == "bashcomp.jarred toplevel".split()
+ else:
+ assert not completion
+
+ @pytest.mark.complete("java -cp java/bashcomp.jar:java/a/c ")
+ def test_4(self, completion, can_list_jar):
+ if can_list_jar:
+ assert completion == "bashcomp.jarred d toplevel".split()
+ else:
+ assert completion == ["d"]
+
+ @pytest.mark.complete("java -cp '' ")
+ def test_5(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("java -jar java/")
+ def test_6(self, completion):
+ assert completion == "a/ bashcomp.jar bashcomp.war".split()
diff --git a/test/t/test_javac.py b/test/t/test_javac.py
new file mode 100644
index 0000000..197004e
--- /dev/null
+++ b/test/t/test_javac.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestJavac:
+ @pytest.mark.complete("javac ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("javac -cp java/")
+ def test_2(self, completion):
+ assert completion == "a/ bashcomp.jar".split()
diff --git a/test/t/test_javadoc.py b/test/t/test_javadoc.py
new file mode 100644
index 0000000..395d196
--- /dev/null
+++ b/test/t/test_javadoc.py
@@ -0,0 +1,17 @@
+import pytest
+
+
+class TestJavadoc:
+ @pytest.mark.complete("javadoc ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("javadoc -linkoffline shared/default/")
+ def test_2(self, completion):
+ assert completion == ["bar bar.d/", "foo.d/"]
+
+ @pytest.mark.complete(
+ "javadoc -nodeprecated -linkoffline foo shared/default/"
+ )
+ def test_3(self, completion):
+ assert completion == ["bar bar.d/", "foo.d/"]
diff --git a/test/t/test_javaws.py b/test/t/test_javaws.py
new file mode 100644
index 0000000..596c735
--- /dev/null
+++ b/test/t/test_javaws.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestJavaws:
+ @pytest.mark.complete("javaws ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("javaws -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_jpegoptim.py b/test/t/test_jpegoptim.py
new file mode 100644
index 0000000..fb52591
--- /dev/null
+++ b/test/t/test_jpegoptim.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestJpegoptim:
+ @pytest.mark.complete("jpegoptim ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("jpegoptim -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_jps.py b/test/t/test_jps.py
new file mode 100644
index 0000000..add9ef9
--- /dev/null
+++ b/test/t/test_jps.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestJps:
+ @pytest.mark.complete("jps -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_jq.py b/test/t/test_jq.py
new file mode 100644
index 0000000..4701414
--- /dev/null
+++ b/test/t/test_jq.py
@@ -0,0 +1,30 @@
+import pytest
+
+
+class TestJq:
+ @pytest.mark.complete("jq ")
+ def test_1(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("jq . ")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "jq -",
+ xfail="! (jq --help 2>&1 || :) | command grep -qF 'options include'",
+ )
+ def test_3(self, completion):
+ assert completion
+
+ @pytest.mark.complete("jq --arg ")
+ def test_4(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("jq --slurpfile ")
+ def test_5(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("jq --slurpfile foo ")
+ def test_6(self, completion):
+ assert completion
diff --git a/test/t/test_jshint.py b/test/t/test_jshint.py
new file mode 100644
index 0000000..58049d1
--- /dev/null
+++ b/test/t/test_jshint.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestJshint:
+ @pytest.mark.complete("jshint ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("jshint -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_json_xs.py b/test/t/test_json_xs.py
new file mode 100644
index 0000000..f6174b1
--- /dev/null
+++ b/test/t/test_json_xs.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestJsonXs:
+ @pytest.mark.complete("json_xs ")
+ def test_1(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("json_xs -")
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_jsonschema.py b/test/t/test_jsonschema.py
new file mode 100644
index 0000000..6027f5d
--- /dev/null
+++ b/test/t/test_jsonschema.py
@@ -0,0 +1,13 @@
+import pytest
+
+
+class TestJsonschema:
+ @pytest.mark.complete("jsonschema ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "jsonschema -", require_cmd=True, require_longopt=True
+ )
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_k3b.py b/test/t/test_k3b.py
new file mode 100644
index 0000000..61b6a4d
--- /dev/null
+++ b/test/t/test_k3b.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestK3b:
+ @pytest.mark.complete("k3b ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("k3b -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_kcov.py b/test/t/test_kcov.py
new file mode 100644
index 0000000..3e377eb
--- /dev/null
+++ b/test/t/test_kcov.py
@@ -0,0 +1,16 @@
+import pytest
+
+
+class TestKcov:
+ @pytest.mark.complete("kcov ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("kcov --exclude-patter", require_cmd=True)
+ def test_2(self, completion):
+ assert completion == "n="
+ assert completion.endswith("=")
+
+ @pytest.mark.complete("kcov -l 42,")
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_kdvi.py b/test/t/test_kdvi.py
new file mode 100644
index 0000000..c2ab011
--- /dev/null
+++ b/test/t/test_kdvi.py
@@ -0,0 +1,10 @@
+import pytest
+
+
+class TestKdvi:
+ @pytest.mark.complete("kdvi ", cwd="kdvi")
+ def test_1(self, completion):
+ assert completion == sorted(
+ "foo/ .dvi .DVI .dvi.bz2 .DVI.bz2 .dvi.gz "
+ ".DVI.gz .dvi.Z .DVI.Z".split()
+ )
diff --git a/test/t/test_kill.py b/test/t/test_kill.py
new file mode 100644
index 0000000..9699435
--- /dev/null
+++ b/test/t/test_kill.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestKill:
+ @pytest.mark.complete("kill 1", xfail="! type ps &>/dev/null")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("kill -s ")
+ def test_2(self, completion):
+ assert all(x in completion for x in "HUP QUIT".split())
+
+ @pytest.mark.complete("kill -")
+ def test_3(self, completion):
+ assert all("-%s" % x in completion for x in "l s ABRT USR1".split())
diff --git a/test/t/test_killall.py b/test/t/test_killall.py
new file mode 100644
index 0000000..4b67d96
--- /dev/null
+++ b/test/t/test_killall.py
@@ -0,0 +1,21 @@
+import pytest
+
+
+class TestKillall:
+
+ # "p": Assume our process name completion runs ps and at least it is shown
+ @pytest.mark.complete("killall p")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("killall --signal ")
+ def test_2(self, completion):
+ assert all(x in completion for x in "INT KILL TERM".split())
+
+ @pytest.mark.complete("killall ")
+ def test_3(self, completion):
+ assert "command=" not in completion
+
+ @pytest.mark.complete("killall -", require_cmd=True)
+ def test_4(self, completion):
+ assert completion
diff --git a/test/t/test_kldload.py b/test/t/test_kldload.py
new file mode 100644
index 0000000..2965e44
--- /dev/null
+++ b/test/t/test_kldload.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestKldload:
+ @pytest.mark.complete("kldload ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_kldunload.py b/test/t/test_kldunload.py
new file mode 100644
index 0000000..a52c99e
--- /dev/null
+++ b/test/t/test_kldunload.py
@@ -0,0 +1,16 @@
+import subprocess
+
+import pytest
+
+
+class TestKldunload:
+ @pytest.mark.complete("kldunload ")
+ def test_1(self, completion):
+ try:
+ subprocess.check_call(
+ r"kldstat 2>/dev/null | command grep -q '\.ko$'", shell=True
+ )
+ except BaseException:
+ assert not completion
+ else:
+ assert completion
diff --git a/test/t/test_koji.py b/test/t/test_koji.py
new file mode 100644
index 0000000..73d3e4c
--- /dev/null
+++ b/test/t/test_koji.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestKoji:
+ @pytest.mark.complete("koji ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("koji -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_kpdf.py b/test/t/test_kpdf.py
new file mode 100644
index 0000000..68b36fe
--- /dev/null
+++ b/test/t/test_kpdf.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestKpdf:
+ @pytest.mark.complete("kpdf ", cwd="kpdf")
+ def test_1(self, completion):
+ assert completion == sorted("foo/ .eps .ps .EPS .PS .pdf .PDF".split())
diff --git a/test/t/test_kplayer.py b/test/t/test_kplayer.py
new file mode 100644
index 0000000..ef8a08e
--- /dev/null
+++ b/test/t/test_kplayer.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestKplayer:
+ @pytest.mark.complete("kplayer ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ktutil.py b/test/t/test_ktutil.py
new file mode 100644
index 0000000..7c90b80
--- /dev/null
+++ b/test/t/test_ktutil.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestKtutil:
+ @pytest.mark.complete("ktutil ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ktutil -")
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_l2ping.py b/test/t/test_l2ping.py
new file mode 100644
index 0000000..c50651b
--- /dev/null
+++ b/test/t/test_l2ping.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestL2ping:
+ @pytest.mark.complete("l2ping -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_larch.py b/test/t/test_larch.py
new file mode 100644
index 0000000..e68183c
--- /dev/null
+++ b/test/t/test_larch.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLarch:
+ @pytest.mark.complete("larch library-")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lastlog.py b/test/t/test_lastlog.py
new file mode 100644
index 0000000..31a855f
--- /dev/null
+++ b/test/t/test_lastlog.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLastlog:
+ @pytest.mark.complete("lastlog -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ld.py b/test/t/test_ld.py
new file mode 100644
index 0000000..f6a16bb
--- /dev/null
+++ b/test/t/test_ld.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestLd:
+ @pytest.mark.complete("ld ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ld -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_ldapadd.py b/test/t/test_ldapadd.py
new file mode 100644
index 0000000..24aa5e3
--- /dev/null
+++ b/test/t/test_ldapadd.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLdapadd:
+ @pytest.mark.complete("ldapadd -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ldapcompare.py b/test/t/test_ldapcompare.py
new file mode 100644
index 0000000..6a3afe9
--- /dev/null
+++ b/test/t/test_ldapcompare.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLdapcompare:
+ @pytest.mark.complete("ldapcompare -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ldapdelete.py b/test/t/test_ldapdelete.py
new file mode 100644
index 0000000..2065d9b
--- /dev/null
+++ b/test/t/test_ldapdelete.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLdapdelete:
+ @pytest.mark.complete("ldapdelete -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ldapmodrdn.py b/test/t/test_ldapmodrdn.py
new file mode 100644
index 0000000..da8bdbd
--- /dev/null
+++ b/test/t/test_ldapmodrdn.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLdapmodrdn:
+ @pytest.mark.complete("ldapmodrdn -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ldappasswd.py b/test/t/test_ldappasswd.py
new file mode 100644
index 0000000..e559f23
--- /dev/null
+++ b/test/t/test_ldappasswd.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLdappasswd:
+ @pytest.mark.complete("ldappasswd -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ldapsearch.py b/test/t/test_ldapsearch.py
new file mode 100644
index 0000000..43797f4
--- /dev/null
+++ b/test/t/test_ldapsearch.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLdapsearch:
+ @pytest.mark.complete("ldapsearch -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ldapvi.py b/test/t/test_ldapvi.py
new file mode 100644
index 0000000..5e65fc4
--- /dev/null
+++ b/test/t/test_ldapvi.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLdapvi:
+ @pytest.mark.complete("ldapvi -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ldapwhoami.py b/test/t/test_ldapwhoami.py
new file mode 100644
index 0000000..9dcfb5f
--- /dev/null
+++ b/test/t/test_ldapwhoami.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLdapwhoami:
+ @pytest.mark.complete("ldapwhoami -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ldd.py b/test/t/test_ldd.py
new file mode 100644
index 0000000..7f7201b
--- /dev/null
+++ b/test/t/test_ldd.py
@@ -0,0 +1,13 @@
+import pytest
+
+
+class TestLdd:
+ @pytest.mark.complete("ldd ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "ldd -", require_cmd=True, xfail="! ldd --help &>/dev/null"
+ )
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_less.py b/test/t/test_less.py
new file mode 100644
index 0000000..70833c3
--- /dev/null
+++ b/test/t/test_less.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestLess:
+ @pytest.mark.complete("less --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("less --", require_longopt=True)
+ def test_no_dashdashdash(self, completion):
+ assert all(not x.startswith("---") for x in completion)
diff --git a/test/t/test_lftp.py b/test/t/test_lftp.py
new file mode 100644
index 0000000..f775a4c
--- /dev/null
+++ b/test/t/test_lftp.py
@@ -0,0 +1,16 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("HOME=$PWD/lftp",))
+class TestLftp:
+ @pytest.mark.complete("lftp ", require_cmd=True)
+ def test_1(self, bash, completion, output_sort_uniq):
+ hosts = output_sort_uniq("compgen -A hostname")
+ assert all(x in completion for x in hosts)
+ # defined in lftp/.lftp/bookmarks
+ assert all(x in completion for x in "lftptest spacetest".split())
+ assert "badbookmark" not in completion
+
+ @pytest.mark.complete("lftp -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_lftpget.py b/test/t/test_lftpget.py
new file mode 100644
index 0000000..c1f453e
--- /dev/null
+++ b/test/t/test_lftpget.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLftpget:
+ @pytest.mark.complete("lftpget -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lilo.py b/test/t/test_lilo.py
new file mode 100644
index 0000000..2c69821
--- /dev/null
+++ b/test/t/test_lilo.py
@@ -0,0 +1,16 @@
+import pytest
+
+
+class TestLilo:
+ @pytest.mark.complete("lilo -")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("lilo -C lilo/lilo.conf -D ")
+ def test_labels(self, completion):
+ # Note that 2.4.33 should not be here, it's commented out
+ assert completion == sorted("try tamu PCDOS WinXP oldDOS".split())
+
+ @pytest.mark.complete("lilo -C -D ")
+ def test_labels_incorrect_command(self, completion):
+ assert not completion
diff --git a/test/t/test_links.py b/test/t/test_links.py
new file mode 100644
index 0000000..0806813
--- /dev/null
+++ b/test/t/test_links.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestLinks:
+ @pytest.mark.complete("links ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("links -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_lintian.py b/test/t/test_lintian.py
new file mode 100644
index 0000000..c652642
--- /dev/null
+++ b/test/t/test_lintian.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLintian:
+ @pytest.mark.complete("lintian --")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lintian_info.py b/test/t/test_lintian_info.py
new file mode 100644
index 0000000..bf9afc5
--- /dev/null
+++ b/test/t/test_lintian_info.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="lintian-info")
+class TestLintianInfo:
+ @pytest.mark.complete("lintian-info ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("lintian-info --", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_lisp.py b/test/t/test_lisp.py
new file mode 100644
index 0000000..8477061
--- /dev/null
+++ b/test/t/test_lisp.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLisp:
+ @pytest.mark.complete("lisp ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_list_admins.py b/test/t/test_list_admins.py
new file mode 100644
index 0000000..b65387e
--- /dev/null
+++ b/test/t/test_list_admins.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestListAdmins:
+ @pytest.mark.complete("list_admins -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_list_lists.py b/test/t/test_list_lists.py
new file mode 100644
index 0000000..966ca25
--- /dev/null
+++ b/test/t/test_list_lists.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestListLists:
+ @pytest.mark.complete("list_lists -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_list_members.py b/test/t/test_list_members.py
new file mode 100644
index 0000000..96ea2ef
--- /dev/null
+++ b/test/t/test_list_members.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestListMembers:
+ @pytest.mark.complete("list_members -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_list_owners.py b/test/t/test_list_owners.py
new file mode 100644
index 0000000..2a6bcab
--- /dev/null
+++ b/test/t/test_list_owners.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("PATH=/usr/lib/mailman/bin:$PATH",))
+class TestListOwners:
+ @pytest.mark.complete("list_owners -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ln.py b/test/t/test_ln.py
new file mode 100644
index 0000000..6bf809c
--- /dev/null
+++ b/test/t/test_ln.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestLn:
+ @pytest.mark.complete("ln ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ln -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_locale_gen.py b/test/t/test_locale_gen.py
new file mode 100644
index 0000000..caffb06
--- /dev/null
+++ b/test/t/test_locale_gen.py
@@ -0,0 +1,13 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="locale-gen")
+class TestLocaleGen:
+ # require_cmd is not strictly true here, but...
+ @pytest.mark.complete("locale-gen ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("locale-gen --", require_longopt=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_look.py b/test/t/test_look.py
new file mode 100644
index 0000000..fd6800e
--- /dev/null
+++ b/test/t/test_look.py
@@ -0,0 +1,16 @@
+import subprocess
+
+import pytest
+
+
+class TestLook:
+ @pytest.mark.complete("look foo")
+ def test_1(self, completion):
+ try:
+ subprocess.check_call(
+ "look foo 2>/dev/null | command grep -q ^foo", shell=True
+ )
+ except BaseException:
+ assert not completion
+ else:
+ assert completion
diff --git a/test/t/test_lpq.py b/test/t/test_lpq.py
new file mode 100644
index 0000000..0d69270
--- /dev/null
+++ b/test/t/test_lpq.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLpq:
+ @pytest.mark.complete("lpq ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lpr.py b/test/t/test_lpr.py
new file mode 100644
index 0000000..30c710b
--- /dev/null
+++ b/test/t/test_lpr.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLpr:
+ @pytest.mark.complete("lpr ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lrzip.py b/test/t/test_lrzip.py
new file mode 100644
index 0000000..d61ee9d
--- /dev/null
+++ b/test/t/test_lrzip.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestLrzip:
+ @pytest.mark.complete("lrzip ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("lrzip ~")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("lrzip -", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_ls.py b/test/t/test_ls.py
new file mode 100644
index 0000000..8abcb59
--- /dev/null
+++ b/test/t/test_ls.py
@@ -0,0 +1,40 @@
+import pytest
+
+from conftest import (
+ assert_bash_exec,
+ assert_complete,
+ find_unique_completion_pair,
+)
+
+
+class TestLs:
+ @pytest.mark.complete(
+ "ls --", require_cmd=True, xfail="! ls --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ls ~")
+ def test_2(self, completion):
+ assert completion
+
+ def test_3(self, bash):
+ """~part should complete to ~full<SPACE> if home dir does not exist."""
+ res = (
+ assert_bash_exec(
+ bash,
+ "for u in $(compgen -u); do "
+ "eval test -d ~$u || echo $u; unset u; done",
+ want_output=True,
+ )
+ .strip()
+ .split()
+ )
+ part_full = find_unique_completion_pair(res)
+ if not part_full:
+ pytest.skip("No suitable test user found")
+ return
+ part, full = part_full
+ completion = assert_complete(bash, "ls ~%s" % part)
+ assert completion == full[len(part) :]
+ assert completion.endswith(" ")
diff --git a/test/t/test_lsof.py b/test/t/test_lsof.py
new file mode 100644
index 0000000..170d269
--- /dev/null
+++ b/test/t/test_lsof.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestLsof:
+ @pytest.mark.complete("lsof ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("lsof -")
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_lspci.py b/test/t/test_lspci.py
new file mode 100644
index 0000000..aba7b5a
--- /dev/null
+++ b/test/t/test_lspci.py
@@ -0,0 +1,13 @@
+import pytest
+
+
+class TestLspci:
+ @pytest.mark.complete("lspci -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "lspci -A ", require_cmd=True, skipif="! lspci -A help &>/dev/null"
+ )
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_lsscsi.py b/test/t/test_lsscsi.py
new file mode 100644
index 0000000..fe01ac1
--- /dev/null
+++ b/test/t/test_lsscsi.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestLsscsi:
+ @pytest.mark.complete("lsscsi ")
+ def test_1(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("lsscsi -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_lsusb.py b/test/t/test_lsusb.py
new file mode 100644
index 0000000..c68d046
--- /dev/null
+++ b/test/t/test_lsusb.py
@@ -0,0 +1,10 @@
+import pytest
+
+
+class TestLsusb:
+ @pytest.mark.complete(
+ "lsusb -",
+ xfail="! (lsusb --help 2>&1 || :) | command grep -qF -- --help",
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lua.py b/test/t/test_lua.py
new file mode 100644
index 0000000..54c2432
--- /dev/null
+++ b/test/t/test_lua.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestLua:
+ @pytest.mark.complete("lua ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("lua -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_luac.py b/test/t/test_luac.py
new file mode 100644
index 0000000..28dc0e8
--- /dev/null
+++ b/test/t/test_luac.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestLuac:
+ @pytest.mark.complete("luac ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("luac -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_luseradd.py b/test/t/test_luseradd.py
new file mode 100644
index 0000000..4f1bec9
--- /dev/null
+++ b/test/t/test_luseradd.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLuseradd:
+ @pytest.mark.complete("luseradd -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_luserdel.py b/test/t/test_luserdel.py
new file mode 100644
index 0000000..ad88557
--- /dev/null
+++ b/test/t/test_luserdel.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestLuserdel:
+ @pytest.mark.complete("luserdel ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("luserdel -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_lusermod.py b/test/t/test_lusermod.py
new file mode 100644
index 0000000..69ef07c
--- /dev/null
+++ b/test/t/test_lusermod.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLusermod:
+ @pytest.mark.complete("lusermod ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lvchange.py b/test/t/test_lvchange.py
new file mode 100644
index 0000000..3e4feda
--- /dev/null
+++ b/test/t/test_lvchange.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestLvchange:
+ @pytest.mark.complete(
+ "lvchange --", require_cmd=True, xfail="! lvchange --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lvcreate.py b/test/t/test_lvcreate.py
new file mode 100644
index 0000000..636f625
--- /dev/null
+++ b/test/t/test_lvcreate.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestLvcreate:
+ @pytest.mark.complete(
+ "lvcreate --", require_cmd=True, xfail="! lvcreate --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lvdisplay.py b/test/t/test_lvdisplay.py
new file mode 100644
index 0000000..5210662
--- /dev/null
+++ b/test/t/test_lvdisplay.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestLvdisplay:
+ @pytest.mark.complete(
+ "lvdisplay --",
+ require_cmd=True,
+ xfail="! lvdisplay --help &>/dev/null",
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lvextend.py b/test/t/test_lvextend.py
new file mode 100644
index 0000000..4daa888
--- /dev/null
+++ b/test/t/test_lvextend.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestLvextend:
+ @pytest.mark.complete(
+ "lvextend --", require_cmd=True, xfail="! lvextend --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lvm.py b/test/t/test_lvm.py
new file mode 100644
index 0000000..ea25b97
--- /dev/null
+++ b/test/t/test_lvm.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestLvm:
+ @pytest.mark.complete("lvm pv")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lvmdiskscan.py b/test/t/test_lvmdiskscan.py
new file mode 100644
index 0000000..1b334b8
--- /dev/null
+++ b/test/t/test_lvmdiskscan.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestLvmdiskscan:
+ @pytest.mark.complete(
+ "lvmdiskscan --",
+ require_cmd=True,
+ xfail="! lvmdiskscan --help &>/dev/null",
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lvreduce.py b/test/t/test_lvreduce.py
new file mode 100644
index 0000000..3b614cb
--- /dev/null
+++ b/test/t/test_lvreduce.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestLvreduce:
+ @pytest.mark.complete(
+ "lvreduce --", require_cmd=True, xfail="! lvreduce --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lvremove.py b/test/t/test_lvremove.py
new file mode 100644
index 0000000..17486aa
--- /dev/null
+++ b/test/t/test_lvremove.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestLvremove:
+ @pytest.mark.complete(
+ "lvremove --", require_cmd=True, xfail="! lvremove --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lvrename.py b/test/t/test_lvrename.py
new file mode 100644
index 0000000..802b72e
--- /dev/null
+++ b/test/t/test_lvrename.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestLvrename:
+ @pytest.mark.complete(
+ "lvrename --", require_cmd=True, xfail="! lvrename --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lvresize.py b/test/t/test_lvresize.py
new file mode 100644
index 0000000..bb71feb
--- /dev/null
+++ b/test/t/test_lvresize.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestLvresize:
+ @pytest.mark.complete(
+ "lvresize --", require_cmd=True, xfail="! lvresize --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lvs.py b/test/t/test_lvs.py
new file mode 100644
index 0000000..eadc8df
--- /dev/null
+++ b/test/t/test_lvs.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestLvs:
+ @pytest.mark.complete(
+ "lvs --", require_cmd=True, xfail="! lvs --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lvscan.py b/test/t/test_lvscan.py
new file mode 100644
index 0000000..a2867b0
--- /dev/null
+++ b/test/t/test_lvscan.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestLvscan:
+ @pytest.mark.complete(
+ "lvscan --", require_cmd=True, xfail="! lvscan --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_lz4.py b/test/t/test_lz4.py
new file mode 100644
index 0000000..0e1208c
--- /dev/null
+++ b/test/t/test_lz4.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestLz4:
+ @pytest.mark.complete("lz4 ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("lz4 ~")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("lz4 -", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_lzip.py b/test/t/test_lzip.py
new file mode 100644
index 0000000..b0313be
--- /dev/null
+++ b/test/t/test_lzip.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestLzip:
+ @pytest.mark.complete("lzip ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("lzip -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_lzma.py b/test/t/test_lzma.py
new file mode 100644
index 0000000..f9d8992
--- /dev/null
+++ b/test/t/test_lzma.py
@@ -0,0 +1,19 @@
+import pytest
+
+
+class TestLzma:
+ @pytest.mark.complete("lzma ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("lzma -")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("lzma -d xz/")
+ def test_3(self, completion):
+ assert completion == "a/ bashcomp.lzma bashcomp.tlz".split()
+
+ @pytest.mark.complete("lzma ~")
+ def test_4(self, completion):
+ assert completion
diff --git a/test/t/test_lzop.py b/test/t/test_lzop.py
new file mode 100644
index 0000000..bd010fd
--- /dev/null
+++ b/test/t/test_lzop.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestLzop:
+ @pytest.mark.complete("lzop ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("lzop ~")
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_m4.py b/test/t/test_m4.py
new file mode 100644
index 0000000..7ecd774
--- /dev/null
+++ b/test/t/test_m4.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestM4:
+ @pytest.mark.complete(
+ "m4 --", require_cmd=True, xfail="! m4 --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_macof.py b/test/t/test_macof.py
new file mode 100644
index 0000000..17f0eae
--- /dev/null
+++ b/test/t/test_macof.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMacof:
+ @pytest.mark.complete("macof -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_mailmanctl.py b/test/t/test_mailmanctl.py
new file mode 100644
index 0000000..2baa050
--- /dev/null
+++ b/test/t/test_mailmanctl.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("PATH=/usr/lib/mailman/bin:$PATH",))
+class TestMailmanctl:
+ @pytest.mark.complete("mailmanctl ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_mailsnarf.py b/test/t/test_mailsnarf.py
new file mode 100644
index 0000000..0dc3e04
--- /dev/null
+++ b/test/t/test_mailsnarf.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMailsnarf:
+ @pytest.mark.complete("mailsnarf -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_make.py b/test/t/test_make.py
new file mode 100644
index 0000000..19861b0
--- /dev/null
+++ b/test/t/test_make.py
@@ -0,0 +1,47 @@
+import os
+
+import pytest
+
+
+class TestMake:
+ @pytest.mark.complete("make -f Ma", cwd="make")
+ def test_1(self, completion):
+ assert completion == "kefile"
+
+ @pytest.mark.complete("make .", cwd="make", require_cmd=True)
+ def test_2(self, bash, completion):
+ """Hidden targets."""
+ assert completion == ".cache/ .test_passes".split()
+ os.remove("%s/make/%s" % (bash.cwd, "extra_makefile"))
+
+ @pytest.mark.complete("make .cache/", cwd="make", require_cmd=True)
+ def test_3(self, bash, completion):
+ assert completion == "1 2".split()
+ os.remove("%s/make/%s" % (bash.cwd, "extra_makefile"))
+
+ @pytest.mark.complete("make ", cwd="shared/empty_dir")
+ def test_4(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("make -j ")
+ def test_5(self, completion):
+ assert completion
+
+ @pytest.mark.complete("make ", cwd="make", require_cmd=True)
+ def test_6(self, bash, completion):
+ assert completion == "all clean extra_makefile install sample".split()
+ os.remove("%s/make/%s" % (bash.cwd, "extra_makefile"))
+
+ @pytest.mark.complete("make .cache/.", cwd="make", require_cmd=True)
+ def test_7(self, bash, completion):
+ assert completion == ".1 .2".split()
+ os.remove("%s/make/%s" % (bash.cwd, "extra_makefile"))
+
+ @pytest.mark.complete("make -C make ", require_cmd=True)
+ def test_8(self, bash, completion):
+ assert completion == "all clean extra_makefile install sample".split()
+ os.remove("%s/make/%s" % (bash.cwd, "extra_makefile"))
+
+ @pytest.mark.complete("make -", require_cmd=True)
+ def test_9(self, completion):
+ assert completion
diff --git a/test/t/test_makepkg.py b/test/t/test_makepkg.py
new file mode 100644
index 0000000..f643a29
--- /dev/null
+++ b/test/t/test_makepkg.py
@@ -0,0 +1,17 @@
+import pytest
+
+
+@pytest.mark.bashcomp(
+ ignore_env=r"^-declare -f _makepkg_bootstrap$",
+ xfail="! makepkg --help 2>&1 | command grep -qiF slackware",
+)
+class TestMakepkg:
+ @pytest.mark.complete("makepkg ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("makepkg --", require_cmd=True)
+ def test_2(self, completion):
+ assert all(
+ x in completion for x in "--chown --linkadd --prepend".split()
+ )
diff --git a/test/t/test_man.py b/test/t/test_man.py
new file mode 100644
index 0000000..1ff9f84
--- /dev/null
+++ b/test/t/test_man.py
@@ -0,0 +1,115 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+@pytest.mark.bashcomp(
+ ignore_env=r"^[+-]((BASHOPTS|MANPATH)=|shopt -. failglob)"
+)
+class TestMan:
+
+ manpath = "$PWD/man"
+ assumed_present = "man"
+
+ @pytest.fixture
+ def colonpath(self, request, bash):
+ try:
+ assert_bash_exec(bash, "uname -s 2>&1 | grep -qiF cygwin")
+ except AssertionError:
+ pass
+ else:
+ pytest.skip("Cygwin doesn't like paths with colons")
+ return
+ assert_bash_exec(bash, "mkdir -p $TESTDIR/../tmp/man/man3")
+ assert_bash_exec(
+ bash, "touch $TESTDIR/../tmp/man/man3/Bash::Completion.3pm.gz"
+ )
+ request.addfinalizer(
+ lambda: assert_bash_exec(bash, "rm -r $TESTDIR/../tmp/man")
+ )
+
+ @pytest.mark.complete(
+ "man bash-completion-testcas",
+ env=dict(MANPATH=manpath),
+ require_cmd=True,
+ )
+ def test_1(self, completion):
+ assert completion == "e"
+
+ @pytest.mark.complete("man man1/f", cwd="man", env=dict(MANPATH=manpath))
+ def test_2(self, completion):
+ assert completion == "oo.1"
+
+ @pytest.mark.complete("man man/", cwd="man", env=dict(MANPATH=manpath))
+ def test_3(self, completion):
+ assert completion == "quux.8"
+
+ @pytest.mark.complete(
+ "man %s" % assumed_present,
+ cwd="shared/empty_dir",
+ env=dict(MANPATH=manpath),
+ )
+ def test_4(self, completion):
+ """
+ Assumed present should not be completed complete when there's no
+ leading/trailing colon in $MANPATH.
+ """
+ assert not completion
+
+ @pytest.mark.complete(
+ "man %s" % assumed_present,
+ require_cmd=True,
+ cwd="shared/empty_dir",
+ env=dict(MANPATH="%s:" % manpath),
+ )
+ def test_5(self, completion):
+ """Trailing colon appends system man path."""
+ assert completion
+
+ @pytest.mark.complete(
+ "man bash-completion-testcas",
+ require_cmd=True,
+ env=dict(MANPATH="%s:" % manpath),
+ )
+ def test_6(self, completion):
+ assert completion == "e"
+
+ @pytest.mark.complete(
+ "man %s" % assumed_present,
+ require_cmd=True,
+ cwd="shared/empty_dir",
+ env=dict(MANPATH=":%s" % manpath),
+ )
+ def test_7(self, completion):
+ """Leading colon prepends system man path."""
+ assert completion
+
+ @pytest.mark.complete(
+ "man bash-completion-testcas",
+ require_cmd=True,
+ env=dict(MANPATH=":%s" % manpath),
+ )
+ def test_8(self, completion):
+ assert completion == "e"
+
+ @pytest.mark.complete(
+ "man %s" % assumed_present,
+ require_cmd=True,
+ cwd="shared/empty_dir",
+ pre_cmds=("shopt -s failglob",),
+ )
+ def test_9(self, bash, completion):
+ assert self.assumed_present in completion
+ assert_bash_exec(bash, "shopt -u failglob")
+
+ @pytest.mark.complete(
+ "man Bash::C",
+ require_cmd=True,
+ env=dict(MANPATH="%s:../tmp/man" % manpath),
+ )
+ def test_10(self, bash, colonpath, completion):
+ assert completion == "ompletion"
+
+ @pytest.mark.complete("man -", require_cmd=True)
+ def test_11(self, completion):
+ assert completion
diff --git a/test/t/test_mc.py b/test/t/test_mc.py
new file mode 100644
index 0000000..31f88b7
--- /dev/null
+++ b/test/t/test_mc.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMc:
+ @pytest.mark.complete("mc -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_mcrypt.py b/test/t/test_mcrypt.py
new file mode 100644
index 0000000..d11f446
--- /dev/null
+++ b/test/t/test_mcrypt.py
@@ -0,0 +1,19 @@
+import pytest
+
+
+class TestMcrypt:
+ @pytest.mark.complete("mcrypt ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mcrypt -a ", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mcrypt -m ", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mcrypt -", require_cmd=True)
+ def test_4(self, completion):
+ assert completion
diff --git a/test/t/test_md5sum.py b/test/t/test_md5sum.py
new file mode 100644
index 0000000..0a3286a
--- /dev/null
+++ b/test/t/test_md5sum.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestMd5sum:
+ @pytest.mark.complete("md5sum ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("md5sum -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_mdadm.py b/test/t/test_mdadm.py
new file mode 100644
index 0000000..143007b
--- /dev/null
+++ b/test/t/test_mdadm.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMdadm:
+ @pytest.mark.complete("mdadm ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_mdecrypt.py b/test/t/test_mdecrypt.py
new file mode 100644
index 0000000..f6f4c8e
--- /dev/null
+++ b/test/t/test_mdecrypt.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMdecrypt:
+ @pytest.mark.complete("mdecrypt ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_mdtool.py b/test/t/test_mdtool.py
new file mode 100644
index 0000000..356e907
--- /dev/null
+++ b/test/t/test_mdtool.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMdtool:
+ @pytest.mark.complete("mdtool ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_medusa.py b/test/t/test_medusa.py
new file mode 100644
index 0000000..87fb91b
--- /dev/null
+++ b/test/t/test_medusa.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMedusa:
+ @pytest.mark.complete("medusa -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_mencoder.py b/test/t/test_mencoder.py
new file mode 100644
index 0000000..a17fb96
--- /dev/null
+++ b/test/t/test_mencoder.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("HOME=$PWD/mplayer",))
+class TestMencoder:
+ @pytest.mark.complete("mencoder ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mencoder -v", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_mii_diag.py b/test/t/test_mii_diag.py
new file mode 100644
index 0000000..6ed96aa
--- /dev/null
+++ b/test/t/test_mii_diag.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="mii-diag")
+class TestMiiDiag:
+ @pytest.mark.complete("mii-diag ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mii-diag -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_mii_tool.py b/test/t/test_mii_tool.py
new file mode 100644
index 0000000..f028787
--- /dev/null
+++ b/test/t/test_mii_tool.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="mii-tool")
+class TestMiiTool:
+ @pytest.mark.complete("mii-tool ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mii-tool -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_minicom.py b/test/t/test_minicom.py
new file mode 100644
index 0000000..6fac457
--- /dev/null
+++ b/test/t/test_minicom.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMinicom:
+ @pytest.mark.complete("minicom -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_mkdir.py b/test/t/test_mkdir.py
new file mode 100644
index 0000000..afc3fd0
--- /dev/null
+++ b/test/t/test_mkdir.py
@@ -0,0 +1,21 @@
+import pytest
+
+
+class TestMkdir:
+ @pytest.mark.complete("mkdir ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mkdir ", cwd="shared/default")
+ def test_2(self, completion):
+ assert completion == ["bar", "bar bar.d/", "foo", "foo.d/"]
+
+ @pytest.mark.xfail # TODO: why path in completion, basename in .output?
+ @pytest.mark.complete("mkdir shared/default/foo.d/")
+ def test_3(self, completion):
+ assert completion.output == "foo"
+ assert completion == [completion.output]
+
+ @pytest.mark.complete("mkdir -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_mkfifo.py b/test/t/test_mkfifo.py
new file mode 100644
index 0000000..92e82de
--- /dev/null
+++ b/test/t/test_mkfifo.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestMkfifo:
+ @pytest.mark.complete("mkfifo ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mkfifo -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_mkinitrd.py b/test/t/test_mkinitrd.py
new file mode 100644
index 0000000..7305925
--- /dev/null
+++ b/test/t/test_mkinitrd.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMkinitrd:
+ @pytest.mark.complete("mkinitrd ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_mkisofs.py b/test/t/test_mkisofs.py
new file mode 100644
index 0000000..541c6e7
--- /dev/null
+++ b/test/t/test_mkisofs.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestMkisofs:
+ @pytest.mark.complete("mkisofs ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mkisofs -uid ")
+ def test_2(self, completion):
+ assert not [x for x in completion if not x.isdigit()]
+
+ @pytest.mark.complete("mkisofs -gid ")
+ def test_3(self, completion):
+ assert not [x for x in completion if not x.isdigit()]
diff --git a/test/t/test_mknod.py b/test/t/test_mknod.py
new file mode 100644
index 0000000..03f21e8
--- /dev/null
+++ b/test/t/test_mknod.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestMknod:
+ @pytest.mark.complete("mknod ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mknod -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_mktemp.py b/test/t/test_mktemp.py
new file mode 100644
index 0000000..9f61be1
--- /dev/null
+++ b/test/t/test_mktemp.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMktemp:
+ @pytest.mark.complete("mktemp -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_mmsitepass.py b/test/t/test_mmsitepass.py
new file mode 100644
index 0000000..4dcd9fb
--- /dev/null
+++ b/test/t/test_mmsitepass.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMmsitepass:
+ @pytest.mark.complete("mmsitepass -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_mock.py b/test/t/test_mock.py
new file mode 100644
index 0000000..5f9eb3e
--- /dev/null
+++ b/test/t/test_mock.py
@@ -0,0 +1,13 @@
+import pytest
+
+
+class TestMock:
+ @pytest.mark.complete("mock ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "mock -", require_cmd=True, xfail="! mock --help &>/dev/null"
+ )
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_modinfo.py b/test/t/test_modinfo.py
new file mode 100644
index 0000000..a4f5c50
--- /dev/null
+++ b/test/t/test_modinfo.py
@@ -0,0 +1,32 @@
+import subprocess
+
+import pytest
+
+
+class TestModinfo:
+ @pytest.mark.complete("modinfo -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ # "in": intel*, ...
+ @pytest.mark.complete(
+ "modinfo in",
+ xfail="! ls /lib/modules/%s &>/dev/null"
+ % subprocess.check_output(
+ "uname -r 2>/dev/null || " "echo non-existent-kernel", shell=True
+ )
+ .decode()
+ .strip(),
+ )
+ def test_2(self, completion):
+ assert completion
+
+ # "in": intel*, ...
+ @pytest.mark.complete("modinfo -k non-existent-kernel in")
+ def test_3(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("modinfo /tm")
+ def test_4(self, completion):
+ assert completion
+ assert not completion.endswith(" ")
diff --git a/test/t/test_modprobe.py b/test/t/test_modprobe.py
new file mode 100644
index 0000000..9201119
--- /dev/null
+++ b/test/t/test_modprobe.py
@@ -0,0 +1,36 @@
+import subprocess
+
+import pytest
+
+
+class TestModprobe:
+ @pytest.mark.complete("modprobe --al")
+ def test_1(self, completion):
+ assert completion == "l"
+
+ # "in": intel*, ...
+ @pytest.mark.complete(
+ "modprobe in",
+ xfail="! ls /lib/modules/%s &>/dev/null"
+ % subprocess.check_output(
+ "uname -r 2>/dev/null || " "echo non-existent-kernel", shell=True
+ )
+ .decode()
+ .strip(),
+ )
+ def test_2(self, completion):
+ assert completion
+
+ # "in": intel*, ...
+ @pytest.mark.complete("modprobe -S non-existent-kernel in")
+ def test_3(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("modprobe non-existent-module ")
+ def test_4(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("modprobe /tm")
+ def test_5(self, completion):
+ assert completion
+ assert not completion.endswith(" ")
diff --git a/test/t/test_module.py b/test/t/test_module.py
new file mode 100644
index 0000000..a66dea7
--- /dev/null
+++ b/test/t/test_module.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestModule:
+ @pytest.mark.complete("module ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_mogrify.py b/test/t/test_mogrify.py
new file mode 100644
index 0000000..22d84a8
--- /dev/null
+++ b/test/t/test_mogrify.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMogrify:
+ @pytest.mark.complete("mogrify ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_monodevelop.py b/test/t/test_monodevelop.py
new file mode 100644
index 0000000..59435a1
--- /dev/null
+++ b/test/t/test_monodevelop.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestMonodevelop:
+ @pytest.mark.complete("monodevelop ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("monodevelop -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_montage.py b/test/t/test_montage.py
new file mode 100644
index 0000000..1237c7d
--- /dev/null
+++ b/test/t/test_montage.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMontage:
+ @pytest.mark.complete("montage ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_mount.py b/test/t/test_mount.py
new file mode 100644
index 0000000..8254fd4
--- /dev/null
+++ b/test/t/test_mount.py
@@ -0,0 +1,22 @@
+import pytest
+
+
+class TestMount:
+ @pytest.mark.complete("mount ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mount -t ")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mount /dev/sda1 def", cwd="shared")
+ def test_3(self, completion):
+ assert completion == "ault/"
+ assert not completion.endswith(" ")
+
+ @pytest.mark.complete(
+ "mount mocksrv:/", env=dict(PATH="$PWD/mount/bin:$PATH")
+ )
+ def test_4(self, completion):
+ assert completion == "/second/path /test/path /test/path2".split()
diff --git a/test/t/test_mplayer.py b/test/t/test_mplayer.py
new file mode 100644
index 0000000..a06991b
--- /dev/null
+++ b/test/t/test_mplayer.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("HOME=$PWD/mplayer",))
+class TestMplayer:
+ @pytest.mark.complete("mplayer ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mplayer -h", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_mr.py b/test/t/test_mr.py
new file mode 100644
index 0000000..bfad643
--- /dev/null
+++ b/test/t/test_mr.py
@@ -0,0 +1,58 @@
+import pytest
+
+
+class TestMr:
+ @pytest.mark.complete("mr ")
+ def test_1(self, completion):
+ assert completion
+
+ # man -h tests below: Some mr versions require man to be around in order
+ # to provide useful output.
+
+ @pytest.mark.complete(
+ "mr --", require_cmd=True, xfail="! man -h &>/dev/null"
+ )
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "mr -c shared/default/foo.d/", xfail="! man -h &>/dev/null"
+ )
+ def test_3(self, completion):
+ assert completion == "foo"
+
+ @pytest.mark.complete(
+ "mr bootstrap shared/default/",
+ require_cmd=True,
+ xfail="! man -h &>/dev/null",
+ )
+ def test_4(self, completion):
+ assert completion == ["bar", "bar bar.d/", "foo", "foo.d/"]
+
+ @pytest.mark.complete(
+ "mr clean -",
+ require_cmd=True,
+ xfail="! man -h &>/dev/null",
+ # "clean" does not exist before mr 1.20141023
+ skipif="! mr help 2>&1 | command grep -qwF clean",
+ )
+ def test_5(self, completion):
+ assert completion == "f"
+
+ @pytest.mark.complete(
+ "mr commit -", require_cmd=True, xfail="! man -h &>/dev/null"
+ )
+ def test_6(self, completion):
+ assert completion == "m"
+
+ @pytest.mark.complete(
+ "mr status ", require_cmd=True, xfail="! man -h &>/dev/null"
+ )
+ def test_7(self, completion):
+ assert not completion
+
+ @pytest.mark.complete(
+ "mr run ", require_cmd=True, xfail="! man -h &>/dev/null"
+ )
+ def test_8(self, completion):
+ assert completion
diff --git a/test/t/test_msgsnarf.py b/test/t/test_msgsnarf.py
new file mode 100644
index 0000000..7484456
--- /dev/null
+++ b/test/t/test_msgsnarf.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMsgsnarf:
+ @pytest.mark.complete("msgsnarf -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_msynctool.py b/test/t/test_msynctool.py
new file mode 100644
index 0000000..530d751
--- /dev/null
+++ b/test/t/test_msynctool.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMsynctool:
+ @pytest.mark.complete("msynctool ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_mtx.py b/test/t/test_mtx.py
new file mode 100644
index 0000000..6b6f59b
--- /dev/null
+++ b/test/t/test_mtx.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMtx:
+ @pytest.mark.complete("mtx ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_munin_node_configure.py b/test/t/test_munin_node_configure.py
new file mode 100644
index 0000000..e7570d8
--- /dev/null
+++ b/test/t/test_munin_node_configure.py
@@ -0,0 +1,19 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="munin-node-configure")
+class TestMuninNodeConfigure:
+ @pytest.mark.complete("munin-node-configure --libdir ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "munin-node-configure -",
+ require_cmd=True,
+ xfail=(
+ "! (munin-node-configure --help 2>&1 || :) "
+ "| command grep -q -- '[[:space:]]-'"
+ ),
+ )
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_munin_run.py b/test/t/test_munin_run.py
new file mode 100644
index 0000000..a031449
--- /dev/null
+++ b/test/t/test_munin_run.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="munin-run")
+class TestMuninRun:
+ @pytest.mark.complete("munin-run -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_munindoc.py b/test/t/test_munindoc.py
new file mode 100644
index 0000000..eea13ca
--- /dev/null
+++ b/test/t/test_munindoc.py
@@ -0,0 +1,10 @@
+import pytest
+
+
+class TestMunindoc:
+
+ # Assume at least munin* available
+ # require_cmd is not strictly correct here, but...
+ @pytest.mark.complete("munindoc m", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_mussh.py b/test/t/test_mussh.py
new file mode 100644
index 0000000..357c2b5
--- /dev/null
+++ b/test/t/test_mussh.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMussh:
+ @pytest.mark.complete("mussh -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_mutt.py b/test/t/test_mutt.py
new file mode 100644
index 0000000..0c4074f
--- /dev/null
+++ b/test/t/test_mutt.py
@@ -0,0 +1,33 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+@pytest.mark.bashcomp(pre_cmds=("HOME=$PWD/mutt",))
+class TestMutt:
+ @pytest.mark.complete("mutt -")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mutt -F muttrc -f =", require_cmd=True, cwd="mutt")
+ def test_2(self, completion):
+ assert completion == "bar/ foo/ muttrc".split()
+
+ @pytest.mark.complete("mutt -F muttrc -A ", cwd="mutt")
+ def test_3(self, completion):
+ assert completion == "a1 a2".split()
+
+ def test_4(self, bash):
+ got = (
+ assert_bash_exec(
+ bash,
+ '_muttconffiles "$HOME/muttrc" "$HOME/muttrc"',
+ want_output=True,
+ )
+ .strip()
+ .split()
+ )
+ assert got == [
+ "%s/mutt/%s" % (bash.cwd, x)
+ for x in ("muttrc", "bar/muttrc_b", "foo/muttrc_f")
+ ]
diff --git a/test/t/test_muttng.py b/test/t/test_muttng.py
new file mode 100644
index 0000000..3ce19ac
--- /dev/null
+++ b/test/t/test_muttng.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMuttng:
+ @pytest.mark.complete("muttng -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_mv.py b/test/t/test_mv.py
new file mode 100644
index 0000000..4a354db
--- /dev/null
+++ b/test/t/test_mv.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestMv:
+ @pytest.mark.complete("mv ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mv -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_mypy.py b/test/t/test_mypy.py
new file mode 100644
index 0000000..11628c1
--- /dev/null
+++ b/test/t/test_mypy.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestMypy:
+ @pytest.mark.complete("mypy ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mypy --", require_cmd=True, require_longopt=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mypy --non-existent-option=--")
+ def test_3(self, completion):
+ assert not completion
diff --git a/test/t/test_mysql.py b/test/t/test_mysql.py
new file mode 100644
index 0000000..6a44b7e
--- /dev/null
+++ b/test/t/test_mysql.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestMysql:
+ @pytest.mark.complete("mysql --")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mysql --default-character-set=")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("mysql --non-existent-option=--")
+ def test_3(self, completion):
+ assert not completion
diff --git a/test/t/test_mysqladmin.py b/test/t/test_mysqladmin.py
new file mode 100644
index 0000000..85046fe
--- /dev/null
+++ b/test/t/test_mysqladmin.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestMysqladmin:
+ @pytest.mark.complete("mysqladmin -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_nc.py b/test/t/test_nc.py
new file mode 100644
index 0000000..38db5ac
--- /dev/null
+++ b/test/t/test_nc.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestNc:
+ @pytest.mark.complete("nc -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ncftp.py b/test/t/test_ncftp.py
new file mode 100644
index 0000000..b37f48f
--- /dev/null
+++ b/test/t/test_ncftp.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestNcftp:
+ @pytest.mark.complete("ncftp ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ncftp -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_nethogs.py b/test/t/test_nethogs.py
new file mode 100644
index 0000000..c57185f
--- /dev/null
+++ b/test/t/test_nethogs.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestNethogs:
+ @pytest.mark.complete("nethogs ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("nethogs -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_netstat.py b/test/t/test_netstat.py
new file mode 100644
index 0000000..57ef26c
--- /dev/null
+++ b/test/t/test_netstat.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestNetstat:
+ @pytest.mark.complete("netstat ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("netstat -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_newgrp.py b/test/t/test_newgrp.py
new file mode 100644
index 0000000..7d65a16
--- /dev/null
+++ b/test/t/test_newgrp.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestNewgrp:
+ @pytest.mark.complete("newgrp ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_newlist.py b/test/t/test_newlist.py
new file mode 100644
index 0000000..1d6b439
--- /dev/null
+++ b/test/t/test_newlist.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestNewlist:
+ @pytest.mark.complete("newlist -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_newusers.py b/test/t/test_newusers.py
new file mode 100644
index 0000000..51d746a
--- /dev/null
+++ b/test/t/test_newusers.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestNewusers:
+ @pytest.mark.complete("newusers ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("newusers -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_ngrep.py b/test/t/test_ngrep.py
new file mode 100644
index 0000000..53fa60d
--- /dev/null
+++ b/test/t/test_ngrep.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestNgrep:
+ @pytest.mark.complete("ngrep -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ngrep -d ")
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_nl.py b/test/t/test_nl.py
new file mode 100644
index 0000000..ca910a5
--- /dev/null
+++ b/test/t/test_nl.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestNl:
+ @pytest.mark.complete("nl ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("nl -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_nm.py b/test/t/test_nm.py
new file mode 100644
index 0000000..328fa50
--- /dev/null
+++ b/test/t/test_nm.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestNm:
+ @pytest.mark.complete("nm ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("nm -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_nmap.py b/test/t/test_nmap.py
new file mode 100644
index 0000000..9aff8b2
--- /dev/null
+++ b/test/t/test_nmap.py
@@ -0,0 +1,47 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+class TestNmap:
+ @pytest.fixture(scope="class")
+ def functions(self, request, bash):
+ assert_bash_exec(bash, "_mock_nmap() { cat nmap/nmap-h.txt; }")
+ assert_bash_exec(bash, "complete -F _nmap _mock_nmap")
+
+ @pytest.mark.complete("nmap --v", require_cmd=True)
+ def test_live_options(self, completion):
+ assert completion
+
+ @pytest.mark.complete("nmap ")
+ def test_hosts(self, completion):
+ assert completion
+
+ @pytest.mark.complete("_mock_nmap -")
+ def test_mock_options(self, completion, functions):
+ assert completion == sorted(
+ "-iL -iR --exclude --excludefile -sL -sn -Pn -PS -PA -PU -PY -PE "
+ "-PP -PM -PO -n -R --dns-servers --system-dns --traceroute -sS "
+ "-sT -sA -sW -sM -sU -sN -sF -sX --scanflags -sI -sY -sZ -sO -b "
+ "-p --exclude-ports -F -r --top-ports --port-ratio -sV "
+ "--version-intensity --version-light --version-all "
+ "--version-trace -sC --script= --script-args= --script-args-file= "
+ "--script-trace --script-updatedb --script-help= -O "
+ "--osscan-limit --osscan-guess "
+ # TODO: -T known mishandled; should expand -T<0-5> to -T0 ... -T5
+ "-T --min-hostgroup --max-hostgroup --min-parallelism "
+ "--max-parallelism --min-rtt-timeout --max-rtt-timeout "
+ "--initial-rtt-timeout --max-retries --host-timeout --scan-delay "
+ "--max-scan-delay --min-rate --max-rate -f --mtu -D -S -e -g "
+ "--source-port --proxies --data --data-string --data-length "
+ "--ip-options --ttl --spoof-mac --badsum -oN -oX -oS -oG -oA -v "
+ "-d --reason --open --packet-trace --iflist --append-output "
+ "--resume --stylesheet --webxml --no-stylesheet -6 -A --datadir "
+ "--send-eth --send-ip --privileged --unprivileged -V -h"
+ "".strip().split()
+ )
+
+ @pytest.mark.complete("_mock_nmap --script-args-f")
+ def test_mock_nospace(self, completion, functions):
+ assert completion == "ile="
+ assert completion.endswith("=") # no space appended
diff --git a/test/t/test_nmcli.py b/test/t/test_nmcli.py
new file mode 100644
index 0000000..f2b7950
--- /dev/null
+++ b/test/t/test_nmcli.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestNmcli:
+ @pytest.mark.complete("nmcli ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_nproc.py b/test/t/test_nproc.py
new file mode 100644
index 0000000..66a49ac
--- /dev/null
+++ b/test/t/test_nproc.py
@@ -0,0 +1,17 @@
+import pytest
+
+
+class TestNproc:
+ @pytest.mark.complete("nproc ")
+ def test_1(self, completion):
+ assert not completion
+
+ @pytest.mark.complete(
+ "nproc --",
+ xfail=(
+ "! nproc --help &>/dev/null || "
+ "! nproc --help 2>&1 | command grep -qF -- --help"
+ ),
+ )
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_nslookup.py b/test/t/test_nslookup.py
new file mode 100644
index 0000000..0286509
--- /dev/null
+++ b/test/t/test_nslookup.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestNslookup:
+ @pytest.mark.complete("nslookup -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_nsupdate.py b/test/t/test_nsupdate.py
new file mode 100644
index 0000000..b8a133c
--- /dev/null
+++ b/test/t/test_nsupdate.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestNsupdate:
+ @pytest.mark.complete("nsupdate ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("nsupdate -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_ntpdate.py b/test/t/test_ntpdate.py
new file mode 100644
index 0000000..c8d65cf
--- /dev/null
+++ b/test/t/test_ntpdate.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestNtpdate:
+ @pytest.mark.complete("ntpdate -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_objcopy.py b/test/t/test_objcopy.py
new file mode 100644
index 0000000..e3130fa
--- /dev/null
+++ b/test/t/test_objcopy.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestObjcopy:
+ @pytest.mark.complete("objcopy ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("objcopy -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_objdump.py b/test/t/test_objdump.py
new file mode 100644
index 0000000..6b8bc74
--- /dev/null
+++ b/test/t/test_objdump.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestObjdump:
+ @pytest.mark.complete("objdump ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_od.py b/test/t/test_od.py
new file mode 100644
index 0000000..e2f5de2
--- /dev/null
+++ b/test/t/test_od.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestOd:
+ @pytest.mark.complete("od ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("od -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_oggdec.py b/test/t/test_oggdec.py
new file mode 100644
index 0000000..395bb86
--- /dev/null
+++ b/test/t/test_oggdec.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestOggdec:
+ @pytest.mark.complete("oggdec ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("oggdec --", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_op.py b/test/t/test_op.py
new file mode 100644
index 0000000..662cde5
--- /dev/null
+++ b/test/t/test_op.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestOp:
+ @pytest.mark.complete("op ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("op --", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_openssl.py b/test/t/test_openssl.py
new file mode 100644
index 0000000..3eaf6d4
--- /dev/null
+++ b/test/t/test_openssl.py
@@ -0,0 +1,16 @@
+import pytest
+
+
+class TestOpenssl:
+ @pytest.mark.complete("openssl ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("openssl pkey -cipher ", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("openssl dgst -s", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
+ assert any(x.startswith("-sha") for x in completion)
diff --git a/test/t/test_opera.py b/test/t/test_opera.py
new file mode 100644
index 0000000..f0c657e
--- /dev/null
+++ b/test/t/test_opera.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestOpera:
+ @pytest.mark.complete("opera ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("opera -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_optipng.py b/test/t/test_optipng.py
new file mode 100644
index 0000000..615d71f
--- /dev/null
+++ b/test/t/test_optipng.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestOptipng:
+ @pytest.mark.complete("optipng ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("optipng -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_p4.py b/test/t/test_p4.py
new file mode 100644
index 0000000..876d261
--- /dev/null
+++ b/test/t/test_p4.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestP4:
+ @pytest.mark.complete("p4 ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pack200.py b/test/t/test_pack200.py
new file mode 100644
index 0000000..0960133
--- /dev/null
+++ b/test/t/test_pack200.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestPack200:
+ @pytest.mark.complete("pack200 ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_passwd.py b/test/t/test_passwd.py
new file mode 100644
index 0000000..f253701
--- /dev/null
+++ b/test/t/test_passwd.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPasswd:
+ @pytest.mark.complete("passwd ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("passwd -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_paste.py b/test/t/test_paste.py
new file mode 100644
index 0000000..ecf030b
--- /dev/null
+++ b/test/t/test_paste.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPaste:
+ @pytest.mark.complete("paste ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("paste -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_patch.py b/test/t/test_patch.py
new file mode 100644
index 0000000..c68a4b6
--- /dev/null
+++ b/test/t/test_patch.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPatch:
+ @pytest.mark.complete("patch ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("patch -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_pdftotext.py b/test/t/test_pdftotext.py
new file mode 100644
index 0000000..90d001f
--- /dev/null
+++ b/test/t/test_pdftotext.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPdftotext:
+ @pytest.mark.complete("pdftotext ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pdftotext -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_perl.py b/test/t/test_perl.py
new file mode 100644
index 0000000..049c91e
--- /dev/null
+++ b/test/t/test_perl.py
@@ -0,0 +1,91 @@
+import pytest
+
+
+@pytest.mark.bashcomp(ignore_env=r"^\+PERL5LIB=")
+class TestPerl:
+ @pytest.mark.complete("perl ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("perl -e ")
+ def test_2(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("perl -V:install", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
+
+ @pytest.mark.complete("perl -V::install", require_cmd=True)
+ def test_4(self, completion):
+ assert completion
+
+ # Assume File::Spec and friends are always installed
+
+ @pytest.mark.complete("perl -MFile", require_cmd=True)
+ def test_5(self, completion):
+ assert completion
+
+ @pytest.mark.complete("perl -MFile::Sp", require_cmd=True)
+ def test_6(self, completion):
+ assert completion
+
+ @pytest.mark.complete("perl -MFile::Spec::Func", require_cmd=True)
+ def test_7(self, completion):
+ assert completion
+
+ @pytest.mark.complete("perl -M-File", require_cmd=True)
+ def test_8(self, completion):
+ assert completion
+
+ @pytest.mark.complete("perl -m-File::", require_cmd=True)
+ def test_9(self, completion):
+ assert completion
+
+ @pytest.mark.complete("perl -")
+ def test_10(self, completion):
+ assert completion
+
+ @pytest.mark.complete("perl foo shared/default/f")
+ def test_11(self, completion):
+ """Second arg should complete files+dirs."""
+ assert completion == "foo foo.d/".split()
+
+ @pytest.mark.complete("perl -Ishared/default/")
+ def test_12(self, completion):
+ """-I without space should complete dirs."""
+ assert completion == ["bar bar.d/", "foo.d/"]
+
+ @pytest.mark.complete("perl -I shared/default/")
+ def test_13(self, completion):
+ """-I with space should complete dirs."""
+ assert completion == ["bar bar.d/", "foo.d/"]
+
+ @pytest.mark.complete("perl -xshared/default/b")
+ def test_14(self, completion):
+ """-x without space should complete dirs."""
+ assert completion == r"ar\ bar.d/"
+
+ @pytest.mark.complete("perl -x shared/default/b")
+ def test_15(self, completion):
+ """-x with space should complete files+dirs."""
+ assert completion == ["bar", "bar bar.d/"]
+
+ @pytest.mark.complete(
+ "perl -d:", env=dict(PERL5LIB="$PWD/perl"), require_cmd=True
+ )
+ def test_16(self, completion):
+ assert "BashCompletion" in completion
+
+ @pytest.mark.complete(
+ "perl -dt:", env=dict(PERL5LIB="$PWD/perl"), require_cmd=True
+ )
+ def test_17(self, completion):
+ assert "BashCompletion" in completion
+
+ @pytest.mark.complete("perl -E ")
+ def test_dash_capital_e(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("perl -e")
+ def test_dash_e(self, completion):
+ assert not completion
diff --git a/test/t/test_perlcritic.py b/test/t/test_perlcritic.py
new file mode 100644
index 0000000..51ba201
--- /dev/null
+++ b/test/t/test_perlcritic.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestPerlcritic:
+ @pytest.mark.complete("perlcritic ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("perlcritic --", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("perlcritic --theme ", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_perldoc.py b/test/t/test_perldoc.py
new file mode 100644
index 0000000..282f824
--- /dev/null
+++ b/test/t/test_perldoc.py
@@ -0,0 +1,18 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("export PERL5LIB=$PWD/perldoc",))
+class TestPerldoc:
+ @pytest.mark.complete("perldoc File::")
+ def test_1(self, completion):
+ assert "Path" in completion # Assume File::Path always installed
+ assert "fixtures/" not in completion # Our fixtures/ dir
+ assert not [x for x in completion if "File::File::" in x]
+
+ @pytest.mark.complete("perldoc -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("perldoc BashCompletion")
+ def test_3(self, completion):
+ assert completion == "BashCompletionDoc BashCompletionModule".split()
diff --git a/test/t/test_perltidy.py b/test/t/test_perltidy.py
new file mode 100644
index 0000000..578923a
--- /dev/null
+++ b/test/t/test_perltidy.py
@@ -0,0 +1,19 @@
+import pytest
+
+
+class TestPerltidy:
+ @pytest.mark.complete("perltidy ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("perltidy -h", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("perltidy -ole=", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
+
+ @pytest.mark.complete("perltidy -doesntexist=", require_cmd=True)
+ def test_4(self, completion):
+ assert not completion
diff --git a/test/t/test_pgrep.py b/test/t/test_pgrep.py
new file mode 100644
index 0000000..9a998ed
--- /dev/null
+++ b/test/t/test_pgrep.py
@@ -0,0 +1,35 @@
+import pytest
+
+
+class TestPgrep:
+
+ # "p": Assume that our process name completion runs ps
+ @pytest.mark.complete("pgrep p")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pgrep -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "pgrep --nslist ",
+ require_cmd=True,
+ skipif=(
+ "! pgrep --help 2>&1 | command grep -qF 'Available namespaces'"
+ ),
+ )
+ def test_nslist(self, completion):
+ assert completion
+ assert not any("," in x for x in completion)
+
+ @pytest.mark.complete(
+ "pgrep --nslist foo,",
+ require_cmd=True,
+ skipif=(
+ "! pgrep --help 2>&1 | command grep -qF 'Available namespaces'"
+ ),
+ )
+ def test_nslist_after_comma(self, completion):
+ assert completion
+ assert not any("," in x for x in completion)
diff --git a/test/t/test_phing.py b/test/t/test_phing.py
new file mode 100644
index 0000000..973a957
--- /dev/null
+++ b/test/t/test_phing.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPhing:
+ @pytest.mark.complete("phing -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("phing -l ", require_cmd=True)
+ def test_2(self, completion):
+ assert not completion
diff --git a/test/t/test_pidof.py b/test/t/test_pidof.py
new file mode 100644
index 0000000..c33a4d3
--- /dev/null
+++ b/test/t/test_pidof.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestPidof:
+
+ # "p": Assume that our process name completion runs ps
+ @pytest.mark.complete("pidof p")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "pidof -", require_cmd=True, xfail="! pidof --help &>/dev/null"
+ )
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_pine.py b/test/t/test_pine.py
new file mode 100644
index 0000000..0c95973
--- /dev/null
+++ b/test/t/test_pine.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestPine:
+ @pytest.mark.complete("pine -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pinfo.py b/test/t/test_pinfo.py
new file mode 100644
index 0000000..a22128e
--- /dev/null
+++ b/test/t/test_pinfo.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("INFOPATH+=:$PWD/info:",))
+class TestPinfo:
+ @pytest.mark.complete("pinfo -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pinfo bash")
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_ping.py b/test/t/test_ping.py
new file mode 100644
index 0000000..f70582a
--- /dev/null
+++ b/test/t/test_ping.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPing:
+ @pytest.mark.complete("ping ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ping -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_pkg_config.py b/test/t/test_pkg_config.py
new file mode 100644
index 0000000..81e02ca
--- /dev/null
+++ b/test/t/test_pkg_config.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="pkg-config")
+class TestPkgConfig:
+ @pytest.mark.complete("pkg-config ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pkg-config -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_pkg_deinstall.py b/test/t/test_pkg_deinstall.py
new file mode 100644
index 0000000..5ce6d13
--- /dev/null
+++ b/test/t/test_pkg_deinstall.py
@@ -0,0 +1,15 @@
+import os
+
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("PKG_DBDIR=$PWD/pkgtools/db",))
+class TestPkgDeinstall:
+ @pytest.mark.complete("pkg_deinstall ")
+ def test_1(self, completion):
+ dirs = sorted(
+ x
+ for x in os.listdir("pkgtools/db")
+ if os.path.isdir("pkgtools/db/%s" % x)
+ )
+ assert completion == dirs
diff --git a/test/t/test_pkg_delete.py b/test/t/test_pkg_delete.py
new file mode 100644
index 0000000..a4b0d85
--- /dev/null
+++ b/test/t/test_pkg_delete.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestPkgDelete:
+ @pytest.mark.complete("pkg_delete ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pkg_get.py b/test/t/test_pkg_get.py
new file mode 100644
index 0000000..cb2d283
--- /dev/null
+++ b/test/t/test_pkg_get.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="pkg-get")
+class TestPkgGet:
+ @pytest.mark.complete("pkg-get ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pkg_info.py b/test/t/test_pkg_info.py
new file mode 100644
index 0000000..6011f81
--- /dev/null
+++ b/test/t/test_pkg_info.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestPkgInfo:
+ @pytest.mark.complete("pkg_info ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pkgadd.py b/test/t/test_pkgadd.py
new file mode 100644
index 0000000..69d08dc
--- /dev/null
+++ b/test/t/test_pkgadd.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+class TestPkgadd:
+ # require_cmd is not strictly true here, but...
+ @pytest.mark.complete("pkgadd ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pkgrm.py b/test/t/test_pkgrm.py
new file mode 100644
index 0000000..2af81ef
--- /dev/null
+++ b/test/t/test_pkgrm.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+class TestPkgrm:
+ # require_cmd is not strictly true here, but...
+ @pytest.mark.complete("pkgrm ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pkgtool.py b/test/t/test_pkgtool.py
new file mode 100644
index 0000000..7d35637
--- /dev/null
+++ b/test/t/test_pkgtool.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestPkgtool:
+ @pytest.mark.complete("pkgtool -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pkgutil.py b/test/t/test_pkgutil.py
new file mode 100644
index 0000000..9664728
--- /dev/null
+++ b/test/t/test_pkgutil.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestPkgutil:
+ @pytest.mark.complete("pkgutil ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pkill.py b/test/t/test_pkill.py
new file mode 100644
index 0000000..a779958
--- /dev/null
+++ b/test/t/test_pkill.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPkill:
+ @pytest.mark.complete("pkill ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pkill -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_plague_client.py b/test/t/test_plague_client.py
new file mode 100644
index 0000000..39eac93
--- /dev/null
+++ b/test/t/test_plague_client.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="plague-client")
+class TestPlagueClient:
+ @pytest.mark.complete("plague-client ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pm_hibernate.py b/test/t/test_pm_hibernate.py
new file mode 100644
index 0000000..31b4625
--- /dev/null
+++ b/test/t/test_pm_hibernate.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="pm-hibernate")
+class TestPmHibernate:
+ @pytest.mark.complete("pm-hibernate -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pm_is_supported.py b/test/t/test_pm_is_supported.py
new file mode 100644
index 0000000..47f064a
--- /dev/null
+++ b/test/t/test_pm_is_supported.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="pm-is-supported")
+class TestPmIsSupported:
+ @pytest.mark.complete("pm-is-supported -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pm_powersave.py b/test/t/test_pm_powersave.py
new file mode 100644
index 0000000..7630a41
--- /dev/null
+++ b/test/t/test_pm_powersave.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="pm-powersave")
+class TestPmPowersave:
+ @pytest.mark.complete("pm-powersave ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pngfix.py b/test/t/test_pngfix.py
new file mode 100644
index 0000000..9b35a39
--- /dev/null
+++ b/test/t/test_pngfix.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPngfix:
+ @pytest.mark.complete("pngfix ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pngfix -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_portinstall.py b/test/t/test_portinstall.py
new file mode 100644
index 0000000..eb2118e
--- /dev/null
+++ b/test/t/test_portinstall.py
@@ -0,0 +1,27 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+@pytest.mark.bashcomp(ignore_env=r"^[+-]PORTSDIR=")
+class TestPortinstall:
+ @pytest.fixture(scope="class")
+ def portsdir(self, request, bash):
+ assert_bash_exec(bash, "PORTSDIR=$PWD/../tmp")
+ assert_bash_exec(
+ bash,
+ "command sed -e s,PORTSDIR,$PORTSDIR,g "
+ "pkgtools/ports/INDEX.dist >$PORTSDIR/INDEX",
+ )
+ assert_bash_exec(bash, "cp $PORTSDIR/INDEX $PORTSDIR/INDEX-5")
+ request.addfinalizer(
+ lambda: assert_bash_exec(bash, "rm $PORTSDIR/INDEX{,-5}")
+ )
+
+ @pytest.mark.complete("portinstall ", env=dict(PORTSDIR="$PWD/../tmp"))
+ def test_1(self, completion, portsdir):
+ assert (
+ completion
+ == "bash-2.05b.007_6 bash-3.1.17 bash-completion-20060301_2 "
+ "shells/bash shells/bash-completion shells/bash2".split()
+ )
diff --git a/test/t/test_portsnap.py b/test/t/test_portsnap.py
new file mode 100644
index 0000000..4f5878e
--- /dev/null
+++ b/test/t/test_portsnap.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestPortsnap:
+ @pytest.mark.complete("portsnap ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_portupgrade.py b/test/t/test_portupgrade.py
new file mode 100644
index 0000000..0b46bbf
--- /dev/null
+++ b/test/t/test_portupgrade.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("PKG_DBDIR=$PWD/pkgtools/db",))
+class TestPortupgrade:
+ @pytest.mark.complete("portupgrade ")
+ def test_1(self, completion):
+ assert completion == "a b-c-d".split()
diff --git a/test/t/test_postcat.py b/test/t/test_postcat.py
new file mode 100644
index 0000000..73922e2
--- /dev/null
+++ b/test/t/test_postcat.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPostcat:
+ @pytest.mark.complete("postcat ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("postcat -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_postconf.py b/test/t/test_postconf.py
new file mode 100644
index 0000000..e034956
--- /dev/null
+++ b/test/t/test_postconf.py
@@ -0,0 +1,20 @@
+import pytest
+
+
+class TestPostconf:
+ @pytest.mark.complete("postconf -", require_cmd=True)
+ def test_1(self, completion):
+ assert len(completion) > 1
+
+ # Broken configs may abort output of postconf halfway through, so use
+ # something from early output to not trigger false positives because of
+ # this. For example, inet_protocols=all but no IPv6 configured:
+ # postconf: fatal: parameter inet_interfaces: no local interface found
+ # for ::1
+ # ...and output can be cut off somewhere near lmtp_tls_secur*.
+ # ...or be completely missing, so all we can do is to skip.
+ @pytest.mark.complete(
+ "postconf al", require_cmd=True, xfail="! postconf &>/dev/null"
+ )
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_postfix.py b/test/t/test_postfix.py
new file mode 100644
index 0000000..10020b0
--- /dev/null
+++ b/test/t/test_postfix.py
@@ -0,0 +1,22 @@
+import getpass
+
+import pytest
+
+
+class TestPostfix:
+ @pytest.mark.complete("postfix ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.xfail(
+ getpass.getuser() != "root",
+ reason="Likely outputs usage only for root",
+ )
+ @pytest.mark.complete(
+ "postfix -",
+ require_cmd=True,
+ xfail="! type unbuffer &>/dev/null",
+ sleep_after_tab=2, # postfix is slow to output usage
+ )
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_postmap.py b/test/t/test_postmap.py
new file mode 100644
index 0000000..ee3eee7
--- /dev/null
+++ b/test/t/test_postmap.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPostmap:
+ @pytest.mark.complete("postmap ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("postmap -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_postsuper.py b/test/t/test_postsuper.py
new file mode 100644
index 0000000..b74de8e
--- /dev/null
+++ b/test/t/test_postsuper.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestPostsuper:
+ @pytest.mark.complete("postsuper ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_povray.py b/test/t/test_povray.py
new file mode 100644
index 0000000..99d08ea
--- /dev/null
+++ b/test/t/test_povray.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestPovray:
+ @pytest.mark.complete("povray ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pr.py b/test/t/test_pr.py
new file mode 100644
index 0000000..c790a86
--- /dev/null
+++ b/test/t/test_pr.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPr:
+ @pytest.mark.complete("pr ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pr -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_prelink.py b/test/t/test_prelink.py
new file mode 100644
index 0000000..e75b969
--- /dev/null
+++ b/test/t/test_prelink.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPrelink:
+ @pytest.mark.complete("prelink ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("prelink -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_printenv.py b/test/t/test_printenv.py
new file mode 100644
index 0000000..540c4f6
--- /dev/null
+++ b/test/t/test_printenv.py
@@ -0,0 +1,19 @@
+import pytest
+
+
+class TestPrintenv:
+ @pytest.mark.complete("printenv ")
+ def test_empty(self, completion):
+ assert completion
+
+ @pytest.mark.complete("printenv PAT")
+ def test_path(self, completion):
+ assert completion == "H" or "PATH" in completion
+
+ @pytest.mark.complete(
+ "printenv -",
+ require_cmd=True,
+ xfail="! printenv --help 2>&1 | command grep -qF -- ' -'",
+ )
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_protoc.py b/test/t/test_protoc.py
new file mode 100644
index 0000000..744b99f
--- /dev/null
+++ b/test/t/test_protoc.py
@@ -0,0 +1,20 @@
+import pytest
+
+
+class TestProtoc:
+ @pytest.mark.complete("protoc ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("protoc -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+ assert any(
+ x.endswith("_out") or x.endswith("_out=") for x in completion
+ )
+
+ @pytest.mark.complete(
+ "protoc --non_existent_plugin_out ", cwd="shared/default"
+ )
+ def test_all_out(self, completion):
+ assert completion == ["bar bar.d/", "foo.d/"]
diff --git a/test/t/test_psql.py b/test/t/test_psql.py
new file mode 100644
index 0000000..ffd6c05
--- /dev/null
+++ b/test/t/test_psql.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPsql:
+
+ # --help can fail due to missing package dependencies, e.g. on Ubuntu 14
+ @pytest.mark.complete(
+ "psql -", require_cmd=True, xfail="! psql --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ptx.py b/test/t/test_ptx.py
new file mode 100644
index 0000000..9ddc91c
--- /dev/null
+++ b/test/t/test_ptx.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPtx:
+ @pytest.mark.complete("ptx ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ptx -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_puppet.py b/test/t/test_puppet.py
new file mode 100644
index 0000000..470f33a
--- /dev/null
+++ b/test/t/test_puppet.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPuppet:
+ @pytest.mark.complete("puppet ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("puppet agent --")
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_pushd.py b/test/t/test_pushd.py
new file mode 100644
index 0000000..290e1d1
--- /dev/null
+++ b/test/t/test_pushd.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestPushd:
+ @pytest.mark.complete("pushd ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pv.py b/test/t/test_pv.py
new file mode 100644
index 0000000..ad04c47
--- /dev/null
+++ b/test/t/test_pv.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestPv:
+ @pytest.mark.complete("pv ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pv -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pv --pidfile ")
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_pvchange.py b/test/t/test_pvchange.py
new file mode 100644
index 0000000..4b0a94c
--- /dev/null
+++ b/test/t/test_pvchange.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestPvchange:
+ @pytest.mark.complete(
+ "pvchange --", require_cmd=True, xfail="! pvchange --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pvcreate.py b/test/t/test_pvcreate.py
new file mode 100644
index 0000000..2847c47
--- /dev/null
+++ b/test/t/test_pvcreate.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestPvcreate:
+ @pytest.mark.complete(
+ "pvcreate --", require_cmd=True, xfail="! pvcreate --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pvdisplay.py b/test/t/test_pvdisplay.py
new file mode 100644
index 0000000..9d1ea83
--- /dev/null
+++ b/test/t/test_pvdisplay.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPvdisplay:
+ @pytest.mark.complete(
+ "pvdisplay --",
+ require_cmd=True,
+ xfail="! pvdisplay --help &>/dev/null",
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pvmove.py b/test/t/test_pvmove.py
new file mode 100644
index 0000000..e0e2ee8
--- /dev/null
+++ b/test/t/test_pvmove.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestPvmove:
+ @pytest.mark.complete(
+ "pvmove --", require_cmd=True, xfail="! pvmove --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pvremove.py b/test/t/test_pvremove.py
new file mode 100644
index 0000000..c9c031a
--- /dev/null
+++ b/test/t/test_pvremove.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestPvremove:
+ @pytest.mark.complete(
+ "pvremove --", require_cmd=True, xfail="! pvremove --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pvs.py b/test/t/test_pvs.py
new file mode 100644
index 0000000..ac173a7
--- /dev/null
+++ b/test/t/test_pvs.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestPvs:
+ @pytest.mark.complete(
+ "pvs --", require_cmd=True, xfail="! pvs --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pvscan.py b/test/t/test_pvscan.py
new file mode 100644
index 0000000..e278956
--- /dev/null
+++ b/test/t/test_pvscan.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestPvscan:
+ @pytest.mark.complete(
+ "pvscan --", require_cmd=True, xfail="! pvscan --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pwck.py b/test/t/test_pwck.py
new file mode 100644
index 0000000..1e36f87
--- /dev/null
+++ b/test/t/test_pwck.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPwck:
+ @pytest.mark.complete("pwck ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pwck -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_pwd.py b/test/t/test_pwd.py
new file mode 100644
index 0000000..fe7dd08
--- /dev/null
+++ b/test/t/test_pwd.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestPwd:
+ @pytest.mark.complete("pwd -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pwdx.py b/test/t/test_pwdx.py
new file mode 100644
index 0000000..552c82c
--- /dev/null
+++ b/test/t/test_pwdx.py
@@ -0,0 +1,19 @@
+import pytest
+
+
+class TestPwdx:
+ @pytest.mark.complete("pwdx ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "pwdx -",
+ require_cmd=True,
+ xfail=(
+ "! (pwdx --help 2>&1 || :) | "
+ "command grep -vF 'invalid process id: --help' | "
+ "command grep -q -- '[[:space:]]-'"
+ ),
+ )
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_pwgen.py b/test/t/test_pwgen.py
new file mode 100644
index 0000000..20ecd73
--- /dev/null
+++ b/test/t/test_pwgen.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestPwgen:
+ @pytest.mark.complete("pwgen -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_pycodestyle.py b/test/t/test_pycodestyle.py
new file mode 100644
index 0000000..4b4f3a4
--- /dev/null
+++ b/test/t/test_pycodestyle.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestPycodestyle:
+ @pytest.mark.complete("pycodestyle ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pycodestyle -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pycodestyle --doesnt-exist=")
+ def test_3(self, completion):
+ assert not completion
diff --git a/test/t/test_pydoc.py b/test/t/test_pydoc.py
new file mode 100644
index 0000000..7cf7eb5
--- /dev/null
+++ b/test/t/test_pydoc.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPydoc:
+ @pytest.mark.complete("pydoc r", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pydoc -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_pydocstyle.py b/test/t/test_pydocstyle.py
new file mode 100644
index 0000000..1f44320
--- /dev/null
+++ b/test/t/test_pydocstyle.py
@@ -0,0 +1,13 @@
+import pytest
+
+
+class TestPydocstyle:
+ @pytest.mark.complete("pydocstyle ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "pydocstyle -", require_cmd=True, require_longopt=True
+ )
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_pyflakes.py b/test/t/test_pyflakes.py
new file mode 100644
index 0000000..9670321
--- /dev/null
+++ b/test/t/test_pyflakes.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPyflakes:
+ @pytest.mark.complete("pyflakes ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pyflakes -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_pylint.py b/test/t/test_pylint.py
new file mode 100644
index 0000000..43a4c43
--- /dev/null
+++ b/test/t/test_pylint.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestPylint:
+ @pytest.mark.complete("pylint --v", require_cmd=True, require_longopt=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pylint --confidence=HIGH,")
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_pylint_3.py b/test/t/test_pylint_3.py
new file mode 100644
index 0000000..ee498c3
--- /dev/null
+++ b/test/t/test_pylint_3.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="pylint-3")
+class TestPylint3:
+ @pytest.mark.complete("pylint-3 --v", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pylint-3 http.clien")
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_pytest.py b/test/t/test_pytest.py
new file mode 100644
index 0000000..e70c7a5
--- /dev/null
+++ b/test/t/test_pytest.py
@@ -0,0 +1,50 @@
+import inspect
+
+import pytest
+
+
+class TestPytest:
+ @pytest.mark.complete("pytest ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pytest -")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("pytest ../t/test_pytest.py:")
+ def test_classes_and_functions(self, completion):
+ assert completion == ":TestPytest :test_function_canary".split()
+
+ @pytest.mark.complete("pytest ../t/test_pytest.py::TestPytest::")
+ def test_class_methods(self, completion):
+ methods = [
+ x[0]
+ for x in inspect.getmembers(self, predicate=inspect.ismethod)
+ if x[0].startswith("test_")
+ ]
+ assert completion == methods
+
+ @pytest.mark.complete("pytest pytest/test_async.py:")
+ def test_classes_and_async_functions(self, completion):
+ assert completion == ":Testing :test_positive".split()
+
+ @pytest.mark.complete("pytest pytest/test_async.py::Testing::")
+ def test_async_class_methods(self, completion):
+ assert completion == "test_positive"
+
+ def non_test_cananary_method(self):
+ pass
+
+
+def test_function_canary():
+ pass
+
+
+def non_test_canary():
+ pass
+
+
+class NonTestCanaryClass:
+ def test_is_this_function_not(self):
+ pass
diff --git a/test/t/test_python.py b/test/t/test_python.py
new file mode 100644
index 0000000..5308dcb
--- /dev/null
+++ b/test/t/test_python.py
@@ -0,0 +1,39 @@
+import pytest
+
+
+class TestPython:
+ @pytest.mark.complete("python ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("python -", require_cmd=True)
+ def test_2(self, completion):
+ assert len(completion) > 1
+
+ @pytest.mark.complete("python -c ")
+ def test_3(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("python shared/default/")
+ def test_4(self, completion):
+ assert completion == ["bar bar.d/", "foo.d/"]
+
+ @pytest.mark.complete("python -c foo shared/default/")
+ def test_5(self, completion):
+ assert completion == ["bar", "bar bar.d/", "foo", "foo.d/"]
+
+ @pytest.mark.complete("python -c foo -")
+ def test_6(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("python -m foo -")
+ def test_7(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("python -m sy", require_cmd=True)
+ def test_8(self, completion):
+ assert completion
+
+ @pytest.mark.complete("python -m json.", require_cmd=True)
+ def test_9(self, completion):
+ assert "json.tool" in completion
diff --git a/test/t/test_python3.py b/test/t/test_python3.py
new file mode 100644
index 0000000..a4f6d96
--- /dev/null
+++ b/test/t/test_python3.py
@@ -0,0 +1,39 @@
+import pytest
+
+
+class TestPython3:
+ @pytest.mark.complete("python3 ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("python3 -", require_cmd=True)
+ def test_2(self, completion):
+ assert len(completion) > 1
+
+ @pytest.mark.complete("python3 -c ")
+ def test_3(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("python3 shared/default/")
+ def test_4(self, completion):
+ assert completion == ["bar bar.d/", "foo.d/"]
+
+ @pytest.mark.complete("python3 -c foo shared/default/")
+ def test_5(self, completion):
+ assert completion == ["bar", "bar bar.d/", "foo", "foo.d/"]
+
+ @pytest.mark.complete("python3 -c foo -")
+ def test_6(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("python3 -m foo -")
+ def test_7(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("python3 -m sy", require_cmd=True)
+ def test_8(self, completion):
+ assert completion
+
+ @pytest.mark.complete("python3 -m json.", require_cmd=True)
+ def test_9(self, completion):
+ assert "json.tool" in completion
diff --git a/test/t/test_pyvenv.py b/test/t/test_pyvenv.py
new file mode 100644
index 0000000..5e9152a
--- /dev/null
+++ b/test/t/test_pyvenv.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestPyvenv:
+ @pytest.mark.complete("pyvenv ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_qemu.py b/test/t/test_qemu.py
new file mode 100644
index 0000000..129c0b4
--- /dev/null
+++ b/test/t/test_qemu.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestQemu:
+ @pytest.mark.complete("qemu ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("qemu -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_qrunner.py b/test/t/test_qrunner.py
new file mode 100644
index 0000000..4e4cdd8
--- /dev/null
+++ b/test/t/test_qrunner.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestQrunner:
+ @pytest.mark.complete("qrunner -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_querybts.py b/test/t/test_querybts.py
new file mode 100644
index 0000000..9c81d13
--- /dev/null
+++ b/test/t/test_querybts.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestQuerybts:
+ @pytest.mark.complete("querybts --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_quota.py b/test/t/test_quota.py
new file mode 100644
index 0000000..c744535
--- /dev/null
+++ b/test/t/test_quota.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestQuota:
+ @pytest.mark.complete("quota ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("quota -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_quotacheck.py b/test/t/test_quotacheck.py
new file mode 100644
index 0000000..8140604
--- /dev/null
+++ b/test/t/test_quotacheck.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestQuotacheck:
+ @pytest.mark.complete("quotacheck -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_quotaon.py b/test/t/test_quotaon.py
new file mode 100644
index 0000000..c4386c6
--- /dev/null
+++ b/test/t/test_quotaon.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestQuotaon:
+ @pytest.mark.complete("quotaon -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_radvdump.py b/test/t/test_radvdump.py
new file mode 100644
index 0000000..a8a16d9
--- /dev/null
+++ b/test/t/test_radvdump.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestRadvdump:
+ @pytest.mark.complete("radvdump ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("radvdump -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_rcs.py b/test/t/test_rcs.py
new file mode 100644
index 0000000..985bb44
--- /dev/null
+++ b/test/t/test_rcs.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestRcs:
+ @pytest.mark.complete("rcs ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_rcsdiff.py b/test/t/test_rcsdiff.py
new file mode 100644
index 0000000..d54934c
--- /dev/null
+++ b/test/t/test_rcsdiff.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestRcsdiff:
+ @pytest.mark.complete("rcsdiff ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_rdesktop.py b/test/t/test_rdesktop.py
new file mode 100644
index 0000000..f20ca51
--- /dev/null
+++ b/test/t/test_rdesktop.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestRdesktop:
+ @pytest.mark.complete("rdesktop -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_rdict.py b/test/t/test_rdict.py
new file mode 100644
index 0000000..da6fb1b
--- /dev/null
+++ b/test/t/test_rdict.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestRdict:
+ @pytest.mark.complete("rdict --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_readelf.py b/test/t/test_readelf.py
new file mode 100644
index 0000000..07ce347
--- /dev/null
+++ b/test/t/test_readelf.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestReadelf:
+ @pytest.mark.complete("readelf --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_readonly.py b/test/t/test_readonly.py
new file mode 100644
index 0000000..0ac310c
--- /dev/null
+++ b/test/t/test_readonly.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestReadonly:
+ @pytest.mark.complete("readonly BASH_ARG")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_remove_members.py b/test/t/test_remove_members.py
new file mode 100644
index 0000000..a3b0afd
--- /dev/null
+++ b/test/t/test_remove_members.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestRemoveMembers:
+ @pytest.mark.complete("remove_members --")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_removepkg.py b/test/t/test_removepkg.py
new file mode 100644
index 0000000..9fd7a9d
--- /dev/null
+++ b/test/t/test_removepkg.py
@@ -0,0 +1,15 @@
+import os
+
+import pytest
+
+
+@pytest.mark.bashcomp(ignore_env=r"^\+ROOT=")
+class TestRemovepkg:
+ @pytest.mark.complete("removepkg -")
+ def test_1(self, completion):
+ assert completion == "-copy -keep -preserve -warn".split()
+
+ @pytest.mark.complete("removepkg ", env=dict(ROOT="./slackware"))
+ def test_2(self, completion):
+ files = sorted(x for x in os.listdir("slackware/var/log/packages"))
+ assert completion == files
diff --git a/test/t/test_renice.py b/test/t/test_renice.py
new file mode 100644
index 0000000..20d59a3
--- /dev/null
+++ b/test/t/test_renice.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestRenice:
+ @pytest.mark.complete("renice 1")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("renice -g ")
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_repomanage.py b/test/t/test_repomanage.py
new file mode 100644
index 0000000..bdaba15
--- /dev/null
+++ b/test/t/test_repomanage.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestRepomanage:
+ @pytest.mark.complete("repomanage ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("repomanage -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_reportbug.py b/test/t/test_reportbug.py
new file mode 100644
index 0000000..2c57b56
--- /dev/null
+++ b/test/t/test_reportbug.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestReportbug:
+ @pytest.mark.complete("reportbug --m", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_reptyr.py b/test/t/test_reptyr.py
new file mode 100644
index 0000000..7c27cb5
--- /dev/null
+++ b/test/t/test_reptyr.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestReptyr:
+ @pytest.mark.complete("reptyr ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("reptyr -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_resolvconf.py b/test/t/test_resolvconf.py
new file mode 100644
index 0000000..fdcf584
--- /dev/null
+++ b/test/t/test_resolvconf.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestResolvconf:
+ @pytest.mark.complete("resolvconf -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_rfcomm.py b/test/t/test_rfcomm.py
new file mode 100644
index 0000000..c30d23b
--- /dev/null
+++ b/test/t/test_rfcomm.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestRfcomm:
+ @pytest.mark.complete("rfcomm ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_rfkill.py b/test/t/test_rfkill.py
new file mode 100644
index 0000000..f8248ff
--- /dev/null
+++ b/test/t/test_rfkill.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestRfkill:
+ @pytest.mark.complete("rfkill ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("rfkill -")
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_ri.py b/test/t/test_ri.py
new file mode 100644
index 0000000..420b6cb
--- /dev/null
+++ b/test/t/test_ri.py
@@ -0,0 +1,16 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("export RI='-d ri'",))
+class TestRi:
+ @pytest.mark.complete("ri -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ri --dump=ri/")
+ def test_2(self, completion):
+ assert completion == "BashCompletion/ cache.ri".split()
+
+ @pytest.mark.complete("ri BashCompletio", require_cmd=True)
+ def test_3(self, completion):
+ assert completion == "n"
diff --git a/test/t/test_rlog.py b/test/t/test_rlog.py
new file mode 100644
index 0000000..87a4da1
--- /dev/null
+++ b/test/t/test_rlog.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestRlog:
+ @pytest.mark.complete("rlog ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_rm.py b/test/t/test_rm.py
new file mode 100644
index 0000000..6fda5a1
--- /dev/null
+++ b/test/t/test_rm.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestRm:
+ @pytest.mark.complete("rm ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("rm -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_rmdir.py b/test/t/test_rmdir.py
new file mode 100644
index 0000000..b981677
--- /dev/null
+++ b/test/t/test_rmdir.py
@@ -0,0 +1,16 @@
+import pytest
+
+
+class TestRmdir:
+ @pytest.mark.complete("rmdir ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("/bin/rmdir shared/default/")
+ def test_2(self, completion):
+ """Should complete dirs only, also when invoked using full path."""
+ assert completion == ["bar bar.d/", "foo.d/"]
+
+ @pytest.mark.complete("rmdir -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_rmlist.py b/test/t/test_rmlist.py
new file mode 100644
index 0000000..3a6c6ec
--- /dev/null
+++ b/test/t/test_rmlist.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestRmlist:
+ @pytest.mark.complete("rmlist -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_rmmod.py b/test/t/test_rmmod.py
new file mode 100644
index 0000000..5528705
--- /dev/null
+++ b/test/t/test_rmmod.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestRmmod:
+ @pytest.mark.complete("rmmod -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_route.py b/test/t/test_route.py
new file mode 100644
index 0000000..741ef58
--- /dev/null
+++ b/test/t/test_route.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestRoute:
+ @pytest.mark.complete("route ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_rpcdebug.py b/test/t/test_rpcdebug.py
new file mode 100644
index 0000000..e92bdee
--- /dev/null
+++ b/test/t/test_rpcdebug.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestRpcdebug:
+ @pytest.mark.complete("rpcdebug -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_rpm.py b/test/t/test_rpm.py
new file mode 100644
index 0000000..e6f7198
--- /dev/null
+++ b/test/t/test_rpm.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestRpm:
+ @pytest.mark.complete("rpm ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("rpm -q ", skipif='test -z "$(rpm -qa 2>/dev/null)"')
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("rpm -", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_rpm2tgz.py b/test/t/test_rpm2tgz.py
new file mode 100644
index 0000000..ad6e8bc
--- /dev/null
+++ b/test/t/test_rpm2tgz.py
@@ -0,0 +1,26 @@
+import os
+
+import pytest
+
+
+class TestRpm2tgz:
+ @pytest.mark.complete("rpm2tgz -")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("rpm2tgz ", cwd="slackware/home")
+ def test_2(self, completion):
+ expected = sorted(
+ [
+ "%s/" % x
+ for x in os.listdir("slackware/home")
+ if os.path.isdir("slackware/home/%s" % x)
+ ]
+ + [
+ x
+ for x in os.listdir("slackware/home")
+ if os.path.isfile("slackware/home/%s" % x)
+ and x.endswith(".rpm")
+ ]
+ )
+ assert completion == expected
diff --git a/test/t/test_rpmbuild.py b/test/t/test_rpmbuild.py
new file mode 100644
index 0000000..06c8087
--- /dev/null
+++ b/test/t/test_rpmbuild.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestRpmbuild:
+ @pytest.mark.complete("rpmbuild -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_rrdtool.py b/test/t/test_rrdtool.py
new file mode 100644
index 0000000..9da8310
--- /dev/null
+++ b/test/t/test_rrdtool.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestRrdtool:
+ @pytest.mark.complete("rrdtool ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_rsync.py b/test/t/test_rsync.py
new file mode 100644
index 0000000..d54ce6f
--- /dev/null
+++ b/test/t/test_rsync.py
@@ -0,0 +1,16 @@
+import pytest
+
+
+@pytest.mark.bashcomp(ignore_env=r"^[+-]_scp_path_esc=")
+class TestRsync:
+ @pytest.mark.complete("rsync ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("rsync --rsh ")
+ def test_2(self, completion):
+ assert completion == "rsh ssh".split()
+
+ @pytest.mark.complete("rsync --rsh=")
+ def test_3(self, completion):
+ assert completion == "rsh ssh".split()
diff --git a/test/t/test_rtcwake.py b/test/t/test_rtcwake.py
new file mode 100644
index 0000000..19d1dfe
--- /dev/null
+++ b/test/t/test_rtcwake.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestRtcwake:
+ @pytest.mark.complete("rtcwake ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("rtcwake -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_runuser.py b/test/t/test_runuser.py
new file mode 100644
index 0000000..01a6d88
--- /dev/null
+++ b/test/t/test_runuser.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestRunuser:
+ @pytest.mark.complete("runuser ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_sbcl.py b/test/t/test_sbcl.py
new file mode 100644
index 0000000..f05741a
--- /dev/null
+++ b/test/t/test_sbcl.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSbcl:
+ @pytest.mark.complete("sbcl shared/default/")
+ def test_1(self, completion):
+ assert completion == ["bar", "bar bar.d/", "foo", "foo.d/"]
diff --git a/test/t/test_sbcl_mt.py b/test/t/test_sbcl_mt.py
new file mode 100644
index 0000000..c396539
--- /dev/null
+++ b/test/t/test_sbcl_mt.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="sbcl-mt")
+class TestSbclMt:
+ @pytest.mark.complete("sbcl-mt shared/default/")
+ def test_1(self, completion):
+ assert completion == ["bar", "bar bar.d/", "foo", "foo.d/"]
diff --git a/test/t/test_sbopkg.py b/test/t/test_sbopkg.py
new file mode 100644
index 0000000..44f1521
--- /dev/null
+++ b/test/t/test_sbopkg.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSbopkg:
+ @pytest.mark.complete("sbopkg -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_scp.py b/test/t/test_scp.py
new file mode 100644
index 0000000..66b8da2
--- /dev/null
+++ b/test/t/test_scp.py
@@ -0,0 +1,79 @@
+from itertools import chain
+
+import pytest
+
+from conftest import assert_bash_exec
+
+LIVE_HOST = "bash_completion"
+
+
+class TestScp:
+ @pytest.mark.complete("scp -F config ", cwd="scp")
+ def test_basic(self, hosts, completion):
+ expected = sorted(
+ chain(
+ (
+ "%s:" % x
+ for x in chain(
+ hosts,
+ # From fixtures/scp/config
+ "gee hut".split(),
+ # From fixtures/scp/known_hosts
+ "blah doo ike".split(),
+ )
+ ),
+ # Local filenames
+ ["config", "known_hosts", r"spaced\ \ conf"],
+ )
+ )
+ assert completion == expected
+
+ @pytest.mark.complete("scp -F 'spaced conf' ", cwd="scp")
+ def test_basic_spaced_conf(self, hosts, completion):
+ expected = sorted(
+ chain(
+ (
+ "%s:" % x
+ for x in chain(
+ hosts,
+ # From "fixtures/scp/spaced conf"
+ "gee jar".split(),
+ # From fixtures/scp/known_hosts
+ "blah doo ike".split(),
+ )
+ ),
+ # Local filenames
+ ["config", "known_hosts", r"spaced\ \ conf"],
+ )
+ )
+ assert completion == expected
+
+ @pytest.mark.complete("scp -F")
+ def test_capital_f_without_space(self, completion):
+ assert completion
+ assert not any(
+ "option requires an argument -- F" in x for x in completion
+ )
+
+ @pytest.fixture(scope="class")
+ def live_pwd(self, bash):
+ try:
+ return assert_bash_exec(
+ bash,
+ "ssh -o 'Batchmode yes' -o 'ConnectTimeout 1' "
+ "%s pwd 2>/dev/null" % LIVE_HOST,
+ want_output=True,
+ ).strip()
+ except AssertionError:
+ pytest.skip("Live host %s not available" % LIVE_HOST)
+
+ @pytest.mark.complete("scp %s:" % LIVE_HOST, sleep_after_tab=2)
+ def test_live(self, live_pwd, completion):
+ """
+ To support this test, configure a HostName entry for LIVE_HOST
+ in ssh's configs, e.g. ~/.ssh/config or /etc/ssh/ssh_config.
+
+ Connection to it must open sufficiently quickly for the
+ ConnectTimeout and sleep_after_tab settings.
+ """
+ assert completion == "%s:%s/" % (LIVE_HOST, live_pwd)
diff --git a/test/t/test_screen.py b/test/t/test_screen.py
new file mode 100644
index 0000000..3e98837
--- /dev/null
+++ b/test/t/test_screen.py
@@ -0,0 +1,48 @@
+import pytest
+
+
+class TestScreen:
+ @pytest.mark.complete("screen -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("screen -c shared/default/")
+ def test_2(self, completion):
+ assert completion == ["bar", "bar bar.d/", "foo", "foo.d/"]
+
+ @pytest.mark.complete("screen cat ")
+ def test_3(self, completion):
+ assert completion
+
+ # Assume at least vt100 and friends are there
+ @pytest.mark.complete("screen -T vt")
+ def test_4(self, completion):
+ assert completion
+
+ @pytest.mark.complete("screen -T foo ca")
+ def test_5(self, completion):
+ assert completion == "t" or "cat" in completion
+
+ @pytest.mark.complete("screen //")
+ def test_telnet(self, completion):
+ assert completion == "telnet"
+
+ @pytest.mark.complete("screen cat //")
+ def test_not_telnet(self, completion):
+ assert completion != "telnet"
+
+ @pytest.mark.complete("screen //telnet ", env=dict(HOME="$PWD/shared"))
+ def test_telnet_first_arg(self, completion):
+ assert "bash-completion-canary-host.local" in completion
+
+ @pytest.mark.complete("screen //telnet foo ", env=dict(HOME="$PWD/shared"))
+ def test_telnet_other_args(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("screen /dev/ttyUSB0 ")
+ def test_serial_2nd_arg(self, completion):
+ assert "19200" in completion
+
+ @pytest.mark.complete("screen /dev/ttyUSB0 9600 ")
+ def test_serial_3rdplus_arg(self, completion):
+ assert not completion
diff --git a/test/t/test_scrub.py b/test/t/test_scrub.py
new file mode 100644
index 0000000..5853ad2
--- /dev/null
+++ b/test/t/test_scrub.py
@@ -0,0 +1,19 @@
+import pytest
+
+
+class TestScrub:
+ @pytest.mark.complete("scrub ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("scrub -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ # Not all scrub versions list available patterns in --help output
+ @pytest.mark.complete(
+ "scrub -p ",
+ xfail="! (scrub --help 2>&1 || :) | command grep -q ^Available",
+ )
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_sdptool.py b/test/t/test_sdptool.py
new file mode 100644
index 0000000..095d90e
--- /dev/null
+++ b/test/t/test_sdptool.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSdptool:
+ @pytest.mark.complete("sdptool ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_secret_tool.py b/test/t/test_secret_tool.py
new file mode 100644
index 0000000..cbfc0cb
--- /dev/null
+++ b/test/t/test_secret_tool.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="secret-tool",)
+class TestSecretTool:
+ @pytest.mark.complete("secret-tool ", require_cmd=True)
+ def test_modes(self, completion):
+ assert "store" in completion
+
+ @pytest.mark.complete("secret-tool search ")
+ def test_no_complete(self, completion):
+ assert not completion
diff --git a/test/t/test_sed.py b/test/t/test_sed.py
new file mode 100644
index 0000000..53079c9
--- /dev/null
+++ b/test/t/test_sed.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSed:
+ @pytest.mark.complete("sed --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_seq.py b/test/t/test_seq.py
new file mode 100644
index 0000000..b672238
--- /dev/null
+++ b/test/t/test_seq.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSeq:
+ @pytest.mark.complete("seq --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_service.py b/test/t/test_service.py
new file mode 100644
index 0000000..7ce4312
--- /dev/null
+++ b/test/t/test_service.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestService:
+ @pytest.mark.complete("service ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_set.py b/test/t/test_set.py
new file mode 100644
index 0000000..08c1671
--- /dev/null
+++ b/test/t/test_set.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSet:
+ @pytest.mark.complete("set no")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_setquota.py b/test/t/test_setquota.py
new file mode 100644
index 0000000..76fd7b9
--- /dev/null
+++ b/test/t/test_setquota.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestSetquota:
+ @pytest.mark.complete("setquota ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("setquota -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_sftp.py b/test/t/test_sftp.py
new file mode 100644
index 0000000..a421a44
--- /dev/null
+++ b/test/t/test_sftp.py
@@ -0,0 +1,46 @@
+from itertools import chain
+
+import pytest
+
+
+class TestSftp:
+ @pytest.mark.complete("sftp -Fsp", cwd="sftp")
+ def test_1(self, completion):
+ assert completion == r"aced\ \ conf"
+
+ @pytest.mark.complete("sftp -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("sftp -F config ", cwd="sftp")
+ def test_hosts(self, hosts, completion):
+ expected = sorted(
+ chain(
+ hosts,
+ # From fixtures/sftp/config
+ "gee hut".split(),
+ # From fixtures/sftp/known_hosts
+ "10.10.10.10 doo ike".split(),
+ )
+ )
+ assert completion == expected
+
+ @pytest.mark.complete(r"sftp -F spaced\ \ conf ", cwd="sftp")
+ def test_hosts_spaced_conf(self, hosts, completion):
+ expected = sorted(
+ chain(
+ hosts,
+ # From "fixtures/sftp/spaced conf"
+ "gee jar".split(),
+ # From fixtures/sftp/known_hosts
+ "10.10.10.10 doo ike".split(),
+ )
+ )
+ assert completion == expected
+
+ @pytest.mark.complete("sftp -F")
+ def test_capital_f_without_space(self, completion):
+ assert completion
+ assert not any(
+ "option requires an argument -- F" in x for x in completion
+ )
diff --git a/test/t/test_sh.py b/test/t/test_sh.py
new file mode 100644
index 0000000..f49a168
--- /dev/null
+++ b/test/t/test_sh.py
@@ -0,0 +1,19 @@
+import pytest
+
+
+class TestSh:
+ @pytest.mark.complete("sh -")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("sh +")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("sh -o ")
+ def test_3(self, completion):
+ assert completion
+
+ @pytest.mark.complete("sh -c ")
+ def test_4(self, completion):
+ assert not completion
diff --git a/test/t/test_sha1sum.py b/test/t/test_sha1sum.py
new file mode 100644
index 0000000..e4296d4
--- /dev/null
+++ b/test/t/test_sha1sum.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSha1sum:
+ @pytest.mark.complete("sha1sum --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_shar.py b/test/t/test_shar.py
new file mode 100644
index 0000000..5c23004
--- /dev/null
+++ b/test/t/test_shar.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestShar:
+ @pytest.mark.complete("shar --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_shellcheck.py b/test/t/test_shellcheck.py
new file mode 100644
index 0000000..703128f
--- /dev/null
+++ b/test/t/test_shellcheck.py
@@ -0,0 +1,19 @@
+import pytest
+
+
+class TestShellcheck:
+ @pytest.mark.complete("shellcheck ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("shellcheck -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("shellcheck --format=", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
+
+ @pytest.mark.complete("shellcheck -s ", require_cmd=True)
+ def test_4(self, completion):
+ assert "bash" in completion
diff --git a/test/t/test_sitecopy.py b/test/t/test_sitecopy.py
new file mode 100644
index 0000000..afdeeaa
--- /dev/null
+++ b/test/t/test_sitecopy.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSitecopy:
+ @pytest.mark.complete("sitecopy --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_slackpkg.py b/test/t/test_slackpkg.py
new file mode 100644
index 0000000..3997bb0
--- /dev/null
+++ b/test/t/test_slackpkg.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSlackpkg:
+ @pytest.mark.complete("slackpkg -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_slapt_get.py b/test/t/test_slapt_get.py
new file mode 100644
index 0000000..9244971
--- /dev/null
+++ b/test/t/test_slapt_get.py
@@ -0,0 +1,44 @@
+import os.path
+from tempfile import mkstemp
+
+import pytest
+
+from conftest import assert_complete, is_bash_type
+
+
+@pytest.mark.bashcomp(cmd="slapt-get")
+class TestSlaptGet:
+ @pytest.fixture(scope="class")
+ def slapt_getrc(self, request, bash):
+ fd, fname = mkstemp(prefix="slapt-getrc.", text=True)
+ request.addfinalizer(lambda: os.remove(fname))
+ with os.fdopen(fd, "w") as f:
+ print(
+ "WORKINGDIR=%s/"
+ % os.path.join(bash.cwd, *"slackware var slapt-get".split()),
+ file=f,
+ )
+ print("SOURCE=file:///home/", file=f)
+ return fname
+
+ @pytest.mark.complete("slapt-get -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("slapt-get --up", require_cmd=True)
+ def test_2(self, completion):
+ assert completion == "--update --upgrade".split()
+
+ @pytest.mark.complete("slapt-get -c non-existent-file --install ")
+ def test_3(self, completion):
+ assert not completion
+
+ def test_install(self, bash, slapt_getrc):
+ if not is_bash_type(bash, "slapt-get"):
+ pytest.skip("slapt-get not found")
+ completion = assert_complete(
+ bash, "slapt-get -c %s --install " % slapt_getrc
+ )
+ assert completion == sorted(
+ "abc-4-i686-1 ran-1.2-noarch-1 qwe-2.1-i486-1".split()
+ )
diff --git a/test/t/test_slapt_src.py b/test/t/test_slapt_src.py
new file mode 100644
index 0000000..b55b722
--- /dev/null
+++ b/test/t/test_slapt_src.py
@@ -0,0 +1,43 @@
+import os
+from tempfile import mkstemp
+
+import pytest
+
+from conftest import assert_complete, is_bash_type
+
+
+@pytest.mark.bashcomp(cmd="slapt-src")
+class TestSlaptSrc:
+ @pytest.fixture(scope="class")
+ def slapt_srcrc(self, request, bash):
+ fd, fname = mkstemp(prefix="slapt-srcrc.", text=True)
+ request.addfinalizer(lambda: os.remove(fname))
+ with os.fdopen(fd, "w") as f:
+ print(
+ "BUILDDIR=%s/"
+ % os.path.join(
+ bash.cwd, *"slackware usr src slapt-src".split()
+ ),
+ file=f,
+ )
+ return fname
+
+ @pytest.mark.complete("slapt-src -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("slapt-src --bu", require_cmd=True)
+ def test_2(self, completion):
+ assert completion == "ild" or "--build" in completion
+
+ @pytest.mark.complete("slapt-src --ins", require_cmd=True)
+ def test_3(self, completion):
+ assert completion == "tall" or "--install" in completion
+
+ def test_install(self, bash, slapt_srcrc):
+ if not is_bash_type(bash, "slapt-src"):
+ pytest.skip("slapt-src not found")
+ completion = assert_complete(
+ bash, "slapt-src --config %s --install " % slapt_srcrc
+ )
+ assert completion == "abc:4 qwe:2.1".split()
diff --git a/test/t/test_smartctl.py b/test/t/test_smartctl.py
new file mode 100644
index 0000000..26d0147
--- /dev/null
+++ b/test/t/test_smartctl.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSmartctl:
+ @pytest.mark.complete("smartctl --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_smbcacls.py b/test/t/test_smbcacls.py
new file mode 100644
index 0000000..0fe84e3
--- /dev/null
+++ b/test/t/test_smbcacls.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSmbcacls:
+ @pytest.mark.complete("smbcacls -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_smbclient.py b/test/t/test_smbclient.py
new file mode 100644
index 0000000..250ab87
--- /dev/null
+++ b/test/t/test_smbclient.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSmbclient:
+ @pytest.mark.complete("smbclient -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_smbcquotas.py b/test/t/test_smbcquotas.py
new file mode 100644
index 0000000..16157ed
--- /dev/null
+++ b/test/t/test_smbcquotas.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSmbcquotas:
+ @pytest.mark.complete("smbcquotas -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_smbget.py b/test/t/test_smbget.py
new file mode 100644
index 0000000..a6df717
--- /dev/null
+++ b/test/t/test_smbget.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSmbget:
+ @pytest.mark.complete("smbget -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_smbpasswd.py b/test/t/test_smbpasswd.py
new file mode 100644
index 0000000..9fae8f2
--- /dev/null
+++ b/test/t/test_smbpasswd.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSmbpasswd:
+ @pytest.mark.complete("smbpasswd -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_smbtar.py b/test/t/test_smbtar.py
new file mode 100644
index 0000000..2a0e01e
--- /dev/null
+++ b/test/t/test_smbtar.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSmbtar:
+ @pytest.mark.complete("smbtar -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_smbtree.py b/test/t/test_smbtree.py
new file mode 100644
index 0000000..2cb6767
--- /dev/null
+++ b/test/t/test_smbtree.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSmbtree:
+ @pytest.mark.complete("smbtree -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_snownews.py b/test/t/test_snownews.py
new file mode 100644
index 0000000..a05df98
--- /dev/null
+++ b/test/t/test_snownews.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSnownews:
+ @pytest.mark.complete("snownews --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_sort.py b/test/t/test_sort.py
new file mode 100644
index 0000000..d1a4e36
--- /dev/null
+++ b/test/t/test_sort.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSort:
+ @pytest.mark.complete("sort --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_split.py b/test/t/test_split.py
new file mode 100644
index 0000000..8c3f1f4
--- /dev/null
+++ b/test/t/test_split.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSplit:
+ @pytest.mark.complete("split --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_spovray.py b/test/t/test_spovray.py
new file mode 100644
index 0000000..9033f83
--- /dev/null
+++ b/test/t/test_spovray.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSpovray:
+ @pytest.mark.complete("spovray ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_sqlite3.py b/test/t/test_sqlite3.py
new file mode 100644
index 0000000..69a1316
--- /dev/null
+++ b/test/t/test_sqlite3.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestSqlite3:
+ @pytest.mark.complete("sqlite3 ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("sqlite3 -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("sqlite3 -scratch foo ", require_cmd=True)
+ def test_3(self, completion):
+ assert not completion
diff --git a/test/t/test_ss.py b/test/t/test_ss.py
new file mode 100644
index 0000000..716c0fd
--- /dev/null
+++ b/test/t/test_ss.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestSs:
+ @pytest.mark.complete("ss -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ss -A ", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ss -A foo,", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_ssh.py b/test/t/test_ssh.py
new file mode 100644
index 0000000..8e95819
--- /dev/null
+++ b/test/t/test_ssh.py
@@ -0,0 +1,60 @@
+import pytest
+
+from conftest import assert_complete, partialize
+
+
+class TestSsh:
+ @pytest.mark.complete("ssh -Fsp", cwd="ssh")
+ def test_1(self, completion):
+ assert completion == r"aced\ \ conf"
+
+ @pytest.mark.complete("ssh -F config ls", cwd="ssh")
+ def test_2(self, completion):
+ """Should complete both commands and hostname."""
+ assert all(x in completion for x in "ls ls_known_host".split())
+
+ @pytest.mark.complete("ssh bash", cwd="ssh")
+ def test_3(self, completion):
+ """
+ First arg should not complete with commands.
+
+ Assumes there's no "bash" known host.
+ """
+ assert "bash" not in completion
+
+ @pytest.mark.complete("ssh -vo AddressFamily=")
+ def test_4(self, completion):
+ assert completion
+
+ @pytest.mark.xfail # TODO our test facilities don't support case change?
+ @pytest.mark.complete("ssh -vo userknownhostsf")
+ def test_5(self, completion):
+ assert "UserKnownHostsFile=" in completion
+
+ @pytest.mark.complete("ssh -", require_cmd=True)
+ def test_6(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ssh -F")
+ def test_capital_f_without_space(self, completion):
+ assert completion
+ assert not any(
+ "option requires an argument -- F" in x for x in completion
+ )
+
+ @pytest.mark.complete("ssh -F nonexistent ")
+ def test_capital_f_nonexistent(self, completion):
+ assert completion
+
+ def test_partial_hostname(self, bash, known_hosts):
+ first_char, partial_hosts = partialize(bash, known_hosts)
+ completion = assert_complete(bash, "ssh %s" % first_char)
+ if len(completion) == 1:
+ assert completion == partial_hosts[0][1:]
+ else:
+ assert completion == sorted(x for x in partial_hosts)
+
+ @pytest.mark.parametrize("protocol", "4 6 9".split())
+ def test_protocol_option_bundling(self, bash, protocol):
+ completion = assert_complete(bash, "ssh -%sF ssh/" % protocol)
+ assert "config" in completion
diff --git a/test/t/test_ssh_add.py b/test/t/test_ssh_add.py
new file mode 100644
index 0000000..7e49372
--- /dev/null
+++ b/test/t/test_ssh_add.py
@@ -0,0 +1,17 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="ssh-add")
+class TestSshAdd:
+ @pytest.mark.complete("ssh-add ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "ssh-add -",
+ require_cmd=True,
+ xfail="ssh-add --help 2>&1 | "
+ "command grep -qiF 'Could not open a connection'",
+ )
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_ssh_copy_id.py b/test/t/test_ssh_copy_id.py
new file mode 100644
index 0000000..e38e901
--- /dev/null
+++ b/test/t/test_ssh_copy_id.py
@@ -0,0 +1,16 @@
+import pytest
+
+
+@pytest.mark.bashcomp(
+ cmd="ssh-copy-id",
+ pre_cmds=(
+ # Some old versions of ssh-copy-id won't output even usage if no
+ # identities are found. Try to make sure there is at least one.
+ "HOME=$PWD/ssh-copy-id",
+ ),
+ ignore_env=r"^[+-]_scp_path_esc=",
+)
+class TestSshCopyId:
+ @pytest.mark.complete("ssh-copy-id -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ssh_keygen.py b/test/t/test_ssh_keygen.py
new file mode 100644
index 0000000..b773ab4
--- /dev/null
+++ b/test/t/test_ssh_keygen.py
@@ -0,0 +1,59 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="ssh-keygen")
+class TestSshKeygen:
+ @pytest.mark.complete("ssh-keygen -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ssh-keygen -s foo_key ssh-copy-id/.ssh/")
+ def test_filedir_pub_at_end_of_s(self, completion):
+ assert completion
+ assert all(x.endswith(".pub") for x in completion)
+
+ @pytest.mark.complete("ssh-keygen -s foo_key -n foo,")
+ def test_usernames_for_n(self, completion):
+ assert completion
+ assert not any("," in x for x in completion)
+ # TODO check that these are usernames
+
+ @pytest.mark.complete("ssh-keygen -s foo_key -h -n foo,")
+ def test_host_for_h_n(self, completion):
+ assert completion
+ assert not any("," in x for x in completion)
+ # TODO check that these are hostnames
+
+ @pytest.mark.complete("ssh-keygen -Y foo -n ")
+ def test_n_with_Y(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("ssh-keygen -r ")
+ def test_r_without_Y(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("ssh-keygen -Y foo -r ")
+ def test_r_with_Y(self, completion):
+ assert "ssh/" in completion
+
+ @pytest.mark.complete("ssh-keygen -t ecdsa -b ")
+ def test_ecdsa_b(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ssh-keygen -t ecdsa-sk -b ")
+ def test_ecdsa_sk_b(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("ssh-keygen -O ")
+ def test_O(self, completion):
+ assert completion
+ assert any(x.endswith("=") for x in completion)
+
+ @pytest.mark.complete("ssh-keygen -O force-command=bas")
+ def test_O_force_command(self, completion):
+ assert completion
+ assert not completion.startswith("force-command=")
+
+ @pytest.mark.complete("ssh-keygen -O unknown=")
+ def test_O_unknown(self, completion):
+ assert not completion
diff --git a/test/t/test_sshfs.py b/test/t/test_sshfs.py
new file mode 100644
index 0000000..44daed3
--- /dev/null
+++ b/test/t/test_sshfs.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(ignore_env=r"^[+-]_scp_path_esc=")
+class TestSshfs:
+ @pytest.mark.complete("sshfs ./")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_sshmitm.py b/test/t/test_sshmitm.py
new file mode 100644
index 0000000..671fcf5
--- /dev/null
+++ b/test/t/test_sshmitm.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSshmitm:
+ @pytest.mark.complete("sshmitm -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_sshow.py b/test/t/test_sshow.py
new file mode 100644
index 0000000..563bc6b
--- /dev/null
+++ b/test/t/test_sshow.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSshow:
+ @pytest.mark.complete("sshow -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_strace.py b/test/t/test_strace.py
new file mode 100644
index 0000000..e0d6aed
--- /dev/null
+++ b/test/t/test_strace.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestStrace:
+ @pytest.mark.complete("strace -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_stream.py b/test/t/test_stream.py
new file mode 100644
index 0000000..a46e901
--- /dev/null
+++ b/test/t/test_stream.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestStream:
+ @pytest.mark.complete("stream ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_strings.py b/test/t/test_strings.py
new file mode 100644
index 0000000..6b5d012
--- /dev/null
+++ b/test/t/test_strings.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestStrings:
+ @pytest.mark.complete("strings ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("strings -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_strip.py b/test/t/test_strip.py
new file mode 100644
index 0000000..105012f
--- /dev/null
+++ b/test/t/test_strip.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestStrip:
+ @pytest.mark.complete("strip --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_su.py b/test/t/test_su.py
new file mode 100644
index 0000000..9aa064d
--- /dev/null
+++ b/test/t/test_su.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestSu:
+ @pytest.mark.complete("su ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("su -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_sudo.py b/test/t/test_sudo.py
new file mode 100644
index 0000000..a349466
--- /dev/null
+++ b/test/t/test_sudo.py
@@ -0,0 +1,83 @@
+import pytest
+
+from conftest import assert_complete
+
+
+class TestSudo:
+ @pytest.mark.complete("sudo -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("sudo cd fo", cwd="shared/default")
+ def test_2(self, completion):
+ assert completion == "o.d/"
+ assert not completion.endswith(" ")
+
+ @pytest.mark.complete("sudo sh share")
+ def test_3(self, completion):
+ assert completion == "d/"
+ assert not completion.endswith(" ")
+
+ @pytest.mark.complete("sudo mount /dev/sda1 def", cwd="shared")
+ def test_4(self, completion):
+ assert completion == "ault/"
+ assert not completion.endswith(" ")
+
+ @pytest.mark.complete("sudo -e -u root bar foo", cwd="shared/default")
+ def test_5(self, completion):
+ assert completion == "foo foo.d/".split()
+
+ def test_6(self, bash, part_full_user):
+ part, full = part_full_user
+ completion = assert_complete(bash, "sudo chown %s" % part)
+ assert completion == full[len(part) :]
+ assert completion.endswith(" ")
+
+ def test_7(self, bash, part_full_user, part_full_group):
+ _, user = part_full_user
+ partgroup, fullgroup = part_full_group
+ completion = assert_complete(
+ bash, "sudo chown %s:%s" % (user, partgroup)
+ )
+ assert completion == fullgroup[len(partgroup) :]
+ assert completion.endswith(" ")
+
+ def test_8(self, bash, part_full_group):
+ part, full = part_full_group
+ completion = assert_complete(bash, "sudo chown dot.user:%s" % part)
+ assert completion == full[len(part) :]
+ assert completion.endswith(" ")
+
+ @pytest.mark.parametrize(
+ "prefix",
+ [
+ r"funky\ user:",
+ "funky.user:",
+ r"funky\.user:",
+ r"fu\ nky.user:",
+ r"f\ o\ o\.\bar:",
+ r"foo\_b\ a\.r\ :",
+ ],
+ )
+ def test_9(self, bash, part_full_group, prefix):
+ """Test preserving special chars in $prefix$partgroup<TAB>."""
+ part, full = part_full_group
+ completion = assert_complete(bash, "sudo chown %s%s" % (prefix, part))
+ assert completion == full[len(part) :]
+ assert completion.endswith(" ")
+
+ def test_10(self, bash, part_full_user, part_full_group):
+ """Test giving up on degenerate cases instead of spewing junk."""
+ _, user = part_full_user
+ partgroup, _ = part_full_group
+ for x in range(2, 5):
+ completion = assert_complete(
+ bash, "sudo chown %s%s:%s" % (user, x * "\\", partgroup)
+ )
+ assert not completion
+
+ def test_11(self, bash, part_full_group):
+ """Test graceful fail on colon in user/group name."""
+ part, _ = part_full_group
+ completion = assert_complete(bash, "sudo chown foo:bar:%s" % part)
+ assert not completion
diff --git a/test/t/test_sum.py b/test/t/test_sum.py
new file mode 100644
index 0000000..bfb2cf4
--- /dev/null
+++ b/test/t/test_sum.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestSum:
+ @pytest.mark.complete("sum ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("sum -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_svcadm.py b/test/t/test_svcadm.py
new file mode 100644
index 0000000..76d86a4
--- /dev/null
+++ b/test/t/test_svcadm.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSvcadm:
+ @pytest.mark.complete("svcadm ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_svk.py b/test/t/test_svk.py
new file mode 100644
index 0000000..8014bb0
--- /dev/null
+++ b/test/t/test_svk.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSvk:
+ @pytest.mark.complete("svk ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_svn.py b/test/t/test_svn.py
new file mode 100644
index 0000000..d8bbee7
--- /dev/null
+++ b/test/t/test_svn.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSvn:
+ @pytest.mark.complete("svn ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_svnadmin.py b/test/t/test_svnadmin.py
new file mode 100644
index 0000000..2dc7c6c
--- /dev/null
+++ b/test/t/test_svnadmin.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSvnadmin:
+ @pytest.mark.complete("svnadmin ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_svnlook.py b/test/t/test_svnlook.py
new file mode 100644
index 0000000..26761b0
--- /dev/null
+++ b/test/t/test_svnlook.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSvnlook:
+ @pytest.mark.complete("svnlook ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_sync_members.py b/test/t/test_sync_members.py
new file mode 100644
index 0000000..f0d2dcf
--- /dev/null
+++ b/test/t/test_sync_members.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestSyncMembers:
+ @pytest.mark.complete("sync_members --")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_synclient.py b/test/t/test_synclient.py
new file mode 100644
index 0000000..8a31a65
--- /dev/null
+++ b/test/t/test_synclient.py
@@ -0,0 +1,16 @@
+import pytest
+
+
+class TestSynclient:
+
+ # synclient -l may error out with e.g.
+ # "Couldn't find synaptics properties. No synaptics driver loaded?"
+ @pytest.mark.complete(
+ "synclient ", require_cmd=True, xfail="! synclient -l &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("synclient -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_sysbench.py b/test/t/test_sysbench.py
new file mode 100644
index 0000000..4992d8a
--- /dev/null
+++ b/test/t/test_sysbench.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestSysbench:
+ @pytest.mark.complete("sysbench ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("sysbench -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_sysctl.py b/test/t/test_sysctl.py
new file mode 100644
index 0000000..f8db50b
--- /dev/null
+++ b/test/t/test_sysctl.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestSysctl:
+ @pytest.mark.complete("sysctl -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "sysctl kern",
+ require_cmd=True,
+ xfail="! sysctl -N -a 2>/dev/null | command grep -q ^kern",
+ )
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_tac.py b/test/t/test_tac.py
new file mode 100644
index 0000000..db433cc
--- /dev/null
+++ b/test/t/test_tac.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestTac:
+ @pytest.mark.complete("tac --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_tail.py b/test/t/test_tail.py
new file mode 100644
index 0000000..6f2b3c6
--- /dev/null
+++ b/test/t/test_tail.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestTail:
+ @pytest.mark.complete("tail --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_tar.py b/test/t/test_tar.py
new file mode 100644
index 0000000..4518d0b
--- /dev/null
+++ b/test/t/test_tar.py
@@ -0,0 +1,120 @@
+import re
+
+import pytest
+
+from conftest import assert_bash_exec
+
+
+@pytest.mark.bashcomp(ignore_env=r"^-declare -f _tar$")
+class TestTar:
+ @pytest.fixture(scope="class")
+ def gnu_tar(self, bash):
+ got = assert_bash_exec(bash, "tar --version || :", want_output=True)
+ if not re.search(r"\bGNU ", got):
+ pytest.skip("Not GNU tar")
+
+ @pytest.mark.complete("tar ")
+ def test_1(self, completion):
+ assert completion
+
+ # Test "f" when mode is not as first option
+ @pytest.mark.complete("tar zfc ", cwd="tar")
+ def test_2(self, completion):
+ assert completion == "dir/ dir2/".split()
+
+ @pytest.mark.complete("tar cf ", cwd="tar")
+ def test_3(self, completion):
+ assert completion == "dir/ dir2/".split()
+
+ @pytest.mark.complete("tar tf archive.tar.xz dir/file", cwd="tar")
+ def test_4(self, completion):
+ assert completion == "dir/fileA dir/fileB dir/fileC".split()
+
+ @pytest.mark.complete("tar cTfvv NOT_EXISTS DONT_CREATE.tar ", cwd="tar")
+ def test_5(self, completion):
+ assert completion == "archive.tar.xz dir/ dir2/ escape.tar".split()
+
+ @pytest.mark.complete("tar xvf ", cwd="tar")
+ def test_6(self, completion):
+ assert completion == "archive.tar.xz dir/ dir2/ escape.tar".split()
+
+ @pytest.mark.complete("tar -c")
+ def test_7(self, completion, gnu_tar):
+ """Test short options."""
+ assert completion
+
+ @pytest.mark.complete("tar -zcf ", cwd="tar")
+ def test_8(self, completion, gnu_tar):
+ """Test mode not as first option."""
+ assert completion == "dir/ dir2/".split()
+
+ @pytest.mark.complete("tar -cf ", cwd="tar")
+ def test_9(self, completion, gnu_tar):
+ """Test that we don't suggest rewriting existing archive."""
+ assert completion == "dir/ dir2/".split()
+
+ @pytest.mark.complete("tar -c --file ", cwd="tar")
+ def test_10(self, completion, gnu_tar):
+ assert completion == "dir/ dir2/".split()
+
+ @pytest.mark.complete("tar -cvv --file ", cwd="tar")
+ def test_11(self, completion, gnu_tar):
+ assert completion == "dir/ dir2/".split()
+
+ @pytest.mark.complete("tar -tf archive.tar.xz dir/file", cwd="tar")
+ def test_12(self, completion, gnu_tar):
+ """Test archive listing."""
+ assert completion == "dir/fileA dir/fileB dir/fileC".split()
+
+ @pytest.mark.complete("tar -t --file archive.tar.xz dir/file", cwd="tar")
+ def test_13(self, completion, gnu_tar):
+ """Test archive listing with --file."""
+ assert completion == "dir/fileA dir/fileB dir/fileC".split()
+
+ @pytest.mark.complete("tar --block")
+ def test_14(self, completion, gnu_tar):
+ assert completion == "--block-number --blocking-factor=".split()
+
+ @pytest.mark.complete("tar --add-fil")
+ def test_15(self, completion, gnu_tar):
+ assert completion == "e="
+ assert not completion.endswith(" ")
+
+ @pytest.mark.complete("tar -cf /dev/null --posi")
+ def test_16(self, completion, gnu_tar):
+ assert completion == "x"
+ assert completion.endswith(" ")
+
+ @pytest.mark.complete("tar --owner=")
+ def test_17(self, bash, completion, gnu_tar, output_sort_uniq):
+ users = output_sort_uniq("compgen -u")
+ assert completion == users
+
+ @pytest.mark.complete("tar --group=")
+ def test_18(self, bash, completion, gnu_tar, output_sort_uniq):
+ groups = output_sort_uniq("compgen -g")
+ assert completion == groups
+
+ # Use -b for this as -b is still not handled by tar's completion
+ @pytest.mark.complete("tar -cvvfb ")
+ def test_19(self, bash, completion, gnu_tar):
+ """Test short option -XXXb <TAB> (arg required)."""
+ assert not completion
+
+ # Use bsdtar here as it completes to only 'zc zt zx'
+ # -- 'tar' can be GNU tar and have more options
+ @pytest.mark.complete("bsdtar z")
+ def test_20(self, bash, completion):
+ assert completion == "zc zt zx".split()
+
+ @pytest.mark.complete("bsdtar cbfvv NON_EXISTENT ", cwd="tar")
+ def test_21(self, bash, completion):
+ """Test _second_ option in "old" argument."""
+ assert completion == "dir/ dir2/".split()
+
+ @pytest.mark.complete(r"tar tf escape.tar a/b\'", cwd="tar")
+ def test_22(self, bash, completion):
+ """Test listing escaped chars in old option."""
+ assert completion == "c/"
+
+ # TODO: "tar tf escape.tar a/b"
diff --git a/test/t/test_tcpdump.py b/test/t/test_tcpdump.py
new file mode 100644
index 0000000..a557364
--- /dev/null
+++ b/test/t/test_tcpdump.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestTcpdump:
+ @pytest.mark.complete("tcpdump -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_tcpkill.py b/test/t/test_tcpkill.py
new file mode 100644
index 0000000..4581a34
--- /dev/null
+++ b/test/t/test_tcpkill.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestTcpkill:
+ @pytest.mark.complete("tcpkill -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_tcpnice.py b/test/t/test_tcpnice.py
new file mode 100644
index 0000000..fbe9592
--- /dev/null
+++ b/test/t/test_tcpnice.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestTcpnice:
+ @pytest.mark.complete("tcpnice -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_tee.py b/test/t/test_tee.py
new file mode 100644
index 0000000..3d8bcd7
--- /dev/null
+++ b/test/t/test_tee.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestTee:
+ @pytest.mark.complete("tee ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("tee -", require_longopt=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_texindex.py b/test/t/test_texindex.py
new file mode 100644
index 0000000..c3f6a0b
--- /dev/null
+++ b/test/t/test_texindex.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestTexindex:
+ @pytest.mark.complete("texindex --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_tightvncviewer.py b/test/t/test_tightvncviewer.py
new file mode 100644
index 0000000..04ebece
--- /dev/null
+++ b/test/t/test_tightvncviewer.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestTightvncviewer:
+ @pytest.mark.complete("tightvncviewer ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_time.py b/test/t/test_time.py
new file mode 100644
index 0000000..231f14e
--- /dev/null
+++ b/test/t/test_time.py
@@ -0,0 +1,23 @@
+import os
+
+import pytest
+
+
+class TestTime:
+ @pytest.mark.complete("time set")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("time -p find -typ")
+ def test_2(self, completion):
+ assert completion # find's options
+
+ @pytest.mark.complete("time shared/bin/")
+ def test_3(self, completion):
+ execs = sorted(
+ x
+ for x in os.listdir("shared/bin")
+ if os.path.isfile("shared/bin/%s" % x)
+ and os.access("shared/bin/%s" % x, os.X_OK)
+ )
+ assert completion == execs
diff --git a/test/t/test_timeout.py b/test/t/test_timeout.py
new file mode 100644
index 0000000..46fe2e0
--- /dev/null
+++ b/test/t/test_timeout.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestTimeout:
+ @pytest.mark.complete("timeout ")
+ def test_1(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("timeout -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_tipc.py b/test/t/test_tipc.py
new file mode 100644
index 0000000..17b2bfd
--- /dev/null
+++ b/test/t/test_tipc.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestTipc:
+ @pytest.mark.complete("tipc ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_totem.py b/test/t/test_totem.py
new file mode 100644
index 0000000..f6fb26f
--- /dev/null
+++ b/test/t/test_totem.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestTotem:
+ @pytest.mark.complete("totem ")
+ def test_basic(self, completion):
+ assert completion
diff --git a/test/t/test_touch.py b/test/t/test_touch.py
new file mode 100644
index 0000000..8a49e50
--- /dev/null
+++ b/test/t/test_touch.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestTouch:
+ @pytest.mark.complete("touch --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_tox.py b/test/t/test_tox.py
new file mode 100644
index 0000000..f012a03
--- /dev/null
+++ b/test/t/test_tox.py
@@ -0,0 +1,19 @@
+import pytest
+
+
+class TestTox:
+ @pytest.mark.complete("tox -")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("tox -e ", cwd="tox")
+ def test_2(self, completion):
+ assert all(x in completion for x in "py37 ALL".split())
+
+ @pytest.mark.complete("tox -e foo,", cwd="tox")
+ def test_3(self, completion):
+ assert all(x in completion for x in "py37 ALL".split())
+
+ @pytest.mark.complete("tox -e foo -- ", cwd="tox")
+ def test_default_after_dashdash(self, completion):
+ assert "tox.ini" in completion
diff --git a/test/t/test_tr.py b/test/t/test_tr.py
new file mode 100644
index 0000000..0a51e9e
--- /dev/null
+++ b/test/t/test_tr.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestTr:
+ @pytest.mark.complete("tr --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_tracepath.py b/test/t/test_tracepath.py
new file mode 100644
index 0000000..e4cac65
--- /dev/null
+++ b/test/t/test_tracepath.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestTracepath:
+ @pytest.mark.complete("tracepath ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("tracepath -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_tshark.py b/test/t/test_tshark.py
new file mode 100644
index 0000000..f49533e
--- /dev/null
+++ b/test/t/test_tshark.py
@@ -0,0 +1,34 @@
+import pytest
+
+
+@pytest.mark.bashcomp(ignore_env=r"^\+_tshark_pr(ef|otocol)s=")
+class TestTshark:
+ @pytest.mark.complete("tshark -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("tshark -G ", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("tshark -O foo,htt", require_cmd=True)
+ def test_3(self, completion):
+ # p: one completion only; http: e.g. http and http2
+ assert completion == "p" or "http" in completion
+
+ @pytest.mark.complete("tshark -o tcp", require_cmd=True)
+ def test_4(self, completion):
+ assert "tcp.desegment_tcp_streams:" in completion
+
+ @pytest.mark.complete("tshark -otcp", require_cmd=True)
+ def test_5(self, completion):
+ assert "-otcp.desegment_tcp_streams:" in completion
+
+ @pytest.mark.complete("tshark -O http")
+ def test_6(self, completion):
+ """Test there are no URLs in completions."""
+ assert not any("://" in x for x in completion)
+
+ @pytest.mark.complete("tshark -r ")
+ def test_input_files(self, completion):
+ assert completion
diff --git a/test/t/test_tsig_keygen.py b/test/t/test_tsig_keygen.py
new file mode 100644
index 0000000..8c8a64a
--- /dev/null
+++ b/test/t/test_tsig_keygen.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="tsig-keygen")
+class TestTsigKeygen:
+ @pytest.mark.complete("tsig-keygen ")
+ def test_basic(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("tsig-keygen -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_tune2fs.py b/test/t/test_tune2fs.py
new file mode 100644
index 0000000..5cc0e41
--- /dev/null
+++ b/test/t/test_tune2fs.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestTune2fs:
+ @pytest.mark.complete("tune2fs ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("tune2fs -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_udevadm.py b/test/t/test_udevadm.py
new file mode 100644
index 0000000..6191c77
--- /dev/null
+++ b/test/t/test_udevadm.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestUdevadm:
+ @pytest.mark.complete("udevadm ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("udevadm -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_ulimit.py b/test/t/test_ulimit.py
new file mode 100644
index 0000000..3ab974c
--- /dev/null
+++ b/test/t/test_ulimit.py
@@ -0,0 +1,35 @@
+import pytest
+
+
+class TestUlimit:
+ @pytest.mark.complete("ulimit ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ulimit -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("ulimit -S -")
+ def test_3(self, completion):
+ """Test modes are completed after -S (-S not treated as mode)."""
+ assert completion
+
+ @pytest.mark.complete("ulimit -u -")
+ def test_4(self, completion):
+ """Test modes are NOT completed if one is specified."""
+ assert not completion
+
+ @pytest.mark.complete("ulimit -c ")
+ def test_5(self, completion):
+ assert completion
+ assert not any(x.startswith("-") for x in completion)
+
+ @pytest.mark.complete("ulimit -a ")
+ def test_6(self, completion):
+ assert completion == sorted("-S -H".split())
+
+ @pytest.mark.complete("ulimit -a -H -")
+ def test_7(self, completion):
+ """Test modes are NOT completed with -a given somewhere."""
+ assert not completion
diff --git a/test/t/test_umount.py b/test/t/test_umount.py
new file mode 100644
index 0000000..2baf0da
--- /dev/null
+++ b/test/t/test_umount.py
@@ -0,0 +1,85 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+class TestUmount:
+ @pytest.fixture(scope="class")
+ def dummy_mnt(self, request, bash):
+ """
+ umount completion from fstab can't be tested directly because it
+ (correctly) uses absolute paths. So we create a custom completion which
+ reads from a file in our text fixture instead.
+ """
+ assert_bash_exec(bash, "unset COMPREPLY cur; unset -f _mnt_completion")
+ assert_bash_exec(
+ bash,
+ "_mnt_completion() { "
+ "local cur=$(_get_cword); "
+ "_linux_fstab $(_get_pword) < mount/test-fstab; "
+ "} && complete -F _mnt_completion _mnt",
+ )
+ request.addfinalizer(
+ lambda: assert_bash_exec(
+ bash, "complete -r _mnt; unset -f _mnt_completion"
+ )
+ )
+
+ @pytest.mark.complete("umount ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("_mnt /mnt/nice-test-p")
+ def test_mnt_basic(self, completion, dummy_mnt):
+ assert completion == "ath"
+
+ # Note in tests below that return only one result, that the result
+ # is shell unescaped due to how assert_complete handles the
+ # "one result on same line case".
+
+ @pytest.mark.complete(r"_mnt /mnt/nice\ test-p")
+ def test_mnt_space(self, completion, dummy_mnt):
+ assert completion == r"ath"
+
+ @pytest.mark.complete(r"_mnt /mnt/nice\$test-p")
+ def test_mnt_dollar(self, completion, dummy_mnt):
+ assert completion == "ath"
+
+ @pytest.mark.complete(r"_mnt /mnt/nice\ test\\p")
+ def test_mnt_backslash(self, completion, dummy_mnt):
+ assert completion == "ath"
+
+ @pytest.mark.complete(r"_mnt /mnt/nice\ ")
+ def test_mnt_after_space(self, completion, dummy_mnt):
+ assert completion == sorted(
+ (r"/mnt/nice\ test\\path", r"/mnt/nice\ test-path")
+ )
+
+ @pytest.mark.complete(r"_mnt /mnt/nice\$")
+ def test_mnt_at_dollar(self, completion, dummy_mnt):
+ assert completion == "test-path"
+
+ @pytest.mark.complete(r"_mnt /mnt/nice\'")
+ def test_mnt_at_quote(self, completion, dummy_mnt):
+ assert completion == "test-path"
+
+ @pytest.mark.complete("_mnt /mnt/other")
+ def test_mnt_other(self, completion, dummy_mnt):
+ assert completion == r"\'test\ path"
+
+ @pytest.mark.complete("_mnt -L Ubu")
+ def test_mnt_label_space(self, completion, dummy_mnt):
+ assert completion == r"ntu\ Karmic"
+
+ @pytest.mark.complete("_mnt -L Deb")
+ def test_mnt_label_quote(self, completion, dummy_mnt):
+ assert completion == r"ian-it\'s\ awesome"
+
+ def test_linux_fstab_unescape(self, bash):
+ assert_bash_exec(bash, r"var=one\'two\\040three\\")
+ assert_bash_exec(bash, "__linux_fstab_unescape var")
+ output = assert_bash_exec(
+ bash, r'printf "%s\n" "$var"', want_output=True
+ )
+ assert output.strip() == "one'two three\\"
+ assert_bash_exec(bash, "unset var")
diff --git a/test/t/test_unace.py b/test/t/test_unace.py
new file mode 100644
index 0000000..e4d5acb
--- /dev/null
+++ b/test/t/test_unace.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestUnace:
+ @pytest.mark.complete("unace -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_uname.py b/test/t/test_uname.py
new file mode 100644
index 0000000..e71a433
--- /dev/null
+++ b/test/t/test_uname.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestUname:
+ @pytest.mark.complete("uname --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_unexpand.py b/test/t/test_unexpand.py
new file mode 100644
index 0000000..2f1359b
--- /dev/null
+++ b/test/t/test_unexpand.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestUnexpand:
+ @pytest.mark.complete("unexpand --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_uniq.py b/test/t/test_uniq.py
new file mode 100644
index 0000000..73691fd
--- /dev/null
+++ b/test/t/test_uniq.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestUniq:
+ @pytest.mark.complete("uniq --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_units.py b/test/t/test_units.py
new file mode 100644
index 0000000..824e2ce
--- /dev/null
+++ b/test/t/test_units.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestUnits:
+ @pytest.mark.complete(
+ "units --", require_cmd=True, xfail="! units --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_unpack200.py b/test/t/test_unpack200.py
new file mode 100644
index 0000000..16c0402
--- /dev/null
+++ b/test/t/test_unpack200.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestUnpack200:
+ @pytest.mark.complete("unpack200 ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_unrar.py b/test/t/test_unrar.py
new file mode 100644
index 0000000..45e336e
--- /dev/null
+++ b/test/t/test_unrar.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestUnrar:
+ @pytest.mark.complete("unrar -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_unset.py b/test/t/test_unset.py
new file mode 100644
index 0000000..9f3eade
--- /dev/null
+++ b/test/t/test_unset.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestUnset:
+ @pytest.mark.complete("unset BASH_ARG")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_unshunt.py b/test/t/test_unshunt.py
new file mode 100644
index 0000000..a354239
--- /dev/null
+++ b/test/t/test_unshunt.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestUnshunt:
+ @pytest.mark.complete("unshunt --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_update_alternatives.py b/test/t/test_update_alternatives.py
new file mode 100644
index 0000000..7c77730
--- /dev/null
+++ b/test/t/test_update_alternatives.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="update-alternatives")
+class TestUpdateAlternatives:
+ @pytest.mark.complete("update-alternatives --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_update_rc_d.py b/test/t/test_update_rc_d.py
new file mode 100644
index 0000000..6f57416
--- /dev/null
+++ b/test/t/test_update_rc_d.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="update-rc.d")
+class TestUpdateRcD:
+ @pytest.mark.complete("update-rc.d -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_upgradepkg.py b/test/t/test_upgradepkg.py
new file mode 100644
index 0000000..87fe8e4
--- /dev/null
+++ b/test/t/test_upgradepkg.py
@@ -0,0 +1,51 @@
+import fnmatch
+import os
+
+import pytest
+
+
+class TestUpgradepkg:
+ @pytest.mark.complete("upgradepkg -")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("upgradepkg --")
+ def test_2(self, completion):
+ assert (
+ completion == "--dry-run --install-new --reinstall "
+ "--verbose".split()
+ )
+
+ @pytest.mark.complete("upgradepkg ", cwd="slackware/home")
+ def test_4(self, completion):
+ expected = sorted(
+ [
+ "%s/" % x
+ for x in os.listdir("slackware/home")
+ if os.path.isdir("./slackware/home/%s" % x)
+ ]
+ + [
+ x
+ for x in os.listdir("slackware/home")
+ if os.path.isfile("./slackware/home/%s" % x)
+ and fnmatch.fnmatch(x, "*.t[bglx]z")
+ ]
+ )
+ assert completion == expected
+
+ @pytest.mark.complete("upgradepkg foo%", cwd="slackware/home")
+ def test_after_percent(self, completion):
+ expected = sorted(
+ [
+ "%s/" % x
+ for x in os.listdir("slackware/home")
+ if os.path.isdir("./slackware/home/%s" % x)
+ ]
+ + [
+ x
+ for x in os.listdir("slackware/home")
+ if os.path.isfile("./slackware/home/%s" % x)
+ and fnmatch.fnmatch(x, "*.t[bglx]z")
+ ]
+ )
+ assert completion == ["foo%%%s" % x for x in expected]
diff --git a/test/t/test_urlsnarf.py b/test/t/test_urlsnarf.py
new file mode 100644
index 0000000..8551c60
--- /dev/null
+++ b/test/t/test_urlsnarf.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestUrlsnarf:
+ @pytest.mark.complete("urlsnarf -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_uscan.py b/test/t/test_uscan.py
new file mode 100644
index 0000000..142c325
--- /dev/null
+++ b/test/t/test_uscan.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestUscan:
+ @pytest.mark.complete("uscan -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_useradd.py b/test/t/test_useradd.py
new file mode 100644
index 0000000..5cbf6ce
--- /dev/null
+++ b/test/t/test_useradd.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestUseradd:
+ @pytest.mark.complete("useradd ")
+ def test_1(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("useradd -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_userdel.py b/test/t/test_userdel.py
new file mode 100644
index 0000000..3405e12
--- /dev/null
+++ b/test/t/test_userdel.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestUserdel:
+ @pytest.mark.complete("userdel -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("userdel roo")
+ def test_2(self, completion):
+ assert completion == "t" or "root" in completion
diff --git a/test/t/test_usermod.py b/test/t/test_usermod.py
new file mode 100644
index 0000000..ef3dd5a
--- /dev/null
+++ b/test/t/test_usermod.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestUsermod:
+ @pytest.mark.complete("usermod ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("usermod -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_valgrind.py b/test/t/test_valgrind.py
new file mode 100644
index 0000000..0553b55
--- /dev/null
+++ b/test/t/test_valgrind.py
@@ -0,0 +1,42 @@
+import os
+
+import pytest
+
+
+class TestValgrind:
+
+ # b: Assume we have at least bash that starts with b in PATH
+ @pytest.mark.complete("valgrind b")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("valgrind -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("valgrind --tool=memche", require_cmd=True)
+ def test_3(self, completion):
+ assert completion == "ck" or "--tool=memcheck" in completion
+
+ @pytest.mark.complete(
+ "valgrind --tool=helgrind --history-l", require_cmd=True
+ )
+ def test_4(self, completion):
+ assert completion == "evel=" or "--history-level=" in completion
+ assert not completion.endswith(" ")
+
+ @pytest.mark.complete(r"valgrind --log-file=v\ 0.log ./bin/", cwd="shared")
+ def test_5(self, completion):
+ expected = sorted(
+ [
+ "%s/"
+ for x in os.listdir("shared/bin")
+ if os.path.isdir("shared/bin/%s" % x)
+ ]
+ + [
+ x
+ for x in os.listdir("shared/bin")
+ if os.path.isfile("shared/bin/%s" % x)
+ ]
+ )
+ assert completion == expected
diff --git a/test/t/test_vdir.py b/test/t/test_vdir.py
new file mode 100644
index 0000000..e186989
--- /dev/null
+++ b/test/t/test_vdir.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestVdir:
+ @pytest.mark.complete("vdir ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("vdir -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_vgcfgbackup.py b/test/t/test_vgcfgbackup.py
new file mode 100644
index 0000000..2e6c6f1
--- /dev/null
+++ b/test/t/test_vgcfgbackup.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestVgcfgbackup:
+ @pytest.mark.complete(
+ "vgcfgbackup -",
+ require_cmd=True,
+ xfail="! vgcfgbackup --help &>/dev/null",
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vgcfgrestore.py b/test/t/test_vgcfgrestore.py
new file mode 100644
index 0000000..acb1a38
--- /dev/null
+++ b/test/t/test_vgcfgrestore.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestVgcfgrestore:
+ @pytest.mark.complete(
+ "vgcfgrestore -",
+ require_cmd=True,
+ xfail="! vgcfgrestore --help &>/dev/null",
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vgchange.py b/test/t/test_vgchange.py
new file mode 100644
index 0000000..ed14f2a
--- /dev/null
+++ b/test/t/test_vgchange.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestVgchange:
+ @pytest.mark.complete(
+ "vgchange -", require_cmd=True, xfail="! vgchange --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vgck.py b/test/t/test_vgck.py
new file mode 100644
index 0000000..52ddf88
--- /dev/null
+++ b/test/t/test_vgck.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestVgck:
+ @pytest.mark.complete(
+ "vgck -", require_cmd=True, xfail="! vgck --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vgconvert.py b/test/t/test_vgconvert.py
new file mode 100644
index 0000000..029fe48
--- /dev/null
+++ b/test/t/test_vgconvert.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestVgconvert:
+ @pytest.mark.complete(
+ "vgconvert -", require_cmd=True, xfail="! vgconvert --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vgcreate.py b/test/t/test_vgcreate.py
new file mode 100644
index 0000000..40c1773
--- /dev/null
+++ b/test/t/test_vgcreate.py
@@ -0,0 +1,13 @@
+import pytest
+
+
+class TestVgcreate:
+ @pytest.mark.complete(
+ "vgcreate -", require_cmd=True, xfail="! vgcreate --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("vgcreate __does_not_exist__", require_cmd=True)
+ def test_2(self, completion):
+ assert not completion
diff --git a/test/t/test_vgdisplay.py b/test/t/test_vgdisplay.py
new file mode 100644
index 0000000..6066729
--- /dev/null
+++ b/test/t/test_vgdisplay.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestVgdisplay:
+ @pytest.mark.complete(
+ "vgdisplay -", require_cmd=True, xfail="! vgdisplay --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vgexport.py b/test/t/test_vgexport.py
new file mode 100644
index 0000000..96ecc3c
--- /dev/null
+++ b/test/t/test_vgexport.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestVgexport:
+ @pytest.mark.complete(
+ "vgexport -", require_cmd=True, xfail="! vgexport --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vgextend.py b/test/t/test_vgextend.py
new file mode 100644
index 0000000..8c41ab6
--- /dev/null
+++ b/test/t/test_vgextend.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestVgextend:
+ @pytest.mark.complete(
+ "vgextend -", require_cmd=True, xfail="! vgextend --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vgimport.py b/test/t/test_vgimport.py
new file mode 100644
index 0000000..24017d2
--- /dev/null
+++ b/test/t/test_vgimport.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestVgimport:
+ @pytest.mark.complete(
+ "vgimport -", require_cmd=True, xfail="! vgimport --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vgmerge.py b/test/t/test_vgmerge.py
new file mode 100644
index 0000000..7d88932
--- /dev/null
+++ b/test/t/test_vgmerge.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestVgmerge:
+ @pytest.mark.complete(
+ "vgmerge -", require_cmd=True, xfail="! vgmerge --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vgmknodes.py b/test/t/test_vgmknodes.py
new file mode 100644
index 0000000..7e046f0
--- /dev/null
+++ b/test/t/test_vgmknodes.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestVgmknodes:
+ @pytest.mark.complete(
+ "vgmknodes -", require_cmd=True, xfail="! vgmknodes --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vgreduce.py b/test/t/test_vgreduce.py
new file mode 100644
index 0000000..26174b9
--- /dev/null
+++ b/test/t/test_vgreduce.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestVgreduce:
+ @pytest.mark.complete(
+ "vgreduce -", require_cmd=True, xfail="! vgreduce --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vgremove.py b/test/t/test_vgremove.py
new file mode 100644
index 0000000..637d5c3
--- /dev/null
+++ b/test/t/test_vgremove.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestVgremove:
+ @pytest.mark.complete(
+ "vgremove -", require_cmd=True, xfail="! vgremove --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vgrename.py b/test/t/test_vgrename.py
new file mode 100644
index 0000000..87a6a72
--- /dev/null
+++ b/test/t/test_vgrename.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestVgrename:
+ @pytest.mark.complete(
+ "vgrename -", require_cmd=True, xfail="! vgrename --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vgs.py b/test/t/test_vgs.py
new file mode 100644
index 0000000..e0d8a03
--- /dev/null
+++ b/test/t/test_vgs.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestVgs:
+ @pytest.mark.complete(
+ "vgs -", require_cmd=True, xfail="! vgs --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vgscan.py b/test/t/test_vgscan.py
new file mode 100644
index 0000000..95a4026
--- /dev/null
+++ b/test/t/test_vgscan.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestVgscan:
+ @pytest.mark.complete(
+ "vgscan -", require_cmd=True, xfail="! vgscan --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vgsplit.py b/test/t/test_vgsplit.py
new file mode 100644
index 0000000..1c3dfa8
--- /dev/null
+++ b/test/t/test_vgsplit.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestVgsplit:
+ @pytest.mark.complete(
+ "vgsplit -", require_cmd=True, xfail="! vgsplit --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vi.py b/test/t/test_vi.py
new file mode 100644
index 0000000..4f7f4c2
--- /dev/null
+++ b/test/t/test_vi.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestVi:
+ @pytest.mark.complete("vi ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("vi shared/ld.so.conf.d/")
+ def test_2(self, completion):
+ assert completion == "foo.txt libfoo.conf".split()
diff --git a/test/t/test_vipw.py b/test/t/test_vipw.py
new file mode 100644
index 0000000..07b454b
--- /dev/null
+++ b/test/t/test_vipw.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestVipw:
+ @pytest.mark.complete("vipw -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vmstat.py b/test/t/test_vmstat.py
new file mode 100644
index 0000000..b7145ff
--- /dev/null
+++ b/test/t/test_vmstat.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestVmstat:
+ @pytest.mark.complete("vmstat -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vncviewer.py b/test/t/test_vncviewer.py
new file mode 100644
index 0000000..9e2f148
--- /dev/null
+++ b/test/t/test_vncviewer.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(ignore_env=r"^-declare -f _vncviewer_bootstrap$")
+class TestVncviewer:
+ @pytest.mark.complete("vncviewer ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_vpnc.py b/test/t/test_vpnc.py
new file mode 100644
index 0000000..dac5b15
--- /dev/null
+++ b/test/t/test_vpnc.py
@@ -0,0 +1,13 @@
+import pytest
+
+
+@pytest.mark.bashcomp(
+ # On CentOS and Fedora, there's something fishy with consolehelper and
+ # /usr/bin/vpnc going on at least when invoked as root; try to invoke the
+ # one in /usr/sbin instead.
+ pre_cmds=("PATH=/usr/sbin:$PATH",)
+)
+class TestVpnc:
+ @pytest.mark.complete("vpnc -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_watch.py b/test/t/test_watch.py
new file mode 100644
index 0000000..b1de7f5
--- /dev/null
+++ b/test/t/test_watch.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestWatch:
+ @pytest.mark.complete("watch -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_wc.py b/test/t/test_wc.py
new file mode 100644
index 0000000..1f83ea7
--- /dev/null
+++ b/test/t/test_wc.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestWc:
+ @pytest.mark.complete("wc --", require_longopt=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_webmitm.py b/test/t/test_webmitm.py
new file mode 100644
index 0000000..d631dcf
--- /dev/null
+++ b/test/t/test_webmitm.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestWebmitm:
+ @pytest.mark.complete("webmitm -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_wget.py b/test/t/test_wget.py
new file mode 100644
index 0000000..de752c2
--- /dev/null
+++ b/test/t/test_wget.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestWget:
+ @pytest.mark.complete("wget ")
+ def test_1(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("wget --s", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_who.py b/test/t/test_who.py
new file mode 100644
index 0000000..9131ac7
--- /dev/null
+++ b/test/t/test_who.py
@@ -0,0 +1,9 @@
+import pytest
+
+
+class TestWho:
+ @pytest.mark.complete(
+ "who --", require_cmd=True, xfail="! who --help &>/dev/null"
+ )
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_wine.py b/test/t/test_wine.py
new file mode 100644
index 0000000..d0e5698
--- /dev/null
+++ b/test/t/test_wine.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestWine:
+ @pytest.mark.complete("wine ", cwd="shared/default")
+ def test_1(self, completion):
+ assert completion == ["bar bar.d/", "foo.d/"]
+
+ @pytest.mark.complete("wine notepad ", cwd="shared/default")
+ def test_2(self, completion):
+ assert completion == ["bar", "bar bar.d/", "foo", "foo.d/"]
diff --git a/test/t/test_withlist.py b/test/t/test_withlist.py
new file mode 100644
index 0000000..752c394
--- /dev/null
+++ b/test/t/test_withlist.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestWithlist:
+ @pytest.mark.complete("withlist --")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_wodim.py b/test/t/test_wodim.py
new file mode 100644
index 0000000..4b785b6
--- /dev/null
+++ b/test/t/test_wodim.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestWodim:
+ @pytest.mark.complete("wodim ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_wol.py b/test/t/test_wol.py
new file mode 100644
index 0000000..bf04f76
--- /dev/null
+++ b/test/t/test_wol.py
@@ -0,0 +1,20 @@
+import pytest
+
+
+@pytest.mark.bashcomp(pre_cmds=("PATH=$PWD/shared/bin:$PATH",))
+class TestWol:
+ @pytest.mark.complete("wol ")
+ def test_1(self, completion):
+ assert all(
+ x in completion
+ for x in "00:00:00:00:00:00 11:11:11:11:11:11 "
+ "22:22:22:22:22:22 33:33:33:33:33:33".split()
+ )
+
+ @pytest.mark.complete("wol 00:")
+ def test_2(self, completion):
+ assert any(x.endswith("00:00:00:00:00") for x in completion)
+
+ @pytest.mark.complete("wol -", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_write.py b/test/t/test_write.py
new file mode 100644
index 0000000..fc4bfa0
--- /dev/null
+++ b/test/t/test_write.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestWrite:
+ @pytest.mark.complete("write roo")
+ def test_1(self, completion):
+ assert completion == "t" or "root" in completion
diff --git a/test/t/test_wsimport.py b/test/t/test_wsimport.py
new file mode 100644
index 0000000..8c27f4b
--- /dev/null
+++ b/test/t/test_wsimport.py
@@ -0,0 +1,18 @@
+import pytest
+
+
+class TestWsimport:
+ @pytest.mark.complete("wsimport ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete(
+ "wsimport -",
+ require_cmd=True,
+ xfail=(
+ "! (wsimport -help 2>&1 || :) | "
+ "command grep -q -- '[[:space:]]-'"
+ ),
+ )
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_wtf.py b/test/t/test_wtf.py
new file mode 100644
index 0000000..45dfcfd
--- /dev/null
+++ b/test/t/test_wtf.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+class TestWtf:
+ # TODO: actually requires an acronym db, not the cmd
+ @pytest.mark.complete("wtf A", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_wvdial.py b/test/t/test_wvdial.py
new file mode 100644
index 0000000..bbc520d
--- /dev/null
+++ b/test/t/test_wvdial.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestWvdial:
+ @pytest.mark.complete("wvdial -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_xdg_mime.py b/test/t/test_xdg_mime.py
new file mode 100644
index 0000000..432be06
--- /dev/null
+++ b/test/t/test_xdg_mime.py
@@ -0,0 +1,28 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="xdg-mime")
+class TestXdgMime:
+ @pytest.mark.complete("xdg-mime ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xdg-mime -")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xdg-mime query ")
+ def test_3(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xdg-mime query filetype ")
+ def test_4(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xdg-mime default foo.desktop ")
+ def test_5(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xdg-mime install --mode ")
+ def test_6(self, completion):
+ assert completion
diff --git a/test/t/test_xdg_settings.py b/test/t/test_xdg_settings.py
new file mode 100644
index 0000000..1a19459
--- /dev/null
+++ b/test/t/test_xdg_settings.py
@@ -0,0 +1,16 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="xdg-settings")
+class TestXdgSettings:
+ @pytest.mark.complete("xdg-settings ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xdg-settings --", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xdg-settings get ", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_xfreerdp.py b/test/t/test_xfreerdp.py
new file mode 100644
index 0000000..5616271
--- /dev/null
+++ b/test/t/test_xfreerdp.py
@@ -0,0 +1,60 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+class TestXfreerdp:
+ def _help(self, bash):
+ return assert_bash_exec(
+ bash, "xfreerdp --help 2>&1 || :", want_output=True
+ )
+
+ @pytest.fixture(scope="class")
+ def help_success(self, bash):
+ output = self._help(bash)
+ # Example from our CentOS 7 container
+ # [04:51:31:663] [238:238] [ERROR][com.freerdp.client.x11] - Failed to get pixmap info
+ if not output or "ERROR" in output.strip().splitlines()[0]:
+ pytest.skip("--help errored")
+
+ @pytest.fixture(scope="class")
+ def slash_syntax(self, bash, help_success):
+ if "/help" not in self._help(bash):
+ pytest.skip("Not slash syntax")
+
+ @pytest.fixture(scope="class")
+ def dash_syntax(self, bash):
+ if "/help" in self._help(bash):
+ pytest.skip("Not dash syntax")
+
+ @pytest.mark.complete("xfreerdp /", require_cmd=True)
+ def test_1(self, bash, completion, help_success, slash_syntax):
+ assert completion
+
+ @pytest.mark.complete("xfreerdp -", require_cmd=True)
+ def test_2(self, completion, help_success):
+ assert completion
+
+ @pytest.mark.complete("xfreerdp +", require_cmd=True)
+ def test_3(self, bash, completion, help_success, slash_syntax):
+ assert completion
+
+ @pytest.mark.complete(
+ "xfreerdp /kbd:",
+ require_cmd=True,
+ skipif='test -z "$(xfreerdp /kbd-list 2>/dev/null)"',
+ )
+ def test_4(self, bash, completion, help_success, slash_syntax):
+ assert completion
+
+ @pytest.mark.complete("xfreerdp /help ", require_cmd=True)
+ def test_5(self, completion, help_success):
+ assert not completion
+
+ @pytest.mark.complete("xfreerdp -k ", require_cmd=True)
+ def test_6(self, bash, completion, help_success, dash_syntax):
+ assert completion
+
+ @pytest.mark.complete("xfreerdp --help ", require_cmd=True)
+ def test_7(self, completion):
+ assert not completion
diff --git a/test/t/test_xgamma.py b/test/t/test_xgamma.py
new file mode 100644
index 0000000..151e2d3
--- /dev/null
+++ b/test/t/test_xgamma.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+class TestXgamma:
+ @pytest.mark.complete("xgamma -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xgamma -gam", require_cmd=True)
+ def test_2(self, completion):
+ assert completion == "ma"
+ assert completion.endswith(" ")
diff --git a/test/t/test_xhost.py b/test/t/test_xhost.py
new file mode 100644
index 0000000..bb2df82
--- /dev/null
+++ b/test/t/test_xhost.py
@@ -0,0 +1,22 @@
+import pytest
+
+from conftest import assert_complete, partialize
+
+
+@pytest.mark.bashcomp(pre_cmds=("HOME=$PWD",))
+class TestXhost:
+ @pytest.mark.parametrize("prefix", ["+", "-", ""])
+ def test_hosts(self, bash, hosts, prefix):
+ completion = assert_complete(bash, "xhost %s" % prefix)
+ assert completion == ["%s%s" % (prefix, x) for x in hosts]
+
+ @pytest.mark.parametrize("prefix", ["+", "-", ""])
+ def test_partial_hosts(self, bash, hosts, prefix):
+ first_char, partial_hosts = partialize(bash, hosts)
+ completion = assert_complete(bash, "xhost %s%s" % (prefix, first_char))
+ if len(completion) == 1:
+ assert completion == partial_hosts[0][1:]
+ else:
+ assert completion == sorted(
+ "%s%s" % (prefix, x) for x in partial_hosts
+ )
diff --git a/test/t/test_xm.py b/test/t/test_xm.py
new file mode 100644
index 0000000..42c4c53
--- /dev/null
+++ b/test/t/test_xm.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestXm:
+ @pytest.mark.complete("xm ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_xmllint.py b/test/t/test_xmllint.py
new file mode 100644
index 0000000..21c52c7
--- /dev/null
+++ b/test/t/test_xmllint.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestXmllint:
+ @pytest.mark.complete("xmllint ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xmllint -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_xmlwf.py b/test/t/test_xmlwf.py
new file mode 100644
index 0000000..901f78a
--- /dev/null
+++ b/test/t/test_xmlwf.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestXmlwf:
+ @pytest.mark.complete("xmlwf ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xmlwf -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_xmms.py b/test/t/test_xmms.py
new file mode 100644
index 0000000..a880b16
--- /dev/null
+++ b/test/t/test_xmms.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestXmms:
+ @pytest.mark.complete("xmms --", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xmms --non-existent-option=--")
+ def test_2(self, completion):
+ assert not completion
diff --git a/test/t/test_xmodmap.py b/test/t/test_xmodmap.py
new file mode 100644
index 0000000..cc33d73
--- /dev/null
+++ b/test/t/test_xmodmap.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestXmodmap:
+ @pytest.mark.complete("xmodmap ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xmodmap -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_xpovray.py b/test/t/test_xpovray.py
new file mode 100644
index 0000000..4f603a7
--- /dev/null
+++ b/test/t/test_xpovray.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestXpovray:
+ @pytest.mark.complete("xpovray ")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_xrandr.py b/test/t/test_xrandr.py
new file mode 100644
index 0000000..e766922
--- /dev/null
+++ b/test/t/test_xrandr.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestXrandr:
+ @pytest.mark.complete("xrandr ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xrandr --mode ")
+ def test_2(self, completion):
+ assert not completion
+
+ @pytest.mark.complete("xrandr -", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_xrdb.py b/test/t/test_xrdb.py
new file mode 100644
index 0000000..3ffce2c
--- /dev/null
+++ b/test/t/test_xrdb.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestXrdb:
+ @pytest.mark.complete("xrdb ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xrdb -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_xsltproc.py b/test/t/test_xsltproc.py
new file mode 100644
index 0000000..259f9eb
--- /dev/null
+++ b/test/t/test_xsltproc.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestXsltproc:
+ @pytest.mark.complete("xsltproc ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xsltproc -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_xvfb_run.py b/test/t/test_xvfb_run.py
new file mode 100644
index 0000000..89eb830
--- /dev/null
+++ b/test/t/test_xvfb_run.py
@@ -0,0 +1,12 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="xvfb-run")
+class TestXvfbRun:
+ @pytest.mark.complete("xvfb-run ")
+ def test_no_args(self, completion):
+ assert any(x in completion for x in ("bash", "xvfb-run"))
+
+ @pytest.mark.complete("xvfb-run -", require_cmd=True)
+ def test_options(self, completion):
+ assert completion
diff --git a/test/t/test_xvnc4viewer.py b/test/t/test_xvnc4viewer.py
new file mode 100644
index 0000000..72fe3f9
--- /dev/null
+++ b/test/t/test_xvnc4viewer.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestXvnc4viewer:
+ @pytest.mark.complete("xvnc4viewer -")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xvnc4viewer -PreferredEncoding ")
+ def test_2(self, completion):
+ assert completion == "hextile raw zrle".split()
+
+ @pytest.mark.complete("xvnc4viewer --preferredencoding ")
+ def test_3(self, completion):
+ assert completion == "hextile raw zrle".split()
diff --git a/test/t/test_xxd.py b/test/t/test_xxd.py
new file mode 100644
index 0000000..9e84bb7
--- /dev/null
+++ b/test/t/test_xxd.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestXxd:
+ @pytest.mark.complete("xxd ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xxd -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_xz.py b/test/t/test_xz.py
new file mode 100644
index 0000000..f226d02
--- /dev/null
+++ b/test/t/test_xz.py
@@ -0,0 +1,26 @@
+import pytest
+
+
+class TestXz:
+ @pytest.mark.complete("xz ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xz -d xz/")
+ def test_2(self, completion):
+ assert (
+ completion == "a/ bashcomp.lzma bashcomp.tar.xz "
+ "bashcomp.tlz bashcomp.xz".split()
+ )
+
+ @pytest.mark.complete("xz xz/")
+ def test_3(self, completion):
+ assert completion == "a/ bashcomp.tar".split()
+
+ @pytest.mark.complete("xz ~")
+ def test_4(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xz -", require_cmd=True)
+ def test_5(self, completion):
+ assert completion
diff --git a/test/t/test_xzdec.py b/test/t/test_xzdec.py
new file mode 100644
index 0000000..a1e9a3b
--- /dev/null
+++ b/test/t/test_xzdec.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestXzdec:
+ @pytest.mark.complete("xzdec ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("xzdec -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/test_ypcat.py b/test/t/test_ypcat.py
new file mode 100644
index 0000000..0fc4b45
--- /dev/null
+++ b/test/t/test_ypcat.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestYpcat:
+ @pytest.mark.complete("ypcat ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_ypmatch.py b/test/t/test_ypmatch.py
new file mode 100644
index 0000000..18331aa
--- /dev/null
+++ b/test/t/test_ypmatch.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+class TestYpmatch:
+ # Actually requires ypcat
+ @pytest.mark.complete("ypmatch foo ", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_yum.py b/test/t/test_yum.py
new file mode 100644
index 0000000..5dd1eba
--- /dev/null
+++ b/test/t/test_yum.py
@@ -0,0 +1,7 @@
+import pytest
+
+
+class TestYum:
+ @pytest.mark.complete("yum -", require_cmd=True)
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_yum_arch.py b/test/t/test_yum_arch.py
new file mode 100644
index 0000000..9bbc38f
--- /dev/null
+++ b/test/t/test_yum_arch.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.bashcomp(cmd="yum-arch")
+class TestYumArch:
+ @pytest.mark.complete("yum-arch -")
+ def test_1(self, completion):
+ assert completion
diff --git a/test/t/test_zopfli.py b/test/t/test_zopfli.py
new file mode 100644
index 0000000..e5a71b3
--- /dev/null
+++ b/test/t/test_zopfli.py
@@ -0,0 +1,15 @@
+import pytest
+
+
+class TestZopfli:
+ @pytest.mark.complete("zopfli ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("zopfli ~")
+ def test_2(self, completion):
+ assert completion
+
+ @pytest.mark.complete("zopfli -", require_cmd=True)
+ def test_3(self, completion):
+ assert completion
diff --git a/test/t/test_zopflipng.py b/test/t/test_zopflipng.py
new file mode 100644
index 0000000..3ff120f
--- /dev/null
+++ b/test/t/test_zopflipng.py
@@ -0,0 +1,11 @@
+import pytest
+
+
+class TestZopflipng:
+ @pytest.mark.complete("zopflipng ")
+ def test_1(self, completion):
+ assert completion
+
+ @pytest.mark.complete("zopflipng -", require_cmd=True)
+ def test_2(self, completion):
+ assert completion
diff --git a/test/t/unit/Makefile.am b/test/t/unit/Makefile.am
new file mode 100644
index 0000000..3eb652a
--- /dev/null
+++ b/test/t/unit/Makefile.am
@@ -0,0 +1,24 @@
+EXTRA_DIST = \
+ test_unit_count_args.py \
+ test_unit_expand.py \
+ test_unit_expand_tilde_by_ref.py \
+ test_unit_filedir.py \
+ test_unit_find_unique_completion_pair.py \
+ test_unit_get_comp_words_by_ref.py \
+ test_unit_get_cword.py \
+ test_unit_init_completion.py \
+ test_unit_ip_addresses.py \
+ test_unit_known_hosts_real.py \
+ test_unit_longopt.py \
+ test_unit_parse_help.py \
+ test_unit_parse_usage.py \
+ test_unit_quote.py \
+ test_unit_quote_readline.py \
+ test_unit_tilde.py \
+ test_unit_variables.py \
+ test_unit_xinetd_services.py
+
+all:
+
+clean-local:
+ $(RM) -R __pycache__
diff --git a/test/t/unit/test_unit_count_args.py b/test/t/unit/test_unit_count_args.py
new file mode 100644
index 0000000..56bce2c
--- /dev/null
+++ b/test/t/unit/test_unit_count_args.py
@@ -0,0 +1,66 @@
+import pytest
+
+from conftest import TestUnitBase, assert_bash_exec
+
+
+@pytest.mark.bashcomp(
+ cmd=None, ignore_env=r"^[+-](args|COMP_(WORDS|CWORD|LINE|POINT))="
+)
+class TestUnitCountArgs(TestUnitBase):
+ def _test(self, *args, **kwargs):
+ return self._test_unit("_count_args %s; echo $args", *args, **kwargs)
+
+ def test_1(self, bash):
+ assert_bash_exec(bash, "COMP_CWORD= _count_args >/dev/null")
+
+ def test_2(self, bash):
+ """a b| should set args to 1"""
+ output = self._test(bash, "(a b)", 1, "a b", 3)
+ assert output == "1"
+
+ def test_3(self, bash):
+ """a b|c should set args to 1"""
+ output = self._test(bash, "(a bc)", 1, "a bc", 3)
+ assert output == "1"
+
+ def test_4(self, bash):
+ """a b c| should set args to 2"""
+ output = self._test(bash, "(a b c)", 2, "a b c", 4)
+ assert output == "2"
+
+ def test_5(self, bash):
+ """a b| c should set args to 1"""
+ output = self._test(bash, "(a b c)", 1, "a b c", 3)
+ assert output == "1"
+
+ def test_6(self, bash):
+ """a b -c| d should set args to 2"""
+ output = self._test(bash, "(a b -c d)", 2, "a b -c d", 6)
+ assert output == "2"
+
+ def test_7(self, bash):
+ """a b -c d e| with -c arg excluded should set args to 2"""
+ output = self._test(
+ bash, "(a b -c d e)", 4, "a b -c d e", 10, arg='"" "@(-c|--foo)"'
+ )
+ assert output == "2"
+
+ def test_8(self, bash):
+ """a -b -c d e| with -c arg excluded
+ and -b included should set args to 1"""
+ output = self._test(
+ bash,
+ "(a -b -c d e)",
+ 4,
+ "a -b -c d e",
+ 11,
+ arg='"" "@(-c|--foo)" "-[b]"',
+ )
+ assert output == "2"
+
+ def test_9(self, bash):
+ """a -b -c d e| with -b included should set args to 3"""
+ output = self._test(
+ bash, "(a -b -c d e)", 4, "a -b -c d e", 11, arg='"" "" "-b"'
+ )
+ assert output == "3"
diff --git a/test/t/unit/test_unit_expand.py b/test/t/unit/test_unit_expand.py
new file mode 100644
index 0000000..d2a3ebc
--- /dev/null
+++ b/test/t/unit/test_unit_expand.py
@@ -0,0 +1,31 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+@pytest.mark.bashcomp(cmd=None, ignore_env=r"^[+-](cur|COMPREPLY)=")
+class TestUnitExpand:
+ def test_1(self, bash):
+ assert_bash_exec(bash, "_expand >/dev/null")
+
+ def test_2(self, bash):
+ """Test environment non-pollution, detected at teardown."""
+ assert_bash_exec(bash, "foo() { _expand; }; foo; unset foo")
+
+ def test_user_home_compreply(self, bash, user_home):
+ user, home = user_home
+ output = assert_bash_exec(
+ bash,
+ r'cur="~%s"; _expand; printf "%%s\n" "$COMPREPLY"' % user,
+ want_output=True,
+ )
+ assert output.strip() == home
+
+ def test_user_home_cur(self, bash, user_home):
+ user, home = user_home
+ output = assert_bash_exec(
+ bash,
+ r'cur="~%s/a"; _expand; printf "%%s\n" "$cur"' % user,
+ want_output=True,
+ )
+ assert output.strip() == "%s/a" % home
diff --git a/test/t/unit/test_unit_expand_tilde_by_ref.py b/test/t/unit/test_unit_expand_tilde_by_ref.py
new file mode 100644
index 0000000..17bdedf
--- /dev/null
+++ b/test/t/unit/test_unit_expand_tilde_by_ref.py
@@ -0,0 +1,46 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+@pytest.mark.bashcomp(cmd=None, ignore_env=r"^[+-]var=")
+class TestUnitExpandTildeByRef:
+ def test_1(self, bash):
+ assert_bash_exec(bash, "__expand_tilde_by_ref >/dev/null")
+
+ def test_2(self, bash):
+ """Test environment non-pollution, detected at teardown."""
+ assert_bash_exec(
+ bash,
+ '_x() { local aa="~"; __expand_tilde_by_ref aa; }; _x; unset _x',
+ )
+
+ @pytest.mark.parametrize("plain_tilde", (True, False))
+ @pytest.mark.parametrize(
+ "suffix_expanded",
+ (
+ ("", True),
+ ("/foo", True),
+ (r"/\$HOME", True),
+ ("/a b", True),
+ ("/*", True),
+ (";echo hello", False),
+ ("/a;echo hello", True),
+ ),
+ )
+ def test_expand(self, bash, user_home, plain_tilde, suffix_expanded):
+ user, home = user_home
+ suffix, expanded = suffix_expanded
+ if plain_tilde:
+ user = ""
+ if not suffix or not expanded:
+ home = "~"
+ elif not expanded:
+ home = "~%s" % user
+ output = assert_bash_exec(
+ bash,
+ r'var="~%s%s"; __expand_tilde_by_ref var; printf "%%s\n" "$var"'
+ % (user, suffix),
+ want_output=True,
+ )
+ assert output.strip() == "%s%s" % (home, suffix.replace(r"\$", "$"),)
diff --git a/test/t/unit/test_unit_filedir.py b/test/t/unit/test_unit_filedir.py
new file mode 100644
index 0000000..b847efc
--- /dev/null
+++ b/test/t/unit/test_unit_filedir.py
@@ -0,0 +1,235 @@
+import os
+import shutil
+import sys
+import tempfile
+from pathlib import Path
+
+import pytest
+
+from conftest import assert_bash_exec, assert_complete
+
+
+@pytest.mark.bashcomp(cmd=None, ignore_env=r"^\+COMPREPLY=")
+class TestUnitFiledir:
+ @pytest.fixture(scope="class")
+ def functions(self, request, bash):
+ assert_bash_exec(
+ bash,
+ "_f() { local cur=$(_get_cword); unset COMPREPLY; _filedir; }; "
+ "complete -F _f f; "
+ "complete -F _f -o filenames f2",
+ )
+ assert_bash_exec(
+ bash,
+ "_g() { local cur=$(_get_cword); unset COMPREPLY; _filedir e1; }; "
+ "complete -F _g g",
+ )
+ assert_bash_exec(
+ bash,
+ "_fd() { local cur=$(_get_cword); unset COMPREPLY; _filedir -d; };"
+ "complete -F _fd fd",
+ )
+
+ @pytest.fixture(scope="class")
+ def non_windows_testdir(self, request, bash):
+ if sys.platform.startswith("win"):
+ pytest.skip("Filenames not allowed on Windows")
+ tempdir = Path(tempfile.mkdtemp(prefix="bash-completion_filedir"))
+ request.addfinalizer(lambda: shutil.rmtree(str(tempdir)))
+ subdir = tempdir / 'a"b'
+ subdir.mkdir()
+ (subdir / "d").touch()
+ subdir = tempdir / "a*b"
+ subdir.mkdir()
+ (subdir / "j").touch()
+ subdir = tempdir / r"a\b"
+ subdir.mkdir()
+ (subdir / "g").touch()
+ return tempdir
+
+ @pytest.fixture(scope="class")
+ def utf8_ctype(self, bash):
+ # TODO: this likely is not the right thing to do. Instead we should
+ # grab the setting from the running shell, possibly eval $(locale)
+ # in a subshell and grab LC_CTYPE from there. That doesn't seem to work
+ # either everywhere though.
+ lc_ctype = os.environ.get("LC_CTYPE", "")
+ if "UTF-8" not in lc_ctype:
+ pytest.skip("Applicable only in LC_CTYPE=UTF-8 setups")
+ return lc_ctype
+
+ def test_1(self, bash):
+ assert_bash_exec(bash, "_filedir >/dev/null")
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_2(self, bash, functions, funcname):
+ completion = assert_complete(bash, "%s ab/" % funcname, cwd="_filedir")
+ assert completion == "e"
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_3(self, bash, functions, funcname):
+ completion = assert_complete(
+ bash, r"%s a\ b/" % funcname, cwd="_filedir"
+ )
+ assert completion == "i"
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_4(self, bash, functions, funcname):
+ completion = assert_complete(
+ bash, r"%s a\'b/" % funcname, cwd="_filedir"
+ )
+ assert completion == "c"
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_5(self, bash, functions, funcname):
+ completion = assert_complete(
+ bash, r"%s a\&b/" % funcname, cwd="_filedir"
+ )
+ assert completion == "f"
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_6(self, bash, functions, funcname):
+ completion = assert_complete(
+ bash, r"%s a\$" % funcname, cwd="_filedir"
+ )
+ assert completion == "b/"
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_7(self, bash, functions, funcname):
+ completion = assert_complete(
+ bash, r"%s 'ab/" % funcname, cwd="_filedir"
+ )
+ assert completion == "e'"
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_8(self, bash, functions, funcname):
+ completion = assert_complete(
+ bash, r"%s 'a b/" % funcname, cwd="_filedir"
+ )
+ assert completion == "i'"
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_9(self, bash, functions, funcname):
+ completion = assert_complete(
+ bash, r"%s 'a$b/" % funcname, cwd="_filedir"
+ )
+ assert completion == "h'"
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_10(self, bash, functions, funcname):
+ completion = assert_complete(
+ bash, r"%s 'a&b/" % funcname, cwd="_filedir"
+ )
+ assert completion == "f'"
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_11(self, bash, functions, funcname):
+ completion = assert_complete(
+ bash, r'%s "ab/' % funcname, cwd="_filedir"
+ )
+ assert completion == 'e"'
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_12(self, bash, functions, funcname):
+ completion = assert_complete(
+ bash, r'%s "a b/' % funcname, cwd="_filedir"
+ )
+ assert completion == 'i"'
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_13(self, bash, functions, funcname):
+ completion = assert_complete(
+ bash, "%s \"a'b/" % funcname, cwd="_filedir"
+ )
+ assert completion == 'c"'
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_14(self, bash, functions, funcname):
+ completion = assert_complete(
+ bash, '%s "a&b/' % funcname, cwd="_filedir"
+ )
+ assert completion == 'f"'
+
+ @pytest.mark.complete(r"fd a\ ", cwd="_filedir")
+ def test_15(self, functions, completion):
+ assert completion == "b/"
+
+ @pytest.mark.complete("g ", cwd="_filedir/ext")
+ def test_16(self, functions, completion):
+ assert completion == sorted("ee.e1 foo/ gg.e1 ii.E1".split())
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_17(self, bash, functions, funcname):
+ completion = assert_complete(
+ bash, r"%s a\$b/" % funcname, cwd="_filedir"
+ )
+ assert completion == "h"
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_18(self, bash, functions, funcname):
+ completion = assert_complete(
+ bash, r"%s \[x" % funcname, cwd="_filedir/brackets"
+ )
+ assert completion == r"\]"
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_19(self, bash, functions, funcname, non_windows_testdir):
+ completion = assert_complete(
+ bash, '%s a\\"b/' % funcname, cwd=non_windows_testdir
+ )
+ assert completion == "d"
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_20(self, bash, functions, funcname, non_windows_testdir):
+ completion = assert_complete(
+ bash, r"%s a\\b/" % funcname, cwd=non_windows_testdir
+ )
+ assert completion == "g"
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_21(self, bash, functions, funcname, non_windows_testdir):
+ completion = assert_complete(
+ bash, "%s 'a\"b/" % funcname, cwd=non_windows_testdir
+ )
+ assert completion == "d'"
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_22(self, bash, functions, funcname, non_windows_testdir):
+ completion = assert_complete(
+ bash, r"%s '%s/a\b/" % (funcname, non_windows_testdir)
+ )
+ assert completion == "g'"
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_23(self, bash, functions, funcname, non_windows_testdir):
+ completion = assert_complete(
+ bash, r'%s "a\"b/' % funcname, cwd=non_windows_testdir
+ )
+ assert completion == 'd"'
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_24(self, bash, functions, funcname, non_windows_testdir):
+ completion = assert_complete(
+ bash, r'%s "a\\b/' % funcname, cwd=non_windows_testdir
+ )
+ assert completion == 'g"'
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_25(self, bash, functions, funcname):
+ completion = assert_complete(
+ bash, r'%s "a\b/' % funcname, cwd="_filedir"
+ )
+ assert completion == '\b\b\bb/e"'
+
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_26(self, bash, functions, funcname):
+ completion = assert_complete(
+ bash, r'%s "a\$b/' % funcname, cwd="_filedir"
+ )
+ assert completion == 'h"'
+
+ @pytest.mark.xfail(reason="TODO: non-ASCII issues with test suite?")
+ @pytest.mark.parametrize("funcname", "f f2".split())
+ def test_27(self, bash, functions, funcname, utf8_ctype):
+ completion = assert_complete(bash, "%s aé/" % funcname, cwd="_filedir")
+ assert completion == "g"
diff --git a/test/t/unit/test_unit_find_unique_completion_pair.py b/test/t/unit/test_unit_find_unique_completion_pair.py
new file mode 100644
index 0000000..25cf9d3
--- /dev/null
+++ b/test/t/unit/test_unit_find_unique_completion_pair.py
@@ -0,0 +1,55 @@
+import pytest
+
+from conftest import find_unique_completion_pair
+
+
+@pytest.mark.bashcomp(cmd=None)
+class TestUnitFindUniqueCompletionPair:
+ def _test(self, inp: str, exp: str) -> None:
+ res = find_unique_completion_pair(inp.split())
+ if exp:
+ part, cont = exp.split()
+ assert res == (part, part + cont)
+ else:
+ assert not exp
+
+ def test_1(self):
+ self._test("a", "")
+
+ def test_2(self):
+ self._test("ab", "a b")
+
+ def test_3(self):
+ self._test("ab ab ab", "a b")
+
+ def test_4(self):
+ self._test("a ab abcd abc", "")
+
+ def test_5(self):
+ self._test("user1 user2", "")
+
+ def test_6(self):
+ self._test("root username1 username2", "ro ot")
+
+ def test_7(self):
+ self._test("root username21 username2", "ro ot")
+
+ def test_8(self):
+ self._test(
+ "long_user_name lang_user_name long_usor_name", "lang_us er_name"
+ )
+
+ def test_9(self):
+ self._test(
+ "lang_user_name1 long_user_name lang_user_name long_usor_name",
+ "long_use r_name",
+ )
+
+ def test_10(self):
+ self._test("root username", "user name")
+
+ def test_11(self):
+ self._test("a aladin", "ala din")
+
+ def test_12(self):
+ self._test("ala aladin", "alad in")
diff --git a/test/t/unit/test_unit_get_comp_words_by_ref.py b/test/t/unit/test_unit_get_comp_words_by_ref.py
new file mode 100644
index 0000000..b6498fa
--- /dev/null
+++ b/test/t/unit/test_unit_get_comp_words_by_ref.py
@@ -0,0 +1,260 @@
+import pytest
+
+from conftest import TestUnitBase, assert_bash_exec
+
+
+@pytest.mark.bashcomp(
+ cmd=None,
+ ignore_env=r"^(\+(words|cword|cur|prev)|[+-]COMP_(WORDS|CWORD|LINE|POINT))=",
+)
+class TestUnitGetCompWordsByRef(TestUnitBase):
+ def _test(self, bash, *args, **kwargs):
+ assert_bash_exec(bash, "unset cur prev")
+ output = self._test_unit(
+ "_get_comp_words_by_ref %s cur prev; echo $cur,${prev-}",
+ bash,
+ *args,
+ **kwargs
+ )
+ return output.strip()
+
+ def test_1(self, bash):
+ assert_bash_exec(
+ bash,
+ "COMP_WORDS=() COMP_CWORD= COMP_POINT= COMP_LINE= "
+ "_get_comp_words_by_ref cur >/dev/null",
+ )
+
+ def test_2(self, bash):
+ """a b|"""
+ output = self._test(bash, "(a b)", 1, "a b", 3)
+ assert output == "b,a"
+
+ def test_3(self, bash):
+ """a |"""
+ output = self._test(bash, "(a)", 1, "a ", 2)
+ assert output == ",a"
+
+ def test_4(self, bash):
+ """|a"""
+ output = self._test(bash, "(a)", 0, "a", 0)
+ assert output == ","
+
+ def test_5(self, bash):
+ """|a """
+ output = self._test(bash, "(a)", 0, "a ", 0)
+ assert output == ","
+
+ def test_6(self, bash):
+ """ | a """
+ output = self._test(bash, "(a)", 0, " a ", 1)
+ assert output.strip() == ","
+
+ def test_7(self, bash):
+ """a b |"""
+ output = self._test(bash, "(a b '')", 2, "a b ", 4)
+ assert output == ",b"
+
+ def test_8(self, bash):
+ """a b | with WORDBREAKS -= :"""
+ output = self._test(bash, "(a b '')", 2, "a b ", 4, arg="-n :")
+ assert output == ",b"
+
+ def test_9(self, bash):
+ """a b|c"""
+ output = self._test(bash, "(a bc)", 1, "a bc", 3)
+ assert output == "b,a"
+
+ def test_10(self, bash):
+ """a | b"""
+ output = self._test(bash, "(a b)", 1, "a b", 2)
+ assert output == ",a"
+
+ def test_11(self, bash):
+ r"""a b\ c|"""
+ output = self._test(bash, r"(a 'b\ c')", 1, r"a b\ c", 6)
+ assert output == r"b\ c,a"
+
+ def test_12(self, bash):
+ r"""a\ b a\ b|"""
+ output = self._test(bash, r"('a\ b' 'a\ b')", 1, r"a\ b a\ b", 9)
+ assert output == r"a\ b,a\ b"
+
+ def test_13(self, bash):
+ r"""a b\| c"""
+ output = self._test(bash, r"(a 'b\ c')", 1, r"a b\ c", 4)
+ assert output == r"b\,a"
+
+ def test_14(self, bash):
+ r"""a "b\|"""
+ output = self._test(bash, "(a '\"b')", 1, 'a "b\\', 5)
+ assert output == r'"b\,a'
+
+ def test_15(self, bash):
+ """a 'b c|"""
+ output = self._test(bash, '(a "\'b c")', 1, "a 'b c", 6)
+ assert output == "'b c,a"
+
+ def test_16(self, bash):
+ """a "b c|"""
+ output = self._test(bash, r'(a "\"b c")', 1, 'a "b c', 6)
+ assert output == '"b c,a'
+
+ def test_17(self, bash):
+ """a b:c| with WORDBREAKS += :"""
+ assert_bash_exec(bash, "add_comp_wordbreak_char :")
+ output = self._test(bash, "(a b : c)", 3, "a b:c", 5)
+ assert output == "c,:"
+
+ def test_18(self, bash):
+ """a b:c| with WORDBREAKS -= :"""
+ output = self._test(bash, "(a b : c)", 3, "a b:c", 5, arg="-n :")
+ assert output == "b:c,a"
+
+ def test_19(self, bash):
+ """a b c:| with WORDBREAKS -= :"""
+ output = self._test(bash, "(a b c :)", 3, "a b c:", 6, arg="-n :")
+ assert output == "c:,b"
+
+ def test_20(self, bash):
+ r"""a b:c | with WORDBREAKS -= :"""
+ output = self._test(bash, "(a b : c '')", 4, "a b:c ", 6, arg="-n :")
+ assert output == ",b:c"
+
+ def test_21(self, bash):
+ """a :| with WORDBREAKS -= :"""
+ output = self._test(bash, "(a :)", 1, "a :", 3, arg="-n :")
+ assert output == ":,a"
+
+ def test_22(self, bash):
+ """a b::| with WORDBREAKS -= :"""
+ output = self._test(bash, "(a b ::)", 2, "a b::", 5, arg="-n :")
+ assert output == "b::,a"
+
+ def test_23(self, bash):
+ """a -n|
+
+ This test makes sure `_get_cword' doesn't use `echo' to return its
+ value, because -n might be interpreted by `echo' and thus woud not
+ be returned.
+ """
+ output = self._test(bash, "(a -n)", 1, "a -n", 4)
+ assert output == "-n,a"
+
+ def test_24(self, bash):
+ """a b>c|"""
+ output = self._test(bash, r"(a b \> c)", 3, "a b>c", 5)
+ assert output.startswith("c,")
+
+ def test_25(self, bash):
+ """a b=c|"""
+ output = self._test(bash, "(a b = c)", 3, "a b=c", 5)
+ assert output.startswith("c,")
+
+ def test_26(self, bash):
+ """a *|"""
+ output = self._test(bash, r"(a \*)", 1, "a *", 4)
+ assert output == "*,a"
+
+ def test_27(self, bash):
+ """a $(b c|"""
+ output = self._test(bash, "(a '$(b c')", 1, "a $(b c", 7)
+ assert output == "$(b c,a"
+
+ def test_28(self, bash):
+ r"""a $(b c\ d|"""
+ output = self._test(bash, r"(a '$(b c\ d')", 1, r"a $(b c\ d", 10)
+ assert output == r"$(b c\ d,a"
+
+ def test_29(self, bash):
+ """a 'b&c|"""
+ output = self._test(bash, '(a "\'b&c")', 1, "a 'b&c", 6)
+ assert output == "'b&c,a"
+
+ def test_30(self, bash):
+ """a b| to all vars"""
+ assert_bash_exec(bash, "unset words cword cur prev")
+ output = self._test_unit(
+ "_get_comp_words_by_ref words cword cur prev%s; "
+ 'echo "${words[@]}",$cword,$cur,$prev',
+ bash,
+ "(a b)",
+ 1,
+ "a b",
+ 3,
+ )
+ assert output == "a b,1,b,a"
+
+ def test_31(self, bash):
+ """a b| to alternate vars"""
+ assert_bash_exec(bash, "unset words2 cword2 cur2 prev2")
+ output = self._test_unit(
+ "_get_comp_words_by_ref -w words2 -i cword2 -c cur2 -p prev2%s; "
+ 'echo $cur2,$prev2,"${words2[@]}",$cword2',
+ bash,
+ "(a b)",
+ 1,
+ "a b",
+ 3,
+ )
+ assert output == "b,a,a b,1"
+ assert_bash_exec(bash, "unset words2 cword2 cur2 prev2")
+
+ def test_32(self, bash):
+ """a b : c| with wordbreaks -= :"""
+ assert_bash_exec(bash, "unset words")
+ output = self._test_unit(
+ '_get_comp_words_by_ref -n : words%s; echo "${words[@]}"',
+ bash,
+ "(a b : c)",
+ 3,
+ "a b : c",
+ 7,
+ )
+ assert output == "a b : c"
+
+ def test_33(self, bash):
+ """a b: c| with wordbreaks -= :"""
+ assert_bash_exec(bash, "unset words")
+ output = self._test_unit(
+ '_get_comp_words_by_ref -n : words%s; echo "${words[@]}"',
+ bash,
+ "(a b : c)",
+ 3,
+ "a b: c",
+ 6,
+ )
+ assert output == "a b: c"
+
+ def test_34(self, bash):
+ """a b :c| with wordbreaks -= :"""
+ assert_bash_exec(bash, "unset words")
+ output = self._test_unit(
+ '_get_comp_words_by_ref -n : words%s; echo "${words[@]}"',
+ bash,
+ "(a b : c)",
+ 3,
+ "a b :c",
+ 6,
+ )
+ assert output == "a b :c"
+
+ def test_35(self, bash):
+ r"""a b\ :c| with wordbreaks -= :"""
+ assert_bash_exec(bash, "unset words")
+ output = self._test_unit(
+ '_get_comp_words_by_ref -n : words%s; echo "${words[@]}"',
+ bash,
+ "(a 'b ' : c)",
+ 3,
+ r"a b\ :c",
+ 7,
+ )
+ assert output == "a b :c"
+
+ def test_unknown_arg_error(self, bash):
+ with pytest.raises(AssertionError) as ex:
+ _ = assert_bash_exec(
+ bash, "_get_comp_words_by_ref dummy", want_output=True
+ )
+ ex.match("dummy.* unknown argument")
diff --git a/test/t/unit/test_unit_get_cword.py b/test/t/unit/test_unit_get_cword.py
new file mode 100644
index 0000000..0b56d16
--- /dev/null
+++ b/test/t/unit/test_unit_get_cword.py
@@ -0,0 +1,154 @@
+import pexpect
+import pytest
+
+from conftest import PS1, TestUnitBase, assert_bash_exec
+
+
+@pytest.mark.bashcomp(
+ cmd=None, ignore_env=r"^[+-](COMP_(WORDS|CWORD|LINE|POINT)|_scp_path_esc)="
+)
+class TestUnitGetCword(TestUnitBase):
+ def _test(self, *args, **kwargs):
+ return self._test_unit("_get_cword %s; echo", *args, **kwargs)
+
+ def test_1(self, bash):
+ assert_bash_exec(
+ bash,
+ "COMP_WORDS=() COMP_CWORD= COMP_LINE= COMP_POINT= "
+ "_get_cword >/dev/null",
+ )
+
+ def test_2(self, bash):
+ """a b| should return b"""
+ output = self._test(bash, "(a b)", 1, "a b", 3)
+ assert output == "b"
+
+ def test_3(self, bash):
+ """a | should return nothing"""
+ output = self._test(bash, "(a)", 1, "a ", 2)
+ assert not output
+
+ def test_4(self, bash):
+ """a b | should return nothing"""
+ output = self._test(bash, "(a b '')", 2, "a b ", 4)
+ assert not output
+
+ def test_5(self, bash):
+ """a b | with WORDBREAKS -= : should return nothing"""
+ output = self._test(bash, "(a b '')", 2, "a b ", 4, arg=":")
+ assert not output
+
+ def test_6(self, bash):
+ """a b|c should return b"""
+ output = self._test(bash, "(a bc)", 1, "a bc", 3)
+ assert output == "b"
+
+ def test_7(self, bash):
+ r"""a b\ c| should return b\ c"""
+ output = self._test(bash, r"(a 'b\ c')", 1, r"a b\ c", 6)
+ assert output == r"b\ c"
+
+ def test_8(self, bash):
+ r"""a b\| c should return b\ """
+ output = self._test(bash, r"(a 'b\ c')", 1, r"a b\ c", 4)
+ assert output == "b\\"
+
+ def test_9(self, bash):
+ r"""a "b\| should return "b\ """
+ output = self._test(bash, "(a '\"b\\')", 1, r"a \"b\\", 5)
+ assert output == '"b\\'
+
+ def test_10(self, bash):
+ r"""a 'b c| should return 'b c"""
+ output = self._test(bash, '(a "\'b c")', 1, "a 'b c", 6)
+ assert output == "'b c"
+
+ def test_11(self, bash):
+ r"""a "b c| should return "b c"""
+ output = self._test(bash, "(a '\"b c')", 1, 'a "b c', 6)
+ assert output == '"b c'
+
+ def test_12(self, bash):
+ """a b:c| with WORDBREAKS += : should return c"""
+ assert_bash_exec(bash, "add_comp_wordbreak_char :")
+ output = self._test(bash, "(a b : c)", 3, "a b:c", 5)
+ assert output == "c"
+
+ def test_13(self, bash):
+ """a b:c| with WORDBREAKS -= : should return b:c"""
+ assert_bash_exec(bash, "add_comp_wordbreak_char :")
+ output = self._test(bash, "(a b : c)", 3, "a b:c", 5, arg=":")
+ assert output == "b:c"
+
+ def test_14(self, bash):
+ """a b c:| with WORDBREAKS -= : should return c:"""
+ assert_bash_exec(bash, "add_comp_wordbreak_char :")
+ output = self._test(bash, "(a b c :)", 3, "a b c:", 6, arg=":")
+ assert output == "c:"
+
+ def test_15(self, bash):
+ """a :| with WORDBREAKS -= : should return :"""
+ assert_bash_exec(bash, "add_comp_wordbreak_char :")
+ output = self._test(bash, "(a :)", 1, "a :", 3, arg=":")
+ assert output == ":"
+
+ def test_16(self, bash):
+ """a b::| with WORDBREAKS -= : should return b::"""
+ assert_bash_exec(bash, "add_comp_wordbreak_char :")
+ output = self._test(bash, "(a b::)", 1, "a b::", 5, arg=":")
+ assert output == "b::"
+
+ def test_17(self, bash):
+ """
+ a -n| should return -n
+
+ This test makes sure `_get_cword' doesn't use `echo' to return its
+ value, because -n might be interpreted by `echo' and thus woud not
+ be returned.
+ """
+ output = self._test(bash, "(a -n)", 1, "a -n", 4)
+ assert output == "-n"
+
+ def test_18(self, bash):
+ """a b>c| should return c"""
+ output = self._test(bash, r"(a b \> c)", 3, "a b>c", 5)
+ assert output == "c"
+
+ def test_19(self, bash):
+ """a b=c| should return c"""
+ output = self._test(bash, "(a b = c)", 3, "a b=c", 5)
+ assert output == "c"
+
+ def test_20(self, bash):
+ """a *| should return *"""
+ output = self._test(bash, r"(a \*)", 1, "a *", 4)
+ assert output == "*"
+
+ def test_21(self, bash):
+ """a $(b c| should return $(b c"""
+ output = self._test(bash, r"(a '$(b c')", 1, "a $(b c", 7)
+ assert output == "$(b c"
+
+ def test_22(self, bash):
+ r"""a $(b c\ d| should return $(b c\ d"""
+ output = self._test(bash, r"(a '$(b c\ d')", 1, r"a $(b c\ d", 10)
+ assert output == r"$(b c\ d"
+
+ def test_23(self, bash):
+ """a 'b&c| should return 'b&c"""
+ output = self._test(bash, '(a "\'b&c")', 1, "a 'b&c", 6)
+ assert output == "'b&c"
+
+ @pytest.mark.xfail(reason="TODO: non-ASCII issues with test suite?")
+ def test_24(self, bash):
+ """Index shouldn't drop below 0"""
+ bash.send("scp ääää§ se\t\r\n")
+ got = bash.expect_exact(
+ [
+ "index: substring expression < 0",
+ PS1,
+ pexpect.EOF,
+ pexpect.TIMEOUT,
+ ]
+ )
+ assert got == 1
diff --git a/test/t/unit/test_unit_init_completion.py b/test/t/unit/test_unit_init_completion.py
new file mode 100644
index 0000000..64a5a79
--- /dev/null
+++ b/test/t/unit/test_unit_init_completion.py
@@ -0,0 +1,34 @@
+import pytest
+
+from conftest import TestUnitBase, assert_bash_exec, assert_complete
+
+
+@pytest.mark.bashcomp(
+ cmd=None,
+ ignore_env=r"^[+-](COMP(_(WORDS|CWORD|LINE|POINT)|REPLY)|"
+ r"cur|cword|words)=",
+)
+class TestUnitInitCompletion(TestUnitBase):
+ def test_1(self, bash):
+ """Test environment non-pollution, detected at teardown."""
+ assert_bash_exec(
+ bash,
+ "foo() { "
+ "local cur prev words cword "
+ "COMP_WORDS=() COMP_CWORD=0 COMP_LINE= COMP_POINT=0; "
+ "_init_completion; }; "
+ "foo; unset foo",
+ )
+
+ def test_2(self, bash):
+ output = self._test_unit(
+ "_init_completion %s; echo $cur,${prev-}", bash, "(a)", 0, "a", 0
+ )
+ assert output == ","
+
+ @pytest.mark.parametrize("redirect", "> >> 2> < &>".split())
+ def test_redirect(self, bash, redirect):
+ completion = assert_complete(
+ bash, "%s " % redirect, cwd="shared/default"
+ )
+ assert all(x in completion for x in "foo bar".split())
diff --git a/test/t/unit/test_unit_ip_addresses.py b/test/t/unit/test_unit_ip_addresses.py
new file mode 100644
index 0000000..8120c88
--- /dev/null
+++ b/test/t/unit/test_unit_ip_addresses.py
@@ -0,0 +1,49 @@
+import pytest
+
+from conftest import assert_bash_exec, in_container
+
+
+@pytest.mark.bashcomp(cmd=None, ignore_env=r"^\+COMPREPLY=")
+class TestUnitIpAddresses:
+ @pytest.fixture(scope="class")
+ def functions(self, request, bash):
+ assert_bash_exec(
+ bash,
+ "_ia() { local cur=$(_get_cword);unset COMPREPLY;"
+ "_ip_addresses; }",
+ )
+ assert_bash_exec(bash, "complete -F _ia ia")
+ assert_bash_exec(
+ bash,
+ "_iaa() { local cur=$(_get_cword);unset COMPREPLY;"
+ "_ip_addresses -a; }",
+ )
+ assert_bash_exec(bash, "complete -F _iaa iaa")
+ assert_bash_exec(
+ bash,
+ " _ia6() { local cur=$(_get_cword);unset COMPREPLY;"
+ "_ip_addresses -6; }",
+ )
+ assert_bash_exec(bash, "complete -F _ia6 ia6")
+
+ def test_1(self, bash):
+ assert_bash_exec(bash, "_ip_addresses")
+
+ @pytest.mark.complete("iaa ")
+ def test_2(self, functions, completion):
+ """_ip_addresses -a should complete ip addresses."""
+ assert completion
+ assert all("." in x or ":" in x for x in completion)
+
+ @pytest.mark.complete("ia ")
+ def test_3(self, functions, completion):
+ """_ip_addresses should complete ipv4 addresses."""
+ assert completion
+ assert all("." in x for x in completion)
+
+ @pytest.mark.xfail(in_container(), reason="Probably fails in a container")
+ @pytest.mark.complete("ia6 ")
+ def test_4(self, functions, completion):
+ """_ip_addresses -6 should complete ipv6 addresses."""
+ assert completion
+ assert all(":" in x for x in completion)
diff --git a/test/t/unit/test_unit_known_hosts_real.py b/test/t/unit/test_unit_known_hosts_real.py
new file mode 100644
index 0000000..ac5205e
--- /dev/null
+++ b/test/t/unit/test_unit_known_hosts_real.py
@@ -0,0 +1,158 @@
+from itertools import chain
+
+import pytest
+
+from conftest import assert_bash_exec
+
+
+@pytest.mark.bashcomp(
+ cmd=None,
+ ignore_env="^[+-](COMP(REPLY|_KNOWN_HOSTS_WITH_HOSTFILE)|OLDHOME)=",
+)
+class TestUnitKnownHostsReal:
+ @pytest.mark.parametrize(
+ "prefix,colon_flag,hostfile",
+ [("", "", True), ("", "", False), ("user@", "c", True)],
+ )
+ def test_basic(
+ self, bash, hosts, avahi_hosts, prefix, colon_flag, hostfile
+ ):
+ expected = (
+ "%s%s%s" % (prefix, x, ":" if colon_flag else "")
+ for x in chain(
+ hosts if hostfile else avahi_hosts,
+ # fixtures/_known_hosts_real/config
+ "gee hus jar #not-a-comment".split(),
+ # fixtures/_known_hosts_real/known_hosts
+ (
+ "doo",
+ "ike",
+ "jub",
+ "10.0.0.1",
+ "kyl",
+ "100.0.0.2",
+ "10.10.0.3",
+ "blah",
+ "fd00:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:5555",
+ "fe80::123:0xff:dead:beef%eth0",
+ "1111:2222:3333:4444:5555:6666:xxxx:abab",
+ "11xx:2222:3333:4444:5555:6666:xxxx:abab",
+ "::42",
+ ),
+ )
+ )
+ assert_bash_exec(
+ bash,
+ "unset -v COMP_KNOWN_HOSTS_WITH_HOSTFILE"
+ if hostfile
+ else "COMP_KNOWN_HOSTS_WITH_HOSTFILE=",
+ )
+ output = assert_bash_exec(
+ bash,
+ "_known_hosts_real -a%sF _known_hosts_real/config '%s'; "
+ r'printf "%%s\n" "${COMPREPLY[@]}"; unset COMPREPLY'
+ % (colon_flag, prefix),
+ want_output=True,
+ )
+ assert sorted(set(output.split())) == sorted(expected)
+
+ @pytest.mark.parametrize(
+ "family,result",
+ (
+ ("4", "127.0.0.1 localhost"),
+ ("6", "::1 localhost"),
+ ("46", "localhost"),
+ ),
+ )
+ def test_ip_filtering(self, bash, family, result):
+ assert_bash_exec(
+ bash, "unset -v COMPREPLY COMP_KNOWN_HOSTS_WITH_HOSTFILE"
+ )
+ output = assert_bash_exec(
+ bash,
+ "COMP_KNOWN_HOSTS_WITH_HOSTFILE= "
+ "_known_hosts_real -%sF _known_hosts_real/localhost_config ''; "
+ r'printf "%%s\n" "${COMPREPLY[@]}"' % family,
+ want_output=True,
+ )
+ assert sorted(set(output.strip().split())) == sorted(result.split())
+
+ def test_consecutive_spaces(self, bash, hosts):
+ expected = hosts.copy()
+ # fixtures/_known_hosts_real/spaced conf
+ expected.extend("gee hus #not-a-comment".split())
+ # fixtures/_known_hosts_real/known_hosts2
+ expected.extend("two two2 two3 two4".split())
+ # fixtures/_known_hosts_/spaced known_hosts
+ expected.extend("doo ike".split())
+
+ output = assert_bash_exec(
+ bash,
+ "unset -v COMPREPLY COMP_KNOWN_HOSTS_WITH_HOSTFILE; "
+ "_known_hosts_real -aF '_known_hosts_real/spaced conf' ''; "
+ r'printf "%s\n" "${COMPREPLY[@]}"',
+ want_output=True,
+ )
+ assert sorted(set(output.strip().split())) == sorted(expected)
+
+ def test_files_starting_with_tilde(self, bash, hosts):
+ expected = hosts.copy()
+ # fixtures/_known_hosts_real/known_hosts2
+ expected.extend("two two2 two3 two4".split())
+ # fixtures/_known_hosts_real/known_hosts3
+ expected.append("three")
+ # fixtures/_known_hosts_real/known_hosts4
+ expected.append("four")
+
+ assert_bash_exec(bash, 'OLDHOME="$HOME"; HOME="%s"' % bash.cwd)
+ output = assert_bash_exec(
+ bash,
+ "unset -v COMPREPLY COMP_KNOWN_HOSTS_WITH_HOSTFILE; "
+ "_known_hosts_real -aF _known_hosts_real/config_tilde ''; "
+ r'printf "%s\n" "${COMPREPLY[@]}"',
+ want_output=True,
+ )
+ assert_bash_exec(bash, 'HOME="$OLDHOME"')
+ assert sorted(set(output.strip().split())) == sorted(expected)
+
+ def test_included_configs(self, bash, hosts):
+ expected = hosts.copy()
+ # fixtures/_known_hosts_real/config_include_recursion
+ expected.append("recursion")
+ # fixtures/_known_hosts_real/.ssh/config_relative_path
+ expected.append("relative_path")
+ # fixtures/_known_hosts_real/.ssh/config_asterisk_*
+ expected.extend("asterisk_1 asterisk_2".split())
+ # fixtures/_known_hosts_real/.ssh/config_question_mark
+ expected.append("question_mark")
+
+ assert_bash_exec(
+ bash, 'OLDHOME="$HOME"; HOME="%s/_known_hosts_real"' % bash.cwd
+ )
+ output = assert_bash_exec(
+ bash,
+ "unset -v COMPREPLY COMP_KNOWN_HOSTS_WITH_HOSTFILE; "
+ "_known_hosts_real -aF _known_hosts_real/config_include ''; "
+ r'printf "%s\n" "${COMPREPLY[@]}"',
+ want_output=True,
+ )
+ assert_bash_exec(bash, 'HOME="$OLDHOME"')
+ assert sorted(set(output.strip().split())) == sorted(expected)
+
+ def test_no_globbing(self, bash):
+ assert_bash_exec(
+ bash, 'OLDHOME="$HOME"; HOME="%s/_known_hosts_real"' % bash.cwd
+ )
+ output = assert_bash_exec(
+ bash,
+ "cd _known_hosts_real; "
+ "unset -v COMPREPLY COMP_KNOWN_HOSTS_WITH_HOSTFILE; "
+ "_known_hosts_real -aF config ''; "
+ r'printf "%s\n" "${COMPREPLY[@]}"; '
+ "cd - &>/dev/null",
+ want_output=True,
+ )
+ assert_bash_exec(bash, 'HOME="$OLDHOME"')
+ completion = sorted(set(output.strip().split()))
+ assert "gee" in completion
+ assert "gee-filename-canary" not in completion
diff --git a/test/t/unit/test_unit_longopt.py b/test/t/unit/test_unit_longopt.py
new file mode 100644
index 0000000..c5488e3
--- /dev/null
+++ b/test/t/unit/test_unit_longopt.py
@@ -0,0 +1,52 @@
+# Based on work by Stephen Gildea, October 2010.
+
+import pytest
+
+from conftest import assert_bash_exec
+
+
+@pytest.mark.bashcomp(cmd=None, ignore_env=r"^\+COMPREPLY=")
+class TestUnitLongopt:
+ @pytest.fixture(scope="class")
+ def functions(self, request, bash):
+ assert_bash_exec(bash, "_grephelp() { cat _longopt/grep--help.txt; }")
+ assert_bash_exec(bash, "complete -F _longopt _grephelp")
+ assert_bash_exec(bash, "_various() { cat _longopt/various.txt; }")
+ assert_bash_exec(bash, "complete -F _longopt _various")
+
+ @pytest.mark.complete("_grephelp --")
+ def test_1(self, functions, completion):
+ """First long option should be included"""
+ assert completion
+ assert all(
+ x in completion for x in "--quiet --recursive --text".split()
+ )
+
+ @pytest.mark.complete("_grephelp -")
+ def test_2(self, functions, completion):
+ """Only long options should be included"""
+ assert completion
+ assert all(x.startswith("--") for x in completion)
+
+ @pytest.mark.complete("_grephelp --")
+ def test_3(self, functions, completion):
+ """Should have both ones ending with a = and ones not"""
+ assert completion
+ assert any(x.endswith("=") for x in completion)
+ assert any(not x.endswith("=") for x in completion)
+
+ @pytest.mark.complete("_various --")
+ def test_no_dashdashdash(self, functions, completion):
+ assert all(not x.startswith("---") for x in completion)
+
+ @pytest.mark.complete("_various --")
+ def test_no_trailingdash(self, functions, completion):
+ assert all(not x.endswith("-") for x in completion)
+
+ @pytest.mark.complete("_various --")
+ def test_underscore(self, functions, completion):
+ assert "--foo_bar" in completion
+
+ @pytest.mark.complete("_various --")
+ def test_equals(self, functions, completion):
+ assert "--foo=" in completion
diff --git a/test/t/unit/test_unit_parse_help.py b/test/t/unit/test_unit_parse_help.py
new file mode 100644
index 0000000..4a02155
--- /dev/null
+++ b/test/t/unit/test_unit_parse_help.py
@@ -0,0 +1,183 @@
+# Based on work by Stephen Gildea, October 2010.
+
+import pytest
+
+from conftest import assert_bash_exec
+
+
+@pytest.mark.bashcomp(cmd=None, ignore_env=r"^\+declare -f fn$")
+class TestUnitParseHelp:
+ def test_1(self, bash):
+ assert_bash_exec(bash, "fn() { echo; }")
+ output = assert_bash_exec(bash, "_parse_help fn")
+ assert not output
+
+ def test_2(self, bash):
+ assert_bash_exec(bash, "fn() { echo 'no dashes here'; }")
+ output = assert_bash_exec(bash, "_parse_help fn")
+ assert not output
+
+ def test_3(self, bash):
+ assert_bash_exec(bash, "fn() { echo 'internal-dash'; }")
+ output = assert_bash_exec(bash, "_parse_help fn")
+ assert not output
+
+ def test_4(self, bash):
+ assert_bash_exec(bash, "fn() { echo 'no -leading-dashes'; }")
+ output = assert_bash_exec(bash, "_parse_help fn")
+ assert not output
+
+ def test_5(self, bash):
+ assert_bash_exec(bash, "fn() { echo '-one dash'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "-one".split()
+
+ def test_6(self, bash):
+ assert_bash_exec(bash, "fn() { echo ' -space dash'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "-space".split()
+
+ def test_7(self, bash):
+ assert_bash_exec(bash, "fn() { echo '-one -two dashes'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "-one".split()
+
+ def test_8(self, bash):
+ assert_bash_exec(bash, "fn() { echo '-one,-t dashes'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "-one".split()
+
+ def test_9(self, bash):
+ assert_bash_exec(bash, "fn() { echo '-one dash-inside'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "-one".split()
+
+ def test_10(self, bash):
+ """Test value not included in completion."""
+ assert_bash_exec(bash, "fn() { echo '--long-arg=value'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--long-arg=".split()
+
+ def test_11(self, bash):
+ """Test -value not seen as option."""
+ assert_bash_exec(bash, "fn() { echo '--long-arg=-value'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--long-arg=".split()
+
+ def test_12(self, bash):
+ assert_bash_exec(bash, "fn() { echo '--long-arg=-value,--opt2=val'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--long-arg=".split()
+
+ def test_13(self, bash):
+ assert_bash_exec(bash, "fn() { echo '-m,--mirror'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--mirror".split()
+
+ def test_14(self, bash):
+ assert_bash_exec(bash, "fn() { echo '-T/--upload-file'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--upload-file".split()
+
+ def test_15(self, bash):
+ assert_bash_exec(bash, "fn() { echo '-T|--upload-file'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--upload-file".split()
+
+ def test_16(self, bash):
+ assert_bash_exec(bash, "fn() { echo '-f, -F, --foo'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--foo".split()
+
+ def test_17(self, bash):
+ assert_bash_exec(bash, "fn() { echo '--foo[=bar]'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--foo".split()
+
+ def test_18(self, bash):
+ assert_bash_exec(bash, "fn() { echo '--foo=<bar>'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--foo=".split()
+
+ def test_19(self, bash):
+ assert_bash_exec(bash, "fn() { echo '--foo={bar,quux}'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--foo=".split()
+
+ def test_20(self, bash):
+ assert_bash_exec(bash, "fn() { echo '--[no]foo'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--foo --nofoo".split()
+
+ def test_21(self, bash):
+ assert_bash_exec(bash, "fn() { echo '--[no-]bar[=quux]'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--bar --no-bar".split()
+
+ def test_22(self, bash):
+ assert_bash_exec(bash, "fn() { echo '--[no-]bar=quux'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--bar= --no-bar=".split()
+
+ def test_23(self, bash):
+ assert_bash_exec(bash, "fn() { echo '--[dont-]foo'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--foo --dont-foo".split()
+
+ def test_24(self, bash):
+ assert_bash_exec(bash, "fn() { echo '-[dont]x --[dont]yy'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--yy --dontyy".split()
+
+ def test_25(self, bash):
+ assert_bash_exec(bash, "fn() { echo '-f FOO, --foo=FOO'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--foo=".split()
+
+ def test_26(self, bash):
+ assert_bash_exec(bash, "fn() { echo '-f [FOO], --foo[=FOO]'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--foo".split()
+
+ def test_27(self, bash):
+ assert_bash_exec(bash, "fn() { echo '--foo.'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--foo".split()
+
+ def test_28(self, bash):
+ assert_bash_exec(bash, "fn() { echo '-f or --foo'; }")
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--foo".split()
+
+ def test_29(self, bash):
+ """Test parsing from stdin."""
+ output = assert_bash_exec(
+ bash, "echo '-f or --foo' | _parse_help -", want_output=True
+ )
+ assert output.split() == "--foo".split()
+
+ def test_30(self, bash):
+ """More than two dashes should not be treated as options."""
+ assert_bash_exec(
+ bash, r"fn() { printf '%s\n' $'----\n---foo\n----- bar'; }"
+ )
+ output = assert_bash_exec(bash, "_parse_help fn")
+ assert not output
+
+ def test_31(self, bash):
+ assert_bash_exec(
+ bash,
+ r"fn() { printf '%s\n' "
+ r"'-F ERROR_FORMAT, --error-format ERROR_FORMAT'; }",
+ )
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--error-format".split()
+
+ def test_32(self, bash):
+ assert_bash_exec(
+ bash,
+ r"fn() { printf '%s\n' "
+ r"'-e CODE1,CODE2.. --exclude=CODE1,CODE2..'; }",
+ )
+ output = assert_bash_exec(bash, "_parse_help fn", want_output=True)
+ assert output.split() == "--exclude=".split()
diff --git a/test/t/unit/test_unit_parse_usage.py b/test/t/unit/test_unit_parse_usage.py
new file mode 100644
index 0000000..f0cb711
--- /dev/null
+++ b/test/t/unit/test_unit_parse_usage.py
@@ -0,0 +1,69 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+@pytest.mark.bashcomp(cmd=None, ignore_env=r"^\+declare -f fn$")
+class TestUnitParseUsage:
+ def test_1(self, bash):
+ assert_bash_exec(bash, "fn() { echo; }")
+ output = assert_bash_exec(bash, "_parse_usage fn")
+ assert not output
+
+ def test_2(self, bash):
+ assert_bash_exec(bash, "fn() { echo 'no dashes here'; }")
+ output = assert_bash_exec(bash, "_parse_usage fn")
+ assert not output
+
+ def test_3(self, bash):
+ assert_bash_exec(bash, "fn() { echo 'foo [-f]'; }")
+ output = assert_bash_exec(bash, "_parse_usage fn", want_output=True)
+ assert output.split() == "-f".split()
+
+ def test_4(self, bash):
+ assert_bash_exec(bash, "fn() { echo 'bar [-aBcD] [-e X]'; }")
+ output = assert_bash_exec(bash, "_parse_usage fn", want_output=True)
+ assert output.split() == "-a -B -c -D -e".split()
+
+ def test_5(self, bash):
+ assert_bash_exec(bash, "fn() { echo '[-[XyZ]] [--long=arg]'; }")
+ output = assert_bash_exec(bash, "_parse_usage fn", want_output=True)
+ assert output.split() == "-X -y -Z --long=".split()
+
+ def test_6(self, bash):
+ assert_bash_exec(bash, "fn() { echo '[-s|--long]'; }")
+ output = assert_bash_exec(bash, "_parse_usage fn", want_output=True)
+ assert output.split() == "--long".split()
+
+ def test_7(self, bash):
+ assert_bash_exec(bash, "fn() { echo '[-s, --long=arg]'; }")
+ output = assert_bash_exec(bash, "_parse_usage fn", want_output=True)
+ assert output.split() == "--long=".split()
+
+ def test_8(self, bash):
+ assert_bash_exec(bash, "fn() { echo '[--long/-s] [-S/--longer]'; }")
+ output = assert_bash_exec(bash, "_parse_usage fn", want_output=True)
+ assert output.split() == "--long --longer".split()
+
+ def test_9(self, bash):
+ assert_bash_exec(bash, "fn() { echo '[ -a ] [ -b foo ]'; }")
+ output = assert_bash_exec(bash, "_parse_usage fn", want_output=True)
+ assert output.split() == "-a -b".split()
+
+ def test_10(self, bash):
+ assert_bash_exec(bash, "fn() { echo '[ -a | --aa ]'; }")
+ output = assert_bash_exec(bash, "_parse_usage fn", want_output=True)
+ assert output.split() == "--aa".split()
+
+ def test_11(self, bash):
+ assert_bash_exec(
+ bash, "fn() { echo ----; echo ---foo; echo '----- bar'; }"
+ )
+ output = assert_bash_exec(bash, "_parse_usage fn")
+ assert not output
+
+ def test_12(self, bash):
+ output = assert_bash_exec(
+ bash, "echo '[-duh]' | _parse_usage -", want_output=True
+ )
+ assert output.split() == "-d -u -h".split()
diff --git a/test/t/unit/test_unit_quote.py b/test/t/unit/test_unit_quote.py
new file mode 100644
index 0000000..b280bd6
--- /dev/null
+++ b/test/t/unit/test_unit_quote.py
@@ -0,0 +1,36 @@
+import pytest
+
+from conftest import TestUnitBase, assert_bash_exec
+
+
+@pytest.mark.bashcomp(cmd=None)
+class TestUnitQuote(TestUnitBase):
+ def test_1(self, bash):
+ output = assert_bash_exec(
+ bash, 'quote "a b"', want_output=True, want_newline=False
+ )
+ assert output.strip() == "'a b'"
+
+ def test_2(self, bash):
+ output = assert_bash_exec(
+ bash, 'quote "a b"', want_output=True, want_newline=False
+ )
+ assert output.strip() == "'a b'"
+
+ def test_3(self, bash):
+ output = assert_bash_exec(
+ bash, 'quote " a "', want_output=True, want_newline=False
+ )
+ assert output.strip() == "' a '"
+
+ def test_4(self, bash):
+ output = assert_bash_exec(
+ bash, "quote \"a'b'c\"", want_output=True, want_newline=False
+ )
+ assert output.strip() == r"'a'\''b'\''c'"
+
+ def test_5(self, bash):
+ output = assert_bash_exec(
+ bash, 'quote "a\'"', want_output=True, want_newline=False
+ )
+ assert output.strip() == r"'a'\'''"
diff --git a/test/t/unit/test_unit_quote_readline.py b/test/t/unit/test_unit_quote_readline.py
new file mode 100644
index 0000000..e2b437e
--- /dev/null
+++ b/test/t/unit/test_unit_quote_readline.py
@@ -0,0 +1,15 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+@pytest.mark.bashcomp(cmd=None)
+class TestUnitQuoteReadline:
+ def test_exec(self, bash):
+ assert_bash_exec(bash, "quote_readline '' >/dev/null")
+
+ def test_env_non_pollution(self, bash):
+ """Test environment non-pollution, detected at teardown."""
+ assert_bash_exec(
+ bash, "foo() { quote_readline meh >/dev/null; }; foo; unset foo"
+ )
diff --git a/test/t/unit/test_unit_tilde.py b/test/t/unit/test_unit_tilde.py
new file mode 100644
index 0000000..35a4e4c
--- /dev/null
+++ b/test/t/unit/test_unit_tilde.py
@@ -0,0 +1,42 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+@pytest.mark.bashcomp(cmd=None, ignore_env=r"^\+COMPREPLY=")
+class TestUnitTilde:
+ def test_1(self, bash):
+ assert_bash_exec(bash, "_tilde >/dev/null")
+
+ def test_2(self, bash):
+ """Test environment non-pollution, detected at teardown."""
+ assert_bash_exec(
+ bash, 'foo() { local aa="~"; _tilde "$aa"; }; foo; unset foo'
+ )
+
+ def test_3(self, bash):
+ """Test for https://bugs.debian.org/766163"""
+ assert_bash_exec(bash, "_tilde ~-o")
+
+ def _test_part_full(self, bash, part, full):
+ res = (
+ assert_bash_exec(
+ bash,
+ '_tilde "~%s"; echo "${COMPREPLY[@]}"' % part,
+ want_output=True,
+ )
+ .strip()
+ .split()
+ )
+ assert res
+ assert res[0] == "~%s" % full
+
+ def test_4(self, bash, part_full_user):
+ """~full should complete to ~full unmodified."""
+ _, full = part_full_user
+ self._test_part_full(bash, full, full)
+
+ def test_5(self, bash, part_full_user):
+ """~part should complete to ~full."""
+ part, full = part_full_user
+ self._test_part_full(bash, part, full)
diff --git a/test/t/unit/test_unit_variables.py b/test/t/unit/test_unit_variables.py
new file mode 100644
index 0000000..d62bc4a
--- /dev/null
+++ b/test/t/unit/test_unit_variables.py
@@ -0,0 +1,41 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+@pytest.mark.bashcomp(cmd=None, ignore_env=r"^[+-](___var|assoc[12])=")
+class TestUnitVariables:
+ @pytest.fixture(scope="class")
+ def functions(self, request, bash):
+ assert_bash_exec(bash, "unset assoc1 && declare -A assoc1=([idx]=1)")
+ assert_bash_exec(
+ bash, "unset assoc2 && declare -A assoc2=([idx1]=1 [idx2]=2)"
+ )
+ assert_bash_exec(bash, "unset ${!___v*} && declare ___var=''")
+ request.addfinalizer(
+ lambda: assert_bash_exec(bash, "unset ___var assoc1 assoc2")
+ )
+
+ @pytest.mark.complete(": $___v")
+ def test_simple_variable_name(self, functions, completion):
+ assert completion == "ar"
+
+ @pytest.mark.complete(": ${assoc1[")
+ def test_single_array_index(self, functions, completion):
+ assert completion == "idx]}"
+
+ @pytest.mark.complete(": ${assoc2[")
+ def test_multiple_array_indexes(self, functions, completion):
+ assert completion == "${assoc2[idx1]} ${assoc2[idx2]}".split()
+
+ @pytest.mark.complete(": ${assoc1[bogus]")
+ def test_closing_curly_after_square(self, functions, completion):
+ assert completion == "}"
+
+ @pytest.mark.complete(": ${assoc1[@")
+ def test_closing_brackets_after_at(self, functions, completion):
+ assert completion == "]}"
+
+ @pytest.mark.complete(": ${#___v")
+ def test_hash_prefix(self, functions, completion):
+ assert completion == "ar}"
diff --git a/test/t/unit/test_unit_xinetd_services.py b/test/t/unit/test_unit_xinetd_services.py
new file mode 100644
index 0000000..7a90cb7
--- /dev/null
+++ b/test/t/unit/test_unit_xinetd_services.py
@@ -0,0 +1,22 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+@pytest.mark.bashcomp(cmd=None, ignore_env=r"^\+COMPREPLY=")
+class TestUnitXinetdServices:
+ def test_direct(self, bash):
+ assert_bash_exec(bash, "_xinetd_services >/dev/null")
+
+ def test_env_non_pollution(self, bash):
+ """Test environment non-pollution, detected at teardown."""
+ assert_bash_exec(bash, "foo() { _xinetd_services; }; foo; unset foo")
+
+ def test_basic(self, bash):
+ output = assert_bash_exec(
+ bash,
+ "foo() { local BASHCOMP_XINETDDIR=$PWD/shared/bin;unset COMPREPLY; "
+ '_xinetd_services; printf "%s\\n" "${COMPREPLY[@]}"; }; foo; unset foo',
+ want_output=True,
+ )
+ assert sorted(output.split()) == ["arp", "ifconfig"]
diff --git a/test/test-cmd-list.txt b/test/test-cmd-list.txt
new file mode 100644
index 0000000..eb8398e
--- /dev/null
+++ b/test/test-cmd-list.txt
@@ -0,0 +1,687 @@
+2to3
+7z
+a2ps
+a2x
+abook
+aclocal
+acpi
+acroread
+adb
+add_members
+alias
+alpine
+animate
+ant
+apache2ctl
+appdata-validate
+apt-build
+apt-cache
+apt-get
+aptitude
+arch
+arp
+arping
+arpspoof
+asciidoc
+aspell
+autoconf
+autoheader
+automake
+autoreconf
+autorpm
+autoscan
+autossh
+autoupdate
+avctrl
+awk
+badblocks
+base64
+bash
+bc
+/bin/chroot
+bind
+/bin/rmdir
+bison
+bk
+bmake
+brctl
+bsdtar
+btdownloadcurses.py
+btdownloadgui.py
+btdownloadheadless.py
+bts
+bzip2
+c++
+cal
+cancel
+cardctl
+carton
+cat
+cc
+ccache
+ccze
+cd
+cdrecord
+cfagent
+cfrun
+chage
+change_pw
+check_db
+check_perms
+checksec
+chfn
+chgrp
+chkconfig
+chmod
+chown
+chpasswd
+chromium-browser
+chronyc
+chroot
+chrpath
+chsh
+ci
+ciptool
+civclient
+civserver
+cksfv
+cleanarch
+clisp
+clone_member
+co
+colordiff
+compare
+compgen
+complete
+composite
+config_list
+configure
+conjure
+convert
+cowsay
+cp
+cpan2dist
+cpio
+cppcheck
+createdb
+createuser
+crontab
+cryptsetup
+csplit
+curl
+cut
+cvs
+cvsps
+date
+dcop
+dd
+declare
+deja-dup
+desktop-file-validate
+df
+dfutool
+dhclient
+dict
+diff
+dir
+display
+dmesg
+dmypy
+dnssec-keygen
+dnsspoof
+dot
+dpkg
+dpkg-deb
+dpkg-query
+dpkg-reconfigure
+dpkg-source
+dropdb
+dropuser
+dselect
+dsniff
+du
+dumpdb
+dumpe2fs
+e2freefrag
+e2label
+ebtables
+ecryptfs-migrate-home
+eject
+enscript
+env
+eog
+etherwake
+ether-wake
+evince
+expand
+explodepkg
+export
+faillog
+fbgs
+fbi
+feh
+file
+filefrag
+file-roller
+filesnarf
+find
+find_member
+finger
+fio
+firefox
+flake8
+fmt
+fold
+freebsd-update
+freeciv
+freeciv-server
+function
+fusermount
+g++
+g4
+g77
+gcc
+gcj
+gcl
+gdb
+genaliases
+gendiff
+genisoimage
+geoiplookup
+getconf
+getent
+gkrellm
+gm
+gmplayer
+gnatmake
+gnokii
+gnome-mplayer
+gnome-screenshot
+gpasswd
+gpc
+gperf
+gpg
+gpg2
+gpgv
+gphoto2
+gprof
+grep
+groupadd
+groupdel
+groupmems
+groupmod
+growisofs
+grpck
+grub
+gssdp-discover
+gzip
+hciattach
+hciconfig
+hcitool
+hddtemp
+head
+hexdump
+hid2hci
+host
+hostname
+hping2
+hping3
+htop
+htpasswd
+hunspell
+hwclock
+iconv
+id
+identify
+idn
+ifdown
+ifstat
+iftop
+ifup
+import
+influx
+info
+inject
+inotifywait
+inotifywatch
+insmod
+installpkg
+interdiff
+invoke-rc.d
+ionice
+ip
+ipcalc
+iperf
+iperf3
+ipmitool
+ipsec
+iptables
+ipv6calc
+irb
+iscsiadm
+isort
+isql
+iwconfig
+iwlist
+iwpriv
+iwspy
+jar
+jarsigner
+java
+javac
+javadoc
+javaws
+jpegoptim
+jps
+jq
+jshint
+jsonschema
+json_xs
+k3b
+kcov
+kdvi
+kill
+killall
+kldload
+kldunload
+koji
+kpdf
+kplayer
+ktutil
+l2ping
+larch
+lastlog
+ld
+ldapadd
+ldapcompare
+ldapdelete
+ldapmodrdn
+ldappasswd
+ldapsearch
+ldapvi
+ldapwhoami
+ldd
+less
+lftp
+lftpget
+lilo
+links
+lintian
+lintian-info
+lisp
+list_admins
+list_lists
+list_members
+list_owners
+ln
+locale-gen
+look
+lpq
+lpr
+lrzip
+ls
+lsof
+lspci
+lsscsi
+lsusb
+lua
+luac
+luseradd
+luserdel
+lusermod
+lvchange
+lvcreate
+lvdisplay
+lvextend
+lvm
+lvmdiskscan
+lvreduce
+lvremove
+lvrename
+lvresize
+lvs
+lvscan
+lz4
+lzip
+lzma
+lzop
+m4
+macof
+mailmanctl
+mailsnarf
+make
+makepkg
+man
+mc
+mcrypt
+md5sum
+mdadm
+mdecrypt
+mdtool
+medusa
+mencoder
+mii-diag
+mii-tool
+minicom
+mkdir
+mkfifo
+mkinitrd
+mkisofs
+mknod
+mktemp
+mmsitepass
+mock
+modinfo
+modprobe
+module
+mogrify
+monodevelop
+montage
+mount
+mplayer
+mr
+msgsnarf
+msynctool
+mtx
+munindoc
+munin-node-configure
+munin-run
+mussh
+mutt
+muttng
+mv
+mypy
+mysql
+mysqladmin
+nc
+ncftp
+nethogs
+netstat
+newgrp
+newlist
+newusers
+ngrep
+nl
+nm
+nmap
+nmcli
+nproc
+nslookup
+nsupdate
+ntpdate
+objcopy
+objdump
+od
+oggdec
+op
+openssl
+opera
+optipng
+p4
+pack200
+passwd
+paste
+patch
+pdftotext
+perl
+perlcritic
+perldoc
+perltidy
+pgrep
+phing
+pidof
+pine
+pinfo
+ping
+pkgadd
+pkg-config
+pkg_deinstall
+pkg_delete
+pkg-get
+pkg_info
+pkgrm
+pkgtool
+pkgutil
+pkill
+plague-client
+pm-hibernate
+pm-is-supported
+pm-powersave
+pngfix
+portinstall
+portsnap
+portupgrade
+postcat
+postconf
+postfix
+postmap
+postsuper
+povray
+pr
+prelink
+printenv
+protoc
+psql
+ptx
+puppet
+pushd
+pv
+pvchange
+pvcreate
+pvdisplay
+pvmove
+pvremove
+pvs
+pvscan
+pwck
+pwd
+pwdx
+pwgen
+pycodestyle
+pydoc
+pydocstyle
+pyflakes
+pylint
+pylint-3
+pytest
+python
+python3
+pyvenv
+qemu
+qrunner
+querybts
+quota
+quotacheck
+quotaon
+radvdump
+rcs
+rcsdiff
+rdesktop
+rdict
+readelf
+readonly
+remove_members
+removepkg
+renice
+repomanage
+reportbug
+reptyr
+resolvconf
+rfcomm
+rfkill
+ri
+rlog
+rm
+rmdir
+rmlist
+rmmod
+route
+rpcdebug
+rpm
+rpm2tgz
+rpmbuild
+rrdtool
+rsync
+rtcwake
+runuser
+sbcl
+sbcl-mt
+sbopkg
+scp
+screen
+scrub
+sdptool
+secret-tool
+sed
+seq
+service
+set
+setquota
+sftp
+sh
+sha1sum
+shar
+shellcheck
+sitecopy
+slackpkg
+slapt-get
+slapt-src
+smartctl
+smbcacls
+smbclient
+smbcquotas
+smbget
+smbpasswd
+smbtar
+smbtree
+snownews
+sort
+split
+spovray
+sqlite3
+ss
+ssh
+ssh-add
+ssh-copy-id
+sshfs
+ssh-keygen
+sshmitm
+sshow
+strace
+stream
+strings
+strip
+su
+sudo
+sum
+svcadm
+svk
+svn
+svnadmin
+svnlook
+synclient
+sync_members
+sysbench
+sysctl
+tac
+tail
+tar
+tcpdump
+tcpkill
+tcpnice
+tee
+texindex
+tightvncviewer
+time
+timeout
+tipc
+totem
+touch
+tox
+tr
+tracepath
+tshark
+tsig-keygen
+tune2fs
+udevadm
+ulimit
+umount
+unace
+uname
+unexpand
+uniq
+units
+unpack200
+unrar
+unset
+unshunt
+update-alternatives
+update-rc.d
+upgradepkg
+urlsnarf
+uscan
+useradd
+userdel
+usermod
+valgrind
+vdir
+vgcfgbackup
+vgcfgrestore
+vgchange
+vgck
+vgconvert
+vgcreate
+vgdisplay
+vgexport
+vgextend
+vgimport
+vgmerge
+vgmknodes
+vgreduce
+vgremove
+vgrename
+vgs
+vgscan
+vgsplit
+vi
+vipw
+vmstat
+vncviewer
+vpnc
+watch
+wc
+webmitm
+wget
+who
+wine
+withlist
+wodim
+wol
+write
+wsimport
+wtf
+wvdial
+xdg-mime
+xdg-settings
+xfreerdp
+xgamma
+xm
+xmllint
+xmlwf
+xmms
+xmodmap
+xpovray
+xrandr
+xrdb
+xsltproc
+xvfb-run
+xvnc4viewer
+xxd
+xz
+xzdec
+ypcat
+ypmatch
+yum
+yum-arch
+zopfli
+zopflipng
diff --git a/test/update-test-cmd-list b/test/update-test-cmd-list
new file mode 100755
index 0000000..115ae16
--- /dev/null
+++ b/test/update-test-cmd-list
@@ -0,0 +1,13 @@
+#!/bin/bash -eu
+
+mydir=$(
+ cd "$(dirname "$0")"
+ pwd
+)
+
+cat "$mydir"/t/test_*.py |
+ tr -d '\n' |
+ grep -Eo '@pytest.mark.complete(\([^)]*\))' |
+ sed -ne 's/^[^"]*"\\\?\([^_][^[:space:]"]*\)[[:space:]"].*/\1/p' |
+ sort -u \
+ >"$mydir"/test-cmd-list.txt