En primer lugar se describe la estrategia de pruebas seguida. Para ello se describe el alcance de estas y el procedimiento de pruebas de regresión realizado.
Otro aspecto tratado es la descripción del entorno que se deberá utilizar para la realización de las pruebas. Esto incluye los requisitos de software y hardware necesarios.
Además se incluyen los perfiles y participantes necesarios para llevar a cabo los casos de prueba. Esto son los roles desde los que se llevarán a cabo las pruebas.
Por último se documentan las diferentes pruebas realizadas según el tipo al que estas pertenecen.
Para el diseño de las pruebas se ha tomado un enfoque funcional o de caja negra, centrada en la especificación de las funciones, la entrada y salida. La técnica utilizada consiste en definir los casos de pruebas a partir de clases de equivalencias:
Para asegurar la estabilidad en el resultado de las pruebas realizadas en cada iteración, se ha implementado un mecanismo que lleve a cabo las pruebas de forma regresiva, ejecutándose todo el conjunto de estas cada vez que una nueva funcionalidad del software es desarrollada.
Además de realizar pruebas funcionales en cada iteración, se han realizado una serie de pruebas no funcionales. Esta comprende aquellas que aseguran que se cumplen los requisitos no funcionales.
El usuario programador hace uso integro del sistema en función a los programas que desarrolle en el lenguaje. Un único programa, o conjunto finito de estos no son suficientes para probar todos los aspectos del sistema. Así aunque las pruebas son llevadas a cabo desde un perfil programador, estas no constituyen programas completos con un objetivo específico, sino baterías de pruebas que pretenden probar cada aspecto funcional del sistema.
Las pruebas unitarias están recogidas en un subsistema de la aplicación que automatizan su ejecución y asegura que son llevadas a cabo de forma regresiva.
A continuación se expone algunos ejemplos de las pruebas unitarias realizadas:
a = true;
a = false;
for (i = 0; i < 10; ++i) a = true;
a = b = true;
array[0] = true;
array[1] = true
for (i = 0; i < 10; ++i) array[i] = true;
str = "ABCDEF"; str[0] = false;
str = "ABCDEF"; str[0] = true;
while (size str) str[0] = false;
a = false; b = &a; a = true;
true = true;
true = false;
a = true = true;
0 == 0;
0 == 1;
1 == 0;
10 == 10;
10 == 2;
2 == 10;
-12 == -12;
-12 == 12;
12 == -12;
18.7 == 18.7;
18.7 == 18;
18 == 18.7;
-18.7 == -18;
-18.69 == -18.7;
18.069 == -18.0;
-11.7999999999999999 == -11.7999999999999999;
-11.7999999999999999 == -11.7999999999999991;
-11.7999999999999999 == -11.7999999999999998;
-11.7999999999999998 == -11.7999999999999999;
-11.79999999999999999 == -11.79999999999999998;
-11.79999999999999999 == -11.8;
999999999999999 == 1000000000000001;
10000000000000001 == 10000000000000001;
10000000000000001 == 10000000000000002;
10000000000000002 == 10000000000000001;
10000000000000002 == 10000000000000001;
9999999999999999 == 100000000000000001;
100000000000000001 == 100000000000000002;
100000000000000001 == 100000000000000002;
Los casos de pruebas expuestos a continuación comprenden la definión y posterior llamada de funciones con cuerpo vacío.
function empty_fun () { }
empty_fun ();
function empty_fun () { }
empty_fun ("param");
function empty_fun (param) { }
empty_func ("param");
function empty_fun (param) { }
empty_func ();
function empty_fun (param) { }
empty_func ("param1", "param2");
param = "param";
function empty_fun (¶m) { }
empty_func (param);
param = {"param"};
function empty_fun (¶m) { }
empty_func (param[0]);
function empty_fun (¶m) { }
empty_func (param);
function empty_fun (¶m) { }
empty_func ("const");
function empty_fun (param1, param2) { }
empty_func ("param1", "param2");
function empty_fun (param1, param2) { }
empty_func ("param1");
function empty_fun (param1, param2) { }
empty_func ("param1", "param2", "param3");
function empty_fun (param1, param2 = "default") { }
empty_function ("param1", "param2");
function empty_fun (param1, param2 = "default") { }
empty_function ("param1");
function empty_fun (param1, param2 = "default") { }
empty_function ();
function empty_fun (param1, param2 = "default") { }
empty_function ("param1", "param2", "param3");
function empty_fun (param1 = "default", param2 = "default") { }
empty_fun ("param1", "param2");
function empty_fun (param1 = "default", param2 = "default") { }
empty_fun ("param1");
function empty_fun (param1 = "default", param2 = "default") { }
empty_fun ();
function empty_fun (param1 = "default", param2 = "default") { }
empty_fun ("param1", "param2", "param3");
En esta sección se recogen algunos casos de pruebas de integración. Junto el software se facilita un sistema de pruebas que comprueba automáticamente todos los casos.
<< 22 / 2 + 8 - 5 * 2;
array = {22};
var = 5;
<< array[0] / 2 + 8 - var * 2;
function const2 () {
return 2;
}
array = {22};
var = 5;
<< array[0] / const2 () + 8 - var * const2 ();
<< !((true && true) || false );
array = {true};
var = true;
<< !((array [0] && var) || false );
function identity (param) {
return param;
}
array = {true};
var = true;
<< !((array [0] && var) || identity (false));
class fac {
function factorial (a) {
fac = 1;
this->recursiva (a, fac);
return fac;
}
private function recursiva (a, &factorial){
if (a > 0){
factorial *= a;
this->recursiva (a - 1, factorial);
}
}
}
f = new fac ();
<< f->factorial (4);
Para comprobar que el sistema cumple la funcionalidad para el que fue diseñado se han realizado una serie de programas tipos, recogiendo diversos estilos de programación, y de una naturaleza distinta. Estos programas han sido codificados en el lenguaje reconocido por el intérprete y se han realizado distintas comprobaciones sobre los mismos.
#!/usr/local/bin/omi
#Calculadora sencilla.
while ( true ) {
<< "=======================";
<< "Calculadora";
<< "Dame un numero";
>> a;
<< "Dame otro";
>> b;
<< "Dame una operacion [0=>suma], [1=>resta], [2=>multi], [3=>divide], [otro=>sale]";
>> op;
if (op == 0)
<< a << " + " << b << " = " << ( a + b );
elif (op == 1)
<< a << " - " << b << " = " << (a - b);
elif (op == 2)
<< a << " * " << b << " = " << (a * b);
elif (op == 3) {
if (op == 0)
<< "Error: no es posible dividir entre 0";
else
<< a << " / " << b << " = " << (a / b);
}
else {
<< "Adios";
break;
}
}
Un cuestioanrios se define mediante preguntas y posibles respuestas. Cada pregunta presenta una valor, la suma de los valores de todas las preguntas se corresponde con el valor del cuestionario. El usuario que realice el cuestionario sacará una nota que se corresponderá con una parte del total según las preguntas que responda correctamente.
Cada pregunta del cuestionario tendrá una serie de posibles respuestas, las respuestas pueden ser de dos tipos:
Este programa ha sido modelado usando programación orientada a objetos. Se presenta un fichero de código fuente por cada clase que conforma el sistema de cuestionarios, otro fichero la definición del DSL junto con el flujo principal que conforma el motor de cuestionarios, y otro fichero que se corresponde con un custionario de ejemplo.
A continuación el diagrama de clases que ilustrna el diseño del sistema:
file: quiz_system.omi
#!/usr/local/bin/omi
#Sistema de cuestionarios
#=======================================================================
include "quiz.class.omi";
#=======================================================================
global quiz;
#=======================================================================
#Funciones del DSL
~multichoice (text, rating) {
quiz->add_question (new MultiChoice (text, rating));
}
~text (text, rating) {
quiz->add_question (new Text (text, rating));
}
~option (text, correct = null) {
quiz->last_question()->add_option(new Option (text, correct));
}
#=======================================================================
if (args[1]){
title = args[2]?:"Sin titulo";
<< title;
quiz = new Quiz (title);
include args[1];
quiz->run_quiz();
}
else
<< "Debe indicar un cuestionario";
#=======================================================================
file: quiz.class.omi
#quiz.class.omi
#=======================================================================
include "question.class.omi";
#=======================================================================
class Quiz {
name = '';
questions = {};
~ Quiz (name) {
this->name = name;
}
~ add_question (question) {
this->questions[size this->questions] = question;
}
~ last_question () {
return this->questions [(size this->questions) - 1];
}
~ run_quiz () {
count = 0;
total = 0;
$(this->questions) {
if ($->ask ()) count += $->rating;
total += $->rating;
}
<< "Tienes " << count << " respuestas correctas de " << total;
}
}
#=======================================================================
file: question.class.omi
#question.class.omi
#=======================================================================
include "option.class.omi";
#=======================================================================
class Question {
title = "";
rating = 0;
options = {};
~ Question (title, rating) {
this->title = title;
this->rating = rating;
}
~ add_option (option) {
this->options [(size this->options)] = option;
}
}
#-----------------------------------------------------------------------
class Text extends Question {
~ Text (title, rating) {
this->Question (title, rating);
}
~ ask () {
<< "";
<< this->title << " (" << this->rating << ")";
<< "Introducir respuesta: ";
>> ans;
n = size (this->options);
for (i = 0; i < n; ++i) {
if (ans == this->options[i]->title)
return true;
}
return false;
}
}
#-----------------------------------------------------------------------
class MultiChoice extends Question {
~ MultiChoice (title, rating) {
this->Question (title, rating);
}
~ ask () {
<< this->title << " (" << this->rating << ")";
count = 0;
$(this->options) << (++count) << " - " << $->title;
<< "Introducir respuesta: ";
>> ans;
return (this->options[ans - 1]) && this->options[ans - 1]->correct;
}
}
#=======================================================================
file: option.class.omi
#option.class.omi
#=======================================================================
class Option {
title = "";
correct = "";
~ Option (title, correct){
this->title = title;
this->correct = correct;
}
}
#=======================================================================
input file: quiz.q
#Ejemplo de cuestionario.
multichoice("Cuanto tiempo duro la guerra de los 100 annos?", 2.5);
option (100, false);
option (116, true);
option (90, false);
option (102, false);
multichoice("Un simil es ...", 2.5);
option ("Una comparacion", true);
option ("Una duda", false);
option ("Un aparato para medir el tiempo", false);
text ("En que provincia desemboca el rio Gualquivir?", 2.5);
option("Cadiz", true);
option("cadiz", true);
Para ejecutar el cuestionario en una terminal de comandos:
prompt$ ./quiz_system.omi quiz.q "Cuestionario"
No es difícil darse cuenta que si ambos jugadores utilizan la estrategia más óptima el juego terminará en empate. Al ser un juego sencillo se utiliza para enseñar conceptos de teoría de juegos y, dentro de la inteligencia artificial, la búsqueda de árboles de juego.
El programa en primer lugar solicita el nombre y tipo de los jugadores, pudiéndose ser estos humanos o máquinas. Luego turno a turno va solicitando a cada jugador una posición vacía de la cuadrícula en la que efectuar el movimiento, esto se hace hasta que se da una línea ganadora o hasta que se completa la cuadrícula.
Para determinar el movimiento o acción llevada en cada turno se prosigue de la siguiente forma:
El programa se divide en tres módulos, cada uno correspondiente a un fichero. En un fichero se disponen las funciones de entrada y salida, tales como solicitar los datos de los jugadores, imprimir el tablero, etc. En otro fichero se encuentran las funciones de inteligencia artificial para el caso de jugadores de tipo máquina. Y en otro se encuentra el flujo principal correspondiente al bucle de juego.
file: IO.omi
#IO.omi
#=======================================================================
~IOJugadores () {
jugadores = {};
for (i = 1; i <= 2; ++i) {
<< "Nombre Jugador " << i;
>> nombre;
<< "Tipo Jugador " << i << " [ 0 => Humano, otro => Maquina ]";
>> tipo;
if (tipo != 0)
tipo = 1;
jugadores [] = {
'nombre' : nombre,
'tipo' : tipo,
'token' : (( i == 1)?1:-1),
};
}
return jugadores;
}
#-----------------------------------------------------------------------
~ IOTablero (tablero) {
for (i = 0; i < 3; ++i)
<< IOToken(tablero[i][0]) << " or "
<< IOToken(tablero[i][1]) << " or "
<< IOToken(tablero[i][2]);
}
#-----------------------------------------------------------------------
~ IOToken (pos) {
if (pos == 1)
return 'X';
elif (pos == -1)
return 'O';
else
return '#';
}
#-----------------------------------------------------------------------
~ IOMover (tablero) {
do {
<< "Dame la fila";
>> row;
<< "Dame la columna";
>> col;
}while (tablero[row][col] !== 0);
return {row, col};
}
#-----------------------------------------------------------------------
~IOGanador (jugadores, ganador) {
if (ganador == 1 ){
<< "El ganador es " << jugadores[0]["nombre"];
}elif (ganador == -1){
<< "El ganador es " << jugadores[1]["nombre"];
}else{
<< "La partida ha quedado en empate";
}
}
#=======================================================================
file: AI.omi
#AI.omi
#=======================================================================
~primerosMov (tablero) {
if (!tablero[1][1])
return {1,1};
do {
col = row = time () % 2;
if (row == 1) row = 2;
if (col == 1) col = 2;
}while (tablero[row][col] !== 0);
return {row, col};
}
#-----------------------------------------------------------------------
~ miniMax (A, turno){
mejor = turno * -1;
minMov = 9;
poda = 1;
Mov = 0;
posicion = {0, 0};
if (!(t_ganador = procesarTablero (A)) && !tableroLleno (A)){
for (cont = 0; cont < 3 && poda; cont ++)
for (cont2 = 0; cont2 < 3 && poda; cont2 ++){
if ( A [cont] [cont2] == 0){
A [cont] [cont2] = turno;
actual = miniMax_R (A, turno * -1,0,Mov);
if (turno == 1 ){
if ( actual >= mejor && Mov <= minMov){
mejor =actual;
posicion [0] = cont;
posicion [1] = cont2;
if (mejor == turno){
minMov = Mov;
if (mejor == 1 && minMov == 0)
poda = 0;
}
}
} else
if ( actual <= mejor && Mov <= minMov){
mejor =actual;
posicion [0] = cont;
posicion [1] = cont2;
if (mejor == turno){
minMov = Mov;
if (mejor == 1 && minMov == 0)
poda = 0;
}
}
A [cont] [cont2] = 0;
}
}
}
return posicion;
}
#-----------------------------------------------------------------------
~ miniMax_R (&A, turno, nMov, &Mov){
mejor = turno * -1;
poda = 1;
minMov = 9 ;
if (!(t_ganador = procesarTablero (A)) && !tableroLleno (A)){
for (cont = 0; cont < 3 && poda; cont ++){
for (cont2 = 0; cont2 < 3 && poda; cont2 ++){
if ( A [cont] [cont2] == 0){
A [cont] [cont2] = turno;
actual = miniMax_R (A, turno * -1, nMov +1, Mov);
if (turno == 1 ){
if ( actual >= mejor && Mov <= minMov){
mejor =actual;
if (mejor == turno){
minMov = Mov;
if (mejor == 1 && minMov == 0)
poda = 0;
}
}
} else
if ( actual <= mejor && Mov <= minMov){
mejor =actual;
if (mejor == turno){
minMov = Mov;
if (mejor == 1 && minMov == 0)
poda = 0;
}
}
A [cont] [cont2] = 0;
}
}
}
Mov = minMov;
return mejor;
}
Mov = nMov;
return t_ganador;
}
#-----------------------------------------------------------------------
~procesarTablero (A) {
ganador = 0;
cont = 0;
for (cont = 0; cont < 3 && ganador == 0; cont ++){
if (A [cont] [0] == A[cont] [1] && A [cont] [1] == A [cont] [2])
ganador = A [cont] [1];
}
for (cont = 0; cont < 3 && ganador == 0; cont ++)
if (A [0] [cont] == A [1] [cont] && A [1] [cont] == A [2] [cont])
ganador = A [0] [cont];
if (A [0][0] == A [1][1] && A [1][1] == A [2][2] && ganador == 0 )
ganador = A [0][0];
if (A [0][2] == A [1][1] && A [1][1] == A [2][0] && ganador == 0)
ganador = A [0][2];
return ganador;
}
#-----------------------------------------------------------------------
~ tableroLleno (A){
resp = 1;
for (cont = 0; cont < 3 && resp; cont ++)
for (cont2 = 0; cont2 < 3 && resp; cont2 ++)
resp = A [cont] [cont2] != 0;
return resp;
}
#=======================================================================
file: tictactoe.omi
#!/usr/local/bin/omi
#=======================================================================
include "IO.omi";
include "AI.omi";
#-----------------------------------------------------------------------
~juego () {
tablero = {{0,0,0},{0,0,0},{0,0,0}};
posicion = {0,0};
turno = 0;
jugadores = IOJugadores ();
while (!(ganador = procesarTablero (tablero)) && !tableroLleno (tablero)){
<< "----------------------------------------------";
IOTablero (tablero);
<< "\nTurno " << jugadores[turno%2]['nombre'];
if (jugadores[turno%2]['tipo'] == 0) {
posicion = IOMover (tablero);
}else {
<< "Calculando movimiento...";
if (turno <= 1) {
posicion = primerosMov (tablero);
}else {
posicion = miniMax (tablero, jugadores[turno%2]['token']);
}
}
tablero[posicion[0]][posicion[1]] = jugadores[turno%2]['token'];
turno ++;
}
IOTablero (tablero);
IOGanador (jugadores, ganador);
}
#-----------------------------------------------------------------------
juego ();
#======================================================================$
El interprete debe presentar un rendimiento óptimo en cuanto tiempo de interpretación. Dado que su objetivo no es constituir una herramienta para la producción de softwatre este aspecto no es crítico, no obstante debe cumplir unos mínimos para que sea operativo.
Por otro lado un programa interpretado no puede excederse en la memoria física que ocupa. Para ello se debe medir la cantidad de memoria de las entidades que conforma el programa.
Además se debe asegurar dentro de unos márgenes que el intérprete está libre de vulnerabilidades y que no es posible hacer un uso indebido del mismo para explotar la plataforma sobre la que se ejecuta o el propio sistema software.
Se considera que el sistema supera las pruebas de rendimiento siempre y cuando el tiempo en pasar los benchmarks sea inferior al doble de los lenguajes pensados para la producción software.
A continuación el código fuente:
file: fibonacci.omi
#!/usr/local/bin/omi
#fibonacci.omi
#=======================================================================
~ fibonaci (n) {
if (n == 1 || n == 2)
return 1;
else
return fibonaci (n - 1) + fibonaci (n - 2);
}
#-----------------------------------------------------------------------
<< fibonaci (args[1]);
#=======================================================================
Los tiempos obtenidos frente otros lenguajes son los siguientes:
| Tamaño de entrada | Tiempo (s) |
|---|---|
| 10 | 0.020 |
| 20 | 0.104 |
| 30 | 8.720 |
| Tamaño de entrada | Tiempo (s) |
|---|---|
| 10 | 0.043 |
| 20 | 0.054 |
| 30 | 5.622 |
| Tamaño de entrada | Tiempo (s) |
|---|---|
| 10 | 0.023 |
| 20 | 0.029 |
| 30 | 4.963 |
El primer benchmark al que ha sido sometido el sistema se denomina ``n-body''. Este conciste en una simulación de un sistema dinámico de partículas que se encuentran bajo la influencia de fuerzas físicas como la gravedad.
El código fuente para la prueba es el siguiente:
file: n-body.omi
#!/usr/local/bin/omi
#=======================================================================
~ energy(&b) {
e = 0.0;
m = size (b);
for (i=0; i < m; ++i) {
b1=b[i];
e += 0.5*b1[6]*(b1[3]*b1[3]+b1[4]*b1[4]+b1[5]*b1[5]);
for (j=i+1; j<m; j++) {
b2=b[j];
dx=b1[0]-b2[0]; dy=b1[1]-b2[1]; dz=b1[2]-b2[2];
e -= (b1[6]*b2[6])/sqrt(dx*dx + dy*dy + dz*dz);
}
}
return e;
}
pi=3.141592653589793;
solar_mass=4*pi*pi;
days_per_year=365.24;
bodies = {
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, solar_mass }, //Sun
{
4.84143144246472090, //Jupiter
-1.16032004402742839,
-0.103622044471123109,
0.00166007664274403694 * days_per_year,
0.00769901118419740425 * days_per_year,
-0.0000690460016972063023 * days_per_year,
0.0009.54791938424326609 * solar_mass
},
{
8.34336671824457987, // Saturn
4.12479856412430479,
-0.403523417114321381,
-0.00276742510726862411 * days_per_year,
0.00499852801234917238 * days_per_year,
0.00002.30417297573763929 * days_per_year,
0.000285885980666130812 * solar_mass
},
{
12.8943695621391310, // Uranus
-15.1111514016986312,
-0.223307578892655734,
0.00296460137564761618 * days_per_year,
0.00237847173959480950 * days_per_year,
-0.0000296589568540237556 * days_per_year,
0.0000436624404335156298 * solar_mass
},
{
15.3796971148509165, // Neptune
-25.9193146099879641,
0.179258772950371181,
0.00268067772490389322 * days_per_year,
0.00162824170038242295 * days_per_year,
-0.0000951592254519715870 * days_per_year,
0.0000515138902046611451 * solar_mass
}
};
// offset_momentum
px=py=pz=0.0;
for (bodies as e) {
px+=e[3]*e[6];
py+=e[4]*e[6];
pz+=e[5]*e[6];
}
bodies[0][3] = -1 * (px) / solar_mass;
bodies[0][4] = -1 * (py) / solar_mass;
bodies[0][5] = -1 * (pz) / solar_mass;
pairs = {};
m=size(bodies);
for (i=0; i<m; ++i)
for (j=i+1; j<m; j++)
pairs[] = {bodies[i], bodies[j]};
n = args[1];
<< energy(bodies);
i=0;
do {
for (pairs as p) {
a=p[0]; b=p[1];
dx=a[0]-b[0]; dy=a[1]-b[1]; dz=a[2]-b[2];
dist = sqrt(dx*dx + dy*dy + dz*dz);
mag = 0.01/(dist*dist*dist);
mag_a = a[6]*mag; mag_b = b[6]*mag;
a[3]-=dx*mag_b; a[4]-=dy*mag_b; a[5]-=dz*mag_b;
b[3]+=dx*mag_a; b[4]+=dy*mag_a; b[5]+=dz*mag_a;
}
for (bodies as b) {
b[0]+=0.01*b[3]; b[1]+=0.01*b[4]; b[2]+=0.01*b[5];
}
} while(++i<n);
<< energy(bodies);
Los tiempos obtenidos frente otros lenguajes son los siguientes:
| Tamaño de entrada | Tiempo (s) |
|---|---|
| 500.000 | 14.10 |
| 5.000.000 | 240.4 |
| 50.000.000 | 1243.02 |
| Tamaño de entrada | Tiempo (s) |
|---|---|
| 500.000 | 7.10 |
| 5.000.000 | 69.00 |
| 50.000.000 | 719.66 |
| Tamaño de entrada | Tiempo (s) |
|---|---|
| 500.000 | 9.86 |
| 5.000.000 | 96.17 |
| 50.000.000 | 967.81 |
Dado que el interprete es una herramienta con la que se van a escribir otros programas, el uso de memoria que haga este influye en gran medida en la cantidad que ocuparán los programas con son interpretados. De esta forma si el interprete no hace un uso óptimo de la memoria los programas que este procesará tampoco.
Las unidades mínimas sobre las que opera el interprete son los nodos ejecutables. Así en primer lugar se va a medir cuánto ocupa los nodos ejecutables básicos y más comunes. Cabe decir que la representación interna de los distintos tipos de datos puede ser configurada como opciones de compilación, es por ello que se presenta la medición en función las distintas configuraciones posibles, indicándose solo aquellas que presentan un esquema óptimo debido a factores como el alineamiento.
La longitud del alineamiento en todos los casos viene dado por el puntero a la tabla de métodos virtuales. Este elemento referencia a una tabla que indexa los métodos de los que dispone un objeto debido a la jerarquía de herencia con la que se definió. Al ser un puntero su tamaño dependerá de la arquitectura del equipo.
En el siguiente diagrama se presenta la memoria ocupada por un nodo de tipo lógico según las distintas combinaciones para la representación interna de los datos:
En el siguiente diagrama se presenta la memoria ocupada por un nodo de tipo aritmético según las distintas combinaciones para la representación interna de los datos:
En el siguiente diagrama se presenta la memoria ocupada por un nodo de tipo cadena de caracteres según las distintas combinaciones para la representación interna de los datos:
La seguidad digital de un empresa se debe comprobar en una serie de niveles, tal que se han de realiza auditorias internas, perimetrales, pruebas APT, etc. Sin embargo, el objetivo de este punto es medir la calidad en función de la seguridad del software desarrollado. Así, para asegurar que la aplicación cumple un mínimo de seguridad se han realizado una serie de auditorías al software.
En el tipo de pruebas realizadas solo se ha tenido en cuenta el software correspondiente al interprete, dejando fuera todo el sistema web que conforma la plataforma de distribución. Un sistema web se ve afectado por tipos de vulnerabilidades tales como DoS, XSS, CSRF, SQL injectión, sistemas de autentificación... Por otro lado en un software de escritorio, como puede ser el interprete, se ve afectado por otro tipos de vulnerabilidades comunes.
Las pruebas que se han realizado sobre el software se enfocan en la entrada del usuario y se pueden categorizar de la siguiente forma:
| Desbordamiento de buffer |
| Desbordamiento de buffer por variables de entorno |
| Desbordamiento de buffer por recursos binarios |
| Injección de código |
| Salto de directorio (path traversal) |
This document was generated using the LaTeX2HTML translator Version 2008 (1.71)
Copyright © 1993, 1994, 1995, 1996,
Nikos Drakos,
Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999,
Ross Moore,
Mathematics Department, Macquarie University, Sydney.
The command line arguments were:
latex2html -no_subdir -split 0 head.tex -html_version 4.0,latin1,unicode
The translation was initiated by franj on 2016-01-16
franj 2016-01-16