java-topology/defects/element-web/unit/ElementWebTest.java

130 lines
5.5 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package unit;
import java.util.*;
/**
* ElementWebTest — CWE-407 benchmark for element-web-0001
*
* element-web-0001: apps/web/src/TextForEvent.tsx:503
* textForPowerEvent() deduplicates user IDs from power level event using indexOf on an array.
* Two forEach loops each calling indexOf (O(n)) to build a dedup list — total O(N²).
*
* Slow: for each userId in contentUsers prevContentUsers: indexOf on accumulator array
* Fast: Set union in O(N)
*
* compile: javac -d . ElementWebTest.java && java -ea unit.ElementWebTest
*/
public class ElementWebTest {
static void bench(String label, Runnable slow, Runnable fast, long sOps, long fOps) {
slow.run(); fast.run(); // warmup
long t0 = System.nanoTime(); slow.run(); long sMs = (System.nanoTime() - t0) / 1_000_000;
long t1 = System.nanoTime(); fast.run(); long fMs = (System.nanoTime() - t1) / 1_000_000;
double ratio = fOps > 0 ? (double) sOps / fOps : 0;
System.out.printf(" %-60s slow:%4dms (%,d ops) fast:%4dms (%,d ops) speedup:%.0fx%n",
label, sMs, sOps, fMs, fOps, ratio);
}
// -----------------------------------------------------------------------
// element-web-0001: users.indexOf dedup in forEach loop
// -----------------------------------------------------------------------
/**
* Slow: Array.indexOf inside forEach — O((A+B)²)
* Simulates building a dedup list from two sets of user IDs.
* Returns total comparison operations performed.
*/
static long slowPowerEventDedup(int contentUsers, int prevContentUsers) {
List<String> contentKeys = new ArrayList<>();
for (int i = 0; i < contentUsers; i++) contentKeys.add("user-" + i);
// prevContent has some overlap + some new users
List<String> prevKeys = new ArrayList<>();
for (int i = contentUsers / 2; i < contentUsers / 2 + prevContentUsers; i++)
prevKeys.add("user-" + i);
List<String> users = new ArrayList<>();
long ops = 0;
// forEach(userId => if (users.indexOf(userId) === -1) users.push(userId))
for (String userId : contentKeys) {
ops += users.size(); // cost of indexOf scan (grows as list fills)
if (!users.contains(userId)) users.add(userId);
}
for (String userId : prevKeys) {
ops += users.size(); // cost of indexOf scan
if (!users.contains(userId)) users.add(userId);
}
return ops;
}
/**
* Fast: Set union — O(A + B)
* Returns total operations (one per element).
*/
static long fastPowerEventDedup(int contentUsers, int prevContentUsers) {
List<String> contentKeys = new ArrayList<>();
for (int i = 0; i < contentUsers; i++) contentKeys.add("user-" + i);
List<String> prevKeys = new ArrayList<>();
for (int i = contentUsers / 2; i < contentUsers / 2 + prevContentUsers; i++)
prevKeys.add("user-" + i);
long ops = 0;
Set<String> userSet = new LinkedHashSet<>();
for (String u : contentKeys) { userSet.add(u); ops++; }
for (String u : prevKeys) { userSet.add(u); ops++; }
// Array.from(userSet) — O(N)
List<String> users = new ArrayList<>(userSet);
ops += users.size();
return ops;
}
public static void main(String[] args) {
System.out.println("ElementWebTest — CWE-407 benchmarks");
System.out.println();
int passed = 0;
int total = 0;
// Small room (N=200 each side)
{
int A = 200, B = 200;
long[] sOps = {0}, fOps = {0};
Runnable s = () -> sOps[0] = slowPowerEventDedup(A, B);
Runnable f = () -> fOps[0] = fastPowerEventDedup(A, B);
sOps[0] = slowPowerEventDedup(A, B);
fOps[0] = fastPowerEventDedup(A, B);
bench("element-web-0001 power event dedup indexOf vs Set (A=" + A + " B=" + B + ")", s, f, sOps[0], fOps[0]);
total++;
if (sOps[0] > fOps[0] * 10L) {
System.out.println(" element-web-0001 small PASS (slow=" + sOps[0] + " > 10x fast=" + fOps[0] + ")");
passed++;
} else {
System.out.println(" element-web-0001 small FAIL (slow=" + sOps[0] + " fast=" + fOps[0] + ")");
}
assert sOps[0] > fOps[0] * 10L : "element-web-0001 small: slow ops not 10x fast ops";
}
// Large room (N=1000 each side — large server with many power level entries)
{
int A = 1000, B = 1000;
long[] sOps = {0}, fOps = {0};
Runnable s = () -> sOps[0] = slowPowerEventDedup(A, B);
Runnable f = () -> fOps[0] = fastPowerEventDedup(A, B);
sOps[0] = slowPowerEventDedup(A, B);
fOps[0] = fastPowerEventDedup(A, B);
bench("element-web-0001 power event dedup indexOf vs Set (A=" + A + " B=" + B + ")", s, f, sOps[0], fOps[0]);
total++;
if (sOps[0] > fOps[0] * 50L) {
System.out.println(" element-web-0001 large PASS (slow=" + sOps[0] + " > 50x fast=" + fOps[0] + ")");
passed++;
} else {
System.out.println(" element-web-0001 large FAIL (slow=" + sOps[0] + " fast=" + fOps[0] + ")");
}
assert sOps[0] > fOps[0] * 50L : "element-web-0001 large: slow ops not 50x fast ops";
}
System.out.println();
System.out.println(passed + "/" + total + " PASS");
}
}