Fake is a small tool to create test doubles for commandline utilities.
Contents
Let's say you're writing a script supposed to manipulate network interface configuration in a GNU/Linux host. The script should use ip(8) to do its work. How would you test it? Requiring a real host environment is an unreasonable burden.
Fake provides an easy interface to create mocks of any command. A fake can either respond to any argument vector or only to specific one(s), it can have whatever body you provide, or it can use builtin behaviors: be quiet or reflect the received arguments, with an exit code of your choice.
Fake creates mocks in $FAKE_BINDIR; it's up to you to make sure this
directory is in your $PATH. A mock for command C consists of
an executable file $FAKE_BINDIR/C called the frontend, and another one
under $FAKE_BINDIR/.C/ (the backend). The filepath of each backend
encodes the argument vector(s) handled by it. A backend for
echo hello world will be named .echo/2-/D1IMOR3F-ETNN4R34.
A backend for any argv starting with echo hello world will be named
.echo/2+/D1IMOR3F-ETNN4R34.
To avoid ENAMETOOLONG errors, fake splits backend names into segments
of $FAKE_BACKEND_CHUNKSIZE characters.
At run time, the frontend executes the most specific backend for the given arguments; if no backend matches, the frontend will emit diagnostic messages on stderr.
fake and the fakes it creates remove $FAKE_BINDIR from their $PATH.
This means adding more fakes won't change the meaning of already existing ones,
and provides protection against boundless recursion:
$ echo ls foo | fake -b ls foo $ ls foo ls: foo: No such file or directory [1]
$ fake -h
fake: usage: fake -h | -hh
fake: usage: fake [-e | -o] [-c] [-v] [-x N] CMD [ARG...]
fake: usage: fake -b [-c] CMD [ARG...]
fake: usage: fake -p [-c] [-v] CMD [ARG...]
fake: usage: fake -t [-c] [-v] CMD [ARG...]
fake: usage: fake -w CMD [ARG...]
fake: use `fake -hh` to display help
$ fake -hh
fake: usage: fake -h | -hh
fake: usage: fake [-e | -o] [-c] [-v] [-x N] CMD [ARG...]
fake: usage: fake -b [-c] CMD [ARG...]
fake: usage: fake -p [-c] [-v] CMD [ARG...]
fake: usage: fake -t [-c] [-v] CMD [ARG...]
fake: usage: fake -w CMD [ARG...]
Options:
-h Display short usage help.
Given twice, display full help.
-b Body. Create fake from stdin.
-c Catchall. Created fake will receive
any uses of CMD not covered by other,
more specific fakes.
-e Error. Created fake will emit current
stdin to its stderr.
-o Output. Created fake will emit current
stdin to its stdout.
-p Pass-through. This backend will remove
$FAKE_BINDIR from $PATH and re-exec its argv.
-t Transparent. Like fake -p but the delegate
will have the original $PATH in environment.
-v Verbose. Reflect received argv on stderr.
-w Which. Print pathname of the fake that
would receive given CMD [ARG...].
-x N Exit code. Fake should exit with N.
Assert particular arguments:
$ rm -r $FAKE_BINDIR/ls $FAKE_BINDIR/.ls $ fake ls $ ls foo fake: error: argv mismatch fake: expected: ls fake: received: ls foo [100] $ rm -r $FAKE_BINDIR/ls $FAKE_BINDIR/.ls $ fake ls foo $ fake ls bar baz $ ls bar fake: error: argv mismatch fake: expected: ls foo fake: expected: ls bar baz fake: received: ls bar [100]
Accept any arguments:
$ rm -r $FAKE_BINDIR/ls $FAKE_BINDIR/.ls $ fake -c ls $ ls -la stuff $ ls
Use user-defined exit code:
$ rm -r $FAKE_BINDIR/ls $FAKE_BINDIR/.ls $ fake -x 42 ls foo $ ls foo [42] $ ls fake: error: argv mismatch fake: expected: ls foo fake: received: ls [100]
Echo received arguments:
$ rm -r $FAKE_BINDIR/ls $FAKE_BINDIR/.ls $ fake -v ls foo $ fake -v ls bar qux $ ls foo ls foo $ ls bar qux ls bar qux
Use user-provided body:
$ rm -r $FAKE_BINDIR/date $FAKE_BINDIR/.date $ echo echo 2010-11-12 | fake -b date $ date 2010-11-12
You can combine options:
$ rm -r $FAKE_BINDIR/ls $FAKE_BINDIR/.ls $ fake -cv ls $ ls ls $ ls foo bar baz ls foo bar baz $ fake -cbx 69 ls <<\EOF > #!/bin/sh > printf -- "argc=%d" "$#" > [ $# -eq 0 ] || printf -- " -- %s" "$@" > printf -- "\n" > EOF $ ls argc=0 [69] $ ls whatever argc=1 -- whatever [69]
Display pathname of the receiver for given argv:
$ rm -r $FAKE_BINDIR/ls $FAKE_BINDIR/.ls $ fake -w ls [1] $ fake ls foo bar $ fake -c ls $ fake -w ls foo /*/.ls/0+ (glob) $ fake -w ls foo bar /*/.ls/2-CPNMU===-C9GN4=== (glob)
Published under the MIT license, see LICENSE file.
Fake requires POSIX shell and BaseXY to run, plus GNU make to build and Cram to run tests.
% ./configure % make check % sudo make install