mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 19:33:11 +02:00
junits (#5988)
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
|
||||
class AppArgsCaptureTest {
|
||||
|
||||
private AppArgsCapture capture;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
capture = new AppArgsCapture();
|
||||
AppArgsCapture.APP_ARGS.set(List.of());
|
||||
}
|
||||
|
||||
@Test
|
||||
void run_withArgs_capturesArgs() {
|
||||
ApplicationArguments args = mock(ApplicationArguments.class);
|
||||
when(args.getSourceArgs()).thenReturn(new String[] {"--server.port=8080", "--debug"});
|
||||
capture.run(args);
|
||||
assertEquals(List.of("--server.port=8080", "--debug"), AppArgsCapture.APP_ARGS.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
void run_withNoArgs_capturesEmptyList() {
|
||||
ApplicationArguments args = mock(ApplicationArguments.class);
|
||||
when(args.getSourceArgs()).thenReturn(new String[] {});
|
||||
capture.run(args);
|
||||
assertEquals(List.of(), AppArgsCapture.APP_ARGS.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
void run_calledTwice_overwritesPreviousArgs() {
|
||||
ApplicationArguments args1 = mock(ApplicationArguments.class);
|
||||
when(args1.getSourceArgs()).thenReturn(new String[] {"--first"});
|
||||
capture.run(args1);
|
||||
assertEquals(List.of("--first"), AppArgsCapture.APP_ARGS.get());
|
||||
|
||||
ApplicationArguments args2 = mock(ApplicationArguments.class);
|
||||
when(args2.getSourceArgs()).thenReturn(new String[] {"--second", "--third"});
|
||||
capture.run(args2);
|
||||
assertEquals(List.of("--second", "--third"), AppArgsCapture.APP_ARGS.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
void appArgs_defaultValue_isEmptyList() {
|
||||
// After setUp resets it
|
||||
assertTrue(AppArgsCapture.APP_ARGS.get().isEmpty());
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
class ApplicationContextProviderTest {
|
||||
|
||||
private ApplicationContextProvider provider;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
provider = new ApplicationContextProvider();
|
||||
// Reset to null state
|
||||
provider.setApplicationContext(null);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
// Clean up static state
|
||||
provider.setApplicationContext(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBean_byClass_whenNoContext_returnsNull() {
|
||||
provider.setApplicationContext(null);
|
||||
assertNull(ApplicationContextProvider.getBean(String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBean_byClass_whenBeanExists_returnsBean() {
|
||||
ApplicationContext ctx = mock(ApplicationContext.class);
|
||||
when(ctx.getBean(String.class)).thenReturn("hello");
|
||||
provider.setApplicationContext(ctx);
|
||||
assertEquals("hello", ApplicationContextProvider.getBean(String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBean_byClass_whenBeanNotFound_returnsNull() {
|
||||
ApplicationContext ctx = mock(ApplicationContext.class);
|
||||
when(ctx.getBean(String.class)).thenThrow(new NoSuchBeanDefinitionException(""));
|
||||
provider.setApplicationContext(ctx);
|
||||
assertNull(ApplicationContextProvider.getBean(String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBean_byNameAndClass_whenNoContext_returnsNull() {
|
||||
provider.setApplicationContext(null);
|
||||
assertNull(ApplicationContextProvider.getBean("myBean", String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBean_byNameAndClass_whenBeanExists_returnsBean() {
|
||||
ApplicationContext ctx = mock(ApplicationContext.class);
|
||||
when(ctx.getBean("myBean", String.class)).thenReturn("world");
|
||||
provider.setApplicationContext(ctx);
|
||||
assertEquals("world", ApplicationContextProvider.getBean("myBean", String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBean_byNameAndClass_whenBeanNotFound_returnsNull() {
|
||||
ApplicationContext ctx = mock(ApplicationContext.class);
|
||||
when(ctx.getBean("missing", String.class)).thenThrow(new NoSuchBeanDefinitionException(""));
|
||||
provider.setApplicationContext(ctx);
|
||||
assertNull(ApplicationContextProvider.getBean("missing", String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void containsBean_whenNoContext_returnsFalse() {
|
||||
provider.setApplicationContext(null);
|
||||
assertFalse(ApplicationContextProvider.containsBean(String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void containsBean_whenBeanExists_returnsTrue() {
|
||||
ApplicationContext ctx = mock(ApplicationContext.class);
|
||||
when(ctx.getBean(String.class)).thenReturn("exists");
|
||||
provider.setApplicationContext(ctx);
|
||||
assertTrue(ApplicationContextProvider.containsBean(String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void containsBean_whenBeanNotFound_returnsFalse() {
|
||||
ApplicationContext ctx = mock(ApplicationContext.class);
|
||||
when(ctx.getBean(Integer.class)).thenThrow(new NoSuchBeanDefinitionException(""));
|
||||
provider.setApplicationContext(ctx);
|
||||
assertFalse(ApplicationContextProvider.containsBean(Integer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void setApplicationContext_updatesStaticContext() {
|
||||
ApplicationContext ctx = mock(ApplicationContext.class);
|
||||
when(ctx.getBean(String.class)).thenReturn("test");
|
||||
provider.setApplicationContext(ctx);
|
||||
assertEquals("test", ApplicationContextProvider.getBean(String.class));
|
||||
|
||||
// Now set a different context
|
||||
ApplicationContext ctx2 = mock(ApplicationContext.class);
|
||||
when(ctx2.getBean(String.class)).thenReturn("updated");
|
||||
provider.setApplicationContext(ctx2);
|
||||
assertEquals("updated", ApplicationContextProvider.getBean(String.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.apache.pdfbox.cos.COSDictionary;
|
||||
import org.apache.pdfbox.cos.COSName;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
|
||||
import org.apache.pdfbox.pdmodel.PageMode;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class AttachmentUtilsTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("should set page mode on catalog")
|
||||
void setsPageMode() {
|
||||
try (PDDocument document = new PDDocument()) {
|
||||
AttachmentUtils.setCatalogViewerPreferences(document, PageMode.USE_ATTACHMENTS);
|
||||
|
||||
PDDocumentCatalog catalog = document.getDocumentCatalog();
|
||||
assertEquals(PageMode.USE_ATTACHMENTS, catalog.getPageMode());
|
||||
} catch (Exception e) {
|
||||
fail("Should not throw: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should create viewer preferences dictionary if absent")
|
||||
void createsViewerPreferences() {
|
||||
try (PDDocument document = new PDDocument()) {
|
||||
AttachmentUtils.setCatalogViewerPreferences(document, PageMode.USE_ATTACHMENTS);
|
||||
|
||||
COSDictionary catalogDict = document.getDocumentCatalog().getCOSObject();
|
||||
COSDictionary viewerPrefs =
|
||||
(COSDictionary) catalogDict.getDictionaryObject(COSName.VIEWER_PREFERENCES);
|
||||
assertNotNull(viewerPrefs);
|
||||
} catch (Exception e) {
|
||||
fail("Should not throw: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should set DisplayDocTitle to true in viewer preferences")
|
||||
void setsDisplayDocTitle() {
|
||||
try (PDDocument document = new PDDocument()) {
|
||||
AttachmentUtils.setCatalogViewerPreferences(document, PageMode.USE_ATTACHMENTS);
|
||||
|
||||
COSDictionary catalogDict = document.getDocumentCatalog().getCOSObject();
|
||||
COSDictionary viewerPrefs =
|
||||
(COSDictionary) catalogDict.getDictionaryObject(COSName.VIEWER_PREFERENCES);
|
||||
assertTrue(viewerPrefs.getBoolean(COSName.getPDFName("DisplayDocTitle"), false));
|
||||
} catch (Exception e) {
|
||||
fail("Should not throw: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should not throw when catalog returns null from mocked document")
|
||||
void handlesNullCatalogGracefully() {
|
||||
PDDocument document = mock(PDDocument.class);
|
||||
when(document.getDocumentCatalog()).thenReturn(null);
|
||||
|
||||
assertDoesNotThrow(
|
||||
() ->
|
||||
AttachmentUtils.setCatalogViewerPreferences(
|
||||
document, PageMode.USE_ATTACHMENTS));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
class CbrUtilsTest {
|
||||
|
||||
// --- isCbrFile tests ---
|
||||
|
||||
@Test
|
||||
void isCbrFile_withCbrExtension_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("comic.cbr");
|
||||
assertTrue(CbrUtils.isCbrFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCbrFile_withRarExtension_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("archive.rar");
|
||||
assertTrue(CbrUtils.isCbrFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCbrFile_withUpperCaseExtension_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("comic.CBR");
|
||||
assertTrue(CbrUtils.isCbrFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCbrFile_withPdfExtension_returnsFalse() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("document.pdf");
|
||||
assertFalse(CbrUtils.isCbrFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCbrFile_withNullFilename_returnsFalse() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn(null);
|
||||
assertFalse(CbrUtils.isCbrFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCbrFile_withCbzExtension_returnsFalse() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("comic.cbz");
|
||||
assertFalse(CbrUtils.isCbrFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCbrFile_withNoExtension_returnsFalse() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("noextension");
|
||||
assertFalse(CbrUtils.isCbrFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCbrFile_withMixedCaseRar_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("file.RaR");
|
||||
assertTrue(CbrUtils.isCbrFile(file));
|
||||
}
|
||||
|
||||
// --- convertCbrToPdf validation tests ---
|
||||
|
||||
@Test
|
||||
void convertCbrToPdf_withNullFile_throwsException() {
|
||||
assertThrows(Exception.class, () -> CbrUtils.convertCbrToPdf(null, null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertCbrToPdf_withEmptyFile_throwsException() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.isEmpty()).thenReturn(true);
|
||||
assertThrows(Exception.class, () -> CbrUtils.convertCbrToPdf(file, null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertCbrToPdf_withNullFilename_throwsException() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.isEmpty()).thenReturn(false);
|
||||
when(file.getOriginalFilename()).thenReturn(null);
|
||||
assertThrows(Exception.class, () -> CbrUtils.convertCbrToPdf(file, null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertCbrToPdf_withWrongExtension_throwsException() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.isEmpty()).thenReturn(false);
|
||||
when(file.getOriginalFilename()).thenReturn("file.pdf");
|
||||
assertThrows(Exception.class, () -> CbrUtils.convertCbrToPdf(file, null, null));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
class CbzUtilsTest {
|
||||
|
||||
// --- isCbzFile tests ---
|
||||
|
||||
@Test
|
||||
void isCbzFile_withCbzExtension_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("comic.cbz");
|
||||
assertTrue(CbzUtils.isCbzFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCbzFile_withZipExtension_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("archive.zip");
|
||||
assertTrue(CbzUtils.isCbzFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCbzFile_withUpperCaseExtension_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("comic.CBZ");
|
||||
assertTrue(CbzUtils.isCbzFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCbzFile_withPdfExtension_returnsFalse() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("document.pdf");
|
||||
assertFalse(CbzUtils.isCbzFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCbzFile_withNullFilename_returnsFalse() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn(null);
|
||||
assertFalse(CbzUtils.isCbzFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCbzFile_withCbrExtension_returnsFalse() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("comic.cbr");
|
||||
assertFalse(CbzUtils.isCbzFile(file));
|
||||
}
|
||||
|
||||
// --- isComicBookFile tests ---
|
||||
|
||||
@Test
|
||||
void isComicBookFile_withCbzExtension_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("comic.cbz");
|
||||
assertTrue(CbzUtils.isComicBookFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isComicBookFile_withZipExtension_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("archive.zip");
|
||||
assertTrue(CbzUtils.isComicBookFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isComicBookFile_withCbrExtension_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("comic.cbr");
|
||||
assertTrue(CbzUtils.isComicBookFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isComicBookFile_withRarExtension_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("archive.rar");
|
||||
assertTrue(CbzUtils.isComicBookFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isComicBookFile_withPdfExtension_returnsFalse() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("document.pdf");
|
||||
assertFalse(CbzUtils.isComicBookFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isComicBookFile_withNullFilename_returnsFalse() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn(null);
|
||||
assertFalse(CbzUtils.isComicBookFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isComicBookFile_withUpperCaseCBR_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("comic.CBR");
|
||||
assertTrue(CbzUtils.isComicBookFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isComicBookFile_withNoExtension_returnsFalse() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("noextension");
|
||||
assertFalse(CbzUtils.isComicBookFile(file));
|
||||
}
|
||||
|
||||
// --- convertCbzToPdf validation tests ---
|
||||
|
||||
@Test
|
||||
void convertCbzToPdf_withNullFile_throwsException() {
|
||||
assertThrows(Exception.class, () -> CbzUtils.convertCbzToPdf(null, null, null, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertCbzToPdf_withEmptyFile_throwsException() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.isEmpty()).thenReturn(true);
|
||||
assertThrows(Exception.class, () -> CbzUtils.convertCbzToPdf(file, null, null, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertCbzToPdf_withNullFilename_throwsException() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.isEmpty()).thenReturn(false);
|
||||
when(file.getOriginalFilename()).thenReturn(null);
|
||||
assertThrows(Exception.class, () -> CbzUtils.convertCbzToPdf(file, null, null, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertCbzToPdf_withWrongExtension_throwsException() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.isEmpty()).thenReturn(false);
|
||||
when(file.getOriginalFilename()).thenReturn("file.pdf");
|
||||
assertThrows(Exception.class, () -> CbzUtils.convertCbzToPdf(file, null, null, false));
|
||||
}
|
||||
}
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
class ChecksumUtilsAdditionalTest {
|
||||
|
||||
private static final byte[] HELLO = "hello".getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
@TempDir Path tempDir;
|
||||
|
||||
private Path writeFile(byte[] data) throws IOException {
|
||||
Path file = tempDir.resolve("testfile.bin");
|
||||
Files.write(file, data);
|
||||
return file;
|
||||
}
|
||||
|
||||
// --- checksum(Path, String) ---
|
||||
|
||||
@Test
|
||||
void testChecksumPath_sha256() throws IOException {
|
||||
Path file = writeFile(HELLO);
|
||||
String hex = ChecksumUtils.checksum(file, "SHA-256");
|
||||
assertEquals("2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", hex);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChecksumPath_md5() throws IOException {
|
||||
Path file = writeFile(HELLO);
|
||||
String hex = ChecksumUtils.checksum(file, "MD5");
|
||||
assertEquals("5d41402abc4b2a76b9719d911017c592", hex);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChecksumPath_crc32() throws IOException {
|
||||
Path file = writeFile(HELLO);
|
||||
String hex = ChecksumUtils.checksum(file, "CRC32");
|
||||
assertEquals("3610a686", hex);
|
||||
}
|
||||
|
||||
// --- checksum(InputStream, String) ---
|
||||
|
||||
@Test
|
||||
void testChecksumStream_adler32() throws IOException {
|
||||
try (InputStream is = new ByteArrayInputStream(HELLO)) {
|
||||
String hex = ChecksumUtils.checksum(is, "ADLER32");
|
||||
assertNotNull(hex);
|
||||
assertEquals(8, hex.length());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChecksumStream_sha1() throws IOException {
|
||||
try (InputStream is = new ByteArrayInputStream(HELLO)) {
|
||||
String hex = ChecksumUtils.checksum(is, "SHA-1");
|
||||
assertEquals("aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", hex);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChecksumStream_unsupportedAlgorithm() {
|
||||
assertThrows(
|
||||
IllegalStateException.class,
|
||||
() -> {
|
||||
try (InputStream is = new ByteArrayInputStream(HELLO)) {
|
||||
ChecksumUtils.checksum(is, "FAKE-ALGO");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- checksumBase64(Path, String) ---
|
||||
|
||||
@Test
|
||||
void testChecksumBase64Path_md5() throws IOException {
|
||||
Path file = writeFile(HELLO);
|
||||
String b64 = ChecksumUtils.checksumBase64(file, "MD5");
|
||||
assertEquals("XUFAKrxLKna5cZ2REBfFkg==", b64);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChecksumBase64Path_crc32() throws IOException {
|
||||
Path file = writeFile(HELLO);
|
||||
String b64 = ChecksumUtils.checksumBase64(file, "CRC32");
|
||||
assertEquals("NhCmhg==", b64);
|
||||
}
|
||||
|
||||
// --- checksumBase64(InputStream, String) ---
|
||||
|
||||
@Test
|
||||
void testChecksumBase64Stream_adler32() throws IOException {
|
||||
try (InputStream is = new ByteArrayInputStream(HELLO)) {
|
||||
String b64 = ChecksumUtils.checksumBase64(is, "ADLER32");
|
||||
assertNotNull(b64);
|
||||
assertFalse(b64.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChecksumBase64Stream_sha256() throws IOException {
|
||||
try (InputStream is = new ByteArrayInputStream(HELLO)) {
|
||||
String b64 = ChecksumUtils.checksumBase64(is, "SHA-256");
|
||||
assertNotNull(b64);
|
||||
assertFalse(b64.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
// --- checksums(Path, String...) ---
|
||||
|
||||
@Test
|
||||
void testChecksumsPath_multipleAlgorithms() throws IOException {
|
||||
Path file = writeFile(HELLO);
|
||||
Map<String, String> results = ChecksumUtils.checksums(file, "MD5", "SHA-256", "CRC32");
|
||||
assertEquals(3, results.size());
|
||||
assertEquals("5d41402abc4b2a76b9719d911017c592", results.get("MD5"));
|
||||
assertEquals(
|
||||
"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824",
|
||||
results.get("SHA-256"));
|
||||
assertEquals("3610a686", results.get("CRC32"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChecksumsPath_preservesOrder() throws IOException {
|
||||
Path file = writeFile(HELLO);
|
||||
// Digests are output first, then Checksums (CRC32/ADLER32), per implementation
|
||||
Map<String, String> results = ChecksumUtils.checksums(file, "MD5", "SHA-1");
|
||||
String[] keys = results.keySet().toArray(new String[0]);
|
||||
assertEquals("MD5", keys[0]);
|
||||
assertEquals("SHA-1", keys[1]);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChecksumsStream_unsupportedAlgorithm() {
|
||||
assertThrows(
|
||||
IllegalStateException.class,
|
||||
() -> {
|
||||
try (InputStream is = new ByteArrayInputStream(HELLO)) {
|
||||
ChecksumUtils.checksums(is, "BOGUS");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- matches(Path, String, String) ---
|
||||
|
||||
@Test
|
||||
void testMatchesPath_correctHash() throws IOException {
|
||||
Path file = writeFile(HELLO);
|
||||
assertTrue(ChecksumUtils.matches(file, "MD5", "5d41402abc4b2a76b9719d911017c592"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMatchesPath_wrongHash() throws IOException {
|
||||
Path file = writeFile(HELLO);
|
||||
assertFalse(ChecksumUtils.matches(file, "MD5", "0000000000000000000000000000000000"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMatchesPath_caseInsensitive() throws IOException {
|
||||
Path file = writeFile(HELLO);
|
||||
assertTrue(ChecksumUtils.matches(file, "MD5", "5D41402ABC4B2A76B9719D911017C592"));
|
||||
}
|
||||
|
||||
// --- matches(InputStream, String, String) ---
|
||||
|
||||
@Test
|
||||
void testMatchesStream_correct() throws IOException {
|
||||
try (InputStream is = new ByteArrayInputStream(HELLO)) {
|
||||
assertTrue(
|
||||
ChecksumUtils.matches(is, "SHA-1", "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMatchesStream_wrong() throws IOException {
|
||||
try (InputStream is = new ByteArrayInputStream(HELLO)) {
|
||||
assertFalse(
|
||||
ChecksumUtils.matches(is, "SHA-1", "0000000000000000000000000000000000000000"));
|
||||
}
|
||||
}
|
||||
|
||||
// --- empty input ---
|
||||
|
||||
@Test
|
||||
void testChecksumEmptyInput() throws IOException {
|
||||
byte[] empty = new byte[0];
|
||||
try (InputStream is = new ByteArrayInputStream(empty)) {
|
||||
String hex = ChecksumUtils.checksum(is, "MD5");
|
||||
// MD5 of empty input is d41d8cd98f00b204e9800998ecf8427e
|
||||
assertEquals("d41d8cd98f00b204e9800998ecf8427e", hex);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChecksumCrc32EmptyInput() throws IOException {
|
||||
byte[] empty = new byte[0];
|
||||
try (InputStream is = new ByteArrayInputStream(empty)) {
|
||||
String hex = ChecksumUtils.checksum(is, "CRC32");
|
||||
assertEquals("00000000", hex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class EmlParserTest {
|
||||
|
||||
@Nested
|
||||
@DisplayName("safeMimeDecode")
|
||||
class SafeMimeDecodeTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("should return empty string for null input")
|
||||
void nullInput() {
|
||||
assertEquals("", EmlParser.safeMimeDecode(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should return empty string for empty input")
|
||||
void emptyInput() {
|
||||
assertEquals("", EmlParser.safeMimeDecode(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should return empty string for blank input")
|
||||
void blankInput() {
|
||||
assertEquals("", EmlParser.safeMimeDecode(" "));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should return plain text as-is")
|
||||
void plainText() {
|
||||
assertEquals("Hello World", EmlParser.safeMimeDecode("Hello World"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should trim surrounding whitespace")
|
||||
void trimWhitespace() {
|
||||
assertEquals("Hello", EmlParser.safeMimeDecode(" Hello "));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should decode base64 MIME encoded word")
|
||||
void decodeBase64MimeWord() {
|
||||
// =?UTF-8?B?SGVsbG8=?= is Base64 for "Hello"
|
||||
assertEquals("Hello", EmlParser.safeMimeDecode("=?UTF-8?B?SGVsbG8=?="));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should decode quoted-printable MIME encoded word")
|
||||
void decodeQpMimeWord() {
|
||||
// =?UTF-8?Q?Hello_World?= where _ means space in Q encoding
|
||||
assertEquals("Hello World", EmlParser.safeMimeDecode("=?UTF-8?Q?Hello_World?="));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should handle mixed text and encoded words")
|
||||
void mixedTextAndEncoded() {
|
||||
String input = "Re: =?UTF-8?B?SGVsbG8=?= test";
|
||||
String result = EmlParser.safeMimeDecode(input);
|
||||
assertEquals("Re: Hello test", result);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("extractEmailContent")
|
||||
class ExtractEmailContentTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("should throw on null input")
|
||||
void nullInput() {
|
||||
assertThrows(Exception.class, () -> EmlParser.extractEmailContent(null, null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should throw on empty input")
|
||||
void emptyInput() {
|
||||
assertThrows(
|
||||
Exception.class, () -> EmlParser.extractEmailContent(new byte[0], null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should throw on invalid content that is not EML or MSG")
|
||||
void invalidContent() {
|
||||
byte[] randomBytes = "This is not an email file at all.".getBytes();
|
||||
assertThrows(
|
||||
Exception.class, () -> EmlParser.extractEmailContent(randomBytes, null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class EmlProcessingUtilsTest {
|
||||
|
||||
@Nested
|
||||
@DisplayName("validateEmlInput")
|
||||
class ValidateEmlInputTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("should throw on null input")
|
||||
void nullInput() {
|
||||
assertThrows(Exception.class, () -> EmlProcessingUtils.validateEmlInput(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should throw on empty input")
|
||||
void emptyInput() {
|
||||
assertThrows(Exception.class, () -> EmlProcessingUtils.validateEmlInput(new byte[0]));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should throw on invalid format with insufficient headers")
|
||||
void invalidFormat() {
|
||||
byte[] data = "Hello, this is just random text without email headers.".getBytes();
|
||||
assertThrows(Exception.class, () -> EmlProcessingUtils.validateEmlInput(data));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should accept valid EML with multiple headers")
|
||||
void validEml() {
|
||||
String emlContent =
|
||||
"From: [email protected]\r\n"
|
||||
+ "To: [email protected]\r\n"
|
||||
+ "Subject: Test\r\n"
|
||||
+ "Date: Mon, 1 Jan 2024 00:00:00 +0000\r\n"
|
||||
+ "\r\n"
|
||||
+ "Body text";
|
||||
assertDoesNotThrow(() -> EmlProcessingUtils.validateEmlInput(emlContent.getBytes()));
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("isMsgFile")
|
||||
class IsMsgFileTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("should return false for null")
|
||||
void nullInput() {
|
||||
assertFalse(EmlProcessingUtils.isMsgFile(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should return false for short bytes")
|
||||
void shortBytes() {
|
||||
assertFalse(EmlProcessingUtils.isMsgFile(new byte[] {0x01, 0x02}));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should return true for MSG magic bytes")
|
||||
void msgMagicBytes() {
|
||||
byte[] magic = {
|
||||
(byte) 0xD0,
|
||||
(byte) 0xCF,
|
||||
(byte) 0x11,
|
||||
(byte) 0xE0,
|
||||
(byte) 0xA1,
|
||||
(byte) 0xB1,
|
||||
(byte) 0x1A,
|
||||
(byte) 0xE1,
|
||||
0x00,
|
||||
0x00
|
||||
};
|
||||
assertTrue(EmlProcessingUtils.isMsgFile(magic));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should return false for non-MSG bytes")
|
||||
void nonMsgBytes() {
|
||||
byte[] data = new byte[] {0x50, 0x4B, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00};
|
||||
assertFalse(EmlProcessingUtils.isMsgFile(data));
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("escapeHtml")
|
||||
class EscapeHtmlTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("should return empty string for null")
|
||||
void nullInput() {
|
||||
assertEquals("", EmlProcessingUtils.escapeHtml(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should escape all HTML special characters")
|
||||
void escapeSpecialChars() {
|
||||
String result = EmlProcessingUtils.escapeHtml("<div class=\"test\">'&'</div>");
|
||||
assertEquals("<div class="test">'&'</div>", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should not modify plain text")
|
||||
void plainText() {
|
||||
assertEquals("Hello World", EmlProcessingUtils.escapeHtml("Hello World"));
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("convertTextToHtml")
|
||||
class ConvertTextToHtmlTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("should return empty string for null")
|
||||
void nullInput() {
|
||||
assertEquals("", EmlProcessingUtils.convertTextToHtml(null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should convert newlines to br tags")
|
||||
void newlinesToBr() {
|
||||
String result = EmlProcessingUtils.convertTextToHtml("Line1\nLine2", null);
|
||||
assertTrue(result.contains("<br>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should convert CRLF to br tags")
|
||||
void crlfToBr() {
|
||||
String result = EmlProcessingUtils.convertTextToHtml("Line1\r\nLine2", null);
|
||||
assertTrue(result.contains("<br>"));
|
||||
assertFalse(result.contains("\r"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should linkify URLs")
|
||||
void linkifyUrls() {
|
||||
String result =
|
||||
EmlProcessingUtils.convertTextToHtml("Visit https://example.com today", null);
|
||||
assertTrue(result.contains("<a href=\"https://example.com\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should linkify email addresses")
|
||||
void linkifyEmails() {
|
||||
String result = EmlProcessingUtils.convertTextToHtml("Contact [email protected]", null);
|
||||
assertTrue(result.contains("mailto:[email protected]"));
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("decodeMimeHeader")
|
||||
class DecodeMimeHeaderTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("should return null for null input")
|
||||
void nullInput() {
|
||||
assertNull(EmlProcessingUtils.decodeMimeHeader(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should return empty string for empty input")
|
||||
void emptyInput() {
|
||||
assertEquals("", EmlProcessingUtils.decodeMimeHeader(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should return plain text unchanged")
|
||||
void plainText() {
|
||||
assertEquals("Hello World", EmlProcessingUtils.decodeMimeHeader("Hello World"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should decode Base64 encoded header")
|
||||
void decodeBase64() {
|
||||
// "Hello" in Base64
|
||||
String result = EmlProcessingUtils.decodeMimeHeader("=?UTF-8?B?SGVsbG8=?=");
|
||||
assertEquals("Hello", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should decode quoted-printable encoded header")
|
||||
void decodeQuotedPrintable() {
|
||||
String result = EmlProcessingUtils.decodeMimeHeader("=?UTF-8?Q?Hello_World?=");
|
||||
assertEquals("Hello World", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should decode concatenated encoded words")
|
||||
void decodeConcatenated() {
|
||||
String input = "=?UTF-8?B?SGVs?= =?UTF-8?B?bG8=?=";
|
||||
String result = EmlProcessingUtils.decodeMimeHeader(input);
|
||||
assertEquals("Hello", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should handle unknown encoding gracefully")
|
||||
void unknownEncoding() {
|
||||
String input = "=?UTF-8?X?unknown?=";
|
||||
String result = EmlProcessingUtils.decodeMimeHeader(input);
|
||||
assertEquals("=?UTF-8?X?unknown?=", result);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("detectMimeType")
|
||||
class DetectMimeTypeTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("should return existing MIME type if provided")
|
||||
void existingMimeType() {
|
||||
assertEquals(
|
||||
"image/jpeg", EmlProcessingUtils.detectMimeType("photo.png", "image/jpeg"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should detect PNG from filename")
|
||||
void detectPng() {
|
||||
assertEquals("image/png", EmlProcessingUtils.detectMimeType("image.png", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should detect JPEG from filename")
|
||||
void detectJpeg() {
|
||||
assertEquals("image/jpeg", EmlProcessingUtils.detectMimeType("photo.jpg", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should default to image/png for unknown extension")
|
||||
void defaultMimeType() {
|
||||
assertEquals("image/png", EmlProcessingUtils.detectMimeType("file.xyz", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should default to image/png for null filename and mime")
|
||||
void nullFilenameAndMime() {
|
||||
assertEquals("image/png", EmlProcessingUtils.detectMimeType(null, null));
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("sanitizeText")
|
||||
class SanitizeTextTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("should escape HTML when no sanitizer provided")
|
||||
void noSanitizer() {
|
||||
String result = EmlProcessingUtils.sanitizeText("<script>", null);
|
||||
assertEquals("<script>", result);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("processEmailHtmlBody")
|
||||
class ProcessEmailHtmlBodyTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("should return empty string for null body")
|
||||
void nullBody() {
|
||||
assertEquals("", EmlProcessingUtils.processEmailHtmlBody(null, null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should strip fixed position CSS")
|
||||
void stripFixedPosition() {
|
||||
String html = "<div style=\"position:fixed; top:0\">content</div>";
|
||||
String result = EmlProcessingUtils.processEmailHtmlBody(html, null, null);
|
||||
assertFalse(result.contains("position:fixed"));
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("decodeUrlEncoded")
|
||||
class DecodeUrlEncodedTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("should decode URL-encoded string")
|
||||
void decodeEncoded() {
|
||||
assertEquals("hello world", EmlProcessingUtils.decodeUrlEncoded("hello%20world"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should return original on invalid encoding")
|
||||
void invalidEncoding() {
|
||||
String result = EmlProcessingUtils.decodeUrlEncoded("%ZZinvalid");
|
||||
assertEquals("%ZZinvalid", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
class ErrorUtilsTest {
|
||||
|
||||
@Nested
|
||||
@DisplayName("exceptionToModel")
|
||||
class ExceptionToModelTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("should add error message to model")
|
||||
void addsErrorMessage() {
|
||||
Model model = mock(Model.class);
|
||||
Exception ex = new RuntimeException("test error");
|
||||
|
||||
ErrorUtils.exceptionToModel(model, ex);
|
||||
|
||||
verify(model).addAttribute("errorMessage", "test error");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should add stack trace to model")
|
||||
void addsStackTrace() {
|
||||
Model model = mock(Model.class);
|
||||
Exception ex = new RuntimeException("test error");
|
||||
|
||||
ErrorUtils.exceptionToModel(model, ex);
|
||||
|
||||
verify(model)
|
||||
.addAttribute(
|
||||
eq("stackTrace"),
|
||||
argThat(
|
||||
arg ->
|
||||
arg instanceof String s
|
||||
&& s.contains("RuntimeException")
|
||||
&& s.contains("test error")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should return the same model instance")
|
||||
void returnsSameModel() {
|
||||
Model model = mock(Model.class);
|
||||
Exception ex = new RuntimeException("test");
|
||||
|
||||
Model result = ErrorUtils.exceptionToModel(model, ex);
|
||||
|
||||
assertSame(model, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should handle exception with null message")
|
||||
void nullExceptionMessage() {
|
||||
Model model = mock(Model.class);
|
||||
Exception ex = new RuntimeException((String) null);
|
||||
|
||||
ErrorUtils.exceptionToModel(model, ex);
|
||||
|
||||
verify(model).addAttribute("errorMessage", null);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("exceptionToModelView")
|
||||
class ExceptionToModelViewTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("should create ModelAndView with error message")
|
||||
void addsErrorMessage() {
|
||||
Model model = mock(Model.class);
|
||||
Exception ex = new RuntimeException("view error");
|
||||
|
||||
ModelAndView result = ErrorUtils.exceptionToModelView(model, ex);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals("view error", result.getModel().get("errorMessage"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should create ModelAndView with stack trace")
|
||||
void addsStackTrace() {
|
||||
Model model = mock(Model.class);
|
||||
Exception ex = new RuntimeException("view error");
|
||||
|
||||
ModelAndView result = ErrorUtils.exceptionToModelView(model, ex);
|
||||
|
||||
String stackTrace = (String) result.getModel().get("stackTrace");
|
||||
assertNotNull(stackTrace);
|
||||
assertTrue(stackTrace.contains("RuntimeException"));
|
||||
assertTrue(stackTrace.contains("view error"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should handle nested exception")
|
||||
void nestedException() {
|
||||
Model model = mock(Model.class);
|
||||
Exception cause = new IllegalArgumentException("root cause");
|
||||
Exception ex = new RuntimeException("wrapper", cause);
|
||||
|
||||
ModelAndView result = ErrorUtils.exceptionToModelView(model, ex);
|
||||
|
||||
String stackTrace = (String) result.getModel().get("stackTrace");
|
||||
assertTrue(stackTrace.contains("root cause"));
|
||||
assertEquals("wrapper", result.getModel().get("errorMessage"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class ExecutorFactoryTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("newVirtualThreadExecutor should return non-null executor")
|
||||
void virtualThreadExecutorNotNull() {
|
||||
ExecutorService executor = ExecutorFactory.newVirtualThreadExecutor();
|
||||
assertNotNull(executor);
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("newVirtualThreadExecutor should execute tasks")
|
||||
void virtualThreadExecutorExecutesTasks() throws Exception {
|
||||
ExecutorService executor = ExecutorFactory.newVirtualThreadExecutor();
|
||||
AtomicBoolean ran = new AtomicBoolean(false);
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
executor.submit(
|
||||
() -> {
|
||||
ran.set(true);
|
||||
latch.countDown();
|
||||
});
|
||||
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
assertTrue(ran.get());
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("newVirtualThreadExecutor should run on virtual threads")
|
||||
void virtualThreadExecutorUsesVirtualThreads() throws Exception {
|
||||
ExecutorService executor = ExecutorFactory.newVirtualThreadExecutor();
|
||||
AtomicReference<Boolean> isVirtual = new AtomicReference<>();
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
executor.submit(
|
||||
() -> {
|
||||
isVirtual.set(Thread.currentThread().isVirtual());
|
||||
latch.countDown();
|
||||
});
|
||||
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
assertTrue(isVirtual.get());
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("newSingleVirtualThreadScheduledExecutor should return non-null")
|
||||
void scheduledExecutorNotNull() {
|
||||
ScheduledExecutorService executor =
|
||||
ExecutorFactory.newSingleVirtualThreadScheduledExecutor();
|
||||
assertNotNull(executor);
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("newSingleVirtualThreadScheduledExecutor should execute scheduled tasks")
|
||||
void scheduledExecutorExecutesTasks() throws Exception {
|
||||
ScheduledExecutorService executor =
|
||||
ExecutorFactory.newSingleVirtualThreadScheduledExecutor();
|
||||
AtomicBoolean ran = new AtomicBoolean(false);
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
executor.schedule(
|
||||
() -> {
|
||||
ran.set(true);
|
||||
latch.countDown();
|
||||
},
|
||||
10,
|
||||
TimeUnit.MILLISECONDS);
|
||||
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
assertTrue(ran.get());
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import stirling.software.common.configuration.RuntimePathConfig;
|
||||
|
||||
class FileMonitorTest {
|
||||
|
||||
@TempDir Path tempDir;
|
||||
|
||||
private FileMonitor createFileMonitor(Path watchDir) throws IOException {
|
||||
Predicate<Path> acceptAll = path -> true;
|
||||
RuntimePathConfig runtimePathConfig = mock(RuntimePathConfig.class);
|
||||
when(runtimePathConfig.getPipelineWatchedFoldersPaths())
|
||||
.thenReturn(List.of(watchDir.toString()));
|
||||
return new FileMonitor(acceptAll, runtimePathConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructor_withValidDirectory() throws IOException {
|
||||
FileMonitor monitor = createFileMonitor(tempDir);
|
||||
assertNotNull(monitor);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructor_withNonExistentDirectory() throws IOException {
|
||||
Path nonExistent = tempDir.resolve("does_not_exist");
|
||||
Predicate<Path> acceptAll = path -> true;
|
||||
RuntimePathConfig config = mock(RuntimePathConfig.class);
|
||||
when(config.getPipelineWatchedFoldersPaths()).thenReturn(List.of(nonExistent.toString()));
|
||||
|
||||
// Should not throw - just logs an error about non-existent path
|
||||
FileMonitor monitor = new FileMonitor(acceptAll, config);
|
||||
assertNotNull(monitor);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructor_withEmptyWatchedFolders() throws IOException {
|
||||
Predicate<Path> acceptAll = path -> true;
|
||||
RuntimePathConfig config = mock(RuntimePathConfig.class);
|
||||
when(config.getPipelineWatchedFoldersPaths()).thenReturn(List.of());
|
||||
|
||||
FileMonitor monitor = new FileMonitor(acceptAll, config);
|
||||
assertNotNull(monitor);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTrackFiles_noEventsDoesNotThrow() throws IOException {
|
||||
FileMonitor monitor = createFileMonitor(tempDir);
|
||||
// Should not throw even when no events have occurred
|
||||
assertDoesNotThrow(() -> monitor.trackFiles());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsFileReadyForProcessing_nonExistentFile() throws IOException {
|
||||
FileMonitor monitor = createFileMonitor(tempDir);
|
||||
Path nonExistent = tempDir.resolve("nonexistent.pdf");
|
||||
|
||||
// Non-existent file should not be ready (file lock check will fail)
|
||||
boolean ready = monitor.isFileReadyForProcessing(nonExistent);
|
||||
assertFalse(ready, "Non-existent file should not be ready for processing");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsFileReadyForProcessing_existingFile() throws IOException, InterruptedException {
|
||||
FileMonitor monitor = createFileMonitor(tempDir);
|
||||
Path testFile = tempDir.resolve("test.pdf");
|
||||
Files.writeString(testFile, "test content");
|
||||
|
||||
// Run trackFiles to process any events
|
||||
monitor.trackFiles();
|
||||
|
||||
// The file might or might not be ready depending on timing,
|
||||
// but calling the method should not throw
|
||||
assertDoesNotThrow(() -> monitor.isFileReadyForProcessing(testFile));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTrackFiles_afterFileCreation() throws IOException {
|
||||
FileMonitor monitor = createFileMonitor(tempDir);
|
||||
|
||||
// Create a file in the watched directory
|
||||
Path testFile = tempDir.resolve("newfile.txt");
|
||||
Files.writeString(testFile, "hello");
|
||||
|
||||
// Track files should process the creation event
|
||||
assertDoesNotThrow(() -> monitor.trackFiles());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructor_withPathFilter() throws IOException {
|
||||
// Filter that rejects all paths
|
||||
Predicate<Path> rejectAll = path -> false;
|
||||
RuntimePathConfig config = mock(RuntimePathConfig.class);
|
||||
when(config.getPipelineWatchedFoldersPaths()).thenReturn(List.of(tempDir.toString()));
|
||||
|
||||
FileMonitor monitor = new FileMonitor(rejectAll, config);
|
||||
assertNotNull(monitor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class FileToPdfTest {
|
||||
|
||||
@Test
|
||||
void testSanitizeZipFilename_normalFilename() {
|
||||
String result = FileToPdf.sanitizeZipFilename("document.html");
|
||||
assertEquals("document.html", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitizeZipFilename_pathTraversal() {
|
||||
String result = FileToPdf.sanitizeZipFilename("../../etc/passwd");
|
||||
// Should remove ../ sequences
|
||||
assertFalse(result.contains(".."), "Path traversal sequences should be removed");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitizeZipFilename_driveLetterRemoved() {
|
||||
String result = FileToPdf.sanitizeZipFilename("C:\\Users\\test\\file.html");
|
||||
assertFalse(result.startsWith("C:"), "Drive letter should be removed");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitizeZipFilename_backslashesNormalized() {
|
||||
String result = FileToPdf.sanitizeZipFilename("path\\to\\file.html");
|
||||
assertFalse(result.contains("\\"), "Backslashes should be normalized to forward slashes");
|
||||
assertTrue(result.contains("/") || !result.contains("\\"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitizeZipFilename_nullInput() {
|
||||
String result = FileToPdf.sanitizeZipFilename(null);
|
||||
assertEquals("", result, "Null input should return empty string");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitizeZipFilename_emptyInput() {
|
||||
String result = FileToPdf.sanitizeZipFilename("");
|
||||
assertEquals("", result, "Empty input should return empty string");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitizeZipFilename_whitespaceOnly() {
|
||||
String result = FileToPdf.sanitizeZipFilename(" ");
|
||||
assertEquals("", result, "Whitespace-only input should return empty string");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitizeZipFilename_leadingSlashes() {
|
||||
String result = FileToPdf.sanitizeZipFilename("///path/to/file.html");
|
||||
assertFalse(result.startsWith("/"), "Leading slashes should be removed");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitizeZipFilename_nestedDirectories() {
|
||||
String result = FileToPdf.sanitizeZipFilename("dir1/dir2/file.html");
|
||||
assertEquals("dir1/dir2/file.html", result, "Normal nested paths should be preserved");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitizeZipFilename_mixedTraversal() {
|
||||
String result = FileToPdf.sanitizeZipFilename("dir/../../../etc/passwd");
|
||||
assertFalse(result.contains(".."), "Mixed path traversal should be removed");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitizeZipFilename_backslashTraversal() {
|
||||
String result = FileToPdf.sanitizeZipFilename("dir\\..\\..\\etc\\passwd");
|
||||
assertFalse(result.contains(".."), "Backslash path traversal should be removed");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDCheckBox;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDComboBox;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDListBox;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDPushButton;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDRadioButton;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDTerminalField;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDTextField;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class FormFieldTypeSupportTest {
|
||||
|
||||
@Test
|
||||
void forField_withNull_returnsNull() {
|
||||
assertNull(FormFieldTypeSupport.forField(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void forField_withTextField_returnsTEXT() {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDTextField field = new PDTextField(form);
|
||||
assertEquals(FormFieldTypeSupport.TEXT, FormFieldTypeSupport.forField(field));
|
||||
} catch (Exception e) {
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void forField_withCheckBox_returnsCHECKBOX() {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDCheckBox field = new PDCheckBox(form);
|
||||
assertEquals(FormFieldTypeSupport.CHECKBOX, FormFieldTypeSupport.forField(field));
|
||||
} catch (Exception e) {
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void forField_withRadioButton_returnsRADIO() {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDRadioButton field = new PDRadioButton(form);
|
||||
assertEquals(FormFieldTypeSupport.RADIO, FormFieldTypeSupport.forField(field));
|
||||
} catch (Exception e) {
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void forField_withComboBox_returnsCOMBOBOX() {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDComboBox field = new PDComboBox(form);
|
||||
assertEquals(FormFieldTypeSupport.COMBOBOX, FormFieldTypeSupport.forField(field));
|
||||
} catch (Exception e) {
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void forField_withListBox_returnsLISTBOX() {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDListBox field = new PDListBox(form);
|
||||
assertEquals(FormFieldTypeSupport.LISTBOX, FormFieldTypeSupport.forField(field));
|
||||
} catch (Exception e) {
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void forField_withSignatureField_returnsSIGNATURE() {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDSignatureField field = new PDSignatureField(form);
|
||||
assertEquals(FormFieldTypeSupport.SIGNATURE, FormFieldTypeSupport.forField(field));
|
||||
} catch (Exception e) {
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void forField_withPushButton_returnsBUTTON() {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDPushButton field = new PDPushButton(form);
|
||||
assertEquals(FormFieldTypeSupport.BUTTON, FormFieldTypeSupport.forField(field));
|
||||
} catch (Exception e) {
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void forTypeName_withValidNames_returnsCorrectEnum() {
|
||||
assertEquals(FormFieldTypeSupport.TEXT, FormFieldTypeSupport.forTypeName("text"));
|
||||
assertEquals(FormFieldTypeSupport.CHECKBOX, FormFieldTypeSupport.forTypeName("checkbox"));
|
||||
assertEquals(FormFieldTypeSupport.RADIO, FormFieldTypeSupport.forTypeName("radio"));
|
||||
assertEquals(FormFieldTypeSupport.COMBOBOX, FormFieldTypeSupport.forTypeName("combobox"));
|
||||
assertEquals(FormFieldTypeSupport.LISTBOX, FormFieldTypeSupport.forTypeName("listbox"));
|
||||
assertEquals(FormFieldTypeSupport.SIGNATURE, FormFieldTypeSupport.forTypeName("signature"));
|
||||
assertEquals(FormFieldTypeSupport.BUTTON, FormFieldTypeSupport.forTypeName("button"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void forTypeName_withNull_returnsNull() {
|
||||
assertNull(FormFieldTypeSupport.forTypeName(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void forTypeName_withUnknown_returnsNull() {
|
||||
assertNull(FormFieldTypeSupport.forTypeName("unknown"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotSupportsDefinitionCreation_textReturnsFalse() {
|
||||
assertFalse(FormFieldTypeSupport.TEXT.doesNotsupportsDefinitionCreation());
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotSupportsDefinitionCreation_radioReturnsTrue() {
|
||||
assertTrue(FormFieldTypeSupport.RADIO.doesNotsupportsDefinitionCreation());
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotSupportsDefinitionCreation_signatureReturnsTrue() {
|
||||
assertTrue(FormFieldTypeSupport.SIGNATURE.doesNotsupportsDefinitionCreation());
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotSupportsDefinitionCreation_buttonReturnsTrue() {
|
||||
assertTrue(FormFieldTypeSupport.BUTTON.doesNotsupportsDefinitionCreation());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createField_text_returnsPDTextField() {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDTerminalField field = FormFieldTypeSupport.TEXT.createField(form);
|
||||
assertInstanceOf(PDTextField.class, field);
|
||||
} catch (Exception e) {
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void createField_checkbox_returnsPDCheckBox() {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDTerminalField field = FormFieldTypeSupport.CHECKBOX.createField(form);
|
||||
assertInstanceOf(PDCheckBox.class, field);
|
||||
} catch (Exception e) {
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDResources;
|
||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDCheckBox;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDTextField;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class FormUtilsAdditionalTest {
|
||||
|
||||
private record SetupDocument(PDPage page, PDAcroForm acroForm) {}
|
||||
|
||||
private static SetupDocument createBasicDocument(PDDocument document) throws IOException {
|
||||
PDPage page = new PDPage();
|
||||
document.addPage(page);
|
||||
|
||||
PDAcroForm acroForm = new PDAcroForm(document);
|
||||
acroForm.setDefaultResources(new PDResources());
|
||||
acroForm.setNeedAppearances(true);
|
||||
document.getDocumentCatalog().setAcroForm(acroForm);
|
||||
|
||||
return new SetupDocument(page, acroForm);
|
||||
}
|
||||
|
||||
private static void attachWidget(
|
||||
SetupDocument setup,
|
||||
org.apache.pdfbox.pdmodel.interactive.form.PDTerminalField field,
|
||||
PDRectangle rectangle)
|
||||
throws IOException {
|
||||
PDAnnotationWidget widget = new PDAnnotationWidget();
|
||||
widget.setRectangle(rectangle);
|
||||
widget.setPage(setup.page);
|
||||
List<PDAnnotationWidget> widgets = new ArrayList<>(field.getWidgets());
|
||||
widgets.add(widget);
|
||||
field.setWidgets(widgets);
|
||||
setup.acroForm.getFields().add(field);
|
||||
setup.page.getAnnotations().add(widget);
|
||||
}
|
||||
|
||||
// --- detectFieldType ---
|
||||
|
||||
@Test
|
||||
void testDetectFieldType_textField() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
SetupDocument setup = createBasicDocument(doc);
|
||||
PDTextField field = new PDTextField(setup.acroForm);
|
||||
assertEquals("text", FormUtils.detectFieldType(field));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDetectFieldType_checkBox() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
SetupDocument setup = createBasicDocument(doc);
|
||||
PDCheckBox field = new PDCheckBox(setup.acroForm);
|
||||
assertEquals("checkbox", FormUtils.detectFieldType(field));
|
||||
}
|
||||
}
|
||||
|
||||
// --- extractFormFields ---
|
||||
|
||||
@Test
|
||||
void testExtractFormFields_nullDocument() {
|
||||
List<FormUtils.FormFieldInfo> fields = FormUtils.extractFormFields(null);
|
||||
assertTrue(fields.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExtractFormFields_noAcroForm() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
doc.addPage(new PDPage());
|
||||
// No AcroForm set
|
||||
List<FormUtils.FormFieldInfo> fields = FormUtils.extractFormFields(doc);
|
||||
assertTrue(fields.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExtractFormFields_singleTextField() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
SetupDocument setup = createBasicDocument(doc);
|
||||
PDTextField textField = new PDTextField(setup.acroForm);
|
||||
textField.setPartialName("firstName");
|
||||
attachWidget(setup, textField, new PDRectangle(50, 700, 200, 20));
|
||||
|
||||
List<FormUtils.FormFieldInfo> fields = FormUtils.extractFormFields(doc);
|
||||
assertEquals(1, fields.size());
|
||||
assertEquals("firstName", fields.get(0).name());
|
||||
assertEquals("text", fields.get(0).type());
|
||||
assertEquals(0, fields.get(0).pageIndex());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExtractFormFields_multipleFields() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
SetupDocument setup = createBasicDocument(doc);
|
||||
|
||||
PDTextField field1 = new PDTextField(setup.acroForm);
|
||||
field1.setPartialName("name");
|
||||
attachWidget(setup, field1, new PDRectangle(50, 700, 200, 20));
|
||||
|
||||
PDTextField field2 = new PDTextField(setup.acroForm);
|
||||
field2.setPartialName("email");
|
||||
attachWidget(setup, field2, new PDRectangle(50, 660, 200, 20));
|
||||
|
||||
List<FormUtils.FormFieldInfo> fields = FormUtils.extractFormFields(doc);
|
||||
assertEquals(2, fields.size());
|
||||
}
|
||||
}
|
||||
|
||||
// --- buildFillTemplateRecord ---
|
||||
|
||||
@Test
|
||||
void testBuildFillTemplateRecord_null() {
|
||||
Map<String, Object> result = FormUtils.buildFillTemplateRecord(null);
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuildFillTemplateRecord_empty() {
|
||||
Map<String, Object> result = FormUtils.buildFillTemplateRecord(Collections.emptyList());
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuildFillTemplateRecord_textField() {
|
||||
FormUtils.FormFieldInfo info =
|
||||
new FormUtils.FormFieldInfo(
|
||||
"name", "Name", "text", "John", null, false, 0, false, null, 0);
|
||||
Map<String, Object> result = FormUtils.buildFillTemplateRecord(List.of(info));
|
||||
assertEquals("John", result.get("name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuildFillTemplateRecord_checkboxField() {
|
||||
FormUtils.FormFieldInfo info =
|
||||
new FormUtils.FormFieldInfo(
|
||||
"agree", "Agreement", "checkbox", "Yes", null, false, 0, false, null, 0);
|
||||
Map<String, Object> result = FormUtils.buildFillTemplateRecord(List.of(info));
|
||||
assertEquals(Boolean.TRUE, result.get("agree"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuildFillTemplateRecord_checkboxFieldOff() {
|
||||
FormUtils.FormFieldInfo info =
|
||||
new FormUtils.FormFieldInfo(
|
||||
"agree", "Agreement", "checkbox", "Off", null, false, 0, false, null, 0);
|
||||
Map<String, Object> result = FormUtils.buildFillTemplateRecord(List.of(info));
|
||||
assertEquals(Boolean.FALSE, result.get("agree"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuildFillTemplateRecord_skipsButton() {
|
||||
FormUtils.FormFieldInfo info =
|
||||
new FormUtils.FormFieldInfo(
|
||||
"submit", "Submit", "button", null, null, false, 0, false, null, 0);
|
||||
Map<String, Object> result = FormUtils.buildFillTemplateRecord(List.of(info));
|
||||
assertFalse(result.containsKey("submit"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuildFillTemplateRecord_skipsSignature() {
|
||||
FormUtils.FormFieldInfo info =
|
||||
new FormUtils.FormFieldInfo(
|
||||
"sig", "Signature", "signature", null, null, false, 0, false, null, 0);
|
||||
Map<String, Object> result = FormUtils.buildFillTemplateRecord(List.of(info));
|
||||
assertFalse(result.containsKey("sig"));
|
||||
}
|
||||
|
||||
// --- safeValue ---
|
||||
|
||||
@Test
|
||||
void testSafeValue_nonNull() {
|
||||
assertEquals("hello", FormUtils.safeValue("hello"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSafeValue_null() {
|
||||
assertEquals("", FormUtils.safeValue(null));
|
||||
}
|
||||
|
||||
// --- applyFieldValues ---
|
||||
|
||||
@Test
|
||||
void testApplyFieldValues_nullDocument() throws IOException {
|
||||
// Should not throw
|
||||
FormUtils.applyFieldValues(null, Map.of("key", "value"), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testApplyFieldValues_noAcroFormStrict() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
doc.addPage(new PDPage());
|
||||
assertThrows(
|
||||
IOException.class,
|
||||
() -> FormUtils.applyFieldValues(doc, Map.of("key", "val"), false, true));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testApplyFieldValues_noAcroFormNonStrict() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
doc.addPage(new PDPage());
|
||||
// Should not throw in non-strict mode
|
||||
FormUtils.applyFieldValues(doc, Map.of("key", "val"), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testApplyFieldValues_setsTextValue() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
SetupDocument setup = createBasicDocument(doc);
|
||||
PDTextField textField = new PDTextField(setup.acroForm);
|
||||
textField.setPartialName("company");
|
||||
attachWidget(setup, textField, new PDRectangle(60, 720, 220, 20));
|
||||
|
||||
FormUtils.applyFieldValues(doc, Map.of("company", "Stirling"), false);
|
||||
assertEquals("Stirling", textField.getValueAsString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testApplyFieldValues_checksCheckbox_nonStrict() throws IOException {
|
||||
// In non-strict mode, checkbox state changes may fail silently
|
||||
// if appearance streams are not properly configured. Just verify no exception.
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
SetupDocument setup = createBasicDocument(doc);
|
||||
PDCheckBox checkBox = new PDCheckBox(setup.acroForm);
|
||||
checkBox.setPartialName("subscribed");
|
||||
checkBox.setExportValues(List.of("Yes"));
|
||||
attachWidget(setup, checkBox, new PDRectangle(60, 680, 16, 16));
|
||||
|
||||
// Should not throw in non-strict mode even if appearance is missing
|
||||
FormUtils.applyFieldValues(doc, Map.of("subscribed", true), false, false);
|
||||
FormUtils.applyFieldValues(doc, Map.of("subscribed", false), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
// --- filterSingleChoiceSelection ---
|
||||
|
||||
@Test
|
||||
void testFilterSingleChoiceSelection_validSelection() {
|
||||
String result =
|
||||
FormUtils.filterSingleChoiceSelection(
|
||||
"Option A", List.of("Option A", "Option B"), "field1");
|
||||
assertEquals("Option A", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFilterSingleChoiceSelection_invalidSelection() {
|
||||
String result =
|
||||
FormUtils.filterSingleChoiceSelection(
|
||||
"Invalid", List.of("Option A", "Option B"), "field1");
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFilterSingleChoiceSelection_nullSelection() {
|
||||
String result = FormUtils.filterSingleChoiceSelection(null, List.of("Option A"), "field1");
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFilterSingleChoiceSelection_emptySelection() {
|
||||
String result = FormUtils.filterSingleChoiceSelection(" ", List.of("Option A"), "field1");
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
// --- extractFieldsWithTemplate ---
|
||||
|
||||
@Test
|
||||
void testExtractFieldsWithTemplate_emptyDocument() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
doc.addPage(new PDPage());
|
||||
FormUtils.FormFieldExtraction extraction = FormUtils.extractFieldsWithTemplate(doc);
|
||||
assertNotNull(extraction);
|
||||
assertTrue(extraction.fields().isEmpty());
|
||||
assertTrue(extraction.template().isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
// --- hasAnyRotatedPage ---
|
||||
|
||||
@Test
|
||||
void testHasAnyRotatedPage_noRotation() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
doc.addPage(new PDPage());
|
||||
assertFalse(FormUtils.hasAnyRotatedPage(doc));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class GeneralFormCopyUtilsTest {
|
||||
|
||||
@Test
|
||||
void hasAnyRotatedPage_noRotation_returnsFalse() throws Exception {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
doc.addPage(new PDPage());
|
||||
doc.addPage(new PDPage());
|
||||
assertFalse(GeneralFormCopyUtils.hasAnyRotatedPage(doc));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasAnyRotatedPage_with90Rotation_returnsTrue() throws Exception {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDPage page = new PDPage();
|
||||
page.setRotation(90);
|
||||
doc.addPage(page);
|
||||
assertTrue(GeneralFormCopyUtils.hasAnyRotatedPage(doc));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasAnyRotatedPage_with180Rotation_returnsTrue() throws Exception {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDPage page = new PDPage();
|
||||
page.setRotation(180);
|
||||
doc.addPage(page);
|
||||
assertTrue(GeneralFormCopyUtils.hasAnyRotatedPage(doc));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasAnyRotatedPage_with360Rotation_returnsFalse() throws Exception {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDPage page = new PDPage();
|
||||
page.setRotation(360);
|
||||
doc.addPage(page);
|
||||
assertFalse(GeneralFormCopyUtils.hasAnyRotatedPage(doc));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasAnyRotatedPage_emptyDocument_returnsFalse() throws Exception {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
assertFalse(GeneralFormCopyUtils.hasAnyRotatedPage(doc));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasAnyRotatedPage_mixedPages_returnsTrue() throws Exception {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
doc.addPage(new PDPage());
|
||||
PDPage rotated = new PDPage();
|
||||
rotated.setRotation(270);
|
||||
doc.addPage(rotated);
|
||||
assertTrue(GeneralFormCopyUtils.hasAnyRotatedPage(doc));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void copyAndTransformFormFields_noAcroForm_doesNotThrow() throws Exception {
|
||||
try (PDDocument source = new PDDocument();
|
||||
PDDocument target = new PDDocument()) {
|
||||
source.addPage(new PDPage());
|
||||
target.addPage(new PDPage());
|
||||
// No acro form set on source - should simply return without error
|
||||
assertDoesNotThrow(
|
||||
() ->
|
||||
GeneralFormCopyUtils.copyAndTransformFormFields(
|
||||
source, target, 1, 1, 1, 1, 612f, 792f));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void copyAndTransformFormFields_emptyAcroForm_doesNotThrow() throws Exception {
|
||||
try (PDDocument source = new PDDocument();
|
||||
PDDocument target = new PDDocument()) {
|
||||
source.addPage(new PDPage());
|
||||
target.addPage(new PDPage());
|
||||
// Empty acro form
|
||||
var acroForm = new org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm(source);
|
||||
source.getDocumentCatalog().setAcroForm(acroForm);
|
||||
assertDoesNotThrow(
|
||||
() ->
|
||||
GeneralFormCopyUtils.copyAndTransformFormFields(
|
||||
source, target, 1, 1, 1, 1, 612f, 792f));
|
||||
}
|
||||
}
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDCheckBox;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDComboBox;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDListBox;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDPushButton;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDRadioButton;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDTerminalField;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDTextField;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class GeneralFormFieldTypeSupportTest {
|
||||
|
||||
@Test
|
||||
void forField_withNull_returnsNull() {
|
||||
assertNull(GeneralFormFieldTypeSupport.forField(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void forField_withTextField_returnsTEXT() throws Exception {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDTextField field = new PDTextField(form);
|
||||
assertEquals(
|
||||
GeneralFormFieldTypeSupport.TEXT, GeneralFormFieldTypeSupport.forField(field));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void forField_withCheckBox_returnsCHECKBOX() throws Exception {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDCheckBox field = new PDCheckBox(form);
|
||||
assertEquals(
|
||||
GeneralFormFieldTypeSupport.CHECKBOX,
|
||||
GeneralFormFieldTypeSupport.forField(field));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void forField_withRadioButton_returnsRADIO() throws Exception {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDRadioButton field = new PDRadioButton(form);
|
||||
assertEquals(
|
||||
GeneralFormFieldTypeSupport.RADIO, GeneralFormFieldTypeSupport.forField(field));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void forField_withComboBox_returnsCOMBOBOX() throws Exception {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDComboBox field = new PDComboBox(form);
|
||||
assertEquals(
|
||||
GeneralFormFieldTypeSupport.COMBOBOX,
|
||||
GeneralFormFieldTypeSupport.forField(field));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void forField_withListBox_returnsLISTBOX() throws Exception {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDListBox field = new PDListBox(form);
|
||||
assertEquals(
|
||||
GeneralFormFieldTypeSupport.LISTBOX,
|
||||
GeneralFormFieldTypeSupport.forField(field));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void forField_withSignatureField_returnsSIGNATURE() throws Exception {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDSignatureField field = new PDSignatureField(form);
|
||||
assertEquals(
|
||||
GeneralFormFieldTypeSupport.SIGNATURE,
|
||||
GeneralFormFieldTypeSupport.forField(field));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void forField_withPushButton_returnsBUTTON() throws Exception {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDPushButton field = new PDPushButton(form);
|
||||
assertEquals(
|
||||
GeneralFormFieldTypeSupport.BUTTON,
|
||||
GeneralFormFieldTypeSupport.forField(field));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void createField_text_returnsPDTextField() throws Exception {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDTerminalField field = GeneralFormFieldTypeSupport.TEXT.createField(form);
|
||||
assertInstanceOf(PDTextField.class, field);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void createField_checkbox_returnsPDCheckBox() throws Exception {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDTerminalField field = GeneralFormFieldTypeSupport.CHECKBOX.createField(form);
|
||||
assertInstanceOf(PDCheckBox.class, field);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void createField_signature_returnsPDSignatureField() throws Exception {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDAcroForm form = new PDAcroForm(doc);
|
||||
PDTerminalField field = GeneralFormFieldTypeSupport.SIGNATURE.createField(form);
|
||||
assertInstanceOf(PDSignatureField.class, field);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void typeName_returnsExpectedValues() {
|
||||
assertEquals("text", GeneralFormFieldTypeSupport.TEXT.typeName());
|
||||
assertEquals("checkbox", GeneralFormFieldTypeSupport.CHECKBOX.typeName());
|
||||
assertEquals("radio", GeneralFormFieldTypeSupport.RADIO.typeName());
|
||||
assertEquals("combobox", GeneralFormFieldTypeSupport.COMBOBOX.typeName());
|
||||
assertEquals("listbox", GeneralFormFieldTypeSupport.LISTBOX.typeName());
|
||||
assertEquals("signature", GeneralFormFieldTypeSupport.SIGNATURE.typeName());
|
||||
assertEquals("button", GeneralFormFieldTypeSupport.BUTTON.typeName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void fallbackWidgetName_returnsExpectedValues() {
|
||||
assertEquals("textField", GeneralFormFieldTypeSupport.TEXT.fallbackWidgetName());
|
||||
assertEquals("checkBox", GeneralFormFieldTypeSupport.CHECKBOX.fallbackWidgetName());
|
||||
assertEquals("radioButton", GeneralFormFieldTypeSupport.RADIO.fallbackWidgetName());
|
||||
assertEquals("comboBox", GeneralFormFieldTypeSupport.COMBOBOX.fallbackWidgetName());
|
||||
assertEquals("listBox", GeneralFormFieldTypeSupport.LISTBOX.fallbackWidgetName());
|
||||
assertEquals("signature", GeneralFormFieldTypeSupport.SIGNATURE.fallbackWidgetName());
|
||||
assertEquals("pushButton", GeneralFormFieldTypeSupport.BUTTON.fallbackWidgetName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferByte;
|
||||
import java.awt.image.DataBufferInt;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class ImageProcessingUtilsTest {
|
||||
|
||||
@Test
|
||||
void convertColorType_greyscale_returnsGrayscaleImage() {
|
||||
BufferedImage source = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB);
|
||||
BufferedImage result = ImageProcessingUtils.convertColorType(source, "greyscale");
|
||||
assertEquals(BufferedImage.TYPE_BYTE_GRAY, result.getType());
|
||||
assertEquals(10, result.getWidth());
|
||||
assertEquals(10, result.getHeight());
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertColorType_blackwhite_returnsBinaryImage() {
|
||||
BufferedImage source = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB);
|
||||
BufferedImage result = ImageProcessingUtils.convertColorType(source, "blackwhite");
|
||||
assertEquals(BufferedImage.TYPE_BYTE_BINARY, result.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertColorType_fullColor_returnsSameImage() {
|
||||
BufferedImage source = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB);
|
||||
BufferedImage result = ImageProcessingUtils.convertColorType(source, "fullcolor");
|
||||
assertSame(source, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertColorType_unknownType_returnsSameImage() {
|
||||
BufferedImage source = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB);
|
||||
BufferedImage result = ImageProcessingUtils.convertColorType(source, "something_else");
|
||||
assertSame(source, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getImageData_byteBuffer_returnsCorrectData() {
|
||||
BufferedImage image = new BufferedImage(2, 2, BufferedImage.TYPE_BYTE_GRAY);
|
||||
byte[] data = ImageProcessingUtils.getImageData(image);
|
||||
assertNotNull(data);
|
||||
assertTrue(data instanceof byte[]);
|
||||
// TYPE_BYTE_GRAY uses DataBufferByte
|
||||
assertTrue(image.getRaster().getDataBuffer() instanceof DataBufferByte);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getImageData_intBuffer_returnsCorrectLength() {
|
||||
BufferedImage image = new BufferedImage(2, 2, BufferedImage.TYPE_INT_RGB);
|
||||
// TYPE_INT_RGB uses DataBufferInt
|
||||
assertTrue(image.getRaster().getDataBuffer() instanceof DataBufferInt);
|
||||
byte[] data = ImageProcessingUtils.getImageData(image);
|
||||
assertNotNull(data);
|
||||
// 2x2 pixels, 4 bytes per int
|
||||
assertEquals(2 * 2 * 4, data.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getImageData_ushortBuffer_returnsRGBData() {
|
||||
// TYPE_USHORT_GRAY uses DataBufferUShort which hits the else branch
|
||||
BufferedImage image = new BufferedImage(2, 2, BufferedImage.TYPE_USHORT_GRAY);
|
||||
byte[] data = ImageProcessingUtils.getImageData(image);
|
||||
assertNotNull(data);
|
||||
// 2x2 pixels, 3 bytes per pixel (RGB)
|
||||
assertEquals(2 * 2 * 3, data.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyOrientation_zeroRotation_returnsSameImage() {
|
||||
BufferedImage image = new BufferedImage(10, 20, BufferedImage.TYPE_INT_RGB);
|
||||
BufferedImage result = ImageProcessingUtils.applyOrientation(image, 0);
|
||||
assertSame(image, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyOrientation_90degrees_returnsRotatedImage() {
|
||||
BufferedImage image = new BufferedImage(10, 20, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g = image.createGraphics();
|
||||
g.setColor(Color.RED);
|
||||
g.fillRect(0, 0, 10, 20);
|
||||
g.dispose();
|
||||
|
||||
BufferedImage result = ImageProcessingUtils.applyOrientation(image, 90);
|
||||
assertNotNull(result);
|
||||
// The rotated image should have non-zero dimensions
|
||||
assertTrue(result.getWidth() > 0);
|
||||
assertTrue(result.getHeight() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyOrientation_180degrees_returnsRotatedImage() {
|
||||
BufferedImage image = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB);
|
||||
BufferedImage result = ImageProcessingUtils.applyOrientation(image, 180);
|
||||
assertNotNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyOrientation_270degrees_returnsRotatedImage() {
|
||||
BufferedImage image = new BufferedImage(10, 20, BufferedImage.TYPE_INT_RGB);
|
||||
BufferedImage result = ImageProcessingUtils.applyOrientation(image, 270);
|
||||
assertNotNull(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class JarPathUtilTest {
|
||||
|
||||
@Test
|
||||
void currentJar_notRunningFromJar_returnsNull() {
|
||||
// When running tests from IDE/Gradle, we are not in a JAR
|
||||
Path result = JarPathUtil.currentJar();
|
||||
assertNull(result, "Should return null when not running from a JAR file");
|
||||
}
|
||||
|
||||
@Test
|
||||
void restartHelperJar_notFound_returnsNull() {
|
||||
// Since we're not running from JAR and restart-helper.jar likely doesn't exist
|
||||
Path result = JarPathUtil.restartHelperJar();
|
||||
assertNull(result, "Should return null when restart-helper.jar is not found");
|
||||
}
|
||||
|
||||
@Test
|
||||
void javaExecutable_returnsNonNullPath() {
|
||||
String result = JarPathUtil.javaExecutable();
|
||||
assertNotNull(result);
|
||||
assertTrue(result.contains("java"), "Should contain 'java' in the path");
|
||||
assertTrue(result.contains("bin"), "Should contain 'bin' in the path");
|
||||
}
|
||||
|
||||
@Test
|
||||
void javaExecutable_containsJavaHome() {
|
||||
String javaHome = System.getProperty("java.home");
|
||||
String result = JarPathUtil.javaExecutable();
|
||||
assertTrue(result.startsWith(javaHome), "Should start with java.home system property");
|
||||
}
|
||||
|
||||
@Test
|
||||
void javaExecutable_windowsHasExeExtension() {
|
||||
String result = JarPathUtil.javaExecutable();
|
||||
if (System.getProperty("os.name").toLowerCase().contains("win")) {
|
||||
assertTrue(result.endsWith(".exe"), "On Windows, should end with .exe");
|
||||
} else {
|
||||
assertFalse(result.endsWith(".exe"), "On non-Windows, should not end with .exe");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class JobContextTest {
|
||||
|
||||
@AfterEach
|
||||
void cleanup() {
|
||||
JobContext.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should return null when no job ID is set")
|
||||
void returnsNullByDefault() {
|
||||
assertNull(JobContext.getJobId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should store and retrieve job ID")
|
||||
void setAndGet() {
|
||||
JobContext.setJobId("job-123");
|
||||
assertEquals("job-123", JobContext.getJobId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should clear job ID")
|
||||
void clearJobId() {
|
||||
JobContext.setJobId("job-456");
|
||||
JobContext.clear();
|
||||
assertNull(JobContext.getJobId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should isolate job IDs between threads")
|
||||
void threadIsolation() throws Exception {
|
||||
JobContext.setJobId("main-job");
|
||||
|
||||
Thread other =
|
||||
new Thread(
|
||||
() -> {
|
||||
assertNull(JobContext.getJobId());
|
||||
JobContext.setJobId("other-job");
|
||||
assertEquals("other-job", JobContext.getJobId());
|
||||
});
|
||||
other.start();
|
||||
other.join();
|
||||
|
||||
assertEquals("main-job", JobContext.getJobId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should allow overwriting job ID")
|
||||
void overwriteJobId() {
|
||||
JobContext.setJobId("first");
|
||||
JobContext.setJobId("second");
|
||||
assertEquals("second", JobContext.getJobId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
||||
|
||||
class PDFServiceTest {
|
||||
|
||||
private PDFService pdfService;
|
||||
private CustomPDFDocumentFactory mockFactory;
|
||||
private final List<PDDocument> documentsToClose = new ArrayList<>();
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
mockFactory = mock(CustomPDFDocumentFactory.class);
|
||||
pdfService = new PDFService(mockFactory);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws IOException {
|
||||
for (PDDocument doc : documentsToClose) {
|
||||
try {
|
||||
doc.close();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PDDocument createDocWithPages(int pageCount) {
|
||||
PDDocument doc = new PDDocument();
|
||||
for (int i = 0; i < pageCount; i++) {
|
||||
doc.addPage(new PDPage());
|
||||
}
|
||||
documentsToClose.add(doc);
|
||||
return doc;
|
||||
}
|
||||
|
||||
@Test
|
||||
void mergeDocuments_twoDocuments_mergesPages() throws IOException {
|
||||
PDDocument merged = new PDDocument();
|
||||
documentsToClose.add(merged);
|
||||
when(mockFactory.createNewDocument()).thenReturn(merged);
|
||||
|
||||
PDDocument doc1 = createDocWithPages(2);
|
||||
PDDocument doc2 = createDocWithPages(3);
|
||||
|
||||
PDDocument result = pdfService.mergeDocuments(List.of(doc1, doc2));
|
||||
assertEquals(5, result.getNumberOfPages());
|
||||
}
|
||||
|
||||
@Test
|
||||
void mergeDocuments_emptyList_returnsEmptyDocument() throws IOException {
|
||||
PDDocument merged = new PDDocument();
|
||||
documentsToClose.add(merged);
|
||||
when(mockFactory.createNewDocument()).thenReturn(merged);
|
||||
|
||||
PDDocument result = pdfService.mergeDocuments(List.of());
|
||||
assertEquals(0, result.getNumberOfPages());
|
||||
}
|
||||
|
||||
@Test
|
||||
void mergeDocuments_singleDocument_returnsSamePages() throws IOException {
|
||||
PDDocument merged = new PDDocument();
|
||||
documentsToClose.add(merged);
|
||||
when(mockFactory.createNewDocument()).thenReturn(merged);
|
||||
|
||||
PDDocument doc1 = createDocWithPages(4);
|
||||
|
||||
PDDocument result = pdfService.mergeDocuments(List.of(doc1));
|
||||
assertEquals(4, result.getNumberOfPages());
|
||||
}
|
||||
|
||||
@Test
|
||||
void mergeDocuments_factoryCalled() throws IOException {
|
||||
PDDocument merged = new PDDocument();
|
||||
documentsToClose.add(merged);
|
||||
when(mockFactory.createNewDocument()).thenReturn(merged);
|
||||
|
||||
PDDocument doc1 = createDocWithPages(1);
|
||||
|
||||
pdfService.mergeDocuments(List.of(doc1));
|
||||
verify(mockFactory).createNewDocument();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class PdfAttachmentHandlerTest {
|
||||
|
||||
@Test
|
||||
void formatEmailDate_nullDate_returnsEmptyString() {
|
||||
assertEquals("", PdfAttachmentHandler.formatEmailDate((Date) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void formatEmailDate_nullZonedDateTime_returnsEmptyString() {
|
||||
assertEquals("", PdfAttachmentHandler.formatEmailDate((ZonedDateTime) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void formatEmailDate_validDate_returnsFormattedString() {
|
||||
// Create a date: January 15, 2024 10:30 AM UTC
|
||||
GregorianCalendar cal = new GregorianCalendar(java.util.TimeZone.getTimeZone("UTC"));
|
||||
cal.set(2024, 0, 15, 10, 30, 0);
|
||||
cal.set(java.util.Calendar.MILLISECOND, 0);
|
||||
Date date = cal.getTime();
|
||||
|
||||
String result = PdfAttachmentHandler.formatEmailDate(date);
|
||||
assertNotNull(result);
|
||||
assertFalse(result.isEmpty());
|
||||
// Should contain the date components
|
||||
assertTrue(result.contains("2024"));
|
||||
assertTrue(result.contains("Jan"));
|
||||
assertTrue(result.contains("15"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void formatEmailDate_zonedDateTime_returnsUTCFormatted() {
|
||||
ZonedDateTime dateTime =
|
||||
ZonedDateTime.of(2024, 3, 15, 14, 30, 0, 0, ZoneId.of("America/New_York"));
|
||||
String result = PdfAttachmentHandler.formatEmailDate(dateTime);
|
||||
assertNotNull(result);
|
||||
assertFalse(result.isEmpty());
|
||||
// Should be converted to UTC
|
||||
assertTrue(result.contains("UTC"));
|
||||
assertTrue(result.contains("2024"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void processInlineImages_nullHtmlContent_returnsNull() {
|
||||
String result = PdfAttachmentHandler.processInlineImages(null, null);
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void processInlineImages_nullEmailContent_returnsOriginal() {
|
||||
String html = "<html><body>test</body></html>";
|
||||
String result = PdfAttachmentHandler.processInlineImages(html, null);
|
||||
assertEquals(html, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void processInlineImages_noCidReferences_returnsOriginal() {
|
||||
EmlParser.EmailContent emailContent = new EmlParser.EmailContent();
|
||||
String html = "<html><body><img src='test.png'/></body></html>";
|
||||
String result = PdfAttachmentHandler.processInlineImages(html, emailContent);
|
||||
assertEquals(html, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void markerPosition_constructorAndGetters() {
|
||||
PdfAttachmentHandler.MarkerPosition pos =
|
||||
new PdfAttachmentHandler.MarkerPosition(2, 100.5f, 200.3f, "@", "test.pdf");
|
||||
assertEquals(2, pos.getPageIndex());
|
||||
assertEquals(100.5f, pos.getX(), 0.001f);
|
||||
assertEquals(200.3f, pos.getY(), 0.001f);
|
||||
assertEquals("@", pos.getCharacter());
|
||||
assertEquals("test.pdf", pos.getFilename());
|
||||
}
|
||||
|
||||
@Test
|
||||
void markerPosition_setters() {
|
||||
PdfAttachmentHandler.MarkerPosition pos =
|
||||
new PdfAttachmentHandler.MarkerPosition(0, 0f, 0f, "@", null);
|
||||
pos.setPageIndex(5);
|
||||
pos.setX(50.0f);
|
||||
pos.setY(75.0f);
|
||||
pos.setFilename("doc.pdf");
|
||||
assertEquals(5, pos.getPageIndex());
|
||||
assertEquals(50.0f, pos.getX(), 0.001f);
|
||||
assertEquals(75.0f, pos.getY(), 0.001f);
|
||||
assertEquals("doc.pdf", pos.getFilename());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
class PdfErrorUtilsTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(
|
||||
strings = {
|
||||
"Missing root object specification",
|
||||
"Header doesn't contain versioninfo",
|
||||
"Expected trailer",
|
||||
"Invalid PDF",
|
||||
"Corrupted",
|
||||
"damaged",
|
||||
"Unknown dir object",
|
||||
"Can't dereference COSObject",
|
||||
"parseCOSString string should start with",
|
||||
"ICCBased colorspace array must have a stream",
|
||||
"1-based index not found",
|
||||
"Invalid dictionary, found:",
|
||||
"AES initialization vector not fully read",
|
||||
"BadPaddingException",
|
||||
"Given final block not properly padded",
|
||||
"End-of-File, expected line"
|
||||
})
|
||||
void isCorruptedPdfError_ioException_corruptionIndicators_returnsTrue(String message) {
|
||||
IOException e = new IOException(message);
|
||||
assertTrue(PdfErrorUtils.isCorruptedPdfError(e));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(
|
||||
strings = {
|
||||
"Missing root object specification in the file",
|
||||
"Header doesn't contain versioninfo xyz",
|
||||
"Some prefix Corrupted suffix"
|
||||
})
|
||||
void isCorruptedPdfError_ioException_messagesContainingIndicators_returnsTrue(String message) {
|
||||
IOException e = new IOException(message);
|
||||
assertTrue(PdfErrorUtils.isCorruptedPdfError(e));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCorruptedPdfError_ioException_normalError_returnsFalse() {
|
||||
IOException e = new IOException("File not found");
|
||||
assertFalse(PdfErrorUtils.isCorruptedPdfError(e));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCorruptedPdfError_ioException_nullMessage_returnsFalse() {
|
||||
IOException e = new IOException((String) null);
|
||||
assertFalse(PdfErrorUtils.isCorruptedPdfError(e));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCorruptedPdfError_genericException_corruptionMessage_returnsTrue() {
|
||||
Exception e = new RuntimeException("Invalid PDF structure");
|
||||
assertTrue(PdfErrorUtils.isCorruptedPdfError(e));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCorruptedPdfError_genericException_normalMessage_returnsFalse() {
|
||||
Exception e = new RuntimeException("Something went wrong");
|
||||
assertFalse(PdfErrorUtils.isCorruptedPdfError(e));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCorruptedPdfError_genericException_nullMessage_returnsFalse() {
|
||||
Exception e = new RuntimeException((String) null);
|
||||
assertFalse(PdfErrorUtils.isCorruptedPdfError(e));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isCorruptedPdfError_ioException_emptyMessage_returnsFalse() {
|
||||
IOException e = new IOException("");
|
||||
assertFalse(PdfErrorUtils.isCorruptedPdfError(e));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
class PdfToCbrUtilsTest {
|
||||
|
||||
@Test
|
||||
void isPdfFile_pdfExtension_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("document.pdf");
|
||||
assertTrue(PdfToCbrUtils.isPdfFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isPdfFile_uppercasePdfExtension_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("document.PDF");
|
||||
assertTrue(PdfToCbrUtils.isPdfFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isPdfFile_mixedCasePdfExtension_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("document.Pdf");
|
||||
assertTrue(PdfToCbrUtils.isPdfFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isPdfFile_nonPdfExtension_returnsFalse() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("document.txt");
|
||||
assertFalse(PdfToCbrUtils.isPdfFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isPdfFile_nullFilename_returnsFalse() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn(null);
|
||||
assertFalse(PdfToCbrUtils.isPdfFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isPdfFile_imageExtension_returnsFalse() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("image.png");
|
||||
assertFalse(PdfToCbrUtils.isPdfFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertPdfToCbr_nullFile_throwsException() {
|
||||
assertThrows(Exception.class, () -> PdfToCbrUtils.convertPdfToCbr(null, 300, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertPdfToCbr_emptyFile_throwsException() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.isEmpty()).thenReturn(true);
|
||||
assertThrows(Exception.class, () -> PdfToCbrUtils.convertPdfToCbr(file, 300, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertPdfToCbr_nonPdfFile_throwsException() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.isEmpty()).thenReturn(false);
|
||||
when(file.getOriginalFilename()).thenReturn("image.png");
|
||||
assertThrows(Exception.class, () -> PdfToCbrUtils.convertPdfToCbr(file, 300, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertPdfToCbr_nullFilename_throwsException() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.isEmpty()).thenReturn(false);
|
||||
when(file.getOriginalFilename()).thenReturn(null);
|
||||
assertThrows(Exception.class, () -> PdfToCbrUtils.convertPdfToCbr(file, 300, null));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
class PdfToCbzUtilsTest {
|
||||
|
||||
@Test
|
||||
void isPdfFile_pdfExtension_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("document.pdf");
|
||||
assertTrue(PdfToCbzUtils.isPdfFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isPdfFile_uppercasePdfExtension_returnsTrue() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("DOCUMENT.PDF");
|
||||
assertTrue(PdfToCbzUtils.isPdfFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isPdfFile_nonPdfExtension_returnsFalse() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("document.docx");
|
||||
assertFalse(PdfToCbzUtils.isPdfFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isPdfFile_nullFilename_returnsFalse() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn(null);
|
||||
assertFalse(PdfToCbzUtils.isPdfFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isPdfFile_noExtension_returnsFalse() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.getOriginalFilename()).thenReturn("document");
|
||||
assertFalse(PdfToCbzUtils.isPdfFile(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertPdfToCbz_nullFile_throwsException() {
|
||||
assertThrows(Exception.class, () -> PdfToCbzUtils.convertPdfToCbz(null, 300, null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertPdfToCbz_emptyFile_throwsException() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.isEmpty()).thenReturn(true);
|
||||
assertThrows(Exception.class, () -> PdfToCbzUtils.convertPdfToCbz(file, 300, null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertPdfToCbz_nonPdfFile_throwsException() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.isEmpty()).thenReturn(false);
|
||||
when(file.getOriginalFilename()).thenReturn("image.jpg");
|
||||
assertThrows(Exception.class, () -> PdfToCbzUtils.convertPdfToCbz(file, 300, null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertPdfToCbz_nullFilename_throwsException() {
|
||||
MultipartFile file = mock(MultipartFile.class);
|
||||
when(file.isEmpty()).thenReturn(false);
|
||||
when(file.getOriginalFilename()).thenReturn(null);
|
||||
assertThrows(Exception.class, () -> PdfToCbzUtils.convertPdfToCbz(file, 300, null, null));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDResources;
|
||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
class PdfUtilsTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({"A0", "A1", "A2", "A3", "A4", "A5", "A6", "LETTER", "LEGAL"})
|
||||
void textToPageSize_validSizes_returnsCorrectRectangle(String size) {
|
||||
PDRectangle result = PdfUtils.textToPageSize(size);
|
||||
assertNotNull(result);
|
||||
assertTrue(result.getWidth() > 0);
|
||||
assertTrue(result.getHeight() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void textToPageSize_lowercaseA4_returnsA4() {
|
||||
PDRectangle result = PdfUtils.textToPageSize("a4");
|
||||
assertEquals(PDRectangle.A4.getWidth(), result.getWidth(), 0.01f);
|
||||
assertEquals(PDRectangle.A4.getHeight(), result.getHeight(), 0.01f);
|
||||
}
|
||||
|
||||
@Test
|
||||
void textToPageSize_invalidSize_throwsException() {
|
||||
assertThrows(Exception.class, () -> PdfUtils.textToPageSize("INVALID"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAllImages_emptyResources_returnsEmptyList() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDPage page = new PDPage();
|
||||
page.setResources(new PDResources());
|
||||
doc.addPage(page);
|
||||
List<RenderedImage> images = PdfUtils.getAllImages(page.getResources());
|
||||
assertTrue(images.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAllImages_withImage_returnsImage() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDPage page = new PDPage();
|
||||
doc.addPage(page);
|
||||
|
||||
BufferedImage bufferedImage = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB);
|
||||
PDImageXObject pdImage = LosslessFactory.createFromImage(doc, bufferedImage);
|
||||
|
||||
PDResources resources = new PDResources();
|
||||
resources.add(pdImage);
|
||||
page.setResources(resources);
|
||||
|
||||
List<RenderedImage> images = PdfUtils.getAllImages(page.getResources());
|
||||
assertEquals(1, images.size());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasImagesOnPage_noImages_returnsFalse() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDPage page = new PDPage();
|
||||
page.setResources(new PDResources());
|
||||
doc.addPage(page);
|
||||
assertFalse(PdfUtils.hasImagesOnPage(page));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasTextOnPage_noText_returnsFalse() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDPage page = new PDPage();
|
||||
doc.addPage(page);
|
||||
assertFalse(PdfUtils.hasTextOnPage(page, "hello"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void pageCount_greaterComparator_correct() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
doc.addPage(new PDPage());
|
||||
doc.addPage(new PDPage());
|
||||
doc.addPage(new PDPage());
|
||||
assertTrue(PdfUtils.pageCount(doc, 2, "greater"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void pageCount_equalComparator_correct() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
doc.addPage(new PDPage());
|
||||
doc.addPage(new PDPage());
|
||||
assertTrue(PdfUtils.pageCount(doc, 2, "equal"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void pageCount_lessComparator_correct() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
doc.addPage(new PDPage());
|
||||
assertTrue(PdfUtils.pageCount(doc, 5, "less"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void pageCount_invalidComparator_throwsException() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
doc.addPage(new PDPage());
|
||||
assertThrows(Exception.class, () -> PdfUtils.pageCount(doc, 1, "invalid"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void pageSize_matchingSize_returnsTrue() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDPage page = new PDPage(PDRectangle.A4);
|
||||
doc.addPage(page);
|
||||
String sizeStr = PDRectangle.A4.getWidth() + "x" + PDRectangle.A4.getHeight();
|
||||
assertTrue(PdfUtils.pageSize(doc, sizeStr));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void pageSize_nonMatchingSize_returnsFalse() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDPage page = new PDPage(PDRectangle.A4);
|
||||
doc.addPage(page);
|
||||
assertFalse(PdfUtils.pageSize(doc, "100x100"));
|
||||
}
|
||||
}
|
||||
|
||||
// --- hasImages ---
|
||||
|
||||
@Test
|
||||
void hasImages_noImages_returnsFalse() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDPage page = new PDPage();
|
||||
page.setResources(new PDResources());
|
||||
doc.addPage(page);
|
||||
assertFalse(PdfUtils.hasImages(doc, "all"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasImages_withImage_returnsTrue() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDPage page = new PDPage();
|
||||
doc.addPage(page);
|
||||
|
||||
BufferedImage bufferedImage = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB);
|
||||
PDImageXObject pdImage = LosslessFactory.createFromImage(doc, bufferedImage);
|
||||
PDResources resources = new PDResources();
|
||||
resources.add(pdImage);
|
||||
page.setResources(resources);
|
||||
|
||||
assertTrue(PdfUtils.hasImages(doc, "all"));
|
||||
}
|
||||
}
|
||||
|
||||
// --- hasText ---
|
||||
|
||||
@Test
|
||||
void hasText_noText_returnsFalse() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
doc.addPage(new PDPage());
|
||||
assertFalse(PdfUtils.hasText(doc, "all", "hello"));
|
||||
}
|
||||
}
|
||||
|
||||
// --- textToPageSize additional ---
|
||||
|
||||
@Test
|
||||
void textToPageSize_letter_returnsLetter() {
|
||||
PDRectangle result = PdfUtils.textToPageSize("letter");
|
||||
assertEquals(PDRectangle.LETTER.getWidth(), result.getWidth(), 0.01f);
|
||||
assertEquals(PDRectangle.LETTER.getHeight(), result.getHeight(), 0.01f);
|
||||
}
|
||||
|
||||
@Test
|
||||
void textToPageSize_legal_returnsLegal() {
|
||||
PDRectangle result = PdfUtils.textToPageSize("legal");
|
||||
assertEquals(PDRectangle.LEGAL.getWidth(), result.getWidth(), 0.01f);
|
||||
assertEquals(PDRectangle.LEGAL.getHeight(), result.getHeight(), 0.01f);
|
||||
}
|
||||
|
||||
// --- pageCount additional ---
|
||||
|
||||
@Test
|
||||
void pageCount_greaterComparator_false() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
doc.addPage(new PDPage());
|
||||
assertFalse(PdfUtils.pageCount(doc, 5, "greater"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void pageCount_equalComparator_false() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
doc.addPage(new PDPage());
|
||||
doc.addPage(new PDPage());
|
||||
assertFalse(PdfUtils.pageCount(doc, 3, "equal"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void pageCount_lessComparator_false() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
doc.addPage(new PDPage());
|
||||
doc.addPage(new PDPage());
|
||||
doc.addPage(new PDPage());
|
||||
assertFalse(PdfUtils.pageCount(doc, 2, "less"));
|
||||
}
|
||||
}
|
||||
|
||||
// --- hasImagesOnPage with image ---
|
||||
|
||||
@Test
|
||||
void hasImagesOnPage_withImage_returnsTrue() throws IOException {
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDPage page = new PDPage();
|
||||
doc.addPage(page);
|
||||
|
||||
BufferedImage bufferedImage = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB);
|
||||
PDImageXObject pdImage = LosslessFactory.createFromImage(doc, bufferedImage);
|
||||
PDResources resources = new PDResources();
|
||||
resources.add(pdImage);
|
||||
page.setResources(resources);
|
||||
|
||||
assertTrue(PdfUtils.hasImagesOnPage(page));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class ProcessExecutorTest {
|
||||
|
||||
// Use reflection to test private validateCommand method
|
||||
private void invokeValidateCommand(ProcessExecutor executor, List<String> command)
|
||||
throws Exception {
|
||||
Method method = ProcessExecutor.class.getDeclaredMethod("validateCommand", List.class);
|
||||
method.setAccessible(true);
|
||||
try {
|
||||
method.invoke(executor, command);
|
||||
} catch (java.lang.reflect.InvocationTargetException e) {
|
||||
throw (Exception) e.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
private ProcessExecutor getExecutor() {
|
||||
return ProcessExecutor.getInstance(ProcessExecutor.Processes.QPDF);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateCommand_nullCommand() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class, () -> invokeValidateCommand(getExecutor(), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateCommand_emptyCommand() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> invokeValidateCommand(getExecutor(), List.of()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateCommand_nullArgument() {
|
||||
List<String> command = new ArrayList<>();
|
||||
command.add("echo");
|
||||
command.add(null);
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> invokeValidateCommand(getExecutor(), command));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateCommand_nullByteInArgument() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> invokeValidateCommand(getExecutor(), List.of("echo", "bad\0arg")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateCommand_newlineInArgument() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> invokeValidateCommand(getExecutor(), List.of("echo", "bad\narg")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateCommand_carriageReturnInArgument() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> invokeValidateCommand(getExecutor(), List.of("echo", "bad\rarg")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateCommand_pathTraversal() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> invokeValidateCommand(getExecutor(), List.of("../../bin/evil")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateCommand_blankExecutable() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> invokeValidateCommand(getExecutor(), List.of(" ")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateCommand_validSimpleCommand() throws Exception {
|
||||
// Simple command names (no path) should pass validation
|
||||
invokeValidateCommand(getExecutor(), List.of("echo", "hello"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetInstance_returnsSameInstance() {
|
||||
ProcessExecutor e1 = ProcessExecutor.getInstance(ProcessExecutor.Processes.QPDF);
|
||||
ProcessExecutor e2 = ProcessExecutor.getInstance(ProcessExecutor.Processes.QPDF);
|
||||
assertSame(e1, e2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetInstance_differentProcessTypes() {
|
||||
ProcessExecutor e1 = ProcessExecutor.getInstance(ProcessExecutor.Processes.QPDF);
|
||||
ProcessExecutor e2 = ProcessExecutor.getInstance(ProcessExecutor.Processes.TESSERACT);
|
||||
assertNotSame(e1, e2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProcessExecutorResult() {
|
||||
ProcessExecutor executor = getExecutor();
|
||||
ProcessExecutor.ProcessExecutorResult result =
|
||||
executor.new ProcessExecutorResult(0, "success");
|
||||
assertEquals(0, result.getRc());
|
||||
assertEquals("success", result.getMessages());
|
||||
|
||||
result.setRc(1);
|
||||
result.setMessages("error");
|
||||
assertEquals(1, result.getRc());
|
||||
assertEquals("error", result.getMessages());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class PropertyConfigsTest {
|
||||
|
||||
private static final String TEST_KEY = "stirling.test.property.key";
|
||||
private static final String TEST_KEY_2 = "stirling.test.property.key2";
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
System.clearProperty(TEST_KEY);
|
||||
System.clearProperty(TEST_KEY_2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetBooleanValue_singleKey_fromSystemProperty() {
|
||||
System.setProperty(TEST_KEY, "true");
|
||||
assertTrue(PropertyConfigs.getBooleanValue(TEST_KEY, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetBooleanValue_singleKey_defaultWhenMissing() {
|
||||
assertFalse(PropertyConfigs.getBooleanValue(TEST_KEY, false));
|
||||
assertTrue(PropertyConfigs.getBooleanValue(TEST_KEY, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetBooleanValue_singleKey_falseValue() {
|
||||
System.setProperty(TEST_KEY, "false");
|
||||
assertFalse(PropertyConfigs.getBooleanValue(TEST_KEY, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetStringValue_singleKey_fromSystemProperty() {
|
||||
System.setProperty(TEST_KEY, "hello");
|
||||
assertEquals("hello", PropertyConfigs.getStringValue(TEST_KEY, "default"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetStringValue_singleKey_defaultWhenMissing() {
|
||||
assertEquals("default", PropertyConfigs.getStringValue(TEST_KEY, "default"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetBooleanValue_listKeys_firstMatch() {
|
||||
System.setProperty(TEST_KEY_2, "true");
|
||||
assertTrue(PropertyConfigs.getBooleanValue(List.of(TEST_KEY, TEST_KEY_2), false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetBooleanValue_listKeys_defaultWhenNoneMatch() {
|
||||
assertFalse(PropertyConfigs.getBooleanValue(List.of(TEST_KEY, TEST_KEY_2), false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetStringValue_listKeys_firstMatch() {
|
||||
System.setProperty(TEST_KEY, "first");
|
||||
System.setProperty(TEST_KEY_2, "second");
|
||||
assertEquals(
|
||||
"first", PropertyConfigs.getStringValue(List.of(TEST_KEY, TEST_KEY_2), "default"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetStringValue_listKeys_defaultWhenNoneMatch() {
|
||||
assertEquals(
|
||||
"default",
|
||||
PropertyConfigs.getStringValue(List.of(TEST_KEY, TEST_KEY_2), "default"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetBooleanValue_nonBooleanString() {
|
||||
System.setProperty(TEST_KEY, "notaboolean");
|
||||
// Boolean.valueOf returns false for non-boolean strings
|
||||
assertFalse(PropertyConfigs.getBooleanValue(TEST_KEY, true));
|
||||
}
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import stirling.software.common.model.oauth2.Provider;
|
||||
|
||||
class ProviderUtilsAdditionalTest {
|
||||
|
||||
@Test
|
||||
void testValidateProvider_null() {
|
||||
assertFalse(ProviderUtils.validateProvider(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateProvider_nullClientId() {
|
||||
Provider provider = new Provider();
|
||||
provider.setClientId(null);
|
||||
provider.setClientSecret("secret");
|
||||
provider.setScopes("read");
|
||||
assertFalse(ProviderUtils.validateProvider(provider));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateProvider_emptyClientId() {
|
||||
Provider provider = new Provider();
|
||||
provider.setClientId("");
|
||||
provider.setClientSecret("secret");
|
||||
provider.setScopes("read");
|
||||
assertFalse(ProviderUtils.validateProvider(provider));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateProvider_blankClientId() {
|
||||
Provider provider = new Provider();
|
||||
provider.setClientId(" ");
|
||||
provider.setClientSecret("secret");
|
||||
provider.setScopes("read");
|
||||
assertFalse(ProviderUtils.validateProvider(provider));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateProvider_nullClientSecret() {
|
||||
Provider provider = new Provider();
|
||||
provider.setClientId("id");
|
||||
provider.setClientSecret(null);
|
||||
provider.setScopes("read");
|
||||
assertFalse(ProviderUtils.validateProvider(provider));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateProvider_emptyClientSecret() {
|
||||
Provider provider = new Provider();
|
||||
provider.setClientId("id");
|
||||
provider.setClientSecret("");
|
||||
provider.setScopes("read");
|
||||
assertFalse(ProviderUtils.validateProvider(provider));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateProvider_nullScopes() {
|
||||
Provider provider = new Provider();
|
||||
provider.setClientId("id");
|
||||
provider.setClientSecret("secret");
|
||||
provider.setScopes(null);
|
||||
assertFalse(ProviderUtils.validateProvider(provider));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateProvider_emptyScopes() {
|
||||
Provider provider = new Provider();
|
||||
provider.setClientId("id");
|
||||
provider.setClientSecret("secret");
|
||||
provider.setScopes("");
|
||||
assertFalse(ProviderUtils.validateProvider(provider));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateProvider_allFieldsValid() {
|
||||
Provider provider = new Provider();
|
||||
provider.setClientId("my-client-id");
|
||||
provider.setClientSecret("my-secret");
|
||||
provider.setScopes("openid,profile");
|
||||
assertTrue(ProviderUtils.validateProvider(provider));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateProvider_singleScope() {
|
||||
Provider provider = new Provider();
|
||||
provider.setClientId("id");
|
||||
provider.setClientSecret("secret");
|
||||
provider.setScopes("email");
|
||||
assertTrue(ProviderUtils.validateProvider(provider));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class RequestUriUtilsTest {
|
||||
|
||||
// --- isStaticResource tests ---
|
||||
|
||||
@Test
|
||||
void testIsStaticResource_nullUri() {
|
||||
assertFalse(RequestUriUtils.isStaticResource(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsStaticResource_cssDirectory() {
|
||||
assertTrue(RequestUriUtils.isStaticResource("/css/style.css"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsStaticResource_jsDirectory() {
|
||||
assertTrue(RequestUriUtils.isStaticResource("/js/app.js"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsStaticResource_imagesDirectory() {
|
||||
assertTrue(RequestUriUtils.isStaticResource("/images/logo.png"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsStaticResource_robotsTxt() {
|
||||
assertTrue(RequestUriUtils.isStaticResource("/robots.txt"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsStaticResource_faviconIco() {
|
||||
assertTrue(RequestUriUtils.isStaticResource("/favicon.ico"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsStaticResource_loginPath() {
|
||||
assertTrue(RequestUriUtils.isStaticResource("/login"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsStaticResource_errorPath() {
|
||||
assertTrue(RequestUriUtils.isStaticResource("/error"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsStaticResource_svgExtension() {
|
||||
assertTrue(RequestUriUtils.isStaticResource("/some/path/icon.svg"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsStaticResource_apiRoute_notStatic() {
|
||||
assertFalse(RequestUriUtils.isStaticResource("/api/v1/convert"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsStaticResource_apiStatusEndpoint() {
|
||||
assertTrue(RequestUriUtils.isStaticResource("/api/v1/info/status"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsStaticResource_withContextPath() {
|
||||
assertTrue(RequestUriUtils.isStaticResource("/app", "/app/css/style.css"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsStaticResource_mobileScannerPath() {
|
||||
assertTrue(RequestUriUtils.isStaticResource("/mobile-scanner"));
|
||||
}
|
||||
|
||||
// --- isFrontendRoute tests ---
|
||||
|
||||
@Test
|
||||
void testIsFrontendRoute_nullUri() {
|
||||
assertFalse(RequestUriUtils.isFrontendRoute("", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsFrontendRoute_apiPath() {
|
||||
assertFalse(RequestUriUtils.isFrontendRoute("", "/api/v1/convert"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsFrontendRoute_backendOnlyPath() {
|
||||
assertFalse(RequestUriUtils.isFrontendRoute("", "/swagger"));
|
||||
assertFalse(RequestUriUtils.isFrontendRoute("", "/register"));
|
||||
assertFalse(RequestUriUtils.isFrontendRoute("", "/actuator"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsFrontendRoute_extensionlessPath() {
|
||||
assertTrue(RequestUriUtils.isFrontendRoute("", "/merge"));
|
||||
assertTrue(RequestUriUtils.isFrontendRoute("", "/split-pdf"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsFrontendRoute_pathWithExtension() {
|
||||
assertFalse(RequestUriUtils.isFrontendRoute("", "/some/file.pdf"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsFrontendRoute_blankPath() {
|
||||
assertFalse(RequestUriUtils.isFrontendRoute("", ""));
|
||||
}
|
||||
|
||||
// --- isTrackableResource tests ---
|
||||
|
||||
@Test
|
||||
void testIsTrackableResource_jsPath() {
|
||||
assertFalse(RequestUriUtils.isTrackableResource("/js/app.js"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsTrackableResource_cssFile() {
|
||||
assertFalse(RequestUriUtils.isTrackableResource("/some/file.css"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsTrackableResource_apiPage() {
|
||||
assertTrue(RequestUriUtils.isTrackableResource("/api/v1/convert"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsTrackableResource_swaggerPath() {
|
||||
assertFalse(RequestUriUtils.isTrackableResource("/swagger-ui/index.html"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsTrackableResource_infoApi() {
|
||||
assertFalse(RequestUriUtils.isTrackableResource("/api/v1/info/status"));
|
||||
}
|
||||
|
||||
// --- isPublicAuthEndpoint tests ---
|
||||
|
||||
@Test
|
||||
void testIsPublicAuthEndpoint_loginPath() {
|
||||
assertTrue(RequestUriUtils.isPublicAuthEndpoint("/login", ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsPublicAuthEndpoint_oauthPath() {
|
||||
assertTrue(RequestUriUtils.isPublicAuthEndpoint("/oauth2/authorization/google", ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsPublicAuthEndpoint_healthEndpoint() {
|
||||
assertTrue(RequestUriUtils.isPublicAuthEndpoint("/actuator/health", ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsPublicAuthEndpoint_regularApiNotPublic() {
|
||||
assertFalse(RequestUriUtils.isPublicAuthEndpoint("/api/v1/convert", ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsPublicAuthEndpoint_withContextPath() {
|
||||
assertTrue(RequestUriUtils.isPublicAuthEndpoint("/app/login", "/app"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import stirling.software.common.model.ApplicationProperties;
|
||||
import stirling.software.common.service.SsrfProtectionService;
|
||||
|
||||
class SvgSanitizerTest {
|
||||
|
||||
private SvgSanitizer sanitizer;
|
||||
private ApplicationProperties applicationProperties;
|
||||
private SsrfProtectionService ssrfProtectionService;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
applicationProperties = new ApplicationProperties();
|
||||
ssrfProtectionService = mock(SsrfProtectionService.class);
|
||||
sanitizer = new SvgSanitizer(ssrfProtectionService, applicationProperties);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitize_validSvg() throws IOException {
|
||||
String svg = "<svg xmlns=\"http://www.w3.org/2000/svg\"><circle r=\"10\"/></svg>";
|
||||
byte[] result = sanitizer.sanitize(svg.getBytes(StandardCharsets.UTF_8));
|
||||
assertNotNull(result);
|
||||
assertTrue(result.length > 0);
|
||||
String output = new String(result, StandardCharsets.UTF_8);
|
||||
assertTrue(output.contains("circle"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitize_removesScriptElement() throws IOException {
|
||||
String svg =
|
||||
"<svg xmlns=\"http://www.w3.org/2000/svg\"><script>alert('xss')</script><circle r=\"10\"/></svg>";
|
||||
byte[] result = sanitizer.sanitize(svg.getBytes(StandardCharsets.UTF_8));
|
||||
String output = new String(result, StandardCharsets.UTF_8);
|
||||
assertFalse(output.contains("script"));
|
||||
assertTrue(output.contains("circle"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitize_removesEventHandler() throws IOException {
|
||||
String svg =
|
||||
"<svg xmlns=\"http://www.w3.org/2000/svg\"><circle r=\"10\" onclick=\"alert('xss')\"/></svg>";
|
||||
byte[] result = sanitizer.sanitize(svg.getBytes(StandardCharsets.UTF_8));
|
||||
String output = new String(result, StandardCharsets.UTF_8);
|
||||
assertFalse(output.contains("onclick"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitize_removesJavascriptUrl() throws IOException {
|
||||
String svg =
|
||||
"<svg xmlns=\"http://www.w3.org/2000/svg\"><a href=\"javascript:alert('xss')\"><circle r=\"10\"/></a></svg>";
|
||||
byte[] result = sanitizer.sanitize(svg.getBytes(StandardCharsets.UTF_8));
|
||||
String output = new String(result, StandardCharsets.UTF_8);
|
||||
assertFalse(output.contains("javascript"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitize_nullInput() {
|
||||
assertThrows(IOException.class, () -> sanitizer.sanitize(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitize_emptyInput() {
|
||||
assertThrows(IOException.class, () -> sanitizer.sanitize(new byte[0]));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitize_disabledByConfig() throws IOException {
|
||||
applicationProperties.getSystem().setDisableSanitize(true);
|
||||
byte[] input =
|
||||
"<svg xmlns=\"http://www.w3.org/2000/svg\"><script>evil</script></svg>"
|
||||
.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] result = sanitizer.sanitize(input);
|
||||
assertArrayEquals(input, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitize_removesForeignObject() throws IOException {
|
||||
String svg =
|
||||
"<svg xmlns=\"http://www.w3.org/2000/svg\"><foreignObject><body>evil</body></foreignObject><rect width=\"10\" height=\"10\"/></svg>";
|
||||
byte[] result = sanitizer.sanitize(svg.getBytes(StandardCharsets.UTF_8));
|
||||
String output = new String(result, StandardCharsets.UTF_8);
|
||||
assertFalse(output.toLowerCase().contains("foreignobject"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSanitize_invalidXml() {
|
||||
byte[] invalid = "not xml at all".getBytes(StandardCharsets.UTF_8);
|
||||
assertThrows(IOException.class, () -> sanitizer.sanitize(invalid));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import stirling.software.common.model.ApplicationProperties;
|
||||
|
||||
class TempFileManagerTest {
|
||||
|
||||
private TempFileManager manager;
|
||||
private TempFileRegistry registry;
|
||||
private ApplicationProperties applicationProperties;
|
||||
|
||||
@TempDir Path tempDir;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
registry = new TempFileRegistry();
|
||||
applicationProperties = new ApplicationProperties();
|
||||
applicationProperties.getSystem().getTempFileManagement().setBaseTmpDir(tempDir.toString());
|
||||
applicationProperties.getSystem().getTempFileManagement().setPrefix("test-stirling-");
|
||||
manager = new TempFileManager(registry, applicationProperties);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateTempFile() throws IOException {
|
||||
File file = manager.createTempFile(".pdf");
|
||||
assertNotNull(file);
|
||||
assertTrue(file.exists());
|
||||
assertTrue(file.getName().endsWith(".pdf"));
|
||||
assertTrue(registry.contains(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateManagedTempFile() throws IOException {
|
||||
TempFile tempFile = manager.createManagedTempFile(".txt");
|
||||
assertNotNull(tempFile);
|
||||
assertTrue(tempFile.exists());
|
||||
assertTrue(tempFile.getFile().getName().endsWith(".txt"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateTempDirectory() throws IOException {
|
||||
Path dir = manager.createTempDirectory();
|
||||
assertNotNull(dir);
|
||||
assertTrue(Files.isDirectory(dir));
|
||||
assertTrue(registry.getTempDirectories().contains(dir));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteTempFile_file() throws IOException {
|
||||
File file = manager.createTempFile(".tmp");
|
||||
assertTrue(file.exists());
|
||||
|
||||
boolean deleted = manager.deleteTempFile(file);
|
||||
assertTrue(deleted);
|
||||
assertFalse(file.exists());
|
||||
assertFalse(registry.contains(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteTempFile_path() throws IOException {
|
||||
File file = manager.createTempFile(".tmp");
|
||||
Path path = file.toPath();
|
||||
assertTrue(Files.exists(path));
|
||||
|
||||
boolean deleted = manager.deleteTempFile(path);
|
||||
assertTrue(deleted);
|
||||
assertFalse(Files.exists(path));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteTempFile_nullFile() {
|
||||
assertFalse(manager.deleteTempFile((File) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteTempFile_nullPath() {
|
||||
assertFalse(manager.deleteTempFile((Path) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteTempFile_nonExistentFile() {
|
||||
File nonExistent = new File(tempDir.toFile(), "does-not-exist.tmp");
|
||||
assertFalse(manager.deleteTempFile(nonExistent));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRegister() throws IOException {
|
||||
File file = Files.createTempFile(tempDir, "existing", ".tmp").toFile();
|
||||
File result = manager.register(file);
|
||||
assertSame(file, result);
|
||||
assertTrue(registry.contains(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRegister_nullFile() {
|
||||
File result = manager.register(null);
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGenerateTempFileName() {
|
||||
String name = manager.generateTempFileName("convert", "pdf");
|
||||
assertNotNull(name);
|
||||
assertTrue(name.startsWith("test-stirling-"));
|
||||
assertTrue(name.contains("convert"));
|
||||
assertTrue(name.endsWith(".pdf"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetMaxAgeMillis() {
|
||||
applicationProperties.getSystem().getTempFileManagement().setMaxAgeHours(2);
|
||||
long millis = manager.getMaxAgeMillis();
|
||||
assertEquals(2 * 60 * 60 * 1000L, millis);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCleanupOldTempFiles() throws IOException, InterruptedException {
|
||||
File file = manager.createTempFile(".tmp");
|
||||
assertTrue(file.exists());
|
||||
|
||||
Thread.sleep(50);
|
||||
int deleted = manager.cleanupOldTempFiles(10);
|
||||
assertTrue(deleted >= 1);
|
||||
assertFalse(file.exists());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
class TempFileRegistryTest {
|
||||
|
||||
private TempFileRegistry registry;
|
||||
|
||||
@TempDir Path tempDir;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
registry = new TempFileRegistry();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRegisterFile() throws IOException {
|
||||
File file = Files.createTempFile(tempDir, "test", ".tmp").toFile();
|
||||
File result = registry.register(file);
|
||||
assertSame(file, result);
|
||||
assertTrue(registry.contains(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRegisterNull() {
|
||||
registry.register((File) null);
|
||||
assertEquals(0, registry.getAllRegisteredFiles().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRegisterPath() throws IOException {
|
||||
Path path = Files.createTempFile(tempDir, "test", ".tmp");
|
||||
Path result = registry.register(path);
|
||||
assertSame(path, result);
|
||||
assertTrue(registry.getAllRegisteredFiles().contains(path));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnregisterFile() throws IOException {
|
||||
File file = Files.createTempFile(tempDir, "test", ".tmp").toFile();
|
||||
registry.register(file);
|
||||
assertTrue(registry.contains(file));
|
||||
|
||||
registry.unregister(file);
|
||||
assertFalse(registry.contains(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnregisterPath() throws IOException {
|
||||
Path path = Files.createTempFile(tempDir, "test", ".tmp");
|
||||
registry.register(path);
|
||||
registry.unregister(path);
|
||||
assertFalse(registry.getAllRegisteredFiles().contains(path));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnregisterNull() {
|
||||
// Should not throw
|
||||
registry.unregister((File) null);
|
||||
registry.unregister((Path) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRegisterDirectory() throws IOException {
|
||||
Path dir = Files.createTempDirectory(tempDir, "testdir");
|
||||
Path result = registry.registerDirectory(dir);
|
||||
assertSame(dir, result);
|
||||
assertTrue(registry.getTempDirectories().contains(dir));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRegisterThirdParty() throws IOException {
|
||||
File file = Files.createTempFile(tempDir, "third", ".tmp").toFile();
|
||||
File result = registry.registerThirdParty(file);
|
||||
assertSame(file, result);
|
||||
assertTrue(registry.getThirdPartyTempFiles().contains(file.toPath()));
|
||||
assertTrue(registry.contains(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testContainsNull() {
|
||||
assertFalse(registry.contains(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetFilesOlderThan() throws IOException, InterruptedException {
|
||||
Path path = Files.createTempFile(tempDir, "old", ".tmp");
|
||||
registry.register(path);
|
||||
|
||||
// Files registered just now should not be "older than 0ms" since
|
||||
// getFilesOlderThan uses isBefore(cutoff), meaning strictly before
|
||||
Thread.sleep(50);
|
||||
Set<Path> oldFiles = registry.getFilesOlderThan(10);
|
||||
assertTrue(oldFiles.contains(path));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetFilesOlderThan_recentFiles() throws IOException {
|
||||
Path path = Files.createTempFile(tempDir, "recent", ".tmp");
|
||||
registry.register(path);
|
||||
|
||||
// With a very large maxAge, no files should be "old"
|
||||
Set<Path> oldFiles = registry.getFilesOlderThan(999_999_999);
|
||||
assertFalse(oldFiles.contains(path));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testClear() throws IOException {
|
||||
File file = Files.createTempFile(tempDir, "clear", ".tmp").toFile();
|
||||
Path dir = Files.createTempDirectory(tempDir, "cleardir");
|
||||
registry.register(file);
|
||||
registry.registerThirdParty(file);
|
||||
registry.registerDirectory(dir);
|
||||
|
||||
registry.clear();
|
||||
|
||||
assertEquals(0, registry.getAllRegisteredFiles().size());
|
||||
assertEquals(0, registry.getThirdPartyTempFiles().size());
|
||||
assertEquals(0, registry.getTempDirectories().size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import stirling.software.common.model.ApplicationProperties;
|
||||
|
||||
class TempFileTest {
|
||||
|
||||
private TempFileManager manager;
|
||||
|
||||
@TempDir Path tempDir;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
TempFileRegistry registry = new TempFileRegistry();
|
||||
ApplicationProperties props = new ApplicationProperties();
|
||||
props.getSystem().getTempFileManagement().setBaseTmpDir(tempDir.toString());
|
||||
props.getSystem().getTempFileManagement().setPrefix("test-");
|
||||
manager = new TempFileManager(registry, props);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTempFileCreation() throws IOException {
|
||||
TempFile tempFile = new TempFile(manager, ".pdf");
|
||||
assertNotNull(tempFile.getFile());
|
||||
assertTrue(tempFile.exists());
|
||||
assertTrue(tempFile.getFile().getName().endsWith(".pdf"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPath() throws IOException {
|
||||
TempFile tempFile = new TempFile(manager, ".txt");
|
||||
Path path = tempFile.getPath();
|
||||
assertNotNull(path);
|
||||
assertEquals(tempFile.getFile().toPath(), path);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAbsolutePath() throws IOException {
|
||||
TempFile tempFile = new TempFile(manager, ".tmp");
|
||||
String absPath = tempFile.getAbsolutePath();
|
||||
assertNotNull(absPath);
|
||||
assertEquals(tempFile.getFile().getAbsolutePath(), absPath);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testClose_deletesFile() throws IOException {
|
||||
TempFile tempFile = new TempFile(manager, ".tmp");
|
||||
assertTrue(tempFile.exists());
|
||||
|
||||
tempFile.close();
|
||||
assertFalse(tempFile.exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTryWithResources() throws IOException {
|
||||
TempFile tempFileRef;
|
||||
try (TempFile tempFile = new TempFile(manager, ".tmp")) {
|
||||
tempFileRef = tempFile;
|
||||
assertTrue(tempFile.exists());
|
||||
}
|
||||
assertFalse(tempFileRef.exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testToString() throws IOException {
|
||||
TempFile tempFile = new TempFile(manager, ".tmp");
|
||||
String str = tempFile.toString();
|
||||
assertTrue(str.startsWith("TempFile{"));
|
||||
assertTrue(str.endsWith("}"));
|
||||
assertTrue(str.contains(tempFile.getFile().getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import stirling.software.common.model.ApplicationProperties;
|
||||
|
||||
class TempFileUtilTest {
|
||||
|
||||
private TempFileManager manager;
|
||||
|
||||
@TempDir Path tempDir;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
TempFileRegistry registry = new TempFileRegistry();
|
||||
ApplicationProperties props = new ApplicationProperties();
|
||||
props.getSystem().getTempFileManagement().setBaseTmpDir(tempDir.toString());
|
||||
props.getSystem().getTempFileManagement().setPrefix("test-");
|
||||
manager = new TempFileManager(registry, props);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWithTempFile_executesAndCleansUp() throws IOException {
|
||||
final File[] fileRef = new File[1];
|
||||
String result =
|
||||
TempFileUtil.withTempFile(
|
||||
manager,
|
||||
".tmp",
|
||||
file -> {
|
||||
fileRef[0] = file;
|
||||
assertTrue(file.exists());
|
||||
return "done";
|
||||
});
|
||||
assertEquals("done", result);
|
||||
assertFalse(fileRef[0].exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWithMultipleTempFiles() throws IOException {
|
||||
final List<File>[] filesRef = new List[1];
|
||||
String result =
|
||||
TempFileUtil.withMultipleTempFiles(
|
||||
manager,
|
||||
3,
|
||||
".tmp",
|
||||
files -> {
|
||||
filesRef[0] = files;
|
||||
assertEquals(3, files.size());
|
||||
for (File f : files) {
|
||||
assertTrue(f.exists());
|
||||
}
|
||||
return "ok";
|
||||
});
|
||||
assertEquals("ok", result);
|
||||
for (File f : filesRef[0]) {
|
||||
assertFalse(f.exists());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSafeDeleteFiles() throws IOException {
|
||||
Path file1 = Files.createTempFile(tempDir, "safe", ".tmp");
|
||||
Path file2 = Files.createTempFile(tempDir, "safe", ".tmp");
|
||||
assertTrue(Files.exists(file1));
|
||||
assertTrue(Files.exists(file2));
|
||||
|
||||
TempFileUtil.safeDeleteFiles(Arrays.asList(file1, file2));
|
||||
assertFalse(Files.exists(file1));
|
||||
assertFalse(Files.exists(file2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSafeDeleteFiles_nullList() {
|
||||
// Should not throw
|
||||
TempFileUtil.safeDeleteFiles(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSafeDeleteFiles_nullElement() throws IOException {
|
||||
Path file = Files.createTempFile(tempDir, "safe", ".tmp");
|
||||
// Should handle null elements gracefully
|
||||
TempFileUtil.safeDeleteFiles(Arrays.asList(null, file));
|
||||
assertFalse(Files.exists(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRegisterExistingTempFile() throws IOException {
|
||||
File file = Files.createTempFile(tempDir, "existing", ".tmp").toFile();
|
||||
File result = TempFileUtil.registerExistingTempFile(manager, file);
|
||||
assertSame(file, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRegisterExistingTempFile_nullManager() throws IOException {
|
||||
File file = Files.createTempFile(tempDir, "existing", ".tmp").toFile();
|
||||
File result = TempFileUtil.registerExistingTempFile(null, file);
|
||||
assertSame(file, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRegisterExistingTempFile_nullFile() {
|
||||
File result = TempFileUtil.registerExistingTempFile(manager, null);
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTempFileCollection() throws IOException {
|
||||
TempFileUtil.TempFileCollection collection = new TempFileUtil.TempFileCollection(manager);
|
||||
File f1 = collection.addTempFile(".tmp");
|
||||
File f2 = collection.addTempFile(".pdf");
|
||||
|
||||
assertTrue(f1.exists());
|
||||
assertTrue(f2.exists());
|
||||
assertEquals(2, collection.getFiles().size());
|
||||
|
||||
collection.close();
|
||||
assertFalse(f1.exists());
|
||||
assertFalse(f2.exists());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
class UrlUtilsTest {
|
||||
|
||||
@Test
|
||||
void testGetOrigin_standardRequest() {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getScheme()).thenReturn("http");
|
||||
when(request.getServerName()).thenReturn("localhost");
|
||||
when(request.getServerPort()).thenReturn(8080);
|
||||
when(request.getContextPath()).thenReturn("");
|
||||
|
||||
assertEquals("http://localhost:8080", UrlUtils.getOrigin(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetOrigin_httpsWithContextPath() {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getScheme()).thenReturn("https");
|
||||
when(request.getServerName()).thenReturn("example.com");
|
||||
when(request.getServerPort()).thenReturn(443);
|
||||
when(request.getContextPath()).thenReturn("/myapp");
|
||||
|
||||
assertEquals("https://example.com:443/myapp", UrlUtils.getOrigin(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsPortAvailable_usedPort() {
|
||||
// Port 0 is special - let the OS pick a port, but commonly used ports should be busy
|
||||
// We test with a high port that might be available
|
||||
// This is inherently environment-dependent
|
||||
boolean result = UrlUtils.isPortAvailable(0);
|
||||
// Port 0 should always be available as the OS assigns an ephemeral port
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindAvailablePort_returnsPort() {
|
||||
// Starting from port 0 should immediately find an available port
|
||||
String port = UrlUtils.findAvailablePort(0);
|
||||
assertNotNull(port);
|
||||
int portNum = Integer.parseInt(port);
|
||||
assertTrue(portNum >= 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetOrigin_customPort() {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getScheme()).thenReturn("http");
|
||||
when(request.getServerName()).thenReturn("192.168.1.1");
|
||||
when(request.getServerPort()).thenReturn(9090);
|
||||
when(request.getContextPath()).thenReturn("/api");
|
||||
|
||||
assertEquals("http://192.168.1.1:9090/api", UrlUtils.getOrigin(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetOrigin_defaultPort80() {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getScheme()).thenReturn("http");
|
||||
when(request.getServerName()).thenReturn("example.com");
|
||||
when(request.getServerPort()).thenReturn(80);
|
||||
when(request.getContextPath()).thenReturn("");
|
||||
|
||||
assertEquals("http://example.com:80", UrlUtils.getOrigin(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetOrigin_emptyContextPath() {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getScheme()).thenReturn("https");
|
||||
when(request.getServerName()).thenReturn("app.example.com");
|
||||
when(request.getServerPort()).thenReturn(443);
|
||||
when(request.getContextPath()).thenReturn("");
|
||||
|
||||
assertEquals("https://app.example.com:443", UrlUtils.getOrigin(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetOrigin_nestedContextPath() {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getScheme()).thenReturn("http");
|
||||
when(request.getServerName()).thenReturn("host");
|
||||
when(request.getServerPort()).thenReturn(3000);
|
||||
when(request.getContextPath()).thenReturn("/a/b/c");
|
||||
|
||||
assertEquals("http://host:3000/a/b/c", UrlUtils.getOrigin(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindAvailablePort_returnsStringOfPort() {
|
||||
String port = UrlUtils.findAvailablePort(49152);
|
||||
assertNotNull(port);
|
||||
int portNum = Integer.parseInt(port);
|
||||
assertTrue(portNum >= 49152);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsPortAvailable_highPort() {
|
||||
// Most high ephemeral ports should be available in test environments
|
||||
// Using port 0 which OS always considers available
|
||||
assertTrue(UrlUtils.isPortAvailable(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetOrigin_ipv4Address() {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getScheme()).thenReturn("http");
|
||||
when(request.getServerName()).thenReturn("10.0.0.1");
|
||||
when(request.getServerPort()).thenReturn(8443);
|
||||
when(request.getContextPath()).thenReturn("");
|
||||
|
||||
assertEquals("http://10.0.0.1:8443", UrlUtils.getOrigin(request));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class ValidationUtilsTest {
|
||||
|
||||
@Test
|
||||
void testIsStringEmpty_null() {
|
||||
assertTrue(ValidationUtils.isStringEmpty(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsStringEmpty_emptyString() {
|
||||
assertTrue(ValidationUtils.isStringEmpty(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsStringEmpty_blankString() {
|
||||
assertTrue(ValidationUtils.isStringEmpty(" "));
|
||||
assertTrue(ValidationUtils.isStringEmpty("\t\n"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsStringEmpty_nonEmptyString() {
|
||||
assertFalse(ValidationUtils.isStringEmpty("hello"));
|
||||
assertFalse(ValidationUtils.isStringEmpty(" a "));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsCollectionEmpty_null() {
|
||||
assertTrue(ValidationUtils.isCollectionEmpty(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsCollectionEmpty_emptyCollection() {
|
||||
assertTrue(ValidationUtils.isCollectionEmpty(Collections.emptyList()));
|
||||
assertTrue(ValidationUtils.isCollectionEmpty(new ArrayList<>()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsCollectionEmpty_nonEmptyCollection() {
|
||||
assertFalse(ValidationUtils.isCollectionEmpty(List.of("a")));
|
||||
assertFalse(ValidationUtils.isCollectionEmpty(List.of("a", "b", "c")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
class WebResponseUtilsTest {
|
||||
|
||||
@Test
|
||||
void testBytesToWebResponse_defaultMediaType() throws IOException {
|
||||
byte[] data = "test content".getBytes(StandardCharsets.UTF_8);
|
||||
ResponseEntity<byte[]> response = WebResponseUtils.bytesToWebResponse(data, "output.pdf");
|
||||
|
||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
assertEquals(MediaType.APPLICATION_PDF, response.getHeaders().getContentType());
|
||||
assertEquals(data.length, response.getHeaders().getContentLength());
|
||||
assertArrayEquals(data, response.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBytesToWebResponse_customMediaType() throws IOException {
|
||||
byte[] data = "zip data".getBytes(StandardCharsets.UTF_8);
|
||||
ResponseEntity<byte[]> response =
|
||||
WebResponseUtils.bytesToWebResponse(
|
||||
data, "output.zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||
|
||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
assertEquals(MediaType.APPLICATION_OCTET_STREAM, response.getHeaders().getContentType());
|
||||
assertArrayEquals(data, response.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBaosToWebResponse() throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
baos.write("baos content".getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
ResponseEntity<byte[]> response = WebResponseUtils.baosToWebResponse(baos, "doc.pdf");
|
||||
|
||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
assertNotNull(response.getBody());
|
||||
assertEquals("baos content", new String(response.getBody(), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBaosToWebResponse_withMediaType() throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
baos.write("data".getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
ResponseEntity<byte[]> response =
|
||||
WebResponseUtils.baosToWebResponse(baos, "doc.html", MediaType.TEXT_HTML);
|
||||
|
||||
assertEquals(MediaType.TEXT_HTML, response.getHeaders().getContentType());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBytesToWebResponse_contentDispositionHeader() throws IOException {
|
||||
byte[] data = "test".getBytes(StandardCharsets.UTF_8);
|
||||
ResponseEntity<byte[]> response = WebResponseUtils.bytesToWebResponse(data, "my file.pdf");
|
||||
|
||||
String contentDisposition = response.getHeaders().getFirst(HttpHeaders.CONTENT_DISPOSITION);
|
||||
assertNotNull(contentDisposition);
|
||||
assertTrue(contentDisposition.contains("attachment"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBytesToWebResponse_specialCharsInFilename() throws IOException {
|
||||
byte[] data = "test".getBytes(StandardCharsets.UTF_8);
|
||||
// A space in the filename gets URL-encoded to '+' then replaced with '%20'
|
||||
ResponseEntity<byte[]> response =
|
||||
WebResponseUtils.bytesToWebResponse(data, "file name.pdf");
|
||||
|
||||
String contentDisposition = response.getHeaders().getFirst(HttpHeaders.CONTENT_DISPOSITION);
|
||||
assertNotNull(contentDisposition);
|
||||
// The space in filename should be encoded as %20 (not +)
|
||||
assertTrue(contentDisposition.contains("%20"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBytesToWebResponse_emptyBytes() throws IOException {
|
||||
byte[] data = new byte[0];
|
||||
ResponseEntity<byte[]> response = WebResponseUtils.bytesToWebResponse(data, "empty.pdf");
|
||||
|
||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
assertEquals(0, response.getHeaders().getContentLength());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package stirling.software.common.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.snakeyaml.engine.v2.api.LoadSettings;
|
||||
|
||||
class YamlHelperTest {
|
||||
|
||||
private static final String SIMPLE_YAML =
|
||||
"server:\n port: 8080\n host: localhost\napp:\n name: test\n debug: true\n";
|
||||
|
||||
private static final LoadSettings LOAD_SETTINGS =
|
||||
LoadSettings.builder()
|
||||
.setUseMarks(true)
|
||||
.setMaxAliasesForCollections(Integer.MAX_VALUE)
|
||||
.setAllowRecursiveKeys(true)
|
||||
.setParseComments(true)
|
||||
.build();
|
||||
|
||||
private YamlHelper createHelper(String yaml) {
|
||||
return new YamlHelper(LOAD_SETTINGS, yaml);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetValueByExactKeyPath_scalarValue() {
|
||||
YamlHelper helper = createHelper(SIMPLE_YAML);
|
||||
Object value = helper.getValueByExactKeyPath("server", "port");
|
||||
assertEquals("8080", value);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetValueByExactKeyPath_stringValue() {
|
||||
YamlHelper helper = new YamlHelper(LOAD_SETTINGS, SIMPLE_YAML);
|
||||
Object value = helper.getValueByExactKeyPath("server", "host");
|
||||
assertEquals("localhost", value);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetValueByExactKeyPath_nonExistentKey() {
|
||||
YamlHelper helper = new YamlHelper(LOAD_SETTINGS, SIMPLE_YAML);
|
||||
Object value = helper.getValueByExactKeyPath("nonexistent", "key");
|
||||
assertNull(value);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAllKeys() {
|
||||
YamlHelper helper = new YamlHelper(LOAD_SETTINGS, SIMPLE_YAML);
|
||||
Set<String> keys = helper.getAllKeys();
|
||||
assertTrue(keys.contains("server"));
|
||||
assertTrue(keys.contains("server.port"));
|
||||
assertTrue(keys.contains("server.host"));
|
||||
assertTrue(keys.contains("app"));
|
||||
assertTrue(keys.contains("app.name"));
|
||||
assertTrue(keys.contains("app.debug"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdateValue() {
|
||||
YamlHelper helper = new YamlHelper(LOAD_SETTINGS, SIMPLE_YAML);
|
||||
boolean updated = helper.updateValue(Arrays.asList("server", "port"), "9090");
|
||||
assertTrue(updated);
|
||||
Object newValue = helper.getValueByExactKeyPath("server", "port");
|
||||
assertEquals("9090", newValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdateValue_nonExistentKey() {
|
||||
YamlHelper helper = new YamlHelper(LOAD_SETTINGS, SIMPLE_YAML);
|
||||
boolean updated = helper.updateValue(Arrays.asList("nonexistent", "key"), "value");
|
||||
assertFalse(updated);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConvertNodeToYaml() {
|
||||
YamlHelper helper = new YamlHelper(LOAD_SETTINGS, SIMPLE_YAML);
|
||||
String yaml = helper.convertNodeToYaml(helper.getUpdatedRootNode());
|
||||
assertNotNull(yaml);
|
||||
assertTrue(yaml.contains("server"));
|
||||
assertTrue(yaml.contains("port"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructorFromFile(@TempDir Path tempDir) throws IOException {
|
||||
Path yamlFile = tempDir.resolve("test.yaml");
|
||||
Files.writeString(yamlFile, SIMPLE_YAML);
|
||||
|
||||
YamlHelper helper = new YamlHelper(yamlFile);
|
||||
Object value = helper.getValueByExactKeyPath("app", "name");
|
||||
assertEquals("test", value);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSequenceValues() {
|
||||
String yaml = "items:\n - alpha\n - beta\n - gamma\n";
|
||||
YamlHelper helper = new YamlHelper(LOAD_SETTINGS, yaml);
|
||||
Object value = helper.getValueByExactKeyPath("items");
|
||||
assertInstanceOf(List.class, value);
|
||||
List<?> list = (List<?>) value;
|
||||
assertEquals(3, list.size());
|
||||
assertEquals("alpha", list.get(0));
|
||||
}
|
||||
|
||||
// --- Static type check methods ---
|
||||
|
||||
@Test
|
||||
void testIsInteger() {
|
||||
assertTrue(YamlHelper.isInteger(42));
|
||||
assertTrue(YamlHelper.isInteger("123"));
|
||||
assertFalse(YamlHelper.isInteger("abc"));
|
||||
assertFalse(YamlHelper.isInteger(3.14));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsFloat() {
|
||||
assertTrue(YamlHelper.isFloat(3.14f));
|
||||
assertTrue(YamlHelper.isFloat(3.14));
|
||||
assertTrue(YamlHelper.isFloat("3.14"));
|
||||
assertFalse(YamlHelper.isFloat("abc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsLong() {
|
||||
assertTrue(YamlHelper.isLong(42L));
|
||||
assertTrue(YamlHelper.isLong("9999999999"));
|
||||
assertFalse(YamlHelper.isLong("notALong"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsAnyInteger() {
|
||||
assertTrue(YamlHelper.isAnyInteger(42));
|
||||
assertTrue(YamlHelper.isAnyInteger((short) 5));
|
||||
assertTrue(YamlHelper.isAnyInteger((byte) 1));
|
||||
assertTrue(YamlHelper.isAnyInteger(100L));
|
||||
assertFalse(YamlHelper.isAnyInteger("xyz"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSave_differentPath(@TempDir Path tempDir) throws IOException {
|
||||
Path originalFile = tempDir.resolve("original.yaml");
|
||||
Files.writeString(originalFile, SIMPLE_YAML);
|
||||
|
||||
YamlHelper helper = new YamlHelper(originalFile);
|
||||
helper.updateValue(Arrays.asList("server", "port"), "9090");
|
||||
|
||||
Path savePath = tempDir.resolve("saved.yaml");
|
||||
helper.save(savePath);
|
||||
|
||||
assertTrue(Files.exists(savePath));
|
||||
String content = Files.readString(savePath);
|
||||
assertTrue(content.contains("9090"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user