diff --git a/src/test/java/dev/kruhlmann/imgfloat/service/AssetCleanupServiceTest.java b/src/test/java/dev/kruhlmann/imgfloat/service/AssetCleanupServiceTest.java new file mode 100644 index 0000000..6e8384e --- /dev/null +++ b/src/test/java/dev/kruhlmann/imgfloat/service/AssetCleanupServiceTest.java @@ -0,0 +1,101 @@ +package dev.kruhlmann.imgfloat.service; + +import static org.mockito.ArgumentMatchers.anySet; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import dev.kruhlmann.imgfloat.model.db.imgfloat.Asset; +import dev.kruhlmann.imgfloat.model.db.imgfloat.ScriptAsset; +import dev.kruhlmann.imgfloat.model.db.imgfloat.ScriptAssetAttachment; +import dev.kruhlmann.imgfloat.repository.AssetRepository; +import dev.kruhlmann.imgfloat.repository.ScriptAssetAttachmentRepository; +import dev.kruhlmann.imgfloat.repository.ScriptAssetRepository; +import dev.kruhlmann.imgfloat.model.AssetType; +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; + +import static org.assertj.core.api.Assertions.assertThat; + +class AssetCleanupServiceTest { + + private AssetRepository assetRepository; + private AssetStorageService assetStorageService; + private ScriptAssetAttachmentRepository attachmentRepository; + private ScriptAssetRepository scriptAssetRepository; + private AssetCleanupService service; + + @BeforeEach + void setup() { + assetRepository = mock(AssetRepository.class); + assetStorageService = mock(AssetStorageService.class); + attachmentRepository = mock(ScriptAssetAttachmentRepository.class); + scriptAssetRepository = mock(ScriptAssetRepository.class); + service = new AssetCleanupService( + assetRepository, assetStorageService, attachmentRepository, scriptAssetRepository + ); + } + + @Test + void cleanupPassesAllReferencedIdsToStorageService() { + Asset asset = new Asset("broadcaster", AssetType.IMAGE); + String assetId = asset.getId(); // UUID generated by constructor + + ScriptAsset script = new ScriptAsset(); + script.setId("script-1"); + script.setSourceFileId("source-file-1"); + script.setLogoFileId("logo-file-1"); + + ScriptAssetAttachment attachment = new ScriptAssetAttachment("script-1", "attach.png"); + attachment.setFileId("attachment-file-1"); + + when(assetRepository.findAll()).thenReturn(List.of(asset)); + when(scriptAssetRepository.findAll()).thenReturn(List.of(script)); + when(attachmentRepository.findAll()).thenReturn(List.of(attachment)); + + service.cleanup(); + + ArgumentCaptor> captor = ArgumentCaptor.forClass((Class) Set.class); + verify(assetStorageService).deleteOrphanedAssets(captor.capture()); + Set referenced = captor.getValue(); + assertThat(referenced).contains(assetId, "source-file-1", "logo-file-1", "attachment-file-1"); + } + + @Test + void cleanupIncludesAttachmentIdWhenFileIdIsNull() { + ScriptAssetAttachment attachment = new ScriptAssetAttachment("script-1", "attach.png"); + attachment.setId("fallback-id"); + attachment.setFileId(null); + + when(assetRepository.findAll()).thenReturn(List.of()); + when(scriptAssetRepository.findAll()).thenReturn(List.of()); + when(attachmentRepository.findAll()).thenReturn(List.of(attachment)); + + service.cleanup(); + + ArgumentCaptor> captor = ArgumentCaptor.forClass((Class) Set.class); + verify(assetStorageService).deleteOrphanedAssets(captor.capture()); + assertThat(captor.getValue()).contains("fallback-id"); + } + + @Test + void cleanupSkipsBlankScriptFileIds() { + ScriptAsset script = new ScriptAsset(); + script.setId("script-1"); + script.setSourceFileId(null); + script.setLogoFileId(" "); + + when(assetRepository.findAll()).thenReturn(List.of()); + when(scriptAssetRepository.findAll()).thenReturn(List.of(script)); + when(attachmentRepository.findAll()).thenReturn(List.of()); + + service.cleanup(); + + ArgumentCaptor> captor = ArgumentCaptor.forClass((Class) Set.class); + verify(assetStorageService).deleteOrphanedAssets(captor.capture()); + assertThat(captor.getValue()).doesNotContain(" ").doesNotContain("script-1"); + } +} diff --git a/src/test/java/dev/kruhlmann/imgfloat/util/StringNormalizerTest.java b/src/test/java/dev/kruhlmann/imgfloat/util/StringNormalizerTest.java new file mode 100644 index 0000000..cd7cb9b --- /dev/null +++ b/src/test/java/dev/kruhlmann/imgfloat/util/StringNormalizerTest.java @@ -0,0 +1,36 @@ +package dev.kruhlmann.imgfloat.util; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class StringNormalizerTest { + + @Test + void toLowerCaseRootReturnsNullForNull() { + assertThat(StringNormalizer.toLowerCaseRoot(null)).isNull(); + } + + @Test + void toLowerCaseRootConvertsToLowercase() { + assertThat(StringNormalizer.toLowerCaseRoot("Hello")).isEqualTo("hello"); + assertThat(StringNormalizer.toLowerCaseRoot("BROADCASTER")).isEqualTo("broadcaster"); + assertThat(StringNormalizer.toLowerCaseRoot("MiXeDcAsE")).isEqualTo("mixedcase"); + } + + @Test + void toLowerCaseRootHandlesAlreadyLowercase() { + assertThat(StringNormalizer.toLowerCaseRoot("already_lower")).isEqualTo("already_lower"); + } + + @Test + void toLowerCaseRootHandlesEmptyString() { + assertThat(StringNormalizer.toLowerCaseRoot("")).isEqualTo(""); + } + + @Test + void toLowerCaseRootUsesRootLocale() { + // Turkish locale would uppercase 'i' to 'İ' but ROOT locale must not + assertThat(StringNormalizer.toLowerCaseRoot("TITLE")).isEqualTo("title"); + } +}