Skip to content

Commit d523347

Browse files
CopilotEvangelinkYoussef1313
authored
Fix OSConditionAttribute to detect OS via reflection for .NET Framework on Mono (#7001)
Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: Evangelink <[email protected]> Co-authored-by: Amaury Levé <[email protected]> Co-authored-by: Youssef Victor <[email protected]>
1 parent 572ba39 commit d523347

File tree

1 file changed

+74
-2
lines changed

1 file changed

+74
-2
lines changed

src/TestFramework/TestFramework/Attributes/TestMethod/OSConditionAttribute.cs

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ public sealed class OSConditionAttribute : ConditionBaseAttribute
2121
#endif
2222
#endif
2323

24+
#if NET462
25+
// Cache the detected OS to avoid repeated reflection calls
26+
private static readonly OperatingSystems? DetectedOS = DetectCurrentOS();
27+
#endif
28+
2429
private readonly OperatingSystems _operatingSystems;
2530

2631
/// <summary>
@@ -51,8 +56,7 @@ public OSConditionAttribute(OperatingSystems operatingSystems)
5156
/// </summary>
5257
public override bool IsConditionMet
5358
#if NET462
54-
// On .NET Framework, we are sure we are running on Windows.
55-
=> (_operatingSystems & OperatingSystems.Windows) != 0;
59+
=> DetectedOS is not null && (_operatingSystems & DetectedOS) != 0;
5660
#else
5761
{
5862
get
@@ -79,6 +83,74 @@ public override bool IsConditionMet
7983
}
8084
#endif
8185

86+
#if NET462
87+
/// <summary>
88+
/// Detects the current operating system using reflection to maintain compatibility with .NET Framework 4.6.2.
89+
/// </summary>
90+
/// <returns>
91+
/// The detected operating system, or null if the OS could not be determined.
92+
/// </returns>
93+
private static OperatingSystems? DetectCurrentOS()
94+
{
95+
// RuntimeInformation.IsOSPlatform is available in .NET Framework 4.7.1+.
96+
// For older .NET Framework versions or environments where the API is not available,
97+
// we return null to fall back to assuming Windows.
98+
// This also handles Mono which supports RuntimeInformation API and can run on non-Windows platforms.
99+
Type? runtimeInformationType = Type.GetType("System.Runtime.InteropServices.RuntimeInformation, System.Runtime.InteropServices.RuntimeInformation")
100+
?? Type.GetType("System.Runtime.InteropServices.RuntimeInformation, mscorlib");
101+
if (runtimeInformationType is null)
102+
{
103+
return OperatingSystems.Windows;
104+
}
105+
106+
MethodInfo? isOSPlatformMethod = runtimeInformationType.GetMethod("IsOSPlatform", BindingFlags.Public | BindingFlags.Static);
107+
if (isOSPlatformMethod is null)
108+
{
109+
// Fallback to Windows if the method is not found
110+
return OperatingSystems.Windows;
111+
}
112+
113+
Type? osPlatformType = Type.GetType("System.Runtime.InteropServices.OSPlatform, System.Runtime.InteropServices.RuntimeInformation")
114+
?? Type.GetType("System.Runtime.InteropServices.OSPlatform, mscorlib")
115+
?? throw ApplicationStateGuard.Unreachable();
116+
117+
// Use the predefined static properties instead of Create() method
118+
// On Mono, the static properties use uppercase strings (e.g., "LINUX") while Create() uses the provided casing,
119+
// and IsOSPlatform performs case-sensitive comparison against the predefined values.
120+
PropertyInfo? windowsProp = osPlatformType.GetProperty("Windows", BindingFlags.Public | BindingFlags.Static);
121+
PropertyInfo? linuxProp = osPlatformType.GetProperty("Linux", BindingFlags.Public | BindingFlags.Static);
122+
PropertyInfo? osxProp = osPlatformType.GetProperty("OSX", BindingFlags.Public | BindingFlags.Static);
123+
PropertyInfo? freebsdProp = osPlatformType.GetProperty("FreeBSD", BindingFlags.Public | BindingFlags.Static);
124+
125+
if (windowsProp != null && IsOSPlatformViaProperty(isOSPlatformMethod, windowsProp))
126+
{
127+
return OperatingSystems.Windows;
128+
}
129+
else if (linuxProp != null && IsOSPlatformViaProperty(isOSPlatformMethod, linuxProp))
130+
{
131+
return OperatingSystems.Linux;
132+
}
133+
else if (osxProp != null && IsOSPlatformViaProperty(isOSPlatformMethod, osxProp))
134+
{
135+
return OperatingSystems.OSX;
136+
}
137+
else if (freebsdProp != null && IsOSPlatformViaProperty(isOSPlatformMethod, freebsdProp))
138+
{
139+
return OperatingSystems.FreeBSD;
140+
}
141+
142+
// Unknown OS
143+
return null;
144+
}
145+
146+
private static bool IsOSPlatformViaProperty(MethodInfo isOSPlatformMethod, PropertyInfo osPlatformProperty)
147+
{
148+
object? osPlatform = osPlatformProperty.GetValue(null);
149+
object? result = isOSPlatformMethod.Invoke(null, [osPlatform]);
150+
return result is true;
151+
}
152+
#endif
153+
82154
/// <summary>
83155
/// Gets the group name for this attribute.
84156
/// </summary>

0 commit comments

Comments
 (0)