/** * CWE-407 unit test: mattermost-0001 * notification.go Push StringArray O(N²) vs map O(N) * * Simulates the notificationsForCRT.Push.Contains(id) pattern from * server/channels/app/notification.go (lines 541, 593). * * model.StringArray.Contains() delegates to slices.Contains() which is * O(P) where P = len(Push). Called once per user in mentionedUsersList * and once per user in allActivityPushUserIds, the total cost is O((N+M)×P). * * The fix builds a map[string]bool once (O(P)) and then all lookups are O(1), * reducing total cost to O(N+M+P). */ public class MattermostTest { /** Simulate StringArray.Contains: linear scan of a String array. */ static boolean stringArrayContains(String[] arr, String target) { for (String s : arr) { if (s.equals(target)) return true; } return false; } /** * Count total element comparisons made by the defective pattern: * for each id in userList, scan pushArray linearly. */ static long countListOps(String[] userList, String[] pushArray) { long ops = 0; for (String id : userList) { for (String p : pushArray) { ops++; if (p.equals(id)) break; // early-exit on match (worst case: no match) } } return ops; } /** * Count total operations for the fixed map pattern: * build the map once, then each lookup is O(1). * We count 1 op per map build entry + 1 op per lookup. */ static long countMapOps(String[] userList, String[] pushArray) { // Build phase: O(P) java.util.Map pushSet = new java.util.HashMap<>(pushArray.length * 2); long ops = 0; for (String id : pushArray) { pushSet.put(id, true); ops++; // one insert op per entry } // Lookup phase: O(1) per user for (String id : userList) { ops++; // one hash lookup pushSet.containsKey(id); } return ops; } static boolean testRatioExceeds10x() { int n = 1000; // mentioned users int p = 1000; // push CRT users (no overlap — worst case for scan) String[] userList = new String[n]; String[] pushArray = new String[p]; for (int i = 0; i < n; i++) userList[i] = "user-mentioned-" + i; for (int i = 0; i < p; i++) pushArray[i] = "user-crt-" + i; long listOps = countListOps(userList, pushArray); long mapOps = countMapOps(userList, pushArray); double ratio = (double) listOps / Math.max(mapOps, 1); System.out.printf(" N=%d P=%d: list_ops=%d map_ops=%d ratio=%.1fx%n", n, p, listOps, mapOps, ratio); if (ratio < 10.0) { System.out.printf(" FAIL: expected ratio >= 10x, got %.1fx%n", ratio); return false; } System.out.println(" PASS"); return true; } static boolean testListGrowsQuadratically() { // Double N and P: op count should 4x for list, 2x for map int n1 = 500, p1 = 500; int n2 = 1000, p2 = 1000; String[] u1 = new String[n1]; for (int i=0;i 3.0) { System.out.printf(" FAIL: map should grow ~2x when inputs double, got %.2fx%n", mapRatio); return false; } System.out.println(" PASS"); return true; } static boolean testMapAlwaysFewerOps() { int[] sizes = {100, 250, 500, 1000}; for (int n : sizes) { String[] u = new String[n]; for (int i=0;i= l) { System.out.printf(" FAIL: N=%d map_ops=%d >= list_ops=%d%n", n, m, l); return false; } } System.out.println(" map_ops < list_ops for N in {100, 250, 500, 1000} PASS"); return true; } public static void main(String[] args) { System.out.println("mattermost-0001 CWE-407 unit test — notification.go Push StringArray vs map"); System.out.println("=".repeat(75)); boolean[] results = { testRatioExceeds10x(), testListGrowsQuadratically(), testMapAlwaysFewerOps(), }; int passed = 0; for (boolean r : results) if (r) passed++; System.out.println(); if (passed == results.length) { System.out.println("ALL PASS (" + passed + "/" + results.length + ")"); } else { System.out.println("FAILED: " + (results.length - passed) + "/" + results.length + " tests failed"); System.exit(1); } } }