#! /bin/sh
# $NetBSD: check-portability.sh,v 1.7 2021/01/04 21:10:01 rillig Exp $
#
# Test cases for mk/check/check-portability.*.
#

set -eu

. "./test.subr"

# Runs the shell program for all files in the current directory.
check_portability_sh() {
	env	PATCHDIR='patches' \
		PREFIX='/nonexistent' \
		"$@" \
		sh "$pkgsrcdir/mk/check/check-portability.sh" \
		1>"$tmpdir/out" 2>&1 \
	&& exitcode=0 || exitcode=$?
}

# Runs the AWK program in standalone mode for the given file.
check_portability_awk() {
	env	CK_FNAME="$1" \
		CK_PROGNAME='check-portability.awk' \
		awk	-f "$pkgsrcdir/mk/check/check-subr.awk" \
			-f "$pkgsrcdir/mk/check/check-portability.awk" \
			"$1" \
		1>"$tmpdir/out" 2>&1 \
	&& exitcode=0 || exitcode=$?
}


if test_case_begin "test ... = ..."; then

	create_file_lines 'file' \
		'if [ "$var" = value ]; then' \
		'  ...' \
		'elif test "$var" = value ]; then' \
		'  ...' \
		'fi'

	check_portability_awk 'file'

	assert_that "$tmpdir/out" --file-is-empty
	assert_that $exitcode --equals 0

	test_case_end
fi


if test_case_begin 'test ... == ...'; then

	create_file_lines 'file' \
		'if [ "$var" == value ]; then' \
		'  ...' \
		'elif test "$var" == value ]; then' \
		'  ...' \
		'fi'

	check_portability_awk 'file'

	create_file 'expected' <<'EOF'
ERROR: [check-portability.awk] => Found test ... == ...:
ERROR: [check-portability.awk] file:1: if [ "$var" == value ]; then
ERROR: [check-portability.awk] file:3: elif test "$var" == value ]; then

Explanation:
===========================================================================
The "test" command, as well as the "[" command, are not required to know
the "==" operator. Only a few implementations like bash and some
versions of ksh support it.

When you run "test foo == foo" on a platform that does not support the
"==" operator, the result will be "false" instead of "true". This can
lead to unexpected behavior.

There are two ways to fix this error message. If the file that contains
the "test ==" is needed for building the package, you should create a
patch for it, replacing the "==" operator with "=". If the file is not
needed, add its name to the CHECK_PORTABILITY_SKIP variable in the
package Makefile.
===========================================================================

EOF
	assert_that "$tmpdir/out" --file-equals 'expected'
	assert_that $exitcode --equals 1

	test_case_end
fi


if test_case_begin 'configure patched, configure.in bad'; then

	create_file_lines 'patches/patch-aa' \
		'+++ configure 2020-05-04'
	create_file_lines 'configure' \
		'#! /bin/sh' \
		'good'
	create_file_lines 'configure.in' \
		'test a == b'

	check_portability_sh \
		'CHECK_PORTABILITY_EXPERIMENTAL=yes'

	assert_that "$tmpdir/out" --file-is-empty
	assert_that $exitcode --equals 0

	test_case_end
fi


if test_case_begin 'Makefile.in patched, Makefile.am bad'; then

	# As of 2020-05-05, Makefile.am is not checked at all since only
	# very few packages actually use that file during the build.

	create_file_lines 'patches/patch-aa' \
		'+++ Makefile.in 2020-05-05'
	create_file_lines 'Makefile.in' \
		'test a = b'
	create_file_lines 'Makefile.am' \
		'test a == b'

	check_portability_sh \
		'CHECK_PORTABILITY_EXPERIMENTAL=yes'

	assert_that "$tmpdir/out" --file-is-empty
	assert_that $exitcode --equals 0

	test_case_end
fi


if test_case_begin 'files that are usually not used for building'; then

	# The following files are mostly interesting to the upstream
	# developers and are not used during the actual build, except
	# if the package rebuilds everything using the GNU autotools.

	create_file_lines 'configure.ac' \
		'test a == b'
	create_file_lines 'Makefile.am' \
		'test a == b'

	check_portability_sh \
		'CHECK_PORTABILITY_EXPERIMENTAL=yes'

	assert_that "$tmpdir/out" --file-is-empty
	assert_that $exitcode --equals 0

	test_case_end
fi


if test_case_begin 'configure patched and still bad'; then

	create_file_lines 'patches/patch-aa' \
		'+++ configure 2020-05-04'
	create_file_lines 'configure' \
		'#! /bin/sh' \
		'test a == b'

	check_portability_sh \
		'CHECK_PORTABILITY_EXPERIMENTAL=yes'

	create_file 'expected' <<'EOF'
ERROR: [check-portability.awk] => Found test ... == ...:
ERROR: [check-portability.awk] configure:2: test a == b

Explanation:
===========================================================================
The "test" command, as well as the "[" command, are not required to know
the "==" operator. Only a few implementations like bash and some
versions of ksh support it.

When you run "test foo == foo" on a platform that does not support the
"==" operator, the result will be "false" instead of "true". This can
lead to unexpected behavior.

There are two ways to fix this error message. If the file that contains
the "test ==" is needed for building the package, you should create a
patch for it, replacing the "==" operator with "=". If the file is not
needed, add its name to the CHECK_PORTABILITY_SKIP variable in the
package Makefile.
===========================================================================

EOF
	assert_that "$tmpdir/out" --file-equals 'expected'
	assert_that $exitcode --equals 1

	test_case_end
fi


if test_case_begin 'special characters in filenames'; then

	# Ensure that the filename matching for patched files
	# does not treat special characters as shell metacharacters.

	create_file_lines 'patches/patch-aa' \
		'+++ [[[[(`" 2020-05-04'
	create_file_lines '+++ [[[[(`"' \
		'#! /bin/sh' \
		'test a = b'

	check_portability_sh \
		'CHECK_PORTABILITY_EXPERIMENTAL=yes'

	assert_that "$tmpdir/out" --file-is-empty
	assert_that $exitcode --equals 0

	test_case_end
fi


if test_case_begin 'no patches'; then

	# Ensure that no error message is printed when there are no
	# patch files.

	create_file_lines 'file' \
		'#! /bin/sh' \
		'test a = b'

	check_portability_sh \
		CHECK_PORTABILITY_EXPERIMENTAL=no

	assert_that "$tmpdir/out" --file-is-empty
	assert_that $exitcode --equals 0

	test_case_end
fi


if test_case_begin 'no experimental by default'; then

	create_file_lines 'configure.in' \
		'test a == b'

	check_portability_sh \
		'CHECK_PORTABILITY_EXPERIMENTAL=no'

	assert_that "$tmpdir/out" --file-is-empty
	assert_that $exitcode --equals 0

	test_case_end
fi


if test_case_begin 'always skip tilde files'; then


	# Projects that use GNU autoconf 2.70 are reported to include
	# backup files like 'configure~' in their distribution, for
	# whatever reason.  Since these files are not used by pkgsrc,
	# they should be ignored.
	#
	# Since the filename is not one of the well-known ones, the file
	# must start with a '#!' line to be actually recognized as a shell
	# program.
	create_file_lines 'configure~' \
		'#! /bin/sh' \
		'test a == b'

	check_portability_sh \
		'CHECK_PORTABILITY_EXPERIMENTAL=no'

	assert_that "$tmpdir/out" --file-is-empty
	assert_that $exitcode --equals 0

	test_case_end
fi
