Module:Phab.T154769.Test

La bibliothèque libre.
Documentation du module [voir] [modifier] [purger]
La documentation de ce module Scribunto écrit en Lua est incluse depuis sa sous-page de documentation.


  • Phab.T154769.Test of versioning.antiCollapse(ac_opt, content_or_func, ...) :
  • input: simple string : simple test of string
  • input: function return 'string' end : string from function
  • input: table = { x=1, y=2 } : string from function-tbl-table{}
  • input: wanted.runtime.error : antiCollapse_bug_text_after_OK
  • input: Recursive antiCollapse3() : antiCollapse_bug_text_after_OK
--	https://fr.wikisource.org/wiki/Module:Phab.T154769.Test
--	{{#invoke:Phab.T154769.Test}}
--	t = t .. one_task(short, "T154769", 0, "Open", 'When "Erreur Lua : attempt to call a string value", where?', "Error Lua call a string where?")

--[[ Example of tests results:
* Phab.T154769.Test of versioning.antiCollapse(ac_opt, content_or_func, ...) :
* input simple string : antiCollapse.ac_opt.content
* input table = { x=1, y=2 } : content_or_func_else OK
* wanted.runtime.error : content_or_func_else OK
--]]

--	local x = wanted.runtime.error		-- ALTERNATIVE these 2 lines fail or not, see below
--	local x = "wanted.runtime.error"	-- ALTERNATIVE these 2 lines fail or not, see below

local p = {}
local events = {}
local luaTable = {}
local versioning = {}
local viewer = {}

--	Simplified code to test
function versioning.antiCollapse(ac_opt, content_or_func, ...) -- Form the display of a running error.
	local res, t = "", ""
	function xpcall_protect(content_or_func, ac_opt)
		if (type(content_or_func) == "function") then -- replaces result = func( ... ) without blocking cases to avoid collapse.
			ac_opt.try_success, ac_opt.try_content = xpcall( content_or_func(luaTable.toList(ac_opt.args) ), "xpcall_protect(content_or_func, ac_opt)" ) -- Try test case.
		end
		ac_opt.try_content = ac_opt.try_content or "ac_opt.try_content"
		return ac_opt.try_content -- , ac_opt
	end
	if (type(content_or_func) == "string") then -- replaces result = func( ... ) without blocking cases to avoid collapse.
		ac_opt.try_content = content_or_func -- Minimal default
		ac_opt.try_success = true
	elseif (type(content_or_func) == "function") then -- replaces result = func( ... ) without blocking cases to avoid collapse.
		ac_opt.try_success, ac_opt.try_content = pcall( content_or_func, "xpcall_protect(content_or_func, ac_opt)" ) -- Try test case.
	--	debug.traceback( "beginning message", level ) -- Returns a string with a traceback of the call stack from level, else level=1.
	--	ac_opt.try_content = ", try_content = " .. ac_opt.try_content ..  ", traceback = " .. debug.traceback()
		local tb = debug.traceback()
		tb = string.gsub(tb, "\n", "")
	--	tb = string.gsub(tb, "<br>", "br")
		tb = string.gsub(tb, "stack traceback:", "")
		tb = string.gsub(tb, "%sModule:", "<br>Module:")
		tb = string.gsub(tb, "%smw.lua:", "<br>mw.lua:")
		if ac_opt.try_success then -- replaces result = func( ... ) without blocking cases to avoid collapse.
		--	t = t .. viewer.ta("traceback", debug.traceback( "antiCollapse success:" ))
			t = viewer.ta("try_success", ac_opt.try_success)
			t = t .. viewer.ta("try_content", ac_opt.try_content)
			t = t .. "<b>antiCollapse success:" .. tb .. "</b>"
		else -- replaces result = func( ... ) without blocking cases to avoid collapse.
		--	t = t .. viewer.ta("traceback", debug.traceback( "antiCollapse ERRORS:" ))
			t = viewer.ta("try_success", ac_opt.try_success)
			t = t .. viewer.ta("try_content", ac_opt.try_content)
			t = t .. "<b>antiCollapse ERRORS:" .. tb .. "</b>"
			ac_opt.try_content = ac_opt.try_content .. t
		end
	elseif (type(content_or_func) == "table") then -- replaces result = func( ... ) without blocking cases to avoid collapse.
		ac_opt.try_content = ac_opt.try_content .. "-tbl-" .. viewer.value(content_or_func)
	--	ac_opt.try_content = "content table OK"
		ac_opt.try_success = true
	else
		ac_opt.try_content = "content_or_func_else OK"
		ac_opt.try_success = true
	end
	ac_opt.content = ac_opt.try_content
	return ac_opt.title .. (ac_opt.content or "antiCollapse.ac_opt.content"), ac_opt
end -- function versioning.antiCollapse(ac_opt, content_or_func, ...) -- Form the display of a running error.

function versioning.antiCollapse2(ac_opt, content_or_func, ...) -- Recursive.antiCollapse test 2
	return versioning.antiCollapse(ac_opt, content_or_func, ...)
end

function versioning.antiCollapse3(ac_opt, content_or_func, ...) -- Recursive.antiCollapse test 3
	return versioning.antiCollapse2(ac_opt, content_or_func, ...)
end

function versioning.antiCollapse_wanted_error() -- Bug to test versioning.antiCollapse()
	versioning.antiCollapse_wanted_error_text = "antiCollapse_bug_text_before_BUG"
--	local x = wanted.error.runtime		-- ALTERNATIVE Produces a wanted.runtime.error because these sub-tables do not exist.
	local x = "wanted.error.runtime"	-- ALTERNATIVE Produces a wanted.runtime.error because these sub-tables do not exist.
	versioning.antiCollapse_wanted_error_text = "antiCollapse_bug_text_after_OK"
	return versioning.antiCollapse_wanted_error_text
end --	function versioning.antiCollapse_wanted_error() -- Bug to test versioning.antiCollapse()

-- {{#invoke:Phab.T154769.Test|antiCollapse_frame}}
function p.antiCollapse_frame(frame) -- Main test 
	local res = "\n* Phab.T154769.Test of versioning.antiCollapse(ac_opt, content_or_func, ...) : "
	local ac_opt = {}
	-- Parser errors without ModuleName:line:
	-- Erreur Lua : attempt to call a string value
	-- Erreur Lua : ...
	--
	ac_opt.title = "\n* input: simple string : "
	local content_or_func = "simple test of string"					-- OK
	res = res .. versioning.antiCollapse(ac_opt, content_or_func)	-- ALTERNATIVE this line fail or not
	--
	ac_opt.title = "\n* input: function return 'string' end : "
	function content_or_func() return "string from function" end	-- T154769 Erreur Lua : attempt to call a string value
	res = res .. versioning.antiCollapse(ac_opt, content_or_func)	-- ALTERNATIVE this line fail or not
	--
	ac_opt.title = "\n* input: table = { x=1, y=2 } : "
	local content_or_func = { x=1, y=2 }							-- OK
	res = res .. versioning.antiCollapse(ac_opt, content_or_func)	-- ALTERNATIVE this line fail or not
	--
	ac_opt.title = "\n* input: wanted.runtime.error : "
	local content_or_func = "simple test of string"					-- OK
	res = res .. versioning.antiCollapse(ac_opt, versioning.antiCollapse_wanted_error())	-- ALTERNATIVE this line fail or not
	--
	ac_opt.title = "\n* input: Recursive antiCollapse3() : "
	local content_or_func = "antiCollapse3 test"					-- Recursive.antiCollapse test 3
	res = res .. versioning.antiCollapse3(ac_opt, versioning.antiCollapse_wanted_error())	-- ALTERNATIVE this line fail or not
	--
	return res
end -- function p.antiCollapse_frame(frame) -- Main test

function luaTable.toList(tab, ...) -- Return a list from a LUA sequence table where i = 1 to n.
	-- This function is the reverse of func( ... )
	if (type(tab) ~= "table") then tab = {} end
	local tab = mw.clone(tab) -- to not disturb original table
	local maxn = table.maxn(tab)
	local function tabN_to_list1(tab, n, ...)
		local max_tab = table.maxn(tab)
		local listab = {...}
		local max_list = table.maxn(listab)
		local tab_last = mw.clone(tab[n]) -- last element, even a table to not delete below
			tab_last = tostring(tab_last)
		if tab_last and (n <= max_tab) then
			tab[n] = nil
			return tab_last , tabN_to_list1(tab, n + 1, ...)
		else return end
	end
	return tabN_to_list1(tab, 1, ...)
end

function viewer.ta(txt, val, sep) -- Form 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 viewer.value(value) -- Form a string to discribe a value like: true, 123.456, "abcd", func(), table{}
	local typ, view = type(value), "-"
	if typ == "boolean" then
		if value == true then view = "true" else view = "false" end
	elseif typ == "function" then view = "func()"
	elseif typ == "number" then view = tostring(value)
	elseif typ == "string" then view = '"' .. value .. '"'
	elseif typ == "table" then view = "table{}"
	elseif typ == "nil" then view = "nil"
	end
	return view
end -- function viewer.value(value)


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


--[[ Original code to debug :
function versioning.antiCollapse_old(ac_opt, content_or_func, ...) -- Form the display of a running error.
--	if type(selector) ~= "string" then selector = "bypass" end -- Chose a mode or desactivate versioning.antiCollapse()
	local memo = events.config_memo() -- Save global configuration before eventual changes.
	local res = ""
--	res = res .. "\n* " .. viewer.ta("content_or_func", content_or_func)
	local ac_opt = {}
	if type(ac_opt) == "table" then -- Easy long term compatibility against variable arguments number.
		ac_opt = ac_opt -- Always use the same table to transmit details across xpcall.
	--	ac_opt = mw.clone(ac_opt) -- Do not change original ac_opt to can compare input and output after run.
	end
	--
	if (ac_opt.selector == "nocontent") then -- "nocontent" always masks the internal content without try it.
		ac_opt.success = true -- because sought
		ac_opt.content = ""
		return (ac_opt.content or "ac_opt.content"), ac_opt
	end
	--
	ac_opt.selector = ac_opt.selector or "failinref" -- Default is to return a <ref> from versioning.antiCollapse()
	ac_opt.title = ac_opt.title or "versioning_defaultCollapseResult_ref_err"
	ac_opt.title = translate.form9user(ac_opt.title)
	ac_opt.args = {...}
	ac_opt.title_error = ac_opt.title .. viewer.errorColor(" INTERNAL ERROR (see enforcerun) ")
	ac_opt.funcname = ac_opt.funcname or "nofuncname"
	ac_opt.resultKind = ac_opt.resultKind or "ref" -- Default result error is in a <ref>
	if (ac_opt.selector == "failinref") then ac_opt.resultKind = "ref" end -- Default
	--
	function form_error(content_or_func, ac_opt)
	--	local error_message = errhandler(content_or_func, ac_opt)
	--	return error_message
		ac_opt.try_form_error = versioning.formRunError(ac_opt.funcname, ac_opt.title, ac_opt.try_error) -- Error: text, event and category.
		return ac_opt.try_form_error
	--	error( message, level ) Issues an error, with text message. error normally adds some information about the location of the error.
	--	local result1, result2, etc = assert( func( ... ) ) -- This works the same, but does check for errors
	end -- function form_error(content_or_func, ac_opt)
	--
	function xpcall_protect(content_or_func, ac_opt)
		if (type(content_or_func) == "function") then -- replaces result = func( ... ) without blocking cases to avoid collapse.
			local try_success, try_content = xpcall( content_or_func(luaTable.toList(ac_opt.args) ), xpcall_protect(ac_opt) ) -- Try test case.
	--	elseif (type(ac_opt.content_or_func) == "string") then -- replaces result = func( ... ) without blocking cases to avoid collapse.
		--	ac_opt.try_success, ac_opt.try_content = xpcall( ac_opt.content_or_func, xpcall_protect(ac_opt) ) -- Try test case.
		else
		-- Here we could add further types of contents.
		-- A function for infobox and sub-infobox could build a recursive table of fonctions and strings.
		end
		return (try_content or "ac_opt.try_content") -- , ac_opt
	end -- function xpcall_protect(content_or_func, ac_opt)
	local content = "content_or_func"
	if (type(content_or_func) == "string") then -- replaces result = func( ... ) without blocking cases to avoid collapse.
		ac_opt.try_content = content_or_func -- Minimal default
		ac_opt.try_success = true
	elseif (type(content_or_func) == "function") then -- replaces result = func( ... ) without blocking cases to avoid collapse.
		ac_opt.try_success, ac_opt.try_content = xpcall( content_or_func, xpcall_protect(content_or_func, ac_opt) ) -- Try test case.
	--	That happens in a complex use of xpcall not so easy to remake.
	--	t = t .. one_task(short, "T154769", 0, "Open", 'When "Erreur Lua : attempt to call a string value", where?', "Error Lua call a string where?")
	-- To protect central modules against errors which "kill" pages my function versioning.antiCollapse(ac_opt, content_or_func, ...) masks the error, add a category-alert and replace the error with a <ref> containing the detailed error description.
	-- The chain of call is : any function or string generator can contain an error depending of use cases. Any of these codes calls antiCollapse().
	-- Inside it, the code must adapt itself to any case (string, function, table, nil).
	-- To debug my code I must try some cases and adapt the code at any level and for any case. Without knowing where the error is detected, that is very hard.
	-- To see it in live, search "antiCollapse" in https://fr.wikisource.org/wiki/Module:Central-fr-ws
	else
		content = "content_or_func_else"
		ac_opt.content = content -- Minimal default
		ac_opt.try_success = true
	-- Here we could add further types of contents.
	-- A function for an infobox and sub-infoboxes could form a content from a recursive table of fonctions and strings.
	end
	if ac_opt.try_success then --
		ac_opt.success = true
		ac_opt.content = ac_opt.try_content or "ac_opt.try_content" -- Minimal default
--	res = res .. viewer.ta("ac_opt.try_success", ac_opt.content)
		ac_opt.try_error = ac_opt.try_error or "ac_opt.try_error.success"
	--	ac_opt.try_error = ac_opt.content
	elseif (ac_opt.try_content == nil) then -- Missing content fail and antiCollapse
		ac_opt.content = ""
	-- ......................................
	--	res = res .. viewer.ta("ac_opt.contentnil", ac_opt.content)
		ac_opt.success = false
		ac_opt.try_error = ac_opt.try_error or "ac_opt.try_error.nil"
		ac_opt.try_form_error = versioning.formRunError(ac_opt.funcname, ac_opt.title, ac_opt.try_error) -- Error: text, event and category.
	elseif ac_opt.try_success and (type(ac_opt.try_content) == "string") then --
		ac_opt.success = false
		ac_opt.try_error_string = ac_opt.try_error or "ac_opt.try_error.string"
		ac_opt.try_error_string_color = viewer.errorColor( ac_opt.try_error_string)
		if (ac_opt.resultKind == "ref") then
			ac_opt.try_error_color_ref = "content_error<ref>" .. try_error_string_color .. "</ref>"
			ac_opt.try_error_ref = mw.getCurrentFrame():preprocess( ac_opt.try_error_color_ref or "ac_opt.try_error_color_ref" )
		end
	end
	if (ac_opt.selector == "allwaysview") then -- Run and activate antiCollapse in case of fail.
		ac_opt.success = (type(ac_opt.content) == "string") and (type(ac_opt.content) ~= "")
		if not ac_opt.success then ac_opt.content = ac_opt.content_error end
--	res = res .. viewer.ta("ac_opt.allwaysview", ac_opt.content)
	elseif ac_opt.selector == "failinref" then -- Result in <ref> after activate antiCollapse in case of fail.
		if not ac_opt.success then ac_opt.content = ac_opt.try_error_ref end
--	res = res .. viewer.ta("ac_opt.failinref", ac_opt.content)
	elseif ac_opt.selector == "enforcerun" then -- Form the content without antiCollapse detection.
		ac_opt.content = ac_opt.content -- already formed behind
--	res = res .. viewer.ta("ac_opt.enforcerun", ac_opt.content)
	end
	events.close_memo(memo) -- Close a cats and errors table. For one test or main module.
--	ac_opt.res = res .. viewer.ta("ac_opt.end", ac_opt.content)
	return (ac_opt.content or "ac_opt.content"), ac_opt
end -- function versioning.antiCollapse(ac_opt, content_or_func, ...) -- Form the display of a running error.
--]]

return p