Skip to content

Commit

Permalink
prelude.mk: Use BATS to write bunch of tests
Browse files Browse the repository at this point in the history
In doing so, find and fix a bug in quote.shell that it trimmed trailing
newlines.  The fix involves exporting NL.
  • Loading branch information
LukeShu committed Sep 5, 2019
1 parent 3168a93 commit d20d098
Show file tree
Hide file tree
Showing 7 changed files with 286 additions and 3 deletions.
6 changes: 3 additions & 3 deletions prelude.mk
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
## Outputs ##
#
# String support:
# - Variable: NL
# - Variable: SPACE
# - Variable: export NL
# - Variable: SPACE
#
# Path support:
# - Function: path.trimprefix
Expand Down Expand Up @@ -70,7 +70,7 @@ joinlist=$(if $(word 2,$2),$(firstword $2)$1$(call joinlist,$1,$(wordlist 2,$(wo
# Based on
# https://git.lukeshu.com/autothing/tree/build-aux/Makefile.once.head/00-quote.mk?id=9384e763b00774603208b3d44977ed0e6762a09a
# but modified to make newlines work with shells other than Bash.
quote.shell = "$$(printf '%s\n' $(subst $(NL),' ','$(subst ','\'',$1)'))"
quote.shell = $(subst $(NL),'"$${NL}"','$(subst ','\'',$1)')

# Usage: VAR = $(call lazyonce,VAR,EXPR)
#
Expand Down
1 change: 1 addition & 0 deletions prelude_str.mk
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ define NL


endef
export NL

# NOTE: this is not a typo, this is actually how you spell space in Make
define SPACE
Expand Down
72 changes: 72 additions & 0 deletions tests/common.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/hint/bash

common_setup() {
test_tmpdir="$(mktemp -d)"
ln -s "$BATS_TEST_DIRNAME/.." "$test_tmpdir/build-aux"
cd "$test_tmpdir"
cat >Makefile <<-'__EOT__'
.DEFAULT_GOAL = all
all:
.PHONY: all
include build-aux/prelude.mk
expr-eq-strict-actual: FORCE; printf '%s' $(call quote.shell,$(EXPR)) > $@
expr-eq-echo-actual: FORCE; echo $(EXPR) > $@
expr-eq-sloppy-actual: FORCE; echo $(foreach w,$(EXPR),$w) > $@
__EOT__
}
setup() { common_setup; }

common_teardown() {
cd /
rm -rf -- "$test_tmpdir"
}
teardown() { common_teardown; }

# Usage: check_executable SNIPPET.mk VARNAME
check_executable() {
[[ $# = 2 ]]
local snippet=$1
local varname=$2

cat >>Makefile <<-__EOT__
include build-aux/${snippet}
include build-aux/var.mk
all: \$(${varname}) \$(var.)${varname}
__EOT__

make

local varvalue
varvalue="$(cat "build-aux/.var.${varname}")"

[[ "$varvalue" == /* ]]
[[ -f "$varvalue" && -x "$varvalue" ]]

eval "${varname}=\$varvalue"
}

check_expr_eq() {
[[ $# = 3 ]]
local mode=$1
local expr=$2
local expected=$3

case "$mode" in
strict) printf '%s' "$expected" > expected;;
echo) echo $expected > expected;;
sloppy) echo $expected > expected;;
esac

make EXPR="$expr" "expr-eq-${mode}-actual"

diff -u expected "expr-eq-${mode}-actual"
}

not() {
# This isn't just "I find 'not' more readable than '!'", it
# serves an actual purpose. '!' won't trigger an errexit, so
# it's no good for assertions. However, it can affect the
# return value of a function, and that function can trigger an
# errexit.
! "$@"
}
171 changes: 171 additions & 0 deletions tests/prelude.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
#!/usr/bin/env bats

load common

@test "prelude.mk: joinlist with separator" {
check_expr_eq echo '$(call joinlist,/,foo bar baz)' 'foo/bar/baz'
}

@test "prelude.mk: joinlist without separator" {
check_expr_eq echo '$(call joinlist,,foo bar baz)' 'foobarbaz'
}

@test "prelude.mk: quote.shell" {
# This test relies on the fact that 'var.mk' is implemented
# using `quote.shell`.
cat >>Makefile <<-'__EOT__'
include build-aux/prelude.mk
include build-aux/var.mk
define actual
some'string"with`special characters)
and newlines and tabs
and 2 trailing newlines
endef
all: $(var.)actual
__EOT__

make
printf 'some'\''string"with`special characters)\nand newlines\tand tabs\nand 2 trailing newlines\n\n' > expected
diff -u expected build-aux/.var.actual
}

@test "prelude.mk: lazyonce" {
cat >>Makefile <<-'__EOT__'
include build-aux/prelude.mk
var = $(call lazyonce,var,$(info eval-time)value)
$(info before)
$(info a: $(var))
$(info b: $(var))
$(info c: $(var))
all: noop
noop: ; @true
.PHONY: noop
__EOT__

make > actual
printf '%s\n' > expected \
'before' \
'eval-time' \
'a: value' \
'b: value' \
'c: value'
diff -u expected actual
}

@test "prelude.mk: build-aux.dir" {
cat >>Makefile <<-'__EOT__'
include build-aux/prelude.mk
include build-aux/var.mk
all: $(var.)build-aux.dir
__EOT__

make
# Check that it points to the right place
[[ "$(cat build-aux/.var.build-aux.dir)" -ef build-aux ]]
}

@test "prelude.mk: build-aux.bindir" {
cat >>Makefile <<-'__EOT__'
include build-aux/prelude.mk
include build-aux/var.mk
all: $(build-aux.bindir) $(var.)build-aux.bindir
__EOT__

make
# Check that it points to the right place
[[ "$(cat build-aux/.var.build-aux.bindir)" -ef build-aux/bin ]]
# Check that it's absolute
[[ "$(cat build-aux/.var.build-aux.bindir)" == /* ]]
}

@test "prelude.mk: FLOCK" {
if ! type flock &>/dev/null && ! type go &>/dev/null; then
skip
fi
check_executable prelude.mk FLOCK
if which flock &>/dev/null; then
[[ "$FLOCK" == "$(which flock)" ]]
fi

# TODO: Check that $FLOCK behaves correctly
}

@test "prelude.mk: COPY_IFCHANGED" {
check_executable prelude.mk COPY_IFCHANGED

# TODO: Check that $COPY_IFCHANGED behaves correctly
}

@test "prelude.mk: MOVE_IFCHANGED" {
check_executable prelude.mk MOVE_IFCHANGED

# TODO: Check that $MOVE_IFCHANGED behaves correctly
}

@test "prelude.mk: WRITE_IFCHANGED" {
check_executable prelude.mk WRITE_IFCHANGED

# TODO: Check that $WRITE_IFCHANGED behaves correctly
}

@test "prelude.mk: TAP_DRIVER" {
check_executable prelude.mk TAP_DRIVER

# TODO: Check that $TAP_DRIVER behaves correctly
}

@test "prelude.mk: clobber" {
if ! [[ -e build-aux/.git ]]; then
# Because we check `git clean -ndx` to make sure
# things are clean.
skip
fi
# Let's not work with a symlink for this test
rm "$test_tmpdir/build-aux"
cp -a "$BATS_TEST_DIRNAME/.." "$test_tmpdir/build-aux"
(cd build-aux && git clean -fdx)

cat >>Makefile <<-'__EOT__'
include build-aux/prelude.mk
include build-aux/var.mk
all: $(COPY_IFCHANGED) $(MOVE_IFCHANGED) $(WRITE_IFCHANGED) $(TAP_DRIVER)
__EOT__

[[ -d build-aux ]]
[[ ! -d build-aux/bin ]]
make all
[[ -d build-aux/bin ]]
[[ -f build-aux/bin/copy-ifchanged && -x build-aux/bin/copy-ifchanged ]]
[[ -n "$(cd build-aux && git clean -ndx)" ]]
make clobber
[[ -d build-aux ]]
[[ ! -d build-aux/bin ]]
[[ -z "$(cd build-aux && git clean -ndx)" ]]
}

@test "prelude.mk: build-aux.bin-go.rule" {
# TODO
}

@test "prelude.mk: FORCE" {
cat >>Makefile <<-'__EOT__'
include build-aux/prelude.mk
all: without-force with-force
without-force: ; touch $@
with-force: FORCE ; touch $@
__EOT__

make
cp -a with-force with-force.bak
cp -a without-force without-force.bak

sleep 2

make
ls -l
[[ with-force -nt with-force.bak ]]
[[ ! without-force -nt without-force.bak ]]
[[ ! without-force -ot without-force.bak ]]
}
15 changes: 15 additions & 0 deletions tests/prelude_go.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env bats

load common

@test "prelude_go.mk: GOHOSTOS" {
# TODO
}

@test "prelude_go.mk: GOHOSTARCH" {
# TODO
}

@test "prelude_go.mk: _prelude.go.lock" {
# TODO
}
11 changes: 11 additions & 0 deletions tests/prelude_path.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env bats

load common

@test "prelude_path.mk: path.trimprefix" {
check_expr_eq echo '$(call path.trimprefix,foo/bar,foo/bar foo/bar/baz qux)' '. baz qux'
}

@test "prelude_path.mk: path.addprefix" {
check_expr_eq echo '$(call path.addprefix,foo/bar,. baz)' 'foo/bar foo/bar/baz'
}
13 changes: 13 additions & 0 deletions tests/prelude_str.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bats

load common

@test "prelude_str.mk: NL" {
# Honestly, this checks `quote.shell` more than it does NL.
check_expr_eq strict '$(NL)' $'\n'
}

@test "prelude_str.mk: SPACE" {
# Honestly, this checks `quote.shell` more than it does SPACE.
check_expr_eq strict '$(SPACE)' ' '
}

0 comments on commit d20d098

Please sign in to comment.