White-Box Testing Part I
Definition of White-Box Testing
- Testing based on analysis of internal logic (design, code, etc.)
- Expected results still come from requirements (not internal logic)
- Also known as structural testing
- White-box testing concerns techniques for designing tests — it is not a level of testing
- Applies primarily to lower levels of testing (e.g., unit and component)
Analogy: เหมือนการตรวจสอบเครื่องยนต์รถโดยเปิดฝากระโปรงดูข้างใน (white-box) แทนที่จะแค่ลองขับดูว่าวิ่งได้ไหม (black-box)
White-Box Testing Techniques
- Logic coverage
- Data-flow coverage
- Path conditions and symbolic evaluation
- Other white-box testing strategies (e.g., "fault-based testing")
Types of Logic Coverage
| Coverage Type | Description |
|---|---|
| Statement | Each statement executed at least once |
| Branch | Each branch traversed (and every entry point taken) at least once |
| Condition | Each condition True ≥ once AND False ≥ once |
| Branch/Condition | Both Branch AND Condition coverage achieved |
| Compound Condition | All combinations of condition values at every branch statement covered |
| Path | All program paths traversed at least once |
Pseudo-Code and Control Flow Graphs
- A Control Flow Graph (CFG) represents a program as nodes and edges
- Nodes = statements or conditions
- Edges = control flow between statements (branches)
Example Program:

1. input(Y)
2. if (Y <= 0)
3. then Y := -Y
4. end_if
5. while (Y > 0) do
6. input(X)
7. Y := Y - 1
8. end_while
Analogy: CFG คือแผนที่ของโปรแกรม — node คือจุดแวะพัก, edge คือถนนที่เชื่อมระหว่างจุด
Statement Coverage
- Requires that each statement will have been executed at least once
- Simplest form of logic coverage
- Also known as Node Coverage
Analogy: คล้ายการเดินสำรวจบ้าน โดยต้องเหยียบเข้าไปทุกห้องอย่างน้อยหนึ่งครั้ง
For the example program above:
-
น่าจะ 2 นะ!
-
1 test case with
Y = -1is enough:- Executes
input(Y)→if (Y<=0)→Y := -Y→while (Y>0)→input(X)→Y := Y-1
- Executes
Branch Coverage
- Requires that each branch will have been traversed, and every program entry point taken, at least once
- Also known as Edge Coverage

Analogy: ต้องขับรถผ่านทุกสาขาของถนน ทั้งทางซ้ายและทางขวาที่ทางแยก — ไม่พอแค่ผ่านจุดหนึ่งจุดใด
Relationship Between Statement and Branch Coverage
- Does Statement ⇒ Branch? NO
- You can cover all statements with 1 test but miss a branch
- Does Branch ⇒ Statement? YES (normally)
- If you traverse every branch, you pass through every statement
- Exception: "Dead Code" — code not reachable via any executable path
Dead Code: โค้ดที่ไม่มีทางเดินถึงได้เลย ไม่ว่า input จะเป็นอะไร เช่น
if (false) { ... }

Condition Coverage
- A branch predicate may have more than one condition
Example:
input(X, Y)
if (Y <= 0) or (X = 0) then
Y := -Y
end_if
while (Y > 0) and (not EOF) do
input(X)
Y := Y - 1
end_while
- Condition Coverage requires each individual condition to be
Trueat least once andFalseat least once - Normally, achieving condition coverage also achieves branch coverage
Condition Table Example (if A or B):
| Test | A | B | Branch Taken |
|---|---|---|---|
| test 1 | T | F | true |
| test 2 | F | T | true |
| test 3 | T | T | true |
| test 4 | F | F | false |
Analogy: Branch coverage ถามว่า "ประตูนี้เคยเปิดและปิดไหม?" แต่ Condition coverage ถามว่า "สวิตช์แต่ละตัวที่ควบคุมประตูนี้เคยอยู่ในทุกสถานะไหม?"
Branch/Condition Coverage
- Requires that both Branch AND Condition Coverage are achieved
- Subsumes both Branch Coverage and Condition Coverage
Compound Condition Coverage
- Problem: Some compilers use short-circuit evaluation
- e.g.,
if (A) or (y/x = 5)— ifAis true,y/x = 5is never evaluated
- e.g.,
- Compound Condition Coverage (also: Multiple Condition Coverage) requires:
- All combinations of condition values at every branch statement covered
- Every entry point taken at least once
- Subsumes Branch/Condition Coverage regardless of evaluation order
Example combinations for if (Y <= 0) or (X = 0):
Y <= 0 | X = 0 |
|---|---|
| T | T |
| T | F |
| F | T |
| F | F |
Analogy: Compound condition เหมือนการทดสอบรีโมทคอนโทรลทุกปุ่มในทุกๆ combination — ไม่ใช่แค่กดแต่ละปุ่มแยกกัน
Path Coverage
- Requires that all program paths will have been traversed at least once
- All Path Coverage may be impractical when loops are present
Why loops are a problem:
- A
forloop that repeats 30 times with 3 paths per iteration = paths
Analogy: เหมือนการเดินทางที่มีทางแยก 30 ครั้ง แต่ละครั้งมี 3 เส้นทาง — การเดินให้ครบทุก combination เป็นไปไม่ได้จริงๆ


Strategies when full Path Coverage is impractical:
- Loop Coverage
- Basis Paths Coverage
- Data-flow Coverage
Loop Coverage
- Requires that the body of loops be executed 0, 1, 2, t, max, and max+1 times (where possible)
| Iterations | Rationale |
|---|---|
| 0 | Is some action needed in the body also needed when body is skipped? |
| 1 | Check lower bound on execution |
| 2 | Check loop re-initialisation |
| t | Check typical number of iterations |
| max | Check upper (valid) bound |
| max+1 | What behavior results if maximum is exceeded? |
Analogy: เหมือนทดสอบลิฟต์ — ดูว่าทำงานถูกเมื่อกด 0 ครั้ง, 1 ครั้ง, ครั้งทั่วไป, ครั้งสูงสุด, และเกินกว่าที่รองรับ
Basis Paths Coverage
- A white-box technique for designing test cases to examine all possible paths at least once
- Achieves 100% statement coverage and 100% branch coverage
- Uses McCabe's Cyclomatic Complexity to determine the number of linearly independent paths
- Then generates test cases for each independent path
Note: In a simple program path:
whileloop bodies are executed at most oncerepeat-untilloop bodies are executed at most twice
Cyclomatic Complexity
- A software metric indicating the complexity of a program
- Measures the number of linearly independent paths through source code
- Developed by Thomas J. McCabe, Sr. in 1976
Three ways to compute :
Where = number of predicate nodes (decision nodes)
Where:
- = number of edges
- = number of nodes
Analogy: Cyclomatic Complexity คือการนับว่าโปรแกรมนี้มี "ทางแยก" กี่จุด — ยิ่งมาก ยิ่งซับซ้อน ยิ่งต้องการ test case มากขึ้น
Example (from lecture):

| Metric | Value |
|---|---|
| Number of Nodes () | 8 |
| Number of Edges () | 10 |
| Number of Predicate Nodes () | 3 |
| Number of Regions () | 4 |
Basis Paths (4 paths):
- Path 1:
1-2-4-7-8 - Path 2:
1-2-3-5-7-8 - Path 3:
1-2-3-6-7-8 - Path 4:
1-2-4-7-2-4-...-7-8(loop)
Exercise: Cyclomatic Complexity
ดูให้เป็น เหมือนจะไม่ยากเลยนะ นับให้ได้มีกี่ path (path = condition node + 1 มั้ง), นับ region ให้ได้ สุดได้เดี๋ยวได้คำตอบเอง

N = 7
E = 8
P = 2
R = 3
P + 1 = 3
E - N + 2 = 3
R = 3
IF A = 10 THEN
IF B > C THEN
A = B
ELSE
A = C
ENDIF
ENDIF
Print A
Print B
Print C
Cyclomatic complexity is ________
Hint: Count predicate nodes →
A=10andB>C→ →
Summary of White-Box Coverage Relationships
Compound Condition Path
| / \
↓ ↓ ↓
Branch/Condition Basis Loop
/ \ Paths
↓ ↓ ↓
Condition Branch ←←←
↓
Statement
Subsumption chain (strongest → weakest):
Analogy: เหมือน coverage ที่สูงกว่า "ครอบคลุม" coverage ที่ต่ำกว่าเสมอ — ถ้าทำ Compound Condition ได้ แปลว่าทำ Branch ได้ด้วยโดยอัตโนมัติ
Swift Code Example & Swift Testing
สมมติว่ามีฟังก์ชัน Swift ที่สอดคล้องกับ pseudo-code ในบทเรียน:
func processValue(y: Int, x: Int) -> Int {
var result = y
// if (Y <= 0) then Y := -Y
if result <= 0 {
result = -result
}
// while (Y > 0) do Y := Y - 1
var count = 0
while result > 0 {
_ = x // input(X) simulation
result -= 1
count += 1
}
return count
}Swift Testing — Coverage Examples
import Testing
@Suite("processValue Tests — White-Box Coverage")
struct ProcessValueTests {
// MARK: - Statement Coverage (1 test covers all statements)
@Test("Statement Coverage — Y negative triggers negation and enters loop")
func statementCoverage() {
// Y = -2 → becomes 2 → loop runs 2 times
let result = processValue(y: -2, x: 1)
#expect(result == 2)
}
// MARK: - Branch Coverage (covers both branches of if)
@Test("Branch Coverage — Y positive (skip if-branch)")
func branchCoverageSkipIf() {
// Y = 3 → if-branch NOT taken → loop runs 3 times
let result = processValue(y: 3, x: 0)
#expect(result == 3)
}
@Test("Branch Coverage — Y zero (take if-branch, skip loop)")
func branchCoverageTakeIf() {
// Y = 0 → if-branch taken → Y = 0 → loop NOT entered
let result = processValue(y: 0, x: 0)
#expect(result == 0)
}
// MARK: - Loop Coverage
@Test("Loop Coverage — 0 iterations")
func loopZeroIterations() {
// Y = 0 → after if: still 0 → loop body never runs
let result = processValue(y: 0, x: 0)
#expect(result == 0)
}
@Test("Loop Coverage — 1 iteration")
func loopOneIteration() {
let result = processValue(y: 1, x: 0)
#expect(result == 1)
}
@Test("Loop Coverage — typical (t) iterations")
func loopTypicalIterations() {
let result = processValue(y: 5, x: 0)
#expect(result == 5)
}
}Note: In real white-box testing, you'd also compute Cyclomatic Complexity of
processValue:
- 2 predicate nodes (
if result <= 0andwhile result > 0)- So 3 independent test paths are needed for Basis Paths coverage
White-Box Testing Part II
White-Box Testing Topics (Overview)
- Logic coverage ← covered in Part I
- Data-flow coverage ← this lecture
- Path conditions and symbolic execution ← Part III
- Other white-box testing strategies (e.g., fault-based testing)
Data-flow Coverage
- Basic idea: Program paths along which variables are defined and then used should be covered
- A family of path selection criteria has been defined, each providing a different degree of coverage
- CASE tool support is very desirable (hard to do manually at scale)
Analogy: เหมือนการติดตามเงิน — ถ้าเราสร้างเงิน (define) แล้วต้องมั่นใจว่ามีเส้นทางที่เงินนั้นถูกใช้ (use) จริงๆ และไม่ถูกแทนที่ระหว่างทาง
Variable Definition (DEF)
A program variable is DEFINED when:
- It appears on the left-hand side of an assignment statement
- e.g.,
x = 17,x = y + 1
- e.g.,
- It is used in an input statement
- e.g.,
read(x),input(x)
- e.g.,
- It is used as a call-by-reference parameter in a subroutine call
- e.g.,
update(&x, y)
- e.g.,
Analogy: DEF คือการ "เกิดของค่า" — ตอนที่ตัวแปรได้รับค่าใหม่เข้ามา เหมือนการเติมน้ำลงในถัง
Variable Use (USE)
A program variable is USED when:
- It appears on the right-hand side of an assignment statement
- e.g.,
y = x + 17
- e.g.,
- It is used as a call-by-value parameter in a subroutine or function call
- e.g.,
y = sqrt(x),update(x, y)
- e.g.,
- It is used in a predicate of a branch statement
- e.g.,
if (x > 0) { ... }
- e.g.,
Analogy: USE คือการ "ดึงน้ำออกจากถัง" มาใช้งาน
Variable Use: p-use and c-use
- p-use (predicate-use): use in a branch predicate/condition
- c-use (computation-use): any other use (assignment RHS, function call parameter, output)
Example:
if ( x > 0 ) {
print(y);
}
x→ p-use (used in theifcondition)y→ c-use (used inprint, a computation context)
Analogy:
- p-use คือการใช้ตัวแปรเพื่อ "ตัดสินใจ" ว่าจะเดินทางไปทิศไหน (branch)
- c-use คือการใช้ตัวแปรเพื่อ "คำนวณ" ค่าอื่นต่อ
Variable Use and Re-definition
A variable can be used AND re-defined in a single statement when:
- It appears on both sides of an assignment:
- e.g.,
y = y + x→yis both used (RHS) and re-defined (LHS)
- e.g.,
- It is used as a call-by-reference parameter:
- e.g.,
increment(&y)→yis read and potentially overwritten
- e.g.,
More Data-flow Terms and Definitions
Def-Clear Path
- A path is definition clear ("def-clear") with respect to variable if it has no re-definition of along the path
- In other words: the value defined at the start of the path reaches the end without being overwritten
Complete Path
- A complete path is a path whose:
- Initial node = start node of the program
- Final node = exit node of the program
Example (from CFG with read(x,v); if(x>0) ...):
- Path is def-clear for
v(no redefinition ofvon ) - Path is NOT def-clear for
v(v is redefined along ) - Paths , are not complete (don't span start→exit)
- Path is complete

Analogy: Def-clear path คือเส้นทางที่ "ไม่มีใครเปลี่ยนมือ" ตลอดทาง — เงินก้อนที่ถูก define ยังเป็นเงินก้อนเดิมเมื่อถึงปลายทาง
Definition-Use Pair (DU-Pair)
More precisely:
- = node where is defined
- = node or edge where is used
- There exists a def-clear path with respect to from to
⚠️ Important: The definition of a DU-pair does NOT require the existence of a feasible def-clear path from to — the path just has to structurally exist in the CFG (it might be infeasible to actually execute)

Infeasible DU-Pairs
- Some DU-pairs may be structurally valid (def-clear path exists in CFG) but infeasible in practice (no input can actually cause execution to follow that path)
- These are marked as infeasible! in analysis
Analogy: เหมือนแผนที่บอกว่ามีถนนเชื่อมสองเมือง แต่จริงๆ ถนนนั้นถูกปิดกั้นด้วยหินถล่ม — structurally มันมี แต่ใช้ไม่ได้จริง

du-pair ให้ iterate เริ่มทุก d node (define) อย่างข้างบนเป็น 1, แล้วไป 5 ไง
แต่ต้องทำสำหรับ Variable ใดซักอันนึงเท่านั้นด้วยนะ เท่าที่โจทย์จะสั่ง
พอมีตารางแบบนี้แล้ว เราก็สามารถมี test case ทั้งหมดที่จะเป็นไปได้แล้ว
Example 1 — Program for DU-Pair Analysis
1. input(A, B)
if (B > 1) {
2. A = A + 7
}
3. if (A > 10) {
4. B = A + B
}
5. output(A, B)
Control Flow Graph:
- Node 1:
input(A, B)→ branches: B>1 (→ node 2), B≤1 (→ node 3) - Node 2:
A := A+7→ node 3 - Node 3:
if (A>10)→ branches: A>10 (→ node 4), A≤10 (→ node 5) - Node 4:
B := A+B→ node 5 - Node 5:
output(A, B)→ exit

Identifying DU-Pairs — Variable A
For variable A, definitions occur at:
- Node 1 (
input(A,B)— A is defined by input) - Node 2 (
A := A+7— A is re-defined)
Uses of A occur at:
- Node 2 (
A := A+7— A used on RHS → c-use) - Node 3 (
if A>10— A used in predicate → p-use) - Node 4 (
B := A+B— A used on RHS → c-use) - Node 5 (
output(A,B)— A used in output → c-use)
Complete DU-Pair Table for Variable A:
| DU-Pair | Path(s) |
|---|---|
| (1, 2) | <1,2> |
| (1, 4) | <1,3,4> |
| (1, 5) | <1,3,4,5> and <1,3,5> |
(1, <3,4>) | <1,3,4> |
(1, <3,5>) | <1,3,5> |
| (2, 4) | <2,3,4> |
| (2, 5) | <2,3,4,5> and <2,3,5> |
(2, <3,4>) | <2,3,4> |
(2, <3,5>) | <2,3,5> |
Note: Pairs with angle brackets like
(1, <3,4>)represent p-use pairs where the "use" is an edge (the branch from node 3 to node 4), not a node. Regular pairs like(1, 4)represent c-use pairs where the use is at a node.
![DU-Pair identification slides with highlighted paths for each du-pair on the CFG]
Dataflow Test Coverage Criteria
All-Defs Coverage
- Every definition of every variable must reach at least one use
- Weakest dataflow criterion
Analogy: ตรวจสอบว่าทุกแหล่งผลิต (def) มีเส้นทางส่งออกไปให้ผู้ใช้ (use) อย่างน้อยหนึ่งคน — ไม่ต้องครบทุกคน
All-Uses Coverage
- Every definition of every variable must reach every use (c-use and p-use)
- Stronger than All-Defs
Analogy: All-Defs คือ "ตรวจสอบว่าโรงงานทุกแห่งส่งสินค้าออกได้บ้าง" แต่ All-Uses คือ "ตรวจสอบว่าทุกโรงงานส่งสินค้าถึงลูกค้าทุกคน"
Checking All-Defs: Test Case <1,2,3,4,5>
For path <1,2,3,4,5>, the def-clear paths subsumed (covered) for variable A are:
| DU-Pair | Path Subsumed? |
|---|---|
| (1, 2) | <1,2> ✓ |
| (1, 4) | <1,3,4> ✗ (path goes 1→2→3, not 1→3) |
| (1, 5) | <1,3,4,5> ✗ |
(1, <3,4>) | ✗ |
(1, <3,5>) | ✗ |
| (2, 4) | <2,3,4> ✓ |
| (2, 5) | <2,3,4,5> ✓ |
(2, <3,4>) | <2,3,4> ✓ |
(2, <3,5>) | ✗ |
- Definition at node 1 → covered by
(1,2)✓ - Definition at node 2 → covered by
(2,4),(2,5)✓ - All-Defs is achieved by
<1,2,3,4,5>alone ✓
Checking All-Uses: Test Cases <1,2,3,4,5>, <1,3,4,5>, <1,2,3,5>
Adding paths <1,3,4,5> and <1,2,3,5>:
After all three test cases, the DU-pair (1, <3,5>) via path <1,3,5> is still NOT covered
<1,2,3,4,5>: doesn't take the B≤1 branch directly to node 3 with A≤10 to node 5<1,3,4,5>: covers(1,<3,4>)✓ but not(1,<3,5>)<1,2,3,5>: covers(2,<3,5>)✓ but not(1,<3,5>)
⚠️ Conclusion: Based on three test cases, All-Defs is achieved, but All-Uses Coverage is NOT achieved because DU-pair
(1, <3,5>)for variable A is never covered!
To cover (1, <3,5>), we need a test case executing path <1,3,5> — i.e., B ≤ 1 (skip node 2, so A is NOT redefined) AND A ≤ 10(skip node 4, go straight to output).
All-du-paths Coverage
- Strongest dataflow criterion
- Subsumes All-Uses
Complete White-Box Coverage Subsumption Relationships
Path
/ \
↓ ↓
Compound All-du-paths Loop
Condition ↓
↓ All-Uses
Branch/ / ↓
Condition ↓ All-Defs
/ \ ↓
↓ Basis Paths
Condition ↓
Branch
↓
Statement
Full hierarchy (strongest → weakest):
![White-Box Coverage Subsumption Relationships diagram]
Analogy: ลองนึกภาพ hierarchy นี้เหมือนระดับความละเอียดของการตรวจร่างกาย — Statement coverage แค่ตรวจว่าทุกอวัยวะยังอยู่ครบ, Branch ตรวจว่าแต่ละอวัยวะทำงานได้, All-Uses ตรวจว่าการส่งสัญญาณระหว่างอวัยวะทำงานถูกต้อง, Path ตรวจทุก scenario ที่เป็นไปได้ทั้งหมด
Exercises
Exercise 1: Identifying DU-Pairs — Variable B
Using the same program and CFG from Example 1:
1. input(A, B)
if (B > 1) {
2. A = A + 7
}
3. if (A > 10) {
4. B = A + B
}
5. output(A, B)
Task: Fill in the DU-Pairs table for variable B
| DU-Pairs | Path |
|---|---|
Hint for solving:
- Where is B defined? → Node 1 (
input(A,B)) and Node 4 (B := A+B)- Where is B used?
- Node 1 predicate:
B > 1→ p-use- Node 4:
B := A+B→ c-use (B on RHS)- Node 5:
output(A,B)→ c-use- Now trace def-clear paths for each (def, use) pair
Exercise 2: Checking Coverage for Variable B
Given these three test cases:
<1,2,3,4,5><1,3,4,5><1,2,3,5>
Question 2.1: Check whether all these paths are def-clear paths for variable B.
Question 2.2: Check whether All-Defs and All-Uses coverages are achieved.
Question 2.3: If the three paths cannot cover All-Defs or All-Uses, identify additional test cases needed.
Hint for solving:
- Definition at node 4 (
B := A+B): after node 4, B is redefined → any path continuing from node 4 to node 5 that uses B is a def-clear path from def@4- Check if there's any use of B that is never reached by a def-clear path from any definition
Swift Code Example & Swift Testing
Swift equivalent of Example 1's program:
func processAB(a: Int, b: Int) -> (Int, Int) {
var a = a
var b = b
// Node 1: input(A, B) — handled by parameters
// Branch: B > 1
if b > 1 {
// Node 2: A = A + 7 [DEF of A, USE of A (c-use)]
a = a + 7
}
// Node 3: if (A > 10) [USE of A (p-use)]
if a > 10 {
// Node 4: B = A + B [DEF of B, USE of A (c-use), USE of B (c-use)]
b = a + b
}
// Node 5: output(A, B) [USE of A (c-use), USE of B (c-use)]
return (a, b)
}Variable Analysis Summary:
// DEF of A: parameter 'a' (node 1), 'a = a + 7' (node 2)
// USE of A: 'a + 7' RHS (node 2, c-use), 'a > 10' predicate (node 3, p-use),
// 'a + b' RHS (node 4, c-use), 'return (a, b)' (node 5, c-use)
// DEF of B: parameter 'b' (node 1), 'b = a + b' (node 4)
// USE of B: 'b > 1' predicate (node 1, p-use), 'a + b' RHS (node 4, c-use),
// 'return (a, b)' (node 5, c-use)Swift Testing — Dataflow Coverage
import Testing
@Suite("processAB — Data-flow Coverage Tests")
struct DataflowTests {
// MARK: - Path <1,2,3,4,5>: b>1 (take node 2) AND a>10 (take node 4)
// Covers DU-pairs: (1,2), (2,4), (2,5), (2,<3,4>) for A
@Test("Path 1-2-3-4-5: B>1 and A>10 after increment")
func path_1_2_3_4_5() {
// a=5, b=2 → b>1 so a becomes 12 → a>10 so b = 12+2 = 14
let (a, b) = processAB(a: 5, b: 2)
#expect(a == 12)
#expect(b == 14)
}
// MARK: - Path <1,3,4,5>: b≤1 (skip node 2) AND a>10
// Covers DU-pair: (1,4), (1,<3,4>) for A
@Test("Path 1-3-4-5: B≤1 and A>10 already")
func path_1_3_4_5() {
// a=11, b=1 → b≤1 skip node2 → a still 11 > 10 → b = 11+1 = 12
let (a, b) = processAB(a: 11, b: 1)
#expect(a == 11)
#expect(b == 12)
}
// MARK: - Path <1,2,3,5>: b>1 AND a≤10 after increment
// Covers DU-pair: (2,5), (2,<3,5>) for A
@Test("Path 1-2-3-5: B>1 but A≤10 after increment")
func path_1_2_3_5() {
// a=1, b=5 → b>1 so a = 1+7 = 8 → a≤10 skip node4 → output(8, 5)
let (a, b) = processAB(a: 1, b: 5)
#expect(a == 8)
#expect(b == 5)
}
// MARK: - Path <1,3,5>: b≤1 AND a≤10
// Covers DU-pair: (1,<3,5>) for A — NEEDED for All-Uses!
@Test("Path 1-3-5: B≤1 and A≤10 — covers missing du-pair (1,<3,5>)")
func path_1_3_5() {
// a=5, b=0 → b≤1 skip node2 → a=5 ≤10 skip node4 → output(5, 0)
let (a, b) = processAB(a: 5, b: 0)
#expect(a == 5)
#expect(b == 0)
}
}Note: The 4th test case (
path_1_3_5) is exactly the missing test case needed to achieve All-Uses coverage for variable A! Without it, DU-pair(1, <3,5>)is never covered.