* Fix the logic + add simple tests.
* Fix non-icu-sharding tests.
* Split ICU WBT file - it was running long on CI.
* Add new wbt files to CI jobs.
* Split sharding wbt into classes ~equal no. of test cases.
* And update job list.
* Fix `File sizes don't match for dotnet.native.wasm`.
* Move file to fix class not found.
* Cleanup.
* Propagate warning update.
* @radical's suggestions.
* Build fix.
* Null test cases.
* Add running the apps.
* @radical's feedback
* Changing type of template required update in options.
* Fix "file sizes don't match for dotnet.native.wasm".
Wasm.Build.Tests.Blazor.MiscTests3
Wasm.Build.Tests.Blazor.NativeTests
Wasm.Build.Tests.Blazor.NoopNativeRebuildTest
+Wasm.Build.Tests.Blazor.IcuTests
Wasm.Build.Tests.BuildPublishTests
Wasm.Build.Tests.ConfigSrcTests
Wasm.Build.Tests.HybridGlobalizationTests
<Target Name="_ResolveGlobalizationConfiguration">
<Error Condition="'$(BlazorIcuDataFileName)' != '' AND !$([System.IO.Path]::GetFileName('$(BlazorIcuDataFileName)').StartsWith('icudt'))" Text="File name in %24(BlazorIcuDataFileName) has to start with 'icudt'." />
<Warning Condition="'$(InvariantGlobalization)' == 'true' AND '$(BlazorWebAssemblyLoadAllGlobalizationData)' == 'true'" Text="%24(BlazorWebAssemblyLoadAllGlobalizationData) has no effect when %24(InvariantGlobalization) is set to true." />
+ <Warning Condition="'$(HybridGlobalization)' == 'true' AND '$(BlazorWebAssemblyLoadAllGlobalizationData)' == 'true'" Text="%24(BlazorWebAssemblyLoadAllGlobalizationData) has no effect when %24(HybridGlobalization) is set to true." />
<Warning Condition="'$(InvariantGlobalization)' == 'true' AND '$(BlazorIcuDataFileName)' != ''" Text="%24(BlazorIcuDataFileName) has no effect when %24(InvariantGlobalization) is set to true." />
<Warning Condition="'$(BlazorWebAssemblyLoadAllGlobalizationData)' == 'true' AND '$(BlazorIcuDataFileName)' != ''" Text="%24(BlazorIcuDataFileName) has no effect when %24(BlazorWebAssemblyLoadAllGlobalizationData) is set to true." />
<Warning Condition="'$(InvariantGlobalization)' == 'true' AND '$(HybridGlobalization)' == 'true'" Text="%24(HybridGlobalization) has no effect when %24(InvariantGlobalization) is set to true." />
<Warning Condition="'$(BlazorIcuDataFileName)' != '' AND '$(HybridGlobalization)' == 'true'" Text="%24(HybridGlobalization) has no effect when %24(BlazorIcuDataFileName) is set." />
<PropertyGroup>
<HybridGlobalization Condition="'$(BlazorIcuDataFileName)' != ''">false</HybridGlobalization>
- <_BlazorWebAssemblyLoadAllGlobalizationData Condition="'$(InvariantGlobalization)' != 'true'">$(BlazorWebAssemblyLoadAllGlobalizationData)</_BlazorWebAssemblyLoadAllGlobalizationData>
+ <_BlazorWebAssemblyLoadAllGlobalizationData Condition="'$(InvariantGlobalization)' != 'true' AND '$(HybridGlobalization)' != 'true'">$(BlazorWebAssemblyLoadAllGlobalizationData)</_BlazorWebAssemblyLoadAllGlobalizationData>
<_BlazorWebAssemblyLoadAllGlobalizationData Condition="'$(_BlazorWebAssemblyLoadAllGlobalizationData)' == ''">false</_BlazorWebAssemblyLoadAllGlobalizationData>
- <_IsHybridGlobalization Condition="'$(InvariantGlobalization)' != 'true' AND '$(HybridGlobalization)' == 'true'"></_IsHybridGlobalization>
+ <_IsHybridGlobalization>$(HybridGlobalization)</_IsHybridGlobalization>
+ <_IsHybridGlobalization Condition="'$(InvariantGlobalization)' == 'true' OR '$(HybridGlobalization)' == ''">false</_IsHybridGlobalization>
<_BlazorIcuDataFileName Condition="'$(InvariantGlobalization)' != 'true' AND '$(BlazorWebAssemblyLoadAllGlobalizationData)' != 'true' AND '$(HybridGlobalization)' != 'true'">$(BlazorIcuDataFileName)</_BlazorIcuDataFileName>
<_LoadCustomIcuData>false</_LoadCustomIcuData>
<_LoadCustomIcuData Condition="'$(_BlazorIcuDataFileName)' != ''">true</_LoadCustomIcuData>
ProjectSatelliteAssemblies="@(IntermediateSatelliteAssembliesWithTargetPath)"
TimeZoneSupport="$(_BlazorEnableTimeZoneSupport)"
InvariantGlobalization="$(_WasmInvariantGlobalization)"
+ HybridGlobalization="$(_IsHybridGlobalization)"
+ LoadFullICUData="$(_BlazorWebAssemblyLoadAllGlobalizationData)"
DotNetJsVersion="$(_WasmRuntimePackVersion)"
CopySymbols="$(_WasmCopyOutputSymbolsToOutputDirectory)"
OutputPath="$(OutputPath)"
InvariantGlobalization="$(InvariantGlobalization)"
LoadCustomIcuData="$(_LoadCustomIcuData)"
IsHybridGlobalization="$(_IsHybridGlobalization)"
- LoadAllICUData="$(_BlazorWebAssemblyLoadAllGlobalizationData)"
+ LoadFullICUData="$(_BlazorWebAssemblyLoadAllGlobalizationData)"
StartupMemoryCache="$(_BlazorWebAssemblyStartupMemoryCache)"
Jiterpreter="$(_BlazorWebAssemblyJiterpreter)"
RuntimeOptions="$(_BlazorWebAssemblyRuntimeOptions)"
PublishPath="$(PublishDir)"
WasmAotAssets="@(WasmNativeAsset)"
InvariantGlobalization="$(_WasmInvariantGlobalization)"
+ HybridGlobalization="$(_IsHybridGlobalization)"
+ LoadFullICUData="$(_BlazorWebAssemblyLoadAllGlobalizationData)"
CopySymbols="$(CopyOutputSymbolsToPublishDirectory)"
ExistingAssets="@(_WasmPublishPrefilteredAssets)"
DotNetJsVersion="$(_WasmRuntimePackVersion)"
InvariantGlobalization="$(InvariantGlobalization)"
LoadCustomIcuData="$(_LoadCustomIcuData)"
IsHybridGlobalization="$(_IsHybridGlobalization)"
- LoadAllICUData="$(_BlazorWebAssemblyLoadAllGlobalizationData)"
+ LoadFullICUData="$(_BlazorWebAssemblyLoadAllGlobalizationData)"
StartupMemoryCache="$(_BlazorWebAssemblyStartupMemoryCache)"
Jiterpreter="$(_BlazorWebAssemblyJiterpreter)"
RuntimeOptions="$(_BlazorWebAssemblyRuntimeOptions)"
bool WarnAsError = true,
bool ExpectRelinkDirWhenPublishing = false,
bool ExpectFingerprintOnDotnetJs = false,
- RuntimeVariant RuntimeType = RuntimeVariant.SingleThreaded
+ RuntimeVariant RuntimeType = RuntimeVariant.SingleThreaded,
+ GlobalizationMode GlobalizationMode = GlobalizationMode.Sharded,
+ string PredefinedIcudt = ""
);
IsPublish: options.IsPublish,
TargetFramework: options.TargetFramework,
BinFrameworkDir: FindBinFrameworkDir(options.Config, options.IsPublish, options.TargetFramework),
- GlobalizationMode: GlobalizationMode.Sharded,
- PredefinedIcudt: null,
+ GlobalizationMode: options.GlobalizationMode,
+ PredefinedIcudt: options.PredefinedIcudt,
ExpectFingerprintOnDotnetJs: options.ExpectFingerprintOnDotnetJs,
ExpectedFileType: options.ExpectedFileType,
RuntimeType: options.RuntimeType,
- AssertIcuAssets: false, // FIXME: this is broken right now
+ AssertIcuAssets: true,
AssertSymbolsFile: false // FIXME: not supported yet
));
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.IO;
+using Xunit;
+using Xunit.Abstractions;
+using Xunit.Sdk;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+#nullable enable
+
+namespace Wasm.Build.Tests.Blazor;
+
+// these tests only check if correct ICU files got copied
+public class IcuTests : BlazorWasmTestBase
+{
+ public IcuTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
+ : base(output, buildContext) {}
+
+ [Theory]
+ [InlineData("Debug", false)]
+ [InlineData("Debug", true)]
+ [InlineData("Debug", null)]
+ [InlineData("Release", false)]
+ [InlineData("Release", true)]
+ [InlineData("Release", null)]
+ public async Task HybridWithInvariant(string config, bool? invariant)
+ {
+ string id = $"blz_hybrid_{config}_{GetRandomId()}";
+ string projectFile = CreateBlazorWasmTemplateProject(id);
+ string extraProperties = "<HybridGlobalization>true</HybridGlobalization>";
+ if (invariant != null)
+ extraProperties += $"<InvariantGlobalization>{invariant}</InvariantGlobalization>";
+ AddItemsPropertiesToProject(projectFile, extraProperties: extraProperties);
+
+ (CommandResult res, string logPath) = BlazorBuild(
+ new BlazorBuildOptions(
+ id,
+ config,
+ WarnAsError: false,
+ GlobalizationMode: invariant == true ? GlobalizationMode.Invariant : GlobalizationMode.Hybrid,
+ ExpectedFileType: invariant == true ? NativeFilesType.Relinked : NativeFilesType.FromRuntimePack
+ ));
+
+ string warning = "$(HybridGlobalization) has no effect when $(InvariantGlobalization) is set to true.";
+ if (invariant == true)
+ {
+ Assert.Contains(warning, res.Output);
+ }
+ else
+ {
+ Assert.DoesNotContain(warning, res.Output);
+ }
+
+ await BlazorRunForBuildWithDotnetRun(new BlazorRunOptions() { Config = config });
+ }
+
+ [Theory]
+ [InlineData("Debug", false)]
+ [InlineData("Debug", true)]
+ [InlineData("Debug", null)]
+ [InlineData("Release", false)]
+ [InlineData("Release", true)]
+ [InlineData("Release", null)]
+ public async Task HybridWithFullIcuFromRuntimePack(string config, bool? fullIcu)
+ {
+ string id = $"blz_hybrid_{config}_{GetRandomId()}";
+ string projectFile = CreateBlazorWasmTemplateProject(id);
+ string extraProperties = "<HybridGlobalization>true</HybridGlobalization>";
+ if (fullIcu != null)
+ extraProperties += $"<BlazorWebAssemblyLoadAllGlobalizationData>{fullIcu}</BlazorWebAssemblyLoadAllGlobalizationData>";
+ AddItemsPropertiesToProject(projectFile, extraProperties: extraProperties);
+
+ (CommandResult res, string logPath) = BlazorBuild(
+ new BlazorBuildOptions(
+ id,
+ config,
+ WarnAsError: false,
+ GlobalizationMode: GlobalizationMode.Hybrid
+ ));
+
+ string warning = "$(BlazorWebAssemblyLoadAllGlobalizationData) has no effect when $(HybridGlobalization) is set to true.";
+ if (fullIcu == true)
+ {
+ Assert.Contains(warning, res.Output);
+ }
+ else
+ {
+ Assert.DoesNotContain(warning, res.Output);
+ }
+
+ await BlazorRunForBuildWithDotnetRun(new BlazorRunOptions() { Config = config });
+ }
+
+ [Theory]
+ [InlineData("Debug", false)]
+ [InlineData("Debug", true)]
+ [InlineData("Debug", null)]
+ [InlineData("Release", false)]
+ [InlineData("Release", true)]
+ [InlineData("Release", null)]
+ public async Task FullIcuFromRuntimePackWithInvariant(string config, bool? invariant)
+ {
+ string id = $"blz_hybrid_{config}_{GetRandomId()}";
+ string projectFile = CreateBlazorWasmTemplateProject(id);
+ string extraProperties = "<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>";
+ if (invariant != null)
+ extraProperties += $"<InvariantGlobalization>{invariant}</InvariantGlobalization>";
+ AddItemsPropertiesToProject(projectFile, extraProperties: extraProperties);
+
+ (CommandResult res, string logPath) = BlazorBuild(
+ new BlazorBuildOptions(
+ id,
+ config,
+ WarnAsError: false,
+ GlobalizationMode: invariant == true ? GlobalizationMode.Invariant : GlobalizationMode.FullIcu,
+ ExpectedFileType: invariant == true ? NativeFilesType.Relinked : NativeFilesType.FromRuntimePack
+ ));
+
+ string warning = "$(BlazorWebAssemblyLoadAllGlobalizationData) has no effect when $(InvariantGlobalization) is set to true.";
+ if (invariant == true)
+ {
+ Assert.Contains(warning, res.Output);
+ }
+ else
+ {
+ Assert.DoesNotContain(warning, res.Output);
+ }
+
+ await BlazorRunForBuildWithDotnetRun(new BlazorRunOptions() { Config = config });
+ }
+}
\ No newline at end of file
Sharded, // chosen based on locale
Invariant, // no icu
FullIcu, // full icu data: icudt.dat is loaded
- PredefinedIcu, // user set WasmIcuDataFileName value and we are loading that file
+ PredefinedIcu, // user set WasmIcuDataFileName/BlazorIcuDataFileName value and we are loading that file
Hybrid // reduced icu, missing data is provided by platform-native functions (web api for wasm)
};
// icu
if (assertOptions.AssertIcuAssets)
{
- _testOutput.WriteLine("Skipping asserting icu assets");
AssertIcuAssets(assertOptions);
}
+ else
+ {
+ _testOutput.WriteLine("Skipping asserting icu assets");
+ }
// symbols
if (assertOptions.AssertSymbolsFile)
"dotnet.runtime"
};
+ private static readonly string[] icuShardsFromRuntimePack = new[]
+ {
+ "icudt_EFIGS",
+ "icudt_CJK",
+ "icudt_no_CJK"
+ };
+
public static bool ShouldFilterCandidate(
ITaskItem candidate,
bool timezoneSupport,
bool invariantGlobalization,
+ bool hybridGlobalization,
+ bool loadFullICUData,
bool copySymbols,
string customIcuCandidateFilename,
bool enableThreads,
".props" when fromMonoPackage => "extension is .props is not supported.",
".blat" when !timezoneSupport => "timezone support is not enabled.",
".dat" when invariantGlobalization && fileName.StartsWith("icudt") => "invariant globalization is enabled",
+ ".dat" when loadFullICUData && fileName != "icudt" => "full ICU data is enabled",
+ ".dat" when hybridGlobalization && fileName != "icudt_hybrid" => "hybrid globalization is enabled",
".dat" when !string.IsNullOrEmpty(customIcuCandidateFilename) && fileName != customIcuCandidateFilename => "custom icu file will be used instead of icu from the runtime pack",
+ ".dat" when IsDefaultIcuMode() && !(icuShardsFromRuntimePack.Any(f => f == fileName)) => "automatic icu shard selection, based on application culture, is enabled",
".json" when fromMonoPackage && (fileName == "emcc-props" || fileName == "package") => $"{fileName}{extension} is not used by Blazor",
".ts" when fromMonoPackage && fileName == "dotnet.d" => "dotnet type definition is not used by Blazor",
".map" when !emitSourceMap && fromMonoPackage && (fileName == "dotnet.js" || fileName == "dotnet.runtime.js") => "source map file is not published",
};
return reason != null;
+
+ bool IsDefaultIcuMode() =>
+ !invariantGlobalization &&
+ !loadFullICUData &&
+ !hybridGlobalization &&
+ string.IsNullOrEmpty(customIcuCandidateFilename);
}
private static bool IsFromMonoPackage(ITaskItem candidate)
public bool InvariantGlobalization { get; set; }
[Required]
+ public bool HybridGlobalization { get; set; }
+
+ [Required]
+ public bool LoadFullICUData { get; set; }
+
+ [Required]
public bool CopySymbols { get; set; }
public bool FingerprintDotNetJs { get; set; }
for (int i = 0; i < Candidates.Length; i++)
{
var candidate = Candidates[i];
- if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, EnableThreads, EmitSourceMap, out var reason))
+ if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, HybridGlobalization, LoadFullICUData, CopySymbols, customIcuCandidateFilename, EnableThreads, EmitSourceMap, out var reason))
{
Log.LogMessage(MessageImportance.Low, "Skipping asset '{0}' because '{1}'", candidate.ItemSpec, reason);
filesToRemove.Add(candidate);
public bool InvariantGlobalization { get; set; }
[Required]
+ public bool HybridGlobalization { get; set; }
+
+ [Required]
+ public bool LoadFullICUData { get; set; }
+
+ [Required]
public bool CopySymbols { get; set; }
[Required]
foreach (var candidate in resolvedFilesToPublish)
{
#pragma warning disable CA1864 // Prefer the 'IDictionary.TryAdd(TKey, TValue)' method. Dictionary.TryAdd() not available in .Net framework.
- if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, EnableThreads, EmitSourceMap, out var reason))
+ if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, HybridGlobalization, LoadFullICUData, CopySymbols, customIcuCandidateFilename, EnableThreads, EmitSourceMap, out var reason))
{
Log.LogMessage(MessageImportance.Low, "Skipping asset '{0}' because '{1}'", candidate.ItemSpec, reason);
if (!resolvedFilesToPublishToRemove.ContainsKey(candidate.ItemSpec))
[Required]
public bool CacheBootResources { get; set; }
- public bool LoadAllICUData { get; set; }
+ public bool LoadFullICUData { get; set; }
public bool IsHybridGlobalization { get; set; }
return GlobalizationMode.Invariant;
else if (IsHybridGlobalization)
return GlobalizationMode.Hybrid;
- else if (LoadAllICUData)
+ else if (LoadFullICUData)
return GlobalizationMode.All;
else if (LoadCustomIcuData)
return GlobalizationMode.Custom;