java-topology/defects/suitecrm/test/SuiteCRMCWE407Test.java

204 lines
6.9 KiB
Java

import java.util.*;
/**
* CWE-407 unit tests for SuiteCRM defects.
*
* suitecrm-0001: InboundEmail.php in_array($overview->imap_uid, $uids)
* — O(I*U) email cache UID membership check
* suitecrm-0002: jjwg_Maps/controller.php in_array($display['id'], $records)
* — O(D*R) map marker record filter
* suitecrm-0003: Email.php in_array(trim($match[0]), $knownEmails)
* — O(N^2) email dedup accumulator
*/
public class SuiteCRMCWE407Test {
// ---- suitecrm-0001: InboundEmail UID membership ----
/** Unpatched: in_array on $uids array — O(I*U) */
static int inboundEmailUnpatched(List<String> insertUids, List<String> cachedUids) {
int updateCount = 0;
for (String uid : insertUids) {
if (cachedUids.contains(uid)) { // O(U) per email
updateCount++;
}
}
return updateCount;
}
/** Patched: hash set for O(1) lookup — O(I+U) */
static int inboundEmailPatched(List<String> insertUids, List<String> cachedUids) {
Set<String> uidSet = new HashSet<>(cachedUids); // O(U) once
int updateCount = 0;
for (String uid : insertUids) {
if (uidSet.contains(uid)) { // O(1) per email
updateCount++;
}
}
return updateCount;
}
// ---- suitecrm-0002: jjwg_Maps record filter ----
/** Unpatched: in_array on $records — O(D*R) */
static int mapMarkersUnpatched(List<String> displayIds, List<String> records) {
int markers = 0;
for (String id : displayIds) {
if (records.contains(id)) { // O(R) per display
markers++;
}
}
return markers;
}
/** Patched: array_flip for O(1) lookup — O(D+R) */
static int mapMarkersPatched(List<String> displayIds, List<String> records) {
Set<String> recordsSet = new HashSet<>(records); // O(R) once
int markers = 0;
for (String id : displayIds) {
if (recordsSet.contains(id)) { // O(1) per display
markers++;
}
}
return markers;
}
// ---- suitecrm-0003: Email knownEmails dedup ----
/** Unpatched: in_array on growing knownEmails — O(N^2) */
static int emailDedupUnpatched(List<String> addresses) {
List<String> knownEmails = new ArrayList<>();
int unique = 0;
for (String addr : addresses) {
if (!knownEmails.contains(addr)) { // O(N) scan
knownEmails.add(addr);
unique++;
}
}
return unique;
}
/** Patched: hash set for O(1) lookup — O(N) total */
static int emailDedupPatched(List<String> addresses) {
Set<String> knownEmailsSet = new HashSet<>();
int unique = 0;
for (String addr : addresses) {
if (!knownEmailsSet.contains(addr)) { // O(1) lookup
knownEmailsSet.add(addr);
unique++;
}
}
return unique;
}
// ---- Test harness ----
static void testSuiteCRM0001() {
System.out.println("=== suitecrm-0001: InboundEmail UID membership ===");
int U = 10000; // cached UIDs in mailbox
int I = 500; // new emails to insert
List<String> cachedUids = new ArrayList<>(U);
for (int i = 0; i < U; i++) {
cachedUids.add("uid_" + i);
}
List<String> insertUids = new ArrayList<>(I);
for (int i = U - I / 2; i < U + I / 2; i++) {
insertUids.add("uid_" + i);
}
// Warmup
inboundEmailPatched(insertUids, cachedUids);
long t0 = System.nanoTime();
int r1 = inboundEmailUnpatched(insertUids, cachedUids);
long unpatched = System.nanoTime() - t0;
t0 = System.nanoTime();
int r2 = inboundEmailPatched(insertUids, cachedUids);
long patched = System.nanoTime() - t0;
assert r1 == r2 : "Result mismatch";
assert r1 == I / 2 : "Expected " + (I / 2) + " updates, got " + r1;
double ratio = (double) unpatched / patched;
System.out.printf(" U=%d I=%d unpatched=%dms patched=%dms ratio=%.1fx%n",
U, I, unpatched / 1_000_000, patched / 1_000_000, ratio);
assert ratio > 5.0 : "Expected >5x ratio, got " + ratio;
System.out.println(" PASS");
}
static void testSuiteCRM0002() {
System.out.println("=== suitecrm-0002: jjwg_Maps record filter ===");
int D = 5000; // display results
int R = 3000; // selected records
List<String> displayIds = new ArrayList<>(D);
for (int i = 0; i < D; i++) {
displayIds.add("id_" + i);
}
List<String> records = new ArrayList<>(R);
for (int i = 0; i < R; i++) {
records.add("id_" + (i * 2)); // even IDs only
}
// Warmup
mapMarkersPatched(displayIds, records);
long t0 = System.nanoTime();
int r1 = mapMarkersUnpatched(displayIds, records);
long unpatched = System.nanoTime() - t0;
t0 = System.nanoTime();
int r2 = mapMarkersPatched(displayIds, records);
long patched = System.nanoTime() - t0;
assert r1 == r2 : "Result mismatch";
double ratio = (double) unpatched / patched;
System.out.printf(" D=%d R=%d unpatched=%dms patched=%dms ratio=%.1fx%n",
D, R, unpatched / 1_000_000, patched / 1_000_000, ratio);
assert ratio > 5.0 : "Expected >5x ratio, got " + ratio;
System.out.println(" PASS");
}
static void testSuiteCRM0003() {
System.out.println("=== suitecrm-0003: Email knownEmails dedup ===");
int N = 10000; // email addresses in mass send
List<String> addresses = new ArrayList<>(N);
for (int i = 0; i < N; i++) {
addresses.add("user" + i + "@example.com");
}
// Add duplicates
for (int i = 0; i < N / 5; i++) {
addresses.add("user" + i + "@example.com");
}
// Warmup
emailDedupPatched(addresses);
long t0 = System.nanoTime();
int r1 = emailDedupUnpatched(addresses);
long unpatched = System.nanoTime() - t0;
t0 = System.nanoTime();
int r2 = emailDedupPatched(addresses);
long patched = System.nanoTime() - t0;
assert r1 == r2 : "Result mismatch";
assert r1 == N : "Expected " + N + " unique, got " + r1;
double ratio = (double) unpatched / patched;
System.out.printf(" N=%d unpatched=%dms patched=%dms ratio=%.1fx%n",
N, unpatched / 1_000_000, patched / 1_000_000, ratio);
assert ratio > 5.0 : "Expected >5x ratio, got " + ratio;
System.out.println(" PASS");
}
public static void main(String[] args) {
testSuiteCRM0001();
testSuiteCRM0002();
testSuiteCRM0003();
System.out.println("\nAll 3 SuiteCRM CWE-407 tests PASSED.");
}
}