From 09b31b7d18053de170e2183a56ed27e311517cc9 Mon Sep 17 00:00:00 2001 From: Marcin Torba Date: Fri, 27 May 2022 17:37:18 +0200 Subject: [PATCH 1/6] Providing inline data into test method. Fix #1050 --- source/TestAdapter/Discover.cs | 9 ++--- source/TestAdapter/Executor.cs | 6 ++-- .../TestFrameworkShared/DataRowAttribute.cs | 21 ++++++++++++ source/TestFrameworkShared/Helper.cs | 33 +++++++++++++++++++ .../TestFrameworkShared.projitems | 2 ++ source/UnitTestLauncher/Program.cs | 20 ++++++++--- 6 files changed, 80 insertions(+), 11 deletions(-) create mode 100644 source/TestFrameworkShared/DataRowAttribute.cs create mode 100644 source/TestFrameworkShared/Helper.cs diff --git a/source/TestAdapter/Discover.cs b/source/TestAdapter/Discover.cs index 5ddbe1c..9627629 100644 --- a/source/TestAdapter/Discover.cs +++ b/source/TestAdapter/Discover.cs @@ -137,9 +137,10 @@ public static List FindTestCases(string source) { if (attrib.GetType().FullName == typeof(SetupAttribute).FullName || attrib.GetType().FullName == typeof(TestMethodAttribute).FullName || - attrib.GetType().FullName == typeof(CleanupAttribute).FullName) + attrib.GetType().FullName == typeof(CleanupAttribute).FullName || + attrib.GetType().FullName == typeof(DataRowAttribute).FullName) { - var testCase = GetFileNameAndLineNumber(allCsFils, type, method); + var testCase = GetFileNameAndLineNumber(allCsFils, type, method, attrib); testCase.Source = source; testCase.ExecutorUri = new Uri(TestsConstants.NanoExecutor); testCase.FullyQualifiedName = $"{type.FullName}.{testCase.DisplayName}"; @@ -221,7 +222,7 @@ private static FileInfo[] FindNfprojSources(string source) } } - private static TestCase GetFileNameAndLineNumber(string[] csFiles, Type className, MethodInfo method) + private static TestCase GetFileNameAndLineNumber(string[] csFiles, Type className, MethodInfo method, object attribute) { var clName = className.Name; var methodName = method.Name; @@ -242,7 +243,7 @@ private static TestCase GetFileNameAndLineNumber(string[] csFiles, Type classNam { flret.CodeFilePath = csFile; flret.LineNumber = lineNum; - flret.DisplayName = method.Name; + flret.DisplayName = Helper.GetDisplayName(method, attribute); return flret; } diff --git a/source/TestAdapter/Executor.cs b/source/TestAdapter/Executor.cs index 3732692..241b261 100644 --- a/source/TestAdapter/Executor.cs +++ b/source/TestAdapter/Executor.cs @@ -737,7 +737,7 @@ private void CheckAllTests(string rawOutput, List results) // Format is "Test passed: MethodName, ticks"; // We do get split with space if the coma is missing, happens time to time - string method = line.Substring(line.IndexOf(TestPassed) + TestPassed.Length).Split(',')[0].Split(' ')[0]; + string method = line.Substring(line.IndexOf(TestPassed) + TestPassed.Length).Split(',')[0]; string ticks = line.Substring(line.IndexOf(TestPassed) + TestPassed.Length + method.Length + 2); long ticksNum = 0; @@ -761,7 +761,7 @@ private void CheckAllTests(string rawOutput, List results) { // Format is "Test failed: MethodName, Exception message"; - string method = line.Substring(line.IndexOf(TestFailed) + TestFailed.Length).Split(',')[0].Split(' ')[0]; + string method = line.Substring(line.IndexOf(TestFailed) + TestFailed.Length).Split(',')[0]; string exception = line.Substring(line.IndexOf(TestFailed) + TestPassed.Length + method.Length + 2); @@ -783,7 +783,7 @@ private void CheckAllTests(string rawOutput, List results) { // Format is "Test failed: MethodName, Exception message"; - string method = line.Substring(line.IndexOf(TestSkipped) + TestSkipped.Length).Split(',')[0].Split(' ')[0]; + string method = line.Substring(line.IndexOf(TestSkipped) + TestSkipped.Length).Split(',')[0]; string exception = line.Substring(line.IndexOf(TestSkipped) + TestPassed.Length + method.Length + 2); diff --git a/source/TestFrameworkShared/DataRowAttribute.cs b/source/TestFrameworkShared/DataRowAttribute.cs new file mode 100644 index 0000000..6ed7719 --- /dev/null +++ b/source/TestFrameworkShared/DataRowAttribute.cs @@ -0,0 +1,21 @@ +using System; + +namespace nanoFramework.TestFramework +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + public class DataRowAttribute : Attribute + { + public object[] MethodParameters { get; } + + public DataRowAttribute(params object[] methodParameters) + { + if (methodParameters == null) + throw new ArgumentNullException($"{nameof(methodParameters)} can not be null"); + + if (methodParameters.Length == 0) + throw new ArgumentException($"{nameof(methodParameters)} can not be empty"); + + MethodParameters = methodParameters; + } + } +} \ No newline at end of file diff --git a/source/TestFrameworkShared/Helper.cs b/source/TestFrameworkShared/Helper.cs new file mode 100644 index 0000000..9dc9573 --- /dev/null +++ b/source/TestFrameworkShared/Helper.cs @@ -0,0 +1,33 @@ +using System.Reflection; + +namespace nanoFramework.TestFramework +{ + public static class Helper + { + private static string GetJoinedParams(object[] data) + { + var returnString = string.Empty; + foreach (var item in data) + returnString += $"{item} | "; + + return returnString.Substring(0, returnString.Length - 4); + } + + public static string GetDisplayName(MethodInfo method, object attribute) + { + /*Comparing via full name, because attribute parameter is from "TestFramework.dll" + and current type TestCaseAttribute is in scope of "TestAdapter" due to shared project + The same reason - reflection to get value + */ + if (attribute.GetType().FullName == typeof(DataRowAttribute).FullName) + { + var methodParameters = (object[])attribute.GetType() + .GetMethod($"get_{nameof(DataRowAttribute.MethodParameters)}").Invoke(attribute, null); + + return $"{method.Name} - (params: {GetJoinedParams(methodParameters)})"; + } + + return method.Name; + } + } +} \ No newline at end of file diff --git a/source/TestFrameworkShared/TestFrameworkShared.projitems b/source/TestFrameworkShared/TestFrameworkShared.projitems index 874363f..ac7b0f1 100644 --- a/source/TestFrameworkShared/TestFrameworkShared.projitems +++ b/source/TestFrameworkShared/TestFrameworkShared.projitems @@ -10,6 +10,8 @@ + + diff --git a/source/UnitTestLauncher/Program.cs b/source/UnitTestLauncher/Program.cs index 8560c5c..23d4be5 100644 --- a/source/UnitTestLauncher/Program.cs +++ b/source/UnitTestLauncher/Program.cs @@ -43,6 +43,7 @@ public static void Main() { // then we run the tests RunTest(methods, typeof(TestMethodAttribute)); + RunTest(methods, typeof(DataRowAttribute)); // last we handle Cleanup RunTest(methods, typeof(CleanupAttribute)); @@ -67,21 +68,23 @@ private static bool RunTest( foreach (var attrib in attribs) { + var methodName = Helper.GetDisplayName(method, attrib); if (attribToRun == attrib.GetType()) { try { dt = DateTime.UtcNow.Ticks; - method.Invoke(null, null); + object[] parameters = GetParameters(attrib); + method.Invoke(null, parameters); totalTicks = DateTime.UtcNow.Ticks - dt; - Console.WriteLine($"Test passed: {method.Name}, {totalTicks}"); + Console.WriteLine($"Test passed: {methodName}, {totalTicks}"); } catch (Exception ex) { if (ex.GetType() == typeof(SkipTestException)) { - Console.WriteLine($"Test skipped: {method.Name}, {ex.Message}"); + Console.WriteLine($"Test skipped: {methodName}, {ex.Message}"); if (isSetupMethod) { // In case the Setup attribute test is skipped, we will skip @@ -91,7 +94,7 @@ private static bool RunTest( } else { - Console.WriteLine($"Test failed: {method.Name}, {ex.Message}"); + Console.WriteLine($"Test failed: {methodName}, {ex.Message}"); } } @@ -101,5 +104,14 @@ private static bool RunTest( return true; } + + private static object[] GetParameters(object attribute) + { + if (attribute.GetType() != typeof(DataRowAttribute)) + return null; + + var testCaseAttribute = (DataRowAttribute)attribute; + return testCaseAttribute.MethodParameters; + } } } From 8185076808761292b113b7efa9cfd6ac6c0fc49e Mon Sep 17 00:00:00 2001 From: Marcin Torba Date: Fri, 27 May 2022 17:59:15 +0200 Subject: [PATCH 2/6] Fix code style. --- source/TestFrameworkShared/DataRowAttribute.cs | 4 ++++ source/TestFrameworkShared/Helper.cs | 2 ++ source/UnitTestLauncher/Program.cs | 2 ++ 3 files changed, 8 insertions(+) diff --git a/source/TestFrameworkShared/DataRowAttribute.cs b/source/TestFrameworkShared/DataRowAttribute.cs index 6ed7719..d9cf5db 100644 --- a/source/TestFrameworkShared/DataRowAttribute.cs +++ b/source/TestFrameworkShared/DataRowAttribute.cs @@ -10,10 +10,14 @@ public class DataRowAttribute : Attribute public DataRowAttribute(params object[] methodParameters) { if (methodParameters == null) + { throw new ArgumentNullException($"{nameof(methodParameters)} can not be null"); + } if (methodParameters.Length == 0) + { throw new ArgumentException($"{nameof(methodParameters)} can not be empty"); + } MethodParameters = methodParameters; } diff --git a/source/TestFrameworkShared/Helper.cs b/source/TestFrameworkShared/Helper.cs index 9dc9573..63b6f41 100644 --- a/source/TestFrameworkShared/Helper.cs +++ b/source/TestFrameworkShared/Helper.cs @@ -8,7 +8,9 @@ private static string GetJoinedParams(object[] data) { var returnString = string.Empty; foreach (var item in data) + { returnString += $"{item} | "; + } return returnString.Substring(0, returnString.Length - 4); } diff --git a/source/UnitTestLauncher/Program.cs b/source/UnitTestLauncher/Program.cs index 23d4be5..800591d 100644 --- a/source/UnitTestLauncher/Program.cs +++ b/source/UnitTestLauncher/Program.cs @@ -108,7 +108,9 @@ private static bool RunTest( private static object[] GetParameters(object attribute) { if (attribute.GetType() != typeof(DataRowAttribute)) + { return null; + } var testCaseAttribute = (DataRowAttribute)attribute; return testCaseAttribute.MethodParameters; From 39e12b27e29c00872aa46fc67e658b1c45e9eca4 Mon Sep 17 00:00:00 2001 From: Marcin Torba Date: Thu, 2 Jun 2022 18:17:34 +0200 Subject: [PATCH 3/6] Intellisence comments + comments + headers --- source/TestAdapter/Discover.cs | 2 +- source/TestAdapter/Executor.cs | 1 - .../TestFrameworkShared/DataRowAttribute.cs | 20 ++++++++++++- source/TestFrameworkShared/Helper.cs | 28 +++++++++++++++---- source/UnitTestLauncher/Program.cs | 2 +- 5 files changed, 43 insertions(+), 10 deletions(-) diff --git a/source/TestAdapter/Discover.cs b/source/TestAdapter/Discover.cs index 9627629..f75c6f7 100644 --- a/source/TestAdapter/Discover.cs +++ b/source/TestAdapter/Discover.cs @@ -243,7 +243,7 @@ private static TestCase GetFileNameAndLineNumber(string[] csFiles, Type classNam { flret.CodeFilePath = csFile; flret.LineNumber = lineNum; - flret.DisplayName = Helper.GetDisplayName(method, attribute); + flret.DisplayName = Helper.GetTestDisplayName(method, attribute); return flret; } diff --git a/source/TestAdapter/Executor.cs b/source/TestAdapter/Executor.cs index 241b261..b4d5e33 100644 --- a/source/TestAdapter/Executor.cs +++ b/source/TestAdapter/Executor.cs @@ -735,7 +735,6 @@ private void CheckAllTests(string rawOutput, List results) if (line.Contains(TestPassed)) { // Format is "Test passed: MethodName, ticks"; - // We do get split with space if the coma is missing, happens time to time string method = line.Substring(line.IndexOf(TestPassed) + TestPassed.Length).Split(',')[0]; string ticks = line.Substring(line.IndexOf(TestPassed) + TestPassed.Length + method.Length + 2); diff --git a/source/TestFrameworkShared/DataRowAttribute.cs b/source/TestFrameworkShared/DataRowAttribute.cs index d9cf5db..f30341a 100644 --- a/source/TestFrameworkShared/DataRowAttribute.cs +++ b/source/TestFrameworkShared/DataRowAttribute.cs @@ -1,12 +1,30 @@ -using System; +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) Microsoft Corporation. All rights reserved. +// See LICENSE file in the project root for full license information. +// + +using System; namespace nanoFramework.TestFramework { + /// + /// Data row attribute. Used for passing multiple parameters into same test method. + /// [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public class DataRowAttribute : Attribute { + /// + /// Array containing all passed parameters + /// public object[] MethodParameters { get; } + /// + /// Initializes a new instance of the DataRowAttribute class. + /// + /// Parameters which should be stored for future execution of test method + /// Thrown when methodParameters is null + /// Thrown when methodParameters is empty public DataRowAttribute(params object[] methodParameters) { if (methodParameters == null) diff --git a/source/TestFrameworkShared/Helper.cs b/source/TestFrameworkShared/Helper.cs index 63b6f41..37569b5 100644 --- a/source/TestFrameworkShared/Helper.cs +++ b/source/TestFrameworkShared/Helper.cs @@ -1,7 +1,16 @@ -using System.Reflection; +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) Microsoft Corporation. All rights reserved. +// See LICENSE file in the project root for full license information. +// + +using System.Reflection; namespace nanoFramework.TestFramework { + /// + /// Helper class for keeping test name same in TestAdapter and TestRunner + /// public static class Helper { private static string GetJoinedParams(object[] data) @@ -12,15 +21,22 @@ private static string GetJoinedParams(object[] data) returnString += $"{item} | "; } + // In each loop iteration we are appending " | " event at the end + // To keep return string clean, we are removing last 3 charcters + // Lenght starts from 1, substring from 0 + // To remove 3 last characters using this method, we need to add 1 return returnString.Substring(0, returnString.Length - 4); } - public static string GetDisplayName(MethodInfo method, object attribute) + /// + /// Generates test display name based on passed and . + /// + /// Returns method name with parameters if passed attribute is of DataRow type + public static string GetTestDisplayName(MethodInfo method, object attribute) { - /*Comparing via full name, because attribute parameter is from "TestFramework.dll" - and current type TestCaseAttribute is in scope of "TestAdapter" due to shared project - The same reason - reflection to get value - */ + // Comparing via full name, because attribute parameter is from "TestFramework.dll" + // and current type TestCaseAttribute is in scope of "TestAdapter" due to shared project + // The same reason - reflection to get value if (attribute.GetType().FullName == typeof(DataRowAttribute).FullName) { var methodParameters = (object[])attribute.GetType() diff --git a/source/UnitTestLauncher/Program.cs b/source/UnitTestLauncher/Program.cs index 800591d..7fe5f33 100644 --- a/source/UnitTestLauncher/Program.cs +++ b/source/UnitTestLauncher/Program.cs @@ -68,7 +68,7 @@ private static bool RunTest( foreach (var attrib in attribs) { - var methodName = Helper.GetDisplayName(method, attrib); + var methodName = Helper.GetTestDisplayName(method, attrib); if (attribToRun == attrib.GetType()) { try From 34f2155dd723f72da0c920ca58f250cc4dc09c58 Mon Sep 17 00:00:00 2001 From: Marcin Torba Date: Fri, 3 Jun 2022 13:56:48 +0200 Subject: [PATCH 4/6] PoC data row example. --- .../DataRowTests.cs | 31 +++++++++++++++++++ .../NFUnitTestByReference.nfproj | 11 +++---- .../packages.config | 4 +-- 3 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 poc/TestOfTestFrameworkByReference/DataRowTests.cs diff --git a/poc/TestOfTestFrameworkByReference/DataRowTests.cs b/poc/TestOfTestFrameworkByReference/DataRowTests.cs new file mode 100644 index 0000000..01c70d1 --- /dev/null +++ b/poc/TestOfTestFrameworkByReference/DataRowTests.cs @@ -0,0 +1,31 @@ +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) Microsoft Corporation. All rights reserved. +// See LICENSE file in the project root for full license information. +// + +using System; +using System.Diagnostics; +using System.Threading; + +namespace nanoFramework.TestFramework.Test +{ + [TestClass] + public class TestOfDataRow + { + [DataRow(1, 2, 3)] + [DataRow(5, 6, 11)] + public void TestAddition(int number1, int number2, int result) + { + var additionResult = number1 + number2; + + Assert.Equal(additionResult, result); + } + + [DataRow("TestString")] + public void TestString(string testData) + { + Assert.Equal(testData, "TestString"); + } + } +} diff --git a/poc/TestOfTestFrameworkByReference/NFUnitTestByReference.nfproj b/poc/TestOfTestFrameworkByReference/NFUnitTestByReference.nfproj index 222a337..2b895a1 100644 --- a/poc/TestOfTestFrameworkByReference/NFUnitTestByReference.nfproj +++ b/poc/TestOfTestFrameworkByReference/NFUnitTestByReference.nfproj @@ -27,6 +27,7 @@ $(MSBuildProjectDirectory)\nano.runsettings + @@ -41,13 +42,11 @@ - - ..\packages\nanoFramework.CoreLibrary.1.11.7\lib\mscorlib.dll - True + + ..\packages\nanoFramework.CoreLibrary.1.12.0\lib\mscorlib.dll - - ..\packages\nanoFramework.Runtime.Native.1.5.2-preview.6\lib\nanoFramework.Runtime.Native.dll - True + + ..\packages\nanoFramework.Runtime.Native.1.5.4\lib\nanoFramework.Runtime.Native.dll diff --git a/poc/TestOfTestFrameworkByReference/packages.config b/poc/TestOfTestFrameworkByReference/packages.config index 75cafc7..1a1eb24 100644 --- a/poc/TestOfTestFrameworkByReference/packages.config +++ b/poc/TestOfTestFrameworkByReference/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file From 9d0e1b39f8194f9ee5c61ec458526245818031c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 3 Jun 2022 13:12:36 +0100 Subject: [PATCH 5/6] Update source/TestFrameworkShared/Helper.cs --- source/TestFrameworkShared/Helper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/TestFrameworkShared/Helper.cs b/source/TestFrameworkShared/Helper.cs index 37569b5..cc00dd3 100644 --- a/source/TestFrameworkShared/Helper.cs +++ b/source/TestFrameworkShared/Helper.cs @@ -48,4 +48,4 @@ public static string GetTestDisplayName(MethodInfo method, object attribute) return method.Name; } } -} \ No newline at end of file +} From 9cc7eef5be83046ea25cb1d75307ad2e28f9732d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 3 Jun 2022 13:13:04 +0100 Subject: [PATCH 6/6] Update source/TestFrameworkShared/DataRowAttribute.cs --- source/TestFrameworkShared/DataRowAttribute.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/TestFrameworkShared/DataRowAttribute.cs b/source/TestFrameworkShared/DataRowAttribute.cs index f30341a..045e10a 100644 --- a/source/TestFrameworkShared/DataRowAttribute.cs +++ b/source/TestFrameworkShared/DataRowAttribute.cs @@ -40,4 +40,4 @@ public DataRowAttribute(params object[] methodParameters) MethodParameters = methodParameters; } } -} \ No newline at end of file +}