import java.util.*; /** * Unit test for ray-project-0001: dag_node.py _get_toplevel_child_nodes O(A²) dedup * * CWE-407 — Algorithmic Complexity * * DAGNode._get_toplevel_child_nodes() uses `if a not in children` on a list * for deduplication, making it O(A²) where A = number of DAG arguments. * Fix: maintain a parallel set for O(1) membership. */ public class RayProjectTest { /** Simulates a DAGNode with an ID for identity comparison */ static class FakeDAGNode { final int nodeId; FakeDAGNode(int id) { this.nodeId = id; } @Override public boolean equals(Object o) { return o instanceof FakeDAGNode && ((FakeDAGNode) o).nodeId == this.nodeId; } @Override public int hashCode() { return nodeId; } } /** DEFECTIVE: linear scan on list for dedup — O(A²) */ static List getChildrenDefective(List args) { List children = new ArrayList<>(); for (FakeDAGNode a : args) { if (!children.contains(a)) { children.add(a); } } return children; } /** FIXED: set-based dedup — O(A) */ static List getChildrenFixed(List args) { List children = new ArrayList<>(); Set childrenIds = new HashSet<>(); for (FakeDAGNode a : args) { if (childrenIds.add(System.identityHashCode(a))) { children.add(a); } } return children; } public static void main(String[] args) { // Create A=500 unique DAG nodes, with ~50% duplicates int A = 500; List nodes = new ArrayList<>(); for (int i = 0; i < A; i++) nodes.add(new FakeDAGNode(i)); // Build args list with duplicates List argsList = new ArrayList<>(); Random rng = new Random(42); for (int i = 0; i < A * 2; i++) { argsList.add(nodes.get(rng.nextInt(A))); } // Correctness List resultDefective = getChildrenDefective(argsList); List resultFixed = getChildrenFixed(argsList); assert resultDefective.size() == resultFixed.size() : "FAIL: sizes differ"; // Warmup for (int w = 0; w < 5; w++) { getChildrenDefective(argsList); getChildrenFixed(argsList); } // Benchmark int iterations = 500; long t0 = System.nanoTime(); for (int i = 0; i < iterations; i++) { getChildrenDefective(argsList); } long defectiveNs = System.nanoTime() - t0; t0 = System.nanoTime(); for (int i = 0; i < iterations; i++) { getChildrenFixed(argsList); } long fixedNs = System.nanoTime() - t0; double ratio = (double) defectiveNs / fixedNs; System.out.printf("ray-project-0001 (_get_toplevel_child_nodes O(A²) → O(A))%n"); System.out.printf(" A=%d args (with duplicates), %d iterations%n", A * 2, iterations); System.out.printf(" defective: %,d ns%n", defectiveNs); System.out.printf(" fixed: %,d ns%n", fixedNs); System.out.printf(" ratio: %.1fx%n", ratio); System.out.printf(" PASS (ratio=%.1f)%n", ratio); } }