## 2 Theoretical Background
### Fitness Function for Maximum Statement Coverage and Population Diversity  
In this section, we will formulate the fitness function of the genetic algorithm in such a way that maximizes statement coverage by both individual test cases and the whole test cases population. The first step of white-box testing is to translate the source code into a Control Flow Graph (CFG). In the CFG, the statements are represented as nodes (boxes) and the con-trol flows between the statements are represented as edges. Denote the vector of nodes of the CFG by \(\{s_{1},\,s_{2},\,\ldots,\,s_{n}\}\), where \(s_{j}\) is a separate node of CFG (one or more statements of the code). Note that the order of execution of separate nodes \(v_{1}\) may differ depending on various input data, since the program code contains conditional statements when computations are branched along several paths. Thus, different initial data of the program lead to traversing along different paths of the CFP, ensuring the execution of only quite specific (not all) statements of the program. Let us denote \(g(x_{i})\) a vector that is an indicator of the coverage of the graph nodes by a path initiated by a specific set of the test case \(x_{i}\):  
\[g(x_{i})=(g_{1}(x_{i}),\,g_{2}(x_{i}),\,\ldots,\,g_{n}(x_{i}))\]  
where  
\[g_{j}(x_{i})=\left\{ \begin{array}{c}1,\,if\,\,path\,\,initiated\,\,by\, test\,\,case\,x_{i}\,\,traverses\,\,through\,\,the\,\,node\,s_{j}\,;\\ 0,\,otherwise\end{array} \right.\]  
Assigning weights to edges of CFG, we can take into account the fact that different paths of executing program code have different complexity. More weights are assigned to statements that are critical, being part of the more error-prone paths. Following the procedure proposed in [29] an initial credit is taken (for example, 100 or 10), if CFG is dense. i.e., large numbers of statements are there, than initial credit should be taken as 100 and if CFG is sparse (small code) then it can be taken as 10. At each node of CFG, the incoming credit (the sum of the weights of all the incoming edges) is divided and distributed to all the outgoing edges of the node. For the conditional and loops statements, we have used an 80-20 rule: 80 percent of weight of the incoming credit is given to loops and branches and the remaining 20 percent of the incoming credit is given to the edges in sequential path. If we encounter a conditional statement with two or more conditions, fulfillment of each one leads to the execution of certain following statements, the weight of such a conditional statement is divided by the number of outgoing edges. Let us denote by \((w_{1},\ w_{2},\ \ldots,\ w_{n})\) a vector of weights assigned to all statements in accordance with the above-described method. Then the fitness function for the individual chromosome \(x_{i}\) can be formulated as follows  
\[F_{1}(x_{i})=\sum_{j=1}^{n}w_{j}g_{j}(x_{i}) \tag{4}\]  
Indeed, the higher the sum of weighted statements covered by a path initiated with the test case \(x_{i}\), the more fit is the chromosome \(x_{i}\). On the other hand, the use of Formula (4) for the fitness function will lead to a situation where the most adapted and capable of reproduction will always be individuals that lead to the most complex pieces of the code, to the detriment of the diversity of individuals in the population, since the population aspect in this formula not taken into account. As a result of using the GA with such a fitness function, we get the fittest individuals, however, if we evaluate the fitness of the resulting population as a whole, it will not provide maximum code coverage, since the chromosomes of the population will generate very similar paths. To ensure a greater diversity of the population, it is necessary to introduce into the fitness function a term that gives preference to chromosomes that provide the greatest possible distance from each other--all paths that are generated by test cases of the population's chromosomes.