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 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 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 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 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 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 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 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 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 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 s1 = Moad0007Algorithm.buildScene(N1, 1000.0); List 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++; } } }