Module:MdTests

La bibliothèque libre.

La documentation pour ce module peut être créée à Module:MdTests/Documentation

local p = {}
local frame = mw.getCurrentFrame() -- this is the frame from Mediawiki
--[[
-- The main central module is mainly an installer of central libraries and a small demonstrator.
-- The main central module installs central libraries and bind the main and its sub-modules
-- local Central = p -- Save as MdTests.lua MdTests try field 'bind_all_sub_modules_test_cases l17 nil ERR 20190906 1038.lua
-------------------------------|-----------|--------------------------- typical length -------------------------|----------max| DODO
Erreur Lua dans Module:MdTests à la ligne 17 : attempt to call field 'bind_all_sub_modules_test_cases' (a nil value).
	-- Résumé : MdTests first minimal test fields from subnane to errors 20190903 2258
	-- Guideline : Convert these mini modules whith this kind of infos
	-- Guideline : some test like MdTestsCentralTry call the 2 modules MdTests and or CentralTry to diversify tests
	-- Guideline : divide the code in functions to test groups of : sought, known, sub modules calling 2 simple, missing.
	-- Guideline : submodules with or without : sought, known, sub modules calling 2 simple, missing.
	-- Guideline : test only one complete OK example and one case of each probable error
		return { case.subnane, case.sought, case.known, case.double, case.founds, case.missings } -- example
--	MWMW : means add a mw version in the table activity.MediaWiki_Versions = { ... }
--	COCO : is the present change point of Lua codage. hh
--]]
activity = {}			-- Library:activity from 20170611 Search story in Central modules.txt
--	args = {}			-- Object:args from 20180106 form known arguments to import, complete from datas and finalize
datas = {}				-- Library:datas from ?
drop_box = {}			-- Object:drop_box from 20170615 rename viewers.drop_box.form() in viewers.drop_box on 20170615
events = {}				-- Object:events from ? "events"
langs = {}				-- Library:langs from i18n tables on 20130118, br-de-en-es-fr-vi from 20170217,
lua_table = {}			-- Library:lua_table from lua_table.level_list() from 20170808
mathroman = {}			-- Library:mathroman from ?
modes = {}				-- Library:modes from arguments support on 20130125 in Module:Author, 20130312 in Module:ControlArgs
central_library = {}	-- Object:central_library from versions.central_library on 20171211 in Module:Centralizer
tableview = {}			-- Object:tableview from 20170208
tab_view = {}			-- Object:tab_view from 20170208
tracker = {}			-- Object:tracker from 20170628
versions = {}			-- Library:versions from versioning on 20170316. From versions support in Module:Author3 on 20150225.
viewers = {}			-- Library:viewers from 20170209

versions.ModuleNS = mw.site.namespaces.Module.name .. ":" -- translate Module: in other languages
versions.loaded_modules_and_libraries = versions.loaded_modules_and_libraries or {}
versions.bind_all_sub_modules_test_cases = versions.bind_all_sub_modules_test_cases or {}
versions.all_sub_modules_test_cases_list = {} -- named list of already tested submodules
versions.all_sub_modules_test_cases_tree = {} -- base of the hierarchical tree of all sought and known tested submodules
	-- Guideline : divide the code in functions to test groups of : sought, known, sub modules calling 2 simple, missing.
	-- Guideline : submodules with or without : sought, known, sub modules calling 2 simple, missing.
	-- Guideline : test only one complete OK example and one case of each probable error
versions.sub_modules_test_cases = { -- Group of tests cases to test viewers.bind_all_sub_modules_test_cases()
	{ ["subnane"] = "CentralTry",	['sought'] = "CentralTry;MdTests", 	["known"] = "CentralTry;MdTests",
		["founds"] = "nil",	['missings'] = "CentralTry;MdTests", },
	{ ["subnane"] = "MdTests",	['sought'] = "CentralTry;MdTests", 	["known"] = "CentralTry;MdTests", 	['double'] = 2,
		["founds"] = "nil",	['missings'] = "CentralTry;MdTests", },
	{ ["subnane"] = "MdTestsCentralTry",	['sought'] = "CentralTry;MdTests", 	["known"] = "CentralTry;MdTests", 	['double'] = 2,
		["founds"] = "nil",	['missings'] = "CentralTry;MdTests", },
	{ ["subnane"] = "CentralTry",	['sought'] = "CentralTry;MdTests", 	["known"] = "CentralTry;MdTests", 	['double'] = 1,
		["founds"] = "nil",	['missings'] = "CentralTry;MdTests", },
	{ ["subnane"] = "MdTests",	['sought'] = "CentralTry;MdTests", 	["known"] = "CentralTry;MdTests", 	['double'] = 1,
		["founds"] = "nil",	['missings'] = "CentralTry;MdTests", },
	{ ["subnane"] = "MdTestsCentralTry",	['sought'] = "CentralTry;MdTests", 	["known"] = "CentralTry;MdTests", 	['double'] = 2,
		["founds"] = "nil",	['missings'] = "CentralTry;MdTests", },
	{ ["subnane"] = "CentralTry",	['sought'] = "CentralTry;MdTests", 	["known"] = "CentralTry;MdTests", 	['double'] = 1,
		["founds"] = "nil",	['missings'] = "CentralTry;MdTests", },
	}

--[==[ -- debug ligne 17


-- Fonctional styles in central modules.
viewers.usual_colors = { -- Available usual fonctional styles for central modules and those using them.
	["add"]		= "blue",		-- Usual fonctional style for add in blue; blue/yellow are more accessible, see T156048.
	["delete"]	= "#C0C000",	-- Usual fonctional style for delete in yellow; blue/yellow are more accessible, see T156048.
	["discreet"]= "#B0B0B0",	-- Usual fonctional style for discreet in light grey.
	["error"]	= "#AA6688",	-- Usual fonctional style for error in modified red.
	["invoke"]	= "#804020",	-- Usual fonctional style for invoke args in brown.
	["mask"]	= "white",		-- Usual fonctional style for mask standard in white.
	["normal"]	= "black",		-- Usual fonctional style for other standard in black.
	["warning"] = "#804020",	-- Usual fonctional style for warnings in brown.
	["wikidata"]= "green",		-- Usual fonctional style for wikidata in green.
}
viewers.usual_colors_memo = "add delete discreet error invoke mask normal warning wikidata"

function viewers.usual_color(t, usual) -- Fonctional style for available usual cases.
	if type(usual) ~= "string" then usual = "normal" end
	local t = tostring(t)
	-- template style:		'<span style="color:black;"									  >	  usual	  </span>' -- template style
	local usual_in_style =	'<span style="color:' .. viewers.usual_colors["normal"] .. ';" >' .. t .. '</span>' -- default style
	if viewers.usual_colors[usual] then -- Adapt the style of usual, if it exists.
		  usual_in_style =	'<span style="color:' .. viewers.usual_colors[ usual	 ] .. ';" >' .. t .. '</span>' -- actual style
	end -- Style for add in blue; blue/yellow are more accessible, see T156048.
	return usual_in_style
end -- function viewers.usual_color(t, usual)

viewers.styles_colors = "add delete discreet error invoke normal warning wikidata"
viewers.styles_formats = "big bold small up"
function viewers.styles(t, styles) -- Fonctional styles for usual cases.
	local t = tostring(t)
	local styles_split = mw.text.split(styles, "%s")
	for i, style in ipairs(styles_split) do
		if viewers.is_in_sp(style, viewers.styles_colors) then
			t = viewers.usual_color(t, style)
		end
		if viewers.is_in_sp(style, viewers.styles_formats) then
			if style == "big" then t = "<big>" .. t .. "</big>" end
			if style == "bold" then t = "<b>" .. t .. "</b>" end
			if style == "small" then t = "<small>" .. t .. "</small>" end
			if style == "up" then t = "<up>" .. t .. "</up>" end
		end
	end
	return t
end -- function viewers.styles(t, opt)

-- These corresponding functions change the colors of a displayed text for available functional styles:
function viewers.styles_color_add(t) return viewers.usual_color(t, "add") end

function viewers.styles_color_delete(t) return viewers.usual_color(t, "delete") end

function viewers.styles_color_discreet(t) return viewers.usual_color(t, "discreet") end --For attentive readers only.
function viewers.styles_color_error(t) return viewers.usual_color(t, "error") end

function viewers.styles_color_colargs(t) return viewers.usual_color(t, "colargs") end

function viewers.styles_color_mask(t) return viewers.usual_color(t, "mask") end

function viewers.styles_color_normal(t) return viewers.usual_color(t, "normal") end

function viewers.styles_color_warning(t) return viewers.usual_color(t, "warning") end

function viewers.styles_color_wikidata(t) return viewers.usual_color(t, "wikidata") end
--	Formats also functional styles for boxes

function viewers.styles_small_caps(t) -- Display a text in small-caps style.
	return '<span style="font-variant: small-caps">' .. t .. '</span>'
end

function viewers.ta(txt, val, sep) -- Formats an argument and its value in a documentation. The text is "nil" if the value is nil.
	if val == nil then val = "nil" end
	if sep == nil then sep = "=" end
	return tostring(txt) .. " " .. tostring(sep) .. " <b>" .. tostring(val) .. "</b> " .. ", "
end

function viewers.tam(txt, val, sep) -- Formats an argument and its value, or mask it if nil.
	if not val then return "" end
	return viewers.ta(txt, val, sep)
end

function tableview.form_one_case(case, tab_view) -- Default: Convert a case from test_group to rowGroup.
	local tocase = mw.clone(case)
	if (type(tocase) == "table") then table.insert( table, tocase )
	return case
end -- function tableview.form_one_case(case)

function tableview.add_Row(case, tab_view) -- Default: Add a row to rowGroup.
	if (type(case) == "table") and (type(tab_view) == "table") and (type(tab_view.rowGroup) == "table") then -- tab_view must be a table
		tab_view.t = tab_view.t .. viewers.ta("add_Row-#rowGroup: ", lua_table.level_count(tab_view.rowGroup) ) -- track to debug
		tab_view.t = tab_view.t .. viewers.ta("add_Row-#case: ", lua_table.level_count(case) ) -- track to debug
		table.insert( tab_view.rowGroup, case)
	elseif (type(case) == "table") and (type(tab_view) == "table") then
	--	tab_view.rowGroup = {}
		table.insert( tab_view.rowGroup, case)
		tab_view.t = (tab_view.t or "") .. viewers.ta("add_Row-#rowGroup: ", lua_table.level_count(tab_view.rowGroup) ) -- track to debug
		tab_view.t = tab_view.t .. viewers.ta("add_Row-#case: ", lua_table.level_count(case) ) -- track to debug
	end
end -- function tableview.add_Row(tab_view)

function tableview.form_all_cases(tab_view) -- Default: Convert all tests cases from test_group to rowGroup.
	local memo = viewers.save_configs("tableview.form_all_cases") -- Save global configuration before eventual changes.
	local tab_view = tab_view
	if (type(tab_view) ~= "table") then tab_view = {} end -- tab_view must be a table
	if type(tab_view.test_group) ~= "table" then -- tab_view.test_group must be a table
		tab_view.test_group = {}
	end
	tab_view.rowGroup = tab_view.rowGroup or {}
	tab_view.track = tab_view.track or {} -- Begin tracking of errors and caracteristics of a tab_view case.
	local trk = tab_view.track
	if (type(tab_view) ~= "table") then trk.tab_view = tab_view end -- err tab_view is table ?
	trk.min_in = 999999 ; trk.max_in = 0
	trk.min_out = 999999 ; trk.max_out = 0
	tab_view.t = tab_view.t or ""
	trk.Start_test = tab_view.test_group -- err tab_view.test_group is table ?
	trk.Start_test_N = lua_table.level_count(tab_view.test_group) -- size tab_view.test_group
	trk.Start_row = tab_view.rowGroup -- err tab_view.test_group is table ?
	trk.Start_row_N = lua_table.level_count(tab_view.rowGroup) -- size tab_view.test_group
	tab_view.t = tab_view.t .. viewers.ta("start#test_group", lua_table.level_count(tab_view.test_group) ) -- track to debug
	if type(tab_view.rowGroup) ~= "table" then tab_view.rowGroup = {} end
	tab_view.t = tab_view.t .. viewers.ta("start#rowGroup", lua_table.level_count(tab_view.rowGroup) ) -- track to debug
	for i, case in ipairs(tab_view.test_group) do
	--	tab_view.t = tab_view.t .. viewers.ta("i", i)
		if case.STOP == "STOP" then break end
		trk.i = i
		trk.case_in = case -- for table error ?
		if type(case) ~= "table" then
			case = { case }
		end -- Cases must be tables of values.
		trk.min_in = 99 ; trk.max_in = 0
		trk.min_out = 99 ; trk.max_out = 0
		if lua_table.level_count(case) < trk.min_in then trk.min_in = lua_table.level_count(case) end
		if lua_table.level_count(case) > trk.max_in then trk.max_in = lua_table.level_count(case) end
		if type(tableview.form_one_case) == "function" then -- Convert all tests cases from test_group to rowGroup.
			case = tab_view.form_one_case(case, tab_view) -- Formats one case
		else
			case = case -- if tableView_form_one_case() is not defined, do not Formats the case
		end
		--	Keep all cells: Insert a masked text in all table cells, to not lost following cells.
		if (type(case) == "table") and (type(tab_view.rowGroup) == "table") then -- Do not fail if case is nil or {}.
			local headers_split = mw.text.split(tab_view.headers, ';', true) -- fr wikisource org
			for i, header in ipairs(headers_split) do
				header = mw.text.trim(header)
				case[i] = case[i] or viewers.usual_color("-", "mask") -- "mask", "discreet", "error"
			end
		end
		if type(case) ~= "table" then -- check case_out
			case = { case }
		end
		if lua_table.level_count(case) < trk.min_out then trk.min_out = lua_table.level_count(case) end
		if lua_table.level_count(case) > trk.max_out then trk.min_out = lua_table.level_count(case) end
		tab_view.add_Row(case, tab_view) -- Default: Add a row to rowGroup.
		trk.End_test = tab_view.test_group -- err tab_view.test_group is table ?
		trk.End_test_N = lua_table.level_count(tab_view.test_group) -- err tab_view.test_group is table ?
		trk.End_row = tab_view.rowGroup -- err tab_view.test_group is table ?
		trk.End_row_N = lua_table.level_count(tab_view.rowGroup) -- err tab_view.test_group is table ?
		tab_view.t = tab_view.t .. "\n* Start: "
		tab_view.t = tab_view.t .. viewers.form9user("tb=<b>%1</b>, tbN=<b>%2</b>, min=<b>%3</b>, max=<b>%4</b>. ", tostring(trk.Start_test), trk.Start_test_N, trk.min_in, trk.max_in) -- track to debug
		tab_view.t = tab_view.t .. viewers.form9user("i=<b>%1</b>, case_in=<b>%2</b>, case_out=<b>%3</b>, ", tostring(trk.i), type(trk.case_in), type(trk.case_out) )
		trk.Start_test = tab_view.test_group -- err tab_view.test_group is table ?
		trk.Start_test_N = lua_table.level_count(tab_view.test_group) -- size tab_view.test_group
		trk.Start_row = tab_view.rowGroup -- err tab_view.test_group is table ?
		trk.Start_row_N = lua_table.level_count(tab_view.rowGroup) -- err tab_view.test_group is table ?
		tab_view.t = tab_view.t .. " ** End: "
		tab_view.t = tab_view.t .. viewers.form9user("tb=<b>%1</b>, tbN=<b>%2</b>, min=<b>%3</b>, max=<b>%4</b>. ", tostring(trk.End_test), trk.End_test_N, trk.min_out, trk.max_out) -- track to debug
		tab_view.track = trk
	end
	viewers.restore_configs(memo, "tableview.form_all_cases") -- Restore global configurations after eventual changes.
end -- function tableview.form_all_cases(tab_view)

function tableview.adapt_options(tab_view) -- Adapt all options for all uses.
	local memo = viewers.save_configs("tableview.adapt_options") -- Save global configuration before eventual changes.
	if type(tab_view) ~= "table" then tab_view = {} end -- tab_view must be a table
	tab_view.t = (tab_view.t or "")
	tab_view.headers = tab_view.headers or "viewers_tableView_default_headers"
	tab_view.headers = viewers.form9user(tab_view.headers)
	tab_view.form_elem_detail = tab_view.form_elem_detail or "viewers_tab_view_form_elem_detail" -- "detail = %1 | %2 | %3 | %4 | %5."
	tab_view.headers_class = tab_view.headers_class or "wikitable alternative center"
	--	headers_class = "wikitable alternative center sortable",
	-- A triable table start with : {| class="wikitable sortable"
	-- A column become fix and not triable with : ||class="unsortable"|
	tab_view.tableStyle = tab_view.tableStyle or " " -- Style of the whole table view.
	tab_view.test_group = tab_view.test_group or viewers.default_test_group
	tab_view.t = (tab_view.t or "") .. viewers.ta("tableView.tab_view.test_group size: ", lua_table.level_count(tab_view.test_group) ) -- track to debug
	tab_view.form_one_case = tab_view.form_one_case or tableview.form_one_case
	tab_view.form_all_cases = tab_view.form_all_cases or tableview.form_all_cases
	tab_view.add_Row = tab_view.add_Row or tableview.add_Row
	tab_view.ccc = tab_view.ccc or tableview.ccc or {} -- To communicate and compute between cases
	tab_view.rowGroup = tab_view.rowGroup or {} -- Only tab_view can change rowGroup to avoid effect from a tableview on the next
	tab_view.track_on = tab_view.track_on or false
	tab_view.t = tab_view.t .. viewers.ta("#tab_view.rowGroup", lua_table.level_count(tab_view.rowGroup) ) -- track to debug
	viewers.restore_configs(memo, "tableview.adapt_options") -- Restore global configurations after eventual changes.
	return tab_view
end -- function tableview.adapt_options(tab_view)

function tableview.form_whole_view(tab_view) -- Formats whole the tableview.new()
	local memo = viewers.save_configs("tableview.form_all_cases") -- Save global configuration before eventual changes.
	local t, err = "", ""
	if (lua_table.level_count(tab_view.test_group) == 0) then
		err = err .. viewers.ta("#tab_view.test_group", lua_table.level_count(tab_view.test_group) )
	end
	local t = viewers.table_head(tab_view.headers_class or "")
	if (type(tab_view.headers) ~= "string") then
		tab_view.headers = "tab_view; headers; missing"
		err = err .. tab_view.headers
	end
	local head = mw.text.split( viewers.form9user(tab_view.headers), ";")
	for i, header in ipairs(head) do -- Formats headers of the table.
		t = t .. viewers.table_col(header or "")
	end
	tableview.form_all_cases(tab_view) -- Default: Convert all tests cases from test_group to rowGroup.
	if (type(tab_view.rowGroup) ~= "table") then tab_view.rowGroup = {} end
	if (lua_table.level_count(tab_view.rowGroup == 0) ) then
		err = err .. "whole:"
		err = err .. viewers.ta("#tab_view.test_group", lua_table.level_count(tab_view.test_group) )
		err = err .. viewers.ta("#tab_view.rowGroup", lua_table.level_count(tab_view.rowGroup) )
	end
	for row_i, columns_i in ipairs(tab_view.rowGroup) do -- Formats the content of each of rows.
		t = t .. viewers.table_row()
		for col, val in ipairs(columns_i) do
			t = t .. viewers.table_dat(val or "") -- each value in columns of row_i
		end
	end
	t = t .. viewers.table_end()
	if tab_view.track_on then t = t .. "tableView_form_whole_view: " .. tostring(err) end
	if (err ~= "") and (tab_view.track_on) then t = t .. "tableView_form_whole_view: " .. tostring(err) end
	viewers.restore_configs(memo, "tableview.form_whole_view")
	return t
end -- function tableview.form_whole_view(tab_view) -- S170610csc

function tableview.new(tab_view) -- Formats a table with lines and columns. S170610tvf
	local memo = viewers.save_configs("tableview.form_whole_view") -- Save global configuration before eventual changes.
	if type(tab_view) ~= "table" then tab_view = {} end -- tab_view must be a table
	tab_view.t = (tab_view.t or "") .. viewers.ta("tableView: ", "start")
	local t = ""
	local err = nil
	tab_view = tableview.adapt_options(tab_view) -- Adapt all options for all uses, before all other adaptations.
	if tab_view.track_on then t = t .. viewers.ta("#test_group", lua_table.level_count(tab_view.test_group) ) .. viewers.ta("#rowGroup", lua_table.level_count(tab_view.rowGroup) ) end
	t = t .. tableview.form_whole_view(tab_view) -- Formats whole the tableview.new()
	if tab_view.track_on then t = t .. viewers.ta("#test_group", lua_table.level_count(tab_view.test_group) ) .. viewers.ta("#rowGroup", lua_table.level_count(tab_view.rowGroup) ) end
	if tab_view.track_on then t = t .. tab_view.t end
	-- Counts of selected and sorted sub-tasks: , #test_group = 43 , #rowGroup = 0
	viewers.restore_configs(memo, "tableview.form_whole_view") -- Restore global configurations after eventual changes.
	return t, err, tab_view
end -- t, err, tab_view = function tableview.new(tab_view)

------------------------------------------------------------------------
------------------------------------------------------------------------

function p.get_one_module_or_library(title, given_module) -- Get a module or a library, then form and record its descriptor.xx
--	local get, module = p.get_one_module_or_library("Module:Centralizer") -- basic example of use
	local get, module, required, loaded = {}
	if type(title) ~= "string" then
		get.title = "abnormal title : " .. tostring(title)
		get.is_nil = true
		return get
	end -- If not loaded, return only an empty get
	if (type(given_module) == "table") then
		module = given_module
	elseif (type(given_module) == "function") then
		module = given_module()
	else -- to require a new module
		loaded = p.pcallRequire(title) -- require() must not fail and block the page if the module do not exists.
		if (type(loaded) == "table") or (type(loaded) == "function") then module = loaded -- The module is well loaded in package.loaded
		else return get end -- If not loaded, return only get.isTitled and get.title
	end
	get.title = title -- like Module:Author, or the versioning library
	get.module = module -- like {...}
	get.is_nil = not module -- like true or false
	get.is_loaded = true and package.loaded[title] -- true if the module is in package.loaded
	get.is_function = (type(module) == "function") -- true if the module is a function
	get.is_table = (type(module) == "table") -- true if the module is a table
	get.i18n = module.i18n -- i18n table of the module
	get.version = module.version -- table including module.version.known and module.version.sought
	get.is_library = (type(module)=="table") and not (type(module)=="function") and not (string.find(title, versions.ModuleNS, 1, true) )
	get.hasi18n = (type(module) == "table") and (type(get.i18n) == "table") -- true if the object has a i18n translations table
	get.versionName = string.gsub(get.title or "", versions.ModuleNS, "") -- without Module:		like versioning or Author
	get.versionTitle = versions.ModuleNS .. get.versionName -- normalize title					like Module:Author
	get.is_module = string.find(get.title, versions.ModuleNS) -- true if the object is				like Module:Author
	get.isI18N = true and string.find(get.title, "/I18N") -- true if the title contains /I18N		like Module:Author/I18N
	get.withoutI18N = string.gsub(get.versionName, "/I18N", "") -- version without /I18N			like versioning or Module:Author
	get.versionI18N = get.withoutI18N .. "/I18N" -- version with /I18N								like Module:Author/I18N
	get.nowstamp = os.date("%Y%m%d%H%M%S") -- like YYYYMMDDhhmmss from module
	-- Special for ISmodule, ISlibrary, ISfunction
	if get.is_library then
		get.revistamp = get.nowstamp
		get.TitleI18N = versions.ModuleNS .. "Library/" .. get.withoutI18N .. "/I18N" --	like Module:Library/versioning/I18N
		get.pagename = TitleI18N -- Locate translations										like Module:Library/versioning/I18N
		get.i18nRoot = get.versionName -- Where locate translations are						like versioning
	elseif get.is_module then
		get.revistamp = mw.getCurrentFrame():preprocess( "{{REVISIONTIMESTAMP:" .. get.title .. "}}" )
		get.pagename = "Module:" .. get.versionName -- Locate translations					like Module:Centralizer/I18N
		get.i18nRoot = get.pagename -- Where locate translations are						like Module:Author
		get.TitleI18N = versions.ModuleNS .. get.withoutI18N .. "/I18N" --				like Module:Centralizer/I18N
	else
		get.revistamp = mw.getCurrentFrame():preprocess( "{{REVISIONTIMESTAMP:" .. get.title .. "}}" )
	end
	get.versionName = string.gsub(get.title or "", versions.ModuleNS, "") -- full version name with perhaps /I18N
	get.simplename = string.gsub(get.versionName, "/I18N", "") -- delete "/I18N" if any
	get.viewI18N = get.simplename
	if type(module) == "function" then
		get.is_function = true -- ISfunction
		get.is_module = false
		get.is_library = false
		get.functionName = get.simplename --												like tostring
		get.pagename = "function:" .. get.simplename --										like function:tostring
	elseif string.find(get.title, versions.ModuleNS) then -- If the module title begin with "Module:"
		get.is_function = false
		get.is_module = true -- ISmodule
		get.is_library = false
		get.moduleName = get.title -- complete the title with "Module:"						like Module:Centralizer
		get.subI18N = get.title .. "/I18N" -- eventual sub-module "/I18N"					like Module:Centralizer/I18N
		get.pagename = versions.ModuleNS .. get.simplename --								like Module:Centralizer
		if get.isI18N then get.pagename = get.pagename .. "/I18N" end --					like Module:Centralizer/I18N
		if get.isI18N then get.viewI18N = get.simplename .. "/I18N" end --					like Central/I18N
	else -- If the module is a library
		get.is_function = false
		get.is_module = false
		get.is_library = true -- ISlibrary
		get.libraryName = get.title -- standard library name								like versioning
		get.versionName = get.libraryName --												like versioning
		get.pagename = versions.ModuleNS .. "Library/" .. get.title --					like Module:Library/versioning
		get.subI18N = get.pagename .. "/I18N" -- /I18N sub-module							like Module:Library/versioning/I18N
		if get.isI18N then get.pagename = get.subI18N end --								like Module:Library/versioning/I18N
		if get.isI18N then get.viewI18N = get.simplename .. "/I18N" end --					like versioning/I18N
	end
	if get.isI18N and (type(get.module) == "table") and (type(get.module.i18n) == "table") then get.sub_i18n = get.module.i18n end
	-- stamp, date and time
	if not get.revistamp then get.revistamp = os.date("%Y%m%d %H%M%S") end
	local function days(stamp) -- approximate the number of days from 0000-01-01
		local day = 0
		if (type(stamp) == "string") and (string.len(stamp) > 7) then
			day = tonumber(string.sub(stamp,1,4)) * 365 +
			tonumber(string.sub(stamp,5,6)) * 30 +
			tonumber(string.sub(stamp,7,8))
		end
		return day
	end
	if get.revistamp then
		get.days_revis = days(get.revistamp)
		get.days_now = days(get.nowstamp)
		get.delay = get.days_now - get.days_revis
		get.revistime = string.sub(get.revistamp,1,4) .. "-" .. string.sub(get.revistamp,5,6) .. "-" .. string.sub(get.revistamp,7,8)
			.. " " .. string.sub(get.revistamp,-6,-5) .. ":" .. string.sub(get.revistamp,-4,-3)
		get.shortdays = string.sub(get.revistamp or "", 3, 8)
		get.shorttime = string.sub(get.revistime or "", -9, -1)
		if get.delay < 25 -- time4
			then get.shortVersion = "v" .. get.shorttime -- short version in "vDD hh:mm" until around 25 days
			else get.shortVersion = "v" .. get.shortdays -- later in date vYYMMDD
		end
		get.versionDate = get.revistime
		get.versionNumber = get.shortVersion
		get.versionName = string.gsub(get.title or "", versions.ModuleNS, "") -- full version name with perhaps /I18N
		get.versionDate = get.revistime
		if type(get.module.version) == "table" then -- For central modules or libraries only:
			get.module.versionName = get.versionName -- Record in each module to later IDENTIFY any module. See task T119978, "own module name"
			get.module.versionDate = get.versionDate -- Record in each module to later DATE any module. See task T119978, "own module name"
		end
	end
	if get.version then
		get.sought = get.version.sought or get.version.selector or ""
		get.known = get.version.known or get.version.all_p or ""
		--
		local str = string.gsub(get.sought, " ", ";")
		get.sought_tab = mw.text.split(str, ";", true)
		get.sought_count = lua_table.level_count(get.sought_tab)
		--
		local str = string.gsub(get.known, "*", ";")
		get.known_tab = mw.text.split(str, ";", true)
		get.known_count = lua_table.level_count(get.known_tab)
	end
	-- Record the get descriptor with others
	p.loaded_modules_and_libraries = p.loaded_modules_and_libraries or {}
	if get.i18n then table.insert(p.loaded_modules_and_libraries, get) end
	--
	p.bind_main_and_sub_modules_get = p.bind_main_and_sub_modules_get or {}
	p.bind_main_and_sub_modules_get[get.title] = get
	return get, module
end -- local get, module = p.get_one_module_or_library(title, given_module)

function p.bind_all_sub_modules(sub_modules, iftest) -- Bind all sub-modules of the main module
	local t = t -- t or
	if (type(t) ~= "string") then t = '\n* <b>p.bind_all_sub_modules(sub_modules, iftest)</b> : Bind all sub-modules of the main module' end
	-- Guideline : make a tree a sub modules from the main module
	-- Guideline : for each sub module : try all sought and check its infos from the test by get.isModule ...  like MdTestsCentralTry call the 2 modules MdTests and or CentralTry to diversify tests
	-- F in functions to test groups of : sought, known, sub modules calling 2 simple, missing.
	-- Guideline : submodules with or without : sought, known, sub modules calling 2 simple, missing.
	-- Guideline : test only one complete OK example and one case of each probable error
	local frame = mw.getCurrentFrame() -- this is the frame from Mediawiki
	local main_module_name = frame:getTitle() -- this is the title of the module invoked
	local subtree = {} -- Contains the structure of sub modules, from sought at each branch/level record the result of get_one_module_or_library
	local bind_all_sub_modules_test_cases = viewers.bind_all_sub_modules_test_cases or {} -- Contains the sequence of sub modules for each one record the result of get_one_module_or_library
	local subsgroup = {} -- for each one do not try it if it is already in the tree. But always record it in subtree
	for key, elem in pairs(bind_all_sub_modules_test_cases) do -- alternatives = known_tab[i]
		table.insert(subsgroup, { case.insub, case.sub, case.sought, case.known, case.sought, case.known, case.errors or "", } )
	end
	return t, sub_modules.sub_used
end -- t, sub_modules = p.bind_all_sub_modules(sub_modules, iftest) -- Bind all sub-modules of the main module

function p.bind_all_sub_modules_test() -- Test : Bind all sub-modules of the main module.
	p.bind_all_sub_modules_track = "TEST"
	local t = t -- t or
	if (type(t) ~= "string") then t = '\n* <b>p.bind_all_sub_modules_test()</b> : Test : Bind all sub-modules of the main module' end
	local tt, sub_modules = p.bind_all_sub_modules(sub_modules, iftest) -- Bind all sub-modules of the main module
	t = t .. tt
	local subsgroup = {}
	for i, case in pairs(sub_modules) do -- alternatives = known_tab[i]
		table.insert(subsgroup, { case.insub, case.sub, case.sought, case.known, case.sought, case.known, case.errors or "", })
	end -- COCO : in case of minimal tests use the input as results : do do later ...
	local tab_view = { -- Group datas and options for a table view with lines and columns.
		title_memo = "p.bind_all_sub_modules() Test : Bind all sub-modules of the main module",
		test_group = subsgroup,
		form_one_case = function(case) -- Convert a case from test_group to rowGroup.
			return { case.subnane, case.sought, case.known, case.founds, case.missings, case.double, case.errors, }
		end,                                           
		headers = " subnane; sought; known; founds; missings; double; errors ",
		headers_class = "wikitable alternative center sortable",
		rowGroup = {},
	--	track_on == "details", convert function tab_view.form_one_case( to form_one_case = function(
	}
	t = t .. tableview.new(tab_view) -- Runs tests cases and formats a table view with lines and columns.
	return t
end -- t = t .. p.bind_all_sub_modules_test()


------------------------------------------------------------------------
------------------------------------------------------------------------

--p.case
function p.read(frame)
--	p.case = case -- adapted by each main module
--    local mainmodule = mainmodule or p.mainmodule -- adapted by each main module
	local t = "\n* " .. mainmodule .. viewers.ta("subnane", case.subnane) .. viewers.ta("sought", case.sought)
	.. viewers.ta("known", case.known) .. viewers.ta("founds", case.founds) .. viewers.ta("missings", case.missings)
	.. viewers.ta("double", case.double) .. viewers.ta("errors", case.errors or "")
	t = t .. p.bind_all_sub_modules_test()
	return t
end

--]==] -- debug ligne 17
function p.read(frame)
	return "minimal text for debug"
end

return p

----------------------------------------------------------------------
----------------------------------------------------------------------

--[[
Module:MdTests/Tests

=== Usage simple ===
<nowiki>
{{MdTests|read}}</nowiki>
{{MdTests|read}}

=== Usage double ===
<nowiki>
{{MdTestsCentralTry|read}}</nowiki>
{{MdTestsCentralTry|read}}
--]]
--	Module:Centralizer/Documentation		-- s.fr.wikisource.Module:Centralizer/Tests in French
--	Module:MdTests/Documentation			-- Tester Module:Centalizer pour l'auteur Victor Hugo
--