From db83e09d8abfc8790314f27bd79c8a7957ea7c68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 7 May 2026 13:20:18 +0100 Subject: [PATCH 1/2] Improve test class discovery - Test-class filtering logic moverd to shared code so class scanning now excludes Attribute-derived types before calling type-level custom-attribute reflection. --- source/TestAdapter/Discover.cs | 2 +- source/TestFrameworkShared/Helper.cs | 27 +++++++++++++++++++++++++++ source/UnitTestLauncher/Program.cs | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/source/TestAdapter/Discover.cs b/source/TestAdapter/Discover.cs index 143648b..927ba2b 100644 --- a/source/TestAdapter/Discover.cs +++ b/source/TestAdapter/Discover.cs @@ -120,7 +120,7 @@ public static List ComposeTestCases(string sourceFile) AppDomain.CurrentDomain.Load(test.GetName()); var typeCandidatesForTests = test.GetTypes() - .Where(x => x.IsClass); + .Where(Helper.IsTestClassCandidate); foreach (var typeCandidate in typeCandidatesForTests) { diff --git a/source/TestFrameworkShared/Helper.cs b/source/TestFrameworkShared/Helper.cs index 5041f01..8d6192f 100644 --- a/source/TestFrameworkShared/Helper.cs +++ b/source/TestFrameworkShared/Helper.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; + namespace nanoFramework.TestFramework { /// @@ -10,6 +12,31 @@ public static class Helper { private delegate bool AnyDelegateType(object source); + /// + /// Checks whether a type can be considered for test discovery and execution. + /// + /// Type to inspect. + /// when the type is a class and not an attribute type. + public static bool IsTestClassCandidate(Type type) + { + return type.IsClass && !IsAttributeType(type); + } + + private static bool IsAttributeType(Type type) + { + var attributeFullName = typeof(Attribute).FullName; + + for (var current = type; current != null; current = current.BaseType) + { + if (current.FullName == attributeFullName) + { + return true; + } + } + + return false; + } + private static bool Any(this object[] array, AnyDelegateType predicate) { foreach (var item in array) diff --git a/source/UnitTestLauncher/Program.cs b/source/UnitTestLauncher/Program.cs index b88fc50..1e6bcb2 100644 --- a/source/UnitTestLauncher/Program.cs +++ b/source/UnitTestLauncher/Program.cs @@ -22,7 +22,7 @@ public static void Main() foreach (var type in allTypes) { - if (!type.IsClass) + if (!Helper.IsTestClassCandidate(type)) { continue; } From b154bf283ed3e4c61c3d28b7a29b2c2b518d3101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 7 May 2026 13:53:22 +0100 Subject: [PATCH 2/2] Improvement from code review --- source/TestFrameworkShared/Helper.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/source/TestFrameworkShared/Helper.cs b/source/TestFrameworkShared/Helper.cs index 8d6192f..570b38c 100644 --- a/source/TestFrameworkShared/Helper.cs +++ b/source/TestFrameworkShared/Helper.cs @@ -26,15 +26,27 @@ private static bool IsAttributeType(Type type) { var attributeFullName = typeof(Attribute).FullName; - for (var current = type; current != null; current = current.BaseType) + Type current = type; + while (current != null) { if (current.FullName == attributeFullName) { return true; } + try + { + current = current.BaseType; + } + catch + { + // Base type assembly not resolvable in this reflection context; + // conservatively treat as attribute to avoid calling GetCustomAttributes on it. + return true; + } } return false; + } private static bool Any(this object[] array, AnyDelegateType predicate)