java-topology/defects/hibernate-orm-0001/test/HibernateOrm0001Test.java
russell@unturf.com 32cbeb5dcb tomcat-0001/hibernate-orm-0001/netty-0001/netty-0002: 4 new CWE-407 defects
tomcat-0001: WebSocket getNegotiatedSubprotocol List.contains O(R×S) MEDIUM 52x
hibernate-orm-0001: FK ordering buildRecursiveOrderedFkSecondPasses List.contains O(N²) HIGH 2.8x
netty-0001: ALPN select/selected List.contains O(S×P) MEDIUM 26x
netty-0002: DnsResolveContext dedup ArrayList.contains O(R²) MEDIUM 30x

All 4/4 unit tests PASS.
2026-03-30 13:55:21 -04:00

127 lines
4.8 KiB
Java

import java.util.*;
/**
* Unit test for hibernate-orm-0001: InFlightMetadataCollectorImpl
* .buildRecursiveOrderedFkSecondPasses List.contains() O(N²)
* → companion HashSet O(N).
*/
public class HibernateOrm0001Test {
// Simulate FkSecondPass as a simple wrapper
static class FkSecondPass {
final String table;
final String dependentTable;
FkSecondPass(String table, String dependentTable) {
this.table = table;
this.dependentTable = dependentTable;
}
@Override public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof FkSecondPass)) return false;
FkSecondPass that = (FkSecondPass) o;
return table.equals(that.table) && dependentTable.equals(that.dependentTable);
}
@Override public int hashCode() {
return Objects.hash(table, dependentTable);
}
}
// --- BEFORE: O(N²) with List.contains() ---
static void buildRecursiveBefore(
List<FkSecondPass> ordered,
Map<String, Set<FkSecondPass>> deps,
String startTable, String currentTable) {
Set<FkSecondPass> dependencies = deps.get(currentTable);
if (dependencies != null) {
for (FkSecondPass fk : dependencies) {
if (!fk.dependentTable.equals(startTable)) {
buildRecursiveBefore(ordered, deps, startTable, fk.dependentTable);
}
if (!ordered.contains(fk)) { // O(N) linear scan
ordered.add(0, fk);
}
}
}
}
// --- AFTER: O(N) with companion HashSet ---
static void buildRecursiveAfter(
List<FkSecondPass> ordered,
Set<FkSecondPass> orderedSet,
Map<String, Set<FkSecondPass>> deps,
String startTable, String currentTable) {
Set<FkSecondPass> dependencies = deps.get(currentTable);
if (dependencies != null) {
for (FkSecondPass fk : dependencies) {
if (!fk.dependentTable.equals(startTable)) {
buildRecursiveAfter(ordered, orderedSet, deps, startTable, fk.dependentTable);
}
if (!orderedSet.contains(fk)) { // O(1) lookup
orderedSet.add(fk);
ordered.add(0, fk);
}
}
}
}
public static void main(String[] args) {
// Build a chain of N tables: t0 → t1 → t2 → ... → tN
int N = 500;
Map<String, Set<FkSecondPass>> deps = new HashMap<>();
for (int i = 0; i < N - 1; i++) {
String table = "t" + i;
String depTable = "t" + (i + 1);
deps.computeIfAbsent(table, k -> new LinkedHashSet<>())
.add(new FkSecondPass(table, depTable));
}
// Correctness
List<FkSecondPass> beforeList = new ArrayList<>();
buildRecursiveBefore(beforeList, deps, "t0", "t0");
List<FkSecondPass> afterList = new ArrayList<>();
Set<FkSecondPass> afterSet = new HashSet<>();
buildRecursiveAfter(afterList, afterSet, deps, "t0", "t0");
assert beforeList.size() == afterList.size() :
"Size mismatch: " + beforeList.size() + " vs " + afterList.size();
for (int i = 0; i < beforeList.size(); i++) {
assert beforeList.get(i).equals(afterList.get(i)) :
"Mismatch at index " + i;
}
System.out.println("PASS correctness: " + beforeList.size() + " FK passes ordered identically");
// Performance
int iterations = 200;
// Warmup
for (int w = 0; w < 20; w++) {
List<FkSecondPass> tmp = new ArrayList<>();
buildRecursiveBefore(tmp, deps, "t0", "t0");
tmp = new ArrayList<>();
Set<FkSecondPass> ts = new HashSet<>();
buildRecursiveAfter(tmp, ts, deps, "t0", "t0");
}
long t0 = System.nanoTime();
for (int i = 0; i < iterations; i++) {
List<FkSecondPass> tmp = new ArrayList<>();
buildRecursiveBefore(tmp, deps, "t0", "t0");
}
long beforeNs = System.nanoTime() - t0;
t0 = System.nanoTime();
for (int i = 0; i < iterations; i++) {
List<FkSecondPass> tmp = new ArrayList<>();
Set<FkSecondPass> ts = new HashSet<>();
buildRecursiveAfter(tmp, ts, deps, "t0", "t0");
}
long afterNs = System.nanoTime() - t0;
double ratio = (double) beforeNs / afterNs;
System.out.printf("PASS performance: before=%dms after=%dms ratio=%.1fx (N=%d)%n",
beforeNs / 1_000_000, afterNs / 1_000_000, ratio, N);
assert ratio > 2.0 : "Expected at least 2x speedup, got " + ratio;
System.out.println("PASS all tests for hibernate-orm-0001");
}
}