GithubHelp home page GithubHelp logo

felipec / sharness Goto Github PK

View Code? Open in Web Editor NEW
373.0 20.0 57.0 428 KB

Shell library to test your tools like Git does

Home Page: http://felipec.github.io/sharness/

License: GNU General Public License v2.0

Makefile 5.21% Shell 85.21% Perl 2.75% Vim Script 6.82%
bash ci shell test-anything-protocol test-harness testing

sharness's Introduction

Sharness

Sharness is a portable shell library to write, run, and analyze automated tests for Unix programs. Since all tests output TAP, the Test Anything Protocol, they can be run with any TAP harness.

Each test is written as a shell script, for example:

#!/bin/sh

test_description='Show basic features of Sharness'

. ./sharness.sh

test_expect_success 'Success is reported like this' '
    echo hello world | grep hello
'

test_expect_success 'Commands are chained this way' '
    test x = "x" &&
    test 2 -gt 1 &&
    echo success
'

test_expect_failure 'We expect this to fail' '
    test 1 = 2
'

test_done

Running the above test script returns the following (TAP) output:

$ ./simple.t
ok 1 - Success is reported like this
ok 2 - Commands are chained this way
ok 3 - You can test for a specific exit code
not ok 4 - We expect this to fail # TODO known breakage
# still have 1 known breakage(s)
# passed all remaining 3 test(s)
1..4

Alternatively, you can run the test through prove(1):

$ prove simple.t
simple.t .. ok
All tests successful.
Files=1, Tests=4,  0 wallclock secs ( 0.02 usr +  0.00 sys =  0.02 CPU)
Result: PASS

Every test is run in a temporary trash directory, so you are free to create as many files as you want, even files in the home directory, because $HOME is set to that temporary trash directory. At the end of the test, that directory is removed (unless there's a failure).

Sharness was derived from the Git project - see README.git for the original documentation.

Installation

First, clone the Git repository:

$ git clone git://github.com/felipec/sharness.git

Then choose an installation method that works best for you:

Per-project installation

If you like to add Sharness to the sources of a project you want to use it for, simply copy the files sharness.sh and example/Makefile to a folder named test inside that project, and source sharness.sh in your test files.

Another way is to use Sharnessify.

Alternatively, you can also add Sharness as a Git submodule to your project.

In per-project installation, Sharness will optionally load extensions from sharness.d/*.sh if a sharness.d directory is found in the same directory as sharness.sh. This allows per-project extensions and enhancements to be added to the test library without requiring modification of sharness.sh.

Per-user installation

$ cd sharness
$ make install

This will install Sharness to $HOME/share/sharness, and its documentation and examples to $HOME/share/doc/sharness.

System-wide installation

$ cd sharness
# make install prefix=/usr/local

This will install Sharness to /usr/local/share/sharness, and its documentation and examples to /usr/local/share/doc/sharness.

Of course, you can change the prefix parameter to install Sharness to any other location.

Usage

The only essential file to Sharness is sharness.sh, which is the core shell library providing test functionality. It's meant to be sourced from test scripts, but not executed.

The following files are optional:

  • example/Makefile - test driver. The default target runs the complete testsuite.
  • lib-sharness/functions.sh - extra functions. These are functions that are nice to have, but not necessary.
  • tools/aggregate-results.sh - tool to show results. Aggregates all the results in test-results. It's meant to be called inside the Makefile after all the tests finish.

Sharness loads the extra functions automatically if you are using bash or zsh, but otherwise you need to set SHARNESS_TEST_SRCDIR to the directory where sharness.sh is.

To see an explanation of all the functions, see the separate API documentation.

To learn how to write and run actual test scripts based on sharness.sh, please read README.git until I come up with more documentation myself.

Command-line options

The *.t test scripts have the following options (again, read README.git for details) :

  • --debug, -d: helps debugging
  • --immediate, -i: stop execution after the first failing test
  • --long-tests, -l: run tests marked with prereq EXPENSIVE
  • --interactive-tests: run tests marked with prereq INTERACTIVE
  • --help, -h: show test description
  • --verbose, -v: show additional debug output
  • --quiet, -q: show less output
  • --chain-lint/--no-chain-lint: check &&-chains in scripts
  • --no-color: don't color the output
  • --tee: also write output to a file
  • --verbose-log: write output to a file, but not on stdout
  • --root=<dir>: create trash directories in <dir> instead of current directory.

Projects using Sharness

See how Sharness is used in real-world projects:

Furthermore, as Sharness was derived from Git, Git's test suite is worth examining as well, especially if you're interested in managing a big number of tests.

Alternatives

Here is a list of other shell testing libraries (sorted alphabetically):

License

Sharness is licensed under the terms of the GNU General Public License version 2 or higher. See file COPYING for full license text.

Contributing

Contributions are welcome, see file CONTRIBUTING for details.

Authors

Sharness was created in April 2011 and maintained until June 2016 by Mathias Lafeldt. The library is derived from the Git project's test-lib.sh. It was maintained by Christian Couder from June 2016 to August 2019, thanks to sponsorship from Protocol Labs. It is currently maintained by Felipe Contreras.

See Github's "contributors" page for a list of developers.

A complete list of authors should include Git contributors to test-lib.sh too.

sharness's People

Contributors

alexanders avatar anarcat avatar bronson avatar chriscool avatar chu11 avatar dun avatar ericcurtin avatar felipec avatar grondo avatar johnkeeping avatar jwilk avatar kkoroviev avatar lespocky avatar lucidone avatar mlafeldt avatar moy avatar mschilli87 avatar peff avatar rafasc avatar rhansen avatar satori avatar seveas avatar stefanbeller avatar sumpfralle avatar thinkerbot avatar tleguern avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sharness's Issues

Clarify purpose of "aggregate-results.sh"

Hello,

I am about to package sharness for Debian.
But I am not sure, if (and how) I should add "aggregate-results.sh" to the package.
At the moment, I see the following options:

  • A) do not include the file in the package
  • B) /usr/share/sharness/aggregate-results.sh: this would be a bit unusual for an executable script
  • C) /usr/share/doc/sharness/examples/aggregate-results.sh: this would be the proper location for an example-like snippet
  • D) /usr/bin/sharness-aggregate-results: I would like to avoid this deviation from upstream (you use a different filename) and I am afraid, that the existence of an executable within the package would confuse new users (and prevent them from reading the docs first). Is this script important enough to be part of the system PATH?

Cheers,
Lars

Missing lazy-prereq support?

As I saw v1.0 announcement, I took a brief look at this package. It does look familiar ;-) but seems to lack quite a lot of things that happened in not-so-recent-past. It seems that the codebase was forked long time ago, long before we split t/test-lib.sh and t/test-lib-funcitons.sh (the latter of which is more generic part, which sharness would want to be tracking)?

Can't locate object method "follower" via package "IO::Pty"

PR #101 changed slave-master terminology to be more inclusive and broke test-terminal.perl in the process because
IO:Pty does not have a follower method, the method is named slave.

The commit needs to be reverted, or the occurrences of follower need to be changed back to slave.

To really eliminate the controversial terminology, we would need an update from upstream.

cc: @chu11

Usage with `prove` would need more documentation

I tried to use prove as suggested by the README, but with some tests tagged as EXPENSIVE I've come on some issues:

  • passing -l to the test under prove is tricky
    • the easiest I found was setting undocumented TEST_LONG in the environment
    • a literal -l could be likely passed using a wrapper script and --exec, but this is so much less comfortable than TEST_OPTS offered by the Makefile driver
  • even then, the skipped expensive tests being counted as success cause a wrong number of "passed tests" (with prove only reporting the test files and needing -v to show the notes about skipped tests) [Note: to my understanding of the TAP protocol it would be that prove itself does not notice the skip lines]

That is to say, maybe it would be worth emphasizing the limitations of using prove together with sharness, and possibly cover alternatives as well to help the user choose. I did not find a single one listed on the TAP website, and other searches brought nothing more - as if prove was the only one of its kind and the norm was to run one's tests by hand and post-process their output with one of the listed viewers.

Cleanup actions are only run if no tests failed

The cleanup helper documentation says:

Public: Schedule cleanup commands to be run unconditionally when all tests
have run.

This can be used to clean up things like test databases. It is not needed to
clean up temporary files, as test_done already does that.

The test_done() function actually only runs the cleanup actions if the $test_failure variable is 0 (no failed tests). As we use this to stop a local dbus-daemon, we have leftover processes as soon as a single test case fails. It works fine if we add test_eval_ "$final_cleanup" to the *) case as well.

Is this behavior intended? If so, I was confused by the documentation.

Lots of dangling branches

Can the repository be cleaned up of obsolete branches? A quick check shows these branches are already merged into master:

 add-tee
 add-verbose-log
 chriscool-add-ipfs-update
 improve-shellcheck
 lib-sharness-functions
 master
 readme-update
 release-1.0
 remove-lf
 remove-shebang
 sourcing-return-code-2
 sumpfralle-more-shellcheck
 test-expect-unstable

New release, version 0.4 or 1.0 or something else?

It looks like there has been no release since v0.3.0 in April 2013.
As there has been some significant changes since that time, it would be nice to create a new release.

What should it be called? 0.4.0? 1.0?

As sharness is quite stable, I think we should aim for 1.0, but perhaps there are things that people would like for a 1.0?
Should we get rid of README.git for example?

Some documentation about contributing to sharness

I think we should have a CONTRIBUTING.md document to tell things like:

  • the same coding rules as in git.git should be followed (https://github.com/git/git/blob/master/Documentation/CodingGuidelines)
  • if some similar changes can benefit Git it is a good idea to first send patchs to the Git mailing list (https://github.com/git/git/blob/master/Documentation/SubmittingPatches)
  • the code in sharness.sh should be kept as much as possible similar as git/git/t/test-lib.sh (variable names, function names, ...)
  • if some changes do not depend on each other, it is better to send different PRs with as few changes as possible in each PR, rather than a big PR with everything
  • it is better to have tests with each PR, as sharness has its own test suite
  • API.md should be updated using make doc when new functions are added

Other things, thoughts?

Additional test function for string comparison?

In one of my tests I use the following approach:

test_expect_success "compare string content" '
    foo=$(do_something)
    expected="foo bar baz"
    [ "$foo" = "$expected" ]
'

The above is simple and good, as long as the tests succeed. But in case of failure, it is hard to understand the issue, since the (unexpected) content of $foo is not visible in the output (and thus not in build logs, etc.).

Instead I would prefer something like the existing test_expect_code, which outputs the real exit code of the command, in case it does not match the expected exit code.

How about the following function?

test_expect_equal_stdout 'foo bar baz' '
    do_something
'

In case of failure, sharness would be able to report the expected and the received texts that are supposed to be equal.

What do you think? Should I prepare a pull request for such a function?

Or would you prefer something similar to the existing test_cmp instead?

Or do you have another idea, how we could get more helpful output regarding failing tests?
(the issue causing this question was https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=910684)

trash dir as home dir when run on Windows

Sharness sets HOME to $SHARNESS_TRASH_DIRECTORY.
This works fine for *nix systems.
But I just run a test suite on Windows (in this case using bash from Git for Windows) and got real files modified by the tests.
The tested tool is written in Python and when Python looks up the user homedir, it looks for HOME only in the *nix variant.

You should also set USERPROFILE to $SHARNESS_TRASH_DIRECTORY, either always or if Windows is detected.
But even if you do detection, you should always set HOME, as the tests might also use that variable directly.

Document usage of "trash" directory

I am under the impression, that the usage of the "trash" directory (i.e. all files written to the current directory during the test being removed afterwards) is not well known.

Thus maybe it could deserve being mentioned somewhere. I am reluctant to send a proposal, since I am not sure, where it could be described. I see the following options:

  • A) add a sub-heading in README.md
  • B) insert a commented example (e.g. with test_cmp) into one of the existing examples in README.md
  • C) some other file?

What do you think?

Make a release v1.2

All the steps needed to make a release are present: pull #116. I even fixed issue #103.

Can we make a release? It's been almost 5 years since the last one.

make test fails with unliked SHELL_PATH

Cloned the master repo and did a make test just to try things out and saw failures all over the place. After digging, it's because the tests in sharness.t did not like my default shell, which is set into the generated test scripts in run_sub_test_lib_test() via the environment variable SHELL_PATH (set in sharness.sh via SHELL).

Since a number of tests in sharness.t assume bourne shell, perhaps it should be set as such?

@@ -50,7 +50,7 @@ run_sub_test_lib_test () {
        (
                cd "$name" &&
                cat >".$name.t" <<-EOF &&
-               #!$SHELL_PATH
+               #!/bin/sh
 
                test_description='$descr (run in sub sharness)

Can send a PR, just wanted to ping first.

Line feed regression

Commit 0f191d8 simply says "sharness.sh: remove LF definition". But why?

This commit broke my tests, which do make use of LF.

I was a member of the Git project, that's why I started using sharness. A good practice of the Git project is to always explain the reasoning behind each change.

I don't see any reasoning behind this change.

test_expect_failure test 2 = 2 does not fail with prove

(ins)[hendry@t14s sharness]$ bash foo.t
ok 1 - Success is reported like this
ok 2 - Commands are chained this way
ok 3 - You can test for a specific exit code
ok 4 - We expect this to fail # TODO known breakage vanished
# 1 known breakage(s) vanished; please update test(s)
# passed all remaining 3 test(s)
1..4
(ins)[hendry@t14s sharness]$ prove .
./foo.t .. ok
All tests successful.

Test Summary Report
-------------------
./foo.t (Wstat: 0 Tests: 4 Failed: 0)
  TODO passed:   4
Files=1, Tests=4,  0 wallclock secs ( 0.01 usr  0.01 sys +  0.01 cusr  0.01 csys =  0.04 CPU)
Result: PASS
(ins)[hendry@t14s sharness]$

Is this expected behavior with prove?

testing scripts with sourced functions

The relative path is not working when testing a script that sources another script.

Let's say we have

#!/usr/bin/env bash
# script foo.sh 
# calling another script bar.sh like this
source bar.sh
baz
exit 0

and of course

#!/usr/bin/env bash
# script bar.sh (in the same directory)
function baz () {
   echo "hello world!"
   exit 0
}

Then when I run sharness via prove --verbose it fails because it cannot find the bar.sh file.
The output is (I did not set a custom SHARNESS_TRASH_DIRECTORY):

../foo.sh: line 4: bar.sh: No such file or directory

Well this is true, but shouldn't it resolve to ../bar.sh instead?

Sharness self-test fails

3e0777c (test/sharness: normalize -x output before testing it, 2019-06-27)

was not enough to fix that failing test in my case.

The output I get is slightly different: ++ true,

Applying the following would make the test pass.

diff --git a/test/sharness.t b/test/sharness.t
index 7f720c3..bb53f38 100755
--- a/test/sharness.t
+++ b/test/sharness.t
@@ -307,10 +307,10 @@ test_expect_success 'pretend we have a pass, fail, and known breakage using -x'
                sed -e '/^ *$/d' >clean_out <out &&
                test_cmp expect_out clean_out &&
                sed -e 's/^> //' >expect_err <<-\\EOF &&
-               > +true
-               > +false
+               > ++ true
+               > ++ false
                > error: last command exited with \$?=1
-               > +false
+               > ++ false
                > error: last command exited with \$?=1
                EOF
                sed -e 's/^+ /+/' >clean_err <err &&

Maybe the normalization could be changed to sed -e 's/^[+]+ /+/'

The user choice of $PS4 can also interfere with this test.

Sourcing sharness.sh returns 1 instead of 0

Since mlafeldt@b65226f sourcing sharness.sh returns 1 instead of 0 previously.

This is because the above commit added the following line at the end of sharness.sh:

test -n "$TEST_LONG" && test_set_prereq EXPENSIVE

If "$TEST_LONG" is empty, the exit code of sourcing sharness.sh is then the exit code of test -n "$TEST_LONG" which is 1.

SHARNESS_TEST_SRCDIR and extensions

Adding sharness as a submodule, having a header on each test.t as follows:

: "${SHARNESS_TEST_DIRECTORY:=.}"
: "${SHARNESS_TEST_SRCDIR:=../sharness}"
. "${SHARNESS_TEST_SRCDIR}/sharness.sh"

and aggregate-results.sh and Makefile can be either copied or symbolic linked, mostly works;

However, it doesn't play well with extensions, because they're loaded from $SHARNESS_TEST_SRCDIR: https://github.com/chriscool/sharness/blob/b57a2a49d6b5663388c8a146d7af5fdf63491fc9/sharness.sh#L488

Wouldn't it make more sense to allow those extensions to be tracked alongside the parent project? For that we would need to either load it from $SHARNESS_TEST_DIRECTORY or add another env to specify a custom directory. This would allow users to keep the submodule clean without custom changes.

Or am I missing the usecase for sharness.d ?

Originally posted by @rafasc in #102 (comment)

Sharnessify script

I created this repo:

https://github.com/chriscool/sharnessify

It has a script to easily add Sharness infrastructure to some projects.

People working on IPFS related repos needed a simple way to add Sharness infrastructure to those repos.

Maybe we could talk about it somewhere in the documentation?

semi-verbose

❤️ sharness.

Would be nice to have a semi verbose option, where test cases would be output like in verbose, but only when they fail. Example:

ok 1 - current dir is writable
ok 2 - ipfs version succeeds
not ok 3 - ipfs version output looks good

expecting success:
    cat version.txt | egrep "^ipfs version [0-9]+\.[0-9]+\.[0-9]" >/dev/ ||
    cat version.txt && echo && false

ipfs version 0.1.7

ok 4 - ipfs help succeeds
ok 5 - ipfs help output looks good
1..5

This is a bit tricky. It might need buffering of the command's stdout/err and redirecting it to dev/null or 1 and 3 when needed (instead of the nice and simple piping of fds).

But buffering is painful. a poor-man's version might be to enable a different verbose mode where the stdio is still redirected to 1 and 2, but sharness itself remains quiet in passing tests. This way, we can be careful where we send all our io, and make sure only what we want to make it back to sharness does (like || cat ... above). This would enable almost the same thing, at the cost of having to be much more careful with test writing (and weird order).

ok 1 - current dir is writable
ok 2 - ipfs version succeeds
# ipfs version 0.1.7
not ok 3 - ipfs version output looks good
#
#   cat version.txt | egrep "^ipfs version [0-9]+\.[0-9]+\.[0-9]" >/dev/ ||
#   cat version.txt | sed -e 's/^/# /' && false
#
ok 4 - ipfs help succeeds
ok 5 - ipfs help output looks good
1..5

Calling functions from Git submodule fails with v1.2.0 release (Regression)

The README.md states this:

Alternatively, you can also add Sharness as a Git submodule to your project.

For my project this is the way I would prefer. That means sharness.sh will not be in the same folder as my tests, but in a subfolder, so I would include sharness/sharness.sh instead of sharness.sh only. I obviously don't want to put my tests into the Git Submodule sharness lives in. This worked fine up to release v1.1.0.

However with v1.2.0 sharness can not source functions, because it expects those to be in SHARNESS_TEST_SRCDIR/lib-sharness/functions.sh. As said above, for the Git Submodule case it's usually not wanted to have your tests and sharness.sh in the same directory.

This could be improved, if that path is not derived from SHARNESS_TEST_SRCDIR but from the actual directory sharness.sh lives in.
My tests fail like this:

% ./mxg.t 
ok 1 - Simple successful test
./mxg.t: 11: test_set_prereq: not found
# passed all 1 test(s)
1..1

As you can see it's not possible to call test_set_prereq from my test anymore. At least that function is affected.

sharness.sh is executable?

Currently the file sharness.sh looks like an executable (permission bit + shebang).
But for now I did not see a use-case for running it directly (instead of simply sourcing it - as the examples do).

Thus maybe the executable flag and the shebang can be removed?

Reasoning: I am about to package sharness for Debian and I would like to handle the sharness.sh file properly (either as a script or as a shell snippet).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.