|
21 | 21 | * <p>A class's depth is the length of the longest acyclic ancestor path that |
22 | 22 | * terminates at a sealed root ({@code isSealed() == true} with no ancestors, |
23 | 23 | * depth 1) <em>within the analyzed batch</em>. A class with no such path — |
24 | | - * cycle members, classes whose only ancestor paths enter a cycle, or classes |
25 | | - * whose chain dead-ends at a non-sealed class in the batch — has depth 0: it |
26 | | - * is not a member of any observable sealed hierarchy. External ancestors (not |
27 | | - * present in the batch) preserve the pre-existing minimum depth of 2 as a |
28 | | - * relationship signal. When both cyclic and valid paths exist, the valid |
29 | | - * path's depth wins. |
| 24 | + * including a cycle member whose ancestor paths do not reach a sealed root, |
| 25 | + * a class whose only ancestor paths enter a cycle, or a class whose chain |
| 26 | + * dead-ends at a non-sealed class in the batch — has depth 0: it is not a |
| 27 | + * member of any observable sealed hierarchy. External ancestors (not present |
| 28 | + * in the batch) preserve the pre-existing minimum depth of 2 as a relationship |
| 29 | + * signal. When both cyclic and valid paths exist, the valid path's depth wins. |
30 | 30 | */ |
31 | 31 | class GraphMetricsCollectorSealedDepthTest { |
32 | 32 |
|
@@ -145,6 +145,24 @@ void mixedCyclicAndValidPaths_validPathWins() { |
145 | 145 | assertEquals(1, root.getSealedHierarchyDepth()); |
146 | 146 | } |
147 | 147 |
|
| 148 | + @DisplayName("a cycle member with a sealed-root path receives its valid depth") |
| 149 | + @Test |
| 150 | + void cycleMemberWithSealedRootPath_hasValidDepth() { |
| 151 | + GraphMetricsCollector collector = newCollector(); |
| 152 | + ClassMetrics root = collector.getOrCreateClassMetrics("com.example.Shape"); |
| 153 | + root.setSealed(true); |
| 154 | + ClassMetrics a = collector.getOrCreateClassMetrics("com.example.A"); |
| 155 | + ClassMetrics b = collector.getOrCreateClassMetrics("com.example.B"); |
| 156 | + a.addSealedHierarchyAncestor("com.example.B"); |
| 157 | + b.addSealedHierarchyAncestor("com.example.A"); |
| 158 | + b.addSealedHierarchyAncestor("com.example.Shape"); |
| 159 | + |
| 160 | + collector.finalizeMetrics(); |
| 161 | + |
| 162 | + assertEquals(3, a.getSealedHierarchyDepth(), "A reaches the Shape root through B"); |
| 163 | + assertEquals(2, b.getSealedHierarchyDepth(), "B reaches the Shape root directly"); |
| 164 | + } |
| 165 | + |
148 | 166 | @DisplayName("a chain ending at a non-sealed class in the batch has depth 0") |
149 | 167 | @Test |
150 | 168 | void chainEndingAtNonSealedClass_hasDepthZero() { |
|
0 commit comments