{
public sealed class OperatingSystem : ISerializable, ICloneable
{
+#if TARGET_UNIX && !TARGET_OSX
+ private static readonly string s_osPlatformName = Interop.Sys.GetUnixName();
+#endif
+
private readonly Version _version;
private readonly PlatformID _platform;
private readonly string? _servicePack;
return _versionString;
}
}
+
+ /// <summary>
+ /// Indicates whether the current application is running on the specified platform.
+ /// </summary>
+ /// <param name="platform">Case-insensitive platform name. Examples: Browser, Linux, FreeBSD, Android, iOS, macOS, tvOS, watchOS, Windows.</param>
+ public static bool IsOSPlatform(string platform)
+ {
+ if (platform == null)
+ {
+ throw new ArgumentNullException(nameof(platform));
+ }
+
+#if TARGET_BROWSER
+ return platform.Equals("BROWSER", StringComparison.OrdinalIgnoreCase);
+#elif TARGET_WINDOWS
+ return platform.Equals("WINDOWS", StringComparison.OrdinalIgnoreCase);
+#elif TARGET_OSX
+ return platform.Equals("OSX", StringComparison.OrdinalIgnoreCase) || platform.Equals("MACOS", StringComparison.OrdinalIgnoreCase);
+#elif TARGET_UNIX
+ return platform.Equals(s_osPlatformName, StringComparison.OrdinalIgnoreCase);
+#else
+#error Unknown OS
+#endif
+ }
+
+ /// <summary>
+ /// Check for the OS with a >= version comparison. Used to guard APIs that were added in the given OS release.
+ /// </summary>
+ /// <param name="platform">Case-insensitive platform name. Examples: Browser, Linux, FreeBSD, Android, iOS, macOS, tvOS, watchOS, Windows.</param>
+ /// <param name="major">Major OS version number.</param>
+ /// <param name="minor">Minor OS version number (optional).</param>
+ /// <param name="build">Build OS version number (optional).</param>
+ /// <param name="revision">Revision OS version number (optional).</param>
+ public static bool IsOSPlatformVersionAtLeast(string platform, int major, int minor = 0, int build = 0, int revision = 0)
+ => IsOSPlatform(platform) && IsOSVersionAtLeast(major, minor, build, revision);
+
+ /// <summary>
+ /// Indicates whether the current application is running as WASM in a Browser.
+ /// </summary>
+ public static bool IsBrowser() =>
+#if TARGET_BROWSER
+ true;
+#else
+ false;
+#endif
+
+ /// <summary>
+ /// Indicates whether the current application is running on Linux.
+ /// </summary>
+ public static bool IsLinux() =>
+#if TARGET_LINUX
+ true;
+#else
+ false;
+#endif
+
+ /// <summary>
+ /// Indicates whether the current application is running on FreeBSD.
+ /// </summary>
+ public static bool IsFreeBSD() =>
+#if TARGET_FREEBSD
+ true;
+#else
+ false;
+#endif
+
+ /// <summary>
+ /// Check for the FreeBSD version (returned by 'uname') with a >= version comparison. Used to guard APIs that were added in the given FreeBSD release.
+ /// </summary>
+ public static bool IsFreeBSDVersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0)
+ => IsFreeBSD() && IsOSVersionAtLeast(major, minor, build, revision);
+
+ /// <summary>
+ /// Indicates whether the current application is running on Android.
+ /// </summary>
+ public static bool IsAndroid() =>
+#if TARGET_ANDROID
+ true;
+#else
+ false;
+#endif
+
+ /// <summary>
+ /// Check for the Android version (returned by 'uname') with a >= version comparison. Used to guard APIs that were added in the given Android release.
+ /// </summary>
+ public static bool IsAndroidVersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0)
+ => IsAndroid() && IsOSVersionAtLeast(major, minor, build, revision);
+
+ /// <summary>
+ /// Indicates whether the current application is running on iOS.
+ /// </summary>
+ public static bool IsIOS() =>
+#if TARGET_IOS
+ true;
+#else
+ false;
+#endif
+
+ /// <summary>
+ /// Check for the iOS version (returned by 'libobjc.get_operatingSystemVersion') with a >= version comparison. Used to guard APIs that were added in the given iOS release.
+ /// </summary>
+ public static bool IsIOSVersionAtLeast(int major, int minor = 0, int build = 0)
+ => IsIOS() && IsOSVersionAtLeast(major, minor, build, 0);
+
+ /// <summary>
+ /// Indicates whether the current application is running on macOS.
+ /// </summary>
+ public static bool IsMacOS() =>
+#if TARGET_OSX
+ true;
+#else
+ false;
+#endif
+
+ /// <summary>
+ /// Check for the macOS version (returned by 'libobjc.get_operatingSystemVersion') with a >= version comparison. Used to guard APIs that were added in the given macOS release.
+ /// </summary>
+ public static bool IsMacOSVersionAtLeast(int major, int minor = 0, int build = 0)
+ => IsMacOS() && IsOSVersionAtLeast(major, minor, build, 0);
+
+ /// <summary>
+ /// Indicates whether the current application is running on tvOS.
+ /// </summary>
+ public static bool IsTvOS() =>
+#if TARGET_TVOS
+ true;
+#else
+ false;
+#endif
+
+ /// <summary>
+ /// Check for the tvOS version (returned by 'libobjc.get_operatingSystemVersion') with a >= version comparison. Used to guard APIs that were added in the given tvOS release.
+ /// </summary>
+ public static bool IsTvOSVersionAtLeast(int major, int minor = 0, int build = 0)
+ => IsTvOS() && IsOSVersionAtLeast(major, minor, build, 0);
+
+ /// <summary>
+ /// Indicates whether the current application is running on watchOS.
+ /// </summary>
+ public static bool IsWatchOS() =>
+#if TARGET_WATCHOS
+ true;
+#else
+ false;
+#endif
+
+ /// <summary>
+ /// Check for the watchOS version (returned by 'libobjc.get_operatingSystemVersion') with a >= version comparison. Used to guard APIs that were added in the given watchOS release.
+ /// </summary>
+ public static bool IsWatchOSVersionAtLeast(int major, int minor = 0, int build = 0)
+ => IsWatchOS() && IsOSVersionAtLeast(major, minor, build, 0);
+
+ /// <summary>
+ /// Indicates whether the current application is running on Windows.
+ /// </summary>
+ public static bool IsWindows() =>
+#if TARGET_WINDOWS
+ true;
+#else
+ false;
+#endif
+
+ /// <summary>
+ /// Check for the Windows version (returned by 'RtlGetVersion') with a >= version comparison. Used to guard APIs that were added in the given Windows release.
+ /// </summary>
+ public static bool IsWindowsVersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0)
+ => IsWindows() && IsOSVersionAtLeast(major, minor, build, revision);
+
+ private static bool IsOSVersionAtLeast(int major, int minor, int build, int revision)
+ {
+ Version current = Environment.OSVersion.Version;
+
+ if (current.Major != major)
+ {
+ return current.Major > major;
+ }
+ if (current.Minor != minor)
+ {
+ return current.Minor > minor;
+ }
+ if (current.Build != build)
+ {
+ return current.Build > build;
+ }
+
+ return current.Revision >= revision
+ || (current.Revision == -1 && revision == 0); // it is unavailable on OSX and Environment.OSVersion.Version.Revision returns -1
+ }
}
}
{
public static class OperatingSystemTests
{
+ private static readonly string[] AllKnownPlatformNames = new[]
+ {
+ "Android",
+ "macOS",
+ "iOS",
+ "tvOS",
+ "watchOS",
+ "Windows",
+ "Linux",
+ "FreeBSD",
+ "Browser"
+ };
+
[Theory]
[InlineData(PlatformID.Other, "1.0.0.0")]
[InlineData(PlatformID.MacOSX, "1.2")]
Assert.Equal(os.Version, os2.Version);
Assert.Equal(os.VersionString, os2.VersionString);
}
+
+ [Fact]
+ public static void IsOSPlatform_InvalidArgs_Throws()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("platform", () => OperatingSystem.IsOSPlatform(null));
+ }
+
+ [Fact]
+ public static void IsOSPlatformVersionAtLeast_InvalidArgs_Throws()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("platform", () => OperatingSystem.IsOSPlatformVersionAtLeast(null, 1));
+ }
+
+ [Fact, PlatformSpecific(TestPlatforms.Browser)]
+ public static void TestIsOSPlatform_Browser() => TestIsOSPlatform("BROWSER", OperatingSystem.IsBrowser);
+
+ [Fact, PlatformSpecific(TestPlatforms.Browser)]
+ public static void TestIsOSVersionAtLeast_Browser() => TestIsOSVersionAtLeast("BROWSER");
+
+ [Fact, PlatformSpecific(TestPlatforms.Linux)]
+ public static void TestIsOSPlatform_Linux() => TestIsOSPlatform("Linux", OperatingSystem.IsLinux);
+
+ [Fact, PlatformSpecific(TestPlatforms.Linux)]
+ public static void TestIsOSVersionAtLeast_Linux() => TestIsOSVersionAtLeast("Linux");
+
+ [Fact, PlatformSpecific(TestPlatforms.FreeBSD)]
+ public static void TestIsOSPlatform_FreeBSD() => TestIsOSPlatform("FreeBSD", OperatingSystem.IsFreeBSD);
+
+ [Fact, PlatformSpecific(TestPlatforms.FreeBSD)]
+ public static void TestIsOSVersionAtLeast_FreeBSD() => TestIsOSVersionAtLeast("FreeBSD");
+
+ [Fact, PlatformSpecific(TestPlatforms.Android)]
+ public static void TestIsOSPlatform_Android() => TestIsOSPlatform("Android", OperatingSystem.IsAndroid);
+
+ [Fact, PlatformSpecific(TestPlatforms.Android)]
+ public static void TestIsOSVersionAtLeast_Android() => TestIsOSVersionAtLeast("Android");
+
+ [Fact, PlatformSpecific(TestPlatforms.iOS)]
+ public static void TestIsOSPlatform_IOS() => TestIsOSPlatform("iOS", OperatingSystem.IsIOS);
+
+ [Fact, PlatformSpecific(TestPlatforms.iOS)]
+ public static void TestIsOSVersionAtLeast_IOS() => TestIsOSVersionAtLeast("iOS");
+
+ [Fact, PlatformSpecific(TestPlatforms.OSX)]
+ public static void TestIsOSPlatform_MacOS() => TestIsOSPlatform("macOS", OperatingSystem.IsMacOS);
+
+ [Fact, PlatformSpecific(TestPlatforms.OSX)]
+ public static void TestIsOSVersionAtLeast_MacOS() => TestIsOSVersionAtLeast("macOS");
+
+ [Fact, PlatformSpecific(TestPlatforms.OSX)]
+ public static void OSX_Is_Treated_as_macOS()
+ {
+ // we prefer "macOS", but still accept "OSX"
+
+ Assert.True(OperatingSystem.IsOSPlatform("OSX"));
+
+ AssertVersionChecks(true, (major, minor, build, revision) => OperatingSystem.IsOSPlatformVersionAtLeast("OSX", major, minor, build, revision));
+ AssertVersionChecks(true, (major, minor, build, revision) => OperatingSystem.IsOSPlatformVersionAtLeast("osx", major, minor, build, revision));
+ AssertVersionChecks(true, (major, minor, build) => OperatingSystem.IsOSPlatformVersionAtLeast("OSX", major, minor, build));
+ AssertVersionChecks(true, (major, minor, build) => OperatingSystem.IsOSPlatformVersionAtLeast("osx", major, minor, build));
+ }
+
+ [Fact, PlatformSpecific(TestPlatforms.tvOS)]
+ public static void TestIsOSPlatform_TvOS() => TestIsOSPlatform("tvOS", OperatingSystem.IsTvOS);
+
+ [Fact, PlatformSpecific(TestPlatforms.tvOS)]
+ public static void TestIsOSVersionAtLeast_TvOS() => TestIsOSVersionAtLeast("tvOS");
+
+ [Fact, PlatformSpecific(TestPlatforms.Windows)]
+ public static void TestIsOSPlatform_Windows() => TestIsOSPlatform("Windows", OperatingSystem.IsWindows);
+
+ [Fact, PlatformSpecific(TestPlatforms.Windows)]
+ public static void TestIsOSVersionAtLeast_Windows() => TestIsOSVersionAtLeast("Windows");
+
+ private static void TestIsOSPlatform(string currentOSName, Func<bool> currentOSCheck)
+ {
+ foreach (string platfromName in AllKnownPlatformNames)
+ {
+ bool expected = currentOSName.Equals(platfromName, StringComparison.OrdinalIgnoreCase);
+
+ Assert.Equal(expected, OperatingSystem.IsOSPlatform(platfromName));
+ Assert.Equal(expected, OperatingSystem.IsOSPlatform(platfromName.ToUpper()));
+ Assert.Equal(expected, OperatingSystem.IsOSPlatform(platfromName.ToLower()));
+ }
+
+ Assert.True(currentOSCheck());
+
+ bool[] allResults = new bool[]
+ {
+ OperatingSystem.IsBrowser(),
+ OperatingSystem.IsLinux(),
+ OperatingSystem.IsFreeBSD(),
+ OperatingSystem.IsAndroid(),
+ OperatingSystem.IsIOS(),
+ OperatingSystem.IsMacOS(),
+ OperatingSystem.IsTvOS(),
+ OperatingSystem.IsWatchOS(),
+ OperatingSystem.IsWindows()
+ };
+
+ Assert.Single(allResults, true);
+ }
+
+ private static void TestIsOSVersionAtLeast(string currentOSName)
+ {
+ foreach (string platfromName in AllKnownPlatformNames)
+ {
+ bool isCurrentOS = currentOSName.Equals(platfromName, StringComparison.OrdinalIgnoreCase);
+
+ AssertVersionChecks(isCurrentOS, (major, minor, build, revision) => OperatingSystem.IsOSPlatformVersionAtLeast(platfromName, major, minor, build, revision));
+ AssertVersionChecks(isCurrentOS, (major, minor, build, revision) => OperatingSystem.IsOSPlatformVersionAtLeast(platfromName.ToLower(), major, minor, build, revision));
+ AssertVersionChecks(isCurrentOS, (major, minor, build, revision) => OperatingSystem.IsOSPlatformVersionAtLeast(platfromName.ToUpper(), major, minor, build, revision));
+ }
+
+ AssertVersionChecks(currentOSName.Equals("Android", StringComparison.OrdinalIgnoreCase), OperatingSystem.IsAndroidVersionAtLeast);
+ AssertVersionChecks(currentOSName.Equals("iOS", StringComparison.OrdinalIgnoreCase), OperatingSystem.IsIOSVersionAtLeast);
+ AssertVersionChecks(currentOSName.Equals("macOS", StringComparison.OrdinalIgnoreCase), OperatingSystem.IsMacOSVersionAtLeast);
+ AssertVersionChecks(currentOSName.Equals("tvOS", StringComparison.OrdinalIgnoreCase), OperatingSystem.IsTvOSVersionAtLeast);
+ AssertVersionChecks(currentOSName.Equals("watchOS", StringComparison.OrdinalIgnoreCase), OperatingSystem.IsWatchOSVersionAtLeast);
+ AssertVersionChecks(currentOSName.Equals("Windows", StringComparison.OrdinalIgnoreCase), OperatingSystem.IsWindowsVersionAtLeast);
+ }
+
+ private static void AssertVersionChecks(bool isCurrentOS, Func<int, int, int, int, bool> isOSVersionAtLeast)
+ {
+ Version current = Environment.OSVersion.Version;
+
+ Assert.False(isOSVersionAtLeast(current.Major + 1, current.Minor, current.Build, current.Revision));
+ Assert.False(isOSVersionAtLeast(current.Major, current.Minor + 1, current.Build, current.Revision));
+ Assert.False(isOSVersionAtLeast(current.Major, current.Minor, current.Build + 1, current.Revision));
+ Assert.False(isOSVersionAtLeast(current.Major, current.Minor, current.Build, Math.Max(current.Revision + 1, 1))); // OSX Revision reports -1
+
+ Assert.Equal(isCurrentOS, isOSVersionAtLeast(current.Major, current.Minor, current.Build, current.Revision));
+
+ Assert.Equal(isCurrentOS, isOSVersionAtLeast(current.Major - 1, current.Minor, current.Build, current.Revision));
+ Assert.Equal(isCurrentOS, isOSVersionAtLeast(current.Major, current.Minor - 1, current.Build, current.Revision));
+ Assert.Equal(isCurrentOS, isOSVersionAtLeast(current.Major, current.Minor, current.Build - 1, current.Revision));
+ Assert.Equal(isCurrentOS, isOSVersionAtLeast(current.Major, current.Minor, current.Build, current.Revision - 1));
+ }
+
+ private static void AssertVersionChecks(bool isCurrentOS, Func<int, int, int, bool> isOSVersionAtLeast)
+ {
+ Version current = Environment.OSVersion.Version;
+
+ Assert.False(isOSVersionAtLeast(current.Major + 1, current.Minor, current.Build));
+ Assert.False(isOSVersionAtLeast(current.Major, current.Minor + 1, current.Build));
+ Assert.False(isOSVersionAtLeast(current.Major, current.Minor, current.Build + 1));
+
+ Assert.Equal(isCurrentOS, isOSVersionAtLeast(current.Major, current.Minor, current.Build));
+
+ Assert.Equal(isCurrentOS, isOSVersionAtLeast(current.Major - 1, current.Minor, current.Build));
+ Assert.Equal(isCurrentOS, isOSVersionAtLeast(current.Major, current.Minor - 1, current.Build));
+ Assert.Equal(isCurrentOS, isOSVersionAtLeast(current.Major, current.Minor, current.Build - 1));
+ }
}
}