diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6f72ed274..7de760cfa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- #992: Implement automatic history purge logic
- #973: Enables CORS and JWT configuration for WebApplications in module.xml
+- #971: Adds support for JSON, YAML, and Toon formats via the -f flag and new -DUnitTest.*Output directives.
### Fixed
- #1001: The `unmap` and `enable` commands will now only activate CPF merge once after all namespaces have been configured instead after every namespace
diff --git a/preload/cls/IPM/Installer.cls b/preload/cls/IPM/Installer.cls
index 26970544b..02916635b 100644
--- a/preload/cls/IPM/Installer.cls
+++ b/preload/cls/IPM/Installer.cls
@@ -113,6 +113,7 @@ ClassMethod ZPMInit(
$$$QuitOnError(##class(%IPM.Repo.UniversalSettings).SetValue("UseStandalonePip", "", 0))
$$$QuitOnError(##class(%IPM.Repo.UniversalSettings).SetValue("SemVerPostRelease", 0, 0))
$$$QuitOnError(##class(%IPM.Repo.UniversalSettings).SetValue("DefaultLogEntryLimit",20, 0))
+ $$$QuitOnError(##class(%IPM.Repo.UniversalSettings).SetValue("TestReportFormat","toon", 0))
quit $$$OK
}
diff --git a/src/cls/IPM/Main.cls b/src/cls/IPM/Main.cls
index 64f7e2819..d6b65e204 100644
--- a/src/cls/IPM/Main.cls
+++ b/src/cls/IPM/Main.cls
@@ -75,6 +75,7 @@ Can also specify desired version to update to.
+
diff --git a/src/cls/IPM/Repo/UniversalSettings.cls b/src/cls/IPM/Repo/UniversalSettings.cls
index e1ff1f3ed..f644c3dc7 100644
--- a/src/cls/IPM/Repo/UniversalSettings.cls
+++ b/src/cls/IPM/Repo/UniversalSettings.cls
@@ -45,7 +45,10 @@ Parameter SemVerPostRelease = "SemVerPostRelease";
/// to retain IPM history records before they are eligible for cleanup.
Parameter HistoryRetain = "history_retain";
-Parameter CONFIGURABLE = "trackingId,analytics,ColorScheme,TerminalPrompt,PublishTimeout,PipCaller,UseStandalonePip,SemVerPostRelease,DefaultLogEntryLimit,HistoryRetain";
+/// Specifies the serialization format (JSON, TOON, YAML) for unit and integration test results in the shell.
+Parameter TestReportFormat = "TestReportFormat";
+
+Parameter CONFIGURABLE = "trackingId,analytics,ColorScheme,TerminalPrompt,PublishTimeout,PipCaller,UseStandalonePip,SemVerPostRelease,DefaultLogEntryLimit,HistoryRetain,TestReportFormat";
/// Returns configArray, that includes all configurable settings
ClassMethod GetAll(Output configArray) As %Status
@@ -190,4 +193,16 @@ ClassMethod GetHistoryRetain() As %Integer
return ..GetValue(..#HistoryRetain)
}
+ClassMethod SetTestReportFormat(
+ val As %String,
+ overwrite As %Boolean = 1) As %Boolean
+{
+ return ..SetValue(..#TestReportFormat, val, overwrite)
+}
+
+ClassMethod GetTestReportFormat() As %String
+{
+ return ..GetValue(..#TestReportFormat)
+}
+
}
diff --git a/src/cls/IPM/ResourceProcessor/Test.cls b/src/cls/IPM/ResourceProcessor/Test.cls
index efb500c85..070aba8f4 100644
--- a/src/cls/IPM/ResourceProcessor/Test.cls
+++ b/src/cls/IPM/ResourceProcessor/Test.cls
@@ -189,23 +189,54 @@ Method OnPhase(
zkill ^UnitTestRoot
$$$ThrowOnError(tSC)
- if $data(pParams("UnitTest","JUnitOutput"),tJUnitFile) {
- set tPostfix = "-"_$zconvert(pPhase,"L")_"-"
- if (..Package '= "") {
- set tPostfix = tPostfix_$replace(..Package,".","-")_"-PKG"
- } elseif (..Class '= "") {
- set tPostfix = tPostfix_$replace(..Class,".","-")_"-CLS"
+ if $data(pParams("UnitTest"))>1 {
+ set outputType=""
+ for {
+ set outputType = $order(pParams("UnitTest",outputType),1,fileName)
+ quit:outputType=""
+ set tPostfix = "-"_$$$lcase(pPhase)_"-"
+ if (..Package '= "") {
+ set tPostfix = tPostfix_$replace(..Package,".","-")_"-PKG"
+ } elseif (..Class '= "") {
+ set tPostfix = tPostfix_$replace(..Class,".","-")_"-CLS"
+ }
+ set outputClass = "%IPM.Test."_outputType
+ if '$$$defClassDefined(outputClass) {
+ $$$ThrowOnError($$$ERROR($$$GeneralError,"The requested "_outputType_" output format does not exist."))
+ }
+ set extension = $select(outputType="JsonOutput":".json",outputType="ToonOutput":".toon",outputType="YamlOutput":".yaml",1:".xml")
+ set fileName = $piece(fileName,".",1,*-1)_tPostfix_extension
+ set tSC = $classmethod(outputClass,"ToFile",fileName)
+ $$$ThrowOnError(tSC)
}
- set tJUnitFile = $piece(tJUnitFile,".",1,*-1)_tPostfix_".xml"
- set tSC = ##class(%IPM.Test.JUnitOutput).ToFile(tJUnitFile)
- $$$ThrowOnError(tSC)
}
+ write !
+ if $data(pParams("outputformat"),outputFormat)||('tVerbose) {
+ write !,"Test result summary",!
+ set defaultOutputFormat = ##class(%IPM.Repo.UniversalSettings).GetTestReportFormat()
+ if defaultOutputFormat'="" {
+ set outputFormat = defaultOutputFormat
+ }
+ else {
+ if $get(outputFormat)="" {
+ set outputFormat="Toon"
+ }
+ }
+ set outputClass = "%IPM.Test."_$zconvert(outputFormat,"w")_"Output"
+ if '$$$defClassDefined(outputClass) {
+ $$$ThrowOnError($$$ERROR($$$GeneralError,"The requested "_outputType_" output format does not exist."))
+ }
+ set defaultTestStatus = "failed"
+ set sc = $classmethod(outputClass,"OutputToDevice",,defaultTestStatus)
+ $$$ThrowOnError(sc)
+ write !
+ }
// By default, detect and report unit test failures as an error from this phase
if $get(pParams("UnitTest","FailuresAreFatal"),1) {
do ##class(%IPM.Test.Manager).OutputFailures()
- set tSC = ##class(%IPM.Test.Manager).GetLastStatus()
- $$$ThrowOnError(tSC)
+ set sc = ##class(%IPM.Test.Manager).GetLastStatus()
+ $$$ThrowOnError(sc)
}
write !
}
diff --git a/src/cls/IPM/Test/Abstract.cls b/src/cls/IPM/Test/Abstract.cls
new file mode 100644
index 000000000..c64cc3817
--- /dev/null
+++ b/src/cls/IPM/Test/Abstract.cls
@@ -0,0 +1,68 @@
+/// The class serves as the base class for all the unit test result formatting.
+Class %IPM.Test.Abstract Extends %RegisteredObject
+{
+
+ClassMethod ToFile(
+ FileName As %String,
+ CaseStatus As %String = "",
+ TestIndex As %Integer = {$order(^UnitTest.Result(""),-1)}) As %Status [ Abstract ]
+{
+}
+
+ClassMethod OutputToDevice(
+ TestIndex As %Integer = {$order(^UnitTest.Result(""),-1)},
+ TestStatus As %String = "") [ Abstract ]
+{
+}
+
+Query FilteredTestResults(
+ Instance As %Integer,
+ TestStatus) As %SQLQuery(ROWSPEC = "TotalCounts:%Integer,namespace:%String,duration:%String,testDateTime:%String,suiteName:%String,testcaseName:%String,methodName:%String,testMethod:%String,assertAction:%String,assertCounter:%Integer,assertDescription:%String,assertLocation:%String", SELECTMODE = "DISPLAY")
+{
+SELECT
+ count(*) as TotalCounts,
+ tinstance.Namespace AS namespace,
+ tinstance.Duration AS duration,
+ tinstance.DateTime AS testDateTime,
+ tsuite.Name AS suiteName,
+ tcase.Name AS testcaseName,
+ tmethod.Name AS methodName,
+ tassert.TestMethod AS testMethod,
+ tassert.Action AS assertAction,
+ tassert.Counter AS assertCounter,
+ tassert.Description AS assertDescription,
+ tassert.Location AS assertLocation
+FROM
+%UnitTest_Result.TestInstance tinstance
+JOIN %UnitTest_Result.TestSuite tsuite ON tsuite.TestInstance=tinstance.ID
+JOIN %UnitTest_Result.TestCase tcase ON tcase.TestSuite=tsuite.ID
+JOIN %UnitTest_Result.TestMethod tmethod ON tmethod.TestCase=tcase.ID
+JOIN %UnitTest_Result.TestAssert tassert ON tassert.TestMethod=tmethod.ID
+WHERE tinstance.ID=:Instance AND tassert.Status=:TestStatus
+}
+
+Query GetAllTestResults(Instance As %Integer) As %SQLQuery(ROWSPEC = "TotalCounts:%String,namespace:%String,duration:%String,testDateTime:%String,suiteName:%String,testcaseName:%String,methodName:%String,testMethod:%String,assertAction:%String,assertCounter:%Integer,assertDescription:%String,assertLocation:%String", SELECTMODE = "DISPLAY")
+{
+SELECT
+ count(*) as TotalCounts,
+ tinstance.Namespace AS namespace,
+ tinstance.Duration AS duration,
+ tinstance.DateTime AS testDateTime,
+ tsuite.Name AS suiteName,
+ tcase.Name AS testcaseName,
+ tmethod.Name AS methodName,
+ tassert.TestMethod AS testMethod,
+ tassert.Action AS assertAction,
+ tassert.Counter AS assertCounter,
+ tassert.Description AS assertDescription,
+ tassert.Location AS assertLocation
+FROM
+%UnitTest_Result.TestInstance tinstance
+JOIN %UnitTest_Result.TestSuite tsuite ON tsuite.TestInstance=tinstance.ID
+JOIN %UnitTest_Result.TestCase tcase ON tcase.TestSuite=tsuite.ID
+JOIN %UnitTest_Result.TestMethod tmethod ON tmethod.TestCase=tcase.ID
+JOIN %UnitTest_Result.TestAssert tassert ON tassert.TestMethod=tmethod.ID
+WHERE tinstance.ID=:Instance
+}
+
+}
diff --git a/src/cls/IPM/Test/JsonOutput.cls b/src/cls/IPM/Test/JsonOutput.cls
new file mode 100644
index 000000000..dac91487d
--- /dev/null
+++ b/src/cls/IPM/Test/JsonOutput.cls
@@ -0,0 +1,93 @@
+Class %IPM.Test.JsonOutput Extends %IPM.Test.Abstract
+{
+
+ClassMethod ToFile(
+ FileName As %String,
+ TestStatus As %String = "",
+ TestIndex As %Integer = {$order(^UnitTest.Result(""),-1)}) As %Status
+{
+ set sc = $$$OK
+ try {
+ set fileStream = ##class(%Stream.FileCharacter).%New()
+ set fileStream.TranslateTable = "UTF8"
+ $$$ThrowOnError(fileStream.LinkToFile(FileName))
+ set responseJson = ..JSON(TestIndex, TestStatus)
+ if $isobject(responseJson) {
+ do fileStream.Write(responseJson.%ToJSON())
+ }
+ $$$ThrowOnError(fileStream.%Save())
+ } catch ex {
+ set sc = ex.AsStatus()
+ }
+ return sc
+}
+
+ClassMethod OutputToDevice(
+ TestIndex As %Integer = {$order(^UnitTest.Result(""),-1)},
+ pCaseStatus As %String = "") As %Status
+{
+ set sc = $$$OK
+ try {
+ set responseJson = ..JSON(TestIndex, pCaseStatus)
+ write !
+ if $isobject(responseJson) {
+ do responseJson.%ToJSON()
+ }
+ } catch ex {
+ set sc = ex.AsStatus()
+ }
+ return sc
+}
+
+ClassMethod JSON(
+ TestIndex As %Integer,
+ TestStatus As %String) As %DynamicObject
+{
+ if TestStatus'="" {
+ set tResult = ..FilteredTestResultsFunc(TestIndex, TestStatus)
+ } else {
+ set tResult = ..GetAllTestResultsFunc(TestIndex)
+ }
+ set unitTest = {}
+ set unitTest.results = []
+ set (previousID,currentSuite,currentTestcase,suiteObj,testcaseObj) = ""
+
+ while tResult.%Next() {
+ if previousID = "" {
+ set unitTest.id = TestIndex
+ set unitTest.namespace = tResult.namespace
+ set unitTest.duration = tResult.duration
+ set unitTest.testDateTime = tResult.testDateTime
+ }
+ set previousID = TestIndex
+ if tResult.suiteName '= currentSuite {
+ set currentSuite = tResult.suiteName
+ set suiteObj = {
+ "suiteName": (currentSuite),
+ "testcases": []
+ }
+ do unitTest.results.%Push(suiteObj)
+ set currentTestcase = ""
+ }
+ if tResult.testcaseName '= currentTestcase {
+ set currentTestcase = tResult.testcaseName
+ set testcaseObj = {
+ "testcaseName": (currentTestcase),
+ "methods": []
+ }
+ do suiteObj.testcases.%Push(testcaseObj)
+ }
+ set methodObj = {
+ "methodName": (tResult.methodName),
+ "testMethod": (tResult.testMethod),
+ "assertAction": (tResult.assertAction),
+ "assertCounter": (tResult.assertCounter),
+ "assertDescription": (tResult.assertDescription),
+ "assertLocation": (tResult.assertLocation)
+ }
+ do testcaseObj.methods.%Push(methodObj)
+ }
+ return unitTest
+}
+
+}
diff --git a/src/cls/IPM/Test/ToonOutput.cls b/src/cls/IPM/Test/ToonOutput.cls
new file mode 100644
index 000000000..f0826a21f
--- /dev/null
+++ b/src/cls/IPM/Test/ToonOutput.cls
@@ -0,0 +1,77 @@
+Class %IPM.Test.ToonOutput Extends %IPM.Test.Abstract
+{
+
+ClassMethod ToFile(
+ FileName As %String,
+ TestStatus As %String = "",
+ TestIndex As %Integer = {$order(^UnitTest.Result(""),-1)}) As %Status
+{
+ set sc = $$$OK
+ try {
+ set fileStream = ##class(%Stream.FileCharacter).%New()
+ set fileStream.TranslateTable = "UTF8"
+ $$$ThrowOnError(fileStream.LinkToFile(FileName))
+
+ if TestStatus'="" {
+ set tResult = ..FilteredTestResultsFunc(TestIndex, TestStatus)
+ } else {
+ set tResult = ..GetAllTestResultsFunc(TestIndex)
+ }
+
+ set currentID=""
+ while tResult.%Next() {
+ if currentID = "" {
+ set currentID = TestIndex
+ do fileStream.WriteLine("unitTest:")
+ do fileStream.WriteLine(" id: "_TestIndex)
+ do fileStream.WriteLine(" namespace: "_tResult.namespace)
+ do fileStream.WriteLine(" duration: "_tResult.duration)
+ do fileStream.WriteLine(" testDateTime: "_tResult.testDateTime)
+ do fileStream.WriteLine()
+ do fileStream.WriteLine("results["_tResult.TotalCounts_"]{suiteName,testcaseName,methodName,status,assertAction,assertCounter,assertDescription,assertLocation}:")
+ }
+ set data = " "_tResult.suiteName_","_tResult.testcaseName_","_tResult.methodName_","_TestIndex_","_
+ tResult.assertAction_","_tResult.assertCounter_","""_$translate(tResult.assertDescription,"""")_""","""_tResult.assertLocation_""""
+ do fileStream.WriteLine(data)
+ }
+ $$$ThrowOnError(fileStream.%Save())
+ } catch ex {
+ set sc = ex.AsStatus()
+ }
+ return sc
+}
+
+ClassMethod OutputToDevice(
+ TestIndex As %Integer = {$order(^UnitTest.Result(""),-1)},
+ TestStatus As %String = "") As %Status
+{
+ set sc = $$$OK
+ try {
+ if TestStatus'="" {
+ set tResult = ..FilteredTestResultsFunc(TestIndex, TestStatus)
+ } else {
+ set tResult = ..GetAllTestResultsFunc(TestIndex)
+ }
+ set currentID=""
+ while tResult.%Next() {
+ if currentID = "" {
+ set currentID = TestIndex
+ write !,"unitTest:"
+ write !," id: "_TestIndex
+ write !," namespace: "_tResult.namespace
+ write !," duration: "_tResult.duration
+ write !," testDateTime: "_tResult.testDateTime
+ write !
+ write !,"results["_tResult.TotalCounts_"]{suiteName,testcaseName,methodName,status,assertAction,assertCounter,assertDescription,assertLocation}:"
+ }
+ set data = " "_tResult.suiteName_","_tResult.testcaseName_","_tResult.methodName_","_TestIndex_","_
+ tResult.assertAction_","_tResult.assertCounter_","""_$translate(tResult.assertDescription,"""")_""","""_tResult.assertLocation_""""
+ write !,data
+ }
+ } catch ex {
+ set sc = ex.AsStatus()
+ }
+ return sc
+}
+
+}
diff --git a/src/cls/IPM/Test/YamlOutput.cls b/src/cls/IPM/Test/YamlOutput.cls
new file mode 100644
index 000000000..bc6c1d229
--- /dev/null
+++ b/src/cls/IPM/Test/YamlOutput.cls
@@ -0,0 +1,83 @@
+Class %IPM.Test.YamlOutput Extends %IPM.Test.Abstract
+{
+
+ClassMethod ToFile(
+ FileName As %String,
+ TestStatus As %String = "",
+ TestIndex As %Integer = {$order(^UnitTest.Result(""),-1)}) As %Status
+{
+ set sc = $$$OK
+ try {
+ set fileStream = ##class(%Stream.FileCharacter).%New()
+ set fileStream.TranslateTable = "UTF8"
+ $$$ThrowOnError(fileStream.LinkToFile(FileName))
+ do fileStream.CopyFrom(..YAML(TestIndex, TestStatus))
+ $$$ThrowOnError(fileStream.%Save())
+ } catch ex {
+ set sc = ex.AsStatus()
+ }
+ return sc
+}
+
+ClassMethod OutputToDevice(
+ TestIndex As %Integer = {$order(^UnitTest.Result(""),-1)},
+ TestStatus As %String = "") As %Status
+{
+ set sc = $$$OK
+ try {
+ set yamlStream = ..YAML(TestIndex, TestStatus)
+ write !
+ while 'yamlStream.AtEnd {
+ write yamlStream.Read()
+ }
+ } catch ex {
+ set sc = ex.AsStatus()
+ }
+ return sc
+}
+
+ClassMethod YAML(
+ TestIndex = {$order(^UnitTest.Result(""),-1)},
+ TestStatus As %String = "") As %Stream.TmpCharacter
+{
+ if TestStatus'="" {
+ set tResult = ..FilteredTestResultsFunc(TestIndex, TestStatus)
+ } else {
+ set tResult = ..GetAllTestResultsFunc(TestIndex)
+ }
+ set yamlStream = ##class(%Stream.TmpCharacter).%New()
+ set (yaml,currentID,currentSuite,currentTestcase) = ""
+ while tResult.%Next() {
+ if currentID = "" {
+ set currentID = TestIndex
+ do yamlStream.WriteLine("unitTest:")
+ do yamlStream.WriteLine(" id: "_TestIndex)
+ do yamlStream.WriteLine(" namespace: """_tResult.namespace_"""")
+ do yamlStream.WriteLine(" duration: "_tResult.duration)
+ do yamlStream.WriteLine(" testDateTime: """_tResult.testDateTime_"""")
+ do yamlStream.WriteLine()
+ do yamlStream.WriteLine(" results:")
+ }
+ if tResult.suiteName '= currentSuite {
+ set currentSuite = tResult.suiteName
+ set currentTestcase = ""
+ do yamlStream.WriteLine(" - suiteName: """_tResult.suiteName_"""")
+ do yamlStream.WriteLine(" testcases:")
+ }
+ if tResult.testcaseName '= currentTestcase {
+ set currentTestcase = tResult.testcaseName
+ do yamlStream.WriteLine(" - testcaseName: """_tResult.testcaseName_"""")
+ do yamlStream.WriteLine(" methods:")
+ }
+ do yamlStream.WriteLine(" - methodName: """_tResult.methodName_"""")
+ do yamlStream.WriteLine(" testMethod: """_tResult.testMethod_"""")
+ do yamlStream.WriteLine(" assertAction: """_tResult.assertAction_"""")
+ do yamlStream.WriteLine(" assertCounter: "_tResult.assertCounter)
+ do yamlStream.WriteLine(" assertDescription: |")
+ do yamlStream.WriteLine(" "_$replace(tResult.assertDescription, $char(10), $char(10)_" "))
+ do yamlStream.WriteLine(" assertLocation: """_tResult.assertLocation_"""")
+ }
+ return yamlStream
+}
+
+}
diff --git a/tests/unit_tests/Test/PM/Unit/CLI.cls b/tests/unit_tests/Test/PM/Unit/CLI.cls
index 8e9f2329a..797ce4541 100644
--- a/tests/unit_tests/Test/PM/Unit/CLI.cls
+++ b/tests/unit_tests/Test/PM/Unit/CLI.cls
@@ -352,4 +352,16 @@ Method TestUninstallWithoutModuleName()
do $$$AssertNotTrue(exists, "Module removed successfully.")
}
+/// Specifies the serialization format (json, toon, yaml) for unit and integration test results in the shell.
+Method TestReportFormatConfiguration()
+{
+ do ..RunCommand("config set TestReportFormat json")
+ set format = ##class(%IPM.Repo.UniversalSettings).GetTestReportFormat()
+ do $$$AssertEquals(format, "json", "Verify TestReportFormat is set to JSON")
+
+ do ..RunCommand("config set TestReportFormat yaml")
+ set format = ##class(%IPM.Repo.UniversalSettings).GetTestReportFormat()
+ do $$$AssertEquals(format, "yaml", "Verify TestReportFormat is set to YAML")
+}
+
}
diff --git a/tests/unit_tests/Test/PM/Unit/TestResultsOPFormatAndFileGenTest.cls b/tests/unit_tests/Test/PM/Unit/TestResultsOPFormatAndFileGenTest.cls
new file mode 100644
index 000000000..354eaa0d3
--- /dev/null
+++ b/tests/unit_tests/Test/PM/Unit/TestResultsOPFormatAndFileGenTest.cls
@@ -0,0 +1,59 @@
+/// Unit Test Class to validate the ZPM 'test' command output configuration.
+/// This class ensures two primary functions work correctly:
+/// 1. Console Formatting: Verifies the `-f` / `-output` flags correctly
+/// format test results for terminal display (e.g., YAML, JSON).
+/// 2. File Generation: Verifies the `-DUnitTest.Output` definitions
+/// successfully create and populate the structured results files (e.g., .json, .yaml, .toon).
+Class Test.PM.Unit.TestResultsOPFormatAndFileGenTest Extends %UnitTest.TestCase
+{
+
+/// generate .yaml,.json,.toon files
+Method TestResultFileGeneration()
+{
+ #define NormalizeFilename(%file) ##class(%File).NormalizeFilename(%file)
+
+ do $$$LogMessage("This file generation picks the last or current unit test id and generate the reports")
+
+ set fileDir = ##class(%File).NormalizeDirectory($get(^UnitTestRoot)_"/test-reports/")
+ if '##class(%File).DirectoryExists(fileDir){
+ set status = ##class(%File).CreateDirectoryChain(fileDir)
+ do $$$AssertStatusOK(status,"Directory created: "_fileDir)
+ }
+
+ do $$$LogMessage("Start generating the reports")
+ set fileName = $$$NormalizeFilename(fileDir_"/test.yaml")
+ set status = ##class(%IPM.Test.YamlOutput).ToFile(fileName)
+ do $$$AssertStatusOK(status,"yaml file generated successfully in "_fileDir)
+
+ set fileName = $$$NormalizeFilename(fileDir_"/test.Json")
+ set status = ##class(%IPM.Test.JsonOutput).ToFile(fileName)
+ do $$$AssertStatusOK(status,"Json file generated successfully in "_fileDir)
+
+ set fileName = $$$NormalizeFilename(fileDir_"/test.toon")
+ set status = ##class(%IPM.Test.ToonOutput).ToFile(fileName)
+ do $$$AssertStatusOK(status,"Toon file generated successfully in "_fileDir)
+
+ do ..ShowGeneratedFilesAndCleaup(fileDir)
+}
+
+Method ShowGeneratedFilesAndCleaup(FileDir As %String)
+{
+ do $$$LogMessage("Display the generated unit test report files")
+ set fileSet = ##class(%File).FileSetFunc(FileDir)
+ while fileSet.%Next() {
+ set file = fileSet.Name
+ set fileNames(file) = fileSet.ItemName
+ do $$$LogMessage("Generated file "_file)
+ }
+ do $$$LogMessage("Started Cleanup the generated unit test report files")
+ set file = ""
+ for {
+ set file = $order(fileNames(file),1,fileName)
+ quit:file=""
+ set status = ##class(%File).Delete(file)
+ do $$$AssertStatusOK(status," File '"_fileName_"' has been deleted successfully")
+ }
+ do $$$LogMessage("File cleanup completed")
+}
+
+}