Repository: authorjapps/zerocode (java)

Issue:
Report generation fails if scenario name contains non allowed characters
About The Problem
---
If the scenario name contains characters that are invalid for a file name (e.g. `/` on windows/linux, or `:` on windows), the report generation fails to produce the report of this scenario.

**To reproduce:**
- Clean-up the target folder
- Edit a scenario file an set a `/` in the name (e.g. `integration_test_files/helloworld/get_api_integration_test.json`)
- Run the test for this scenario: `mvn test -ntp -pl core -Dtest=**/HelloWorldInMemoryTest`

**Expected:** Report generation succeeds, see e.g. this action run: https://github.com/javiertuya/zerocode/actions/runs/11425689187

**Actual:** Report generation fails, see e.g. this action run: https://github.com/javiertuya/zerocode/actions/runs/11425675217. Report generation displays this message:
```
2024-10-20 10:45:40,538 [main] INFO org.jsmart.zerocode.core.engine.listener.TestUtilityListener - Generating test-statistics reports. please wait...
2024-10-20 10:45:40,539 [main] ERROR org.jsmart.zerocode.core.report.ZeroCodeReportGeneratorImpl - 
			************
Now files were found in folder:target/zerocode-test-reports/, hence could not proceed. 
(If this was intentional, then you can safely ignore this error) 
			************** 
```
Implemented Solution
---
The special chars replaced via "_". More details are in the PR below.
Please go to the "Motivation & Context" section in [this](https://github.com/authorjapps/zerocode/pull/692#issue-2614300875) PR.

Pull request:
ISSUE-689 # Sanitize json report file name
# Sanitize json report file name

## Fixes Issue
- [x] Which issue or ticket was(will be) fixed by this PR? Fix #689 
PR Branch
**https://github.com/javiertuya/zerocode/tree/689-report-scenario-invalid-chars**

## Motivation and Context

To generate html reports, a json file is created for each scenario. The file name is taken from the scenario name. Report for this scenario fails if the name contains characters that are not allowed as part of a filename. This PR sanitizes the report file name.

Note to reviewers: Sanitization is strict (only keeps alphanumeric, spaces, dots and dashes) because the report filenames are guaranteed to be unique because they contain the correlation id. It could be less strict by replacing only the windows forbidden characters (also valid for unix), even making different replacements for linux and windows, but I'm not sure if it's worth it.

## Checklist:

* [x] New Unit tests were added
  * [ ] Covered in existing Unit tests

* [ ] Integration tests were added
  * [ ] Covered in existing Integration tests

* [x] Test names are meaningful

* [x] Feature manually tested and outcome is successful

* [x] PR doesn't break any of the earlier features for end users
  * [ ] WARNING! This might break one or more earlier earlier features, hence left a comment tagging all reviewrs

* [x] Branch build passed in CI

* [x] No 'package.*' in the imports

* [ ] Relevant DOcumentation page added or updated with clear instructions and examples for the end user
  * [x] Not applicable. This was only a code refactor change, no functional or behaviourial changes were introduced

* [ ] Http test added to `http-testing` module(if applicable) ?
  * [x] Not applicable. The changes did not affect HTTP automation flow

* [ ] Kafka test added to `kafka-testing` module(if applicable) ?
  * [x] Not applicable. The changes did not affect Kafka automation flow


Patch:
diff --git a/core/src/main/java/org/jsmart/zerocode/core/domain/builders/ZeroCodeIoWriteBuilder.java b/core/src/main/java/org/jsmart/zerocode/core/domain/builders/ZeroCodeIoWriteBuilder.java
index 7d4c5e26..92fd0fdb 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/domain/builders/ZeroCodeIoWriteBuilder.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/domain/builders/ZeroCodeIoWriteBuilder.java
@@ -16,6 +16,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
 import static org.jsmart.zerocode.core.constants.ZeroCodeReportConstants.TARGET_REPORT_DIR;
+import static org.jsmart.zerocode.core.utils.SmartUtils.sanitizeReportFileName;
 import static org.slf4j.LoggerFactory.getLogger;
 
 public class ZeroCodeIoWriteBuilder {
@@ -60,6 +61,7 @@ public class ZeroCodeIoWriteBuilder {
 
             final ObjectMapper mapper = new ObjectMapperProvider().get();
 
+            fileName = sanitizeReportFileName(fileName);
             File file = new File(TARGET_REPORT_DIR + fileName);
             file.getParentFile().mkdirs();
             mapper.writeValue(file, this.built);
diff --git a/core/src/main/java/org/jsmart/zerocode/core/utils/SmartUtils.java b/core/src/main/java/org/jsmart/zerocode/core/utils/SmartUtils.java
index 8e8a8e2b..966f1476 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/utils/SmartUtils.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/utils/SmartUtils.java
@@ -87,6 +87,10 @@ public class SmartUtils {
         return map;
     }
 
+    public static String sanitizeReportFileName(String fileName) {
+    	return fileName.replaceAll("[^A-Za-z0-9 \\-_.]", "_");
+    }
+
     public static List<String> getAllEndPointFiles(String packageName) {
         if(isValidAbsolutePath(packageName)){
             return retrieveScenariosByAbsPath(packageName);


Test patch:
diff --git a/core/src/test/java/org/jsmart/zerocode/core/utils/SmartUtilsTest.java b/core/src/test/java/org/jsmart/zerocode/core/utils/SmartUtilsTest.java
index 247d04ef..a2b7421b 100644
--- a/core/src/test/java/org/jsmart/zerocode/core/utils/SmartUtilsTest.java
+++ b/core/src/test/java/org/jsmart/zerocode/core/utils/SmartUtilsTest.java
@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.Map;
 
 import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -236,6 +237,13 @@ public class SmartUtilsTest {
         assertThat(allScenarios.get(0), containsString("cherry_pick_tests/folder_b/test_case_2.json"));
     }
 
+    @Test
+    public void testSanitizeReportFile() {
+    	String orig = "file !#$%&'()*+,-./09:;<=>?@AZ[]^_`az{|}~\"\\";
+    	String dest = "file ___________-._09_______AZ_____az______";
+    	assertThat(SmartUtils.sanitizeReportFileName(orig), equalTo(dest));
+    }
+
     // Move this to File Util class
     private static File createCascadeIfNotExisting(String fileName) {
         try {