import java.util.*; /** * CWE-407 unit test for digikam-0001: Haar similarity search targetAlbums * QList::contains() called for every image in DB during similarity search. * O(N * A) where N = images, A = target albums → O(N) with QSet. * * Simulates fulfillsRestrictions called N times with targetAlbums.contains(). */ public class DigikamHaarTargetAlbumsTest { // --- DEFECTIVE: List contains in inner loop --- static int searchDefective(int numImages, List targetAlbums, int[] imageAlbums) { int matches = 0; for (int i = 0; i < numImages; i++) { int albumId = imageAlbums[i]; if (targetAlbums.isEmpty() || targetAlbums.contains(albumId)) { // O(A) matches++; } } return matches; } // --- PATCHED: Set contains in inner loop --- static int searchPatched(int numImages, Set targetAlbumsSet, int[] imageAlbums) { int matches = 0; for (int i = 0; i < numImages; i++) { int albumId = imageAlbums[i]; if (targetAlbumsSet.isEmpty() || targetAlbumsSet.contains(albumId)) { // O(1) matches++; } } return matches; } public static void main(String[] args) { int N = 50000; // images in database int A = 200; // target albums int totalAlbums = 500; // Build target albums list/set List targetAlbumsList = new ArrayList<>(); Set targetAlbumsSet = new HashSet<>(); for (int i = 0; i < A; i++) { targetAlbumsList.add(i); targetAlbumsSet.add(i); } // Build image album assignments Random rng = new Random(42); int[] imageAlbums = new int[N]; for (int i = 0; i < N; i++) { imageAlbums[i] = rng.nextInt(totalAlbums); } // Warm up for (int w = 0; w < 3; w++) { searchDefective(N, targetAlbumsList, imageAlbums); searchPatched(N, targetAlbumsSet, imageAlbums); } // Benchmark defective int iterations = 20; long startDef = System.nanoTime(); int resultDef = 0; for (int i = 0; i < iterations; i++) { resultDef = searchDefective(N, targetAlbumsList, imageAlbums); } long defectiveNs = System.nanoTime() - startDef; // Benchmark patched long startPat = System.nanoTime(); int resultPat = 0; for (int i = 0; i < iterations; i++) { resultPat = searchPatched(N, targetAlbumsSet, imageAlbums); } long patchedNs = System.nanoTime() - startPat; double ratio = (double) defectiveNs / patchedNs; System.out.println("digikam-0001: Haar searchDatabase targetAlbums.contains()"); System.out.println("N=" + N + " images, A=" + A + " target albums"); System.out.println("Defective matches: " + resultDef + " Patched matches: " + resultPat); System.out.printf("Defective: %.3f ms%n", defectiveNs / 1e6); System.out.printf("Patched: %.3f ms%n", patchedNs / 1e6); System.out.printf("Ratio: %.1fx%n", ratio); assert resultDef == resultPat : "Results must match!"; boolean pass = ratio > 2.0; System.out.println(pass ? "PASS" : "FAIL"); if (!pass) System.exit(1); } }