feat: add unit, integration, and functional test coverage for all 9 MOADs

Each MOAD now has a synthetic defective specimen and fixed specimen
proven from first principles across three test tiers:

Unit (tests/unit/Moad000X*.java):
  - Correctness: defective and fixed produce identical functional output
  - Defect behavior: defective specimen exhibits the defect (measurable)
  - Fix behavior: fixed specimen eliminates the defect

Integration (tests/integration/AllMoadsIntegrationTest.java):
  - All 9 MOADs proven at medium scale (N=500-2000)
  - MOAD-0001: O(N^2) vs O(N) list scan at N=1000
  - MOAD-0002: 500 sessions trample each other (defective) vs coexist (fixed)
  - MOAD-0003: 250 anonymous requests leak auth identity (defective) vs zero (fixed)
  - MOAD-0004: 3000 credential exposures across 1000 requests (defective) vs zero (fixed)
  - MOAD-0005: 500 computes for 500 concurrent misses vs exactly 1
  - MOAD-0006: all 500 passwords extractable from DB (defective) vs unextractable (fixed)
  - MOAD-0007: N=2000 spatial objects, defective visits all 2000 vs O(log N + k)
  - MOAD-0009: 990 wasted firings for 1000 ticks / 10 events vs zero waste
  - MOAD-0011: 10240 NFA steps vs 13 steps on N=12 adversarial input (788x)

Functional (tests/functional/AllMoadsFunctionalTest.java):
  - MOAD-0005: real-thread contention proves herd (defective >1 compute, fixed exactly 1)
  - MOAD-0007: N=50000 spatial objects, 50M defective probes vs 516K fixed (97x speedup)
  - MOAD-0009: 10000 ticks / 10 events, 9990 wasted firings vs zero (1000x ratio)
  - MOAD-0011: N=16 adversarial, 163840 defective steps vs 17 fixed (9638x ratio)

Support algorithms (tests/support/Moad000X*.java):
  - Moad0002Algorithm: shared mutable global state (DefectiveAudioSystem / FixedAudioSystem + Context)
  - Moad0003Algorithm: ThreadLocal not cleared (handleDefective / handleFixed with finally)
  - Moad0004Algorithm: HTTP headers logged verbatim (logDefective / logFixed with CREDENTIAL_HEADERS denylist)
  - Moad0005Algorithm: get+null+compute+put (DefectiveCache HashMap / FixedCache ConcurrentHashMap.computeIfAbsent)
  - Moad0006Algorithm: Base64 password storage (DefectiveCredentialStore / FixedCredentialStore SHA-256+salt)
  - Moad0007Algorithm: linear spatial scan (queryDefective list / queryFixed sorted array + binary search)
  - Moad0009Algorithm: timer-driven polling (runDefectiveScheduler / runFixedEventDriven)
  - Moad0011Algorithm: PCRE nested quantifiers (matchDefective backtracking NFA / matchFixed linear NFA)

Makefile: added unit-moad-0002 through unit-moad-0011 targets,
integration-all-moads, functional-all-moads. integration and functional
targets now depend on all-MOADs variants.
This commit is contained in:
russell@unturf.com 2026-04-12 15:43:19 -04:00
parent 1f88aa0374
commit 4888153e40
19 changed files with 3359 additions and 5 deletions

View file

@ -0,0 +1,155 @@
package unit;
import support.Moad0002Algorithm;
import support.Moad0002Algorithm.Context;
import support.Moad0002Algorithm.DefectiveAudioSystem;
import support.Moad0002Algorithm.DefectiveDisplaySystem;
import support.Moad0002Algorithm.FixedAudioSystem;
import support.Moad0002Algorithm.FixedDisplaySystem;
/**
* Unit tests for MOAD-0002: An Intertangled Defect.
*
* Proves from first principles:
* 1. Defective: AudioSystem.setLocale() mutates state seen by DisplaySystem
* cross-subsystem interference through shared global state.
* 2. Defective: two independent "contexts" sharing GLOBAL cannot coexist
* the second write tramples the first silently.
* 3. Fixed: two Context objects carry independent values simultaneously.
* 4. Fixed: AudioSystem and DisplaySystem read from separate Context objects
* without interfering with each other.
*
* No build tool required. Compile and run:
*
* cd tests
* java -m jdk.compiler/com.sun.tools.javac.Main -cp . \
* support/Moad0002Algorithm.java unit/Moad0002UnitTest.java
* java -cp . unit.Moad0002UnitTest
*/
public class Moad0002UnitTest {
private static int passed = 0;
private static int failed = 0;
public static void main(String[] args) {
System.out.println("=== Moad0002UnitTest (An Intertangled Defect) ===\n");
System.out.println("-- Correctness: subsystems read values correctly --");
testDefectiveBasicRead();
testFixedBasicRead();
System.out.println("\n-- Defect: shared global state causes cross-subsystem interference --");
testDefectiveAudioLocaleLeaksToDisplay();
testDefectiveTwoContextsTrample();
System.out.println("\n-- Fix: isolated Context objects prevent interference --");
testFixedTwoContextsCoexist();
testFixedSubsystemsDoNotInterfere();
System.out.printf("\n%d passed, %d failed%n", passed, failed);
if (failed > 0) System.exit(1);
}
// Correctness
static void testDefectiveBasicRead() {
Moad0002Algorithm.resetGlobal();
DefectiveAudioSystem audio = new DefectiveAudioSystem();
audio.setVolume(80);
assertEqual("defective audio: volume reads back correctly", 80, audio.getVolume());
}
static void testFixedBasicRead() {
Context ctx = new Context(70, 200, "fr");
FixedAudioSystem audio = new FixedAudioSystem(ctx);
FixedDisplaySystem display = new FixedDisplaySystem(ctx);
assertEqual("fixed audio: volume", 70, audio.getVolume());
assertEqual("fixed display: brightness", 200, display.getBrightness());
assertEqual("fixed audio: locale", "fr", audio.getLocale());
assertEqual("fixed display: locale", "fr", display.getLocale());
}
// Defect
static void testDefectiveAudioLocaleLeaksToDisplay() {
Moad0002Algorithm.resetGlobal();
DefectiveAudioSystem audio = new DefectiveAudioSystem();
DefectiveDisplaySystem display = new DefectiveDisplaySystem();
// AudioSystem configures locale conceptually an audio concern (TTS language)
audio.setLocale("ja");
// DEFECT: DisplaySystem reads the same global sees audio's mutation
// This is the intertangle: two subsystems that should be independent
// are coupled through a shared mutable state object.
String displayLocale = display.getLocale();
assertEqual("defective: audio locale write leaks into display", "ja", displayLocale);
}
static void testDefectiveTwoContextsTrample() {
Moad0002Algorithm.resetGlobal();
// Two independent "sessions" each configure their own audio subsystem.
DefectiveAudioSystem session1 = new DefectiveAudioSystem();
DefectiveAudioSystem session2 = new DefectiveAudioSystem();
session1.setVolume(30); // session 1 sets volume to 30
session2.setVolume(90); // session 2 sets volume to 90 TRAMPLES session 1
// DEFECT: session 1 now sees 90, not 30 its configuration was silently destroyed.
// Two contexts cannot coexist when they share a global state object.
int session1Volume = session1.getVolume();
assertEqual("defective: session2 write tramples session1 volume", 90, session1Volume);
}
// Fix
static void testFixedTwoContextsCoexist() {
Context ctx1 = new Context(30, 150, "en");
Context ctx2 = new Context(90, 200, "ja");
FixedAudioSystem s1 = new FixedAudioSystem(ctx1);
FixedAudioSystem s2 = new FixedAudioSystem(ctx2);
// FIX: both values coexist ctx1 and ctx2 are independent objects
assertEqual("fixed: session1 volume preserved after session2 created", 30, s1.getVolume());
assertEqual("fixed: session2 volume independent of session1", 90, s2.getVolume());
assertEqual("fixed: session1 locale preserved", "en", s1.getLocale());
assertEqual("fixed: session2 locale independent", "ja", s2.getLocale());
}
static void testFixedSubsystemsDoNotInterfere() {
Context audioCtx = new Context(75, 0, "de");
Context displayCtx = new Context(0, 180, "fr");
FixedAudioSystem audio = new FixedAudioSystem(audioCtx);
FixedDisplaySystem display = new FixedDisplaySystem(displayCtx);
// FIX: each subsystem reads only its own context no cross-contamination
assertEqual("fixed: audio locale unaffected by display context", "de", audio.getLocale());
assertEqual("fixed: display locale unaffected by audio context", "fr", display.getLocale());
assertEqual("fixed: display brightness from own context", 180, display.getBrightness());
assertEqual("fixed: audio volume from own context", 75, audio.getVolume());
}
// Helpers
static void assertEqual(String label, int expected, int actual) {
if (expected == actual) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — expected %d, got %d%n", label, expected, actual);
failed++;
}
}
static void assertEqual(String label, String expected, String actual) {
if (expected == null ? actual == null : expected.equals(actual)) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — expected '%s', got '%s'%n", label, expected, actual);
failed++;
}
}
}

View file

@ -0,0 +1,142 @@
package unit;
import support.Moad0003Algorithm;
/**
* Unit tests for MOAD-0003: A Leaked Context.
*
* Proves from first principles:
* 1. Defective: ThreadLocal set in request R1 remains accessible after R1
* completes the next request R2 (which never calls set()) inherits R1's
* identity. This is the thread-pool leak: the thread is reused, but the
* ThreadLocal is not cleared between units of work.
* 2. Fixed: ThreadLocal.remove() in a finally block ensures R2 sees null
* each request starts from a clean slate.
* 3. Both correctly return the identity when explicitly set.
* 4. Partial-set scenario: R2 sets its own identity and removes it correctly
* even when R1 failed to clean up in the defective variant.
*
* No build tool required. Compile and run:
*
* cd tests
* java -m jdk.compiler/com.sun.tools.javac.Main -cp . \
* support/Moad0003Algorithm.java unit/Moad0003UnitTest.java
* java -cp . unit.Moad0003UnitTest
*/
public class Moad0003UnitTest {
private static int passed = 0;
private static int failed = 0;
public static void main(String[] args) {
System.out.println("=== Moad0003UnitTest (A Leaked Context) ===\n");
System.out.println("-- Correctness: identity returned correctly when set --");
testDefectiveReturnsSetIdentity();
testFixedReturnsSetIdentity();
System.out.println("\n-- Defect: stale identity leaks to anonymous next request --");
testDefectiveLeaksToAnonymousRequest();
testDefectiveLeaksAcrossMultipleRequests();
System.out.println("\n-- Fix: ThreadLocal.remove() cleans up before next request --");
testFixedAnonymousRequestSeesNull();
testFixedMultipleRequestsClean();
System.out.printf("\n%d passed, %d failed%n", passed, failed);
if (failed > 0) System.exit(1);
}
// Correctness
static void testDefectiveReturnsSetIdentity() {
Moad0003Algorithm.reset();
String result = Moad0003Algorithm.handleDefective("alice");
assertEqual("defective: returns set identity 'alice'", "alice", result);
Moad0003Algorithm.reset(); // clean up after defective handler
}
static void testFixedReturnsSetIdentity() {
Moad0003Algorithm.reset();
String result = Moad0003Algorithm.handleFixed("bob");
assertEqual("fixed: returns set identity 'bob'", "bob", result);
// handleFixed removes ThreadLocal automatically
}
// Defect
static void testDefectiveLeaksToAnonymousRequest() {
Moad0003Algorithm.reset();
// Request R1: authenticated as "alice"
Moad0003Algorithm.handleDefective("alice");
// R1 completes but DOES NOT call remove() ThreadLocal still holds "alice"
// Request R2: anonymous never calls set()
// Simulates the same pooled thread handling the next request.
String leaked = Moad0003Algorithm.handleDefectiveAnonymous();
// DEFECT: R2 sees "alice" even though it never set any identity.
// A CSRF-style confusion: R2 could perform privileged operations as "alice".
assertEqual("defective: anonymous request leaks alice's identity", "alice", leaked);
Moad0003Algorithm.reset();
}
static void testDefectiveLeaksAcrossMultipleRequests() {
Moad0003Algorithm.reset();
// R1 sets identity, completes without cleanup
Moad0003Algorithm.handleDefective("carol");
// R2 anonymous sees leaked "carol"
String leak1 = Moad0003Algorithm.handleDefectiveAnonymous();
// R3 anonymous still sees "carol" (ThreadLocal persists until explicitly removed)
String leak2 = Moad0003Algorithm.handleDefectiveAnonymous();
assertEqual("defective: first anonymous request leaks 'carol'", "carol", leak1);
assertEqual("defective: second anonymous request still leaks 'carol'", "carol", leak2);
Moad0003Algorithm.reset();
}
// Fix
static void testFixedAnonymousRequestSeesNull() {
Moad0003Algorithm.reset();
// R1: authenticated handleFixed removes ThreadLocal in finally
Moad0003Algorithm.handleFixed("alice");
// ThreadLocal is now null handleFixed called remove() before returning
// R2: anonymous sees null (clean slate)
String identity = Moad0003Algorithm.handleFixedAnonymous();
assertEqual("fixed: anonymous request after fixed handler sees null", null, identity);
}
static void testFixedMultipleRequestsClean() {
Moad0003Algorithm.reset();
// Simulate 3 requests on the same pooled thread, alternating auth/anon
String r1 = Moad0003Algorithm.handleFixed("alice"); // auth
String r2 = Moad0003Algorithm.handleFixedAnonymous(); // anon must be null
String r3 = Moad0003Algorithm.handleFixed("bob"); // auth
String r4 = Moad0003Algorithm.handleFixedAnonymous(); // anon must be null
assertEqual("fixed: R1 returns 'alice'", "alice", r1);
assertEqual("fixed: R2 anonymous sees null (not alice)", null, r2);
assertEqual("fixed: R3 returns 'bob'", "bob", r3);
assertEqual("fixed: R4 anonymous sees null (not bob)", null, r4);
}
// Helpers
static void assertEqual(String label, String expected, String actual) {
if (expected == null ? actual == null : expected.equals(actual)) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — expected '%s', got '%s'%n", label, expected, actual);
failed++;
}
}
}

View file

@ -0,0 +1,174 @@
package unit;
import support.Moad0004Algorithm;
import support.Moad0004Algorithm.Result;
import java.util.Map;
/**
* Unit tests for MOAD-0004: A Logged Secret.
*
* Proves from first principles:
* 1. Defective: Authorization and Cookie headers appear verbatim in the log line
* bearer token and session cookie exposed in cleartext.
* 2. Defective: leak count equals the number of credential headers present.
* 3. Fixed: credential header values are replaced with [REDACTED]
* log line contains header names (for debugging) but not values.
* 4. Fixed: non-credential headers (Host, Content-Type) pass through unchanged.
* 5. Both handle empty header maps without error.
*
* No build tool required. Compile and run:
*
* cd tests
* java -m jdk.compiler/com.sun.tools.javac.Main -cp . \
* support/Moad0004Algorithm.java unit/Moad0004UnitTest.java
* java -cp . unit.Moad0004UnitTest
*/
public class Moad0004UnitTest {
private static int passed = 0;
private static int failed = 0;
public static void main(String[] args) {
System.out.println("=== Moad0004UnitTest (A Logged Secret) ===\n");
System.out.println("-- Correctness: both handle headers without throwing --");
testBothHandleEmpty();
System.out.println("\n-- Defect: credential headers appear in cleartext log --");
testDefectiveAuthorizationLeaks();
testDefectiveCookieLeaks();
testDefectiveCountsAllCredentialHeaders();
testDefectiveNonCredentialHeadersPresent();
System.out.println("\n-- Fix: credential headers redacted, non-credential headers intact --");
testFixedAuthorizationRedacted();
testFixedCookieRedacted();
testFixedNonCredentialHeadersPassThrough();
testFixedZeroLeakCount();
System.out.printf("\n%d passed, %d failed%n", passed, failed);
if (failed > 0) System.exit(1);
}
// Correctness
static void testBothHandleEmpty() {
Map<String, String> empty = Map.of();
Result def = Moad0004Algorithm.logDefective(empty);
Result fix = Moad0004Algorithm.logFixed(empty);
assertEqual("defective: empty headers, zero leaks", 0, def.credentialLeakCount);
assertEqual("fixed: empty headers, zero leaks", 0, fix.credentialLeakCount);
}
// Defect
static void testDefectiveAuthorizationLeaks() {
Map<String, String> headers = Moad0004Algorithm.sampleHeaders();
Result result = Moad0004Algorithm.logDefective(headers);
// DEFECT: bearer token appears in the log line verbatim
assertContains("defective: Authorization value in log (bearer token exposed)",
result.logLine, "eyJhbGciOiJSUzI1NiJ9.secret.token");
}
static void testDefectiveCookieLeaks() {
Map<String, String> headers = Moad0004Algorithm.sampleHeaders();
Result result = Moad0004Algorithm.logDefective(headers);
// DEFECT: session cookie and CSRF token appear in the log line
assertContains("defective: Cookie value in log (session cookie exposed)",
result.logLine, "session=abc123def456");
}
static void testDefectiveCountsAllCredentialHeaders() {
Map<String, String> headers = Moad0004Algorithm.sampleHeaders();
Result result = Moad0004Algorithm.logDefective(headers);
// sampleHeaders() contains: Authorization, Cookie, X-Api-Key = 3 credential headers
assertEqual("defective: counts 3 credential header leaks", 3, result.credentialLeakCount);
}
static void testDefectiveNonCredentialHeadersPresent() {
Map<String, String> headers = Moad0004Algorithm.sampleHeaders();
Result result = Moad0004Algorithm.logDefective(headers);
// Non-credential headers should appear (correct behavior for logging)
assertContains("defective: Host header present in log", result.logLine, "api.example.com");
assertContains("defective: X-Request-Id present in log", result.logLine, "req-7f3a9c");
}
// Fix
static void testFixedAuthorizationRedacted() {
Map<String, String> headers = Moad0004Algorithm.sampleHeaders();
Result result = Moad0004Algorithm.logFixed(headers);
// FIX: bearer token must NOT appear in the log line
assertNotContains("fixed: bearer token NOT in log",
result.logLine, "eyJhbGciOiJSUzI1NiJ9.secret.token");
// The header name should still appear (useful for debugging)
assertContains("fixed: Authorization header name present (redacted value)",
result.logLine, "Authorization");
}
static void testFixedCookieRedacted() {
Map<String, String> headers = Moad0004Algorithm.sampleHeaders();
Result result = Moad0004Algorithm.logFixed(headers);
// FIX: session cookie must NOT appear
assertNotContains("fixed: session cookie NOT in log", result.logLine, "session=abc123def456");
// The header name should still appear
assertContains("fixed: Cookie header name present", result.logLine, "Cookie");
}
static void testFixedNonCredentialHeadersPassThrough() {
Map<String, String> headers = Moad0004Algorithm.sampleHeaders();
Result result = Moad0004Algorithm.logFixed(headers);
// Non-credential headers must pass through unchanged
assertContains("fixed: Host value passes through", result.logLine, "api.example.com");
assertContains("fixed: X-Request-Id passes through", result.logLine, "req-7f3a9c");
assertContains("fixed: Content-Type passes through", result.logLine, "application/json");
}
static void testFixedZeroLeakCount() {
Map<String, String> headers = Moad0004Algorithm.sampleHeaders();
Result result = Moad0004Algorithm.logFixed(headers);
assertEqual("fixed: zero credential leaks", 0, result.credentialLeakCount);
}
// Helpers
static void assertEqual(String label, int expected, int actual) {
if (expected == actual) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — expected %d, got %d%n", label, expected, actual);
failed++;
}
}
static void assertContains(String label, String haystack, String needle) {
if (haystack.contains(needle)) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — '%s' not found in: %s%n", label, needle, haystack);
failed++;
}
}
static void assertNotContains(String label, String haystack, String needle) {
if (!haystack.contains(needle)) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — '%s' should NOT be in: %s%n", label, needle, haystack);
failed++;
}
}
}

View file

@ -0,0 +1,183 @@
package unit;
import support.Moad0005Algorithm;
import support.Moad0005Algorithm.DefectiveCache;
import support.Moad0005Algorithm.FixedCache;
/**
* Unit tests for MOAD-0005: CWE-362 A Thundering Herd.
*
* Proves from first principles:
* 1. Defective: N callers all seeing a null cache entry all invoke
* expensiveCompute() N computes instead of 1. This is the herd.
* 2. Fixed: ConcurrentHashMap.computeIfAbsent() ensures exactly 1 compute
* regardless of how many callers miss simultaneously.
* 3. Both return the same (correct) value for any key.
* 4. Sequential access on a warm cache: both call compute exactly once.
*
* The single-threaded simulation models the race window: all callers read
* before any caller's put() completes. Integration tests use real threads.
*
* No build tool required. Compile and run:
*
* cd tests
* java -m jdk.compiler/com.sun.tools.javac.Main -cp . \
* support/Moad0005Algorithm.java unit/Moad0005UnitTest.java
* java -cp . unit.Moad0005UnitTest
*/
public class Moad0005UnitTest {
private static int passed = 0;
private static int failed = 0;
public static void main(String[] args) {
System.out.println("=== Moad0005UnitTest (A Thundering Herd) ===\n");
System.out.println("-- Correctness: both caches return correct value --");
testDefectiveReturnsCorrectValue();
testFixedReturnsCorrectValue();
testBothReturnSameValue();
System.out.println("\n-- Defect: N concurrent misses produce N computes --");
testDefectiveConcurrentMissN10();
testDefectiveConcurrentMissN50();
testDefectiveComputeCountScalesWithCallers();
System.out.println("\n-- Fix: N concurrent misses produce exactly 1 compute --");
testFixedConcurrentMissN10();
testFixedConcurrentMissN50();
testFixedComputeCountAlwaysOne();
System.out.println("\n-- Warm cache: both compute exactly once sequentially --");
testDefectiveWarmCacheNoRecompute();
testFixedWarmCacheNoRecompute();
System.out.printf("\n%d passed, %d failed%n", passed, failed);
if (failed > 0) System.exit(1);
}
// Correctness
static void testDefectiveReturnsCorrectValue() {
Moad0005Algorithm.resetCounter();
DefectiveCache cache = new DefectiveCache();
String val = cache.getOrCompute("foo");
assertEqual("defective: returns 'value-for-foo'", "value-for-foo", val);
}
static void testFixedReturnsCorrectValue() {
Moad0005Algorithm.resetCounter();
FixedCache cache = new FixedCache();
String val = cache.getOrCompute("foo");
assertEqual("fixed: returns 'value-for-foo'", "value-for-foo", val);
}
static void testBothReturnSameValue() {
Moad0005Algorithm.resetCounter();
DefectiveCache def = new DefectiveCache();
FixedCache fix = new FixedCache();
String dVal = def.getOrCompute("bar");
Moad0005Algorithm.resetCounter();
String fVal = fix.getOrCompute("bar");
assertEqual("both: return same value for 'bar'", dVal, fVal);
}
// Defect
static void testDefectiveConcurrentMissN10() {
int computes = Moad0005Algorithm.simulateDefectiveConcurrentMiss(10, "key");
// DEFECT: all 10 callers see null simultaneously 10 computes
assertEqual("defective: 10 concurrent misses cause 10 computes (herd)", 10, computes);
}
static void testDefectiveConcurrentMissN50() {
int computes = Moad0005Algorithm.simulateDefectiveConcurrentMiss(50, "key");
// DEFECT: 50 concurrent misses 50 computes
assertEqual("defective: 50 concurrent misses cause 50 computes (herd)", 50, computes);
}
static void testDefectiveComputeCountScalesWithCallers() {
int c10 = Moad0005Algorithm.simulateDefectiveConcurrentMiss(10, "key");
int c20 = Moad0005Algorithm.simulateDefectiveConcurrentMiss(20, "key");
// DEFECT: compute count scales linearly with caller count (N wasted computes)
assertTrue("defective: doubling callers doubles computes",
c20 == 2 * c10, "c10=" + c10 + " c20=" + c20);
}
// Fix
static void testFixedConcurrentMissN10() {
int computes = Moad0005Algorithm.simulateFixedConcurrentMiss(10, "key");
// FIX: computeIfAbsent exactly 1 compute regardless of caller count
assertEqual("fixed: 10 concurrent misses cause exactly 1 compute", 1, computes);
}
static void testFixedConcurrentMissN50() {
int computes = Moad0005Algorithm.simulateFixedConcurrentMiss(50, "key");
assertEqual("fixed: 50 concurrent misses cause exactly 1 compute", 1, computes);
}
static void testFixedComputeCountAlwaysOne() {
int c10 = Moad0005Algorithm.simulateFixedConcurrentMiss(10, "key");
int c100 = Moad0005Algorithm.simulateFixedConcurrentMiss(100, "key");
// FIX: compute count does not scale always 1
assertEqual("fixed: 10 callers — 1 compute", 1, c10);
assertEqual("fixed: 100 callers — 1 compute", 1, c100);
}
// Warm cache
static void testDefectiveWarmCacheNoRecompute() {
Moad0005Algorithm.resetCounter();
DefectiveCache cache = new DefectiveCache();
cache.getOrCompute("warm"); // cold miss 1 compute
int afterFirst = Moad0005Algorithm.COMPUTE_CALLS.get();
cache.getOrCompute("warm"); // warm hit 0 compute
int afterSecond = Moad0005Algorithm.COMPUTE_CALLS.get();
assertEqual("defective: first call computes once", 1, afterFirst);
assertEqual("defective: second sequential call hits cache", 1, afterSecond);
}
static void testFixedWarmCacheNoRecompute() {
Moad0005Algorithm.resetCounter();
FixedCache cache = new FixedCache();
cache.getOrCompute("warm"); // cold miss 1 compute
int afterFirst = Moad0005Algorithm.COMPUTE_CALLS.get();
cache.getOrCompute("warm"); // warm hit 0 compute
int afterSecond = Moad0005Algorithm.COMPUTE_CALLS.get();
assertEqual("fixed: first call computes once", 1, afterFirst);
assertEqual("fixed: second sequential call hits cache", 1, afterSecond);
}
// Helpers
static void assertEqual(String label, int expected, int actual) {
if (expected == actual) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — expected %d, got %d%n", label, expected, actual);
failed++;
}
}
static void assertEqual(String label, String expected, String actual) {
if (expected == null ? actual == null : expected.equals(actual)) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — expected '%s', got '%s'%n", label, expected, actual);
failed++;
}
}
static void assertTrue(String label, boolean condition, String detail) {
if (condition) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — %s%n", label, detail);
failed++;
}
}
}

View file

@ -0,0 +1,238 @@
package unit;
import support.Moad0006Algorithm;
import support.Moad0006Algorithm.DefectiveCredentialStore;
import support.Moad0006Algorithm.FixedCredentialStore;
/**
* Unit tests for MOAD-0006: CWE-257 A Glass Safe.
*
* Proves from first principles:
* 1. Defective: Base64 encoding is reversible stored credential decodes
* to the original password. An attacker with DB read access extracts
* every password in plaintext.
* 2. Defective: stored value is deterministic same password always produces
* same encoded string, enabling rainbow table attacks.
* 3. Fixed: SHA-256 + salt is one-way the stored hash cannot be decoded
* to recover the original password.
* 4. Fixed: salt randomization same password stored twice produces
* different hash values (defeats rainbow tables).
* 5. Both correctly verify a correct password and reject an incorrect one.
*
* No build tool required. Compile and run:
*
* cd tests
* java -m jdk.compiler/com.sun.tools.javac.Main -cp . \
* support/Moad0006Algorithm.java unit/Moad0006UnitTest.java
* java -cp . unit.Moad0006UnitTest
*/
public class Moad0006UnitTest {
private static int passed = 0;
private static int failed = 0;
public static void main(String[] args) {
System.out.println("=== Moad0006UnitTest (A Glass Safe) ===\n");
System.out.println("-- Correctness: verification works for both --");
testDefectiveVerifyCorrect();
testDefectiveRejectWrong();
testFixedVerifyCorrect();
testFixedRejectWrong();
System.out.println("\n-- Defect: stored value is reversible (glass safe opens) --");
testDefectivePasswordExtractable();
testDefectiveDeterministicStorage();
testDefectiveMultipleUsersExtractable();
System.out.println("\n-- Fix: stored value is one-way (hash cannot be reversed) --");
testFixedPasswordNotExtractable();
testFixedSaltRandomization();
testFixedHashNotEqualToPassword();
System.out.printf("\n%d passed, %d failed%n", passed, failed);
if (failed > 0) System.exit(1);
}
// Correctness
static void testDefectiveVerifyCorrect() {
DefectiveCredentialStore store = new DefectiveCredentialStore();
store.storePassword("alice", "hunter2");
assertTrue("defective: correct password verified", store.verify("alice", "hunter2"));
}
static void testDefectiveRejectWrong() {
DefectiveCredentialStore store = new DefectiveCredentialStore();
store.storePassword("alice", "hunter2");
assertFalse("defective: wrong password rejected", store.verify("alice", "wrongpass"));
}
static void testFixedVerifyCorrect() {
FixedCredentialStore store = new FixedCredentialStore();
store.storePassword("bob", "correct-horse-battery-staple");
assertTrue("fixed: correct password verified", store.verify("bob", "correct-horse-battery-staple"));
}
static void testFixedRejectWrong() {
FixedCredentialStore store = new FixedCredentialStore();
store.storePassword("bob", "correct-horse-battery-staple");
assertFalse("fixed: wrong password rejected", store.verify("bob", "wrong-answer"));
}
// Defect
static void testDefectivePasswordExtractable() {
DefectiveCredentialStore store = new DefectiveCredentialStore();
store.storePassword("alice", "s3cr3t!");
// DEFECT: attacker with DB access calls extractPassword()
String extracted = store.extractPassword("alice");
assertEqual("defective: original password extracted from DB (glass safe opens)",
"s3cr3t!", extracted);
}
static void testDefectiveDeterministicStorage() {
DefectiveCredentialStore store1 = new DefectiveCredentialStore();
DefectiveCredentialStore store2 = new DefectiveCredentialStore();
store1.storePassword("u1", "password123");
store2.storePassword("u2", "password123");
// DEFECT: same password same stored value rainbow table attack works
String raw1 = store1.rawStored("u1");
String raw2 = store2.rawStored("u2");
assertEqual("defective: same password produces identical stored values (no salt)",
raw1, raw2);
}
static void testDefectiveMultipleUsersExtractable() {
DefectiveCredentialStore store = new DefectiveCredentialStore();
store.storePassword("admin", "admin123");
store.storePassword("finance", "Q4RevenueReport!");
// DEFECT: all users' passwords extractable from one DB dump
assertEqual("defective: admin password extracted", "admin123", store.extractPassword("admin"));
assertEqual("defective: finance password extracted", "Q4RevenueReport!", store.extractPassword("finance"));
}
// Fix
static void testFixedPasswordNotExtractable() {
FixedCredentialStore store = new FixedCredentialStore();
store.storePassword("alice", "s3cr3t!");
// FIX: raw hash is stored cannot reverse to original password
byte[] hash = store.rawHash("alice");
byte[] salt = store.rawSalt("alice");
assertNotNull("fixed: hash exists in store", hash);
assertNotNull("fixed: salt exists in store", salt);
// Verify hash does not equal password bytes
String hashHex = bytesToHex(hash);
assertNotContains("fixed: hash does not contain plaintext password",
hashHex, "s3cr3t!");
// FIX: no extractPassword() method exists on FixedCredentialStore
// (This is verified by the fact that FixedCredentialStore does not have that method
// the API surface itself proves the fix.)
assertTrue("fixed: FixedCredentialStore has no extractPassword() method (API enforces fix)",
!hasExtractMethod(store));
}
static void testFixedSaltRandomization() {
// Store the same password for two users
FixedCredentialStore store = new FixedCredentialStore();
store.storePassword("u1", "shared-password");
store.storePassword("u2", "shared-password");
byte[] hash1 = store.rawHash("u1");
byte[] hash2 = store.rawHash("u2");
byte[] salt1 = store.rawSalt("u1");
byte[] salt2 = store.rawSalt("u2");
// FIX: different salts different hashes rainbow table attack fails
assertNotEqualBytes("fixed: same password produces different hashes (random salt)",
hash1, hash2);
assertNotEqualBytes("fixed: unique salt per user", salt1, salt2);
}
static void testFixedHashNotEqualToPassword() {
FixedCredentialStore store = new FixedCredentialStore();
String password = "mypassword";
store.storePassword("user", password);
byte[] hash = store.rawHash("user");
// Hash bytes should not equal password bytes
byte[] passwordBytes = password.getBytes(java.nio.charset.StandardCharsets.UTF_8);
assertFalseBytes("fixed: stored hash does not equal password bytes", hash, passwordBytes);
}
// Helpers
static void assertEqual(String label, String expected, String actual) {
if (expected == null ? actual == null : expected.equals(actual)) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — expected '%s', got '%s'%n", label, expected, actual);
failed++;
}
}
static void assertTrue(String label, boolean condition) {
if (condition) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s%n", label);
failed++;
}
}
static void assertFalse(String label, boolean condition) {
assertTrue(label, !condition);
}
static void assertNotNull(String label, Object obj) {
assertTrue(label + " (not null)", obj != null);
}
static void assertNotContains(String label, String haystack, String needle) {
if (!haystack.contains(needle)) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — found '%s' in '%s'%n", label, needle, haystack);
failed++;
}
}
static void assertNotEqualBytes(String label, byte[] a, byte[] b) {
if (!java.util.Arrays.equals(a, b)) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — byte arrays are equal when they should differ%n", label);
failed++;
}
}
static void assertFalseBytes(String label, byte[] a, byte[] b) {
assertNotEqualBytes(label, a, b);
}
static boolean hasExtractMethod(FixedCredentialStore store) {
try {
store.getClass().getMethod("extractPassword", String.class);
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) sb.append(String.format("%02x", b));
return sb.toString();
}
}

View file

@ -0,0 +1,207 @@
package unit;
import support.Moad0007Algorithm;
import support.Moad0007Algorithm.SpatialObject;
import support.Moad0007Algorithm.Result;
import java.util.List;
/**
* Unit tests for MOAD-0007: CWE-407 A Flatland Defect.
*
* Proves from first principles:
* 1. Both defective and fixed produce identical query results (same hits).
* 2. Defective: queryDefective() visits all N objects for every query
* probeCount == N regardless of how many objects match.
* 3. Fixed: queryFixed() visits O(log N + k) objects probeCount grows as
* log(N) for empty queries and log(N)+k for queries returning k hits.
* 4. Doubling N doubles defective probes; fixed probes grow only by 1 (log step).
* 5. Empty-range query: defective still visits all N; fixed visits O(log N).
*
* No build tool required. Compile and run:
*
* cd tests
* java -m jdk.compiler/com.sun.tools.javac.Main -cp . \
* support/Moad0007Algorithm.java unit/Moad0007UnitTest.java
* java -cp . unit.Moad0007UnitTest
*/
public class Moad0007UnitTest {
private static int passed = 0;
private static int failed = 0;
public static void main(String[] args) {
System.out.println("=== Moad0007UnitTest (A Flatland Defect) ===\n");
System.out.println("-- Correctness: same query results from both implementations --");
testSmallSceneAllMatch();
testSmallScenePartialMatch();
testSmallSceneNoMatch();
System.out.println("\n-- Defect: linear scan visits all N objects (O(N) probes) --");
testDefectiveProbesAllN100();
testDefectiveProbesAllN200();
testDefectiveEmptyQueryStillVisitsAllN();
System.out.println("\n-- Fix: binary search visits O(log N + k) objects --");
testFixedProbesLogN100();
testFixedProbesLogN200();
testFixedEmptyQueryVisitsLogN();
System.out.println("\n-- Complexity: doubling N doubles defective probes, barely changes fixed --");
testDoublingNEffect();
System.out.printf("\n%d passed, %d failed%n", passed, failed);
if (failed > 0) System.exit(1);
}
// Correctness
static void testSmallSceneAllMatch() {
List<SpatialObject> scene = Moad0007Algorithm.buildScene(10, 100.0);
SpatialObject[] index = Moad0007Algorithm.buildIndex(scene);
Result def = Moad0007Algorithm.queryDefective(scene, 0.0, 100.0);
Result fix = Moad0007Algorithm.queryFixed(index, 0.0, 100.0);
assertEqual("correctness: all-match hit counts equal", def.hits.size(), fix.hits.size());
assertEqual("correctness: all-match returns 10 hits", 10, def.hits.size());
}
static void testSmallScenePartialMatch() {
List<SpatialObject> scene = Moad0007Algorithm.buildScene(10, 100.0);
SpatialObject[] index = Moad0007Algorithm.buildIndex(scene);
// Middle third: positions [33, 66]
Result def = Moad0007Algorithm.queryDefective(scene, 33.0, 66.0);
Result fix = Moad0007Algorithm.queryFixed(index, 33.0, 66.0);
assertEqual("correctness: partial-match hit counts equal", def.hits.size(), fix.hits.size());
assertTrue("correctness: partial match returns some hits (>0, <10)",
def.hits.size() > 0 && def.hits.size() < 10,
"hits=" + def.hits.size());
}
static void testSmallSceneNoMatch() {
List<SpatialObject> scene = Moad0007Algorithm.buildScene(10, 100.0);
SpatialObject[] index = Moad0007Algorithm.buildIndex(scene);
// Query outside the scene bounds
Result def = Moad0007Algorithm.queryDefective(scene, 200.0, 300.0);
Result fix = Moad0007Algorithm.queryFixed(index, 200.0, 300.0);
assertEqual("correctness: no-match — both return 0 hits (defective)", 0, def.hits.size());
assertEqual("correctness: no-match — both return 0 hits (fixed)", 0, fix.hits.size());
}
// Defect
static void testDefectiveProbesAllN100() {
int N = 100;
List<SpatialObject> scene = Moad0007Algorithm.buildScene(N, 1000.0);
// Even a no-match query visits all N
Result result = Moad0007Algorithm.queryDefective(scene, 2000.0, 3000.0);
assertEqual("defective N=100: probes all 100 objects (even no-match)", N, result.probeCount);
}
static void testDefectiveProbesAllN200() {
int N = 200;
List<SpatialObject> scene = Moad0007Algorithm.buildScene(N, 1000.0);
Result result = Moad0007Algorithm.queryDefective(scene, 2000.0, 3000.0);
assertEqual("defective N=200: probes all 200 objects", N, result.probeCount);
}
static void testDefectiveEmptyQueryStillVisitsAllN() {
int N = 150;
List<SpatialObject> scene = Moad0007Algorithm.buildScene(N, 500.0);
Result result = Moad0007Algorithm.queryDefective(scene, -100.0, -50.0); // no objects here
assertEqual("defective: empty-range query still visits all N=" + N, N, result.probeCount);
}
// Fix
static void testFixedProbesLogN100() {
int N = 100;
List<SpatialObject> scene = Moad0007Algorithm.buildScene(N, 1000.0);
SpatialObject[] index = Moad0007Algorithm.buildIndex(scene);
// No-match query: probes should be O(log N) = ~7 for N=100
Result result = Moad0007Algorithm.queryFixed(index, 2000.0, 3000.0);
// Binary search on 100 elements: at most ceil(log2(100)) = 7 steps, plus 1 for the exit check
int expectedMax = (int)(Math.ceil(Math.log(N) / Math.log(2))) + 2;
assertTrue("fixed N=100: no-match query probes <= " + expectedMax + " (log N)",
result.probeCount <= expectedMax,
"probeCount=" + result.probeCount);
assertTrue("fixed N=100: probes much less than N",
result.probeCount < N / 4,
"probeCount=" + result.probeCount + " N=" + N);
}
static void testFixedProbesLogN200() {
int N = 200;
List<SpatialObject> scene = Moad0007Algorithm.buildScene(N, 1000.0);
SpatialObject[] index = Moad0007Algorithm.buildIndex(scene);
Result result = Moad0007Algorithm.queryFixed(index, 2000.0, 3000.0);
int expectedMax = (int)(Math.ceil(Math.log(N) / Math.log(2))) + 2;
assertTrue("fixed N=200: no-match query probes <= " + expectedMax,
result.probeCount <= expectedMax,
"probeCount=" + result.probeCount);
}
static void testFixedEmptyQueryVisitsLogN() {
int N = 128; // power of 2 for clean log result
List<SpatialObject> scene = Moad0007Algorithm.buildScene(N, 1000.0);
SpatialObject[] index = Moad0007Algorithm.buildIndex(scene);
Result result = Moad0007Algorithm.queryFixed(index, -100.0, -1.0); // below all objects
// Binary search on 128 elements: 7 steps max (log2(128) = 7)
assertTrue("fixed N=128: out-of-range query probes at most 9 (log N + overhead)",
result.probeCount <= 9,
"probeCount=" + result.probeCount);
}
// Complexity
static void testDoublingNEffect() {
// Defective: doubling N doubles probes
int N1 = 100, N2 = 200;
List<SpatialObject> s1 = Moad0007Algorithm.buildScene(N1, 1000.0);
List<SpatialObject> s2 = Moad0007Algorithm.buildScene(N2, 1000.0);
SpatialObject[] i1 = Moad0007Algorithm.buildIndex(s1);
SpatialObject[] i2 = Moad0007Algorithm.buildIndex(s2);
Result def1 = Moad0007Algorithm.queryDefective(s1, 2000.0, 3000.0);
Result def2 = Moad0007Algorithm.queryDefective(s2, 2000.0, 3000.0);
Result fix1 = Moad0007Algorithm.queryFixed(i1, 2000.0, 3000.0);
Result fix2 = Moad0007Algorithm.queryFixed(i2, 2000.0, 3000.0);
// Defective: probes double exactly with N
assertEqual("defective: doubling N doubles probes (linear)", def1.probeCount * 2, def2.probeCount);
// Fixed: doubling N adds at most 1 log step
int fixDelta = fix2.probeCount - fix1.probeCount;
assertTrue("fixed: doubling N adds at most 1 probe (log growth)",
fixDelta <= 1,
"fix1.probes=" + fix1.probeCount + " fix2.probes=" + fix2.probeCount + " delta=" + fixDelta);
}
// Helpers
static void assertEqual(String label, int expected, int actual) {
if (expected == actual) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — expected %d, got %d%n", label, expected, actual);
failed++;
}
}
static void assertTrue(String label, boolean condition, String detail) {
if (condition) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — %s%n", label, detail);
failed++;
}
}
}

View file

@ -0,0 +1,174 @@
package unit;
import support.Moad0009Algorithm;
import support.Moad0009Algorithm.Event;
import support.Moad0009Algorithm.Result;
import java.util.List;
/**
* Unit tests for MOAD-0009: A Metered Heart.
*
* Proves from first principles:
* 1. Defective scheduler fires on every timer tick (N firings for N ticks)
* even when only M events occur N - M firings are wasted.
* 2. Fixed event-driven handler fires exactly once per event (M firings for M events).
* 3. Both correctly process the same set of events (same events handled).
* 4. Defective wastes fire count grows with poll interval; fixed stays constant.
* 5. Zero-event scenario: defective fires N times on empty queue; fixed fires 0.
*
* No build tool required. Compile and run:
*
* cd tests
* java -m jdk.compiler/com.sun.tools.javac.Main -cp . \
* support/Moad0009Algorithm.java unit/Moad0009UnitTest.java
* java -cp . unit.Moad0009UnitTest
*/
public class Moad0009UnitTest {
private static int passed = 0;
private static int failed = 0;
public static void main(String[] args) {
System.out.println("=== Moad0009UnitTest (A Metered Heart) ===\n");
System.out.println("-- Correctness: both process the same events --");
testBothProcessSameEvents();
testBothHandleNoEvents();
System.out.println("\n-- Defect: timer fires N times regardless of M events --");
testDefectiveFiresEveryTick();
testDefectiveWastedFiresN100M3();
testDefectiveZeroEventsStillFiresN();
System.out.println("\n-- Fix: fires exactly once per event --");
testFixedFiresExactlyMTimes();
testFixedZeroEventsZeroFirings();
testFixedFireCountEqualsEventCount();
System.out.println("\n-- Comparison: defective wastes grow with poll count; fixed stays M --");
testWastedFiresGrowWithPollCount();
System.out.printf("\n%d passed, %d failed%n", passed, failed);
if (failed > 0) System.exit(1);
}
// Correctness
static void testBothProcessSameEvents() {
List<Event> events = Moad0009Algorithm.buildEvents(3, 10);
Result def = Moad0009Algorithm.runDefectiveScheduler(20, events);
Result fix = Moad0009Algorithm.runFixedEventDriven(events);
assertEqual("correctness: both process same event count", def.eventsProcessed, fix.eventsProcessed);
assertEqual("correctness: both process all 3 events", 3, def.eventsProcessed);
}
static void testBothHandleNoEvents() {
List<Event> events = List.of();
Result def = Moad0009Algorithm.runDefectiveScheduler(10, events);
Result fix = Moad0009Algorithm.runFixedEventDriven(events);
assertEqual("correctness: both process 0 events from empty list", 0, def.eventsProcessed);
assertEqual("correctness: fixed: 0 events processed", 0, fix.eventsProcessed);
}
// Defect
static void testDefectiveFiresEveryTick() {
int ticks = 50;
List<Event> events = Moad0009Algorithm.buildEvents(2, ticks);
Result result = Moad0009Algorithm.runDefectiveScheduler(ticks, events);
// DEFECT: fires every tick regardless of events
assertEqual("defective: fires exactly N=" + ticks + " times", ticks, result.firings);
}
static void testDefectiveWastedFiresN100M3() {
int ticks = 100;
int eventCount = 3;
List<Event> events = Moad0009Algorithm.buildEvents(eventCount, ticks);
Result result = Moad0009Algorithm.runDefectiveScheduler(ticks, events);
// DEFECT: 100 firings for 3 events = 97 wasted firings (97% waste)
int wasted = result.firings - result.eventsProcessed;
assertEqual("defective: 97 wasted firings (100 ticks, 3 events)", 97, wasted);
assertTrue("defective: waste ratio > 95%",
(double) wasted / result.firings > 0.95,
"wasted=" + wasted + " total=" + result.firings);
}
static void testDefectiveZeroEventsStillFiresN() {
int ticks = 60;
List<Event> events = List.of();
Result result = Moad0009Algorithm.runDefectiveScheduler(ticks, events);
// DEFECT: no events exist, but timer still fires 60 times pure waste
assertEqual("defective: 0 events, fires N=" + ticks + " times (100% waste)", ticks, result.firings);
assertEqual("defective: 0 events processed", 0, result.eventsProcessed);
}
// Fix
static void testFixedFiresExactlyMTimes() {
List<Event> events = Moad0009Algorithm.buildEvents(5, 100);
Result result = Moad0009Algorithm.runFixedEventDriven(events);
assertEqual("fixed: fires exactly M=5 times (one per event)", 5, result.firings);
}
static void testFixedZeroEventsZeroFirings() {
List<Event> events = List.of();
Result result = Moad0009Algorithm.runFixedEventDriven(events);
assertEqual("fixed: 0 events → 0 firings (no wasted work)", 0, result.firings);
}
static void testFixedFireCountEqualsEventCount() {
for (int m : new int[]{1, 7, 23, 100}) {
List<Event> events = Moad0009Algorithm.buildEvents(m, 200);
Result result = Moad0009Algorithm.runFixedEventDriven(events);
assertEqual("fixed: M=" + m + " events → exactly M=" + m + " firings",
m, result.firings);
}
}
// Comparison
static void testWastedFiresGrowWithPollCount() {
List<Event> events = Moad0009Algorithm.buildEvents(2, 200);
// More ticks = more waste in defective; fixed stays at M=2
Result def50 = Moad0009Algorithm.runDefectiveScheduler(50, events);
Result def200 = Moad0009Algorithm.runDefectiveScheduler(200, events);
Result fix = Moad0009Algorithm.runFixedEventDriven(events);
assertTrue("defective: 50 ticks → 50 firings", def50.firings == 50, "got " + def50.firings);
assertTrue("defective: 200 ticks → 200 firings", def200.firings == 200, "got " + def200.firings);
assertTrue("fixed: always 2 firings regardless of tick count", fix.firings == 2, "got " + fix.firings);
// Wasted = defective.firings - events processed
int waste50 = def50.firings - def50.eventsProcessed;
int waste200 = def200.firings - def200.eventsProcessed;
assertTrue("defective: waste grows with tick count (200 > 50)",
waste200 > waste50, "waste50=" + waste50 + " waste200=" + waste200);
}
// Helpers
static void assertEqual(String label, int expected, int actual) {
if (expected == actual) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — expected %d, got %d%n", label, expected, actual);
failed++;
}
}
static void assertTrue(String label, boolean condition, String detail) {
if (condition) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — %s%n", label, detail);
failed++;
}
}
}

View file

@ -0,0 +1,210 @@
package unit;
import support.Moad0011Algorithm;
import support.Moad0011Algorithm.Result;
/**
* Unit tests for MOAD-0011: CWE-1333 A Catastrophic Inheritance.
*
* Proves from first principles:
* 1. Structural: hasCatastrophicStructure() detects nested quantifiers in
* known-bad patterns and passes known-safe patterns.
* 2. Behavioral (step counting): defective NFA for (a+)+b explores
* exponentially many states on adversarial input; fixed NFA is linear.
* 3. Growth: doubling adversarial input length more than doubles defective
* steps (super-linear / exponential growth); fixed steps grow exactly linearly.
* 4. Both produce identical match results on matching and non-matching inputs.
*
* The step-counting NFA proves the algorithmic complexity without relying on
* wall-clock timing suitable for deterministic unit testing. Functional tests
* use a timed match on a moderate adversarial input to prove behavioral impact.
*
* No build tool required. Compile and run:
*
* cd tests
* java -m jdk.compiler/com.sun.tools.javac.Main -cp . \
* support/Moad0011Algorithm.java unit/Moad0011UnitTest.java
* java -cp . unit.Moad0011UnitTest
*/
public class Moad0011UnitTest {
private static int passed = 0;
private static int failed = 0;
public static void main(String[] args) {
System.out.println("=== Moad0011UnitTest (A Catastrophic Inheritance) ===\n");
System.out.println("-- Structural detection: hasCatastrophicStructure() --");
testDetectsKnownBadPatterns();
testPassesKnownSafePatterns();
System.out.println("\n-- Correctness: both produce identical match results --");
testBothMatchMatchingInput();
testBothRejectNonMatchingInput();
testBothMatchSingleA();
System.out.println("\n-- Defect: step count grows super-linearly on adversarial input --");
testDefectiveStepCountExponentialGrowth();
testDefectiveAdversarialN8IsLarge();
System.out.println("\n-- Fix: step count grows linearly on adversarial input --");
testFixedStepCountLinearGrowth();
testFixedAdversarialN8IsSmall();
System.out.println("\n-- Ratio: defective steps >> fixed steps on adversarial input --");
testStepRatioAdvantageForFixed();
System.out.printf("\n%d passed, %d failed%n", passed, failed);
if (failed > 0) System.exit(1);
}
// Structural detection
static void testDetectsKnownBadPatterns() {
String[] bad = {
"(a+)+b", // classic ReDoS outer + wraps inner a+
"(a+)+", // same, no terminal
"(a*)+", // inner * outer +
"(ab+c*)+", // complex inner group with quantifiers
Moad0011Algorithm.DEFECTIVE_PATTERN_BLEACH,
Moad0011Algorithm.DEFECTIVE_PATTERN_CSS,
};
for (String p : bad) {
assertTrue("detects bad pattern: " + p,
Moad0011Algorithm.hasCatastrophicStructure(p),
"expected catastrophic, got safe");
}
}
static void testPassesKnownSafePatterns() {
String[] safe = {
"a+b", // simple concatenation no nesting
"a+", // single quantifier
"(a|b)+", // alternation with outer +, no inner quantifier
"[a-z]+", // character class, single quantifier
"(abc)+", // fixed group, no inner quantifier
Moad0011Algorithm.FIXED_PATTERN_BLEACH,
Moad0011Algorithm.FIXED_PATTERN_CSS,
};
for (String p : safe) {
assertFalse("passes safe pattern: " + p,
Moad0011Algorithm.hasCatastrophicStructure(p),
"expected safe, got catastrophic");
}
}
// Correctness
static void testBothMatchMatchingInput() {
String input = Moad0011Algorithm.matchingInput(5); // "aaaaab"
Result def = Moad0011Algorithm.matchDefective(input);
Result fix = Moad0011Algorithm.matchFixed(input);
assertTrue("defective: matches 'aaaaab'", def.matched, "expected match");
assertTrue("fixed: matches 'aaaaab'", fix.matched, "expected match");
}
static void testBothRejectNonMatchingInput() {
String input = Moad0011Algorithm.adversarialInput(5); // "aaaaac" no 'b'
Result def = Moad0011Algorithm.matchDefective(input);
Result fix = Moad0011Algorithm.matchFixed(input);
assertFalse("defective: rejects 'aaaaac'", def.matched, "expected no match");
assertFalse("fixed: rejects 'aaaaac'", fix.matched, "expected no match");
}
static void testBothMatchSingleA() {
String input = "ab";
Result def = Moad0011Algorithm.matchDefective(input);
Result fix = Moad0011Algorithm.matchFixed(input);
assertTrue("defective: matches 'ab'", def.matched, "expected match");
assertTrue("fixed: matches 'ab'", fix.matched, "expected match");
}
// Defect
static void testDefectiveStepCountExponentialGrowth() {
// Adversarial input: N a's + 'c' non-matching, forces maximum backtracking
long steps4 = Moad0011Algorithm.matchDefective(Moad0011Algorithm.adversarialInput(4)).steps;
long steps6 = Moad0011Algorithm.matchDefective(Moad0011Algorithm.adversarialInput(6)).steps;
long steps8 = Moad0011Algorithm.matchDefective(Moad0011Algorithm.adversarialInput(8)).steps;
// Exponential growth: steps8 >> steps6 >> steps4
// Ratio should be super-linear (greater than linear doubling)
double ratio64 = (double) steps6 / steps4;
double ratio86 = (double) steps8 / steps6;
assertTrue("defective: steps grow super-linearly from N=4 to N=6 (ratio > 2.0)",
ratio64 > 2.0, "ratio64=" + ratio64);
assertTrue("defective: steps grow super-linearly from N=6 to N=8 (ratio > 2.0)",
ratio86 > 2.0, "ratio86=" + ratio86);
System.out.printf(" steps N=4: %d, N=6: %d, N=8: %d (ratios: %.1fx, %.1fx)%n",
steps4, steps6, steps8, ratio64, ratio86);
}
static void testDefectiveAdversarialN8IsLarge() {
long steps = Moad0011Algorithm.matchDefective(Moad0011Algorithm.adversarialInput(8)).steps;
// N=8 adversarial input: expect hundreds or thousands of steps (super-linear)
assertTrue("defective: N=8 adversarial input requires many steps (>50)",
steps > 50, "steps=" + steps);
}
// Fix
static void testFixedStepCountLinearGrowth() {
long steps4 = Moad0011Algorithm.matchFixed(Moad0011Algorithm.adversarialInput(4)).steps;
long steps8 = Moad0011Algorithm.matchFixed(Moad0011Algorithm.adversarialInput(8)).steps;
long steps16 = Moad0011Algorithm.matchFixed(Moad0011Algorithm.adversarialInput(16)).steps;
// Linear growth: doubling N should roughly double steps (ratio ~2x)
double ratio84 = (double) steps8 / steps4;
double ratio168 = (double) steps16 / steps8;
// Allow ratio up to 3.0 to be generous with small constants, but it must not be exponential
assertTrue("fixed: doubling N from 4 to 8 roughly doubles steps (ratio 1.0-3.0)",
ratio84 >= 1.0 && ratio84 <= 3.0, "ratio84=" + ratio84);
assertTrue("fixed: doubling N from 8 to 16 roughly doubles steps (ratio 1.0-3.0)",
ratio168 >= 1.0 && ratio168 <= 3.0, "ratio168=" + ratio168);
System.out.printf(" steps N=4: %d, N=8: %d, N=16: %d (ratios: %.1fx, %.1fx)%n",
steps4, steps8, steps16, ratio84, ratio168);
}
static void testFixedAdversarialN8IsSmall() {
long steps = Moad0011Algorithm.matchFixed(Moad0011Algorithm.adversarialInput(8)).steps;
// Fixed NFA: O(N) steps N=8 means steps should be a small multiple of 8
assertTrue("fixed: N=8 adversarial requires <= 20 steps (linear)",
steps <= 20, "steps=" + steps);
}
// Ratio
static void testStepRatioAdvantageForFixed() {
String adversarial = Moad0011Algorithm.adversarialInput(10);
long defSteps = Moad0011Algorithm.matchDefective(adversarial).steps;
long fixSteps = Moad0011Algorithm.matchFixed(adversarial).steps;
// At N=10, defective explores exponentially many states vs fixed linear scan
double ratio = (double) defSteps / fixSteps;
assertTrue("defective steps >> fixed steps at N=10 adversarial (ratio > 10x)",
ratio > 10.0, "defSteps=" + defSteps + " fixSteps=" + fixSteps + " ratio=" + ratio);
System.out.printf(" N=10 adversarial: defective=%d steps, fixed=%d steps (%.0fx advantage)%n",
defSteps, fixSteps, ratio);
}
// Helpers
static void assertTrue(String label, boolean condition, String detail) {
if (condition) {
System.out.printf(" PASS: %s%n", label);
passed++;
} else {
System.out.printf(" FAIL: %s — %s%n", label, detail);
failed++;
}
}
static void assertFalse(String label, boolean condition, String detail) {
assertTrue(label, !condition, detail);
}
}