element-web-0003: TextForEvent.tsx textForCanonicalAliasEvent alt_aliases .filter(x => !arr.includes(x)) O(A*B) MEDIUM 19.5x — fix: Set.has() element-web-0004: utils/arrays.ts arrayDiff + arrayIntersection .filter(i => !arr.includes(i)) O(A*B) MEDIUM 18x — fix: Set.has() Used by 15+ callsites: room-list, notifications, spaces, beacons, maps conduit-0001: server_server.rs get_missing_events_route earliest_events.contains() (Vec) in growing BFS loop O(Q*E) MEDIUM-HIGH 7.4x Federation endpoint — remote server controls input size matrix-rust-sdk: could not clone (GitHub HTTPS unreachable)
322 lines
12 KiB
Java
322 lines
12 KiB
Java
import java.util.*;
|
||
|
||
/**
|
||
* CWE-407 unit tests for element-web (Matrix client) defects.
|
||
*
|
||
* element-web-0001: TextForEvent.tsx textForPowerEvent()
|
||
* users array + indexOf for dedup -> O(U^2)
|
||
* Fix: Set-based dedup -> O(U)
|
||
*
|
||
* element-web-0002: TextForEvent.tsx textForPinnedEvent()
|
||
* previouslyPinned.indexOf inside filter -> O(P*Q)
|
||
* Fix: Set.has() inside filter -> O(P+Q)
|
||
*
|
||
* element-web-0003: TextForEvent.tsx textForCanonicalAliasEvent()
|
||
* oldAltAliases.filter(a => !newAltAliases.includes(a)) -> O(A*B)
|
||
* Fix: Set.has() inside filter -> O(A+B)
|
||
*
|
||
* element-web-0004: utils/arrays.ts arrayDiff() and arrayIntersection()
|
||
* b.filter(i => !a.includes(i)) -> O(A*B)
|
||
* Fix: new Set(a) then setA.has() -> O(A+B)
|
||
*/
|
||
public class ElementWebTest {
|
||
|
||
// --- element-web-0001: user dedup ---
|
||
|
||
static List<String> deduplicateUsersArray(String[] current, String[] previous) {
|
||
List<String> users = new ArrayList<>();
|
||
for (String u : current) {
|
||
if (!users.contains(u)) users.add(u); // O(U) per user
|
||
}
|
||
for (String u : previous) {
|
||
if (!users.contains(u)) users.add(u);
|
||
}
|
||
return users;
|
||
}
|
||
|
||
static List<String> deduplicateUsersSet(String[] current, String[] previous) {
|
||
Set<String> seen = new LinkedHashSet<>(); // preserves insertion order
|
||
for (String u : current) seen.add(u);
|
||
for (String u : previous) seen.add(u);
|
||
return new ArrayList<>(seen);
|
||
}
|
||
|
||
static void testElementWeb0001() throws Exception {
|
||
int U = 1000;
|
||
String[] current = new String[U];
|
||
String[] previous = new String[U];
|
||
for (int i = 0; i < U; i++) {
|
||
current[i] = "@user" + i + ":matrix.org";
|
||
previous[i] = "@user" + (i + U / 2) + ":matrix.org"; // partial overlap
|
||
}
|
||
|
||
// correctness
|
||
List<String> rArr = deduplicateUsersArray(current, previous);
|
||
List<String> rSet = deduplicateUsersSet(current, previous);
|
||
Collections.sort(rArr);
|
||
Collections.sort(rSet);
|
||
assert rArr.equals(rSet) : "array and set must produce same user list";
|
||
|
||
// performance
|
||
long t0 = System.nanoTime();
|
||
for (int r = 0; r < 200; r++) deduplicateUsersArray(current, previous);
|
||
long tArr = System.nanoTime() - t0;
|
||
|
||
t0 = System.nanoTime();
|
||
for (int r = 0; r < 200; r++) deduplicateUsersSet(current, previous);
|
||
long tSet = System.nanoTime() - t0;
|
||
|
||
double ratio = (double) tArr / tSet;
|
||
System.out.printf("element-web-0001: array=%.3fs set=%.3fs ratio=%.1f×%n",
|
||
tArr / 1e9, tSet / 1e9, ratio);
|
||
assert ratio > 10 : "Expected >10x speedup, got " + ratio;
|
||
System.out.println("PASS element-web-0001");
|
||
}
|
||
|
||
// --- element-web-0002: pinned messages filter ---
|
||
|
||
static List<String> newlyPinnedIndexOf(List<String> pinned, List<String> previouslyPinned) {
|
||
List<String> result = new ArrayList<>();
|
||
for (String item : pinned) {
|
||
if (!previouslyPinned.contains(item)) result.add(item); // O(P) per item
|
||
}
|
||
return result;
|
||
}
|
||
|
||
static List<String> newlyPinnedSet(List<String> pinned, List<String> previouslyPinned) {
|
||
Set<String> prevSet = new HashSet<>(previouslyPinned); // O(1) lookup
|
||
List<String> result = new ArrayList<>();
|
||
for (String item : pinned) {
|
||
if (!prevSet.contains(item)) result.add(item);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
static void testElementWeb0002() throws Exception {
|
||
int P = 1000;
|
||
List<String> pinned = new ArrayList<>();
|
||
List<String> previouslyPinned = new ArrayList<>();
|
||
for (int i = 0; i < P; i++) {
|
||
pinned.add("$event" + i);
|
||
previouslyPinned.add("$event" + (i + P / 2));
|
||
}
|
||
|
||
// correctness
|
||
List<String> r1 = newlyPinnedIndexOf(pinned, previouslyPinned);
|
||
List<String> r2 = newlyPinnedSet(pinned, previouslyPinned);
|
||
Collections.sort(r1);
|
||
Collections.sort(r2);
|
||
assert r1.equals(r2) : "indexOf and set paths must agree";
|
||
|
||
// performance
|
||
long t0 = System.nanoTime();
|
||
for (int r = 0; r < 200; r++) newlyPinnedIndexOf(pinned, previouslyPinned);
|
||
long tIndexOf = System.nanoTime() - t0;
|
||
|
||
t0 = System.nanoTime();
|
||
for (int r = 0; r < 200; r++) newlyPinnedSet(pinned, previouslyPinned);
|
||
long tSet = System.nanoTime() - t0;
|
||
|
||
double ratio = (double) tIndexOf / tSet;
|
||
System.out.printf("element-web-0002: indexOf=%.3fs set=%.3fs ratio=%.1f×%n",
|
||
tIndexOf / 1e9, tSet / 1e9, ratio);
|
||
assert ratio > 5 : "Expected >5x speedup, got " + ratio;
|
||
System.out.println("PASS element-web-0002");
|
||
}
|
||
|
||
// --- element-web-0003: canonical alias alt_aliases diff ---
|
||
|
||
static List<String> removedAliasesIncludes(List<String> oldAlt, List<String> newAlt) {
|
||
List<String> removed = new ArrayList<>();
|
||
for (String alias : oldAlt) {
|
||
if (!newAlt.contains(alias)) removed.add(alias); // O(N) per alias
|
||
}
|
||
return removed;
|
||
}
|
||
|
||
static List<String> addedAliasesIncludes(List<String> oldAlt, List<String> newAlt) {
|
||
List<String> added = new ArrayList<>();
|
||
for (String alias : newAlt) {
|
||
if (!oldAlt.contains(alias)) added.add(alias);
|
||
}
|
||
return added;
|
||
}
|
||
|
||
static List<String> removedAliasesSet(List<String> oldAlt, List<String> newAlt) {
|
||
Set<String> newSet = new HashSet<>(newAlt);
|
||
List<String> removed = new ArrayList<>();
|
||
for (String alias : oldAlt) {
|
||
if (!newSet.contains(alias)) removed.add(alias); // O(1) per alias
|
||
}
|
||
return removed;
|
||
}
|
||
|
||
static List<String> addedAliasesSet(List<String> oldAlt, List<String> newAlt) {
|
||
Set<String> oldSet = new HashSet<>(oldAlt);
|
||
List<String> added = new ArrayList<>();
|
||
for (String alias : newAlt) {
|
||
if (!oldSet.contains(alias)) added.add(alias);
|
||
}
|
||
return added;
|
||
}
|
||
|
||
static void testElementWeb0003() throws Exception {
|
||
int A = 1000;
|
||
List<String> oldAlt = new ArrayList<>();
|
||
List<String> newAlt = new ArrayList<>();
|
||
for (int i = 0; i < A; i++) {
|
||
oldAlt.add("#alias" + i + ":matrix.org");
|
||
newAlt.add("#alias" + (i + A / 2) + ":matrix.org");
|
||
}
|
||
|
||
// correctness
|
||
List<String> removedArr = removedAliasesIncludes(oldAlt, newAlt);
|
||
List<String> removedSet = removedAliasesSet(oldAlt, newAlt);
|
||
Collections.sort(removedArr);
|
||
Collections.sort(removedSet);
|
||
assert removedArr.equals(removedSet) : "removed aliases must agree";
|
||
|
||
List<String> addedArr = addedAliasesIncludes(oldAlt, newAlt);
|
||
List<String> addedSetR = addedAliasesSet(oldAlt, newAlt);
|
||
Collections.sort(addedArr);
|
||
Collections.sort(addedSetR);
|
||
assert addedArr.equals(addedSetR) : "added aliases must agree";
|
||
|
||
// performance
|
||
long t0 = System.nanoTime();
|
||
for (int r = 0; r < 200; r++) {
|
||
removedAliasesIncludes(oldAlt, newAlt);
|
||
addedAliasesIncludes(oldAlt, newAlt);
|
||
}
|
||
long tArr = System.nanoTime() - t0;
|
||
|
||
t0 = System.nanoTime();
|
||
for (int r = 0; r < 200; r++) {
|
||
removedAliasesSet(oldAlt, newAlt);
|
||
addedAliasesSet(oldAlt, newAlt);
|
||
}
|
||
long tSet = System.nanoTime() - t0;
|
||
|
||
double ratio = (double) tArr / tSet;
|
||
System.out.printf("element-web-0003: includes=%.3fs set=%.3fs ratio=%.1f×%n",
|
||
tArr / 1e9, tSet / 1e9, ratio);
|
||
assert ratio > 5 : "Expected >5x speedup, got " + ratio;
|
||
System.out.println("PASS element-web-0003");
|
||
}
|
||
|
||
// --- element-web-0004: arrayDiff + arrayIntersection ---
|
||
|
||
static Map<String, List<String>> arrayDiffIncludes(List<String> a, List<String> b) {
|
||
List<String> added = new ArrayList<>();
|
||
for (String i : b) {
|
||
if (!a.contains(i)) added.add(i); // O(A) per element
|
||
}
|
||
List<String> removed = new ArrayList<>();
|
||
for (String i : a) {
|
||
if (!b.contains(i)) removed.add(i); // O(B) per element
|
||
}
|
||
Map<String, List<String>> result = new HashMap<>();
|
||
result.put("added", added);
|
||
result.put("removed", removed);
|
||
return result;
|
||
}
|
||
|
||
static Map<String, List<String>> arrayDiffSet(List<String> a, List<String> b) {
|
||
Set<String> setA = new HashSet<>(a);
|
||
Set<String> setB = new HashSet<>(b);
|
||
List<String> added = new ArrayList<>();
|
||
for (String i : b) {
|
||
if (!setA.contains(i)) added.add(i); // O(1) per element
|
||
}
|
||
List<String> removed = new ArrayList<>();
|
||
for (String i : a) {
|
||
if (!setB.contains(i)) removed.add(i);
|
||
}
|
||
Map<String, List<String>> result = new HashMap<>();
|
||
result.put("added", added);
|
||
result.put("removed", removed);
|
||
return result;
|
||
}
|
||
|
||
static List<String> arrayIntersectionIncludes(List<String> a, List<String> b) {
|
||
List<String> result = new ArrayList<>();
|
||
for (String i : a) {
|
||
if (b.contains(i)) result.add(i); // O(B) per element
|
||
}
|
||
return result;
|
||
}
|
||
|
||
static List<String> arrayIntersectionSet(List<String> a, List<String> b) {
|
||
Set<String> setB = new HashSet<>(b);
|
||
List<String> result = new ArrayList<>();
|
||
for (String i : a) {
|
||
if (setB.contains(i)) result.add(i); // O(1) per element
|
||
}
|
||
return result;
|
||
}
|
||
|
||
static void testElementWeb0004() throws Exception {
|
||
int N = 1000;
|
||
List<String> a = new ArrayList<>();
|
||
List<String> b = new ArrayList<>();
|
||
for (int i = 0; i < N; i++) {
|
||
a.add("room_" + i);
|
||
b.add("room_" + (i + N / 2));
|
||
}
|
||
|
||
// correctness: arrayDiff
|
||
Map<String, List<String>> d1 = arrayDiffIncludes(a, b);
|
||
Map<String, List<String>> d2 = arrayDiffSet(a, b);
|
||
List<String> added1 = new ArrayList<>(d1.get("added")); Collections.sort(added1);
|
||
List<String> added2 = new ArrayList<>(d2.get("added")); Collections.sort(added2);
|
||
assert added1.equals(added2) : "arrayDiff added must agree";
|
||
List<String> rem1 = new ArrayList<>(d1.get("removed")); Collections.sort(rem1);
|
||
List<String> rem2 = new ArrayList<>(d2.get("removed")); Collections.sort(rem2);
|
||
assert rem1.equals(rem2) : "arrayDiff removed must agree";
|
||
|
||
// correctness: arrayIntersection
|
||
List<String> i1 = arrayIntersectionIncludes(a, b);
|
||
List<String> i2 = arrayIntersectionSet(a, b);
|
||
Collections.sort(i1);
|
||
Collections.sort(i2);
|
||
assert i1.equals(i2) : "arrayIntersection must agree";
|
||
|
||
// performance: arrayDiff
|
||
long t0 = System.nanoTime();
|
||
for (int r = 0; r < 200; r++) arrayDiffIncludes(a, b);
|
||
long tInc = System.nanoTime() - t0;
|
||
|
||
t0 = System.nanoTime();
|
||
for (int r = 0; r < 200; r++) arrayDiffSet(a, b);
|
||
long tSet = System.nanoTime() - t0;
|
||
|
||
double ratio = (double) tInc / tSet;
|
||
System.out.printf("element-web-0004-diff: includes=%.3fs set=%.3fs ratio=%.1f×%n",
|
||
tInc / 1e9, tSet / 1e9, ratio);
|
||
assert ratio > 5 : "Expected >5x speedup for arrayDiff, got " + ratio;
|
||
|
||
// performance: arrayIntersection
|
||
t0 = System.nanoTime();
|
||
for (int r = 0; r < 200; r++) arrayIntersectionIncludes(a, b);
|
||
tInc = System.nanoTime() - t0;
|
||
|
||
t0 = System.nanoTime();
|
||
for (int r = 0; r < 200; r++) arrayIntersectionSet(a, b);
|
||
tSet = System.nanoTime() - t0;
|
||
|
||
double ratio2 = (double) tInc / tSet;
|
||
System.out.printf("element-web-0004-intersect: includes=%.3fs set=%.3fs ratio=%.1f×%n",
|
||
tInc / 1e9, tSet / 1e9, ratio2);
|
||
assert ratio2 > 5 : "Expected >5x speedup for arrayIntersection, got " + ratio2;
|
||
|
||
System.out.println("PASS element-web-0004");
|
||
}
|
||
|
||
public static void main(String[] args) throws Exception {
|
||
testElementWeb0001();
|
||
testElementWeb0002();
|
||
testElementWeb0003();
|
||
testElementWeb0004();
|
||
System.out.println("ALL PASS");
|
||
}
|
||
}
|