2014-05-09 00:46:18 -04:00
|
|
|
#!/bin/bash
|
|
|
|
# Specification DSL test
|
|
|
|
#
|
|
|
|
# Copyright (C) 2014 Mike Gewitz
|
|
|
|
#
|
|
|
|
# This file is part of shspec.
|
|
|
|
#
|
|
|
|
# shspec is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
# TODO: This is incompletely tested because the tests must be written as the
|
|
|
|
# system itself is written! Therefore, it is not presently capable of
|
|
|
|
# running all necessary assertions on itself.
|
|
|
|
#
|
|
|
|
# Note: this test case will run pretty slowly because it forks a new process
|
|
|
|
# for each expectation.
|
|
|
|
##
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# It is necessary to test syntax in a separate process so we do not
|
|
|
|
# interfere with the existing stack
|
|
|
|
#
|
|
|
|
# This will take an arbitrary script from stdin and execute it
|
|
|
|
test-run()
|
|
|
|
{
|
|
|
|
../src/run-spec <( cat )
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
describe _begin-spec
|
|
|
|
it is a placeholder that exits successfully
|
|
|
|
expect _begin-spec
|
|
|
|
to succeed
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
describe describe
|
|
|
|
it fails if not paired with an "'end'"
|
|
|
|
expect test-run <<< '
|
|
|
|
describe foo
|
|
|
|
# no end
|
|
|
|
'; to fail
|
|
|
|
end
|
|
|
|
|
|
|
|
it succeeds if paired with matching "'end'"
|
|
|
|
expect test-run <<< '
|
|
|
|
describe foo
|
|
|
|
end
|
|
|
|
'; to succeed
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
describe it
|
|
|
|
it fails within "'describe'" if not paired with an "'end'"
|
|
|
|
expect test-run <<< '
|
|
|
|
describe it test
|
|
|
|
it will fail
|
|
|
|
# no end
|
|
|
|
end
|
|
|
|
'; to fail
|
|
|
|
end
|
|
|
|
|
|
|
|
it succeeds within "'describe'" if paired with an "'end'"
|
|
|
|
expect test-run <<< '
|
|
|
|
describe it test
|
|
|
|
it will succeed
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to succeed
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
describe expect
|
|
|
|
it fails when not within "'describe'"
|
|
|
|
expect test-run <<< '
|
|
|
|
describe will fail
|
|
|
|
# not within it
|
|
|
|
expect true; to succeed
|
|
|
|
end
|
|
|
|
'; to fail
|
|
|
|
end
|
|
|
|
|
|
|
|
it succeeds with "'to'" clause when when within "'describe'"
|
|
|
|
expect test-run <<< '
|
|
|
|
describe foo
|
|
|
|
it will succeed
|
|
|
|
expect true; to succeed
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to succeed
|
|
|
|
end
|
|
|
|
|
|
|
|
it fails when missing "'to'" clause of expectation
|
|
|
|
expect test-run <<< '
|
|
|
|
describe foo
|
|
|
|
it will fail
|
|
|
|
# no "to" clause
|
|
|
|
expect true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to fail
|
|
|
|
end
|
|
|
|
|
|
|
|
it cannot be "'end'd" before "'to'" clause
|
|
|
|
expect test-run <<< '
|
|
|
|
describe foo
|
|
|
|
it will fail
|
|
|
|
expect true
|
|
|
|
# expectation is unfinished
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to fail
|
|
|
|
end
|
|
|
|
|
2014-05-10 00:34:01 -04:00
|
|
|
|
|
|
|
# the "premise" is the command executed by the `expect' line
|
|
|
|
describe premise
|
|
|
|
it properly executes quoted command lines
|
|
|
|
expect test-run <<< '
|
|
|
|
chk() { test $# -eq 1; }
|
|
|
|
describe foo
|
|
|
|
it handles whitespace
|
|
|
|
expect chk "foo bar"
|
|
|
|
to succeed
|
|
|
|
end
|
2014-05-09 00:46:18 -04:00
|
|
|
end
|
2014-05-10 00:34:01 -04:00
|
|
|
'; to succeed
|
|
|
|
end
|
2014-05-09 00:46:18 -04:00
|
|
|
end
|
|
|
|
|
2014-05-09 01:59:21 -04:00
|
|
|
|
2014-05-10 00:34:01 -04:00
|
|
|
# the expectation handler performs the assertion logic
|
|
|
|
describe handler
|
|
|
|
it is provided premise exit code as first argument
|
|
|
|
expect test-run <<< '
|
|
|
|
declare excode=123
|
|
|
|
_expect--chk() { test "$1" -eq $excode; }
|
|
|
|
|
|
|
|
describe foo
|
|
|
|
it exposes exit code
|
|
|
|
expect exit $excode
|
|
|
|
to chk
|
|
|
|
end
|
2014-05-09 01:59:21 -04:00
|
|
|
end
|
2014-05-10 00:34:01 -04:00
|
|
|
'; to succeed
|
|
|
|
end
|
|
|
|
|
|
|
|
# the "remainder" clause is the portion of the sentence that follows the
|
|
|
|
# execution of the expectation handler
|
|
|
|
it is provided remainder clause after shift argument
|
|
|
|
expect test-run <<< '
|
|
|
|
declare remain="a b c"
|
|
|
|
_expect--chk()
|
|
|
|
{
|
|
|
|
shift "$2"
|
|
|
|
test "$*" == "$remain"
|
|
|
|
}
|
|
|
|
|
|
|
|
describe foo
|
|
|
|
it should expose remainder clause
|
|
|
|
expect true
|
|
|
|
to chk $remain
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to succeed
|
|
|
|
end
|
|
|
|
|
|
|
|
it receives premise output via stdin
|
|
|
|
expect test-run <<< '
|
|
|
|
declare str=foo
|
|
|
|
_expect--chk() { test "$(cat)" == "$str"; }
|
|
|
|
|
|
|
|
describe foo
|
|
|
|
it pipes command output
|
|
|
|
expect echo "$str"
|
|
|
|
to chk
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to succeed
|
|
|
|
end
|
2014-05-13 00:50:52 -04:00
|
|
|
|
|
|
|
# that is, if we use <<< to provide premise output from memory, a
|
|
|
|
# newline will be added; we don't want that!
|
|
|
|
it does not have newline added to premise output if missing
|
|
|
|
expect test-run <<< '
|
|
|
|
_expect--chk() { test "$( wc -c )" -eq 0; }
|
|
|
|
|
|
|
|
describe foo
|
|
|
|
it should not add newline
|
|
|
|
expect true
|
|
|
|
to chk
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to succeed
|
|
|
|
end
|
2014-05-09 01:59:21 -04:00
|
|
|
end
|
|
|
|
|
2014-05-09 00:46:18 -04:00
|
|
|
|
|
|
|
describe to
|
|
|
|
it fails when missing assertion string
|
|
|
|
expect test-run <<< '
|
|
|
|
describe foo
|
|
|
|
it will fail
|
|
|
|
# missing assertion sting
|
|
|
|
expect true; to
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to fail
|
|
|
|
end
|
|
|
|
|
|
|
|
it can only follow an "'expect'" clause
|
|
|
|
expect test-run <<< '
|
|
|
|
describe foo
|
|
|
|
it will fail
|
|
|
|
# does not follow expect clause
|
|
|
|
to succeed
|
|
|
|
end
|
|
|
|
'; to fail
|
|
|
|
end
|
|
|
|
|
|
|
|
it will fail on unknwon expectation
|
|
|
|
expect test-run <<< '
|
|
|
|
describe foo
|
|
|
|
it will fail
|
|
|
|
expect true
|
|
|
|
to ___some-invalid-expectation___
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to fail
|
|
|
|
end
|
|
|
|
|
|
|
|
it will fail when expectation fails
|
|
|
|
expect test-run <<< '
|
|
|
|
describe foo
|
|
|
|
it will fail
|
|
|
|
# true is not a failure
|
|
|
|
expect true; to fail
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to fail
|
|
|
|
end
|
|
|
|
|
|
|
|
it will succeed when expectation succeeds
|
|
|
|
expect test-run <<< '
|
|
|
|
describe foo
|
|
|
|
it will succeed
|
|
|
|
expect false; to fail
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to succeed
|
|
|
|
end
|
|
|
|
end
|
2014-05-09 21:48:09 -04:00
|
|
|
|
|
|
|
|
|
|
|
describe and
|
|
|
|
# technically, we want this to be permitted after any declaration, but
|
|
|
|
# we do not yet support any others
|
|
|
|
it must appear after a "'to'" declaration
|
|
|
|
expect test-run <<< '
|
|
|
|
describe foo
|
|
|
|
it should fail
|
|
|
|
expect true
|
|
|
|
# missing "to"
|
|
|
|
and to succeed
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to fail
|
|
|
|
end
|
|
|
|
|
|
|
|
it adds additional expectations to preceding declaration
|
|
|
|
# impossible condition
|
|
|
|
expect test-run <<< '
|
|
|
|
describe foo
|
|
|
|
it should fail
|
|
|
|
expect true
|
|
|
|
to succeed
|
|
|
|
and to fail
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to fail
|
|
|
|
|
|
|
|
# redundant to demonstrate that it does not always fail
|
|
|
|
expect test-run <<< '
|
|
|
|
describe foo
|
|
|
|
it should fail
|
|
|
|
expect true
|
|
|
|
to succeed
|
|
|
|
and to succeed
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to succeed
|
|
|
|
end
|
|
|
|
end
|
2014-05-12 23:51:08 -04:00
|
|
|
|
|
|
|
|
|
|
|
describe be
|
|
|
|
it cannot stand alone
|
|
|
|
expect test-run <<< '
|
|
|
|
describe foo
|
|
|
|
it should fail
|
|
|
|
expect true
|
|
|
|
to be
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to fail
|
|
|
|
end
|
|
|
|
|
|
|
|
it processes arguments as if it did not exist
|
|
|
|
expect test-run <<< '
|
|
|
|
expected="foo bar baz"
|
|
|
|
_expect--awesome() { shift "$2"; test "$*" == "$expected"; }
|
|
|
|
|
|
|
|
describe foo
|
|
|
|
it should succeed
|
|
|
|
expect true
|
|
|
|
# ignore the fact that this sounds awkward
|
|
|
|
to be awesome $expected
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to succeed
|
|
|
|
end
|
|
|
|
end
|
2014-05-13 21:38:30 -04:00
|
|
|
|
|
|
|
|
|
|
|
describe _proxy-to
|
|
|
|
it proxies remainder clause with variable shift length
|
|
|
|
expect test-run <<< '
|
|
|
|
expected="foo bar baz"
|
|
|
|
_expect--chk() { shift "$2"; test "$*" == "$expected"; }
|
|
|
|
|
|
|
|
describe foo
|
|
|
|
it should succeed
|
|
|
|
expect _proxy-to 0 2 chk $expected
|
|
|
|
to succeed
|
|
|
|
|
|
|
|
expect _proxy-to 0 3 /dev/null chk $expected
|
|
|
|
to succeed
|
|
|
|
end
|
|
|
|
end
|
|
|
|
'; to succeed
|
|
|
|
end
|
|
|
|
end
|
2014-05-09 00:46:18 -04:00
|
|
|
end
|
|
|
|
|