diff --git a/data/xml/javax-package-custom-target.windup.xml b/data/xml/javax-package-custom-target.windup.xml
new file mode 100644
index 0000000..2064af1
--- /dev/null
+++ b/data/xml/javax-package-custom-target.windup.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ This ruleset evaluates whether a custom target can be used within a custom rule
+
+
+
+
+
+
+
+
+
+
+
+ IMPORT
+
+
+
+
+ `javax.*` packages must be renamed to `jakarta.*` for Jakarta EE9 compatibility.
+
+
+
+
+
+
diff --git a/data/xml/javax-package-custom.windup.xml b/data/xml/javax-package-custom.windup.xml
new file mode 100644
index 0000000..15af7b0
--- /dev/null
+++ b/data/xml/javax-package-custom.windup.xml
@@ -0,0 +1,25 @@
+
+
+ This ruleset provides analysis of applications that use RESTEasy 3.0 and may require individual attention when migrating to RESTEasy 3.6.
+
+
+
+
+
+
+
+
+
+ IMPORT
+
+
+
+
+ `javax.*` packages must be renamed to `jakarta.*` for Jakarta EE9 compatibility.
+
+ tag
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/test_advanced_options.py b/tests/test_advanced_options.py
index 2c66524..3e4e688 100644
--- a/tests/test_advanced_options.py
+++ b/tests/test_advanced_options.py
@@ -3,6 +3,7 @@
from utils.command import build_command
from utils.report import assert_story_points_from_report_file
+from utils.report import assert_valid_csv
def test_skip_report(analysis_data):
@@ -65,3 +66,45 @@ def test_transaction_analysis(analysis_data):
assert_story_points_from_report_file(application_data['story_points'])
assert os.path.exists(report_path + '/reports/divareport_petclinic.html') is True
+
+
+def test_csv_report(analysis_data):
+ application_data = analysis_data['jee_example_app']
+ report_path = os.getenv('REPORT_OUTPUT_PATH')
+
+ command = build_command(
+ application_data['file_name'],
+ application_data['source'],
+ application_data['target'],
+ **{'exportCSV': ''}
+ )
+ output = subprocess.run(command, shell=True, check=True, stdout=subprocess.PIPE, encoding='utf-8').stdout
+
+ assert 'Report created' in output
+
+ assert_valid_csv(os.path.join(report_path, 'AllIssues.csv'))
+ assert_valid_csv(os.path.join(report_path, 'ApplicationFileTechnologies.csv'))
+ assert_valid_csv(os.path.join(report_path, 'jee_example_app_1_0_0_ear.csv'))
+
+
+def test_custom_rules_analysis(analysis_data):
+ application_data = analysis_data['complete_duke']
+ report_path = os.getenv('REPORT_OUTPUT_PATH')
+ custom_rule_path = os.path.join(os.getenv('PROJECT_PATH'), 'data/xml', 'javax-package-custom.windup.xml')
+
+ command = build_command(
+ application_data['file_name'],
+ application_data['source'],
+ application_data['target'],
+ **{'userRulesDirectory': custom_rule_path}
+ )
+
+ output = subprocess.run(command, shell=True, check=True, stdout=subprocess.PIPE, encoding='utf-8').stdout
+ assert 'Report created' in output
+
+ migration_issues_path = os.path.join(report_path, 'reports/migration_issues.html')
+ assert os.path.exists(migration_issues_path) is True
+
+ with open(migration_issues_path) as file:
+ file_content = file.read()
+ assert 'CUSTOM RULE for javax.* package import' in file_content
diff --git a/utils/report.py b/utils/report.py
index c192a8a..8982e1d 100644
--- a/utils/report.py
+++ b/utils/report.py
@@ -1,3 +1,4 @@
+import csv
import os
from bs4 import BeautifulSoup
@@ -13,3 +14,28 @@ def assert_story_points_from_report_file(story_points):
report_story_points = int(parsed_report.find('span', class_='points').text)
assert report_story_points == story_points
+
+
+def assert_valid_csv(csv_file_path, **kwargs):
+ """
+ Asserts that the given CSV file is valid.
+ A CSV file is considered valid if it exists and all of its rows have the same number of columns.
+
+ Args:
+ csv_file_path (str): The file path of the CSV file to validate.
+ **kwargs (str): Optional keyword arguments.
+ delimiter (str): The delimiter used in the CSV file. Defaults to ','.
+
+ Raises:
+ AssertionError: If the CSV file does not exist or if its rows have different numbers of columns.
+
+ Returns:
+ None.
+ """
+ assert os.path.exists(csv_file_path) is True
+ delimiter = kwargs.get('delimiter', ',')
+
+ with open(csv_file_path, mode='r') as csv_file:
+ csv_reader = csv.DictReader(csv_file, delimiter=delimiter)
+ columns_number = len(next(csv_reader))
+ assert all(len(row) == columns_number for row in csv_reader) is True