1
0

Meilenstein-Präfixe aus Klassennamen entfernt

This commit is contained in:
2026-04-02 09:11:52 +02:00
parent c0cdd0ed6e
commit 7d5c21f14c
21 changed files with 501 additions and 455 deletions

View File

@@ -1,10 +1,10 @@
package de.gecheckt.pdf.umbenenner.application.service;
import de.gecheckt.pdf.umbenenner.application.config.StartConfiguration;
import de.gecheckt.pdf.umbenenner.domain.model.M3DocumentProcessingOutcome;
import de.gecheckt.pdf.umbenenner.domain.model.M3PreCheckFailed;
import de.gecheckt.pdf.umbenenner.domain.model.M3PreCheckPassed;
import de.gecheckt.pdf.umbenenner.domain.model.M3TechnicalDocumentError;
import de.gecheckt.pdf.umbenenner.domain.model.DocumentProcessingOutcome;
import de.gecheckt.pdf.umbenenner.domain.model.PreCheckFailed;
import de.gecheckt.pdf.umbenenner.domain.model.PreCheckPassed;
import de.gecheckt.pdf.umbenenner.domain.model.TechnicalDocumentError;
import de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionContentError;
import de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionSuccess;
import de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionTechnicalError;
@@ -23,11 +23,11 @@ import java.nio.file.Path;
import static org.junit.jupiter.api.Assertions.*;
/**
* Tests for {@link M3DocumentProcessingService}.
* Tests for {@link DocumentProcessingService}.
* <p>
* Verifies that all four M3 document processing outcomes are correctly classified.
* Verifies that all document processing outcomes are correctly classified.
*/
class M3DocumentProcessingServiceTest {
class DocumentProcessingServiceTest {
@TempDir
Path tempDir;
@@ -75,12 +75,12 @@ class M3DocumentProcessingServiceTest {
var extraction = new PdfExtractionSuccess("This is valid PDF text", new PdfPageCount(5));
// Act
M3DocumentProcessingOutcome outcome = M3DocumentProcessingService.processDocument(
DocumentProcessingOutcome outcome = DocumentProcessingService.processDocument(
candidate, extraction, configuration);
// Assert: Should produce M3PreCheckPassed
assertInstanceOf(M3PreCheckPassed.class, outcome);
M3PreCheckPassed passed = (M3PreCheckPassed) outcome;
// Assert: Should produce PreCheckPassed
assertInstanceOf(PreCheckPassed.class, outcome);
PreCheckPassed passed = (PreCheckPassed) outcome;
assertEquals(candidate, passed.candidate());
assertEquals(extraction, passed.extraction());
}
@@ -91,12 +91,12 @@ class M3DocumentProcessingServiceTest {
var extraction = new PdfExtractionSuccess(" \n \t ", new PdfPageCount(1));
// Act
M3DocumentProcessingOutcome outcome = M3DocumentProcessingService.processDocument(
DocumentProcessingOutcome outcome = DocumentProcessingService.processDocument(
candidate, extraction, configuration);
// Assert: Should produce M3PreCheckFailed with appropriate reason
assertInstanceOf(M3PreCheckFailed.class, outcome);
M3PreCheckFailed failed = (M3PreCheckFailed) outcome;
// Assert: Should produce PreCheckFailed with appropriate reason
assertInstanceOf(PreCheckFailed.class, outcome);
PreCheckFailed failed = (PreCheckFailed) outcome;
assertEquals(candidate, failed.candidate());
assertTrue(failed.failureReason().toLowerCase().contains("usable"));
}
@@ -107,28 +107,28 @@ class M3DocumentProcessingServiceTest {
var extraction = new PdfExtractionSuccess("Valid text content", new PdfPageCount(50));
// Act
M3DocumentProcessingOutcome outcome = M3DocumentProcessingService.processDocument(
DocumentProcessingOutcome outcome = DocumentProcessingService.processDocument(
candidate, extraction, configuration);
// Assert: Should produce M3PreCheckFailed with page limit reason
assertInstanceOf(M3PreCheckFailed.class, outcome);
M3PreCheckFailed failed = (M3PreCheckFailed) outcome;
// Assert: Should produce PreCheckFailed with page limit reason
assertInstanceOf(PreCheckFailed.class, outcome);
PreCheckFailed failed = (PreCheckFailed) outcome;
assertEquals(candidate, failed.candidate());
assertTrue(failed.failureReason().toLowerCase().contains("page"));
}
@Test
void testProcessDocument_WithContentError() {
// Arrange: PDF content not extractable (classified as technical document error in M3)
// Arrange: PDF content not extractable (classified as technical document error)
var contentError = new PdfExtractionContentError("PDF is corrupted");
// Act
M3DocumentProcessingOutcome outcome = M3DocumentProcessingService.processDocument(
DocumentProcessingOutcome outcome = DocumentProcessingService.processDocument(
candidate, contentError, configuration);
// Assert: Should produce M3TechnicalDocumentError
assertInstanceOf(M3TechnicalDocumentError.class, outcome);
M3TechnicalDocumentError result = (M3TechnicalDocumentError) outcome;
// Assert: Should produce TechnicalDocumentError
assertInstanceOf(TechnicalDocumentError.class, outcome);
TechnicalDocumentError result = (TechnicalDocumentError) outcome;
assertEquals(candidate, result.candidate());
assertTrue(result.errorMessage().contains("PDF is corrupted"));
}
@@ -140,12 +140,12 @@ class M3DocumentProcessingServiceTest {
new RuntimeException("File not found"));
// Act
M3DocumentProcessingOutcome outcome = M3DocumentProcessingService.processDocument(
DocumentProcessingOutcome outcome = DocumentProcessingService.processDocument(
candidate, technicalError, configuration);
// Assert: Should produce M3TechnicalDocumentError
assertInstanceOf(M3TechnicalDocumentError.class, outcome);
M3TechnicalDocumentError result = (M3TechnicalDocumentError) outcome;
// Assert: Should produce TechnicalDocumentError
assertInstanceOf(TechnicalDocumentError.class, outcome);
TechnicalDocumentError result = (TechnicalDocumentError) outcome;
assertEquals(candidate, result.candidate());
assertEquals("I/O error reading file", result.errorMessage());
assertNotNull(result.cause());
@@ -157,12 +157,12 @@ class M3DocumentProcessingServiceTest {
var technicalError = new PdfExtractionTechnicalError("Unknown error", null);
// Act
M3DocumentProcessingOutcome outcome = M3DocumentProcessingService.processDocument(
DocumentProcessingOutcome outcome = DocumentProcessingService.processDocument(
candidate, technicalError, configuration);
// Assert
assertInstanceOf(M3TechnicalDocumentError.class, outcome);
M3TechnicalDocumentError result = (M3TechnicalDocumentError) outcome;
assertInstanceOf(TechnicalDocumentError.class, outcome);
TechnicalDocumentError result = (TechnicalDocumentError) outcome;
assertNull(result.cause());
}
@@ -173,14 +173,14 @@ class M3DocumentProcessingServiceTest {
// Act & Assert
assertThrows(NullPointerException.class,
() -> M3DocumentProcessingService.processDocument(null, extraction, configuration));
() -> DocumentProcessingService.processDocument(null, extraction, configuration));
}
@Test
void testProcessDocument_WithNullExtractionResult_ThrowsException() {
// Act & Assert
assertThrows(NullPointerException.class,
() -> M3DocumentProcessingService.processDocument(candidate, null, configuration));
() -> DocumentProcessingService.processDocument(candidate, null, configuration));
}
@Test
@@ -190,6 +190,6 @@ class M3DocumentProcessingServiceTest {
// Act & Assert
assertThrows(NullPointerException.class,
() -> M3DocumentProcessingService.processDocument(candidate, extraction, null));
() -> DocumentProcessingService.processDocument(candidate, extraction, null));
}
}
}

View File

@@ -1,10 +1,10 @@
package de.gecheckt.pdf.umbenenner.application.service;
import de.gecheckt.pdf.umbenenner.application.config.StartConfiguration;
import de.gecheckt.pdf.umbenenner.domain.model.M3DocumentProcessingOutcome;
import de.gecheckt.pdf.umbenenner.domain.model.M3PreCheckFailed;
import de.gecheckt.pdf.umbenenner.domain.model.M3PreCheckFailureReason;
import de.gecheckt.pdf.umbenenner.domain.model.M3PreCheckPassed;
import de.gecheckt.pdf.umbenenner.domain.model.DocumentProcessingOutcome;
import de.gecheckt.pdf.umbenenner.domain.model.PreCheckFailed;
import de.gecheckt.pdf.umbenenner.domain.model.PreCheckFailureReason;
import de.gecheckt.pdf.umbenenner.domain.model.PreCheckPassed;
import de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionSuccess;
import de.gecheckt.pdf.umbenenner.domain.model.PdfPageCount;
import de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentCandidate;
@@ -20,11 +20,11 @@ import java.nio.file.Path;
import static org.junit.jupiter.api.Assertions.*;
/**
* Tests for {@link M3PreCheckEvaluator}.
* Tests for {@link PreCheckEvaluator}.
* <p>
* Verifies correct M3 pre-check logic for usable text and page limit validation.
* Verifies correct pre-check logic for usable text and page limit validation.
*/
class M3PreCheckEvaluatorTest {
class PreCheckEvaluatorTest {
@TempDir
Path tempDir;
@@ -35,10 +35,10 @@ class M3PreCheckEvaluatorTest {
SourceDocumentCandidate candidate = buildCandidate();
PdfExtractionSuccess extraction = new PdfExtractionSuccess("Some meaningful text", new PdfPageCount(5));
M3DocumentProcessingOutcome result = M3PreCheckEvaluator.evaluate(candidate, extraction, config);
DocumentProcessingOutcome result = PreCheckEvaluator.evaluate(candidate, extraction, config);
assertTrue(result instanceof M3PreCheckPassed, "Should pass when text is usable and page count is valid");
M3PreCheckPassed passed = (M3PreCheckPassed) result;
assertTrue(result instanceof PreCheckPassed, "Should pass when text is usable and page count is valid");
PreCheckPassed passed = (PreCheckPassed) result;
assertSame(passed.candidate(), candidate, "Candidate should be preserved");
assertSame(passed.extraction(), extraction, "Extraction should be preserved");
}
@@ -49,11 +49,11 @@ class M3PreCheckEvaluatorTest {
SourceDocumentCandidate candidate = buildCandidate();
PdfExtractionSuccess extraction = new PdfExtractionSuccess("", new PdfPageCount(1));
M3DocumentProcessingOutcome result = M3PreCheckEvaluator.evaluate(candidate, extraction, config);
DocumentProcessingOutcome result = PreCheckEvaluator.evaluate(candidate, extraction, config);
assertTrue(result instanceof M3PreCheckFailed, "Should fail with empty text");
M3PreCheckFailed failed = (M3PreCheckFailed) result;
assertEquals(M3PreCheckFailureReason.NO_USABLE_TEXT.getDescription(), failed.failureReason());
assertTrue(result instanceof PreCheckFailed, "Should fail with empty text");
PreCheckFailed failed = (PreCheckFailed) result;
assertEquals(PreCheckFailureReason.NO_USABLE_TEXT.getDescription(), failed.failureReason());
}
@Test
@@ -62,11 +62,11 @@ class M3PreCheckEvaluatorTest {
SourceDocumentCandidate candidate = buildCandidate();
PdfExtractionSuccess extraction = new PdfExtractionSuccess(" \n\t \r\n ", new PdfPageCount(1));
M3DocumentProcessingOutcome result = M3PreCheckEvaluator.evaluate(candidate, extraction, config);
DocumentProcessingOutcome result = PreCheckEvaluator.evaluate(candidate, extraction, config);
assertTrue(result instanceof M3PreCheckFailed, "Should fail with whitespace-only text");
M3PreCheckFailed failed = (M3PreCheckFailed) result;
assertEquals(M3PreCheckFailureReason.NO_USABLE_TEXT.getDescription(), failed.failureReason());
assertTrue(result instanceof PreCheckFailed, "Should fail with whitespace-only text");
PreCheckFailed failed = (PreCheckFailed) result;
assertEquals(PreCheckFailureReason.NO_USABLE_TEXT.getDescription(), failed.failureReason());
}
@Test
@@ -75,11 +75,11 @@ class M3PreCheckEvaluatorTest {
SourceDocumentCandidate candidate = buildCandidate();
PdfExtractionSuccess extraction = new PdfExtractionSuccess("!@#$%^&*()_+-=[]{}|;:',.<>?/", new PdfPageCount(1));
M3DocumentProcessingOutcome result = M3PreCheckEvaluator.evaluate(candidate, extraction, config);
DocumentProcessingOutcome result = PreCheckEvaluator.evaluate(candidate, extraction, config);
assertTrue(result instanceof M3PreCheckFailed, "Should fail with special characters only");
M3PreCheckFailed failed = (M3PreCheckFailed) result;
assertEquals(M3PreCheckFailureReason.NO_USABLE_TEXT.getDescription(), failed.failureReason());
assertTrue(result instanceof PreCheckFailed, "Should fail with special characters only");
PreCheckFailed failed = (PreCheckFailed) result;
assertEquals(PreCheckFailureReason.NO_USABLE_TEXT.getDescription(), failed.failureReason());
}
@Test
@@ -88,9 +88,9 @@ class M3PreCheckEvaluatorTest {
SourceDocumentCandidate candidate = buildCandidate();
PdfExtractionSuccess extraction = new PdfExtractionSuccess("a", new PdfPageCount(1));
M3DocumentProcessingOutcome result = M3PreCheckEvaluator.evaluate(candidate, extraction, config);
DocumentProcessingOutcome result = PreCheckEvaluator.evaluate(candidate, extraction, config);
assertTrue(result instanceof M3PreCheckPassed, "Should pass with single letter");
assertTrue(result instanceof PreCheckPassed, "Should pass with single letter");
}
@Test
@@ -99,9 +99,9 @@ class M3PreCheckEvaluatorTest {
SourceDocumentCandidate candidate = buildCandidate();
PdfExtractionSuccess extraction = new PdfExtractionSuccess("5", new PdfPageCount(1));
M3DocumentProcessingOutcome result = M3PreCheckEvaluator.evaluate(candidate, extraction, config);
DocumentProcessingOutcome result = PreCheckEvaluator.evaluate(candidate, extraction, config);
assertTrue(result instanceof M3PreCheckPassed, "Should pass with single digit");
assertTrue(result instanceof PreCheckPassed, "Should pass with single digit");
}
@Test
@@ -110,9 +110,9 @@ class M3PreCheckEvaluatorTest {
SourceDocumentCandidate candidate = buildCandidate();
PdfExtractionSuccess extraction = new PdfExtractionSuccess("!@#a$%^&*", new PdfPageCount(1));
M3DocumentProcessingOutcome result = M3PreCheckEvaluator.evaluate(candidate, extraction, config);
DocumentProcessingOutcome result = PreCheckEvaluator.evaluate(candidate, extraction, config);
assertTrue(result instanceof M3PreCheckPassed, "Should pass when letters/digits are present among special chars");
assertTrue(result instanceof PreCheckPassed, "Should pass when letters/digits are present among special chars");
}
@Test
@@ -121,9 +121,9 @@ class M3PreCheckEvaluatorTest {
SourceDocumentCandidate candidate = buildCandidate();
PdfExtractionSuccess extraction = new PdfExtractionSuccess(" meaningful text ", new PdfPageCount(1));
M3DocumentProcessingOutcome result = M3PreCheckEvaluator.evaluate(candidate, extraction, config);
DocumentProcessingOutcome result = PreCheckEvaluator.evaluate(candidate, extraction, config);
assertTrue(result instanceof M3PreCheckPassed, "Should pass when text has meaningful content despite whitespace");
assertTrue(result instanceof PreCheckPassed, "Should pass when text has meaningful content despite whitespace");
}
@Test
@@ -132,9 +132,9 @@ class M3PreCheckEvaluatorTest {
SourceDocumentCandidate candidate = buildCandidate();
PdfExtractionSuccess extraction = new PdfExtractionSuccess("Valid text", new PdfPageCount(5));
M3DocumentProcessingOutcome result = M3PreCheckEvaluator.evaluate(candidate, extraction, config);
DocumentProcessingOutcome result = PreCheckEvaluator.evaluate(candidate, extraction, config);
assertTrue(result instanceof M3PreCheckPassed, "Should pass when page count equals limit (not exceeded)");
assertTrue(result instanceof PreCheckPassed, "Should pass when page count equals limit (not exceeded)");
}
@Test
@@ -143,11 +143,11 @@ class M3PreCheckEvaluatorTest {
SourceDocumentCandidate candidate = buildCandidate();
PdfExtractionSuccess extraction = new PdfExtractionSuccess("Valid text", new PdfPageCount(6));
M3DocumentProcessingOutcome result = M3PreCheckEvaluator.evaluate(candidate, extraction, config);
DocumentProcessingOutcome result = PreCheckEvaluator.evaluate(candidate, extraction, config);
assertTrue(result instanceof M3PreCheckFailed, "Should fail when page count exceeds limit");
M3PreCheckFailed failed = (M3PreCheckFailed) result;
assertEquals(M3PreCheckFailureReason.PAGE_LIMIT_EXCEEDED.getDescription(), failed.failureReason());
assertTrue(result instanceof PreCheckFailed, "Should fail when page count exceeds limit");
PreCheckFailed failed = (PreCheckFailed) result;
assertEquals(PreCheckFailureReason.PAGE_LIMIT_EXCEEDED.getDescription(), failed.failureReason());
}
@Test
@@ -156,11 +156,11 @@ class M3PreCheckEvaluatorTest {
SourceDocumentCandidate candidate = buildCandidate();
PdfExtractionSuccess extraction = new PdfExtractionSuccess("Excellent meaningful text with lots of content", new PdfPageCount(100));
M3DocumentProcessingOutcome result = M3PreCheckEvaluator.evaluate(candidate, extraction, config);
DocumentProcessingOutcome result = PreCheckEvaluator.evaluate(candidate, extraction, config);
assertTrue(result instanceof M3PreCheckFailed, "Should fail with page limit exceeded even if text is good");
M3PreCheckFailed failed = (M3PreCheckFailed) result;
assertEquals(M3PreCheckFailureReason.PAGE_LIMIT_EXCEEDED.getDescription(), failed.failureReason());
assertTrue(result instanceof PreCheckFailed, "Should fail with page limit exceeded even if text is good");
PreCheckFailed failed = (PreCheckFailed) result;
assertEquals(PreCheckFailureReason.PAGE_LIMIT_EXCEEDED.getDescription(), failed.failureReason());
}
@Test
@@ -171,11 +171,11 @@ class M3PreCheckEvaluatorTest {
SourceDocumentCandidate candidate = buildCandidate();
PdfExtractionSuccess extraction = new PdfExtractionSuccess("", new PdfPageCount(10));
M3DocumentProcessingOutcome result = M3PreCheckEvaluator.evaluate(candidate, extraction, config);
DocumentProcessingOutcome result = PreCheckEvaluator.evaluate(candidate, extraction, config);
assertTrue(result instanceof M3PreCheckFailed, "Should fail when both checks fail");
// The specific order of checks doesn't matter for M3; just verify one reason is returned
M3PreCheckFailed failed = (M3PreCheckFailed) result;
assertTrue(result instanceof PreCheckFailed, "Should fail when both checks fail");
// The specific order of checks doesn't matter; just verify one reason is returned
PreCheckFailed failed = (PreCheckFailed) result;
assertNotNull(failed.failureReason());
assertFalse(failed.failureReason().isEmpty());
}
@@ -186,7 +186,7 @@ class M3PreCheckEvaluatorTest {
PdfExtractionSuccess extraction = new PdfExtractionSuccess("Valid text", new PdfPageCount(1));
assertThrows(NullPointerException.class, () ->
M3PreCheckEvaluator.evaluate(null, extraction, config)
PreCheckEvaluator.evaluate(null, extraction, config)
);
}
@@ -196,7 +196,7 @@ class M3PreCheckEvaluatorTest {
SourceDocumentCandidate candidate = buildCandidate();
assertThrows(NullPointerException.class, () ->
M3PreCheckEvaluator.evaluate(candidate, null, config)
PreCheckEvaluator.evaluate(candidate, null, config)
);
}
@@ -206,7 +206,7 @@ class M3PreCheckEvaluatorTest {
PdfExtractionSuccess extraction = new PdfExtractionSuccess("Valid text", new PdfPageCount(1));
assertThrows(NullPointerException.class, () ->
M3PreCheckEvaluator.evaluate(candidate, extraction, null)
PreCheckEvaluator.evaluate(candidate, extraction, null)
);
}
@@ -216,9 +216,9 @@ class M3PreCheckEvaluatorTest {
SourceDocumentCandidate candidate = buildCandidate();
PdfExtractionSuccess extraction = new PdfExtractionSuccess("Äußerst äöüß Großes", new PdfPageCount(1));
M3DocumentProcessingOutcome result = M3PreCheckEvaluator.evaluate(candidate, extraction, config);
DocumentProcessingOutcome result = PreCheckEvaluator.evaluate(candidate, extraction, config);
assertTrue(result instanceof M3PreCheckPassed, "Should pass with German umlauts (ÄÖÜß)");
assertTrue(result instanceof PreCheckPassed, "Should pass with German umlauts (ÄÖÜß)");
}
@Test
@@ -227,9 +227,9 @@ class M3PreCheckEvaluatorTest {
SourceDocumentCandidate candidate = buildCandidate();
PdfExtractionSuccess extraction = new PdfExtractionSuccess("Αβγδ 中文 καλημέρα", new PdfPageCount(1));
M3DocumentProcessingOutcome result = M3PreCheckEvaluator.evaluate(candidate, extraction, config);
DocumentProcessingOutcome result = PreCheckEvaluator.evaluate(candidate, extraction, config);
assertTrue(result instanceof M3PreCheckPassed, "Should pass with Greek, Chinese, and other Unicode letters");
assertTrue(result instanceof PreCheckPassed, "Should pass with Greek, Chinese, and other Unicode letters");
}
// =========================================================================
@@ -273,4 +273,4 @@ class M3PreCheckEvaluatorTest {
SourceDocumentLocator locator = new SourceDocumentLocator(pdfFile.toString());
return new SourceDocumentCandidate(pdfFile.getFileName().toString(), 0L, locator);
}
}
}

View File

@@ -31,25 +31,25 @@ import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
/**
* Tests for {@link M2BatchRunProcessingUseCase}.
* Tests for {@link BatchRunProcessingUseCase}.
* <p>
* Covers:
* <ul>
* <li>Lock acquisition and release lifecycle (M2)</li>
* <li>M3 source folder scanning and per-document processing loop</li>
* <li>M3 happy path: candidate passes pre-checks, ends controlled without KI or target copy</li>
* <li>M3 deterministic content errors: no usable text, page limit exceeded</li>
* <li>M3 technical extraction errors: controlled per-document end, batch continues</li>
* <li>Lock acquisition and release lifecycle</li>
* <li>Source folder scanning and per-document processing loop</li>
* <li>Happy path: candidate passes pre-checks, ends controlled without KI or target copy</li>
* <li>Deterministic content errors: no usable text, page limit exceeded</li>
* <li>Technical extraction errors: controlled per-document end, batch continues</li>
* <li>Source folder access failure: batch fails with FAILURE outcome</li>
* </ul>
*/
class M2BatchRunProcessingUseCaseTest {
class BatchRunProcessingUseCaseTest {
@TempDir
Path tempDir;
// -------------------------------------------------------------------------
// M2: Lock lifecycle tests (preserved, updated constructor)
// Lock lifecycle tests
// -------------------------------------------------------------------------
@Test
@@ -57,7 +57,7 @@ class M2BatchRunProcessingUseCaseTest {
MockRunLockPort lockPort = new MockRunLockPort();
StartConfiguration config = buildConfig(tempDir);
M2BatchRunProcessingUseCase useCase = new M2BatchRunProcessingUseCase(
BatchRunProcessingUseCase useCase = new BatchRunProcessingUseCase(
config, lockPort, new EmptyCandidatesPort(), new NoOpExtractionPort());
BatchRunContext context = new BatchRunContext(new RunId("test-run-1"), Instant.now());
@@ -73,7 +73,7 @@ class M2BatchRunProcessingUseCaseTest {
CountingRunLockPort lockPort = new CountingRunLockPort(true);
StartConfiguration config = buildConfig(tempDir);
M2BatchRunProcessingUseCase useCase = new M2BatchRunProcessingUseCase(
BatchRunProcessingUseCase useCase = new BatchRunProcessingUseCase(
config, lockPort, new EmptyCandidatesPort(), new NoOpExtractionPort());
BatchRunContext context = new BatchRunContext(new RunId("test-run-2"), Instant.now());
@@ -85,14 +85,14 @@ class M2BatchRunProcessingUseCaseTest {
}
/**
* Regression test for M2-F1: when acquire() fails, release() must NOT be called.
* Regression test: when acquire() fails, release() must NOT be called.
*/
@Test
void execute_doesNotReleaseLockWhenAcquireFails() throws Exception {
CountingRunLockPort lockPort = new CountingRunLockPort(true);
StartConfiguration config = buildConfig(tempDir);
M2BatchRunProcessingUseCase useCase = new M2BatchRunProcessingUseCase(
BatchRunProcessingUseCase useCase = new BatchRunProcessingUseCase(
config, lockPort, new EmptyCandidatesPort(), new NoOpExtractionPort());
BatchRunContext context = new BatchRunContext(new RunId("test-run-f1"), Instant.now());
@@ -108,7 +108,7 @@ class M2BatchRunProcessingUseCaseTest {
ErrorAfterAcquireLockPort lockPort = new ErrorAfterAcquireLockPort();
StartConfiguration config = buildConfig(tempDir);
M2BatchRunProcessingUseCase useCase = new M2BatchRunProcessingUseCase(
BatchRunProcessingUseCase useCase = new BatchRunProcessingUseCase(
config, lockPort, new EmptyCandidatesPort(), new NoOpExtractionPort());
BatchRunContext context = new BatchRunContext(new RunId("test-run-3"), Instant.now());
@@ -120,7 +120,7 @@ class M2BatchRunProcessingUseCaseTest {
}
// -------------------------------------------------------------------------
// M3: Source folder scanning and candidate processing
// Source folder scanning and candidate processing
// -------------------------------------------------------------------------
@Test
@@ -128,9 +128,9 @@ class M2BatchRunProcessingUseCaseTest {
MockRunLockPort lockPort = new MockRunLockPort();
StartConfiguration config = buildConfig(tempDir);
M2BatchRunProcessingUseCase useCase = new M2BatchRunProcessingUseCase(
BatchRunProcessingUseCase useCase = new BatchRunProcessingUseCase(
config, lockPort, new EmptyCandidatesPort(), new NoOpExtractionPort());
BatchRunContext context = new BatchRunContext(new RunId("m3-empty"), Instant.now());
BatchRunContext context = new BatchRunContext(new RunId("empty"), Instant.now());
BatchRunOutcome outcome = useCase.execute(context);
@@ -138,7 +138,7 @@ class M2BatchRunProcessingUseCaseTest {
}
@Test
void execute_m3HappyPath_candidatePassesPreChecks_endsControlledWithoutKiOrCopy() throws Exception {
void execute_happyPath_candidatePassesPreChecks_endsControlledWithoutKiOrCopy() throws Exception {
MockRunLockPort lockPort = new MockRunLockPort();
StartConfiguration config = buildConfig(tempDir);
@@ -148,19 +148,19 @@ class M2BatchRunProcessingUseCaseTest {
FixedCandidatesPort candidatesPort = new FixedCandidatesPort(List.of(candidate));
FixedExtractionPort extractionPort = new FixedExtractionPort(success);
M2BatchRunProcessingUseCase useCase = new M2BatchRunProcessingUseCase(
BatchRunProcessingUseCase useCase = new BatchRunProcessingUseCase(
config, lockPort, candidatesPort, extractionPort);
BatchRunContext context = new BatchRunContext(new RunId("m3-happy"), Instant.now());
BatchRunContext context = new BatchRunContext(new RunId("happy"), Instant.now());
BatchRunOutcome outcome = useCase.execute(context);
// Batch run succeeds; document ended controlled at M3 boundary (no KI, no copy)
assertTrue(outcome.isSuccess(), "M3 happy path should yield SUCCESS");
// Batch run succeeds; document ended controlled at boundary (no KI, no copy)
assertTrue(outcome.isSuccess(), "Happy path should yield SUCCESS");
assertEquals(1, extractionPort.callCount(), "Extraction should be called exactly once");
}
@Test
void execute_m3NoUsableText_candidateEndsControlled_batchContinues() throws Exception {
void execute_noUsableText_candidateEndsControlled_batchContinues() throws Exception {
MockRunLockPort lockPort = new MockRunLockPort();
StartConfiguration config = buildConfig(tempDir);
@@ -170,9 +170,9 @@ class M2BatchRunProcessingUseCaseTest {
FixedCandidatesPort candidatesPort = new FixedCandidatesPort(List.of(candidate));
FixedExtractionPort extractionPort = new FixedExtractionPort(emptySuccess);
M2BatchRunProcessingUseCase useCase = new M2BatchRunProcessingUseCase(
BatchRunProcessingUseCase useCase = new BatchRunProcessingUseCase(
config, lockPort, candidatesPort, extractionPort);
BatchRunContext context = new BatchRunContext(new RunId("m3-no-text"), Instant.now());
BatchRunContext context = new BatchRunContext(new RunId("no-text"), Instant.now());
BatchRunOutcome outcome = useCase.execute(context);
@@ -181,7 +181,7 @@ class M2BatchRunProcessingUseCaseTest {
}
@Test
void execute_m3PageLimitExceeded_candidateEndsControlled_batchContinues() throws Exception {
void execute_pageLimitExceeded_candidateEndsControlled_batchContinues() throws Exception {
MockRunLockPort lockPort = new MockRunLockPort();
// Config has maxPages=3; document has 10 pages
StartConfiguration config = buildConfig(tempDir);
@@ -191,9 +191,9 @@ class M2BatchRunProcessingUseCaseTest {
FixedCandidatesPort candidatesPort = new FixedCandidatesPort(List.of(candidate));
FixedExtractionPort extractionPort = new FixedExtractionPort(manyPages);
M2BatchRunProcessingUseCase useCase = new M2BatchRunProcessingUseCase(
BatchRunProcessingUseCase useCase = new BatchRunProcessingUseCase(
config, lockPort, candidatesPort, extractionPort);
BatchRunContext context = new BatchRunContext(new RunId("m3-page-limit"), Instant.now());
BatchRunContext context = new BatchRunContext(new RunId("page-limit"), Instant.now());
BatchRunOutcome outcome = useCase.execute(context);
@@ -202,7 +202,7 @@ class M2BatchRunProcessingUseCaseTest {
}
@Test
void execute_m3ExtractionContentError_candidateEndsControlled_batchContinues() throws Exception {
void execute_extractionContentError_candidateEndsControlled_batchContinues() throws Exception {
MockRunLockPort lockPort = new MockRunLockPort();
StartConfiguration config = buildConfig(tempDir);
@@ -211,9 +211,9 @@ class M2BatchRunProcessingUseCaseTest {
FixedCandidatesPort candidatesPort = new FixedCandidatesPort(List.of(candidate));
FixedExtractionPort extractionPort = new FixedExtractionPort(contentError);
M2BatchRunProcessingUseCase useCase = new M2BatchRunProcessingUseCase(
BatchRunProcessingUseCase useCase = new BatchRunProcessingUseCase(
config, lockPort, candidatesPort, extractionPort);
BatchRunContext context = new BatchRunContext(new RunId("m3-content-error"), Instant.now());
BatchRunContext context = new BatchRunContext(new RunId("content-error"), Instant.now());
BatchRunOutcome outcome = useCase.execute(context);
@@ -221,7 +221,7 @@ class M2BatchRunProcessingUseCaseTest {
}
@Test
void execute_m3ExtractionTechnicalError_candidateEndsControlled_batchContinues() throws Exception {
void execute_extractionTechnicalError_candidateEndsControlled_batchContinues() throws Exception {
MockRunLockPort lockPort = new MockRunLockPort();
StartConfiguration config = buildConfig(tempDir);
@@ -230,9 +230,9 @@ class M2BatchRunProcessingUseCaseTest {
FixedCandidatesPort candidatesPort = new FixedCandidatesPort(List.of(candidate));
FixedExtractionPort extractionPort = new FixedExtractionPort(technicalError);
M2BatchRunProcessingUseCase useCase = new M2BatchRunProcessingUseCase(
BatchRunProcessingUseCase useCase = new BatchRunProcessingUseCase(
config, lockPort, candidatesPort, extractionPort);
BatchRunContext context = new BatchRunContext(new RunId("m3-tech-error"), Instant.now());
BatchRunContext context = new BatchRunContext(new RunId("tech-error"), Instant.now());
BatchRunOutcome outcome = useCase.execute(context);
@@ -240,7 +240,7 @@ class M2BatchRunProcessingUseCaseTest {
}
@Test
void execute_m3SourceAccessException_returnsFailure() throws Exception {
void execute_sourceAccessException_returnsFailure() throws Exception {
MockRunLockPort lockPort = new MockRunLockPort();
StartConfiguration config = buildConfig(tempDir);
@@ -248,9 +248,9 @@ class M2BatchRunProcessingUseCaseTest {
throw new SourceDocumentAccessException("Source folder not readable");
};
M2BatchRunProcessingUseCase useCase = new M2BatchRunProcessingUseCase(
BatchRunProcessingUseCase useCase = new BatchRunProcessingUseCase(
config, lockPort, failingPort, new NoOpExtractionPort());
BatchRunContext context = new BatchRunContext(new RunId("m3-access-fail"), Instant.now());
BatchRunContext context = new BatchRunContext(new RunId("access-fail"), Instant.now());
BatchRunOutcome outcome = useCase.execute(context);
@@ -261,11 +261,11 @@ class M2BatchRunProcessingUseCaseTest {
}
/**
* Mixed-batch test: one document per M3 outcome type in a single run.
* Proves that no individual outcome aborts the overall batch (AP-008 explicit contract).
* Mixed-batch test: one document per outcome type in a single run.
* Proves that no individual outcome aborts the overall batch.
*/
@Test
void execute_m3MixedBatch_allOutcomeTypes_batchOverallSucceeds() throws Exception {
void execute_mixedBatch_allOutcomeTypes_batchOverallSucceeds() throws Exception {
MockRunLockPort lockPort = new MockRunLockPort();
// maxPages=3 in buildConfig; pageLimitCandidate has 10 pages exceeds limit
StartConfiguration config = buildConfig(tempDir);
@@ -287,20 +287,20 @@ class M2BatchRunProcessingUseCaseTest {
.with(technicalErrorCandidate, new PdfExtractionTechnicalError("I/O error", null))
.with(contentErrorCandidate, new PdfExtractionContentError("PDF is encrypted"));
M2BatchRunProcessingUseCase useCase = new M2BatchRunProcessingUseCase(
BatchRunProcessingUseCase useCase = new BatchRunProcessingUseCase(
config, lockPort, candidatesPort, extractionPort);
BatchRunContext context = new BatchRunContext(new RunId("m3-mixed"), Instant.now());
BatchRunContext context = new BatchRunContext(new RunId("mixed"), Instant.now());
BatchRunOutcome outcome = useCase.execute(context);
assertTrue(outcome.isSuccess(),
"Mixed batch with all M3 outcome types must yield batch SUCCESS");
"Mixed batch with all outcome types must yield batch SUCCESS");
assertEquals(5, extractionPort.callCount(),
"Extraction must be attempted for each of the 5 candidates");
}
@Test
void execute_m3MultipleCandidates_allProcessed_batchSucceeds() throws Exception {
void execute_multipleCandidates_allProcessed_batchSucceeds() throws Exception {
MockRunLockPort lockPort = new MockRunLockPort();
StartConfiguration config = buildConfig(tempDir);
@@ -313,9 +313,9 @@ class M2BatchRunProcessingUseCaseTest {
FixedCandidatesPort candidatesPort = new FixedCandidatesPort(candidates);
FixedExtractionPort extractionPort = new FixedExtractionPort(success);
M2BatchRunProcessingUseCase useCase = new M2BatchRunProcessingUseCase(
BatchRunProcessingUseCase useCase = new BatchRunProcessingUseCase(
config, lockPort, candidatesPort, extractionPort);
BatchRunContext context = new BatchRunContext(new RunId("m3-multi"), Instant.now());
BatchRunContext context = new BatchRunContext(new RunId("multi"), Instant.now());
BatchRunOutcome outcome = useCase.execute(context);
@@ -480,4 +480,4 @@ class M2BatchRunProcessingUseCaseTest {
int callCount() { return calls; }
}
}
}