From 8d9c22a461d32febcc9871352bd2af561eba95b2 Mon Sep 17 00:00:00 2001 From: Pascal Wolterink Date: Fri, 1 Nov 2024 12:07:31 +0100 Subject: [PATCH 1/2] escape characters in xml --- TcUnit/TcUnit/POUs/FB_xUnitXmlPublisher.TcPOU | 4 +-- .../POUs/Functions/F_XmlEscapeString.TcPOU | 35 +++++++++++++++++++ TcUnit/TcUnit/TcUnit.plcproj | 5 ++- 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 TcUnit/TcUnit/POUs/Functions/F_XmlEscapeString.TcPOU diff --git a/TcUnit/TcUnit/POUs/FB_xUnitXmlPublisher.TcPOU b/TcUnit/TcUnit/POUs/FB_xUnitXmlPublisher.TcPOU index 741e7ee..a0d7416 100644 --- a/TcUnit/TcUnit/POUs/FB_xUnitXmlPublisher.TcPOU +++ b/TcUnit/TcUnit/POUs/FB_xUnitXmlPublisher.TcPOU @@ -115,7 +115,7 @@ IF PublishTrigger.Q THEN FOR CurrentTestCount := 1 TO UnitTestResults.TestSuiteResults[CurrentSuiteNumber].NumberOfTests BY 1 DO // Xml.NewTag('testcase'); - Xml.NewParameter('name', UnitTestResults.TestSuiteResults[CurrentSuiteNumber].TestCaseResults[CurrentTestCount].TestName); + Xml.NewParameter('name', F_XmlEscapeString(UnitTestResults.TestSuiteResults[CurrentSuiteNumber].TestCaseResults[CurrentTestCount].TestName)); Xml.NewParameter('classname', UnitTestResults.TestSuiteResults[CurrentSuiteNumber].TestCaseResults[CurrentTestCount].TestClassName); Xml.NewParameter('time', LREAL_TO_STRING(UnitTestResults.TestSuiteResults[CurrentSuiteNumber].TestCaseResults[CurrentTestCount].Duration)); @@ -133,7 +133,7 @@ IF PublishTrigger.Q THEN *) Xml.NewTag('failure'); - Xml.NewParameter('message', UnitTestResults.TestSuiteResults[CurrentSuiteNumber].TestCaseResults[CurrentTestCount].FailureMessage); + Xml.NewParameter('message', F_XmlEscapeString(UnitTestResults.TestSuiteResults[CurrentSuiteNumber].TestCaseResults[CurrentTestCount].FailureMessage)); Xml.NewParameter('type', F_AssertionTypeToString(UnitTestResults.TestSuiteResults[CurrentSuiteNumber].TestCaseResults[CurrentTestCount].FailureType)); // Close failure tag Xml.CloseTag(); diff --git a/TcUnit/TcUnit/POUs/Functions/F_XmlEscapeString.TcPOU b/TcUnit/TcUnit/POUs/Functions/F_XmlEscapeString.TcPOU new file mode 100644 index 0000000..08c11bd --- /dev/null +++ b/TcUnit/TcUnit/POUs/Functions/F_XmlEscapeString.TcPOU @@ -0,0 +1,35 @@ + + + + '; + AMP : STRING(1) := '&'; + + ESCAPED_QUOTE : STRING(6) := '"'; + ESCAPED_APOS : STRING(6) := '''; + ESCAPED_LT : STRING(4) := '<'; + ESCAPED_GT : STRING(4) := '>'; + ESCAPED_AMP : STRING(5) := '&'; +END_VAR]]> + + + + + \ No newline at end of file diff --git a/TcUnit/TcUnit/TcUnit.plcproj b/TcUnit/TcUnit/TcUnit.plcproj index 89fb59a..2d1b6b5 100644 --- a/TcUnit/TcUnit/TcUnit.plcproj +++ b/TcUnit/TcUnit/TcUnit.plcproj @@ -1,4 +1,4 @@ - + @@ -161,6 +161,9 @@ Documentation and examples are available at www.tcunit.org Code + + Code + Code From 870517c3a28d1e8853be4f403f75749032b0c507 Mon Sep 17 00:00:00 2001 From: Pascal Wolterink Date: Fri, 1 Nov 2024 14:42:48 +0100 Subject: [PATCH 2/2] Added tests --- .../TcUnit-Verifier/FB_TestXUnitPublisher.cs | 40 +++++++++++++++++++ .../TcUnit-Verifier/Program.cs | 7 +++- .../TcUnit-Verifier/TcUnit-Verifier.csproj | 1 + .../TestFunctionBlockAssert.cs | 2 +- .../TcUnitVerifier/TcUnitVerifier.plcproj | 9 +++++ .../Test/FB_TestXUnitPublisher.TcPOU | 29 ++++++++++++++ .../TcUnitVerifier/Test/PRG_TEST.TcPOU | 1 + 7 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 TcUnit-Verifier/TcUnit-Verifier_DotNet/TcUnit-Verifier/FB_TestXUnitPublisher.cs create mode 100644 TcUnit-Verifier/TcUnit-Verifier_TwinCAT/TcUnit-Verifier_TwinCAT/TcUnitVerifier/Test/FB_TestXUnitPublisher.TcPOU diff --git a/TcUnit-Verifier/TcUnit-Verifier_DotNet/TcUnit-Verifier/FB_TestXUnitPublisher.cs b/TcUnit-Verifier/TcUnit-Verifier_DotNet/TcUnit-Verifier/FB_TestXUnitPublisher.cs new file mode 100644 index 0000000..67f3b32 --- /dev/null +++ b/TcUnit-Verifier/TcUnit-Verifier_DotNet/TcUnit-Verifier/FB_TestXUnitPublisher.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Xml.Linq; + +namespace TcUnit.Verifier +{ + class FB_TestXUnitPublisher : TestFunctionBlockAssert + { + public FB_TestXUnitPublisher(IEnumerable errors, string xmlTestResultsFilePath, string testFunctionBlockInstance = null) + : base(errors, testFunctionBlockInstance) + { + Test_ParceXml(xmlTestResultsFilePath); + Test_EscapedFailedMessage(); + Test_EscapedFunctionName(); + } + private void Test_ParceXml(string xmlTestResultsFilePath) + { + try + { + XDocument _ = XDocument.Load(xmlTestResultsFilePath); + } + catch (Exception) + { + log.Info("Test suite " + _testFunctionBlockInstance + " could not parse xml file: " + xmlTestResultsFilePath); + } + + } + private void Test_EscapedFailedMessage() + { + string testMessage = "PRG_TEST." + _testFunctionBlockInstance + "@Test_EscapedFailedMessage"; + AssertContainsMessage(testMessage, EnvDTE80.vsBuildErrorLevel.vsBuildErrorLevelHigh); + } + + private void Test_EscapedFunctionName() + { + string testMessage = "PRG_TEST." + _testFunctionBlockInstance + "@Test_EscapedFunctionName"; + AssertDoesNotContainMessage(testMessage, EnvDTE80.vsBuildErrorLevel.vsBuildErrorLevelHigh); + } + } +} diff --git a/TcUnit-Verifier/TcUnit-Verifier_DotNet/TcUnit-Verifier/Program.cs b/TcUnit-Verifier/TcUnit-Verifier_DotNet/TcUnit-Verifier/Program.cs index b544b1a..6e0a2b2 100644 --- a/TcUnit-Verifier/TcUnit-Verifier_DotNet/TcUnit-Verifier/Program.cs +++ b/TcUnit-Verifier/TcUnit-Verifier_DotNet/TcUnit-Verifier/Program.cs @@ -1,4 +1,4 @@ -using NDesk.Options; +using NDesk.Options; using log4net; using System; using System.Collections.Generic; @@ -16,9 +16,10 @@ class Program { private static string tcUnitVerifierPath = null; private static string tcUnitTargetNetId = "127.0.0.1.1.1"; + private static string tcUnitXUnitFilePath = @"C:\TwinCAT\3.1\Boot\tcunit_xunit_testresults.xml"; private static VisualStudioInstance vsInstance = null; private static ILog log = LogManager.GetLogger("TcUnit-Verifier"); - private static int expectedNumberOfFailedTests = 121; // Update this if you add intentionally failing tests + private static int expectedNumberOfFailedTests = 122; // Update this if you add intentionally failing tests [STAThread] static void Main(string[] args) @@ -31,6 +32,7 @@ static void Main(string[] args) OptionSet options = new OptionSet() .Add("v=|TcUnitVerifierPath=", "Path to TcUnit-Verifier TwinCAT solution", v => tcUnitVerifierPath = v) .Add("t=|TcUnitTargetNetId=", "[OPTIONAL] Target NetId of TwinCAT runtime to run TcUnit-Verifier", t => tcUnitTargetNetId = t) + .Add("x=|TcUnitXUnitFilePath=", "[OPTIONAL] path and filename for the TcUnit-Verifier xunit testresults", t => tcUnitXUnitFilePath = t) .Add("?|h|help", h => showHelp = h != null); try @@ -213,6 +215,7 @@ static void Main(string[] args) new FB_TestDurationMeasurement(errors); new FB_EmptyAssertionMessage(errors); new FB_AssertCountExceedsMaxNumber(errors); + new FB_TestXUnitPublisher(errors, tcUnitXUnitFilePath); log.Info("Done."); diff --git a/TcUnit-Verifier/TcUnit-Verifier_DotNet/TcUnit-Verifier/TcUnit-Verifier.csproj b/TcUnit-Verifier/TcUnit-Verifier_DotNet/TcUnit-Verifier/TcUnit-Verifier.csproj index 59dc271..ecaa9c4 100644 --- a/TcUnit-Verifier/TcUnit-Verifier_DotNet/TcUnit-Verifier/TcUnit-Verifier.csproj +++ b/TcUnit-Verifier/TcUnit-Verifier_DotNet/TcUnit-Verifier/TcUnit-Verifier.csproj @@ -59,6 +59,7 @@ + diff --git a/TcUnit-Verifier/TcUnit-Verifier_DotNet/TcUnit-Verifier/TestFunctionBlockAssert.cs b/TcUnit-Verifier/TcUnit-Verifier_DotNet/TcUnit-Verifier/TestFunctionBlockAssert.cs index 5fd7e51..82992a6 100644 --- a/TcUnit-Verifier/TcUnit-Verifier_DotNet/TcUnit-Verifier/TestFunctionBlockAssert.cs +++ b/TcUnit-Verifier/TcUnit-Verifier_DotNet/TcUnit-Verifier/TestFunctionBlockAssert.cs @@ -10,7 +10,7 @@ class TestFunctionBlockAssert { private IEnumerable _errors; protected string _testFunctionBlockInstance; - private static ILog log = LogManager.GetLogger("TcUnit-Verifier"); + protected static ILog log = LogManager.GetLogger("TcUnit-Verifier"); private string DefaultFunctionBlockInstance { diff --git a/TcUnit-Verifier/TcUnit-Verifier_TwinCAT/TcUnit-Verifier_TwinCAT/TcUnitVerifier/TcUnitVerifier.plcproj b/TcUnit-Verifier/TcUnit-Verifier_TwinCAT/TcUnit-Verifier_TwinCAT/TcUnitVerifier/TcUnitVerifier.plcproj index 0f43c74..184017d 100644 --- a/TcUnit-Verifier/TcUnit-Verifier_TwinCAT/TcUnit-Verifier_TwinCAT/TcUnitVerifier/TcUnitVerifier.plcproj +++ b/TcUnit-Verifier/TcUnit-Verifier_TwinCAT/TcUnit-Verifier_TwinCAT/TcUnitVerifier/TcUnitVerifier.plcproj @@ -104,6 +104,9 @@ Code + + Code + Code @@ -146,6 +149,12 @@ TcUnit, * (www.tcunit.org) TcUnit + + + XUNITENABLEPUBLISH + TRUE + + diff --git a/TcUnit-Verifier/TcUnit-Verifier_TwinCAT/TcUnit-Verifier_TwinCAT/TcUnitVerifier/Test/FB_TestXUnitPublisher.TcPOU b/TcUnit-Verifier/TcUnit-Verifier_TwinCAT/TcUnit-Verifier_TwinCAT/TcUnitVerifier/Test/FB_TestXUnitPublisher.TcPOU new file mode 100644 index 0000000..ade91f9 --- /dev/null +++ b/TcUnit-Verifier/TcUnit-Verifier_TwinCAT/TcUnit-Verifier_TwinCAT/TcUnitVerifier/Test/FB_TestXUnitPublisher.TcPOU @@ -0,0 +1,29 @@ + + + + + + + + + + + be $'escaped$' & parsed properly'); + +TEST_FINISHED();]]> + + + + + + &'); + +TEST_FINISHED();]]> + + + + \ No newline at end of file diff --git a/TcUnit-Verifier/TcUnit-Verifier_TwinCAT/TcUnit-Verifier_TwinCAT/TcUnitVerifier/Test/PRG_TEST.TcPOU b/TcUnit-Verifier/TcUnit-Verifier_TwinCAT/TcUnit-Verifier_TwinCAT/TcUnitVerifier/Test/PRG_TEST.TcPOU index 86b8416..3ecb2f0 100644 --- a/TcUnit-Verifier/TcUnit-Verifier_TwinCAT/TcUnit-Verifier_TwinCAT/TcUnitVerifier/Test/PRG_TEST.TcPOU +++ b/TcUnit-Verifier/TcUnit-Verifier_TwinCAT/TcUnit-Verifier_TwinCAT/TcUnitVerifier/Test/PRG_TEST.TcPOU @@ -31,6 +31,7 @@ VAR TestFinishedNamed : FB_TestFinishedNamed; EmptyAssertionMessage : FB_EmptyAssertionMessage; AssertCountExceedsMaxNumber : FB_AssertCountExceedsMaxNumber; + TestXUnitPublisher : FB_TestXUnitPublisher; (* The testsuite below is not active, as it will make TcUnit to abort. Uncomment if you want to test the function of where a test with a name that doesn't exist is set to finished *) //TestFinishedNamedDoesNotExist : FB_TestFinishedNamedDoesNotExist;