stringtranslate.com

Módulo:ScribuntoUnit

------------------------------------------------------------------------------- -- Pruebas unitarias para Scribunto. ------------------------------------------------------------------------------- require ( 'strict' ) local DebugHelper = {} local ScribuntoUnit = {} -- La tabla cfg contiene todas las cadenas localizables y la configuración, para facilitar la transferencia de este módulo a otra wiki. local cfg = mw . loadData ( 'Module:ScribuntoUnit/config' ) ------------------------------------------------------------------------------- -- Concatena claves y valores, ideal para mostrar una plantilla o una tabla de argumentos de función del analizador. -- @param keySeparator une la clave y el valor (por defecto "=") -- @param separator une los diferentes pares clave-valor (por defecto ", ") -- @example concatWithKeys({a = 1, b = 2, c = 3}, ' => ', ', ') => "a => 1, b => 2, c => 3" -- función DebugHelper . concatWithKeys ( tabla , separadorclave , separador ) separadorclave = separadorclave o ' = ' separador = separador o ', ' local concatenado = '' local i = 1 local primero = verdadero local argumentos sin nombre = verdadero para k , v en pares ( tabla ) hacer si primero entonces primero = falso de lo contrario concatenado = concatenado .. separador fin si k == i y argumentos sin nombre entonces i = i + 1 concatenado = concatenado .. tostring ( v ) de lo contrario argumentos sin nombre = falso concatenado = concatenado .. tostring ( k ) .. separadorclave .. tostring ( v ) fin fin                                                                                          devuelve  concatenado fin ------------------------------------------------------------------------------- -- Compara dos tablas recursivamente (los valores que no son de tabla también se manejan correctamente). -- @param ignoreMetatable si es falso, se usa t1.__eq para la comparación -- function DebugHelper . deepCompare ( t1 , t2 , ignoreMetatable ) local type1 = type ( t1 ) local type2 = type ( t2 ) si type1 ~= type2 entonces devuelve falso fin si type1 ~= 'table' entonces devuelve t1 == t2 fin local metatable = getmetatable ( t1 ) si no ignoreMetatable y metatable y metatable . __eq entonces devuelve t1 == t2 fin para k1 , v1 en pares ( t1 ) hacer local v2 = t2 [ k1 ] si v2 == nil o no DebugHelper . deepCompare ( v1 , v2 ) entonces devuelve falso fin fin para k2 , v2 en pares ( t2 ) hacer si t1 [ k2 ] == nil entonces devuelve falso fin fin devuelve verdadero fin ------------------------------------------------------------------------------- -- Genera un error con información de la pila -- @param detalla una tabla con detalles del error -- - debe tener una clave 'text' que es el mensaje de error a mostrar -- - se agregará una clave 'trace' con los datos de la pila -- - y una clave 'source' con el número de archivo/línea -- - se agregará una metatabla para el manejo de errores -- function DebugHelper . raise                                                                                                 ( detalles ,  nivel ) nivel = ( nivel o 1 ) + 1 detalles . trace = debug. traceback ( '' , nivel ) detalles . source = string. match ( detalles . trace , '^%s*stack traceback:%s*(%S*: )' ) -- setmetatable(detalles, { -- __tostring: function() return detalles. text fin -- }) error ( detalles , nivel ) fin ------------------------------------------------------------------------------- -- cuando se usa en una prueba, esa prueba se ignora y el conteo de omisiones aumenta en uno. -- función ScribuntoUnit : markTestSkipped () DebugHelper . raise ({ ScribuntoUnit = true , skipped = true }, 3 ) fin ------------------------------------------------------------------------------- -- Fallar una prueba incondicionalmente -- @param message descripción opcional de la prueba -- función ScribuntoUnit : fail ( message ) DebugHelper . raise ({ ScribuntoUnit = true , text = "La prueba falló" , message = message }, 2 ) end ------------------------------------------------------------------------------- -- Comprueba que la entrada sea verdadera -- @param message descripción opcional de la prueba -- function ScribuntoUnit : assertTrue ( actual , message ) if not actual then DebugHelper . raise ({ ScribuntoUnit = true , text = string.format ( "No se pudo afirmar que %s es verdadero" , tostring ( actual )), message = message }, 2 ) end                                                      fin ------------------------------------------------------------------------------- -- Comprueba que la entrada es falsa -- @param mensaje descripción opcional de la prueba -- función ScribuntoUnit : assertFalse ( actual , message ) si es actual entonces DebugHelper.raise ({ ScribuntoUnit = true , text = string.format ( "No se pudo afirmar que %s es falso" , tostring ( actual ) ), message = message }, 2 ) fin fin ------------------------------------------------------------------------------- -- Comprueba que una cadena de entrada contiene la cadena esperada -- @param mensaje descripción opcional de la prueba -- @param simple la búsqueda se realiza con una cadena simple en lugar de una ustring patrón -- función ScribuntoUnit : assertStringContains ( patrón , s , simple , mensaje ) si es tipo ( patrón ) ~= 'cadena' entonces DebugHelper . raise ({ ScribuntoUnit = true , text = mw . ustring . format ( "Error de tipo de patrón (cadena esperada, se obtuvo %s)" , type ( patrón )), message = message }, 2 ) end if type ( s ) ~= 'string' then DebugHelper . raise ({ ScribuntoUnit = true , text = mw . ustring . format ( "Error de tipo de cadena (cadena esperada, se obtuvo %s)" , type ( s )), message = message }, 2 ) end if not mw . ustring . find ( s , patrón , nulo                                                 ,  plain )  entonces DebugHelper . raise ({ ScribuntoUnit = true , text = mw . ustring . format ( 'No se pudo encontrar %s "%s" en la cadena "%s"' , plain y "cadena simple" o "patrón" , patrón , s ), mensaje = mensaje }, 2 ) fin fin ------------------------------------------------------------------------------- -- Comprueba que una cadena de entrada no contenga la cadena esperada -- @param mensaje descripción opcional de la prueba -- @param simple la búsqueda se realiza con una cadena simple en lugar de un patrón ustring -- función ScribuntoUnit : assertNotStringContains ( patrón , s , plain , mensaje ) si tipo ( patrón ) ~= 'cadena' entonces DebugHelper . raise ({ ScribuntoUnit = true , text = mw . ustring . format ( "Error de tipo de patrón (cadena esperada, se obtuvo %s)" , type ( patrón )), message = message }, 2 ) end if type ( s ) ~= 'string' then DebugHelper . raise ({ ScribuntoUnit = true , text = mw . ustring . format ( "Error de tipo de cadena (cadena esperada, se obtuvo %s)" , type ( s )), message = message }, 2 ) end local i , j = mw . ustring . find ( s , patrón , nil , plain ) if i then local match = mw .                                                      ustring . sub ( s ,  i ,  j ) DebugHelper . raise ({ ScribuntoUnit = true , text = mw . ustring . format ( 'Se encontró coincidencia "%s" para %s "%s"' , match , plain y "cadena simple" o "patrón" , patrón ), message = message }, 2 ) end end ------------------------------------------------------------------------------- -- Comprueba que una entrada tiene el valor esperado. -- @param message descripción opcional de la prueba -- @example assertEquals(4, add(2,2), "2+2 debería ser 4") -- function ScribuntoUnit : assertEquals ( esperado , actual , mensaje ) if type ( esperado ) == 'número' and type ( actual ) == 'número' then self : assertWithinDelta ( esperado , actual , 1e-8 , mensaje ) elseif esperado ~= actual then DebugHelper . raise ({ ScribuntoUnit = true , text = string.format ( "No se pudo afirmar que %s es igual al esperado %s" , tostring ( actual ), tostring ( esperado )), actual = actual , esperado = esperado , mensaje = mensaje , }, 2 ) end end ------------------------------------------------------------------------------- -- Comprueba que una entrada no tiene el valor esperado. -- @param message descripción opcional de la prueba -- @example assertNotEquals(5, add(2,2), "2+2 no debe ser 5") -- function ScribuntoUnit : assertNotEquals ( esperado ,                                                          actual ,  mensaje ) si tipo ( esperado ) == 'número' y tipo ( actual ) == ' número' entonces auto : assertNotWithinDelta ( esperado , actual , 1e-8 , mensaje ) de lo contrario, si esperado == actual entonces DebugHelper.raise ({ ScribuntoUnit = true , texto = string.format ( "No se pudo afirmar que %s no es igual al esperado %s" , tostring ( actual ), tostring ( esperado )), actual = actual , esperado = esperado , mensaje = mensaje , }, 2 ) fin fin ------------------------------------------------------------------------------- -- Valida que tanto el valor esperado como el real sean números -- @param mensaje descripción opcional de la prueba -- función local validationNumbers ( esperado , actual , mensaje ) si tipo ( esperado ) ~= "número" entonces DebugHelper . raise ({ ScribuntoUnit = true , text = string.format ( "El valor esperado %s no es un número" , tostring ( esperado )), actual = actual , esperado = esperado , mensaje = mensaje , }, 3 ) end if type ( actual ) ~= "número" then DebugHelper . raise ({ ScribuntoUnit = true , text = string.format ( "El valor real %s no es un número" , tostring ( actual )),                                                                                  actual  =  actual , esperado = esperado , mensaje = mensaje , }, 3 ) fin fin ------------------------------------------------------------------------------- -- Comprueba que 'actual' está dentro de 'delta' de 'esperado'. -- @param mensaje descripción opcional de la prueba -- @ejemplo assertWithinDelta(1/3, 3/9, 0.000001, "3/9 debe ser 1/3") función ScribuntoUnit : assertWithinDelta ( esperado , actual , delta , mensaje ) validarNumbers ( esperado , actual , mensaje ) diff local = esperado - actual si diff < 0 entonces diff = - diff fin -- en lugar de importar math.abs si diff > delta entonces DebugHelper . raise ({ ScribuntoUnit = true , text = string.format ( "No se pudo afirmar que %f está dentro de %f del esperado %f" , actual , delta , esperado ), actual = actual , esperado = esperado , mensaje = mensaje , }, 2 ) end end ------------------------------------------------------------------------------- -- Comprueba que 'actual' no está dentro de 'delta' de 'esperado'. -- @param message descripción opcional de la prueba -- @example assertNotWithinDelta(1/3, 2/3, 0.000001, "1/3 no debería ser 2/3") function ScribuntoUnit : assertNotWithinDelta ( esperado , actual , delta , mensaje ) validationNumbers ( esperado , actual , mensaje ) local diff = esperado - actual if diff < 0 then diff = - diff end                                                                                      -- en lugar de importar math.abs si diff <= delta entonces DebugHelper.raise ({ ScribuntoUnit = true , text = string.format ( "No se pudo afirmar que %f no está dentro de %f del %f esperado" , actual , delta , esperado ) , actual = actual , esperado = esperado , message = message , } , 2 ) fin fin ------------------------------------------------------------------------------- -- Comprueba que una tabla tiene el valor esperado (incluidas las subtablas). -- @param message descripción opcional de la prueba -- @example assertDeepEquals({{1,3} , {2,4}} , partición(odd, {1,2,3,4})) función ScribuntoUnit : assertDeepEquals ( esperado , actual , mensaje ) si no DebugHelper.deepCompare ( esperado , actual ) entonces si tipo ( esperado ) == 'tabla' entonces esperado = mw . dumpObject ( esperado ) fin si tipo ( actual ) == 'tabla' entonces actual = mw . dumpObject ( actual ) fin DebugHelper . raise ({ ScribuntoUnit = true , texto = string. formato ( "No se pudo afirmar que %s es igual al esperado %s" , tostring ( actual ), tostring ( esperado )), actual = actual , esperado = esperado , mensaje = mensaje , }, 2 ) fin fin ------------------------------------------------------------------------------- -- Comprueba que un wikitexto da el resultado esperado después del procesamiento.                                                                              -- @param message descripción opcional de la prueba -- @example assertResultEquals("Hola mundo", "{{concat|Hola|mundo}}") function  ScribuntoUnit : assertResultEquals ( esperado ,  texto ,  mensaje ) local frame = self.frame local actual = frame : preprocess ( texto ) si esperado ~= actual entonces DebugHelper.raise ( { ScribuntoUnit = true , texto = string.format ( "No se pudo afirmar que %s es igual a esperado %s después del preprocesamiento" , texto , tostring ( esperado ) ) , actual = actual , actualRaw = texto , esperado = esperado , mensaje = mensaje , } , 2 ) fin fin ------------------------------------------------------------------------------- -- Comprueba que dos wikitextos den el mismo resultado después del procesamiento. -- @param message descripción opcional de la prueba -- @example assertSameResult("{{concat|Hola|mundo}}", "{{deleteLastChar|¡Hola mundo!}}") function ScribuntoUnit : assertSameResult ( text1 , text2 , message ) local frame = self . frame local processing1 = frame : preprocess ( text1 ) local processing2 = frame : preprocess ( text2 ) if processing1 ~= processing2 then DebugHelper . raise ({ ScribuntoUnit = true , text = string. formate ( "No se pudo afirmar que %s es igual al %s esperado después del preprocesamiento" , processing1 , processing2 ), actual = processing1 , actualRaw = text1                                                                            , esperado = procesado2 , esperadoRaw = texto2 , mensaje = mensaje , }, 2 ) fin fin ------------------------------------------------------------------------------- -- Comprueba que una función de analizador proporcione la salida esperada. -- @param mensaje descripción opcional de la prueba -- @ejemplo assertParserFunctionEquals("Hola mundo", "msg: concat ", {"Hola", " mundo"}) función ScribuntoUnit : assertParserFunctionEquals ( esperado , pfname , args , mensaje ) marco local = self.marco local actual = marco : callParserFunction { nombre = pfname , args = args } si esperado ~ = actual entonces DebugHelper . raise ({ ScribuntoUnit = true , text = string.format ( "No se pudo afirmar que %s con argumentos %s es igual al esperado %s después del preprocesamiento" , DebugHelper . concatWithKeys ( args ), pfname , expected ), actual = actual , actualRaw = pfname , expected = expected , message = message , }, 2 ) end end ------------------------------------------------------------------------------- -- Comprueba que una plantilla proporcione el resultado esperado. -- @param message descripción opcional de la prueba -- @example assertTemplateEquals("Hola mundo", "concat", {"Hola", " mundo"}) function ScribuntoUnit : assertTemplateEquals ( expected , template , args , message ) local frame = self . frame local actual = frame : expandTemplate { title = template                                                                             ,  args  =  args } si se esperaba ~= actual entonces DebugHelper . raise ({ ScribuntoUnit = true , text = string. format ( "No se pudo afirmar que %s con argumentos %s es igual al esperado %s después del preprocesamiento" , DebugHelper . concatWithKeys ( args ), plantilla , esperado ), actual = actual , actualRaw = plantilla , esperado = esperado , mensaje = mensaje , }, 2 ) fin fin ------------------------------------------------------------------------------- -- Comprueba si una función genera un error -- @param fn la función a probar -- @param expectedMessage opcional el mensaje de error esperado -- @param message opcional descripción de la función de prueba ScribuntoUnit : assertThrows ( fn , expectedMessage , mensaje ) local exitoso , actualMessage = pcall ( fn ) si es exitoso entonces DebugHelper . raise ({ ScribuntoUnit = true , text = 'Se esperaba una excepción pero no se lanzó ninguna' , message = message , }, 2 ) end -- Para cadenas, elimina el número de línea agregado al mensaje de error actualMessage = type ( actualMessage ) == 'string' and string.match ( actualMessage , 'Module:[^:]*:[0-9]*: (.*)' ) or actualMessage local messagesMatch = DebugHelper . deepCompare ( expectedMessage , actualMessage ) if expectedMessage and not messagesMatch then DebugHelper . raise ({ ScribuntoUnit =                                                                                  true , expected = expectedMessage , actual = actualMessage , text = string.format ( 'Se esperaba una excepción con el mensaje %s, pero se obtuvo el mensaje %s' , tostring ( esperatedMessage ), tostring ( actualMessage ) ), message = message }, 2 ) end end ------------------------------------------------------------------------------- -- Comprueba si una función no genera un error -- @param fn la función a probar -- @param message descripción opcional de la función de prueba ScribuntoUnit : assertDoesNotThrow ( fn , message ) local successfullyed , actualMessage = pcall ( fn ) if successfully then return end -- Para cadenas, elimina el número de línea añadido al mensaje de error actualMessage = type ( actualMessage ) == 'string' and string.match ( actualMessage , 'Module:[^:]*:[0-9]*: (.*)' ) or actualMessage DebugHelper . raise ({ ScribuntoUnit = true , actual = actualMessage , text = string.format ( 'No se esperaba ninguna excepción, pero se obtuvo una excepción con el mensaje %s' , tostring ( actualMessage ) ), message = message }, 2 ) end ------------------------------------------------------------------------------- -- Crea una nueva suite de pruebas. -- @param o una tabla con funciones de prueba (alternativamente, las funciones se pueden agregar más tarde a la suite devuelta) -- function ScribuntoUnit : new ( o ) o = o or {} o . _tests = {} setmetatable ( o , { __index = self ,                                                            __newindex  =  function  ( t ,  k ,  v ) if type ( k ) == "string" and k : find ( '^test' ) and type ( v ) == "function" then -- Almacena las funciones de prueba en el orden en que fueron definidas table.insert ( o . _tests , { name = k , test = v }) else rawset ( t , k , v ) end end }) o . run = function ( frame ) return self : run ( o , frame ) end return o end ------------------------------------------------------------------------------- -- Restablece los contadores globales -- function ScribuntoUnit : init ( frame ) self . frame = frame o mw . getCurrentFrame () self . successCount = 0 self . failureCount = 0 self . skipCount = 0 self . resultados = {} fin ------------------------------------------------------------------------------- -- Ejecuta un solo caso de prueba -- @param nombre prueba número -- @param función de prueba que contiene afirmaciones -- función ScribuntoUnit : runTest ( suite , nombre , prueba ) local success , detalles = pcall ( prueba , suite ) si success entonces self . successCount = self . successCount + 1 table.insert ( self .                                                                        resultados ,  { nombre  =  nombre ,  éxito  =  verdadero } ) elseif tipo ( detalles ) ~ = ' tabla ' o no detalles . ScribuntoUnit entonces -- un error real , no una aserción fallida self.failureCount = self.failureCount + 1 tabla.insert ( self.resultados , { nombre = nombre , error = verdadero , mensaje = ' Error de Lua -- ' .. tostring ( detalles ) } ) elseif detalles.skipped entonces self.skipCount = self.skipCount + 1 tabla.insert ( self.resultados , { nombre = nombre , skipped = verdadero } ) else self.failureCount = self.failureCount + 1 mensaje local = detalles.fuente o " " si detalles.mensaje entonces mensaje = mensaje .. detalles.mensaje .. " \ n " fin mensaje = mensaje .. detalles .text table.insert ( self.results , { name = name , error = true , message = message , expected = details.esperate , actual = details.actual , testname = details.message }) end end ------------------------------------------------------------------------------- -- Ejecuta todas las pruebas y muestra los resultados .                                                                                         -- function  ScribuntoUnit : runSuite ( suite ,  frame ) self : init ( frame ) for i , testDetails in ipairs ( suite . _tests ) do self : runTest ( suite , testDetails . name , testDetails . test ) end return { successCount = self . successCount , failureCount = self . failureCount , skipCount = self . skipCount , results = self . results , } end ------------------------------------------------------------------------------- -- #invoke punto de entrada para ejecutar las pruebas. -- Se puede llamar sin un marco, en cuyo caso usará mw.log para la salida -- @param displayMode see displayResults() -- function ScribuntoUnit : run ( suite , frame ) local testData = self : runSuite ( suite , frame ) if frame y frame . args entonces devuelve self : displayResults ( testData , frame.args.displayMode o 'table' ) de lo contrario devuelve self : displayResults ( testData , ' log' ) fin fin ------------------------------------------------------------------------------- -- Muestra los resultados de la prueba -- @param displayMode : 'table', 'log ' o 'short' -- función ScribuntoUnit : displayResults ( testData , displayMode ) si displayMode == ' table' entonces devuelve self : displayResultsAsTable                                                      ( testData ) elseif displayMode == 'log' then return self : displayResultsAsLog ( testData ) elseif displayMode == 'short' then return self : displayResultsAsShort ( testData ) else error ( 'modo de visualización desconocido' ) end end function ScribuntoUnit : displayResultsAsLog ( testData ) if testData . failureCount > 0 then mw . log ( '¡FALLAS!' ) elseif testData . skipCount > 0 then mw . log ( 'Algunas pruebas no se pudieron ejecutar sin un marco y se omitieron. Invoque este conjunto de pruebas como plantilla para ejecutar todas las pruebas.' ) end mw . log ( string.format ( 'Afirmaciones: éxito: %d, error: %d, omitido: %d' , testData . successCount , testData . failureCount , testData . skipCount )) mw . log ( '-------------------------------------------------------------------------------' ) para _ , resultado en ipairs ( testData . results ) hacer si resultado . error entonces mw . log ( string. formato ( '%s: %s' , resultado . nombre , resultado . mensaje )) fin fin fin función ScribuntoUnit : displayResultsAsShort ( testData ) texto local = string. formato ( cfg . shortResultsFormat , testData . successCount , testData . failureCount , testData .                                                          skipCount ) si testData.failureCount > 0 entonces texto = ' < span class = " error " > ' .. texto .. ' </span> ' fin devolver texto fin función ScribuntoUnit : displayResultsAsTable ( testData ) iconoExito local , IconoExito = self.frame : preproceso ( cfg.successIndicator ) , self.frame : preproceso ( cfg.failureIndicator ) texto local = ' ' si testData.failureCount > 0 entonces local msg = mw.message.newRawMessage ( cfg.failureSummary , testData.failureCount ) : plain ( ) msg ​​= self.frame : preproceso ( msg ) si cfg.failureCategory entonces msg = cfg .failureCategory .. msg end text = texto .. failIcon .. ' ' .. msg .. ' \n ' else text = texto .. successIcon .. ' ' .. cfg . successSummary .. ' \n ' end text = texto .. '{| class="wikitable scribunto-test-table" \n ' text = texto .. '! \n ! ' .. cfg . nameString .. ' \n ! ' .. cfg . expectedString .. ' \n ! ' .. cfg . actualString ..' \n ' para _                                                                                      ,  resultado  en  ipairs ( testData . results )  hacer texto = texto .. '|- \n ' si resultado . error entonces texto = texto .. '| ' .. failIcon .. ' \n | ' si ( resultado . esperado y resultado . actual ) entonces nombre local = resultado . nombre si resultado . nombreprueba entonces nombre = nombre .. ' / ' .. resultado . nombreprueba fin texto = texto .. mw . texto . nowiki ( nombre ) .. ' \n | ' .. mw . texto . nowiki ( tostring ( resultado . esperado )) .. ' \n | ' .. mw . texto . nowiki ( tostring ( resultado . actual )) .. ' \n ' de lo contrario texto = texto .. mw . texto . nowiki ( resultado . nombre ) .. ' \n | ' .. ' colspan="2" | ' .. mw . texto . nowiki ( resultado . mensaje ) .. ' \n ' fin de lo contrario texto = texto .. '| ' .. successIcon .. ' \n | ' .. mw . texto . nowiki ( resultado . nombre ) .. ' \n | \n | \n ' fin fin texto =                                                                                      texto  ..  '|} \n ' devolver texto fin devolver ScribuntoUnit