pygame: CLEAN — runtime uses dict/set throughout (O(1) membership) libgdx-0002: ModelBuilder.rebuildReferences Array.contains O(P*M) — patch libgdx-0005: Stage.touchDragged touchFocuses.contains O(F^2) — patch libgdx-0006: AfterAction.delegate currentActions.indexOf O(W*A) per frame — patch unit: extend LibGDXTest to 7 tests, all PASS (50x-1971x speedup measured)
165 lines
6.7 KiB
Java
165 lines
6.7 KiB
Java
import java.util.*;
|
|
|
|
/**
|
|
* CWE-407 unit test — NATS Server nats-server-0001
|
|
*
|
|
* server/reload.go diffRoutes()
|
|
* Two nested O(R) loops compare every old URL against every new URL.
|
|
* Complexity: O(R²) where R = number of route URLs.
|
|
* Large NATS clusters can carry hundreds of route URLs; config-reload
|
|
* (triggered by SIGHUP or file watcher) executes diffRoutes on every reload.
|
|
*
|
|
* Fix: build map[string]struct{} keyed on url.String() for each list,
|
|
* then two single-pass O(R) sweeps replace the double loop → O(R) total.
|
|
*/
|
|
public class NatsServerTest {
|
|
|
|
// ---- defect simulation --------------------------------------------------
|
|
|
|
/** O(R²): for each old URL, scan all new URLs for a match. */
|
|
static void diffRoutes_quadratic(List<String> old, List<String> newList,
|
|
List<String> add, List<String> remove) {
|
|
outer:
|
|
for (String oldRoute : old) {
|
|
for (String newRoute : newList) {
|
|
if (oldRoute.equals(newRoute)) {
|
|
continue outer;
|
|
}
|
|
}
|
|
remove.add(oldRoute);
|
|
}
|
|
outer:
|
|
for (String newRoute : newList) {
|
|
for (String oldRoute : old) {
|
|
if (newRoute.equals(oldRoute)) {
|
|
continue outer;
|
|
}
|
|
}
|
|
add.add(newRoute);
|
|
}
|
|
}
|
|
|
|
// ---- fix simulation -----------------------------------------------------
|
|
|
|
/** O(R): build HashSets, then single-pass each list. */
|
|
static void diffRoutes_linear(List<String> old, List<String> newList,
|
|
List<String> add, List<String> remove) {
|
|
Set<String> newSet = new HashSet<>(newList);
|
|
Set<String> oldSet = new HashSet<>(old);
|
|
for (String o : old) {
|
|
if (!newSet.contains(o)) remove.add(o);
|
|
}
|
|
for (String n : newList) {
|
|
if (!oldSet.contains(n)) add.add(n);
|
|
}
|
|
}
|
|
|
|
// ---- helpers ------------------------------------------------------------
|
|
|
|
static List<String> makeRoutes(int base, int count) {
|
|
List<String> urls = new ArrayList<>(count);
|
|
for (int i = 0; i < count; i++) {
|
|
urls.add("nats://node-" + (base + i) + ".cluster.local:6222");
|
|
}
|
|
return urls;
|
|
}
|
|
|
|
// ---- tests --------------------------------------------------------------
|
|
|
|
static void testCorrectnessSmall() {
|
|
List<String> old = Arrays.asList(
|
|
"nats://a:6222", "nats://b:6222", "nats://c:6222"
|
|
);
|
|
List<String> newList = Arrays.asList(
|
|
"nats://b:6222", "nats://c:6222", "nats://d:6222"
|
|
);
|
|
|
|
List<String> addQ = new ArrayList<>(), removeQ = new ArrayList<>();
|
|
List<String> addL = new ArrayList<>(), removeL = new ArrayList<>();
|
|
diffRoutes_quadratic(old, newList, addQ, removeQ);
|
|
diffRoutes_linear(old, newList, addL, removeL);
|
|
|
|
Collections.sort(addQ); Collections.sort(addL);
|
|
Collections.sort(removeQ); Collections.sort(removeL);
|
|
assert addQ.equals(addL) : "add mismatch: " + addQ + " vs " + addL;
|
|
assert removeQ.equals(removeL) : "remove mismatch: " + removeQ + " vs " + removeL;
|
|
assert addL.equals(Arrays.asList("nats://d:6222")) : "expected d to be added";
|
|
assert removeL.equals(Arrays.asList("nats://a:6222")) : "expected a to be removed";
|
|
System.out.println("PASS testCorrectnessSmall");
|
|
}
|
|
|
|
static void testEmptyOld() {
|
|
List<String> old = Collections.emptyList();
|
|
List<String> newList = Arrays.asList("nats://x:6222", "nats://y:6222");
|
|
List<String> addQ = new ArrayList<>(), removeQ = new ArrayList<>();
|
|
List<String> addL = new ArrayList<>(), removeL = new ArrayList<>();
|
|
diffRoutes_quadratic(old, newList, addQ, removeQ);
|
|
diffRoutes_linear(old, newList, addL, removeL);
|
|
assert addQ.equals(addL) && removeQ.equals(removeL) : "empty-old mismatch";
|
|
System.out.println("PASS testEmptyOld");
|
|
}
|
|
|
|
static void testEmptyNew() {
|
|
List<String> old = Arrays.asList("nats://x:6222", "nats://y:6222");
|
|
List<String> newList = Collections.emptyList();
|
|
List<String> addQ = new ArrayList<>(), removeQ = new ArrayList<>();
|
|
List<String> addL = new ArrayList<>(), removeL = new ArrayList<>();
|
|
diffRoutes_quadratic(old, newList, addQ, removeQ);
|
|
diffRoutes_linear(old, newList, addL, removeL);
|
|
assert addQ.equals(addL) && removeQ.equals(removeL) : "empty-new mismatch";
|
|
System.out.println("PASS testEmptyNew");
|
|
}
|
|
|
|
static void testIdenticalLists() {
|
|
List<String> old = Arrays.asList("nats://a:6222", "nats://b:6222");
|
|
List<String> newList = new ArrayList<>(old);
|
|
List<String> addQ = new ArrayList<>(), removeQ = new ArrayList<>();
|
|
List<String> addL = new ArrayList<>(), removeL = new ArrayList<>();
|
|
diffRoutes_quadratic(old, newList, addQ, removeQ);
|
|
diffRoutes_linear(old, newList, addL, removeL);
|
|
assert addQ.isEmpty() && removeQ.isEmpty() : "identical: unexpected diff (quadratic)";
|
|
assert addL.isEmpty() && removeL.isEmpty() : "identical: unexpected diff (linear)";
|
|
System.out.println("PASS testIdenticalLists");
|
|
}
|
|
|
|
static void testBenchmarkRatio() {
|
|
// Simulate a large NATS cluster: R=300 route URLs, 1 change on reload
|
|
int R = 300;
|
|
List<String> old = makeRoutes(0, R);
|
|
List<String> newList = makeRoutes(1, R); // shifted by 1 → 1 remove, 1 add
|
|
|
|
int ITERS = 200;
|
|
|
|
long t0 = System.nanoTime();
|
|
for (int i = 0; i < ITERS; i++) {
|
|
List<String> add = new ArrayList<>(), remove = new ArrayList<>();
|
|
diffRoutes_quadratic(old, newList, add, remove);
|
|
}
|
|
long quadraticNs = System.nanoTime() - t0;
|
|
|
|
long t1 = System.nanoTime();
|
|
for (int i = 0; i < ITERS; i++) {
|
|
List<String> add = new ArrayList<>(), remove = new ArrayList<>();
|
|
diffRoutes_linear(old, newList, add, remove);
|
|
}
|
|
long linearNs = System.nanoTime() - t1;
|
|
|
|
double ratio = (double) quadraticNs / linearNs;
|
|
System.out.printf("BENCH R=%d iters=%d quadratic=%.1fms linear=%.1fms ratio=%.1fx%n",
|
|
R, ITERS,
|
|
quadraticNs / 1e6,
|
|
linearNs / 1e6,
|
|
ratio);
|
|
assert ratio >= 2.0 : "Expected >=2x speedup at R=" + R + ", got " + ratio;
|
|
System.out.println("PASS testBenchmarkRatio");
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
testCorrectnessSmall();
|
|
testEmptyOld();
|
|
testEmptyNew();
|
|
testIdenticalLists();
|
|
testBenchmarkRatio();
|
|
System.out.println("ALL PASS");
|
|
}
|
|
}
|