java-topology/defects/digikam/test/DigikamHaarTargetAlbumsTest.java

94 lines
3.3 KiB
Java

import java.util.*;
/**
* CWE-407 unit test for digikam-0001: Haar similarity search targetAlbums
* QList<int>::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<Integer> 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<Integer> 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<Integer> targetAlbumsList = new ArrayList<>();
Set<Integer> 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);
}
}