Wed Apr 29 18:33:57 2020 UTC ()
mk/subst.mk: allow identity substitutions in SUBST_NOOP_OK=no mode

There are several cases where patterns like s|man|${PKGMANDIR}| appear in
SUBST_SED.  Up to now, these had been categorized as no-ops and required
extra code to make the package build when SUBST_NOOP_OK was set to "no".

This was against the original intention of SUBST_NOOP_OK, which was to
find outdated substitution patterns that do not occur in SUBST_FILES
anymore, most often because the packages have been updated since.

The identity substitutions do appear in the files, they just don't change
them.  Typical cases are for PKGMANDIR, DEVOSSAUDIO, PREFIX, and these
variables may well be different in another pkgsrc setup.  These patterns
are therefore excluded from the SUBST_NOOP_OK check.


(rillig)
diff -r1.84 -r1.85 pkgsrc/mk/subst.mk
diff -r0 -r1.1 pkgsrc/mk/scripts/subst-identity.awk
diff -r1.25 -r1.26 pkgsrc/regress/infra-unittests/subst.sh
diff -r1.10 -r1.11 pkgsrc/regress/infra-unittests/test.subr

cvs diff -r1.84 -r1.85 pkgsrc/mk/subst.mk (switch to unified diff)

--- pkgsrc/mk/subst.mk 2020/04/23 19:32:53 1.84
+++ pkgsrc/mk/subst.mk 2020/04/29 18:33:56 1.85
@@ -1,211 +1,230 @@ @@ -1,211 +1,230 @@
1# $NetBSD: subst.mk,v 1.84 2020/04/23 19:32:53 rillig Exp $ 1# $NetBSD: subst.mk,v 1.85 2020/04/29 18:33:56 rillig Exp $
2# 2#
3# The subst framework replaces text in one or more files in the WRKSRC 3# The subst framework replaces text in one or more files in the WRKSRC
4# directory. Packages can define several ``classes'' of replacements. 4# directory. Packages can define several ``classes'' of replacements.
5# Each such class defines: 5# Each such class defines:
6# 6#
7# - in which stage of the build process the replacement happens 7# - in which stage of the build process the replacement happens
8# - which files are affected by the replacement 8# - which files are affected by the replacement
9# - which text or pattern is replaced by which replacement text 9# - which text or pattern is replaced by which replacement text
10# 10#
11# A typical example is: 11# A typical example is:
12# 12#
13# SUBST_CLASSES+= prefix 13# SUBST_CLASSES+= prefix
14# SUBST_STAGE.prefix= pre-configure 14# SUBST_STAGE.prefix= pre-configure
15# SUBST_FILES.prefix= ./configure doc/*.html 15# SUBST_FILES.prefix= ./configure doc/*.html
16# SUBST_SED.prefix= -e 's,/usr/local,${PREFIX},g' 16# SUBST_SED.prefix= -e 's,/usr/local,${PREFIX},g'
17# 17#
18# User-settable variables: 18# User-settable variables:
19# 19#
20# SUBST_SHOW_DIFF 20# SUBST_SHOW_DIFF
21# Whether to log each changed file as a unified diff, for all 21# Whether to log each changed file as a unified diff, for all
22# SUBST classes. Defaults to "no". 22# SUBST classes. Defaults to "no".
23# 23#
24# SUBST_NOOP_OK 24# SUBST_NOOP_OK
25# Whether it is ok to have filename patterns in SUBST_FILES that 25# Whether it is ok to list files in SUBST_FILES that don't contain
26# don't have any effect. 26# any of the patterns from SUBST_SED or SUBST_VARS. Such a
 27# situation often arises when a package is updated to a newer
 28# version, and the build instructions of the package have been
 29# made more portable or flexible.
 30#
 31# This setting only affects the filename patterns in SUBST_FILES.
 32# It does not (yet) affect the regular expressions in SUBST_SED.
 33#
 34# From the viewpoint of sed(1), a pattern like s|man|man| may look
 35# redundant but it really isn't, because the second "man" probably
 36# comes from ${PKGMANDIR}, which may be configured to a different
 37# directory. Patterns like these are therefore allowed, even if
 38# they are no-ops in the current configuration.
27# 39#
28# For backwards compatibility this defaults to "yes", but it 40# For backwards compatibility this defaults to "yes", but it
29# should rather be set to "no". 41# should rather be set to "no".
30# 42#
31# Package-settable variables: 43# Package-settable variables:
32# 44#
33# SUBST_CLASSES 45# SUBST_CLASSES
34# A list of class names. When adding new classes to this list, be 46# A list of class names. When adding new classes to this list, be
35# sure to append them (+=) instead of overriding them (=). 47# sure to append them (+=) instead of overriding them (=).
36# 48#
37# SUBST_STAGE.<class> 49# SUBST_STAGE.<class>
38# "stage" at which we do the text replacement. Should be one of 50# "stage" at which we do the text replacement. Should be one of
39# {pre,do,post}-{extract,configure,build,install}. 51# {pre,do,post}-{extract,configure,build,install}.
40# 52#
41# SUBST_MESSAGE.<class> 53# SUBST_MESSAGE.<class>
42# The message to display before doing the substitution. 54# The message to display before doing the substitution.
43# 55#
44# SUBST_FILES.<class> 56# SUBST_FILES.<class>
45# A list of file patterns on which to run the substitution; 57# A list of file patterns on which to run the substitution;
46# the filenames are either absolute or relative to ${WRKSRC}. 58# the filenames are either absolute or relative to ${WRKSRC}.
47# 59#
48# Starting with 2020Q1, it is an error if any of these patterns 60# Starting with 2020Q1, it is an error if any of these patterns
49# has no effect at all, to catch typos and outdated definitions. 61# has no effect at all, to catch typos and outdated definitions.
50# To prevent this, see SUBST_NOOP_OK.<class> below. 62# To prevent this, see SUBST_NOOP_OK.<class> below.
51# 63#
52# In most cases the filename patterns are given directly. 64# In most cases the filename patterns are given directly.
53# If that is not flexible enough, use the :sh variable modifier. 65# If that is not flexible enough, use the :sh variable modifier.
54# See mk/configure/replace-localedir.mk for an example. 66# See mk/configure/replace-localedir.mk for an example.
55# 67#
56# SUBST_SED.<class> 68# SUBST_SED.<class>
57# List of sed(1) arguments to run on the specified files. 69# List of sed(1) arguments to run on the specified files.
58# Multiple commands can be specified using the -e option of sed. 70# Multiple commands can be specified using the -e option of sed.
59# Do not use non-standard sed options (e.g. -E). 71# Do not use non-standard sed options (e.g. -E).
60# 72#
61# SUBST_VARS.<class> 73# SUBST_VARS.<class>
62# List of variables that are substituted whenever they appear in 74# List of variables that are substituted whenever they appear in
63# the form @VARNAME@. This is basically a shortcut for 75# the form @VARNAME@. This is basically a shortcut for
64# 76#
65# -e 's,@VARNAME@,${VARNAME},g' 77# -e 's,@VARNAME@,${VARNAME},g'
66# 78#
67# that even works when ${VARNAME} contains arbitrary characters. 79# that even works when ${VARNAME} contains arbitrary characters.
68# SUBST_SED and SUBST_VARS can be combined freely. 80# SUBST_SED and SUBST_VARS can be combined freely.
69# 81#
70# SUBST_FILTER_CMD.<class> 82# SUBST_FILTER_CMD.<class>
71# Filter used to perform the actual substitution on the specified 83# Filter used to perform the actual substitution on the specified
72# files. Defaults to ${SED} ${SUBST_SED.<class>}. 84# files. Defaults to ${SED} ${SUBST_SED.<class>}.
73# 85#
74# SUBST_SKIP_TEXT_CHECK.<class> 86# SUBST_SKIP_TEXT_CHECK.<class>
75# By default, each file is checked whether it really is a text file 87# By default, each file is checked whether it really is a text file
76# before any substitutions are done to it. Since that test is not 88# before any substitutions are done to it. Since that test is not
77# perfect, it can be disabled by setting this variable to "yes". 89# perfect, it can be disabled by setting this variable to "yes".
78# 90#
79# SUBST_SHOW_DIFF.<class> 91# SUBST_SHOW_DIFF.<class>
80# During development of a package, this can be set to "yes" to see 92# During development of a package, this can be set to "yes" to see
81# the actual changes as a unified diff. 93# the actual changes as a unified diff.
82# 94#
83# SUBST_NOOP_OK.<class> 95# SUBST_NOOP_OK.<class>
84# Whether to fail when a SUBST_FILES pattern has no effect. 96# Whether to fail when a SUBST_FILES pattern has no effect.
85# In most cases, "yes" is appropriate, to catch typos and outdated 97# In most cases, "yes" is appropriate, to catch typos and outdated
86# definitions. 98# definitions.
87# 99#
88# Default: no (up to 2019Q4), yes (starting with 2020Q1) 100# Default: no (up to 2019Q4), yes (starting with 2020Q1)
89# 101#
90# See also: 102# See also:
91# PLIST_SUBST 103# PLIST_SUBST
92# 104#
93# Keywords: subst 105# Keywords: subst
94# 106#
95 107
96SUBST_SHOW_DIFF?= no 108SUBST_SHOW_DIFF?= no
97SUBST_NOOP_OK?= yes # only for backwards compatiblity 109SUBST_NOOP_OK?= yes # only for backwards compatibility
98 110
99_VARGROUPS+= subst 111_VARGROUPS+= subst
100_USER_VARS.subst= SUBST_SHOW_DIFF SUBST_NOOP_OK 112_USER_VARS.subst= SUBST_SHOW_DIFF SUBST_NOOP_OK
101_PKG_VARS.subst= SUBST_CLASSES 113_PKG_VARS.subst= SUBST_CLASSES
102.for c in ${SUBST_CLASSES} 114.for c in ${SUBST_CLASSES}
103. for pv in SUBST_STAGE SUBST_MESSAGE SUBST_FILES SUBST_SED SUBST_VARS \ 115. for pv in SUBST_STAGE SUBST_MESSAGE SUBST_FILES SUBST_SED SUBST_VARS \
104 SUBST_FILTER_CMD SUBST_SKIP_TEXT_CHECK SUBST_NOOP_OK 116 SUBST_FILTER_CMD SUBST_SKIP_TEXT_CHECK SUBST_NOOP_OK
105_PKG_VARS.subst+= ${pv}.${c} 117_PKG_VARS.subst+= ${pv}.${c}
106. endfor 118. endfor
107.endfor 119.endfor
108_DEF_VARS.subst= ECHO_SUBST_MSG 120_DEF_VARS.subst= ECHO_SUBST_MSG
109_USE_VARS.subst= WRKDIR WRKSRC 121_USE_VARS.subst= WRKDIR WRKSRC
110_IGN_VARS.subst= _SUBST_IS_TEXT_FILE_CMD 122_IGN_VARS.subst= _SUBST_IS_TEXT_FILE_CMD
111_SORTED_VARS.subst= SUBST_CLASSES SUBST_FILES.* SUBST_VARS.* 123_SORTED_VARS.subst= SUBST_CLASSES SUBST_FILES.* SUBST_VARS.*
112_LISTED_VARS.subst= SUBST_SED.* SUBST_FILTER_CMD.* 124_LISTED_VARS.subst= SUBST_SED.* SUBST_FILTER_CMD.*
113 125
114ECHO_SUBST_MSG?= ${STEP_MSG} 126ECHO_SUBST_MSG?= ${STEP_MSG}
115 127
116# _SUBST_IS_TEXT_FILE_CMD exits successfully if $$file is a text file. 128# _SUBST_IS_TEXT_FILE_CMD exits successfully if $$file is a text file.
117_SUBST_IS_TEXT_FILE_CMD= \ 129_SUBST_IS_TEXT_FILE_CMD= \
118 [ -z "`LC_ALL=C ${TR} -cd '\\0' < \"$$file\" | ${TR} '\\0' 'x'`" ] 130 [ -z "`LC_ALL=C ${TR} -cd '\\0' < \"$$file\" | ${TR} '\\0' 'x'`" ]
119 131
120.if ${SUBST_CLASSES:U:O} != ${SUBST_CLASSES:U:O:u} 132.if ${SUBST_CLASSES:U:O} != ${SUBST_CLASSES:U:O:u}
121PKG_FAIL_REASON+= "[subst.mk] duplicate SUBST class in: ${SUBST_CLASSES:O}" 133PKG_FAIL_REASON+= "[subst.mk] duplicate SUBST class in: ${SUBST_CLASSES:O}"
122.endif 134.endif
123 135
124.for class in ${SUBST_CLASSES:O:u} 136.for class in ${SUBST_CLASSES:O:u}
125_SUBST_COOKIE.${class}= ${WRKDIR}/.subst_${class}_done 137_SUBST_COOKIE.${class}= ${WRKDIR}/.subst_${class}_done
126 138
127SUBST_FILTER_CMD.${class}?= LC_ALL=C ${SED} ${SUBST_SED.${class}} 139SUBST_FILTER_CMD.${class}?= LC_ALL=C ${SED} ${SUBST_SED.${class}}
128SUBST_VARS.${class}?= # none 140SUBST_VARS.${class}?= # none
129SUBST_MESSAGE.${class}?= Substituting "${class}" in ${SUBST_FILES.${class}} 141SUBST_MESSAGE.${class}?= Substituting "${class}" in ${SUBST_FILES.${class}}
130. for v in ${SUBST_VARS.${class}} 142. for v in ${SUBST_VARS.${class}}
131SUBST_FILTER_CMD.${class}+= -e s,@${v:C|[.[\\*^]|\\\\&|gW:Q}@,${${v}:S|\\|\\\\|gW:S|,|\\,|gW:S|&|\\\&|gW:S|${.newline}|\\${.newline}|gW:Q},g 143SUBST_FILTER_CMD.${class}+= -e s,@${v:C|[.[\\*^]|\\\\&|gW:Q}@,${${v}:S|\\|\\\\|gW:S|,|\\,|gW:S|&|\\\&|gW:S|${.newline}|\\${.newline}|gW:Q},g
132. endfor 144. endfor
133. if ${SUBST_SHOW_DIFF.${class}:U${SUBST_SHOW_DIFF}:tl} == yes 145. if ${SUBST_SHOW_DIFF.${class}:U${SUBST_SHOW_DIFF}:tl} == yes
134_SUBST_KEEP.${class}?= LC_ALL=C ${DIFF} -u "$$file" "$$tmpfile" || true 146_SUBST_KEEP.${class}?= LC_ALL=C ${DIFF} -u "$$file" "$$tmpfile" || true
135. endif 147. endif
136_SUBST_KEEP.${class}?= ${DO_NADA} 148_SUBST_KEEP.${class}?= ${DO_NADA}
137SUBST_SKIP_TEXT_CHECK.${class}?= \ 149SUBST_SKIP_TEXT_CHECK.${class}?= \
138 no 150 no
139SUBST_NOOP_OK.${class}?= ${SUBST_NOOP_OK} 151SUBST_NOOP_OK.${class}?= ${SUBST_NOOP_OK}
140_SUBST_WARN.${class}= ${${SUBST_NOOP_OK.${class}:tl} == yes:?${INFO_MSG}:${WARNING_MSG}} "[subst.mk:${class}]" 152_SUBST_WARN.${class}= ${${SUBST_NOOP_OK.${class}:tl} == yes:?${INFO_MSG}:${WARNING_MSG}} "[subst.mk:${class}]"
141 153
142. if !empty(SUBST_SKIP_TEXT_CHECK.${class}:M[Yy][Ee][Ss]) 154. if !empty(SUBST_SKIP_TEXT_CHECK.${class}:M[Yy][Ee][Ss])
143_SUBST_IS_TEXT_FILE_CMD.${class}= ${TRUE} 155_SUBST_IS_TEXT_FILE_CMD.${class}= ${TRUE}
144. else 156. else
145_SUBST_IS_TEXT_FILE_CMD.${class}= ${_SUBST_IS_TEXT_FILE_CMD} 157_SUBST_IS_TEXT_FILE_CMD.${class}= ${_SUBST_IS_TEXT_FILE_CMD}
146. endif 158. endif
147 159
148. if defined(SUBST_STAGE.${class}) 160. if defined(SUBST_STAGE.${class})
149${SUBST_STAGE.${class}}: subst-${class} 161${SUBST_STAGE.${class}}: subst-${class}
150. else 162. else
151# SUBST_STAGE.* does not need to be defined. 163# SUBST_STAGE.* does not need to be defined.
152#PKG_FAIL_REASON+= "SUBST_STAGE missing for ${class}." 164#PKG_FAIL_REASON+= "SUBST_STAGE missing for ${class}."
153. endif 165. endif
154 166
155.PHONY: subst-${class} 167.PHONY: subst-${class}
156subst-${class}: ${_SUBST_COOKIE.${class}} 168subst-${class}: ${_SUBST_COOKIE.${class}}
157 169
158${_SUBST_COOKIE.${class}}: 170${_SUBST_COOKIE.${class}}:
159 ${RUN} set -u; \ 171 ${RUN} set -u; \
160 message=${SUBST_MESSAGE.${class}:Q}; \ 172 message=${SUBST_MESSAGE.${class}:Q}; \
161 [ "$$message" ] && ${ECHO_SUBST_MSG} "$$message"; \ 173 [ "$$message" ] && ${ECHO_SUBST_MSG} "$$message"; \
162 \ 174 \
163 cd ${WRKSRC}; \ 175 cd ${WRKSRC}; \
164 patterns=${SUBST_FILES.${class}:Q}; \ 176 patterns=${SUBST_FILES.${class}:Q}; \
165 set -f; \ 177 set -f; \
166 noop_count=''; \ 178 noop_count=''; \
167 noop_patterns=''; \ 179 noop_patterns=''; \
168 noop_sep=''; \ 180 noop_sep=''; \
169 for pattern in $$patterns; do \ 181 for pattern in $$patterns; do \
170 set +f; \ 182 set +f; \
171 changed=no; \ 183 changed=no; \
172 for file in $$pattern; do \ 184 for file in $$pattern; do \
173 case $$file in ([!A-Za-z0-9/]*) file="./$$file";; esac; \ 185 case $$file in ([!A-Za-z0-9/]*) file="./$$file";; esac; \
174 tmpfile="$$file.subst.sav"; \ 186 tmpfile="$$file.subst.sav"; \
175 [ -d "$$file" ] && continue; \ 187 [ -d "$$file" ] && continue; \
176 [ -f "$$file" ] || { \ 188 [ -f "$$file" ] || { \
177 ${_SUBST_WARN.${class}} "Ignoring non-existent file \"$$file\"."; \ 189 ${_SUBST_WARN.${class}} "Ignoring non-existent file \"$$file\"."; \
178 continue; \ 190 continue; \
179 }; \ 191 }; \
180 ${_SUBST_IS_TEXT_FILE_CMD.${class}} || { \ 192 ${_SUBST_IS_TEXT_FILE_CMD.${class}} || { \
181 ${_SUBST_WARN.${class}} "Ignoring non-text file \"$$file\"."; \ 193 ${_SUBST_WARN.${class}} "Ignoring non-text file \"$$file\"."; \
182 continue; \ 194 continue; \
183 }; \ 195 }; \
184 ${SUBST_FILTER_CMD.${class}} < "$$file" > "$$tmpfile"; \ 196 ${SUBST_FILTER_CMD.${class}} < "$$file" > "$$tmpfile"; \
185 ${CMP} -s "$$tmpfile" "$$file" && { \ 197 ${CMP} -s "$$tmpfile" "$$file" && { \
 198 [ ${"${SUBST_FILTER_CMD.${class}}" == "LC_ALL=C ${SED} ${SUBST_SED.${class}}":?true:false} ] \
 199 && ${AWK} -f ${PKGSRCDIR}/mk/scripts/subst-identity.awk -- ${SUBST_SED.${class}} \
 200 && found=`LC_ALL=C ${SED} -n ${SUBST_SED.${class}:C,^['"]?s.*,&p,} "$$file"` \
 201 && [ "x$$found" != "x" ] && { \
 202 changed=yes; \
 203 continue; \
 204 }; \
186 ${_SUBST_WARN.${class}} "Nothing changed in \"$$file\"."; \ 205 ${_SUBST_WARN.${class}} "Nothing changed in \"$$file\"."; \
187 ${RM} -f "$$tmpfile"; \ 206 ${RM} -f "$$tmpfile"; \
188 continue; \ 207 continue; \
189 }; \ 208 }; \
190 [ -x "$$file" ] && ${CHMOD} +x "$$tmpfile"; \ 209 [ -x "$$file" ] && ${CHMOD} +x "$$tmpfile"; \
191 changed=yes; \ 210 changed=yes; \
192 ${_SUBST_KEEP.${class}}; \ 211 ${_SUBST_KEEP.${class}}; \
193 ${MV} -f "$$tmpfile" "$$file"; \ 212 ${MV} -f "$$tmpfile" "$$file"; \
194 ${ECHO} "$$file" >> ${.TARGET}.tmp; \ 213 ${ECHO} "$$file" >> ${.TARGET}.tmp; \
195 done; \ 214 done; \
196 \ 215 \
197 [ "$$changed,${SUBST_NOOP_OK.${class}:tl}" = no,no ] && { \ 216 [ "$$changed,${SUBST_NOOP_OK.${class}:tl}" = no,no ] && { \
198 noop_count="$$noop_count+"; \ 217 noop_count="$$noop_count+"; \
199 noop_patterns="$$noop_patterns$$noop_sep$$pattern"; \ 218 noop_patterns="$$noop_patterns$$noop_sep$$pattern"; \
200 noop_sep=" "; \ 219 noop_sep=" "; \
201 }; \ 220 }; \
202 done; \ 221 done; \
203 \ 222 \
204 case $$noop_count in \ 223 case $$noop_count in \
205 ('') ;; \ 224 ('') ;; \
206 (+) ${FAIL_MSG} "[subst.mk:${class}] The filename pattern \"$$noop_patterns\" has no effect.";; \ 225 (+) ${FAIL_MSG} "[subst.mk:${class}] The filename pattern \"$$noop_patterns\" has no effect.";; \
207 (*) ${FAIL_MSG} "[subst.mk:${class}] The filename patterns \"$$noop_patterns\" have no effect."; \ 226 (*) ${FAIL_MSG} "[subst.mk:${class}] The filename patterns \"$$noop_patterns\" have no effect."; \
208 esac; \ 227 esac; \
209 ${TOUCH} ${TOUCH_FLAGS} ${.TARGET}.tmp; \ 228 ${TOUCH} ${TOUCH_FLAGS} ${.TARGET}.tmp; \
210 ${MV} ${.TARGET}.tmp ${.TARGET} 229 ${MV} ${.TARGET}.tmp ${.TARGET}
211.endfor 230.endfor

File Added: pkgsrc/mk/scripts/subst-identity.awk
#! /usr/bin/awk -f
# $NetBSD: subst-identity.awk,v 1.1 2020/04/29 18:33:57 rillig Exp $
#
# Tests whether a sed(1) command line consists of only identity substitutions
# like s,id,id,.
#
# See SUBST_NOOP_OK and regress/infra-unittests/subst.sh.
#

function is_safe_char(ch) {
	return ch ~ /[\t -~]/ && ch !~ /[$&*.\[\\\]^]/;
}

function is_identity_subst(s,   len, i, sep, pat) {
	len = length(s);
	if (len < 6 || substr(s, 1, 1) != "s")
		return 0;

	sep = substr(s, 2, 1);
	i = 3;
	while (i < len && substr(s, i, 1) != sep && is_safe_char(substr(s, i, 1)))
		i++;
	pat = substr(s, 3, i - 3);

	return (s == "s" sep pat sep pat sep ||
		s == "s" sep pat sep pat sep "g");
}

function main(   i) {
	for (i = 1; i + 1 < ARGC; i += 2)
		if (ARGV[i] != "-e" || !is_identity_subst(ARGV[i + 1]))
			return 0;
	return i == ARGC && ARGC > 1;
}

BEGIN {
	exit(main() ? 0 : 1);
}

cvs diff -r1.25 -r1.26 pkgsrc/regress/infra-unittests/subst.sh (switch to unified diff)

--- pkgsrc/regress/infra-unittests/subst.sh 2020/04/26 12:46:33 1.25
+++ pkgsrc/regress/infra-unittests/subst.sh 2020/04/29 18:33:56 1.26
@@ -1,1133 +1,1331 @@ @@ -1,1133 +1,1331 @@
1#! /bin/sh 1#! /bin/sh
2# $NetBSD: subst.sh,v 1.25 2020/04/26 12:46:33 rillig Exp $ 2# $NetBSD: subst.sh,v 1.26 2020/04/29 18:33:56 rillig Exp $
3# 3#
4# Tests for mk/subst.mk. 4# Tests for mk/subst.mk.
5# 5#
6 6
7set -eu 7set -eu
8 8
9. "./test.subr" 9. "./test.subr"
10 10
11test_case_set_up() { 11test_case_set_up() {
12 rm -rf "$tmpdir"/.??* "$tmpdir"/* 12 rm -rf "$tmpdir"/.??* "$tmpdir"/*
13 13
14 create_file "prepare-subst.mk" <<EOF 14 create_file "prepare-subst.mk" <<EOF
15 15
16# The tools that are used by subst.mk 16# The tools that are used by subst.mk
 17AWK= awk
17CHMOD= chmod 18CHMOD= chmod
18CMP= cmp 19CMP= cmp
19DIFF= diff 20DIFF= diff
20ECHO= echo 21ECHO= echo
21MKDIR= mkdir -p 22MKDIR= mkdir -p
22MV= mv 23MV= mv
23RM= rm 24RM= rm
24RMDIR= rmdir 25RMDIR= rmdir
25SED= sed 26SED= sed
26TEST= test 27TEST= test
27TOUCH= touch 28TOUCH= touch
28TOUCH_FLAGS= # none 29TOUCH_FLAGS= # none
29TR= tr 30TR= tr
30TRUE= true 31TRUE= true
31 32
32# Commands that are specific to pkgsrc 33# Commands that are specific to pkgsrc
33RUN= @set -e; 34RUN= @set -e;
34STEP_MSG= echo "=>" 35STEP_MSG= echo "=>"
35DO_NADA= : do-nada 36DO_NADA= : do-nada
36INFO_MSG= echo "info:" 37INFO_MSG= echo "info:"
37WARNING_MSG= echo "warning:" 38WARNING_MSG= echo "warning:"
38FAIL_MSG= sh $pkgsrcdir/mk/scripts/fail echo "fail:" 39FAIL_MSG= sh $pkgsrcdir/mk/scripts/fail echo "fail:"
39 40
40WRKDIR= $tmpdir 41WRKDIR= $tmpdir
41WRKSRC= $tmpdir 42WRKSRC= $tmpdir
42EOF 43EOF
43} 44}
44 45
45 46
46if test_case_begin "single file"; then 47if test_case_begin "single file"; then
47 48
48 # A single file is patched successfully. 49 # A single file is patched successfully.
49 50
50 create_file "subst-single.mk" <<EOF 51 create_file "subst-single.mk" <<EOF
51SUBST_CLASSES+= class 52SUBST_CLASSES+= class
52SUBST_STAGE.class= pre-configure 53SUBST_STAGE.class= pre-configure
53SUBST_FILES.class= subst-single.txt 54SUBST_FILES.class= subst-single.txt
54SUBST_SED.class= -e 's,before,after,' 55SUBST_SED.class= -e 's,before,after,'
55 56
56.include "prepare-subst.mk" 57.include "prepare-subst.mk"
57.include "mk/subst.mk" 58.include "mk/subst.mk"
58 59
59all: subst-class 60all: subst-class
60EOF 61EOF
61 62
62 create_file_lines "subst-single.txt" \ 63 create_file_lines "subst-single.txt" \
63 "before" 64 "before"
64 65
65 run_bmake "subst-single.mk" > "$tmpdir/output" 66 run_bmake "subst-single.mk" > "$tmpdir/output"
66 67
67 assert_that "output" --file-contains-exactly "=> Substituting \"class\" in subst-single.txt" 68 assert_that "output" --file-contains-exactly "=> Substituting \"class\" in subst-single.txt"
68 assert_that "subst-single.txt" --file-contains-exactly "after" 69 assert_that "subst-single.txt" --file-contains-exactly "after"
69 70
70 test_case_end 71 test_case_end
71fi 72fi
72 73
73 74
74if test_case_begin "several individual files"; then 75if test_case_begin "several individual files"; then
75 76
76 # Several individual files are patched successfully. 77 # Several individual files are patched successfully.
77 78
78 create_file "testcase.mk" <<EOF 79 create_file "testcase.mk" <<EOF
79SUBST_CLASSES+= class 80SUBST_CLASSES+= class
80SUBST_STAGE.class= pre-configure 81SUBST_STAGE.class= pre-configure
81SUBST_FILES.class= first second third 82SUBST_FILES.class= first second third
82SUBST_SED.class= -e 's,file,example,' 83SUBST_SED.class= -e 's,file,example,'
83 84
84.include "prepare-subst.mk" 85.include "prepare-subst.mk"
85.include "mk/subst.mk" 86.include "mk/subst.mk"
86 87
87all: subst-class 88all: subst-class
88EOF 89EOF
89 90
90 create_file_lines "first" "the first file" 91 create_file_lines "first" "the first file"
91 create_file_lines "second" "the second file" 92 create_file_lines "second" "the second file"
92 create_file_lines "third" "the third file" 93 create_file_lines "third" "the third file"
93 94
94 output=$(run_bmake "testcase.mk") 95 output=$(run_bmake "testcase.mk")
95 96
96 assert_that "$output" --equals "=> Substituting \"class\" in first second third" 97 assert_that "$output" --equals "=> Substituting \"class\" in first second third"
97 assert_that "first" --file-contains-exactly "the first example" 98 assert_that "first" --file-contains-exactly "the first example"
98 assert_that "second" --file-contains-exactly "the second example" 99 assert_that "second" --file-contains-exactly "the second example"
99 assert_that "third" --file-contains-exactly "the third example" 100 assert_that "third" --file-contains-exactly "the third example"
100 101
101 test_case_end 102 test_case_end
102fi 103fi
103 104
104 105
105if test_case_begin "several files by pattern"; then 106if test_case_begin "several files by pattern"; then
106 107
107 # Several files are patched successfully. 108 # Several files are patched successfully.
108 # The filenames are given by a pattern. 109 # The filenames are given by a pattern.
109 110
110 create_file "testcase.mk" <<EOF 111 create_file "testcase.mk" <<EOF
111SUBST_CLASSES+= class 112SUBST_CLASSES+= class
112SUBST_STAGE.class= pre-configure 113SUBST_STAGE.class= pre-configure
113SUBST_FILES.class= pattern-* 114SUBST_FILES.class= pattern-*
114SUBST_SED.class= -e 's,file,example,' 115SUBST_SED.class= -e 's,file,example,'
115 116
116.include "prepare-subst.mk" 117.include "prepare-subst.mk"
117.include "mk/subst.mk" 118.include "mk/subst.mk"
118 119
119all: subst-class 120all: subst-class
120EOF 121EOF
121 122
122 create_file_lines "pattern-first" "the first file" 123 create_file_lines "pattern-first" "the first file"
123 create_file_lines "pattern-second" "the second file" 124 create_file_lines "pattern-second" "the second file"
124 create_file_lines "pattern-third" "the third file" 125 create_file_lines "pattern-third" "the third file"
125 126
126 output=$(run_bmake "testcase.mk") 127 output=$(run_bmake "testcase.mk")
127 128
128 assert_that "$output" --equals "=> Substituting \"class\" in pattern-*" 129 assert_that "$output" --equals "=> Substituting \"class\" in pattern-*"
129 assert_that "pattern-first" --file-contains-exactly "the first example" 130 assert_that "pattern-first" --file-contains-exactly "the first example"
130 assert_that "pattern-second" --file-contains-exactly "the second example" 131 assert_that "pattern-second" --file-contains-exactly "the second example"
131 assert_that "pattern-third" --file-contains-exactly "the third example" 132 assert_that "pattern-third" --file-contains-exactly "the third example"
132 133
133 test_case_end 134 test_case_end
134fi 135fi
135 136
136 137
137if test_case_begin "pattern with 1 noop"; then 138if test_case_begin "pattern with 1 noop"; then
138 139
139 # Several files are given via a pattern. 140 # Several files are given via a pattern.
140 # Most of the files are patched, but one stays the same. 141 # Most of the files are patched, but one stays the same.
141 # Since it is easier to give a too broad pattern like *.py 142 # Since it is easier to give a too broad pattern like *.py
142 # than to exclude a few files from such a pattern, 143 # than to exclude a few files from such a pattern,
143 # only an info is logged. 144 # only an info is logged.
144 # This is not an error. 145 # This is not an error.
145 146
146 create_file "testcase.mk" <<EOF 147 create_file "testcase.mk" <<EOF
147SUBST_CLASSES+= class 148SUBST_CLASSES+= class
148SUBST_STAGE.class= pre-configure 149SUBST_STAGE.class= pre-configure
149SUBST_FILES.class= pattern-* 150SUBST_FILES.class= pattern-*
150SUBST_SED.class= -e 's,file,example,' 151SUBST_SED.class= -e 's,file,example,'
151 152
152.include "prepare-subst.mk" 153.include "prepare-subst.mk"
153.include "mk/subst.mk" 154.include "mk/subst.mk"
154 155
155all: subst-class 156all: subst-class
156EOF 157EOF
157 158
158 create_file_lines "pattern-first" "the first file" 159 create_file_lines "pattern-first" "the first file"
159 create_file_lines "pattern-second" "the second is already an example" 160 create_file_lines "pattern-second" "the second is already an example"
160 create_file_lines "pattern-third" "the third file" 161 create_file_lines "pattern-third" "the third file"
161 162
162 run_bmake "testcase.mk" > "$tmpdir/actual-output" 163 run_bmake "testcase.mk" > "$tmpdir/actual-output"
163 create_file_lines "expected-output" \ 164 create_file_lines "expected-output" \
164 '=> Substituting "class" in pattern-*' \ 165 '=> Substituting "class" in pattern-*' \
165 'info: [subst.mk:class] Nothing changed in "pattern-second".' 166 'info: [subst.mk:class] Nothing changed in "pattern-second".'
166 167
167 assert_that "actual-output" --file-equals "expected-output" 168 assert_that "actual-output" --file-equals "expected-output"
168 assert_that "pattern-first" --file-contains-exactly "the first example" 169 assert_that "pattern-first" --file-contains-exactly "the first example"
169 assert_that "pattern-second" --file-contains-exactly "the second is already an example" 170 assert_that "pattern-second" --file-contains-exactly "the second is already an example"
170 assert_that "pattern-third" --file-contains-exactly "the third example" 171 assert_that "pattern-third" --file-contains-exactly "the third example"
171 172
172 test_case_end 173 test_case_end
173fi 174fi
174 175
175 176
176if test_case_begin "single file noop, noop_ok=yes"; then 177if test_case_begin "single file noop, noop_ok=yes"; then
177 178
178 create_file "testcase.mk" <<EOF 179 create_file "testcase.mk" <<EOF
179SUBST_CLASSES+= class 180SUBST_CLASSES+= class
180SUBST_STAGE.class= pre-configure 181SUBST_STAGE.class= pre-configure
181SUBST_FILES.class= single 182SUBST_FILES.class= single
182SUBST_SED.class= -e 's,file,example,' 183SUBST_SED.class= -e 's,file,example,'
183SUBST_NOOP_OK.class= yes 184SUBST_NOOP_OK.class= yes
184 185
185.include "prepare-subst.mk" 186.include "prepare-subst.mk"
186.include "mk/subst.mk" 187.include "mk/subst.mk"
187 188
188all: subst-class 189all: subst-class
189EOF 190EOF
190 191
191 create_file_lines "single" "already an example" 192 create_file_lines "single" "already an example"
192 193
193 run_bmake "testcase.mk" > "$tmpdir/actual-output" && exitcode=0 || exitcode=$? 194 run_bmake "testcase.mk" > "$tmpdir/actual-output" && exitcode=0 || exitcode=$?
194 195
195 create_file_lines "expected-output" \ 196 create_file_lines "expected-output" \
196 '=> Substituting "class" in single' \ 197 '=> Substituting "class" in single' \
197 'info: [subst.mk:class] Nothing changed in "single".' 198 'info: [subst.mk:class] Nothing changed in "single".'
198 assert_that "actual-output" --file-equals "expected-output" 199 assert_that "actual-output" --file-equals "expected-output"
199 assert_that "single" --file-contains-exactly "already an example" 200 assert_that "single" --file-contains-exactly "already an example"
200 assert_that "$exitcode" --equals "0" 201 assert_that "$exitcode" --equals "0"
201 202
202 test_case_end 203 test_case_end
203fi 204fi
204 205
205 206
206if test_case_begin "single file noop, noop_ok=no"; then 207if test_case_begin "single file noop, noop_ok=no"; then
207 208
208 create_file "testcase.mk" <<EOF 209 create_file "testcase.mk" <<EOF
209SUBST_CLASSES+= class 210SUBST_CLASSES+= class
210SUBST_STAGE.class= pre-configure 211SUBST_STAGE.class= pre-configure
211SUBST_FILES.class= single 212SUBST_FILES.class= single
212SUBST_SED.class= -e 's,file,example,' 213SUBST_SED.class= -e 's,file,example,'
213SUBST_NOOP_OK.class= no 214SUBST_NOOP_OK.class= no
214 215
215.include "prepare-subst.mk" 216.include "prepare-subst.mk"
216.include "mk/subst.mk" 217.include "mk/subst.mk"
217 218
218all: subst-class 219all: subst-class
219EOF 220EOF
220 221
221 create_file_lines "single" "already an example" 222 create_file_lines "single" "already an example"
222 223
223 run_bmake "testcase.mk" > "$tmpdir/actual-output" && exitcode=0 || exitcode=$? 224 run_bmake "testcase.mk" > "$tmpdir/actual-output" && exitcode=0 || exitcode=$?
224 225
225 create_file_lines "expected-output" \ 226 create_file_lines "expected-output" \
226 '=> Substituting "class" in single' \ 227 '=> Substituting "class" in single' \
227 'warning: [subst.mk:class] Nothing changed in "single".' \ 228 'warning: [subst.mk:class] Nothing changed in "single".' \
228 'fail: [subst.mk:class] The filename pattern "single" has no effect.' \ 229 'fail: [subst.mk:class] The filename pattern "single" has no effect.' \
229 '*** Error code 1' \ 230 '*** Error code 1' \
230 '' \ 231 '' \
231 'Stop.' \ 232 'Stop.' \
232 "$make: stopped in $PWD" 233 "$make: stopped in $PWD"
233 assert_that "actual-output" --file-equals "expected-output" 234 assert_that "actual-output" --file-equals "expected-output"
234 assert_that "single" --file-contains-exactly "already an example" 235 assert_that "single" --file-contains-exactly "already an example"
235 assert_that "$exitcode" --equals "1" 236 assert_that "$exitcode" --equals "1"
236 237
237 test_case_end 238 test_case_end
238fi 239fi
239 240
240 241
241if test_case_begin "single file nonexistent"; then 242if test_case_begin "single file nonexistent"; then
242 243
243 create_file "testcase.mk" <<EOF 244 create_file "testcase.mk" <<EOF
244SUBST_CLASSES+= class 245SUBST_CLASSES+= class
245SUBST_STAGE.class= pre-configure 246SUBST_STAGE.class= pre-configure
246SUBST_FILES.class= nonexistent 247SUBST_FILES.class= nonexistent
247SUBST_SED.class= -e 's,file,example,' 248SUBST_SED.class= -e 's,file,example,'
248SUBST_NOOP_OK.class= no 249SUBST_NOOP_OK.class= no
249 250
250.include "prepare-subst.mk" 251.include "prepare-subst.mk"
251.include "mk/subst.mk" 252.include "mk/subst.mk"
252 253
253all: subst-class 254all: subst-class
254EOF 255EOF
255 256
256 run_bmake "testcase.mk" > "$tmpdir/actual-output" && exitcode=0 || exitcode=$? 257 run_bmake "testcase.mk" > "$tmpdir/actual-output" && exitcode=0 || exitcode=$?
257 258
258 create_file_lines "expected-output" \ 259 create_file_lines "expected-output" \
259 '=> Substituting "class" in nonexistent' \ 260 '=> Substituting "class" in nonexistent' \
260 'warning: [subst.mk:class] Ignoring non-existent file "nonexistent".' \ 261 'warning: [subst.mk:class] Ignoring non-existent file "nonexistent".' \
261 'fail: [subst.mk:class] The filename pattern "nonexistent" has no effect.' \ 262 'fail: [subst.mk:class] The filename pattern "nonexistent" has no effect.' \
262 '*** Error code 1' \ 263 '*** Error code 1' \
263 '' \ 264 '' \
264 'Stop.' \ 265 'Stop.' \
265 "$make: stopped in $PWD" 266 "$make: stopped in $PWD"
266 assert_that "actual-output" --file-equals "expected-output" 267 assert_that "actual-output" --file-equals "expected-output"
267 assert_that "$exitcode" --equals "1" 268 assert_that "$exitcode" --equals "1"
268 269
269 test_case_end 270 test_case_end
270fi 271fi
271 272
272 273
273if test_case_begin "single file nonexistent ok"; then 274if test_case_begin "single file nonexistent ok"; then
274 275
275 create_file "testcase.mk" <<EOF 276 create_file "testcase.mk" <<EOF
276SUBST_CLASSES+= class 277SUBST_CLASSES+= class
277SUBST_STAGE.class= pre-configure 278SUBST_STAGE.class= pre-configure
278SUBST_FILES.class= nonexistent 279SUBST_FILES.class= nonexistent
279SUBST_SED.class= -e 's,file,example,' 280SUBST_SED.class= -e 's,file,example,'
280SUBST_NOOP_OK.class= yes 281SUBST_NOOP_OK.class= yes
281 282
282.include "prepare-subst.mk" 283.include "prepare-subst.mk"
283.include "mk/subst.mk" 284.include "mk/subst.mk"
284 285
285all: subst-class 286all: subst-class
286EOF 287EOF
287 288
288 run_bmake "testcase.mk" > "$tmpdir/actual-output" && exitcode=0 || exitcode=$? 289 run_bmake "testcase.mk" > "$tmpdir/actual-output" && exitcode=0 || exitcode=$?
289 290
290 create_file_lines "expected-output" \ 291 create_file_lines "expected-output" \
291 '=> Substituting "class" in nonexistent' \ 292 '=> Substituting "class" in nonexistent' \
292 'info: [subst.mk:class] Ignoring non-existent file "nonexistent".' 293 'info: [subst.mk:class] Ignoring non-existent file "nonexistent".'
293 assert_that "actual-output" --file-equals "expected-output" 294 assert_that "actual-output" --file-equals "expected-output"
294 assert_that "$exitcode" --equals "0" 295 assert_that "$exitcode" --equals "0"
295 296
296 test_case_end 297 test_case_end
297fi 298fi
298 299
299 300
300if test_case_begin "several patterns, 1 nonexistent"; then 301if test_case_begin "several patterns, 1 nonexistent"; then
301 302
302 create_file "testcase.mk" <<EOF 303 create_file "testcase.mk" <<EOF
303SUBST_CLASSES+= class 304SUBST_CLASSES+= class
304SUBST_STAGE.class= pre-configure 305SUBST_STAGE.class= pre-configure
305SUBST_FILES.class= *exist* *not-found* 306SUBST_FILES.class= *exist* *not-found*
306SUBST_SED.class= -e 's,file,example,' 307SUBST_SED.class= -e 's,file,example,'
307 308
308.include "prepare-subst.mk" 309.include "prepare-subst.mk"
309.include "mk/subst.mk" 310.include "mk/subst.mk"
310 311
311all: subst-class 312all: subst-class
312EOF 313EOF
313 314
314 create_file_lines "exists" "this file exists" 315 create_file_lines "exists" "this file exists"
315 316
316 run_bmake "testcase.mk" > "$tmpdir/actual-output" && exitcode=0 || exitcode=$? 317 run_bmake "testcase.mk" > "$tmpdir/actual-output" && exitcode=0 || exitcode=$?
317 318
318 create_file_lines "expected-output" \ 319 create_file_lines "expected-output" \
319 '=> Substituting "class" in *exist* *not-found*' \ 320 '=> Substituting "class" in *exist* *not-found*' \
320 'info: [subst.mk:class] Ignoring non-existent file "./*not-found*".' 321 'info: [subst.mk:class] Ignoring non-existent file "./*not-found*".'
321 assert_that "actual-output" --file-equals "expected-output" 322 assert_that "actual-output" --file-equals "expected-output"
322 assert_that "exists" --file-contains-exactly "this example exists" 323 assert_that "exists" --file-contains-exactly "this example exists"
323 assert_that "$exitcode" --equals "0" 324 assert_that "$exitcode" --equals "0"
324 325
325 test_case_end 326 test_case_end
326fi 327fi
327 328
328 329
329if test_case_begin "multiple missing files, all are reported at once"; then 330if test_case_begin "multiple missing files, all are reported at once"; then
330 331
331 create_file "testcase.mk" <<EOF 332 create_file "testcase.mk" <<EOF
332SUBST_CLASSES+= class 333SUBST_CLASSES+= class
333SUBST_STAGE.class= pre-configure 334SUBST_STAGE.class= pre-configure
334SUBST_FILES.class= does not exist 335SUBST_FILES.class= does not exist
335SUBST_SED.class= -e 'sahara' 336SUBST_SED.class= -e 'sahara'
336 337
337.include "prepare-subst.mk" 338.include "prepare-subst.mk"
338.include "mk/subst.mk" 339.include "mk/subst.mk"
339EOF 340EOF
340 341
341 run_bmake "testcase.mk" > "$tmpdir/actual-output" && exitcode=0 || exitcode=$? 342 run_bmake "testcase.mk" > "$tmpdir/actual-output" && exitcode=0 || exitcode=$?
342 343
343 create_file_lines "expected-output" \ 344 create_file_lines "expected-output" \
344 '=> Substituting "class" in does not exist' \ 345 '=> Substituting "class" in does not exist' \
345 'info: [subst.mk:class] Ignoring non-existent file "does".' \ 346 'info: [subst.mk:class] Ignoring non-existent file "does".' \
346 'info: [subst.mk:class] Ignoring non-existent file "not".' \ 347 'info: [subst.mk:class] Ignoring non-existent file "not".' \
347 'info: [subst.mk:class] Ignoring non-existent file "exist".' 348 'info: [subst.mk:class] Ignoring non-existent file "exist".'
348 assert_that "actual-output" --file-equals "expected-output" 349 assert_that "actual-output" --file-equals "expected-output"
349 assert_that "$exitcode" --equals "0" 350 assert_that "$exitcode" --equals "0"
350 351
351 test_case_end 352 test_case_end
352fi 353fi
353 354
354 355
355if test_case_begin "multiple no-op files, all are reported at once"; then 356if test_case_begin "multiple no-op files, all are reported at once"; then
356 357
357 create_file "testcase.mk" <<EOF 358 create_file "testcase.mk" <<EOF
358SUBST_CLASSES+= class 359SUBST_CLASSES+= class
359SUBST_STAGE.class= pre-configure 360SUBST_STAGE.class= pre-configure
360SUBST_FILES.class= first second third 361SUBST_FILES.class= first second third
361SUBST_SED.class= -e 's,from,to,' 362SUBST_SED.class= -e 's,from,to,'
362 363
363.include "prepare-subst.mk" 364.include "prepare-subst.mk"
364.include "mk/subst.mk" 365.include "mk/subst.mk"
365EOF 366EOF
366 create_file_lines "first" "text" 367 create_file_lines "first" "text"
367 create_file_lines "second" "second" 368 create_file_lines "second" "second"
368 create_file_lines "third" "third" 369 create_file_lines "third" "third"
369 370
370 run_bmake "testcase.mk" > "$tmpdir/actual-output" && exitcode=0 || exitcode=$? 371 run_bmake "testcase.mk" > "$tmpdir/actual-output" && exitcode=0 || exitcode=$?
371 372
372 create_file_lines "expected-output" \ 373 create_file_lines "expected-output" \
373 '=> Substituting "class" in first second third' \ 374 '=> Substituting "class" in first second third' \
374 'info: [subst.mk:class] Nothing changed in "first".' \ 375 'info: [subst.mk:class] Nothing changed in "first".' \
375 'info: [subst.mk:class] Nothing changed in "second".' \ 376 'info: [subst.mk:class] Nothing changed in "second".' \
376 'info: [subst.mk:class] Nothing changed in "third".' 377 'info: [subst.mk:class] Nothing changed in "third".'
377 assert_that "actual-output" --file-equals "expected-output" 378 assert_that "actual-output" --file-equals "expected-output"
378 assert_that "$exitcode" --equals "0" 379 assert_that "$exitcode" --equals "0"
379 380
380 test_case_end 381 test_case_end
381fi 382fi
382 383
383 384
384if test_case_begin "late evaluation of SUBST_FILES"; then 385if test_case_begin "late evaluation of SUBST_FILES"; then
385 386
386 # Ensure that SUBST_FILES is evaluated as late as possible. 387 # Ensure that SUBST_FILES is evaluated as late as possible.
387 # Evaluating it early breaks cases like pkglocaledir where the 388 # Evaluating it early breaks cases like pkglocaledir where the
388 # list of files is generated by a shell command. 389 # list of files is generated by a shell command.
389 # See mk/configure/replace-localedir.mk. 390 # See mk/configure/replace-localedir.mk.
390 391
391 create_file "testcase.mk" <<EOF 392 create_file "testcase.mk" <<EOF
392REPLACE_FILES_CMD.class= \ 393REPLACE_FILES_CMD.class= \
393 cd \${WRKSRC} && echo *r* 394 cd \${WRKSRC} && echo *r*
394 395
395SUBST_CLASSES+= class 396SUBST_CLASSES+= class
396SUBST_STAGE.class= pre-configure 397SUBST_STAGE.class= pre-configure
397SUBST_FILES.class= first third # \${REPLACE_FILES_CMD.class:sh} 398SUBST_FILES.class= first third # \${REPLACE_FILES_CMD.class:sh}
398SUBST_SED.class= -e 's,from,to,' 399SUBST_SED.class= -e 's,from,to,'
399 400
400.include "prepare-subst.mk" 401.include "prepare-subst.mk"
401RUN= @set -e; 402RUN= @set -e;
402WRKSRC= \${WRKDIR}/package-1.0 403WRKSRC= \${WRKDIR}/package-1.0
403.include "mk/subst.mk" 404.include "mk/subst.mk"
404 405
405# It is tricky that the dependency must use an internal implementation 406# It is tricky that the dependency must use an internal implementation
406# detail, but that's the only way to guarantee the correct ordering. 407# detail, but that's the only way to guarantee the correct ordering.
407\${_SUBST_COOKIE.class}: prepare-subst-class 408\${_SUBST_COOKIE.class}: prepare-subst-class
408prepare-subst-class: 409prepare-subst-class:
409 \${RUN} \${MKDIR} \${WRKSRC} 410 \${RUN} \${MKDIR} \${WRKSRC}
410 \${RUN} \${ECHO} "from" > "\${WRKSRC}/first" 411 \${RUN} \${ECHO} "from" > "\${WRKSRC}/first"
411 \${RUN} \${ECHO} "from" > "\${WRKSRC}/second" 412 \${RUN} \${ECHO} "from" > "\${WRKSRC}/second"
412 \${RUN} \${ECHO} "from" > "\${WRKSRC}/third" 413 \${RUN} \${ECHO} "from" > "\${WRKSRC}/third"
413EOF 414EOF
414 415
415 run_bmake "testcase.mk" "subst-class" \ 416 run_bmake "testcase.mk" "subst-class" \
416 1> "$tmpdir/actual-output" \ 417 1> "$tmpdir/actual-output" \
417 2> "$tmpdir/actual-stderr" \ 418 2> "$tmpdir/actual-stderr" \
418 && exitcode=0 || exitcode=$? 419 && exitcode=0 || exitcode=$?
419 420
420 create_file_lines "expected-output" \ 421 create_file_lines "expected-output" \
421 '=> Substituting "class" in first third' 422 '=> Substituting "class" in first third'
422 assert_that "actual-output" --file-equals "expected-output" 423 assert_that "actual-output" --file-equals "expected-output"
423 assert_that "actual-stderr" --file-is-empty 424 assert_that "actual-stderr" --file-is-empty
424 assert_that "package-1.0/first" --file-contains-exactly "to" 425 assert_that "package-1.0/first" --file-contains-exactly "to"
425 assert_that "package-1.0/second" --file-contains-exactly "from" 426 assert_that "package-1.0/second" --file-contains-exactly "from"
426 assert_that "package-1.0/third" --file-contains-exactly "to" 427 assert_that "package-1.0/third" --file-contains-exactly "to"
427 assert_that "$exitcode" --equals "0" 428 assert_that "$exitcode" --equals "0"
428 429
429 test_case_end 430 test_case_end
430fi 431fi
431 432
432 433
433if test_case_begin "special characters in filenames"; then 434if test_case_begin "special characters in filenames"; then
434 435
435 create_file "testcase.mk" <<EOF 436 create_file "testcase.mk" <<EOF
436SUBST_CLASSES+= class 437SUBST_CLASSES+= class
437SUBST_STAGE.class= pre-configure 438SUBST_STAGE.class= pre-configure
438SUBST_FILES.class= * 439SUBST_FILES.class= *
439SUBST_SED.class= -e s,before,after, 440SUBST_SED.class= -e s,before,after,
440SUBST_NOOP_OK.class= yes 441SUBST_NOOP_OK.class= yes
441 442
442.include "prepare-subst.mk" 443.include "prepare-subst.mk"
443.include "mk/subst.mk" 444.include "mk/subst.mk"
444EOF 445EOF
445 446
446 create_file_lines " !\"#\$%&'()*+,-." "before" 447 create_file_lines " !\"#\$%&'()*+,-." "before"
447 create_file_lines "0123456789:;<=>?" "before" 448 create_file_lines "0123456789:;<=>?" "before"
448 create_file_lines "@ABCDEFGHIJKLMNO" "before" 449 create_file_lines "@ABCDEFGHIJKLMNO" "before"
449 create_file_lines "PQRSTUVWXYZ[\\]^_" "before" 450 create_file_lines "PQRSTUVWXYZ[\\]^_" "before"
450 create_file_lines "\`abcdefghijklmno" "before" 451 create_file_lines "\`abcdefghijklmno" "before"
451 create_file_lines "pqrstuvwxyz{|}~" "before" 452 create_file_lines "pqrstuvwxyz{|}~" "before"
452 create_file_lines "--no-option" "before" 453 create_file_lines "--no-option" "before"
453 create_file_lines ".hidden" "before" 454 create_file_lines ".hidden" "before"
454 455
455 run_bmake "testcase.mk" "subst-class" \ 456 run_bmake "testcase.mk" "subst-class" \
456 1> "$tmpdir/stdout" \ 457 1> "$tmpdir/stdout" \
457 2> "$tmpdir/stderr" \ 458 2> "$tmpdir/stderr" \
458 && exitcode=0 || exitcode=$? 459 && exitcode=0 || exitcode=$?
459 460
460 assert_that "stdout" --file-is-lines \ 461 assert_that "stdout" --file-is-lines \
461 '=> Substituting "class" in *' \ 462 '=> Substituting "class" in *' \
462 'info: [subst.mk:class] Nothing changed in "prepare-subst.mk".' \ 463 'info: [subst.mk:class] Nothing changed in "prepare-subst.mk".' \
463 'info: [subst.mk:class] Nothing changed in "stderr".' \ 464 'info: [subst.mk:class] Nothing changed in "stderr".' \
464 'info: [subst.mk:class] Nothing changed in "stdout".' \ 465 'info: [subst.mk:class] Nothing changed in "stdout".' \
465 'info: [subst.mk:class] Nothing changed in "test.subr.main.mk".' 466 'info: [subst.mk:class] Nothing changed in "test.subr.main.mk".'
466 assert_that "stderr" --file-is-empty 467 assert_that "stderr" --file-is-empty
467 assert_that "$exitcode" --equals "0" 468 assert_that "$exitcode" --equals "0"
468 469
469 assert_that " !\"#\$%&'()*+,-." --file-is-lines "after" 470 assert_that " !\"#\$%&'()*+,-." --file-is-lines "after"
470 assert_that "0123456789:;<=>?" --file-is-lines "after" 471 assert_that "0123456789:;<=>?" --file-is-lines "after"
471 assert_that "@ABCDEFGHIJKLMNO" --file-is-lines "after" 472 assert_that "@ABCDEFGHIJKLMNO" --file-is-lines "after"
472 assert_that "PQRSTUVWXYZ[\\]^_" --file-is-lines "after" 473 assert_that "PQRSTUVWXYZ[\\]^_" --file-is-lines "after"
473 assert_that "\`abcdefghijklmno" --file-is-lines "after" 474 assert_that "\`abcdefghijklmno" --file-is-lines "after"
474 assert_that "pqrstuvwxyz{|}~" --file-is-lines "after" 475 assert_that "pqrstuvwxyz{|}~" --file-is-lines "after"
475 assert_that "--no-option" --file-is-lines "after" 476 assert_that "--no-option" --file-is-lines "after"
476 assert_that ".hidden" --file-is-lines "before" 477 assert_that ".hidden" --file-is-lines "before"
477 478
478 test_case_end 479 test_case_end
479fi 480fi
480 481
481if test_case_begin "brackets in filename patterns"; then 482if test_case_begin "brackets in filename patterns"; then
482 483
483 create_file "testcase.mk" <<EOF 484 create_file "testcase.mk" <<EOF
484SUBST_CLASSES+= class 485SUBST_CLASSES+= class
485SUBST_STAGE.class= pre-configure 486SUBST_STAGE.class= pre-configure
486SUBST_FILES.class= [*] 487SUBST_FILES.class= [*]
487SUBST_SED.class= -e s,before,after, 488SUBST_SED.class= -e s,before,after,
488SUBST_NOOP_OK.class= yes 489SUBST_NOOP_OK.class= yes
489 490
490.include "prepare-subst.mk" 491.include "prepare-subst.mk"
491.include "mk/subst.mk" 492.include "mk/subst.mk"
492EOF 493EOF
493 494
494 create_file_lines "any" "before" 495 create_file_lines "any" "before"
495 create_file_lines "x" "before" 496 create_file_lines "x" "before"
496 create_file_lines "*" "before" 497 create_file_lines "*" "before"
497 create_file_lines "[*]" "before" 498 create_file_lines "[*]" "before"
498 499
499 run_bmake "testcase.mk" "subst-class" \ 500 run_bmake "testcase.mk" "subst-class" \
500 1> "$tmpdir/stdout" \ 501 1> "$tmpdir/stdout" \
501 2> "$tmpdir/stderr" \ 502 2> "$tmpdir/stderr" \
502 && exitcode=0 || exitcode=$? 503 && exitcode=0 || exitcode=$?
503 504
504 assert_that "stdout" --file-is-lines \ 505 assert_that "stdout" --file-is-lines \
505 '=> Substituting "class" in [*]' 506 '=> Substituting "class" in [*]'
506 assert_that "stderr" --file-is-empty 507 assert_that "stderr" --file-is-empty
507 assert_that "$exitcode" --equals "0" 508 assert_that "$exitcode" --equals "0"
508 509
509 assert_that "any" --file-is-lines "before" 510 assert_that "any" --file-is-lines "before"
510 assert_that "x" --file-is-lines "before" 511 assert_that "x" --file-is-lines "before"
511 assert_that "*" --file-is-lines "after" 512 assert_that "*" --file-is-lines "after"
512 assert_that "[*]" --file-is-lines "before" 513 assert_that "[*]" --file-is-lines "before"
513 514
514 test_case_end 515 test_case_end
515fi 516fi
516 517
517 518
518if test_case_begin "duplicate SUBST class"; then 519if test_case_begin "duplicate SUBST class"; then
519 520
520 create_file "testcase.mk" <<EOF 521 create_file "testcase.mk" <<EOF
521SUBST_CLASSES+= one 522SUBST_CLASSES+= one
522SUBST_CLASSES+= two 523SUBST_CLASSES+= two
523SUBST_CLASSES+= one 524SUBST_CLASSES+= one
524 525
525all: 526all:
526 @printf 'fail reason: %s\n' \${PKG_FAIL_REASON} 1>&2 527 @printf 'fail reason: %s\n' \${PKG_FAIL_REASON} 1>&2
527 528
528.include "prepare-subst.mk" 529.include "prepare-subst.mk"
529.include "mk/subst.mk" 530.include "mk/subst.mk"
530EOF 531EOF
531 532
532 run_bmake "testcase.mk" "all" \ 533 run_bmake "testcase.mk" "all" \
533 1> "$tmpdir/stdout" \ 534 1> "$tmpdir/stdout" \
534 2> "$tmpdir/stderr" \ 535 2> "$tmpdir/stderr" \
535 && exitcode=0 || exitcode=$? 536 && exitcode=0 || exitcode=$?
536 537
537 assert_that "stdout" --file-is-empty 538 assert_that "stdout" --file-is-empty
538 assert_that "stderr" --file-is-lines \ 539 assert_that "stderr" --file-is-lines \
539 "fail reason: [subst.mk] duplicate SUBST class in: one one two" 540 "fail reason: [subst.mk] duplicate SUBST class in: one one two"
540 assert_that "$exitcode" --equals 0 541 assert_that "$exitcode" --equals 0
541 542
542 test_case_end 543 test_case_end
543fi 544fi
544 545
545 546
546if test_case_begin "several SUBST classes"; then 547if test_case_begin "several SUBST classes"; then
547 548
548 # It's ok to have several SUBST classes that apply to the same file. 549 # It's ok to have several SUBST classes that apply to the same file.
549 # The order of execution is not guaranteed though. 550 # The order of execution is not guaranteed though.
550 551
551 create_file_lines "file" "zero one two three four" 552 create_file_lines "file" "zero one two three four"
552 553
553 create_file "testcase.mk" <<EOF 554 create_file "testcase.mk" <<EOF
554SUBST_CLASSES+= one 555SUBST_CLASSES+= one
555SUBST_STAGE.one= pre-configure 556SUBST_STAGE.one= pre-configure
556SUBST_FILES.one= file 557SUBST_FILES.one= file
557SUBST_SED.one= -e 's,one,I,' 558SUBST_SED.one= -e 's,one,I,'
558 559
559SUBST_CLASSES+= two 560SUBST_CLASSES+= two
560SUBST_STAGE.two= pre-configure 561SUBST_STAGE.two= pre-configure
561SUBST_FILES.two= file 562SUBST_FILES.two= file
562SUBST_SED.two= -e 's,two,II,' 563SUBST_SED.two= -e 's,two,II,'
563 564
564SUBST_CLASSES+= three 565SUBST_CLASSES+= three
565SUBST_STAGE.three= pre-configure 566SUBST_STAGE.three= pre-configure
566SUBST_FILES.three= file 567SUBST_FILES.three= file
567SUBST_SED.three= -e 's,three,III,' 568SUBST_SED.three= -e 's,three,III,'
568 569
569.include "prepare-subst.mk" 570.include "prepare-subst.mk"
570.include "mk/subst.mk" 571.include "mk/subst.mk"
571EOF 572EOF
572 573
573 run_bmake "testcase.mk" "pre-configure" \ 574 run_bmake "testcase.mk" "pre-configure" \
574 1> "$tmpdir/stdout" \ 575 1> "$tmpdir/stdout" \
575 2> "$tmpdir/stderr" \ 576 2> "$tmpdir/stderr" \
576 && exitcode=0 || exitcode=$? 577 && exitcode=0 || exitcode=$?
577 578
578 # The order of the above output is not guaranteed. 579 # The order of the above output is not guaranteed.
579 LC_ALL=C sort < "$tmpdir/stdout" > "$tmpdir/stdout-sorted" 580 LC_ALL=C sort < "$tmpdir/stdout" > "$tmpdir/stdout-sorted"
580 581
581 assert_that "file" --file-is-lines "zero I II III four" 582 assert_that "file" --file-is-lines "zero I II III four"
582 assert_that "stdout-sorted" --file-is-lines \ 583 assert_that "stdout-sorted" --file-is-lines \
583 "=> Substituting \"one\" in file" \ 584 "=> Substituting \"one\" in file" \
584 "=> Substituting \"three\" in file" \ 585 "=> Substituting \"three\" in file" \
585 "=> Substituting \"two\" in file" 586 "=> Substituting \"two\" in file"
586 assert_that "stderr" --file-is-empty 587 assert_that "stderr" --file-is-empty
587 assert_that "$exitcode" --equals 0 588 assert_that "$exitcode" --equals 0
588 589
589 test_case_end 590 test_case_end
590fi 591fi
591 592
592 593
593if test_case_begin "show diff"; then 594if test_case_begin "show diff"; then
594 595
595 create_file_lines "file" "one" "two" "three" 596 create_file_lines "file" "one" "two" "three"
596 597
597 create_file "testcase.mk" <<EOF 598 create_file "testcase.mk" <<EOF
598SUBST_CLASSES+= two 599SUBST_CLASSES+= two
599SUBST_STAGE.two= pre-configure 600SUBST_STAGE.two= pre-configure
600SUBST_FILES.two= file 601SUBST_FILES.two= file
601SUBST_SED.two= -e 's,two,II,' 602SUBST_SED.two= -e 's,two,II,'
602SUBST_SHOW_DIFF.two= yes 603SUBST_SHOW_DIFF.two= yes
603 604
604.include "prepare-subst.mk" 605.include "prepare-subst.mk"
605.include "mk/subst.mk" 606.include "mk/subst.mk"
606EOF 607EOF
607 608
608 LC_ALL=C \ 609 LC_ALL=C \
609 run_bmake "testcase.mk" "pre-configure" \ 610 run_bmake "testcase.mk" "pre-configure" \
610 1> "$tmpdir/stdout" \ 611 1> "$tmpdir/stdout" \
611 2> "$tmpdir/stderr" \ 612 2> "$tmpdir/stderr" \
612 && exitcode=0 || exitcode=$? 613 && exitcode=0 || exitcode=$?
613 614
614 awk '{ if (/^(---|\+\+\+) /) { print $1 " " $2 " (filtered timestamp)" } else { print $0 } }' \ 615 awk '{ if (/^(---|\+\+\+) /) { print $1 " " $2 " (filtered timestamp)" } else { print $0 } }' \
615 < "$tmpdir/stdout" > "$tmpdir/stdout-filtered" 616 < "$tmpdir/stdout" > "$tmpdir/stdout-filtered"
616 617
617 assert_that "file" --file-is-lines "one" "II" "three" 618 assert_that "file" --file-is-lines "one" "II" "three"
618 assert_that "stdout-filtered" --file-is-lines \ 619 assert_that "stdout-filtered" --file-is-lines \
619 "=> Substituting \"two\" in file" \ 620 "=> Substituting \"two\" in file" \
620 "--- file (filtered timestamp)" \ 621 "--- file (filtered timestamp)" \
621 "+++ file.subst.sav (filtered timestamp)" \ 622 "+++ file.subst.sav (filtered timestamp)" \
622 "@@ -1,3 +1,3 @@" \ 623 "@@ -1,3 +1,3 @@" \
623 " one" \ 624 " one" \
624 "-two" \ 625 "-two" \
625 "+II" \ 626 "+II" \
626 " three" 627 " three"
627 assert_that "stderr" --file-is-empty 628 assert_that "stderr" --file-is-empty
628 assert_that "$exitcode" --equals 0 629 assert_that "$exitcode" --equals 0
629 630
630 test_case_end 631 test_case_end
631fi 632fi
632 633
633 634
634if test_case_begin "global show diff"; then 635if test_case_begin "global show diff"; then
635 636
636 create_file_lines "file" "one" "two" "three" 637 create_file_lines "file" "one" "two" "three"
637 638
638 create_file "testcase.mk" <<EOF 639 create_file "testcase.mk" <<EOF
639SUBST_CLASSES+= two 640SUBST_CLASSES+= two
640SUBST_STAGE.two= pre-configure 641SUBST_STAGE.two= pre-configure
641SUBST_FILES.two= file 642SUBST_FILES.two= file
642SUBST_SED.two= -e 's,two,II,' 643SUBST_SED.two= -e 's,two,II,'
643SUBST_SHOW_DIFF= yes 644SUBST_SHOW_DIFF= yes
644 645
645.include "prepare-subst.mk" 646.include "prepare-subst.mk"
646.include "mk/subst.mk" 647.include "mk/subst.mk"
647EOF 648EOF
648 649
649 run_bmake "testcase.mk" "pre-configure" \ 650 run_bmake "testcase.mk" "pre-configure" \
650 1> "$tmpdir/stdout" \ 651 1> "$tmpdir/stdout" \
651 2> "$tmpdir/stderr" \ 652 2> "$tmpdir/stderr" \
652 && exitcode=0 || exitcode=$? 653 && exitcode=0 || exitcode=$?
653 654
654 awk '{ if (/^(---|\+\+\+) /) { print $1 " " $2 " (filtered timestamp)" } else { print $0 } }' \ 655 awk '{ if (/^(---|\+\+\+) /) { print $1 " " $2 " (filtered timestamp)" } else { print $0 } }' \
655 < "$tmpdir/stdout" > "$tmpdir/stdout-filtered" 656 < "$tmpdir/stdout" > "$tmpdir/stdout-filtered"
656 657
657 assert_that "file" --file-is-lines "one" "II" "three" 658 assert_that "file" --file-is-lines "one" "II" "three"
658 assert_that "stdout-filtered" --file-is-lines \ 659 assert_that "stdout-filtered" --file-is-lines \
659 "=> Substituting \"two\" in file" \ 660 "=> Substituting \"two\" in file" \
660 "--- file (filtered timestamp)" \ 661 "--- file (filtered timestamp)" \
661 "+++ file.subst.sav (filtered timestamp)" \ 662 "+++ file.subst.sav (filtered timestamp)" \
662 "@@ -1,3 +1,3 @@" \ 663 "@@ -1,3 +1,3 @@" \
663 " one" \ 664 " one" \
664 "-two" \ 665 "-two" \
665 "+II" \ 666 "+II" \
666 " three" 667 " three"
667 assert_that "stderr" --file-is-empty 668 assert_that "stderr" --file-is-empty
668 assert_that "$exitcode" --equals 0 669 assert_that "$exitcode" --equals 0
669 670
670 test_case_end 671 test_case_end
671fi 672fi
672 673
673 674
674if test_case_begin "SUBST_VARS"; then 675if test_case_begin "SUBST_VARS"; then
675 676
676 create_file_lines "testcase.mk" \ 677 create_file_lines "testcase.mk" \
677 'SUBST_CLASSES+= vars' \ 678 'SUBST_CLASSES+= vars' \
678 'SUBST_STAGE.vars= pre-configure' \ 679 'SUBST_STAGE.vars= pre-configure' \
679 'SUBST_FILES.vars= vars.txt' \ 680 'SUBST_FILES.vars= vars.txt' \
680 'SUBST_VARS.vars= PLAIN DQUOT SQUOT DELIM PRINTABLE' \ 681 'SUBST_VARS.vars= PLAIN DQUOT SQUOT DELIM PRINTABLE' \
681 'SUBST_VARS.vars+= UNDEFINED' \ 682 'SUBST_VARS.vars+= UNDEFINED' \
682 '' \ 683 '' \
683 'PLAIN= plain' \ 684 'PLAIN= plain' \
684 'DQUOT= "double quoted"' \ 685 'DQUOT= "double quoted"' \
685 'SQUOT= '\''single quoted'\''' \ 686 'SQUOT= '\''single quoted'\''' \
686 'DELIM= hello, world' \ 687 'DELIM= hello, world' \
687 'PRINTABLE= !"\#$$%&'\''()*+,-./09:;<=>?@AZ[\]^_`az{|}' \ 688 'PRINTABLE= !"\#$$%&'\''()*+,-./09:;<=>?@AZ[\]^_`az{|}' \
688 '#UNDEFINED= # undefined' \ 689 '#UNDEFINED= # undefined' \
689 '' \ 690 '' \
690 '.include "prepare-subst.mk"' \ 691 '.include "prepare-subst.mk"' \
691 '.include "mk/subst.mk"' 692 '.include "mk/subst.mk"'
692 create_file_lines "vars.txt" \ 693 create_file_lines "vars.txt" \
693 "@PLAIN@" \ 694 "@PLAIN@" \
694 "@DQUOT@" \ 695 "@DQUOT@" \
695 "@SQUOT@" \ 696 "@SQUOT@" \
696 "@DELIM@" \ 697 "@DELIM@" \
697 "@PRINTABLE@" \ 698 "@PRINTABLE@" \
698 "@UNDEFINED@" 699 "@UNDEFINED@"
699 700
700 run_bmake "testcase.mk" "pre-configure" \ 701 run_bmake "testcase.mk" "pre-configure" \
701 1> "$tmpdir/stdout" \ 702 1> "$tmpdir/stdout" \
702 2> "$tmpdir/stderr" \ 703 2> "$tmpdir/stderr" \
703 && exitcode=0 || exitcode=$? 704 && exitcode=0 || exitcode=$?
704 705
705 # The double quotes and single quotes are kept since the variables 706 # The double quotes and single quotes are kept since the variables
706 # are treated as simple string variables, not as lists of shell 707 # are treated as simple string variables, not as lists of shell
707 # words. In these string variables, the quotes are part of the value. 708 # words. In these string variables, the quotes are part of the value.
708 assert_that "vars.txt" --file-is-lines \ 709 assert_that "vars.txt" --file-is-lines \
709 "plain" \ 710 "plain" \
710 "\"double quoted\"" \ 711 "\"double quoted\"" \
711 "'single quoted'" \ 712 "'single quoted'" \
712 "hello, world" \ 713 "hello, world" \
713 '!"#$%&'\''()*+,-./09:;<=>?@AZ[\]^_`az{|}' \ 714 '!"#$%&'\''()*+,-./09:;<=>?@AZ[\]^_`az{|}' \
714 "" 715 ""
715 assert_that "stdout" --file-is-lines \ 716 assert_that "stdout" --file-is-lines \
716 "=> Substituting \"vars\" in vars.txt" 717 "=> Substituting \"vars\" in vars.txt"
717 assert_that "stderr" --file-is-empty 718 assert_that "stderr" --file-is-empty
718 assert_that "$exitcode" --equals 0 719 assert_that "$exitcode" --equals 0
719 720
720 test_case_end 721 test_case_end
721fi 722fi
722 723
723if test_case_begin "SUBST_VARS with surrounding whitespace"; then 724if test_case_begin "SUBST_VARS with surrounding whitespace"; then
724 725
725 # Ensure that leading and trailing whitespace is preserved 726 # Ensure that leading and trailing whitespace is preserved
726 # in the variable values. 727 # in the variable values.
727 728
728 create_file_lines "testcase.mk" \ 729 create_file_lines "testcase.mk" \
729 'SUBST_CLASSES+= vars' \ 730 'SUBST_CLASSES+= vars' \
730 'SUBST_STAGE.vars= pre-configure' \ 731 'SUBST_STAGE.vars= pre-configure' \
731 'SUBST_FILES.vars= vars.txt' \ 732 'SUBST_FILES.vars= vars.txt' \
732 'SUBST_VARS.vars= SPACE TAB NEWLINE' \ 733 'SUBST_VARS.vars= SPACE TAB NEWLINE' \
733 '' \ 734 '' \
734 'SPACE= ${:U }between spaces${:U }' \ 735 'SPACE= ${:U }between spaces${:U }' \
735 'TAB= ${:U }between tabs${:U }' \ 736 'TAB= ${:U }between tabs${:U }' \
736 'NEWLINE= ${.newline}between newlines${.newline}' \ 737 'NEWLINE= ${.newline}between newlines${.newline}' \
737 '' \ 738 '' \
738 '.include "prepare-subst.mk"' \ 739 '.include "prepare-subst.mk"' \
739 '.include "mk/subst.mk"' 740 '.include "mk/subst.mk"'
740 create_file_lines "vars.txt" \ 741 create_file_lines "vars.txt" \
741 "@SPACE@" \ 742 "@SPACE@" \
742 "@TAB@" \ 743 "@TAB@" \
743 "@NEWLINE@" 744 "@NEWLINE@"
744 745
745 run_bmake "testcase.mk" "pre-configure" \ 746 run_bmake "testcase.mk" "pre-configure" \
746 1> "$tmpdir/stdout" \ 747 1> "$tmpdir/stdout" \
747 2> "$tmpdir/stderr" \ 748 2> "$tmpdir/stderr" \
748 && exitcode=0 || exitcode=$? 749 && exitcode=0 || exitcode=$?
749 750
750 space=' ' 751 space=' '
751 tab=' ' 752 tab=' '
752 newline=' 753 newline='
753' 754'
754 assert_that "vars.txt" --file-is-lines \ 755 assert_that "vars.txt" --file-is-lines \
755 "$space""between spaces""$space" \ 756 "$space""between spaces""$space" \
756 "$tab""between tabs""$tab" \ 757 "$tab""between tabs""$tab" \
757 "$newline""between newlines""$newline" 758 "$newline""between newlines""$newline"
758 assert_that "stdout" --file-is-lines \ 759 assert_that "stdout" --file-is-lines \
759 "=> Substituting \"vars\" in vars.txt" 760 "=> Substituting \"vars\" in vars.txt"
760 assert_that "stderr" --file-is-empty 761 assert_that "stderr" --file-is-empty
761 assert_that "$exitcode" --equals 0 762 assert_that "$exitcode" --equals 0
762 763
763 test_case_end 764 test_case_end
764fi 765fi
765 766
766 767
767if test_case_begin "SUBST_VARS with backslashes"; then 768if test_case_begin "SUBST_VARS with backslashes"; then
768 769
769 create_file_lines "testcase.mk" \ 770 create_file_lines "testcase.mk" \
770 'SUBST_CLASSES+= bs' \ 771 'SUBST_CLASSES+= bs' \
771 'SUBST_STAGE.bs= pre-configure' \ 772 'SUBST_STAGE.bs= pre-configure' \
772 'SUBST_FILES.bs= backslash.txt' \ 773 'SUBST_FILES.bs= backslash.txt' \
773 'SUBST_VARS.bs= BACKSLASHES' \ 774 'SUBST_VARS.bs= BACKSLASHES' \
774 '' \ 775 '' \
775 'BACKSLASHES= \" \, \\, \" \'\'' \0\000 \x40 \089 \a \$$' \ 776 'BACKSLASHES= \" \, \\, \" \'\'' \0\000 \x40 \089 \a \$$' \
776 '' \ 777 '' \
777 '.include "prepare-subst.mk"' \ 778 '.include "prepare-subst.mk"' \
778 '.include "mk/subst.mk"' 779 '.include "mk/subst.mk"'
779 create_file_lines "backslash.txt" "@BACKSLASHES@" 780 create_file_lines "backslash.txt" "@BACKSLASHES@"
780 781
781 run_bmake "testcase.mk" "pre-configure" \ 782 run_bmake "testcase.mk" "pre-configure" \
782 1> "$tmpdir/stdout" \ 783 1> "$tmpdir/stdout" \
783 2> "$tmpdir/stderr" \ 784 2> "$tmpdir/stderr" \
784 && exitcode=0 || exitcode=$? 785 && exitcode=0 || exitcode=$?
785 786
786 assert_that "backslash.txt" --file-is-lines \ 787 assert_that "backslash.txt" --file-is-lines \
787 '\" \, \\, \" \'\'' \0\000 \x40 \089 \a \$' 788 '\" \, \\, \" \'\'' \0\000 \x40 \089 \a \$'
788 assert_that "stdout" --file-is-lines \ 789 assert_that "stdout" --file-is-lines \
789 "=> Substituting \"bs\" in backslash.txt" 790 "=> Substituting \"bs\" in backslash.txt"
790 assert_that "stderr" --file-is-empty 791 assert_that "stderr" --file-is-empty
791 assert_that "$exitcode" --equals 0 792 assert_that "$exitcode" --equals 0
792 793
793 test_case_end 794 test_case_end
794fi 795fi
795 796
796 797
797if test_case_begin "SUBST_VARS for variables with regex characters"; then 798if test_case_begin "SUBST_VARS for variables with regex characters"; then
798 799
799 # Ensure that special regex characters like dots and parentheses 800 # Ensure that special regex characters like dots and parentheses
800 # may appear in variable names and are properly escaped. 801 # may appear in variable names and are properly escaped.
801 802
802 # Variable names containing a dollar are not supported. 803 # Variable names containing a dollar are not supported.
803 # Bmake behaves very surprisingly when a $ is expanded inside a :C 804 # Bmake behaves very surprisingly when a $ is expanded inside a :C
804 # modifier. Nobody needs this feature anyway, it was just an 805 # modifier. Nobody needs this feature anyway, it was just an
805 # experiment to see whether this would be theoretically possible. 806 # experiment to see whether this would be theoretically possible.
806 807
807 # Variable names ending with a backslash are not supported. 808 # Variable names ending with a backslash are not supported.
808 # The backslash may only occur in the middle of the variable name. 809 # The backslash may only occur in the middle of the variable name.
809 810
810 create_file_lines "testcase.mk" \ 811 create_file_lines "testcase.mk" \
811 'SUBST_CLASSES+= vars' \ 812 'SUBST_CLASSES+= vars' \
812 'SUBST_STAGE.vars= pre-configure' \ 813 'SUBST_STAGE.vars= pre-configure' \
813 'SUBST_FILES.vars= vars.txt' \ 814 'SUBST_FILES.vars= vars.txt' \
814 'SUBST_VARS.vars= VAR...... VAR.abcde' \ 815 'SUBST_VARS.vars= VAR...... VAR.abcde' \
815 'SUBST_VARS.vars+= VAR.() VAR.<> VAR.[]' \ 816 'SUBST_VARS.vars+= VAR.() VAR.<> VAR.[]' \
816 'SUBST_VARS.vars+= VAR.$$x VAR.^ VAR.\x' \ 817 'SUBST_VARS.vars+= VAR.$$x VAR.^ VAR.\x' \
817 '' \ 818 '' \
818 'VAR......= dots' \ 819 'VAR......= dots' \
819 'VAR.abcde= letters' \ 820 'VAR.abcde= letters' \
820 'VAR.()= parentheses' \ 821 'VAR.()= parentheses' \
821 'VAR.<>= angle brackets' \ 822 'VAR.<>= angle brackets' \
822 'VAR.[]= square brackets' \ 823 'VAR.[]= square brackets' \
823 'VAR.$$x= dollar' \ 824 'VAR.$$x= dollar' \
824 'VAR.^= circumflex' \ 825 'VAR.^= circumflex' \
825 'VAR.\x= backslash' \ 826 'VAR.\x= backslash' \
826 '' \ 827 '' \
827 '.include "prepare-subst.mk"' \ 828 '.include "prepare-subst.mk"' \
828 '.include "mk/subst.mk"' 829 '.include "mk/subst.mk"'
829 create_file_lines "vars.txt" \ 830 create_file_lines "vars.txt" \
830 "@VAR......@" \ 831 "@VAR......@" \
831 "@VAR.abcde@" \ 832 "@VAR.abcde@" \
832 "@VAR.()@" \ 833 "@VAR.()@" \
833 "@VAR.<>@" \ 834 "@VAR.<>@" \
834 "@VAR.[]@" \ 835 "@VAR.[]@" \
835 '@VAR.$x@' \ 836 '@VAR.$x@' \
836 '@VAR.^@' \ 837 '@VAR.^@' \
837 '@VAR.\x@' 838 '@VAR.\x@'
838 839
839 run_bmake "testcase.mk" "pre-configure" \ 840 run_bmake "testcase.mk" "pre-configure" \
840 1> "$tmpdir/stdout" \ 841 1> "$tmpdir/stdout" \
841 2> "$tmpdir/stderr" \ 842 2> "$tmpdir/stderr" \
842 && exitcode=0 || exitcode=$? 843 && exitcode=0 || exitcode=$?
843 844
844 assert_that "vars.txt" --file-is-lines \ 845 assert_that "vars.txt" --file-is-lines \
845 "dots" \ 846 "dots" \
846 "letters" \ 847 "letters" \
847 "parentheses" \ 848 "parentheses" \
848 "angle brackets" \ 849 "angle brackets" \
849 "square brackets" \ 850 "square brackets" \
850 '@VAR.$x@' \ 851 '@VAR.$x@' \
851 'circumflex' \ 852 'circumflex' \
852 'backslash' 853 'backslash'
853 assert_that "stdout" --file-is-lines \ 854 assert_that "stdout" --file-is-lines \
854 "=> Substituting \"vars\" in vars.txt" 855 "=> Substituting \"vars\" in vars.txt"
855 assert_that "stderr" --file-is-empty 856 assert_that "stderr" --file-is-empty
856 assert_that "$exitcode" --equals 0 857 assert_that "$exitcode" --equals 0
857 858
858 test_case_end 859 test_case_end
859fi 860fi
860 861
861if test_case_begin "pattern matches directory"; then 862if test_case_begin "pattern matches directory"; then
862 863
863 # When a pattern matches a directory, that directory is silently 864 # When a pattern matches a directory, that directory is silently
864 # skipped. 865 # skipped.
865 # 866 #
866 # In this test case, the pattern also matches a regular file that 867 # In this test case, the pattern also matches a regular file that
867 # is actually modified. Therefore the pattern has an effect, and 868 # is actually modified. Therefore the pattern has an effect, and
868 # there is no error message. 869 # there is no error message.
869 870
870 create_file_lines "testcase.mk" \ 871 create_file_lines "testcase.mk" \
871 'SUBST_CLASSES+= dir' \ 872 'SUBST_CLASSES+= dir' \
872 'SUBST_STAGE.dir= pre-configure' \ 873 'SUBST_STAGE.dir= pre-configure' \
873 'SUBST_FILES.dir= sub*' \ 874 'SUBST_FILES.dir= sub*' \
874 'SUBST_VARS.dir= VAR' \ 875 'SUBST_VARS.dir= VAR' \
875 'SUBST_NOOP_OK.dir= no' \ 876 'SUBST_NOOP_OK.dir= no' \
876 '' \ 877 '' \
877 'VAR= value' \ 878 'VAR= value' \
878 '' \ 879 '' \
879 '.include "prepare-subst.mk"' \ 880 '.include "prepare-subst.mk"' \
880 '.include "mk/subst.mk"' 881 '.include "mk/subst.mk"'
881 mkdir "$tmpdir/subdir" 882 mkdir "$tmpdir/subdir"
882 create_file_lines "subdir/subfile" \ 883 create_file_lines "subdir/subfile" \
883 "@VAR@" 884 "@VAR@"
884 create_file_lines "subst-file" \ 885 create_file_lines "subst-file" \
885 "@VAR@" 886 "@VAR@"
886 887
887 run_bmake "testcase.mk" "pre-configure" \ 888 run_bmake "testcase.mk" "pre-configure" \
888 1> "$tmpdir/stdout" \ 889 1> "$tmpdir/stdout" \
889 2> "$tmpdir/stderr" \ 890 2> "$tmpdir/stderr" \
890 && exitcode=0 || exitcode=$? 891 && exitcode=0 || exitcode=$?
891 892
892 assert_that "subst-file" --file-is-lines "value" 893 assert_that "subst-file" --file-is-lines "value"
893 assert_that "subdir/subfile" --file-is-lines "@VAR@" # unchanged 894 assert_that "subdir/subfile" --file-is-lines "@VAR@" # unchanged
894 assert_that "stdout" --file-is-lines \ 895 assert_that "stdout" --file-is-lines \
895 "=> Substituting \"dir\" in sub*" 896 "=> Substituting \"dir\" in sub*"
896 assert_that "stderr" --file-is-empty 897 assert_that "stderr" --file-is-empty
897 assert_that "$exitcode" --equals 0 898 assert_that "$exitcode" --equals 0
898 899
899 test_case_end 900 test_case_end
900fi 901fi
901 902
902 903
903if test_case_begin "pattern matches only directory"; then 904if test_case_begin "pattern matches only directory"; then
904 905
905 # When a pattern matches a directory, that directory is silently 906 # When a pattern matches a directory, that directory is silently
906 # skipped. 907 # skipped.
907 908
908 create_file_lines "testcase.mk" \ 909 create_file_lines "testcase.mk" \
909 'SUBST_CLASSES+= dir' \ 910 'SUBST_CLASSES+= dir' \
910 'SUBST_STAGE.dir= pre-configure' \ 911 'SUBST_STAGE.dir= pre-configure' \
911 'SUBST_FILES.dir= sub*' \ 912 'SUBST_FILES.dir= sub*' \
912 'SUBST_VARS.dir= VAR' \ 913 'SUBST_VARS.dir= VAR' \
913 'SUBST_NOOP_OK.dir= no' \ 914 'SUBST_NOOP_OK.dir= no' \
914 '' \ 915 '' \
915 'VAR= value' \ 916 'VAR= value' \
916 '' \ 917 '' \
917 '.include "prepare-subst.mk"' \ 918 '.include "prepare-subst.mk"' \
918 '.include "mk/subst.mk"' 919 '.include "mk/subst.mk"'
919 mkdir "$tmpdir/subdir" 920 mkdir "$tmpdir/subdir"
920 create_file_lines "subdir/subfile" \ 921 create_file_lines "subdir/subfile" \
921 "@VAR@" 922 "@VAR@"
922 923
923 run_bmake "testcase.mk" "pre-configure" \ 924 run_bmake "testcase.mk" "pre-configure" \
924 1> "$tmpdir/stdout" \ 925 1> "$tmpdir/stdout" \
925 2> "$tmpdir/stderr" \ 926 2> "$tmpdir/stderr" \
926 && exitcode=0 || exitcode=$? 927 && exitcode=0 || exitcode=$?
927 928
928 assert_that "subdir/subfile" --file-is-lines "@VAR@" # unchanged 929 assert_that "subdir/subfile" --file-is-lines "@VAR@" # unchanged
929 assert_that "stdout" --file-is-lines \ 930 assert_that "stdout" --file-is-lines \
930 "=> Substituting \"dir\" in sub*" \ 931 "=> Substituting \"dir\" in sub*" \
931 'fail: [subst.mk:dir] The filename pattern "sub*" has no effect.' \ 932 'fail: [subst.mk:dir] The filename pattern "sub*" has no effect.' \
932 "*** Error code 1" \ 933 "*** Error code 1" \
933 "" \ 934 "" \
934 "Stop." \ 935 "Stop." \
935 "$make: stopped in $PWD" 936 "$make: stopped in $PWD"
936 assert_that "stderr" --file-is-empty 937 assert_that "stderr" --file-is-empty
937 assert_that "$exitcode" --equals 1 938 assert_that "$exitcode" --equals 1
938 939
939 test_case_end 940 test_case_end
940fi 941fi
941 942
942 943
943if test_case_begin "two filename patterns have no effect"; then 944if test_case_begin "two filename patterns have no effect"; then
944 945
945 # All patterns of SUBST_FILES should be applied before erroring out, 946 # All patterns of SUBST_FILES should be applied before erroring out,
946 # to give a complete picture of the situation. 947 # to give a complete picture of the situation.
947 948
948 create_file_lines "testcase.mk" \ 949 create_file_lines "testcase.mk" \
949 'SUBST_CLASSES+= id' \ 950 'SUBST_CLASSES+= id' \
950 'SUBST_STAGE.id= pre-configure' \ 951 'SUBST_STAGE.id= pre-configure' \
951 'SUBST_FILES.id= file1 file2' \ 952 'SUBST_FILES.id= file1 file2' \
952 'SUBST_VARS.id= A B' \ 953 'SUBST_VARS.id= A B' \
953 'SUBST_NOOP_OK.id= no' \ 954 'SUBST_NOOP_OK.id= no' \
954 'A= a-value' \ 955 'A= a-value' \
955 'B= b-value' \ 956 'B= b-value' \
956 '' \ 957 '' \
957 '.include "prepare-subst.mk"' \ 958 '.include "prepare-subst.mk"' \
958 '.include "mk/subst.mk"' 959 '.include "mk/subst.mk"'
959 create_file_lines "file1" "nothing to replace" 960 create_file_lines "file1" "nothing to replace"
960 create_file_lines "file2" "nothing to replace" 961 create_file_lines "file2" "nothing to replace"
961 962
962 run_bmake "testcase.mk" "pre-configure" 1> "$tmpdir/out" 2>&1 \ 963 run_bmake "testcase.mk" "pre-configure" 1> "$tmpdir/out" 2>&1 \
963 && exitcode=0 || exitcode=$? 964 && exitcode=0 || exitcode=$?
964 965
965 assert_that "out" --file-is-lines \ 966 assert_that "out" --file-is-lines \
966 '=> Substituting "id" in file1 file2' \ 967 '=> Substituting "id" in file1 file2' \
967 'warning: [subst.mk:id] Nothing changed in "file1".' \ 968 'warning: [subst.mk:id] Nothing changed in "file1".' \
968 'warning: [subst.mk:id] Nothing changed in "file2".' \ 969 'warning: [subst.mk:id] Nothing changed in "file2".' \
969 'fail: [subst.mk:id] The filename patterns "file1 file2" have no effect.' \ 970 'fail: [subst.mk:id] The filename patterns "file1 file2" have no effect.' \
970 '*** Error code 1' \ 971 '*** Error code 1' \
971 '' \ 972 '' \
972 'Stop.' \ 973 'Stop.' \
973 "$make: stopped in $PWD" 974 "$make: stopped in $PWD"
974 975
975 test_case_end 976 test_case_end
976fi 977fi
977 978
978 979
979if test_case_begin "empty SUBST_FILES"; then 980if test_case_begin "empty SUBST_FILES"; then
980 981
981 # An empty SUBST_FILES section is ok. 982 # An empty SUBST_FILES section is ok.
982 # It may have been produced by a shell command like find(1). 983 # It may have been produced by a shell command like find(1).
983 984
984 create_file_lines "testcase.mk" \ 985 create_file_lines "testcase.mk" \
985 'SUBST_CLASSES+= id' \ 986 'SUBST_CLASSES+= id' \
986 'SUBST_STAGE.id= pre-configure' \ 987 'SUBST_STAGE.id= pre-configure' \
987 'SUBST_FILES.id= # none' \ 988 'SUBST_FILES.id= # none' \
988 'SUBST_SED.id= -e s,from,to,' \ 989 'SUBST_SED.id= -e s,from,to,' \
989 'SUBST_NOOP_OK.id= no' \ 990 'SUBST_NOOP_OK.id= no' \
990 '' \ 991 '' \
991 'all:' \ 992 'all:' \
992 ' @printf "%s\n" ${PKG_FAIL_REASON:Uok}' \ 993 ' @printf "%s\n" ${PKG_FAIL_REASON:Uok}' \
993 '' \ 994 '' \
994 '.include "prepare-subst.mk"' \ 995 '.include "prepare-subst.mk"' \
995 '.include "mk/subst.mk"' 996 '.include "mk/subst.mk"'
996 997
997 run_bmake "testcase.mk" "pre-configure" "all" 1> "$tmpdir/out" 2>&1 \ 998 run_bmake "testcase.mk" "pre-configure" "all" 1> "$tmpdir/out" 2>&1 \
998 && exitcode=0 || exitcode=$? 999 && exitcode=0 || exitcode=$?
999 1000
1000 assert_that "out" --file-is-lines \ 1001 assert_that "out" --file-is-lines \
1001 '=> Substituting "id" in ' \ 1002 '=> Substituting "id" in ' \
1002 'ok' 1003 'ok'
1003 1004
1004 test_case_end 1005 test_case_end
1005fi 1006fi
1006 1007
1007 1008
1008if test_case_begin "empty SUBST_SED"; then 1009if test_case_begin "empty SUBST_SED"; then
1009 1010
1010 create_file_lines "testcase.mk" \ 1011 create_file_lines "testcase.mk" \
1011 'SUBST_CLASSES+= id' \ 1012 'SUBST_CLASSES+= id' \
1012 'SUBST_STAGE.id= pre-configure' \ 1013 'SUBST_STAGE.id= pre-configure' \
1013 'SUBST_FILES.id= file' \ 1014 'SUBST_FILES.id= file' \
1014 'SUBST_SED.id= # none' \ 1015 'SUBST_SED.id= # none' \
1015 'SUBST_NOOP_OK.id= no' \ 1016 'SUBST_NOOP_OK.id= no' \
1016 '' \ 1017 '' \
1017 'all:' \ 1018 'all:' \
1018 ' @printf "%s\n" ${PKG_FAIL_REASON:Uok}' \ 1019 ' @printf "%s\n" ${PKG_FAIL_REASON:Uok}' \
1019 '' \ 1020 '' \
1020 '.include "prepare-subst.mk"' \ 1021 '.include "prepare-subst.mk"' \
1021 '.include "mk/subst.mk"' 1022 '.include "mk/subst.mk"'
1022 1023
1023 run_bmake "testcase.mk" "pre-configure" "all" 1> "$tmpdir/out" 2>&1 \ 1024 run_bmake "testcase.mk" "pre-configure" "all" 1> "$tmpdir/out" 2>&1 \
1024 && exitcode=0 || exitcode=$? 1025 && exitcode=0 || exitcode=$?
1025 1026
1026 assert_that "out" --file-is-lines \ 1027 assert_that "out" --file-is-lines \
1027 '=> Substituting "id" in file' \ 1028 '=> Substituting "id" in file' \
1028 'warning: [subst.mk:id] Ignoring non-existent file "file".' \ 1029 'warning: [subst.mk:id] Ignoring non-existent file "file".' \
1029 'fail: [subst.mk:id] The filename pattern "file" has no effect.' \ 1030 'fail: [subst.mk:id] The filename pattern "file" has no effect.' \
1030 '*** Error code 1' \ 1031 '*** Error code 1' \
1031 '' \ 1032 '' \
1032 'Stop.' \ 1033 'Stop.' \
1033 "$make: stopped in $PWD" 1034 "$make: stopped in $PWD"
1034 1035
1035 test_case_end 1036 test_case_end
1036fi 1037fi
1037 1038
1038 1039
1039if test_case_begin "typo in SUBST_CLASSES"; then 1040if test_case_begin "typo in SUBST_CLASSES"; then
1040 1041
1041 # Look closely. The SUBST_CLASSES line contains a typo. 1042 # Look closely. The SUBST_CLASSES line contains a typo.
1042 # subst.mk does not catch this, but pkglint does. 1043 # subst.mk does not catch this, but pkglint does.
1043 1044
1044 create_file_lines "testcase.mk" \ 1045 create_file_lines "testcase.mk" \
1045 'SUBST_CLASSES=+ id' \ 1046 'SUBST_CLASSES=+ id' \
1046 'SUBST_STAGE.id= pre-configure' \ 1047 'SUBST_STAGE.id= pre-configure' \
1047 'SUBST_FILES.id= file' \ 1048 'SUBST_FILES.id= file' \
1048 'SUBST_SED.id= # none' \ 1049 'SUBST_SED.id= # none' \
1049 'SUBST_NOOP_OK.id= no' \ 1050 'SUBST_NOOP_OK.id= no' \
1050 '' \ 1051 '' \
1051 'all:' \ 1052 'all:' \
1052 ' @printf "%s\n" ${PKG_FAIL_REASON:Uok}' \ 1053 ' @printf "%s\n" ${PKG_FAIL_REASON:Uok}' \
1053 '' \ 1054 '' \
1054 '.include "prepare-subst.mk"' \ 1055 '.include "prepare-subst.mk"' \
1055 '.include "mk/subst.mk"' 1056 '.include "mk/subst.mk"'
1056 1057
1057 run_bmake "testcase.mk" "pre-configure" "all" 1> "$tmpdir/out" 2>&1 \ 1058 run_bmake "testcase.mk" "pre-configure" "all" 1> "$tmpdir/out" 2>&1 \
1058 && exitcode=0 || exitcode=$? 1059 && exitcode=0 || exitcode=$?
1059 1060
1060 assert_that "out" --file-is-lines \ 1061 assert_that "out" --file-is-lines \
1061 '=> Substituting "id" in file' \ 1062 '=> Substituting "id" in file' \
1062 'warning: [subst.mk:id] Ignoring non-existent file "file".' \ 1063 'warning: [subst.mk:id] Ignoring non-existent file "file".' \
1063 'fail: [subst.mk:id] The filename pattern "file" has no effect.' \ 1064 'fail: [subst.mk:id] The filename pattern "file" has no effect.' \
1064 '*** Error code 1' \ 1065 '*** Error code 1' \
1065 '' \ 1066 '' \
1066 'Stop.' \ 1067 'Stop.' \
1067 "$make: stopped in $PWD" 1068 "$make: stopped in $PWD"
1068 1069
1069 test_case_end 1070 test_case_end
1070fi 1071fi
1071 1072
1072 1073
1073if test_case_begin "executable bit is preserved"; then 1074if test_case_begin "executable bit is preserved"; then
1074 1075
1075 create_file_lines "testcase.mk" \ 1076 create_file_lines "testcase.mk" \
1076 'SUBST_CLASSES+= id' \ 1077 'SUBST_CLASSES+= id' \
1077 'SUBST_STAGE.id= pre-configure' \ 1078 'SUBST_STAGE.id= pre-configure' \
1078 'SUBST_FILES.id= cmd data' \ 1079 'SUBST_FILES.id= cmd data' \
1079 'SUBST_VARS.id= VAR' \ 1080 'SUBST_VARS.id= VAR' \
1080 'VAR= replaced' \ 1081 'VAR= replaced' \
1081 '' \ 1082 '' \
1082 '.include "prepare-subst.mk"' \ 1083 '.include "prepare-subst.mk"' \
1083 '.include "mk/subst.mk"' 1084 '.include "mk/subst.mk"'
1084 create_file_lines "cmd" \ 1085 create_file_lines "cmd" \
1085 '@VAR@' 1086 '@VAR@'
1086 create_file_lines "data" \ 1087 create_file_lines "data" \
1087 '@VAR@' 1088 '@VAR@'
1088 chmod +x "$tmpdir/cmd" 1089 chmod +x "$tmpdir/cmd"
1089 1090
1090 run_bmake "testcase.mk" "pre-configure" 1> "$tmpdir/out" 2>&1 \ 1091 run_bmake "testcase.mk" "pre-configure" 1> "$tmpdir/out" 2>&1 \
1091 && exitcode=0 || exitcode=$? 1092 && exitcode=0 || exitcode=$?
1092 1093
1093 assert_that "out" --file-is-lines \ 1094 assert_that "out" --file-is-lines \
1094 '=> Substituting "id" in cmd data' 1095 '=> Substituting "id" in cmd data'
1095 assert_that "cmd" --file-is-lines "replaced" 1096 assert_that "cmd" --file-is-lines "replaced"
1096 assert_that "data" --file-is-lines "replaced" 1097 assert_that "data" --file-is-lines "replaced"
1097 [ -x "$tmpdir/cmd" ] \ 1098 [ -x "$tmpdir/cmd" ] \
1098 || assert_fail "cmd must still be executable" 1099 || assert_fail "cmd must still be executable"
1099 [ -x "$tmpdir/data" ] \ 1100 [ -x "$tmpdir/data" ] \
1100 && assert_fail "data must not be executable" 1101 && assert_fail "data must not be executable"
1101 1102
1102 test_case_end 1103 test_case_end
1103fi 1104fi
1104 1105
1105 1106
1106if test_case_begin "unreadable file"; then 1107if test_case_begin "unreadable file"; then
1107 1108
1108 create_file_lines "testcase.mk" \ 1109 create_file_lines "testcase.mk" \
1109 'SUBST_CLASSES+= id' \ 1110 'SUBST_CLASSES+= id' \
1110 'SUBST_STAGE.id= pre-configure' \ 1111 'SUBST_STAGE.id= pre-configure' \
1111 'SUBST_FILES.id= unreadable-file' \ 1112 'SUBST_FILES.id= unreadable-file' \
1112 'SUBST_SED.id= -e s,before,after,' \ 1113 'SUBST_SED.id= -e s,before,after,' \
1113 '' \ 1114 '' \
1114 '.include "prepare-subst.mk"' \ 1115 '.include "prepare-subst.mk"' \
1115 '.include "mk/subst.mk"' 1116 '.include "mk/subst.mk"'
1116 create_file_lines "unreadable-file" \ 1117 create_file_lines "unreadable-file" \
1117 'before' 1118 'before'
1118 chmod 0000 "$tmpdir/unreadable-file" 1119 chmod 0000 "$tmpdir/unreadable-file"
1119 1120
1120 run_bmake "testcase.mk" "pre-configure" 1> "$tmpdir/out" 2>&1 \ 1121 run_bmake "testcase.mk" "pre-configure" 1> "$tmpdir/out" 2>&1 \
1121 && exitcode=0 || exitcode=$? 1122 && exitcode=0 || exitcode=$?
1122 1123
1123 assert_that "out" --file-is-lines \ 1124 assert_that "out" --file-is-lines \
1124 '=> Substituting "id" in unreadable-file' \ 1125 '=> Substituting "id" in unreadable-file' \
1125 'sh: cannot open unreadable-file: permission denied' \ 1126 'sh: cannot open unreadable-file: permission denied' \
1126 'sh: cannot open unreadable-file: permission denied' \ 1127 'sh: cannot open unreadable-file: permission denied' \
1127 '*** Error code 1' \ 1128 '*** Error code 1' \
1128 '' \ 1129 '' \
1129 'Stop.' \ 1130 'Stop.' \
1130 "$make: stopped in $PWD" 1131 "$make: stopped in $PWD"
1131 1132
1132 test_case_end 1133 test_case_end
1133fi 1134fi
 1135
 1136
 1137if test_case_begin "identity substitution implementation"; then
 1138
 1139 assert_identity() {
 1140 ai_expected="$1"; shift
 1141 awk -f "$pkgsrcdir/mk/scripts/subst-identity.awk" -- "$@" \
 1142 && ai_actual="yes" || ai_actual="no"
 1143
 1144 [ "$ai_actual" = "$ai_expected" ] \
 1145 || assert_fail "expected '%s', got '%s' for %s\n" "$ai_expected" "$ai_actual" "$*"
 1146 }
 1147
 1148 # If there is no SUBST_SED at all, this is not the situation
 1149 # that is targeted by this test for identity substitution.
 1150 assert_identity "no" # no substitutions at all
 1151
 1152 # Even though this is an identity substitution, it is missing
 1153 # the -e option and thus does not follow the usual format.
 1154 # Therefore it is considered just a normal substitution.
 1155 assert_identity "no" 's,from,from,'
 1156
 1157 # The following are typical identity substitutions.
 1158 # It does not matter whether the g modifier is there or not.
 1159 # Unknown modifiers are not allowed though.
 1160 assert_identity "yes" -e 's,from,from,'
 1161 assert_identity "yes" -e 's;from;from;'
 1162 assert_identity "yes" -e 's,from,from,g'
 1163 assert_identity "no" -e 's,from,from,gunknown'
 1164
 1165 # The identity substitution may include characters other than
 1166 # A-Za-z0-9, but no characters that have a special meaning in
 1167 # basic regular expressions.
 1168 assert_identity "yes" -e 's,/dev/audio,/dev/audio,'
 1169 assert_identity "yes" -e 's!/dev/audio!/dev/audio!'
 1170
 1171 # There may be several identity substitutions in the same
 1172 # SUBST_SED. As long as all these substitutions are identity
 1173 # substitutions, they may be skipped. As soon as there is one
 1174 # other substitution, the whole SUBST_SED is treated as usual.
 1175 assert_identity "yes" -e 's;from;from;' -e 's!second!second!'
 1176 assert_identity "no" -e 's,changing,x,' -e 's,id,id,'
 1177 assert_identity "no" -e 's,id,id,' -e 's,changing,x,'
 1178
 1179 # A demonstration of all ASCII characters that may appear in an
 1180 # identity substitution.
 1181 #
 1182 # The # and $ are excluded since they are interpreted specially
 1183 # in Makefiles and would thus be confusing to the human reader.
 1184 #
 1185 # The characters *.?[\]^ have a special meaning in the pattern of the
 1186 # substitution.
 1187 # The & has a special meaning in the replacement of the
 1188 # substitution.
 1189 specials='!"%'\''()+,-/:;<=>@_`{|}~'
 1190 assert_identity "yes" -e "sX${specials}X${specials}X"
 1191
 1192 test_case_end
 1193fi
 1194
 1195
 1196if test_case_begin "identity substitution, found in file"; then
 1197
 1198 # There are many situations in which a fixed text is replaced
 1199 # with a dynamic value that may or may not be equal to the
 1200 # original text.
 1201 #
 1202 # Typical examples are s|man|${PKGMANDIR}|, s|/usr/pkg|${PREFIX}|,
 1203 # s|/dev/audio|${DEVOSSAUDIO}|.
 1204 #
 1205 # It is not an error if these substitutions result in a no-op,
 1206 # provided that the text is actually found in the file.
 1207 #
 1208 # Alternatives for this special exception would be:
 1209 #
 1210 # 1. Mark these blocks as SUBST_NOOP_OK. This would not detect
 1211 # outdated definitions. Since this detection is the main goal
 1212 # of SUBST_NOOP_OK, this is out of the question.
 1213 #
 1214 # 2. Surround these blocks with a condition like ".if ${VAR} !=
 1215 # fixed-value ... .endif". This pattern only works if VAR is
 1216 # definitely assigned, which often requires a corresponding
 1217 # .include line, leading to code bloat. It would also mean that
 1218 # variables defined in bsd.pkg.mk could not be used in SUBST
 1219 # blocks like these.
 1220
 1221 create_file_lines "testcase.mk" \
 1222 'SUBST_CLASSES+= id' \
 1223 'SUBST_FILES.id= file' \
 1224 'SUBST_SED.id= -e s,before,before,' \
 1225 'SUBST_NOOP_OK.id= no' \
 1226 '' \
 1227 '.include "prepare-subst.mk"' \
 1228 '.include "mk/subst.mk"'
 1229 create_file_lines "file" \
 1230 'before'
 1231
 1232 run_bmake "testcase.mk" "subst-id" 1> "$tmpdir/out" 2>&1 \
 1233 && exitcode=0 || exitcode=$?
 1234
 1235 assert_that "out" --file-is-lines \
 1236 '=> Substituting "id" in file'
 1237
 1238 test_case_end
 1239fi
 1240
 1241
 1242if test_case_begin "identity substitution, not found in file"; then
 1243
 1244 create_file_lines "testcase.mk" \
 1245 'SUBST_CLASSES+= id' \
 1246 'SUBST_FILES.id= file' \
 1247 'SUBST_SED.id= s,before,before,' \
 1248 'SUBST_NOOP_OK.id= no' \
 1249 '' \
 1250 '.include "prepare-subst.mk"' \
 1251 '.include "mk/subst.mk"'
 1252 create_file_lines "file" \
 1253 'other'
 1254
 1255 run_bmake "testcase.mk" "subst-id" 1> "$tmpdir/out" 2>&1 \
 1256 && exitcode=0 || exitcode=$?
 1257
 1258 assert_that "out" --file-is-lines \
 1259 '=> Substituting "id" in file' \
 1260 'warning: [subst.mk:id] Nothing changed in "file".' \
 1261 'fail: [subst.mk:id] The filename pattern "file" has no effect.' \
 1262 '*** Error code 1' \
 1263 '' \
 1264 'Stop.' \
 1265 "$make: stopped in $PWD"
 1266
 1267 test_case_end
 1268fi
 1269
 1270
 1271if test_case_begin "identity + effective substitution"; then
 1272
 1273 create_file_lines "testcase.mk" \
 1274 'SUBST_CLASSES+= id' \
 1275 'SUBST_FILES.id= file' \
 1276 'SUBST_SED.id= -e s,no-op,no-op,g' \
 1277 'SUBST_SED.id+= -e s,from,to,' \
 1278 'SUBST_NOOP_OK.id= no' \
 1279 '' \
 1280 '.include "prepare-subst.mk"' \
 1281 '.include "mk/subst.mk"'
 1282 create_file_lines "file" \
 1283 'from'
 1284
 1285 run_bmake "testcase.mk" "subst-id" 1> "$tmpdir/out" 2>&1 \
 1286 && exitcode=0 || exitcode=$?
 1287
 1288 assert_that "out" --file-is-lines \
 1289 '=> Substituting "id" in file'
 1290 assert_that "file" --file-is-lines \
 1291 'to'
 1292
 1293 test_case_end
 1294fi
 1295
 1296
 1297if test_case_begin "identity + no-op substitution"; then
 1298
 1299 # If there were only an identity substitution, it wouldn't be an
 1300 # error. But since there is a regular substitution as well,
 1301 # that substitution is an unexpected no-op and is therefore
 1302 # flagged as an error.
 1303
 1304 create_file_lines "testcase.mk" \
 1305 'SUBST_CLASSES+= id' \
 1306 'SUBST_FILES.id= file' \
 1307 'SUBST_SED.id= -e s,no-op,no-op,g' \
 1308 'SUBST_SED.id+= -e s,from,to,' \
 1309 'SUBST_NOOP_OK.id= no' \
 1310 '' \
 1311 '.include "prepare-subst.mk"' \
 1312 '.include "mk/subst.mk"'
 1313 create_file_lines "file" \
 1314 'other'
 1315
 1316 run_bmake "testcase.mk" "subst-id" 1> "$tmpdir/out" 2>&1 \
 1317 && exitcode=0 || exitcode=$?
 1318
 1319 assert_that "out" --file-is-lines \
 1320 '=> Substituting "id" in file' \
 1321 'warning: [subst.mk:id] Nothing changed in "file".' \
 1322 'fail: [subst.mk:id] The filename pattern "file" has no effect.' \
 1323 '*** Error code 1' \
 1324 '' \
 1325 'Stop.' \
 1326 "$make: stopped in $PWD"
 1327 assert_that "file" --file-is-lines \
 1328 'other'
 1329
 1330 test_case_end
 1331fi

cvs diff -r1.10 -r1.11 pkgsrc/regress/infra-unittests/test.subr (switch to unified diff)

--- pkgsrc/regress/infra-unittests/test.subr 2020/04/26 12:46:33 1.10
+++ pkgsrc/regress/infra-unittests/test.subr 2020/04/29 18:33:56 1.11
@@ -1,344 +1,344 @@ @@ -1,344 +1,344 @@
1#! /bin/sh 1#! /bin/sh
2# $NetBSD: test.subr,v 1.10 2020/04/26 12:46:33 rillig Exp $ 2# $NetBSD: test.subr,v 1.11 2020/04/29 18:33:56 rillig Exp $
3# 3#
4# This file defines utilities for testing Makefile fragments and shell 4# This file defines utilities for testing Makefile fragments and shell
5# programs from the pkgsrc infrastructure. While testing one part of the 5# programs from the pkgsrc infrastructure. While testing one part of the
6# infrastructure, other parts can be mocked away. 6# infrastructure, other parts can be mocked away.
7# 7#
8# A test case is defined by the following functions: 8# A test case is defined by the following functions:
9# 9#
10# test_case_begin 10# test_case_begin
11# test_case_set_up 11# test_case_set_up
12# test_case_tear_down 12# test_case_tear_down
13# test_case_end 13# test_case_end
14# 14#
15# These functions form the structure for a test. To define a test, use the 15# These functions form the structure for a test. To define a test, use the
16# following pattern: 16# following pattern:
17# 17#
18# if test_case_begin "description of the test"; then 18# if test_case_begin "description of the test"; then
19# ... 19# ...
20# test_end 20# test_end
21# fi 21# fi
22# 22#
23# The functions test_case_set_up and test_case_tear_down can be defined in the 23# The functions test_case_set_up and test_case_tear_down can be defined in the
24# test file to provide a test fixture that is common to all test cases. These 24# test file to provide a test fixture that is common to all test cases. These
25# functions are called by test_case_begin and test_case_end, respectively. 25# functions are called by test_case_begin and test_case_end, respectively.
26# 26#
27# During a test case, the following variables are defined: 27# During a test case, the following variables are defined:
28# 28#
29# tmpdir a directory for creating intermediate files 29# tmpdir a directory for creating intermediate files
30# pkgsrcdir the real pkgsrc directory 30# pkgsrcdir the real pkgsrc directory
31# mocked_pkgsrcdir 31# mocked_pkgsrcdir
32# the directory where the mock files are installed, 32# the directory where the mock files are installed,
33# which override the Makefile fragments from the real 33# which override the Makefile fragments from the real
34# pkgsrc infrastructure 34# pkgsrc infrastructure
35# 35#
36# 36#
37# Setting up a test 37# Setting up a test
38# 38#
39# mock_cmd 39# mock_cmd
40# Returns the path to a newly created shell program whose behavior 40# Returns the path to a newly created shell program whose behavior
41# (output and exit status) is specified by pairs of 41# (output and exit status) is specified by pairs of
42# --when-args/--then-output or --when-args/--then-exit. 42# --when-args/--then-output or --when-args/--then-exit.
43# 43#
44# Example: 44# Example:
45# 45#
46# hello=$(mock_cmd mock-hello \ 46# hello=$(mock_cmd mock-hello \
47# --when-args "" --then-output "Hello, world!" \ 47# --when-args "" --then-output "Hello, world!" \
48# --when-args "-t" --then-output "hello, world" \ 48# --when-args "-t" --then-output "hello, world" \
49# --when-args "-?" --then-exit 1 49# --when-args "-?" --then-exit 1
50# ) 50# )
51# 51#
52# create_file $filename <<EOF ... EOF 52# create_file $filename <<EOF ... EOF
53# Creates a file in the temporary directory. The filename is relative 53# Creates a file in the temporary directory. The filename is relative
54# to the temporary directory. 54# to the temporary directory.
55# 55#
56# create_file_lines $filename $line1 $line2 ... 56# create_file_lines $filename $line1 $line2 ...
57# Creates a file in the temporary directory containing the given lines. 57# Creates a file in the temporary directory containing the given lines.
58# 58#
59# create_pkgsrc_file $filename <<EOF ... EOF 59# create_pkgsrc_file $filename <<EOF ... EOF
60# Creates a file in the temporary pkgsrc directory. If it is a Makefile 60# Creates a file in the temporary pkgsrc directory. If it is a Makefile
61# fragment, it will be included instead of the one in the real pkgsrc 61# fragment, it will be included instead of the one in the real pkgsrc
62# infrastructure. 62# infrastructure.
63# 63#
64# This is typically used for creating an empty file for mk/bsd.prefs.mk 64# This is typically used for creating an empty file for mk/bsd.prefs.mk
65# or similar files that are included by the file that is currently under 65# or similar files that are included by the file that is currently under
66# test. 66# test.
67# 67#
68# Example: 68# Example:
69# 69#
70# create_pkgsrc_file "mk/pkg-build-options.mk" <<EOF 70# create_pkgsrc_file "mk/pkg-build-options.mk" <<EOF
71# # nothing 71# # nothing
72# EOF 72# EOF
73# 73#
74# 74#
75# Running the code to be tested 75# Running the code to be tested
76# 76#
77# run_bmake $filename $bmake_args... 77# run_bmake $filename $bmake_args...
78# Runs bmake with the correct environment so that it picks up the mocked 78# Runs bmake with the correct environment so that it picks up the mocked
79# infrastructure files first and then the ones from the real pkgsrc 79# infrastructure files first and then the ones from the real pkgsrc
80# installation. The filename is relative to the temporary directory. 80# installation. The filename is relative to the temporary directory.
81# 81#
82# 82#
83# Checking the result 83# Checking the result
84# 84#
85# assert_that $actual --equals $expected 85# assert_that $actual --equals $expected
86# Complains loudly if the string $actual is not equal to $expected. 86# Complains loudly if the string $actual is not equal to $expected.
87# 87#
88# assert_that $tmpfile --file-contains-exactly $content 88# assert_that $tmpfile --file-contains-exactly $content
89# Complains loudly if the file in $tmpdir does not contain the $content, 89# Complains loudly if the file in $tmpdir does not contain the $content,
90# plus a trailing newline. 90# plus a trailing newline.
91# 91#
92# assert_that $tmpfile1 --file-equals $tmpfile2 92# assert_that $tmpfile1 --file-equals $tmpfile2
93# Complains loudly if the two files in $tmpdir differ. 93# Complains loudly if the two files in $tmpdir differ.
94# 94#
95# assert_that $tmpfile --file-is-empty 95# assert_that $tmpfile --file-is-empty
96# Complains loudly if the file in $tmpdir is not empty. 96# Complains loudly if the file in $tmpdir is not empty.
97# 97#
98# assert_that $tmpfile --file-is-lines $lines... 98# assert_that $tmpfile --file-is-lines $lines...
99# Complains loudly if the file in $tmpdir does not consist of exactly 99# Complains loudly if the file in $tmpdir does not consist of exactly
100# the given lines. 100# the given lines.
101# 101#
102# assert_succeed 102# assert_succeed
103# Counts one succeeded assertion, for the verbose statistics. 103# Counts one succeeded assertion, for the verbose statistics.
104# 104#
105# assert_fail $format $args... 105# assert_fail $format $args...
106# Marks the current test as failed but continues to execute it. 106# Marks the current test as failed but continues to execute it.
107# 107#
108# 108#
109# Misc 109# Misc
110# 110#
111# cleanup 111# cleanup
112# If this variable is yes (the default), clean up the temporary 112# If this variable is yes (the default), clean up the temporary
113# directory after the test has run successfully. 113# directory after the test has run successfully.
114# 114#
115 115
116set -eu 116set -eu
117 117
118: "${cleanup:=yes}" 118: "${cleanup:=yes}"
119: "${make:=bmake}" 119: "${make:=bmake}"
120: "${if_verbose=:}" 120: "${if_verbose=:}"
121tmpdir="${TMP:-/tmp}/infra-unittests-$$" 121tmpdir="${TMP:-/tmp}/infra-unittests-$$"
122mocked_pkgsrcdir="$tmpdir/pkgsrc" 122mocked_pkgsrcdir="$tmpdir/pkgsrc"
123rm -rf "$tmpdir" 123rm -rf "$tmpdir"
124mkdir -p "$mocked_pkgsrcdir" 124mkdir -p "$mocked_pkgsrcdir"
125 125
126pkgsrcdir="" 126pkgsrcdir=""
127for relative_pkgsrcdir in . .. ../.. ../../..; do 127for relative_pkgsrcdir in . .. ../.. ../../..; do
128 if [ -f "$relative_pkgsrcdir/mk/bsd.pkg.mk" ]; then 128 if [ -f "$relative_pkgsrcdir/mk/bsd.pkg.mk" ]; then
129 pkgsrcdir="$PWD/$relative_pkgsrcdir" 129 pkgsrcdir="$PWD/$relative_pkgsrcdir"
130 break 130 break
131 fi 131 fi
132done 132done
133if [ -z "$pkgsrcdir" ]; then 133if [ -z "$pkgsrcdir" ]; then
134 printf 'error: must be run from somewhere inside the pkgsrc directory\n' 1>&2 134 printf 'error: must be run from somewhere inside the pkgsrc directory\n' 1>&2
135 exit 1 135 exit 1
136fi 136fi
137 137
138verbose_printf() { 138verbose_printf() {
139 $if_verbose printf "$@" 139 $if_verbose printf "$@"
140} 140}
141 141
142test_case_name="unknown test" 142test_case_name="unknown test"
143test_case_begun=0 143test_case_begun=0
144test_case_ended=0 144test_case_ended=0
145 145
146test_case_begin() { 146test_case_begin() {
147 test_case_name="$1" 147 test_case_name="$1"
148 test_case_begun="`expr "$test_case_begun" + 1`" 148 test_case_begun="`expr "$test_case_begun" + 1`"
149 verbose_printf 'running test case "%s"\n' "$test_case_name" 149 verbose_printf 'running test case "%s"\n' "$test_case_name"
150 150
151 test_case_set_up 151 test_case_set_up
152} 152}
153 153
154# Can be redefined by actual tests. 154# Can be redefined by actual tests.
155test_case_set_up() { 155test_case_set_up() {
156} 156}
157 157
158# Can be redefined by actual tests. 158# Can be redefined by actual tests.
159test_case_tear_down() { 159test_case_tear_down() {
160} 160}
161 161
162test_case_end() { 162test_case_end() {
163 test_case_tear_down 163 test_case_tear_down
164 164
165 test_case_ended="`expr "$test_case_ended" + 1`" 165 test_case_ended="`expr "$test_case_ended" + 1`"
166 test "$test_case_ended" = "$test_case_begun" \ 166 test "$test_case_ended" = "$test_case_begun" \
167 || assert_fail 'unbalanced test_case_begin (%d) and test_case_end (%d)\n' \ 167 || assert_fail 'unbalanced test_case_begin (%d) and test_case_end (%d)\n' \
168 "$test_case_begun" "$test_case_ended" 168 "$test_case_begun" "$test_case_ended"
169 169
170 test_case_name="unknown test" 170 test_case_name="unknown test"
171} 171}
172 172
173test_subr_cleanup() { 173test_subr_cleanup() {
174 exit_status=$? 174 exit_status=$?
175 if [ $exit_status -ne 0 ]; then 175 if [ $exit_status -ne 0 ]; then
176 printf 'info: the test files are in %s\n' "$tmpdir" 1>&2 176 printf 'info: the test files are in %s\n' "$tmpdir" 1>&2
177 exit $exit_status 177 exit $exit_status
178 fi 178 fi
179 179
180 [ "$cleanup" = "yes" ] && rm -rf "$tmpdir" 180 [ "$cleanup" = "yes" ] && rm -rf "$tmpdir"
181 181
182 verbose_printf '%s%d assertions succeeded, %d failed\n' \ 182 verbose_printf '%s%d assertions succeeded, %d failed\n' \
183 "$assert_fail_sep" "$assert_succeeded" "$assert_failed" 183 "$assert_fail_sep" "$assert_succeeded" "$assert_failed"
184 184
185 if [ "$assert_failed" != 0 ]; then 185 if [ "$assert_failed" != 0 ]; then
186 exit 1 186 exit 1
187 fi 187 fi
188} 188}
189trap "test_subr_cleanup" EXIT 189trap "test_subr_cleanup" EXIT
190 190
191mock_cmd() { 191mock_cmd() {
192 cmdname="$1" 192 cmdname="$1"
193 shift 1 193 shift 1
194 194
195 { 195 {
196 printf '#! /bin/sh\n' 196 printf '#! /bin/sh\n'
197 printf '\n' 197 printf '\n'
198 198
199 while [ $# -ge 4 ]; do 199 while [ $# -ge 4 ]; do
200 case $1,$3 in 200 case $1,$3 in
201 (--when-args,--then-output) 201 (--when-args,--then-output)
202 cat <<EOF 202 cat <<EOF
203[ "x\$*" = "x$2" ] && { printf '%s\n' "$4" && exit 0; } 203[ "x\$*" = "x$2" ] && { printf '%s\n' "$4" && exit 0; }
204 204
205EOF 205EOF
206 shift 4 206 shift 4
207 ;; 207 ;;
208 (--when-args,--then-exit) 208 (--when-args,--then-exit)
209 cat <<EOF 209 cat <<EOF
210[ "x\$*" = "x$2" ] && exit $4 210[ "x\$*" = "x$2" ] && exit $4
211 211
212EOF 212EOF
213 shift 4 213 shift 4
214 ;; 214 ;;
215 *) printf 'error: invalid arguments to mock_cmd: %s\n' "$*" 1>&2 215 *) printf 'error: invalid arguments to mock_cmd: %s\n' "$*" 1>&2
216 exit 1 216 exit 1
217 ;; 217 ;;
218 esac 218 esac
219 done 219 done
220 cat <<EOF 220 cat <<EOF
221printf 'error: %s: no mock behavior defined for arguments "%s"\n' "\$0" "\$*" 1>&2 221printf 'error: %s: no mock behavior defined for arguments "%s"\n' "\$0" "\$*" 1>&2
222exit 1 222exit 1
223EOF 223EOF
224 } > "$tmpdir/$cmdname" 224 } > "$tmpdir/$cmdname"
225 chmod +x "$tmpdir/$cmdname" 225 chmod +x "$tmpdir/$cmdname"
226 226
227 printf '%s\n' "$tmpdir/$cmdname" 227 printf '%s\n' "$tmpdir/$cmdname"
228} 228}
229 229
230create_file() { 230create_file() {
231 assert_that "$#" --equals 1 231 assert_that "$#" --equals 1
232 mkdir -p "$(dirname "$tmpdir/$1")" 232 mkdir -p "$(dirname "$tmpdir/$1")"
233 cat > "$tmpdir/$1" 233 cat > "$tmpdir/$1"
234} 234}
235 235
236create_file_lines() { 236create_file_lines() {
237 mkdir -p "$(dirname "$tmpdir/$1")" 237 mkdir -p "$(dirname "$tmpdir/$1")"
238 _cfl_filename="$1"; shift 238 _cfl_filename="$1"; shift
239 printf '%s\n' "$@" > "$tmpdir/$_cfl_filename" 239 printf '%s\n' "$@" > "$tmpdir/$_cfl_filename"
240} 240}
241 241
242create_pkgsrc_file() { 242create_pkgsrc_file() {
243 mkdir -p "$(dirname "$mocked_pkgsrcdir/$1")" 243 mkdir -p "$(dirname "$mocked_pkgsrcdir/$1")"
244 cat > "$mocked_pkgsrcdir/$1" 244 cat > "$mocked_pkgsrcdir/$1"
245} 245}
246 246
247run_bmake() { 247run_bmake() {
248 cat <<EOF > "$tmpdir/test.subr.main.mk" 248 cat <<EOF > "$tmpdir/test.subr.main.mk"
249PKGSRCDIR= $relative_pkgsrcdir 249PKGSRCDIR= $pkgsrcdir
250.PATH: $mocked_pkgsrcdir 250.PATH: $mocked_pkgsrcdir
251.PATH: $pkgsrcdir 251.PATH: $pkgsrcdir
252.include "$1" 252.include "$1"
253EOF 253EOF
254 shift 254 shift
255 255
256 "$make" -f "$tmpdir/test.subr.main.mk" "$@" 256 "$make" -f "$tmpdir/test.subr.main.mk" "$@"
257} 257}
258 258
259assert_succeeded=0 259assert_succeeded=0
260assert_failed=0 260assert_failed=0
261assert_fail_sep='' 261assert_fail_sep=''
262 262
263assert_succeed() { 263assert_succeed() {
264 assert_succeeded=`expr "$assert_succeeded" + 1` 264 assert_succeeded=`expr "$assert_succeeded" + 1`
265} 265}
266 266
267assert_fail() { 267assert_fail() {
268 printf '%s' "$assert_fail_sep" 1>&2 268 printf '%s' "$assert_fail_sep" 1>&2
269 assert_fail_sep=' 269 assert_fail_sep='
270' 270'
271 271
272 printf 'assertion failed in "%s": ' "$test_case_name" 1>&2 272 printf 'assertion failed in "%s": ' "$test_case_name" 1>&2
273 273
274 printf "$@" 1>&2 274 printf "$@" 1>&2
275 assert_failed=`expr "$assert_failed" + 1` 275 assert_failed=`expr "$assert_failed" + 1`
276} 276}
277 277
278tmpdir_equal() { 278tmpdir_equal() {
279 (cd "$tmpdir" && diff -u -- "$@" >/dev/null) || return 1 279 (cd "$tmpdir" && diff -u -- "$@" >/dev/null) || return 1
280} 280}
281 281
282tmpdir_diff() { 282tmpdir_diff() {
283 # removes the timestamps from the diff files since these are not 283 # removes the timestamps from the diff files since these are not
284 # useful in tests. 284 # useful in tests.
285 (cd "$tmpdir" && diff -u -- "$@" || true) \ 285 (cd "$tmpdir" && diff -u -- "$@" || true) \
286 | awk '/^(---|[+][+][+]) / { print($1, $2); next } { print }' 1>&2 286 | awk '/^(---|[+][+][+]) / { print($1, $2); next } { print }' 1>&2
287} 287}
288 288
289assert_that() { 289assert_that() {
290 case "$2" in 290 case "$2" in
291 (--equals) 291 (--equals)
292 if [ "x$1" = "x$3" ]; then 292 if [ "x$1" = "x$3" ]; then
293 assert_succeed 293 assert_succeed
294 return 0 294 return 0
295 fi 295 fi
296 assert_fail '\n expected: <%s>\n but was: <%s>\n' "$3" "$1" 296 assert_fail '\n expected: <%s>\n but was: <%s>\n' "$3" "$1"
297 ;; 297 ;;
298 298
299 (--file-contains-exactly) 299 (--file-contains-exactly)
300 printf '%s\n' "$3" > "$tmpdir/expected" 300 printf '%s\n' "$3" > "$tmpdir/expected"
301 if tmpdir_equal "expected" "$1"; then 301 if tmpdir_equal "expected" "$1"; then
302 assert_succeed 302 assert_succeed
303 return 0 303 return 0
304 fi 304 fi
305 assert_fail 'file "%s" has unexpected content:\n' "$1" 305 assert_fail 'file "%s" has unexpected content:\n' "$1"
306 tmpdir_diff "expected" "$1" 306 tmpdir_diff "expected" "$1"
307 ;; 307 ;;
308 308
309 (--file-equals) 309 (--file-equals)
310 if tmpdir_equal "$3" "$1"; then 310 if tmpdir_equal "$3" "$1"; then
311 assert_succeed 311 assert_succeed
312 return 0 312 return 0
313 fi 313 fi
314 assert_fail 'files "%s" and "%s" differ:\n' "$1" "$3" 314 assert_fail 'files "%s" and "%s" differ:\n' "$1" "$3"
315 tmpdir_diff "$3" "$1" 315 tmpdir_diff "$3" "$1"
316 ;; 316 ;;
317 317
318 (--file-is-empty) 318 (--file-is-empty)
319 if tmpdir_equal "/dev/null" "$1"; then 319 if tmpdir_equal "/dev/null" "$1"; then
320 assert_succeed 320 assert_succeed
321 return 0 321 return 0
322 fi 322 fi
323 assert_fail 'file "%s" is not empty:\n' "$1" 323 assert_fail 'file "%s" is not empty:\n' "$1"
324 tmpdir_diff "/dev/null" "$1" 324 tmpdir_diff "/dev/null" "$1"
325 ;; 325 ;;
326 326
327 (--file-is-lines) 327 (--file-is-lines)
328 _assert_that_tmp_actual="$1" 328 _assert_that_tmp_actual="$1"
329 _assert_that_filename="$1"; shift 2 329 _assert_that_filename="$1"; shift 2
330 330
331 printf '%s\n' "$@" > "$tmpdir/expected" 331 printf '%s\n' "$@" > "$tmpdir/expected"
332 if tmpdir_equal "expected" "$_assert_that_tmp_actual"; then 332 if tmpdir_equal "expected" "$_assert_that_tmp_actual"; then
333 assert_succeed 333 assert_succeed
334 return 0 334 return 0
335 fi 335 fi
336 assert_fail 'file "%s" has unexpected content:\n' "$_assert_that_filename" 336 assert_fail 'file "%s" has unexpected content:\n' "$_assert_that_filename"
337 tmpdir_diff "expected" "$_assert_that_tmp_actual" 337 tmpdir_diff "expected" "$_assert_that_tmp_actual"
338 ;; 338 ;;
339 339
340 (*) 340 (*)
341 printf 'usage: assert_that <expr> --equals <expr>\n' 1>&2 341 printf 'usage: assert_that <expr> --equals <expr>\n' 1>&2
342 exit 1 342 exit 1
343 esac 343 esac
344} 344}