Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[release/6.0] Fix loading app-local ICU #77117

Merged
merged 9 commits into from
Oct 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public static partial class PlatformDetection
// do it in a way that failures don't cascade.
//

private static bool IsLinux => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
public static bool IsLinux => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
public static bool IsOpenSUSE => IsDistroAndVersion("opensuse");
public static bool IsUbuntu => IsDistroAndVersion("ubuntu");
public static bool IsDebian => IsDistroAndVersion("debian");
Expand All @@ -32,6 +32,7 @@ public static partial class PlatformDetection
public static bool IsSLES => IsDistroAndVersion("sles");
public static bool IsTizen => IsDistroAndVersion("tizen");
public static bool IsFedora => IsDistroAndVersion("fedora");
public static bool IsLinuxBionic => IsBionic();

// OSX family
public static bool IsOSXLike => IsOSX || IsiOS || IstvOS || IsMacCatalyst;
Expand Down Expand Up @@ -171,6 +172,21 @@ private static Version ToVersion(string versionString)
}
}

/// <summary>
/// Assume that Android environment variables but Linux OS mean Android libc
/// </summary>
private static bool IsBionic()
{
if (IsLinux)
{
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("ANDROID_STORAGE")))
{
return true;
}
}
return false;
}

private static DistroInfo GetDistroInfo()
{
DistroInfo result = new DistroInfo();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public static partial class PlatformDetection
public static bool IsArmOrArm64Process => IsArmProcess || IsArm64Process;
public static bool IsNotArmNorArm64Process => !IsArmOrArm64Process;
public static bool IsX86Process => RuntimeInformation.ProcessArchitecture == Architecture.X86;
public static bool IsX64Process => RuntimeInformation.ProcessArchitecture == Architecture.X64;
public static bool IsArgIteratorSupported => IsMonoRuntime || (IsWindows && IsNotArmProcess);
public static bool IsArgIteratorNotSupported => !IsArgIteratorSupported;
public static bool Is32BitProcess => IntPtr.Size == 4;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@ void GlobalizationNative_InitICUFunctions(void* icuuc, void* icuin, const char*
ValidateICUDataCanLoad();

InitializeVariableMaxAndTopPointers(symbolVersion);
InitializeUColClonePointers(symbolVersion);
}

#undef PER_FUNCTION_BLOCK
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent)</TargetFrameworks>
<TestRuntime>true</TestRuntime>
<IncludeRemoteExecutor>true</IncludeRemoteExecutor>
</PropertyGroup>
<ItemGroup>
<Compile Include="IcuAppLocal.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.ICU.ICU4C.Runtime" Version="68.2.0.9" />

<!--
We define this switch dynamically during the runtime using RemoteExecutor.
The reason is, if we enable ICU app-local here, this test will compile and run
on all supported OSs even the ICU NuGet package not have native bits support such OSs.
Note, it doesn't matter if we have test case conditioned to not run on such OSs, because
the test has to start running first before filtering the test cases and the globalization
code will run and fail fast at that time.

<RuntimeHostConfigurationOption Include="System.Globalization.AppLocalIcu" Value="68.2.0.9" />
-->
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.DotNet.RemoteExecutor;
using System.Diagnostics;
using System.Reflection;
using Xunit;

namespace System.Globalization.Tests
{
public class IcuAppLocalTests
{
private static bool SupportsIcuPackageDownload => RemoteExecutor.IsSupported &&
((PlatformDetection.IsWindows && !PlatformDetection.IsArmProcess) ||
(PlatformDetection.IsLinux && (PlatformDetection.IsX64Process || PlatformDetection.IsArm64Process) &&
!PlatformDetection.IsAlpine && !PlatformDetection.IsLinuxBionic));


[ConditionalFact(nameof(SupportsIcuPackageDownload))]
public void TestIcuAppLocal()
{
// We define this switch dynamically during the runtime using RemoteExecutor.
// The reason is, if we enable ICU app-local here, this test will compile and run
// on all supported OSs even the ICU NuGet package not have native bits support such OSs.
// Note, it doesn't matter if we have test case conditioned to not run on such OSs, because
// the test has to start running first before filtering the test cases and the globalization
// code will run and fail fast at that time.

ProcessStartInfo psi = new ProcessStartInfo();
psi.Environment.Add("DOTNET_SYSTEM_GLOBALIZATION_APPLOCALICU", "68.2.0.9");

RemoteExecutor.Invoke(() =>
{
// Ensure initializing globalization code before checking the ICU version.
CultureInfo ci = CultureInfo.GetCultureInfo("en-US");

Type? interopGlobalization = Type.GetType("Interop+Globalization, System.Private.CoreLib");
Assert.NotNull(interopGlobalization);

MethodInfo? methodInfo = interopGlobalization.GetMethod("GetICUVersion", BindingFlags.NonPublic | BindingFlags.Static);
Assert.NotNull(methodInfo);

// Assert the ICU version 0x44020009 is 68.2.0.9
Assert.Equal(0x44020009, (int)methodInfo.Invoke(null, null));

// Now call globalization API to ensure the binding working without any problem.
Assert.Equal(-1, ci.CompareInfo.Compare("sample\u0000", "Sample\u0000", CompareOptions.IgnoreSymbols));
}, new RemoteInvokeOptions { StartInfo = psi }).Dispose();
}
}
}