##############################################################################
#   Modules Revision 3.0
#   Providing a flexible user environment
#
#   File:		modules.70-maint/%M%
#   Revision:		%I%
#   First Edition:	2019/12/16
#   Last Mod.:		%U%, %G%
#
#   Authors:		Xavier Delaruelle, xavier.delaruelle@cea.fr
#
#   Description:	Testuite testsequence
#   Command:
#   Modulefiles:
#   Sub-Command:    list, savelist, avail, whatis, search
#
#   Comment:	%C{
#           Test JSON format output
#		}C%
#
##############################################################################

# ensure regular avail search match is set for these tests
setenv_var MODULES_SEARCH_MATCH starts_with

# ensure avail tests are made using in depth mode
setenv_var MODULES_AVAIL_INDEPTH 1

# ensure last matching element is returned when unloading modules
setenv_var MODULES_UNLOAD_MATCH_ORDER returnlast

set mp $modpath.2
set mpre [regsub -all "\(\[.+?\]\)" $mp {\\\1}]

# setup specific environment
setenv_path_var MODULEPATH $mp


# check json output on supported sub-commands over the different module kinds
# (modulefile, symbols, alias, directory, virtual modules)
testouterr_cmd sh {avail nocase/ --json} OK "{\"$mp\": {
\"nocase/deep/3\": { \"name\": \"nocase/deep/3\", \"type\": \"modulefile\", \"symbols\": \[\], \"tags\": \[\], \"pathname\": \"$mp/nocase/deep/3\"},
\"nocase/1\": { \"name\": \"nocase/1\", \"type\": \"modulefile\", \"symbols\": \[ \"vers\" \], \"tags\": \[\], \"pathname\": \"$mp/nocase/1\"},
\"nocase/alias\": { \"name\": \"nocase/alias\", \"type\": \"alias\", \"symbols\": \[\], \"tags\": \[\], \"target\": \"nocase/1\"},
\"nocase/ialias\": { \"name\": \"nocase/ialias\", \"type\": \"alias\", \"symbols\": \[\], \"tags\": \[\], \"target\": \"Nocase/Virt\"},
\"nocase/virt\": { \"name\": \"nocase/virt\", \"type\": \"modulefile\", \"symbols\": \[\], \"tags\": \[\], \"pathname\": \"$mp/nocase/1\"},
\"nocase/deep\": { \"name\": \"nocase/deep\", \"type\": \"directory\", \"symbols\": \[ \"dirsym\" \]},
\"nocase/regular\": { \"name\": \"nocase/regular\", \"type\": \"modulefile\", \"symbols\": \[\], \"tags\": \[\], \"pathname\": \"$mp/nocase/regular\"},
\"nocase/deep/2\": { \"name\": \"nocase/deep/2\", \"type\": \"modulefile\", \"symbols\": \[\], \"tags\": \[\], \"pathname\": \"$mp/nocase/deep/2\"}
}}"
testouterr_cmd sh {whatis nocase/ --json} OK "{\"$mp\": {
\"nocase/1\": { \"name\": \"nocase/1\", \"whatis\": \[ \"nocase/1\" \]},
\"nocase/deep/2\": { \"name\": \"nocase/deep/2\", \"whatis\": \[ \"nocase/deep/2\" \]},
\"nocase/deep/3\": { \"name\": \"nocase/deep/3\", \"whatis\": \[ \"nocase/deep/3\" \]},
\"nocase/regular\": { \"name\": \"nocase/regular\", \"whatis\": \[ \"nocase/regular\" \]},
\"nocase/virt\": { \"name\": \"nocase/virt\", \"whatis\": \[ \"nocase/virt\" \]}
}}"
# newline in result comes from a modulefile that directly puts to stderr during its search evaluation
testouterr_cmd sh {search nocase/ --json} ERR "{\n\"$mp\": {
\"nocase/1\": { \"name\": \"nocase/1\", \"whatis\": \[ \"nocase/1\" \]},
\"nocase/deep/2\": { \"name\": \"nocase/deep/2\", \"whatis\": \[ \"nocase/deep/2\" \]},
\"nocase/deep/3\": { \"name\": \"nocase/deep/3\", \"whatis\": \[ \"nocase/deep/3\" \]},
\"nocase/regular\": { \"name\": \"nocase/regular\", \"whatis\": \[ \"nocase/regular\" \]},
\"nocase/virt\": { \"name\": \"nocase/virt\", \"whatis\": \[ \"nocase/virt\" \]}
}}"
testouterr_cmd sh {list --json} OK "{}"
testouterr_cmd sh {savelist --json} OK "{}"

# test list sub-command on loaded environment
setenv_loaded_module [list nocase/virt extdfl/1.3.1 extdfl3/1.1/3] [list $mp/nocase/1 $mp/extdfl/1.3.1 $mp/extdfl3/1.1/3]
setenv_path_var MODULES_LMALTNAME extdfl/1.3.1&extdfl/default&extdfl
set tserr "{\"nocase/virt\": { \"name\": \"nocase/virt\", \"type\": \"modulefile\", \"variants\": {}, \"symbols\": \[\], \"tags\": \[\], \"pathname\": \"$mp/nocase/1\"},
\"extdfl/1.3.1\": { \"name\": \"extdfl/1.3.1\", \"type\": \"modulefile\", \"variants\": {}, \"symbols\": \[ \"default\" \], \"tags\": \[\], \"pathname\": \"$mp/extdfl/1.3.1\"},
\"extdfl3/1.1/3\": { \"name\": \"extdfl3/1.1/3\", \"type\": \"modulefile\", \"variants\": {}, \"symbols\": \[\], \"tags\": \[\], \"pathname\": \"$mp/extdfl3/1.1/3\"}}"
testouterr_cmd sh {list -j} OK $tserr
testouterr_cmd sh {ml -j} OK $tserr
testouterr_cmd sh {ml --json} OK $tserr
# test mix of -t -l -j switches, last wins
testouterr_cmd sh {list -t -j} OK $tserr
testouterr_cmd sh {list -l -j} OK $tserr
unsetenv_loaded_module
unsetenv_path_var MODULES_LMALTNAME

# test savelist sub-command with collections
set orighome $env(HOME)
setenv_var HOME $orighome/home
testouterr_cmd sh {savelist -j} OK "{\"coll1\": { \"name\": \"coll1\", \"target\": \"\", \"pathname\": \"$orighome/home/.module/coll1\"},
\"coll2\": { \"name\": \"coll2\", \"target\": \"\", \"pathname\": \"$orighome/home/.module/coll2\"},
\"coll3\": { \"name\": \"coll3\", \"target\": \"\", \"pathname\": \"$orighome/home/.module/coll3\"},
\"coll4.target\": { \"name\": \"coll4.target\", \"target\": \"\", \"pathname\": \"$orighome/home/.module/coll4.target\"},
\"coll6.target\": { \"name\": \"coll6.target\", \"target\": \"\", \"pathname\": \"$orighome/home/.module/coll6.target\"},
\"default\": { \"name\": \"default\", \"target\": \"\", \"pathname\": \"$orighome/home/.module/default\"},
\"infocmd\": { \"name\": \"infocmd\", \"target\": \"\", \"pathname\": \"$orighome/home/.module/infocmd\"},
\"infocmdexp\": { \"name\": \"infocmdexp\", \"target\": \"\", \"pathname\": \"$orighome/home/.module/infocmdexp\"}}"
setenv_var MODULES_COLLECTION_TARGET target
set tserr "{\"coll4\": { \"name\": \"coll4\", \"target\": \"target\", \"pathname\": \"$orighome/home/.module/coll4.target\"},
\"coll6\": { \"name\": \"coll6\", \"target\": \"target\", \"pathname\": \"$orighome/home/.module/coll6.target\"}}"
testouterr_cmd sh {savelist -j} OK $tserr
# test mix of -t -l -j switches, last wins
testouterr_cmd sh {savelist -t -j} OK $tserr
testouterr_cmd sh {savelist -l -j} OK $tserr
unsetenv_var MODULES_COLLECTION_TARGET
setenv_var HOME $orighome
unset orighome

# test on other sub-commands
set ans [list]
lappend ans [list setpath LOADEDMODULES extdfl/1.3.1]
lappend ans [list setpath _LMFILES_ $mp/extdfl/1.3.1]
lappend ans [list setpath MODULES_LMALTNAME extdfl/1.3.1&extdfl/default&extdfl]
testouterr_cmd sh {load -v -j extdfl} $ans [msg_load extdfl/1.3.1]
setenv_loaded_module [list extdfl/1.3.1] [list $mp/extdfl/1.3.1]
set ans [list]
lappend ans [list unsetpath LOADEDMODULES]
lappend ans [list unsetpath _LMFILES_]
testouterr_cmd sh {unload -v extdfl --json} $ans [msg_unload extdfl/1.3.1]
unsetenv_loaded_module

# test over an unknown modulefile
testouterr_cmd sh {avail -j unk} OK "{}"
# newline in result comes from a modulefile that directly puts to stderr during its search evaluation
testouterr_cmd sh {search -j unk} ERR "{\n}"
testouterr_cmd sh {whatis -j unk} ERR "{\"errors\": \[\n{ \"severity\": \"ERROR\", \"message\": \[ \"Unable to locate a modulefile for 'unk'\" \] } \]\n}"

# test badly specified commands
set tserr "$error_msgs: Invalid option '--foo'\n$err_typehelp"
testouterr_cmd sh {avail -j --foo} ERR $tserr
testouterr_cmd sh {whatis -j --foo} ERR $tserr
testouterr_cmd sh {search -j --foo} ERR $tserr
testouterr_cmd sh {list -j --foo} ERR $tserr
testouterr_cmd sh {savelist -j --foo} ERR $tserr

# check a modulepath recorded with an extra / does not impact output
setenv_path_var MODULEPATH $mp/
set tserr "{\"$mp\": {
\"extdfl/1.3.1\": { \"name\": \"extdfl/1.3.1\", \"type\": \"modulefile\", \"symbols\": \[ \"default\" \], \"tags\": \[\], \"pathname\": \"$mp/extdfl/1.3.1\"}
}}"
testouterr_cmd sh {avail -j extdfl/default} OK $tserr
# test mix of -t -l -j switches, last wins
testouterr_cmd sh {avail -t -j extdfl/default} OK $tserr
testouterr_cmd sh {avail -l -j extdfl/default} OK $tserr
setenv_path_var MODULEPATH $mp

# check NaN value processed by JSON output formatting routine
testouterr_cmd sh {whatis --json NaN} OK "{\"$mp\": {
\"NaN\": { \"name\": \"NaN\", \"whatis\": \[ \"NaN\" \]}
}}"

# result from multiple paths (including "global/user modulerc")
setenv_var MODULERCFILE $env(TESTSUITEDIR)/etc/rc
setenv_path_var MODULEPATH $modpath:$mp
testouterrjson_cmd sh {avail -j -C *foo} OK "{\"global/user modulerc\": {
\"sym_foo\": { \"name\": \"sym_foo\", \"type\": \"alias\", \"symbols\": \[ \"special2\" \], \"tags\": \[\], \"target\": \"loc_rc2/foo\"}
},
\"$modpath\": {
\"loc_rc1/1.0\": { \"name\": \"loc_rc1/1.0\", \"type\": \"modulefile\", \"symbols\": \[ \"foo\" \], \"tags\": \[\], \"pathname\": \"$modpath/loc_rc1/1.0\"},
\"loc_rc2/1.0\": { \"name\": \"loc_rc2/1.0\", \"type\": \"modulefile\", \"symbols\": \[ \"bar\", \"blah\", \"foo\", \"special2\" \], \"tags\": \[\], \"pathname\": \"$modpath/loc_rc2/1.0\"},
\"loc_tr/3.0\": { \"name\": \"loc_tr/3.0\", \"type\": \"modulefile\", \"symbols\": \[ \"bar\", \"default\", \"exp\", \"foo\", \"reg\", \"tr2bar\", \"tr2exp\", \"trbar\", \"trexp\", \"trreg\" \], \"tags\": \[\], \"pathname\": \"$modpath/loc_tr/3.0\"},
\"info/specified\": { \"name\": \"info/specified\", \"type\": \"modulefile\", \"symbols\": \[ \"foo\" \], \"tags\": \[\], \"pathname\": \"$modpath/info/specified\"},
\"modbad/foo\": { \"name\": \"modbad/foo\", \"type\": \"modulefile\", \"symbols\": \[\], \"tags\": \[\], \"pathname\": \"$modpath/modbad/foo\"},
\"inforc/foo\": { \"name\": \"inforc/foo\", \"type\": \"alias\", \"symbols\": \[\], \"tags\": \[\], \"target\": \"inforc/1.0\"}
},
\"$mp\": {
\"foo/1\": { \"name\": \"foo/1\", \"type\": \"modulefile\", \"symbols\": \[\], \"tags\": \[\], \"pathname\": \"$mp/foo/1\"},
\"nanfoo/1\": { \"name\": \"nanfoo/1\", \"type\": \"modulefile\", \"symbols\": \[ \"nan\" \], \"tags\": \[\], \"pathname\": \"$mp/nanfoo/1\"},
\"foo/2\": { \"name\": \"foo/2\", \"type\": \"modulefile\", \"symbols\": \[\], \"tags\": \[\], \"pathname\": \"$mp/foo/2\"},
\"extdfl7/10foo\": { \"name\": \"extdfl7/10foo\", \"type\": \"modulefile\", \"symbols\": \[\], \"tags\": \[\], \"pathname\": \"$mp/extdfl7/10foo\"},
\"foo/0.1\": { \"name\": \"foo/0.1\", \"type\": \"modulefile\", \"symbols\": \[\], \"tags\": \[\], \"pathname\": \"$mp/foo/0.1\"},
\"foo/0.2\": { \"name\": \"foo/0.2\", \"type\": \"modulefile\", \"symbols\": \[\], \"tags\": \[\], \"pathname\": \"$mp/foo/0.2\"}
}}"

testouterr_cmd sh {whatis -j *foo} ERR "{\"$modpath\": {
\"loc_rc2/1.0\": { \"name\": \"loc_rc2/1.0\", \"whatis\": \[ \"loc_rc2/1.0\" \]}
},
\"$mp\": {
\"foo/0.1\": { \"name\": \"foo/0.1\", \"whatis\": \[\]},
\"foo/0.2\": { \"name\": \"foo/0.2\", \"whatis\": \[\]},
\"foo/1\": { \"name\": \"foo/1\", \"whatis\": \[\]},
\"foo/2\": { \"name\": \"foo/2\", \"whatis\": \[\]},
\"nanfoo/1\": { \"name\": \"nanfoo/1\", \"whatis\": \[\]}
}}"

setenv_var MODULERCFILE $ORIG_MODULERCFILE
setenv_path_var MODULEPATH $mp

# no MODULEPATH defined
unsetenv_path_var MODULEPATH
set tserr "{\"errors\": \[\n{ \"severity\": \"ERROR\", \"message\": \[ \"$msg_nomodpath\" \] } \]\n}"
testouterr_cmd sh {avail -j} ERR $tserr
testouterr_cmd sh {whatis -j} ERR $tserr
testouterr_cmd sh {search -j} ERR $tserr
testouterr_cmd sh {list -j} OK "{}"
testouterr_cmd sh {savelist -j} OK "{}"
# test silent mode
testouterr_cmd sh {avail -j -s} ERR "{}"
testouterr_cmd sh {whatis -j -s} ERR "{}"
testouterr_cmd sh {search -j -s} ERR "{}"
# MODULEPATH defined, directory does not exits
setenv_path_var MODULEPATH $mp.unk
testouterr_cmd sh {--json avail} OK "{}"
testouterr_cmd sh {--json whatis} OK "{}"
testouterr_cmd sh {--json search} OK "{}"
testouterr_cmd sh {--json list} OK "{}"
testouterr_cmd sh {--json savelist} OK "{}"
# MODULEPATH defined, but no modulefiles in it
setenv_path_var MODULEPATH $env(TESTSUITEDIR)/config
testouterr_cmd sh {-j avail} OK "{}"
testouterr_cmd sh {-j whatis} OK "{}"
testouterr_cmd sh {-j search} OK "{}"
testouterr_cmd sh {-j list} OK "{}"
testouterr_cmd sh {-j savelist} OK "{}"

# erroneous modulefiles are evaluated
setenv_path_var MODULEPATH $modpath
testouterr_cmd sh {whatis --json bad2} OK "{\"$modpath\": {
\"bad2/body\": { \"name\": \"bad2/body\", \"whatis\": \[ \"erroneous module test\" \]},
\"bad2/proc\": { \"name\": \"bad2/proc\", \"whatis\": \[ \"erroneous module test\" \]}
}}"
testouterr_cmd sh {search --json erroneous} ERR "{\"$modpath\": {
\"bad/after\": { \"name\": \"bad/after\", \"whatis\": \[ \"erroneous module test\" \]},
\"bad2/body\": { \"name\": \"bad2/body\", \"whatis\": \[ \"erroneous module test\" \]},
\"bad2/proc\": { \"name\": \"bad2/proc\", \"whatis\": \[ \"erroneous module test\" \]}
}}"
setenv_path_var MODULEPATH $mp

# check multiple error messages rendering
if {$is_file_perms_editable && $tcl_platform(user) ne {root} && !$is_locked_dir_file_readable && !$is_locked_file_readable && !$is_filesystem_icase} {
	change_file_perms $mp/IcAsE/1 ugo-rx
	change_file_perms $mp/ICASE/1 ugo-rx
	change_file_perms $mp/iCaSe/1 ugo-rx
	change_file_perms $mp/icASE/1 ugo-rx
	change_file_perms $mp/icase/1 ugo-rx
	testouterrjson_cmd sh {whatis --json -i ICASE/1} ERR "{\"errors\": \[
{ \"severity\": \"ERROR\", \"message\": \[ \"Permission denied on '$mp/icase/1'\" \] },
{ \"severity\": \"ERROR\", \"message\": \[ \"Permission denied on '$mp/iCaSe/1'\" \] },
{ \"severity\": \"ERROR\", \"message\": \[ \"Permission denied on '$mp/ICASE/1'\" \] },
{ \"severity\": \"ERROR\", \"message\": \[ \"Permission denied on '$mp/icASE/1'\" \] },
{ \"severity\": \"ERROR\", \"message\": \[ \"Permission denied on '$mp/IcAsE/1'\" \] } \]
}"
	testouterr_cmd sh {whatis --json -i -s ICASE/1} ERR "{}"
	restore_file_perms $mp/IcAsE/1
	restore_file_perms $mp/ICASE/1
	restore_file_perms $mp/iCaSe/1
	restore_file_perms $mp/icASE/1
	restore_file_perms $mp/icase/1
} elseif { $verbose > 0 } {
    send_user "\tskipping multiple error message rendering test as file access cannot be restricted\n"
}

# no command line switch mix (-t -j -l) within modulefiles, as module command
# is converted to nop in modulerc evaluation context or whatis modulefile
# evaluation context: a -t/-j/-l set in modulefile/modulerc cannot change a
# command line switch preference set at top level

# check " character in error message
# check mix of warning and error message rendering
# check late error message firing
if {[siteconfig_isStderrTty]} {
	setenv_var MODULES_PAGER foo
	setenv_loaded_module [list foo bar] [list $mp/foo]
	testouterr_cmd sh {list --json} ERR "{\"errors\": \[
{ \"severity\": \"ERROR\", \"message\": \[ \"Loaded environment state is inconsistent\", \"LOADEDMODULES=foo bar\", \"_LMFILES_=$mp/foo\" \] },
{ \"severity\": \"WARNING\", \"message\": \[ \"couldn't execute \\\"foo\\\": no such file or directory\" \] } \]
}"
	unsetenv_var MODULES_PAGER
	unsetenv_loaded_module
} elseif { $verbose > 0 } {
    send_user "\tskipping warning/error mix rendering and late error firing test as pager cannot be started\n"
}


#
#  Cleanup
#

reset_test_env
