package unit; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Love2dJoystickLookupTest — CWE-407 love2d-0001 * * Models JoystickModule::getJoystickFromID(int instanceid): * slow() = O(n) linear scan of activeSticks vector (current defect) * fast() = O(1) HashMap lookup keyed on instanceID (patch) * * Assert: slowOps > fastOps * Nx at N=64 joysticks. */ public class Love2dJoystickLookupTest { static class Joystick { final int instanceID; Joystick(int id) { this.instanceID = id; } int getInstanceID() { return instanceID; } } static long slowOps; static long fastOps; /** * slow: O(n) linear scan — models love2d getJoystickFromID defect. */ static Joystick getJoystickFromIDSlow(List activeSticks, int instanceid) { for (Joystick stick : activeSticks) { slowOps++; if (stick.getInstanceID() == instanceid) return stick; } return null; } /** * fast: O(1) hash map lookup — models patched getJoystickFromID. */ static Joystick getJoystickFromIDFast(Map sticksById, int instanceid) { fastOps++; return sticksById.get(instanceid); } public static void main(String[] args) { final int N = 64; // number of active joysticks final int NX = 5; // minimum required speedup factor final int EVENTS = 5000; // SDL events dispatched per measurement // Build joystick list (instanceIDs 1..N) List activeSticks = new ArrayList<>(); Map sticksById = new HashMap<>(); for (int i = 1; i <= N; i++) { Joystick j = new Joystick(i); activeSticks.add(j); sticksById.put(i, j); } // Worst-case: always look up the last joystick (forces full scan for slow) int targetID = N; slowOps = 0; fastOps = 0; // Each event calls getJoystickFromID once (7 event types in love2d, simulate 1) for (int e = 0; e < EVENTS; e++) { getJoystickFromIDSlow(activeSticks, targetID); } long totalSlowOps = slowOps; for (int e = 0; e < EVENTS; e++) { getJoystickFromIDFast(sticksById, targetID); } long totalFastOps = fastOps; // Correctness check Joystick slowResult = getJoystickFromIDSlow(activeSticks, targetID); Joystick fastResult = getJoystickFromIDFast(sticksById, targetID); boolean correctnessOk = (slowResult != null && fastResult != null && slowResult.getInstanceID() == fastResult.getInstanceID()); boolean speedupOk = totalSlowOps > totalFastOps * NX; System.out.printf("N=%d joysticks, target instanceID=%d, EVENTS=%d%n", N, targetID, EVENTS); System.out.printf("slow (linear) ops: %d%n", totalSlowOps); System.out.printf("fast (hashmap) ops: %d%n", totalFastOps); System.out.printf("speedup ratio: %.1fx (required >%dx)%n", (double) totalSlowOps / totalFastOps, NX); int passed = 0, total = 2; if (correctnessOk) { System.out.println("1/2 PASS correctness: both return same joystick"); passed++; } else { System.out.printf("1/2 FAIL correctness: slow=%s fast=%s%n", slowResult == null ? "null" : slowResult.getInstanceID(), fastResult == null ? "null" : fastResult.getInstanceID()); } if (speedupOk) { System.out.printf("2/2 PASS speedup: %d > %d * %d%n", totalSlowOps, totalFastOps, NX); passed++; } else { System.out.printf("2/2 FAIL speedup: %d not > %d * %d%n", totalSlowOps, totalFastOps, NX); } System.out.printf("%d/%d PASS%n", passed, total); if (passed < total) System.exit(1); } }