## Articoli

## From soft. routine to math. function

*On a method to to reduce a generic Software Routine into a mathematical function, and possible applications for the Black Box (Functional) Software Testing*

In this article I describe a method that can be used to reduce a general software routine, that accept input alphanumeric values and return alphanumerics output values, into a mathematical function.

A generic software routine take and produce alphanumeric strings as input/output and, generally speaking, there are no ways to define an order in these strings, i.e. between two strings, to say which string come before or after the other. To better explain the concept, consider a simple software routine that produce as output the reverse string it takes as input. This routine can be defined as a mathematical function, in this way: f(x_{1} x_{2}... x_{n})=x_{n} x_{(n-1)} ... x_{1} where x_{n} x_{(n-1)} ... x_{1} are generic alphanumerics characters. If we would like to draw a Cartesian graph of the function we need to know if, for example, the string x_{n} x_{(n-1)} ... x_{1} comes before or after the other string x_{n} x_{(n-1)} ... x_{(n-5)} or any other string we can use as input of the function. If we are able to reduce a software routine into a well defined mathematical function, we are able also to use the mathematical well-know methods to test the same function, sampling some of the input values of the function (in some statistical ways) to verify if the output of the same function for these input values are as expected. This method, that is strictly a black-box method, should also be applied to any routine with whatsoever number of inputs and outputs; it's clear that in these cases we have to deal with multi variables functions.

In this artice we will not deal with statistical sampling methods, but we will only describe a method to associate a generic string with a number, in a unambiguous way, and then discuss how to apply this method for the test and the regression test of generic software routines. If you are interested in the details, download the complete article published on the Testing Experience magazine (article's URL: http://www.testingexperience.com/testingexperience03_08.pdf ) at the end of the article or read it online here.

With the analysis details I've also developed some Perl scripts that implement what I summarized above. The scripts (downloadable with the article too) are:

**Script # 1**. This script, called *StringToNumber.pl* takes as input a string and a dictionary, in the forms of an array of chars separated by space and return the number equivalent to the input string. To run the script, from DOS or *IX system, you need to run the following command:

`perl StringToNumber.pl <input string> <dictionary>`

For example:

`perl StringToNumber.pl ABECDEADD "A B C D E"`

returns the number 637549 Yo can avoid to explicitly call “perl” interpreter before the script name if you give the execution permission (chmod +x StringToNumber.pl) on *IX system to the script. In windows depends on how your system is configured. We do not bother you with these details. A DOS script called *runStringToNumber.bat* should also be used to run the script (avoiding to write the dictionary - that usually is fixed - all the times) passing only the string input parameter, in this way:

`runStringToNumber.bat ABECDEADD`

#!/usr/bin/perl -w #------------------------------------------------------------------------------- # Program: StringToNumber.pl # Version: 1.0 # Date : 25 May 2008 # Author: Berta Danilo # License: GPL version 3 (see below). # # Program description: # The program implements the method described in the # documents: "On a method to to reduce a generic Software # Routine into a mathematical function, and possible # applications for the Black Box (Functional) Software Testing" # to convert a string into a number. Please, refer to the document # for detail about the method implemented. # # Limitation: # The program does not control: # -> Wrong dictionary format as input data # In this case the program will abort and/or return wrong results. #------------------------------------------------------------------------------- # Get input data from consolle # Verify the number of inputs passed (must be 2) if($#ARGV != 1 ){ print "Wrong number of input arguments. Required: string and dictionary"; exit(1); } # Input string to be transformed into a number, taking care of the input # dictionary $instring = $ARGV[0]; # Get the dictionary. @dictionary = split(" ",$ARGV[1]); # Get the base value from the number of elements in dictionary $base = @dictionary; # Length of the input string $len = length($instring); # Start to read the string sequentially (char by char), with the purpose to # calculate the number using the formula: # N = a_1*base^(len-1)+a_2*base^(len-2)+ ... + a_len $number = 0; # The final number to be calculated for($i=0;$i<=$len-1;$i++){ # Single char read from the string $char = substr($instring,$i,1); # The power the base must be raised. As for the formula above, the first # power is (len-1) - case when i=0 - and then decrement by one until # $power = 0. $power = $len - $i - 1; # In what follow, start to read the array. If a letter is found that is not # in the dictionary, an error is raised. It can be there are some more short # way to perform the operation (without a cycle). I'll think about another # time. $error = 1; # 1 means true: it's supposed an error for default. # Pessimistic point of view. for($j=0;$j<=$#dictionary;$j++) { if($char eq $dictionary[$j]) # The letter was found in the dictionary { # Get the position of the letter in the dictionary. # First position = 1) $position = $j + 1; # Calculate the output number chunk by chunk using the formula # reported above. $number = $number + $position*($base**$power); $error = 0; # Reset the error } } # If error is raised (char does not belong to the dictionary) # stop the cycle. if($error == 1){ print "String with char not in the dictionary: invalid string\n"; exit(1); } } # Return the number. print $number;

**Script # 2**. This script, called *NumberToString.pl* takes as input a number and a dictionary, in the forms of an array of chars separated by space and return the number equivalent to the input string. To run the script, from DOS or *IX system, you need to run the following command:

`perl NumberToString.pl <input number> <dictionary>`

For example:

`perl NumberToString.pl 637549 "A B C D E"`

and return the string: ABECDEADD. The same considerations for the script # 1 are valid for this one. A DOS script called `runNumberToString.bat`

should also be used to run the script passing only the string input parameter, in this way:

`runNumberToString.bat 637549`

#!/usr/bin/perl -w #------------------------------------------------------------------------------- # Program: NumberToString.pl # Version: 1.0 # Date : 25 May 2008 # Author: Berta Danilo # License: GPL version 3 (see below). # # Program description: # The program implements the method described in the # documents: "On a method to to reduce a generic Software # Routine into a mathematical function, and possible # applications for the Black Box (Functional) Software Testing" # to convert a number into a string. Please, refer to the document # for detail about the method implemented. # # Limitation: # The program does not control: # -> Wrong number format as input data. # -> Wrong dictionary format as input data # In both the case the program will abort and/or return wrong results. #------------------------------------------------------------------------------- # ---- START OF THE PROGRAM ---- # Get input data from consolle # Verify the number of inputs passed (must be 2) if($#ARGV != 1 ){ print "Wrong number of input arguments. Required: number and dictionary"; exit(1); } # Get the input number to convert into a string $number = $ARGV[0]; # Get the dictionary. @dictionary = split(" ",$ARGV[1]); # Get the base value from the number of elements in dictionary $base = @dictionary; #Variables inizialization. Only trapped negative numbers or zero if($number <= 0) { $continue = 0; # When false (0) the process finish } else { $continue = 1; # When true (1) the process continue } @out = (); # Contain the output string # ------------------------------------------------- # It will be possible to use a recurring function # For now, we prefer to follow step by step the # process as defined in the document referenced # in the head of the script. # ------------------------------------------------- # Start the process. The while cycle exit when $continue=0 while ($continue) { # Step 1: calculate the division result and the remainder $remainder = $number%$base; $result = int($number/$base); #Step 2: if the remainder is zero, replace it by the dictionary's base value #and subtract 1 to the result. if($remainder==0) { $result = $result-1; $remainder = $base; } # Start to insert data into the array that contain the output string, adding # element on the "head" of the array (unshift function) unshift @out, $dictionary[$remainder-1]; #Step 3: prepare the data for the next cycle. Assign to the dividend of the #next division , the result just calculated $number = $result; #Step # 4: verify if the exit condition from the while cycle are verified #This happen when the division result is zero. if($result==0) { $continue = 0; } } # Print out the result in consolle print @out; # ------------------------------------------------------------------------------ # ---- TECHNICAL NOTES ---- # # Note # 1: # # From http://en.wikipedia.org/wiki/Floor_function: # # C and related programming languages have a feature called type casting which # allows to turn a floating point value into an integer by prefixing it with # (int). # This operation is truncation or the round to zero method, a mixture of the # floor and ceiling function: # # -->> # for positive or 0 x it returns floor(x), and for negative x it returns # ceiling(x) #<<--- # # # Many other languages, such as Java (tested with Sun JDK version 1.5.0_05), # Perl (as of version 5.8.0), and PHP (tested on version 5.2.1) behave similarly # and exhibit rounding errors, as does the POSIX floor() # function, every time floating point types are used to store real values. # # # From INT function perl's man page: # # Returns the integer portion of EXPR. If EXPR is omitted, uses $_ . # You should not use this function for rounding: one because it truncates # towards 0 , and two because machine representations of floating point numbers # can sometimes produce counterintuitive results. # For example, int(-6.725/0.025) produces -268 rather than the correct -269; # that's because it's really more like -268.99999999999994315658 instead. # Usually, the sprintf, printf, or the POSIX::floor and POSIX::ceil functions # will serve you better than will int(). # # SUMMARY: # I've to use the int function for positive number ONLY, because it's exactly # the same to the POSIX's floor. Any way, I'm interested in positive numbers # only. # # # ------------------------------------------------------------------------------

**Script # 3**. This script, called* EvaluateFunction.pl* implements both the scripts #1 and #2. It takes as input a dictionary, in the forms of an array of chars separated by space and return the table of the result of the function that should be used to plot the cartesian diagram of the same function. The function is written inside the code (that it's not so nice, but it's only a prof of concept script).

#!/usr/bin/perl -w #------------------------------------------------------------------------------- # Program: EvaluateFunction.pl # Version: 1.0 # Date : 25 May 2008 # Author: Berta Danilo # License: GPL version 3 (see below). # # Program description: # The program perform the reduction of a software funcion, working # with alphanumerics input/output string into a equivalent-numeric # mathematical function, as described in the documents: # "On a method to to reduce a generic Software Routine into # a mathematical function, and possible applications for the Black Box # (Functional) Software Testing". # Please, refer to the document for detail about the method implemented. # Go to line 59 (or search for 'function') to personalize your function. # # Limitation: # The program does not control: # -> Wrong number format as input data. # -> Wrong dictionary format as input data # In both the case the program will abort and/or return wrong results. #------------------------------------------------------------------------------- # ---- START OF THE PROGRAM EvaluateFunction ---- # Get input data from consolle # Verify the number of inputs passed (must be 1, the dictionary) if($#ARGV != 1 ){ print "Wrong number of input arguments. Required: dictionary, points' number"; exit(1); } # Get the dictionary. @dictionary = split(" ",$ARGV[0]); # Get the base value from the number of elements in dictionary $base = @dictionary; $numpoints = $ARGV[1]; # Print the header print "\n\n"; print "X num" . "\t" . "Y num" . "\t\t" . "X str" . "\t" . "Y str" . "\n"; # Main of the program - evaluate the function for($xValueNumber=1;$xValueNumber<=$numpoints;$xValueNumber++) { # Calculate the string x-values from number x-value (cycle variable) $xValueString = &NumberToString($xValueNumber); #------------------------------------------------------------------------------- # Write here your function that operate on the $xValueString input string # The 'reverse' function simply reverse the string. I.e. ABC become CBA $yValueString= reverse $xValueString; #------------------------------------------------------------------------------- # calculate the number y-values from the y-string value $yValueNumber = &StringToNumber($yValueString); # Print out the table of results print $xValueNumber . "\t" . $yValueNumber . "\t\t" . $xValueString . "\t" . $yValueString . "\n"; }

To use the script you need to:

- Personalize the function you would like to generate the data to plot in the main routine of the program. As default, the function is the “
*string reverse*”, that produce as output the reversed input string. For example ABC become CBA. - Call the program as:

`perl EvaluateFunction.pl <dictionary> <number of point>`

The output will be a table of data (separated by tabs) with *<number of point>* points with the x input and y output string and equivalent numeric value of the software function. For example, the output of the command:

`perl EvaluateFunction.pl "A B C D E" 10`

will be a 10 value table as following:

X_{ num} (original string) |
Y_{num}(reverse string) |
X (original string) | Y (reverse string) |

1 | 1 | A | A |

2 | 2 | B | B |

3 | 3 | C | C |

4 | 4 | D | D |

5 | 5 | E | E |

6 | 6 | F | F |

7 | 7 | AA | AA |

8 | 13 | AB | BA |

9 | 19 | AC | CA |

10 | 25 | AD | DA |

The first columns is the X input numbers equivalent of the input strings in the third column, while the second columns is the Y output numbers equivalent of the output strings in the fourth column (that is the real output of the reverse string function, or whatever function you decide to call).

These scripts were tested for Perl version v5.10.0 built for MSWin32-x86-multi-thread for windows operating system (Windows Vista) and Perl version v5.8.8 build for i486- linux-thread-multi onto debian version (Kurumin). These are not so much control of the formal validity of the uses inputs (wrong number format, wrong dictionary format and so on), so please take care to use the right format, elsewhere the result is non guarantee.

The plot of the "*reverse string*" function is the following:

Below it's possible to download all the scripts and the article.