summaryrefslogtreecommitdiff
path: root/unit-tests
diff options
context:
space:
mode:
Diffstat (limited to 'unit-tests')
-rw-r--r--unit-tests/Makefile.in101
-rw-r--r--unit-tests/comment31
-rw-r--r--unit-tests/cond1109
-rw-r--r--unit-tests/doterror20
-rw-r--r--unit-tests/dotwait61
-rw-r--r--unit-tests/error10
-rw-r--r--unit-tests/export22
-rw-r--r--unit-tests/export-all23
-rw-r--r--unit-tests/export-env24
-rw-r--r--unit-tests/forloop45
-rw-r--r--unit-tests/forsubst10
-rw-r--r--unit-tests/hash18
-rw-r--r--unit-tests/misc16
-rw-r--r--unit-tests/moderrs31
-rw-r--r--unit-tests/modmatch25
-rw-r--r--unit-tests/modmisc38
-rw-r--r--unit-tests/modorder22
-rw-r--r--unit-tests/modts43
-rw-r--r--unit-tests/modword151
-rw-r--r--unit-tests/order20
-rw-r--r--unit-tests/phony-end9
-rw-r--r--unit-tests/posix24
-rw-r--r--unit-tests/qequals8
-rw-r--r--unit-tests/sysv26
-rw-r--r--unit-tests/ternary8
-rw-r--r--unit-tests/test.exp380
-rw-r--r--unit-tests/unexport8
-rw-r--r--unit-tests/unexport-env14
-rw-r--r--unit-tests/varcmd49
29 files changed, 1346 insertions, 0 deletions
diff --git a/unit-tests/Makefile.in b/unit-tests/Makefile.in
new file mode 100644
index 0000000..bfd29b2
--- /dev/null
+++ b/unit-tests/Makefile.in
@@ -0,0 +1,101 @@
+# $Id: Makefile.in,v 1.42 2013/03/23 02:31:13 sjg Exp $
+#
+# $NetBSD: Makefile,v 1.36 2013/03/22 16:36:46 sjg Exp $
+#
+# Unit tests for make(1)
+# The main targets are:
+#
+# all: run all the tests
+# test: run 'all', capture output and compare to expected results
+# accept: move generated output to expected results
+#
+# Adding a test case.
+# Each feature should get its own set of tests in its own suitably
+# named makefile which should be added to SUBFILES to hook it in.
+#
+
+srcdir= @srcdir@
+
+.MAIN: all
+
+UNIT_TESTS:= ${srcdir}
+
+# Simple sub-makefiles - we run them as a black box
+# keep the list sorted.
+SUBFILES= \
+ comment \
+ cond1 \
+ error \
+ export \
+ export-all \
+ export-env \
+ doterror \
+ dotwait \
+ forloop \
+ forsubst \
+ hash \
+ misc \
+ moderrs \
+ modmatch \
+ modmisc \
+ modorder \
+ modts \
+ modword \
+ order \
+ phony-end \
+ posix \
+ qequals \
+ sysv \
+ ternary \
+ unexport \
+ unexport-env \
+ varcmd
+
+all: ${SUBFILES}
+
+flags.doterror=
+flags.order=-j1
+
+# the tests are actually done with sub-makes.
+.PHONY: ${SUBFILES}
+.PRECIOUS: ${SUBFILES}
+${SUBFILES}:
+ -@${.MAKE} ${flags.$@:U-k} -f ${UNIT_TESTS}/$@
+
+clean:
+ rm -f *.out *.fail *.core
+
+.-include <obj.mk>
+
+TEST_MAKE?= ${.MAKE}
+TOOL_SED?= sed
+TOOL_TR?= tr
+TOOL_DIFF?= diff
+DIFF_FLAGS?= @diff_u@
+
+.if defined(.PARSEDIR)
+# ensure consistent results from sort(1)
+LC_ALL= C
+LANG= C
+.export LANG LC_ALL
+.endif
+
+# The driver.
+# We always pretend .MAKE was called 'make'
+# and strip ${.CURDIR}/ from the output
+# and replace anything after 'stopped in' with unit-tests
+# so the results can be compared.
+test:
+ @echo "${TEST_MAKE} -f ${MAKEFILE} > ${.TARGET}.out 2>&1"
+ @cd ${.OBJDIR} && ${TEST_MAKE} -f ${MAKEFILE} 2>&1 | \
+ ${TOOL_TR} -d '\015' | \
+ ${TOOL_SED} -e 's,^${TEST_MAKE:T:C/\./\\\./g}:,make:,' \
+ -e '/stopped/s, /.*, unit-tests,' \
+ -e 's,${.CURDIR:C/\./\\\./g}/,,g' \
+ -e 's,${UNIT_TESTS:C/\./\\\./g}/,,g' > ${.TARGET}.out || { \
+ tail ${.TARGET}.out; mv ${.TARGET}.out ${.TARGET}.fail; exit 1; }
+ ${TOOL_DIFF} ${DIFF_FLAGS} ${UNIT_TESTS}/${.TARGET}.exp ${.TARGET}.out
+
+accept:
+ mv test.out ${srcdir}/test.exp
+
diff --git a/unit-tests/comment b/unit-tests/comment
new file mode 100644
index 0000000..7dd7dbb
--- /dev/null
+++ b/unit-tests/comment
@@ -0,0 +1,31 @@
+# This is a comment
+.if ${MACHINE_ARCH} == something
+FOO=bar
+.endif
+
+#\
+ Multiline comment
+
+BAR=# defined
+FOOBAR= # defined
+
+# This is an escaped comment \
+that keeps going until the end of this line
+
+# Another escaped comment \
+that \
+goes \
+on
+
+# This is NOT an escaped comment due to the double backslashes \\
+all: hi foo bar
+ @echo comment testing done
+
+hi:
+ @echo comment testing start
+
+foo:
+ @echo this is $@
+
+bar:
+ @echo This is how a comment looks: '# comment'
diff --git a/unit-tests/cond1 b/unit-tests/cond1
new file mode 100644
index 0000000..c877c3d
--- /dev/null
+++ b/unit-tests/cond1
@@ -0,0 +1,109 @@
+# $Id: cond1,v 1.1.1.3 2011/03/06 00:04:58 sjg Exp $
+
+# hard code these!
+TEST_UNAME_S= NetBSD
+TEST_UNAME_M= sparc
+TEST_MACHINE= i386
+
+.if ${TEST_UNAME_S}
+Ok=var,
+.endif
+.if ("${TEST_UNAME_S}")
+Ok+=(\"var\"),
+.endif
+.if (${TEST_UNAME_M} != ${TEST_MACHINE})
+Ok+=(var != var),
+.endif
+.if ${TEST_UNAME_M} != ${TEST_MACHINE}
+Ok+= var != var,
+.endif
+.if !((${TEST_UNAME_M} != ${TEST_MACHINE}) && defined(X))
+Ok+= !((var != var) && defined(name)),
+.endif
+# from bsd.obj.mk
+MKOBJ?=no
+.if ${MKOBJ} == "no"
+o= no
+Ok+= var == "quoted",
+.else
+.if defined(notMAKEOBJDIRPREFIX) || defined(norMAKEOBJDIR)
+.if defined(notMAKEOBJDIRPREFIX)
+o=${MAKEOBJDIRPREFIX}${__curdir}
+.else
+o= ${MAKEOBJDIR}
+.endif
+.endif
+o= o
+.endif
+
+# repeat the above to check we get the same result
+.if ${MKOBJ} == "no"
+o2= no
+.else
+.if defined(notMAKEOBJDIRPREFIX) || defined(norMAKEOBJDIR)
+.if defined(notMAKEOBJDIRPREFIX)
+o2=${MAKEOBJDIRPREFIX}${__curdir}
+.else
+o2= ${MAKEOBJDIR}
+.endif
+.endif
+o2= o
+.endif
+
+PRIMES=2 3 5 7 11
+NUMBERS=1 2 3 4 5
+
+n=2
+.if ${PRIMES:M$n} == ""
+X=not
+.else
+X=
+.endif
+
+.if ${MACHINE_ARCH} == no-such
+A=one
+.else
+.if ${MACHINE_ARCH} == not-this
+.if ${MACHINE_ARCH} == something-else
+A=unlikely
+.else
+A=no
+.endif
+.endif
+A=other
+# We expect an extra else warning - we're not skipping here
+.else
+A=this should be an error
+.endif
+
+.if $X != ""
+.if $X == not
+B=one
+.else
+B=other
+# We expect an extra else warning - we are skipping here
+.else
+B=this should be an error
+.endif
+.else
+B=unknown
+.endif
+
+.if "quoted" == quoted
+C=clever
+.else
+C=dim
+.endif
+
+.if defined(nosuch) && ${nosuch:Mx} != ""
+# this should not happen
+.info nosuch is x
+.endif
+
+all:
+ @echo "$n is $X prime"
+ @echo "A='$A' B='$B' C='$C' o='$o,${o2}'"
+ @echo "Passed:${.newline} ${Ok:S/,/${.newline}/}"
+ @echo "${NUMBERS:@n@$n is ${("${PRIMES:M$n}" == ""):?not:} prime${.newline}@}"
+ @echo "${"${DoNotQuoteHere:U0}" > 0:?OK:No}"
+ @echo "${${NoSuchNumber:U42} > 0:?OK:No}"
diff --git a/unit-tests/doterror b/unit-tests/doterror
new file mode 100644
index 0000000..75d8920
--- /dev/null
+++ b/unit-tests/doterror
@@ -0,0 +1,20 @@
+# $Id: doterror,v 1.1.1.1 2010/04/08 17:43:00 sjg Exp $
+
+
+.BEGIN:
+ @echo At first, I am
+
+.END:
+ @echo not reached
+
+.ERROR:
+ @echo "$@: Looks like '${.ERROR_TARGET}' is upset."
+
+all: happy sad
+
+happy:
+ @echo $@
+
+sad:
+ @echo and now: $@; exit 1
+
diff --git a/unit-tests/dotwait b/unit-tests/dotwait
new file mode 100644
index 0000000..43706af
--- /dev/null
+++ b/unit-tests/dotwait
@@ -0,0 +1,61 @@
+# $NetBSD: dotwait,v 1.1 2006/02/26 22:45:46 apb Exp $
+
+THISMAKEFILE:= ${.PARSEDIR}/${.PARSEFILE}
+
+TESTS= simple recursive shared cycle
+PAUSE= sleep 1
+
+# Use a .for loop rather than dependencies here, to ensure
+# that the tests are run one by one, with parallelism
+# only within tests.
+# Ignore "--- target ---" lines printed by parallel make.
+all:
+.for t in ${TESTS}
+ @${.MAKE} -f ${THISMAKEFILE} -j4 $t | grep -v "^--- "
+.endfor
+
+#
+# Within each test, the names of the sub-targets follow these
+# conventions:
+# * If it's expected that two or more targets may be made in parallel,
+# then the target names will differ only in an alphabetic component
+# such as ".a" or ".b".
+# * If it's expected that two or more targets should be made in sequence
+# then the target names will differ in numeric components, such that
+# lexical ordering of the target names matches the expected order
+# in which the targets should be made.
+#
+# Targets may echo ${PARALLEL_TARG} to print a modified version
+# of their own name, in which alphabetic components like ".a" or ".b"
+# are converted to ".*". Two targets that are expected to
+# be made in parallel will thus print the same strings, so that the
+# output is independent of the order in which these targets are made.
+#
+PARALLEL_TARG= ${.TARGET:C/\.[a-z]/.*/g:Q}
+.DEFAULT:
+ @echo ${PARALLEL_TARG}; ${PAUSE}; echo ${PARALLEL_TARG}
+_ECHOUSE: .USE
+ @echo ${PARALLEL_TARG}; ${PAUSE}; echo ${PARALLEL_TARG}
+
+# simple: no recursion, no cycles
+simple: simple.1 .WAIT simple.2
+
+# recursive: all children of the left hand side of the .WAIT
+# must be made before any child of the right hand side.
+recursive: recursive.1.99 .WAIT recursive.2.99
+recursive.1.99: recursive.1.1.a recursive.1.1.b _ECHOUSE
+recursive.2.99: recursive.2.1.a recursive.2.1.b _ECHOUSE
+
+# shared: both shared.1.99 and shared.2.99 depend on shared.0.
+# shared.0 must be made first, even though it is a child of
+# the right hand side of the .WAIT.
+shared: shared.1.99 .WAIT shared.2.99
+shared.1.99: shared.0 _ECHOUSE
+shared.2.99: shared.2.1 shared.0 _ECHOUSE
+
+# cycle: the cyclic dependency must not cause infinite recursion
+# leading to stack overflow and a crash.
+cycle: cycle.1.99 .WAIT cycle.2.99
+cycle.2.99: cycle.2.98 _ECHOUSE
+cycle.2.98: cycle.2.97 _ECHOUSE
+cycle.2.97: cycle.2.99 _ECHOUSE
diff --git a/unit-tests/error b/unit-tests/error
new file mode 100644
index 0000000..c0a1403
--- /dev/null
+++ b/unit-tests/error
@@ -0,0 +1,10 @@
+# $Id: error,v 1.1.1.2 2010/05/24 23:36:03 sjg Exp $
+
+.info just FYI
+.warning this could be serious
+.error this is fatal
+
+all:
+
+.info.html:
+ @echo this should be ignored
diff --git a/unit-tests/export b/unit-tests/export
new file mode 100644
index 0000000..3e2ad95
--- /dev/null
+++ b/unit-tests/export
@@ -0,0 +1,22 @@
+# $Id: export,v 1.1.1.1 2007/10/08 20:30:12 sjg Exp $
+
+UT_TEST=export
+UT_FOO=foo${BAR}
+UT_FU=fubar
+UT_ZOO=hoopie
+UT_NO=all
+# belive it or not, we expect this one to come out with $UT_FU unexpanded.
+UT_DOLLAR= This is $$UT_FU
+
+.export UT_FU UT_FOO
+.export UT_DOLLAR
+# this one will be ignored
+.export .MAKE.PID
+
+BAR=bar is ${UT_FU}
+
+.MAKE.EXPORTED+= UT_ZOO UT_TEST
+
+all:
+ @env | grep '^UT_' | sort
+
diff --git a/unit-tests/export-all b/unit-tests/export-all
new file mode 100644
index 0000000..a243fe3
--- /dev/null
+++ b/unit-tests/export-all
@@ -0,0 +1,23 @@
+# $Id: export-all,v 1.1.1.2 2010/04/21 04:26:14 sjg Exp $
+
+UT_OK=good
+UT_F=fine
+
+# the old way to do :tA
+M_tAbad = C,.*,cd & \&\& 'pwd',:sh
+# the new
+M_tA = tA
+
+here := ${.PARSEDIR}
+
+# this will cause trouble (recursing if we let it)
+UT_BADDIR = ${${here}/../${here:T}:L:${M_tAbad}:T}
+# this will be ok
+UT_OKDIR = ${${here}/../${here:T}:L:${M_tA}:T}
+
+.export
+
+.include "export"
+
+UT_TEST=export-all
+UT_ALL=even this gets exported
diff --git a/unit-tests/export-env b/unit-tests/export-env
new file mode 100644
index 0000000..b6ce6a2
--- /dev/null
+++ b/unit-tests/export-env
@@ -0,0 +1,24 @@
+# $Id: export-env,v 1.1.1.1 2013/03/23 02:26:59 sjg Exp $
+
+# our normal .export, subsequent changes affect the environment
+UT_TEST=this
+.export UT_TEST
+UT_TEST:= ${.PARSEFILE}
+
+# not so with .export-env
+UT_ENV=exported
+.export-env UT_ENV
+UT_ENV=not-exported
+
+# gmake style export goes further; affects nothing but the environment
+UT_EXP=before-export
+export UT_EXP=exported
+UT_EXP=not-exported
+
+all:
+ @echo make:; ${UT_TEST UT_ENV UT_EXP:L:@v@echo $v=${$v};@}
+ @echo env:; ${UT_TEST UT_ENV UT_EXP:L:@v@echo $v=$${$v};@}
+
+
+
+
diff --git a/unit-tests/forloop b/unit-tests/forloop
new file mode 100644
index 0000000..0b50e66
--- /dev/null
+++ b/unit-tests/forloop
@@ -0,0 +1,45 @@
+# $Id: forloop,v 1.1.1.1 2012/06/19 23:30:49 sjg Exp $
+
+all: for-loop
+
+LIST = one "two and three" four "five"
+
+.if make(for-fail)
+for-fail:
+
+XTRA_LIST = xtra
+.else
+
+.for x in ${LIST}
+X!= echo 'x=$x' >&2; echo
+.endfor
+
+CFL = -I/this -I"This or that" -Ithat "-DTHIS=\"this and that\""
+cfl=
+.for x in ${CFL}
+X!= echo 'x=$x' >&2; echo
+.if empty(cfl)
+cfl= $x
+.else
+cfl+= $x
+.endif
+.endfor
+X!= echo 'cfl=${cfl}' >&2; echo
+
+.if ${cfl} != ${CFL}
+.error ${.newline}'${cfl}' != ${.newline}'${CFL}'
+.endif
+
+.for a b in ${EMPTY}
+X!= echo 'a=$a b=$b' >&2; echo
+.endfor
+.endif
+
+.for a b in ${LIST} ${LIST:tu} ${XTRA_LIST}
+X!= echo 'a=$a b=$b' >&2; echo
+.endfor
+
+for-loop:
+ @echo We expect an error next:
+ @(cd ${.CURDIR} && ${.MAKE} -f ${MAKEFILE} for-fail) && \
+ { echo "Oops that should have failed!"; exit 1; } || echo OK
diff --git a/unit-tests/forsubst b/unit-tests/forsubst
new file mode 100644
index 0000000..d3a7de1
--- /dev/null
+++ b/unit-tests/forsubst
@@ -0,0 +1,10 @@
+# $Id: forsubst,v 1.1.1.1 2009/10/07 18:53:35 sjg Exp $
+
+all: for-subst
+
+here := ${.PARSEDIR}
+# this should not run foul of the parser
+.for file in ${.PARSEFILE}
+for-subst: ${file:S;^;${here}/;g}
+ @echo ".for with :S;... OK"
+.endfor
diff --git a/unit-tests/hash b/unit-tests/hash
new file mode 100644
index 0000000..1ed84e7
--- /dev/null
+++ b/unit-tests/hash
@@ -0,0 +1,18 @@
+STR1=
+STR2= a
+STR3= ab
+STR4= abc
+STR5= abcd
+STR6= abcde
+STR7= abcdef
+STR8= abcdefghijklmnopqrstuvwxyz
+
+all:
+ @echo ${STR1:hash}
+ @echo ${STR2:hash}
+ @echo ${STR3:hash}
+ @echo ${STR4:hash}
+ @echo ${STR5:hash}
+ @echo ${STR6:hash}
+ @echo ${STR7:hash}
+ @echo ${STR8:hash}
diff --git a/unit-tests/misc b/unit-tests/misc
new file mode 100644
index 0000000..4ba3655
--- /dev/null
+++ b/unit-tests/misc
@@ -0,0 +1,16 @@
+# $Id: misc,v 1.1.1.1 2011/03/06 00:04:58 sjg Exp $
+
+.if !exists(${.CURDIR}/)
+.warning ${.CURDIR}/ doesn't exist ?
+.endif
+
+.if !exists(${.CURDIR}/.)
+.warning ${.CURDIR}/. doesn't exist ?
+.endif
+
+.if !exists(${.CURDIR}/..)
+.warning ${.CURDIR}/.. doesn't exist ?
+.endif
+
+all:
+ @: all is well
diff --git a/unit-tests/moderrs b/unit-tests/moderrs
new file mode 100644
index 0000000..b8f78ce
--- /dev/null
+++ b/unit-tests/moderrs
@@ -0,0 +1,31 @@
+# $Id: moderrs,v 1.2 2006/05/11 18:53:39 sjg Exp $
+#
+# various modifier error tests
+
+VAR=TheVariable
+# incase we have to change it ;-)
+MOD_UNKN=Z
+MOD_TERM=S,V,v
+MOD_S:= ${MOD_TERM},
+
+all: modunkn modunknV varterm vartermV modtermV
+
+modunkn:
+ @echo "Expect: Unknown modifier 'Z'"
+ @echo "VAR:Z=${VAR:Z}"
+
+modunknV:
+ @echo "Expect: Unknown modifier 'Z'"
+ @echo "VAR:${MOD_UNKN}=${VAR:${MOD_UNKN}}"
+
+varterm:
+ @echo "Expect: Unclosed variable specification for VAR"
+ @echo VAR:S,V,v,=${VAR:S,V,v,
+
+vartermV:
+ @echo "Expect: Unclosed variable specification for VAR"
+ @echo VAR:${MOD_TERM},=${VAR:${MOD_S}
+
+modtermV:
+ @echo "Expect: Unclosed substitution for VAR (, missing)"
+ -@echo "VAR:${MOD_TERM}=${VAR:${MOD_TERM}}"
diff --git a/unit-tests/modmatch b/unit-tests/modmatch
new file mode 100644
index 0000000..48a1bef
--- /dev/null
+++ b/unit-tests/modmatch
@@ -0,0 +1,25 @@
+
+X=a b c d e
+
+.for x in $X
+LIB${x:tu}=/tmp/lib$x.a
+.endfor
+
+X_LIBS= ${LIBA} ${LIBD} ${LIBE}
+
+LIB?=a
+
+var = head
+res = no
+.if !empty(var:M${:Uhead\:tail:C/:.*//})
+res = OK
+.endif
+
+all:
+ @for x in $X; do ${.MAKE} -f ${MAKEFILE} show LIB=$$x; done
+ @echo "Mscanner=${res}"
+
+show:
+ @echo 'LIB=${LIB} X_LIBS:M$${LIB$${LIB:tu}} is "${X_LIBS:M${LIB${LIB:tu}}}"'
+ @echo 'LIB=${LIB} X_LIBS:M*/lib$${LIB}.a is "${X_LIBS:M*/lib${LIB}.a}"'
+ @echo 'LIB=${LIB} X_LIBS:M*/lib$${LIB}.a:tu is "${X_LIBS:M*/lib${LIB}.a:tu}"'
diff --git a/unit-tests/modmisc b/unit-tests/modmisc
new file mode 100644
index 0000000..d562e46
--- /dev/null
+++ b/unit-tests/modmisc
@@ -0,0 +1,38 @@
+# $Id: modmisc,v 1.1.1.5 2011/04/11 15:10:32 sjg Exp $
+#
+# miscellaneous modifier tests
+
+# do not put any dirs in this list which exist on some
+# but not all target systems - an exists() check is below.
+path=:/bin:/tmp::/:.:/no/such/dir:.
+# strip cwd from path.
+MOD_NODOT=S/:/ /g:N.:ts:
+# and decorate, note that $'s need to be doubled. Also note that
+# the modifier_variable can be used with other modifiers.
+MOD_NODOTX=S/:/ /g:N.:@d@'$$d'@
+# another mod - pretend it is more interesting
+MOD_HOMES=S,/home/,/homes/,
+MOD_OPT=@d@$${exists($$d):?$$d:$${d:S,/usr,/opt,}}@
+MOD_SEP=S,:, ,g
+
+all: modvar modvarloop modsysv
+
+modsysv:
+ @echo "The answer is ${libfoo.a:L:libfoo.a=42}"
+
+modvar:
+ @echo "path='${path}'"
+ @echo "path='${path:${MOD_NODOT}}'"
+ @echo "path='${path:S,home,homes,:${MOD_NODOT}}'"
+ @echo "path=${path:${MOD_NODOTX}:ts:}"
+ @echo "path=${path:${MOD_HOMES}:${MOD_NODOTX}:ts:}"
+
+.for d in ${path:${MOD_SEP}:N.} /usr/xbin
+path_$d?= ${d:${MOD_OPT}:${MOD_HOMES}}/
+paths+= ${d:${MOD_OPT}:${MOD_HOMES}}
+.endfor
+
+modvarloop:
+ @echo "path_/usr/xbin=${path_/usr/xbin}"
+ @echo "paths=${paths}"
+ @echo "PATHS=${paths:tu}"
diff --git a/unit-tests/modorder b/unit-tests/modorder
new file mode 100644
index 0000000..68b66fb
--- /dev/null
+++ b/unit-tests/modorder
@@ -0,0 +1,22 @@
+# $NetBSD: modorder,v 1.2 2007/10/05 15:27:46 sjg Exp $
+
+LIST= one two three four five six seven eight nine ten
+LISTX= ${LIST:Ox}
+LISTSX:= ${LIST:Ox}
+TEST_RESULT= && echo Ok || echo Failed
+
+# unit-tests have to produce the same results on each run
+# so we cannot actually include :Ox output.
+all:
+ @echo "LIST = ${LIST}"
+ @echo "LIST:O = ${LIST:O}"
+ # Note that 1 in every 10! trials two independently generated
+ # randomized orderings will be the same. The test framework doesn't
+ # support checking probabilistic output, so we accept that the test
+ # will incorrectly fail with probability 2.8E-7.
+ @echo "LIST:Ox = `test '${LIST:Ox}' != '${LIST:Ox}' ${TEST_RESULT}`"
+ @echo "LIST:O:Ox = `test '${LIST:O:Ox}' != '${LIST:O:Ox}' ${TEST_RESULT}`"
+ @echo "LISTX = `test '${LISTX}' != '${LISTX}' ${TEST_RESULT}`"
+ @echo "LISTSX = `test '${LISTSX}' = '${LISTSX}' ${TEST_RESULT}`"
+ @echo "BADMOD 1 = ${LIST:OX}"
+ @echo "BADMOD 2 = ${LIST:OxXX}"
diff --git a/unit-tests/modts b/unit-tests/modts
new file mode 100644
index 0000000..616bd89
--- /dev/null
+++ b/unit-tests/modts
@@ -0,0 +1,43 @@
+
+LIST= one two three
+LIST+= four five six
+
+FU_mod-ts = a / b / cool
+
+AAA= a a a
+B.aaa= Baaa
+
+all: mod-ts
+
+# Use print or printf iff they are builtin.
+# XXX note that this causes problems, when make decides
+# there is no need to use a shell, so avoid where possible.
+.if ${type print 2> /dev/null || echo:L:sh:Mbuiltin} != ""
+PRINT= print -r --
+.elif ${type printf 2> /dev/null || echo:L:sh:Mbuiltin} != ""
+PRINT= printf '%s\n'
+.else
+PRINT= echo
+.endif
+
+mod-ts:
+ @echo 'LIST="${LIST}"'
+ @echo 'LIST:ts,="${LIST:ts,}"'
+ @echo 'LIST:ts/:tu="${LIST:ts/:tu}"'
+ @echo 'LIST:ts::tu="${LIST:ts::tu}"'
+ @echo 'LIST:ts:tu="${LIST:ts:tu}"'
+ @echo 'LIST:tu:ts/="${LIST:tu:ts/}"'
+ @echo 'LIST:ts:="${LIST:ts:}"'
+ @echo 'LIST:ts="${LIST:ts}"'
+ @echo 'LIST:ts:S/two/2/="${LIST:ts:S/two/2/}"'
+ @echo 'LIST:S/two/2/:ts="${LIST:S/two/2/:ts}"'
+ @echo 'LIST:ts/:S/two/2/="${LIST:ts/:S/two/2/}"'
+ @echo "Pretend the '/' in '/n' etc. below are back-slashes."
+ @${PRINT} 'LIST:ts/n="${LIST:ts\n}"'
+ @${PRINT} 'LIST:ts/t="${LIST:ts\t}"'
+ @${PRINT} 'LIST:ts/012:tu="${LIST:ts\012:tu}"'
+ @${PRINT} 'LIST:tx="${LIST:tx}"'
+ @${PRINT} 'LIST:ts/x:tu="${LIST:ts\x:tu}"'
+ @${PRINT} 'FU_$@="${FU_${@:ts}:ts}"'
+ @${PRINT} 'FU_$@:ts:T="${FU_${@:ts}:ts:T}" == cool?'
+ @${PRINT} 'B.$${AAA:ts}="${B.${AAA:ts}}" == Baaa?'
diff --git a/unit-tests/modword b/unit-tests/modword
new file mode 100644
index 0000000..39355d7
--- /dev/null
+++ b/unit-tests/modword
@@ -0,0 +1,151 @@
+# $Id: modword,v 1.1.1.1 2003/09/28 17:01:48 sjg Exp $
+#
+# Test behaviour of new :[] modifier
+
+all: mod-squarebrackets mod-S-W mod-C-W mod-tW-tw
+
+LIST= one two three
+LIST+= four five six
+LONGLIST= 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+
+EMPTY= # the space should be ignored
+ESCAPEDSPACE=\ # escaped space before the '#'
+REALLYSPACE:=${EMPTY:C/^/ /W}
+HASH= \#
+AT= @
+STAR= *
+ZERO= 0
+ONE= 1
+MINUSONE= -1
+
+mod-squarebrackets: mod-squarebrackets-0-star-at \
+ mod-squarebrackets-hash \
+ mod-squarebrackets-n \
+ mod-squarebrackets-start-end \
+ mod-squarebrackets-nested
+
+mod-squarebrackets-0-star-at:
+ @echo 'LIST:[]="${LIST:[]}" is an error'
+ @echo 'LIST:[0]="${LIST:[0]}"'
+ @echo 'LIST:[0x0]="${LIST:[0x0]}"'
+ @echo 'LIST:[000]="${LIST:[000]}"'
+ @echo 'LIST:[*]="${LIST:[*]}"'
+ @echo 'LIST:[@]="${LIST:[@]}"'
+ @echo 'LIST:[0]:C/ /,/="${LIST:[0]:C/ /,/}"'
+ @echo 'LIST:[0]:C/ /,/g="${LIST:[0]:C/ /,/g}"'
+ @echo 'LIST:[0]:C/ /,/1g="${LIST:[0]:C/ /,/1g}"'
+ @echo 'LIST:[*]:C/ /,/="${LIST:[*]:C/ /,/}"'
+ @echo 'LIST:[*]:C/ /,/g="${LIST:[*]:C/ /,/g}"'
+ @echo 'LIST:[*]:C/ /,/1g="${LIST:[*]:C/ /,/1g}"'
+ @echo 'LIST:[@]:C/ /,/="${LIST:[@]:C/ /,/}"'
+ @echo 'LIST:[@]:C/ /,/g="${LIST:[@]:C/ /,/g}"'
+ @echo 'LIST:[@]:C/ /,/1g="${LIST:[@]:C/ /,/1g}"'
+ @echo 'LIST:[@]:[0]:C/ /,/="${LIST:[@]:[0]:C/ /,/}"'
+ @echo 'LIST:[0]:[@]:C/ /,/="${LIST:[0]:[@]:C/ /,/}"'
+ @echo 'LIST:[@]:[*]:C/ /,/="${LIST:[@]:[*]:C/ /,/}"'
+ @echo 'LIST:[*]:[@]:C/ /,/="${LIST:[*]:[@]:C/ /,/}"'
+
+mod-squarebrackets-hash:
+ @echo 'EMPTY="${EMPTY}"'
+ @echo 'EMPTY:[#]="${EMPTY:[#]}" == 1 ?'
+ @echo 'ESCAPEDSPACE="${ESCAPEDSPACE}"'
+ @echo 'ESCAPEDSPACE:[#]="${ESCAPEDSPACE:[#]}" == 1 ?'
+ @echo 'REALLYSPACE="${REALLYSPACE}"'
+ @echo 'REALLYSPACE:[#]="${REALLYSPACE:[#]}" == 1 ?'
+ @echo 'LIST:[#]="${LIST:[#]}"'
+ @echo 'LIST:[0]:[#]="${LIST:[0]:[#]}" == 1 ?'
+ @echo 'LIST:[*]:[#]="${LIST:[*]:[#]}" == 1 ?'
+ @echo 'LIST:[@]:[#]="${LIST:[@]:[#]}"'
+ @echo 'LIST:[1]:[#]="${LIST:[1]:[#]}"'
+ @echo 'LIST:[1..3]:[#]="${LIST:[1..3]:[#]}"'
+
+mod-squarebrackets-n:
+ @echo 'EMPTY:[1]="${EMPTY:[1]}"'
+ @echo 'ESCAPEDSPACE="${ESCAPEDSPACE}"'
+ @echo 'ESCAPEDSPACE:[1]="${ESCAPEDSPACE:[1]}"'
+ @echo 'REALLYSPACE="${REALLYSPACE}"'
+ @echo 'REALLYSPACE:[1]="${REALLYSPACE:[1]}" == "" ?'
+ @echo 'REALLYSPACE:[*]:[1]="${REALLYSPACE:[*]:[1]}" == " " ?'
+ @echo 'LIST:[1]="${LIST:[1]}"'
+ @echo 'LIST:[1.]="${LIST:[1.]}" is an error'
+ @echo 'LIST:[1].="${LIST:[1].}" is an error'
+ @echo 'LIST:[2]="${LIST:[2]}"'
+ @echo 'LIST:[6]="${LIST:[6]}"'
+ @echo 'LIST:[7]="${LIST:[7]}"'
+ @echo 'LIST:[999]="${LIST:[999]}"'
+ @echo 'LIST:[-]="${LIST:[-]}" is an error'
+ @echo 'LIST:[--]="${LIST:[--]}" is an error'
+ @echo 'LIST:[-1]="${LIST:[-1]}"'
+ @echo 'LIST:[-2]="${LIST:[-2]}"'
+ @echo 'LIST:[-6]="${LIST:[-6]}"'
+ @echo 'LIST:[-7]="${LIST:[-7]}"'
+ @echo 'LIST:[-999]="${LIST:[-999]}"'
+ @echo 'LONGLIST:[17]="${LONGLIST:[17]}"'
+ @echo 'LONGLIST:[0x11]="${LONGLIST:[0x11]}"'
+ @echo 'LONGLIST:[021]="${LONGLIST:[021]}"'
+ @echo 'LIST:[0]:[1]="${LIST:[0]:[1]}"'
+ @echo 'LIST:[*]:[1]="${LIST:[*]:[1]}"'
+ @echo 'LIST:[@]:[1]="${LIST:[@]:[1]}"'
+ @echo 'LIST:[0]:[2]="${LIST:[0]:[2]}"'
+ @echo 'LIST:[*]:[2]="${LIST:[*]:[2]}"'
+ @echo 'LIST:[@]:[2]="${LIST:[@]:[2]}"'
+ @echo 'LIST:[*]:C/ /,/:[2]="${LIST:[*]:C/ /,/:[2]}"'
+ @echo 'LIST:[*]:C/ /,/:[*]:[2]="${LIST:[*]:C/ /,/:[*]:[2]}"'
+ @echo 'LIST:[*]:C/ /,/:[@]:[2]="${LIST:[*]:C/ /,/:[@]:[2]}"'
+
+mod-squarebrackets-start-end:
+ @echo 'LIST:[1.]="${LIST:[1.]}" is an error'
+ @echo 'LIST:[1..]="${LIST:[1..]}" is an error'
+ @echo 'LIST:[1..1]="${LIST:[1..1]}"'
+ @echo 'LIST:[1..1.]="${LIST:[1..1.]}" is an error'
+ @echo 'LIST:[1..2]="${LIST:[1..2]}"'
+ @echo 'LIST:[2..1]="${LIST:[2..1]}"'
+ @echo 'LIST:[3..-2]="${LIST:[3..-2]}"'
+ @echo 'LIST:[-4..4]="${LIST:[-4..4]}"'
+ @echo 'LIST:[0..1]="${LIST:[0..1]}" is an error'
+ @echo 'LIST:[-1..0]="${LIST:[-1..0]}" is an error'
+ @echo 'LIST:[-1..1]="${LIST:[-1..1]}"'
+ @echo 'LIST:[0..0]="${LIST:[0..0]}"'
+ @echo 'LIST:[3..99]="${LIST:[3..99]}"'
+ @echo 'LIST:[-3..-99]="${LIST:[-3..-99]}"'
+ @echo 'LIST:[-99..-3]="${LIST:[-99..-3]}"'
+
+mod-squarebrackets-nested:
+ @echo 'HASH="${HASH}" == "#" ?'
+ @echo 'LIST:[$${HASH}]="${LIST:[${HASH}]}"'
+ @echo 'LIST:[$${ZERO}]="${LIST:[${ZERO}]}"'
+ @echo 'LIST:[$${ZERO}x$${ONE}]="${LIST:[${ZERO}x${ONE}]}"'
+ @echo 'LIST:[$${ONE}]="${LIST:[${ONE}]}"'
+ @echo 'LIST:[$${MINUSONE}]="${LIST:[${MINUSONE}]}"'
+ @echo 'LIST:[$${STAR}]="${LIST:[${STAR}]}"'
+ @echo 'LIST:[$${AT}]="${LIST:[${AT}]}"'
+ @echo 'LIST:[$${EMPTY}]="${LIST:[${EMPTY}]}" is an error'
+ @echo 'LIST:[$${LONGLIST:[21]:S/2//}]="${LIST:[${LONGLIST:[21]:S/2//}]}"'
+ @echo 'LIST:[$${LIST:[#]}]="${LIST:[${LIST:[#]}]}"'
+ @echo 'LIST:[$${LIST:[$${HASH}]}]="${LIST:[${LIST:[${HASH}]}]}"'
+
+mod-C-W:
+ @echo 'LIST:C/ /,/="${LIST:C/ /,/}"'
+ @echo 'LIST:C/ /,/W="${LIST:C/ /,/W}"'
+ @echo 'LIST:C/ /,/gW="${LIST:C/ /,/gW}"'
+ @echo 'EMPTY:C/^/,/="${EMPTY:C/^/,/}"'
+ @echo 'EMPTY:C/^/,/W="${EMPTY:C/^/,/W}"'
+
+mod-S-W:
+ @echo 'LIST:S/ /,/="${LIST:S/ /,/}"'
+ @echo 'LIST:S/ /,/W="${LIST:S/ /,/W}"'
+ @echo 'LIST:S/ /,/gW="${LIST:S/ /,/gW}"'
+ @echo 'EMPTY:S/^/,/="${EMPTY:S/^/,/}"'
+ @echo 'EMPTY:S/^/,/W="${EMPTY:S/^/,/W}"'
+
+mod-tW-tw:
+ @echo 'LIST:tW="${LIST:tW}"'
+ @echo 'LIST:tw="${LIST:tw}"'
+ @echo 'LIST:tW:C/ /,/="${LIST:tW:C/ /,/}"'
+ @echo 'LIST:tW:C/ /,/g="${LIST:tW:C/ /,/g}"'
+ @echo 'LIST:tW:C/ /,/1g="${LIST:tW:C/ /,/1g}"'
+ @echo 'LIST:tw:C/ /,/="${LIST:tw:C/ /,/}"'
+ @echo 'LIST:tw:C/ /,/g="${LIST:tw:C/ /,/g}"'
+ @echo 'LIST:tw:C/ /,/1g="${LIST:tw:C/ /,/1g}"'
+ @echo 'LIST:tw:tW:C/ /,/="${LIST:tw:tW:C/ /,/}"'
+ @echo 'LIST:tW:tw:C/ /,/="${LIST:tW:tw:C/ /,/}"'
diff --git a/unit-tests/order b/unit-tests/order
new file mode 100644
index 0000000..175da47
--- /dev/null
+++ b/unit-tests/order
@@ -0,0 +1,20 @@
+# $NetBSD: order,v 1.1 2012/11/09 19:08:28 sjg Exp $
+
+# Test that .ORDER is handled correctly.
+# The explicit dependency the.o: the.h will make us examine the.h
+# the .ORDER will prevent us building it immediately,
+# we should then examine the.c rather than stop.
+
+all: the.o
+
+.ORDER: the.c the.h
+
+the.c the.h:
+ @echo Making $@
+
+.SUFFIXES: .o .c
+
+.c.o:
+ @echo Making $@ from $?
+
+the.o: the.h
diff --git a/unit-tests/phony-end b/unit-tests/phony-end
new file mode 100644
index 0000000..d61884c
--- /dev/null
+++ b/unit-tests/phony-end
@@ -0,0 +1,9 @@
+# $Id: phony-end,v 1.1.1.1 2011/10/01 17:19:39 sjg Exp $
+
+all ok also.ok bug phony:
+ @echo '${.TARGET .PREFIX .IMPSRC:L:@v@$v="${$v}"@}'
+
+.END: ok also.ok bug
+
+phony bug: .PHONY
+all: phony
diff --git a/unit-tests/posix b/unit-tests/posix
new file mode 100644
index 0000000..48ed7a3
--- /dev/null
+++ b/unit-tests/posix
@@ -0,0 +1,24 @@
+# $Id: posix,v 1.1.1.1 2004/05/08 16:45:39 sjg Exp $
+
+all: x plus subs err
+
+x:
+ @echo "Posix says we should execute the command as if run by system(3)"
+ @echo "Expect 'Hello,' and 'World!'"
+ @echo Hello,; false; echo "World!"
+
+plus:
+ @echo a command
+ +@echo "a command prefixed by '+' executes even with -n"
+ @echo another command
+
+subs:
+ @echo make -n
+ @${.MAKE} -f ${MAKEFILE} -n plus
+ @echo make -n -j1
+ @${.MAKE} -f ${MAKEFILE} -n -j1 plus
+
+err:
+ @(echo Now we expect an error...; exit 1)
+ @echo "Oops! you shouldn't see this!"
+
diff --git a/unit-tests/qequals b/unit-tests/qequals
new file mode 100644
index 0000000..e23078e
--- /dev/null
+++ b/unit-tests/qequals
@@ -0,0 +1,8 @@
+# $Id: qequals,v 1.1.1.1 2008/03/31 00:13:05 sjg Exp $
+
+M= i386
+V.i386= OK
+V.$M ?= bug
+
+all:
+ @echo 'V.$M ?= ${V.$M}'
diff --git a/unit-tests/sysv b/unit-tests/sysv
new file mode 100644
index 0000000..9eedacb
--- /dev/null
+++ b/unit-tests/sysv
@@ -0,0 +1,26 @@
+# $Id: sysv,v 1.1.1.2 2011/06/05 04:23:49 sjg Exp $
+
+FOO ?=
+FOOBAR = $(FOO:=bar)
+
+_this := ${.PARSEDIR}/${.PARSEFILE}
+
+B = /b
+S = /
+FUN = ${B}${S}fun
+SUN = the Sun
+
+# we expect nothing when FOO is empty
+all: foo fun
+
+foo:
+ @echo FOOBAR = $(FOOBAR)
+.if empty(FOO)
+ @FOO="foo fu" ${.MAKE} -f ${_this} foo
+.endif
+
+fun:
+ @echo ${FUN:T}
+ @echo ${FUN:${B}${S}fun=fun}
+ @echo ${FUN:${B}${S}%=%}
+ @echo ${In:L:%=% ${SUN}}
diff --git a/unit-tests/ternary b/unit-tests/ternary
new file mode 100644
index 0000000..77f8349
--- /dev/null
+++ b/unit-tests/ternary
@@ -0,0 +1,8 @@
+
+all:
+ @for x in "" A= A=42; do ${.MAKE} -f ${MAKEFILE} show $$x; done
+
+show:
+ @echo "The answer is ${A:?known:unknown}"
+ @echo "The answer is ${A:?$A:unknown}"
+ @echo "The answer is ${empty(A):?empty:$A}"
diff --git a/unit-tests/test.exp b/unit-tests/test.exp
new file mode 100644
index 0000000..b6fad78
--- /dev/null
+++ b/unit-tests/test.exp
@@ -0,0 +1,380 @@
+comment testing start
+this is foo
+This is how a comment looks: # comment
+comment testing done
+make: "cond1" line 75: warning: extra else
+make: "cond1" line 85: warning: extra else
+2 is prime
+A='other' B='unknown' C='clever' o='no,no'
+Passed:
+ var
+ ("var")
+ (var != var)
+ var != var
+ !((var != var) && defined(name))
+ var == quoted
+
+1 is not prime
+2 is prime
+3 is prime
+4 is not prime
+5 is prime
+
+make: warning: String comparison operator should be either == or !=
+make: Bad conditional expression `"0" > 0' in "0" > 0?OK:No
+
+OK
+make: "error" line 3: just FYI
+make: "error" line 4: warning: this could be serious
+make: "error" line 5: this is fatal
+UT_DOLLAR=This is $UT_FU
+UT_FOO=foobar is fubar
+UT_FU=fubar
+UT_TEST=export
+UT_ZOO=hoopie
+UT_ALL=even this gets exported
+UT_BADDIR=unit-tests
+UT_DOLLAR=This is $UT_FU
+UT_F=fine
+UT_FOO=foobar is fubar
+UT_FU=fubar
+UT_NO=all
+UT_OK=good
+UT_OKDIR=unit-tests
+UT_TEST=export-all
+UT_ZOO=hoopie
+make:
+UT_TEST=export-env
+UT_ENV=not-exported
+UT_EXP=not-exported
+env:
+UT_TEST=export-env
+UT_ENV=exported
+UT_EXP=exported
+At first, I am
+happy
+and now: sad
+.ERROR: Looks like 'sad' is upset.
+*** Error code 1
+
+Stop.
+make: stopped in unit-tests
+simple.1
+simple.1
+simple.2
+simple.2
+recursive.1.1.*
+recursive.1.1.*
+recursive.1.1.*
+recursive.1.1.*
+recursive.1.99
+recursive.1.99
+recursive.2.1.*
+recursive.2.1.*
+recursive.2.1.*
+recursive.2.1.*
+recursive.2.99
+recursive.2.99
+shared.0
+shared.0
+shared.1.99
+shared.1.99
+shared.2.1
+shared.2.1
+shared.2.99
+shared.2.99
+make: Graph cycles through `cycle.2.99'
+make: Graph cycles through `cycle.2.98'
+make: Graph cycles through `cycle.2.97'
+cycle.1.99
+cycle.1.99
+x=one
+x="two and three"
+x=four
+x="five"
+x=-I/this
+x=-I"This or that"
+x=-Ithat
+x="-DTHIS=\"this and that\""
+cfl=-I/this -I"This or that" -Ithat "-DTHIS=\"this and that\""
+a=one b="two and three"
+a=four b="five"
+a=ONE b="TWO AND THREE"
+a=FOUR b="FIVE"
+We expect an error next:
+make: "forloop" line 38: Wrong number of words (9) in .for substitution list with 2 vars
+make: Fatal errors encountered -- cannot continue
+make: stopped in unit-tests
+OK
+.for with :S;... OK
+b2af338b
+3360ac65
+7747f046
+9ca87054
+880fe816
+208fcbd3
+d5d376eb
+de41416c
+Expect: Unknown modifier 'Z'
+make: Unknown modifier 'Z'
+VAR:Z=
+Expect: Unknown modifier 'Z'
+make: Unknown modifier 'Z'
+VAR:Z=
+Expect: Unclosed variable specification for VAR
+make: Unclosed variable specification (expecting '}') for "VAR" (value "Thevariable") modifier S
+VAR:S,V,v,=Thevariable
+Expect: Unclosed variable specification for VAR
+make: Unclosed variable specification after complex modifier (expecting '}') for VAR
+VAR:S,V,v,=Thevariable
+Expect: Unclosed substitution for VAR (, missing)
+make: Unclosed substitution for VAR (, missing)
+VAR:S,V,v=
+LIB=a X_LIBS:M${LIB${LIB:tu}} is "/tmp/liba.a"
+LIB=a X_LIBS:M*/lib${LIB}.a is "/tmp/liba.a"
+LIB=a X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBA.A"
+LIB=b X_LIBS:M${LIB${LIB:tu}} is ""
+LIB=b X_LIBS:M*/lib${LIB}.a is ""
+LIB=b X_LIBS:M*/lib${LIB}.a:tu is ""
+LIB=c X_LIBS:M${LIB${LIB:tu}} is ""
+LIB=c X_LIBS:M*/lib${LIB}.a is ""
+LIB=c X_LIBS:M*/lib${LIB}.a:tu is ""
+LIB=d X_LIBS:M${LIB${LIB:tu}} is "/tmp/libd.a"
+LIB=d X_LIBS:M*/lib${LIB}.a is "/tmp/libd.a"
+LIB=d X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBD.A"
+LIB=e X_LIBS:M${LIB${LIB:tu}} is "/tmp/libe.a"
+LIB=e X_LIBS:M*/lib${LIB}.a is "/tmp/libe.a"
+LIB=e X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBE.A"
+Mscanner=OK
+path=':/bin:/tmp::/:.:/no/such/dir:.'
+path='/bin:/tmp:/:/no/such/dir'
+path='/bin:/tmp:/:/no/such/dir'
+path='/bin':'/tmp':'/':'/no/such/dir'
+path='/bin':'/tmp':'/':'/no/such/dir'
+path_/usr/xbin=/opt/xbin/
+paths=/bin /tmp / /no/such/dir /opt/xbin
+PATHS=/BIN /TMP / /NO/SUCH/DIR /OPT/XBIN
+The answer is 42
+LIST = one two three four five six seven eight nine ten
+LIST:O = eight five four nine one seven six ten three two
+LIST:Ox = Ok
+LIST:O:Ox = Ok
+LISTX = Ok
+LISTSX = Ok
+make: Bad modifier `:OX' for LIST
+BADMOD 1 = }
+make: Bad modifier `:OxXX' for LIST
+BADMOD 2 = XX}
+LIST="one two three four five six"
+LIST:ts,="one,two,three,four,five,six"
+LIST:ts/:tu="ONE/TWO/THREE/FOUR/FIVE/SIX"
+LIST:ts::tu="ONE:TWO:THREE:FOUR:FIVE:SIX"
+LIST:ts:tu="ONETWOTHREEFOURFIVESIX"
+LIST:tu:ts/="ONE/TWO/THREE/FOUR/FIVE/SIX"
+LIST:ts:="one:two:three:four:five:six"
+LIST:ts="onetwothreefourfivesix"
+LIST:ts:S/two/2/="one2threefourfivesix"
+LIST:S/two/2/:ts="one2threefourfivesix"
+LIST:ts/:S/two/2/="one/2/three/four/five/six"
+Pretend the '/' in '/n' etc. below are back-slashes.
+LIST:ts/n="one
+two
+three
+four
+five
+six"
+LIST:ts/t="one two three four five six"
+LIST:ts/012:tu="ONE
+TWO
+THREE
+FOUR
+FIVE
+SIX"
+make: Bad modifier `:tx' for LIST
+LIST:tx="}"
+make: Bad modifier `:ts\x' for LIST
+LIST:ts/x:tu="\x:tu}"
+FU_mod-ts="a/b/cool"
+FU_mod-ts:ts:T="cool" == cool?
+B.${AAA:ts}="Baaa" == Baaa?
+make: Bad modifier `:[]' for LIST
+LIST:[]="" is an error
+LIST:[0]="one two three four five six"
+LIST:[0x0]="one two three four five six"
+LIST:[000]="one two three four five six"
+LIST:[*]="one two three four five six"
+LIST:[@]="one two three four five six"
+LIST:[0]:C/ /,/="one,two three four five six"
+LIST:[0]:C/ /,/g="one,two,three,four,five,six"
+LIST:[0]:C/ /,/1g="one,two,three,four,five,six"
+LIST:[*]:C/ /,/="one,two three four five six"
+LIST:[*]:C/ /,/g="one,two,three,four,five,six"
+LIST:[*]:C/ /,/1g="one,two,three,four,five,six"
+LIST:[@]:C/ /,/="one two three four five six"
+LIST:[@]:C/ /,/g="one two three four five six"
+LIST:[@]:C/ /,/1g="one two three four five six"
+LIST:[@]:[0]:C/ /,/="one,two three four five six"
+LIST:[0]:[@]:C/ /,/="one two three four five six"
+LIST:[@]:[*]:C/ /,/="one,two three four five six"
+LIST:[*]:[@]:C/ /,/="one two three four five six"
+EMPTY=""
+EMPTY:[#]="1" == 1 ?
+ESCAPEDSPACE="\ "
+ESCAPEDSPACE:[#]="1" == 1 ?
+REALLYSPACE=" "
+REALLYSPACE:[#]="1" == 1 ?
+LIST:[#]="6"
+LIST:[0]:[#]="1" == 1 ?
+LIST:[*]:[#]="1" == 1 ?
+LIST:[@]:[#]="6"
+LIST:[1]:[#]="1"
+LIST:[1..3]:[#]="3"
+EMPTY:[1]=""
+ESCAPEDSPACE="\ "
+ESCAPEDSPACE:[1]="\ "
+REALLYSPACE=" "
+REALLYSPACE:[1]="" == "" ?
+REALLYSPACE:[*]:[1]=" " == " " ?
+LIST:[1]="one"
+make: Bad modifier `:[1.]' for LIST
+LIST:[1.]="" is an error
+make: Bad modifier `:[1].' for LIST
+LIST:[1].="}" is an error
+LIST:[2]="two"
+LIST:[6]="six"
+LIST:[7]=""
+LIST:[999]=""
+make: Bad modifier `:[-]' for LIST
+LIST:[-]="" is an error
+make: Bad modifier `:[--]' for LIST
+LIST:[--]="" is an error
+LIST:[-1]="six"
+LIST:[-2]="five"
+LIST:[-6]="one"
+LIST:[-7]=""
+LIST:[-999]=""
+LONGLIST:[17]="17"
+LONGLIST:[0x11]="17"
+LONGLIST:[021]="17"
+LIST:[0]:[1]="one two three four five six"
+LIST:[*]:[1]="one two three four five six"
+LIST:[@]:[1]="one"
+LIST:[0]:[2]=""
+LIST:[*]:[2]=""
+LIST:[@]:[2]="two"
+LIST:[*]:C/ /,/:[2]=""
+LIST:[*]:C/ /,/:[*]:[2]=""
+LIST:[*]:C/ /,/:[@]:[2]="three"
+make: Bad modifier `:[1.]' for LIST
+LIST:[1.]="" is an error
+make: Bad modifier `:[1..]' for LIST
+LIST:[1..]="" is an error
+LIST:[1..1]="one"
+make: Bad modifier `:[1..1.]' for LIST
+LIST:[1..1.]="" is an error
+LIST:[1..2]="one two"
+LIST:[2..1]="two one"
+LIST:[3..-2]="three four five"
+LIST:[-4..4]="three four"
+make: Bad modifier `:[0..1]' for LIST
+LIST:[0..1]="" is an error
+make: Bad modifier `:[-1..0]' for LIST
+LIST:[-1..0]="" is an error
+LIST:[-1..1]="six five four three two one"
+LIST:[0..0]="one two three four five six"
+LIST:[3..99]="three four five six"
+LIST:[-3..-99]="four three two one"
+LIST:[-99..-3]="one two three four"
+HASH="#" == "#" ?
+LIST:[${HASH}]="6"
+LIST:[${ZERO}]="one two three four five six"
+LIST:[${ZERO}x${ONE}]="one"
+LIST:[${ONE}]="one"
+LIST:[${MINUSONE}]="six"
+LIST:[${STAR}]="one two three four five six"
+LIST:[${AT}]="one two three four five six"
+make: Bad modifier `:[${EMPTY' for LIST
+LIST:[${EMPTY}]="" is an error
+LIST:[${LONGLIST:[21]:S/2//}]="one"
+LIST:[${LIST:[#]}]="six"
+LIST:[${LIST:[${HASH}]}]="six"
+LIST:S/ /,/="one two three four five six"
+LIST:S/ /,/W="one,two three four five six"
+LIST:S/ /,/gW="one,two,three,four,five,six"
+EMPTY:S/^/,/=","
+EMPTY:S/^/,/W=","
+LIST:C/ /,/="one two three four five six"
+LIST:C/ /,/W="one,two three four five six"
+LIST:C/ /,/gW="one,two,three,four,five,six"
+EMPTY:C/^/,/=","
+EMPTY:C/^/,/W=","
+LIST:tW="one two three four five six"
+LIST:tw="one two three four five six"
+LIST:tW:C/ /,/="one,two three four five six"
+LIST:tW:C/ /,/g="one,two,three,four,five,six"
+LIST:tW:C/ /,/1g="one,two,three,four,five,six"
+LIST:tw:C/ /,/="one two three four five six"
+LIST:tw:C/ /,/g="one two three four five six"
+LIST:tw:C/ /,/1g="one two three four five six"
+LIST:tw:tW:C/ /,/="one,two three four five six"
+LIST:tW:tw:C/ /,/="one two three four five six"
+Making the.c
+Making the.h
+Making the.o from the.h the.c
+.TARGET="phony" .PREFIX="phony" .IMPSRC=""
+.TARGET="all" .PREFIX="all" .IMPSRC=""
+.TARGET="ok" .PREFIX="ok" .IMPSRC=""
+.TARGET="also.ok" .PREFIX="also.ok" .IMPSRC=""
+.TARGET="bug" .PREFIX="bug" .IMPSRC=""
+Posix says we should execute the command as if run by system(3)
+Expect 'Hello,' and 'World!'
+Hello,
+World!
+a command
+a command prefixed by '+' executes even with -n
+another command
+make -n
+echo a command
+echo "a command prefixed by '+' executes even with -n"
+a command prefixed by '+' executes even with -n
+echo another command
+make -n -j1
+{ echo a command
+} || exit $?
+echo "a command prefixed by '+' executes even with -n"
+a command prefixed by '+' executes even with -n
+{ echo another command
+} || exit $?
+Now we expect an error...
+*** Error code 1 (continuing)
+`all' not remade because of errors.
+V.i386 ?= OK
+FOOBAR =
+FOOBAR = foobar fubar
+fun
+fun
+fun
+In the Sun
+The answer is unknown
+The answer is unknown
+The answer is empty
+The answer is known
+The answer is
+The answer is empty
+The answer is known
+The answer is 42
+The answer is 42
+UT_DOLLAR=This is $UT_FU
+UT_FU=fubar
+UT_TEST=unexport
+UT_TEST=unexport-env
+default FU=<v>fu</v> FOO=<v>foo</v> VAR=<v></v>
+two FU=<v>bar</v> FOO=<v>goo</v> VAR=<v></v>
+three FU=<v>bar</v> FOO=<v>goo</v> VAR=<v></v>
+four FU=<v>bar</v> FOO=<v>goo</v> VAR=<v>Internal</v>
+five FU=<v>bar</v> FOO=<v>goo</v> VAR=<v>Internal</v>
+five v=is x k=is x
+six v=is y k=is y
+show-v v=override k=override
+*** Error code 1 (ignored)
+*** Error code 1 (ignored)
diff --git a/unit-tests/unexport b/unit-tests/unexport
new file mode 100644
index 0000000..fb40d0c
--- /dev/null
+++ b/unit-tests/unexport
@@ -0,0 +1,8 @@
+# $Id: unexport,v 1.1.1.1 2009/11/19 00:31:11 sjg Exp $
+
+# pick up a bunch of exported vars
+.include "export"
+
+.unexport UT_ZOO UT_FOO
+
+UT_TEST = unexport
diff --git a/unit-tests/unexport-env b/unit-tests/unexport-env
new file mode 100644
index 0000000..f6a2ff9
--- /dev/null
+++ b/unit-tests/unexport-env
@@ -0,0 +1,14 @@
+# $Id: unexport-env,v 1.1.1.1 2009/11/19 00:31:11 sjg Exp $
+
+# pick up a bunch of exported vars
+.include "export"
+
+# an example of setting up a minimal environment.
+PATH = /bin:/usr/bin:/sbin:/usr/sbin
+
+# now clobber the environment to just PATH and UT_TEST
+UT_TEST = unexport-env
+
+# this removes everything
+.unexport-env
+.export PATH UT_TEST
diff --git a/unit-tests/varcmd b/unit-tests/varcmd
new file mode 100644
index 0000000..a58e014
--- /dev/null
+++ b/unit-tests/varcmd
@@ -0,0 +1,49 @@
+# $Id: varcmd,v 1.3 2008/05/15 04:30:47 sjg Exp $
+#
+# Test behaviour of recursive make and vars set on command line.
+
+FU=fu
+FOO?=foo
+.if !empty(.TARGETS)
+TAG=${.TARGETS}
+.endif
+TAG?=default
+
+all: one
+
+show:
+ @echo "${TAG} FU=<v>${FU}</v> FOO=<v>${FOO}</v> VAR=<v>${VAR}</v>"
+
+one: show
+ @${.MAKE} -f ${MAKEFILE} FU=bar FOO=goo two
+
+two: show
+ @${.MAKE} -f ${MAKEFILE} three
+
+three: show
+ @${.MAKE} -f ${MAKEFILE} four
+
+
+.ifmake four
+VAR=Internal
+.MAKEOVERRIDES+= VAR
+.endif
+
+four: show
+ @${.MAKE} -f ${MAKEFILE} five
+
+M = x
+V.y = is y
+V.x = is x
+V := ${V.$M}
+K := ${V}
+
+show-v:
+ @echo '${TAG} v=${V} k=${K}'
+
+five: show show-v
+ @${.MAKE} -f ${MAKEFILE} M=y six
+
+six: show-v
+ @${.MAKE} -f ${MAKEFILE} V=override show-v
+