package unit; /** * CWE-407 unit test: ONOS PipelineTraceableHitChain.addDataPlaneEntity() * Defect: ArrayList.contains() O(n) inside O(n) forEach loop = O(n²) * Fix: LinkedHashSet — O(1) add/contains, insertion order preserved * * slow(): ArrayList-backed chain — counts equality comparisons via instrumented elements * fast(): LinkedHashSet-backed chain — O(1) per add regardless of chain size * Assert: slowOps > fastOps * 5 (chain of N=200 entries → ~10000 vs ~200 ops) */ public class OnosPipelineHitChainTest { /** Instrumented entity that counts equals() calls. */ static class CountingEntity { final int id; static long totalEquals = 0; CountingEntity(int id) { this.id = id; } @Override public boolean equals(Object o) { totalEquals++; if (!(o instanceof CountingEntity)) return false; return id == ((CountingEntity) o).id; } @Override public int hashCode() { return Integer.hashCode(id); } } /** Slow path: ArrayList — .contains() scans linearly before each add. */ static long slow(int n) { java.util.List list = new java.util.ArrayList<>(); CountingEntity.totalEquals = 0; // Simulate addDataPlaneEntity called for each of n elements (chain copy) for (int i = 0; i < n; i++) { CountingEntity e = new CountingEntity(i); if (!list.contains(e)) { // O(i) scan list.add(e); } } return CountingEntity.totalEquals; } /** Fast path: LinkedHashSet — .add() uses hashCode+equals O(1) average. */ static long fast(int n) { java.util.LinkedHashSet set = new java.util.LinkedHashSet<>(); CountingEntity.totalEquals = 0; for (int i = 0; i < n; i++) { set.add(new CountingEntity(i)); // O(1) avg } return CountingEntity.totalEquals; } public static void main(String[] args) { int N = 200; int MULTIPLIER = 5; long sOps = slow(N); long fOps = fast(N); System.out.println("N=" + N); System.out.println("slow (ArrayList.contains): " + sOps + " equals() calls"); System.out.println("fast (LinkedHashSet.add): " + fOps + " equals() calls"); if (sOps > fOps * MULTIPLIER) { System.out.println("1/1 PASS (slow=" + sOps + " > fast*" + MULTIPLIER + "=" + (fOps * MULTIPLIER) + ")"); } else { System.out.println("1/1 FAIL (slow=" + sOps + " not > fast*" + MULTIPLIER + "=" + (fOps * MULTIPLIER) + ")"); System.exit(1); } } }