Files
Gen4_R-Car_Trace32/2_Trunk/demo/t32cast/eca/coverage.c
2025-10-14 09:52:32 +09:00

757 lines
20 KiB
C

#include "coverage.h"
#define TRUE 1
#define FALSE 0
#define CTRL_IDX 0xa
#define FUNCTION_LIKE_MACRO(idx__, val__) do { \
(array[(idx__)] != 0xffu && array[(idx__) + 1u] != 0xffu) ? \
(((idx__) == (val__)) ? SetFalse(&(val__)) : SetTrue(&(val__))) : \
SetFalse(&(val__)); \
} while (0)
struct Compound {
int a;
int b;
int c;
int d;
int e;
int f;
};
enum Color {
RED = 0,
YELLOW = -1,
BLUE = 1,
ORANGE = -2,
GREEN = 2,
};
static volatile unsigned char array[5] = { 0xff, 0xff, 0xa, 0xb, 0 };
static int Identity(int const a)
{
return a;
}
static void SetTrue(int* value)
{
value[0] = TRUE;
}
static void SetFalse(int* value)
{
value[0] = FALSE;
}
static int TestFunctionLikeMacro(void)
{
int result = -1;
FUNCTION_LIKE_MACRO(0, result);
return result;
}
static unsigned ComplexBooleanParameter(int const a, int const b, int const c, int const d)
{
unsigned outcome = FALSE;
if (Identity((!a || !(b > -36)) && (!Identity(c) && !(Identity(d) > 2)))) {
outcome = TRUE;
}
else {
outcome = FALSE;
}
return outcome;
}
static void TestComplexBooleanParameter(void)
{
ComplexBooleanParameter(-4768, 5003, 8031, 5240);
ComplexBooleanParameter(-4768, -36, 6858, 5240);
ComplexBooleanParameter(-4768, -36, 0, 3335);
ComplexBooleanParameter(0, -102, 0, 2);
ComplexBooleanParameter(-4768, -36, 0, 2);
}
static unsigned ComplexFor(int const a, int const b, int const c, int const d)
{
unsigned num_cycles = 0u;
for (; (((a || b) && (c > -23)) || (Identity(d) < 5)); num_cycles++) {
if (num_cycles > 1u) {
break;
}
}
return num_cycles;
}
static void TestComplexFor(void)
{
/* Set of test vectors for MC/DC */
ComplexFor(0, 0, -22, 5);
ComplexFor(0, 0, -23, 5);
ComplexFor(0, 1, -23, 5);
ComplexFor(0, 0, -23, 4);
ComplexFor(0, 1, -22, 5);
ComplexFor(1, 0, -22, 5);
}
static unsigned ComplexDoWhile(int const a, int const b, int const c, int const d)
{
unsigned num_cycles = 0u;
do {
if (num_cycles > 1u) {
break;
}
num_cycles++;
}
while (((!(Identity(a) >= -45) && Identity(b)) && Identity(c)) || d);
return num_cycles;
}
static void TestComplexDoWhile(void)
{
/* Set of test vectors for MC/DC */
ComplexDoWhile(-45, 1, 1, 0);
ComplexDoWhile(-46, 0, 0, 0);
ComplexDoWhile(-46, 0, 1, 0);
ComplexDoWhile(-46, 1, 0, 0);
ComplexDoWhile(-46, 0, 0, 1);
ComplexDoWhile(-46, 1, 1, 0);
}
static unsigned ComplexWhile(int const a, int const b, int const c, int const d)
{
unsigned num_cycles = 0u;
while ((!(a > -70) && !(Identity(b) == 39)) || !(c <= -13) || (Identity(d) < 39)) {
if (num_cycles > 1u) {
break;
}
num_cycles++;
}
return num_cycles;
}
static void TestComplexWhile(void)
{
/* Set of test vectors for MC/DC */
ComplexWhile(-69, 40, -13, 39);
ComplexWhile(-70, 39, -13, 39);
ComplexWhile(-70, 39, -12, 39);
ComplexWhile(-70, 39, -13, 38);
ComplexWhile(-70, 40, -13, 39);
}
static unsigned ComplexIf(int const a, int const b, int const c, int const d)
{
unsigned outcome = FALSE;
if (a && !(b > -100 || !(c > 42)) && Identity(d) < 36) {
outcome = TRUE;
}
else {
outcome = FALSE;
}
return outcome;
}
static void TestComplexIf(void)
{
/* Set of test vectors for MC/DC */
ComplexIf(0, -100, 42, 36);
ComplexIf(1, -99, 42, 36);
ComplexIf(1, -100, 42, 36);
ComplexIf(1, -100, 43, 36);
ComplexIf(1, -100, 43, 35);
}
static int SwitchCase(enum Color const color)
{
int offset = 0;
switch (color) {
case RED:
offset = 10;
break;
case BLUE:
offset = 8;
break;
case ORANGE:
offset = 6;
break;
case YELLOW:
case GREEN:
offset = 2;
break;
default:
offset = -1;
break;
}
return offset;
}
static void TestSwitchCase(int const tic)
{
/* Switch-case expression
*
* There are several options for compilers to model switch-case
* expressions. Representations containing jump or value tables are not
* suitable for a trace-based measurement of code coverage. It is possible
* for most compilers to suppress the creation of jump tables via compiler
* flags. The result is a binary search incorporating conditional branches
* that suitable for monitoring the status of each condition.
*/
if (tic) {
/* Set of test vectors for MC/DC */
SwitchCase(RED);
SwitchCase(BLUE);
SwitchCase(ORANGE);
SwitchCase(YELLOW);
SwitchCase(GREEN);
SwitchCase(3); /* Lower than expected input range */
SwitchCase(-3); /* Higher than expected input range */
}
else {
/* Expected input range */
SwitchCase(RED);
SwitchCase(BLUE);
SwitchCase(ORANGE);
SwitchCase(YELLOW);
SwitchCase(GREEN);
}
}
static unsigned MultiLine(struct Compound *compound)
{
if ( ( compound->a == TRUE
|| compound->b == TRUE
|| compound->c == TRUE)
&& ( compound->d == TRUE
|| compound->e == TRUE
|| compound->f == TRUE)) {
return TRUE;
}
return FALSE;
}
static void TestMultiline(void)
{
/* Multi-line multi-operator decision
*
* Each operator resides on a distinct line, so compilers may choose
* to create additional entries in the debug symbol information per
* line. However, even though this may improve debugging it also
* conceals the direct relationship of these lines. A semantic analysis
* is required to restore this relationship and reason about the decision
* as a whole.
*/
/* Set of test vectors for decision coverage */
struct Compound compound = {0};
compound.a = FALSE;
compound.b = FALSE;
compound.c = FALSE;
compound.d = TRUE;
compound.e = TRUE;
compound.f = TRUE;
if (MultiLine(&compound) == TRUE) {
return;
}
compound.b = TRUE;
MultiLine(&compound);
}
static unsigned NestedExprTrans(int a, int b, float c)
{
/* Equivalence transformation for decision with nested Boolean expression
*
* Equivalent expression after transformation. The nested Boolean
* expression is extracted and put into a branching context. Compilers
* typically choose to use conditional branches for modelling this type of
* structure.
*/
int tmp = 0;
if ((float) b < c) {
tmp = 1;
}
if (a > (b + tmp)) {
return TRUE;
}
return FALSE;
}
static unsigned NestedExpr(int a, int b, float c)
{
/* Decision with nested Boolean expression
*
* Expression showing a nested Boolean expression. Compilers may choose to
* model nested expressions with conditional or unconditional instructions
* instead of conditional branches that are not suitable for the trace-
* based measurement of code coverage.
*/
return (a > (b + ((float) b < c)));
}
static void TestExprNesting(void)
{
/* Decision with nested Boolean expression
*
* The decision contains a nested Boolean expression. Both decision and
* nested expression must be analyzed as two distinct decisions. Compilers
* may choose to model nested expressions with conditional or unconditional
* instructions instead of conditional branches that are not suitable for
* the trace-based measurement of code coverage. Transforming the
* expression into a branching context may force the use of conditional
* instructions.
*/
/* Set of test vectors for MC/DC */
NestedExpr(1, 1, 3.0f); /* top: T, nested: T */
NestedExpr(6, 4, 3.0f); /* top: F, nested: F */
/* Transformed expression */
NestedExprTrans(1, 1, 3.0f); /* top: T, nested: T */
NestedExprTrans(6, 4, 3.0f); /* top: F, nested: F */
}
static float TernaryExprTrans(float const a, float const b)
{
/* Equivalence transformation for ternary expression
*
* Equivalent expression after transformation. The decision appears in a
* branching context once more. Compilers typically choose to use
* conditional branches for modelling this type of expression.
*/
if (a >= b) {
return a;
}
else {
return b;
}
}
static float TernaryExpr(float const a, float const b)
{
/* Ternary expression as decision
*
* Expression showing a decision with ternary expression. Compilers may
* choose to model ternanry expressions with conditional or unconditional
* instructions instead of conditional branches that are not suitable for
* the trace-based measurement of code coverage.
*/
return (a >= b) ? a : b;
}
static void TestTernaryExpr(void)
{
/* Test for ternary expression as decision
*
* Compilers may choose to model ternanry expressions with conditional or
* unconditional instructions instead of conditional branches that are not
* suitable for the trace-based measurement of code coverage. Transforming
* the expression into a branching context may force the use of conditional
* instructions.
*/
/* Set of test vectors for both MC/DC and OBC */
TernaryExpr(0.0f, 0.0f);
TernaryExpr(0.0f, 1.0f);
/* Transformed expression */
TernaryExprTrans(0.0f, 0.0f);
TernaryExprTrans(0.0f, 1.0f);
}
static int SimpleIfFunctionCall(int const a)
{
/* If-then block controlled by nested function call
*
* The expression shows an expression in branching context. The outcome of
* the decision is controlled by the Boolean return value of a simple
* function.
*/
if (Identity(a)) {
return 1;
}
return 0;
}
static void TestSimpleIfFunctionCall(void)
{
/* Test for if-then construct with nested function call
*
* Tests whether the compiler uses conditional branches to model this
* simple expression type.
*/
SimpleIfFunctionCall(0);
SimpleIfFunctionCall(1);
}
static int BooleanAssignmentRelExprTrans(int const a, int const b)
{
/* Equivalence transformation for relational expression
*
* Equivalent expression after transformation. The decision appears in a
* branching context once more. Compilers typically choose to use
* conditional branches for modelling this type of expression.
*/
if (a == b) {
return TRUE;
}
return FALSE;
}
static int BooleanAssignmentRelExpr(int const a, int const b)
{
/* Relational expression as decision
*
* Expression showing a decision in non-branching context. Compilers may
* choose to model Boolean assignments with conditional or unconditional
* instructions instead of conditional branches that are not suitable for
* the trace-based measurement of code coverage.
*/
return a == b;
}
static void TestNoBranchCtxRelExpr(void)
{
/* Test for relational expression as decision
*
* Relational operators are no Boolean operators. Hence, the decision
* has a single condition.
* Compilers may choose to model Boolean assignments with conditional or
* unconditional instructions instead of conditional branches that are not
* suitable for the trace-based measurement of code coverage. Transforming
* the expression into a branching context may force the use of conditional
* instructions.
*/
/* Set of test vectors for both MC/DC and OBC */
BooleanAssignmentRelExpr(0, 0);
BooleanAssignmentRelExpr(0, 1);
/* Transformed expression */
BooleanAssignmentRelExprTrans(0, 0);
BooleanAssignmentRelExprTrans(0, 1);
}
static int BooleanAssignmentNotOp(int const a, int const b, int const c)
{
/* Decision in assignment
*
* Boolan expression that does not occur in branching context.
*
* Structure: Truth table: Test vectors for MC/DC:
*
* a----> F a b c | outcome a: 1. + 2.
* \ -------+--------- b: 2. + 3.
* b----> F 1. F x x | F c: 2. + 4.
* |\ 2. T F F | T
* | c----> F 3. T T x | F
* v | 4. T F T | F
* T v
* T
*/
return a && !(b || c);
}
static void TestNoBranchCtxNotOp(void)
{
/* Test for decision in assignment
*
* Boolan expression that does not occur in branching context.
*
* Decision: a && !(b || c)
*
* Structure: Truth table: Test vectors for MC/DC:
*
* a----> F a b c | outcome a: 1. + 2.
* \ -------+--------- b: 2. + 3.
* b----> F 1. F x x | F c: 2. + 4.
* |\ 2. T F F | T
* | c----> F 3. T T x | F
* v | 4. T F T | F
* T v
* T
*/
/* Set of test vectors for both MC/DC and OBC */
BooleanAssignmentNotOp(0, 1, 1); /* 1. */
BooleanAssignmentNotOp(1, 0, 0); /* 2. */
BooleanAssignmentNotOp(1, 1, 1); /* 3. */
BooleanAssignmentNotOp(1, 0, 1); /* 4. */
}
static int BooleanExprCoupledTerms(int const a, int const b)
{
/* Decision with strongly coupled terms
*
* Each condition that appears more than once is treated like
* a distinct condition. Masking of subexpressions is used to find
* independence pairs that are suitable even though more than one value
* is changing at the same time.
*
* Structure: Truth table: Test vectors for MC/DC:
*
* a---+ a b | outcome a(1): 1. + 2.
* \ | -----+--------- b(1): 2. + 4.
* b-+--> F 1. F F | F a(2): 3. + 4.
* |\v 2. T F | T b(2): 1. + 3.
* | a----> F 3. F T | T
* | \ 4. T T | F
* v b----> F
* T |
* v
* T
*/
unsigned outcome = FALSE;
if ((a && !b) || (!a && b)) {
outcome = TRUE;
}
else {
outcome = FALSE;
}
return outcome;
}
static void TestMaskingMcdc(void)
{
/* Test for decision with strongly coupled terms
*
* Each condition that appears more than once is treated like
* a distinct condition. Masking of subexpressions is used to find
* independence pairs that are suitable even though more than one value
* is changing at the same time.
*
* Decision: (a && !b) || (!a && b)
*
* Structure: Truth table: Test vectors for MC/DC:
*
* a---+ a b | outcome a(1): 1. + 2.
* \ | -----+--------- b(1): 2. + 4.
* b-+--> F 1. F F | F a(2): 3. + 4.
* |\v 2. T F | T b(2): 1. + 3.
* | a----> F 3. F T | T
* | \ 4. T T | F
* v b----> F
* T |
* v
* T
*/
/* Set of test vectors for MC/DC */
BooleanExprCoupledTerms(0, 0); /* 1. */
BooleanExprCoupledTerms(1, 0); /* 2. */
BooleanExprCoupledTerms(0, 1); /* 3. */
BooleanExprCoupledTerms(1, 1); /* 4. */
}
static unsigned BooleanExprMixedOps(int const a, int const b, int const c)
{
/* Deviation of MC/DC and OBC
*
* The structure of the decision results in the deviation of MC/DC and
* Object Code Branch Coverage. Full coverage of all conditional branches
* at the object code level alone is not sufficient to achieve MC/DC.
*
* Structure: Truth table: Test vectors for MC/DC:
*
* a----+ a b c | outcome a: 1. + 5.
* | | -------+--------- b: 3. + 5.
* v | 1. T x T | T c: 1. + 2.
* b | 2. T x F | F
* |\ v 3. F T T | T Test vectors for OBC:
* | +->c---->T 4. F T F | F 2. + 3. + 5.
* | | 5. F F x | F
* v v
* F F
*/
unsigned outcome = FALSE;
if ((a || b) && c) {
outcome = TRUE;
}
else {
outcome = FALSE;
}
return outcome;
}
static void TestObcDiffersMcdc(int const tic)
{
/* Test for deviation of MC/DC and OBC
*
* The structure of the decision results in the deviation of MC/DC and
* Object Code Branch Coverage. Full coverage of all conditional branches
* at the object code level alone is not sufficient to achieve MC/DC.
*
* Decision: (a || b) && c
*
* Structure: Truth table: Test vectors for MC/DC:
*
* a----+ a b c | outcome a: 1. + 5.
* | | -------+--------- b: 3. + 5.
* v | 1. T x T | T c: 1. + 2.
* b | 2. T x F | F
* |\ v 3. F T T | T Test vectors for OBC:
* | +->c---->T 4. F T F | F 2. + 3. + 5.
* | | 5. F F x | F
* v v
* F F
*/
if (tic) {
/* Set of test vectors for MC/DC */
BooleanExprMixedOps(1, 0, 1); /* 1. */
BooleanExprMixedOps(1, 0, 0); /* 2. */
BooleanExprMixedOps(0, 1, 1); /* 3. */
BooleanExprMixedOps(0, 0, 0); /* 5. */
}
else {
/* Set of test vectors for OBC */
BooleanExprMixedOps(1, 0, 0); /* 2. */
BooleanExprMixedOps(0, 1, 1); /* 3. */
BooleanExprMixedOps(0, 0, 0); /* 5. */
}
}
static unsigned BooleanExprSameOps(int const a, int const b, int const c)
{
/* Equivalence of MC/DC and OBC
*
* The structure of the decision results in the equivalence of MC/DC
* and Object Code Branch Coverage. Full coverage of all conditional
* branches at the object code level is sufficient to achieve MC/DC.
*
* Structure: Truth table: Test vectors for MC/DC:
*
* a----> T a b c | outcome a: 1. + 4.
* \ -------+--------- b: 2. + 4.
* b----> T 1. T x x | T c: 3. + 4.
* \ 2. F T x | T
* c----> T 3. F F T | T
* | 4. F F F | F
* v
* F
*/
unsigned outcome = FALSE;
if (a || b || c) {
outcome = TRUE;
}
else {
outcome = FALSE;
}
return outcome;
}
static void TestObcEqualsMcdc(void)
{
/* Test for equivalence of MC/DC and OBC
*
* The structure of the decision results in the equivalence of MC/DC
* and Object Code Branch Coverage. Full coverage of all conditional
* branches at the object code level is sufficient to achieve MC/DC.
*
* Decision: a || b || c
*
* Structure: Truth table: Test vectors for MC/DC:
*
* a----> T a b c | outcome a: 1. + 4.
* \ -------+--------- b: 2. + 4.
* b----> T 1. T x x | T c: 3. + 4.
* \ 2. F T x | T
* c----> T 3. F F T | T
* | 4. F F F | F
* v
* F
*/
/* Set of test vectors for both MC/DC and OBC */
BooleanExprSameOps(1, 0, 0); /* 1. */
BooleanExprSameOps(0, 1, 0); /* 2. */
BooleanExprSameOps(0, 0, 1); /* 3. */
BooleanExprSameOps(0, 0, 0); /* 4. */
}
void RunCoverageDemo(void)
{
static unsigned tic = 1u;
while (TRUE) {
tic = !tic;
TestObcEqualsMcdc();
TestObcDiffersMcdc(tic);
TestMaskingMcdc();
TestNoBranchCtxNotOp();
TestNoBranchCtxRelExpr();
TestSimpleIfFunctionCall();
TestTernaryExpr();
TestExprNesting();
TestMultiline();
TestSwitchCase(tic);
TestComplexIf();
TestComplexFor();
TestComplexWhile();
TestComplexDoWhile();
TestComplexBooleanParameter();
TestFunctionLikeMacro();
}
}