VS Code (4 defects): - vscode-0001: extensionGalleryService uuid dedup O(N×M) MEDIUM 100x - vscode-0002: abstractExtensionManagementService deps O(D²) MEDIUM 49x - vscode-0003: userDataSync merge compare() O(N×M) across 8 files MEDIUM 250x - vscode-0004: configurationModels override identifiers O(N×M) LOW-MEDIUM 18x Zed (2 defects): - zed-0001: lsp_store LSP edit dedup Vec::contains O(E²) MEDIUM 49x - zed-0002: extension_builder manifest dedup Vec::contains O(N²) LOW 24x 6/6 unit tests PASS
226 lines
8.8 KiB
Java
226 lines
8.8 KiB
Java
import java.util.*;
|
||
|
||
/**
|
||
* CWE-407 unit tests for VS Code defects.
|
||
*
|
||
* vscode-0001: extensionGalleryService getExtensions uuid dedup O(N×M)
|
||
* vscode-0002: abstractExtensionManagementService getAllDepsAndPacks O(D²)
|
||
* vscode-0003: userDataSync merge compare() O(N×M) array includes (8 sites)
|
||
* vscode-0004: configurationModels override identifiers O(N×M)
|
||
*/
|
||
public class VscodeTest {
|
||
|
||
// ---------------------------------------------------------------
|
||
// vscode-0001: gallery uuid includes O(N×M)
|
||
// ---------------------------------------------------------------
|
||
|
||
/** BEFORE: uuids array with Array.includes() — O(N×M) */
|
||
static int galleryUuidBefore(List<String> extensionUuids, List<String> resultUuids) {
|
||
int ops = 0;
|
||
// const uuids = result.map(r => r.identifier.uuid); // array
|
||
for (String uuid : extensionUuids) {
|
||
// uuids.includes(e.uuid)
|
||
for (String r : resultUuids) {
|
||
ops++;
|
||
if (r.equals(uuid)) break;
|
||
}
|
||
}
|
||
return ops;
|
||
}
|
||
|
||
/** AFTER: uuids Set with Set.has() — O(N+M) */
|
||
static int galleryUuidAfter(List<String> extensionUuids, List<String> resultUuids) {
|
||
int ops = 0;
|
||
Set<String> uuidSet = new HashSet<>(resultUuids);
|
||
ops += resultUuids.size(); // set construction
|
||
for (String uuid : extensionUuids) {
|
||
ops++; // set lookup O(1)
|
||
uuidSet.contains(uuid);
|
||
}
|
||
return ops;
|
||
}
|
||
|
||
// ---------------------------------------------------------------
|
||
// vscode-0002: getAllDepsAndPacks includes O(D²)
|
||
// ---------------------------------------------------------------
|
||
|
||
/** BEFORE: allDepsOrPacks.includes() in recursive traversal — O(D²) */
|
||
static int depsScanBefore(List<String> depChain) {
|
||
int ops = 0;
|
||
List<String> allDeps = new ArrayList<>();
|
||
for (String id : depChain) {
|
||
// allDepsOrPacks.includes(id.toLowerCase())
|
||
boolean found = false;
|
||
for (String existing : allDeps) {
|
||
ops++;
|
||
if (existing.equals(id)) { found = true; break; }
|
||
}
|
||
if (!found) allDeps.add(id);
|
||
}
|
||
return ops;
|
||
}
|
||
|
||
/** AFTER: Set for seen-check — O(D) */
|
||
static int depsScanAfter(List<String> depChain) {
|
||
int ops = 0;
|
||
Set<String> seen = new HashSet<>();
|
||
List<String> allDeps = new ArrayList<>();
|
||
for (String id : depChain) {
|
||
ops++; // set lookup
|
||
if (!seen.contains(id)) {
|
||
seen.add(id);
|
||
allDeps.add(id);
|
||
}
|
||
}
|
||
return ops;
|
||
}
|
||
|
||
// ---------------------------------------------------------------
|
||
// vscode-0003: sync merge compare() — filter+includes O(N×M)
|
||
// ---------------------------------------------------------------
|
||
|
||
/** BEFORE: fromKeys.filter(key => !toKeys.includes(key)) — O(N×M) */
|
||
static int mergeCompareBefore(List<String> fromKeys, List<String> toKeys) {
|
||
int ops = 0;
|
||
// added = toKeys.filter(key => !fromKeys.includes(key))
|
||
for (String key : toKeys) {
|
||
for (String fk : fromKeys) {
|
||
ops++;
|
||
if (fk.equals(key)) break;
|
||
}
|
||
}
|
||
// removed = fromKeys.filter(key => !toKeys.includes(key))
|
||
for (String key : fromKeys) {
|
||
for (String tk : toKeys) {
|
||
ops++;
|
||
if (tk.equals(key)) break;
|
||
}
|
||
}
|
||
return ops;
|
||
}
|
||
|
||
/** AFTER: Set lookup — O(N+M) */
|
||
static int mergeCompareAfter(List<String> fromKeys, List<String> toKeys) {
|
||
int ops = 0;
|
||
Set<String> fromSet = new HashSet<>(fromKeys);
|
||
ops += fromKeys.size();
|
||
Set<String> toSet = new HashSet<>(toKeys);
|
||
ops += toKeys.size();
|
||
for (String key : toKeys) { ops++; fromSet.contains(key); }
|
||
for (String key : fromKeys) { ops++; toSet.contains(key); }
|
||
return ops;
|
||
}
|
||
|
||
// ---------------------------------------------------------------
|
||
// vscode-0004: config override identifiers — filter+includes O(N×M)
|
||
// ---------------------------------------------------------------
|
||
|
||
/** BEFORE: overrideIdentifiers.filter + includes — O(N²) */
|
||
static int configOverrideBefore(List<String> fromIds, List<String> toIds) {
|
||
int ops = 0;
|
||
// addedOverrideIdentifiers = toIds.filter(key => !fromIds.includes(key))
|
||
for (String key : toIds) {
|
||
for (String fk : fromIds) { ops++; if (fk.equals(key)) break; }
|
||
}
|
||
// removedOverrideIdentifiers = fromIds.filter(key => !toIds.includes(key))
|
||
for (String key : fromIds) {
|
||
for (String tk : toIds) { ops++; if (tk.equals(key)) break; }
|
||
}
|
||
// inner loop: toOverrideIdentifiers.includes(identifier)
|
||
for (String id : fromIds) {
|
||
for (String tk : toIds) { ops++; if (tk.equals(id)) break; }
|
||
}
|
||
return ops;
|
||
}
|
||
|
||
/** AFTER: Set lookups — O(N+M) */
|
||
static int configOverrideAfter(List<String> fromIds, List<String> toIds) {
|
||
int ops = 0;
|
||
Set<String> fromSet = new HashSet<>(fromIds);
|
||
ops += fromIds.size();
|
||
Set<String> toSet = new HashSet<>(toIds);
|
||
ops += toIds.size();
|
||
for (String key : toIds) { ops++; fromSet.contains(key); }
|
||
for (String key : fromIds) { ops++; toSet.contains(key); }
|
||
for (String id : fromIds) { ops++; toSet.contains(id); }
|
||
return ops;
|
||
}
|
||
|
||
// ---------------------------------------------------------------
|
||
// Main: run all tests
|
||
// ---------------------------------------------------------------
|
||
public static void main(String[] args) {
|
||
int pass = 0, fail = 0;
|
||
|
||
// --- vscode-0001: gallery uuid ---
|
||
{
|
||
int N = 200;
|
||
List<String> extUuids = new ArrayList<>();
|
||
List<String> resultUuids = new ArrayList<>();
|
||
for (int i = 0; i < N; i++) {
|
||
extUuids.add("ext-" + i);
|
||
resultUuids.add("res-" + i); // disjoint = worst case
|
||
}
|
||
int before = galleryUuidBefore(extUuids, resultUuids);
|
||
int after = galleryUuidAfter(extUuids, resultUuids);
|
||
double ratio = (double) before / after;
|
||
boolean ok = ratio > 10;
|
||
System.out.printf("vscode-0001 gallery-uuid N=%d before=%d after=%d ratio=%.1fx %s%n",
|
||
N, before, after, ratio, ok ? "PASS" : "FAIL");
|
||
if (ok) pass++; else fail++;
|
||
}
|
||
|
||
// --- vscode-0002: deps scan ---
|
||
{
|
||
int D = 100;
|
||
List<String> deps = new ArrayList<>();
|
||
for (int i = 0; i < D; i++) deps.add("dep-" + i);
|
||
int before = depsScanBefore(deps);
|
||
int after = depsScanAfter(deps);
|
||
double ratio = (double) before / after;
|
||
boolean ok = ratio > 10;
|
||
System.out.printf("vscode-0002 deps-scan D=%d before=%d after=%d ratio=%.1fx %s%n",
|
||
D, before, after, ratio, ok ? "PASS" : "FAIL");
|
||
if (ok) pass++; else fail++;
|
||
}
|
||
|
||
// --- vscode-0003: sync merge compare ---
|
||
{
|
||
int N = 500;
|
||
List<String> fromKeys = new ArrayList<>();
|
||
List<String> toKeys = new ArrayList<>();
|
||
for (int i = 0; i < N; i++) {
|
||
fromKeys.add("setting-" + i);
|
||
toKeys.add("setting-" + (i + N)); // disjoint = worst case
|
||
}
|
||
int before = mergeCompareBefore(fromKeys, toKeys);
|
||
int after = mergeCompareAfter(fromKeys, toKeys);
|
||
double ratio = (double) before / after;
|
||
boolean ok = ratio > 50;
|
||
System.out.printf("vscode-0003 sync-merge-compare N=%d before=%d after=%d ratio=%.1fx %s%n",
|
||
N, before, after, ratio, ok ? "PASS" : "FAIL");
|
||
if (ok) pass++; else fail++;
|
||
}
|
||
|
||
// --- vscode-0004: config override identifiers ---
|
||
{
|
||
int N = 30;
|
||
List<String> fromIds = new ArrayList<>();
|
||
List<String> toIds = new ArrayList<>();
|
||
for (int i = 0; i < N; i++) {
|
||
fromIds.add("[lang-" + i + "]");
|
||
toIds.add("[lang-" + (i + N) + "]"); // disjoint
|
||
}
|
||
int before = configOverrideBefore(fromIds, toIds);
|
||
int after = configOverrideAfter(fromIds, toIds);
|
||
double ratio = (double) before / after;
|
||
boolean ok = ratio > 5;
|
||
System.out.printf("vscode-0004 config-overrides N=%d before=%d after=%d ratio=%.1fx %s%n",
|
||
N, before, after, ratio, ok ? "PASS" : "FAIL");
|
||
if (ok) pass++; else fail++;
|
||
}
|
||
|
||
System.out.printf("%n%d/%d PASS%n", pass, pass + fail);
|
||
if (fail > 0) System.exit(1);
|
||
}
|
||
}
|