diff --git a/src/main/java/de/rub/nds/scanner/core/execution/Scanner.java b/src/main/java/de/rub/nds/scanner/core/execution/Scanner.java index 1aa896c2..4f0f11be 100644 --- a/src/main/java/de/rub/nds/scanner/core/execution/Scanner.java +++ b/src/main/java/de/rub/nds/scanner/core/execution/Scanner.java @@ -58,10 +58,25 @@ public abstract class Scanner< * @param executorConfig The executor configuration to use. */ public Scanner(ExecutorConfig executorConfig) { + this(executorConfig, (ProbeProgressCallback) null); + } + + /** + * Creates a new scanner instance with a progress callback. + * + * @param executorConfig The executor configuration to use. + * @param progressCallback the callback to invoke on probe completion, or null for no callbacks + */ + public Scanner( + ExecutorConfig executorConfig, + ProbeProgressCallback progressCallback) { this.executorConfig = executorConfig; probeList = new LinkedList<>(); afterList = new LinkedList<>(); fillProbeListsAtScanStart = true; + if (progressCallback != null) { + this.progressCallback = progressCallback; + } } /** @@ -73,10 +88,29 @@ public Scanner(ExecutorConfig executorConfig) { */ public Scanner( ExecutorConfig executorConfig, List probeList, List afterList) { + this(executorConfig, probeList, afterList, null); + } + + /** + * Creates a new scanner instance with a progress callback. + * + * @param executorConfig The executor configuration to use. + * @param probeList The list of probes to execute. + * @param afterList The list of after probes to execute. + * @param progressCallback the callback to invoke on probe completion, or null for no callbacks + */ + public Scanner( + ExecutorConfig executorConfig, + List probeList, + List afterList, + ProbeProgressCallback progressCallback) { this.executorConfig = executorConfig; this.probeList = new LinkedList<>(probeList); this.afterList = new LinkedList<>(afterList); fillProbeListsAtScanStart = false; + if (progressCallback != null) { + this.progressCallback = progressCallback; + } } /** diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java index 60c3622e..f7559a7e 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java @@ -151,11 +151,25 @@ static class TestScanner extends Scanner progressCallback) { + super(config, progressCallback); + } + TestScanner( ExecutorConfig config, List probeList, List afterList) { super(config, probeList, afterList); } + TestScanner( + ExecutorConfig config, + List probeList, + List afterList, + ProbeProgressCallback progressCallback) { + super(config, probeList, afterList, progressCallback); + } + @Override public void close() { // Implementation for AutoCloseable @@ -506,4 +520,75 @@ public void testProgressCallbackReportsCorrectProbeCount() { // Verify callback was invoked for each probe assertEquals(expectedProbeCount, completedCounts.size()); } + + // ---- Constructor-based progress callback tests ---- + + @Test + public void testConstructorWithCallbackIsInvoked() { + List probeList = new ArrayList<>(); + probeList.add(new TestProbe(new TestProbeType("probe1"))); + probeList.add(new TestProbe(new TestProbeType("probe2"))); + + List afterList = new ArrayList<>(); + + final int[] callbackInvocations = {0}; + ProbeProgressCallback callback = + (probe, report, completedProbes, totalProbes) -> callbackInvocations[0]++; + + try (TestScanner scanner = + new TestScanner(executorConfig, probeList, afterList, callback)) { + scanner.scan(); + } + + assertEquals(2, callbackInvocations[0], "Constructor callback should be invoked per probe"); + } + + @Test + public void testConstructorWithNullCallbackScansSuccessfully() { + try (TestScanner scanner = new TestScanner(executorConfig, null)) { + TestReport report = scanner.scan(); + assertNotNull(report); + } + } + + @Test + public void testDefaultConstructorCallbackIsInvokedViaFillProbes() { + final int[] callbackInvocations = {0}; + ProbeProgressCallback callback = + (probe, report, completedProbes, totalProbes) -> callbackInvocations[0]++; + + try (TestScanner scanner = new TestScanner(executorConfig, callback)) { + // fillProbeLists will be called; no probes added so callback won't fire + TestReport report = scanner.scan(); + assertNotNull(report); + assertTrue(scanner.isFillProbesCalled()); + } + + assertEquals(0, callbackInvocations[0], "No probes registered so callback should not fire"); + } + + @Test + public void testConstructorCallbackReportsCorrectProbeCount() { + List probeList = new ArrayList<>(); + int expectedProbeCount = 3; + for (int i = 0; i < expectedProbeCount; i++) { + probeList.add(new TestProbe(new TestProbeType("probe" + i))); + } + + List afterList = new ArrayList<>(); + + final List completedCounts = new ArrayList<>(); + ProbeProgressCallback callback = + (probe, report, completedProbes, totalProbes) -> { + assertEquals(expectedProbeCount, totalProbes); + completedCounts.add(completedProbes); + }; + + try (TestScanner scanner = + new TestScanner(executorConfig, probeList, afterList, callback)) { + scanner.scan(); + } + + assertEquals(expectedProbeCount, completedCounts.size()); + } }