diff --git a/docs/input-folder-scheduler-plan.md b/docs/input-folder-scheduler-plan.md index 9adef70..93e7a68 100644 --- a/docs/input-folder-scheduler-plan.md +++ b/docs/input-folder-scheduler-plan.md @@ -28,7 +28,7 @@ Note: the local machine's filesystem root is read-only in this workspace, so abs 8. [x] Add FFmpeg clipping into `/output/clips//` using 8-second MP4/H.264/AAC segments. 9. [x] Add success handling that moves processed source files to processed storage. 10. [x] Add failure handling for FFmpeg or filesystem errors. -11. [ ] Add unit tests for ordering, invalid-file handling, repeat prevention, and state transitions. +11. [x] Add unit tests for ordering, invalid-file handling, repeat prevention, and state transitions. 12. [ ] Add optional FFmpeg integration test for a short fixture. 13. [ ] Add local profile or documented runtime config for enabling the scheduler. 14. [ ] Run verification and mark feature complete. diff --git a/src/test/java/org/example/videoclips/folder/FolderVideoScanSchedulerTest.java b/src/test/java/org/example/videoclips/folder/FolderVideoScanSchedulerTest.java index aaaa25a..fcfea4d 100644 --- a/src/test/java/org/example/videoclips/folder/FolderVideoScanSchedulerTest.java +++ b/src/test/java/org/example/videoclips/folder/FolderVideoScanSchedulerTest.java @@ -10,6 +10,8 @@ import java.nio.file.Path; import java.nio.file.attribute.PosixFilePermission; import java.util.Optional; import java.util.Set; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -122,6 +124,31 @@ class FolderVideoScanSchedulerTest { assertEquals("video", Files.readString(tempDir.resolve("processed/1.mp4"))); } + @Test + void processesOneCandidatePerScanInNaturalOrder() throws Exception { + Files.writeString(tempDir.resolve("2.mp4"), "second"); + Files.writeString(tempDir.resolve("1.mp4"), "first"); + List clippedSources = new ArrayList<>(); + FolderFfmpegClipper clipper = mock(FolderFfmpegClipper.class); + when(clipper.clip(any())).thenAnswer(invocation -> { + Path source = invocation.getArgument(0); + clippedSources.add(source.getFileName().toString()); + return new FolderFfmpegClipper.ClipResult(tempDir.resolve("output/result"), 1); + }); + FolderVideoScanScheduler scheduler = scheduler(tempDir, acceptedValidator(), clipper); + + scheduler.scan(); + + assertEquals(List.of("1.mp4"), clippedSources); + assertTrue(Files.exists(tempDir.resolve("processed/1.mp4"))); + assertTrue(Files.exists(tempDir.resolve("2.mp4"))); + + scheduler.scan(); + + assertEquals(List.of("1.mp4", "2.mp4"), clippedSources); + assertTrue(Files.exists(tempDir.resolve("processed/2.mp4"))); + } + @Test void invalidCandidateIsMovedToRejectedDirectory() throws Exception { Files.writeString(tempDir.resolve("invalid.mp4"), "not video");