java-topology/defects/pitivi-0001/unit/PitiviMediaLibraryTest.java

148 lines
5.7 KiB
Java

package unit;
import java.util.*;
/**
* PitiviMediaLibraryTest — CWE-407 pitivi-0001
*
* Models MediaLibraryWidget.update_asset_thumbs() in pitivi/medialibrary.py lines 918-921:
* slow() = O(I * U): for item in store: if item.id in asset_uris (list)
* fast() = O(I + U): asset_uris_set = set(asset_uris); for item in store: if id in set
*
* Parameters: I=items in media library store, U=changed URIs from ThumbnailCache.update_caches().
* Assert: slowOps > fastOps * 5x at I=300, U=30.
*/
public class PitiviMediaLibraryTest {
static long slowOps;
static long fastOps;
/**
* Slow: O(I * U) — models: if item.asset.props.id in asset_uris (list)
* asset_uris is list[str] returned by ThumbnailCache.update_caches().
*/
static Set<String> updateThumbsSlow(List<String> storeIds, List<String> assetUris) {
slowOps = 0;
Set<String> disregarded = new LinkedHashSet<>();
for (String id : storeIds) {
for (String uri : assetUris) { // O(U) linear scan per store item
slowOps++;
if (id.equals(uri)) {
disregarded.add(id);
break;
}
}
}
return disregarded;
}
/**
* Fast: O(I + U) — models: asset_uris_set = set(asset_uris); if id in asset_uris_set
* Build set once: O(U). Lookup per item: O(1).
*/
static Set<String> updateThumbsFast(List<String> storeIds, List<String> assetUris) {
fastOps = 0;
Set<String> uriSet = new HashSet<>(assetUris);
fastOps += assetUris.size(); // set construction
Set<String> disregarded = new LinkedHashSet<>();
for (String id : storeIds) {
fastOps++; // O(1) hash lookup
if (uriSet.contains(id)) {
disregarded.add(id);
}
}
return disregarded;
}
public static void main(String[] args) {
int passed = 0;
int failed = 0;
// Test 1: correctness — same items disregarded
{
List<String> store = Arrays.asList(
"file:///home/user/video/clip1.mp4",
"file:///home/user/video/clip2.mp4",
"file:///home/user/video/clip3.mp4",
"file:///home/user/video/clip4.mp4"
);
List<String> changed = Arrays.asList(
"file:///home/user/video/clip1.mp4",
"file:///home/user/video/clip3.mp4"
);
Set<String> slow = updateThumbsSlow(store, changed);
Set<String> fast = updateThumbsFast(store, changed);
if (slow.equals(fast) && slow.size() == 2) {
System.out.println("PASS test1: both methods disregard same 2 items");
passed++;
} else {
System.out.println("FAIL test1: slow=" + slow + " fast=" + fast);
failed++;
}
}
// Test 2: op-count speedup at I=300, U=30
{
int I = 300;
int U = 30;
List<String> storeIds = new ArrayList<>();
for (int i = 0; i < I; i++) storeIds.add("file:///video/clip-" + i + ".mp4");
// U changed URIs, every 5th clip changed
List<String> assetUris = new ArrayList<>();
for (int i = 0; i < U; i++) assetUris.add("file:///video/clip-" + (i * 5) + ".mp4");
Set<String> slow = updateThumbsSlow(storeIds, assetUris);
long sOps = slowOps;
Set<String> fast = updateThumbsFast(storeIds, assetUris);
long fOps = fastOps;
if (!slow.equals(fast)) {
System.out.println("FAIL test2: results differ slow=" + slow.size() + " fast=" + fast.size());
failed++;
} else {
double ratio = (double) sOps / fOps;
if (ratio >= 5.0) {
System.out.printf("PASS test2: I=%d U=%d sOps=%d fOps=%d ratio=%.1fx%n",
I, U, sOps, fOps, ratio);
passed++;
} else {
System.out.printf("FAIL test2: ratio=%.1fx (want >=5x) sOps=%d fOps=%d%n",
ratio, sOps, fOps);
failed++;
}
}
}
// Test 3: no changed files (empty asset_uris)
{
List<String> store = Arrays.asList("file:///a.mp4", "file:///b.mp4");
Set<String> slow = updateThumbsSlow(store, Collections.emptyList());
Set<String> fast = updateThumbsFast(store, Collections.emptyList());
if (slow.isEmpty() && fast.isEmpty()) {
System.out.println("PASS test3: empty asset_uris handled correctly");
passed++;
} else {
System.out.println("FAIL test3: expected empty, got slow=" + slow + " fast=" + fast);
failed++;
}
}
// Test 4: all files changed
{
List<String> store = new ArrayList<>();
for (int i = 0; i < 10; i++) store.add("file:///clip-" + i + ".mp4");
Set<String> slow = updateThumbsSlow(store, new ArrayList<>(store));
Set<String> fast = updateThumbsFast(store, new ArrayList<>(store));
if (slow.equals(fast) && slow.size() == 10) {
System.out.println("PASS test4: all-changed case correct");
passed++;
} else {
System.out.println("FAIL test4: slow=" + slow.size() + " fast=" + fast.size());
failed++;
}
}
System.out.printf("%nResult: %d/%d tests passed%n", passed, passed + failed);
if (failed > 0) System.exit(1);
}
}