jitsi-meet-0003: av-moderation pendingAudio/Video/Desktop Array.find() dedup O(P^2) in large moderated meetings — 249.5x op-count at P=500, 138.5x measured at P=2000. Fix: Map<id, participant> for O(1) dedup. jitsi-meet-0004: visitors middleware delta Array.findIndex() per update O(U*V) in large broadcast events — 15x at V=5000 U=1000. Fix: Map-based apply-delta O(1) per join/leave. solvespace-0002: VRML export colours_present std::vector + find_if O(T*C) per triangle — 250x op-count at T=50k C=500. Fix: unordered_map keyed by ToPackedInt() RGBA uint32. MOAD-0002/0003/0004/0005: CLEAN for both targets. All 13 unit tests PASS.
171 lines
6.8 KiB
Java
171 lines
6.8 KiB
Java
import java.util.*;
|
|
|
|
/**
|
|
* Unit test for jitsi-meet-0003: AV moderation pending participant dedup.
|
|
*
|
|
* Models the TypeScript reducer logic in Java to verify O(1) Map-based dedup
|
|
* vs O(P) Array.find() dedup.
|
|
*
|
|
* Defect location:
|
|
* react/features/av-moderation/reducer.ts line 210 (PARTICIPANT_PENDING_AUDIO)
|
|
* react/features/av-moderation/functions.ts line 129 (isParticipantPending)
|
|
*
|
|
* Compile and run:
|
|
* javac defects/jitsi-meet-0003/unit/AvModerationPendingTest.java
|
|
* java -cp defects/jitsi-meet-0003/unit AvModerationPendingTest
|
|
*/
|
|
public class AvModerationPendingTest {
|
|
|
|
// --- Defective implementation: Array.find() for dedup ---
|
|
|
|
static List<Map<String, String>> pendingArrayAdd(
|
|
List<Map<String, String>> pending, Map<String, String> participant) {
|
|
// O(P) linear scan — mirrors reducer.ts line 210
|
|
boolean alreadyPresent = false;
|
|
for (Map<String, String> p : pending) {
|
|
if (p.get("id").equals(participant.get("id"))) {
|
|
alreadyPresent = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!alreadyPresent) {
|
|
List<Map<String, String>> updated = new ArrayList<>(pending);
|
|
updated.add(participant);
|
|
return updated;
|
|
}
|
|
return pending;
|
|
}
|
|
|
|
static boolean isPendingArray(List<Map<String, String>> pending, String id) {
|
|
// O(P) — mirrors functions.ts line 129
|
|
for (Map<String, String> p : pending) {
|
|
if (p.get("id").equals(id)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// --- Fixed implementation: Map for O(1) dedup ---
|
|
|
|
static Map<String, Map<String, String>> pendingMapAdd(
|
|
Map<String, Map<String, String>> pending, Map<String, String> participant) {
|
|
String id = participant.get("id");
|
|
if (!pending.containsKey(id)) {
|
|
Map<String, Map<String, String>> updated = new LinkedHashMap<>(pending);
|
|
updated.put(id, participant);
|
|
return updated;
|
|
}
|
|
return pending;
|
|
}
|
|
|
|
static boolean isPendingMap(Map<String, Map<String, String>> pending, String id) {
|
|
return pending.containsKey(id); // O(1)
|
|
}
|
|
|
|
// --- Helpers ---
|
|
|
|
static Map<String, String> participant(String id) {
|
|
Map<String, String> p = new HashMap<>();
|
|
p.put("id", id);
|
|
p.put("name", "Participant " + id);
|
|
return p;
|
|
}
|
|
|
|
static void check(boolean condition, String msg) {
|
|
if (!condition) throw new AssertionError("FAIL: " + msg);
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
System.out.println("jitsi-meet-0003: AvModerationPendingTest");
|
|
|
|
// Test 1: Array dedup correctness
|
|
{
|
|
List<Map<String, String>> pending = new ArrayList<>();
|
|
pending = pendingArrayAdd(pending, participant("p1"));
|
|
pending = pendingArrayAdd(pending, participant("p1")); // duplicate
|
|
pending = pendingArrayAdd(pending, participant("p2"));
|
|
check(pending.size() == 2, "Array: duplicate must be rejected, got " + pending.size());
|
|
check(isPendingArray(pending, "p1"), "Array: p1 must be present");
|
|
check(isPendingArray(pending, "p2"), "Array: p2 must be present");
|
|
check(!isPendingArray(pending, "p3"), "Array: p3 must be absent");
|
|
System.out.println(" PASS test-1: array dedup correctness");
|
|
}
|
|
|
|
// Test 2: Map dedup correctness
|
|
{
|
|
Map<String, Map<String, String>> pending = new LinkedHashMap<>();
|
|
pending = pendingMapAdd(pending, participant("p1"));
|
|
pending = pendingMapAdd(pending, participant("p1")); // duplicate
|
|
pending = pendingMapAdd(pending, participant("p2"));
|
|
check(pending.size() == 2, "Map: duplicate must be rejected, got " + pending.size());
|
|
check(isPendingMap(pending, "p1"), "Map: p1 must be present");
|
|
check(isPendingMap(pending, "p2"), "Map: p2 must be present");
|
|
check(!isPendingMap(pending, "p3"), "Map: p3 must be absent");
|
|
System.out.println(" PASS test-2: map dedup correctness");
|
|
}
|
|
|
|
// Test 3: Performance — count total comparisons (algorithmic, not timing)
|
|
// Defective: adding P unique participants costs O(1)+O(2)+...+O(P) = O(P^2/2) comparisons
|
|
// Fixed: O(P) hash lookups regardless of order
|
|
{
|
|
int P = 500;
|
|
// Count comparison ops for array: each add scans the current list
|
|
long arrayOps = 0;
|
|
for (int size = 0; size < P; size++) {
|
|
arrayOps += size; // scan from 0..size-1 before confirming absent
|
|
}
|
|
// Count comparison ops for map: O(1) per add (hash)
|
|
long mapOps = P; // one hash + compare per add
|
|
|
|
check(arrayOps > mapOps * 10,
|
|
"Array O(P^2) ops=" + arrayOps + " must be >> map O(P) ops=" + mapOps);
|
|
|
|
double ratio = (double) arrayOps / mapOps;
|
|
System.out.printf(" PASS test-3: op-count P=%d | array %,d ops | map %,d ops | %.1fx%n",
|
|
P, arrayOps, mapOps, ratio);
|
|
}
|
|
|
|
// Test 4: isParticipantPending lookup performance
|
|
// Use a large enough list to make timing differences measurable
|
|
{
|
|
int P = 2000;
|
|
int REPEATS = 500;
|
|
List<Map<String, String>> arrayPending = new ArrayList<>();
|
|
Map<String, Map<String, String>> mapPending = new LinkedHashMap<>();
|
|
|
|
for (int i = 0; i < P; i++) {
|
|
Map<String, String> p = participant("p" + i);
|
|
arrayPending.add(p);
|
|
mapPending.put(p.get("id"), p);
|
|
}
|
|
|
|
// warm-up
|
|
for (int i = 0; i < P; i++) {
|
|
isPendingArray(arrayPending, "p" + i);
|
|
isPendingMap(mapPending, "p" + i);
|
|
}
|
|
|
|
long arrayStart = System.nanoTime();
|
|
for (int r = 0; r < REPEATS; r++) {
|
|
for (int i = 0; i < P; i++) {
|
|
isPendingArray(arrayPending, "p" + i);
|
|
}
|
|
}
|
|
long arrayLookupTime = System.nanoTime() - arrayStart;
|
|
|
|
long mapStart = System.nanoTime();
|
|
for (int r = 0; r < REPEATS; r++) {
|
|
for (int i = 0; i < P; i++) {
|
|
isPendingMap(mapPending, "p" + i);
|
|
}
|
|
}
|
|
long mapLookupTime = System.nanoTime() - mapStart;
|
|
|
|
double ratio = (double) arrayLookupTime / mapLookupTime;
|
|
System.out.printf(" PASS test-4: lookup P=%d x%d | array %,d ns | map %,d ns | %.1fx%n",
|
|
P, REPEATS, arrayLookupTime, mapLookupTime, ratio);
|
|
check(mapLookupTime < arrayLookupTime, "Map lookup must be faster than array scan P=" + P);
|
|
}
|
|
|
|
System.out.println("ALL 4 PASS");
|
|
}
|
|
}
|