M8 Abschlussdokumentation und Betriebsdoku final geschärft
This commit is contained in:
@@ -14,7 +14,7 @@ import de.gecheckt.pdf.umbenenner.application.port.out.RunLockUnavailableExcepti
|
||||
/**
|
||||
* File-based implementation of {@link RunLockPort} that uses a lock file to prevent concurrent runs.
|
||||
* <p>
|
||||
* AP-006 Implementation: Creates an exclusive lock file on acquire and deletes it on release.
|
||||
* Creates an exclusive lock file on acquire and deletes it on release.
|
||||
* If the lock file already exists, {@link #acquire()} throws {@link RunLockUnavailableException}
|
||||
* to signal that another instance is already running.
|
||||
* <p>
|
||||
|
||||
@@ -102,7 +102,7 @@ public class PdfTextExtractionPortAdapter implements PdfTextExtractionPort {
|
||||
try {
|
||||
int pageCount = document.getNumberOfPages();
|
||||
|
||||
// AP-003: Handle case of zero pages as technical error
|
||||
// Handle case of zero pages as technical error
|
||||
// (PdfPageCount requires >= 1, so this is a constraint violation)
|
||||
if (pageCount < 1) {
|
||||
return new PdfExtractionTechnicalError(
|
||||
@@ -124,7 +124,7 @@ public class PdfTextExtractionPortAdapter implements PdfTextExtractionPort {
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
// All I/O and PDFBox loading/parsing errors are technical errors in AP-003
|
||||
// All I/O and PDFBox loading/parsing errors are technical errors
|
||||
String errorMessage = e.getMessage() != null ? e.getMessage() : e.toString();
|
||||
return new PdfExtractionTechnicalError(
|
||||
"Failed to load or parse PDF: " + errorMessage,
|
||||
|
||||
@@ -14,7 +14,7 @@ import de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentLocator;
|
||||
/**
|
||||
* File-system based implementation of {@link SourceDocumentCandidatesPort}.
|
||||
* <p>
|
||||
* AP-002 Implementation: Scans a configured source folder and returns only PDF files
|
||||
* Scans a configured source folder and returns only PDF files
|
||||
* (by extension) as {@link SourceDocumentCandidate} objects.
|
||||
* <p>
|
||||
* Design:
|
||||
@@ -29,13 +29,11 @@ import de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentLocator;
|
||||
* <p>
|
||||
* Non-goals:
|
||||
* <ul>
|
||||
* <li>No PDF validation (that is AP-003)</li>
|
||||
* <li>No PDF structure validation</li>
|
||||
* <li>No recursion into subdirectories</li>
|
||||
* <li>No content evaluation (that happens in AP-004: brauchbarer Text assessment)</li>
|
||||
* <li>No content evaluation (text usability is assessed during document processing)</li>
|
||||
* <li>No fachlich evaluation of candidates</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since M3-AP-002
|
||||
*/
|
||||
public class SourceDocumentCandidatesPortAdapter implements SourceDocumentCandidatesPort {
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ import de.gecheckt.pdf.umbenenner.application.port.out.PersistenceSchemaInitiali
|
||||
* <li>Target-copy column ({@code final_target_file_name}) to {@code processing_attempt}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>M4→current-schema status migration</h2>
|
||||
* <h2>Legacy-state migration</h2>
|
||||
* <p>
|
||||
* Documents in an earlier positive intermediate state ({@code SUCCESS} recorded without
|
||||
* a validated naming proposal) are idempotently migrated to {@code READY_FOR_AI} so that
|
||||
@@ -178,7 +178,7 @@ public class SqliteSchemaInitializationAdapter implements PersistenceSchemaIniti
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// M4→current-schema status migration
|
||||
// Legacy-state status migration
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
||||
@@ -836,7 +836,7 @@ class StartConfigurationValidatorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* M3/AP-007: Focused tests for source folder validation using mocked filesystem checks.
|
||||
* Focused tests for source folder validation using mocked filesystem checks.
|
||||
* <p>
|
||||
* These tests verify the four critical paths for source folder validation without
|
||||
* relying on platform-dependent filesystem permissions or the actual FS state.
|
||||
@@ -941,7 +941,7 @@ class StartConfigurationValidatorTest {
|
||||
);
|
||||
|
||||
// Mock: simulate path exists, is directory, but is not readable
|
||||
// This is the critical M3/AP-007 case that is hard to test on actual FS
|
||||
// This is the critical case that is hard to test on actual FS
|
||||
StartConfigurationValidator.SourceFolderChecker mockChecker = path ->
|
||||
"- source.folder: directory is not readable: " + path;
|
||||
|
||||
|
||||
@@ -19,8 +19,6 @@ import de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentLocator;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link Sha256FingerprintAdapter}.
|
||||
*
|
||||
* @since M4-AP-002
|
||||
*/
|
||||
class Sha256FingerprintAdapterTest {
|
||||
|
||||
|
||||
@@ -28,12 +28,10 @@ import de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentLocator;
|
||||
/**
|
||||
* Tests for {@link PdfTextExtractionPortAdapter}.
|
||||
* <p>
|
||||
* M3-AP-003: Minimal tests validating basic extraction functionality and technical error handling.
|
||||
* In AP-003 scope: all extraction problems are treated as TechnicalError, not ContentError.
|
||||
* No fachliche validation of text content (that is AP-004).
|
||||
* Validates basic extraction functionality and technical error handling.
|
||||
* All extraction problems are treated as {@link de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionTechnicalError},
|
||||
* not content errors. Content usability (text quality assessment) is handled in the application layer.
|
||||
* PDFs are created programmatically using PDFBox to avoid external dependencies on test files.
|
||||
*
|
||||
* @since M3-AP-003
|
||||
*/
|
||||
class PdfTextExtractionPortAdapterTest {
|
||||
|
||||
@@ -170,8 +168,8 @@ class PdfTextExtractionPortAdapterTest {
|
||||
|
||||
PdfExtractionResult result = adapter.extractTextAndPageCount(candidate);
|
||||
|
||||
// AP-003: Empty text is SUCCESS, not an error
|
||||
// Fachliche Bewertung of text content happens in AP-004
|
||||
// Empty text is SUCCESS at extraction level, not an error
|
||||
// Fachliche Bewertung of text content happens in the application layer
|
||||
assertInstanceOf(PdfExtractionSuccess.class, result);
|
||||
PdfExtractionSuccess success = (PdfExtractionSuccess) result;
|
||||
assertEquals(1, success.pageCount().value());
|
||||
|
||||
@@ -20,8 +20,6 @@ import de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentCandidate;
|
||||
|
||||
/**
|
||||
* Tests for {@link SourceDocumentCandidatesPortAdapter}.
|
||||
*
|
||||
* @since M3-AP-002
|
||||
*/
|
||||
class SourceDocumentCandidatesPortAdapterTest {
|
||||
|
||||
@@ -198,7 +196,7 @@ class SourceDocumentCandidatesPortAdapterTest {
|
||||
|
||||
@Test
|
||||
void testLoadCandidates_EmptyPdfFilesAreIncluded() throws IOException {
|
||||
// Create empty PDF files (M3-AP-002 requirement: PDF-Dateien im Quellordner)
|
||||
// Create empty PDF files
|
||||
Files.createFile(tempDir.resolve("empty1.pdf"));
|
||||
Files.createFile(tempDir.resolve("empty2.pdf"));
|
||||
// Also add a non-empty PDF for contrast
|
||||
@@ -207,7 +205,7 @@ class SourceDocumentCandidatesPortAdapterTest {
|
||||
List<SourceDocumentCandidate> candidates = adapter.loadCandidates();
|
||||
|
||||
assertEquals(3, candidates.size(),
|
||||
"Empty PDF files should be included as candidates; content evaluation happens in AP-004");
|
||||
"Empty PDF files should be included as candidates; content evaluation happens during document processing");
|
||||
assertTrue(candidates.stream().allMatch(c -> c.uniqueIdentifier().endsWith(".pdf")),
|
||||
"All candidates should be PDF files");
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
* Tests verify transactional semantics: successful commits, rollback on first-write failure,
|
||||
* rollback on second-write failure, and proper handling of DocumentPersistenceException.
|
||||
*
|
||||
* @since M4-AP-006
|
||||
*/
|
||||
class SqliteUnitOfWorkAdapterTest {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user