/* AVG: return the average of n integers */ /* 1. FLOWGRAPH: artificial enter . . . . . . . . . 1 . R1 . R2 | . v . . 4 <-------- 2 <-----+ . | F | . +---+---+ T | | . |F T| v | . v v R3 | . 3 | . 6 R4 5 | . | | . | | +-------+ . +-> 7 <-+ . exit . . . . 2. CYCLOMETRIC COMPLEXITY: Predicates (2) + 1 = Edges (9) - Nodes (7) + 1 = Regions (4) - 1 = 3 3. BASIS SET OF CYCLES: 1. 1-2-4-5-7-1 2. 1-2-4-6-7-1 3. 2-3-2 Note this third CYCLE: 2-3-2. This does not look like a PATH. It starts at node 2 (while), goes around the loop, and returns to the top of the loop. This is NOT a CYCLE: 1-2-3-2-4-5-7-1 ^ ^ This starts at node 1 and returns to node 1, but in the midst, it visits node 2 twice. This violates the definition of a CYCLE: must not visit a node more than once (other than the start/stop point). So any time code has a loop, that will form a CYCLE itself - no matter how far down it is nested in the code. PATHS will always start at the top of the function, and end at the bottom of the function. CYCLES do one of two things: 1. start at top, bounce off loop(s), flow to bottom, return via artificial edge OR 2. start at a loop, go around the loop, return to the top of the loop PATHS do one of two things: 1. start at top, bounce off loop(s), flow to bottom OR 2. start at the top, hit a loop, go around the loop, exit the loop, and flow to the bottom (If there is a loop farther down, a PATH could either bounce or go around. That helps to make more INDEPENDENT PATHS.) LINEARLY INDEPENDENT PATHS: 1. 1-2-4-5-7 // bounce off while loop (because n=0; no data to read) 2. 1-2-3-2-4-6-7 // go around loop once (n=1; compute average) 3. 1-2-3-2-4-5-7 INFEASIBLE // go around loop once but then n can't be 0 Note 1: There are only two FEASIBLE paths because if the loop is taken, then n must be greater than 0. After the loop, there is no way that the IF statement can be TRUE. If it goes around the loop, then the IF will always be FALSE. If it does not go around the loop, then the IF will always be TRUE. By graph theory, we can list CC=3 independent paths, but we cannot find an actual test case for this last one. Note 2: This white box strategy does not do 100% path coverage, but we can't do anything about that - it's just the nature of the logic of the program. There IS another path: 1-2-4-6-7 which bounces off the loop because n=0 and then tries to go FALSE on the IF. But this is INFEASIBLE too. Also, NEVER list 4 paths as INDEPENDENT when CC=3. Note 3: Now this leads to another problem. What if there are 4 paths, as above. We can only label 3 of them INDEPENDENT, but we can choose any of the 3. (Remember Ex3.3 where there were 4 paths, and any 3 of them independent?). Always try to pick the FEASIBLE ones. In the above example, 2 were FEASIBLE and 2 were INFEASIBLE, so there's no way to find 3 FEASIBLE. But certainly do NOT pick 1 FEASBILE and 2 INFEASIBLE. There will be cases where CC=3, say, and we might have 3 FEASIBLE and 1 INFEASIBLE. Pick the 3 FEASIBLE ones because we're trying to actually do some testing. Note 4: Make sure you understand this: there will always be CC number of INDEPENDENT paths according to graph theory. But to force to program along a certain path requires actual test cases. And going a certain direction at the beginning of the path may make it INFEASIBLE later on in the path. Remember, if you can touch a NEW edge, you have an INDEPENDENT path. Here's how to fill-out the correct table: 4. LINEARLY INDEPENDENT PATHS 5. FEASABLE (YES/NO) 6. TEST CASES 7. RESULT (n,a) (max) 1. 1-2-4-5-7 YES 0 999 2. 1-2-3-2-4-6-7 YES 1 1 1 3. 1-2-3-2-4-5-7 NO See avg.bat */ #include #define INF 999 int debug = 0; /* instrumentation for the line #'s*/ int L(int i) { if (debug) printf("%d-",i); return 1; } float avg(int n) { int sum, i, a; float avg; L(1); i = 1; sum = 0; while (L(2)&&(i<=n)) { L(3); scanf("%d",&a); sum += a; i++; } if (L(4)&&(n==0)) { L(5); avg = INF; } else { L(6); avg = sum/n; } L(7); if (debug) printf("\nActual : avg=%.1f\n",avg); return avg; } int main(int argc, char *argv[]) { int n; if (argc > 1) { debug = 1; printf("Path : "); } scanf("%d",&n); printf("avg :%.1f\n",avg(n)); }