148 lines
5.7 KiB
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);
|
|
}
|
|
}
|