#!/usr/bin/env -S bats --report-formatter junit --formatter tap -j 8
# -*-sh-*-
# shellcheck disable=SC2030,SC2031

load ../common/test_helper_functions

setup_file() {
	TESTNAME="modules"

	export TESTNAME
}

setup() {
	OUTPUT="$(mktemp)"

	export OUTPUT
}

teardown() {
	rm -f "${OUTPUT}"
}

# The "module list" message when no module is loaded differs between Lmod
# and Environment Modules
assert_no_modules_loaded() {
	[[ "${output}" == *"No modules loaded"* || "${output}" == *"No Modulefiles Currently Loaded"* ]] || flunk "unexpected module list output: ${output}"
}

@test "[${TESTNAME}] module purge" {
	run module purge
	assert_success
}

@test "[${TESTNAME}] module list" {
	module purge || exit 1
	run module list
	assert_success
	assert_no_modules_loaded
}

@test "[${TESTNAME}] module help" {
	module purge || exit 1
	export MODULEPATH=./example-modules:"${MODULEPATH}"
	module help test-module &>"${OUTPUT}" || exit 1
	# drop empty and separator lines to get the help message last
	local my_output
	my_output=$(sed '/^$/d; /^-/d' "${OUTPUT}" | tail -1)
	assert_equal "Help message from test module" "${my_output}"
}

@test "[${TESTNAME}] module load/unload" {
	module purge || exit 1
	export MODULEPATH=./example-modules:"${MODULEPATH}"

	# verify env variable is not set prior to load
	if [ -n "${TEST_MODULE}" ]; then
		exit 1
	fi

	# load test-module and verify load works
	module load test-module || exit 1
	module list &>"${OUTPUT}" || exit 1
	grep -q '1) test-module' "${OUTPUT}" || flunk "test-module not loaded"

	# verify env variable was added correctly
	assert_equal "beeblebrox" "${TEST_MODULE}"

	# reload same module and verify no error
	run module load test-module
	assert_success

	# verify load of non-existent module generates error
	run module load test-module-it-should-no-workie
	assert_failure

	# remove test-module and verify
	module unload test-module || exit 1
	run module list
	assert_success
	assert_no_modules_loaded

	# verify environment variable was removed
	[ -z "${TEST_MODULE}" ]
	assert_success
}

@test "[${TESTNAME}] module whatis" {
	module purge || exit 1
	export MODULEPATH=./example-modules:"${MODULEPATH}"
	module whatis test-module &>"${OUTPUT}" || exit 1
	local my_output
	# drop empty and separator lines, then normalize spacing
	my_output=$(sed '/^$/d; /^-/d; s/ \+//; s/ *$//' "${OUTPUT}")
	assert_equal "test-module: whatis: test-module" "${my_output}"
}

@test "[${TESTNAME}] module swap" {
	module purge || exit 1
	export MODULEPATH=./example-modules:"${MODULEPATH}"
	module load test-module || exit 1

	# verify family conflict: depending on the module tool configuration,
	# loading another module of the same family is either refused or
	# replaces the loaded module, but both are never loaded together
	module load test2-module 2>/dev/null || true
	if [[ ":${LOADEDMODULES}:" == *":test-module:"* ]]; then
		[[ ":${LOADEDMODULES}:" != *":test2-module:"* ]] || flunk "test-module and test2-module both loaded"
		assert_equal "beeblebrox" "${TEST_MODULE}"
	else
		[[ ":${LOADEDMODULES}:" == *":test2-module:"* ]] || flunk "test2-module not loaded after conflict resolution"
		module swap test2-module test-module || exit 1
	fi

	module swap test-module test2-module || exit 1

	# verify correct env variable loaded after swap
	assert_equal "zaphod" "${TEST_MODULE}"

	# swap back and verify env variable
	module swap test2-module test-module || exit 1
	assert_equal "beeblebrox" "${TEST_MODULE}"
}

@test "[${TESTNAME}] path updated" {
	module purge || exit 1
	export MODULEPATH=./example-modules:"${MODULEPATH}"
	local orig_path="${PATH}"

	if [ -z "${MANPATH}" ]; then
		export MANPATH="/foo"
	fi

	local orig_manpath="${MANPATH}"

	# verify path after module load
	module load test-module || exit 1
	assert_equal "/my/test-module-path:${orig_path}" "${PATH}"

	# verify path after load of same module
	module load test-module || exit 1
	assert_equal "/my/test-module-path:${orig_path}" "${PATH}"

	# verify path after swap to new module
	module swap test-module test2-module || exit 1
	assert_equal "/my/test2-module-path:${orig_path}" "${PATH}"
	if [[ "${MANPATH}" != *"${orig_manpath}"* ]]; then
		flunk "${orig_manpath} missing from MANPATH"
	fi
	if [[ "${MANPATH}" != *"/my/test2-manpath"* ]]; then
		flunk "/my/test2-manpath missing from MANPATH"
	fi

	# verify path after addition of a new module
	module load test3-module || exit 1
	assert_equal "/my/test3-module-path:/my/test2-module-path:${orig_path}" "${PATH}"
	if [[ "${MANPATH}" != *"${orig_manpath}"* ]]; then
		flunk "${orig_manpath} missing from MANPATH"
	fi
	if [[ "${MANPATH}" != *"/my/test2-manpath"* ]]; then
		flunk "/my/test2-manpath missing from MANPATH"
	fi
	if [[ "${MANPATH}" != *"/my/test3-manpath"* ]]; then
		flunk "/my/test3-manpath missing from MANPATH"
	fi

	# verify path after removal of test modules
	module delete test2-module || exit 1
	assert_equal "/my/test3-module-path:${orig_path}" "${PATH}"
	module remove test3-module || exit 1
	assert_equal "${orig_path}" "${PATH}"
	assert_equal "${orig_manpath}" "${MANPATH}"
}

@test "[${TESTNAME}] module depends-on" {
	module purge || exit 1
	export MODULEPATH=./example-modules:"${MODULEPATH}"

	# verify dependent load
	module load test4-module || exit 1
	module list &>"${OUTPUT}" || exit 1
	grep -q '1) test3-module' "${OUTPUT}" || flunk "test3-module not loaded as dependency"
	grep -q '2) test4-module' "${OUTPUT}" || flunk "test4-module not loaded"

	# verify dependent unload
	module unload test4-module || exit 1
	run module list
	assert_success
	assert_no_modules_loaded
}
