From 5f1f49288826ef3e782457d93b63d6513fb63910 Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Sun, 3 Aug 2025 06:12:32 +0800 Subject: [PATCH 1/8] Update zh_TW Traditional Chinese translation (#4100) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description of Changes Summary by GitHub Copilot: > > This pull request updates translations in the `messages_zh_TW.properties` file to improve localization for Traditional Chinese. The changes focus on replacing English text with accurate Chinese translations. > > ### Localization Updates: > > * Updated `invalidRoleMessage` to translate "Invalid role" into Traditional Chinese as "無效的角色" for better localization. > * Updated `proFeatures` to translate "Pro Features" into Traditional Chinese as "專業版功能" to align with the rest of the localized content. > --- ## Checklist ### General - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [x] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [x] I have performed a self-review of my own code - [x] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details. --- app/core/src/main/resources/messages_zh_TW.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/core/src/main/resources/messages_zh_TW.properties b/app/core/src/main/resources/messages_zh_TW.properties index 95c9bf20e..bbd3cd495 100644 --- a/app/core/src/main/resources/messages_zh_TW.properties +++ b/app/core/src/main/resources/messages_zh_TW.properties @@ -260,7 +260,7 @@ disabledCurrentUserMessage=無法停用目前使用者 downgradeCurrentUserLongMessage=無法降級目前使用者的角色。因此,將不會顯示目前使用者。 userAlreadyExistsOAuthMessage=使用者已經以 OAuth2 使用者身份存在。 userAlreadyExistsWebMessage=使用者已經以網頁使用者身份存在。 -invalidRoleMessage=Invalid role. +invalidRoleMessage=無效的角色。 error=錯誤 oops=哎呀! help=說明 @@ -273,7 +273,7 @@ color=顏色 sponsor=贊助 info=資訊 pro=專業版 -proFeatures=Pro Features +proFeatures=專業版功能 page=頁面 pages=頁面 loading=載入中... From 77a27930b5b8dd70c5c4cf300c46328cf3404f0b Mon Sep 17 00:00:00 2001 From: Ludy Date: Sun, 3 Aug 2025 00:12:51 +0200 Subject: [PATCH 2/8] ci(github-actions): improve concurrency grouping with PR number fallback (#4101) # Description of Changes - Updated the `concurrency.group` key in the following GitHub Actions workflows: - `.github/workflows/build.yml` - `.github/workflows/check_properties.yml` - `.github/workflows/sonarqube.yml` - The grouping string now uses `github.event.pull_request.number` (if present) as a fallback before falling back to `ref_name` or `ref`. - This helps ensure better grouping for PR-based workflows, improving job cancellation behavior and avoiding unnecessary parallel job execution when multiple pushes occur on the same PR. No functional behavior is changed in the actual build or check logic. --- ## Checklist ### General - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [x] I have performed a self-review of my own code - [x] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details. --- .github/workflows/build.yml | 4 ++-- .github/workflows/check_properties.yml | 6 +++--- .github/workflows/sonarqube.yml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index db847f570..d87e478d3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ on: # This ensures that jobs are grouped by the workflow and branch, allowing for cancellation of # in-progress jobs when a new commit is pushed to the same branch or a new pull request is opened. concurrency: - group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref_name || github.ref }} + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref_name || github.ref }} cancel-in-progress: true permissions: @@ -147,7 +147,7 @@ jobs: - name: Generate OpenAPI documentation run: ./gradlew :stirling-pdf:generateOpenApiDocs - + - name: Upload OpenAPI Documentation uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: diff --git a/.github/workflows/check_properties.yml b/.github/workflows/check_properties.yml index 4ba927e3a..32a970ef1 100644 --- a/.github/workflows/check_properties.yml +++ b/.github/workflows/check_properties.yml @@ -15,7 +15,7 @@ on: # This ensures that jobs are grouped by the workflow and branch, allowing for cancellation of # in-progress jobs when a new commit is pushed to the same branch or a new pull request is opened. concurrency: - group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref_name || github.ref }} + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref_name || github.ref }} cancel-in-progress: true permissions: @@ -127,7 +127,7 @@ jobs: // Filter for relevant files based on the PR changes const changedFiles = files - .filter(file => + .filter(file => file.status !== "removed" && /^app\/core\/src\/main\/resources\/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$/.test(file.filename) ) @@ -289,4 +289,4 @@ jobs: rm -rf pr-branch rm -f pr-branch-messages_en_GB.properties main-branch-messages_en_GB.properties changed_files.txt result.txt echo "Cleanup complete." - continue-on-error: true # Ensure cleanup runs even if previous steps fail \ No newline at end of file + continue-on-error: true # Ensure cleanup runs even if previous steps fail diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml index b16037b47..71f01438c 100644 --- a/.github/workflows/sonarqube.yml +++ b/.github/workflows/sonarqube.yml @@ -18,7 +18,7 @@ on: # This ensures that jobs are grouped by the workflow and branch, allowing for cancellation of # in-progress jobs when a new commit is pushed to the same branch or a new pull request is opened. concurrency: - group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref_name || github.ref }} + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref_name || github.ref }} cancel-in-progress: true permissions: From 9e0f6dd2e138b475fc7689e9fdb754dea983e06b Mon Sep 17 00:00:00 2001 From: Ludy Date: Sun, 3 Aug 2025 00:14:03 +0200 Subject: [PATCH 3/8] style(spotless): centralize and expand formatting config in root build.gradle (#4098) # Description of Changes - Removed redundant `spotless` configurations from `app/common`, `app/core`, and `app/proprietary` modules. - Consolidated all formatting logic into the root `build.gradle` file. - Extended Spotless support to include: - YAML files (`*.yml`, `*.yaml`) - Gradle scripts (`*.gradle`, including nested `app/**/*.gradle`) - Updated `googleJavaFormatVersion` from `1.27.0` to `1.28.0`. This change improves maintainability by enforcing consistent formatting across all modules from a single location. Additionally, it ensures formatting is applied to Gradle and YAML files, which were previously unformatted. --- ## Checklist ### General - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [x] I have performed a self-review of my own code - [x] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details. --- app/common/build.gradle | 15 +++++++++++++-- app/core/build.gradle | 15 +++++++++++++-- app/proprietary/build.gradle | 17 ++++++++++++++--- build.gradle | 30 ++++++++++++------------------ 4 files changed, 52 insertions(+), 25 deletions(-) diff --git a/app/common/build.gradle b/app/common/build.gradle index 515a52a5c..7b210406e 100644 --- a/app/common/build.gradle +++ b/app/common/build.gradle @@ -4,8 +4,7 @@ bootRun { } spotless { java { - target sourceSets.main.allJava - target sourceSets.test.allJava + target 'src/**/java/**/*.java' googleJavaFormat(googleJavaFormatVersion).aosp().reorderImports(false) importOrder("java", "javax", "org", "com", "net", "io", "jakarta", "lombok", "me", "stirling") @@ -14,6 +13,18 @@ spotless { leadingTabsToSpaces() endWithNewline() } + yaml { + target '**/*.yml', '**/*.yaml' + trimTrailingWhitespace() + leadingTabsToSpaces() + endWithNewline() + } + format 'gradle', { + target '**/gradle/*.gradle', '**/*.gradle' + trimTrailingWhitespace() + leadingTabsToSpaces() + endWithNewline() + } } dependencies { api 'org.springframework.boot:spring-boot-starter-web' diff --git a/app/core/build.gradle b/app/core/build.gradle index 46aad111c..037a89497 100644 --- a/app/core/build.gradle +++ b/app/core/build.gradle @@ -14,8 +14,7 @@ configurations { spotless { java { - target sourceSets.main.allJava - target sourceSets.test.allJava + target 'src/**/java/**/*.java' googleJavaFormat(googleJavaFormatVersion).aosp().reorderImports(false) importOrder("java", "javax", "org", "com", "net", "io", "jakarta", "lombok", "me", "stirling") @@ -24,6 +23,18 @@ spotless { leadingTabsToSpaces() endWithNewline() } + yaml { + target '**/*.yml', '**/*.yaml' + trimTrailingWhitespace() + leadingTabsToSpaces() + endWithNewline() + } + format 'gradle', { + target '**/gradle/*.gradle', '**/*.gradle' + trimTrailingWhitespace() + leadingTabsToSpaces() + endWithNewline() + } } dependencies { diff --git a/app/proprietary/build.gradle b/app/proprietary/build.gradle index 467d8a138..80b61438a 100644 --- a/app/proprietary/build.gradle +++ b/app/proprietary/build.gradle @@ -5,9 +5,8 @@ bootRun { enabled = false } spotless { - java { - target sourceSets.main.allJava - target sourceSets.test.allJava + java { + target 'src/**/java/**/*.java' googleJavaFormat(googleJavaFormatVersion).aosp().reorderImports(false) importOrder("java", "javax", "org", "com", "net", "io", "jakarta", "lombok", "me", "stirling") @@ -16,6 +15,18 @@ spotless { leadingTabsToSpaces() endWithNewline() } + yaml { + target '**/*.yml', '**/*.yaml' + trimTrailingWhitespace() + leadingTabsToSpaces() + endWithNewline() + } + format 'gradle', { + target '**/gradle/*.gradle', '**/*.gradle' + trimTrailingWhitespace() + leadingTabsToSpaces() + endWithNewline() + } } dependencies { implementation project(':common') diff --git a/build.gradle b/build.gradle index ceb786ff0..554d92689 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,7 @@ ext { springSecuritySamlVersion = "6.5.2" openSamlVersion = "4.3.2" commonmarkVersion = "0.25.0" - googleJavaFormatVersion = "1.27.0" + googleJavaFormatVersion = "1.28.0" tempJrePath = null } @@ -158,9 +158,9 @@ subprojects { useJUnitPlatform() } - tasks.named("processResources") { - dependsOn(rootProject.tasks.writeVersion) - } + tasks.named("processResources") { + dependsOn(rootProject.tasks.writeVersion) + } if (name == 'stirling-pdf') { apply plugin: 'org.springdoc.openapi-gradle-plugin' @@ -528,20 +528,14 @@ launch4j { } spotless { - java { - target sourceSets.main.allJava - target sourceSets.test.allJava - target project(':common').sourceSets.main.allJava - target project(':common').sourceSets.test.allJava - target project(':proprietary').sourceSets.main.allJava - target project(':proprietary').sourceSets.test.allJava - target project(':stirling-pdf').sourceSets.main.allJava - target project(':stirling-pdf').sourceSets.test.allJava - - googleJavaFormat(googleJavaFormatVersion).aosp().reorderImports(false) - - importOrder("java", "javax", "org", "com", "net", "io", "jakarta", "lombok", "me", "stirling") - toggleOffOn() + yaml { + target '*.yml', '*.yaml' + trimTrailingWhitespace() + leadingTabsToSpaces() + endWithNewline() + } + format 'gradle', { + target 'build.gradle', 'settings.gradle', 'gradle/*.gradle', 'gradle/**/*.gradle' trimTrailingWhitespace() leadingTabsToSpaces() endWithNewline() From 62779d99d108dde985867659c07218604b3876c6 Mon Sep 17 00:00:00 2001 From: Ludy Date: Sun, 3 Aug 2025 00:16:15 +0200 Subject: [PATCH 4/8] fix(stamp): validate image filename only for image stamp type (#4099) # Description of Changes - **What was changed**: Moved the filename validation logic for `stampImage` inside a condition that checks whether the stamp type is `"image"`. - **Why the change was made**: Previously, the validation was applied regardless of stamp type, leading to unnecessary errors for non-image-based stamps where no `stampImage` is provided. Closes #4097 --- ## Checklist ### General - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [x] I have performed a self-review of my own code - [x] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../SPDF/controller/api/misc/StampController.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/StampController.java b/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/StampController.java index f5bc9dc65..0df77bca7 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/StampController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/StampController.java @@ -70,9 +70,14 @@ public class StampController { String stampType = request.getStampType(); String stampText = request.getStampText(); MultipartFile stampImage = request.getStampImage(); - String stampImageName = stampImage.getOriginalFilename(); - if (stampImageName.contains("..") || stampImageName.startsWith("/")) { - throw new IllegalArgumentException("Invalid stamp image file path"); + if ("image".equalsIgnoreCase(stampType)) { + if (stampImage == null) { + throw new IllegalArgumentException("Stamp image file must be provided when stamp type is 'image'"); + } + String stampImageName = stampImage.getOriginalFilename(); + if (stampImageName == null || stampImageName.contains("..") || stampImageName.startsWith("/")) { + throw new IllegalArgumentException("Invalid stamp image file path"); + } } String alphabet = request.getAlphabet(); float fontSize = request.getFontSize(); From 56c79eb63c61751de02834e3116907ffe23ebc0f Mon Sep 17 00:00:00 2001 From: "stirlingbot[bot]" <195170888+stirlingbot[bot]@users.noreply.github.com> Date: Sat, 2 Aug 2025 23:18:48 +0100 Subject: [PATCH 5/8] =?UTF-8?q?=F0=9F=A4=96=20format=20everything=20with?= =?UTF-8?q?=20pre-commit=20by=20stirlingbot=20(#4075)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Auto-generated by [create-pull-request][1] with **stirlingbot** [1]: https://github.com/peter-evans/create-pull-request Signed-off-by: stirlingbot[bot] Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- .../AutoJobPostMappingIntegrationTest.java | 92 +-- .../common/service/FileStorageTest.java | 27 +- .../service/JobExecutorServiceTest.java | 84 +- .../software/common/service/JobQueueTest.java | 15 +- .../common/service/ResourceMonitorTest.java | 49 +- .../common/service/TaskManagerTest.java | 23 +- .../service/TempFileCleanupServiceTest.java | 349 ++++---- .../common/util/CheckProgramInstallTest.java | 21 +- .../common/util/CustomHtmlSanitizerTest.java | 12 +- .../software/common/util/EmlToPdfTest.java | 753 ++++++++++-------- .../software/common/util/FileMonitorTest.java | 1 + .../software/common/util/FileToPdfTest.java | 28 +- .../common/util/ProviderUtilsTest.java | 12 +- .../common/util/SpringContextHolderTest.java | 7 +- .../HighContrastColorReplaceDeciderTest.java | 8 +- .../misc/InvertFullColorStrategyTest.java | 1 + .../ReplaceAndInvertColorStrategyTest.java | 1 + .../StringToArrayListPropertyEditorTest.java | 11 +- .../EditTableOfContentsControllerTest.java | 97 ++- .../controller/api/MergeControllerTest.java | 66 +- .../api/misc/AttachmentControllerTest.java | 56 +- .../api/pipeline/PipelineProcessorTest.java | 2 +- .../SPDF/service/AttachmentServiceTest.java | 24 +- .../SPDF/service/SignatureServiceTest.java | 2 +- .../common/controller/JobControllerTest.java | 104 ++- .../CustomLogoutSuccessHandlerTest.java | 11 +- .../configuration/DatabaseConfigTest.java | 7 +- .../security/service/EmailServiceTest.java | 9 +- .../security/service/TeamServiceTest.java | 25 +- .../security/service/UserServiceTest.java | 68 +- 31 files changed, 1097 insertions(+), 870 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e1de0c28b..a97b3a2a8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -43,4 +43,4 @@ repos: # - stylelint-config-standard@38.0.0 # - "@stylistic/stylelint-plugin@3.1.3" # files: \.(css)$ - # args: [--fix] \ No newline at end of file + # args: [--fix] diff --git a/app/common/src/test/java/stirling/software/common/annotations/AutoJobPostMappingIntegrationTest.java b/app/common/src/test/java/stirling/software/common/annotations/AutoJobPostMappingIntegrationTest.java index 6d72855fb..2c4546ac0 100644 --- a/app/common/src/test/java/stirling/software/common/annotations/AutoJobPostMappingIntegrationTest.java +++ b/app/common/src/test/java/stirling/software/common/annotations/AutoJobPostMappingIntegrationTest.java @@ -7,24 +7,19 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.junit.jupiter.api.BeforeEach; - -import java.util.Arrays; import java.util.function.Supplier; import org.aspectj.lang.ProceedingJoinPoint; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.ResponseEntity; @@ -45,62 +40,44 @@ class AutoJobPostMappingIntegrationTest { private AutoJobAspect autoJobAspect; - @Mock - private JobExecutorService jobExecutorService; + @Mock private JobExecutorService jobExecutorService; - @Mock - private HttpServletRequest request; + @Mock private HttpServletRequest request; - @Mock - private FileOrUploadService fileOrUploadService; + @Mock private FileOrUploadService fileOrUploadService; - @Mock - private FileStorage fileStorage; + @Mock private FileStorage fileStorage; + @Mock private ResourceMonitor resourceMonitor; - @Mock - private ResourceMonitor resourceMonitor; - - @Mock - private JobQueue jobQueue; + @Mock private JobQueue jobQueue; @BeforeEach void setUp() { - autoJobAspect = new AutoJobAspect( - jobExecutorService, - request, - fileOrUploadService, - fileStorage - ); + autoJobAspect = + new AutoJobAspect(jobExecutorService, request, fileOrUploadService, fileStorage); } - @Mock - private ProceedingJoinPoint joinPoint; + @Mock private ProceedingJoinPoint joinPoint; - @Mock - private AutoJobPostMapping autoJobPostMapping; + @Mock private AutoJobPostMapping autoJobPostMapping; - @Captor - private ArgumentCaptor> workCaptor; + @Captor private ArgumentCaptor> workCaptor; - @Captor - private ArgumentCaptor asyncCaptor; + @Captor private ArgumentCaptor asyncCaptor; - @Captor - private ArgumentCaptor timeoutCaptor; + @Captor private ArgumentCaptor timeoutCaptor; - @Captor - private ArgumentCaptor queueableCaptor; + @Captor private ArgumentCaptor queueableCaptor; - @Captor - private ArgumentCaptor resourceWeightCaptor; + @Captor private ArgumentCaptor resourceWeightCaptor; @Test void shouldExecuteWithCustomParameters() throws Throwable { // Given PDFFile pdfFile = new PDFFile(); pdfFile.setFileId("test-file-id"); - Object[] args = new Object[] { pdfFile }; + Object[] args = new Object[] {pdfFile}; when(joinPoint.getArgs()).thenReturn(args); when(request.getParameter("async")).thenReturn("true"); @@ -113,9 +90,8 @@ class AutoJobPostMappingIntegrationTest { MultipartFile mockFile = mock(MultipartFile.class); when(fileStorage.retrieveFile("test-file-id")).thenReturn(mockFile); - when(jobExecutorService.runJobGeneric( - anyBoolean(), any(Supplier.class), anyLong(), anyBoolean(), anyInt())) + anyBoolean(), any(Supplier.class), anyLong(), anyBoolean(), anyInt())) .thenReturn(ResponseEntity.ok("success")); // When @@ -124,12 +100,13 @@ class AutoJobPostMappingIntegrationTest { // Then assertEquals(ResponseEntity.ok("success"), result); - verify(jobExecutorService).runJobGeneric( - asyncCaptor.capture(), - workCaptor.capture(), - timeoutCaptor.capture(), - queueableCaptor.capture(), - resourceWeightCaptor.capture()); + verify(jobExecutorService) + .runJobGeneric( + asyncCaptor.capture(), + workCaptor.capture(), + timeoutCaptor.capture(), + queueableCaptor.capture(), + resourceWeightCaptor.capture()); assertTrue(asyncCaptor.getValue(), "Async should be true"); assertEquals(60000L, timeoutCaptor.getValue(), "Timeout should be 60000ms"); @@ -158,11 +135,12 @@ class AutoJobPostMappingIntegrationTest { // Mock jobExecutorService to execute the work immediately when(jobExecutorService.runJobGeneric( - anyBoolean(), any(Supplier.class), anyLong(), anyBoolean(), anyInt())) - .thenAnswer(invocation -> { - Supplier work = invocation.getArgument(1); - return work.get(); - }); + anyBoolean(), any(Supplier.class), anyLong(), anyBoolean(), anyInt())) + .thenAnswer( + invocation -> { + Supplier work = invocation.getArgument(1); + return work.get(); + }); // When Object result = autoJobAspect.wrapWithJobExecution(joinPoint, autoJobPostMapping); @@ -179,7 +157,7 @@ class AutoJobPostMappingIntegrationTest { // Given PDFFile pdfFile = new PDFFile(); pdfFile.setFileInput(mock(MultipartFile.class)); - Object[] args = new Object[] { pdfFile }; + Object[] args = new Object[] {pdfFile}; when(joinPoint.getArgs()).thenReturn(args); when(request.getParameter("async")).thenReturn("true"); @@ -190,14 +168,16 @@ class AutoJobPostMappingIntegrationTest { // Mock job executor to return a successful response when(jobExecutorService.runJobGeneric( - anyBoolean(), any(Supplier.class), anyLong(), anyBoolean(), anyInt())) + anyBoolean(), any(Supplier.class), anyLong(), anyBoolean(), anyInt())) .thenReturn(ResponseEntity.ok("success")); // When autoJobAspect.wrapWithJobExecution(joinPoint, autoJobPostMapping); // Then - assertEquals("stored-file-id", pdfFile.getFileId(), + assertEquals( + "stored-file-id", + pdfFile.getFileId(), "FileId should be set to the stored file id"); assertNotNull(pdfFile.getFileInput(), "FileInput should be replaced with persistent file"); diff --git a/app/common/src/test/java/stirling/software/common/service/FileStorageTest.java b/app/common/src/test/java/stirling/software/common/service/FileStorageTest.java index 81ab5857e..76f3e353e 100644 --- a/app/common/src/test/java/stirling/software/common/service/FileStorageTest.java +++ b/app/common/src/test/java/stirling/software/common/service/FileStorageTest.java @@ -1,10 +1,9 @@ package stirling.software.common.service; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; import static org.mockito.AdditionalAnswers.*; +import static org.mockito.Mockito.*; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -21,14 +20,11 @@ import org.springframework.web.multipart.MultipartFile; class FileStorageTest { - @TempDir - Path tempDir; + @TempDir Path tempDir; - @Mock - private FileOrUploadService fileOrUploadService; + @Mock private FileOrUploadService fileOrUploadService; - @InjectMocks - private FileStorage fileStorage; + @InjectMocks private FileStorage fileStorage; private MultipartFile mockFile; @@ -50,11 +46,14 @@ class FileStorageTest { when(mockFile.getBytes()).thenReturn(fileContent); // Set up mock to handle transferTo by writing the file - doAnswer(invocation -> { - java.io.File file = invocation.getArgument(0); - Files.write(file.toPath(), fileContent); - return null; - }).when(mockFile).transferTo(any(java.io.File.class)); + doAnswer( + invocation -> { + java.io.File file = invocation.getArgument(0); + Files.write(file.toPath(), fileContent); + return null; + }) + .when(mockFile) + .transferTo(any(java.io.File.class)); // Act String fileId = fileStorage.storeFile(mockFile); @@ -90,7 +89,7 @@ class FileStorageTest { MultipartFile expectedFile = mock(MultipartFile.class); when(fileOrUploadService.toMockMultipartFile(eq(fileId), eq(fileContent))) - .thenReturn(expectedFile); + .thenReturn(expectedFile); // Act MultipartFile result = fileStorage.retrieveFile(fileId); diff --git a/app/common/src/test/java/stirling/software/common/service/JobExecutorServiceTest.java b/app/common/src/test/java/stirling/software/common/service/JobExecutorServiceTest.java index 370db503b..630ac80bf 100644 --- a/app/common/src/test/java/stirling/software/common/service/JobExecutorServiceTest.java +++ b/app/common/src/test/java/stirling/software/common/service/JobExecutorServiceTest.java @@ -4,14 +4,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -30,11 +25,9 @@ import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.test.util.ReflectionTestUtils; import jakarta.servlet.http.HttpServletRequest; -import stirling.software.common.model.job.JobProgress; import stirling.software.common.model.job.JobResponse; @ExtendWith(MockitoExtension.class) @@ -42,36 +35,31 @@ class JobExecutorServiceTest { private JobExecutorService jobExecutorService; - @Mock - private TaskManager taskManager; + @Mock private TaskManager taskManager; - @Mock - private FileStorage fileStorage; + @Mock private FileStorage fileStorage; - @Mock - private HttpServletRequest request; + @Mock private HttpServletRequest request; - @Mock - private ResourceMonitor resourceMonitor; + @Mock private ResourceMonitor resourceMonitor; - @Mock - private JobQueue jobQueue; + @Mock private JobQueue jobQueue; - @Captor - private ArgumentCaptor jobIdCaptor; + @Captor private ArgumentCaptor jobIdCaptor; @BeforeEach void setUp() { // Initialize the service manually with all its dependencies - jobExecutorService = new JobExecutorService( - taskManager, - fileStorage, - request, - resourceMonitor, - jobQueue, - 30000L, // asyncRequestTimeoutMs - "30m" // sessionTimeout - ); + jobExecutorService = + new JobExecutorService( + taskManager, + fileStorage, + request, + resourceMonitor, + jobQueue, + 30000L, // asyncRequestTimeoutMs + "30m" // sessionTimeout + ); } @Test @@ -109,13 +97,13 @@ class JobExecutorServiceTest { verify(taskManager).createTask(jobIdCaptor.capture()); } - @Test void shouldHandleSyncJobError() { // Given - Supplier work = () -> { - throw new RuntimeException("Test error"); - }; + Supplier work = + () -> { + throw new RuntimeException("Test error"); + }; // When ResponseEntity response = jobExecutorService.runJobGeneric(false, work); @@ -141,8 +129,7 @@ class JobExecutorServiceTest { when(jobQueue.queueJob(anyString(), eq(80), any(), anyLong())).thenReturn(future); // When - ResponseEntity response = jobExecutorService.runJobGeneric( - true, work, 5000, true, 80); + ResponseEntity response = jobExecutorService.runJobGeneric(true, work, 5000, true, 80); // Then assertEquals(HttpStatus.OK, response.getStatusCode()); @@ -160,8 +147,9 @@ class JobExecutorServiceTest { long customTimeout = 60000L; // Use reflection to access the private executeWithTimeout method - java.lang.reflect.Method executeMethod = JobExecutorService.class - .getDeclaredMethod("executeWithTimeout", Supplier.class, long.class); + java.lang.reflect.Method executeMethod = + JobExecutorService.class.getDeclaredMethod( + "executeWithTimeout", Supplier.class, long.class); executeMethod.setAccessible(true); // Create a spy on the JobExecutorService to verify method calls @@ -177,19 +165,21 @@ class JobExecutorServiceTest { @Test void shouldHandleTimeout() throws Exception { // Given - Supplier work = () -> { - try { - Thread.sleep(100); // Simulate long-running job - return "test-result"; - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException(e); - } - }; + Supplier work = + () -> { + try { + Thread.sleep(100); // Simulate long-running job + return "test-result"; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + }; // Use reflection to access the private executeWithTimeout method - java.lang.reflect.Method executeMethod = JobExecutorService.class - .getDeclaredMethod("executeWithTimeout", Supplier.class, long.class); + java.lang.reflect.Method executeMethod = + JobExecutorService.class.getDeclaredMethod( + "executeWithTimeout", Supplier.class, long.class); executeMethod.setAccessible(true); // When/Then diff --git a/app/common/src/test/java/stirling/software/common/service/JobQueueTest.java b/app/common/src/test/java/stirling/software/common/service/JobQueueTest.java index 64c836faf..ca0698436 100644 --- a/app/common/src/test/java/stirling/software/common/service/JobQueueTest.java +++ b/app/common/src/test/java/stirling/software/common/service/JobQueueTest.java @@ -1,10 +1,8 @@ package stirling.software.common.service; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.Map; @@ -17,7 +15,6 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import stirling.software.common.model.job.JobProgress; import stirling.software.common.service.ResourceMonitor.ResourceStatus; @ExtendWith(MockitoExtension.class) @@ -25,16 +22,17 @@ class JobQueueTest { private JobQueue jobQueue; - @Mock - private ResourceMonitor resourceMonitor; + @Mock private ResourceMonitor resourceMonitor; - - private final AtomicReference statusRef = new AtomicReference<>(ResourceStatus.OK); + private final AtomicReference statusRef = + new AtomicReference<>(ResourceStatus.OK); @BeforeEach void setUp() { // Mark stubbing as lenient to avoid UnnecessaryStubbingException - lenient().when(resourceMonitor.calculateDynamicQueueCapacity(anyInt(), anyInt())).thenReturn(10); + lenient() + .when(resourceMonitor.calculateDynamicQueueCapacity(anyInt(), anyInt())) + .thenReturn(10); lenient().when(resourceMonitor.getCurrentStatus()).thenReturn(statusRef); // Initialize JobQueue with mocked ResourceMonitor @@ -50,7 +48,6 @@ class JobQueueTest { jobQueue.queueJob(jobId, resourceWeight, work, timeoutMs); - assertTrue(jobQueue.isJobQueued(jobId)); assertEquals(1, jobQueue.getTotalQueuedJobs()); } diff --git a/app/common/src/test/java/stirling/software/common/service/ResourceMonitorTest.java b/app/common/src/test/java/stirling/software/common/service/ResourceMonitorTest.java index 9667f4999..25a098764 100644 --- a/app/common/src/test/java/stirling/software/common/service/ResourceMonitorTest.java +++ b/app/common/src/test/java/stirling/software/common/service/ResourceMonitorTest.java @@ -1,14 +1,10 @@ package stirling.software.common.service; -import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import java.lang.management.MemoryMXBean; -import java.lang.management.MemoryUsage; import java.lang.management.OperatingSystemMXBean; import java.time.Instant; import java.util.concurrent.atomic.AtomicReference; @@ -30,20 +26,19 @@ import stirling.software.common.service.ResourceMonitor.ResourceStatus; @ExtendWith(MockitoExtension.class) class ResourceMonitorTest { - @InjectMocks - private ResourceMonitor resourceMonitor; + @InjectMocks private ResourceMonitor resourceMonitor; - @Mock - private OperatingSystemMXBean osMXBean; + @Mock private OperatingSystemMXBean osMXBean; - @Mock - private MemoryMXBean memoryMXBean; + @Mock private MemoryMXBean memoryMXBean; @Spy - private AtomicReference currentStatus = new AtomicReference<>(ResourceStatus.OK); + private AtomicReference currentStatus = + new AtomicReference<>(ResourceStatus.OK); @Spy - private AtomicReference latestMetrics = new AtomicReference<>(new ResourceMetrics()); + private AtomicReference latestMetrics = + new AtomicReference<>(new ResourceMetrics()); @BeforeEach void setUp() { @@ -92,23 +87,26 @@ class ResourceMonitorTest { assertEquals(3, capacity, "With CRITICAL status, capacity should be reduced to 30%"); // Test minimum capacity enforcement - assertEquals(minCapacity, resourceMonitor.calculateDynamicQueueCapacity(1, minCapacity), + assertEquals( + minCapacity, + resourceMonitor.calculateDynamicQueueCapacity(1, minCapacity), "Should never go below minimum capacity"); } @ParameterizedTest @CsvSource({ - "10, OK, false", // Light job, OK status + "10, OK, false", // Light job, OK status "10, WARNING, false", // Light job, WARNING status "10, CRITICAL, true", // Light job, CRITICAL status - "30, OK, false", // Medium job, OK status - "30, WARNING, true", // Medium job, WARNING status + "30, OK, false", // Medium job, OK status + "30, WARNING, true", // Medium job, WARNING status "30, CRITICAL, true", // Medium job, CRITICAL status - "80, OK, true", // Heavy job, OK status - "80, WARNING, true", // Heavy job, WARNING status - "80, CRITICAL, true" // Heavy job, CRITICAL status + "80, OK, true", // Heavy job, OK status + "80, WARNING, true", // Heavy job, WARNING status + "80, CRITICAL, true" // Heavy job, CRITICAL status }) - void shouldQueueJobBasedOnWeightAndStatus(int weight, ResourceStatus status, boolean shouldQueue) { + void shouldQueueJobBasedOnWeightAndStatus( + int weight, ResourceStatus status, boolean shouldQueue) { // Given currentStatus.set(status); @@ -116,8 +114,11 @@ class ResourceMonitorTest { boolean result = resourceMonitor.shouldQueueJob(weight); // Then - assertEquals(shouldQueue, result, - String.format("For weight %d and status %s, shouldQueue should be %s", + assertEquals( + shouldQueue, + result, + String.format( + "For weight %d and status %s, shouldQueue should be %s", weight, status, shouldQueue)); } @@ -131,7 +132,9 @@ class ResourceMonitorTest { ResourceMetrics freshMetrics = new ResourceMetrics(0.5, 0.5, 1024, 2048, 4096, now); // When/Then - assertTrue(staleMetrics.isStale(5000), "Metrics from 6 seconds ago should be stale with 5s threshold"); + assertTrue( + staleMetrics.isStale(5000), + "Metrics from 6 seconds ago should be stale with 5s threshold"); assertFalse(freshMetrics.isStale(5000), "Fresh metrics should not be stale"); } } diff --git a/app/common/src/test/java/stirling/software/common/service/TaskManagerTest.java b/app/common/src/test/java/stirling/software/common/service/TaskManagerTest.java index 5fd2dcc87..5b8027b62 100644 --- a/app/common/src/test/java/stirling/software/common/service/TaskManagerTest.java +++ b/app/common/src/test/java/stirling/software/common/service/TaskManagerTest.java @@ -6,7 +6,6 @@ import static org.mockito.Mockito.*; import java.time.LocalDateTime; import java.util.Map; import java.util.UUID; -import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -22,11 +21,9 @@ import stirling.software.common.model.job.ResultFile; class TaskManagerTest { - @Mock - private FileStorage fileStorage; + @Mock private FileStorage fileStorage; - @InjectMocks - private TaskManager taskManager; + @InjectMocks private TaskManager taskManager; private AutoCloseable closeable; @@ -234,18 +231,20 @@ class TaskManagerTest { ReflectionTestUtils.setField(oldJob, "complete", true); // Create a ResultFile and set it using the new approach - ResultFile resultFile = ResultFile.builder() - .fileId("file-id") - .fileName("test.pdf") - .contentType("application/pdf") - .fileSize(1024L) - .build(); + ResultFile resultFile = + ResultFile.builder() + .fileId("file-id") + .fileName("test.pdf") + .contentType("application/pdf") + .fileSize(1024L) + .build(); ReflectionTestUtils.setField(oldJob, "resultFiles", java.util.List.of(resultFile)); when(fileStorage.deleteFile("file-id")).thenReturn(true); // Obtain access to the private jobResults map - Map jobResultsMap = (Map) ReflectionTestUtils.getField(taskManager, "jobResults"); + Map jobResultsMap = + (Map) ReflectionTestUtils.getField(taskManager, "jobResults"); // 3. Create an active job String activeJobId = "active-job"; diff --git a/app/common/src/test/java/stirling/software/common/service/TempFileCleanupServiceTest.java b/app/common/src/test/java/stirling/software/common/service/TempFileCleanupServiceTest.java index 34c471227..0418a746e 100644 --- a/app/common/src/test/java/stirling/software/common/service/TempFileCleanupServiceTest.java +++ b/app/common/src/test/java/stirling/software/common/service/TempFileCleanupServiceTest.java @@ -12,7 +12,6 @@ import java.nio.file.Path; import java.nio.file.attribute.FileTime; import java.util.HashSet; import java.util.Set; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.stream.Stream; @@ -30,31 +29,22 @@ import stirling.software.common.model.ApplicationProperties; import stirling.software.common.util.TempFileManager; import stirling.software.common.util.TempFileRegistry; -/** - * Tests for the TempFileCleanupService, focusing on its pattern-matching and cleanup logic. - */ +/** Tests for the TempFileCleanupService, focusing on its pattern-matching and cleanup logic. */ public class TempFileCleanupServiceTest { - @TempDir - Path tempDir; + @TempDir Path tempDir; - @Mock - private TempFileRegistry registry; + @Mock private TempFileRegistry registry; - @Mock - private TempFileManager tempFileManager; + @Mock private TempFileManager tempFileManager; - @Mock - private ApplicationProperties applicationProperties; + @Mock private ApplicationProperties applicationProperties; - @Mock - private ApplicationProperties.System system; + @Mock private ApplicationProperties.System system; - @Mock - private ApplicationProperties.TempFileManagement tempFileManagement; + @Mock private ApplicationProperties.TempFileManagement tempFileManagement; - @InjectMocks - private TempFileCleanupService cleanupService; + @InjectMocks private TempFileCleanupService cleanupService; private Path systemTempDir; private Path customTempDir; @@ -124,7 +114,8 @@ public class TempFileCleanupServiceTest { // Files that should be preserved Path jettyFile1 = Files.createFile(systemTempDir.resolve("jetty-123.tmp")); - Path jettyFile2 = Files.createFile(systemTempDir.resolve("something-with-jetty-inside.tmp")); + Path jettyFile2 = + Files.createFile(systemTempDir.resolve("something-with-jetty-inside.tmp")); Path regularFile = Files.createFile(systemTempDir.resolve("important.txt")); // Create a nested directory with temp files @@ -143,19 +134,29 @@ public class TempFileCleanupServiceTest { // Use MockedStatic to mock Files operations try (MockedStatic mockedFiles = mockStatic(Files.class)) { // Mock Files.list for each directory we'll process - mockedFiles.when(() -> Files.list(eq(systemTempDir))) - .thenReturn(Stream.of( - ourTempFile1, ourTempFile2, oldTempFile, sysTempFile1, - jettyFile1, jettyFile2, regularFile, emptyFile, nestedDir)); + mockedFiles + .when(() -> Files.list(eq(systemTempDir))) + .thenReturn( + Stream.of( + ourTempFile1, + ourTempFile2, + oldTempFile, + sysTempFile1, + jettyFile1, + jettyFile2, + regularFile, + emptyFile, + nestedDir)); - mockedFiles.when(() -> Files.list(eq(customTempDir))) + mockedFiles + .when(() -> Files.list(eq(customTempDir))) .thenReturn(Stream.of(ourTempFile3, ourTempFile4, sysTempFile2, sysTempFile3)); - mockedFiles.when(() -> Files.list(eq(libreOfficeTempDir))) + mockedFiles + .when(() -> Files.list(eq(libreOfficeTempDir))) .thenReturn(Stream.of(ourTempFile5)); - mockedFiles.when(() -> Files.list(eq(nestedDir))) - .thenReturn(Stream.of(nestedTempFile)); + mockedFiles.when(() -> Files.list(eq(nestedDir))).thenReturn(Stream.of(nestedTempFile)); // Configure Files.isDirectory for each path mockedFiles.when(() -> Files.isDirectory(eq(nestedDir))).thenReturn(true); @@ -165,48 +166,59 @@ public class TempFileCleanupServiceTest { mockedFiles.when(() -> Files.exists(any(Path.class))).thenReturn(true); // Configure Files.getLastModifiedTime to return different times based on file names - mockedFiles.when(() -> Files.getLastModifiedTime(any(Path.class))) - .thenAnswer(invocation -> { - Path path = invocation.getArgument(0); - String fileName = path.getFileName().toString(); + mockedFiles + .when(() -> Files.getLastModifiedTime(any(Path.class))) + .thenAnswer( + invocation -> { + Path path = invocation.getArgument(0); + String fileName = path.getFileName().toString(); - // For files with "old" in the name, return a timestamp older than maxAgeMillis - if (fileName.contains("old")) { - return FileTime.fromMillis(System.currentTimeMillis() - 5000000); - } - // For empty.tmp file, return a timestamp older than 5 minutes (for empty file test) - else if (fileName.equals("empty.tmp")) { - return FileTime.fromMillis(System.currentTimeMillis() - 6 * 60 * 1000); - } - // For all other files, return a recent timestamp - else { - return FileTime.fromMillis(System.currentTimeMillis() - 60000); // 1 minute ago - } - }); + // For files with "old" in the name, return a timestamp older than + // maxAgeMillis + if (fileName.contains("old")) { + return FileTime.fromMillis( + System.currentTimeMillis() - 5000000); + } + // For empty.tmp file, return a timestamp older than 5 minutes (for + // empty file test) + else if (fileName.equals("empty.tmp")) { + return FileTime.fromMillis( + System.currentTimeMillis() - 6 * 60 * 1000); + } + // For all other files, return a recent timestamp + else { + return FileTime.fromMillis( + System.currentTimeMillis() - 60000); // 1 minute ago + } + }); // Configure Files.size to return different sizes based on file names - mockedFiles.when(() -> Files.size(any(Path.class))) - .thenAnswer(invocation -> { - Path path = invocation.getArgument(0); - String fileName = path.getFileName().toString(); + mockedFiles + .when(() -> Files.size(any(Path.class))) + .thenAnswer( + invocation -> { + Path path = invocation.getArgument(0); + String fileName = path.getFileName().toString(); - // Return 0 bytes for the empty file - if (fileName.equals("empty.tmp")) { - return 0L; - } - // Return normal size for all other files - else { - return 1024L; // 1 KB - } - }); + // Return 0 bytes for the empty file + if (fileName.equals("empty.tmp")) { + return 0L; + } + // Return normal size for all other files + else { + return 1024L; // 1 KB + } + }); // For deleteIfExists, track which files would be deleted - mockedFiles.when(() -> Files.deleteIfExists(any(Path.class))) - .thenAnswer(invocation -> { - Path path = invocation.getArgument(0); - deletedFiles.add(path); - return true; - }); + mockedFiles + .when(() -> Files.deleteIfExists(any(Path.class))) + .thenAnswer( + invocation -> { + Path path = invocation.getArgument(0); + deletedFiles.add(path); + return true; + }); // Act - set containerMode to false for this test invokeCleanupDirectoryStreaming(systemTempDir, false, 0, 3600000); @@ -218,20 +230,33 @@ public class TempFileCleanupServiceTest { assertTrue(deletedFiles.contains(emptyFile), "Empty file should be deleted"); // Regular temp files should not be deleted because they're too new - assertFalse(deletedFiles.contains(ourTempFile1), "Recent temp file should be preserved"); - assertFalse(deletedFiles.contains(ourTempFile2), "Recent temp file should be preserved"); - assertFalse(deletedFiles.contains(ourTempFile3), "Recent temp file should be preserved"); - assertFalse(deletedFiles.contains(ourTempFile4), "Recent temp file should be preserved"); - assertFalse(deletedFiles.contains(ourTempFile5), "Recent temp file should be preserved"); + assertFalse( + deletedFiles.contains(ourTempFile1), "Recent temp file should be preserved"); + assertFalse( + deletedFiles.contains(ourTempFile2), "Recent temp file should be preserved"); + assertFalse( + deletedFiles.contains(ourTempFile3), "Recent temp file should be preserved"); + assertFalse( + deletedFiles.contains(ourTempFile4), "Recent temp file should be preserved"); + assertFalse( + deletedFiles.contains(ourTempFile5), "Recent temp file should be preserved"); // System temp files should not be deleted in non-container mode - assertFalse(deletedFiles.contains(sysTempFile1), "System temp file should be preserved in non-container mode"); - assertFalse(deletedFiles.contains(sysTempFile2), "System temp file should be preserved in non-container mode"); - assertFalse(deletedFiles.contains(sysTempFile3), "System temp file should be preserved in non-container mode"); + assertFalse( + deletedFiles.contains(sysTempFile1), + "System temp file should be preserved in non-container mode"); + assertFalse( + deletedFiles.contains(sysTempFile2), + "System temp file should be preserved in non-container mode"); + assertFalse( + deletedFiles.contains(sysTempFile3), + "System temp file should be preserved in non-container mode"); // Jetty files and regular files should never be deleted assertFalse(deletedFiles.contains(jettyFile1), "Jetty file should be preserved"); - assertFalse(deletedFiles.contains(jettyFile2), "File with jetty in name should be preserved"); + assertFalse( + deletedFiles.contains(jettyFile2), + "File with jetty in name should be preserved"); assertFalse(deletedFiles.contains(regularFile), "Regular file should be preserved"); } } @@ -252,7 +277,8 @@ public class TempFileCleanupServiceTest { // Use MockedStatic to mock Files operations try (MockedStatic mockedFiles = mockStatic(Files.class)) { // Mock Files.list for systemTempDir - mockedFiles.when(() -> Files.list(eq(systemTempDir))) + mockedFiles + .when(() -> Files.list(eq(systemTempDir))) .thenReturn(Stream.of(ourTempFile, sysTempFile, regularFile)); // Configure Files.isDirectory @@ -262,28 +288,37 @@ public class TempFileCleanupServiceTest { mockedFiles.when(() -> Files.exists(any(Path.class))).thenReturn(true); // Configure Files.getLastModifiedTime to return recent timestamps - mockedFiles.when(() -> Files.getLastModifiedTime(any(Path.class))) - .thenReturn(FileTime.fromMillis(System.currentTimeMillis() - 60000)); // 1 minute ago + mockedFiles + .when(() -> Files.getLastModifiedTime(any(Path.class))) + .thenReturn( + FileTime.fromMillis( + System.currentTimeMillis() - 60000)); // 1 minute ago // Configure Files.size to return normal size - mockedFiles.when(() -> Files.size(any(Path.class))) - .thenReturn(1024L); // 1 KB + mockedFiles.when(() -> Files.size(any(Path.class))).thenReturn(1024L); // 1 KB // For deleteIfExists, track which files would be deleted - mockedFiles.when(() -> Files.deleteIfExists(any(Path.class))) - .thenAnswer(invocation -> { - Path path = invocation.getArgument(0); - deletedFiles.add(path); - return true; - }); + mockedFiles + .when(() -> Files.deleteIfExists(any(Path.class))) + .thenAnswer( + invocation -> { + Path path = invocation.getArgument(0); + deletedFiles.add(path); + return true; + }); // Act - set containerMode to true and maxAgeMillis to 0 for container startup cleanup invokeCleanupDirectoryStreaming(systemTempDir, true, 0, 0); - // Assert - In container mode, both our temp files and system temp files should be deleted + // Assert - In container mode, both our temp files and system temp files should be + // deleted // regardless of age (when maxAgeMillis is 0) - assertTrue(deletedFiles.contains(ourTempFile), "Our temp file should be deleted in container mode"); - assertTrue(deletedFiles.contains(sysTempFile), "System temp file should be deleted in container mode"); + assertTrue( + deletedFiles.contains(ourTempFile), + "Our temp file should be deleted in container mode"); + assertTrue( + deletedFiles.contains(sysTempFile), + "System temp file should be deleted in container mode"); assertFalse(deletedFiles.contains(regularFile), "Regular file should be preserved"); } } @@ -303,7 +338,8 @@ public class TempFileCleanupServiceTest { // Use MockedStatic to mock Files operations try (MockedStatic mockedFiles = mockStatic(Files.class)) { // Mock Files.list for systemTempDir - mockedFiles.when(() -> Files.list(eq(systemTempDir))) + mockedFiles + .when(() -> Files.list(eq(systemTempDir))) .thenReturn(Stream.of(emptyFile, recentEmptyFile)); // Configure Files.isDirectory @@ -313,39 +349,46 @@ public class TempFileCleanupServiceTest { mockedFiles.when(() -> Files.exists(any(Path.class))).thenReturn(true); // Configure Files.getLastModifiedTime to return different times based on file names - mockedFiles.when(() -> Files.getLastModifiedTime(any(Path.class))) - .thenAnswer(invocation -> { - Path path = invocation.getArgument(0); - String fileName = path.getFileName().toString(); + mockedFiles + .when(() -> Files.getLastModifiedTime(any(Path.class))) + .thenAnswer( + invocation -> { + Path path = invocation.getArgument(0); + String fileName = path.getFileName().toString(); - if (fileName.equals("empty.tmp")) { - // More than 5 minutes old - return FileTime.fromMillis(System.currentTimeMillis() - 6 * 60 * 1000); - } else { - // Less than 5 minutes old - return FileTime.fromMillis(System.currentTimeMillis() - 2 * 60 * 1000); - } - }); + if (fileName.equals("empty.tmp")) { + // More than 5 minutes old + return FileTime.fromMillis( + System.currentTimeMillis() - 6 * 60 * 1000); + } else { + // Less than 5 minutes old + return FileTime.fromMillis( + System.currentTimeMillis() - 2 * 60 * 1000); + } + }); // Configure Files.size to return 0 for empty files - mockedFiles.when(() -> Files.size(any(Path.class))) - .thenReturn(0L); + mockedFiles.when(() -> Files.size(any(Path.class))).thenReturn(0L); // For deleteIfExists, track which files would be deleted - mockedFiles.when(() -> Files.deleteIfExists(any(Path.class))) - .thenAnswer(invocation -> { - Path path = invocation.getArgument(0); - deletedFiles.add(path); - return true; - }); + mockedFiles + .when(() -> Files.deleteIfExists(any(Path.class))) + .thenAnswer( + invocation -> { + Path path = invocation.getArgument(0); + deletedFiles.add(path); + return true; + }); // Act invokeCleanupDirectoryStreaming(systemTempDir, false, 0, 3600000); // Assert - assertTrue(deletedFiles.contains(emptyFile), + assertTrue( + deletedFiles.contains(emptyFile), "Empty file older than 5 minutes should be deleted"); - assertFalse(deletedFiles.contains(recentEmptyFile), + assertFalse( + deletedFiles.contains(recentEmptyFile), "Empty file newer than 5 minutes should not be deleted"); } } @@ -370,17 +413,13 @@ public class TempFileCleanupServiceTest { // Use MockedStatic to mock Files operations try (MockedStatic mockedFiles = mockStatic(Files.class)) { // Mock Files.list for each directory - mockedFiles.when(() -> Files.list(eq(systemTempDir))) - .thenReturn(Stream.of(dir1)); + mockedFiles.when(() -> Files.list(eq(systemTempDir))).thenReturn(Stream.of(dir1)); - mockedFiles.when(() -> Files.list(eq(dir1))) - .thenReturn(Stream.of(tempFile1, dir2)); + mockedFiles.when(() -> Files.list(eq(dir1))).thenReturn(Stream.of(tempFile1, dir2)); - mockedFiles.when(() -> Files.list(eq(dir2))) - .thenReturn(Stream.of(tempFile2, dir3)); + mockedFiles.when(() -> Files.list(eq(dir2))).thenReturn(Stream.of(tempFile2, dir3)); - mockedFiles.when(() -> Files.list(eq(dir3))) - .thenReturn(Stream.of(tempFile3)); + mockedFiles.when(() -> Files.list(eq(dir3))).thenReturn(Stream.of(tempFile3)); // Configure Files.isDirectory for each path mockedFiles.when(() -> Files.isDirectory(eq(dir1))).thenReturn(true); @@ -394,31 +433,35 @@ public class TempFileCleanupServiceTest { mockedFiles.when(() -> Files.exists(any(Path.class))).thenReturn(true); // Configure Files.getLastModifiedTime to return different times based on file names - mockedFiles.when(() -> Files.getLastModifiedTime(any(Path.class))) - .thenAnswer(invocation -> { - Path path = invocation.getArgument(0); - String fileName = path.getFileName().toString(); + mockedFiles + .when(() -> Files.getLastModifiedTime(any(Path.class))) + .thenAnswer( + invocation -> { + Path path = invocation.getArgument(0); + String fileName = path.getFileName().toString(); - if (fileName.contains("old")) { - // Old file - return FileTime.fromMillis(System.currentTimeMillis() - 5000000); - } else { - // Recent file - return FileTime.fromMillis(System.currentTimeMillis() - 60000); - } - }); + if (fileName.contains("old")) { + // Old file + return FileTime.fromMillis( + System.currentTimeMillis() - 5000000); + } else { + // Recent file + return FileTime.fromMillis(System.currentTimeMillis() - 60000); + } + }); // Configure Files.size to return normal size - mockedFiles.when(() -> Files.size(any(Path.class))) - .thenReturn(1024L); + mockedFiles.when(() -> Files.size(any(Path.class))).thenReturn(1024L); // For deleteIfExists, track which files would be deleted - mockedFiles.when(() -> Files.deleteIfExists(any(Path.class))) - .thenAnswer(invocation -> { - Path path = invocation.getArgument(0); - deletedFiles.add(path); - return true; - }); + mockedFiles + .when(() -> Files.deleteIfExists(any(Path.class))) + .thenAnswer( + invocation -> { + Path path = invocation.getArgument(0); + deletedFiles.add(path); + return true; + }); // Act invokeCleanupDirectoryStreaming(systemTempDir, false, 0, 3600000); @@ -430,14 +473,15 @@ public class TempFileCleanupServiceTest { // Assert assertFalse(deletedFiles.contains(tempFile1), "Recent temp file should be preserved"); assertFalse(deletedFiles.contains(tempFile2), "Recent temp file should be preserved"); - assertTrue(deletedFiles.contains(tempFile3), "Old temp file in nested directory should be deleted"); + assertTrue( + deletedFiles.contains(tempFile3), + "Old temp file in nested directory should be deleted"); } } - /** - * Helper method to invoke the private cleanupDirectoryStreaming method using reflection - */ - private void invokeCleanupDirectoryStreaming(Path directory, boolean containerMode, int depth, long maxAgeMillis) + /** Helper method to invoke the private cleanupDirectoryStreaming method using reflection */ + private void invokeCleanupDirectoryStreaming( + Path directory, boolean containerMode, int depth, long maxAgeMillis) throws IOException { try { // Create a consumer that tracks deleted files @@ -445,13 +489,26 @@ public class TempFileCleanupServiceTest { Consumer deleteCallback = path -> deleteCount.incrementAndGet(); // Get the method with updated signature - var method = TempFileCleanupService.class.getDeclaredMethod( - "cleanupDirectoryStreaming", - Path.class, boolean.class, int.class, long.class, boolean.class, Consumer.class); + var method = + TempFileCleanupService.class.getDeclaredMethod( + "cleanupDirectoryStreaming", + Path.class, + boolean.class, + int.class, + long.class, + boolean.class, + Consumer.class); method.setAccessible(true); // Invoke the method with appropriate parameters - method.invoke(cleanupService, directory, containerMode, depth, maxAgeMillis, false, deleteCallback); + method.invoke( + cleanupService, + directory, + containerMode, + depth, + maxAgeMillis, + false, + deleteCallback); } catch (Exception e) { throw new RuntimeException("Error invoking cleanupDirectoryStreaming", e); } diff --git a/app/common/src/test/java/stirling/software/common/util/CheckProgramInstallTest.java b/app/common/src/test/java/stirling/software/common/util/CheckProgramInstallTest.java index 17723a5e4..ae8132618 100644 --- a/app/common/src/test/java/stirling/software/common/util/CheckProgramInstallTest.java +++ b/app/common/src/test/java/stirling/software/common/util/CheckProgramInstallTest.java @@ -1,14 +1,5 @@ package stirling.software.common.util; -import java.io.IOException; -import java.lang.reflect.Field; -import java.util.Arrays; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; @@ -19,6 +10,18 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.Arrays; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult; + class CheckProgramInstallTest { private MockedStatic mockProcessExecutor; diff --git a/app/common/src/test/java/stirling/software/common/util/CustomHtmlSanitizerTest.java b/app/common/src/test/java/stirling/software/common/util/CustomHtmlSanitizerTest.java index 7df293459..eaf992f71 100644 --- a/app/common/src/test/java/stirling/software/common/util/CustomHtmlSanitizerTest.java +++ b/app/common/src/test/java/stirling/software/common/util/CustomHtmlSanitizerTest.java @@ -23,15 +23,19 @@ class CustomHtmlSanitizerTest { @BeforeEach void setUp() { SsrfProtectionService mockSsrfProtectionService = mock(SsrfProtectionService.class); - stirling.software.common.model.ApplicationProperties mockApplicationProperties = mock(stirling.software.common.model.ApplicationProperties.class); - stirling.software.common.model.ApplicationProperties.System mockSystem = mock(stirling.software.common.model.ApplicationProperties.System.class); + stirling.software.common.model.ApplicationProperties mockApplicationProperties = + mock(stirling.software.common.model.ApplicationProperties.class); + stirling.software.common.model.ApplicationProperties.System mockSystem = + mock(stirling.software.common.model.ApplicationProperties.System.class); // Allow all URLs by default for basic tests - when(mockSsrfProtectionService.isUrlAllowed(org.mockito.ArgumentMatchers.anyString())).thenReturn(true); + when(mockSsrfProtectionService.isUrlAllowed(org.mockito.ArgumentMatchers.anyString())) + .thenReturn(true); when(mockApplicationProperties.getSystem()).thenReturn(mockSystem); when(mockSystem.getDisableSanitize()).thenReturn(false); // Enable sanitization for tests - customHtmlSanitizer = new CustomHtmlSanitizer(mockSsrfProtectionService, mockApplicationProperties); + customHtmlSanitizer = + new CustomHtmlSanitizer(mockSsrfProtectionService, mockApplicationProperties); } @ParameterizedTest diff --git a/app/common/src/test/java/stirling/software/common/util/EmlToPdfTest.java b/app/common/src/test/java/stirling/software/common/util/EmlToPdfTest.java index 18ebf5b2d..952bc692a 100644 --- a/app/common/src/test/java/stirling/software/common/util/EmlToPdfTest.java +++ b/app/common/src/test/java/stirling/software/common/util/EmlToPdfTest.java @@ -1,5 +1,18 @@ package stirling.software.common.util; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -7,12 +20,7 @@ import java.util.Base64; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -20,22 +28,13 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyString; import org.mockito.Mock; import org.mockito.MockedStatic; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import org.mockito.junit.jupiter.MockitoExtension; -import org.junit.jupiter.api.BeforeEach; import stirling.software.common.model.api.converters.EmlToPdfRequest; import stirling.software.common.service.CustomPDFDocumentFactory; import stirling.software.common.service.SsrfProtectionService; -import stirling.software.common.util.CustomHtmlSanitizer; @DisplayName("EML to PDF Conversion tests") class EmlToPdfTest { @@ -45,21 +44,29 @@ class EmlToPdfTest { @BeforeEach void setUp() { SsrfProtectionService mockSsrfProtectionService = mock(SsrfProtectionService.class); - stirling.software.common.model.ApplicationProperties mockApplicationProperties = mock(stirling.software.common.model.ApplicationProperties.class); - stirling.software.common.model.ApplicationProperties.System mockSystem = mock(stirling.software.common.model.ApplicationProperties.System.class); + stirling.software.common.model.ApplicationProperties mockApplicationProperties = + mock(stirling.software.common.model.ApplicationProperties.class); + stirling.software.common.model.ApplicationProperties.System mockSystem = + mock(stirling.software.common.model.ApplicationProperties.System.class); - when(mockSsrfProtectionService.isUrlAllowed(org.mockito.ArgumentMatchers.anyString())).thenReturn(true); + when(mockSsrfProtectionService.isUrlAllowed(org.mockito.ArgumentMatchers.anyString())) + .thenReturn(true); when(mockApplicationProperties.getSystem()).thenReturn(mockSystem); when(mockSystem.getDisableSanitize()).thenReturn(false); - customHtmlSanitizer = new CustomHtmlSanitizer(mockSsrfProtectionService, mockApplicationProperties); + customHtmlSanitizer = + new CustomHtmlSanitizer(mockSsrfProtectionService, mockApplicationProperties); } - // Focus on testing EML to HTML conversion functionality since the PDF conversion relies on WeasyPrint + // Focus on testing EML to HTML conversion functionality since the PDF conversion relies on + // WeasyPrint // But HTML to PDF conversion is also briefly tested at PdfConversionTests class. - private void testEmailConversion(String emlContent, String[] expectedContent, boolean includeAttachments) throws IOException { + private void testEmailConversion( + String emlContent, String[] expectedContent, boolean includeAttachments) + throws IOException { byte[] emlBytes = emlContent.getBytes(StandardCharsets.UTF_8); - EmlToPdfRequest request = includeAttachments ? createRequestWithAttachments() : createBasicRequest(); + EmlToPdfRequest request = + includeAttachments ? createRequestWithAttachments() : createBasicRequest(); String htmlResult = EmlToPdf.convertEmlToHtml(emlBytes, request); @@ -75,19 +82,23 @@ class EmlToPdfTest { @Test @DisplayName("Should parse simple text email correctly") void parseSimpleTextEmail() throws IOException { - String emlContent = createSimpleTextEmail( - "sender@example.com", - "recipient@example.com", - "Simple Test Subject", - "This is a simple plain text email body."); + String emlContent = + createSimpleTextEmail( + "sender@example.com", + "recipient@example.com", + "Simple Test Subject", + "This is a simple plain text email body."); - testEmailConversion(emlContent, new String[] { - "Simple Test Subject", - "sender@example.com", - "recipient@example.com", - "This is a simple plain text email body", - "" - }, false); + testEmailConversion( + emlContent, + new String[] { + "Simple Test Subject", + "sender@example.com", + "recipient@example.com", + "This is a simple plain text email body", + "" + }, + false); } @Test @@ -103,47 +114,51 @@ class EmlToPdfTest { assertNotNull(htmlResult); assertTrue(htmlResult.contains("sender@example.com")); assertTrue(htmlResult.contains("This is an email body")); - assertTrue(htmlResult.contains("") || - htmlResult.contains("No Subject")); + assertTrue( + htmlResult.contains("") + || htmlResult.contains("No Subject")); } @Test @DisplayName("Should parse HTML email with styling") void parseHtmlEmailWithStyling() throws IOException { - String htmlBody = "" + - "
Important Notice
" + - "
This is HTML content with styling.
" + - "
Best regards
"; + String htmlBody = + "" + + "
Important Notice
" + + "
This is HTML content with styling.
" + + "
Best regards
"; - String emlContent = createHtmlEmail( - "html@example.com", "user@example.com", "HTML Email Test", htmlBody); + String emlContent = + createHtmlEmail( + "html@example.com", "user@example.com", "HTML Email Test", htmlBody); - testEmailConversion(emlContent, new String[] { - "HTML Email Test", - "Important Notice", - "HTML content", - "font-weight: bold" - }, false); + testEmailConversion( + emlContent, + new String[] { + "HTML Email Test", "Important Notice", "HTML content", "font-weight: bold" + }, + false); } @Test @DisplayName("Should parse multipart email with attachments") void parseMultipartEmailWithAttachments() throws IOException { String boundary = "----=_Part_" + getTimestamp(); - String emlContent = createMultipartEmailWithAttachment( - "multipart@example.com", - "user@example.com", - "Multipart Email Test", - "This email has both text content and an attachment.", - boundary, - "document.txt", - "Sample attachment content"); + String emlContent = + createMultipartEmailWithAttachment( + "multipart@example.com", + "user@example.com", + "Multipart Email Test", + "This email has both text content and an attachment.", + boundary, + "document.txt", + "Sample attachment content"); - testEmailConversion(emlContent, new String[] { - "Multipart Email Test", - "This email has both text content" - }, true); + testEmailConversion( + emlContent, + new String[] {"Multipart Email Test", "This email has both text content"}, + true); } } @@ -155,39 +170,41 @@ class EmlToPdfTest { @DisplayName("Should handle international characters and UTF-8") void handleInternationalCharacters() throws IOException { String bodyWithIntlChars = "Hello! 你好 Привет مرحبا Hëllö Thañks! Önë Mörë"; - String emlContent = createSimpleTextEmail( - "intl@example.com", - "user@example.com", - "International Characters Test", - bodyWithIntlChars); + String emlContent = + createSimpleTextEmail( + "intl@example.com", + "user@example.com", + "International Characters Test", + bodyWithIntlChars); - testEmailConversion(emlContent, new String[] { - "你好", "Привет", "مرحبا", "Hëllö", "Önë", "Mörë" - }, false); + testEmailConversion( + emlContent, + new String[] {"你好", "Привет", "مرحبا", "Hëllö", "Önë", "Mörë"}, + false); } @Test @DisplayName("Should decode quoted-printable content correctly") void decodeQuotedPrintableContent() throws IOException { - String content = createQuotedPrintableEmail( - ); + String content = createQuotedPrintableEmail(); - testEmailConversion(content, new String[] { - "Quoted-Printable Test", - "This is quoted printable content with special chars: éàè." - }, false); + testEmailConversion( + content, + new String[] { + "Quoted-Printable Test", + "This is quoted printable content with special chars: éàè." + }, + false); } @Test @DisplayName("Should decode Base64 content") void decodeBase64Content() throws IOException { String originalText = "This is Base64 encoded content: éàü ñ"; - String content = createBase64Email( - originalText); + String content = createBase64Email(originalText); - testEmailConversion(content, new String[] { - "Base64 Test", "Base64 encoded content" - }, false); + testEmailConversion( + content, new String[] {"Base64 Test", "Base64 encoded content"}, false); } @Test @@ -195,8 +212,12 @@ class EmlToPdfTest { void handleInlineImages() throws IOException { String boundary = "----=_Part_CID_1234567890"; String cid = "image123@example.com"; - String htmlBody = "

Here is an image:

"; - String imageBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="; + String htmlBody = + "

Here is an image:

"; + String imageBase64 = + "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="; String emlContent = createEmailWithInlineImage(htmlBody, boundary, cid, imageBase64); @@ -218,15 +239,17 @@ class EmlToPdfTest { @Test @DisplayName("Should generate valid HTML structure") void generateValidHtmlStructure() throws IOException { - String emlContent = createSimpleTextEmail( - "structure@test.com", - "user@test.com", - "HTML Structure Test", - "Testing HTML structure output"); + String emlContent = + createSimpleTextEmail( + "structure@test.com", + "user@test.com", + "HTML Structure Test", + "Testing HTML structure output"); - testEmailConversion(emlContent, new String[] { - "", "", "HTML Structure Test" - }, false); + testEmailConversion( + emlContent, + new String[] {"", "", "HTML Structure Test"}, + false); byte[] emlBytes = emlContent.getBytes(StandardCharsets.UTF_8); String htmlResult = EmlToPdf.convertEmlToHtml(emlBytes, createBasicRequest()); @@ -236,17 +259,19 @@ class EmlToPdfTest { @Test @DisplayName("Should preserve safe CSS and remove problematic styles") void handleCssStylesCorrectly() throws IOException { - String styledHtml = "" + - "
Safe styling
" + - "
Problematic styling
" + - "
Good styling
" + - ""; + String styledHtml = + "" + + "
Safe styling
" + + "
Problematic styling
" + + "
Good styling
" + + ""; - String emlContent = createHtmlEmail("css@test.com", "user@test.com", "CSS Test", styledHtml); + String emlContent = + createHtmlEmail("css@test.com", "user@test.com", "CSS Test", styledHtml); byte[] emlBytes = emlContent.getBytes(StandardCharsets.UTF_8); EmlToPdfRequest request = createBasicRequest(); @@ -264,19 +289,22 @@ class EmlToPdfTest { @Test @DisplayName("Should handle complex nested HTML structures") void handleComplexNestedHtml() throws IOException { - String complexHtml = "Complex Email" + - "

Email Header

" + - "

Paragraph with link

    " + - "
  • List item 1
  • List item 2 with emphasis
" + - "" + - "
Cell 1Cell 2
Cell 3Cell 4
"; + String complexHtml = + "Complex Email" + + "

Email Header

" + + "

Paragraph with link

    " + + "
  • List item 1
  • List item 2 with emphasis
" + + "" + + "
Cell 1Cell 2
Cell 3Cell 4
"; - String emlContent = createHtmlEmail( - "complex@test.com", "user@test.com", "Complex HTML Test", complexHtml); + String emlContent = + createHtmlEmail( + "complex@test.com", "user@test.com", "Complex HTML Test", complexHtml); - testEmailConversion(emlContent, new String[] { - "Email Header", "List item 2", "Cell 3", "example.com" - }, false); + testEmailConversion( + emlContent, + new String[] {"Email Header", "List item 2", "Cell 3", "example.com"}, + false); byte[] emlBytes = emlContent.getBytes(StandardCharsets.UTF_8); String htmlResult = EmlToPdf.convertEmlToHtml(emlBytes, createBasicRequest()); @@ -293,9 +321,10 @@ class EmlToPdfTest { void rejectNullInput() { EmlToPdfRequest request = createBasicRequest(); - Exception exception = assertThrows( - IllegalArgumentException.class, - () -> EmlToPdf.convertEmlToHtml(null, request)); + Exception exception = + assertThrows( + IllegalArgumentException.class, + () -> EmlToPdf.convertEmlToHtml(null, request)); assertTrue(exception.getMessage().contains("EML file is empty or null")); } @@ -304,16 +333,18 @@ class EmlToPdfTest { void rejectEmptyInput() { EmlToPdfRequest request = createBasicRequest(); - Exception exception = assertThrows( - IllegalArgumentException.class, - () -> EmlToPdf.convertEmlToHtml(new byte[0], request)); + Exception exception = + assertThrows( + IllegalArgumentException.class, + () -> EmlToPdf.convertEmlToHtml(new byte[0], request)); assertTrue(exception.getMessage().contains("EML file is empty or null")); } @Test @DisplayName("Should handle malformed EML gracefully") void handleMalformedEmlGracefully() { - String malformedEml = """ + String malformedEml = + """ From: sender@test.com Subject: Malformed EML This line breaks header format @@ -337,12 +368,14 @@ class EmlToPdfTest { @Test @DisplayName("Should reject invalid EML format") void rejectInvalidEmlFormat() { - byte[] invalidEml = "This is definitely not an EML file".getBytes(StandardCharsets.UTF_8); + byte[] invalidEml = + "This is definitely not an EML file".getBytes(StandardCharsets.UTF_8); EmlToPdfRequest request = createBasicRequest(); - Exception exception = assertThrows( - IllegalArgumentException.class, - () -> EmlToPdf.convertEmlToHtml(invalidEml, request)); + Exception exception = + assertThrows( + IllegalArgumentException.class, + () -> EmlToPdf.convertEmlToHtml(invalidEml, request)); assertTrue(exception.getMessage().contains("Invalid EML file format")); } } @@ -354,20 +387,22 @@ class EmlToPdfTest { @Test @DisplayName("Should successfully parse email using advanced parser") void initializeDependencyMailSession() { - assertDoesNotThrow(() -> { - String emlContent = createSimpleTextEmail( - "Dependency@test.com", - "user@test.com", - "Dependency Mail Test", - "Testing Dependency Mail integration."); + assertDoesNotThrow( + () -> { + String emlContent = + createSimpleTextEmail( + "Dependency@test.com", + "user@test.com", + "Dependency Mail Test", + "Testing Dependency Mail integration."); - byte[] emlBytes = emlContent.getBytes(StandardCharsets.UTF_8); - EmlToPdfRequest request = createBasicRequest(); + byte[] emlBytes = emlContent.getBytes(StandardCharsets.UTF_8); + EmlToPdfRequest request = createBasicRequest(); - String htmlResult = EmlToPdf.convertEmlToHtml(emlBytes, request); - assertNotNull(htmlResult); - assertTrue(htmlResult.contains("Dependency Mail Test")); - }); + String htmlResult = EmlToPdf.convertEmlToHtml(emlBytes, request); + assertNotNull(htmlResult); + assertTrue(htmlResult.contains("Dependency Mail Test")); + }); } @Test @@ -397,18 +432,20 @@ class EmlToPdfTest { @DisplayName("Should handle email with only an attachment and no body") void handleAttachmentOnlyEmail() throws IOException { String boundary = "----=_Part_AttachmentOnly_1234567890"; - String emlContent = createMultipartEmailWithAttachment( - "sender@example.com", - "recipient@example.com", - "Attachment Only Test", - "", - boundary, - "data.bin", - "binary data"); + String emlContent = + createMultipartEmailWithAttachment( + "sender@example.com", + "recipient@example.com", + "Attachment Only Test", + "", + boundary, + "data.bin", + "binary data"); - testEmailConversion(emlContent, new String[] { - "Attachment Only Test", "data.bin", "No content available" - }, true); + testEmailConversion( + emlContent, + new String[] {"Attachment Only Test", "data.bin", "No content available"}, + true); } @Test @@ -417,11 +454,13 @@ class EmlToPdfTest { String boundary = "----=_Part_MixedAttachments_1234567890"; String cid = "inline_image@example.com"; String htmlBody = ""; - String imageBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR42mNkAAIAAAoAAb6A/yoAAAAASUVORK5CYII="; + String imageBase64 = + "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR42mNkAAIAAAoAAb6A/yoAAAAASUVORK5CYII="; String attachmentText = "This is a text attachment."; - String emlContent = createEmailWithMixedAttachments( - htmlBody, boundary, cid, imageBase64, attachmentText); + String emlContent = + createEmailWithMixedAttachments( + htmlBody, boundary, cid, imageBase64, attachmentText); byte[] emlBytes = emlContent.getBytes(StandardCharsets.UTF_8); EmlToPdfRequest request = createRequestWithAttachments(); @@ -439,12 +478,13 @@ class EmlToPdfTest { String subject = "Subject with special characters: ñ é ü"; String body = "Body with special characters: ñ é ü"; - String emlContent = createSimpleTextEmailWithCharset( - "sender@example.com", - "recipient@example.com", - subject, - body, - "ISO-8859-1"); + String emlContent = + createSimpleTextEmailWithCharset( + "sender@example.com", + "recipient@example.com", + subject, + body, + "ISO-8859-1"); byte[] emlBytes = emlContent.getBytes(StandardCharsets.ISO_8859_1); EmlToPdfRequest request = createBasicRequest(); @@ -464,36 +504,40 @@ class EmlToPdfTest { longLine.append("word").append(i).append(" "); } - String emlContent = createSimpleTextEmail( - "sender@example.com", - "recipient@example.com", - "Long Line Test", - longLine.toString()); + String emlContent = + createSimpleTextEmail( + "sender@example.com", + "recipient@example.com", + "Long Line Test", + longLine.toString()); - testEmailConversion(emlContent, new String[] { - "Long Line Test", "This is a very long line", "word999" - }, false); + testEmailConversion( + emlContent, + new String[] {"Long Line Test", "This is a very long line", "word999"}, + false); } @Test @DisplayName("Should handle .eml files as attachments") void handleEmlAttachment() throws IOException { String boundary = "----=_Part_EmlAttachment_1234567890"; - String innerEmlContent = createSimpleTextEmail( - "inner@example.com", - "inner_recipient@example.com", - "Inner Email Subject", - "This is the body of the attached email."); + String innerEmlContent = + createSimpleTextEmail( + "inner@example.com", + "inner_recipient@example.com", + "Inner Email Subject", + "This is the body of the attached email."); - String emlContent = createEmailWithEmlAttachment( - boundary, - innerEmlContent); + String emlContent = createEmailWithEmlAttachment(boundary, innerEmlContent); - testEmailConversion(emlContent, new String[] { - "Fwd: Inner Email Subject", - "Please see the attached email.", - "attached_email.eml" - }, true); + testEmailConversion( + emlContent, + new String[] { + "Fwd: Inner Email Subject", + "Please see the attached email.", + "attached_email.eml" + }, + true); } @ParameterizedTest @@ -503,12 +547,9 @@ class EmlToPdfTest { String subject = "Encoding Test"; String body = "Testing " + charset + " encoding"; - String emlContent = createSimpleTextEmailWithCharset( - "sender@example.com", - "recipient@example.com", - subject, - body, - charset); + String emlContent = + createSimpleTextEmailWithCharset( + "sender@example.com", "recipient@example.com", subject, body, charset); testEmailConversion(emlContent, new String[] {subject, body}, false); } @@ -530,7 +571,7 @@ class EmlToPdfTest { @DisplayName("Should convert EML to PDF without attachments when not requested") void convertEmlToPdfWithoutAttachments() throws Exception { String emlContent = - createSimpleTextEmail("from@test.com", "to@test.com", "Subject", "Body"); + createSimpleTextEmail("from@test.com", "to@test.com", "Subject", "Body"); byte[] emlBytes = emlContent.getBytes(StandardCharsets.UTF_8); EmlToPdfRequest request = createBasicRequest(); @@ -544,28 +585,29 @@ class EmlToPdfTest { when(mockPdfDocumentFactory.load(any(byte[].class))).thenReturn(mockPdDocument); when(mockPdDocument.getNumberOfPages()).thenReturn(1); - try (MockedStatic fileToPdf = mockStatic(FileToPdf.class, org.mockito.Mockito.withSettings().lenient())) { + try (MockedStatic fileToPdf = + mockStatic(FileToPdf.class, org.mockito.Mockito.withSettings().lenient())) { fileToPdf - .when( - () -> - FileToPdf.convertHtmlToPdf( - anyString(), - any(), - any(byte[].class), - anyString(), - any(TempFileManager.class), - any(CustomHtmlSanitizer.class))) - .thenReturn(fakePdfBytes); + .when( + () -> + FileToPdf.convertHtmlToPdf( + anyString(), + any(), + any(byte[].class), + anyString(), + any(TempFileManager.class), + any(CustomHtmlSanitizer.class))) + .thenReturn(fakePdfBytes); byte[] resultPdf = - EmlToPdf.convertEmlToPdf( - "weasyprint", - request, - emlBytes, - "test.eml", - mockPdfDocumentFactory, - mockTempFileManager, - customHtmlSanitizer); + EmlToPdf.convertEmlToPdf( + "weasyprint", + request, + emlBytes, + "test.eml", + mockPdfDocumentFactory, + mockTempFileManager, + customHtmlSanitizer); assertArrayEquals(fakePdfBytes, resultPdf); @@ -575,14 +617,14 @@ class EmlToPdfTest { } fileToPdf.verify( - () -> - FileToPdf.convertHtmlToPdf( - anyString(), - any(), - any(byte[].class), - anyString(), - any(TempFileManager.class), - any(CustomHtmlSanitizer.class))); + () -> + FileToPdf.convertHtmlToPdf( + anyString(), + any(), + any(byte[].class), + anyString(), + any(TempFileManager.class), + any(CustomHtmlSanitizer.class))); verify(mockPdfDocumentFactory).load(resultPdf); } } @@ -592,14 +634,15 @@ class EmlToPdfTest { @DisplayName("Should convert EML to PDF with attachments when requested") void convertEmlToPdfWithAttachments() throws Exception { String boundary = "----=_Part_1234567890"; - String emlContent = createMultipartEmailWithAttachment( - "multipart@example.com", - "user@example.com", - "Multipart Email Test", - "This email has both text content and an attachment.", - boundary, - "document.txt", - "Sample attachment content"); + String emlContent = + createMultipartEmailWithAttachment( + "multipart@example.com", + "user@example.com", + "Multipart Email Test", + "This email has both text content and an attachment.", + boundary, + "document.txt", + "Sample attachment content"); byte[] emlBytes = emlContent.getBytes(StandardCharsets.UTF_8); EmlToPdfRequest request = createRequestWithAttachments(); @@ -613,39 +656,40 @@ class EmlToPdfTest { when(mockPdfDocumentFactory.load(any(byte[].class))).thenReturn(mockPdDocument); when(mockPdDocument.getNumberOfPages()).thenReturn(1); - try (MockedStatic fileToPdf = mockStatic(FileToPdf.class, org.mockito.Mockito.withSettings().lenient())) { + try (MockedStatic fileToPdf = + mockStatic(FileToPdf.class, org.mockito.Mockito.withSettings().lenient())) { fileToPdf - .when( - () -> - FileToPdf.convertHtmlToPdf( - anyString(), - any(), - any(byte[].class), - anyString(), - any(TempFileManager.class), - any(CustomHtmlSanitizer.class))) - .thenReturn(fakePdfBytes); + .when( + () -> + FileToPdf.convertHtmlToPdf( + anyString(), + any(), + any(byte[].class), + anyString(), + any(TempFileManager.class), + any(CustomHtmlSanitizer.class))) + .thenReturn(fakePdfBytes); try (MockedStatic ignored = - mockStatic( - EmlToPdf.class, - invocation -> { - String methodName = invocation.getMethod().getName(); - return switch (methodName) { - case "shouldAttachFiles" -> true; - case "attachFilesToPdf" -> fakePdfBytes; - default -> invocation.callRealMethod(); - }; - })) { + mockStatic( + EmlToPdf.class, + invocation -> { + String methodName = invocation.getMethod().getName(); + return switch (methodName) { + case "shouldAttachFiles" -> true; + case "attachFilesToPdf" -> fakePdfBytes; + default -> invocation.callRealMethod(); + }; + })) { byte[] resultPdf = - EmlToPdf.convertEmlToPdf( - "weasyprint", - request, - emlBytes, - "test.eml", - mockPdfDocumentFactory, - mockTempFileManager, - customHtmlSanitizer); + EmlToPdf.convertEmlToPdf( + "weasyprint", + request, + emlBytes, + "test.eml", + mockPdfDocumentFactory, + mockTempFileManager, + customHtmlSanitizer); assertArrayEquals(fakePdfBytes, resultPdf); @@ -655,14 +699,14 @@ class EmlToPdfTest { } fileToPdf.verify( - () -> - FileToPdf.convertHtmlToPdf( - anyString(), - any(), - any(byte[].class), - anyString(), - any(TempFileManager.class), - any(CustomHtmlSanitizer.class))); + () -> + FileToPdf.convertHtmlToPdf( + anyString(), + any(), + any(byte[].class), + anyString(), + any(TempFileManager.class), + any(CustomHtmlSanitizer.class))); verify(mockPdfDocumentFactory).load(resultPdf); } @@ -674,34 +718,37 @@ class EmlToPdfTest { @DisplayName("Should handle errors during EML to PDF conversion") void handleErrorsDuringConversion() { String emlContent = - createSimpleTextEmail("from@test.com", "to@test.com", "Subject", "Body"); + createSimpleTextEmail("from@test.com", "to@test.com", "Subject", "Body"); byte[] emlBytes = emlContent.getBytes(StandardCharsets.UTF_8); EmlToPdfRequest request = createBasicRequest(); String errorMessage = "Conversion failed"; - try (MockedStatic fileToPdf = mockStatic(FileToPdf.class, org.mockito.Mockito.withSettings().lenient())) { + try (MockedStatic fileToPdf = + mockStatic(FileToPdf.class, org.mockito.Mockito.withSettings().lenient())) { fileToPdf - .when( - () -> - FileToPdf.convertHtmlToPdf( - anyString(), - any(), - any(byte[].class), - anyString(), - any(TempFileManager.class), - any(CustomHtmlSanitizer.class))) - .thenThrow(new IOException(errorMessage)); + .when( + () -> + FileToPdf.convertHtmlToPdf( + anyString(), + any(), + any(byte[].class), + anyString(), + any(TempFileManager.class), + any(CustomHtmlSanitizer.class))) + .thenThrow(new IOException(errorMessage)); - IOException exception = assertThrows( - IOException.class, - () -> EmlToPdf.convertEmlToPdf( - "weasyprint", - request, - emlBytes, - "test.eml", - mockPdfDocumentFactory, - mockTempFileManager, - customHtmlSanitizer)); + IOException exception = + assertThrows( + IOException.class, + () -> + EmlToPdf.convertEmlToPdf( + "weasyprint", + request, + emlBytes, + "test.eml", + mockPdfDocumentFactory, + mockTempFileManager, + customHtmlSanitizer)); assertTrue(exception.getMessage().contains(errorMessage)); } @@ -710,36 +757,47 @@ class EmlToPdfTest { // Helper methods private String getTimestamp() { - java.time.ZonedDateTime fixedDateTime = java.time.ZonedDateTime.of(2023, 1, 1, 12, 0, 0, 0, java.time.ZoneId.of("GMT")); + java.time.ZonedDateTime fixedDateTime = + java.time.ZonedDateTime.of(2023, 1, 1, 12, 0, 0, 0, java.time.ZoneId.of("GMT")); return java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME.format(fixedDateTime); } + private String createSimpleTextEmail(String from, String to, String subject, String body) { return createSimpleTextEmailWithCharset(from, to, subject, body, "UTF-8"); } - private String createSimpleTextEmailWithCharset(String from, String to, String subject, String body, String charset) { + private String createSimpleTextEmailWithCharset( + String from, String to, String subject, String body, String charset) { return String.format( - "From: %s\nTo: %s\nSubject: %s\nDate: %s\nContent-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n%s", - from, to, subject, getTimestamp(), charset, body); + "From: %s\nTo: %s\nSubject: %s\nDate: %s\nContent-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n%s", + from, to, subject, getTimestamp(), charset, body); } private String createEmailWithCustomHeaders() { return String.format( - "From: sender@example.com\nDate: %s\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit\n\n%s", - getTimestamp(), "This is an email body with some headers missing."); + "From: sender@example.com\nDate: %s\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit\n\n%s", + getTimestamp(), "This is an email body with some headers missing."); } private String createHtmlEmail(String from, String to, String subject, String htmlBody) { return String.format( - "From: %s\nTo: %s\nSubject: %s\nDate: %s\nContent-Type: text/html; charset=UTF-8\nContent-Transfer-Encoding: 8bit\n\n%s", - from, to, subject, getTimestamp(), htmlBody); + "From: %s\nTo: %s\nSubject: %s\nDate: %s\nContent-Type: text/html; charset=UTF-8\nContent-Transfer-Encoding: 8bit\n\n%s", + from, to, subject, getTimestamp(), htmlBody); } - private String createMultipartEmailWithAttachment(String from, String to, String subject, String body, - String boundary, String filename, String attachmentContent) { - String encodedContent = Base64.getEncoder().encodeToString(attachmentContent.getBytes(StandardCharsets.UTF_8)); + private String createMultipartEmailWithAttachment( + String from, + String to, + String subject, + String body, + String boundary, + String filename, + String attachmentContent) { + String encodedContent = + Base64.getEncoder() + .encodeToString(attachmentContent.getBytes(StandardCharsets.UTF_8)); return String.format( - """ + """ From: %s To: %s Subject: %s @@ -760,13 +818,25 @@ class EmlToPdfTest { %s --%s--""", - from, to, subject, getTimestamp(), boundary, boundary, body, boundary, filename, encodedContent, boundary); + from, + to, + subject, + getTimestamp(), + boundary, + boundary, + body, + boundary, + filename, + encodedContent, + boundary); } private String createEmailWithEmlAttachment(String boundary, String attachmentEmlContent) { - String encodedContent = Base64.getEncoder().encodeToString(attachmentEmlContent.getBytes(StandardCharsets.UTF_8)); + String encodedContent = + Base64.getEncoder() + .encodeToString(attachmentEmlContent.getBytes(StandardCharsets.UTF_8)); return String.format( - """ + """ From: %s To: %s Subject: %s @@ -787,12 +857,24 @@ class EmlToPdfTest { %s --%s--""", - "outer@example.com", "outer_recipient@example.com", "Fwd: Inner Email Subject", getTimestamp(), boundary, boundary, "Please see the attached email.", boundary, "attached_email.eml", "attached_email.eml", encodedContent, boundary); + "outer@example.com", + "outer_recipient@example.com", + "Fwd: Inner Email Subject", + getTimestamp(), + boundary, + boundary, + "Please see the attached email.", + boundary, + "attached_email.eml", + "attached_email.eml", + encodedContent, + boundary); } - private String createMultipartAlternativeEmail(String textBody, String htmlBody, String boundary) { + private String createMultipartAlternativeEmail( + String textBody, String htmlBody, String boundary) { return String.format( - """ + """ From: %s To: %s Subject: %s @@ -813,26 +895,44 @@ class EmlToPdfTest { %s --%s--""", - "sender@example.com", "receiver@example.com", "Multipart/Alternative Test", getTimestamp(), - boundary, boundary, textBody, boundary, htmlBody, boundary); + "sender@example.com", + "receiver@example.com", + "Multipart/Alternative Test", + getTimestamp(), + boundary, + boundary, + textBody, + boundary, + htmlBody, + boundary); } private String createQuotedPrintableEmail() { return String.format( - "From: %s\nTo: %s\nSubject: %s\nDate: %s\nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: quoted-printable\n\n%s", - "sender@example.com", "recipient@example.com", "Quoted-Printable Test", getTimestamp(), "This is quoted=20printable content with special chars: =C3=A9=C3=A0=C3=A8."); + "From: %s\nTo: %s\nSubject: %s\nDate: %s\nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: quoted-printable\n\n%s", + "sender@example.com", + "recipient@example.com", + "Quoted-Printable Test", + getTimestamp(), + "This is quoted=20printable content with special chars: =C3=A9=C3=A0=C3=A8."); } private String createBase64Email(String body) { - String encodedBody = Base64.getEncoder().encodeToString(body.getBytes(StandardCharsets.UTF_8)); + String encodedBody = + Base64.getEncoder().encodeToString(body.getBytes(StandardCharsets.UTF_8)); return String.format( - "From: %s\nTo: %s\nSubject: %s\nDate: %s\nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: base64\n\n%s", - "sender@example.com", "recipient@example.com", "Base64 Test", getTimestamp(), encodedBody); + "From: %s\nTo: %s\nSubject: %s\nDate: %s\nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: base64\n\n%s", + "sender@example.com", + "recipient@example.com", + "Base64 Test", + getTimestamp(), + encodedBody); } - private String createEmailWithInlineImage(String htmlBody, String boundary, String contentId, String base64Image) { + private String createEmailWithInlineImage( + String htmlBody, String boundary, String contentId, String base64Image) { return String.format( - """ + """ From: %s To: %s Subject: %s @@ -854,15 +954,29 @@ class EmlToPdfTest { %s --%s--""", - "sender@example.com", "receiver@example.com", "Inline Image Test", getTimestamp(), - boundary, boundary, htmlBody, boundary, contentId, base64Image, boundary); + "sender@example.com", + "receiver@example.com", + "Inline Image Test", + getTimestamp(), + boundary, + boundary, + htmlBody, + boundary, + contentId, + base64Image, + boundary); } - private String createEmailWithMixedAttachments(String htmlBody, String boundary, String contentId, - String base64Image, String attachmentBody) { - String encodedAttachment = Base64.getEncoder().encodeToString(attachmentBody.getBytes(StandardCharsets.UTF_8)); + private String createEmailWithMixedAttachments( + String htmlBody, + String boundary, + String contentId, + String base64Image, + String attachmentBody) { + String encodedAttachment = + Base64.getEncoder().encodeToString(attachmentBody.getBytes(StandardCharsets.UTF_8)); return String.format( - """ + """ From: %s To: %s Subject: %s @@ -896,10 +1010,25 @@ class EmlToPdfTest { %s --%s--""", - "sender@example.com", "receiver@example.com", "Mixed Attachments Test", getTimestamp(), - boundary, boundary, boundary, boundary, htmlBody, boundary, contentId, base64Image, boundary, - boundary, "text.txt", encodedAttachment, boundary); + "sender@example.com", + "receiver@example.com", + "Mixed Attachments Test", + getTimestamp(), + boundary, + boundary, + boundary, + boundary, + htmlBody, + boundary, + contentId, + base64Image, + boundary, + boundary, + "text.txt", + encodedAttachment, + boundary); } + // Creates a basic EmlToPdfRequest with default settings private EmlToPdfRequest createBasicRequest() { EmlToPdfRequest request = new EmlToPdfRequest(); diff --git a/app/common/src/test/java/stirling/software/common/util/FileMonitorTest.java b/app/common/src/test/java/stirling/software/common/util/FileMonitorTest.java index 0a0ff107a..b7d59eab8 100644 --- a/app/common/src/test/java/stirling/software/common/util/FileMonitorTest.java +++ b/app/common/src/test/java/stirling/software/common/util/FileMonitorTest.java @@ -19,6 +19,7 @@ import org.junit.jupiter.api.io.TempDir; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; + import stirling.software.common.configuration.RuntimePathConfig; @ExtendWith(MockitoExtension.class) diff --git a/app/common/src/test/java/stirling/software/common/util/FileToPdfTest.java b/app/common/src/test/java/stirling/software/common/util/FileToPdfTest.java index 38294404b..bddfad0f7 100644 --- a/app/common/src/test/java/stirling/software/common/util/FileToPdfTest.java +++ b/app/common/src/test/java/stirling/software/common/util/FileToPdfTest.java @@ -1,15 +1,14 @@ package stirling.software.common.util; -import java.nio.file.Files; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.mockito.ArgumentMatchers.anyString; -import java.io.File; import java.io.IOException; +import java.nio.file.Files; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -24,14 +23,18 @@ public class FileToPdfTest { @BeforeEach void setUp() { SsrfProtectionService mockSsrfProtectionService = mock(SsrfProtectionService.class); - stirling.software.common.model.ApplicationProperties mockApplicationProperties = mock(stirling.software.common.model.ApplicationProperties.class); - stirling.software.common.model.ApplicationProperties.System mockSystem = mock(stirling.software.common.model.ApplicationProperties.System.class); + stirling.software.common.model.ApplicationProperties mockApplicationProperties = + mock(stirling.software.common.model.ApplicationProperties.class); + stirling.software.common.model.ApplicationProperties.System mockSystem = + mock(stirling.software.common.model.ApplicationProperties.System.class); - when(mockSsrfProtectionService.isUrlAllowed(org.mockito.ArgumentMatchers.anyString())).thenReturn(true); + when(mockSsrfProtectionService.isUrlAllowed(org.mockito.ArgumentMatchers.anyString())) + .thenReturn(true); when(mockApplicationProperties.getSystem()).thenReturn(mockSystem); when(mockSystem.getDisableSanitize()).thenReturn(false); - customHtmlSanitizer = new CustomHtmlSanitizer(mockSsrfProtectionService, mockApplicationProperties); + customHtmlSanitizer = + new CustomHtmlSanitizer(mockSsrfProtectionService, mockApplicationProperties); } /** @@ -48,8 +51,8 @@ public class FileToPdfTest { // Mock the temp file creation to return real temp files try { when(tempFileManager.createTempFile(anyString())) - .thenReturn(Files.createTempFile("test", ".pdf").toFile()) - .thenReturn(Files.createTempFile("test", ".html").toFile()); + .thenReturn(Files.createTempFile("test", ".pdf").toFile()) + .thenReturn(Files.createTempFile("test", ".html").toFile()); } catch (IOException e) { throw new RuntimeException(e); } @@ -60,7 +63,12 @@ public class FileToPdfTest { Exception.class, () -> FileToPdf.convertHtmlToPdf( - "/path/", request, fileBytes, fileName, tempFileManager, customHtmlSanitizer)); + "/path/", + request, + fileBytes, + fileName, + tempFileManager, + customHtmlSanitizer)); assertNotNull(thrown); } diff --git a/app/common/src/test/java/stirling/software/common/util/ProviderUtilsTest.java b/app/common/src/test/java/stirling/software/common/util/ProviderUtilsTest.java index 18dd04ead..119f3c384 100644 --- a/app/common/src/test/java/stirling/software/common/util/ProviderUtilsTest.java +++ b/app/common/src/test/java/stirling/software/common/util/ProviderUtilsTest.java @@ -1,21 +1,23 @@ package stirling.software.common.util; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import java.util.List; import java.util.stream.Stream; -import org.junit.jupiter.api.Assertions; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.mockito.junit.jupiter.MockitoExtension; + import stirling.software.common.model.enumeration.UsernameAttribute; import stirling.software.common.model.oauth2.GitHubProvider; import stirling.software.common.model.oauth2.GoogleProvider; import stirling.software.common.model.oauth2.Provider; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class ProviderUtilsTest { @@ -40,7 +42,7 @@ class ProviderUtilsTest { public static Stream providerParams() { Provider generic = null; var google = - new GoogleProvider(null, "clientSecret", List.of("scope"), UsernameAttribute.EMAIL); + new GoogleProvider(null, "clientSecret", List.of("scope"), UsernameAttribute.EMAIL); var github = new GitHubProvider("clientId", "", List.of("scope"), UsernameAttribute.LOGIN); return Stream.of(Arguments.of(generic), Arguments.of(google), Arguments.of(github)); diff --git a/app/common/src/test/java/stirling/software/common/util/SpringContextHolderTest.java b/app/common/src/test/java/stirling/software/common/util/SpringContextHolderTest.java index fe3fea769..0f53bb404 100644 --- a/app/common/src/test/java/stirling/software/common/util/SpringContextHolderTest.java +++ b/app/common/src/test/java/stirling/software/common/util/SpringContextHolderTest.java @@ -42,7 +42,6 @@ class SpringContextHolderTest { verify(mockApplicationContext).getBean(TestBean.class); } - @Test void testGetBean_ApplicationContextNotSet() { // Don't set application context @@ -58,7 +57,8 @@ class SpringContextHolderTest { void testGetBean_BeanNotFound() { // Arrange contextHolder.setApplicationContext(mockApplicationContext); - when(mockApplicationContext.getBean(TestBean.class)).thenThrow(new org.springframework.beans.BeansException("Bean not found") {}); + when(mockApplicationContext.getBean(TestBean.class)) + .thenThrow(new org.springframework.beans.BeansException("Bean not found") {}); // Act TestBean result = SpringContextHolder.getBean(TestBean.class); @@ -68,6 +68,5 @@ class SpringContextHolderTest { } // Simple test class - private static class TestBean { - } + private static class TestBean {} } diff --git a/app/common/src/test/java/stirling/software/common/util/misc/HighContrastColorReplaceDeciderTest.java b/app/common/src/test/java/stirling/software/common/util/misc/HighContrastColorReplaceDeciderTest.java index 7b01783d1..9ae3d6eb7 100644 --- a/app/common/src/test/java/stirling/software/common/util/misc/HighContrastColorReplaceDeciderTest.java +++ b/app/common/src/test/java/stirling/software/common/util/misc/HighContrastColorReplaceDeciderTest.java @@ -1,11 +1,13 @@ package stirling.software.common.util.misc; -import org.junit.jupiter.api.Test; -import stirling.software.common.model.api.misc.HighContrastColorCombination; -import stirling.software.common.model.api.misc.ReplaceAndInvert; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertNull; +import org.junit.jupiter.api.Test; + +import stirling.software.common.model.api.misc.HighContrastColorCombination; +import stirling.software.common.model.api.misc.ReplaceAndInvert; + class HighContrastColorReplaceDeciderTest { @Test diff --git a/app/common/src/test/java/stirling/software/common/util/misc/InvertFullColorStrategyTest.java b/app/common/src/test/java/stirling/software/common/util/misc/InvertFullColorStrategyTest.java index d6a4fad94..61b48e4f7 100644 --- a/app/common/src/test/java/stirling/software/common/util/misc/InvertFullColorStrategyTest.java +++ b/app/common/src/test/java/stirling/software/common/util/misc/InvertFullColorStrategyTest.java @@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test; import org.springframework.core.io.InputStreamResource; import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; + import stirling.software.common.model.api.misc.ReplaceAndInvert; class InvertFullColorStrategyTest { diff --git a/app/common/src/test/java/stirling/software/common/util/misc/ReplaceAndInvertColorStrategyTest.java b/app/common/src/test/java/stirling/software/common/util/misc/ReplaceAndInvertColorStrategyTest.java index f5520146e..0f9471773 100644 --- a/app/common/src/test/java/stirling/software/common/util/misc/ReplaceAndInvertColorStrategyTest.java +++ b/app/common/src/test/java/stirling/software/common/util/misc/ReplaceAndInvertColorStrategyTest.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.Test; import org.springframework.core.io.InputStreamResource; import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; + import stirling.software.common.model.api.misc.ReplaceAndInvert; class ReplaceAndInvertColorStrategyTest { diff --git a/app/common/src/test/java/stirling/software/common/util/propertyeditor/StringToArrayListPropertyEditorTest.java b/app/common/src/test/java/stirling/software/common/util/propertyeditor/StringToArrayListPropertyEditorTest.java index 6cdfeae62..ce1535986 100644 --- a/app/common/src/test/java/stirling/software/common/util/propertyeditor/StringToArrayListPropertyEditorTest.java +++ b/app/common/src/test/java/stirling/software/common/util/propertyeditor/StringToArrayListPropertyEditorTest.java @@ -1,14 +1,17 @@ package stirling.software.common.util.propertyeditor; -import java.util.List; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import stirling.software.common.model.api.security.RedactionArea; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import stirling.software.common.model.api.security.RedactionArea; + class StringToArrayListPropertyEditorTest { private StringToArrayListPropertyEditor editor; diff --git a/app/core/src/test/java/stirling/software/SPDF/controller/api/EditTableOfContentsControllerTest.java b/app/core/src/test/java/stirling/software/SPDF/controller/api/EditTableOfContentsControllerTest.java index c6a93c931..fc8783f73 100644 --- a/app/core/src/test/java/stirling/software/SPDF/controller/api/EditTableOfContentsControllerTest.java +++ b/app/core/src/test/java/stirling/software/SPDF/controller/api/EditTableOfContentsControllerTest.java @@ -36,14 +36,11 @@ import stirling.software.common.service.CustomPDFDocumentFactory; @ExtendWith(MockitoExtension.class) class EditTableOfContentsControllerTest { - @Mock - private CustomPDFDocumentFactory pdfDocumentFactory; + @Mock private CustomPDFDocumentFactory pdfDocumentFactory; - @Mock - private ObjectMapper objectMapper; + @Mock private ObjectMapper objectMapper; - @InjectMocks - private EditTableOfContentsController editTableOfContentsController; + @InjectMocks private EditTableOfContentsController editTableOfContentsController; private MockMultipartFile mockFile; private PDDocument mockDocument; @@ -56,7 +53,9 @@ class EditTableOfContentsControllerTest { @BeforeEach void setUp() { - mockFile = new MockMultipartFile("file", "test.pdf", "application/pdf", "PDF content".getBytes()); + mockFile = + new MockMultipartFile( + "file", "test.pdf", "application/pdf", "PDF content".getBytes()); mockDocument = mock(PDDocument.class); mockCatalog = mock(PDDocumentCatalog.class); mockPages = mock(PDPageTree.class); @@ -149,7 +148,8 @@ class EditTableOfContentsControllerTest { assertEquals(1, parentBookmark.get("pageNumber")); @SuppressWarnings("unchecked") - List> children = (List>) parentBookmark.get("children"); + List> children = + (List>) parentBookmark.get("children"); assertEquals(1, children.size()); Map childBookmark = children.get(0); @@ -202,17 +202,21 @@ class EditTableOfContentsControllerTest { bookmarks.add(bookmark); when(pdfDocumentFactory.load(mockFile)).thenReturn(mockDocument); - when(objectMapper.readValue(eq(request.getBookmarkData()), any(TypeReference.class))).thenReturn(bookmarks); + when(objectMapper.readValue(eq(request.getBookmarkData()), any(TypeReference.class))) + .thenReturn(bookmarks); when(mockDocument.getDocumentCatalog()).thenReturn(mockCatalog); when(mockDocument.getNumberOfPages()).thenReturn(5); when(mockDocument.getPage(0)).thenReturn(mockPage1); // Mock saving behavior - doAnswer(invocation -> { - ByteArrayOutputStream baos = invocation.getArgument(0); - baos.write("mocked pdf content".getBytes()); - return null; - }).when(mockDocument).save(any(ByteArrayOutputStream.class)); + doAnswer( + invocation -> { + ByteArrayOutputStream baos = invocation.getArgument(0); + baos.write("mocked pdf content".getBytes()); + return null; + }) + .when(mockDocument) + .save(any(ByteArrayOutputStream.class)); // When ResponseEntity result = editTableOfContentsController.editTableOfContents(request); @@ -221,7 +225,8 @@ class EditTableOfContentsControllerTest { assertNotNull(result); assertNotNull(result.getBody()); - ArgumentCaptor outlineCaptor = ArgumentCaptor.forClass(PDDocumentOutline.class); + ArgumentCaptor outlineCaptor = + ArgumentCaptor.forClass(PDDocumentOutline.class); verify(mockCatalog).setDocumentOutline(outlineCaptor.capture()); PDDocumentOutline capturedOutline = outlineCaptor.getValue(); @@ -236,7 +241,8 @@ class EditTableOfContentsControllerTest { EditTableOfContentsRequest request = new EditTableOfContentsRequest(); request.setFileInput(mockFile); - String bookmarkJson = "[{\"title\":\"Chapter 1\",\"pageNumber\":1,\"children\":[{\"title\":\"Section 1.1\",\"pageNumber\":2,\"children\":[]}]}]"; + String bookmarkJson = + "[{\"title\":\"Chapter 1\",\"pageNumber\":1,\"children\":[{\"title\":\"Section 1.1\",\"pageNumber\":2,\"children\":[]}]}]"; request.setBookmarkData(bookmarkJson); List bookmarks = new ArrayList<>(); @@ -255,17 +261,21 @@ class EditTableOfContentsControllerTest { bookmarks.add(parentBookmark); when(pdfDocumentFactory.load(mockFile)).thenReturn(mockDocument); - when(objectMapper.readValue(eq(bookmarkJson), any(TypeReference.class))).thenReturn(bookmarks); + when(objectMapper.readValue(eq(bookmarkJson), any(TypeReference.class))) + .thenReturn(bookmarks); when(mockDocument.getDocumentCatalog()).thenReturn(mockCatalog); when(mockDocument.getNumberOfPages()).thenReturn(5); when(mockDocument.getPage(0)).thenReturn(mockPage1); when(mockDocument.getPage(1)).thenReturn(mockPage2); - doAnswer(invocation -> { - ByteArrayOutputStream baos = invocation.getArgument(0); - baos.write("mocked pdf content".getBytes()); - return null; - }).when(mockDocument).save(any(ByteArrayOutputStream.class)); + doAnswer( + invocation -> { + ByteArrayOutputStream baos = invocation.getArgument(0); + baos.write("mocked pdf content".getBytes()); + return null; + }) + .when(mockDocument) + .save(any(ByteArrayOutputStream.class)); // When ResponseEntity result = editTableOfContentsController.editTableOfContents(request); @@ -281,7 +291,8 @@ class EditTableOfContentsControllerTest { // Given EditTableOfContentsRequest request = new EditTableOfContentsRequest(); request.setFileInput(mockFile); - request.setBookmarkData("[{\"title\":\"Chapter 1\",\"pageNumber\":-5,\"children\":[]},{\"title\":\"Chapter 2\",\"pageNumber\":100,\"children\":[]}]"); + request.setBookmarkData( + "[{\"title\":\"Chapter 1\",\"pageNumber\":-5,\"children\":[]},{\"title\":\"Chapter 2\",\"pageNumber\":100,\"children\":[]}]"); List bookmarks = new ArrayList<>(); @@ -299,17 +310,21 @@ class EditTableOfContentsControllerTest { bookmarks.add(bookmark2); when(pdfDocumentFactory.load(mockFile)).thenReturn(mockDocument); - when(objectMapper.readValue(eq(request.getBookmarkData()), any(TypeReference.class))).thenReturn(bookmarks); + when(objectMapper.readValue(eq(request.getBookmarkData()), any(TypeReference.class))) + .thenReturn(bookmarks); when(mockDocument.getDocumentCatalog()).thenReturn(mockCatalog); when(mockDocument.getNumberOfPages()).thenReturn(5); when(mockDocument.getPage(0)).thenReturn(mockPage1); // For negative page number when(mockDocument.getPage(4)).thenReturn(mockPage2); // For page number exceeding bounds - doAnswer(invocation -> { - ByteArrayOutputStream baos = invocation.getArgument(0); - baos.write("mocked pdf content".getBytes()); - return null; - }).when(mockDocument).save(any(ByteArrayOutputStream.class)); + doAnswer( + invocation -> { + ByteArrayOutputStream baos = invocation.getArgument(0); + baos.write("mocked pdf content".getBytes()); + return null; + }) + .when(mockDocument) + .save(any(ByteArrayOutputStream.class)); // When ResponseEntity result = editTableOfContentsController.editTableOfContents(request); @@ -332,16 +347,20 @@ class EditTableOfContentsControllerTest { when(mockDocument.getPage(2)).thenReturn(mockPage1); // 0-indexed // When - Method createOutlineItemMethod = EditTableOfContentsController.class.getDeclaredMethod("createOutlineItem", PDDocument.class, BookmarkItem.class); + Method createOutlineItemMethod = + EditTableOfContentsController.class.getDeclaredMethod( + "createOutlineItem", PDDocument.class, BookmarkItem.class); createOutlineItemMethod.setAccessible(true); - PDOutlineItem result = (PDOutlineItem) createOutlineItemMethod.invoke(editTableOfContentsController, mockDocument, bookmark); + PDOutlineItem result = + (PDOutlineItem) + createOutlineItemMethod.invoke( + editTableOfContentsController, mockDocument, bookmark); // Then assertNotNull(result); verify(mockDocument).getPage(2); } - @Test void testBookmarkItem_GettersAndSetters() { // Given @@ -365,18 +384,24 @@ class EditTableOfContentsControllerTest { EditTableOfContentsRequest request = new EditTableOfContentsRequest(); request.setFileInput(mockFile); - when(pdfDocumentFactory.load(mockFile)).thenThrow(new RuntimeException("Failed to load PDF")); + when(pdfDocumentFactory.load(mockFile)) + .thenThrow(new RuntimeException("Failed to load PDF")); // When & Then - assertThrows(RuntimeException.class, () -> editTableOfContentsController.editTableOfContents(request)); + assertThrows( + RuntimeException.class, + () -> editTableOfContentsController.editTableOfContents(request)); } @Test void testExtractBookmarks_IOExceptionDuringLoad_ThrowsException() throws Exception { // Given - when(pdfDocumentFactory.load(mockFile)).thenThrow(new RuntimeException("Failed to load PDF")); + when(pdfDocumentFactory.load(mockFile)) + .thenThrow(new RuntimeException("Failed to load PDF")); // When & Then - assertThrows(RuntimeException.class, () -> editTableOfContentsController.extractBookmarks(mockFile)); + assertThrows( + RuntimeException.class, + () -> editTableOfContentsController.extractBookmarks(mockFile)); } } diff --git a/app/core/src/test/java/stirling/software/SPDF/controller/api/MergeControllerTest.java b/app/core/src/test/java/stirling/software/SPDF/controller/api/MergeControllerTest.java index 03ececa62..1c07d26f2 100644 --- a/app/core/src/test/java/stirling/software/SPDF/controller/api/MergeControllerTest.java +++ b/app/core/src/test/java/stirling/software/SPDF/controller/api/MergeControllerTest.java @@ -29,11 +29,9 @@ import stirling.software.common.service.CustomPDFDocumentFactory; @ExtendWith(MockitoExtension.class) class MergeControllerTest { - @Mock - private CustomPDFDocumentFactory pdfDocumentFactory; + @Mock private CustomPDFDocumentFactory pdfDocumentFactory; - @InjectMocks - private MergeController mergeController; + @InjectMocks private MergeController mergeController; private MockMultipartFile mockFile1; private MockMultipartFile mockFile2; @@ -47,9 +45,15 @@ class MergeControllerTest { @BeforeEach void setUp() { - mockFile1 = new MockMultipartFile("file1", "document1.pdf", "application/pdf", "PDF content 1".getBytes()); - mockFile2 = new MockMultipartFile("file2", "document2.pdf", "application/pdf", "PDF content 2".getBytes()); - mockFile3 = new MockMultipartFile("file3", "chapter3.pdf", "application/pdf", "PDF content 3".getBytes()); + mockFile1 = + new MockMultipartFile( + "file1", "document1.pdf", "application/pdf", "PDF content 1".getBytes()); + mockFile2 = + new MockMultipartFile( + "file2", "document2.pdf", "application/pdf", "PDF content 2".getBytes()); + mockFile3 = + new MockMultipartFile( + "file3", "chapter3.pdf", "application/pdf", "PDF content 3".getBytes()); mockDocument = mock(PDDocument.class); mockMergedDocument = mock(PDDocument.class); @@ -85,12 +89,15 @@ class MergeControllerTest { when(doc3.getNumberOfPages()).thenReturn(2); // When - Method addTableOfContentsMethod = MergeController.class.getDeclaredMethod("addTableOfContents", PDDocument.class, MultipartFile[].class); + Method addTableOfContentsMethod = + MergeController.class.getDeclaredMethod( + "addTableOfContents", PDDocument.class, MultipartFile[].class); addTableOfContentsMethod.setAccessible(true); addTableOfContentsMethod.invoke(mergeController, mockMergedDocument, files); // Then - ArgumentCaptor outlineCaptor = ArgumentCaptor.forClass(PDDocumentOutline.class); + ArgumentCaptor outlineCaptor = + ArgumentCaptor.forClass(PDDocumentOutline.class); verify(mockCatalog).setDocumentOutline(outlineCaptor.capture()); PDDocumentOutline capturedOutline = outlineCaptor.getValue(); @@ -121,7 +128,9 @@ class MergeControllerTest { when(doc1.getNumberOfPages()).thenReturn(3); // When - Method addTableOfContentsMethod = MergeController.class.getDeclaredMethod("addTableOfContents", PDDocument.class, MultipartFile[].class); + Method addTableOfContentsMethod = + MergeController.class.getDeclaredMethod( + "addTableOfContents", PDDocument.class, MultipartFile[].class); addTableOfContentsMethod.setAccessible(true); addTableOfContentsMethod.invoke(mergeController, mockMergedDocument, files); @@ -138,7 +147,9 @@ class MergeControllerTest { when(mockMergedDocument.getDocumentCatalog()).thenReturn(mockCatalog); // When - Method addTableOfContentsMethod = MergeController.class.getDeclaredMethod("addTableOfContents", PDDocument.class, MultipartFile[].class); + Method addTableOfContentsMethod = + MergeController.class.getDeclaredMethod( + "addTableOfContents", PDDocument.class, MultipartFile[].class); addTableOfContentsMethod.setAccessible(true); addTableOfContentsMethod.invoke(mergeController, mockMergedDocument, files); @@ -155,7 +166,8 @@ class MergeControllerTest { when(mockMergedDocument.getDocumentCatalog()).thenReturn(mockCatalog); when(mockMergedDocument.getNumberOfPages()).thenReturn(4); - when(mockMergedDocument.getPage(anyInt())).thenReturn(mockPage1); // Use anyInt() to avoid stubbing conflicts + when(mockMergedDocument.getPage(anyInt())) + .thenReturn(mockPage1); // Use anyInt() to avoid stubbing conflicts // First document loads successfully PDDocument doc1 = mock(PDDocument.class); @@ -163,16 +175,18 @@ class MergeControllerTest { when(doc1.getNumberOfPages()).thenReturn(2); // Second document throws IOException - when(pdfDocumentFactory.load(mockFile2)).thenThrow(new IOException("Failed to load document")); + when(pdfDocumentFactory.load(mockFile2)) + .thenThrow(new IOException("Failed to load document")); // When - Method addTableOfContentsMethod = MergeController.class.getDeclaredMethod("addTableOfContents", PDDocument.class, MultipartFile[].class); + Method addTableOfContentsMethod = + MergeController.class.getDeclaredMethod( + "addTableOfContents", PDDocument.class, MultipartFile[].class); addTableOfContentsMethod.setAccessible(true); // Should not throw exception - assertDoesNotThrow(() -> - addTableOfContentsMethod.invoke(mergeController, mockMergedDocument, files) - ); + assertDoesNotThrow( + () -> addTableOfContentsMethod.invoke(mergeController, mockMergedDocument, files)); // Then verify(mockCatalog).setDocumentOutline(any(PDDocumentOutline.class)); @@ -184,7 +198,9 @@ class MergeControllerTest { @Test void testAddTableOfContents_FilenameWithoutExtension_UsesFullName() throws Exception { // Given - MockMultipartFile fileWithoutExtension = new MockMultipartFile("file", "document_no_ext", "application/pdf", "PDF content".getBytes()); + MockMultipartFile fileWithoutExtension = + new MockMultipartFile( + "file", "document_no_ext", "application/pdf", "PDF content".getBytes()); MultipartFile[] files = {fileWithoutExtension}; when(mockMergedDocument.getDocumentCatalog()).thenReturn(mockCatalog); @@ -196,7 +212,9 @@ class MergeControllerTest { when(doc.getNumberOfPages()).thenReturn(1); // When - Method addTableOfContentsMethod = MergeController.class.getDeclaredMethod("addTableOfContents", PDDocument.class, MultipartFile[].class); + Method addTableOfContentsMethod = + MergeController.class.getDeclaredMethod( + "addTableOfContents", PDDocument.class, MultipartFile[].class); addTableOfContentsMethod.setAccessible(true); addTableOfContentsMethod.invoke(mergeController, mockMergedDocument, files); @@ -218,13 +236,14 @@ class MergeControllerTest { when(doc1.getNumberOfPages()).thenReturn(3); // When - Method addTableOfContentsMethod = MergeController.class.getDeclaredMethod("addTableOfContents", PDDocument.class, MultipartFile[].class); + Method addTableOfContentsMethod = + MergeController.class.getDeclaredMethod( + "addTableOfContents", PDDocument.class, MultipartFile[].class); addTableOfContentsMethod.setAccessible(true); // Should not throw exception - assertDoesNotThrow(() -> - addTableOfContentsMethod.invoke(mergeController, mockMergedDocument, files) - ); + assertDoesNotThrow( + () -> addTableOfContentsMethod.invoke(mergeController, mockMergedDocument, files)); // Then verify(mockCatalog).setDocumentOutline(any(PDDocumentOutline.class)); @@ -275,5 +294,4 @@ class MergeControllerTest { assertEquals(mockMergedDocument, result); verify(mockMergedDocument, never()).addPage(any(PDPage.class)); } - } diff --git a/app/core/src/test/java/stirling/software/SPDF/controller/api/misc/AttachmentControllerTest.java b/app/core/src/test/java/stirling/software/SPDF/controller/api/misc/AttachmentControllerTest.java index 9047bffb5..f73ca3120 100644 --- a/app/core/src/test/java/stirling/software/SPDF/controller/api/misc/AttachmentControllerTest.java +++ b/app/core/src/test/java/stirling/software/SPDF/controller/api/misc/AttachmentControllerTest.java @@ -4,8 +4,6 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; -import org.mockito.MockedStatic; - import java.io.IOException; import java.util.List; @@ -15,6 +13,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.MockedStatic; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -29,14 +28,11 @@ import stirling.software.common.util.WebResponseUtils; @ExtendWith(MockitoExtension.class) class AttachmentControllerTest { - @Mock - private CustomPDFDocumentFactory pdfDocumentFactory; + @Mock private CustomPDFDocumentFactory pdfDocumentFactory; - @Mock - private AttachmentServiceInterface pdfAttachmentService; + @Mock private AttachmentServiceInterface pdfAttachmentService; - @InjectMocks - private AttachmentController attachmentController; + @InjectMocks private AttachmentController attachmentController; private MockMultipartFile pdfFile; private MockMultipartFile attachment1; @@ -47,9 +43,15 @@ class AttachmentControllerTest { @BeforeEach void setUp() { - pdfFile = new MockMultipartFile("fileInput", "test.pdf", "application/pdf", "PDF content".getBytes()); - attachment1 = new MockMultipartFile("attachment1", "file1.txt", "text/plain", "File 1 content".getBytes()); - attachment2 = new MockMultipartFile("attachment2", "file2.jpg", "image/jpeg", "Image content".getBytes()); + pdfFile = + new MockMultipartFile( + "fileInput", "test.pdf", "application/pdf", "PDF content".getBytes()); + attachment1 = + new MockMultipartFile( + "attachment1", "file1.txt", "text/plain", "File 1 content".getBytes()); + attachment2 = + new MockMultipartFile( + "attachment2", "file2.jpg", "image/jpeg", "Image content".getBytes()); request = new AddAttachmentRequest(); mockDocument = mock(PDDocument.class); modifiedMockDocument = mock(PDDocument.class); @@ -60,13 +62,21 @@ class AttachmentControllerTest { List attachments = List.of(attachment1, attachment2); request.setAttachments(attachments); request.setFileInput(pdfFile); - ResponseEntity expectedResponse = ResponseEntity.ok("modified PDF content".getBytes()); + ResponseEntity expectedResponse = + ResponseEntity.ok("modified PDF content".getBytes()); when(pdfDocumentFactory.load(pdfFile, false)).thenReturn(mockDocument); - when(pdfAttachmentService.addAttachment(mockDocument, attachments)).thenReturn(modifiedMockDocument); + when(pdfAttachmentService.addAttachment(mockDocument, attachments)) + .thenReturn(modifiedMockDocument); - try (MockedStatic mockedWebResponseUtils = mockStatic(WebResponseUtils.class)) { - mockedWebResponseUtils.when(() -> WebResponseUtils.pdfDocToWebResponse(eq(modifiedMockDocument), eq("test_with_attachments.pdf"))) + try (MockedStatic mockedWebResponseUtils = + mockStatic(WebResponseUtils.class)) { + mockedWebResponseUtils + .when( + () -> + WebResponseUtils.pdfDocToWebResponse( + eq(modifiedMockDocument), + eq("test_with_attachments.pdf"))) .thenReturn(expectedResponse); ResponseEntity response = attachmentController.addAttachments(request); @@ -84,13 +94,21 @@ class AttachmentControllerTest { List attachments = List.of(attachment1); request.setAttachments(attachments); request.setFileInput(pdfFile); - ResponseEntity expectedResponse = ResponseEntity.ok("modified PDF content".getBytes()); + ResponseEntity expectedResponse = + ResponseEntity.ok("modified PDF content".getBytes()); when(pdfDocumentFactory.load(pdfFile, false)).thenReturn(mockDocument); - when(pdfAttachmentService.addAttachment(mockDocument, attachments)).thenReturn(modifiedMockDocument); + when(pdfAttachmentService.addAttachment(mockDocument, attachments)) + .thenReturn(modifiedMockDocument); - try (MockedStatic mockedWebResponseUtils = mockStatic(WebResponseUtils.class)) { - mockedWebResponseUtils.when(() -> WebResponseUtils.pdfDocToWebResponse(eq(modifiedMockDocument), eq("test_with_attachments.pdf"))) + try (MockedStatic mockedWebResponseUtils = + mockStatic(WebResponseUtils.class)) { + mockedWebResponseUtils + .when( + () -> + WebResponseUtils.pdfDocToWebResponse( + eq(modifiedMockDocument), + eq("test_with_attachments.pdf"))) .thenReturn(expectedResponse); ResponseEntity response = attachmentController.addAttachments(request); diff --git a/app/core/src/test/java/stirling/software/SPDF/controller/api/pipeline/PipelineProcessorTest.java b/app/core/src/test/java/stirling/software/SPDF/controller/api/pipeline/PipelineProcessorTest.java index 0a40fcd5b..b359e25ff 100644 --- a/app/core/src/test/java/stirling/software/SPDF/controller/api/pipeline/PipelineProcessorTest.java +++ b/app/core/src/test/java/stirling/software/SPDF/controller/api/pipeline/PipelineProcessorTest.java @@ -20,11 +20,11 @@ import org.springframework.http.ResponseEntity; import jakarta.servlet.ServletContext; -import stirling.software.common.service.UserServiceInterface; import stirling.software.SPDF.model.PipelineConfig; import stirling.software.SPDF.model.PipelineOperation; import stirling.software.SPDF.model.PipelineResult; import stirling.software.SPDF.service.ApiDocService; +import stirling.software.common.service.UserServiceInterface; @ExtendWith(MockitoExtension.class) class PipelineProcessorTest { diff --git a/app/core/src/test/java/stirling/software/SPDF/service/AttachmentServiceTest.java b/app/core/src/test/java/stirling/software/SPDF/service/AttachmentServiceTest.java index 837530533..985698f30 100644 --- a/app/core/src/test/java/stirling/software/SPDF/service/AttachmentServiceTest.java +++ b/app/core/src/test/java/stirling/software/SPDF/service/AttachmentServiceTest.java @@ -1,15 +1,17 @@ package stirling.software.SPDF.service; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.List; + import org.apache.pdfbox.pdmodel.PDDocument; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.web.multipart.MultipartFile; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; class AttachmentServiceTest { @@ -27,8 +29,8 @@ class AttachmentServiceTest { var attachments = List.of(mock(MultipartFile.class)); when(attachments.get(0).getOriginalFilename()).thenReturn("test.txt"); - when(attachments.get(0).getInputStream()).thenReturn( - new ByteArrayInputStream("Test content".getBytes())); + when(attachments.get(0).getInputStream()) + .thenReturn(new ByteArrayInputStream("Test content".getBytes())); when(attachments.get(0).getSize()).thenReturn(12L); when(attachments.get(0).getContentType()).thenReturn("text/plain"); @@ -49,14 +51,14 @@ class AttachmentServiceTest { var attachments = List.of(attachment1, attachment2); when(attachment1.getOriginalFilename()).thenReturn("document.pdf"); - when(attachment1.getInputStream()).thenReturn( - new ByteArrayInputStream("PDF content".getBytes())); + when(attachment1.getInputStream()) + .thenReturn(new ByteArrayInputStream("PDF content".getBytes())); when(attachment1.getSize()).thenReturn(15L); when(attachment1.getContentType()).thenReturn("application/pdf"); when(attachment2.getOriginalFilename()).thenReturn("image.jpg"); - when(attachment2.getInputStream()).thenReturn( - new ByteArrayInputStream("Image content".getBytes())); + when(attachment2.getInputStream()) + .thenReturn(new ByteArrayInputStream("Image content".getBytes())); when(attachment2.getSize()).thenReturn(20L); when(attachment2.getContentType()).thenReturn("image/jpeg"); @@ -74,8 +76,8 @@ class AttachmentServiceTest { var attachments = List.of(mock(MultipartFile.class)); when(attachments.get(0).getOriginalFilename()).thenReturn("image.jpg"); - when(attachments.get(0).getInputStream()).thenReturn( - new ByteArrayInputStream("Image content".getBytes())); + when(attachments.get(0).getInputStream()) + .thenReturn(new ByteArrayInputStream("Image content".getBytes())); when(attachments.get(0).getSize()).thenReturn(25L); when(attachments.get(0).getContentType()).thenReturn(""); diff --git a/app/core/src/test/java/stirling/software/SPDF/service/SignatureServiceTest.java b/app/core/src/test/java/stirling/software/SPDF/service/SignatureServiceTest.java index 06ed4f2aa..5161e82ea 100644 --- a/app/core/src/test/java/stirling/software/SPDF/service/SignatureServiceTest.java +++ b/app/core/src/test/java/stirling/software/SPDF/service/SignatureServiceTest.java @@ -17,8 +17,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.mockito.MockedStatic; -import stirling.software.common.configuration.InstallationPathConfig; import stirling.software.SPDF.model.SignatureFile; +import stirling.software.common.configuration.InstallationPathConfig; class SignatureServiceTest { diff --git a/app/core/src/test/java/stirling/software/common/controller/JobControllerTest.java b/app/core/src/test/java/stirling/software/common/controller/JobControllerTest.java index 3ec041eb5..73b550cde 100644 --- a/app/core/src/test/java/stirling/software/common/controller/JobControllerTest.java +++ b/app/core/src/test/java/stirling/software/common/controller/JobControllerTest.java @@ -12,36 +12,28 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpSession; + import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpSession; import stirling.software.common.model.job.JobResult; -import stirling.software.common.model.job.JobStats; -import stirling.software.common.model.job.ResultFile; import stirling.software.common.service.FileStorage; import stirling.software.common.service.JobQueue; import stirling.software.common.service.TaskManager; class JobControllerTest { - @Mock - private TaskManager taskManager; + @Mock private TaskManager taskManager; - @Mock - private FileStorage fileStorage; + @Mock private FileStorage fileStorage; - @Mock - private JobQueue jobQueue; + @Mock private JobQueue jobQueue; - @Mock - private HttpServletRequest request; + @Mock private HttpServletRequest request; private MockHttpSession session; - @InjectMocks - private JobController controller; + @InjectMocks private JobController controller; @BeforeEach void setUp() { @@ -139,7 +131,8 @@ class JobControllerTest { JobResult mockResult = new JobResult(); mockResult.setJobId(jobId); - mockResult.completeWithSingleFile(fileId, originalFileName, contentType, fileContent.length); + mockResult.completeWithSingleFile( + fileId, originalFileName, contentType, fileContent.length); when(taskManager.getJobResult(jobId)).thenReturn(mockResult); when(fileStorage.retrieveBytes(fileId)).thenReturn(fileContent); @@ -150,7 +143,8 @@ class JobControllerTest { // Assert assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(contentType, response.getHeaders().getFirst("Content-Type")); - assertTrue(response.getHeaders().getFirst("Content-Disposition").contains(originalFileName)); + assertTrue( + response.getHeaders().getFirst("Content-Disposition").contains(originalFileName)); assertEquals(fileContent, response.getBody()); } @@ -229,45 +223,45 @@ class JobControllerTest { assertTrue(response.getBody().toString().contains("Error retrieving file")); } - /* - * @Test void testGetJobStats() { // Arrange JobStats mockStats = - * JobStats.builder() .totalJobs(10) .activeJobs(3) .completedJobs(7) .build(); - * - * when(taskManager.getJobStats()).thenReturn(mockStats); - * - * // Act ResponseEntity response = controller.getJobStats(); - * - * // Assert assertEquals(HttpStatus.OK, response.getStatusCode()); - * assertEquals(mockStats, response.getBody()); } - * - * @Test void testCleanupOldJobs() { // Arrange when(taskManager.getJobStats()) - * .thenReturn(JobStats.builder().totalJobs(10).build()) - * .thenReturn(JobStats.builder().totalJobs(7).build()); - * - * // Act ResponseEntity response = controller.cleanupOldJobs(); - * - * // Assert assertEquals(HttpStatus.OK, response.getStatusCode()); - * - * @SuppressWarnings("unchecked") Map responseBody = - * (Map) response.getBody(); assertEquals("Cleanup complete", - * responseBody.get("message")); assertEquals(3, - * responseBody.get("removedJobs")); assertEquals(7, - * responseBody.get("remainingJobs")); - * - * verify(taskManager).cleanupOldJobs(); } - * - * @Test void testGetQueueStats() { // Arrange Map - * mockQueueStats = Map.of( "queuedJobs", 5, "queueCapacity", 10, - * "resourceStatus", "OK" ); - * - * when(jobQueue.getQueueStats()).thenReturn(mockQueueStats); - * - * // Act ResponseEntity response = controller.getQueueStats(); - * - * // Assert assertEquals(HttpStatus.OK, response.getStatusCode()); - * assertEquals(mockQueueStats, response.getBody()); - * verify(jobQueue).getQueueStats(); } - */ + /* + * @Test void testGetJobStats() { // Arrange JobStats mockStats = + * JobStats.builder() .totalJobs(10) .activeJobs(3) .completedJobs(7) .build(); + * + * when(taskManager.getJobStats()).thenReturn(mockStats); + * + * // Act ResponseEntity response = controller.getJobStats(); + * + * // Assert assertEquals(HttpStatus.OK, response.getStatusCode()); + * assertEquals(mockStats, response.getBody()); } + * + * @Test void testCleanupOldJobs() { // Arrange when(taskManager.getJobStats()) + * .thenReturn(JobStats.builder().totalJobs(10).build()) + * .thenReturn(JobStats.builder().totalJobs(7).build()); + * + * // Act ResponseEntity response = controller.cleanupOldJobs(); + * + * // Assert assertEquals(HttpStatus.OK, response.getStatusCode()); + * + * @SuppressWarnings("unchecked") Map responseBody = + * (Map) response.getBody(); assertEquals("Cleanup complete", + * responseBody.get("message")); assertEquals(3, + * responseBody.get("removedJobs")); assertEquals(7, + * responseBody.get("remainingJobs")); + * + * verify(taskManager).cleanupOldJobs(); } + * + * @Test void testGetQueueStats() { // Arrange Map + * mockQueueStats = Map.of( "queuedJobs", 5, "queueCapacity", 10, + * "resourceStatus", "OK" ); + * + * when(jobQueue.getQueueStats()).thenReturn(mockQueueStats); + * + * // Act ResponseEntity response = controller.getQueueStats(); + * + * // Assert assertEquals(HttpStatus.OK, response.getStatusCode()); + * assertEquals(mockQueueStats, response.getBody()); + * verify(jobQueue).getQueueStats(); } + */ @Test void testCancelJob_InQueue() { // Arrange diff --git a/app/proprietary/src/test/java/stirling/software/proprietary/security/CustomLogoutSuccessHandlerTest.java b/app/proprietary/src/test/java/stirling/software/proprietary/security/CustomLogoutSuccessHandlerTest.java index a5abd6be5..04ca4c35f 100644 --- a/app/proprietary/src/test/java/stirling/software/proprietary/security/CustomLogoutSuccessHandlerTest.java +++ b/app/proprietary/src/test/java/stirling/software/proprietary/security/CustomLogoutSuccessHandlerTest.java @@ -1,17 +1,20 @@ package stirling.software.proprietary.security; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; +import static org.mockito.Mockito.*; + import java.io.IOException; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + import stirling.software.common.model.ApplicationProperties; -import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class CustomLogoutSuccessHandlerTest { diff --git a/app/proprietary/src/test/java/stirling/software/proprietary/security/configuration/DatabaseConfigTest.java b/app/proprietary/src/test/java/stirling/software/proprietary/security/configuration/DatabaseConfigTest.java index b1dc3a29e..eac32eec4 100644 --- a/app/proprietary/src/test/java/stirling/software/proprietary/security/configuration/DatabaseConfigTest.java +++ b/app/proprietary/src/test/java/stirling/software/proprietary/security/configuration/DatabaseConfigTest.java @@ -1,6 +1,10 @@ package stirling.software.proprietary.security.configuration; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.when; + import javax.sql.DataSource; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -8,10 +12,9 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.exception.UnsupportedProviderException; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class DatabaseConfigTest { diff --git a/app/proprietary/src/test/java/stirling/software/proprietary/security/service/EmailServiceTest.java b/app/proprietary/src/test/java/stirling/software/proprietary/security/service/EmailServiceTest.java index e953783a8..b1cd5a8dd 100644 --- a/app/proprietary/src/test/java/stirling/software/proprietary/security/service/EmailServiceTest.java +++ b/app/proprietary/src/test/java/stirling/software/proprietary/security/service/EmailServiceTest.java @@ -2,8 +2,10 @@ package stirling.software.proprietary.security.service; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; -import jakarta.mail.MessagingException; -import jakarta.mail.internet.MimeMessage; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -17,9 +19,6 @@ import jakarta.mail.internet.MimeMessage; import stirling.software.common.model.ApplicationProperties; import stirling.software.proprietary.security.model.api.Email; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) public class EmailServiceTest { diff --git a/app/proprietary/src/test/java/stirling/software/proprietary/security/service/TeamServiceTest.java b/app/proprietary/src/test/java/stirling/software/proprietary/security/service/TeamServiceTest.java index 264c0b59a..f4e8244a8 100644 --- a/app/proprietary/src/test/java/stirling/software/proprietary/security/service/TeamServiceTest.java +++ b/app/proprietary/src/test/java/stirling/software/proprietary/security/service/TeamServiceTest.java @@ -1,25 +1,26 @@ package stirling.software.proprietary.security.service; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + import java.util.Optional; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; + import stirling.software.proprietary.model.Team; import stirling.software.proprietary.security.repository.TeamRepository; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class TeamServiceTest { - @Mock - private TeamRepository teamRepository; + @Mock private TeamRepository teamRepository; - @InjectMocks - private TeamService teamService; + @InjectMocks private TeamService teamService; @Test void getDefaultTeam() { @@ -41,8 +42,7 @@ class TeamServiceTest { defaultTeam.setId(1L); defaultTeam.setName(teamName); - when(teamRepository.findByName(teamName)) - .thenReturn(Optional.empty()); + when(teamRepository.findByName(teamName)).thenReturn(Optional.empty()); when(teamRepository.save(any(Team.class))).thenReturn(defaultTeam); Team result = teamService.getOrCreateDefaultTeam(); @@ -56,7 +56,7 @@ class TeamServiceTest { team.setName("Eldians"); when(teamRepository.findByName(TeamService.INTERNAL_TEAM_NAME)) - .thenReturn(Optional.of(team)); + .thenReturn(Optional.of(team)); Team result = teamService.getOrCreateInternalTeam(); @@ -70,11 +70,10 @@ class TeamServiceTest { internalTeam.setId(2L); internalTeam.setName(teamName); - when(teamRepository.findByName(teamName)) - .thenReturn(Optional.empty()); + when(teamRepository.findByName(teamName)).thenReturn(Optional.empty()); when(teamRepository.save(any(Team.class))).thenReturn(internalTeam); when(teamRepository.findByName(TeamService.INTERNAL_TEAM_NAME)) - .thenReturn(Optional.empty()); + .thenReturn(Optional.empty()); Team result = teamService.getOrCreateInternalTeam(); diff --git a/app/proprietary/src/test/java/stirling/software/proprietary/security/service/UserServiceTest.java b/app/proprietary/src/test/java/stirling/software/proprietary/security/service/UserServiceTest.java index d0fbbb154..be087314a 100644 --- a/app/proprietary/src/test/java/stirling/software/proprietary/security/service/UserServiceTest.java +++ b/app/proprietary/src/test/java/stirling/software/proprietary/security/service/UserServiceTest.java @@ -1,8 +1,13 @@ package stirling.software.proprietary.security.service; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; + import java.sql.SQLException; -import java.util.Locale; import java.util.Optional; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -11,10 +16,9 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.context.MessageSource; import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.test.context.bean.override.mockito.MockitoBean; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.enumeration.Role; -import stirling.software.common.model.exception.UnsupportedProviderException; import stirling.software.proprietary.model.Team; import stirling.software.proprietary.security.database.repository.AuthorityRepository; import stirling.software.proprietary.security.database.repository.UserRepository; @@ -22,42 +26,27 @@ import stirling.software.proprietary.security.model.AuthenticationType; import stirling.software.proprietary.security.model.User; import stirling.software.proprietary.security.repository.TeamRepository; import stirling.software.proprietary.security.session.SessionPersistentRegistry; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class UserServiceTest { - @Mock - private UserRepository userRepository; + @Mock private UserRepository userRepository; - @Mock - private TeamRepository teamRepository; + @Mock private TeamRepository teamRepository; - @Mock - private AuthorityRepository authorityRepository; + @Mock private AuthorityRepository authorityRepository; - @Mock - private PasswordEncoder passwordEncoder; + @Mock private PasswordEncoder passwordEncoder; - @Mock - private MessageSource messageSource; + @Mock private MessageSource messageSource; - @Mock - private SessionPersistentRegistry sessionPersistentRegistry; + @Mock private SessionPersistentRegistry sessionPersistentRegistry; - @Mock - private DatabaseServiceInterface databaseService; + @Mock private DatabaseServiceInterface databaseService; - @Mock - private ApplicationProperties.Security.OAUTH2 oauth2Properties; + @Mock private ApplicationProperties.Security.OAUTH2 oauth2Properties; - @InjectMocks - private UserService userService; + @InjectMocks private UserService userService; private Team mockTeam; private User mockUser; @@ -146,10 +135,10 @@ class UserServiceTest { AuthenticationType authType = AuthenticationType.WEB; // When & Then - IllegalArgumentException exception = assertThrows( - IllegalArgumentException.class, - () -> userService.saveUser(invalidUsername, authType) - ); + IllegalArgumentException exception = + assertThrows( + IllegalArgumentException.class, + () -> userService.saveUser(invalidUsername, authType)); verify(userRepository, never()).save(any(User.class)); verify(databaseService, never()).exportDatabase(); @@ -221,10 +210,10 @@ class UserServiceTest { AuthenticationType authType = AuthenticationType.WEB; // When & Then - IllegalArgumentException exception = assertThrows( - IllegalArgumentException.class, - () -> userService.saveUser(reservedUsername, authType) - ); + IllegalArgumentException exception = + assertThrows( + IllegalArgumentException.class, + () -> userService.saveUser(reservedUsername, authType)); verify(userRepository, never()).save(any(User.class)); verify(databaseService, never()).exportDatabase(); @@ -237,10 +226,10 @@ class UserServiceTest { AuthenticationType authType = AuthenticationType.WEB; // When & Then - IllegalArgumentException exception = assertThrows( - IllegalArgumentException.class, - () -> userService.saveUser(anonymousUsername, authType) - ); + IllegalArgumentException exception = + assertThrows( + IllegalArgumentException.class, + () -> userService.saveUser(anonymousUsername, authType)); verify(userRepository, never()).save(any(User.class)); verify(databaseService, never()).exportDatabase(); @@ -313,5 +302,4 @@ class UserServiceTest { verify(userRepository).save(any(User.class)); verify(databaseService).exportDatabase(); } - } From c40fac80536c2eb619ab98f056d684180aa362ab Mon Sep 17 00:00:00 2001 From: "stirlingbot[bot]" <195170888+stirlingbot[bot]@users.noreply.github.com> Date: Sat, 2 Aug 2025 23:19:08 +0100 Subject: [PATCH 6/8] Update 3rd Party Licenses (#4073) Auto-generated by stirlingbot[bot] Signed-off-by: stirlingbot[bot] Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com> --- .../resources/static/3rdPartyLicenses.json | 199 ++++++++---------- 1 file changed, 93 insertions(+), 106 deletions(-) diff --git a/app/core/src/main/resources/static/3rdPartyLicenses.json b/app/core/src/main/resources/static/3rdPartyLicenses.json index 23e9c5bc8..59acd0fc2 100644 --- a/app/core/src/main/resources/static/3rdPartyLicenses.json +++ b/app/core/src/main/resources/static/3rdPartyLicenses.json @@ -45,77 +45,77 @@ { "moduleName": "com.fasterxml.jackson.core:jackson-annotations", "moduleUrl": "https://github.com/FasterXML/jackson", - "moduleVersion": "2.19.1", + "moduleVersion": "2.19.2", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "com.fasterxml.jackson.core:jackson-core", "moduleUrl": "https://github.com/FasterXML/jackson-core", - "moduleVersion": "2.19.1", + "moduleVersion": "2.19.2", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "com.fasterxml.jackson.core:jackson-databind", "moduleUrl": "https://github.com/FasterXML/jackson", - "moduleVersion": "2.19.1", + "moduleVersion": "2.19.2", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml", "moduleUrl": "https://github.com/FasterXML/jackson-dataformats-text", - "moduleVersion": "2.19.1", + "moduleVersion": "2.19.2", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "com.fasterxml.jackson.datatype:jackson-datatype-jdk8", "moduleUrl": "https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8", - "moduleVersion": "2.19.1", + "moduleVersion": "2.19.2", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "com.fasterxml.jackson.datatype:jackson-datatype-jsr310", "moduleUrl": "https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310", - "moduleVersion": "2.19.1", + "moduleVersion": "2.19.2", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-base", "moduleUrl": "https://github.com/FasterXML/jackson-jakarta-rs-providers/jackson-jakarta-rs-base", - "moduleVersion": "2.19.1", + "moduleVersion": "2.19.2", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-json-provider", "moduleUrl": "https://github.com/FasterXML/jackson-jakarta-rs-providers/jackson-jakarta-rs-json-provider", - "moduleVersion": "2.19.1", + "moduleVersion": "2.19.2", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "com.fasterxml.jackson.module:jackson-module-jakarta-xmlbind-annotations", "moduleUrl": "https://github.com/FasterXML/jackson-modules-base", - "moduleVersion": "2.19.1", + "moduleVersion": "2.19.2", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "com.fasterxml.jackson.module:jackson-module-parameter-names", "moduleUrl": "https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names", - "moduleVersion": "2.19.1", + "moduleVersion": "2.19.2", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "com.fasterxml.jackson:jackson-bom", "moduleUrl": "https://github.com/FasterXML/jackson-bom", - "moduleVersion": "2.19.1", + "moduleVersion": "2.19.2", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, @@ -199,13 +199,6 @@ "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, - { - "moduleName": "com.google.protobuf:protobuf-java", - "moduleUrl": "https://developers.google.com/protocol-buffers/", - "moduleVersion": "4.31.0", - "moduleLicense": "BSD-3-Clause", - "moduleLicenseUrl": "https://opensource.org/licenses/BSD-3-Clause" - }, { "moduleName": "com.google.zxing:core", "moduleUrl": "https://github.com/zxing/zxing/core", @@ -277,7 +270,7 @@ { "moduleName": "com.opencsv:opencsv", "moduleUrl": "http://opencsv.sf.net", - "moduleVersion": "5.11.2", + "moduleVersion": "5.12.0", "moduleLicense": "Apache 2", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, @@ -498,7 +491,7 @@ { "moduleName": "com.zaxxer:HikariCP", "moduleUrl": "https://github.com/brettwooldridge/HikariCP", - "moduleVersion": "6.3.0", + "moduleVersion": "6.3.1", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, @@ -553,77 +546,71 @@ { "moduleName": "io.micrometer:micrometer-commons", "moduleUrl": "https://github.com/micrometer-metrics/micrometer", - "moduleVersion": "1.15.1", + "moduleVersion": "1.15.2", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "io.micrometer:micrometer-core", "moduleUrl": "https://github.com/micrometer-metrics/micrometer", - "moduleVersion": "1.15.1", + "moduleVersion": "1.15.2", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "io.micrometer:micrometer-jakarta9", "moduleUrl": "https://github.com/micrometer-metrics/micrometer", - "moduleVersion": "1.15.1", + "moduleVersion": "1.15.2", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "io.micrometer:micrometer-observation", "moduleUrl": "https://github.com/micrometer-metrics/micrometer", - "moduleVersion": "1.15.1", + "moduleVersion": "1.15.2", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "io.micrometer:micrometer-registry-prometheus", "moduleUrl": "https://github.com/micrometer-metrics/micrometer", - "moduleVersion": "1.15.1", + "moduleVersion": "1.15.2", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "io.prometheus:prometheus-metrics-config", - "moduleVersion": "1.3.8", + "moduleVersion": "1.3.10", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "io.prometheus:prometheus-metrics-core", - "moduleVersion": "1.3.8", + "moduleVersion": "1.3.10", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "io.prometheus:prometheus-metrics-exposition-formats", - "moduleVersion": "1.3.8", - "moduleLicense": "The Apache Software License, Version 2.0", - "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" - }, - { - "moduleName": "io.prometheus:prometheus-metrics-exposition-formats-no-protobuf", - "moduleVersion": "1.3.8", + "moduleVersion": "1.3.10", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "io.prometheus:prometheus-metrics-exposition-textformats", - "moduleVersion": "1.3.8", + "moduleVersion": "1.3.10", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "io.prometheus:prometheus-metrics-model", - "moduleVersion": "1.3.8", + "moduleVersion": "1.3.10", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "io.prometheus:prometheus-metrics-tracer-common", - "moduleVersion": "1.3.8", + "moduleVersion": "1.3.10", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, @@ -925,7 +912,7 @@ { "moduleName": "org.apache.tomcat.embed:tomcat-embed-el", "moduleUrl": "https://tomcat.apache.org/", - "moduleVersion": "10.1.42", + "moduleVersion": "10.1.43", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, @@ -1034,182 +1021,182 @@ { "moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jakarta-client", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jakarta-common", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jakarta-server", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jetty-server", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-servlet", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty.ee10:jetty-ee10-annotations", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty.ee10:jetty-ee10-plus", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty.ee10:jetty-ee10-servlet", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty.ee10:jetty-ee10-servlets", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty.ee10:jetty-ee10-webapp", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty.websocket:jetty-websocket-core-client", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty.websocket:jetty-websocket-core-common", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty.websocket:jetty-websocket-core-server", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty.websocket:jetty-websocket-jetty-api", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty.websocket:jetty-websocket-jetty-common", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty:jetty-alpn-client", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty:jetty-client", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty:jetty-ee", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty:jetty-http", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty:jetty-io", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty:jetty-plus", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty:jetty-security", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty:jetty-server", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty:jetty-session", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty:jetty-util", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, { "moduleName": "org.eclipse.jetty:jetty-xml", "moduleUrl": "https://jetty.org/", - "moduleVersion": "12.0.22", + "moduleVersion": "12.0.23", "moduleLicense": "Eclipse Public License - Version 2.0", "moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/" }, @@ -1251,7 +1238,7 @@ { "moduleName": "org.hibernate.orm:hibernate-core", "moduleUrl": "https://www.hibernate.org/orm/6.6", - "moduleVersion": "6.6.18.Final", + "moduleVersion": "6.6.22.Final", "moduleLicense": "GNU Library General Public License v2.1 or later", "moduleLicenseUrl": "https://www.opensource.org/licenses/LGPL-2.1" }, @@ -1468,196 +1455,196 @@ { "moduleName": "org.springframework.boot:spring-boot", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-actuator", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-actuator-autoconfigure", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-autoconfigure", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-starter", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-starter-actuator", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-starter-aop", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-starter-data-jpa", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-starter-jdbc", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-starter-jetty", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-starter-json", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-starter-logging", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-starter-mail", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-starter-oauth2-client", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-starter-security", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-starter-thymeleaf", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-starter-validation", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.boot:spring-boot-starter-web", "moduleUrl": "https://spring.io/projects/spring-boot", - "moduleVersion": "3.5.3", + "moduleVersion": "3.5.4", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.data:spring-data-commons", "moduleUrl": "https://spring.io/projects/spring-data", - "moduleVersion": "3.5.1", + "moduleVersion": "3.5.2", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.data:spring-data-jpa", "moduleUrl": "https://projects.spring.io/spring-data-jpa", - "moduleVersion": "3.5.1", + "moduleVersion": "3.5.2", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.security:spring-security-config", "moduleUrl": "https://spring.io/projects/spring-security", - "moduleVersion": "6.5.1", + "moduleVersion": "6.5.2", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.security:spring-security-core", "moduleUrl": "https://spring.io/projects/spring-security", - "moduleVersion": "6.5.1", + "moduleVersion": "6.5.2", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.security:spring-security-crypto", "moduleUrl": "https://spring.io/projects/spring-security", - "moduleVersion": "6.5.1", + "moduleVersion": "6.5.2", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.security:spring-security-oauth2-client", "moduleUrl": "https://spring.io/projects/spring-security", - "moduleVersion": "6.5.1", + "moduleVersion": "6.5.2", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.security:spring-security-oauth2-core", "moduleUrl": "https://spring.io/projects/spring-security", - "moduleVersion": "6.5.1", + "moduleVersion": "6.5.2", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.security:spring-security-oauth2-jose", "moduleUrl": "https://spring.io/projects/spring-security", - "moduleVersion": "6.5.1", + "moduleVersion": "6.5.2", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.security:spring-security-saml2-service-provider", "moduleUrl": "https://spring.io/projects/spring-security", - "moduleVersion": "6.5.1", + "moduleVersion": "6.5.2", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework.security:spring-security-web", "moduleUrl": "https://spring.io/projects/spring-security", - "moduleVersion": "6.5.1", + "moduleVersion": "6.5.2", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, @@ -1671,91 +1658,91 @@ { "moduleName": "org.springframework:spring-aop", "moduleUrl": "https://github.com/spring-projects/spring-framework", - "moduleVersion": "6.2.8", + "moduleVersion": "6.2.9", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework:spring-aspects", "moduleUrl": "https://github.com/spring-projects/spring-framework", - "moduleVersion": "6.2.8", + "moduleVersion": "6.2.9", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework:spring-beans", "moduleUrl": "https://github.com/spring-projects/spring-framework", - "moduleVersion": "6.2.8", + "moduleVersion": "6.2.9", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework:spring-context", "moduleUrl": "https://github.com/spring-projects/spring-framework", - "moduleVersion": "6.2.8", + "moduleVersion": "6.2.9", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework:spring-context-support", "moduleUrl": "https://github.com/spring-projects/spring-framework", - "moduleVersion": "6.2.8", + "moduleVersion": "6.2.9", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework:spring-core", "moduleUrl": "https://github.com/spring-projects/spring-framework", - "moduleVersion": "6.2.8", + "moduleVersion": "6.2.9", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework:spring-expression", "moduleUrl": "https://github.com/spring-projects/spring-framework", - "moduleVersion": "6.2.8", + "moduleVersion": "6.2.9", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework:spring-jcl", "moduleUrl": "https://github.com/spring-projects/spring-framework", - "moduleVersion": "6.2.8", + "moduleVersion": "6.2.9", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework:spring-jdbc", "moduleUrl": "https://github.com/spring-projects/spring-framework", - "moduleVersion": "6.2.8", + "moduleVersion": "6.2.9", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework:spring-orm", "moduleUrl": "https://github.com/spring-projects/spring-framework", - "moduleVersion": "6.2.8", + "moduleVersion": "6.2.9", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework:spring-tx", "moduleUrl": "https://github.com/spring-projects/spring-framework", - "moduleVersion": "6.2.8", + "moduleVersion": "6.2.9", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework:spring-web", "moduleUrl": "https://github.com/spring-projects/spring-framework", - "moduleVersion": "6.2.8", + "moduleVersion": "6.2.9", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "org.springframework:spring-webmvc", "moduleUrl": "https://github.com/spring-projects/spring-framework", - "moduleVersion": "6.2.8", + "moduleVersion": "6.2.9", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, From ae8f68427b8e54a823ca47f9c47d4701003403bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sz=C3=BCcs?= <127139797+balazs-szucs@users.noreply.github.com> Date: Sun, 3 Aug 2025 00:19:24 +0200 Subject: [PATCH 7/8] Updated Hungarian translation (#4094) # Description of Changes Should be last untranslated string. --- ## Checklist ### General - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [x] I have performed a self-review of my own code - [x] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [x] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [x] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details. --- app/core/src/main/resources/messages_hu_HU.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/core/src/main/resources/messages_hu_HU.properties b/app/core/src/main/resources/messages_hu_HU.properties index f04440968..3132d4fdc 100644 --- a/app/core/src/main/resources/messages_hu_HU.properties +++ b/app/core/src/main/resources/messages_hu_HU.properties @@ -1282,7 +1282,7 @@ merge.header=Több PDF egyesítése (2+) merge.sortByName=Rendezés név szerint merge.sortByDate=Rendezés dátum szerint merge.removeCertSign=Digitális aláírás eltávolítása az egyesített fájlban? -merge.generateToc=Generate table of contents in the merged file? +merge.generateToc=Tartalomjegyzék létrehozása az egyesített fájlban? merge.submit=Egyesítés From 6634b5d6e432c5f5947d1c433413d71dcd328fc4 Mon Sep 17 00:00:00 2001 From: "stirlingbot[bot]" <195170888+stirlingbot[bot]@users.noreply.github.com> Date: Sat, 2 Aug 2025 23:19:52 +0100 Subject: [PATCH 8/8] =?UTF-8?q?=F0=9F=A4=96=20format=20everything=20with?= =?UTF-8?q?=20pre-commit=20by=20stirlingbot=20(#4104)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Auto-generated by [create-pull-request][1] with **stirlingbot** [1]: https://github.com/peter-evans/create-pull-request Signed-off-by: stirlingbot[bot] Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com> --- .../software/SPDF/controller/api/misc/StampController.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/StampController.java b/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/StampController.java index 0df77bca7..2a4a3f665 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/StampController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/StampController.java @@ -72,10 +72,13 @@ public class StampController { MultipartFile stampImage = request.getStampImage(); if ("image".equalsIgnoreCase(stampType)) { if (stampImage == null) { - throw new IllegalArgumentException("Stamp image file must be provided when stamp type is 'image'"); + throw new IllegalArgumentException( + "Stamp image file must be provided when stamp type is 'image'"); } String stampImageName = stampImage.getOriginalFilename(); - if (stampImageName == null || stampImageName.contains("..") || stampImageName.startsWith("/")) { + if (stampImageName == null + || stampImageName.contains("..") + || stampImageName.startsWith("/")) { throw new IllegalArgumentException("Invalid stamp image file path"); } }