java-topology/tests/unit/TopoSorterComplexityTest.java
russell@unturf.com 0a580b313d undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
2026-03-26 17:11:57 -04:00

210 lines
9.2 KiB
Java

package unit;
import support.TopoSorterAlgorithm;
import support.TopoSorterAlgorithm.Result;
import java.util.List;
/**
* Unit tests for DEFECT 0003: ModuleHashesBuilder$TopoSorter Deque.contains().
*
* Proves:
* 1. Both implementations produce identical topological orderings (correctness).
* 2. Defective version makes exactly V*(V-1)/2 comparisons for a V-node chain.
* 3. Fixed version makes exactly V comparisons for the same chain.
* 4. Doubling V quadruples defective work; doubling V doubles fixed work.
*
* No build tool required. Compile and run:
*
* cd tests
* java -m jdk.compiler/com.sun.tools.javac.Main -cp . \
* support/TopoSorterAlgorithm.java unit/TopoSorterComplexityTest.java
* java -cp . unit.TopoSorterComplexityTest
*/
public class TopoSorterComplexityTest {
private static int passed = 0;
private static int failed = 0;
public static void main(String[] args) {
System.out.println("=== TopoSorterComplexityTest (DEFECT 0003) ===\n");
System.out.println("-- Correctness: both sorters produce the same ordering --");
testCorrectnessSmall();
testCorrectnessMedium();
testCorrectnessSingleNode();
System.out.println("\n-- Complexity: defective comparison counts V*(V-1)/2 --");
testDefectiveExactCounts();
System.out.println("\n-- Complexity: fixed comparison counts V --");
testFixedExactCounts();
System.out.println("\n-- Complexity: growth ratio proves quadratic vs linear --");
testGrowthRatio();
System.out.printf("\n%d passed, %d failed%n", passed, failed);
if (failed > 0) System.exit(1);
}
// ─── Correctness ─────────────────────────────────────────────────────────
static void testCorrectnessSmall() {
List<TopoSorterAlgorithm.Node> graph = TopoSorterAlgorithm.buildLinearChain(5);
Result def = TopoSorterAlgorithm.topoSortDefective(graph);
List<TopoSorterAlgorithm.Node> graph2 = TopoSorterAlgorithm.buildLinearChain(5);
Result fix = TopoSorterAlgorithm.topoSortFixed(graph2);
assertEqual("small: defective sorted count", 5, def.sorted.size());
assertEqual("small: fixed sorted count", 5, fix.sorted.size());
// Chain N0→...→N4 sorted as [N0, N1, N2, N3, N4]
for (int i = 0; i < 5; i++) {
assertEqual("small: defective sorted[" + i + "]", "N" + i, def.sorted.get(i).label);
assertEqual("small: fixed sorted[" + i + "]", "N" + i, fix.sorted.get(i).label);
}
}
static void testCorrectnessMedium() {
List<TopoSorterAlgorithm.Node> graph = TopoSorterAlgorithm.buildLinearChain(20);
Result def = TopoSorterAlgorithm.topoSortDefective(graph);
List<TopoSorterAlgorithm.Node> graph2 = TopoSorterAlgorithm.buildLinearChain(20);
Result fix = TopoSorterAlgorithm.topoSortFixed(graph2);
assertEqual("medium: defective sorted count", 20, def.sorted.size());
assertEqual("medium: fixed sorted count", 20, fix.sorted.size());
for (int i = 0; i < 20; i++) {
assertEqual("medium: sorted[" + i + "] labels match",
def.sorted.get(i).label, fix.sorted.get(i).label);
}
}
static void testCorrectnessSingleNode() {
List<TopoSorterAlgorithm.Node> g1 = TopoSorterAlgorithm.buildLinearChain(1);
List<TopoSorterAlgorithm.Node> g2 = TopoSorterAlgorithm.buildLinearChain(1);
Result def = TopoSorterAlgorithm.topoSortDefective(g1);
Result fix = TopoSorterAlgorithm.topoSortFixed(g2);
assertEqual("single: defective count", 1, def.sorted.size());
assertEqual("single: fixed count", 1, fix.sorted.size());
assertEqual("single: defective comparisons", 0L, def.comparisons);
assertEqual("single: fixed comparisons", 1L, fix.comparisons);
}
// ─── Exact comparison counts ──────────────────────────────────────────────
/**
* PROVES DEFECT: a V-node chain forces exactly V*(V-1)/2 comparisons with
* the Deque.contains() scan.
*
* Derivation:
* visit(N0): stack=[], scan 0 elements → 0 comparisons
* visit(N1): stack=[N0], scan 1 element → 1 comparison
* visit(N_k): stack is k deep → k comparisons
* Total: 0+1+2+...+(V-1) = V*(V-1)/2.
*/
static void testDefectiveExactCounts() {
System.out.println("[defective] linearChain(V) — expected V*(V-1)/2:");
int[] sizes = {5, 10, 20, 50, 100};
for (int v : sizes) {
List<TopoSorterAlgorithm.Node> graph = TopoSorterAlgorithm.buildLinearChain(v);
Result r = TopoSorterAlgorithm.topoSortDefective(graph);
long expected = (long) v * (v - 1) / 2;
System.out.printf(" V=%-4d actual=%-8d expected=%-8d %s%n",
v, r.comparisons, expected,
r.comparisons == expected ? "PASS" : "FAIL expected=" + expected);
assertEqual("defective V=" + v, expected, r.comparisons);
}
}
/**
* PROVES FIX: a V-node chain requires exactly V comparisons — one per node visit.
*/
static void testFixedExactCounts() {
System.out.println("[fixed] linearChain(V) — expected V:");
int[] sizes = {5, 10, 20, 50, 100};
for (int v : sizes) {
List<TopoSorterAlgorithm.Node> graph = TopoSorterAlgorithm.buildLinearChain(v);
Result r = TopoSorterAlgorithm.topoSortFixed(graph);
long expected = v;
System.out.printf(" V=%-4d actual=%-8d expected=%-8d %s%n",
v, r.comparisons, expected,
r.comparisons == expected ? "PASS" : "FAIL");
assertEqual("fixed V=" + v, expected, r.comparisons);
}
}
// ─── Growth ratio ─────────────────────────────────────────────────────────
/**
* PROVES QUADRATIC GROWTH:
* Doubling V → defective comparisons quadruple (≈4x), fixed double (≈2x).
*
* Math:
* defective(V) = V*(V-1)/2 ≈ V²/2
* defective(2V) = 2V*(2V-1)/2 ≈ 2V² → ratio ≈ 4
* fixed(V) = V, fixed(2V) = 2V → ratio = 2 (exact)
*
* Exact defective ratio = 2V*(2V-1) / (V*(V-1)) = 2*(2V-1)/(V-1)
* → approaches 4 as V→∞; ≥3.8 for V≥10.
*/
static void testGrowthRatio() {
int[][] pairs = {{10, 20}, {20, 40}, {50, 100}, {100, 200}};
for (int[] pair : pairs) {
int v1 = pair[0], v2 = pair[1];
List<TopoSorterAlgorithm.Node> g1 = TopoSorterAlgorithm.buildLinearChain(v1);
List<TopoSorterAlgorithm.Node> g2 = TopoSorterAlgorithm.buildLinearChain(v2);
List<TopoSorterAlgorithm.Node> g3 = TopoSorterAlgorithm.buildLinearChain(v1);
List<TopoSorterAlgorithm.Node> g4 = TopoSorterAlgorithm.buildLinearChain(v2);
long def1 = TopoSorterAlgorithm.topoSortDefective(g1).comparisons;
long def2 = TopoSorterAlgorithm.topoSortDefective(g2).comparisons;
long fix1 = TopoSorterAlgorithm.topoSortFixed(g3).comparisons;
long fix2 = TopoSorterAlgorithm.topoSortFixed(g4).comparisons;
double defRatio = (double) def2 / def1;
double fixRatio = (double) fix2 / fix1;
System.out.printf(" V %d→%d: defective ratio=%.2f (expect ~4.0) fixed ratio=%.2f (expect 2.0)%n",
v1, v2, defRatio, fixRatio);
assertTrue("defective V=" + v1 + "" + v2 + " ratio ≥ 3.8", defRatio >= 3.8);
// exact ratio = 2*(2V-1)/(V-1) → 4.22 at V=10, converges to 4.0
assertTrue("defective V=" + v1 + "" + v2 + " ratio ≤ 4.25", defRatio <= 4.25);
assertTrue("fixed V=" + v1 + "" + v2 + " ratio = 2.0", fixRatio == 2.0);
}
}
// ─── Helpers ─────────────────────────────────────────────────────────────
static void assertEqual(String name, long expected, long actual) {
if (expected == actual) {
System.out.printf(" PASS %s%n", name);
passed++;
} else {
System.out.printf(" FAIL %s expected=%d actual=%d%n", name, expected, actual);
failed++;
}
}
static void assertEqual(String name, String expected, String actual) {
if (expected.equals(actual)) {
System.out.printf(" PASS %s%n", name);
passed++;
} else {
System.out.printf(" FAIL %s expected=%s actual=%s%n", name, expected, actual);
failed++;
}
}
static void assertTrue(String name, boolean condition) {
if (condition) {
System.out.printf(" PASS %s%n", name);
passed++;
} else {
System.out.printf(" FAIL %s%n", name);
failed++;
}
}
}