java-topology/defects/cmake-0006/unit/WrittenSettingsAlgorithm.java
russell@unturf.com fb1ff685c1 cmake+mpd: 5-MOAD scan; 3 new CWE-407 defects, MPD CLEAN all 5 MOADs
cmake-0005: cmQtAutoGen MergeOptions std::find over baseOpts in newOpts loop, O(N*M), 31.5x at N=M=50
cmake-0006: cmVisualStudio10TargetGenerator FinishWritingSource writtenSettings O(S^2), 15.3x at S=30
cmake-0007: cmGeneratorExpressionNode TargetRuntimeDllDirsNode dllDirs O(D^2), 10.3x at D=100

MPD: all 5 MOADs CLEAN; updated CLEAN.md with MOAD-0002 through MOAD-0005 analysis.
Unit tests: 3/3 PASS.
2026-03-31 22:31:15 -04:00

111 lines
4.6 KiB
Java

import java.util.*;
/**
* Unit test for cmake-0006: FinishWritingSource writtenSettings O(S^2) -> O(S).
*
* Models the dedup logic: for each (config, setting) pair, skip if already written.
* Defect: std::find over vector grows O(S) per check -> O(C * S^2) total.
* Fix: unordered_set -> O(1) per check -> O(C * S) total.
*/
public class WrittenSettingsAlgorithm {
static final int CONFIGS = 4;
static final int SETTINGS_PER_CONFIG = 30;
// Simulate settings: each config has same setting names (all should dedup after first config)
static Map<String, Map<String, String>> buildToolSettings() {
Map<String, Map<String, String>> toolSettings = new LinkedHashMap<>();
for (int c = 0; c < CONFIGS; c++) {
String config = "Config" + c;
Map<String, String> settings = new LinkedHashMap<>();
for (int s = 0; s < SETTINGS_PER_CONFIG; s++) {
settings.put("Setting" + s, "Value" + c + "_" + s);
}
toolSettings.put(config, settings);
}
return toolSettings;
}
// --- Defective: std::find over vector ---
static long finishWritingSourceDefective(Map<String, Map<String, String>> toolSettings) {
List<String> writtenSettings = new ArrayList<>();
long ops = 0;
for (Map.Entry<String, Map<String, String>> configEntry : toolSettings.entrySet()) {
for (Map.Entry<String, String> setting : configEntry.getValue().entrySet()) {
// O(S) linear scan -- the defect
for (String ws : writtenSettings) {
ops++;
if (ws.equals(setting.getKey())) break;
}
if (!writtenSettings.contains(setting.getKey())) {
writtenSettings.add(setting.getKey());
}
}
}
return ops;
}
// --- Fixed: unordered_set ---
static long finishWritingSourceFixed(Map<String, Map<String, String>> toolSettings) {
Set<String> writtenSettings = new HashSet<>();
long ops = 0;
for (Map.Entry<String, Map<String, String>> configEntry : toolSettings.entrySet()) {
for (Map.Entry<String, String> setting : configEntry.getValue().entrySet()) {
ops++; // O(1) hash check
if (!writtenSettings.contains(setting.getKey())) {
writtenSettings.add(setting.getKey());
}
}
}
return ops;
}
// --- Correctness: both produce same written set ---
static void testCorrectness() {
Map<String, Map<String, String>> toolSettings = buildToolSettings();
Set<String> defectWritten = new HashSet<>();
List<String> defectList = new ArrayList<>();
for (Map.Entry<String, Map<String, String>> ce : toolSettings.entrySet()) {
for (Map.Entry<String, String> s : ce.getValue().entrySet()) {
if (!defectList.contains(s.getKey())) defectList.add(s.getKey());
}
}
defectWritten.addAll(defectList);
Set<String> fixedWritten = new HashSet<>();
for (Map.Entry<String, Map<String, String>> ce : toolSettings.entrySet()) {
for (Map.Entry<String, String> s : ce.getValue().entrySet()) {
fixedWritten.add(s.getKey());
}
}
if (!defectWritten.equals(fixedWritten)) {
throw new AssertionError("Written sets differ: defect=" + defectWritten.size()
+ " fixed=" + fixedWritten.size());
}
if (fixedWritten.size() != SETTINGS_PER_CONFIG) {
throw new AssertionError("Expected " + SETTINGS_PER_CONFIG + " unique settings, got " + fixedWritten.size());
}
System.out.println("PASS testCorrectness (written set matches, size=" + fixedWritten.size() + ")");
}
static void testBenchmark() {
Map<String, Map<String, String>> toolSettings = buildToolSettings();
long defectOps = finishWritingSourceDefective(toolSettings);
long fixedOps = finishWritingSourceFixed(toolSettings);
double ratio = (double) defectOps / fixedOps;
System.out.printf("BENCH finishWritingSource C=%d S=%d: defective=%d ops, fixed=%d ops, ratio=%.1fx%n",
CONFIGS, SETTINGS_PER_CONFIG, defectOps, fixedOps, ratio);
if (ratio < 3.0) {
throw new AssertionError("Expected ratio >= 3x, got " + ratio);
}
System.out.println("PASS testBenchmark (ratio >= 3x confirmed)");
}
public static void main(String[] args) {
testCorrectness();
testBenchmark();
System.out.println("ALL PASS cmake-0006 WrittenSettings");
}
}